aboutsummaryrefslogtreecommitdiff
path: root/src/models.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/models.c')
-rw-r--r--src/models.c234
1 files changed, 164 insertions, 70 deletions
diff --git a/src/models.c b/src/models.c
index bef19e10..0a692f5c 100644
--- a/src/models.c
+++ b/src/models.c
@@ -1,17 +1,19 @@
/**********************************************************************************************
*
-* raylib.models - Basic functions to draw 3d shapes and 3d models
+* raylib.models - Basic functions to deal with 3d shapes and 3d models
*
* CONFIGURATION:
*
-* #define SUPPORT_FILEFORMAT_OBJ / SUPPORT_LOAD_OBJ
+* #define SUPPORT_FILEFORMAT_OBJ
+* Selected desired fileformats to be supported for loading.
*
* #define SUPPORT_FILEFORMAT_MTL
+* Selected desired fileformats to be supported for loading.
*
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -30,6 +32,12 @@
*
**********************************************************************************************/
+// Default configuration flags (supported features)
+//-------------------------------------------------
+#define SUPPORT_FILEFORMAT_OBJ
+#define SUPPORT_FILEFORMAT_MTL
+//-------------------------------------------------
+
#include "raylib.h"
#if defined(PLATFORM_ANDROID)
@@ -61,8 +69,12 @@
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
+#if defined(SUPPORT_FILEFORMAT_OBJ)
static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data
+#endif
+#if defined(SUPPORT_FILEFORMAT_MTL)
static Material LoadMTL(const char *fileName); // Load MTL material data
+#endif
static Mesh GenMeshHeightmap(Image image, Vector3 size);
static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
@@ -580,8 +592,11 @@ Mesh LoadMesh(const char *fileName)
{
Mesh mesh = { 0 };
- if (strcmp(GetExtension(fileName), "obj") == 0) mesh = LoadOBJ(fileName);
- else TraceLog(WARNING, "[%s] Mesh extension not recognized, it can't be loaded", fileName);
+#if defined(SUPPORT_FILEFORMAT_OBJ)
+ if (IsFileExtension(fileName, ".obj")) mesh = LoadOBJ(fileName);
+#else
+ TraceLog(WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName);
+#endif
if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded");
else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
@@ -592,13 +607,13 @@ Mesh LoadMesh(const char *fileName)
}
// Load mesh from vertex data
-// NOTE: All vertex data arrays must be same size: numVertex
-Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData)
+// NOTE: All vertex data arrays must be same size: vertexCount
+Mesh LoadMeshEx(int vertexCount, float *vData, float *vtData, float *vnData, Color *cData)
{
Mesh mesh = { 0 };
- mesh.vertexCount = numVertex;
- mesh.triangleCount = numVertex/3;
+ mesh.vertexCount = vertexCount;
+ mesh.triangleCount = vertexCount/3;
mesh.vertices = vData;
mesh.texcoords = vtData;
mesh.texcoords2 = NULL;
@@ -690,8 +705,11 @@ Material LoadMaterial(const char *fileName)
{
Material material = { 0 };
- if (strcmp(GetExtension(fileName), "mtl") == 0) material = LoadMTL(fileName);
- else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName);
+#if defined(SUPPORT_FILEFORMAT_MTL)
+ if (IsFileExtension(fileName, ".mtl")) material = LoadMTL(fileName);
+#else
+ TraceLog(WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName);
+#endif
return material;
}
@@ -736,9 +754,9 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Color *pixels = GetImageData(heightmap);
// NOTE: One vertex per pixel
- int numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
+ int triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
- mesh.vertexCount = numTriangles*3;
+ mesh.vertexCount = triangleCount*3;
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
@@ -1200,11 +1218,13 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+
+ Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
//Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates
- model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
+ model.transform = MatrixMultiply(model.transform, matTransform);
model.material.colDiffuse = tint; // TODO: Multiply tint color by diffuse color?
rlglDrawMesh(model.mesh, model.material, model.transform);
@@ -1521,11 +1541,11 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
result.hit = true;
result.distance = t;
result.hit = true;
- result.hitNormal = VectorCrossProduct(edge1, edge2);
- VectorNormalize(&result.hitNormal);
+ result.normal = VectorCrossProduct(edge1, edge2);
+ VectorNormalize(&result.normal);
Vector3 rayDir = ray.direction;
VectorScale(&rayDir, t);
- result.hitPosition = VectorAdd(ray.position, rayDir);
+ result.position = VectorAdd(ray.position, rayDir);
}
return result;
@@ -1548,8 +1568,8 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
VectorScale(&rayDir, t);
result.hit = true;
result.distance = t;
- result.hitNormal = (Vector3){ 0.0, 1.0, 0.0 };
- result.hitPosition = VectorAdd(ray.position, rayDir);
+ result.normal = (Vector3){ 0.0, 1.0, 0.0 };
+ result.position = VectorAdd(ray.position, rayDir);
}
}
@@ -1588,6 +1608,7 @@ BoundingBox CalculateBoundingBox(Mesh mesh)
// Module specific Functions Definition
//----------------------------------------------------------------------------------
+#if defined(SUPPORT_FILEFORMAT_OBJ)
// Load OBJ mesh data
static Mesh LoadOBJ(const char *fileName)
{
@@ -1596,10 +1617,10 @@ static Mesh LoadOBJ(const char *fileName)
char dataType;
char comments[200];
- int numVertex = 0;
- int numNormals = 0;
- int numTexCoords = 0;
- int numTriangles = 0;
+ int vertexCount = 0;
+ int normalCount = 0;
+ int texcoordCount = 0;
+ int triangleCount = 0;
FILE *objFile;
@@ -1611,7 +1632,7 @@ static Mesh LoadOBJ(const char *fileName)
return mesh;
}
- // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
+ // First reading pass: Get vertexCount, normalCount, texcoordCount, triangleCount
// NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
// NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
while (!feof(objFile))
@@ -1635,40 +1656,40 @@ static Mesh LoadOBJ(const char *fileName)
if (dataType == 't') // Read texCoord
{
- numTexCoords++;
+ texcoordCount++;
fgets(comments, 200, objFile);
}
else if (dataType == 'n') // Read normals
{
- numNormals++;
+ normalCount++;
fgets(comments, 200, objFile);
}
else // Read vertex
{
- numVertex++;
+ vertexCount++;
fgets(comments, 200, objFile);
}
} break;
case 'f':
{
- numTriangles++;
+ triangleCount++;
fgets(comments, 200, objFile);
} break;
default: break;
}
}
- TraceLog(DEBUG, "[%s] Model num vertices: %i", fileName, numVertex);
- TraceLog(DEBUG, "[%s] Model num texcoords: %i", fileName, numTexCoords);
- TraceLog(DEBUG, "[%s] Model num normals: %i", fileName, numNormals);
- TraceLog(DEBUG, "[%s] Model num triangles: %i", fileName, numTriangles);
+ TraceLog(DEBUG, "[%s] Model vertices: %i", fileName, vertexCount);
+ TraceLog(DEBUG, "[%s] Model texcoords: %i", fileName, texcoordCount);
+ TraceLog(DEBUG, "[%s] Model normals: %i", fileName, normalCount);
+ TraceLog(DEBUG, "[%s] Model triangles: %i", fileName, triangleCount);
// Once we know the number of vertices to store, we create required arrays
- Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3));
+ Vector3 *midVertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3));
Vector3 *midNormals = NULL;
- if (numNormals > 0) midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3));
+ if (normalCount > 0) midNormals = (Vector3 *)malloc(normalCount*sizeof(Vector3));
Vector2 *midTexCoords = NULL;
- if (numTexCoords > 0) midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2));
+ if (texcoordCount > 0) midTexCoords = (Vector2 *)malloc(texcoordCount*sizeof(Vector2));
int countVertex = 0;
int countNormals = 0;
@@ -1719,7 +1740,7 @@ static Mesh LoadOBJ(const char *fileName)
// At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals
// Now we can organize that data into our Mesh struct
- mesh.vertexCount = numTriangles*3;
+ mesh.vertexCount = triangleCount*3;
// Additional arrays to store vertex data as floats
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
@@ -1731,11 +1752,11 @@ static Mesh LoadOBJ(const char *fileName)
int tcCounter = 0; // Used to count texcoords float by float
int nCounter = 0; // Used to count normals float by float
- int vNum[3], vtNum[3], vnNum[3]; // Used to store triangle indices for v, vt, vn
+ int vCount[3], vtCount[3], vnCount[3]; // Used to store triangle indices for v, vt, vn
rewind(objFile); // Return to the beginning of the file, to read again
- if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
+ if (normalCount == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
// Third reading pass: Get faces (triangles) data and fill VertexArray
while (!feof(objFile))
@@ -1749,43 +1770,43 @@ static Mesh LoadOBJ(const char *fileName)
{
// NOTE: It could be that OBJ does not have normals or texcoords defined!
- if ((numNormals == 0) && (numTexCoords == 0)) fscanf(objFile, "%i %i %i", &vNum[0], &vNum[1], &vNum[2]);
- else if (numNormals == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vNum[0], &vtNum[0], &vNum[1], &vtNum[1], &vNum[2], &vtNum[2]);
- else if (numTexCoords == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vNum[0], &vnNum[0], &vNum[1], &vnNum[1], &vNum[2], &vnNum[2]);
- else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vNum[0], &vtNum[0], &vnNum[0], &vNum[1], &vtNum[1], &vnNum[1], &vNum[2], &vtNum[2], &vnNum[2]);
+ if ((normalCount == 0) && (texcoordCount == 0)) fscanf(objFile, "%i %i %i", &vCount[0], &vCount[1], &vCount[2]);
+ else if (normalCount == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vCount[0], &vtCount[0], &vCount[1], &vtCount[1], &vCount[2], &vtCount[2]);
+ else if (texcoordCount == 0) fscanf(objFile, "%i//%i %i//%i %i//%i", &vCount[0], &vnCount[0], &vCount[1], &vnCount[1], &vCount[2], &vnCount[2]);
+ else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vCount[0], &vtCount[0], &vnCount[0], &vCount[1], &vtCount[1], &vnCount[1], &vCount[2], &vtCount[2], &vnCount[2]);
- mesh.vertices[vCounter] = midVertices[vNum[0]-1].x;
- mesh.vertices[vCounter + 1] = midVertices[vNum[0]-1].y;
- mesh.vertices[vCounter + 2] = midVertices[vNum[0]-1].z;
+ mesh.vertices[vCounter] = midVertices[vCount[0]-1].x;
+ mesh.vertices[vCounter + 1] = midVertices[vCount[0]-1].y;
+ mesh.vertices[vCounter + 2] = midVertices[vCount[0]-1].z;
vCounter += 3;
- mesh.vertices[vCounter] = midVertices[vNum[1]-1].x;
- mesh.vertices[vCounter + 1] = midVertices[vNum[1]-1].y;
- mesh.vertices[vCounter + 2] = midVertices[vNum[1]-1].z;
+ mesh.vertices[vCounter] = midVertices[vCount[1]-1].x;
+ mesh.vertices[vCounter + 1] = midVertices[vCount[1]-1].y;
+ mesh.vertices[vCounter + 2] = midVertices[vCount[1]-1].z;
vCounter += 3;
- mesh.vertices[vCounter] = midVertices[vNum[2]-1].x;
- mesh.vertices[vCounter + 1] = midVertices[vNum[2]-1].y;
- mesh.vertices[vCounter + 2] = midVertices[vNum[2]-1].z;
+ mesh.vertices[vCounter] = midVertices[vCount[2]-1].x;
+ mesh.vertices[vCounter + 1] = midVertices[vCount[2]-1].y;
+ mesh.vertices[vCounter + 2] = midVertices[vCount[2]-1].z;
vCounter += 3;
- if (numNormals > 0)
+ if (normalCount > 0)
{
- mesh.normals[nCounter] = midNormals[vnNum[0]-1].x;
- mesh.normals[nCounter + 1] = midNormals[vnNum[0]-1].y;
- mesh.normals[nCounter + 2] = midNormals[vnNum[0]-1].z;
+ mesh.normals[nCounter] = midNormals[vnCount[0]-1].x;
+ mesh.normals[nCounter + 1] = midNormals[vnCount[0]-1].y;
+ mesh.normals[nCounter + 2] = midNormals[vnCount[0]-1].z;
nCounter += 3;
- mesh.normals[nCounter] = midNormals[vnNum[1]-1].x;
- mesh.normals[nCounter + 1] = midNormals[vnNum[1]-1].y;
- mesh.normals[nCounter + 2] = midNormals[vnNum[1]-1].z;
+ mesh.normals[nCounter] = midNormals[vnCount[1]-1].x;
+ mesh.normals[nCounter + 1] = midNormals[vnCount[1]-1].y;
+ mesh.normals[nCounter + 2] = midNormals[vnCount[1]-1].z;
nCounter += 3;
- mesh.normals[nCounter] = midNormals[vnNum[2]-1].x;
- mesh.normals[nCounter + 1] = midNormals[vnNum[2]-1].y;
- mesh.normals[nCounter + 2] = midNormals[vnNum[2]-1].z;
+ mesh.normals[nCounter] = midNormals[vnCount[2]-1].x;
+ mesh.normals[nCounter + 1] = midNormals[vnCount[2]-1].y;
+ mesh.normals[nCounter + 2] = midNormals[vnCount[2]-1].z;
nCounter += 3;
}
else
{
// If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)]
- Vector3 norm = VectorCrossProduct(VectorSubtract(midVertices[vNum[1]-1], midVertices[vNum[0]-1]), VectorSubtract(midVertices[vNum[2]-1], midVertices[vNum[0]-1]));
+ Vector3 norm = VectorCrossProduct(VectorSubtract(midVertices[vCount[1]-1], midVertices[vCount[0]-1]), VectorSubtract(midVertices[vCount[2]-1], midVertices[vCount[0]-1]));
VectorNormalize(&norm);
mesh.normals[nCounter] = norm.x;
@@ -1802,18 +1823,18 @@ static Mesh LoadOBJ(const char *fileName)
nCounter += 3;
}
- if (numTexCoords > 0)
+ if (texcoordCount > 0)
{
// NOTE: If using negative texture coordinates with a texture filter of GL_CLAMP_TO_EDGE doesn't work!
// NOTE: Texture coordinates are Y flipped upside-down
- mesh.texcoords[tcCounter] = midTexCoords[vtNum[0]-1].x;
- mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[0]-1].y;
+ mesh.texcoords[tcCounter] = midTexCoords[vtCount[0]-1].x;
+ mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[0]-1].y;
tcCounter += 2;
- mesh.texcoords[tcCounter] = midTexCoords[vtNum[1]-1].x;
- mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[1]-1].y;
+ mesh.texcoords[tcCounter] = midTexCoords[vtCount[1]-1].x;
+ mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[1]-1].y;
tcCounter += 2;
- mesh.texcoords[tcCounter] = midTexCoords[vtNum[2]-1].x;
- mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtNum[2]-1].y;
+ mesh.texcoords[tcCounter] = midTexCoords[vtCount[2]-1].x;
+ mesh.texcoords[tcCounter + 1] = 1.0f - midTexCoords[vtCount[2]-1].y;
tcCounter += 2;
}
} break;
@@ -1824,7 +1845,77 @@ static Mesh LoadOBJ(const char *fileName)
fclose(objFile);
// Security check, just in case no normals or no texcoords defined in OBJ
- if (numTexCoords == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f;
+ if (texcoordCount == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f;
+ else
+ {
+ // Attempt to calculate mesh tangents and binormals using positions and texture coordinates
+ mesh.tangents = (float *)malloc(mesh.vertexCount*3*sizeof(float));
+ // mesh.binormals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
+
+ int vCount = 0;
+ int uvCount = 0;
+ while (vCount < mesh.vertexCount*3)
+ {
+ // Calculate mesh vertex positions as Vector3
+ Vector3 v0 = { mesh.vertices[vCount], mesh.vertices[vCount + 1], mesh.vertices[vCount + 2] };
+ Vector3 v1 = { mesh.vertices[vCount + 3], mesh.vertices[vCount + 4], mesh.vertices[vCount + 5] };
+ Vector3 v2 = { mesh.vertices[vCount + 6], mesh.vertices[vCount + 7], mesh.vertices[vCount + 8] };
+
+ // Calculate mesh texture coordinates as Vector2
+ Vector2 uv0 = { mesh.texcoords[uvCount + 0], mesh.texcoords[uvCount + 1] };
+ Vector2 uv1 = { mesh.texcoords[uvCount + 2], mesh.texcoords[uvCount + 3] };
+ Vector2 uv2 = { mesh.texcoords[uvCount + 4], mesh.texcoords[uvCount + 5] };
+
+ // Calculate edges of the triangle (position delta)
+ Vector3 deltaPos1 = VectorSubtract(v1, v0);
+ Vector3 deltaPos2 = VectorSubtract(v2, v0);
+
+ // UV delta
+ Vector2 deltaUV1 = { uv1.x - uv0.x, uv1.y - uv0.y };
+ Vector2 deltaUV2 = { uv2.x - uv0.x, uv2.y - uv0.y };
+
+ float r = 1.0f/(deltaUV1.x*deltaUV2.y - deltaUV1.y*deltaUV2.x);
+ Vector3 t1 = { deltaPos1.x*deltaUV2.y, deltaPos1.y*deltaUV2.y, deltaPos1.z*deltaUV2.y };
+ Vector3 t2 = { deltaPos2.x*deltaUV1.y, deltaPos2.y*deltaUV1.y, deltaPos2.z*deltaUV1.y };
+ // Vector3 b1 = { deltaPos2.x*deltaUV1.x, deltaPos2.y*deltaUV1.x, deltaPos2.z*deltaUV1.x };
+ // Vector3 b2 = { deltaPos1.x*deltaUV2.x, deltaPos1.y*deltaUV2.x, deltaPos1.z*deltaUV2.x };
+
+ // Calculate vertex tangent
+ Vector3 tangent = VectorSubtract(t1, t2);
+ VectorScale(&tangent, r);
+
+ // Apply calculated tangents data to mesh struct
+ mesh.tangents[vCount + 0] = tangent.x;
+ mesh.tangents[vCount + 1] = tangent.y;
+ mesh.tangents[vCount + 2] = tangent.z;
+ mesh.tangents[vCount + 3] = tangent.x;
+ mesh.tangents[vCount + 4] = tangent.y;
+ mesh.tangents[vCount + 5] = tangent.z;
+ mesh.tangents[vCount + 6] = tangent.x;
+ mesh.tangents[vCount + 7] = tangent.y;
+ mesh.tangents[vCount + 8] = tangent.z;
+
+ // TODO: add binormals to mesh struct and assign buffers id and locations properly
+ /* // Calculate vertex binormal
+ Vector3 binormal = VectorSubtract(b1, b2);
+ VectorScale(&binormal, r);
+
+ // Apply calculated binormals data to mesh struct
+ mesh.binormals[vCount + 0] = binormal.x;
+ mesh.binormals[vCount + 1] = binormal.y;
+ mesh.binormals[vCount + 2] = binormal.z;
+ mesh.binormals[vCount + 3] = binormal.x;
+ mesh.binormals[vCount + 4] = binormal.y;
+ mesh.binormals[vCount + 5] = binormal.z;
+ mesh.binormals[vCount + 6] = binormal.x;
+ mesh.binormals[vCount + 7] = binormal.y;
+ mesh.binormals[vCount + 8] = binormal.z; */
+
+ // Update vertex position and texture coordinates counters
+ vCount += 9;
+ uvCount += 6;
+ }
+ }
// Now we can free temp mid* arrays
free(midVertices);
@@ -1836,7 +1927,9 @@ static Mesh LoadOBJ(const char *fileName)
return mesh;
}
+#endif
+#if defined(SUPPORT_FILEFORMAT_MTL)
// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/)
// NOTE: Texture map parameters are not supported
static Material LoadMTL(const char *fileName)
@@ -2000,3 +2093,4 @@ static Material LoadMTL(const char *fileName)
return material;
}
+#endif