You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
25 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plDrawableGenerator Class Functions //
// //
//// Version History /////////////////////////////////////////////////////////
// //
// 5.15.2001 mcn - Created. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plDrawableGenerator.h"
#include "plDrawableSpans.h"
#include "plGeometrySpan.h"
#include "hsFastMath.h"
#include "plRenderLevel.h"
#include "hsResMgr.h"
#include "../pnKeyedObject/plUoid.h"
// Making light white and dark black by default, because this is really
// redundant. The handling of what color unlit and fully lit map to is
// encapsulated in the material used to draw the mesh. The caller
// wants illumination values, and can handle on screen contrast
// through the material. mf
hsColorRGBA plDrawableGenerator::fLiteColor = { 1, 1, 1, 1 };
hsColorRGBA plDrawableGenerator::fDarkColor = { 0.0, 0.0, 0.0, 1 };
//// SetFauxLightColors //////////////////////////////////////////////////////
// Set the colors for the foux lighting on generated drawables
void plDrawableGenerator::SetFauxLightColors( hsColorRGBA &lite, hsColorRGBA &dark )
{
fLiteColor = lite;
fDarkColor = dark;
}
//// IQuickShadeVerts ////////////////////////////////////////////////////////
// Quickly shades vertices based on a fake directional light. Good for doing
// faux shadings on proxy objects.
void plDrawableGenerator::IQuickShadeVerts( UInt32 count, hsVector3 *normals, hsColorRGBA *colors, hsColorRGBA* origColors, const hsColorRGBA* multColor )
{
hsVector3 lightDir;
float scale;
lightDir.Set( 1, 1, 1 );
lightDir.Normalize();
while( count-- )
{
scale = ( normals[ count ] * lightDir );
// pretend there are two opposing directional lights, but the
// one pointing downish is a little stronger.
const hsScalar kReverseLight = -0.8f;
if( scale < 0 )
scale = kReverseLight * scale;
colors[ count ] = fLiteColor * scale + fDarkColor * ( 1.f - scale );
if( origColors )
colors[ count ] *= origColors[ count ];
if( multColor )
colors[ count ] *= *multColor;
}
}
void plDrawableGenerator::IFillSpan( UInt32 vertCount, hsPoint3 *positions, hsVector3 *normals,
hsPoint3 *uvws, UInt32 uvwsPerVtx,
hsColorRGBA *origColors, hsBool fauxShade, const hsColorRGBA* multColor,
UInt32 numIndices, UInt16 *indices,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
plGeometrySpan* span )
{
hsTArray<hsVector3> myNormals;
/// Calculate normals if we don't have them
if( normals == nil )
{
int i;
hsVector3 normal, v1, v2;
myNormals.SetCount( vertCount );
for( i = 0; i < vertCount; i++ )
myNormals[ i ].Set( 0, 0, 0 );
for( i = 0; i < numIndices; i += 3 )
{
v1.Set( &positions[ indices[ i + 1 ] ], &positions[ indices[ i ] ] );
v2.Set( &positions[ indices[ i + 2 ] ], &positions[ indices[ i ] ] );
normal = v1 % v2;
myNormals[ indices[ i ] ] += normal;
myNormals[ indices[ i + 1 ] ] += normal;
myNormals[ indices[ i + 2 ] ] += normal;
}
for( i = 0; i < vertCount; i++ )
myNormals[ i ].Normalize();
normals = myNormals.AcquireArray();
}
if( uvws == nil )
uvwsPerVtx = 0;
span->BeginCreate( material, localToWorld, plGeometrySpan::UVCountToFormat( (UInt8)uvwsPerVtx ) );
if( !origColors && !fauxShade )
span->AddVertexArray( vertCount, positions, normals, nil, uvws, uvwsPerVtx );
else
{
hsTArray<hsColorRGBA> colArray;
hsColorRGBA* colors;
if( fauxShade )
{
colArray.SetCount(vertCount);
IQuickShadeVerts( vertCount, normals, colArray.AcquireArray(), origColors, multColor );
colors = colArray.AcquireArray();
}
else // just use the origColors
{
colors = origColors;
}
hsTArray<UInt32> tempColors;
int i;
UInt8 a, r, g, b;
tempColors.SetCount( vertCount );
for( i = 0; i < vertCount; i++ )
{
hsColorRGBA *color = &colors[ i ];
a = (UInt8)( color->a >= 1 ? 255 : color->a <= 0 ? 0 : color->a * 255.0 );
r = (UInt8)( color->r >= 1 ? 255 : color->r <= 0 ? 0 : color->r * 255.0 );
g = (UInt8)( color->g >= 1 ? 255 : color->g <= 0 ? 0 : color->g * 255.0 );
b = (UInt8)( color->b >= 1 ? 255 : color->b <= 0 ? 0 : color->b * 255.0 );
tempColors[ i ] = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | ( b );
}
span->AddVertexArray( vertCount, positions, normals, tempColors.AcquireArray(), uvws, uvwsPerVtx );
}
span->AddIndexArray( numIndices, indices );
span->EndCreate();
}
//// RegenerateDrawable ////////////////////////////////////////////////////////
// Static function that refills an existing drawable based on the vertex/index
// data given. That data had better match the data the drawable was first filled
// with (i.e. vertex/index count
hsBool plDrawableGenerator::RegenerateDrawable( UInt32 vertCount, hsPoint3 *positions, hsVector3 *normals,
hsPoint3 *uvws, UInt32 uvwsPerVtx,
hsColorRGBA *origColors, hsBool fauxShade, const hsColorRGBA* multColor,
UInt32 numIndices, UInt16 *indices,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
UInt32 diIndex, plDrawableSpans *destDraw )
{
plDISpanIndex spanList = destDraw->GetDISpans( diIndex );
if( spanList.GetCount() != 1 )
{
hsAssert(false, "Don't know how to distribute this geometry over multiple spans");
return false;
}
plGeometrySpan* span = destDraw->GetGeometrySpan(spanList[0]);
if( (span->fNumVerts != vertCount)
||(span->fNumIndices != numIndices) )
{
hsAssert(false, "Mismatched data coming in for a refill");
return false;
}
IFillSpan( vertCount, positions, normals,
uvws, uvwsPerVtx,
origColors, fauxShade, multColor,
numIndices, indices,
material, localToWorld, blended,
span );
destDraw->RefreshDISpans( diIndex );
return true;
}
//// GenerateDrawable ////////////////////////////////////////////////////////
// Static function that creates a new drawable based on the vertex/index
// data given.
plDrawableSpans *plDrawableGenerator::GenerateDrawable( UInt32 vertCount, hsPoint3 *positions, hsVector3 *normals,
hsPoint3 *uvws, UInt32 uvwsPerVtx,
hsColorRGBA *origColors, hsBool fauxShade, const hsColorRGBA* multColor,
UInt32 numIndices, UInt16 *indices,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
plDrawableSpans *newDraw;
hsTArray<plGeometrySpan *> spanArray;
plGeometrySpan *span;
// Set up props on the new drawable
if( toAddTo != nil )
newDraw = toAddTo;
else
{
newDraw = TRACKED_NEW plDrawableSpans;
// newDraw->SetNativeProperty( plDrawable::kPropVolatile, true );
if( blended )
{
newDraw->SetRenderLevel(plRenderLevel(plRenderLevel::kBlendRendMajorLevel, plRenderLevel::kDefRendMinorLevel));
newDraw->SetNativeProperty( plDrawable::kPropSortSpans | plDrawable::kPropSortFaces, true );
}
static int nameIdx = 0;
char buff[256];
sprintf(buff, "%s_%d", "GenDrawable", nameIdx++);
hsgResMgr::ResMgr()->NewKey( buff, newDraw, plLocation::kGlobalFixedLoc );
}
// Create a temp plGeometrySpan
spanArray.SetCount( 1 );
span = spanArray[ 0 ] = TRACKED_NEW plGeometrySpan;
IFillSpan( vertCount, positions, normals,
uvws, uvwsPerVtx,
origColors, fauxShade, multColor,
numIndices, indices,
material, localToWorld, blended,
span );
/// Now add the span to the new drawable, clear up the span's buffers and return!
UInt32 trash = UInt32(-1);
UInt32 idx = newDraw->AppendDISpans( spanArray, trash, false );
if( retIndex != nil )
retIndex->Append(idx);
return newDraw;
}
//// GenerateSphericalDrawable ///////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateSphericalDrawable( const hsPoint3& pos, hsScalar radius, hsGMaterial *material,
const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo,
hsScalar qualityScalar )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<UInt16> indices;
hsTArray<hsColorRGBA> colors;
hsPoint3 point;
hsVector3 normal;
int i, j, numDivisions, start;
float angle, z, x, y, internRad;
plDrawableSpans *drawable;
numDivisions = (int)( radius * qualityScalar / 10.f );
if( numDivisions < 5 )
numDivisions = 5;
else if( numDivisions > 30 )
numDivisions = 30;
/// Generate points
for( i = 0; i <= numDivisions; i++ )
{
angle = (float)i * ( hsScalarPI ) / (float)numDivisions;
hsFastMath::SinCosInRange( angle, internRad, z );
internRad *= radius;
for( j = 0; j < numDivisions; j++ )
{
angle = (float)j * ( 2 * hsScalarPI ) / (float)numDivisions;
hsFastMath::SinCosInRange( angle, x, y );
point.Set( pos.fX + x * internRad, pos.fY + y * internRad, pos.fZ + z * radius );
normal.Set( x * internRad, y * internRad, z * radius );
normal.Normalize();
points.Append( point );
normals.Append( normal );
}
}
/// Generate indices
for( i = 0, start = 0; i < numDivisions; i++, start += numDivisions )
{
for( j = 0; j < numDivisions - 1; j++ )
{
indices.Append( start + j );
indices.Append( start + j + 1 );
indices.Append( start + j + numDivisions + 1 );
indices.Append( start + j );
indices.Append( start + j + numDivisions + 1 );
indices.Append( start + j + numDivisions );
}
indices.Append( start + j );
indices.Append( start );
indices.Append( start + numDivisions );
indices.Append( start + j );
indices.Append( start + numDivisions );
indices.Append( start + j + numDivisions );
}
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
nil, 0,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}
//// GenerateBoxDrawable /////////////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateBoxDrawable( hsScalar width, hsScalar height, hsScalar depth,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsVector3 xVec, yVec, zVec;
hsPoint3 pt;
xVec.Set( width, 0, 0 );
yVec.Set( 0, height, 0 );
zVec.Set( 0, 0, depth );
pt.Set( -width / 2.f, -height / 2.f, -depth / 2.f );
return GenerateBoxDrawable( pt, xVec, yVec, zVec, material, localToWorld, blended, multColor, retIndex, toAddTo );
}
//// GenerateBoxDrawable /////////////////////////////////////////////////////
// Version that takes a corner and three vectors, for x, y and z edges.
#define CALC_NORMAL( nA, xVec, yVec, zVec ) { hsVector3 n = (xVec) + (yVec) + (zVec); n = -n; n.Normalize(); nA.Append( n ); }
plDrawableSpans *plDrawableGenerator::GenerateBoxDrawable( const hsPoint3 &corner, const hsVector3 &xVec, const hsVector3 &yVec, const hsVector3 &zVec,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<UInt16> indices;
hsTArray<hsColorRGBA> colors;
hsTArray<hsPoint3> uvws;
hsPoint3 point;
plDrawableSpans *drawable;
float mults[ 8 ][ 3 ] = { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
{ -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } };
/// Generate points and normals
points.Expand( 8 );
normals.Expand( 8 );
point = corner; points.Append( point );
point += xVec; points.Append( point );
point += yVec; points.Append( point );
point = corner + yVec; points.Append( point );
point = corner + zVec; points.Append( point );
point += xVec; points.Append( point );
point += yVec; points.Append( point );
point = corner + zVec + yVec; points.Append( point );
CALC_NORMAL( normals, xVec, yVec, zVec );
CALC_NORMAL( normals, -xVec, yVec, zVec );
CALC_NORMAL( normals, -xVec, -yVec, zVec );
CALC_NORMAL( normals, xVec, -yVec, zVec );
CALC_NORMAL( normals, xVec, yVec, -zVec );
CALC_NORMAL( normals, -xVec, yVec, -zVec );
CALC_NORMAL( normals, -xVec, -yVec, -zVec );
CALC_NORMAL( normals, xVec, -yVec, -zVec );
uvws.Expand( 8 );
uvws.Append( hsPoint3( 0.f, 1.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 1.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 0.f, 0.f ) );
uvws.Append( hsPoint3( 0.f, 0.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 1.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 0.f, 0.f ) );
uvws.Append( hsPoint3( 0.f, 0.f, 0.f ) );
uvws.Append( hsPoint3( 0.f, 1.f, 0.f ) );
/// Generate indices
indices.Expand( 36 );
indices.Append( 0 ); indices.Append( 1 ); indices.Append( 2 );
indices.Append( 0 ); indices.Append( 2 ); indices.Append( 3 );
indices.Append( 1 ); indices.Append( 0 ); indices.Append( 4 );
indices.Append( 1 ); indices.Append( 4 ); indices.Append( 5 );
indices.Append( 2 ); indices.Append( 1 ); indices.Append( 5 );
indices.Append( 2 ); indices.Append( 5 ); indices.Append( 6 );
indices.Append( 3 ); indices.Append( 2 ); indices.Append( 6 );
indices.Append( 3 ); indices.Append( 6 ); indices.Append( 7 );
indices.Append( 0 ); indices.Append( 3 ); indices.Append( 7 );
indices.Append( 0 ); indices.Append( 7 ); indices.Append( 4 );
indices.Append( 7 ); indices.Append( 6 ); indices.Append( 5 );
indices.Append( 7 ); indices.Append( 5 ); indices.Append( 4 );
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
uvws.AcquireArray(), 1,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}
//// GenerateBoundsDrawable //////////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateBoundsDrawable( hsBounds3Ext *bounds,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<UInt16> indices;
hsTArray<hsColorRGBA> colors;
hsPoint3 point;
hsVector3 normal;
int i;
plDrawableSpans *drawable;
float mults[ 8 ][ 3 ] = { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
{ -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } };
/// Generate points and normals
points.Expand( 8 );
normals.Expand( 8 );
hsPoint3 min = bounds->GetMins();
hsPoint3 max = bounds->GetMaxs();
for( i = 0; i < 8; i++ )
{
points.Append( hsPoint3( mults[ i ][ 0 ] > 0 ? max.fX : min.fX,
mults[ i ][ 1 ] > 0 ? max.fY : min.fY,
mults[ i ][ 2 ] > 0 ? max.fZ : min.fZ ) );
normals.Append( hsVector3( mults[ i ][ 0 ], mults[ i ][ 1 ], mults[ i ][ 2 ] ) );
}
/// Generate indices
indices.Expand( 36 );
indices.Append( 0 ); indices.Append( 1 ); indices.Append( 2 );
indices.Append( 0 ); indices.Append( 2 ); indices.Append( 3 );
indices.Append( 1 ); indices.Append( 0 ); indices.Append( 4 );
indices.Append( 1 ); indices.Append( 4 ); indices.Append( 5 );
indices.Append( 2 ); indices.Append( 1 ); indices.Append( 5 );
indices.Append( 2 ); indices.Append( 5 ); indices.Append( 6 );
indices.Append( 3 ); indices.Append( 2 ); indices.Append( 6 );
indices.Append( 3 ); indices.Append( 6 ); indices.Append( 7 );
indices.Append( 0 ); indices.Append( 3 ); indices.Append( 7 );
indices.Append( 0 ); indices.Append( 7 ); indices.Append( 4 );
indices.Append( 7 ); indices.Append( 6 ); indices.Append( 5 );
indices.Append( 7 ); indices.Append( 5 ); indices.Append( 4 );
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
nil, 0,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}
//// GenerateConicalDrawable /////////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateConicalDrawable( hsScalar radius, hsScalar height, hsGMaterial *material,
const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsVector3 direction;
direction.Set( 0, 0, height );
return GenerateConicalDrawable( hsPoint3( 0, 0, 0 ), direction, radius, material, localToWorld, blended,
multColor, retIndex, toAddTo );
}
//// GenerateConicalDrawable /////////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateConicalDrawable( hsPoint3 &apex, hsVector3 &direction, hsScalar radius, hsGMaterial *material,
const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<UInt16> indices;
hsTArray<hsColorRGBA> colors;
hsPoint3 point;
hsVector3 normal;
int i, numDivisions;
float angle, x, y;
plDrawableSpans *drawable;
numDivisions = (int)( radius / 4.f );
if( numDivisions < 6 )
numDivisions = 6;
else if( numDivisions > 20 )
numDivisions = 20;
/// First, we need a few more vectors--specifically, the x and y vectors for the cone's base
hsPoint3 baseCenter = apex + direction;
hsVector3 xVec, yVec;
xVec.Set( 1, 0, 0 );
yVec = xVec % direction;
if( yVec.MagnitudeSquared() == 0 )
{
xVec.Set( 0, 1, 0 );
yVec = xVec % direction;
hsAssert( yVec.MagnitudeSquared() != 0, "Weird funkiness when doing this!!!" );
}
xVec = yVec % direction;
xVec.Normalize();
yVec.Normalize();
/// Now generate points based on those
points.Expand( numDivisions + 2 );
normals.Expand( numDivisions + 2 );
points.Append( apex );
normals.Append( -direction );
for( i = 0; i < numDivisions; i++ )
{
angle = (float)i * ( hsScalarPI * 2.f ) / (float)numDivisions;
hsFastMath::SinCosInRange( angle, x, y );
points.Append( baseCenter + ( xVec * x * radius ) + ( yVec * y * radius ) );
normals.Append( ( xVec * x ) + ( yVec * y ) );
}
/// Generate indices
indices.Expand( ( numDivisions + 1 + numDivisions - 2 ) * 3 );
for( i = 0; i < numDivisions - 1; i++ )
{
indices.Append( 0 );
indices.Append( i + 2 );
indices.Append( i + 1 );
}
indices.Append( 0 );
indices.Append( 1 );
indices.Append( numDivisions );
// Bottom cap
for( i = 3; i < numDivisions + 1; i++ )
{
indices.Append( i - 1 );
indices.Append( i );
indices.Append( 1 );
}
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
nil, 0,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}
//// GenerateAxesDrawable ////////////////////////////////////////////////////
plDrawableSpans *plDrawableGenerator::GenerateAxesDrawable( hsGMaterial *material,
const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<hsColorRGBA> colors;
hsTArray<UInt16> indices;
int i;
float size = 15;
plDrawableSpans *drawable;
/// Generate points
points.SetCount( 6 * 3 );
normals.SetCount( 6 * 3 );
colors.SetCount( 6 * 3 );
points[ 0 ].Set( 0, 0, 0 );
points[ 1 ].Set( size, -size * 0.1f, 0 );
points[ 2 ].Set( size, -size * 0.3f, 0 );
points[ 3 ].Set( size * 1.3f, 0, 0 );
points[ 4 ].Set( size, size * 0.3f, 0 );
points[ 5 ].Set( size, size * 0.1f, 0 );
for( i = 0; i < 6; i++ )
{
points[ i + 6 ].fX = - points[ i ].fY;
points[ i + 6 ].fY = points[ i ].fX;
points[ i + 6 ].fZ = 0;
points[ i + 12 ].fX = points[ i ].fY;
points[ i + 12 ].fZ = points[ i ].fX;
points[ i + 12 ].fY = 0;
colors[ i ].Set( 1, 0, 0, 1 );
colors[ i + 6 ].Set( 0, 1, 0, 1 );
colors[ i + 12 ].Set( 0, 0, 1, 1 );
if( multColor )
colors[ i ] *= *multColor;
}
/// Generate indices
indices.SetCount( 6 * 3 );
for( i = 0; i < 18; i += 6 )
{
indices[ i ] = i + 0;
indices[ i + 1 ] = i + 1;
indices[ i + 2 ] = i + 5;
indices[ i + 3 ] = i + 2;
indices[ i + 4 ] = i + 3;
indices[ i + 5 ] = i + 4;
}
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
nil, 0,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}
//// GeneratePlanarDrawable //////////////////////////////////////////////////
// Version that takes a corner and two vectors, for x and y edges.
#define CALC_PNORMAL( nA, xVec, yVec ) { hsVector3 n = (xVec) % (yVec); n.Normalize(); nA.Append( n ); }
plDrawableSpans *plDrawableGenerator::GeneratePlanarDrawable( const hsPoint3 &corner, const hsVector3 &xVec, const hsVector3 &yVec,
hsGMaterial *material, const hsMatrix44 &localToWorld, hsBool blended,
const hsColorRGBA* multColor,
hsTArray<UInt32> *retIndex, plDrawableSpans *toAddTo )
{
hsTArray<hsPoint3> points;
hsTArray<hsVector3> normals;
hsTArray<UInt16> indices;
hsTArray<hsColorRGBA> colors;
hsTArray<hsPoint3> uvws;
hsPoint3 point;
plDrawableSpans *drawable;
/// Generate points and normals
points.Expand( 4 );
normals.Expand( 4 );
point = corner; points.Append( point );
point += xVec; points.Append( point );
point += yVec; points.Append( point );
point = corner + yVec; points.Append( point );
CALC_PNORMAL( normals, xVec, yVec );
CALC_PNORMAL( normals, xVec, yVec );
CALC_PNORMAL( normals, xVec, yVec );
CALC_PNORMAL( normals, xVec, yVec );
uvws.Expand( 4 );
uvws.Append( hsPoint3( 0.f, 1.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 1.f, 0.f ) );
uvws.Append( hsPoint3( 1.f, 0.f, 0.f ) );
uvws.Append( hsPoint3( 0.f, 0.f, 0.f ) );
/// Generate indices
indices.Expand( 6 );
indices.Append( 0 ); indices.Append( 1 ); indices.Append( 2 );
indices.Append( 0 ); indices.Append( 2 ); indices.Append( 3 );
/// Create a drawable for it
drawable = plDrawableGenerator::GenerateDrawable( points.GetCount(), points.AcquireArray(), normals.AcquireArray(),
uvws.AcquireArray(), 1,
nil, true, multColor,
indices.GetCount(), indices.AcquireArray(),
material, localToWorld, blended, retIndex, toAddTo );
return drawable;
}