diff --git a/bind/v4k.lua b/bind/v4k.lua index 4556c1b..5f7377b 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -2957,7 +2957,8 @@ unsigned num_textures; handle *textures; char **texture_names; material_t* materials; -texture_t *lightmap; +texture_t lightmap; +float *lmdata; unsigned num_meshes; unsigned num_triangles; unsigned num_joints; @@ -2969,6 +2970,8 @@ mat44 pivot; int stride; void *verts; int num_verts; +void *tris; +int num_tris; handle vao, ibo, vbo, vao_instanced; unsigned flags; unsigned billboard; @@ -3004,14 +3007,15 @@ anim_t* anims; typedef struct lightmap_t { struct lm_context *ctx; bool ready; -texture_t lightmap; +int w, h; +int atlas_w, atlas_h; +texture_t atlas; model_t** models; +unsigned shader; } 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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void *userdata); void lightmap_destroy(lightmap_t *lm); typedef struct skybox_t { handle program; @@ -3337,7 +3341,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,3954)___COUNTER__; typedef struct { unsigned static_assert_on_L__LINE__ : !!(sizeof(sprite_t)); } static_assert_on_Lconcat(_L,3954)___COUNTER__;; +enum { OBJTYPE_sprite_t = 10 }; typedef struct { unsigned static_assert_on_L__LINE__ : !!(10 <= 255); } static_assert_on_Lconcat(_L,3959)___COUNTER__; typedef struct { unsigned static_assert_on_L__LINE__ : !!(sizeof(sprite_t)); } static_assert_on_Lconcat(_L,3959)___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 631c27a..9b5c05c 100644 --- a/demos/99-lmap.c +++ b/demos/99-lmap.c @@ -1,407 +1,63 @@ #include "v4k.h" -#define LIGHTMAPPER_IMPLEMENTATION -//#define LM_DEBUG_INTERPOLATION -#include "3rd_lightmapper.h" +skybox_t sky; +model_t litm; -#define scene_t scene_t2 - -typedef struct { - float p[3]; - float t[2]; -} vertex_t; - -typedef struct -{ - GLuint program; - GLint u_lightmap; - GLint u_projection; - GLint u_view; - - GLuint lightmap; - int w, h; - - GLuint vao, vbo, ibo; - vertex_t *vertices; - unsigned short *indices; - unsigned int vertexCount, indexCount; -} scene_t; - -static int initScene(scene_t *scene); -static void drawScene(scene_t *scene, float *view, float *projection); -static void destroyScene(scene_t *scene); - -static int bake(scene_t *scene) -{ - lm_context *ctx = lmCreate( - 64, // hemisphere resolution (power of two, max=512) - 0.001f, 100.0f, // zNear, zFar of hemisphere cameras - 1.0f, 1.0f, 1.0f, // background color (white for ambient occlusion) - 2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled) - // check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels. - 0.0f); // modifier for camera-to-surface distance for hemisphere rendering. - // tweak this to trade-off between interpolated normals quality and other artifacts (see declaration). - - if (!ctx) - { - fprintf(stderr, "Error: Could not initialize lightmapper.\n"); - return 0; - } - - int w = scene->w, h = scene->h; - float *data = CALLOC(w * h * 4, sizeof(float)); - for (int b = 0; b < 1; b++) { - memset(data, 0, w*h*4); - lmSetTargetLightmap(ctx, data, w, h, 4); - - lmSetGeometry(ctx, NULL, // no transformation in this example - 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); - - return 1; -} - -static void fpsCameraViewMatrix(float *view); - -static void mainLoop(scene_t *scene) -{ - glViewport(0, 0, window_width(), window_height()); - - // camera for glfw window - float view[16], projection[16]; - fpsCameraViewMatrix(view); - perspective44(projection, 45.0f, window_aspect(), 0.01f, 100.0f); - - // draw to screen with a blueish sky - glClearColor(0.6f, 0.8f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - drawScene(scene, view, projection); +void bakedrawmodel(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata) { + shader_bind(lm->shader); + model_render(*m, proj, view, m->pivot, lm->shader); + shader_float("u_litboost", 4.0); + model_render(litm, proj, view, litm.pivot, lm->shader); } int main() { window_create(0.5, WINDOW_VSYNC_DISABLED); - - scene_t scene = {0}; - if (!initScene(&scene)) + camera_t cam = camera(); + sky = skybox(0, 0); skybox_mie_calc_sh(&sky, 2.0f); + model_t mdl = model("gazebo.obj", 0); + litm = model("cube.obj", MODEL_MATCAPS); { - fprintf(stderr, "Could not initialize scene.\n"); - return EXIT_FAILURE; + mat44 lp; scaling44(lp, 0.3, 0.3, 0.3); translate44(lp, 8,4,0); + copy44(litm.pivot, lp); } + rotate44(mdl.pivot, -90, 1, 0, 0); + scale44(mdl.pivot, 4,4,4); + shader_bind(mdl.program); + shader_vec3v("u_coefficients_sh", 9, sky.cubemap.sh); + // shader_bool("u_texmod", 0); + + unsigned char emissive[] = { 255, 180, 0, 255 }; + texture_t emission = texture_create(1,1,4,emissive,TEXTURE_LINEAR); + model_set_texture(litm, emission); + + lightmap_t baker = lightmap(64, 0.001, 1000, vec3(0,0,0), 2, 0.01, 0.0); + lightmap_setup(&baker, 640, 640); + array_push(baker.models, &mdl); window_title("AO Baking demo"); - while (window_swap()) - { - mainLoop(&scene); + while (window_swap() && !input(KEY_ESC)) { + bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); + if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f); + vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); + vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed); + camera_moveby(&cam, wasdecq); + camera_fps(&cam, mouse.x,mouse.y); + window_cursor( !active ); + + skybox_render(&sky, cam.proj, cam.view); + model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); + model_render(litm, cam.proj, cam.view, litm.pivot, 0); if( ui_panel("Lightmapper", PANEL_OPEN) ) { ui_label2("Freecam", "Mouse + W/A/S/D/E/Q keys"); ui_label("Warning " ICON_MD_WARNING "@This will take a few seconds and bake a lightmap illuminated by: The mesh itself (initially black) + A white sky (1.0f, 1.0f, 1.0f)"); - if( ui_button("Bake 1 light bounce") ) { - bake(&scene); + int b=2; + if( ui_button(va("Bake %d light bounce", b)) ) { + lightmap_bake(&baker, b, bakedrawmodel, 0); } ui_panel_end(); } } - - destroyScene(&scene); } - -// helpers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static int loadSimpleObjFile(const char *filename, vertex_t **vertices, unsigned int *vertexCount, unsigned short **indices, unsigned int *indexCount); - -static int initScene(scene_t *scene) -{ - // load mesh - if (!loadSimpleObjFile("demos/art/meshes/gazebo.obj", &scene->vertices, &scene->vertexCount, &scene->indices, &scene->indexCount)) - { - fprintf(stderr, "Error loading obj file\n"); - return 0; - } - - glGenVertexArrays(1, &scene->vao); - glBindVertexArray(scene->vao); - - glGenBuffers(1, &scene->vbo); - glBindBuffer(GL_ARRAY_BUFFER, scene->vbo); - glBufferData(GL_ARRAY_BUFFER, scene->vertexCount * sizeof(vertex_t), scene->vertices, GL_STATIC_DRAW); - - glGenBuffers(1, &scene->ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, scene->ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, scene->indexCount * sizeof(unsigned short), scene->indices, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, p)); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)offsetof(vertex_t, t)); - - // create lightmap texture - scene->w = 654; - scene->h = 654; - glGenTextures(1, &scene->lightmap); - glBindTexture(GL_TEXTURE_2D, scene->lightmap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - unsigned char emissive[] = { 0, 0, 0, 255 }; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); - - // load shader - const char *vp = - "in vec3 a_position;\n" - "in vec2 a_texcoord;\n" - "uniform mat4 u_view;\n" - "uniform mat4 u_projection;\n" - "out vec2 v_texcoord;\n" - - "void main()\n" - "{\n" - "gl_Position = u_projection * (u_view * vec4(a_position, 1.0));\n" - "v_texcoord = a_texcoord;\n" - "}\n"; - - const char *fp = - "in vec2 v_texcoord;\n" - "uniform sampler2D u_lightmap;\n" - "out vec4 o_color;\n" - - "void main()\n" - "{\n" - "o_color = vec4(texture(u_lightmap, v_texcoord).rgb, gl_FrontFacing ? 1.0 : 0.0);\n" - "}\n"; - - scene->program = shader(vp, fp, "a_position,a_texcoord", "o_color", NULL); - if (!scene->program) - { - fprintf(stderr, "Error loading shader\n"); - return 0; - } - scene->u_view = glGetUniformLocation(scene->program, "u_view"); - scene->u_projection = glGetUniformLocation(scene->program, "u_projection"); - scene->u_lightmap = glGetUniformLocation(scene->program, "u_lightmap"); - - return 1; -} - -static void drawScene(scene_t *scene, float *view, float *projection) -{ - glEnable(GL_DEPTH_TEST); - - glUseProgram(scene->program); - glUniform1i(scene->u_lightmap, 0); - glUniformMatrix4fv(scene->u_projection, 1, GL_FALSE, projection); - glUniformMatrix4fv(scene->u_view, 1, GL_FALSE, view); - - glBindTexture(GL_TEXTURE_2D, scene->lightmap); - - glBindVertexArray(scene->vao); - glDrawElements(GL_TRIANGLES, scene->indexCount, GL_UNSIGNED_SHORT, 0); -} - -static void destroyScene(scene_t *scene) -{ - FREE(scene->vertices); - FREE(scene->indices); - glDeleteVertexArrays(1, &scene->vao); - glDeleteBuffers(1, &scene->vbo); - glDeleteBuffers(1, &scene->ibo); - glDeleteTextures(1, &scene->lightmap); - glDeleteProgram(scene->program); -} - -static int loadSimpleObjFile(const char *filename, vertex_t **vertices, unsigned int *vertexCount, unsigned short **indices, unsigned int *indexCount) -{ - FILE *file = fopen(filename, "rt"); - if (!file) - return 0; - char line[1024]; - - // first pass - unsigned int np = 0, nn = 0, nt = 0, nf = 0; - while (!feof(file)) - { - fgets(line, 1024, file); - if (line[0] == '#') continue; - if (line[0] == 'v') - { - if (line[1] == ' ') { np++; continue; } - if (line[1] == 'n') { nn++; continue; } - if (line[1] == 't') { nt++; continue; } - assert(!"unknown vertex attribute"); - } - if (line[0] == 'f') { nf++; continue; } - assert(!"unknown identifier"); - } - assert(np && np == nn && np == nt && nf); // only supports obj files without separately indexed vertex attributes - - // allocate memory - *vertexCount = np; - *vertices = CALLOC(np, sizeof(vertex_t)); - *indexCount = nf * 3; - *indices = CALLOC(nf * 3, sizeof(unsigned short)); - - // second pass - fseek(file, 0, SEEK_SET); - unsigned int cp = 0, cn = 0, ct = 0, cf = 0; - while (!feof(file)) - { - fgets(line, 1024, file); - if (line[0] == '#') continue; - if (line[0] == 'v') - { - if (line[1] == ' ') { float *p = (*vertices)[cp++].p; char *e1, *e2; p[0] = (float)strtod(line + 2, &e1); p[1] = (float)strtod(e1, &e2); p[2] = (float)strtod(e2, 0); continue; } - if (line[1] == 'n') { /*float *n = (*vertices)[cn++].n; char *e1, *e2; n[0] = (float)strtod(line + 3, &e1); n[1] = (float)strtod(e1, &e2); n[2] = (float)strtod(e2, 0);*/ continue; } // no normals needed - if (line[1] == 't') { float *t = (*vertices)[ct++].t; char *e1; t[0] = (float)strtod(line + 3, &e1); t[1] = (float)strtod(e1, 0); continue; } - assert(!"unknown vertex attribute"); - } - if (line[0] == 'f') - { - unsigned short *tri = (*indices) + cf; - cf += 3; - char *e1, *e2, *e3 = line + 1; - for (int i = 0; i < 3; i++) - { - unsigned long pi = strtoul(e3 + 1, &e1, 10); - assert(e1[0] == '/'); - unsigned long ti = strtoul(e1 + 1, &e2, 10); - assert(e2[0] == '/'); - unsigned long ni = strtoul(e2 + 1, &e3, 10); - assert(pi == ti && pi == ni); - tri[i] = (unsigned short)(pi - 1); - } - continue; - } - assert(!"unknown identifier"); - } - - fclose(file); - return 1; -} - - - -static void fpsCameraViewMatrix(float *view) -{ - // initial camera config - static float position[] = { 0.0f, 0.3f, 1.5f }; - static float rotation[] = { 0.0f, 0.0f }; - - // mouse look - static double lastMouse[] = { 0.0, 0.0 }; - double mouse_coord[2]; - mouse_coord[0] = input(MOUSE_X); - mouse_coord[1] = input(MOUSE_Y); - if (input(MOUSE_L)) - { - rotation[0] += (float)(mouse_coord[1] - lastMouse[1]) * -0.2f; - rotation[1] += (float)(mouse_coord[0] - lastMouse[0]) * -0.2f; - } - lastMouse[0] = mouse_coord[0]; - lastMouse[1] = mouse_coord[1]; - - float rotationY[16], rotationX[16], rotationYX[16]; - rotation44(rotationX, rotation[0], 1.0f, 0.0f, 0.0f); - rotation44(rotationY, rotation[1], 0.0f, 1.0f, 0.0f); - multiply44x2(rotationYX, rotationY, rotationX); - - // keyboard movement (WSADEQ) - float speed = input(KEY_SHIFT) ? 0.1f : 0.01f; - vec3 movement = {0}; - if (input(KEY_W)) movement.z -= speed; - if (input(KEY_S)) movement.z += speed; - if (input(KEY_A)) movement.x -= speed; - if (input(KEY_D)) movement.x += speed; - if (input(KEY_E)) movement.y -= speed; - if (input(KEY_Q)) movement.y += speed; - - vec3 worldMovement = transform344(rotationYX, movement); - position[0] += worldMovement.x; - position[1] += worldMovement.y; - position[2] += worldMovement.z; - - // construct view matrix - float inverseRotation[16], inverseTranslation[16]; - transpose44(inverseRotation, rotationYX); - translation44(inverseTranslation, -position[0], -position[1], -position[2]); - multiply44x2(view, inverseRotation, inverseTranslation); // = inverse(translation(position) * rotationYX); -} - -#if 0 - -####################################################################### - 76702 17.93% rendered hemicubes integrated to lightmap texels. - 179388 41.94% interpolated lightmap texels. - 171626 40.13% wasted lightmap texels. - - 29.95% of used texels were rendered. -####################################################################### -Finished baking 731 triangles. -Saved result.tga - -vs - -####################################################################### - 124 0.05% rendered hemicubes integrated to lightmap texels. - 201 0.08% interpolated lightmap texels. - 261947 99.88% wasted lightmap texels. - - 38.15% of used texels were rendered. -####################################################################### -Finished baking 731 triangles. -Saved result.tga - -#endif - diff --git a/engine/art/shaders/fs_32_4_model.glsl b/engine/art/shaders/fs_32_4_model.glsl index c439a3b..4d2b0f3 100644 --- a/engine/art/shaders/fs_32_4_model.glsl +++ b/engine/art/shaders/fs_32_4_model.glsl @@ -6,6 +6,12 @@ uniform bool u_lit = false; uniform bool u_matcaps = false; uniform vec4 u_diffuse = vec4(1.0,1.0,1.0,1.0); +// lightmapping +uniform sampler2D u_lightmap; +uniform bool u_texlit; +uniform bool u_texmod = true; +uniform float u_litboost = 1.0; + in vec3 v_position; in vec3 v_position_ws; #ifdef RIM @@ -16,7 +22,7 @@ uniform vec3 u_rimpivot = vec3(0,0,0); uniform bool u_rimambient = true; #endif in vec3 v_normal, v_normal_ws; -in vec2 v_texcoord; +in vec2 v_texcoord, v_texcoord2; in vec4 v_color; out vec4 fragcolor; @@ -110,25 +116,49 @@ vec3 lighting() { return lit; } +vec3 sh_lighting(vec3 n) { + vec3 SHLightResult[9]; + SHLightResult[0] = 0.282095f * u_coefficients_sh[0]; + SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y; + SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z; + SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x; + SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y; + SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z; + SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f); + SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z; + SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y); + vec3 result = vec3(0.0); + for (int i = 0; i < 9; ++i) + result += SHLightResult[i]; + return result; +} + +#ifdef LIGHTMAP_BAKING +void main() { + vec3 n = normalize(v_normal_ws); + vec4 diffuse; + + if(u_textured) { + diffuse = texture(u_texture2d, v_texcoord); + } else { + diffuse = u_diffuse; // * v_color; + } + + if (u_texlit) { + vec4 litsample = texture(u_lightmap, v_texcoord); + diffuse *= litsample; + } + + fragcolor = vec4(diffuse.rgb*u_litboost, 1.0); +} +#else void main() { vec3 n = normalize(v_normal_ws); vec4 lit = vec4(1.0, 1.0, 1.0, 1.0); // SH lighting - { - vec3 SHLightResult[9]; - SHLightResult[0] = 0.282095f * u_coefficients_sh[0]; - SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y; - SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z; - SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x; - SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y; - SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z; - SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f); - SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z; - SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y); - vec3 result = vec3(0.0); - for (int i = 0; i < 9; ++i) - result += SHLightResult[i]; + if (!u_texlit) { + vec3 result = sh_lighting(n); if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0); } @@ -146,6 +176,18 @@ void main() { } else { diffuse = u_diffuse; // * v_color; } + + if (u_texlit) { + vec4 litsample = texture(u_lightmap, v_texcoord); + + if (u_texmod) { + diffuse *= litsample; + } else { + diffuse += litsample; + } + + diffuse.rgb += sh_lighting(n); + } // lighting mix fragcolor = diffuse * lit * shadowing(); @@ -163,4 +205,5 @@ void main() { 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 +} +#endif diff --git a/engine/art/shaders/vs_3223444143_16_332_model.glsl b/engine/art/shaders/vs_323444143_16_3322_model.glsl similarity index 98% rename from engine/art/shaders/vs_3223444143_16_332_model.glsl rename to engine/art/shaders/vs_323444143_16_3322_model.glsl index ca83128..b9e94c2 100644 --- a/engine/art/shaders/vs_3223444143_16_332_model.glsl +++ b/engine/art/shaders/vs_323444143_16_3322_model.glsl @@ -49,7 +49,6 @@ 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 @@ -58,10 +57,11 @@ in vec4 att_weights; // @todo: downgrade from float to byte in float att_vertexindex; // for blendshapes in vec4 att_color; in vec3 att_bitangent; // @todo: remove? also, ass2iqe might output this +in vec2 att_texcoord2; out vec4 v_color; out vec3 v_position, v_position_ws; out vec3 v_normal, v_normal_ws; -out vec2 v_texcoord; +out vec2 v_texcoord, v_texcoord2; @@ -118,6 +118,7 @@ void main() { v_normal = normalize(v_normal); v_position = att_position; v_texcoord = att_texcoord; + v_texcoord2 = att_texcoord2; v_color = att_color; mat4 modelView = view * att_instanced_matrix; mat4 l_model = att_instanced_matrix; diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 4b73396..d1381e6 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17511,7 +17511,9 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; - texture_t *lightmap; + + texture_t lightmap; + float *lmdata; unsigned num_meshes; unsigned num_triangles; @@ -17525,6 +17527,8 @@ typedef struct model_t { int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; + void *tris; + int num_tris; handle vao, ibo, vbo, vao_instanced; unsigned flags; @@ -17576,15 +17580,16 @@ API anims_t animations(const char *pathfile, int flags); typedef struct lightmap_t { struct lm_context *ctx; // private bool ready; - texture_t lightmap; //@fixme: do we need it per-model? + int w, h; + int atlas_w, atlas_h; //@fixme: implement + texture_t atlas; //@fixme: implement this array(model_t*) models; + unsigned shader; } 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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void *userdata); API void lightmap_destroy(lightmap_t *lm); // ----------------------------------------------------------------------------- @@ -369322,13 +369327,13 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; - GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; GLubyte blendweights[4]; GLfloat blendvertexindex; GLubyte color[4]; + GLfloat texcoord2[2]; } iqm_vertex; typedef struct iqm_t { @@ -369438,6 +369443,13 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if( (loc = glGetUniformLocation(shader, "u_billboard")) >= 0 ) { glUniform1i( loc, m.billboard ); } + if( (loc = glGetUniformLocation(shader, "texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } + else + if( (loc = glGetUniformLocation(shader, "u_texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -369482,28 +369494,26 @@ 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, 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) ); + 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) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(12); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(11); // animation if(numframes > 0) { - 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) ); + 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); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); - glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -369515,22 +369525,26 @@ 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(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))); + 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))); + 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); } + // lmap data + glVertexAttribPointer(12, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glEnableVertexAttribArray(12); + // 7 bitangent? into texcoord.z? glBindVertexArray( 0 ); @@ -369595,6 +369609,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { } struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; + m->num_tris = hdr->num_triangles; + m->tris = (void*)tris; glGenVertexArrays(1, &vao); glBindVertexArray(vao); @@ -369636,22 +369652,22 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); -m->stride = sizeof(iqm_vertex); -#if 0 -m->stride = 0; -if(inposition) m->stride += sizeof(verts[0].position); -if(innormal) m->stride += sizeof(verts[0].normal); -if(intangent) m->stride += sizeof(verts[0].tangent); -if(intexcoord) m->stride += sizeof(verts[0].texcoord); -if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? -if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? -if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); -if(inblendweightf) m->stride += sizeof(verts[0].blendweights); -if(invertexcolor8) m->stride += sizeof(verts[0].color); -#endif -//for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); -//m->verts = verts; //FREE(verts); -m->verts = 0; FREE(verts); + m->stride = sizeof(iqm_vertex); + #if 0 + m->stride = 0; + if(inposition) m->stride += sizeof(verts[0].position); + if(innormal) m->stride += sizeof(verts[0].normal); + if(intangent) m->stride += sizeof(verts[0].tangent); + if(intexcoord) m->stride += sizeof(verts[0].texcoord); + if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? + if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? + if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); + if(inblendweightf) m->stride += sizeof(verts[0].blendweights); + if(invertexcolor8) m->stride += sizeof(verts[0].color); + #endif + //for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); + m->verts = verts; + /*m->verts = 0; FREE(verts);*/ textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); @@ -369883,8 +369899,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_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", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -370126,7 +370142,7 @@ float model_animate(model_t m, float curframe) { } static -void model_draw_call(model_t m) { +void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; @@ -370138,17 +370154,21 @@ void model_draw_call(model_t m) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[i] ); - glUniform1i(glGetUniformLocation(m.program, "fsDiffTex"), 0 /*<-- unit!*/ ); + glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; - if ((loc = glGetUniformLocation(m.program, "u_textured")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(m.program, "u_diffuse")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); } } + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m.lightmap.id); + glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 ); + glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); profile_incstat("Render.num_drawcalls", +1); profile_incstat("Render.num_triangles", +im->num_triangles); @@ -370170,7 +370190,7 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in } model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m); + model_draw_call(m, shader > 0 ? shader : m.program); } void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { @@ -370287,114 +370307,99 @@ lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, return lm; } - return lm; -} + const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM + lm.shader = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", + va("%s", "LIGHTMAP_BAKING")); -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; - } + return lm; } void lightmap_destroy(lightmap_t *lm) { lmDestroy(lm->ctx); - lightmap_destroytexture(lm); + shader_destroy(lm->shader); // } 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); + //@fixme: prep atlas for lightmaps + lm->w = w; + lm->h = h; } -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) { +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, 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); + GLint cullface=0; + glGetIntegerv(GL_CULL_FACE, &cullface); + glDisable(GL_CULL_FACE); - // 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); + int w = lm->w, h = lm->h; + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (m->lightmap.w != 0) { + texture_destroy(&m->lightmap); + } + m->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR|TEXTURE_FLOAT); + glBindTexture(GL_TEXTURE_2D, m->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); + } + for (int b = 0; b < bounces; b++) { + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (!m->lmdata) { + m->lmdata = CALLOC(w*h*4, sizeof(float)); + } + memset(m->lmdata, 0, w*h*4); + lmSetTargetLightmap(lm->ctx, m->lmdata, w, h, 4); + lmSetGeometry(lm->ctx, m->pivot, + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, position), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, normal), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, texcoord), sizeof(iqm_vertex), + m->num_tris*3, LM_UNSIGNED_INT, m->tris); + + glDisable(GL_BLEND); + int vp[4]; + float view[16], projection[16]; + while (lmBegin(lm->ctx, vp, view, projection)) + { + // render to lightmapper framebuffer + glViewport(vp[0], vp[1], vp[2], vp[3]); + drawscene(lm, m, view, projection, userdata); + lmEnd(lm->ctx); + } + } + + // postprocess texture + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + float *temp = CALLOC(w * h * 4, sizeof(float)); + for (int i = 0; i < 16; i++) + { + lmImageDilate(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + } + lmImageSmooth(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + lmImagePower(m->lmdata, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + FREE(temp); + + // save result to a file + // if (lmImageSaveTGAf("result.tga", m->lmdata, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + // upload result + glBindTexture(GL_TEXTURE_2D, m->lightmap.id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, m->lmdata); + FREE(m->lmdata); m->lmdata = NULL; + } + } - // 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); + if (cullface) glEnable(GL_CULL_FACE); } #line 0 diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 2471c9b..c27d397 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -2766,13 +2766,13 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; - GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; GLubyte blendweights[4]; GLfloat blendvertexindex; GLubyte color[4]; + GLfloat texcoord2[2]; } iqm_vertex; typedef struct iqm_t { @@ -2882,6 +2882,13 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if( (loc = glGetUniformLocation(shader, "u_billboard")) >= 0 ) { glUniform1i( loc, m.billboard ); } + if( (loc = glGetUniformLocation(shader, "texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } + else + if( (loc = glGetUniformLocation(shader, "u_texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -2926,28 +2933,26 @@ 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, 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) ); + 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) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(12); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(11); // animation if(numframes > 0) { - 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) ); + 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); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); - glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -2959,22 +2964,26 @@ 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(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))); + 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))); + 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); } + // lmap data + glVertexAttribPointer(12, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glEnableVertexAttribArray(12); + // 7 bitangent? into texcoord.z? glBindVertexArray( 0 ); @@ -3039,6 +3048,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { } struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; + m->num_tris = hdr->num_triangles; + m->tris = (void*)tris; glGenVertexArrays(1, &vao); glBindVertexArray(vao); @@ -3080,22 +3091,22 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); -m->stride = sizeof(iqm_vertex); -#if 0 -m->stride = 0; -if(inposition) m->stride += sizeof(verts[0].position); -if(innormal) m->stride += sizeof(verts[0].normal); -if(intangent) m->stride += sizeof(verts[0].tangent); -if(intexcoord) m->stride += sizeof(verts[0].texcoord); -if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? -if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? -if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); -if(inblendweightf) m->stride += sizeof(verts[0].blendweights); -if(invertexcolor8) m->stride += sizeof(verts[0].color); -#endif -//for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); -//m->verts = verts; //FREE(verts); -m->verts = 0; FREE(verts); + m->stride = sizeof(iqm_vertex); + #if 0 + m->stride = 0; + if(inposition) m->stride += sizeof(verts[0].position); + if(innormal) m->stride += sizeof(verts[0].normal); + if(intangent) m->stride += sizeof(verts[0].tangent); + if(intexcoord) m->stride += sizeof(verts[0].texcoord); + if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? + if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? + if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); + if(inblendweightf) m->stride += sizeof(verts[0].blendweights); + if(invertexcolor8) m->stride += sizeof(verts[0].color); + #endif + //for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); + m->verts = verts; + /*m->verts = 0; FREE(verts);*/ textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); @@ -3327,8 +3338,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_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", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -3570,7 +3581,7 @@ float model_animate(model_t m, float curframe) { } static -void model_draw_call(model_t m) { +void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; @@ -3582,17 +3593,21 @@ void model_draw_call(model_t m) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[i] ); - glUniform1i(glGetUniformLocation(m.program, "fsDiffTex"), 0 /*<-- unit!*/ ); + glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; - if ((loc = glGetUniformLocation(m.program, "u_textured")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(m.program, "u_diffuse")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); } } + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m.lightmap.id); + glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 ); + glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); profile_incstat("Render.num_drawcalls", +1); profile_incstat("Render.num_triangles", +im->num_triangles); @@ -3614,7 +3629,7 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in } model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m); + model_draw_call(m, shader > 0 ? shader : m.program); } void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { @@ -3731,113 +3746,98 @@ lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, return lm; } - return lm; -} + const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM + lm.shader = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", + va("%s", "LIGHTMAP_BAKING")); -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; - } + return lm; } void lightmap_destroy(lightmap_t *lm) { lmDestroy(lm->ctx); - lightmap_destroytexture(lm); + shader_destroy(lm->shader); // } 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); + //@fixme: prep atlas for lightmaps + lm->w = w; + lm->h = h; } -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) { +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, 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); + GLint cullface=0; + glGetIntegerv(GL_CULL_FACE, &cullface); + glDisable(GL_CULL_FACE); - // 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); + int w = lm->w, h = lm->h; + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (m->lightmap.w != 0) { + texture_destroy(&m->lightmap); + } + m->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR|TEXTURE_FLOAT); + glBindTexture(GL_TEXTURE_2D, m->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); + } + for (int b = 0; b < bounces; b++) { + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (!m->lmdata) { + m->lmdata = CALLOC(w*h*4, sizeof(float)); + } + memset(m->lmdata, 0, w*h*4); + lmSetTargetLightmap(lm->ctx, m->lmdata, w, h, 4); + lmSetGeometry(lm->ctx, m->pivot, + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, position), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, normal), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, texcoord), sizeof(iqm_vertex), + m->num_tris*3, LM_UNSIGNED_INT, m->tris); + + glDisable(GL_BLEND); + int vp[4]; + float view[16], projection[16]; + while (lmBegin(lm->ctx, vp, view, projection)) + { + // render to lightmapper framebuffer + glViewport(vp[0], vp[1], vp[2], vp[3]); + drawscene(lm, m, view, projection, userdata); + lmEnd(lm->ctx); + } + } + + // postprocess texture + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + float *temp = CALLOC(w * h * 4, sizeof(float)); + for (int i = 0; i < 16; i++) + { + lmImageDilate(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + } + lmImageSmooth(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + lmImagePower(m->lmdata, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + FREE(temp); + + // save result to a file + // if (lmImageSaveTGAf("result.tga", m->lmdata, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + // upload result + glBindTexture(GL_TEXTURE_2D, m->lightmap.id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, m->lmdata); + FREE(m->lmdata); m->lmdata = NULL; + } + } - // 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); + if (cullface) glEnable(GL_CULL_FACE); } diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index c374521..a4b6518 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -520,7 +520,9 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; - texture_t *lightmap; + + texture_t lightmap; + float *lmdata; unsigned num_meshes; unsigned num_triangles; @@ -534,6 +536,8 @@ typedef struct model_t { int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; + void *tris; + int num_tris; handle vao, ibo, vbo, vao_instanced; unsigned flags; @@ -585,15 +589,16 @@ API anims_t animations(const char *pathfile, int flags); typedef struct lightmap_t { struct lm_context *ctx; // private bool ready; - texture_t lightmap; //@fixme: do we need it per-model? + int w, h; + int atlas_w, atlas_h; //@fixme: implement + texture_t atlas; //@fixme: implement this array(model_t*) models; + unsigned shader; } 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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void *userdata); API void lightmap_destroy(lightmap_t *lm); // ----------------------------------------------------------------------------- diff --git a/engine/v4k.c b/engine/v4k.c index 8aac7d3..a34e597 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -19682,13 +19682,13 @@ struct iqmbounds { typedef struct iqm_vertex { GLfloat position[3]; GLfloat texcoord[2]; - GLfloat texcoord2[2]; GLfloat normal[3]; GLfloat tangent[4]; GLubyte blendindexes[4]; GLubyte blendweights[4]; GLfloat blendvertexindex; GLubyte color[4]; + GLfloat texcoord2[2]; } iqm_vertex; typedef struct iqm_t { @@ -19798,6 +19798,13 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if( (loc = glGetUniformLocation(shader, "u_billboard")) >= 0 ) { glUniform1i( loc, m.billboard ); } + if( (loc = glGetUniformLocation(shader, "texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } + else + if( (loc = glGetUniformLocation(shader, "u_texlit")) >= 0 ) { + glUniform1i( loc, (m.lightmap.w != 0) ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -19842,28 +19849,26 @@ 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, 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) ); + 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) ); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); // vertex color - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); - glEnableVertexAttribArray(12); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex,color) ); + glEnableVertexAttribArray(11); // animation if(numframes > 0) { - 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) ); + 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); glEnableVertexAttribArray(9); glEnableVertexAttribArray(10); - glEnableVertexAttribArray(11); } // mat4 attribute; for instanced rendering @@ -19875,22 +19880,26 @@ 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(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))); + 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))); + 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); } + // lmap data + glVertexAttribPointer(12, 2, GL_FLOAT, GL_FALSE, sizeof(iqm_vertex), (GLvoid*)offsetof(iqm_vertex, texcoord2) ); + glEnableVertexAttribArray(12); + // 7 bitangent? into texcoord.z? glBindVertexArray( 0 ); @@ -19955,6 +19964,8 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { } struct iqmtriangle *tris = (struct iqmtriangle *)&buf[hdr->ofs_triangles]; + m->num_tris = hdr->num_triangles; + m->tris = (void*)tris; glGenVertexArrays(1, &vao); glBindVertexArray(vao); @@ -19996,22 +20007,22 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) { glBufferData(GL_ARRAY_BUFFER, hdr->num_vertexes*sizeof(iqm_vertex), verts, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); -m->stride = sizeof(iqm_vertex); -#if 0 -m->stride = 0; -if(inposition) m->stride += sizeof(verts[0].position); -if(innormal) m->stride += sizeof(verts[0].normal); -if(intangent) m->stride += sizeof(verts[0].tangent); -if(intexcoord) m->stride += sizeof(verts[0].texcoord); -if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? -if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? -if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); -if(inblendweightf) m->stride += sizeof(verts[0].blendweights); -if(invertexcolor8) m->stride += sizeof(verts[0].color); -#endif -//for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); -//m->verts = verts; //FREE(verts); -m->verts = 0; FREE(verts); + m->stride = sizeof(iqm_vertex); + #if 0 + m->stride = 0; + if(inposition) m->stride += sizeof(verts[0].position); + if(innormal) m->stride += sizeof(verts[0].normal); + if(intangent) m->stride += sizeof(verts[0].tangent); + if(intexcoord) m->stride += sizeof(verts[0].texcoord); + if(inblendindex8) m->stride += sizeof(verts[0].blendindexes); // no index8? bug? + if(inblendweight8) m->stride += sizeof(verts[0].blendweights); // no weight8? bug? + if(inblendindexi) m->stride += sizeof(verts[0].blendindexes); + if(inblendweightf) m->stride += sizeof(verts[0].blendweights); + if(invertexcolor8) m->stride += sizeof(verts[0].color); + #endif + //for( int i = 0; i < 16; ++i ) printf("%.9g%s", ((float*)verts)[i], (i % 3) == 2 ? "\n" : ","); + m->verts = verts; + /*m->verts = 0; FREE(verts);*/ textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); @@ -20243,8 +20254,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_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", + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -20486,7 +20497,7 @@ float model_animate(model_t m, float curframe) { } static -void model_draw_call(model_t m) { +void model_draw_call(model_t m, int shader) { if(!m.iqm) return; iqm_t *q = m.iqm; @@ -20498,17 +20509,21 @@ void model_draw_call(model_t m) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[i] ); - glUniform1i(glGetUniformLocation(m.program, "fsDiffTex"), 0 /*<-- unit!*/ ); + glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 ); int loc; - if ((loc = glGetUniformLocation(m.program, "u_textured")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { bool textured = !!textures[i] && textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(m.program, "u_diffuse")) >= 0) { + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a); } } + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m.lightmap.id); + glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 ); + glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); profile_incstat("Render.num_drawcalls", +1); profile_incstat("Render.num_triangles", +im->num_triangles); @@ -20530,7 +20545,7 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in } model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); - model_draw_call(m); + model_draw_call(m, shader > 0 ? shader : m.program); } void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { @@ -20647,114 +20662,99 @@ lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, return lm; } - return lm; -} + const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM + lm.shader = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_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,att_texcoord2","fragColor", + va("%s", "LIGHTMAP_BAKING")); -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; - } + return lm; } void lightmap_destroy(lightmap_t *lm) { lmDestroy(lm->ctx); - lightmap_destroytexture(lm); + shader_destroy(lm->shader); // } 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); + //@fixme: prep atlas for lightmaps + lm->w = w; + lm->h = h; } -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) { +void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, 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); + GLint cullface=0; + glGetIntegerv(GL_CULL_FACE, &cullface); + glDisable(GL_CULL_FACE); - // 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); + int w = lm->w, h = lm->h; + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (m->lightmap.w != 0) { + texture_destroy(&m->lightmap); + } + m->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR|TEXTURE_FLOAT); + glBindTexture(GL_TEXTURE_2D, m->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); + } + for (int b = 0; b < bounces; b++) { + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + if (!m->lmdata) { + m->lmdata = CALLOC(w*h*4, sizeof(float)); + } + memset(m->lmdata, 0, w*h*4); + lmSetTargetLightmap(lm->ctx, m->lmdata, w, h, 4); + lmSetGeometry(lm->ctx, m->pivot, + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, position), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, normal), sizeof(iqm_vertex), + LM_FLOAT, (uint8_t*)m->verts + offsetof(iqm_vertex, texcoord), sizeof(iqm_vertex), + m->num_tris*3, LM_UNSIGNED_INT, m->tris); + + glDisable(GL_BLEND); + int vp[4]; + float view[16], projection[16]; + while (lmBegin(lm->ctx, vp, view, projection)) + { + // render to lightmapper framebuffer + glViewport(vp[0], vp[1], vp[2], vp[3]); + drawscene(lm, m, view, projection, userdata); + lmEnd(lm->ctx); + } + } + + // postprocess texture + for (int i = 0; i < array_count(lm->models); i++) { + model_t *m = lm->models[i]; + float *temp = CALLOC(w * h * 4, sizeof(float)); + for (int i = 0; i < 16; i++) + { + lmImageDilate(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + } + lmImageSmooth(m->lmdata, temp, w, h, 4); + lmImageDilate(temp, m->lmdata, w, h, 4); + lmImagePower(m->lmdata, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels + FREE(temp); + + // save result to a file + // if (lmImageSaveTGAf("result.tga", m->lmdata, w, h, 4, 1.0f)) + // printf("Saved result.tga\n"); + // upload result + glBindTexture(GL_TEXTURE_2D, m->lightmap.id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, m->lmdata); + FREE(m->lmdata); m->lmdata = NULL; + } + } - // 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); + if (cullface) glEnable(GL_CULL_FACE); } #line 0 diff --git a/engine/v4k.h b/engine/v4k.h index 1393659..b463ec7 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3578,7 +3578,9 @@ typedef struct model_t { handle *textures; char **texture_names; array(material_t) materials; - texture_t *lightmap; + + texture_t lightmap; + float *lmdata; unsigned num_meshes; unsigned num_triangles; @@ -3592,6 +3594,8 @@ typedef struct model_t { int stride; // usually 68 bytes for a p3 u2 u2 n3 t4 i4B w4B c4B vertex stream void *verts; int num_verts; + void *tris; + int num_tris; handle vao, ibo, vbo, vao_instanced; unsigned flags; @@ -3643,15 +3647,16 @@ API anims_t animations(const char *pathfile, int flags); typedef struct lightmap_t { struct lm_context *ctx; // private bool ready; - texture_t lightmap; //@fixme: do we need it per-model? + int w, h; + int atlas_w, atlas_h; //@fixme: implement + texture_t atlas; //@fixme: implement this array(model_t*) models; + unsigned shader; } 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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void *userdata); API void lightmap_destroy(lightmap_t *lm); // ----------------------------------------------------------------------------- diff --git a/result.tga b/result.tga new file mode 100644 index 0000000..f7b31c1 Binary files /dev/null and b/result.tga differ