From 470574517ab61ed71d769261cdcc136e8d0220d8 Mon Sep 17 00:00:00 2001 From: Hristo Stamenov Date: Wed, 26 May 2021 21:23:13 +0300 Subject: [PATCH] Implement vertex color attribute for GLTF and IQM (#1790) Added a simple cube with vertex colors for testing both. --- examples/models/models_gltf_model.c | 5 +- .../resources/gltf/vertex_colored_object.glb | Bin 0 -> 2512 bytes .../models/vertex_colored_object.iqm | Bin 0 -> 1800 bytes src/models.c | 56 +++++++++++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 examples/models/resources/gltf/vertex_colored_object.glb create mode 100644 examples/models/resources/models/vertex_colored_object.iqm diff --git a/examples/models/models_gltf_model.c b/examples/models/models_gltf_model.c index d5bd1687e..3475b3f0c 100644 --- a/examples/models/models_gltf_model.c +++ b/examples/models/models_gltf_model.c @@ -21,7 +21,7 @@ #include -#define MAX_MODELS 6 +#define MAX_MODELS 7 int main(void) { @@ -30,7 +30,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation"); + InitWindow(screenWidth, screenHeight, "raylib [models] example - model"); // Define the camera to look into our 3d world Camera camera = { 0 }; @@ -48,6 +48,7 @@ int main(void) model[3] = LoadModel("resources/gltf/BoxAnimated.glb"); model[4] = LoadModel("resources/gltf/AnimatedTriangle.gltf"); model[5] = LoadModel("resources/gltf/AnimatedMorphCube.glb"); + model[6] = LoadModel("resources/gltf/vertex_colored_object.glb"); int currentModel = 0; diff --git a/examples/models/resources/gltf/vertex_colored_object.glb b/examples/models/resources/gltf/vertex_colored_object.glb new file mode 100644 index 0000000000000000000000000000000000000000..0b57eddbdfdd1666dbf812f5b8d6e3151fec59e4 GIT binary patch literal 2512 zcmb7E-EZ4e6u%oCYsVNXgYg<&i8s&OPhUF{lrC&qp>0r7O`xh`PU5DP61#Go!ssgH zfq#Mj0$zDSf=3>C;J-m4oO5G0ncJn?O|H+m=i_%i?y>uWy~o!HA%CwC^2-fEzHB#l zPiZ(BMLDgX(teagS(v98t<$fLvNTCYwLZAi9uA_U7iG1rPnxw8?kZO?>d=!Y8^vh? z#=>Rv%%P($0MI%sxDl=IpVA~8f{eDU&Y?-#i%`KF?udi4gSq6C4x`bLbuWAx<4y#) z=NQ{@|0svRS(=Brjl9oX?gh+f_z6$5fCb87uF=}}nS`fQfyV;p0ds{B+;C}pF16=# zuE9fl0zARBFC66t&mkJj^S9Klu1?sBKFgQ|`@*-n&)gF)PFrQ`ll5{(U0&vHh3B;;X*LW8@sIPdnCGJ|075e^<}(MB z(6_?9-PqjTY*8G6c|R7rZ#&<4o=4kJ($C>bA$%WfLC`!rw4X4BFW$`gYGd$TV$K8T zkZyCC&fW!RH>n>_uD3miPU@B{?D}+4U+J!IpWTV)BT*0Hhw0RZ3v4HU^ zzQjQNWqc_^x{NRN%jiatPl_Qzb>=&67)C%x1^F?{NN-TSxl+wB1 zYvVvXYl{$oQ|3{PWz}VFMXsfd^#R{<+1x5Ns4L@~=T@<~fCKSru*oI#&(CJ^DnrPJw)Coi6$rb>Tve*O#PFH`B~|Dv=?uaP_C z19A=aO>&F84N2XC{So<)yiab!^EP>p+$C?3HF&O(`{V|>PFCT$O5P#s zgpP#kVFll{?W?nf$?MI=<$3+0drxS`Js9@{W2^xo(?HCGp)vEiK6otDbtF)ap$!U| zKH&~}pxyB>)7p&itQepLPn>dcG18him&S1|Ie6^jIOKvBbF@?sd3*|L1IQ8M15%DI ztt4-RQ}{;L!_na{0v?XVI^5-beL0+yM~54E<2ilM;pj0hNrU6l`m(g3(H2=5W1!f&cW*zn#BkYt}Yj z?b@ofHqWhnt2$16`)(avPBpgO?t+@f2baTB>-wOphS;4^j@Pm8!j5DwhW*F-V<)l; t*^}^07!}5RJnlLBcv6@Wh^Ia0Uok7p3B>cBFUT(nO9Jt-=X&M8vJdPphlv0H literal 0 HcmV?d00001 diff --git a/src/models.c b/src/models.c index 551ee7af2..af4fd65c8 100644 --- a/src/models.c +++ b/src/models.c @@ -3458,7 +3458,7 @@ static Model LoadIQM(const char *fileName) IQM_TANGENT = 3, // NOTE: Tangents unused by default IQM_BLENDINDEXES = 4, IQM_BLENDWEIGHTS = 5, - IQM_COLOR = 6, // NOTE: Vertex colors unused by default + IQM_COLOR = 6, IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default }; @@ -3474,6 +3474,7 @@ static Model LoadIQM(const char *fileName) float *text = NULL; char *blendi = NULL; unsigned char *blendw = NULL; + unsigned char *color = NULL; // In case file can not be read, return an empty model if (fileDataPtr == NULL) return model; @@ -3662,6 +3663,25 @@ static Model LoadIQM(const char *fileName) } } } break; + case IQM_COLOR: + { + color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char)); + //fseek(iqmFile, va[i].offset, SEEK_SET); + //fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile); + memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char)); + + for (unsigned int m = 0; m < iqmHeader->num_meshes; m++) + { + model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char)); + + int vCounter = 0; + for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++) + { + model.meshes[m].colors[vCounter] = color[i]; + vCounter++; + } + } + } break; } } @@ -4301,6 +4321,40 @@ static Model LoadGLTF(const char *fileName) TRACELOG(LOG_WARNING, "MODEL: [%s] glTF normals must be float or int", fileName); } } + else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_color) + { + cgltf_accessor *acc = data->meshes[i].primitives[p].attributes[j].data; + model.meshes[primitiveIndex].colors = RL_MALLOC(acc->count*4*sizeof(unsigned char)); + + if (acc->component_type == cgltf_component_type_r_8u) + { + for (int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, model.meshes[primitiveIndex].colors + (a*4), 4, sizeof(unsigned char)); + } + } + if (acc->component_type == cgltf_component_type_r_16u) + { + TRACELOG(LOG_WARNING, "MODEL: [%s] converting glTF colors to unsigned char", fileName); + for (int a = 0; a < acc->count; a++) + { + unsigned short readValue[4]; + for (int a = 0; a < acc->count; a++) + { + GLTFReadValue(acc, a, readValue, 4, sizeof(unsigned short)); + // 257 = 65535/255 + model.meshes[primitiveIndex].colors[(a*4) + 0] = (unsigned char)(readValue[0] / 257); + model.meshes[primitiveIndex].colors[(a*4) + 1] = (unsigned char)(readValue[1] / 257); + model.meshes[primitiveIndex].colors[(a*4) + 2] = (unsigned char)(readValue[2] / 257); + model.meshes[primitiveIndex].colors[(a*4) + 3] = (unsigned char)(readValue[3] / 257); + } + } + } + else + { + TRACELOG(LOG_WARNING, "MODEL: [%s] glTF colors must be uchar or ushort", fileName); + } + } } cgltf_accessor *acc = data->meshes[i].primitives[p].indices;