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.
765 lines
31 KiB
765 lines
31 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/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
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 "HeadSpin.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_t 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 float 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_t vertCount, hsPoint3 *positions, hsVector3 *normals, |
|
hsPoint3 *uvws, uint32_t uvwsPerVtx, |
|
hsColorRGBA *origColors, bool fauxShade, const hsColorRGBA* multColor, |
|
uint32_t numIndices, uint16_t *indices, |
|
hsGMaterial *material, const hsMatrix44 &localToWorld, bool 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_t)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_t> tempColors; |
|
int i; |
|
uint8_t a, r, g, b; |
|
|
|
|
|
tempColors.SetCount( vertCount ); |
|
for( i = 0; i < vertCount; i++ ) |
|
{ |
|
hsColorRGBA *color = &colors[ i ]; |
|
a = (uint8_t)( color->a >= 1 ? 255 : color->a <= 0 ? 0 : color->a * 255.0 ); |
|
r = (uint8_t)( color->r >= 1 ? 255 : color->r <= 0 ? 0 : color->r * 255.0 ); |
|
g = (uint8_t)( color->g >= 1 ? 255 : color->g <= 0 ? 0 : color->g * 255.0 ); |
|
b = (uint8_t)( 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 |
|
|
|
bool plDrawableGenerator::RegenerateDrawable( uint32_t vertCount, hsPoint3 *positions, hsVector3 *normals, |
|
hsPoint3 *uvws, uint32_t uvwsPerVtx, |
|
hsColorRGBA *origColors, bool fauxShade, const hsColorRGBA* multColor, |
|
uint32_t numIndices, uint16_t *indices, |
|
hsGMaterial *material, const hsMatrix44 &localToWorld, bool blended, |
|
uint32_t 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_t vertCount, hsPoint3 *positions, hsVector3 *normals, |
|
hsPoint3 *uvws, uint32_t uvwsPerVtx, |
|
hsColorRGBA *origColors, bool fauxShade, const hsColorRGBA* multColor, |
|
uint32_t numIndices, uint16_t *indices, |
|
hsGMaterial *material, const hsMatrix44 &localToWorld, bool blended, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
plDrawableSpans *newDraw; |
|
hsTArray<plGeometrySpan *> spanArray; |
|
plGeometrySpan *span; |
|
|
|
// Set up props on the new drawable |
|
if( toAddTo != nil ) |
|
newDraw = toAddTo; |
|
else |
|
{ |
|
newDraw = 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; |
|
plString buff = plFormat("GenDrawable_{}", nameIdx++); |
|
hsgResMgr::ResMgr()->NewKey( buff, newDraw, plLocation::kGlobalFixedLoc ); |
|
} |
|
|
|
// Create a temp plGeometrySpan |
|
spanArray.SetCount( 1 ); |
|
span = spanArray[ 0 ] = 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_t trash = uint32_t(-1); |
|
uint32_t idx = newDraw->AppendDISpans( spanArray, trash, false ); |
|
if( retIndex != nil ) |
|
retIndex->Append(idx); |
|
|
|
return newDraw; |
|
} |
|
|
|
//// GenerateSphericalDrawable /////////////////////////////////////////////// |
|
|
|
plDrawableSpans *plDrawableGenerator::GenerateSphericalDrawable( const hsPoint3& pos, float radius, hsGMaterial *material, |
|
const hsMatrix44 &localToWorld, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo, |
|
float qualityScalar ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<uint16_t> 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 * ( M_PI ) / (float)numDivisions; |
|
hsFastMath::SinCosInRange( angle, internRad, z ); |
|
internRad *= radius; |
|
|
|
for( j = 0; j < numDivisions; j++ ) |
|
{ |
|
angle = (float)j * ( 2 * M_PI ) / (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( float width, float height, float depth, |
|
hsGMaterial *material, const hsMatrix44 &localToWorld, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *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, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<uint16_t> 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, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<uint16_t> 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( float radius, float height, hsGMaterial *material, |
|
const hsMatrix44 &localToWorld, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsVector3 direction; |
|
|
|
|
|
direction.Set( 0, 0, height ); |
|
|
|
hsPoint3 zero(0, 0, 0); |
|
return GenerateConicalDrawable(zero, direction, radius, material, localToWorld, blended, |
|
multColor, retIndex, toAddTo ); |
|
} |
|
|
|
|
|
//// GenerateConicalDrawable ///////////////////////////////////////////////// |
|
|
|
plDrawableSpans *plDrawableGenerator::GenerateConicalDrawable( hsPoint3 &apex, hsVector3 &direction, float radius, hsGMaterial *material, |
|
const hsMatrix44 &localToWorld, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<uint16_t> 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 * ( M_PI * 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, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<hsColorRGBA> colors; |
|
hsTArray<uint16_t> 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, bool blended, |
|
const hsColorRGBA* multColor, |
|
hsTArray<uint32_t> *retIndex, plDrawableSpans *toAddTo ) |
|
{ |
|
hsTArray<hsPoint3> points; |
|
hsTArray<hsVector3> normals; |
|
hsTArray<uint16_t> 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; |
|
} |
|
|
|
|
|
|