mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-20 17:41:06 +00:00
e263521330
The GLSL compiler requires any #version lines to be the first (real) line of the program, even #line causes an error, so if the first line of the chunk starts with #version, insert the #line directive as the second line.
170 lines
4 KiB
C
170 lines
4 KiB
C
/*
|
|
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 *effects_freelist;
|
|
|
|
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, 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, sizeof (const char *));
|
|
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;
|
|
}
|
|
if (strncmp ("#version ", chunk->text, 9) == 0) {
|
|
const char *eol = strchr (chunk->text, '\n');
|
|
int vline_len = eol ? eol - chunk->text + 1 : 0;
|
|
shader->strings[num] = nva ("%.*s#line %d\n%s", vline_len,
|
|
chunk->text,
|
|
chunk->start_line + 1,
|
|
chunk->text + vline_len);
|
|
} else {
|
|
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);
|
|
}
|