|
|
@ -296,7 +296,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei |
|
|
|
float x = position.x; |
|
|
|
float y = position.y; |
|
|
|
float z = position.z; |
|
|
|
|
|
|
|
|
|
|
|
if (rlCheckBufferLimit(36)) rlglDraw(); |
|
|
|
|
|
|
|
rlEnableTexture(texture.id); |
|
|
@ -362,7 +362,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color |
|
|
|
{ |
|
|
|
int numVertex = (rings + 2)*slices*6; |
|
|
|
if (rlCheckBufferLimit(numVertex)) rlglDraw(); |
|
|
|
|
|
|
|
|
|
|
|
rlPushMatrix(); |
|
|
|
// NOTE: Transformation is applied in inverse order (scale -> translate) |
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |
|
|
@ -405,7 +405,7 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col |
|
|
|
{ |
|
|
|
int numVertex = (rings + 2)*slices*6; |
|
|
|
if (rlCheckBufferLimit(numVertex)) rlglDraw(); |
|
|
|
|
|
|
|
|
|
|
|
rlPushMatrix(); |
|
|
|
// NOTE: Transformation is applied in inverse order (scale -> translate) |
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |
|
|
@ -449,7 +449,7 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col |
|
|
|
void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) |
|
|
|
{ |
|
|
|
if (sides < 3) sides = 3; |
|
|
|
|
|
|
|
|
|
|
|
int numVertex = sides*6; |
|
|
|
if (rlCheckBufferLimit(numVertex)) rlglDraw(); |
|
|
|
|
|
|
@ -508,7 +508,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h |
|
|
|
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) |
|
|
|
{ |
|
|
|
if (sides < 3) sides = 3; |
|
|
|
|
|
|
|
|
|
|
|
int numVertex = sides*8; |
|
|
|
if (rlCheckBufferLimit(numVertex)) rlglDraw(); |
|
|
|
|
|
|
@ -540,7 +540,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl |
|
|
|
void DrawPlane(Vector3 centerPos, Vector2 size, Color color) |
|
|
|
{ |
|
|
|
if (rlCheckBufferLimit(4)) rlglDraw(); |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: Plane is always created on XZ ground |
|
|
|
rlPushMatrix(); |
|
|
|
rlTranslatef(centerPos.x, centerPos.y, centerPos.z); |
|
|
@ -725,9 +725,9 @@ Mesh *LoadMeshes(const char *fileName, int *meshCount) |
|
|
|
{ |
|
|
|
Mesh *meshes = NULL; |
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Load meshes from file (OBJ, IQM, GLTF) |
|
|
|
|
|
|
|
|
|
|
|
*meshCount = count; |
|
|
|
return meshes; |
|
|
|
} |
|
|
@ -800,7 +800,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount) |
|
|
|
{ |
|
|
|
Material *materials = NULL; |
|
|
|
unsigned int count = 0; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Support IQM and GLTF for materials parsing |
|
|
|
|
|
|
|
#if defined(SUPPORT_FILEFORMAT_MTL) |
|
|
@ -853,7 +853,7 @@ void UnloadMaterial(Material material) |
|
|
|
{ |
|
|
|
if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
RL_FREE(material.maps); |
|
|
|
} |
|
|
|
|
|
|
@ -908,7 +908,7 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) |
|
|
|
float framerate; |
|
|
|
unsigned int flags; |
|
|
|
} IQMAnim; |
|
|
|
|
|
|
|
|
|
|
|
FILE *iqmFile; |
|
|
|
IQMHeader iqm; |
|
|
|
|
|
|
@ -1076,7 +1076,7 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount) |
|
|
|
RL_FREE(framedata); |
|
|
|
RL_FREE(poses); |
|
|
|
RL_FREE(anim); |
|
|
|
|
|
|
|
|
|
|
|
fclose(iqmFile); |
|
|
|
|
|
|
|
return animations; |
|
|
@ -1151,7 +1151,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame) |
|
|
|
void UnloadModelAnimation(ModelAnimation anim) |
|
|
|
{ |
|
|
|
for (int i = 0; i < anim.frameCount; i++) RL_FREE(anim.framePoses[i]); |
|
|
|
|
|
|
|
|
|
|
|
RL_FREE(anim.bones); |
|
|
|
RL_FREE(anim.framePoses); |
|
|
|
} |
|
|
@ -1161,7 +1161,7 @@ void UnloadModelAnimation(ModelAnimation anim) |
|
|
|
bool IsModelAnimationValid(Model model, ModelAnimation anim) |
|
|
|
{ |
|
|
|
int result = true; |
|
|
|
|
|
|
|
|
|
|
|
if (model.boneCount != anim.boneCount) result = false; |
|
|
|
else |
|
|
|
{ |
|
|
@ -2336,7 +2336,7 @@ void MeshTangents(Mesh *mesh) |
|
|
|
|
|
|
|
RL_FREE(tan1); |
|
|
|
RL_FREE(tan2); |
|
|
|
|
|
|
|
|
|
|
|
// Load a new tangent attributes buffer |
|
|
|
mesh->vboId[LOC_VERTEX_TANGENT] = rlLoadAttribBuffer(mesh->vaoId, LOC_VERTEX_TANGENT, mesh->tangents, mesh->vertexCount*4*sizeof(float), false); |
|
|
|
|
|
|
@ -2491,7 +2491,7 @@ void DrawBoundingBox(BoundingBox box, Color color) |
|
|
|
bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB) |
|
|
|
{ |
|
|
|
bool collision = false; |
|
|
|
|
|
|
|
|
|
|
|
// Simple way to check for collision, just checking distance between two points |
|
|
|
// Unfortunately, sqrtf() is a costly operation, so we avoid it with following solution |
|
|
|
/* |
|
|
@ -2503,10 +2503,10 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa |
|
|
|
|
|
|
|
if (distance <= (radiusA + radiusB)) collision = true; |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
// Check for distances squared to avoid sqrtf() |
|
|
|
if (Vector3DotProduct(Vector3Subtract(centerB, centerA), Vector3Subtract(centerB, centerA)) <= (radiusA + radiusB)*(radiusA + radiusB)) collision = true; |
|
|
|
|
|
|
|
|
|
|
|
return collision; |
|
|
|
} |
|
|
|
|
|
|
@ -2798,7 +2798,7 @@ static Model LoadOBJ(const char *fileName) |
|
|
|
model.materialCount = materialCount; |
|
|
|
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); |
|
|
|
|
|
|
|
/* |
|
|
@ -2897,7 +2897,7 @@ static Model LoadOBJ(const char *fileName) |
|
|
|
*/ |
|
|
|
|
|
|
|
model.materials[m].maps[MAP_DIFFUSE].texture = GetTextureDefault(); // Get default texture, in case no texture is defined |
|
|
|
|
|
|
|
|
|
|
|
if (materials[m].diffuse_texname != NULL) model.materials[m].maps[MAP_DIFFUSE].texture = LoadTexture(materials[m].diffuse_texname); //char *diffuse_texname; // map_Kd |
|
|
|
model.materials[m].maps[MAP_DIFFUSE].color = (Color){ (float)(materials[m].diffuse[0]*255.0f), (float)(materials[m].diffuse[1]*255.0f), (float)(materials[m].diffuse[2]*255.0f), 255 }; //float diffuse[3]; |
|
|
|
model.materials[m].maps[MAP_DIFFUSE].value = 0.0f; |
|
|
@ -2918,6 +2918,7 @@ static Model LoadOBJ(const char *fileName) |
|
|
|
tinyobj_attrib_free(&attrib); |
|
|
|
tinyobj_shapes_free(meshes, meshCount); |
|
|
|
tinyobj_materials_free(materials, materialCount); |
|
|
|
RL_FREE(data); // oh ray how did you miss this...! :-p |
|
|
|
} |
|
|
|
|
|
|
|
// NOTE: At this point we have all model data loaded |
|
|
@ -2966,13 +2967,13 @@ static Model LoadIQM(const char *fileName) |
|
|
|
typedef struct IQMTriangle { |
|
|
|
unsigned int vertex[3]; |
|
|
|
} IQMTriangle; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct IQMJoint { |
|
|
|
unsigned int name; |
|
|
|
int parent; |
|
|
|
float translate[3], rotate[4], scale[3]; |
|
|
|
} IQMJoint; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct IQMVertexArray { |
|
|
|
unsigned int type; |
|
|
|
unsigned int flags; |
|
|
@ -3090,7 +3091,7 @@ static Model LoadIQM(const char *fileName) |
|
|
|
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning) |
|
|
|
model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); |
|
|
|
model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); |
|
|
|
|
|
|
|
|
|
|
|
model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); |
|
|
|
} |
|
|
|
|
|
|
@ -3286,7 +3287,7 @@ static const unsigned char base64Table[] = { |
|
|
|
static int GetSizeBase64(char *input) |
|
|
|
{ |
|
|
|
int size = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; input[4*i] != 0; i++) |
|
|
|
{ |
|
|
|
if (input[4*i + 3] == '=') |
|
|
@ -3296,7 +3297,7 @@ static int GetSizeBase64(char *input) |
|
|
|
} |
|
|
|
else size += 3; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
@ -3340,24 +3341,24 @@ static unsigned char *DecodeBase64(char *input, int *size) |
|
|
|
static Model LoadGLTF(const char *fileName) |
|
|
|
{ |
|
|
|
/*********************************************************************************** |
|
|
|
|
|
|
|
|
|
|
|
Function implemented by Wilhem Barbier (@wbrbr) |
|
|
|
|
|
|
|
|
|
|
|
Features: |
|
|
|
- Supports .gltf and .glb files |
|
|
|
- Supports embedded (base64) or external textures |
|
|
|
- Loads the albedo/diffuse texture (other maps could be added) |
|
|
|
- Supports multiple mesh per model and multiple primitives per model |
|
|
|
|
|
|
|
|
|
|
|
Some restrictions (not exhaustive): |
|
|
|
- Triangle-only meshes |
|
|
|
- Not supported node hierarchies or transforms |
|
|
|
- Only loads the diffuse texture... but not too hard to support other maps (normal, roughness/metalness...) |
|
|
|
- Only supports unsigned short indices (no byte/unsigned int) |
|
|
|
- Only supports float for texture coordinates (no byte/unsigned short) |
|
|
|
|
|
|
|
|
|
|
|
*************************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
#define LOAD_ACCESSOR(type, nbcomp, acc, dst) \ |
|
|
|
{ \ |
|
|
|
int n = 0; \ |
|
|
@ -3369,7 +3370,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
n += acc->stride/sizeof(type);\ |
|
|
|
}\ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Model model = { 0 }; |
|
|
|
|
|
|
|
// glTF file loading |
|
|
@ -3403,7 +3404,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
result = cgltf_load_buffers(&options, data, fileName); |
|
|
|
|
|
|
|
int primitivesCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < data->meshes_count; i++) primitivesCount += (int)data->meshes[i].primitives_count; |
|
|
|
|
|
|
|
// Process glTF data and map to model |
|
|
@ -3412,7 +3413,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
model.materialCount = data->materials_count + 1; |
|
|
|
model.materials = RL_MALLOC(model.materialCount*sizeof(Material)); |
|
|
|
model.meshMaterial = RL_MALLOC(model.meshCount*sizeof(int)); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int)); |
|
|
|
|
|
|
|
for (int i = 0; i < model.materialCount - 1; i++) |
|
|
@ -3420,7 +3421,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
Color tint = WHITE; |
|
|
|
Texture2D texture = { 0 }; |
|
|
|
const char *texPath = GetDirectoryPath(fileName); |
|
|
|
|
|
|
|
|
|
|
|
if (data->materials[i].has_pbr_metallic_roughness) |
|
|
|
{ |
|
|
|
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255.99f); |
|
|
@ -3435,12 +3436,12 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
tint.b = 1.0f; |
|
|
|
tint.a = 1.0f; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (data->materials[i].has_pbr_metallic_roughness) |
|
|
|
{ |
|
|
|
cgltf_image *img = data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image; |
|
|
|
|
|
|
|
if (img->uri) |
|
|
|
|
|
|
|
if (img->uri) |
|
|
|
{ |
|
|
|
if ((strlen(img->uri) > 5) && |
|
|
|
(img->uri[0] == 'd') && |
|
|
@ -3461,10 +3462,10 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
{ |
|
|
|
int size; |
|
|
|
unsigned char *data = DecodeBase64(img->uri + i + 1, &size); |
|
|
|
|
|
|
|
|
|
|
|
int w, h; |
|
|
|
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4); |
|
|
|
|
|
|
|
|
|
|
|
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); |
|
|
|
ImageColorTint(&image, tint); |
|
|
|
texture = LoadTextureFromImage(image); |
|
|
@ -3491,7 +3492,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
unsigned char *data = RL_MALLOC(img->buffer_view->size); |
|
|
|
int n = img->buffer_view->offset; |
|
|
|
int stride = img->buffer_view->stride ? img->buffer_view->stride : 1; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < img->buffer_view->size; i++) |
|
|
|
{ |
|
|
|
data[i] = ((unsigned char *)img->buffer_view->buffer->data)[n]; |
|
|
@ -3500,7 +3501,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
|
|
|
|
int w, h; |
|
|
|
unsigned char *raw = stbi_load_from_memory(data, img->buffer_view->size, &w, &h, NULL, 4); |
|
|
|
|
|
|
|
|
|
|
|
Image image = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8); |
|
|
|
ImageColorTint(&image, tint); |
|
|
|
texture = LoadTextureFromImage(image); |
|
|
@ -3512,16 +3513,16 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
texture = LoadTextureFromImage(image); |
|
|
|
UnloadImage(image); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
model.materials[i] = LoadMaterialDefault(); |
|
|
|
model.materials[i].maps[MAP_DIFFUSE].texture = texture; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
model.materials[model.materialCount - 1] = LoadMaterialDefault(); |
|
|
|
|
|
|
|
int primitiveIndex = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < data->meshes_count; i++) |
|
|
|
{ |
|
|
|
for (int p = 0; p < data->meshes[i].primitives_count; p++) |
|
|
@ -3546,7 +3547,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_texcoord) |
|
|
|
{ |
|
|
|
cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; |
|
|
|
|
|
|
|
|
|
|
|
if (acc->component_type == cgltf_component_type_r_32f) |
|
|
|
{ |
|
|
|
model.meshes[primitiveIndex].texcoords = RL_MALLOC(sizeof(float)*acc->count*2); |
|
|
@ -3561,7 +3562,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
} |
|
|
|
|
|
|
|
cgltf_accessor *acc = data->meshes[i].primitives[p].indices; |
|
|
|
|
|
|
|
|
|
|
|
if (acc) |
|
|
|
{ |
|
|
|
if (acc->component_type == cgltf_component_type_r_16u) |
|
|
@ -3591,7 +3592,7 @@ static Model LoadGLTF(const char *fileName) |
|
|
|
{ |
|
|
|
model.meshMaterial[primitiveIndex] = model.materialCount - 1;; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
primitiveIndex++; |
|
|
|
} |
|
|
|
} |
|
|
|