1051 lines
41 KiB
C
1051 lines
41 KiB
C
// glad needs to be initialized before GLFW
|
|
#include <math.h>
|
|
#include <glad/glad.h>
|
|
#include <GLFW/glfw3.h>
|
|
#include <stdio.h>
|
|
#include <StormLib.h>
|
|
#include "logger/log.h"
|
|
#include "util.h"
|
|
#include "logger/gl_log.h"
|
|
#include "renderer/matrix.h"
|
|
#include "renderer/mesh.h"
|
|
#include "renderer/shader.h"
|
|
#include "renderer/vector.h"
|
|
#include "wmo/wmo.h"
|
|
#include "wmo/wmo_structs.h"
|
|
#include "renderer/texture.h"
|
|
|
|
|
|
|
|
// reported window size maybe good to know for a few things
|
|
int g_win_width = 640;
|
|
int g_win_height = 480;
|
|
// keep track of framebuffer size for things like the viewport and the mouse cursor
|
|
int g_fb_width = 640;
|
|
int g_fb_height = 480;
|
|
// time tracking
|
|
double previous_seconds;
|
|
int frame_count;
|
|
|
|
// function to update the window title with a frame rate
|
|
void _update_fps_counter(GLFWwindow* window) {
|
|
double current_seconds;
|
|
double elapsed_seconds;
|
|
current_seconds = glfwGetTime();
|
|
elapsed_seconds = current_seconds - previous_seconds;
|
|
/* limit text updates to 4 per second */
|
|
if (elapsed_seconds > 0.25) {
|
|
previous_seconds = current_seconds;
|
|
char tmp[128];
|
|
double fps = (double)frame_count / elapsed_seconds;
|
|
// 1000 / fps = expected ms per frame
|
|
// elapsed_seconds / frame_count * 1000 = time per frame in ms
|
|
sprintf(tmp, "opengl @ fps: %.2f time per frame in milliseconds: %.4f", fps,
|
|
((elapsed_seconds / frame_count) * 1000));
|
|
glfwSetWindowTitle(window, tmp);
|
|
frame_count = 0;
|
|
}
|
|
frame_count++;
|
|
}
|
|
|
|
// clears stdin buffer, trailing '\n' causes issues when using scanf_s() and fgets() for file name parsing
|
|
void clear_input_buffer() {
|
|
int c;
|
|
while ((c = getchar()) != '\n' && c != EOF);
|
|
}
|
|
|
|
void glfw_error_callback(int error, const char *description) {
|
|
gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
|
|
log_error("GLFW ERROR: code %i msg: %s", error, description);
|
|
}
|
|
|
|
void glfw_window_size_callback(GLFWwindow* window, int width, int height) {
|
|
g_win_width = width;
|
|
g_win_height = height;
|
|
gl_log("Window Resolution changed: width: %d, height: %d\n");
|
|
}
|
|
|
|
void glfw_framebuffer_resize_callback(GLFWwindow* window, int width, int height) {
|
|
g_fb_width = width;
|
|
g_fb_height = height;
|
|
gl_log("Framebuffer resized: width: %d, height: %d\n");
|
|
|
|
// TODO: update any perspective matrices used here
|
|
//mat4_make_perspective(67 * ONE_DEG_IN_RAD, g_fb_width/g_fb_height, 1.0f, 100.0f);
|
|
}
|
|
|
|
const char *GL_type_to_string(GLenum type) {
|
|
switch (type) {
|
|
case GL_BOOL: return "bool";
|
|
case GL_INT: return "int";
|
|
case GL_FLOAT: return "float";
|
|
case GL_FLOAT_VEC2: return "vec2";
|
|
case GL_FLOAT_VEC3: return "vec3";
|
|
case GL_FLOAT_VEC4: return "vec4";
|
|
case GL_FLOAT_MAT2: return "mat2";
|
|
case GL_FLOAT_MAT3: return "mat3";
|
|
case GL_FLOAT_MAT4: return "mat4";
|
|
case GL_SAMPLER_2D: return "sampler2D";
|
|
case GL_SAMPLER_3D: return "sampler3D";
|
|
case GL_SAMPLER_CUBE: return "samplerCube";
|
|
case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
|
|
default: break;
|
|
}
|
|
return "other";
|
|
}
|
|
|
|
void _print_shader_info_log(GLuint shader_index) {
|
|
int max_length = 2048;
|
|
int actual_length = 0;
|
|
char log[2048];
|
|
glGetShaderInfoLog(shader_index, max_length, &actual_length, log);
|
|
printf("shader info log for GL index %u:\n%s\n", shader_index, log);
|
|
}
|
|
|
|
void _print_programme_info_log(GLuint programme) {
|
|
int max_length = 2048;
|
|
int actual_length = 0;
|
|
char log[2048];
|
|
glGetProgramInfoLog(programme, max_length, &actual_length, log);
|
|
log_info("program info log for GL index %u:\n%s", programme, log);
|
|
}
|
|
|
|
void print_all(GLuint programme) {
|
|
log_info("--------------------\nshader programme %i info:", programme);
|
|
int params = -1;
|
|
glGetProgramiv(programme, GL_LINK_STATUS, ¶ms);
|
|
log_info("GL_LINK_STATUS = %i", params);
|
|
|
|
glGetProgramiv(programme, GL_ATTACHED_SHADERS, ¶ms);
|
|
log_info("GL_ATTACHED_SHADERS = %i", params);
|
|
for (GLuint i = 0; i < (GLuint)params; i++) {
|
|
char name[64];
|
|
int max_length = 64;
|
|
int actual_length = 0;
|
|
int size = 0;
|
|
GLenum type;
|
|
glGetActiveAttrib(programme, i, max_length, &actual_length, &size, &type, name);
|
|
if (size > 1) {
|
|
for (int j = 0; j < size; j++) {
|
|
char long_name[64];
|
|
sprintf(long_name, "%s[%i]", name, j);
|
|
int location = glGetAttribLocation(programme, long_name);
|
|
log_info(" %i) type:%s name:%s location:%i", i, GL_type_to_string(type), long_name, location);
|
|
}
|
|
} else {
|
|
int location = glGetAttribLocation(programme, name);
|
|
log_info(" %i) type:%s name:%s location:%i", i, GL_type_to_string(type), name, location);
|
|
}
|
|
}
|
|
|
|
glGetProgramiv(programme, GL_ACTIVE_UNIFORMS, ¶ms);
|
|
log_info("GL_ACTIVE_UNIFORMS = %i", params);
|
|
for (GLuint i = 0; i < (GLuint)params; i++) {
|
|
char name[64];
|
|
int max_length = 64;
|
|
int actual_length = 0;
|
|
int size = 0;
|
|
GLenum type;
|
|
glGetActiveUniform(programme, i, max_length, &actual_length, &size, &type, name);
|
|
if (size > 1) {
|
|
for (int j = 0; j < size; j++) {
|
|
char long_name[64];
|
|
sprintf(long_name, "%s[%i]", name, j);
|
|
int location = glGetUniformLocation(programme, long_name);
|
|
log_info(" %i) type:%s name:%s location:%i", i, GL_type_to_string (type), long_name, location);
|
|
}
|
|
} else {
|
|
int location = glGetUniformLocation(programme, name);
|
|
log_info(" %i) type:%s name:%s location:%i", i, GL_type_to_string (type), name, location);
|
|
}
|
|
}
|
|
|
|
_print_programme_info_log(programme);
|
|
}
|
|
|
|
// should only be used during development, quite computationally expensive
|
|
bool is_valid(GLuint programme) {
|
|
glValidateProgram(programme);
|
|
int params = -1;
|
|
glGetProgramiv(programme, GL_VALIDATE_STATUS, ¶ms);
|
|
log_info("program %i GL_VALIDATE_STATUS = %i", programme, params);
|
|
if (GL_TRUE != params) {
|
|
_print_programme_info_log(programme);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void init() {
|
|
|
|
printf("What would you like to do?\n");
|
|
printf("\t1. Open MPQ\n\t2. Create MPQ\n\t3. Extract BLPs from WMO\n\t4. Renderer\n");
|
|
|
|
int input = 0;
|
|
scanf_s("%d", &input);
|
|
clear_input_buffer();
|
|
|
|
switch (input) {
|
|
case 1:
|
|
{
|
|
HANDLE hMPQ = NULL;
|
|
//DWORD dwError = 0;
|
|
HANDLE hMPQ_COMMON = NULL;
|
|
|
|
ArchiveManager manager;
|
|
//char mpqFilePath[MAX_PATH];
|
|
// get_mpq_file_path(mpqFilePath, MAX_PATH);
|
|
|
|
PathList list_container;
|
|
char wowDataDir[MAX_PATH];
|
|
get_data_dir(wowDataDir, MAX_PATH);
|
|
|
|
|
|
init_archive_manager(&manager, wowDataDir);
|
|
|
|
init_path_list(&list_container);
|
|
|
|
recursively_scan_directory(wowDataDir, &list_container);
|
|
for (int i = 0; i < list_container.count; i++) {
|
|
log_info("Found path: '%s'", list_container.entries[i].path);
|
|
}
|
|
// free_path_list(&list_container);
|
|
|
|
qsort(list_container.entries, list_container.count, sizeof(ArchiveEntry),
|
|
archive_comparator);
|
|
|
|
for (int i = 0; i < list_container.count; i++) {
|
|
HANDLE hArchive;
|
|
const char *mpqFilePath = list_container.entries[i].path;
|
|
|
|
if (manager.count >= manager.capacity) {
|
|
expand_archive_manager(&manager);
|
|
}
|
|
|
|
if (!SFileOpenArchive(
|
|
mpqFilePath,
|
|
0,
|
|
MPQ_OPEN_READ_ONLY,
|
|
&hArchive))
|
|
{
|
|
// Log error and continue to the next archive!
|
|
log_error("Error opening MPQ '%s'. Error code: %lu\n", mpqFilePath, GetLastError());
|
|
continue;
|
|
}
|
|
|
|
// Success: Store the handle in the ArchiveManager
|
|
manager.archives[manager.count++] = hArchive;
|
|
// TODO - honestly I should mount these as needed... check newest patch first -> oldest
|
|
// for files needed
|
|
log_info("Successfully mounted archive #%zu: %s", manager.count, mpqFilePath);
|
|
}
|
|
|
|
/*
|
|
if (!SFileOpenArchive(
|
|
mpqFilePath,
|
|
0,
|
|
MPQ_OPEN_READ_ONLY,
|
|
&hMPQ)) {
|
|
log_error("Error opening MPQ '%s'. Error code: %lu\n", mpqFilePath, GetLastError());
|
|
return;
|
|
}
|
|
|
|
if (!SFileOpenArchive("./common.MPQ", 0, MPQ_OPEN_READ_ONLY, &hMPQ_COMMON)) {
|
|
DWORD dwError = GetLastError();
|
|
log_error("Error opening `common.MPQ` at `%s`. Error code: %lu\n", "./common.MPQ", dwError);
|
|
return;
|
|
}
|
|
|
|
log_info("Successfully opened MPQ file: '%s'\n", mpqFilePath);
|
|
getchar();
|
|
|
|
log_info("Getting (listfile) for test run...\n");
|
|
get_file_size_in_mpq(get_file_in_mpq(hMPQ, "(listfile)"), "(listfile)");
|
|
|
|
log_info("Getting (CTFNightelf_A.wmo) for WMO data test");
|
|
//WMOData test_WMOdata = load_wmo_data(hMPQ, "World\\wmo\\PvP\\Buildings\\CTF\\CTFOrc_A.wmo");*/
|
|
// "World\\wmo\\Dungeon\\MD_Caveden\\MD_VrykulDen.wmo"
|
|
//char *wmoFileName = "World\\wmo\\PvP\\Buildings\\CTF\\CTFNightelf_A.wmo";
|
|
//char *wmoFileName = "World\\wmo\\Dungeon\\MD_Caveden\\MD_VrykulDen.wmo";
|
|
//char *wmoFileName = "World\\wmo\\Test\\test_petes_wmo_rotation_test.wmo";
|
|
char *wmoFileName = "World\\wmo\\Dungeon\\Ulduar\\Ulduar_Raid.wmo";
|
|
WMOData test_WMOdata = load_wmo_data(&manager, wmoFileName);
|
|
|
|
const char *log_file_name = "wmo_geometry_export.obj.log";
|
|
char log_file_path[MAX_PATH];
|
|
snprintf(log_file_path, MAX_PATH, "%s.obj.log", log_file_name);
|
|
|
|
FILE *log_file = fopen(log_file_name, "w");
|
|
if (log_file == NULL) {
|
|
log_error("Failed to open log file: '%s'. Check permissions or dir", log_file_name);
|
|
}
|
|
|
|
|
|
WMORootData wmo_root_data = {0};
|
|
|
|
// TODO - SOURCE OF ERROR FOR BYTE MISMATCH?
|
|
parse_wmo_chunks(&manager, test_WMOdata.data, test_WMOdata.size, &wmo_root_data, wmoFileName);
|
|
|
|
// extract_wmo_geometry(&wmo_root_data, log_file);
|
|
if (log_file != NULL) {
|
|
fclose(log_file);
|
|
}
|
|
|
|
if (wmo_root_data.motx_data_ptr && wmo_root_data.momt_data_ptr) {
|
|
log_info("Successfully located chunks.");
|
|
// log_info("Located MVER chunk at offset %td", out_wmo_data.mver_data_ptr - wmo_buffer);
|
|
// pass by reference
|
|
parse_momt_and_extract_textures(&manager, &wmo_root_data);
|
|
|
|
} else {
|
|
log_error("Failed to find required MOMT and MOTX chunks.");
|
|
}
|
|
|
|
log_info("Testing struct data storage... MVER at %td, MOGN at %td",
|
|
wmo_root_data.mver_data_ptr - test_WMOdata.data,
|
|
wmo_root_data.mogn_data_ptr - test_WMOdata.data);
|
|
|
|
if (!restart_gl_log()) {
|
|
break;
|
|
}
|
|
|
|
gl_log("starting GLFW\n%s\n", glfwGetVersionString());
|
|
glfwSetErrorCallback(glfw_error_callback);
|
|
|
|
// Initialize GLFW helper library to start GL context and O/S window
|
|
if (!glfwInit()) {
|
|
log_error("Could not initialize glfw");
|
|
return;
|
|
}
|
|
|
|
glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 6);
|
|
glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint (GLFW_SAMPLES, 4); // Set to "16" before taking screen shots?
|
|
|
|
GLFWmonitor *mon = glfwGetPrimaryMonitor();
|
|
const GLFWvidmode *vmode = glfwGetVideoMode(mon);
|
|
// Create a windowed mode window and its OpenGL context
|
|
GLFWwindow* window = glfwCreateWindow(vmode->width, vmode->height, "GLFW Window", mon, NULL);
|
|
if (!window) {
|
|
log_error("Could not create glfw window, Error: %d", GetLastError());
|
|
glfwTerminate();
|
|
return;
|
|
}
|
|
// Make window's context current
|
|
glfwMakeContextCurrent(window);
|
|
|
|
// Load all OpenGL function pointers with GLAD
|
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
|
log_error("Failed to initialize GLAD");
|
|
glfwTerminate();
|
|
return;
|
|
}
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
// log GL params
|
|
log_gl_params();
|
|
|
|
// get version info
|
|
const GLubyte* renderer = glGetString(GL_RENDERER);
|
|
const GLubyte* version = glGetString(GL_VERSION);
|
|
log_info("Renderer: %s", renderer);
|
|
log_info("OpenGL version supported %s", version);
|
|
|
|
glfwSetWindowSizeCallback(window, glfw_window_size_callback);
|
|
glfwSetFramebufferSizeCallback(window, glfw_framebuffer_resize_callback);
|
|
|
|
// tell GL to only draw onto a pixel if the shape is closer to the viewer
|
|
glEnable(GL_DEPTH_TEST); // enable depth testing
|
|
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
|
|
|
|
wmo_load_textures_to_gpu(&manager, &wmo_root_data);
|
|
|
|
GroupMesh *meshes = (GroupMesh*)calloc(wmo_root_data.group_count, sizeof(GroupMesh));
|
|
|
|
if (wmo_root_data.groups == NULL || wmo_root_data.group_count == 0) {
|
|
log_error("No WMO groups loaded. Skipping mesh creation");
|
|
} else {
|
|
for (size_t i = 0; i < wmo_root_data.group_count; i++) {
|
|
if (wmo_root_data.groups[i].movt_data_ptr != NULL) {
|
|
meshes[i] = create_mesh_from_group(&wmo_root_data.groups[i], &wmo_root_data);
|
|
} else {
|
|
log_warn("Skipping empty group %zu", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
GLfloat points [] = {
|
|
0.0f, 0.5f, -1.0f,
|
|
0.4f, -0.5f, -1.0f,
|
|
-0.4f, -0.5f, -1.0f,
|
|
//-0.4f, -0.5f, 0.0f,
|
|
//-0.4f, 0.5f, 0.0f,
|
|
//0.4f, -0.5f, 0.0f,
|
|
};
|
|
|
|
GLfloat colours[] = {
|
|
1.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f
|
|
};
|
|
|
|
float matrix[16] = {
|
|
1.0f, 0.0f, 0.0f, 0.0f, // first column
|
|
0.0f, 1.0f, 0.0f, 0.0f, // second column
|
|
0.0f, 0.0f, 1.0f, 0.0f, // third column
|
|
0.5f, 0.0f, 0.0f, 1.0f // fourth column
|
|
};
|
|
|
|
GLuint points_vbo = 0;
|
|
glGenBuffers(1, &points_vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
|
|
|
|
GLuint colours_vbo = 0;
|
|
glGenBuffers(1, &colours_vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, colours_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);
|
|
|
|
// bind vbos to ONE vertex array object
|
|
// need to keep track of the VAO index for each type of mesh that is created
|
|
GLuint vao = 0;
|
|
glGenVertexArrays(1, &vao);
|
|
glBindVertexArray(vao);
|
|
//glEnableVertexAttribArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, colours_vbo);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
|
|
// this only affects the currently bound vertex array object.
|
|
// only affects the attributes above basically
|
|
// need to bind every new vertex array and repeat this procedure for those too
|
|
glEnableVertexAttribArray(0);
|
|
glEnableVertexAttribArray(1);
|
|
|
|
|
|
GLfloat rotation_x = 0.01;
|
|
GLfloat rotation_y = 0.01;
|
|
GLfloat rotation_z = 0.01;
|
|
mat4_t scale_matrix = mat4_make_scale(1.0f, 1.0f, 1.0f);
|
|
mat4_t translate_matrix = mat4_make_translation(1.0f, 1.0f, 5.0f);
|
|
mat4_t rotation_matrix_x = mat4_make_rotation_x(rotation_x);
|
|
mat4_t rotation_matrix_y = mat4_make_rotation_y(rotation_y);
|
|
mat4_t rotation_matrix_z = mat4_make_rotation_z(rotation_z);
|
|
*/
|
|
char *vertex_shader = ("../../shaders/wmo.vert");
|
|
char *fragment_shader = ("../../shaders/wmo.frag");
|
|
GLuint shader_programme = create_shader_program_from_files(vertex_shader, fragment_shader);
|
|
//print_all(shader_programme);
|
|
|
|
// get unique location of the variable "inputColour"
|
|
//GLuint colour_location = glGetUniformLocation(shader_programme, "inputColour");
|
|
int matrix_location = glGetUniformLocation(shader_programme, "matrix");
|
|
glUseProgram(shader_programme);
|
|
|
|
float matrix[16] = {
|
|
1.0f, 0.0f, 0.0f, 0.0f, // first column
|
|
0.0f, 1.0f, 0.0f, 0.0f, // second column
|
|
0.0f, 0.0f, 1.0f, 0.0f, // third column
|
|
0.5f, 0.0f, 0.0f, 1.0f // fourth column
|
|
};
|
|
//glUniformMatrix4fv(matrix_location, 1, GL_FALSE, matrix);
|
|
// assigns an initial colour to the fragment shader
|
|
// can change uniform variables with glUniform() but only affects shader
|
|
// glUniform4f(colour_location, 1.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
/* pass pointer to matrix array's first element*/
|
|
|
|
|
|
// Optional: Set up the viewport and clear color once
|
|
int width, height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
glViewport(0, 0, width, height);
|
|
glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
|
|
|
|
//glEnable(GL_CULL_FACE);
|
|
//glCullFace(GL_BACK);
|
|
//glFrontFace(GL_CW); // GL_CCW for counter clock-wise
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
float speed = 10.0f; // 1 unit per second
|
|
float last_position = 0.0f;
|
|
float cam_speed = 10.0f; // 1 unit per sec
|
|
float cam_yaw_speed = 3.5f; // 3.5 degrees per second
|
|
vec3_t cam_pos = { 0.0f, 20.0f, 150.0f }; // don't start at zero, or we will be too close
|
|
float cam_yaw = 0.0f; // y-rotation in degrees
|
|
float cam_pitch = 0.0f;
|
|
mat4_t T = mat4_make_translation(-cam_pos.x, -cam_pos.y, -cam_pos.z);
|
|
mat4_t R = mat4_make_rotation_y(-cam_yaw);
|
|
mat4_t view_mat = mat4_mul_mat4(R, T);
|
|
|
|
/*
|
|
// projection matrix variables
|
|
// input variables
|
|
float znear = 0.1f; // clipping plane
|
|
float zfar = 1000.0f; // clipping plane
|
|
float fov = 67.0f * ONE_DEG_IN_RAD; // convert 67 degrees to radians
|
|
float aspect = (float)width / (float)height; // aspect ratio
|
|
// matrix components
|
|
float range = tan(fov * 0.5f) * znear;
|
|
//float Sx = (2.0f * znear) / (range * aspect + range * aspect);
|
|
float Sy = znear / range;
|
|
float Sx = Sy / aspect;
|
|
float Sz = -(zfar + znear) / (zfar - znear);
|
|
float Pz = -(2.0f * zfar * znear) / (zfar - znear);
|
|
|
|
float proj_mat[] = {
|
|
Sx, 0.0f, 0.0f, 0.0f,
|
|
0.0f, Sy, 0.0f, 0.0f,
|
|
0.0f, 0.0f, Sz, -1.0f,
|
|
0.0f, 0.0f, Pz, 0.0f
|
|
};*/
|
|
|
|
float fov_radians = 67.0f * ONE_DEG_IN_RAD;
|
|
|
|
mat4_t projection = mat4_make_perspective(fov_radians, (float)width / (float)height, 0.1f, 1000.0f);
|
|
|
|
|
|
//mat4_t rotation_correction = mat4_make_rotation_x(TO_RAD(-90.0f));
|
|
mat4_t model_mat = mat4_identity();
|
|
|
|
int view_mat_location = glGetUniformLocation (shader_programme, "view");
|
|
glUseProgram (shader_programme);
|
|
//glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
|
|
int proj_mat_location = glGetUniformLocation (shader_programme, "proj");
|
|
glUseProgram (shader_programme);
|
|
//glUniformMatrix4fv (proj_mat_location, 1, GL_FALSE, proj_mat);
|
|
|
|
glUniformMatrix4fv(matrix_location, 1, GL_FALSE, model_mat.m);
|
|
glUniformMatrix4fv(view_mat_location, 1, GL_FALSE, view_mat.m);
|
|
glUniformMatrix4fv(proj_mat_location, 1, GL_FALSE, projection.m);
|
|
|
|
print_all(shader_programme);
|
|
// call `glPolygonMode` before rendering if you want to use wire-frame rendering mode
|
|
// Loop until the user closes the window
|
|
while(!glfwWindowShouldClose(window)) {
|
|
_update_fps_counter(window);
|
|
|
|
// add a timer for doing animation
|
|
static double previous_seconds = 0;
|
|
double current_seconds = glfwGetTime();
|
|
double elapsed_seconds = current_seconds - previous_seconds;
|
|
previous_seconds = current_seconds;
|
|
|
|
if (fabs(last_position) > 1.0f) {
|
|
speed = -speed;
|
|
}
|
|
//rotation_z += 0.1;
|
|
// update the matrix
|
|
//matrix[12] = elapsed_seconds * speed + last_position;
|
|
//last_position = matrix[12];
|
|
//glUseProgram(shader_programme);
|
|
//glUniformMatrix4fv(matrix_location, 1, GL_FALSE, rotation_matrix_z.m);
|
|
|
|
double current_time = glfwGetTime();
|
|
/*if (current_time > 5000) {
|
|
mat4_t new_scale_matrix = mat4_make_scale(0.5f, 2.0f, 1.0f);
|
|
glUseProgram(shader_programme);
|
|
glUniformMatrix4fv(matrix_location, 1, GL_FALSE, new_scale_matrix.m);
|
|
}*/
|
|
/*
|
|
if (current_time > 5000) {
|
|
// Scale the vectors, rotate, then translate
|
|
mat4_t S = mat4_make_scale(1.5f, 1.5f, 1.5f);
|
|
mat4_t Rz = mat4_make_rotation_z(M_PI / 4.0f);
|
|
mat4_t T = mat4_make_translation(1.0f, 0.0f, 0.0f);
|
|
|
|
mat4_t temp_matrix = mat4_mul_mat4(Rz, S);
|
|
mat4_t final_matrix = mat4_mul_mat4(T, temp_matrix);
|
|
|
|
glUseProgram(shader_programme);
|
|
glUniformMatrix4fv(matrix_location, 1, GL_FALSE, final_matrix.m);
|
|
}*/
|
|
|
|
float yaw_rad = TO_RAD(cam_yaw);
|
|
float pitch_rad = TO_RAD(cam_pitch);
|
|
|
|
vec3_t cam_front;
|
|
cam_front.x = cosf(yaw_rad) * cosf(pitch_rad);
|
|
cam_front.y = sinf(pitch_rad);
|
|
cam_front.z = sinf(yaw_rad) * cosf(pitch_rad);
|
|
|
|
vec3_normalize(&cam_front);
|
|
|
|
vec3_t world_up = { 0.0f, 1.0f, 0.0f };
|
|
|
|
vec3_t cam_right = vec3_cross(cam_front, world_up);
|
|
vec3_normalize(&cam_right);
|
|
|
|
vec3_t cam_up = vec3_cross(cam_right, cam_front);
|
|
vec3_normalize(&cam_up);
|
|
|
|
float move_dist = cam_speed * elapsed_seconds;
|
|
|
|
view_mat = mat4_look_at(
|
|
cam_pos.x, cam_pos.y, cam_pos.z,
|
|
cam_pos.x + cam_front.x, cam_pos.y + cam_front.y, cam_pos.z + cam_front.z,
|
|
cam_up.x, cam_up.y, cam_up.z
|
|
);
|
|
|
|
// Render here
|
|
// wipe the drawing surface clear
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
// Update viewport size for scaling
|
|
glViewport(0, 0, g_fb_width, g_fb_height);
|
|
|
|
for (size_t i = 0; i < wmo_root_data.group_count; i++) {
|
|
if (meshes[i].VAO != 0) {
|
|
//glActiveTexture(GL_TEXTURE0);
|
|
//glBindTexture(GL_TEXTURE_2D, meshes[i].textureID);
|
|
|
|
draw_group_mesh(meshes[i]);
|
|
}
|
|
}
|
|
|
|
|
|
// update other events like input handling
|
|
glfwPollEvents();
|
|
// Swap front and back buffers
|
|
glfwSwapBuffers(window);
|
|
// Check if we should exit
|
|
if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
|
|
glfwSetWindowShouldClose(window, 1);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_9)) {
|
|
glfwSetWindowMonitor(window, NULL, 480, 270, vmode->width / 2, vmode->height / 2, GLFW_DONT_CARE);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_8)) {
|
|
glfwSetWindowMonitor(window, mon, 0, 0, vmode->width, vmode->height, vmode->refreshRate);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_7)) {
|
|
shader_reload(&shader_programme, vertex_shader, fragment_shader);
|
|
|
|
int new_matrix_loc = glGetUniformLocation(shader_programme, "matrix");
|
|
int new_view_loc = glGetUniformLocation(shader_programme, "view");
|
|
int new_proj_loc = glGetUniformLocation(shader_programme, "proj");
|
|
|
|
glUseProgram(shader_programme);
|
|
glUniformMatrix4fv(new_matrix_loc, 1, GL_FALSE, model_mat.m);
|
|
glUniformMatrix4fv(new_view_loc, 1, GL_FALSE, view_mat.m);
|
|
glUniformMatrix4fv(new_proj_loc, 1, GL_FALSE, projection.m);
|
|
}
|
|
|
|
|
|
// control keys
|
|
bool cam_moved = false;
|
|
if (glfwGetKey (window, GLFW_KEY_A)) {
|
|
//cam_pos[0] -= cam_speed * elapsed_seconds;
|
|
vec3_t move_vec = vec3_mul(cam_right, move_dist);
|
|
cam_pos = vec3_sub(cam_pos, move_vec);
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_D)) {
|
|
//cam_pos[0] += cam_speed * elapsed_seconds;
|
|
vec3_t move_vec = vec3_mul(cam_right, move_dist);
|
|
cam_pos = vec3_add(cam_pos, move_vec);
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_PAGE_UP)) {
|
|
//cam_pos[1] += cam_speed * elapsed_seconds;
|
|
cam_pos.y += move_dist;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_PAGE_DOWN)) {
|
|
//cam_pos[1] -= cam_speed * elapsed_seconds;
|
|
cam_pos.y -= move_dist;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_W)) {
|
|
//cam_pos[2] -= cam_speed * elapsed_seconds;
|
|
vec3_t move_vec = vec3_mul(cam_front, move_dist);
|
|
|
|
cam_pos = vec3_add(cam_pos, move_vec);
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_S)) {
|
|
//cam_pos[2] += cam_speed * elapsed_seconds;
|
|
vec3_t move_vec = vec3_mul(cam_front, move_dist);
|
|
|
|
cam_pos = vec3_sub(cam_pos, move_vec);
|
|
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_LEFT)) {
|
|
cam_yaw += cam_yaw_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_RIGHT)) {
|
|
cam_yaw -= cam_yaw_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_UP)) {
|
|
cam_pitch += cam_yaw_speed *elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_DOWN)) {
|
|
cam_pitch -= cam_yaw_speed * elapsed_seconds;
|
|
}
|
|
|
|
if (cam_pitch > 89.0f) {
|
|
cam_pitch = 89.0f;
|
|
}
|
|
if (cam_pitch < -89.0f) {
|
|
cam_pitch = -89.0f;
|
|
}
|
|
|
|
// update view matrix
|
|
if (cam_moved) {
|
|
//T = mat4_make_translation(-cam_pos.x, -cam_pos.y, -cam_pos.z);
|
|
//R = mat4_make_rotation_y(-cam_yaw);
|
|
//view_mat = mat4_mul_mat4(R, T);
|
|
view_mat = mat4_look_at(
|
|
cam_pos.x, cam_pos.y, cam_pos.z,
|
|
cam_pos.x + cam_front.x, cam_pos.y + cam_front.y, cam_pos.z + cam_front.z,
|
|
cam_up.x, cam_up.y, cam_up.z
|
|
);
|
|
glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
|
|
}
|
|
}
|
|
free_group_mesh(meshes);
|
|
glfwTerminate();
|
|
break;
|
|
}
|
|
case 2:
|
|
printf("TODO!!");
|
|
break;
|
|
case 3:
|
|
// printf("Enter a WMO filename or path\n");
|
|
|
|
FILE *file_handle = NULL;
|
|
char wmo_file_path[MAX_PATH];
|
|
get_wmo_file_path(wmo_file_path, MAX_PATH);
|
|
|
|
if (load_wmo_file(wmo_file_path, &file_handle) == 0) {
|
|
log_info("Successfully loaded WMO file '%s'!", wmo_file_path);
|
|
} else {
|
|
log_error("Could not open WMO file '%s': %d", wmo_file_path, GetLastError());
|
|
}
|
|
|
|
WMOData test_WMOdata = load_wmo_data_from_file(&file_handle);
|
|
|
|
WMORootData wmo_root_data = {0};
|
|
HANDLE hMPQ = NULL;
|
|
HANDLE hMPQ_COMMON = NULL;
|
|
// parse_wmo_chunks(hMPQ, test_WMOdata.data, test_WMOdata.size, hMPQ_COMMON, &wmo_root_data, wmo_file_path);
|
|
|
|
log_info("Sizeof SMOGroupInfo: %d", sizeof(SMOGroupInfo));
|
|
|
|
if (wmo_root_data.motx_data_ptr && wmo_root_data.momt_data_ptr) {
|
|
log_info("Successfully located chunks.");
|
|
// log_info("Located MVER chunk at offset %td", out_wmo_data.mver_data_ptr - wmo_buffer);
|
|
// pass by reference
|
|
// TODO: this currently uses stormlib for extracting out of the MPQ's when loaded
|
|
// when we do it manually loading, there will be 0 BLP's unless we load from data dir
|
|
// which is kinda redundant then, we could just export a list of BLP's through text...?
|
|
// but the only way to do it I imagine with actual BLP files is loading the MPQ's themselves...
|
|
// unless the MPQ is already fully extracted then we could just read from that 'cache'... otherwise we would just
|
|
// read from MPQ memory!! only problem is the startup time is long while reading with Stormlib...
|
|
// probably should just read header data of MPQ's and confirm if the file exists with the listfile instead of loading the whole
|
|
// mpq into memory as we won't need EVERYTHING in there at the current moment (reduce debugging time)
|
|
// parse_momt_and_extract_textures(hMPQ, &wmo_root_data, hMPQ_COMMON);
|
|
} else {
|
|
log_error("Failed to find required MOMT and MOTX chunks.");
|
|
}
|
|
|
|
break;
|
|
case 4:
|
|
if (!restart_gl_log()) {
|
|
break;
|
|
}
|
|
|
|
gl_log("starting GLFW\n%s\n", glfwGetVersionString());
|
|
glfwSetErrorCallback(glfw_error_callback);
|
|
|
|
// Initialize GLFW helper library to start GL context and O/S window
|
|
if (!glfwInit()) {
|
|
log_error("Could not initialize glfw");
|
|
return;
|
|
}
|
|
|
|
glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 6);
|
|
glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint (GLFW_SAMPLES, 4); // Set to "16" before taking screen shots?
|
|
|
|
GLFWmonitor *mon = glfwGetPrimaryMonitor();
|
|
const GLFWvidmode *vmode = glfwGetVideoMode(mon);
|
|
// Create a windowed mode window and its OpenGL context
|
|
GLFWwindow* window = glfwCreateWindow(vmode->width, vmode->height, "GLFW Window", mon, NULL);
|
|
if (!window) {
|
|
log_error("Could not create glfw window, Error: %d", GetLastError());
|
|
glfwTerminate();
|
|
return;
|
|
}
|
|
// Make window's context current
|
|
glfwMakeContextCurrent(window);
|
|
|
|
// Load all OpenGL function pointers with GLAD
|
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
|
log_error("Failed to initialize GLAD");
|
|
glfwTerminate();
|
|
return;
|
|
}
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
// log GL params
|
|
log_gl_params();
|
|
|
|
// get version info
|
|
const GLubyte* renderer = glGetString(GL_RENDERER);
|
|
const GLubyte* version = glGetString(GL_VERSION);
|
|
log_info("Renderer: %s", renderer);
|
|
log_info("OpenGL version supported %s", version);
|
|
|
|
glfwSetWindowSizeCallback(window, glfw_window_size_callback);
|
|
glfwSetFramebufferSizeCallback(window, glfw_framebuffer_resize_callback);
|
|
|
|
// tell GL to only draw onto a pixel if the shape is closer to the viewer
|
|
glEnable(GL_DEPTH_TEST); // enable depth testing
|
|
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
|
|
|
|
GLfloat points [] = {
|
|
0.0f, 0.5f, -1.0f,
|
|
0.4f, -0.5f, -1.0f,
|
|
-0.4f, -0.5f, -1.0f,
|
|
//-0.4f, -0.5f, 0.0f,
|
|
//-0.4f, 0.5f, 0.0f,
|
|
//0.4f, -0.5f, 0.0f,
|
|
};
|
|
|
|
GLfloat colours[] = {
|
|
1.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f
|
|
};
|
|
|
|
float matrix[16] = {
|
|
1.0f, 0.0f, 0.0f, 0.0f, // first column
|
|
0.0f, 1.0f, 0.0f, 0.0f, // second column
|
|
0.0f, 0.0f, 1.0f, 0.0f, // third column
|
|
0.5f, 0.0f, 0.0f, 1.0f // fourth column
|
|
};
|
|
|
|
GLuint points_vbo = 0;
|
|
glGenBuffers(1, &points_vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
|
|
|
|
GLuint colours_vbo = 0;
|
|
glGenBuffers(1, &colours_vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, colours_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);
|
|
|
|
// bind vbos to ONE vertex array object
|
|
// need to keep track of the VAO index for each type of mesh that is created
|
|
GLuint vao = 0;
|
|
glGenVertexArrays(1, &vao);
|
|
glBindVertexArray(vao);
|
|
glEnableVertexAttribArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glBindBuffer(GL_ARRAY_BUFFER, colours_vbo);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
|
|
// this only affects the currently bound vertex array object.
|
|
// only affects the attributes above basically
|
|
// need to bind every new vertex array and repeat this procedure for those too
|
|
glEnableVertexAttribArray(0);
|
|
glEnableVertexAttribArray(1);
|
|
|
|
GLfloat rotation_x = 0.01;
|
|
GLfloat rotation_y = 0.01;
|
|
GLfloat rotation_z = 0.01;
|
|
mat4_t scale_matrix = mat4_make_scale(1.0f, 1.0f, 1.0f);
|
|
mat4_t translate_matrix = mat4_make_translation(1.0f, 1.0f, 5.0f);
|
|
mat4_t rotation_matrix_x = mat4_make_rotation_x(rotation_x);
|
|
mat4_t rotation_matrix_y = mat4_make_rotation_y(rotation_y);
|
|
mat4_t rotation_matrix_z = mat4_make_rotation_z(rotation_z);
|
|
|
|
char *vertex_shader = ("../../shaders/wmo.vert");
|
|
char *fragment_shader = ("../../shaders/wmo.frag");
|
|
GLuint shader_programme = create_shader_program_from_files(vertex_shader, fragment_shader);
|
|
// print_all(shader_programme);
|
|
|
|
// get unique location of the variable "inputColour"
|
|
GLuint colour_location = glGetUniformLocation(shader_programme, "inputColour");
|
|
int matrix_location = glGetUniformLocation(shader_programme, "matrix");
|
|
glUseProgram(shader_programme);
|
|
glUniformMatrix4fv(matrix_location, 1, GL_FALSE, matrix);
|
|
// assigns an initial colour to the fragment shader
|
|
// can change uniform variables with glUniform() but only affects shader
|
|
glUniform4f(colour_location, 1.0f, 0.0f, 0.0f, 1.0f);
|
|
/* pass pointer to matrix array's first element*/
|
|
|
|
// Optional: Set up the viewport and clear color once
|
|
int width, height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
glViewport(0, 0, width, height);
|
|
glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
|
|
|
|
//glEnable(GL_CULL_FACE);
|
|
//glCullFace(GL_BACK);
|
|
//glFrontFace(GL_CW); // GL_CCW for counter clock-wise
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
float speed = 1.0f; // 1 unit per second
|
|
float last_position = 0.0f;
|
|
float cam_speed = 1.0f; // 1 unit per sec
|
|
float cam_yaw_speed = 1.0f; // 10 degrees per second
|
|
float cam_pos[] = { 0.0f, 0.0f, 2.0f }; // don't start at zero, or we will be too close
|
|
float cam_yaw = 0.0f; // y-rotation in degrees
|
|
mat4_t T = mat4_make_translation(-cam_pos[0], -cam_pos[1], -cam_pos[2]);
|
|
mat4_t R = mat4_make_rotation_y(-cam_yaw);
|
|
mat4_t view_mat = mat4_mul_mat4(R, T);
|
|
|
|
// input variables
|
|
float znear = 0.1f; // clipping plane
|
|
float zfar = 100.0f; // clipping plane
|
|
float fov = 67.0f * ONE_DEG_IN_RAD; // convert 67 degrees to radians
|
|
float aspect = (float)width / (float)height; // aspect ratio
|
|
// matrix components
|
|
float range = tan(fov * 0.5f) * znear;
|
|
//float Sx = (2.0f * znear) / (range * aspect + range * aspect);
|
|
float Sy = znear / range;
|
|
float Sx = Sy / aspect;
|
|
float Sz = -(zfar + znear) / (zfar - znear);
|
|
float Pz = -(2.0f * zfar * znear) / (zfar - znear);
|
|
|
|
float proj_mat[] = {
|
|
Sx, 0.0f, 0.0f, 0.0f,
|
|
0.0f, Sy, 0.0f, 0.0f,
|
|
0.0f, 0.0f, Sz, -1.0f,
|
|
0.0f, 0.0f, Pz, 0.0f
|
|
};
|
|
|
|
int view_mat_location = glGetUniformLocation (shader_programme, "view");
|
|
glUseProgram (shader_programme);
|
|
glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
|
|
int proj_mat_location = glGetUniformLocation (shader_programme, "proj");
|
|
glUseProgram (shader_programme);
|
|
glUniformMatrix4fv (proj_mat_location, 1, GL_FALSE, proj_mat);
|
|
|
|
// call `glPolygonMode` before rendering if you want to use wire-frame rendering mode
|
|
// Loop until the user closes the window
|
|
while(!glfwWindowShouldClose(window)) {
|
|
_update_fps_counter(window);
|
|
|
|
// add a timer for doing animation
|
|
static double previous_seconds = 0;
|
|
double current_seconds = glfwGetTime();
|
|
double elapsed_seconds = current_seconds - previous_seconds;
|
|
previous_seconds = current_seconds;
|
|
|
|
if (fabs(last_position) > 1.0f) {
|
|
speed = -speed;
|
|
}
|
|
|
|
double current_time = glfwGetTime();
|
|
|
|
// Render here
|
|
// wipe the drawing surface clear
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
// Update viewport size for scaling
|
|
glViewport(0, 0, g_fb_width, g_fb_height);
|
|
|
|
// draw points from the currently bound VAO with current in-use shader
|
|
// GL_POINTS looks ideal for debugging vertex locations if unsure
|
|
glUseProgram(shader_programme);
|
|
//glBindVertexArray(vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
|
|
// update other events like input handling
|
|
glfwPollEvents();
|
|
// Swap front and back buffers
|
|
glfwSwapBuffers(window);
|
|
// Check if we should exit
|
|
if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
|
|
glfwSetWindowShouldClose(window, 1);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_9)) {
|
|
glfwSetWindowMonitor(window, NULL, 480, 270, vmode->width / 2, vmode->height / 2, GLFW_DONT_CARE);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_8)) {
|
|
glfwSetWindowMonitor(window, mon, 0, 0, vmode->width, vmode->height, vmode->refreshRate);
|
|
} else if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_7)) {
|
|
shader_reload(&shader_programme, vertex_shader, fragment_shader);
|
|
|
|
int new_matrix_loc = glGetUniformLocation(shader_programme, "matrix");
|
|
int new_view_loc = glGetUniformLocation(shader_programme, "view");
|
|
int new_proj_loc = glGetUniformLocation(shader_programme, "proj");
|
|
|
|
glUseProgram(shader_programme);
|
|
glUniformMatrix4fv(new_matrix_loc, 1, GL_FALSE, matrix);
|
|
glUniformMatrix4fv(new_view_loc, 1, GL_FALSE, view_mat.m);
|
|
glUniformMatrix4fv(new_proj_loc, 1, GL_FALSE, proj_mat);
|
|
}
|
|
|
|
|
|
// control keys
|
|
bool cam_moved = false;
|
|
if (glfwGetKey (window, GLFW_KEY_A)) {
|
|
cam_pos[0] -= cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_D)) {
|
|
cam_pos[0] += cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_PAGE_UP)) {
|
|
cam_pos[1] += cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_PAGE_DOWN)) {
|
|
cam_pos[1] -= cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_W)) {
|
|
cam_pos[2] -= cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_S)) {
|
|
cam_pos[2] += cam_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_LEFT)) {
|
|
cam_yaw += cam_yaw_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
if (glfwGetKey (window, GLFW_KEY_RIGHT)) {
|
|
cam_yaw -= cam_yaw_speed * elapsed_seconds;
|
|
cam_moved = true;
|
|
}
|
|
// update view matrix
|
|
if (cam_moved) {
|
|
T = mat4_make_translation(-cam_pos[0], -cam_pos[1], -cam_pos[2]);
|
|
R = mat4_make_rotation_y(-cam_yaw);
|
|
view_mat = mat4_mul_mat4(R, T);
|
|
glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
|
|
}
|
|
}
|
|
glfwTerminate();
|
|
break;
|
|
default:
|
|
printf("DEFAULT TODO!");
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
log_set_level(1);
|
|
log_info("Starting program and initializing...");
|
|
|
|
init();
|
|
|
|
|
|
// hard coded path or './' source path works currently
|
|
// const char *mpqFileName = "F:\\C Projects\\BLPExtractor\\patch-3.MPQ";
|
|
|
|
return 0;
|
|
} |