diff --git a/data/mdl/maxwell.mdl b/data/mdl/maxwell.mdl new file mode 100644 index 0000000..6c9d243 Binary files /dev/null and b/data/mdl/maxwell.mdl differ diff --git a/data/mdl/tetopear.mdl b/data/mdl/tetopear.mdl index a801843..6bdbd80 100644 Binary files a/data/mdl/tetopear.mdl and b/data/mdl/tetopear.mdl differ diff --git a/engine/include/GearSrc/GL.h b/engine/include/GearSrc/GL.h index 5b40afb..1f6a9cf 100644 --- a/engine/include/GearSrc/GL.h +++ b/engine/include/GearSrc/GL.h @@ -18,9 +18,12 @@ GSDECL int GSGLShaderPrepare(GSGL gl, GLuint* shader, const char* vs, const char /* gl_texture.c */ GSDECL void GSGLTexturePrepare(GSGL gl, GLuint* texture, unsigned char* rgba, int width, int height); GSDECL void GSGLTextureSet(GSGL gl, GLuint texture); -GSDECL int GSGLTextureLoadFile(GSGL gl, GLuint* texture, int* width, int* height, const char* filename); GSDECL void GSGLTextureDelete(GSGL gl, GLuint texture); +/* gl_common.c */ +GSDECL int GSGLTextureLoadFile(GSGL gl, GLuint* texture, int* width, int* height, const char* filename); +GSDECL int GSGLTextureTry(GSGL gl, GLuint* texture, int* width, int* height, const char* prefix); + /* gl_shadow.c */ GSDECL void GSGLShadowInit(GSGL gl); GSDECL int GSGLShadowBeforeMapping(GSGL gl); diff --git a/engine/include/GearSrc/TypeDefs.h b/engine/include/GearSrc/TypeDefs.h index e8b9249..1d91019 100644 --- a/engine/include/GearSrc/TypeDefs.h +++ b/engine/include/GearSrc/TypeDefs.h @@ -50,7 +50,9 @@ typedef struct _GSGL* GSGL; typedef struct _GSSkyBox* GSSkyBox; typedef struct _GSModel* GSModel; -typedef struct _GSModelFace GSModelFace; +typedef struct _GSModelFace GSModelFace; +typedef struct _GSModelMaterial GSModelMaterial; +typedef struct _GSModelUseMaterial GSModelUseMaterial; #else typedef void* GSClient; typedef void* GSServer; @@ -121,12 +123,24 @@ struct _GSModelFace { GSVector2* texcoord; }; +struct _GSModelMaterial { + char* key; + GLuint value; +}; + +struct _GSModelUseMaterial { + int key; + char* value; +}; + struct _GSModel { GSEngine engine; - GLuint texture; GLuint call_list; + GSModelMaterial* material; + GSModelUseMaterial* usemtl; + float* vertex; float* texcoord; GSModelFace* face; diff --git a/engine/src/gl_common.c b/engine/src/gl_common.c new file mode 100644 index 0000000..eef2733 --- /dev/null +++ b/engine/src/gl_common.c @@ -0,0 +1,62 @@ +#include + +#include +#include + +#include + +int GSGLTextureLoadFile(GSGL gl, GLuint* texture, int* width, int* height, const char* filename) { + GSFile f = GSFileOpen(gl->engine, filename); + unsigned char* data; + unsigned char* rgba; + unsigned long sz; + int ch; + int st = 1; + int w, h; + if(f == NULL) return 0; + + sz = GSFileSize(f); + + data = malloc(sz); + GSFileRead(f, data, sz); + GSFileClose(f); + + if((rgba = stbi_load_from_memory(data, sz, &w, &h, &ch, 4)) == NULL) { + st = 0; + } else { + GSGLTexturePrepare(gl, texture, rgba, w, h); + + free(rgba); + } + + if(width != NULL) *width = w; + if(height != NULL) *height = h; + + free(data); + + return st; +} + +int GSGLTextureTry(GSGL gl, GLuint* texture, int* width, int* height, const char* prefix) { + char* png = GSStringConcat(prefix, ".png"); + char* bmp = GSStringConcat(prefix, ".bmp"); + char* jpg = GSStringConcat(prefix, ".jpg"); + char* jpeg = GSStringConcat(prefix, ".jpeg"); + int st = 1; + + if(GSGLTextureLoadFile(gl, texture, width, height, prefix)) { + } else if(GSGLTextureLoadFile(gl, texture, width, height, png)) { + } else if(GSGLTextureLoadFile(gl, texture, width, height, bmp)) { + } else if(GSGLTextureLoadFile(gl, texture, width, height, jpg)) { + } else if(GSGLTextureLoadFile(gl, texture, width, height, jpeg)) { + } else { + st = 0; + } + + free(jpeg); + free(jpg); + free(bmp); + free(png); + + return st; +} diff --git a/engine/src/gl_texture.c b/engine/src/gl_texture.c index 5b8af35..1e3d594 100644 --- a/engine/src/gl_texture.c +++ b/engine/src/gl_texture.c @@ -1,9 +1,5 @@ #include -#include - -#include - void GSGLTexturePrepare(GSGL gl, GLuint* texture, unsigned char* rgba, int width, int height) { glGenTextures(1, texture); glBindTexture(GL_TEXTURE_2D, *texture); @@ -23,38 +19,6 @@ void GSGLTextureDisable(GSGL gl, GLuint texture) { glBindTexture(GL_TEXTURE_2D, 0); } -int GSGLTextureLoadFile(GSGL gl, GLuint* texture, int* width, int* height, const char* filename) { - GSFile f = GSFileOpen(gl->engine, filename); - unsigned char* data; - unsigned char* rgba; - unsigned long sz; - int ch; - int st = 1; - int w, h; - if(f == NULL) return 0; - - sz = GSFileSize(f); - - data = malloc(sz); - GSFileRead(f, data, sz); - GSFileClose(f); - - if((rgba = stbi_load_from_memory(data, sz, &w, &h, &ch, 4)) == NULL) { - st = 0; - } else { - GSGLTexturePrepare(gl, texture, rgba, w, h); - - free(rgba); - } - - if(width != NULL) *width = w; - if(height != NULL) *height = h; - - free(data); - - return st; -} - void GSGLTextureSet(GSGL gl, GLuint texture) { glBindTexture(GL_TEXTURE_2D, texture); if(texture == 0) { diff --git a/engine/src/model.c b/engine/src/model.c index 11cb5ff..f29cd1a 100644 --- a/engine/src/model.c +++ b/engine/src/model.c @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -25,13 +26,18 @@ static void parse_obj(GSModel model, char* txt) { if(strlen(f) > 0 && f[0] != '#') { char* arg; - if(f[strlen(f) - 1] == '\n') f[strlen(f) - 1] = 0; + if(f[strlen(f) - 1] == '\r') f[strlen(f) - 1] = 0; if((arg = strchr(f, ' ')) != NULL) { arg[0] = 0; arg++; - if(strcmp(f, "v") == 0) { + if(strcmp(f, "usemtl") == 0) { + int k = arrlen(model->face); + char* v = GSStringDuplicate(arg); + + hmput(model->usemtl, k, v); + } else if(strcmp(f, "v") == 0) { float v0, v1, v2; sscanf(arg, "%f %f %f", &v0, &v1, &v2); @@ -154,12 +160,54 @@ static void parse_obj(GSModel model, char* txt) { } } +static void parse_mtl(GSModel model, char* txt) { + char* f = txt; + char* m = NULL; + + while(1) { + char* s = strchr(f, '\n'); + + if(s != NULL) s[0] = 0; + + if(strlen(f) > 0 && f[0] != '#') { + char* arg; + + if(f[strlen(f) - 1] == '\r') f[strlen(f) - 1] = 0; + + if((arg = strchr(f, ' ')) != NULL) { + arg[0] = 0; + arg++; + + if(strcmp(f, "newmtl") == 0) { + GLuint v = 0; + + shput(model->material, arg, v); + + if(m != NULL) free(m); + m = GSStringDuplicate(arg); + } else if(strcmp(f, "map_Kd") == 0 && m != NULL) { + GLuint t = 0; + char* p = GSStringConcat("model-ws:/", arg); + + if(GSGLTextureTry(model->engine->client->gl, &t, NULL, NULL, p)) { + shput(model->material, m, t); + } + } + } + } + + if(s == NULL) break; + f = s + 1; + } + + if(m != NULL) free(m); +} + GSModel GSModelOpen(GSEngine engine, const char* path) { GSModel model = malloc(sizeof(*model)); GSFile f; char* buffer; unsigned int size; - int w, h; GSGL gl = NULL; if(engine->client != NULL) gl = engine->client->gl; @@ -173,6 +221,22 @@ GSModel GSModelOpen(GSEngine engine, const char* path) { return NULL; } + model->material = NULL; + sh_new_strdup(model->material); + + model->usemtl = NULL; + + if(gl != NULL) { + GLuint t = 0; + + GSGLTextureTry(gl, &t, NULL, NULL, "model-ws:/model"); + + if(t != 0) { + char* k = "default"; + shput(model->material, k, t); + } + } + if((f = GSFileOpen(engine, "model-ws:/model.obj")) == NULL) { GSEngineUnregisterResource(engine, "model-ws"); @@ -180,14 +244,6 @@ GSModel GSModelOpen(GSEngine engine, const char* path) { return NULL; } - if(gl != NULL) { - if(GSGLTextureLoadFile(gl, &model->texture, &w, &h, "model-ws:/model.png")) { - } else if(GSGLTextureLoadFile(gl, &model->texture, &w, &h, "model-ws:/model.bmp")) { - } else if(GSGLTextureLoadFile(gl, &model->texture, &w, &h, "model-ws:/model.jpg")) { - } else if(GSGLTextureLoadFile(gl, &model->texture, &w, &h, "model-ws:/model.jpeg")) { - } - } - size = GSFileSize(f); buffer = malloc(size + 1); buffer[size] = 0; @@ -199,6 +255,19 @@ GSModel GSModelOpen(GSEngine engine, const char* path) { free(buffer); + if(gl != NULL && (f = GSFileOpen(engine, "model-ws:/model.mtl")) != NULL) { + size = GSFileSize(f); + buffer = malloc(size + 1); + buffer[size] = 0; + + GSFileRead(f, buffer, size); + GSFileClose(f); + + parse_mtl(model, buffer); + + free(buffer); + } + GSEngineUnregisterResource(engine, "model-ws"); GSLog(GSLogInfo, "Opened model %s, %d vertexes, %d faces", path, arrlen(model->vertex), arrlen(model->face)); @@ -225,9 +294,17 @@ void GSModelDraw(GSModel model, GSVector3 pos, GSVector3 rot) { GSGLSetPosition(gl, pos, rot); if(model->call_list == 0) { - GSGLTextureSet(gl, model->texture); + char* k = "default"; + + GSGLTextureSet(gl, shget(model->material, k)); for(i = 0; i < arrlen(model->face); i++) { + int ind = hmgeti(model->usemtl, i); + + if(ind != -1) { + GSGLTextureSet(gl, shget(model->material, model->usemtl[ind].value)); + } + GSGLPolygon(gl, model->face[i].count, model->face[i].vertex, model->face[i].texcoord, model->face[i].normal); } @@ -247,10 +324,18 @@ void GSModelClose(GSModel model) { } arrfree(model->face); + for(i = 0; i < shlen(model->material); i++) { + GSGLTextureDelete(model->engine->client->gl, model->material[i].value); + } + shfree(model->material); + + for(i = 0; i < hmlen(model->usemtl); i++) { + free(model->usemtl[i].value); + } + hmfree(model->usemtl); + arrfree(model->vertex); arrfree(model->texcoord); - if(model->texture != 0) GSGLTextureDelete(model->engine->client->gl, model->texture); - free(model); } diff --git a/resource/model/tetopear/model.mtl b/resource/model/tetopear/model.mtl new file mode 100644 index 0000000..476f4c9 --- /dev/null +++ b/resource/model/tetopear/model.mtl @@ -0,0 +1,12 @@ +# File generated by ImageToStl.com - Free Image and 3D model conversion tools + +newmtl mat0 +Ns 0 +Ka 1.0 1.0 1.0 +Kd 1 1 1 +Ks 0.5 0.5 0.5 +Ke 0.0 0.0 0.0 +Ni 1.0 +d 1 +illum 2 +map_Kd model.png diff --git a/resource/model/tetopear/model.obj b/resource/model/tetopear/model.obj index da523b4..39bd598 100644 --- a/resource/model/tetopear/model.obj +++ b/resource/model/tetopear/model.obj @@ -1878,7 +1878,7 @@ vt 0.49441 0.27544 vt 0.49577 0.28985 vt 0.04985 0.93435 vt 0.04985 0.93435 - +usemtl mat0 f 1/1/1 2/2/2 3/3/3 f 1/1/1 3/3/3 4/4/4 f 5/5/5 6/6/6 1/1/1