private List<J3DRenderer.VertexFormatLayout> BuildVertexArraysFromFile() { List<J3DRenderer.VertexFormatLayout> finalData = new List<J3DRenderer.VertexFormatLayout>(); //Now, let's try to get our data. for (uint i = 0; i < _file.Shapes.GetBatchCount(); i++) { J3DFormat.Batch batch = _file.Shapes.GetBatch(i); RenderBatch renderBatch = new RenderBatch(); _renderList.Add(renderBatch); //Console.WriteLine("[{0}] Unk0: {5}, Attb: {6} Mtx Type: {1} #Packets {2}[{3}] Matrix Index: {4}", i, batch.MatrixType, batch.PacketCount, batch.PacketIndex, batch.FirstMatrixIndex, batch.Unknown0, batch.AttribOffset); uint attributeCount = 0; for (uint attribIndex = 0; attribIndex < 13; attribIndex++) { J3DFormat.BatchAttribute attrib = _file.Shapes.GetAttribute(attribIndex, batch.AttribOffset); if (attrib.AttribType == J3DFormat.ArrayTypes.NullAttr) break; attributeCount++; } for (ushort p = 0; p < batch.PacketCount; p++) { RenderPacket renderPacket = new RenderPacket(); renderBatch.Packets.Add(renderPacket); //Matrix Data J3DFormat.PacketMatrixData pmd = _file.Shapes.GetPacketMatrixData((ushort)(batch.FirstMatrixIndex + p)); renderPacket.DrawIndexes = new ushort[pmd.Count]; for (ushort mtx = 0; mtx < pmd.Count; mtx++) { //Console.WriteLine("{4} {0} Packet: {1} Index: {2} PMD Unknown: {3}", i, p, _file.Shapes.GetMatrixTableIndex((ushort) (pmd.FirstIndex + mtx)), pmd.Unknown, mtx); renderPacket.DrawIndexes[mtx] = _file.Shapes.GetMatrixTableIndex((ushort)(pmd.FirstIndex + mtx)); } J3DFormat.BatchPacketLocation packetLoc = _file.Shapes.GetBatchPacketLocation((ushort)(batch.PacketIndex + p)); uint numPrimitiveBytesRead = packetLoc.Offset; while (numPrimitiveBytesRead < packetLoc.Offset + packetLoc.PacketSize) { J3DFormat.BatchPrimitive primitive = _file.Shapes.GetPrimitive(numPrimitiveBytesRead); numPrimitiveBytesRead += J3DFormat.BatchPrimitive.Size; //Game pads the chunks out with zeros, so this is signal for early break. if (primitive.Type == 0) { break; } var primList = new PrimitiveList(); primList.VertexCount = primitive.VertexCount; primList.VertexStart = finalData.Count; primList.DrawType = primitive.Type == J3DFormat.PrimitiveTypes.TriangleStrip ? PrimitiveType.TriangleStrip : PrimitiveType.TriangleFan; //Todo: More support renderPacket.PrimList.Add(primList); for (int vert = 0; vert < primitive.VertexCount; vert++) { J3DRenderer.VertexFormatLayout newVertex = new J3DRenderer.VertexFormatLayout(); for (uint vertIndex = 0; vertIndex < attributeCount; vertIndex++) { var batchAttrib = _file.Shapes.GetAttribute(vertIndex, batch.AttribOffset); ushort curIndex = _file.Shapes.GetPrimitiveIndex(numPrimitiveBytesRead, batchAttrib); switch (batchAttrib.AttribType) { case J3DFormat.ArrayTypes.Position: newVertex.Position = _file.Vertexes.GetPosition(curIndex); break; case J3DFormat.ArrayTypes.Normal: newVertex.Color = new Vector4(_file.Vertexes.GetNormal(curIndex, 14), 1); //temp break; case J3DFormat.ArrayTypes.Color0: newVertex.Color = _file.Vertexes.GetColor0(curIndex); break; case J3DFormat.ArrayTypes.Tex0: newVertex.TexCoord = _file.Vertexes.GetTex0(curIndex, 8); break; case J3DFormat.ArrayTypes.PositionMatrixIndex: //Console.WriteLine("B: {0} P: {1} Prim: {2} Vert{3} Index: {4}", i, p, renderPacket.PrimList.Count, vert, curIndex); primList.PosMatrixIndex.Add(curIndex); break; default: Console.WriteLine("Unknown AttribType {0}, Index: {1}", batchAttrib.AttribType, curIndex); break; } numPrimitiveBytesRead += GetAttribElementSize(batchAttrib.DataType); } //Add our vertex to our list of Vertexes finalData.Add(newVertex); } //Console.WriteLine("Batch {0} Prim {1} #Vertices with PosMtxIndex: {2}", i, p, primList.PosMatrixIndex.Count); } } //Console.WriteLine("Finished batch {0}, triangleStrip count: {1}", i, _renderList.Count); } return finalData; }
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); } }