OpenGL: update simple shader API.

Restore fixed function lighting code for now and control use of GLSL shader
with a variable, make light types more clear, reduce state changes, some other
minor tweaks.
This commit is contained in:
Brecht Van Lommel
2015-11-27 21:06:23 +01:00
parent 263f4cd342
commit b5f9746dae
2 changed files with 119 additions and 39 deletions

View File

@@ -41,7 +41,7 @@ extern "C" {
/* Fixed Function Shader */ /* Fixed Function Shader */
typedef enum GPUSimpleShaderOption { typedef enum GPUSimpleShaderOption {
GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */ GPU_SHADER_USE_COLOR = (1<<0), /* use glColor, for lighting it replaces diffuse */
GPU_SHADER_LIGHTING = (1<<1), /* use lighting */ GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */ GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */ GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
@@ -55,25 +55,32 @@ void GPU_simple_shaders_init(void);
void GPU_simple_shaders_exit(void); void GPU_simple_shaders_exit(void);
void GPU_simple_shader_bind(int options); void GPU_simple_shader_bind(int options);
void GPU_simple_shader_unbind(void); int GPU_simple_shader_bound_options(void);
void GPU_simple_shader_colors(const float diffuse[3], const float specular[3], void GPU_simple_shader_colors(const float diffuse[3], const float specular[3],
int shininess, float alpha); int shininess, float alpha);
bool GPU_simple_shader_need_normals(void);
/* Fixed Function Lighting */ /* Fixed Function Lighting */
typedef enum GPULightType {
GPU_LIGHT_POINT,
GPU_LIGHT_SPOT,
GPU_LIGHT_SUN
} GPULightType;
typedef struct GPULightData { typedef struct GPULightData {
float position[4]; GPULightType type;
float diffuse[4];
float specular[4]; float position[3];
float direction[3];
float diffuse[3];
float specular[3];
float constant_attenuation; float constant_attenuation;
float linear_attenuation; float linear_attenuation;
float quadratic_attenuation; float quadratic_attenuation;
float spot_direction[3];
float spot_cutoff; float spot_cutoff;
float spot_exponent; float spot_exponent;
} GPULightData; } GPULightData;

View File

@@ -52,13 +52,13 @@
/* State */ /* State */
// #define NUM_OPENGL_LIGHTS 8 static const bool USE_GLSL = false;
static struct { static struct {
GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS]; GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS]; bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
bool need_normals; int bound_options;
int lights_enabled; int lights_enabled;
int lights_directional; int lights_directional;
@@ -104,7 +104,7 @@ static int detect_options()
if (glIsEnabled(GL_TEXTURE_2D)) if (glIsEnabled(GL_TEXTURE_2D))
options |= GPU_SHADER_TEXTURE_2D; options |= GPU_SHADER_TEXTURE_2D;
if (glIsEnabled(GL_COLOR_MATERIAL)) if (glIsEnabled(GL_COLOR_MATERIAL))
options |= GPU_SHADER_OVERRIDE_DIFFUSE; options |= GPU_SHADER_USE_COLOR;
if (glIsEnabled(GL_LIGHTING)) if (glIsEnabled(GL_LIGHTING))
options |= GPU_SHADER_LIGHTING; options |= GPU_SHADER_LIGHTING;
@@ -136,7 +136,7 @@ static GPUShader *gpu_simple_shader(int options)
/* create shader if it doesn't exist yet */ /* create shader if it doesn't exist yet */
char defines[64*GPU_SHADER_OPTIONS_NUM] = ""; char defines[64*GPU_SHADER_OPTIONS_NUM] = "";
if (options & GPU_SHADER_OVERRIDE_DIFFUSE) if (options & GPU_SHADER_USE_COLOR)
strcat(defines, "#define USE_COLOR\n"); strcat(defines, "#define USE_COLOR\n");
if (options & GPU_SHADER_TWO_SIDED) if (options & GPU_SHADER_TWO_SIDED)
strcat(defines, "#define USE_TWO_SIDED\n"); strcat(defines, "#define USE_TWO_SIDED\n");
@@ -173,18 +173,53 @@ static GPUShader *gpu_simple_shader(int options)
void GPU_simple_shader_bind(int options) void GPU_simple_shader_bind(int options)
{ {
if (USE_GLSL) {
if (options) {
GPUShader *shader = gpu_simple_shader(options); GPUShader *shader = gpu_simple_shader(options);
if (shader) if (shader)
GPU_shader_bind(shader); GPU_shader_bind(shader);
}
else {
GPU_shader_unbind();
}
}
else {
int bound_options = GPU_MATERIAL_STATE.bound_options;
/* temporary hack, should be solved outside of this file */ if (options & GPU_SHADER_LIGHTING) {
GPU_MATERIAL_STATE.need_normals = (options & GPU_SHADER_LIGHTING); glEnable(GL_LIGHTING);
if (options & GPU_SHADER_USE_COLOR)
glEnable(GL_COLOR_MATERIAL);
else
glDisable(GL_COLOR_MATERIAL);
if (options & GPU_SHADER_TWO_SIDED)
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
else
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
}
else if (bound_options & GPU_SHADER_LIGHTING) {
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
}
if (options & GPU_SHADER_TEXTURE_2D)
glEnable(GL_TEXTURE_2D);
else if (bound_options & GPU_SHADER_TEXTURE_2D)
glDisable(GL_TEXTURE_2D);
}
GPU_MATERIAL_STATE.bound_options = options;
} }
void GPU_simple_shader_unbind(void) int GPU_simple_shader_bound_options(void)
{ {
GPU_shader_unbind(); /* ideally this should disappear, anything that uses this is making fragile
* assumptions that the simple shader is bound and not another shader */
return GPU_MATERIAL_STATE.bound_options;
} }
/* Material Colors */ /* Material Colors */
@@ -194,10 +229,16 @@ void GPU_simple_shader_colors(const float diffuse[3], const float specular[3],
{ {
float gl_diffuse[4], gl_specular[4]; float gl_diffuse[4], gl_specular[4];
if (diffuse)
copy_v3_v3(gl_diffuse, diffuse); copy_v3_v3(gl_diffuse, diffuse);
else
zero_v3(gl_diffuse);
gl_diffuse[3] = alpha; gl_diffuse[3] = alpha;
if (specular)
copy_v3_v3(gl_specular, specular); copy_v3_v3(gl_specular, specular);
else
zero_v3(gl_specular);
gl_specular[3] = 1.0f; gl_specular[3] = 1.0f;
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse);
@@ -205,43 +246,75 @@ void GPU_simple_shader_colors(const float diffuse[3], const float specular[3],
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128)); glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
} }
bool GPU_simple_shader_need_normals(void)
{
return GPU_MATERIAL_STATE.need_normals;
}
void GPU_simple_shader_light_set(int light_num, GPULightData *light) void GPU_simple_shader_light_set(int light_num, GPULightData *light)
{ {
int light_bit = (1 << light_num); int light_bit = (1 << light_num);
/* note that light position is affected by the current modelview matrix! */
GPU_MATERIAL_STATE.lights_enabled &= ~light_bit; GPU_MATERIAL_STATE.lights_enabled &= ~light_bit;
GPU_MATERIAL_STATE.lights_directional &= ~light_bit; GPU_MATERIAL_STATE.lights_directional &= ~light_bit;
if (light) { if (light) {
float position[4], diffuse[4], specular[4];
glEnable(GL_LIGHT0+light_num); glEnable(GL_LIGHT0+light_num);
glLightfv(GL_LIGHT0+light_num, GL_POSITION, light->position); /* position */
glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, light->diffuse); if (light->type == GPU_LIGHT_SUN) {
glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, light->specular); copy_v3_v3(position, light->direction);
position[3] = 0.0f;
}
else {
copy_v3_v3(position, light->position);
position[3] = 1.0f;
}
glLightfv(GL_LIGHT0+light_num, GL_POSITION, position);
/* energy */
copy_v3_v3(diffuse, light->diffuse);
copy_v3_v3(specular, light->specular);
diffuse[3] = 1.0f;
specular[3] = 1.0f;
glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, specular);
/* attenuation */
if (light->type == GPU_LIGHT_SUN) {
glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, 1.0f);
glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, 0.0f);
glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, 0.0f);
}
else {
glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation); glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation);
glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation); glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation);
glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation); glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation);
}
glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->spot_direction); /* spot */
glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->direction);
if (light->type == GPU_LIGHT_SPOT) {
glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff); glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff);
glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent); glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent);
}
else {
glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, 180.0f);
glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, 0.0f);
}
GPU_MATERIAL_STATE.lights_enabled |= light_bit; GPU_MATERIAL_STATE.lights_enabled |= light_bit;
if (light->position[3] == 0.0f) if (light->position[3] == 0.0f)
GPU_MATERIAL_STATE.lights_directional |= light_bit; GPU_MATERIAL_STATE.lights_directional |= light_bit;
} }
else { else {
if (USE_GLSL) {
/* glsl shader needs these zero to skip them */
const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero); glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero);
glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero); glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero);
glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero); glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero);
}
glDisable(GL_LIGHT0+light_num); glDisable(GL_LIGHT0+light_num);
} }