added animation support to obj
This commit is contained in:
@@ -22,10 +22,10 @@ public:
|
||||
ObjLoader();
|
||||
~ObjLoader();
|
||||
|
||||
void load(ObjModel *o_result, char *t_fileName, float t_scale);
|
||||
void load(Frame *o_result, char *t_fileName, float t_scale);
|
||||
|
||||
private:
|
||||
void allocateObjMemory(FILE *t_file, ObjModel *t_result);
|
||||
void allocateObjMemory(FILE *t_file, Frame *t_result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
/*
|
||||
# ______ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2020, tyra - https://github.com/h4570/tyra
|
||||
# Licenced under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _TYRA_ANIM_STATE_
|
||||
#define _TYRA_ANIM_STATE_
|
||||
|
||||
#include <tamtypes.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 startFrame;
|
||||
u32 endFrame;
|
||||
float speed;
|
||||
float interpolation;
|
||||
u32 animType;
|
||||
u32 currentFrame;
|
||||
u32 nextFrame;
|
||||
} AnimState;
|
||||
|
||||
#endif
|
||||
@@ -15,17 +15,7 @@
|
||||
#include <math3d.h>
|
||||
#include "math/vector3.hpp"
|
||||
#include "math/point.hpp"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 startFrame;
|
||||
u32 endFrame;
|
||||
float speed;
|
||||
float interpolation;
|
||||
u32 animType;
|
||||
u32 currentFrame;
|
||||
u32 nextFrame;
|
||||
} MD2AnimState;
|
||||
#include "./anim_state.hpp"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -43,7 +33,7 @@ public:
|
||||
Point *coordinates;
|
||||
u32 *normalIndexes;
|
||||
MD2Triangle *triangles;
|
||||
MD2AnimState animState;
|
||||
AnimState animState;
|
||||
/** File name without extension */
|
||||
char *filename;
|
||||
MD2Model(char *t_md2File);
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
void loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale);
|
||||
void loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale, u16 framesAmount);
|
||||
void setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec);
|
||||
void loadDff(char *t_subfolder, char *t_dffFile, Vector3 &t_initPos, float t_scale);
|
||||
void setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <tamtypes.h>
|
||||
#include <math3d.h>
|
||||
#include "math/vector3.hpp"
|
||||
#include "./anim_state.hpp"
|
||||
|
||||
struct ObjMaterial
|
||||
{
|
||||
@@ -22,19 +23,26 @@ struct ObjMaterial
|
||||
u32 *verticeFaces, *coordinateFaces, *normalFaces;
|
||||
};
|
||||
|
||||
struct Frame
|
||||
{
|
||||
u16 number;
|
||||
u32 verticesCount, coordinatesCount, normalsCount, materialsCount;
|
||||
Vector3 *vertices __attribute__((aligned(16))),
|
||||
*coordinates __attribute__((aligned(16))),
|
||||
*normals __attribute__((aligned(16)));
|
||||
ObjMaterial *materials;
|
||||
};
|
||||
|
||||
/** Class which have common types for all 3D objects */
|
||||
class ObjModel
|
||||
{
|
||||
|
||||
public:
|
||||
u32 verticesCount, coordinatesCount, normalsCount, materialsCount;
|
||||
Vector3 *vertices __attribute__((aligned(16))),
|
||||
*coordinates __attribute__((aligned(16))),
|
||||
*normals __attribute__((aligned(16)));
|
||||
|
||||
/** File name without extension */
|
||||
char *filename;
|
||||
ObjMaterial *materials;
|
||||
u16 frameCount;
|
||||
Frame *frames;
|
||||
AnimState animState;
|
||||
|
||||
ObjModel(char *t_objFile);
|
||||
~ObjModel();
|
||||
@@ -43,6 +51,8 @@ public:
|
||||
u8 isMemoryAllocated;
|
||||
|
||||
private:
|
||||
Vector3 calc3Vectors[3];
|
||||
Vector3 calcVector;
|
||||
void fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_materialI, u32 t_getI, u32 t_setI);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ class String
|
||||
{
|
||||
|
||||
public:
|
||||
static char *createU32ToString(u32 a);
|
||||
static char *createWithLeadingZeros(char *a);
|
||||
static char *createCopy(char *source);
|
||||
static u32 getLength(char *a);
|
||||
static char *createConcatenated(char *a, char *b);
|
||||
|
||||
@@ -30,7 +30,7 @@ ObjLoader::~ObjLoader() {}
|
||||
* Notice: At this moment textures names are MATERIAL names from .obj file!
|
||||
* Notice 2: Faces MUST be triangulated (check out blender export settings).
|
||||
*/
|
||||
void ObjLoader::load(ObjModel *o_result, char *t_filename, float t_scale)
|
||||
void ObjLoader::load(Frame *o_result, char *t_filename, float t_scale)
|
||||
{
|
||||
FILE *file = fopen(t_filename, "rb");
|
||||
if (file == NULL)
|
||||
@@ -102,7 +102,7 @@ void ObjLoader::load(ObjModel *o_result, char *t_filename, float t_scale)
|
||||
}
|
||||
|
||||
/** Calculate how many vertices(v), coordinates(vt), normals(vn) and faces(f) have .obj file */
|
||||
void ObjLoader::allocateObjMemory(FILE *t_file, ObjModel *o_result)
|
||||
void ObjLoader::allocateObjMemory(FILE *t_file, Frame *o_result)
|
||||
{
|
||||
o_result->verticesCount = 0;
|
||||
o_result->coordinatesCount = 0;
|
||||
@@ -157,5 +157,5 @@ void ObjLoader::allocateObjMemory(FILE *t_file, ObjModel *o_result)
|
||||
o_result->vertices = new Vector3[o_result->verticesCount];
|
||||
o_result->coordinates = new Vector3[o_result->coordinatesCount];
|
||||
o_result->normals = new Vector3[o_result->normalsCount];
|
||||
o_result->isMemoryAllocated = true;
|
||||
// o_result->isMemoryAllocated = true;
|
||||
}
|
||||
|
||||
+35
-10
@@ -78,16 +78,36 @@ void Mesh::setDff(Vector3 &t_initPos, DffModel *t_dffModel, MeshSpec *t_spec)
|
||||
isDffLoaded = true;
|
||||
}
|
||||
|
||||
void Mesh::loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale)
|
||||
void Mesh::loadObj(char *t_subfolder, char *t_objFile, Vector3 &t_initPos, float t_scale, u16 framesAmount)
|
||||
{
|
||||
createSpecIfNotCreated();
|
||||
ObjLoader loader = ObjLoader();
|
||||
obj = new ObjModel(t_objFile);
|
||||
char *objPath = String::createConcatenated(t_subfolder, t_objFile);
|
||||
loader.load(obj, objPath, t_scale);
|
||||
delete[] objPath;
|
||||
|
||||
obj->frameCount = framesAmount;
|
||||
obj->frames = new Frame[framesAmount];
|
||||
|
||||
char *part1 = String::createConcatenated(t_subfolder, t_objFile); // "folder/object"
|
||||
char *part2 = String::createConcatenated(part1, "_"); // "folder/object_"
|
||||
delete[] part1;
|
||||
|
||||
for (u16 i = 0; i < framesAmount; i++)
|
||||
{
|
||||
char *part3 = String::createU32ToString(i + 1); // 0 -> "1"
|
||||
char *part4 = String::createWithLeadingZeros(part3); // "000001"
|
||||
char *part5 = String::createConcatenated(part2, part4); // "folder/object_000001"
|
||||
char *finalPath = String::createConcatenated(part5, ".obj"); // "folder/object_000001.obj"
|
||||
loader.load(&obj->frames[i], finalPath, t_scale);
|
||||
delete[] part3;
|
||||
delete[] part4;
|
||||
delete[] part5;
|
||||
delete[] finalPath;
|
||||
}
|
||||
|
||||
delete[] part2;
|
||||
|
||||
position = t_initPos;
|
||||
setVerticesReference(obj->getFacesCount(), obj->vertices);
|
||||
setVerticesReference(obj->getFacesCount(), obj->frames[0].vertices);
|
||||
setDefaultColor();
|
||||
isObjLoaded = true;
|
||||
loadTextures(t_subfolder, ".bmp");
|
||||
@@ -100,7 +120,7 @@ void Mesh::setObj(Vector3 &t_initPos, ObjModel *t_objModel, MeshSpec *t_spec)
|
||||
spec = t_spec;
|
||||
isSpecInitialized = true;
|
||||
obj = t_objModel;
|
||||
setVerticesReference(obj->getFacesCount(), obj->vertices);
|
||||
setVerticesReference(obj->getFacesCount(), obj->frames[0].vertices);
|
||||
setDefaultColor();
|
||||
isObjLoaded = true;
|
||||
}
|
||||
@@ -159,10 +179,10 @@ void Mesh::loadTextures(char *t_subfolder, char *t_extension)
|
||||
BmpLoader bmpLoader = BmpLoader();
|
||||
if (isObjLoaded)
|
||||
{
|
||||
spec->textures = new Texture[obj->materialsCount];
|
||||
for (u8 i = 0; i < obj->materialsCount; i++)
|
||||
spec->textures = new Texture[obj->frames[0].materialsCount];
|
||||
for (u8 i = 0; i < obj->frames[0].materialsCount; i++)
|
||||
{
|
||||
bmpLoader.load(spec->textures[i], t_subfolder, obj->materials[i].materialName, t_extension);
|
||||
bmpLoader.load(spec->textures[i], t_subfolder, obj->frames[0].materials[i].materialName, t_extension);
|
||||
setDefaultWrapSettings(spec->textures[i].wrapSettings);
|
||||
}
|
||||
}
|
||||
@@ -265,8 +285,13 @@ void Mesh::playAnimation(u32 t_startFrame, u32 t_endFrame)
|
||||
md2->animState.startFrame = t_startFrame;
|
||||
md2->animState.endFrame = t_endFrame;
|
||||
}
|
||||
else if (isObjLoaded == 1)
|
||||
{
|
||||
obj->animState.startFrame = t_startFrame;
|
||||
obj->animState.endFrame = t_endFrame;
|
||||
}
|
||||
else
|
||||
PRINT_ERR("Animation is only supported in MD2 format!");
|
||||
PRINT_ERR("Animation is only supported in MD2/OBJ format!");
|
||||
}
|
||||
|
||||
/** Returns next farthest vertex of 3D object
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
|
||||
ObjModel::ObjModel(char *t_objFile)
|
||||
{
|
||||
animState.startFrame = 0;
|
||||
animState.endFrame = 0;
|
||||
animState.interpolation = 0.0F;
|
||||
animState.animType = 0;
|
||||
animState.currentFrame = 0;
|
||||
animState.nextFrame = 0;
|
||||
animState.speed = 0.1F;
|
||||
filename = String::createWithoutExtension(t_objFile);
|
||||
}
|
||||
|
||||
@@ -26,17 +33,18 @@ ObjModel::~ObjModel()
|
||||
{
|
||||
if (isMemoryAllocated == true)
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] coordinates;
|
||||
delete[] normals;
|
||||
for (u16 i = 0; i < materialsCount; i++)
|
||||
{
|
||||
delete[] materials[i].verticeFaces;
|
||||
delete[] materials[i].coordinateFaces;
|
||||
delete[] materials[i].normalFaces;
|
||||
delete[] materials[i].materialName;
|
||||
}
|
||||
delete[] materials;
|
||||
// TODO !!!!
|
||||
// delete[] vertices;
|
||||
// delete[] coordinates;
|
||||
// delete[] normals;
|
||||
// for (u16 i = 0; i < materialsCount; i++)
|
||||
// {
|
||||
// delete[] materials[i].verticeFaces;
|
||||
// delete[] materials[i].coordinateFaces;
|
||||
// delete[] materials[i].normalFaces;
|
||||
// delete[] materials[i].materialName;
|
||||
// }
|
||||
// delete[] materials;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,48 +54,75 @@ ObjModel::~ObjModel()
|
||||
|
||||
u32 ObjModel::getFacesCount()
|
||||
{
|
||||
u32 result = 0;
|
||||
for (u16 i = 0; i < materialsCount; i++)
|
||||
result += materials[i].facesCount;
|
||||
u32 result = 0; // TODO
|
||||
for (u16 i = 0; i < frames[0].materialsCount; i++)
|
||||
result += frames[0].materials[i].facesCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 ObjModel::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, Vector3 &t_cameraPos, float t_scale, u8 t_shouldBeBackfaceCulled)
|
||||
{
|
||||
u32 addedFaces = 0;
|
||||
for (u32 j = 0; j < materials[t_materialIndex].facesCount; j += 3)
|
||||
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(
|
||||
&t_cameraPos,
|
||||
&vertices[materials[t_materialIndex].verticeFaces[j]],
|
||||
&vertices[materials[t_materialIndex].verticeFaces[j + 1]],
|
||||
&vertices[materials[t_materialIndex].verticeFaces[j + 2]]) == 0)
|
||||
|
||||
animState.interpolation += animState.speed; // TODO move it out
|
||||
if (animState.interpolation >= 1.0F)
|
||||
{
|
||||
animState.interpolation = 0.0F;
|
||||
animState.currentFrame = animState.nextFrame;
|
||||
if (++animState.nextFrame > animState.endFrame)
|
||||
animState.nextFrame = animState.startFrame;
|
||||
}
|
||||
|
||||
for (u32 j = 0; j < frames[animState.currentFrame].materials[t_materialIndex].facesCount; j += 3)
|
||||
{
|
||||
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||
{
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, t_materialIndex, j, addedFaces++);
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, t_materialIndex, j + 1, addedFaces++);
|
||||
fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, t_materialIndex, j + 2, addedFaces++);
|
||||
const ObjMaterial CURR_MAT = frames[animState.currentFrame].materials[t_materialIndex];
|
||||
const Vector3 CURR_VERT = frames[animState.currentFrame].vertices[CURR_MAT.verticeFaces[j + iVert]];
|
||||
if (animState.startFrame == animState.endFrame)
|
||||
{
|
||||
calc3Vectors[iVert].x = CURR_VERT.x * t_scale;
|
||||
calc3Vectors[iVert].y = CURR_VERT.y * t_scale;
|
||||
calc3Vectors[iVert].z = CURR_VERT.z * t_scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
const Vector3 NEXT_VERT = frames[animState.nextFrame].vertices[CURR_MAT.verticeFaces[j + iVert]];
|
||||
calcVector.setByLerp(CURR_VERT, NEXT_VERT, animState.interpolation);
|
||||
calc3Vectors[iVert].x = calcVector.x * t_scale;
|
||||
calc3Vectors[iVert].y = calcVector.y * t_scale;
|
||||
calc3Vectors[iVert].z = calcVector.z * t_scale;
|
||||
}
|
||||
}
|
||||
if (!t_shouldBeBackfaceCulled || Vector3::shouldBeBackfaceCulled(&t_cameraPos, &calc3Vectors[2], &calc3Vectors[1], &calc3Vectors[0]) == 0)
|
||||
for (u32 iVert = 0; iVert < 3; iVert++)
|
||||
{
|
||||
const u32 CURR_FRAME = animState.currentFrame;
|
||||
o_vertices[addedFaces][0] = calc3Vectors[iVert].x;
|
||||
o_vertices[addedFaces][1] = calc3Vectors[iVert].y;
|
||||
o_vertices[addedFaces][2] = calc3Vectors[iVert].z;
|
||||
o_vertices[addedFaces][3] = 1.0F;
|
||||
|
||||
o_normals[addedFaces][0] = frames[CURR_FRAME].normals[frames[CURR_FRAME].materials[t_materialIndex].normalFaces[j]].x;
|
||||
o_normals[addedFaces][1] = frames[CURR_FRAME].normals[frames[CURR_FRAME].materials[t_materialIndex].normalFaces[j]].y;
|
||||
o_normals[addedFaces][2] = frames[CURR_FRAME].normals[frames[CURR_FRAME].materials[t_materialIndex].normalFaces[j]].z;
|
||||
o_normals[addedFaces][3] = 1.0F;
|
||||
|
||||
o_coordinates[addedFaces][0] = frames[CURR_FRAME].coordinates[frames[CURR_FRAME].materials[t_materialIndex].coordinateFaces[j]].x;
|
||||
o_coordinates[addedFaces][1] = frames[CURR_FRAME].coordinates[frames[CURR_FRAME].materials[t_materialIndex].coordinateFaces[j]].y;
|
||||
o_coordinates[addedFaces][2] = 1.0F;
|
||||
o_coordinates[addedFaces][3] = 1.0F;
|
||||
|
||||
o_colors[addedFaces][0] = 1.0F;
|
||||
o_colors[addedFaces][1] = 1.0F;
|
||||
o_colors[addedFaces][2] = 1.0F;
|
||||
o_colors[addedFaces++][3] = 1.0F;
|
||||
}
|
||||
// fillNextFace(o_vertices, o_normals, o_coordinates, o_colors, t_materialIndex, j, addedFaces++);
|
||||
}
|
||||
return addedFaces;
|
||||
}
|
||||
|
||||
void ObjModel::fillNextFace(VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, VECTOR *o_colors, u32 t_materialI, u32 t_getI, u32 t_setI)
|
||||
{
|
||||
o_vertices[t_setI][0] = vertices[materials[t_materialI].verticeFaces[t_getI]].x;
|
||||
o_vertices[t_setI][1] = vertices[materials[t_materialI].verticeFaces[t_getI]].y;
|
||||
o_vertices[t_setI][2] = vertices[materials[t_materialI].verticeFaces[t_getI]].z;
|
||||
o_vertices[t_setI][3] = 1.0F;
|
||||
|
||||
o_normals[t_setI][0] = normals[materials[t_materialI].normalFaces[t_getI]].x;
|
||||
o_normals[t_setI][1] = normals[materials[t_materialI].normalFaces[t_getI]].y;
|
||||
o_normals[t_setI][2] = normals[materials[t_materialI].normalFaces[t_getI]].z;
|
||||
o_normals[t_setI][3] = 1.0F;
|
||||
|
||||
o_coordinates[t_setI][0] = coordinates[materials[t_materialI].coordinateFaces[t_getI]].x;
|
||||
o_coordinates[t_setI][1] = coordinates[materials[t_materialI].coordinateFaces[t_getI]].y;
|
||||
o_coordinates[t_setI][2] = 1.0F;
|
||||
o_coordinates[t_setI][3] = 1.0F;
|
||||
|
||||
o_colors[t_setI][0] = 1.0F;
|
||||
o_colors[t_setI][1] = 1.0F;
|
||||
o_colors[t_setI][2] = 1.0F;
|
||||
o_colors[t_setI][3] = 1.0F;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ void Renderer::draw(Mesh *t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
|
||||
VECTOR *coordinates = new VECTOR[vertCount];
|
||||
VECTOR *colors = new VECTOR[vertCount];
|
||||
if (t_mesh->isObjLoaded)
|
||||
for (u32 i = 0; i < t_mesh->obj->materialsCount; i++)
|
||||
for (u32 i = 0; i < t_mesh->obj->frames[0].materialsCount; i++)
|
||||
{
|
||||
changeTexture(t_mesh, i);
|
||||
vertCount = t_mesh->getDrawData(i, vertices, normals, coordinates, colors, *renderData.cameraPosition);
|
||||
|
||||
@@ -9,8 +9,31 @@
|
||||
*/
|
||||
|
||||
#include "../include/utils/string.hpp"
|
||||
#include "../include/utils/debug.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
char *String::createU32ToString(u32 a)
|
||||
{
|
||||
char *result = new char[(((sizeof a) * CHAR_BIT) + 2) / 3 + 2];
|
||||
sprintf(result, "%d", a);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Converts "123" to "000123". 6 digits length */
|
||||
char *String::createWithLeadingZeros(char *a)
|
||||
{
|
||||
const u8 digitsAmount = 6;
|
||||
char *part = createConcatenated("00000000", a);
|
||||
u16 partLength = getLength(part);
|
||||
u16 insert = 0;
|
||||
char *result = new char[digitsAmount + 1];
|
||||
for (u16 i = partLength - digitsAmount; i < partLength; i++)
|
||||
result[insert++] = part[i];
|
||||
delete[] part;
|
||||
result[digitsAmount] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
char *String::createWithoutExtension(char *source)
|
||||
{
|
||||
u32 length = 0;
|
||||
@@ -34,6 +57,7 @@ char *String::createCopy(char *source)
|
||||
return res;
|
||||
}
|
||||
|
||||
// For test\0 will return 4
|
||||
u32 String::getLength(char *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
|
||||
Reference in New Issue
Block a user