1
0
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:
Timmy Sjöstedt 2013-07-01 02:22:29 +02:00
parent 1640d3b8c3
commit 6cf179069e
5 changed files with 397 additions and 0 deletions

View File

@ -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
View 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
View 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
View 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
View 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;
}