796 lines
19 KiB
C++
796 lines
19 KiB
C++
// Copyright (C) 2002-2009 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_BSP_LOADER_
|
|
|
|
#include "CQuake3ShaderSceneNode.h"
|
|
#include "ISceneManager.h"
|
|
#include "IVideoDriver.h"
|
|
#include "ICameraSceneNode.h"
|
|
#include "SViewFrustum.h"
|
|
#include "IMeshManipulator.h"
|
|
#include "SMesh.h"
|
|
#include "IMaterialRenderer.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace scene
|
|
{
|
|
|
|
|
|
CQuake3ShaderSceneNode::CQuake3ShaderSceneNode(
|
|
scene::ISceneNode* parent, scene::ISceneManager* mgr,s32 id,
|
|
io::IFileSystem *fileSystem, scene::IMeshBuffer *buffer,
|
|
const quake3::SShader * shader)
|
|
: scene::ISceneNode(parent, mgr, id), MeshBuffer(0), Original(0),
|
|
Shader(shader), TimeAbs(0.f)
|
|
{
|
|
#ifdef _DEBUG
|
|
core::stringc dName = "CQuake3ShaderSceneNode ";
|
|
dName += Shader->name;
|
|
|
|
setDebugName( dName.c_str() );
|
|
#endif
|
|
|
|
MeshBuffer = new SMeshBuffer();
|
|
Original = new SMeshBufferLightMap();
|
|
|
|
// name the Scene Node
|
|
this->Name = Shader->name;
|
|
|
|
// clone meshbuffer to modifiable buffer
|
|
cloneBuffer( static_cast< scene::SMeshBufferLightMap *>( buffer ) );
|
|
|
|
// load all Textures in all stages
|
|
loadTextures( fileSystem );
|
|
|
|
setAutomaticCulling( scene::EAC_BOX );
|
|
}
|
|
|
|
|
|
CQuake3ShaderSceneNode::~CQuake3ShaderSceneNode()
|
|
{
|
|
if (MeshBuffer)
|
|
MeshBuffer->drop();
|
|
if (Original)
|
|
Original->drop();
|
|
}
|
|
|
|
|
|
/*
|
|
create single copies
|
|
*/
|
|
void CQuake3ShaderSceneNode::cloneBuffer( scene::SMeshBufferLightMap * buffer )
|
|
{
|
|
Original->Material = buffer->Material;
|
|
MeshBuffer->Material = buffer->Material;
|
|
|
|
Original->Indices = buffer->Indices;
|
|
MeshBuffer->Indices = buffer->Indices;
|
|
|
|
const u32 vsize = buffer->Vertices.size();
|
|
|
|
Original->Vertices.reallocate( vsize );
|
|
MeshBuffer->Vertices.reallocate( vsize );
|
|
for ( u32 i = 0; i!= vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords& src = buffer->Vertices[i];
|
|
|
|
// Original has same Vertex Format
|
|
Original->Vertices.push_back(src);
|
|
|
|
// we have a different vertex format
|
|
MeshBuffer->Vertices.push_back(src);
|
|
MeshBuffer->Vertices.getLast().Color=0xFFFFFFFF;
|
|
}
|
|
|
|
MeshBuffer->recalculateBoundingBox();
|
|
|
|
#if 1
|
|
// move the (temp) Mesh
|
|
{
|
|
// original bounding box
|
|
const core::aabbox3df& b = MeshBuffer->getBoundingBox();
|
|
|
|
// set Scene Node Position
|
|
setPosition( b.getCenter() );
|
|
|
|
core::matrix4 m;
|
|
m.setTranslation( -b.getCenter() );
|
|
SceneManager->getMeshManipulator()->transform( Original, m );
|
|
SceneManager->getMeshManipulator()->transform( MeshBuffer, m );
|
|
|
|
MeshBuffer->recalculateBoundingBox();
|
|
}
|
|
#endif
|
|
// used for sorting
|
|
MeshBuffer->Material.setTexture(0, (video::ITexture*) Shader);
|
|
}
|
|
|
|
|
|
/*
|
|
load the textures for all stages
|
|
*/
|
|
void CQuake3ShaderSceneNode::loadTextures( io::IFileSystem * fileSystem )
|
|
{
|
|
const quake3::SVarGroup *group;
|
|
u32 i;
|
|
|
|
// clear all stages and prefill empty
|
|
Q3Texture.clear();
|
|
for ( i = 0; i != Shader->VarGroup->VariableGroup.size(); ++i )
|
|
{
|
|
Q3Texture.push_back( SQ3Texture() );
|
|
}
|
|
|
|
u32 pos;
|
|
|
|
// get texture map
|
|
for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i )
|
|
{
|
|
group = Shader->getGroup( i );
|
|
|
|
const core::stringc &mapname = group->get( "map" );
|
|
if ( 0 == mapname.size() )
|
|
continue;
|
|
|
|
// our lightmap is passed in material.Texture[2]
|
|
if ( mapname == "$lightmap" )
|
|
{
|
|
Q3Texture [i].Texture.push_back( Original->getMaterial().getTexture(1) );
|
|
}
|
|
else
|
|
{
|
|
pos = 0;
|
|
quake3::getTextures( Q3Texture [i].Texture, mapname, pos, fileSystem, SceneManager->getVideoDriver() );
|
|
}
|
|
}
|
|
|
|
// get anim map
|
|
for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i )
|
|
{
|
|
if ( Q3Texture [i].Texture.size() )
|
|
continue;
|
|
|
|
group = Shader->getGroup( i );
|
|
|
|
const core::stringc &animmap = group->get( "animmap" );
|
|
if ( 0 == animmap.size() )
|
|
continue;
|
|
|
|
// first parameter is frequency
|
|
pos = 0;
|
|
Q3Texture [i].TextureFrequency = core::max_( 0.0001f, quake3::getAsFloat( animmap, pos ) );
|
|
|
|
quake3::getTextures( Q3Texture [i].Texture, animmap, pos,fileSystem, SceneManager->getVideoDriver() );
|
|
}
|
|
|
|
// get clamp map
|
|
for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i )
|
|
{
|
|
if ( Q3Texture [i].Texture.size() )
|
|
continue;
|
|
|
|
group = Shader->getGroup( i );
|
|
|
|
const core::stringc &clampmap = group->get( "clampmap" );
|
|
if ( 0 == clampmap.size() )
|
|
continue;
|
|
|
|
Q3Texture [i].TextureAddressMode = video::ETC_CLAMP;
|
|
pos = 0;
|
|
quake3::getTextures( Q3Texture [i].Texture, clampmap, pos,fileSystem, SceneManager->getVideoDriver() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Register each texture stage, if first is visible
|
|
*/
|
|
void CQuake3ShaderSceneNode::OnRegisterSceneNode()
|
|
{
|
|
if ( isVisible() )
|
|
{
|
|
SceneManager->registerNodeForRendering(this, isTransparent() ? ESNRP_TRANSPARENT: ESNRP_SOLID );
|
|
}
|
|
ISceneNode::OnRegisterSceneNode();
|
|
}
|
|
|
|
/*
|
|
is this a transparent node ?
|
|
*/
|
|
bool CQuake3ShaderSceneNode::isTransparent() const
|
|
{
|
|
bool ret = false;
|
|
|
|
// generic stage
|
|
const quake3::SVarGroup *group;
|
|
|
|
group = Shader->getGroup( 1 );
|
|
/*
|
|
if ( group->isDefined( "surfaceparm", "nonsolid" ) )
|
|
{
|
|
ret = true;
|
|
}
|
|
*/
|
|
if ( group->isDefined( "surfaceparm", "trans" ) )
|
|
{
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
for ( u32 stage = 0; stage < Shader->VarGroup->VariableGroup.size(); ++stage )
|
|
{
|
|
if ( 0 == Q3Texture [ stage].Texture.size() )
|
|
continue;
|
|
|
|
group = Shader->getGroup( stage );
|
|
quake3::SBlendFunc blendfunc;
|
|
quake3::getBlendFunc( group->get( "blendfunc" ), blendfunc );
|
|
quake3::getBlendFunc( group->get( "alphafunc" ), blendfunc );
|
|
|
|
ret = blendfunc.isTransparent;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
render in multipass technique
|
|
*/
|
|
void CQuake3ShaderSceneNode::render()
|
|
{
|
|
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
|
|
|
bool isTransparentPass =
|
|
SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
|
|
|
|
video::SMaterial material;
|
|
const quake3::SVarGroup *group;
|
|
|
|
material.Lighting = false;
|
|
material.setTexture(1, 0);
|
|
material.NormalizeNormals = false;
|
|
|
|
// generic stage
|
|
group = Shader->getGroup( 1 );
|
|
material.BackfaceCulling = quake3::isDisabled( group->get( "cull" ) );
|
|
|
|
// u32 zEnable = group->getIndex( "polygonoffset" ) >= 0;
|
|
|
|
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation );
|
|
|
|
u32 drawCount = 0;
|
|
for ( u32 stage = 0; stage < Shader->VarGroup->VariableGroup.size(); ++stage )
|
|
//for ( u32 stage = 2; stage < 3; ++stage )
|
|
{
|
|
SQ3Texture &q = Q3Texture[stage];
|
|
|
|
// advance current stage
|
|
core::matrix4 texture;
|
|
animate( stage, texture );
|
|
|
|
// stage 1 finished, no drawing stage ( vertex transform only )
|
|
if ( 0 == q.Texture.size() )
|
|
continue;
|
|
|
|
// current stage
|
|
group = Shader->getGroup( stage );
|
|
|
|
material.setTexture(0, q.Texture[ q.TextureIndex ]);
|
|
material.ZBuffer = quake3::getDepthFunction( group->get( "depthfunc" ) );
|
|
|
|
if ( group->getIndex( "depthwrite" ) >= 0 )
|
|
{
|
|
material.ZWriteEnable = true;
|
|
}
|
|
else
|
|
{
|
|
material.ZWriteEnable = drawCount ? false: !isTransparentPass;
|
|
}
|
|
|
|
//resolve quake3 blendfunction to irrlicht Material Type
|
|
quake3::SBlendFunc blendfunc;
|
|
quake3::getBlendFunc( group->get( "blendfunc" ), blendfunc );
|
|
quake3::getBlendFunc( group->get( "alphafunc" ), blendfunc );
|
|
|
|
material.MaterialType = blendfunc.type;
|
|
material.MaterialTypeParam = blendfunc.param;
|
|
|
|
material.TextureLayer[0].TextureWrap = q.TextureAddressMode;
|
|
material.setTextureMatrix( 0, texture );
|
|
|
|
driver->setMaterial( material );
|
|
driver->drawMeshBuffer( MeshBuffer );
|
|
drawCount += 1;
|
|
}
|
|
|
|
if ( DebugDataVisible & scene::EDS_BBOX )
|
|
{
|
|
video::SMaterial deb_m;
|
|
deb_m.Lighting = false;
|
|
driver->setMaterial(deb_m);
|
|
driver->draw3DBox( getBoundingBox(), video::SColor(0,255,255,255));
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_wave( f32 dt, quake3::SModifierFunction &function )
|
|
{
|
|
function.wave = core::reciprocal( function.wave );
|
|
|
|
const f32 phase = function.phase;
|
|
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
for ( u32 i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
const f32 wavephase = (src.Pos.X + src.Pos.Y + src.Pos.Z) * function.wave;
|
|
function.phase = phase + wavephase;
|
|
|
|
const f32 f = function.evaluate( dt );
|
|
|
|
dst.Pos.X = src.Pos.X + f * src.Normal.X;
|
|
dst.Pos.Y = src.Pos.Y + f * src.Normal.Y;
|
|
dst.Pos.Z = src.Pos.Z + f * src.Normal.Z;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_bulge( f32 dt, quake3::SModifierFunction &function )
|
|
{
|
|
function.func = 0;
|
|
function.wave = core::reciprocal( function.bulgewidth );
|
|
|
|
dt *= function.bulgespeed * 0.1f;
|
|
const f32 phase = function.phase;
|
|
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
for ( u32 i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
const f32 wavephase = (Original->Vertices[i].TCoords.X ) * function.wave;
|
|
function.phase = phase + wavephase;
|
|
|
|
const f32 f = function.evaluate( dt );
|
|
|
|
dst.Pos.X = src.Pos.X + f * src.Normal.X;
|
|
dst.Pos.Y = src.Pos.Y + f * src.Normal.Y;
|
|
dst.Pos.Z = src.Pos.Z + f * src.Normal.Z;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_autosprite( f32 dt, quake3::SModifierFunction &function )
|
|
{
|
|
const core::matrix4 &m = SceneManager->getActiveCamera()->getViewFrustum()->Matrices [ video::ETS_VIEW ];
|
|
const core::vector3df view( -m[2], -m[6] , -m[10] );
|
|
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
|
|
core::aabbox3df box;
|
|
u32 g;
|
|
|
|
for ( u32 i = 0; i < vsize; i += 4 )
|
|
{
|
|
// in pairs of 4
|
|
box.reset( Original->Vertices[i].Pos );
|
|
for ( g = 1; g != 4; ++g )
|
|
{
|
|
box.addInternalPoint( Original->Vertices[i + g].Pos );
|
|
}
|
|
|
|
core::vector3df c = box.getCenter();
|
|
f32 sh = 0.5f * ( box.MaxEdge.Z - box.MinEdge.Z );
|
|
f32 sv = 0.5f * ( box.MaxEdge.Y - box.MinEdge.Y );
|
|
|
|
const core::vector3df h( m[0] * sh, m[4] * sh, m[8] * sh );
|
|
const core::vector3df v( m[1] * sv, m[5] * sv, m[9] * sv );
|
|
|
|
MeshBuffer->Vertices[ i + 0 ].Pos = c + h + v;
|
|
MeshBuffer->Vertices[ i + 1 ].Pos = c - h - v;
|
|
MeshBuffer->Vertices[ i + 2 ].Pos = c + h - v;
|
|
MeshBuffer->Vertices[ i + 3 ].Pos = c - h + v;
|
|
|
|
MeshBuffer->Vertices[ i + 0 ].Normal = view;
|
|
MeshBuffer->Vertices[ i + 1 ].Normal = view;
|
|
MeshBuffer->Vertices[ i + 2 ].Normal = view;
|
|
MeshBuffer->Vertices[ i + 3 ].Normal = view;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generate Vertex Color
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_rgbgen( f32 dt, quake3::SModifierFunction &function )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case 6:
|
|
//identity
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color = 0xFFFFFFFF;
|
|
break;
|
|
case 7:
|
|
// vertex
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color = Original->Vertices[i].Color;
|
|
break;
|
|
case 5:
|
|
{
|
|
// wave
|
|
f32 f = function.evaluate( dt ) * 255.f;
|
|
s32 value = core::clamp( core::floor32(f), 0, 255 );
|
|
value |= value << 8;
|
|
value |= value << 16;
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color = value;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Generate Texture Coordinates
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_tcgen( f32 dt, quake3::SModifierFunction &function )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
|
|
switch ( function.tcgen )
|
|
{
|
|
case 12:
|
|
//tcgen turb
|
|
{
|
|
function.wave = core::reciprocal( function.wave );
|
|
|
|
const f32 phase = function.phase;
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
const f32 wavephase = (src.Pos.X + src.Pos.Y + src.Pos.Z) * function.wave;
|
|
function.phase = phase + wavephase;
|
|
|
|
const f32 f = function.evaluate( dt );
|
|
|
|
dst.TCoords.X = src.TCoords.X + f * src.Normal.X;
|
|
dst.TCoords.Y = src.TCoords.Y + f * src.Normal.Y;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
// tcgen texture
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords;
|
|
break;
|
|
case 9:
|
|
// tcgen lightmap
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords2;
|
|
break;
|
|
case 10:
|
|
{
|
|
// tcgen environment ( D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR )
|
|
|
|
// using eye linear, sphere map may be cooler;-)
|
|
// modelmatrix is identity
|
|
const core::matrix4 &view = SceneManager->getActiveCamera()->getViewFrustum()->Matrices [ video::ETS_VIEW ];
|
|
const core::matrix4 &viewinverse = SceneManager->getActiveCamera()->getViewFrustum()->Matrices [ SViewFrustum::ETS_VIEW_MODEL_INVERSE_3 ];
|
|
|
|
// eyePlane
|
|
core::vector3df eyePlaneS;
|
|
core::vector3df eyePlaneT;
|
|
|
|
viewinverse.transformVect( eyePlaneS, core::vector3df(1.f, 0.f, 0.f) );
|
|
viewinverse.transformVect( eyePlaneT, core::vector3df(0.f, 1.f, 0.f) );
|
|
|
|
eyePlaneS.normalize();
|
|
eyePlaneT.normalize();
|
|
|
|
core::vector3df v;
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
// vertex in eye space
|
|
view.transformVect( v, Original->Vertices[i].Pos );
|
|
v.normalize();
|
|
|
|
MeshBuffer->Vertices[i].TCoords.X = (1.f + eyePlaneS.dotProduct(v) ) * 0.5f;
|
|
MeshBuffer->Vertices[i].TCoords.Y = 1.f - ( (1.f + eyePlaneT.dotProduct(v) ) * 0.5f );
|
|
}
|
|
|
|
} break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Transform Texture Coordinates
|
|
*/
|
|
void CQuake3ShaderSceneNode::transformtex( const core::matrix4 &m, const u32 addressMode )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = MeshBuffer->Vertices.size();
|
|
|
|
f32 tx1;
|
|
f32 ty1;
|
|
|
|
if ( addressMode )
|
|
{
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
core::vector2df &tx = MeshBuffer->Vertices[i].TCoords;
|
|
|
|
tx1 = m[0] * tx.X + m[4] * tx.Y + m[8];
|
|
ty1 = m[1] * tx.X + m[5] * tx.Y + m[9];
|
|
|
|
tx.X = tx1;
|
|
tx.Y = ty1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
core::vector2df &tx = MeshBuffer->Vertices[i].TCoords;
|
|
|
|
tx1 = m[0] * tx.X + m[4] * tx.Y + m[8];
|
|
ty1 = m[1] * tx.X + m[5] * tx.Y + m[9];
|
|
|
|
tx.X = tx1 <= 0.f ? 0.f : tx1 >= 1.f ? 1.f : tx1;
|
|
tx.Y = ty1 <= 0.f ? 0.f : ty1 >= 1.f ? 1.f : ty1;
|
|
|
|
//tx.X = core::clamp( tx1, 0.f, 1.f );
|
|
//tx.Y = core::clamp( ty1, 0.f, 1.f );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Texture & Vertex Transform Animator
|
|
|
|
Return a Texture Transformation for this stage
|
|
Vertex transformation are called if found
|
|
|
|
*/
|
|
void CQuake3ShaderSceneNode::animate( u32 stage,core::matrix4 &texture )
|
|
{
|
|
const quake3::SVarGroup *group = Shader->getGroup( stage );
|
|
|
|
// select current texture
|
|
if ( Q3Texture [ stage ].TextureFrequency != 0.f )
|
|
{
|
|
s32 v = core::floor32( TimeAbs * Q3Texture[stage].TextureFrequency );
|
|
Q3Texture [ stage ].TextureIndex = v % Q3Texture[stage].Texture.size();
|
|
}
|
|
|
|
core::matrix4 m2;
|
|
quake3::SModifierFunction function;
|
|
|
|
f32 f0;
|
|
f32 f1;
|
|
|
|
// walk group for all modifiers
|
|
for ( u32 g = 0; g != group->Variable.size(); ++g )
|
|
{
|
|
const quake3::SVariable &v = group->Variable[g];
|
|
|
|
// get the modifier
|
|
static const c8 * modifierList[] =
|
|
{
|
|
"tcmod","deformvertexes","rgbgen","tcgen","map"
|
|
};
|
|
|
|
u32 pos = 0;
|
|
function.masterfunc0 = quake3::isEqual( v.name, pos, modifierList, 5 );
|
|
|
|
if ( -2 == function.masterfunc0 )
|
|
continue;
|
|
|
|
switch ( function.masterfunc0 )
|
|
{
|
|
//tcmod
|
|
case 0:
|
|
m2.makeIdentity();
|
|
break;
|
|
}
|
|
|
|
// get the modifier function
|
|
static const c8 * funclist[] =
|
|
{
|
|
"scroll","scale","rotate","stretch","turb",
|
|
"wave","identity","vertex",
|
|
"texture","lightmap","environment","$lightmap",
|
|
"bulge","autosprite","autosprite2"
|
|
};
|
|
|
|
pos = 0;
|
|
function.masterfunc1 = quake3::isEqual( v.content, pos, funclist, 14 );
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case 0:
|
|
// scroll
|
|
f0 = quake3::getAsFloat( v.content, pos ) * TimeAbs;
|
|
f1 = quake3::getAsFloat( v.content, pos ) * TimeAbs;
|
|
m2.setTextureTranslate( f0, f1 );
|
|
break;
|
|
case 1:
|
|
// scale
|
|
f0 = quake3::getAsFloat( v.content, pos );
|
|
f1 = quake3::getAsFloat( v.content, pos );
|
|
m2.setTextureScale( f0, f1 );
|
|
break;
|
|
case 2:
|
|
//rotate
|
|
m2.setTextureRotationCenter( quake3::getAsFloat( v.content, pos ) * core::DEGTORAD * TimeAbs );
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
{
|
|
// turb == sin, default == sin
|
|
function.func = 0;
|
|
|
|
if (function.masterfunc1 == 5 && function.masterfunc0 == 1)
|
|
{
|
|
// deformvertexes, wave
|
|
function.wave = quake3::getAsFloat( v.content, pos );
|
|
}
|
|
|
|
if (function.masterfunc1 == 3 ||
|
|
function.masterfunc1 == 4 ||
|
|
function.masterfunc1 == 5)
|
|
{
|
|
// stretch, wave, tub
|
|
quake3::getModifierFunc( function, v.content, pos );
|
|
}
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case 3:
|
|
// stretch
|
|
f0 = core::reciprocal( function.evaluate(TimeAbs) );
|
|
m2.setTextureScaleCenter( f0, f0 );
|
|
break;
|
|
case 4:
|
|
{
|
|
// turb
|
|
/*
|
|
quake3::SModifierFunction ampFunction;
|
|
ampFunction.func = 0;
|
|
ampFunction.freq = function.freq;
|
|
ampFunction.base = 1.f;
|
|
ampFunction.amp = 0.2f;
|
|
f2 = ampFunction.evaluate( TimeAbs );
|
|
|
|
f0 = function.evaluate( TimeAbs );
|
|
function.func = 1;
|
|
f1 = function.evaluate( TimeAbs );
|
|
|
|
m2.setTextureTranslate( f0, f1 );
|
|
m2.setTextureScaleCenter( f2, f2 );
|
|
//m2.setTextureScale( f2, f2 );
|
|
*/
|
|
}break;
|
|
case 5:
|
|
if ( function.masterfunc0 == 1 )
|
|
{
|
|
vertextransform_wave( TimeAbs, function );
|
|
}
|
|
else
|
|
{
|
|
vertextransform_rgbgen( TimeAbs, function );
|
|
}
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
vertextransform_rgbgen( TimeAbs, function );
|
|
break;
|
|
}
|
|
|
|
} break;
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
// "texture","lightmap","environment"
|
|
function.tcgen = function.masterfunc1;
|
|
break;
|
|
case 11:
|
|
// map == lightmap, tcgen == lightmap
|
|
function.tcgen = 9;
|
|
break;
|
|
case 12:
|
|
// deformvertexes bulge
|
|
function.bulgewidth = quake3::getAsFloat( v.content, pos );
|
|
function.bulgeheight = quake3::getAsFloat( v.content, pos );
|
|
function.bulgespeed = quake3::getAsFloat( v.content, pos );
|
|
|
|
vertextransform_bulge(TimeAbs, function);
|
|
break;
|
|
|
|
case 13:
|
|
case 14:
|
|
// deformvertexes autosprite
|
|
vertextransform_autosprite(TimeAbs, function);
|
|
break;
|
|
|
|
} // func
|
|
|
|
switch ( function.masterfunc0 )
|
|
{
|
|
case 0:
|
|
texture *= m2;
|
|
break;
|
|
}
|
|
|
|
} // group
|
|
|
|
// texture coordinate modifier
|
|
vertextransform_tcgen(TimeAbs, function);
|
|
}
|
|
|
|
|
|
void CQuake3ShaderSceneNode::OnAnimate(u32 timeMs)
|
|
{
|
|
TimeAbs = f32( timeMs ) * (1.f/1000.f);
|
|
ISceneNode::OnAnimate( timeMs );
|
|
}
|
|
|
|
const core::aabbox3d<f32>& CQuake3ShaderSceneNode::getBoundingBox() const
|
|
{
|
|
return MeshBuffer->getBoundingBox();
|
|
}
|
|
|
|
|
|
u32 CQuake3ShaderSceneNode::getMaterialCount() const
|
|
{
|
|
return Q3Texture.size();
|
|
}
|
|
|
|
video::SMaterial& CQuake3ShaderSceneNode::getMaterial(u32 i)
|
|
{
|
|
video::SMaterial& m = MeshBuffer->getMaterial();
|
|
m.setTexture(0, 0);
|
|
if ( Q3Texture [ i ].TextureIndex )
|
|
m.setTexture(0, Q3Texture [ i ].Texture [ Q3Texture [ i ].TextureIndex ]);
|
|
return m;
|
|
}
|
|
|
|
|
|
} // end namespace scene
|
|
} // end namespace irr
|
|
|
|
#endif
|
|
|