#include "mapviewer.h" void CWorld::Init() { SetInterior(0); SetLODmultiplier(1.0); ObjList = NULL; } void CWorld::Draw(int DrawTransp) { float d; CWorldObj *op; Instance *ip; int atm; bool drawn; bool dffLoaded = false; bool txdLoaded = false; for (op = ObjList; op != NULL; op = op->next) { /* These two don't work with GTA3 PS2, don't know why */ if (strcmp(op->ModelName, "TRAFFICCONE") == 0) continue; if (strcmp(op->ModelName, "PARKTABLE1") == 0) continue; drawn = false; if (op->isTimed) if (!isVisible(op)) goto unload; for (ip = op->InstList; ip != NULL; ip = ip->next) { /* Skip Island LODs */ if (ip->isIslandLOD) continue; /* Check for interior */ if ((Game.GetVersion() & GAMEVICECITY) != 0) if (Interior != ip->Interior && ip->Interior != 13) continue; /* Check for culling */ if (GLView.DoCulling() && op->BSphere[3] != 0) if (isCulled(ip)) continue; /* Check for Draw distance */ d = Camera.DistanceTo(ip->PositionV); if ((atm = isCorrectLOD(ip, d)) == -1) continue; /* Load DFF, if needed */ if (op->Clump == NULL) { // if (dffLoaded) // continue; if (!FileLoader.LoadDff(op)) continue; dffLoaded = true; } if (op->TxdEntry != NULL) op->TxdEntry->RefCount++; if (GLView.UseTextures()) { /* Load TXD, if needed */ if (op->TexDict == NULL) { // if (txdLoaded) // continue; if (!FileLoader.LoadTxd(op)) continue; txdLoaded = true; } } /* Draw the object */ RwTexDictionarySetCurrent(op->TexDict); glPushMatrix(); TransformItem(ip); op->Draw(false, atm, DrawTransp); glPopMatrix(); drawn = true; } unload: if (op->Clump != NULL) { if (!drawn) { // cout << op->ModelName // << " not used...unloading\n"; FileLoader.UnloadWorldObj(op); } } } // cout << endl << endl << endl << endl; } int CWorld::isCorrectLOD(Instance *Inst, float d) { /* // display only those lods that don't have a non-lod if (Inst->MinDrawDist[0] != 60) return false; else return true; */ ///* int i; for (i = 0; i < Inst->Obj->ObjCount; i++) { if (d*LODmultiplier < Inst->MaxDrawDist[i] && d*LODmultiplier > Inst->MinDrawDist[i]) return i; } return -1; //*/ } #if 0 void CWorld::BuildTree() { CWorldObj *op, *lodo; Instance *ip, *lodi; cout << "Loading, please wait..." << flush; for (op = ObjList; op != NULL; op = op->next) { /* Set Minimal Draw Dist for LODs */ if (!op->isLOD) { if ((lodo = GetLOD(op))) lodo->MinDrawDist[0] = op->DrawDist[0]; } /* for (ip = op->InstList; ip != NULL; ip = ip->next) { ip->DrawDist = new float[op->ObjCount]; memcpy(ip->DrawDist, op->DrawDist, op->ObjCount*sizeof(float)); if ((lodi = GetLOD(ip))) { lodo = lodi->Obj; ip->MinDrawDist = new float[lodo->ObjCount]; memcpy(lodi->DrawDist, lodo->DrawDist, lodo->ObjCount*sizeof(float)); } } */ /* Give every object its dff and txd */ if (op->Clump == NULL) op->DffEntry=Directory.GetEntry(op->ModelName, ".DFF"); if (op->TexDict == NULL) op->TxdEntry=Directory.GetEntry(op->TextureName, ".TXD"); } cout << "done\n"; } #endif void CWorld::AddInstance(Instance *Inst) { CWorldObj *Obj; Obj = GetObjByID(Inst->ID); if (!Obj) { cerr << "Couldn't find Object to add instance to\n"; cerr << Inst->Name << endl; return; } Inst->Obj = Obj; Inst->next = Obj->InstList; Obj->InstList = Inst; } void CWorld::AddInstancesFromBinFile(FILE *file, vector &Iv) { int i, j; int numEntries; Instance *Inst; CWorldObj *Obj; fseek(file, 4, SEEK_CUR); if (fread(&numEntries, 4, 1, file) != 1) exiterror("Error in binary IPL", ""); fseek(file, 68, SEEK_CUR); for (i = 0; i < numEntries; i++) { Inst = new Instance; if (fread(Inst->PositionV, 4, 3, file) != 3) exiterror("Error in binary IPL", ""); if (fread(Inst->Rotation, 4, 4, file) != 4) exiterror("Error in binary IPL", ""); if (fread(&Inst->ID, 4, 1, file) != 1) exiterror("Error in binary IPL", ""); if (fread(&Inst->Interior, 4, 1, file) != 1) exiterror("Error in binary IPL", ""); if (fread(&Inst->LOD, 4, 1, file) != 1) exiterror("Error in binary IPL", ""); Inst->Obj = NULL; Inst->Index = Index; Obj = GetObjByID(Inst->ID); if (Obj) strcpy(Inst->Name, Obj->ModelName); AddInstance(Inst); Iv.push_back(Inst); /* We now have an object associated */ Inst->isLOD = Inst->Obj->isLOD; Inst->isIslandLOD = Inst->Obj->isIslandLOD; Inst->MaxDrawDist = new float[Inst->Obj->ObjCount]; Inst->MinDrawDist = new float[Inst->Obj->ObjCount]; for (j = 0; j < Inst->Obj->ObjCount; j++) { Inst->MaxDrawDist[j] = Inst->Obj->DrawDist[j]; Inst->MinDrawDist[j] = Inst->Obj->MinDrawDist[j]; } Index++; } } void CWorld::AddInstancesFromPlainFile(FILE *file, vector &Iv) { int BlockType; char buffer[512]; char *pos; Instance *Inst; int i; BlockType = 0; while (ReadConfigLine(file, buffer) != NULL) { if (strcmp(buffer, "inst") == 0) { BlockType = INST; continue; } if (strcmp(buffer, "cull") == 0) { BlockType = CULL; continue; } if (strcmp(buffer, "end") == 0) { BlockType = END; continue; } if (BlockType == INST) { pos = buffer; Inst = new Instance; Inst->Index = Index; pos = GetInt(pos, &Inst->ID); pos = GetWordUp(pos, Inst->Name); if ((Game.GetVersion() & GAMEIII) == 0) pos = GetInt(pos, &Inst->Interior); pos = GetFloat(pos, &Inst->PositionV[0]); pos = GetFloat(pos, &Inst->PositionV[1]); pos = GetFloat(pos, &Inst->PositionV[2]); if ((Game.GetVersion() & GAMESANANDREAS) == 0) { pos = GetFloat(pos, &Inst->ScaleV[0]); pos = GetFloat(pos, &Inst->ScaleV[1]); pos = GetFloat(pos, &Inst->ScaleV[2]); } pos = GetFloat(pos, &Inst->Rotation[0]); pos = GetFloat(pos, &Inst->Rotation[1]); pos = GetFloat(pos, &Inst->Rotation[2]); pos = GetFloat(pos, &Inst->Rotation[3]); Inst->MinDrawDist = NULL; Inst->MaxDrawDist = NULL; if ((Game.GetVersion() & GAMESANANDREAS) != 0) pos = GetInt(pos, &Inst->LOD); else Inst->LOD = -1; /* if (Inst->Name[0] == 'L' && Inst->Name[1] == 'O' && Inst->Name[2] == 'D') { Inst->isLOD = true; Inst->isIslandLOD = false; } else if (Inst->Name[6] == 'L' && Inst->Name[7] == 'O' && Inst->Name[8] == 'D') { Inst->isLOD = true; Inst->isIslandLOD = true; } else { Inst->isLOD = false; Inst->isIslandLOD = false; } */ AddInstance(Inst); Iv.push_back(Inst); /* We now have an object associated */ Inst->isLOD = Inst->Obj->isLOD; Inst->isIslandLOD = Inst->Obj->isIslandLOD; Inst->MaxDrawDist = new float[Inst->Obj->ObjCount]; Inst->MinDrawDist = new float[Inst->Obj->ObjCount]; for (i = 0; i < Inst->Obj->ObjCount; i++) { Inst->MaxDrawDist[i] = Inst->Obj->DrawDist[i]; Inst->MinDrawDist[i]=Inst->Obj->MinDrawDist[i]; } Index++; } } } Instance *CWorld::GetLOD(Instance *Inst, vector &Iv) { uint i; char LODname[64]; strcpy(LODname, Inst->Name); strncpy(LODname, "LOD", 3); for (i = 0; i < Iv.size(); i++) { if (strcmp(Iv[i]->Name, LODname) == 0) return Iv[i]; } return NULL; } void CWorld::AddInstancesFromFile(FILE *file, char *Name) { uint i, j; vector Instv; CWorldObj *op; DirEntry *Entry; FILE *bin; char BinName[32]; char EntryName[48]; int base; Index = 0; /* Plain file */ AddInstancesFromPlainFile(file, Instv); /* Binary file */ strcpy(BinName, Name); BinName[strlen(BinName)-4] = '\0'; strcat(BinName, "_STREAM"); i = 0; sprintf(EntryName, "%s%d.IPL", BinName, i++); while ((Entry = Directory.GetEntry(EntryName))) { bin = FileLoader.OpenFile(Entry); AddInstancesFromBinFile(bin, Instv); sprintf(EntryName, "%s%d.IPL", BinName, i++); } /* Build tree */ base = 0; for (i = 0; i < Instv.size(); i++) { Instance *ip = Instv[i]; if (!ip->Obj) cout << ip->Name << " " << ip->LOD << endl; op = ip->Obj; if (!(Game.GetVersion() & GAMESANANDREAS)) { if (ip->isLOD) ip->LODp = NULL; else ip->LODp = GetLOD(ip, Instv); } else { /* When Index == 0, we're at the beginning of a file */ if (ip->Index == 0) base = i; if (ip->LOD != -1) ip->LODp = Instv[base+ip->LOD]; else ip->LODp = NULL; } if (ip->LODp) for (j = 0; j < op->ObjCount; j++) ip->LODp->MinDrawDist[j] = ip->MaxDrawDist[j]; /* Give every object its dff and txd */ if (op->Clump == NULL) { op->DffEntry = Directory.GetEntry(op->ModelName, ".DFF"); } if (op->TexDict == NULL) { op->TxdEntry = Directory.GetEntry(op->TextureName, ".TXD"); } } } /* CWorldObj *CWorld::GetLOD(CWorldObj *Obj) { CWorldObj *op; char LODName[64]; strcpy(LODName, Obj->ModelName); LODName[0] = 'L'; LODName[1] = 'O'; LODName[2] = 'D'; for (op = ObjList; op != NULL; op = op->next) { if (strcmp(op->ModelName, LODName) == 0) return op; } return NULL; } */ CWorldObj *CWorld::GetObjByID(int ID) { CWorldObj *op; for (op = ObjList; op != NULL; op = op->next) if (op->ID == ID) return op; return NULL; } void CWorld::AddObj(CWorldObj *Obj) { Obj->next = ObjList; ObjList = Obj; } void CWorld::AddObjsFromFile(FILE *file) { int i; char buffer[512]; char TexName[48]; char *pos; int BlockType; CWorldObj *Obj; // C2dfx Twodfx; DirEntry *Entry; BlockType = 0; while (ReadConfigLine(file, buffer) != NULL) { if (strcmp(buffer, "objs") == 0) { BlockType = OBJS; continue; } if (strcmp(buffer, "tobj") == 0) { BlockType = TOBJ; continue; } if (strcmp(buffer, "path") == 0) { BlockType = PATH; continue; } if (strcmp(buffer, "2dfx") == 0) { BlockType = TWODFX; continue; } if (strcmp(buffer, "anim") == 0) { BlockType = ANIM; continue; } if (strcmp(buffer, "txdp") == 0) { BlockType = TXDP; continue; } if (strcmp(buffer, "end") == 0) { BlockType = END; continue; } if (BlockType == OBJS || BlockType == TOBJ || BlockType == ANIM) { Obj = new CWorldObj; pos = buffer; pos = GetInt(pos, &Obj->ID); pos = GetWordUp(pos, Obj->ModelName); if (Obj->ModelName[0] == 'L' && Obj->ModelName[1] == 'O' && Obj->ModelName[2] == 'D') { Obj->isLOD = true; Obj->isIslandLOD = false; } else if (Obj->ModelName[6] == 'L' && Obj->ModelName[7] == 'O' && Obj->ModelName[8] == 'D') { Obj->isLOD = true; Obj->isIslandLOD = true; } else { Obj->isLOD = false; Obj->isIslandLOD = false; } pos = GetWordUp(pos, Obj->TextureName); if (BlockType == ANIM) pos = GetWordUp(pos, Obj->AnimName); if (!(Game.GetVersion() & GAMESANANDREAS)) pos = GetInt(pos, &Obj->ObjCount); else Obj->ObjCount = 1; Obj->DrawDist = new float[Obj->ObjCount]; Obj->MinDrawDist = new float[Obj->ObjCount]; for (i = 0; i < Obj->ObjCount; i++) { pos = GetFloat(pos, &Obj->DrawDist[i]); Obj->MinDrawDist[i] = 0; /* Assume a minimum distance of 60 for LODs */ if (Obj->isLOD) Obj->MinDrawDist[i] = 60; } pos = GetInt(pos, &Obj->Flags); if (BlockType == TOBJ) { pos = GetInt(pos, &Obj->TimeOn); pos = GetInt(pos, &Obj->TimeOff); Obj->isTimed = true; } else { Obj->isTimed = false; } Obj->BSphere[0] = 0; Obj->BSphere[1] = 0; Obj->BSphere[2] = 0; Obj->BSphere[3] = 0; Obj->Clump = NULL; Obj->TexDict = NULL; Obj->next = NULL; Obj->InstList = NULL; AddObj(Obj); Obj = NULL; } else if (BlockType == TXDP) { pos = buffer; pos = GetWordUp(pos, TexName); Entry = Directory.GetEntry(TexName, ".TXD"); pos = GetWordUp(pos, TexName); if (Entry != NULL) Entry->Parent = Directory.GetEntry(TexName, ".TXD"); } /* else if (BlockType == TWODFX) { pos = buffer; pos = GetInt(pos, &Twodfx.ID); pos = GetFloat(pos, &Twodfx.PositionV[0]); pos = GetFloat(pos, &Twodfx.PositionV[1]); pos = GetFloat(pos, &Twodfx.PositionV[2]); pos = GetRGBA(pos, Twodfx.Color); pos = GetInt(pos, &Twodfx.Type); if (Twodfx.Type != 0) continue; pos = GetQuotedWordUp(pos, Twodfx.CoronaTexture); pos = GetQuotedWordUp(pos, Twodfx.ShadowTexture); pos = GetInt(pos, &Twodfx.DrawDist); pos = GetInt(pos, &Twodfx.outer_range); pos = GetInt(pos, &Twodfx.lamp_size); pos = GetInt(pos, &Twodfx.inner_range); pos = GetInt(pos, &Twodfx.corona_size); pos = GetInt(pos, &Twodfx.control); pos = GetInt(pos, &Twodfx.reflection_on_wet_roads); pos = GetInt(pos, &Twodfx.lensflare); pos = GetInt(pos, &Twodfx.dust); FxList.push_back(Twodfx); } */ } } void CWorld::DumpObjs() { CWorldObj *op; Instance *ip; for (op = ObjList; op != NULL; op = op->next) { cout << op->ModelName << " "; cout << op->DrawDist[0] << endl; for (ip = op->InstList; ip != NULL; ip = ip->next) { cout << " " << ip->Name << endl; } } } void CWorld::SetInterior(int i) { Interior = i; } int CWorld::GetInterior() { return Interior; } void CWorld::SetLODmultiplier(float m) { LODmultiplier = m; } float CWorld::GetLODmultiplier() { return LODmultiplier; }