preparing doodad rendering, rendering cubes in place, need to fix alignment rotation as it is wildy off
This commit is contained in:
@@ -36,6 +36,7 @@ add_executable(BLPExtractor
|
||||
src/renderer/texture.c
|
||||
src/renderer/texture.h
|
||||
src/renderer/render_types.h
|
||||
src/renderer/render_types.c
|
||||
)
|
||||
|
||||
# static C runtime /MTd (debug mode StormLibDUS.lib)
|
||||
|
||||
@@ -3,14 +3,21 @@ out vec4 FragColor;
|
||||
|
||||
in vec2 TexCoord;
|
||||
in vec4 VertexColour;
|
||||
|
||||
uniform sampler2D texSampler;
|
||||
uniform vec4 u_overrideColour;
|
||||
|
||||
void main() {
|
||||
// sample the texture
|
||||
vec4 texColor = texture(texSampler, TexCoord);
|
||||
if (u_overrideColour.a > 0.0) {
|
||||
FragColor = u_overrideColour;
|
||||
return;
|
||||
}
|
||||
|
||||
if (texColor.a < 0.1) discard;
|
||||
// sample the texture
|
||||
vec4 texColour = texture(texSampler, TexCoord) * VertexColour;
|
||||
|
||||
if (texColour.a < 0.1) discard;
|
||||
|
||||
//FragColor = vec4(0.6, 0.0, 1.0, 1.0);
|
||||
FragColor = texColor * VertexColour;
|
||||
FragColor = texColour;
|
||||
}
|
||||
@@ -7,12 +7,24 @@ layout(location = 3) in vec4 vertex_colour;
|
||||
out vec2 TexCoord;
|
||||
out vec4 VertexColour;
|
||||
|
||||
uniform mat4 matrix; // must match "matrix" in C code
|
||||
uniform mat4 view; // must match "view" in C code
|
||||
uniform mat4 proj; // must match "proj" in C code
|
||||
// TODO: change c code to match with u_<uniformName>
|
||||
// also types really matter for shaders!!
|
||||
uniform mat4 matrix;
|
||||
uniform mat4 view;
|
||||
uniform mat4 proj;
|
||||
uniform vec3 u_lightDir;
|
||||
uniform float u_lightInfluence; // 0.0 indoors, 1.0 outdoors
|
||||
|
||||
void main() {
|
||||
gl_Position = proj * view * matrix * vec4(vertex_position, 1.0);
|
||||
|
||||
// max 0.3 so the shadowed side isn't pure black (ambient light)
|
||||
float diffuse = max(dot(normalize(vertex_normal), normalize(u_lightDir)), 0.3);
|
||||
|
||||
float intensity = mix(1.0, diffuse, u_lightInfluence);
|
||||
|
||||
vec3 lighting = intensity * vertex_colour.rgb;
|
||||
|
||||
VertexColour = vec4(lighting, vertex_colour.a);
|
||||
TexCoord = vertex_tex;
|
||||
VertexColour = vertex_colour;
|
||||
}
|
||||
143
src/main.c
143
src/main.c
@@ -377,14 +377,37 @@ void init() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
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,
|
||||
// front face
|
||||
-0.5f, -0.5f, 0.5f, // bottom-left front
|
||||
0.5f, -0.5f, 0.5f, // bottom-right front
|
||||
0.5f, 0.5f, 0.5f, // top-right front
|
||||
-0.5f, 0.5f, 0.5f, // top-left front
|
||||
// back face
|
||||
-0.5f, -0.5f, -0.5f, // bottom-left back
|
||||
0.5f, -0.5f, -0.5f, // bottom-right back
|
||||
0.5f, 0.5f, -0.5f, // top-right back
|
||||
-0.5f, 0.5f, -0.5f // top-left back
|
||||
};
|
||||
|
||||
GLfloat cube_points [] = {
|
||||
// front face
|
||||
-0.5f, -0.5f, 0.5f, // bottom-left front
|
||||
0.5f, -0.5f, 0.5f, // bottom-right front
|
||||
0.5f, 0.5f, 0.5f, // top-right front
|
||||
-0.5f, 0.5f, 0.5f, // top-left front
|
||||
// back face
|
||||
-0.5f, -0.5f, -0.5f, // bottom-left back
|
||||
0.5f, -0.5f, -0.5f, // bottom-right back
|
||||
0.5f, 0.5f, -0.5f, // top-right back
|
||||
-0.5f, 0.5f, -0.5f // top-left back
|
||||
};
|
||||
|
||||
unsigned int cube_indices[] = {
|
||||
0,1, 1,2, 2,3, 3,0, // Front Face
|
||||
4,5, 5,6, 6,7, 7,4, // Back Face
|
||||
0,4, 1,5, 2,6, 3,7 // Connecting Lines
|
||||
};
|
||||
|
||||
GLfloat colours[] = {
|
||||
@@ -400,6 +423,23 @@ void init() {
|
||||
0.5f, 0.0f, 0.0f, 1.0f // fourth column
|
||||
};
|
||||
|
||||
GLuint cubeVAO, cubeVBO, cubeEBO;
|
||||
glGenVertexArrays(1, &cubeVAO);
|
||||
glGenBuffers(1, &cubeVBO);
|
||||
glGenBuffers(1, &cubeEBO);
|
||||
|
||||
glBindVertexArray(cubeVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_points), cube_points, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeEBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_indices), cube_indices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
GLuint points_vbo = 0;
|
||||
glGenBuffers(1, &points_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
|
||||
@@ -436,7 +476,7 @@ void init() {
|
||||
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);
|
||||
@@ -447,12 +487,14 @@ void init() {
|
||||
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
|
||||
@@ -552,7 +594,34 @@ void init() {
|
||||
glUniformMatrix4fv(view_mat_location, 1, GL_FALSE, view_mat.m);
|
||||
glUniformMatrix4fv(proj_mat_location, 1, GL_FALSE, projection.m);
|
||||
|
||||
GLint override_loc = glGetUniformLocation(shader_programme, "u_overrideColour");
|
||||
|
||||
float lightDir[3] = { 0.2f, 1.0f, 0.4f };
|
||||
GLint light_location = glGetUniformLocation(shader_programme, "u_lightDir");
|
||||
glUniform3fv(light_location, 1, lightDir);
|
||||
GLint light_influence_location = glGetUniformLocation(shader_programme, "u_lightInfluence");
|
||||
glUniform1f(light_influence_location, 0.0f);
|
||||
|
||||
SMODoodadDef* doodads = (SMODoodadDef*)wmo_root_data.modd_data_ptr;
|
||||
char* names = (char*)wmo_root_data.modn_data_ptr;
|
||||
|
||||
size_t num_doodads = wmo_root_data.modd_size / sizeof(SMODoodadDef);
|
||||
print_all(shader_programme);
|
||||
for (int i = 0; i < num_doodads; i++) {
|
||||
uint32_t name_index = doodads[i].ref.name_index;
|
||||
|
||||
if (name_index >= wmo_root_data.modn_size) {
|
||||
log_error("Doodad %lu has invalid name offset: %u (MODN size: %lu)",
|
||||
i, name_index, wmo_root_data.modn_size);
|
||||
continue;
|
||||
}
|
||||
char* modelName = names + name_index;
|
||||
log_info("Doodad %lu: %s at (%f, %f, %f) [Scale: %.2f]",
|
||||
i, modelName, doodads[i].position.x, doodads[i].position.y, doodads[i].position.z, doodads[i].scale);
|
||||
}
|
||||
|
||||
glUseProgram(shader_programme);
|
||||
glBindVertexArray(cubeVAO);
|
||||
// call `glPolygonMode` before rendering if you want to use wire-frame rendering mode
|
||||
// Loop until the user closes the window
|
||||
while(!glfwWindowShouldClose(window)) {
|
||||
@@ -617,13 +686,24 @@ void init() {
|
||||
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);
|
||||
|
||||
glUseProgram(shader_programme);
|
||||
glUniform3fv(light_location, 1, lightDir);
|
||||
glUniform4f(override_loc, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
for (size_t i = 0; i < wmo_root_data.group_count; i++) {
|
||||
if (meshes[i].is_outdoor) {
|
||||
// enable sun
|
||||
glUniform1f(light_influence_location, 1.0f);
|
||||
} else {
|
||||
// disable sun (use baked lighting)
|
||||
glUniform1f(light_influence_location, 0.0f);
|
||||
}
|
||||
|
||||
if (meshes[i].VAO != 0) {
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
//glBindTexture(GL_TEXTURE_2D, meshes[i].textureID);
|
||||
@@ -632,6 +712,49 @@ void init() {
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(shader_programme);
|
||||
glBindVertexArray(cubeVAO);
|
||||
glUniform4f(override_loc, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
glUniform1f(light_influence_location, 0.0f);
|
||||
// draw doodads as cubes
|
||||
if (wmo_root_data.modd_data_ptr) {
|
||||
doodads = (SMODoodadDef*)wmo_root_data.modd_data_ptr;
|
||||
num_doodads = wmo_root_data.modd_size / sizeof(SMODoodadDef);
|
||||
|
||||
for (size_t i = 0; i < num_doodads; i++) {
|
||||
SMODoodadDef* d = &doodads[i];
|
||||
|
||||
// scale
|
||||
mat4_t mat_scale = mat4_make_scale(d->scale, d->scale, d->scale);
|
||||
|
||||
// rotate
|
||||
C4Quaternion q = {
|
||||
d->orientation.x,
|
||||
d->orientation.y,
|
||||
d->orientation.z,
|
||||
d->orientation.w
|
||||
};
|
||||
mat4_t mat_rot = mat4_from_quaternion(
|
||||
q
|
||||
);
|
||||
|
||||
// translate
|
||||
mat4_t mat_trans = mat4_make_translation(d->position.x, d->position.y, d->position.z);
|
||||
|
||||
// combine (order: T * R * S)
|
||||
mat4_t model = mat4_identity();
|
||||
model = mat4_mul_mat4(mat_rot, mat_scale);
|
||||
model = mat4_mul_mat4(mat_trans, model);
|
||||
|
||||
glUniformMatrix4fv(matrix_location, 1, GL_FALSE, model.m);
|
||||
|
||||
// draw lines (24 indices)
|
||||
// (void*)0 is the offset into the EBO bound earlier
|
||||
glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, (void*)0);
|
||||
}
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
// update other events like input handling
|
||||
glfwPollEvents();
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Created by Tristan on 12/10/2025.
|
||||
//
|
||||
|
||||
#include "matrix.h"
|
||||
#include <math.h>
|
||||
#include "matrix.h"
|
||||
|
||||
mat4_t mat4_identity(void) {
|
||||
mat4_t m = {
|
||||
@@ -154,6 +154,46 @@ mat4_t mat4_make_quaternion(const GLfloat* q) {
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_t mat4_from_quaternion(C4Quaternion q) {
|
||||
mat4_t m;
|
||||
|
||||
// WoW - x, y, z, w
|
||||
float x = q.x;
|
||||
float y = q.y;
|
||||
float z = q.z;
|
||||
float w = q.w;
|
||||
|
||||
float x2 = x * x;
|
||||
float y2 = y * y;
|
||||
float z2 = z * z;
|
||||
|
||||
// col 1
|
||||
m.m[0] = 1.0f - (2.0f * y2) - (2.0f * z2);
|
||||
m.m[1] = (2.0f * x * y) + (2.0f * w * z);
|
||||
m.m[2] = (2 * x * z) - (2 * w * y);
|
||||
m.m[3] = 0.0f;
|
||||
|
||||
// col 2
|
||||
m.m[4] = (2.0f * x * y) - (2.0f * w * z);
|
||||
m.m[5] = 1.0f - (2 * x2) - (2 * z2);
|
||||
m.m[6] = (2.0f * y * z) + (2.0f * w * x);
|
||||
m.m[7] = 0.0f;
|
||||
|
||||
// col 3
|
||||
m.m[8] = (2.0f * x * z) + (2.0f * w * y);
|
||||
m.m[9] = (2.0f * y * z) - (2.0f * w * x);
|
||||
m.m[10] = 1.0f - (2.0f * x2) - (2.0 * y2);
|
||||
m.m[11] = 0.0f;
|
||||
|
||||
// col 4
|
||||
m.m[12] = 0.0f;
|
||||
m.m[13] = 0.0f;
|
||||
m.m[14] = 0.0f;
|
||||
m.m[15] = 1.0f;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_t mat4_look_at(float eyex, float eyey, float eyez,
|
||||
float targetx, float targety, float targetz,
|
||||
float upx, float upy, float upz) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
#include "render_types.h"
|
||||
#include "glad/glad.h"
|
||||
|
||||
#define M_PI 3.14159265358979323846
|
||||
#define ONE_DEG_IN_RAD (2.0 * M_PI) / 360.0 // 0.017444444
|
||||
#ifndef TO_RAD
|
||||
#define TO_RAD(deg) ((deg) * 3.14159265358979323846)
|
||||
#define TO_RAD(deg) ((deg) * M_PI)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@@ -22,6 +23,7 @@ mat4_t mat4_make_rotation_z(GLfloat m);
|
||||
mat4_t mat4_make_scale(GLfloat sx, GLfloat sy, GLfloat sz);
|
||||
mat4_t mat4_make_translation(GLfloat tx, GLfloat ty, GLfloat tz);
|
||||
mat4_t mat4_make_quaternion(const GLfloat* q, GLfloat* m);
|
||||
mat4_t mat4_from_quaternion(C4Quaternion q);
|
||||
mat4_t mat4_make_perspective(float fov_rad, float aspect, float znear, float zfar);
|
||||
mat4_t mat4_mul_mat4(mat4_t a, mat4_t b);
|
||||
mat4_t mat4_identity(void);
|
||||
|
||||
@@ -30,6 +30,7 @@ GroupMesh create_mesh_from_group(const WMOGroupData* group, const WMORootData* r
|
||||
// size_t num_colours = (group->mocv_data_ptr) ? group->mocv_size / 4 : 0;
|
||||
|
||||
int is_outdoor = !group->header.flags.isIndoor;
|
||||
mesh.is_outdoor = is_outdoor;
|
||||
int has_mocv = group->header.flags.vertexColors;
|
||||
|
||||
for (size_t i = 0; i < num_vertices; i++) {
|
||||
@@ -63,7 +64,8 @@ GroupMesh create_mesh_from_group(const WMOGroupData* group, const WMORootData* r
|
||||
vertices[i].colour.b = colours[i].r;
|
||||
vertices[i].colour.g = colours[i].g;
|
||||
vertices[i].colour.r = colours[i].b;
|
||||
vertices[i].colour.a = colours[i].a;
|
||||
// set alpha to 255 instead of colours[i].a because only supporting one texture at this moment
|
||||
vertices[i].colour.a = 255;
|
||||
} else {
|
||||
vertices[i].colour = (CImVector){ .b = 255, .g = 255, .r = 255, .a = 255 };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ typedef struct {
|
||||
GLuint VAO, VBO, EBO;
|
||||
RenderBatch* batches;
|
||||
size_t batchCount;
|
||||
int is_outdoor;
|
||||
} GroupMesh;
|
||||
|
||||
GroupMesh create_mesh_from_group(const WMOGroupData* group, const WMORootData* root_data);
|
||||
|
||||
6
src/renderer/render_types.c
Normal file
6
src/renderer/render_types.c
Normal file
@@ -0,0 +1,6 @@
|
||||
//
|
||||
// Created by Tristan on 1/6/2026.
|
||||
//
|
||||
|
||||
#include "render_types.h"
|
||||
|
||||
@@ -7,4 +7,11 @@
|
||||
|
||||
// TODO: move common types out of mesh.h/wmo_structures.h into here for header simplicity when linking :)
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
} C4Quaternion;
|
||||
|
||||
#endif //RENDER_TYPES_H
|
||||
|
||||
@@ -32,7 +32,7 @@ GLuint texture_load_from_blp_memory(const uint8_t* file_data, size_t file_size)
|
||||
case 1: // DXT3
|
||||
glFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
break;
|
||||
case 7:
|
||||
case 7: // DXT5
|
||||
glFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
default:
|
||||
@@ -55,14 +55,15 @@ GLuint texture_load_from_blp_memory(const uint8_t* file_data, size_t file_size)
|
||||
int blockSize = (glFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || glFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (h->mipOffset[i] == 0 || (width == 0 && height == 0)) break;
|
||||
if (h->mipOffset[i] == 0 || (width == 0 && height == 0))
|
||||
break;
|
||||
|
||||
const uint8_t* dataPtr = file_data + h->mipOffset[i];
|
||||
const uint8_t* data_ptr = file_data + h->mipOffset[i];
|
||||
uint32_t mipSize = ((width + 3) / 4) * ((height + 3) / 4) * blockSize;
|
||||
if (mipSize == 0)
|
||||
mipSize = blockSize;
|
||||
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, i, glFormat, width, height, 0, mipSize, dataPtr);
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, i, glFormat, width, height, 0, mipSize, data_ptr);
|
||||
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
12
src/util.c
12
src/util.c
@@ -94,18 +94,6 @@ int create_dir_recursive(const char *full_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: might not need this honestly
|
||||
/*
|
||||
WMOData load_mver_data() {
|
||||
WMOChunkHeader mver_header;
|
||||
WMOData result = {NULL, 0};
|
||||
DWORD bytesRead = 0;
|
||||
// magic;
|
||||
// size;
|
||||
// version;
|
||||
// return;
|
||||
}*/
|
||||
|
||||
WMOData load_wmo_data(ArchiveManager *archives, const char *wmoFileName) {
|
||||
HANDLE hFile = get_file_in_archives(archives, wmoFileName);
|
||||
WMOData result = {NULL, 0};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define WMO_STRUCTS_H
|
||||
#include "StormLib.h"
|
||||
#include "glad/glad.h"
|
||||
#include "../renderer/render_types.h"
|
||||
|
||||
/* ---------- Enums ---------- */
|
||||
typedef enum
|
||||
@@ -110,6 +111,9 @@ typedef struct {
|
||||
uint32_t runTimeData[4]; // 0x30: 16 bytes of runtime data
|
||||
} SMOMaterial;
|
||||
|
||||
// MODD
|
||||
|
||||
|
||||
// MOPT
|
||||
typedef struct {
|
||||
uint16_t startVertex;
|
||||
@@ -222,6 +226,30 @@ typedef struct {
|
||||
uint32_t unk; // 0x40: Unused 20740?
|
||||
} SMOGroupHeader;
|
||||
|
||||
// MODD
|
||||
typedef struct {
|
||||
union {
|
||||
uint32_t header;
|
||||
struct {
|
||||
uint32_t name_index : 24; // Offset into MODN chunk (filename '\0' terminated)
|
||||
uint32_t flags : 8; //
|
||||
} ref;
|
||||
};
|
||||
C3Vector position; // (X, Z, -Y)
|
||||
C4Quaternion orientation; // (X, Y, Z, W)
|
||||
float scale; // scale factor (1.0 normal size)
|
||||
CImVector colour; // Vertex color lighting for the model (B,G,R,A) https://wowdev.wiki/WMO#MODD_chunk
|
||||
} SMODoodadDef;
|
||||
#pragma pack(pop)
|
||||
|
||||
// MODS
|
||||
typedef struct {
|
||||
char name[20]; // Set name (e.g "Set_$DefaultGlobal")
|
||||
uint32_t firstInstance; // index of first doodad instance in this set, into MODD directly
|
||||
uint32_t count; // number of doodad instances in this set
|
||||
uint32_t unused;
|
||||
} SMODoodadSet;
|
||||
|
||||
typedef struct {
|
||||
uint16_t indices;
|
||||
} MOVIChunk;
|
||||
|
||||
Reference in New Issue
Block a user