From 860f67d522251b27473604e3effcdc7d205eb813 Mon Sep 17 00:00:00 2001 From: Fatbag Date: Tue, 7 Feb 2012 15:49:09 -0600 Subject: [PATCH] Working skeleton parser and "renderer", though at the moment the body mesh does not map correctly on to the skeleton. --- Libraries/libvitaboy/CMakeLists.txt | 1 + Libraries/libvitaboy/Renderer.cpp | 218 ++++++++++++++++++++++------ Libraries/libvitaboy/anim.cpp | 20 +-- Libraries/libvitaboy/libvitaboy.cpp | 49 ++++++- Libraries/libvitaboy/libvitaboy.hpp | 66 ++++++++- Libraries/libvitaboy/mesh.cpp | 33 +++-- 6 files changed, 296 insertions(+), 91 deletions(-) diff --git a/Libraries/libvitaboy/CMakeLists.txt b/Libraries/libvitaboy/CMakeLists.txt index d2d494c..a0ed4a6 100644 --- a/Libraries/libvitaboy/CMakeLists.txt +++ b/Libraries/libvitaboy/CMakeLists.txt @@ -9,6 +9,7 @@ set(LIBVITABOY_SOURCES anim.cpp libvitaboy.cpp mesh.cpp + skel.cpp ) if(WIN32) set(LIBVITABOY_SOURCES ${LIBVITABOY_SOURCES} resource.rc) diff --git a/Libraries/libvitaboy/Renderer.cpp b/Libraries/libvitaboy/Renderer.cpp index 8dad4f7..3dbafd9 100644 --- a/Libraries/libvitaboy/Renderer.cpp +++ b/Libraries/libvitaboy/Renderer.cpp @@ -18,34 +18,44 @@ HGLRC hRC=NULL; // Permanent Rendering Context HWND hWnd=NULL; // Holds Our Window Handle HINSTANCE hInstance; // Holds The Instance Of The Application -bool keys[256]; // Array Used For The Keyboard Routine +bool keys[256] = {0}; // Array Used For The Keyboard Routine bool active=TRUE; // Window Active Flag Set To TRUE By Default bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default float zoom = -4; -float xrot = 0; -float yrot = 0; -float zrot = 90; +struct CharacterPlacement_t { + Vertex_t Translation; + Vertex_t Rotation; +}; -GLuint texture[1]; // Storage For One Texture ( NEW ) +CharacterPlacement_t Character = {{0,0,0}, {0,0,0}}; -Mesh_t Mesh; +GLuint texture[2]; // Storage For One Texture ( NEW ) +enum { Texture_Head, Texture_Body }; + +Skeleton_t Skeleton; +Mesh_t HeadMesh, BodyMesh; + +bool DrawMesh = true; +bool ShowSkeleton = true; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc int LoadGLTextures() // Load Bitmaps And Convert To Textures { - /* load an image file directly as a new OpenGL texture */ - texture[0] = SOIL_load_OGL_texture("texture.jpg", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y); - if(texture[0] == 0) - return false; + for(int i=0; i<2; i++){ + /* load an image file directly as a new OpenGL texture */ + texture[i] = SOIL_load_OGL_texture((i==0) ? "head.jpg" : "body.jpg", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS); + if(texture[i] == 0) + return false; - // Typical Texture Generation Using Data From The Bitmap - glBindTexture(GL_TEXTURE_2D, texture[0]); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // Typical Texture Generation Using Data From The Bitmap + glBindTexture(GL_TEXTURE_2D, texture[i]); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } return true; // Return Success } @@ -79,40 +89,103 @@ int InitGL(void) // All Setup For OpenGL Goes Here glShadeModel(GL_SMOOTH); // Enable Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background glClearDepth(1.0f); // Depth Buffer Setup + glPointSize(5.0); glEnable(GL_DEPTH_TEST); // Enables Depth Testing + glEnable(GL_CULL_FACE); + glEnable(GL_RESCALE_NORMAL); + glDisable(GL_BLEND); glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations return TRUE; // Initialization Went OK } +void DrawBonesMesh(Bone_t& Bone){ + glTranslatef(Bone.Translation.x, Bone.Translation.y, Bone.Translation.z); + float RotationMatrix[16]; + FindQuaternionMatrix(RotationMatrix, &Bone.Rotation); + glMultMatrixf(RotationMatrix); + + if(!strcmp(Bone.Name, "HEAD")){ + glBindTexture(GL_TEXTURE_2D, texture[0]); + + glVertexPointer(3, GL_FLOAT, offsetof(Vertex_t, y)-offsetof(Vertex_t, x)-sizeof(float), HeadMesh.VertexData); + glNormalPointer(GL_FLOAT, offsetof(Vertex_t, y)-offsetof(Vertex_t, x)-sizeof(float), HeadMesh.VertexNorms); + glTexCoordPointer(2, GL_FLOAT, offsetof(TextureVertex_t, v)-offsetof(TextureVertex_t, u)-sizeof(float), HeadMesh.TextureVertexData); + glDrawElements(GL_TRIANGLES, HeadMesh.FaceCount*3, GL_UNSIGNED_INT, HeadMesh.FaceData); + }else{ + glBindTexture(GL_TEXTURE_2D, texture[1]); + + glVertexPointer(3, GL_FLOAT, offsetof(Vertex_t, y)-offsetof(Vertex_t, x)-sizeof(float), BodyMesh.VertexData); + glNormalPointer(GL_FLOAT, offsetof(Vertex_t, y)-offsetof(Vertex_t, x)-sizeof(float), BodyMesh.VertexNorms); + glTexCoordPointer(2, GL_FLOAT, offsetof(TextureVertex_t, v)-offsetof(TextureVertex_t, u)-sizeof(float), BodyMesh.TextureVertexData); + glDrawElements(GL_TRIANGLES, BodyMesh.FaceCount*3, GL_UNSIGNED_INT, BodyMesh.FaceData); + } + + for(unsigned i=0; i=-10.0f) zoom-=0.05f; } - if(keys[VK_UP]){ if((xrot-=1.0f) <=-360) xrot+=360; } - if(keys[VK_DOWN]){ if((xrot+=1.0f) >=360) xrot-=360; } - if(keys[VK_LEFT]){ if((yrot-=1.0f) <=-360) yrot+=360; } - if(keys[VK_RIGHT]){ if((yrot+=1.0f) >=360) yrot-=360; } - if(keys['X']){ if((zrot-=1.0f) <=-360) zrot+=360; } - if(keys['Z']){ if((zrot+=1.0f) >=360) zrot-=360; } + if(keys['A']) /*{if(zoom <=-1.0f) zoom+=0.05f; }*/ zoom+=0.05f; + if(keys['S']) /*{if(zoom >=-10.0f) zoom-=0.05f; }*/ zoom-=0.05f; + if(keys[VK_UP]){ if((Character.Rotation.x-=1.0f) <=-360) Character.Rotation.x+=360; } + if(keys[VK_DOWN]){ if((Character.Rotation.x+=1.0f) >=360) Character.Rotation.x-=360; } + if(keys[VK_LEFT]){ if((Character.Rotation.y-=1.0f) <=-360) Character.Rotation.y+=360; } + if(keys[VK_RIGHT]){ if((Character.Rotation.y+=1.0f) >=360) Character.Rotation.y-=360; } + if(keys['X']){ if((Character.Rotation.z-=1.0f) <=-360) Character.Rotation.z+=360; } + if(keys['Z']){ if((Character.Rotation.z+=1.0f) >=360) Character.Rotation.z-=360; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer - glLoadIdentity(); // Reset The Current Modelview Matrix - glTranslatef(0.0f,0.0f,zoom); // Move Into The Screen - glRotatef(xrot,1.0f,0.0f,0.0f); - glRotatef(yrot,0.0f,1.0f,0.0f); - glRotatef(zrot,0.0f,0.0f,1.0f); + glLoadIdentity(); + glTranslatef(Character.Translation.x, Character.Translation.y, zoom + Character.Translation.z); + glRotatef(Character.Rotation.x,1.0f,0.0f,0.0f); + glRotatef(Character.Rotation.y,0.0f,1.0f,0.0f); + glRotatef(Character.Rotation.z,0.0f,0.0f,1.0f); - glBindTexture(GL_TEXTURE_2D, texture[0]); + if(DrawMesh){ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glColor3f(1.0, 1.0, 1.0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + DrawBonesMesh(Skeleton.Bones[0]); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(3, GL_FLOAT, offsetof(Vertex_t, y)-offsetof(Vertex_t, x)-sizeof(float), Mesh.UnclothedVertexData); - glTexCoordPointer(2, GL_FLOAT, offsetof(TextureVertex_t, v)-offsetof(TextureVertex_t, u)-sizeof(float), Mesh.TextureVertexData); - glDrawElements(GL_TRIANGLES, Mesh.FaceCount*3, GL_UNSIGNED_INT, Mesh.FaceData); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if(ShowSkeleton){ + glClear(GL_DEPTH_BUFFER_BIT); + DrawBonesSkeleton(Skeleton.Bones[0]); + } return TRUE; // Keep Going } @@ -409,29 +482,80 @@ int WINAPI WinMain( HINSTANCE hInstance, // Instance uint8_t *InData; DWORD bytestransferred; - hFile = CreateFile("mesh.mesh", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + hFile = CreateFile("skeleton.skel", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(hFile == INVALID_HANDLE_VALUE){ if(GetLastError() == ERROR_FILE_NOT_FOUND){ - MessageBox(NULL, "The specified mesh does not exist.", "Error", MB_OK); - return -1; + MessageBox(NULL, "The specified skeleton does not exist.", "Error", MB_OK); + return 0; } - MessageBox(NULL, "The mesh could not be opened for reading.", "Error", MB_OK); - return -1; + MessageBox(NULL, "The skeleton could not be opened for reading.", "Error", MB_OK); + return 0; } FileSize = GetFileSize(hFile, NULL); InData = (uint8_t*) malloc(FileSize); if(InData == NULL){ - MessageBox(NULL, "Memory for the mesh could not be allocated.", "Error", MB_OK); - return -1; + MessageBox(NULL, "Memory for the skeleton could not be allocated.", "Error", MB_OK); + return 0; } if(!ReadFile(hFile, InData, FileSize, &bytestransferred, NULL) || bytestransferred != FileSize){ - MessageBox(NULL, "The mesh could not be read.", "Error", MB_OK); - return -1; + MessageBox(NULL, "The skeleton could not be read.", "Error", MB_OK); + return 0; } CloseHandle(hFile); VBFile.set(InData, FileSize); - ReadMesh(Mesh); + ReadSkeleton(Skeleton); + free(InData); + + hFile = CreateFile("head.mesh", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFile == INVALID_HANDLE_VALUE){ + if(GetLastError() == ERROR_FILE_NOT_FOUND){ + MessageBox(NULL, "head.mesh does not exist.", "Error", MB_OK); + return 0; + } + MessageBox(NULL, "head.mesh could not be opened for reading.", "Error", MB_OK); + return 0; + } + FileSize = GetFileSize(hFile, NULL); + InData = (uint8_t*) malloc(FileSize); + if(InData == NULL){ + MessageBox(NULL, "Memory for head.mesh could not be allocated.", "Error", MB_OK); + return 0; + } + if(!ReadFile(hFile, InData, FileSize, &bytestransferred, NULL) || bytestransferred != FileSize){ + MessageBox(NULL, "The head.mesh could not be read.", "Error", MB_OK); + return 0; + } + CloseHandle(hFile); + + VBFile.set(InData, FileSize); + ReadMesh(HeadMesh); + free(InData); + + hFile = CreateFile("body.mesh", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFile == INVALID_HANDLE_VALUE){ + if(GetLastError() == ERROR_FILE_NOT_FOUND){ + MessageBox(NULL, "body.mesh does not exist.", "Error", MB_OK); + return 0; + } + MessageBox(NULL, "body.mesh could not be opened for reading.", "Error", MB_OK); + return 0; + } + FileSize = GetFileSize(hFile, NULL); + InData = (uint8_t*) malloc(FileSize); + if(InData == NULL){ + MessageBox(NULL, "Memory for body.mesh could not be allocated.", "Error", MB_OK); + return 0; + } + if(!ReadFile(hFile, InData, FileSize, &bytestransferred, NULL) || bytestransferred != FileSize){ + MessageBox(NULL, "The body.mesh could not be read.", "Error", MB_OK); + return 0; + } + CloseHandle(hFile); + + VBFile.set(InData, FileSize); + ReadMesh(BodyMesh); + free(InData); // Create Our OpenGL Window if (!CreateGLWindow("libvitaboy - Renderer",640,480,16,fullscreen)) diff --git a/Libraries/libvitaboy/anim.cpp b/Libraries/libvitaboy/anim.cpp index 5f50a5c..0af71c0 100644 --- a/Libraries/libvitaboy/anim.cpp +++ b/Libraries/libvitaboy/anim.cpp @@ -75,10 +75,10 @@ void ReadMotion(Animation_t& Animation, Motion_t& Motion){ unsigned pos = VBFile.getpos(); VBFile.seekto(Animation.RotationsOffset + 16*Motion.RotationsOffset); for(unsigned i=0; ix * Quaternion->x; + float y2 = Quaternion->y * Quaternion->y; + float z2 = Quaternion->z * Quaternion->z; + float xy = Quaternion->x * Quaternion->y; + float xz = Quaternion->x * Quaternion->z; + float yz = Quaternion->y * Quaternion->z; + float wx = Quaternion->w * Quaternion->x; + float wy = Quaternion->w * Quaternion->y; + float wz = Quaternion->w * Quaternion->z; + + Matrix[0] = 1.0f - 2.0f * (y2 + z2); + Matrix[1] = 2.0f * (xy - wz); + Matrix[2] = 2.0f * (xz + wy); + Matrix[3] = 0.0f; + Matrix[4] = 2.0f * (xy + wz); + Matrix[5] = 1.0f - 2.0f * (x2 + z2); + Matrix[6] = 2.0f * (yz - wx); + Matrix[7] = 0.0f; + Matrix[8] = 2.0f * (xz - wy); + Matrix[9] = 2.0f * (yz + wx); + Matrix[10] = 1.0f - 2.0f * (x2 + y2); + Matrix[11] = 0.0f; + Matrix[12] = 0.0f; + Matrix[13] = 0.0f; + Matrix[14] = 0.0f; + Matrix[15] = 1.0f; +} \ No newline at end of file diff --git a/Libraries/libvitaboy/libvitaboy.hpp b/Libraries/libvitaboy/libvitaboy.hpp index c2cb670..18af404 100644 --- a/Libraries/libvitaboy/libvitaboy.hpp +++ b/Libraries/libvitaboy/libvitaboy.hpp @@ -77,7 +77,7 @@ class VBFile_t { extern VBFile_t VBFile; /**** -** Animation (*.anim) +** Common */ struct Translation_t { @@ -85,7 +85,7 @@ struct Translation_t { }; struct Rotation_t { - float w, x, y, z; + float x, y, z, w; }; struct KeyValuePair_t { @@ -103,6 +103,16 @@ struct PropsList_t { Prop_t * Props; }; +void ReadPropEntry(KeyValuePair_t& Entry); +void ReadPropEntries(Prop_t& Prop); +void ReadPropsList(PropsList_t& PropsList); +void FindQuaternionMatrix(float * Matrix, Rotation_t * Quaternion); + + +/**** +** Animation (*.anim) +*/ + struct TimeProp_t { uint32_t ID; PropsList_t PropsList; @@ -150,11 +160,8 @@ struct Animation_t { Motion_t * Motions; }; -void ReadPropEntry(KeyValuePair_t& Entry); -void ReadPropEntries(Prop_t& Prop); void ReadAnimation(Animation_t& Animation); void ReadMotion(Animation_t& Animation, Motion_t& Motion); -void ReadPropsList(PropsList_t& PropsList); void ReadPropsLists(Motion_t& Motion); void ReadTimePropsList(TimePropsList_t& TimePropsList); void ReadTimePropsLists(Motion_t& Motion); @@ -176,6 +183,14 @@ struct Face_t { unsigned VertexA, VertexB, VertexC; }; +struct BoneBinding_t { + unsigned BoneIndex; + unsigned FirstVertex; + unsigned VertexCount; + unsigned FirstBlendedVertex; + unsigned BlendedVertexCount; +}; + struct Mesh_t { uint32_t Version; uint32_t BoneCount; @@ -183,12 +198,47 @@ struct Mesh_t { uint32_t FaceCount; Face_t * FaceData; uint32_t BindingCount; + BoneBinding_t * BoneBindings; uint32_t TextureVertexCount; TextureVertex_t * TextureVertexData; uint32_t BlendDataCount; uint32_t VertexCount; - Vertex_t * UnclothedVertexData; - Vertex_t * ClothedVertexData; + Vertex_t * VertexData; + Vertex_t * VertexNorms; }; -void ReadMesh(Mesh_t& Mesh); \ No newline at end of file +void ReadMesh(Mesh_t& Mesh); + + +/**** +** Skeleton (*.skel) +*/ + +struct Bone_t { + uint32_t Unknown; + char * Name; + char * ParentsName; + uint8_t HasProps; + PropsList_t PropsList; + Translation_t Translation; + Rotation_t Rotation; + uint32_t CanTranslate; + uint32_t CanRotate; + uint32_t CanBlend; + float WiggleValue; + float WigglePower; + + unsigned ChildrenCount; + Bone_t ** Children; +}; + +struct Skeleton_t { + uint32_t Version; + char * Name; + uint16_t BoneCount; + Bone_t * Bones; +}; + +void ReadSkeleton(Skeleton_t& Bone); +void ReadBone(Skeleton_t& Skeleton, Bone_t& Bone, unsigned Index); +unsigned FindBone(Skeleton_t& Skeleton, const char * BoneName, unsigned Count); \ No newline at end of file diff --git a/Libraries/libvitaboy/mesh.cpp b/Libraries/libvitaboy/mesh.cpp index a077c02..a60efa8 100644 --- a/Libraries/libvitaboy/mesh.cpp +++ b/Libraries/libvitaboy/mesh.cpp @@ -1,8 +1,8 @@ #include "libvitaboy.hpp" void ReadMesh(Mesh_t& Mesh){ + printf("\n========== Mesh ==========\n"); Mesh.Version = VBFile.readint32(); - printf("========== Mesh ==========\n"); printf("Version: %u\n", Mesh.Version); Mesh.BoneCount = VBFile.readint32(); @@ -23,21 +23,22 @@ void ReadMesh(Mesh_t& Mesh){ } Mesh.BindingCount = VBFile.readint32(); + Mesh.BoneBindings = (BoneBinding_t*) malloc(Mesh.BindingCount * sizeof(BoneBinding_t)); printf("BindingCount: %u\n", Mesh.BindingCount); for(unsigned i=0; i