Skip to content

Commit

Permalink
output: add skybox support (#1414)
Browse files Browse the repository at this point in the history
This adds support for skybox rendering similar to TR2. A default
injection is provided for Lost Valley, Colossuem and Obelisk of
Khamoon; custom level builders can use object slot 184.

Resolves #94.
  • Loading branch information
lahm86 authored Jul 20, 2024
1 parent 59c584c commit faf07b6
Show file tree
Hide file tree
Showing 25 changed files with 250 additions and 107 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
8 changes: 8 additions & 0 deletions GAMEFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,14 @@ provided with the game achieves.
using the 3D pickups option.
</td>
</tr>
<tr valign="top">
<td>
<code>*_skybox.bin</code>
</td>
<td>
Injects a predefined skybox model into specific levels.
</td>
</tr>
<tr valign="top">
<td>
<code>*_textures.bin</code>
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,24 @@ topic](https://www.tombraiderforums.com/showthread.php?p=8286101).
</th>
</tr>
<tr>
<th>
Skybox support
<img src="docs/showcase/skybox.jpg"/>
</th>
<th>
Customizable draw distance
<img src="docs/showcase/draw_distance.webp"/>
</th>
</tr>
<tr>
<th>
Fly cheat
<img src="docs/showcase/fly_cheat.jpg"/>
</th>
<th>
Developer console
<img src="docs/showcase/console.webp"/>
</th>
</tr>
<tr>
<th>
Expand Down Expand Up @@ -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
Expand All @@ -565,15 +576,15 @@ 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
- **Palace Midas**: incorrect textures in rooms 31, 34, 40 and 45, missing textures in rooms 2, 5, 9, 13, 30, and 53, and stretched textures in rooms 7 and 20
- **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
Expand Down
3 changes: 3 additions & 0 deletions data/ship/cfg/TR1X_gameflow.json5
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"music": 57,
"injections": [
"data/injections/valley_itemrots.bin",
"data/injections/valley_skybox.bin",
"data/injections/valley_textures.bin",
],
"sequence": [
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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": [
Expand Down
Binary file added data/ship/data/injections/colosseum_skybox.bin
Binary file not shown.
Binary file added data/ship/data/injections/obelisk_skybox.bin
Binary file not shown.
Binary file modified data/ship/data/injections/obelisk_textures.bin
Binary file not shown.
Binary file added data/ship/data/injections/valley_skybox.bin
Binary file not shown.
Binary file modified data/ship/data/injections/valley_textures.bin
Binary file not shown.
Binary file added docs/showcase/console.webp
Binary file not shown.
Binary file added docs/showcase/skybox.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/config_map.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
30 changes: 21 additions & 9 deletions src/game/inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <stddef.h>

#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,
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -1540,31 +1545,38 @@ 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));
File_Read(&target_vertex, sizeof(int16_t), 1, fp);
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)
Expand Down
4 changes: 4 additions & 0 deletions src/game/level.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "game/level.h"

#include "config.h"
#include "game/camera.h"
#include "game/carrier.h"
#include "game/effects.h"
Expand Down Expand Up @@ -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;
}

Expand Down
84 changes: 72 additions & 12 deletions src/game/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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++;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/game/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit faf07b6

Please sign in to comment.