2013-07-01 02:22:29 +02:00
|
|
|
#define GLEW_STATIC
|
|
|
|
#include <GL/glew.h>
|
|
|
|
|
2013-07-02 08:40:43 +02:00
|
|
|
#include <renderwure/engine/GTAEngine.hpp>
|
|
|
|
#include <renderwure/loaders/LoaderDFF.hpp>
|
2013-07-01 02:22:29 +02:00
|
|
|
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
|
|
|
|
#include <SFML/Graphics.hpp>
|
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
#include <memory>
|
|
|
|
|
2013-07-01 02:22:29 +02:00
|
|
|
constexpr int WIDTH = 800,
|
|
|
|
HEIGHT = 600;
|
|
|
|
|
2013-07-02 00:16:02 +02:00
|
|
|
constexpr double PiOver180 = 3.1415926535897932384626433832795028/180;
|
|
|
|
|
2013-07-01 02:22:29 +02:00
|
|
|
sf::Window window;
|
|
|
|
|
|
|
|
const char *vertexShaderSource = "#version 130\n"
|
|
|
|
"in vec3 position;"
|
2013-07-01 05:40:11 +02:00
|
|
|
"in vec2 texCoords;"
|
|
|
|
"out vec2 TexCoords;"
|
2013-07-01 02:22:29 +02:00
|
|
|
"uniform mat4 model;"
|
|
|
|
"uniform mat4 view;"
|
|
|
|
"uniform mat4 proj;"
|
|
|
|
"void main()"
|
|
|
|
"{"
|
2013-07-01 05:40:11 +02:00
|
|
|
" TexCoords = texCoords;"
|
|
|
|
" gl_Position = proj * view * model * vec4(position, 1.0);"
|
2013-07-01 02:22:29 +02:00
|
|
|
"}";
|
|
|
|
const char *fragmentShaderSource = "#version 130\n"
|
2013-07-01 05:40:11 +02:00
|
|
|
"in vec2 TexCoords;"
|
|
|
|
"uniform sampler2D texture;"
|
2013-07-01 02:22:29 +02:00
|
|
|
"void main()"
|
|
|
|
"{"
|
2013-07-02 04:51:59 +02:00
|
|
|
" vec4 c = texture2D(texture, TexCoords);"
|
|
|
|
" if(c.a < 0.9) discard;"
|
|
|
|
" gl_FragColor = c;"
|
2013-07-01 02:22:29 +02:00
|
|
|
"}";
|
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
GLuint uniModel, uniProj, uniView;
|
|
|
|
GLuint posAttrib, texAttrib;
|
|
|
|
|
|
|
|
LoaderDFF dffLoader;
|
2013-07-02 08:06:03 +02:00
|
|
|
GTAEngine* gta = nullptr;
|
2013-07-01 05:40:11 +02:00
|
|
|
|
2013-07-01 05:54:03 +02:00
|
|
|
glm::vec3 selectedModelCenter;
|
2013-07-01 05:40:11 +02:00
|
|
|
|
2013-07-02 00:16:02 +02:00
|
|
|
glm::vec3 plyPos;
|
|
|
|
glm::vec2 plyLook;
|
|
|
|
|
2013-07-01 02:22:29 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
void init(std::string gtapath)
|
2013-07-01 02:22:29 +02:00
|
|
|
{
|
|
|
|
glClearColor(0.2, 0.2, 0.2, 1.0);
|
2013-07-01 05:40:11 +02:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
2013-07-01 02:22:29 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
posAttrib = glGetAttribLocation(shaderProgram, "position");
|
2013-07-01 05:40:11 +02:00
|
|
|
texAttrib = glGetAttribLocation(shaderProgram, "texCoords");
|
2013-07-01 02:22:29 +02:00
|
|
|
|
|
|
|
uniModel = glGetUniformLocation(shaderProgram, "model");
|
|
|
|
uniView = glGetUniformLocation(shaderProgram, "view");
|
|
|
|
uniProj = glGetUniformLocation(shaderProgram, "proj");
|
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
glm::mat4 proj = glm::perspective(80.f, (float) WIDTH/HEIGHT, 0.1f, 5000.f);
|
|
|
|
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(proj));
|
2013-07-02 08:06:03 +02:00
|
|
|
|
|
|
|
// GTA GET
|
|
|
|
gta = new GTAEngine(gtapath);
|
|
|
|
|
|
|
|
// This is harcoded in GTA III for some reason
|
|
|
|
gta->gameData.loadIMG("/models/gta3");
|
|
|
|
|
|
|
|
gta->load();
|
|
|
|
|
|
|
|
// Test out a known IPL.
|
|
|
|
gta->loadItems(gtapath + "/data/maps/industsw/industSW.ipl");
|
|
|
|
//gta->loadItems(gtapath + "/data/maps/industnw/industNW.ipl");
|
|
|
|
//gta->loadItems(gtapath + "/data/maps/industse/industSE.ipl");
|
|
|
|
//gta->loadItems(gtapath + "/data/maps/industne/industNE.ipl");
|
|
|
|
|
|
|
|
plyPos = gta->itemCentroid / (float) gta->instances.size();
|
2013-07-01 02:22:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void update()
|
|
|
|
{
|
2013-07-02 00:16:02 +02:00
|
|
|
float dt = 1.0/60.0; // we'll be fine
|
2013-07-01 02:22:29 +02:00
|
|
|
static int i = 0;
|
2013-07-02 00:16:02 +02:00
|
|
|
constexpr float moveSpeed = 20;
|
|
|
|
|
|
|
|
sf::Vector2i screenCenter{sf::Vector2i{window.getSize()} / 2};
|
|
|
|
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
|
|
sf::Vector2i deltaMouse = mousePos - screenCenter;
|
|
|
|
sf::Mouse::setPosition(screenCenter, window);
|
|
|
|
|
|
|
|
plyLook.x += deltaMouse.x / 10.0;
|
|
|
|
plyLook.y += deltaMouse.y / 10.0;
|
|
|
|
|
|
|
|
if (plyLook.y > 90)
|
|
|
|
plyLook.y = 90;
|
|
|
|
else if (plyLook.y < -90)
|
|
|
|
plyLook.y = -90;
|
|
|
|
|
|
|
|
bool doMove = false;
|
|
|
|
int direction = 1;
|
|
|
|
int strafeDirection = 0;
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
|
|
|
doMove = true;
|
|
|
|
}
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
|
|
|
doMove = true;
|
|
|
|
direction = -1;
|
|
|
|
}
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
|
|
|
|
doMove = true;
|
|
|
|
strafeDirection = -1;
|
|
|
|
}
|
|
|
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
|
|
|
|
doMove = true;
|
|
|
|
strafeDirection = 1;
|
|
|
|
}
|
|
|
|
if (doMove) {
|
|
|
|
plyPos += dt * moveSpeed * direction * glm::vec3{
|
|
|
|
sin((plyLook.x + 90*strafeDirection) * PiOver180),
|
|
|
|
cos((plyLook.x + 90*strafeDirection) * PiOver180),
|
|
|
|
-sin(plyLook.y * PiOver180),
|
|
|
|
};
|
|
|
|
}
|
2013-07-01 02:22:29 +02:00
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
glm::mat4 view;
|
2013-07-02 00:16:02 +02:00
|
|
|
view = glm::rotate(view, -90.f, glm::vec3(1, 0, 0));
|
|
|
|
view = glm::rotate(view, plyLook.y, glm::vec3(1, 0, 0));
|
|
|
|
view = glm::rotate(view, plyLook.x, glm::vec3(0, 0, 1));
|
|
|
|
view = glm::translate(view, -plyPos);
|
2013-07-01 05:40:11 +02:00
|
|
|
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(view));
|
2013-07-01 02:22:29 +02:00
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void render()
|
|
|
|
{
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
2013-07-02 08:06:03 +02:00
|
|
|
|
|
|
|
auto& textureLoader = gta->gameData.textureLoader;
|
2013-07-01 02:22:29 +02:00
|
|
|
|
2013-07-02 08:06:03 +02:00
|
|
|
for (size_t i = 0; i < gta->instances.size(); ++i) {
|
|
|
|
auto &obj = gta->instances[i];
|
2013-07-01 05:40:11 +02:00
|
|
|
std::string modelname = obj.model;
|
|
|
|
if (modelname.substr(0, 3) == "LOD")
|
|
|
|
continue;
|
2013-07-02 08:06:03 +02:00
|
|
|
auto &model = gta->gameData.models[modelname];
|
2013-07-01 05:40:11 +02:00
|
|
|
// std::cout << "Rendering " << modelname << std::endl;
|
2013-07-02 08:06:03 +02:00
|
|
|
|
|
|
|
if(!model)
|
|
|
|
{
|
|
|
|
std::cout << "model " << modelname << " not there (" << gta->gameData.models.size() << " models loaded)" << std::endl;
|
|
|
|
}
|
2013-07-01 05:40:11 +02:00
|
|
|
|
|
|
|
for (size_t g = 0; g < model->geometries.size(); g++) {
|
2013-07-01 02:22:29 +02:00
|
|
|
|
2013-07-01 21:52:09 +02:00
|
|
|
// This is a hack I have no idea why negating the quaternion fixes the issue but it does.
|
|
|
|
glm::quat rot(-obj.rotW, obj.rotX, obj.rotY, obj.rotZ);
|
2013-07-01 05:40:11 +02:00
|
|
|
glm::mat4 matrixModel;
|
2013-07-01 21:52:09 +02:00
|
|
|
matrixModel = glm::translate(matrixModel, glm::vec3(obj.posX, obj.posY, obj.posZ));
|
2013-07-01 05:40:11 +02:00
|
|
|
matrixModel = glm::scale(matrixModel, glm::vec3(obj.scaleX, obj.scaleY, obj.scaleZ));
|
2013-07-01 21:52:09 +02:00
|
|
|
matrixModel = matrixModel * glm::mat4_cast(rot);
|
2013-07-01 05:40:11 +02:00
|
|
|
glUniformMatrix4fv(uniModel, 1, GL_FALSE, glm::value_ptr(matrixModel));
|
2013-07-02 03:44:08 +02:00
|
|
|
|
2013-07-01 05:40:11 +02:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, model->geometries[g].VBO);
|
|
|
|
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
2013-07-01 23:16:47 +02:00
|
|
|
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)(model->geometries[g].vertices.size() * sizeof(float) * 3));
|
2013-07-01 05:40:11 +02:00
|
|
|
glEnableVertexAttribArray(posAttrib);
|
|
|
|
glEnableVertexAttribArray(texAttrib);
|
2013-07-02 03:44:08 +02:00
|
|
|
|
|
|
|
for(size_t sg = 0; sg < model->geometries[g].subgeom.size(); ++sg)
|
|
|
|
{
|
|
|
|
if (model->geometries[g].materials.size() > model->geometries[g].subgeom[sg].material) {
|
|
|
|
// std::cout << model->geometries[g].textures.size() << std::endl;
|
|
|
|
// std::cout << "Looking for " << model->geometries[g].textures[0].name << std::endl;
|
|
|
|
if(model->geometries[g].materials[model->geometries[g].subgeom[sg].material].textures.size() > 0) {
|
|
|
|
textureLoader.bindTexture(model->geometries[g].materials[model->geometries[g].subgeom[sg].material].textures[0].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->geometries[g].subgeom[sg].EBO);
|
2013-07-01 05:40:11 +02:00
|
|
|
|
2013-07-02 03:44:08 +02:00
|
|
|
glDrawElements(GL_TRIANGLES, model->geometries[g].subgeom[sg].indices.size(), GL_UNSIGNED_INT, NULL);
|
|
|
|
}
|
2013-07-01 05:40:11 +02:00
|
|
|
}
|
|
|
|
}
|
2013-07-01 02:22:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2013-07-01 05:40:11 +02:00
|
|
|
if (argc < 2) {
|
|
|
|
std::cout << "Usage: " << argv[0] << " <path to GTA3 root folder>" << std::endl;
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2013-07-01 02:22:29 +02:00
|
|
|
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;
|
|
|
|
}
|