naev 0.11.5
nlua_shader.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <lauxlib.h>
11
12#include "naev.h"
15#include "nlua_shader.h"
16
17#include "log.h"
18#include "ndata.h"
19#include "nluadef.h"
20#include "array.h"
21#include "nlua_tex.h"
22#include "render.h"
23
24/* Shader metatable methods. */
25static int shaderL_gc( lua_State *L );
26static int shaderL_eq( lua_State *L );
27static int shaderL_new( lua_State *L );
28static int shaderL_send( lua_State *L );
29static int shaderL_sendRaw( lua_State *L );
30static int shaderL_hasUniform( lua_State *L );
31static int shaderL_addPostProcess( lua_State *L );
32static int shaderL_rmPostProcess( lua_State *L );
33static const luaL_Reg shaderL_methods[] = {
34 { "__gc", shaderL_gc },
35 { "__eq", shaderL_eq },
36 { "new", shaderL_new },
37 { "send", shaderL_send },
38 { "sendRaw", shaderL_sendRaw },
39 { "hasUniform", shaderL_hasUniform },
40 { "addPPShader", shaderL_addPostProcess },
41 { "rmPPShader", shaderL_rmPostProcess },
42 {0,0}
43};
45/* Useful stuff. */
46static int shader_compareUniform( const void *a, const void *b);
47static int shader_searchUniform( const void *id, const void *u );
48static LuaUniform_t *shader_getUniform( const LuaShader_t *ls, const char *name );
49static int shaderL_sendHelper( lua_State *L, int ignore_missing );
50
57int nlua_loadShader( nlua_env env )
58{
59 nlua_register(env, SHADER_METATABLE, shaderL_methods, 1);
60 return 0;
61}
62
75LuaShader_t* lua_toshader( lua_State *L, int ind )
76{
77 return (LuaShader_t*) lua_touserdata(L,ind);
78}
86LuaShader_t* luaL_checkshader( lua_State *L, int ind )
87{
88 if (lua_isshader(L,ind))
89 return lua_toshader(L,ind);
90 luaL_typerror(L, ind, SHADER_METATABLE);
91 return NULL;
92}
100LuaShader_t* lua_pushshader( lua_State *L, LuaShader_t shader )
101{
102 LuaShader_t *c = (LuaShader_t*) lua_newuserdata(L, sizeof(LuaShader_t));
103 *c = shader;
104 luaL_getmetatable(L, SHADER_METATABLE);
105 lua_setmetatable(L, -2);
106 return c;
107}
115int lua_isshader( lua_State *L, int ind )
116{
117 int ret;
118
119 if (lua_getmetatable(L,ind)==0)
120 return 0;
121 lua_getfield(L, LUA_REGISTRYINDEX, SHADER_METATABLE);
122
123 ret = 0;
124 if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */
125 ret = 1;
126
127 lua_pop(L, 2); /* remove both metatables */
128 return ret;
129}
130
137static int shaderL_gc( lua_State *L )
138{
139 LuaShader_t *shader = luaL_checkshader(L,1);
140 if (shader->pp_id > 0)
141 render_postprocessRm( shader->pp_id );
142 glDeleteProgram( shader->program );
143 array_free( shader->tex );
144 free(shader->uniforms);
145 return 0;
146}
147
156static int shaderL_eq( lua_State *L )
157{
158 LuaShader_t *f1, *f2;
159 f1 = luaL_checkshader(L,1);
160 f2 = luaL_checkshader(L,2);
161 lua_pushboolean( L, (memcmp( f1, f2, sizeof(LuaShader_t) )==0) );
162 return 1;
163}
164
165/*
166 * For qsort.
167 */
168static int shader_compareUniform( const void *a, const void *b )
169{
170 const LuaUniform_t *u1, *u2;
171 u1 = (const LuaUniform_t*) a;
172 u2 = (const LuaUniform_t*) b;
173 return strcmp(u1->name, u2->name);
174}
175
176static int shader_searchUniform( const void *id, const void *u )
177{
178 return strcmp( (const char*)id, ((LuaUniform_t*)u)->name );
179}
180
181static LuaUniform_t *shader_getUniform( const LuaShader_t *ls, const char *name )
182{
183 return bsearch( name, ls->uniforms, ls->nuniforms, sizeof(LuaUniform_t), shader_searchUniform );
184}
185
194static int shaderL_new( lua_State *L )
195{
196 LuaShader_t shader;
197 const char *pixelcode, *vertexcode;
198 GLint ntex;
199 GLsizei length;
200
201 /* Get arguments. */
202 pixelcode = luaL_checkstring(L,1);
203 vertexcode = luaL_checkstring(L,2);
204
205 /* Initialize. */
206 memset( &shader, 0, sizeof(shader) );
207
208 /* Do from string. */
209 shader.program = gl_program_vert_frag_string( vertexcode, strlen(vertexcode), pixelcode, strlen(pixelcode) );
210 if (shader.program == 0)
211 return NLUA_ERROR(L,_("shader failed to compile!"));
212
213 /* Set up defaults. */
214#define ATTRIB(name) \
215 shader.name = glGetAttribLocation( shader.program, #name )
216#define UNIFORM(name) \
217 shader.name = glGetUniformLocation( shader.program, #name )
218 UNIFORM( ViewSpaceFromLocal );
219 UNIFORM( ClipSpaceFromView );
220 UNIFORM( ClipSpaceFromLocal );
221 UNIFORM( ViewNormalFromLocal );
222 UNIFORM( MainTex );
223 UNIFORM( ConstantColour );
224 UNIFORM( love_ScreenSize );
225 ATTRIB( VertexPosition );
226 ATTRIB( VertexTexCoord );
227 ATTRIB( VertexColour );
228#undef ATTRIB
229#undef UNIFORM
230
231 /* Do other uniforms. */
232 glGetProgramiv( shader.program, GL_ACTIVE_UNIFORMS, &shader.nuniforms );
233 shader.uniforms = calloc( shader.nuniforms, sizeof(LuaUniform_t) );
234 ntex = 0;
235 for (GLint i=0; i<shader.nuniforms; i++) {
236 LuaUniform_t *u = &shader.uniforms[i];
237 glGetActiveUniform( shader.program, (GLuint)i, SHADER_NAME_MAXLEN, &length, &u->size, &u->type, u->name );
238 u->id = glGetUniformLocation( shader.program, u->name );
239 u->tex = -1;
240
241 /* Textures need special care. */
242 if ((u->type==GL_SAMPLER_2D) && (strcmp(u->name,"MainTex")!=0)) {
243 if (shader.tex == NULL)
244 shader.tex = array_create(LuaTexture_t);
245 LuaTexture_t *t = &array_grow( &shader.tex );
246 ntex++;
247 t->active = GL_TEXTURE0+ntex;
248 t->texid = 0;
249 t->uniform = u->id;
250 t->value = ntex;
251 u->tex = ntex-1;
252 }
253 }
254 qsort( shader.uniforms, shader.nuniforms, sizeof(LuaUniform_t), shader_compareUniform );
255
256 /* Check if there are textures. */
257
258 gl_checkErr();
259
260 lua_pushshader( L, shader );
261 return 1;
262}
263
267void shader_parseUniformArgsFloat( GLfloat values[4], lua_State *L, int idx, int n )
268{
269 if (lua_istable(L,idx)) {
270 for (int j=0; j<n; j++) {
271 lua_pushnumber(L,j+1);
272 lua_gettable(L,idx);
273 values[j] = luaL_checknumber(L,-1);
274 }
275 lua_pop(L,n);
276 }
277 else {
278 for (int j=0; j<n; j++)
279 values[j] = luaL_checknumber(L,idx+j);
280 }
281}
282
286void shader_parseUniformArgsInt( GLint values[4], lua_State *L, int idx, int n )
287{
288 if (lua_istable(L,idx)) {
289 for (int j=0; j<n; j++) {
290 lua_pushnumber(L,j+1);
291 lua_gettable(L,idx);
292 values[j] = luaL_checkint(L,-1);
293 }
294 lua_pop(L,n);
295 }
296 else {
297 for (int j=0; j<n; j++)
298 values[j] = luaL_checkint(L,idx+j);
299 }
300}
301
309static int shaderL_send( lua_State *L )
310{
311 return shaderL_sendHelper( L, 0 );
312}
313
321static int shaderL_sendRaw( lua_State *L )
322{
323 return shaderL_sendHelper( L, 1 );
324}
325
329static int shaderL_sendHelper( lua_State *L, int ignore_missing )
330{
331 LuaShader_t *ls;
332 LuaUniform_t *u;
333 const char *name;
334 int idx;
335 GLfloat values[4];
336 GLint ivalues[4];
337 glTexture *tex;
338
339 ls = luaL_checkshader(L,1);
340 name = luaL_checkstring(L,2);
341
342 u = shader_getUniform( ls, name );
343 if (u==NULL) {
344 if (ignore_missing)
345 return 0;
346 return NLUA_ERROR(L,_("Shader does not have uniform '%s'!"), name);
347 }
348
349 /* With OpenGL 4.1 or ARB_separate_shader_objects, there
350 * is no need to set the program first. */
351 glUseProgram( ls->program );
352 idx = 3;
353 switch (u->type) {
354 case GL_FLOAT:
355 shader_parseUniformArgsFloat( values, L, idx, 1 );
356 glUniform1f( u->id, values[0] );
357 break;
358 case GL_FLOAT_VEC2:
359 shader_parseUniformArgsFloat( values, L, idx, 2 );
360 glUniform2f( u->id, values[0], values[1] );
361 break;
362 case GL_FLOAT_VEC3:
363 shader_parseUniformArgsFloat( values, L, idx, 3 );
364 glUniform3f( u->id, values[0], values[1], values[2] );
365 break;
366 case GL_FLOAT_VEC4:
367 shader_parseUniformArgsFloat( values, L, idx, 4 );
368 glUniform4f( u->id, values[0], values[1], values[2], values[3] );
369 break;
370
371 case GL_INT:
372 shader_parseUniformArgsInt( ivalues, L, idx, 1 );
373 glUniform1i( u->id, ivalues[0] );
374 break;
375 case GL_INT_VEC2:
376 shader_parseUniformArgsInt( ivalues, L, idx, 2 );
377 glUniform2i( u->id, ivalues[0], ivalues[1] );
378 break;
379 case GL_INT_VEC3:
380 shader_parseUniformArgsInt( ivalues, L, idx, 3 );
381 glUniform3i( u->id, ivalues[0], ivalues[1], ivalues[2] );
382 break;
383 case GL_INT_VEC4:
384 shader_parseUniformArgsInt( ivalues, L, idx, 4 );
385 glUniform4i( u->id, ivalues[0], ivalues[1], ivalues[2], ivalues[3] );
386 break;
387
388 case GL_SAMPLER_2D:
389 tex = luaL_checktex(L,idx);
390 ls->tex[ u->tex ].texid = tex->texture;
391 break;
392
393 default:
394 WARN(_("Unsupported shader uniform type '%d' for uniform '%s'. Ignoring."), u->type, u->name );
395 }
396 glUseProgram( 0 );
397
398 gl_checkErr();
399
400 return 0;
401}
402
411static int shaderL_hasUniform( lua_State *L )
412{
413 /* Parameters. */
414 const LuaShader_t *ls = luaL_checkshader(L,1);
415 const char *name = luaL_checkstring(L,2);
416
417 /* Search. */
418 lua_pushboolean(L, shader_getUniform(ls,name)!=NULL);
419 return 1;
420}
421
431static int shaderL_addPostProcess( lua_State *L )
432{
433 LuaShader_t *ls = luaL_checkshader(L,1);
434 const char *str = luaL_optstring(L,2,"final");
435 int priority = luaL_optinteger(L,3,0);
436 int layer = PP_LAYER_FINAL;
437
438 if (strcmp(str,"final")==0)
439 layer = PP_LAYER_FINAL;
440 else if (strcmp(str,"game")==0)
441 layer = PP_LAYER_GAME;
442 else if (strcmp(str,"gui")==0)
443 layer = PP_LAYER_GUI;
444 else if (strcmp(str,"core")==0)
445 layer = PP_LAYER_CORE;
446 else
447 return NLUA_ERROR(L,_("Layer was '%s', but must be one of 'final', 'game', 'gui', or 'core'."), str);
448
449 if (ls->pp_id == 0)
450 ls->pp_id = render_postprocessAdd( ls, layer, priority, 0 );
451 lua_pushboolean(L, ls->pp_id>0);
452 return 1;
453}
454
462static int shaderL_rmPostProcess( lua_State *L )
463{
464 LuaShader_t *ls = luaL_checkshader(L,1);
465 lua_pushboolean( L, render_postprocessRm( ls->pp_id ) );
466 ls->pp_id = 0;
467 return 1;
468}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
Header file with generic functions and naev-specifics.
LuaShader_t * lua_pushshader(lua_State *L, LuaShader_t shader)
Pushes a shader on the stack.
void shader_parseUniformArgsFloat(GLfloat values[4], lua_State *L, int idx, int n)
Helper to parse up float vector (or arguments).
static int shaderL_send(lua_State *L)
Allows setting values of uniforms for a shader. Errors out if the uniform is unknown or unused (as in...
static int shaderL_sendRaw(lua_State *L)
Allows setting values of uniforms for a shader, while ignoring unknown (or unused) uniforms.
void shader_parseUniformArgsInt(GLint values[4], lua_State *L, int idx, int n)
Helper to parse up integer vector (or arguments).
static const luaL_Reg shaderL_methods[]
Definition nlua_shader.c:33
static int shaderL_eq(lua_State *L)
Compares two shaders to see if they are the same.
static int shaderL_new(lua_State *L)
Creates a new shader.
static int shaderL_hasUniform(lua_State *L)
Checks to see if a shader has a uniform.
static int shaderL_addPostProcess(lua_State *L)
Sets a shader as a post-processing shader.
LuaShader_t * lua_toshader(lua_State *L, int ind)
Lua bindings to interact with shaders.
Definition nlua_shader.c:75
int nlua_loadShader(nlua_env env)
Loads the shader library.
Definition nlua_shader.c:57
LuaShader_t * luaL_checkshader(lua_State *L, int ind)
Gets shader at index or raises error if there is no shader at index.
Definition nlua_shader.c:86
static int shaderL_rmPostProcess(lua_State *L)
Removes a shader as a post-processing shader.
static int shaderL_sendHelper(lua_State *L, int ignore_missing)
Helper to set the uniform while handling unknown/inactive uniforms.
int lua_isshader(lua_State *L, int ind)
Checks to see if ind is a shader.
static int shaderL_gc(lua_State *L)
Frees a shader.
glTexture * luaL_checktex(lua_State *L, int ind)
Gets texture at index or raises error if there is no texture at index.
Definition nlua_tex.c:100
static const double c[]
Definition rng.c:264
unsigned int pp_id
Definition nlua_shader.h:51
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
GLuint texture
Definition opengl_tex.h:52