mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
tr1/output/objects: rewrite object mesh drawing
Some checks are pending
Run code linters / Run code linters (push) Waiting to run
Some checks are pending
Run code linters / Run code linters (push) Waiting to run
This commit is contained in:
parent
28dbf86d32
commit
096e837685
26 changed files with 774 additions and 638 deletions
|
@ -1,5 +1,9 @@
|
|||
#define NEUTRAL_SHADE 0x1000
|
||||
#define NO_VERT_MOVE 0x2000
|
||||
|
||||
#define VERT_NO_CAUSTICS 0x01
|
||||
#define VERT_FLAT_SHADED 0x02
|
||||
#define VERT_REFLECTIVE 0x04
|
||||
#define VERT_NO_LIGHTING 0x08
|
||||
|
||||
#ifdef VERTEX
|
||||
|
||||
|
@ -11,68 +15,86 @@ uniform float uWibbleOffset;
|
|||
uniform bool uTrapezoidFilterEnabled;
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in int inUVWIdx;
|
||||
layout(location = 2) in vec2 inTrapezoidRatios;
|
||||
layout(location = 3) in int inFlags;
|
||||
layout(location = 4) in float inShade;
|
||||
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;
|
||||
|
||||
out vec2 gTexUV;
|
||||
flat out int gFlags;
|
||||
flat out int gTexLayer;
|
||||
out vec2 gTexUV;
|
||||
out vec2 gTrapezoidRatios;
|
||||
out float gShade;
|
||||
out vec4 gColor;
|
||||
out vec3 gNormal;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = uMatProjection * uMatModelView * vec4(inPosition, 1.0);
|
||||
|
||||
if (uWibbleOffset >= 0.0 && (inFlags & NO_VERT_MOVE) == 0) {
|
||||
if (uWibbleOffset >= 0.0 && (inFlags & VERT_NO_CAUSTICS) == 0) {
|
||||
gl_Position.xyz =
|
||||
waterWibble(gl_Position, uViewportSize, uWibbleOffset);
|
||||
}
|
||||
|
||||
vec3 uvw = texelFetch(uUVW, int(inUVWIdx)).xyz;
|
||||
gTexUV = uvw.xy;
|
||||
gFlags = inFlags;
|
||||
gTexLayer = int(uvw.z);
|
||||
gTexUV = uvw.xy;
|
||||
gTrapezoidRatios = inTrapezoidRatios;
|
||||
if (uTrapezoidFilterEnabled) {
|
||||
gTexUV *= inTrapezoidRatios;
|
||||
}
|
||||
gShade = inShade;
|
||||
gColor = inColor;
|
||||
gNormal = inNormal;
|
||||
}
|
||||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2DArray uTexture;
|
||||
uniform sampler2DArray uTexAtlas;
|
||||
uniform sampler2D uTexEnvMap;
|
||||
uniform bool uSmoothingEnabled;
|
||||
uniform bool uAlphaDiscardEnabled;
|
||||
uniform bool uTrapezoidFilterEnabled;
|
||||
uniform float uAlphaThreshold;
|
||||
uniform float uBrightnessMultiplier;
|
||||
uniform vec3 uGlobalTint;
|
||||
|
||||
in vec2 gTexUV;
|
||||
flat in int gFlags;
|
||||
flat in int gTexLayer;
|
||||
in vec2 gTexUV;
|
||||
in float gShade;
|
||||
in vec4 gColor;
|
||||
in vec2 gTrapezoidRatios;
|
||||
in vec3 gNormal;
|
||||
out vec4 outColor;
|
||||
|
||||
void main(void) {
|
||||
vec4 texColor = vec4(1);
|
||||
vec4 texColor = gColor;
|
||||
vec3 texCoords = vec3(gTexUV.x, gTexUV.y, gTexLayer);
|
||||
if (texCoords.z >= 0) {
|
||||
if (uTrapezoidFilterEnabled) {
|
||||
texCoords.xy /= gTrapezoidRatios.xy;
|
||||
}
|
||||
if (uTrapezoidFilterEnabled) {
|
||||
texCoords.xy /= gTrapezoidRatios.xy;
|
||||
}
|
||||
|
||||
if (uSmoothingEnabled && discardTranslucent(uTexture, texCoords)) {
|
||||
if ((gFlags & VERT_FLAT_SHADED) == 0 && texCoords.z >= 0) {
|
||||
if (uAlphaDiscardEnabled && uSmoothingEnabled && discardTranslucent(uTexAtlas, texCoords)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
texColor = texture(uTexture, texCoords);
|
||||
texColor = texture(uTexAtlas, texCoords);
|
||||
if (uAlphaThreshold >= 0.0 && texColor.a <= uAlphaThreshold) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
if ((gFlags & VERT_REFLECTIVE) != 0) {
|
||||
texColor *= texture(uTexEnvMap, (normalize(gNormal) * 0.5 + 0.5).xy) * 2;
|
||||
}
|
||||
|
||||
texColor.rgb *= 2.0 - (gShade / NEUTRAL_SHADE);
|
||||
if ((gFlags & VERT_NO_LIGHTING) == 0) {
|
||||
texColor.rgb *= 2.0 - (gShade / NEUTRAL_SHADE);
|
||||
}
|
||||
texColor.rgb *= uBrightnessMultiplier;
|
||||
texColor.rgb *= uGlobalTint;
|
||||
outColor = vec4(texColor.rgb, 1.0);
|
||||
|
|
|
@ -35,7 +35,8 @@ void main(void) {
|
|||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2DArray uTexture;
|
||||
uniform sampler2DArray uTexAtlas;
|
||||
uniform sampler2D uTexEnvMap;
|
||||
uniform bool uSmoothingEnabled;
|
||||
uniform float uBrightnessMultiplier;
|
||||
uniform vec3 uGlobalTint;
|
||||
|
@ -47,8 +48,8 @@ out vec4 outColor;
|
|||
|
||||
void main(void) {
|
||||
vec3 uvw = vec3(gTexUV.x, gTexUV.y, gTexLayer);
|
||||
vec4 texColor = texture(uTexture, uvw);
|
||||
if (uSmoothingEnabled && discardTranslucent(uTexture, uvw)) {
|
||||
vec4 texColor = texture(uTexAtlas, uvw);
|
||||
if (uSmoothingEnabled && discardTranslucent(uTexAtlas, uvw)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
|
|
|
@ -297,6 +297,7 @@ static void M_ReadObjectMesh(OBJECT_MESH *const mesh, VFILE *const file)
|
|||
VFile_Skip(file, sizeof(int16_t));
|
||||
|
||||
mesh->enable_reflections = false;
|
||||
mesh->disable_lighting = false;
|
||||
|
||||
{
|
||||
mesh->num_vertices = VFile_ReadS16(file);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "game/game_buf.h"
|
||||
#include "game/matrix.h"
|
||||
#include "game/output.h"
|
||||
#include "game/output/objects.h"
|
||||
|
||||
static OBJECT m_Objects[O_NUMBER_OF] = {};
|
||||
static STATIC_OBJECT_3D m_StaticObjects3D[MAX_STATIC_OBJECTS] = {};
|
||||
|
@ -84,6 +85,16 @@ OBJECT_MESH *Object_GetMesh(const int32_t index)
|
|||
return m_MeshPointers[index];
|
||||
}
|
||||
|
||||
int32_t Object_GetMeshIndex(const OBJECT_MESH *const mesh)
|
||||
{
|
||||
for (int32_t i = 0; i < m_MeshCount; i++) {
|
||||
if (mesh == m_MeshPointers[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t Object_GetMeshCount(void)
|
||||
{
|
||||
return m_MeshCount;
|
||||
|
@ -122,6 +133,10 @@ void Object_SwapMesh(
|
|||
m_MeshPointers[obj1->mesh_idx + mesh_num] =
|
||||
m_MeshPointers[obj2->mesh_idx + mesh_num];
|
||||
m_MeshPointers[obj2->mesh_idx + mesh_num] = temp;
|
||||
#if TR_VERSION == 1
|
||||
Output_Objects_UpdateMesh(m_MeshPointers[obj1->mesh_idx + mesh_num]);
|
||||
Output_Objects_UpdateMesh(m_MeshPointers[obj2->mesh_idx + mesh_num]);
|
||||
#endif
|
||||
}
|
||||
|
||||
ANIM *Object_GetAnim(const OBJECT *const obj, const int32_t anim_idx)
|
||||
|
|
|
@ -24,6 +24,7 @@ void Object_StoreMesh(OBJECT_MESH *mesh);
|
|||
|
||||
int32_t Object_GetMeshCount(void);
|
||||
OBJECT_MESH *Object_FindMesh(int32_t data_offset);
|
||||
int32_t Object_GetMeshIndex(const OBJECT_MESH *mesh);
|
||||
int32_t Object_GetMeshOffset(const OBJECT_MESH *mesh);
|
||||
void Object_SetMeshOffset(OBJECT_MESH *mesh, int32_t data_offset);
|
||||
|
||||
|
|
|
@ -33,7 +33,9 @@ typedef struct {
|
|||
FACE3 *tex_face3s;
|
||||
FACE4 *flat_face4s;
|
||||
FACE3 *flat_face3s;
|
||||
|
||||
bool enable_reflections;
|
||||
bool disable_lighting;
|
||||
} OBJECT_MESH;
|
||||
|
||||
#if TR_VERSION == 1
|
||||
|
|
7
src/libtrx/include/libtrx/game/output/objects.h
Normal file
7
src/libtrx/include/libtrx/game/output/objects.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../objects/types.h"
|
||||
|
||||
#if TR_VERSION == 1
|
||||
extern void Output_Objects_UpdateMesh(const OBJECT_MESH *mesh);
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "game/lara/draw.h"
|
||||
#include "game/lara/hair.h"
|
||||
#include "game/output.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/overlay.h"
|
||||
#include "game/room_draw.h"
|
||||
#include "game/viewport.h"
|
||||
|
@ -24,7 +25,7 @@ void Game_Draw(bool draw_overlay)
|
|||
Room_DrawAllRooms(g_Camera.interp.room_num, g_Camera.target.room_num);
|
||||
|
||||
if (g_Config.visuals.enable_reflections) {
|
||||
Output_FillEnvironmentMap();
|
||||
Output_Textures_UpdateEnvironmentMap();
|
||||
}
|
||||
|
||||
if (Room_Get(g_LaraItem->room_num)->flags & RF_UNDERWATER) {
|
||||
|
|
|
@ -269,7 +269,7 @@ static void M_CompleteSetup(const GF_LEVEL *const level)
|
|||
Level_LoadTexturePages();
|
||||
Level_LoadPalettes();
|
||||
Level_LoadFaces();
|
||||
Output_DownloadTextures();
|
||||
Output_ObserveLevelLoad();
|
||||
|
||||
// Initialise the sound effects.
|
||||
LEVEL_INFO *const info = Level_GetInfo();
|
||||
|
@ -376,6 +376,11 @@ void Level_Load(const GF_LEVEL *const level)
|
|||
Benchmark_End(&benchmark, nullptr);
|
||||
}
|
||||
|
||||
void Level_Unload(void)
|
||||
{
|
||||
Output_ObserveLevelUnload();
|
||||
}
|
||||
|
||||
bool Level_Initialise(
|
||||
const GF_LEVEL *const level, const GF_SEQUENCE_CONTEXT seq_ctx)
|
||||
{
|
||||
|
@ -424,6 +429,7 @@ bool Level_Initialise(
|
|||
Pierre_Reset();
|
||||
|
||||
Lara_InitialiseLoad(NO_ITEM);
|
||||
Level_Unload();
|
||||
Level_Load(level);
|
||||
GameStringTable_Apply(level);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "game/lara/common.h"
|
||||
#include "game/objects/vars.h"
|
||||
#include "game/output.h"
|
||||
#include "game/output/objects.h"
|
||||
#include "game/room.h"
|
||||
#include "game/viewport.h"
|
||||
#include "global/const.h"
|
||||
|
@ -278,22 +279,19 @@ void Object_SetMeshReflective(
|
|||
|
||||
OBJECT_MESH *const mesh = Object_GetMesh(obj->mesh_idx + mesh_idx);
|
||||
mesh->enable_reflections = enabled;
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_tex_face4s; i++) {
|
||||
mesh->tex_face4s[i].enable_reflections = enabled;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_tex_face3s; i++) {
|
||||
mesh->tex_face3s[i].enable_reflections = enabled;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_flat_face4s; i++) {
|
||||
mesh->flat_face4s[i].enable_reflections = enabled;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_flat_face3s; i++) {
|
||||
mesh->flat_face3s[i].enable_reflections = enabled;
|
||||
}
|
||||
Output_Objects_UpdateMesh(mesh);
|
||||
}
|
||||
|
||||
void Object_SetReflective(const GAME_OBJECT_ID obj_id, const bool enabled)
|
||||
|
|
|
@ -27,6 +27,17 @@ static void M_SetupLaraExtra(void)
|
|||
obj->control_func = Lara_ControlExtra;
|
||||
}
|
||||
|
||||
static void M_SetupSkybox(void)
|
||||
{
|
||||
const OBJECT *const obj = Object_Get(O_SKYBOX);
|
||||
if (obj->loaded) {
|
||||
for (int32_t i = 0; i < obj->mesh_count; i++) {
|
||||
OBJECT_MESH *const obj_mesh = Object_GetMesh(obj->mesh_idx + i);
|
||||
obj_mesh->disable_lighting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DisableObject(const GAME_OBJECT_ID obj_id)
|
||||
{
|
||||
OBJECT *const obj = Object_Get(obj_id);
|
||||
|
@ -67,6 +78,7 @@ void Object_SetupAllObjects(void)
|
|||
|
||||
M_SetupLara();
|
||||
M_SetupLaraExtra();
|
||||
M_SetupSkybox();
|
||||
|
||||
Lara_Hair_Initialise();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "game/output.h"
|
||||
|
||||
#include "game/output/meshes.h"
|
||||
#include "game/output/objects.h"
|
||||
#include "game/output/rooms.h"
|
||||
#include "game/output/sprites.h"
|
||||
#include "game/output/textures.h"
|
||||
|
@ -15,6 +16,7 @@
|
|||
#include <libtrx/engine/image.h>
|
||||
#include <libtrx/filesystem.h>
|
||||
#include <libtrx/game/game_buf.h>
|
||||
#include <libtrx/game/output.h>
|
||||
#include <libtrx/memory.h>
|
||||
|
||||
#define MAX_LIGHTNINGS 64
|
||||
|
@ -63,20 +65,14 @@ static struct {
|
|||
GLint bound_vao;
|
||||
GLint bound_vbo;
|
||||
GLint bound_texture;
|
||||
GLint bound_polygon_state[2];
|
||||
} m_CachedState;
|
||||
|
||||
static void M_DrawSphere(const XYZ_32 pos, const int32_t radius);
|
||||
static void M_DrawFlatFace3s(const FACE3 *faces, int32_t count);
|
||||
static void M_DrawFlatFace4s(const FACE4 *faces, int32_t count);
|
||||
static void M_DrawTexturedFace3s(const FACE3 *faces, int32_t count);
|
||||
static void M_DrawTexturedFace4s(const FACE4 *faces, int32_t count);
|
||||
static void M_DrawObjectFace3EnvMap(const FACE3 *faces, int32_t count);
|
||||
static void M_DrawObjectFace4EnvMap(const FACE4 *faces, int32_t count);
|
||||
static uint16_t M_CalcVertex(PHD_VBUF *vbuf, const XYZ_16 pos);
|
||||
static bool M_CalcObjectVertices(const XYZ_16 *vertices, int16_t count);
|
||||
static void M_CalcVerticeLight(const OBJECT_MESH *mesh);
|
||||
static bool M_CalcVerticeEnvMap(const OBJECT_MESH *mesh);
|
||||
static void M_CalcSkyboxLight(const OBJECT_MESH *mesh);
|
||||
|
||||
static void M_DrawSphere(const XYZ_32 pos, const int32_t radius)
|
||||
{
|
||||
|
@ -138,145 +134,6 @@ static void M_DrawSphere(const XYZ_32 pos, const int32_t radius)
|
|||
GFX_Context_SetWireframeMode(wireframe_state);
|
||||
}
|
||||
|
||||
static void M_DrawFlatFace3s(const FACE3 *const faces, const int32_t count)
|
||||
{
|
||||
S_Output_DisableTextureMode();
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE3 *const face = &faces[i];
|
||||
PHD_VBUF *const vns[3] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
};
|
||||
|
||||
const RGBA_8888 color =
|
||||
Output_RGB2RGBA(Output_GetPaletteColor8(face->palette_idx));
|
||||
S_Output_DrawFlatTriangle(vns[0], vns[1], vns[2], color);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawFlatFace4s(const FACE4 *const faces, const int32_t count)
|
||||
{
|
||||
S_Output_DisableTextureMode();
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE4 *const face = &faces[i];
|
||||
PHD_VBUF *const vns[4] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
&m_VBuf[face->vertices[3]],
|
||||
};
|
||||
|
||||
const RGBA_8888 color =
|
||||
Output_RGB2RGBA(Output_GetPaletteColor8(face->palette_idx));
|
||||
S_Output_DrawFlatTriangle(vns[0], vns[1], vns[2], color);
|
||||
S_Output_DrawFlatTriangle(vns[2], vns[3], vns[0], color);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawTexturedFace3s(const FACE3 *const faces, const int32_t count)
|
||||
{
|
||||
S_Output_EnableTextureMode();
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE3 *const face = &faces[i];
|
||||
PHD_VBUF *const vns[3] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
};
|
||||
|
||||
OBJECT_TEXTURE *const tex = Output_GetObjectTexture(face->texture_idx);
|
||||
for (int32_t j = 0; j < 3; j++) {
|
||||
vns[j]->u = tex->uv[j].u;
|
||||
vns[j]->v = tex->uv[j].v;
|
||||
vns[j]->z = 1.0f;
|
||||
vns[j]->w = 1.0f;
|
||||
}
|
||||
|
||||
S_Output_DrawTexturedTriangle(
|
||||
vns[0], vns[1], vns[2], tex->tex_page, tex->draw_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawTexturedFace4s(const FACE4 *const faces, const int32_t count)
|
||||
{
|
||||
S_Output_EnableTextureMode();
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE4 *const face = &faces[i];
|
||||
PHD_VBUF *const vns[4] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
&m_VBuf[face->vertices[3]],
|
||||
};
|
||||
|
||||
OBJECT_TEXTURE *const tex = Output_GetObjectTexture(face->texture_idx);
|
||||
for (int32_t j = 0; j < 4; j++) {
|
||||
vns[j]->u = tex->uv[j].u;
|
||||
vns[j]->v = tex->uv[j].v;
|
||||
if (g_Config.rendering.enable_trapezoid_filter) {
|
||||
vns[j]->z = face->texture_zw[j].z;
|
||||
vns[j]->w = face->texture_zw[j].w;
|
||||
} else {
|
||||
vns[j]->z = 1.0f;
|
||||
vns[j]->w = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
S_Output_DrawTexturedQuad(
|
||||
vns[0], vns[1], vns[2], vns[3], tex->tex_page, tex->draw_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawObjectFace3EnvMap(
|
||||
const FACE3 *const faces, const int32_t count)
|
||||
{
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE3 *const face = &faces[i];
|
||||
PHD_VBUF *vns[3] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
};
|
||||
|
||||
for (int32_t j = 0; j < 3; j++) {
|
||||
vns[j]->u = m_EnvMapUV[face->vertices[j]].u;
|
||||
vns[j]->v = m_EnvMapUV[face->vertices[j]].v;
|
||||
}
|
||||
|
||||
if (face->enable_reflections) {
|
||||
S_Output_DrawEnvMapTriangle(vns[0], vns[1], vns[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawObjectFace4EnvMap(
|
||||
const FACE4 *const faces, const int32_t count)
|
||||
{
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
const FACE4 *const face = &faces[i];
|
||||
PHD_VBUF *vns[4] = {
|
||||
&m_VBuf[face->vertices[0]],
|
||||
&m_VBuf[face->vertices[1]],
|
||||
&m_VBuf[face->vertices[2]],
|
||||
&m_VBuf[face->vertices[3]],
|
||||
};
|
||||
|
||||
for (int32_t j = 0; j < 4; j++) {
|
||||
vns[j]->u = m_EnvMapUV[face->vertices[j]].u;
|
||||
vns[j]->v = m_EnvMapUV[face->vertices[j]].v;
|
||||
}
|
||||
|
||||
if (face->enable_reflections) {
|
||||
S_Output_DrawEnvMapQuad(vns[0], vns[1], vns[2], vns[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t M_CalcVertex(PHD_VBUF *const vbuf, const XYZ_16 pos)
|
||||
{
|
||||
// clang-format off
|
||||
|
@ -349,7 +206,6 @@ static void M_CalcVerticeLight(const OBJECT_MESH *const mesh)
|
|||
CLAMP(shade, 0, 0x1FFF);
|
||||
m_VBuf[i].g = shade;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -359,7 +215,6 @@ static void M_CalcVerticeLight(const OBJECT_MESH *const mesh)
|
|||
for (int32_t i = 0; i < mesh->num_lights; i++) {
|
||||
m_VBuf[i].g = shade;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -437,24 +292,20 @@ static bool M_CalcVerticeEnvMap(const OBJECT_MESH *mesh)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void M_CalcSkyboxLight(const OBJECT_MESH *const mesh)
|
||||
{
|
||||
for (int32_t i = 0; i < ABS(mesh->num_lights); i++) {
|
||||
m_VBuf[i].g = 0xFFF;
|
||||
}
|
||||
}
|
||||
|
||||
bool Output_Init(void)
|
||||
{
|
||||
const bool result = S_Output_Init();
|
||||
Output_Textures_Init();
|
||||
Output_Sprites_Init();
|
||||
Output_Meshes_Init();
|
||||
Output_Rooms_Init();
|
||||
return S_Output_Init();
|
||||
Output_Objects_Init();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Output_Shutdown(void)
|
||||
{
|
||||
Output_Objects_Shutdown();
|
||||
Output_Rooms_Shutdown();
|
||||
Output_Meshes_Shutdown();
|
||||
Output_Sprites_Shutdown();
|
||||
|
@ -483,13 +334,18 @@ void Output_ApplyRenderSettings(void)
|
|||
}
|
||||
}
|
||||
|
||||
void Output_DownloadTextures(void)
|
||||
void Output_ObserveLevelLoad(void)
|
||||
{
|
||||
S_Output_DownloadTextures(Output_GetTexturePageCount());
|
||||
|
||||
Output_Textures_ObserveLevelLoad();
|
||||
Output_Sprites_ObserveLevelLoad();
|
||||
Output_Rooms_ObserveLevelLoad();
|
||||
Output_Objects_ObserveLevelLoad();
|
||||
}
|
||||
|
||||
void Output_ObserveLevelUnload(void)
|
||||
{
|
||||
Output_Objects_ObserveLevelUnload();
|
||||
}
|
||||
|
||||
void Output_DrawBlack(void)
|
||||
|
@ -540,26 +396,10 @@ void Output_ClearDepthBuffer(void)
|
|||
|
||||
void Output_DrawObjectMesh(const OBJECT_MESH *const mesh, const int32_t clip)
|
||||
{
|
||||
if (!M_CalcObjectVertices(mesh->vertices, mesh->num_vertices)) {
|
||||
return;
|
||||
}
|
||||
|
||||
M_CalcVerticeLight(mesh);
|
||||
M_DrawTexturedFace4s(mesh->tex_face4s, mesh->num_tex_face4s);
|
||||
M_DrawTexturedFace3s(mesh->tex_face3s, mesh->num_tex_face3s);
|
||||
M_DrawFlatFace4s(mesh->flat_face4s, mesh->num_flat_face4s);
|
||||
M_DrawFlatFace3s(mesh->flat_face3s, mesh->num_flat_face3s);
|
||||
|
||||
if (mesh->enable_reflections && g_Config.visuals.enable_reflections) {
|
||||
if (!M_CalcVerticeEnvMap(mesh)) {
|
||||
return;
|
||||
}
|
||||
|
||||
M_DrawObjectFace4EnvMap(mesh->tex_face4s, mesh->num_tex_face4s);
|
||||
M_DrawObjectFace3EnvMap(mesh->tex_face3s, mesh->num_tex_face3s);
|
||||
M_DrawObjectFace4EnvMap(mesh->flat_face4s, mesh->num_flat_face4s);
|
||||
M_DrawObjectFace3EnvMap(mesh->flat_face3s, mesh->num_flat_face3s);
|
||||
}
|
||||
S_Output_Flush();
|
||||
Output_RememberState();
|
||||
Output_Objects_RenderMesh(g_MatrixPtr, Output_GetTint(), mesh);
|
||||
Output_RestoreState();
|
||||
|
||||
if (g_Config.rendering.enable_debug_spheres) {
|
||||
M_DrawSphere(
|
||||
|
@ -570,6 +410,7 @@ void Output_DrawObjectMesh(const OBJECT_MESH *const mesh, const int32_t clip)
|
|||
},
|
||||
mesh->radius);
|
||||
}
|
||||
S_Output_Flush();
|
||||
}
|
||||
|
||||
void Output_DrawObjectMesh_I(const OBJECT_MESH *const mesh, const int32_t clip)
|
||||
|
@ -597,22 +438,24 @@ void Output_DrawSkybox(const OBJECT_MESH *const mesh)
|
|||
g_PhdRight = Viewport_GetMaxX();
|
||||
g_PhdBottom = Viewport_GetMaxY();
|
||||
|
||||
if (!M_CalcObjectVertices(mesh->vertices, mesh->num_vertices)) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_Output_DisableDepthTest();
|
||||
M_CalcSkyboxLight(mesh);
|
||||
M_DrawTexturedFace4s(mesh->tex_face4s, mesh->num_tex_face4s);
|
||||
M_DrawTexturedFace3s(mesh->tex_face3s, mesh->num_tex_face3s);
|
||||
M_DrawFlatFace4s(mesh->flat_face4s, mesh->num_flat_face4s);
|
||||
M_DrawFlatFace3s(mesh->flat_face3s, mesh->num_flat_face3s);
|
||||
Output_RememberState();
|
||||
Output_Objects_RenderMesh(g_MatrixPtr, Output_GetTint(), mesh);
|
||||
Output_RestoreState();
|
||||
S_Output_EnableDepthTest();
|
||||
}
|
||||
|
||||
void Output_DrawRoomMesh(const ROOM *const room)
|
||||
void Output_DrawRoomMesh(ROOM *const room)
|
||||
{
|
||||
Output_LightRoom(room);
|
||||
Output_EnableScissor(
|
||||
room->bound_left, room->bound_bottom,
|
||||
room->bound_right - room->bound_left,
|
||||
room->bound_bottom - room->bound_top);
|
||||
Output_RememberState();
|
||||
Output_Rooms_RenderRoom(g_MatrixPtr, Output_GetTint(), room);
|
||||
Output_RestoreState();
|
||||
Output_DisableScissor();
|
||||
}
|
||||
|
||||
void Output_DrawRoomPortals(const ROOM *const room)
|
||||
|
@ -808,6 +651,16 @@ void Output_SetLightDivider(const int32_t divider)
|
|||
m_LsDivider = divider;
|
||||
}
|
||||
|
||||
int32_t Output_GetLightDivider(void)
|
||||
{
|
||||
return m_LsDivider;
|
||||
}
|
||||
|
||||
XYZ_32 Output_GetLightVectorView(void)
|
||||
{
|
||||
return m_LsVectorView;
|
||||
}
|
||||
|
||||
int32_t Output_GetNearZ(void)
|
||||
{
|
||||
return Output_GetDrawDistMin() << W2V_SHIFT;
|
||||
|
@ -1048,7 +901,7 @@ void Output_AnimateTextures(const int32_t num_frames)
|
|||
m_AnimatedTexturesOffset -= 5;
|
||||
}
|
||||
if (update) {
|
||||
Output_Textures_Update();
|
||||
Output_Textures_CycleAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1336,6 +1189,7 @@ void Output_RememberState(void)
|
|||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &m_CachedState.bound_vao);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &m_CachedState.bound_vbo);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_CachedState.bound_texture);
|
||||
glGetIntegerv(GL_POLYGON_MODE, &m_CachedState.bound_polygon_state[0]);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
|
@ -1345,5 +1199,6 @@ void Output_RestoreState(void)
|
|||
glBindBuffer(GL_ARRAY_BUFFER, m_CachedState.bound_vbo);
|
||||
glBindTexture(GL_TEXTURE_2D, m_CachedState.bound_texture);
|
||||
glUseProgram(m_CachedState.bound_program);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, m_CachedState.bound_polygon_state[0]);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ void Output_ReserveVertexBuffer(size_t size);
|
|||
|
||||
void Output_SetWindowSize(int width, int height);
|
||||
void Output_ApplyRenderSettings(void);
|
||||
void Output_DownloadTextures(void);
|
||||
void Output_ObserveLevelLoad(void);
|
||||
void Output_ObserveLevelUnload(void);
|
||||
|
||||
int32_t Output_GetNearZ(void);
|
||||
int32_t Output_GetFarZ(void);
|
||||
|
@ -38,7 +39,7 @@ void Output_SetSkyboxEnabled(bool enabled);
|
|||
bool Output_IsSkyboxEnabled(void);
|
||||
void Output_DrawSkybox(const OBJECT_MESH *mesh);
|
||||
|
||||
void Output_DrawRoomMesh(const ROOM *mesh);
|
||||
void Output_DrawRoomMesh(ROOM *mesh);
|
||||
void Output_DrawRoomPortals(const ROOM *room);
|
||||
void Output_DrawRoomTriggers(const ROOM *room);
|
||||
void Output_DrawShadow(int16_t size, const BOUNDS_16 *bounds, const ITEM *item);
|
||||
|
@ -98,3 +99,5 @@ void Output_RememberState(void);
|
|||
void Output_RestoreState(void);
|
||||
|
||||
float Output_AdjustUV(uint16_t uv);
|
||||
int32_t Output_GetLightDivider(void);
|
||||
XYZ_32 Output_GetLightVectorView(void);
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
#include "game/output/shader.h"
|
||||
|
||||
// clang-format off
|
||||
#define VERT_NO_CAUSTICS 0b0000'0001 // = 0x01
|
||||
#define VERT_FLAT_SHADED 0b0000'0010 // = 0x02
|
||||
#define VERT_REFLECTIVE 0b0000'0100 // = 0x04
|
||||
#define VERT_NO_LIGHTING 0b0000'1000 // = 0x08
|
||||
// clang-format on
|
||||
|
||||
void Output_Meshes_Init(void);
|
||||
void Output_Meshes_Shutdown(void);
|
||||
void Output_Meshes_RenderBegin(void);
|
||||
|
|
423
src/tr1/game/output/objects.c
Normal file
423
src/tr1/game/output/objects.c
Normal file
|
@ -0,0 +1,423 @@
|
|||
#include "game/output.h"
|
||||
#include "game/output/meshes.h"
|
||||
#include "game/output/rooms.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/output/utils.h"
|
||||
|
||||
#include <libtrx/debug.h>
|
||||
#include <libtrx/gfx/gl/utils.h>
|
||||
#include <libtrx/memory.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
|
||||
// clang-format on
|
||||
} M_MESH_VERTEX;
|
||||
|
||||
typedef uint16_t M_MESH_SHADE;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
int32_t vertex_start;
|
||||
int32_t vertex_count;
|
||||
} M_BATCH;
|
||||
|
||||
static struct {
|
||||
GLuint vao;
|
||||
GLuint geom_vbo;
|
||||
size_t vertex_count;
|
||||
GLuint shade_vbo;
|
||||
M_MESH_VERTEX *geom_vbo_data;
|
||||
M_MESH_SHADE *shade_vbo_data;
|
||||
int32_t *light_idx_map;
|
||||
size_t batch_count;
|
||||
M_BATCH *batches;
|
||||
} m_Priv;
|
||||
|
||||
static OUTPUT_SHADER *m_Shader = nullptr;
|
||||
|
||||
static M_BATCH *M_GetBatch(const OBJECT_MESH *const mesh)
|
||||
{
|
||||
const int16_t mesh_num = Object_GetMeshIndex(mesh);
|
||||
return &m_Priv.batches[mesh_num];
|
||||
}
|
||||
|
||||
static void M_FillVertex(
|
||||
M_MESH_VERTEX *const out_vertex, const int32_t uvw_idx, const XYZ_16 pos,
|
||||
const XYZ_16 normal, const uint16_t flags)
|
||||
{
|
||||
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 = flags;
|
||||
}
|
||||
|
||||
static uint16_t M_GetFlags(const OBJECT_MESH *const mesh, const bool flat)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
if (flat) {
|
||||
flags |= VERT_FLAT_SHADED;
|
||||
}
|
||||
if (mesh->enable_reflections) {
|
||||
flags |= VERT_REFLECTIVE;
|
||||
}
|
||||
if (mesh->disable_lighting) {
|
||||
flags |= VERT_NO_LIGHTING;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillRoomFace4(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX *out_vertex,
|
||||
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->vertices[face->vertices[j]],
|
||||
mesh->lighting.normals[face->vertices[j]], M_GetFlags(mesh, flat));
|
||||
out_vertex->trapezoid_ratio[0] = face->texture_zw[j].z;
|
||||
out_vertex->trapezoid_ratio[1] = face->texture_zw[j].w;
|
||||
if (flat) {
|
||||
out_vertex->color =
|
||||
Output_RGB2RGBA(Output_GetPaletteColor8(face->palette_idx));
|
||||
} else {
|
||||
out_vertex->color = (RGBA_8888) { 255, 255, 255, 255 };
|
||||
}
|
||||
out_vertex++;
|
||||
}
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
static M_MESH_VERTEX *M_FillRoomFace3(
|
||||
const OBJECT_MESH *const mesh, M_MESH_VERTEX *out_vertex,
|
||||
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->vertices[face->vertices[j]],
|
||||
mesh->lighting.normals[face->vertices[j]], M_GetFlags(mesh, flat));
|
||||
out_vertex->trapezoid_ratio[0] = 1.0f;
|
||||
out_vertex->trapezoid_ratio[1] = 1.0f;
|
||||
if (flat) {
|
||||
out_vertex->color =
|
||||
Output_RGB2RGBA(Output_GetPaletteColor8(face->palette_idx));
|
||||
} else {
|
||||
out_vertex->color = (RGBA_8888) { 255, 255, 255, 255 };
|
||||
}
|
||||
out_vertex++;
|
||||
}
|
||||
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];
|
||||
|
||||
for (int32_t i = 0; i < mesh->num_tex_face4s; i++) {
|
||||
out_vertex =
|
||||
M_FillRoomFace4(mesh, out_vertex, &mesh->tex_face4s[i], false);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_tex_face3s; i++) {
|
||||
out_vertex =
|
||||
M_FillRoomFace3(mesh, out_vertex, &mesh->tex_face3s[i], false);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face4s; i++) {
|
||||
out_vertex =
|
||||
M_FillRoomFace4(mesh, out_vertex, &mesh->flat_face4s[i], true);
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face3s; i++) {
|
||||
out_vertex =
|
||||
M_FillRoomFace3(mesh, out_vertex, &mesh->flat_face3s[i], true);
|
||||
}
|
||||
|
||||
#define SET(v, j) light_idx_map[v] = face->vertices[j];
|
||||
int32_t *const light_idx_map = &m_Priv.light_idx_map[batch->vertex_start];
|
||||
int32_t v = 0;
|
||||
for (int32_t i = 0; i < mesh->num_tex_face4s; i++) {
|
||||
const FACE4 *const face = &mesh->tex_face4s[i];
|
||||
for (int32_t j = 0; j < OUTPUT_QUAD_VERTICES; j++) {
|
||||
SET(v, OUTPUT_QUAD_TO_FAN(j));
|
||||
v++;
|
||||
}
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_tex_face3s; i++) {
|
||||
const FACE3 *const face = &mesh->tex_face3s[i];
|
||||
for (int32_t j = 0; j < OUTPUT_TRI_VERTICES; j++) {
|
||||
SET(v, OUTPUT_TRI_TO_FAN(j));
|
||||
v++;
|
||||
}
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face4s; i++) {
|
||||
const FACE4 *const face = &mesh->flat_face4s[i];
|
||||
for (int32_t j = 0; j < OUTPUT_QUAD_VERTICES; j++) {
|
||||
SET(v, OUTPUT_QUAD_TO_FAN(j));
|
||||
v++;
|
||||
}
|
||||
}
|
||||
for (int32_t i = 0; i < mesh->num_flat_face3s; i++) {
|
||||
const FACE3 *const face = &mesh->flat_face3s[i];
|
||||
for (int32_t j = 0; j < OUTPUT_TRI_VERTICES; j++) {
|
||||
SET(v, OUTPUT_TRI_TO_FAN(j));
|
||||
v++;
|
||||
}
|
||||
}
|
||||
#undef SET
|
||||
}
|
||||
|
||||
static void M_UpdateShades(
|
||||
const MATRIX *const matrix, const OBJECT_MESH *const mesh)
|
||||
{
|
||||
M_BATCH *const batch = M_GetBatch(mesh);
|
||||
M_MESH_SHADE *const out_shades =
|
||||
&m_Priv.shade_vbo_data[batch->vertex_start];
|
||||
int32_t *const light_idx_map = &m_Priv.light_idx_map[batch->vertex_start];
|
||||
|
||||
const int32_t ls_adder = Output_GetLightAdder();
|
||||
const int32_t ls_divider = Output_GetLightDivider();
|
||||
const XYZ_32 ls_vector_view = Output_GetLightVectorView();
|
||||
|
||||
if (mesh->num_lights <= 0) {
|
||||
for (int32_t i = 0; i < batch->vertex_count; i++) {
|
||||
const int32_t j = light_idx_map[i];
|
||||
int16_t shade = ls_adder + mesh->lighting.lights[j];
|
||||
CLAMP(shade, 0, 0x1FFF);
|
||||
out_shades[i] = shade;
|
||||
}
|
||||
} else if (ls_divider == 0) {
|
||||
int16_t shade = ls_adder;
|
||||
CLAMP(shade, 0, 0x1FFF);
|
||||
for (int32_t i = 0; i < batch->vertex_count; i++) {
|
||||
out_shades[i] = shade;
|
||||
}
|
||||
} else {
|
||||
// clang-format off
|
||||
const int32_t xv = (
|
||||
matrix->_00 * ls_vector_view.x +
|
||||
matrix->_10 * ls_vector_view.y +
|
||||
matrix->_20 * ls_vector_view.z
|
||||
) / ls_divider;
|
||||
|
||||
const int32_t yv = (
|
||||
matrix->_01 * ls_vector_view.x +
|
||||
matrix->_11 * ls_vector_view.y +
|
||||
matrix->_21 * ls_vector_view.z
|
||||
) / ls_divider;
|
||||
|
||||
const int32_t zv = (
|
||||
matrix->_02 * ls_vector_view.x +
|
||||
matrix->_12 * ls_vector_view.y +
|
||||
matrix->_22 * ls_vector_view.z
|
||||
) / ls_divider;
|
||||
// clang-format on
|
||||
|
||||
for (int32_t i = 0; i < batch->vertex_count; i++) {
|
||||
const int32_t j = light_idx_map[i];
|
||||
const XYZ_16 *const normal = &mesh->lighting.normals[j];
|
||||
int16_t shade = ls_adder
|
||||
+ ((normal->x * xv + normal->y * yv + normal->z * zv) >> 16);
|
||||
CLAMP(shade, 0, 0x1FFF);
|
||||
out_shades[i] = shade;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_UpdateVertices(void)
|
||||
{
|
||||
for (int32_t i = 0; i < Object_GetMeshCount(); i++) {
|
||||
M_UpdateGeometry(Object_GetMesh(i));
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
m_Priv.vertex_count * sizeof(M_MESH_VERTEX), m_Priv.geom_vbo_data,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
GFX_TRACK_DATA(
|
||||
glBufferData, GL_ARRAY_BUFFER,
|
||||
m_Priv.vertex_count * sizeof(M_MESH_SHADE), m_Priv.shade_vbo_data,
|
||||
GL_DYNAMIC_DRAW); // shades are always dynamic
|
||||
}
|
||||
|
||||
static void M_PrepareBuffers(void)
|
||||
{
|
||||
m_Priv.batch_count = Object_GetMeshCount();
|
||||
m_Priv.batches =
|
||||
Memory_Realloc(m_Priv.batches, sizeof(M_BATCH) * m_Priv.batch_count);
|
||||
|
||||
int32_t last_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->vertex_start = last_vertex;
|
||||
batch->vertex_count = 0;
|
||||
batch->vertex_count += obj_mesh->num_tex_face4s * OUTPUT_QUAD_VERTICES;
|
||||
batch->vertex_count += obj_mesh->num_tex_face3s * OUTPUT_TRI_VERTICES;
|
||||
batch->vertex_count += obj_mesh->num_flat_face4s * OUTPUT_QUAD_VERTICES;
|
||||
batch->vertex_count += obj_mesh->num_flat_face3s * OUTPUT_TRI_VERTICES;
|
||||
last_vertex += batch->vertex_count;
|
||||
}
|
||||
m_Priv.vertex_count = last_vertex;
|
||||
|
||||
m_Priv.geom_vbo_data =
|
||||
Memory_Alloc(m_Priv.vertex_count * sizeof(M_MESH_VERTEX));
|
||||
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.shade_vbo);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
glBindVertexArray(m_Priv.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(
|
||||
0, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, pos));
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(
|
||||
1, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, normal));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
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),
|
||||
(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);
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(
|
||||
6, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
|
||||
M_UpdateVertices();
|
||||
}
|
||||
|
||||
static void M_FreeBuffers(void)
|
||||
{
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
if (m_Priv.vao != 0) {
|
||||
glDeleteVertexArrays(1, &m_Priv.vao);
|
||||
m_Priv.vao = 0;
|
||||
}
|
||||
if (m_Priv.geom_vbo != 0) {
|
||||
glDeleteBuffers(1, &m_Priv.geom_vbo);
|
||||
m_Priv.geom_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.shade_vbo_data);
|
||||
Memory_FreePointer(&m_Priv.light_idx_map);
|
||||
Memory_FreePointer(&m_Priv.batches);
|
||||
}
|
||||
|
||||
void Output_Objects_Init(void)
|
||||
{
|
||||
m_Shader = Output_Meshes_GetShader();
|
||||
}
|
||||
|
||||
void Output_Objects_Shutdown(void)
|
||||
{
|
||||
M_FreeBuffers();
|
||||
}
|
||||
|
||||
void Output_Objects_ObserveLevelLoad(void)
|
||||
{
|
||||
M_PrepareBuffers();
|
||||
}
|
||||
|
||||
void Output_Objects_ObserveLevelUnload(void)
|
||||
{
|
||||
M_FreeBuffers();
|
||||
}
|
||||
|
||||
void Output_Objects_UpdateMesh(const OBJECT_MESH *const mesh)
|
||||
{
|
||||
if (m_Priv.geom_vbo_data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const M_BATCH *const batch = M_GetBatch(mesh);
|
||||
M_UpdateGeometry(mesh);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.geom_vbo);
|
||||
GFX_TRACK_SUBDATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
batch->vertex_start * sizeof(M_MESH_VERTEX),
|
||||
batch->vertex_count * sizeof(M_MESH_VERTEX),
|
||||
&m_Priv.geom_vbo_data[batch->vertex_start]);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
void Output_Objects_RenderMesh(
|
||||
const MATRIX *const matrix, const RGB_F tint, const OBJECT_MESH *const mesh)
|
||||
{
|
||||
const M_BATCH *const batch = M_GetBatch(mesh);
|
||||
|
||||
M_UpdateShades(matrix, mesh);
|
||||
|
||||
Output_Shader_UploadMatrix(m_Shader, matrix);
|
||||
Output_Shader_UploadTint(m_Shader, tint);
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
GFX_TRACK_SUBDATA(
|
||||
glBufferSubData, GL_ARRAY_BUFFER,
|
||||
batch->vertex_start * sizeof(M_MESH_SHADE),
|
||||
batch->vertex_count * sizeof(M_MESH_SHADE),
|
||||
&m_Priv.shade_vbo_data[batch->vertex_start]);
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glBindVertexArray(m_Priv.vao);
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetObjectUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
Output_Shader_UploadWibble(m_Shader, -1.0f);
|
||||
glDrawArrays(GL_TRIANGLES, batch->vertex_start, batch->vertex_count);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
GFX_GL_CheckError();
|
||||
}
|
14
src/tr1/game/output/objects.h
Normal file
14
src/tr1/game/output/objects.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <libtrx/game/matrix.h>
|
||||
#include <libtrx/game/objects/types.h>
|
||||
#include <libtrx/game/output/types.h>
|
||||
|
||||
void Output_Objects_Init(void);
|
||||
void Output_Objects_Shutdown(void);
|
||||
void Output_Objects_ObserveLevelLoad(void);
|
||||
void Output_Objects_ObserveLevelUnload(void);
|
||||
|
||||
void Output_Objects_UpdateMesh(const OBJECT_MESH *mesh);
|
||||
void Output_Objects_RenderMesh(
|
||||
const MATRIX *matrix, RGB_F tint, const OBJECT_MESH *mesh);
|
|
@ -11,17 +11,12 @@
|
|||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
// attribute 0
|
||||
XYZ_F pos;
|
||||
|
||||
// attribute 1
|
||||
int32_t uvw_idx;
|
||||
|
||||
// attribute 2
|
||||
float trapezoid_ratio[2];
|
||||
|
||||
// attribute 3
|
||||
uint16_t flags;
|
||||
// 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
|
||||
} M_MESH_VERTEX;
|
||||
|
||||
typedef uint16_t M_MESH_SHADE;
|
||||
|
@ -64,7 +59,7 @@ static void M_FillVertex(
|
|||
{
|
||||
out_vertex->pos = (XYZ_F) { .x = pos.x, .y = pos.y, .z = pos.z };
|
||||
out_vertex->uvw_idx = uvw_idx;
|
||||
out_vertex->flags = flags;
|
||||
out_vertex->flags = flags & NO_VERT_MOVE ? VERT_NO_CAUSTICS : 0;
|
||||
}
|
||||
|
||||
static void M_AppendRoomFace4(const ROOM *const room, const FACE4 *const face)
|
||||
|
@ -190,25 +185,29 @@ static void M_PrepareBuffers(void)
|
|||
0, 3, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, pos));
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribIPointer(
|
||||
1, 1, GL_UNSIGNED_INT, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, uvw_idx));
|
||||
// ignore attribute 1 (normals) - rooms never have reflective faces
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(
|
||||
2, 2, GL_FLOAT, GL_FALSE, sizeof(M_MESH_VERTEX),
|
||||
(void *)(intptr_t)offsetof(M_MESH_VERTEX, trapezoid_ratio));
|
||||
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(
|
||||
3, 1, GL_UNSIGNED_SHORT, sizeof(M_MESH_VERTEX),
|
||||
4, 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
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_Priv.shade_vbo);
|
||||
glEnableVertexAttribArray(4);
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(
|
||||
4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
6, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(M_MESH_SHADE), 0);
|
||||
|
||||
M_UpdateRoomVertices();
|
||||
}
|
||||
|
@ -271,10 +270,15 @@ void Output_Rooms_RenderRoom(
|
|||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glBindVertexArray(m_Priv.vao);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetObjectUVWsTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetObjectUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
if (Output_GetWibbleOffset() >= 0) {
|
||||
Output_Shader_UploadWibble(m_Shader, -1);
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
typedef enum {
|
||||
M_UNIFORM_TEX_ATLAS,
|
||||
M_UNIFORM_TEX_UVW,
|
||||
M_UNIFORM_TEX_ENV_MAP,
|
||||
M_UNIFORM_SMOOTHING_ENABLED,
|
||||
M_UNIFORM_ALPHA_DISCARD_ENABLED,
|
||||
M_UNIFORM_ALPHA_THRESHOLD,
|
||||
M_UNIFORM_TRAPEZOID_FILTER_ENABLED,
|
||||
M_UNIFORM_BRIGHTNESS_MULTIPLIER,
|
||||
M_UNIFORM_GLOBAL_TINT,
|
||||
|
@ -42,9 +45,12 @@ OUTPUT_SHADER *Output_Shader_Create(const char *const path)
|
|||
GFX_GL_Program_Link(&shader->program);
|
||||
|
||||
const char *const uniform_names[] = {
|
||||
[M_UNIFORM_TEX_ATLAS] = "uTexture",
|
||||
[M_UNIFORM_TEX_ATLAS] = "uTexAtlas",
|
||||
[M_UNIFORM_TEX_UVW] = "uUVW",
|
||||
[M_UNIFORM_TEX_ENV_MAP] = "uTexEnvMap",
|
||||
[M_UNIFORM_SMOOTHING_ENABLED] = "uSmoothingEnabled",
|
||||
[M_UNIFORM_ALPHA_DISCARD_ENABLED] = "uAlphaDiscardEnabled",
|
||||
[M_UNIFORM_ALPHA_THRESHOLD] = "uAlphaThreshold",
|
||||
[M_UNIFORM_TRAPEZOID_FILTER_ENABLED] = "uTrapezoidFilterEnabled",
|
||||
[M_UNIFORM_BRIGHTNESS_MULTIPLIER] = "uBrightnessMultiplier",
|
||||
[M_UNIFORM_GLOBAL_TINT] = "uGlobalTint",
|
||||
|
@ -62,6 +68,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);
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
@ -77,6 +84,12 @@ void Output_Shader_UploadCommonUniforms(const OUTPUT_SHADER *const shader)
|
|||
GFX_TRACK_UNIFORM(
|
||||
glUniform1f, shader->uniforms[M_UNIFORM_SMOOTHING_ENABLED],
|
||||
g_Config.rendering.texture_filter);
|
||||
GFX_TRACK_UNIFORM(
|
||||
glUniform1f, shader->uniforms[M_UNIFORM_ALPHA_THRESHOLD],
|
||||
g_Config.rendering.enable_wireframe ? -1.0f : 0.0f);
|
||||
GFX_TRACK_UNIFORM(
|
||||
glUniform1i, shader->uniforms[M_UNIFORM_ALPHA_DISCARD_ENABLED],
|
||||
!g_Config.rendering.enable_wireframe);
|
||||
GFX_TRACK_UNIFORM(
|
||||
glUniform1f, shader->uniforms[M_UNIFORM_TRAPEZOID_FILTER_ENABLED],
|
||||
g_Config.rendering.enable_trapezoid_filter);
|
||||
|
|
|
@ -191,15 +191,15 @@ static void M_DrawBuffer(
|
|||
{
|
||||
glBindVertexArray(buffer->vao);
|
||||
GFX_GL_CheckError();
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
GFX_GL_CheckError();
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetSpriteUVWsTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, Output_Textures_GetSpriteUVWsTexture());
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, Output_Textures_GetEnvMapTexture());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, Output_Textures_GetAtlasTexture());
|
||||
GFX_GL_CheckError();
|
||||
glDrawArrays(GL_TRIANGLES, start, count);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
|
|
@ -41,19 +41,20 @@ static struct {
|
|||
} m_AnimationRanges;
|
||||
|
||||
static struct {
|
||||
GLuint tex; // 3D texture to hold atlas pages
|
||||
GLuint tex_atlas;
|
||||
GLuint tex_env_map;
|
||||
M_TEXTURE_DATA objects;
|
||||
M_TEXTURE_DATA sprites;
|
||||
} m_LevelData = {};
|
||||
} m_Priv = {};
|
||||
|
||||
int M_CompareAnimationRange(const void *const a, const void *const b)
|
||||
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;
|
||||
}
|
||||
|
||||
void M_MergeAndGlueAnimationRanges(M_ANIMATION_RANGES *const source)
|
||||
static void M_MergeAndGlueAnimationRanges(M_ANIMATION_RANGES *const source)
|
||||
{
|
||||
ASSERT(source != nullptr);
|
||||
if (source->range_count == 0) {
|
||||
|
@ -169,29 +170,10 @@ static void M_FreeTextureData(M_TEXTURE_DATA *const data)
|
|||
}
|
||||
}
|
||||
|
||||
void Output_Textures_Init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void Output_Textures_Shutdown(void)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
M_FreeTextureData(&m_LevelData.objects);
|
||||
M_FreeTextureData(&m_LevelData.sprites);
|
||||
if (m_LevelData.tex != 0) {
|
||||
glDeleteTextures(1, &m_LevelData.tex);
|
||||
m_LevelData.tex = 0;
|
||||
}
|
||||
|
||||
Memory_FreePointer(&m_AnimationRanges.objects.ranges);
|
||||
Memory_FreePointer(&m_AnimationRanges.sprites.ranges);
|
||||
}
|
||||
|
||||
static void M_FillObjectUVW(const int32_t i)
|
||||
{
|
||||
const OBJECT_TEXTURE *const texture = Output_GetObjectTexture(i);
|
||||
M_UVW *const corners = m_LevelData.objects.uvw[i].corners;
|
||||
M_UVW *const corners = m_Priv.objects.uvw[i].corners;
|
||||
for (int32_t j = 0; j < 4; j++) {
|
||||
corners[j].u = Output_AdjustUV(texture->uv[j].u);
|
||||
corners[j].v = Output_AdjustUV(texture->uv[j].v);
|
||||
|
@ -207,7 +189,7 @@ static void M_FillSpriteUVW(const int32_t i)
|
|||
const float v0 = (sprite->offset >> 8) / 256.0f + adj;
|
||||
const float u1 = u0 + (sprite->width >> 8) / 256.0f - 2 * adj;
|
||||
const float v1 = v0 + (sprite->height >> 8) / 256.0f - 2 * adj;
|
||||
M_UVW *const corners = m_LevelData.sprites.uvw[i].corners;
|
||||
M_UVW *const corners = m_Priv.sprites.uvw[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;
|
||||
|
@ -241,17 +223,17 @@ static void M_UploadTextureData(const M_TEXTURE_DATA *const data)
|
|||
|
||||
static void M_UploadObjectUVWs(void)
|
||||
{
|
||||
M_UploadTextureData(&m_LevelData.objects);
|
||||
M_UploadTextureData(&m_Priv.objects);
|
||||
}
|
||||
|
||||
static void M_UploadSpriteUVWs(void)
|
||||
{
|
||||
M_UploadTextureData(&m_LevelData.sprites);
|
||||
M_UploadTextureData(&m_Priv.sprites);
|
||||
}
|
||||
|
||||
static void M_UploadObjectAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
||||
{
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_LevelData.objects.tbo);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.objects.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++) {
|
||||
|
@ -261,13 +243,13 @@ static void M_UploadObjectAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
|||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
range->index * sizeof(M_UVW_PACK),
|
||||
range->count * sizeof(M_UVW_PACK),
|
||||
m_LevelData.objects.uvw + range->index);
|
||||
m_Priv.objects.uvw + range->index);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_UploadSpriteAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
||||
{
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_LevelData.sprites.tbo);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, m_Priv.sprites.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++) {
|
||||
|
@ -277,7 +259,7 @@ static void M_UploadSpriteAnimatedUVWs(const M_ANIMATION_RANGES *const source)
|
|||
glBufferSubData, GL_TEXTURE_BUFFER,
|
||||
range->index * sizeof(M_UVW_PACK),
|
||||
range->count * sizeof(M_UVW_PACK),
|
||||
m_LevelData.sprites.uvw + range->index);
|
||||
m_Priv.sprites.uvw + range->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,20 +283,31 @@ static void M_PrepareTextureData(M_TEXTURE_DATA *const data, const size_t count)
|
|||
|
||||
static void M_PrepareObjectUVWs(void)
|
||||
{
|
||||
M_PrepareTextureData(&m_LevelData.objects, Output_GetObjectTextureCount());
|
||||
M_PrepareTextureData(&m_Priv.objects, Output_GetObjectTextureCount());
|
||||
M_FillObjectUVWs();
|
||||
}
|
||||
|
||||
static void M_PrepareSpriteUVWs(void)
|
||||
{
|
||||
M_PrepareTextureData(&m_LevelData.sprites, Output_GetSpriteTextureCount());
|
||||
M_PrepareTextureData(&m_Priv.sprites, Output_GetSpriteTextureCount());
|
||||
M_FillSpriteUVWs();
|
||||
}
|
||||
|
||||
static void M_PrepareEnvMap(void)
|
||||
{
|
||||
glGenTextures(1, &m_Priv.tex_env_map);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Priv.tex_env_map);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
static void M_UploadAtlas(void)
|
||||
{
|
||||
glGenTextures(1, &m_LevelData.tex);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_LevelData.tex);
|
||||
glGenTextures(1, &m_Priv.tex_atlas);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_Priv.tex_atlas);
|
||||
glTexStorage3D(
|
||||
GL_TEXTURE_2D_ARRAY,
|
||||
1, // number of mipmaps
|
||||
|
@ -322,7 +315,6 @@ static void M_UploadAtlas(void)
|
|||
Output_GetTexturePageCount());
|
||||
GFX_GL_CheckError();
|
||||
|
||||
// TODO: handle bilinear toggle
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
@ -345,9 +337,37 @@ static void M_UploadAtlas(void)
|
|||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
static void M_FreeLevelData(void)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||
M_FreeTextureData(&m_Priv.objects);
|
||||
M_FreeTextureData(&m_Priv.sprites);
|
||||
if (m_Priv.tex_atlas != 0) {
|
||||
glDeleteTextures(1, &m_Priv.tex_atlas);
|
||||
m_Priv.tex_atlas = 0;
|
||||
}
|
||||
Memory_FreePointer(&m_AnimationRanges.objects.ranges);
|
||||
Memory_FreePointer(&m_AnimationRanges.sprites.ranges);
|
||||
}
|
||||
|
||||
void Output_Textures_Init(void)
|
||||
{
|
||||
M_PrepareEnvMap();
|
||||
}
|
||||
|
||||
void Output_Textures_Shutdown(void)
|
||||
{
|
||||
M_FreeLevelData();
|
||||
if (m_Priv.tex_env_map != 0) {
|
||||
glDeleteTextures(1, &m_Priv.tex_env_map);
|
||||
m_Priv.tex_env_map = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Output_Textures_ObserveLevelLoad(void)
|
||||
{
|
||||
Output_Textures_Shutdown();
|
||||
M_FreeLevelData();
|
||||
M_PrepareAnimationRanges();
|
||||
M_PrepareObjectUVWs();
|
||||
M_PrepareSpriteUVWs();
|
||||
|
@ -356,35 +376,62 @@ void Output_Textures_ObserveLevelLoad(void)
|
|||
M_UploadAtlas();
|
||||
}
|
||||
|
||||
void Output_Textures_Update(void)
|
||||
void Output_Textures_UpdateEnvironmentMap(void)
|
||||
{
|
||||
if (m_LevelData.sprites.tex != 0) {
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
GFX_GL_CheckError();
|
||||
|
||||
const GLint vp_x = viewport[0];
|
||||
const GLint vp_y = viewport[1];
|
||||
const GLint vp_w = viewport[2];
|
||||
const GLint vp_h = viewport[3];
|
||||
|
||||
const int32_t side = MIN(vp_w, vp_h);
|
||||
const int32_t x = vp_x + (vp_w - side) / 2;
|
||||
const int32_t y = vp_y + (vp_h - side) / 2;
|
||||
const int32_t w = side;
|
||||
const int32_t h = side;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_Priv.tex_env_map);
|
||||
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, w, h, 0);
|
||||
GFX_GL_CheckError();
|
||||
}
|
||||
|
||||
void Output_Textures_CycleAnimations(void)
|
||||
{
|
||||
if (m_Priv.sprites.tex != 0) {
|
||||
M_UploadSpriteAnimatedUVWs(&m_AnimationRanges.sprites);
|
||||
}
|
||||
if (m_LevelData.objects.tex != 0) {
|
||||
if (m_Priv.objects.tex != 0) {
|
||||
M_UploadObjectAnimatedUVWs(&m_AnimationRanges.objects);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetObjectUVWsTexture(void)
|
||||
{
|
||||
return m_LevelData.objects.tex;
|
||||
return m_Priv.objects.tex;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetSpriteUVWsTexture(void)
|
||||
{
|
||||
return m_LevelData.sprites.tex;
|
||||
return m_Priv.sprites.tex;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetAtlasTexture(void)
|
||||
{
|
||||
return m_LevelData.tex;
|
||||
return m_Priv.tex_atlas;
|
||||
}
|
||||
|
||||
GLuint Output_Textures_GetEnvMapTexture(void)
|
||||
{
|
||||
return m_Priv.tex_env_map;
|
||||
}
|
||||
|
||||
void Output_Textures_ApplyRenderSettings(void)
|
||||
{
|
||||
// re-adjust UVs when the bilinear filter is toggled.
|
||||
if (m_LevelData.objects.tex != 0) {
|
||||
if (m_Priv.objects.tex != 0) {
|
||||
M_FillObjectUVWs();
|
||||
M_UploadObjectUVWs();
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
void Output_Textures_Init(void);
|
||||
void Output_Textures_Shutdown(void);
|
||||
void Output_Textures_ObserveLevelLoad(void);
|
||||
void Output_Textures_Update(void);
|
||||
void Output_Textures_UpdateEnvironmentMap(void);
|
||||
void Output_Textures_CycleAnimations(void);
|
||||
void Output_Textures_ApplyRenderSettings(void);
|
||||
GLuint Output_Textures_GetObjectUVWsTexture(void);
|
||||
GLuint Output_Textures_GetSpriteUVWsTexture(void);
|
||||
GLuint Output_Textures_GetAtlasTexture(void);
|
||||
GLuint Output_Textures_GetEnvMapTexture(void);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "game/inventory.h"
|
||||
#include "game/items.h"
|
||||
#include "game/output.h"
|
||||
#include "game/output/meshes.h"
|
||||
#include "game/output/shader.h"
|
||||
#include "game/screen.h"
|
||||
#include "game/text.h"
|
||||
#include "game/viewport.h"
|
||||
|
@ -376,6 +378,7 @@ static void M_DrawPickup3D(DISPLAY_PICKUP *pu)
|
|||
int16_t old_fov = Viewport_GetFOV();
|
||||
Viewport_SetFOV(PICKUPS_FOV * DEG_1);
|
||||
Viewport_Init(vp_x1, vp_y1, vp_x2 - vp_x1, vp_y2 - vp_y1);
|
||||
glViewport(vp_x1, -vp_y1, screen_width, screen_height);
|
||||
Output_ApplyFOV();
|
||||
|
||||
Matrix_PushUnit();
|
||||
|
@ -422,6 +425,7 @@ static void M_DrawPickup3D(DISPLAY_PICKUP *pu)
|
|||
Matrix_Pop();
|
||||
Viewport_Init(0, 0, Screen_GetResWidth(), Screen_GetResHeight());
|
||||
Viewport_SetFOV(old_fov);
|
||||
glViewport(0, 0, Screen_GetResWidth(), Screen_GetResHeight());
|
||||
}
|
||||
|
||||
static void M_DrawPickups3D(void)
|
||||
|
|
|
@ -280,15 +280,7 @@ void Room_DrawSingleRoom(int16_t room_num)
|
|||
g_PhdTop = room->bound_top;
|
||||
g_PhdBottom = room->bound_bottom;
|
||||
|
||||
Output_LightRoom(room);
|
||||
Output_EnableScissor(
|
||||
room->bound_left, room->bound_bottom,
|
||||
room->bound_right - room->bound_left,
|
||||
room->bound_bottom - room->bound_top);
|
||||
Output_RememberState();
|
||||
Output_DrawRoomMesh(room);
|
||||
Output_RestoreState();
|
||||
Output_DisableScissor();
|
||||
|
||||
int16_t item_num = room->item_num;
|
||||
while (item_num != NO_ITEM) {
|
||||
|
|
|
@ -245,6 +245,7 @@ sources = [
|
|||
'game/option/option_sound.c',
|
||||
'game/output.c',
|
||||
'game/output/meshes.c',
|
||||
'game/output/objects.c',
|
||||
'game/output/rooms.c',
|
||||
'game/output/shader.c',
|
||||
'game/output/sprites.c',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "specific/s_output.h"
|
||||
|
||||
#include "game/output.h"
|
||||
#include "game/output/textures.h"
|
||||
#include "game/screen.h"
|
||||
#include "game/shell.h"
|
||||
#include "game/viewport.h"
|
||||
|
@ -29,7 +30,6 @@
|
|||
}
|
||||
|
||||
static int m_TextureMap[GFX_MAX_TEXTURES] = { GFX_NO_TEXTURE };
|
||||
static int m_EnvMapTexture = GFX_NO_TEXTURE;
|
||||
|
||||
static GFX_2D_RENDERER *m_Renderer2D = nullptr;
|
||||
static GFX_3D_RENDERER *m_Renderer3D = nullptr;
|
||||
|
@ -38,19 +38,16 @@ static int32_t m_SelectedTexture = -1;
|
|||
|
||||
static int32_t m_SurfaceWidth = 0;
|
||||
static int32_t m_SurfaceHeight = 0;
|
||||
static float m_SurfaceMinX = 0.0f;
|
||||
static float m_SurfaceMinY = 0.0f;
|
||||
static float m_SurfaceMaxX = 0.0f;
|
||||
static float m_SurfaceMaxY = 0.0f;
|
||||
static GFX_2D_SURFACE *m_PrimarySurface = nullptr;
|
||||
static GFX_2D_SURFACE *m_PictureSurface = nullptr;
|
||||
static GFX_2D_SURFACE *m_TextureSurfaces[GFX_MAX_TEXTURES] = { nullptr };
|
||||
|
||||
static inline float M_GetUV(uint16_t uv);
|
||||
static void M_SelectTexture(int32_t texture_num);
|
||||
static void M_EnableTextureMode(void);
|
||||
static void M_DrawBackdropSurface(void);
|
||||
static void M_ReleaseTextures(void);
|
||||
static void M_ReleaseSurfaces(void);
|
||||
static void M_FlipPrimaryBuffer(void);
|
||||
static void M_ClearSurface(GFX_2D_SURFACE *surface);
|
||||
static void M_DrawTriangleFan(GFX_3D_VERTEX *vertices, int vertex_count);
|
||||
static void M_DrawTriangleStrip(GFX_3D_VERTEX *vertices, int vertex_count);
|
||||
static int32_t M_VisibleZClip(
|
||||
|
@ -66,6 +63,40 @@ static inline float M_GetUV(const uint16_t uv)
|
|||
: ((uv & 0xFF00) + 127) / 65536.0f;
|
||||
}
|
||||
|
||||
static void M_SelectTexture(const int32_t texture_num)
|
||||
{
|
||||
if (texture_num == m_SelectedTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TextureMap[texture_num] == GFX_NO_TEXTURE) {
|
||||
LOG_ERROR("ERROR: Attempt to select unloaded texture");
|
||||
return;
|
||||
}
|
||||
|
||||
GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_TextureMap[texture_num]);
|
||||
|
||||
m_SelectedTexture = texture_num;
|
||||
}
|
||||
|
||||
static void M_EnableTextureMode(void)
|
||||
{
|
||||
if (m_IsTextureMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsTextureMode = true;
|
||||
GFX_3D_Renderer_SetTexturingEnabled(m_Renderer3D, m_IsTextureMode);
|
||||
}
|
||||
|
||||
static void M_DrawBackdropSurface(void)
|
||||
{
|
||||
if (m_PictureSurface == nullptr) {
|
||||
return;
|
||||
}
|
||||
GFX_2D_Renderer_Render(m_Renderer2D);
|
||||
}
|
||||
|
||||
static void M_ReleaseTextures(void)
|
||||
{
|
||||
if (m_Renderer3D == nullptr) {
|
||||
|
@ -78,20 +109,10 @@ static void M_ReleaseTextures(void)
|
|||
m_TextureMap[i] = GFX_NO_TEXTURE;
|
||||
}
|
||||
}
|
||||
if (m_EnvMapTexture != GFX_NO_TEXTURE) {
|
||||
GFX_3D_Renderer_UnregisterEnvironmentMap(m_Renderer3D, m_EnvMapTexture);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_ReleaseSurfaces(void)
|
||||
{
|
||||
if (m_PrimarySurface) {
|
||||
M_ClearSurface(m_PrimarySurface);
|
||||
|
||||
GFX_2D_Surface_Free(m_PrimarySurface);
|
||||
m_PrimarySurface = nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < GFX_MAX_TEXTURES; i++) {
|
||||
if (m_TextureSurfaces[i] != nullptr) {
|
||||
GFX_2D_Surface_Free(m_TextureSurfaces[i]);
|
||||
|
@ -105,21 +126,11 @@ static void M_ReleaseSurfaces(void)
|
|||
}
|
||||
}
|
||||
|
||||
void Output_FillEnvironmentMap(void)
|
||||
{
|
||||
GFX_3D_Renderer_FillEnvironmentMap(m_Renderer3D);
|
||||
}
|
||||
|
||||
static void M_FlipPrimaryBuffer(void)
|
||||
{
|
||||
GFX_Context_SwapBuffers();
|
||||
}
|
||||
|
||||
static void M_ClearSurface(GFX_2D_SURFACE *surface)
|
||||
{
|
||||
GFX_2D_Surface_Clear(surface, 0);
|
||||
}
|
||||
|
||||
static void M_DrawTriangleFan(GFX_3D_VERTEX *vertices, int vertex_count)
|
||||
{
|
||||
GFX_3D_Renderer_RenderPrimFan(m_Renderer3D, vertices, vertex_count);
|
||||
|
@ -217,16 +228,6 @@ static int32_t M_ZedClipper(
|
|||
return count < 3 ? 0 : count;
|
||||
}
|
||||
|
||||
void S_Output_EnableTextureMode(void)
|
||||
{
|
||||
if (m_IsTextureMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsTextureMode = true;
|
||||
GFX_3D_Renderer_SetTexturingEnabled(m_Renderer3D, m_IsTextureMode);
|
||||
}
|
||||
|
||||
void S_Output_DisableTextureMode(void)
|
||||
{
|
||||
if (!m_IsTextureMode) {
|
||||
|
@ -266,7 +267,7 @@ void S_Output_RenderBegin(void)
|
|||
{
|
||||
GFX_Context_Clear();
|
||||
GFX_Track_Reset();
|
||||
S_Output_DrawBackdropSurface();
|
||||
M_DrawBackdropSurface();
|
||||
GFX_3D_Renderer_RenderBegin(m_Renderer3D);
|
||||
GFX_3D_Renderer_SetTextureFilter(
|
||||
m_Renderer3D, g_Config.rendering.texture_filter);
|
||||
|
@ -294,14 +295,6 @@ void S_Output_ClearDepthBuffer(void)
|
|||
GFX_3D_Renderer_ClearDepth(m_Renderer3D);
|
||||
}
|
||||
|
||||
void S_Output_DrawBackdropSurface(void)
|
||||
{
|
||||
if (m_PictureSurface == nullptr) {
|
||||
return;
|
||||
}
|
||||
GFX_2D_Renderer_Render(m_Renderer2D);
|
||||
}
|
||||
|
||||
void S_Output_DownloadBackdropSurface(const IMAGE *const image)
|
||||
{
|
||||
GFX_2D_Surface_Free(m_PictureSurface);
|
||||
|
@ -316,22 +309,6 @@ void S_Output_DownloadBackdropSurface(const IMAGE *const image)
|
|||
m_Renderer2D, &m_PictureSurface->desc, m_PictureSurface->buffer);
|
||||
}
|
||||
|
||||
void S_Output_SelectTexture(const int32_t texture_num)
|
||||
{
|
||||
if (texture_num == m_SelectedTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TextureMap[texture_num] == GFX_NO_TEXTURE) {
|
||||
LOG_ERROR("ERROR: Attempt to select unloaded texture");
|
||||
return;
|
||||
}
|
||||
|
||||
GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_TextureMap[texture_num]);
|
||||
|
||||
m_SelectedTexture = texture_num;
|
||||
}
|
||||
|
||||
void S_Output_DrawSprite(
|
||||
int16_t x1, int16_t y1, int16_t x2, int y2, int z, int sprnum, int shade)
|
||||
{
|
||||
|
@ -406,8 +383,8 @@ void S_Output_DrawSprite(
|
|||
}
|
||||
|
||||
if (m_TextureMap[sprite->tex_page] != GFX_NO_TEXTURE) {
|
||||
S_Output_EnableTextureMode();
|
||||
S_Output_SelectTexture(sprite->tex_page);
|
||||
M_EnableTextureMode();
|
||||
M_SelectTexture(sprite->tex_page);
|
||||
M_DrawTriangleFan(vertices, vertex_count);
|
||||
} else {
|
||||
S_Output_DisableTextureMode();
|
||||
|
@ -627,10 +604,6 @@ void S_Output_ApplyRenderSettings(void)
|
|||
|
||||
m_SurfaceWidth = Screen_GetResWidth();
|
||||
m_SurfaceHeight = Screen_GetResHeight();
|
||||
m_SurfaceMinX = 0.0f;
|
||||
m_SurfaceMinY = 0.0f;
|
||||
m_SurfaceMaxX = Screen_GetResWidth() - 1.0f;
|
||||
m_SurfaceMaxY = Screen_GetResHeight() - 1.0f;
|
||||
|
||||
GFX_Context_SetVSync(g_Config.rendering.enable_vsync);
|
||||
GFX_Context_SetDisplayFilter(g_Config.rendering.fbo_filter);
|
||||
|
@ -640,12 +613,6 @@ void S_Output_ApplyRenderSettings(void)
|
|||
GFX_Context_SetLineWidth(g_Config.rendering.wireframe_width);
|
||||
GFX_3D_Renderer_SetAnisotropyFilter(
|
||||
m_Renderer3D, g_Config.rendering.anisotropy_filter);
|
||||
|
||||
if (m_PrimarySurface == nullptr) {
|
||||
GFX_2D_SURFACE_DESC surface_desc = {};
|
||||
m_PrimarySurface = GFX_2D_Surface_Create(&surface_desc);
|
||||
}
|
||||
M_ClearSurface(m_PrimarySurface);
|
||||
}
|
||||
|
||||
void S_Output_SetWindowSize(int width, int height)
|
||||
|
@ -745,252 +712,6 @@ void S_Output_DrawFlatTriangle(
|
|||
M_DrawTriangleFan(vertices, vertex_count);
|
||||
}
|
||||
|
||||
void S_Output_DrawEnvMapTriangle(
|
||||
const PHD_VBUF *const vn1, const PHD_VBUF *const vn2,
|
||||
const PHD_VBUF *const vn3)
|
||||
{
|
||||
int vertex_count = 3;
|
||||
GFX_3D_VERTEX vertices[vertex_count * CLIP_VERTCOUNT_SCALE];
|
||||
|
||||
const float multiplier = g_Config.visuals.brightness / 16.0f;
|
||||
const PHD_VBUF *const src_vbuf[3] = { vn1, vn2, vn3 };
|
||||
|
||||
if (vn3->clip & vn2->clip & vn1->clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vn1->clip >= 0 && vn2->clip >= 0 && vn3->clip >= 0) {
|
||||
if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < vertex_count; i++) {
|
||||
vertices[i].x = src_vbuf[i]->xs;
|
||||
vertices[i].y = src_vbuf[i]->ys;
|
||||
vertices[i].z = MAP_DEPTH(src_vbuf[i]->zv);
|
||||
|
||||
vertices[i].w = 1.0f / src_vbuf[i]->zv;
|
||||
vertices[i].s = M_GetUV(src_vbuf[i]->u);
|
||||
vertices[i].t = M_GetUV(src_vbuf[i]->v);
|
||||
vertices[i].tex_coord[2] = src_vbuf[i]->tex_coord[2];
|
||||
vertices[i].tex_coord[3] = src_vbuf[i]->tex_coord[3];
|
||||
|
||||
vertices[i].r = vertices[i].g = vertices[i].b =
|
||||
(8192.0f - src_vbuf[i]->g) * multiplier;
|
||||
|
||||
Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b);
|
||||
}
|
||||
} else {
|
||||
if (!M_VisibleZClip(vn1, vn2, vn3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_count =
|
||||
M_ZedClipper(vertex_count, (const PHD_VBUF **)src_vbuf, vertices);
|
||||
if (vertex_count == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vertex_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_Output_EnableTextureMode();
|
||||
GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_EnvMapTexture);
|
||||
GFX_3D_Renderer_SetBlendingMode(m_Renderer3D, GFX_BLEND_MODE_MULTIPLY);
|
||||
M_DrawTriangleFan(vertices, vertex_count);
|
||||
GFX_3D_Renderer_SetBlendingMode(m_Renderer3D, GFX_BLEND_MODE_OFF);
|
||||
m_SelectedTexture = -1;
|
||||
}
|
||||
|
||||
void S_Output_DrawEnvMapQuad(
|
||||
const PHD_VBUF *const vn1, const PHD_VBUF *const vn2,
|
||||
const PHD_VBUF *const vn3, const PHD_VBUF *const vn4)
|
||||
{
|
||||
int vertex_count = 4;
|
||||
GFX_3D_VERTEX vertices[vertex_count];
|
||||
|
||||
if (vn4->clip | vn3->clip | vn2->clip | vn1->clip) {
|
||||
if ((vn4->clip & vn3->clip & vn2->clip & vn1->clip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vn1->clip >= 0 && vn2->clip >= 0 && vn3->clip >= 0
|
||||
&& vn4->clip >= 0) {
|
||||
if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) {
|
||||
return;
|
||||
}
|
||||
} else if (!M_VisibleZClip(vn1, vn2, vn3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_Output_DrawEnvMapTriangle(vn1, vn2, vn3);
|
||||
S_Output_DrawEnvMapTriangle(vn3, vn4, vn1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float multiplier = g_Config.visuals.brightness / 16.0f;
|
||||
|
||||
const PHD_VBUF *const src_vbuf[4] = { vn2, vn1, vn3, vn4 };
|
||||
|
||||
for (int32_t i = 0; i < vertex_count; i++) {
|
||||
vertices[i].x = src_vbuf[i]->xs;
|
||||
vertices[i].y = src_vbuf[i]->ys;
|
||||
vertices[i].z = MAP_DEPTH(src_vbuf[i]->zv);
|
||||
|
||||
vertices[i].w = 1.0f / src_vbuf[i]->zv;
|
||||
vertices[i].s = M_GetUV(src_vbuf[i]->u);
|
||||
vertices[i].t = M_GetUV(src_vbuf[i]->v);
|
||||
vertices[i].tex_coord[2] = src_vbuf[i]->tex_coord[2];
|
||||
vertices[i].tex_coord[3] = src_vbuf[i]->tex_coord[3];
|
||||
|
||||
vertices[i].r = vertices[i].g = vertices[i].b =
|
||||
(8192.0f - src_vbuf[i]->g) * multiplier;
|
||||
|
||||
Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b);
|
||||
}
|
||||
|
||||
S_Output_EnableTextureMode();
|
||||
GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_EnvMapTexture);
|
||||
GFX_3D_Renderer_SetBlendingMode(m_Renderer3D, GFX_BLEND_MODE_MULTIPLY);
|
||||
GFX_3D_Renderer_RenderPrimStrip(m_Renderer3D, vertices, vertex_count);
|
||||
GFX_3D_Renderer_SetBlendingMode(m_Renderer3D, GFX_BLEND_MODE_OFF);
|
||||
m_SelectedTexture = -1;
|
||||
}
|
||||
|
||||
void S_Output_DrawTexturedTriangle(
|
||||
PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, int16_t tpage,
|
||||
uint16_t textype)
|
||||
{
|
||||
int vertex_count = 3;
|
||||
GFX_3D_VERTEX vertices[vertex_count * CLIP_VERTCOUNT_SCALE];
|
||||
PHD_VBUF *src_vbuf[3];
|
||||
|
||||
float multiplier = g_Config.visuals.brightness / 16.0f;
|
||||
|
||||
src_vbuf[0] = vn1;
|
||||
src_vbuf[1] = vn2;
|
||||
src_vbuf[2] = vn3;
|
||||
|
||||
if (vn3->clip & vn2->clip & vn1->clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_vbuf[0]->clip >= 0 && src_vbuf[1]->clip >= 0
|
||||
&& src_vbuf[2]->clip >= 0) {
|
||||
if (!VBUF_VISIBLE(*src_vbuf[0], *src_vbuf[1], *src_vbuf[2])) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < vertex_count; i++) {
|
||||
vertices[i].x = src_vbuf[i]->xs;
|
||||
vertices[i].y = src_vbuf[i]->ys;
|
||||
vertices[i].z = MAP_DEPTH(src_vbuf[i]->zv);
|
||||
|
||||
vertices[i].w = 1.0f / src_vbuf[i]->zv;
|
||||
vertices[i].s = M_GetUV(src_vbuf[i]->u);
|
||||
vertices[i].t = M_GetUV(src_vbuf[i]->v);
|
||||
vertices[i].tex_coord[2] = src_vbuf[i]->tex_coord[2];
|
||||
vertices[i].tex_coord[3] = src_vbuf[i]->tex_coord[3];
|
||||
|
||||
vertices[i].r = vertices[i].g = vertices[i].b =
|
||||
(8192.0f - src_vbuf[i]->g) * multiplier;
|
||||
|
||||
Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b);
|
||||
}
|
||||
} else {
|
||||
if (!M_VisibleZClip(src_vbuf[0], src_vbuf[1], src_vbuf[2])) {
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_count =
|
||||
M_ZedClipper(vertex_count, (const PHD_VBUF **)src_vbuf, vertices);
|
||||
if (vertex_count == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vertex_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TextureMap[tpage] != GFX_NO_TEXTURE) {
|
||||
S_Output_EnableTextureMode();
|
||||
S_Output_SelectTexture(tpage);
|
||||
M_DrawTriangleFan(vertices, vertex_count);
|
||||
} else {
|
||||
S_Output_DisableTextureMode();
|
||||
M_DrawTriangleFan(vertices, vertex_count);
|
||||
}
|
||||
}
|
||||
|
||||
void S_Output_DrawTexturedQuad(
|
||||
PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, int16_t tpage,
|
||||
uint16_t textype)
|
||||
{
|
||||
int vertex_count = 4;
|
||||
GFX_3D_VERTEX vertices[vertex_count];
|
||||
PHD_VBUF *src_vbuf[4] = { vn1, vn2, vn3, vn4 };
|
||||
|
||||
if (src_vbuf[3]->clip | src_vbuf[2]->clip | src_vbuf[1]->clip
|
||||
| src_vbuf[0]->clip) {
|
||||
if ((src_vbuf[3]->clip & src_vbuf[2]->clip & src_vbuf[1]->clip
|
||||
& src_vbuf[0]->clip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_vbuf[0]->clip >= 0 && src_vbuf[1]->clip >= 0
|
||||
&& src_vbuf[2]->clip >= 0 && src_vbuf[3]->clip >= 0) {
|
||||
if (!VBUF_VISIBLE(*src_vbuf[0], *src_vbuf[1], *src_vbuf[2])) {
|
||||
return;
|
||||
}
|
||||
} else if (!M_VisibleZClip(src_vbuf[0], src_vbuf[1], src_vbuf[2])) {
|
||||
return;
|
||||
}
|
||||
|
||||
S_Output_DrawTexturedTriangle(vn1, vn2, vn3, tpage, textype);
|
||||
S_Output_DrawTexturedTriangle(vn3, vn4, vn1, tpage, textype);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VBUF_VISIBLE(*src_vbuf[0], *src_vbuf[1], *src_vbuf[2])) {
|
||||
return;
|
||||
}
|
||||
|
||||
float multiplier = g_Config.visuals.brightness / 16.0f;
|
||||
|
||||
for (int32_t i = 0; i < vertex_count; i++) {
|
||||
vertices[i].x = src_vbuf[i]->xs;
|
||||
vertices[i].y = src_vbuf[i]->ys;
|
||||
vertices[i].z = MAP_DEPTH(src_vbuf[i]->zv);
|
||||
|
||||
vertices[i].w = 1.0f / src_vbuf[i]->zv;
|
||||
vertices[i].s = M_GetUV(src_vbuf[i]->u);
|
||||
vertices[i].t = M_GetUV(src_vbuf[i]->v);
|
||||
vertices[i].tex_coord[2] = src_vbuf[i]->tex_coord[2];
|
||||
vertices[i].tex_coord[3] = src_vbuf[i]->tex_coord[3];
|
||||
|
||||
vertices[i].r = vertices[i].g = vertices[i].b =
|
||||
(8192.0f - src_vbuf[i]->g) * multiplier;
|
||||
|
||||
Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b);
|
||||
}
|
||||
|
||||
if (m_TextureMap[tpage] != GFX_NO_TEXTURE) {
|
||||
S_Output_EnableTextureMode();
|
||||
S_Output_SelectTexture(tpage);
|
||||
} else {
|
||||
S_Output_DisableTextureMode();
|
||||
}
|
||||
|
||||
GFX_3D_Renderer_RenderPrimFan(m_Renderer3D, vertices, vertex_count);
|
||||
}
|
||||
|
||||
void S_Output_DownloadTextures(int32_t pages)
|
||||
{
|
||||
if (pages > GFX_MAX_TEXTURES) {
|
||||
|
@ -1020,8 +741,6 @@ void S_Output_DownloadTextures(int32_t pages)
|
|||
}
|
||||
|
||||
m_SelectedTexture = -1;
|
||||
|
||||
m_EnvMapTexture = GFX_3D_Renderer_RegisterEnvironmentMap(m_Renderer3D);
|
||||
}
|
||||
|
||||
void S_Output_DrawScreenFrame(
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
bool S_Output_Init(void);
|
||||
void S_Output_Shutdown(void);
|
||||
|
||||
void S_Output_EnableTextureMode(void);
|
||||
void S_Output_DisableTextureMode(void);
|
||||
void S_Output_SetBlendingMode(GFX_BLEND_MODE blend_mode);
|
||||
void S_Output_EnableDepthWrites(void);
|
||||
|
@ -28,23 +27,10 @@ void S_Output_SetWindowSize(int width, int height);
|
|||
void S_Output_ApplyRenderSettings(void);
|
||||
|
||||
void S_Output_DownloadTextures(int32_t pages);
|
||||
void S_Output_SelectTexture(int32_t texture_num);
|
||||
void S_Output_DownloadBackdropSurface(const IMAGE *image);
|
||||
void S_Output_DrawBackdropSurface(void);
|
||||
|
||||
void S_Output_DrawFlatTriangle(
|
||||
PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, RGBA_8888 color);
|
||||
void S_Output_DrawEnvMapTriangle(
|
||||
const PHD_VBUF *vn1, const PHD_VBUF *vn2, const PHD_VBUF *vn3);
|
||||
void S_Output_DrawEnvMapQuad(
|
||||
const PHD_VBUF *vn1, const PHD_VBUF *vn2, const PHD_VBUF *vn3,
|
||||
const PHD_VBUF *vn4);
|
||||
void S_Output_DrawTexturedTriangle(
|
||||
PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, int16_t tpage,
|
||||
uint16_t textype);
|
||||
void S_Output_DrawTexturedQuad(
|
||||
PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, int16_t tpage,
|
||||
uint16_t textype);
|
||||
void S_Output_Draw3DLine(
|
||||
const PHD_VBUF *vn1, const PHD_VBUF *vn2, const RGBA_8888 color);
|
||||
void S_Output_DrawSprite(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue