diff --git a/CHANGELOG.md b/CHANGELOG.md index cb88fb08e..b4213e653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## [Unreleased](https://github.com/LostArtefacts/TR1X/compare/stable...develop) - ××××-××-×× - added deadly water feature from TR2+ for custom levels (#1404) +- added skybox support, with a default option provided for Lost Valley, Colosseum and Obelisk of Khamoon (#94) - fixed adjacent Midas Touch objects potentially allowing gold bar duplication in custom levels (#1415) - fixed the excessive pitch and playback speed correction for music files with sampling rate other than 44100 Hz (#1417) diff --git a/GAMEFLOW.md b/GAMEFLOW.md index f83e7fd40..4e95e2b5e 100644 --- a/GAMEFLOW.md +++ b/GAMEFLOW.md @@ -1333,6 +1333,14 @@ provided with the game achieves. using the 3D pickups option. + + + *_skybox.bin + + + Injects a predefined skybox model into specific levels. + + *_textures.bin diff --git a/README.md b/README.md index 540b97836..c464c62a1 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,24 @@ topic](https://www.tombraiderforums.com/showthread.php?p=8286101). + + Skybox support + + Customizable draw distance + + Fly cheat + + Developer console + + @@ -554,6 +564,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det - added a vsync option - 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` - 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 @@ -565,7 +576,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det - **Gym**: incorrect textures in room 9 - **Caves**: an incorrect texture in room 6 and missing textures in rooms 1, 10, 14 and 30 - **City of Vilcabamba**: an incorrect texture in room 26, and a missing texture and a stretched texture in room 15 - - **Lost Valley**: incorrect textures in rooms 6, 9, 16 and 35, missing textures in rooms 9, 25, 26, 27, 51, and 90, and stretched textures in room 63 + - **Lost Valley**: incorrect textures in rooms 6, 9, 16, 34 and 35, missing textures in rooms 6, 9, 25, 26, 27, 51, and 90, and stretched textures in room 63 - **Tomb of Qualopec**: an incorrect and missing textures in room 8, and a misaligned texture in room 5 - **St. Francis' Folly**: incorrect textures in rooms 1, 4, 18 and 35, and a misaligned texture in room 3 - **Colosseum**: incorrect Midas textures appearing at the roof, incorrect textures in rooms 37, 67, 75 and 82, and missing textures in rooms 2 and 7 @@ -573,7 +584,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det - **The Cistern**: missing textures in rooms 3 and 9 and a stretched texture in room 102 - **Tomb of Tihocan**: incorrect textures in rooms 75 and 89 and a misaligned texture in room 104 - **City of Khamoon**: incorrect textures in rooms 47, 48, 51, 60 and 64, and a missing texture in room 58 - - **Obelisk of Khamoon**: incorrect textures in rooms 22, 23, 42 and 65 + - **Obelisk of Khamoon**: incorrect textures in rooms 22, 23, 42 and 65; added shading to the gaps into City of Khamoon in rooms 8 and 20/21 - **Sanctuary of the Scion**: missing textures in rooms 1, 11, 21, 52, 53, and 54 - **Natla's Mines**: a missing texture in room 35, overlapping textures in room 55, an incorrect texture in room 69, and stretched textures in rooms 23 and 24 - **Pre-Atlantis Cutscene**: stretched textures in rooms 6 and 21 diff --git a/data/ship/cfg/TR1X_gameflow.json5 b/data/ship/cfg/TR1X_gameflow.json5 index 08615ba8c..f15a010a2 100644 --- a/data/ship/cfg/TR1X_gameflow.json5 +++ b/data/ship/cfg/TR1X_gameflow.json5 @@ -106,6 +106,7 @@ "music": 57, "injections": [ "data/injections/valley_itemrots.bin", + "data/injections/valley_skybox.bin", "data/injections/valley_textures.bin", ], "sequence": [ @@ -182,6 +183,7 @@ "data/injections/colosseum_door.bin", "data/injections/colosseum_fd.bin", "data/injections/colosseum_itemrots.bin", + "data/injections/colosseum_skybox.bin", "data/injections/colosseum_textures.bin", ], "sequence": [ @@ -311,6 +313,7 @@ "injections": [ "data/injections/obelisk_fd.bin", "data/injections/obelisk_itemrots.bin", + "data/injections/obelisk_skybox.bin", "data/injections/obelisk_textures.bin", ], "sequence": [ diff --git a/data/ship/data/injections/colosseum_skybox.bin b/data/ship/data/injections/colosseum_skybox.bin new file mode 100644 index 000000000..0b8db1794 Binary files /dev/null and b/data/ship/data/injections/colosseum_skybox.bin differ diff --git a/data/ship/data/injections/obelisk_skybox.bin b/data/ship/data/injections/obelisk_skybox.bin new file mode 100644 index 000000000..ac9dd0ced Binary files /dev/null and b/data/ship/data/injections/obelisk_skybox.bin differ diff --git a/data/ship/data/injections/obelisk_textures.bin b/data/ship/data/injections/obelisk_textures.bin index 50772ce4b..4cd29293f 100644 Binary files a/data/ship/data/injections/obelisk_textures.bin and b/data/ship/data/injections/obelisk_textures.bin differ diff --git a/data/ship/data/injections/valley_skybox.bin b/data/ship/data/injections/valley_skybox.bin new file mode 100644 index 000000000..6f21d675d Binary files /dev/null and b/data/ship/data/injections/valley_skybox.bin differ diff --git a/data/ship/data/injections/valley_textures.bin b/data/ship/data/injections/valley_textures.bin index 123b722a9..901eded51 100644 Binary files a/data/ship/data/injections/valley_textures.bin and b/data/ship/data/injections/valley_textures.bin differ diff --git a/docs/showcase/console.webp b/docs/showcase/console.webp new file mode 100644 index 000000000..e93414eb5 Binary files /dev/null and b/docs/showcase/console.webp differ diff --git a/docs/showcase/skybox.jpg b/docs/showcase/skybox.jpg new file mode 100644 index 000000000..f12b66a98 Binary files /dev/null and b/docs/showcase/skybox.jpg differ diff --git a/src/config.h b/src/config.h index 7b5ee4a8a..73d6db69b 100644 --- a/src/config.h +++ b/src/config.h @@ -90,6 +90,7 @@ typedef struct { TARGET_LOCK_MODE target_mode; bool enable_loading_screens; bool fix_animated_sprites; + bool enable_skybox; struct { int32_t layout; diff --git a/src/config_map.def b/src/config_map.def index 236f6b014..c2e9c6834 100644 --- a/src/config_map.def +++ b/src/config_map.def @@ -103,3 +103,4 @@ CFG_DOUBLE(ui.text_scale, DEFAULT_UI_SCALE) CFG_DOUBLE(ui.bar_scale, DEFAULT_UI_SCALE) CFG_BOOL(profile.new_game_plus_unlock, false) CFG_BOOL(fix_animated_sprites, true) +CFG_BOOL(enable_skybox, true) diff --git a/src/game/inject.c b/src/game/inject.c index a23e5745a..cd2923aeb 100644 --- a/src/game/inject.c +++ b/src/game/inject.c @@ -18,7 +18,7 @@ #include #define INJECTION_MAGIC MKTAG('T', '1', 'M', 'J') -#define INJECTION_CURRENT_VERSION 6 +#define INJECTION_CURRENT_VERSION 7 typedef enum INJECTION_VERSION { INJ_VERSION_1 = 1, @@ -27,6 +27,7 @@ typedef enum INJECTION_VERSION { INJ_VERSION_4 = 4, INJ_VERSION_5 = 5, INJ_VERSION_6 = 6, + INJ_VERSION_7 = 7, } INJECTION_VERSION; typedef enum INJECTION_TYPE { @@ -40,6 +41,7 @@ typedef enum INJECTION_TYPE { INJ_ITEM_POSITION = 7, INJ_PS1_ENEMY = 8, INJ_DISABLE_ANIM_SPRITE = 9, + INJ_SKYBOX = 10, } INJECTION_TYPE; typedef struct INJECTION { @@ -95,7 +97,7 @@ typedef enum FLOOR_EDIT_TYPE { typedef enum ROOM_MESH_EDIT_TYPE { RMET_TEXTURE_FACE = 0, RMET_MOVE_FACE = 1, - RMET_MOVE_VERTEX = 2, + RMET_ALTER_VERTEX = 2, RMET_ROTATE_FACE = 3, RMET_ADD_FACE = 4, RMET_ADD_VERTEX = 5, @@ -143,7 +145,7 @@ static void Inject_TriggeredItem(INJECTION *injection, LEVEL_INFO *level_info); static void Inject_RoomMeshEdits(INJECTION *injection); static void Inject_TextureRoomFace(INJECTION *injection); static void Inject_MoveRoomFace(INJECTION *injection); -static void Inject_MoveRoomVertex(INJECTION *injection); +static void Inject_AlterRoomVertex(INJECTION *injection); static void Inject_RotateRoomFace(INJECTION *injection); static void Inject_AddRoomFace(INJECTION *injection); static void Inject_AddRoomVertex(INJECTION *injection); @@ -231,6 +233,9 @@ static void Inject_LoadFromFile(INJECTION *injection, const char *filename) case INJ_DISABLE_ANIM_SPRITE: injection->relevant = !g_Config.fix_animated_sprites; break; + case INJ_SKYBOX: + injection->relevant = g_Config.enable_skybox; + break; default: LOG_WARNING("%s is of unknown type %d", filename, injection->type); break; @@ -1456,8 +1461,8 @@ static void Inject_RoomMeshEdits(INJECTION *injection) case RMET_MOVE_FACE: Inject_MoveRoomFace(injection); break; - case RMET_MOVE_VERTEX: - Inject_MoveRoomVertex(injection); + case RMET_ALTER_VERTEX: + Inject_AlterRoomVertex(injection); break; case RMET_ROTATE_FACE: Inject_RotateRoomFace(injection); @@ -1531,7 +1536,7 @@ static void Inject_MoveRoomFace(INJECTION *injection) } } -static void Inject_MoveRoomVertex(INJECTION *injection) +static void Inject_AlterRoomVertex(INJECTION *injection) { MYFILE *fp = injection->fp; @@ -1540,6 +1545,7 @@ static void Inject_MoveRoomVertex(INJECTION *injection) int16_t x_change; int16_t y_change; int16_t z_change; + int16_t shade_change; File_Read(&target_room, sizeof(int16_t), 1, fp); File_Skip(fp, sizeof(int32_t)); @@ -1547,24 +1553,30 @@ static void Inject_MoveRoomVertex(INJECTION *injection) File_Read(&x_change, sizeof(int16_t), 1, fp); File_Read(&y_change, sizeof(int16_t), 1, fp); File_Read(&z_change, sizeof(int16_t), 1, fp); + if (injection->version >= INJ_VERSION_7) { + File_Read(&shade_change, sizeof(int16_t), 1, fp); + } else { + shade_change = 0; + } if (target_room < 0 || target_room >= g_RoomCount) { LOG_WARNING("Room index %d is invalid", target_room); return; } - ROOM_INFO *r = &g_RoomInfo[target_room]; - int16_t vertex_count = *r->data; + const ROOM_INFO *const room = &g_RoomInfo[target_room]; + const int16_t vertex_count = *room->data; if (target_vertex < 0 || target_vertex >= vertex_count) { LOG_WARNING( "Vertex index %d, room %d is invalid", target_vertex, target_room); return; } - int16_t *data_ptr = r->data + target_vertex * 4; + int16_t *const data_ptr = room->data + target_vertex * 4; *(data_ptr + 1) += x_change; *(data_ptr + 2) += y_change; *(data_ptr + 3) += z_change; + *(data_ptr + 4) += shade_change; } static void Inject_RotateRoomFace(INJECTION *injection) diff --git a/src/game/level.c b/src/game/level.c index 12fd18e38..7756217b0 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -1,5 +1,6 @@ #include "game/level.h" +#include "config.h" #include "game/camera.h" #include "game/carrier.h" #include "game/effects.h" @@ -1007,6 +1008,9 @@ bool Level_Load(int level_num) : g_GameFlow.draw_distance_max) * WALL_L); + Output_SetSkyboxEnabled( + g_Config.enable_skybox && g_Objects[O_SKYBOX].loaded); + return ret; } diff --git a/src/game/output.c b/src/game/output.c index d90a32ae9..7ffd2217a 100644 --- a/src/game/output.c +++ b/src/game/output.c @@ -32,6 +32,7 @@ typedef struct { } edges[2]; } LIGHTNING; +static bool m_IsSkyboxEnabled = false; static bool m_IsWibbleEffect = false; static bool m_IsWaterEffect = false; static bool m_IsShadeEffect = false; @@ -74,6 +75,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_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); static void Output_CalcWibbleTable(void); @@ -201,21 +203,29 @@ static const int16_t *Output_CalcObjectVertices(const int16_t *obj_ptr) obj_ptr++; int vertex_count = *obj_ptr++; for (int i = 0; i < vertex_count; i++) { - double xv = g_MatrixPtr->_00 * obj_ptr[0] - + g_MatrixPtr->_01 * obj_ptr[1] + g_MatrixPtr->_02 * obj_ptr[2] - + g_MatrixPtr->_03; - double yv = g_MatrixPtr->_10 * obj_ptr[0] - + g_MatrixPtr->_11 * obj_ptr[1] + g_MatrixPtr->_12 * obj_ptr[2] - + g_MatrixPtr->_13; - int32_t zv_int = g_MatrixPtr->_20 * obj_ptr[0] - + g_MatrixPtr->_21 * obj_ptr[1] + g_MatrixPtr->_22 * obj_ptr[2] - + g_MatrixPtr->_23; - double zv = zv_int; + // clang-format off + double xv = + g_MatrixPtr->_00 * obj_ptr[0] + + g_MatrixPtr->_01 * obj_ptr[1] + + g_MatrixPtr->_02 * obj_ptr[2] + + g_MatrixPtr->_03; + double yv = + g_MatrixPtr->_10 * obj_ptr[0] + + g_MatrixPtr->_11 * obj_ptr[1] + + g_MatrixPtr->_12 * obj_ptr[2] + + g_MatrixPtr->_13; + double zv = + g_MatrixPtr->_20 * obj_ptr[0] + + g_MatrixPtr->_21 * obj_ptr[1] + + g_MatrixPtr->_22 * obj_ptr[2] + + g_MatrixPtr->_23; + // clang-format on + m_VBuf[i].xv = xv; m_VBuf[i].yv = yv; m_VBuf[i].zv = zv; - int32_t clip_flags; + int16_t clip_flags; if (zv < Output_GetNearZ()) { clip_flags = -32768; } else { @@ -293,6 +303,23 @@ static const int16_t *Output_CalcVerticeLight(const int16_t *obj_ptr) return obj_ptr; } +static const int16_t *Output_CalcSkyboxLight(const int16_t *obj_ptr) +{ + int32_t vertex_count = *obj_ptr++; + if (vertex_count > 0) { + obj_ptr += 3 * vertex_count; + } else { + vertex_count = -vertex_count; + obj_ptr += vertex_count; + } + + for (int i = 0; i < vertex_count; i++) { + m_VBuf[i].g = 0xFFF; + } + + return obj_ptr; +} + static const int16_t *Output_CalcRoomVertices(const int16_t *obj_ptr) { int32_t vertex_count = *obj_ptr++; @@ -320,7 +347,9 @@ static const int16_t *Output_CalcRoomVertices(const int16_t *obj_ptr) int32_t depth = zv_int >> W2V_SHIFT; if (depth > Output_GetDrawDistMax()) { m_VBuf[i].g = 0x1FFF; - clip_flags |= 16; + if (!m_IsSkyboxEnabled) { + clip_flags |= 16; + } } else if (depth) { m_VBuf[i].g += Output_CalcFogShade(depth); if (!m_IsWaterEffect) { @@ -594,6 +623,37 @@ void Output_DrawPolygons_I(const int16_t *obj_ptr, int32_t clip) Matrix_Pop(); } +void Output_SetSkyboxEnabled(const bool enabled) +{ + m_IsSkyboxEnabled = enabled; +} + +bool Output_IsSkyboxEnabled(void) +{ + return m_IsSkyboxEnabled; +} + +void Output_DrawSkybox(const int16_t *obj_ptr) +{ + g_PhdLeft = Viewport_GetMinX(); + g_PhdTop = Viewport_GetMinY(); + g_PhdRight = Viewport_GetMaxX(); + g_PhdBottom = Viewport_GetMaxY(); + + obj_ptr = Output_CalcObjectVertices(obj_ptr + 4); + if (!obj_ptr) { + return; + } + + S_Output_DisableDepthTest(); + obj_ptr = Output_CalcSkyboxLight(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); + S_Output_EnableDepthTest(); +} + void Output_DrawRoom(const int16_t *obj_ptr) { obj_ptr = Output_CalcRoomVertices(obj_ptr); diff --git a/src/game/output.h b/src/game/output.h index 6a70cfa8d..722479f62 100644 --- a/src/game/output.h +++ b/src/game/output.h @@ -49,6 +49,10 @@ void Output_CalculateObjectLighting( void Output_DrawPolygons(const int16_t *obj_ptr, int clip); void Output_DrawPolygons_I(const int16_t *obj_ptr, int32_t clip); +void Output_SetSkyboxEnabled(bool enabled); +bool Output_IsSkyboxEnabled(void); +void Output_DrawSkybox(const int16_t *obj_ptr); + void Output_DrawRoom(const int16_t *obj_ptr); void Output_DrawShadow( int16_t size, const BOUNDS_16 *bounds, const ITEM_INFO *item); diff --git a/src/game/room_draw.c b/src/game/room_draw.c index 8769d844a..086527c72 100644 --- a/src/game/room_draw.c +++ b/src/game/room_draw.c @@ -22,6 +22,7 @@ static void Room_PrintDrawStack(void); static bool Room_SetBounds(const DOOR_INFO *door, const ROOM_INFO *parent); static void Room_GetBounds(int16_t room_num); static void Room_PrepareToDraw(int16_t room_num); +static void Room_DrawSkybox(void); static void Room_PrintDrawStack(void) { @@ -203,6 +204,7 @@ void Room_DrawAllRooms(int16_t base_room, int16_t target_room) Room_PrepareToDraw(base_room); Room_PrepareToDraw(target_room); + Room_DrawSkybox(); for (int i = 0; i < g_RoomsToDrawCount; i++) { Room_DrawSingleRoom(g_RoomsToDraw[i]); @@ -248,6 +250,26 @@ static void Room_PrepareToDraw(int16_t room_num) Matrix_Pop(); } +static void Room_DrawSkybox(void) +{ + if (!Output_IsSkyboxEnabled()) { + return; + } + + Output_SetupAboveWater(g_Camera.underwater); + Matrix_Push(); + g_MatrixPtr->_03 = 0; + g_MatrixPtr->_13 = 0; + g_MatrixPtr->_23 = 0; + + const OBJECT_INFO skybox = g_Objects[O_SKYBOX]; + const FRAME_INFO *const frame = g_Anims[skybox.anim_index].frame_ptr; + Matrix_RotYXZpack(frame->mesh_rots[0]); + Output_DrawSkybox(g_Meshes[skybox.mesh_index]); + + Matrix_Pop(); +} + void Room_DrawSingleRoom(int16_t room_num) { bool camera_underwater = diff --git a/src/global/types.h b/src/global/types.h index 3a1435034..7586ef7ed 100644 --- a/src/global/types.h +++ b/src/global/types.h @@ -209,7 +209,7 @@ typedef enum GAME_OBJECT_ID { O_BIG_POD = 181, O_BOAT = 182, O_EARTHQUAKE = 183, - O_TEMP5 = 184, + O_SKYBOX = 184, O_TEMP6 = 185, O_TEMP7 = 186, O_TEMP8 = 187, diff --git a/src/specific/s_output.c b/src/specific/s_output.c index a933a6538..6fda93376 100644 --- a/src/specific/s_output.c +++ b/src/specific/s_output.c @@ -20,6 +20,9 @@ #include #define CLIP_VERTCOUNT_SCALE 4 +#define VBUF_VISIBLE(a, b, c) \ + (((a).ys - (b).ys) * ((c).xs - (b).xs) \ + >= ((c).ys - (b).ys) * ((a).xs - (b).xs)) #define S_Output_CheckError(result) \ { \ @@ -333,62 +336,40 @@ static int32_t S_Output_VisibleZClip( static int32_t S_Output_ZedClipper( int32_t vertex_count, POINT_INFO *pts, GFX_3D_Vertex *vertices) { - int32_t count; - POINT_INFO *pts0; - POINT_INFO *pts1; - GFX_3D_Vertex *v; - float clip; + const float multiplier = g_Config.brightness / 16.0f; + const float near_z = Output_GetNearZ(); + const float persp_o_near_z = g_PhdPersp / near_z; - float multiplier = g_Config.brightness / 16.0f; - float near_z = Output_GetNearZ(); - float persp_o_near_z = g_PhdPersp / near_z; - - v = &vertices[0]; - pts0 = &pts[vertex_count - 1]; + GFX_3D_Vertex *v = &vertices[0]; + POINT_INFO *pts0 = &pts[0]; + POINT_INFO *pts1 = &pts[vertex_count - 1]; for (int i = 0; i < vertex_count; i++) { - pts1 = pts0; - pts0 = &pts[i]; - if (near_z > pts1->zv) { - if (near_z > pts0->zv) { - continue; - } + int32_t diff0 = near_z - pts0->zv; + int32_t diff1 = near_z - pts1->zv; + if ((diff0 | diff1) >= 0) { + goto loop_end; + } - clip = (near_z - pts0->zv) / (pts1->zv - pts0->zv); - v->x = ((pts1->xv - pts0->xv) * clip + pts0->xv) * persp_o_near_z + if ((diff0 ^ diff1) < 0) { + double clip = diff0 / (pts1->zv - pts0->zv); + v->x = (pts0->xv + (pts1->xv - pts0->xv) * clip) * persp_o_near_z + Viewport_GetCenterX(); - v->y = ((pts1->yv - pts0->yv) * clip + pts0->yv) * persp_o_near_z + v->y = (pts0->yv + (pts1->yv - pts0->yv) * clip) * persp_o_near_z + Viewport_GetCenterY(); v->z = near_z * 0.0001f; v->w = 65536.0f / near_z; - v->s = v->w * ((pts1->u - pts0->u) * clip + pts0->u) / 256.0f; - v->t = v->w * ((pts1->v - pts0->v) * clip + pts0->v) / 256.0f; + v->s = v->w * (pts0->u + (pts1->u - pts0->u) * clip) / 256.0f; + v->t = v->w * (pts0->v + (pts1->v - pts0->v) * clip) / 256.0f; v->r = v->g = v->b = - (8192.0f - ((pts1->g - pts0->g) * clip + pts0->g)) * multiplier; + (8192.0f - (pts0->g + (pts1->g - pts0->g) * clip)) * multiplier; Output_ApplyWaterEffect(&v->r, &v->g, &v->b); v++; } - if (near_z > pts0->zv) { - clip = (near_z - pts0->zv) / (pts1->zv - pts0->zv); - v->x = ((pts1->xv - pts0->xv) * clip + pts0->xv) * persp_o_near_z - + Viewport_GetCenterX(); - v->y = ((pts1->yv - pts0->yv) * clip + pts0->yv) * persp_o_near_z - + Viewport_GetCenterY(); - v->z = near_z * 0.0001f; - - v->w = 65536.0f / near_z; - v->s = v->w * ((pts1->u - pts0->u) * clip + pts0->u) / 256.0f; - v->t = v->w * ((pts1->v - pts0->v) * clip + pts0->v) / 256.0f; - - v->r = v->g = v->b = - (8192.0f - ((pts1->g - pts0->g) * clip + pts0->g)) * multiplier; - Output_ApplyWaterEffect(&v->r, &v->g, &v->b); - - v++; - } else { + if (diff0 < 0) { v->x = pts0->xs; v->y = pts0->ys; v->z = pts0->zv * 0.0001f; @@ -402,9 +383,12 @@ static int32_t S_Output_ZedClipper( v++; } + + loop_end: + pts1 = pts0++; } - count = v - vertices; + const int32_t count = v - vertices; return count < 3 ? 0 : count; } @@ -943,50 +927,67 @@ void S_Output_DrawFlatTriangle( { int vertex_count = 3; GFX_3D_Vertex vertices[vertex_count * CLIP_VERTCOUNT_SCALE]; - float light; + PHD_VBUF *src_vbuf[3]; + + src_vbuf[0] = vn1; + src_vbuf[1] = vn2; + src_vbuf[2] = vn3; - if (!((vn3->clip & vn2->clip & vn1->clip) == 0 && vn1->clip >= 0 - && vn2->clip >= 0 && vn3->clip >= 0 - && (vn1->ys - vn2->ys) * (vn3->xs - vn2->xs) - - (vn3->ys - vn2->ys) * (vn1->xs - vn2->xs) - >= 0)) { + if (vn3->clip & vn2->clip & vn1->clip) { return; } float multiplier = g_Config.brightness / (16.0f * 255.0f); - - light = (8192.0f - vn1->g) * multiplier; - vertices[0].x = vn1->xs; - vertices[0].y = vn1->ys; - vertices[0].z = vn1->zv * 0.0001f; - vertices[0].r = color.r * light; - vertices[0].g = color.g * light; - vertices[0].b = color.b * light; - - light = (8192.0f - vn2->g) * multiplier; - vertices[1].x = vn2->xs; - vertices[1].y = vn2->ys; - vertices[1].z = vn2->zv * 0.0001f; - vertices[1].r = color.r * light; - vertices[1].g = color.g * light; - vertices[1].b = color.b * light; - - light = (8192.0f - vn3->g) * multiplier; - vertices[2].x = vn3->xs; - vertices[2].y = vn3->ys; - vertices[2].z = vn3->zv * 0.0001f; - vertices[2].r = color.r * light; - vertices[2].g = color.g * light; - vertices[2].b = color.b * light; - for (int i = 0; i < vertex_count; i++) { + vertices[i].x = src_vbuf[i]->xs; + vertices[i].y = src_vbuf[i]->ys; + vertices[i].z = src_vbuf[i]->zv * 0.0001f; + const float light = (8192.0f - src_vbuf[i]->g) * multiplier; + vertices[i].r = color.r * light; + vertices[i].g = color.g * light; + vertices[i].b = color.b * light; + Output_ApplyWaterEffect(&vertices[i].r, &vertices[i].g, &vertices[i].b); } - if (vn1->clip || vn2->clip || vn3->clip) { + if ((vn1->clip | vn2->clip | vn3->clip) >= 0) { + if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) { + return; + } + + if (vn1->clip || vn2->clip || vn3->clip) { + vertex_count = S_Output_ClipVertices( + vertices, vertex_count, sizeof(vertices) / sizeof(vertices[0])); + } + } else { + if (!S_Output_VisibleZClip(vn1, vn2, vn3)) { + return; + } + + POINT_INFO points[3]; + for (int i = 0; i < vertex_count; i++) { + points[i].xv = src_vbuf[i]->xv; + points[i].yv = src_vbuf[i]->yv; + points[i].zv = src_vbuf[i]->zv; + points[i].xs = src_vbuf[i]->xs; + points[i].ys = src_vbuf[i]->ys; + points[i].g = src_vbuf[i]->g; + } + + vertex_count = S_Output_ZedClipper(vertex_count, points, vertices); + if (!vertex_count) { + return; + } + for (int i = 0; i < vertex_count; i++) { + vertices[i].r *= color.r / 255.0f; + vertices[i].g *= color.g / 255.0f; + vertices[i].b *= color.b / 255.0f; + } + vertex_count = S_Output_ClipVertices( vertices, vertex_count, sizeof(vertices) / sizeof(vertices[0])); } + if (!vertex_count) { return; } @@ -1019,9 +1020,7 @@ void S_Output_DrawTexturedTriangle( } if (vn1->clip >= 0 && vn2->clip >= 0 && vn3->clip >= 0) { - if ((vn1->ys - vn2->ys) * (vn3->xs - vn2->xs) - - (vn3->ys - vn2->ys) * (vn1->xs - vn2->xs) - < 0) { + if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) { return; } @@ -1101,9 +1100,7 @@ void S_Output_DrawTexturedQuad( if (vn1->clip >= 0 && vn2->clip >= 0 && vn3->clip >= 0 && vn4->clip >= 0) { - if ((vn1->ys - vn2->ys) * (vn3->xs - vn2->xs) - - (vn3->ys - vn2->ys) * (vn1->xs - vn2->xs) - < 0) { + if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) { return; } } else if (!S_Output_VisibleZClip(vn1, vn2, vn3)) { @@ -1117,9 +1114,7 @@ void S_Output_DrawTexturedQuad( return; } - if ((vn1->ys - vn2->ys) * (vn3->xs - vn2->xs) - - (vn3->ys - vn2->ys) * (vn1->xs - vn2->xs) - < 0) { + if (!VBUF_VISIBLE(*vn1, *vn2, *vn3)) { return; } diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/en.json b/tools/config/TR1X_ConfigTool/Resources/Lang/en.json index fc471680e..81f604ea5 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/en.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/en.json @@ -321,6 +321,10 @@ "Title": "Resolution height", "Description": "Overrides game resolution. See notes on Resolution Width." }, + "enable_skybox": { + "Title": "Skybox", + "Description": "Enables the skybox in supported levels." + }, "enable_braid": { "Title": "Braid", "Description": "Enables Lara's braid." diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/es.json b/tools/config/TR1X_ConfigTool/Resources/Lang/es.json index 2c4d1bc2e..8856bcdec 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/es.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/es.json @@ -145,6 +145,10 @@ "Title": "Recogidas en 3D", "Description": "Permite que los modelos en 3D se representen en lugar de los sprites para los objetos a recoger." }, + "enable_skybox": { + "Title": "Cielo", + "Description": "Habilita el cielo en niveles soportados." + }, "enable_braid": { "Title": "Trenza", "Description": "Habilita la trenza de Lara." diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/fr.json b/tools/config/TR1X_ConfigTool/Resources/Lang/fr.json index decca5241..5f233549f 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/fr.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/fr.json @@ -321,6 +321,10 @@ "Title": "Hauteur de résolution", "Description": "Remplace la résolution du jeu. Voir les notes sur la largeur de résolution." }, + "enable_skybox": { + "Title": "Ciel", + "Description": "Active le ciel dans les niveaux pris en charge." + }, "enable_braid": { "Title": "Tresse de Lara", "Description": "Active la tresse de Lara." diff --git a/tools/config/TR1X_ConfigTool/Resources/Lang/it.json b/tools/config/TR1X_ConfigTool/Resources/Lang/it.json index f4fac7b10..78e6b9189 100644 --- a/tools/config/TR1X_ConfigTool/Resources/Lang/it.json +++ b/tools/config/TR1X_ConfigTool/Resources/Lang/it.json @@ -321,6 +321,10 @@ "Title": "Altezza risoluzione", "Description": "Sostituisce la risoluzione del gioco. Osserva le note dell'opzione 'Larghezza risoluzione'." }, + "enable_skybox": { + "Title": "Cielo", + "Description": "Abilita il cielo nei livelli supportati." + }, "enable_braid": { "Title": "Treccia", "Description": "Abilita la treccia di Lara." diff --git a/tools/config/TR1X_ConfigTool/Resources/specification.json b/tools/config/TR1X_ConfigTool/Resources/specification.json index e6bb00857..b909a9a38 100644 --- a/tools/config/TR1X_ConfigTool/Resources/specification.json +++ b/tools/config/TR1X_ConfigTool/Resources/specification.json @@ -379,6 +379,11 @@ "DefaultValue": -1, "MinimumValue": -1 }, + { + "Field": "enable_skybox", + "DataType": "Bool", + "DefaultValue": true + }, { "Field": "enable_braid", "DataType": "Bool",