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.
1047 lines
28 KiB
1047 lines
28 KiB
14 years ago
|
/*==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==*/
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// plPlates.cpp - Implementation of plates and plate manager //
|
||
|
// //
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "hsWindows.h"
|
||
|
#include "hsTypes.h"
|
||
|
#include "plPipeline.h"
|
||
|
#include "plPlates.h"
|
||
|
|
||
|
#include "../plJPEG/plJPEG.h"
|
||
|
#include "../plGImage/plMipmap.h"
|
||
|
#include "../plSurface/plLayer.h"
|
||
|
#include "../plSurface/hsGMaterial.h"
|
||
|
#include "../plMessage/plLayRefMsg.h"
|
||
|
#include "../pnMessage/plRefMsg.h"
|
||
|
#include "hsGDeviceRef.h"
|
||
|
#include "hsResMgr.h"
|
||
|
#include "plPipeDebugFlags.h"
|
||
|
|
||
|
|
||
|
// A bit of a hack so that we will have the correct instance in the SceneViewer
|
||
|
static HINSTANCE gHInstance = GetModuleHandle(nil);
|
||
|
|
||
|
void SetHInstance(void *instance)
|
||
|
{
|
||
|
gHInstance = (HINSTANCE)instance;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//// plPlate Functions ///////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
UInt32 plPlate::fMagicUniqueKeyInt = 0;
|
||
|
|
||
|
plPlate::plPlate( plPlate **owningHandle )
|
||
|
{
|
||
|
fXformMatrix.Reset();
|
||
|
fDepth = 1.0f;
|
||
|
fMaterial = nil;
|
||
|
fFlags = 0;
|
||
|
fOpacity = 1.f;
|
||
|
|
||
|
fNext = nil;
|
||
|
fPrevPtr = nil;
|
||
|
fOwningHandle = owningHandle;
|
||
|
fMipmap = nil;
|
||
|
memset( fTitle, 0, sizeof( fTitle ) );
|
||
|
}
|
||
|
|
||
|
plPlate::~plPlate()
|
||
|
{
|
||
|
if( fFlags & kFlagLocalMaterial )
|
||
|
fMaterial->GetKey()->UnRefObject();
|
||
|
else
|
||
|
{
|
||
|
hsRefCnt_SafeUnRef( fMaterial );
|
||
|
}
|
||
|
|
||
|
fMaterial = nil;
|
||
|
*fOwningHandle = nil;
|
||
|
}
|
||
|
|
||
|
//// SetPosition /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlate::SetPosition( hsScalar x, hsScalar y, hsScalar z )
|
||
|
{
|
||
|
hsVector3 triple;
|
||
|
|
||
|
|
||
|
if( z != -1.0f )
|
||
|
{
|
||
|
/// Gotta resort--let the manager do it
|
||
|
plPlateManager::Instance().IResortPlate( this, ( z + 1.0f <= fDepth ) ? true : false );
|
||
|
fDepth = z + 1.0f;
|
||
|
}
|
||
|
|
||
|
x *= fDepth / 1.0f;
|
||
|
y *= fDepth / 1.0f;
|
||
|
triple.fX = x;
|
||
|
triple.fY = y;
|
||
|
triple.fZ = fDepth;
|
||
|
|
||
|
fXformMatrix.SetTranslate( &triple );
|
||
|
}
|
||
|
|
||
|
//// SetSize /////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlate::SetSize( hsScalar width, hsScalar height, bool adjustByAspectRation )
|
||
|
{
|
||
|
hsVector3 size;
|
||
|
|
||
|
width *= fDepth / 1.0f;
|
||
|
height *= fDepth / 1.0f;
|
||
|
|
||
|
size.fX = adjustByAspectRation ? (width * ((hsScalar)plPlateManager::Instance().GetPipeHeight() / (hsScalar)plPlateManager::Instance().GetPipeWidth())) : width;
|
||
|
size.fY = height;
|
||
|
size.fZ = 1.0f;
|
||
|
|
||
|
fXformMatrix.SetScale( &size );
|
||
|
}
|
||
|
|
||
|
//// SetTransform ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlate::SetTransform( hsMatrix44 &matrix, hsBool reSort )
|
||
|
{
|
||
|
fXformMatrix = matrix;
|
||
|
if( reSort )
|
||
|
plPlateManager::Instance().IResortPlate( this, false );
|
||
|
}
|
||
|
|
||
|
//// SetMaterial /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlate::SetMaterial( hsGMaterial *material )
|
||
|
{
|
||
|
hsRefCnt_SafeAssign( fMaterial, material );
|
||
|
}
|
||
|
|
||
|
void plPlate::SetTexture(plBitmap *texture)
|
||
|
{
|
||
|
plLayer *layer;
|
||
|
hsGMaterial *material;
|
||
|
char keyName[ 128 ];
|
||
|
|
||
|
material = TRACKED_NEW hsGMaterial();
|
||
|
sprintf( keyName, "PlateBlank#%d", fMagicUniqueKeyInt++ );
|
||
|
hsgResMgr::ResMgr()->NewKey( keyName, material, plLocation::kGlobalFixedLoc );
|
||
|
layer = material->MakeBaseLayer();
|
||
|
layer->SetShadeFlags( layer->GetShadeFlags() | hsGMatState::kShadeNoShade | hsGMatState::kShadeWhite | hsGMatState::kShadeReallyNoFog );
|
||
|
layer->SetZFlags( layer->GetZFlags() | hsGMatState::kZNoZRead );
|
||
|
layer->SetBlendFlags( layer->GetBlendFlags() | hsGMatState::kBlendAlpha );
|
||
|
layer->SetOpacity( fOpacity );
|
||
|
layer->SetUVWSrc(plLayerInterface::kUVWPassThru);
|
||
|
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(texture->GetKey(), TRACKED_NEW plGenRefMsg(layer->GetKey(), plRefMsg::kOnCreate, -1, plLayRefMsg::kTexture), plRefFlags::kActiveRef);
|
||
|
|
||
|
SetMaterial(material);
|
||
|
}
|
||
|
|
||
|
//// SetOpacity //////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlate::SetOpacity( hsScalar opacity )
|
||
|
{
|
||
|
if( fMaterial != nil && fMaterial->GetLayer( 0 ) != nil )
|
||
|
{
|
||
|
plLayer *layer = (plLayer *)fMaterial->GetLayer( 0 );
|
||
|
layer->SetOpacity( opacity );
|
||
|
}
|
||
|
|
||
|
fOpacity = opacity;
|
||
|
}
|
||
|
|
||
|
//// CreateMaterial /////////////////////////////////////////////////////
|
||
|
// Creates a new material for this plate with either a specified texture
|
||
|
// or an empty, white-filled bitmap.
|
||
|
|
||
|
plMipmap *plPlate::CreateMaterial( UInt32 width, UInt32 height, hsBool withAlpha, plMipmap* texture )
|
||
|
{
|
||
|
plLayer *layer;
|
||
|
hsGMaterial *material;
|
||
|
char keyName[ 128 ];
|
||
|
|
||
|
|
||
|
if (texture)
|
||
|
{
|
||
|
fMipmap = texture;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/// Create a new bitmap
|
||
|
fMipmap = TRACKED_NEW plMipmap( width, height, withAlpha ? plMipmap::kARGB32Config : plMipmap::kRGB32Config, 1 );
|
||
|
memset( fMipmap->GetImage(), 0xff, height * fMipmap->GetRowBytes() );
|
||
|
sprintf( keyName, "PlateBitmap#%d", fMagicUniqueKeyInt++ );
|
||
|
hsgResMgr::ResMgr()->NewKey( keyName, fMipmap, plLocation::kGlobalFixedLoc );
|
||
|
fMipmap->SetFlags( fMipmap->GetFlags() | plMipmap::kDontThrowAwayImage );
|
||
|
}
|
||
|
|
||
|
/// NOW create a layer wrapper and a material for that layer
|
||
|
material = TRACKED_NEW hsGMaterial();
|
||
|
sprintf( keyName, "PlateBlank#%d", fMagicUniqueKeyInt++ );
|
||
|
hsgResMgr::ResMgr()->NewKey( keyName, material, plLocation::kGlobalFixedLoc );
|
||
|
layer = material->MakeBaseLayer();
|
||
|
layer->SetShadeFlags( layer->GetShadeFlags() | hsGMatState::kShadeNoShade | hsGMatState::kShadeWhite | hsGMatState::kShadeReallyNoFog );
|
||
|
layer->SetZFlags( layer->GetZFlags() | hsGMatState::kZNoZRead );
|
||
|
layer->SetBlendFlags( layer->GetBlendFlags() | hsGMatState::kBlendAlpha );
|
||
|
layer->SetOpacity( fOpacity );
|
||
|
|
||
|
hsgResMgr::ResMgr()->AddViaNotify( fMipmap->GetKey(), TRACKED_NEW plLayRefMsg( layer->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef );
|
||
|
|
||
|
// Set up a ref to these. Since we don't have a key, we use the
|
||
|
// generic RefObject() (and matching UnRefObject() when we're done).
|
||
|
// If we had a key, we would use myKey->AddViaNotify(otherKey) and myKey->Release(otherKey).
|
||
|
material->GetKey()->RefObject();
|
||
|
|
||
|
/// Set this as our new material and return the bitmap
|
||
|
fFlags |= kFlagLocalMaterial;
|
||
|
fMaterial = material;
|
||
|
return fMipmap;
|
||
|
}
|
||
|
|
||
|
//// CreateFromResource //////////////////////////////////////////////////////
|
||
|
// Creates a plate's material from a resource of the given name.
|
||
|
|
||
|
// This is where hacks beget hacks.
|
||
|
// We have two problems here. First, the main cursor we use most of the time (IDB_CURSOR_UP)
|
||
|
// is a greyscale cursor, so it's color is copied to alpha and then set to white. But its
|
||
|
// color doesn't go to black, it goes to 0x040404, which when used for alpha is just enough
|
||
|
// to be annoying in 32 bit (ghost white square around cursor).
|
||
|
// Second, Win98 seems to be doing some sort of dither on the cursors that use a color key
|
||
|
// (colorKey == 0xff00ff), so the purple parts aren't exactly matching the colorKey, so
|
||
|
// we have a big opaque (except for the parts that dither out to 0xff00ff) purple square
|
||
|
// around the cursor.
|
||
|
// So, when it comes to color keying, we're going to pretend we're in 16 bit mode, and only
|
||
|
// check the upper 5 bits of each channel. If they match the colorKey, close enough to be
|
||
|
// transparent.
|
||
|
// For grey scale, if the alpha comes out less than 8 (upper 5 bits off), again close enough
|
||
|
// for complete transparency.
|
||
|
//
|
||
|
// All this happens in CreateFromResource and ReloadFromResource, so I've moved the alpha setting
|
||
|
// code to a function they can both use, rather than cut and pasting code (what a concept, must
|
||
|
// be one of those new-fangled OOP patterns).
|
||
|
//
|
||
|
void plPlate::ISetResourceAlphas(UInt32 colorKey)
|
||
|
{
|
||
|
if( !fMipmap )
|
||
|
return;
|
||
|
|
||
|
/// Set alphas
|
||
|
colorKey &= 0x00f8f8f8;
|
||
|
|
||
|
UInt32 numPix = fMipmap->GetWidth() * fMipmap->GetHeight();
|
||
|
|
||
|
UInt32 *d;
|
||
|
int i;
|
||
|
hsBool hasColorKey = false;
|
||
|
for( i = 0, d = (UInt32 *)(fMipmap->GetImage()); i < numPix; i++ )
|
||
|
{
|
||
|
if( (d[ i ] & 0x00f8f8f8) == colorKey )
|
||
|
{
|
||
|
hasColorKey = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if( hasColorKey )
|
||
|
{
|
||
|
for( i = 0, d = (UInt32 *)(fMipmap->GetImage()); i < numPix; i++ )
|
||
|
{
|
||
|
// Win98 for some reason likes to return full alpha on the pixels,
|
||
|
// whereas Win2k/XP likes 0 alpha. Go figure...
|
||
|
if( ( d[ i ] & 0x00f8f8f8 ) == colorKey )
|
||
|
d[ i ] = 0;
|
||
|
else
|
||
|
d[ i ] |= 0xff000000;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No color key, must be a b/w alpha mask
|
||
|
for( i = 0, d = (UInt32 *)(fMipmap->GetImage()); i < numPix; i++ )
|
||
|
{
|
||
|
UInt32 alpha = d[i] & 0xff;
|
||
|
if( !(alpha & 0xf8) )
|
||
|
d[i] = 0x00ffffff;
|
||
|
else
|
||
|
d[ i ] = ( alpha << 24 ) | 0x00ffffff;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void plPlate::CreateFromResource( const char *resName, UInt32 colorKey )
|
||
|
{
|
||
|
/*
|
||
|
Someday the following might actually work, once we get a plugin that
|
||
|
exports a material in the latest format, plus have the material actually
|
||
|
read in its layers (or maybe we'll have to read() them in manually?)
|
||
|
Right now, we just keep it here so we don't have to look up how to do it
|
||
|
when we need it.
|
||
|
|
||
|
hsRAMStream rsrcStream;
|
||
|
HGLOBAL rsrcHdl;
|
||
|
HRSRC findInfo;
|
||
|
UInt8 *ptr;
|
||
|
UInt32 size;
|
||
|
|
||
|
|
||
|
findInfo = FindResource( GetModuleHandle( nil ), (LPCTSTR)1001, "HSMR" );
|
||
|
size = SizeofResource( GetModuleHandle( nil ), findInfo );
|
||
|
rsrcHdl = LoadResource( GetModuleHandle( nil ), findInfo );
|
||
|
ptr = (UInt8 *)LockResource( rsrcHdl );
|
||
|
|
||
|
rsrcStream.Write( size, ptr );
|
||
|
|
||
|
UnlockResource( rsrcHdl );
|
||
|
|
||
|
rsrcStream.Rewind();
|
||
|
|
||
|
fMaterial = TRACKED_NEW hsGMaterial;
|
||
|
fMaterial->Read( &rsrcStream );
|
||
|
*/
|
||
|
UInt32 width, height;
|
||
|
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
HBITMAP rsrc;
|
||
|
BITMAPINFO bMapInfo;
|
||
|
HDC hDC = GetDC( nil );
|
||
|
|
||
|
rsrc = (HBITMAP)LoadImage( gHInstance, resName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
|
||
|
if( rsrc == nil )
|
||
|
{
|
||
|
/// Copy data into a new material
|
||
|
CreateMaterial( 32, 32, true );
|
||
|
SetSize( 0.1, 0.1 );
|
||
|
ReleaseDC( nil, hDC );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// hsAssert( rsrc != nil, "Cannot find specified resource" );
|
||
|
|
||
|
memset( &bMapInfo, 0, sizeof( bMapInfo ) );
|
||
|
bMapInfo.bmiHeader.biSize = sizeof( bMapInfo.bmiHeader );
|
||
|
height = GetDIBits( hDC, rsrc, 0, 0, nil, &bMapInfo, DIB_RGB_COLORS );
|
||
|
hsAssert( height != 0, "Cannot get resource bitmap bits" );
|
||
|
|
||
|
width = bMapInfo.bmiHeader.biWidth;
|
||
|
height = bMapInfo.bmiHeader.biHeight;
|
||
|
bMapInfo.bmiHeader.biBitCount = 32;
|
||
|
bMapInfo.bmiHeader.biCompression = BI_RGB;
|
||
|
#endif
|
||
|
|
||
|
/// Copy data into a new material
|
||
|
CreateMaterial( width, height, true );
|
||
|
SetSize( (float)width, (float)height );
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
bMapInfo.bmiHeader.biHeight *= -1;
|
||
|
GetDIBits( hDC, rsrc, 0, height, fMipmap->GetImage(), &bMapInfo, DIB_RGB_COLORS );
|
||
|
|
||
|
ReleaseDC( nil, hDC );
|
||
|
DeleteObject( rsrc );
|
||
|
#endif
|
||
|
|
||
|
ISetResourceAlphas(colorKey);
|
||
|
}
|
||
|
|
||
|
//// ReloadFromResource //////////////////////////////////////////////////////
|
||
|
// Creates a plate's material from a resource of the given name.
|
||
|
|
||
|
void plPlate::ReloadFromResource( const char *resName, UInt32 colorKey )
|
||
|
{
|
||
|
UInt32 width, height;
|
||
|
|
||
|
|
||
|
if( !fMaterial || fMaterial->GetNumLayers() < 1 || fMaterial->GetLayer( 0 ) == nil || fMipmap == nil )
|
||
|
{
|
||
|
hsStatusMessage( "WARNING: Not refilling plate material; bitmap not yet assigned\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
HBITMAP rsrc;
|
||
|
BITMAPINFO bMapInfo;
|
||
|
HDC hDC = GetDC( nil );
|
||
|
|
||
|
rsrc = (HBITMAP)LoadImage( gHInstance, resName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
|
||
|
if( rsrc == nil )
|
||
|
{
|
||
|
ReleaseDC( nil, hDC );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// hsAssert( rsrc != nil, "Cannot find specified resource" );
|
||
|
|
||
|
memset( &bMapInfo, 0, sizeof( bMapInfo ) );
|
||
|
bMapInfo.bmiHeader.biSize = sizeof( bMapInfo.bmiHeader );
|
||
|
height = GetDIBits( hDC, rsrc, 0, 0, nil, &bMapInfo, DIB_RGB_COLORS );
|
||
|
hsAssert( height != 0, "Cannot get resource bitmap bits" );
|
||
|
|
||
|
width = bMapInfo.bmiHeader.biWidth;
|
||
|
height = bMapInfo.bmiHeader.biHeight;
|
||
|
bMapInfo.bmiHeader.biBitCount = 32;
|
||
|
bMapInfo.bmiHeader.biCompression = BI_RGB;
|
||
|
#endif
|
||
|
|
||
|
/// Copy the data into the existing material
|
||
|
if( fMipmap->GetWidth() != width || fMipmap->GetHeight() != height )
|
||
|
{
|
||
|
hsStatusMessage( "WARNING: Not refilling plate material; resource size does not match\n" );
|
||
|
}
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
bMapInfo.bmiHeader.biHeight *= -1;
|
||
|
GetDIBits( hDC, rsrc, 0, height, fMipmap->GetImage(), &bMapInfo, DIB_RGB_COLORS );
|
||
|
|
||
|
ReleaseDC( nil, hDC );
|
||
|
DeleteObject( rsrc );
|
||
|
#endif
|
||
|
|
||
|
ISetResourceAlphas(colorKey);
|
||
|
|
||
|
if( fMipmap->GetDeviceRef() )
|
||
|
fMipmap->GetDeviceRef()->SetDirty( true );
|
||
|
}
|
||
|
|
||
|
void plPlate::CreateFromJPEGResource( const char *resName, UInt32 colorKey )
|
||
|
{
|
||
|
hsRAMStream stream;
|
||
|
plMipmap* jpgTexture = nil;
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
|
||
|
HRSRC res = FindResource(NULL, resName, "JPEG");
|
||
|
if (!res)
|
||
|
goto error;
|
||
|
|
||
|
HGLOBAL resourceLoaded = LoadResource(NULL, res);
|
||
|
if (!resourceLoaded)
|
||
|
goto error;
|
||
|
|
||
|
byte* data = (byte*)LockResource(resourceLoaded);
|
||
|
if (!data)
|
||
|
goto error;
|
||
|
|
||
|
DWORD resSize = SizeofResource(NULL, res);
|
||
|
if (resSize == 0)
|
||
|
goto error;
|
||
|
|
||
|
stream.Write(sizeof(DWORD), &resSize);
|
||
|
stream.Write(resSize, data);
|
||
|
stream.Rewind();
|
||
|
|
||
|
UnlockResource(resourceLoaded);
|
||
|
|
||
|
char keyName[128];
|
||
|
sprintf( keyName, "PlateJPEG#%d", fMagicUniqueKeyInt++ );
|
||
|
|
||
|
jpgTexture = plJPEG::Instance().ReadFromStream(&stream);
|
||
|
|
||
|
if (jpgTexture)
|
||
|
{
|
||
|
hsgResMgr::ResMgr()->NewKey(keyName, jpgTexture, plLocation::kGlobalFixedLoc);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
CreateMaterial( 256, 256, true, jpgTexture);
|
||
|
ISetResourceAlphas(colorKey);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
error:
|
||
|
/// Copy data into a new material
|
||
|
CreateMaterial( 32, 32, true );
|
||
|
SetSize( 0.1, 0.1 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void plPlate::ReloadFromJPEGResource( const char *resName, UInt32 colorKey )
|
||
|
{
|
||
|
hsRAMStream stream;
|
||
|
plMipmap* jpgTexture = nil;
|
||
|
|
||
|
#if HS_BUILD_FOR_WIN32
|
||
|
|
||
|
HRSRC res = FindResource(NULL, resName, "JPEG");
|
||
|
if (!res)
|
||
|
return;
|
||
|
|
||
|
HGLOBAL resourceLoaded = LoadResource(NULL, res);
|
||
|
if (!resourceLoaded)
|
||
|
return;
|
||
|
|
||
|
byte* data = (byte*)LockResource(resourceLoaded);
|
||
|
if (!data)
|
||
|
return;
|
||
|
|
||
|
DWORD resSize = SizeofResource(NULL, res);
|
||
|
if (resSize == 0)
|
||
|
return;
|
||
|
|
||
|
stream.Write(sizeof(DWORD), &resSize);
|
||
|
stream.Write(resSize, data);
|
||
|
stream.Rewind();
|
||
|
|
||
|
UnlockResource(resourceLoaded);
|
||
|
|
||
|
jpgTexture = plJPEG::Instance().ReadFromStream(&stream);
|
||
|
|
||
|
if (jpgTexture)
|
||
|
{
|
||
|
|
||
|
#endif
|
||
|
fMipmap->CopyFrom(jpgTexture);
|
||
|
|
||
|
ISetResourceAlphas(colorKey);
|
||
|
|
||
|
if( fMipmap->GetDeviceRef() )
|
||
|
fMipmap->GetDeviceRef()->SetDirty( true );
|
||
|
|
||
|
delete jpgTexture;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// ILink ///////////////////////////////////////////////////////////////////
|
||
|
// Links a plate into a plate list, but also sorts by decreasing depth,
|
||
|
// so the plate won't actually necessarily be added after the pointer
|
||
|
// given.
|
||
|
|
||
|
void plPlate::ILink( plPlate **back )
|
||
|
{
|
||
|
hsAssert( fNext == nil && fPrevPtr == nil, "Trying to link a plate that's already linked" );
|
||
|
|
||
|
|
||
|
/// Advance back as far as we need to go
|
||
|
while( *back != nil && (*back)->fDepth > fDepth )
|
||
|
back = &( (*back)->fNext );
|
||
|
|
||
|
/// Link!
|
||
|
fNext = *back;
|
||
|
if( *back )
|
||
|
(*back)->fPrevPtr = &fNext;
|
||
|
fPrevPtr = back;
|
||
|
*back = this;
|
||
|
}
|
||
|
|
||
|
hsBool plPlate::IsVisible()
|
||
|
{
|
||
|
// return not-visible if our material is not valid
|
||
|
if (fMaterial->GetNumLayers() == 0)
|
||
|
return false;
|
||
|
plLayerInterface* layer = fMaterial->GetLayer(0);
|
||
|
if (layer->GetTexture() == nil)
|
||
|
return false;
|
||
|
|
||
|
// cursory check of material indicates it's valid, return our visible flag status
|
||
|
return ( fFlags & kFlagVisible ) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//// plGraphPlate Functions //////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//// Constructor & Destructor ////////////////////////////////////////////////
|
||
|
|
||
|
plGraphPlate::plGraphPlate( plPlate **owningHandle ) : plPlate( owningHandle )
|
||
|
{
|
||
|
fFlags |= kFlagIsAGraph;
|
||
|
SetLabelText( nil );
|
||
|
}
|
||
|
|
||
|
plGraphPlate::~plGraphPlate()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//// IMakePow2 ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
UInt32 plGraphPlate::IMakePow2( UInt32 value )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
|
||
|
for( i = 0; value != 0; i++, value >>= 1 );
|
||
|
return 1 << i;
|
||
|
}
|
||
|
|
||
|
//// SetDataRange ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::SetDataRange( UInt32 min, UInt32 max, UInt32 width )
|
||
|
{
|
||
|
UInt32 height;
|
||
|
|
||
|
|
||
|
width = IMakePow2( width + 4 );
|
||
|
height = IMakePow2( max - min + 1 + 4 );
|
||
|
|
||
|
CreateMaterial( width, height, true );
|
||
|
fMin = min;
|
||
|
fMax = max;
|
||
|
|
||
|
SetDataLabels( fMin, fMax );
|
||
|
SetColors();
|
||
|
SetDataColors();
|
||
|
ClearData();
|
||
|
}
|
||
|
|
||
|
//// SetDataLabels ///////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::SetDataLabels( UInt32 min, UInt32 max )
|
||
|
{
|
||
|
fLabelMin = min;
|
||
|
fLabelMax = max;
|
||
|
}
|
||
|
|
||
|
//// ClearData ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::ClearData( void )
|
||
|
{
|
||
|
UInt32 *bits = (UInt32 *)fMipmap->GetImage(), *ptr;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
// Background color
|
||
|
for( i = 0; i < fMipmap->GetWidth() * fMipmap->GetHeight(); bits[ i ] = fBGHexColor, i++ );
|
||
|
|
||
|
// Axes
|
||
|
ptr = bits + fMipmap->GetWidth();
|
||
|
*ptr = fAxesHexColor;
|
||
|
for( ptr++, i = 0; i < fMipmap->GetHeight() - 4; i++, ptr += fMipmap->GetWidth() )
|
||
|
*ptr = fAxesHexColor;
|
||
|
for( i = 0; i < fMipmap->GetWidth() - 4; ptr[ i ] = fAxesHexColor, i++ );
|
||
|
ptr += fMipmap->GetWidth() - 1;
|
||
|
ptr[ 0 ] = fAxesHexColor;
|
||
|
ptr[ fMipmap->GetWidth() - 5 + 1 ] = fAxesHexColor;
|
||
|
|
||
|
if( fMaterial->GetLayer( 0 ) != nil && fMaterial->GetLayer( 0 )->GetTexture() )
|
||
|
{
|
||
|
hsGDeviceRef *ref = fMaterial->GetLayer( 0 )->GetTexture()->GetDeviceRef();
|
||
|
if( ref != nil )
|
||
|
ref->SetDirty( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// AddData /////////////////////////////////////////////////////////////////
|
||
|
// Scroll graph data left by one, then add the new value
|
||
|
|
||
|
void plGraphPlate::AddData( Int32 value, Int32 value2, Int32 value3, Int32 value4 )
|
||
|
{
|
||
|
std::vector<Int32> values;
|
||
|
if (value != -1)
|
||
|
values.push_back(value);
|
||
|
if (value2 != -1)
|
||
|
values.push_back(value2);
|
||
|
if (value3 != -1)
|
||
|
values.push_back(value3);
|
||
|
if (value4 != -1)
|
||
|
values.push_back(value4);
|
||
|
AddData(values);
|
||
|
}
|
||
|
|
||
|
void plGraphPlate::AddData( std::vector<Int32> values )
|
||
|
{
|
||
|
hsAssert( fMipmap != nil, "Trying to add data to an uninitialized plGraphPlate" );
|
||
|
|
||
|
fMipmap->SetCurrLevel( 0 );
|
||
|
|
||
|
UInt32 *bits = (UInt32 *)fMipmap->GetImage(), *ptr;
|
||
|
UInt32 *minDPos = fMipmap->GetAddr32( 3, fMipmap->GetHeight() - 3 - 10 );
|
||
|
UInt32 *maxDPos = fMipmap->GetAddr32( 3, 2 );
|
||
|
int i, j;
|
||
|
std::vector<int> lows, his;
|
||
|
float lineCtr, lineInc;
|
||
|
int lastLineInt, lineInt, bumpCtr;
|
||
|
|
||
|
// make sure we have enough colors
|
||
|
if (values.size() > fDataHexColors.size())
|
||
|
{
|
||
|
for (i=fDataHexColors.size(); i<values.size(); i++)
|
||
|
fDataHexColors.push_back(0xff00ff00); // make it a nice green color
|
||
|
}
|
||
|
|
||
|
// make sure we have enough "last values"
|
||
|
if (values.size() > fLastValues.size())
|
||
|
{
|
||
|
for (i=fLastValues.size(); i<values.size(); i++)
|
||
|
fLastValues.push_back(0);
|
||
|
}
|
||
|
|
||
|
// Scale values
|
||
|
for (i=0; i<values.size(); i++)
|
||
|
{
|
||
|
lows.push_back(0);
|
||
|
his.push_back(0);
|
||
|
|
||
|
if( values[ i ] > fLabelMax )
|
||
|
values[ i ] = fLabelMax;
|
||
|
else if( values[ i ] < fLabelMin )
|
||
|
values[ i ] = fLabelMin;
|
||
|
values[ i ] = (UInt32)( (float)values[ i ] * ( fMipmap->GetHeight() - 4 ) / ( fLabelMax - fLabelMin + 1 ) );
|
||
|
|
||
|
if( values[ i ] < fLastValues[ i ] )
|
||
|
{
|
||
|
lows[ i ] = values[ i ] - 1;
|
||
|
his[ i ] = fLastValues[ i ];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lows[ i ] = fLastValues[ i ] - 1;
|
||
|
his[ i ] = values[ i ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lineCtr = 0;
|
||
|
lastLineInt = 0;
|
||
|
bumpCtr = 0;
|
||
|
lineInc = 8.0f / ( fMipmap->GetHeight() - 4 );
|
||
|
IDrawNumber( fLabelMin, minDPos, fMipmap->GetWidth(), fBGHexColor );
|
||
|
IDrawNumber( fLabelMax, maxDPos, fMipmap->GetWidth(), fBGHexColor );
|
||
|
for( i = 0, ptr = bits + fMipmap->GetWidth() + 2, j = fMipmap->GetHeight() - 4; i < fMipmap->GetHeight() - 4; i++, j-- )
|
||
|
{
|
||
|
lineInt = (int)lineCtr;
|
||
|
if( lineInt != lastLineInt )
|
||
|
bumpCtr = 2;
|
||
|
|
||
|
memmove( ptr, ptr + 1, ( fMipmap->GetWidth() - 5 ) * sizeof( UInt32 ) );
|
||
|
int dataIndex;
|
||
|
bool dataPlotted = false;
|
||
|
for (dataIndex = 0; dataIndex < values.size(); dataIndex++)
|
||
|
{
|
||
|
if( j >= lows[ dataIndex ] && j <= his[ dataIndex ] )
|
||
|
{
|
||
|
ptr[ fMipmap->GetWidth() - 5 ] = fDataHexColors[ dataIndex ];
|
||
|
dataPlotted = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!dataPlotted)
|
||
|
{
|
||
|
if( bumpCtr > 0 )
|
||
|
{
|
||
|
if( lineInt == 4 )
|
||
|
ptr[ fMipmap->GetWidth() - 5 ] = fGraphHexColor | 0xff000000;
|
||
|
else
|
||
|
ptr[ fMipmap->GetWidth() - 5 ] = fGraphHexColor;
|
||
|
bumpCtr--;
|
||
|
}
|
||
|
else
|
||
|
ptr[ fMipmap->GetWidth() - 5 ] = fBGHexColor;
|
||
|
}
|
||
|
|
||
|
ptr += fMipmap->GetWidth();
|
||
|
|
||
|
lastLineInt = lineInt;
|
||
|
lineCtr += lineInc;
|
||
|
}
|
||
|
IDrawNumber( fLabelMin, minDPos, fMipmap->GetWidth(), fAxesHexColor );
|
||
|
IDrawNumber( fLabelMax, maxDPos, fMipmap->GetWidth(), fAxesHexColor );
|
||
|
|
||
|
fLastValues = values;
|
||
|
|
||
|
if( fMaterial->GetLayer( 0 ) != nil && fMaterial->GetLayer( 0 )->GetTexture() != nil )
|
||
|
{
|
||
|
hsGDeviceRef *ref = fMaterial->GetLayer( 0 )->GetTexture()->GetDeviceRef();
|
||
|
if( ref != nil )
|
||
|
ref->SetDirty( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// SetColors ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::SetColors( UInt32 bgHexColor, UInt32 axesHexColor, UInt32 dataHexColor, UInt32 graphHexColor )
|
||
|
{
|
||
|
fBGHexColor = bgHexColor;
|
||
|
fAxesHexColor = axesHexColor;
|
||
|
if (fDataHexColors.size() == 0)
|
||
|
fDataHexColors.push_back(dataHexColor);
|
||
|
else
|
||
|
fDataHexColors[ 0 ] = dataHexColor;
|
||
|
fGraphHexColor = graphHexColor;
|
||
|
|
||
|
ClearData();
|
||
|
}
|
||
|
|
||
|
//// SetDataColors ///////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::SetDataColors( UInt32 hexColor1, UInt32 hexColor2, UInt32 hexColor3, UInt32 hexColor4 )
|
||
|
{
|
||
|
std::vector<UInt32> colors;
|
||
|
colors.push_back(hexColor1);
|
||
|
colors.push_back(hexColor2);
|
||
|
colors.push_back(hexColor3);
|
||
|
colors.push_back(hexColor4);
|
||
|
SetDataColors(colors);
|
||
|
}
|
||
|
|
||
|
void plGraphPlate::SetDataColors( const std::vector<UInt32> & hexColors )
|
||
|
{
|
||
|
fDataHexColors = hexColors;
|
||
|
}
|
||
|
|
||
|
//// SetLabelText ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::SetLabelText( char *text1, char *text2, char *text3, char *text4 )
|
||
|
{
|
||
|
std::vector<std::string> strings;
|
||
|
if( text1 != nil )
|
||
|
strings.push_back(text1);
|
||
|
else
|
||
|
strings.push_back("");
|
||
|
|
||
|
if( text2 != nil )
|
||
|
strings.push_back(text2);
|
||
|
else
|
||
|
strings.push_back("");
|
||
|
|
||
|
if( text3 != nil )
|
||
|
strings.push_back(text3);
|
||
|
else
|
||
|
strings.push_back("");
|
||
|
|
||
|
if( text4 != nil )
|
||
|
strings.push_back(text4);
|
||
|
else
|
||
|
strings.push_back("");
|
||
|
SetLabelText(strings);
|
||
|
}
|
||
|
|
||
|
void plGraphPlate::SetLabelText( const std::vector<std::string> & text )
|
||
|
{
|
||
|
fLabelText = text;
|
||
|
}
|
||
|
|
||
|
//// IDrawNumber /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::IDrawNumber( UInt32 number, UInt32 *dataPtr, UInt32 stride, UInt32 color )
|
||
|
{
|
||
|
char str[ 16 ];
|
||
|
int i;
|
||
|
|
||
|
|
||
|
sprintf( str, "%d", number );
|
||
|
for( i = 0; str[ i ] != 0; i++ )
|
||
|
{
|
||
|
IDrawDigit( str[ i ] - '0', dataPtr, stride, color );
|
||
|
dataPtr += 7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// IDrawDigit //////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plGraphPlate::IDrawDigit( char digit, UInt32 *dataPtr, UInt32 stride, UInt32 color )
|
||
|
{
|
||
|
/// Yes, I know this is ugly. Move it into another file if you like.
|
||
|
char digits[ 10 ][ 5 * 3 ] =
|
||
|
{ { 1,1,1,
|
||
|
1,0,1,
|
||
|
1,0,1,
|
||
|
1,0,1,
|
||
|
1,1,1 },
|
||
|
{ 0,1,0,
|
||
|
1,1,0,
|
||
|
0,1,0,
|
||
|
0,1,0,
|
||
|
1,1,1 },
|
||
|
{ 2,2,2,
|
||
|
0,0,2,
|
||
|
0,2,0,
|
||
|
2,0,0,
|
||
|
2,2,2 },
|
||
|
{ 3,3,3,
|
||
|
0,0,3,
|
||
|
3,3,3,
|
||
|
0,0,3,
|
||
|
3,3,3 },
|
||
|
{ 4,0,4,
|
||
|
4,0,4,
|
||
|
4,4,4,
|
||
|
0,0,4,
|
||
|
0,0,4 },
|
||
|
{ 5,5,5,
|
||
|
5,0,0,
|
||
|
5,5,5,
|
||
|
0,0,5,
|
||
|
5,5,5 },
|
||
|
{ 6,6,6,
|
||
|
6,0,0,
|
||
|
6,6,6,
|
||
|
6,0,6,
|
||
|
6,6,6 },
|
||
|
{ 7,7,7,
|
||
|
0,0,7,
|
||
|
0,0,7,
|
||
|
0,0,7,
|
||
|
0,0,7 },
|
||
|
{ 8,8,8,
|
||
|
8,0,8,
|
||
|
8,8,8,
|
||
|
8,0,8,
|
||
|
8,8,8 },
|
||
|
{ 9,9,9,
|
||
|
9,0,9,
|
||
|
9,9,9,
|
||
|
0,0,9,
|
||
|
0,0,9 } };
|
||
|
|
||
|
|
||
|
char *digData = digits[ digit ];
|
||
|
int i, j;
|
||
|
|
||
|
|
||
|
for( i = 0; i < 5; i++ )
|
||
|
{
|
||
|
for( j = 0; j < 6; j += 2 )
|
||
|
{
|
||
|
if( *digData )
|
||
|
{
|
||
|
dataPtr[ j ] = color;
|
||
|
dataPtr[ j + 1 ] = color;
|
||
|
dataPtr[ j + stride ] = color;
|
||
|
dataPtr[ j + stride + 1 ] = color;
|
||
|
}
|
||
|
digData++;
|
||
|
}
|
||
|
dataPtr += stride + stride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//// plPlateManager Functions ////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
plPlateManager *plPlateManager::fInstance = nil;
|
||
|
|
||
|
|
||
|
//// Destructor /////////////////////////////////////////////////////////////
|
||
|
|
||
|
plPlateManager::~plPlateManager()
|
||
|
{
|
||
|
while( fPlates != nil )
|
||
|
DestroyPlate( fPlates );
|
||
|
|
||
|
fInstance = nil;
|
||
|
}
|
||
|
|
||
|
//// CreatePlate /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlateManager::CreatePlate( plPlate **handle )
|
||
|
{
|
||
|
plPlate *plate = TRACKED_NEW plPlate( handle );
|
||
|
|
||
|
|
||
|
plate->ILink( &fPlates );
|
||
|
*handle = plate;
|
||
|
}
|
||
|
|
||
|
void plPlateManager::CreatePlate( plPlate **handle, hsScalar width, hsScalar height )
|
||
|
{
|
||
|
CreatePlate( handle );
|
||
|
(*handle)->SetSize( width, height );
|
||
|
}
|
||
|
|
||
|
void plPlateManager::CreatePlate( plPlate **handle, hsScalar x, hsScalar y, hsScalar width, hsScalar height )
|
||
|
{
|
||
|
CreatePlate( handle );
|
||
|
(*handle)->SetPosition( x, y );
|
||
|
(*handle)->SetSize( width, height );
|
||
|
}
|
||
|
|
||
|
void plPlateManager::CreateGraphPlate( plGraphPlate **handle )
|
||
|
{
|
||
|
plGraphPlate *plate = TRACKED_NEW plGraphPlate( (plPlate **)handle );
|
||
|
|
||
|
|
||
|
plate->ILink( &fPlates );
|
||
|
*handle = plate;
|
||
|
}
|
||
|
|
||
|
//// DestroyPlate ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlateManager::DestroyPlate( plPlate *plate )
|
||
|
{
|
||
|
if( plate != nil )
|
||
|
{
|
||
|
plate->IUnlink();
|
||
|
delete plate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// GetPipeWidth/Height /////////////////////////////////////////////////////
|
||
|
|
||
|
UInt32 plPlateManager::GetPipeWidth( void )
|
||
|
{
|
||
|
return fOwner->Width();
|
||
|
}
|
||
|
|
||
|
UInt32 plPlateManager::GetPipeHeight( void )
|
||
|
{
|
||
|
return fOwner->Height();
|
||
|
}
|
||
|
|
||
|
//// DrawToDevice ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlateManager::DrawToDevice( plPipeline *pipe )
|
||
|
{
|
||
|
if( !pipe->IsDebugFlagSet(plPipeDbg::kFlagNoPlates) )
|
||
|
IDrawToDevice( pipe );
|
||
|
}
|
||
|
|
||
|
//// IResortPlate ////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlateManager::IResortPlate( plPlate *plate, bool fromCurrent )
|
||
|
{
|
||
|
plPlate **start = &fPlates;
|
||
|
|
||
|
|
||
|
if( fromCurrent )
|
||
|
start = plate->fPrevPtr;
|
||
|
|
||
|
plate->IUnlink();
|
||
|
plate->ILink( start );
|
||
|
}
|
||
|
|
||
|
//// SetPlateScreenPos ///////////////////////////////////////////////////////
|
||
|
|
||
|
void plPlateManager::SetPlateScreenPos( plPlate *plate, UInt32 x, UInt32 y )
|
||
|
{
|
||
|
float cX = ( (float)x / fOwner->Width() ) * 2.0f - 1.0f;
|
||
|
float cY = ( (float)y / fOwner->Height() ) * 2.0f - 1.0f;
|
||
|
|
||
|
plate->SetPosition( cX, cY );
|
||
|
}
|
||
|
|
||
|
void plPlateManager::SetPlatePixelSize( plPlate *plate, UInt32 pWidth, UInt32 pHeight )
|
||
|
{
|
||
|
float width = (float)pWidth / fOwner->Width() * 2.0f;
|
||
|
float height = (float)pHeight / fOwner->Height() * 2.0f;
|
||
|
|
||
|
plate->SetSize(width, height);
|
||
|
}
|