mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 06:52:34 +02:00
Added simple DFF loader and model/map viewer prototype
This commit is contained in:
parent
1640d3b8c3
commit
6cf179069e
@ -3,3 +3,4 @@ project(gtfw)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++11")
|
||||
|
||||
add_subdirectory(datadump)
|
||||
add_subdirectory(viewer)
|
||||
|
126
framework/LoaderDFF.cpp
Normal file
126
framework/LoaderDFF.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "LoaderDFF.h"
|
||||
|
||||
#include "../framework/rwbinarystream.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void LoaderDFF::loadFromMemory(char *data)
|
||||
{
|
||||
RW::BinaryStreamSection root(data);
|
||||
|
||||
this->clump = root.readStructure<RW::BSClump>();
|
||||
|
||||
size_t dataI = 0;
|
||||
while (root.hasMoreData(dataI)) {
|
||||
auto sec = root.getNextChildSection(dataI);
|
||||
|
||||
switch (sec.header.id) {
|
||||
case RW::SID_GeometryList: {
|
||||
auto list = sec.readStructure<RW::BSGeometryList>();
|
||||
size_t gdataI = 0;
|
||||
while (sec.hasMoreData(gdataI)) {
|
||||
Geometry geometryStruct;
|
||||
auto item = sec.getNextChildSection(gdataI);
|
||||
|
||||
if (item.header.id == RW::SID_Geometry) {
|
||||
size_t dataI = 0, secI = 0;
|
||||
auto geometry = item.readStructure<RW::BSGeometry>();
|
||||
std::cout << " verts(" << geometry.numverts << ") tris(" << geometry.numtris << ")" << std::endl;
|
||||
item.getNextChildSection(secI);
|
||||
char *data = item.raw() + sizeof(RW::BSSectionHeader) + sizeof(RW::BSGeometry);
|
||||
|
||||
if (item.header.versionid < 0x1003FFFF)
|
||||
auto colors = readStructure<RW::BSGeometryColor>(data, dataI);
|
||||
|
||||
if (geometry.flags & RW::BSGeometry::VertexColors) {
|
||||
for (size_t v = 0; v < geometry.numverts; ++v) {
|
||||
readStructure<RW::BSColor>(data, dataI);
|
||||
}
|
||||
}
|
||||
|
||||
/** TEX COORDS **/
|
||||
if (geometry.flags & RW::BSGeometry::TexCoords1 || geometry.flags & RW::BSGeometry::TexCoords2) {
|
||||
for (size_t v = 0; v < geometry.numverts; ++v) {
|
||||
geometryStruct.texcoords.push_back(readStructure<RW::BSGeometryUV>(data, dataI));
|
||||
}
|
||||
}
|
||||
|
||||
/** INDICIES **/
|
||||
for (int j = 0; j < geometry.numtris; ++j) {
|
||||
geometryStruct.triangles.push_back(readStructure<RW::BSGeometryTriangle>(data, dataI));
|
||||
}
|
||||
|
||||
/** GEOMETRY BOUNDS **/
|
||||
geometryStruct.geometryBounds = readStructure<RW::BSGeometryBounds>(data, dataI);
|
||||
|
||||
/** VERTICES **/
|
||||
for (int v = 0; v < geometry.numverts; ++v) {
|
||||
geometryStruct.vertices.push_back(readStructure<RW::BSTVector3>(data, dataI));
|
||||
}
|
||||
|
||||
/** NORMALS **/
|
||||
if (geometry.flags & RW::BSGeometry::StoreNormals) {
|
||||
for (int n = 0; n < geometry.numverts; ++n) {
|
||||
geometryStruct.normals.push_back(readStructure<RW::BSTVector3>(data, dataI));
|
||||
}
|
||||
}
|
||||
|
||||
/** TEXTURES **/
|
||||
auto materiallistsec = item.getNextChildSection(secI);
|
||||
auto materialList = materiallistsec.readStructure<RW::BSMaterialList>();
|
||||
|
||||
// Skip over the per-material byte values that I don't know what do.
|
||||
dataI += sizeof(uint32_t) * materialList.nummaterials;
|
||||
|
||||
size_t matI = 0;
|
||||
materiallistsec.getNextChildSection(matI);
|
||||
|
||||
for (size_t m = 0; m < materialList.nummaterials; ++m) {
|
||||
auto materialsec = materiallistsec.getNextChildSection(matI);
|
||||
if (materialsec.header.id != RW::SID_Material)
|
||||
continue;
|
||||
|
||||
auto material = materialsec.readStructure<RW::BSMaterial>();
|
||||
|
||||
size_t texI = 0;
|
||||
materialsec.getNextChildSection(texI);
|
||||
|
||||
for (size_t t = 0; t < material.numtextures; ++t) {
|
||||
auto texsec = materialsec.getNextChildSection(texI);
|
||||
auto texture = texsec.readStructure<RW::BSTexture>();
|
||||
|
||||
std::string textureName, alphaName;
|
||||
size_t yetAnotherI = 0;
|
||||
texsec.getNextChildSection(yetAnotherI);
|
||||
|
||||
auto namesec = texsec.getNextChildSection(yetAnotherI);
|
||||
auto alphasec = texsec.getNextChildSection(yetAnotherI);
|
||||
|
||||
// The data is null terminated anyway.
|
||||
textureName = namesec.raw();
|
||||
alphaName = alphasec.raw();
|
||||
|
||||
geometryStruct.textures.push_back({textureName, alphaName});
|
||||
}
|
||||
}
|
||||
|
||||
// Add it
|
||||
geometries.push_back(geometryStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> T LoaderDFF::readStructure(char *data, size_t &dataI)
|
||||
{
|
||||
size_t originalOffset = dataI;
|
||||
dataI += sizeof(T);
|
||||
return *reinterpret_cast<T*>(data + originalOffset);
|
||||
}
|
||||
|
||||
RW::BSSectionHeader LoaderDFF::readHeader(char *data, size_t &dataI)
|
||||
{
|
||||
return readStructure<RW::BSSectionHeader>(data, dataI);
|
||||
}
|
35
framework/LoaderDFF.h
Normal file
35
framework/LoaderDFF.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "rwbinarystream.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class LoaderDFF
|
||||
{
|
||||
private:
|
||||
template<class T> T readStructure(char *data, size_t &dataI);
|
||||
RW::BSSectionHeader readHeader(char *data, size_t &dataI);
|
||||
|
||||
RW::BSClump clump;
|
||||
|
||||
public:
|
||||
void loadFromMemory(char *data);
|
||||
|
||||
struct Texture {
|
||||
std::string name;
|
||||
std::string alphaName;
|
||||
};
|
||||
struct Geometry {
|
||||
RW::BSGeometryBounds geometryBounds;
|
||||
|
||||
std::vector<RW::BSGeometryUV> texcoords;
|
||||
std::vector<RW::BSGeometryTriangle> triangles;
|
||||
std::vector<RW::BSTVector3> vertices;
|
||||
std::vector<RW::BSTVector3> normals;
|
||||
|
||||
std::vector<Texture> textures;
|
||||
};
|
||||
|
||||
std::vector<Geometry> geometries;
|
||||
};
|
5
viewer/CMakeLists.txt
Normal file
5
viewer/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
add_executable(viewer main.cpp ../framework/LoaderIPL.cpp ../framework/LoaderIMG.cpp ../framework/LoaderDFF.cpp)
|
||||
|
||||
target_link_libraries( viewer sfml-graphics sfml-window sfml-system GL GLEW )
|
||||
|
||||
install(TARGETS viewer RUNTIME DESTINATION bin)
|
230
viewer/main.cpp
Normal file
230
viewer/main.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "../framework/LoaderIPL.h"
|
||||
#include "../framework/LoaderIMG.h"
|
||||
#include "../framework/LoaderDFF.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
constexpr int WIDTH = 800,
|
||||
HEIGHT = 600;
|
||||
|
||||
sf::Window window;
|
||||
|
||||
const char *vertexShaderSource = "#version 130\n"
|
||||
"in vec3 position;"
|
||||
// "in vec2 texCoords;"
|
||||
// "out vec2 TexCoords;"
|
||||
"uniform mat4 model;"
|
||||
"uniform mat4 view;"
|
||||
"uniform mat4 proj;"
|
||||
"void main()"
|
||||
"{"
|
||||
// " TexCoords = texCoords;"
|
||||
" gl_Position = proj * model * vec4(position, 1.0);"
|
||||
"}";
|
||||
const char *fragmentShaderSource = "#version 130\n"
|
||||
// "in vec2 TexCoords;"
|
||||
// "uniform sampler2D texture;"
|
||||
"void main()"
|
||||
"{"
|
||||
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);"
|
||||
// " gl_FragColor = texture2D(texture, TexCoords);"
|
||||
"}";
|
||||
|
||||
GLuint compileShader(GLenum type, const char *source)
|
||||
{
|
||||
GLuint shader = glCreateShader(type);
|
||||
glShaderSource(shader, 1, &source, NULL);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
GLint len;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
|
||||
GLchar *buffer = new GLchar[len];
|
||||
glGetShaderInfoLog(shader, len, NULL, buffer);
|
||||
|
||||
std::cerr << "ERROR compiling shader: " << buffer << std::endl;
|
||||
delete[] buffer;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void handleEvent(sf::Event &event)
|
||||
{
|
||||
switch (event.type) {
|
||||
case sf::Event::KeyPressed:
|
||||
switch (event.key.code) {
|
||||
case sf::Keyboard::Escape:
|
||||
window.close();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint uniModel, uniProj, uniView;
|
||||
GLuint posAttrib;
|
||||
GLuint VBO, EBO;
|
||||
|
||||
LoaderDFF dffLoader;
|
||||
|
||||
LoaderDFF::Geometry *selectedGeometry;
|
||||
|
||||
void init(std::string filepath)
|
||||
{
|
||||
glClearColor(0.2, 0.2, 0.2, 1.0);
|
||||
// glEnable(GL_DEPTH_TEST);
|
||||
|
||||
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
||||
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
||||
GLuint shaderProgram = glCreateProgram();
|
||||
glAttachShader(shaderProgram, vertexShader);
|
||||
glAttachShader(shaderProgram, fragmentShader);
|
||||
glLinkProgram(shaderProgram);
|
||||
glUseProgram(shaderProgram);
|
||||
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenBuffers(1, &EBO);
|
||||
|
||||
posAttrib = glGetAttribLocation(shaderProgram, "position");
|
||||
GLuint texAttrib = glGetAttribLocation(shaderProgram, "texCoords");
|
||||
|
||||
uniModel = glGetUniformLocation(shaderProgram, "model");
|
||||
uniView = glGetUniformLocation(shaderProgram, "view");
|
||||
uniProj = glGetUniformLocation(shaderProgram, "proj");
|
||||
|
||||
LoaderIPL iplLoader;
|
||||
LoaderIMG imgLoader;
|
||||
|
||||
if (iplLoader.load(filepath)) {
|
||||
printf("IPL Loaded, size: %d\n", iplLoader.m_instances.size());
|
||||
|
||||
if (imgLoader.load("/home/iostream/.wine/drive_c/Program Files (x86)/Rockstar Games/GTAIII/models/gta3")) {
|
||||
std::string filename = iplLoader.m_instances[0].model + ".dff";
|
||||
std::cout << "Loading " << filename << std::endl;
|
||||
char *file = imgLoader.loadToMemory(filename);
|
||||
|
||||
dffLoader.loadFromMemory(file);
|
||||
|
||||
selectedGeometry = &dffLoader.geometries[0];
|
||||
/*
|
||||
for (int i = 0; i < 10; i++) {
|
||||
auto v = selectedGeometry->vertices[i];
|
||||
std::cout << v.x << ", " << v.y << ", " << v.z << std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
selectedGeometry->vertices.size() * 3 * sizeof(float),
|
||||
&selectedGeometry->vertices[0],
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
uint16_t indicies[selectedGeometry->triangles.size() * 3];
|
||||
size_t i = 0;
|
||||
for (auto &tri : selectedGeometry->triangles) {
|
||||
indicies[i] = tri.first;
|
||||
indicies[i + 1] = tri.second;
|
||||
indicies[i + 2] = tri.third;
|
||||
i += 3;
|
||||
}
|
||||
/*
|
||||
for (int i = 0; i < 8; i++) {
|
||||
glm::vec3 t{indicies[i*3], indicies[i*3 + 1], indicies[i*3 + 2]};
|
||||
auto v1 = selectedGeometry->vertices[t.x];
|
||||
auto v2 = selectedGeometry->vertices[t.y];
|
||||
auto v3 = selectedGeometry->vertices[t.z];
|
||||
std::cout << t.x << ", " << t.y << ", " << t.z << std::endl;
|
||||
std::cout << v1.x << ", " << v1.y << ", " << v1.z << std::endl;
|
||||
std::cout << v2.x << ", " << v2.y << ", " << v2.z << std::endl;
|
||||
std::cout << v3.x << ", " << v3.y << ", " << v3.z << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
*/
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
sizeof(indicies),
|
||||
indicies,
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
glm::mat4 proj = glm::perspective(80.f, (float) WIDTH/HEIGHT, 0.1f, 100.f);
|
||||
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
|
||||
} else {
|
||||
std::cerr << "IMG failed to load" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
for (size_t i = 0; i < iplLoader.m_instances.size(); ++i) {
|
||||
printf("IPL entry id: %d\n", iplLoader.m_instances[i].id);
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
printf("IPL failed to load.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
static int i = 0;
|
||||
|
||||
glm::mat4 model;
|
||||
model = glm::translate(model, glm::vec3(0, 0, -10.0));
|
||||
model = glm::rotate(model, 100.f, glm::vec3(1, 0, 0));
|
||||
model = glm::rotate(model, i*1.f, glm::vec3(0, 0, 1));
|
||||
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(model));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glEnableVertexAttribArray(posAttrib);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, selectedGeometry->triangles.size() * 3, GL_UNSIGNED_SHORT, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
glewExperimental = GL_TRUE;
|
||||
glewInit();
|
||||
|
||||
window.create(sf::VideoMode(WIDTH, HEIGHT), "GTA3 Viewer", sf::Style::Close);
|
||||
window.setVerticalSyncEnabled(true);
|
||||
|
||||
init(argv[1]);
|
||||
|
||||
while (window.isOpen()) {
|
||||
sf::Event event;
|
||||
while (window.pollEvent(event)) {
|
||||
handleEvent(event);
|
||||
}
|
||||
|
||||
update();
|
||||
|
||||
render();
|
||||
window.display();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user