mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
Added new framework with BinaryStream and stuff and an example app
This commit is contained in:
parent
bea0f3e9bd
commit
3ba30764dc
@ -1,6 +1,11 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
project(gtfw)
|
project(gtfw)
|
||||||
|
|
||||||
SET(CMAKE_CXX_FLAGS "-g -std=c++11")
|
SET(CMAKE_CXX_FLAGS "-g -std=c++11")
|
||||||
|
|
||||||
add_subdirectory(datadump)
|
add_subdirectory(datadump)
|
||||||
add_subdirectory(viewer)
|
add_subdirectory(viewer)
|
||||||
|
|
||||||
|
add_subdirectory(framework2)
|
||||||
|
add_subdirectory(analyzer)
|
||||||
|
7
analyzer/CMakeLists.txt
Normal file
7
analyzer/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
add_executable(analyzer main.cpp)
|
||||||
|
|
||||||
|
include_directories(../framework2/include)
|
||||||
|
|
||||||
|
target_link_libraries( analyzer renderware sfml-graphics )
|
||||||
|
|
||||||
|
install(TARGETS analyzer RUNTIME DESTINATION bin)
|
77
analyzer/main.cpp
Normal file
77
analyzer/main.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <renderware/BinaryStream.hpp>
|
||||||
|
#include <renderware/TextureArchive.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::cout << std::showbase;
|
||||||
|
|
||||||
|
std::string gtapath = "/home/iostream/.wine/drive_c/Program Files (x86)/Rockstar Games/GTAIII/";
|
||||||
|
auto ojg = RW::BinaryStream::parse(gtapath +"/models/MISC.TXD");
|
||||||
|
// auto ojg = RW::BinaryStream::parse("OJG.TXD");
|
||||||
|
|
||||||
|
auto texture = RW::TextureArchive::create(*ojg);
|
||||||
|
|
||||||
|
std::cout << "Found " << texture->numTextures << " textures!" << std::endl;
|
||||||
|
sf::Image img;
|
||||||
|
for (size_t i = 0; i < texture->numTextures; i++) {
|
||||||
|
auto &tex = texture->textures[i];
|
||||||
|
std::cout << "Processing " << tex.header.diffuseName << std::endl;
|
||||||
|
|
||||||
|
img.create(tex.header.width, tex.header.height);
|
||||||
|
|
||||||
|
for (int j = 0; j < tex.header.width; j++) {
|
||||||
|
for (int i = 0; i < tex.header.width; i++) {
|
||||||
|
bool hasAlpha = (tex.header.rasterFormat & 0x0500) == 0x0500;
|
||||||
|
if (tex.header.rasterFormat & 0x2000) {
|
||||||
|
uint8_t pixelIndex = 4 * tex.body.pixels[j*tex.header.width + i];
|
||||||
|
|
||||||
|
img.setPixel(i, j, {
|
||||||
|
tex.body.palette[pixelIndex + 0],
|
||||||
|
tex.body.palette[pixelIndex + 1],
|
||||||
|
tex.body.palette[pixelIndex + 2],
|
||||||
|
(hasAlpha ? tex.body.palette[pixelIndex + 3] : static_cast<sf::Uint8>(255))
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uint8_t pixel = 4 * tex.body.pixels[j*tex.header.width + i];
|
||||||
|
img.setPixel(i, j, {
|
||||||
|
tex.body.pixels[pixel + 0],
|
||||||
|
tex.body.pixels[pixel + 1],
|
||||||
|
tex.body.pixels[pixel + 2],
|
||||||
|
tex.body.pixels[pixel + 3],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << tex.header.diffuseName << ".png";
|
||||||
|
img.saveToFile(ss.str());
|
||||||
|
|
||||||
|
size_t scaleUp = 8;
|
||||||
|
img.create(16*scaleUp, 16*scaleUp);
|
||||||
|
for (int j = 0; j < 16; j++) {
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
uint8_t pixelIndex = 4 * (j*16 + i);
|
||||||
|
|
||||||
|
for (int y = 0; y < scaleUp; y++) {
|
||||||
|
for (int x = 0; x < scaleUp; x++) {
|
||||||
|
img.setPixel((i*scaleUp)+x, (j*scaleUp)+y, {
|
||||||
|
tex.body.palette[pixelIndex + 0],
|
||||||
|
tex.body.palette[pixelIndex + 1],
|
||||||
|
tex.body.palette[pixelIndex + 2],
|
||||||
|
tex.body.palette[pixelIndex + 3],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.saveToFile("palette"+ ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
89
framework2/BinaryStream.cpp
Normal file
89
framework2/BinaryStream.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include <renderware/BinaryStream.hpp>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace RW
|
||||||
|
{
|
||||||
|
|
||||||
|
std::unique_ptr<BinaryStream> BinaryStream::parse(std::string filename)
|
||||||
|
{
|
||||||
|
std::ifstream dfile(filename);
|
||||||
|
if ( ! dfile.is_open()) {
|
||||||
|
std::cerr << "Error opening file " << filename << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfile.seekg(0, std::ios_base::end);
|
||||||
|
size_t length = dfile.tellg();
|
||||||
|
dfile.seekg(0);
|
||||||
|
char *data = new char[length];
|
||||||
|
dfile.read(data, length);
|
||||||
|
// std::cout << "File is " << length << " bytes" << std::endl << std::endl;
|
||||||
|
|
||||||
|
auto BS = std::unique_ptr<BinaryStream>(new BinaryStream);
|
||||||
|
|
||||||
|
// Set file's ACTUAL length
|
||||||
|
auto header = reinterpret_cast<nativeSectionHeader_t *>(data);
|
||||||
|
length = header->size + sizeof(nativeSectionHeader_t);
|
||||||
|
|
||||||
|
sectionHeader_t *prevHeader = nullptr;
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < length) {
|
||||||
|
nativeSectionHeader_t *sectionHeader = reinterpret_cast<nativeSectionHeader_t *>(data + offset);
|
||||||
|
sectionHeader_t *sec = new sectionHeader_t;
|
||||||
|
sec->ID = sectionHeader->ID;
|
||||||
|
sec->size = sectionHeader->size;
|
||||||
|
sec->version = sectionHeader->version;
|
||||||
|
if (prevHeader == nullptr)
|
||||||
|
BS->rootHeader = sec;
|
||||||
|
else
|
||||||
|
prevHeader->next = sec;
|
||||||
|
|
||||||
|
if (sectionHeader->ID == 0) {
|
||||||
|
std::cout << "Section ID is ZERO! Abort!" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Section " << std::hex << sectionHeader->ID
|
||||||
|
<< " (" << sectionIdString(sectionHeader->ID) << ")"
|
||||||
|
<< " - " << std::dec << sectionHeader->size << " bytes" << std::endl;
|
||||||
|
/*
|
||||||
|
std::cout << "Offset " << std::hex << offset << std::endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
size_t bytesOfData = 0;
|
||||||
|
switch (sectionHeader->ID) {
|
||||||
|
case STRUCT:
|
||||||
|
bytesOfData = sectionHeader->size;
|
||||||
|
sec->data = new uint8_t[bytesOfData];
|
||||||
|
memcpy(sec->data, data + offset + sizeof(nativeSectionHeader_t), bytesOfData);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// std::cout << "It has " << std::dec << bytesOfData << " bytes of data!" << std::endl;
|
||||||
|
offset += sizeof(nativeSectionHeader_t) + bytesOfData;
|
||||||
|
|
||||||
|
// std::cout << std::endl;
|
||||||
|
|
||||||
|
prevHeader = sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
return BS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BinaryStream::sectionIdString(uint32_t id)
|
||||||
|
{
|
||||||
|
switch (id) {
|
||||||
|
case STRUCT: return "STRUCT";
|
||||||
|
case EXTENSION: return "EXTENSION";
|
||||||
|
case TEXTURE_NATIVE: return "TEXTURE_NATIVE";
|
||||||
|
case TEXTURE_DICTIONARY: return "TEXTURE_DICTIONARY";
|
||||||
|
default: return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
3
framework2/CMakeLists.txt
Normal file
3
framework2/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
add_library(renderware BinaryStream.cpp TextureArchive.cpp )
|
||||||
|
|
||||||
|
include_directories(include)
|
50
framework2/TextureArchive.cpp
Normal file
50
framework2/TextureArchive.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <renderware/TextureArchive.hpp>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace RW
|
||||||
|
{
|
||||||
|
|
||||||
|
std::unique_ptr<TextureArchive> TextureArchive::create(BinaryStream &binaryStream)
|
||||||
|
{
|
||||||
|
auto textureArchive = std::unique_ptr<TextureArchive>(new TextureArchive);
|
||||||
|
|
||||||
|
auto section = binaryStream.rootHeader;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
section->ID == BinaryStream::TEXTURE_DICTIONARY
|
||||||
|
&& "BinaryStream passed to this function must be a TEXTURE DICTIONARY"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Struct
|
||||||
|
section = section->next;
|
||||||
|
textureArchive->numTextures = ((uint16_t *) section->data)[0];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < textureArchive->numTextures; i++) {
|
||||||
|
section = section->next; // Texture Native
|
||||||
|
section = section->next; // Struct
|
||||||
|
|
||||||
|
Texture texture = *reinterpret_cast<Texture *>(section->data);
|
||||||
|
|
||||||
|
if (texture.header.rasterFormat & 0x2000) {
|
||||||
|
memcpy(texture.body.palette, section->data + sizeof(TextureHeader), 1024);
|
||||||
|
|
||||||
|
texture.body.pixels = new uint8_t[texture.header.width * texture.header.height];
|
||||||
|
memcpy(texture.body.pixels, section->data + sizeof(TextureHeader) + 1024, texture.header.width * texture.header.height);
|
||||||
|
} else {
|
||||||
|
size_t bufSize = texture.header.width * texture.header.height * texture.header.bpp/8;
|
||||||
|
texture.body.pixels = new uint8_t[bufSize];
|
||||||
|
memcpy(texture.body.pixels, section->data + sizeof(TextureHeader), bufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
textureArchive->textures.push_back(texture);
|
||||||
|
|
||||||
|
section = section->next; // Extension
|
||||||
|
}
|
||||||
|
|
||||||
|
return textureArchive;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
framework2/include/renderware/BinaryStream.hpp
Normal file
40
framework2/include/renderware/BinaryStream.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace RW
|
||||||
|
{
|
||||||
|
|
||||||
|
class BinaryStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct nativeSectionHeader_t
|
||||||
|
{
|
||||||
|
uint32_t ID;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t version;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
STRUCT = 0x0001,
|
||||||
|
EXTENSION = 0x0003,
|
||||||
|
TEXTURE_NATIVE = 0x0015,
|
||||||
|
TEXTURE_DICTIONARY = 0x0016,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sectionHeader_t {
|
||||||
|
uint32_t ID;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
uint8_t *data = nullptr;
|
||||||
|
sectionHeader_t *next = nullptr;
|
||||||
|
} *rootHeader;
|
||||||
|
|
||||||
|
static std::unique_ptr<BinaryStream> parse(std::string filename);
|
||||||
|
|
||||||
|
static std::string sectionIdString(uint32_t id);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
46
framework2/include/renderware/TextureArchive.hpp
Normal file
46
framework2/include/renderware/TextureArchive.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <renderware/BinaryStream.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace RW
|
||||||
|
{
|
||||||
|
|
||||||
|
class TextureArchive
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct TextureHeader {
|
||||||
|
uint32_t platformID;
|
||||||
|
uint16_t filterFlags;
|
||||||
|
uint8_t textureWrapV;
|
||||||
|
uint8_t textureWrapU;
|
||||||
|
uint8_t diffuseName[32];
|
||||||
|
uint8_t alphaName[32];
|
||||||
|
uint32_t rasterFormat;
|
||||||
|
uint32_t alpha;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint8_t bpp;
|
||||||
|
uint8_t numMipmap;
|
||||||
|
uint8_t rasterType;
|
||||||
|
uint8_t compression;
|
||||||
|
uint32_t dataSize;
|
||||||
|
};
|
||||||
|
struct TextureBody {
|
||||||
|
uint8_t palette[1024];
|
||||||
|
uint8_t *pixels;
|
||||||
|
};
|
||||||
|
struct Texture {
|
||||||
|
TextureHeader header;
|
||||||
|
TextureBody body;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t numTextures;
|
||||||
|
std::vector<Texture> textures;
|
||||||
|
|
||||||
|
static std::unique_ptr<TextureArchive> create(BinaryStream &binaryStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user