Torque3D/Engine/source/afx/util/afxParticlePool_T3D.cpp
Areloch 5525f8ecdd Converts all game, gui editor, and system classes to utilize assets
Processed core, tools and default modules to utilize assets
Converted all console types that were string based, such as TypeImageFilename to utilize const char*/the string table, which avoids a lot of type swapping shenanigans and avoids string corruption
Removed unneeded MainEditor mockup module
Removed some unused/duplicate image assets from the tools
2021-07-19 01:07:08 -05:00

492 lines
16 KiB
C++

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#include "afx/arcaneFX.h"
#include "scene/sceneRenderState.h"
#include "T3D/fx/particleEmitter.h"
#include "renderInstance/renderPassManager.h"
#include "lighting/lightInfo.h"
#include "lighting/lightManager.h"
#include "afx/util/afxParticlePool.h"
void afxParticlePool::prepRenderImage(SceneRenderState* state)
{
const LightInfo *sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
pool_prepBatchRender(state->getRenderPass(), state->getCameraPosition(), sunlight->getAmbient());
};
void afxParticlePool::pool_prepBatchRender(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
{
if (emitters.empty())
return;
switch (mDataBlock->pool_type)
{
case afxParticlePoolData::POOL_TWOPASS :
pool_renderObject_TwoPass(renderManager, camPos, ambientColor);
break;
case afxParticlePoolData::POOL_NORMAL :
default:
pool_renderObject_Normal(renderManager, camPos, ambientColor);
}
}
void afxParticlePool::pool_renderObject_Normal(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
{
S32 n_parts = 0;
for (S32 i = 0; i < emitters.size(); i++)
n_parts += emitters[i]->n_parts;
if (n_parts == 0)
return;
ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
main_emitter_data->allocPrimBuffer(n_parts);
orderedVector.clear();
MatrixF modelview = GFX->getWorldMatrix();
Point3F viewvec; modelview.getRow(1, &viewvec);
for (U32 i=0; i < emitters.size(); i++)
{
// add each particle and a distance based sort key to orderedVector
for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
{
orderedVector.increment();
orderedVector.last().p = pp;
orderedVector.last().k = mDot(pp->pos, viewvec);
orderedVector.last().emitter = emitters[i];
}
}
// qsort the list into far to near ordering
dQsort(orderedVector.address(), orderedVector.size(), sizeof(SortParticlePool), cmpSortParticlePool);
static Vector<GFXVertexPCT> tempBuff(2048);
tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
Point3F basePoints[4];
basePoints[0] = Point3F(-1.0, 0.0, -1.0);
basePoints[1] = Point3F( 1.0, 0.0, -1.0);
basePoints[2] = Point3F( 1.0, 0.0, 1.0);
basePoints[3] = Point3F(-1.0, 0.0, 1.0);
MatrixF camView = GFX->getWorldMatrix();
camView.transpose(); // inverse - this gets the particles facing camera
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
if (emitter->mDataBlock->orientParticles)
emitter->setupOriented(particle, camPos, ambientColor, buffPtr);
else
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
buffPtr+=4;
}
// create new VB if emitter size grows
if( !mVertBuff || n_parts > mCurBuffSize )
{
mCurBuffSize = n_parts;
mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
}
// lock and copy tempBuff to video RAM
GFXVertexPCT *verts = mVertBuff.lock();
dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
mVertBuff.unlock();
//MeshRenderInst *ri = gRenderInstManager->allocInst<MeshRenderInst>();
ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
ri->vertBuff = &mVertBuff;
ri->primBuff = &main_emitter_data->primBuff;
ri->translucentSort = true;
ri->type = RenderPassManager::RIT_Particle;
ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
ri->defaultKey = (-sort_priority*100);
ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
GFX->getViewMatrix() *
GFX->getWorldMatrix() );
ri->count = n_parts;
ri->blendStyle = main_emitter_data->blendStyle;
// use first particle's texture unless there is an emitter texture to override it
if (main_emitter_data->textureHandle)
ri->diffuseTex = &*(main_emitter_data->textureHandle);
else
ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource());
ri->softnessDistance = main_emitter_data->softnessDistance;
// Sort by texture too.
//ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff;
renderManager->addInst( ri );
}
void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
{
S32 n_parts = 0;
for (S32 i = 0; i < emitters.size(); i++)
n_parts += emitters[i]->n_parts;
if (n_parts == 0)
return;
ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
main_emitter_data->allocPrimBuffer(n_parts);
orderedVector.clear();
F32 min_d=0.0f, max_d=0.0f;
for (U32 i=0; i < emitters.size(); i++)
{
if (!emitters[i]->mDataBlock->pool_depth_fade || !emitters[i]->mDataBlock->pool_radial_fade)
continue;
// add particles to orderedVector and calc distance and min/max distance
for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
{
F32 dist = (pp->pos-camPos).len();
if (dist > max_d)
max_d = dist;
else if (dist < min_d)
min_d = dist;
orderedVector.increment();
orderedVector.last().p = pp;
orderedVector.last().k = dist;
orderedVector.last().emitter = emitters[i];
}
}
// Add remaining emitters particles to the orderedVector that do not participate in the
// above depth computations:
for (U32 i=0; i < emitters.size(); i++)
{
if (emitters[i]->mDataBlock->pool_depth_fade || emitters[i]->mDataBlock->pool_radial_fade)
continue;
for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
{
orderedVector.increment();
orderedVector.last().p = pp;
orderedVector.last().k = 0; // no need to compute depth here
orderedVector.last().emitter = emitters[i];
}
}
static Vector<GFXVertexPCT> tempBuff(2048);
tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
Point3F basePoints[4];
basePoints[0] = Point3F(-1.0, 0.0, -1.0);
basePoints[1] = Point3F( 1.0, 0.0, -1.0);
basePoints[2] = Point3F( 1.0, 0.0, 1.0);
basePoints[3] = Point3F(-1.0, 0.0, 1.0);
MatrixF camView = GFX->getWorldMatrix();
camView.transpose(); // inverse - this gets the particles facing camera
//~~~~~~~~~~~~~~~~~~~~//
Point3F bbox_center; mObjBox.getCenter(&bbox_center);
F32 d_range = max_d - min_d;
bool d_safe = (d_range>0.0001);
F32 d_half = min_d + (d_range*0.5f);
//~~~~~~~~~~~~~~~~~~~~//
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
LinearColorF color_save = particle->color;
particle->color.set(mDataBlock->base_color.red, mDataBlock->base_color.green, mDataBlock->base_color.blue, mDataBlock->base_color.alpha*particle->color.alpha);
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
// create new VB if emitter size grows
if( !mVertBuff || n_parts > mCurBuffSize )
{
mCurBuffSize = n_parts;
mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
}
// lock and copy tempBuff to video RAM
GFXVertexPCT *verts = mVertBuff.lock();
dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
mVertBuff.unlock();
ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
ri->vertBuff = &mVertBuff;
ri->primBuff = &main_emitter_data->primBuff;
ri->translucentSort = true;
ri->type = RenderPassManager::RIT_Particle;
ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
ri->defaultKey = (-sort_priority*100);
ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
GFX->getViewMatrix() *
GFX->getWorldMatrix() );
ri->count = n_parts;
ri->blendStyle = ParticleRenderInst::BlendNormal;
// use first particle's texture unless there is an emitter texture to override it
//if (main_emitter_data->textureHandle)
// ri->diffuseTex = &*(main_emitter_data->textureHandle);
//else
ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureExtResource());
F32 save_sort_dist = ri->sortDistSq;
ri->softnessDistance = main_emitter_data->softnessDistance;
renderManager->addInst( ri );
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// 2nd-pass
buffPtr = tempBuff.address();
bbox_center.z = mObjBox.minExtents.z;
F32 max_radius = (max_d-min_d)*0.5f;
// gather fade settings
bool do_mixed_fades = false;
bool do_radial_fades = (emitters[0]->mDataBlock->pool_radial_fade && (max_radius>0.0001f));
bool do_depth_fades = (emitters[0]->mDataBlock->pool_depth_fade && d_safe);
for (U32 i = 1; i < emitters.size(); i++)
{
if ( (do_radial_fades != (emitters[i]->mDataBlock->pool_radial_fade && (max_radius>0.0001f))) ||
(do_depth_fades != (emitters[i]->mDataBlock->pool_depth_fade && d_safe)))
{
do_mixed_fades = true;
break;
}
}
if (do_mixed_fades)
{
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
F32 bf = 1.0; // blend factor
// blend factor due to radius
if (emitter->mDataBlock->pool_radial_fade && (max_radius>0.0001f))
{
F32 p_radius = (particle->pos-bbox_center).len();
F32 bf_radius = p_radius/max_radius;
if (bf_radius>1.0f) bf_radius = 1.0f;
bf *= bf_radius*bf_radius; // quadratic for faster falloff
}
// blend factor, depth based
if (emitter->mDataBlock->pool_depth_fade && d_safe && (orderedVector[i].k > d_half))
{
F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
bf *= bf_depth;
}
// overall blend factor weight
bf *= mDataBlock->blend_weight;
LinearColorF color_save = particle->color;
particle->color = particle->color*bf;
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
}
else if (do_radial_fades && do_depth_fades)
{
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
F32 bf = 1.0; // blend factor
// blend factor due to radius
F32 p_radius = (particle->pos-bbox_center).len();
F32 bf_radius = p_radius/max_radius;
if (bf_radius>1.0f) bf_radius = 1.0f;
bf *= bf_radius*bf_radius; // quadratic for faster falloff
// blend factor, depth based
if (orderedVector[i].k > d_half)
{
F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
bf *= bf_depth;
}
// overall blend factor weight
bf *= mDataBlock->blend_weight;
LinearColorF color_save = particle->color;
particle->color = particle->color*bf;
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
}
else if (do_radial_fades) // && !do_depth_fades
{
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
F32 bf = 1.0; // blend factor
// blend factor due to radius
F32 p_radius = (particle->pos-bbox_center).len();
F32 bf_radius = p_radius/max_radius;
if (bf_radius>1.0f) bf_radius = 1.0f;
bf *= bf_radius*bf_radius; // quadratic for faster falloff
// overall blend factor weight
bf *= mDataBlock->blend_weight;
LinearColorF color_save = particle->color;
particle->color = particle->color*bf;
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
}
else if (do_depth_fades) // && !do_radial_fades
{
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
F32 bf = 1.0; // blend factor
// blend factor, depth based
if (orderedVector[i].k > d_half)
{
F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
bf *= bf_depth;
}
// overall blend factor weight
bf *= mDataBlock->blend_weight;
LinearColorF color_save = particle->color;
particle->color = particle->color*bf;
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
}
else // (no fades)
{
for (U32 i = 0; i < orderedVector.size(); i++)
{
Particle* particle = orderedVector[i].p;
ParticleEmitter* emitter = orderedVector[i].emitter;
F32 bf = mDataBlock->blend_weight; // blend factor
LinearColorF color_save = particle->color;
particle->color = particle->color*bf;
emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
particle->color = color_save;
buffPtr+=4;
}
}
// create new VB if emitter size grows
if( !mVertBuff2 || n_parts > mCurBuffSize2 )
{
mCurBuffSize2 = n_parts;
mVertBuff2.set(GFX, n_parts*4, GFXBufferTypeDynamic);
}
// lock and copy tempBuff to video RAM
verts = mVertBuff2.lock();
dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
mVertBuff2.unlock();
ri = renderManager->allocInst<ParticleRenderInst>();
ri->vertBuff = &mVertBuff2;
ri->primBuff = &main_emitter_data->primBuff;
ri->translucentSort = true;
ri->type = RenderPassManager::RIT_Particle;
ri->sortDistSq = save_sort_dist;
ri->defaultKey = (-sort_priority*100) + 1;
ri->modelViewProj = renderManager->allocUniqueXform( GFX->getProjectionMatrix() *
GFX->getViewMatrix() *
GFX->getWorldMatrix() );
ri->count = n_parts;
ri->blendStyle = ParticleRenderInst::BlendAdditive;
// use first particle's texture unless there is an emitter texture to override it
if (main_emitter_data->textureHandle)
ri->diffuseTex = &*(main_emitter_data->textureHandle);
else
ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->getTextureResource());
ri->softnessDistance = main_emitter_data->softnessDistance;
renderManager->addInst( ri );
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//