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.

313 lines
14 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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plGeometrySpan Header //
// //
// plGeometrySpans are abstract reprentations of Plasma 2.0 geometry data. //
// They consist of a material, a transform, bounds and an abstract vertex //
// and index buffer pair. plGeometrySpans is what is fed to plDrawableIce //
// to convert into its own internal data structures; the format for the //
// vertex and index data is (or should be) identical. More or less, they //
// are identical to Ice's plIcicle, but this is more abstract (read: not //
// internal to Ice). //
// //
// Also included is a temporary hacked triMesh-to-geometrySpan[] converter //
// for everyone's convenience until triMeshes disappear. //
// //
//// Version History /////////////////////////////////////////////////////////
// //
// Created 3.8.2001 mcn //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plGeometrySpan_h
#define _plGeometrySpan_h
#include "hsTemplates.h"
#include "hsBounds.h"
#include "hsMatrix44.h"
#include "hsColorRGBA.h"
#include "hsBitVector.h"
class hsGMaterial;
class plFogEnvironment;
//// plGeometrySpan Class Definition /////////////////////////////////////////
class plGeometrySpan
{
public:
enum
{
kMaxNumUVChannels = 8
};
/// Duplication of the formats from plGBufferGroup; theoretically, they
/// could be different, but they're identical for now
enum Formats
{
kUVCountMask = 0x0f, // Problem is, we need enough bits to store the max #, which means
// we really want ( max # << 1 ) - 1
kSkinNoWeights = 0x00, // 0000000
kSkin1Weight = 0x10, // 0010000
kSkin2Weights = 0x20, // 0100000
kSkin3Weights = 0x30, // 0110000
kSkinWeightMask = 0x30, // 0110000
kSkinIndices = 0x40, // 1000000
};
enum Properties
{
kPropRunTimeLight = 0x01,
kPropNoPreShade = 0x02,
kLiteMaterial = 0x00,
kLiteVtxPreshaded = 0x04,
kLiteVtxNonPreshaded = 0x08,
kLiteMask = 0x0c,
kRequiresBlending = 0x10,
kInstanced = 0x20,
kUserOwned = 0x40,
kPropNoShadow = 0x80,
kPropForceShadow = 0x100,
kDiffuseFoldedIn = 0x200, // Sometimes we want to fold the diffuse color of the material into the vertex color (but only once).
kPropReverseSort = 0x400,
kWaterHeight = 0x800,
kFirstInstance = 0x1000,
kPartialSort = 0x2000,
kVisLOS = 0x4000,
kPropNoShadowCast = 0x8000
};
enum
{
kNoGroupID = 0
};
// Note: these are public because this is really just a glorified
// struct; no data hiding here
hsGMaterial *fMaterial;
hsMatrix44 fLocalToWorld;
hsMatrix44 fWorldToLocal;
hsBounds3Ext fLocalBounds;
hsBounds3Ext fWorldBounds;
plFogEnvironment *fFogEnviron;
UInt32 fBaseMatrix;
UInt8 fNumMatrices;
UInt16 fLocalUVWChans;
UInt16 fMaxBoneIdx;
UInt32 fPenBoneIdx;
hsScalar fMinDist;
hsScalar fMaxDist;
hsScalar fWaterHeight;
UInt8 fFormat;
UInt32 fProps;
UInt32 fNumVerts, fNumIndices;
/// Current vertex format:
/// float position[ 3 ];
/// float normal[ 3 ];
/// float uvCoords[ ][ 3 ];
/// float weights[]; // 0-3 blending weights
/// UInt32 weightIndices; // Only if there are >= 1 blending weights
UInt8* fVertexData;
UInt16* fIndexData;
UInt32 fDecalLevel;
hsColorRGBA* fMultColor;
hsColorRGBA* fAddColor;
UInt32* fDiffuseRGBA;
UInt32* fSpecularRGBA;
mutable hsTArray<plGeometrySpan *>* fInstanceRefs;
mutable UInt32 fInstanceGroupID; // For writing out/reading in instance refs
// The following is only used for logging during export. It is never set
// at runtime. Don't even think about using it for anything.
const char* fMaxOwner;
// The following is ONLY used during pack; it's so we can do a reverse lookup
// from the instanceRefs list to the correct span in the drawable
UInt32 fSpanRefIndex;
// These two matrices are inverses of each other (duh). They are only used on computing the local
// bounds. fLocalBounds is always the bounds in the space defined by fWorldToLocal, but the bounds
// are an OBB, and the orientation of the OBB isn't necessarily the same as fLocalToWorld's axes.
// For now, it is the orientation of the pivot point in max (but might be further optimized).
hsMatrix44 fLocalToOBB;
hsMatrix44 fOBBToLocal;
plGeometrySpan();
plGeometrySpan( const plGeometrySpan *instance );
~plGeometrySpan();
/// UV stuff
UInt8 GetNumUVs( void ) const { return ( fFormat & kUVCountMask ); }
void SetNumUVs( UInt8 numUVs )
{
hsAssert( numUVs < kMaxNumUVChannels, "Invalid UV count to plGeometrySpan" );
fFormat = ( fFormat & ~kUVCountMask ) | numUVs;
}
static UInt8 CalcNumUVs( UInt8 format ) { return ( format & kUVCountMask ); }
static UInt8 UVCountToFormat( UInt8 numUVs ) { return numUVs & kUVCountMask; }
/// Creation functions
void BeginCreate( hsGMaterial *material, const hsMatrix44 &l2wMatrix, UInt8 format );
// Phasing these in...
// Note: uvArray should be a fixed array with enough pointers for the max # of uv channels.
// Any unused UVs should be nil
UInt16 AddVertex( hsPoint3 *position, hsPoint3 *normal, hsColorRGBA& multColor, hsColorRGBA& addColor,
hsPoint3 **uvPtrArray, float weight1 = -1.0f, float weight2 = -1.0f, float weight3 = -1.0f, UInt32 weightIndices = 0 );
UInt16 AddVertex( hsPoint3 *position, hsPoint3 *normal, UInt32 hexColor, UInt32 specularColor = 0,
hsPoint3 **uvPtrArray = nil, float weight1 = -1.0f, float weight2 = -1.0f, float weight3 = -1.0f, UInt32 weightIndices = 0 );
void AddIndex( UInt16 index );
void AddTriIndices( UInt16 index1, UInt16 index2, UInt16 index3 );
void AddTriangle( hsPoint3 *vert1, hsPoint3 *vert2, hsPoint3 *vert3, UInt32 color );
// uvws is an array count*uvwsPerVtx long in order [uvw(s) for vtx0, uvw(s) for vtx1, ...], or is nil
void AddVertexArray( UInt32 count, hsPoint3 *positions, hsVector3 *normals, UInt32 *colors, hsPoint3 *uvws=nil, int uvwsPerVtx=0 );
void AddIndexArray( UInt32 count, UInt16 *indices );
void EndCreate( void );
/// Manipulation--currently only used for applying static lighting, which of course needs individual vertices
// Wrong. Also used for the interleaving of the multiple vertex data streams here into single vertex
// stream within the plGBufferGroups. mf.
void ExtractInitColor( UInt32 index, hsColorRGBA *multColor, hsColorRGBA *addColor) const;
void ExtractVertex( UInt32 index, hsPoint3 *pos, hsVector3 *normal, hsColorRGBA *color, hsColorRGBA *specColor = nil );
void ExtractVertex( UInt32 index, hsPoint3 *pos, hsVector3 *normal, UInt32 *color, UInt32 *specColor = nil );
void ExtractUv( UInt32 vIdx, UInt8 uvIdx, hsPoint3* uv );
void ExtractWeights( UInt32 vIdx, float *weightArray, UInt32 *indices );
void StuffVertex( UInt32 index, hsPoint3 *pos, hsPoint3 *normal, hsColorRGBA *color, hsColorRGBA *specColor = nil );
void StuffVertex( UInt32 index, hsColorRGBA *color, hsColorRGBA *specColor = nil );
// Clear out the buffers
void ClearBuffers( void );
// Duplicate this span from a given span
void CopyFrom( const plGeometrySpan *source );
// Make this span an instance of the given span. Handles the instance ref array as well as copying over pointers
void MakeInstanceOf( const plGeometrySpan *instance );
// Get the size of one vertex in a span, based on a format
static UInt32 GetVertexSize( UInt8 format );
void Read( hsStream *stream );
void Write( hsStream *stream );
static UInt32 AllocateNewGroupID() { return IAllocateNewGroupID(); }
void BreakInstance();
void ChangeInstance(plGeometrySpan* newInstance);
void UnInstance();
void AdjustBounds(hsBounds3Ext& bnd) const;
protected:
struct TempVertex
{
hsPoint3 fPosition;
hsPoint3 fNormal;
UInt32 fColor, fSpecularColor;
hsColorRGBA fMultColor, fAddColor;
hsPoint3 fUVs[ kMaxNumUVChannels ];
float fWeights[ 3 ];
UInt32 fIndices;
};
hsBool fCreating;
hsTArray<TempVertex> fVertAccum;
hsTArray<UInt16> fIndexAccum;
void IUnShareData();
void IDuplicateUniqueData( const plGeometrySpan *source );
void IClearMembers( void );
// Please don't yell at me. We can't write out the instanceRef pointers, and we can't write
// out keys because we're not keyed objects, and we can't be keyed objects because we need
// to be deleted eventually. So instead, we assign each geoSpan a instanceGroupID, unique
// for each instance group but identical among all geoSpans in a given group (i.e. all
// members of the instanceRef list). We write these IDs out, then on read, we rebuild the
// instanceRef arrays by using a hash table to find insert new hsTArrays at the given groupID,
// and looking up in that hash table to get pointers for each geoSpan's instanceRef array.
// THIS is because we need a way of assigning unique, unused groupIDs to each geoSpan instance
// group, and since we only need to know if the ID has been used yet, we can just use a bitVector.
// NOTE: Group IDs start at 1, not 0, because 0 is reserved for "no instance group". So subtract
// 1 from the group ID when accessing this array...
// ....Please don't yell at me :(
static hsBitVector fInstanceGroupIDFlags;
// The following is for rebuilding the said groups on read. The sad thing is that we also
// have to write out the instanceRef array count for each geoSpan, so that when we read in
// to do the lookup here, we know that we've read everything and can dump the entry in this
// table.
static hsTArray<hsTArray<plGeometrySpan *> *> fInstanceGroups;
// THIS is so we can clear fInstanceGroups as early and as efficiently as possible; see
// the notes on IGetInstanceGroup().
static UInt32 fHighestReadInstanceGroup;
static UInt32 IAllocateNewGroupID( void );
static void IClearGroupID( UInt32 groupID );
static hsTArray<plGeometrySpan *> *IGetInstanceGroup( UInt32 groupID, UInt32 expectedCount );
};
#endif // _plGeometrySpan_h