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" > + +