From 1cb8ae9255a4c8ad7cb5b557abf13392d82df8fe Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Tue, 10 Sep 2024 00:55:33 +0200 Subject: [PATCH] output: add reflections Resolves #154. --- CHANGELOG.md | 1 + README.md | 1 + data/ship/cfg/TR1X_gameflow.json5 | 1 + data/ship/cfg/TR1X_gameflow_demo_pc.json5 | 1 + data/ship/cfg/TR1X_gameflow_ub.json5 | 1 + src/config.h | 1 + src/config_map.def | 1 + src/game/collide.c | 5 +- src/game/game/game_draw.c | 16 +++ src/game/game_string.def | 1 + src/game/lara/lara_hair.c | 20 +-- src/game/lara/lara_state.c | 4 + src/game/objects/common.c | 62 ++++++++ src/game/objects/common.h | 3 + src/game/objects/general/save_crystal.c | 1 + src/game/option/option_graphics.c | 28 +++- src/game/output.c | 168 +++++++++++++++++++--- src/game/output.h | 13 +- src/game/room_draw.c | 9 -- src/gfx/3d/3d_renderer.c | 74 +++++++++- src/gfx/3d/3d_renderer.h | 12 +- src/gfx/gl/texture.c | 36 ++++- src/gfx/gl/texture.h | 1 + src/specific/s_output.c | 53 ++++--- src/specific/s_output.h | 6 +- 25 files changed, 440 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0d95385..685791885 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [Unreleased](https://github.com/LostArtefacts/TR1X/compare/stable...develop) - ××××-××-×× - added `/exit` command (#1462) +- added reflections to Midas Hand death animation and savegame crystals (#154) - fixed `/play`, `/load`, `/demo` and similar commands not working in stats, credits, cinematics and fmvs (#1477) - fixed console commands being able to interfere with demos, cutscenes and the title screen (#1489, regression from 3.0) - fixed reopening the compass not resetting its needle (#1472, regression from 4.0) diff --git a/README.md b/README.md index ee25a9e56..f38ca6f47 100644 --- a/README.md +++ b/README.md @@ -571,6 +571,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det - added contextual arrows to menu options - added support for animated room sprites, which also restores intended behavior in, for example, The Cistern room 0 - added skybox support, with a default option provided for Lost Valley, Colosseum and Obelisk of Khamoon; custom level builders can use object slot `184` +- added reflections of Midas Hand death animation and savegame crystals - changed the Scion in The Great Pyramid from spawning blood when hit to a richochet effect - fixed thin black lines between polygons - fixed black screen flashing when navigating the inventory diff --git a/data/ship/cfg/TR1X_gameflow.json5 b/data/ship/cfg/TR1X_gameflow.json5 index 1a586c615..90cadeca2 100644 --- a/data/ship/cfg/TR1X_gameflow.json5 +++ b/data/ship/cfg/TR1X_gameflow.json5 @@ -611,6 +611,7 @@ "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", "DETAIL_PRETTY_PIXELS": "Pretty pixels", + "DETAIL_REFLECTIONS": "Reflections", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/data/ship/cfg/TR1X_gameflow_demo_pc.json5 b/data/ship/cfg/TR1X_gameflow_demo_pc.json5 index dfa54506b..8bec7807f 100644 --- a/data/ship/cfg/TR1X_gameflow_demo_pc.json5 +++ b/data/ship/cfg/TR1X_gameflow_demo_pc.json5 @@ -107,6 +107,7 @@ "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", "DETAIL_PRETTY_PIXELS": "Pretty pixels", + "DETAIL_REFLECTIONS": "Reflections", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/data/ship/cfg/TR1X_gameflow_ub.json5 b/data/ship/cfg/TR1X_gameflow_ub.json5 index b95c77a84..a1ef7975a 100644 --- a/data/ship/cfg/TR1X_gameflow_ub.json5 +++ b/data/ship/cfg/TR1X_gameflow_ub.json5 @@ -179,6 +179,7 @@ "DETAIL_FPS": "FPS", "DETAIL_PERSPECTIVE": "Perspective", "DETAIL_PRETTY_PIXELS": "Pretty pixels", + "DETAIL_REFLECTIONS": "Reflections", "DETAIL_BILINEAR": "Bilinear", "DETAIL_TEXTURE_FILTER": "Texture filter", "DETAIL_FBO_FILTER": "FBO filter", diff --git a/src/config.h b/src/config.h index 9a98de138..6252b9261 100644 --- a/src/config.h +++ b/src/config.h @@ -118,6 +118,7 @@ typedef struct { float anisotropy_filter; int32_t turbo_speed; bool pretty_pixels; + bool enable_reflections; } rendering; struct { diff --git a/src/config_map.def b/src/config_map.def index a000b48a5..d14aca3e7 100644 --- a/src/config_map.def +++ b/src/config_map.def @@ -97,6 +97,7 @@ CFG_DOUBLE(g_Config, rendering.wireframe_width, 2.5) CFG_BOOL(g_Config, rendering.enable_perspective_filter, true) CFG_BOOL(g_Config, rendering.enable_vsync, true) CFG_BOOL(g_Config, rendering.pretty_pixels, true) +CFG_BOOL(g_Config, rendering.enable_reflections, true) CFG_INT32(g_Config, music_volume, 8) CFG_INT32(g_Config, sound_volume, 8) CFG_INT32(g_Config, input.layout, 0) diff --git a/src/game/collide.c b/src/game/collide.c index b0bb34dcc..e637483b3 100644 --- a/src/game/collide.c +++ b/src/game/collide.c @@ -2,6 +2,7 @@ #include "config.h" #include "game/items.h" +#include "game/output.h" #include "game/room.h" #include "global/const.h" #include "global/types.h" @@ -514,7 +515,7 @@ int32_t Collide_GetSpheres(ITEM_INFO *item, SPHERE *ptr, int32_t world_space) ptr->x = x + (g_MatrixPtr->_03 >> W2V_SHIFT); ptr->y = y + (g_MatrixPtr->_13 >> W2V_SHIFT); ptr->z = z + (g_MatrixPtr->_23 >> W2V_SHIFT); - ptr->r = objptr[3]; + ptr->r = DISABLE_REFLECTION_BIT(objptr[3]); ptr++; Matrix_Pop(); @@ -547,7 +548,7 @@ int32_t Collide_GetSpheres(ITEM_INFO *item, SPHERE *ptr, int32_t world_space) ptr->x = x + (g_MatrixPtr->_03 >> W2V_SHIFT); ptr->y = y + (g_MatrixPtr->_13 >> W2V_SHIFT); ptr->z = z + (g_MatrixPtr->_23 >> W2V_SHIFT); - ptr->r = objptr[3]; + ptr->r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop(); ptr++; diff --git a/src/game/game/game_draw.c b/src/game/game/game_draw.c index e9a072c3c..bb7645382 100644 --- a/src/game/game/game_draw.c +++ b/src/game/game/game_draw.c @@ -1,7 +1,9 @@ #include "game/game.h" +#include "config.h" #include "game/camera.h" #include "game/interpolation.h" +#include "game/lara/lara_draw.h" #include "game/lara/lara_hair.h" #include "game/output.h" #include "game/overlay.h" @@ -20,11 +22,25 @@ void Game_DrawScene(bool draw_overlay) if (g_Objects[O_LARA].loaded) { Room_DrawAllRooms(g_Camera.interp.room_num, g_Camera.target.room_num); + + if (g_Config.rendering.enable_reflections) { + Output_FillEnvironmentMap(); + } + + if (g_RoomInfo[g_LaraItem->room_num].flags & RF_UNDERWATER) { + Output_SetupBelowWater(g_Camera.underwater); + } else { + Output_SetupAboveWater(g_Camera.underwater); + } + + Lara_Draw(g_LaraItem); + if (draw_overlay) { Overlay_DrawGameInfo(); } else { Overlay_HideGameInfo(); } + } else { // cinematic scene for (int i = 0; i < g_RoomsToDrawCount; i++) { diff --git a/src/game/game_string.def b/src/game/game_string.def index ba5b99762..007a1214a 100644 --- a/src/game/game_string.def +++ b/src/game/game_string.def @@ -24,6 +24,7 @@ GS_DEFINE(DETAIL_LEVEL_LOW, "Low") GS_DEFINE(DETAIL_FPS, "FPS") GS_DEFINE(DETAIL_PERSPECTIVE, "Perspective") GS_DEFINE(DETAIL_PRETTY_PIXELS, "Pretty pixels") +GS_DEFINE(DETAIL_REFLECTIONS, "Reflections") GS_DEFINE(DETAIL_BILINEAR, "Bilinear") GS_DEFINE(DETAIL_TEXTURE_FILTER, "Texture filter") GS_DEFINE(DETAIL_FBO_FILTER, "FBO filter") diff --git a/src/game/lara/lara_hair.c b/src/game/lara/lara_hair.c index baf0b74a4..231b7c4db 100644 --- a/src/game/lara/lara_hair.c +++ b/src/game/lara/lara_hair.c @@ -147,7 +147,7 @@ void Lara_Hair_Control(void) sphere[0].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[0].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[0].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[0].r = objptr[3]; + sphere[0].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop_I(); // torso @@ -165,7 +165,7 @@ void Lara_Hair_Control(void) sphere[1].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[1].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[1].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[1].r = objptr[3]; + sphere[1].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop_I(); // right arm @@ -180,7 +180,7 @@ void Lara_Hair_Control(void) sphere[3].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[3].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[3].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[3].r = (int32_t)objptr[3] * 3 / 2; + sphere[3].r = (int32_t)DISABLE_REFLECTION_BIT(objptr[3]) * 3 / 2; Matrix_Pop_I(); // left arm @@ -195,7 +195,7 @@ void Lara_Hair_Control(void) sphere[4].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[4].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[4].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[4].r = (int32_t)objptr[3] * 3 / 2; + sphere[4].r = (int32_t)DISABLE_REFLECTION_BIT(objptr[3]) * 3 / 2; Matrix_Pop_I(); // head @@ -213,7 +213,7 @@ void Lara_Hair_Control(void) sphere[2].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[2].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[2].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[2].r = objptr[3]; + sphere[2].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop_I(); Matrix_TranslateRel_I(HAIR_OFFSET_X, HAIR_OFFSET_Y, HAIR_OFFSET_Z); @@ -231,7 +231,7 @@ void Lara_Hair_Control(void) sphere[0].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[0].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[0].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[0].r = objptr[3]; + sphere[0].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop(); // torso @@ -247,7 +247,7 @@ void Lara_Hair_Control(void) sphere[1].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[1].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[1].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[1].r = objptr[3]; + sphere[1].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop(); // right arm @@ -260,7 +260,7 @@ void Lara_Hair_Control(void) sphere[3].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[3].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[3].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[3].r = (int32_t)objptr[3] * 3 / 2; + sphere[3].r = (int32_t)DISABLE_REFLECTION_BIT(objptr[3]) * 3 / 2; Matrix_Pop(); // left arm @@ -273,7 +273,7 @@ void Lara_Hair_Control(void) sphere[4].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[4].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[4].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[4].r = (int32_t)objptr[3] * 3 / 2; + sphere[4].r = (int32_t)DISABLE_REFLECTION_BIT(objptr[3]) * 3 / 2; Matrix_Pop(); // head @@ -289,7 +289,7 @@ void Lara_Hair_Control(void) sphere[2].x = g_MatrixPtr->_03 >> W2V_SHIFT; sphere[2].y = g_MatrixPtr->_13 >> W2V_SHIFT; sphere[2].z = g_MatrixPtr->_23 >> W2V_SHIFT; - sphere[2].r = objptr[3]; + sphere[2].r = DISABLE_REFLECTION_BIT(objptr[3]); Matrix_Pop(); Matrix_TranslateRel(HAIR_OFFSET_X, HAIR_OFFSET_Y, HAIR_OFFSET_Z); diff --git a/src/game/lara/lara_state.c b/src/game/lara/lara_state.c index 2371197ee..acd925f72 100644 --- a/src/game/lara/lara_state.c +++ b/src/game/lara/lara_state.c @@ -5,6 +5,7 @@ #include "game/items.h" #include "game/lara.h" #include "game/lara/lara_look.h" +#include "game/objects/common.h" #include "game/objects/effects/twinkle.h" #include "game/room.h" #include "game/sound.h" @@ -678,6 +679,8 @@ void Lara_State_DieMidas(ITEM_INFO *item, COLL_INFO *coll) coll->enable_spaz = 0; coll->enable_baddie_push = 0; + Object_SetReflective(O_LARA_EXTRA, true); + int frm = item->frame_num - g_Anims[item->anim_num].frame_base; switch (frm) { case 5: @@ -745,6 +748,7 @@ void Lara_State_DieMidas(ITEM_INFO *item, COLL_INFO *coll) break; case 225: + Object_SetReflective(O_HAIR, true); g_Lara.mesh_effects |= (1 << LM_HEAD); Lara_SwapSingleMesh(LM_HEAD, O_LARA_EXTRA); break; diff --git a/src/game/objects/common.c b/src/game/objects/common.c index 40a0c6f22..476b67844 100644 --- a/src/game/objects/common.c +++ b/src/game/objects/common.c @@ -632,3 +632,65 @@ void Object_DrawUnclippedItem(ITEM_INFO *item) g_PhdRight = right; g_PhdBottom = bottom; } + +void Object_SetMeshReflective( + const GAME_OBJECT_ID object_id, const int32_t mesh_idx, const bool enabled) +{ + const OBJECT_INFO *const object = &g_Objects[object_id]; + if (!object->loaded) { + return; + } + int16_t *obj_ptr = g_Meshes[object->mesh_index + mesh_idx]; + + TOGGLE_REFLECTION_ENABLED(obj_ptr[3], enabled); + + obj_ptr += 5; + int32_t vertex_count = *obj_ptr++; + obj_ptr += vertex_count * 3; + vertex_count = *obj_ptr++; + if (vertex_count > 0) { + obj_ptr += vertex_count * 3; + } else { + obj_ptr += vertex_count; + } + + // textured quads + int32_t num = *obj_ptr++; + for (int32_t i = 0; i < num; i++) { + // skip vertices + obj_ptr += 4; + TOGGLE_REFLECTION_ENABLED(*obj_ptr++, enabled); + } + + // textured triangles + num = *obj_ptr++; + for (int32_t i = 0; i < num; i++) { + // skip vertices + obj_ptr += 3; + TOGGLE_REFLECTION_ENABLED(*obj_ptr++, enabled); + } + + // color quads + num = *obj_ptr++; + for (int32_t i = 0; i < num; i++) { + // skip vertices + obj_ptr += 4; + TOGGLE_REFLECTION_ENABLED(*obj_ptr++, enabled); + } + + // color triangles + num = *obj_ptr++; + for (int32_t i = 0; i < num; i++) { + // skip vertices + obj_ptr += 3; + TOGGLE_REFLECTION_ENABLED(*obj_ptr++, enabled); + } +} + +void Object_SetReflective(const GAME_OBJECT_ID object_id, const bool enabled) +{ + const OBJECT_INFO *const object = &g_Objects[object_id]; + for (int32_t i = 0; i < object->nmeshes; i++) { + Object_SetMeshReflective(object_id, i, enabled); + } +} diff --git a/src/game/objects/common.h b/src/game/objects/common.h index 26d61b0b8..a46e93b6d 100644 --- a/src/game/objects/common.h +++ b/src/game/objects/common.h @@ -43,3 +43,6 @@ void Object_DrawSpriteItem(ITEM_INFO *item); void Object_DrawPickupItem(ITEM_INFO *item); void Object_DrawAnimatingItem(ITEM_INFO *item); void Object_DrawUnclippedItem(ITEM_INFO *item); +void Object_SetMeshReflective( + GAME_OBJECT_ID object_id, int32_t mesh_idx, bool enabled); +void Object_SetReflective(GAME_OBJECT_ID object_id, bool enabled); diff --git a/src/game/objects/general/save_crystal.c b/src/game/objects/general/save_crystal.c index 9e8702049..7335077dd 100644 --- a/src/game/objects/general/save_crystal.c +++ b/src/game/objects/general/save_crystal.c @@ -36,6 +36,7 @@ void SaveCrystal_Setup(OBJECT_INFO *obj) obj->save_flags = 1; } obj->bounds = SaveCrystal_Bounds; + Object_SetReflective(O_SAVEGAME_ITEM, true); } void SaveCrystal_Initialise(int16_t item_num) diff --git a/src/game/option/option_graphics.c b/src/game/option/option_graphics.c index b31636fdf..b2e889054 100644 --- a/src/game/option/option_graphics.c +++ b/src/game/option/option_graphics.c @@ -50,9 +50,10 @@ typedef enum GRAPHICS_OPTION_NAME { OPTION_RESOLUTION, OPTION_PERSPECTIVE, OPTION_PRETTY_PIXELS, + OPTION_REFLECTIONS, OPTION_NUMBER_OF, OPTION_MIN = OPTION_FPS, - OPTION_MAX = OPTION_PRETTY_PIXELS, + OPTION_MAX = OPTION_REFLECTIONS, } GRAPHICS_OPTION_NAME; typedef struct GRAPHICS_OPTION_ROW { @@ -85,6 +86,7 @@ static const GRAPHICS_OPTION_ROW m_GfxOptionRows[] = { { OPTION_RESOLUTION, GS_DETAIL_RESOLUTION, GS_DETAIL_RESOLUTION_FMT }, { OPTION_PERSPECTIVE, GS_DETAIL_PERSPECTIVE, GS_MISC_ON }, { OPTION_PRETTY_PIXELS, GS_DETAIL_PRETTY_PIXELS, GS_MISC_ON }, + { OPTION_REFLECTIONS, GS_DETAIL_REFLECTIONS, GS_MISC_ON }, // end { OPTION_NUMBER_OF, 0, 0 }, }; @@ -302,6 +304,10 @@ static void Option_Graphics_UpdateArrows( m_HideArrowLeft = !g_Config.rendering.pretty_pixels; m_HideArrowRight = g_Config.rendering.pretty_pixels; break; + case OPTION_REFLECTIONS: + m_HideArrowLeft = !g_Config.rendering.enable_reflections; + m_HideArrowRight = g_Config.rendering.enable_reflections; + break; case OPTION_NUMBER_OF: default: @@ -447,6 +453,12 @@ static void Option_Graphics_ChangeTextOption( break; } + case OPTION_REFLECTIONS: { + bool is_enabled = g_Config.rendering.enable_reflections; + Text_ChangeText(value_text, is_enabled ? GS(MISC_ON) : GS(MISC_OFF)); + break; + } + case OPTION_NUMBER_OF: default: break; @@ -557,6 +569,13 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) } break; + case OPTION_REFLECTIONS: + if (!g_Config.rendering.enable_reflections) { + g_Config.rendering.enable_reflections = true; + reset = OPTION_REFLECTIONS; + } + break; + case OPTION_NUMBER_OF: default: break; @@ -644,6 +663,13 @@ void Option_Graphics(INVENTORY_ITEM *inv_item) } break; + case OPTION_REFLECTIONS: + if (g_Config.rendering.enable_reflections) { + g_Config.rendering.enable_reflections = false; + reset = OPTION_REFLECTIONS; + } + break; + case OPTION_NUMBER_OF: default: break; diff --git a/src/game/output.c b/src/game/output.c index f57bdb695..b98b09147 100644 --- a/src/game/output.c +++ b/src/game/output.c @@ -25,6 +25,7 @@ #include #define MAX_LIGHTNINGS 64 +#define PHD_IONE (PHD_ONE / 4) typedef struct { struct { @@ -37,6 +38,8 @@ static bool m_IsSkyboxEnabled = false; static bool m_IsWibbleEffect = false; static bool m_IsWaterEffect = false; static bool m_IsShadeEffect = false; +static bool m_IsTintEffect = false; +static RGB_F m_TintColor = { 0 }; static int m_OverlayCurAlpha = 0; static int m_OverlayDstAlpha = 0; static int m_BackdropCurAlpha = 0; @@ -52,6 +55,7 @@ static int32_t m_ShadeTable[WIBBLE_SIZE] = { 0 }; static int32_t m_RandTable[WIBBLE_SIZE] = { 0 }; static PHD_VBUF *m_VBuf = NULL; +static PHD_UV *m_EnvMapUV = NULL; static int32_t m_DrawDistFade = 0; static int32_t m_DrawDistMax = 0; static RGB_F m_WaterColor = { 0 }; @@ -79,6 +83,7 @@ static const int16_t *Output_DrawRoomSprites( const int16_t *obj_ptr, int32_t vertex_count); static const int16_t *Output_CalcObjectVertices(const int16_t *obj_ptr); static const int16_t *Output_CalcVerticeLight(const int16_t *obj_ptr); +static const int16_t *Output_CalcVerticeEnvMap(const int16_t *obj_ptr); static const int16_t *Output_CalcSkyboxLight(const int16_t *obj_ptr); static const int16_t *Output_CalcRoomVertices(const int16_t *obj_ptr); static int32_t Output_CalcFogShade(int32_t depth); @@ -89,14 +94,14 @@ static const int16_t *Output_DrawObjectG3( { S_Output_DisableTextureMode(); - for (int i = 0; i < number; i++) { - PHD_VBUF *vns[3] = { + for (int32_t i = 0; i < number; i++) { + PHD_VBUF *const vns[3] = { &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], }; - uint8_t color_idx = *obj_ptr++; - RGB_888 color = Output_GetPaletteColor(color_idx); + const int16_t color_idx = DISABLE_REFLECTION_BIT(*obj_ptr++); + const RGB_888 color = Output_GetPaletteColor(color_idx); S_Output_DrawFlatTriangle(vns[0], vns[1], vns[2], color); } @@ -108,15 +113,16 @@ static const int16_t *Output_DrawObjectG4( { S_Output_DisableTextureMode(); - for (int i = 0; i < number; i++) { - PHD_VBUF *vns[4] = { + for (int32_t i = 0; i < number; i++) { + PHD_VBUF *const vns[4] = { &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], }; - uint8_t color_idx = *obj_ptr++; - RGB_888 color = Output_GetPaletteColor(color_idx); + const int16_t color_idx = DISABLE_REFLECTION_BIT(*obj_ptr++); + + const RGB_888 color = Output_GetPaletteColor(color_idx); S_Output_DrawFlatTriangle(vns[0], vns[1], vns[2], color); S_Output_DrawFlatTriangle(vns[2], vns[3], vns[0], color); } @@ -129,13 +135,14 @@ static const int16_t *Output_DrawObjectGT3( { S_Output_EnableTextureMode(); - for (int i = 0; i < number; i++) { - PHD_VBUF *vns[3] = { + for (int32_t i = 0; i < number; i++) { + PHD_VBUF *const vns[3] = { &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], }; - PHD_TEXTURE *tex = &g_PhdTextureInfo[*obj_ptr++]; + const int16_t texture_num = DISABLE_REFLECTION_BIT(*obj_ptr++); + PHD_TEXTURE *const tex = &g_PhdTextureInfo[texture_num]; S_Output_DrawTexturedTriangle( vns[0], vns[1], vns[2], tex->tpage, &tex->uv[0], &tex->uv[1], @@ -150,14 +157,15 @@ static const int16_t *Output_DrawObjectGT4( { S_Output_EnableTextureMode(); - for (int i = 0; i < number; i++) { - PHD_VBUF *vns[4] = { + for (int32_t i = 0; i < number; i++) { + PHD_VBUF *const vns[4] = { &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], &m_VBuf[*obj_ptr++], }; - PHD_TEXTURE *tex = &g_PhdTextureInfo[*obj_ptr++]; + const int16_t texture_num = DISABLE_REFLECTION_BIT(*obj_ptr++); + PHD_TEXTURE *const tex = &g_PhdTextureInfo[texture_num]; S_Output_DrawTexturedQuad( vns[0], vns[1], vns[2], vns[3], tex->tpage, &tex->uv[0], @@ -167,6 +175,56 @@ static const int16_t *Output_DrawObjectGT4( return obj_ptr; } +static const int16_t *Output_DrawObjectEnvMap( + const int16_t *obj_ptr, const int32_t poly_count, + const int32_t vertex_count, const bool textured) +{ + if (textured) { + S_Output_EnableTextureMode(); + } else { + S_Output_DisableTextureMode(); + } + + PHD_VBUF *vns[4]; + PHD_UV uv[4]; + + for (int32_t i = 0; i < poly_count; i++) { + for (int32_t j = 0; j < vertex_count; j++) { + const int16_t vertex_num = *obj_ptr++; + vns[j] = &m_VBuf[vertex_num]; + uv[j] = m_EnvMapUV[vertex_num]; + } + + const int16_t color_or_texture_num = *obj_ptr++; + if (!IS_REFLECTION_ENABLED(color_or_texture_num)) { + continue; + } + + if (!textured) { + const RGB_888 pixel = + S_Output_GetPaletteColor(color_or_texture_num & ~0x8000); + m_TintColor.r = pixel.r / 255.0f; + m_TintColor.g = pixel.g / 255.0f; + m_TintColor.b = pixel.b / 255.0f; + m_IsTintEffect = true; + } + + if (vertex_count == 3) { + S_Output_DrawTexturedTriangle( + vns[0], vns[1], vns[2], ENV_MAP_TEXTURE, &uv[0], &uv[1], &uv[2], + 0); + } else if (vertex_count == 4) { + S_Output_DrawTexturedQuad( + vns[0], vns[1], vns[2], vns[3], ENV_MAP_TEXTURE, &uv[0], &uv[1], + &uv[2], &uv[3], 0); + } + + m_IsTintEffect = false; + } + + return obj_ptr; +} + static const int16_t *Output_DrawRoomSprites( const int16_t *obj_ptr, int32_t vertex_count) { @@ -307,6 +365,51 @@ static const int16_t *Output_CalcVerticeLight(const int16_t *obj_ptr) return obj_ptr; } +static const int16_t *Output_CalcVerticeEnvMap(const int16_t *obj_ptr) +{ + const int32_t vtx_count = *obj_ptr++; + if (vtx_count <= 0) { + return NULL; + } + + for (int32_t i = 0; i < vtx_count; ++i) { + // make sure that reflection will be drawn after normal poly + m_VBuf[i].zv -= (double)(W2V_SCALE / 2); + + // set lighting that depends only from fog distance + m_VBuf[i].g = 0x1000; + + const int32_t depth = g_MatrixPtr->_23 >> W2V_SHIFT; + m_VBuf[i].g += Output_CalcFogShade(depth); + + // reflection can be darker but not brighter + CLAMP(m_VBuf[i].g, 0x1000, 0x1FFF); + + // rotate normal vectors for X/Y, no translation + + // clang-format off + int32_t x = ( + g_MatrixPtr->_00 * obj_ptr[0] + + g_MatrixPtr->_01 * obj_ptr[1] + + g_MatrixPtr->_02 * obj_ptr[2] + ) >> W2V_SHIFT; + + int32_t y = ( + g_MatrixPtr->_10 * obj_ptr[0] + + g_MatrixPtr->_11 * obj_ptr[1] + + g_MatrixPtr->_12 * obj_ptr[2] + ) >> W2V_SHIFT; + // clang-format on + + CLAMP(x, -PHD_ONE, PHD_IONE); + CLAMP(y, -PHD_ONE, PHD_IONE); + m_EnvMapUV[i].u = PHD_ONE / PHD_IONE * (x + PHD_IONE) / 2; + m_EnvMapUV[i].v = PHD_ONE - PHD_ONE / PHD_IONE * (y + PHD_IONE) / 2; + obj_ptr += 3; + } + return obj_ptr; +} + static const int16_t *Output_CalcSkyboxLight(const int16_t *obj_ptr) { int32_t vertex_count = *obj_ptr++; @@ -439,6 +542,7 @@ void Output_Shutdown(void) void Output_ReserveVertexBuffer(const size_t size) { m_VBuf = GameBuf_Alloc(size * sizeof(PHD_VBUF), GBUF_VERTEX_BUFFER); + m_EnvMapUV = GameBuf_Alloc(size * sizeof(PHD_UV), GBUF_VERTEX_BUFFER); } void Output_SetWindowSize(int width, int height) @@ -608,14 +712,30 @@ void Output_CalculateObjectLighting( void Output_DrawPolygons(const int16_t *obj_ptr, int clip) { + const bool has_reflections = IS_REFLECTION_ENABLED(obj_ptr[3]); obj_ptr += 4; + obj_ptr = Output_CalcObjectVertices(obj_ptr); - if (obj_ptr) { - obj_ptr = Output_CalcVerticeLight(obj_ptr); - obj_ptr = Output_DrawObjectGT4(obj_ptr + 1, *obj_ptr); - obj_ptr = Output_DrawObjectGT3(obj_ptr + 1, *obj_ptr); - obj_ptr = Output_DrawObjectG4(obj_ptr + 1, *obj_ptr); - obj_ptr = Output_DrawObjectG3(obj_ptr + 1, *obj_ptr); + if (obj_ptr == NULL) { + return; + } + + const int16_t *obj_ptr_old = obj_ptr; + obj_ptr = Output_CalcVerticeLight(obj_ptr); + obj_ptr = Output_DrawObjectGT4(obj_ptr + 1, *obj_ptr); + obj_ptr = Output_DrawObjectGT3(obj_ptr + 1, *obj_ptr); + obj_ptr = Output_DrawObjectG4(obj_ptr + 1, *obj_ptr); + obj_ptr = Output_DrawObjectG3(obj_ptr + 1, *obj_ptr); + + if (has_reflections && g_Config.rendering.enable_reflections) { + obj_ptr = obj_ptr_old; + obj_ptr = Output_CalcVerticeEnvMap(obj_ptr); + if (obj_ptr != NULL) { + obj_ptr = Output_DrawObjectEnvMap(obj_ptr + 1, *obj_ptr, 4, true); + obj_ptr = Output_DrawObjectEnvMap(obj_ptr + 1, *obj_ptr, 3, true); + obj_ptr = Output_DrawObjectEnvMap(obj_ptr + 1, *obj_ptr, 4, false); + obj_ptr = Output_DrawObjectEnvMap(obj_ptr + 1, *obj_ptr, 3, false); + } } } @@ -1179,13 +1299,19 @@ bool Output_FadeIsAnimating(void) || m_BackdropCurAlpha != m_BackdropDstAlpha; } -void Output_ApplyWaterEffect(float *r, float *g, float *b) +void Output_ApplyTint(float *r, float *g, float *b) { if (m_IsShadeEffect) { *r *= m_WaterColor.r; *g *= m_WaterColor.g; *b *= m_WaterColor.b; } + + if (m_IsTintEffect) { + *r *= m_TintColor.r; + *g *= m_TintColor.g; + *b *= m_TintColor.b; + } } bool Output_MakeScreenshot(const char *path) diff --git a/src/game/output.h b/src/game/output.h index 722479f62..223135b9e 100644 --- a/src/game/output.h +++ b/src/game/output.h @@ -5,6 +5,16 @@ #include #include +// TODO: remove these macros +#define IS_REFLECTION_ENABLED(target) ((uint16_t)(target) & 0x8000) +#define DISABLE_REFLECTION_BIT(target) ((uint16_t)(target) & ~0x8000) +#define TOGGLE_REFLECTION_ENABLED(target, enabled) \ + if (enabled) { \ + target |= 0x8000; \ + } else { \ + target &= ~0x8000; \ + } + bool Output_Init(void); void Output_Shutdown(void); void Output_ReserveVertexBuffer(size_t size); @@ -105,8 +115,9 @@ void Output_AnimateTextures(void); void Output_AnimateFades(void); void Output_RotateLight(int16_t pitch, int16_t yaw); -void Output_ApplyWaterEffect(float *r, float *g, float *b); +void Output_ApplyTint(float *r, float *g, float *b); +void Output_FillEnvironmentMap(void); bool Output_MakeScreenshot(const char *path); int Output_GetObjectBounds(const BOUNDS_16 *bounds); diff --git a/src/game/room_draw.c b/src/game/room_draw.c index b0bf75295..063c412f9 100644 --- a/src/game/room_draw.c +++ b/src/game/room_draw.c @@ -209,15 +209,6 @@ void Room_DrawAllRooms(int16_t base_room, int16_t target_room) for (int i = 0; i < g_RoomsToDrawCount; i++) { Room_DrawSingleRoom(g_RoomsToDraw[i]); } - - if (g_Objects[O_LARA].loaded) { - if (g_RoomInfo[g_LaraItem->room_num].flags & RF_UNDERWATER) { - Output_SetupBelowWater(g_Camera.underwater); - } else { - Output_SetupAboveWater(g_Camera.underwater); - } - Lara_Draw(g_LaraItem); - } } static void Room_PrepareToDraw(int16_t room_num) diff --git a/src/gfx/3d/3d_renderer.c b/src/gfx/3d/3d_renderer.c index b97a86aa4..3a01c2194 100644 --- a/src/gfx/3d/3d_renderer.c +++ b/src/gfx/3d/3d_renderer.c @@ -16,15 +16,22 @@ static void GFX_3D_Renderer_SelectTextureImpl( GFX_3D_Renderer *renderer, int texture_num) { assert(renderer); - if (texture_num == GFX_NO_TEXTURE) { + + GFX_GL_Texture *texture = NULL; + if (texture_num == GFX_ENV_MAP_TEXTURE) { + texture = renderer->env_map_texture; + } else if (texture_num != GFX_NO_TEXTURE) { + assert(texture_num >= 0); + assert(texture_num < GFX_MAX_TEXTURES); + texture = renderer->textures[texture_num]; + } + + if (texture == NULL) { glBindTexture(GL_TEXTURE_2D, 0); + GFX_GL_CheckError(); return; } - assert(texture_num >= 0); - assert(texture_num < GFX_MAX_TEXTURES); - - GFX_GL_Texture *texture = renderer->textures[texture_num]; GFX_GL_Texture_Bind(texture); } @@ -147,7 +154,59 @@ void GFX_3D_Renderer_ClearDepth(GFX_3D_Renderer *renderer) GFX_GL_CheckError(); } -int GFX_3D_Renderer_TextureReg( +int GFX_3D_Renderer_RegisterEnvironmentMap(GFX_3D_Renderer *const renderer) +{ + assert(renderer != NULL); + assert(renderer->env_map_texture == NULL); + + GFX_GL_Texture *texture = GFX_GL_Texture_Create(GL_TEXTURE_2D); + renderer->env_map_texture = texture; + + GFX_3D_Renderer_RestoreTexture(renderer); + GFX_GL_CheckError(); + return GFX_ENV_MAP_TEXTURE; +} + +bool GFX_3D_Renderer_UnregisterEnvironmentMap( + GFX_3D_Renderer *const renderer, const int texture_num) +{ + assert(renderer != NULL); + + GFX_GL_Texture *const texture = renderer->env_map_texture; + if (texture == NULL) { + LOG_ERROR("No environment map registered"); + return false; + } + + if (texture_num != GFX_ENV_MAP_TEXTURE) { + LOG_ERROR("Invalid environment map texture ID"); + return false; + } + + // unbind texture if currently bound + if (renderer->selected_texture_num == texture_num) { + GFX_3D_Renderer_SelectTextureImpl(renderer, GFX_NO_TEXTURE); + renderer->selected_texture_num = GFX_NO_TEXTURE; + } + + GFX_GL_Texture_Free(texture); + renderer->env_map_texture = NULL; + return true; +} + +void GFX_3D_Renderer_FillEnvironmentMap(GFX_3D_Renderer *const renderer) +{ + assert(renderer != NULL); + + GFX_GL_Texture *const env_map = renderer->env_map_texture; + if (env_map != NULL) { + GFX_3D_VertexStream_RenderPending(&renderer->vertex_stream); + GFX_GL_Texture_LoadFromBackBuffer(env_map); + GFX_3D_Renderer_RestoreTexture(renderer); + } +} + +int GFX_3D_Renderer_RegisterTexturePage( GFX_3D_Renderer *renderer, const void *data, int width, int height) { assert(renderer); @@ -170,7 +229,8 @@ int GFX_3D_Renderer_TextureReg( return texture_num; } -bool GFX_3D_Renderer_TextureUnreg(GFX_3D_Renderer *renderer, int texture_num) +bool GFX_3D_Renderer_UnregisterTexturePage( + GFX_3D_Renderer *renderer, int texture_num) { assert(renderer); assert(texture_num >= 0); diff --git a/src/gfx/3d/3d_renderer.h b/src/gfx/3d/3d_renderer.h index 33ebda81a..267563467 100644 --- a/src/gfx/3d/3d_renderer.h +++ b/src/gfx/3d/3d_renderer.h @@ -9,6 +9,7 @@ #define GFX_MAX_TEXTURES 128 #define GFX_NO_TEXTURE (-1) +#define GFX_ENV_MAP_TEXTURE (-2) #include #include @@ -19,6 +20,7 @@ typedef struct GFX_3D_Renderer { GFX_3D_VertexStream vertex_stream; GFX_GL_Texture *textures[GFX_MAX_TEXTURES]; + GFX_GL_Texture *env_map_texture; int selected_texture_num; // shader variable locations @@ -35,9 +37,15 @@ void GFX_3D_Renderer_RenderBegin(GFX_3D_Renderer *renderer); void GFX_3D_Renderer_RenderEnd(GFX_3D_Renderer *renderer); void GFX_3D_Renderer_ClearDepth(GFX_3D_Renderer *renderer); -int GFX_3D_Renderer_TextureReg( +int GFX_3D_Renderer_RegisterTexturePage( GFX_3D_Renderer *renderer, const void *data, int width, int height); -bool GFX_3D_Renderer_TextureUnreg(GFX_3D_Renderer *renderer, int texture_num); +bool GFX_3D_Renderer_UnregisterTexturePage( + GFX_3D_Renderer *renderer, int texture_num); + +int GFX_3D_Renderer_RegisterEnvironmentMap(GFX_3D_Renderer *renderer); +bool GFX_3D_Renderer_UnregisterEnvironmentMap( + GFX_3D_Renderer *renderer, int texture_num); +void GFX_3D_Renderer_FillEnvironmentMap(GFX_3D_Renderer *renderer); void GFX_3D_Renderer_SelectTexture(GFX_3D_Renderer *renderer, int texture_num); void GFX_3D_Renderer_RestoreTexture(GFX_3D_Renderer *renderer); diff --git a/src/gfx/gl/texture.c b/src/gfx/gl/texture.c index 3d916b467..3ca5a2efd 100644 --- a/src/gfx/gl/texture.c +++ b/src/gfx/gl/texture.c @@ -3,6 +3,7 @@ #include "gfx/gl/utils.h" #include +#include #include @@ -15,7 +16,7 @@ GFX_GL_Texture *GFX_GL_Texture_Create(GLenum target) void GFX_GL_Texture_Free(GFX_GL_Texture *texture) { - if (texture) { + if (texture != NULL) { GFX_GL_Texture_Close(texture); Memory_FreePointer(&texture); } @@ -23,7 +24,7 @@ void GFX_GL_Texture_Free(GFX_GL_Texture *texture) void GFX_GL_Texture_Init(GFX_GL_Texture *texture, GLenum target) { - assert(texture); + assert(texture != NULL); texture->target = target; glGenTextures(1, &texture->id); GFX_GL_CheckError(); @@ -31,14 +32,14 @@ void GFX_GL_Texture_Init(GFX_GL_Texture *texture, GLenum target) void GFX_GL_Texture_Close(GFX_GL_Texture *texture) { - assert(texture); + assert(texture != NULL); glDeleteTextures(1, &texture->id); GFX_GL_CheckError(); } void GFX_GL_Texture_Bind(GFX_GL_Texture *texture) { - assert(texture); + assert(texture != NULL); glBindTexture(texture->target, texture->id); GFX_GL_CheckError(); } @@ -47,7 +48,7 @@ void GFX_GL_Texture_Load( GFX_GL_Texture *texture, const void *data, int width, int height, GLint internal_format, GLint format) { - assert(texture); + assert(texture != NULL); GFX_GL_Texture_Bind(texture); @@ -59,3 +60,28 @@ void GFX_GL_Texture_Load( glGenerateMipmap(GL_TEXTURE_2D); GFX_GL_CheckError(); } + +void GFX_GL_Texture_LoadFromBackBuffer(GFX_GL_Texture *const texture) +{ + assert(texture != NULL); + + GFX_GL_Texture_Bind(texture); + + 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; + + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, w, h, 0); + GFX_GL_CheckError(); +} diff --git a/src/gfx/gl/texture.h b/src/gfx/gl/texture.h index a64a7ef2a..463a299ce 100644 --- a/src/gfx/gl/texture.h +++ b/src/gfx/gl/texture.h @@ -16,3 +16,4 @@ void GFX_GL_Texture_Bind(GFX_GL_Texture *texture); void GFX_GL_Texture_Load( GFX_GL_Texture *texture, const void *data, int width, int height, GLint internal_format, GLint format); +void GFX_GL_Texture_LoadFromBackBuffer(GFX_GL_Texture *texture); diff --git a/src/specific/s_output.c b/src/specific/s_output.c index 77e3e38e7..dde1781e9 100644 --- a/src/specific/s_output.c +++ b/src/specific/s_output.c @@ -31,6 +31,7 @@ } static int m_TextureMap[GFX_MAX_TEXTURES] = { GFX_NO_TEXTURE }; +static int m_EnvMapTexture = GFX_NO_TEXTURE; static RGB_888 m_ColorPalette[256]; static GFX_2D_Renderer *m_Renderer2D = NULL; @@ -78,10 +79,14 @@ static void S_Output_ReleaseTextures(void) } for (int i = 0; i < GFX_MAX_TEXTURES; i++) { if (m_TextureMap[i] != GFX_NO_TEXTURE) { - GFX_3D_Renderer_TextureUnreg(m_Renderer3D, m_TextureMap[i]); + GFX_3D_Renderer_UnregisterTexturePage( + m_Renderer3D, m_TextureMap[i]); m_TextureMap[i] = GFX_NO_TEXTURE; } } + if (m_EnvMapTexture != GFX_NO_TEXTURE) { + GFX_3D_Renderer_UnregisterEnvironmentMap(m_Renderer3D, m_EnvMapTexture); + } } static void S_Output_ReleaseSurfaces(void) @@ -106,6 +111,11 @@ static void S_Output_ReleaseSurfaces(void) } } +void Output_FillEnvironmentMap(void) +{ + GFX_3D_Renderer_FillEnvironmentMap(m_Renderer3D); +} + static void S_Output_FlipPrimaryBuffer(void) { GFX_Context_SwapBuffers(); @@ -371,7 +381,7 @@ static int32_t S_Output_ZedClipper( v->r = v->g = v->b = (8192.0f - (pts0->g + (pts1->g - pts0->g) * clip)) * multiplier; - Output_ApplyWaterEffect(&v->r, &v->g, &v->b); + Output_ApplyTint(&v->r, &v->g, &v->b); v++; } @@ -386,7 +396,7 @@ static int32_t S_Output_ZedClipper( v->t = pts0->v * v->w / 256.0f; v->r = v->g = v->b = (8192.0f - pts0->g) * multiplier; - Output_ApplyWaterEffect(&v->r, &v->g, &v->b); + Output_ApplyTint(&v->r, &v->g, &v->b); v++; } @@ -494,19 +504,24 @@ void S_Output_DownloadBackdropSurface(const IMAGE *const image) m_PictureSurface = GFX_2D_Surface_CreateFromImage(image); } -void S_Output_SelectTexture(int tex_num) +void S_Output_SelectTexture(const int32_t texture_num) { - if (tex_num == m_SelectedTexture) { + if (texture_num == m_SelectedTexture) { return; } - if (m_TextureMap[tex_num] == GFX_NO_TEXTURE) { - LOG_ERROR("ERROR: Attempt to select unloaded texture"); - return; + if (texture_num == ENV_MAP_TEXTURE) { + GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_EnvMapTexture); + } else { + 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]); } - GFX_3D_Renderer_SelectTexture(m_Renderer3D, m_TextureMap[tex_num]); - m_SelectedTexture = tex_num; + m_SelectedTexture = texture_num; } void S_Output_DrawSprite( @@ -818,7 +833,6 @@ void S_Output_ApplyRenderSettings(void) GFX_2D_SurfaceDesc surface_desc = { 0 }; m_PrimarySurface = GFX_2D_Surface_Create(&surface_desc); } - S_Output_ClearSurface(m_PrimarySurface); for (int i = 0; i < GFX_MAX_TEXTURES; i++) { @@ -887,7 +901,7 @@ void S_Output_DrawFlatTriangle( vertices[i].g = color.g * light; vertices[i].b = color.b * light; - Output_ApplyWaterEffect(&vertices[i].r, &vertices[i].g, &vertices[i].b); + Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b); } if ((vn1->clip | vn2->clip | vn3->clip) >= 0) { @@ -978,8 +992,7 @@ void S_Output_DrawTexturedTriangle( vertices[i].r = vertices[i].g = vertices[i].b = (8192.0f - src_vbuf[i]->g) * multiplier; - Output_ApplyWaterEffect( - &vertices[i].r, &vertices[i].g, &vertices[i].b); + Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b); } if (vn1->clip || vn2->clip || vn3->clip) { @@ -1014,7 +1027,7 @@ void S_Output_DrawTexturedTriangle( return; } - if (m_TextureMap[tpage] != GFX_NO_TEXTURE) { + if (tpage == ENV_MAP_TEXTURE || m_TextureMap[tpage] != GFX_NO_TEXTURE) { S_Output_EnableTextureMode(); S_Output_SelectTexture(tpage); S_Output_DrawTriangleFan(vertices, vertex_count); @@ -1025,7 +1038,7 @@ void S_Output_DrawTexturedTriangle( } void S_Output_DrawTexturedQuad( - PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, uint16_t tpage, + PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, int16_t tpage, PHD_UV *uv1, PHD_UV *uv2, PHD_UV *uv3, PHD_UV *uv4, uint16_t textype) { int vertex_count = 4; @@ -1082,10 +1095,10 @@ void S_Output_DrawTexturedQuad( vertices[i].r = vertices[i].g = vertices[i].b = (8192.0f - src_vbuf[i]->g) * multiplier; - Output_ApplyWaterEffect(&vertices[i].r, &vertices[i].g, &vertices[i].b); + Output_ApplyTint(&vertices[i].r, &vertices[i].g, &vertices[i].b); } - if (m_TextureMap[tpage] != GFX_NO_TEXTURE) { + if (tpage == ENV_MAP_TEXTURE || m_TextureMap[tpage] != GFX_NO_TEXTURE) { S_Output_EnableTextureMode(); S_Output_SelectTexture(tpage); } else { @@ -1122,12 +1135,14 @@ void S_Output_DownloadTextures(int32_t pages) result = GFX_2D_Surface_Unlock(m_TextureSurfaces[i]); S_Output_CheckError(result); - m_TextureMap[i] = GFX_3D_Renderer_TextureReg( + m_TextureMap[i] = GFX_3D_Renderer_RegisterTexturePage( m_Renderer3D, surface_desc.pixels, surface_desc.width, surface_desc.height); } m_SelectedTexture = -1; + + m_EnvMapTexture = GFX_3D_Renderer_RegisterEnvironmentMap(m_Renderer3D); } bool S_Output_MakeScreenshot(const char *path) diff --git a/src/specific/s_output.h b/src/specific/s_output.h index 6f2a2adbe..2606b3bae 100644 --- a/src/specific/s_output.h +++ b/src/specific/s_output.h @@ -7,6 +7,8 @@ #include #include +#define ENV_MAP_TEXTURE (-1) + bool S_Output_Init(void); void S_Output_Shutdown(void); @@ -27,7 +29,7 @@ void S_Output_SetPalette(RGB_888 palette[256]); RGB_888 S_Output_GetPaletteColor(uint8_t idx); void S_Output_DownloadTextures(int32_t pages); -void S_Output_SelectTexture(int tex_num); +void S_Output_SelectTexture(int32_t texture_num); void S_Output_DownloadBackdropSurface(const IMAGE *image); void S_Output_DrawBackdropSurface(void); @@ -37,7 +39,7 @@ void S_Output_DrawTexturedTriangle( PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, int16_t tpage, PHD_UV *uv1, PHD_UV *uv2, PHD_UV *uv3, uint16_t textype); void S_Output_DrawTexturedQuad( - PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, uint16_t tpage, + PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3, PHD_VBUF *vn4, int16_t tpage, PHD_UV *uv1, PHD_UV *uv2, PHD_UV *uv3, PHD_UV *uv4, uint16_t textype); void S_Output_DrawSprite( int16_t x1, int16_t y1, int16_t x2, int y2, int z, int sprnum, int shade);