private void DrawModelRecursive(ref Matrix4[] jointMatrix, SceneGraph curNode, BaseRenderer renderer, bool bSelectedPass) { switch (curNode.NodeType) { case J3DFormat.HierarchyDataTypes.Material: if (!bSelectedPass) { GL.BindTexture(TextureTarget.Texture2D, GetGLTexIdFromCache(curNode.DataIndex)); } break; case J3DFormat.HierarchyDataTypes.Batch: /* For each batch, we're going to enable the * appropriate Vertex Attributes for that batch * and set default values for vertex attribs that * the batch doesn't use, then draw all primitives * within it.*/ if (bSelectedPass) { #region Selected float[] front_face_wireframe_color = { 1.0f, 1.0f, 1.0f, 1.0f }; float[] back_face_wireframe_color = { 0.7f, 0.7f, 0.7f, 0.7f }; GL.LineWidth(1); GL.Enable(EnableCap.CullFace); //GL.Disable(EnableCap.DepthTest); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); GL.EnableVertexAttribArray((int)BaseRenderer.ShaderAttributeIds.Position); // 1. Draw the back-faces with a darker color: GL.CullFace(CullFaceMode.Back); GL.VertexAttrib4((int)BaseRenderer.ShaderAttributeIds.Color, back_face_wireframe_color); foreach (var packet in _renderList[curNode.DataIndex].Packets) { int vertexIndex = 0; foreach (var primitive in packet.PrimList) { //Uhh... ushort drawIndex = packet.DrawIndexes[primitive.PosMatrixIndex[vertexIndex] / 3]; bool isWeighted = _file.Draw.IsWeighted(drawIndex); if (isWeighted) { } else { var jnt = _file.Joints.GetJoint(curNode.DataIndex); Vector3 jntRot = jnt.GetRotation().ToDegrees(); Vector3 trans = jnt.GetTranslation(); Matrix4 trnMatrix = Matrix4.CreateTranslation(trans); Matrix4 rtMatrix = Matrix4.CreateRotationX(jntRot.X) * Matrix4.CreateRotationY(jntRot.Y) * Matrix4.CreateRotationZ(jntRot.Z); Matrix4 sclMatrix = Matrix4.CreateScale(jnt.GetScale()); Matrix4 final = trnMatrix * rtMatrix * sclMatrix; //renderer.SetModelMatrix(Matrix4.Identity); renderer.SetModelMatrix(final); } GL.DrawArrays(primitive.DrawType, primitive.VertexStart, primitive.VertexCount); vertexIndex++; } } // 2. Draw the front-faces with a lighter color: GL.CullFace(CullFaceMode.Front); GL.VertexAttrib4((int)BaseRenderer.ShaderAttributeIds.Color, front_face_wireframe_color); /*foreach (var primitive in _renderList[curNode.DataIndex]) * { * GL.DrawArrays(primitive.DrawType, primitive.VertexStart, primitive.VertexCount); * }*/ GL.DisableVertexAttribArray((int)BaseRenderer.ShaderAttributeIds.Position); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); //GL.Enable(EnableCap.DepthTest); GL.LineWidth(1); #endregion } else { SetVertexAttribArraysForBatch(true, curNode.DataIndex); //GL.CullFace(CullFaceMode.Front); for (int packetIndex = 0; packetIndex < _renderList[curNode.DataIndex].Packets.Count; packetIndex++) { RenderPacket packet = _renderList[curNode.DataIndex].Packets[packetIndex]; foreach (var primitive in packet.PrimList) { renderer.SetModelMatrix(Matrix4.Identity); if (primitive.PosMatrixIndex.Count > 0) { var transformedData = new J3DRenderer.VertexFormatLayout[primitive.VertexCount]; //For each vertex within this primitive, we're going to get its id. for (int vertexIndex = 0; vertexIndex < primitive.VertexCount; vertexIndex++) { ushort vertIndex = primitive.PosMatrixIndex[vertexIndex]; ushort drawIndex = packet.DrawIndexes[vertIndex / 3]; //ehh int seriously = 0; while (drawIndex == 0xFFFF) { RenderPacket prevPacket = _renderList[curNode.DataIndex].Packets[packetIndex - seriously]; drawIndex = prevPacket.DrawIndexes[vertIndex / 3]; seriously++; } bool isWeighted = _file.Draw.IsWeighted(drawIndex); if (isWeighted) { ushort numBonesAffecting = _file.Envelopes.GetCount(_file.Draw.GetIndex(drawIndex)); //Much WTFs ushort offset = 0; for (ushort i = 0; i < _file.Draw.GetIndex(drawIndex); i++) { offset += _file.Envelopes.GetCount(i); } offset *= 2; Matrix4 finalTransform = Matrix4.Identity; for (ushort i = 0; i < numBonesAffecting; i++) { ushort boneIndex = _file.Envelopes.GetIndexOffset((ushort)(offset + (i * 0x2))); float boneWeight = _file.Envelopes.GetWeight((ushort)((offset / 2) + i)); Matrix3x4 envMatrix = _file.Envelopes.GetMatrix(boneIndex); Matrix4 newEnvelopeMtx = new Matrix4(envMatrix.Row0, envMatrix.Row1, envMatrix.Row2, new Vector4(0, 0, 0, 1)); SkeletonJoint joint = _skeleCopy[boneIndex]; //Matrix4 transMatrix = Matrix4.CreateTranslation(joint.Position); //We need to use the bone's matrix from EVP1 to get the joint matrix Matrix4 jointMtx = joint.Rotation * newEnvelopeMtx; //finalTransform = Matrix4.Mult(jointMtx * newEnvelopeMtx, boneWeight) * finalTransform; //ToDo: This is the wrong scale. //AddScaleMatrix(ref finalTransform, Matrix4.Mult(jointMtx, newEnvelopeMtx), 1f); } transformedData[vertexIndex] = _vertDataBind[primitive.VertexStart + vertexIndex]; Vector3 vertPosition = transformedData[vertexIndex].Position; transformedData[vertexIndex].Position = Vector3.TransformPosition(vertPosition, finalTransform); } else { //If the vertex is not weighted, we're just going to use the position //from the bone matrix. Something like this. Vector3 vertPosition = _vertDataBind[primitive.VertexStart + vertexIndex].Position; transformedData[vertexIndex] = _vertDataBind[primitive.VertexStart + vertexIndex]; SkeletonJoint joint = _skeleCopy[_file.Draw.GetIndex(drawIndex)]; Matrix4 transMatrix = Matrix4.CreateTranslation(joint.Position); Matrix4 final = joint.Rotation * transMatrix; transformedData[vertexIndex].Position = Vector3.TransformPosition(vertPosition, final); } } //Re-upload the subsection to the buffer. GL.BindBuffer(BufferTarget.ArrayBuffer, _glVbo); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)(primitive.VertexStart * (9 * 4)), (IntPtr)(primitive.VertexCount * (9 * 4)), transformedData); float[] front_face_wireframe_color = { 1.0f, 1.0f, 1.0f, 1.0f }; GL.VertexAttrib4((int)BaseRenderer.ShaderAttributeIds.Color, front_face_wireframe_color); } GL.DrawArrays(primitive.DrawType, primitive.VertexStart, primitive.VertexCount); } } SetVertexAttribArraysForBatch(false, curNode.DataIndex); } break; } foreach (SceneGraph subNode in curNode.Children) { DrawModelRecursive(ref jointMatrix, subNode, renderer, bSelectedPass); } }