Re3/src/core/FileLoader.cpp

1852 lines
42 KiB
C++
Raw Normal View History

2019-06-17 04:30:02 -04:00
#include "common.h"
#include "main.h"
2020-04-17 09:31:11 -04:00
#include "General.h"
2019-07-08 15:44:32 -04:00
#include "Quaternion.h"
2019-06-17 04:30:02 -04:00
#include "ModelInfo.h"
#include "ModelIndices.h"
#include "TempColModels.h"
2019-06-18 03:50:26 -04:00
#include "VisibilityPlugins.h"
#include "FileMgr.h"
2019-06-19 19:07:57 -04:00
#include "HandlingMgr.h"
2019-06-17 04:30:02 -04:00
#include "CarCtrl.h"
#include "PedType.h"
#include "AnimManager.h"
#include "Game.h"
#include "RwHelper.h"
#include "NodeName.h"
#include "TxdStore.h"
#include "PathFind.h"
2019-06-18 03:50:26 -04:00
#include "ObjectData.h"
#include "DummyObject.h"
#include "World.h"
#include "Zones.h"
2019-07-07 07:09:11 -04:00
#include "ZoneCull.h"
2019-06-18 03:50:26 -04:00
#include "CdStream.h"
2019-06-17 04:30:02 -04:00
#include "FileLoader.h"
2020-11-26 10:47:19 -05:00
#include "MemoryHeap.h"
2019-06-17 04:30:02 -04:00
char CFileLoader::ms_line[256];
const char*
GetFilename(const char *filename)
{
char *s = strrchr((char*)filename, '\\');
return s ? s+1 : filename;
}
void
LoadingScreenLoadingFile(const char *filename)
{
sprintf(gString, "Loading %s", GetFilename(filename));
2019-06-30 06:53:39 -04:00
LoadingScreen("Loading the Game", gString, nil);
2019-06-17 04:30:02 -04:00
}
void
CFileLoader::LoadLevel(const char *filename)
{
int fd;
RwTexDictionary *savedTxd;
2019-06-28 13:23:28 -04:00
eLevelName savedLevel;
2019-06-17 04:30:02 -04:00
bool objectsLoaded;
char *line;
char txdname[64];
savedTxd = RwTexDictionaryGetCurrent();
objectsLoaded = false;
savedLevel = CGame::currLevel;
if(savedTxd == nil){
savedTxd = RwTexDictionaryCreate();
RwTexDictionarySetCurrent(savedTxd);
}
2020-11-30 18:22:57 -05:00
#if GTA_VERSION <= GTA3_PS2_160
CFileMgr::ChangeDir("\\DATA\\");
2019-06-17 04:30:02 -04:00
fd = CFileMgr::OpenFile(filename, "r");
2020-11-30 18:22:57 -05:00
CFileMgr::ChangeDir("\\");
#else
fd = CFileMgr::OpenFile(filename, "r");
#endif
2019-06-17 04:30:02 -04:00
assert(fd > 0);
for(line = LoadLine(fd); line; line = LoadLine(fd)){
if(*line == '#')
continue;
2020-12-25 08:18:13 -05:00
#ifdef FIX_BUGS
if(strncmp(line, "EXIT", 4) == 0)
#else
if(strncmp(line, "EXIT", 9) == 0)
#endif
2019-06-17 04:30:02 -04:00
break;
if(strncmp(line, "IMAGEPATH", 9) == 0){
RwImageSetPath(line + 10);
}else if(strncmp(line, "TEXDICTION", 10) == 0){
2020-11-26 10:47:19 -05:00
PUSH_MEMID(MEMID_TEXTURES);
2019-06-17 04:30:02 -04:00
strcpy(txdname, line+11);
LoadingScreenLoadingFile(txdname);
RwTexDictionary *txd = LoadTexDictionary(txdname);
AddTexDictionaries(savedTxd, txd);
RwTexDictionaryDestroy(txd);
2020-11-26 10:47:19 -05:00
POP_MEMID();
2019-06-17 04:30:02 -04:00
}else if(strncmp(line, "COLFILE", 7) == 0){
int level;
sscanf(line+8, "%d", &level);
2019-06-28 13:23:28 -04:00
CGame::currLevel = (eLevelName)level;
2019-06-17 04:30:02 -04:00
LoadingScreenLoadingFile(line+10);
LoadCollisionFile(line+10);
CGame::currLevel = savedLevel;
}else if(strncmp(line, "MODELFILE", 9) == 0){
LoadingScreenLoadingFile(line + 10);
LoadModelFile(line + 10);
}else if(strncmp(line, "HIERFILE", 8) == 0){
LoadingScreenLoadingFile(line + 9);
LoadClumpFile(line + 9);
}else if(strncmp(line, "IDE", 3) == 0){
LoadingScreenLoadingFile(line + 4);
LoadObjectTypes(line + 4);
2019-06-18 03:50:26 -04:00
}else if(strncmp(line, "IPL", 3) == 0){
if(!objectsLoaded){
2020-11-26 10:47:19 -05:00
PUSH_MEMID(MEMID_DEF_MODELS);
2020-01-21 02:47:24 -05:00
CModelInfo::ConstructMloClumps();
2020-11-26 10:47:19 -05:00
POP_MEMID();
2019-06-18 03:50:26 -04:00
CObjectData::Initialise("DATA\\OBJECT.DAT");
objectsLoaded = true;
}
2020-11-26 10:47:19 -05:00
PUSH_MEMID(MEMID_WORLD);
2019-06-18 03:50:26 -04:00
LoadingScreenLoadingFile(line + 4);
2019-06-18 05:29:48 -04:00
LoadScene(line + 4);
2020-11-26 10:47:19 -05:00
POP_MEMID();
2019-06-18 03:50:26 -04:00
}else if(strncmp(line, "MAPZONE", 7) == 0){
LoadingScreenLoadingFile(line + 8);
LoadMapZones(line + 8);
}else if(strncmp(line, "SPLASH", 6) == 0){
#ifndef DISABLE_LOADING_SCREEN
2019-06-18 03:50:26 -04:00
LoadSplash(GetRandomSplashScreen());
#endif
2020-12-21 06:38:02 -05:00
#ifndef GTA_PS2
2019-06-18 03:50:26 -04:00
}else if(strncmp(line, "CDIMAGE", 7) == 0){
CdStreamAddImage(line + 8);
2020-12-21 06:38:02 -05:00
#endif
2019-06-17 04:30:02 -04:00
}
}
CFileMgr::CloseFile(fd);
RwTexDictionarySetCurrent(savedTxd);
}
void
CFileLoader::LoadCollisionFromDatFile(int currlevel)
{
int fd;
char *line;
fd = CFileMgr::OpenFile(CGame::aDatFile, "r");
assert(fd > 0);
for(line = LoadLine(fd); line; line = LoadLine(fd)){
if(*line == '#')
continue;
if(strncmp(line, "COLFILE", 7) == 0){
int level;
sscanf(line+8, "%d", &level);
if(currlevel == level)
LoadCollisionFile(line+10);
}
}
CFileMgr::CloseFile(fd);
}
char*
CFileLoader::LoadLine(int fd)
{
int i;
char *line;
2019-06-30 06:53:39 -04:00
if(CFileMgr::ReadLine(fd, ms_line, 256) == false)
2019-06-17 04:30:02 -04:00
return nil;
for(i = 0; ms_line[i] != '\0'; i++)
if(ms_line[i] < ' ' || ms_line[i] == ',')
ms_line[i] = ' ';
for(line = ms_line; *line <= ' ' && *line != '\0'; line++);
return line;
}
RwTexDictionary*
CFileLoader::LoadTexDictionary(const char *filename)
{
RwTexDictionary *txd;
RwStream *stream;
txd = nil;
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
debug("Loading texture dictionary file %s\n", filename);
if(stream){
if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil))
txd = RwTexDictionaryGtaStreamRead(stream);
RwStreamClose(stream, nil);
}
if(txd == nil)
txd = RwTexDictionaryCreate();
return txd;
}
struct ColHeader
{
2020-12-25 08:18:13 -05:00
uint32 ident;
uint32 size;
};
2019-06-17 04:30:02 -04:00
void
CFileLoader::LoadCollisionFile(const char *filename)
{
int fd;
char modelname[24];
CBaseModelInfo *mi;
ColHeader header;
2019-06-17 04:30:02 -04:00
2020-11-26 10:47:19 -05:00
PUSH_MEMID(MEMID_COLLISION);
2019-06-17 04:30:02 -04:00
debug("Loading collision file %s\n", filename);
fd = CFileMgr::OpenFile(filename, "rb");
while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){
2020-12-25 08:18:13 -05:00
assert(header.ident == 'LLOC');
2019-06-17 04:30:02 -04:00
CFileMgr::Read(fd, (char*)work_buff, header.size);
memcpy(modelname, work_buff, 24);
mi = CModelInfo::GetModelInfo(modelname, nil);
if(mi){
if(mi->GetColModel()){
LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname);
}else{
CColModel *model = new CColModel;
LoadCollisionModel(work_buff+24, *model, modelname);
mi->SetColModel(model, true);
}
}else{
debug("colmodel %s can't find a modelinfo\n", modelname);
}
}
CFileMgr::CloseFile(fd);
2020-11-26 10:47:19 -05:00
POP_MEMID();
2019-06-17 04:30:02 -04:00
}
void
CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname)
{
int i;
model.boundingSphere.radius = *(float*)(buf);
model.boundingSphere.center.x = *(float*)(buf+4);
model.boundingSphere.center.y = *(float*)(buf+8);
model.boundingSphere.center.z = *(float*)(buf+12);
model.boundingBox.min.x = *(float*)(buf+16);
model.boundingBox.min.y = *(float*)(buf+20);
model.boundingBox.min.z = *(float*)(buf+24);
model.boundingBox.max.x = *(float*)(buf+28);
model.boundingBox.max.y = *(float*)(buf+32);
model.boundingBox.max.z = *(float*)(buf+36);
model.numSpheres = *(int16*)(buf+40);
buf += 44;
if(model.numSpheres > 0){
model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere));
REGISTER_MEMPTR(&model.spheres);
2019-06-17 04:30:02 -04:00
for(i = 0; i < model.numSpheres; i++){
model.spheres[i].Set(*(float*)buf, *(CVector*)(buf+4), buf[16], buf[17]);
buf += 20;
}
}else
model.spheres = nil;
model.numLines = *(int16*)buf;
buf += 4;
if(model.numLines > 0){
model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine));
REGISTER_MEMPTR(&model.lines);
2019-06-17 04:30:02 -04:00
for(i = 0; i < model.numLines; i++){
model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12));
buf += 24;
}
}else
model.lines = nil;
model.numBoxes = *(int16*)buf;
buf += 4;
if(model.numBoxes > 0){
model.boxes = (CColBox*)RwMalloc(model.numBoxes*sizeof(CColBox));
REGISTER_MEMPTR(&model.boxes);
2019-06-17 04:30:02 -04:00
for(i = 0; i < model.numBoxes; i++){
model.boxes[i].Set(*(CVector*)buf, *(CVector*)(buf+12), buf[24], buf[25]);
buf += 28;
}
}else
model.boxes = nil;
int32 numVertices = *(int16*)buf;
buf += 4;
if(numVertices > 0){
2020-07-27 09:38:12 -04:00
model.vertices = (CompressedVector*)RwMalloc(numVertices*sizeof(CompressedVector));
REGISTER_MEMPTR(&model.vertices);
2019-06-17 04:30:02 -04:00
for(i = 0; i < numVertices; i++){
2020-07-27 09:38:12 -04:00
model.vertices[i].Set(*(float*)buf, *(float*)(buf+4), *(float*)(buf+8));
if(Abs(*(float*)buf) >= 256.0f ||
Abs(*(float*)(buf+4)) >= 256.0f ||
Abs(*(float*)(buf+8)) >= 256.0f)
2019-06-17 04:30:02 -04:00
printf("%s:Collision volume too big\n", modelname);
buf += 12;
}
}else
model.vertices = nil;
model.numTriangles = *(int16*)buf;
buf += 4;
if(model.numTriangles > 0){
model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle));
REGISTER_MEMPTR(&model.triangles);
2019-06-17 04:30:02 -04:00
for(i = 0; i < model.numTriangles; i++){
model.triangles[i].Set(model.vertices, *(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12], buf[13]);
buf += 16;
}
}else
model.triangles = nil;
}
static void
GetNameAndLOD(char *nodename, char *name, int *n)
{
char *underscore = nil;
for(char *s = nodename; *s != '\0'; s++){
if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L'))
underscore = s;
}
if(underscore){
strncpy(name, nodename, underscore - nodename);
name[underscore - nodename] = '\0';
*n = atoi(underscore + 2);
}else{
strncpy(name, nodename, 24);
*n = 0;
}
}
RpAtomic*
CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data)
{
CSimpleModelInfo *mi;
char *nodename, name[24];
int n;
RpClump *clump = (RpClump*)data;
nodename = GetFrameNodeName(RpAtomicGetFrame(atomic));
2019-06-17 04:30:02 -04:00
GetNameAndLOD(nodename, name, &n);
2019-06-30 06:53:39 -04:00
mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, nil);
2019-06-17 04:30:02 -04:00
if(mi){
assert(mi->IsSimple());
mi->SetAtomic(n, atomic);
RpClumpRemoveAtomic(clump, atomic);
RpAtomicSetFrame(atomic, RwFrameCreate());
CVisibilityPlugins::SetAtomicModelInfo(atomic, mi);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
}else{
debug("Can't find Atomic %s\n", name);
}
return atomic;
}
#ifdef LIBRW
void
InitClump(RpClump *clump)
{
RpClumpForAllAtomics(clump, ConvertPlatformAtomic, nil);
}
#else
#define InitClump(clump)
#endif
2019-06-17 04:30:02 -04:00
void
CFileLoader::LoadModelFile(const char *filename)
{
RwStream *stream;
RpClump *clump;
debug("Loading model file %s\n", filename);
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
clump = RpClumpStreamRead(stream);
if(clump){
InitClump(clump);
2019-06-17 04:30:02 -04:00
RpClumpForAllAtomics(clump, FindRelatedModelInfoCB, clump);
RpClumpDestroy(clump);
}
}
RwStreamClose(stream, nil);
}
void
CFileLoader::LoadClumpFile(const char *filename)
{
RwStream *stream;
RpClump *clump;
char *nodename, name[24];
int n;
CClumpModelInfo *mi;
debug("Loading model file %s\n", filename);
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
while(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
clump = RpClumpStreamRead(stream);
if(clump){
nodename = GetFrameNodeName(RpClumpGetFrame(clump));
GetNameAndLOD(nodename, name, &n);
2019-06-30 06:53:39 -04:00
mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil);
2019-07-20 08:39:38 -04:00
if(mi){
InitClump(clump);
2019-07-20 08:39:38 -04:00
assert(mi->IsClump());
2019-06-17 04:30:02 -04:00
mi->SetClump(clump);
2019-07-20 08:39:38 -04:00
}else
2019-06-17 04:30:02 -04:00
RpClumpDestroy(clump);
}
}
RwStreamClose(stream, nil);
}
bool
CFileLoader::LoadClumpFile(RwStream *stream, uint32 id)
{
RpClump *clump;
CClumpModelInfo *mi;
if(!RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
return false;
clump = RpClumpStreamRead(stream);
if(clump == nil)
return false;
mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id);
mi->SetClump(clump);
2020-05-05 08:06:55 -04:00
if (mi->GetModelType() == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) {
2019-06-17 04:30:02 -04:00
// Read LOD ped
clump = RpClumpStreamRead(stream);
InitClump(clump);
2019-06-17 04:30:02 -04:00
if(clump){
((CPedModelInfo*)mi)->SetLowDetailClump(clump);
RpClumpDestroy(clump);
}
}
return true;
}
bool
CFileLoader::StartLoadClumpFile(RwStream *stream, uint32 id)
{
if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
2021-01-08 14:50:59 -05:00
printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetModelName());
2019-06-17 04:30:02 -04:00
return RpClumpGtaStreamRead1(stream);
}else{
printf("FAILED\n");
return false;
}
}
bool
CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id)
{
RpClump *clump;
CClumpModelInfo *mi;
2021-01-08 14:50:59 -05:00
printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetModelName());
2019-06-17 04:30:02 -04:00
clump = RpClumpGtaStreamRead2(stream);
if(clump){
InitClump(clump);
2019-06-17 04:30:02 -04:00
mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id);
mi->SetClump(clump);
return true;
}else{
printf("FAILED\n");
return false;
}
}
CSimpleModelInfo *gpRelatedModelInfo;
bool
CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id)
{
RpClump *clump;
if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){
clump = RpClumpStreamRead(stream);
if(clump == nil)
return false;
InitClump(clump);
2019-06-17 04:30:02 -04:00
gpRelatedModelInfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
RpClumpForAllAtomics(clump, SetRelatedModelInfoCB, clump);
RpClumpDestroy(clump);
}
return true;
}
#ifdef HARDCODED_MODEL_FLAGS
char *DoubleSidedNames[] = {
"chnabankdoor",
"Security_Hut",
"Hospital_Sub",
"phonebooth1",
"trafficlight1",
"sub_roadbarrier",
"redlightbuild09",
"doublestreetlght1",
"doc_shedbig31",
"com_land_128",
"garage7",
"proj_garage01",
"buildingground2",
"buildingground3",
"ch_roof_kb",
"overpassind",
"casino",
"ind_land100",
"fuckedup_skewlbus",
"Police_Station_ind",
"flagsitaly",
"sidebarrier_gaz1",
"bar_barrier12",
"bar_barrier10b",
"sidebarrier_gaz2",
"doc_shedbig3",
"doc_shedbig4",
"verticalift_bridge",
"verticalift_bridg2",
"usdcrdlrbuild01",
"apairporthanger",
"apairporthangerA",
"porthangerclosed",
"redlightbuild13",
"doc_rave",
"const_woodfence",
"const_woodfence2",
"const_woodfence3",
"subfraightback01",
"subfraightback02",
"subfraightback03",
"subfraightback04",
"subind_build03",
"chinabanner1",
"chinabanner2",
"chinabanner3",
"chinabanner4",
"Pumpfirescape",
"Pumphouse",
"amcounder",
"barrel1",
"barrel2",
"barrel3",
"barrel4",
"com_1way50",
"com_1way20",
"overpasscom01",
"overpasscom02",
"overpasscom03",
"overpasscom04",
"overpass_comse",
"newdockbuilding",
"newdockbuilding2",
"policeballhall",
"fuzballdoor",
"ind_land106",
"PoliceBallSigns",
"amcoudet",
"rustship_structure",
"impexpgrgesub",
"ind_land128",
"fshfctry_dstryd",
"railtrax_bentl",
"railtrax_lo4b",
"railtrax_straight",
"railtrax_bentrb",
"railtrax_skew",
"newtrackaaa",
"railtrax_skew5",
// these they forgot:
"railtrax_skewp",
"railtrax_ske2b",
"railtrax_strtshort",
"railtrax_2b",
"railtrax_straightss",
"railtrax_bentr",
2021-01-04 12:04:50 -05:00
"ind_land125",
"salvstrans",
"bridge_liftsec",
"subsign1",
"carparkfence",
"newairportwall4",
"apair_terminal",
"Helipad",
"bar_barrier10",
"damissionfence",
"sub_floodlite",
"suburbbridge1",
"damfencing",
"demfence08",
"damfence07",
"damfence06",
"damfence05",
"damfence04",
"damfence03",
"damfence02",
"damfence01",
"Dam_pod2",
"Dam_pod1",
"columansion_wall",
"wrckdhse020",
"wrckdhse01",
"arc_bridge",
"gRD_overpass19kbc",
"gRD_overpass19bkb",
"gRD_overpass19kb",
"gRD_overpass18kb",
"road_under",
"com_roadkb23",
"com_roadkb22",
"nbbridgerda",
"nbbridgerdb",
"policetenkb1",
"block3_scraper2",
"Clnm_cthdrlfcde",
"broadwaybuild",
"combillboard03",
"com_park3b",
"com_docksaa",
"newdockbuilding2",
"com_roadkb22",
"sidebarrier_gaz2",
"tunnelsupport1",
"skyscrpunbuilt2",
"cons_buid02",
"rail_platformw",
"railtrax_bent1",
"nrailstepswest",
"building_fucked",
"franksclb02",
"salvsdetail",
"crgoshp01",
"shp_wlkway",
"bar_barriergate1",
"plnt_pylon01",
"fishfctory",
"doc_crane_cab",
"nrailsteps",
"iten_club01",
"mak_Watertank",
"basketballcourt"
"carlift01",
"carlift02",
"iten_chinatown4",
"iten_details7",
"ind_customroad002"
"ind_brgrd1way",
"ind_customroad060",
"ind_customroad002",
"ind_land108",
"ind_customroad004",
"ind_customroad003",
"nbbridgcabls01",
"sbwy_tunl_bit",
"sbwy_tunl_bend",
"sbwy_tunl_cstm11",
"sbwy_tunl_cstm10",
"sbwy_tunl_cstm9",
"sbwy_tunl_cstm8",
"sbwy_tunl_cstm7",
"sbwy_tunl_cstm6",
"sbwy_tunl_cstm5",
"sbwy_tunl_cstm4",
"sbwy_tunl_cstm3",
"sbwy_tunl_cstm2",
"sbwy_tunl_cstm1",
2021-01-04 12:07:39 -05:00
""
2021-01-04 12:04:50 -05:00
};
char *TreeNames[] = {
"coast_treepatch",
"comparknewtrees",
"comtreepatchprk",
"condotree01",
"condotree1",
"indatree03",
"indtreepatch5",
"indtreepatch06f",
"new_carprktrees",
"new_carprktrees4",
"newcoasttrees1",
"newcoasttrees2",
"newcoasttrees3",
"newtreepatch_sub",
"newtrees1_sub",
"newunitrepatch",
"pinetree_narrow",
"pinetree_wide",
"treencom2",
"treepatch",
"treepatch01_sub",
"treepatch02_sub",
"treepatch2",
"treepatch2b",
"treepatch03",
"treepatch03_sub",
"treepatch04_sub",
"treepatch05_sub",
"treepatch06_sub",
"treepatch07_sub",
"treepatch08_sub",
"treepatch09_sub",
"treepatch10_sub",
"treepatch11_sub",
"treepatch12_sub",
"treepatch13_sub",
"treepatch14_sub",
"treepatch15_sub",
"treepatch16_sub",
"treepatch17_sub",
"treepatch18_sub",
"treepatch19_sub",
"treepatch20_sub",
"treepatch21_sub",
"treepatch22_sub",
"treepatch23_sub",
"treepatch24_sub",
"treepatch25_sub",
"treepatch26_sub",
"treepatch27_sub",
"treepatch28_sub",
"treepatch29_sub",
"treepatch30_sub",
"treepatch31_sub",
"treepatch32_sub",
"treepatch33_sub",
"treepatch34_sub",
"treepatch35_sub",
"treepatch69",
"treepatch152_sub",
"treepatch153_sub",
"treepatch171_sub",
"treepatch172_sub",
"treepatch173_sub",
"treepatch212_sub",
"treepatch213_sub",
"treepatch214_sub",
"treepatcha",
"treepatchb",
"treepatchcomtop1",
"treepatchd",
"treepatche",
"treepatchh",
"treepatchindaa2",
"treepatchindnew",
"treepatchindnew2",
"treepatchk",
"treepatchkb4",
"treepatchkb5",
"treepatchkb6",
"treepatchkb7",
"treepatchkb9",
"treepatchl",
"treepatchm",
"treepatchnew_sub",
"treepatchttwrs",
"treesuni1",
"trepatchindaa1",
"veg_bush2",
"veg_bush14",
"veg_tree1",
"veg_tree3",
"veg_treea1",
"veg_treea3",
"veg_treeb1",
"veg_treenew01",
"veg_treenew03",
"veg_treenew05",
"veg_treenew06",
"veg_treenew08",
"veg_treenew09",
"veg_treenew10",
"veg_treenew16",
"veg_treenew17",
"vegclubtree01",
"vegclubtree02",
"vegclubtree03",
"vegpathtree",
""
};
char *OptimizedNames[] = {
"coast_treepatch",
"comparknewtrees",
"comtreepatchprk",
"indtreepatch5",
"indtreepatch06f",
"new_carprktrees",
"new_carprktrees4",
"newcoasttrees1",
"newcoasttrees2",
"newcoasttrees3",
"newtreepatch_sub",
"newtrees1_sub",
"newunitrepatch",
"treepatch",
"treepatch01_sub",
"treepatch02_sub",
"treepatch2",
"treepatch2b",
"treepatch03",
"treepatch03_sub",
"treepatch04_sub",
"treepatch05_sub",
"treepatch06_sub",
"treepatch07_sub",
"treepatch08_sub",
"treepatch09_sub",
"treepatch10_sub",
"treepatch11_sub",
"treepatch12_sub",
"treepatch13_sub",
"treepatch14_sub",
"treepatch15_sub",
"treepatch16_sub",
"treepatch17_sub",
"treepatch18_sub",
"treepatch19_sub",
"treepatch20_sub",
"treepatch21_sub",
"treepatch22_sub",
"treepatch23_sub",
"treepatch24_sub",
"treepatch25_sub",
"treepatch26_sub",
"treepatch27_sub",
"treepatch28_sub",
"treepatch29_sub",
"treepatch30_sub",
"treepatch31_sub",
"treepatch32_sub",
"treepatch33_sub",
"treepatch34_sub",
"treepatch35_sub",
"treepatch69",
"treepatch152_sub",
"treepatch153_sub",
"treepatch171_sub",
"treepatch172_sub",
"treepatch173_sub",
"treepatch212_sub",
"treepatch213_sub",
"treepatch214_sub",
"treepatcha",
"treepatchb",
"treepatchcomtop1",
"treepatchd",
"treepatche",
"treepatchh",
"treepatchindaa2",
"treepatchindnew",
"treepatchindnew2",
"treepatchk",
"treepatchkb4",
"treepatchkb5",
"treepatchkb6",
"treepatchkb7",
"treepatchkb9",
"treepatchl",
"treepatchm",
"treepatchnew_sub",
"treepatchttwrs",
"treesuni1",
"trepatchindaa1",
"combtm_treeshad01",
"combtm_treeshad02",
"combtm_treeshad03",
"combtm_treeshad04",
"combtm_treeshad05",
"combtm_treeshad06",
"comtop_tshad",
"comtop_tshad2",
"comtop_tshad3",
"comtop_tshad4",
"comtop_tshad5",
"comtop_tshad6",
"se_treeshad01",
"se_treeshad02",
"se_treeshad03",
"se_treeshad04",
"se_treeshad05",
"se_treeshad06",
"treeshads01",
"treeshads02",
"treeshads03",
"treeshads04",
"treeshads05",
""
};
// not from mobile
static bool
MatchModelName(char *name, char **list)
{
int i;
char *s;
for(i = 0; *list[i] != '\0'; i++)
if(strncmp(name, "LOD", 3) == 0){
if(!CGeneral::faststricmp(name+3, list[i]+3))
return true;
}else{
if(!CGeneral::faststricmp(name, list[i]))
return true;
}
return false;
}
#endif
2019-06-17 04:30:02 -04:00
RpAtomic*
CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data)
{
char *nodename, name[24];
int n;
RpClump *clump = (RpClump*)data;
nodename = GetFrameNodeName(RpAtomicGetFrame(atomic));
GetNameAndLOD(nodename, name, &n);
gpRelatedModelInfo->SetAtomic(n, atomic);
RpClumpRemoveAtomic(clump, atomic);
RpAtomicSetFrame(atomic, RwFrameCreate());
CVisibilityPlugins::SetAtomicModelInfo(atomic, gpRelatedModelInfo);
2019-06-30 06:53:39 -04:00
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
2019-06-17 04:30:02 -04:00
return atomic;
}
RpClump*
CFileLoader::LoadAtomicFile2Return(const char *filename)
{
RwStream *stream;
RpClump *clump;
clump = nil;
debug("Loading model file %s\n", filename);
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil))
clump = RpClumpStreamRead(stream);
if(clump)
InitClump(clump);
2019-06-17 04:30:02 -04:00
RwStreamClose(stream, nil);
return clump;
}
static RwTexture*
MoveTexturesCB(RwTexture *texture, void *pData)
{
RwTexDictionaryAddTexture((RwTexDictionary*)pData, texture);
return texture;
}
void
CFileLoader::AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src)
{
RwTexDictionaryForAllTextures(src, MoveTexturesCB, dst);
}
2020-12-25 08:18:13 -05:00
#define isLine3(l, a, b, c) ((l[0] == a) && (l[1] == b) && (l[2] == c))
#define isLine4(l, a, b, c, d) ((l[0] == a) && (l[1] == b) && (l[2] == c) && (l[3] == d))
2019-06-17 04:30:02 -04:00
void
CFileLoader::LoadObjectTypes(const char *filename)
{
enum {
NONE,
OBJS,
MLO,
TOBJ,
HIER,
CARS,
PEDS,
PATH,
TWODFX
2019-06-17 04:30:02 -04:00
};
char *line;
int fd;
int section;
int pathIndex;
char pathTypeStr[20];
int id, pathType;
int mlo;
2019-06-17 04:30:02 -04:00
2019-06-18 03:50:26 -04:00
section = NONE;
2019-06-17 04:30:02 -04:00
pathIndex = -1;
mlo = 0;
2019-06-17 04:30:02 -04:00
debug("Loading object types from %s...\n", filename);
fd = CFileMgr::OpenFile(filename, "rb");
for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
if(*line == '\0' || *line == '#')
continue;
if(section == NONE){
2020-12-25 08:18:13 -05:00
if(isLine4(line, 'o','b','j','s')) section = OBJS;
else if(isLine4(line, 't','o','b','j')) section = TOBJ;
else if(isLine4(line, 'h','i','e','r')) section = HIER;
else if(isLine4(line, 'c','a','r','s')) section = CARS;
else if(isLine4(line, 'p','e','d','s')) section = PEDS;
else if(isLine4(line, 'p','a','t','h')) section = PATH;
else if(isLine4(line, '2','d','f','x')) section = TWODFX;
}else if(isLine3(line, 'e','n','d')){
2019-06-17 04:30:02 -04:00
section = section == MLO ? OBJS : NONE;
}else switch(section){
case OBJS:
2020-12-25 08:18:13 -05:00
if(isLine3(line, 's','t','a'))
mlo = LoadMLO(line);
2019-06-17 04:30:02 -04:00
else
LoadObject(line);
break;
case MLO:
LoadMLOInstance(mlo, line);
2019-06-17 04:30:02 -04:00
break;
case TOBJ:
LoadTimeObject(line);
break;
case HIER:
LoadClumpObject(line);
break;
case CARS:
LoadVehicleObject(line);
break;
case PEDS:
LoadPedObject(line);
break;
case PATH:
if(pathIndex == -1){
id = LoadPathHeader(line, pathTypeStr);
2020-12-25 08:18:13 -05:00
if(strcmp(pathTypeStr, "ped") == 0)
2019-06-17 04:30:02 -04:00
pathType = 1;
2020-12-25 08:18:13 -05:00
else if(strcmp(pathTypeStr, "car") == 0)
2019-06-17 04:30:02 -04:00
pathType = 0;
pathIndex = 0;
}else{
if(pathType == 1)
LoadPedPathNode(line, id, pathIndex);
else if(pathType == 0)
LoadCarPathNode(line, id, pathIndex);
pathIndex++;
if(pathIndex == 12)
pathIndex = -1;
}
break;
case TWODFX:
2019-06-17 04:30:02 -04:00
Load2dEffect(line);
break;
}
}
CFileMgr::CloseFile(fd);
for(id = 0; id < MODELINFOSIZE; id++){
CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
if(mi && mi->IsSimple())
mi->SetupBigBuilding();
}
}
void
SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags)
{
mi->m_normalCull = !!(flags & 1);
mi->m_noFade = !!(flags & 2);
mi->m_drawLast = !!(flags & (4|8));
mi->m_additive = !!(flags & 8);
mi->m_isSubway = !!(flags & 0x10);
mi->m_ignoreLight = !!(flags & 0x20);
mi->m_noZwrite = !!(flags & 0x40);
#ifdef EXTRA_MODEL_FLAGS
// same flag values as SA
mi->m_bIsTree = !!(flags & 0x2000);
mi->m_bIsDoubleSided = !!(flags & 0x200000);
// new value otherwise unused
mi->m_bCanBeIgnored = !!(flags & 0x10000);
#ifdef HARDCODED_MODEL_FLAGS
// mobile sets these flags in CFileLoader::SetRelatedModelInfoCB, but that's stupid
2021-01-08 14:50:59 -05:00
if(MatchModelName(mi->GetModelName(), DoubleSidedNames)) mi->m_bIsDoubleSided = true;
if(MatchModelName(mi->GetModelName(), TreeNames)) mi->m_bIsTree = true;
if(MatchModelName(mi->GetModelName(), OptimizedNames)) mi->m_bCanBeIgnored = true;
#endif
#endif
2019-06-17 04:30:02 -04:00
}
void
CFileLoader::LoadObject(const char *line)
{
int id, numObjs;
char model[24], txd[24];
float dist[3];
uint32 flags;
int damaged;
CSimpleModelInfo *mi;
if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
return;
switch(numObjs){
case 1:
sscanf(line, "%d %s %s %d %f %d",
&id, model, txd, &numObjs, &dist[0], &flags);
damaged = 0;
break;
case 2:
sscanf(line, "%d %s %s %d %f %f %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &flags);
damaged = dist[0] < dist[1] ? // Are distances increasing?
0 : // Yes, no damage model
1; // No, 1 is damaged
break;
case 3:
sscanf(line, "%d %s %s %d %f %f %f %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags);
damaged = dist[0] < dist[1] ? // Are distances increasing?
(dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model
1; // No, 1 and 2 are damaged
break;
}
mi = CModelInfo::AddSimpleModel(id);
2021-01-08 14:50:59 -05:00
mi->SetModelName(model);
2019-06-17 04:30:02 -04:00
mi->SetNumAtomics(numObjs);
mi->SetLodDistances(dist);
SetModelInfoFlags(mi, flags);
mi->m_firstDamaged = damaged;
mi->SetTexDictionary(txd);
MatchModelString(model, id);
}
int
CFileLoader::LoadMLO(const char *line)
{
char smth[8];
char name[24];
int modelIndex;
float someFloat;
sscanf(line, "%s %s %d %f", smth, name, &modelIndex, &someFloat);
CMloModelInfo *minfo = CModelInfo::AddMloModel(modelIndex);
2021-01-08 14:50:59 -05:00
minfo->SetModelName(name);
minfo->field_34 = someFloat;
2020-01-23 10:29:36 -05:00
int instId = CModelInfo::GetMloInstanceStore().allocPtr;
minfo->firstInstance = instId;
minfo->lastInstance = instId;
minfo->SetTexDictionary("generic");
return modelIndex;
}
void
CFileLoader::LoadMLOInstance(int id, const char *line)
{
char name[24];
RwV3d pos, scale, rot;
float angle;
int modelIndex;
CMloModelInfo *minfo = (CMloModelInfo*)CModelInfo::GetModelInfo(id);
sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f",
&modelIndex,
name,
&pos.x, &pos.y, &pos.z,
&scale.x, &scale.y, &scale.z,
&rot.x, &rot.y, &rot.z,
&angle);
2020-01-29 06:00:40 -05:00
float rad = Acos(angle) * 2.0f;
2020-12-18 07:58:59 -05:00
CInstance *inst = CModelInfo::GetMloInstanceStore().Alloc();
minfo->lastInstance++;
RwMatrix *matrix = RwMatrixCreate();
RwMatrixScale(matrix, &scale, rwCOMBINEREPLACE);
RwMatrixRotate(matrix, &rot, -RADTODEG(rad), rwCOMBINEPOSTCONCAT);
RwMatrixTranslate(matrix, &pos, rwCOMBINEPOSTCONCAT);
inst->GetMatrix() = CMatrix(matrix);
inst->GetMatrix().UpdateRW();
inst->m_modelIndex = modelIndex;
RwMatrixDestroy(matrix);
}
2019-06-17 04:30:02 -04:00
void
CFileLoader::LoadTimeObject(const char *line)
{
int id, numObjs;
char model[24], txd[24];
float dist[3];
uint32 flags;
int timeOn, timeOff;
int damaged;
CTimeModelInfo *mi, *other;
if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
return;
switch(numObjs){
case 1:
sscanf(line, "%d %s %s %d %f %d %d %d",
&id, model, txd, &numObjs, &dist[0], &flags, &timeOn, &timeOff);
damaged = 0;
break;
case 2:
sscanf(line, "%d %s %s %d %f %f %d %d %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &flags, &timeOn, &timeOff);
damaged = dist[0] < dist[1] ? // Are distances increasing?
0 : // Yes, no damage model
1; // No, 1 is damaged
break;
case 3:
sscanf(line, "%d %s %s %d %f %f %f %d %d %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags, &timeOn, &timeOff);
damaged = dist[0] < dist[1] ? // Are distances increasing?
(dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model
1; // No, 1 and 2 are damaged
break;
}
mi = CModelInfo::AddTimeModel(id);
2021-01-08 14:50:59 -05:00
mi->SetModelName(model);
2019-06-17 04:30:02 -04:00
mi->SetNumAtomics(numObjs);
mi->SetLodDistances(dist);
SetModelInfoFlags(mi, flags);
mi->m_firstDamaged = damaged;
mi->SetTimes(timeOn, timeOff);
mi->SetTexDictionary(txd);
other = mi->FindOtherTimeModel();
if(other)
other->SetOtherTimeModel(id);
MatchModelString(model, id);
}
void
CFileLoader::LoadClumpObject(const char *line)
{
int id;
char model[24], txd[24];
CClumpModelInfo *mi;
2020-05-11 19:24:57 -04:00
if(sscanf(line, "%d %s %s", &id, model, txd) == 3){
2019-06-17 04:30:02 -04:00
mi = CModelInfo::AddClumpModel(id);
2021-01-08 14:50:59 -05:00
mi->SetModelName(model);
2019-06-17 04:30:02 -04:00
mi->SetTexDictionary(txd);
mi->SetColModel(&CTempColModels::ms_colModelBBox);
}
}
void
CFileLoader::LoadVehicleObject(const char *line)
{
int id;
char model[24], txd[24];
char type[8], handlingId[16], gamename[32], vehclass[12];
uint32 frequency, comprules;
int32 level, misc;
float wheelScale;
CVehicleModelInfo *mi;
char *p;
sscanf(line, "%d %s %s %s %s %s %s %d %d %x %d %f",
&id, model, txd,
type, handlingId, gamename, vehclass,
&frequency, &level, &comprules, &misc, &wheelScale);
mi = CModelInfo::AddVehicleModel(id);
2021-01-08 14:50:59 -05:00
mi->SetModelName(model);
2019-06-17 04:30:02 -04:00
mi->SetTexDictionary(txd);
for(p = gamename; *p; p++)
if(*p == '_') *p = ' ';
2020-05-10 11:09:57 -04:00
strcpy(mi->m_gameName, gamename);
2019-06-17 04:30:02 -04:00
mi->m_level = level;
mi->m_compRules = comprules;
2020-12-25 08:18:13 -05:00
if(strcmp(type, "car") == 0){
2019-06-17 04:30:02 -04:00
mi->m_wheelId = misc;
mi->m_wheelScale = wheelScale;
2019-10-25 12:39:26 -04:00
mi->m_vehicleType = VEHICLE_TYPE_CAR;
2020-12-25 08:18:13 -05:00
}else if(strcmp(type, "boat") == 0){
2019-06-17 04:30:02 -04:00
mi->m_vehicleType = VEHICLE_TYPE_BOAT;
2020-12-25 08:18:13 -05:00
}else if(strcmp(type, "train") == 0){
2019-06-17 04:30:02 -04:00
mi->m_vehicleType = VEHICLE_TYPE_TRAIN;
2020-12-25 08:18:13 -05:00
}else if(strcmp(type, "heli") == 0){
2019-06-17 04:30:02 -04:00
mi->m_vehicleType = VEHICLE_TYPE_HELI;
2020-12-25 08:18:13 -05:00
}else if(strcmp(type, "plane") == 0){
2019-07-31 17:57:18 -04:00
mi->m_planeLodId = misc;
2019-06-17 04:30:02 -04:00
mi->m_wheelScale = 1.0f;
mi->m_vehicleType = VEHICLE_TYPE_PLANE;
2020-12-25 08:18:13 -05:00
}else if(strcmp(type, "bike") == 0){
2019-06-17 04:30:02 -04:00
mi->m_bikeSteerAngle = misc;
mi->m_wheelScale = wheelScale;
mi->m_vehicleType = VEHICLE_TYPE_BIKE;
}else
assert(0);
mi->m_handlingId = mod_HandlingManager.GetHandlingId(handlingId);
// Well this is kinda dumb....
2020-12-25 08:18:13 -05:00
if(strcmp(vehclass, "poorfamily") == 0){
mi->m_vehicleClass = CCarCtrl::POOR;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::POOR);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "richfamily") == 0){
mi->m_vehicleClass = CCarCtrl::RICH;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::RICH);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "executive") == 0){
mi->m_vehicleClass = CCarCtrl::EXEC;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::EXEC);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "worker") == 0){
mi->m_vehicleClass = CCarCtrl::WORKER;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::WORKER);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "special") == 0){
mi->m_vehicleClass = CCarCtrl::SPECIAL;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::SPECIAL);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "big") == 0){
mi->m_vehicleClass = CCarCtrl::BIG;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::BIG);
2020-12-25 08:18:13 -05:00
}else if(strcmp(vehclass, "taxi") == 0){
mi->m_vehicleClass = CCarCtrl::TAXI;
2019-06-17 04:30:02 -04:00
while(frequency-- > 0)
CCarCtrl::AddToCarArray(id, CCarCtrl::TAXI);
2019-06-17 04:30:02 -04:00
}
}
void
CFileLoader::LoadPedObject(const char *line)
{
int id;
char model[24], txd[24];
char pedType[24], pedStats[24], animGroup[24];
int carsCanDrive;
CPedModelInfo *mi;
int animGroupId;
if(sscanf(line, "%d %s %s %s %s %s %x",
&id, model, txd,
pedType, pedStats, animGroup, &carsCanDrive) != 7)
return;
mi = CModelInfo::AddPedModel(id);
2021-01-08 14:50:59 -05:00
mi->SetModelName(model);
2019-06-17 04:30:02 -04:00
mi->SetTexDictionary(txd);
mi->SetColModel(&CTempColModels::ms_colModelPed1);
mi->m_pedType = CPedType::FindPedType(pedType);
mi->m_pedStatType = CPedStats::GetPedStatType(pedStats);
for(animGroupId = 0; animGroupId < NUM_ANIM_ASSOC_GROUPS; animGroupId++)
if(strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)animGroupId)) == 0)
break;
mi->m_animGroup = animGroupId;
mi->m_carsCanDrive = carsCanDrive;
2019-06-17 04:30:02 -04:00
// ???
CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1);
}
int
CFileLoader::LoadPathHeader(const char *line, char *type)
{
int id;
char modelname[32];
sscanf(line, "%s %d %s", type, &id, modelname);
return id;
}
void
CFileLoader::LoadPedPathNode(const char *line, int id, int node)
{
int type, next, cross;
float x, y, z, width;
sscanf(line, "%d %d %d %f %f %f %f", &type, &next, &cross, &x, &y, &z, &width);
ThePaths.StoreNodeInfoPed(id, node, type, next, x, y, z, 0, !!cross);
}
void
CFileLoader::LoadCarPathNode(const char *line, int id, int node)
{
int type, next, cross, numLeft, numRight;
float x, y, z, width;
sscanf(line, "%d %d %d %f %f %f %f %d %d", &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight);
ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight);
}
2019-06-17 04:30:02 -04:00
void
CFileLoader::Load2dEffect(const char *line)
{
int id, r, g, b, a, type;
float x, y, z;
char corona[32], shadow[32];
2019-06-30 15:06:55 -04:00
int shadowIntens, lightType, roadReflection, flare, flags, probability;
2019-06-17 04:30:02 -04:00
CBaseModelInfo *mi;
C2dEffect *effect;
char *p;
sscanf(line, "%d %f %f %f %d %d %d %d %d", &id, &x, &y, &z, &r, &g, &b, &a, &type);
CTxdStore::PushCurrentTxd();
CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle"));
mi = CModelInfo::GetModelInfo(id);
2020-12-18 07:58:59 -05:00
effect = CModelInfo::Get2dEffectStore().Alloc();
2019-06-17 04:30:02 -04:00
mi->Add2dEffect(effect);
effect->pos = CVector(x, y, z);
effect->col = CRGBA(r, g, b, a);
effect->type = type;
switch(effect->type){
case EFFECT_LIGHT:
while(*line++ != '"');
p = corona;
while(*line != '"') *p++ = *line++;
*p = '\0';
line++;
while(*line++ != '"');
p = shadow;
while(*line != '"') *p++ = *line++;
*p = '\0';
line++;
sscanf(line, "%f %f %f %f %d %d %d %d %d",
&effect->light.dist,
2019-06-30 15:06:55 -04:00
&effect->light.range,
2019-06-17 04:30:02 -04:00
&effect->light.size,
2020-06-28 06:05:31 -04:00
&effect->light.shadowSize,
2019-06-30 15:06:55 -04:00
&shadowIntens, &lightType, &roadReflection, &flare, &flags);
2019-06-17 04:30:02 -04:00
effect->light.corona = RwTextureRead(corona, nil);
effect->light.shadow = RwTextureRead(shadow, nil);
effect->light.shadowIntensity = shadowIntens;
2019-06-30 15:06:55 -04:00
effect->light.lightType = lightType;
2019-06-17 04:30:02 -04:00
effect->light.roadReflection = roadReflection;
effect->light.flareType = flare;
2020-03-01 19:03:39 -05:00
if(flags & LIGHTFLAG_FOG_ALWAYS)
flags &= ~LIGHTFLAG_FOG_NORMAL;
2019-06-17 04:30:02 -04:00
effect->light.flags = flags;
break;
case EFFECT_PARTICLE:
sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f",
&id, &x, &y, &z, &r, &g, &b, &a, &type,
&effect->particle.particleType,
&effect->particle.dir.x,
&effect->particle.dir.y,
&effect->particle.dir.z,
&effect->particle.scale);
break;
case EFFECT_ATTRACTOR:
sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %d",
&id, &x, &y, &z, &r, &g, &b, &a, &type,
&flags,
&effect->attractor.dir.x,
&effect->attractor.dir.y,
&effect->attractor.dir.z,
&probability);
2020-06-25 09:12:57 -04:00
effect->attractor.type = flags;
#ifdef FIX_BUGS
effect->attractor.probability = clamp(probability, 0, 255);
#else
2019-06-17 04:30:02 -04:00
effect->attractor.probability = probability;
#endif
2019-06-17 04:30:02 -04:00
break;
}
CTxdStore::PopCurrentTxd();
}
2019-06-18 03:50:26 -04:00
void
CFileLoader::LoadScene(const char *filename)
{
enum {
NONE,
INST,
ZONE,
CULL,
PICK,
PATH,
};
char *line;
int fd;
int section;
int pathIndex;
char pathTypeStr[20];
section = NONE;
pathIndex = -1;
debug("Creating objects from %s...\n", filename);
fd = CFileMgr::OpenFile(filename, "rb");
for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
if(*line == '\0' || *line == '#')
continue;
if(section == NONE){
2020-12-25 08:18:13 -05:00
if(isLine4(line, 'i','n','s','t')) section = INST;
else if(isLine4(line, 'z','o','n','e')) section = ZONE;
else if(isLine4(line, 'c','u','l','l')) section = CULL;
else if(isLine4(line, 'p','i','c','k')) section = PICK;
else if(isLine4(line, 'p','a','t','h')) section = PATH;
}else if(isLine3(line, 'e','n','d')){
2019-06-18 03:50:26 -04:00
section = NONE;
}else switch(section){
case INST:
LoadObjectInstance(line);
break;
case ZONE:
LoadZone(line);
break;
case CULL:
LoadCullZone(line);
break;
case PICK:
// unused
LoadPickup(line);
break;
case PATH:
// unfinished in the game
if(pathIndex == -1){
LoadPathHeader(line, pathTypeStr);
2020-12-25 08:18:13 -05:00
strcmp(pathTypeStr, "ped");
2019-06-18 03:50:26 -04:00
// type not set
pathIndex = 0;
}else{
// nodes not loaded
pathIndex++;
if(pathIndex == 12)
pathIndex = -1;
}
break;
}
}
CFileMgr::CloseFile(fd);
debug("Finished loading IPL\n");
}
void
CFileLoader::LoadObjectInstance(const char *line)
{
int id;
char name[24];
RwV3d trans, scale, axis;
float angle;
CSimpleModelInfo *mi;
RwMatrix *xform;
CEntity *entity;
if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f",
&id, name,
&trans.x, &trans.y, &trans.z,
&scale.x, &scale.y, &scale.z,
&axis.x, &axis.y, &axis.z, &angle) != 12)
return;
mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
if(mi == nil)
return;
assert(mi->IsSimple());
angle = -RADTODEG(2.0f * acosf(angle));
xform = RwMatrixCreate();
RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE);
RwMatrixTranslate(xform, &trans, rwCOMBINEPOSTCONCAT);
if(mi->GetObjectID() == -1){
if(ThePaths.IsPathObject(id)){
entity = new CTreadable;
ThePaths.RegisterMapObject((CTreadable*)entity);
}else
entity = new CBuilding;
entity->SetModelIndexNoCreate(id);
entity->GetMatrix() = CMatrix(xform);
2020-05-06 06:23:26 -04:00
entity->m_level = CTheZones::GetLevelFromPosition(&entity->GetPosition());
2019-06-18 03:50:26 -04:00
if(mi->IsSimple()){
if(mi->m_isBigBuilding)
entity->SetupBigBuilding();
if(mi->m_isSubway)
entity->bIsSubway = true;
}
if(mi->GetLargestLodDistance() < 2.0f)
entity->bIsVisible = false;
CWorld::Add(entity);
}else{
entity = new CDummyObject;
entity->SetModelIndexNoCreate(id);
entity->GetMatrix() = CMatrix(xform);
CWorld::Add(entity);
if(IsGlass(entity->GetModelIndex()))
entity->bIsVisible = false;
2020-05-06 06:23:26 -04:00
entity->m_level = CTheZones::GetLevelFromPosition(&entity->GetPosition());
2019-06-18 03:50:26 -04:00
}
RwMatrixDestroy(xform);
}
void
CFileLoader::LoadZone(const char *line)
{
char name[24];
int type, level;
float minx, miny, minz;
float maxx, maxy, maxz;
if(sscanf(line, "%s %d %f %f %f %f %f %f %d", name, &type, &minx, &miny, &minz, &maxx, &maxy, &maxz, &level) == 9)
CTheZones::CreateZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level);
}
void
CFileLoader::LoadCullZone(const char *line)
{
CVector pos;
float minx, miny, minz;
float maxx, maxy, maxz;
int flags;
int wantedLevelDrop = 0;
sscanf(line, "%f %f %f %f %f %f %f %f %f %d %d",
&pos.x, &pos.y, &pos.z,
&minx, &miny, &minz,
&maxx, &maxy, &maxz,
&flags, &wantedLevelDrop);
2019-06-21 11:28:55 -04:00
CCullZones::AddCullZone(pos, minx, maxx, miny, maxy, minz, maxz, flags, wantedLevelDrop);
2019-06-18 03:50:26 -04:00
}
// unused
void
CFileLoader::LoadPickup(const char *line)
{
int id;
float x, y, z;
sscanf(line, "%d %f %f %f", &id, &x, &y, &z);
}
void
CFileLoader::LoadMapZones(const char *filename)
{
enum {
NONE,
INST,
ZONE,
CULL,
PICK,
PATH,
};
char *line;
int fd;
int section;
section = NONE;
debug("Creating zones from %s...\n", filename);
fd = CFileMgr::OpenFile(filename, "rb");
for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){
if(*line == '\0' || *line == '#')
continue;
if(section == NONE){
2020-12-25 08:18:13 -05:00
if(isLine4(line, 'z','o','n','e')) section = ZONE;
}else if(isLine3(line, 'e','n','d')){
2019-06-18 03:50:26 -04:00
section = NONE;
}else switch(section){
case ZONE: {
char name[24];
int type, level;
float minx, miny, minz;
float maxx, maxy, maxz;
if(sscanf(line, "%s %d %f %f %f %f %f %f %d",
2020-05-11 19:24:57 -04:00
name, &type,
2019-06-18 03:50:26 -04:00
&minx, &miny, &minz,
&maxx, &maxy, &maxz,
&level) == 9)
CTheZones::CreateMapZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level);
}
break;
}
}
CFileMgr::CloseFile(fd);
debug("Finished loading IPL\n");
}
void
CFileLoader::ReloadPaths(const char *filename)
{
enum {
NONE,
PATH,
};
char *line;
int section = NONE;
int id, pathType, pathIndex = -1;
char pathTypeStr[20];
debug("Reloading paths from %s...\n", filename);
int fd = CFileMgr::OpenFile(filename, "r");
for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
if (*line == '\0' || *line == '#')
continue;
if (section == NONE) {
2020-12-25 08:18:13 -05:00
if (isLine4(line, 'p','a','t','h')) {
section = PATH;
ThePaths.AllocatePathFindInfoMem(4500);
}
2020-12-25 08:18:13 -05:00
} else if (isLine3(line, 'e','n','d')) {
section = NONE;
} else {
switch (section) {
case PATH:
if (pathIndex == -1) {
id = LoadPathHeader(line, pathTypeStr);
2020-12-25 08:18:13 -05:00
if (strcmp(pathTypeStr, "ped") == 0)
pathType = 1;
2020-12-25 08:18:13 -05:00
else if (strcmp(pathTypeStr, "car") == 0)
pathType = 0;
pathIndex = 0;
} else {
if (pathType == 1)
LoadPedPathNode(line, id, pathIndex);
else if (pathType == 0)
LoadCarPathNode(line, id, pathIndex);
pathIndex++;
if (pathIndex == 12)
pathIndex = -1;
}
break;
default:
break;
}
}
}
CFileMgr::CloseFile(fd);
}
void
CFileLoader::ReloadObjectTypes(const char *filename)
{
enum {
NONE,
OBJS,
TOBJ,
TWODFX
};
char *line;
int section = NONE;
CModelInfo::ReInit2dEffects();
debug("Reloading object types from %s...\n", filename);
CFileMgr::ChangeDir("\\DATA\\MAPS\\");
int fd = CFileMgr::OpenFile(filename, "r");
CFileMgr::ChangeDir("\\");
for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
if (*line == '\0' || *line == '#')
continue;
if (section == NONE) {
2020-12-25 08:18:13 -05:00
if (isLine4(line, 'o','b','j','s')) section = OBJS;
else if (isLine4(line, 't','o','b','j')) section = TOBJ;
else if (isLine4(line, '2','d','f','x')) section = TWODFX;
} else if (isLine3(line, 'e','n','d')) {
section = NONE;
} else {
switch (section) {
case OBJS:
case TOBJ:
ReloadObject(line);
break;
case TWODFX:
Load2dEffect(line);
break;
default:
break;
}
}
}
CFileMgr::CloseFile(fd);
}
void
CFileLoader::ReloadObject(const char *line)
{
int id, numObjs;
char model[24], txd[24];
float dist[3];
uint32 flags;
CSimpleModelInfo *mi;
if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4)
return;
switch(numObjs){
case 1:
sscanf(line, "%d %s %s %d %f %d",
&id, model, txd, &numObjs, &dist[0], &flags);
break;
case 2:
sscanf(line, "%d %s %s %d %f %f %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &flags);
break;
case 3:
sscanf(line, "%d %s %s %d %f %f %f %d",
&id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags);
break;
}
mi = (CSimpleModelInfo*) CModelInfo::GetModelInfo(id);
if (
#ifdef FIX_BUGS
mi &&
#endif
2021-01-08 14:50:59 -05:00
mi->GetModelType() == MITYPE_SIMPLE && !strcmp(mi->GetModelName(), model) && mi->m_numAtomics == numObjs) {
mi->SetLodDistances(dist);
SetModelInfoFlags(mi, flags);
} else {
printf("Can't reload %s\n", model);
}
}
// unused mobile function - crashes
void
CFileLoader::ReLoadScene(const char *filename)
{
char *line;
CFileMgr::ChangeDir("\\DATA\\");
int fd = CFileMgr::OpenFile(filename, "r");
CFileMgr::ChangeDir("\\");
for (line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)) {
if (*line == '#')
continue;
2020-12-25 08:18:13 -05:00
#ifdef FIX_BUGS
if (strncmp(line, "EXIT", 4) == 0)
#else
if (strncmp(line, "EXIT", 9) == 0)
#endif
break;
if (strncmp(line, "IDE", 3) == 0) {
LoadObjectTypes(line + 4);
}
}
CFileMgr::CloseFile(fd);
}