mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-26 10:40:31 +01:00
2928a632a4
This breaks compiling. To have old values replace false with EZW_OFF and true with EWZ_AUTO. There's a bit history to this change. ZWriteFineControl got introduced after 1.8 so it was never in a released version. Basically it was needed after some changes had been made to allow shaders to have zwrite enabled independent of the material-type (which worked badly for shaders). This had caused other problems as it was then enabled too often instead. So to quickly fix those bugs and avoid breaking compatibility I had introduced a new enum ZWriteFineControl in SMaterial. This worked and didn't break compiling - but I noticed by now that introducing a second flag for this made maintainance for an already very hard to understand problem (figuring out the implementation of transparency and zwriting) even more complicated. So to keep maintance somewhat sane I decided to break compiling now and merge those two flags. The behavior should not be affected by this commit - except for users which set this flag already in their code and have to switch to the enum now. Serialization is switched on loading old files (so SMaterial has enum already and writes that out). git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6026 dfc29bdd-3216-0410-991c-e03cc46cb475
1386 lines
38 KiB
C++
1386 lines
38 KiB
C++
// Copyright (C) 2002-2012 Thomas Alten / 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_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"
|
|
#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
|
|
#include "CShadowVolumeSceneNode.h"
|
|
#else
|
|
#include "IShadowVolumeSceneNode.h"
|
|
#endif
|
|
|
|
namespace irr
|
|
{
|
|
namespace scene
|
|
{
|
|
|
|
// who, if not you..
|
|
using namespace quake3;
|
|
|
|
/*!
|
|
*/
|
|
CQuake3ShaderSceneNode::CQuake3ShaderSceneNode(
|
|
scene::ISceneNode* parent, scene::ISceneManager* mgr,s32 id,
|
|
io::IFileSystem *fileSystem, const scene::IMeshBuffer *original,
|
|
const IShader * shader)
|
|
: scene::IMeshSceneNode(parent, mgr, id,
|
|
core::vector3df(0.f, 0.f, 0.f),
|
|
core::vector3df(0.f, 0.f, 0.f),
|
|
core::vector3df(1.f, 1.f, 1.f)),
|
|
Shader(shader), Mesh(0), Shadow(0), Original(0), MeshBuffer(0), TimeAbs(0.f)
|
|
{
|
|
#ifdef _DEBUG
|
|
core::stringc dName = "CQuake3ShaderSceneNode ";
|
|
dName += Shader->name;
|
|
|
|
setDebugName( dName.c_str() );
|
|
#endif
|
|
|
|
// name the Scene Node
|
|
this->Name = Shader->name;
|
|
|
|
// take lightmap vertex type
|
|
MeshBuffer = new SMeshBuffer();
|
|
|
|
Mesh = new SMesh ();
|
|
Mesh->addMeshBuffer ( MeshBuffer );
|
|
MeshBuffer->drop ();
|
|
|
|
//Original = new SMeshBufferLightMap();
|
|
Original = (const scene::SMeshBufferLightMap*) original;
|
|
Original->grab();
|
|
|
|
// clone meshbuffer to modifiable buffer
|
|
cloneBuffer(MeshBuffer, Original,
|
|
Original->getMaterial().ColorMask != 0);
|
|
|
|
// load all Textures in all stages
|
|
loadTextures( fileSystem );
|
|
|
|
setAutomaticCulling( scene::EAC_OFF );
|
|
}
|
|
|
|
|
|
/*!
|
|
*/
|
|
CQuake3ShaderSceneNode::~CQuake3ShaderSceneNode()
|
|
{
|
|
if (Shadow)
|
|
Shadow->drop();
|
|
|
|
if (Mesh)
|
|
Mesh->drop();
|
|
|
|
if (Original)
|
|
Original->drop();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
create single copies
|
|
*/
|
|
void CQuake3ShaderSceneNode::cloneBuffer( scene::SMeshBuffer *dest, const scene::SMeshBufferLightMap * buffer, bool translateCenter )
|
|
{
|
|
dest->Material = buffer->Material;
|
|
dest->Indices = buffer->Indices;
|
|
|
|
const u32 vsize = buffer->Vertices.size();
|
|
|
|
dest->Vertices.set_used( vsize );
|
|
for ( u32 i = 0; i!= vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords& src = buffer->Vertices[i];
|
|
video::S3DVertex &dst = dest->Vertices[i];
|
|
|
|
dst.Pos = src.Pos;
|
|
dst.Normal = src.Normal;
|
|
dst.Color = 0xFFFFFFFF;
|
|
dst.TCoords = src.TCoords;
|
|
|
|
if ( i == 0 )
|
|
dest->BoundingBox.reset ( src.Pos );
|
|
else
|
|
dest->BoundingBox.addInternalPoint ( src.Pos );
|
|
}
|
|
|
|
// move the (temp) Mesh to a ScenePosititon
|
|
// set Scene Node Position
|
|
|
|
if ( translateCenter )
|
|
{
|
|
MeshOffset = dest->BoundingBox.getCenter();
|
|
setPosition( MeshOffset );
|
|
|
|
core::matrix4 m;
|
|
m.setTranslation( -MeshOffset );
|
|
SceneManager->getMeshManipulator()->transform( dest, m );
|
|
}
|
|
|
|
// No Texture!. Use Shader-Pointer for sorting
|
|
dest->Material.setTexture(0, (video::ITexture*) Shader);
|
|
}
|
|
|
|
|
|
/*
|
|
load the textures for all stages
|
|
*/
|
|
void CQuake3ShaderSceneNode::loadTextures( io::IFileSystem * fileSystem )
|
|
{
|
|
const SVarGroup *group;
|
|
u32 i;
|
|
|
|
video::IVideoDriver *driver = SceneManager->getVideoDriver();
|
|
|
|
// generic stage
|
|
u32 mipmap = 0;
|
|
group = Shader->getGroup( 1 );
|
|
if ( group->isDefined ( "nomipmaps" ) )
|
|
{
|
|
mipmap = 2 | (driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS)? 1: 0 );
|
|
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
|
|
}
|
|
|
|
// clear all stages and prefill empty
|
|
Q3Texture.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE );
|
|
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;
|
|
getTextures( Q3Texture [i].Texture, mapname, pos, fileSystem, driver );
|
|
}
|
|
}
|
|
|
|
// 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, getAsFloat( animmap, pos ) );
|
|
|
|
getTextures( Q3Texture [i].Texture, animmap, pos,fileSystem, driver );
|
|
}
|
|
|
|
// 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_TO_EDGE;
|
|
pos = 0;
|
|
getTextures( Q3Texture [i].Texture, clampmap, pos,fileSystem, driver );
|
|
}
|
|
|
|
if ( mipmap & 2 )
|
|
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap & 1);
|
|
}
|
|
|
|
/*
|
|
Register each texture stage, if first is visible
|
|
*/
|
|
void CQuake3ShaderSceneNode::OnRegisterSceneNode()
|
|
{
|
|
if ( isVisible() )
|
|
{
|
|
SceneManager->registerNodeForRendering(this, getRenderStage() );
|
|
}
|
|
ISceneNode::OnRegisterSceneNode();
|
|
}
|
|
|
|
/*
|
|
is this a transparent node ?
|
|
*/
|
|
E_SCENE_NODE_RENDER_PASS CQuake3ShaderSceneNode::getRenderStage() const
|
|
{
|
|
E_SCENE_NODE_RENDER_PASS ret = ESNRP_SOLID;
|
|
|
|
// generic stage
|
|
const SVarGroup *group;
|
|
|
|
group = Shader->getGroup( 1 );
|
|
/*
|
|
else
|
|
if ( group->getIndex( "portal" ) >= 0 )
|
|
{
|
|
ret = ESNRP_TRANSPARENT_EFFECT;
|
|
}
|
|
else
|
|
*/
|
|
if ( group->isDefined( "sort", "opaque" ) )
|
|
{
|
|
ret = ESNRP_SOLID;
|
|
}
|
|
else
|
|
if ( group->isDefined( "sort", "additive" ) )
|
|
{
|
|
ret = ESNRP_TRANSPARENT;
|
|
}
|
|
else
|
|
if ( strstr ( Shader->name.c_str(), "flame" ) ||
|
|
group->isDefined( "surfaceparm", "water" ) ||
|
|
group->isDefined( "sort", "underwater" )
|
|
)
|
|
{
|
|
ret = ESNRP_TRANSPARENT_EFFECT;
|
|
}
|
|
else
|
|
{
|
|
// Look if first drawing stage needs graphical underlay
|
|
for ( u32 stage = 2; stage < Shader->VarGroup->VariableGroup.size(); ++stage )
|
|
{
|
|
if ( 0 == Q3Texture [ stage ].Texture.size() )
|
|
continue;
|
|
|
|
group = Shader->getGroup( stage );
|
|
|
|
SBlendFunc blendfunc ( video::EMFN_MODULATE_1X );
|
|
getBlendFunc( group->get( "blendfunc" ), blendfunc );
|
|
getBlendFunc( group->get( "alphafunc" ), blendfunc );
|
|
|
|
//ret = blendfunc.isTransparent ? ESNRP_TRANSPARENT : ESNRP_SOLID;
|
|
if ( blendfunc.isTransparent )
|
|
{
|
|
ret = ESNRP_TRANSPARENT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
render in multipass technique
|
|
*/
|
|
void CQuake3ShaderSceneNode::render()
|
|
{
|
|
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
|
E_SCENE_NODE_RENDER_PASS pass = SceneManager->getSceneNodeRenderPass();
|
|
|
|
video::SMaterial material;
|
|
const SVarGroup *group;
|
|
|
|
material.Lighting = false;
|
|
material.setTexture(1, 0);
|
|
material.NormalizeNormals = false;
|
|
|
|
// generic stage
|
|
group = Shader->getGroup( 1 );
|
|
material.BackfaceCulling = getCullingFunction( group->get( "cull" ) );
|
|
|
|
u32 pushProjection = 0;
|
|
core::matrix4 projection ( core::matrix4::EM4CONST_NOTHING );
|
|
|
|
// decal ( solve z-fighting )
|
|
if ( group->isDefined( "polygonoffset" ) )
|
|
{
|
|
projection = driver->getTransform( video::ETS_PROJECTION );
|
|
|
|
core::matrix4 decalProjection ( projection );
|
|
|
|
/*
|
|
f32 n = SceneManager->getActiveCamera()->getNearValue();
|
|
f32 f = SceneManager->getActiveCamera()->getFarValue ();
|
|
|
|
f32 delta = 0.01f;
|
|
f32 pz = 0.2f;
|
|
f32 epsilon = -2.f * f * n * delta / ( ( f + n ) * pz * ( pz + delta ) );
|
|
decalProjection[10] *= 1.f + epsilon;
|
|
*/
|
|
// TODO: involve camera
|
|
decalProjection[10] -= 0.0002f;
|
|
driver->setTransform( video::ETS_PROJECTION, decalProjection );
|
|
pushProjection |= 1;
|
|
}
|
|
|
|
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation );
|
|
if (Shadow)
|
|
Shadow->updateShadowVolumes();
|
|
|
|
//! render all stages
|
|
u32 drawCount = (pass == ESNRP_TRANSPARENT_EFFECT) ? 1 : 0;
|
|
core::matrix4 textureMatrix ( core::matrix4::EM4CONST_NOTHING );
|
|
for ( u32 stage = 1; stage < Shader->VarGroup->VariableGroup.size(); ++stage )
|
|
{
|
|
SQ3Texture &q = Q3Texture[stage];
|
|
|
|
// advance current stage
|
|
textureMatrix.makeIdentity();
|
|
animate( stage, textureMatrix );
|
|
|
|
// stage finished, no drawing stage ( vertex transform only )
|
|
video::ITexture * tex = q.Texture.size() ? q.Texture [ q.TextureIndex ] : 0;
|
|
if ( 0 == tex )
|
|
continue;
|
|
|
|
// current stage
|
|
group = Shader->getGroup( stage );
|
|
|
|
material.setTexture(0, tex );
|
|
material.ZBuffer = getDepthFunction( group->get( "depthfunc" ) );
|
|
|
|
// TODO: maybe should be video::EZW_ON instead of EZW_AUTO now (we didn't have that before and I just kept old values here when introducing it to not break anything)
|
|
if ( group->isDefined( "depthwrite" ) )
|
|
{
|
|
material.ZWriteEnable = video::EZW_AUTO;
|
|
}
|
|
else
|
|
{
|
|
material.ZWriteEnable = drawCount == 0 ? video::EZW_AUTO : video::EZW_OFF;
|
|
}
|
|
|
|
//resolve quake3 blendfunction to irrlicht Material Type
|
|
SBlendFunc blendfunc ( video::EMFN_MODULATE_1X );
|
|
getBlendFunc( group->get( "blendfunc" ), blendfunc );
|
|
getBlendFunc( group->get( "alphafunc" ), blendfunc );
|
|
|
|
material.MaterialType = blendfunc.type;
|
|
material.MaterialTypeParam = blendfunc.param0;
|
|
|
|
material.TextureLayer[0].TextureWrapU = q.TextureAddressMode;
|
|
material.TextureLayer[0].TextureWrapV = q.TextureAddressMode;
|
|
material.TextureLayer[0].TextureWrapW = q.TextureAddressMode;
|
|
//material.TextureLayer[0].TrilinearFilter = 1;
|
|
//material.TextureLayer[0].AnisotropicFilter = 0xFF;
|
|
material.setTextureMatrix( 0, textureMatrix );
|
|
|
|
driver->setMaterial( material );
|
|
driver->drawMeshBuffer( MeshBuffer );
|
|
drawCount += 1;
|
|
|
|
}
|
|
|
|
if ( DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY )
|
|
{
|
|
video::SMaterial deb_m;
|
|
deb_m.Wireframe = true;
|
|
deb_m.Lighting = false;
|
|
deb_m.BackfaceCulling = material.BackfaceCulling;
|
|
driver->setMaterial( deb_m );
|
|
|
|
driver->drawMeshBuffer( MeshBuffer );
|
|
}
|
|
|
|
// show normals
|
|
if ( DebugDataVisible & scene::EDS_NORMALS )
|
|
{
|
|
video::SMaterial deb_m;
|
|
|
|
IAnimatedMesh * arrow = SceneManager->addArrowMesh (
|
|
"__debugnormalq3",
|
|
0xFFECEC00,0xFF999900,
|
|
4, 8,
|
|
8.f, 6.f,
|
|
0.5f,1.f
|
|
);
|
|
if ( 0 == arrow )
|
|
{
|
|
arrow = SceneManager->getMesh ( "__debugnormalq3" );
|
|
}
|
|
const IMesh *mesh = arrow->getMesh ( 0 );
|
|
|
|
// find a good scaling factor
|
|
|
|
core::matrix4 m2;
|
|
|
|
// draw normals
|
|
const scene::IMeshBuffer* mb = MeshBuffer;
|
|
const u32 vSize = video::getVertexPitchFromType(mb->getVertexType());
|
|
const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices();
|
|
|
|
//f32 colCycle = 270.f / (f32) core::s32_max ( mb->getVertexCount() - 1, 1 );
|
|
|
|
for ( u32 i=0; i != mb->getVertexCount(); ++i )
|
|
{
|
|
// Align to v->normal
|
|
m2.buildRotateFromTo ( core::vector3df ( 0.f, 1.f, 0 ), v->Normal );
|
|
m2.setTranslation ( v->Pos + AbsoluteTransformation.getTranslation () );
|
|
/*
|
|
core::quaternion quatRot( v->Normal.Z, 0.f, -v->Normal.X, 1 + v->Normal.Y );
|
|
quatRot.normalize();
|
|
quatRot.getMatrix ( m2, v->Pos );
|
|
|
|
m2 [ 12 ] += AbsoluteTransformation [ 12 ];
|
|
m2 [ 13 ] += AbsoluteTransformation [ 13 ];
|
|
m2 [ 14 ] += AbsoluteTransformation [ 14 ];
|
|
*/
|
|
driver->setTransform(video::ETS_WORLD, m2 );
|
|
|
|
deb_m.Lighting = true;
|
|
/*
|
|
irr::video::SColorHSL color;
|
|
irr::video::SColor rgb(0);
|
|
color.Hue = i * colCycle * core::DEGTORAD;
|
|
color.Saturation = 1.f;
|
|
color.Luminance = 0.5f;
|
|
color.toRGB( deb_m.EmissiveColor );
|
|
*/
|
|
switch ( i )
|
|
{
|
|
case 0: deb_m.EmissiveColor.set(0xFFFFFFFF); break;
|
|
case 1: deb_m.EmissiveColor.set(0xFFFF0000); break;
|
|
case 2: deb_m.EmissiveColor.set(0xFF00FF00); break;
|
|
case 3: deb_m.EmissiveColor.set(0xFF0000FF); break;
|
|
default:
|
|
deb_m.EmissiveColor = v->Color; break;
|
|
}
|
|
driver->setMaterial( deb_m );
|
|
|
|
for ( u32 a = 0; a != mesh->getMeshBufferCount(); ++a )
|
|
driver->drawMeshBuffer ( mesh->getMeshBuffer ( a ) );
|
|
|
|
v = (const video::S3DVertex*) ( (u8*) v + vSize );
|
|
}
|
|
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
|
}
|
|
|
|
|
|
if ( pushProjection & 1 )
|
|
{
|
|
driver->setTransform( video::ETS_PROJECTION, projection );
|
|
}
|
|
|
|
if ( DebugDataVisible & scene::EDS_BBOX )
|
|
{
|
|
video::SMaterial deb_m;
|
|
deb_m.Lighting = false;
|
|
driver->setMaterial(deb_m);
|
|
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
|
driver->draw3DBox( getBoundingBox(), video::SColor(255,255,0,0));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//! Removes a child from this scene node.
|
|
//! Implemented here, to be able to remove the shadow properly, if there is one,
|
|
//! or to remove attached childs.
|
|
bool CQuake3ShaderSceneNode::removeChild(ISceneNode* child)
|
|
{
|
|
if (child && Shadow == child)
|
|
{
|
|
Shadow->drop();
|
|
Shadow = 0;
|
|
}
|
|
|
|
return ISceneNode::removeChild(child);
|
|
}
|
|
|
|
|
|
//! Creates shadow volume scene node as child of this node
|
|
//! and returns a pointer to it.
|
|
IShadowVolumeSceneNode* CQuake3ShaderSceneNode::addShadowVolumeSceneNode(
|
|
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
|
|
{
|
|
#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
|
|
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
|
|
return 0;
|
|
|
|
if (!shadowMesh)
|
|
shadowMesh = Mesh; // if null is given, use the mesh of node
|
|
|
|
if (Shadow)
|
|
Shadow->drop();
|
|
|
|
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
|
|
return Shadow;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*!
|
|
3.3.1 deformVertexes wave <div> <func> <base> <amplitude> <phase> <freq>
|
|
Designed for water surfaces, modifying the values differently at each point.
|
|
It accepts the standard wave functions of the type sin, triangle, square, sawtooth
|
|
or inversesawtooth. The "div" parameter is used to control the wave "spread"
|
|
- a value equal to the tessSize of the surface is a good default value
|
|
(tessSize is subdivision size, in game units, used for the shader when seen in the game world) .
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_wave( f32 dt, SModifierFunction &function )
|
|
{
|
|
function.wave = core::reciprocal( function.wave );
|
|
|
|
const f32 phase = function.phase;
|
|
|
|
const u32 vsize = Original->Vertices.size();
|
|
for ( u32 i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
if ( 0 == function.count )
|
|
dst.Pos = src.Pos - MeshOffset;
|
|
|
|
const f32 wavephase = (dst.Pos.X + dst.Pos.Y + dst.Pos.Z) * function.wave;
|
|
function.phase = phase + wavephase;
|
|
|
|
const f32 f = function.evaluate( dt );
|
|
|
|
dst.Pos.X += f * src.Normal.X;
|
|
dst.Pos.Y += f * src.Normal.Y;
|
|
dst.Pos.Z += f * src.Normal.Z;
|
|
|
|
if ( i == 0 )
|
|
MeshBuffer->BoundingBox.reset ( dst.Pos );
|
|
else
|
|
MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos );
|
|
}
|
|
function.count = 1;
|
|
}
|
|
|
|
/*!
|
|
deformVertexes move x y z func base amplitude phase freq
|
|
The move parameter is used to make a brush, curve patch or model
|
|
appear to move together as a unit. The x y z values are the distance
|
|
and direction in game units the object appears to move relative to
|
|
it's point of origin in the map. The func base amplitude phase freq values are
|
|
the same as found in other waveform manipulations.
|
|
|
|
The product of the function modifies the values x, y, and z.
|
|
Therefore, if you have an amplitude of 5 and an x value of 2,
|
|
the object will travel 10 units from its point of origin along the x axis.
|
|
This results in a total of 20 units of motion along the x axis, since the
|
|
amplitude is the variation both above and below the base.
|
|
|
|
It must be noted that an object made with this shader does not actually
|
|
change position, it only appears to.
|
|
|
|
Design Notes:
|
|
If an object is made up of surfaces with different shaders, all must have
|
|
matching deformVertexes move values or the object will appear to tear itself apart.
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_move( f32 dt, SModifierFunction &function )
|
|
{
|
|
function.wave = core::reciprocal( function.wave );
|
|
const f32 f = function.evaluate( dt );
|
|
|
|
const u32 vsize = Original->Vertices.size();
|
|
for ( u32 i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
if ( 0 == function.count )
|
|
dst.Pos = src.Pos - MeshOffset;
|
|
|
|
dst.Pos.X += f * function.x;
|
|
dst.Pos.Y += f * function.y;
|
|
dst.Pos.Z += f * function.z;
|
|
|
|
if ( i == 0 )
|
|
MeshBuffer->BoundingBox.reset ( dst.Pos );
|
|
else
|
|
MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos );
|
|
}
|
|
function.count = 1;
|
|
|
|
}
|
|
|
|
/*!
|
|
3.3.2 deformVertexes normal <div> <func> <base> <amplitude ~0.1-~0.5> <frequency ~1.0-~4.0>
|
|
This deformation affects the normals of a vertex without actually moving it,
|
|
which will effect later shader options like lighting and especially environment mapping.
|
|
If the shader stages don't use normals in any of their calculations, there will
|
|
be no visible effect.
|
|
|
|
Design Notes: Putting values of 0.1 t o 0.5 in Amplitude and 1.0 to 4.0 in the
|
|
Frequency can produce some satisfying results. Some things that have been
|
|
done with it: A small fluttering bat, falling leaves, rain, flags.
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_normal( f32 dt, SModifierFunction &function )
|
|
{
|
|
function.func = SINUS;
|
|
const u32 vsize = Original->Vertices.size();
|
|
for ( u32 i = 0; i != vsize; ++i )
|
|
{
|
|
const video::S3DVertex2TCoords &src = Original->Vertices[i];
|
|
video::S3DVertex &dst = MeshBuffer->Vertices[i];
|
|
|
|
function.base = atan2f ( src.Pos.X, src.Pos.Y );
|
|
function.phase = src.Pos.X + src.Pos.Z;
|
|
|
|
const f32 lat = function.evaluate( dt );
|
|
|
|
function.base = src.Normal.Y;
|
|
function.phase = src.Normal.Z + src.Normal.X;
|
|
|
|
const f32 lng = function.evaluate( dt );
|
|
|
|
dst.Normal.X = cosf ( lat ) * sinf ( lng );
|
|
dst.Normal.Y = sinf ( lat ) * sinf ( lng );
|
|
dst.Normal.Z = cosf ( lng );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
3.3.3 deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
|
|
This forces a bulge to move along the given s and t directions. Designed for use
|
|
on curved pipes.
|
|
|
|
Specific parameter definitions for deform keywords:
|
|
<div> This is roughly defined as the size of the waves that occur.
|
|
It is measured in game units. Smaller values create a greater
|
|
density of smaller wave forms occurring in a given area.
|
|
Larger values create a lesser density of waves, or otherwise put,
|
|
the appearance of larger waves. To look correct this value should
|
|
closely correspond to the value (in pixels) set for tessSize (tessellation size)
|
|
of the texture. A value of 100.0 is a good default value
|
|
(which means your tessSize should be close to that for things to look "wavelike").
|
|
|
|
<func> This is the type of wave form being created. Sin stands for sine wave,
|
|
a regular smoothly flowing wave. Triangle is a wave with a sharp ascent
|
|
and a sharp decay. It will make a choppy looking wave forms.
|
|
A square wave is simply on or off for the period of the
|
|
frequency with no in between. The sawtooth wave has the ascent of a
|
|
triangle wave, but has the decay cut off sharply like a square wave.
|
|
An inversesawtooth wave reverses this.
|
|
|
|
<base> This is the distance, in game units that the apparent surface of the
|
|
texture is displaced from the actual surface of the brush as placed
|
|
in the editor. A positive value appears above the brush surface.
|
|
A negative value appears below the brush surface.
|
|
An example of this is the Quad effect, which essentially is a
|
|
shell with a positive base value to stand it away from the model
|
|
surface and a 0 (zero) value for amplitude.
|
|
|
|
<amplitude> The distance that the deformation moves away from the base value.
|
|
See Wave Forms in the introduction for a description of amplitude.
|
|
|
|
<phase> See Wave Forms in the introduction for a description of phase)
|
|
|
|
<frequency> See Wave Forms in the introduction for a description of frequency)
|
|
|
|
Design Note: The div and amplitude parameters, when used in conjunction with
|
|
liquid volumes like water should take into consideration how much the water
|
|
will be moving. A large ocean area would have have massive swells (big div values)
|
|
that rose and fell dramatically (big amplitude values). While a small, quiet pool
|
|
may move very little.
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_bulge( f32 dt, SModifierFunction &function )
|
|
{
|
|
function.func = SINUS;
|
|
function.wave = core::reciprocal( function.bulgewidth );
|
|
|
|
dt *= function.bulgespeed * 0.1f;
|
|
const f32 phase = function.phase;
|
|
|
|
const u32 vsize = Original->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 );
|
|
|
|
if ( 0 == function.count )
|
|
dst.Pos = src.Pos - MeshOffset;
|
|
|
|
dst.Pos.X += f * src.Normal.X;
|
|
dst.Pos.Y += f * src.Normal.Y;
|
|
dst.Pos.Z += f * src.Normal.Z;
|
|
|
|
if ( i == 0 )
|
|
MeshBuffer->BoundingBox.reset ( dst.Pos );
|
|
else
|
|
MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos );
|
|
}
|
|
|
|
function.count = 1;
|
|
}
|
|
|
|
|
|
/*!
|
|
deformVertexes autosprite
|
|
|
|
This function can be used to make any given triangle quad
|
|
(pair of triangles that form a square rectangle) automatically behave
|
|
like a sprite without having to make it a separate entity. This means
|
|
that the "sprite" on which the texture is placed will rotate to always
|
|
appear at right angles to the player's view as a sprite would. Any four-sided
|
|
brush side, flat patch, or pair of triangles in a model can have the autosprite
|
|
effect on it. The brush face containing a texture with this shader keyword must
|
|
be square.
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_autosprite( f32 dt, SModifierFunction &function )
|
|
{
|
|
u32 vsize = Original->Vertices.size();
|
|
u32 g;
|
|
u32 i;
|
|
|
|
const core::vector3df& camPos = SceneManager->getActiveCamera()->getPosition();
|
|
|
|
video::S3DVertex * dv = MeshBuffer->Vertices.pointer();
|
|
const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer();
|
|
|
|
core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING );
|
|
core::quaternion q;
|
|
for ( i = 0; i < vsize; i += 4 )
|
|
{
|
|
// quad-plane
|
|
core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos );
|
|
core::vector3df forward = camPos - center;
|
|
|
|
q.rotationFromTo ( vin[i].Normal, forward );
|
|
q.getMatrixCenter ( lookat, center, MeshOffset );
|
|
|
|
for ( g = 0; g < 4; ++g )
|
|
{
|
|
lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos );
|
|
lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal );
|
|
}
|
|
|
|
}
|
|
function.count = 1;
|
|
}
|
|
|
|
|
|
/*!
|
|
deformVertexes autosprite2
|
|
Is a slightly modified "sprite" that only rotates around the middle of its longest axis.
|
|
This allows you to make a pillar of fire that you can walk around, or an energy beam
|
|
stretched across the room.
|
|
*/
|
|
|
|
struct sortaxis
|
|
{
|
|
core::vector3df v;
|
|
bool operator < ( const sortaxis &other ) const
|
|
{
|
|
return v.getLengthSQ () < other.v.getLengthSQ ();
|
|
}
|
|
};
|
|
/*!
|
|
*/
|
|
void CQuake3ShaderSceneNode::deformvertexes_autosprite2( f32 dt, SModifierFunction &function )
|
|
{
|
|
u32 vsize = Original->Vertices.size();
|
|
u32 g;
|
|
u32 i;
|
|
|
|
const core::vector3df camPos = SceneManager->getActiveCamera()->getAbsolutePosition();
|
|
|
|
video::S3DVertex * dv = MeshBuffer->Vertices.pointer();
|
|
const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer();
|
|
|
|
core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING );
|
|
|
|
core::array < sortaxis > axis;
|
|
axis.set_used ( 3 );
|
|
|
|
for ( i = 0; i < vsize; i += 4 )
|
|
{
|
|
// quad-plane
|
|
core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos );
|
|
|
|
// longes axe
|
|
axis[0].v = vin[i+1].Pos - vin[i+0].Pos;
|
|
axis[1].v = vin[i+2].Pos - vin[i+0].Pos;
|
|
axis[2].v = vin[i+3].Pos - vin[i+0].Pos;
|
|
axis.set_sorted ( false );
|
|
axis.sort ();
|
|
|
|
lookat.buildAxisAlignedBillboard ( camPos, center, MeshOffset, axis[1].v, vin[i+0].Normal );
|
|
|
|
for ( g = 0; g < 4; ++g )
|
|
{
|
|
lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos );
|
|
lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal );
|
|
}
|
|
}
|
|
function.count = 1;
|
|
}
|
|
|
|
/*
|
|
Generate Vertex Color
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_rgbgen( f32 dt, SModifierFunction &function )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = Original->Vertices.size();
|
|
|
|
switch ( function.rgbgen )
|
|
{
|
|
case IDENTITY:
|
|
//rgbgen identity
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.set(0xFFFFFFFF);
|
|
break;
|
|
|
|
case IDENTITYLIGHTING:
|
|
// rgbgen identitylighting TODO: overbright
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.set(0xFF7F7F7F);
|
|
break;
|
|
|
|
case EXACTVERTEX:
|
|
// alphagen exactvertex TODO lighting
|
|
case VERTEX:
|
|
// rgbgen vertex
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color=Original->Vertices[i].Color;
|
|
break;
|
|
case WAVE:
|
|
{
|
|
// rgbGen wave <func> <base> <amp> <phase> <freq>
|
|
f32 f = function.evaluate( dt ) * 255.f;
|
|
s32 value = core::clamp( core::floor32(f), 0, 255 );
|
|
value = 0xFF000000 | value << 16 | value << 8 | value;
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.set(value);
|
|
} break;
|
|
case CONSTANT:
|
|
{
|
|
//rgbgen const ( x y z )
|
|
video::SColorf cf( function.x, function.y, function.z );
|
|
video::SColor col = cf.toSColor();
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color=col;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generate Vertex Color, Alpha
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_alphagen( f32 dt, SModifierFunction &function )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = Original->Vertices.size();
|
|
|
|
switch ( function.alphagen )
|
|
{
|
|
case IDENTITY:
|
|
//alphagen identity
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.setAlpha ( 0xFF );
|
|
break;
|
|
|
|
case EXACTVERTEX:
|
|
// alphagen exactvertex TODO lighting
|
|
case VERTEX:
|
|
// alphagen vertex
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.setAlpha ( Original->Vertices[i].Color.getAlpha() );
|
|
break;
|
|
case CONSTANT:
|
|
{
|
|
// alphagen const
|
|
u32 a = (u32) ( function.x * 255.f );
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.setAlpha ( a );
|
|
} break;
|
|
|
|
case LIGHTINGSPECULAR:
|
|
{
|
|
// alphagen lightingspecular TODO!!!
|
|
const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum();
|
|
const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW );
|
|
|
|
const f32 *m = view.pointer();
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
const core::vector3df &n = Original->Vertices[i].Normal;
|
|
MeshBuffer->Vertices[i].Color.setAlpha ((u32)( 128.f *(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2]))));
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
case WAVE:
|
|
{
|
|
// alphagen wave
|
|
f32 f = function.evaluate( dt ) * 255.f;
|
|
s32 value = core::clamp( core::floor32(f), 0, 255 );
|
|
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].Color.setAlpha ( value );
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Generate Texture Coordinates
|
|
*/
|
|
void CQuake3ShaderSceneNode::vertextransform_tcgen( f32 dt, SModifierFunction &function )
|
|
{
|
|
u32 i;
|
|
const u32 vsize = Original->Vertices.size();
|
|
|
|
switch ( function.tcgen )
|
|
{
|
|
case TURBULENCE:
|
|
//tcgen turb
|
|
{
|
|
function.wave = core::reciprocal( function.phase );
|
|
|
|
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 TEXTURE:
|
|
// tcgen texture
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords;
|
|
break;
|
|
case LIGHTMAP:
|
|
// tcgen lightmap
|
|
for ( i = 0; i != vsize; ++i )
|
|
MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords2;
|
|
break;
|
|
case ENVIRONMENT:
|
|
{
|
|
// tcgen environment
|
|
const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum();
|
|
const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW );
|
|
|
|
const f32 *m = view.pointer();
|
|
|
|
core::vector3df n;
|
|
for ( i = 0; i != vsize; ++i )
|
|
{
|
|
//const core::vector3df &n = Original->Vertices[i].Normal;
|
|
|
|
n = frustum->cameraPosition - Original->Vertices[i].Pos;
|
|
n.normalize();
|
|
n += Original->Vertices[i].Normal;
|
|
n.normalize();
|
|
|
|
MeshBuffer->Vertices[i].TCoords.X = 0.5f*(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2]));
|
|
MeshBuffer->Vertices[i].TCoords.Y = 0.5f*(1.f+(n.X*m[4]+n.Y*m[5]+n.Z*m[6]));
|
|
}
|
|
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
/*
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
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 SVarGroup *group = Shader->getGroup( stage );
|
|
|
|
// select current texture
|
|
SQ3Texture &q3Tex = Q3Texture [ stage ];
|
|
if ( q3Tex.TextureFrequency != 0.f )
|
|
{
|
|
s32 v = core::floor32( TimeAbs * q3Tex.TextureFrequency );
|
|
q3Tex.TextureIndex = v % q3Tex.Texture.size();
|
|
}
|
|
|
|
core::matrix4 m2;
|
|
SModifierFunction function;
|
|
|
|
f32 f[16];
|
|
|
|
// walk group for all modifiers
|
|
for ( u32 g = 0; g != group->Variable.size(); ++g )
|
|
{
|
|
const SVariable &v = group->Variable[g];
|
|
|
|
// get the modifier
|
|
static const c8 * const modifierList[] =
|
|
{
|
|
"tcmod","deformvertexes","rgbgen","tcgen","map","alphagen"
|
|
};
|
|
|
|
u32 pos = 0;
|
|
function.masterfunc0 = (eQ3ModifierFunction) isEqual( v.name, pos, modifierList, 6 );
|
|
|
|
if ( UNKNOWN == function.masterfunc0 )
|
|
continue;
|
|
|
|
switch ( function.masterfunc0 )
|
|
{
|
|
//tcmod
|
|
case TCMOD:
|
|
m2.makeIdentity();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// get the modifier function
|
|
static const c8 * const funclist[] =
|
|
{
|
|
"scroll","scale","rotate","stretch","turb",
|
|
"wave","identity","vertex",
|
|
"texture","lightmap","environment","$lightmap",
|
|
"bulge","autosprite","autosprite2","transform",
|
|
"exactvertex","const","lightingspecular","move","normal",
|
|
"identitylighting"
|
|
};
|
|
static const c8 * const groupToken[] = { "(", ")" };
|
|
|
|
pos = 0;
|
|
function.masterfunc1 = (eQ3ModifierFunction) isEqual( v.content, pos, funclist, 22 );
|
|
if ( function.masterfunc1 != UNKNOWN )
|
|
function.masterfunc1 = (eQ3ModifierFunction) ((u32) function.masterfunc1 + FUNCTION2 + 1);
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case SCROLL:
|
|
// tcMod scroll <sSpeed> <tSpeed>
|
|
f[0] = getAsFloat( v.content, pos ) * TimeAbs;
|
|
f[1] = getAsFloat( v.content, pos ) * TimeAbs;
|
|
m2.setTextureTranslate( f[0], f[1] );
|
|
break;
|
|
case SCALE:
|
|
// tcmod scale <sScale> <tScale>
|
|
f[0] = getAsFloat( v.content, pos );
|
|
f[1] = getAsFloat( v.content, pos );
|
|
m2.setTextureScale( f[0], f[1] );
|
|
break;
|
|
case ROTATE:
|
|
// tcmod rotate <degrees per second>
|
|
m2.setTextureRotationCenter( getAsFloat( v.content, pos ) *
|
|
core::DEGTORAD *
|
|
TimeAbs
|
|
);
|
|
break;
|
|
case TRANSFORM:
|
|
// tcMod <transform> <m00> <m01> <m10> <m11> <t0> <t1>
|
|
memset(f, 0, sizeof ( f ));
|
|
f[10] = f[15] = 1.f;
|
|
|
|
f[0] = getAsFloat( v.content, pos );
|
|
f[1] = getAsFloat( v.content, pos );
|
|
f[4] = getAsFloat( v.content, pos );
|
|
f[5] = getAsFloat( v.content, pos );
|
|
f[8] = getAsFloat( v.content, pos );
|
|
f[9] = getAsFloat( v.content, pos );
|
|
m2.setM ( f );
|
|
break;
|
|
|
|
case STRETCH: // stretch
|
|
case TURBULENCE: // turb
|
|
case WAVE: // wave
|
|
case IDENTITY: // identity
|
|
case IDENTITYLIGHTING:
|
|
case VERTEX: // vertex
|
|
case MOVE:
|
|
case CONSTANT:
|
|
{
|
|
// turb == sin, default == sin
|
|
function.func = SINUS;
|
|
|
|
if ( function.masterfunc0 == DEFORMVERTEXES )
|
|
{
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case WAVE:
|
|
// deformvertexes wave
|
|
function.wave = getAsFloat( v.content, pos );
|
|
break;
|
|
case MOVE:
|
|
//deformvertexes move
|
|
function.x = getAsFloat( v.content, pos );
|
|
function.z = getAsFloat( v.content, pos );
|
|
function.y = getAsFloat( v.content, pos );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case STRETCH:
|
|
case TURBULENCE:
|
|
case WAVE:
|
|
case MOVE:
|
|
getModifierFunc( function, v.content, pos );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case STRETCH:
|
|
//tcMod stretch <func> <base> <amplitude> <phase> <frequency>
|
|
f[0] = core::reciprocal( function.evaluate(TimeAbs) );
|
|
m2.setTextureScaleCenter( f[0], f[0] );
|
|
break;
|
|
case TURBULENCE:
|
|
//tcMod turb <base> <amplitude> <phase> <freq>
|
|
//function.tcgen = TURBULENCE;
|
|
m2.setTextureRotationCenter( function.frequency *
|
|
core::DEGTORAD *
|
|
TimeAbs
|
|
);
|
|
break;
|
|
case WAVE:
|
|
case IDENTITY:
|
|
case IDENTITYLIGHTING:
|
|
case VERTEX:
|
|
case EXACTVERTEX:
|
|
case CONSTANT:
|
|
case LIGHTINGSPECULAR:
|
|
case MOVE:
|
|
switch ( function.masterfunc0 )
|
|
{
|
|
case DEFORMVERTEXES:
|
|
switch ( function.masterfunc1 )
|
|
{
|
|
case WAVE:
|
|
deformvertexes_wave( TimeAbs, function );
|
|
break;
|
|
case MOVE:
|
|
deformvertexes_move( TimeAbs, function );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case RGBGEN:
|
|
function.rgbgen = function.masterfunc1;
|
|
if ( function.rgbgen == CONSTANT )
|
|
{
|
|
isEqual ( v.content, pos, groupToken, 2 );
|
|
function.x = getAsFloat( v.content, pos );
|
|
function.y = getAsFloat( v.content, pos );
|
|
function.z = getAsFloat( v.content, pos );
|
|
}
|
|
//vertextransform_rgbgen( TimeAbs, function );
|
|
break;
|
|
case ALPHAGEN:
|
|
function.alphagen = function.masterfunc1;
|
|
if ( function.alphagen == CONSTANT )
|
|
{
|
|
function.x = getAsFloat( v.content, pos );
|
|
}
|
|
|
|
//vertextransform_alphagen( TimeAbs, function );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
} break;
|
|
case TEXTURE:
|
|
case LIGHTMAP:
|
|
case ENVIRONMENT:
|
|
// "texture","lightmap","environment"
|
|
function.tcgen = function.masterfunc1;
|
|
break;
|
|
case DOLLAR_LIGHTMAP:
|
|
// map == lightmap, tcgen == lightmap
|
|
function.tcgen = LIGHTMAP;
|
|
break;
|
|
case BULGE:
|
|
// deformvertexes bulge
|
|
function.bulgewidth = getAsFloat( v.content, pos );
|
|
function.bulgeheight = getAsFloat( v.content, pos );
|
|
function.bulgespeed = getAsFloat( v.content, pos );
|
|
|
|
deformvertexes_bulge(TimeAbs, function);
|
|
break;
|
|
|
|
case NORMAL:
|
|
// deformvertexes normal
|
|
function.amp = getAsFloat( v.content, pos );
|
|
function.frequency = getAsFloat( v.content, pos );
|
|
|
|
deformvertexes_normal(TimeAbs, function);
|
|
break;
|
|
|
|
case AUTOSPRITE:
|
|
// deformvertexes autosprite
|
|
deformvertexes_autosprite(TimeAbs, function);
|
|
break;
|
|
|
|
case AUTOSPRITE2:
|
|
// deformvertexes autosprite2
|
|
deformvertexes_autosprite2(TimeAbs, function);
|
|
break;
|
|
default:
|
|
break;
|
|
} // func
|
|
|
|
switch ( function.masterfunc0 )
|
|
{
|
|
case TCMOD:
|
|
texture *= m2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
} // group
|
|
|
|
vertextransform_rgbgen( TimeAbs, function );
|
|
vertextransform_alphagen( TimeAbs, function );
|
|
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->Material;
|
|
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
|
|
|