lightmapping support

main
Dominik Madarász 2023-12-01 16:05:38 +01:00
parent f5b664efe1
commit 985b4de0d2
10 changed files with 533 additions and 814 deletions

View File

@ -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);

View File

@ -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

View File

@ -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,12 +116,7 @@ vec3 lighting() {
return lit;
}
void main() {
vec3 n = normalize(v_normal_ws);
vec4 lit = vec4(1.0, 1.0, 1.0, 1.0);
// SH lighting
{
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;
@ -129,6 +130,35 @@ void main() {
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
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);
}
@ -147,6 +177,18 @@ void main() {
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();
@ -164,3 +206,4 @@ void main() {
fragcolor += vec4(col, 1.0);}
#endif
}
#endif

View File

@ -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;

View File

@ -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);
// 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);
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;
}
}
if (cullface) glEnable(GL_CULL_FACE);
}
#line 0

View File

@ -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);
// 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);
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;
}
}
if (cullface) glEnable(GL_CULL_FACE);
}

View File

@ -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);
// -----------------------------------------------------------------------------

View File

@ -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);
// 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);
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;
}
}
if (cullface) glEnable(GL_CULL_FACE);
}
#line 0

View File

@ -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);
// -----------------------------------------------------------------------------

BIN
result.tga 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB