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
#include "IrrCompileConfig.h"
6
#ifdef _IRR_COMPILE_WITH_OPENGL_
8
#include "COpenGLShaderMaterialRenderer.h"
9
#include "IGPUProgrammingServices.h"
10
#include "IShaderConstantSetCallBack.h"
11
#include "IVideoDriver.h"
13
#include "COpenGLDriver.h"
22
COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(video::COpenGLDriver* driver,
23
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
24
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData)
25
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
26
VertexShader(0), UserData(userData)
29
setDebugName("COpenGLShaderMaterialRenderer");
32
PixelShader.set_used(4);
33
for (u32 i=0; i<4; ++i)
44
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, EVT_STANDARD);
48
//! constructor only for use by derived classes who want to
49
//! create a fall back material for example.
50
COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(COpenGLDriver* driver,
51
IShaderConstantSetCallBack* callback,
52
IMaterialRenderer* baseMaterial, s32 userData)
53
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
54
VertexShader(0), UserData(userData)
56
PixelShader.set_used(4);
57
for (u32 i=0; i<4; ++i)
71
COpenGLShaderMaterialRenderer::~COpenGLShaderMaterialRenderer()
77
Driver->extGlDeletePrograms(1, &VertexShader);
79
for (u32 i=0; i<PixelShader.size(); ++i)
81
Driver->extGlDeletePrograms(1, &PixelShader[i]);
88
void COpenGLShaderMaterialRenderer::init(s32& outMaterialTypeNr,
89
const c8* vertexShaderProgram, const c8* pixelShaderProgram,
92
outMaterialTypeNr = -1;
96
// create vertex shader
97
success=createVertexShader(vertexShaderProgram);
99
// create pixel shader
100
if (!createPixelShader(pixelShaderProgram) || !success)
103
// register as a new material
104
outMaterialTypeNr = Driver->addMaterialRenderer(this);
108
bool COpenGLShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
110
// call callback to set shader constants
111
if (CallBack && (VertexShader || PixelShader[0]))
112
CallBack->OnSetConstants(service, UserData);
118
void COpenGLShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial,
119
bool resetAllRenderstates, video::IMaterialRendererServices* services)
121
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
125
// set new vertex shader
126
#ifdef GL_ARB_vertex_program
127
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader);
128
glEnable(GL_VERTEX_PROGRAM_ARB);
129
#elif defined(GL_NV_vertex_program)
130
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_NV, VertexShader);
131
glEnable(GL_VERTEX_PROGRAM_NV);
135
// set new pixel shader
138
GLuint nextShader=PixelShader[0];
139
if (material.FogEnable)
142
glGetIntegerv(GL_FOG_MODE, &curFogMode);
143
// if (Driver->LinearFog && PixelShader[1])
144
if (curFogMode==GL_LINEAR && PixelShader[1])
145
nextShader=PixelShader[1];
146
// else if (!Driver->LinearFog && PixelShader[2])
147
else if (curFogMode==GL_EXP && PixelShader[2])
148
nextShader=PixelShader[2];
149
else if (curFogMode==GL_EXP2 && PixelShader[3])
150
nextShader=PixelShader[3];
152
#ifdef GL_ARB_fragment_program
153
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, nextShader);
154
glEnable(GL_FRAGMENT_PROGRAM_ARB);
155
#elif defined(GL_NV_fragment_program)
156
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_NV, nextShader);
157
glEnable(GL_FRAGMENT_PROGRAM_NV);
162
BaseMaterial->OnSetMaterial(material, material, true, services);
165
//let callback know used material
167
CallBack->OnSetMaterial(material);
169
for (u32 i=0; i<MATERIAL_MAX_TEXTURES; ++i)
170
Driver->setActiveTexture(i, material.getTexture(i));
171
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
175
void COpenGLShaderMaterialRenderer::OnUnsetMaterial()
177
// disable vertex shader
178
#ifdef GL_ARB_vertex_program
180
glDisable(GL_VERTEX_PROGRAM_ARB);
181
#elif defined(GL_NV_vertex_program)
183
glDisable(GL_VERTEX_PROGRAM_NV);
186
#ifdef GL_ARB_fragment_program
188
glDisable(GL_FRAGMENT_PROGRAM_ARB);
189
#elif defined(GL_NV_fragment_program)
191
glDisable(GL_FRAGMENT_PROGRAM_NV);
195
BaseMaterial->OnUnsetMaterial();
199
//! Returns if the material is transparent.
200
bool COpenGLShaderMaterialRenderer::isTransparent() const
202
return BaseMaterial ? BaseMaterial->isTransparent() : false;
206
// This method needs a properly cleaned error state before the checked instruction is called
207
bool COpenGLShaderMaterialRenderer::checkError(const irr::c8* type)
209
#if defined(GL_ARB_vertex_program) || defined(GL_NV_vertex_program) || defined(GL_ARB_fragment_program) || defined(GL_NV_fragment_program)
210
GLenum g = glGetError();
211
if (g == GL_NO_ERROR)
214
core::stringc errString = type;
215
errString += " compilation failed";
217
errString += " at position ";
219
#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
220
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
222
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos );
224
errString += core::stringc(s32(errPos));
226
#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
227
errString += reinterpret_cast<const char*>(glGetString(GL_PROGRAM_ERROR_STRING_ARB));
229
errString += reinterpret_cast<const char*>(glGetString(GL_PROGRAM_ERROR_STRING_NV));
232
core::stringc errString("Shaders not supported.");
234
os::Printer::log(errString.c_str(), ELL_ERROR);
239
bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh)
244
const core::stringc inshdr(pxsh);
246
const s32 pos = inshdr.find("#_IRR_FOG_MODE_");
247
const u32 numShaders = (-1 != pos)?4:1;
249
for (u32 i=0; i<numShaders; ++i)
257
shdr = inshdr.subString(0, pos);
259
case 1: shdr += "OPTION ARB_fog_linear;"; break;
260
case 2: shdr += "OPTION ARB_fog_exp;"; break;
261
case 3: shdr += "OPTION ARB_fog_exp2;"; break;
263
shdr += inshdr.subString(pos+16, inshdr.size()-pos-16);
265
Driver->extGlGenPrograms(1, &PixelShader[i]);
266
#ifdef GL_ARB_fragment_program
267
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[i]);
268
#elif defined GL_NV_fragment_program
269
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_NV, PixelShader[i]);
272
// clear error buffer
273
while(glGetError() != GL_NO_ERROR)
276
#ifdef GL_ARB_fragment_program
278
Driver->extGlProgramString(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
279
shdr.size(), shdr.c_str());
280
#elif defined GL_NV_fragment_program
281
Driver->extGlLoadProgram(GL_FRAGMENT_PROGRAM_NV, PixelShader[i],
282
shdr.size(), shdr.c_str());
285
if (checkError("Pixel shader"))
287
Driver->extGlDeletePrograms(1, &PixelShader[i]);
298
bool COpenGLShaderMaterialRenderer::createVertexShader(const c8* vtxsh)
303
Driver->extGlGenPrograms(1, &VertexShader);
304
#ifdef GL_ARB_vertex_program
305
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader);
306
#elif defined GL_NV_vertex_program
307
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_NV, VertexShader);
310
// clear error buffer
311
while(glGetError() != GL_NO_ERROR)
315
#ifdef GL_ARB_vertex_program
316
Driver->extGlProgramString(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
317
(GLsizei)strlen(vtxsh), vtxsh);
318
#elif defined GL_NV_vertex_program
319
Driver->extGlLoadProgram(GL_VERTEX_PROGRAM_NV, VertexShader,
320
(GLsizei)strlen(vtxsh), vtxsh);
323
if (checkError("Vertex shader"))
325
Driver->extGlDeletePrograms(1, &VertexShader);
335
} // end namespace video
336
} // end namespace irr