From d55fc911129258a040e4c19e5319e6267c3b533a Mon Sep 17 00:00:00 2001 From: "wagic.jeck" Date: Mon, 14 Sep 2009 08:28:49 +0000 Subject: [PATCH] Jeck - [Requires JGE rebuild] Extensive cache improvements. * Numerous cache fixes, reduced filesystem access. * Cache fails very gracefully. * Cache is now a templated class, with individual caches per data-type. * Much easier to extend. * Extensively debugged. Try compiling with -DDEBUG_CACHE. * Caches limits can be set on a per-item basis. * hgeParticleSystemInfo are now cached, mana particles now fall back to defaults. * Samples are not cached, but track filesystem misses using the cache backbone. * Avatars are cached. Default baka avatar is now baka.jpg, to prevent collision with player. A note on the retrieval types: RETRIEVE_MANAGE puts a resource into a seperate, managed resource list. Managed resources are guarenteed valid for the lifetime of the program. Retrieving a managed quad promotes the associated texture to managed. Don't do that by mistake. Calls to Resources.Refresh() will attempt to reload managed resources in place. RETRIVE_LOCK (and by extension, RETRIEVE_VRAM), returns a resource after locking it. A resource may have many locks, and remains in cache until they are all released. If the resource is managed, it returns it unmodified. A note on quads: Unlike all other RetrieveWhatever() functions, the default behavior for RetrieveQuad is RETRIEVE_LOCK. Worse, Release(JQuad*) is slow, and will /always/ release one lock from the associated texture. There's a long and complicated explanation for this, involving support for live relinking of textures to existing quads, but basically what it means is that we only use RetrieveQuad for quads we intend to store and later Release(). If a temporary quad is needed, the preferred method is to use NEW JQuad* and SAFE_DELETE with RetrieveTexture(). RetrieveTempQuad is also provided, but is only guaranteed until the next call to the cache. Note that RetrieveCard has none of these problems. --- JGE/include/JResourceManager.h | 190 +- JGE/include/JTypes.h | 1031 +++++----- JGE/src/JResourceManager.cpp | 1007 ++++------ JGE/src/JSfx.cpp | 3 +- JGE/src/linux/JSfx.cpp | 2 + JGE/src/win/JSoundSystem_Win.cpp | 439 ++-- projects/mtg/Makefile | 2 +- .../ai/baka/{avatar.jpg => avatars/baka.jpg} | Bin projects/mtg/include/WCachedResource.h | 95 + projects/mtg/include/WResourceManager.h | 223 ++- projects/mtg/src/AIPlayer.cpp | 23 +- projects/mtg/src/CardGui.cpp | 32 +- projects/mtg/src/GameApp.cpp | 28 +- projects/mtg/src/GameStateDeckViewer.cpp | 2 +- projects/mtg/src/GameStateDuel.cpp | 5 +- projects/mtg/src/GameStateMenu.cpp | 24 +- projects/mtg/src/GameStateOptions.cpp | 2 +- projects/mtg/src/GuiCombat.cpp | 5 +- projects/mtg/src/GuiMana.cpp | 82 +- projects/mtg/src/MTGCardInstance.cpp | 1331 ++++++------- projects/mtg/src/OptionItem.cpp | 7 +- projects/mtg/src/Player.cpp | 10 +- projects/mtg/src/SimpleMenu.cpp | 8 +- projects/mtg/src/TestSuiteAI.cpp | 11 +- projects/mtg/src/WCachedResource.cpp | 387 ++++ projects/mtg/src/WResourceManager.cpp | 1767 ++++++++++------- projects/mtg/template.vcproj | 8 + 27 files changed, 3732 insertions(+), 2992 deletions(-) rename projects/mtg/bin/Res/ai/baka/{avatar.jpg => avatars/baka.jpg} (100%) create mode 100644 projects/mtg/include/WCachedResource.h create mode 100644 projects/mtg/src/WCachedResource.cpp diff --git a/JGE/include/JResourceManager.h b/JGE/include/JResourceManager.h index b9dcaef73..eb86ab469 100644 --- a/JGE/include/JResourceManager.h +++ b/JGE/include/JResourceManager.h @@ -1,102 +1,88 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- - -#ifndef _RESOURCE_MANAGER_H_ -#define _RESOURCE_MANAGER_H_ - -#ifdef WIN32 -#pragma warning(disable : 4786) -#endif - -#include -#include -#include -#include - -using namespace std; - - -#define INVALID_ID -1 - -class JRenderer; -class JSample; -class JMusic; -class JTexture; -class JQuad; -class JLBFont; - -class JResourceManager -{ -public: - JResourceManager(); - virtual ~JResourceManager(); - - //void SetResourceRoot(const string& resourceRoot); - bool LoadResource(const string& resourceName); - - void RemoveAll(); - - virtual int CreateTexture(const string &textureName); - JTexture* GetTexture(const string &textureName); - JTexture* GetTexture(int id); - - virtual int CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height); - JQuad* GetQuad(const string &quadName); - JQuad* GetQuad(int id); - - virtual int LoadJLBFont(const string &fontName, int height); - JLBFont* GetJLBFont(const string &fontName); - JLBFont* GetJLBFont(int id); - - virtual int LoadMusic(const string &musicName); - JMusic* GetMusic(const string &musicName); - JMusic* GetMusic(int id); - - virtual int LoadSample(const string &sampleName); - JSample* GetSample(const string &sampleName); - JSample* GetSample(int id); - -// int RegisterParticleEffect(const string &effectName); -// JParticleEffect* GetParticleEffect(const string &effectName); -// JParticleEffect* GetParticleEffect(int id); -// -// int RegisterMotionEmitter(const string &emitterName); -// JMotionEmitter* GetMotionEmitter(const string &emitterName); -// JMotionEmitter* GetMotionEmitter(int id); - -protected: - - //JRenderer *mRenderer; - - //string mResourceRoot; - - vector mTextureList; - map mTextureMap; - - vector mQuadList; - map mQuadMap; - -// vector mParticleEffectList; -// map mParticleEffectMap; -// -// vector mMotionEmitterList; -// map mMotionEmitterMap; - - vector mFontList; - map mFontMap; - - vector mMusicList; - map mMusicMap; - - vector mSampleList; - map mSampleMap; -}; - -#endif +//------------------------------------------------------------------------------------- +// +// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. +// +// Licensed under the BSD license, see LICENSE in JGE root for details. +// +// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) +// +//------------------------------------------------------------------------------------- + +#ifndef _RESOURCE_MANAGER_H_ +#define _RESOURCE_MANAGER_H_ + +#ifdef WIN32 +#pragma warning(disable : 4786) +#endif + +#include +#include +#include +#include + +using namespace std; + + +#define INVALID_ID -1 + +class JRenderer; +class JSample; +class JMusic; +class JTexture; +class JQuad; +class JLBFont; + +class JResourceManager +{ +public: + JResourceManager(); + virtual ~JResourceManager(); + + //void SetResourceRoot(const string& resourceRoot); + bool LoadResource(const string& resourceName); + + virtual void RemoveAll(); + + virtual int CreateTexture(const string &textureName); + virtual JTexture* GetTexture(const string &textureName); + virtual JTexture* GetTexture(int id); + + virtual int CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height); + virtual JQuad* GetQuad(const string &quadName); + virtual JQuad* GetQuad(int id); + + virtual int LoadJLBFont(const string &fontName, int height); + virtual JLBFont* GetJLBFont(const string &fontName); + virtual JLBFont* GetJLBFont(int id); + +// int RegisterParticleEffect(const string &effectName); +// JParticleEffect* GetParticleEffect(const string &effectName); +// JParticleEffect* GetParticleEffect(int id); +// +// int RegisterMotionEmitter(const string &emitterName); +// JMotionEmitter* GetMotionEmitter(const string &emitterName); +// JMotionEmitter* GetMotionEmitter(int id); + +protected: + + //JRenderer *mRenderer; + + //string mResourceRoot; + + vector mTextureList; + map mTextureMap; + + vector mQuadList; + map mQuadMap; + +// vector mParticleEffectList; +// map mParticleEffectMap; +// +// vector mMotionEmitterList; +// map mMotionEmitterMap; + + vector mFontList; + map mFontMap; +}; + +#endif diff --git a/JGE/include/JTypes.h b/JGE/include/JTypes.h index aba171564..ca5be11da 100644 --- a/JGE/include/JTypes.h +++ b/JGE/include/JTypes.h @@ -1,515 +1,516 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- - -#ifndef _JTYPES_H -#define _JTYPES_H - -#if defined (WIN32) || defined (LINUX) - -#include - -#else - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "JAudio.h" - -#endif - -#ifndef __GNUC__ -#define __attribute__(arg) -#endif - - -#define MAX_CHANNEL 128 - - -#ifndef M_PI -#define M_PI 3.14159265358979323846f -#define M_PI_2 1.57079632679489661923f -#define M_PI_4 0.785398163397448309616f -#define M_1_PI 0.318309886183790671538f -#define M_2_PI 0.636619772367581343076f -#endif - -#define RAD2DEG 57.29577951f -#define DEG2RAD 0.017453293f - -#define SAFE_DELETE(x) do { if (x) { delete x; x = NULL; } } while(false) -#define SAFE_DELETE_ARRAY(x) if (x) { delete [] x; x = NULL; } - - -#define SCREEN_WIDTH 480 -#define SCREEN_HEIGHT 272 -#define SCREEN_WIDTH_F 480.0f -#define SCREEN_HEIGHT_F 272.0f - - -#ifdef WIN32 -// #define DEFAULT_BLEND BLEND_DEFAULT -// #define BLEND_OPTION_ADD BLEND_COLORADD -// #define BLEND_OPTION_BLEND (BLEND_COLORADD | BLEND_ALPHABLEND | BLEND_NOZWRITE) -#else - #define DEFAULT_BLEND GU_TFX_MODULATE - #define BLEND_OPTION_ADD GU_TFX_ADD - #define BLEND_OPTION_BLEND GU_TFX_BLEND -#endif - -#ifdef WIN32 - #include -#endif -#ifdef LINUX - typedef unsigned char byte; - typedef unsigned long DWORD; - typedef unsigned char BYTE; - typedef bool BOOL; -#endif -#if defined (WIN32) || defined (LINUX) - - #include - #include - - #include "../Dependencies/include/fmod.h" - - //#include "../HGE/include/hge.h" - //#include "../HGE/include/hgeSprite.h" - - //#define u8 BYTE - //#define u16 WORD - //#define u32 DWORD -/* - typedef signed char s8; - typedef signed short s16; - typedef signed long s32; - typedef unsigned char u8; - typedef unsigned short u16; - typedef unsigned long u32; -*/ -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; - - - #define BLEND_ZERO GL_ZERO - #define BLEND_ONE GL_ONE - #define BLEND_SRC_COLOR GL_SRC_COLOR - #define BLEND_ONE_MINUS_SRC_COLOR GL_ONE_MINUS_SRC_COLOR - #define BLEND_SRC_ALPHA GL_SRC_ALPHA - #define BLEND_ONE_MINUS_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA - #define BLEND_DST_ALPHA GL_DST_ALPHA - #define BLEND_ONE_MINUS_DST_ALPHA GL_ONE_MINUS_DST_ALPHA - #define BLEND_DST_COLOR GL_DST_COLOR - #define BLEND_ONE_MINUS_DST_COLOR GL_ONE_MINUS_DST_COLOR - #define BLEND_SRC_ALPHA_SATURATE GL_SRC_ALPHA_SATURATE - - #define ARGB(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) - #define RGBA(r, g, b, a) (((a) << 24) | ((b) << 16) | ((g) << 8) | (r)) - - typedef enum PspCtrlButtons - { - PSP_CTRL_SELECT = 0x000001, - PSP_CTRL_START = 0x000008, - PSP_CTRL_UP = 0x000010, - PSP_CTRL_RIGHT = 0x000020, - PSP_CTRL_DOWN = 0x000040, - PSP_CTRL_LEFT = 0x000080, - PSP_CTRL_LTRIGGER = 0x000100, - PSP_CTRL_RTRIGGER = 0x000200, - PSP_CTRL_TRIANGLE = 0x001000, - PSP_CTRL_CIRCLE = 0x002000, - PSP_CTRL_CROSS = 0x004000, - PSP_CTRL_SQUARE = 0x008000, - PSP_CTRL_HOME = 0x010000, - PSP_CTRL_HOLD = 0x020000, - PSP_CTRL_NOTE = 0x800000 - } PspCtrlButtons; - - #define TEXTURE_FORMAT 0 - #define GU_PSM_8888 0 - #define GU_PSM_5551 0 - #define GU_PSM_4444 0 - #define PIXEL_TYPE DWORD - -#else // PSP - - #ifndef ABGR8888 - #define ABGR8888 - #endif - - - #if defined (ABGR8888) - #ifndef ARGB - #define ARGB(a, r, g, b) ((a << 24) | (b << 16) | (g << 8) | r) // macro to assemble pixels in correct format - #endif - #define MAKE_COLOR(a, c) (a << 24 | c) - #define MASK_ALPHA 0xFF000000 // masks for accessing individual pixels - #define MASK_BLUE 0x00FF0000 - #define MASK_GREEN 0x0000FF00 - #define MASK_RED 0x000000FF - #define PIXEL_TYPE u32 - #define PIXEL_SIZE 4 - #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_8888 - - #define BUFFER_FORMAT GU_PSM_8888 - #define TEXTURE_FORMAT GU_PSM_8888 - #define TEXTURE_COLOR_FORMAT GU_COLOR_8888 - - - #elif defined (ABGR5551) - - #ifndef ARGB - #define ARGB(a, r, g, b) ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | ((a >> 7) << 15)) - #endif - #define MAKE_COLOR(a, c) (((a>>7)<<15) | c) - #define MASK_ALPHA 0x8000 - #define MASK_BLUE 0x7C00 - #define MASK_GREEN 0x03E0 - #define MASK_RED 0x001F - #define PIXEL_TYPE u16 - #define PIXEL_SIZE 2 - #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_5551 - - #define BUFFER_FORMAT GU_PSM_8888 - #define TEXTURE_FORMAT GU_PSM_5551 - #define TEXTURE_COLOR_FORMAT GU_COLOR_5551 - - #elif defined (ABGR4444) - #ifndef ARGB - #define ARGB(a, r, g, b) ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12)) - #endif - #define MAKE_COLOR(a, c) (((a>>4)<<12) | c) - #define MASK_ALPHA 0xF000 - #define MASK_BLUE 0x0F00 - #define MASK_GREEN 0x00F0 - #define MASK_RED 0x000F - #define PIXEL_TYPE u16 - #define PIXEL_SIZE 2 - #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_4444 - - #define BUFFER_FORMAT GU_PSM_4444 - #define TEXTURE_FORMAT GU_PSM_4444 - #define TEXTURE_COLOR_FORMAT GU_COLOR_4444 - - #endif - - #define FRAME_BUFFER_WIDTH 512 - #define FRAME_BUFFER_SIZE FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*PIXEL_SIZE - - #define SLICE_SIZE_F 64.0f - typedef unsigned int DWORD; - - #define BLEND_ZERO 0x1000 - #define BLEND_ONE 0x1002 - #define BLEND_SRC_COLOR GU_SRC_COLOR - #define BLEND_ONE_MINUS_SRC_COLOR GU_ONE_MINUS_SRC_COLOR - #define BLEND_SRC_ALPHA GU_SRC_ALPHA - #define BLEND_ONE_MINUS_SRC_ALPHA GU_ONE_MINUS_SRC_ALPHA - #define BLEND_DST_ALPHA GU_DST_ALPHA - #define BLEND_ONE_MINUS_DST_ALPHA GU_ONE_MINUS_DST_ALPHA - #define BLEND_DST_COLOR GU_DST_COLOR - #define BLEND_ONE_MINUS_DST_COLOR GU_ONE_MINUS_DST_COLOR - #define BLEND_SRC_ALPHA_SATURATE BLEND_ONE - - typedef struct - { - ScePspFVector2 texture; - //PIXEL_TYPE color; - //ScePspFVector3 normal; - ScePspFVector3 pos; - } PSPVertex3D; - - -#endif - - - - -//------------------------------------------------------------------------------------------------ -struct Vertex -{ - float u, v; - PIXEL_TYPE color; - float x, y, z; -}; - - -//------------------------------------------------------------------------------------------------ -struct Vertex3D -{ - float u, v; - //float nx, ny, nz; - float x, y, z; -}; - - -//------------------------------------------------------------------------------------------------ -struct VertexColor -{ - PIXEL_TYPE color; - float x, y, z; -}; - - -struct JColor -{ - union - { - struct - { - u8 b; - u8 g; - u8 r; - u8 a; - }; - DWORD color; - }; -}; - - - -enum -{ - TEX_TYPE_NONE, - TEX_TYPE_USE_VRAM, - TEX_TYPE_MIPMAP, - TEX_TYPE_NORMAL, - TEX_TYPE_SKYBOX -}; - - -enum -{ - MODE_UNKNOWN, - MODE_2D, - MODE_3D -}; - - -enum -{ - TEX_FILTER_NONE, - TEX_FILTER_LINEAR, - TEX_FILTER_NEAREST -}; - -//------------------------------------------------------------------------------------------------ -class JTexture -{ -public: - JTexture(); - ~JTexture(); - - void UpdateBits(int x, int y, int width, int height, PIXEL_TYPE* bits); - - int mWidth; - int mHeight; - int mTexWidth; - int mTexHeight; - - int mFilter; - -#if defined (WIN32) || defined (LINUX) - GLuint mTexId; -#else - int mTextureFormat; - int mTexId; - bool mInVideoRAM; - PIXEL_TYPE* mBits; -#endif -}; - - -////////////////////////////////////////////////////////////////////////// -/// Custom filter for processing the texture image while loading. You -/// can change the pixels by using a custom filter before the image is -/// created as a texture. -/// -////////////////////////////////////////////////////////////////////////// -class JImageFilter -{ -public: - - ////////////////////////////////////////////////////////////////////////// - /// Pure virtual function for the custom filter to implement. - /// - /// @param pix - Image data. - /// @param width - Width of the image. - /// @param height - Height of the image. - /// - ////////////////////////////////////////////////////////////////////////// - virtual void ProcessImage(PIXEL_TYPE* pix, int width, int height) = 0; -}; - - -////////////////////////////////////////////////////////////////////////// -/// Image quad. -/// -////////////////////////////////////////////////////////////////////////// -class JQuad -{ -public: - - ////////////////////////////////////////////////////////////////////////// - /// Constructor. - /// - /// @param tex - Texture of the quad. - /// @param x - X position of the quad in texture. - /// @param y - Y position of the quad in texture. - /// @param width - Width of the quad. - /// @param height - Height of the quad. - /// - ////////////////////////////////////////////////////////////////////////// - JQuad(JTexture *tex, float x, float y, float width, float height); - - ////////////////////////////////////////////////////////////////////////// - /// Set blending color of the quad. - /// - /// @param color - Color. - /// - ////////////////////////////////////////////////////////////////////////// - void SetColor(PIXEL_TYPE color); - - ////////////////////////////////////////////////////////////////////////// - /// Set anchor point of the quad. - /// - /// @param x - X position of the anchor point. - /// @param y - Y position of the anchor point. - /// - ////////////////////////////////////////////////////////////////////////// - void SetHotSpot(float x, float y); - - ////////////////////////////////////////////////////////////////////////// - /// Set UV positions of the quad. - /// - /// @param x - X position of the quad in texture. - /// @param y - Y position of the quad in texture. - /// @param w - Width of the quad. - /// @param h - Height of the quad. - /// - ////////////////////////////////////////////////////////////////////////// - void SetTextureRect(float x, float y, float w, float h); - - ////////////////////////////////////////////////////////////////////////// - /// Get UV positions of the quad. - /// - /// @return x - X position of the quad in texture. - /// @return y - Y position of the quad in texture. - /// @return w - Width of the quad. - /// @return h - Height of the quad. - /// - ////////////////////////////////////////////////////////////////////////// - void GetTextureRect(float *x, float *y, float *w, float *h); - - ////////////////////////////////////////////////////////////////////////// - /// Set horizontal flipping. - /// - /// @param hflip - flipping flag; - /// - ////////////////////////////////////////////////////////////////////////// - void SetHFlip(bool hflip) { mHFlipped = hflip; } - - ////////////////////////////////////////////////////////////////////////// - /// Set vetical flipping. - /// - /// @param hflip - flipping flag; - /// - ////////////////////////////////////////////////////////////////////////// - void SetVFlip(bool vflip) { mVFlipped = vflip; } - - JTexture* mTex; - -#if defined (WIN32) || defined(LINUX) - float mTX0; - float mTY0; - float mTX1; - float mTY1; - JColor mColor[4]; // up to 4 vertices -#else - PIXEL_TYPE mColor[4]; // up to 4 vertices - int mBlend; // GU_TFX_MODULATE, GU_TFX_DECAL, GU_TFX_BLEND, GU_TFX_REPLACE, GU_TFX_ADD -#endif - - float mX; - float mY; - float mWidth; - float mHeight; - float mHotSpotX; - float mHotSpotY; - - bool mHFlipped; - bool mVFlipped; -}; - -//#endif - - -////////////////////////////////////////////////////////////////////////// -/// \enum JFONT_TEXT_ALIGNMENT -/// -/// Font alignment. -/// -////////////////////////////////////////////////////////////////////////// -enum JFONT_TEXT_ALIGNMENT -{ - JGETEXT_LEFT, ///< Text alignment to left. - JGETEXT_CENTER, ///< Text alignment to center. - JGETEXT_RIGHT ///< Text alignment to right. -}; - - -enum JINIT_FLAG -{ - JINIT_FLAG_NORMAL, - JINIT_FLAG_ENABLE3D -}; - - -//------------------------------------------------------------------------------------------------ -class JFont -{ -public: - JQuad* mQuad; - int mWidth; - int mHeight; - int mSpacing; - int mAlign; - float mScale; -}; - - -//------------------------------------------------------------------------------------------------ -class Rect -{ -public: - int x; - int y; - int width; - int height; - -public: - Rect(int _x, int _y, int _width, int _height): x(_x), y(_y), width(_width), height(_height) {} - -}; - - - -#endif +//------------------------------------------------------------------------------------- +// +// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. +// +// Licensed under the BSD license, see LICENSE in JGE root for details. +// +// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) +// +//------------------------------------------------------------------------------------- + +#ifndef _JTYPES_H +#define _JTYPES_H + +#if defined (WIN32) || defined (LINUX) + +#include + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "JAudio.h" + +#endif + +#ifndef __GNUC__ +#define __attribute__(arg) +#endif + + +#define MAX_CHANNEL 128 + + +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#define M_PI_2 1.57079632679489661923f +#define M_PI_4 0.785398163397448309616f +#define M_1_PI 0.318309886183790671538f +#define M_2_PI 0.636619772367581343076f +#endif + +#define RAD2DEG 57.29577951f +#define DEG2RAD 0.017453293f + +#define SAFE_DELETE(x) do { if (x) { delete x; x = NULL; } } while(false) +#define SAFE_DELETE_ARRAY(x) if (x) { delete [] x; x = NULL; } + + +#define SCREEN_WIDTH 480 +#define SCREEN_HEIGHT 272 +#define SCREEN_WIDTH_F 480.0f +#define SCREEN_HEIGHT_F 272.0f + + +#ifdef WIN32 +// #define DEFAULT_BLEND BLEND_DEFAULT +// #define BLEND_OPTION_ADD BLEND_COLORADD +// #define BLEND_OPTION_BLEND (BLEND_COLORADD | BLEND_ALPHABLEND | BLEND_NOZWRITE) +#else + #define DEFAULT_BLEND GU_TFX_MODULATE + #define BLEND_OPTION_ADD GU_TFX_ADD + #define BLEND_OPTION_BLEND GU_TFX_BLEND +#endif + +#ifdef WIN32 + #include +#endif +#ifdef LINUX + typedef unsigned char byte; + typedef unsigned long DWORD; + typedef unsigned char BYTE; + typedef bool BOOL; +#endif +#if defined (WIN32) || defined (LINUX) + + #include + #include + + #include "../Dependencies/include/fmod.h" + + //#include "../HGE/include/hge.h" + //#include "../HGE/include/hgeSprite.h" + + //#define u8 BYTE + //#define u16 WORD + //#define u32 DWORD +/* + typedef signed char s8; + typedef signed short s16; + typedef signed long s32; + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned long u32; +*/ +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + + + #define BLEND_ZERO GL_ZERO + #define BLEND_ONE GL_ONE + #define BLEND_SRC_COLOR GL_SRC_COLOR + #define BLEND_ONE_MINUS_SRC_COLOR GL_ONE_MINUS_SRC_COLOR + #define BLEND_SRC_ALPHA GL_SRC_ALPHA + #define BLEND_ONE_MINUS_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA + #define BLEND_DST_ALPHA GL_DST_ALPHA + #define BLEND_ONE_MINUS_DST_ALPHA GL_ONE_MINUS_DST_ALPHA + #define BLEND_DST_COLOR GL_DST_COLOR + #define BLEND_ONE_MINUS_DST_COLOR GL_ONE_MINUS_DST_COLOR + #define BLEND_SRC_ALPHA_SATURATE GL_SRC_ALPHA_SATURATE + + #define ARGB(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) + #define RGBA(r, g, b, a) (((a) << 24) | ((b) << 16) | ((g) << 8) | (r)) + + typedef enum PspCtrlButtons + { + PSP_CTRL_SELECT = 0x000001, + PSP_CTRL_START = 0x000008, + PSP_CTRL_UP = 0x000010, + PSP_CTRL_RIGHT = 0x000020, + PSP_CTRL_DOWN = 0x000040, + PSP_CTRL_LEFT = 0x000080, + PSP_CTRL_LTRIGGER = 0x000100, + PSP_CTRL_RTRIGGER = 0x000200, + PSP_CTRL_TRIANGLE = 0x001000, + PSP_CTRL_CIRCLE = 0x002000, + PSP_CTRL_CROSS = 0x004000, + PSP_CTRL_SQUARE = 0x008000, + PSP_CTRL_HOME = 0x010000, + PSP_CTRL_HOLD = 0x020000, + PSP_CTRL_NOTE = 0x800000 + } PspCtrlButtons; + + #define TEXTURE_FORMAT 0 + #define GU_PSM_8888 0 + #define GU_PSM_5551 0 + #define GU_PSM_4444 0 + #define GU_PSM_5650 0 + #define PIXEL_TYPE DWORD + +#else // PSP + + #ifndef ABGR8888 + #define ABGR8888 + #endif + + + #if defined (ABGR8888) + #ifndef ARGB + #define ARGB(a, r, g, b) ((a << 24) | (b << 16) | (g << 8) | r) // macro to assemble pixels in correct format + #endif + #define MAKE_COLOR(a, c) (a << 24 | c) + #define MASK_ALPHA 0xFF000000 // masks for accessing individual pixels + #define MASK_BLUE 0x00FF0000 + #define MASK_GREEN 0x0000FF00 + #define MASK_RED 0x000000FF + #define PIXEL_TYPE u32 + #define PIXEL_SIZE 4 + #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_8888 + + #define BUFFER_FORMAT GU_PSM_8888 + #define TEXTURE_FORMAT GU_PSM_8888 + #define TEXTURE_COLOR_FORMAT GU_COLOR_8888 + + + #elif defined (ABGR5551) + + #ifndef ARGB + #define ARGB(a, r, g, b) ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | ((a >> 7) << 15)) + #endif + #define MAKE_COLOR(a, c) (((a>>7)<<15) | c) + #define MASK_ALPHA 0x8000 + #define MASK_BLUE 0x7C00 + #define MASK_GREEN 0x03E0 + #define MASK_RED 0x001F + #define PIXEL_TYPE u16 + #define PIXEL_SIZE 2 + #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_5551 + + #define BUFFER_FORMAT GU_PSM_8888 + #define TEXTURE_FORMAT GU_PSM_5551 + #define TEXTURE_COLOR_FORMAT GU_COLOR_5551 + + #elif defined (ABGR4444) + #ifndef ARGB + #define ARGB(a, r, g, b) ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12)) + #endif + #define MAKE_COLOR(a, c) (((a>>4)<<12) | c) + #define MASK_ALPHA 0xF000 + #define MASK_BLUE 0x0F00 + #define MASK_GREEN 0x00F0 + #define MASK_RED 0x000F + #define PIXEL_TYPE u16 + #define PIXEL_SIZE 2 + #define PIXEL_FORMAT PSP_DISPLAY_PIXEL_FORMAT_4444 + + #define BUFFER_FORMAT GU_PSM_4444 + #define TEXTURE_FORMAT GU_PSM_4444 + #define TEXTURE_COLOR_FORMAT GU_COLOR_4444 + + #endif + + #define FRAME_BUFFER_WIDTH 512 + #define FRAME_BUFFER_SIZE FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*PIXEL_SIZE + + #define SLICE_SIZE_F 64.0f + typedef unsigned int DWORD; + + #define BLEND_ZERO 0x1000 + #define BLEND_ONE 0x1002 + #define BLEND_SRC_COLOR GU_SRC_COLOR + #define BLEND_ONE_MINUS_SRC_COLOR GU_ONE_MINUS_SRC_COLOR + #define BLEND_SRC_ALPHA GU_SRC_ALPHA + #define BLEND_ONE_MINUS_SRC_ALPHA GU_ONE_MINUS_SRC_ALPHA + #define BLEND_DST_ALPHA GU_DST_ALPHA + #define BLEND_ONE_MINUS_DST_ALPHA GU_ONE_MINUS_DST_ALPHA + #define BLEND_DST_COLOR GU_DST_COLOR + #define BLEND_ONE_MINUS_DST_COLOR GU_ONE_MINUS_DST_COLOR + #define BLEND_SRC_ALPHA_SATURATE BLEND_ONE + + typedef struct + { + ScePspFVector2 texture; + //PIXEL_TYPE color; + //ScePspFVector3 normal; + ScePspFVector3 pos; + } PSPVertex3D; + + +#endif + + + + +//------------------------------------------------------------------------------------------------ +struct Vertex +{ + float u, v; + PIXEL_TYPE color; + float x, y, z; +}; + + +//------------------------------------------------------------------------------------------------ +struct Vertex3D +{ + float u, v; + //float nx, ny, nz; + float x, y, z; +}; + + +//------------------------------------------------------------------------------------------------ +struct VertexColor +{ + PIXEL_TYPE color; + float x, y, z; +}; + + +struct JColor +{ + union + { + struct + { + u8 b; + u8 g; + u8 r; + u8 a; + }; + DWORD color; + }; +}; + + + +enum +{ + TEX_TYPE_NONE, + TEX_TYPE_USE_VRAM, + TEX_TYPE_MIPMAP, + TEX_TYPE_NORMAL, + TEX_TYPE_SKYBOX +}; + + +enum +{ + MODE_UNKNOWN, + MODE_2D, + MODE_3D +}; + + +enum +{ + TEX_FILTER_NONE, + TEX_FILTER_LINEAR, + TEX_FILTER_NEAREST +}; + +//------------------------------------------------------------------------------------------------ +class JTexture +{ +public: + JTexture(); + ~JTexture(); + + void UpdateBits(int x, int y, int width, int height, PIXEL_TYPE* bits); + + int mWidth; + int mHeight; + int mTexWidth; + int mTexHeight; + + int mFilter; + +#if defined (WIN32) || defined (LINUX) + GLuint mTexId; +#else + int mTextureFormat; + int mTexId; + bool mInVideoRAM; + PIXEL_TYPE* mBits; +#endif +}; + + +////////////////////////////////////////////////////////////////////////// +/// Custom filter for processing the texture image while loading. You +/// can change the pixels by using a custom filter before the image is +/// created as a texture. +/// +////////////////////////////////////////////////////////////////////////// +class JImageFilter +{ +public: + + ////////////////////////////////////////////////////////////////////////// + /// Pure virtual function for the custom filter to implement. + /// + /// @param pix - Image data. + /// @param width - Width of the image. + /// @param height - Height of the image. + /// + ////////////////////////////////////////////////////////////////////////// + virtual void ProcessImage(PIXEL_TYPE* pix, int width, int height) = 0; +}; + + +////////////////////////////////////////////////////////////////////////// +/// Image quad. +/// +////////////////////////////////////////////////////////////////////////// +class JQuad +{ +public: + + ////////////////////////////////////////////////////////////////////////// + /// Constructor. + /// + /// @param tex - Texture of the quad. + /// @param x - X position of the quad in texture. + /// @param y - Y position of the quad in texture. + /// @param width - Width of the quad. + /// @param height - Height of the quad. + /// + ////////////////////////////////////////////////////////////////////////// + JQuad(JTexture *tex, float x, float y, float width, float height); + + ////////////////////////////////////////////////////////////////////////// + /// Set blending color of the quad. + /// + /// @param color - Color. + /// + ////////////////////////////////////////////////////////////////////////// + void SetColor(PIXEL_TYPE color); + + ////////////////////////////////////////////////////////////////////////// + /// Set anchor point of the quad. + /// + /// @param x - X position of the anchor point. + /// @param y - Y position of the anchor point. + /// + ////////////////////////////////////////////////////////////////////////// + void SetHotSpot(float x, float y); + + ////////////////////////////////////////////////////////////////////////// + /// Set UV positions of the quad. + /// + /// @param x - X position of the quad in texture. + /// @param y - Y position of the quad in texture. + /// @param w - Width of the quad. + /// @param h - Height of the quad. + /// + ////////////////////////////////////////////////////////////////////////// + void SetTextureRect(float x, float y, float w, float h); + + ////////////////////////////////////////////////////////////////////////// + /// Get UV positions of the quad. + /// + /// @return x - X position of the quad in texture. + /// @return y - Y position of the quad in texture. + /// @return w - Width of the quad. + /// @return h - Height of the quad. + /// + ////////////////////////////////////////////////////////////////////////// + void GetTextureRect(float *x, float *y, float *w, float *h); + + ////////////////////////////////////////////////////////////////////////// + /// Set horizontal flipping. + /// + /// @param hflip - flipping flag; + /// + ////////////////////////////////////////////////////////////////////////// + void SetHFlip(bool hflip) { mHFlipped = hflip; } + + ////////////////////////////////////////////////////////////////////////// + /// Set vetical flipping. + /// + /// @param hflip - flipping flag; + /// + ////////////////////////////////////////////////////////////////////////// + void SetVFlip(bool vflip) { mVFlipped = vflip; } + + JTexture* mTex; + +#if defined (WIN32) || defined(LINUX) + float mTX0; + float mTY0; + float mTX1; + float mTY1; + JColor mColor[4]; // up to 4 vertices +#else + PIXEL_TYPE mColor[4]; // up to 4 vertices + int mBlend; // GU_TFX_MODULATE, GU_TFX_DECAL, GU_TFX_BLEND, GU_TFX_REPLACE, GU_TFX_ADD +#endif + + float mX; + float mY; + float mWidth; + float mHeight; + float mHotSpotX; + float mHotSpotY; + + bool mHFlipped; + bool mVFlipped; +}; + +//#endif + + +////////////////////////////////////////////////////////////////////////// +/// \enum JFONT_TEXT_ALIGNMENT +/// +/// Font alignment. +/// +////////////////////////////////////////////////////////////////////////// +enum JFONT_TEXT_ALIGNMENT +{ + JGETEXT_LEFT, ///< Text alignment to left. + JGETEXT_CENTER, ///< Text alignment to center. + JGETEXT_RIGHT ///< Text alignment to right. +}; + + +enum JINIT_FLAG +{ + JINIT_FLAG_NORMAL, + JINIT_FLAG_ENABLE3D +}; + + +//------------------------------------------------------------------------------------------------ +class JFont +{ +public: + JQuad* mQuad; + int mWidth; + int mHeight; + int mSpacing; + int mAlign; + float mScale; +}; + + +//------------------------------------------------------------------------------------------------ +class Rect +{ +public: + int x; + int y; + int width; + int height; + +public: + Rect(int _x, int _y, int _width, int _height): x(_x), y(_y), width(_width), height(_height) {} + +}; + + + +#endif diff --git a/JGE/src/JResourceManager.cpp b/JGE/src/JResourceManager.cpp index 003b19924..6a956ad2d 100644 --- a/JGE/src/JResourceManager.cpp +++ b/JGE/src/JResourceManager.cpp @@ -1,570 +1,437 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- - -#include "../include/JGE.h" -#include "../include/JRenderer.h" -#include "../include/JSoundSystem.h" -#include "../include/JResourceManager.h" -#include "../include/JFileSystem.h" -#include "../include/JLBFont.h" -#include "tinyxml/tinyxml.h" - -#if defined (_DEBUG) && defined (WIN32) -#include "crtdbg.h" -#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) -#else -#define NEW new -#endif - -JResourceManager::JResourceManager() -{ - //mResourceRoot = "Res/"; // default root folder - - mTextureList.clear(); - mTextureList.reserve(16); - mTextureMap.clear(); - - mQuadList.clear(); - mQuadList.reserve(128); - mQuadMap.clear(); - - mFontList.clear(); - mFontList.reserve(4); - mFontMap.clear(); - - mMusicList.clear(); - mMusicList.reserve(4); - mMusicMap.clear(); - - mSampleList.clear(); - mSampleList.reserve(8); - mSampleMap.clear(); - -// mParticleEffectList.clear(); -// mParticleEffectList.reserve(8); -// mParticleEffectMap.clear(); -// -// mMotionEmitterList.clear(); -// mMotionEmitterList.reserve(16); -// mMotionEmitterMap.clear(); -} - - -JResourceManager::~JResourceManager() -{ - - RemoveAll(); -} - - -void JResourceManager::RemoveAll() -{ - for (vector::iterator tex = mTextureList.begin(); tex != mTextureList.end(); ++tex) - delete *tex; - - mTextureList.clear(); - mTextureMap.clear(); - - for (vector::iterator quad = mQuadList.begin(); quad != mQuadList.end(); ++quad) - delete *quad; - - mQuadList.clear(); - mQuadMap.clear(); - - for (vector::iterator font = mFontList.begin(); font != mFontList.end(); ++font) - delete *font; - - mFontList.clear(); - mFontMap.clear(); - - for (vector::iterator music = mMusicList.begin(); music != mMusicList.end(); ++music) - delete *music; - - mMusicList.clear(); - mMusicMap.clear(); - - for (vector::iterator sample = mSampleList.begin(); sample != mSampleList.end(); ++sample) - delete *sample; - - mSampleList.clear(); - mSampleMap.clear(); - -// for (vector::iterator effect = mParticleEffectList.begin(); effect != mParticleEffectList.end(); ++effect) -// delete *effect; -// -// mParticleEffectList.clear(); -// mParticleEffectMap.clear(); -// -// for (vector::iterator emitter = mMotionEmitterList.begin(); emitter != mMotionEmitterList.end(); ++emitter) -// delete *emitter; -// -// mMotionEmitterList.clear(); -// mMotionEmitterMap.clear(); - -} - - -bool JResourceManager::LoadResource(const string& resourceName) -{ - string path = /*mResourceRoot + */resourceName; - -// TiXmlDocument doc(path.c_str()); -// -// if (!doc.LoadFile()) return false; - - - JGE *engine = JGE::GetInstance(); - if (engine == NULL) return false; - - - JFileSystem *fileSystem = JFileSystem::GetInstance(); - if (fileSystem == NULL) return false; - - - - if (!fileSystem->OpenFile(path.c_str())) return false; - - int size = fileSystem->GetFileSize(); - char *xmlBuffer = new char[size]; - fileSystem->ReadFile(xmlBuffer, size); - - TiXmlDocument doc; - doc.Parse(xmlBuffer); - - TiXmlNode* resource = 0; - TiXmlNode* node = 0; - TiXmlElement* element = 0; - - resource = doc.FirstChild("resource"); - if (resource) - { - element = resource->ToElement(); - printf("---- Loading %s:%s\n", element->Value(), element->Attribute("name")); - - for (node = resource->FirstChild(); node; node = node->NextSibling()) - { - element = node->ToElement(); - if (element != NULL) - { - if (strcmp(element->Value(), "texture")==0) - { - CreateTexture(element->Attribute("name")); - } - else if (strcmp(element->Value(), "quad")==0) - { - string quadName = element->Attribute("name"); - string textureName = element->Attribute("texture"); - float x = 0.0f; - float y = 0.0f; - float width = 16.0f; - float height = 16.0f; - float value; - float hotspotX = 0.0f; - float hotspotY = 0.0f; - - if (element->QueryFloatAttribute("x", &value) == TIXML_SUCCESS) - x = value; - - if (element->QueryFloatAttribute("y", &value) == TIXML_SUCCESS) - y = value; - - if (element->QueryFloatAttribute("width", &value) == TIXML_SUCCESS) - width = value; - - if (element->QueryFloatAttribute("height", &value) == TIXML_SUCCESS) - height = value; - - if (element->QueryFloatAttribute("w", &value) == TIXML_SUCCESS) - width = value; - - if (element->QueryFloatAttribute("h", &value) == TIXML_SUCCESS) - height = value; - - if (element->QueryFloatAttribute("hotspot.x", &value) == TIXML_SUCCESS) - hotspotX = value; - else - hotspotX = width/2; - - if (element->QueryFloatAttribute("hotspot.y", &value) == TIXML_SUCCESS) - hotspotY = value; - else - hotspotY = height/2; - -// if (element->QueryFloatAttribute("regx", &value) == TIXML_SUCCESS) -// hotspotX = width/2; -// -// if (element->QueryFloatAttribute("regy", &value) == TIXML_SUCCESS) -// hotspotY = height/2; - - int id = CreateQuad(quadName, textureName, x, y, width, height); - if (id != INVALID_ID) - { - GetQuad(id)->SetHotSpot(hotspotX, hotspotY); - } - } - else if (strcmp(element->Value(), "font")==0) - { - } - else if (strcmp(element->Value(), "music")==0) - { - LoadMusic(element->Attribute("name")); - } - else if (strcmp(element->Value(), "sample")==0) - { - LoadSample(element->Attribute("name")); - } -// else if (strcmp(element->Value(), "effect")==0) -// { -// RegisterParticleEffect(element->Attribute("name")); -// } -// else if (strcmp(element->Value(), "motion_emitter")==0) -// { -// RegisterMotionEmitter(element->Attribute("name")); -// } - } - } - - } - - fileSystem->CloseFile(); - delete[] xmlBuffer; -// JGERelease(); - - return true; -} - - -int JResourceManager::CreateTexture(const string &textureName) -{ - map::iterator itr = mTextureMap.find(textureName); - - if (itr == mTextureMap.end()) - { - string path = /*mResourceRoot + */textureName; - - printf("creating texture:%s\n", path.c_str()); - - JTexture *tex = JRenderer::GetInstance()->LoadTexture(path.c_str()); - - if (tex == NULL) - return INVALID_ID; - - int id = mTextureList.size(); - mTextureList.push_back(tex); - mTextureMap[textureName] = id; - - return id; - } - else - return itr->second; -} - - -JTexture *JResourceManager::GetTexture(const string &textureName) -{ - map::iterator itr = mTextureMap.find(textureName); - - if (itr == mTextureMap.end()) - return NULL; - else - return mTextureList[itr->second]; -} - - -JTexture *JResourceManager::GetTexture(int id) -{ - if (id >=0 && id < (int)mTextureList.size()) - return mTextureList[id]; - else - return NULL; -} - - -int JResourceManager::CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height) -{ - map::iterator itr = mQuadMap.find(quadName); - - if (itr == mQuadMap.end()) - { - JTexture *tex = GetTexture(textureName); - if (tex == NULL) - { - int texId = CreateTexture(textureName); // load texture if necessary - tex = GetTexture(texId); - } - - if (tex == NULL) // no texture, no quad... - return INVALID_ID; - - printf("creating quad:%s\n", quadName.c_str()); - - int id = mQuadList.size(); - mQuadList.push_back(NEW JQuad(tex, x, y, width, height)); - - mQuadMap[quadName] = id; - - return id; - - } - else - return itr->second; -} - - -JQuad *JResourceManager::GetQuad(const string &quadName) -{ - map::iterator itr = mQuadMap.find(quadName); - - if (itr == mQuadMap.end()) - return NULL; - else - return mQuadList[itr->second]; -} - - -JQuad *JResourceManager::GetQuad(int id) -{ - if (id >=0 && id < (int)mQuadList.size()) - return mQuadList[id]; - else - return NULL; -} - - -int JResourceManager::LoadJLBFont(const string &fontName, int height) -{ - map::iterator itr = mFontMap.find(fontName); - - if (itr == mFontMap.end()) - { - string path = /*mResourceRoot + */fontName; - - printf("creating font:%s\n", path.c_str()); - - int id = mFontList.size(); - /////////////////////////////////////// - mFontList.push_back(NEW JLBFont(path.c_str(), height, true)); - - mFontMap[fontName] = id; - - return id; - } - else - return itr->second; -} - - -JLBFont *JResourceManager::GetJLBFont(const string &fontName) -{ - map::iterator itr = mFontMap.find(fontName); - - if (itr == mFontMap.end()) - return NULL; - else - return mFontList[itr->second]; -} - - -JLBFont *JResourceManager::GetJLBFont(int id) -{ - if (id >=0 && id < (int)mFontList.size()) - return mFontList[id]; - else - return NULL; -} - - -int JResourceManager::LoadMusic(const string &musicName) -{ - map::iterator itr = mMusicMap.find(musicName); - - if (itr == mMusicMap.end()) - { - string path = /*mResourceRoot + */musicName; - - printf("creating music:%s\n", path.c_str()); - - JMusic *music = JSoundSystem::GetInstance()->LoadMusic(path.c_str()); - if (music == NULL) - return INVALID_ID; - - int id = mMusicList.size(); - mMusicList.push_back(music); - - mMusicMap[musicName] = id; - - return id; - } - else - return itr->second; -} - - -JMusic *JResourceManager::GetMusic(const string &musicName) -{ - map::iterator itr = mMusicMap.find(musicName); - - if (itr == mMusicMap.end()) - return NULL; - else - return mMusicList[itr->second]; -} - - -JMusic *JResourceManager::GetMusic(int id) -{ - if (id >=0 && id < (int)mMusicList.size()) - return mMusicList[id]; - else - return NULL; -} - - -int JResourceManager::LoadSample(const string &sampleName) -{ - map::iterator itr = mSampleMap.find(sampleName); - - if (itr == mSampleMap.end()) - { - string path = /*mResourceRoot + */sampleName; - - printf("creating sample:%s\n", path.c_str()); - - JSample *sample = JSoundSystem::GetInstance()->LoadSample(path.c_str()); - if (sample == NULL) - return INVALID_ID; - - int id = mSampleList.size(); - mSampleList.push_back(sample); - - mSampleMap[sampleName] = id; - - return id; - } - else - return itr->second; -} - - -JSample *JResourceManager::GetSample(const string &sampleName) -{ - map::iterator itr = mSampleMap.find(sampleName); - - if (itr == mSampleMap.end()) - return NULL; - else - return mSampleList[itr->second]; -} - - -JSample *JResourceManager::GetSample(int id) -{ - if (id >=0 && id < (int)mSampleList.size()) - return mSampleList[id]; - else - return NULL; -} - -// -// -// int JResourceManager::RegisterParticleEffect(const string &effectName) -// { -// map::iterator itr = mParticleEffectMap.find(effectName); -// -// if (itr == mParticleEffectMap.end()) -// { -// string path = mResourceRoot + effectName; -// printf("creating effect:%s\n", path.c_str()); -// JParticleEffect *effect = new JParticleEffect(path.c_str()); -// -// if (effect == NULL) -// return INVALID_ID; -// -// -// int id = mParticleEffectList.size(); -// mParticleEffectList.push_back(effect); -// -// mParticleEffectMap[effectName] = id; -// -// return id; -// -// } -// else -// return itr->second; -// } -// -// -// JParticleEffect *JResourceManager::GetParticleEffect(const string &effectName) -// { -// map::iterator itr = mParticleEffectMap.find(effectName); -// -// if (itr == mParticleEffectMap.end()) -// return NULL; -// else -// return mParticleEffectList[itr->second]; -// } -// -// -// JParticleEffect *JResourceManager::GetParticleEffect(int id) -// { -// if (id >=0 && id < (int)mParticleEffectList.size()) -// return mParticleEffectList[id]; -// else -// return NULL; -// } -// -// -// -// int JResourceManager::RegisterMotionEmitter(const string &emitterName) -// { -// map::iterator itr = mMotionEmitterMap.find(emitterName); -// -// if (itr == mMotionEmitterMap.end()) -// { -// string path = mResourceRoot + emitterName; -// printf("creating effect:%s\n", path.c_str()); -// JMotionEmitter *emitter = new JMotionEmitter(); -// -// if (emitter == NULL) -// return INVALID_ID; -// -// emitter->LoadMotionML(path.c_str()); -// -// int id = mMotionEmitterList.size(); -// mMotionEmitterList.push_back(emitter); -// -// mMotionEmitterMap[emitterName] = id; -// -// return id; -// -// } -// else -// return itr->second; -// } -// -// -// JMotionEmitter *JResourceManager::GetMotionEmitter(const string &emitterName) -// { -// map::iterator itr = mMotionEmitterMap.find(emitterName); -// -// if (itr == mMotionEmitterMap.end()) -// return NULL; -// else -// return mMotionEmitterList[itr->second]; -// } -// -// -// JMotionEmitter *JResourceManager::GetMotionEmitter(int id) -// { -// if (id >=0 && id < (int)mMotionEmitterList.size()) -// return mMotionEmitterList[id]; -// else -// return NULL; -// } +//------------------------------------------------------------------------------------- +// +// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. +// +// Licensed under the BSD license, see LICENSE in JGE root for details. +// +// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) +// +//------------------------------------------------------------------------------------- + +#include "../include/JGE.h" +#include "../include/JRenderer.h" +#include "../include/JSoundSystem.h" +#include "../include/JResourceManager.h" +#include "../include/JFileSystem.h" +#include "../include/JLBFont.h" +#include "tinyxml/tinyxml.h" + +#if defined (_DEBUG) && defined (WIN32) +#include "crtdbg.h" +#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +#else +#define NEW new +#endif + +JResourceManager::JResourceManager() +{ + //mResourceRoot = "Res/"; // default root folder + + mTextureList.clear(); + mTextureList.reserve(16); + mTextureMap.clear(); + + mQuadList.clear(); + mQuadList.reserve(128); + mQuadMap.clear(); + + mFontList.clear(); + mFontList.reserve(4); + mFontMap.clear(); + +// mParticleEffectList.clear(); +// mParticleEffectList.reserve(8); +// mParticleEffectMap.clear(); +// +// mMotionEmitterList.clear(); +// mMotionEmitterList.reserve(16); +// mMotionEmitterMap.clear(); +} + + +JResourceManager::~JResourceManager() +{ + + RemoveAll(); +} + + +void JResourceManager::RemoveAll() +{ + for (vector::iterator tex = mTextureList.begin(); tex != mTextureList.end(); ++tex) + delete *tex; + + mTextureList.clear(); + mTextureMap.clear(); + + for (vector::iterator quad = mQuadList.begin(); quad != mQuadList.end(); ++quad) + delete *quad; + + mQuadList.clear(); + mQuadMap.clear(); + + for (vector::iterator font = mFontList.begin(); font != mFontList.end(); ++font) + delete *font; + + mFontList.clear(); + mFontMap.clear(); +} + + +bool JResourceManager::LoadResource(const string& resourceName) +{ + string path = /*mResourceRoot + */resourceName; + +// TiXmlDocument doc(path.c_str()); +// +// if (!doc.LoadFile()) return false; + + + JGE *engine = JGE::GetInstance(); + if (engine == NULL) return false; + + + JFileSystem *fileSystem = JFileSystem::GetInstance(); + if (fileSystem == NULL) return false; + + + + if (!fileSystem->OpenFile(path.c_str())) return false; + + int size = fileSystem->GetFileSize(); + char *xmlBuffer = new char[size]; + fileSystem->ReadFile(xmlBuffer, size); + + TiXmlDocument doc; + doc.Parse(xmlBuffer); + + TiXmlNode* resource = 0; + TiXmlNode* node = 0; + TiXmlElement* element = 0; + + resource = doc.FirstChild("resource"); + if (resource) + { + element = resource->ToElement(); + printf("---- Loading %s:%s\n", element->Value(), element->Attribute("name")); + + for (node = resource->FirstChild(); node; node = node->NextSibling()) + { + element = node->ToElement(); + if (element != NULL) + { + if (strcmp(element->Value(), "texture")==0) + { + CreateTexture(element->Attribute("name")); + } + else if (strcmp(element->Value(), "quad")==0) + { + string quadName = element->Attribute("name"); + string textureName = element->Attribute("texture"); + float x = 0.0f; + float y = 0.0f; + float width = 16.0f; + float height = 16.0f; + float value; + float hotspotX = 0.0f; + float hotspotY = 0.0f; + + if (element->QueryFloatAttribute("x", &value) == TIXML_SUCCESS) + x = value; + + if (element->QueryFloatAttribute("y", &value) == TIXML_SUCCESS) + y = value; + + if (element->QueryFloatAttribute("width", &value) == TIXML_SUCCESS) + width = value; + + if (element->QueryFloatAttribute("height", &value) == TIXML_SUCCESS) + height = value; + + if (element->QueryFloatAttribute("w", &value) == TIXML_SUCCESS) + width = value; + + if (element->QueryFloatAttribute("h", &value) == TIXML_SUCCESS) + height = value; + + if (element->QueryFloatAttribute("hotspot.x", &value) == TIXML_SUCCESS) + hotspotX = value; + else + hotspotX = width/2; + + if (element->QueryFloatAttribute("hotspot.y", &value) == TIXML_SUCCESS) + hotspotY = value; + else + hotspotY = height/2; + +// if (element->QueryFloatAttribute("regx", &value) == TIXML_SUCCESS) +// hotspotX = width/2; +// +// if (element->QueryFloatAttribute("regy", &value) == TIXML_SUCCESS) +// hotspotY = height/2; + + int id = CreateQuad(quadName, textureName, x, y, width, height); + if (id != INVALID_ID) + { + GetQuad(id)->SetHotSpot(hotspotX, hotspotY); + } + } + else if (strcmp(element->Value(), "font")==0) + { + } +// else if (strcmp(element->Value(), "effect")==0) +// { +// RegisterParticleEffect(element->Attribute("name")); +// } +// else if (strcmp(element->Value(), "motion_emitter")==0) +// { +// RegisterMotionEmitter(element->Attribute("name")); +// } + } + } + + } + + fileSystem->CloseFile(); + delete[] xmlBuffer; +// JGERelease(); + + return true; +} + + +int JResourceManager::CreateTexture(const string &textureName) +{ + map::iterator itr = mTextureMap.find(textureName); + + if (itr == mTextureMap.end()) + { + string path = /*mResourceRoot + */textureName; + + printf("creating texture:%s\n", path.c_str()); + + JTexture *tex = JRenderer::GetInstance()->LoadTexture(path.c_str()); + + if (tex == NULL) + return INVALID_ID; + + int id = mTextureList.size(); + mTextureList.push_back(tex); + mTextureMap[textureName] = id; + + return id; + } + else + return itr->second; +} + + +JTexture *JResourceManager::GetTexture(const string &textureName) +{ + map::iterator itr = mTextureMap.find(textureName); + + if (itr == mTextureMap.end()) + return NULL; + else + return mTextureList[itr->second]; +} + + +JTexture *JResourceManager::GetTexture(int id) +{ + if (id >=0 && id < (int)mTextureList.size()) + return mTextureList[id]; + else + return NULL; +} + + +int JResourceManager::CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height) +{ + map::iterator itr = mQuadMap.find(quadName); + + if (itr == mQuadMap.end()) + { + JTexture *tex = GetTexture(textureName); + if (tex == NULL) + { + int texId = CreateTexture(textureName); // load texture if necessary + tex = GetTexture(texId); + } + + if (tex == NULL) // no texture, no quad... + return INVALID_ID; + + printf("creating quad:%s\n", quadName.c_str()); + + int id = mQuadList.size(); + mQuadList.push_back(NEW JQuad(tex, x, y, width, height)); + + mQuadMap[quadName] = id; + + return id; + + } + else + return itr->second; +} + + +JQuad *JResourceManager::GetQuad(const string &quadName) +{ + map::iterator itr = mQuadMap.find(quadName); + + if (itr == mQuadMap.end()) + return NULL; + else + return mQuadList[itr->second]; +} + + +JQuad *JResourceManager::GetQuad(int id) +{ + if (id >=0 && id < (int)mQuadList.size()) + return mQuadList[id]; + else + return NULL; +} + + +int JResourceManager::LoadJLBFont(const string &fontName, int height) +{ + map::iterator itr = mFontMap.find(fontName); + + if (itr == mFontMap.end()) + { + string path = /*mResourceRoot + */fontName; + + printf("creating font:%s\n", path.c_str()); + + int id = mFontList.size(); + /////////////////////////////////////// + mFontList.push_back(NEW JLBFont(path.c_str(), height, true)); + + mFontMap[fontName] = id; + + return id; + } + else + return itr->second; +} + + +JLBFont *JResourceManager::GetJLBFont(const string &fontName) +{ + map::iterator itr = mFontMap.find(fontName); + + if (itr == mFontMap.end()) + return NULL; + else + return mFontList[itr->second]; +} + + +JLBFont *JResourceManager::GetJLBFont(int id) +{ + if (id >=0 && id < (int)mFontList.size()) + return mFontList[id]; + else + return NULL; +} + +// +// +// int JResourceManager::RegisterParticleEffect(const string &effectName) +// { +// map::iterator itr = mParticleEffectMap.find(effectName); +// +// if (itr == mParticleEffectMap.end()) +// { +// string path = mResourceRoot + effectName; +// printf("creating effect:%s\n", path.c_str()); +// JParticleEffect *effect = new JParticleEffect(path.c_str()); +// +// if (effect == NULL) +// return INVALID_ID; +// +// +// int id = mParticleEffectList.size(); +// mParticleEffectList.push_back(effect); +// +// mParticleEffectMap[effectName] = id; +// +// return id; +// +// } +// else +// return itr->second; +// } +// +// +// JParticleEffect *JResourceManager::GetParticleEffect(const string &effectName) +// { +// map::iterator itr = mParticleEffectMap.find(effectName); +// +// if (itr == mParticleEffectMap.end()) +// return NULL; +// else +// return mParticleEffectList[itr->second]; +// } +// +// +// JParticleEffect *JResourceManager::GetParticleEffect(int id) +// { +// if (id >=0 && id < (int)mParticleEffectList.size()) +// return mParticleEffectList[id]; +// else +// return NULL; +// } +// +// +// +// int JResourceManager::RegisterMotionEmitter(const string &emitterName) +// { +// map::iterator itr = mMotionEmitterMap.find(emitterName); +// +// if (itr == mMotionEmitterMap.end()) +// { +// string path = mResourceRoot + emitterName; +// printf("creating effect:%s\n", path.c_str()); +// JMotionEmitter *emitter = new JMotionEmitter(); +// +// if (emitter == NULL) +// return INVALID_ID; +// +// emitter->LoadMotionML(path.c_str()); +// +// int id = mMotionEmitterList.size(); +// mMotionEmitterList.push_back(emitter); +// +// mMotionEmitterMap[emitterName] = id; +// +// return id; +// +// } +// else +// return itr->second; +// } +// +// +// JMotionEmitter *JResourceManager::GetMotionEmitter(const string &emitterName) +// { +// map::iterator itr = mMotionEmitterMap.find(emitterName); +// +// if (itr == mMotionEmitterMap.end()) +// return NULL; +// else +// return mMotionEmitterList[itr->second]; +// } +// +// +// JMotionEmitter *JResourceManager::GetMotionEmitter(int id) +// { +// if (id >=0 && id < (int)mMotionEmitterList.size()) +// return mMotionEmitterList[id]; +// else +// return NULL; +// } diff --git a/JGE/src/JSfx.cpp b/JGE/src/JSfx.cpp index 03bd4fe84..c7f9bfddf 100644 --- a/JGE/src/JSfx.cpp +++ b/JGE/src/JSfx.cpp @@ -133,7 +133,8 @@ JSample *JSoundSystem::LoadSample(const char *fileName) if (sample) { sample->mSample = new WAVDATA; - loadWaveData(sample->mSample, s, 1); + if(!loadWaveData(sample->mSample, s, 1)) + sample->mSample = NULL; } return sample; diff --git a/JGE/src/linux/JSfx.cpp b/JGE/src/linux/JSfx.cpp index 8bea57da7..8d88deb37 100644 --- a/JGE/src/linux/JSfx.cpp +++ b/JGE/src/linux/JSfx.cpp @@ -202,6 +202,8 @@ JSample *JSoundSystem::LoadSample(const char *fileName) delete[] buffer; fileSystem->CloseFile(); } + else + sample->mSample = NULL; } diff --git a/JGE/src/win/JSoundSystem_Win.cpp b/JGE/src/win/JSoundSystem_Win.cpp index c11df794c..a7c01a2e6 100644 --- a/JGE/src/win/JSoundSystem_Win.cpp +++ b/JGE/src/win/JSoundSystem_Win.cpp @@ -1,219 +1,220 @@ -//------------------------------------------------------------------------------------- -// -// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. -// -// Licensed under the BSD license, see LICENSE in JGE root for details. -// -// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) -// -//------------------------------------------------------------------------------------- - -#include "../../Dependencies/include/png.h" -#include "../../Dependencies/include/fmod.h" - -#include "../../include/JSoundSystem.h" -#include "../../include/JFileSystem.h" - - -////////////////////////////////////////////////////////////////////////// -JMusic::JMusic() -{ -} - -void JMusic::Update(){ - -} - -int JMusic::getPlayTime(){ - return FSOUND_GetCurrentPosition(JSoundSystem::GetInstance()->mChannel)/44.1; //todo more generic, here it's only 44kHz -} - -JMusic::~JMusic() -{ - JSoundSystem::GetInstance()->StopMusic(this); - //JSoundSystem::GetInstance()->FreeMusic(this); - - if (mTrack) - FSOUND_Sample_Free(mTrack); -} - - -////////////////////////////////////////////////////////////////////////// -JSample::JSample() -{ - -} - -JSample::~JSample() -{ - //JSoundSystem::GetInstance()->FreeSample(this); - if (mSample) - FSOUND_Sample_Free(mSample); -} - - -////////////////////////////////////////////////////////////////////////// -JSoundSystem* JSoundSystem::mInstance = NULL; - - -JSoundSystem* JSoundSystem::GetInstance() -{ - if (mInstance == NULL) - { - mInstance = new JSoundSystem(); - mInstance->InitSoundSystem(); - } - - return mInstance; -} - - -void JSoundSystem::Destroy() -{ - if (mInstance) - { - mInstance->DestroySoundSystem(); - delete mInstance; - mInstance = NULL; - } -} - - -JSoundSystem::JSoundSystem() -{ - -} - - -JSoundSystem::~JSoundSystem() -{ - -} - - -void JSoundSystem::InitSoundSystem() -{ - FSOUND_Init(44100, 32, 0); -} - - -void JSoundSystem::DestroySoundSystem() -{ - FSOUND_Close(); - -} - - -JMusic *JSoundSystem::LoadMusic(const char *fileName) -{ - JMusic* music = new JMusic(); - if (music) - { - JFileSystem* fileSystem = JFileSystem::GetInstance(); - if (fileSystem->OpenFile(fileName)) - { - - // FMUSIC is for MOD... - // int size = fileSystem->GetFileSize(); - // char *buffer = new char[size]; - // fileSystem->ReadFile(buffer, size); - // music->mTrack = FMUSIC_LoadSongEx(buffer, 0, size, FSOUND_LOADMEMORY, NULL, 0); - // - // delete[] buffer; - // fileSystem->CloseFile(); - - int size = fileSystem->GetFileSize(); - char *buffer = new char[size]; - fileSystem->ReadFile(buffer, size); - music->mTrack = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, FSOUND_LOADMEMORY, 0, size); - - delete[] buffer; - fileSystem->CloseFile(); - } - - } - - return music; -} - -// void JSoundSystem::FreeMusic(JMusic *music) -// { -// if (music) -// { -// // if (music->mTrack) -// // FMUSIC_FreeSong(music->mTrack); -// // delete music; -// // music = NULL; -// -// if (music->mTrack) -// FSOUND_Sample_Free(music->mTrack); -// -// //delete music; -// //music = NULL; -// } -// } - -void JSoundSystem::PlayMusic(JMusic *music, bool looping) -{ - - if (music && music->mTrack) - { - mChannel = FSOUND_PlaySound(FSOUND_FREE, music->mTrack); - - if (looping) - FSOUND_SetLoopMode(mChannel, FSOUND_LOOP_NORMAL); - else - FSOUND_SetLoopMode(mChannel, FSOUND_LOOP_OFF); - - } -} - - -void JSoundSystem::StopMusic(JMusic *music) -{ - // if (music && music->mTrack) - // FMUSIC_StopSong(music->mTrack); - - FSOUND_StopSound(mChannel); -} - - -void JSoundSystem::SetVolume(int volume) -{ - FSOUND_SetSFXMasterVolume(volume); - - mVolume = volume; -} - - - - -JSample *JSoundSystem::LoadSample(const char *fileName) -{ - JSample* sample = new JSample(); - if (sample) - { - JFileSystem* fileSystem = JFileSystem::GetInstance(); - if (fileSystem->OpenFile(fileName)) - { - int size = fileSystem->GetFileSize(); - char *buffer = new char[size]; - fileSystem->ReadFile(buffer, size); - sample->mSample = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, FSOUND_LOADMEMORY, 0, size); - - delete[] buffer; - fileSystem->CloseFile(); - } - - } - - return sample; -} - - -void JSoundSystem::PlaySample(JSample *sample) -{ - if (sample && sample->mSample) - FSOUND_PlaySound(FSOUND_FREE, sample->mSample); -} - +//------------------------------------------------------------------------------------- +// +// JGE++ is a hardware accelerated 2D game SDK for PSP/Windows. +// +// Licensed under the BSD license, see LICENSE in JGE root for details. +// +// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) +// +//------------------------------------------------------------------------------------- + +#include "../../Dependencies/include/png.h" +#include "../../Dependencies/include/fmod.h" + +#include "../../include/JSoundSystem.h" +#include "../../include/JFileSystem.h" + + +////////////////////////////////////////////////////////////////////////// +JMusic::JMusic() +{ +} + +void JMusic::Update(){ + +} + +int JMusic::getPlayTime(){ + return FSOUND_GetCurrentPosition(JSoundSystem::GetInstance()->mChannel)/44.1; //todo more generic, here it's only 44kHz +} + +JMusic::~JMusic() +{ + JSoundSystem::GetInstance()->StopMusic(this); + //JSoundSystem::GetInstance()->FreeMusic(this); + + if (mTrack) + FSOUND_Sample_Free(mTrack); +} + + +////////////////////////////////////////////////////////////////////////// +JSample::JSample() +{ + +} + +JSample::~JSample() +{ + //JSoundSystem::GetInstance()->FreeSample(this); + if (mSample) + FSOUND_Sample_Free(mSample); +} + + +////////////////////////////////////////////////////////////////////////// +JSoundSystem* JSoundSystem::mInstance = NULL; + + +JSoundSystem* JSoundSystem::GetInstance() +{ + if (mInstance == NULL) + { + mInstance = new JSoundSystem(); + mInstance->InitSoundSystem(); + } + + return mInstance; +} + + +void JSoundSystem::Destroy() +{ + if (mInstance) + { + mInstance->DestroySoundSystem(); + delete mInstance; + mInstance = NULL; + } +} + + +JSoundSystem::JSoundSystem() +{ + +} + + +JSoundSystem::~JSoundSystem() +{ + +} + + +void JSoundSystem::InitSoundSystem() +{ + FSOUND_Init(44100, 32, 0); +} + + +void JSoundSystem::DestroySoundSystem() +{ + FSOUND_Close(); + +} + + +JMusic *JSoundSystem::LoadMusic(const char *fileName) +{ + JMusic* music = new JMusic(); + if (music) + { + JFileSystem* fileSystem = JFileSystem::GetInstance(); + if (fileSystem->OpenFile(fileName)) + { + + // FMUSIC is for MOD... + // int size = fileSystem->GetFileSize(); + // char *buffer = new char[size]; + // fileSystem->ReadFile(buffer, size); + // music->mTrack = FMUSIC_LoadSongEx(buffer, 0, size, FSOUND_LOADMEMORY, NULL, 0); + // + // delete[] buffer; + // fileSystem->CloseFile(); + + int size = fileSystem->GetFileSize(); + char *buffer = new char[size]; + fileSystem->ReadFile(buffer, size); + music->mTrack = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, FSOUND_LOADMEMORY, 0, size); + + delete[] buffer; + fileSystem->CloseFile(); + } + + } + + return music; +} + +// void JSoundSystem::FreeMusic(JMusic *music) +// { +// if (music) +// { +// // if (music->mTrack) +// // FMUSIC_FreeSong(music->mTrack); +// // delete music; +// // music = NULL; +// +// if (music->mTrack) +// FSOUND_Sample_Free(music->mTrack); +// +// //delete music; +// //music = NULL; +// } +// } + +void JSoundSystem::PlayMusic(JMusic *music, bool looping) +{ + + if (music && music->mTrack) + { + mChannel = FSOUND_PlaySound(FSOUND_FREE, music->mTrack); + + if (looping) + FSOUND_SetLoopMode(mChannel, FSOUND_LOOP_NORMAL); + else + FSOUND_SetLoopMode(mChannel, FSOUND_LOOP_OFF); + + } +} + + +void JSoundSystem::StopMusic(JMusic *music) +{ + // if (music && music->mTrack) + // FMUSIC_StopSong(music->mTrack); + + FSOUND_StopSound(mChannel); +} + + +void JSoundSystem::SetVolume(int volume) +{ + FSOUND_SetSFXMasterVolume(volume); + + mVolume = volume; +} + + + + +JSample *JSoundSystem::LoadSample(const char *fileName) +{ + JSample* sample = new JSample(); + if (sample) + { + JFileSystem* fileSystem = JFileSystem::GetInstance(); + if (fileSystem->OpenFile(fileName)) + { + int size = fileSystem->GetFileSize(); + char *buffer = new char[size]; + fileSystem->ReadFile(buffer, size); + sample->mSample = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, FSOUND_LOADMEMORY, 0, size); + + delete[] buffer; + fileSystem->CloseFile(); + }else + sample->mSample = NULL; + + } + + return sample; +} + + +void JSoundSystem::PlaySample(JSample *sample) +{ + if (sample && sample->mSample) + FSOUND_PlaySound(FSOUND_FREE, sample->mSample); +} + diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index 4e85cd098..4e65960fd 100644 --- a/projects/mtg/Makefile +++ b/projects/mtg/Makefile @@ -1,4 +1,4 @@ -OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/Blocker.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardSelector.o objs/ConstraintResolver.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGRules.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/Pos.o objs/PriceList.o objs/ReplacementEffects.o objs/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/SimplePad.o objs/Token.o objs/Translate.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o +OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/Blocker.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardSelector.o objs/ConstraintResolver.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGRules.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/Pos.o objs/PriceList.o objs/ReplacementEffects.o objs/ShopItem.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/SimplePad.o objs/Token.o objs/Translate.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o objs/WCachedResource.o DEPS = $(patsubst objs/%.o, deps/%.d, $(OBJS)) RESULT = $(shell psp-config --psp-prefix 2> Makefile.cache) diff --git a/projects/mtg/bin/Res/ai/baka/avatar.jpg b/projects/mtg/bin/Res/ai/baka/avatars/baka.jpg similarity index 100% rename from projects/mtg/bin/Res/ai/baka/avatar.jpg rename to projects/mtg/bin/Res/ai/baka/avatars/baka.jpg diff --git a/projects/mtg/include/WCachedResource.h b/projects/mtg/include/WCachedResource.h new file mode 100644 index 000000000..6cf3e7880 --- /dev/null +++ b/projects/mtg/include/WCachedResource.h @@ -0,0 +1,95 @@ +#ifndef _WCACHEDRESOURCE_H_ +#define _WCACHEDRESOURCE_H_ +#include + +class WResource{ +public: + friend class WResourceManager; + template friend class WCache; + + WResource(); + virtual ~WResource(); + + virtual void Nullify()=0; //For when our size is 0, so we don't free anything by mistake. + virtual unsigned long size()=0; //Size of cached item in bytes. + virtual void Refresh(string filename)=0; //Basically calls Attempt(filename) and remaps in situ. + virtual bool isGood()=0; //Return true if this has data. + virtual bool Attempt(string filename, int submode, int & error)=0; //Returns true if we've loaded our data and isGood(). + +protected: + bool isLocked(); //Is the resource locked? + bool isPermanent(); //Is the resource permanent? + void lock(); //Lock it. + void deadbolt(); //Make it permanent. + void unlock(bool force = false); //Unlock it. Forcing a lock will also remove "permanent" status. + void hit(); //Update resource's last used time. + + int loadedMode; //What submode settings were we loaded with? (For refresh) + unsigned int lastTime; //When was the last time we were hit? + unsigned char locks; //Remember to unlock when we're done using locked stuff, or else this'll be useless. +}; + +class WCachedTexture: public WResource{ +public: + friend class WResourceManager; + template friend class WCache; + WCachedTexture(); + ~WCachedTexture(); + + void Refresh(string filename); + unsigned long size(); + bool isGood(); + bool Attempt(string filename, int submode, int & error); + bool compare(JTexture * t) {return (t == texture);}; + + void Nullify(); + JTexture * Actual(); //Return this texture as is. Does not make a new one. + JQuad * GetQuad(string resname); + JQuad * GetQuad(float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f,string resname=""); //Get us a new/existing quad. + JQuad * GetCard(float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f,string resname=""); //Same as above, but centered when new. + bool ReleaseQuad(JQuad* quad); //We're done with this quad, so delete and stop tracking. True if existed. +protected: + JTexture * texture; + bool bVRAM; + map trackedQuads; +}; + +class WCachedParticles: public WResource{ +public: + friend class WResourceManager; + template friend class WCache; + WCachedParticles(); + ~WCachedParticles(); + + void Nullify(); + void Refresh(string filename); + unsigned long size(); + bool isGood(); + bool Attempt(string filename, int submode, int & error); + bool compare(hgeParticleSystemInfo * p) {return (p == particles);}; + + hgeParticleSystemInfo * Actual(); +protected: + hgeParticleSystemInfo * particles; +}; + +class WCachedSample: public WResource{ +public: + friend class WResourceManager; + template friend class WCache; + WCachedSample(); + ~WCachedSample(); + + void Nullify(); + bool compare(JSample * s) {return (s == sample);}; + unsigned long size(); + bool isGood(); + void Refresh(string filename); + bool Attempt(string filename, int submode, int & error); + + JSample * Actual(); //Return this sample. +protected: + JSample * sample; +}; + +#endif \ No newline at end of file diff --git a/projects/mtg/include/WResourceManager.h b/projects/mtg/include/WResourceManager.h index a09971e9f..4aec4f888 100644 --- a/projects/mtg/include/WResourceManager.h +++ b/projects/mtg/include/WResourceManager.h @@ -5,73 +5,109 @@ #include #include "MTGDeck.h" #include "MTGCard.h" +#include "WCachedResource.h" -#ifdef WIN32 -#define CACHE_SIZE_PIXELS 20000000 -#define MAX_CACHE_OBJECTS 2000 -#else -#define CACHE_SIZE_PIXELS 2000000 +//Hard Limits. +#define LARGE_CACHE_LIMIT 5000000 +#define SMALL_CACHE_LIMIT 2000000 #define MAX_CACHE_OBJECTS 200 -#endif +#define MAX_CACHE_ATTEMPTS 10 +#define MAX_CACHE_MISSES 200 - -class WCachedResource{ -public: - friend class WResourceManager; - bool isLocked(); //Is the resource locked? - void lock(); //Lock it. - void unlock(bool force = false); //Unlock it. If force, then set locks to 0. - void hit(); //Update resource last used time. - - WCachedResource(); - -protected: - unsigned int lastTime; - unsigned char locks; //Remember to unlock when we're done using locked stuff, or else this'll be useless. -}; - -class WCachedTexture: public WCachedResource{ -public: - friend class WResourceManager; - WCachedTexture(); - ~WCachedTexture(); - - JTexture * GetTexture(); //Return this texture as is. Does not make a new one. - JQuad * GetQuad(float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f); //Get us a new/existing quad. - JQuad * GetCard(float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f); //Same as above, but centered when new. - bool ReleaseQuad(JQuad* quad); //We're done with this quad, so delete and stop tracking. True if existed. -protected: - JTexture * texture; - bool bVRAM; - vector trackedQuads; -}; - -class WCachedSample: public WCachedResource{ -public: - friend class WResourceManager; - WCachedSample(); - ~WCachedSample(); - - JSample * GetSample(); //Return this sample. -protected: - JSample * sample; +enum ENUM_WRES_INFO{ + WRES_UNLOCKED = 0, //Resource is unlocked. + WRES_MAX_LOCK = 250, //Maximum number of locks for a resource. + WRES_PERMANENT = 251, //Resource is permanent (ie, managed) }; enum ENUM_RETRIEVE_STYLE{ RETRIEVE_EXISTING, //Only returns a resource if it already exists. Does not lock or unlock. RETRIEVE_NORMAL, //Returns or creates a resource. Does not change lock status. - RETRIEVE_LOCK, //As above, locks cached resource. - RETRIEVE_UNLOCK, //As above, unlocks cached resource. - RETRIEVE_RESOURCE, //Only retrieves a managed resource. - RETRIEVE_VRAM, //If we create the texture, use vram. Also locks. - RETRIEVE_MANAGE, //Permanently adds retrieved resource to resource manager. + RETRIEVE_LOCK, //As above, locks cached resource. Not for quads. + RETRIEVE_UNLOCK, //As above, unlocks cached resource. Not for quads. + RETRIEVE_RESOURCE, //Only retrieves a managed resource. Does not make a new one. + RETRIEVE_VRAM, //Retrieve it, and use vram if have to we create it. Must still remove it. + RETRIEVE_MANAGE, //Makes resource permanent. + RETRIEVE_THUMB, //Retrieve it as a thumbnail. + CACHE_THUMB = RETRIEVE_THUMB, //Backwords compatibility. }; enum ENUM_CACHE_SUBTYPE{ - CACHE_CARD, - CACHE_THUMB + CACHE_NORMAL = (1<<0), //Use default values. Not really a flag. + CACHE_EXISTING = (1<<1), //Retrieve it only if it already exists + + //Because these bits only modify how a cached resource's Attempt() is called, + //We can use them over and over for each resource type. + TEXTURE_SUB_CARD = (1<<2), //Retrieve using cardFile, not graphicsFile. + TEXTURE_SUB_AVATAR = (1<<6), //Retrieve using avatarFile, not graphicsFile. + TEXTURE_SUB_THUMB = (1<<3),//Retrieve prepending "thumbnails\" to the filename. + TEXTURE_SUB_VRAM = (1<<4), //For textures. If we have to allocate, do it in VRAM. + TEXTURE_SUB_5551 = (1<<5), //For textures. If we have to allocate, use RGBA5551. + }; +enum ENUM_CACHE_ERROR{ + CACHE_ERROR_NONE = 0, + CACHE_ERROR_NOT_CACHED = CACHE_ERROR_NONE, + CACHE_ERROR_404, + CACHE_ERROR_BAD, + CACHE_ERROR_LOST, + CACHE_ERROR_NOT_MANAGED, +}; + +template +class WCache{ +public: + friend class WResourceManager; + + WCache(); + ~WCache(); + + cacheItem* Retrieve(string filename, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //Primary interface function. + bool Release(cacheActual* actual); //Releases an item, and deletes it if unlocked. + bool RemoveMiss(string id=""); //Removes a cache miss. + bool RemoveOldest(); //Remove oldest unlocked item. + bool Cleanup(); //Repeats RemoveOldest() until cache fits in size limits + void Clear(); //Removes everything cached. Not lock safe, does not remove managed items. + void ClearUnlocked(); //Remove all unlocked items. + void ClearMisses(); //Clear all cache misses. + void Refresh(); //Refreshes all cache items. + unsigned int Flatten(); //Ensures that the times don't loop. Returns new lastTime. + void Resize(unsigned long size, int items); //Sets new limits, then enforces them. Lock safe, so not a "hard limit". + +protected: + bool RemoveItem(cacheItem * item, bool force = true); //Removes an item, deleting it. if(force), ignores locks / permanent + bool UnlinkCache(cacheItem * item); //Removes an item from our cache, does not delete it. Use with care. + bool Delete(cacheItem * item); //Call SAFE_DELETE on cacheItem. If maxCached == 0, nullify first. (This means you have to free that cacheActual later!) + cacheItem* Get(string id, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //Subordinate to Retrieve. + cacheItem* AttemptNew(string filename, int submode); //Attempts a new cache item, progressively clearing cache if it fails. + + string makeID(string filename, int submode); //Makes an ID appropriate to the submode. + string makeFilename(string id, int submode); //Makes a filename from an ID. + + map cache; + map managed; //Cache can be arbitrarily large, so managed items are seperate. + unsigned long totalSize; + unsigned long cacheSize; + + //Applies to cacheSize only. + unsigned long maxCacheSize; + unsigned int maxCached; + + unsigned int cacheItems; + int mError; + +#if defined DEBUG_CACHE + string lastRemoved; + string lastReleased; + string lastExpired; +#endif +}; + +struct WManagedQuad { + WCachedTexture * texture; + string resname; +}; //This class is a wrapper for JResourceManager class WResourceManager: public JResourceManager @@ -80,64 +116,77 @@ public: WResourceManager(); ~WResourceManager(); - JQuad * RetrieveCard(MTGCard * card, int type = CACHE_CARD, int style = RETRIEVE_NORMAL); - JSample * RetrieveSample(string filename, int style = RETRIEVE_NORMAL); - JTexture * RetrieveTexture(string filename, int style = RETRIEVE_NORMAL); - JQuad * RetrieveQuad(string filename, float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f, string resname="", int style = RETRIEVE_NORMAL); + JQuad * RetrieveCard(MTGCard * card, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //RetrieveCard is reversed to match current use. + JSample * RetrieveSample(string filename, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); + JTexture * RetrieveTexture(string filename, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); + JQuad * RetrieveQuad(string filename, float offX=0.0f, float offY=0.0f, float width=0.0f, float height=0.0f, string resname="", int style = RETRIEVE_LOCK, int submode = CACHE_NORMAL); + JQuad * RetrieveTempQuad(string filename); + hgeParticleSystemInfo * RetrievePSI(string filename, JQuad * texture, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); + void Release(JTexture * tex); void Release(JQuad * quad); void Release(JSample * sample); - void ClearMisses(); - void ClearUnlocked(); - void ClearSamples(); - void Refresh(); //Refreshes all files in cache, for when mode/profile changes. + + bool Cleanup(); //Force a cleanup. Return false if nothing removed. + void ClearMisses(); //Remove all cache misses. + void ClearUnlocked(); //Remove unlocked items. + void Refresh(); //Refreshes all files in cache, for when mode/profile changes. unsigned int nowTime(); + unsigned long Size(); + unsigned long SizeCached(); + unsigned long SizeManaged(); + + unsigned int Count(); + unsigned int CountCached(); + unsigned int CountManaged(); + + int CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height); + JQuad* GetQuad(const string &quadName); + JQuad* GetQuad(int id); + //Our file redirect system. string graphicsFile(const string filename, const string specific = ""); - string cardFile(const string filename, const string setname, const string specific = ""); + string avatarFile(const string filename, const string specific = ""); + string cardFile(const string filename, const string specific = ""); string musicFile(const string filename, const string specific = ""); string sfxFile(const string filename, const string specific = ""); int fileOK(string filename, bool relative = false); - - //Not part of our interface, but left public to maintain JResourceManager compatibility - //These are for managed resources only. + //For backwards compatibility with JResourceManager. Avoid using these, they're not optimal. int CreateTexture(const string &textureName); - int CreateQuad(const string &quadName, const string &textureName, float x=0.0f, float y=0.0f, float width=0.0f, float height=0.0f); + JTexture* GetTexture(const string &textureName); + JTexture* GetTexture(int id); + + //Wrapped from JResourceManger. TODO: Privatize int LoadJLBFont(const string &fontName, int height); - int LoadMusic(const string &musicName); - int LoadSample(const string &sampleName); //Wrapped from JSoundSystem. TODO: Privatize. JMusic * ssLoadMusic(const char *fileName); -private: - bool RemoveOldestTexture(); - bool RemoveOldestSample(); - - bool cleanup(); + void LargeCache(); + void SmallCache(); - JTexture * attemptTexture(string filename, int mode = 0, int format = TEXTURE_FORMAT); + void DebugRender(); - WCachedTexture * getCachedTexture(string filename, bool makenew = true, int mode = 0, int format = TEXTURE_FORMAT); - WCachedTexture * getCachedCard(MTGCard * card, int type = CACHE_CARD, bool makenew = true); - WCachedSample * getCachedSample(string filename, bool makenew = true); +#ifdef DEBUG_CACHE + unsigned long menuCached; + string debugMessage; +#endif +private: void FlattenTimes(); //To prevent bad cache timing on int overflow - //For cached stuff - map textureCache; - map sampleCache; - - vector mTextureMissing; //For managed textures. - //Current access time. - int lastTime; + //For cached stuff + WCache textureWCache; + WCache sampleWCache; + WCache psiWCache; + vector managedQuads; + //Statistics of record. - int nb_textures; - long totalsize; + unsigned int lastTime; }; extern WResourceManager resources; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 220498d9b..52d873c65 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -562,7 +562,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op if (deckid == -1){ //Evil twin sprintf(deckFile, opponent->deckFile.c_str()); OutputDebugString(opponent->deckFile.c_str()); - sprintf(avatarFile, "%s",options.profileFile("avatar.jpg","graphics",true,true).c_str()); + sprintf(avatarFile, "baka.jpg"); sprintf(deckFileSmall, "ai_baka_eviltwin"); }else{ if (!deckid){ @@ -583,11 +583,10 @@ AIPlayer * AIPlayerFactory::createAIPlayer(MTGAllCards * collection, Player * op deckid = 1 + rand() % (nbdecks); } sprintf(deckFile, RESPATH"/ai/baka/deck%i.txt",deckid); - sprintf(avatarFile, "ai/baka/avatars/avatar%i.jpg",deckid); + sprintf(avatarFile, "avatar%i.jpg",deckid); sprintf(deckFileSmall, "ai_baka_deck%i",deckid); } - MTGDeck * tempDeck = NEW MTGDeck(deckFile, collection); MTGPlayerCards * deck = NEW MTGPlayerCards(collection,tempDeck); delete tempDeck; @@ -632,12 +631,18 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * potentialMana, const c } AIPlayerBaka::AIPlayerBaka(MTGPlayerCards * deck, string file, string fileSmall, string avatarFile) : AIPlayer(deck, file, fileSmall) { - if (fileExists(avatarFile.c_str())) - mAvatarTex = JRenderer::GetInstance()->LoadTexture(avatarFile.c_str(), TEX_TYPE_USE_VRAM); - else - mAvatarTex = JRenderer::GetInstance()->LoadTexture("ai/baka/avatar.jpg", TEX_TYPE_USE_VRAM); - if (mAvatarTex) - mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); + mAvatarTex = resources.RetrieveTexture(avatarFile,RETRIEVE_VRAM,TEXTURE_SUB_AVATAR); + + if(!mAvatarTex){ + avatarFile = "baka.jpg"; + mAvatarTex = resources.RetrieveTexture(avatarFile,RETRIEVE_VRAM,TEXTURE_SUB_AVATAR); + } + + if(mAvatarTex) + mAvatar = resources.RetrieveQuad(avatarFile, 0, 0, 35, 50,"bakaAvatar",RETRIEVE_VRAM,TEXTURE_SUB_AVATAR); + else + mAvatar = NULL; + initTimer(); } diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 1eec0e5a8..bef8edd4f 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -111,14 +111,14 @@ JQuad * CardGui::alternateThumbQuad(MTGCard * card){ JQuad * q; switch(card->getColor()) { - case Constants::MTG_COLOR_ARTIFACT : q = resources.RetrieveQuad("artifact_thumb.jpg");break; - case Constants::MTG_COLOR_GREEN: q = resources.RetrieveQuad("green_thumb.jpg");break; - case Constants::MTG_COLOR_BLUE : q = resources.RetrieveQuad("blue_thumb.jpg");break; - case Constants::MTG_COLOR_RED : q = resources.RetrieveQuad("red_thumb.jpg");break; - case Constants::MTG_COLOR_BLACK: q = resources.RetrieveQuad("black_thumb.jpg");break; - case Constants::MTG_COLOR_WHITE: q = resources.RetrieveQuad("white_thumb.jpg");break; - case Constants::MTG_COLOR_LAND : q = resources.RetrieveQuad("land_thumb.jpg");break; - default: q = resources.RetrieveQuad("black_thumb.jpg");break; + case Constants::MTG_COLOR_ARTIFACT : q = resources.RetrieveTempQuad("artifact_thumb.jpg");break; + case Constants::MTG_COLOR_GREEN: q = resources.RetrieveTempQuad("green_thumb.jpg");break; + case Constants::MTG_COLOR_BLUE : q = resources.RetrieveTempQuad("blue_thumb.jpg");break; + case Constants::MTG_COLOR_RED : q = resources.RetrieveTempQuad("red_thumb.jpg");break; + case Constants::MTG_COLOR_BLACK: q = resources.RetrieveTempQuad("black_thumb.jpg");break; + case Constants::MTG_COLOR_WHITE: q = resources.RetrieveTempQuad("white_thumb.jpg");break; + case Constants::MTG_COLOR_LAND : q = resources.RetrieveTempQuad("land_thumb.jpg");break; + default: q = resources.RetrieveTempQuad("black_thumb.jpg");break; } if(q && q->mTex) q->SetHotSpot(q->mTex->mWidth/2,q->mTex->mHeight/2); @@ -131,14 +131,14 @@ void CardGui::alternateRender(MTGCard * card, const Pos& pos){ JQuad * q; switch(card->getColor()) { - case Constants::MTG_COLOR_ARTIFACT: q = resources.RetrieveQuad("artifact.jpg");break; - case Constants::MTG_COLOR_GREEN: q = resources.RetrieveQuad("green.jpg");break; - case Constants::MTG_COLOR_BLUE : q = resources.RetrieveQuad("blue.jpg");break; - case Constants::MTG_COLOR_RED : q = resources.RetrieveQuad("red.jpg");break; - case Constants::MTG_COLOR_BLACK: q = resources.RetrieveQuad("black.jpg");break; - case Constants::MTG_COLOR_WHITE: q = resources.RetrieveQuad("white.jpg");break; - case Constants::MTG_COLOR_LAND: q = resources.RetrieveQuad("land.jpg");break; - default: q = resources.RetrieveQuad("black.jpg");break; + case Constants::MTG_COLOR_ARTIFACT: q = resources.RetrieveTempQuad("artifact.jpg");break; + case Constants::MTG_COLOR_GREEN: q = resources.RetrieveTempQuad("green.jpg");break; + case Constants::MTG_COLOR_BLUE : q = resources.RetrieveTempQuad("blue.jpg");break; + case Constants::MTG_COLOR_RED : q = resources.RetrieveTempQuad("red.jpg");break; + case Constants::MTG_COLOR_BLACK: q = resources.RetrieveTempQuad("black.jpg");break; + case Constants::MTG_COLOR_WHITE: q = resources.RetrieveTempQuad("white.jpg");break; + case Constants::MTG_COLOR_LAND: q = resources.RetrieveTempQuad("land.jpg");break; + default: q = resources.RetrieveTempQuad("black.jpg");break; } if(q && q->mTex){ q->SetHotSpot(q->mTex->mWidth/2,q->mTex->mHeight/2); diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 35301fb4b..d989e98f1 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -106,17 +106,17 @@ void GameApp::Create() for (int i = sizeof(manaIcons)/sizeof(manaIcons[0]) - 1; i >= 0; --i) manaIcons[i]->SetHotSpot(16,16); resources.RetrieveTexture("back.jpg",RETRIEVE_MANAGE); - resources.RetrieveQuad("back.jpg", 0, 0, 200, 285, "back",RETRIEVE_MANAGE); - resources.GetQuad("back")->SetHotSpot(100, 145); + JQuad * jq = resources.RetrieveQuad("back.jpg", 0, 0, 200, 285, "back",RETRIEVE_MANAGE); + jq->SetHotSpot(100, 145); resources.RetrieveTexture("back_thumb.jpg",RETRIEVE_MANAGE); resources.RetrieveQuad("back_thumb.jpg", 0, 0, MTG_MINIIMAGE_WIDTH, MTG_MINIIMAGE_HEIGHT, "back_thumb",RETRIEVE_MANAGE); resources.RetrieveTexture("particles.png",RETRIEVE_MANAGE); - resources.RetrieveQuad("particles.png", 0, 0, 32, 32, "particles",RETRIEVE_MANAGE); - resources.GetQuad("particles")->SetHotSpot(16,16); - resources.RetrieveQuad("particles.png", 64, 0, 32, 32, "stars",RETRIEVE_MANAGE); - resources.GetQuad("stars")->SetHotSpot(16,16); + jq = resources.RetrieveQuad("particles.png", 0, 0, 32, 32, "particles",RETRIEVE_MANAGE); + jq->SetHotSpot(16,16); + jq = resources.RetrieveQuad("particles.png", 64, 0, 32, 32, "stars",RETRIEVE_MANAGE); + jq->SetHotSpot(16,16); resources.LoadJLBFont("simon",11); resources.GetJLBFont("simon")->SetTracking(-1); @@ -134,14 +134,13 @@ void GameApp::Create() resources.RetrieveTexture("DefenderIcon.png",RETRIEVE_MANAGE); resources.RetrieveTexture("shadow.png",RETRIEVE_MANAGE); - resources.RetrieveQuad("BattleIcon.png", 0, 0, 25, 25,"BattleIcon",RETRIEVE_MANAGE); - resources.RetrieveQuad("DefenderIcon.png", 0, 0, 24, 23,"DefenderIcon",RETRIEVE_MANAGE); - resources.RetrieveQuad("shadow.png", 0, 0, 1, 1,"shadow",RETRIEVE_MANAGE); + jq = resources.RetrieveQuad("BattleIcon.png", 0, 0, 25, 25,"BattleIcon",RETRIEVE_MANAGE); + jq->SetHotSpot(12, 12); + jq = resources.RetrieveQuad("DefenderIcon.png", 0, 0, 24, 23,"DefenderIcon",RETRIEVE_MANAGE); + jq->SetHotSpot(12, 12); + jq = resources.RetrieveQuad("shadow.png", 0, 0, 1, 1,"shadow",RETRIEVE_MANAGE); + jq->SetHotSpot(0.5, 0.5); - resources.GetQuad("BattleIcon")->SetHotSpot(12, 12); - resources.GetQuad("DefenderIcon")->SetHotSpot(12, 12); - resources.GetQuad("shadow")->SetHotSpot(0.5, 0.5); - collection = NEW MTGAllCards(); Particles[0] = NEW hgeParticleSystem("graphics/particle1.psi", resources.GetQuad("particles")); @@ -284,6 +283,9 @@ void GameApp::Render() mCurrentState->Render(); } +#ifdef DEBUG_CACHE + resources.DebugRender(); +#endif } diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index 8ecc61f13..302f4abce 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -546,7 +546,7 @@ void GameStateDeckViewer::renderCard(int id, float rotation){ JQuad * quad = NULL; int showName = 0; - quad = resources.RetrieveCard(card,CACHE_CARD,RETRIEVE_EXISTING); + quad = resources.RetrieveCard(card,RETRIEVE_EXISTING); if (!quad){ if(last_user_activity > (abs(2-id) + 1)* NO_USER_ACTIVITY_SHOWCARD_DELAY) quad = resources.RetrieveCard(card); diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index eef3440df..72b2d64e0 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -42,7 +42,7 @@ GameStateDuel::GameStateDuel(GameApp* parent): GameState(parent) { deck[i]=NULL; mPlayers[i]=NULL; } - + resources.LargeCache(); premadeDeck = false; game = NULL; deckmenu = NULL; @@ -63,6 +63,7 @@ GameStateDuel::~GameStateDuel() { void GameStateDuel::Start() { JRenderer * renderer = JRenderer::GetInstance(); + resources.SmallCache(); renderer->ResetPrivateVRAM(); renderer->EnableVSync(true); @@ -217,7 +218,7 @@ void GameStateDuel::End() #if defined (WIN32) || defined (LINUX) OutputDebugString("Ending GamestateDuel\n"); #endif - + resources.SmallCache(); SAFE_DELETE(deckmenu); JRenderer::GetInstance()->EnableVSync(false); if (mPlayers[0] && mPlayers[1]) mPlayers[0]->End(); diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index da2f0959a..ef832cc53 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -152,11 +152,27 @@ void GameStateMenu::Start(){ //How many cards total ? PlayerData * playerdata = NEW PlayerData(mParent->collection); - if(!options[Options::ACTIVE_PROFILE].isDefault()) - sprintf(nbcardsStr, "%s: %i of %i cards", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); + if(playerdata && !options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, "%s: %i cards (%i)", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); else sprintf(nbcardsStr, "Database: %i cards", mParent->collection->totalCards()); + SAFE_DELETE(playerdata); + +#if defined DEBUG_CACHE + resources.ClearUnlocked(); //So we can tell if we've any extra locks. + + if(!resources.menuCached) + resources.menuCached = resources.CountCached(); + + if(resources.CountCached() != resources.menuCached){ + char buf[512]; + unsigned int i = resources.CountCached()-resources.menuCached; + sprintf(buf,"Warning: %u leftover locked items.",i); + resources.debugMessage = buf; + } + +#endif } @@ -306,8 +322,8 @@ void GameStateMenu::Update(float dt) //List active profile and database size. PlayerData * playerdata = NEW PlayerData(mParent->collection); - if(!options[Options::ACTIVE_PROFILE].isDefault()) - sprintf(nbcardsStr, "%s: %i of %i cards", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); + if(playerdata && !options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, "%s: %i cards (%i)", options[Options::ACTIVE_PROFILE].str.c_str(), playerdata->collection->totalCards(), mParent->collection->totalCards()); else sprintf(nbcardsStr, "Database: %i cards", mParent->collection->totalCards()); SAFE_DELETE(playerdata); diff --git a/projects/mtg/src/GameStateOptions.cpp b/projects/mtg/src/GameStateOptions.cpp index 725ba38f5..06f29669b 100644 --- a/projects/mtg/src/GameStateOptions.cpp +++ b/projects/mtg/src/GameStateOptions.cpp @@ -38,7 +38,7 @@ void GameStateOptions::Start() optionsList->Add(NEW OptionInteger(Options::INTERRUPT_SECONDS, "Seconds to pause for an Interrupt", 20, 1)); optionsList->Add(NEW OptionInteger(Options::INTERRUPTMYSPELLS, "Interrupt my spells")); optionsList->Add(NEW OptionInteger(Options::INTERRUPTMYABILITIES, "Interrupt my abilities")); - optionsList->Add(NEW OptionInteger(Options::CACHESIZE, "Image Cache Size", 60, 5,0,"Default")); + optionsList->Add(NEW OptionInteger(Options::CACHESIZE, "Use large cache")); optionsTabs = NEW OptionsMenu(); optionsTabs->Add(optionsList); diff --git a/projects/mtg/src/GuiCombat.cpp b/projects/mtg/src/GuiCombat.cpp index 72ce61aa3..ac49fe1b3 100644 --- a/projects/mtg/src/GuiCombat.cpp +++ b/projects/mtg/src/GuiCombat.cpp @@ -19,7 +19,7 @@ GuiCombat::GuiCombat(GameObserver* go) : GuiLayer(), go(go), active(false), acti enemy_avatar(SCREEN_WIDTH - MARGIN, TOP_LINE, 2, 0, 255), cursor_pos(NONE), step(DAMAGE) { - if (NULL == ok_quad) + if(NULL == ok_quad) { ok_quad = resources.RetrieveQuad("OK.png"); if (ok_quad) ok_quad->SetHotSpot(28, 22); @@ -28,6 +28,9 @@ GuiCombat::GuiCombat(GameObserver* go) : GuiLayer(), go(go), active(false), acti GuiCombat::~GuiCombat() { + if(ok_quad) + resources.Release(ok_quad); + for (inner_iterator it = attackers.begin(); it != attackers.end(); ++it) { for (vector::iterator q = (*it)->blockers.begin(); q != (*it)->blockers.end(); ++q) diff --git a/projects/mtg/src/GuiMana.cpp b/projects/mtg/src/GuiMana.cpp index a396f6928..d6ead1a68 100644 --- a/projects/mtg/src/GuiMana.cpp +++ b/projects/mtg/src/GuiMana.cpp @@ -10,26 +10,93 @@ const float ManaIcon::DESTY = 20; ManaIcon::ManaIcon(int color, float x, float y) : Pos(x, y, 0.5, 0.0, 255), f(-1), mode(ALIVE), color(color) { + hgeParticleSystemInfo * psi = NULL; + JQuad * mq = resources.GetQuad("stars"); + + if(!mq){ + particleSys = NULL; + return; + } + switch (color) { case Constants::MTG_COLOR_RED : - particleSys = NEW hgeParticleSystem("graphics/manared.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("manared.psi",mq); break; case Constants::MTG_COLOR_BLUE : - particleSys = NEW hgeParticleSystem("graphics/manablue.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("manablue.psi",mq); break; case Constants::MTG_COLOR_GREEN : - particleSys = NEW hgeParticleSystem("graphics/managreen.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("managreen.psi",mq); break; case Constants::MTG_COLOR_BLACK : - particleSys = NEW hgeParticleSystem("graphics/manablack.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("manablack.psi",mq); break; case Constants::MTG_COLOR_WHITE : - particleSys = NEW hgeParticleSystem("graphics/manawhite.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("manawhite.psi",mq); break; default : - particleSys = NEW hgeParticleSystem("graphics/mana.psi", resources.GetQuad("stars")); + psi = resources.RetrievePSI("mana.psi",mq); } + + if(!psi){ + psi = NEW hgeParticleSystemInfo(); + hgeParticleSystemInfo * defaults = resources.RetrievePSI("mana.psi",mq); + if(defaults){ + memcpy(psi,defaults,sizeof(hgeParticleSystemInfo)); + } + else{ + memset(psi,0,sizeof(hgeParticleSystemInfo)); + + //Default values for particle system! Cribbed from mana.psi + //Really, we should just be loading that and then changing colors... + /*psi->nEmission = 114; + psi->fLifetime = -1; + psi->fParticleLifeMin = 1.1507937; + psi->fParticleLifeMax = 1.4682540; + psi->fSpeedMin = 0.0099999998; + psi->fSizeStart = 0.5; + psi->fSizeEnd = 0.69999999; + psi->fSizeVar = 0.25396827; + psi->fSpinStart = -5.5555553; + psi->fAlphaVar = 0.77777779; + psi->sprite = mq;*/ + } + + switch(color){ + case Constants::MTG_COLOR_RED : + psi->colColorStart.SetHWColor(ARGB(161,240,40,44)); + psi->colColorEnd.SetHWColor(ARGB(14,242,155,153)); + break; + case Constants::MTG_COLOR_BLUE : + psi->colColorStart.SetHWColor(ARGB(161,28,40,224)); + psi->colColorEnd.SetHWColor(ARGB(14,255,255,255)); + break; + case Constants::MTG_COLOR_GREEN : + psi->colColorStart.SetHWColor(ARGB(161,36,242,44)); + psi->colColorEnd.SetHWColor(ARGB(14,129,244,153)); + break; + case Constants::MTG_COLOR_BLACK : + psi->colColorStart.SetHWColor(ARGB(161,210,117,210)); + psi->colColorEnd.SetHWColor(ARGB(14,80,56,80)); + break; + case Constants::MTG_COLOR_WHITE : + psi->colColorStart.SetHWColor(ARGB(151,151,127,38)); + psi->colColorEnd.SetHWColor(ARGB(8,255,255,255)); + break; + default: + psi->colColorStart.SetHWColor(ARGB(161,236,242,232)); + psi->colColorEnd.SetHWColor(ARGB(14,238,244,204)); + break; + } + + particleSys = NEW hgeParticleSystem(psi); + SAFE_DELETE(psi); //Not handled by cache, so kill it here. + } + else + particleSys = NEW hgeParticleSystem(psi); //Cache will clean psi up later. + + icon = manaIcons[color]; particleSys->FireAt(x, y); @@ -59,6 +126,9 @@ ManaIcon::~ManaIcon() void ManaIcon::Render() { + if(!particleSys) + return; + JRenderer* renderer = JRenderer::GetInstance(); renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 0e67e2e14..c06e2e804 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -1,664 +1,667 @@ -/*--------------------------------------------- - Card Instance - Instance of a given MTGCard in the game - Although there is only one MTGCard of each type, there can be as much Instances of it as needed in the game - -------------------------------------------- -*/ -#include "../include/config.h" -#include "../include/MTGCardInstance.h" -#include "../include/CardDescriptor.h" -#include "../include/Counters.h" -#include "../include/Subtypes.h" -#include -using namespace std; - -MTGCardInstance::MTGCardInstance(): MTGCard(), Damageable(0), view(NULL){ - LOG("==Creating MTGCardInstance=="); - initMTGCI(); - LOG("==Creating MTGCardInstance Successful=="); -} -MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to): MTGCard(card), Damageable(card->getToughness()), view(NULL){ - LOG("==Creating MTGCardInstance=="); - initMTGCI(); - model = card; - attacker = 0; - lifeOrig = life; - belongs_to = arg_belongs_to; - owner = NULL; - if (arg_belongs_to) owner = arg_belongs_to->library->owner; - lastController = owner; - defenser = NULL; - banding = NULL; - life = toughness; - LOG("==Creating MTGCardInstance Successful=="); - -} - -void MTGCardInstance::copy(MTGCardInstance * card){ - MTGCard * source = card->model; - for(map::const_iterator it = source->basicAbilities.begin(); it != source->basicAbilities.end(); ++it){ - int i = it->first; - basicAbilities[i] = source->basicAbilities[i]; - } - for (int i = 0; i< MAX_TYPES_PER_CARD; i++){ - types[i] = source->types[i]; - } - nb_types = source->nb_types; - for (int i = 0; i< Constants::MTG_NB_COLORS; i++){ - colors[i] = source->colors[i]; - } - manaCost.copy(source->getManaCost()); - - text = source->text; - name = source->name; - //strcpy(image_name, source->image_name); - - //rarity = source->rarity; - power = source->power; - toughness = source->toughness; - life = toughness; - lifeOrig = life; - //mtgid = source->mtgid; - //setId = source->setId; - magicText = source->magicText; - spellTargetType = source->spellTargetType; - alias = source->alias; - - //Now this is dirty... - int backupid = mtgid; - mtgid = source->getId(); - Spell * spell = NEW Spell(this); - AbilityFactory af; - GameObserver * g = GameObserver::GetInstance(); - af.addAbilities(g->mLayers->actionLayer()->getMaxId(), spell); - delete spell; - mtgid = backupid; -} - -MTGCardInstance::~MTGCardInstance(){ - LOG("==Deleting MTGCardInstance=="); - SAFE_DELETE(untapBlockers); - SAFE_DELETE(counters); - SAFE_DELETE(previous); - LOG("==Deleting MTGCardInstance Succesfull=="); -} -void MTGCardInstance::initMTGCI(){ - sample = ""; - model=NULL; - isToken = false; - lifeOrig = 0; - doDamageTest = 1; - belongs_to=NULL; - tapped = 0; - untapBlockers = NULL; - untapping = 0; - summoningSickness = 0; - target = NULL; - nbprotections = 0; - type_as_damageable = DAMAGEABLE_MTGCARDINSTANCE; - banding = NULL; - owner = NULL; - changedZoneRecently = 0; - counters = NEW Counters(this); - previousZone = NULL; - previous = NULL; - next = NULL; - lastController = NULL; - regenerateTokens = 0; - blocked = false; -} - - -const string MTGCardInstance::getDisplayName() const { - return getName(); -} - -void MTGCardInstance::addType(int type){ - types[nb_types] = type; - nb_types++; -} - -UntapBlockers * MTGCardInstance::getUntapBlockers(){ - if (!untapBlockers) untapBlockers = NEW UntapBlockers(); - return untapBlockers; -} - -int MTGCardInstance::isInPlay(){ - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0 ; i < 2 ; i++){ - MTGGameZone * zone = game->players[i]->game->inPlay; - if (zone->hasCard(this)) return 1; - } - return 0; -} - -int MTGCardInstance::afterDamage(){ - if (!doDamageTest) return 0; - doDamageTest = 0; - if (!isCreature()) return 0; - if (life <=0 && isInPlay()){ - return destroy(); - } - return 0; -} - -int MTGCardInstance::bury(){ - Player * p = controller(); - if (!basicAbilities[Constants::INDESTRUCTIBLE]){ - p->game->putInZone(this,p->game->inPlay,owner->game->graveyard); - return 1; - } - return 0; -} -int MTGCardInstance::destroy(){ - if (!triggerRegenerate()) return bury(); - return 0; -} - -MTGGameZone * MTGCardInstance::getCurrentZone(){ - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0; i < 2; i++){ - MTGPlayerCards * g = game->players[i]->game; - MTGGameZone * zones[] = {g->inPlay,g->graveyard,g->hand, g->library}; - for (int k = 0; k < 4; k++){ - MTGGameZone * zone = zones[k]; - if (zone->hasCard(this)) return zone; - } - } - return NULL; -} - -int MTGCardInstance::has(int basicAbility){ - return basicAbilities[basicAbility]; -} - -//Taps the card -void MTGCardInstance::tap(){ - if (tapped) return; - tapped = 1; - WEvent * e = NEW WEventCardTap(this, 0, 1); - GameObserver * game = GameObserver::GetInstance(); - game->receiveEvent(e); -} - -void MTGCardInstance::untap(){ - if (!tapped) return; - tapped = 0; - WEvent * e = NEW WEventCardTap(this, 1, 0); - GameObserver * game = GameObserver::GetInstance(); - game->receiveEvent(e); -} - - -void MTGCardInstance::setUntapping(){ - untapping = 1; -} - -int MTGCardInstance::isUntapping(){ - return untapping; -} - -//Tries to Untap the card -void MTGCardInstance::attemptUntap(){ - if (untapping){ - untap(); - untapping = 0; - } -} - -//Tells if the card is tapped or not -int MTGCardInstance::isTapped(){ - return tapped; -} - -void MTGCardInstance::resetAllDamage(){ - nb_damages = 0; -} - -int MTGCardInstance::regenerate(){ - return ++regenerateTokens; -} - -int MTGCardInstance::triggerRegenerate(){ - if (! regenerateTokens) return 0; - regenerateTokens--; - tap(); - life = toughness; - initAttackersDefensers(); - return 1; -} - - -int MTGCardInstance::initAttackersDefensers(){ - setAttacker(0); - setDefenser(NULL); - banding = NULL; - blockers.clear(); - blocked = false; - return 1; -} - -//Function to call to remove all damages, etc to a card (generally at the end of the turn) -int MTGCardInstance::cleanup(){ - initAttackersDefensers(); - life=toughness; - GameObserver * game = GameObserver::GetInstance(); - if (!game || game->currentPlayer == controller()) summoningSickness = 0; - if (previous && !previous->stillInUse()){ - SAFE_DELETE(previous); - } - regenerateTokens = 0; - return 1; -} - -int MTGCardInstance::stillInUse(){ -GameObserver * game = GameObserver::GetInstance(); -if (game->mLayers->actionLayer()->stillInUse(this)) return 1; -if (!previous) return 0; -return previous->stillInUse(); -} - -/* Summoning Sickness - * 212.3f A creature's activated ability with the tap symbol or the untap symbol in its activation cost - * can't be played unless the creature has been under its controller's control since the start of his or - * her most recent turn. A creature can't attack unless it has been under its controller's control - * since the start of his or her most recent turn. This rule is informally called the "summoning - * sickness" rule. Ignore this rule for creatures with haste (see rule 502.5). - */ -int MTGCardInstance::hasSummoningSickness(){ - if (!summoningSickness) return 0; - if (basicAbilities[Constants::HASTE]) return 0; - if (!isCreature()) return 0; - return 1; -} - -MTGCardInstance * MTGCardInstance::changeController(Player * newController){ - Player * originalOwner = controller(); - if (originalOwner == newController) return 0; - MTGCardInstance * copy = originalOwner->game->putInZone(this, originalOwner->game->inPlay, newController->game->inPlay); - copy->summoningSickness = 1; - return copy; -} - -//Reset the card parameters -int MTGCardInstance::reset(){ - cleanup(); - untap(); - SAFE_DELETE(counters); - counters = NEW Counters(this); - return 1; -} - - -Player * MTGCardInstance::controller(){ - GameObserver * game = GameObserver::GetInstance(); - if (!game) return NULL; - for (int i = 0; i < 2; ++i){ - if (game->players[i]->game->inPlay->hasCard(this)) return game->players[i]; - if (game->players[i]->game->stack->hasCard(this)) return game->players[i]; - if (game->players[i]->game->graveyard->hasCard(this)) return game->players[i]; - if (game->players[i]->game->hand->hasCard(this)) return game->players[i]; - if (game->players[i]->game->library->hasCard(this)) return game->players[i]; - } - return lastController; -} - -int MTGCardInstance::canAttack(){ - if (tapped) return 0; - if (hasSummoningSickness()) return 0; - if (basicAbilities[Constants::DEFENSER] || basicAbilities[Constants::CANTATTACK]) return 0; - if (!isCreature()) return 0; - if (!isInPlay()) return 0; - return 1; -} - - -int MTGCardInstance::addToToughness(int value){ - toughness+=value; - life+=value; - doDamageTest = 1; - return 1; -} - -int MTGCardInstance::setToughness(int value){ - toughness=value; - life=value; - doDamageTest = 1; - return 1; -} - -int MTGCardInstance::canBlock(){ - if (tapped) return 0; - if (basicAbilities[Constants::CANTBLOCK]) return 0; - if (!isCreature()) return 0; - if (!isInPlay()) return 0; - return 1; -} - -int MTGCardInstance::canBlock(MTGCardInstance * opponent){ - if (!canBlock()) return 0; - if (!opponent) return 1; - if (!opponent->isAttacker()) return 0; - // Comprehensive rule 502.7f : If a creature with protection attacks, it can't be blocked by creatures that have the stated quality. - if (opponent->protectedAgainst(this)) return 0; - if (opponent->basicAbilities[Constants::UNBLOCKABLE]) return 0; - if (opponent->basicAbilities[Constants::FEAR] && !(hasColor(Constants::MTG_COLOR_ARTIFACT) || hasColor(Constants::MTG_COLOR_BLACK))) return 0; - - //intimidate - if (opponent->basicAbilities[Constants::INTIMIDATE] && !(hasColor(Constants::MTG_COLOR_ARTIFACT))){ - int canblock = 0; - for (int i = Constants::PROTECTIONGREEN; i <= Constants::PROTECTIONWHITE; ++i){ - if(hasColor(i) && opponent->hasColor(i)){ - canblock = 1; - break; - } - } - if (!canblock) return 0; - } - - if (opponent->basicAbilities[Constants::FLYING] && !( basicAbilities[Constants::FLYING] || basicAbilities[Constants::REACH])) return 0; - //Can block only creatures with flying if has cloud - if (basicAbilities[Constants::CLOUD] && !( opponent->basicAbilities[Constants::FLYING])) return 0; - // If opponent has shadow and a creature does not have either shadow or reachshadow it cannot be blocked - if (opponent->basicAbilities[Constants::SHADOW] && !( basicAbilities[Constants::SHADOW] || basicAbilities[Constants::REACHSHADOW])) return 0; - // If opponent does not have shadow and a creature has shadow it cannot be blocked - if (!opponent->basicAbilities[Constants::SHADOW] && basicAbilities[Constants::SHADOW]) return 0; - if (opponent->basicAbilities[Constants::SWAMPWALK] && controller()->game->inPlay->hasType("swamp")) return 0; - if (opponent->basicAbilities[Constants::FORESTWALK] && controller()->game->inPlay->hasType("forest")) return 0; - if (opponent->basicAbilities[Constants::ISLANDWALK] && controller()->game->inPlay->hasType("island")) return 0; - if (opponent->basicAbilities[Constants::MOUNTAINWALK] && controller()->game->inPlay->hasType("mountain")) return 0; - if (opponent->basicAbilities[Constants::PLAINSWALK] && controller()->game->inPlay->hasType("plains")) return 0; - return 1; -} - -MTGCardInstance * MTGCardInstance::getNextPartner(){ - MTGInPlay * inplay = controller()->game->inPlay; - MTGCardInstance * bandingPartner = inplay->getNextAttacker(banding); - while (bandingPartner){ - if (basicAbilities[Constants::BANDING] || bandingPartner->basicAbilities[Constants::BANDING]) return bandingPartner; - bandingPartner = inplay->getNextAttacker(bandingPartner); - } - return NULL; -} - -void MTGCardInstance::unband(){ - if (!banding) return; - - MTGCardInstance * _banding = banding; - banding = NULL; - MTGCardInstance * newbanding = NULL; - MTGInPlay * inplay = controller()->game->inPlay; - int nbpartners = inplay->nbPartners(this); - MTGCardInstance * card = inplay->getNextAttacker(NULL); - while(card){ - if (card != this){ - if (card->banding == _banding){ - if (nbpartners == 1){ - card->banding = NULL; - return; - }else{ - if (!newbanding) newbanding = card; - card->banding = newbanding; - } - } - } - card = inplay->getNextAttacker(card); - } - return ; -} - -int MTGCardInstance::setAttacker(int value){ - Targetable * previousTarget = NULL; - Targetable * target = NULL; - Player * p = controller()->opponent(); - if (value) target = p; - if (attacker) previousTarget = p; - attacker = value; - WEvent * e = NEW WEventCreatureAttacker(this,previousTarget, target); - GameObserver::GetInstance()->receiveEvent(e); - return 1; -} - -int MTGCardInstance::toggleAttacker(){ - if (!attacker){ - if (!basicAbilities[Constants::VIGILANCE]) tap(); - setAttacker(1); - return 1; - }else{ - //Banding needs to be debugged... - /*MTGCardInstance * bandingPartner = getNextPartner(); - if (bandingPartner){ - if (banding) unband(); - if (!bandingPartner->banding) bandingPartner->banding = bandingPartner; - banding = bandingPartner->banding; - return 1; - }else{*/ - untap(); - setAttacker(0); - return 1; - //} - } - return 0; -} - -int MTGCardInstance::isAttacker(){ - return attacker; -} - -MTGCardInstance * MTGCardInstance::isDefenser(){ - return defenser; -} - - -int MTGCardInstance::nbOpponents(){ - int result= 0; - MTGCardInstance* opponent = getNextOpponent(); - while (opponent){ - result++; - opponent = getNextOpponent(opponent); - } - return result; -} - -MTGCardInstance * MTGCardInstance::getNextDefenser(MTGCardInstance * previous){ - int found_previous = 0; - if (!previous) found_previous = 1; - list::iterator it; - for (it= blockers.begin(); it != blockers.end(); ++it){ - MTGCardInstance * c = *it; - if (found_previous && c->isInPlay()) return c; - if (c == previous) found_previous = 1; - } - return NULL; -} - -int MTGCardInstance::raiseBlockerRankOrder(MTGCardInstance * blocker){ - list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); - list::iterator it2 = it1; - if (blockers.begin() == it2) ++it2; else --it2; - - std::iter_swap(it1,it2); - WEvent* e = NEW WEventCreatureBlockerRank(*it1,*it2,this); - GameObserver::GetInstance()->receiveEvent(e); - //delete(e); - return 1; -} - -int MTGCardInstance::bringBlockerToFrontOfOrder(MTGCardInstance * blocker){ - list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); - list::iterator it2 = blockers.begin(); - if (it2 != it1) - { - std::iter_swap(it1,it2); - WEvent* e = NEW WEventCreatureBlockerRank(blocker,*it2,this); - GameObserver::GetInstance()->receiveEvent(e); - //delete(e); - } - return 1; -} - -int MTGCardInstance::removeBlocker(MTGCardInstance * blocker){ - blockers.remove(blocker); - if (!blockers.size()) blocked = false; - return 1; -} - -int MTGCardInstance::addBlocker(MTGCardInstance * blocker){ - blockers.push_back(blocker); - blocked = true; - return 1; -} - -//Returns opponents to this card for this turn. This * should * take into account banding -MTGCardInstance * MTGCardInstance::getNextOpponent(MTGCardInstance * previous){ - GameObserver * game = GameObserver::GetInstance(); - int foundprevious = 0; - if (!previous) foundprevious = 1; - if (attacker && game->currentPlayer->game->inPlay->hasCard(this)){ - MTGInPlay * inPlay = game->opponent()->game->inPlay; - for (int i = 0; i < inPlay->nb_cards; i ++){ - MTGCardInstance * current = inPlay->cards[i]; - if (current == previous){ - foundprevious = 1; - }else if (foundprevious){ - MTGCardInstance * defensersOpponent = current->isDefenser(); - if (defensersOpponent && (defensersOpponent == this || (banding && defensersOpponent->banding == banding))){ - return current; - } - } - } - }else if (defenser && game->opponent()->game->inPlay->hasCard(this)){ - MTGInPlay * inPlay = game->currentPlayer->game->inPlay; - for (int i = 0; i < inPlay->nb_cards; i ++){ - MTGCardInstance * current = inPlay->cards[i]; - if (current == previous){ - foundprevious = 1; - }else if (foundprevious){ - if (defenser == current || (current->banding && defenser->banding == current->banding)){ - return current; - } - } - } - } - return NULL; -} - -int MTGCardInstance::setDefenser(MTGCardInstance * opponent){ - GameObserver * g = GameObserver::GetInstance(); - if (defenser) { - if (g->players[0]->game->battlefield->hasCard(defenser) || - g->players[1]->game->battlefield->hasCard(defenser) ) { - defenser->removeBlocker(this); - } - } - WEvent * e = NULL; - if (defenser != opponent) e = NEW WEventCreatureBlocker(this, defenser, opponent); - defenser = opponent; - if (defenser) defenser->addBlocker(this); - if (e) g->receiveEvent(e); - return 1; -} - -int MTGCardInstance::toggleDefenser(MTGCardInstance * opponent){ - if (canBlock()){ - if (canBlock(opponent)){ - setDefenser(opponent); - return 1; - } - } - return 0; -} - - -int MTGCardInstance::addProtection(CardDescriptor * cd){ - protections[nbprotections] = cd; - nbprotections++; - return nbprotections; -} - -int MTGCardInstance::removeProtection(CardDescriptor * cd, int erase){ - for (int i = 0; i < nbprotections ; i++){ - if (protections[i] == cd){ - if (erase) delete (protections[i]); - protections[i] = protections[nbprotections -1]; - protections[nbprotections -1] = NULL; - nbprotections--; - return 1; - } - } - return 0; -} - -int MTGCardInstance::protectedAgainst(MTGCardInstance * card){ - //Basic protections - for (int i=Constants::PROTECTIONGREEN; i <= Constants::PROTECTIONWHITE; i++){ - if (basicAbilities[i] && card->hasColor( i - Constants::PROTECTIONGREEN + Constants::MTG_COLOR_GREEN )) return 1; - } - - //General protections - for (int i = 0; i < nbprotections ; i++){ - if (protections[i]->match(card)) return 1; - } - return 0; -} - -/* Choose a sound sample to associate to that card */ -JSample * MTGCardInstance::getSample(){ - if (!sample.size()){ - for (int i = nb_types-1; i>0; i--){ - string type = Subtypes::subtypesList->find(types[i]); - type = type + ".wav"; - if (fileExists(resources.sfxFile(type).c_str())){ - sample = string(type); - break; - } - } - } - if (!sample.size()){ - for(map::const_iterator it = basicAbilities.begin(); it != basicAbilities.end(); ++it){ - int i = it->first; - if (!basicAbilities[i]) continue; - string type = Constants::MTGBasicAbilities[i]; - type = type + ".wav"; - if (fileExists(resources.sfxFile(type).c_str())){ - sample = type; - break; - } - } - } - if (!sample.size()){ - string type = Subtypes::subtypesList->find(types[0]); - type = type + ".wav"; - if (fileExists(resources.sfxFile(type).c_str())){ - sample = type; - } - } - - if (sample.size()) return resources.RetrieveSample(sample); - - return NULL; -} - -int MTGCardInstance::stepPower(CombatStep step) -{ - switch (step) - { - case FIRST_STRIKE : - case END_FIRST_STRIKE : - if (has(Constants::FIRSTSTRIKE) || has(Constants::DOUBLESTRIKE)) return MAX(0, power); else return 0; - case DAMAGE : - case END_DAMAGE : - default : - if (has(Constants::FIRSTSTRIKE)) return 0; else return MAX(0, power); - } -} - -std::ostream& MTGCardInstance::toString(std::ostream& out) const -{ - return out << name; -} - -std::ostream& operator<<(std::ostream& out, const MTGCardInstance& c) -{ - return c.toString(out); -} +/*--------------------------------------------- + Card Instance + Instance of a given MTGCard in the game + Although there is only one MTGCard of each type, there can be as much Instances of it as needed in the game + -------------------------------------------- +*/ +#include "../include/config.h" +#include "../include/MTGCardInstance.h" +#include "../include/CardDescriptor.h" +#include "../include/Counters.h" +#include "../include/Subtypes.h" +#include +using namespace std; + +MTGCardInstance::MTGCardInstance(): MTGCard(), Damageable(0), view(NULL){ + LOG("==Creating MTGCardInstance=="); + initMTGCI(); + LOG("==Creating MTGCardInstance Successful=="); +} +MTGCardInstance::MTGCardInstance(MTGCard * card, MTGPlayerCards * arg_belongs_to): MTGCard(card), Damageable(card->getToughness()), view(NULL){ + LOG("==Creating MTGCardInstance=="); + initMTGCI(); + model = card; + attacker = 0; + lifeOrig = life; + belongs_to = arg_belongs_to; + owner = NULL; + if (arg_belongs_to) owner = arg_belongs_to->library->owner; + lastController = owner; + defenser = NULL; + banding = NULL; + life = toughness; + LOG("==Creating MTGCardInstance Successful=="); + +} + +void MTGCardInstance::copy(MTGCardInstance * card){ + MTGCard * source = card->model; + for(map::const_iterator it = source->basicAbilities.begin(); it != source->basicAbilities.end(); ++it){ + int i = it->first; + basicAbilities[i] = source->basicAbilities[i]; + } + for (int i = 0; i< MAX_TYPES_PER_CARD; i++){ + types[i] = source->types[i]; + } + nb_types = source->nb_types; + for (int i = 0; i< Constants::MTG_NB_COLORS; i++){ + colors[i] = source->colors[i]; + } + manaCost.copy(source->getManaCost()); + + text = source->text; + name = source->name; + //strcpy(image_name, source->image_name); + + //rarity = source->rarity; + power = source->power; + toughness = source->toughness; + life = toughness; + lifeOrig = life; + //mtgid = source->mtgid; + //setId = source->setId; + magicText = source->magicText; + spellTargetType = source->spellTargetType; + alias = source->alias; + + //Now this is dirty... + int backupid = mtgid; + mtgid = source->getId(); + Spell * spell = NEW Spell(this); + AbilityFactory af; + GameObserver * g = GameObserver::GetInstance(); + af.addAbilities(g->mLayers->actionLayer()->getMaxId(), spell); + delete spell; + mtgid = backupid; +} + +MTGCardInstance::~MTGCardInstance(){ + LOG("==Deleting MTGCardInstance=="); + SAFE_DELETE(untapBlockers); + SAFE_DELETE(counters); + SAFE_DELETE(previous); + LOG("==Deleting MTGCardInstance Succesfull=="); +} +void MTGCardInstance::initMTGCI(){ + sample = ""; + model=NULL; + isToken = false; + lifeOrig = 0; + doDamageTest = 1; + belongs_to=NULL; + tapped = 0; + untapBlockers = NULL; + untapping = 0; + summoningSickness = 0; + target = NULL; + nbprotections = 0; + type_as_damageable = DAMAGEABLE_MTGCARDINSTANCE; + banding = NULL; + owner = NULL; + changedZoneRecently = 0; + counters = NEW Counters(this); + previousZone = NULL; + previous = NULL; + next = NULL; + lastController = NULL; + regenerateTokens = 0; + blocked = false; +} + + +const string MTGCardInstance::getDisplayName() const { + return getName(); +} + +void MTGCardInstance::addType(int type){ + types[nb_types] = type; + nb_types++; +} + +UntapBlockers * MTGCardInstance::getUntapBlockers(){ + if (!untapBlockers) untapBlockers = NEW UntapBlockers(); + return untapBlockers; +} + +int MTGCardInstance::isInPlay(){ + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0 ; i < 2 ; i++){ + MTGGameZone * zone = game->players[i]->game->inPlay; + if (zone->hasCard(this)) return 1; + } + return 0; +} + +int MTGCardInstance::afterDamage(){ + if (!doDamageTest) return 0; + doDamageTest = 0; + if (!isCreature()) return 0; + if (life <=0 && isInPlay()){ + return destroy(); + } + return 0; +} + +int MTGCardInstance::bury(){ + Player * p = controller(); + if (!basicAbilities[Constants::INDESTRUCTIBLE]){ + p->game->putInZone(this,p->game->inPlay,owner->game->graveyard); + return 1; + } + return 0; +} +int MTGCardInstance::destroy(){ + if (!triggerRegenerate()) return bury(); + return 0; +} + +MTGGameZone * MTGCardInstance::getCurrentZone(){ + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0; i < 2; i++){ + MTGPlayerCards * g = game->players[i]->game; + MTGGameZone * zones[] = {g->inPlay,g->graveyard,g->hand, g->library}; + for (int k = 0; k < 4; k++){ + MTGGameZone * zone = zones[k]; + if (zone->hasCard(this)) return zone; + } + } + return NULL; +} + +int MTGCardInstance::has(int basicAbility){ + return basicAbilities[basicAbility]; +} + +//Taps the card +void MTGCardInstance::tap(){ + if (tapped) return; + tapped = 1; + WEvent * e = NEW WEventCardTap(this, 0, 1); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(e); +} + +void MTGCardInstance::untap(){ + if (!tapped) return; + tapped = 0; + WEvent * e = NEW WEventCardTap(this, 1, 0); + GameObserver * game = GameObserver::GetInstance(); + game->receiveEvent(e); +} + + +void MTGCardInstance::setUntapping(){ + untapping = 1; +} + +int MTGCardInstance::isUntapping(){ + return untapping; +} + +//Tries to Untap the card +void MTGCardInstance::attemptUntap(){ + if (untapping){ + untap(); + untapping = 0; + } +} + +//Tells if the card is tapped or not +int MTGCardInstance::isTapped(){ + return tapped; +} + +void MTGCardInstance::resetAllDamage(){ + nb_damages = 0; +} + +int MTGCardInstance::regenerate(){ + return ++regenerateTokens; +} + +int MTGCardInstance::triggerRegenerate(){ + if (! regenerateTokens) return 0; + regenerateTokens--; + tap(); + life = toughness; + initAttackersDefensers(); + return 1; +} + + +int MTGCardInstance::initAttackersDefensers(){ + setAttacker(0); + setDefenser(NULL); + banding = NULL; + blockers.clear(); + blocked = false; + return 1; +} + +//Function to call to remove all damages, etc to a card (generally at the end of the turn) +int MTGCardInstance::cleanup(){ + initAttackersDefensers(); + life=toughness; + GameObserver * game = GameObserver::GetInstance(); + if (!game || game->currentPlayer == controller()) summoningSickness = 0; + if (previous && !previous->stillInUse()){ + SAFE_DELETE(previous); + } + regenerateTokens = 0; + return 1; +} + +int MTGCardInstance::stillInUse(){ +GameObserver * game = GameObserver::GetInstance(); +if (game->mLayers->actionLayer()->stillInUse(this)) return 1; +if (!previous) return 0; +return previous->stillInUse(); +} + +/* Summoning Sickness + * 212.3f A creature's activated ability with the tap symbol or the untap symbol in its activation cost + * can't be played unless the creature has been under its controller's control since the start of his or + * her most recent turn. A creature can't attack unless it has been under its controller's control + * since the start of his or her most recent turn. This rule is informally called the "summoning + * sickness" rule. Ignore this rule for creatures with haste (see rule 502.5). + */ +int MTGCardInstance::hasSummoningSickness(){ + if (!summoningSickness) return 0; + if (basicAbilities[Constants::HASTE]) return 0; + if (!isCreature()) return 0; + return 1; +} + +MTGCardInstance * MTGCardInstance::changeController(Player * newController){ + Player * originalOwner = controller(); + if (originalOwner == newController) return 0; + MTGCardInstance * copy = originalOwner->game->putInZone(this, originalOwner->game->inPlay, newController->game->inPlay); + copy->summoningSickness = 1; + return copy; +} + +//Reset the card parameters +int MTGCardInstance::reset(){ + cleanup(); + untap(); + SAFE_DELETE(counters); + counters = NEW Counters(this); + return 1; +} + + +Player * MTGCardInstance::controller(){ + GameObserver * game = GameObserver::GetInstance(); + if (!game) return NULL; + for (int i = 0; i < 2; ++i){ + if (game->players[i]->game->inPlay->hasCard(this)) return game->players[i]; + if (game->players[i]->game->stack->hasCard(this)) return game->players[i]; + if (game->players[i]->game->graveyard->hasCard(this)) return game->players[i]; + if (game->players[i]->game->hand->hasCard(this)) return game->players[i]; + if (game->players[i]->game->library->hasCard(this)) return game->players[i]; + } + return lastController; +} + +int MTGCardInstance::canAttack(){ + if (tapped) return 0; + if (hasSummoningSickness()) return 0; + if (basicAbilities[Constants::DEFENSER] || basicAbilities[Constants::CANTATTACK]) return 0; + if (!isCreature()) return 0; + if (!isInPlay()) return 0; + return 1; +} + + +int MTGCardInstance::addToToughness(int value){ + toughness+=value; + life+=value; + doDamageTest = 1; + return 1; +} + +int MTGCardInstance::setToughness(int value){ + toughness=value; + life=value; + doDamageTest = 1; + return 1; +} + +int MTGCardInstance::canBlock(){ + if (tapped) return 0; + if (basicAbilities[Constants::CANTBLOCK]) return 0; + if (!isCreature()) return 0; + if (!isInPlay()) return 0; + return 1; +} + +int MTGCardInstance::canBlock(MTGCardInstance * opponent){ + if (!canBlock()) return 0; + if (!opponent) return 1; + if (!opponent->isAttacker()) return 0; + // Comprehensive rule 502.7f : If a creature with protection attacks, it can't be blocked by creatures that have the stated quality. + if (opponent->protectedAgainst(this)) return 0; + if (opponent->basicAbilities[Constants::UNBLOCKABLE]) return 0; + if (opponent->basicAbilities[Constants::FEAR] && !(hasColor(Constants::MTG_COLOR_ARTIFACT) || hasColor(Constants::MTG_COLOR_BLACK))) return 0; + + //intimidate + if (opponent->basicAbilities[Constants::INTIMIDATE] && !(hasColor(Constants::MTG_COLOR_ARTIFACT))){ + int canblock = 0; + for (int i = Constants::PROTECTIONGREEN; i <= Constants::PROTECTIONWHITE; ++i){ + if(hasColor(i) && opponent->hasColor(i)){ + canblock = 1; + break; + } + } + if (!canblock) return 0; + } + + if (opponent->basicAbilities[Constants::FLYING] && !( basicAbilities[Constants::FLYING] || basicAbilities[Constants::REACH])) return 0; + //Can block only creatures with flying if has cloud + if (basicAbilities[Constants::CLOUD] && !( opponent->basicAbilities[Constants::FLYING])) return 0; + // If opponent has shadow and a creature does not have either shadow or reachshadow it cannot be blocked + if (opponent->basicAbilities[Constants::SHADOW] && !( basicAbilities[Constants::SHADOW] || basicAbilities[Constants::REACHSHADOW])) return 0; + // If opponent does not have shadow and a creature has shadow it cannot be blocked + if (!opponent->basicAbilities[Constants::SHADOW] && basicAbilities[Constants::SHADOW]) return 0; + if (opponent->basicAbilities[Constants::SWAMPWALK] && controller()->game->inPlay->hasType("swamp")) return 0; + if (opponent->basicAbilities[Constants::FORESTWALK] && controller()->game->inPlay->hasType("forest")) return 0; + if (opponent->basicAbilities[Constants::ISLANDWALK] && controller()->game->inPlay->hasType("island")) return 0; + if (opponent->basicAbilities[Constants::MOUNTAINWALK] && controller()->game->inPlay->hasType("mountain")) return 0; + if (opponent->basicAbilities[Constants::PLAINSWALK] && controller()->game->inPlay->hasType("plains")) return 0; + return 1; +} + +MTGCardInstance * MTGCardInstance::getNextPartner(){ + MTGInPlay * inplay = controller()->game->inPlay; + MTGCardInstance * bandingPartner = inplay->getNextAttacker(banding); + while (bandingPartner){ + if (basicAbilities[Constants::BANDING] || bandingPartner->basicAbilities[Constants::BANDING]) return bandingPartner; + bandingPartner = inplay->getNextAttacker(bandingPartner); + } + return NULL; +} + +void MTGCardInstance::unband(){ + if (!banding) return; + + MTGCardInstance * _banding = banding; + banding = NULL; + MTGCardInstance * newbanding = NULL; + MTGInPlay * inplay = controller()->game->inPlay; + int nbpartners = inplay->nbPartners(this); + MTGCardInstance * card = inplay->getNextAttacker(NULL); + while(card){ + if (card != this){ + if (card->banding == _banding){ + if (nbpartners == 1){ + card->banding = NULL; + return; + }else{ + if (!newbanding) newbanding = card; + card->banding = newbanding; + } + } + } + card = inplay->getNextAttacker(card); + } + return ; +} + +int MTGCardInstance::setAttacker(int value){ + Targetable * previousTarget = NULL; + Targetable * target = NULL; + Player * p = controller()->opponent(); + if (value) target = p; + if (attacker) previousTarget = p; + attacker = value; + WEvent * e = NEW WEventCreatureAttacker(this,previousTarget, target); + GameObserver::GetInstance()->receiveEvent(e); + return 1; +} + +int MTGCardInstance::toggleAttacker(){ + if (!attacker){ + if (!basicAbilities[Constants::VIGILANCE]) tap(); + setAttacker(1); + return 1; + }else{ + //Banding needs to be debugged... + /*MTGCardInstance * bandingPartner = getNextPartner(); + if (bandingPartner){ + if (banding) unband(); + if (!bandingPartner->banding) bandingPartner->banding = bandingPartner; + banding = bandingPartner->banding; + return 1; + }else{*/ + untap(); + setAttacker(0); + return 1; + //} + } + return 0; +} + +int MTGCardInstance::isAttacker(){ + return attacker; +} + +MTGCardInstance * MTGCardInstance::isDefenser(){ + return defenser; +} + + +int MTGCardInstance::nbOpponents(){ + int result= 0; + MTGCardInstance* opponent = getNextOpponent(); + while (opponent){ + result++; + opponent = getNextOpponent(opponent); + } + return result; +} + +MTGCardInstance * MTGCardInstance::getNextDefenser(MTGCardInstance * previous){ + int found_previous = 0; + if (!previous) found_previous = 1; + list::iterator it; + for (it= blockers.begin(); it != blockers.end(); ++it){ + MTGCardInstance * c = *it; + if (found_previous && c->isInPlay()) return c; + if (c == previous) found_previous = 1; + } + return NULL; +} + +int MTGCardInstance::raiseBlockerRankOrder(MTGCardInstance * blocker){ + list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); + list::iterator it2 = it1; + if (blockers.begin() == it2) ++it2; else --it2; + + std::iter_swap(it1,it2); + WEvent* e = NEW WEventCreatureBlockerRank(*it1,*it2,this); + GameObserver::GetInstance()->receiveEvent(e); + //delete(e); + return 1; +} + +int MTGCardInstance::bringBlockerToFrontOfOrder(MTGCardInstance * blocker){ + list::iterator it1 = find(blockers.begin(), blockers.end(), blocker); + list::iterator it2 = blockers.begin(); + if (it2 != it1) + { + std::iter_swap(it1,it2); + WEvent* e = NEW WEventCreatureBlockerRank(blocker,*it2,this); + GameObserver::GetInstance()->receiveEvent(e); + //delete(e); + } + return 1; +} + +int MTGCardInstance::removeBlocker(MTGCardInstance * blocker){ + blockers.remove(blocker); + if (!blockers.size()) blocked = false; + return 1; +} + +int MTGCardInstance::addBlocker(MTGCardInstance * blocker){ + blockers.push_back(blocker); + blocked = true; + return 1; +} + +//Returns opponents to this card for this turn. This * should * take into account banding +MTGCardInstance * MTGCardInstance::getNextOpponent(MTGCardInstance * previous){ + GameObserver * game = GameObserver::GetInstance(); + int foundprevious = 0; + if (!previous) foundprevious = 1; + if (attacker && game->currentPlayer->game->inPlay->hasCard(this)){ + MTGInPlay * inPlay = game->opponent()->game->inPlay; + for (int i = 0; i < inPlay->nb_cards; i ++){ + MTGCardInstance * current = inPlay->cards[i]; + if (current == previous){ + foundprevious = 1; + }else if (foundprevious){ + MTGCardInstance * defensersOpponent = current->isDefenser(); + if (defensersOpponent && (defensersOpponent == this || (banding && defensersOpponent->banding == banding))){ + return current; + } + } + } + }else if (defenser && game->opponent()->game->inPlay->hasCard(this)){ + MTGInPlay * inPlay = game->currentPlayer->game->inPlay; + for (int i = 0; i < inPlay->nb_cards; i ++){ + MTGCardInstance * current = inPlay->cards[i]; + if (current == previous){ + foundprevious = 1; + }else if (foundprevious){ + if (defenser == current || (current->banding && defenser->banding == current->banding)){ + return current; + } + } + } + } + return NULL; +} + +int MTGCardInstance::setDefenser(MTGCardInstance * opponent){ + GameObserver * g = GameObserver::GetInstance(); + if (defenser) { + if (g->players[0]->game->battlefield->hasCard(defenser) || + g->players[1]->game->battlefield->hasCard(defenser) ) { + defenser->removeBlocker(this); + } + } + WEvent * e = NULL; + if (defenser != opponent) e = NEW WEventCreatureBlocker(this, defenser, opponent); + defenser = opponent; + if (defenser) defenser->addBlocker(this); + if (e) g->receiveEvent(e); + return 1; +} + +int MTGCardInstance::toggleDefenser(MTGCardInstance * opponent){ + if (canBlock()){ + if (canBlock(opponent)){ + setDefenser(opponent); + return 1; + } + } + return 0; +} + + +int MTGCardInstance::addProtection(CardDescriptor * cd){ + protections[nbprotections] = cd; + nbprotections++; + return nbprotections; +} + +int MTGCardInstance::removeProtection(CardDescriptor * cd, int erase){ + for (int i = 0; i < nbprotections ; i++){ + if (protections[i] == cd){ + if (erase) delete (protections[i]); + protections[i] = protections[nbprotections -1]; + protections[nbprotections -1] = NULL; + nbprotections--; + return 1; + } + } + return 0; +} + +int MTGCardInstance::protectedAgainst(MTGCardInstance * card){ + //Basic protections + for (int i=Constants::PROTECTIONGREEN; i <= Constants::PROTECTIONWHITE; i++){ + if (basicAbilities[i] && card->hasColor( i - Constants::PROTECTIONGREEN + Constants::MTG_COLOR_GREEN )) return 1; + } + + //General protections + for (int i = 0; i < nbprotections ; i++){ + if (protections[i]->match(card)) return 1; + } + return 0; +} + +/* Choose a sound sample to associate to that card */ +JSample * MTGCardInstance::getSample(){ + JSample * js; + + if(sample.size()) + return resources.RetrieveSample(sample); + + for (int i = nb_types-1; i>0; i--){ + string type = Subtypes::subtypesList->find(types[i]); + type = type + ".wav"; + js = resources.RetrieveSample(type); + if (js){ + sample = string(type); + return js; + } + } + + for(map::const_iterator it = basicAbilities.begin(); it != basicAbilities.end(); ++it){ + int i = it->first; + if (!basicAbilities[i]) continue; + string type = Constants::MTGBasicAbilities[i]; + type = type + ".wav"; + js = resources.RetrieveSample(type); + if (js){ + sample = string(type); + return js; + } + } + + string type = Subtypes::subtypesList->find(types[0]); + type = type + ".wav"; + js = resources.RetrieveSample(type); + if (js){ + sample = string(type); + return js; + } + + return NULL; +} + +int MTGCardInstance::stepPower(CombatStep step) +{ + switch (step) + { + case FIRST_STRIKE : + case END_FIRST_STRIKE : + if (has(Constants::FIRSTSTRIKE) || has(Constants::DOUBLESTRIKE)) return MAX(0, power); else return 0; + case DAMAGE : + case END_DAMAGE : + default : + if (has(Constants::FIRSTSTRIKE)) return 0; else return MAX(0, power); + } +} + +std::ostream& MTGCardInstance::toString(std::ostream& out) const +{ + return out << name; +} + +std::ostream& operator<<(std::ostream& out, const MTGCardInstance& c) +{ + return c.toString(out); +} diff --git a/projects/mtg/src/OptionItem.cpp b/projects/mtg/src/OptionItem.cpp index afdf46964..97eba2b9a 100644 --- a/projects/mtg/src/OptionItem.cpp +++ b/projects/mtg/src/OptionItem.cpp @@ -235,7 +235,6 @@ void OptionProfile::populate(){ renderer->BindTexture(mAvatarTex); } - options.reloadProfile(); PlayerData * pdata = NEW PlayerData(app->collection); options[Options::ACTIVE_PROFILE] = temp; @@ -313,7 +312,8 @@ void OptionProfile::cancelSubmode() options[Options::ACTIVE_PROFILE] = selections[initialValue]; value = initialValue; - populate(); + options.reloadProfile(false); + populate(); bCheck = false; } void OptionProfile::acceptSubmode() @@ -323,6 +323,7 @@ void OptionProfile::acceptSubmode() options[Options::ACTIVE_PROFILE] = selections[value]; initialValue = value; + options.reloadProfile(); populate(); bCheck = false; } @@ -762,7 +763,7 @@ void OptionNewProfile::Update(float dt){ if(temp != value){ options[Options::ACTIVE_PROFILE] = value; - options.reloadProfile(); + options.reloadProfile(false); } value = ""; bChanged = true; diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 54f8ae0c6..622ddc1d5 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -24,8 +24,8 @@ void Player::End(){ Player::~Player(){ SAFE_DELETE(manaPool); - SAFE_DELETE(mAvatarTex); - SAFE_DELETE(mAvatar); + resources.Release(mAvatar); + resources.Release(mAvatarTex); } const string Player::getDisplayName() const { @@ -57,9 +57,11 @@ Player * Player::opponent(){ } HumanPlayer::HumanPlayer(MTGPlayerCards * deck, string file, string fileSmall) : Player(deck, file, fileSmall) { - mAvatarTex = JRenderer::GetInstance()->LoadTexture(options.profileFile("avatar.jpg","player",true,true).c_str(), TEX_TYPE_USE_VRAM); + mAvatarTex = resources.RetrieveTexture("avatar.jpg",RETRIEVE_VRAM,TEXTURE_SUB_AVATAR); if (mAvatarTex) - mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); + mAvatar = resources.RetrieveQuad("avatar.jpg",0,0,35,50,"playerAvatar",RETRIEVE_NORMAL,TEXTURE_SUB_AVATAR); + else + mAvatar = NULL; } ManaPool * Player::getManaPool(){ diff --git a/projects/mtg/src/SimpleMenu.cpp b/projects/mtg/src/SimpleMenu.cpp index 4eb0efe72..0b2364981 100644 --- a/projects/mtg/src/SimpleMenu.cpp +++ b/projects/mtg/src/SimpleMenu.cpp @@ -57,7 +57,13 @@ if (NULL == spadeL) spadeL = resources.RetrieveQuad("spade_ul.png", 2, 1, 16, 13 resources.LoadJLBFont("smallface", 7); titleFont = resources.GetJLBFont("smallface"); } - if (NULL == stars) stars = NEW hgeParticleSystem("graphics/stars.psi", resources.GetQuad("stars")); + + if (NULL == stars){ + JQuad * starQuad = resources.GetQuad("stars"); + hgeParticleSystemInfo * psi = resources.RetrievePSI("stars.psi", starQuad); + if(psi) + stars = NEW hgeParticleSystem(psi); + } stars->MoveTo(mX, mY); } diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index 2de1e95e9..355de280e 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -12,10 +12,13 @@ TestSuiteAI::TestSuiteAI(TestSuite * _suite, int playerId):AIPlayer(_suite->buil suite = _suite; timer = 0; humanMode = 0; - mAvatarTex = JRenderer::GetInstance()->LoadTexture("ai/baka/avatar.jpg", TEX_TYPE_USE_VRAM); - if (mAvatarTex){ - mAvatar = NEW JQuad(mAvatarTex, 0, 0, 35, 50); - } + + mAvatarTex = resources.RetrieveTexture("baka.jpg",RETRIEVE_VRAM,TEXTURE_SUB_AVATAR); + if(mAvatarTex) + mAvatar = resources.RetrieveQuad("baka.jpg", 0, 0, 35, 50,"bakaAvatar",RETRIEVE_NORMAL,TEXTURE_SUB_AVATAR); + else + mAvatar = NULL; + } int TestSuite::getMTGId(string cardName){ diff --git a/projects/mtg/src/WCachedResource.cpp b/projects/mtg/src/WCachedResource.cpp new file mode 100644 index 000000000..8519fdfc4 --- /dev/null +++ b/projects/mtg/src/WCachedResource.cpp @@ -0,0 +1,387 @@ +#include "../include/config.h" +#include "../include/utils.h" +#include +#include +#include +#include +#include +#include +#include "../include/GameOptions.h" +#include "../include/WResourceManager.h" + +//WResource +WResource::~WResource(){ + return; +} +WResource::WResource(){ + locks = WRES_UNLOCKED; + lastTime = resources.nowTime(); + loadedMode = 0; +} + +bool WResource::isLocked(){ + return (locks != WRES_UNLOCKED); +} + +bool WResource::isPermanent(){ + return (locks == WRES_PERMANENT); +} + +void WResource::deadbolt(){ + if(locks <= WRES_MAX_LOCK) + locks = WRES_PERMANENT; +} + +void WResource::lock(){ + if(locks < WRES_MAX_LOCK) + locks++; +} + +void WResource::unlock(bool force){ + if(force) + locks = 0; + else if(locks > WRES_UNLOCKED && locks <= WRES_MAX_LOCK) + locks--; +} + +void WResource::hit(){ + lastTime = resources.nowTime(); +} +//WCachedTexture +WCachedTexture::WCachedTexture(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached texture created.\n"); +#endif + texture = NULL; +} + +WCachedTexture::~WCachedTexture(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached texture destroyed.\n"); +#endif + + if(texture) + SAFE_DELETE(texture); + + if(!trackedQuads.size()) + return; + + map::iterator it, nit; + + for(it=trackedQuads.begin();it!=trackedQuads.end();it=nit){ + nit = it; + nit++; + trackedQuads.erase(it); + } + trackedQuads.clear(); +} + +JTexture * WCachedTexture::Actual(){ + return texture; +} + +bool WCachedTexture::ReleaseQuad(JQuad* quad){ +#ifdef DEBUG_CACHE + OutputDebugString("Quad released.\n"); +#endif + + for(map::iterator i = trackedQuads.begin();i!=trackedQuads.end();i++){ + if(i->first == quad ){ + unlock(); + trackedQuads.erase(i); + return true; + } + } + return false; +} + +JQuad * WCachedTexture::GetQuad(float offX, float offY, float width, float height,string resname){ + if(texture == NULL) + return NULL; + + JQuad * jq = NULL; + + map::iterator it; + std::transform(resname.begin(),resname.end(),resname.begin(),::tolower); + + if(width == 0.0f || width > texture->mWidth) + width = texture->mWidth; + if(height == 0.0f || height > texture->mHeight) + height = texture->mHeight; + + + for(it = trackedQuads.begin();it!=trackedQuads.end();it++){ + if(it->second == resname){ + jq = it->first; + } + } + + if(jq == NULL){ + jq = NEW JQuad(texture,offX,offY,width,height); + if(!jq) { + //Probably out of memory. Try again. + resources.Cleanup(); + jq = NEW JQuad(texture,offX,offY,width,height); + } + + if(!jq) + return NULL; //Probably a crash. + + trackedQuads[jq] = resname; + return jq; + }else{ + //Update JQ's values to what we called this with. + jq->SetTextureRect(offX,offY,width,height); + return jq; + } + + return NULL; +} +JQuad * WCachedTexture::GetQuad(string resname){ + map::iterator it; + std::transform(resname.begin(),resname.end(),resname.begin(),::tolower); + for(it = trackedQuads.begin();it!=trackedQuads.end();it++){ + if(it->second == resname){ + return it->first; + } + } + + return NULL; +} +JQuad * WCachedTexture::GetCard(float offX, float offY, float width, float height, string resname){ + JQuad * jq = GetQuad(offX,offY,width,height,resname); + if(jq) + jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2); + + return jq; +} + +unsigned long WCachedTexture::size(){ + if(!texture) + return 0; + return texture->mTexHeight*texture->mTexWidth; +} + +bool WCachedTexture::isGood(){ + if(!texture) + return false; + + return true; +} +void WCachedTexture::Refresh(string filename){ + int error = 0; + JTexture* old = texture; + texture = NULL; + + if(!Attempt(filename,loadedMode, error)) + SAFE_DELETE(texture); + + if(!texture) + texture = old; + else + SAFE_DELETE(old); + + for(map::iterator it=trackedQuads.begin();it!=trackedQuads.end();it++){ + if(it->first) + it->first->mTex = texture; + } +} + +bool WCachedTexture::Attempt(string filename, int submode, int & error){ + int format = TEXTURE_FORMAT; + loadedMode = submode; + string realname; + + //Form correct filename. + if(submode & TEXTURE_SUB_CARD){ + if(submode & TEXTURE_SUB_THUMB){ + for(string::size_type i= 0;i < filename.size();i++){ + if(filename[i] == '\\' || filename[i] == '/'){ + filename.insert(i+1,"thumbnails/"); + break; + } + } + + } + realname = resources.cardFile(filename); + } + else{ + if(submode & TEXTURE_SUB_THUMB) + filename.insert(0,"thumbnails/"); + + if(submode & TEXTURE_SUB_AVATAR) + realname = resources.avatarFile(filename); + else + realname = resources.graphicsFile(filename); + } + + //Apply pixel mode + if(submode & TEXTURE_SUB_5551) + format = GU_PSM_5551; + + //Use Vram? + if(submode & TEXTURE_SUB_VRAM){ + texture = JRenderer::GetInstance()->LoadTexture(realname.c_str(),TEX_TYPE_USE_VRAM,format); + } + else + texture = JRenderer::GetInstance()->LoadTexture(realname.c_str(),TEX_TYPE_NORMAL,format); + + //Failure. + if(!texture){ + if(!fileExists(realname.c_str())) + error = CACHE_ERROR_404; + return false; + } + + //Failure of a different sort. + if(texture->mTexId == -1){ + SAFE_DELETE(texture); + error = CACHE_ERROR_BAD; + return false; + } + + error = CACHE_ERROR_NONE; + return true; +} + +void WCachedTexture::Nullify(){ + if(texture) + texture = NULL; +} + +//WCachedSample +void WCachedSample::Nullify(){ + if(sample){ + sample = NULL; + } +} + +WCachedSample::WCachedSample(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached sample created.\n"); +#endif + sample = NULL; +} + +WCachedSample::~WCachedSample(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached sample destroyed.\n"); +#endif + SAFE_DELETE(sample); +} + +JSample * WCachedSample::Actual(){ + return sample; +} + +unsigned long WCachedSample::size(){ + if(!sample || !sample->mSample) + return 0; + +#if defined WIN32 || defined LINUX + return FSOUND_Sample_GetLength(sample->mSample); +#else + return sample->mSample->fileSize; +#endif +} + +bool WCachedSample::isGood(){ + if(!sample || !sample->mSample) + return false; + + return true; +} +void WCachedSample::Refresh(string filename){ + return; +} + +bool WCachedSample::Attempt(string filename, int submode, int & error){ + loadedMode = submode; + + sample = JSoundSystem::GetInstance()->LoadSample(resources.sfxFile(filename).c_str()); + + if(!isGood()){ + SAFE_DELETE(sample); + if(!fileExists(filename.c_str())) + error = CACHE_ERROR_404; + else + error = CACHE_ERROR_BAD; + + return false; + } + + return true; +} + +//WCachedParticles + +bool WCachedParticles::isGood(){ + if(!particles) + return false; + return true; +} +unsigned long WCachedParticles::size(){ + if(!particles) + return 0; //Sizeof(pointer) + + return sizeof(hgeParticleSystemInfo); +} + +//Only effects future particle systems, of course. +void WCachedParticles::Refresh(string filename){ + hgeParticleSystemInfo * old = particles; + + int error = 0; + Attempt(filename,loadedMode,error); + + if(isGood()) + SAFE_DELETE(old); + else{ + SAFE_DELETE(particles); + particles = old; + } + + return; +} + +bool WCachedParticles::Attempt(string filename, int submode, int & error){ + + JFileSystem* fileSys = JFileSystem::GetInstance(); + + if(!fileSys->OpenFile(resources.graphicsFile(filename))){ + error = CACHE_ERROR_404; + return false; + } + + SAFE_DELETE(particles); + + particles = NEW hgeParticleSystemInfo; + fileSys->ReadFile(particles, sizeof(hgeParticleSystemInfo)); + fileSys->CloseFile(); + + particles->sprite=NULL; + error = CACHE_ERROR_NONE; + return true; +} + +hgeParticleSystemInfo * WCachedParticles::Actual(){ + return particles; +} + +WCachedParticles::WCachedParticles(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached particles created.\n"); +#endif + particles = NULL; +} +WCachedParticles::~WCachedParticles(){ +#ifdef DEBUG_CACHE + OutputDebugString("Cached particles destroyed.\n"); +#endif + SAFE_DELETE(particles); +} + +void WCachedParticles::Nullify(){ + if(particles) + particles = NULL; +} diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 1563efcd6..f30cb9555 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -9,169 +9,108 @@ #include #include "../include/WResourceManager.h" - WResourceManager resources; -WCachedResource::WCachedResource(){ - locks = 0; - lastTime = resources.nowTime(); +unsigned int vTime = 0; + +//WResourceManager +void WResourceManager::DebugRender(){ + JRenderer* renderer = JRenderer::GetInstance(); + JLBFont * font = resources.GetJLBFont(Constants::MAIN_FONT); + + if(!font || !renderer) + return; + + font->SetScale(DEFAULT_MAIN_FONT_SCALE); + renderer->FillRect(0,0,SCREEN_WIDTH,20,ARGB(128,155,0,0)); +#ifdef DEBUG_CACHE + if(debugMessage.size()) + renderer->FillRect(0,SCREEN_HEIGHT-30,SCREEN_WIDTH,40,ARGB(128,155,0,0)); + else +#endif + renderer->FillRect(0,SCREEN_HEIGHT-20,SCREEN_WIDTH,40,ARGB(128,155,0,0)); + char buf[512]; + + + unsigned long man = 0; + unsigned int misses = 0; + + if(textureWCache.cacheItems < textureWCache.cache.size()) + misses = textureWCache.cache.size()-textureWCache.cacheItems; + + if(textureWCache.totalSize > textureWCache.cacheSize) + man = textureWCache.totalSize - textureWCache.cacheSize; + + sprintf(buf,"Textures %u+%u (of %u) items (%u misses), Pixels: %lu+%lu (of %lu)", + textureWCache.cacheItems, textureWCache.managed.size(),textureWCache.maxCached, + misses,textureWCache.cacheSize,man,textureWCache.maxCacheSize); + font->DrawString(buf, 10,5); + + + + sprintf(buf,"Total Size: %lu (%lu cached, %lu managed)",Size(),SizeCached(),SizeManaged()); + font->DrawString(buf, SCREEN_WIDTH-10,SCREEN_HEIGHT-15,JGETEXT_RIGHT); + +#ifdef DEBUG_CACHE + if(debugMessage.size()) + font->DrawString(debugMessage.c_str(), SCREEN_WIDTH-10,SCREEN_HEIGHT-25,JGETEXT_RIGHT); +#endif } -bool WCachedResource::isLocked(){ - return (locks != 0); +unsigned long WResourceManager::Size(){ + unsigned long res = 0; + res += textureWCache.totalSize; + res += sampleWCache.totalSize; + res += psiWCache.totalSize; + return res; } -void WCachedResource::lock(){ - if(locks < 255) - locks++; +unsigned long WResourceManager::SizeCached(){ + unsigned long res = 0; + res += textureWCache.cacheSize; + res += sampleWCache.cacheSize; + res += psiWCache.cacheSize; + return res; } -void WCachedResource::unlock(bool force){ - if(force) - locks = 0; - else if(locks > 0) - locks--; +unsigned long WResourceManager::SizeManaged(){ + unsigned long res = 0; + if(textureWCache.totalSize > textureWCache.cacheSize) + res += textureWCache.totalSize - textureWCache.cacheSize; + + if(sampleWCache.totalSize > sampleWCache.cacheSize) + res += sampleWCache.totalSize - sampleWCache.cacheSize; + + if(psiWCache.totalSize > psiWCache.cacheSize) + res += psiWCache.totalSize - psiWCache.cacheSize; + + return res; } - -void WCachedResource::hit(){ - lastTime = resources.nowTime(); +unsigned int WResourceManager::Count(){ + unsigned int count = 0; + count += textureWCache.cacheItems; + count += textureWCache.managed.size(); + count += sampleWCache.cacheItems; + count += sampleWCache.managed.size(); + count += psiWCache.cacheItems; + count += psiWCache.managed.size(); + return count; } - -WCachedTexture::WCachedTexture(){ - texture = NULL; - bVRAM = false; +unsigned int WResourceManager::CountCached(){ + unsigned int count = 0; + count += textureWCache.cacheItems; + count += sampleWCache.cacheItems; + count += psiWCache.cacheItems; + return count; } - -WCachedTexture::~WCachedTexture(){ - SAFE_DELETE(texture); - for(vector::iterator i = trackedQuads.begin();i!=trackedQuads.end();i++) - SAFE_DELETE((*i)); +unsigned int WResourceManager::CountManaged(){ + unsigned int count = 0; + count += textureWCache.managed.size(); + count += sampleWCache.managed.size(); + count += psiWCache.managed.size(); + return count; } -JTexture * WCachedTexture::GetTexture(){ - return texture; -} - -bool WCachedTexture::ReleaseQuad(JQuad* quad){ - for(vector::iterator i = trackedQuads.begin();i!=trackedQuads.end();i++){ - if((*i) == quad){ - SAFE_DELETE(quad); - trackedQuads.erase(i); - return true; - } - } - return false; -} - -JQuad * WCachedTexture::GetQuad(float offX, float offY, float width, float height){ - if(texture == NULL) - return NULL; - - if(width == 0.0f) - width = texture->mWidth; - if(height == 0.0f) - height = texture->mHeight; - - vector::iterator it; - for(it = trackedQuads.begin();it!=trackedQuads.end();it++) - if((*it)->mHeight == height && (*it)->mWidth == width - && (*it)->mX == offX && (*it)->mY == offY) - return (*it); - - JQuad * jq = NEW JQuad(texture,offX,offY,width,height); - trackedQuads.push_back(jq); - return jq; -} - -JQuad * WCachedTexture::GetCard(float offX, float offY, float width, float height){ - if(texture == NULL) - return NULL; - - if(width == 0.0f) - width = texture->mWidth; - if(height == 0.0f) - height = texture->mHeight; - - vector::iterator it; - for(it = trackedQuads.begin();it!=trackedQuads.end();it++) - if((*it)->mHeight == height && (*it)->mWidth == width - && (*it)->mX == offX && (*it)->mY == offY) - return (*it); - - JQuad * jq = NEW JQuad(texture,offX,offY,width,height); - jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2); - trackedQuads.push_back(jq); - return jq; -} - -WCachedSample::WCachedSample(){ - sample = NULL; -} - -WCachedSample::~WCachedSample(){ - SAFE_DELETE(sample); -} - -JSample * WCachedSample::GetSample(){ - return sample; -} -void WResourceManager::ClearMisses(){ - map::iterator itTex, nextTex; - map::iterator itSfx, nextSfx; - - for(itTex = textureCache.begin(); itTex != textureCache.end();itTex=nextTex){ - nextTex = itTex; - nextTex++; - - if(itTex->second == NULL){ - textureCache.erase(itTex); - } - } - for(itSfx = sampleCache.begin(); itSfx != sampleCache.end();itSfx=nextSfx){ - nextSfx = itSfx; - nextSfx++; - - if(itSfx->second == NULL){ - sampleCache.erase(itSfx); - } - } -} - -void WResourceManager::ClearUnlocked(){ - map::iterator itTex, nextTex; - map::iterator itSfx, nextSfx; - - for(itTex = textureCache.begin(); itTex != textureCache.end();itTex=nextTex){ - nextTex = itTex; - nextTex++; - - if(!itTex->second || (itTex->second && !itTex->second->isLocked())){ - textureCache.erase(itTex); - } - } - for(itSfx = sampleCache.begin(); itSfx != sampleCache.end();itSfx=nextSfx){ - nextSfx = itSfx; - nextSfx++; - - if(!itSfx->second || (itSfx->second && !itSfx->second->isLocked())){ - sampleCache.erase(itSfx); - } - } -} - -bool WResourceManager::cleanup(){ - long maxSize = options[Options::CACHESIZE].number * 100000; - if (!maxSize) maxSize = CACHE_SIZE_PIXELS; - - ClearMisses(); - while (textureCache.size() > MAX_CACHE_OBJECTS - 1 || totalsize > maxSize){ - int result = RemoveOldestTexture(); - if (!result) return false; - } - return true; -} - - unsigned int WResourceManager::nowTime(){ if(lastTime == 65535) FlattenTimes(); @@ -179,240 +118,19 @@ unsigned int WResourceManager::nowTime(){ return ++lastTime; } -void WResourceManager::ClearSamples(){ - map::iterator next; - for(map::iterator it = sampleCache.begin();it!=sampleCache.end();it=next){ - next = it; - next++; - - if(it->second && !it->second->isLocked()) - SAFE_DELETE(it->second); - } - sampleCache.clear(); -} - -WCachedSample * WResourceManager::getCachedSample(string filename, bool makenew){ - map::iterator miss = sampleCache.find(filename); - if(miss != sampleCache.end() && miss->second == NULL) - return NULL; //We've found a cache miss, so return null. - - WCachedSample * csample = sampleCache[filename]; - - //Failed to cache it! - if(!csample && makenew){ - //Space in cache, make new sample - if(cleanup()){ - csample = NEW WCachedSample(); - string sfile = sfxFile(filename); - if(sfile != ""){ - csample->sample = JSoundSystem::GetInstance()->LoadSample(sfile.c_str()); - //Potential cache overflow- clean the cache - if(!csample->sample && fileExists(sfile.c_str())){ - ClearSamples(); - csample->sample = JSoundSystem::GetInstance()->LoadSample(sfile.c_str()); - } - } - else - csample->sample = NULL; - - //Failed. Leave the cache miss alone. - if(!csample->sample){ - SAFE_DELETE(csample); - return NULL; - } - //Success! - csample->hit(); - sampleCache[filename] = csample; - } - else - return NULL; //Error. - } - - return csample; -} - -WCachedTexture * WResourceManager::getCachedTexture(string filename, bool makenew, int mode, int format){ - WCachedTexture * ctex = textureCache[filename]; - //Failed to cache it! - if(!ctex && makenew){ - //Space in cache, make new texture - if(cleanup()){ - ctex = NEW WCachedTexture(); - //Within limits, keep removing items from cache until we can create this - ctex->texture = attemptTexture(graphicsFile(filename)); - - if(!ctex->texture){ - for(map::iterator it=textureCache.begin();it!=textureCache.end();it++) - if(it->first == filename){ - textureCache.erase(it); - break; - } - SAFE_DELETE(ctex); - return NULL; - } - totalsize+=ctex->texture->mTexHeight *ctex->texture->mTexWidth; - char buf[512]; - sprintf(buf,"Cache size: %ld\n",totalsize); - OutputDebugString(buf); - ctex->hit(); - textureCache[filename] = ctex; - } - else - return NULL; //Error. - } - - return ctex; -} - -JTexture * WResourceManager::attemptTexture(string filename, int mode, int format){ - JTexture * result = JRenderer::GetInstance()->LoadTexture(filename.c_str(),mode,format); - - if(result == NULL){ - if(!fileExists(filename.c_str())) - return NULL; - - for(int attempt=0;attempt<10;attempt++){ - if(!RemoveOldestTexture()) - break; - result = JRenderer::GetInstance()->LoadTexture(filename.c_str(),mode,format); - if(result) - break; - } - - //Still no result, so clear cache entirely, then try again. - if(!result){ - ClearUnlocked(); - result = JRenderer::GetInstance()->LoadTexture(filename.c_str(),mode,format); - } - } - - return result; -} - - -WCachedTexture * WResourceManager:: getCachedCard(MTGCard * card, int type, bool makenew){ - string filename = card->getImageName(); - if(type == CACHE_THUMB) - filename = "thumbnails/"+filename; - - map::iterator miss = textureCache.find(filename); - if(miss != textureCache.end() && miss->second == NULL) - return NULL; //We've found a cache miss, so return null. - - if(miss == textureCache.end() && !makenew) - return NULL; //cache empty and don't want to create - - WCachedTexture * ctex = textureCache[filename]; - //Failed to find it in cache! - if(!ctex && makenew){ - if(cleanup()){ - //Space in cache, make new texture - ctex = NEW WCachedTexture(); - string cfile = cardFile(filename,card->getSetName()); - if(cfile != ""){ - //Within limits, keep removing items from cache until we can create this - ctex->texture = attemptTexture(cfile); - } - else - ctex->texture = NULL; - - //Couldn't create texture, so fail. Leave failure in cache, so we don't try again later. - if(!ctex->texture){ - SAFE_DELETE(ctex); - return NULL; - } - totalsize+=ctex->texture->mTexHeight *ctex->texture->mTexWidth; - char buf[512]; - sprintf(buf,"Cache size: %ld\n",totalsize); - OutputDebugString(buf); - ctex->hit(); - textureCache[filename] = ctex; - } - else - return NULL; //Error. - } - - return ctex; -} - void WResourceManager::FlattenTimes(){ - unsigned int youngest = 65535; - unsigned int oldest = 0; + unsigned int t; + lastTime = sampleWCache.Flatten(); - for (map::iterator it = textureCache.begin(); it != textureCache.end(); ++it){ - if(!it->second) continue; - if(it->second->lastTime < youngest) youngest = it->second->lastTime; - if(it->second->lastTime > oldest) oldest = it->second->lastTime; - } - for (map::iterator it = sampleCache.begin(); it != sampleCache.end(); ++it){ - if(!it->second) continue; - if(it->second->lastTime < youngest) youngest = it->second->lastTime; - if(it->second->lastTime > oldest) oldest = it->second->lastTime; - } + t = textureWCache.Flatten(); + if(t > lastTime) + lastTime = t; - for (map::iterator it = sampleCache.begin(); it != sampleCache.end(); ++it){ - if(!it->second) continue; - it->second->lastTime -= youngest; - } - for (map::iterator it = textureCache.begin(); it != textureCache.end(); ++it){ - if(!it->second) continue; - it->second->lastTime -= youngest; - } - - lastTime = oldest; + t = psiWCache.Flatten(); + if(t > lastTime) + lastTime = t; } -bool WResourceManager::RemoveOldestTexture(){ - map::iterator oldest; - oldest = textureCache.end(); - for(map::iterator it = textureCache.begin();it!=textureCache.end();it++){ - if(it->second && !it->second->isLocked() - && (oldest == textureCache.end() || it->second->lastTime < oldest->second->lastTime)) - oldest = it; - } - - if(oldest != textureCache.end()){ - if(oldest->second){ - if(!oldest->second->isLocked() ){ - if(oldest->second->texture) - totalsize-=oldest->second->texture->mTexHeight * oldest->second->texture->mTexWidth; - SAFE_DELETE(oldest->second); - } - else - return false; - } - - textureCache.erase(oldest); - return true; - } - - return false; -} - -bool WResourceManager::RemoveOldestSample(){ - map::iterator it, saved; - saved = sampleCache.end(); - - for(it = sampleCache.begin();it!=sampleCache.end();it++){ - if(it->second && !it->second->isLocked() - && (saved == sampleCache.end() || it->second->lastTime < saved->second->lastTime)) - saved = it; - } - - if(saved != sampleCache.end()){ - if(saved->second){ - if(!saved->second->isLocked()){ - SAFE_DELETE(saved->second); - } - else - return false; - } - - sampleCache.erase(saved); - return true; - } - return false; -} WResourceManager::WResourceManager(){ #ifdef WIN32 @@ -420,301 +138,328 @@ WResourceManager::WResourceManager(){ sprintf(buf, " Init WResourceManager : %p\n", this); OutputDebugString(buf); #endif - +#ifdef DEBUG_CACHE + menuCached = 0; +#endif mTextureList.clear(); - mTextureList.reserve(16); + mTextureList.reserve(0); mTextureMap.clear(); mQuadList.clear(); - mQuadList.reserve(128); + mQuadList.reserve(0); mQuadMap.clear(); mFontList.clear(); mFontList.reserve(4); mFontMap.clear(); - mMusicList.clear(); - mMusicList.reserve(4); - mMusicMap.clear(); - - mSampleList.clear(); - mSampleList.reserve(8); - mSampleMap.clear(); - - nb_textures = 0; - totalsize = 0; + psiWCache.Resize(SMALL_CACHE_LIMIT,6); //Plenty of room for mana symbols, or whatever. + sampleWCache.Resize(SMALL_CACHE_LIMIT,0); //This guy only exists so we can track misses. + textureWCache.Resize(LARGE_CACHE_LIMIT,MAX_CACHE_OBJECTS); lastTime = 0; } WResourceManager::~WResourceManager(){ - LOG("==Destroying WResourceManager=="); - for (map::iterator it = textureCache.begin(); it != textureCache.end(); ++it){ - delete it->second; - } - for (map::iterator it = sampleCache.begin(); it != sampleCache.end(); ++it){ - delete it->second; - } - - textureCache.clear(); - sampleCache.clear(); - RemoveAll(); LOG("==Successfully Destroyed WResourceManager=="); - } -JQuad * WResourceManager::RetrieveCard(MTGCard * card, int type, int style){ +JQuad * WResourceManager::RetrieveCard(MTGCard * card, int style, int submode){ //Cards are never, ever resource managed, so just check cache. - WCachedTexture * tc; - if(style == RETRIEVE_EXISTING) - tc = getCachedCard(card,type,false); - else - tc = getCachedCard(card,type,true); - - //Perform lock or unlock on entry. - if(tc != NULL){ - if(style == RETRIEVE_LOCK) tc->lock(); - else if(style == RETRIEVE_UNLOCK) tc->unlock(); + + submode = submode | TEXTURE_SUB_CARD; + + string filename = card->getSetName(); + filename += "/"; + filename += card->getImageName(); + WCachedTexture * res = NULL; + + //Aliases. + if(style == RETRIEVE_VRAM){ + submode = submode | TEXTURE_SUB_VRAM; + style = RETRIEVE_LOCK; + } + else if(style == RETRIEVE_THUMB){ + submode = submode | TEXTURE_SUB_THUMB; + style = RETRIEVE_NORMAL; } - //Texture exists! Get quad. - if(tc && tc->texture != NULL){ - tc->hit(); - return tc->GetCard(); + res = textureWCache.Retrieve(filename,style,submode|TEXTURE_SUB_5551); //Force RGBA5650. JPG doesn't support transparency anyways. + + if(res) //A non-null result will always be good. + return res->GetCard(); + + return NULL; +} + +int WResourceManager::CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height){ + if(!quadName.size() || !textureName.size()) + return INVALID_ID; + + string resname = quadName; + std::transform(resname.begin(),resname.end(),resname.begin(),::tolower); + + vector::iterator it; + int pos = 0; + for(it = managedQuads.begin();it!=managedQuads.end();it++,pos++){ + if(it->resname == resname) + return pos; + } + + WCachedTexture * jtex = textureWCache.Retrieve(textureName,RETRIEVE_MANAGE); + + //Somehow, jtex wasn't promoted. + if(RETRIEVE_MANAGE && jtex && !jtex->isPermanent()) + return INVALID_ID; + + if(jtex){ + JQuad * jq = jtex->GetQuad(x,y,width,height,quadName); + + if(jq){ + WManagedQuad mq; + mq.resname = resname; + mq.texture = jtex; + managedQuads.push_back(mq); + } + + return (int) (managedQuads.size() - 1); + } + + return INVALID_ID; +} + +JQuad * WResourceManager::GetQuad(const string &quadName){ + string lookup = quadName; + std::transform(lookup.begin(),lookup.end(),lookup.begin(),::tolower); + + for(vector::iterator it=managedQuads.begin();it!=managedQuads.end();it++){ + if(it->resname == lookup) + return it->texture->GetQuad(lookup); } return NULL; } -JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY, float width, float height, string resname, int style){ +JQuad * WResourceManager::GetQuad(int id){ + if(id < 0 || id >= (int) managedQuads.size()) + return NULL; - for(vector::iterator it=mTextureMissing.begin();it!=mTextureMissing.end();it++){ - if((*it) == filename) - return NULL; - } + WCachedTexture * jtex = managedQuads[id].texture; + if(!jtex) + return NULL; - if(resname == "") + return jtex->GetQuad(managedQuads[id].resname); +} + +JQuad * WResourceManager::RetrieveTempQuad(string filename){ + return RetrieveQuad(filename,0,0,0,0,"",RETRIEVE_NORMAL); +} + +JQuad * WResourceManager::RetrieveQuad(string filename, float offX, float offY, float width, float height, string resname, int style, int submode){ + JQuad * jq = NULL; + + //Lookup managed resources, but only with a real resname. + if(resname.size() && (style == RETRIEVE_MANAGE || style == RETRIEVE_RESOURCE)){ + jq = GetQuad(resname); + if(jq || style == RETRIEVE_RESOURCE) + return jq; + } + + //Resname defaults to filename. + if(!resname.size()) resname = filename; - //Check our managed resources. - JQuad * retval = GetQuad(resname); - if(retval != NULL || style == RETRIEVE_RESOURCE) - return retval; + //No quad, but we have a managed texture for this! + WCachedTexture * jtex = textureWCache.Retrieve(filename,style,submode); - //We have a managed resource named this! - JTexture * jtex = GetTexture(filename); + //Somehow, jtex wasn't promoted. + if(style == RETRIEVE_MANAGE && jtex && !jtex->isPermanent()) + return NULL; + + //Make this quad, overwriting any similarly resname'd quads. if(jtex){ - //Make this quad, overwriting any similarly resname'd quads. - CreateQuad(resname,filename,offX,offY,width,height); - return GetQuad(resname); - } - - //If we don't have an existing texture, check cache. - WCachedTexture * tc = NULL; - if(style != RETRIEVE_MANAGE){ - if(style == RETRIEVE_EXISTING) - tc = getCachedTexture(filename,false); - else if(style == RETRIEVE_VRAM) - tc = getCachedTexture(filename,true,TEX_TYPE_USE_VRAM); - else - tc = getCachedTexture(filename); - } - - //Quads never mess with locks. Ever. - if(style == RETRIEVE_MANAGE){ - //Remove cache hit from cache - map::iterator it = textureCache.end(); - tc = textureCache[filename]; - for(it = textureCache.begin();it!=textureCache.end();it++){ - if(it->first == filename) - break; + jq = jtex->GetQuad(offX,offY,width,height,resname); + + if(style == RETRIEVE_MANAGE && resname != ""){ + WManagedQuad mq; + mq.resname = resname; + mq.texture = jtex; + managedQuads.push_back(mq); } - - if(it != textureCache.end()){ - SAFE_DELETE(it->second); - textureCache.erase(it); - } - //Pop texture & quad into resource manager - CreateQuad(resname,filename,offX,offY,width,height); - return GetQuad(resname); + + return jq; } - //Texture exists! Get quad. - if(tc && tc->texture != NULL){ - if(style == RETRIEVE_VRAM) - tc->bVRAM = true; - tc->hit(); - return tc->GetQuad(offX,offY,width,height); - } - - //Texture doesn't exist, so no quad. Record miss. - mTextureMissing.push_back(filename); + //Texture doesn't exist, so no quad. return NULL; } void WResourceManager::Release(JTexture * tex){ - if(tex == NULL) + if(!tex) return; - map::iterator it; - for(it = textureCache.begin();it!=textureCache.end();it++){ - if(it->second && it->second->texture == tex) - break; - } - if(it != textureCache.end()){ - it->second->unlock(); - if(!it->second->isLocked()){ - if(it->second->texture) - totalsize-=it->second->texture->mTexHeight * it->second->texture->mTexWidth; - SAFE_DELETE(it->second); - textureCache.erase(it); - } - } + textureWCache.Release(tex); } void WResourceManager::Release(JQuad * quad){ - map::iterator it; - if(quad == NULL) + if(!quad) return; - for(it = textureCache.begin();it!=textureCache.end();it++){ + map::iterator it; + for(it = textureWCache.cache.begin();it!=textureWCache.cache.end();it++){ if(it->second && it->second->ReleaseQuad(quad)) break; } - if(it != textureCache.end()){ - if(!it->second->isLocked()){ - SAFE_DELETE(it->second); - textureCache.erase(it); - } - } + if(it != textureWCache.cache.end() && it->second) + textureWCache.RemoveItem(it->second,false); //won't remove locked. } +void WResourceManager::ClearMisses(){ + textureWCache.ClearMisses(); + sampleWCache.ClearMisses(); + psiWCache.ClearMisses(); +} + +void WResourceManager::ClearUnlocked(){ + textureWCache.ClearUnlocked(); + sampleWCache.ClearUnlocked(); + psiWCache.ClearUnlocked(); +} + +bool WResourceManager::Cleanup(){ + int check = 0; + + if(textureWCache.Cleanup()) + check++; + if(sampleWCache.Cleanup()) + check++; + if(psiWCache.Cleanup()) + check++; + + return (check > 0); +} void WResourceManager::Release(JSample * sample){ - if(sample == NULL) + if(!sample) return; - map::iterator it; - for(it = sampleCache.begin();it!=sampleCache.end();it++){ - if(it->second && it->second->sample == sample) - break; - } - - if(it != sampleCache.end()){ - it->second->unlock(); - if(!it->second->isLocked()){ - SAFE_DELETE(it->second); - sampleCache.erase(it); - } - } + sampleWCache.Release(sample); } -JTexture * WResourceManager::RetrieveTexture(string filename, int style){ -//Check our resources. - JTexture * retval = GetTexture(filename); - if(retval != NULL || style == RETRIEVE_RESOURCE) - return retval; +JTexture * WResourceManager::RetrieveTexture(string filename, int style, int submode){ + WCachedTexture * res = NULL; - //Check cache. - WCachedTexture * tc = NULL; - if(style != RETRIEVE_MANAGE){ - if(style == RETRIEVE_EXISTING) - tc = getCachedTexture(filename,false); - else if(style == RETRIEVE_VRAM) - tc = getCachedTexture(filename,true,TEX_TYPE_USE_VRAM); - else - tc = getCachedTexture(filename); + //Aliases. + if(style == RETRIEVE_VRAM){ + submode = submode | TEXTURE_SUB_VRAM; + style = RETRIEVE_LOCK; + } + else if(style == RETRIEVE_THUMB){ + submode = submode | TEXTURE_SUB_THUMB; + style = RETRIEVE_NORMAL; } - if(style == RETRIEVE_MANAGE){ - for(vector::iterator it = mTextureMissing.begin();it!=mTextureMissing.end();it++){ - if((*it) == filename) - return NULL; + res = textureWCache.Retrieve(filename,style,submode); + + if(res){ //a non-null result will always be good. + JTexture * t = res->Actual(); + JRenderer::GetInstance()->BindTexture(t); + return t; + } +#ifdef DEBUG_CACHE + else{ + switch(textureWCache.mError){ + case CACHE_ERROR_NONE: + debugMessage = "Not in cache: "; + break; + case CACHE_ERROR_404: + debugMessage = "File not found: "; + break; + case CACHE_ERROR_BAD: + debugMessage = "Cache bad: "; + break; + case CACHE_ERROR_NOT_MANAGED: + debugMessage = "Resource not managed: "; + break; + case CACHE_ERROR_LOST: + debugMessage = "Resource went bad, potential memory leak: "; + break; + default: + debugMessage = "Unspecified error: "; } + debugMessage += filename; } +#endif + + return NULL; +} + +int WResourceManager::CreateTexture(const string &textureName) { + JTexture * jtex = RetrieveTexture(textureName,RETRIEVE_MANAGE); - //Perform lock or unlock on entry. - if(style != RETRIEVE_MANAGE && tc){ - if(style == RETRIEVE_LOCK || style == RETRIEVE_VRAM) tc->lock(); - else if(style == RETRIEVE_UNLOCK) tc->unlock(); - } - else if(style == RETRIEVE_MANAGE){ - //Remove cache hit from cache - tc = textureCache[filename]; - map::iterator it = textureCache.end(); - for(it = textureCache.begin();it!=textureCache.end();it++){ - if(it->first == filename) - break; - } + if(jtex) + return (int) jtex->mTexId; //Because it's unsigned on windows/linux. - if(it != textureCache.end()){ - SAFE_DELETE(it->second); - textureCache.erase(it); - } - //Pop texture into resource manager - int val = CreateTexture(filename); - if(val == INVALID_ID){ - mTextureMissing.push_back(filename); - return NULL;//file not found - } - - return GetTexture(val); - } - - //Texture exists! Get it. - if(tc && tc->texture != NULL){ - tc->hit(); - return tc->GetTexture(); - } - - return retval; + return INVALID_ID; } -JSample * WResourceManager::RetrieveSample(string filename, int style){ -//Check our resources. - JSample * retval = GetSample(filename); - if(retval != NULL || style == RETRIEVE_RESOURCE) - return retval; +JTexture* WResourceManager::GetTexture(const string &textureName){ + JTexture * jtex = RetrieveTexture(textureName,RETRIEVE_RESOURCE); + return jtex; +} - //Check cache. - WCachedSample * tc = NULL; +JTexture* WResourceManager::GetTexture(int id){ + map::iterator it; + JTexture *jtex = NULL; - if(style != RETRIEVE_MANAGE){ - if(style == RETRIEVE_EXISTING) - tc = getCachedSample(filename,false); - else - tc = getCachedSample(filename); - } + if(id == INVALID_ID) + return NULL; - //Perform lock or unlock on entry. - if(style != RETRIEVE_MANAGE && tc){ - if(style == RETRIEVE_LOCK || style == RETRIEVE_VRAM) tc->lock(); - else if(style == RETRIEVE_UNLOCK) tc->unlock(); - } - else if(style == RETRIEVE_MANAGE){ - //Remove cache hit from cache - tc = sampleCache[filename]; - map::iterator it; - for(it = sampleCache.begin();it!=sampleCache.end();it++){ - if(it->first == filename) - break; - } - - if(it != sampleCache.end()){ - SAFE_DELETE(it->second); - sampleCache.erase(it); + for(it = textureWCache.managed.begin();it!= textureWCache.managed.end(); it++){ + if(it->second){ + jtex = it->second->Actual(); + if(jtex->mTexId == id) + return jtex; } - //Pop sample into resource manager - LoadSample(filename); - return GetSample(filename); } + return jtex; +} + +hgeParticleSystemInfo * WResourceManager::RetrievePSI(string filename, JQuad * texture, int style, int submode){ + + if(!texture) + return NULL; + + WCachedParticles * res = psiWCache.Retrieve(filename,style,submode); + + if(res) //A non-null result will always be good. + { + hgeParticleSystemInfo * i = res->Actual(); + i->sprite = texture; + return i; + } + + return NULL; +} + +JSample * WResourceManager::RetrieveSample(string filename, int style, int submode){ + //Check cache. This just tracks misses. + WCachedSample * tc = NULL; + tc = sampleWCache.Get(filename,submode); + //Sample exists! Get it. - if(tc && tc->sample != NULL){ - tc->hit(); - return tc->GetSample(); + if(tc && tc->isGood()){ + JSample * js = tc->Actual(); + + //Samples are freed when played, so remove this. Because maxCached is 0, this will Nullify() first. + sampleWCache.RemoveItem(tc,true); + //Adjust sizes accordingly. + sampleWCache.cacheSize = 0; + sampleWCache.totalSize = 0; + return js; } - return retval; + return NULL; } string WResourceManager::graphicsFile(const string filename, const string specific){ @@ -762,21 +507,74 @@ string WResourceManager::graphicsFile(const string filename, const string specif return graphdir; } -string WResourceManager::cardFile(const string filename, const string setname, const string specific){ + +string WResourceManager::avatarFile(const string filename, const string specific){ + char buf[512]; + + //Check the specific location, if any. + if(specific != ""){ + sprintf(buf,"%s/%s",specific.c_str(),filename.c_str()); + if(fileOK(buf,true)) + return buf; + } + + //Check the profile folder. + string profile = options[Options::ACTIVE_PROFILE].str; + std::transform(profile.begin(), profile.end(), profile.begin(), ::tolower); + if(profile != "" && profile != "default"){ + sprintf(buf,"profiles/%s/%s",profile.c_str(),filename.c_str()); + if(fileOK(buf,true)) + return buf; + }else{ + sprintf(buf,"player/%s",filename.c_str()); + if(fileOK(buf,true)) + return buf; + } + + //Check the theme folder. + string theme = options[Options::ACTIVE_THEME].str; + std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower); + + if(theme != "" && theme != "default"){ + sprintf(buf,"themes/%s/%s",theme.c_str(),filename.c_str()); + if(fileOK(buf,true)) + return buf; + } + + //Failure. Check mode graphics + string mode = options[Options::ACTIVE_MODE].str; + std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower); + + if(mode != "" && mode != "defualt"){ + sprintf(buf,"modes/%s/graphics/%s",mode.c_str(),filename.c_str()); + if(fileOK(buf,true)) + return buf; + } + + //Failure. Check Baka + sprintf(buf,"ai/baka/avatars/%s",filename.c_str()); + if(fileOK(buf,true)) + return buf; + + //Failure. Check graphics + char graphdir[512]; + sprintf(graphdir,"graphics/%s",filename.c_str()); + if(fileOK(graphdir,true)) + return graphdir; + + //Complete abject failure. Probably a crash... + return graphdir; +} + +string WResourceManager::cardFile(const string filename, const string specific){ JFileSystem* fs = JFileSystem::GetInstance(); char buf[512]; - char sets[512]; fs->DetachZipFile(); - if(setname != "") - sprintf(sets,"sets/%s",setname.c_str()); - else - sprintf(sets,"sets"); - //Check the specific location, if any. if(specific != ""){ - sprintf(buf,"%s/%s/%s",specific.c_str(),sets,filename.c_str()); + sprintf(buf,"%s/sets/%s",specific.c_str(),filename.c_str()); if(fileOK(buf,true)) return buf; } @@ -786,7 +584,7 @@ string WResourceManager::cardFile(const string filename, const string setname, c std::transform(theme.begin(), theme.end(), theme.begin(), ::tolower); if(theme != "" && theme != "default"){ - sprintf(buf,"themes/%s/%s/%s",theme.c_str(),sets,filename.c_str()); + sprintf(buf,"themes/%s/sets/%s",theme.c_str(),filename.c_str()); if(fileOK(buf,true)) return buf; } @@ -796,27 +594,37 @@ string WResourceManager::cardFile(const string filename, const string setname, c std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower); if(mode != "" && mode != "defualt"){ - sprintf(buf,"modes/%s/%s/%s",mode.c_str(),sets,filename.c_str()); + sprintf(buf,"modes/%s/sets/%s",mode.c_str(),filename.c_str()); if(fileOK(buf,true)) return buf; } //Failure. Check sets char defdir[512]; - sprintf(defdir,"%s/%s",sets,filename.c_str()); + sprintf(defdir,"sets/%s",filename.c_str()); if(fileOK(defdir,true)) return defdir; //Failure. Assume it's in a zip file? - if(setname.size()){ - char zipname[100]; - sprintf(zipname, "Res/sets/%s/%s.zip", setname.c_str(),setname.c_str()); - if (fileOK(zipname)){ - fs->AttachZipFile(zipname); - return filename; - } + string::size_type i; + for(i = 0;i < filename.size();i++){ + if(filename[i] == '\\' || filename[i] == '/') + break; + } + + if(i != filename.size()){ + string set = filename.substr(0,i); + + if(set.size()){ + char zipname[512]; + sprintf(zipname, "Res/sets/%s/%s.zip", set.c_str(),set.c_str()); + if (fileOK(zipname)){ + fs->AttachZipFile(zipname); + return filename.substr(i+1); + } + } } - + //Complete failure. return ""; } @@ -920,31 +728,6 @@ int WResourceManager::fileOK(string filename, bool relative){ return result; } -int WResourceManager::CreateTexture(const string &textureName) { - int id = INVALID_ID; - map::iterator itr = mTextureMap.find(textureName); - - if (itr == mTextureMap.end()) - { - string path = graphicsFile(textureName); - - printf("creating texture:%s\n", path.c_str()); - - JTexture *tex = JRenderer::GetInstance()->LoadTexture(path.c_str()); - - if (tex != NULL) - { - id = mTextureList.size(); - mTextureList.push_back(tex); - mTextureMap[textureName] = id; - } - - return id; - } - else - return itr->second; -} - int WResourceManager::LoadJLBFont(const string &fontName, int height){ map::iterator itr = mFontMap.find(fontName); @@ -964,53 +747,24 @@ int WResourceManager::LoadJLBFont(const string &fontName, int height){ else return itr->second; } - -int WResourceManager::LoadMusic(const string &musicName){ - map::iterator itr = mMusicMap.find(musicName); - - if (itr == mMusicMap.end()) - { - string path = musicFile(musicName); - - printf("creating music:%s\n", path.c_str()); - - JMusic *music = JSoundSystem::GetInstance()->LoadMusic(path.c_str()); - if (music == NULL) - return INVALID_ID; - - int id = mMusicList.size(); - mMusicList.push_back(music); - - mMusicMap[musicName] = id; - - return id; - } - else - return itr->second; +void WResourceManager::LargeCache(){ +#if (defined WIN32 || defined LINUX) && !defined DEBUG_CACHE + return; +#else + //Does not check option so we can use large cache during + //deck editor, when it's pretty much always safe. + textureWCache.Resize(LARGE_CACHE_LIMIT,MAX_CACHE_OBJECTS); + textureWCache.Cleanup(); +#endif } - -int WResourceManager::LoadSample(const string &sampleName){ - map::iterator itr = mSampleMap.find(sampleName); - - if (itr == mSampleMap.end()) - { - string path = sfxFile(sampleName); - - printf("creating sample:%s\n", path.c_str()); - - JSample *sample = JSoundSystem::GetInstance()->LoadSample(path.c_str()); - if (sample == NULL) - return INVALID_ID; - - int id = mSampleList.size(); - mSampleList.push_back(sample); - - mSampleMap[sampleName] = id; - - return id; - } - else - return itr->second; +void WResourceManager::SmallCache(){ +#if (defined WIN32 || defined LINUX) && !defined DEBUG_CACHE + return; +#else + if(options[Options::CACHESIZE].number == 0){ + textureWCache.Resize(SMALL_CACHE_LIMIT,MAX_CACHE_OBJECTS); + textureWCache.Cleanup();} +#endif } JMusic * WResourceManager::ssLoadMusic(const char *fileName){ @@ -1018,86 +772,14 @@ JMusic * WResourceManager::ssLoadMusic(const char *fileName){ } -//Unmodified from JResourceManager - -int WResourceManager::CreateQuad(const string &quadName, const string &textureName, float x, float y, float width, float height){ - map::iterator itr = mQuadMap.find(quadName); - - if (itr == mQuadMap.end()) - { - JTexture *tex = GetTexture(textureName); - if (tex == NULL) - { - int texId = CreateTexture(textureName); // load texture if necessary - tex = GetTexture(texId); - } - - if (tex == NULL) // no texture, no quad... - return INVALID_ID; - - printf("creating quad:%s\n", quadName.c_str()); - - int id = mQuadList.size(); - if(width == 0.0f) - width = tex->mWidth; - if(height == 0.0f) - height = tex->mHeight; - - mQuadList.push_back(NEW JQuad(tex, x, y, width, height)); - - mQuadMap[quadName] = id; - - return id; - - } - else - return itr->second; -} - void WResourceManager::Refresh(){ + //Really easy cache relinking. + sampleWCache.Refresh(); + textureWCache.Refresh(); + psiWCache.Refresh(); + map::iterator it; vector::iterator q; - JTexture * oldtex; - - mTextureMissing.clear(); - ClearMisses(); - ClearSamples(); - - for(it = textureCache.begin();it!=textureCache.end();it++){ - if(it->second == NULL) - continue; - - oldtex = it->second->texture; - - //Reload the texture. - if(it->second->bVRAM) - it->second->texture = JRenderer::GetInstance()->LoadTexture(graphicsFile(it->first).c_str(),TEX_TYPE_USE_VRAM,TEXTURE_FORMAT); - else - it->second->texture = JRenderer::GetInstance()->LoadTexture(graphicsFile(it->first).c_str(),0,TEXTURE_FORMAT); - - //This texture doesn't exist in our current theme. Either use the old one, or record cache miss. - if(!it->second->texture){ - if(it->second->isLocked()) - it->second->texture = oldtex; - else{ - if(oldtex) - totalsize -= oldtex->mTexHeight * oldtex->mTexWidth; - - SAFE_DELETE(oldtex); - SAFE_DELETE(it->second); - } - continue; - } - else{ - //Alright, log the new size. - totalsize += it->second->texture->mTexHeight * it->second->texture->mTexWidth; - } - - //Relink quads to new texture. - for(q = it->second->trackedQuads.begin(); q != it->second->trackedQuads.end(); q++){ - (*q)->mTex = it->second->texture; - } - } //Now do some juggling so that managed resources also reload. map oldTextures; @@ -1106,6 +788,7 @@ void WResourceManager::Refresh(){ vector::iterator jtex; map::iterator mapping; JTexture * newtex; + JTexture * oldtex = NULL; //Store old mappings. for(mapping = mTextureMap.begin();mapping != mTextureMap.end();mapping++){ @@ -1157,7 +840,555 @@ void WResourceManager::Refresh(){ if(!oldIt->second || !oldIt->first ) continue; - oldtex = oldIt->first; SAFE_DELETE(oldtex); } +} + +//WCache +template +bool WCache::RemoveOldest(){ + typename map ::iterator oldest = cache.end(); + + for(typename map::iterator it = cache.begin();it!=cache.end();it++){ + if(it->second && !it->second->isLocked() + && (oldest == cache.end() || it->second->lastTime < oldest->second->lastTime)) + oldest = it; + } + + if(oldest != cache.end() && oldest->second && !oldest->second->isLocked()){ + unsigned long isize = oldest->second->size(); + cacheSize -= isize; + totalSize -= isize; + cacheItems--; +#if defined DEBUG_CACHE + lastExpired = oldest->first; +#endif + Delete(oldest->second); + cache.erase(oldest); + return true; + } + + return false; + +} +template +void WCache::Clear(){ + typename map::iterator it, next; + + for(it = cache.begin(); it != cache.end();it=next){ + next = it; + next++; + + if(it->second){ + unsigned long isize = it->second->size(); + totalSize -= isize; + cacheSize -= isize; + Delete(it->second); + cacheItems--; + } + cache.erase(it); + } + for(it = managed.begin(); it != managed.end();it=next){ + next = it; + next++; + + if(!it->second) + managed.erase(it); + } +} + +template +void WCache::ClearUnlocked(){ + typename map::iterator it, next; + + for(it = cache.begin(); it != cache.end();it=next){ + next = it; + next++; + + if(it->second && !it->second->isLocked()){ + unsigned long isize = it->second->size(); + totalSize -= isize; + cacheSize -= isize; + Delete(it->second); + cacheItems--; + cache.erase(it); + } + else if(!it->second){ + cache.erase(it); + } + } +} + +template +void WCache::ClearMisses(){ + typename map::iterator it, next; + + for(it = cache.begin(); it != cache.end();it=next){ + next = it; + next++; + + if(!it->second) + cache.erase(it); + } + for(it = managed.begin(); it != managed.end();it=next){ + next = it; + next++; + + if(!it->second) + managed.erase(it); + } +} +template +void WCache::Resize(unsigned long size, int items){ + maxCacheSize = size; + + if(items > MAX_CACHE_OBJECTS || items < 0) + maxCached = MAX_CACHE_OBJECTS; + else + maxCached = items; +} +template +cacheItem* WCache::AttemptNew(string filename, int submode){ +// Cleanup(); + + if(submode & CACHE_EXISTING){ //Should never get this far. + mError = CACHE_ERROR_NOT_CACHED; + return NULL; + } + + cacheItem* item = NEW cacheItem; + + mError = CACHE_ERROR_NONE; + + if(item == NULL || !item->Attempt(filename,submode,mError)){ + //No such file. Fail. + if(mError == CACHE_ERROR_404){ + Delete(item); + return NULL; + } + + + for(int attempt=0;attempt<10;attempt++){ + if(!RemoveOldest()) + break; + + if(!item) + item = NEW cacheItem ; + + if(item && item->Attempt(filename,submode,mError)) + break; + } + + + //Still no result, so clear cache entirely, then try again. + if(!item || !item->isGood()){ + ClearUnlocked(); + if(!item) item = NEW(cacheItem); + item->Attempt(filename,submode,mError); + } + + //Worst cache scenerio. Clear every cache we've got. + if(!item || !item->isGood()){ + resources.ClearUnlocked(); + if(!item) item = NEW(cacheItem); + item->Attempt(filename,submode,mError); + } + } + + if(item && !item->isGood()){ + Delete(item); + mError = CACHE_ERROR_BAD; + } + else + mError = CACHE_ERROR_NONE; + + Cleanup(); + return item; +} + +template +cacheItem * WCache::Retrieve(string filename, int style, int submode){ + //Check cache. + cacheItem * tc = NULL; + + if(style == RETRIEVE_EXISTING || style == RETRIEVE_RESOURCE) + tc = Get(filename,style,submode|CACHE_EXISTING); + else + tc = Get(filename,style,submode); + + //Retrieve resource only works on permanent items. + if(style == RETRIEVE_RESOURCE && tc && !tc->isPermanent()){ + mError = CACHE_ERROR_NOT_MANAGED; + return NULL; + } + + //Perform lock or unlock on entry. + if(tc){ + if(style == RETRIEVE_LOCK) tc->lock(); + else if(style == RETRIEVE_UNLOCK) tc->unlock(); + else if(style == RETRIEVE_MANAGE && !tc->isPermanent()) { + //Unlink the managed resource from the cache. + UnlinkCache(tc); + + //Post it in managed resources. + managed[makeID(filename,submode)] = tc; + tc->deadbolt(); + } + } + + //Resource exists! + if(tc){ + if(tc->isGood()){ + tc->hit(); + return tc; //Everything fine. + } + else{ + //Something went wrong. + Delete(tc); + } + } + + //Record managed failure. Cache failure is recorded in Get(). + if(style == RETRIEVE_MANAGE || style == RETRIEVE_RESOURCE) + managed[makeID(filename,submode)] = NULL; + + return NULL; +} +template +string WCache::makeID(string id, int submode){ + string lookup = id; + + //To differentiate between cached thumbnails and the real thing. + if(submode & TEXTURE_SUB_THUMB) + lookup.insert(0,"T"); + + return lookup; +} + +template +string WCache::makeFilename(string id, int submode){ + //To differentiate between cached thumbnails and the real thing. + if(submode & TEXTURE_SUB_THUMB) + return id.substr(1); + + return id; +} + +template +cacheItem * WCache::Get(string id, int style, int submode){ + typename map::iterator it; + string lookup = makeID(id,submode); + + //Check for managed resources first. Always + it = managed.end(); + for(it = managed.begin();it!=managed.end();it++){ + if(it->first == lookup) + break; + } + //Something is managed. + if(it != managed.end()) { + if(!it->second && style == RETRIEVE_RESOURCE) + return NULL; //A miss. + else + return it->second; //A hit. + } + //Failed to find managed resource and won't create one. Record a miss. + else if(style == RETRIEVE_RESOURCE){ + managed[lookup] = NULL; + return NULL; + } + + //Not managed, so look in cache. + if(it == managed.end() && style != RETRIEVE_MANAGE && style != RETRIEVE_RESOURCE ){ + it = cache.end(); + for(it = cache.begin();it!=cache.end();it++){ + if(it->first == lookup) + break; + } + //Well, we've found something... + if(it != cache.end()) { + if(!it->second && (submode & CACHE_EXISTING)) + return NULL; //A miss. + else + return it->second; //A hit. + } + } + + cacheItem * item = NULL; + + if(style != RETRIEVE_MANAGE) + item = cache[lookup]; //We don't know about this one yet. + + //Found something. + if(item){ + //Item went bad? + if(!item->isGood()){ + + //If we're allowed, attempt to revive it. + if(!(submode & CACHE_EXISTING)) + item->Attempt(id,submode,mError); + + //Still bad, so remove it and return NULL + if(submode & CACHE_EXISTING || !item->isGood()){ + if(!item->isLocked()){ + RemoveItem(item); //Delete it. + mError = CACHE_ERROR_BAD; + } + //Worst case scenerio. Hopefully never happens.... hasn't so far. + else{ + item->Nullify(); //We're giving up on anything allocated here. + mError = CACHE_ERROR_LOST; //This is a potential memory leak, but might prevent a crash. + } + return NULL; + } + } + + //Alright, everythings fine! + mError = CACHE_ERROR_NONE; + return item; + } + + //Didn't exist in cache. + if(submode & CACHE_EXISTING ){ + RemoveMiss(lookup); + mError = CACHE_ERROR_NOT_CACHED; + return NULL; + } + else{ + //Space in cache, make new texture + item = AttemptNew(id,submode); + + //Couldn't make new item. + if(item && !item->isGood()) + Delete(item); + } + + if(style == RETRIEVE_MANAGE){ + if(item){ + managed[lookup] = item; //Record a hit. + item->deadbolt(); //Make permanent. + } + else if(mError == CACHE_ERROR_404) + managed[lookup] = item; //File not found. Record a miss + } + else{ + if(!item && mError != CACHE_ERROR_404) + RemoveMiss(lookup); + else + cache[lookup] = item; + } + + //Succeeded in making a new item. + if(item){ + unsigned long isize =item->size(); + totalSize += isize; + + mError = CACHE_ERROR_NONE; + if(style != RETRIEVE_MANAGE){ + cacheItems++; + cacheSize += isize; + } + + return item; + } + + //Failure. + return NULL; +} + +template +void WCache::Refresh(){ + typename map::iterator it; + ClearUnlocked(); + + for(it = cache.begin();it!=cache.end();it++){ + if(it->second){ + it->second->Refresh(makeFilename(it->first,it->second->loadedMode)); + } + } + for(it = managed.begin();it!=managed.end();it++){ + if(it->second){ + it->second->Refresh(makeFilename(it->first,it->second->loadedMode)); + } + } +} + +template +WCache::WCache(){ + cacheSize = 0; + totalSize = 0; + + maxCacheSize = SMALL_CACHE_LIMIT; + + maxCached = MAX_CACHE_OBJECTS; + cacheItems = 0; + mError = CACHE_ERROR_NONE; +} + +template +WCache::~WCache(){ + typename map::iterator it; + + for(it=cache.begin();it!=cache.end();it++){ + if(!it->second) + continue; + + Delete(it->second); + } + + for(it=managed.begin();it!=managed.end();it++){ + if(!it->second) + continue; + + Delete(it->second); + } +} + + +template +bool WCache::Cleanup(){ + while(cacheItems < cache.size() && cache.size() - cacheItems > MAX_CACHE_MISSES){ + RemoveMiss(); + } + + while (cacheItems > MAX_CACHE_OBJECTS || cacheItems > maxCached || cacheSize > maxCacheSize ){ + if (!RemoveOldest()) + return false; + } + return true; +} + +template +unsigned int WCache::Flatten(){ + unsigned int youngest = 65535; + unsigned int oldest = 0; + + for (typename map::iterator it = cache.begin(); it != cache.end(); ++it){ + if(!it->second) continue; + if(it->second->lastTime < youngest) youngest = it->second->lastTime; + if(it->second->lastTime > oldest) oldest = it->second->lastTime; + } + + for (typename map::iterator it = cache.begin(); it != cache.end(); ++it){ + if(!it->second) continue; + it->second->lastTime -= youngest; + } + + return (oldest - youngest); +} + +template +bool WCache::RemoveMiss(string id){ + typename map::iterator it = cache.end(); + + for(it = cache.begin();it!=cache.end();it++){ + if((id == "" || it->first == id) && it->second == NULL) + break; + } + + if(it != cache.end()) + { + cache.erase(it); + return true; + } + + return false; +} + +template +bool WCache::RemoveItem(cacheItem * item, bool force){ + typename map::iterator it = cache.end(); + + if(item == NULL) + return false; //Use RemoveMiss to remove cache misses, not this. + + for(it = cache.begin();it!=cache.end();it++){ + if(it->second == item) + break; + } + if(it != cache.end() && it->second && (force || !it->second->isLocked())){ + unsigned long isize = it->second->size(); + totalSize -= isize; + cacheSize -= isize; + + cacheItems--; +#if defined DEBUG_CACHE + lastRemoved = it->first; +#endif + Delete(it->second); + cache.erase(it); + return true; + } + + return false; +} + +template +bool WCache::UnlinkCache(cacheItem * item){ + typename map::iterator it = cache.end(); + + if(item == NULL) + return false; //Use RemoveMiss to remove cache misses, not this. + + for(it = cache.begin();it!=cache.end();it++){ + if(it->second == item) + break; + } + if(it != cache.end() && it->second){ + it->second = NULL; + unsigned long isize = item->size(); + + cacheSize-=isize; + cacheItems--; + cache.erase(it); + return true; + } + + return false; +} + +template +bool WCache::Delete(cacheItem * item){ + if(!item) + return false; + + if(maxCached == 0) + item->Nullify(); + + SAFE_DELETE(item); + return true; +} + +template +bool WCache::Release(cacheActual* actual){ + if(!actual) + return false; + + typename map::iterator it; + for(it=cache.begin();it!=cache.end();it++){ + if(it->second && it->second->compare(actual)) + break; + } + + if(it == cache.end()) + return false; //Not here, can't release. + + if(it->second){ + it->second->unlock(); //Release one lock. + if(it->second->isLocked()) + return true; //Still locked, won't delete. + + unsigned long isize = it->second->size(); + totalSize -= isize; + cacheSize -= isize; + cacheItems--; +#if defined DEBUG_CACHE + lastReleased = it->first; +#endif + Delete(it->second); + } + + //Released! + cache.erase(it); + return true; } \ No newline at end of file diff --git a/projects/mtg/template.vcproj b/projects/mtg/template.vcproj index bcf84218a..a3bab709d 100644 --- a/projects/mtg/template.vcproj +++ b/projects/mtg/template.vcproj @@ -556,6 +556,10 @@ RelativePath=".\src\WEvent.cpp" > + + @@ -909,6 +913,10 @@ RelativePath=".\include\WResourceManager.h" > + +