1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
// This file was originally written by William Finlayson. I (Nikolaus
6
// Gebhardt) did some minor modifications and changes to it and integrated it
7
// into Irrlicht. Thanks a lot to William for his work on this and that he gave
8
// me his permission to add it into Irrlicht using the zlib license.
10
// After Irrlicht 0.12, Michael Zoech did some improvements to this renderer, I
11
// merged this into Irrlicht 0.14, thanks to him for his work.
13
#include "IrrCompileConfig.h"
14
#ifdef _IRR_COMPILE_WITH_OPENGL_
16
#include "COpenGLSLMaterialRenderer.h"
17
#include "IGPUProgrammingServices.h"
18
#include "IShaderConstantSetCallBack.h"
19
#include "IMaterialRendererServices.h"
20
#include "IVideoDriver.h"
22
#include "COpenGLDriver.h"
31
COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver* driver,
32
s32& outMaterialTypeNr, const c8* vertexShaderProgram,
33
const c8* vertexShaderEntryPointName,
34
E_VERTEX_SHADER_TYPE vsCompileTarget,
35
const c8* pixelShaderProgram,
36
const c8* pixelShaderEntryPointName,
37
E_PIXEL_SHADER_TYPE psCompileTarget,
38
const c8* geometryShaderProgram,
39
const c8* geometryShaderEntryPointName,
40
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
41
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
43
IShaderConstantSetCallBack* callback,
44
video::IMaterialRenderer* baseMaterial,
46
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
47
Program(0), Program2(0), UserData(userData)
50
setDebugName("COpenGLSLMaterialRenderer");
53
//entry points must always be main, and the compile target isn't selectable
54
//it is fine to ignore what has been asked for, as the compiler should spot anything wrong
55
//just check that GLSL is available
63
if (!Driver->queryFeature(EVDF_ARB_GLSL))
66
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, geometryShaderProgram);
70
//! constructor only for use by derived classes who want to
71
//! create a fall back material for example.
72
COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(COpenGLDriver* driver,
73
IShaderConstantSetCallBack* callback,
74
IMaterialRenderer* baseMaterial, s32 userData)
75
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
76
Program(0), Program2(0), UserData(userData)
87
COpenGLSLMaterialRenderer::~COpenGLSLMaterialRenderer()
94
GLhandleARB shaders[8];
96
Driver->extGlGetAttachedObjects(Program, 8, &count, shaders);
97
for (GLint i=0; i<count; ++i)
98
Driver->extGlDeleteObject(shaders[i]);
99
Driver->extGlDeleteObject(Program);
107
Driver->extGlGetAttachedShaders(Program2, 8, &count, shaders);
108
for (GLint i=0; i<count; ++i)
109
Driver->extGlDeleteShader(shaders[i]);
110
Driver->extGlDeleteProgram(Program2);
117
BaseMaterial->drop();
121
void COpenGLSLMaterialRenderer::init(s32& outMaterialTypeNr,
122
const c8* vertexShaderProgram,
123
const c8* pixelShaderProgram,
124
const c8* geometryShaderProgram,
125
scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
128
outMaterialTypeNr = -1;
130
if (!createProgram())
133
#if defined(GL_ARB_vertex_shader) && defined (GL_ARB_fragment_shader)
134
if (vertexShaderProgram)
135
if (!createShader(GL_VERTEX_SHADER_ARB, vertexShaderProgram))
138
if (pixelShaderProgram)
139
if (!createShader(GL_FRAGMENT_SHADER_ARB, pixelShaderProgram))
143
#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_program4) || defined(GL_NV_geometry_shader4)
144
if (geometryShaderProgram && Driver->queryFeature(EVDF_GEOMETRY_SHADER))
146
if (!createShader(GL_GEOMETRY_SHADER_EXT, geometryShaderProgram))
148
#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4)
151
Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_INPUT_TYPE_EXT, Driver->primitiveTypeToGL(inType));
152
Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_OUTPUT_TYPE_EXT, Driver->primitiveTypeToGL(outType));
154
Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, Driver->MaxGeometryVerticesOut);
156
Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
160
Driver->extGlProgramParameteri(Program, GL_GEOMETRY_INPUT_TYPE_EXT, Driver->primitiveTypeToGL(inType));
161
Driver->extGlProgramParameteri(Program, GL_GEOMETRY_OUTPUT_TYPE_EXT, Driver->primitiveTypeToGL(outType));
163
Driver->extGlProgramParameteri(Program, GL_GEOMETRY_VERTICES_OUT_EXT, Driver->MaxGeometryVerticesOut);
165
Driver->extGlProgramParameteri(Program, GL_GEOMETRY_VERTICES_OUT_EXT, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
167
#elif defined(GL_NV_geometry_program4)
169
Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, Driver->MaxGeometryVerticesOut);
171
Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
179
// register myself as new material
180
outMaterialTypeNr = Driver->addMaterialRenderer(this);
184
bool COpenGLSLMaterialRenderer::OnRender(IMaterialRendererServices* service,
185
E_VERTEX_TYPE vtxtype)
187
// call callback to set shader constants
188
if (CallBack && (Program||Program2))
189
CallBack->OnSetConstants(this, UserData);
195
void COpenGLSLMaterialRenderer::OnSetMaterial(const video::SMaterial& material,
196
const video::SMaterial& lastMaterial,
197
bool resetAllRenderstates,
198
video::IMaterialRendererServices* services)
200
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
203
Driver->extGlUseProgram(Program2);
205
Driver->extGlUseProgramObject(Program);
208
BaseMaterial->OnSetMaterial(material, material, true, this);
211
//let callback know used material
213
CallBack->OnSetMaterial(material);
215
for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i)
216
Driver->setActiveTexture(i, material.getTexture(i));
217
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
221
void COpenGLSLMaterialRenderer::OnUnsetMaterial()
224
Driver->extGlUseProgramObject(0);
226
Driver->extGlUseProgram(0);
229
BaseMaterial->OnUnsetMaterial();
233
//! Returns if the material is transparent.
234
bool COpenGLSLMaterialRenderer::isTransparent() const
236
return BaseMaterial ? BaseMaterial->isTransparent() : false;
240
bool COpenGLSLMaterialRenderer::createProgram()
242
if (Driver->Version>=200)
243
Program2 = Driver->extGlCreateProgram();
245
Program = Driver->extGlCreateProgramObject();
250
bool COpenGLSLMaterialRenderer::createShader(GLenum shaderType, const char* shader)
254
GLuint shaderHandle = Driver->extGlCreateShader(shaderType);
255
Driver->extGlShaderSource(shaderHandle, 1, &shader, NULL);
256
Driver->extGlCompileShader(shaderHandle);
260
#ifdef GL_VERSION_2_0
261
Driver->extGlGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
264
if (status != GL_TRUE)
266
os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
267
// check error message and log it
270
#ifdef GL_VERSION_2_0
271
Driver->extGlGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH,
276
GLchar *infoLog = new GLchar[maxLength];
277
Driver->extGlGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog);
278
os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
285
Driver->extGlAttachShader(Program2, shaderHandle);
289
GLhandleARB shaderHandle = Driver->extGlCreateShaderObject(shaderType);
291
Driver->extGlShaderSourceARB(shaderHandle, 1, &shader, NULL);
292
Driver->extGlCompileShaderARB(shaderHandle);
296
#ifdef GL_ARB_shader_objects
297
Driver->extGlGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status);
302
os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
303
// check error message and log it
306
#ifdef GL_ARB_shader_objects
307
Driver->extGlGetObjectParameteriv(shaderHandle,
308
GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
312
GLcharARB *infoLog = new GLcharARB[maxLength];
313
Driver->extGlGetInfoLog(shaderHandle, maxLength, &length, infoLog);
314
os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
321
Driver->extGlAttachObject(Program, shaderHandle);
327
bool COpenGLSLMaterialRenderer::linkProgram()
331
Driver->extGlLinkProgram(Program2);
335
#ifdef GL_VERSION_2_0
336
Driver->extGlGetProgramiv(Program2, GL_LINK_STATUS, &status);
341
os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
342
// check error message and log it
345
#ifdef GL_VERSION_2_0
346
Driver->extGlGetProgramiv(Program2, GL_INFO_LOG_LENGTH, &maxLength);
350
GLchar *infoLog = new GLchar[maxLength];
351
Driver->extGlGetProgramInfoLog(Program2, maxLength, &length, infoLog);
352
os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
359
// get uniforms information
362
#ifdef GL_VERSION_2_0
363
Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORMS, &num);
373
#ifdef GL_VERSION_2_0
374
Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen);
379
os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
383
// seems that some implementations use an extra null terminator
385
c8 *buf = new c8[maxlen];
388
UniformInfo.reallocate(num);
390
for (GLint i=0; i < num; ++i)
393
memset(buf, 0, maxlen);
396
Driver->extGlGetActiveUniform(Program2, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLchar*>(buf));
399
UniformInfo.push_back(ui);
406
Driver->extGlLinkProgramARB(Program);
410
#ifdef GL_ARB_shader_objects
411
Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_LINK_STATUS_ARB, &status);
416
os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
417
// check error message and log it
420
#ifdef GL_ARB_shader_objects
421
Driver->extGlGetObjectParameteriv(Program,
422
GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
426
GLcharARB *infoLog = new GLcharARB[maxLength];
427
Driver->extGlGetInfoLog(Program, maxLength, &length, infoLog);
428
os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
435
// get uniforms information
438
#ifdef GL_ARB_shader_objects
439
Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &num);
449
#ifdef GL_ARB_shader_objects
450
Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &maxlen);
455
os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
459
// seems that some implementations use an extra null terminator
461
c8 *buf = new c8[maxlen];
464
UniformInfo.reallocate(num);
466
for (int i=0; i < num; ++i)
469
memset(buf, 0, maxlen);
472
Driver->extGlGetActiveUniformARB(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLcharARB*>(buf));
475
UniformInfo.push_back(ui);
485
void COpenGLSLMaterialRenderer::setBasicRenderStates(const SMaterial& material,
486
const SMaterial& lastMaterial,
487
bool resetAllRenderstates)
490
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
494
bool COpenGLSLMaterialRenderer::setVertexShaderConstant(const c8* name, const f32* floats, int count)
496
return setPixelShaderConstant(name, floats, count);
500
void COpenGLSLMaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
502
os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING);
505
bool COpenGLSLMaterialRenderer::setPixelShaderConstant(const c8* name, const f32* floats, int count)
508
const u32 num = UniformInfo.size();
510
for (i=0; i < num; ++i)
512
if (UniformInfo[i].name == name)
519
#if defined(GL_VERSION_2_0)||defined(GL_ARB_shader_objects)
522
Location=Driver->extGlGetUniformLocation(Program2,name);
524
Location=Driver->extGlGetUniformLocationARB(Program,name);
526
switch (UniformInfo[i].type)
529
Driver->extGlUniform1fv(Location, count, floats);
531
case GL_FLOAT_VEC2_ARB:
532
Driver->extGlUniform2fv(Location, count/2, floats);
534
case GL_FLOAT_VEC3_ARB:
535
Driver->extGlUniform3fv(Location, count/3, floats);
537
case GL_FLOAT_VEC4_ARB:
538
Driver->extGlUniform4fv(Location, count/4, floats);
540
case GL_FLOAT_MAT2_ARB:
541
Driver->extGlUniformMatrix2fv(Location, count/4, false, floats);
543
case GL_FLOAT_MAT3_ARB:
544
Driver->extGlUniformMatrix3fv(Location, count/9, false, floats);
546
case GL_FLOAT_MAT4_ARB:
547
Driver->extGlUniformMatrix4fv(Location, count/16, false, floats);
550
Driver->extGlUniform1iv(Location, count, reinterpret_cast<const GLint*>(floats));
560
void COpenGLSLMaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
562
os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING);
565
IVideoDriver* COpenGLSLMaterialRenderer::getVideoDriver()
570
} // end namespace video
571
} // end namespace irr