mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
1570 lines
37 KiB
C++
1570 lines
37 KiB
C++
|
#include <string.h>
|
||
|
#include <core/defines.h>
|
||
|
#include <core/debug.h>
|
||
|
#include <sys/file/filesys.h>
|
||
|
#include <core/math.h>
|
||
|
#include <core/math/vector.h>
|
||
|
#include <eestruct.h>
|
||
|
#include <sifdev.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "sprite.h"
|
||
|
#include "dma.h"
|
||
|
#include "vif.h"
|
||
|
#include "vu1.h"
|
||
|
#include "gif.h"
|
||
|
#include "gs.h"
|
||
|
#include "vu1code.h"
|
||
|
#include "texturemem.h"
|
||
|
#include "render.h"
|
||
|
#include "switches.h"
|
||
|
#include <gel/scripting/symboltable.h>
|
||
|
|
||
|
/*
|
||
|
|
||
|
|
||
|
|
||
|
.img file format
|
||
|
--------------------------
|
||
|
|
||
|
Offset Size (Bytes) Field
|
||
|
---------------------------------------------------------------
|
||
|
0x00 4 Version (currently 1)
|
||
|
0x04 4 Basename of file in CRC format
|
||
|
0x08 4 PS2 TW (log2 Width)
|
||
|
0x0c 4 PS2 TH (log2 Height)
|
||
|
0x10 4 PS2 PSM (Bit depth)
|
||
|
0x14 4 PS2 CPSM (CLUT bit depth)
|
||
|
0x18 4 PS2 MXL (Number of mipmaps)
|
||
|
0x1c 2 Original image width
|
||
|
0x1e 2 Original image height
|
||
|
0x20 Upto 1K CLUT data
|
||
|
0x20+CLUT_size W*H*depth Texture mipmaps
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
font->vram upload format
|
||
|
------------------------
|
||
|
|
||
|
|
||
|
GIFtag PACKED 4
|
||
|
BITBLTBUF ?
|
||
|
TRXPOS 0
|
||
|
TRXREG w,h
|
||
|
TRXDIR 0
|
||
|
|
||
|
GIFtag IMAGE (w*h+15)/16
|
||
|
... (tex data)
|
||
|
|
||
|
GIFtag PACKED 4
|
||
|
BITBLTBUF ?
|
||
|
TRXPOS 0
|
||
|
TRXREG w,h
|
||
|
TRXDIR 0
|
||
|
|
||
|
GIFtag IMAGE 64
|
||
|
... (clut data)
|
||
|
|
||
|
|
||
|
|
||
|
total size in bytes = 12*16+((w*h+15)/16)*16+1024 = 1216+((w*h+15)/16)*16
|
||
|
|
||
|
this will be referenced as follows:
|
||
|
|
||
|
dma ref
|
||
|
NOP
|
||
|
DIRECT 76+(w*h+15)/16
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
namespace NxPs2
|
||
|
{
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* SSingleTexture */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
SSingleTexture * SSingleTexture::sp_stexture_list = NULL;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SSingleTexture::SSingleTexture()
|
||
|
{
|
||
|
Dbg_Error("Must supply a filename when creating a SSingleTexture");
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// .img.ps2 buffer
|
||
|
|
||
|
SSingleTexture::SSingleTexture(uint8* p_buffer, int buffer_size, bool sprite, bool alloc_vram, bool load_screen) :
|
||
|
m_flags(0),
|
||
|
m_usage_count(0)
|
||
|
{
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
strcpy(m_name,"texture from buffer");
|
||
|
#endif
|
||
|
|
||
|
mp_TexBitBltBuf = mp_ClutBitBltBuf = NULL;
|
||
|
|
||
|
// Set flags
|
||
|
if (load_screen)
|
||
|
{
|
||
|
m_flags |= mLOAD_SCREEN;
|
||
|
}
|
||
|
if (sprite)
|
||
|
{
|
||
|
m_flags |= mSPRITE;
|
||
|
}
|
||
|
if ((sprite && alloc_vram) && !load_screen)
|
||
|
{
|
||
|
m_flags |= mALLOC_VRAM;
|
||
|
}
|
||
|
|
||
|
// open the font file
|
||
|
if (!sprite)
|
||
|
{
|
||
|
Dbg_Assert(!alloc_vram);
|
||
|
}
|
||
|
|
||
|
mp_PixelData = mp_ClutData = NULL;
|
||
|
m_PixelDataSize = m_ClutDataSize = 0;
|
||
|
|
||
|
mp_TexBuffer = (uint8*)Mem::Malloc( buffer_size );
|
||
|
Dbg_Assert( mp_TexBuffer );
|
||
|
memcpy( mp_TexBuffer, p_buffer, buffer_size );
|
||
|
m_TexBufferSize = buffer_size;
|
||
|
|
||
|
// Initialize all the data
|
||
|
InitTexture(false);
|
||
|
|
||
|
// add texture to texture list
|
||
|
if (sprite && !load_screen)
|
||
|
{
|
||
|
mp_next = sp_stexture_list;
|
||
|
sp_stexture_list = this;
|
||
|
}
|
||
|
|
||
|
if (load_screen) {
|
||
|
FlipTextureVertical();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// .img.ps2 file
|
||
|
|
||
|
SSingleTexture::SSingleTexture(const char *Filename, bool sprite, bool alloc_vram, bool load_screen) :
|
||
|
m_flags(0),
|
||
|
m_usage_count(0)
|
||
|
{
|
||
|
char ExtendedFilename[128];
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
strcpy(m_name,Filename);
|
||
|
#endif
|
||
|
|
||
|
mp_TexBitBltBuf = mp_ClutBitBltBuf = NULL;
|
||
|
|
||
|
// Set flags
|
||
|
if (load_screen)
|
||
|
{
|
||
|
m_flags |= mLOAD_SCREEN;
|
||
|
}
|
||
|
if (sprite)
|
||
|
{
|
||
|
m_flags |= mSPRITE;
|
||
|
}
|
||
|
if ((sprite && alloc_vram) && !load_screen)
|
||
|
{
|
||
|
m_flags |= mALLOC_VRAM;
|
||
|
}
|
||
|
|
||
|
// open the font file
|
||
|
if (sprite)
|
||
|
{
|
||
|
// strcpy(ExtendedFilename, "images/");
|
||
|
// strcat(ExtendedFilename, Filename);
|
||
|
strcpy(ExtendedFilename, Filename);
|
||
|
} else {
|
||
|
Dbg_Assert(!alloc_vram);
|
||
|
|
||
|
strcpy(ExtendedFilename, Filename);
|
||
|
}
|
||
|
strcat(ExtendedFilename, ".img.ps2");
|
||
|
|
||
|
mp_PixelData = mp_ClutData = NULL;
|
||
|
m_PixelDataSize = m_ClutDataSize = 0;
|
||
|
|
||
|
#if 0
|
||
|
void *pFile = File::Open(ExtendedFilename, "rb");
|
||
|
// get file size and allocate texture buffer
|
||
|
m_TexBufferSize = File::GetFileSize(pFile);
|
||
|
mp_TexBuffer = (uint8 *)Mem::Malloc(m_TexBufferSize);
|
||
|
File::Read(mp_TexBuffer, 1, m_TexBufferSize, pFile);
|
||
|
File::Close(pFile);
|
||
|
#else
|
||
|
mp_TexBuffer = (uint8*)File::LoadAlloc(ExtendedFilename, &m_TexBufferSize);
|
||
|
#endif
|
||
|
|
||
|
// Initialize all the data
|
||
|
InitTexture(false);
|
||
|
|
||
|
// add texture to texture list
|
||
|
if (sprite && !load_screen)
|
||
|
{
|
||
|
mp_next = sp_stexture_list;
|
||
|
sp_stexture_list = this;
|
||
|
}
|
||
|
|
||
|
if (load_screen) {
|
||
|
FlipTextureVertical();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// raw buffer
|
||
|
|
||
|
SSingleTexture::SSingleTexture(uint8* p_buffer, int width, int height, int bitdepth, int clut_bitdepth, int mipmaps,
|
||
|
bool sprite, bool alloc_vram, bool load_screen):
|
||
|
m_flags(0),
|
||
|
m_usage_count(0)
|
||
|
{
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
strcpy(m_name,"texture from raw data");
|
||
|
#endif
|
||
|
|
||
|
mp_TexBitBltBuf = mp_ClutBitBltBuf = NULL;
|
||
|
|
||
|
// Set flags
|
||
|
if (load_screen)
|
||
|
{
|
||
|
m_flags |= mLOAD_SCREEN;
|
||
|
}
|
||
|
if (sprite)
|
||
|
{
|
||
|
m_flags |= mSPRITE;
|
||
|
}
|
||
|
if ((sprite && alloc_vram) && !load_screen)
|
||
|
{
|
||
|
m_flags |= mALLOC_VRAM;
|
||
|
}
|
||
|
|
||
|
// open the font file
|
||
|
if (!sprite)
|
||
|
{
|
||
|
Dbg_Assert(!alloc_vram);
|
||
|
}
|
||
|
|
||
|
mp_PixelData = mp_ClutData = NULL;
|
||
|
m_PixelDataSize = m_ClutDataSize = 0;
|
||
|
mp_TexBuffer = NULL; // Since we aren't allocating any memory
|
||
|
m_TexBufferSize = 0;
|
||
|
|
||
|
m_checksum = 0;
|
||
|
m_orig_width = width;
|
||
|
m_orig_height = height;
|
||
|
|
||
|
// Initialize all the data
|
||
|
//InitTexture(false);
|
||
|
uint32 TW, TH, PSM, CPSM, MXL;
|
||
|
|
||
|
TW = TextureMemoryLayout::numBits(width - 1); // Rounds up to the nearest 2^N
|
||
|
TH = TextureMemoryLayout::numBits(height - 1);
|
||
|
|
||
|
PSM = bitdepth_to_psm(bitdepth);
|
||
|
CPSM = bitdepth_to_psm(clut_bitdepth);
|
||
|
|
||
|
MXL = mipmaps - 1;
|
||
|
|
||
|
// Raw data is inverted vertically from the way we expect textures.
|
||
|
m_flags |= mINVERTED;
|
||
|
|
||
|
setup_reg_and_dma(p_buffer, TW, TH, PSM, CPSM, MXL, false);
|
||
|
|
||
|
// add texture to texture list
|
||
|
if (sprite && !load_screen)
|
||
|
{
|
||
|
mp_next = sp_stexture_list;
|
||
|
sp_stexture_list = this;
|
||
|
}
|
||
|
|
||
|
if (load_screen) {
|
||
|
FlipTextureVertical();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// copy constructor
|
||
|
|
||
|
SSingleTexture::SSingleTexture(const SSingleTexture & src_texture)
|
||
|
{
|
||
|
// Copy checksum and flags
|
||
|
m_checksum = src_texture.m_checksum;
|
||
|
m_flags = src_texture.m_flags;
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
strcpy(m_name,src_texture.m_name);
|
||
|
#endif
|
||
|
|
||
|
// Init some of the data before we call InitTexture()
|
||
|
m_usage_count = 0;
|
||
|
mp_TexBitBltBuf = mp_ClutBitBltBuf = NULL;
|
||
|
mp_PixelData = mp_ClutData = NULL;
|
||
|
m_PixelDataSize = m_ClutDataSize = 0;
|
||
|
|
||
|
// Copy file buffer
|
||
|
m_TexBufferSize = src_texture.m_TexBufferSize;
|
||
|
if (m_TexBufferSize && src_texture.mp_TexBuffer)
|
||
|
{
|
||
|
mp_TexBuffer = (uint8 *)Mem::Malloc(m_TexBufferSize);
|
||
|
memcpy(mp_TexBuffer, src_texture.mp_TexBuffer, m_TexBufferSize);
|
||
|
|
||
|
// This routine will initialize and allocate the rest
|
||
|
InitTexture(true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_MsgAssert(0, ("Can't copy SSingleTexture that was created with a raw buffer"));
|
||
|
//InitTexture(true);
|
||
|
}
|
||
|
|
||
|
// add texture to texture list
|
||
|
if ((m_flags & mSPRITE) && !(m_flags & mLOAD_SCREEN))
|
||
|
{
|
||
|
mp_next = sp_stexture_list;
|
||
|
sp_stexture_list = this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SSingleTexture::~SSingleTexture()
|
||
|
{
|
||
|
// find texture and unchain from list
|
||
|
if (sp_stexture_list == this)
|
||
|
{
|
||
|
sp_stexture_list = mp_next;
|
||
|
} else if (sp_stexture_list) {
|
||
|
SSingleTexture *p_texture = sp_stexture_list;
|
||
|
|
||
|
while(p_texture->mp_next)
|
||
|
{
|
||
|
if (p_texture->mp_next == this)
|
||
|
{
|
||
|
p_texture->mp_next = mp_next;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
p_texture = p_texture->mp_next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// free memory
|
||
|
if (mp_VifData) Mem::Free(mp_VifData);
|
||
|
if (mp_TexBuffer) Mem::Free(mp_TexBuffer);
|
||
|
|
||
|
Dbg_MsgAssert(m_usage_count == 0, ("Trying to remove SSingleTexture %x that is still being used", m_checksum));
|
||
|
|
||
|
// and re-do VRAM allocation
|
||
|
VRAMNeedsUpdating();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
#define STEX_USE_CALL 1
|
||
|
|
||
|
const static uint32 TEXTURE_VERSION = 1;
|
||
|
|
||
|
TextureMemoryLayout TexMemLayout;
|
||
|
|
||
|
bool SSingleTexture::InitTexture(bool copy)
|
||
|
{
|
||
|
uint32 TW, TH, PSM, CPSM, MXL = 0;
|
||
|
|
||
|
uint8 *pData = mp_TexBuffer;
|
||
|
|
||
|
uint32 version;
|
||
|
version = *(uint32 *)pData, pData+=4;
|
||
|
Dbg_MsgAssert(version >= TEXTURE_VERSION, ("Wrong version in .img file: %d. Game uses: %d", version, TEXTURE_VERSION));
|
||
|
m_checksum = *(uint32 *)pData, pData+=4;
|
||
|
|
||
|
// get dimensions
|
||
|
TW = *(uint32 *)pData, pData+=4;
|
||
|
TH = *(uint32 *)pData, pData+=4;
|
||
|
|
||
|
// get pixel storage modes
|
||
|
PSM = *(uint32 *)pData, pData+=4; // for texels
|
||
|
CPSM = *(uint32 *)pData, pData+=4; // for clut
|
||
|
|
||
|
// get maximum mipmap level
|
||
|
if (version >= 2)
|
||
|
{
|
||
|
MXL = *(uint32 *)pData, pData+=4;
|
||
|
}
|
||
|
Dbg_Assert(MXL == 0);
|
||
|
m_orig_width = *(uint16 *)pData, pData+=2;
|
||
|
m_orig_height = *(uint16 *)pData, pData+=2;
|
||
|
|
||
|
// bail if it's a non-texture
|
||
|
Dbg_MsgAssert((TW != 0xFFFFFFFF), ("No texture in .img file\n"));
|
||
|
|
||
|
// quadword-align
|
||
|
pData = (uint8 *)(((uint)(pData+15)) & 0xFFFFFFF0);
|
||
|
|
||
|
return setup_reg_and_dma(pData, TW, TH, PSM, CPSM, MXL, copy);
|
||
|
}
|
||
|
|
||
|
bool SSingleTexture::setup_reg_and_dma(uint8 *pData, uint32 TW, uint32 TH, uint32 PSM, uint32 CPSM, uint32 MXL, bool copy)
|
||
|
{
|
||
|
uint TBW;
|
||
|
uint Width, Height, NumTexBytes, NumTexQWords, NumClutBytes, NumClutQWords, NumVramBytes;
|
||
|
uint BitsPerTexel, BitsPerClutEntry, PaletteSize;
|
||
|
uint NextTBP;
|
||
|
int j,k;
|
||
|
|
||
|
uint8 *old_dma_loc = dma::pLoc;
|
||
|
|
||
|
// initialise base pointers
|
||
|
if (IsInVRAM())
|
||
|
{
|
||
|
NextTBP = FontVramBase;
|
||
|
} else {
|
||
|
NextTBP = FontVramStart;
|
||
|
}
|
||
|
|
||
|
// bits per texel and palette size
|
||
|
switch (PSM)
|
||
|
{
|
||
|
case PSMCT32:
|
||
|
BitsPerTexel = 32;
|
||
|
PaletteSize = 0;
|
||
|
break;
|
||
|
case PSMCT24:
|
||
|
BitsPerTexel = 24;
|
||
|
PaletteSize = 0;
|
||
|
break;
|
||
|
case PSMCT16:
|
||
|
BitsPerTexel = 16;
|
||
|
PaletteSize = 0;
|
||
|
break;
|
||
|
case PSMT8:
|
||
|
BitsPerTexel = 8;
|
||
|
PaletteSize = 256;
|
||
|
break;
|
||
|
case PSMT4:
|
||
|
BitsPerTexel = 4;
|
||
|
PaletteSize = 16;
|
||
|
break;
|
||
|
default:
|
||
|
printf("Unknown PSM %d in texture file\n", PSM);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
// bits per clut entry
|
||
|
if (BitsPerTexel < 16)
|
||
|
switch (CPSM)
|
||
|
{
|
||
|
case PSMCT32:
|
||
|
BitsPerClutEntry = 32;
|
||
|
break;
|
||
|
case PSMCT16:
|
||
|
BitsPerClutEntry = 16;
|
||
|
break;
|
||
|
default:
|
||
|
printf("Unknown CPSM %d in texture file\n", PSM);
|
||
|
exit(1);
|
||
|
}
|
||
|
else
|
||
|
BitsPerClutEntry = 0;
|
||
|
|
||
|
// rearrange 256-colour cluts according to requirements of CSM1
|
||
|
if (!copy && PSM==PSMT8)
|
||
|
{
|
||
|
uint32 temp32;
|
||
|
uint16 temp16;
|
||
|
for (j=0; j<256; j+=32)
|
||
|
for (k=0; k<8; k++)
|
||
|
if (CPSM==PSMCT32)
|
||
|
{
|
||
|
temp32 = ((uint32 *)pData)[j+k+8];
|
||
|
((uint32 *)pData)[j+k+8] = ((uint32 *)pData)[j+k+16];
|
||
|
((uint32 *)pData)[j+k+16] = temp32;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
temp16 = ((uint16 *)pData)[j+k+8];
|
||
|
((uint16 *)pData)[j+k+8] = ((uint16 *)pData)[j+k+16];
|
||
|
((uint16 *)pData)[j+k+16] = temp16;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// calculate texture dimensions
|
||
|
Width = (TW>=0 ? 1<<TW : 0);
|
||
|
Height = (TH>=0 ? 1<<TH : 0);
|
||
|
TBW = (Width+63) >> 6;
|
||
|
if (BitsPerTexel<16 && TBW<2)
|
||
|
TBW = 2;
|
||
|
|
||
|
// Calculate memory needed
|
||
|
int min_width = Width, min_height = Height;
|
||
|
TexMemLayout.getMinSize(min_width, min_height, PSM);
|
||
|
m_NumTexVramBlocks = TexMemLayout.getImageSize(min_width, min_height, PSM);
|
||
|
NumVramBytes = m_NumTexVramBlocks * 256;
|
||
|
//NumVramBytes = (TBW << 6) * Height * BitsPerTexel >> 3;
|
||
|
|
||
|
// calculate sizes within file
|
||
|
NumClutBytes = PaletteSize * BitsPerClutEntry >> 3;
|
||
|
NumClutQWords = NumClutBytes >> 4;
|
||
|
NumTexBytes = Width * Height * BitsPerTexel >> 3;
|
||
|
NumTexQWords = NumTexBytes >> 4;
|
||
|
|
||
|
//Dbg_Message("Texture size (%d, %d) of bitdepth %d and BufferWidth %d", Width, Height, BitsPerTexel, TBW);
|
||
|
//Dbg_MsgAssert(calcVramBytes <= NumVramBytes, ("Need more memory: %d vs. needed %d", NumVramBytes, calcVramBytes));
|
||
|
|
||
|
// allocate memory for vif stream
|
||
|
#if STEX_USE_CALL
|
||
|
m_VifSize = 272;
|
||
|
#else
|
||
|
m_VifSize = 1024 + NumClutBytes + NumTexBytes; //256; //1216 + (((Width*Height+15)>>4)<<4);
|
||
|
#endif // STEX_USE_CALL
|
||
|
mp_VifData = (uint8 *)Mem::Malloc(m_VifSize);
|
||
|
Dbg_MsgAssert(mp_VifData, ("couldn't malloc memory for vif data"));
|
||
|
Dbg_MsgAssert(((uint32)mp_VifData & 15) == 0, ("vif data not qword aligned"));
|
||
|
|
||
|
// build dma data in this buffer
|
||
|
dma::pLoc = mp_VifData;
|
||
|
|
||
|
// calculate TBP
|
||
|
m_TBP = NextTBP;
|
||
|
|
||
|
// calculate next TBP
|
||
|
//NextTBP = (((TBP<<8)+NumVramBytes+0x1FFF) & 0xFFFFE000) >> 8;
|
||
|
NextTBP = m_TBP + m_NumTexVramBlocks;
|
||
|
|
||
|
// calculate CBP
|
||
|
m_CBP = NextTBP;
|
||
|
if (BitsPerTexel >= 16)
|
||
|
m_NumClutVramBlocks = 0;
|
||
|
else if (BitsPerTexel == 4)
|
||
|
m_NumClutVramBlocks = 4;
|
||
|
else
|
||
|
m_NumClutVramBlocks = (CPSM==PSMCT32 ? 4 : 4);
|
||
|
|
||
|
NextTBP += m_NumClutVramBlocks;
|
||
|
|
||
|
if (IsInVRAM() && Script::GetInt( "vram_debug", false ))
|
||
|
{
|
||
|
Dbg_Message("VRAM Used = %d blocks, texture Size = %d blocks, blocks left = %d out of %d",
|
||
|
NextTBP - FontVramStart, m_NumTexVramBlocks + m_NumClutVramBlocks, FontVramSize - (NextTBP - FontVramStart),FontVramSize);
|
||
|
}
|
||
|
|
||
|
// bail if VRAM would become over-packed
|
||
|
if (IsInVRAM() && (NextTBP > (FontVramStart + FontVramSize)))
|
||
|
{
|
||
|
Dbg_MsgAssert(0, ("SingleTexture: 2D VRAM Buffer Full: %x.", NextTBP));
|
||
|
//pData += NumClutBytes;
|
||
|
//pData = (uint8 *)(((uint)(pData+NumTexBytes+15)) & 0xFFFFFFF0);
|
||
|
// And restore the CurrentDMALoc, which we were just using temporarily.
|
||
|
dma::pLoc = old_dma_loc;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// add clut upload to dma list if necessary
|
||
|
if (BitsPerTexel < 16)
|
||
|
{
|
||
|
#if STEX_USE_CALL
|
||
|
dma::BeginTag(dma::cnt,0);
|
||
|
vif::NOP();
|
||
|
vif::DIRECT(6);
|
||
|
gif::Tag2(gs::A_D,1,PACKED,0,0,0,4);
|
||
|
mp_ClutBitBltBuf = gs::Reg2_pData(gs::BITBLTBUF,PackBITBLTBUF(0,0,0,m_CBP,1,CPSM));
|
||
|
gs::Reg2(gs::TRXPOS, PackTRXPOS(0,0,0,0,0));
|
||
|
if (PSM==PSMT4)
|
||
|
gs::Reg2(gs::TRXREG,PackTRXREG(8,2));
|
||
|
else
|
||
|
gs::Reg2(gs::TRXREG,PackTRXREG(16,16));
|
||
|
gs::Reg2(gs::TRXDIR, 0);
|
||
|
gif::Tag2(0,0,IMAGE,0,0,0,NumClutQWords);
|
||
|
dma::EndTag();
|
||
|
dma::Tag(dma::ref, NumClutQWords, (uint)pData);
|
||
|
vif::NOP();
|
||
|
vif::DIRECT(NumClutQWords);
|
||
|
#else
|
||
|
// clut upload header
|
||
|
gif::Tag2(gs::A_D,1,PACKED,0,0,0,4);
|
||
|
mp_ClutBitBltBuf = gs::Reg2_pData(gs::BITBLTBUF,PackBITBLTBUF(0,0,0,m_CBP,1,CPSM));
|
||
|
gs::Reg2(gs::TRXPOS, PackTRXPOS(0,0,0,0,0));
|
||
|
if (PSM==PSMT4)
|
||
|
gs::Reg2(gs::TRXREG,PackTRXREG(8,2));
|
||
|
else
|
||
|
gs::Reg2(gs::TRXREG,PackTRXREG(16,16));
|
||
|
gs::Reg2(gs::TRXDIR, 0);
|
||
|
gif::Tag2(0,0,IMAGE,0,0,0,NumClutQWords);
|
||
|
|
||
|
// read clut bitmap data
|
||
|
memcpy(dma::pLoc, pData, NumClutBytes);
|
||
|
|
||
|
// step dma location
|
||
|
dma::pLoc += NumClutBytes;
|
||
|
#endif // STEX_USE_CALL
|
||
|
|
||
|
// Save pointer
|
||
|
mp_ClutData = pData;
|
||
|
m_ClutDataSize = NumClutBytes;
|
||
|
|
||
|
// step past clut data, and quadword-align
|
||
|
pData = (uint8 *)(((uint)(pData+NumClutBytes+15)) & 0xFFFFFFF0);
|
||
|
}
|
||
|
|
||
|
#if STEX_USE_CALL
|
||
|
// add texture upload to dma list
|
||
|
dma::BeginTag(dma::cnt,0);
|
||
|
vif::NOP();
|
||
|
vif::DIRECT(6);
|
||
|
gif::Tag2(gs::A_D,1,PACKED,0,0,0,4);
|
||
|
mp_TexBitBltBuf = gs::Reg2_pData(gs::BITBLTBUF,PackBITBLTBUF(0,0,0,m_TBP,TBW,PSM));
|
||
|
gs::Reg2(gs::TRXPOS, PackTRXPOS(0,0,0,0,0));
|
||
|
gs::Reg2(gs::TRXREG, PackTRXREG(Width,Height));
|
||
|
gs::Reg2(gs::TRXDIR, 0);
|
||
|
gif::Tag2(0, 0, IMAGE, 0, 0, 0, NumTexQWords);
|
||
|
dma::EndTag();
|
||
|
dma::Tag(dma::ref, NumTexQWords, (uint)pData);
|
||
|
vif::NOP();
|
||
|
vif::DIRECT(NumTexQWords);
|
||
|
#else
|
||
|
// texture upload header
|
||
|
gif::Tag2(gs::A_D,1,PACKED,0,0,0,4);
|
||
|
mp_TexBitBltBuf = gs::Reg2_pData(gs::BITBLTBUF,PackBITBLTBUF(0,0,0,m_TBP,TBW,PSM));
|
||
|
gs::Reg2(gs::TRXPOS, PackTRXPOS(0,0,0,0,0));
|
||
|
gs::Reg2(gs::TRXREG, PackTRXREG(Width,Height));
|
||
|
gs::Reg2(gs::TRXDIR, 0);
|
||
|
gif::Tag2(0, 0, IMAGE, 0, 0, 0, NumTexQWords);
|
||
|
|
||
|
// read texture bitmap data
|
||
|
memcpy(dma::pLoc, pData, NumTexBytes);
|
||
|
dma::pLoc += NumTexQWords<<4;
|
||
|
#endif // STEX_USE_CALL
|
||
|
|
||
|
// Handle mipmaps, if any (but don't make any DMA packets for them)
|
||
|
if (!(m_flags & mSPRITE) && (MXL > 0))
|
||
|
{
|
||
|
for (j = 1; j < (int) MXL; j++)
|
||
|
{
|
||
|
int mip_width = (TW>=0 ? 1<<TW : 0) >> j;
|
||
|
int mip_height = (TH>=0 ? 1<<TH : 0) >> j;
|
||
|
|
||
|
// Add in mip sizes
|
||
|
NumTexBytes += mip_width * mip_height * BitsPerTexel >> 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Save pointer
|
||
|
mp_PixelData = pData;
|
||
|
m_PixelDataSize = NumTexBytes;
|
||
|
|
||
|
// make entry in texture table
|
||
|
m_RegTEX0 = PackTEX0(m_TBP,TBW,PSM,TW,TH,1,MODULATE,m_CBP,CPSM,0,0,1);
|
||
|
m_RegTEX1 = PackTEX1(1,0,LINEAR,LINEAR,0,0,0);
|
||
|
|
||
|
// update vram base pointer
|
||
|
if (IsInVRAM())
|
||
|
{
|
||
|
FontVramBase = NextTBP;
|
||
|
}
|
||
|
|
||
|
#if STEX_USE_CALL
|
||
|
// Since this data is called, do a return
|
||
|
dma::Tag(dma::ret, 0, 0);
|
||
|
vif::NOP();
|
||
|
vif::NOP();
|
||
|
#endif // STEX_USE_CALL
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
uint ActualSize = (uint) dma::pLoc - (uint) mp_VifData;
|
||
|
Dbg_MsgAssert(ActualSize <= m_VifSize, ("Did not allocate enough DMA space for textures: allocated=%d actual=%d", m_VifSize, ActualSize));
|
||
|
//Dbg_Message("Texture packet size = %d", (int) dma::pLoc - (int) pVifData);
|
||
|
#endif
|
||
|
|
||
|
// And restore the CurrentDMALoc, which we were just using temporarily.
|
||
|
dma::pLoc = old_dma_loc;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Need to do this to textures that are copied directly into the frame buffer
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::FlipTextureVertical()
|
||
|
{
|
||
|
int startrow = 0;
|
||
|
int endrow = m_orig_height - 1;
|
||
|
int rowsize = (m_orig_width * GetBitdepth()) / 8;
|
||
|
|
||
|
uint8 *p_temp_buffer = new uint8[rowsize];
|
||
|
while (startrow < endrow)
|
||
|
{
|
||
|
// Swap rows
|
||
|
memcpy(p_temp_buffer, &(mp_PixelData[startrow * rowsize]),rowsize);
|
||
|
memcpy(&(mp_PixelData[startrow * rowsize]), &(mp_PixelData[endrow * rowsize]), rowsize);
|
||
|
memcpy(&(mp_PixelData[endrow * rowsize]), p_temp_buffer, rowsize);
|
||
|
|
||
|
startrow++;
|
||
|
endrow--;
|
||
|
}
|
||
|
|
||
|
delete p_temp_buffer;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
bool SSingleTexture::AddToVRAM()
|
||
|
{
|
||
|
Dbg_MsgAssert(!(m_flags & mAUTO_ALLOC), ("Can't use AddToVRAM() on a auto allocated texture"));
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
// printf ("++++ Adding %s ++++\n",m_name);
|
||
|
#endif
|
||
|
m_flags |= mALLOC_VRAM;
|
||
|
|
||
|
VRAMNeedsUpdating();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
bool SSingleTexture::RemoveFromVRAM()
|
||
|
{
|
||
|
Dbg_MsgAssert(!(m_flags & mAUTO_ALLOC), ("Can't use RemoveFromVRAM() on a auto allocated texture"));
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
// printf ("---- removing %s ----\n",m_name);
|
||
|
#endif
|
||
|
m_flags &= ~mALLOC_VRAM;
|
||
|
|
||
|
VRAMNeedsUpdating();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::SetAutoAllocate()
|
||
|
{
|
||
|
m_flags |= mAUTO_ALLOC;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::inc_usage_count()
|
||
|
{
|
||
|
m_usage_count++;
|
||
|
m_flags |= mALLOC_VRAM;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::dec_usage_count()
|
||
|
{
|
||
|
if (--m_usage_count == 0)
|
||
|
{
|
||
|
m_flags &= ~mALLOC_VRAM;
|
||
|
}
|
||
|
|
||
|
Dbg_MsgAssert(m_usage_count >= 0, ("Usage Count negative on SSingleTexture %x", m_checksum));
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::UseTexture(bool use)
|
||
|
{
|
||
|
Dbg_MsgAssert(m_flags & mAUTO_ALLOC, ("Can't use UseTexture() on a non-auto allocated texture"));
|
||
|
|
||
|
bool old_alloc = IsInVRAM();
|
||
|
|
||
|
// Update usage
|
||
|
if (use)
|
||
|
{
|
||
|
inc_usage_count();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dec_usage_count();
|
||
|
}
|
||
|
|
||
|
// See if we need to update DMA
|
||
|
if (old_alloc != use)
|
||
|
{
|
||
|
VRAMNeedsUpdating();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
uint16 SSingleTexture::GetOrigWidth() const
|
||
|
{
|
||
|
return m_orig_width;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
uint16 SSingleTexture::GetOrigHeight() const
|
||
|
{
|
||
|
return m_orig_height;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::ReallocateVRAM()
|
||
|
{
|
||
|
// Don't realloc load screens
|
||
|
if (!IsInVRAM()) return;
|
||
|
|
||
|
// calculate TBP
|
||
|
m_TBP = FontVramBase;
|
||
|
FontVramBase += m_NumTexVramBlocks;
|
||
|
|
||
|
// calculate CBP
|
||
|
m_CBP = FontVramBase;
|
||
|
FontVramBase += m_NumClutVramBlocks;
|
||
|
|
||
|
// bail if VRAM would become over-packed
|
||
|
if (FontVramBase > (FontVramStart + FontVramSize))
|
||
|
{
|
||
|
Dbg_MsgAssert(0, ("SingleTexture Realloc: 2D VRAM Buffer Full: %x.", FontVramBase));
|
||
|
}
|
||
|
|
||
|
// Modify the data
|
||
|
gs::ModifyTBP(gs::TEX0_1, (uint32 *) &m_RegTEX0, m_TBP, m_CBP);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSingleTexture::UpdateDMA()
|
||
|
{
|
||
|
// Modify the packets
|
||
|
gs::ModifyTBP(gs::BITBLTBUF, mp_TexBitBltBuf, m_TBP);
|
||
|
if (mp_ClutBitBltBuf)
|
||
|
{
|
||
|
gs::ModifyTBP(gs::BITBLTBUF, mp_ClutBitBltBuf, m_CBP);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// The following Get() calls are very inefficient. They should only be
|
||
|
// used when necessary (i.e. initialization).
|
||
|
//
|
||
|
uint16 SSingleTexture::GetWidth() const
|
||
|
{
|
||
|
sceGsTex0 tex0 = *((sceGsTex0 *) &m_RegTEX0);
|
||
|
uint16 TW = tex0.TW;
|
||
|
//uint16 TW = (uint16) ((RegTEX0 >> 26) & M04);
|
||
|
|
||
|
return 1 << TW;
|
||
|
}
|
||
|
|
||
|
uint16 SSingleTexture::GetHeight() const
|
||
|
{
|
||
|
sceGsTex0 tex0 = *((sceGsTex0 *) &m_RegTEX0);
|
||
|
uint16 TH = tex0.TH;
|
||
|
//uint16 TH = (uint16) ((RegTEX0 >> 30) & M04);
|
||
|
|
||
|
return 1 << TH;
|
||
|
}
|
||
|
|
||
|
uint8 SSingleTexture::GetBitdepth() const
|
||
|
{
|
||
|
sceGsTex0 tex0 = *((sceGsTex0 *) &m_RegTEX0);
|
||
|
uint PSM = tex0.PSM;
|
||
|
|
||
|
switch (PSM)
|
||
|
{
|
||
|
case PSMCT32:
|
||
|
return 32;
|
||
|
break;
|
||
|
case PSMCT24:
|
||
|
return 24;
|
||
|
break;
|
||
|
case PSMCT16:
|
||
|
return 16;
|
||
|
break;
|
||
|
case PSMT8:
|
||
|
return 8;
|
||
|
break;
|
||
|
case PSMT4:
|
||
|
return 4;
|
||
|
break;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 SSingleTexture::GetClutBitdepth() const
|
||
|
{
|
||
|
sceGsTex0 tex0 = *((sceGsTex0 *) &m_RegTEX0);
|
||
|
uint CPSM = tex0.CPSM;
|
||
|
|
||
|
switch (CPSM)
|
||
|
{
|
||
|
case PSMCT32:
|
||
|
return 32;
|
||
|
break;
|
||
|
case PSMCT24:
|
||
|
return 24;
|
||
|
break;
|
||
|
case PSMCT16:
|
||
|
return 16;
|
||
|
break;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 SSingleTexture::GetNumMipmaps() const
|
||
|
{
|
||
|
return 1; // By definition for this class
|
||
|
}
|
||
|
|
||
|
bool SSingleTexture::IsTransparent() const
|
||
|
{
|
||
|
//Dbg_Error("Not working yet");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
uint32 SSingleTexture::bitdepth_to_psm(int bitdepth)
|
||
|
{
|
||
|
switch (bitdepth)
|
||
|
{
|
||
|
case 32:
|
||
|
return PSMCT32;
|
||
|
break;
|
||
|
case 24:
|
||
|
return PSMCT24;
|
||
|
break;
|
||
|
case 16:
|
||
|
return PSMCT16;
|
||
|
break;
|
||
|
case 8:
|
||
|
return PSMT8;
|
||
|
break;
|
||
|
case 4:
|
||
|
return PSMT4;
|
||
|
break;
|
||
|
default:
|
||
|
Dbg_MsgAssert(0, ("Bitdepth %d is not supported on PS2", bitdepth));
|
||
|
return PSMCT32;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
void SSingleTexture::sPrintAllTextureInfo()
|
||
|
{
|
||
|
for (SSingleTexture *pTexture=SSingleTexture::sp_stexture_list; pTexture; pTexture=pTexture->mp_next)
|
||
|
{
|
||
|
Dbg_Message("Texture name %s: using vram: %d, blocks %d", pTexture->m_name, pTexture->IsInVRAM(),
|
||
|
pTexture->m_NumTexVramBlocks + pTexture->m_NumClutVramBlocks);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSingleTexture::sPrintAllocatedTextureInfo()
|
||
|
{
|
||
|
for (SSingleTexture *pTexture=SSingleTexture::sp_stexture_list; pTexture; pTexture=pTexture->mp_next)
|
||
|
{
|
||
|
if (!pTexture->IsInVRAM())
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Dbg_Message("Texture name %s: using vram: <true>, blocks %d", pTexture->m_name,
|
||
|
pTexture->m_NumTexVramBlocks + pTexture->m_NumClutVramBlocks);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* SScissorWindow */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
SScissorWindow DefaultScissorWindow;
|
||
|
|
||
|
void SetTextWindow(uint16 x0, uint16 x1, uint16 y0, uint16 y1)
|
||
|
{
|
||
|
DefaultScissorWindow.SetScissor(x0, y0, x1, y1);
|
||
|
}
|
||
|
|
||
|
void SScissorWindow::SetScissor(uint16 x0, uint16 y0, uint16 x1, uint16 y1)
|
||
|
{
|
||
|
m_RegSCISSOR = (uint64)x0 | (uint64)x1<<16 | (uint64)y0<<32 | (uint64)y1<<48;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* SDraw2D */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
float SDraw2D::s_screen_scale_x = 1.0f;
|
||
|
float SDraw2D::s_screen_scale_y = 1.0f;
|
||
|
|
||
|
bool SDraw2D::s_constant_z_enabled = false;
|
||
|
uint32 SDraw2D::s_constant_z = 0x7FFFFF;
|
||
|
|
||
|
SDraw2D * SDraw2D::sp_2D_sorted_draw_list = NULL;
|
||
|
SDraw2D * SDraw2D::sp_2D_zbuffer_draw_list = NULL;
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SDraw2D::SDraw2D(float pri, bool hide) :
|
||
|
m_hidden(hide),
|
||
|
m_use_zbuffer(false),
|
||
|
m_pri(pri),
|
||
|
m_z(0xFFFFFF),
|
||
|
mp_scissor_window(&DefaultScissorWindow)
|
||
|
{
|
||
|
mp_next = NULL;
|
||
|
|
||
|
// add to sorted draw list
|
||
|
if (!m_hidden)
|
||
|
{
|
||
|
InsertSortedDrawList(&sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SDraw2D::~SDraw2D()
|
||
|
{
|
||
|
// Try removing from draw list
|
||
|
if (m_use_zbuffer)
|
||
|
{
|
||
|
RemoveDrawList(&sp_2D_zbuffer_draw_list);
|
||
|
} else {
|
||
|
RemoveDrawList(&sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::SetPriority(float pri)
|
||
|
{
|
||
|
if (m_pri != pri)
|
||
|
{
|
||
|
m_pri = pri;
|
||
|
|
||
|
// By removing and re-inserting, we re-sort the list
|
||
|
if (!m_hidden)
|
||
|
{
|
||
|
if (m_use_zbuffer)
|
||
|
{
|
||
|
RemoveDrawList(&sp_2D_zbuffer_draw_list);
|
||
|
} else {
|
||
|
RemoveDrawList(&sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
InsertSortedDrawList(&sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
|
||
|
m_use_zbuffer = false;
|
||
|
m_z = 0xFFFFFF;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::SetZValue(uint32 z)
|
||
|
{
|
||
|
if (m_z != z)
|
||
|
{
|
||
|
m_z = z;
|
||
|
|
||
|
// Switch lists, if necessary
|
||
|
if (!m_use_zbuffer && !m_hidden)
|
||
|
{
|
||
|
RemoveDrawList(&sp_2D_sorted_draw_list);
|
||
|
InsertDrawList(&sp_2D_zbuffer_draw_list);
|
||
|
}
|
||
|
|
||
|
m_use_zbuffer = true;
|
||
|
m_pri = 0.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::SetHidden(bool hide)
|
||
|
{
|
||
|
if (m_hidden != hide)
|
||
|
{
|
||
|
m_hidden = hide;
|
||
|
if (m_use_zbuffer)
|
||
|
{
|
||
|
if (hide)
|
||
|
{
|
||
|
RemoveDrawList(&sp_2D_zbuffer_draw_list);
|
||
|
} else {
|
||
|
InsertDrawList(&sp_2D_zbuffer_draw_list);
|
||
|
}
|
||
|
} else {
|
||
|
if (hide)
|
||
|
{
|
||
|
RemoveDrawList(&sp_2D_sorted_draw_list);
|
||
|
} else {
|
||
|
InsertSortedDrawList(&sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::SetScissorWindow(SScissorWindow *p_scissor)
|
||
|
{
|
||
|
if (p_scissor)
|
||
|
{
|
||
|
mp_scissor_window = p_scissor;
|
||
|
} else {
|
||
|
mp_scissor_window = &DefaultScissorWindow;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::DrawAll()
|
||
|
{
|
||
|
// Figure out screen scale (for PAL mode)
|
||
|
CalcScreenScale();
|
||
|
|
||
|
// Init certain GS registers for 2D drawing
|
||
|
dma::BeginTag(dma::cnt, 0);
|
||
|
gs::BeginPrim(ABS,0,0);
|
||
|
gs::Reg1(gs::CLAMP_1,PackCLAMP(CLAMP,CLAMP,0,0,0,0)); // Man, I hope this is the last time I fix the CLAMP bug
|
||
|
gs::Reg1(gs::XYOFFSET_1, PackXYOFFSET(XOFFSET, YOFFSET));
|
||
|
gs::Reg1(gs::TEST_1, PackTEST(1,AGREATER,0,KEEP,0,0,1,ZGEQUAL));
|
||
|
gs::EndPrim(0);
|
||
|
dma::EndTag();
|
||
|
|
||
|
// Draw items needing ZBuffer first
|
||
|
DrawList(sp_2D_zbuffer_draw_list);
|
||
|
if (s_constant_z_enabled)
|
||
|
{
|
||
|
DrawList(sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
|
||
|
// Turn off ZBuffer
|
||
|
dma::BeginTag(dma::cnt, 0);
|
||
|
gs::BeginPrim(ABS,0,0);
|
||
|
gs::Reg1(gs::TEST_1, PackTEST(0,0,0,0,0,0,1,ZGEQUAL));
|
||
|
gs::EndPrim(0);
|
||
|
dma::EndTag();
|
||
|
|
||
|
// Draw the sorted list now if we aren't using constant Z
|
||
|
if (!s_constant_z_enabled)
|
||
|
{
|
||
|
DrawList(sp_2D_sorted_draw_list);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::DrawList(SDraw2D *pDraw)
|
||
|
{
|
||
|
while (pDraw)
|
||
|
{
|
||
|
if (!pDraw->m_hidden)
|
||
|
{
|
||
|
pDraw->BeginDraw();
|
||
|
pDraw->Draw();
|
||
|
pDraw->EndDraw();
|
||
|
}
|
||
|
pDraw = pDraw->mp_next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::EnableConstantZValue(bool enable)
|
||
|
{
|
||
|
s_constant_z_enabled = enable;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::SetConstantZValue(uint32 z)
|
||
|
{
|
||
|
s_constant_z = z;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
uint32 SDraw2D::GetConstantZValue()
|
||
|
{
|
||
|
return s_constant_z;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Figure out screen scale (mainly for PAL mode)
|
||
|
//
|
||
|
|
||
|
void SDraw2D::CalcScreenScale()
|
||
|
{
|
||
|
if (Config::NTSC())
|
||
|
{
|
||
|
s_screen_scale_x = 1.0f;
|
||
|
s_screen_scale_y = 1.0f;
|
||
|
} else {
|
||
|
s_screen_scale_x = ((float) HRES_PAL) / ((float) HRES_NTSC);
|
||
|
s_screen_scale_y = ((float) VRES_PAL) / ((float) VRES_NTSC);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::InsertSortedDrawList(SDraw2D **p_list)
|
||
|
{
|
||
|
Dbg_Assert(!m_use_zbuffer);
|
||
|
|
||
|
if (!*p_list || // Empty List
|
||
|
(m_pri <= (*p_list)->m_pri)) // Start List
|
||
|
{
|
||
|
mp_next = *p_list;
|
||
|
*p_list = this;
|
||
|
} else { // Insert
|
||
|
SDraw2D *p_cur = *p_list;
|
||
|
|
||
|
// Find where to insert
|
||
|
while(p_cur->mp_next)
|
||
|
{
|
||
|
if (m_pri <= p_cur->mp_next->m_pri)
|
||
|
break;
|
||
|
|
||
|
p_cur = p_cur->mp_next;
|
||
|
}
|
||
|
|
||
|
// Insert at this point
|
||
|
mp_next = p_cur->mp_next;
|
||
|
p_cur->mp_next = this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::InsertDrawList(SDraw2D **p_list)
|
||
|
{
|
||
|
if (!*p_list) // Empty List
|
||
|
{
|
||
|
mp_next = *p_list;
|
||
|
*p_list = this;
|
||
|
} else { // Insert at end of list
|
||
|
SDraw2D *p_cur = *p_list;
|
||
|
|
||
|
while(p_cur->mp_next)
|
||
|
{
|
||
|
p_cur = p_cur->mp_next;
|
||
|
}
|
||
|
|
||
|
mp_next = p_cur->mp_next;
|
||
|
p_cur->mp_next = this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SDraw2D::RemoveDrawList(SDraw2D **p_list)
|
||
|
{
|
||
|
// Take out from draw list
|
||
|
if (*p_list == this)
|
||
|
{
|
||
|
*p_list = mp_next;
|
||
|
}
|
||
|
else if (*p_list)
|
||
|
{
|
||
|
SDraw2D *p_cur = *p_list;
|
||
|
|
||
|
while(p_cur->mp_next)
|
||
|
{
|
||
|
if (p_cur->mp_next == this)
|
||
|
{
|
||
|
p_cur->mp_next = mp_next;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
p_cur = p_cur->mp_next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* SSprite */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SSprite::SSprite(float pri) : SDraw2D(pri, true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
SSprite::~SSprite()
|
||
|
{
|
||
|
// Deallocates the underlying texture, if there was one
|
||
|
SetHidden(true);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSprite::SetHidden(bool hide)
|
||
|
{
|
||
|
bool old_hide = IsHidden();
|
||
|
|
||
|
// Do the actual hide call
|
||
|
SDraw2D::SetHidden(hide);
|
||
|
|
||
|
// Make sure vram status is correct if we changed hidden states
|
||
|
if (mp_texture && (old_hide != hide))
|
||
|
{
|
||
|
mp_texture->UseTexture(!hide);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSprite::SetTexture(SSingleTexture *p_texture)
|
||
|
{
|
||
|
// Set auto VRAM allocate
|
||
|
if (p_texture && (mp_texture != p_texture))
|
||
|
{
|
||
|
p_texture->SetAutoAllocate();
|
||
|
|
||
|
// Change usage counts if we aren't hidden
|
||
|
if (!IsHidden())
|
||
|
{
|
||
|
p_texture->UseTexture(true);
|
||
|
if (mp_texture)
|
||
|
{
|
||
|
mp_texture->UseTexture(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mp_texture = p_texture;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSprite::BeginDraw()
|
||
|
{
|
||
|
|
||
|
// dma tag
|
||
|
dma::BeginTag(dma::cnt, 0);
|
||
|
|
||
|
vu1::Buffer = vu1::Loc;
|
||
|
|
||
|
int tme_flag = (mp_texture) ? TME : 0;
|
||
|
|
||
|
Dbg_Assert(GetScissorWindow());
|
||
|
|
||
|
// GS context
|
||
|
gs::BeginPrim(ABS,0,0);
|
||
|
gs::Reg1(gs::SCISSOR_1, GetScissorWindow()->GetScissorReg());
|
||
|
if (mp_texture)
|
||
|
{
|
||
|
Dbg_MsgAssert(mp_texture->IsInVRAM(), ("Can't draw sprite when its texture 0x%x, (%s) is not in VRAM.",mp_texture->m_checksum,mp_texture->m_name));
|
||
|
|
||
|
gs::Reg1(gs::TEX0_1, mp_texture->m_RegTEX0);
|
||
|
gs::Reg1(gs::TEX1_1, mp_texture->m_RegTEX1);
|
||
|
}
|
||
|
gs::Reg1(gs::ALPHA_1, PackALPHA(0,1,0,1,0));
|
||
|
gs::Reg1(gs::COLCLAMP, PackCOLCLAMP(1));
|
||
|
gs::Reg1(gs::RGBAQ, (uint64)m_rgba);
|
||
|
gs::EndPrim(0);
|
||
|
|
||
|
// unpack giftag
|
||
|
vif::UNPACK(0, V4_32, 1, ABS, UNSIGNED, 0);
|
||
|
if (m_rot == 0.0f)
|
||
|
{
|
||
|
gif::BeginTagImmediate(gs::UV|gs::XYZ2<<4, 2, PACKED, SPRITE|tme_flag|FST|ABE, 1, VU1_ADDR(GSPrim));
|
||
|
} else {
|
||
|
gif::BeginTagImmediate(gs::UV|gs::XYZ2<<4, 2, PACKED, TRISTRIP|tme_flag|FST|ABE, 1, VU1_ADDR(GSPrim));
|
||
|
}
|
||
|
|
||
|
// begin unpack for uv/xyz's
|
||
|
vif::BeginUNPACK(0, V4_32, ABS, SIGNED, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSprite::Draw()
|
||
|
{
|
||
|
Dbg_Assert(GetScissorWindow());
|
||
|
|
||
|
const int start_screen_x = XOFFSET + ((GetScissorWindow()->GetScissorReg() & 0x7FF) << 4) + ((int) (m_xpos * s_screen_scale_x * 16.0f));
|
||
|
const int start_screen_y = YOFFSET + ((GetScissorWindow()->GetScissorReg() >> 32 & 0x7FF) << 4) + ((int) (m_ypos * s_screen_scale_y * 16.0f));
|
||
|
|
||
|
uint16 u0,v0,u1,v1;
|
||
|
float x0,y0,x1,y1;
|
||
|
uint32 z;
|
||
|
|
||
|
uint16 tex_height = (mp_texture) ? mp_texture->GetHeight() : m_height;
|
||
|
|
||
|
u0 = /* 8 +*/ (0);
|
||
|
v0 = /*-8 +*/ (tex_height << 4);
|
||
|
u1 = /* 8 +*/ (m_width << 4);
|
||
|
v1 = /*-8 +*/ ((tex_height - m_height) << 4);
|
||
|
|
||
|
// Check for flip
|
||
|
float abs_scale_x = m_scale_x;// * s_screen_scale_x;
|
||
|
float abs_scale_y = m_scale_y;// * s_screen_scale_y;
|
||
|
if (abs_scale_x < 0.0f)
|
||
|
{
|
||
|
uint16 temp = u0;
|
||
|
u0 = u1;
|
||
|
u1 = temp;
|
||
|
abs_scale_x = -abs_scale_x;
|
||
|
}
|
||
|
if (abs_scale_y < 0.0f)
|
||
|
{
|
||
|
uint16 temp = v0;
|
||
|
v0 = v1;
|
||
|
v1 = temp;
|
||
|
abs_scale_y = -abs_scale_y;
|
||
|
}
|
||
|
|
||
|
x0 = -m_xhot * 16.0f * abs_scale_x;
|
||
|
y0 = -m_yhot * 16.0f * abs_scale_y;
|
||
|
|
||
|
x1 = x0 + ((float) (u1 - u0) * abs_scale_x);
|
||
|
y1 = y0 + ((float) (v0 - v1) * abs_scale_y);
|
||
|
|
||
|
z = s_constant_z_enabled ? s_constant_z : GetZValue();
|
||
|
|
||
|
// Flip V if texture is inverted in VRAM
|
||
|
if (mp_texture && mp_texture->IsInverted())
|
||
|
{
|
||
|
uint16 temp = v0;
|
||
|
v0 = v1;
|
||
|
v1 = temp;
|
||
|
}
|
||
|
|
||
|
// Check for rotation
|
||
|
if (m_rot != 0.0f)
|
||
|
{
|
||
|
Mth::Vector p0(x0, y0, 0.0f, 0.0f);
|
||
|
Mth::Vector p1(x1, y0, 0.0f, 0.0f);
|
||
|
Mth::Vector p2(x0, y1, 0.0f, 0.0f);
|
||
|
Mth::Vector p3(x1, y1, 0.0f, 0.0f);
|
||
|
|
||
|
p0.RotateZ(m_rot);
|
||
|
p1.RotateZ(m_rot);
|
||
|
p2.RotateZ(m_rot);
|
||
|
p3.RotateZ(m_rot);
|
||
|
|
||
|
//printf("Before (%d, %d) - (%d, %d)\n", x0, y0, x1, y1);
|
||
|
//printf("After (%d, %d) - (%d, %d)\n", (int) p0.GetX(), (int) p0.GetY(), (int) p3.GetX(), (int) p3.GetY());
|
||
|
|
||
|
int xi0 = ((int) (p0.GetX() * s_screen_scale_x)) + start_screen_x;
|
||
|
int xi1 = ((int) (p1.GetX() * s_screen_scale_x)) + start_screen_x;
|
||
|
int xi2 = ((int) (p2.GetX() * s_screen_scale_x)) + start_screen_x;
|
||
|
int xi3 = ((int) (p3.GetX() * s_screen_scale_x)) + start_screen_x;
|
||
|
int yi0 = ((int) (p0.GetY() * s_screen_scale_y)) + start_screen_y;
|
||
|
int yi1 = ((int) (p1.GetY() * s_screen_scale_y)) + start_screen_y;
|
||
|
int yi2 = ((int) (p2.GetY() * s_screen_scale_y)) + start_screen_y;
|
||
|
int yi3 = ((int) (p3.GetY() * s_screen_scale_y)) + start_screen_y;
|
||
|
|
||
|
// Cull, if necessary
|
||
|
if (NeedsCulling() && ((xi0 | xi1 | xi2 | xi3 | yi0 | yi1 | yi2 | yi3) & 0xFFFF0000))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Do a TRISTRIP
|
||
|
vif::StoreV4_32(u0,v0,0,0);
|
||
|
vif::StoreV4_32(xi0, yi0, z, 0);
|
||
|
vif::StoreV4_32(u1,v0,0,0);
|
||
|
vif::StoreV4_32(xi1, yi1, z, 0);
|
||
|
vif::StoreV4_32(u0,v1,0,0);
|
||
|
vif::StoreV4_32(xi2, yi2, z, 0);
|
||
|
vif::StoreV4_32(u1,v1,0,0);
|
||
|
vif::StoreV4_32(xi3, yi3, z, 0);
|
||
|
} else {
|
||
|
// Just outputting two points for a SPRITE
|
||
|
int xi0 = ((int) (x0 * s_screen_scale_x)) + start_screen_x;
|
||
|
int xi1 = ((int) (x1 * s_screen_scale_x)) + start_screen_x;
|
||
|
int yi0 = ((int) (y0 * s_screen_scale_y)) + start_screen_y;
|
||
|
int yi1 = ((int) (y1 * s_screen_scale_y)) + start_screen_y;
|
||
|
|
||
|
// Cull, if necessary
|
||
|
if (NeedsCulling() && ((xi0 | xi1 | yi0 | yi1) & 0xFFFF0000))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
vif::StoreV4_32(u0,v0,0,0);
|
||
|
vif::StoreV4_32(xi0,yi0,z,0);
|
||
|
vif::StoreV4_32(u1,v1,0,0);
|
||
|
vif::StoreV4_32(xi1,yi1,z,0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
|
||
|
void SSprite::EndDraw(void)
|
||
|
{
|
||
|
vif::EndUNPACK();
|
||
|
gif::EndTagImmediate(1);
|
||
|
vif::MSCAL(VU1_ADDR(Parser));
|
||
|
dma::EndTag();
|
||
|
}
|
||
|
|
||
|
} // namespace NxPs2
|
||
|
|