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 "COGLES2MaterialRenderer.h"
\r
7 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
9 #include "EVertexAttributes.h"
\r
10 #include "IGPUProgrammingServices.h"
\r
11 #include "IShaderConstantSetCallBack.h"
\r
12 #include "IVideoDriver.h"
\r
15 #include "COGLES2Driver.h"
\r
17 #include "COpenGLCoreTexture.h"
\r
18 #include "COpenGLCoreCacheHandler.h"
\r
26 COGLES2MaterialRenderer::COGLES2MaterialRenderer(COGLES2Driver* driver,
\r
27 s32& outMaterialTypeNr,
\r
28 const c8* vertexShaderProgram,
\r
29 const c8* pixelShaderProgram,
\r
30 IShaderConstantSetCallBack* callback,
\r
31 E_MATERIAL_TYPE baseMaterial,
\r
33 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData)
\r
36 setDebugName("COGLES2MaterialRenderer");
\r
39 switch (baseMaterial)
\r
41 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
42 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
45 case EMT_TRANSPARENT_ADD_COLOR:
\r
46 FixedBlending = true;
\r
48 case EMT_ONETEXTURE_BLEND:
\r
58 init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram);
\r
62 COGLES2MaterialRenderer::COGLES2MaterialRenderer(COGLES2Driver* driver,
\r
63 IShaderConstantSetCallBack* callback,
\r
64 E_MATERIAL_TYPE baseMaterial, s32 userData)
\r
65 : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData)
\r
67 switch (baseMaterial)
\r
69 case EMT_TRANSPARENT_VERTEX_ALPHA:
\r
70 case EMT_TRANSPARENT_ALPHA_CHANNEL:
\r
73 case EMT_TRANSPARENT_ADD_COLOR:
\r
74 FixedBlending = true;
\r
76 case EMT_ONETEXTURE_BLEND:
\r
88 COGLES2MaterialRenderer::~COGLES2MaterialRenderer()
\r
97 glGetAttachedShaders(Program, 8, &count, shaders);
\r
99 count=core::min_(count,8);
\r
100 for (GLint i=0; i<count; ++i)
\r
101 glDeleteShader(shaders[i]);
\r
102 glDeleteProgram(Program);
\r
106 UniformInfo.clear();
\r
109 GLuint COGLES2MaterialRenderer::getProgram() const
\r
114 void COGLES2MaterialRenderer::init(s32& outMaterialTypeNr,
\r
115 const c8* vertexShaderProgram,
\r
116 const c8* pixelShaderProgram,
\r
119 outMaterialTypeNr = -1;
\r
121 Program = glCreateProgram();
\r
126 if (vertexShaderProgram)
\r
127 if (!createShader(GL_VERTEX_SHADER, vertexShaderProgram))
\r
130 if (pixelShaderProgram)
\r
131 if (!createShader(GL_FRAGMENT_SHADER, pixelShaderProgram))
\r
134 for ( size_t i = 0; i < EVA_COUNT; ++i )
\r
135 glBindAttribLocation( Program, i, sBuiltInVertexAttributeNames[i]);
\r
137 if (!linkProgram())
\r
141 outMaterialTypeNr = Driver->addMaterialRenderer(this);
\r
145 bool COGLES2MaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
\r
147 if (CallBack && Program)
\r
148 CallBack->OnSetConstants(this, UserData);
\r
154 void COGLES2MaterialRenderer::OnSetMaterial(const video::SMaterial& material,
\r
155 const video::SMaterial& lastMaterial,
\r
156 bool resetAllRenderstates,
\r
157 video::IMaterialRendererServices* services)
\r
159 COGLES2CacheHandler* cacheHandler = Driver->getCacheHandler();
\r
161 cacheHandler->setProgram(Program);
\r
163 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
167 cacheHandler->setBlend(true);
\r
168 cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
170 else if (FixedBlending)
\r
172 cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
\r
173 cacheHandler->setBlend(true);
\r
177 E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact;
\r
178 E_MODULATE_FUNC modulate;
\r
180 unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam);
\r
182 cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact),
\r
183 Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact));
\r
185 cacheHandler->setBlend(true);
\r
189 CallBack->OnSetMaterial(material);
\r
193 void COGLES2MaterialRenderer::OnUnsetMaterial()
\r
198 bool COGLES2MaterialRenderer::isTransparent() const
\r
200 return (Alpha || Blending || FixedBlending);
\r
204 s32 COGLES2MaterialRenderer::getRenderCapability() const
\r
210 bool COGLES2MaterialRenderer::createShader(GLenum shaderType, const char* shader)
\r
214 GLuint shaderHandle = glCreateShader(shaderType);
\r
215 glShaderSource(shaderHandle, 1, &shader, NULL);
\r
216 glCompileShader(shaderHandle);
\r
220 glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
\r
222 if (status != GL_TRUE)
\r
224 os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
\r
229 glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH,
\r
234 GLchar *infoLog = new GLchar[maxLength];
\r
235 glGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog);
\r
236 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
243 glAttachShader(Program, shaderHandle);
\r
250 bool COGLES2MaterialRenderer::linkProgram()
\r
254 glLinkProgram(Program);
\r
258 glGetProgramiv(Program, GL_LINK_STATUS, &status);
\r
262 os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
\r
267 glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &maxLength);
\r
271 GLchar *infoLog = new GLchar[maxLength];
\r
272 glGetProgramInfoLog(Program, maxLength, &length, infoLog);
\r
273 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
\r
282 glGetProgramiv(Program, GL_ACTIVE_UNIFORMS, &num);
\r
289 glGetProgramiv(Program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen);
\r
293 os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
\r
297 // seems that some implementations use an extra null terminator.
\r
299 c8 *buf = new c8[maxlen];
\r
301 UniformInfo.clear();
\r
302 UniformInfo.reallocate(num);
\r
304 for (GLint i=0; i < num; ++i)
\r
307 memset(buf, 0, maxlen);
\r
310 glGetActiveUniform(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLchar*>(buf));
\r
312 core::stringc name = "";
\r
314 // array support, workaround for some bugged drivers.
\r
315 for (s32 i = 0; i < maxlen; ++i)
\r
317 if (buf[i] == '[' || buf[i] == '\0')
\r
324 ui.location = glGetUniformLocation(Program, buf);
\r
326 UniformInfo.push_back(ui);
\r
336 void COGLES2MaterialRenderer::setBasicRenderStates(const SMaterial& material,
\r
337 const SMaterial& lastMaterial,
\r
338 bool resetAllRenderstates)
\r
340 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
\r
343 s32 COGLES2MaterialRenderer::getVertexShaderConstantID(const c8* name)
\r
345 return getPixelShaderConstantID(name);
\r
348 s32 COGLES2MaterialRenderer::getPixelShaderConstantID(const c8* name)
\r
350 for (u32 i = 0; i < UniformInfo.size(); ++i)
\r
352 if (UniformInfo[i].name == name)
\r
359 void COGLES2MaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
361 os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING);
\r
364 void COGLES2MaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
366 os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING);
\r
369 bool COGLES2MaterialRenderer::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
371 return setPixelShaderConstant(index, floats, count);
\r
374 bool COGLES2MaterialRenderer::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
376 return setPixelShaderConstant(index, ints, count);
\r
379 bool COGLES2MaterialRenderer::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
381 return setPixelShaderConstant(index, ints, count);
\r
384 bool COGLES2MaterialRenderer::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
386 if(index < 0 || UniformInfo[index].location < 0)
\r
389 bool status = true;
\r
391 switch (UniformInfo[index].type)
\r
394 glUniform1fv(UniformInfo[index].location, count, floats);
\r
396 case GL_FLOAT_VEC2:
\r
397 glUniform2fv(UniformInfo[index].location, count/2, floats);
\r
399 case GL_FLOAT_VEC3:
\r
400 glUniform3fv(UniformInfo[index].location, count/3, floats);
\r
402 case GL_FLOAT_VEC4:
\r
403 glUniform4fv(UniformInfo[index].location, count/4, floats);
\r
405 case GL_FLOAT_MAT2:
\r
406 glUniformMatrix2fv(UniformInfo[index].location, count/4, false, floats);
\r
408 case GL_FLOAT_MAT3:
\r
409 glUniformMatrix3fv(UniformInfo[index].location, count/9, false, floats);
\r
411 case GL_FLOAT_MAT4:
\r
412 glUniformMatrix4fv(UniformInfo[index].location, count/16, false, floats);
\r
414 case GL_SAMPLER_2D:
\r
415 case GL_SAMPLER_CUBE:
\r
419 const GLint id = (GLint)(*floats);
\r
420 glUniform1iv(UniformInfo[index].location, 1, &id);
\r
434 bool COGLES2MaterialRenderer::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
436 if(index < 0 || UniformInfo[index].location < 0)
\r
439 bool status = true;
\r
441 switch (UniformInfo[index].type)
\r
445 glUniform1iv(UniformInfo[index].location, count, ints);
\r
449 glUniform2iv(UniformInfo[index].location, count/2, ints);
\r
453 glUniform3iv(UniformInfo[index].location, count/3, ints);
\r
457 glUniform4iv(UniformInfo[index].location, count/4, ints);
\r
459 case GL_SAMPLER_2D:
\r
460 case GL_SAMPLER_CUBE:
\r
461 glUniform1iv(UniformInfo[index].location, 1, ints);
\r
471 bool COGLES2MaterialRenderer::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
473 os::Printer::log("Unsigned int support needs at least GLES 3.0", ELL_WARNING);
\r
477 IVideoDriver* COGLES2MaterialRenderer::getVideoDriver()
\r