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:
lahm86 2024-07-20 11:57:15 +01:00 committed by GitHub
parent 59c584cecf
commit faf07b6c17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 250 additions and 107 deletions

View file

@ -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)

View file

@ -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>

View file

@ -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

View file

@ -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": [

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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 =

View file

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

View file

@ -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;
}

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -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."

View file

@ -379,6 +379,11 @@
"DefaultValue": -1,
"MinimumValue": -1
},
{
"Field": "enable_skybox",
"DataType": "Bool",
"DefaultValue": true
},
{
"Field": "enable_braid",
"DataType": "Bool",