summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/TxdStore.cpp43
-rw-r--r--src/TxdStore.h1
-rw-r--r--src/render/Clouds.cpp1
-rw-r--r--src/render/Font.cpp515
-rw-r--r--src/render/Font.h108
-rw-r--r--src/render/Sprite.cpp347
-rw-r--r--src/render/Sprite.h26
-rw-r--r--src/render/Sprite2d.cpp498
-rw-r--r--src/render/Sprite2d.h49
-rw-r--r--src/rw.cpp1
10 files changed, 1382 insertions, 207 deletions
diff --git a/src/TxdStore.cpp b/src/TxdStore.cpp
index ba8eecb9..a5fc1758 100644
--- a/src/TxdStore.cpp
+++ b/src/TxdStore.cpp
@@ -4,6 +4,9 @@
#include "Streaming.h"
#include "TxdStore.h"
+WRAPPER RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream) { EAXJMP(0x5924A0); }
+
+
CPool<TxdDef,TxdDef> *&CTxdStore::ms_pTxdPool = *(CPool<TxdDef,TxdDef>**)0x8F5FB8;
RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC;
@@ -32,6 +35,15 @@ CTxdStore::AddTxdSlot(const char *name)
return ms_pTxdPool->GetJustIndex(def);
}
+void
+CTxdStore::RemoveTxdSlot(int slot)
+{
+ TxdDef *def = GetSlot(slot);
+ if(def->texDict)
+ RwTexDictionaryDestroy(def->texDict);
+ ms_pTxdPool->Delete(def);
+}
+
int
CTxdStore::FindTxdSlot(const char *name)
{
@@ -98,33 +110,34 @@ CTxdStore::RemoveRefWithoutDelete(int slot)
GetSlot(slot)->refCount--;
}
-/*
bool
CTxdStore::LoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
- if(!rw::findChunk(stream, rw::ID_TEXDICTIONARY, nil, nil)){
- return false;
- }else{
- def->texDict = rw::TexDictionary::streamRead(stream);
- convertTxd(def->texDict);
+
+ if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){
+ def->texDict = RwTexDictionaryGtaStreamRead(stream);
return def->texDict != nil;
}
+ printf("Failed to load TXD\n");
+ return false;
}
bool
CTxdStore::LoadTxd(int slot, const char *filename)
{
- rw::StreamFile stream;
- if(stream.open(getPath(filename), "rb")){
- LoadTxd(slot, &stream);
- stream.close();
- return true;
- }
- printf("Failed to open TXD\n");
- return false;
+ RwStream *stream;
+ bool ret;
+
+ ret = false;
+ _rwD3D8TexDictionaryEnableRasterFormatConversion(true);
+ do
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
+ while(stream == nil);
+ ret = LoadTxd(slot, stream);
+ RwStreamClose(stream, nil);
+ return ret;
}
-*/
void
CTxdStore::RemoveTxd(int slot)
diff --git a/src/TxdStore.h b/src/TxdStore.h
index 2cfef0e0..a9526cf2 100644
--- a/src/TxdStore.h
+++ b/src/TxdStore.h
@@ -16,6 +16,7 @@ public:
static void Initialize(void);
static void Shutdown(void);
static int AddTxdSlot(const char *name);
+ static void RemoveTxdSlot(int slot);
static int FindTxdSlot(const char *name);
static char *GetTxdName(int slot);
static void PushCurrentTxd(void);
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp
index 64bc93e8..6854c80c 100644
--- a/src/render/Clouds.cpp
+++ b/src/render/Clouds.cpp
@@ -1,6 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "Sprite.h"
+#include "Sprite2d.h"
#include "General.h"
#include "Coronas.h"
#include "Camera.h"
diff --git a/src/render/Font.cpp b/src/render/Font.cpp
new file mode 100644
index 00000000..b145bf38
--- /dev/null
+++ b/src/render/Font.cpp
@@ -0,0 +1,515 @@
+#include "common.h"
+#include "patcher.h"
+#include "Sprite2d.h"
+#include "TxdStore.h"
+#include "Font.h"
+
+CFontDetails &CFont::Details = *(CFontDetails*)0x8F317C;
+int16 &CFont::NewLine = *(int16*)0x95CC94;
+CSprite2d *CFont::Sprite = (CSprite2d*)0x95CC04;
+
+int16 CFont::Size[3][193] = {
+ {
+ 13, 12, 31, 35, 23, 35, 31, 9, 14, 15, 25, 30, 11, 17, 13, 31,
+ 23, 16, 22, 21, 24, 23, 23, 20, 23, 22, 10, 35, 26, 26, 26, 26,
+ 30, 26, 24, 23, 24, 22, 21, 24, 26, 10, 20, 26, 22, 29, 26, 25,
+ 23, 25, 24, 24, 22, 25, 24, 29, 29, 23, 25, 37, 22, 37, 35, 37,
+ 35, 21, 22, 21, 21, 22, 13, 22, 21, 10, 16, 22, 11, 32, 21, 21,
+ 23, 22, 16, 20, 14, 21, 20, 30, 25, 21, 21, 33, 33, 33, 33, 35,
+ 27, 27, 27, 27, 32, 24, 23, 23, 23, 23, 11, 11, 11, 11, 26, 26,
+ 26, 26, 26, 26, 26, 25, 26, 21, 21, 21, 21, 32, 23, 22, 22, 22,
+ 22, 11, 11, 11, 11, 22, 22, 22, 22, 22, 22, 22, 22, 26, 21, 24,
+ 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 18, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 20
+ },
+
+ {
+ 13, 9, 21, 35, 23, 35, 35, 11, 35, 35, 25, 35, 11, 17, 13, 33,
+ 28, 14, 22, 21, 24, 23, 23, 21, 23, 22, 10, 35, 13, 35, 13, 33,
+ 5, 25, 22, 23, 24, 21, 21, 24, 24, 9, 20, 24, 21, 27, 25, 25,
+ 22, 25, 23, 20, 23, 23, 23, 31, 23, 23, 23, 37, 33, 37, 35, 37,
+ 35, 21, 19, 19, 21, 19, 17, 21, 21, 8, 17, 18, 14, 24, 21, 21,
+ 20, 22, 19, 20, 20, 19, 20, 26, 21, 20, 21, 33, 33, 33, 33, 35,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 16
+ },
+
+ {
+ 15, 14, 16, 25, 19, 26, 22, 11, 18, 18, 27, 26, 13, 19, 9, 27,
+ 19, 18, 19, 19, 22, 19, 20, 18, 19, 20, 12, 32, 15, 32, 15, 35,
+ 15, 19, 19, 19, 19, 19, 16, 19, 20, 9, 19, 20, 14, 29, 19, 20,
+ 19, 19, 19, 19, 21, 19, 20, 32, 20, 19, 19, 33, 31, 39, 37, 39,
+ 37, 21, 21, 21, 23, 21, 19, 23, 23, 10, 19, 20, 16, 26, 23, 23,
+ 20, 20, 20, 22, 21, 22, 22, 26, 22, 22, 23, 35, 35, 35, 35, 37,
+ 19, 19, 19, 19, 29, 19, 19, 19, 19, 19, 9, 9, 9, 9, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 30, 19, 19, 19, 19,
+ 19, 10, 10, 10, 10, 19, 19, 19, 19, 19, 19, 19, 19, 19, 23, 35,
+ 12, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19
+ }
+};
+
+uint16 foreign_table[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 177, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 175,
+ 128, 129, 130, 0, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+ 0, 173, 142, 143, 144, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 150,
+ 151, 152, 153, 0, 154, 0, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 0, 174, 165, 166, 167, 0, 168, 0, 0, 169, 170, 171, 172, 0, 0, 0,
+};
+
+void
+CFont::Initialise(void)
+{
+ int slot;
+
+ slot = CTxdStore::AddTxdSlot("fonts");
+ CTxdStore::LoadTxd(slot, "MODELS/FONTS.TXD");
+ CTxdStore::AddRef(slot);
+ CTxdStore::PushCurrentTxd();
+ CTxdStore::SetCurrentTxd(slot);
+ Sprite[0].SetTexture("font2", "font2_mask");
+ Sprite[1].SetTexture("pager", "pager_mask");
+ Sprite[2].SetTexture("font1", "font1_mask");
+ SetScale(1.0f, 1.0f);
+ SetSlantRefPoint(SCREENW, 0.0f);
+ SetSlant(0.0);
+ SetColor(CRGBA(0xFF, 0xFF, 0xFF, 0));
+ SetJustifyOff();
+ SetCentreOff();
+ SetWrapx(640.0f);
+ SetCentreSize(640.0f);
+ SetBackgroundOff();
+ SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80));
+ SetBackGroundOnlyTextOff();
+ SetPropOn();
+ SetFontStyle(0);
+ SetRightJustifyWrap(0.0);
+ SetAlphaFade(255.0f);
+ SetDropShadowPosition(0);
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CFont::Shutdown(void)
+{
+ Sprite[0].Delete();
+ Sprite[1].Delete();
+ Sprite[2].Delete();
+ CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("fonts"));
+}
+
+void
+CFont::InitPerFrame(void)
+{
+ Details.bank = CSprite2d::GetBank(30, Sprite[0].m_pTexture);
+ CSprite2d::GetBank(15, Sprite[1].m_pTexture);
+ CSprite2d::GetBank(15, Sprite[2].m_pTexture);
+ SetDropShadowPosition(0);
+ NewLine = 0;
+}
+
+void
+CFont::PrintChar(float x, float y, uint16 c)
+{
+ if(x <= 0.0f || x >= SCREENW ||
+ y <= 0.0f || y >= SCREENH) // BUG: game uses SCREENW again
+ return;
+
+ float w = GetCharacterWidth(c) / 32.0f;
+ float xoff = c & 0xF;
+ float yoff = c >> 4;
+
+ if(Details.style == 0 || Details.style == 2){
+ if(Details.dropShadowPosition != 0){
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x + Details.dropShadowPosition,
+ y + Details.dropShadowPosition,
+ x + Details.dropShadowPosition + 32.0f * Details.scaleX * 1.0f,
+ y + Details.dropShadowPosition + 40.0f * Details.scaleY * 0.5f),
+ Details.dropColor,
+ xoff/16.0f, yoff/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
+ xoff/16.0f, (yoff+1.0f)/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.0001f);
+ }
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x, y,
+ x + 32.0f * Details.scaleX * 1.0f,
+ y + 40.0f * Details.scaleY * 0.5f),
+ Details.color,
+ xoff/16.0f, yoff/12.8f,
+ (xoff+1.0f)/16.0f - 0.001f, yoff/12.8f,
+ xoff/16.0f, (yoff+1.0f)/12.8f - 0.002f,
+ (xoff+1.0f)/16.0f - 0.001f, (yoff+1.0f)/12.8f - 0.002f);
+ }else{
+ CSprite2d::AddSpriteToBank(Details.bank + Details.style, // BUG: game doesn't add bank
+ CRect(x, y,
+ x + 32.0f * Details.scaleX * w,
+ y + 32.0f * Details.scaleY * 0.5f),
+ Details.color,
+ xoff/16.0f, yoff/16.0f,
+ (xoff+w)/16.0f, yoff/16.0f,
+ xoff/16.0f, (yoff+1.0f)/16.0f,
+ (xoff+w)/16.0f - 0.0001f, (yoff+1.0f)/16.0f - 0.0001f);
+ }
+}
+
+void
+CFont::PrintString(float xstart, float ystart, uint16 *s)
+{
+ CRect rect;
+ int numSpaces;
+ float lineLength;
+ float x, y;
+ bool first;
+ uint16 *start, *t;
+
+ if(*s == '*')
+ return;
+
+ if(Details.background){
+ GetNumberLines(xstart, ystart, s); // BUG: result not used
+ GetTextRect(&rect, xstart, ystart, s);
+ CSprite2d::DrawRect(rect, Details.backgroundColor);
+ }
+
+ lineLength = 0.0f;
+ numSpaces = 0;
+ first = true;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+ start = s;
+
+ // This is super ugly, I blame R*
+ for(;;){
+ for(;;){
+ for(;;){
+ if(*s == '\0')
+ return;
+ int xend = Details.centre ? Details.centreSize :
+ Details.rightJustify ? xstart - Details.rightJustifyWrap :
+ Details.wrapX;
+ if(x + GetStringWidth(s) > xend && !first){
+ // flush line
+ float spaceWidth = !Details.justify || Details.centre ? 0.0f :
+ (Details.wrapX - lineLength) / numSpaces;
+ float xleft = Details.centre ? xstart - x/2 :
+ Details.rightJustify ? xstart - x :
+ xstart;
+ PrintString(xleft, y, start, s, spaceWidth);
+ // reset things
+ lineLength = 0.0f;
+ numSpaces = 0;
+ first = true;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ start = s;
+ }else
+ break;
+ }
+ // advance by one word
+ t = GetNextSpace(s);
+ if(t[0] == '\0' ||
+ t[0] == ' ' && t[1] == '\0')
+ break;
+ if(!first)
+ numSpaces++;
+ first = false;
+ x += GetStringWidth(s) + GetCharacterSize(*t - ' ');
+ lineLength = x;
+ s = t+1;
+ }
+ // print rest
+ if(t[0] == ' ' && t[1] == '\0')
+ t[0] = '\0';
+ x += GetStringWidth(s);
+ s = t;
+ float xleft = Details.centre ? xstart - x/2 :
+ Details.rightJustify ? xstart - x :
+ xstart;
+ PrintString(xleft, y, start, s, 0.0f);
+ }
+}
+
+int
+CFont::GetNumberLines(float xstart, float ystart, uint16 *s)
+{
+ int n;
+ float x, y;
+ uint16 *t;
+
+ n = 0;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+
+ while(*s){
+ if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
+ // reached end of line
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ n++;
+ // Why even?
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ }else{
+ // still space in current line
+ t = GetNextSpace(s);
+ if(*t == '\0'){
+ // end of string
+ x += GetStringWidth(s);
+ n++;
+ s = t;
+ }else{
+ x += GetStringWidth(s);
+ x += GetCharacterSize(*t - ' ');
+ s = t+1;
+ }
+ }
+ }
+
+ return n;
+}
+
+void
+CFont::GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s)
+{
+ int numLines;
+ float x, y;
+ int16 maxlength;
+ uint16 *t;
+
+ maxlength = 0;
+ numLines = 0;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ y = ystart;
+
+ while(*s){
+ if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){
+ // reached end of line
+ if(x > maxlength)
+ maxlength = x;
+ if(Details.centre || Details.rightJustify)
+ x = 0.0f;
+ else
+ x = xstart;
+ numLines++;
+ y += 32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY;
+ }else{
+ // still space in current line
+ t = GetNextSpace(s);
+ if(*t == '\0'){
+ // end of string
+ x += GetStringWidth(s);
+ if(x > maxlength)
+ maxlength = x;
+ numLines++;
+ s = t;
+ }else{
+ x += GetStringWidth(s);
+ x += GetCharacterSize(*t - ' ');
+ s = t+1;
+ }
+ }
+ }
+
+ if(Details.centre){
+ if(Details.backgroundOnlyText){
+ rect->left = xstart - maxlength/2 - 4.0f;
+ rect->right = xstart + maxlength/2 + 4.0f;
+ rect->top = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f;
+ rect->bottom = ystart - 2.0f;
+ }else{
+ rect->left = xstart - Details.centreSize*0.5f - 4.0f;
+ rect->right = xstart + Details.centreSize*0.5f + 4.0f;
+ rect->top = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f;
+ rect->bottom = ystart - 2.0f;
+ }
+ }else{
+ rect->left = xstart - 4.0f;
+ rect->right = Details.wrapX;
+ // WTF?
+ rect->top = ystart - 4.0f + 4.0f;
+ rect->bottom = (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * numLines +
+ ystart + 2.0f + 2.0f;
+ }
+}
+
+void
+CFont::PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth)
+{
+ uint16 *s, c, unused;
+
+ for(s = start; s < end; s++){
+ if(*s == '~')
+ s = ParseToken(s, &unused);
+ c = *s - ' ';
+ if(Details.slant != 0.0f)
+ y = (Details.slantRefX - x)*Details.slant + Details.slantRefY;
+ PrintChar(x, y, c);
+ x += GetCharacterSize(c);
+ if(c == 0) // space
+ x += spwidth;
+ }
+}
+
+float
+CFont::GetCharacterWidth(uint16 c)
+{
+ if(Details.proportional)
+ return Size[Details.style][c];
+ else
+ return Size[Details.style][192];
+}
+
+float
+CFont::GetCharacterSize(uint16 c)
+{
+ if(Details.proportional)
+ return Size[Details.style][c] * Details.scaleX;
+ else
+ return Size[Details.style][192] * Details.scaleX;
+}
+
+float
+CFont::GetStringWidth(uint16 *s, bool spaces)
+{
+ float w;
+
+ w = 0.0f;
+ for(; (*s != ' ' || spaces) && *s != '\0'; s++){
+ if(*s == '~'){
+ s++;
+ while(*s != '~') s++;
+ s++;
+ if(*s == ' ' && !spaces)
+ break;
+ }
+ w += GetCharacterSize(*s - ' ');
+ }
+ return w;
+}
+
+uint16*
+CFont::GetNextSpace(uint16 *s)
+{
+ for(; *s != ' ' && *s != '\0'; s++)
+ if(*s == '~'){
+ s++;
+ while(*s != '~') s++;
+ s++;
+ if(*s == ' ')
+ break;
+ }
+ return s;
+}
+
+uint16*
+CFont::ParseToken(uint16 *s, uint16*)
+{
+ s++;
+ if(Details.color.r || Details.color.g || Details.color.b)
+ switch(*s){
+ case 'N':
+ case 'n':
+ NewLine = 1;
+ break;
+ case 'b': SetColor(CRGBA(0x80, 0xA7, 0xF3, 0xFF)); break;
+ case 'g': SetColor(CRGBA(0x5F, 0xA0, 0x6A, 0xFF)); break;
+ case 'h': SetColor(CRGBA(0xE1, 0xE1, 0xE1, 0xFF)); break;
+ case 'l': SetColor(CRGBA(0x00, 0x00, 0x00, 0xFF)); break;
+ case 'p': SetColor(CRGBA(0xA8, 0x6E, 0xFC, 0xFF)); break;
+ case 'r': SetColor(CRGBA(0x71, 0x2B, 0x49, 0xFF)); break;
+ case 'w': SetColor(CRGBA(0xAF, 0xAF, 0xAF, 0xFF)); break;
+ case 'y': SetColor(CRGBA(0xD2, 0xC4, 0x6A, 0xFF)); break;
+ }
+ while(*s != '~') s++;
+ return s+1;
+}
+
+void
+CFont::DrawFonts(void)
+{
+ CSprite2d::DrawBank(Details.bank);
+ CSprite2d::DrawBank(Details.bank+1);
+ CSprite2d::DrawBank(Details.bank+2);
+}
+
+uint16
+CFont::character_code(uint8 c)
+{
+ if(c < 128)
+ return c;
+ return foreign_table[c-128];
+}
+
+STARTPATCHES
+
+ InjectHook(0x500A40, CFont::Initialise, PATCH_JUMP);
+ InjectHook(0x500BA0, CFont::Shutdown, PATCH_JUMP);
+ InjectHook(0x500BE0, CFont::InitPerFrame, PATCH_JUMP);
+ InjectHook(0x500C30, CFont::PrintChar, PATCH_JUMP);
+ InjectHook(0x500F50, (void (*)(float, float, uint16*))CFont::PrintString, PATCH_JUMP);
+ InjectHook(0x501260, CFont::GetNumberLines, PATCH_JUMP);
+ InjectHook(0x5013B0, CFont::GetTextRect, PATCH_JUMP);
+ InjectHook(0x501730, (void (*)(float, float, uint16*, uint16*, float))CFont::PrintString, PATCH_JUMP);
+ InjectHook(0x5017E0, CFont::GetCharacterWidth, PATCH_JUMP);
+ InjectHook(0x501840, CFont::GetCharacterSize, PATCH_JUMP);
+ InjectHook(0x5018A0, CFont::GetStringWidth, PATCH_JUMP);
+ InjectHook(0x501960, CFont::GetNextSpace, PATCH_JUMP);
+ InjectHook(0x5019A0, CFont::ParseToken, PATCH_JUMP);
+ InjectHook(0x501B50, CFont::DrawFonts, PATCH_JUMP);
+ InjectHook(0x501E80, CFont::character_code, PATCH_JUMP);
+
+ InjectHook(0x501B80, CFont::SetScale, PATCH_JUMP);
+ InjectHook(0x501BA0, CFont::SetSlantRefPoint, PATCH_JUMP);
+ InjectHook(0x501BC0, CFont::SetSlant, PATCH_JUMP);
+ InjectHook(0x501BD0, CFont::SetColor, PATCH_JUMP);
+ InjectHook(0x501C60, CFont::SetJustifyOn, PATCH_JUMP);
+ InjectHook(0x501C80, CFont::SetJustifyOff, PATCH_JUMP);
+ InjectHook(0x501C90, CFont::SetCentreOn, PATCH_JUMP);
+ InjectHook(0x501CB0, CFont::SetCentreOff, PATCH_JUMP);
+ InjectHook(0x501CC0, CFont::SetWrapx, PATCH_JUMP);
+ InjectHook(0x501CD0, CFont::SetCentreSize, PATCH_JUMP);
+ InjectHook(0x501CE0, CFont::SetBackgroundOn, PATCH_JUMP);
+ InjectHook(0x501CF0, CFont::SetBackgroundOff, PATCH_JUMP);
+ InjectHook(0x501D00, CFont::SetBackgroundColor, PATCH_JUMP);
+ InjectHook(0x501D30, CFont::SetBackGroundOnlyTextOn, PATCH_JUMP);
+ InjectHook(0x501D40, CFont::SetBackGroundOnlyTextOff, PATCH_JUMP);
+ InjectHook(0x501D50, CFont::SetRightJustifyOn, PATCH_JUMP);
+ InjectHook(0x501D70, CFont::SetRightJustifyOff, PATCH_JUMP);
+ InjectHook(0x501D90, CFont::SetPropOff, PATCH_JUMP);
+ InjectHook(0x501DA0, CFont::SetPropOn, PATCH_JUMP);
+ InjectHook(0x501DB0, CFont::SetFontStyle, PATCH_JUMP);
+ InjectHook(0x501DC0, CFont::SetRightJustifyWrap, PATCH_JUMP);
+ InjectHook(0x501DD0, CFont::SetAlphaFade, PATCH_JUMP);
+ InjectHook(0x501DE0, CFont::SetDropColor, PATCH_JUMP);
+ InjectHook(0x501E70, CFont::SetDropShadowPosition, PATCH_JUMP);
+
+ENDPATCHES
diff --git a/src/render/Font.h b/src/render/Font.h
new file mode 100644
index 00000000..017aaeea
--- /dev/null
+++ b/src/render/Font.h
@@ -0,0 +1,108 @@
+#pragma once
+
+struct CFontDetails
+{
+ CRGBA color;
+ float scaleX;
+ float scaleY;
+ float slant;
+ float slantRefX;
+ float slantRefY;
+ bool justify;
+ bool centre;
+ bool rightJustify;
+ bool background;
+ bool backgroundOnlyText;
+ bool proportional;
+ float alphaFade;
+ CRGBA backgroundColor;
+ float wrapX;
+ float centreSize;
+ float rightJustifyWrap;
+ int16 style;
+ int32 bank;
+ int16 dropShadowPosition;
+ CRGBA dropColor;
+};
+
+class CSprite2d;
+
+class CFont
+{
+ static CFontDetails &Details;
+ static int16 Size[3][193];
+ static int16 &NewLine;
+ static CSprite2d *Sprite; //[3]
+public:
+ static void Initialise(void);
+ static void Shutdown(void);
+ static void InitPerFrame(void);
+ static void PrintChar(float x, float y, uint16 c);
+ static void PrintString(float x, float y, uint16 *s);
+ static int GetNumberLines(float xstart, float ystart, uint16 *s);
+ static void GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s);
+ static void PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth);
+ static float GetCharacterWidth(uint16 c);
+ static float GetCharacterSize(uint16 c);
+ static float GetStringWidth(uint16 *s, bool spaces = false);
+ static uint16 *GetNextSpace(uint16 *s);
+ static uint16 *ParseToken(uint16 *s, uint16*);
+ static void DrawFonts(void);
+ static uint16 character_code(uint8 c);
+
+ static void SetScale(float x, float y) { Details.scaleX = x; Details.scaleY = y; }
+ static void SetSlantRefPoint(float x, float y) { Details.slantRefX = x; Details.slantRefY = y; }
+ static void SetSlant(float s) { Details.slant = s; }
+ static void SetJustifyOn(void) {
+ Details.justify = true;
+ Details.centre = false;
+ Details.rightJustify = false;
+ }
+ static void SetJustifyOff(void) {
+ Details.justify = false;
+ Details.rightJustify = false;
+ }
+ static void SetRightJustifyOn(void) {
+ Details.rightJustify = true;
+ Details.justify = false;
+ Details.centre = false;
+ }
+ static void SetRightJustifyOff(void) {
+ Details.rightJustify = false;
+ Details.justify = false;
+ Details.centre = false;
+ }
+ static void SetCentreOn(void) {
+ Details.centre = true;
+ Details.justify = false;
+ Details.rightJustify = false;
+ }
+ static void SetCentreOff(void) {
+ Details.centre = false;
+ }
+ static void SetWrapx(float x) { Details.wrapX = x; }
+ static void SetCentreSize(float s) { Details.centreSize = s; }
+ static void SetBackgroundOn(void) { Details.background = true; }
+ static void SetBackgroundOff(void) { Details.background = false; }
+ static void SetBackGroundOnlyTextOn(void) { Details.backgroundOnlyText = true; }
+ static void SetBackGroundOnlyTextOff(void) { Details.backgroundOnlyText = false; }
+ static void SetPropOn(void) { Details.proportional = true; }
+ static void SetPropOff(void) { Details.proportional = false; }
+ static void SetFontStyle(int16 style) { Details.style = style; }
+ static void SetRightJustifyWrap(float wrap) { Details.rightJustifyWrap = wrap; }
+ static void SetAlphaFade(float fade) { Details.alphaFade = fade; }
+ static void SetDropShadowPosition(int16 pos) { Details.dropShadowPosition = pos; }
+
+ // TODO: really just CRGBA but that isn't passed correctly
+ static void SetBackgroundColor(const CRGBA &col) { Details.backgroundColor = col; }
+ static void SetColor(const CRGBA &col) {
+ Details.color = col;
+ if(Details.alphaFade < 255.0f)
+ Details.color.a *= Details.alphaFade/255.0f;
+ }
+ static void SetDropColor(const CRGBA &col) {
+ Details.dropColor = col;
+ if(Details.alphaFade < 255.0f)
+ Details.dropColor.a *= Details.alphaFade/255.0f;
+ }
+};
diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp
index 74eefccf..509564ac 100644
--- a/src/render/Sprite.cpp
+++ b/src/render/Sprite.cpp
@@ -10,175 +10,9 @@
#undef near
#endif
-RwIm2DVertex *CSprite2d::maVertices = (RwIm2DVertex*)0x6E9168;
-float &CSprite2d::RecipNearClip = *(float*)0x880DB4;
-
-// Arguments:
-// 2---3
-// | |
-// 0---1
-void
-CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far)
-{
- float screenz, z, recipz;
-
- if(far){
- screenz = RwIm2DGetFarScreenZ();
- z = RwCameraGetFarClipPlane(Scene.camera);
- }else{
- screenz = RwIm2DGetNearScreenZ();
- z = 1.0f/RecipNearClip;
- }
- recipz = 1.0f/z;
-
- // This is what we draw:
- // 0---1
- // | / |
- // 3---2
- RwIm2DVertexSetScreenX(&maVertices[0], r.left);
- RwIm2DVertexSetScreenY(&maVertices[0], r.bottom);
- RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[0], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
- RwIm2DVertexSetU(&maVertices[0], 0.0f, recipz);
- RwIm2DVertexSetV(&maVertices[0], 0.0f, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[1], r.right);
- RwIm2DVertexSetScreenY(&maVertices[1], r.bottom);
- RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[1], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
- RwIm2DVertexSetU(&maVertices[1], 1.0f, recipz);
- RwIm2DVertexSetV(&maVertices[1], 0.0f, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[2], r.right);
- RwIm2DVertexSetScreenY(&maVertices[2], r.top);
- RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[2], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
- RwIm2DVertexSetU(&maVertices[2], 1.0f, recipz);
- RwIm2DVertexSetV(&maVertices[2], 1.0f, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[3], r.left);
- RwIm2DVertexSetScreenY(&maVertices[3], r.top);
- RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[3], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
- RwIm2DVertexSetU(&maVertices[3], 0.0f, recipz);
- RwIm2DVertexSetV(&maVertices[3], 1.0f, recipz);
-}
-
-void
-CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
- float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
-{
- float screenz, z, recipz;
-
- screenz = RwIm2DGetNearScreenZ();
- z = 1.0f/RecipNearClip;
- recipz = 1.0f/z;
-
- // This is what we draw:
- // 0---1
- // | / |
- // 3---2
- RwIm2DVertexSetScreenX(&maVertices[0], r.left);
- RwIm2DVertexSetScreenY(&maVertices[0], r.bottom);
- RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[0], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
- RwIm2DVertexSetU(&maVertices[0], u0, recipz);
- RwIm2DVertexSetV(&maVertices[0], v0, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[1], r.right);
- RwIm2DVertexSetScreenY(&maVertices[1], r.bottom);
- RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[1], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
- RwIm2DVertexSetU(&maVertices[1], u1, recipz);
- RwIm2DVertexSetV(&maVertices[1], v1, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[2], r.right);
- RwIm2DVertexSetScreenY(&maVertices[2], r.top);
- RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[2], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
- RwIm2DVertexSetU(&maVertices[2], u2, recipz);
- RwIm2DVertexSetV(&maVertices[2], v2, recipz);
-
- RwIm2DVertexSetScreenX(&maVertices[3], r.left);
- RwIm2DVertexSetScreenY(&maVertices[3], r.top);
- RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
- RwIm2DVertexSetCameraZ(&maVertices[3], z);
- RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
- RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
- RwIm2DVertexSetU(&maVertices[3], u3, recipz);
- RwIm2DVertexSetV(&maVertices[3], v3, recipz);
-}
-
-void
-CSprite2d::SetRenderState(void)
-{
- if(m_pTexture)
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(m_pTexture));
- else
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
-}
-
-void
-CSprite2d::DrawRect(const CRect &r, const CRGBA &col)
-{
- SetVertices(r, col, col, col, col, false);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(col.a != 255));
- RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
-}
-
-void
-CSprite2d::DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
-{
- SetVertices(r, c0, c1, c2, c3, false);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
- RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
-}
-
-void
-CSprite2d::DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
-{
- SetVertices(r, c0, c1, c2, c3, false);
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
- RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
-}
-
-
-
float &CSprite::m_f2DNearScreenZ = *(float*)0x8F1ABC;
float &CSprite::m_f2DFarScreenZ = *(float*)0x8F2C94;
+float &CSprite::m_fRecipNearClipPlane = *(float*)0x8F5FFC;
int32 &CSprite::m_bFlushSpriteBufferSwitchZTest = *(int32*)0x8F5FB0;
float
@@ -221,6 +55,13 @@ CSprite::InitSpriteBuffer(void)
}
void
+CSprite::InitSpriteBuffer2D(void)
+{
+ m_fRecipNearClipPlane = 1.0f / RwCameraGetNearClipPlane(Scene.camera);
+ InitSpriteBuffer();
+}
+
+void
CSprite::FlushSpriteBuffer(void)
{
if(nSpriteBufferIndex > 0){
@@ -533,21 +374,179 @@ CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, f
FlushSpriteBuffer();
}
-STARTPATCHES
- InjectHook(0x51EE90, (void (*)(const CRect&, const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&, uint32))CSprite2d::SetVertices, PATCH_JUMP);
- InjectHook(0x51F220, (void (*)(const CRect&, const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&,
- float, float, float, float, float, float, float, float))CSprite2d::SetVertices, PATCH_JUMP);
- InjectHook(0x51F970, (void (*)(const CRect&, const CRGBA&))CSprite2d::DrawRect, PATCH_JUMP);
- InjectHook(0x51FA00, (void (*)(const CRect&, const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&))CSprite2d::DrawRect, PATCH_JUMP);
- InjectHook(0x51FA80, CSprite2d::DrawRectXLU, PATCH_JUMP);
+void
+CSprite::Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ float screenz, recipz;
+
+ screenz = m_f2DNearScreenZ;
+ recipz = m_fRecipNearClipPlane;
+
+ RwIm2DVertexSetScreenX(&verts[0], r.left);
+ RwIm2DVertexSetScreenY(&verts[0], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[0], screenz);
+ RwIm2DVertexSetCameraZ(&verts[0], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[0], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[0], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[1], r.right);
+ RwIm2DVertexSetScreenY(&verts[1], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[1], screenz);
+ RwIm2DVertexSetCameraZ(&verts[1], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[1], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&verts[1], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[1], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[2], r.right);
+ RwIm2DVertexSetScreenY(&verts[2], r.top);
+ RwIm2DVertexSetScreenZ(&verts[2], screenz);
+ RwIm2DVertexSetCameraZ(&verts[2], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[2], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[2], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[3], r.left);
+ RwIm2DVertexSetScreenY(&verts[3], r.top);
+ RwIm2DVertexSetScreenZ(&verts[3], screenz);
+ RwIm2DVertexSetCameraZ(&verts[3], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[3], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&verts[3], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[3], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[4], r.left);
+ RwIm2DVertexSetScreenY(&verts[4], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[4], screenz);
+ RwIm2DVertexSetCameraZ(&verts[4], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[4], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[4], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[4], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[5], r.right);
+ RwIm2DVertexSetScreenY(&verts[5], r.top);
+ RwIm2DVertexSetScreenZ(&verts[5], screenz);
+ RwIm2DVertexSetCameraZ(&verts[5], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[5], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[5], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[5], 1.0f, recipz);
+}
+void
+CSprite::Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
+ const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ float screenz, recipz;
+
+ screenz = m_f2DNearScreenZ;
+ recipz = m_fRecipNearClipPlane;
+
+ RwIm2DVertexSetScreenX(&verts[0], x3);
+ RwIm2DVertexSetScreenY(&verts[0], y3);
+ RwIm2DVertexSetScreenZ(&verts[0], screenz);
+ RwIm2DVertexSetCameraZ(&verts[0], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[0], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[0], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[1], x4);
+ RwIm2DVertexSetScreenY(&verts[1], y4);
+ RwIm2DVertexSetScreenZ(&verts[1], screenz);
+ RwIm2DVertexSetCameraZ(&verts[1], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[1], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&verts[1], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[1], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[2], x2);
+ RwIm2DVertexSetScreenY(&verts[2], y2);
+ RwIm2DVertexSetScreenZ(&verts[2], screenz);
+ RwIm2DVertexSetCameraZ(&verts[2], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[2], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[2], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[3], x1);
+ RwIm2DVertexSetScreenY(&verts[3], y1);
+ RwIm2DVertexSetScreenZ(&verts[3], screenz);
+ RwIm2DVertexSetCameraZ(&verts[3], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[3], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&verts[3], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[3], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[4], x3);
+ RwIm2DVertexSetScreenY(&verts[4], y3);
+ RwIm2DVertexSetScreenZ(&verts[4], screenz);
+ RwIm2DVertexSetCameraZ(&verts[4], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[4], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[4], 0.0f, recipz);
+ RwIm2DVertexSetV(&verts[4], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[5], x2);
+ RwIm2DVertexSetScreenY(&verts[5], y2);
+ RwIm2DVertexSetScreenZ(&verts[5], screenz);
+ RwIm2DVertexSetCameraZ(&verts[5], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[5], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[5], 1.0f, recipz);
+ RwIm2DVertexSetV(&verts[5], 1.0f, recipz);
+}
+
+void
+CSprite::RenderBufferedOneXLUSprite2D(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, uint8 alpha)
+{
+ m_bFlushSpriteBufferSwitchZTest = 1;
+ CRGBA col(intens * colour.red >> 8, intens * colour.green >> 8, intens * colour.blue >> 8, alpha);
+ CRect rect(x - w, y - h, x + h, y + h);
+ Set6Vertices2D(&SpriteBufferVerts[6 * nSpriteBufferIndex], rect, col, col, col, col);
+ nSpriteBufferIndex++;
+ if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
+ FlushSpriteBuffer();
+}
+
+void
+CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, float rotation, uint8 alpha)
+{
+ m_bFlushSpriteBufferSwitchZTest = 1;
+ CRGBA col(intens * colour.red >> 8, intens * colour.green >> 8, intens * colour.blue >> 8, alpha);
+ float c = cos(DEGTORAD(rotation));
+ float s = sin(DEGTORAD(rotation));
+
+ Set6Vertices2D(&SpriteBufferVerts[6 * nSpriteBufferIndex],
+ x + c*w - s*h,
+ y - c*h - s*w,
+ x + c*w + s*h,
+ y + c*h - s*w,
+ x - c*w - s*h,
+ y - c*h + s*w,
+ x - c*w + s*h,
+ y + c*h + s*w,
+ col, col, col, col);
+ nSpriteBufferIndex++;
+ if(nSpriteBufferIndex >= SPRITEBUFFERSIZE)
+ FlushSpriteBuffer();
+}
+
+STARTPATCHES
InjectHook(0x51C4A0, CSprite::CalcHorizonCoors, PATCH_JUMP);
InjectHook(0x51C3A0, CSprite::CalcScreenCoors, PATCH_JUMP);
InjectHook(0x51C590, CSprite::InitSpriteBuffer, PATCH_JUMP);
+ InjectHook(0x51C5B0, CSprite::InitSpriteBuffer2D, PATCH_JUMP);
InjectHook(0x51C520, CSprite::FlushSpriteBuffer, PATCH_JUMP);
InjectHook(0x51C960, CSprite::RenderOneXLUSprite, PATCH_JUMP);
InjectHook(0x51C5D0, CSprite::RenderBufferedOneXLUSprite, PATCH_JUMP);
InjectHook(0x51D5B0, CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension, PATCH_JUMP);
InjectHook(0x51CCD0, CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect, PATCH_JUMP);
InjectHook(0x51D9E0, CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours, PATCH_JUMP);
+ InjectHook(0x51E3C0, CSprite::RenderBufferedOneXLUSprite2D, PATCH_JUMP);
+ InjectHook(0x51E490, CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension, PATCH_JUMP);
ENDPATCHES
diff --git a/src/render/Sprite.h b/src/render/Sprite.h
index 53d36de3..7bc5c35e 100644
--- a/src/render/Sprite.h
+++ b/src/render/Sprite.h
@@ -1,32 +1,16 @@
#pragma once
-class CSprite2d
-{
- RwTexture *m_pTexture;
-
- static RwIm2DVertex *maVertices; //[4];
-public:
- static float &RecipNearClip;
-
- void SetRenderState(void);
-
- static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far);
- static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
- float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
- static void DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
- static void DrawRect(const CRect &r, const CRGBA &col);
- static void DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
-};
-
class CSprite
{
static float &m_f2DNearScreenZ;
static float &m_f2DFarScreenZ;
+ static float &m_fRecipNearClipPlane;
static int32 &m_bFlushSpriteBufferSwitchZTest;
public:
static float CalcHorizonCoors(void);
static bool CalcScreenCoors(const RwV3d &in, RwV3d *out, float *outw, float *outh, bool farclip);
static void InitSpriteBuffer(void);
+ static void InitSpriteBuffer2D(void);
static void FlushSpriteBuffer(void);
static void RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a);
static void RenderBufferedOneXLUSprite(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, uint8 a);
@@ -34,4 +18,10 @@ public:
static void RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float roll, uint8 a);
// cx/y is the direction in which the colour changes
static void RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, float w, float h, uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2, float cx, float cy, float recipz, float rotation, uint8 a);
+ static void Set6Vertices2D(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+ static void Set6Vertices2D(RwIm2DVertex *verts, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
+ const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+ static void RenderBufferedOneXLUSprite2D(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, uint8 alpha);
+ static void RenderBufferedOneXLUSprite2D_Rotate_Dimension(float x, float y, float w, float h, const RwRGBA &colour, int16 intens, float rotation, uint8 alpha);
+
};
diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp
new file mode 100644
index 00000000..2311a75e
--- /dev/null
+++ b/src/render/Sprite2d.cpp
@@ -0,0 +1,498 @@
+#include "common.h"
+#include "patcher.h"
+#include "Draw.h"
+#include "Camera.h"
+#include "Sprite2d.h"
+
+// Get rid of bullshit windows definitions, we're not running on an 8086
+#ifdef far
+#undef far
+#undef near
+#endif
+
+RwIm2DVertex *CSprite2d::maVertices = (RwIm2DVertex*)0x6E9168;
+float &CSprite2d::RecipNearClip = *(float*)0x880DB4;
+int32 &CSprite2d::mCurrentBank = *(int32*)0x8F1AF4;
+RwTexture **CSprite2d::mpBankTextures = (RwTexture**)0x774DC0;
+int32 *CSprite2d::mCurrentSprite = (int32*)0x6F4500;
+int32 *CSprite2d::mBankStart = (int32*)0x774BE8;
+RwIm2DVertex *CSprite2d::maBankVertices = (RwIm2DVertex*)0x8429F8;
+
+
+void
+CSprite2d::SetRecipNearClip(void)
+{
+ RecipNearClip = 1.0f / RwCameraGetNearClipPlane(Scene.camera);
+}
+
+void
+CSprite2d::InitPerFrame(void)
+{
+ int i;
+
+ mCurrentBank = 0;
+ for(i = 0; i < 10; i++)
+ mCurrentSprite[i] = 0;
+ for(i = 0; i < 10; i++)
+ mpBankTextures[i] = nil;
+}
+
+int32
+CSprite2d::GetBank(int32 n, RwTexture *tex)
+{
+ mpBankTextures[mCurrentBank] = tex;
+ mCurrentSprite[mCurrentBank] = 0;
+ mBankStart[mCurrentBank+1] = mBankStart[mCurrentBank] + n;
+ return mCurrentBank++;
+}
+
+void
+CSprite2d::AddSpriteToBank(int32 bank, const CRect &rect, const CRGBA &col,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
+{
+ SetVertices(&maBankVertices[6 * (mCurrentSprite[bank] + mBankStart[bank])],
+ rect, col, col, col, col,
+ u0, v0, u1, v1, u2, v2, u3, v3);
+ mCurrentSprite[bank]++;
+ if(mCurrentSprite[bank] + mBankStart[bank] >= mBankStart[bank+1]){
+ DrawBank(bank);
+ mCurrentSprite[bank] = 0;
+ }
+}
+
+void
+CSprite2d::DrawBank(int32 bank)
+{
+ if(mCurrentSprite[bank] == 0)
+ return;
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER,
+ mpBankTextures[bank] ? RwTextureGetRaster(mpBankTextures[bank]) : nil);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwIm2DRenderPrimitive(rwPRIMTYPETRILIST, &maBankVertices[6*mBankStart[bank]], 6*mCurrentSprite[bank]);
+ mCurrentSprite[bank] = 0;
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+}
+
+
+void
+CSprite2d::Delete(void)
+{
+ if(m_pTexture){
+ RwTextureDestroy(m_pTexture);
+ m_pTexture = nil;
+ }
+}
+
+void
+CSprite2d::SetTexture(char *name)
+{
+ Delete();
+ if(name)
+ m_pTexture = RwTextureRead(name, nil);
+}
+
+void
+CSprite2d::SetTexture(char *name, char *mask)
+{
+ Delete();
+ if(name)
+ m_pTexture = RwTextureRead(name, mask);
+}
+
+void
+CSprite2d::SetAddressing(RwTextureAddressMode addr)
+{
+ if(m_pTexture)
+ RwTextureSetAddressing(m_pTexture, addr);
+}
+
+void
+CSprite2d::SetRenderState(void)
+{
+ if(m_pTexture)
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(m_pTexture));
+ else
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+}
+
+void
+CSprite2d::Draw(float x, float y, float w, float h, const CRGBA &col)
+{
+ SetVertices(CRect(x, y, x + w, y + h), col, col, col, col, 0);
+ SetRenderState();
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+}
+
+void
+CSprite2d::Draw(const CRect &rect, const CRGBA &col)
+{
+ SetVertices(rect, col, col, col, col, 0);
+ SetRenderState();
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+}
+
+void
+CSprite2d::Draw(const CRect &rect, const CRGBA &col,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
+{
+ SetVertices(rect, col, col, col, col, u0, v0, u1, v1, u3, v3, u2, v2);
+ SetRenderState();
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+}
+
+void
+CSprite2d::Draw(const CRect &rect, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ SetVertices(rect, c0, c1, c2, c3, 0);
+ SetRenderState();
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+}
+
+void
+CSprite2d::Draw(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &col)
+{
+ SetVertices(x1, y2, x2, y2, x3, y3, x4, y4, col, col, col, col);
+ SetRenderState();
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+}
+
+
+// Arguments:
+// 2---3
+// | |
+// 0---1
+void
+CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far)
+{
+ float screenz, z, recipz;
+
+ if(far){
+ screenz = RwIm2DGetFarScreenZ();
+ z = RwCameraGetFarClipPlane(Scene.camera);
+ }else{
+ screenz = RwIm2DGetNearScreenZ();
+ z = 1.0f/RecipNearClip;
+ }
+ recipz = 1.0f/z;
+
+ // This is what we draw:
+ // 0---1
+ // | / |
+ // 3---2
+ RwIm2DVertexSetScreenX(&maVertices[0], r.left);
+ RwIm2DVertexSetScreenY(&maVertices[0], r.bottom);
+ RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[0], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&maVertices[0], 0.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[0], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[1], r.right);
+ RwIm2DVertexSetScreenY(&maVertices[1], r.bottom);
+ RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[1], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&maVertices[1], 1.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[1], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[2], r.right);
+ RwIm2DVertexSetScreenY(&maVertices[2], r.top);
+ RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[2], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&maVertices[2], 1.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[2], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[3], r.left);
+ RwIm2DVertexSetScreenY(&maVertices[3], r.top);
+ RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[3], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&maVertices[3], 0.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[3], 1.0f, recipz);
+}
+
+void
+CSprite2d::SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
+{
+ float screenz, z, recipz;
+
+ screenz = RwIm2DGetNearScreenZ();
+ z = 1.0f/RecipNearClip;
+ recipz = 1.0f/z;
+
+ // This is what we draw:
+ // 0---1
+ // | / |
+ // 3---2
+ RwIm2DVertexSetScreenX(&maVertices[0], r.left);
+ RwIm2DVertexSetScreenY(&maVertices[0], r.bottom);
+ RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[0], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&maVertices[0], u0, recipz);
+ RwIm2DVertexSetV(&maVertices[0], v0, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[1], r.right);
+ RwIm2DVertexSetScreenY(&maVertices[1], r.bottom);
+ RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[1], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&maVertices[1], u1, recipz);
+ RwIm2DVertexSetV(&maVertices[1], v1, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[2], r.right);
+ RwIm2DVertexSetScreenY(&maVertices[2], r.top);
+ RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[2], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&maVertices[2], u2, recipz);
+ RwIm2DVertexSetV(&maVertices[2], v2, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[3], r.left);
+ RwIm2DVertexSetScreenY(&maVertices[3], r.top);
+ RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[3], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&maVertices[3], u3, recipz);
+ RwIm2DVertexSetV(&maVertices[3], v3, recipz);
+}
+
+void
+CSprite2d::SetVertices(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
+ const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ float screenz, recipz;
+
+ screenz = RwIm2DGetNearScreenZ();
+ recipz = RecipNearClip;
+
+ RwIm2DVertexSetScreenX(&maVertices[0], x3);
+ RwIm2DVertexSetScreenY(&maVertices[0], y3);
+ RwIm2DVertexSetScreenZ(&maVertices[0], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[0], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[0], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&maVertices[0], 0.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[0], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[1], x4);
+ RwIm2DVertexSetScreenY(&maVertices[1], y4);
+ RwIm2DVertexSetScreenZ(&maVertices[1], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[1], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[1], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[1], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&maVertices[1], 1.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[1], 0.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[2], x2);
+ RwIm2DVertexSetScreenY(&maVertices[2], y2);
+ RwIm2DVertexSetScreenZ(&maVertices[2], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[2], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[2], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&maVertices[2], 1.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[2], 1.0f, recipz);
+
+ RwIm2DVertexSetScreenX(&maVertices[3], x1);
+ RwIm2DVertexSetScreenY(&maVertices[3], y1);
+ RwIm2DVertexSetScreenZ(&maVertices[3], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[3], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[3], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[3], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&maVertices[3], 0.0f, recipz);
+ RwIm2DVertexSetV(&maVertices[3], 1.0f, recipz);
+}
+
+void
+CSprite2d::SetVertices(int n, float *positions, float *uvs, const CRGBA &col)
+{
+ int i;
+ float screenz, recipz;
+
+ screenz = RwIm2DGetNearScreenZ();
+ recipz = RecipNearClip;
+
+
+ for(i = 0; i < n; i++){
+ RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
+ RwIm2DVertexSetScreenY(&maVertices[i], positions[i*2 + 1]);
+ RwIm2DVertexSetScreenZ(&maVertices[i], screenz + 0.0001f);
+ RwIm2DVertexSetCameraZ(&maVertices[i], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[i], col.r, col.g, col.b, col.a);
+ RwIm2DVertexSetU(&maVertices[i], uvs[i*2 + 0], recipz);
+ RwIm2DVertexSetV(&maVertices[i], uvs[i*2 + 1], recipz);
+ }
+}
+
+void
+CSprite2d::SetMaskVertices(int n, float *positions)
+{
+ int i;
+ float screenz, recipz;
+
+ screenz = RwIm2DGetNearScreenZ();
+ recipz = RecipNearClip;
+
+ for(i = 0; i < n; i++){
+ RwIm2DVertexSetScreenX(&maVertices[i], positions[i*2 + 0]);
+ RwIm2DVertexSetScreenY(&maVertices[i], positions[i*2 + 1]);
+ RwIm2DVertexSetScreenZ(&maVertices[i], screenz);
+ RwIm2DVertexSetCameraZ(&maVertices[i], z);
+ RwIm2DVertexSetRecipCameraZ(&maVertices[i], recipz);
+ RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0);
+ }
+}
+
+void
+CSprite2d::SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2)
+{
+ float screenz, recipz;
+
+ screenz = RwIm2DGetNearScreenZ();
+ recipz = RecipNearClip;
+
+ RwIm2DVertexSetScreenX(&verts[0], r.left);
+ RwIm2DVertexSetScreenY(&verts[0], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[0], screenz);
+ RwIm2DVertexSetCameraZ(&verts[0], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[0], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[0], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[0], u0, recipz);
+ RwIm2DVertexSetV(&verts[0], v0, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[1], r.left);
+ RwIm2DVertexSetScreenY(&verts[1], r.top);
+ RwIm2DVertexSetScreenZ(&verts[1], screenz);
+ RwIm2DVertexSetCameraZ(&verts[1], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[1], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[1], c0.r, c0.g, c0.b, c0.a);
+ RwIm2DVertexSetU(&verts[1], u2, recipz);
+ RwIm2DVertexSetV(&verts[1], v2, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[2], r.right);
+ RwIm2DVertexSetScreenY(&verts[2], r.top);
+ RwIm2DVertexSetScreenZ(&verts[2], screenz);
+ RwIm2DVertexSetCameraZ(&verts[2], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[2], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[2], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[2], u3, recipz);
+ RwIm2DVertexSetV(&verts[2], v3, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[3], r.left);
+ RwIm2DVertexSetScreenY(&verts[3], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[3], screenz);
+ RwIm2DVertexSetCameraZ(&verts[3], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[3], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[3], c2.r, c2.g, c2.b, c2.a);
+ RwIm2DVertexSetU(&verts[3], u0, recipz);
+ RwIm2DVertexSetV(&verts[3], v0, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[4], r.right);
+ RwIm2DVertexSetScreenY(&verts[4], r.top);
+ RwIm2DVertexSetScreenZ(&verts[4], screenz);
+ RwIm2DVertexSetCameraZ(&verts[4], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[4], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[4], c1.r, c1.g, c1.b, c1.a);
+ RwIm2DVertexSetU(&verts[4], u3, recipz);
+ RwIm2DVertexSetV(&verts[4], v3, recipz);
+
+ RwIm2DVertexSetScreenX(&verts[5], r.right);
+ RwIm2DVertexSetScreenY(&verts[5], r.bottom);
+ RwIm2DVertexSetScreenZ(&verts[5], screenz);
+ RwIm2DVertexSetCameraZ(&verts[5], z);
+ RwIm2DVertexSetRecipCameraZ(&verts[5], recipz);
+ RwIm2DVertexSetIntRGBA(&verts[5], c3.r, c3.g, c3.b, c3.a);
+ RwIm2DVertexSetU(&verts[5], u1, recipz);
+ RwIm2DVertexSetV(&verts[5], v1, recipz);
+
+}
+
+void
+CSprite2d::DrawRect(const CRect &r, const CRGBA &col)
+{
+ SetVertices(r, col, col, col, col, false);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(col.a != 255));
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
+}
+
+void
+CSprite2d::DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ SetVertices(r, c0, c1, c2, c3, false);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, maVertices, 4);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+}
+
+void
+CSprite2d::DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3)
+{
+ SetVertices(r, c0, c1, c2, c3, false);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+}
+
+STARTPATCHES
+#define C4 const CRGBA&, const CRGBA&, const CRGBA&, const CRGBA&
+#define F8 float, float, float, float, float, float, float, float
+
+ InjectHook(0x51EA20, CSprite2d::SetRecipNearClip, PATCH_JUMP);
+ InjectHook(0x51EAE0, CSprite2d::InitPerFrame, PATCH_JUMP);
+ InjectHook(0x51EB70, CSprite2d::GetBank, PATCH_JUMP);
+ InjectHook(0x51EBC0, CSprite2d::AddSpriteToBank, PATCH_JUMP);
+ InjectHook(0x51EC50, CSprite2d::DrawBank, PATCH_JUMP);
+
+ InjectHook(0x51EA00, &CSprite2d::Delete, PATCH_JUMP);
+ InjectHook(0x51F950, &CSprite2d::SetRenderState, PATCH_JUMP);
+ InjectHook(0x51EA40, (void (CSprite2d::*)(char*))&CSprite2d::SetTexture, PATCH_JUMP);
+ InjectHook(0x51EA70, (void (CSprite2d::*)(char*,char*))&CSprite2d::SetTexture, PATCH_JUMP);
+ InjectHook(0x51EAA0, &CSprite2d::SetAddressing, PATCH_JUMP);
+
+ InjectHook(0x51EE90, (void (*)(const CRect&, C4, uint32))CSprite2d::SetVertices, PATCH_JUMP);
+ InjectHook(0x51F220, (void (*)(const CRect&, C4, F8))CSprite2d::SetVertices, PATCH_JUMP);
+ InjectHook(0x51F070, (void (*)(F8, C4))CSprite2d::SetVertices, PATCH_JUMP);
+ InjectHook(0x51F3E0, (void (*)(int, float*, float*, const CRGBA&))CSprite2d::SetVertices, PATCH_JUMP);
+ InjectHook(0x51F490, CSprite2d::SetMaskVertices, PATCH_JUMP);
+ InjectHook(0x51F720, (void (*)(RwIm2DVertex*, const CRect&, C4, F8))CSprite2d::SetVertices, PATCH_JUMP);
+
+ InjectHook(0x51ECE0, (void (CSprite2d::*)(float, float, float, float, const CRGBA &))&CSprite2d::Draw, PATCH_JUMP);
+ InjectHook(0x51ED50, (void (CSprite2d::*)(const CRect &, const CRGBA &))&CSprite2d::Draw, PATCH_JUMP);
+ InjectHook(0x51ED90, (void (CSprite2d::*)(const CRect &, const CRGBA &, F8))&CSprite2d::Draw, PATCH_JUMP);
+ InjectHook(0x51EDF0, (void (CSprite2d::*)(const CRect &, C4))&CSprite2d::Draw, PATCH_JUMP);
+ InjectHook(0x51EE40, (void (CSprite2d::*)(F8, const CRGBA &))&CSprite2d::Draw, PATCH_JUMP);
+
+ InjectHook(0x51F970, (void (*)(const CRect&, const CRGBA&))CSprite2d::DrawRect, PATCH_JUMP);
+ InjectHook(0x51FA00, (void (*)(const CRect&, C4))CSprite2d::DrawRect, PATCH_JUMP);
+ InjectHook(0x51FA80, CSprite2d::DrawRectXLU, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/render/Sprite2d.h b/src/render/Sprite2d.h
new file mode 100644
index 00000000..1813d4ee
--- /dev/null
+++ b/src/render/Sprite2d.h
@@ -0,0 +1,49 @@
+#pragma once
+
+class CSprite2d
+{
+ static float &RecipNearClip;
+ static int32 &mCurrentBank;
+ static RwTexture **mpBankTextures; //[10];
+ static int32 *mCurrentSprite; //[10];
+ static int32 *mBankStart; //[10];
+ static RwIm2DVertex *maBankVertices; //[500];
+ static RwIm2DVertex *maVertices; //[4];
+public:
+ RwTexture *m_pTexture;
+
+ static void SetRecipNearClip(void);
+ static void InitPerFrame(void);
+ static int32 GetBank(int32 n, RwTexture *tex);
+ static void AddSpriteToBank(int32 bank, const CRect &rect, const CRGBA &col,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
+ static void DrawBank(int32 bank);
+
+ CSprite2d(void) : m_pTexture(nil) {};
+ ~CSprite2d(void) { Delete(); };
+ void Delete(void);
+ void SetRenderState(void);
+ void SetTexture(char *name);
+ void SetTexture(char *name, char *mask);
+ void SetAddressing(RwTextureAddressMode addr);
+ void Draw(float x, float y, float w, float h, const CRGBA &col);
+ void Draw(const CRect &rect, const CRGBA &col);
+ void Draw(const CRect &rect, const CRGBA &col,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
+ void Draw(const CRect &rect, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+ void Draw(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, const CRGBA &col);
+
+ static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3, uint32 far);
+ static void SetVertices(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
+ static void SetVertices(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
+ const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+ static void SetVertices(int n, float *positions, float *uvs, const CRGBA &col);
+ static void SetMaskVertices(int n, float *positions);
+ static void SetVertices(RwIm2DVertex *verts, const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3,
+ float u0, float v0, float u1, float v1, float u3, float v3, float u2, float v2);
+
+ static void DrawRect(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+ static void DrawRect(const CRect &r, const CRGBA &col);
+ static void DrawRectXLU(const CRect &r, const CRGBA &c0, const CRGBA &c1, const CRGBA &c2, const CRGBA &c3);
+};
diff --git a/src/rw.cpp b/src/rw.cpp
index 13383783..b0e838ac 100644
--- a/src/rw.cpp
+++ b/src/rw.cpp
@@ -207,6 +207,7 @@ static uint32_t RwStreamFindChunk_A = AddressByVersion<uint32_t>(0x5AA540, 0, 0,
WRAPPER RwBool RwStreamFindChunk(RwStream*, RwUInt32, RwUInt32*, RwUInt32*) { VARJMP(RwStreamFindChunk_A); }
static uint32_t RwTexDictionaryStreamRead_A = AddressByVersion<uint32_t>(0x5924A0, 0, 0, 0x61E710, 0, 0);
WRAPPER RwTexDictionary *RwTexDictionaryStreamRead(RwStream*) { VARJMP(RwTexDictionaryStreamRead_A); }
+WRAPPER void _rwD3D8TexDictionaryEnableRasterFormatConversion(RwBool enable) { EAXJMP(0x5BE280); }
static uint32_t RpGeometryLock_A = AddressByVersion<uint32_t>(0, 0, 0, 0x64CCD0, 0, 0);
static uint32_t RpGeometryUnlock_A = AddressByVersion<uint32_t>(0, 0, 0, 0x64CD00, 0, 0);