irrlicht/source/Irrlicht/IBurningShader.cpp

402 lines
9.8 KiB
C++

// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// 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_BURNINGSVIDEO_
#include "SoftwareDriver2_compile_config.h"
#include "IBurningShader.h"
#include "CSoftwareDriver2.h"
#include "IShaderConstantSetCallBack.h"
namespace irr
{
namespace video
{
const tFixPointu IBurningShader::dithermask[] =
{
0x00,0x80,0x20,0xa0,
0xc0,0x40,0xe0,0x60,
0x30,0xb0,0x10,0x90,
0xf0,0x70,0xd0,0x50
};
void IBurningShader::constructor_IBurningShader(CBurningVideoDriver* driver)
{
#ifdef _DEBUG
setDebugName("IBurningShader");
#endif
EdgeTestPass = edge_test_pass;
EdgeTestPass_stack = edge_test_pass;
for ( u32 i = 0; i < BURNING_MATERIAL_MAX_TEXTURES; ++i )
{
IT[i].Texture = 0;
}
Driver = driver;
CallBack = 0;
RenderTarget = 0;
ColorMask = COLOR_BRIGHT_WHITE;
DepthBuffer = (CDepthBuffer*) driver->getDepthBuffer ();
if ( DepthBuffer )
DepthBuffer->grab();
Stencil = (CStencilBuffer*) driver->getStencilBuffer ();
if ( Stencil )
Stencil->grab();
stencilOp[0] = StencilOp_KEEP;
stencilOp[1] = StencilOp_KEEP;
stencilOp[2] = StencilOp_KEEP;
AlphaRef = 0;
RenderPass_ShaderIsTransparent = 0;
PrimitiveColor = COLOR_BRIGHT_WHITE;
TL_Flag = 0;
}
IBurningShader::IBurningShader(CBurningVideoDriver* driver)
{
constructor_IBurningShader(driver);
}
//! Constructor
IBurningShader::IBurningShader(
CBurningVideoDriver* driver,
s32& outMaterialTypeNr,
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
const c8* geometryShaderProgram ,
const c8* geometryShaderEntryPointName,
E_GEOMETRY_SHADER_TYPE gsCompileTarget,
scene::E_PRIMITIVE_TYPE inType,
scene::E_PRIMITIVE_TYPE outType,
u32 verticesOut,
IShaderConstantSetCallBack* callback,
E_MATERIAL_TYPE baseMaterial,
s32 userData)
{
constructor_IBurningShader(driver);
BaseMaterial = baseMaterial;
CallBack = callback;
if (CallBack)
CallBack->grab();
// register myself as new material
outMaterialTypeNr = Driver->addMaterialRenderer(this);
}
//! destructor
IBurningShader::~IBurningShader()
{
if (RenderTarget)
RenderTarget->drop();
if (DepthBuffer)
DepthBuffer->drop();
if (Stencil)
Stencil->drop();
for ( u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i )
{
if ( IT[i].Texture )
IT[i].Texture->drop();
}
if (CallBack)
CallBack->drop();
}
//! sets a render target
void IBurningShader::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort)
{
if (RenderTarget)
RenderTarget->drop();
RenderTarget = (video::CImage* ) surface;
if (RenderTarget)
{
RenderTarget->grab();
//(fp24*) DepthBuffer->lock() = DepthBuffer->lock();
}
}
//! sets the Texture
void IBurningShader::setTextureParam( const size_t stage, video::CSoftwareTexture2* texture, s32 lodFactor)
{
sInternalTexture *it = &IT[stage];
if ( it->Texture)
it->Texture->drop();
it->Texture = texture;
if ( it->Texture)
{
it->Texture->grab();
// select mignify and magnify
it->lodFactor = lodFactor;
//only mipmap chain (means positive lodFactor)
u32 existing_level = it->Texture->getMipmapLevel(lodFactor);
it->data = (tVideoSample*) it->Texture->lock(ETLM_READ_ONLY, existing_level, 0);
// prepare for optimal fixpoint
it->pitchlog2 = s32_log2_s32 ( it->Texture->getPitch() );
const core::dimension2d<u32> &dim = it->Texture->getSize();
it->textureXMask = s32_to_fixPoint ( dim.Width - 1 ) & FIX_POINT_UNSIGNED_MASK;
it->textureYMask = s32_to_fixPoint ( dim.Height - 1 ) & FIX_POINT_UNSIGNED_MASK;
}
}
//emulate a line with degenerate triangle and special shader mode (not perfect...)
void IBurningShader::drawLine ( const s4DVertex *a,const s4DVertex *b)
{
sVec2 d;
d.x = b->Pos.x - a->Pos.x; d.x *= d.x;
d.y = b->Pos.y - a->Pos.y; d.y *= d.y;
//if ( d.x * d.y < 0.001f ) return;
if ( a->Pos.x > b->Pos.x ) swapVertexPointer(&a, &b);
s4DVertex c = *a;
const f32 w = (f32)RenderTarget->getDimension().Width-1;
const f32 h = (f32)RenderTarget->getDimension().Height-1;
if ( d.x < 2.f ) { c.Pos.x = b->Pos.x + 1.f + d.y; if ( c.Pos.x > w ) c.Pos.x = w; }
else c.Pos.x = b->Pos.x;
if ( d.y < 2.f ) { c.Pos.y = b->Pos.y + 1.f; if ( c.Pos.y > h ) c.Pos.y = h; EdgeTestPass |= edge_test_first_line; }
drawTriangle ( a,b,&c );
EdgeTestPass &= ~edge_test_first_line;
}
void IBurningShader::drawPoint(const s4DVertex *a)
{
}
void IBurningShader::drawWireFrameTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c )
{
if ( EdgeTestPass & edge_test_pass ) drawTriangle(a, b, c);
else if (EdgeTestPass & edge_test_point)
{
drawPoint(a);
drawPoint(b);
drawPoint(c);
}
else
{
drawLine(a, b);
drawLine(b, c);
drawLine(a, c);
}
}
void IBurningShader::OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services)
{
if (Driver)
Driver->setFallback_Material(BaseMaterial);
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (CallBack)
CallBack->OnSetMaterial(material);
}
void IBurningShader::OnUnsetMaterial()
{
}
bool IBurningShader::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
// call callback to set shader constants
if (CallBack)
CallBack->OnSetConstants(this, UserData);
return true;
}
//! Returns if the material is transparent.
bool IBurningShader::isTransparent() const
{
return RenderPass_ShaderIsTransparent != 0;
}
//! Access the callback provided by the users when creating shader materials
IShaderConstantSetCallBack* IBurningShader::getShaderConstantSetCallBack() const
{
return CallBack;
}
// implementations for the render services
void IBurningShader::setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates)
{
// forward
Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
}
s32 IBurningShader::getShaderConstantID(EBurningUniformFlags flags,const c8* name)
{
if (!name || !name[0])
return -1;
BurningUniform add;
tiny_strcpy(add.name, name);
add.type = flags;
s32 index = UniformInfo.linear_search(add);
if (index < 0)
{
UniformInfo.push_back(add);
index = UniformInfo.size() - 1;
}
return index;
}
const char* tiny_itoa(s32 value, int base)
{
static char b[32];
int p = 31;
//int sign = 0;
//if (value < 0) { sign = 1; value = -value; }
b[p] = '\0';
do {
b[--p] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[value%base];
value /= base;
} while (value && p > 0);
//if (sign && p > 0) { b[--p] = '-'; }
return b + p;
}
bool IBurningShader::setShaderConstantID(EBurningUniformFlags flags, s32 index, const void* data, size_t u32_count)
{
if ((u32)index >= UniformInfo.size())
return false;
#if 0
BurningUniform add;
while ((u32)index >= UniformInfo.size())
{
tiny_strcpy(add.name, tiny_itoa(UniformInfo.size(),10));
add.type = flags;
UniformInfo.push_back(add);
}
#endif
BurningUniform& use = UniformInfo[index];
use.type = flags;
const u32* s = (u32*)data;
u32* d = (u32*)use.data;
if (!s) u32_count = 0;
if (u32_count > array_size(use.data)) u32_count = array_size(use.data);
for (size_t i = 0; i < u32_count; ++i)
{
d[i] = s[i];
}
return true;
}
s32 IBurningShader::getVertexShaderConstantID(const c8* name)
{
return getShaderConstantID(BL_VERTEX_PROGRAM, name);
}
s32 IBurningShader::getPixelShaderConstantID(const c8* name)
{
return getShaderConstantID(BL_FRAGMENT_PROGRAM, name);
}
void IBurningShader::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
{
c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
tiny_strcpy(name, tiny_itoa(startRegister, 10));
setShaderConstantID(BL_VERTEX_FLOAT, getShaderConstantID(BL_VERTEX_PROGRAM,name), data, constantAmount);
}
void IBurningShader::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
{
c8 name[BL_ACTIVE_UNIFORM_MAX_LENGTH];
tiny_strcpy(name, tiny_itoa(startRegister, 10));
setShaderConstantID(BL_FRAGMENT_FLOAT, getShaderConstantID(BL_FRAGMENT_PROGRAM, name), data, constantAmount);
}
bool IBurningShader::setVertexShaderConstant(s32 index, const f32* floats, int count)
{
return setShaderConstantID(BL_VERTEX_FLOAT, index, floats, count);
}
bool IBurningShader::setVertexShaderConstant(s32 index, const s32* ints, int count)
{
return setShaderConstantID(BL_VERTEX_INT, index, ints, count);
}
bool IBurningShader::setVertexShaderConstant(s32 index, const u32* ints, int count)
{
return setShaderConstantID(BL_VERTEX_UINT, index, ints, count);
}
bool IBurningShader::setPixelShaderConstant(s32 index, const f32* floats, int count)
{
return setShaderConstantID(BL_FRAGMENT_FLOAT, index, floats, count);
}
bool IBurningShader::setPixelShaderConstant(s32 index, const s32* ints, int count)
{
return setShaderConstantID(BL_FRAGMENT_INT, index, ints, count);
}
bool IBurningShader::setPixelShaderConstant(s32 index, const u32* ints, int count)
{
return setShaderConstantID(BL_FRAGMENT_UINT, index, ints, count);
}
void IBurningShader::setStencilOp(eBurningStencilOp sfail, eBurningStencilOp dpfail, eBurningStencilOp dppass)
{
stencilOp[0] = sfail;
stencilOp[1] = dpfail;
stencilOp[2] = dppass;
}
IVideoDriver* IBurningShader::getVideoDriver()
{
return Driver;
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_