static SSTexturedNormalCube()
 {
     int verticesPerQuad = c_vertices.Length;
     SSVertex_PosNormTex[] vertices = new SSVertex_PosNormTex[verticesPerQuad * 6];
     for (int f = 0; f < 6; ++f) {
         for (int v = 0; v < verticesPerQuad; ++v) {
             SSVertex_PosNormTex vertex = c_vertices [v];
             vertex.Position = Vector3.Transform(vertex.Position, c_faceTransforms [f]);
             vertex.Normal = Vector3.Transform (vertex.Normal, c_faceTransforms [f]);
             vertices [f * verticesPerQuad + v] = vertex;
         }
     }
     Instance = new SSVertexBuffer<SSVertex_PosNormTex> (vertices);
 }
Example #2
0
        static SSTexturedNormalCube()
        {
            int verticesPerQuad = c_vertices.Length;

            SSVertex_PosNormTex[] vertices = new SSVertex_PosNormTex[verticesPerQuad * 6];
            for (int f = 0; f < 6; ++f)
            {
                for (int v = 0; v < verticesPerQuad; ++v)
                {
                    SSVertex_PosNormTex vertex = c_vertices [v];
                    vertex.Position = Vector3.Transform(vertex.Position, c_faceTransforms [f]);
                    vertex.Normal   = Vector3.Transform(vertex.Normal, c_faceTransforms [f]);
                    vertices [f * verticesPerQuad + v] = vertex;
                }
            }
            Instance = new SSVertexBuffer <SSVertex_PosNormTex> (vertices);
        }
        protected override void setupScene()
        {
            base.setupScene ();

            // checkerboard floor
            #if true
            {
                SSTexture tex = SSAssetManager.GetInstance<SSTexture> (".", "checkerboard.png");
                const float tileSz = 4f;
                const int gridSz = 10;
                var tileVertices = new SSVertex_PosNormTex[SSTexturedNormalQuad.c_doubleFaceVertices.Length];
                SSTexturedNormalQuad.c_doubleFaceVertices.CopyTo(tileVertices, 0);
                for (int v = 0; v < tileVertices.Length; ++v) {
                    tileVertices[v].TexCoord *= (float)gridSz;
                }

                var quadMesh = new SSVertexMesh<SSVertex_PosNormTex>(tileVertices);
                quadMesh.textureMaterial = new SSTextureMaterial(tex);
                var tileObj = new SSObjectMesh(quadMesh);
                tileObj.Name = "Tiles";
                tileObj.Selectable = false;
                tileObj.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, (float)Math.PI/2f));
                tileObj.Scale = new Vector3(tileSz * gridSz);
                //tileObj.boundingSphere = new SSObjectSphere(0f);
                scene.AddObject(tileObj);
            }
            #endif

            // skeleton mesh test
            #if true
            {
                SSSkeletalAnimation animIdle
                    = SSAssetManager.GetInstance<SSSkeletalAnimationMD5>("./boneman", "boneman_idle.md5anim");
                SSSkeletalAnimation animRunning
                    = SSAssetManager.GetInstance<SSSkeletalAnimationMD5>("./boneman", "boneman_running.md5anim");
                SSSkeletalAnimation animAttack
                = SSAssetManager.GetInstance<SSSkeletalAnimationMD5>("./boneman", "boneman_attack.md5anim");

                SSSkeletalMesh[] meshes
                    = SSAssetManager.GetInstance<SSSkeletalMeshMD5[]>("./boneman", "boneman.md5mesh");
                var tex = SSAssetManager.GetInstance<SSTexture>("./boneman", "skin.png");
                foreach (var skeliMesh in meshes) {

                #if true
                var renderMesh0 = new SSSkeletalRenderMesh(skeliMesh);
                var obj0 = new SSObjectMesh(renderMesh0);
                obj0.MainColor = Color4.DarkGray;
                obj0.Name = "grey bones (bind pose)";
                obj0.Pos = new Vector3(-18f, 0f, -18f);
                obj0.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(obj0);

                tracker0 = new SSSimpleObjectTrackingJoint(obj0);
                tracker0.jointPositionLocal = animIdle.computeJointFrame(11, 0).position;
                tracker0.neutralViewOrientationLocal = animIdle.computeJointFrame(11, 0).orientation;
                tracker0.neutralViewDirectionBindPose = Vector3.UnitY;
                tracker0.neutralViewUpBindPose = Vector3.UnitZ;
                renderMesh0.addCustomizedJoint(11, tracker0);
                #endif

                #if true
                var renderMesh1 = new SSSkeletalRenderMesh(skeliMesh);
                var obj1 = new SSObjectMesh(renderMesh1);
                obj1.MainColor = Color4.DarkRed;
                obj1.Name = "red bones (running loop)";
                obj1.Pos = new Vector3(6f, 0f, -12f);
                obj1.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(obj1);

                renderMesh1.playAnimationLoop(animRunning, 0f);
                #endif

                #if true
                var renderMesh2 = new SSSkeletalRenderMesh(skeliMesh);
                renderMesh2.playAnimationLoop(animIdle, 0f, "all");
                renderMesh2.playAnimationLoop(animRunning, 0f, "LeftClavicle", "RightClavicle");
                var obj2 = new SSObjectMesh(renderMesh2);
                obj2.MainColor = Color.Green;
                obj2.Name = "green bones (idle + running loop mixed)";
                obj2.Pos = new Vector3(0f, 0f, -12f);
                obj2.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(obj2);
                #endif

                #if true
                var renderMesh3 = new SSSkeletalRenderMesh(skeliMesh);
                renderMesh3.playAnimationLoop(animIdle, 0f, "all");
                var obj3 = new SSObjectMesh(renderMesh3);
                obj3.MainColor = Color.DarkCyan;
                obj3.Name = "blue bones (idle loop)";
                obj3.Pos = new Vector3(-6f, 0f, -12f);
                obj3.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(obj3);
                #endif

                // state machines setup for skeletal render mesh 4 and 5
                var skeletonWalkDescr = new SSAnimationStateMachine();
                skeletonWalkDescr.addState("idle", animIdle, true);
                skeletonWalkDescr.addState("running1", animRunning);
                skeletonWalkDescr.addState("running2", animRunning);
                skeletonWalkDescr.addAnimationEndsTransition("idle", "running1", 0.3f);
                skeletonWalkDescr.addAnimationEndsTransition("running1", "running2", 0f);
                skeletonWalkDescr.addAnimationEndsTransition("running2", "idle", 0.3f);

                var skeletonAttackDescr = new SSAnimationStateMachine();
                skeletonAttackDescr.addState("inactive", null, true);
                skeletonAttackDescr.addState("attack", animAttack);
                skeletonAttackDescr.addStateTransition(null, "attack", 0.5f);
                skeletonAttackDescr.addAnimationEndsTransition("attack", "inactive", 0.5f);

                #if true
                // state machine test (in slow motion)
                var renderMesh4 = new SSSkeletalRenderMesh(skeliMesh);
                renderMesh4.timeScale = 0.25f;

                var obj4 = new SSObjectMesh(renderMesh4);
                obj4.MainColor = Color.DarkMagenta;
                obj4.Name = "magenta bones (looping idle/walk; interactive attack; slowmo)";
                obj4.Pos = new Vector3(-12f, 0f, 0f);
                obj4.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(obj4);

                var renderMesh4WallSm = renderMesh4.addStateMachine(skeletonWalkDescr, "all");
                renderMesh4AttackSm = renderMesh4.addStateMachine(skeletonAttackDescr, "LeftClavicle", "RightClavicle");

                tracker4 = new SSSimpleObjectTrackingJoint(obj4);
                tracker4.jointPositionLocal = animRunning.computeJointFrame(11, 0).position;
                tracker4.neutralViewOrientationLocal = animRunning.computeJointFrame(11, 0).orientation;
                tracker4.neutralViewDirectionBindPose = Vector3.UnitY;
                renderMesh4.addCustomizedJoint(11, tracker4);
                #endif

                #if true
                // another mesh, using the same state machine but running at normal speed
                var renderMesh5 = new SSSkeletalRenderMesh(skeliMesh);
                var renderMesh5WalkSm = renderMesh5.addStateMachine(skeletonWalkDescr, "all");
                renderMesh5AttackSm = renderMesh5.addStateMachine(skeletonAttackDescr, "LeftClavicle", "RightClavicle");
                var obj5 = new SSObjectMesh(renderMesh5);
                obj5.Name = "orange bones (looping idle/walk, interactive attack + parametric neck rotation)";
                obj5.Pos = new Vector3(12f, 0f, 0f);
                obj5.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                obj5.MainColor = Color4.DarkOrange;
                scene.AddObject(obj5);

                renderMesh5NeckJoint = new SSPolarJoint();
                renderMesh5NeckJoint.positionOffset = new Vector3(0f, 0.75f, 0f);
                renderMesh5.addCustomizedJoint("UpperNek", renderMesh5NeckJoint);
                #endif
                }
            }
            #endif

            #if true
            // bob mesh test
            {
                var bobMeshes = SSAssetManager.GetInstance<SSSkeletalMeshMD5[]>(
                    "./bob_lamp/", "bob_lamp_update.md5mesh");
                var bobAnim = SSAssetManager.GetInstance<SSSkeletalAnimationMD5>(
                    "./bob_lamp/", "bob_lamp_update.md5anim");
                var bobRender = new SSSkeletalRenderMesh(bobMeshes);
                bobRender.playAnimationLoop(bobAnim, 0f);
                bobRender.alphaBlendingEnabled = true;
                bobRender.timeScale = 0.5f;
                var bobObj = new SSObjectMesh(bobRender);
                bobObj.Name = "Bob";
                bobObj.Pos = new Vector3(10f, 0f, 10f);
                bobObj.Orient(Quaternion.FromAxisAngle(Vector3.UnitX, -(float)Math.PI/2f));
                scene.AddObject(bobObj);
            }
            #endif
        }
        // convert wavefrontobjloader vector formats, to our OpenTK Vector3 format
        // generateDrawIndexBuffer(..)
        //
        // Walks the wavefront faces, feeds pre-configured verticies to the VertexSoup,
        // and returns a new index-buffer pointing to the new VertexSoup.verticies indicies.
        public static void generateDrawIndexBuffer(
			WavefrontObjLoader wff, 
            WavefrontObjLoader.MaterialInfoWithFaces objMatSubset,
			out UInt16[] indicies_return, 
			out SSVertex_PosNormTex[] verticies_return)
        {
            const bool shouldDedup = true; // this lets us turn on/of vertex-soup deduping

            var soup = new VertexSoup<SSVertex_PosNormTex>(deDup:shouldDedup);
            List<UInt16> draw_indicies = new List<UInt16>();

            // (0) go throu`gh the materials and faces, DENORMALIZE from WF-OBJ into fully-configured verticies

            // load indexes
            var m = objMatSubset;

            // wavefrontOBJ stores color in CIE-XYZ color space. Convert this to Alpha-RGB
            var materialDiffuseColor = WavefrontObjLoader.CIEXYZtoColor(m.mtl.vDiffuse).ToArgb();

            foreach (var face in m.faces) {

                // iterate over the vericies of a wave-front FACE...

                // DEREFERENCE each .obj vertex paramater (position, normal, texture coordinate)
                SSVertex_PosNormTex[] vertex_list = new SSVertex_PosNormTex[face.v_idx.Length];
                for (int facevertex = 0; facevertex < face.v_idx.Length; facevertex++) {

                    // position
                    vertex_list[facevertex].Position = wff.positions[face.v_idx[facevertex]].Xyz;

                    // normal
                    int normal_idx = face.n_idx[facevertex];
                    if (normal_idx != -1) {
                        vertex_list[facevertex].Normal = wff.normals[normal_idx];
                    }

                    // texture coordinate
                    int tex_index = face.tex_idx[facevertex];
                    if (tex_index != -1 ) {
                        vertex_list[facevertex].Tu = wff.texCoords[tex_index].X;
                        vertex_list[facevertex].Tv = 1- wff.texCoords[tex_index].Y;
                    }
                }

                // turn them into indicies in the vertex soup..
                //   .. we hand the soup a set of fully configured verticies. It
                //   .. dedups and accumulates them, and hands us back indicies
                //   .. relative to it's growing list of deduped verticies.
                UInt16[] soup_indicies = soup.digestVerticies(vertex_list);

                // now we add these indicies to the draw-list. Right now we assume
                // draw is using GL_TRIANGLE, so we convert NGONS into triange lists
                if (soup_indicies.Length == 3) { // triangle
                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[1]);
                    draw_indicies.Add(soup_indicies[2]);
                } else if (soup_indicies.Length == 4) { // quad
                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[1]);
                    draw_indicies.Add(soup_indicies[2]);

                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[2]);
                    draw_indicies.Add(soup_indicies[3]);
                } else {
                    // This n-gon algorithm only works if the n-gon is coplanar and convex,
                    // which Wavefront OBJ says they must be.
                    //  .. to tesselate concave ngons, one must tesselate using a more complex method, see
                    //    http://en.wikipedia.org/wiki/Polygon_triangulation#Ear_clipping_method

                    // manually generate a triangle-fan
                    for (int x = 1; x < (soup_indicies.Length-1); x++) {
                        draw_indicies.Add(soup_indicies[0]);
                        draw_indicies.Add(soup_indicies[x]);
                        draw_indicies.Add(soup_indicies[x+1]);
                    }
                    // throw new NotImplementedException("unhandled face size: " + newindicies.Length);
                }
            }

            // convert the linked-lists into arrays and return
            indicies_return = draw_indicies.ToArray();
            verticies_return = soup.verticies.ToArray();

            Console.WriteLine ("VertexSoup_VertexFormatBinder:generateDrawIndexBuffer : \r\n   {0} verticies, {1} indicies.  Dedup = {2}",
                              verticies_return.Length, indicies_return.Length,
                              shouldDedup ? "YES" : "NO");
        }
        // convert wavefrontobjloader vector formats, to our OpenTK Vector3 format
        // generateDrawIndexBuffer(..)
        //
        // Walks the wavefront faces, feeds pre-configured verticies to the VertexSoup,
        // and returns a new index-buffer pointing to the new VertexSoup.verticies indicies.

        public static void generateDrawIndexBuffer(
            WavefrontObjLoader wff,
            WavefrontObjLoader.MaterialInfoWithFaces objMatSubset,
            out UInt16[] indicies_return,
            out SSVertex_PosNormTex[] verticies_return)
        {
            const bool shouldDedup = true;             // this lets us turn on/of vertex-soup deduping

            var           soup          = new VertexSoup <SSVertex_PosNormTex>(deDup: shouldDedup);
            List <UInt16> draw_indicies = new List <UInt16>();

            // (0) go throu`gh the materials and faces, DENORMALIZE from WF-OBJ into fully-configured verticies

            // load indexes
            var m = objMatSubset;

            // wavefrontOBJ stores color in CIE-XYZ color space. Convert this to Alpha-RGB
            var materialDiffuseColor = WavefrontObjLoader.CIEXYZtoColor(m.mtl.vDiffuse).ToArgb();

            foreach (var face in m.faces)
            {
                // iterate over the vericies of a wave-front FACE...

                // DEREFERENCE each .obj vertex paramater (position, normal, texture coordinate)
                SSVertex_PosNormTex[] vertex_list = new SSVertex_PosNormTex[face.v_idx.Length];
                for (int facevertex = 0; facevertex < face.v_idx.Length; facevertex++)
                {
                    // position
                    vertex_list[facevertex].Position = wff.positions[face.v_idx[facevertex]].Xyz;

                    // normal
                    int normal_idx = face.n_idx[facevertex];
                    if (normal_idx != -1)
                    {
                        vertex_list[facevertex].Normal = wff.normals[normal_idx];
                    }

                    // texture coordinate
                    int tex_index = face.tex_idx[facevertex];
                    if (tex_index != -1)
                    {
                        vertex_list[facevertex].Tu = wff.texCoords[tex_index].X;
                        vertex_list[facevertex].Tv = 1 - wff.texCoords[tex_index].Y;
                    }
                }

                // turn them into indicies in the vertex soup..
                //   .. we hand the soup a set of fully configured verticies. It
                //   .. dedups and accumulates them, and hands us back indicies
                //   .. relative to it's growing list of deduped verticies.
                UInt16[] soup_indicies = soup.digestVerticies(vertex_list);

                // now we add these indicies to the draw-list. Right now we assume
                // draw is using GL_TRIANGLE, so we convert NGONS into triange lists
                if (soup_indicies.Length == 3)                   // triangle
                {
                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[1]);
                    draw_indicies.Add(soup_indicies[2]);
                }
                else if (soup_indicies.Length == 4)                     // quad
                {
                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[1]);
                    draw_indicies.Add(soup_indicies[2]);

                    draw_indicies.Add(soup_indicies[0]);
                    draw_indicies.Add(soup_indicies[2]);
                    draw_indicies.Add(soup_indicies[3]);
                }
                else
                {
                    // This n-gon algorithm only works if the n-gon is coplanar and convex,
                    // which Wavefront OBJ says they must be.
                    //  .. to tesselate concave ngons, one must tesselate using a more complex method, see
                    //    http://en.wikipedia.org/wiki/Polygon_triangulation#Ear_clipping_method

                    // manually generate a triangle-fan
                    for (int x = 1; x < (soup_indicies.Length - 1); x++)
                    {
                        draw_indicies.Add(soup_indicies[0]);
                        draw_indicies.Add(soup_indicies[x]);
                        draw_indicies.Add(soup_indicies[x + 1]);
                    }
                    // throw new NotImplementedException("unhandled face size: " + newindicies.Length);
                }
            }


            // convert the linked-lists into arrays and return
            indicies_return  = draw_indicies.ToArray();
            verticies_return = soup.verticies.ToArray();

            Console.WriteLine("VertexSoup_VertexFormatBinder:generateDrawIndexBuffer : \r\n   {0} verticies, {1} indicies.  Dedup = {2}",
                              verticies_return.Length, indicies_return.Length,
                              shouldDedup ? "YES" : "NO");
        }