aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp')
-rw-r--r--libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp693
1 files changed, 693 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp
new file mode 100644
index 0000000..af47c0e
--- /dev/null
+++ b/libraries/irrlicht-1.8.1/source/Irrlicht/COpenGLSLMaterialRenderer.cpp
@@ -0,0 +1,693 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
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.
9
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.
12
13#include "IrrCompileConfig.h"
14#ifdef _IRR_COMPILE_WITH_OPENGL_
15
16#include "COpenGLSLMaterialRenderer.h"
17#include "IGPUProgrammingServices.h"
18#include "IShaderConstantSetCallBack.h"
19#include "IMaterialRendererServices.h"
20#include "IVideoDriver.h"
21#include "os.h"
22#include "COpenGLDriver.h"
23
24namespace irr
25{
26namespace video
27{
28
29
30//! Constructor
31COpenGLSLMaterialRenderer::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,
42 u32 verticesOut,
43 IShaderConstantSetCallBack* callback,
44 video::IMaterialRenderer* baseMaterial,
45 s32 userData)
46 : Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
47 Program(0), Program2(0), UserData(userData)
48{
49 #ifdef _DEBUG
50 setDebugName("COpenGLSLMaterialRenderer");
51 #endif
52
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
56
57 if (BaseMaterial)
58 BaseMaterial->grab();
59
60 if (CallBack)
61 CallBack->grab();
62
63 if (!Driver->queryFeature(EVDF_ARB_GLSL))
64 return;
65
66 init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, geometryShaderProgram);
67}
68
69
70//! constructor only for use by derived classes who want to
71//! create a fall back material for example.
72COpenGLSLMaterialRenderer::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)
77{
78 if (BaseMaterial)
79 BaseMaterial->grab();
80
81 if (CallBack)
82 CallBack->grab();
83}
84
85
86//! Destructor
87COpenGLSLMaterialRenderer::~COpenGLSLMaterialRenderer()
88{
89 if (CallBack)
90 CallBack->drop();
91
92 if (Program)
93 {
94 GLhandleARB shaders[8];
95 GLint count;
96 Driver->extGlGetAttachedObjects(Program, 8, &count, shaders);
97 // avoid bugs in some drivers, which return larger numbers
98 count=core::min_(count,8);
99 for (GLint i=0; i<count; ++i)
100 Driver->extGlDeleteObject(shaders[i]);
101 Driver->extGlDeleteObject(Program);
102 Program = 0;
103 }
104
105 if (Program2)
106 {
107 GLuint shaders[8];
108 GLint count;
109 Driver->extGlGetAttachedShaders(Program2, 8, &count, shaders);
110 // avoid bugs in some drivers, which return larger numbers
111 count=core::min_(count,8);
112 for (GLint i=0; i<count; ++i)
113 Driver->extGlDeleteShader(shaders[i]);
114 Driver->extGlDeleteProgram(Program2);
115 Program2 = 0;
116 }
117
118 UniformInfo.clear();
119
120 if (BaseMaterial)
121 BaseMaterial->drop();
122}
123
124
125void COpenGLSLMaterialRenderer::init(s32& outMaterialTypeNr,
126 const c8* vertexShaderProgram,
127 const c8* pixelShaderProgram,
128 const c8* geometryShaderProgram,
129 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
130 u32 verticesOut)
131{
132 outMaterialTypeNr = -1;
133
134 if (!createProgram())
135 return;
136
137#if defined(GL_ARB_vertex_shader) && defined (GL_ARB_fragment_shader)
138 if (vertexShaderProgram)
139 if (!createShader(GL_VERTEX_SHADER_ARB, vertexShaderProgram))
140 return;
141
142 if (pixelShaderProgram)
143 if (!createShader(GL_FRAGMENT_SHADER_ARB, pixelShaderProgram))
144 return;
145#endif
146
147#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_program4) || defined(GL_NV_geometry_shader4)
148 if (geometryShaderProgram && Driver->queryFeature(EVDF_GEOMETRY_SHADER))
149 {
150 if (!createShader(GL_GEOMETRY_SHADER_EXT, geometryShaderProgram))
151 return;
152#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4)
153 if (Program2) // Geometry shaders are supported only in OGL2.x+ drivers.
154 {
155 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_INPUT_TYPE_EXT, Driver->primitiveTypeToGL(inType));
156 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_OUTPUT_TYPE_EXT, Driver->primitiveTypeToGL(outType));
157 if (verticesOut==0)
158 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, Driver->MaxGeometryVerticesOut);
159 else
160 Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
161 }
162#elif defined(GL_NV_geometry_program4)
163 if (verticesOut==0)
164 Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, Driver->MaxGeometryVerticesOut);
165 else
166 Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, core::min_(verticesOut, Driver->MaxGeometryVerticesOut));
167#endif
168 }
169#endif
170
171 if (!linkProgram())
172 return;
173
174 // register myself as new material
175 outMaterialTypeNr = Driver->addMaterialRenderer(this);
176}
177
178
179bool COpenGLSLMaterialRenderer::OnRender(IMaterialRendererServices* service,
180 E_VERTEX_TYPE vtxtype)
181{
182 // call callback to set shader constants
183 if (CallBack && (Program||Program2))
184 CallBack->OnSetConstants(this, UserData);
185
186 return true;
187}
188
189
190void COpenGLSLMaterialRenderer::OnSetMaterial(const video::SMaterial& material,
191 const video::SMaterial& lastMaterial,
192 bool resetAllRenderstates,
193 video::IMaterialRendererServices* services)
194{
195 if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
196 {
197 if (Program2)
198 Driver->extGlUseProgram(Program2);
199 else if (Program)
200 Driver->extGlUseProgramObject(Program);
201
202 if (BaseMaterial)
203 BaseMaterial->OnSetMaterial(material, material, true, this);
204 }
205
206 //let callback know used material
207 if (CallBack)
208 CallBack->OnSetMaterial(material);
209
210 for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i)
211 Driver->setActiveTexture(i, material.getTexture(i));
212 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
213}
214
215
216void COpenGLSLMaterialRenderer::OnUnsetMaterial()
217{
218 if (Program)
219 Driver->extGlUseProgramObject(0);
220 if (Program2)
221 Driver->extGlUseProgram(0);
222
223 if (BaseMaterial)
224 BaseMaterial->OnUnsetMaterial();
225}
226
227
228//! Returns if the material is transparent.
229bool COpenGLSLMaterialRenderer::isTransparent() const
230{
231 return BaseMaterial ? BaseMaterial->isTransparent() : false;
232}
233
234
235bool COpenGLSLMaterialRenderer::createProgram()
236{
237 if (Driver->Version>=200)
238 Program2 = Driver->extGlCreateProgram();
239 else
240 Program = Driver->extGlCreateProgramObject();
241 return true;
242}
243
244
245bool COpenGLSLMaterialRenderer::createShader(GLenum shaderType, const char* shader)
246{
247 if (Program2)
248 {
249 GLuint shaderHandle = Driver->extGlCreateShader(shaderType);
250 Driver->extGlShaderSource(shaderHandle, 1, &shader, NULL);
251 Driver->extGlCompileShader(shaderHandle);
252
253 GLint status = 0;
254
255#ifdef GL_VERSION_2_0
256 Driver->extGlGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
257#endif
258
259 if (status != GL_TRUE)
260 {
261 os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
262 // check error message and log it
263 GLint maxLength=0;
264 GLint length;
265#ifdef GL_VERSION_2_0
266 Driver->extGlGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH,
267 &maxLength);
268#endif
269 if (maxLength)
270 {
271 GLchar *infoLog = new GLchar[maxLength];
272 Driver->extGlGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog);
273 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
274 delete [] infoLog;
275 }
276
277 return false;
278 }
279
280 Driver->extGlAttachShader(Program2, shaderHandle);
281 }
282 else
283 {
284 GLhandleARB shaderHandle = Driver->extGlCreateShaderObject(shaderType);
285
286 Driver->extGlShaderSourceARB(shaderHandle, 1, &shader, NULL);
287 Driver->extGlCompileShaderARB(shaderHandle);
288
289 GLint status = 0;
290
291#ifdef GL_ARB_shader_objects
292 Driver->extGlGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status);
293#endif
294
295 if (!status)
296 {
297 os::Printer::log("GLSL shader failed to compile", ELL_ERROR);
298 // check error message and log it
299 GLint maxLength=0;
300 GLsizei length;
301#ifdef GL_ARB_shader_objects
302 Driver->extGlGetObjectParameteriv(shaderHandle,
303 GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
304#endif
305 if (maxLength)
306 {
307 GLcharARB *infoLog = new GLcharARB[maxLength];
308 Driver->extGlGetInfoLog(shaderHandle, maxLength, &length, infoLog);
309 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
310 delete [] infoLog;
311 }
312
313 return false;
314 }
315
316 Driver->extGlAttachObject(Program, shaderHandle);
317 }
318 return true;
319}
320
321
322bool COpenGLSLMaterialRenderer::linkProgram()
323{
324 if (Program2)
325 {
326 Driver->extGlLinkProgram(Program2);
327
328 GLint status = 0;
329
330#ifdef GL_VERSION_2_0
331 Driver->extGlGetProgramiv(Program2, GL_LINK_STATUS, &status);
332#endif
333
334 if (!status)
335 {
336 os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
337 // check error message and log it
338 GLint maxLength=0;
339 GLsizei length;
340#ifdef GL_VERSION_2_0
341 Driver->extGlGetProgramiv(Program2, GL_INFO_LOG_LENGTH, &maxLength);
342#endif
343 if (maxLength)
344 {
345 GLchar *infoLog = new GLchar[maxLength];
346 Driver->extGlGetProgramInfoLog(Program2, maxLength, &length, infoLog);
347 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
348 delete [] infoLog;
349 }
350
351 return false;
352 }
353
354 // get uniforms information
355
356 GLint num = 0;
357#ifdef GL_VERSION_2_0
358 Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORMS, &num);
359#endif
360
361 if (num == 0)
362 {
363 // no uniforms
364 return true;
365 }
366
367 GLint maxlen = 0;
368#ifdef GL_VERSION_2_0
369 Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen);
370#endif
371
372 if (maxlen == 0)
373 {
374 os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
375 return false;
376 }
377
378 // seems that some implementations use an extra null terminator
379 ++maxlen;
380 c8 *buf = new c8[maxlen];
381
382 UniformInfo.clear();
383 UniformInfo.reallocate(num);
384
385 for (GLint i=0; i < num; ++i)
386 {
387 SUniformInfo ui;
388 memset(buf, 0, maxlen);
389
390 GLint size;
391 Driver->extGlGetActiveUniform(Program2, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLchar*>(buf));
392 ui.name = buf;
393
394 UniformInfo.push_back(ui);
395 }
396
397 delete [] buf;
398 }
399 else
400 {
401 Driver->extGlLinkProgramARB(Program);
402
403 GLint status = 0;
404
405#ifdef GL_ARB_shader_objects
406 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_LINK_STATUS_ARB, &status);
407#endif
408
409 if (!status)
410 {
411 os::Printer::log("GLSL shader program failed to link", ELL_ERROR);
412 // check error message and log it
413 GLint maxLength=0;
414 GLsizei length;
415#ifdef GL_ARB_shader_objects
416 Driver->extGlGetObjectParameteriv(Program,
417 GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
418#endif
419 if (maxLength)
420 {
421 GLcharARB *infoLog = new GLcharARB[maxLength];
422 Driver->extGlGetInfoLog(Program, maxLength, &length, infoLog);
423 os::Printer::log(reinterpret_cast<const c8*>(infoLog), ELL_ERROR);
424 delete [] infoLog;
425 }
426
427 return false;
428 }
429
430 // get uniforms information
431
432 GLint num = 0;
433 #ifdef GL_ARB_shader_objects
434 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &num);
435 #endif
436
437 if (num == 0)
438 {
439 // no uniforms
440 return true;
441 }
442
443 GLint maxlen = 0;
444 #ifdef GL_ARB_shader_objects
445 Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &maxlen);
446 #endif
447
448 if (maxlen == 0)
449 {
450 os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR);
451 return false;
452 }
453
454 // seems that some implementations use an extra null terminator
455 ++maxlen;
456 c8 *buf = new c8[maxlen];
457
458 UniformInfo.clear();
459 UniformInfo.reallocate(num);
460
461 for (int i=0; i < num; ++i)
462 {
463 SUniformInfo ui;
464 memset(buf, 0, maxlen);
465
466 GLint size;
467 Driver->extGlGetActiveUniformARB(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast<GLcharARB*>(buf));
468 ui.name = buf;
469
470 UniformInfo.push_back(ui);
471 }
472
473 delete [] buf;
474 }
475
476 return true;
477}
478
479
480void COpenGLSLMaterialRenderer::setBasicRenderStates(const SMaterial& material,
481 const SMaterial& lastMaterial,
482 bool resetAllRenderstates)
483{
484 // forward
485 Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
486}
487
488
489bool COpenGLSLMaterialRenderer::setVertexShaderConstant(const c8* name, const f32* floats, int count)
490{
491 return setPixelShaderConstant(name, floats, count);
492}
493
494bool COpenGLSLMaterialRenderer::setVertexShaderConstant(const c8* name, const bool* bools, int count)
495{
496 return setPixelShaderConstant(name, bools, count);
497}
498
499bool COpenGLSLMaterialRenderer::setVertexShaderConstant(const c8* name, const s32* ints, int count)
500{
501 return setPixelShaderConstant(name, ints, count);
502}
503
504void COpenGLSLMaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
505{
506 os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING);
507}
508
509bool COpenGLSLMaterialRenderer::setPixelShaderConstant(const c8* name, const f32* floats, int count)
510{
511 u32 i;
512 const u32 num = UniformInfo.size();
513
514 for (i=0; i < num; ++i)
515 {
516 if (UniformInfo[i].name == name)
517 break;
518 }
519
520 if (i == num)
521 return false;
522
523#if defined(GL_VERSION_2_0)||defined(GL_ARB_shader_objects)
524 GLint Location=0;
525 if (Program2)
526 Location=Driver->extGlGetUniformLocation(Program2,name);
527 else
528 Location=Driver->extGlGetUniformLocationARB(Program,name);
529
530 bool status = true;
531
532 switch (UniformInfo[i].type)
533 {
534 case GL_FLOAT:
535 Driver->extGlUniform1fv(Location, count, floats);
536 break;
537 case GL_FLOAT_VEC2:
538 Driver->extGlUniform2fv(Location, count/2, floats);
539 break;
540 case GL_FLOAT_VEC3:
541 Driver->extGlUniform3fv(Location, count/3, floats);
542 break;
543 case GL_FLOAT_VEC4:
544 Driver->extGlUniform4fv(Location, count/4, floats);
545 break;
546 case GL_FLOAT_MAT2:
547 Driver->extGlUniformMatrix2fv(Location, count/4, false, floats);
548 break;
549 case GL_FLOAT_MAT3:
550 Driver->extGlUniformMatrix3fv(Location, count/9, false, floats);
551 break;
552 case GL_FLOAT_MAT4:
553 Driver->extGlUniformMatrix4fv(Location, count/16, false, floats);
554 break;
555 case GL_SAMPLER_1D:
556 case GL_SAMPLER_2D:
557 case GL_SAMPLER_3D:
558 case GL_SAMPLER_CUBE:
559 case GL_SAMPLER_1D_SHADOW:
560 case GL_SAMPLER_2D_SHADOW:
561 {
562 const GLint id = static_cast<GLint>(*floats);
563 Driver->extGlUniform1iv(Location, 1, &id);
564 }
565 break;
566 default:
567 status = false;
568 break;
569 }
570 return status;
571#else
572 return false;
573#endif
574}
575
576bool COpenGLSLMaterialRenderer::setPixelShaderConstant(const c8* name, const bool* bools, int count)
577{
578 u32 i;
579 const u32 num = UniformInfo.size();
580
581 for (i=0; i < num; ++i)
582 {
583 if (UniformInfo[i].name == name)
584 break;
585 }
586
587 if (i == num)
588 return false;
589
590#if defined(GL_VERSION_2_0)||defined(GL_ARB_shader_objects)
591 GLint Location=0;
592 if (Program2)
593 Location=Driver->extGlGetUniformLocation(Program2,name);
594 else
595 Location=Driver->extGlGetUniformLocationARB(Program,name);
596
597 bool status = true;
598
599 switch (UniformInfo[i].type)
600 {
601 case GL_BOOL:
602 Driver->extGlUniform1iv(Location, count, (GLint*)bools);
603 break;
604 case GL_BOOL_VEC2:
605 Driver->extGlUniform2iv(Location, count/2, (GLint*)bools);
606 break;
607 case GL_BOOL_VEC3:
608 Driver->extGlUniform3iv(Location, count/3, (GLint*)bools);
609 break;
610 case GL_BOOL_VEC4:
611 Driver->extGlUniform4iv(Location, count/4, (GLint*)bools);
612 break;
613 default:
614 status = false;
615 break;
616 }
617 return status;
618#else
619 return false;
620#endif
621}
622
623bool COpenGLSLMaterialRenderer::setPixelShaderConstant(const c8* name, const s32* ints, int count)
624{
625 u32 i;
626 const u32 num = UniformInfo.size();
627
628 for (i=0; i < num; ++i)
629 {
630 if (UniformInfo[i].name == name)
631 break;
632 }
633
634 if (i == num)
635 return false;
636
637#if defined(GL_VERSION_2_0)||defined(GL_ARB_shader_objects)
638 GLint Location=0;
639 if (Program2)
640 Location=Driver->extGlGetUniformLocation(Program2,name);
641 else
642 Location=Driver->extGlGetUniformLocationARB(Program,name);
643
644 bool status = true;
645
646 switch (UniformInfo[i].type)
647 {
648 case GL_INT:
649 Driver->extGlUniform1iv(Location, count, ints);
650 break;
651 case GL_INT_VEC2:
652 Driver->extGlUniform2iv(Location, count/2, ints);
653 break;
654 case GL_INT_VEC3:
655 Driver->extGlUniform3iv(Location, count/3, ints);
656 break;
657 case GL_INT_VEC4:
658 Driver->extGlUniform4iv(Location, count/4, ints);
659 break;
660 case GL_SAMPLER_1D:
661 case GL_SAMPLER_2D:
662 case GL_SAMPLER_3D:
663 case GL_SAMPLER_CUBE:
664 case GL_SAMPLER_1D_SHADOW:
665 case GL_SAMPLER_2D_SHADOW:
666 Driver->extGlUniform1iv(Location, 1, ints);
667 break;
668 default:
669 status = false;
670 break;
671 }
672 return status;
673#else
674 return false;
675#endif
676}
677
678void COpenGLSLMaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
679{
680 os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING);
681}
682
683IVideoDriver* COpenGLSLMaterialRenderer::getVideoDriver()
684{
685 return Driver;
686}
687
688} // end namespace video
689} // end namespace irr
690
691
692#endif
693