From 084f549ba10c0d8f4512a3bb91334186f33638dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Fri, 1 Dec 2023 12:01:03 +0100 Subject: [PATCH] wip: lmap --- bind/v4k.lua | 15 +- demos/99-lmap.c | 2 +- engine/art/shaders/fs_32_4_model.glsl | 23 +-- ...l.glsl => vs_3223444143_16_332_model.glsl} | 1 + engine/joint/v4k.h | 180 ++++++++++++++++-- engine/split/v4k_extend.h | 3 - engine/split/v4k_render.c | 163 ++++++++++++++-- engine/split/v4k_render.h | 14 +- engine/v4k.c | 163 ++++++++++++++-- engine/v4k.h | 17 +- 10 files changed, 505 insertions(+), 76 deletions(-) rename engine/art/shaders/{vs_323444143_16_332_model.glsl => vs_3223444143_16_332_model.glsl} (99%) diff --git a/bind/v4k.lua b/bind/v4k.lua index f16a31b..4556c1b 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1257,6 +1257,9 @@ ffi.cdef([[ //lcpp INF [0000] vec3: macro name but used as C declaration in:API vec3 pose(bool forward, float curframe, int minframe, int maxframe, bool loop, float *opt_retframe); //lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC vec3 pose(bool forward, float curframe, int minframe, int maxframe, bool loop, float *opt_retframe); //lcpp INF [0000] vec3: macro name but used as C declaration in: vec3 pose(bool forward, float curframe, int minframe, int maxframe, bool loop, float *opt_retframe); +//lcpp INF [0000] vec3: macro name but used as C declaration in:API lightmap_t lightmap(int hmsize , float near, float far, vec3 color , int passes , float threshold , float distmod ); +//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC lightmap_t lightmap(int hmsize , float near, float far, vec3 color , int passes , float threshold , float distmod ); +//lcpp INF [0000] vec3: macro name but used as C declaration in: lightmap_t lightmap(int hmsize , float near, float far, vec3 color , int passes , float threshold , float distmod ); //lcpp INF [0000] vec3: macro name but used as C declaration in:API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); //lcpp INF [0000] vec3: macro name but used as C declaration in:API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); //lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); @@ -2954,6 +2957,7 @@ unsigned num_textures; handle *textures; char **texture_names; material_t* materials; +texture_t *lightmap; unsigned num_meshes; unsigned num_triangles; unsigned num_joints; @@ -2999,7 +3003,16 @@ anim_t* anims; anims_t animations(const char *pathfile, int flags); typedef struct lightmap_t { struct lm_context *ctx; +bool ready; +texture_t lightmap; +model_t** models; } lightmap_t; + lightmap_t lightmap(int hmsize , float near, float far, vec3 color , int passes , float threshold , float distmod ); + void lightmap_setup(lightmap_t *lm, int w, int h); + void lightmap_addmodel(lightmap_t *lm, model_t *m); + void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata); + void lightmap_clear(lightmap_t *lm); + void lightmap_destroy(lightmap_t *lm); typedef struct skybox_t { handle program; mesh_t geometry; @@ -3324,7 +3337,7 @@ unsigned play; bool paused; struct atlas_t *a; } sprite_t; -enum { OBJTYPE_sprite_t = 10 }; typedef struct { unsigned static_assert_on_L__LINE__ : !!(10 <= 255); } static_assert_on_Lconcat(_L,3945)___COUNTER__; typedef struct { unsigned static_assert_on_L__LINE__ : !!(sizeof(sprite_t)); } static_assert_on_Lconcat(_L,3945)___COUNTER__;; +enum { OBJTYPE_sprite_t = 10 }; typedef struct { unsigned static_assert_on_L__LINE__ : !!(10 <= 255); } static_assert_on_Lconcat(_L,3954)___COUNTER__; typedef struct { unsigned static_assert_on_L__LINE__ : !!(sizeof(sprite_t)); } static_assert_on_Lconcat(_L,3954)___COUNTER__;; void sprite_ctor(sprite_t *s); void sprite_dtor(sprite_t *s); void sprite_tick(sprite_t *s); diff --git a/demos/99-lmap.c b/demos/99-lmap.c index 306c2d2..631c27a 100644 --- a/demos/99-lmap.c +++ b/demos/99-lmap.c @@ -1,7 +1,7 @@ #include "v4k.h" #define LIGHTMAPPER_IMPLEMENTATION -// #define LM_DEBUG_INTERPOLATION +//#define LM_DEBUG_INTERPOLATION #include "3rd_lightmapper.h" #define scene_t scene_t2 diff --git a/engine/art/shaders/fs_32_4_model.glsl b/engine/art/shaders/fs_32_4_model.glsl index 2354662..c439a3b 100644 --- a/engine/art/shaders/fs_32_4_model.glsl +++ b/engine/art/shaders/fs_32_4_model.glsl @@ -143,8 +143,8 @@ void main() { diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y)); } else if(u_textured) { diffuse = texture(u_texture2d, v_texcoord); - } else { - diffuse = u_diffuse; // * v_color; + } else { + diffuse = u_diffuse; // * v_color; } // lighting mix @@ -152,14 +152,15 @@ void main() { // rimlight #ifdef RIM - {vec3 n = normalize(mat3(M) * v_normal); // convert normal to view space - vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space - vec3 v = vec3(0,-1,0); - if (!u_rimambient) { - v = normalize(u_rimpivot-p); - } - float rim = 1.0 - max(dot(v,n), 0.0); - vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z)); - fragcolor += vec4(col, 1.0);} + { + vec3 n = normalize(mat3(M) * v_normal); // convert normal to view space + vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space + vec3 v = vec3(0,-1,0); + if (!u_rimambient) { + v = normalize(u_rimpivot-p); + } + float rim = 1.0 - max(dot(v,n), 0.0); + vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z)); + fragcolor += vec4(col, 1.0);} #endif } \ No newline at end of file diff --git a/engine/art/shaders/vs_323444143_16_332_model.glsl b/engine/art/shaders/vs_3223444143_16_332_model.glsl similarity index 99% rename from engine/art/shaders/vs_323444143_16_332_model.glsl rename to engine/art/shaders/vs_3223444143_16_332_model.glsl index 4e1044f..ca83128 100644 --- a/engine/art/shaders/vs_323444143_16_332_model.glsl +++ b/engine/art/shaders/vs_3223444143_16_332_model.glsl @@ -49,6 +49,7 @@ uniform sampler2DArray blend_shapes; // @todo: implement me in vec3 att_position; // @todo: reorder ass2iqe to emit p3 n3 u2 t3 b3 c4B i4 w4 instead in vec2 att_texcoord; +in vec2 att_texcoord2; in vec3 att_normal; in vec4 att_tangent; // vec3 + bi sign in mat4 att_instanced_matrix; // for instanced rendering diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 5f24544..4b73396 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -15930,9 +15930,6 @@ API void script_call(const char *lua_function); API bool script_tests(); -// ----------------------------------------------------------------------------- -// script framework - enum { SCRIPT_LUA = 1, SCRIPT_DEBUGGER = 2, @@ -17514,6 +17511,7 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; + texture_t *lightmap; unsigned num_meshes; unsigned num_triangles; @@ -17524,7 +17522,7 @@ typedef struct model_t { float curframe; mat44 pivot; - int stride; // usually 60 bytes (12*4+4*3) for a p3 u2 n3 t4 i4B w4B c4B vertex stream + int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; handle vao, ibo, vbo, vao_instanced; @@ -17573,11 +17571,22 @@ API anims_t animations(const char *pathfile, int flags); // ----------------------------------------------------------------------------- // lightmapping utils +// @fixme: support xatlas uv packing typedef struct lightmap_t { struct lm_context *ctx; // private + bool ready; + texture_t lightmap; //@fixme: do we need it per-model? + array(model_t*) models; } lightmap_t; +API lightmap_t lightmap(int hmsize /*64*/, float near, float far, vec3 color /*1,1,1 for AO*/, int passes /*2*/, float threshold /*0.01f*/, float distmod /*0.0f*/); +API void lightmap_setup(lightmap_t *lm, int w, int h); +API void lightmap_addmodel(lightmap_t *lm, model_t *m); +API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata); +API void lightmap_clear(lightmap_t *lm); +API void lightmap_destroy(lightmap_t *lm); + // ----------------------------------------------------------------------------- // skyboxes @@ -369313,6 +369322,7 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; + GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; @@ -369472,26 +369482,28 @@ void model_set_state(model_t m) { glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); - glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(11); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(12); // animation if(numframes > 0) { - glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); - glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); - glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); - glEnableVertexAttribArray(8); + glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); + glVertexAttribPointer( 10, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); + glVertexAttribPointer(11, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); + glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -369503,20 +369515,20 @@ void model_set_state(model_t m) { glBindBuffer(GL_ARRAY_BUFFER, m.vao_instanced); glBufferData(GL_ARRAY_BUFFER, m.num_instances * mat4_size, m.instanced_matrices, GL_STATIC_DRAW); - glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); - glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); - glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glEnableVertexAttribArray(6); glEnableVertexAttribArray(7); + glEnableVertexAttribArray(8); - glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glVertexAttribDivisor(6, 1); glVertexAttribDivisor(7, 1); + glVertexAttribDivisor(8, 1); } // 7 bitangent? into texcoord.z? @@ -369598,7 +369610,10 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { if(inposition) memcpy(v->position, &inposition[i*3], sizeof(v->position)); if(innormal) memcpy(v->normal, &innormal[i*3], sizeof(v->normal)); if(intangent) memcpy(v->tangent, &intangent[i*4], sizeof(v->tangent)); - if(intexcoord) memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + if(intexcoord) { + memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + memcpy(v->texcoord2, &intexcoord[i*2], sizeof(v->texcoord2)); // populate UV1 with the same value, used by lightmapper + } if(inblendindex8) memcpy(v->blendindexes, &inblendindex8[i*4], sizeof(v->blendindexes)); if(inblendweight8) memcpy(v->blendweights, &inblendweight8[i*4], sizeof(v->blendweights)); if(inblendindexi) { @@ -369868,8 +369883,8 @@ model_t model_from_mem(const void *mem, int len, int flags) { // static int shaderprog = -1; // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_3223444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + "att_position,att_texcoord,att_texcoord2,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -370259,6 +370274,129 @@ anims_t animations(const char *pathfile, int flags) { } return a; } + +// ----------------------------------------------------------------------------- +// lightmapping utils +// @fixme: support xatlas uv packing, add UV1 coords to vertex model specs +lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, float threshold, float distmod) { + lightmap_t lm = {0}; + lm.ctx = lmCreate(hmsize, cnear, cfar, color.x, color.y, color.z, passes, threshold, distmod); + + if (!lm.ctx) { + PANIC("Error: Could not initialize lightmapper.\n"); + return lm; + } + + return lm; +} + +static +void lightmap_destroytexture(lightmap_t *lm) { + texture_destroy(&lm->lightmap); + for (int i = 0; i < array_count(lm->models); i++) { + lm->models[i]->lightmap = NULL; + } +} + +void lightmap_destroy(lightmap_t *lm) { + lmDestroy(lm->ctx); + lightmap_destroytexture(lm); + // +} + +void lightmap_setup(lightmap_t *lm, int w, int h) { + if (lm->ready) { + lightmap_destroytexture(lm); + } + lm->ready=1; + + lm->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + +void lightmap_addmodel(lightmap_t *lm, model_t *m) { + array_push(lm->models, m); +} + +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata) { + ASSERT(lm->ready); + // @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU. + // @fixme: combine all verts data together and push to lmSetGeometry + + // int w = lm->lightmap->w, h = lm->lightmap->h; + // float *data = CALLOC(w * h * 4, sizeof(float)); + // memset(data, 0, w*h*4); + // for (int b = 0; b < bounces; b++) { + // lmSetTargetLightmap(lm->ctx, data, w, h, 4); + + // lmSetGeometry(lm->ctx, NULL, + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, p), sizeof(vertex_t), + // LM_NONE , NULL , 0 , // no interpolated normals in this example + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, t), sizeof(vertex_t), + // scene->indexCount, LM_UNSIGNED_SHORT, scene->indices); + + + // glDisable(GL_BLEND); + + // int vp[4]; + // float view[16], projection[16]; + // double lastUpdateTime = 0.0; + // while (lmBegin(ctx, vp, view, projection)) + // { + // // render to lightmapper framebuffer + // glViewport(vp[0], vp[1], vp[2], vp[3]); + // drawScene(scene, view, projection); + + // // display progress every second (printf is expensive) + // double time = time_ms() / 1000.0; + // if (time - lastUpdateTime > 1.0) + // { + // lastUpdateTime = time; + // printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); + // fflush(stdout); + // } + + // lmEnd(ctx); + // // window_swap(); + // } + // printf("\rFinished baking %d triangles.\n", scene->indexCount / 3); + // } + + // lmDestroy(ctx); + + // // postprocess texture + // float *temp = CALLOC(w * h * 4, sizeof(float)); + // for (int i = 0; i < 16; i++) + // { + // lmImageDilate(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // } + // lmImageSmooth(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + // FREE(temp); + + // // save result to a file + // if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + + // // upload result + // glBindTexture(GL_TEXTURE_2D, scene->lightmap); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, data); + // FREE(data); +} + +void lightmap_clear(lightmap_t *lm) { + ASSERT(lm->ready); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + #line 0 #line 1 "v4k_renderdd.c" diff --git a/engine/split/v4k_extend.h b/engine/split/v4k_extend.h index 3254ffa..d6b67f6 100644 --- a/engine/split/v4k_extend.h +++ b/engine/split/v4k_extend.h @@ -23,9 +23,6 @@ API void script_call(const char *lua_function); API bool script_tests(); -// ----------------------------------------------------------------------------- -// script framework - enum { SCRIPT_LUA = 1, SCRIPT_DEBUGGER = 2, diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 414d192..2471c9b 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -2766,6 +2766,7 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; + GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; @@ -2925,26 +2926,28 @@ void model_set_state(model_t m) { glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); - glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(11); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(12); // animation if(numframes > 0) { - glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); - glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); - glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); - glEnableVertexAttribArray(8); + glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); + glVertexAttribPointer( 10, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); + glVertexAttribPointer(11, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); + glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -2956,20 +2959,20 @@ void model_set_state(model_t m) { glBindBuffer(GL_ARRAY_BUFFER, m.vao_instanced); glBufferData(GL_ARRAY_BUFFER, m.num_instances * mat4_size, m.instanced_matrices, GL_STATIC_DRAW); - glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); - glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); - glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glEnableVertexAttribArray(6); glEnableVertexAttribArray(7); + glEnableVertexAttribArray(8); - glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glVertexAttribDivisor(6, 1); glVertexAttribDivisor(7, 1); + glVertexAttribDivisor(8, 1); } // 7 bitangent? into texcoord.z? @@ -3051,7 +3054,10 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { if(inposition) memcpy(v->position, &inposition[i*3], sizeof(v->position)); if(innormal) memcpy(v->normal, &innormal[i*3], sizeof(v->normal)); if(intangent) memcpy(v->tangent, &intangent[i*4], sizeof(v->tangent)); - if(intexcoord) memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + if(intexcoord) { + memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + memcpy(v->texcoord2, &intexcoord[i*2], sizeof(v->texcoord2)); // populate UV1 with the same value, used by lightmapper + } if(inblendindex8) memcpy(v->blendindexes, &inblendindex8[i*4], sizeof(v->blendindexes)); if(inblendweight8) memcpy(v->blendweights, &inblendweight8[i*4], sizeof(v->blendweights)); if(inblendindexi) { @@ -3321,8 +3327,8 @@ model_t model_from_mem(const void *mem, int len, int flags) { // static int shaderprog = -1; // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_3223444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + "att_position,att_texcoord,att_texcoord2,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -3712,3 +3718,126 @@ anims_t animations(const char *pathfile, int flags) { } return a; } + +// ----------------------------------------------------------------------------- +// lightmapping utils +// @fixme: support xatlas uv packing, add UV1 coords to vertex model specs +lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, float threshold, float distmod) { + lightmap_t lm = {0}; + lm.ctx = lmCreate(hmsize, cnear, cfar, color.x, color.y, color.z, passes, threshold, distmod); + + if (!lm.ctx) { + PANIC("Error: Could not initialize lightmapper.\n"); + return lm; + } + + return lm; +} + +static +void lightmap_destroytexture(lightmap_t *lm) { + texture_destroy(&lm->lightmap); + for (int i = 0; i < array_count(lm->models); i++) { + lm->models[i]->lightmap = NULL; + } +} + +void lightmap_destroy(lightmap_t *lm) { + lmDestroy(lm->ctx); + lightmap_destroytexture(lm); + // +} + +void lightmap_setup(lightmap_t *lm, int w, int h) { + if (lm->ready) { + lightmap_destroytexture(lm); + } + lm->ready=1; + + lm->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + +void lightmap_addmodel(lightmap_t *lm, model_t *m) { + array_push(lm->models, m); +} + +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata) { + ASSERT(lm->ready); + // @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU. + // @fixme: combine all verts data together and push to lmSetGeometry + + // int w = lm->lightmap->w, h = lm->lightmap->h; + // float *data = CALLOC(w * h * 4, sizeof(float)); + // memset(data, 0, w*h*4); + // for (int b = 0; b < bounces; b++) { + // lmSetTargetLightmap(lm->ctx, data, w, h, 4); + + // lmSetGeometry(lm->ctx, NULL, + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, p), sizeof(vertex_t), + // LM_NONE , NULL , 0 , // no interpolated normals in this example + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, t), sizeof(vertex_t), + // scene->indexCount, LM_UNSIGNED_SHORT, scene->indices); + + + // glDisable(GL_BLEND); + + // int vp[4]; + // float view[16], projection[16]; + // double lastUpdateTime = 0.0; + // while (lmBegin(ctx, vp, view, projection)) + // { + // // render to lightmapper framebuffer + // glViewport(vp[0], vp[1], vp[2], vp[3]); + // drawScene(scene, view, projection); + + // // display progress every second (printf is expensive) + // double time = time_ms() / 1000.0; + // if (time - lastUpdateTime > 1.0) + // { + // lastUpdateTime = time; + // printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); + // fflush(stdout); + // } + + // lmEnd(ctx); + // // window_swap(); + // } + // printf("\rFinished baking %d triangles.\n", scene->indexCount / 3); + // } + + // lmDestroy(ctx); + + // // postprocess texture + // float *temp = CALLOC(w * h * 4, sizeof(float)); + // for (int i = 0; i < 16; i++) + // { + // lmImageDilate(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // } + // lmImageSmooth(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + // FREE(temp); + + // // save result to a file + // if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + + // // upload result + // glBindTexture(GL_TEXTURE_2D, scene->lightmap); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, data); + // FREE(data); +} + +void lightmap_clear(lightmap_t *lm) { + ASSERT(lm->ready); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index e784c97..c374521 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -520,6 +520,7 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; + texture_t *lightmap; unsigned num_meshes; unsigned num_triangles; @@ -530,7 +531,7 @@ typedef struct model_t { float curframe; mat44 pivot; - int stride; // usually 60 bytes (12*4+4*3) for a p3 u2 n3 t4 i4B w4B c4B vertex stream + int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; handle vao, ibo, vbo, vao_instanced; @@ -579,11 +580,22 @@ API anims_t animations(const char *pathfile, int flags); // ----------------------------------------------------------------------------- // lightmapping utils +// @fixme: support xatlas uv packing typedef struct lightmap_t { struct lm_context *ctx; // private + bool ready; + texture_t lightmap; //@fixme: do we need it per-model? + array(model_t*) models; } lightmap_t; +API lightmap_t lightmap(int hmsize /*64*/, float near, float far, vec3 color /*1,1,1 for AO*/, int passes /*2*/, float threshold /*0.01f*/, float distmod /*0.0f*/); +API void lightmap_setup(lightmap_t *lm, int w, int h); +API void lightmap_addmodel(lightmap_t *lm, model_t *m); +API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata); +API void lightmap_clear(lightmap_t *lm); +API void lightmap_destroy(lightmap_t *lm); + // ----------------------------------------------------------------------------- // skyboxes diff --git a/engine/v4k.c b/engine/v4k.c index 706ffff..8aac7d3 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -19682,6 +19682,7 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; + GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; @@ -19841,26 +19842,28 @@ void model_set_state(model_t m) { glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, position) ); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord) ); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); - glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, normal) ); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, tangent) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); + glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(11); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(12); // animation if(numframes > 0) { - glVertexAttribPointer( 8, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); - glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); - glVertexAttribPointer(10, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); - glEnableVertexAttribArray(8); + glVertexAttribPointer( 9, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendindexes) ); + glVertexAttribPointer( 10, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,blendweights) ); + glVertexAttribPointer(11, 1, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, blendvertexindex) ); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); + glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -19872,20 +19875,20 @@ void model_set_state(model_t m) { glBindBuffer(GL_ARRAY_BUFFER, m.vao_instanced); glBufferData(GL_ARRAY_BUFFER, m.num_instances * mat4_size, m.instanced_matrices, GL_STATIC_DRAW); - glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); - glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); + glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(0 * vec4_size))); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(1 * vec4_size))); + glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(2 * vec4_size))); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, 4 * vec4_size, (GLvoid*)(((char*)NULL)+(3 * vec4_size))); - glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glEnableVertexAttribArray(6); glEnableVertexAttribArray(7); + glEnableVertexAttribArray(8); - glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glVertexAttribDivisor(6, 1); glVertexAttribDivisor(7, 1); + glVertexAttribDivisor(8, 1); } // 7 bitangent? into texcoord.z? @@ -19967,7 +19970,10 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { if(inposition) memcpy(v->position, &inposition[i*3], sizeof(v->position)); if(innormal) memcpy(v->normal, &innormal[i*3], sizeof(v->normal)); if(intangent) memcpy(v->tangent, &intangent[i*4], sizeof(v->tangent)); - if(intexcoord) memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + if(intexcoord) { + memcpy(v->texcoord, &intexcoord[i*2], sizeof(v->texcoord)); + memcpy(v->texcoord2, &intexcoord[i*2], sizeof(v->texcoord2)); // populate UV1 with the same value, used by lightmapper + } if(inblendindex8) memcpy(v->blendindexes, &inblendindex8[i*4], sizeof(v->blendindexes)); if(inblendweight8) memcpy(v->blendweights, &inblendweight8[i*4], sizeof(v->blendweights)); if(inblendindexi) { @@ -20237,8 +20243,8 @@ model_t model_from_mem(const void *mem, int len, int flags) { // static int shaderprog = -1; // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_3223444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + "att_position,att_texcoord,att_texcoord2,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -20628,6 +20634,129 @@ anims_t animations(const char *pathfile, int flags) { } return a; } + +// ----------------------------------------------------------------------------- +// lightmapping utils +// @fixme: support xatlas uv packing, add UV1 coords to vertex model specs +lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, float threshold, float distmod) { + lightmap_t lm = {0}; + lm.ctx = lmCreate(hmsize, cnear, cfar, color.x, color.y, color.z, passes, threshold, distmod); + + if (!lm.ctx) { + PANIC("Error: Could not initialize lightmapper.\n"); + return lm; + } + + return lm; +} + +static +void lightmap_destroytexture(lightmap_t *lm) { + texture_destroy(&lm->lightmap); + for (int i = 0; i < array_count(lm->models); i++) { + lm->models[i]->lightmap = NULL; + } +} + +void lightmap_destroy(lightmap_t *lm) { + lmDestroy(lm->ctx); + lightmap_destroytexture(lm); + // +} + +void lightmap_setup(lightmap_t *lm, int w, int h) { + if (lm->ready) { + lightmap_destroytexture(lm); + } + lm->ready=1; + + lm->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + +void lightmap_addmodel(lightmap_t *lm, model_t *m) { + array_push(lm->models, m); +} + +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata) { + ASSERT(lm->ready); + // @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU. + // @fixme: combine all verts data together and push to lmSetGeometry + + // int w = lm->lightmap->w, h = lm->lightmap->h; + // float *data = CALLOC(w * h * 4, sizeof(float)); + // memset(data, 0, w*h*4); + // for (int b = 0; b < bounces; b++) { + // lmSetTargetLightmap(lm->ctx, data, w, h, 4); + + // lmSetGeometry(lm->ctx, NULL, + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, p), sizeof(vertex_t), + // LM_NONE , NULL , 0 , // no interpolated normals in this example + // LM_FLOAT, (unsigned char*)scene->vertices + offsetof(vertex_t, t), sizeof(vertex_t), + // scene->indexCount, LM_UNSIGNED_SHORT, scene->indices); + + + // glDisable(GL_BLEND); + + // int vp[4]; + // float view[16], projection[16]; + // double lastUpdateTime = 0.0; + // while (lmBegin(ctx, vp, view, projection)) + // { + // // render to lightmapper framebuffer + // glViewport(vp[0], vp[1], vp[2], vp[3]); + // drawScene(scene, view, projection); + + // // display progress every second (printf is expensive) + // double time = time_ms() / 1000.0; + // if (time - lastUpdateTime > 1.0) + // { + // lastUpdateTime = time; + // printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); + // fflush(stdout); + // } + + // lmEnd(ctx); + // // window_swap(); + // } + // printf("\rFinished baking %d triangles.\n", scene->indexCount / 3); + // } + + // lmDestroy(ctx); + + // // postprocess texture + // float *temp = CALLOC(w * h * 4, sizeof(float)); + // for (int i = 0; i < 16; i++) + // { + // lmImageDilate(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // } + // lmImageSmooth(data, temp, w, h, 4); + // lmImageDilate(temp, data, w, h, 4); + // lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + // FREE(temp); + + // // save result to a file + // if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + + // // upload result + // glBindTexture(GL_TEXTURE_2D, scene->lightmap); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, data); + // FREE(data); +} + +void lightmap_clear(lightmap_t *lm) { + ASSERT(lm->ready); + glBindTexture(GL_TEXTURE_2D, lm->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); +} + #line 0 #line 1 "v4k_renderdd.c" diff --git a/engine/v4k.h b/engine/v4k.h index f5253d9..1393659 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -1997,9 +1997,6 @@ API void script_call(const char *lua_function); API bool script_tests(); -// ----------------------------------------------------------------------------- -// script framework - enum { SCRIPT_LUA = 1, SCRIPT_DEBUGGER = 2, @@ -3581,6 +3578,7 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; + texture_t *lightmap; unsigned num_meshes; unsigned num_triangles; @@ -3591,7 +3589,7 @@ typedef struct model_t { float curframe; mat44 pivot; - int stride; // usually 60 bytes (12*4+4*3) for a p3 u2 n3 t4 i4B w4B c4B vertex stream + int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; handle vao, ibo, vbo, vao_instanced; @@ -3640,11 +3638,22 @@ API anims_t animations(const char *pathfile, int flags); // ----------------------------------------------------------------------------- // lightmapping utils +// @fixme: support xatlas uv packing typedef struct lightmap_t { struct lm_context *ctx; // private + bool ready; + texture_t lightmap; //@fixme: do we need it per-model? + array(model_t*) models; } lightmap_t; +API lightmap_t lightmap(int hmsize /*64*/, float near, float far, vec3 color /*1,1,1 for AO*/, int passes /*2*/, float threshold /*0.01f*/, float distmod /*0.0f*/); +API void lightmap_setup(lightmap_t *lm, int w, int h); +API void lightmap_addmodel(lightmap_t *lm, model_t *m); +API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, float *view, float *proj, void *userdata), void *userdata); +API void lightmap_clear(lightmap_t *lm); +API void lightmap_destroy(lightmap_t *lm); + // ----------------------------------------------------------------------------- // skyboxes