mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
parent
2819ea18ea
commit
57cedf1fc8
8 changed files with 213 additions and 95 deletions
|
@ -7,6 +7,7 @@
|
|||
- added the ability to skip FMVs with the action key (#1650)
|
||||
- added the ability to hold forward/back to move through menus more quickly (#1644)
|
||||
- added optional rendering of pickups in the UI as 3D meshes (#1633)
|
||||
- added optional rendering of pickups on the ground as 3D meshes (#1634)
|
||||
- changed the inputs backend from DirectX to SDL (#1695)
|
||||
- improved controller support to match TR1X
|
||||
- changed the number of custom layouts to 3
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
#include "game/items.h"
|
||||
#include "game/lara/misc.h"
|
||||
#include "game/matrix.h"
|
||||
#include "global/funcs.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
#include <libtrx/utils.h>
|
||||
|
||||
OBJECT *Object_GetObject(GAME_OBJECT_ID object_id)
|
||||
{
|
||||
return &g_Objects[object_id];
|
||||
|
@ -45,3 +48,83 @@ void __cdecl Object_Collision_Trap(
|
|||
Object_Collision(item_num, lara_item, coll);
|
||||
}
|
||||
}
|
||||
|
||||
BOUNDS_16 Object_GetBoundingBox(
|
||||
const OBJECT *const obj, const FRAME_INFO *const frame)
|
||||
{
|
||||
int16_t **mesh_ptrs = &g_Meshes[obj->mesh_idx];
|
||||
int32_t *bone = &g_AnimBones[obj->bone_idx];
|
||||
const int16_t *mesh_rots = frame->mesh_rots;
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_TranslateRel(frame->offset.x, frame->offset.y, frame->offset.z);
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
|
||||
BOUNDS_16 new_bounds = {
|
||||
.min_x = 0x7FFF,
|
||||
.min_y = 0x7FFF,
|
||||
.min_z = 0x7FFF,
|
||||
.max_x = -0x7FFF,
|
||||
.max_y = -0x7FFF,
|
||||
.max_z = -0x7FFF,
|
||||
};
|
||||
|
||||
for (int32_t mesh_idx = 0; mesh_idx < obj->mesh_count; mesh_idx++) {
|
||||
if (mesh_idx != 0) {
|
||||
int32_t bone_extra_flags = *bone;
|
||||
if (bone_extra_flags & BF_MATRIX_POP) {
|
||||
Matrix_Pop();
|
||||
}
|
||||
|
||||
if (bone_extra_flags & BF_MATRIX_PUSH) {
|
||||
Matrix_Push();
|
||||
}
|
||||
|
||||
Matrix_TranslateRel(bone[1], bone[2], bone[3]);
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
bone += 4;
|
||||
}
|
||||
|
||||
const int16_t *obj_ptr = mesh_ptrs[mesh_idx];
|
||||
obj_ptr += 5;
|
||||
const int32_t vtx_count = *obj_ptr++;
|
||||
for (int32_t i = 0; i < vtx_count; i++) {
|
||||
// clang-format off
|
||||
const MATRIX *const mptr = g_MatrixPtr;
|
||||
const double xv = (
|
||||
mptr->_00 * obj_ptr[0] +
|
||||
mptr->_01 * obj_ptr[1] +
|
||||
mptr->_02 * obj_ptr[2] +
|
||||
mptr->_03
|
||||
);
|
||||
const double yv = (
|
||||
mptr->_10 * obj_ptr[0] +
|
||||
mptr->_11 * obj_ptr[1] +
|
||||
mptr->_12 * obj_ptr[2] +
|
||||
mptr->_13
|
||||
);
|
||||
double zv = (
|
||||
mptr->_20 * obj_ptr[0] +
|
||||
mptr->_21 * obj_ptr[1] +
|
||||
mptr->_22 * obj_ptr[2] +
|
||||
mptr->_23
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
const int32_t x = ((int32_t)xv) >> W2V_SHIFT;
|
||||
const int32_t y = ((int32_t)yv) >> W2V_SHIFT;
|
||||
const int32_t z = ((int32_t)zv) >> W2V_SHIFT;
|
||||
|
||||
new_bounds.min_x = MIN(new_bounds.min_x, x);
|
||||
new_bounds.min_y = MIN(new_bounds.min_y, y);
|
||||
new_bounds.min_z = MIN(new_bounds.min_z, z);
|
||||
new_bounds.max_x = MAX(new_bounds.max_x, x);
|
||||
new_bounds.max_y = MAX(new_bounds.max_y, y);
|
||||
new_bounds.max_z = MAX(new_bounds.max_z, z);
|
||||
obj_ptr += 3;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix_Pop();
|
||||
return new_bounds;
|
||||
}
|
||||
|
|
|
@ -11,3 +11,5 @@ void __cdecl Object_Collision(
|
|||
|
||||
void __cdecl Object_Collision_Trap(
|
||||
int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
BOUNDS_16 Object_GetBoundingBox(const OBJECT *obj, const FRAME_INFO *frame);
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
#include "game/objects/general/pickup.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "game/gameflow.h"
|
||||
#include "game/gun/gun.h"
|
||||
#include "game/input.h"
|
||||
#include "game/inventory/backpack.h"
|
||||
#include "game/inventory/common.h"
|
||||
#include "game/items.h"
|
||||
#include "game/lara/control.h"
|
||||
#include "game/lara/misc.h"
|
||||
#include "game/matrix.h"
|
||||
#include "game/objects/common.h"
|
||||
#include "game/output.h"
|
||||
#include "game/overlay.h"
|
||||
#include "game/room.h"
|
||||
#include "global/funcs.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
|
@ -66,8 +72,7 @@ static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
|||
item->rot.z = 0;
|
||||
|
||||
if (!Item_TestPosition(g_PickupBounds, item, lara_item)) {
|
||||
item->rot = old_rot;
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (lara_item->current_anim_state == LS_PICKUP) {
|
||||
|
@ -75,7 +80,7 @@ static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
|||
== g_Anims[LA_PICKUP].frame_base + LF_PICKUP_ERASE) {
|
||||
M_DoPickup(item_num);
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (lara_item->current_anim_state == LS_FLARE_PICKUP) {
|
||||
|
@ -85,7 +90,7 @@ static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
|||
&& g_Lara.gun_type != LGT_FLARE) {
|
||||
M_DoFlarePickup(item_num);
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (g_Input.action && !lara_item->gravity
|
||||
|
@ -108,9 +113,10 @@ static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
|||
lara_item->goal_anim_state = LS_STOP;
|
||||
g_Lara.gun_status = LGS_HANDS_BUSY;
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
item->rot = old_rot;
|
||||
}
|
||||
|
||||
|
@ -124,8 +130,7 @@ static void M_DoUnderwater(const int16_t item_num, ITEM *const lara_item)
|
|||
item->rot.z = 0;
|
||||
|
||||
if (!Item_TestPosition(g_PickupBoundsUW, item, lara_item)) {
|
||||
item->rot = old_rot;
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (lara_item->current_anim_state == LS_PICKUP) {
|
||||
|
@ -133,7 +138,7 @@ static void M_DoUnderwater(const int16_t item_num, ITEM *const lara_item)
|
|||
== g_Anims[LA_UNDERWATER_PICKUP].frame_base + LF_PICKUP_UW) {
|
||||
M_DoPickup(item_num);
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (lara_item->current_anim_state == LS_FLARE_PICKUP) {
|
||||
|
@ -145,14 +150,14 @@ static void M_DoUnderwater(const int16_t item_num, ITEM *const lara_item)
|
|||
M_DoFlarePickup(item_num);
|
||||
Flare_DrawMeshes();
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (g_Input.action && lara_item->current_anim_state == LS_TREAD
|
||||
&& g_Lara.gun_status == LGS_ARMLESS
|
||||
&& (g_Lara.gun_type != LGT_FLARE || item->object_id != O_FLARE_ITEM)) {
|
||||
if (!Lara_MovePosition(&g_PickupPositionUW, item, lara_item)) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (item->object_id == O_FLARE_ITEM) {
|
||||
|
@ -168,9 +173,10 @@ static void M_DoUnderwater(const int16_t item_num, ITEM *const lara_item)
|
|||
} while (lara_item->current_anim_state != LS_PICKUP);
|
||||
lara_item->goal_anim_state = LS_TREAD;
|
||||
}
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
item->rot = old_rot;
|
||||
}
|
||||
|
||||
|
@ -179,11 +185,107 @@ void Pickup_Setup(OBJECT *const obj)
|
|||
// TODO: change this to Pickup_Collision after we decompile
|
||||
// both comparisons in ExtractSaveGameInfo() and GetCarriedItems()
|
||||
obj->collision = (void *)0x00437E70;
|
||||
obj->draw_routine = Object_DrawSpriteItem;
|
||||
obj->draw_routine = Pickup_Draw;
|
||||
obj->save_position = 1;
|
||||
obj->save_flags = 1;
|
||||
}
|
||||
|
||||
void Pickup_Draw(const ITEM *const item)
|
||||
{
|
||||
if (!g_Config.visuals.enable_3d_pickups) {
|
||||
Object_DrawSpriteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_Objects[item->object_id].loaded) {
|
||||
Object_DrawSpriteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert item to menu display item.
|
||||
const GAME_OBJECT_ID inv_object_id = Inv_GetItemOption(item->object_id);
|
||||
const OBJECT *const obj = Object_GetObject(inv_object_id);
|
||||
if (!obj->loaded || obj->mesh_count < 0) {
|
||||
Object_DrawSpriteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the first frame of the first animation, and its bounding box.
|
||||
const FRAME_INFO *frame = (const FRAME_INFO *)obj->frame_base;
|
||||
const BOUNDS_16 bounds = Object_GetBoundingBox(obj, frame);
|
||||
|
||||
// First - Is there floor under the item?
|
||||
// This is mostly true, but for example the 4 items in the Obelisk of
|
||||
// Khamoon the 4 items are sitting on top of a static mesh which is not
|
||||
// floor.
|
||||
int16_t room_num = item->room_num;
|
||||
const SECTOR *const sector =
|
||||
Room_GetSector(item->pos.x, item->pos.y, item->pos.z, &room_num);
|
||||
const int16_t floor_height =
|
||||
Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
int16_t offset;
|
||||
if (item->pos.y == floor_height) {
|
||||
// Is the floor "just below" the item? Take the position from the anim.
|
||||
offset =
|
||||
floor_height - frame->offset.y - (bounds.max_y - bounds.min_y) / 2;
|
||||
} else {
|
||||
// Otherwise leave it as-is.
|
||||
offset = item->pos.y;
|
||||
}
|
||||
|
||||
Matrix_Push();
|
||||
Matrix_TranslateAbs(item->pos.x, offset, item->pos.z);
|
||||
Matrix_RotYXZ(item->rot.y, item->rot.x, item->rot.z);
|
||||
|
||||
S_CalculateLight(item->pos.x, item->pos.y, item->pos.z, item->room_num);
|
||||
|
||||
const int32_t clip = S_GetObjectBounds(&frame->bounds);
|
||||
if (clip) {
|
||||
// From this point on the function is a slightly customised version
|
||||
// of the code in DrawAnimatingItem starting with the line that
|
||||
// matches the following line.
|
||||
int32_t bit = 1;
|
||||
int16_t **meshpp = &g_Meshes[obj->mesh_idx];
|
||||
int32_t *bone = &g_AnimBones[obj->bone_idx];
|
||||
|
||||
Matrix_TranslateRel(frame->offset.x, frame->offset.y, frame->offset.z);
|
||||
|
||||
const int16_t *mesh_rots = frame->mesh_rots;
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
|
||||
if (item->mesh_bits & bit) {
|
||||
Output_InsertPolygons(*meshpp++, clip);
|
||||
}
|
||||
|
||||
for (int i = 1; i < obj->mesh_count; i++) {
|
||||
int32_t bone_extra_flags = *bone;
|
||||
if (bone_extra_flags & BF_MATRIX_POP) {
|
||||
Matrix_Pop();
|
||||
}
|
||||
|
||||
if (bone_extra_flags & BF_MATRIX_PUSH) {
|
||||
Matrix_Push();
|
||||
}
|
||||
|
||||
Matrix_TranslateRel(bone[1], bone[2], bone[3]);
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
|
||||
// Extra rotation is ignored in this case as it's not needed.
|
||||
|
||||
bit <<= 1;
|
||||
if (item->mesh_bits & bit) {
|
||||
Output_InsertPolygons(*meshpp, clip);
|
||||
}
|
||||
|
||||
bone += 4;
|
||||
meshpp++;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix_Pop();
|
||||
}
|
||||
|
||||
void __cdecl Pickup_Collision(
|
||||
const int16_t item_num, ITEM *const lara_item, COLL_INFO *const coll)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
void Pickup_Setup(OBJECT *obj);
|
||||
|
||||
void Pickup_Draw(const ITEM *item);
|
||||
|
||||
void __cdecl Pickup_Collision(
|
||||
int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "game/inventory/common.h"
|
||||
#include "game/matrix.h"
|
||||
#include "game/music.h"
|
||||
#include "game/objects/common.h"
|
||||
#include "game/output.h"
|
||||
#include "game/text.h"
|
||||
#include "game/viewport.h"
|
||||
|
@ -71,88 +72,6 @@ static float M_Ease(const int32_t cur_frame, const int32_t max_frames)
|
|||
return result;
|
||||
}
|
||||
|
||||
static BOUNDS_16 M_GetBounds(
|
||||
const OBJECT *const obj, const FRAME_INFO *const frame)
|
||||
{
|
||||
int16_t **mesh_ptrs = &g_Meshes[obj->mesh_idx];
|
||||
int32_t *bone = &g_AnimBones[obj->bone_idx];
|
||||
const int16_t *mesh_rots = frame->mesh_rots;
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_TranslateRel(frame->offset.x, frame->offset.y, frame->offset.z);
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
|
||||
BOUNDS_16 new_bounds = {
|
||||
.min_x = 0x7FFF,
|
||||
.min_y = 0x7FFF,
|
||||
.min_z = 0x7FFF,
|
||||
.max_x = -0x7FFF,
|
||||
.max_y = -0x7FFF,
|
||||
.max_z = -0x7FFF,
|
||||
};
|
||||
|
||||
for (int32_t mesh_idx = 0; mesh_idx < obj->mesh_count; mesh_idx++) {
|
||||
if (mesh_idx != 0) {
|
||||
int32_t bone_extra_flags = *bone;
|
||||
if (bone_extra_flags & BF_MATRIX_POP) {
|
||||
Matrix_Pop();
|
||||
}
|
||||
|
||||
if (bone_extra_flags & BF_MATRIX_PUSH) {
|
||||
Matrix_Push();
|
||||
}
|
||||
|
||||
Matrix_TranslateRel(bone[1], bone[2], bone[3]);
|
||||
Matrix_RotYXZsuperpack(&mesh_rots, 0);
|
||||
bone += 4;
|
||||
}
|
||||
|
||||
const int16_t *obj_ptr = mesh_ptrs[mesh_idx];
|
||||
obj_ptr += 5;
|
||||
const int32_t vtx_count = *obj_ptr++;
|
||||
for (int32_t i = 0; i < vtx_count; i++) {
|
||||
PHD_VBUF *const vbuf = &g_PhdVBuf[i];
|
||||
|
||||
// clang-format off
|
||||
const MATRIX *const mptr = g_MatrixPtr;
|
||||
const double xv = (
|
||||
mptr->_00 * obj_ptr[0] +
|
||||
mptr->_01 * obj_ptr[1] +
|
||||
mptr->_02 * obj_ptr[2] +
|
||||
mptr->_03
|
||||
);
|
||||
const double yv = (
|
||||
mptr->_10 * obj_ptr[0] +
|
||||
mptr->_11 * obj_ptr[1] +
|
||||
mptr->_12 * obj_ptr[2] +
|
||||
mptr->_13
|
||||
);
|
||||
double zv = (
|
||||
mptr->_20 * obj_ptr[0] +
|
||||
mptr->_21 * obj_ptr[1] +
|
||||
mptr->_22 * obj_ptr[2] +
|
||||
mptr->_23
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
const int32_t x = ((int32_t)xv) >> W2V_SHIFT;
|
||||
const int32_t y = ((int32_t)yv) >> W2V_SHIFT;
|
||||
const int32_t z = ((int32_t)zv) >> W2V_SHIFT;
|
||||
|
||||
new_bounds.min_x = MIN(new_bounds.min_x, x);
|
||||
new_bounds.min_y = MIN(new_bounds.min_y, y);
|
||||
new_bounds.min_z = MIN(new_bounds.min_z, z);
|
||||
new_bounds.max_x = MAX(new_bounds.max_x, x);
|
||||
new_bounds.max_y = MAX(new_bounds.max_y, y);
|
||||
new_bounds.max_z = MAX(new_bounds.max_z, z);
|
||||
obj_ptr += 3;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix_Pop();
|
||||
return new_bounds;
|
||||
}
|
||||
|
||||
bool __cdecl Overlay_FlashCounter(const int32_t ticks)
|
||||
{
|
||||
if (m_FlashCounter > 0) {
|
||||
|
@ -457,7 +376,7 @@ static void M_DrawPickup3D(const DISPLAY_PICKUP *const pickup)
|
|||
if (frame->bounds.min_x == frame->bounds.max_x
|
||||
&& frame->bounds.min_y == frame->bounds.max_y) {
|
||||
// fix broken collision box for the prayer wheel
|
||||
bounds = M_GetBounds(obj, frame);
|
||||
bounds = Object_GetBoundingBox(obj, frame);
|
||||
}
|
||||
|
||||
const int32_t scale = 1280;
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
}
|
||||
},
|
||||
"Properties": {
|
||||
"enable_3d_pickups": {
|
||||
"Title": "3D pickups",
|
||||
"Description": "Enables 3D models to be rendered in place of the sprites for pickup items."
|
||||
},
|
||||
"enable_cheats": {
|
||||
"Title": "Cheats",
|
||||
"Description": "Enables various cheats:\n- L: immediately end the level.\n- I: give Lara all weapons; a boost of ammo and medipacks; and all plot items for the current level.\n- O: enable DOZY cheat (swimming midair).\n - WALK key: exit DOZY.\n - GUN key: open the closest door (doesn't work in certain places)."
|
||||
|
|
|
@ -46,6 +46,11 @@
|
|||
"ID": "graphics",
|
||||
"Image": "Graphics/graphic5.jpg",
|
||||
"Properties": [
|
||||
{
|
||||
"Field": "enable_3d_pickups",
|
||||
"DataType": "Bool",
|
||||
"DefaultValue": true
|
||||
},
|
||||
{
|
||||
"Field": "screenshot_format",
|
||||
"DataType": "Enum",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue