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, &currentProgram);
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, &currentProgram);
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