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",
|