mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
output: add skybox support (#1414)
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.
This commit is contained in:
parent
59c584cecf
commit
faf07b6c17
25 changed files with 250 additions and 107 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
15
README.md
15
README.md
|
@ -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>
|
||||
|
@ -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
|
||||
|
|
|
@ -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": [
|
||||
|
|
BIN
data/ship/data/injections/colosseum_skybox.bin
Normal file
BIN
data/ship/data/injections/colosseum_skybox.bin
Normal file
Binary file not shown.
BIN
data/ship/data/injections/obelisk_skybox.bin
Normal file
BIN
data/ship/data/injections/obelisk_skybox.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
data/ship/data/injections/valley_skybox.bin
Normal file
BIN
data/ship/data/injections/valley_skybox.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/showcase/console.webp
Normal file
BIN
docs/showcase/console.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
BIN
docs/showcase/skybox.jpg
Normal file
BIN
docs/showcase/skybox.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 195 KiB |
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#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];
|
||||
|
||||
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)) {
|
||||
src_vbuf[0] = vn1;
|
||||
src_vbuf[1] = vn2;
|
||||
src_vbuf[2] = vn3;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -379,6 +379,11 @@
|
|||
"DefaultValue": -1,
|
||||
"MinimumValue": -1
|
||||
},
|
||||
{
|
||||
"Field": "enable_skybox",
|
||||
"DataType": "Bool",
|
||||
"DefaultValue": true
|
||||
},
|
||||
{
|
||||
"Field": "enable_braid",
|
||||
"DataType": "Bool",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue