Add all new AFX files

This commit is contained in:
Marc Chapman 2017-07-26 09:35:44 +01:00
parent 3d7c1bbbf7
commit d7a8510756
218 changed files with 54970 additions and 0 deletions

View file

@ -0,0 +1,280 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "afx/util/afxAnimCurve.h"
afxAnimCurve::afxAnimCurve() : usable( false ), final_value( 0.0f ), start_value( 0.0f )
{
evaluator = new afxHermiteEval();
}
afxAnimCurve::~afxAnimCurve()
{
delete evaluator;
}
void afxAnimCurve::addKey( Point2F &v )
{
Key k;
k.time = v.x;
k.value = v.y;
keys.push_back( k );
usable = false;
}
void afxAnimCurve::addKey( F32 time, F32 value )
{
Key k;
k.time = time;
k.value = value;
keys.push_back( k );
usable = false;
}
void afxAnimCurve::setKeyTime( int index, F32 t )
{
if( ( index < 0 ) || ( index >= keys.size() ) )
return;
Key &k = keys[index];
k.time = t;
usable = false;
}
void afxAnimCurve::setKeyValue( int index, F32 v )
{
if( ( index < 0 ) || ( index >= keys.size() ) )
return;
Key &k = keys[index];
k.value = v;
if( index == 0 )
start_value = v;
else if( index == keys.size()-1 )
final_value = v;
}
//bool afxAnimCurve::compare_Key( const afxAnimCurve::Key &a, const afxAnimCurve::Key &b )
//{
// return a.time < b.time;
//}
S32 QSORT_CALLBACK afxAnimCurve::compare_Key( const void* a, const void* b )
{
const Key *key_a = (Key *)a;
const Key *key_b = (Key *)b;
//Con::printf( "*** %f %f", key_a->time, key_b->time );
//return key_a->time < key_b->time;
if (key_a->time > key_b->time)
return 1;
else if (key_a->time < key_b->time)
return -1;
else
return 0;
}
void afxAnimCurve::sort( )
{
if( keys.size() == 0 )
return;
//std::sort( keys.begin(), keys.end(), afxAnimCurve::compare_Key );
dQsort( keys.address(), keys.size(), sizeof(Key), afxAnimCurve::compare_Key );
start_value = keys[0].value;
final_value = keys[keys.size()-1].value;
start_time = keys[0].time;
final_time = keys[keys.size()-1].time;
usable = true;
}
int afxAnimCurve::numKeys()
{
return keys.size();
}
F32 afxAnimCurve::getKeyTime( int index )
{
if( ( index < 0 ) || ( index >= keys.size() ) )
return 0.0f;
Key &k = keys[index];
return k.time;
}
F32 afxAnimCurve::getKeyValue( int index )
{
if( ( index < 0 ) || ( index >= keys.size() ) )
return 0.0f;
Key &k = keys[index];
return k.value;
}
Point2F afxAnimCurve::getSegment( F32 time )
{
Point2F segment( 0, 0 );
if( keys.size() == 0 )
return segment;
int start_index = 0;
for( ; start_index < keys.size()-1; start_index++ )
{
if( time < keys[start_index+1].time )
break;
}
int end_index = start_index+1;
segment.x = (F32)start_index;
segment.y = (F32)end_index;
return segment;
}
F32 afxAnimCurve::evaluate( F32 time )
{
if( !usable )
return 0.0f;
if( time <= start_time )
return start_value;
if( time >= final_time )
return final_value;
if( keys.size() == 1 )
return start_value;
int start_index = 0;
for( ; start_index < keys.size()-1; start_index++ )
{
if( time < keys[start_index+1].time )
break;
}
int end_index = start_index+1;
Key k0 = keys[start_index];
Key k1 = keys[end_index];
Point2F v0( (F32) k0.time, k0.value );
Point2F v1( (F32) k1.time, k1.value );
// Compute tangents
Point2F tan0 = computeTangentK0( v0, v1, start_index );
Point2F tan1 = computeTangentK1( v0, v1, end_index );
F32 time_perc = (F32)( time - k0.time ) / (F32)( k1.time - k0.time );
Point2F vnew = evaluator->evaluateCurve( v0,
v1,
tan0,
tan1,
time_perc );
return vnew.y;
}
Point2F afxAnimCurve::computeTangentK0( Point2F &k0, Point2F &k1, int start_index )
{
Point2F tan0;
Point2F k_prev;
Point2F k_next;
// tangent for k0
if( start_index == 0 )
{
k_prev = k0; // Setting previous point to k0, creating a hidden point in
// the same spot
k_next = k1;
}
else
{
Key &k = keys[start_index-1];
k_prev.set( k.time, k.value );
k_next = k1;
}
tan0 = k_next-k_prev; //k_next.subtract( k_prev );
tan0 *= .5f;
return tan0;
}
Point2F afxAnimCurve::computeTangentK1( Point2F &k0, Point2F &k1, int end_index )
{
Point2F tan1;
Point2F k_prev;
Point2F k_next;
// tangent for k1
if( end_index == keys.size()-1 )
{
k_prev = k0;
k_next = k1; // Setting next point to k1, creating a hidden point in
// the same spot
}
else
{
k_prev = k0;
Key &k = keys[end_index+1];
k_next.set( k.time, k.value );
}
tan1 = k_next-k_prev; //k_next.subtract( k_prev );
tan1 *= .5f;
return tan1;
}
void afxAnimCurve::print()
{
Con::printf( "afxAnimCurve -------------------------" );
for( int i = 0; i < keys.size(); i++ )
{
Key &k = keys[i];
Con::printf( "%f: %f", k.time, k.value );
}
Con::printf( "-----------------------------------" );
}
void afxAnimCurve::printKey( int index )
{
Key &k = keys[index];
Con::printf( "%f: %f", k.time, k.value );
}

View file

@ -0,0 +1,82 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_ANIM_CURVE_H_
#define _AFX_ANIM_CURVE_H_
#include "core/util/tVector.h"
#include "afx/util/afxCurveEval.h"
class afxAnimCurve
{
class Key
{
public:
F32 time;
F32 value;
};
private:
afxCurveEval* evaluator;
F32 final_value;
F32 start_value;
F32 final_time;
F32 start_time;
bool usable;
//std::vector<Key> keys;
Vector<Key> keys;
//static bool compare_Key( const Key &a, const Key &b );
static S32 QSORT_CALLBACK compare_Key( const void* a, const void* b );
public:
afxAnimCurve();
~afxAnimCurve();
void addKey( Point2F &v );
void addKey( F32 time, F32 value );
void setKeyTime( int index, F32 t );
void setKeyValue( int index, F32 v );
void sort( );
int numKeys();
F32 getKeyTime( int index );
F32 getKeyValue( int index );
Point2F getSegment( F32 time );
F32 evaluate( F32 time );
void print();
void printKey( int index );
private:
Point2F computeTangentK0( Point2F &k0, Point2F &k1, int start_index );
Point2F computeTangentK1( Point2F &k0, Point2F &k1, int end_index );
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_ANIM_CURVE_H_

View file

@ -0,0 +1,332 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "afx/util/afxCurveEval.h"
#include "afx/util/afxCurve3D.h"
afxCurve3D::afxCurve3D() : usable( false ), default_vector( 0, 0, 0 )
{
evaluator = new afxHermiteEval();
}
afxCurve3D::~afxCurve3D()
{
delete evaluator;
}
void afxCurve3D::addPoint( F32 param, Point3F &v )
{
if( param < 0.0f || param > 1.0f )
return;
CurvePoint p;
p.parameter = param;
p.point.set( v );
points.push_back( p );
usable = false;
}
void afxCurve3D::setPoint( int index, Point3F &v )
{
if( ( index < 0 ) || ( index >= points.size() ) )
return;
CurvePoint &p = points[index];
p.point = v;
if( index == 0 )
start_value = v;
else if( index == points.size()-1 )
final_value = v;
}
//bool afxCurve3D::compare_CurvePoint( const afxCurve3D::CurvePoint &a, const afxCurve3D::CurvePoint &b )
//{
// return a.parameter < b.parameter;
//}
S32 QSORT_CALLBACK afxCurve3D::compare_CurvePoint( const void* a, const void* b )
{
//CurvePoint *cp_a = *((CurvePoint **)a);
//CurvePoint *cp_b = *((CurvePoint **)b);
const CurvePoint *cp_a = (CurvePoint *)a;
const CurvePoint *cp_b = (CurvePoint *)b;
//Con::printf( "*** %f %f", cp_a->parameter, cp_b->parameter );
//return cp_a->parameter < cp_b->parameter;
//return 1;
if (cp_a->parameter > cp_b->parameter)
return 1;
else if (cp_a->parameter < cp_b->parameter)
return -1;
else
return 0;
}
void afxCurve3D::sort( )
{
if( points.size() == 0 )
return;
if( points.size() == 1 )
{
start_value = points[0].point;
final_value = start_value;
usable = true;
return;
}
//Con::printf( "*** pre-sort" );
//std::sort( points.begin(), points.end(), afxCurve3D::compare_CurvePoint );
dQsort( points.address(), points.size(), sizeof(CurvePoint), afxCurve3D::compare_CurvePoint );
//Con::printf( "*** post-sort" );
start_value = points[0].point;
final_value = points[points.size()-1].point;
usable = true;
start_tangent = evaluateTangent( 0.0f );
final_tangent = evaluateTangent( 1.0f );
}
int afxCurve3D::numPoints()
{
return points.size();
}
F32 afxCurve3D::getParameter( int index )
{
if( ( index < 0 ) || ( index >= points.size() ) )
return 0.0f;
return points[index].parameter;
}
Point3F afxCurve3D::getPoint( int index )
{
if( ( index < 0 ) || ( index >= points.size() ) )
return default_vector;
return points[index].point;
}
Point3F afxCurve3D::evaluate( F32 param )
{
if( !usable )
return default_vector;
if( param <= 0.0f )
return start_value;
if( param >= 1.0f )
return final_value;
if( points.size() == 1 )
return start_value;
int start_index = 0;
for( ; start_index < points.size()-1; start_index++ )
{
if( param < points[start_index+1].parameter )
break;
}
int end_index = start_index+1;
CurvePoint p0 = points[start_index];
CurvePoint p1 = points[end_index];
// Compute tangents
//Point3F tan0 = computeTangentP0( p0.point, p1.point, start_index );
//Point3F tan1 = computeTangentP1( p0.point, p1.point, end_index );
F32 local_param = ( param - p0.parameter ) / ( p1.parameter - p0.parameter );
//Point3F vnew = evaluator->evaluateCurve( p0.point,
// p1.point,
// tan0,
// tan1,
// local_param );
Point3F vnew = evaluator->evaluateCurve( p0.point, p1.point,
p0.tangent, p1.tangent,
local_param );
return vnew;
}
Point3F afxCurve3D::evaluateTangent( F32 param )
{
if( !usable )
return default_vector;
if( param < 0.0f )
return start_tangent;
if( param > 1.0f )
return final_tangent;
if( points.size() == 1 )
return start_tangent;
int start_index = 0;
for( ; start_index < points.size()-1; start_index++ )
{
if( param < points[start_index+1].parameter )
break;
}
int end_index = start_index+1;
if( param == 1.0f )
{
end_index = points.size()-1;
start_index = end_index - 1;
}
CurvePoint p0 = points[start_index];
CurvePoint p1 = points[end_index];
// Compute tangents
//Point3F tan0 = computeTangentP0( p0.point, p1.point, start_index );
//Point3F tan1 = computeTangentP1( p0.point, p1.point, end_index );
F32 local_param = ( param - p0.parameter ) / ( p1.parameter - p0.parameter );
//Point3F vnew = evaluator->evaluateCurveTangent( p0.point,
// p1.point,
// tan0,
// tan1,
// local_param );
Point3F vnew = evaluator->evaluateCurveTangent( p0.point, p1.point,
p0.tangent, p1.tangent,
local_param );
return vnew;
}
Point3F afxCurve3D::computeTangentP0( Point3F &p0, Point3F &p1, int start_index )
{
Point3F tan0;
Point3F p_prev;
Point3F p_next;
// tangent for p0
if( start_index == 0 )
{
p_prev = p0; // Setting previous point to p0, creating a hidden point in
// the same spot
p_next = p1;
}
else
{
CurvePoint &p = points[start_index-1];
p_prev = p.point;
p_next = p1;
}
tan0 = p_next-p_prev; //p_next.subtract( p_prev );
tan0 *= .5f; //= tan0.scale( .5f );
return tan0;
}
Point3F afxCurve3D::computeTangentP1( Point3F &p0, Point3F &p1, int end_index )
{
Point3F tan1;
Point3F p_prev;
Point3F p_next;
// tangent for p1
if( end_index == points.size()-1 )
{
p_prev = p0;
p_next = p1; // Setting next point to p1, creating a hidden point in
// the same spot
}
else
{
p_prev = p0;
CurvePoint &p = points[end_index+1];
p_next = p.point;
}
tan1 = p_next-p_prev; //p_next.subtract( p_prev );
tan1 *= .5f; //= tan1.scale( .5f );
//Con::printf("UPDATE");
return tan1;
}
void afxCurve3D::computeTangents()
{
CurvePoint *p_prev;
CurvePoint *p_next;
for( int i = 0; i < points.size(); i++ )
{
CurvePoint *p = &points[i];
if( i == 0 )
{
p_prev = p; // Setting previous point to p0, creating a hidden point in
// the same spot
p_next = &points[i+1];
}
else if( i == points.size()-1 )
{
p_prev = &points[i-1];
p_next = p; // Setting next point to p1, creating a hidden point in
// the same spot
}
else
{
p_prev = &points[i-1];
p_next = &points[i+1];
}
p->tangent = p_next->point - p_prev->point;
//(p->tangent).normalize();
p->tangent *= .5f;
//Con::printf( "%d: %f %f %f", i, p->tangent.x, p->tangent.y, p->tangent.z );
}
}
void afxCurve3D::print()
{
Con::printf( "afxCurve3D -------------------------" );
for( int i = 0; i < points.size(); i++ )
{
CurvePoint &p = points[i];
Con::printf( "%f: %f %f %f", p.parameter, p.point.x, p.point.y, p.point.z );
}
Con::printf( "---------------------------------" );
}

View file

@ -0,0 +1,92 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_CURVE_3D_H_
#define _AFX_CURVE_3D_H_
#include "core/util/tVector.h"
#include "math/mPoint3.h"
class afxCurveEval;
class afxCurve3D
{
class CurvePoint
{
public:
F32 parameter;
Point3F point;
// new:
Point3F tangent;
};
private:
afxCurveEval* evaluator;
Point3F start_value;
Point3F final_value;
Point3F start_tangent;
Point3F final_tangent;
bool usable;
//std::vector<CurvePoint> points;
Vector<CurvePoint> points;
Point3F default_vector;
//static bool compare_CurvePoint( const CurvePoint &a, const CurvePoint &b );
static S32 QSORT_CALLBACK compare_CurvePoint( const void* a, const void* b );
// new
Point3F last_tangent;
bool flip;
public:
afxCurve3D();
~afxCurve3D();
void addPoint( F32 param, Point3F &v );
void setPoint( int index, Point3F &v );
void sort( );
int numPoints();
F32 getParameter( int index );
Point3F getPoint( int index );
Point3F evaluate( F32 param );
Point3F evaluateTangent( F32 param );
void print();
void computeTangents();
//MatrixF createOrientFromDir( Point3F &direction );
private:
Point3F computeTangentP0( Point3F &p0, Point3F &p1, int start_index );
Point3F computeTangentP1( Point3F &p0, Point3F &p1, int end_index );
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_CURVE_3D_H_

View file

@ -0,0 +1,122 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "afx/util/afxCurveEval.h"
Point2F afxHermiteEval::evaluateCurve( Point2F &v0, Point2F &v1,
Point2F &t0, Point2F &t1, F32 t )
{
F32 t_3 = t*t*t;
F32 t_2 = t*t;
F32 h1 = ( 2.0f * t_3 ) - ( 3.0f * t_2 ) + 1;
F32 h2 = (-2.0f * t_3 ) + ( 3.0f * t_2 );
F32 h3 = t_3 - ( 2.0f * t_2 ) + t;
F32 h4 = t_3 - t_2;
Point2F v(
(h1*v0.x)+(h2*v1.x)+(h3*t0.x)+(h4*t1.x),
(h1*v0.y)+(h2*v1.y)+(h3*t0.y)+(h4*t1.y) );
return v;
}
Point2F afxHermiteEval::evaluateCurve( Point2F &v0, Point2F &v1, F32 t )
{
Point2F tangent( 1, 0 );
return( evaluateCurve( v0, v1, tangent, tangent, t ) );
}
Point2F afxHermiteEval::evaluateCurveTangent( Point2F &v0, Point2F &v1,
Point2F &t0, Point2F &t1, F32 t )
{
F32 t_2 = t*t;
F32 h1_der = ( 6.0f * t_2 ) - ( 6.0f * t );
F32 h2_der = (-6.0f * t_2 ) + ( 6.0f * t );
F32 h3_der = ( 3.0f * t_2 ) - ( 4.0f * t ) + 1;
F32 h4_der = ( 3.0f * t_2 ) - ( 2.0f * t );
Point2F tangent(
(h1_der*v0.x)+(h2_der*v1.x)+(h3_der*t0.x)+(h4_der*t1.x),
(h1_der*v0.y)+(h2_der*v1.y)+(h3_der*t0.y)+(h4_der*t1.y) );
return tangent;
}
Point2F afxHermiteEval::evaluateCurveTangent( Point2F &v0, Point2F &v1, F32 t )
{
Point2F tangent( 1, 0 );
return( evaluateCurveTangent( v0, v1, tangent, tangent, t ) );
}
Point3F afxHermiteEval::evaluateCurve( Point3F &v0, Point3F &v1,
Point3F &t0, Point3F &t1, F32 t )
{
F32 t_3 = t*t*t;
F32 t_2 = t*t;
F32 h1 = ( 2.0f * t_3 ) - ( 3.0f * t_2 ) + 1;
F32 h2 = (-2.0f * t_3 ) + ( 3.0f * t_2 );
F32 h3 = t_3 - ( 2.0f * t_2 ) + t;
F32 h4 = t_3 - t_2;
Point3F v(
(h1*v0.x)+(h2*v1.x)+(h3*t0.x)+(h4*t1.x),
(h1*v0.y)+(h2*v1.y)+(h3*t0.y)+(h4*t1.y),
(h1*v0.z)+(h2*v1.z)+(h3*t0.z)+(h4*t1.z) );
return v;
}
Point3F afxHermiteEval::evaluateCurve( Point3F &v0, Point3F &v1, F32 t )
{
Point3F tangent( 1, 0, 0 );
return( evaluateCurve( v0, v1, tangent, tangent, t ) );
}
Point3F afxHermiteEval::evaluateCurveTangent( Point3F &v0, Point3F &v1,
Point3F &t0, Point3F &t1, F32 t )
{
F32 t_2 = t*t;
F32 h1_der = ( 6.0f * t_2 ) - ( 6.0f * t );
F32 h2_der = (-6.0f * t_2 ) + ( 6.0f * t );
F32 h3_der = ( 3.0f * t_2 ) - ( 4.0f * t ) + 1;
F32 h4_der = ( 3.0f * t_2 ) - ( 2.0f * t );
Point3F tangent(
(h1_der*v0.x)+(h2_der*v1.x)+(h3_der*t0.x)+(h4_der*t1.x),
(h1_der*v0.y)+(h2_der*v1.y)+(h3_der*t0.y)+(h4_der*t1.y),
(h1_der*v0.z)+(h2_der*v1.z)+(h3_der*t0.z)+(h4_der*t1.z) );
return tangent;
}
Point3F afxHermiteEval::evaluateCurveTangent( Point3F &v0, Point3F &v1, F32 t )
{
Point3F tangent( 1, 0, 0 );
return( evaluateCurveTangent( v0, v1, tangent, tangent, t ) );
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,62 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_CURVE_EVAL_BASE_H_
#define _AFX_CURVE_EVAL_BASE_H_
#include "math/mPoint2.h"
#include "math/mPoint3.h"
class afxCurveEval
{
public:
virtual Point2F evaluateCurve(Point2F& v0, Point2F& v1, F32 t)=0;
virtual Point2F evaluateCurve(Point2F& v0, Point2F& v1, Point2F& t0, Point2F& t1, F32 t)=0;
virtual Point2F evaluateCurveTangent(Point2F& v0, Point2F& v1, F32 t)=0;
virtual Point2F evaluateCurveTangent(Point2F& v0, Point2F& v1, Point2F& t0, Point2F& t1, F32 t)=0;
virtual Point3F evaluateCurve(Point3F& v0, Point3F& v1, F32 t)=0;
virtual Point3F evaluateCurve(Point3F& v0, Point3F& v1, Point3F& t0, Point3F& t1, F32 t)=0;
virtual Point3F evaluateCurveTangent(Point3F& v0, Point3F& v1, F32 t)=0;
virtual Point3F evaluateCurveTangent(Point3F& v0, Point3F& v1, Point3F& t0, Point3F& t1, F32 t)=0;
};
class afxHermiteEval : public afxCurveEval
{
public:
Point2F evaluateCurve(Point2F& v0, Point2F& v1, F32 t);
Point2F evaluateCurve(Point2F& v0, Point2F& v1, Point2F& t0, Point2F& t1, F32 t);
Point2F evaluateCurveTangent(Point2F& v0, Point2F& v1, F32 t);
Point2F evaluateCurveTangent(Point2F& v0, Point2F& v1, Point2F& t0, Point2F& t1, F32 t);
Point3F evaluateCurve(Point3F& v0, Point3F& v1, F32 t);
Point3F evaluateCurve(Point3F& v0, Point3F& v1, Point3F& t0, Point3F& t1, F32 t);
Point3F evaluateCurveTangent(Point3F& v0, Point3F& v1, F32 t);
Point3F evaluateCurveTangent(Point3F& v0, Point3F& v1, Point3F& t0, Point3F& t1, F32 t);
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_CURVE_EVAL_BASE_H_

View file

@ -0,0 +1,98 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "afxEase.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
F32
afxEase::t(F32 t, F32 ein, F32 eout)
{
if (t == 0.0)
return 0.0;
if (t == 1.0)
return 1.0;
F32 ee = eout - ein + 1.0;
// ease in section
if (t <= ein)
{
F32 tin = t/ein;
return (mSin(M_PI_F*(tin - 1.0)) + M_PI_F*tin)*ein*(1.0/M_PI_F)/ee;
}
// middle linear section
else if (t <= eout)
{
return (2.0*t - ein)/ee;
}
// ease out section
else
{
F32 iout = 1.0 - eout;
F32 g = (t - eout)*M_PI_F/iout;
return ((mSin(g) + g)*(iout)/M_PI_F + 2.0*eout - ein)*1.0/ee + 0.0;
}
}
F32
afxEase::eq(F32 t, F32 a, F32 b, F32 ein, F32 eout)
{
if (t == 0.0)
return a;
if (t == 1.0)
return b;
F32 ab = b - a;
F32 ee = eout - ein + 1.0;
// ease in section
if (t <= ein)
{
F32 tin = t/ein;
return a + (mSin(M_PI_F*(tin - 1.0)) + M_PI_F*tin)*ab*ein*(1.0/M_PI_F)/ee;
}
// middle linear section
else if (t <= eout)
{
return a + ab*(2.0*t - ein)/ee;
}
// ease out section
else
{
F32 iout = 1.0 - eout;
F32 g = (t - eout)*M_PI_F/iout;
return ((mSin(g) + g)*(iout)/M_PI_F + 2.0*eout - ein)*ab/ee + a;
}
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,41 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_EASE_H_
#define _AFX_EASE_H_
#include "platform/platform.h"
class afxEase
{
public:
static F32 t(F32 t, F32 ein, F32 eout);
static F32 eq(F32 t, F32 a, F32 b, F32 ein, F32 eout);
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_EASE_H_

View file

@ -0,0 +1,233 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "T3D/fx/particleEmitter.h"
#include "afx/afxChoreographer.h"
#include "afx/util/afxParticlePool.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
IMPLEMENT_CO_DATABLOCK_V1(afxParticlePoolData);
ConsoleDocClass( afxParticlePoolData,
"@brief A ParticlePool datablock.\n\n"
"@ingroup afxUtil\n"
"@ingroup AFX\n"
);
Vector<afxParticlePool::SortParticlePool> afxParticlePool::orderedVector;
afxParticlePoolData::afxParticlePoolData()
{
pool_type = POOL_NORMAL;
base_color.set(0.0f, 0.0f, 0.0f, 1.0f);
blend_weight = 1.0f;
}
afxParticlePoolData::afxParticlePoolData(const afxParticlePoolData& other, bool temp_clone) : GameBaseData(other, temp_clone)
{
pool_type = other.pool_type;
base_color = other.base_color;
blend_weight = other.blend_weight;
}
ImplementEnumType( afxParticlePool_PoolType, "Possible particle pool types.\n" "@ingroup afxParticlePool\n\n" )
{ afxParticlePoolData::POOL_NORMAL, "normal", "..." },
{ afxParticlePoolData::POOL_TWOPASS, "two-pass", "..." },
EndImplementEnumType;
afxParticlePoolData::~afxParticlePoolData()
{
}
void afxParticlePoolData::initPersistFields()
{
addField("poolType", TYPEID< afxParticlePoolData::PoolType >(), Offset(pool_type, afxParticlePoolData),
"...");
addField("baseColor", TypeColorF, Offset(base_color, afxParticlePoolData),
"...");
addField("blendWeight", TypeF32, Offset(blend_weight, afxParticlePoolData),
"...");
Parent::initPersistFields();
};
void afxParticlePoolData::packData(BitStream* stream)
{
Parent::packData(stream);
stream->write(pool_type);
stream->write(base_color);
stream->write(blend_weight);
};
void afxParticlePoolData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
stream->read(&pool_type);
stream->read(&base_color);
stream->read(&blend_weight);
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
IMPLEMENT_CO_NETOBJECT_V1(afxParticlePool);
ConsoleDocClass( afxParticlePool,
"@brief A ParticlePool object as defined by an afxParticlePoolData datablock.\n\n"
"@ingroup afxUtil\n"
"@ingroup AFX\n"
);
afxParticlePool::afxParticlePool()
{
mDataBlock = 0;
key_block = 0;
key_index = 0;
choreographer = 0;
sort_priority = S8_MAX;
mNetFlags.set(IsGhost);
mTypeMask |= StaticObjectType;
mCurBuffSize = mCurBuffSize2 = 0;
};
afxParticlePool::~afxParticlePool()
{
for (S32 i = 0; i < emitters.size(); i++)
if (emitters[i])
emitters[i]->clearPool();
if (choreographer)
choreographer->unregisterParticlePool(this);
if (mDataBlock && mDataBlock->isTempClone())
{
delete mDataBlock;
mDataBlock = 0;
}
}
bool afxParticlePool::onNewDataBlock(GameBaseData* dptr, bool reload)
{
mDataBlock = dynamic_cast<afxParticlePoolData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
return false;
return true;
}
bool afxParticlePool::onAdd()
{
if (!Parent::onAdd())
return false;
mObjBox.minExtents.set(-0.5, -0.5, -0.5);
mObjBox.maxExtents.set( 0.5, 0.5, 0.5);
resetWorldBox();
addToScene();
return true;
};
void afxParticlePool::onRemove()
{
removeFromScene();
Parent::onRemove();
};
void afxParticlePool::addParticleEmitter(ParticleEmitter* emitter)
{
emitters.push_back(emitter);
}
void afxParticlePool::removeParticleEmitter(ParticleEmitter* emitter)
{
for (U32 i=0; i < emitters.size(); i++)
if (emitters[i] == emitter)
{
emitters.erase(i);
break;
}
if (emitters.empty())
{
if (choreographer)
{
choreographer->unregisterParticlePool(this);
choreographer = 0;
}
Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + 500);
}
}
void afxParticlePool::updatePoolBBox(ParticleEmitter* emitter)
{
if (emitter->mObjBox.minExtents.x < mObjBox.minExtents.x)
mObjBox.minExtents.x = emitter->mObjBox.minExtents.x;
if (emitter->mObjBox.minExtents.y < mObjBox.minExtents.y)
mObjBox.minExtents.y = emitter->mObjBox.minExtents.y;
if (emitter->mObjBox.minExtents.z < mObjBox.minExtents.z)
mObjBox.minExtents.z = emitter->mObjBox.minExtents.z;
if (emitter->mObjBox.maxExtents.x > mObjBox.maxExtents.x)
mObjBox.maxExtents.x = emitter->mObjBox.maxExtents.x;
if (emitter->mObjBox.maxExtents.y > mObjBox.maxExtents.y)
mObjBox.maxExtents.y = emitter->mObjBox.maxExtents.y;
if (emitter->mObjBox.maxExtents.z > mObjBox.maxExtents.z)
mObjBox.maxExtents.z = emitter->mObjBox.maxExtents.z;
resetWorldBox();
}
void afxParticlePool::setSortPriority(S8 priority)
{
if (priority < sort_priority)
sort_priority = (priority == 0) ? 1 : priority;
}
int QSORT_CALLBACK afxParticlePool::cmpSortParticlePool(const void* p1, const void* p2)
{
const SortParticlePool* sp1 = (const SortParticlePool*)p1;
const SortParticlePool* sp2 = (const SortParticlePool*)p2;
if (sp2->k > sp1->k)
return 1;
else if (sp2->k == sp1->k)
return 0;
else
return -1;
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,143 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_PARTICLE_POOL_H_
#define _AFX_PARTICLE_POOL_H_
class afxParticlePoolData : public GameBaseData
{
private:
typedef GameBaseData Parent;
public:
enum PoolType
{
POOL_NORMAL,
POOL_TWOPASS
};
U32 pool_type;
LinearColorF base_color;
F32 blend_weight;
public:
/*C*/ afxParticlePoolData();
/*C*/ afxParticlePoolData(const afxParticlePoolData&, bool = false);
/*D*/ ~afxParticlePoolData();
virtual void packData(BitStream*);
virtual void unpackData(BitStream*);
virtual bool allowSubstitutions() const { return true; }
static void initPersistFields();
DECLARE_CONOBJECT(afxParticlePoolData);
DECLARE_CATEGORY("AFX");
};
typedef afxParticlePoolData::PoolType afxParticlePool_PoolType;
DefineEnumType( afxParticlePool_PoolType );
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
struct Particle;
class ParticleEmitter;
class afxChoreographer;
typedef Vector<ParticleEmitter*> ParticleEmitterList;
class afxParticlePool : public GameBase
{
typedef GameBase Parent;
class ObjectDeleteEvent : public SimEvent
{
public:
void process(SimObject *obj) { if (obj) obj->deleteObject(); }
};
struct SortParticlePool
{
Particle* p;
F32 k; // interpreted differently depending on rendering method
ParticleEmitter* emitter;
};
private:
afxParticlePoolData* mDataBlock;
afxParticlePoolData* key_block;
U32 key_index;
ParticleEmitterList emitters;
afxChoreographer* choreographer;
S8 sort_priority;
static Vector<SortParticlePool> orderedVector;
static int QSORT_CALLBACK cmpSortParticlePool(const void* p1, const void* p2);
S32 mCurBuffSize;
GFXVertexBufferHandle<GFXVertexPCT> mVertBuff;
S32 mCurBuffSize2;
GFXVertexBufferHandle<GFXVertexPCT> mVertBuff2;
protected:
virtual void prepRenderImage(SceneRenderState*);
void pool_prepBatchRender(RenderPassManager*, const Point3F &camPos, const LinearColorF &ambientColor);
void pool_renderObject_Normal(RenderPassManager*, const Point3F &camPos, const LinearColorF &ambientColor);
void pool_renderObject_TwoPass(RenderPassManager*, const Point3F &camPos, const LinearColorF &ambientColor);
virtual bool onAdd();
virtual void onRemove();
void renderBillboardParticle_blend(Particle&, const Point3F* basePnts, const MatrixF& camView, const F32 spinFactor,
const F32 blend_factor, ParticleEmitter*);
void renderBillboardParticle_color(Particle&, const Point3F* basePnts, const MatrixF& camView, const F32 spinFactor,
const LinearColorF& color, ParticleEmitter*);
public:
/*C*/ afxParticlePool();
/*D*/ ~afxParticlePool();
virtual bool onNewDataBlock(GameBaseData* dptr, bool reload);
void addParticleEmitter(ParticleEmitter*);
void removeParticleEmitter(ParticleEmitter*);
void setChoreographer(afxChoreographer* ch) { choreographer = ch; }
void setKeyBlock(afxParticlePoolData* db, U32 idx) { key_block = db; key_index = idx; }
bool hasMatchingKeyBlock(const afxParticlePoolData* db, U32 idx) const { return (db == key_block && idx == key_index); }
void updatePoolBBox(ParticleEmitter*);
void setSortPriority(S8 priority);
DECLARE_CONOBJECT(afxParticlePool);
DECLARE_CATEGORY("AFX");
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_PARTICLE_POOL_H_

View file

@ -0,0 +1,491 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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]->textureHandle);
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]->textureExtHandle);
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]->textureHandle);
ri->softnessDistance = main_emitter_data->softnessDistance;
renderManager->addInst( ri );
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,530 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "afx/util/afxPath.h"
#include "afx/util/afxPath3D.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// afxPathData
IMPLEMENT_CO_DATABLOCK_V1(afxPathData);
ConsoleDocClass( afxPathData,
"@brief A datablock for specifiying a 3D path for use with AFX.\n\n"
"@ingroup afxUtil\n"
"@ingroup AFX\n"
"@ingroup Datablocks\n"
);
StringTableEntry afxPathData::POINTS_FIELD;
StringTableEntry afxPathData::ROLL_FIELD;
StringTableEntry afxPathData::TIMES_FIELD;
ImplementEnumType( afxPath3DLoopType, "Possible loop types for an afxPath.\n" "@ingroup afxPath\n\n" )
{ afxPath3D::LOOP_CONSTANT, "constant", "..." },
{ afxPath3D::LOOP_CYCLE, "cycle", "..." },
{ afxPath3D::LOOP_OSCILLATE, "oscillate", "..." },
EndImplementEnumType;
afxPathData::afxPathData()
{
if (POINTS_FIELD == 0)
{
POINTS_FIELD = StringTable->insert("points");
ROLL_FIELD = StringTable->insert("roll");
TIMES_FIELD = StringTable->insert("times");
}
loop_string = ST_NULLSTRING;
delay = 0;
lifetime = 0;
loop_type = 0;
mult = 1.0f;
time_offset = 0.0f;
resolved = false;
reverse = false;
offset.zero();
echo = false;
concentric = false;
points_string = ST_NULLSTRING;
points = 0;
num_points = 0;
update_points = true;
roll_string = ST_NULLSTRING;
rolls = 0;
update_rolls = true;
times_string = ST_NULLSTRING;
times = 0;
update_times = true;
}
afxPathData::afxPathData(const afxPathData& other, bool temp_clone) : GameBaseData(other, temp_clone)
{
points_string = other.points_string;
roll_string = other.roll_string;
loop_string = other.loop_string;
delay = other.delay;
lifetime = other.lifetime;
loop_type = other.loop_type; // --
mult = other.mult;
time_offset = other.time_offset;
resolved = other.resolved; // --
reverse = other.reverse;
offset = other.offset;
echo = other.echo;
concentric = other.concentric;
times_string = other.times_string;
num_points = other.num_points; // --
if (other.points && num_points > 0)
{
points = new Point3F[num_points];
dMemcpy(points, other.points, sizeof(Point3F)*num_points); // --
}
else
points = 0;
if (other.rolls && num_points > 0)
{
rolls = new F32[num_points];
dMemcpy(rolls, other.rolls, sizeof(F32)*num_points); // --
}
else
rolls = 0;
if (other.times && num_points > 0)
{
times = new F32[num_points];
dMemcpy(times, other.times, sizeof(F32)*num_points); // --
}
else
times = 0;
update_points = other.update_points; // --
update_rolls = other.update_rolls; // --
update_times = other.update_times; // --
}
afxPathData::~afxPathData()
{
clear_arrays();
}
void afxPathData::initPersistFields()
{
addField("points", TypeString, Offset(points_string, afxPathData),
"...");
addField("roll", TypeString, Offset(roll_string, afxPathData),
"...");
addField("times", TypeString, Offset(times_string, afxPathData),
"...");
addField("loop", TypeString, Offset(loop_string, afxPathData),
"...");
addField("mult", TypeF32, Offset(mult, afxPathData),
"...");
addField("delay", TypeF32, Offset(delay, afxPathData),
"...");
addField("lifetime", TypeF32, Offset(lifetime, afxPathData),
"...");
addField("timeOffset", TypeF32, Offset(time_offset, afxPathData),
"...");
addField("reverse", TypeBool, Offset(reverse, afxPathData),
"...");
addField("offset", TypePoint3F, Offset(offset, afxPathData),
"...");
addField("echo", TypeBool, Offset(echo, afxPathData),
"...");
addField("concentric", TypeBool, Offset(concentric, afxPathData),
"...");
Parent::initPersistFields();
}
bool afxPathData::onAdd()
{
if (Parent::onAdd() == false)
return false;
update_derived_values();
return true;
}
void afxPathData::onRemove()
{
clear_arrays();
loop_type = 0;
Parent::onRemove();
}
void afxPathData::packData(BitStream* stream)
{
Parent::packData(stream);
stream->write(num_points);
if (num_points > 0)
{
for (U32 i = 0; i < num_points; i++)
mathWrite(*stream, points[i]);
if (stream->writeFlag(rolls != 0))
{
for (U32 i = 0; i < num_points; i++)
stream->write(rolls[i]);
}
if (stream->writeFlag(times != 0))
{
for (U32 i = 0; i < num_points; i++)
stream->write(times[i]);
}
}
stream->writeString(loop_string);
stream->write(delay);
stream->write(lifetime);
stream->write(time_offset);
stream->write(mult);
stream->writeFlag(reverse);
mathWrite(*stream, offset);
stream->writeFlag(echo);
stream->writeFlag(concentric);
}
void afxPathData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
clear_arrays();
// read the points and rolls
stream->read(&num_points);
if (num_points > 0)
{
points = new Point3F[num_points];
for (U32 i = 0; i < num_points; i++)
mathRead(*stream, &points[i]);
update_points = false;
if (stream->readFlag())
{
rolls = new F32[num_points];
for (U32 i = 0; i < num_points; i++)
stream->read(&rolls[i]);
update_rolls = false;
}
if (stream->readFlag())
{
times = new F32[num_points];
for (U32 i = 0; i < num_points; i++)
stream->read(&times[i]);
update_times = false;
}
}
loop_string = stream->readSTString();
stream->read(&delay);
stream->read(&lifetime);
stream->read(&time_offset);
stream->read(&mult);
reverse = stream->readFlag();
mathRead(*stream, &offset);
echo = stream->readFlag();
concentric = stream->readFlag();
}
void afxPathData::update_derived_values()
{
U32 num_rolls = (rolls != 0) ? num_points : 0;
U32 num_times = (times != 0) ? num_points : 0;
if (update_points)
{
derive_points_array();
update_points = false;
}
if (update_rolls || num_rolls != num_points)
{
derive_rolls_array();
update_rolls = false;
}
if (update_times || num_times != num_points)
{
derive_times_array();
update_times = false;
}
// CAUTION: The following block of code is fragile and tricky since it depends
// on the underlying structures defined by ImplementEnumType/EndImplementEnumType.
// This done because the enum text is parsed from a longer string.
if (loop_string != ST_NULLSTRING)
{
for (unsigned int i = 0; i < _afxPath3DLoopType::_sEnumTable.getNumValues(); i++)
{
if (dStricmp(_afxPath3DLoopType::_sEnumTable[i].mName, loop_string) == 0)
{
loop_type = _afxPath3DLoopType::_sEnumTable[i].mInt;
break;
}
}
}
else
{
loop_string = _afxPath3DLoopType::_sEnumTable[0].mName;
loop_type = _afxPath3DLoopType::_sEnumTable[0].mInt;
}
}
bool afxPathData::preload(bool server, String &errorStr)
{
if (!Parent::preload(server, errorStr))
return false;
update_derived_values();
return true;
}
void afxPathData::onStaticModified(const char* slot, const char* newValue)
{
Parent::onStaticModified(slot, newValue);
if (slot == POINTS_FIELD)
{
update_points = true;
return;
}
if (slot == ROLL_FIELD)
{
update_rolls = true;
return;
}
if (slot == TIMES_FIELD)
{
update_times = true;
return;
}
}
void afxPathData::extract_floats_from_string(Vector<F32>& values, const char* points_str)
{
values.clear();
if (!points_str)
return;
// make a copy of points_str for tokenizing
char* tokCopy = dStrdup(points_str);
// extract each token, convert to float, add to values[]
char* currTok = dStrtok(tokCopy, " \t");
while (currTok != NULL)
{
F32 value = dAtof(currTok);
values.push_back(value);
currTok = dStrtok(NULL, " \t");
}
dFree(tokCopy);
}
Point3F* afxPathData::build_points_array(Vector<F32>& values, U32& n_points, bool reverse)
{
AssertFatal(values.size() > 0, "Values array is empty.");
AssertFatal(values.size()%3 == 0, "Values array is not a multiple of 3.");
n_points = values.size()/3;
Point3F* points = new Point3F[n_points];
if (reverse)
{
U32 p_i = 0;
for (S32 i = values.size()-1; i > 1; i-=3)
points[p_i++].set(values[i-2], values[i-1], values[i]);
}
else
{
U32 p_i = 0;
for (U32 i = 0; i < values.size(); i+=3)
points[p_i++].set(values[i], values[i+1], values[i+2]);
}
return points;
}
F32* afxPathData::build_floats_array(Vector<F32>& values, U32& n_floats, bool reverse)
{
AssertFatal(values.size() > 0, "Values array is empty.");
n_floats = values.size();
F32* floats = new F32[n_floats];
if (reverse)
{
F32* f = floats;
for (S32 i = values.size()-1; i >= 0; i--)
{
*f = values[i];
f++;
}
}
else
{
for (U32 i = 0; i < values.size(); i++)
floats[i] = values[i];
}
return floats;
}
void afxPathData::clear_arrays()
{
num_points = 0;
if (points)
{
delete [] points;
points = 0;
}
if (rolls)
{
delete [] rolls;
rolls = 0;
}
if (times)
{
delete [] times;
times = 0;
}
update_points = true;
update_rolls = true;
update_times = true;
}
void afxPathData::derive_points_array()
{
if (points_string == ST_NULLSTRING)
return;
if (points)
{
delete [] points;
points = 0;
}
num_points = 0;
Vector<F32> values;
extract_floats_from_string(values, points_string);
if (values.size() == 0)
{
Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) empty points field, datablock is invalid.", getName());
return;
}
if (values.size()%3 != 0)
{
Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total points values is not a multiple of 3, datablock is invalid.", getName());
return;
}
points = build_points_array(values, num_points, reverse);
if (offset.x != 0.0f || offset.y != 0.0f || offset.z != 0.0f)
{
// add offset here for efficiency (saves an addition from afxXM_PathConform)
for (U32 i = 0; i < num_points; i++)
points[i] += offset;
}
}
void afxPathData::derive_rolls_array()
{
if (roll_string == ST_NULLSTRING)
return;
if (rolls)
{
delete [] rolls;
rolls = 0;
}
Vector<F32> values;
extract_floats_from_string(values, roll_string);
if (values.size() == 0)
return;
if (values.size() != num_points)
{
Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total roll values is not equal to total points, rolls ignored.", getName());
return;
}
U32 num_rolls = 0;
rolls = build_floats_array(values, num_rolls, reverse);
AssertFatal(num_rolls == num_points, "Unexpected error: num_rolls disagrees with num_points.");
}
void afxPathData::derive_times_array()
{
if (times_string == ST_NULLSTRING)
return;
if (times)
{
delete [] times;
times = 0;
}
Vector<F32> values;
extract_floats_from_string(values, times_string);
if (values.size() == 0)
return;
if (values.size() != num_points)
{
Con::warnf(ConsoleLogEntry::General, "afxPathData(%s) total time values is not equal to total points, times ignored", getName());
return;
}
U32 num_times = 0;
times = build_floats_array(values, num_times, reverse);
AssertFatal(num_times == num_points, "Unexpected error: num_times disagrees with num_points.");
}
void afxPathData::onPerformSubstitutions()
{
Parent::onPerformSubstitutions();
update_derived_values();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,102 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_PATH_H_
#define _AFX_PATH_H_
#include "core/util/tVector.h"
class afxPathData : public GameBaseData
{
typedef GameBaseData Parent;
static StringTableEntry POINTS_FIELD;
static StringTableEntry ROLL_FIELD;
static StringTableEntry TIMES_FIELD;
bool resolved;
bool update_points;
bool update_rolls;
bool update_times;
void update_derived_values();
void clear_arrays();
void derive_points_array();
void derive_rolls_array();
void derive_times_array();
static void extract_floats_from_string(Vector<F32>& values, const char* points_str);
static Point3F* build_points_array(Vector<F32>& values, U32& n_points, bool reverse=false);
static F32* build_floats_array(Vector<F32>& values, U32& n_floats, bool reverse=false);
public:
U32 num_points;
StringTableEntry points_string;
Point3F* points;
StringTableEntry roll_string;
F32* rolls;
StringTableEntry times_string;
F32* times;
StringTableEntry loop_string;
F32 delay;
F32 lifetime;
U32 loop_type;
F32 mult;
F32 time_offset;
bool reverse;
Point3F offset;
bool echo;
bool concentric;
public:
/*C*/ afxPathData();
/*C*/ afxPathData(const afxPathData&, bool = false);
/*D*/ ~afxPathData();
virtual bool onAdd();
virtual void onRemove();
virtual void packData(BitStream*);
virtual void unpackData(BitStream*);
bool preload(bool server, String &errorStr);
virtual void onStaticModified(const char* slotName, const char* newValue = NULL);
virtual void onPerformSubstitutions();
virtual bool allowSubstitutions() const { return true; }
static void initPersistFields();
DECLARE_CONOBJECT(afxPathData);
DECLARE_CATEGORY("AFX");
};
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_PATH_H_

View file

@ -0,0 +1,342 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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 "console/console.h"
#include "afx/util/afxPath3D.h"
afxPath3D::afxPath3D() : start_time(0), num_points(0), loop_type(LOOP_CONSTANT)
{
}
afxPath3D::~afxPath3D()
{
}
void afxPath3D::sortAll()
{
curve.sort();
curve_parameters.sort();
}
void afxPath3D::setStartTime( F32 time )
{
start_time = time;
}
void afxPath3D::setLoopType( U32 loop_type )
{
this->loop_type = loop_type;
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
F32 afxPath3D::getEndTime()
{
return end_time;
}
int afxPath3D::getNumPoints()
{
return num_points;
}
Point3F afxPath3D::getPointPosition( int index )
{
if (index < 0 || index >= num_points)
return Point3F(0.0f, 0.0f, 0.0f);
return curve.getPoint(index);
}
F32 afxPath3D::getPointTime( int index )
{
if (index < 0 || index >= num_points)
return 0.0f;
return curve_parameters.getKeyTime(index);
}
F32 afxPath3D::getPointParameter( int index )
{
if (index < 0 || index >= num_points)
return 0.0f;
return curve_parameters.getKeyValue(index);
}
Point2F afxPath3D::getParameterSegment( F32 time )
{
return curve_parameters.getSegment(time);
}
void afxPath3D::setPointPosition( int index, Point3F &p )
{
if (index < 0 || index >= num_points)
return;
curve.setPoint(index, p);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
F32 afxPath3D::calcCurveTime( F32 time )
{
if( time <= start_time )
return 0.0f;
if( time <= end_time )
return time-start_time;
switch( loop_type )
{
case LOOP_CYCLE :
{
return mFmod( time-start_time, end_time-start_time );
}
case LOOP_OSCILLATE :
{
F32 t1 = time-start_time;
F32 t2 = end_time-start_time;
if( (int)(t1/t2) % 2 ) // odd segment
return t2 - mFmod( t1, t2 );
else // even segment
return mFmod( t1, t2 );
}
case LOOP_CONSTANT :
default:
return end_time;
}
}
Point3F afxPath3D::evaluateAtTime( F32 time )
{
F32 ctime = calcCurveTime( time );
F32 param = curve_parameters.evaluate( ctime );
return curve.evaluate(param);
}
Point3F afxPath3D::evaluateAtTime(F32 t0, F32 t1)
{
F32 ctime = calcCurveTime(t0);
F32 param = curve_parameters.evaluate( ctime );
Point3F p0 = curve.evaluate(param);
ctime = calcCurveTime(t1);
param = curve_parameters.evaluate( ctime );
Point3F p1 = curve.evaluate(param);
return p1-p0;
}
Point3F afxPath3D::evaluateTangentAtTime( F32 time )
{
F32 ctime = calcCurveTime( time );
F32 param = curve_parameters.evaluate( ctime );
return curve.evaluateTangent(param);
}
Point3F afxPath3D::evaluateTangentAtPoint( int index )
{
F32 param = curve_parameters.getKeyValue(index);
return curve.evaluateTangent(param);
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
void afxPath3D::buildPath( int num_points, Point3F curve_points[], F32 start_time, F32 end_time )
{
this->num_points = num_points;
// Add points to path
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f;
for( int i = 0; i < num_points; i++, param += param_inc )
{
if( i == num_points-1 )
param = 1.0f;
curve.addPoint( param, curve_points[i] );
}
curve.computeTangents();
initPathParametersNEW( curve_points, start_time, end_time );
sortAll();
}
void afxPath3D::buildPath( int num_points, Point3F curve_points[], F32 speed )
{
this->num_points = num_points;
// Add points to path
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f;
for( int i = 0; i < num_points; i++, param += param_inc )
{
if( i == num_points-1 )
param = 1.0f;
curve.addPoint( param, curve_points[i] );
}
initPathParameters( curve_points, speed );
sortAll();
}
void afxPath3D::buildPath( int num_points, Point3F curve_points[],
F32 point_times[], F32 time_offset, F32 time_factor )
{
this->num_points = num_points;
// Add points to path
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f;
for( int i = 0; i < num_points; i++, param += param_inc )
{
if( i == num_points-1 )
param = 1.0f;
curve.addPoint( param, curve_points[i] );
curve_parameters.addKey( (point_times[i]+time_offset)*time_factor, param );
}
// Set end time
end_time = (point_times[num_points-1]+time_offset)*time_factor;
sortAll();
}
void afxPath3D::buildPath( int num_points, Point3F curve_points[], Point2F curve_params[] )
{
this->num_points = num_points;
// Add points to path
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f;
for( int i = 0; i < num_points; i++, param += param_inc )
{
if( i == num_points-1 )
param = 1.0f;
curve.addPoint( param, curve_points[i] );
}
//
for (int i = 0; i < num_points; i++)
curve_parameters.addKey( curve_params[i] );
// Set end time
end_time = curve_params[num_points - 1].x;
sortAll();
}
void afxPath3D::reBuildPath()
{
curve.computeTangents();
sortAll();
}
void afxPath3D::initPathParameters( Point3F curve_points[], F32 speed )
{
// Compute the time for each point dependent on the speed of the character and the
// distance it must travel (approximately!)
int num_segments = num_points - 1;
F32 *point_distances = new F32[num_segments];
for( int i = 0; i < num_segments; i++ )
{
Point3F p1 = curve_points[i+1];
Point3F p0 = curve_points[i];
point_distances[i] = (p1-p0).len();
}
F32 *times = new F32[num_segments];
F32 last_time = 0;//start_time;
for( int i = 0; i < num_segments; i++ )
{
times[i] = last_time + (point_distances[i] / speed);
last_time = times[i];
}
curve_parameters.addKey( 0, 0.0f );//start_time, 0.0f );
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f + param_inc;
for( int i = 0; i < num_segments; i++, param += param_inc )
curve_parameters.addKey( times[i], param );
// Set end time
end_time = times[num_segments-1];
if (point_distances)
delete [] point_distances;
if (times)
delete [] times;
}
void afxPath3D::initPathParametersNEW( Point3F curve_points[], F32 start_time, F32 end_time )
{
int num_segments = num_points - 1;
F32 *point_distances = new F32[num_segments];
F32 total_distance = 0.0f;
for( int i = 0; i < num_segments; i++ )
{
Point3F p1 = curve_points[i+1];
Point3F p0 = curve_points[i];
point_distances[i] = (p1-p0).len();
total_distance += point_distances[i];
}
F32 duration = end_time - start_time;
F32 time = 0.0f; //start_time;
curve_parameters.addKey( time, 0.0f );
F32 param_inc = 1.0f / (F32)(num_points - 1);
F32 param = 0.0f + param_inc;
for( int i=0; i < num_segments; i++, param += param_inc )
{
time += (point_distances[i]/total_distance) * duration;
curve_parameters.addKey( time, param );
}
// Set end time ????
//end_time = time;
this->start_time = start_time;
this->end_time = end_time;
if (point_distances)
delete [] point_distances;
}
void afxPath3D::print()
{
// curve.print();
curve_parameters.print();
}
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

View file

@ -0,0 +1,101 @@
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// 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.
//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _AFX_PATH3D_UTIL_H_
#define _AFX_PATH3D_UTIL_H_
#include "afx/util/afxCurve3D.h"
#include "afx/util/afxAnimCurve.h"
#include "math/mMatrix.h"
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
class afxPath3D : public EngineObject
{
private:
// Path-related data
afxCurve3D curve;
afxAnimCurve curve_parameters;
int num_points;
// Time data
F32 start_time;
F32 end_time;
public:
/*C*/ afxPath3D( );
/*D*/ ~afxPath3D();
void sortAll();
void setStartTime(F32 time);
F32 getEndTime();
int getNumPoints();
Point3F getPointPosition(int index);
F32 getPointTime(int index);
F32 getPointParameter(int index);
Point2F getParameterSegment(F32 time);
void setPointPosition(int index, Point3F &p);
Point3F evaluateAtTime(F32 time);
Point3F evaluateAtTime(F32 t0, F32 t1); // returns delta
Point3F evaluateTangentAtTime(F32 time);
Point3F evaluateTangentAtPoint(int index);
void buildPath(int num_points, Point3F curve_points[], F32 start_time, F32 end_time);
void buildPath(int num_points, Point3F curve_points[], F32 speed);
void buildPath(int num_points, Point3F curve_points[], F32 point_times[], F32 time_offset, F32 time_factor);
void buildPath(int num_points, Point3F curve_points[], Point2F curve_params[]);
void reBuildPath();
void print();
enum LoopType
{
LOOP_CONSTANT,
LOOP_CYCLE,
LOOP_OSCILLATE
};
U32 loop_type;
void setLoopType(U32);
private:
void initPathParameters(Point3F curve_points[], F32 speed);
void initPathParametersNEW(Point3F curve_points[], F32 start_time, F32 end_time);
F32 calcCurveTime(F32 time);
};
typedef afxPath3D::LoopType afxPath3DLoopType;
DefineEnumType( afxPath3DLoopType );
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#endif // _AFX_PATH3D_UTIL_H_

View file

@ -0,0 +1,115 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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.
//-----------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// Adapted to a 2D test for intersecting atlas triangles with zodiacs.
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
//-----------------------------------------------------------------------------
// AABB-triangle overlap test code originally by Tomas Akenine-Möller
// Assisted by Pierre Terdiman and David Hunt
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
// Ported to TSE by BJG, 2005-4-14
//-----------------------------------------------------------------------------
#include "afx/arcaneFX.h"
#include "afx/util/afxTriBoxCheck2D_T3D.h"
#define FINDMINMAX(x0,x1,x2,min,max) \
min = max = x0; \
if(x1<min) min=x1;\
if(x1>max) max=x1;\
if(x2<min) min=x2;\
if(x2>max) max=x2;
/*======================== Z-tests ========================*/
#define AXISTEST_Z12(a, b, fa, fb) \
p1 = a*v1.x - b*v1.y; \
p2 = a*v2.x - b*v2.y; \
if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
if(min>rad || max<-rad) return false;
#define AXISTEST_Z0(a, b, fa, fb) \
p0 = a*v0.x - b*v0.y; \
p1 = a*v1.x - b*v1.y; \
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
if(min>rad || max<-rad) return false;
bool afxTriBoxOverlap2D(const Point3F& boxcenter, const Point3F& boxhalfsize, const Point3F& a, const Point3F& b, const Point3F& c)
{
/* use separating axis theorem to test overlap between triangle and box */
/* need to test for overlap in these directions: */
/* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
/* we do not even need to test these) */
/* 2) normal of the triangle */
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
/* this gives 3x3=9 more tests */
F32 min,max,p0,p1,p2,rad;
/* move everything so that the boxcenter is in (0,0,0) */
Point3F v0 = a - boxcenter;
Point3F v1 = b - boxcenter;
Point3F v2 = c - boxcenter;
/* compute triangle edges */
Point3F e0 = v1 - v0; /* tri edge 0 */
Point3F e1 = v2 - v1; /* tri edge 1 */
Point3F e2 = v0 - v2; /* tri edge 2 */
/* Bullet 3: */
/* test the 3 tests first */
F32 fex = mFabs(e0.x);
F32 fey = mFabs(e0.y);
AXISTEST_Z12(e0.y, e0.x, fey, fex);
fex = mFabs(e1.x);
fey = mFabs(e1.y);
AXISTEST_Z0(e1.y, e1.x, fey, fex);
fex = mFabs(e2.x);
fey = mFabs(e2.y);
AXISTEST_Z12(e2.y, e2.x, fey, fex);
/* Bullet 1: */
/* first test overlap in the {x,y,z}-directions */
/* find min, max of the triangle each direction, and test for overlap in */
/* that direction -- this is equivalent to testing a minimal AABB around */
/* the triangle against the AABB */
/* test in X-direction */
FINDMINMAX(v0.x,v1.x,v2.x,min,max);
if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
/* test in Y-direction */
FINDMINMAX(v0.y,v1.y,v2.y,min,max);
if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
return true; /* box and triangle overlaps */
}

View file

@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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.
//-----------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//
// Adapted to a 2D test for intersecting atlas triangles with zodiacs.
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
//-----------------------------------------------------------------------------
// AABB-triangle overlap test code originally by Tomas Akenine-Möller
// Assisted by Pierre Terdiman and David Hunt
// http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
// Ported to TSE by BJG, 2005-4-14
//-----------------------------------------------------------------------------
#ifndef _AFX_TRIBOXCHECK_2D_H_
#define _AFX_TRIBOXCHECK_2D_H_
#include "math/mPoint3.h"
#include "math/mBox.h"
bool afxTriBoxOverlap2D(const Point3F& boxcenter, const Point3F& boxhalfsize, const Point3F& a, const Point3F& b, const Point3F& c);
#endif // _AFX_TRIBOXCHECK_2D_H_