mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
tr1/output: optimize uvw access
This commit is contained in:
parent
0df70ce4bf
commit
2aa0f2e161
25 changed files with 753 additions and 393 deletions
|
@ -1,8 +1,6 @@
|
|||
#ifdef VERTEX
|
||||
|
||||
uniform int uTime;
|
||||
uniform samplerBuffer uUVW; // texture u, v, layer
|
||||
uniform samplerBuffer uAtlasSizes; // texture x, y, w, h
|
||||
uniform vec2 uViewportSize;
|
||||
uniform mat4 uMatProjection;
|
||||
uniform mat4 uMatModelView;
|
||||
|
@ -11,11 +9,12 @@ uniform bool uWibbleEffect;
|
|||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in int inUVWIdx;
|
||||
layout(location = 3) in vec2 inTrapezoidRatios;
|
||||
layout(location = 4) in int inFlags;
|
||||
layout(location = 5) in vec4 inColor;
|
||||
layout(location = 6) in float inShade;
|
||||
layout(location = 2) in vec3 inUVW;
|
||||
layout(location = 3) in vec4 inTextureSize;
|
||||
layout(location = 4) in vec2 inTrapezoidRatios;
|
||||
layout(location = 5) in int inFlags;
|
||||
layout(location = 6) in vec4 inColor;
|
||||
layout(location = 7) in float inShade;
|
||||
|
||||
out vec4 gWorldPos;
|
||||
out vec3 gNormal;
|
||||
|
@ -37,11 +36,10 @@ void main(void) {
|
|||
waterWibble(gl_Position, uViewportSize, uTime);
|
||||
}
|
||||
|
||||
vec3 uvw = texelFetch(uUVW, int(inUVWIdx)).xyz;
|
||||
gAtlasSize = texelFetch(uAtlasSizes, int(inUVWIdx / 4));
|
||||
gFlags = inFlags;
|
||||
gTexLayer = int(uvw.z);
|
||||
gTexUV = uvw.xy;
|
||||
gAtlasSize = inTextureSize;
|
||||
gTexUV = inUVW.xy;
|
||||
gTexLayer = int(inUVW.z);
|
||||
gTrapezoidRatios = inTrapezoidRatios;
|
||||
if (uTrapezoidFilterEnabled) {
|
||||
gTexUV *= inTrapezoidRatios;
|
||||
|
|
|
@ -9,7 +9,7 @@ uniform int uTime;
|
|||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec2 inDisplacement;
|
||||
layout(location = 2) in int inUVWIdx;
|
||||
layout(location = 2) in vec3 inUVW;
|
||||
layout(location = 3) in float inShade;
|
||||
|
||||
out vec4 gWorldPos;
|
||||
|
@ -28,9 +28,8 @@ void main(void) {
|
|||
waterWibble(gl_Position, uViewportSize, uTime);
|
||||
}
|
||||
|
||||
vec3 uvw = texelFetch(uUVW, int(inUVWIdx)).xyz;
|
||||
gTexUV = uvw.xy;
|
||||
gTexLayer = int(uvw.z);
|
||||
gTexUV = inUVW.xy;
|
||||
gTexLayer = int(inUVW.z);
|
||||
gShade = inShade;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "game/items.h"
|
||||
#include "game/objects/common.h"
|
||||
#include "game/objects/traps/movable_block.h"
|
||||
#include "game/output.h"
|
||||
#include "game/rooms/const.h"
|
||||
#include "game/rooms/enum.h"
|
||||
#include "game/sound/common.h"
|
||||
|
@ -294,6 +295,8 @@ void Room_FlipMap(void)
|
|||
room->effect_num = flipped->effect_num;
|
||||
|
||||
M_AddFlipItems(room);
|
||||
Output_ObserveRoomFlip(flipped);
|
||||
Output_ObserveRoomFlip(room);
|
||||
}
|
||||
|
||||
MovableBlock_HandleFlipMap(RFS_FLIPPED);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
extern void Output_ObserveLevelLoad(void);
|
||||
extern void Output_ObserveLevelUnload(void);
|
||||
extern void Output_ObserveRoomFlip(const ROOM *room);
|
||||
|
||||
extern bool Output_MakeScreenshot(const char *path);
|
||||
extern void Output_BeginScene(void);
|
||||
|
|
|
@ -15,6 +15,7 @@ typedef struct {
|
|||
|
||||
VECTOR *Vector_Create(size_t item_size);
|
||||
VECTOR *Vector_CreateAtCapacity(size_t item_size, int32_t capacity);
|
||||
void Vector_EnsureCapacity(VECTOR *vector, int32_t capacity);
|
||||
void Vector_Free(VECTOR *vector);
|
||||
|
||||
int32_t Vector_IndexOf(const VECTOR *vector, const void *item);
|
||||
|
@ -22,6 +23,7 @@ int32_t Vector_LastIndexOf(const VECTOR *vector, const void *item);
|
|||
bool Vector_Contains(const VECTOR *vector, const void *item);
|
||||
|
||||
void *Vector_Get(VECTOR *vector, int32_t index);
|
||||
void *Vector_GetData(VECTOR *vector);
|
||||
void Vector_Add(VECTOR *vector, const void *item);
|
||||
void Vector_Insert(VECTOR *vector, int32_t index, const void *item);
|
||||
void Vector_Swap(VECTOR *vector, int32_t index1, int32_t index2);
|
||||
|
|
|
@ -42,6 +42,16 @@ VECTOR *Vector_CreateAtCapacity(const size_t item_size, const int32_t capacity)
|
|||
return vector;
|
||||
}
|
||||
|
||||
void Vector_EnsureCapacity(VECTOR *const vector, const int32_t capacity)
|
||||
{
|
||||
if (vector->capacity >= capacity) {
|
||||
return;
|
||||
}
|
||||
vector->capacity = capacity;
|
||||
P(vector).items =
|
||||
Memory_Realloc(P(vector).items, vector->item_size * capacity);
|
||||
}
|
||||
|
||||
void Vector_Free(VECTOR *vector)
|
||||
{
|
||||
Memory_FreePointer(&P(vector).items);
|
||||
|
@ -86,6 +96,11 @@ void *Vector_Get(VECTOR *const vector, const int32_t index)
|
|||
return (void *)(items + index * vector->item_size);
|
||||
}
|
||||
|
||||
void *Vector_GetData(VECTOR *const vector)
|
||||
{
|
||||
return P(vector).items;
|
||||
}
|
||||
|
||||
void Vector_Add(VECTOR *const vector, const void *const item)
|
||||
{
|
||||
M_EnsureCapacity(vector, 1);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "game/level.h"
|
||||
#include "game/output/meshes/common.h"
|
||||
#include "game/output/meshes/rooms.h"
|
||||
#include "game/output/sprites.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/overlay.h"
|
||||
|
@ -440,6 +441,11 @@ void Output_ObserveLevelUnload(void)
|
|||
Output_Meshes_ObserveLevelUnload();
|
||||
}
|
||||
|
||||
void Output_ObserveRoomFlip(const ROOM *room)
|
||||
{
|
||||
Output_Meshes_ObserveRoomFlip(room);
|
||||
}
|
||||
|
||||
void Output_FlushTranslucentObjects(void)
|
||||
{
|
||||
Output_RememberState();
|
||||
|
|
|
@ -158,7 +158,6 @@ void Output_DrawRoomPortals(const ROOM *const room)
|
|||
}
|
||||
}
|
||||
for (int32_t i = 0; i < vertex_count; i++) {
|
||||
vertices[i].uvw_idx = -1;
|
||||
vertices[i].flags =
|
||||
VERT_FLAT_SHADED | VERT_NO_LIGHTING | VERT_NO_CAUSTICS;
|
||||
vertices[i].color = color;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/output/shader.h"
|
||||
#include "game/output/textures.h"
|
||||
|
||||
// clang-format off
|
||||
#define VERT_NO_CAUSTICS 0b0000'0001 // = 0x01
|
||||
|
@ -9,6 +10,15 @@
|
|||
#define VERT_NO_LIGHTING 0b0000'1000 // = 0x08
|
||||
// clang-format on
|
||||
|
||||
typedef struct {
|
||||
// attribute 2
|
||||
OUTPUT_UVW uvw;
|
||||
// attribute 3
|
||||
OUTPUT_TEXTURE_SIZE texture_size;
|
||||
// attribute 4
|
||||
float trapezoid_ratio[2];
|
||||
} OUTPUT_MESH_TEXTURE;
|
||||
|
||||
void Output_Meshes_Init(void);
|
||||
void Output_Meshes_Shutdown(void);
|
||||
void Output_Meshes_UploadProjectionMatrix(void);
|
||||
|
|
|
@ -34,28 +34,33 @@ void Output_Meshes_InitDynamic(void)
|
|||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, normal));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribIPointer(
|
||||
2, 1, GL_UNSIGNED_INT, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, uvw_idx));
|
||||
glVertexAttribPointer(
|
||||
2, 3, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, uvw));
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(
|
||||
3, 2, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, trapezoid_ratio));
|
||||
3, 4, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, texture_size));
|
||||
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribIPointer(
|
||||
4, 1, GL_UNSIGNED_SHORT, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, flags));
|
||||
glVertexAttribPointer(
|
||||
4, 2, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, trapezoid_ratio));
|
||||
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribPointer(
|
||||
5, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, color));
|
||||
glVertexAttribIPointer(
|
||||
5, 1, GL_UNSIGNED_SHORT, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, flags));
|
||||
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(
|
||||
6, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
6, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, color));
|
||||
|
||||
glEnableVertexAttribArray(7);
|
||||
glVertexAttribPointer(
|
||||
7, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(OUTPUT_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_VERTEX, shade));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/output/shader.h"
|
||||
#include "game/output/textures.h"
|
||||
|
||||
#include <libtrx/game/math/types.h>
|
||||
#include <libtrx/game/output/types.h>
|
||||
|
@ -9,13 +10,14 @@
|
|||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
// clang-format off
|
||||
XYZ_F pos; // attribute 0
|
||||
XYZ_F normal; // attribute 1
|
||||
int32_t uvw_idx; // attribute 2
|
||||
float trapezoid_ratio[2]; // attribute 3
|
||||
uint16_t flags; // attribute 4
|
||||
RGBA_8888 color; // attribute 5
|
||||
int16_t shade; // attribute 6
|
||||
XYZ_F pos; // attribute 0
|
||||
XYZ_F normal; // attribute 1
|
||||
OUTPUT_UVW uvw; // attribute 2
|
||||
OUTPUT_TEXTURE_SIZE texture_size; // attribute 3
|
||||
float trapezoid_ratio[2]; // attribute 4
|
||||
uint16_t flags; // attribute 5
|
||||
RGBA_8888 color; // attribute 6
|
||||
int16_t shade; // attribute 7
|
||||
// clang-format on
|
||||
} OUTPUT_MESH_VERTEX;
|
||||
#pragma pack(pop)
|
||||
|
|
|
@ -4,38 +4,45 @@
|
|||
#include "game/output/meshes/common.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/output/utils.h"
|
||||
#include "game/output/vertex_range.h"
|
||||
|
||||
#include <libtrx/debug.h>
|
||||
#include <libtrx/game/output/objects.h>
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
#include <libtrx/memory.h>
|
||||
#include <libtrx/vector.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
// clang-format off
|
||||
XYZ_F pos; // attribute 0
|
||||
XYZ_F normal; // attribute 1
|
||||
int32_t uvw_idx; // attribute 2
|
||||
float trapezoid_ratio[2]; // attribute 3
|
||||
uint16_t flags; // attribute 4
|
||||
RGBA_8888 color; // attribute 5
|
||||
// attribute 0
|
||||
XYZ_F pos;
|
||||
// attribute 1
|
||||
XYZ_F normal;
|
||||
// attribute 5
|
||||
uint16_t flags;
|
||||
// attribute 6
|
||||
RGBA_8888 color;
|
||||
// clang-format on
|
||||
} M_MESH_VERTEX;
|
||||
|
||||
// attribute 7
|
||||
typedef int16_t M_MESH_SHADE;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
int32_t vertex_start;
|
||||
int32_t vertex_count;
|
||||
VECTOR *animated_vertices;
|
||||
} M_BATCH;
|
||||
|
||||
static struct {
|
||||
size_t vertex_count;
|
||||
GLuint vao;
|
||||
GLuint geom_vbo;
|
||||
size_t vertex_count;
|
||||
GLuint tex_vbo;
|
||||
GLuint shade_vbo;
|
||||
M_MESH_VERTEX *geom_vbo_data;
|
||||
OUTPUT_MESH_TEXTURE *tex_vbo_data;
|
||||
M_MESH_SHADE *shade_vbo_data;
|
||||
int32_t *light_idx_map;
|
||||
size_t batch_count;
|
||||
|
@ -65,8 +72,18 @@ static uint16_t M_GetFlags(const OBJECT_MESH *const mesh, const bool flat)
|
|||
return flags;
|
||||
}
|
||||
|
||||
static void M_FillTexture(
|
||||
OUTPUT_MESH_TEXTURE *const out_texture, const int32_t uvw_idx,
|
||||
const float trapezoid_ratio_x, const float trapezoid_ratio_y)
|
||||
{
|
||||
out_texture->uvw = Output_Textures_GetUVW(uvw_idx);
|
||||
out_texture->texture_size = Output_Textures_GetAtlasSize(uvw_idx / 4);
|
||||
out_texture->trapezoid_ratio[0] = trapezoid_ratio_x;
|
||||
out_texture->trapezoid_ratio[1] = trapezoid_ratio_y;
|
||||
}
|
||||
|
||||
static void M_FillVertex(
|
||||
M_MESH_VERTEX *const out_vertex, const int32_t uvw_idx,
|
||||
M_MESH_VERTEX *out_vertex, const int32_t uvw_idx,
|
||||
const OBJECT_MESH *const mesh, const int32_t vertex_idx,
|
||||
const int32_t palette_idx)
|
||||
{
|
||||
|
@ -75,7 +92,6 @@ static void M_FillVertex(
|
|||
out_vertex->pos = (XYZ_F) { .x = pos.x, .y = pos.y, .z = pos.z };
|
||||
out_vertex->normal =
|
||||
(XYZ_F) { .x = normal.x, .y = -normal.y, .z = normal.z };
|
||||
out_vertex->uvw_idx = uvw_idx;
|
||||
out_vertex->flags = M_GetFlags(mesh, palette_idx >= 0);
|
||||
if (palette_idx >= 0) {
|
||||
out_vertex->color =
|
||||
|
@ -85,57 +101,63 @@ static void M_FillVertex(
|
|||
}
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillFace4(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX *out_vertex,
|
||||
const FACE4 *const face, const bool flat)
|
||||
static void M_FillFace4(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX **out_vertex,
|
||||
OUTPUT_MESH_TEXTURE **out_texture, const FACE4 *const face, const bool flat)
|
||||
{
|
||||
for (int32_t i = 0; i < OUTPUT_QUAD_VERTICES; i++) {
|
||||
const int32_t j = OUTPUT_QUAD_TO_FAN(i);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + j;
|
||||
M_FillVertex(
|
||||
out_vertex, uvw_idx, mesh, face->vertices[j],
|
||||
*out_vertex, uvw_idx, mesh, face->vertices[j],
|
||||
flat ? face->palette_idx : -1);
|
||||
out_vertex->trapezoid_ratio[0] = face->texture_zw[j].z;
|
||||
out_vertex->trapezoid_ratio[1] = face->texture_zw[j].w;
|
||||
out_vertex++;
|
||||
M_FillTexture(
|
||||
*out_texture, uvw_idx, face->texture_zw[j].z,
|
||||
face->texture_zw[j].w);
|
||||
(*out_vertex)++;
|
||||
(*out_texture)++;
|
||||
}
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillFace3(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX *out_vertex,
|
||||
const FACE3 *const face, const bool flat)
|
||||
static void M_FillFace3(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX **out_vertex,
|
||||
OUTPUT_MESH_TEXTURE **out_texture, const FACE3 *const face, const bool flat)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(mesh);
|
||||
for (int32_t i = 0; i < OUTPUT_TRI_VERTICES; i++) {
|
||||
const int32_t j = OUTPUT_TRI_TO_FAN(i);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + j;
|
||||
M_FillVertex(
|
||||
out_vertex, uvw_idx, mesh, face->vertices[j],
|
||||
*out_vertex, uvw_idx, mesh, face->vertices[j],
|
||||
flat ? face->palette_idx : -1);
|
||||
out_vertex->trapezoid_ratio[0] = 1.0f;
|
||||
out_vertex->trapezoid_ratio[1] = 1.0f;
|
||||
out_vertex++;
|
||||
M_FillTexture(*out_texture, uvw_idx, 1.0f, 1.0f);
|
||||
(*out_vertex)++;
|
||||
(*out_texture)++;
|
||||
}
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
static void M_UpdateGeometry(const OBJECT_MESH *const mesh)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(mesh);
|
||||
M_MESH_VERTEX *out_vertex = &m_Priv.geom_vbo_data[batch->vertex_start];
|
||||
OUTPUT_MESH_TEXTURE *out_texture =
|
||||
&m_Priv.tex_vbo_data[batch->vertex_start];
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_tex_face4s; i++) {
|
||||
out_vertex = M_FillFace4(mesh, out_vertex, &mesh->tex_face4s[i], false);
|
||||
M_FillFace4(
|
||||
mesh, &out_vertex, &out_texture, &mesh->tex_face4s[i], false);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_tex_face3s; i++) {
|
||||
out_vertex = M_FillFace3(mesh, out_vertex, &mesh->tex_face3s[i], false);
|
||||
M_FillFace3(
|
||||
mesh, &out_vertex, &out_texture, &mesh->tex_face3s[i], false);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face4s; i++) {
|
||||
out_vertex = M_FillFace4(mesh, out_vertex, &mesh->flat_face4s[i], true);
|
||||
M_FillFace4(
|
||||
mesh, &out_vertex, &out_texture, &mesh->flat_face4s[i], true);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face3s; i++) {
|
||||
out_vertex = M_FillFace3(mesh, out_vertex, &mesh->flat_face3s[i], true);
|
||||
M_FillFace3(
|
||||
mesh, &out_vertex, &out_texture, &mesh->flat_face3s[i], true);
|
||||
}
|
||||
|
||||
#define SET(v, j) light_idx_map[v] = face->vertices[j];
|
||||
|
@ -241,6 +263,12 @@ static void M_UpdateVertices(void)
|
|||
m_Priv.vertex_count * sizeof(M_MESH_VERTEX), m_Priv.geom_vbo_data,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
m_Priv.vertex_count * sizeof(OUTPUT_MESH_TEXTURE), m_Priv.tex_vbo_data,
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
|
@ -268,54 +296,105 @@ static void M_PrepareBuffers(void)
|
|||
}
|
||||
m_Priv.vertex_count = last_vertex;
|
||||
|
||||
int32_t current_vertex = 0;
|
||||
for (int32_t i = 0; i < Object_GetMeshCount(); i++) {
|
||||
const OBJECT_MESH *const obj_mesh = Object_GetMesh(i);
|
||||
M_BATCH *const batch = &m_Priv.batches[i];
|
||||
batch->animated_vertices = Vector_Create(sizeof(OUTPUT_VERTEX_RANGE));
|
||||
for (int32_t j = 0; j < obj_mesh->num_tex_face4s; j++) {
|
||||
const FACE4 *const face = &obj_mesh->tex_face4s[j];
|
||||
if (Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
Vector_Add(
|
||||
batch->animated_vertices,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = current_vertex,
|
||||
.vertex_count = OUTPUT_QUAD_VERTICES,
|
||||
});
|
||||
}
|
||||
current_vertex += OUTPUT_QUAD_VERTICES;
|
||||
}
|
||||
for (int32_t j = 0; j < obj_mesh->num_tex_face3s; j++) {
|
||||
const FACE3 *const face = &obj_mesh->tex_face3s[j];
|
||||
if (Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
Vector_Add(
|
||||
batch->animated_vertices,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = current_vertex,
|
||||
.vertex_count = OUTPUT_TRI_VERTICES,
|
||||
});
|
||||
}
|
||||
current_vertex += OUTPUT_TRI_VERTICES;
|
||||
}
|
||||
current_vertex += obj_mesh->num_flat_face4s * OUTPUT_QUAD_VERTICES;
|
||||
current_vertex += obj_mesh->num_flat_face3s * OUTPUT_TRI_VERTICES;
|
||||
Output_GlueVertexRanges(batch->animated_vertices);
|
||||
}
|
||||
|
||||
m_Priv.geom_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(M_MESH_VERTEX));
|
||||
m_Priv.tex_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(OUTPUT_MESH_TEXTURE));
|
||||
m_Priv.shade_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(M_MESH_SHADE));
|
||||
m_Priv.light_idx_map = Memory_Alloc(m_Priv.vertex_count * sizeof(int32_t));
|
||||
|
||||
glGenVertexArrays(1, &m_Priv.vao);
|
||||
glGenBuffers(1, &m_Priv.geom_vbo);
|
||||
glGenBuffers(1, &m_Priv.tex_vbo);
|
||||
glGenBuffers(1, &m_Priv.shade_vbo);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
glBindVertexArray(m_Priv.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
// attribute 0: position
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(
|
||||
0, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, pos));
|
||||
|
||||
// attribute 1: normal
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(
|
||||
1, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, normal));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
// attribute 5: flags
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribIPointer(
|
||||
2, 1, GL_UNSIGNED_INT, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, uvw_idx));
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(
|
||||
3, 2, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, trapezoid_ratio));
|
||||
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribIPointer(
|
||||
4, 1, GL_UNSIGNED_SHORT, sizeof(M_MESH_VERTEX),
|
||||
5, 1, GL_UNSIGNED_SHORT, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, flags));
|
||||
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribPointer(
|
||||
5, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, color));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
// attribute 6: color
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(
|
||||
6, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
6, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, color));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
// attribute 2: uvw
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(
|
||||
2, 3, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, uvw));
|
||||
|
||||
// attribute 3: texture size
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(
|
||||
3, 4, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, texture_size));
|
||||
|
||||
// attribute 4: trapezoid ratios
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribPointer(
|
||||
4, 2, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, trapezoid_ratio));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
|
||||
// attribute 7: shade
|
||||
glEnableVertexAttribArray(7);
|
||||
glVertexAttribPointer(
|
||||
7, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
|
||||
M_UpdateVertices();
|
||||
}
|
||||
|
@ -332,13 +411,21 @@ static void M_FreeBuffers(void)
|
|||
glDeleteBuffers(1, &m_Priv.geom_vbo);
|
||||
m_Priv.geom_vbo = 0;
|
||||
}
|
||||
if (m_Priv.tex_vbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.tex_vbo);
|
||||
m_Priv.tex_vbo = 0;
|
||||
}
|
||||
if (m_Priv.shade_vbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.shade_vbo);
|
||||
m_Priv.shade_vbo = 0;
|
||||
}
|
||||
Memory_FreePointer(&m_Priv.geom_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.tex_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.shade_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.light_idx_map);
|
||||
for (int32_t i = 0; i < (int32_t)m_Priv.batch_count; i++) {
|
||||
Vector_Free(m_Priv.batches[i].animated_vertices);
|
||||
}
|
||||
Memory_FreePointer(&m_Priv.batches);
|
||||
}
|
||||
|
||||
|
@ -362,6 +449,65 @@ void Output_Meshes_ObserveLevelUnloadObjects(void)
|
|||
M_FreeBuffers();
|
||||
}
|
||||
|
||||
static void M_FillAnimatedTextures(const OBJECT_MESH *const obj_mesh)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(obj_mesh);
|
||||
OUTPUT_MESH_TEXTURE *out_texture =
|
||||
&m_Priv.tex_vbo_data[batch->vertex_start];
|
||||
for (int32_t j = 0; j < obj_mesh->num_tex_face4s; j++) {
|
||||
const FACE4 *const face = &obj_mesh->tex_face4s[j];
|
||||
if (!Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
out_texture += OUTPUT_QUAD_VERTICES;
|
||||
continue;
|
||||
}
|
||||
for (int32_t k = 0; k < OUTPUT_QUAD_VERTICES; k++) {
|
||||
const int32_t l = OUTPUT_QUAD_TO_FAN(k);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + l;
|
||||
M_FillTexture(
|
||||
out_texture, uvw_idx, face->texture_zw[l].z,
|
||||
face->texture_zw[l].w);
|
||||
out_texture++;
|
||||
}
|
||||
}
|
||||
for (int32_t j = 0; j < obj_mesh->num_tex_face3s; j++) {
|
||||
const FACE3 *const face = &obj_mesh->tex_face3s[j];
|
||||
if (!Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
out_texture += OUTPUT_TRI_VERTICES;
|
||||
continue;
|
||||
}
|
||||
for (int32_t k = 0; k < OUTPUT_TRI_VERTICES; k++) {
|
||||
const int32_t l = OUTPUT_TRI_TO_FAN(k);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + l;
|
||||
M_FillTexture(out_texture, uvw_idx, 1.0f, 1.0f);
|
||||
out_texture++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_UpdateAnimedTextures(const OBJECT_MESH *const obj_mesh)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(obj_mesh);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
for (int32_t i = 0; i < batch->animated_vertices->count; i++) {
|
||||
const OUTPUT_VERTEX_RANGE *const range =
|
||||
Vector_Get(batch->animated_vertices, i);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
range->vertex_start * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
range->vertex_count * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
&m_Priv.tex_vbo_data[range->vertex_start]);
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Meshes_ObserveTextureAnimationObjects(void)
|
||||
{
|
||||
for (int32_t i = 0; i < Object_GetMeshCount(); i++) {
|
||||
const OBJECT_MESH *const obj_mesh = Object_GetMesh(i);
|
||||
M_FillAnimatedTextures(obj_mesh);
|
||||
M_UpdateAnimedTextures(obj_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Meshes_ObserveObjectMeshSwap(
|
||||
const OBJECT_MESH *const mesh_1, const OBJECT_MESH *const mesh_2)
|
||||
{
|
||||
|
@ -393,6 +539,14 @@ void Output_Meshes_ObserveObjectMeshUpdate(const OBJECT_MESH *const mesh)
|
|||
batch->vertex_count * sizeof(M_MESH_VERTEX),
|
||||
&m_Priv.geom_vbo_data[batch->vertex_start]);
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
GFX_TRACK_SUBDATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
batch->vertex_start * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
batch->vertex_count * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
&m_Priv.tex_vbo_data[batch->vertex_start]);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
void Output_Meshes_RenderObjectMesh(
|
||||
|
@ -421,11 +575,7 @@ void Output_Meshes_RenderObjectMesh(
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetAtlasSizesTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
Output_Shader_UploadWibbleEffect(m_Shader, false);
|
||||
|
|
|
@ -9,6 +9,7 @@ void Output_Meshes_InitObjects(void);
|
|||
void Output_Meshes_ShutdownObjects(void);
|
||||
void Output_Meshes_ObserveLevelLoadObjects(void);
|
||||
void Output_Meshes_ObserveLevelUnloadObjects(void);
|
||||
void Output_Meshes_ObserveTextureAnimationObjects(void);
|
||||
|
||||
void Output_Meshes_RenderObjectMesh(
|
||||
const MATRIX *matrix, RGB_F tint, const OBJECT_MESH *mesh);
|
||||
|
|
|
@ -4,22 +4,23 @@
|
|||
#include "game/output/meshes/common.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/output/utils.h"
|
||||
#include "game/output/vertex_range.h"
|
||||
#include "game/random.h"
|
||||
#include "game/room.h"
|
||||
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
#include <libtrx/memory.h>
|
||||
#include <libtrx/vector.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
// clang-format off
|
||||
XYZ_F pos; // attribute 0
|
||||
int32_t uvw_idx; // attribute 2
|
||||
float trapezoid_ratio[2]; // attribute 3
|
||||
uint16_t flags; // attribute 4
|
||||
// clang-format on
|
||||
// attribute 0
|
||||
XYZ_F pos;
|
||||
// attribute 5
|
||||
uint16_t flags;
|
||||
} M_MESH_VERTEX;
|
||||
|
||||
// attribute 7
|
||||
typedef int16_t M_MESH_SHADE;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -27,14 +28,17 @@ typedef struct {
|
|||
int32_t vertex_start;
|
||||
int32_t vertex_count;
|
||||
int16_t *caustics;
|
||||
VECTOR *animated_vertices;
|
||||
} M_BATCH;
|
||||
|
||||
static struct {
|
||||
size_t vertex_count;
|
||||
GLuint vao;
|
||||
GLuint geom_vbo;
|
||||
size_t vertex_count;
|
||||
GLuint tex_vbo;
|
||||
GLuint shade_vbo;
|
||||
M_MESH_VERTEX *geom_vbo_data;
|
||||
OUTPUT_MESH_TEXTURE *tex_vbo_data;
|
||||
M_MESH_SHADE *shade_vbo_data;
|
||||
size_t batch_count;
|
||||
M_BATCH *batches;
|
||||
|
@ -69,55 +73,67 @@ static M_BATCH *M_GetBatch(const ROOM *const room)
|
|||
}
|
||||
|
||||
static void M_FillVertex(
|
||||
M_MESH_VERTEX *const out_vertex, const int32_t uvw_idx, const XYZ_16 pos,
|
||||
const uint16_t flags)
|
||||
M_MESH_VERTEX *const out_vertex, const XYZ_16 pos, const uint16_t flags)
|
||||
{
|
||||
out_vertex->pos = (XYZ_F) { .x = pos.x, .y = pos.y, .z = pos.z };
|
||||
out_vertex->uvw_idx = uvw_idx;
|
||||
out_vertex->flags = flags & NO_VERT_MOVE ? VERT_NO_CAUSTICS : 0;
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillRoomFace4(
|
||||
const ROOM *const room, M_MESH_VERTEX *out_vertex, const FACE4 *const face)
|
||||
static void M_FillTexture(
|
||||
OUTPUT_MESH_TEXTURE *const out_texture, const int32_t uvw_idx,
|
||||
const float trapezoid_ratio_x, const float trapezoid_ratio_y)
|
||||
{
|
||||
out_texture->uvw = Output_Textures_GetUVW(uvw_idx);
|
||||
out_texture->texture_size = Output_Textures_GetAtlasSize(uvw_idx / 4);
|
||||
out_texture->trapezoid_ratio[0] = trapezoid_ratio_x;
|
||||
out_texture->trapezoid_ratio[1] = trapezoid_ratio_y;
|
||||
}
|
||||
|
||||
static void M_FillRoomFace4(
|
||||
const ROOM *const room, M_MESH_VERTEX **out_vertex,
|
||||
OUTPUT_MESH_TEXTURE **out_texture, const FACE4 *const face)
|
||||
{
|
||||
for (int32_t i = 0; i < OUTPUT_QUAD_VERTICES; i++) {
|
||||
const int32_t j = OUTPUT_QUAD_TO_FAN(i);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + j;
|
||||
const ROOM_VERTEX *const room_vertex =
|
||||
&room->mesh.vertices[face->vertices[j]];
|
||||
M_FillVertex(out_vertex, uvw_idx, room_vertex->pos, room_vertex->flags);
|
||||
out_vertex->trapezoid_ratio[0] = face->texture_zw[j].z;
|
||||
out_vertex->trapezoid_ratio[1] = face->texture_zw[j].w;
|
||||
out_vertex++;
|
||||
M_FillVertex(*out_vertex, room_vertex->pos, room_vertex->flags);
|
||||
M_FillTexture(
|
||||
*out_texture, uvw_idx, face->texture_zw[j].z,
|
||||
face->texture_zw[j].w);
|
||||
(*out_vertex)++;
|
||||
(*out_texture)++;
|
||||
}
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillRoomFace3(
|
||||
const ROOM *const room, M_MESH_VERTEX *out_vertex, const FACE3 *const face)
|
||||
static void M_FillRoomFace3(
|
||||
const ROOM *const room, M_MESH_VERTEX **out_vertex,
|
||||
OUTPUT_MESH_TEXTURE **out_texture, const FACE3 *const face)
|
||||
{
|
||||
for (int32_t i = 0; i < OUTPUT_TRI_VERTICES; i++) {
|
||||
const int32_t j = OUTPUT_TRI_TO_FAN(i);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + j;
|
||||
const ROOM_VERTEX *const room_vertex =
|
||||
&room->mesh.vertices[face->vertices[j]];
|
||||
M_FillVertex(out_vertex, uvw_idx, room_vertex->pos, room_vertex->flags);
|
||||
out_vertex->trapezoid_ratio[0] = 1.0f;
|
||||
out_vertex->trapezoid_ratio[1] = 1.0f;
|
||||
out_vertex++;
|
||||
M_FillVertex(*out_vertex, room_vertex->pos, room_vertex->flags);
|
||||
M_FillTexture(*out_texture, uvw_idx, 1.0f, 1.0f);
|
||||
(*out_vertex)++;
|
||||
(*out_texture)++;
|
||||
}
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
static void M_UpdateRoomGeometry(const ROOM *const room)
|
||||
{
|
||||
M_BATCH *const batch = &m_Priv.batches[Room_GetNumber(room)];
|
||||
M_MESH_VERTEX *out_vertex = &m_Priv.geom_vbo_data[batch->vertex_start];
|
||||
OUTPUT_MESH_TEXTURE *out_texture =
|
||||
&m_Priv.tex_vbo_data[batch->vertex_start];
|
||||
for (int32_t i = 0; i < room->mesh.num_face4s; i++) {
|
||||
out_vertex = M_FillRoomFace4(room, out_vertex, &room->mesh.face4s[i]);
|
||||
M_FillRoomFace4(room, &out_vertex, &out_texture, &room->mesh.face4s[i]);
|
||||
}
|
||||
for (int32_t i = 0; i < room->mesh.num_face3s; i++) {
|
||||
out_vertex = M_FillRoomFace3(room, out_vertex, &room->mesh.face3s[i]);
|
||||
M_FillRoomFace3(room, &out_vertex, &out_texture, &room->mesh.face3s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +176,12 @@ static void M_UpdateVertices(void)
|
|||
m_Priv.vertex_count * sizeof(M_MESH_VERTEX), m_Priv.geom_vbo_data,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
m_Priv.vertex_count * sizeof(OUTPUT_MESH_TEXTURE), m_Priv.tex_vbo_data,
|
||||
GL_DYNAMIC_DRAW); // allow animating textures
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
|
@ -181,10 +203,8 @@ static void M_PrepareBuffers(void)
|
|||
Memory_Alloc(room->mesh.num_vertices * sizeof(int16_t));
|
||||
batch->vertex_start = last_vertex;
|
||||
batch->vertex_count = 0;
|
||||
batch->vertex_count +=
|
||||
Room_Get(i)->mesh.num_face4s * OUTPUT_QUAD_VERTICES;
|
||||
batch->vertex_count +=
|
||||
Room_Get(i)->mesh.num_face3s * OUTPUT_TRI_VERTICES;
|
||||
batch->vertex_count += room->mesh.num_face4s * OUTPUT_QUAD_VERTICES;
|
||||
batch->vertex_count += room->mesh.num_face3s * OUTPUT_TRI_VERTICES;
|
||||
last_vertex += batch->vertex_count;
|
||||
|
||||
for (int32_t j = 0; j < room->mesh.num_vertices; j++) {
|
||||
|
@ -192,50 +212,96 @@ static void M_PrepareBuffers(void)
|
|||
m_CausticsTable[(room->mesh.num_vertices - j) % WIBBLE_SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
m_Priv.vertex_count = last_vertex;
|
||||
|
||||
int32_t current_vertex = 0;
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
const ROOM *const room = Room_Get(i);
|
||||
M_BATCH *const batch = M_GetBatch(room);
|
||||
batch->animated_vertices = Vector_Create(sizeof(OUTPUT_VERTEX_RANGE));
|
||||
for (int32_t j = 0; j < room->mesh.num_face4s; j++) {
|
||||
const FACE4 *const face = &room->mesh.face4s[j];
|
||||
if (Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
Vector_Add(
|
||||
batch->animated_vertices,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = current_vertex,
|
||||
.vertex_count = OUTPUT_QUAD_VERTICES,
|
||||
});
|
||||
}
|
||||
current_vertex += OUTPUT_QUAD_VERTICES;
|
||||
}
|
||||
for (int32_t j = 0; j < room->mesh.num_face3s; j++) {
|
||||
const FACE3 *const face = &room->mesh.face3s[j];
|
||||
if (Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
Vector_Add(
|
||||
batch->animated_vertices,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = current_vertex,
|
||||
.vertex_count = OUTPUT_TRI_VERTICES,
|
||||
});
|
||||
}
|
||||
current_vertex += OUTPUT_TRI_VERTICES;
|
||||
}
|
||||
Output_GlueVertexRanges(batch->animated_vertices);
|
||||
}
|
||||
|
||||
m_Priv.geom_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(M_MESH_VERTEX));
|
||||
m_Priv.tex_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(OUTPUT_MESH_TEXTURE));
|
||||
m_Priv.shade_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(M_MESH_SHADE));
|
||||
|
||||
glGenVertexArrays(1, &m_Priv.vao);
|
||||
glGenBuffers(1, &m_Priv.geom_vbo);
|
||||
glGenBuffers(1, &m_Priv.tex_vbo);
|
||||
glGenBuffers(1, &m_Priv.shade_vbo);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
glBindVertexArray(m_Priv.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
// attribute 0: position
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(
|
||||
0, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, pos));
|
||||
|
||||
// ignore attribute 1 (normals) - rooms never have reflective faces
|
||||
// attribute 1: normal (ignore)
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
// attribute 5: flags
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribIPointer(
|
||||
2, 1, GL_UNSIGNED_INT, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, uvw_idx));
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(
|
||||
3, 2, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, trapezoid_ratio));
|
||||
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribIPointer(
|
||||
4, 1, GL_UNSIGNED_SHORT, sizeof(M_MESH_VERTEX),
|
||||
5, 1, GL_UNSIGNED_SHORT, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, flags));
|
||||
|
||||
// ignore attribute 5 (mesh color) - rooms only ever use textured faces
|
||||
// attribute 6: mesh color (ignore)
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
// attribute 2: uvw
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(
|
||||
2, 3, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, uvw));
|
||||
|
||||
// attribute 3: texture size
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(
|
||||
3, 4, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, texture_size));
|
||||
|
||||
// attribute 4: trapezoid ratios
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribPointer(
|
||||
4, 2, GL_FLOAT, GL_FALSE, sizeof(OUTPUT_MESH_TEXTURE),
|
||||
(void *)(intptr_t)offsetof(OUTPUT_MESH_TEXTURE, trapezoid_ratio));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
glEnableVertexAttribArray(6);
|
||||
|
||||
// attribute 7 (shade)
|
||||
glEnableVertexAttribArray(7);
|
||||
glVertexAttribPointer(
|
||||
6, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
7, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
|
||||
M_UpdateVertices();
|
||||
}
|
||||
|
@ -252,13 +318,19 @@ static void M_FreeBuffers(void)
|
|||
glDeleteBuffers(1, &m_Priv.geom_vbo);
|
||||
m_Priv.geom_vbo = 0;
|
||||
}
|
||||
if (m_Priv.tex_vbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.tex_vbo);
|
||||
m_Priv.tex_vbo = 0;
|
||||
}
|
||||
if (m_Priv.shade_vbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.shade_vbo);
|
||||
m_Priv.shade_vbo = 0;
|
||||
}
|
||||
Memory_FreePointer(&m_Priv.geom_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.tex_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.shade_vbo_data);
|
||||
for (int32_t i = 0; i < (int32_t)m_Priv.batch_count; i++) {
|
||||
Vector_Free(m_Priv.batches[i].animated_vertices);
|
||||
Memory_FreePointer(&m_Priv.batches[i].caustics);
|
||||
}
|
||||
Memory_FreePointer(&m_Priv.batches);
|
||||
|
@ -285,6 +357,71 @@ void Output_Meshes_ObserveLevelLoadRooms(void)
|
|||
M_PrepareBuffers();
|
||||
}
|
||||
|
||||
static void M_FillAnimatedTextures(const ROOM *const room)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(room);
|
||||
OUTPUT_MESH_TEXTURE *out_texture =
|
||||
&m_Priv.tex_vbo_data[batch->vertex_start];
|
||||
for (int32_t j = 0; j < room->mesh.num_face4s; j++) {
|
||||
const FACE4 *const face = &room->mesh.face4s[j];
|
||||
if (!Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
out_texture += OUTPUT_QUAD_VERTICES;
|
||||
continue;
|
||||
}
|
||||
for (int32_t k = 0; k < OUTPUT_QUAD_VERTICES; k++) {
|
||||
const int32_t l = OUTPUT_QUAD_TO_FAN(k);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + l;
|
||||
M_FillTexture(
|
||||
out_texture, uvw_idx, face->texture_zw[l].z,
|
||||
face->texture_zw[l].w);
|
||||
out_texture++;
|
||||
}
|
||||
}
|
||||
for (int32_t j = 0; j < room->mesh.num_face3s; j++) {
|
||||
const FACE3 *const face = &room->mesh.face3s[j];
|
||||
if (!Output_Textures_IsObjectTextureAnimated(face->texture_idx)) {
|
||||
out_texture += OUTPUT_TRI_VERTICES;
|
||||
continue;
|
||||
}
|
||||
for (int32_t k = 0; k < OUTPUT_TRI_VERTICES; k++) {
|
||||
const int32_t l = OUTPUT_TRI_TO_FAN(k);
|
||||
const int32_t uvw_idx = face->texture_idx * 4 + l;
|
||||
M_FillTexture(out_texture, uvw_idx, 1.0f, 1.0f);
|
||||
out_texture++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_UpdateAnimatedTextures(const ROOM *const room)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(room);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.tex_vbo);
|
||||
for (int32_t i = 0; i < batch->animated_vertices->count; i++) {
|
||||
const OUTPUT_VERTEX_RANGE *const range =
|
||||
Vector_Get(batch->animated_vertices, i);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
range->vertex_start * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
range->vertex_count * sizeof(OUTPUT_MESH_TEXTURE),
|
||||
&m_Priv.tex_vbo_data[range->vertex_start]);
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Meshes_ObserveTextureAnimationRooms(void)
|
||||
{
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
const ROOM *const room = Room_Get(i);
|
||||
M_FillAnimatedTextures(room);
|
||||
M_UpdateAnimatedTextures(room);
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Meshes_ObserveRoomFlip(const ROOM *const room)
|
||||
{
|
||||
M_FillAnimatedTextures(room);
|
||||
M_UpdateAnimatedTextures(room);
|
||||
}
|
||||
|
||||
void Output_Meshes_RenderRoomMesh(
|
||||
const MATRIX *const matrix, const RGB_F tint, const ROOM *const room)
|
||||
{
|
||||
|
@ -311,11 +448,7 @@ void Output_Meshes_RenderRoomMesh(
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetAtlasSizesTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
if (Output_GetWibbleEffect()) {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
void Output_Meshes_InitRooms(void);
|
||||
void Output_Meshes_ShutdownRooms(void);
|
||||
void Output_Meshes_ObserveLevelLoadRooms(void);
|
||||
void Output_Meshes_ObserveTextureAnimationRooms(void);
|
||||
void Output_Meshes_ObserveRoomFlip(const ROOM *room);
|
||||
|
||||
void Output_Meshes_RenderRoomMesh(
|
||||
const MATRIX *matrix, RGB_F tint, const ROOM *room);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
typedef enum {
|
||||
M_UNIFORM_TIME,
|
||||
M_UNIFORM_TEX_ATLAS,
|
||||
M_UNIFORM_TEX_ATLAS_SIZES,
|
||||
M_UNIFORM_TEX_UVW,
|
||||
M_UNIFORM_TEX_ENV_MAP,
|
||||
M_UNIFORM_SMOOTHING_ENABLED,
|
||||
M_UNIFORM_ALPHA_DISCARD_ENABLED,
|
||||
|
@ -52,8 +50,6 @@ OUTPUT_SHADER *Output_Shader_Create(const char *const path)
|
|||
const char *const uniform_names[] = {
|
||||
[M_UNIFORM_TIME] = "uTime",
|
||||
[M_UNIFORM_TEX_ATLAS] = "uTexAtlas",
|
||||
[M_UNIFORM_TEX_ATLAS_SIZES] = "uAtlasSizes",
|
||||
[M_UNIFORM_TEX_UVW] = "uUVW",
|
||||
[M_UNIFORM_TEX_ENV_MAP] = "uTexEnvMap",
|
||||
[M_UNIFORM_SMOOTHING_ENABLED] = "uSmoothingEnabled",
|
||||
[M_UNIFORM_ALPHA_DISCARD_ENABLED] = "uAlphaDiscardEnabled",
|
||||
|
@ -77,9 +73,7 @@ OUTPUT_SHADER *Output_Shader_Create(const char *const path)
|
|||
|
||||
GFX_GL_Program_Bind(&shader->program);
|
||||
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ATLAS], 0);
|
||||
glUniform1i(shader->uniforms[M_UNIFORM_TEX_UVW], 1);
|
||||
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ENV_MAP], 2);
|
||||
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ATLAS_SIZES], 3);
|
||||
glUniform1i(shader->uniforms[M_UNIFORM_TEX_ENV_MAP], 1);
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "game/output/shader.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/output/utils.h"
|
||||
#include "game/output/vertex_range.h"
|
||||
#include "game/room.h"
|
||||
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
|
@ -22,7 +23,7 @@ typedef struct {
|
|||
} displacement;
|
||||
|
||||
// attribute 2
|
||||
int32_t uvw_idx;
|
||||
OUTPUT_UVW uvw;
|
||||
} M_SPRITE_VERTEX;
|
||||
|
||||
typedef uint16_t M_SPRITE_SHADE;
|
||||
|
@ -57,6 +58,7 @@ static struct {
|
|||
M_SPRITE_BUFFER sprite_buf;
|
||||
size_t room_batch_count;
|
||||
M_ROOM_BATCH *room_batches;
|
||||
VECTOR *animated_vertices;
|
||||
} m_LevelData = {};
|
||||
|
||||
static struct {
|
||||
|
@ -71,8 +73,8 @@ static void M_MakeQuad(
|
|||
|
||||
for (int32_t k = 0; k < 4; k++) {
|
||||
out_quad[k].pos = (XYZ_F) { .x = pos.x, .y = pos.y, .z = pos.z };
|
||||
out_quad[k].uvw_idx =
|
||||
Output_Textures_GetSpritesUVWsBase() + sprite_idx * 4 + k;
|
||||
out_quad[k].uvw = Output_Textures_GetUVW(
|
||||
Output_Textures_GetSpritesUVWsBase() + sprite_idx * 4 + k);
|
||||
}
|
||||
|
||||
out_quad[0].displacement.x = sprite->x0;
|
||||
|
@ -144,9 +146,9 @@ static void M_PrepareBuffer(
|
|||
(void *)(intptr_t)offsetof(M_SPRITE_VERTEX, displacement));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribIPointer(
|
||||
2, 1, GL_UNSIGNED_INT, sizeof(M_SPRITE_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_SPRITE_VERTEX, uvw_idx));
|
||||
glVertexAttribPointer(
|
||||
2, 3, GL_FLOAT, GL_FALSE, sizeof(M_SPRITE_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_SPRITE_VERTEX, uvw));
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer->shade_vbo);
|
||||
glEnableVertexAttribArray(3);
|
||||
|
@ -192,8 +194,6 @@ static void M_DrawBuffer(
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
|
@ -214,9 +214,29 @@ static void M_PrepareLevelBatches(void)
|
|||
room_batch->quad_count = room->mesh.num_sprites;
|
||||
current_quad += room->mesh.num_sprites;
|
||||
}
|
||||
|
||||
Vector_Clear(m_LevelData.animated_vertices);
|
||||
int32_t current_vertex = 0;
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
const ROOM *const room = Room_Get(i);
|
||||
for (int32_t j = 0; j < room->mesh.num_sprites; j++) {
|
||||
const ROOM_SPRITE *const room_sprite = &room->mesh.sprites[j];
|
||||
const int16_t sprite_idx = room_sprite->texture;
|
||||
if (Output_Textures_IsSpriteTextureAnimated(sprite_idx)) {
|
||||
Vector_Add(
|
||||
m_LevelData.animated_vertices,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = current_vertex,
|
||||
.vertex_count = OUTPUT_QUAD_VERTICES,
|
||||
});
|
||||
}
|
||||
current_vertex += OUTPUT_QUAD_VERTICES;
|
||||
}
|
||||
}
|
||||
Output_GlueVertexRanges(m_LevelData.animated_vertices);
|
||||
}
|
||||
|
||||
static void M_UpdateRoomGeometry(const ROOM *const room)
|
||||
static void M_FillRoomGeometry(const ROOM *const room)
|
||||
{
|
||||
int32_t current_vertex = 0;
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
|
@ -230,6 +250,7 @@ static void M_UpdateRoomGeometry(const ROOM *const room)
|
|||
|
||||
M_SPRITE_VERTEX quad[4];
|
||||
M_MakeQuad(quad, sprite_idx, pos);
|
||||
|
||||
for (int32_t k = 0; k < OUTPUT_QUAD_VERTICES; k++) {
|
||||
m_LevelData.sprite_buf.geom_vbo_data[current_vertex] =
|
||||
quad[OUTPUT_QUAD_TO_FAN(k)];
|
||||
|
@ -273,12 +294,12 @@ static void M_PrepareLevelBuffers(void)
|
|||
M_PrepareBuffer(&m_Dynamic.sprite_buf, 500, GL_DYNAMIC_DRAW);
|
||||
M_PrepareBuffer(
|
||||
&m_LevelData.sprite_buf, num_quads * OUTPUT_QUAD_VERTICES,
|
||||
GL_STATIC_DRAW);
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
m_LevelData.sprite_buf.vertex_count = num_quads * OUTPUT_QUAD_VERTICES;
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
const ROOM *const room = Room_Get(i);
|
||||
M_UpdateRoomGeometry(room);
|
||||
M_FillRoomGeometry(room);
|
||||
}
|
||||
M_BufferReallocGPU(&m_LevelData.sprite_buf);
|
||||
}
|
||||
|
@ -286,11 +307,14 @@ static void M_PrepareLevelBuffers(void)
|
|||
void Output_Sprites_Init(void)
|
||||
{
|
||||
m_Shader = Output_Shader_Create("shaders/sprites.glsl");
|
||||
m_LevelData.animated_vertices = Vector_Create(sizeof(OUTPUT_VERTEX_RANGE));
|
||||
m_Dynamic.source = Vector_CreateAtCapacity(sizeof(M_DYNAMIC_SPRITE), 50);
|
||||
}
|
||||
|
||||
void Output_Sprites_Shutdown(void)
|
||||
{
|
||||
Vector_Free(m_LevelData.animated_vertices);
|
||||
Vector_Free(m_Dynamic.source);
|
||||
M_FreeBuffers();
|
||||
Output_Shader_Free(m_Shader);
|
||||
m_Shader = nullptr;
|
||||
|
@ -303,6 +327,39 @@ void Output_Sprites_ObserveLevelLoad(void)
|
|||
M_PrepareLevelBatches();
|
||||
}
|
||||
|
||||
void Output_Sprites_ObserveTextureAnimation(void)
|
||||
{
|
||||
int32_t current_vertex = 0;
|
||||
for (int32_t i = 0; i < Room_GetCount(); i++) {
|
||||
const ROOM *const room = Room_Get(i);
|
||||
for (int32_t j = 0; j < room->mesh.num_sprites; j++) {
|
||||
const ROOM_SPRITE *const room_sprite = &room->mesh.sprites[j];
|
||||
const int16_t sprite_idx = room_sprite->texture;
|
||||
if (!Output_Textures_IsSpriteTextureAnimated(sprite_idx)) {
|
||||
current_vertex += OUTPUT_QUAD_VERTICES;
|
||||
continue;
|
||||
}
|
||||
for (int32_t k = 0; k < OUTPUT_QUAD_VERTICES; k++) {
|
||||
m_LevelData.sprite_buf.geom_vbo_data[current_vertex].uvw =
|
||||
Output_Textures_GetUVW(
|
||||
Output_Textures_GetSpritesUVWsBase() + sprite_idx * 4
|
||||
+ OUTPUT_QUAD_TO_FAN(k));
|
||||
current_vertex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_LevelData.sprite_buf.geom_vbo);
|
||||
for (int32_t i = 0; i < m_LevelData.animated_vertices->count; i++) {
|
||||
const OUTPUT_VERTEX_RANGE *const range =
|
||||
Vector_Get(m_LevelData.animated_vertices, i);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
range->vertex_start * sizeof(M_SPRITE_VERTEX),
|
||||
range->vertex_count * sizeof(M_SPRITE_VERTEX),
|
||||
&m_LevelData.sprite_buf.geom_vbo_data[range->vertex_start]);
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Sprites_RenderRoomSprites(
|
||||
const MATRIX *const matrix, const RGB_F tint, const ROOM *const room)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
void Output_Sprites_Init(void);
|
||||
void Output_Sprites_Shutdown(void);
|
||||
void Output_Sprites_ObserveLevelLoad(void);
|
||||
void Output_Sprites_ObserveTextureAnimation(void);
|
||||
void Output_Sprites_UploadProjectionMatrix(void);
|
||||
|
||||
void Output_Sprites_RenderBegin(void);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "game/output.h"
|
||||
#include "game/output/meshes/common.h"
|
||||
#include "game/output/meshes/objects.h"
|
||||
#include "game/output/meshes/rooms.h"
|
||||
#include "game/output/sprites.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
|
@ -145,5 +148,8 @@ void Output_AnimateTextures(const int32_t num_frames)
|
|||
}
|
||||
if (update) {
|
||||
Output_Textures_CycleAnimations();
|
||||
Output_Sprites_ObserveTextureAnimation();
|
||||
Output_Meshes_ObserveTextureAnimationRooms();
|
||||
Output_Meshes_ObserveTextureAnimationObjects();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "game/output/textures.h"
|
||||
|
||||
#include "game/output.h"
|
||||
#include "game/output/vertex_range.h"
|
||||
|
||||
#include <libtrx/debug.h>
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
|
@ -8,35 +9,13 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
float x0, y0, x1, y1;
|
||||
} M_ATLAS_SIZE;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
int32_t index;
|
||||
int32_t count;
|
||||
} M_ANIMATION_RANGE;
|
||||
|
||||
typedef struct {
|
||||
int32_t range_count;
|
||||
M_ANIMATION_RANGE *ranges;
|
||||
} M_ANIMATION_RANGES;
|
||||
|
||||
typedef struct {
|
||||
float u;
|
||||
float v;
|
||||
float w;
|
||||
} M_UVW;
|
||||
|
||||
typedef struct {
|
||||
M_UVW corners[4];
|
||||
OUTPUT_UVW corners[4];
|
||||
} M_UVW_PACK;
|
||||
|
||||
static struct {
|
||||
M_ANIMATION_RANGES objects;
|
||||
M_ANIMATION_RANGES sprites;
|
||||
VECTOR *objects;
|
||||
VECTOR *sprites;
|
||||
} m_AnimationRanges;
|
||||
|
||||
static struct {
|
||||
|
@ -44,139 +23,117 @@ static struct {
|
|||
GLuint tex_env_map;
|
||||
|
||||
struct {
|
||||
GLuint tbo; // buffer to hold UV data
|
||||
GLuint tex; // texture to hold UV buffer
|
||||
int32_t count;
|
||||
int32_t count_objects;
|
||||
int32_t count_sprites;
|
||||
M_UVW_PACK *data;
|
||||
M_UVW_PACK *data_objects;
|
||||
M_UVW_PACK *data_sprites;
|
||||
|
||||
bool *animated_objects;
|
||||
bool *animated_sprites;
|
||||
} uvws;
|
||||
|
||||
struct {
|
||||
GLuint tex;
|
||||
GLuint tbo;
|
||||
M_ATLAS_SIZE *data;
|
||||
M_ATLAS_SIZE *data_objects;
|
||||
M_ATLAS_SIZE *data_sprites;
|
||||
OUTPUT_TEXTURE_SIZE *data;
|
||||
OUTPUT_TEXTURE_SIZE *data_objects;
|
||||
OUTPUT_TEXTURE_SIZE *data_sprites;
|
||||
} atlas_sizes;
|
||||
} m_Priv = {};
|
||||
|
||||
static int M_CompareAnimationRange(const void *const a, const void *const b)
|
||||
{
|
||||
const M_ANIMATION_RANGE *const range_a = (M_ANIMATION_RANGE *)a;
|
||||
const M_ANIMATION_RANGE *const range_b = (M_ANIMATION_RANGE *)b;
|
||||
return range_a->index - range_b->index;
|
||||
}
|
||||
|
||||
static void M_MergeAndGlueAnimationRanges(M_ANIMATION_RANGES *const source)
|
||||
{
|
||||
ASSERT(source != nullptr);
|
||||
if (source->range_count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort ranges by index
|
||||
qsort(
|
||||
source->ranges, source->range_count, sizeof(M_ANIMATION_RANGE),
|
||||
M_CompareAnimationRange);
|
||||
|
||||
// Initialize a new index to store the merged ranges
|
||||
int32_t new_range_count = 0;
|
||||
|
||||
// Iterate over sorted ranges and merge them
|
||||
for (int32_t i = 0; i < source->range_count; i++) {
|
||||
if (new_range_count == 0) {
|
||||
// First range - just copy it
|
||||
source->ranges[new_range_count++] = source->ranges[i];
|
||||
} else {
|
||||
// Check if the previous range can be merged with the current one
|
||||
M_ANIMATION_RANGE *const last_range =
|
||||
&source->ranges[new_range_count - 1];
|
||||
const int32_t last_start = last_range->index;
|
||||
const int32_t last_end = last_range->index + last_range->count;
|
||||
const int32_t current_start = source->ranges[i].index;
|
||||
const int32_t current_end =
|
||||
source->ranges[i].index + source->ranges[i].count;
|
||||
|
||||
if (current_start >= last_start && current_start <= last_end) {
|
||||
last_range->count = current_end - last_range->index;
|
||||
} else if (current_end >= last_start && current_end <= last_end) {
|
||||
last_range->index = source->ranges[i].index;
|
||||
} else {
|
||||
source->ranges[new_range_count++] = source->ranges[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the range count with the new number of merged ranges
|
||||
source->range_count = new_range_count;
|
||||
}
|
||||
|
||||
static void M_PrepareObjectAnimationRanges(void)
|
||||
{
|
||||
m_AnimationRanges.objects.range_count = 0;
|
||||
size_t required_size = 0;
|
||||
for (const ANIMATED_TEXTURE_RANGE *src_range =
|
||||
Output_GetAnimatedTextureRange(0);
|
||||
src_range != nullptr; src_range = src_range->next_range) {
|
||||
m_AnimationRanges.objects.range_count += src_range->num_textures;
|
||||
required_size += src_range->num_textures;
|
||||
}
|
||||
|
||||
m_AnimationRanges.objects.ranges = Memory_Realloc(
|
||||
m_AnimationRanges.objects.ranges,
|
||||
m_AnimationRanges.objects.range_count * sizeof(M_ANIMATION_RANGE));
|
||||
Vector_Clear(m_AnimationRanges.objects);
|
||||
Vector_EnsureCapacity(m_AnimationRanges.objects, required_size);
|
||||
|
||||
M_ANIMATION_RANGE *dst_range = m_AnimationRanges.objects.ranges;
|
||||
for (const ANIMATED_TEXTURE_RANGE *src_range =
|
||||
Output_GetAnimatedTextureRange(0);
|
||||
src_range != nullptr; src_range = src_range->next_range) {
|
||||
for (int32_t i = 0; i < src_range->num_textures; i++) {
|
||||
dst_range->index = src_range->textures[i];
|
||||
dst_range->count = 1;
|
||||
dst_range++;
|
||||
Vector_Add(
|
||||
m_AnimationRanges.objects,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = src_range->textures[i],
|
||||
.vertex_count = 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
M_MergeAndGlueAnimationRanges(&m_AnimationRanges.objects);
|
||||
Output_GlueVertexRanges(m_AnimationRanges.objects);
|
||||
}
|
||||
|
||||
static void M_PrepareSpriteAnimationRanges(void)
|
||||
{
|
||||
m_AnimationRanges.sprites.range_count = 0;
|
||||
size_t required_size = 0;
|
||||
for (int32_t i = 0; i < MAX_STATIC_OBJECTS; i++) {
|
||||
const STATIC_OBJECT_2D *const obj = Object_Get2DStatic(i);
|
||||
if (!obj->loaded || obj->frame_count == 1) {
|
||||
continue;
|
||||
}
|
||||
m_AnimationRanges.sprites.range_count++;
|
||||
required_size++;
|
||||
}
|
||||
|
||||
m_AnimationRanges.sprites.ranges = Memory_Realloc(
|
||||
m_AnimationRanges.sprites.ranges,
|
||||
m_AnimationRanges.sprites.range_count * sizeof(M_ANIMATION_RANGE));
|
||||
Vector_Clear(m_AnimationRanges.sprites);
|
||||
Vector_EnsureCapacity(m_AnimationRanges.sprites, required_size);
|
||||
|
||||
M_ANIMATION_RANGE *dst_range = m_AnimationRanges.sprites.ranges;
|
||||
for (int32_t i = 0; i < MAX_STATIC_OBJECTS; i++) {
|
||||
const STATIC_OBJECT_2D *const obj = Object_Get2DStatic(i);
|
||||
if (!obj->loaded || obj->frame_count == 1) {
|
||||
continue;
|
||||
}
|
||||
dst_range->index = obj->texture_idx;
|
||||
dst_range->count = obj->frame_count;
|
||||
dst_range++;
|
||||
Vector_Add(
|
||||
m_AnimationRanges.sprites,
|
||||
&(OUTPUT_VERTEX_RANGE) {
|
||||
.vertex_start = obj->texture_idx,
|
||||
.vertex_count = obj->frame_count,
|
||||
});
|
||||
}
|
||||
M_MergeAndGlueAnimationRanges(&m_AnimationRanges.sprites);
|
||||
Output_GlueVertexRanges(m_AnimationRanges.sprites);
|
||||
}
|
||||
|
||||
static void M_PrepareAnimationRanges(void)
|
||||
{
|
||||
M_PrepareObjectAnimationRanges();
|
||||
M_PrepareSpriteAnimationRanges();
|
||||
|
||||
for (int32_t i = 0; i < Output_GetObjectTextureCount(); i++) {
|
||||
m_Priv.uvws.animated_objects[i] = false;
|
||||
for (int32_t j = 0; j < m_AnimationRanges.objects->count; j++) {
|
||||
const OUTPUT_VERTEX_RANGE *const dst_range =
|
||||
Vector_Get(m_AnimationRanges.objects, j);
|
||||
const int32_t range_start = dst_range->vertex_start;
|
||||
const int32_t range_end = range_start + dst_range->vertex_count;
|
||||
if (i >= range_start && i < range_end) {
|
||||
m_Priv.uvws.animated_objects[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < Output_GetSpriteTextureCount(); i++) {
|
||||
m_Priv.uvws.animated_sprites[i] = false;
|
||||
for (int32_t j = 0; j < m_AnimationRanges.sprites->count; j++) {
|
||||
const OUTPUT_VERTEX_RANGE *const dst_range =
|
||||
Vector_Get(m_AnimationRanges.sprites, j);
|
||||
const int32_t range_start = dst_range->vertex_start;
|
||||
const int32_t range_end = range_start + dst_range->vertex_count;
|
||||
if (i >= range_start && i < range_end) {
|
||||
m_Priv.uvws.animated_sprites[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_FillAtlasObjectSize(const int32_t i)
|
||||
{
|
||||
M_ATLAS_SIZE *const size = &m_Priv.atlas_sizes.data_objects[i];
|
||||
OUTPUT_TEXTURE_SIZE *const size = &m_Priv.atlas_sizes.data_objects[i];
|
||||
const OBJECT_TEXTURE *const texture = Output_GetObjectTexture(i);
|
||||
size->x0 = texture->uv[0].u;
|
||||
size->y0 = texture->uv[0].v;
|
||||
|
@ -196,7 +153,7 @@ static void M_FillAtlasObjectSize(const int32_t i)
|
|||
|
||||
static void M_FillAtlasSpriteSize(const int32_t i)
|
||||
{
|
||||
M_ATLAS_SIZE *const size = &m_Priv.atlas_sizes.data_sprites[i];
|
||||
OUTPUT_TEXTURE_SIZE *const size = &m_Priv.atlas_sizes.data_sprites[i];
|
||||
const SPRITE_TEXTURE *const sprite = Output_GetSpriteTexture(i);
|
||||
const float adj = 0.1 / 256.0f;
|
||||
const float u0 = (sprite->offset & 0xFF) / 256.0f + adj;
|
||||
|
@ -212,7 +169,7 @@ static void M_FillAtlasSpriteSize(const int32_t i)
|
|||
static void M_FillObjectUVW(const int32_t i)
|
||||
{
|
||||
const OBJECT_TEXTURE *const texture = Output_GetObjectTexture(i);
|
||||
M_UVW *const corners = m_Priv.uvws.data_objects[i].corners;
|
||||
OUTPUT_UVW *const corners = m_Priv.uvws.data_objects[i].corners;
|
||||
for (int32_t j = 0; j < 4; j++) {
|
||||
corners[j].u = texture->uv[j].u / 65535.0f;
|
||||
corners[j].v = texture->uv[j].v / 65535.0f;
|
||||
|
@ -228,7 +185,7 @@ static void M_FillSpriteUVW(const int32_t i)
|
|||
const float v0 = (sprite->offset >> 8) / 256.0f + adj;
|
||||
const float u1 = u0 + sprite->width / 65536.0f - 2 * adj;
|
||||
const float v1 = v0 + sprite->height / 65536.0f - 2 * adj;
|
||||
M_UVW *const corners = m_Priv.uvws.data_sprites[i].corners;
|
||||
OUTPUT_UVW *const corners = m_Priv.uvws.data_sprites[i].corners;
|
||||
// clang-format off
|
||||
corners[0].u = u0; corners[0].v = v0; corners[0].w = sprite->tex_page;
|
||||
corners[1].u = u1; corners[1].v = v0; corners[1].w = sprite->tex_page;
|
||||
|
@ -251,78 +208,29 @@ static void M_FillSpriteUVWs(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_UploadUVWs(void)
|
||||
static void M_UpdateObjectAnimatedUVWs(VECTOR *const source)
|
||||
{
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.uvws.tbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_TEXTURE_BUFFER, m_Priv.uvws.count * sizeof(M_UVW_PACK),
|
||||
m_Priv.uvws.data, GL_DYNAMIC_DRAW);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
static void M_UploadObjectAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
||||
{
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.uvws.tbo);
|
||||
for (int32_t i = 0; i < source->range_count; i++) {
|
||||
const M_ANIMATION_RANGE *const range = &source->ranges[i];
|
||||
for (int32_t j = 0; j < range->count; j++) {
|
||||
M_FillObjectUVW(range->index + j);
|
||||
for (int32_t i = 0; i < source->count; i++) {
|
||||
const OUTPUT_VERTEX_RANGE *const range = Vector_Get(source, i);
|
||||
for (int32_t j = 0; j < range->vertex_count; j++) {
|
||||
M_FillObjectUVW(range->vertex_start + j);
|
||||
M_FillAtlasObjectSize(range->vertex_start + j);
|
||||
}
|
||||
const M_UVW_PACK *const source =
|
||||
m_Priv.uvws.data_objects + range->index;
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
(source - m_Priv.uvws.data) * sizeof(M_UVW_PACK),
|
||||
range->count * sizeof(M_UVW_PACK), source);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tbo);
|
||||
for (int32_t i = 0; i < source->range_count; i++) {
|
||||
const M_ANIMATION_RANGE *const range = &source->ranges[i];
|
||||
for (int32_t j = 0; j < range->count; j++) {
|
||||
M_FillAtlasObjectSize(range->index + j);
|
||||
}
|
||||
const M_ATLAS_SIZE *const source =
|
||||
m_Priv.atlas_sizes.data_objects + range->index;
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
(source - m_Priv.atlas_sizes.data) * sizeof(M_ATLAS_SIZE),
|
||||
range->count * sizeof(M_ATLAS_SIZE), source);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_UploadSpriteAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
||||
static void M_UpdateSpriteAnimatedUVWs(VECTOR *const source)
|
||||
{
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.uvws.tbo);
|
||||
for (int32_t i = 0; i < source->range_count; i++) {
|
||||
const M_ANIMATION_RANGE *const range = &source->ranges[i];
|
||||
for (int32_t j = 0; j < range->count; j++) {
|
||||
M_FillSpriteUVW(range->index + j);
|
||||
for (int32_t i = 0; i < source->count; i++) {
|
||||
const OUTPUT_VERTEX_RANGE *const range = Vector_Get(source, i);
|
||||
for (int32_t j = 0; j < range->vertex_count; j++) {
|
||||
M_FillSpriteUVW(range->vertex_start + j);
|
||||
M_FillAtlasSpriteSize(range->vertex_start + j);
|
||||
}
|
||||
const M_UVW_PACK *const source =
|
||||
m_Priv.uvws.data_sprites + range->index;
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
(source - m_Priv.uvws.data) * sizeof(M_UVW_PACK),
|
||||
range->count * sizeof(M_UVW_PACK), source);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tbo);
|
||||
for (int32_t i = 0; i < source->range_count; i++) {
|
||||
const M_ANIMATION_RANGE *const range = &source->ranges[i];
|
||||
for (int32_t j = 0; j < range->count; j++) {
|
||||
M_FillAtlasSpriteSize(range->index + j);
|
||||
}
|
||||
const M_ATLAS_SIZE *const source =
|
||||
m_Priv.atlas_sizes.data_sprites + range->index;
|
||||
GFX_TRACK_DATA(
|
||||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
(source - m_Priv.atlas_sizes.data) * sizeof(M_ATLAS_SIZE),
|
||||
range->count * sizeof(M_ATLAS_SIZE), source);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_PrepareUVWBuffers(void)
|
||||
static void M_PrepareUVWs(void)
|
||||
{
|
||||
m_Priv.uvws.count_objects = Output_GetObjectTextureCount();
|
||||
m_Priv.uvws.count_sprites = Output_GetSpriteTextureCount();
|
||||
|
@ -330,23 +238,10 @@ static void M_PrepareUVWBuffers(void)
|
|||
m_Priv.uvws.data = Memory_Alloc(m_Priv.uvws.count * sizeof(M_UVW_PACK));
|
||||
m_Priv.uvws.data_objects = m_Priv.uvws.data;
|
||||
m_Priv.uvws.data_sprites = m_Priv.uvws.data + m_Priv.uvws.count_objects;
|
||||
|
||||
glGenBuffers(1, &m_Priv.uvws.tbo);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.uvws.tbo);
|
||||
|
||||
GLint limit;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &limit);
|
||||
ASSERT(m_Priv.uvws.count * sizeof(M_UVW_PACK) <= (size_t)limit);
|
||||
|
||||
glGenTextures(1, &m_Priv.uvws.tex);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_Priv.uvws.tex);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, m_Priv.uvws.tbo);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
static void M_PrepareUVWs(void)
|
||||
{
|
||||
M_PrepareUVWBuffers();
|
||||
m_Priv.uvws.animated_objects =
|
||||
Memory_Alloc(m_Priv.uvws.count_objects * sizeof(bool));
|
||||
m_Priv.uvws.animated_sprites =
|
||||
Memory_Alloc(m_Priv.uvws.count_sprites * sizeof(bool));
|
||||
M_FillObjectUVWs();
|
||||
M_FillSpriteUVWs();
|
||||
}
|
||||
|
@ -364,16 +259,11 @@ static void M_PrepareEnvMap(void)
|
|||
|
||||
static void M_PrepareAtlasSizes(void)
|
||||
{
|
||||
glGenBuffers(1, &m_Priv.atlas_sizes.tbo);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tbo);
|
||||
glGenTextures(1, &m_Priv.atlas_sizes.tex);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, m_Priv.atlas_sizes.tex);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_Priv.atlas_sizes.tbo);
|
||||
const int32_t count_objects = Output_GetObjectTextureCount();
|
||||
const int32_t count_sprites = Output_GetSpriteTextureCount();
|
||||
const int32_t count = count_objects + count_sprites;
|
||||
m_Priv.atlas_sizes.data =
|
||||
Memory_Realloc(m_Priv.atlas_sizes.data, count * sizeof(M_ATLAS_SIZE));
|
||||
m_Priv.atlas_sizes.data = Memory_Realloc(
|
||||
m_Priv.atlas_sizes.data, count * sizeof(OUTPUT_TEXTURE_SIZE));
|
||||
m_Priv.atlas_sizes.data_objects = m_Priv.atlas_sizes.data;
|
||||
m_Priv.atlas_sizes.data_sprites = m_Priv.atlas_sizes.data + count_objects;
|
||||
for (int32_t i = 0; i < count_objects; i++) {
|
||||
|
@ -382,9 +272,6 @@ static void M_PrepareAtlasSizes(void)
|
|||
for (int32_t i = 0; i < count_sprites; i++) {
|
||||
M_FillAtlasSpriteSize(i);
|
||||
}
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_TEXTURE_BUFFER, count * sizeof(M_ATLAS_SIZE),
|
||||
m_Priv.atlas_sizes.data, GL_DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
static void M_UploadAtlas(void)
|
||||
|
@ -428,38 +315,27 @@ static void M_FreeLevelData(void)
|
|||
{
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
if (m_Priv.uvws.tbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.uvws.tbo);
|
||||
m_Priv.uvws.tbo = 0;
|
||||
}
|
||||
if (m_Priv.uvws.tex != 0) {
|
||||
glDeleteTextures(1, &m_Priv.uvws.tex);
|
||||
m_Priv.uvws.tex = 0;
|
||||
}
|
||||
if (m_Priv.tex_atlas != 0) {
|
||||
glDeleteTextures(1, &m_Priv.tex_atlas);
|
||||
m_Priv.tex_atlas = 0;
|
||||
}
|
||||
if (m_Priv.atlas_sizes.tex != 0) {
|
||||
glDeleteTextures(1, &m_Priv.atlas_sizes.tex);
|
||||
m_Priv.atlas_sizes.tex = 0;
|
||||
}
|
||||
if (m_Priv.atlas_sizes.tbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.atlas_sizes.tbo);
|
||||
m_Priv.atlas_sizes.tbo = 0;
|
||||
}
|
||||
Memory_FreePointer(&m_Priv.uvws.data);
|
||||
Memory_FreePointer(&m_Priv.uvws.animated_objects);
|
||||
Memory_FreePointer(&m_Priv.uvws.animated_sprites);
|
||||
Memory_FreePointer(&m_Priv.atlas_sizes.data);
|
||||
Memory_FreePointer(&m_AnimationRanges.objects.ranges);
|
||||
Memory_FreePointer(&m_AnimationRanges.sprites.ranges);
|
||||
}
|
||||
|
||||
void Output_Textures_Init(void)
|
||||
{
|
||||
M_PrepareEnvMap();
|
||||
m_AnimationRanges.objects = Vector_Create(sizeof(OUTPUT_VERTEX_RANGE));
|
||||
m_AnimationRanges.sprites = Vector_Create(sizeof(OUTPUT_VERTEX_RANGE));
|
||||
}
|
||||
|
||||
void Output_Textures_Shutdown(void)
|
||||
{
|
||||
Vector_Free(m_AnimationRanges.objects);
|
||||
Vector_Free(m_AnimationRanges.sprites);
|
||||
M_FreeLevelData();
|
||||
if (m_Priv.tex_env_map != 0) {
|
||||
glDeleteTextures(1, &m_Priv.tex_env_map);
|
||||
|
@ -470,9 +346,8 @@ void Output_Textures_Shutdown(void)
|
|||
void Output_Textures_ObserveLevelLoad(void)
|
||||
{
|
||||
M_FreeLevelData();
|
||||
M_PrepareAnimationRanges();
|
||||
M_PrepareUVWs();
|
||||
M_UploadUVWs();
|
||||
M_PrepareAnimationRanges();
|
||||
M_UploadAtlas();
|
||||
}
|
||||
|
||||
|
@ -500,27 +375,17 @@ void Output_Textures_UpdateEnvironmentMap(void)
|
|||
|
||||
void Output_Textures_CycleAnimations(void)
|
||||
{
|
||||
if (m_Priv.uvws.tex != 0) {
|
||||
M_UploadSpriteAnimatedUVWs(&m_AnimationRanges.sprites);
|
||||
M_UploadObjectAnimatedUVWs(&m_AnimationRanges.objects);
|
||||
if (m_Priv.uvws.count != 0) {
|
||||
M_UpdateSpriteAnimatedUVWs(m_AnimationRanges.sprites);
|
||||
M_UpdateObjectAnimatedUVWs(m_AnimationRanges.objects);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetUVWsTexture(void)
|
||||
{
|
||||
return m_Priv.uvws.tex;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetAtlasTexture(void)
|
||||
{
|
||||
return m_Priv.tex_atlas;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetAtlasSizesTexture(void)
|
||||
{
|
||||
return m_Priv.atlas_sizes.tex;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetEnvMapTexture(void)
|
||||
{
|
||||
return m_Priv.tex_env_map;
|
||||
|
@ -528,16 +393,35 @@ GLuint Output_Textures_GetEnvMapTexture(void)
|
|||
|
||||
int32_t Output_Textures_GetSpritesUVWsBase(void)
|
||||
{
|
||||
const size_t num = sizeof(M_UVW_PACK) / sizeof(M_UVW);
|
||||
const size_t num = sizeof(M_UVW_PACK) / sizeof(OUTPUT_UVW);
|
||||
ASSERT(num == 4);
|
||||
return m_Priv.uvws.count_objects * num;
|
||||
}
|
||||
|
||||
OUTPUT_UVW Output_Textures_GetUVW(const int32_t uvw_idx)
|
||||
{
|
||||
return m_Priv.uvws.data[uvw_idx / 4].corners[uvw_idx % 4];
|
||||
}
|
||||
|
||||
OUTPUT_TEXTURE_SIZE Output_Textures_GetAtlasSize(const int32_t uvw_idx)
|
||||
{
|
||||
return m_Priv.atlas_sizes.data[uvw_idx];
|
||||
}
|
||||
|
||||
bool Output_Textures_IsObjectTextureAnimated(const int32_t texture_idx)
|
||||
{
|
||||
return m_Priv.uvws.animated_objects[texture_idx];
|
||||
}
|
||||
|
||||
bool Output_Textures_IsSpriteTextureAnimated(const int32_t uvw_idx)
|
||||
{
|
||||
return m_Priv.uvws.animated_sprites[uvw_idx];
|
||||
}
|
||||
|
||||
void Output_Textures_ApplyRenderSettings(void)
|
||||
{
|
||||
// re-adjust UVs when the bilinear filter is toggled.
|
||||
if (m_Priv.uvws.tex != 0) {
|
||||
if (m_Priv.uvws.count != 0) {
|
||||
M_FillObjectUVWs();
|
||||
M_UploadUVWs();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,32 @@
|
|||
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
float x0;
|
||||
float y0;
|
||||
float x1;
|
||||
float y1;
|
||||
} OUTPUT_TEXTURE_SIZE;
|
||||
|
||||
typedef struct {
|
||||
float u;
|
||||
float v;
|
||||
float w;
|
||||
} OUTPUT_UVW;
|
||||
#pragma pack(pop)
|
||||
|
||||
void Output_Textures_Init(void);
|
||||
void Output_Textures_Shutdown(void);
|
||||
void Output_Textures_ObserveLevelLoad(void);
|
||||
void Output_Textures_UpdateEnvironmentMap(void);
|
||||
void Output_Textures_CycleAnimations(void);
|
||||
void Output_Textures_ApplyRenderSettings(void);
|
||||
GLuint Output_Textures_GetUVWsTexture(void);
|
||||
GLuint Output_Textures_GetAtlasTexture(void);
|
||||
GLuint Output_Textures_GetAtlasSizesTexture(void);
|
||||
GLuint Output_Textures_GetEnvMapTexture(void);
|
||||
int32_t Output_Textures_GetSpritesUVWsBase(void);
|
||||
|
||||
OUTPUT_UVW Output_Textures_GetUVW(int32_t uvw_idx);
|
||||
OUTPUT_TEXTURE_SIZE Output_Textures_GetAtlasSize(int32_t uvw_idx);
|
||||
bool Output_Textures_IsObjectTextureAnimated(int32_t texture_idx);
|
||||
bool Output_Textures_IsSpriteTextureAnimated(int32_t sprite_idx);
|
||||
|
|
59
src/tr1/game/output/vertex_range.c
Normal file
59
src/tr1/game/output/vertex_range.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "game/output/vertex_range.h"
|
||||
|
||||
#include <libtrx/debug.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static int M_CompareRanges(const void *const a, const void *const b)
|
||||
{
|
||||
const OUTPUT_VERTEX_RANGE *const range_a = (OUTPUT_VERTEX_RANGE *)a;
|
||||
const OUTPUT_VERTEX_RANGE *const range_b = (OUTPUT_VERTEX_RANGE *)b;
|
||||
return range_a->vertex_start - range_b->vertex_start;
|
||||
}
|
||||
|
||||
void Output_GlueVertexRanges(VECTOR *const target)
|
||||
{
|
||||
ASSERT(target != nullptr);
|
||||
if (target->count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
OUTPUT_VERTEX_RANGE *const ranges =
|
||||
(OUTPUT_VERTEX_RANGE *)Vector_Get(target, 0);
|
||||
|
||||
qsort(ranges, target->count, sizeof(OUTPUT_VERTEX_RANGE), M_CompareRanges);
|
||||
|
||||
// Initialize a new index to store the merged ranges
|
||||
int32_t new_range_count = 0;
|
||||
|
||||
// Iterate over sorted ranges and merge them
|
||||
for (int32_t i = 0; i < target->count; i++) {
|
||||
if (new_range_count == 0) {
|
||||
// First range - just copy it
|
||||
ranges[new_range_count] = ranges[i];
|
||||
new_range_count++;
|
||||
} else {
|
||||
// Check if the previous range can be merged with the current one
|
||||
OUTPUT_VERTEX_RANGE *const last_range =
|
||||
&ranges[new_range_count - 1];
|
||||
const int32_t last_start = last_range->vertex_start;
|
||||
const int32_t last_end =
|
||||
last_range->vertex_start + last_range->vertex_count;
|
||||
const int32_t current_start = ranges[i].vertex_start;
|
||||
const int32_t current_end =
|
||||
ranges[i].vertex_start + ranges[i].vertex_count;
|
||||
|
||||
if (current_start >= last_start && current_start <= last_end) {
|
||||
last_range->vertex_count =
|
||||
current_end - last_range->vertex_start;
|
||||
} else if (current_end >= last_start && current_end <= last_end) {
|
||||
last_range->vertex_start = ranges[i].vertex_start;
|
||||
} else {
|
||||
ranges[new_range_count++] = ranges[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the range vertex_count with the new number of merged ranges
|
||||
target->count = new_range_count;
|
||||
}
|
10
src/tr1/game/output/vertex_range.h
Normal file
10
src/tr1/game/output/vertex_range.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <libtrx/vector.h>
|
||||
|
||||
typedef struct {
|
||||
int32_t vertex_start;
|
||||
int32_t vertex_count;
|
||||
} OUTPUT_VERTEX_RANGE;
|
||||
|
||||
void Output_GlueVertexRanges(VECTOR *vertex_range);
|
|
@ -254,6 +254,7 @@ sources = [
|
|||
'game/output/sprites.c',
|
||||
'game/output/state.c',
|
||||
'game/output/textures.c',
|
||||
'game/output/vertex_range.c',
|
||||
'game/overlay.c',
|
||||
'game/requester.c',
|
||||
'game/room.c',
|
||||
|
|
|
@ -434,6 +434,10 @@ void Output_ObserveLevelUnload(void)
|
|||
}
|
||||
}
|
||||
|
||||
void Output_ObserveRoomFlip(const ROOM *room)
|
||||
{
|
||||
}
|
||||
|
||||
void Output_DrawObjectMesh(const OBJECT_MESH *const mesh, const int32_t clip)
|
||||
{
|
||||
g_FltWinLeft = 0.0f;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue