2014-04-14 21:29:19 -05:00
# include "global.h"
# include <cassert>
# include "ActorMultiVertex.h"
# include "RageTextureManager.h"
# include "XmlFile.h"
# include "RageLog.h"
# include "RageDisplay.h"
# include "RageTexture.h"
# include "RageUtil.h"
# include "ActorUtil.h"
# include "Foreach.h"
# include "LuaBinding.h"
# include "LuaManager.h"
# include "LocalizedString.h"
static const char * DrawModeNames [ ] = {
" Quads " ,
" QuadStrip " ,
" Fan " ,
" Strip " ,
" Triangles " ,
" LineStrip " ,
" SymmetricQuadStrip " ,
} ;
static const int DrawModeVertexGroupSizes [ ] = {
4 , // Quads
2 , // QuadStrip
1 , // Fan
1 , // Strip
3 , // Triangles
1 , // LineStrip
3 , // SymmetricQuadStrip
1 , // NUM_DrawMode
1 , // DrawMode_Invalid
} ;
static const int DrawModeMinimumToDraw [ ] = {
4 , // Quads
4 , // QuadStrip
3 , // Fan
3 , // Strip
3 , // Triangles
2 , // LineStrip
6 , // SymmetricQuadStrip
1 , // NUM_DrawMode
1 , // DrawMode_Invalid
} ;
XToString ( DrawMode ) ;
XToLocalizedString ( DrawMode ) ;
LuaXType ( DrawMode ) ;
REGISTER_ACTOR_CLASS ( ActorMultiVertex ) ;
ActorMultiVertex : : ActorMultiVertex ( )
{
// Use blank texture by default.
RageTextureID ID = TEXTUREMAN - > GetDefaultTextureID ( ) ;
_Texture = TEXTUREMAN - > LoadTexture ( ID ) ;
_EffectMode = EffectMode_Normal ;
_TextureMode = TextureMode_Modulate ;
}
ActorMultiVertex : : ~ ActorMultiVertex ( )
{
UnloadTexture ( ) ;
}
ActorMultiVertex : : ActorMultiVertex ( const ActorMultiVertex & cpy ) :
Actor ( cpy )
{
# define CPY(a) a = cpy.a
CPY ( AMV_Tweens ) ;
CPY ( AMV_current ) ;
CPY ( AMV_start ) ;
CPY ( _EffectMode ) ;
CPY ( _TextureMode ) ;
# undef CPY
if ( cpy . _Texture ! = NULL )
{
_Texture = TEXTUREMAN - > CopyTexture ( cpy . _Texture ) ;
}
else
{
_Texture = NULL ;
}
}
void ActorMultiVertex : : LoadFromNode ( const XNode * Node )
{
RString path ;
Node - > GetAttrValue ( " Texture " , path ) ;
if ( ! path . empty ( ) & & ! TEXTUREMAN - > IsTextureRegistered ( RageTextureID ( path ) ) )
{
ActorUtil : : GetAttrPath ( Node , " Texture " , path ) ;
}
if ( ! path . empty ( ) )
{
LoadFromTexture ( path ) ;
}
Actor : : LoadFromNode ( Node ) ;
}
void ActorMultiVertex : : SetTexture ( RageTexture * Texture )
{
if ( _Texture ! = Texture )
{
UnloadTexture ( ) ;
_Texture = Texture ;
}
}
void ActorMultiVertex : : LoadFromTexture ( RageTextureID ID )
{
RageTexture * Texture = NULL ;
if ( _Texture & & _Texture - > GetID ( ) = = ID )
{
return ;
}
Texture = TEXTUREMAN - > LoadTexture ( ID ) ;
SetTexture ( Texture ) ;
}
void ActorMultiVertex : : UnloadTexture ( )
{
if ( _Texture ! = NULL )
{
TEXTUREMAN - > UnloadTexture ( _Texture ) ;
_Texture = NULL ;
}
}
void ActorMultiVertex : : SetNumVertices ( size_t n )
{
if ( n = = 0 )
{
for ( size_t i = 0 ; i < AMV_Tweens . size ( ) ; + + i )
{
AMV_Tweens [ i ] . vertices . clear ( ) ;
}
AMV_current . vertices . clear ( ) ;
AMV_start . vertices . clear ( ) ;
}
else
{
for ( size_t i = 0 ; i < AMV_Tweens . size ( ) ; + + i )
{
AMV_Tweens [ i ] . vertices . resize ( n ) ;
}
AMV_current . vertices . resize ( n ) ;
AMV_start . vertices . resize ( n ) ;
}
}
void ActorMultiVertex : : AddVertex ( )
{
for ( size_t i = 0 ; i < AMV_Tweens . size ( ) ; + + i )
{
AMV_Tweens [ i ] . vertices . push_back ( RageSpriteVertex ( ) ) ;
}
AMV_current . vertices . push_back ( RageSpriteVertex ( ) ) ;
AMV_start . vertices . push_back ( RageSpriteVertex ( ) ) ;
}
void ActorMultiVertex : : AddVertices ( int Add )
{
int size = AMV_DestTweenState ( ) . vertices . size ( ) ;
size + = Add ;
for ( size_t i = 0 ; i < AMV_Tweens . size ( ) ; + + i )
{
AMV_Tweens [ i ] . vertices . resize ( size ) ;
}
AMV_current . vertices . resize ( size ) ;
AMV_start . vertices . resize ( size ) ;
}
void ActorMultiVertex : : SetVertexPos ( int index , float x , float y , float z )
{
AMV_DestTweenState ( ) . vertices [ index ] . p = RageVector3 ( x , y , z ) ;
}
void ActorMultiVertex : : SetVertexColor ( int index , RageColor c )
{
AMV_DestTweenState ( ) . vertices [ index ] . c = c ;
}
void ActorMultiVertex : : SetVertexCoords ( int index , float TexCoordX , float TexCoordY )
{
AMV_DestTweenState ( ) . vertices [ index ] . t = RageVector2 ( TexCoordX , TexCoordY ) ;
}
void ActorMultiVertex : : DrawPrimitives ( )
{
Actor : : SetGlobalRenderStates ( ) ; // set Actor-specified render states
DISPLAY - > ClearAllTextures ( ) ;
DISPLAY - > SetTexture ( TextureUnit_1 , _Texture - > GetTexHandle ( ) ) ;
Actor : : SetTextureRenderStates ( ) ;
DISPLAY - > SetEffectMode ( _EffectMode ) ;
// set temporary diffuse and glow
static AMV_TweenState TS ;
AMV_TempState = & TS ;
TS = AMV_current ;
// skip if no change or fully transparent
if ( m_pTempState - > diffuse [ 0 ] ! = RageColor ( 1 , 1 , 1 , 1 ) & & m_pTempState - > diffuse [ 0 ] . a > 0 )
{
for ( size_t i = 0 ; i < TS . vertices . size ( ) ; i + + )
{
// RageVColor * RageColor
TS . vertices [ i ] . c . b * = m_pTempState - > diffuse [ 0 ] . b ;
TS . vertices [ i ] . c . r * = m_pTempState - > diffuse [ 0 ] . r ;
TS . vertices [ i ] . c . g * = m_pTempState - > diffuse [ 0 ] . g ;
TS . vertices [ i ] . c . a * = m_pTempState - > diffuse [ 0 ] . a ;
}
}
// Draw diffuse pass.
if ( m_pTempState - > diffuse [ 0 ] . a > 0 )
{
DISPLAY - > SetTextureMode ( TextureUnit_1 , _TextureMode ) ;
DrawInternal ( AMV_TempState ) ;
}
// Draw the glow pass
if ( m_pTempState - > glow . a > 0 )
{
for ( size_t i = 0 ; i < TS . vertices . size ( ) ; i + + )
{
TS . vertices [ i ] . c = m_pTempState - > glow ;
}
DISPLAY - > SetTextureMode ( TextureUnit_1 , TextureMode_Glow ) ;
DrawInternal ( AMV_TempState ) ;
}
}
void ActorMultiVertex : : DrawInternal ( const AMV_TweenState * TS )
{
int FirstToDraw = TS - > FirstToDraw ;
int NumToDraw = TS - > GetSafeNumToDraw ( TS - > _DrawMode , TS - > NumToDraw ) ;
if ( NumToDraw = = 0 )
{
// Nothing to draw.
return ;
}
switch ( TS - > _DrawMode )
{
case DrawMode_Quads :
{
DISPLAY - > DrawQuads ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
case DrawMode_QuadStrip :
{
DISPLAY - > DrawQuadStrip ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
case DrawMode_Fan :
{
DISPLAY - > DrawFan ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
case DrawMode_Strip :
{
DISPLAY - > DrawStrip ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
case DrawMode_Triangles :
{
DISPLAY - > DrawTriangles ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
case DrawMode_LineStrip :
{
DISPLAY - > DrawLineStrip ( & TS - > vertices [ FirstToDraw ] , NumToDraw , TS - > line_width ) ;
break ;
}
case DrawMode_SymmetricQuadStrip :
{
DISPLAY - > DrawSymmetricQuadStrip ( & TS - > vertices [ FirstToDraw ] , NumToDraw ) ;
break ;
}
}
DISPLAY - > SetEffectMode ( EffectMode_Normal ) ;
}
bool ActorMultiVertex : : EarlyAbortDraw ( ) const
{
if ( AMV_current . FirstToDraw > = ( int ) AMV_current . vertices . size ( ) | | AMV_current . _DrawMode > = NUM_DrawMode )
{
return true ;
}
return false ;
}
void ActorMultiVertex : : SetCurrentTweenStart ( )
{
AMV_start = AMV_current ;
}
void ActorMultiVertex : : EraseHeadTween ( )
{
AMV_current = AMV_Tweens [ 0 ] ;
AMV_Tweens . erase ( AMV_Tweens . begin ( ) ) ;
}
void ActorMultiVertex : : UpdatePercentThroughTween ( float PercentThroughTween )
{
AMV_TweenState : : MakeWeightedAverage ( AMV_current , AMV_start , AMV_Tweens [ 0 ] , PercentThroughTween ) ;
}
void ActorMultiVertex : : BeginTweening ( float time , ITween * pTween )
{
Actor : : BeginTweening ( time , pTween ) ;
if ( AMV_Tweens . size ( ) > = 1 ) // if there was already a TS on the stack
{
AMV_Tweens . push_back ( AMV_Tweens . back ( ) ) ;
}
else
{
AMV_Tweens . push_back ( AMV_current ) ;
}
}
void ActorMultiVertex : : StopTweening ( )
{
AMV_Tweens . clear ( ) ;
Actor : : StopTweening ( ) ;
}
void ActorMultiVertex : : FinishTweening ( )
{
if ( ! AMV_Tweens . empty ( ) )
{
AMV_current = AMV_DestTweenState ( ) ;
}
Actor : : FinishTweening ( ) ;
}
void ActorMultiVertex : : AMV_TweenState : : SetDrawState ( DrawMode dm , int first , int num )
{
if ( first > = ( int ) vertices . size ( ) & & vertices . size ( ) > 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex:SetDrawState: FirstToDraw > vertices.size(), %d > %u " , FirstToDraw + 1 , ( unsigned int ) vertices . size ( ) ) ;
2014-04-14 21:29:19 -05:00
return ;
}
int safe_num = GetSafeNumToDraw ( dm , num ) ;
if ( num ! = safe_num & & num ! = - 1 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex:SetDrawState: NumToDraw %d is not valid for %u vertices with DrawMode %s " , num , ( unsigned int ) vertices . size ( ) , DrawModeNames [ dm ] ) ;
2014-04-14 21:29:19 -05:00
return ;
}
_DrawMode = dm ;
FirstToDraw = first ;
NumToDraw = num ;
}
void ActorMultiVertex : : AMV_TweenState : : MakeWeightedAverage ( AMV_TweenState & average_out , const AMV_TweenState & ts1 , const AMV_TweenState & ts2 , float percent_between )
{
average_out . line_width = lerp ( percent_between , ts1 . line_width , ts2 . line_width ) ;
for ( size_t v = 0 ; v < average_out . vertices . size ( ) ; + + v )
{
WeightedAvergeOfRSVs ( average_out . vertices [ v ] , ts1 . vertices [ v ] , ts2 . vertices [ v ] , percent_between ) ;
}
}
int ActorMultiVertex : : AMV_TweenState : : GetSafeNumToDraw ( DrawMode dm , int num ) const
{
int max = vertices . size ( ) - FirstToDraw ;
// NumToDraw == -1 draws all vertices
if ( num = = - 1 | | num > max )
{
num = max ;
}
num - = ( num % DrawModeVertexGroupSizes [ dm ] ) ;
if ( num < DrawModeMinimumToDraw [ dm ] )
{
num = 0 ;
}
return num ;
}
// lua start
# include "LuaBinding.h"
/** @brief Allow Lua to have access to the ActorMultiVertex. */
class LunaActorMultiVertex : public Luna < ActorMultiVertex >
{
public :
static int SetNumVertices ( T * p , lua_State * L )
{
p - > SetNumVertices ( IArg ( 1 ) ) ;
return 0 ;
}
static int GetNumVertices ( T * p , lua_State * L ) { lua_pushnumber ( L , p - > GetNumVertices ( ) ) ; return 1 ; }
static void SetVertexFromStack ( T * p , lua_State * L , size_t VertexIndex , int DataStackIndex )
{
// Use the number of arguments to determine which property a table is for
if ( lua_type ( L , DataStackIndex ) ! = LUA_TTABLE )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertex: non-table parameter supplied. Table of tables of vertex data expected. " ) ;
2014-04-14 21:29:19 -05:00
return ;
}
size_t NumDataParts = lua_objlen ( L , DataStackIndex ) ;
for ( size_t i = 0 ; i < NumDataParts ; + + i )
{
lua_pushnumber ( L , i + 1 ) ;
lua_gettable ( L , DataStackIndex ) ;
int DataPieceIndex = lua_gettop ( L ) ;
size_t DataPieceElements = lua_objlen ( L , DataPieceIndex ) ;
if ( lua_type ( L , DataPieceIndex ) ! = LUA_TTABLE )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertex: non-table parameter %u supplied inside table of parameters, table expected. " , ( unsigned int ) i ) ;
2014-04-14 21:29:19 -05:00
return ;
}
int pushes = 1 ;
if ( DataPieceElements = = 2 )
{
pushes + = 2 ;
lua_rawgeti ( L , DataPieceIndex , 1 ) ;
float x = FArg ( - 1 ) ;
lua_rawgeti ( L , DataPieceIndex , 2 ) ;
float y = FArg ( - 1 ) ;
p - > SetVertexCoords ( VertexIndex , x , y ) ;
}
else if ( DataPieceElements = = 3 )
{
pushes + = 3 ;
lua_rawgeti ( L , DataPieceIndex , 1 ) ;
float x = FArg ( - 1 ) ;
lua_rawgeti ( L , DataPieceIndex , 2 ) ;
float y = FArg ( - 1 ) ;
lua_rawgeti ( L , DataPieceIndex , 3 ) ;
float z = FArg ( - 1 ) ;
p - > SetVertexPos ( VertexIndex , x , y , z ) ;
}
else if ( DataPieceElements = = 4 )
{
// RageColor pops the things it pushes onto the stack, so we don't need to.
RageColor c ;
// Does not use FromStackCompat because we are not compatible with passing a color in non-table form.
c . FromStack ( L , DataPieceIndex ) ;
p - > SetVertexColor ( VertexIndex , c ) ;
}
else
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertex: Parameter %u has %u elements supplied. 2, 3, or 4 expected. " , ( unsigned int ) i , ( unsigned int ) DataPieceElements ) ;
2014-04-14 21:29:19 -05:00
}
// Avoid a stack underflow by only popping the amount we pushed.
lua_pop ( L , pushes ) ;
}
return ;
}
static int SetVertex ( T * p , lua_State * L )
{
// Indices from Lua are one-indexed. -1 to adjust.
int Index = IArg ( 1 ) - 1 ;
if ( Index < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertex: index %d provided, cannot set Index < 1 " , Index + 1 ) ;
2014-04-14 21:29:19 -05:00
return 0 ;
}
else if ( Index = = ( int ) p - > GetNumVertices ( ) )
{
p - > AddVertices ( 1 ) ;
}
else if ( Index > ( int ) p - > GetNumVertices ( ) )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertex: Cannot set vertex %d if there is no vertex %d, only %u vertices. " , Index + 1 , Index , ( unsigned int ) p - > GetNumVertices ( ) ) ;
2014-04-14 21:29:19 -05:00
return 0 ;
}
SetVertexFromStack ( p , L , Index , lua_gettop ( L ) ) ;
return 0 ;
}
static int SetVertices ( T * p , lua_State * L )
{
int First = 0 ;
int StackIndex = lua_gettop ( L ) ;
// Allow the user to just pass a table without specifying a starting point.
if ( lua_type ( L , 1 ) = = LUA_TNUMBER )
{
// Indices from Lua are one-indexed. -1 to adjust.
First = IArg ( 1 ) - 1 ;
if ( First < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetVertices: index %d provided, cannot set Index < 1 " , First + 1 ) ;
2014-04-14 21:29:19 -05:00
return 0 ;
}
}
int Last = First + lua_objlen ( L , StackIndex ) ;
if ( Last > ( int ) p - > GetNumVertices ( ) )
{
p - > AddVertices ( Last - p - > GetNumVertices ( ) ) ;
}
for ( int n = First ; n < Last ; + + n )
{
lua_pushnumber ( L , n - First + 1 ) ;
lua_gettable ( L , StackIndex ) ;
SetVertexFromStack ( p , L , n , lua_gettop ( L ) ) ;
lua_pop ( L , 1 ) ;
}
return 0 ;
}
static int SetEffectMode ( T * p , lua_State * L )
{
EffectMode em = Enum : : Check < EffectMode > ( L , 1 ) ;
p - > SetEffectMode ( em ) ;
return 0 ;
}
static int SetTextureMode ( T * p , lua_State * L )
{
TextureMode tm = Enum : : Check < TextureMode > ( L , 1 ) ;
p - > SetTextureMode ( tm ) ;
return 0 ;
}
static int SetLineWidth ( T * p , lua_State * L )
{
float Width = FArg ( 1 ) ;
if ( Width < 0 )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex::SetLineWidth: cannot set negative width. " ) ;
2014-04-14 21:29:19 -05:00
return 0 ;
}
p - > SetLineWidth ( Width ) ;
return 0 ;
}
static int SetDrawState ( T * p , lua_State * L )
{
DrawMode dm = p - > GetDestDrawMode ( ) ;
int first = p - > GetDestFirstToDraw ( ) ;
int num = p - > GetDestNumToDraw ( ) ;
int ArgsIndex = 1 ;
if ( ! lua_istable ( L , ArgsIndex ) )
{
2014-07-07 00:39:27 -06:00
LuaHelpers : : ReportScriptErrorFmt ( " ActorMultiVertex:SetDrawState: Table expected, something else recieved. Doing nothing. " ) ;
2014-04-14 21:29:19 -05:00
return 0 ;
}
// Fetch the draw mode, if provided.
lua_getfield ( L , ArgsIndex , " Mode " ) ;
if ( ! lua_isnil ( L , - 1 ) )
{
dm = Enum : : Check < DrawMode > ( L , - 1 ) ;
}
lua_pop ( L , 1 ) ;
// Fetch FirstToDraw, if provided.
lua_getfield ( L , ArgsIndex , " First " ) ;
if ( ! lua_isnil ( L , - 1 ) )
{
// Indices from Lua are one-indexed. -1 to adjust.
first = IArg ( - 1 ) - 1 ;
}
lua_pop ( L , 1 ) ;
// Fetch NumToDraw, if provided.
lua_getfield ( L , ArgsIndex , " Num " ) ;
if ( ! lua_isnil ( L , - 1 ) )
{
num = IArg ( - 1 ) ;
}
lua_pop ( L , 1 ) ;
p - > SetDrawState ( dm , first , num ) ;
return 0 ;
}
static int GetDestDrawMode ( T * p , lua_State * L )
{
Enum : : Push ( L , p - > GetDestDrawMode ( ) ) ;
return 1 ;
}
static int GetDestFirstToDraw ( T * p , lua_State * L )
{
// Indices in Lua are one-indexed. +1 to adjust.
lua_pushnumber ( L , p - > GetDestFirstToDraw ( ) + 1 ) ;
return 1 ;
}
static int GetDestNumToDraw ( T * p , lua_State * L )
{
lua_pushnumber ( L , p - > GetDestNumToDraw ( ) ) ;
return 1 ;
}
static int GetCurrDrawMode ( T * p , lua_State * L )
{
Enum : : Push ( L , p - > GetCurrDrawMode ( ) ) ;
return 1 ;
}
static int GetCurrFirstToDraw ( T * p , lua_State * L )
{
// Indices in Lua are one-indexed. +1 to adjust.
lua_pushnumber ( L , p - > GetCurrFirstToDraw ( ) + 1 ) ;
return 1 ;
}
static int GetCurrNumToDraw ( T * p , lua_State * L )
{
lua_pushnumber ( L , p - > GetCurrNumToDraw ( ) ) ;
return 1 ;
}
static int LoadTexture ( T * p , lua_State * L )
{
if ( lua_isnil ( L , 1 ) )
{
p - > UnloadTexture ( ) ;
}
else
{
RageTextureID ID ( SArg ( 1 ) ) ;
p - > LoadFromTexture ( ID ) ;
}
return 0 ;
}
static int SetTexture ( T * p , lua_State * L )
{
RageTexture * Texture = Luna < RageTexture > : : check ( L , 1 ) ;
Texture = TEXTUREMAN - > CopyTexture ( Texture ) ;
p - > SetTexture ( Texture ) ;
return 0 ;
}
2014-09-02 05:18:29 -06:00
static int GetTexture ( T * p , lua_State * L )
{
RageTexture * texture = p - > GetTexture ( ) ;
if ( texture ! = NULL )
{
texture - > PushSelf ( L ) ;
}
else
{
lua_pushnil ( L ) ;
}
return 1 ;
}
2014-04-14 21:29:19 -05:00
LunaActorMultiVertex ( )
{
ADD_METHOD ( SetVertex ) ;
ADD_METHOD ( SetVertices ) ;
ADD_METHOD ( SetEffectMode ) ;
ADD_METHOD ( SetTextureMode ) ;
ADD_METHOD ( SetLineWidth ) ;
ADD_METHOD ( SetDrawState ) ;
ADD_METHOD ( SetNumVertices ) ;
ADD_METHOD ( GetNumVertices ) ;
ADD_METHOD ( GetDestDrawMode ) ;
ADD_METHOD ( GetDestFirstToDraw ) ;
ADD_METHOD ( GetDestNumToDraw ) ;
ADD_METHOD ( GetCurrDrawMode ) ;
ADD_METHOD ( GetCurrFirstToDraw ) ;
ADD_METHOD ( GetCurrNumToDraw ) ;
// Copy from RageTexture
ADD_METHOD ( SetTexture ) ;
2014-09-02 05:18:29 -06:00
ADD_METHOD ( GetTexture ) ;
2014-04-14 21:29:19 -05:00
// Load from file path
ADD_METHOD ( LoadTexture ) ;
}
} ;
LUA_REGISTER_DERIVED_CLASS ( ActorMultiVertex , Actor )
/*
* (c) 2014 Matthew Gardner and Eric Reese
* All rights reserved.
*
* 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, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* 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 OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/