add progress func
parent
17dae10084
commit
7bcfb3e00c
|
@ -3015,7 +3015,7 @@ 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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, 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 (*progressupdate)(float progress), void *userdata);
|
||||
void lightmap_destroy(lightmap_t *lm);
|
||||
typedef struct skybox_t {
|
||||
handle program;
|
||||
|
|
|
@ -10,9 +10,20 @@ void bakedrawmodel(lightmap_t *lm, model_t *m, float *view, float *proj, void *u
|
|||
model_render(litm, proj, view, litm.pivot, lm->shader);
|
||||
}
|
||||
|
||||
void progressupdate(float progress) {
|
||||
static double lastUpdateTime = 0.0;
|
||||
double time = time_ss();
|
||||
if (time - lastUpdateTime > 1.0) {
|
||||
lastUpdateTime = time;
|
||||
PRINTF("progress: %.02f%%", progress*100);
|
||||
}
|
||||
// window_swap();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
window_create(0.5, WINDOW_VSYNC_DISABLED);
|
||||
window_create(0.5, 0);
|
||||
window_title(__FILE__);
|
||||
camera_t cam = camera();
|
||||
sky = skybox(0, 0); skybox_mie_calc_sh(&sky, 2.0f);
|
||||
model_t mdl = model("gazebo.obj", 0);
|
||||
|
@ -31,11 +42,12 @@ int main()
|
|||
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);
|
||||
lightmap_t baker = lightmap(64, 0.01, 100, vec3(0,0,0), 2, 0.01, 0.0);
|
||||
lightmap_setup(&baker, 512, 512);
|
||||
array_push(baker.models, &mdl);
|
||||
|
||||
window_title("AO Baking demo");
|
||||
bool do_bake=0;
|
||||
int b=1;
|
||||
|
||||
while (window_swap() && !input(KEY_ESC)) {
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
|
@ -53,11 +65,16 @@ int main()
|
|||
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)");
|
||||
int b=2;
|
||||
ui_int("Bounces", &b);
|
||||
if( ui_button(va("Bake %d light bounce", b)) ) {
|
||||
lightmap_bake(&baker, b, bakedrawmodel, 0);
|
||||
do_bake=1;
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
if (do_bake) {
|
||||
do_bake=0;
|
||||
lightmap_bake(&baker, b, bakedrawmodel, progressupdate, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17589,7 +17589,7 @@ typedef struct 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_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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||
API void lightmap_destroy(lightmap_t *lm);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -348237,6 +348237,7 @@ struct lm_context
|
|||
{
|
||||
GLuint texture;
|
||||
lm_ivec2 writePosition;
|
||||
int width, height;
|
||||
lm_ivec2 *toLightmapLocation;
|
||||
} storage;
|
||||
} hemisphere;
|
||||
|
@ -348497,10 +348498,72 @@ static lm_bool lm_findNextConservativeTriangleRasterizerPosition(lm_context *ctx
|
|||
return lm_findFirstConservativeTriangleRasterizerPosition(ctx);
|
||||
}
|
||||
|
||||
static void lm_integrateHemisphereBatch(lm_context *ctx)
|
||||
static void lm_writeResultsToLightmap(lm_context* ctx)
|
||||
{
|
||||
// do the GPU->CPU transfer of downsampled hemispheres
|
||||
float* hemi = (float*)LM_CALLOC(ctx->hemisphere.storage.width * ctx->hemisphere.storage.height, 4 * sizeof(float));
|
||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
||||
|
||||
// write results to lightmap texture
|
||||
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
||||
{
|
||||
for (int x = 0; x < ctx->hemisphere.storage.width; x++)
|
||||
{
|
||||
int index = y * ctx->hemisphere.storage.width + x;
|
||||
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[index];
|
||||
if (lmUV.x >= 0)
|
||||
{
|
||||
float* c = hemi + index * 4;
|
||||
float validity = c[3];
|
||||
float* lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
||||
if (!lm[0] && validity > 0.9)
|
||||
{
|
||||
float scale = 1.0f / validity;
|
||||
switch (ctx->lightmap.channels)
|
||||
{
|
||||
case 1:
|
||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||
break;
|
||||
case 2:
|
||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||
lm[1] = 1.0f; // do we want to support this format?
|
||||
break;
|
||||
case 3:
|
||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||
break;
|
||||
case 4:
|
||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||
lm[3] = 1.0f;
|
||||
break;
|
||||
default:
|
||||
assert(LM_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef LM_DEBUG_INTERPOLATION
|
||||
// set sampled pixel to red in debug output
|
||||
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
ctx->hemisphere.storage.toLightmapLocation[index].x = -1; // reset
|
||||
}
|
||||
}
|
||||
|
||||
LM_FREE(hemi);
|
||||
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
||||
}
|
||||
|
||||
|
||||
static lm_bool lm_integrateHemisphereBatch(lm_context *ctx)
|
||||
{
|
||||
if (!ctx->hemisphere.fbHemiIndex)
|
||||
return; // nothing to do
|
||||
return LM_FALSE; // nothing to do
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glBindVertexArray(ctx->hemisphere.vao);
|
||||
|
@ -348568,83 +348631,30 @@ static void lm_integrateHemisphereBatch(lm_context *ctx)
|
|||
{
|
||||
int sx = ctx->hemisphere.storage.writePosition.x + x;
|
||||
unsigned int hemiIndex = y * ctx->hemisphere.fbHemiCountX + x;
|
||||
if (hemiIndex >= ctx->hemisphere.fbHemiIndex)
|
||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = lm_i2(-1, -1);
|
||||
else
|
||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->hemisphere.storage.width + sx] =
|
||||
(hemiIndex >= ctx->hemisphere.fbHemiIndex) ?
|
||||
lm_i2(-1, -1) :
|
||||
ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
||||
}
|
||||
}
|
||||
|
||||
lm_bool needWrite = LM_TRUE;
|
||||
// advance storage texture write position
|
||||
ctx->hemisphere.storage.writePosition.x += ctx->hemisphere.fbHemiCountX;
|
||||
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->lightmap.width)
|
||||
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->hemisphere.storage.width)
|
||||
{
|
||||
ctx->hemisphere.storage.writePosition.x = 0;
|
||||
// storage is full
|
||||
if (ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY >= ctx->hemisphere.storage.height) {
|
||||
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||
needWrite = LM_FALSE;
|
||||
} else {
|
||||
ctx->hemisphere.storage.writePosition.y += ctx->hemisphere.fbHemiCountY;
|
||||
assert(ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY < ctx->lightmap.height);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->hemisphere.fbHemiIndex = 0;
|
||||
}
|
||||
|
||||
static void lm_writeResultsToLightmap(lm_context *ctx)
|
||||
{
|
||||
// do the GPU->CPU transfer of downsampled hemispheres
|
||||
float *hemi = (float*)LM_CALLOC(ctx->lightmap.width * ctx->lightmap.height, 4 * sizeof(float));
|
||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
||||
|
||||
// write results to lightmap texture
|
||||
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
||||
{
|
||||
for (int x = 0; x < ctx->lightmap.width; x++)
|
||||
{
|
||||
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x];
|
||||
if (lmUV.x >= 0)
|
||||
{
|
||||
float *c = hemi + (y * ctx->lightmap.width + x) * 4;
|
||||
float validity = c[3];
|
||||
float *lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
||||
if (!lm[0] && validity > 0.9)
|
||||
{
|
||||
float scale = 1.0f / validity;
|
||||
switch (ctx->lightmap.channels)
|
||||
{
|
||||
case 1:
|
||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||
break;
|
||||
case 2:
|
||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||
lm[1] = 1.0f; // do we want to support this format?
|
||||
break;
|
||||
case 3:
|
||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||
break;
|
||||
case 4:
|
||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||
lm[3] = 1.0f;
|
||||
break;
|
||||
default:
|
||||
assert(LM_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef LM_DEBUG_INTERPOLATION
|
||||
// set sampled pixel to red in debug output
|
||||
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x].x = -1; // reset
|
||||
}
|
||||
}
|
||||
|
||||
LM_FREE(hemi);
|
||||
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
||||
return needWrite;
|
||||
}
|
||||
|
||||
static void lm_setView(
|
||||
|
@ -348921,6 +348931,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
|||
// TODO: signed formats
|
||||
case LM_FLOAT: {
|
||||
n = *(const lm_vec3*)nPtr;
|
||||
n = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
||||
} break;
|
||||
case LM_NONE: {
|
||||
n = flatNormal;
|
||||
|
@ -348929,7 +348940,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
|||
assert(LM_FALSE);
|
||||
} break;
|
||||
}
|
||||
ctx->meshPosition.triangle.n[i] = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
||||
ctx->meshPosition.triangle.n[i] = n;
|
||||
}
|
||||
|
||||
// calculate area of interest (on lightmap) for conservative rasterization
|
||||
|
@ -349286,16 +349297,13 @@ void lmSetHemisphereWeights(lm_context *ctx, lm_weight_func f, void *userdata)
|
|||
LM_FREE(weights);
|
||||
}
|
||||
|
||||
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
||||
static void lm_initStorage(lm_context *ctx, int w, int h)
|
||||
{
|
||||
ctx->lightmap.data = outLightmap;
|
||||
ctx->lightmap.width = w;
|
||||
ctx->lightmap.height = h;
|
||||
ctx->lightmap.channels = c;
|
||||
|
||||
// allocate storage texture
|
||||
if (!ctx->hemisphere.storage.texture)
|
||||
glGenTextures(1, &ctx->hemisphere.storage.texture);
|
||||
ctx->hemisphere.storage.width = w;
|
||||
ctx->hemisphere.storage.height = h;
|
||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
@ -349310,6 +349318,18 @@ void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int
|
|||
// invalidate all positions
|
||||
for (int i = 0; i < w * h; i++)
|
||||
ctx->hemisphere.storage.toLightmapLocation[i].x = -1;
|
||||
}
|
||||
|
||||
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
||||
{
|
||||
ctx->lightmap.data = outLightmap;
|
||||
ctx->lightmap.width = w;
|
||||
ctx->lightmap.height = h;
|
||||
ctx->lightmap.channels = c;
|
||||
|
||||
unsigned int sw = w > ctx->hemisphere.fbHemiCountX ? w : ctx->hemisphere.fbHemiCountX;
|
||||
unsigned int sh = h > ctx->hemisphere.fbHemiCountY ? h : ctx->hemisphere.fbHemiCountY;
|
||||
lm_initStorage(ctx, sw, sh);
|
||||
|
||||
#ifdef LM_DEBUG_INTERPOLATION
|
||||
if (ctx->lightmap.debug)
|
||||
|
@ -349363,7 +349383,7 @@ lm_bool lmBegin(lm_context *ctx, int* outViewport4, float* outView4x4, float* ou
|
|||
}
|
||||
else
|
||||
{ // ...and there are no triangles left: finish
|
||||
lm_integrateHemisphereBatch(ctx); // integrate and store last batch
|
||||
if (lm_integrateHemisphereBatch(ctx)) // integrate and store last batch
|
||||
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||
|
||||
if (++ctx->meshPosition.pass == ctx->meshPosition.passCount)
|
||||
|
@ -349639,8 +349659,7 @@ lm_bool lmImageSaveTGAf(const char *filename, const float *image, int w, int h,
|
|||
return success;
|
||||
}
|
||||
|
||||
#endif // LIGHTMAPPER_IMPLEMENTATION
|
||||
#line 0
|
||||
#endif // LIGHTMAPPER_IMPLEMENTATION#line 0
|
||||
|
||||
#endif // V4K_3RD
|
||||
/* game framework.
|
||||
|
@ -370328,7 +370347,7 @@ void lightmap_setup(lightmap_t *lm, int w, int h) {
|
|||
lm->h = h;
|
||||
}
|
||||
|
||||
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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata) {
|
||||
ASSERT(lm->ready);
|
||||
// @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU.
|
||||
|
||||
|
@ -370371,6 +370390,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
|
|||
// render to lightmapper framebuffer
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
drawscene(lm, m, view, projection, userdata);
|
||||
if (progressupdate) progressupdate(lmProgress(lm->ctx));
|
||||
lmEnd(lm->ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3767,7 +3767,7 @@ void lightmap_setup(lightmap_t *lm, int w, int h) {
|
|||
lm->h = h;
|
||||
}
|
||||
|
||||
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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata) {
|
||||
ASSERT(lm->ready);
|
||||
// @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU.
|
||||
|
||||
|
@ -3810,6 +3810,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
|
|||
// render to lightmapper framebuffer
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
drawscene(lm, m, view, projection, userdata);
|
||||
if (progressupdate) progressupdate(lmProgress(lm->ctx));
|
||||
lmEnd(lm->ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -598,7 +598,7 @@ typedef struct 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_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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||
API void lightmap_destroy(lightmap_t *lm);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -20683,7 +20683,7 @@ void lightmap_setup(lightmap_t *lm, int w, int h) {
|
|||
lm->h = h;
|
||||
}
|
||||
|
||||
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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata) {
|
||||
ASSERT(lm->ready);
|
||||
// @fixme: use xatlas to UV pack all models, update their UV1 and upload them to GPU.
|
||||
|
||||
|
@ -20726,6 +20726,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
|
|||
// render to lightmapper framebuffer
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
drawscene(lm, m, view, projection, userdata);
|
||||
if (progressupdate) progressupdate(lmProgress(lm->ctx));
|
||||
lmEnd(lm->ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3656,7 +3656,7 @@ typedef struct 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_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_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||
API void lightmap_destroy(lightmap_t *lm);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue