diff --git a/extra/game/models/collada/collada-docs.factor b/extra/game/models/collada/collada-docs.factor index 32f2bcace1..402f5eddc1 100644 --- a/extra/game/models/collada/collada-docs.factor +++ b/extra/game/models/collada/collada-docs.factor @@ -2,7 +2,7 @@ ! See http://factorcode.org/license.txt for BSD license. USING: help.markup help.crossref help.stylesheet help.topics help.syntax definitions io prettyprint summary arrays math sequences vocabs strings -see xml.data hashtables assocs ; +see xml.data hashtables assocs game.models.collada.private game.models.util ; IN: game.models.collada ABOUT: "game.models.collada" @@ -10,9 +10,6 @@ ABOUT: "game.models.collada" ARTICLE: "game.models.collada" "Conversion of COLLADA assets" "The " { $vocab-link "game.models.collada" } " vocabulary implements words for converting COLLADA assets to data suitable for use with OpenGL. See the COLLADA documentation at " { $url "http://collada.org" } "." ; -HELP: model -{ $class-description "Tuple of a packed attribute buffer, index buffer and vertex format suitable for a single OpenGL draw call." } ; - HELP: source { $class-description "Tuple of a vertex attribute semantic, offset in triangle index buffer and float data for a single vertex attribute." } ; @@ -22,13 +19,6 @@ HELP: up-axis HELP: unit-ratio { $description "Scaling ratio for the coordinates of the tags being read." } ; -HELP: indexed-seq -{ $class-description "A sequence described by a sequence of unique elements and a sequence of indices. The sequence can only be appended to. An associative map is used as a reverse lookup table when appending." } ; - -HELP: -{ $values { "dseq-exemplar" sequence } { "iseq-examplar" sequence } { "rassoc-examplar" assoc } } -{ $class-description "Construct an " { $link indexed-seq } " using the given examplars for the underlying data structures." } ; - HELP: string>numbers ( string -- number-seq ) { $values { "string" string } { "number-seq" sequence } } { $description "Splits a string on whitespace and converts the elements to a number sequence." } ; @@ -77,10 +67,6 @@ HELP: largest-offset+1 { $values { "source-seq" sequence } { "largest-offset+1" number } } { $description "Finds the largest offset in the sequence of " { $link source } " tuples and adds 1, which is the index stride for " { $link group-indices } "." } ; -HELP: -{ $values { "attribute-buffer" sequence } { "index-buffer" sequence } { "sources" sequence } { "model" model } } -{ $description "Converts the inputs to a form suitable for use with " { $vocab-link "gpu" } " and constructs a " { $link model } "." } ; - HELP: pack-attributes { $values { "source-indices" sequence } { "sources" sequence } { "attributes" sequence } } { $description "Packs the attributes for a single vertex into a sequence from a set of source data streams." } ; diff --git a/extra/game/models/collada/collada.factor b/extra/game/models/collada/collada.factor index 7f04aa992f..3de255bae8 100644 --- a/extra/game/models/collada/collada.factor +++ b/extra/game/models/collada/collada.factor @@ -5,62 +5,25 @@ locals math math.parser sequences sequences.deep specialized-arrays.instances.alien.c-types.float specialized-arrays.instances.alien.c-types.uint splitting xml xml.data xml.traversal math.order -namespaces combinators images gpu.shaders io make ; +namespaces combinators images gpu.shaders io make +game.models.util io.encodings.ascii game.models.loader ; IN: game.models.collada -TUPLE: model attribute-buffer index-buffer vertex-format ; -TUPLE: source semantic offset data ; - -SYMBOLS: up-axis unit-ratio ; +SINGLETON: collada-models +"dae" ascii collada-models register-models-class ERROR: missing-attr tag attr ; ERROR: missing-child tag child-name ; -TUPLE: indexed-seq dseq iseq rassoc ; -INSTANCE: indexed-seq sequence - -M: indexed-seq length - iseq>> length ; inline - -M: indexed-seq nth - [ iseq>> nth ] keep dseq>> nth ; inline - -M:: indexed-seq set-nth ( elt n seq -- ) - seq dseq>> :> dseq - seq iseq>> :> iseq - seq rassoc>> :> rassoc - seq length n = not [ seq immutable ] when - elt rassoc at - [ - iseq push - ] - [ - dseq length - [ elt rassoc set-at ] - [ iseq push ] bi - elt dseq push - ] if* ; inline - -: ( dseq-examplar iseq-exampler rassoc-examplar -- indexed-seq ) - indexed-seq new - swap clone >>rassoc - swap clone >>iseq - swap clone >>dseq ; - -M: indexed-seq new-resizable - [ dseq>> ] [ iseq>> ] [ rassoc>> ] tri - dup -rot - [ [ dseq>> new-resizable ] keep (>>dseq) ] - [ [ iseq>> new-resizable ] keep (>>iseq) ] - [ [ rassoc>> clone nip ] keep (>>rassoc) ] - 2tri ; - +numbers ( string -- number-seq ) - " \t\n" split [ "" = ] trim [ string>number ] map ; + " \t\n" split harvest [ string>number ] map ; : string>floats ( string -- float-seq ) - " \t\n" split [ "" = ] trim [ string>float ] map ; + " \t\n" split harvest [ string>float ] map ; : x/ ( tag child-name -- child-tag ) [ tag-named ] @@ -78,7 +41,6 @@ M: indexed-seq new-resizable [ tags-named ] dip map ; inline SINGLETONS: x-up y-up z-up ; - UNION: rh-up x-up y-up z-up ; GENERIC: >y-up-axis! ( seq from-axis -- seq ) @@ -159,19 +121,10 @@ M: z-up >y-up-axis! : largest-offset+1 ( source-seq -- largest-offset+1 ) [ offset>> ] [ max ] map-reduce 1 + ; -: ( attribute-buffer index-buffer sources -- model ) - [ flatten >float-array ] - [ flatten >uint-array ] - [ - [ - { - [ semantic>> ] - [ drop float-components ] - [ data>> first length ] - [ drop f ] - } cleave vertex-attribute boa - ] map - ] tri* model boa ; +VERTEX-FORMAT: collada-vertex-format + { "POSITION" float-components 3 f } + { "NORMAL" float-components 3 f } + { "TEXCOORD" float-components 2 f } ; : pack-attributes ( source-indices sources -- attributes ) [ @@ -184,9 +137,7 @@ M: z-up >y-up-axis! ] V{ } make flatten ; :: soa>aos ( triangles-indices sources -- attribute-buffer index-buffer ) - [ triangles-indices [ [ - sources pack-attributes , - ] each ] each ] + [ triangles-indices [ [ sources pack-attributes , ] each ] each ] V{ } V{ } H{ } make [ dseq>> ] [ iseq>> ] bi ; : triangles>model ( sources vertices triangles-tag -- model ) @@ -198,7 +149,10 @@ M: z-up >y-up-axis! group-indices ] [ - [ soa>aos ] keep + soa>aos + [ flatten >float-array ] + [ flatten >uint-array ] + bi* collada-vertex-format model boa ] bi ; : mesh>triangles ( sources vertices mesh-tag -- models ) @@ -206,9 +160,13 @@ M: z-up >y-up-axis! : mesh>models ( mesh-tag -- models ) [ - { { up-axis y-up } { unit-ratio 0.5 } } [ + { { up-axis y-up } { unit-ratio 1 } } [ mesh>sources ] bind ] [ mesh>vertices ] [ mesh>triangles ] tri ; +PRIVATE> + +M: collada-models stream>models + drop read-xml "mesh" deep-tags-named [ mesh>models ] map flatten ; diff --git a/extra/game/models/loader/loader.factor b/extra/game/models/loader/loader.factor new file mode 100644 index 0000000000..237f1a9164 --- /dev/null +++ b/extra/game/models/loader/loader.factor @@ -0,0 +1,46 @@ +! Copyright (C) 2010 Your name. +! See http://factorcode.org/license.txt for BSD license. +USING: accessors assocs byte-arrays combinators game.models +io.encodings.ascii io.files io.pathnames io.streams.byte-array +kernel namespaces sequences splitting +strings unicode.case arrays io.encodings ; +IN: game.models.loader + +ERROR: unknown-models-extension extension ; + +lower types get ?at + [ unknown-models-extension ] unless second ; + +: models-encoding ( path -- encoding ) + file-extension >lower types get ?at + [ unknown-models-extension ] unless first ; + +: open-models-file ( path encoding -- stream ) + ; + +PRIVATE> + +GENERIC# load-models* 2 ( obj encoding class -- models ) + +GENERIC: stream>models ( stream class -- models ) + +: register-models-class ( extension encoding class -- ) + 2array swap types get set-at ; + +: load-models ( path -- models ) + [ dup models-encoding open-models-file ] [ models-encoding ] [ models-class ] tri load-models* ; + +M: byte-array load-models* + [ ] dip stream>models ; + +M: decoder load-models* nip stream>models ; + +M: string load-models* [ open-models-file ] dip stream>models ; + +M: pathname load-models* [ open-models-file ] dip stream>models ; diff --git a/extra/game/models/models-docs.factor b/extra/game/models/models-docs.factor new file mode 100644 index 0000000000..907c32e294 --- /dev/null +++ b/extra/game/models/models-docs.factor @@ -0,0 +1,9 @@ +! Copyright (C) 2010 Erik Charlebois +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.crossref help.stylesheet help.topics help.syntax +definitions io prettyprint summary arrays math sequences vocabs strings +see ; +IN: game.models + +HELP: model +{ $class-description "Tuple of a packed attribute buffer, index buffer and vertex format suitable for a single OpenGL draw call." } ; diff --git a/extra/game/models/models.factor b/extra/game/models/models.factor new file mode 100644 index 0000000000..5575f5fb80 --- /dev/null +++ b/extra/game/models/models.factor @@ -0,0 +1,7 @@ +! Copyright (C) 2010 Your name. +! See http://factorcode.org/license.txt for BSD license. +USING: ; +IN: game.models + +TUPLE: model attribute-buffer index-buffer vertex-format ; + diff --git a/extra/game/models/obj/obj-docs.factor b/extra/game/models/obj/obj-docs.factor new file mode 100644 index 0000000000..e69de29bb2 diff --git a/extra/game/models/obj/obj.factor b/extra/game/models/obj/obj.factor new file mode 100644 index 0000000000..94927c9db8 --- /dev/null +++ b/extra/game/models/obj/obj.factor @@ -0,0 +1,98 @@ +! Copyright (C) 2010 Your name. +! See http://factorcode.org/license.txt for BSD license. +USING: io io.encodings.ascii math.parser sequences splitting kernel +assocs io.files combinators math.order math namespaces +arrays sequences.deep accessors +specialized-arrays.instances.alien.c-types.float +specialized-arrays.instances.alien.c-types.uint +game.models.util gpu.shaders images game.models.loader ; +IN: game.models.obj + +SINGLETON: obj-models +"obj" ascii obj-models register-models-class + +floats ( x -- y ) + [ string>float ] map ; + +: string>faces ( x -- y ) + [ "/" split [ string>number ] map ] map ; + +: 3face>aos ( x -- y ) + dup length { + { 3 + [ + first3 + [ 1 - v get nth ] + [ 1 - vt get nth ] + [ 1 - vn get nth ] tri* 3array flatten + ] } + { 2 + [ + first2 + [ 1 - v get nth ] + [ 1 - vt get nth ] bi* 2array flatten + ] } + } case ; + + +: 4face>aos ( x -- y z ) + [ 3 head [ 3face>aos 1array ] map ] + [ [ 0 swap nth ] [ 2 swap nth ] [ 3 swap nth ] tri 3array [ 3face>aos 1array ] map ] + bi + ; + +: faces>aos ( x -- y ) + dup length + { + { 3 [ [ 3face>aos 1array ] map 1array ] } + { 4 [ 4face>aos 2array ] } + } case ; + +: push* ( x z -- y ) + [ push ] keep ; + +: line>obj ( line -- ) + " \t\n" split harvest dup + length 1 > + [ + [ rest ] [ first ] bi + { + { "#" [ drop ] } + { "v" [ string>floats 3 head v [ push* ] change ] } + { "vt" [ string>floats 2 head vt [ push* ] change ] } + { "vn" [ string>floats 3 head vn [ push* ] change ] } + { "f" [ string>faces faces>aos [ [ i [ push* ] change ] each ] each ] } + { "o" [ drop ] } + { "g" [ drop ] } + { "s" [ drop ] } + { "mtllib" [ drop ] } + { "usemtl" [ drop ] } + } case + ] + [ drop ] if ; + +PRIVATE> + +M: obj-models stream>models + drop + [ + V{ } + [ clone v set ] + [ clone vt set ] + [ clone vn set ] tri + V{ } V{ } H{ } i set + ] H{ } make-assoc + [ + [ line>obj ] each-stream-line i get + ] bind + [ dseq>> flatten >float-array ] + [ iseq>> flatten >uint-array ] bi obj-vertex-format model boa 1array ; + diff --git a/extra/game/models/util/util-docs.factor b/extra/game/models/util/util-docs.factor new file mode 100644 index 0000000000..e38836cec7 --- /dev/null +++ b/extra/game/models/util/util-docs.factor @@ -0,0 +1,13 @@ +! Copyright (C) 2010 Erik Charlebois +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.crossref help.stylesheet help.topics help.syntax +definitions io prettyprint summary arrays math sequences vocabs strings +see xml.data hashtables assocs ; +IN: game.models.util + +HELP: indexed-seq +{ $class-description "A sequence described by a sequence of unique elements and a sequence of indices. The sequence can only be appended to. An associative map is used as a reverse lookup table when appending." } ; + +HELP: +{ $values { "dseq-exemplar" sequence } { "iseq-examplar" sequence } { "rassoc-examplar" assoc } } +{ $class-description "Construct an " { $link indexed-seq } " using the given examplars for the underlying data structures." } ; diff --git a/extra/game/models/util/util-tests.factor b/extra/game/models/util/util-tests.factor new file mode 100644 index 0000000000..1b5b005e44 --- /dev/null +++ b/extra/game/models/util/util-tests.factor @@ -0,0 +1,14 @@ +USING: game.models.util tools.test make accessors kernel ; +IN: game.models.util.tests + +[ V{ 1 2 3 4 } ] [ + [ 1 , 1 , 2 , 3 , 3 , 4 , ] + V{ } V{ } H{ } make + dseq>> +] unit-test + +[ V{ 0 0 1 2 2 3 } ] [ + [ 1 , 1 , 2 , 3 , 3 , 4 , ] + V{ } V{ } H{ } make + iseq>> +] unit-test diff --git a/extra/game/models/util/util.factor b/extra/game/models/util/util.factor new file mode 100644 index 0000000000..76f93f8365 --- /dev/null +++ b/extra/game/models/util/util.factor @@ -0,0 +1,46 @@ +! Copyright (C) 2010 Your name. +! See http://factorcode.org/license.txt for BSD license. +USING: sequences accessors kernel locals assocs ; +IN: game.models.util + +TUPLE: model attribute-buffer index-buffer vertex-format ; + +TUPLE: indexed-seq dseq iseq rassoc ; +INSTANCE: indexed-seq sequence + +M: indexed-seq length + iseq>> length ; inline + +M: indexed-seq nth + [ iseq>> nth ] keep dseq>> nth ; inline + +M:: indexed-seq set-nth ( elt n seq -- ) + seq dseq>> :> dseq + seq iseq>> :> iseq + seq rassoc>> :> rassoc + seq length n = not [ seq immutable ] when + elt rassoc at + [ + iseq push + ] + [ + dseq length + [ elt rassoc set-at ] + [ iseq push ] bi + elt dseq push + ] if* ; inline + +: ( dseq-examplar iseq-exampler rassoc-examplar -- indexed-seq ) + indexed-seq new + swap clone >>rassoc + swap clone >>iseq + swap clone >>dseq ; + +M: indexed-seq new-resizable + [ dseq>> ] [ iseq>> ] [ rassoc>> ] tri + dup -rot + [ [ dseq>> new-resizable ] keep (>>dseq) ] + [ [ iseq>> new-resizable ] keep (>>iseq) ] + [ [ rassoc>> clone nip ] keep (>>rassoc) ] + 2tri ; + diff --git a/basis/collada/viewer/viewer.factor b/extra/model-viewer/model-viewer.factor similarity index 65% rename from basis/collada/viewer/viewer.factor rename to extra/model-viewer/model-viewer.factor index 07fb09203f..641e4fe763 100644 --- a/basis/collada/viewer/viewer.factor +++ b/extra/model-viewer/model-viewer.factor @@ -8,17 +8,15 @@ io io.encodings.ascii io.files io.files.temp kernel locals math math.matrices math.vectors.simd math.parser math.vectors method-chains namespaces sequences splitting threads ui ui.gadgets ui.gadgets.worlds ui.pixel-formats specialized-arrays -specialized-vectors literals game.models.collada fry xml xml.traversal sequences.deep - -math.bitwise -opengl.gl -prettyprint ; +specialized-vectors literals fry xml +xml.traversal sequences.deep destructors math.bitwise opengl.gl +game.models.obj game.models.loader game.models.collada ; FROM: alien.c-types => float ; SPECIALIZED-ARRAY: float SPECIALIZED-VECTOR: uint -IN: collada.viewer +IN: model-viewer -GLSL-SHADER: collada-vertex-shader vertex-shader +GLSL-SHADER: model-vertex-shader vertex-shader uniform mat4 mv_matrix, p_matrix; uniform vec3 light_position; @@ -38,7 +36,7 @@ void main() } ; -GLSL-SHADER: collada-fragment-shader fragment-shader +GLSL-SHADER: model-fragment-shader fragment-shader varying vec2 texit; varying vec3 norm; void main() @@ -47,8 +45,8 @@ void main() } ; -GLSL-PROGRAM: collada-program - collada-vertex-shader collada-fragment-shader ; +GLSL-PROGRAM: model-program + model-vertex-shader model-fragment-shader ; GLSL-SHADER: debug-vertex-shader vertex-shader uniform mat4 mv_matrix, p_matrix; @@ -75,18 +73,18 @@ void main() GLSL-PROGRAM: debug-program debug-vertex-shader debug-fragment-shader ; -UNIFORM-TUPLE: collada-uniforms < mvp-uniforms +UNIFORM-TUPLE: model-uniforms < mvp-uniforms { "light-position" vec3-uniform f } ; -TUPLE: collada-state +TUPLE: model-state models vertex-arrays index-vectors ; -TUPLE: collada-world < wasd-world - { collada collada-state } ; +TUPLE: model-world < wasd-world + { model-state model-state } ; -VERTEX-FORMAT: collada-vertex +VERTEX-FORMAT: model-vertex { "POSITION" float-components 3 f } { "NORMAL" float-components 3 f } { "TEXCOORD" float-components 2 f } ; @@ -95,46 +93,50 @@ VERTEX-FORMAT: debug-vertex { "POSITION" float-components 3 f } { "COLOR" float-components 3 f } ; -: ( models -- buffers ) -! drop -! float-array{ -0.5 0 0 1 0 0 0 1 0 0 1 0 0.5 0 0 0 0 1 } -! uint-array{ 0 1 2 } -! f model boa 1array +TUPLE: vbo vertex-buffer index-buffer index-count vertex-format ; + +: ( models -- buffers ) [ - [ attribute-buffer>> underlying>> static-upload draw-usage vertex-buffer byte-array>buffer ] - [ index-buffer>> underlying>> static-upload draw-usage index-buffer byte-array>buffer ] - [ index-buffer>> length ] tri 3array + { + [ attribute-buffer>> underlying>> static-upload draw-usage vertex-buffer byte-array>buffer ] + [ index-buffer>> underlying>> static-upload draw-usage index-buffer byte-array>buffer ] + [ index-buffer>> length ] + [ vertex-format>> ] + } cleave vbo boa ] map ; -: fill-collada-state ( collada-state -- ) - dup models>> +: fill-model-state ( model-state -- ) + dup models>> [ [ - first collada-program collada-vertex buffer>vertex-array + [ vertex-buffer>> model-program ] + [ vertex-format>> ] bi buffer>vertex-array ] map >>vertex-arrays drop ] [ [ - [ second ] [ third ] bi + [ index-buffer>> ] [ index-count>> ] bi '[ _ 0 _ uint-indexes ] call ] map >>index-vectors drop ] 2bi ; - -: ( -- collada-state ) - collada-state new - "C:/Users/erikc/Downloads/test2.dae" - #! "/Users/erikc/Documents/mech.dae" - file>xml "mesh" deep-tags-named [ mesh>models ] map flatten >>models ; -M: collada-world begin-game-world +: model-files ( -- files ) + { "C:/Users/erikc/Downloads/test2.dae" + "C:/Users/erikc/Downloads/Sponza.obj" } ; + +: ( -- model-state ) + model-state new + model-files [ load-models ] [ append ] map-reduce >>models ; + +M: model-world begin-game-world init-gpu { 0.0 0.0 2.0 } 0 0 set-wasd-view - [ fill-collada-state drop ] [ >>collada drop ] 2bi ; + [ fill-model-state drop ] [ >>model-state drop ] 2bi ; -: ( world -- uniforms ) +: ( world -- uniforms ) [ wasd-mv-matrix ] [ wasd-p-matrix ] bi { -10000.0 10000.0 10000.0 } ! light position - collada-uniforms boa ; + model-uniforms boa ; : draw-line ( world from to color -- ) [ 3 head ] tri@ dup -rot append -rot append swap append >float-array @@ -144,7 +146,7 @@ M: collada-world begin-game-world { 0 1 } >uint-array stream-upload draw-usage index-buffer byte-array>buffer 2 '[ _ 0 _ uint-indexes ] call - rot + rot { { "primitive-mode" [ 3drop lines-mode ] } @@ -161,19 +163,20 @@ M: collada-world begin-game-world { 0 0 0 } { 0 1 0 } { 0 1 0 } { 0 0 0 } { 0 0 1 } { 0 0 1 } } draw-lines ; -: draw-collada ( world -- ) +: draw-model ( world -- ) 0 0 0 0 glClearColor 1 glClearDepth HEX: ffffffff glClearStencil { GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT GL_STENCIL_BUFFER_BIT } flags glClear [ - #! triangle-lines dup t set-gpu-state + triangle-fill dup t set-gpu-state face-ccw cull-back set-gpu-state + cmp-less set-gpu-state - [ collada>> vertex-arrays>> ] - [ collada>> index-vectors>> ] - [ ] + [ model-state>> vertex-arrays>> ] + [ model-state>> index-vectors>> ] + [ ] tri [ { @@ -190,20 +193,17 @@ M: collada-world begin-game-world ] bi ; -M: collada-world draw-world* - draw-collada ; +M: model-world draw-world* + draw-model ; -M: collada-world wasd-movement-speed drop 1/4. ; -M: collada-world wasd-near-plane drop 1/32. ; -M: collada-world wasd-far-plane drop 1024.0 ; +M: model-world wasd-movement-speed drop 1/4. ; +M: model-world wasd-near-plane drop 1/32. ; +M: model-world wasd-far-plane drop 1024.0 ; -GAME: collada-game { - { world-class collada-world } - { title "Collada Viewer" } - { pixel-format-attributes { - windowed - double-buffered - } } +GAME: model-viewer { + { world-class model-world } + { title "Model Viewer" } + { pixel-format-attributes { windowed double-buffered } } { grab-input? t } { use-game-input? t } { pref-dim { 1024 768 } }