Initial commit

This commit is contained in:
Shinovon 2026-04-22 07:30:27 +05:00
commit 77cdaaf97e
827 changed files with 418745 additions and 0 deletions

224
src/rw/ClumpRead.cpp Normal file
View file

@ -0,0 +1,224 @@
#include "common.h"
struct rpGeometryList
{
RpGeometry **geometries;
int32 numGeoms;
};
struct rpAtomicBinary
{
RwInt32 frameIndex;
RwInt32 geomIndex;
RwInt32 flags;
RwInt32 unused;
};
static int32 numberGeometrys;
static int32 streamPosition;
static rpGeometryList gGeomList;
static rwFrameList gFrameList;
static RpClumpChunkInfo gClumpInfo;
rpGeometryList*
GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist)
{
int i;
RwUInt32 size, version;
RwInt32 numGeoms;
numberGeometrys = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size == 4);
if(RwStreamRead(stream, &numGeoms, 4) != 4)
return nil;
numberGeometrys = numGeoms/2;
geomlist->numGeoms = numGeoms;
if(geomlist->numGeoms > 0){
geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*));
if(geomlist->geometries == nil)
return nil;
memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*));
}else
geomlist->geometries = nil;
for(i = 0; i < numberGeometrys; i++){
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
return nil;
geomlist->geometries[i] = RpGeometryStreamRead(stream);
if(geomlist->geometries[i] == nil)
return nil;
}
return geomlist;
}
rpGeometryList*
GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist)
{
int i;
RwUInt32 version;
for(i = numberGeometrys; i < geomlist->numGeoms; i++){
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
return nil;
geomlist->geometries[i] = RpGeometryStreamRead(stream);
if(geomlist->geometries[i] == nil)
return nil;
}
return geomlist;
}
void
GeometryListDeinitialize(rpGeometryList *geomlist)
{
int i;
for(i = 0; i < geomlist->numGeoms; i++)
if(geomlist->geometries[i])
RpGeometryDestroy(geomlist->geometries[i]);
if(geomlist->numGeoms){
RwFree(geomlist->geometries);
geomlist->numGeoms = 0;
}
}
RpAtomic*
ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList)
{
RwUInt32 size, version;
rpAtomicBinary a;
RpAtomic *atomic;
numberGeometrys = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size <= sizeof(rpAtomicBinary));
if(RwStreamRead(stream, &a, size) != size)
return nil;
atomic = RpAtomicCreate();
if(atomic == nil)
return nil;
RpAtomicSetFlags(atomic, a.flags);
if(frmList->numFrames){
assert(a.frameIndex < frmList->numFrames);
RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]);
}
if(geomList->numGeoms){
assert(a.geomIndex < geomList->numGeoms);
RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0);
}else{
RpGeometry *geom;
if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){
RpAtomicDestroy(atomic);
return nil;
}
geom = RpGeometryStreamRead(stream);
if(geom == nil){
RpAtomicDestroy(atomic);
return nil;
}
RpAtomicSetGeometry(atomic, geom, 0);
RpGeometryDestroy(geom);
}
return atomic;
}
bool
RpClumpGtaStreamRead1(RwStream *stream)
{
RwUInt32 size, version;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return false;
if(version >= 0x33000){
assert(size == 12);
if(RwStreamRead(stream, &gClumpInfo, 12) != 12)
return false;
}else{
assert(size == 4);
if(RwStreamRead(stream, &gClumpInfo, 4) != 4)
return false;
}
if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version))
return false;
if(rwFrameListStreamRead(stream, &gFrameList) == nil)
return false;
if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){
rwFrameListDeinitialize(&gFrameList);
return false;
}
if(GeometryListStreamRead1(stream, &gGeomList) == nil){
rwFrameListDeinitialize(&gFrameList);
return false;
}
streamPosition = STREAMPOS(stream);
return true;
}
RpClump*
RpClumpGtaStreamRead2(RwStream *stream)
{
int i;
RwUInt32 version;
RpAtomic *atomic;
RpClump *clump;
clump = RpClumpCreate();
if(clump == nil)
return nil;
RwStreamSkip(stream, streamPosition - STREAMPOS(stream));
if(GeometryListStreamRead2(stream, &gGeomList) == nil){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
RpClumpSetFrame(clump, gFrameList.frames[0]);
for(i = 0; i < gClumpInfo.numAtomics; i++){
if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList);
if(atomic == nil){
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
RpClumpDestroy(clump);
return nil;
}
RpClumpAddAtomic(clump, atomic);
}
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
return clump;
}
void
RpClumpGtaCancelStream(void)
{
GeometryListDeinitialize(&gGeomList);
rwFrameListDeinitialize(&gFrameList);
gFrameList.numFrames = 0;
}

355
src/rw/Lights.cpp Normal file
View file

@ -0,0 +1,355 @@
#include "common.h"
#include <rwcore.h>
#include <rpworld.h>
#include "Lights.h"
#include "Timer.h"
#include "Timecycle.h"
#include "Coronas.h"
#include "Weather.h"
#include "ZoneCull.h"
#include "Frontend.h"
RpLight *pAmbient;
RpLight *pDirect;
RpLight *pExtraDirectionals[4] = { nil };
int LightStrengths[4];
int NumExtraDirLightsInWorld;
RwRGBAReal AmbientLightColourForFrame;
RwRGBAReal AmbientLightColourForFrame_PedsCarsAndObjects;
RwRGBAReal DirectionalLightColourForFrame;
RwRGBAReal AmbientLightColour;
RwRGBAReal DirectionalLightColour;
void
SetLightsWithTimeOfDayColour(RpWorld *)
{
CVector vec1, vec2, vecsun;
RwMatrix mat;
if(pAmbient){
AmbientLightColourForFrame.red = CTimeCycle::GetAmbientRed() * CCoronas::LightsMult;
AmbientLightColourForFrame.green = CTimeCycle::GetAmbientGreen() * CCoronas::LightsMult;
AmbientLightColourForFrame.blue = CTimeCycle::GetAmbientBlue() * CCoronas::LightsMult;
if(CWeather::LightningFlash && !CCullZones::CamNoRain()){
AmbientLightColourForFrame.red = 1.0f;
AmbientLightColourForFrame.green = 1.0f;
AmbientLightColourForFrame.blue = 1.0f;
}
AmbientLightColourForFrame_PedsCarsAndObjects.red = Min(1.0f, AmbientLightColourForFrame.red*1.3f);
AmbientLightColourForFrame_PedsCarsAndObjects.green = Min(1.0f, AmbientLightColourForFrame.green*1.3f);
AmbientLightColourForFrame_PedsCarsAndObjects.blue = Min(1.0f, AmbientLightColourForFrame.blue*1.3f);
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
}
if(pDirect){
DirectionalLightColourForFrame.red = CTimeCycle::GetDirectionalRed() * CCoronas::LightsMult;
DirectionalLightColourForFrame.green = CTimeCycle::GetDirectionalGreen() * CCoronas::LightsMult;
DirectionalLightColourForFrame.blue = CTimeCycle::GetDirectionalBlue() * CCoronas::LightsMult;
RpLightSetColor(pDirect, &DirectionalLightColourForFrame);
vecsun = CTimeCycle::m_VectorToSun[CTimeCycle::m_CurrentStoredValue];
vec1 = CVector(0.0f, 0.0f, 1.0f);
vec2 = CrossProduct(vec1, vecsun);
vec2.Normalise();
vec1 = CrossProduct(vec2, vecsun);
mat.at.x = -vecsun.x;
mat.at.y = -vecsun.y;
mat.at.z = -vecsun.z;
mat.right.x = vec1.x;
mat.right.y = vec1.y;
mat.right.z = vec1.z;
mat.up.x = vec2.x;
mat.up.y = vec2.y;
mat.up.z = vec2.z;
RwFrameTransform(RpLightGetFrame(pDirect), &mat, rwCOMBINEREPLACE);
}
if(CMenuManager::m_PrefsBrightness > 256){
float f1 = 2.0f * (CMenuManager::m_PrefsBrightness/256.0f - 1.0f) * 0.6f + 1.0f;
float f2 = 3.0f * (CMenuManager::m_PrefsBrightness/256.0f - 1.0f) * 0.6f + 1.0f;
AmbientLightColourForFrame.red = Min(1.0f, AmbientLightColourForFrame.red * f2);
AmbientLightColourForFrame.green = Min(1.0f, AmbientLightColourForFrame.green * f2);
AmbientLightColourForFrame.blue = Min(1.0f, AmbientLightColourForFrame.blue * f2);
AmbientLightColourForFrame_PedsCarsAndObjects.red = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.red * f1);
AmbientLightColourForFrame_PedsCarsAndObjects.green = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.green * f1);
AmbientLightColourForFrame_PedsCarsAndObjects.blue = Min(1.0f, AmbientLightColourForFrame_PedsCarsAndObjects.blue * f1);
#ifdef FIX_BUGS
DirectionalLightColourForFrame.red = Min(1.0f, DirectionalLightColourForFrame.red * f1);
DirectionalLightColourForFrame.green = Min(1.0f, DirectionalLightColourForFrame.green * f1);
DirectionalLightColourForFrame.blue = Min(1.0f, DirectionalLightColourForFrame.blue * f1);
#else
DirectionalLightColourForFrame.red = Min(1.0f, AmbientLightColourForFrame.red * f1);
DirectionalLightColourForFrame.green = Min(1.0f, AmbientLightColourForFrame.green * f1);
DirectionalLightColourForFrame.blue = Min(1.0f, AmbientLightColourForFrame.blue * f1);
#endif
}
}
RpWorld*
LightsCreate(RpWorld *world)
{
int i;
RwRGBAReal color;
RwFrame *frame;
if(world == nil)
return nil;
pAmbient = RpLightCreate(rpLIGHTAMBIENT);
RpLightSetFlags(pAmbient, rpLIGHTLIGHTATOMICS);
color.red = 0.25f;
color.green = 0.25f;
color.blue = 0.2f;
RpLightSetColor(pAmbient, &color);
pDirect = RpLightCreate(rpLIGHTDIRECTIONAL);
RpLightSetFlags(pDirect, rpLIGHTLIGHTATOMICS);
color.red = 1.0f;
color.green = 0.85f;
color.blue = 0.45f;
RpLightSetColor(pDirect, &color);
RpLightSetRadius(pDirect, 2.0f);
frame = RwFrameCreate();
RpLightSetFrame(pDirect, frame);
RwV3d axis = { 1.0f, 1.0f, 0.0f };
RwFrameRotate(frame, &axis, 160.0f, rwCOMBINEPRECONCAT);
RpWorldAddLight(world, pAmbient);
RpWorldAddLight(world, pDirect);
for(i = 0; i < NUMEXTRADIRECTIONALS; i++){
pExtraDirectionals[i] = RpLightCreate(rpLIGHTDIRECTIONAL);
RpLightSetFlags(pExtraDirectionals[i], 0);
color.red = 1.0f;
color.green = 0.5f;
color.blue = 0.0f;
RpLightSetColor(pExtraDirectionals[i], &color);
RpLightSetRadius(pExtraDirectionals[i], 2.0f);
frame = RwFrameCreate();
RpLightSetFrame(pExtraDirectionals[i], frame);
RpWorldAddLight(world, pExtraDirectionals[i]);
}
return world;
}
void
LightsDestroy(RpWorld *world)
{
int i;
if(world == nil)
return;
if(pAmbient){
RpWorldRemoveLight(world, pAmbient);
RpLightDestroy(pAmbient);
pAmbient = nil;
}
if(pDirect){
RpWorldRemoveLight(world, pDirect);
RwFrameDestroy(RpLightGetFrame(pDirect));
RpLightDestroy(pDirect);
pDirect = nil;
}
for(i = 0; i < NUMEXTRADIRECTIONALS; i++)
if(pExtraDirectionals[i]){
RpWorldRemoveLight(world, pExtraDirectionals[i]);
RwFrameDestroy(RpLightGetFrame(pExtraDirectionals[i]));
RpLightDestroy(pExtraDirectionals[i]);
pExtraDirectionals[i] = nil;
}
}
void
WorldReplaceNormalLightsWithScorched(RpWorld *world, float l)
{
RwRGBAReal color;
color.red = l;
color.green = l;
color.blue = l;
RpLightSetColor(pAmbient, &color);
RpLightSetFlags(pDirect, 0);
}
void
WorldReplaceScorchedLightsWithNormal(RpWorld *world)
{
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
RpLightSetFlags(pDirect, rpLIGHTLIGHTATOMICS);
}
void
AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, float red, float green, float blue)
{
float strength;
int weakest;
int i, n;
RwRGBAReal color;
RwV3d *dir;
strength = Max(Max(red, green), blue);
n = -1;
if(NumExtraDirLightsInWorld < NUMEXTRADIRECTIONALS)
n = NumExtraDirLightsInWorld;
else{
weakest = strength;
for(i = 0; i < NUMEXTRADIRECTIONALS; i++)
if(LightStrengths[i] < weakest){
weakest = LightStrengths[i];
n = i;
}
}
if(n < 0)
return;
color.red = red;
color.green = green;
color.blue = blue;
RpLightSetColor(pExtraDirectionals[n], &color);
dir = RwMatrixGetAt(RwFrameGetMatrix(RpLightGetFrame(pExtraDirectionals[n])));
dir->x = -dirx;
dir->y = -diry;
dir->z = -dirz;
RwMatrixUpdate(RwFrameGetMatrix(RpLightGetFrame(pExtraDirectionals[n])));
RwFrameUpdateObjects(RpLightGetFrame(pExtraDirectionals[n]));
RpLightSetFlags(pExtraDirectionals[n], rpLIGHTLIGHTATOMICS);
LightStrengths[n] = strength;
NumExtraDirLightsInWorld = Min(NumExtraDirLightsInWorld+1, NUMEXTRADIRECTIONALS);
}
void
RemoveExtraDirectionalLights(RpWorld *world)
{
int i;
for(i = 0; i < NumExtraDirLightsInWorld; i++)
RpLightSetFlags(pExtraDirectionals[i], 0);
NumExtraDirLightsInWorld = 0;
}
void
SetAmbientAndDirectionalColours(float f)
{
AmbientLightColour.red = AmbientLightColourForFrame.red * f;
AmbientLightColour.green = AmbientLightColourForFrame.green * f;
AmbientLightColour.blue = AmbientLightColourForFrame.blue * f;
DirectionalLightColour.red = DirectionalLightColourForFrame.red * f;
DirectionalLightColour.green = DirectionalLightColourForFrame.green * f;
DirectionalLightColour.blue = DirectionalLightColourForFrame.blue * f;
RpLightSetColor(pAmbient, &AmbientLightColour);
RpLightSetColor(pDirect, &DirectionalLightColour);
}
// unused
void
SetFlashyColours(float f)
{
if(CTimer::GetTimeInMilliseconds() & 0x100){
AmbientLightColour.red = 1.0f;
AmbientLightColour.green = 1.0f;
AmbientLightColour.blue = 1.0f;
DirectionalLightColour.red = DirectionalLightColourForFrame.red;
DirectionalLightColour.green = DirectionalLightColourForFrame.green;
DirectionalLightColour.blue = DirectionalLightColourForFrame.blue;
RpLightSetColor(pAmbient, &AmbientLightColour);
RpLightSetColor(pDirect, &DirectionalLightColour);
}else{
SetAmbientAndDirectionalColours(f * 0.75f);
}
}
// unused
void
SetFlashyColours_Mild(float f)
{
if(CTimer::GetTimeInMilliseconds() & 0x100){
AmbientLightColour.red = 0.65f;
AmbientLightColour.green = 0.65f;
AmbientLightColour.blue = 0.65f;
DirectionalLightColour.red = DirectionalLightColourForFrame.red;
DirectionalLightColour.green = DirectionalLightColourForFrame.green;
DirectionalLightColour.blue = DirectionalLightColourForFrame.blue;
RpLightSetColor(pAmbient, &AmbientLightColour);
RpLightSetColor(pDirect, &DirectionalLightColour);
}else{
SetAmbientAndDirectionalColours(f * 0.9f);
}
}
void
SetBrightMarkerColours(float f)
{
AmbientLightColour.red = 0.6f;
AmbientLightColour.green = 0.6f;
AmbientLightColour.blue = 0.6f;
DirectionalLightColour.red = (1.0f - DirectionalLightColourForFrame.red) * 0.4f + DirectionalLightColourForFrame.red;
DirectionalLightColour.green = (1.0f - DirectionalLightColourForFrame.green) * 0.4f + DirectionalLightColourForFrame.green;
DirectionalLightColour.blue = (1.0f - DirectionalLightColourForFrame.blue) * 0.4f + DirectionalLightColourForFrame.blue;
RpLightSetColor(pAmbient, &AmbientLightColour);
RpLightSetColor(pDirect, &DirectionalLightColour);
}
void
ReSetAmbientAndDirectionalColours(void)
{
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
RpLightSetColor(pDirect, &DirectionalLightColourForFrame);
}
void
DeActivateDirectional(void)
{
RpLightSetFlags(pDirect, 0);
}
void
ActivateDirectional(void)
{
RpLightSetFlags(pDirect, rpLIGHTLIGHTATOMICS);
}
void
SetAmbientColours(void)
{
RpLightSetColor(pAmbient, &AmbientLightColourForFrame);
}
void
SetAmbientColoursForPedsCarsAndObjects(void)
{
RpLightSetColor(pAmbient, &AmbientLightColourForFrame_PedsCarsAndObjects);
}
uint8 IndicateR[] = { 0, 255, 0, 0, 255, 255, 0 };
uint8 IndicateG[] = { 0, 0, 255, 0, 255, 0, 255 };
uint8 IndicateB[] = { 0, 0, 0, 255, 0, 255, 255 };
void
SetAmbientColoursToIndicateRoadGroup(int i)
{
AmbientLightColour.red = IndicateR[i%7]/255.0f;
AmbientLightColour.green = IndicateG[i%7]/255.0f;
AmbientLightColour.blue = IndicateB[i%7]/255.0f;
RpLightSetColor(pAmbient, &AmbientLightColour);
}
void
SetAmbientColours(RwRGBAReal *color)
{
RpLightSetColor(pAmbient, color);
}

26
src/rw/Lights.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
extern RpLight *pAmbient;
extern RpLight *pDirect;
extern RpLight *pExtraDirectionals[4];
extern int LightStrengths[4];
extern int NumExtraDirLightsInWorld;
void SetLightsWithTimeOfDayColour(RpWorld *);
RpWorld *LightsCreate(RpWorld *world);
void LightsDestroy(RpWorld *world);
void WorldReplaceNormalLightsWithScorched(RpWorld *world, float l);
void WorldReplaceScorchedLightsWithNormal(RpWorld *world);
void AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, float red, float green, float blue);
void RemoveExtraDirectionalLights(RpWorld *world);
void SetAmbientAndDirectionalColours(float f);
void SetFlashyColours(float f);
void SetFlashyColours_Mild(float f);
void SetBrightMarkerColours(float f);
void ReSetAmbientAndDirectionalColours(void);
void DeActivateDirectional(void);
void ActivateDirectional(void);
void SetAmbientColours(void);
void SetAmbientColoursForPedsCarsAndObjects(void);
void SetAmbientColoursToIndicateRoadGroup(int i);
void SetAmbientColours(RwRGBAReal *color);

497
src/rw/MemoryHeap.cpp Normal file
View file

@ -0,0 +1,497 @@
#include "common.h"
#include "main.h"
#include "FileMgr.h"
#include "Timer.h"
#include "ModelInfo.h"
#include "Streaming.h"
#include "FileLoader.h"
#include "MemoryHeap.h"
#ifdef USE_CUSTOM_ALLOCATOR
//#define MEMORYHEAP_ASSERT(cond) { if (!(cond)) { printf("ASSERT File:%s Line:%d\n", __FILE__, __LINE__); exit(1); } }
//#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) { if (!(cond)) { printf("ASSERT File:%s Line:%d:\n\t%s\n", __FILE__, __LINE__, message); exit(1); } }
#define MEMORYHEAP_ASSERT(cond) assert(cond)
#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) assert(cond)
// registered pointers that we keep track of
void **gPtrList[4000];
int32 numPtrs;
int32 gPosnInList;
// indices into the ptr list in here are free
CStack<int32, 4000> m_ptrListIndexStack;
// how much memory we've moved
uint32 memMoved;
CMemoryHeap gMainHeap;
void
CMemoryHeap::Init(uint32 total)
{
MEMORYHEAP_ASSERT((total != 0xF) != 0);
m_totalMemUsed = 0;
m_memUsed = nil;
m_currentMemID = MEMID_FREE;
m_blocksUsed = nil;
m_totalBlocksUsed = 0;
m_unkMemId = -1;
uint8 *mem = (uint8*)malloc(total);
assert(((uintptr)mem & 0xF) == 0);
m_start = (HeapBlockDesc*)mem;
m_end = (HeapBlockDesc*)(mem + total - sizeof(HeapBlockDesc));
m_start->m_memId = MEMID_FREE;
m_start->m_size = total - 2*sizeof(HeapBlockDesc);
m_end->m_memId = MEMID_GAME;
m_end->m_size = 0;
m_freeList.m_last.m_size = INT_MAX;
m_freeList.Init();
m_freeList.Insert(m_start);
// TODO: figure out what these are and use sizeof
m_fixedSize[0].Init(0x10);
m_fixedSize[1].Init(0x20);
m_fixedSize[2].Init(0xE0);
m_fixedSize[3].Init(0x60);
m_fixedSize[4].Init(0x1C0);
m_fixedSize[5].Init(0x50);
m_currentMemID = MEMID_FREE; // disable registration
m_memUsed = (uint32*)Malloc(NUM_MEMIDS * sizeof(uint32));
m_blocksUsed = (uint32*)Malloc(NUM_MEMIDS * sizeof(uint32));
RegisterMalloc(GetDescFromHeapPointer(m_memUsed));
RegisterMalloc(GetDescFromHeapPointer(m_blocksUsed));
m_currentMemID = MEMID_GAME;
for(int i = 0; i < NUM_MEMIDS; i++){
m_memUsed[i] = 0;
m_blocksUsed[i] = 0;
}
}
void
CMemoryHeap::RegisterMalloc(HeapBlockDesc *block)
{
block->m_memId = m_currentMemID;
if(m_currentMemID == MEMID_FREE)
return;
m_totalMemUsed += block->m_size + sizeof(HeapBlockDesc);
m_memUsed[m_currentMemID] += block->m_size + sizeof(HeapBlockDesc);
m_blocksUsed[m_currentMemID]++;
m_totalBlocksUsed++;
}
void
CMemoryHeap::RegisterFree(HeapBlockDesc *block)
{
if(block->m_memId == MEMID_FREE)
return;
m_totalMemUsed -= block->m_size + sizeof(HeapBlockDesc);
m_memUsed[block->m_memId] -= block->m_size + sizeof(HeapBlockDesc);
m_blocksUsed[block->m_memId]--;
m_totalBlocksUsed--;
}
void*
CMemoryHeap::Malloc(uint32 size)
{
static int recursion = 0;
// weird way to round up
if((size & 0xF) != 0)
size = (size&~0xF) + 0x10;
recursion++;
// See if we can allocate from one of the fixed-size lists
for(int i = 0; i < NUM_FIXED_MEMBLOCKS; i++){
CommonSize *list = &m_fixedSize[i];
if(m_fixedSize[i].m_size == size){
HeapBlockDesc *block = list->Malloc();
if(block){
RegisterMalloc(block);
recursion--;
return block->GetDataPointer();
}
break;
}
}
// now try the normal free list
HeapBlockDesc *next;
for(HeapBlockDesc *block = m_freeList.m_first.m_next;
block != &m_freeList.m_last;
block = next){
MEMORYHEAP_ASSERT(block->m_memId == MEMID_FREE);
MEMORYHEAP_ASSERT_MESSAGE(block >= m_start && block <= m_end, "Block outside of memory");
// make sure block has maximum size
uint32 initialsize = block->m_size;
uint32 blocksize = CombineFreeBlocks(block);
#ifdef FIX_BUGS
// has to be done here because block can be moved
next = block->m_next;
#endif
if(initialsize != blocksize){
block->RemoveHeapFreeBlock();
HeapBlockDesc *pos = block->m_prev->FindSmallestFreeBlock(block->m_size);
block->InsertHeapFreeBlock(pos->m_prev);
}
if(block->m_size >= size){
// got space to allocate from!
block->RemoveHeapFreeBlock();
FillInBlockData(block, block->GetNextConsecutive(), size);
recursion--;
return block->GetDataPointer();
}
#ifndef FIX_BUGS
next = block->m_next;
#endif
}
// oh no, we're losing, try to free some stuff
static bool removeCollision = false;
static bool removeIslands = false;
static bool removeBigBuildings = false;
size_t initialMemoryUsed = CStreaming::ms_memoryUsed;
CStreaming::MakeSpaceFor(0xCFE800 - CStreaming::ms_memoryUsed);
if (recursion > 10)
CGame::TidyUpMemory(true, false);
else if (recursion > 6)
CGame::TidyUpMemory(false, true);
if (initialMemoryUsed == CStreaming::ms_memoryUsed && recursion > 11) {
if (!removeCollision && !CGame::playingIntro) {
CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_GENERIC);
removeCollision = true;
}
else if (!removeIslands && !CGame::playingIntro) {
CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL);
CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL);
CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN);
removeIslands = true;
}
else if (!removeBigBuildings) {
CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL);
CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL);
CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN);
}
else {
LoadingScreen("NO MORE MEMORY", nil, nil);
LoadingScreen("NO MORE MEMORY", nil, nil);
}
CGame::TidyUpMemory(true, false);
}
void *mem = Malloc(size);
if (removeCollision) {
CTimer::Stop();
// TODO: different on PS2
CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory);
removeCollision = false;
CTimer::Update();
}
if (removeBigBuildings || removeIslands) {
CTimer::Stop();
if (!CGame::playingIntro)
CStreaming::RequestBigBuildings(CGame::currLevel);
CStreaming::LoadAllRequestedModels(true);
removeBigBuildings = false;
removeIslands = false;
CTimer::Update();
}
recursion--;
return mem;
}
void*
CMemoryHeap::Realloc(void *ptr, uint32 size)
{
if(ptr == nil)
return Malloc(size);
// weird way to round up
if((size & 0xF) != 0)
size = (size&~0xF) + 0x10;
HeapBlockDesc *block = GetDescFromHeapPointer(ptr);
#ifdef FIX_BUGS
// better handling of size < block->m_size
if(size == 0){
Free(ptr);
return nil;
}
if(block->m_size >= size){
// shrink allocated block
RegisterFree(block);
PushMemId(block->m_memId);
FillInBlockData(block, block->GetNextConsecutive(), size);
PopMemId();
return ptr;
}
#else
// not growing. just returning here is a bit cheap though
if(block->m_size >= size)
return ptr;
#endif
// have to grow allocated block
HeapBlockDesc *next = block->GetNextConsecutive();
MEMORYHEAP_ASSERT_MESSAGE(next >= m_start && next <= m_end, "Block outside of memory");
if(next->m_memId == MEMID_FREE){
// try to grow the current block
// make sure the next free block has maximum size
uint32 freespace = CombineFreeBlocks(next);
HeapBlockDesc *end = next->GetNextConsecutive();
MEMORYHEAP_ASSERT_MESSAGE(end >= m_start && end <= m_end, "Block outside of memory");
// why the sizeof here?
if(block->m_size + next->m_size + sizeof(HeapBlockDesc) >= size){
// enough space to grow
next->RemoveHeapFreeBlock();
RegisterFree(block);
PushMemId(block->m_memId);
FillInBlockData(block, next->GetNextConsecutive(), size);
PopMemId();
return ptr;
}
}
// can't grow the existing block, have to get a new one and copy
PushMemId(block->m_memId);
void *dst = Malloc(size);
PopMemId();
memcpy(dst, ptr, block->m_size);
Free(ptr);
return dst;
}
void
CMemoryHeap::Free(void *ptr)
{
HeapBlockDesc *block = GetDescFromHeapPointer(ptr);
MEMORYHEAP_ASSERT_MESSAGE(block->m_memId != MEMID_FREE, "MemoryHeap corrupt");
MEMORYHEAP_ASSERT(m_unkMemId == -1 || m_unkMemId == block->m_memId);
RegisterFree(block);
block->m_memId = MEMID_FREE;
CombineFreeBlocks(block);
FreeBlock(block);
if(block->m_ptrListIndex != -1){
int32 idx = block->m_ptrListIndex;
gPtrList[idx] = nil;
m_ptrListIndexStack.push(idx);
}
block->m_ptrListIndex = -1;
}
// allocate 'size' bytes from 'block'
void
CMemoryHeap::FillInBlockData(HeapBlockDesc *block, HeapBlockDesc *end, uint32 size)
{
block->m_size = size;
block->m_ptrListIndex = -1;
HeapBlockDesc *remainder = block->GetNextConsecutive();
MEMORYHEAP_ASSERT(remainder <= end);
if(remainder < end-1){
RegisterMalloc(block);
// can fit another block in the remaining space
remainder->m_size = GetSizeBetweenBlocks(remainder, end);
remainder->m_memId = MEMID_FREE;
MEMORYHEAP_ASSERT(remainder->m_size != 0);
FreeBlock(remainder);
}else{
// fully allocate this one
if(remainder < end)
// no gaps allowed
block->m_size = GetSizeBetweenBlocks(block, end);
RegisterMalloc(block);
}
}
// Make sure free block has no other free blocks after it
uint32
CMemoryHeap::CombineFreeBlocks(HeapBlockDesc *block)
{
HeapBlockDesc *next = block->GetNextConsecutive();
if(next->m_memId != MEMID_FREE)
return block->m_size;
// get rid of free blocks after this one and adjust size
for(; next->m_memId == MEMID_FREE; next = next->GetNextConsecutive())
next->RemoveHeapFreeBlock();
block->m_size = GetSizeBetweenBlocks(block, next);
return block->m_size;
}
// Try to move all registered memory blocks into more optimal location
void
CMemoryHeap::TidyHeap(void)
{
for(int i = 0; i < numPtrs; i++){
if(gPtrList[i] == nil || *gPtrList[i] == nil)
continue;
HeapBlockDesc *newblock = WhereShouldMemoryMove(*gPtrList[i]);
if(newblock)
*gPtrList[i] = MoveHeapBlock(newblock, GetDescFromHeapPointer(*gPtrList[i]));
}
}
//
void
CMemoryHeap::RegisterMemPointer(void *ptr)
{
HeapBlockDesc *block = GetDescFromHeapPointer(*(void**)ptr);
if(block->m_ptrListIndex != -1)
return; // already registered
int index;
if(m_ptrListIndexStack.sp > 0){
// re-use a previously free'd index
index = m_ptrListIndexStack.pop();
}else{
// have to find a new index
index = gPosnInList;
void **pp = gPtrList[index];
// we're replacing an old pointer here??
if(pp && *pp && *pp != (void*)0xDDDDDDDD)
GetDescFromHeapPointer(*pp)->m_ptrListIndex = -1;
gPosnInList++;
if(gPosnInList == 4000)
gPosnInList = 0;
if(numPtrs < 4000)
numPtrs++;
}
gPtrList[index] = (void**)ptr;
block->m_ptrListIndex = index;
}
void*
CMemoryHeap::MoveMemory(void *ptr)
{
HeapBlockDesc *newblock = WhereShouldMemoryMove(ptr);
if(newblock)
return MoveHeapBlock(newblock, GetDescFromHeapPointer(ptr));
else
return ptr;
}
HeapBlockDesc*
CMemoryHeap::WhereShouldMemoryMove(void *ptr)
{
HeapBlockDesc *block = GetDescFromHeapPointer(ptr);
MEMORYHEAP_ASSERT(block->m_memId != MEMID_FREE);
HeapBlockDesc *next = block->GetNextConsecutive();
if(next->m_memId != MEMID_FREE)
return nil;
// we want to move the block into another block
// such that the free space between this and the next block can be minimized
HeapBlockDesc *newblock = m_freeList.m_first.FindSmallestFreeBlock(block->m_size);
// size of free space wouldn't decrease, so return
if(newblock->m_size >= block->m_size + next->m_size)
return nil;
// size of free space wouldn't decrease enough
if(newblock->m_size >= 16 + 1.125f*block->m_size) // what are 16 and 1.125 here? sizeof(HeapBlockDesc)?
return nil;
return newblock;
}
void*
CMemoryHeap::MoveHeapBlock(HeapBlockDesc *dst, HeapBlockDesc *src)
{
PushMemId(src->m_memId);
dst->RemoveHeapFreeBlock();
FillInBlockData(dst, dst->GetNextConsecutive(), src->m_size);
PopMemId();
memcpy(dst->GetDataPointer(), src->GetDataPointer(), src->m_size);
memMoved += src->m_size;
dst->m_ptrListIndex = src->m_ptrListIndex;
src->m_ptrListIndex = -1;
Free(src->GetDataPointer());
return dst->GetDataPointer();
}
uint32
CMemoryHeap::GetMemoryUsed(int32 id)
{
return m_memUsed[id];
}
uint32
CMemoryHeap::GetBlocksUsed(int32 id)
{
return m_blocksUsed[id];
}
void
CMemoryHeap::PopMemId(void)
{
assert(m_idStack.sp > 0);
m_currentMemID = m_idStack.pop();
assert(m_currentMemID != MEMID_FREE);
}
void
CMemoryHeap::PushMemId(int32 id)
{
MEMORYHEAP_ASSERT(id != MEMID_FREE);
assert(m_idStack.sp < 16);
m_idStack.push(m_currentMemID);
m_currentMemID = id;
}
void
CMemoryHeap::ParseHeap(void)
{
char tmp[16];
int fd = CFileMgr::OpenFileForWriting("heap.txt");
CTimer::Stop();
// CMemoryHeap::IntegrityCheck();
uint32 addrQW = 0;
for(HeapBlockDesc *block = m_start; block < m_end; block = block->GetNextConsecutive()){
char chr = '*'; // free
if(block->m_memId != MEMID_FREE)
chr = block->m_memId-1 + 'A';
int numQW = block->m_size>>4;
if((addrQW & 0x3F) == 0){
sprintf(tmp, "\n%5dK:", addrQW>>6);
CFileMgr::Write(fd, tmp, 8);
}
CFileMgr::Write(fd, "#", 1); // the descriptor, has to be 16 bytes!!!!
addrQW++;
while(numQW--){
if((addrQW & 0x3F) == 0){
sprintf(tmp, "\n%5dK:", addrQW>>6);
CFileMgr::Write(fd, tmp, 8);
}
CFileMgr::Write(fd, &chr, 1);
addrQW++;
}
}
CTimer::Update();
CFileMgr::CloseFile(fd);
}
void
CommonSize::Init(uint32 size)
{
m_freeList.Init();
m_size = size;
m_failed = 0;
m_remaining = 0;
}
#endif

202
src/rw/MemoryHeap.h Normal file
View file

@ -0,0 +1,202 @@
#pragma once
// some windows shit
#ifdef MoveMemory
#undef MoveMemory
#endif
#ifdef USE_CUSTOM_ALLOCATOR
#define PUSH_MEMID(id) gMainHeap.PushMemId(id)
#define POP_MEMID() gMainHeap.PopMemId()
#define REGISTER_MEMPTR(ptr) gMainHeap.RegisterMemPointer(ptr)
#else
#define PUSH_MEMID(id)
#define POP_MEMID()
#define REGISTER_MEMPTR(ptr)
#endif
enum {
MEMID_FREE,
MEMID_GAME = 1, // "Game"
MEMID_WORLD = 2, // "World"
MEMID_ANIMATION = 3, // "Animation"
MEMID_POOLS = 4, // "Pools"
MEMID_DEF_MODELS = 5, // "Default Models"
MEMID_STREAM = 6, // "Streaming"
MEMID_STREAM_MODELS = 7, // "Streamed Models" (instance)
MEMID_STREAM_TEXUTRES = 8, // "Streamed Textures"
MEMID_TEXTURES = 9, // "Textures"
MEMID_COLLISION = 10, // "Collision"
MEMID_RENDERLIST = 11, // ?
MEMID_GAME_PROCESS = 12, // "Game Process"
MEMID_SCRIPT = 13, // "Script"
MEMID_CARS = 14, // "Cars"
MEMID_RENDER = 15, // "Render"
MEMID_FRONTEND = 17, // ?
NUM_MEMIDS,
NUM_FIXED_MEMBLOCKS = 6
};
template<typename T, uint32 N>
class CStack
{
public:
T values[N];
uint32 sp;
CStack() : sp(0) {}
void push(const T& val) { values[sp++] = val; }
T& pop() { return values[--sp]; }
};
struct HeapBlockDesc
{
uint32 m_size;
int16 m_memId;
int16 m_ptrListIndex;
HeapBlockDesc *m_next;
HeapBlockDesc *m_prev;
HeapBlockDesc *GetNextConsecutive(void)
{
return (HeapBlockDesc*)((uintptr)this + sizeof(HeapBlockDesc) + m_size);
}
void *GetDataPointer(void)
{
return (void*)((uintptr)this + sizeof(HeapBlockDesc));
}
void RemoveHeapFreeBlock(void)
{
m_next->m_prev = m_prev;
m_prev->m_next = m_next;
}
// after node
void InsertHeapFreeBlock(HeapBlockDesc *node)
{
m_next = node->m_next;
node->m_next->m_prev = this;
m_prev = node;
node->m_next = this;
}
HeapBlockDesc *FindSmallestFreeBlock(uint32 size)
{
HeapBlockDesc *b;
for(b = m_next; b->m_size < size; b = b->m_next);
return b;
}
};
#ifdef USE_CUSTOM_ALLOCATOR
// TODO: figure something out for 64 bit pointers
static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense");
#endif
struct HeapBlockList
{
HeapBlockDesc m_first;
HeapBlockDesc m_last;
void Init(void)
{
m_first.m_next = &m_last;
m_last.m_prev = &m_first;
}
void Insert(HeapBlockDesc *node)
{
node->InsertHeapFreeBlock(&m_first);
}
};
struct CommonSize
{
HeapBlockList m_freeList;
uint32 m_size;
uint32 m_failed;
uint32 m_remaining;
void Init(uint32 size);
void Free(HeapBlockDesc *node)
{
m_freeList.Insert(node);
m_remaining++;
}
HeapBlockDesc *Malloc(void)
{
if(m_freeList.m_first.m_next == &m_freeList.m_last){
m_failed++;
return nil;
}
HeapBlockDesc *block = m_freeList.m_first.m_next;
m_remaining--;
block->RemoveHeapFreeBlock();
block->m_ptrListIndex = -1;
return block;
}
};
class CMemoryHeap
{
public:
HeapBlockDesc *m_start;
HeapBlockDesc *m_end;
HeapBlockList m_freeList;
CommonSize m_fixedSize[NUM_FIXED_MEMBLOCKS];
uint32 m_totalMemUsed;
CStack<int32, 16> m_idStack;
uint32 m_currentMemID;
uint32 *m_memUsed;
uint32 m_totalBlocksUsed;
uint32 *m_blocksUsed;
uint32 m_unkMemId;
CMemoryHeap(void) : m_start(nil) {}
void Init(uint32 total);
void RegisterMalloc(HeapBlockDesc *block);
void RegisterFree(HeapBlockDesc *block);
void *Malloc(uint32 size);
void *Realloc(void *ptr, uint32 size);
void Free(void *ptr);
void FillInBlockData(HeapBlockDesc *block, HeapBlockDesc *end, uint32 size);
uint32 CombineFreeBlocks(HeapBlockDesc *block);
void *MoveMemory(void *ptr);
HeapBlockDesc *WhereShouldMemoryMove(void *ptr);
void *MoveHeapBlock(HeapBlockDesc *dst, HeapBlockDesc *src);
void PopMemId(void);
void PushMemId(int32 id);
void RegisterMemPointer(void *ptr);
void TidyHeap(void);
uint32 GetMemoryUsed(int32 id);
uint32 GetBlocksUsed(int32 id);
int32 GetLargestFreeBlock(void) { return m_freeList.m_last.m_prev->m_size; }
void ParseHeap(void);
HeapBlockDesc *GetDescFromHeapPointer(void *block)
{
return (HeapBlockDesc*)((uintptr)block - sizeof(HeapBlockDesc));
}
uint32 GetSizeBetweenBlocks(HeapBlockDesc *first, HeapBlockDesc *second)
{
return (uintptr)second - (uintptr)first - sizeof(HeapBlockDesc);
}
void FreeBlock(HeapBlockDesc *block){
for(int i = 0; i < NUM_FIXED_MEMBLOCKS; i++){
if(m_fixedSize[i].m_size == block->m_size){
m_fixedSize[i].Free(block);
return;
}
}
HeapBlockDesc *b = m_freeList.m_first.FindSmallestFreeBlock(block->m_size);
block->InsertHeapFreeBlock(b->m_prev);
}
};
extern CMemoryHeap gMainHeap;

130
src/rw/MemoryMgr.cpp Normal file
View file

@ -0,0 +1,130 @@
#include "common.h"
#include "MemoryHeap.h"
#include "MemoryMgr.h"
uint8 *pMemoryTop;
void
InitMemoryMgr(void)
{
#ifdef USE_CUSTOM_ALLOCATOR
#ifdef GTA_PS2
#error "finish this"
#else
// randomly allocate 128mb
gMainHeap.Init(128*1024*1024);
#endif
#endif
}
RwMemoryFunctions memFuncs = {
MemoryMgrMalloc,
MemoryMgrFree,
MemoryMgrRealloc,
MemoryMgrCalloc
};
#ifdef USE_CUSTOM_ALLOCATOR
// game seems to be using heap directly here, but this is nicer
void *operator new(size_t sz) throw() { return MemoryMgrMalloc(sz); }
void *operator new[](size_t sz) throw() { return MemoryMgrMalloc(sz); }
void operator delete(void *ptr) throw() { MemoryMgrFree(ptr); }
void operator delete[](void *ptr) throw() { MemoryMgrFree(ptr); }
#endif
void*
MemoryMgrMalloc(size_t size)
{
#ifdef USE_CUSTOM_ALLOCATOR
void *mem = gMainHeap.Malloc(size);
#else
void *mem = malloc(size);
#endif
if((uint8*)mem + size > pMemoryTop)
pMemoryTop = (uint8*)mem + size ;
return mem;
}
void*
MemoryMgrRealloc(void *ptr, size_t size)
{
#ifdef USE_CUSTOM_ALLOCATOR
void *mem = gMainHeap.Realloc(ptr, size);
#else
void *mem = realloc(ptr, size);
#endif
if((uint8*)mem + size > pMemoryTop)
pMemoryTop = (uint8*)mem + size ;
return mem;
}
void*
MemoryMgrCalloc(size_t num, size_t size)
{
#ifdef USE_CUSTOM_ALLOCATOR
void *mem = gMainHeap.Malloc(num*size);
#else
void *mem = calloc(num, size);
#endif
if((uint8*)mem + size > pMemoryTop)
pMemoryTop = (uint8*)mem + size ;
#ifdef FIX_BUGS
memset(mem, 0, num*size);
#endif
return mem;
}
void
MemoryMgrFree(void *ptr)
{
#ifdef USE_CUSTOM_ALLOCATOR
#ifdef FIX_BUGS
// i don't suppose this is handled by RW?
if(ptr == nil) return;
#endif
gMainHeap.Free(ptr);
#else
free(ptr);
#endif
}
void *
RwMallocAlign(RwUInt32 size, RwUInt32 align)
{
#if defined (FIX_BUGS) || defined(FIX_BUGS_64)
uintptr ptralign = align-1;
void *mem = (void *)MemoryMgrMalloc(size + sizeof(uintptr) + ptralign);
ASSERT(mem != nil);
void *addr = (void *)((((uintptr)mem) + sizeof(uintptr) + ptralign) & ~ptralign);
ASSERT(addr != nil);
#else
void *mem = (void *)MemoryMgrMalloc(size + align);
ASSERT(mem != nil);
void *addr = (void *)((((uintptr)mem) + align) & ~(align - 1));
ASSERT(addr != nil);
#endif
*(((void **)addr) - 1) = mem;
return addr;
}
void
RwFreeAlign(void *mem)
{
ASSERT(mem != nil);
void *addr = *(((void **)mem) - 1);
ASSERT(addr != nil);
MemoryMgrFree(addr);
}

12
src/rw/MemoryMgr.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
extern RwMemoryFunctions memFuncs;
void InitMemoryMgr(void);
void *MemoryMgrMalloc(size_t size);
void *MemoryMgrRealloc(void *ptr, size_t size);
void *MemoryMgrCalloc(size_t num, size_t size);
void MemoryMgrFree(void *ptr);
void *RwMallocAlign(RwUInt32 size, RwUInt32 align);
void RwFreeAlign(void *mem);

77
src/rw/NodeName.cpp Normal file
View file

@ -0,0 +1,77 @@
#include "common.h"
#include "NodeName.h"
static int32 gPluginOffset;
enum
{
ID_NODENAME = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0xFE),
};
#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset))
void*
NodeNameConstructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
if(gPluginOffset > 0)
NODENAMEEXT(object)[0] = '\0';
return object;
}
void*
NodeNameDestructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
return object;
}
void*
NodeNameCopy(void *dstObject, const void *srcObject, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
strncpy(NODENAMEEXT(dstObject), NODENAMEEXT(srcObject), 23);
return nil;
}
RwStream*
NodeNameStreamRead(RwStream *stream, RwInt32 binaryLength, void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
RwStreamRead(stream, NODENAMEEXT(object), binaryLength);
NODENAMEEXT(object)[binaryLength] = '\0';
return stream;
}
RwStream*
NodeNameStreamWrite(RwStream *stream, RwInt32 binaryLength, const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
RwStreamWrite(stream, NODENAMEEXT(object), binaryLength);
return stream;
}
RwInt32
NodeNameStreamGetSize(const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
{
char *name = NODENAMEEXT(object); // can't be nil
return name ? (RwInt32)rwstrlen(name) : 0;
}
bool
NodeNamePluginAttach(void)
{
gPluginOffset = RwFrameRegisterPlugin(24, ID_NODENAME,
NodeNameConstructor,
NodeNameDestructor,
NodeNameCopy);
RwFrameRegisterPluginStream(ID_NODENAME,
NodeNameStreamRead,
NodeNameStreamWrite,
NodeNameStreamGetSize);
return gPluginOffset != -1;
}
char*
GetFrameNodeName(RwFrame *frame)
{
if(gPluginOffset < 0)
return nil;
return NODENAMEEXT(frame);
}

4
src/rw/NodeName.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
bool NodeNamePluginAttach(void);
char *GetFrameNodeName(RwFrame *frame);

735
src/rw/RwHelper.cpp Normal file
View file

@ -0,0 +1,735 @@
#define WITHD3D
#include "common.h"
#include <rpskin.h>
#include "RwHelper.h"
#include "Timecycle.h"
#include "skeleton.h"
#include "Debug.h"
#include "MBlur.h"
#if !defined(FINAL) || defined(DEBUGMENU)
#include "rtcharse.h"
#endif
#ifndef FINAL
RtCharset *debugCharset;
bool bDebugRenderGroups;
#endif
#ifdef PS2_ALPHA_TEST
bool gPS2alphaTest = true;
#else
bool gPS2alphaTest = false;
#endif
bool gBackfaceCulling = true;
#if !defined(FINAL) || defined(DEBUGMENU)
static bool charsetOpen;
void OpenCharsetSafe()
{
if(!charsetOpen)
RtCharsetOpen();
charsetOpen = true;
}
#endif
void CreateDebugFont()
{
#ifndef FINAL
RwRGBA color = { 255, 255, 128, 255 };
RwRGBA colorbg = { 0, 0, 0, 0 };
OpenCharsetSafe();
debugCharset = RtCharsetCreate(&color, &colorbg);
#endif
}
void DestroyDebugFont()
{
#ifndef FINAL
RtCharsetDestroy(debugCharset);
RtCharsetClose();
charsetOpen = false;
#endif
}
void ObrsPrintfString(const char *str, short x, short y)
{
#ifndef FINAL
RtCharsetPrintBuffered(debugCharset, str, x*8, y*16, true);
#endif
}
void FlushObrsPrintfs()
{
#ifndef FINAL
RtCharsetBufferFlush();
#endif
}
void
DefinedState(void)
{
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP);
RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255));
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR);
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
#ifdef LIBRW
rw::SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
rw::SetRenderState(rw::GSALPHATEST, gPS2alphaTest);
#else
// D3D stuff
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
#endif
SetAlphaRef(2);
}
void
SetAlphaRef(int ref)
{
#ifdef LIBRW
rw::SetRenderState(rw::ALPHATESTREF, ref+1);
#else
RwD3D8SetRenderState(D3DRS_ALPHAREF, ref);
#endif
}
void
SetCullMode(uint32 mode)
{
if(gBackfaceCulling)
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)mode);
else
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
}
#ifndef FINAL
void
PushRendergroup(const char *name)
{
if(!bDebugRenderGroups)
return;
#if defined(RW_OPENGL)
if(GLAD_GL_KHR_debug)
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, name);
#elif defined(RW_D3D9)
static WCHAR tmp[256];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, tmp, sizeof(tmp));
D3DPERF_BeginEvent(0xFFFFFFFF, tmp);
#endif
}
void
PopRendergroup(void)
{
if(!bDebugRenderGroups)
return;
#if defined(RW_OPENGL)
if(GLAD_GL_KHR_debug)
glPopDebugGroup();
#elif defined(RW_D3D9)
D3DPERF_EndEvent();
#endif
}
#endif
RwFrame*
GetFirstFrameCallback(RwFrame *child, void *data)
{
*(RwFrame**)data = child;
return nil;
}
RwFrame*
GetFirstChild(RwFrame *frame)
{
RwFrame *child;
child = nil;
RwFrameForAllChildren(frame, GetFirstFrameCallback, &child);
return child;
}
RwObject*
GetFirstObjectCallback(RwObject *object, void *data)
{
*(RwObject**)data = object;
return nil;
}
RwObject*
GetFirstObject(RwFrame *frame)
{
RwObject *obj;
obj = nil;
RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj);
return obj;
}
RpAtomic*
GetFirstAtomicCallback(RpAtomic *atm, void *data)
{
*(RpAtomic**)data = atm;
return nil;
}
RpAtomic*
GetFirstAtomic(RpClump *clump)
{
RpAtomic *atm;
atm = nil;
RpClumpForAllAtomics(clump, GetFirstAtomicCallback, &atm);
return atm;
}
RwTexture*
GetFirstTextureCallback(RwTexture *tex, void *data)
{
*(RwTexture**)data = tex;
return nil;
}
RwTexture*
GetFirstTexture(RwTexDictionary *txd)
{
RwTexture *tex;
tex = nil;
RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex);
return tex;
}
#ifdef PED_SKIN
static RpAtomic*
isSkinnedCb(RpAtomic *atomic, void *data)
{
RpAtomic **pAtomic = (RpAtomic**)data;
if(*pAtomic)
return nil; // already found one
if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)))
*pAtomic = atomic; // we could just return nil here directly...
return atomic;
}
RpAtomic*
IsClumpSkinned(RpClump *clump)
{
RpAtomic *atomic = nil;
RpClumpForAllAtomics(clump, isSkinnedCb, &atomic);
return atomic;
}
static RpAtomic*
GetAnimHierarchyCallback(RpAtomic *atomic, void *data)
{
*(RpHAnimHierarchy**)data = RpSkinAtomicGetHAnimHierarchy(atomic);
return nil;
}
RpHAnimHierarchy*
GetAnimHierarchyFromSkinClump(RpClump *clump)
{
RpHAnimHierarchy *hier = nil;
RpClumpForAllAtomics(clump, GetAnimHierarchyCallback, &hier);
return hier;
}
static RwFrame*
GetAnimHierarchyFromClumpCB(RwFrame *frame, void *data)
{
RpHAnimHierarchy *hier = RpHAnimFrameGetHierarchy(frame);
if(hier){
*(RpHAnimHierarchy**)data = hier;
return nil;
}
RwFrameForAllChildren(frame, GetAnimHierarchyFromClumpCB, data);
return frame;
}
RpHAnimHierarchy*
GetAnimHierarchyFromClump(RpClump *clump)
{
RpHAnimHierarchy *hier = nil;
RwFrameForAllChildren(RpClumpGetFrame(clump), GetAnimHierarchyFromClumpCB, &hier);
return hier;
}
RwFrame*
GetHierarchyFromChildNodesCB(RwFrame *frame, void *data)
{
RpHAnimHierarchy **pHier = (RpHAnimHierarchy**)data;
RpHAnimHierarchy *hier = RpHAnimFrameGetHierarchy(frame);
if(hier == nil)
RwFrameForAllChildren(frame, GetHierarchyFromChildNodesCB, &hier);
*pHier = hier;
return nil;
}
void
SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable)
{
int i, parent;
RpAtomic *atomic;
RpSkin *skin;
RpHAnimHierarchy *hier;
int numBones;
RwMatrix m, invmat;
int stack[32];
int sp;
if(boneTable == nil)
return;
// atomic = GetFirstAtomic(clump); // mobile, also VC
atomic = IsClumpSkinned(clump); // xbox, seems safer
assert(atomic);
skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic));
assert(skin);
hier = GetAnimHierarchyFromSkinClump(clump);
assert(hier);
boneTable[0].x = 0.0f;
boneTable[0].y = 0.0f;
boneTable[0].z = 0.0f;
numBones = RpSkinGetNumBones(skin);
parent = 0;
sp = 0;
#ifdef FIX_BUGS
stack[0] = 0; // i think this is ok
#endif
for(i = 1; i < numBones; i++){
RwMatrixCopy(&m, &RpSkinGetSkinToBoneMatrices(skin)[i]);
RwMatrixInvert(&invmat, &m);
const RwMatrix *x = RpSkinGetSkinToBoneMatrices(skin);
RwV3dTransformPoints(&boneTable[i], &invmat.pos, 1, &x[parent]);
if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX)
stack[++sp] = parent;
if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX)
parent = stack[sp--];
else
parent = i;
//assert(parent >= 0 && parent < numBones);
}
}
RpHAnimAnimation*
HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier)
{
int i;
#if defined FIX_BUGS || defined LIBRW
int numNodes = hier->numNodes*2; // you're supposed to have at least two KFs per node
#else
int numNodes = hier->numNodes;
#endif
RpHAnimAnimation *anim = RpHAnimAnimationCreate(rpHANIMSTDKEYFRAMETYPEID, numNodes, 0, 0.0f);
if(anim == nil)
return nil;
RpHAnimStdKeyFrame *frame;
for(i = 0; i < numNodes; i++){
frame = (RpHAnimStdKeyFrame*)HANIMFRAME(anim, i); // games uses struct size here, not safe
frame->q.real = 1.0f;
frame->q.imag.x = frame->q.imag.y = frame->q.imag.z = 0.0f;
frame->t.x = frame->t.y = frame->t.z = 0.0f;
#if defined FIX_BUGS || defined LIBRW
// times are subtracted and divided giving NaNs
// so they can't both be 0
frame->time = i/hier->numNodes;
#else
frame->time = 0.0f;
#endif
frame->prevFrame = nil;
}
return anim;
}
void
RenderSkeleton(RpHAnimHierarchy *hier)
{
int i;
int sp;
int stack[32];
int par;
CVector p1, p2;
int numNodes = hier->numNodes;
RwMatrix *mats = RpHAnimHierarchyGetMatrixArray(hier);
p1 = mats[0].pos;
par = 0;
sp = 0;
stack[sp++] = par;
for(i = 1; i < numNodes; i++){
p1 = mats[par].pos;
p2 = mats[i].pos;
CDebug::AddLine(p1, p2, 0xFFFFFFFF, 0xFFFFFFFF);
if(HIERNODEINFO(hier)[i].flags & rpHANIMPUSHPARENTMATRIX)
stack[sp++] = par;
par = i;
if(HIERNODEINFO(hier)[i].flags & rpHANIMPOPPARENTMATRIX)
par = stack[--sp];
}
}
#endif
void
CameraSize(RwCamera * camera, RwRect * rect,
RwReal viewWindow, RwReal aspectRatio)
{
if (camera)
{
RwVideoMode videoMode;
RwRect r;
RwRect origSize = { 0, 0, 0, 0 }; // FIX just to make the compier happy
RwV2d vw;
RwEngineGetVideoModeInfo(&videoMode,
RwEngineGetCurrentVideoMode());
origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera));
origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera));
if (!rect)
{
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
{
/* For full screen applications, resizing the camera just doesn't
* make sense, use the video mode size.
*/
r.x = r.y = 0;
r.w = videoMode.width;
r.h = videoMode.height;
rect = &r;
}
else
{
/*
rect not specified - reuse current values
*/
r.w = RwRasterGetWidth(RwCameraGetRaster(camera));
r.h = RwRasterGetHeight(RwCameraGetRaster(camera));
r.x = r.y = 0;
rect = &r;
}
}
if (( origSize.w != rect->w ) || ( origSize.h != rect->h ))
{
RwRaster *raster;
RwRaster *zRaster;
// BUG: game just changes camera raster's sizes, but this is a hack
#if defined FIX_BUGS || defined LIBRW
/*
* Destroy rasters...
*/
raster = RwCameraGetRaster(camera);
if( raster )
{
RwRasterDestroy(raster);
camera->frameBuffer = nil;
}
zRaster = RwCameraGetZRaster(camera);
if( zRaster )
{
RwRasterDestroy(zRaster);
camera->zBuffer = nil;
}
/*
* Create new rasters...
*/
raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
if( raster && zRaster )
{
RwCameraSetRaster(camera, raster);
RwCameraSetZRaster(camera, zRaster);
}
else
{
if( raster )
{
RwRasterDestroy(raster);
}
if( zRaster )
{
RwRasterDestroy(zRaster);
}
rect->x = origSize.x;
rect->y = origSize.y;
rect->w = origSize.w;
rect->h = origSize.h;
/*
* Use default values...
*/
raster =
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA);
zRaster =
RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER);
RwCameraSetRaster(camera, raster);
RwCameraSetZRaster(camera, zRaster);
}
#else
raster = RwCameraGetRaster(camera);
zRaster = RwCameraGetZRaster(camera);
raster->width = zRaster->width = rect->w;
raster->height = zRaster->height = rect->h;
#endif
#ifdef FIX_BUGS
if(CMBlur::BlurOn){
CMBlur::MotionBlurClose();
CMBlur::MotionBlurOpen(camera);
}
#endif
}
/* Figure out the view window */
if (videoMode.flags & rwVIDEOMODEEXCLUSIVE)
{
/* derive ratio from aspect ratio */
vw.x = viewWindow;
vw.y = viewWindow / aspectRatio;
}
else
{
/* derive from pixel ratios */
if (rect->w > rect->h)
{
vw.x = viewWindow;
vw.y = (rect->h * viewWindow) / rect->w;
}
else
{
vw.x = (rect->w * viewWindow) / rect->h;
vw.y = viewWindow;
}
}
RwCameraSetViewWindow(camera, &vw);
RsGlobal.width = rect->w;
RsGlobal.height = rect->h;
}
return;
}
void
CameraDestroy(RwCamera *camera)
{
RwRaster *raster, *tmpRaster;
RwFrame *frame;
if (camera)
{
frame = RwCameraGetFrame(camera);
if (frame)
{
RwFrameDestroy(frame);
}
raster = RwCameraGetRaster(camera);
if (raster)
{
tmpRaster = RwRasterGetParent(raster);
RwRasterDestroy(raster);
if ((tmpRaster != nil) && (tmpRaster != raster))
{
RwRasterDestroy(tmpRaster);
}
}
raster = RwCameraGetZRaster(camera);
if (raster)
{
tmpRaster = RwRasterGetParent(raster);
RwRasterDestroy(raster);
if ((tmpRaster != nil) && (tmpRaster != raster))
{
RwRasterDestroy(tmpRaster);
}
}
RwCameraDestroy(camera);
}
return;
}
RwCamera *
CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer)
{
RwCamera *camera;
camera = RwCameraCreate();
if (camera)
{
RwCameraSetFrame(camera, RwFrameCreate());
RwCameraSetRaster(camera,
RwRasterCreate(0, 0, 0, rwRASTERTYPECAMERA));
if (zBuffer)
{
RwCameraSetZRaster(camera,
RwRasterCreate(0, 0, 0,
rwRASTERTYPEZBUFFER));
}
/* now check that everything is valid */
if (RwCameraGetFrame(camera) &&
RwCameraGetRaster(camera) &&
RwRasterGetParent(RwCameraGetRaster(camera)) &&
(!zBuffer || (RwCameraGetZRaster(camera) &&
RwRasterGetParent(RwCameraGetZRaster
(camera)))))
{
/* everything OK */
return (camera);
}
}
/* if we're here then an error must have occurred so clean up */
CameraDestroy(camera);
return (nil);
}
#ifdef LIBRW
#include <rpmatfx.h>
#include "VehicleModelInfo.h"
int32
findPlatform(rw::Atomic *a)
{
rw::Geometry *g = a->geometry;
if(g->instData)
return g->instData->platform;
return 0;
}
// in CVehicleModelInfo in VC
static RpMaterial*
GetMatFXEffectMaterialCB(RpMaterial *material, void *data)
{
if(RpMatFXMaterialGetEffects(material) == rpMATFXEFFECTNULL)
return material;
*(int*)data = RpMatFXMaterialGetEffects(material);
return nil;
}
// Game doesn't read atomic extensions so we never get any other than the default pipe,
// but we need it for uninstancing
void
attachPipe(rw::Atomic *atomic)
{
if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic)))
atomic->pipeline = rw::skinGlobals.pipelines[rw::platform];
else{
int fx = rpMATFXEFFECTNULL;
RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), GetMatFXEffectMaterialCB, &fx);
if(fx != rpMATFXEFFECTNULL)
RpMatFXAtomicEnableEffects(atomic);
}
}
// Attach pipes for the platform we have native data for so we can uninstance
void
switchPipes(rw::Atomic *a, int32 platform)
{
if(a->pipeline && a->pipeline->platform != platform){
uint32 plgid = a->pipeline->pluginID;
switch(plgid){
// assume default pipe won't be attached explicitly
case rw::ID_SKIN:
a->pipeline = rw::skinGlobals.pipelines[platform];
break;
case rw::ID_MATFX:
a->pipeline = rw::matFXGlobals.pipelines[platform];
break;
}
}
}
RpAtomic*
ConvertPlatformAtomic(RpAtomic *atomic, void *data)
{
int32 driver = rw::platform;
int32 platform = findPlatform(atomic);
if(platform != 0 && platform != driver){
attachPipe(atomic); // kludge
rw::ObjPipeline *origPipe = atomic->pipeline;
rw::platform = platform;
switchPipes(atomic, rw::platform);
if(atomic->geometry->flags & rw::Geometry::NATIVE)
atomic->uninstance();
// no ADC in this game
//rw::ps2::unconvertADC(atomic->geometry);
rw::platform = driver;
atomic->pipeline = origPipe;
}
return atomic;
}
#endif
#if defined(FIX_BUGS) && defined(GTA_PC)
RwUInt32 saved_alphafunc, saved_alpharef;
void
SetAlphaTest(RwUInt32 alpharef)
{
#ifdef LIBRW
saved_alphafunc = rw::GetRenderState(rw::ALPHATESTFUNC);
saved_alpharef = rw::GetRenderState(rw::ALPHATESTREF);
rw::SetRenderState(rw::ALPHATESTFUNC, rw::ALPHAGREATEREQUAL);
rw::SetRenderState(rw::ALPHATESTREF, 0);
#else
RwD3D8GetRenderState(D3DRS_ALPHAFUNC, &saved_alphafunc);
RwD3D8GetRenderState(D3DRS_ALPHAREF, &saved_alpharef);
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
RwD3D8SetRenderState(D3DRS_ALPHAREF, alpharef);
#endif
}
void
RestoreAlphaTest()
{
#ifdef LIBRW
rw::SetRenderState(rw::ALPHATESTFUNC, saved_alphafunc);
rw::SetRenderState(rw::ALPHATESTREF, saved_alpharef);
#else
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, saved_alphafunc);
RwD3D8SetRenderState(D3DRS_ALPHAREF, saved_alpharef);
#endif
}
#endif

63
src/rw/RwHelper.h Normal file
View file

@ -0,0 +1,63 @@
#pragma once
extern bool bDebugRenderGroups;
extern bool gPS2alphaTest;
void OpenCharsetSafe();
void CreateDebugFont();
void DestroyDebugFont();
void ObrsPrintfString(const char *str, short x, short y);
void FlushObrsPrintfs();
void DefinedState(void);
void SetAlphaRef(int ref);
void SetCullMode(uint32 mode);
RwFrame *GetFirstChild(RwFrame *frame);
RwObject *GetFirstObject(RwFrame *frame);
RpAtomic *GetFirstAtomic(RpClump *clump);
RwTexture *GetFirstTexture(RwTexDictionary *txd);
#ifdef PED_SKIN
RpAtomic *IsClumpSkinned(RpClump *clump);
RpHAnimHierarchy *GetAnimHierarchyFromSkinClump(RpClump *clump); // get from atomic
RpHAnimHierarchy *GetAnimHierarchyFromClump(RpClump *clump); // get from frame
RwFrame *GetHierarchyFromChildNodesCB(RwFrame *frame, void *data);
void SkinGetBonePositionsToTable(RpClump *clump, RwV3d *boneTable);
RpHAnimAnimation *HAnimAnimationCreateForHierarchy(RpHAnimHierarchy *hier);
RpAtomic *AtomicRemoveAnimFromSkinCB(RpAtomic *atomic, void *data);
void RenderSkeleton(RpHAnimHierarchy *hier);
#endif
RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream);
RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream);
RwTexDictionary *RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict);
void ReadVideoCardCapsFile(uint32&, uint32&, uint32&, uint32&);
bool CheckVideoCardCaps(void);
void WriteVideoCardCapsFile(void);
void ConvertingTexturesScreen(uint32, uint32, const char*);
void DealWithTxdWriteError(uint32, uint32, const char*);
bool CreateTxdImageForVideoCard();
bool RpClumpGtaStreamRead1(RwStream *stream);
RpClump *RpClumpGtaStreamRead2(RwStream *stream);
void RpClumpGtaCancelStream(void);
void CameraSize(RwCamera *camera,
RwRect *rect,
RwReal viewWindow,
RwReal aspectRatio);
void CameraDestroy(RwCamera *camera);
RwCamera *CameraCreate(RwInt32 width,
RwInt32 height,
RwBool zBuffer);
RpAtomic *ConvertPlatformAtomic(RpAtomic *atomic, void *data);
#if defined(FIX_BUGS) && defined (GTA_PC)
void SetAlphaTest(RwUInt32 alpharef);
void RestoreAlphaTest();
#else
#define SetAlphaTest(a) (0)
#define RestoreAlphaTest() (0)
#endif

312
src/rw/RwMatFX.cpp Normal file
View file

@ -0,0 +1,312 @@
#ifndef LIBRW
#define WITHD3D
#include "common.h"
#include "rpmatfx.h"
struct MatFXNothing { int pad[5]; int effect; };
struct MatFXBump
{
RwFrame *bumpFrame;
RwTexture *bumpedTex;
RwTexture *bumpTex;
float negBumpCoefficient;
int pad;
int effect;
};
struct MatFXEnv
{
RwFrame *envFrame;
RwTexture *envTex;
float envCoeff;
int envFBalpha;
int pad;
int effect;
};
struct MatFXDual
{
RwTexture *dualTex;
RwInt32 srcBlend;
RwInt32 dstBlend;
};
struct MatFX
{
union {
MatFXNothing n;
MatFXBump b;
MatFXEnv e;
MatFXDual d;
} fx[2];
int effects;
};
extern "C" {
extern int MatFXMaterialDataOffset;
extern int MatFXAtomicDataOffset;
void _rpMatFXD3D8AtomicMatFXEnvRender(RxD3D8InstanceData* inst, int flags, int sel, RwTexture* texture, RwTexture* envMap);
void _rpMatFXD3D8AtomicMatFXRenderBlack(RxD3D8InstanceData *inst);
void _rpMatFXD3D8AtomicMatFXBumpMapRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *bumpMap, RwTexture *envMap);
void _rpMatFXD3D8AtomicMatFXDualPassRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *dualTexture);
}
#ifdef PS2_MATFX
void
_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture)
{
if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
RwD3D8SetTexture(texture, 0);
else
RwD3D8SetTexture(nil, 0);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0);
RwD3D8SetPixelShader(0);
RwD3D8SetVertexShader(inst->vertexShader);
RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
if(inst->indexBuffer){
RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
}else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
}
// map [-1; -1] -> [0; 1], flip V
static RwMatrix scalenormal = {
{ 0.5f, 0.0f, 0.0f }, 0,
{ 0.0f, -0.5f, 0.0f }, 0,
{ 0.0f, 0.0f, 1.0f }, 0,
{ 0.5f, 0.5f, 0.0f }, 0,
};
// flipped U for PS2
static RwMatrix scalenormal_flipU = {
{ -0.5f, 0.0f, 0.0f }, 0,
{ 0.0f, -0.5f, 0.0f }, 0,
{ 0.0f, 0.0f, 1.0f }, 0,
{ 0.5f, 0.5f, 0.0f }, 0,
};
void
ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame)
{
RwD3D8SetTexture(tex, n);
RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2);
RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL);
if(frame){
RwMatrix *envframemat = RwMatrixCreate();
RwMatrix *tmpmat = RwMatrixCreate();
RwMatrix *envmat = RwMatrixCreate();
RwMatrixInvert(envframemat, RwFrameGetLTM(frame));
// PS2
// can this be simplified?
*tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera)));
RwV3dNegate(&tmpmat->right, &tmpmat->right);
tmpmat->flags = 0;
tmpmat->pos.x = 0.0f;
tmpmat->pos.y = 0.0f;
tmpmat->pos.z = 0.0f;
RwMatrixMultiply(envmat, tmpmat, envframemat);
*tmpmat = *envmat;
// important because envframemat can have a translation that we don't like
tmpmat->pos.x = 0.0f;
tmpmat->pos.y = 0.0f;
tmpmat->pos.z = 0.0f;
// for some reason we flip in U as well
RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU);
RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat);
RwMatrixDestroy(envmat);
RwMatrixDestroy(tmpmat);
RwMatrixDestroy(envframemat);
}else
RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal);
}
void
_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap)
{
MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset);
MatFXEnv *env = &matfx->fx[sel].e;
uint8 intens = (uint8)(env->envCoeff*255.0f);
if(intens == 0 || envMap == nil){
if(sel == 0)
_rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture);
return;
}
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
RwD3D8SetTexture(texture, 0);
else
RwD3D8SetTexture(nil, 0);
RwD3D8SetPixelShader(0);
RwD3D8SetVertexShader(inst->vertexShader);
RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
if(inst->indexBuffer)
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
// Effect pass
ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwUInt32 src, dst, lighting, zwrite, fog, fogcol;
RwRenderStateGet(rwRENDERSTATESRCBLEND, &src);
RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst);
// This is of course not using framebuffer alpha,
// but if the diffuse texture had no alpha, the result should actually be rather the same
if(env->envFBalpha)
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
else
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite);
RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog);
RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
if(fog){
RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol);
RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0);
}
D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens);
RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor);
RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR);
// alpha unused
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
//RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
if(inst->indexBuffer)
RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
else
RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
// Reset states
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst);
RwD3D8SetRenderState(D3DRS_LIGHTING, lighting);
RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite);
if(fog)
RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol);
RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0);
RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
}
void
_rwD3D8EnableClippingIfNeeded(void *object, RwUInt8 type)
{
int clip;
if (type == rpATOMIC)
clip = !RwD3D8CameraIsSphereFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), RpAtomicGetWorldBoundingSphere((RpAtomic *)object));
else
clip = !RwD3D8CameraIsBBoxFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), &((RpWorldSector *)object)->tightBoundingBox);
RwD3D8SetRenderState(D3DRS_CLIPPING, clip);
}
void
_rwD3D8AtomicMatFXRenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags)
{
RwBool lighting;
RwBool forceBlack;
RxD3D8ResEntryHeader *header;
RxD3D8InstanceData *inst;
RwInt32 i;
if (flags & rpGEOMETRYPRELIT) {
RwD3D8SetRenderState(D3DRS_COLORVERTEX, 1);
RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
} else {
RwD3D8SetRenderState(D3DRS_COLORVERTEX, 0);
RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
}
_rwD3D8EnableClippingIfNeeded(object, type);
RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
if (lighting || flags & rpGEOMETRYPRELIT) {
forceBlack = FALSE;
} else {
forceBlack = TRUE;
RwD3D8SetTexture(nil, 0);
RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(0, 0, 0, 255));
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
}
header = (RxD3D8ResEntryHeader *)(repEntry + 1);
inst = (RxD3D8InstanceData *)(header + 1);
for (i = 0; i < header->numMeshes; i++) {
if (forceBlack)
_rpMatFXD3D8AtomicMatFXRenderBlack(inst);
else {
if (lighting)
RwD3D8SetSurfaceProperties(&inst->material->color, &inst->material->surfaceProps, flags & rpGEOMETRYMODULATEMATERIALCOLOR);
MatFX *matfx = *RWPLUGINOFFSET(MatFX *, inst->material, MatFXMaterialDataOffset);
int effect = matfx ? matfx->effects : rpMATFXEFFECTNULL;
switch (effect) {
case rpMATFXEFFECTNULL:
default:
_rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, inst->material->texture);
break;
case rpMATFXEFFECTBUMPMAP:
_rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, nil);
break;
case rpMATFXEFFECTENVMAP:
{
// TODO: matfx switch in the settings
//_rpMatFXD3D8AtomicMatFXEnvRender(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex);
_rpMatFXD3D8AtomicMatFXEnvRender_ps2(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex);
break;
}
case rpMATFXEFFECTBUMPENVMAP:
_rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, matfx->fx[1].e.envTex);
break;
case rpMATFXEFFECTDUAL:
_rpMatFXD3D8AtomicMatFXDualPassRender(inst, flags, inst->material->texture, matfx->fx[0].d.dualTex);
break;
}
}
inst++;
}
if (forceBlack) {
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
}
}
void
ReplaceMatFxCallback()
{
RxD3D8AllInOneSetRenderCallBack(
RxPipelineFindNodeByName(RpMatFXGetD3D8Pipeline(rpMATFXD3D8ATOMICPIPELINE), RxNodeDefinitionGetD3D8AtomicAllInOne()->name, nil, nil),
_rwD3D8AtomicMatFXRenderCallback);
}
#endif // PS2_MATFX
#endif // !LIBRW

247
src/rw/RwPS2AlphaTest.cpp Normal file
View file

@ -0,0 +1,247 @@
#ifndef LIBRW
#define WITHD3D
#include "common.h"
#ifdef PS2_ALPHA_TEST
#include "rwcore.h"
extern "C" {
RwBool _rwD3D8RenderStateIsVertexAlphaEnable(void);
RwBool _rwD3D8RenderStateVertexAlphaEnable(RwBool enable);
RwRaster *_rwD3D8RWGetRasterStage(RwUInt32 stage);
}
extern bool gPS2alphaTest;
void
_rxD3D8DualPassRenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags)
{
RxD3D8ResEntryHeader *resEntryHeader;
RxD3D8InstanceData *instancedData;
RwInt32 numMeshes;
RwBool lighting;
RwBool vertexAlphaBlend;
RwBool forceBlack;
RwUInt32 ditherEnable;
RwUInt32 shadeMode;
void *lastVertexBuffer;
/* Get lighting state */
RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
forceBlack = FALSE;
if (lighting) {
if (flags & rxGEOMETRY_PRELIT) {
/* Emmisive color from the vertex colors */
RwD3D8SetRenderState(D3DRS_COLORVERTEX, TRUE);
RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1);
} else {
/* Emmisive color from material, set to black in the submit node */
RwD3D8SetRenderState(D3DRS_COLORVERTEX, FALSE);
RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
}
} else {
if ((flags & rxGEOMETRY_PRELIT) == 0) {
forceBlack = TRUE;
RwD3D8GetRenderState(D3DRS_DITHERENABLE, &ditherEnable);
RwD3D8GetRenderState(D3DRS_SHADEMODE, &shadeMode);
RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, 0xff000000);
RwD3D8SetRenderState(D3DRS_DITHERENABLE, FALSE);
RwD3D8SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
}
}
/* Enable clipping */
if (type == rpATOMIC) {
RpAtomic *atomic;
RwCamera *cam;
atomic = (RpAtomic *)object;
cam = RwCameraGetCurrentCamera();
// RWASSERT(cam);
if (RwD3D8CameraIsSphereFullyInsideFrustum(cam, RpAtomicGetWorldBoundingSphere(atomic))) {
RwD3D8SetRenderState(D3DRS_CLIPPING, FALSE);
} else {
RwD3D8SetRenderState(D3DRS_CLIPPING, TRUE);
}
} else {
RpWorldSector *worldSector;
RwCamera *cam;
worldSector = (RpWorldSector *)object;
cam = RwCameraGetCurrentCamera();
// RWASSERT(cam);
if (RwD3D8CameraIsBBoxFullyInsideFrustum(cam, RpWorldSectorGetTightBBox(worldSector))) {
RwD3D8SetRenderState(D3DRS_CLIPPING, FALSE);
} else {
RwD3D8SetRenderState(D3DRS_CLIPPING, TRUE);
}
}
/* Set texture to NULL if hasn't any texture flags */
if ((flags & (rxGEOMETRY_TEXTURED | rpGEOMETRYTEXTURED2)) == 0) {
RwD3D8SetTexture(NULL, 0);
if (forceBlack) {
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
RwD3D8SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
}
/* Get vertex alpha Blend state */
vertexAlphaBlend = _rwD3D8RenderStateIsVertexAlphaEnable();
/* Set Last vertex buffer to force the call */
lastVertexBuffer = (void *)0xffffffff;
/* Get the instanced data */
resEntryHeader = (RxD3D8ResEntryHeader *)(repEntry + 1);
instancedData = (RxD3D8InstanceData *)(resEntryHeader + 1);
/*
* Data shared between meshes
*/
/*
* Set the Default Pixel shader
*/
RwD3D8SetPixelShader(0);
/*
* Vertex shader
*/
RwD3D8SetVertexShader(instancedData->vertexShader);
/* Get the number of meshes */
numMeshes = resEntryHeader->numMeshes;
while (numMeshes--) {
// RWASSERT(instancedData->material != NULL);
if ((flags & (rxGEOMETRY_TEXTURED | rpGEOMETRYTEXTURED2))) {
RwD3D8SetTexture(instancedData->material->texture, 0);
if (forceBlack) {
/* Only change the colorop, we need to use the texture alpha channel */
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
}
}
if (instancedData->vertexAlpha || (0xFF != instancedData->material->color.alpha)) {
if (!vertexAlphaBlend) {
vertexAlphaBlend = TRUE;
_rwD3D8RenderStateVertexAlphaEnable(TRUE);
}
} else {
if (vertexAlphaBlend) {
vertexAlphaBlend = FALSE;
_rwD3D8RenderStateVertexAlphaEnable(FALSE);
}
}
if (lighting) {
if (instancedData->vertexAlpha) {
RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
} else {
RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
}
RwD3D8SetSurfaceProperties(&instancedData->material->color, &instancedData->material->surfaceProps, (flags & rxGEOMETRY_MODULATE));
}
/*
* Render
*/
/* Set the stream source */
if (lastVertexBuffer != instancedData->vertexBuffer) {
RwD3D8SetStreamSource(0, instancedData->vertexBuffer, instancedData->stride);
lastVertexBuffer = instancedData->vertexBuffer;
}
if (!gPS2alphaTest) {
/* Set the Index buffer */
if (instancedData->indexBuffer != NULL) {
RwD3D8SetIndices(instancedData->indexBuffer, instancedData->baseIndex);
/* Draw the indexed primitive */
RwD3D8DrawIndexedPrimitive((D3DPRIMITIVETYPE)instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
} else {
RwD3D8DrawPrimitive((D3DPRIMITIVETYPE)instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
}
} else {
RwD3D8SetIndices(instancedData->indexBuffer, instancedData->baseIndex);
int hasAlpha, alphafunc, alpharef, zwrite;
RwD3D8GetRenderState(D3DRS_ALPHABLENDENABLE, &hasAlpha);
RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite);
if (hasAlpha && zwrite) {
RwD3D8GetRenderState(D3DRS_ALPHAFUNC, &alphafunc);
RwD3D8GetRenderState(D3DRS_ALPHAREF, &alpharef);
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
RwD3D8SetRenderState(D3DRS_ALPHAREF, 128);
if (instancedData->indexBuffer)
RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
else
RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE);
if (instancedData->indexBuffer)
RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
else
RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
RwD3D8SetRenderState(D3DRS_ALPHAFUNC, alphafunc);
RwD3D8SetRenderState(D3DRS_ALPHAREF, alpharef);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
} else {
if (instancedData->indexBuffer)
RwD3D8DrawIndexedPrimitive(instancedData->primType, 0, instancedData->numVertices, 0, instancedData->numIndices);
else
RwD3D8DrawPrimitive(instancedData->primType, instancedData->baseIndex, instancedData->numVertices);
}
}
/* Move onto the next instancedData */
instancedData++;
}
if (forceBlack) {
RwD3D8SetRenderState(D3DRS_DITHERENABLE, ditherEnable);
RwD3D8SetRenderState(D3DRS_SHADEMODE, shadeMode);
if (_rwD3D8RWGetRasterStage(0)) {
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
} else {
RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
}
}
}
void
ReplaceAtomicPipeCallback()
{
RxD3D8AllInOneSetRenderCallBack(RxPipelineFindNodeByName(RXPIPELINEGLOBAL(platformAtomicPipeline), RxNodeDefinitionGetD3D8AtomicAllInOne()->name, nil, nil),
_rxD3D8DualPassRenderCallback);
}
#endif // PS2_ALPHA_TEST
#endif // !LIBRW

459
src/rw/TexRead.cpp Normal file
View file

@ -0,0 +1,459 @@
#pragma warning( push )
#pragma warning( disable : 4005)
#pragma warning( pop )
#define FORCE_PC_SCALING
#include "common.h"
#ifdef ANISOTROPIC_FILTERING
#include "rpanisot.h"
#endif
#include "crossplatform.h"
#include "platform.h"
#include "Timer.h"
#ifdef GTA_PC
#include "FileMgr.h"
#include "Pad.h"
#include "main.h"
#include "Directory.h"
#include "Streaming.h"
#include "TxdStore.h"
#include "CdStream.h"
#include "Font.h"
#include "Sprite2d.h"
#include "Text.h"
#include "RwHelper.h"
#include "Frontend.h"
#endif //GTA_PC
float texLoadTime;
int32 texNumLoaded;
#ifdef LIBRW
#define READNATIVE(stream, tex, size) rwNativeTextureHackRead(stream, tex, size)
#else
#define READNATIVE(stream, tex, size) RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, tex, size))
#endif
RwTexture*
RwTextureGtaStreamRead(RwStream *stream)
{
RwUInt32 size, version;
RwTexture *tex;
if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version))
return nil;
float preloadTime = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond();
if(!READNATIVE(stream, &tex, size))
return nil;
if (gGameState == GS_INIT_PLAYING_GAME) {
texLoadTime = (texNumLoaded * texLoadTime + (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond() - preloadTime) / (float)(texNumLoaded+1);
texNumLoaded++;
}
#ifdef ANISOTROPIC_FILTERING
if(tex && RpAnisotGetMaxSupportedMaxAnisotropy() > 1) // BUG? this was RpAnisotTextureGetMaxAnisotropy, but that doesn't make much sense
RpAnisotTextureSetMaxAnisotropy(tex, RpAnisotGetMaxSupportedMaxAnisotropy());
#endif
return tex;
}
RwTexture*
destroyTexture(RwTexture *texture, void *data)
{
RwTextureDestroy(texture);
return texture;
}
RwTexDictionary*
RwTexDictionaryGtaStreamRead(RwStream *stream)
{
RwUInt32 size, version;
RwInt32 numTextures;
RwTexDictionary *texDict;
RwTexture *tex;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
if(RwStreamRead(stream, &numTextures, size) != size)
return nil;
texDict = RwTexDictionaryCreate();
if(texDict == nil)
return nil;
while(numTextures--){
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
return texDict;
}
static int32 numberTextures = -1;
static int32 streamPosition;
RwTexDictionary*
RwTexDictionaryGtaStreamRead1(RwStream *stream)
{
RwUInt32 size, version;
RwInt32 numTextures;
RwTexDictionary *texDict;
RwTexture *tex;
numberTextures = 0;
if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
return nil;
assert(size == 4);
if(RwStreamRead(stream, &numTextures, size) != size)
return nil;
texDict = RwTexDictionaryCreate();
if(texDict == nil)
return nil;
numberTextures = numTextures/2;
while(numTextures > numberTextures){
numTextures--;
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
numberTextures = numTextures;
streamPosition = STREAMPOS(stream);
return texDict;
}
RwTexDictionary*
RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict)
{
RwTexture *tex;
RwStreamSkip(stream, streamPosition - STREAMPOS(stream));
while(numberTextures--){
tex = RwTextureGtaStreamRead(stream);
if(tex == nil){
RwTexDictionaryForAllTextures(texDict, destroyTexture, nil);
RwTexDictionaryDestroy(texDict);
return nil;
}
RwTexDictionaryAddTexture(texDict, tex);
}
return texDict;
}
#ifdef GTA_PC
#ifdef LIBRW
#define CAPSVERSION 0
struct GPUcaps
{
uint32 version; // so we can force regeneration easily
uint32 platform;
uint32 subplatform;
uint32 dxtSupport;
};
static void
GetGPUcaps(GPUcaps *caps)
{
caps->version = CAPSVERSION;
caps->platform = rw::platform;
caps->subplatform = 0;
caps->dxtSupport = 0;
// TODO: more later
#ifdef RW_GL3
caps->subplatform = rw::gl3::gl3Caps.gles;
caps->dxtSupport = rw::gl3::gl3Caps.dxtSupported;
#endif
#ifdef RW_D3D9
caps->dxtSupport = 1; // TODO, probably
#endif
}
void
ReadVideoCardCapsFile(GPUcaps *caps)
{
memset(caps, 0, sizeof(GPUcaps));
int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "rb");
if (file != 0) {
CFileMgr::Read(file, (char*)&caps->version, 4);
CFileMgr::Read(file, (char*)&caps->platform, 4);
CFileMgr::Read(file, (char*)&caps->subplatform, 4);
CFileMgr::Read(file, (char*)&caps->dxtSupport, 4);
CFileMgr::CloseFile(file);
}
}
bool
CheckVideoCardCaps(void)
{
GPUcaps caps, fcaps;
GetGPUcaps(&caps);
ReadVideoCardCapsFile(&fcaps);
return caps.version != fcaps.version ||
caps.platform != fcaps.platform ||
caps.subplatform != fcaps.subplatform ||
caps.dxtSupport != fcaps.dxtSupport;
}
void
WriteVideoCardCapsFile(void)
{
GPUcaps caps;
GetGPUcaps(&caps);
int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "wb");
if (file != 0) {
CFileMgr::Write(file, (char*)&caps.version, 4);
CFileMgr::Write(file, (char*)&caps.platform, 4);
CFileMgr::Write(file, (char*)&caps.subplatform, 4);
CFileMgr::Write(file, (char*)&caps.dxtSupport, 4);
CFileMgr::CloseFile(file);
}
}
#else
extern "C" RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags);
void
ReadVideoCardCapsFile(uint32 &cap32, uint32 &cap24, uint32 &cap16, uint32 &cap8)
{
cap32 = UINT32_MAX;
cap24 = UINT32_MAX;
cap16 = UINT32_MAX;
cap8 = UINT32_MAX;
int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "rb");
if (file != 0) {
CFileMgr::Read(file, (char*)&cap32, 4);
CFileMgr::Read(file, (char*)&cap24, 4);
CFileMgr::Read(file, (char*)&cap16, 4);
CFileMgr::Read(file, (char*)&cap8, 4);
CFileMgr::CloseFile(file);
}
}
bool
CheckVideoCardCaps(void)
{
uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
uint32 fcap32, fcap24, fcap16, fcap8;
ReadVideoCardCapsFile(fcap32, fcap24, fcap16, fcap8);
return cap32 != fcap32 || cap24 != fcap24 || cap16 != fcap16 || cap8 != fcap8;
}
void
WriteVideoCardCapsFile(void)
{
uint32 cap32 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT8888);
uint32 cap24 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT888);
uint32 cap16 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMAT1555);
uint32 cap8 = _rwD3D8FindCorrectRasterFormat(rwRASTERTYPETEXTURE, rwRASTERFORMATPAL8 | rwRASTERFORMAT8888);
int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "wb");
if (file != 0) {
CFileMgr::Write(file, (char*)&cap32, 4);
CFileMgr::Write(file, (char*)&cap24, 4);
CFileMgr::Write(file, (char*)&cap16, 4);
CFileMgr::Write(file, (char*)&cap8, 4);
CFileMgr::CloseFile(file);
}
}
#endif
void
ConvertingTexturesScreen(uint32 num, uint32 count, const char *text)
{
HandleExit();
CSprite2d *splash = LoadSplash(nil);
if (!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255))
return;
CSprite2d::SetRecipNearClip();
CSprite2d::InitPerFrame();
CFont::InitPerFrame();
DefinedState();
RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255));
CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), SCREEN_SCALE_FROM_RIGHT(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(64, 64, 64, 255));
CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(240.0f), (SCREEN_SCALE_FROM_RIGHT(200.0f) - SCREEN_SCALE_X(200.0f)) * ((float)num / (float)count) + SCREEN_SCALE_X(200.0f), SCREEN_SCALE_Y(248.0f)), CRGBA(255, 217, 106, 255));
CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(120.0f), SCREEN_SCALE_Y(150.0f), SCREEN_SCALE_FROM_RIGHT(120.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(220.0f)), CRGBA(50, 50, 50, 210));
CFont::SetBackgroundOff();
CFont::SetPropOn();
CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f));
CFont::SetCentreOff();
CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(170.0f));
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(255, 217, 106, 255));
CFont::SetBackGroundOnlyTextOff();
CFont::SetFontStyle(FONT_BANK);
CFont::PrintString(SCREEN_SCALE_X(170.0f), SCREEN_SCALE_Y(160.0f), TheText.Get(text));
CFont::DrawFonts();
DoRWStuffEndOfFrame();
}
void
DealWithTxdWriteError(uint32 num, uint32 count, const char *text)
{
while (!RsGlobal.quit) {
ConvertingTexturesScreen(num, count, text);
CPad::UpdatePads();
if (CPad::GetPad(0)->GetEscapeJustDown())
break;
}
RsGlobal.quit = false;
LoadingScreen(nil, nil, nil);
RsGlobal.quit = true;
}
#ifdef LIBRW
#define STREAMTELL(str) str->tell()
#else
#define STREAMTELL(str) filesys->rwftell((str)->Type.file.fpFile)
#endif
bool
CreateTxdImageForVideoCard()
{
uint8 *buf = new uint8[CDSTREAM_SECTOR_SIZE];
CDirectory *pDir = new CDirectory(TXDSTORESIZE);
CDirectory::DirectoryInfo dirInfo;
CStreaming::FlushRequestList();
#ifndef LIBRW
RwFileFunctions *filesys = RwOsGetFileInterface();
#endif
RwStream *img = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMWRITE, "models\\txd.img");
if (img == nil) {
// original code does otherwise and it leaks
delete []buf;
delete pDir;
if (_dwOperatingSystemVersion == OS_WINNT || _dwOperatingSystemVersion == OS_WIN2000 || _dwOperatingSystemVersion == OS_WINXP)
DealWithTxdWriteError(0, TXDSTORESIZE, "CVT_CRT");
return false;
}
#ifdef RW_GL3
// so we can read back DXT with GLES
// only works for textures that are not yet loaded
// so let's hope that is the case for all
rw::gl3::needToReadBackTextures = true;
#endif
#ifdef DISABLE_VSYNC_ON_TEXTURE_CONVERSION
// let's disable vsync and frame limiter to speed up texture conversion
// (actually we probably don't need to disable frame limiter in here, but let's do it just in case =P)
int8 vsyncState = CMenuManager::m_PrefsVsync;
int8 frameLimiterState = CMenuManager::m_PrefsFrameLimiter;
CMenuManager::m_PrefsVsync = 0;
CMenuManager::m_PrefsFrameLimiter = 0;
#endif
int32 i;
for (i = 0; i < TXDSTORESIZE; i++) {
ConvertingTexturesScreen(i, TXDSTORESIZE, "CVT_MSG");
if (CTxdStore::GetSlot(i) != nil && CStreaming::IsObjectInCdImage(i + STREAM_OFFSET_TXD)) {
#ifdef FIX_BUGS
if(strcmp(CTxdStore::GetTxdName(i), "generic") == 0)
continue;
#endif
CStreaming::RequestTxd(i, STREAMFLAGS_KEEP_IN_MEMORY);
CStreaming::RequestModelStream(0);
CStreaming::FlushChannels();
char filename[64];
sprintf(filename, "%s.txd", CTxdStore::GetTxdName(i));
if (CTxdStore::GetSlot(i)->texDict) {
int32 pos = STREAMTELL(img);
if (RwTexDictionaryStreamWrite(CTxdStore::GetSlot(i)->texDict, img) == nil) {
DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
RwStreamClose(img, nil);
delete []buf;
delete pDir;
CStreaming::RemoveTxd(i);
#ifdef RW_GL3
rw::gl3::needToReadBackTextures = false;
#endif
return false;
}
int32 size = STREAMTELL(img) - pos;
int32 num = size % CDSTREAM_SECTOR_SIZE;
size /= CDSTREAM_SECTOR_SIZE;
if (num != 0) {
size++;
num = CDSTREAM_SECTOR_SIZE - num;
RwStreamWrite(img, buf, num);
}
dirInfo.offset = pos / CDSTREAM_SECTOR_SIZE;
dirInfo.size = size;
strncpy(dirInfo.name, filename, sizeof(dirInfo.name));
pDir->AddItem(dirInfo);
CStreaming::RemoveTxd(i);
}
CStreaming::FlushRequestList();
}
}
#ifdef DISABLE_VSYNC_ON_TEXTURE_CONVERSION
// restore vsync and frame limiter states
CMenuManager::m_PrefsVsync = vsyncState;
CMenuManager::m_PrefsFrameLimiter = frameLimiterState;
#endif
RwStreamClose(img, nil);
delete []buf;
#ifdef RW_GL3
rw::gl3::needToReadBackTextures = false;
#endif
if (!pDir->WriteDirFile("models\\txd.dir")) {
DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR");
delete pDir;
return false;
}
delete pDir;
WriteVideoCardCapsFile();
return true;
}
#endif // GTA_PC

221
src/rw/TexturePools.cpp Normal file
View file

@ -0,0 +1,221 @@
#ifndef LIBRW
#include <d3d8.h>
#define WITHD3D
#include "common.h"
#include "TexturePools.h"
// TODO: this needs to be integrated into RW
extern "C" LPDIRECT3DDEVICE8 _RwD3DDevice;
CTexturePool aTexturePools[12];
CPaletteList PaletteList;
int numTexturePools;
int MaxPaletteIndex;
bool bUsePaletteIndex = true;
void
CTexturePool::Create(D3DFORMAT _Format, int _size, uint32 mipmapLevels, int32 numTextures)
{
Format = _Format;
size = _size;
levels = mipmapLevels;
pTextures = new IDirect3DTexture8 *[numTextures];
texturesMax = numTextures;
texturesNum = 0;
texturesUsed = 0;
}
void
CTexturePool::Release()
{
int i = 0;
while (i < texturesNum) {
pTextures[i]->Release();
i++;
}
delete[] pTextures;
pTextures = nil;
texturesNum = 0;
texturesUsed = 0;
}
IDirect3DTexture8 *
CTexturePool::FindTexture()
{
if (texturesNum == 0)
return nil;
texturesUsed--;
return pTextures[--texturesNum];
}
bool
CTexturePool::AddTexture(IDirect3DTexture8 *texture)
{
++texturesUsed;
if (texturesNum >= texturesMax)
return false;
pTextures[texturesNum] = texture;
++texturesNum;
return true;
}
void
CTexturePool::Resize(int numTextures)
{
if (numTextures == texturesMax)
return;
IDirect3DTexture8 **newTextures = new IDirect3DTexture8 *[numTextures];
for (int i = 0; i < texturesNum && i < numTextures; i++)
newTextures[i] = pTextures[i];
if (numTextures < texturesNum) {
for (int i = numTextures; i < texturesNum; i++)
pTextures[i]->Release();
}
delete[] pTextures;
pTextures = newTextures;
texturesMax = numTextures;
}
void
CPaletteList::Alloc(int max)
{
Data = new int[max];
Max = max;
Num = 0;
}
void
CPaletteList::Free()
{
delete[] Data;
Data = nil;
Num = 0;
}
int
CPaletteList::Find()
{
if (Num == 0)
return -1;
return Data[--Num];
}
void
CPaletteList::Add(int item)
{
if (Num < Max)
Data[Num++] = item;
else {
Resize(2 * Max);
Add(item);
}
}
void
CPaletteList::Resize(int max)
{
if (max == Max)
return;
int *newData = new int[4 * max];
for (int i = 0; i < Num && i < max; i++)
newData[i] = Data[i];
delete[] Data;
Data = newData;
Max = max;
}
HRESULT
CreateTexture(int width, int height, int levels, D3DFORMAT Format, IDirect3DTexture8 **texture)
{
if (width == height) {
for (int i = 0; i < numTexturePools; i++) {
if (width != aTexturePools[i].GetSize() && levels == aTexturePools[i].levels && Format == aTexturePools[i].Format)
*texture = aTexturePools[i].FindTexture();
}
}
if (*texture)
return D3D_OK;
else
return _RwD3DDevice->CreateTexture(width, height, levels, 0, Format, D3DPOOL_MANAGED, texture);
}
void
ReleaseTexture(IDirect3DTexture8 *texture)
{
int levels = 1;
if (texture->GetLevelCount() > 1)
levels = 0;
D3DSURFACE_DESC SURFACE_DESC;
texture->GetLevelDesc(0, &SURFACE_DESC);
if (SURFACE_DESC.Width == SURFACE_DESC.Height) {
for (int i = 0; i < numTexturePools; i++) {
if (SURFACE_DESC.Width == aTexturePools[i].GetSize() && SURFACE_DESC.Format == aTexturePools[i].Format && levels == aTexturePools[i].levels) {
if (!aTexturePools[i].AddTexture(texture)) {
if (aTexturePools[i].texturesUsed > 3 * aTexturePools[i].texturesMax / 2) {
aTexturePools[i].Resize(2 * aTexturePools[i].texturesMax);
aTexturePools[i].texturesUsed--;
aTexturePools[i].AddTexture(texture);
} else {
texture->Release();
}
}
return;
}
}
}
if (numTexturePools < 12 && bUsePaletteIndex && levels != 0 && SURFACE_DESC.Width == SURFACE_DESC.Height &&
(SURFACE_DESC.Width == 64 || SURFACE_DESC.Width == 128 || SURFACE_DESC.Width == 256)) {
aTexturePools[numTexturePools].Create(SURFACE_DESC.Format, SURFACE_DESC.Width, 1, 16);
aTexturePools[numTexturePools].AddTexture(texture);
numTexturePools++;
} else
texture->Release();
}
int
FindAvailablePaletteIndex()
{
int index = PaletteList.Find();
if (index == -1)
index = MaxPaletteIndex++;
return index;
}
void
AddAvailablePaletteIndex(int index)
{
if (bUsePaletteIndex)
PaletteList.Add(index);
}
void
_TexturePoolsInitialise()
{
PaletteList.Alloc(100);
MaxPaletteIndex = 0;
}
void
_TexturePoolsShutdown()
{
for (int i = 0; i < numTexturePools; i++)
aTexturePools[i].Release();
numTexturePools = 0;
bUsePaletteIndex = false;
PaletteList.Free();
}
#endif // !LIBRW

42
src/rw/TexturePools.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
class CTexturePool
{
public:
D3DFORMAT Format;
int size;
uint32 levels;
int32 texturesMax;
int32 texturesUsed;
int32 texturesNum;
IDirect3DTexture8 **pTextures;
public:
CTexturePool() {}
void Create(D3DFORMAT _Format, int size, uint32 mipmapLevels, int32 numTextures);
void Release();
IDirect3DTexture8 *FindTexture();
bool AddTexture(IDirect3DTexture8 *texture);
void Resize(int numTextures);
#ifdef FIX_BUGS
int GetSize() { return size; }
#else
float GetSize() { return size; }
#endif
};
class CPaletteList
{
int Max;
int Num;
int *Data;
public:
void Alloc(int max);
void Free();
int Find();
void Add(int item);
void Resize(int max);
};
void _TexturePoolsInitialise();
void _TexturePoolsShutdown();

183
src/rw/TxdStore.cpp Normal file
View file

@ -0,0 +1,183 @@
#include "common.h"
#include "templates.h"
#include "General.h"
#include "Streaming.h"
#include "RwHelper.h"
#include "TxdStore.h"
CPool<TxdDef,TxdDef> *CTxdStore::ms_pTxdPool;
RwTexDictionary *CTxdStore::ms_pStoredTxd;
void
CTxdStore::Initialise(void)
{
if(ms_pTxdPool == nil)
ms_pTxdPool = new CPool<TxdDef,TxdDef>(TXDSTORESIZE);
}
void
CTxdStore::Shutdown(void)
{
if(ms_pTxdPool)
delete ms_pTxdPool;
}
void
CTxdStore::GameShutdown(void)
{
int i;
for(i = 0; i < TXDSTORESIZE; i++){
TxdDef *def = GetSlot(i);
if(def && GetNumRefs(i) == 0)
RemoveTxdSlot(i);
}
}
int
CTxdStore::AddTxdSlot(const char *name)
{
TxdDef *def = ms_pTxdPool->New();
assert(def);
def->texDict = nil;
def->refCount = 0;
strcpy(def->name, 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)
{
int size = ms_pTxdPool->GetSize();
for(int i = 0; i < size; i++){
TxdDef *def = GetSlot(i);
if(def && !CGeneral::faststricmp(def->name, name))
return i;
}
return -1;
}
char*
CTxdStore::GetTxdName(int slot)
{
return GetSlot(slot)->name;
}
void
CTxdStore::PushCurrentTxd(void)
{
ms_pStoredTxd = RwTexDictionaryGetCurrent();
}
void
CTxdStore::PopCurrentTxd(void)
{
RwTexDictionarySetCurrent(ms_pStoredTxd);
ms_pStoredTxd = nil;
}
void
CTxdStore::SetCurrentTxd(int slot)
{
RwTexDictionarySetCurrent(GetSlot(slot)->texDict);
}
void
CTxdStore::Create(int slot)
{
GetSlot(slot)->texDict = RwTexDictionaryCreate();
}
int
CTxdStore::GetNumRefs(int slot)
{
return GetSlot(slot)->refCount;
}
void
CTxdStore::AddRef(int slot)
{
GetSlot(slot)->refCount++;
}
void
CTxdStore::RemoveRef(int slot)
{
if(--GetSlot(slot)->refCount <= 0)
CStreaming::RemoveTxd(slot);
}
void
CTxdStore::RemoveRefWithoutDelete(int slot)
{
GetSlot(slot)->refCount--;
}
bool
CTxdStore::LoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
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)
{
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;
}
bool
CTxdStore::StartLoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){
def->texDict = RwTexDictionaryGtaStreamRead1(stream);
return def->texDict != nil;
}else{
printf("Failed to load TXD\n");
return false;
}
}
bool
CTxdStore::FinishLoadTxd(int slot, RwStream *stream)
{
TxdDef *def = GetSlot(slot);
def->texDict = RwTexDictionaryGtaStreamRead2(stream, def->texDict);
return def->texDict != nil;
}
void
CTxdStore::RemoveTxd(int slot)
{
TxdDef *def = GetSlot(slot);
if(def->texDict)
RwTexDictionaryDestroy(def->texDict);
def->texDict = nil;
}

44
src/rw/TxdStore.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#include "templates.h"
struct TxdDef {
RwTexDictionary *texDict;
int refCount;
char name[20];
};
class CTxdStore
{
static CPool<TxdDef,TxdDef> *ms_pTxdPool;
static RwTexDictionary *ms_pStoredTxd;
public:
static void Initialise(void);
static void Shutdown(void);
static void GameShutdown(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);
static void PopCurrentTxd(void);
static void SetCurrentTxd(int slot);
static void Create(int slot);
static int GetNumRefs(int slot);
static void AddRef(int slot);
static void RemoveRef(int slot);
static void RemoveRefWithoutDelete(int slot);
static bool LoadTxd(int slot, RwStream *stream);
static bool LoadTxd(int slot, const char *filename);
static bool StartLoadTxd(int slot, RwStream *stream);
static bool FinishLoadTxd(int slot, RwStream *stream);
static void RemoveTxd(int slot);
static TxdDef *GetSlot(int slot) {
assert(slot >= 0);
assert(ms_pTxdPool);
assert(slot < ms_pTxdPool->GetSize());
return ms_pTxdPool->GetSlot(slot);
}
static bool isTxdLoaded(int slot);
};

1059
src/rw/VisibilityPlugins.cpp Normal file

File diff suppressed because it is too large Load diff

141
src/rw/VisibilityPlugins.h Normal file
View file

@ -0,0 +1,141 @@
#pragma once
#include "templates.h"
class CEntity;
class CSimpleModelInfo;
class CClumpModelInfo;
typedef bool (*ClumpVisibilityCB)(RpClump*);
class CVisibilityPlugins
{
public:
struct AlphaObjectInfo
{
union {
CEntity *entity;
RpAtomic *atomic;
};
float sort;
};
static CLinkList<AlphaObjectInfo> m_alphaList;
static CLinkList<AlphaObjectInfo> m_alphaEntityList;
#ifdef NEW_RENDERER
static CLinkList<AlphaObjectInfo> m_alphaBuildingList;
#endif
static RwCamera *ms_pCamera;
static RwV3d *ms_pCameraPosn;
static float ms_cullCompsDist;
static float ms_vehicleLod0Dist;
static float ms_vehicleLod1Dist;
static float ms_vehicleFadeDist;
static float ms_bigVehicleLod0Dist;
static float ms_bigVehicleLod1Dist;
static float ms_pedLod0Dist;
static float ms_pedLod1Dist;
static float ms_pedFadeDist;
static void Initialise(void);
static void Shutdown(void);
static void InitAlphaEntityList(void);
static bool InsertEntityIntoSortedList(CEntity *e, float dist);
static void InitAlphaAtomicList(void);
static bool InsertAtomicIntoSortedList(RpAtomic *a, float dist);
static void SetRenderWareCamera(RwCamera *camera);
static RpAtomic *RenderWheelAtomicCB(RpAtomic *atomic);
static RpAtomic *RenderObjNormalAtomic(RpAtomic *atomic);
static RpAtomic *RenderAlphaAtomic(RpAtomic *atomic, int alpha);
static RpAtomic *RenderFadingAtomic(RpAtomic *atm, float dist);
static RpAtomic *RenderVehicleHiDetailCB(RpAtomic *atomic);
static RpAtomic *RenderVehicleHiDetailAlphaCB(RpAtomic *atomic);
static RpAtomic *RenderVehicleHiDetailCB_BigVehicle(RpAtomic *atomic);
static RpAtomic *RenderVehicleHiDetailAlphaCB_BigVehicle(RpAtomic *atomic);
static RpAtomic *RenderVehicleHiDetailCB_Boat(RpAtomic *atomic);
static RpAtomic *RenderVehicleLowDetailCB_BigVehicle(RpAtomic *atomic);
static RpAtomic *RenderVehicleLowDetailAlphaCB_BigVehicle(RpAtomic *atomic);
static RpAtomic *RenderVehicleReallyLowDetailCB(RpAtomic *atomic);
static RpAtomic *RenderVehicleReallyLowDetailCB_BigVehicle(RpAtomic *atomic);
static RpAtomic *RenderTrainHiDetailCB(RpAtomic *atomic);
static RpAtomic *RenderTrainHiDetailAlphaCB(RpAtomic *atomic);
static RpAtomic *RenderPlayerCB(RpAtomic *atomic);
static RpAtomic *RenderPedLowDetailCB(RpAtomic *atomic);
static RpAtomic *RenderPedHiDetailCB(RpAtomic *atomic);
static RpAtomic *RenderPedCB(RpAtomic *atomic); // for skinned models with only one clump
static void RenderAlphaAtomics(void);
static void RenderFadingEntities(void);
// All actually unused
static bool DefaultVisibilityCB(RpClump *clump);
static bool FrustumSphereCB(RpClump *clump);
static bool MloVisibilityCB(RpClump *clump);
static bool VehicleVisibilityCB(RpClump *clump);
static bool VehicleVisibilityCB_BigVehicle(RpClump *clump);
static float GetDistanceSquaredFromCamera(RwFrame *frame);
static float GetDotProductWithCameraVector(RwMatrix *atomicMat, RwMatrix *clumpMat, uint32 flags);
//
// RW Plugins
//
union AtomicExt
{
CSimpleModelInfo *modelInfo; // used by SimpleModelInfo
int flags; // used by ClumpModelInfo
};
static void SetAtomicModelInfo(RpAtomic*, CSimpleModelInfo*);
static CSimpleModelInfo *GetAtomicModelInfo(RpAtomic *atomic);
static void SetAtomicFlag(RpAtomic*, int);
static void ClearAtomicFlag(RpAtomic*, int);
static void SetAtomicId(RpAtomic *atomic, int);
static int GetAtomicId(RpAtomic *atomic);
static void SetAtomicRenderCallback(RpAtomic*, RpAtomicCallBackRender);
static void *AtomicConstructor(void *object, int32 offset, int32 len);
static void *AtomicDestructor(void *object, int32 offset, int32 len);
static void *AtomicCopyConstructor(void *dst, const void *src,
int32 offset, int32 len);
static int32 ms_atomicPluginOffset;
struct FrameExt
{
// BUG: this is abused to hold a pointer by SetClumpModelInfo
intptr id;
};
static void SetFrameHierarchyId(RwFrame *frame, intptr id);
static intptr GetFrameHierarchyId(RwFrame *frame);
static void *FrameConstructor(void *object, int32 offset, int32 len);
static void *FrameDestructor(void *object, int32 offset, int32 len);
static void *FrameCopyConstructor(void *dst, const void *src,
int32 offset, int32 len);
static int32 ms_framePluginOffset;
struct ClumpExt
{
ClumpVisibilityCB visibilityCB;
int alpha;
};
static void SetClumpModelInfo(RpClump*, CClumpModelInfo*);
static CClumpModelInfo *GetClumpModelInfo(RpClump*);
static void SetClumpAlpha(RpClump*, int);
static int GetClumpAlpha(RpClump*);
static bool IsClumpVisible(RpClump*);
static void *ClumpConstructor(void *object, int32 offset, int32 len);
static void *ClumpDestructor(void *object, int32 offset, int32 len);
static void *ClumpCopyConstructor(void *dst, const void *src,
int32 offset, int32 len);
static int32 ms_clumpPluginOffset;
static bool PluginAttach(void);
};
RpMaterial *SetAlphaCB(RpMaterial *material, void *data);