1 // Copyright (C) 2014 Patryk Nadrowski
\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 #include "MaterialRenderer.h"
\r
7 #include "EVertexAttributes.h"
\r
8 #include "IGPUProgrammingServices.h"
\r
9 #include "IShaderConstantSetCallBack.h"
\r
10 #include "IVideoDriver.h"
\r
15 #include "COpenGLCoreTexture.h"
\r
16 #include "COpenGLCoreCacheHandler.h"
\r
24 COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase* driver,
\r
25 s32& outMaterialTypeNr,
\r
26 const c8* vertexShaderProgram,
\r
27 const c8* pixelShaderProgram,
\r
28 IShaderConstantSetCallBack* callback,
\r
29 E_MATERIAL_TYPE baseMaterial,
\r
31 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData)
\r
34 setDebugName("MaterialRenderer");
\r
37 switch (baseMaterial)
\r
39 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
40 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
43 case EMT_TRANSPARENT_ADD_COLOR:
\r
44 FixedBlending = true;
\r
46 case EMT_ONETEXTURE_BLEND:
\r
56 init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram);
\r
60 COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase* driver,
\r
61 IShaderConstantSetCallBack* callback,
\r
62 E_MATERIAL_TYPE baseMaterial, s32 userData)
\r
63 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData)
\r
65 switch (baseMaterial)
\r
67 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
68 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
71 case EMT_TRANSPARENT_ADD_COLOR:
\r
72 FixedBlending = true;
\r
74 case EMT_ONETEXTURE_BLEND:
\r
86 COpenGL3MaterialRenderer::~COpenGL3MaterialRenderer()
\r
95 glGetAttachedShaders(Program, 8, &count, shaders);
\r
97 count=core::min_(count,8);
\r
98 for (GLint i=0; i<count; ++i)
\r
99 glDeleteShader(shaders[i]);
\r
100 glDeleteProgram(Program);
\r
104 UniformInfo.clear();
\r
107 GLuint COpenGL3MaterialRenderer::getProgram() const
\r
112 void COpenGL3MaterialRenderer::init(s32& outMaterialTypeNr,
\r
113 const c8* vertexShaderProgram,
\r
114 const c8* pixelShaderProgram,
\r
117 outMaterialTypeNr = -1;
\r
119 Program = glCreateProgram();
\r
124 if (vertexShaderProgram)
\r
125 if (!createShader(GL_VERTEX_SHADER, vertexShaderProgram))
\r
128 if (pixelShaderProgram)
\r
129 if (!createShader(GL_FRAGMENT_SHADER, pixelShaderProgram))
\r
132 for ( size_t i = 0; i < EVA_COUNT; ++i )
\r
133 glBindAttribLocation( Program, i, sBuiltInVertexAttributeNames[i]);
\r
135 if (!linkProgram())
\r
139 outMaterialTypeNr = Driver->addMaterialRenderer(this);
\r
143 bool COpenGL3MaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
\r
145 if (CallBack && Program)
\r
146 CallBack->OnSetConstants(this, UserData);
\r
152 void COpenGL3MaterialRenderer::OnSetMaterial(const video::SMaterial& material,
\r
153 const video::SMaterial& lastMaterial,
\r
154 bool resetAllRenderstates,
\r
155 video::IMaterialRendererServices* services)
\r
157 COpenGL3CacheHandler* cacheHandler = Driver->getCacheHandler();
\r
159 cacheHandler->setProgram(Program);
\r
161 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
165 cacheHandler->setBlend(true);
\r
166 cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
168 else if (FixedBlending)
\r
170 cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
\r
171 cacheHandler->setBlend(true);
\r
175 E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact;
\r
176 E_MODULATE_FUNC modulate;
\r
178 unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam);
\r
180 cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact),
\r
181 Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact));
\r
183 cacheHandler->setBlend(true);
\r
187 CallBack->OnSetMaterial(material);
\r
191 void COpenGL3MaterialRenderer::OnUnsetMaterial()
\r
196 bool COpenGL3MaterialRenderer::isTransparent() const
\r
198 return (Alpha || Blending || FixedBlending);
\r
202 s32 COpenGL3MaterialRenderer::getRenderCapability() const
\r
208 bool COpenGL3MaterialRenderer::createShader(GLenum shaderType, const char* shader)
\r
212 GLuint shaderHandle = glCreateShader(shaderType);
\r
213 glShaderSource(shaderHandle, 1, &shader, NULL);
\r
214 glCompileShader(shaderHandle);
\r
218 glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
\r
220 if (status != GL_TRUE)
\r
222 os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
\r
227 glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH,
\r
232 GLchar *infoLog = new GLchar[maxLength];
\r
233 glGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog);
\r
234 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
241 glAttachShader(Program, shaderHandle);
\r
248 bool COpenGL3MaterialRenderer::linkProgram()
\r
252 glLinkProgram(Program);
\r
256 glGetProgramiv(Program, GL_LINK_STATUS, &status);
\r
260 os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
\r
265 glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &maxLength);
\r
269 GLchar *infoLog = new GLchar[maxLength];
\r
270 glGetProgramInfoLog(Program, maxLength, &length, infoLog);
\r
271 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
280 glGetProgramiv(Program, GL_ACTIVE_UNIFORMS, &num);
\r
287 glGetProgramiv(Program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen);
\r
291 os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
\r
295 // seems that some implementations use an extra null terminator.
\r
297 c8 *buf = new c8[maxlen];
\r
299 UniformInfo.clear();
\r
300 UniformInfo.reallocate(num);
\r
302 for (GLint i=0; i < num; ++i)
\r
305 memset(buf, 0, maxlen);
\r
308 glGetActiveUniform(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLchar*>(buf));
\r
310 core::stringc name = "";
\r
312 // array support, workaround for some bugged drivers.
\r
313 for (s32 i = 0; i < maxlen; ++i)
\r
315 if (buf[i] == '[' || buf[i] == '\0')
\r
322 ui.location = glGetUniformLocation(Program, buf);
\r
324 UniformInfo.push_back(ui);
\r
334 void COpenGL3MaterialRenderer::setBasicRenderStates(const SMaterial& material,
\r
335 const SMaterial& lastMaterial,
\r
336 bool resetAllRenderstates)
\r
338 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
341 s32 COpenGL3MaterialRenderer::getVertexShaderConstantID(const c8* name)
\r
343 return getPixelShaderConstantID(name);
\r
346 s32 COpenGL3MaterialRenderer::getPixelShaderConstantID(const c8* name)
\r
348 for (u32 i = 0; i < UniformInfo.size(); ++i)
\r
350 if (UniformInfo[i].name == name)
\r
357 void COpenGL3MaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
359 os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING);
\r
362 void COpenGL3MaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
364 os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING);
\r
367 bool COpenGL3MaterialRenderer::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
369 return setPixelShaderConstant(index, floats, count);
\r
372 bool COpenGL3MaterialRenderer::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
374 return setPixelShaderConstant(index, ints, count);
\r
377 bool COpenGL3MaterialRenderer::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
379 return setPixelShaderConstant(index, ints, count);
\r
382 bool COpenGL3MaterialRenderer::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
384 if(index < 0 || UniformInfo[index].location < 0)
\r
387 bool status = true;
\r
389 switch (UniformInfo[index].type)
\r
392 glUniform1fv(UniformInfo[index].location, count, floats);
\r
394 case GL_FLOAT_VEC2:
\r
395 glUniform2fv(UniformInfo[index].location, count/2, floats);
\r
397 case GL_FLOAT_VEC3:
\r
398 glUniform3fv(UniformInfo[index].location, count/3, floats);
\r
400 case GL_FLOAT_VEC4:
\r
401 glUniform4fv(UniformInfo[index].location, count/4, floats);
\r
403 case GL_FLOAT_MAT2:
\r
404 glUniformMatrix2fv(UniformInfo[index].location, count/4, false, floats);
\r
406 case GL_FLOAT_MAT3:
\r
407 glUniformMatrix3fv(UniformInfo[index].location, count/9, false, floats);
\r
409 case GL_FLOAT_MAT4:
\r
410 glUniformMatrix4fv(UniformInfo[index].location, count/16, false, floats);
\r
412 case GL_SAMPLER_2D:
\r
413 case GL_SAMPLER_CUBE:
\r
417 const GLint id = (GLint)(*floats);
\r
418 glUniform1iv(UniformInfo[index].location, 1, &id);
\r
432 bool COpenGL3MaterialRenderer::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
434 if(index < 0 || UniformInfo[index].location < 0)
\r
437 bool status = true;
\r
439 switch (UniformInfo[index].type)
\r
443 glUniform1iv(UniformInfo[index].location, count, ints);
\r
447 glUniform2iv(UniformInfo[index].location, count/2, ints);
\r
451 glUniform3iv(UniformInfo[index].location, count/3, ints);
\r
455 glUniform4iv(UniformInfo[index].location, count/4, ints);
\r
457 case GL_SAMPLER_2D:
\r
458 case GL_SAMPLER_CUBE:
\r
459 glUniform1iv(UniformInfo[index].location, 1, ints);
\r
469 bool COpenGL3MaterialRenderer::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
471 os::Printer::log("Unsigned int support needs at least GLES 3.0", ELL_WARNING);
\r
475 IVideoDriver* COpenGL3MaterialRenderer::getVideoDriver()
\r