From fff4880c4f7d3dcbe1e9e1360eb2cfa4a1adba4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Sat, 23 Sep 2023 20:53:25 +0200 Subject: [PATCH] render: finish up phong shading --- demos/99-material.c | 3 +- engine/art/shaders/fs_32_4_model.glsl | 65 ++++++++--- .../shaders/vs_323444143_16_332_model.glsl | 3 +- engine/art/shaders/vs_332_32.glsl | 5 +- engine/bind/v4k.lua | 29 +++-- engine/joint/v4k.h | 104 ++++++++++++++---- engine/split/v4k_render.c | 29 ++++- engine/split/v4k_render.h | 8 ++ engine/split/v4k_scene.c | 46 ++++++-- engine/split/v4k_scene.h | 21 ++-- engine/v4k.c | 75 ++++++++++--- engine/v4k.h | 29 +++-- 12 files changed, 318 insertions(+), 99 deletions(-) diff --git a/demos/99-material.c b/demos/99-material.c index 74c08ba..0fd5413 100644 --- a/demos/99-material.c +++ b/demos/99-material.c @@ -41,7 +41,7 @@ int main() { // create point light light_t* l = scene_spawn_light(); - light_type(l, LIGHT_POINT); + light_type(l, LIGHT_SPOT); while(window_swap() && !input(KEY_ESC)) { // draw environment @@ -53,6 +53,7 @@ int main() { // update light position light_teleport(l, cam.position); + light_dir(l, cam.look); // draw scene scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND|SCENE_UPDATE_SH_COEF); diff --git a/engine/art/shaders/fs_32_4_model.glsl b/engine/art/shaders/fs_32_4_model.glsl index af08e7f..e90bf22 100644 --- a/engine/art/shaders/fs_32_4_model.glsl +++ b/engine/art/shaders/fs_32_4_model.glsl @@ -7,6 +7,7 @@ uniform bool u_matcaps = false; uniform vec4 u_diffuse = vec4(1.0,1.0,1.0,1.0); in vec3 v_position; +in vec3 v_position_ws; #ifdef RIM uniform mat4 M; // RIM uniform vec3 u_rimcolor = vec3(0.2,0.2,0.2); @@ -28,14 +29,25 @@ vec4 shadowing() { return shadowmap(vpeye, vneye, v_texcoord, sc); } +uniform vec3 u_cam_pos; +uniform vec3 u_cam_dir; + uniform int u_num_lights; struct light_t { int type; - vec3 color; + vec3 diffuse; + vec3 specular; + vec3 ambient; vec3 pos; vec3 dir; - float radius; + float innerCone; + float outerCone; + + // falloff + float constant; + float linear; + float quadratic; }; #define MAX_LIGHTS 16 @@ -45,27 +57,53 @@ const int LIGHT_SPOT = 2; uniform light_t u_lights[MAX_LIGHTS]; -vec3 calculate_light(light_t l, vec3 normal, vec3 fragPos, vec3 viewDir) { +#ifdef SHADING_PHONG +vec3 shading_phong(light_t l) { vec3 lightDir; float attenuation = 1.0; if (l.type == LIGHT_DIRECTIONAL) { lightDir = normalize(-l.dir); } else if (l.type == LIGHT_POINT) { - vec3 toLight = l.pos - fragPos; + vec3 toLight = l.pos - v_position_ws; lightDir = normalize(toLight); float distance = length(toLight); - float factor = distance / (l.radius*l.radius); - attenuation = clamp(1.0 - factor, 0.0, 1.0); + attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance)); + } else if (l.type == LIGHT_SPOT) { + vec3 toLight = l.pos - v_position_ws; + lightDir = normalize(toLight); + float distance = length(toLight); + attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance)); + + // Calculate spotlight effect + float angle = dot(l.dir, normalize(-lightDir)); + if (angle > l.outerCone) { + float intensity = (angle-l.outerCone)/(l.innerCone-l.outerCone); + attenuation *= clamp(intensity, 0.0, 1.0); + } else { + attenuation = 0.0; + } } - float diff = max(dot(normal, lightDir), 0.0); + float diffuse = max(dot(v_normal, lightDir), 0.0); - // vec3 reflectDir = reflect(-lightDir, normal); - // float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); - // vec3 specular = spec * lightColor; + vec3 halfVec = normalize(lightDir + u_cam_dir); + float specular = pow(max(dot(v_normal, halfVec), 0.0), 32); - return (diff /* + specular */) * l.color; + return (attenuation*l.ambient + diffuse*attenuation*l.diffuse + specular*attenuation*l.specular); +} +#endif + +vec3 lighting() { + vec3 lit = vec3(0,0,0); +#ifndef SHADING_NONE + for (int i=0; i= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -343729,13 +343760,14 @@ model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; const char *ptr = (const char *)mem; - static int shaderprog = -1; - if( shaderprog < 0 ) { + // can't cache shader programs since we enable features via flags here + // static int shaderprog = -1; + // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", - (flags&MODEL_RIMLIGHT)?"RIM":NULL); - } + va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); + // } iqm_t *q = CALLOC(1, sizeof(iqm_t)); program = shaderprog; @@ -345198,9 +345230,13 @@ void object_billboard(object_t *obj, unsigned mode) { light_t light() { light_t l = {0}; - l.color = vec3(1,1,1); - l.radius = 2.5f; + l.diffuse = vec3(1,1,1); l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.innerCone = 0.9f; // 25 deg + l.outerCone = 0.85f; // 31 deg return l; } @@ -345210,9 +345246,19 @@ void light_type(light_t* l, char type) { l->type = type; } -void light_color(light_t* l, vec3 color) { +void light_diffuse(light_t* l, vec3 color) { l->cached = 0; - l->color = color; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; } void light_teleport(light_t* l, vec3 pos) { @@ -345225,9 +345271,16 @@ void light_dir(light_t* l, vec3 dir) { l->dir = dir; } -void light_radius(light_t* l, float radius) { +void light_falloff(light_t* l, float constant, float linear, float quadratic) { l->cached = 0; - l->radius = radius; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); } void light_update(unsigned num_lights, light_t *lv) { @@ -345236,9 +345289,16 @@ void light_update(unsigned num_lights, light_t *lv) { for (unsigned i=0; i < num_lights; ++i) { lv[i].cached = 1; shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].color", i), lv[i].color); shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); } } @@ -345259,8 +345319,6 @@ scene_t* scene_get_active() { scene_t* scene_push() { scene_t *s = REALLOC(0, sizeof(scene_t)), clear = {0}; *s = clear; - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; - s->program = shader(strlerp(1, symbols, vfs_read("shaders/vs_332_32.glsl")), strlerp(1, symbols, vfs_read("shaders/fs_32_4_model.glsl")), "att_position,att_normal,att_texcoord,att_color", "fragcolor", NULL); s->skybox = skybox(NULL, 0); array_push(scenes, s); last_scene = s; @@ -345371,7 +345429,6 @@ void scene_render(int flags) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); - glUseProgram(last_scene->program); if(flags & SCENE_BACKGROUND) { if(last_scene->skybox.program) { @@ -345392,7 +345449,6 @@ void scene_render(int flags) { glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); -// glUseProgram(last_scene->program); // @fixme: CW ok for one-sided rendering. CCW ok for FXs. we need both (flags & SCENE_CULLFACE ? glEnable : glDisable)(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index d15ad23..4329f23 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -3683,6 +3683,24 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, mat44 vp; multiply44x2(vp, proj, view); glUniformMatrix4fv( loc, 1, GL_FALSE, vp); } + if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -4119,13 +4137,14 @@ model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; const char *ptr = (const char *)mem; - static int shaderprog = -1; - if( shaderprog < 0 ) { + // can't cache shader programs since we enable features via flags here + // static int shaderprog = -1; + // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", - (flags&MODEL_RIMLIGHT)?"RIM":NULL); - } + va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); + // } iqm_t *q = CALLOC(1, sizeof(iqm_t)); program = shaderprog; diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index 0bc4afb..6eb3744 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -572,6 +572,14 @@ enum MODEL_FLAGS { MODEL_RIMLIGHT = 16 }; +//@todo: make this data-driven +// enum SHADING_MODE { +// SHADING_NONE, +// SHADING_PHONG, +// SHADING_CARTOON, +// // SHADING_PBR, +// }; + typedef struct model_t { struct iqm_t *iqm; // private diff --git a/engine/split/v4k_scene.c b/engine/split/v4k_scene.c index a272545..ee8e6c9 100644 --- a/engine/split/v4k_scene.c +++ b/engine/split/v4k_scene.c @@ -243,9 +243,13 @@ void object_billboard(object_t *obj, unsigned mode) { light_t light() { light_t l = {0}; - l.color = vec3(1,1,1); - l.radius = 2.5f; + l.diffuse = vec3(1,1,1); l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.innerCone = 0.9f; // 25 deg + l.outerCone = 0.85f; // 31 deg return l; } @@ -255,9 +259,19 @@ void light_type(light_t* l, char type) { l->type = type; } -void light_color(light_t* l, vec3 color) { +void light_diffuse(light_t* l, vec3 color) { l->cached = 0; - l->color = color; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; } void light_teleport(light_t* l, vec3 pos) { @@ -270,9 +284,16 @@ void light_dir(light_t* l, vec3 dir) { l->dir = dir; } -void light_radius(light_t* l, float radius) { +void light_falloff(light_t* l, float constant, float linear, float quadratic) { l->cached = 0; - l->radius = radius; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); } void light_update(unsigned num_lights, light_t *lv) { @@ -281,9 +302,16 @@ void light_update(unsigned num_lights, light_t *lv) { for (unsigned i=0; i < num_lights; ++i) { lv[i].cached = 1; shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].color", i), lv[i].color); shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); } } @@ -304,8 +332,6 @@ scene_t* scene_get_active() { scene_t* scene_push() { scene_t *s = REALLOC(0, sizeof(scene_t)), clear = {0}; *s = clear; - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; - s->program = shader(strlerp(1, symbols, vfs_read("shaders/vs_332_32.glsl")), strlerp(1, symbols, vfs_read("shaders/fs_32_4_model.glsl")), "att_position,att_normal,att_texcoord,att_color", "fragcolor", NULL); s->skybox = skybox(NULL, 0); array_push(scenes, s); last_scene = s; @@ -416,7 +442,6 @@ void scene_render(int flags) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); - glUseProgram(last_scene->program); if(flags & SCENE_BACKGROUND) { if(last_scene->skybox.program) { @@ -437,7 +462,6 @@ void scene_render(int flags) { glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); -// glUseProgram(last_scene->program); // @fixme: CW ok for one-sided rendering. CCW ok for FXs. we need both (flags & SCENE_CULLFACE ? glEnable : glDisable)(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); diff --git a/engine/split/v4k_scene.h b/engine/split/v4k_scene.h index b3962b1..480fe39 100644 --- a/engine/split/v4k_scene.h +++ b/engine/split/v4k_scene.h @@ -66,21 +66,28 @@ enum LIGHT_FLAGS { typedef struct light_t { char type; - vec3 color; + vec3 diffuse, specular, ambient; vec3 pos, dir; - float radius; + struct { + float constant, linear, quadratic; + } falloff; + float innerCone, outerCone; + //@todo: cookie, flare + + // internals bool cached; //< used by scene to invalidate cached light data - //@todo: inner/outer cone, flags, cookie, flare } light_t; API light_t light(); // API void light_flags(int flags); API void light_type(light_t* l, char type); -API void light_color(light_t* l, vec3 color); +API void light_diffuse(light_t* l, vec3 color); +API void light_specular(light_t* l, vec3 color); +API void light_ambient(light_t* l, vec3 color); API void light_teleport(light_t* l, vec3 pos); API void light_dir(light_t* l, vec3 dir); -API void light_radius(light_t* l, float radius); -// API void light_cone(light_t* l, float inner, float outer); +API void light_falloff(light_t* l, float constant, float linear, float quadratic); +API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); // scene @@ -94,8 +101,6 @@ enum SCENE_FLAGS { }; typedef struct scene_t { - handle program; - array(object_t) objs; array(light_t) lights; diff --git a/engine/v4k.c b/engine/v4k.c index e7b8006..e314d03 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -13947,6 +13947,24 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, mat44 vp; multiply44x2(vp, proj, view); glUniformMatrix4fv( loc, 1, GL_FALSE, vp); } + if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { + vec3 pos = vec3(view[3], view[6], view[9]); + glUniform3fv( loc, 1, &pos.x ); + } + if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } + else + if( (loc = glGetUniformLocation(shader, "cam_dir")) >= 0 ) { + vec3 dir = vec3(view[0], view[1], view[2]); + glUniform3fv( loc, 1, &dir.x ); + } #if 0 // @todo: mat44 projview (useful?) #endif @@ -14383,13 +14401,14 @@ model_t model_from_mem(const void *mem, int len, int flags) { model_t m = {0}; const char *ptr = (const char *)mem; - static int shaderprog = -1; - if( shaderprog < 0 ) { + // can't cache shader programs since we enable features via flags here + // static int shaderprog = -1; + // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, + int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_332_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent","fragColor", - (flags&MODEL_RIMLIGHT)?"RIM":NULL); - } + va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); + // } iqm_t *q = CALLOC(1, sizeof(iqm_t)); program = shaderprog; @@ -15852,9 +15871,13 @@ void object_billboard(object_t *obj, unsigned mode) { light_t light() { light_t l = {0}; - l.color = vec3(1,1,1); - l.radius = 2.5f; + l.diffuse = vec3(1,1,1); l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.innerCone = 0.9f; // 25 deg + l.outerCone = 0.85f; // 31 deg return l; } @@ -15864,9 +15887,19 @@ void light_type(light_t* l, char type) { l->type = type; } -void light_color(light_t* l, vec3 color) { +void light_diffuse(light_t* l, vec3 color) { l->cached = 0; - l->color = color; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; } void light_teleport(light_t* l, vec3 pos) { @@ -15879,9 +15912,16 @@ void light_dir(light_t* l, vec3 dir) { l->dir = dir; } -void light_radius(light_t* l, float radius) { +void light_falloff(light_t* l, float constant, float linear, float quadratic) { l->cached = 0; - l->radius = radius; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); } void light_update(unsigned num_lights, light_t *lv) { @@ -15890,9 +15930,16 @@ void light_update(unsigned num_lights, light_t *lv) { for (unsigned i=0; i < num_lights; ++i) { lv[i].cached = 1; shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].color", i), lv[i].color); shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); } } @@ -15913,8 +15960,6 @@ scene_t* scene_get_active() { scene_t* scene_push() { scene_t *s = REALLOC(0, sizeof(scene_t)), clear = {0}; *s = clear; - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; - s->program = shader(strlerp(1, symbols, vfs_read("shaders/vs_332_32.glsl")), strlerp(1, symbols, vfs_read("shaders/fs_32_4_model.glsl")), "att_position,att_normal,att_texcoord,att_color", "fragcolor", NULL); s->skybox = skybox(NULL, 0); array_push(scenes, s); last_scene = s; @@ -16025,7 +16070,6 @@ void scene_render(int flags) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); - glUseProgram(last_scene->program); if(flags & SCENE_BACKGROUND) { if(last_scene->skybox.program) { @@ -16046,7 +16090,6 @@ void scene_render(int flags) { glDepthFunc(GL_LESS); glActiveTexture(GL_TEXTURE0); -// glUseProgram(last_scene->program); // @fixme: CW ok for one-sided rendering. CCW ok for FXs. we need both (flags & SCENE_CULLFACE ? glEnable : glDisable)(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); diff --git a/engine/v4k.h b/engine/v4k.h index 42ed38d..64cb9fa 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3005,6 +3005,14 @@ enum MODEL_FLAGS { MODEL_RIMLIGHT = 16 }; +//@todo: make this data-driven +// enum SHADING_MODE { +// SHADING_NONE, +// SHADING_PHONG, +// SHADING_CARTOON, +// // SHADING_PBR, +// }; + typedef struct model_t { struct iqm_t *iqm; // private @@ -3247,21 +3255,28 @@ enum LIGHT_FLAGS { typedef struct light_t { char type; - vec3 color; + vec3 diffuse, specular, ambient; vec3 pos, dir; - float radius; + struct { + float constant, linear, quadratic; + } falloff; + float innerCone, outerCone; + //@todo: cookie, flare + + // internals bool cached; //< used by scene to invalidate cached light data - //@todo: inner/outer cone, flags, cookie, flare } light_t; API light_t light(); // API void light_flags(int flags); API void light_type(light_t* l, char type); -API void light_color(light_t* l, vec3 color); +API void light_diffuse(light_t* l, vec3 color); +API void light_specular(light_t* l, vec3 color); +API void light_ambient(light_t* l, vec3 color); API void light_teleport(light_t* l, vec3 pos); API void light_dir(light_t* l, vec3 dir); -API void light_radius(light_t* l, float radius); -// API void light_cone(light_t* l, float inner, float outer); +API void light_falloff(light_t* l, float constant, float linear, float quadratic); +API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); // scene @@ -3275,8 +3290,6 @@ enum SCENE_FLAGS { }; typedef struct scene_t { - handle program; - array(object_t) objs; array(light_t) lights;