mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-05-06 19:01:18 +03:00
draw: add 3d pickups
This commit is contained in:
parent
3b2664bfc4
commit
8631b0902f
8 changed files with 217 additions and 5 deletions
|
@ -163,6 +163,9 @@
|
|||
// Overrides ingame brightness.
|
||||
"brightness": 1.0,
|
||||
|
||||
// Enable round shadow instead of the default octagon one.
|
||||
// Enables round shadow instead of the default octagon one.
|
||||
"enable_round_shadow": true,
|
||||
|
||||
// Enables 3D models to be rendered in place of the sprites for pickup items
|
||||
"enable_3d_pickups" : true,
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ int8_t T1MReadConfigFromJson(const char *cfg_data)
|
|||
READ_BOOL(enable_xbox_one_controller, 0);
|
||||
READ_FLOAT(brightness, 1.0);
|
||||
READ_BOOL(enable_round_shadow, 1);
|
||||
READ_BOOL(enable_3d_pickups, 1);
|
||||
|
||||
READ_BAR_SHOWING_MODE(healthbar_showing_mode, T1M_BSM_FLASHING_OR_DEFAULT);
|
||||
READ_BAR_SHOWING_MODE(airbar_showing_mode, T1M_BSM_DEFAULT);
|
||||
|
|
|
@ -70,6 +70,7 @@ typedef struct {
|
|||
int8_t enable_xbox_one_controller;
|
||||
float brightness;
|
||||
int8_t enable_round_shadow;
|
||||
int8_t enable_3d_pickups;
|
||||
} T1MConfigStruct;
|
||||
|
||||
extern T1MConfigStruct T1MConfig;
|
||||
|
|
206
src/game/draw.c
206
src/game/draw.c
|
@ -2,14 +2,19 @@
|
|||
|
||||
#include "3dsystem/3d_gen.h"
|
||||
#include "3dsystem/scalespr.h"
|
||||
#include "config.h"
|
||||
#include "game/control.h"
|
||||
#include "game/game.h"
|
||||
#include "game/hair.h"
|
||||
#include "game/health.h"
|
||||
#include "game/inv.h"
|
||||
#include "global/const.h"
|
||||
#include "global/vars.h"
|
||||
#include "specific/output.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static int16_t InterpolatedBounds[6];
|
||||
|
||||
int32_t DrawPhaseCinematic()
|
||||
|
@ -343,6 +348,207 @@ void DrawDummyItem(ITEM_INFO *item)
|
|||
{
|
||||
}
|
||||
|
||||
void DrawPickupItem(ITEM_INFO *item)
|
||||
{
|
||||
if (!T1MConfig.enable_3d_pickups) {
|
||||
DrawSpriteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert item to menu display item.
|
||||
int16_t item_num_option = Inv_GetItemOption(item->object_number);
|
||||
// Save the frame number.
|
||||
int16_t old_frame_number = item->frame_number;
|
||||
// Modify item to be the anim for inv item and animation 0.
|
||||
item->anim_number = Objects[item_num_option].anim_index;
|
||||
item->frame_number = Anims[item->anim_number].frame_base;
|
||||
|
||||
OBJECT_INFO *object = &Objects[item_num_option];
|
||||
|
||||
int16_t *frmptr[2];
|
||||
int32_t rate;
|
||||
int32_t frac = GetFrames(item, frmptr, &rate);
|
||||
|
||||
// Restore the old frame number in case we need to get the sprite again.
|
||||
item->frame_number = old_frame_number;
|
||||
|
||||
// Fall back to normal sprite rendering if not found.
|
||||
if (object->nmeshes < 0) {
|
||||
DrawSpriteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Good news is there is a mesh, we just need to work out where to put it
|
||||
|
||||
// First - Is there floor under the item?
|
||||
// This is mostly true, but for example the 4 items in the Obelisk of
|
||||
// Kharmoon the 4 items are sitting ontop of a static mesh which is not
|
||||
// floor.
|
||||
FLOOR_INFO *floor =
|
||||
GetFloor(item->pos.x, item->pos.y, item->pos.z, &item->room_number);
|
||||
int16_t floor_height =
|
||||
GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
// Assume this is our offset.
|
||||
int16_t offset = floor_height;
|
||||
// Is the floor "just below" the item?
|
||||
int16_t floor_mapped_delta = abs(floor_height - item->pos.y);
|
||||
if (floor_mapped_delta > WALL_L / 4 || floor_mapped_delta == 0) {
|
||||
// No, now we need to move it a bit.
|
||||
// First get the sprite that was to be used,
|
||||
|
||||
int16_t spr_num =
|
||||
Objects[item->object_number].mesh_index - item->frame_number;
|
||||
PHD_SPRITE *sprite = &PhdSpriteInfo[spr_num];
|
||||
|
||||
// and get the animation bounding box, which is not the mesh one.
|
||||
int16_t min_y = frmptr[0][FRAME_BOUND_MIN_Y];
|
||||
int16_t max_y = frmptr[0][FRAME_BOUND_MAX_Y];
|
||||
int16_t anim_y = frmptr[0][FRAME_POS_Y];
|
||||
|
||||
// Sifferent objects need different heuristics.
|
||||
switch (item_num_option) {
|
||||
case O_GUN_OPTION:
|
||||
case O_SHOTGUN_OPTION:
|
||||
case O_MAGNUM_OPTION:
|
||||
case O_UZI_OPTION:
|
||||
case O_MAG_AMMO_OPTION:
|
||||
case O_UZI_AMMO_OPTION:
|
||||
case O_EXPLOSIVE_OPTION:
|
||||
case O_LEADBAR_OPTION:
|
||||
case O_PICKUP_OPTION1:
|
||||
case O_PICKUP_OPTION2:
|
||||
case O_SCION_OPTION:
|
||||
// Ignore the sprite and just position based upon the anim.
|
||||
offset = item->pos.y + (min_y - anim_y) / 2;
|
||||
break;
|
||||
case O_MEDI_OPTION:
|
||||
case O_BIGMEDI_OPTION:
|
||||
case O_SG_AMMO_OPTION:
|
||||
case O_PUZZLE_OPTION1:
|
||||
case O_PUZZLE_OPTION2:
|
||||
case O_PUZZLE_OPTION3:
|
||||
case O_PUZZLE_OPTION4:
|
||||
case O_KEY_OPTION1:
|
||||
case O_KEY_OPTION2:
|
||||
case O_KEY_OPTION3:
|
||||
case O_KEY_OPTION4: {
|
||||
// Take the difference from the bottom of the sprite and the bottom
|
||||
// of the animation and divide it by 8.
|
||||
// 8 was chosen because in testing it positioned objects correctly.
|
||||
// Specifically the 4 items in the Obelisk of Kharmoon and keys.
|
||||
// Some objects have a centred mesh and some have one that is from
|
||||
// the bottom, for the centred ones; move up from the
|
||||
// bottom is necessary.
|
||||
int centred = abs(min_y + max_y) < 8;
|
||||
if (floor_mapped_delta) {
|
||||
offset = item->pos.y - abs(min_y - sprite->y1) / 8;
|
||||
} else if (centred) {
|
||||
offset = item->pos.y + min_y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
phd_PushMatrix();
|
||||
phd_TranslateAbs(item->pos.x, offset, item->pos.z);
|
||||
|
||||
int16_t *frame = &object->frame_base[(object->nmeshes * 2 + 10)];
|
||||
CalculateObjectLighting(item, frame);
|
||||
|
||||
int32_t x = (PhdMatrixPtr->_03 >> W2V_SHIFT) + item->pos.x;
|
||||
int32_t y = (PhdMatrixPtr->_13 >> W2V_SHIFT) + item->pos.y;
|
||||
int32_t z = (PhdMatrixPtr->_23 >> W2V_SHIFT) + item->pos.z;
|
||||
S_CalculateLight(x, y, z, item->room_number);
|
||||
|
||||
int32_t clip = S_GetObjectBounds(frame);
|
||||
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 = &Meshes[object->mesh_index];
|
||||
int32_t *bone = &AnimBones[object->bone_index];
|
||||
|
||||
if (!frac) {
|
||||
phd_TranslateRel(
|
||||
frmptr[0][FRAME_POS_X], frmptr[0][FRAME_POS_Y],
|
||||
frmptr[0][FRAME_POS_Z]);
|
||||
|
||||
int32_t *packed_rotation = (int32_t *)(frmptr[0] + FRAME_ROT);
|
||||
phd_RotYXZpack(*packed_rotation++);
|
||||
|
||||
if (item->mesh_bits & bit) {
|
||||
phd_PutPolygons(*meshpp++, clip);
|
||||
}
|
||||
|
||||
for (int i = 1; i < object->nmeshes; i++) {
|
||||
int32_t bone_extra_flags = *bone;
|
||||
if (bone_extra_flags & BEB_POP) {
|
||||
phd_PopMatrix();
|
||||
}
|
||||
|
||||
if (bone_extra_flags & BEB_PUSH) {
|
||||
phd_PushMatrix();
|
||||
}
|
||||
|
||||
phd_TranslateRel(bone[1], bone[2], bone[3]);
|
||||
phd_RotYXZpack(*packed_rotation++);
|
||||
|
||||
// Extra rotation is ignored in this case as it's not needed.
|
||||
|
||||
bit <<= 1;
|
||||
if (item->mesh_bits & bit) {
|
||||
phd_PutPolygons(*meshpp, clip);
|
||||
}
|
||||
|
||||
bone += 4;
|
||||
meshpp++;
|
||||
}
|
||||
} else {
|
||||
// This should never happen but is here "just in case".
|
||||
InitInterpolate(frac, rate);
|
||||
phd_TranslateRel_ID(
|
||||
frmptr[0][FRAME_POS_X], frmptr[0][FRAME_POS_Y],
|
||||
frmptr[0][FRAME_POS_Z], frmptr[1][FRAME_POS_X],
|
||||
frmptr[1][FRAME_POS_Y], frmptr[1][FRAME_POS_Z]);
|
||||
int32_t *packed_rotation1 = (int32_t *)(frmptr[0] + FRAME_ROT);
|
||||
int32_t *packed_rotation2 = (int32_t *)(frmptr[1] + FRAME_ROT);
|
||||
phd_RotYXZpack_I(*packed_rotation1++, *packed_rotation2++);
|
||||
|
||||
if (item->mesh_bits & bit) {
|
||||
phd_PutPolygons_I(*meshpp++, clip);
|
||||
}
|
||||
|
||||
for (int i = 1; i < object->nmeshes; i++) {
|
||||
int32_t bone_extra_flags = *bone;
|
||||
if (bone_extra_flags & BEB_POP) {
|
||||
phd_PopMatrix_I();
|
||||
}
|
||||
|
||||
if (bone_extra_flags & BEB_PUSH) {
|
||||
phd_PushMatrix_I();
|
||||
}
|
||||
|
||||
phd_TranslateRel_I(bone[1], bone[2], bone[3]);
|
||||
phd_RotYXZpack_I(*packed_rotation1++, *packed_rotation2++);
|
||||
|
||||
// Extra rotation is ignored in this case as it's not needed.
|
||||
|
||||
bit <<= 1;
|
||||
if (item->mesh_bits & bit) {
|
||||
phd_PutPolygons_I(*meshpp, clip);
|
||||
}
|
||||
|
||||
bone += 4;
|
||||
meshpp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
phd_PopMatrix();
|
||||
}
|
||||
|
||||
void DrawAnimatingItem(ITEM_INFO *item)
|
||||
{
|
||||
static int16_t null_rotation[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
|
|
@ -14,6 +14,7 @@ void PrintRooms(int16_t room_number);
|
|||
void DrawEffect(int16_t fxnum);
|
||||
void DrawSpriteItem(ITEM_INFO *item);
|
||||
void DrawDummyItem(ITEM_INFO *item);
|
||||
void DrawPickupItem(ITEM_INFO *item);
|
||||
void DrawAnimatingItem(ITEM_INFO *item);
|
||||
void DrawUnclippedItem(ITEM_INFO *item);
|
||||
void DrawLara(ITEM_INFO *item);
|
||||
|
|
|
@ -21,7 +21,7 @@ void SetupMovingBar(OBJECT_INFO *obj)
|
|||
|
||||
void SetupLeadBar(OBJECT_INFO *obj)
|
||||
{
|
||||
obj->draw_routine = DrawSpriteItem;
|
||||
obj->draw_routine = DrawPickupItem;
|
||||
obj->collision = PickUpCollision;
|
||||
obj->save_flags = 1;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ int16_t PickUpBoundsUW[12] = {
|
|||
|
||||
void SetupPickupObject(OBJECT_INFO *obj)
|
||||
{
|
||||
obj->draw_routine = DrawSpriteItem;
|
||||
obj->draw_routine = DrawPickupItem;
|
||||
obj->collision = PickUpCollision;
|
||||
obj->save_flags = 1;
|
||||
}
|
||||
|
|
|
@ -46,13 +46,13 @@ int16_t PickUpScion4Bounds[12] = {
|
|||
|
||||
void SetupScion1(OBJECT_INFO *obj)
|
||||
{
|
||||
Objects[O_SCION_ITEM].draw_routine = DrawSpriteItem;
|
||||
Objects[O_SCION_ITEM].draw_routine = DrawPickupItem;
|
||||
Objects[O_SCION_ITEM].collision = PickUpScionCollision;
|
||||
}
|
||||
|
||||
void SetupScion2(OBJECT_INFO *obj)
|
||||
{
|
||||
Objects[O_SCION_ITEM2].draw_routine = DrawSpriteItem;
|
||||
Objects[O_SCION_ITEM2].draw_routine = DrawPickupItem;
|
||||
Objects[O_SCION_ITEM2].collision = PickUpCollision;
|
||||
Objects[O_SCION_ITEM2].save_flags = 1;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue