239 lines
5.9 KiB
C++
239 lines
5.9 KiB
C++
// Copyright (C) 2002-2007 Nikolaus Gebhardt
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#include "IrrCompileConfig.h"
|
|
#ifdef _IRR_COMPILE_WITH_OPENGL_
|
|
|
|
#include "COpenGLShaderMaterialRenderer.h"
|
|
#include "IGPUProgrammingServices.h"
|
|
#include "IShaderConstantSetCallBack.h"
|
|
#include "IVideoDriver.h"
|
|
#include "os.h"
|
|
#include "COpenGLDriver.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace video
|
|
{
|
|
|
|
|
|
//! Constructor
|
|
COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(video::COpenGLDriver* driver,
|
|
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
|
|
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData)
|
|
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
|
|
VertexShader(0), PixelShader(0), UserData(userData)
|
|
{
|
|
if (BaseMaterial)
|
|
BaseMaterial->grab();
|
|
|
|
if (CallBack)
|
|
CallBack->grab();
|
|
|
|
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, EVT_STANDARD);
|
|
}
|
|
|
|
|
|
//! constructor only for use by derived classes who want to
|
|
//! create a fall back material for example.
|
|
COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(COpenGLDriver* driver,
|
|
IShaderConstantSetCallBack* callback,
|
|
IMaterialRenderer* baseMaterial, s32 userData)
|
|
: Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
|
|
VertexShader(0), PixelShader(0), UserData(userData)
|
|
{
|
|
if (BaseMaterial)
|
|
BaseMaterial->grab();
|
|
|
|
if (CallBack)
|
|
CallBack->grab();
|
|
}
|
|
|
|
|
|
//! Destructor
|
|
COpenGLShaderMaterialRenderer::~COpenGLShaderMaterialRenderer()
|
|
{
|
|
if (CallBack)
|
|
CallBack->drop();
|
|
|
|
if (VertexShader)
|
|
Driver->extGlDeletePrograms(1, &VertexShader);
|
|
|
|
if (PixelShader)
|
|
Driver->extGlDeletePrograms(1, &PixelShader);
|
|
|
|
if (BaseMaterial)
|
|
BaseMaterial->drop ();
|
|
}
|
|
|
|
void COpenGLShaderMaterialRenderer::init(s32& outMaterialTypeNr, const c8* vertexShaderProgram,
|
|
const c8* pixelShaderProgram, E_VERTEX_TYPE type)
|
|
{
|
|
outMaterialTypeNr = -1;
|
|
|
|
// create vertex shader
|
|
if (!createVertexShader(vertexShaderProgram))
|
|
return;
|
|
|
|
// create pixel shader
|
|
if (!createPixelShader(pixelShaderProgram))
|
|
return;
|
|
|
|
// register myself as new material
|
|
outMaterialTypeNr = Driver->addMaterialRenderer(this);
|
|
}
|
|
|
|
bool COpenGLShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
|
|
{
|
|
// call callback to set shader constants
|
|
if (CallBack && (VertexShader || PixelShader))
|
|
CallBack->OnSetConstants(service, UserData);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void COpenGLShaderMaterialRenderer::OnSetMaterial(video::SMaterial& material, const video::SMaterial& lastMaterial,
|
|
bool resetAllRenderstates, video::IMaterialRendererServices* services)
|
|
{
|
|
Driver->setTexture(3, material.Textures[3]);
|
|
Driver->setTexture(2, material.Textures[2]);
|
|
Driver->setTexture(1, material.Textures[1]);
|
|
Driver->setTexture(0, material.Textures[0]);
|
|
|
|
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
|
|
|
|
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
|
|
{
|
|
#ifdef GL_ARB_vertex_program
|
|
if (VertexShader)
|
|
{
|
|
// set new vertex shader
|
|
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader);
|
|
glEnable(GL_VERTEX_PROGRAM_ARB);
|
|
}
|
|
#endif
|
|
|
|
// set new pixel shader
|
|
#ifdef GL_ARB_fragment_program
|
|
if (PixelShader)
|
|
{
|
|
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader);
|
|
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
}
|
|
#endif
|
|
|
|
if (BaseMaterial)
|
|
BaseMaterial->OnSetMaterial(material, material, true, services);
|
|
}
|
|
}
|
|
|
|
|
|
void COpenGLShaderMaterialRenderer::OnUnsetMaterial()
|
|
{
|
|
// disable vertex shader
|
|
#ifdef GL_ARB_vertex_program
|
|
if (VertexShader)
|
|
glDisable(GL_VERTEX_PROGRAM_ARB);
|
|
#endif
|
|
|
|
#ifdef GL_ARB_fragment_program
|
|
if (PixelShader)
|
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
#endif
|
|
|
|
if (BaseMaterial)
|
|
BaseMaterial->OnUnsetMaterial();
|
|
}
|
|
|
|
//! Returns if the material is transparent.
|
|
bool COpenGLShaderMaterialRenderer::isTransparent()
|
|
{
|
|
return BaseMaterial ? BaseMaterial->isTransparent() : false;
|
|
}
|
|
|
|
bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh)
|
|
{
|
|
if (!pxsh)
|
|
return true;
|
|
|
|
Driver->extGlGenPrograms(1, &PixelShader);
|
|
#ifdef GL_ARB_fragment_program
|
|
Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader);
|
|
|
|
// clear error buffer
|
|
while(glGetError() != GL_NO_ERROR) {}
|
|
|
|
// compile
|
|
Driver->extGlProgramString(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
|
strlen(pxsh), pxsh);
|
|
#endif
|
|
|
|
#ifdef GL_ARB_vertex_program
|
|
GLenum g = glGetError();
|
|
if (g != GL_NO_ERROR)
|
|
{
|
|
GLint errPos;
|
|
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
|
|
|
|
const GLubyte* errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
|
|
|
char tmp[2048];
|
|
sprintf(tmp, "Pixel shader compilation failed at position %d:\n%s", errPos, errString);
|
|
os::Printer::log(tmp);
|
|
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool COpenGLShaderMaterialRenderer::createVertexShader(const char* vtxsh)
|
|
{
|
|
if (!vtxsh)
|
|
return true;
|
|
|
|
#ifdef GL_ARB_vertex_program
|
|
Driver->extGlGenPrograms(1, &VertexShader);
|
|
Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader);
|
|
|
|
// clear error buffer
|
|
while(glGetError() != GL_NO_ERROR) {}
|
|
|
|
// compile
|
|
Driver->extGlProgramString(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
|
|
strlen(vtxsh), vtxsh);
|
|
|
|
GLenum g = glGetError();
|
|
if (g != GL_NO_ERROR)
|
|
{
|
|
GLint errPos;
|
|
glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
|
|
|
|
const GLubyte* errString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
|
|
|
char tmp[2048];
|
|
sprintf(tmp, "Vertex shader compilation failed at position %d:\n%s", errPos, errString);
|
|
os::Printer::log(tmp);
|
|
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
} // end namespace video
|
|
} // end namespace irr
|
|
|
|
|
|
#endif
|
|
|