commit 3e28e22b6e3b651bfea55234eff5b26c6e035eb5 Author: gered Date: Mon Dec 10 15:28:23 2012 -0500 initial commit (based on MeshConverter source) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c6e5c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +*.sdf +*.opensdf +*.user +*.suo +/*.exe +/*.idb +/*.ilk +/*.pdb +*.vpwhistu +*.vtg +/*.dll +/ms3dtomesh +/build diff --git a/generate_makefile.sh b/generate_makefile.sh new file mode 100644 index 0000000..33d7a29 --- /dev/null +++ b/generate_makefile.sh @@ -0,0 +1,3 @@ +#!/bin/sh +type premake4 >/dev/null 2>&1 || { echo >&2 "'premake4' not found in your path."; exit 1; } +premake4 --file=premake.lua gmake diff --git a/generate_vs2010.bat b/generate_vs2010.bat new file mode 100644 index 0000000..9538990 --- /dev/null +++ b/generate_vs2010.bat @@ -0,0 +1,8 @@ +@echo off +for %%X in (premake4.exe) do (set FOUND=%%~$PATH:X) +if not defined FOUND ( +echo 'premake4' not found in your path. +exit /b +) + +premake4 --file=premake.lua vs2010 diff --git a/premake.lua b/premake.lua new file mode 100644 index 0000000..c4f1c74 --- /dev/null +++ b/premake.lua @@ -0,0 +1,63 @@ + +BUILD_DIR = "build" + +if _ACTION == "clean" then + os.rmdir(BUILD_DIR) +end + +solution "Ms3dToMesh" + configurations { "Debug", "Release" } + location (BUILD_DIR .. "/" .. _ACTION) + +project "Ms3dToMesh" + kind "ConsoleApp" + language "C++" + location (BUILD_DIR .. "/" .. _ACTION) + files { + "./src/**.c*", + "./src/**.h", + } + debugdir "." + + ---- PLATFORM SPECIFICS ---------------------------------------------------- + configuration "vs*" + flags { + "NoPCH", + "NoMinimalRebuild" + } + buildoptions { "/MP" } + defines { + "_CRT_SECURE_NO_WARNINGS", + "_CRT_NONSTDC_NO_WARNINGS" + } + + configuration "gmake" + kind "ConsoleApp" + buildoptions { "-Wall" } + + configuration { "windows", "gmake" } + kind "ConsoleApp" + defines { + "_GNU_SOURCE=1", + } + links { + "mingw32", + } + linkoptions { + "-static-libgcc", + "-static-libstdc++", + } + ---------------------------------------------------------------------------- + + configuration "Debug" + defines { + "DEBUG", + "DEBUG_ASSERT_BREAK", + } + flags { "Symbols" } + + configuration "Release" + defines { + "NDEBUG", + } + flags { "Optimize" } diff --git a/src/geometry/vector2.h b/src/geometry/vector2.h new file mode 100644 index 0000000..48886c7 --- /dev/null +++ b/src/geometry/vector2.h @@ -0,0 +1,11 @@ +#ifndef __VECTOR2_H_INCLUDED__ +#define __VECTOR2_H_INCLUDED__ + +class Vector2 +{ +public: + float x; + float y; +}; + +#endif \ No newline at end of file diff --git a/src/geometry/vector3.h b/src/geometry/vector3.h new file mode 100644 index 0000000..a3799db --- /dev/null +++ b/src/geometry/vector3.h @@ -0,0 +1,319 @@ +#ifndef __VECTOR3_H_INCLUDED__ +#define __VECTOR3_H_INCLUDED__ + +#include + +/** + * Represents a 3D vector and provides common methods/operators + * for vector math + */ +class Vector3 +{ +public: + Vector3() {} + Vector3(float vx, float vy, float vz) { x = vx; y = vy; z = vz; } + Vector3(const float *v) { x = v[0]; y = v[1]; z = v[2]; } + ~Vector3() {} + + static Vector3 Cross(const Vector3 &a, const Vector3 &b); + static float Dot(const Vector3 &a, const Vector3 &b); + static Vector3 Normalize(const Vector3 &a); + static Vector3 SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3); + static float Magnitude(const Vector3 &a); + static float SquaredLength(const Vector3 &a); + static Vector3 SetLength(const Vector3 &v, float length); + static float Distance(const Vector3 &a, const Vector3 &b); + static bool IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc); + + float x; + float y; + float z; +}; + +bool operator==(const Vector3 &left, const Vector3 &right); +Vector3 operator-(const Vector3 &left); +Vector3 operator+(const Vector3 &left, const Vector3 &right); +Vector3 &operator+=(Vector3 &left, const Vector3 &right); +Vector3 operator-(const Vector3 &left, const Vector3 &right); +Vector3 &operator-=(Vector3 &left, const Vector3 &right); +Vector3 operator*(const Vector3 &left, float right); +Vector3 &operator*=(Vector3 &left, float right); +Vector3 operator/(const Vector3 &left, float right); +Vector3 &operator/=(Vector3 &left, float right); +Vector3 operator*(const Vector3 &left, const Vector3 &right); +Vector3 &operator*=(Vector3 &left, const Vector3 &right); +Vector3 operator/(const Vector3 &left, const Vector3 &right); +Vector3 &operator/=(Vector3 &left, const Vector3 &right); + +#define ZERO_VECTOR Vector3(0.0f, 0.0f, 0.0f) + +#define X_AXIS Vector3(1.0f, 0.0f, 0.0f) +#define Y_AXIS Vector3(0.0f, 1.0f, 0.0f) +#define Z_AXIS Vector3(0.0f, 0.0f, 1.0f) + +#define UP_VECTOR Vector3(0.0f, 1.0f, 0.0f) + +/** + * Computes the cross product of 2 vectors. + * x = a.y * b.z - b.y * a.z + * y = a.z * b.x - b.z * a.x + * z = a.x * b.y - b.x * a.y + * @param a first vector + * @param b second vector + * + * @return Vector3 the cross product + */ +inline Vector3 Vector3::Cross(const Vector3 &a, const Vector3 &b) +{ + return Vector3( + (a.y * b.z) - (b.y * a.z), + (a.z * b.x) - (b.z * a.x), + (a.x * b.y) - (b.x * a.y) + ); +} + +/** + * Computes the dot product of 2 vectors. + * dot = (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + * @param a first vector + * @param b second vector + * + * @return float the dot product + */ +inline float Vector3::Dot(const Vector3 &a, const Vector3 &b) +{ + return (a.x * b.x) + + (a.y * b.y) + + (a.z * b.z); +} + +/** + * Normalizes a vector + * x = a.x / ||a|| + * y = a.y / ||a|| + * z = a.z / ||a|| + * @param a vector to normalize + * + * @return Vector3 the normalized vector + */ +inline Vector3 Vector3::Normalize(const Vector3 &a) +{ + float magnitudeSquared = (a.x * a.x) + (a.y * a.y) + (a.z * a.z); + if (magnitudeSquared > 0.0f) + { + float inverseMagnitude = 1.0f / sqrtf(magnitudeSquared); + return Vector3( + a.x * inverseMagnitude, + a.y * inverseMagnitude, + a.z * inverseMagnitude + ); + } + else + return a; +} + +/** + * Calculates a normal vector for the given 3 vectors making up + * a triangle (counter-clockwise order) + * @param v1 first vertex + * @param v2 second vertex + * @param v3 third vertex + * + * @return Vector3 normal vector for the triangle + */ +inline Vector3 Vector3::SurfaceNormal(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) +{ + return Vector3::Normalize(Vector3::Cross(v2 - v1, v3 - v1)); +} + +/** + * Returns magnitude of a vector. + * ||a|| = sqrt((a.x * a.x) + (a.y * a.y) + (a.z * a.z)) + * @param a vector to calculate the magnitude of + * + * @return float vector magnitude + */ +inline float Vector3::Magnitude(const Vector3 &a) +{ + return sqrtf( + (a.x * a.x) + + (a.y * a.y) + + (a.z * a.z) + ); +} + +/** + * Returns the squared length of a vector (the magnitude minus + * the sqrt call) + * @param a vector to calculate the squared length of + * + * @return float squared length of the vector + */ +inline float Vector3::SquaredLength(const Vector3 &a) +{ + return + (a.x * a.x) + + (a.y * a.y) + + (a.z * a.z); +} + +/** + * Adjusts a vector so that it's magnitude is equal to the given + * length + * @param v the original vector to be adjusted + * @param length desired vector magnitude + * + * @return Vector3 the resulting vector after it's length has + * been converted to the desired amount + */ +inline Vector3 Vector3::SetLength(const Vector3 &v, float length) +{ + float magnitude = Vector3::Magnitude(v); + return v * (length / magnitude); +} + +/** + * Calculates the distance between two points + * @param a the first point + * @param b the second point + * + * @return float the distance between both points + */ +inline float Vector3::Distance(const Vector3 &a, const Vector3 &b) +{ + return sqrtf( + ((b.x - a.x) * (b.x - a.x)) + + ((b.y - a.y) * (b.y - a.y)) + + ((b.z - a.z) * (b.z - a.z)) + ); +} + +/** + * Checks if a given point lies inside a triangle or not + * @param point point to test + * @param a first vector of the triangle + * @param b second vector of the triangle + * @param c third vector of the triangle + * + * @return BOOL TRUE if the point lies inside the triangle, + * FALSE if it doesn't + */ +inline bool Vector3::IsPointInTriangle(const Vector3 &point, const Vector3 &pa, const Vector3 &pb, const Vector3 &pc) +{ + Vector3 edge1 = pb - pa; + Vector3 edge2 = pc - pa; + + float a = Vector3::Dot(edge1, edge1); + float b = Vector3::Dot(edge1, edge2); + float c = Vector3::Dot(edge2, edge2); + float ac_bb = (a * c) - (b * b); + Vector3 vp(point.x - pa.x, point.y - pa.y, point.z - pa.z); + + float d = Vector3::Dot(vp, edge1); + float e = Vector3::Dot(vp, edge2); + float x = (d * c) - (e * b); + float y = (e * a) - (d * b); + float z = x + y - ac_bb; + + int result = (( ((unsigned int&) z)& ~(((unsigned int&) x)|((unsigned int&) y)) ) & 0x80000000); + if (result == 0) + return false; + else + return true; +} + +inline bool operator==(const Vector3 &left, const Vector3 &right) +{ + return (left.x == right.x && left.y == right.y && left.z == right.z); +} + +inline Vector3 operator-(const Vector3 &left) +{ + return Vector3(-left.x, -left.y, -left.z); +} + +inline Vector3 operator+(const Vector3 &left, const Vector3 &right) +{ + return Vector3(left.x + right.x, left.y + right.y, left.z + right.z); +} + +inline Vector3 &operator+=(Vector3 &left, const Vector3 &right) +{ + left.x += right.x; + left.y += right.y; + left.z += right.z; + + return left; +} + +inline Vector3 operator-(const Vector3 &left, const Vector3 &right) +{ + return Vector3(left.x - right.x, left.y - right.y, left.z - right.z); +} + +inline Vector3 &operator-=(Vector3 &left, const Vector3 &right) +{ + left.x -= right.x; + left.y -= right.y; + left.z -= right.z; + + return left; +} + +inline Vector3 operator*(const Vector3 &left, float right) +{ + return Vector3(left.x * right, left.y * right, left.z * right); +} + +inline Vector3 &operator*=(Vector3 &left, float right) +{ + left.x *= right; + left.y *= right; + left.z *= right; + + return left; +} + +inline Vector3 operator/(const Vector3 &left, float right) +{ + return Vector3(left.x / right, left.y / right, left.z / right); +} + +inline Vector3 &operator/=(Vector3 &left, float right) +{ + left.x /= right; + left.y /= right; + left.z /= right; + + return left; +} + +inline Vector3 operator*(const Vector3 &left, const Vector3 &right) +{ + return Vector3(left.x * right.x, left.y * right.y, left.z * right.z); +} + +inline Vector3 &operator*=(Vector3 &left, const Vector3 &right) +{ + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + + return left; +} + +inline Vector3 operator/(const Vector3 &left, const Vector3 &right) +{ + return Vector3(left.x / right.x, left.y / right.y, left.z / right.z); +} + +inline Vector3 &operator/=(Vector3 &left, const Vector3 &right) +{ + left.x /= right.x; + left.y /= right.y; + left.z /= right.z; + + return left; +} + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..f2692ad --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,85 @@ +#include +#include +#include + +#include "ms3d/ms3d.h" + +int main(int argc, char **argv) +{ + printf("MS3D-to-MESH Converter\n"); + + if (argc == 1) + { + printf("No input file specified.\n"); + printf("Usage: ms3dtomesh.exe [--scale=] [inputfile]\n\n"); + return 1; + } + + // input file is always the last argument + std::string file = argv[argc - 1]; + + // default option values + float scaleFactor = 1.0f; + + // find any options and update their values + for (int i = 1; i < argc - 1; ++i) + { + std::string arg = argv[i]; + + if (arg.substr(0, 8) == "--scale=") + { + // scale factor + + if (arg.length() == 8) + { + printf("Missing scale factor.\n"); + return 1; + } + + scaleFactor = (float)atof(arg.substr(8).c_str()); + + if (scaleFactor == 0.0f) + { + printf("Invalid or 0.0 scale factor.\n"); + return 1; + } + } + } + + std::string extension; + + try + { + extension = file.substr(file.find_last_of('.'), std::string::npos); + for (unsigned int i = 0; i < extension.size(); ++i) + extension[i] = tolower(extension[i]); + } + catch (std::exception &e) + { + extension = ""; + } + + std::string meshFile = ""; + if (extension.length() > 0) + { + meshFile = file; + meshFile.erase(meshFile.find_last_of('.'), std::string::npos); + meshFile.append(".mesh"); + } + + Ms3d *ms3d = new Ms3d(); + if (!ms3d->Load(file)) + { + printf("Error loading MS3D file.\n\n"); + return 1; + } + if (!ms3d->ConvertToMesh(meshFile, scaleFactor)) + { + printf("Error converting MS3D to MESH.\n\n"); + return 1; + } + + printf("Finished converting to %s\n", meshFile.c_str()); + + return 0; +} diff --git a/src/ms3d/ms3d.cpp b/src/ms3d/ms3d.cpp new file mode 100644 index 0000000..e9bceae --- /dev/null +++ b/src/ms3d/ms3d.cpp @@ -0,0 +1,443 @@ +#include "ms3d.h" + +#include + +#include "../util/files.h" + +Ms3d::Ms3d() +{ + m_numVertices = 0; + m_numTriangles = 0; + m_numMeshes = 0; + m_numMaterials = 0; + m_numJoints = 0; + m_vertices = NULL; + m_triangles = NULL; + m_meshes = NULL; + m_materials = NULL; + m_joints = NULL; +} + +void Ms3d::Release() +{ + delete[] m_vertices; + delete[] m_triangles; + delete[] m_meshes; + delete[] m_materials; + delete[] m_joints; + m_numVertices = 0; + m_numTriangles = 0; + m_numMeshes = 0; + m_numMaterials = 0; + m_numJoints = 0; +} + +bool Ms3d::Load(const std::string &file) +{ + FILE *fp; + Ms3dHeader header; + + fp = fopen(file.c_str(), "rb"); + if (!fp) + return false; + + // filetype verification + fread(&header.id, 10, 1, fp); + if (strncmp(header.id, "MS3D000000", 10) != 0) + { + fclose(fp); + return false; + } + fread(&header.version, 4, 1, fp); + if (header.version != 4) + { + fclose(fp); + return false; + } + + // read vertices + fread(&m_numVertices, 2, 1, fp); + m_vertices = new Ms3dVertex[m_numVertices]; + + for (int i = 0; i < m_numVertices; ++i) + { + Ms3dVertex *vertex = &m_vertices[i]; + + fread(&vertex->editorFlags, 1, 1, fp); + fread(&vertex->vertex.x, 4, 1, fp); + fread(&vertex->vertex.y, 4, 1, fp); + fread(&vertex->vertex.z, 4, 1, fp); + fread(&vertex->jointIndex, 1, 1, fp); + fread(&vertex->unused, 1, 1, fp); + } + + // read triangle definitions + fread(&m_numTriangles, 2, 1, fp); + m_triangles = new Ms3dTriangle[m_numTriangles]; + + for (int i = 0; i < m_numTriangles; ++i) + { + Ms3dTriangle *triangle = &m_triangles[i]; + + fread(&triangle->editorFlags, 2, 1, fp); + for (int j = 0; j < 3; ++j) + fread(&triangle->vertices[j], 2, 1, fp); + for (int j = 0; j < 3; ++j) + { + fread(&triangle->normals[j].x, 4, 1, fp); + fread(&triangle->normals[j].y, 4, 1, fp); + fread(&triangle->normals[j].z, 4, 1, fp); + } + for (int j = 0; j < 3; ++j) + fread(&triangle->texCoords[j].x, 4, 1, fp); + for (int j = 0; j < 3; ++j) + fread(&triangle->texCoords[j].y, 4, 1, fp); + fread(&triangle->smoothingGroup, 1, 1, fp); + fread(&triangle->meshIndex, 1, 1, fp); + } + + // read mesh information + fread(&m_numMeshes, 2, 1, fp); + m_meshes = new Ms3dMesh[m_numMeshes]; + + for (int i = 0; i < m_numMeshes; ++i) + { + Ms3dMesh *mesh = &m_meshes[i]; + + fread(&mesh->editorFlags, 1, 1, fp); + ReadString(fp, mesh->name, 32); + fread(&mesh->numTriangles, 2, 1, fp); + mesh->triangles = new unsigned short[mesh->numTriangles]; + for (int j = 0; j < mesh->numTriangles; ++j) + fread(&mesh->triangles[j], 2, 1, fp); + fread(&mesh->materialIndex, 1, 1, fp); + } + + // read material information + fread(&m_numMaterials, 2, 1, fp); + if (m_numMaterials > 0) + { + m_materials = new Ms3dMaterial[m_numMaterials]; + + for (int i = 0; i < m_numMaterials; ++i) + { + Ms3dMaterial *material = &m_materials[i]; + + ReadString(fp, material->name, 32); + for (int j = 0; j < 4; ++j) + fread(&material->ambient[j], 4, 1, fp); + for (int j = 0; j < 4; ++j) + fread(&material->diffuse[j], 4, 1, fp); + for (int j = 0; j < 4; ++j) + fread(&material->specular[j], 4, 1, fp); + for (int j = 0; j < 4; ++j) + fread(&material->emissive[j], 4, 1, fp); + fread(&material->shininess, 4, 1, fp); + fread(&material->transparency, 4, 1, fp); + fread(&material->mode, 1, 1, fp); + ReadString(fp, material->texture, 128); + ReadString(fp, material->alpha, 128); + } + } + + // read joints + fread(&m_animationFps, 4, 1, fp); + fread(&m_editorAnimationTime, 4, 1, fp); + fread(&m_numFrames, 4, 1, fp); + fread(&m_numJoints, 2, 1, fp); + if (m_numJoints > 0) + { + m_joints = new Ms3dJoint[m_numJoints]; + + for (int i = 0; i < m_numJoints; ++i) + { + Ms3dJoint *joint = &m_joints[i]; + + fread(&joint->editorFlags, 1, 1, fp); + ReadString(fp, joint->name, 32); + ReadString(fp, joint->parentName, 32); + fread(&joint->rotation.x, 4, 1, fp); + fread(&joint->rotation.y, 4, 1, fp); + fread(&joint->rotation.z, 4, 1, fp); + fread(&joint->position.x, 4, 1, fp); + fread(&joint->position.y, 4, 1, fp); + fread(&joint->position.z, 4, 1, fp); + fread(&joint->numRotationFrames, 2, 1, fp); + fread(&joint->numTranslationFrames, 2, 1, fp); + joint->rotationFrames = new Ms3dKeyFrame[joint->numRotationFrames]; + for (int j = 0; j < joint->numRotationFrames; ++j) + { + Ms3dKeyFrame *frame = &joint->rotationFrames[j]; + fread(&frame->time, 4, 1, fp); + fread(&frame->param.x, 4, 1, fp); + fread(&frame->param.y, 4, 1, fp); + fread(&frame->param.z, 4, 1, fp); + } + joint->translationFrames = new Ms3dKeyFrame[joint->numTranslationFrames]; + for (int j = 0; j < joint->numTranslationFrames; ++j) + { + Ms3dKeyFrame *frame = &joint->translationFrames[j]; + fread(&frame->time, 4, 1, fp); + fread(&frame->param.x, 4, 1, fp); + fread(&frame->param.y, 4, 1, fp); + fread(&frame->param.z, 4, 1, fp); + } + } + } + + fclose(fp); + + // check for an animation definition file + std::string animationFile = file; + animationFile.erase(animationFile.find_last_of('.', std::string::npos)); + animationFile.append(".animations"); + + fp = fopen(animationFile.c_str(), "r"); + if (fp != NULL) + { + char *buffer = new char[80]; + std::string line; + std::string name; + std::string temp; + int start; + int end; + + while (!feof(fp)) + { + fgets(buffer, 80, fp); + line = buffer; + + if (strlen(buffer) > 5) // minimum length for a viable frame definition + { + // get animation name + int nameEnd = line.find_first_of(','); + if (nameEnd == std::string::npos) + continue; + name = line.substr(0, nameEnd); + + // get start frame index + int startEnd = line.find_first_of(',', nameEnd + 1); + if (startEnd == std::string::npos) + continue; + temp = line.substr(nameEnd + 1, startEnd); + start = atoi(temp.c_str()); + + // get end frame index + temp = line.substr(startEnd + 1, std::string::npos); + end = atoi(temp.c_str()); + + Ms3dAnimation *animation = new Ms3dAnimation(); + animation->name = name; + animation->startFrame = start; + animation->endFrame = end; + m_animations.push_back(*animation); + } + } + delete[] buffer; + + fclose(fp); + } + return true; +} + +bool Ms3d::ConvertToMesh(const std::string &file, float scaleFactor) +{ + FILE *fp = fopen(file.c_str(), "wb"); + if (fp == NULL) + return false; + + fputs("MESH", fp); + unsigned char version = 1; + fwrite(&version, 1, 1, fp); + + // vertices chunk + fputs("VTX", fp); + long numVertices = m_numVertices; + long sizeOfVertices = ((sizeof(float) * 3)) * numVertices + sizeof(long); + fwrite(&sizeOfVertices, sizeof(long), 1, fp); + fwrite(&numVertices, sizeof(long), 1, fp); + for (long i = 0; i < numVertices; ++i) + { + Ms3dVertex *vertex = &m_vertices[i]; + + vertex->vertex *= scaleFactor; + + fwrite(&vertex->vertex.x, sizeof(float), 1, fp); + fwrite(&vertex->vertex.y, sizeof(float), 1, fp); + fwrite(&vertex->vertex.z, sizeof(float), 1, fp); + } + + // triangles chunk + fputs("TRI", fp); + long numTriangles = m_numTriangles; + long sizeOfTriangles = (sizeof(int) * 4 + (sizeof(float) * 3) * 3 + (sizeof(float) * 2) * 3) * numTriangles + sizeof(long); + fwrite(&sizeOfTriangles, sizeof(long), 1, fp); + fwrite(&numTriangles, sizeof(long), 1, fp); + for (long i = 0; i < numTriangles; ++i) + { + Ms3dTriangle *triangle = &m_triangles[i]; + int index = triangle->vertices[0]; + fwrite(&index, sizeof(int), 1, fp); + index = triangle->vertices[1]; + fwrite(&index, sizeof(int), 1, fp); + index = triangle->vertices[2]; + fwrite(&index, sizeof(int), 1, fp); + + index = triangle->meshIndex; + fwrite(&index, sizeof(int), 1, fp); + + for (int j = 0; j < 3; ++j) + { + fwrite(&triangle->normals[j].x, sizeof(float), 1, fp); + fwrite(&triangle->normals[j].y, sizeof(float), 1, fp); + fwrite(&triangle->normals[j].z, sizeof(float), 1, fp); + } + for (int j = 0; j < 3; ++j) + { + fwrite(&triangle->texCoords[j].x, sizeof(float), 1, fp); + fwrite(&triangle->texCoords[j].y, sizeof(float), 1, fp); + } + } + + // sub-meshes / groups chunk + fputs("GRP", fp); + long numGroups = m_numMeshes; + long sizeOfGroupNames = 0; + for (long i = 0; i < numGroups; ++i) + sizeOfGroupNames += (m_meshes[i].name.length() + 1); + long sizeOfGroups = sizeOfGroupNames + (sizeof(int)) * numGroups + sizeof(long); + fwrite(&sizeOfGroups, sizeof(long), 1, fp); + fwrite(&numGroups, sizeof(long), 1, fp); + for (long i = 0; i < numGroups; ++i) + { + Ms3dMesh *mesh = &m_meshes[i]; + fwrite(mesh->name.c_str(), mesh->name.length(), 1, fp); + char c = '\0'; + fwrite(&c, 1, 1, fp); + int numTriangles = mesh->numTriangles; + fwrite(&numTriangles, sizeof(int), 1, fp); + } + + // joints chunk + fputs("JNT", fp); + long numJoints = m_numJoints; + long sizeOfJointNames = 0; + for (long i = 0; i < numJoints; ++i) + sizeOfJointNames += (m_joints[i].name.length() + 1); + long sizeOfJoints = sizeOfJointNames + (sizeof(int) + sizeof(float) * 3 + sizeof(float) * 3) * numJoints + sizeof(long); + fwrite(&sizeOfJoints, sizeof(long), 1, fp); + fwrite(&numJoints, sizeof(long), 1, fp); + for (long i = 0; i < numJoints; ++i) + { + Ms3dJoint *joint = &m_joints[i]; + + joint->position *= scaleFactor; + + fwrite(joint->name.c_str(), joint->name.length(), 1, fp); + char c = '\0'; + fwrite(&c, 1, 1, fp); + int parentIndex = FindIndexOfJoint(joint->parentName); + fwrite(&parentIndex, sizeof(int), 1, fp); + fwrite(&joint->position.x, sizeof(float), 1, fp); + fwrite(&joint->position.y, sizeof(float), 1, fp); + fwrite(&joint->position.z, sizeof(float), 1, fp); + fwrite(&joint->rotation.x, sizeof(float), 1, fp); + fwrite(&joint->rotation.y, sizeof(float), 1, fp); + fwrite(&joint->rotation.z, sizeof(float), 1, fp); + } + + // joints to vertices mapping chunk + fputs("JTV", fp); + long numMappings = numVertices; + long sizeOfJointMappings = (sizeof(int) + sizeof(float)) * numMappings + sizeof(long); + fwrite(&sizeOfJointMappings, sizeof(long), 1, fp); + fwrite(&numMappings, sizeof(long), 1, fp); + for (long i = 0; i < numMappings; ++i) + { + Ms3dVertex *vertex = &m_vertices[i]; + int jointIndex = vertex->jointIndex; + fwrite(&jointIndex, sizeof(int), 1, fp); + float weight = 1.0f; + fwrite(&weight, sizeof(float), 1, fp); + } + + // joint animation keyframes + fputs("JKF", fp); + long numFrames = m_numFrames; + long sizeOfJointFrames = ((6 * sizeof(float)) * m_numJoints) * numFrames + sizeof(long); + fwrite(&sizeOfJointFrames, sizeof(long), 1, fp); + fwrite(&numFrames, sizeof(long), 1, fp); + for (long i = 0; i < numFrames; ++i) + { + for (int j = 0; j < m_numJoints; ++j) + { + Ms3dJoint *joint = &m_joints[j]; + Ms3dKeyFrame *position; + Ms3dKeyFrame *rotation; + + if (i >= joint->numTranslationFrames) + position = &joint->translationFrames[0]; + else + position = &joint->translationFrames[i]; + if (i >= joint->numRotationFrames) + rotation = &joint->rotationFrames[0]; + else + rotation = &joint->rotationFrames[i]; + + position->param *= scaleFactor; + + fwrite(&position->param.x, sizeof(float), 1, fp); + fwrite(&position->param.y, sizeof(float), 1, fp); + fwrite(&position->param.z, sizeof(float), 1, fp); + fwrite(&rotation->param.x, sizeof(float), 1, fp); + fwrite(&rotation->param.y, sizeof(float), 1, fp); + fwrite(&rotation->param.z, sizeof(float), 1, fp); + } + } + + if (m_animations.size() > 0) + { + // figure out the size of all the animation name strings + long sizeofNames = 0; + for (unsigned int i = 0; i < m_animations.size(); ++i) + sizeofNames += m_animations[i].name.length() + 1; + + // animations chunk + fputs("ANI", fp); + long numAnimations = m_animations.size(); + long sizeofAnimations = (sizeof(long) * 2) * numAnimations + sizeofNames + sizeof(long); + fwrite(&sizeofAnimations, sizeof(long), 1, fp); + fwrite(&numAnimations, sizeof(long), 1, fp); + for (long i = 0; i < numAnimations; ++i) + { + long data; + const Ms3dAnimation *animation = &m_animations[i]; + //fputs(animation->name.c_str(), fp); + fputs(animation->name.c_str(), fp); + fwrite("\0", 1, 1, fp); + data = animation->startFrame; + fwrite(&data, sizeof(long), 1, fp); + data = animation->endFrame; + fwrite(&data, sizeof(long), 1, fp); + } + } + + fclose(fp); + + return true; +} + +int Ms3d::FindIndexOfJoint(const std::string &jointName) +{ + if (jointName.length() == 0) + return -1; + + for (int i = 0; i < m_numJoints; ++i) + { + Ms3dJoint *joint = &m_joints[i]; + if (joint->name == jointName) + return i; + } + + return -1; +} diff --git a/src/ms3d/ms3d.h b/src/ms3d/ms3d.h new file mode 100644 index 0000000..05cc540 --- /dev/null +++ b/src/ms3d/ms3d.h @@ -0,0 +1,146 @@ +#ifndef __MS3D_H_INCLUDED__ +#define __MS3D_H_INCLUDED__ + +#include +#include "../geometry/vector3.h" +#include "../geometry/vector2.h" +#include + +struct Ms3dHeader +{ + char id[10]; + long version; +}; + +struct Ms3dVertex +{ + unsigned char editorFlags; + Vector3 vertex; + char jointIndex; + unsigned char unused; +}; + +struct Ms3dTriangle +{ + unsigned short editorFlags; + unsigned short vertices[3]; + Vector3 normals[3]; + Vector2 texCoords[3]; + unsigned char smoothingGroup; + unsigned char meshIndex; +}; + +struct Ms3dMesh +{ + unsigned char editorFlags; + std::string name; + unsigned short numTriangles; + unsigned short *triangles; + char materialIndex; + + Ms3dMesh() + { + triangles = NULL; + } + + ~Ms3dMesh() + { + delete[] triangles; + } +}; + +struct Ms3dMaterial +{ + std::string name; + float ambient[4]; + float diffuse[4]; + float specular[4]; + float emissive[4]; + float shininess; + float transparency; + char mode; + std::string texture; + std::string alpha; +}; + +struct Ms3dKeyFrame +{ + float time; + Vector3 param; +}; + +struct Ms3dJoint +{ + unsigned char editorFlags; + std::string name; + std::string parentName; + Vector3 rotation; + Vector3 position; + unsigned short numRotationFrames; + unsigned short numTranslationFrames; + Ms3dKeyFrame *rotationFrames; + Ms3dKeyFrame *translationFrames; + + Ms3dJoint() + { + rotationFrames = NULL; + translationFrames = NULL; + } + + ~Ms3dJoint() + { + delete[] rotationFrames; + delete[] translationFrames; + } +}; + +struct Ms3dAnimation +{ + std::string name; + unsigned int startFrame; + unsigned int endFrame; +}; + +class Ms3d +{ +public: + Ms3d(); + virtual ~Ms3d() { Release(); } + + void Release(); + bool Load(const std::string &file); + bool ConvertToMesh(const std::string &file, float scaleFactor); + + unsigned short GetNumVertices() { return m_numVertices; } + unsigned short GetNumTriangles() { return m_numTriangles; } + unsigned short GetNumMeshes() { return m_numMeshes; } + unsigned short GetNumMaterials() { return m_numMaterials; } + unsigned short GetNumJoints() { return m_numJoints; } + float GetAnimationFps() { return m_animationFps; } + int GetNumFrames() { return m_numFrames; } + Ms3dVertex* GetVertices() { return m_vertices; } + Ms3dTriangle* GetTriangles() { return m_triangles; } + Ms3dMesh* GetMeshes() { return m_meshes; } + Ms3dMaterial* GetMaterials() { return m_materials; } + Ms3dJoint* GetJoints() { return m_joints; } + +private: + int FindIndexOfJoint(const std::string &jointName); + + unsigned short m_numVertices; + unsigned short m_numTriangles; + unsigned short m_numMeshes; + unsigned short m_numMaterials; + unsigned short m_numJoints; + float m_animationFps; + float m_editorAnimationTime; + int m_numFrames; + Ms3dVertex *m_vertices; + Ms3dTriangle *m_triangles; + Ms3dMesh *m_meshes; + Ms3dMaterial *m_materials; + Ms3dJoint *m_joints; + std::vector m_animations; +}; + +#endif diff --git a/src/util/files.cpp b/src/util/files.cpp new file mode 100644 index 0000000..38253dc --- /dev/null +++ b/src/util/files.cpp @@ -0,0 +1,25 @@ +#include "files.h" + +void ReadString(FILE *fp, std::string &buffer, int fixedLength) +{ + char c; + + if (fixedLength > 0) + { + for (int i = 0; i < fixedLength; ++i) + { + fread(&c, 1, 1, fp); + if (c != '\0') + buffer += c; + } + } + else + { + do + { + fread(&c, 1, 1, fp); + if (c != '\0') + buffer += c; + } while (c != '\0'); + } +} diff --git a/src/util/files.h b/src/util/files.h new file mode 100644 index 0000000..6ad1d72 --- /dev/null +++ b/src/util/files.h @@ -0,0 +1,9 @@ +#ifndef __UTIL_FILES_H_INCLUDED__ +#define __UTIL_FILES_H_INCLUDED__ + +#include +#include + +void ReadString(FILE *fp, std::string &buffer, int fixedLength = 0); + +#endif