Add basic support for shader "effects".

Again, based on The OpenGL Shader Wrangler. The wrangling part is not used
yet, but the shader compiler has been modified to take the built up shader.
Just to keep things compiling, a wrapper has been temporarily created.
This commit is contained in:
Bill Currie 2013-02-26 21:52:35 +09:00
parent 3b56f0e3bf
commit 96c40cb9a1
10 changed files with 213 additions and 33 deletions

View file

@ -30,6 +30,12 @@
#include "QF/qtypes.h"
typedef struct shader_s {
int num_strings;
const char **strings;
const char **src;
} shader_t;
typedef struct shaderparam_s {
const char *name;
qboolean uniform;
@ -40,9 +46,15 @@ extern int glsl_palette;
extern int glsl_colormap;
void GLSL_Init_Common (void);
int GLSL_CompileShader (const char *name, const char *shader_src, int type);
int GLSL_CompileShader (const char *name, const shader_t *shader, int type);
int GLSL_CompileShaderS (const char *name, const char *src, int type);
int GLSL_LinkProgram (const char *name, int vert, int frag);
int GLSL_ResolveShaderParam (int program, shaderparam_t *param);
void GLSL_DumpAttribArrays (void);
int GLSL_RegisterEffect (const char *name, const char *src);
shader_t *GLSL_BuildShader (const char **effect_keys);
void GLSL_FreeShader (shader_t *shader);
#endif // __QF_GLSL_vid_h

View file

@ -17,8 +17,8 @@ shader_gen= \
glsl_src = \
glsl_alias.c glsl_bsp.c glsl_draw.c glsl_fog.c glsl_iqm.c glsl_lightmap.c \
glsl_main.c glsl_particles.c glsl_screen.c glsl_sprite.c glsl_textures.c \
qfglsl.c vid_common_glsl.c
glsl_main.c glsl_particles.c glsl_screen.c glsl_shader.c glsl_sprite.c \
glsl_textures.c qfglsl.c vid_common_glsl.c
noinst_LTLIBRARIES= libglsl.la
BUILT_SOURCES= $(shader_gen)

View file

@ -113,9 +113,9 @@ glsl_R_InitAlias (void)
int vert;
int frag;
vert = GLSL_CompileShader ("quakemdl.vert", quakemdl_vert,
vert = GLSL_CompileShaderS ("quakemdl.vert", quakemdl_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakemdl.frag", quakemdl_frag,
frag = GLSL_CompileShaderS ("quakemdl.frag", quakemdl_frag,
GL_FRAGMENT_SHADER);
quake_mdl.program = GLSL_LinkProgram ("quakemdl", vert, frag);
GLSL_ResolveShaderParam (quake_mdl.program, &quake_mdl.mvp_matrix);

View file

@ -1244,9 +1244,9 @@ glsl_R_InitBsp (void)
int vert;
int frag;
vert = GLSL_CompileShader ("quakebsp.vert", quakebsp_vert,
vert = GLSL_CompileShaderS ("quakebsp.vert", quakebsp_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakebsp.frag", quakebsp_frag,
frag = GLSL_CompileShaderS ("quakebsp.frag", quakebsp_frag,
GL_FRAGMENT_SHADER);
quake_bsp.program = GLSL_LinkProgram ("quakebsp", vert, frag);
GLSL_ResolveShaderParam (quake_bsp.program, &quake_bsp.mvp_matrix);
@ -1258,7 +1258,7 @@ glsl_R_InitBsp (void)
GLSL_ResolveShaderParam (quake_bsp.program, &quake_bsp.color);
GLSL_ResolveShaderParam (quake_bsp.program, &quake_bsp.fog);
frag = GLSL_CompileShader ("quaketrb.frag", quaketurb_frag,
frag = GLSL_CompileShaderS ("quaketrb.frag", quaketurb_frag,
GL_FRAGMENT_SHADER);
quake_turb.program = GLSL_LinkProgram ("quaketrb", vert, frag);
GLSL_ResolveShaderParam (quake_turb.program, &quake_turb.mvp_matrix);
@ -1270,9 +1270,9 @@ glsl_R_InitBsp (void)
GLSL_ResolveShaderParam (quake_turb.program, &quake_turb.color);
GLSL_ResolveShaderParam (quake_turb.program, &quake_turb.fog);
vert = GLSL_CompileShader ("quakesky.vert", quakesky_vert,
vert = GLSL_CompileShaderS ("quakesky.vert", quakesky_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakeski.frag", quakeskyid_frag,
frag = GLSL_CompileShaderS ("quakeski.frag", quakeskyid_frag,
GL_FRAGMENT_SHADER);
quake_skyid.program = GLSL_LinkProgram ("quakeskyid", vert, frag);
GLSL_ResolveShaderParam (quake_skyid.program, &quake_skyid.mvp_matrix);
@ -1284,7 +1284,7 @@ glsl_R_InitBsp (void)
GLSL_ResolveShaderParam (quake_skyid.program, &quake_skyid.realtime);
GLSL_ResolveShaderParam (quake_skyid.program, &quake_skyid.fog);
frag = GLSL_CompileShader ("quakeskb.frag", quakeskybox_frag,
frag = GLSL_CompileShaderS ("quakeskb.frag", quakeskybox_frag,
GL_FRAGMENT_SHADER);
quake_skybox.program = GLSL_LinkProgram ("quakeskybox", vert, frag);
GLSL_ResolveShaderParam (quake_skybox.program, &quake_skybox.mvp_matrix);

View file

@ -381,9 +381,9 @@ glsl_Draw_Init (void)
draw_queue = dstring_new ();
vert = GLSL_CompileShader ("quakeico.vert", quakeicon_vert,
vert = GLSL_CompileShaderS ("quakeico.vert", quakeicon_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quake2d.frag", quake2d_frag,
frag = GLSL_CompileShaderS ("quake2d.frag", quake2d_frag,
GL_FRAGMENT_SHADER);
quake_2d.program = GLSL_LinkProgram ("quake2d", vert, frag);
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.texture);

View file

@ -140,8 +140,8 @@ glsl_R_InitIQM (void)
int frag;
int i;
vert = GLSL_CompileShader ("iqm.vert", iqm_vert, GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("iqm.frag", iqm_frag, GL_FRAGMENT_SHADER);
vert = GLSL_CompileShaderS ("iqm.vert", iqm_vert, GL_VERTEX_SHADER);
frag = GLSL_CompileShaderS ("iqm.frag", iqm_frag, GL_FRAGMENT_SHADER);
iqm_shader.program = GLSL_LinkProgram ("iqm", vert, frag);
GLSL_ResolveShaderParam (iqm_shader.program, &iqm_shader.mvp_matrix);
GLSL_ResolveShaderParam (iqm_shader.program, &iqm_shader.norm_matrix);

View file

@ -223,9 +223,9 @@ glsl_R_InitParticles (void)
qfeglGetFloatv (GL_ALIASED_POINT_SIZE_RANGE, v);
Sys_MaskPrintf (SYS_GLSL, "point size: %g - %g\n", v[0], v[1]);
vert = GLSL_CompileShader ("quakepnt.vert", quakepoint_vert,
vert = GLSL_CompileShaderS ("quakepnt.vert", quakepoint_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakepnt.frag", quakepoint_frag,
frag = GLSL_CompileShaderS ("quakepnt.frag", quakepoint_frag,
GL_FRAGMENT_SHADER);
quake_point.program = GLSL_LinkProgram ("quakepoint", vert, frag);
GLSL_ResolveShaderParam (quake_point.program, &quake_point.mvp_matrix);
@ -234,9 +234,9 @@ glsl_R_InitParticles (void)
GLSL_ResolveShaderParam (quake_point.program, &quake_point.color);
GLSL_ResolveShaderParam (quake_point.program, &quake_point.fog);
vert = GLSL_CompileShader ("quakepar.vert", quakepart_vert,
vert = GLSL_CompileShaderS ("quakepar.vert", quakepart_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakepar.frag", quakepart_frag,
frag = GLSL_CompileShaderS ("quakepar.frag", quakepart_frag,
GL_FRAGMENT_SHADER);
quake_part.program = GLSL_LinkProgram ("quakepart", vert, frag);
GLSL_ResolveShaderParam (quake_part.program, &quake_part.mvp_matrix);

View file

@ -0,0 +1,161 @@
/*
glsl_shader.c
Shader management based on The OpenGL Shader Wrangler
http://prideout.net/blog/?p=11
Copyright (C) 2013 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2013/02/26
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/alloc.h"
#include "QF/dstring.h"
#include "QF/hash.h"
#include "QF/segtext.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/GLSL/qf_vid.h"
typedef struct glsl_effect_s {
struct glsl_effect_s *next;
const char *name;
segtext_t *text;
} glsl_effect_t;
static hashtab_t *effect_tab;
static glsl_effect_t *free_effects;
static glsl_effect_t *
new_effect (void)
{
glsl_effect_t *effect;
ALLOC (64, glsl_effect_t, effects, effect);
return effect;
}
static const char *
effect_get_key (const void *e, void *unused)
{
glsl_effect_t *effect = (glsl_effect_t *) e;
return effect->name;
}
int
GLSL_RegisterEffect (const char *name, const char *src)
{
glsl_effect_t *effect;
segtext_t *text;
if (!effect_tab)
effect_tab = Hash_NewTable (61, effect_get_key, 0, 0);
if (Hash_Find (effect_tab, name)) {
Sys_Printf ("WARNING: ignoring duplicate '%s' effect\n", name);
return 0;
}
text = Segtext_new (src);
if (!text) {
Sys_Printf ("WARNING: %s: problem parsing effect source\n", name);
return 0;
}
effect = new_effect ();
effect->name = strdup (name);
effect->text = text;
Hash_Add (effect_tab, effect);
return 1;
}
shader_t *
GLSL_BuildShader (const char **effect_keys)
{
const char *dot;
const char **key;
int num_keys = 0;
shader_t *shader;
dstring_t *ekey;
glsl_effect_t *effect;
const segchunk_t *chunk;
for (key = effect_keys; *key; key++)
num_keys++;
shader = malloc (sizeof (shader_t));
shader->num_strings = num_keys;
shader->strings = calloc (2, num_keys);
shader->src = shader->strings + num_keys;
ekey = dstring_new ();
for (key = effect_keys; *key; key++) {
int num = key - effect_keys;
dot = strchr (*key, '.');
if (!dot) {
Sys_Printf ("Invalid effect key: '%s'\n", *key);
goto error;
}
dstring_copysubstr (ekey, *key, dot - *key);
effect = Hash_Find (effect_tab, ekey->str);
if (!effect) {
Sys_Printf ("Unknown effect: '%s'\n", ekey->str);
goto error;
}
dot++;
chunk = Segtext_FindChunk (effect->text, dot);
if (!chunk) {
Sys_Printf ("Unknown shader key: '%s'\n", dot);
goto error;
}
shader->strings[num] = nva ("#line %d\n%s", chunk->start_line,
chunk->text);
shader->src[num] = strdup (ekey->str);
}
dstring_delete (ekey);
return shader;
error:
// there is guaranteed to be a null in the array if an error occurs.
for (key = shader->strings; *key; key++) {
free ((char *) *key);
free ((char *) shader->src[key - shader->strings]);
}
free (shader->strings);
free (shader);
dstring_delete (ekey);
return 0;
}
void
GLSL_FreeShader (shader_t *shader)
{
int i;
for (i = 0; i < shader->num_strings; i++) {
free ((char *) shader->strings[i]);
free ((char *) shader->src[i]);
}
free (shader->strings);
free (shader);
}

View file

@ -98,9 +98,9 @@ glsl_R_InitSprites (void)
{
int frag, vert;
vert = GLSL_CompileShader ("quakespr.vert", quakesprite_vert,
vert = GLSL_CompileShaderS ("quakespr.vert", quakesprite_vert,
GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("quakespr.frag", quakesprite_frag,
frag = GLSL_CompileShaderS ("quakespr.frag", quakesprite_frag,
GL_FRAGMENT_SHADER);
quake_sprite.program = GLSL_LinkProgram ("quakespr", vert, frag);
GLSL_ResolveShaderParam (quake_sprite.program, &quake_sprite.spritea);

View file

@ -184,33 +184,40 @@ GLSL_Init_Common (void)
}
int
GLSL_CompileShader (const char *name, const char *shader_src, int type)
GLSL_CompileShader (const char *name, const shader_t *shader, int type)
{
const char *src[1];
int shader;
int sid;
int compiled;
src[0] = shader_src;
shader = qfeglCreateShader (type);
qfeglShaderSource (shader, 1, src, 0);
qfeglCompileShader (shader);
qfeglGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
sid = qfeglCreateShader (type);
qfeglShaderSource (sid, shader->num_strings, shader->strings, 0);
qfeglCompileShader (sid);
qfeglGetShaderiv (sid, GL_COMPILE_STATUS, &compiled);
if (!compiled || (developer->int_val & SYS_GLSL)) {
dstring_t *log = dstring_new ();
int size;
qfeglGetShaderiv (shader, GL_INFO_LOG_LENGTH, &size);
qfeglGetShaderiv (sid, GL_INFO_LOG_LENGTH, &size);
log->size = size + 1; // for terminating null
dstring_adjust (log);
qfeglGetShaderInfoLog (shader, log->size, 0, log->str);
qfeglGetShaderInfoLog (sid, log->size, 0, log->str);
if (!compiled)
qfeglDeleteShader (shader);
qfeglDeleteShader (sid);
Sys_Printf ("Shader (%s) compile log:\n----8<----\n%s----8<----\n",
name, log->str);
dstring_delete (log);
if (!compiled)
return 0;
}
return shader;
return sid;
}
int
GLSL_CompileShaderS (const char *name, const char *src, int type)
{
const char *shader_src = src;
const char *shader_name = "wrapped";
shader_t shader = {1, &shader_src, &shader_name};
return GLSL_CompileShader (name, &shader, type);
}
static const char *