1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 // This file was originally written by William Finlayson. I (Nikolaus
\r
6 // Gebhardt) did some minor modifications and changes to it and integrated it
\r
7 // into Irrlicht. Thanks a lot to William for his work on this and that he gave
\r
8 // me his permission to add it into Irrlicht using the zlib license.
\r
10 // After Irrlicht 0.12, Michael Zoech did some improvements to this renderer, I
\r
11 // merged this into Irrlicht 0.14, thanks to him for his work.
\r
13 #include "COpenGLSLMaterialRenderer.h"
\r
15 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
17 #include "IGPUProgrammingServices.h"
\r
18 #include "IShaderConstantSetCallBack.h"
\r
19 #include "IMaterialRendererServices.h"
\r
20 #include "IVideoDriver.h"
\r
23 #include "COpenGLDriver.h"
\r
24 #include "COpenGLCacheHandler.h"
\r
25 #include "COpenGLMaterialRenderer.h"
\r
27 #include "COpenGLCoreFeature.h"
\r
36 COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver* driver,
\r
37 s32& outMaterialTypeNr, const c8* vertexShaderProgram,
\r
38 const c8* vertexShaderEntryPointName,
\r
39 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
40 const c8* pixelShaderProgram,
\r
41 const c8* pixelShaderEntryPointName,
\r
42 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
43 const c8* geometryShaderProgram,
\r
44 const c8* geometryShaderEntryPointName,
\r
45 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
46 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
48 IShaderConstantSetCallBack* callback,
\r
49 E_MATERIAL_TYPE baseMaterial,
\r
51 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), AlphaTest(false), Program(0), Program2(0), UserData(userData)
\r
54 setDebugName("COpenGLSLMaterialRenderer");
\r
57 switch (baseMaterial)
\r
59 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
60 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
63 case EMT_TRANSPARENT_ADD_COLOR:
\r
64 FixedBlending = true;
\r
66 case EMT_ONETEXTURE_BLEND:
\r
69 case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
\r
79 if (!Driver->queryFeature(EVDF_ARB_GLSL))
\r
82 init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, geometryShaderProgram);
\r
86 //! constructor only for use by derived classes who want to
\r
87 //! create a fall back material for example.
\r
88 COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(COpenGLDriver* driver,
\r
89 IShaderConstantSetCallBack* callback,
\r
90 E_MATERIAL_TYPE baseMaterial, s32 userData)
\r
91 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), AlphaTest(false), Program(0), Program2(0), UserData(userData)
\r
93 switch (baseMaterial)
\r
95 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
96 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
99 case EMT_TRANSPARENT_ADD_COLOR:
\r
100 FixedBlending = true;
\r
102 case EMT_ONETEXTURE_BLEND:
\r
105 case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
\r
118 COpenGLSLMaterialRenderer::~COpenGLSLMaterialRenderer()
\r
125 GLhandleARB shaders[8];
\r
127 Driver->extGlGetAttachedObjects(Program, 8, &count, shaders);
\r
128 // avoid bugs in some drivers, which return larger numbers
\r
129 // use int variable to avoid compiler problems with template
\r
130 int mincount=core::min_((int)count,8);
\r
131 for (int i=0; i<mincount; ++i)
\r
132 Driver->extGlDeleteObject(shaders[i]);
\r
133 Driver->extGlDeleteObject(Program);
\r
141 Driver->extGlGetAttachedShaders(Program2, 8, &count, shaders);
\r
142 // avoid bugs in some drivers, which return larger numbers
\r
143 // use int variable to avoid compiler problems with template
\r
144 int mincount=core::min_((int)count,8);
\r
145 for (int i=0; i<mincount; ++i)
\r
146 Driver->extGlDeleteShader(shaders[i]);
\r
147 Driver->extGlDeleteProgram(Program2);
\r
151 UniformInfo.clear();
\r
155 void COpenGLSLMaterialRenderer::init(s32& outMaterialTypeNr,
\r
156 const c8* vertexShaderProgram,
\r
157 const c8* pixelShaderProgram,
\r
158 const c8* geometryShaderProgram,
\r
159 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
162 outMaterialTypeNr = -1;
\r
164 if (!createProgram())
\r
167 #if defined(GL_ARB_vertex_shader) && defined (GL_ARB_fragment_shader)
\r
168 if (vertexShaderProgram)
\r
169 if (!createShader(GL_VERTEX_SHADER_ARB, vertexShaderProgram))
\r
172 if (pixelShaderProgram)
\r
173 if (!createShader(GL_FRAGMENT_SHADER_ARB, pixelShaderProgram))
\r
177 #if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_program4) || defined(GL_NV_geometry_shader4)
\r
178 if (geometryShaderProgram && Driver->queryFeature(EVDF_GEOMETRY_SHADER))
\r
180 if (!createShader(GL_GEOMETRY_SHADER_EXT, geometryShaderProgram))
\r
182 #if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4)
\r
183 if (Program2) // Geometry shaders are supported only in OGL2.x+ drivers.
\r
185 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_INPUT_TYPE_EXT, Driver->primitiveTypeToGL(inType));
\r
186 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_OUTPUT_TYPE_EXT, Driver->primitiveTypeToGL(outType));
\r
187 if (verticesOut==0)
\r
188 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, Driver->MaxGeometryVerticesOut);
\r
190 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
\r
192 #elif defined(GL_NV_geometry_program4)
\r
193 if (verticesOut==0)
\r
194 Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, Driver->MaxGeometryVerticesOut);
\r
196 Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
\r
201 if (!linkProgram())
\r
204 // register myself as new material
\r
205 outMaterialTypeNr = Driver->addMaterialRenderer(this);
\r
209 bool COpenGLSLMaterialRenderer::OnRender(IMaterialRendererServices* service,
\r
210 E_VERTEX_TYPE vtxtype)
\r
212 // call callback to set shader constants
\r
213 if (CallBack && (Program||Program2))
\r
214 CallBack->OnSetConstants(this, UserData);
\r
220 void COpenGLSLMaterialRenderer::OnSetMaterial(const video::SMaterial& material,
\r
221 const video::SMaterial& lastMaterial,
\r
222 bool resetAllRenderstates,
\r
223 video::IMaterialRendererServices* services)
\r
225 if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_ENABLE)
\r
226 Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE_TO_DISABLE);
\r
228 Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE);
\r
230 COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler();
\r
232 if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
\r
235 Driver->irrGlUseProgram(Program2);
\r
237 Driver->extGlUseProgramObject(Program);
\r
240 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
244 cacheHandler->setBlend(true);
\r
245 cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
246 cacheHandler->setAlphaTest(true);
\r
247 cacheHandler->setAlphaFunc(GL_GREATER, 0.f);
\r
249 else if (FixedBlending)
\r
251 cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
\r
252 cacheHandler->setBlend(true);
\r
256 E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact;
\r
257 E_MODULATE_FUNC modulate;
\r
259 unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam);
\r
261 if (Driver->queryFeature(EVDF_BLEND_SEPARATE))
\r
263 cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact),
\r
264 Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact));
\r
268 cacheHandler->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact));
\r
271 cacheHandler->setBlend(true);
\r
273 else if (AlphaTest)
\r
275 cacheHandler->setAlphaTest(true);
\r
276 cacheHandler->setAlphaFunc(GL_GREATER, 0.5f);
\r
280 CallBack->OnSetMaterial(material);
\r
284 void COpenGLSLMaterialRenderer::OnUnsetMaterial()
\r
287 Driver->extGlUseProgramObject(0);
\r
289 Driver->irrGlUseProgram(0);
\r
291 COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler();
\r
292 if (Alpha || FixedBlending || Blending)
\r
294 cacheHandler->setBlend(false);
\r
296 if (Alpha || AlphaTest)
\r
298 cacheHandler->setAlphaTest(false);
\r
303 //! Returns if the material is transparent.
\r
304 bool COpenGLSLMaterialRenderer::isTransparent() const
\r
306 return (Alpha || Blending || FixedBlending);
\r
310 bool COpenGLSLMaterialRenderer::createProgram()
\r
312 if (Driver->Version>=200)
\r
313 Program2 = Driver->extGlCreateProgram();
\r
315 Program = Driver->extGlCreateProgramObject();
\r
320 bool COpenGLSLMaterialRenderer::createShader(GLenum shaderType, const char* shader)
\r
324 GLuint shaderHandle = Driver->extGlCreateShader(shaderType);
\r
325 Driver->extGlShaderSource(shaderHandle, 1, &shader, NULL);
\r
326 Driver->extGlCompileShader(shaderHandle);
\r
330 #ifdef GL_VERSION_2_0
\r
331 Driver->extGlGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
\r
334 if (status != GL_TRUE)
\r
336 core::stringc typeInfo("shaderType: ");
\r
337 typeInfo += core::stringc((unsigned long)shaderType);
\r
338 os::Printer::log("GLSL (> 2.x) shader failed to compile", typeInfo.c_str(), ELL_ERROR);
\r
339 // check error message and log it
\r
342 #ifdef GL_VERSION_2_0
\r
343 Driver->extGlGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH,
\r
348 GLchar *infoLog = new GLchar[maxLength];
\r
349 Driver->extGlGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog);
\r
350 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
357 Driver->extGlAttachShader(Program2, shaderHandle);
\r
361 GLhandleARB shaderHandle = Driver->extGlCreateShaderObject(shaderType);
\r
363 Driver->extGlShaderSourceARB(shaderHandle, 1, &shader, NULL);
\r
364 Driver->extGlCompileShaderARB(shaderHandle);
\r
368 #ifdef GL_ARB_shader_objects
\r
369 Driver->extGlGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status);
\r
374 core::stringc typeInfo("shaderType: ");
\r
375 typeInfo += core::stringc((unsigned long)shaderType);
\r
376 os::Printer::log("GLSL shader failed to compile", typeInfo.c_str(), ELL_ERROR);
\r
377 // check error message and log it
\r
380 #ifdef GL_ARB_shader_objects
\r
381 Driver->extGlGetObjectParameteriv(shaderHandle,
\r
382 GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
\r
386 GLcharARB *infoLog = new GLcharARB[maxLength];
\r
387 Driver->extGlGetInfoLog(shaderHandle, maxLength, &length, infoLog);
\r
388 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
395 Driver->extGlAttachObject(Program, shaderHandle);
\r
401 bool COpenGLSLMaterialRenderer::linkProgram()
\r
405 Driver->extGlLinkProgram(Program2);
\r
409 #ifdef GL_VERSION_2_0
\r
410 Driver->extGlGetProgramiv(Program2, GL_LINK_STATUS, &status);
\r
415 os::Printer::log("GLSL (> 2.x) shader program failed to link", ELL_ERROR);
\r
416 // check error message and log it
\r
419 #ifdef GL_VERSION_2_0
\r
420 Driver->extGlGetProgramiv(Program2, GL_INFO_LOG_LENGTH, &maxLength);
\r
424 GLchar *infoLog = new GLchar[maxLength];
\r
425 Driver->extGlGetProgramInfoLog(Program2, maxLength, &length, infoLog);
\r
426 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
433 // get uniforms information
\r
436 #ifdef GL_VERSION_2_0
\r
437 Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORMS, &num);
\r
447 #ifdef GL_VERSION_2_0
\r
448 Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen);
\r
453 os::Printer::log("GLSL (> 2.x): failed to retrieve uniform information", ELL_ERROR);
\r
457 // seems that some implementations use an extra null terminator
\r
459 c8 *buf = new c8[maxlen];
\r
461 UniformInfo.clear();
\r
462 UniformInfo.reallocate(num);
\r
464 for (GLint i=0; i < num; ++i)
\r
467 memset(buf, 0, maxlen);
\r
470 Driver->extGlGetActiveUniform(Program2, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLchar*>(buf));
\r
472 ui.location = Driver->extGlGetUniformLocation(Program2, buf);
\r
474 UniformInfo.push_back(ui);
\r
481 Driver->extGlLinkProgramARB(Program);
\r
485 #ifdef GL_ARB_shader_objects
\r
486 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_LINK_STATUS_ARB, &status);
\r
491 os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
\r
492 // check error message and log it
\r
495 #ifdef GL_ARB_shader_objects
\r
496 Driver->extGlGetObjectParameteriv(Program,
\r
497 GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
\r
501 GLcharARB *infoLog = new GLcharARB[maxLength];
\r
502 Driver->extGlGetInfoLog(Program, maxLength, &length, infoLog);
\r
503 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
510 // get uniforms information
\r
513 #ifdef GL_ARB_shader_objects
\r
514 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &num);
\r
524 #ifdef GL_ARB_shader_objects
\r
525 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &maxlen);
\r
530 os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
\r
534 // seems that some implementations use an extra null terminator
\r
536 c8 *buf = new c8[maxlen];
\r
538 UniformInfo.clear();
\r
539 UniformInfo.reallocate(num);
\r
541 for (int i=0; i < num; ++i)
\r
544 memset(buf, 0, maxlen);
\r
547 Driver->extGlGetActiveUniformARB(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLcharARB*>(buf));
\r
549 ui.location = Driver->extGlGetUniformLocationARB(Program, buf);
\r
551 UniformInfo.push_back(ui);
\r
561 void COpenGLSLMaterialRenderer::setBasicRenderStates(const SMaterial& material,
\r
562 const SMaterial& lastMaterial,
\r
563 bool resetAllRenderstates)
\r
566 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
569 s32 COpenGLSLMaterialRenderer::getVertexShaderConstantID(const c8* name)
\r
571 return getPixelShaderConstantID(name);
\r
574 s32 COpenGLSLMaterialRenderer::getPixelShaderConstantID(const c8* name)
\r
576 for (u32 i = 0; i < UniformInfo.size(); ++i)
\r
578 if (UniformInfo[i].name == name)
\r
585 void COpenGLSLMaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
587 os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING);
\r
590 void COpenGLSLMaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
592 os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING);
\r
595 bool COpenGLSLMaterialRenderer::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
597 return setPixelShaderConstant(index, floats, count);
\r
600 bool COpenGLSLMaterialRenderer::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
602 return setPixelShaderConstant(index, ints, count);
\r
605 bool COpenGLSLMaterialRenderer::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
607 return setPixelShaderConstant(index, ints, count);
\r
610 bool COpenGLSLMaterialRenderer::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
612 if(index < 0 || UniformInfo[index].location < 0)
\r
615 bool status = true;
\r
617 switch (UniformInfo[index].type)
\r
620 Driver->extGlUniform1fv(UniformInfo[index].location, count, floats);
\r
622 case GL_FLOAT_VEC2:
\r
623 Driver->extGlUniform2fv(UniformInfo[index].location, count/2, floats);
\r
625 case GL_FLOAT_VEC3:
\r
626 Driver->extGlUniform3fv(UniformInfo[index].location, count/3, floats);
\r
628 case GL_FLOAT_VEC4:
\r
629 Driver->extGlUniform4fv(UniformInfo[index].location, count/4, floats);
\r
631 case GL_FLOAT_MAT2:
\r
632 Driver->extGlUniformMatrix2fv(UniformInfo[index].location, count/4, false, floats);
\r
634 case GL_FLOAT_MAT2x3:
\r
635 Driver->extGlUniformMatrix2x3fv(UniformInfo[index].location, count/6, false, floats);
\r
637 case GL_FLOAT_MAT2x4:
\r
638 Driver->extGlUniformMatrix2x4fv(UniformInfo[index].location, count/8, false, floats);
\r
640 case GL_FLOAT_MAT3x2:
\r
641 Driver->extGlUniformMatrix3x2fv(UniformInfo[index].location, count/6, false, floats);
\r
643 case GL_FLOAT_MAT3:
\r
644 Driver->extGlUniformMatrix3fv(UniformInfo[index].location, count/9, false, floats);
\r
646 case GL_FLOAT_MAT3x4:
\r
647 Driver->extGlUniformMatrix3x4fv(UniformInfo[index].location, count/12, false, floats);
\r
649 case GL_FLOAT_MAT4x2:
\r
650 Driver->extGlUniformMatrix4x2fv(UniformInfo[index].location, count/8, false, floats);
\r
652 case GL_FLOAT_MAT4x3:
\r
653 Driver->extGlUniformMatrix4x3fv(UniformInfo[index].location, count/12, false, floats);
\r
655 case GL_FLOAT_MAT4:
\r
656 Driver->extGlUniformMatrix4fv(UniformInfo[index].location, count/16, false, floats);
\r
658 case GL_SAMPLER_1D:
\r
659 case GL_SAMPLER_2D:
\r
660 case GL_SAMPLER_3D:
\r
661 case GL_SAMPLER_CUBE:
\r
662 case GL_SAMPLER_1D_SHADOW:
\r
663 case GL_SAMPLER_2D_SHADOW:
\r
667 const GLint id = static_cast<GLint>(*floats);
\r
668 Driver->extGlUniform1iv(UniformInfo[index].location, 1, &id);
\r
681 bool COpenGLSLMaterialRenderer::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
683 if(index < 0 || UniformInfo[index].location < 0)
\r
686 bool status = true;
\r
688 switch (UniformInfo[index].type)
\r
692 Driver->extGlUniform1iv(UniformInfo[index].location, count, reinterpret_cast<const GLint*>(ints));
\r
696 Driver->extGlUniform2iv(UniformInfo[index].location, count/2, reinterpret_cast<const GLint*>(ints));
\r
700 Driver->extGlUniform3iv(UniformInfo[index].location, count/3, reinterpret_cast<const GLint*>(ints));
\r
704 Driver->extGlUniform4iv(UniformInfo[index].location, count/4, reinterpret_cast<const GLint*>(ints));
\r
706 case GL_SAMPLER_1D:
\r
707 case GL_SAMPLER_2D:
\r
708 case GL_SAMPLER_3D:
\r
709 case GL_SAMPLER_CUBE:
\r
710 case GL_SAMPLER_1D_SHADOW:
\r
711 case GL_SAMPLER_2D_SHADOW:
\r
712 Driver->extGlUniform1iv(UniformInfo[index].location, 1, reinterpret_cast<const GLint*>(ints));
\r
721 bool COpenGLSLMaterialRenderer::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
723 if(index < 0 || UniformInfo[index].location < 0)
\r
726 bool status = true;
\r
728 switch (UniformInfo[index].type)
\r
730 case GL_UNSIGNED_INT:
\r
731 Driver->extGlUniform1uiv(UniformInfo[index].location, count, reinterpret_cast<const GLuint*>(ints));
\r
733 #if defined(GL_VERSION_3_0)
\r
734 case GL_UNSIGNED_INT_VEC2:
\r
735 Driver->extGlUniform2uiv(UniformInfo[index].location, count/2, reinterpret_cast<const GLuint*>(ints));
\r
737 case GL_UNSIGNED_INT_VEC3:
\r
738 Driver->extGlUniform3uiv(UniformInfo[index].location, count/3, reinterpret_cast<const GLuint*>(ints));
\r
740 case GL_UNSIGNED_INT_VEC4:
\r
741 Driver->extGlUniform4uiv(UniformInfo[index].location, count/4, reinterpret_cast<const GLuint*>(ints));
\r
751 IVideoDriver* COpenGLSLMaterialRenderer::getVideoDriver()
\r
756 } // end namespace video
\r
757 } // end namespace irr
\r