Add multi texture support for materials in GLTF format (#979)

* Initial commit of addition for GLTF materials.. should support loading more than just albedo map.

* Clean up

* fixed seg faults and leaks

* temp don't overwrite defuse colour when rendering

* undid something dumb!

* correctly mixed diffuse map color when rendering to preserve not overwrite it
This commit is contained in:
Tyler Jessilynn Bezera 2019-10-21 08:38:23 -07:00 committed by Ray
parent ab52f98480
commit 3f7fa6d6e7
2 changed files with 133 additions and 96 deletions

View File

@ -2385,8 +2385,15 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
for (int i = 0; i < model.meshCount; i++)
{
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = tint;
Color c = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color;
Color s = c;
c.r = ((c.r/255) * (tint.r/255)) * 255;
c.g = ((c.g/255) * (tint.g/255)) * 255;
c.b = ((c.b/255) * (tint.b/255)) * 255;
c.a = ((c.a/255) * (tint.a/255)) * 255;
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = c;
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = s;
}
}
@ -3344,6 +3351,92 @@ static unsigned char *DecodeBase64(char *input, int *size)
return buf;
}
//static Texture LoadTextureFromCGLTFTextureView(cgltf_texture_view* view, Color tint, char* texPath)
static Texture LoadTextureFromCGLTFTextureView(cgltf_image* image, Color tint, const char* texPath)
{
Texture texture = {0};
//cgltf_image *image = view->texture->image;
if (image->uri)
{
if ((strlen(image->uri) > 5) &&
(image->uri[0] == 'd') &&
(image->uri[1] == 'a') &&
(image->uri[2] == 't') &&
(image->uri[3] == 'a') &&
(image->uri[4] == ':'))
{
// Data URI
// Format: data:<mediatype>;base64,<data>
// Find the comma
int i = 0;
while ((image->uri[i] != ',') && (image->uri[i] != 0))
i++;
if (image->uri[i] == 0)
TraceLog(LOG_WARNING, "Invalid data URI");
else
{
int size;
unsigned char *data = DecodeBase64(image->uri + i + 1, &size);
int w, h;
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
}
}
else
{
char *textureName = image->uri;
char *texturePath = RL_MALLOC(strlen(texPath) + strlen(textureName) + 2);
strcpy(texturePath, texPath);
strcat(texturePath, "/");
strcat(texturePath, textureName);
Image rimage = LoadImage(texturePath);
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
RL_FREE(texturePath);
}
}
else if (image->buffer_view)
{
unsigned char *data = RL_MALLOC(image->buffer_view->size);
int n = image->buffer_view->offset;
int stride = image->buffer_view->stride ? image->buffer_view->stride : 1;
for (int i = 0; i < image->buffer_view->size; i++)
{
data[i] = ((unsigned char *)image->buffer_view->buffer->data)[n];
n += stride;
}
int w, h;
unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
free(raw);
free(data);
}
else
{
Image rimage = LoadImageEx(&tint, 1, 1);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
}
return texture;
}
// Load glTF mesh data
static Model LoadGLTF(const char *fileName)
{
@ -3426,106 +3519,49 @@ static Model LoadGLTF(const char *fileName)
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
//For each material
for (int i = 0; i < model.materialCount - 1; i++)
{
Color tint = WHITE;
Texture2D texture = { 0 };
model.materials[i] = LoadMaterialDefault();
Color tint = (Color){ 255, 255, 255, 255 };
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);
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255.99f);
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255.99f);
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255.99f);
}
else
{
tint.r = 1.0f;
tint.g = 1.0f;
tint.b = 1.0f;
tint.a = 1.0f;
}
//Ensure material follows raylib support for PBR (metallic/roughness flow)
if (data->materials[i].has_pbr_metallic_roughness) {
float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
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 ((strlen(img->uri) > 5) &&
(img->uri[0] == 'd') &&
(img->uri[1] == 'a') &&
(img->uri[2] == 't') &&
(img->uri[3] == 'a') &&
(img->uri[4] == ':'))
{
// Data URI
// Format: data:<mediatype>;base64,<data>
// Find the comma
int i = 0;
while ((img->uri[i] != ',') && (img->uri[i] != 0)) i++;
if (img->uri[i] == 0) TraceLog(LOG_WARNING, "[%s] Invalid data URI", fileName);
else
{
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);
UnloadImage(image);
}
}
else
{
char *textureName = img->uri;
char *texturePath = RL_MALLOC(strlen(texPath) + strlen(textureName) + 2);
strcpy(texturePath, texPath);
strcat(texturePath, "/");
strcat(texturePath, textureName);
Image image = LoadImage(texturePath);
ImageColorTint(&image, tint);
texture = LoadTextureFromImage(image);
UnloadImage(image);
RL_FREE(texturePath);
}
}
else if (img->buffer_view)
{
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];
n += stride;
}
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);
UnloadImage(image);
}
else
{
Image image = LoadImageEx(&tint, 1, 1);
texture = LoadTextureFromImage(image);
UnloadImage(image);
if (model.materials[i].name && data->materials[i].name) {
strcpy(model.materials[i].name, data->materials[i].name);
}
model.materials[i] = LoadMaterialDefault();
model.materials[i].maps[MAP_DIFFUSE].texture = texture;
// shouldn't these be *255 ???
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
model.materials[i].maps[MAP_ROUGHNESS].color = tint;
if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture) {
model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCGLTFTextureView(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, tint, texPath);
}
//tint isn't need for other textures.. pass null or clear? (try full white because of mixing (multiplying * white has no effect))
tint = (Color){ 255, 255, 255, 255 };
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture) {
model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCGLTFTextureView(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, tint, texPath);
}
model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
model.materials[i].maps[MAP_METALNESS].value = metallic;
if (data->materials[i].normal_texture.texture) {
model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCGLTFTextureView(data->materials[i].normal_texture.texture->image, tint, texPath);
}
if (data->materials[i].occlusion_texture.texture) {
model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCGLTFTextureView(data->materials[i].occlusion_texture.texture->image, tint, texPath);
}
}
}

View File

@ -106,7 +106,7 @@
#ifndef RL_FREE
#define RL_FREE(p) free(p)
#endif
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
#if defined(__cplusplus)
@ -336,6 +336,7 @@ typedef struct MaterialMap {
// Material type (generic)
typedef struct Material {
char* name; // Material name
Shader shader; // Material shader
MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS)
float *params; // Material generic parameters (if required)
@ -1406,7 +1407,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
//------------------------------------------------------------------------------------
// Network (Module: network)
//------------------------------------------------------------------------------------