OpenGTA/read_gry.cpp
2018-09-23 10:57:34 +05:00

1056 lines
38 KiB
C++
Executable File

/************************************************************************
* Copyright (c) 2005-2007 tok@openlinux.org.uk *
* *
* This file contains code derived from information copyrighted by *
* DMA Design. It may not be used in a commercial product. *
* *
* See license.txt for details. *
* *
* This notice may not be removed or altered. *
************************************************************************/
#include <iostream>
#include <cassert>
#include <sstream>
#include <algorithm>
#include "opengta.h"
#include "buffercache.h"
#include "log.h"
#include "m_exceptions.h"
#include "set.h"
using namespace Util;
namespace OpenGTA {
#define GTA_GRAPHICS_GRX 290
#define GTA_GRAPHICS_GRY 325
#define GTA_GRAPHICS_G24 336
PHYSFS_uint16 GraphicsBase::SpriteNumbers::countByType(const SpriteTypes & t) const {
switch (t) {
case ARROW:
return GTA_SPRITE_ARROW;
case DIGIT:
return GTA_SPRITE_DIGITS;
case BOAT:
return GTA_SPRITE_BOAT;
case BOX:
return GTA_SPRITE_BOX;
case BUS:
return GTA_SPRITE_BUS;
case CAR:
return GTA_SPRITE_CAR;
case OBJECT:
return GTA_SPRITE_OBJECT;
case PED:
return GTA_SPRITE_PED;
case SPEEDO:
return GTA_SPRITE_SPEEDO;
case TANK:
return GTA_SPRITE_TANK;
case TRAFFIC_LIGHT:
return GTA_SPRITE_TRAFFIC_LIGHTS;
case TRAIN:
return GTA_SPRITE_TRAIN;
case TRDOOR:
return GTA_SPRITE_TRDOORS;
case BIKE:
return GTA_SPRITE_BIKE;
case TRAM:
return GTA_SPRITE_TRAM;
case WBUS:
return GTA_SPRITE_WBUS;
case WCAR:
return GTA_SPRITE_WCAR;
case EX:
return GTA_SPRITE_EX;
case TUMCAR:
return GTA_SPRITE_TUMCAR;
case TUMTRUCK:
return GTA_SPRITE_TUMTRUCK;
case FERRY:
return GTA_SPRITE_FERRY;
default:
break;
}
INFO << "UPS: " << t << std::endl;
assert(0);
}
PHYSFS_uint16 GraphicsBase::SpriteNumbers::reIndex(const PHYSFS_uint16 & id, const SpriteTypes & t) const {
switch (t) {
case ARROW:
return id;
case DIGIT:
return GTA_SPRITE_ARROW + id;
case BOAT:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + id;
case BOX:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT + id;
case BUS:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + id;
case CAR:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + id;
case OBJECT:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + id;
case PED:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ id;
case SPEEDO:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + id;
case TANK:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + id;
case TRAFFIC_LIGHT:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK + id;
case TRAIN:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + id;
case TRDOOR:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + id;
case BIKE:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS + id;
case TRAM:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + id;
case WBUS:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + id;
case WCAR:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + GTA_SPRITE_WBUS + id;
case EX:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + GTA_SPRITE_WBUS + GTA_SPRITE_WCAR + id;
case TUMCAR:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + GTA_SPRITE_WBUS + GTA_SPRITE_WCAR +
GTA_SPRITE_TUMCAR + id;
case TUMTRUCK:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + GTA_SPRITE_WBUS + GTA_SPRITE_WCAR +
GTA_SPRITE_TUMCAR + GTA_SPRITE_TUMCAR + id;
case FERRY:
return GTA_SPRITE_ARROW + GTA_SPRITE_DIGITS + GTA_SPRITE_BOAT +
GTA_SPRITE_BOX + GTA_SPRITE_BUS + GTA_SPRITE_CAR + GTA_SPRITE_OBJECT
+ GTA_SPRITE_PED + GTA_SPRITE_SPEEDO + GTA_SPRITE_TANK +
+ GTA_SPRITE_TRAFFIC_LIGHTS + GTA_SPRITE_TRAIN + GTA_SPRITE_TRDOORS +
GTA_SPRITE_BIKE + GTA_SPRITE_TRAM + GTA_SPRITE_WBUS + GTA_SPRITE_WCAR +
GTA_SPRITE_TUMCAR + GTA_SPRITE_TUMCAR + GTA_SPRITE_TUMTRUCK + id;
}
assert(0); // should never be reached
return 0;
}
GraphicsBase::GraphicsBase() : sideTexBlockMove(256) {
rawTiles = NULL;
rawSprites = NULL;
delta_is_a_set = false;
for (int i=0; i < 256; ++i)
sideTexBlockMove.set_item(i, true);
}
bool GraphicsBase::isBlockingSide(uint8_t id) {
return sideTexBlockMove.get_item(id);
}
void GraphicsBase::setupBlocking(const std::string & filename) {
// style001
sideTexBlockMove.set_item(10, false);
sideTexBlockMove.set_item(20, false);
sideTexBlockMove.set_item(97, false);
sideTexBlockMove.set_item(109, false);
sideTexBlockMove.set_item(110, false);
sideTexBlockMove.set_item(115, false);
sideTexBlockMove.set_item(116, false);
sideTexBlockMove.set_item(155, false);
sideTexBlockMove.set_item(156, false);
sideTexBlockMove.set_item(157, false);
sideTexBlockMove.set_item(158, false);
}
bool GraphicsBase::getDeltaHandling() {
return delta_is_a_set;
}
void GraphicsBase::setDeltaHandling(bool delta_as_set) {
delta_is_a_set = delta_as_set;
}
GraphicsBase::~GraphicsBase() {
if (fd)
PHYSFS_close(fd);
std::vector<LoadedAnim*>::iterator i = animations.begin();
while (i != animations.end()) {
delete *i;
i++;
}
animations.clear();
std::vector<SpriteInfo*>::iterator i2 = spriteInfos.begin();
while (i2 != spriteInfos.end()) {
delete *i2;
i2++;
}
spriteInfos.clear();
std::vector<ObjectInfo*>::iterator i3 = objectInfos.begin();
while (i3 != objectInfos.end()) {
delete *i3;
i3++;
}
objectInfos.clear();
std::vector<CarInfo*>::iterator i4 = carInfos.begin();
while (i4 != carInfos.end()) {
delete *i4;
i4++;
}
carInfos.clear();
if (rawTiles)
delete [] rawTiles;
if (rawSprites)
delete [] rawSprites;
}
bool GraphicsBase::isAnimatedBlock(uint8_t area_code, uint8_t id) {
std::vector<LoadedAnim*>::iterator i = animations.begin();
while (i != animations.end()) {
if ((*i)->which == area_code && (*i)->block == id)
return true;
++i;
}
return false;
}
GraphicsBase::CarInfo* GraphicsBase::findCarByModel(PHYSFS_uint8 model) {
std::vector<CarInfo*>::iterator i = carInfos.begin();
while (i != carInfos.end()) {
if ((*i)->model == model)
return *i;
++i;
}
//throw std::string("Failed to find car by model");
std::ostringstream o;
o << "Searching for car model " << int(model) << " failed";
throw E_UNKNOWNKEY(o.str());
return NULL;
}
unsigned int GraphicsBase::getRandomPedRemapNumber() {
return int(rand() * (1.0f / (1.0f + RAND_MAX)) *
(lastValidPedRemap - firstValidPedRemap) +
firstValidPedRemap);
}
unsigned int GraphicsBase::getPedRemapNumberType(unsigned int _type) {
ERROR << "not implemented"<< std::endl;
return _type;
}
uint8_t GraphicsBase::getFormat() {
if (_topHeaderSize == 52)
return 0;
else if (_topHeaderSize == 64)
return 1;
throw E_INVALIDFORMAT("graphics-base header size");
return 255;
}
Graphics8Bit::Graphics8Bit(const std::string& style) : GraphicsBase() {
fd = PHYSFS_openRead(style.c_str());
if (fd == NULL) {
std::string style2(style);
std::transform(style2.begin(), style2.end(), style2.begin(), tolower);
fd = PHYSFS_openRead(style2.c_str());
}
if (fd == NULL) {
//throw std::string("FileNotFound: ") + style;
std::ostringstream o;
o << style << " with error: " << SDL_GetError();
throw E_FILENOTFOUND(o.str());
}
_topHeaderSize = 52;
rawTiles = NULL;
rawSprites = NULL;
masterRGB = NULL;
auxBlockTrailSize = 0;
loadHeader();
setupBlocking(style);
firstValidPedRemap = 131;
lastValidPedRemap = 187;
}
Graphics8Bit::~Graphics8Bit() {
//if (rawSprites)
// delete [] rawSprites;
if (masterRGB)
delete masterRGB;
}
void Graphics8Bit::dump() {
uint32_t gs = sideSize + lidSize + auxSize;
INFO << "* graphics info *" << std::endl <<
gs << " bytes in " << gs / 65536 << " pages " << gs / 4096
<< " images" << std::endl <<
spriteInfos.size() << " sprites (" << spriteInfoSize <<") total: " <<
spriteGraphicsSize << " bytes" << std::endl <<
"sprite numbers: " << std::endl <<
spriteNumbers.GTA_SPRITE_ARROW << " arrows" << std::endl <<
spriteNumbers.GTA_SPRITE_DIGITS << " digits" << std::endl <<
spriteNumbers.GTA_SPRITE_BOAT << " boats" << std::endl <<
spriteNumbers.GTA_SPRITE_BOX << " boxes" << std::endl <<
spriteNumbers.GTA_SPRITE_BUS << " buses" << std::endl <<
spriteNumbers.GTA_SPRITE_CAR << " cars" << std::endl <<
spriteNumbers.GTA_SPRITE_OBJECT << " objects" << std::endl <<
spriteNumbers.GTA_SPRITE_PED << " peds" << std::endl <<
spriteNumbers.GTA_SPRITE_SPEEDO << " speedos" << std::endl <<
spriteNumbers.GTA_SPRITE_TANK << " tanks" << std::endl <<
spriteNumbers.GTA_SPRITE_TRAFFIC_LIGHTS << " traffic lights" << std::endl <<
spriteNumbers.GTA_SPRITE_TRAIN << " trains" << std::endl <<
spriteNumbers.GTA_SPRITE_TRDOORS << " train doors" << std::endl <<
spriteNumbers.GTA_SPRITE_BIKE << " bikes" << std::endl <<
spriteNumbers.GTA_SPRITE_TRAM << " trams" << std::endl <<
spriteNumbers.GTA_SPRITE_WBUS << " wbuses" << std::endl <<
spriteNumbers.GTA_SPRITE_WCAR << " wcars" << std::endl <<
spriteNumbers.GTA_SPRITE_EX << " exes"<< std::endl <<
spriteNumbers.GTA_SPRITE_TUMCAR << " tumcars" << std::endl <<
spriteNumbers.GTA_SPRITE_TUMTRUCK << " tumtrucks" << std::endl <<
spriteNumbers.GTA_SPRITE_FERRY << " ferries"<< std::endl <<
"#object-info: " << objectInfos.size() << " #car-info: " << carInfos.size() << std::endl;
}
void Graphics8Bit::loadHeader() {
PHYSFS_uint32 vc;
PHYSFS_readULE32(fd, &vc);
if(vc != GTA_GRAPHICS_GRY) {
ERROR << "graphics file specifies version " << vc <<
" instead of " << GTA_GRAPHICS_GRY << std::endl;
throw E_INVALIDFORMAT("8-bit loader failed");
return;
}
PHYSFS_readULE32(fd, &sideSize);
PHYSFS_readULE32(fd, &lidSize);
PHYSFS_readULE32(fd, &auxSize);
PHYSFS_readULE32(fd, &animSize);
PHYSFS_readULE32(fd, &paletteSize);
PHYSFS_readULE32(fd, &remapSize);
PHYSFS_readULE32(fd, &remapIndexSize);
PHYSFS_readULE32(fd, &objectInfoSize);
PHYSFS_readULE32(fd, &carInfoSize);
PHYSFS_readULE32(fd, &spriteInfoSize);
PHYSFS_readULE32(fd, &spriteGraphicsSize);
PHYSFS_readULE32(fd, &spriteNumberSize);
INFO << "Block textures: S " << sideSize / 4096 << " L " <<
lidSize / 4096 << " A " << auxSize / 4096 << std::endl;
if (sideSize % 4096 != 0) {
ERROR << "Side-Block texture size is not a multiple of 4096" << std::endl;
return;
}
if (lidSize % 4096 != 0) {
ERROR << "Lid-Block texture size is not a multiple of 4096" << std::endl;
return;
}
if (auxSize % 4096 != 0) {
ERROR << "Aux-Block texture size is not a multiple of 4096" << std::endl;
return;
}
PHYSFS_uint32 tmp = sideSize / 4096 + lidSize / 4096 + auxSize / 4096;
tmp = tmp % 4;
if (tmp) {
auxBlockTrailSize = (4 - tmp) * 4096;
INFO << "adjusting aux-block by " << auxBlockTrailSize << std::endl;
}
INFO << "Anim size: " << animSize << " palette size: " << paletteSize <<
" remap size: " << remapSize << " remap-index size: " << remapIndexSize << std::endl;
INFO << "Obj-info size: " << objectInfoSize << " car-size: " << carInfoSize <<
" sprite-info size: " << spriteInfoSize << " graphic size: " << spriteGraphicsSize <<
" numbers s: " << spriteNumberSize << std::endl;
if (spriteNumberSize != 42) {
ERROR << "spriteNumberSize is " << spriteNumberSize << " (should be 42)" << std::endl;
return;
}
loadTileTextures();
loadAnim();
loadPalette();
loadRemapTables();
loadRemapIndex();
loadObjectInfo();
loadCarInfo();
loadSpriteInfo();
loadSpriteGraphics();
loadSpriteNumbers();
dump();
}
void GraphicsBase::loadAnim() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize;
PHYSFS_seek(fd, st);
PHYSFS_uint8 numAnim;
PHYSFS_read(fd, static_cast<void*>(&numAnim), 1, 1);
for (int i=0; i<numAnim;i++) {
uint8_t block, which, speed, frameCount;
PHYSFS_read(fd, static_cast<void*>(&block), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&which), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&speed), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&frameCount), 1, 1);
LoadedAnim *animation = new LoadedAnim(frameCount);
animation->block = block;
animation->which = which;
animation->speed = speed;
animation->frameCount = frameCount;
if (animation->frameCount > 180) {
ERROR << "found animation with " << int(animation->frameCount)
<< " frames ???" << std::endl;
}
for (int j=0; j<animation->frameCount; j++) {
uint8_t val;
PHYSFS_read(fd, static_cast<void*>(&val), 1, 1);
animation->frame[j] = val;
//PHYSFS_read(fd, static_cast<void*>(&animations[i].frame[j]), 1, 1);
}
animations.push_back(animation);
}
}
void Graphics8Bit::loadPalette() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize;
PHYSFS_seek(fd, st);
if (masterRGB)
delete masterRGB;
masterRGB = new RGBPalette(fd);
}
void Graphics8Bit::loadRemapTables() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize;
PHYSFS_seek(fd, st);
PHYSFS_read(fd, static_cast<void*>(remapTables), 256, 256);
/*
for (int i=0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
std::cout << int(remapTables[i][j]) << " ";
}
std::cout << std::endl;
}*/
}
void Graphics8Bit::loadRemapIndex() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize;
PHYSFS_seek(fd, st);
PHYSFS_read(fd, static_cast<void*>(&remapIndex), 4, 256);
/*
std::cout << "LID remap tables" << std::endl;
for (int i=0; i<256; ++i) {
std::cout << i << ": " << int(remapIndex[i][0]) << ", " << int(remapIndex[i][1]) <<
", " << int(remapIndex[i][2]) << ", " << int(remapIndex[i][3]) << std::endl;
}*/
}
void GraphicsBase::loadObjectInfo_shared(PHYSFS_uint64 offset) {
PHYSFS_seek(fd, offset);
assert(objectInfoSize % 20 == 0);
int c = objectInfoSize / 20;
for (int i=0; i< c; i++) {
ObjectInfo *obj = new ObjectInfo();
PHYSFS_readULE32(fd, &obj->width);
PHYSFS_readULE32(fd, &obj->height);
PHYSFS_readULE32(fd, &obj->depth);
PHYSFS_readULE16(fd, &obj->sprNum);
PHYSFS_readULE16(fd, &obj->weight);
PHYSFS_readULE16(fd, &obj->aux);
PHYSFS_read(fd, static_cast<void*>(&obj->status), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&obj->numInto), 1, 1);
objectInfos.push_back(obj);
}
}
void Graphics8Bit::loadObjectInfo() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize;
loadObjectInfo_shared(st);
}
void GraphicsBase::loadCarInfo_shared(PHYSFS_uint64 offset) {
PHYSFS_seek(fd, offset);
//INFO << "starting at offset " << offset << std::endl;
PHYSFS_uint32 bytes_read = 0;
while (bytes_read < carInfoSize) {
//INFO << bytes_read << ": " << carInfoSize << std::endl;
CarInfo * car = new CarInfo();
PHYSFS_readSLE16(fd, &car->width);
PHYSFS_readSLE16(fd, &car->height);
PHYSFS_readSLE16(fd, &car->depth);
PHYSFS_readSLE16(fd, &car->sprNum);
PHYSFS_readSLE16(fd, &car->weightDescriptor);
PHYSFS_readSLE16(fd, &car->maxSpeed);
PHYSFS_readSLE16(fd, &car->minSpeed);
PHYSFS_readSLE16(fd, &car->acceleration);
PHYSFS_readSLE16(fd, &car->braking);
PHYSFS_readSLE16(fd, &car->grip);
PHYSFS_readSLE16(fd, &car->handling);
bytes_read += 2 * 11;
for (int i=0; i < 12; i++) {
PHYSFS_readSLE16(fd, &car->remap24[i].h);
PHYSFS_readSLE16(fd, &car->remap24[i].l);
PHYSFS_readSLE16(fd, &car->remap24[i].s);
}
bytes_read += 12 * 3 * 2;
for (int i=0; i < 12; i++) {
PHYSFS_read(fd, static_cast<void*>(&car->remap8[i]), 1, 1);
}
bytes_read += 12;
PHYSFS_read(fd, static_cast<void*>(&car->vtype), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->model), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->turning), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->damagable), 1, 1);
bytes_read += 4;
for (int i=0; i < 4; i++)
PHYSFS_readULE16(fd, &car->value[i]);
bytes_read += 4 * 2;
PHYSFS_read(fd, static_cast<void*>(&car->cx), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->cy), 1, 1);
PHYSFS_readULE32(fd, &car->moment);
bytes_read += 2 + 4;
PHYSFS_uint32 fixed_tmp;
PHYSFS_readULE32(fd, &fixed_tmp);
car->rbpMass = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->g1_Thrust = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->tyreAdhesionX = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->tyreAdhesionY = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->handBrakeFriction = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->footBrakeFriction = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->frontBrakeBias = float(fixed_tmp)/65536;
bytes_read += 7 * 4;
PHYSFS_readSLE16(fd, &car->turnRatio);
PHYSFS_readSLE16(fd, &car->driveWheelOffset);
PHYSFS_readSLE16(fd, &car->steeringWheelOffset);
bytes_read += 3 * 2;
PHYSFS_readULE32(fd, &fixed_tmp);
car->backEndSlideValue = float(fixed_tmp)/65536;
PHYSFS_readULE32(fd, &fixed_tmp);
car->handBrakeSlideValue = float(fixed_tmp)/65536;
bytes_read += 2 * 4;
PHYSFS_read(fd, static_cast<void*>(&car->convertible), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->engine), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->radio), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->horn), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->soundFunction), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&car->fastChangeFlag), 1, 1);
bytes_read += 6;
PHYSFS_readSLE16(fd, &car->numDoors);
bytes_read += 2;
if (car->numDoors > 2) {
WARN << "num-doors: " << car->numDoors << " > 2 ???" << std::endl;
car->numDoors = 0;
}
for (int i=0; i < car->numDoors; i++) {
PHYSFS_readSLE16(fd, &car->door[i].rpy);
PHYSFS_readSLE16(fd, &car->door[i].rpx);
PHYSFS_readSLE16(fd, &car->door[i].object);
PHYSFS_readSLE16(fd, &car->door[i].delta);
bytes_read += 4 * 2;
}
carInfos.push_back(car);
}
assert(bytes_read == carInfoSize);
}
void Graphics8Bit::loadCarInfo() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize + objectInfoSize;
loadCarInfo_shared(st);
}
void Graphics8Bit::loadSpriteInfo() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize + objectInfoSize + carInfoSize;
PHYSFS_seek(fd, st);
PHYSFS_uint8 v;
PHYSFS_uint32 w;
PHYSFS_uint32 _bytes_read = 0;
while (_bytes_read < spriteInfoSize) {
SpriteInfo *si = new SpriteInfo();
PHYSFS_read(fd, static_cast<void*>(&si->w), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&si->h), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&si->deltaCount), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&v), 1, 1);
PHYSFS_readULE16(fd, &si->size);
PHYSFS_readULE32(fd, &w);
_bytes_read += 10;
//si->ptr = reinterpret_cast<unsigned char*>(w);
si->page = w / 65536;
si->xoffset = (w % 65536) % 256;
si->yoffset = (w % 65536) / 256;
si->clut = 0;
/*
std::cout << int(si->w) << "," << int(si->h) << " = " << si->size << " deltas: " << int(si->deltaCount) <<
" at " << w << std::endl;
*/
// sanity check
if (v)
WARN << "Compression flag active in sprite!" << std::endl;
if (int(si->w) * int(si->h) != int(si->size)) {
ERROR << "Sprite info size mismatch: " << int(si->w) << "x" << int(si->h) <<
" != " << si->size << std::endl;
return;
}
if (si->deltaCount > 32) {
ERROR << "Delta count of sprite is " << si->deltaCount << std::endl;
return;
}
for (PHYSFS_uint8 j = 0; j < 33; ++j) {
si->delta[j].size = 0;
si->delta[j].ptr = 0;
if (si->deltaCount && (j < si->deltaCount)) {
//std::cout << "reading " << int(j) << std::endl;
PHYSFS_readULE16(fd, &si->delta[j].size);
PHYSFS_readULE32(fd, &w);
_bytes_read += 6;
si->delta[j].ptr = reinterpret_cast<unsigned char*>(w);
}
}
spriteInfos.push_back(si);
}
st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize + objectInfoSize + carInfoSize + spriteInfoSize;
assert(PHYSFS_tell(fd) == PHYSFS_sint64(st));
}
void Graphics8Bit::loadSpriteGraphics() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize + objectInfoSize + carInfoSize + spriteInfoSize;
PHYSFS_seek(fd, st);
rawSprites = new unsigned char[spriteGraphicsSize];
assert(rawSprites != NULL);
PHYSFS_read(fd, static_cast<void*>(rawSprites), spriteGraphicsSize, 1);
if (spriteInfos.size() == 0) {
INFO << "No SpriteInfo post-loading work done - structure is empty" << std::endl;
return;
}
std::vector<SpriteInfo*>::const_iterator i = spriteInfos.begin();
std::vector<SpriteInfo*>::const_iterator end = spriteInfos.end();
PHYSFS_uint32 _pagewise = 256 * 256;
while (i != end) {
SpriteInfo *info = *i;
/*
PHYSFS_uint32 offset = reinterpret_cast<PHYSFS_uint32>(info->ptr);
PHYSFS_uint32 page = offset / 65536;
PHYSFS_uint32 y = (offset % 65536) / 256;
PHYSFS_uint32 x = (offset % 65536) % 256;
*/
//std::cout << int(info->w) << "x" << int(info->h) << " " << int(info->deltaCount) << " deltas" << std::endl;
//std::cout << offset << " page " << page << " x,y " << x <<","<<y<< std::endl;
//info->ptr = rawSprites + page * _pagewise + 256 * y + x;
for (uint8_t k = 0; k < info->deltaCount; ++k) {
PHYSFS_uint32 offset = reinterpret_cast<PHYSFS_uint32>(info->delta[k].ptr);
PHYSFS_uint32 page = offset / 65536;
PHYSFS_uint32 y = (offset % 65536) / 256;
PHYSFS_uint32 x = (offset % 65536) % 256;
info->delta[k].ptr = rawSprites + page * _pagewise + 256 * y + x;
}
i++;
}
return;
}
void GraphicsBase::loadSpriteNumbers_shared(PHYSFS_uint64 offset) {
PHYSFS_seek(fd, offset);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_ARROW);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_DIGITS);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_BOAT);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_BOX);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_BUS);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_CAR);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_OBJECT);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_PED);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_SPEEDO);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TANK);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TRAFFIC_LIGHTS);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TRAIN);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TRDOORS);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_BIKE);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TRAM);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_WBUS);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_WCAR);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_EX);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TUMCAR);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_TUMTRUCK);
PHYSFS_readULE16(fd, &spriteNumbers.GTA_SPRITE_FERRY);
}
void Graphics8Bit::loadSpriteNumbers() {
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize + paletteSize +
remapSize + remapIndexSize + objectInfoSize + carInfoSize +
spriteInfoSize + spriteGraphicsSize;
loadSpriteNumbers_shared(st);
}
void GraphicsBase::loadTileTextures() {
PHYSFS_seek(fd, static_cast<PHYSFS_uint64>(_topHeaderSize));
PHYSFS_uint64 ts = sideSize+lidSize+auxSize;
rawTiles = new unsigned char[ts];
int r = PHYSFS_read(fd, static_cast<void*>(rawTiles), 1, ts);
if ( PHYSFS_uint64(r) == ts )
return;
else if ( r == -1) {
INFO << "Could not read texture raw data" << std::endl;
return;
}
else
INFO << "This message should never be displayed! (" << std::endl;
}
void GraphicsBase::handleDeltas(const SpriteInfo & info, unsigned char* buffer, Uint32 delta) {
const unsigned int b_offset = 256 * info.yoffset + info.xoffset;
if (delta_is_a_set) {
Util::Set delta_set(32, (unsigned char*)&delta);
for (int i = 0; i < 20; ++i) {
if (delta_set.get_item(i)) {
assert(i < info.deltaCount);
const DeltaInfo & di = info.delta[i];
applyDelta(info, buffer, b_offset, di);
}
}
for (int i=20; i < 24; i++) {
if (delta_set.get_item(i)) {
const DeltaInfo & di = info.delta[i - 20 + 6];
applyDelta(info, buffer, b_offset, di, true);
}
}
for (int i=24; i < 28; i++) {
if (delta_set.get_item(i)) {
const DeltaInfo & di = info.delta[i - 24 + 11];
applyDelta(info, buffer, b_offset, di, true);
}
}
//assert(0);
}
else {
// delta is only an index; one to big
assert(delta <= info.deltaCount);
const DeltaInfo & di = info.delta[delta - 1];
applyDelta(info, buffer, b_offset, di);
}
}
unsigned char* Graphics8Bit::getSpriteBitmap(size_t id, int remap = -1, Uint32 delta = 0) {
SpriteInfo *info = spriteInfos[id];
assert(info != NULL);
//PHYSFS_uint32 offset = reinterpret_cast<PHYSFS_uint32>(info->ptr);
//const PHYSFS_uint32 page = offset / 65536;
const PHYSFS_uint32 y = info->yoffset; // (offset % 65536) / 256;
const PHYSFS_uint32 x = info->xoffset; // (offset % 65536) % 256;
const PHYSFS_uint32 page_size = 256 * 256;
unsigned char * page_start = rawSprites + info->page * page_size;// + 256 * y + x;
assert(page_start != NULL);
BufferCache & bcache = BufferCacheHolder::Instance();
unsigned char * dest = bcache.requestBuffer(page_size);
bcache.lockBuffer(dest);
unsigned char * result = dest;
assert(dest != NULL);
memcpy(dest, page_start, page_size);
if (delta > 0) {
handleDeltas(*info, result, delta);
/*
assert(delta < info->deltaCount);
DeltaInfo & di = info->delta[delta];
applyDelta(*info, result+256*y+x, di);
*/
}
if (remap > -1)
applyRemap(page_size, remap, result);
unsigned char* bigbuf = bcache.requestBuffer(page_size * 4);
masterRGB->apply(page_size, result, bigbuf, true);
assert(page_size > PHYSFS_uint32(info->w * info->h * 4));
for (uint16_t i = 0; i < info->h; i++) {
memcpy(result, bigbuf+(256*y+x)*4, info->w * 4);
result += info->w * 4;
bigbuf += 256 * 4;
}
return dest;
}
void GraphicsBase::applyDelta(const SpriteInfo & spriteInfo, unsigned
char* buffer, Uint32 page_offset, const DeltaInfo & deltaInfo, bool mirror) {
unsigned char* b = buffer + page_offset;
unsigned char* delta = deltaInfo.ptr;
PHYSFS_sint32 length_to_go = deltaInfo.size;
if (mirror) {
PHYSFS_uint32 doff = 0;
while (length_to_go > 0) {
PHYSFS_uint16* offset = (PHYSFS_uint16*) delta;
doff += *offset;
delta += 2;
unsigned char this_length = *delta;
++delta;
PHYSFS_uint32 noff = page_offset + doff;
PHYSFS_uint32 _y = noff / 256 * 256;
PHYSFS_uint32 _x = doff % 256;
for (int i=0; i < this_length; i++)
*(buffer + _y + spriteInfo.xoffset + spriteInfo.w - _x - i - 1) = *(delta+i);
length_to_go -= (this_length + 3);
doff += this_length;
delta += this_length;
}
return;
}
while (length_to_go > 0) {
PHYSFS_uint16* offset = (PHYSFS_uint16*) delta;
b += *offset;
delta += 2;
unsigned char this_length = *delta;
++delta;
memcpy(b, delta, this_length);
b += this_length;
delta += this_length;
length_to_go -= (this_length + 3);
}
}
void Graphics8Bit::applyRemap(unsigned int len, unsigned int which, unsigned char* buffer) {
assert(buffer!=NULL);
unsigned char* t = buffer;
for (unsigned int i = 0; i < len; ++i) {
*t = remapTables[which][*t]; //FIXME: is this the right order? Is this correct at all?
t++;
}
}
void GraphicsBase::prepareSideTexture(unsigned int idx, unsigned char* dst) {
assert(dst!=NULL);
++idx;
assert(rawTiles);
unsigned char* rt = rawTiles + (idx / 4) * 4096 * 4 + (idx % 4) * 64;
for (int i=0; i<64; i++) {
memcpy(dst, rt, 64);
dst += 64;
rt += 64*4;
}
}
unsigned char* Graphics8Bit::getSide(unsigned int idx, unsigned int palIdx, bool rgba = false) {
prepareSideTexture(idx-1, reinterpret_cast<unsigned char*>(tileTmp));
unsigned char *res;
if (rgba) {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGBA), true);
res = reinterpret_cast<unsigned char*>(tileTmpRGBA);
}
else {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGB), false);
res = reinterpret_cast<unsigned char*>(tileTmpRGB);
}
return res;
}
void GraphicsBase::prepareLidTexture(unsigned int idx, unsigned char* dst) {
assert(dst!=NULL);
unsigned char* rt = rawTiles;
assert(rawTiles);
idx += sideSize / 4096 + 1; // FIXME: assumes partition == block end
rt += (idx / 4) * 4096 * 4 + (idx % 4) * 64;
for (int i=0; i<64; i++) {
memcpy(dst, rt, 64);
dst += 64;
rt += 64*4;
}
}
unsigned char *Graphics8Bit::getLid(unsigned int idx, unsigned int palIdx, bool rgba = false) {
prepareLidTexture(idx-1, reinterpret_cast<unsigned char*>(tileTmp));
if (palIdx > 0)
applyRemap(4096, palIdx, reinterpret_cast<unsigned char*>(tileTmp));
unsigned char *res;
if (rgba) {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGBA), true);
res = reinterpret_cast<unsigned char*>(tileTmpRGBA);
}
else {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGB), false);
res = reinterpret_cast<unsigned char*>(tileTmpRGB);
}
return res;
}
void GraphicsBase::prepareAuxTexture(unsigned int idx, unsigned char* dst) {
assert(dst!=NULL);
unsigned char* rt = rawTiles;
assert(rawTiles);
idx += (sideSize+lidSize)/4096 + 1; // FIXME: assumes partition == block end
rt += (idx / 4) * 4096 * 4 + (idx % 4) * 64;
for (int i=0; i<64; i++) {
memcpy(dst, rt, 64);
dst += 64;
rt += 64*4;
}
}
unsigned char* Graphics8Bit::getAux(unsigned int idx, unsigned int palIdx, bool rgba = false) {
prepareAuxTexture(idx-1, reinterpret_cast<unsigned char*>(tileTmp));
unsigned char *res;
if (rgba) {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGBA), true);
res = reinterpret_cast<unsigned char*>(tileTmpRGBA);
}
else {
masterRGB->apply(4096, reinterpret_cast<unsigned char*>(tileTmp),
reinterpret_cast<unsigned char*>(tileTmpRGB), false);
res = reinterpret_cast<unsigned char*>(tileTmpRGB);
}
return res;
}
unsigned char* GraphicsBase::getTmpBuffer(bool rgba = false) {
if (rgba)
return reinterpret_cast<unsigned char*>(tileTmpRGBA);
return reinterpret_cast<unsigned char*>(tileTmpRGB);
}
/* RGBPalette */
Graphics8Bit::RGBPalette::RGBPalette() {
}
Graphics8Bit::RGBPalette::RGBPalette(const std::string& palette) {
PHYSFS_file* fd = PHYSFS_openRead(palette.c_str());
if (fd == NULL) {
std::string pal2(palette);
transform(pal2.begin(), pal2.end(), pal2.begin(), tolower);
fd = PHYSFS_openRead(pal2.c_str());
}
if (!fd) {
std::ostringstream o;
o << palette << " with error: " << PHYSFS_getLastError();
throw E_FILENOTFOUND(o.str());
}
loadFromFile(fd);
}
Graphics8Bit::RGBPalette::RGBPalette(PHYSFS_file* fd) {
loadFromFile(fd);
}
int Graphics8Bit::RGBPalette::loadFromFile(PHYSFS_file* fd) {
PHYSFS_read(fd, static_cast<void*>(&data), 1, 256*3);
/*
int max_sum = 0;
for (int i = 1; i < 256; i+=3) {
int sum = int(data[i]) + int(data[i+1]) + int(data[i+2]);
if (sum > max_sum)
max_sum = sum;
}*/
return 0;
}
void Graphics8Bit::RGBPalette::apply(unsigned int len, const unsigned char* src,
unsigned char* dst, bool rgba ) {
for (unsigned int i = 0; i < len; i++) {
*dst = data[*src * 3 ]; ++dst;
*dst = data[*src * 3 + 1]; ++dst;
*dst = data[*src * 3 + 2]; ++dst;
if (rgba) {
if (*src == 0)
*dst = 0x00;
else
*dst = 0xff;
++dst;
}
++src;
}
}
}