1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3
4 #include "LuaShaders.h"
5
6 #include "LuaInclude.h"
7
8 #include "LuaHashString.h"
9 #include "LuaHandle.h"
10 #include "LuaOpenGL.h"
11 #include "LuaOpenGLUtils.h"
12 #include "LuaUtils.h"
13
14 #include "Game/Camera.h"
15 #include "Rendering/ShadowHandler.h"
16 #include "System/Log/ILog.h"
17 #include "System/Util.h"
18
19 #include <string>
20 #include <vector>
21 using std::string;
22 using std::vector;
23
24
25 int LuaShaders::activeShaderDepth = 0;
26
27
28 /******************************************************************************/
29 /******************************************************************************/
30
PushEntries(lua_State * L)31 bool LuaShaders::PushEntries(lua_State* L)
32 {
33 #define REGISTER_LUA_CFUNC(x) \
34 lua_pushstring(L, #x); \
35 lua_pushcfunction(L, x); \
36 lua_rawset(L, -3)
37
38 REGISTER_LUA_CFUNC(CreateShader);
39 REGISTER_LUA_CFUNC(DeleteShader);
40 REGISTER_LUA_CFUNC(UseShader);
41 REGISTER_LUA_CFUNC(ActiveShader);
42
43 REGISTER_LUA_CFUNC(GetActiveUniforms);
44 REGISTER_LUA_CFUNC(GetUniformLocation);
45 REGISTER_LUA_CFUNC(Uniform);
46 REGISTER_LUA_CFUNC(UniformInt);
47 REGISTER_LUA_CFUNC(UniformArray);
48 REGISTER_LUA_CFUNC(UniformMatrix);
49
50 REGISTER_LUA_CFUNC(SetShaderParameter);
51
52 REGISTER_LUA_CFUNC(GetShaderLog);
53
54 return true;
55 }
56
57
58 /******************************************************************************/
59 /******************************************************************************/
60
LuaShaders()61 LuaShaders::LuaShaders()
62 {
63 Program p;
64 p.id = 0;
65 programs.push_back(p);
66 }
67
68
~LuaShaders()69 LuaShaders::~LuaShaders()
70 {
71 for (int p = 0; p < (int)programs.size(); p++) {
72 DeleteProgram(programs[p]);
73 }
74 programs.clear();
75 }
76
77
78 /******************************************************************************/
79 /******************************************************************************/
80
CheckDrawingEnabled(lua_State * L,const char * caller)81 inline void CheckDrawingEnabled(lua_State* L, const char* caller)
82 {
83 if (!LuaOpenGL::IsDrawingEnabled(L)) {
84 luaL_error(L, "%s(): OpenGL calls can only be used in Draw() "
85 "call-ins, or while creating display lists", caller);
86 }
87 }
88
89
90 /******************************************************************************/
91 /******************************************************************************/
92
GetProgramName(unsigned int progID) const93 GLuint LuaShaders::GetProgramName(unsigned int progID) const
94 {
95 if (progID < programs.size()) {
96 return programs[progID].id;
97 } else {
98 return 0;
99 }
100 }
101
102
GetProgramName(lua_State * L,int index) const103 GLuint LuaShaders::GetProgramName(lua_State* L, int index) const
104 {
105 const int progID = (GLuint)luaL_checkint(L, 1);
106 if ((progID <= 0) || (progID >= (int)programs.size())) {
107 return 0;
108 }
109 return programs[progID].id;
110 }
111
112
AddProgram(const Program & p)113 unsigned int LuaShaders::AddProgram(const Program& p)
114 {
115 if (!unused.empty()) {
116 const unsigned int index = unused[unused.size() - 1];
117 programs[index] = p;
118 unused.pop_back();
119 return index;
120 }
121 programs.push_back(p);
122 return (programs.size() - 1);
123 }
124
125
RemoveProgram(unsigned int progID)126 void LuaShaders::RemoveProgram(unsigned int progID)
127 {
128 if (progID < programs.size()) {
129 Program& p = programs[progID];
130 DeleteProgram(p);
131 unused.push_back(progID);
132 }
133 }
134
135
DeleteProgram(Program & p)136 void LuaShaders::DeleteProgram(Program& p)
137 {
138 if (p.id == 0) {
139 return;
140 }
141
142 for (int o = 0; o < (int)p.objects.size(); o++) {
143 Object& obj = p.objects[o];
144 glDetachShader(p.id, obj.id);
145 glDeleteShader(obj.id);
146 }
147 p.objects.clear();
148
149 glDeleteProgram(p.id);
150 p.id = 0;
151 }
152
153
154 /******************************************************************************/
155 /******************************************************************************/
156
GetShaderLog(lua_State * L)157 int LuaShaders::GetShaderLog(lua_State* L)
158 {
159 const LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
160 lua_pushsstring(L, shaders.errorLog);
161 return 1;
162 }
163
164
165 /******************************************************************************/
166 /******************************************************************************/
167
168 enum {
169 UNIFORM_TYPE_INT = 0, // includes arrays
170 UNIFORM_TYPE_FLOAT = 1, // includes arrays
171 UNIFORM_TYPE_FLOAT_MATRIX = 2,
172 };
173
ParseUniformType(lua_State * L,int loc,int type)174 static void ParseUniformType(lua_State* L, int loc, int type)
175 {
176 switch (type) {
177 case UNIFORM_TYPE_FLOAT: {
178 if (lua_israwnumber(L, -1)) {
179 glUniform1f(loc, lua_tofloat(L, -1));
180 }
181 else if (lua_istable(L, -1)) {
182 float array[32] = {0.0f};
183 const int count = LuaUtils::ParseFloatArray(L, -1, array, sizeof(array) / sizeof(float));
184
185 switch (count) {
186 case 1: { glUniform1f(loc, array[0] ); break; }
187 case 2: { glUniform2f(loc, array[0], array[1] ); break; }
188 case 3: { glUniform3f(loc, array[0], array[1], array[2] ); break; }
189 case 4: { glUniform4f(loc, array[0], array[1], array[2], array[3]); break; }
190 default: { glUniform1fv(loc, count, &array[0]); } break;
191 }
192 }
193
194 return;
195 }
196 case UNIFORM_TYPE_INT: {
197 if (lua_israwnumber(L, -1)) {
198 glUniform1i(loc, lua_toint(L, -1));
199 }
200 else if (lua_istable(L, -1)) {
201 int array[32] = {0};
202 const int count = LuaUtils::ParseIntArray(L, -1, array, sizeof(array) / sizeof(int));
203
204 switch (count) {
205 case 1: { glUniform1i(loc, array[0] ); break; }
206 case 2: { glUniform2i(loc, array[0], array[1] ); break; }
207 case 3: { glUniform3i(loc, array[0], array[1], array[2] ); break; }
208 case 4: { glUniform4i(loc, array[0], array[1], array[2], array[3]); break; }
209 default: { glUniform1iv(loc, count, &array[0]); } break;
210 }
211 }
212 } break;
213 case UNIFORM_TYPE_FLOAT_MATRIX: {
214 if (lua_istable(L, -1)) {
215 float array[16] = {0.0f};
216 const int count = LuaUtils::ParseFloatArray(L, -1, array, 16);
217
218 switch (count) {
219 case (2 * 2): { glUniformMatrix2fv(loc, 1, GL_FALSE, array); break; }
220 case (3 * 3): { glUniformMatrix3fv(loc, 1, GL_FALSE, array); break; }
221 case (4 * 4): { glUniformMatrix4fv(loc, 1, GL_FALSE, array); break; }
222 }
223 }
224 } break;
225 }
226 }
227
ParseUniformsTable(lua_State * L,const char * fieldName,int index,int type,GLuint progName)228 static bool ParseUniformsTable(lua_State* L, const char* fieldName, int index, int type, GLuint progName)
229 {
230 lua_getfield(L, index, fieldName);
231
232 if (lua_istable(L, -1)) {
233 const int table = lua_gettop(L);
234
235 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
236 if (!lua_israwstring(L, -2))
237 continue;
238
239 const string name = lua_tostring(L, -2);
240 const GLint loc = glGetUniformLocation(progName, name.c_str());
241
242 if (loc < 0)
243 continue;
244
245 ParseUniformType(L, loc, type);
246 }
247 }
248
249 lua_pop(L, 1);
250 return true;
251 }
252
253
ParseUniformSetupTables(lua_State * L,int index,GLuint progName)254 static bool ParseUniformSetupTables(lua_State* L, int index, GLuint progName)
255 {
256 GLint currentProgram;
257 glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram);
258
259 glUseProgram(progName);
260
261 const bool success =
262 ParseUniformsTable(L, "uniform", index, UNIFORM_TYPE_FLOAT, progName) &&
263 ParseUniformsTable(L, "uniformFloat", index, UNIFORM_TYPE_FLOAT, progName) &&
264 ParseUniformsTable(L, "uniformInt", index, UNIFORM_TYPE_INT, progName) &&
265 ParseUniformsTable(L, "uniformMatrix", index, UNIFORM_TYPE_FLOAT_MATRIX, progName);
266
267 glUseProgram(currentProgram);
268
269 return success;
270 }
271
272
273 /******************************************************************************/
274 /******************************************************************************/
275
CompileObject(lua_State * L,const vector<string> & defs,const vector<string> & sources,const GLenum type,bool & success)276 static GLuint CompileObject(
277 lua_State* L,
278 const vector<string>& defs,
279 const vector<string>& sources,
280 const GLenum type,
281 bool& success
282 ) {
283 if (sources.empty()) {
284 success = true;
285 return 0;
286 }
287
288 GLuint obj = glCreateShader(type);
289 if (obj == 0) {
290 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
291 shaders.errorLog = "Could not create shader object";
292 return 0;
293 }
294
295 std::vector<const GLchar*> text(defs.size() + sources.size());
296
297 for (unsigned int i = 0; i < defs.size(); i++)
298 text[i] = defs[i].c_str();
299 for (unsigned int i = 0; i < sources.size(); i++)
300 text[defs.size() + i] = sources[i].c_str();
301
302 glShaderSource(obj, text.size(), &text[0], NULL);
303 glCompileShader(obj);
304
305 GLint result;
306 glGetShaderiv(obj, GL_COMPILE_STATUS, &result);
307 if (result != GL_TRUE) {
308 GLchar log[4096];
309 GLsizei logSize = sizeof(log);
310 glGetShaderInfoLog(obj, logSize, &logSize, log);
311
312 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
313 shaders.errorLog = log;
314 if (shaders.errorLog.empty()) {
315 shaders.errorLog = "Empty error message: code = "
316 + IntToString(result) + " (0x"
317 + IntToString(result, "%04X") + ")";
318 }
319
320 glDeleteShader(obj);
321
322 success = false;
323 return 0;
324 }
325
326 success = true;
327 return obj;
328 }
329
330
ParseShaderTable(lua_State * L,const int table,const char * key,vector<string> & data)331 static bool ParseShaderTable(
332 lua_State* L,
333 const int table,
334 const char* key,
335 vector<string>& data
336 ) {
337 lua_getfield(L, table, key);
338
339 if (lua_israwstring(L, -1)) {
340 const string txt = lua_tostring(L, -1);
341 if (!txt.empty()) {
342 data.push_back(txt);
343 }
344 }
345 else if (lua_istable(L, -1)) {
346 const int subtable = lua_gettop(L);
347 for (lua_pushnil(L); lua_next(L, subtable) != 0; lua_pop(L, 1)) {
348 if (!lua_israwnumber(L, -2) || !lua_israwstring(L, -1)) {
349 continue;
350 }
351 const string txt = lua_tostring(L, -1);
352 if (!txt.empty()) {
353 data.push_back(txt);
354 }
355 }
356 }
357 else if (!lua_isnil(L, -1)) {
358 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
359 shaders.errorLog = "\"" + string(key) + "\" must be a string or a table value!";
360 lua_pop(L, 1);
361 return false;
362 }
363
364 lua_pop(L, 1);
365 return true;
366 }
367
368
ApplyGeometryParameters(lua_State * L,int table,GLuint prog)369 static void ApplyGeometryParameters(lua_State* L, int table, GLuint prog)
370 {
371 if (!IS_GL_FUNCTION_AVAILABLE(glProgramParameteriEXT)) {
372 return;
373 }
374
375 struct { const char* name; GLenum param; } parameters[] = {
376 { "geoInputType", GL_GEOMETRY_INPUT_TYPE_EXT },
377 { "geoOutputType", GL_GEOMETRY_OUTPUT_TYPE_EXT },
378 { "geoOutputVerts", GL_GEOMETRY_VERTICES_OUT_EXT }
379 };
380
381 const int count = sizeof(parameters) / sizeof(parameters[0]);
382 for (int i = 0; i < count; i++) {
383 lua_getfield(L, table, parameters[i].name);
384 if (lua_israwnumber(L, -1)) {
385 const GLint type = lua_toint(L, -1);
386 glProgramParameteriEXT(prog, parameters[i].param, type);
387 }
388 lua_pop(L, 1);
389 }
390 }
391
392
CreateShader(lua_State * L)393 int LuaShaders::CreateShader(lua_State* L)
394 {
395 const int args = lua_gettop(L);
396
397 if ((args != 1) || !lua_istable(L, 1)) {
398 luaL_error(L, "Incorrect arguments to gl.CreateShader()");
399 }
400
401 vector<string> shdrDefs;
402 vector<string> vertSrcs;
403 vector<string> geomSrcs;
404 vector<string> fragSrcs;
405
406 ParseShaderTable(L, 1, "definitions", shdrDefs);
407
408 if (!ParseShaderTable(L, 1, "vertex", vertSrcs) ||
409 !ParseShaderTable(L, 1, "geometry", geomSrcs) ||
410 !ParseShaderTable(L, 1, "fragment", fragSrcs)) {
411 return 0;
412 }
413
414 if (vertSrcs.empty() && fragSrcs.empty() && geomSrcs.empty())
415 return 0;
416
417 bool success;
418 const GLuint vertObj = CompileObject(L, shdrDefs, vertSrcs, GL_VERTEX_SHADER, success);
419
420 if (!success)
421 return 0;
422
423 const GLuint geomObj = CompileObject(L, shdrDefs, geomSrcs, GL_GEOMETRY_SHADER_EXT, success);
424
425 if (!success) {
426 glDeleteShader(vertObj);
427 return 0;
428 }
429
430 const GLuint fragObj = CompileObject(L, shdrDefs, fragSrcs, GL_FRAGMENT_SHADER, success);
431
432 if (!success) {
433 glDeleteShader(vertObj);
434 glDeleteShader(geomObj);
435 return 0;
436 }
437
438 const GLuint prog = glCreateProgram();
439
440 Program p;
441 p.id = prog;
442
443 if (vertObj != 0) {
444 glAttachShader(prog, vertObj);
445 p.objects.push_back(Object(vertObj, GL_VERTEX_SHADER));
446 }
447 if (geomObj != 0) {
448 glAttachShader(prog, geomObj);
449 p.objects.push_back(Object(geomObj, GL_GEOMETRY_SHADER_EXT));
450 ApplyGeometryParameters(L, 1, prog); // done before linking
451 }
452 if (fragObj != 0) {
453 glAttachShader(prog, fragObj);
454 p.objects.push_back(Object(fragObj, GL_FRAGMENT_SHADER));
455 }
456
457 glLinkProgram(prog);
458
459 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
460
461 GLint result;
462 glGetProgramiv(prog, GL_LINK_STATUS, &result);
463
464 if (result != GL_TRUE) {
465 GLchar log[4096];
466 GLsizei logSize = sizeof(log);
467 glGetProgramInfoLog(prog, logSize, &logSize, log);
468 shaders.errorLog = log;
469
470 DeleteProgram(p);
471 return 0;
472 }
473
474 // Allows setting up uniforms when drawing is disabled
475 // (much more convenient for sampler uniforms, and static
476 // configuration values)
477 ParseUniformSetupTables(L, 1, prog);
478
479 lua_pushnumber(L, shaders.AddProgram(p));
480 return 1;
481 }
482
483
DeleteShader(lua_State * L)484 int LuaShaders::DeleteShader(lua_State* L)
485 {
486 if (lua_isnil(L, 1)) {
487 return 0;
488 }
489 const int progID = luaL_checkint(L, 1);
490 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
491 shaders.RemoveProgram(progID);
492 return 0;
493 }
494
495
UseShader(lua_State * L)496 int LuaShaders::UseShader(lua_State* L)
497 {
498 CheckDrawingEnabled(L, __FUNCTION__);
499
500 const int progID = luaL_checkint(L, 1);
501 if (progID == 0) {
502 glUseProgram(0);
503 lua_pushboolean(L, true);
504 return 1;
505 }
506
507 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
508 const GLuint progName = shaders.GetProgramName(progID);
509 if (progName == 0) {
510 lua_pushboolean(L, false);
511 } else {
512 glUseProgram(progName);
513 lua_pushboolean(L, true);
514 }
515 return 1;
516 }
517
518
ActiveShader(lua_State * L)519 int LuaShaders::ActiveShader(lua_State* L)
520 {
521 const int progID = luaL_checkint(L, 1);
522 luaL_checktype(L, 2, LUA_TFUNCTION);
523
524 GLuint progName;
525 if (progID == 0) {
526 progName = 0;
527 }
528 else {
529 LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
530 progName = shaders.GetProgramName(progID);
531 if (progName == 0) {
532 return 0;
533 }
534 }
535
536 GLint currentProgram;
537 glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram);
538
539 glUseProgram(progName);
540 activeShaderDepth++;
541 const int error = lua_pcall(L, lua_gettop(L) - 2, 0, 0);
542 activeShaderDepth--;
543 glUseProgram(currentProgram);
544
545 if (error != 0) {
546 LOG_L(L_ERROR, "gl.ActiveShader: error(%i) = %s",
547 error, lua_tostring(L, -1));
548 lua_error(L);
549 }
550
551 return 0;
552 }
553
554
555 /******************************************************************************/
556 /******************************************************************************/
557
UniformTypeString(GLenum type)558 static const char* UniformTypeString(GLenum type)
559 {
560 #define UNIFORM_STRING_CASE(x) \
561 case (GL_ ## x): { \
562 static const string str = StringToLower(#x); \
563 return str.c_str(); \
564 }
565
566 switch (type) {
567 UNIFORM_STRING_CASE(FLOAT)
568 UNIFORM_STRING_CASE(FLOAT_VEC2)
569 UNIFORM_STRING_CASE(FLOAT_VEC3)
570 UNIFORM_STRING_CASE(FLOAT_VEC4)
571 UNIFORM_STRING_CASE(FLOAT_MAT2)
572 UNIFORM_STRING_CASE(FLOAT_MAT3)
573 UNIFORM_STRING_CASE(FLOAT_MAT4)
574 UNIFORM_STRING_CASE(SAMPLER_1D)
575 UNIFORM_STRING_CASE(SAMPLER_2D)
576 UNIFORM_STRING_CASE(SAMPLER_3D)
577 UNIFORM_STRING_CASE(SAMPLER_CUBE)
578 UNIFORM_STRING_CASE(SAMPLER_1D_SHADOW)
579 UNIFORM_STRING_CASE(SAMPLER_2D_SHADOW)
580 UNIFORM_STRING_CASE(INT)
581 UNIFORM_STRING_CASE(INT_VEC2)
582 UNIFORM_STRING_CASE(INT_VEC3)
583 UNIFORM_STRING_CASE(INT_VEC4)
584 UNIFORM_STRING_CASE(BOOL)
585 UNIFORM_STRING_CASE(BOOL_VEC2)
586 UNIFORM_STRING_CASE(BOOL_VEC3)
587 UNIFORM_STRING_CASE(BOOL_VEC4)
588 default: {
589 return "unknown_type";
590 }
591 }
592 }
593
594
GetActiveUniforms(lua_State * L)595 int LuaShaders::GetActiveUniforms(lua_State* L)
596 {
597 const LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
598 const GLuint progName = shaders.GetProgramName(L, 1);
599 if (progName == 0) {
600 return 0;
601 }
602
603 GLint uniformCount;
604 glGetProgramiv(progName, GL_ACTIVE_UNIFORMS, &uniformCount);
605
606 lua_newtable(L);
607
608 for (GLint i = 0; i < uniformCount; i++) {
609 GLsizei length;
610 GLint size;
611 GLenum type;
612 GLchar name[1024];
613 glGetActiveUniform(progName, i, sizeof(name), &length, &size, &type, name);
614
615 lua_newtable(L); {
616 HSTR_PUSH_STRING(L, "name", name);
617 HSTR_PUSH_STRING(L, "type", UniformTypeString(type));
618 HSTR_PUSH_NUMBER(L, "length", length);
619 HSTR_PUSH_NUMBER(L, "size", size);
620 }
621 lua_rawseti(L, -2, i + 1);
622 }
623
624 return 1;
625 }
626
627
GetUniformLocation(lua_State * L)628 int LuaShaders::GetUniformLocation(lua_State* L)
629 {
630 const LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
631 const GLuint progName = shaders.GetProgramName(L, 1);
632 if (progName == 0) {
633 return 0;
634 }
635
636 const string name = luaL_checkstring(L, 2);
637 const GLint location = glGetUniformLocation(progName, name.c_str());
638 lua_pushnumber(L, location);
639 return 1;
640 }
641
642
643 /******************************************************************************/
644 /******************************************************************************/
645
Uniform(lua_State * L)646 int LuaShaders::Uniform(lua_State* L)
647 {
648 if (activeShaderDepth <= 0)
649 CheckDrawingEnabled(L, __FUNCTION__);
650
651 const GLuint location = (GLuint) luaL_checknumber(L, 1);
652 const int numValues = lua_gettop(L) - 1;
653
654 switch (numValues) {
655 case 1: {
656 glUniform1f(location, luaL_checkfloat(L, 2));
657 break;
658 }
659 case 2: {
660 glUniform2f(location, luaL_checkfloat(L, 2), luaL_checkfloat(L, 3));
661 break;
662 }
663 case 3: {
664 glUniform3f(location, luaL_checkfloat(L, 2), luaL_checkfloat(L, 3), luaL_checkfloat(L, 4));
665 break;
666 }
667 case 4: {
668 glUniform4f(location, luaL_checkfloat(L, 2), luaL_checkfloat(L, 3), luaL_checkfloat(L, 4), luaL_checkfloat(L, 5));
669 break;
670 }
671 default: {
672 luaL_error(L, "Incorrect arguments to gl.Uniform()");
673 }
674 }
675
676 return 0;
677 }
678
679
UniformInt(lua_State * L)680 int LuaShaders::UniformInt(lua_State* L)
681 {
682 if (activeShaderDepth <= 0)
683 CheckDrawingEnabled(L, __FUNCTION__);
684
685 const GLuint location = (GLuint) luaL_checknumber(L, 1);
686 const int numValues = lua_gettop(L) - 1;
687
688 switch (numValues) {
689 case 1: {
690 glUniform1i(location, luaL_checkint(L, 2));
691 break;
692 }
693 case 2: {
694 glUniform2i(location, luaL_checkint(L, 2), luaL_checkint(L, 3));
695 break;
696 }
697 case 3: {
698 glUniform3i(location, luaL_checkint(L, 2), luaL_checkint(L, 3), luaL_checkint(L, 4));
699 break;
700 }
701 case 4: {
702 glUniform4i(location, luaL_checkint(L, 2), luaL_checkint(L, 3), luaL_checkint(L, 4), luaL_checkint(L, 5));
703 break;
704 }
705 default: {
706 luaL_error(L, "Incorrect arguments to gl.UniformInt()");
707 }
708 }
709
710 return 0;
711 }
712
UniformArray(lua_State * L)713 int LuaShaders::UniformArray(lua_State* L)
714 {
715 if (activeShaderDepth <= 0)
716 CheckDrawingEnabled(L, __FUNCTION__);
717
718 if (!lua_istable(L, 3))
719 return 0;
720
721 const GLuint location = (GLuint) luaL_checknumber(L, 1);
722
723 switch (luaL_checkint(L, 2)) {
724 case UNIFORM_TYPE_INT: {
725 int array[32] = {0};
726 const int count = LuaUtils::ParseIntArray(L, 3, array, sizeof(array) / sizeof(int));
727
728 glUniform1iv(location, count, &array[0]);
729 } break;
730
731 case UNIFORM_TYPE_FLOAT: {
732 float array[32] = {0.0f};
733 const int count = LuaUtils::ParseFloatArray(L, 3, array, sizeof(array) / sizeof(float));
734
735 glUniform1fv(location, count, &array[0]);
736 } break;
737
738 default: {
739 } break;
740 }
741
742 return 0;
743 }
744
UniformMatrix(lua_State * L)745 int LuaShaders::UniformMatrix(lua_State* L)
746 {
747 if (activeShaderDepth <= 0)
748 CheckDrawingEnabled(L, __FUNCTION__);
749
750 const GLuint location = (GLuint)luaL_checknumber(L, 1);
751 const int numValues = lua_gettop(L) - 1;
752
753 switch (numValues) {
754 case 1: {
755 if (!lua_isstring(L, 2)) {
756 luaL_error(L, "Incorrect arguments to gl.UniformMatrix()");
757 }
758
759 const string matName = lua_tostring(L, 2);
760 const CMatrix44f* mat = LuaOpenGLUtils::GetNamedMatrix(matName);
761
762 if (mat) {
763 glUniformMatrix4fv(location, 1, GL_FALSE, *mat);
764 } else {
765 luaL_error(L, "Incorrect arguments to gl.UniformMatrix()");
766 }
767 break;
768 }
769 case (2 * 2): {
770 float array[2 * 2];
771
772 for (int i = 0; i < (2 * 2); i++) {
773 array[i] = luaL_checkfloat(L, i + 2);
774 }
775
776 glUniformMatrix2fv(location, 1, GL_FALSE, array);
777 break;
778 }
779 case (3 * 3): {
780 float array[3 * 3];
781
782 for (int i = 0; i < (3 * 3); i++) {
783 array[i] = luaL_checkfloat(L, i + 2);
784 }
785
786 glUniformMatrix3fv(location, 1, GL_FALSE, array);
787 break;
788 }
789 case (4 * 4): {
790 float array[4 * 4];
791
792 for (int i = 0; i < (4 * 4); i++) {
793 array[i] = luaL_checkfloat(L, i + 2);
794 }
795
796 glUniformMatrix4fv(location, 1, GL_FALSE, array);
797 break;
798 }
799 default: {
800 luaL_error(L, "Incorrect arguments to gl.UniformMatrix()");
801 }
802 }
803
804 return 0;
805 }
806
807
SetShaderParameter(lua_State * L)808 int LuaShaders::SetShaderParameter(lua_State* L)
809 {
810 if (activeShaderDepth <= 0) {
811 CheckDrawingEnabled(L, __FUNCTION__);
812 }
813
814 const LuaShaders& shaders = CLuaHandle::GetActiveShaders(L);
815 const GLuint progName = shaders.GetProgramName(L, 1);
816 if (progName == 0) {
817 return 0;
818 }
819
820 const GLenum param = (GLenum)luaL_checkint(L, 2);
821 const GLint value = (GLint)luaL_checkint(L, 3);
822
823 if (IS_GL_FUNCTION_AVAILABLE(glProgramParameteriEXT)) {
824 glProgramParameteriEXT(progName, param, value);
825 }
826
827 return 0;
828 }
829
830
831 /******************************************************************************/
832 /******************************************************************************/
833