1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-10 23:24:06 +02:00

GBA fix akill textures, sprites drawing, swimming states, animated textures, follow and static camera logic, pickups, underwater caustics. objects logic (GYM, LEVEL1, LEVEL2)

This commit is contained in:
XProger
2021-06-29 02:23:42 +03:00
parent 4ecd12da37
commit f55d0543fe
20 changed files with 3710 additions and 1053 deletions

View File

@@ -30,6 +30,7 @@
<ClInclude Include="draw.h" />
<ClInclude Include="enemy.h" />
<ClInclude Include="game.h" />
<ClInclude Include="inventory.h" />
<ClInclude Include="item.h" />
<ClInclude Include="lara.h" />
<ClInclude Include="level.h" />
@@ -146,6 +147,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -166,6 +168,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@@ -3,18 +3,22 @@
#include "common.h"
#define CAM_SPEED (1 << 3)
#define CAM_ROT_SPEED (1 << 9)
#define CAM_ROT_X_MAX int16(85 * 0x8000 / 180)
#define CAM_DIST_FOLLOW (1024 + 512)
#define CAM_SPEED (1 << 3)
#define CAM_ROT_SPEED (1 << 9)
#define CAM_DIST_FOLLOW (1024 + 512)
#define CAMERA_ANGLE_FOLLOW -10 * DEG2SHORT
#define CAMERA_ANGLE_MAX 85 * DEG2SHORT
#define CAMERA_TRACE_SHIFT 3
#define CAMERA_TRACE_STEPS (1 << CAMERA_TRACE_SHIFT)
enum CameraMode
{
CAMERA_MODE_FREE = 0,
CAMERA_MODE_FOLLOW = 1,
CAMERA_MODE_COMBAT = 2,
CAMERA_MODE_FIXED = 3,
CAMERA_MODE_OBJECT = 4,
CAMERA_MODE_FREE,
CAMERA_MODE_FOLLOW,
CAMERA_MODE_COMBAT,
CAMERA_MODE_LOOK,
CAMERA_MODE_FIXED,
CAMERA_MODE_OBJECT,
};
struct Camera
@@ -27,37 +31,63 @@ struct Camera
Location view;
Location target;
int32 targetDist;
int16 targetAngleX;
int16 targetAngleY;
int16 targetDist;
int16 angleX;
int16 angleY;
AABB frustumBase;
Item* item;
Item* laraItem;
Item* lastItem;
Item* lookAtItem;
int32 speed;
int32 timer;
int32 index;
int32 lastIndex;
CameraMode mode;
bool modeSwitch;
void init()
bool modeSwitch;
bool lastFixed;
bool center;
void init(Item* lara)
{
item = NULL;
mode = CAMERA_MODE_FOLLOW;
modeSwitch = false;
target.pos = lara->pos;
target.pos.y -= 1024;
target.room = lara->room;
view = target;
view.pos.z -= 100;
angleX = 0;
angleY = 0;
view.pos = vec3i(0);
target.pos = view.pos;
targetDist = CAM_DIST_FOLLOW;
targetAngleX = 0;
targetAngleY = 0;
targetDist = CAM_DIST_FOLLOW;
laraItem = lara;
lastItem = NULL;
lookAtItem = NULL;
speed = 1;
timer = 0;
index = -1;
lastIndex = -1;
mode = CAMERA_MODE_FOLLOW;
modeSwitch = false;
lastFixed = false;
center = false;
}
void freeControl()
void updateFree()
{
matrixSetView(view.pos, angleX, angleY);
@@ -68,7 +98,7 @@ struct Camera
if (keys & IK_LEFT) angleY -= CAM_ROT_SPEED;
if (keys & IK_RIGHT) angleY += CAM_ROT_SPEED;
angleX = X_CLAMP(angleX, -CAM_ROT_X_MAX, CAM_ROT_X_MAX);
angleX = X_CLAMP(angleX, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX);
if (keys & IK_A)
{
@@ -133,6 +163,166 @@ struct Camera
return true;
}
bool trace(const Location &from, Location &to, int32 radius)
{
vec3i d = to.pos - from.pos;
d.x >>= CAMERA_TRACE_SHIFT;
d.y >>= CAMERA_TRACE_SHIFT;
d.z >>= CAMERA_TRACE_SHIFT;
Room* room = from.room;
vec3i pos = from.pos;
int32 i;
for (i = 0; i < CAMERA_TRACE_STEPS; i++)
{
if (radius)
{
to.pos = pos;
to.room = room;
}
pos += d;
room = room->getRoom(pos.x, pos.y, pos.z);
const Sector* sector = room->getSector(pos.x, pos.z);
int32 floor = sector->getFloor(pos.x, pos.y, pos.z);
int32 ceiling = sector->getCeiling(pos.x, pos.y, pos.z);
if (floor == WALL || ceiling == WALL || ceiling >= floor)
{
return false;
}
int32 h = pos.y - floor;
if (h > 0)
{
if (h >= radius) {
return false;
}
pos.y = floor;
}
h = ceiling - pos.y;
if (h > 0)
{
if (h >= radius) {
return false;
}
pos.y = ceiling;
}
}
to.pos = pos;
to.room = room;
return true;
}
Location getLocationForAngle(int32 angle, int32 distH, int32 distV)
{
Location res;
res.pos.x = target.pos.x - (distH * phd_sin(angle) >> FIXED_SHIFT);
res.pos.y = target.pos.y + (distV);
res.pos.z = target.pos.z - (distH * phd_cos(angle) >> FIXED_SHIFT);
res.room = target.room;
return res;
}
Location getBestLocation(Item* item)
{
int32 distH = targetDist * phd_cos(targetAngleX) >> FIXED_SHIFT;
int32 distV = targetDist * phd_sin(targetAngleX) >> FIXED_SHIFT;
Location best = getLocationForAngle(targetAngleY + item->angle.y, distH, distV);
if (trace(target, best, 200))
return best;
int32 distQ = X_SQR(target.pos.x - best.pos.x) + X_SQR(target.pos.z - best.pos.z);
if (distQ > X_SQR(768))
return best;
int32 minDistQ = INT_MAX;
for (int32 i = 0; i < 4; i++)
{
Location tmp = getLocationForAngle(i * ANGLE_90, distH, distV);
if (!trace(target, tmp, 200) || !trace(tmp, view, 0)) {
continue;
}
distQ = X_SQR(view.pos.x - tmp.pos.x) + X_SQR(view.pos.z - tmp.pos.z);
if (distQ < minDistQ)
{
minDistQ = distQ;
best = tmp;
}
}
return best;
}
void move(const Location &to, int32 speed)
{
vec3i d = to.pos - view.pos;
if (speed > 1)
{
d.x /= speed;
d.y /= speed;
d.z /= speed;
}
view.pos += d;
view.room = to.room->getRoom(view.pos.x, view.pos.y, view.pos.z);
}
void updateFollow(Item* item)
{
if (targetAngleX == 0) {
targetAngleX = CAMERA_ANGLE_FOLLOW;
}
targetAngleX = X_CLAMP(targetAngleX + item->angle.x, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX);
Location best = getBestLocation(item);
move(best, lastFixed ? speed : 12);
}
void updateCombat()
{
//
}
void updateLook()
{
//
}
void updateFixed()
{
const FixedCamera* cam = cameras + index;
Location best;
best.pos = cam->pos;
best.room = rooms + cam->roomIndex;
lastFixed = true;
move(best, 1);
if (timer != 0)
{
timer--;
if (timer == 0) {
timer = -1;
}
}
}
void update()
{
if (keys & IK_START)
@@ -152,51 +342,98 @@ struct Camera
if (mode == CAMERA_MODE_FREE)
{
freeControl();
}
if (mode == CAMERA_MODE_FOLLOW && item)
{
int32 tx = item->pos.x;
int32 ty = item->pos.y;
int32 tz = item->pos.z;
const Bounds &box = item->getBoundingBox();
ty += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
target.pos.x = tx;
target.pos.y += (ty - target.pos.y) >> 2;
target.pos.z = tz;
int16 angle = item->angle.y + targetAngleY;
int32 dy = targetDist * phd_sin(targetAngleX) >> FIXED_SHIFT;
int32 dz = targetDist * phd_cos(targetAngleX) >> FIXED_SHIFT;
int32 cx = target.pos.x - (phd_sin(angle) * dz >> FIXED_SHIFT);
int32 cy = target.pos.y - 256 + dy;
int32 cz = target.pos.z - (phd_cos(angle) * dz >> FIXED_SHIFT);
view.pos.x += (cx - view.pos.x) >> 2;
view.pos.y += (cy - view.pos.y) >> 2;
view.pos.z += (cz - view.pos.z) >> 2;
updateFree();
prepareFrustum();
matrixSetView(view.pos, angleX, angleY);
updateRoom();
vec3i dir = target.pos - view.pos;
anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY);
return;
}
bool isFixed = false;
Item* item = laraItem;
if (lookAtItem && (mode == CAMERA_MODE_FIXED || mode == CAMERA_MODE_OBJECT))
{
isFixed = true;
item = lookAtItem;
}
ASSERT(item);
target.room = item->room;
const Bounds &box = item->getBoundingBox();
int32 y = item->pos.y;
if (isFixed) {
y += (box.minY + box.maxY) >> 1;
} else {
y += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
}
if (mode == CAMERA_MODE_LOOK || mode == CAMERA_MODE_COMBAT)
{
y -= 256;
if (lastFixed) {
target.pos.y = 0;
speed = 1;
} else {
target.pos.y += (y - target.pos.y) >> 2;
speed = (mode == CAMERA_MODE_LOOK) ? 4 : 8;
}
} else {
target.pos.x = item->pos.x;
target.pos.z = item->pos.z;
if (center)
{
int32 offset = (box.minZ + box.maxZ) >> 1;
target.pos.x += (phd_sin(item->angle.y) * offset) >> FIXED_SHIFT;
target.pos.z += (phd_cos(item->angle.y) * offset) >> FIXED_SHIFT;
}
lastFixed ^= isFixed;
if (lastFixed) {
target.pos.y = y;
speed = 1;
} else {
target.pos.y += (y - target.pos.y) >> 2;
}
}
switch (mode)
{
case CAMERA_MODE_FOLLOW : updateFollow(item); break;
case CAMERA_MODE_COMBAT : updateCombat(); break;
case CAMERA_MODE_LOOK : updateLook(); break;
default : updateFixed();
}
lastFixed = isFixed;
lastIndex = index;
if (mode != CAMERA_MODE_OBJECT || timer == -1)
{
mode = CAMERA_MODE_FOLLOW;
index = -1;
lastItem = lookAtItem;
lookAtItem = NULL;
targetAngleX = 0;
targetAngleY = 0;
targetDist = CAM_DIST_FOLLOW;
center = false;
}
vec3i dir = target.pos - view.pos;
anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY);
prepareFrustum();
matrixSetView(view.pos, angleX, angleY);
updateRoom();
// reset additional angles, Lara states can override it during the update proc
targetAngleX = 0;
targetAngleY = 0;
targetDist = CAM_DIST_FOLLOW;
}
void prepareFrustum()

View File

@@ -47,7 +47,7 @@ struct CollisionInfo
vec3i pos;
int16 angle;
int16 quadrant;
uint16 quadrant;
CollisionType type;
@@ -132,8 +132,8 @@ bool collideStatic(Room* room, CollisionInfo &cinfo, const vec3i &p, int32 heigh
{
const RoomMesh* mesh = room->data.meshes + i;
#ifdef NO_STATIC_MESHES
if (mesh->id != STATIC_MESH_GATE) continue;
#ifdef NO_STATIC_MESH_PLANTS
if (mesh->id < 10) continue;
#endif
const StaticMesh* staticMesh = staticMeshes + mesh->id;
@@ -191,8 +191,8 @@ bool collideStatic(Room* room, CollisionInfo &cinfo, const vec3i &p, int32 heigh
void collideRoom(Item* item, int32 height, int32 yOffset = 0)
{
cinfo.type = CT_NONE;
cinfo.offset = vec3i(0, 0, 0);
cinfo.type = CT_NONE;
cinfo.offset = vec3i(0, 0, 0);
vec3i p = item->pos;
p.y += yOffset;
@@ -203,8 +203,10 @@ void collideRoom(Item* item, int32 height, int32 yOffset = 0)
int32 floor, ceiling;
Room* room = item->room;
#define CHECK_HEIGHT(v) {\
const Room* room = item->room->getRoom(v.x, cy, v.z);\
room = room->getRoom(v.x, cy, v.z);\
const Sector* sector = room->getSector(v.x, v.z);\
floor = sector->getFloor(v.x, cy, v.z);\
if (floor != WALL) floor -= p.y;\

View File

@@ -12,6 +12,31 @@ EWRAM_DATA SaveGame gSaveGame;
const FloorData* gLastFloorData;
FloorData gLastFloorSlant;
int32 rand_seed_ctrl;
int32 rand_seed_draw;
void set_seed_ctrl(int32 seed)
{
rand_seed_ctrl = seed;
}
void set_seed_draw(int32 seed)
{
rand_seed_draw = seed;
}
#define X_RAND(seed) (((seed = 0x3039 + seed * 0x41C64E6D) >> 10) & 0x7FFF);
int16 rand_ctrl()
{
return X_RAND(rand_seed_ctrl);
}
int16 rand_draw()
{
return X_RAND(rand_seed_draw);
}
const uint16 divTable[DIV_TABLE_SIZE] = { // ROM, not a big difference with IWRAM
0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492,
0x2000, 0x1C71, 0x1999, 0x1745, 0x1555, 0x13B1, 0x1249, 0x1111,
@@ -805,7 +830,9 @@ void matrixFrame(const vec3i &pos, uint16* angles)
matrixRotateYXZ(angleX, angleY, angleZ);
}
#define LERP_FAST(a, b, mul, div) a = (a + b) >> 1
#define LERP_1(a, b, mul, div) a = (b + a) >> 1
#define LERP_2(a, b, mul, div) a = a + ((b - a) >> 2)
#define LERP_3(a, b, mul, div) a = b - ((b - a) >> 2)
#define LERP_SLOW(a, b, mul, div) a = a + (b - a) * mul / div
#define LERP_ROW(lerp_func, a, b, mul, div) \
@@ -818,15 +845,23 @@ void matrixLerp(const Matrix &n, int32 multiplier, int32 divider)
{
Matrix &m = matrixGet();
if (divider == 2) {
LERP_ROW(LERP_FAST, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_FAST, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_FAST, m[2], n[2], multiplier, divider);
if ((divider == 2) || ((divider == 4) && (multiplier == 2))) {
LERP_ROW(LERP_1, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_1, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_1, m[2], n[2], multiplier, divider);
} else if (multiplier == 1) {
LERP_ROW(LERP_2, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_2, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_2, m[2], n[2], multiplier, divider);
} else {
LERP_ROW(LERP_SLOW, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_SLOW, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_SLOW, m[2], n[2], multiplier, divider);
LERP_ROW(LERP_3, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_3, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_3, m[2], n[2], multiplier, divider);
}
//LERP_ROW(LERP_SLOW, m[0], n[0], multiplier, divider);
//LERP_ROW(LERP_SLOW, m[1], n[1], multiplier, divider);
//LERP_ROW(LERP_SLOW, m[2], n[2], multiplier, divider);
}
void matrixSetIdentity()

View File

@@ -29,7 +29,7 @@
//#define DEBUG_OVERDRAW
#endif
#define NO_STATIC_MESHES
#define NO_STATIC_MESH_PLANTS
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
@@ -98,8 +98,6 @@
#define ALIGN16 __attribute__((aligned(16)))
#endif
#define UNUSED(x) (void)(x)
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
@@ -149,6 +147,9 @@ typedef int16 Index;
extern uint16 fb[VRAM_WIDTH * FRAME_HEIGHT];
#endif
// system
int32 osGetSystemTimeMS();
#ifdef PROFILE
#if defined(_WIN32)
@@ -228,6 +229,13 @@ struct vec3s {
vec3s() {}
X_INLINE vec3s(int16 x, int16 y, int16 z) : x(x), y(y), z(z) {}
X_INLINE vec3s operator + (const vec3s &v) const { return vec3s(x + v.x, y + v.y, z + v.z); }
X_INLINE vec3s operator - (const vec3s &v) const { return vec3s(x - v.x, y - v.y, z - v.z); }
X_INLINE bool operator == (const vec3s &v) { return x == v.x && y == v.y && z == v.z; }
X_INLINE bool operator != (const vec3s &v) { return x != v.x || y != v.y || z != v.z; }
X_INLINE vec3s& operator += (const vec3s &v) { x += v.x; y += v.y; z += v.z; return *this; }
X_INLINE vec3s& operator -= (const vec3s &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
};
struct vec3i {
@@ -239,6 +247,10 @@ struct vec3i {
X_INLINE vec3i(vec3s &v) : x(v.x), y(v.y), z(v.z) {}
X_INLINE vec3i operator + (const vec3i &v) const { return vec3i(x + v.x, y + v.y, z + v.z); }
X_INLINE vec3i operator - (const vec3i &v) const { return vec3i(x - v.x, y - v.y, z - v.z); }
X_INLINE vec3i operator * (int32 s) const { return vec3i(x * s, y * s, z * s); }
X_INLINE vec3i operator / (int32 s) const { return vec3i(x / s, y / s, z / s); }
X_INLINE bool operator == (const vec3i &v) const { return x == v.x && y == v.y && z == v.z; }
X_INLINE bool operator != (const vec3i &v) const { return x != v.x || y != v.y || z != v.z; }
X_INLINE vec3i& operator += (const vec3i &v) { x += v.x; y += v.y; z += v.z; return *this; }
X_INLINE vec3i& operator -= (const vec3i &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
};
@@ -308,6 +320,10 @@ struct Bounds {
X_INLINE Bounds() {}
X_INLINE Bounds(int16 minX, int16 maxX, int16 minY, int16 maxY, int16 minZ, int16 maxZ) :
minX(minX), maxX(maxX), minY(minY), maxY(maxY), minZ(minZ), maxZ(maxZ) {}
X_INLINE vec3i getCenter() const {
return vec3i((maxX + minX) >> 1, (maxY + minY) >> 1, (maxZ + minZ) >> 1);
}
};
struct AABB {
@@ -327,10 +343,9 @@ struct RoomVertex {
};
struct RoomSprite {
int16 x, y, z;
vec3s pos;
uint8 g;
uint8 reserved;
uint16 texture;
uint8 index;
};
struct Portal {
@@ -405,7 +420,12 @@ struct RoomInfo
uint8 xSectors;
uint8 zSectors;
uint8 alternateRoom;
uint8 flags;
union {
uint8 value;
struct {
uint8 water:1, :7;
};
} flags;
RoomData data;
};
@@ -427,7 +447,8 @@ struct Room {
void add(Item* item);
void remove(Item* item);
const Sector* getSector(int32 posX, int32 posZ) const;
const Sector* getSector(int32 x, int32 z) const;
const Sector* getWaterSector(int32 x, int32 z) const;
Room* getRoom(int32 x, int32 y, int32 z);
bool checkPortal(const Portal* portal);
Room** addVisibleRoom(Room** list);
@@ -435,19 +456,16 @@ struct Room {
Room** getNearRooms(const vec3i &pos, int32 radius, int32 height);
Room** getAdjRooms();
Room** getVisibleRooms();
int32 getWaterLevel();
int32 getWaterDepth();
};
struct Node {
uint32 flags;
vec3i pos;
vec3i pos;
};
struct Model {
uint8 type;
int8 count;
uint8 type;
int8 count;
uint16 start;
uint16 nodeIndex;
uint16 animIndex;
@@ -475,69 +493,73 @@ struct SoundInfo
};
struct Anim {
uint32 frameOffset;
uint8 frameRate;
uint8 frameSize;
uint16 state;
int32 speed;
int32 accel;
uint16 frameBegin;
uint16 frameEnd;
uint16 nextAnimIndex;
uint16 nextFrameIndex;
uint16 statesCount;
uint16 statesStart;
uint16 commandsCount;
uint16 commandsStart;
uint32 frameOffset;
uint8 frameRate;
uint8 frameSize;
uint16 state;
int32 speed;
int32 accel;
uint16 frameBegin;
uint16 frameEnd;
uint16 nextAnimIndex;
uint16 nextFrameIndex;
uint16 statesCount;
uint16 statesStart;
uint16 commandsCount;
uint16 commandsStart;
};
struct AnimState {
uint8 state;
uint8 rangesCount;
uint8 state;
uint8 rangesCount;
uint16 rangesStart;
};
struct AnimRange {
uint16 frameBegin;
uint16 frameEnd;
uint16 nextAnimIndex;
uint16 nextFrameIndex;
uint16 frameBegin;
uint16 frameEnd;
uint16 nextAnimIndex;
uint16 nextFrameIndex;
};
struct AnimFrame {
Bounds box;
vec3s pos;
Bounds box;
vec3s pos;
uint16 angles[1];
};
struct Texture {
uint16 attribute;
uint16 tile:14, :2;
uint32 uv0;
uint32 uv1;
uint32 uv2;
uint32 uv3;
uint16 attribute;
uint16 tile:14, :2;
uint32 uv0;
uint32 uv1;
uint32 uv2;
uint32 uv3;
};
struct Sprite {
uint16 tile;
uint8 u, v;
uint16 w, h;
int16 l, t, r, b;
uint16 tile;
uint8 u, v;
uint8 w, h;
int16 l, t, r, b;
};
struct SpriteSeq {
uint16 type;
uint16 unused;
int16 count;
int16 start;
uint16 type;
uint16 unused;
int16 count;
int16 start;
};
struct FixedCamera {
vec3i pos;
int16 roomIndex;
union {
uint16 value;
struct {
uint16 timer:8, once:1, speed:5, :2;
};
} flags;
};
struct ItemInfo
@@ -546,7 +568,9 @@ struct ItemInfo
uint8 roomIndex;
vec3s pos;
uint16 intensity;
uint16 flags;
struct {
uint16 value:14, angle:2;
} flags;
};
#define ITEM_FLAGS_MASK_ALL 0x1F
@@ -631,8 +655,8 @@ struct Lara;
E( TRAP_DOOR_2 ) \
E( UNUSED_4 ) \
E( BRIDGE_FLAT ) \
E( BRIDGE_TILT1 ) \
E( BRIDGE_TILT2 ) \
E( BRIDGE_TILT_1 ) \
E( BRIDGE_TILT_2 ) \
E( INV_PASSPORT ) \
E( INV_COMPASS ) \
E( INV_HOME ) \
@@ -680,14 +704,14 @@ struct Lara;
E( INV_PUZZLE_2 ) \
E( INV_PUZZLE_3 ) \
E( INV_PUZZLE_4 ) \
E( PUZZLE_HOLE_1 ) \
E( PUZZLE_HOLE_2 ) \
E( PUZZLE_HOLE_3 ) \
E( PUZZLE_HOLE_4 ) \
E( PUZZLE_DONE_1 ) \
E( PUZZLE_DONE_2 ) \
E( PUZZLE_DONE_3 ) \
E( PUZZLE_DONE_4 ) \
E( PUZZLEHOLE_1 ) \
E( PUZZLEHOLE_2 ) \
E( PUZZLEHOLE_3 ) \
E( PUZZLEHOLE_4 ) \
E( PUZZLEHOLE_DONE_1 ) \
E( PUZZLEHOLE_DONE_2 ) \
E( PUZZLEHOLE_DONE_3 ) \
E( PUZZLEHOLE_DONE_4 ) \
E( LEADBAR ) \
E( INV_LEADBAR ) \
E( MIDAS_HAND ) \
@@ -699,10 +723,10 @@ struct Lara;
E( INV_KEY_ITEM_2 ) \
E( INV_KEY_ITEM_3 ) \
E( INV_KEY_ITEM_4 ) \
E( KEY_HOLE_1 ) \
E( KEY_HOLE_2 ) \
E( KEY_HOLE_3 ) \
E( KEY_HOLE_4 ) \
E( KEYHOLE_1 ) \
E( KEYHOLE_2 ) \
E( KEYHOLE_3 ) \
E( KEYHOLE_4 ) \
E( UNUSED_5 ) \
E( UNUSED_6 ) \
E( SCION_PICKUP_QUALOPEC ) \
@@ -739,9 +763,9 @@ struct Lara;
E( UNUSED_16 ) \
E( UNUSED_17 ) \
E( LAVA_PARTICLE ) \
E( TRAP_LAVA_EMITTER ) \
E( LAVA_EMITTER ) \
E( FLAME ) \
E( TRAP_FLAME_EMITTER ) \
E( FLAME_EMITTER ) \
E( TRAP_LAVA ) \
E( MUTANT_EGG_BIG ) \
E( BOAT ) \
@@ -772,7 +796,7 @@ struct Item {
union {
struct {
uint16 save:1, gravity:1, active:1, status:2, collision:1, custom:2, once:1, mask:5, reverse:1, shadow:1; // TODO
uint16 save:1, gravity:1, active:1, status:2, collision:1, dozy:1, custom:1, once:1, mask:5, reverse:1, shadow:1; // TODO
};
uint16 value;
} flags;
@@ -795,15 +819,18 @@ struct Item {
};
int16 moveAngle;
int16 floor;
int16 turnSpeed;
int16 vSpeedHack;
uint16 input;
uint8 type;
uint8 intensity;
int16 roomFloor;
int16 vSpeedHack;
int16 swimTimer;
uint8 weaponState;
uint8 _reserved;
Item* nextItem;
Item* nextActive;
@@ -821,19 +848,42 @@ struct Item {
const Anim* animSet(int32 newAnimIndex, bool resetState, int32 frameOffset = 0);
const Anim* animChange(const Anim* anim);
void animCmd(bool fx, const Anim* anim);
void animSkip(int32 stateBefore, int32 stateAfter, bool advance = false);
void animProcess(bool movement = true);
bool animIsEnd(int32 offset) const;
bool moveTo(const vec3i &point, Item* item, bool lerp);
void skipAnim();
void updateAnim(bool movement = true);
void updateRoom(int32 offset = 0);
int32 calcLighting(const Bounds& box) const;
vec3i getRelative(const vec3i &point) const;
int32 getWaterLevel();
int32 getWaterDepth();
Item* init(Room* room);
X_INLINE Item() {}
Item(Room* room);
virtual void collide(Lara* lara, CollisionInfo* cinfo);
virtual void update();
virtual void draw();
virtual void collide(Lara* lara, CollisionInfo* cinfo);
};
enum WeaponState {
WEAPON_STATE_FREE,
WEAPON_STATE_BUSY,
WEAPON_STATE_DRAW,
WEAPON_STATE_HOLSTER,
WEAPON_STATE_READY
};
enum WeaponType {
WEAPON_TYPE_NONE,
WEAPON_TYPE_PISTOLS,
WEAPON_TYPE_MAGNUMS,
WEAPON_TYPE_UZIS,
WEAPON_TYPE_SHOTGUN,
WEAPON_TYPE_MAX
};
struct SaveGame
@@ -842,7 +892,8 @@ struct SaveGame
uint8 once:1, mask:5, :2;
};
uint8 secrets;
uint8 secrets;
uint8 pickups;
TrackFlags tracks[64];
};
@@ -927,9 +978,9 @@ enum SlantType {
enum WaterState {
WATER_STATE_ABOVE,
WATER_STATE_WADE,
WATER_STATE_SURFACE,
WATER_STATE_UNDER,
WATER_STATE_WADE,
};
enum AnimCommand {
@@ -1076,8 +1127,10 @@ struct Level {
uint16 spriteSequencesCount;
uint16 soundSourcesCount;
uint16 boxesCount;
uint16 texturesCount;
uint16 animTexDataSize;
uint16 itemsCount;
uint16 camerasCount;
uint16 cameraFramesCount;
const uint16* palette;
@@ -1098,12 +1151,12 @@ struct Level {
const Texture* textures;
const Sprite* sprites;
const SpriteSeq* spriteSequences;
uint32 cameras;
const FixedCamera* cameras;
uint32 soundSources;
const Box* boxes;
const uint16* overlaps;
const uint16* zones[2][3];
uint32 animTexData;
const int16* animTexData;
const ItemInfo* itemsInfo;
uint32 cameraFrames;
const uint16* soundMap;
@@ -1177,9 +1230,12 @@ extern int32 fps;
#define MAX_MODELS ITEM_MAX
#define MAX_ROOMS 139 // LEVEL7A
#define MAX_STATIC_MESHES 50
#define MAX_VERTICES 3072
#define MAX_CAMERAS 16
#define MAX_VERTICES (4*1024)
#define MAX_TEXTURES 1536
#define MAX_FACES 1024
#define MAX_ROOM_LIST 16
#define MAX_CAUSTICS 32
#define FOV_SHIFT 3
#define FOG_SHIFT 1
@@ -1196,7 +1252,8 @@ extern int32 fps;
#define FACE_COLORED 0x4000
#define FACE_CLIPPED 0x2000
#define FACE_FLAT 0x1000
#define FACE_SHADOW 0x0800
#define FACE_SPRITE 0x0800
#define FACE_SHADOW (FACE_COLORED | FACE_FLAT | FACE_SPRITE)
#define FACE_TEXTURE 0x07FF
#define NO_ROOM 0xFF
@@ -1216,6 +1273,7 @@ extern int32 fps;
#define X_MIN(a,b) ((a) < (b) ? (a) : (b))
#define X_MAX(a,b) ((a) > (b) ? (a) : (b))
#define X_SQR(x) ((x) * (x))
#define X_COUNT(x) int32(sizeof(x) / sizeof(x[0]))
#define DP43c(a,bx,by,bz) ((a).x * bx + (a).y * by + (a).z * bz + (a).w)
#define DP33c(a,bx,by,bz) ((a).x * bx + (a).y * by + (a).z * bz)
@@ -1298,12 +1356,10 @@ X_INLINE void swap(T &a, T &b) {
b = tmp;
}
X_INLINE int32 classify(const Vertex &v, const Rect &clip) {
return (v.x < clip.x0 ? 1 : 0) |
(v.x > clip.x1 ? 2 : 0) |
(v.y < clip.y0 ? 4 : 0) |
(v.y > clip.y1 ? 8 : 0);
}
void set_seed_ctrl(int32 seed);
void set_seed_draw(int32 seed);
int16 rand_ctrl();
int16 rand_draw();
int32 phd_sin(int32 x);
int32 phd_cos(int32 x);
@@ -1363,10 +1419,11 @@ int32 rectIsVisible(const Rect* rect);
int32 boxIsVisible(const Bounds* box);
void transform(int32 vx, int32 vy, int32 vz, int32 vg);
bool transformBoxRect(const Bounds* box, Rect* rect);
void transformRoom(const RoomVertex* vertices, int32 vCount);
void transformMesh(const vec3s* vertices, int32 vCount, uint16 intensity);
void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics);
void transformMesh(const vec3s* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal);
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex);
void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index);
void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex);
void faceAddMesh(const Quad* rFaces, const Quad* crFaces, const Triangle* tFaces, const Triangle* ctFaces, int32 rCount, int32 crCount, int32 tCount, int32 ctCount, int32 startVertex);
@@ -1377,7 +1434,7 @@ void readLevel(const uint8 *data);
Lara* getLara(const vec3i &pos);
bool useSwitch(Item* item, int32 timer);
bool useKey(Item* item);
bool useKey(Item* item, Item* lara);
bool usePickup(Item* item);
void musicPlay(int32 track);
@@ -1395,13 +1452,4 @@ X_INLINE void dmaFill(void *dst, uint8 value, uint32 count)
#endif
}
X_INLINE int16 xRand()
{
#ifdef __GBA__
return qran();
#else
return rand();
#endif
}
#endif

View File

@@ -4,7 +4,85 @@
#include "common.h"
#include "item.h"
extern AABB fastClipAABB;
int32 lightAmbient;
int32 caustics[MAX_CAUSTICS];
int32 causticsRand[MAX_CAUSTICS];
int32 causticsFrame;
void drawInit()
{
for (int32 i = 0; i < MAX_CAUSTICS; i++)
{
int16 rot = i * (ANGLE_90 * 4) / MAX_CAUSTICS;
caustics[i] = phd_sin(rot) * 768 >> FIXED_SHIFT;
causticsRand[i] = (rand_draw() >> 5) - 511;
}
}
void drawFree()
{
//
}
void calcLightingDynamic(const Room* room, const vec3i &point)
{
const RoomInfo* info = room->info;
lightAmbient = (info->ambient << 5);
if (!info->lightsCount)
return;
lightAmbient = 8191 - lightAmbient;
int32 maxLum = 0;
for (int i = 0; i < info->lightsCount; i++)
{
const Light* light = room->data.lights + i;
vec3i pos;
pos.x = light->pos.x + (info->x << 8);
pos.y = light->pos.y;
pos.z = light->pos.z + (info->z << 8);
int32 radius = light->radius << 8;
int32 intensity = light->intensity << 5;
vec3i d = point - pos;
int32 dist = dot(d, d) >> 12;
int32 att = X_SQR(radius) >> 12;
int32 lum = (intensity * att) / (dist + att) + lightAmbient;
if (lum > maxLum)
{
maxLum = lum;
}
}
lightAmbient = 8191 - ((maxLum + lightAmbient) >> 1);
Matrix &m = matrixGet();
int32 fogZ = m[2].w >> FIXED_SHIFT;
if (fogZ > FOG_MIN) {
lightAmbient += (fogZ - FOG_MIN) << FOG_SHIFT;
lightAmbient = X_MIN(lightAmbient, 8191);
}
}
void calcLightingStatic(int32 intensity)
{
lightAmbient = intensity - 4096;
Matrix &m = matrixGet();
int32 fogZ = m[2].w >> FIXED_SHIFT;
if (fogZ > FOG_MIN) {
lightAmbient += (fogZ - FOG_MIN) << FOG_SHIFT;
}
}
void drawNumber(int32 number, int32 x, int32 y)
{
@@ -22,7 +100,7 @@ void drawNumber(int32 number, int32 x, int32 y)
}
}
void drawMesh(int16 meshIndex, uint16 intensity)
void drawMesh(int16 meshIndex)
{
int32 offset = level.meshOffsets[meshIndex];
const uint8* ptr = level.meshData + offset;
@@ -33,12 +111,17 @@ void drawMesh(int16 meshIndex, uint16 intensity)
const vec3s* vertices = (vec3s*)ptr;
ptr += vCount * 3 * sizeof(int16);
const uint16* vIntensity = NULL;
const vec3s* vNormal = NULL;
int16 nCount = *(int16*)ptr; ptr += 2;
//const int16* normals = (int16*)ptr;
if (nCount > 0) { // normals
vNormal = (vec3s*)ptr;
ptr += nCount * 3 * sizeof(int16);
} else { // intensity
ptr += vCount * sizeof(int16);
vIntensity = (uint16*)ptr;
ptr += vCount * sizeof(uint16);
}
int16 rCount = *(int16*)ptr; ptr += 2;
@@ -56,7 +139,7 @@ void drawMesh(int16 meshIndex, uint16 intensity)
int32 startVertex = gVerticesCount;
PROFILE_START();
transformMesh(vertices, vCount, intensity);
transformMesh(vertices, vCount, vIntensity, vNormal);
PROFILE_STOP(dbg_transform);
PROFILE_START();
@@ -106,16 +189,17 @@ void drawShadow(const Item* item, int32 size)
6, 3, 4, 5
};
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 0, startVertex);
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 4, startVertex);
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 8, startVertex);
faceAddQuad(FACE_SHADOW, indices + 0, startVertex);
faceAddQuad(FACE_SHADOW, indices + 4, startVertex);
faceAddQuad(FACE_SHADOW, indices + 8, startVertex);
matrixPop();
}
void drawSprite(const Item* item)
{
// TODO
vec3i d = item->pos - cameraViewPos;
faceAddSprite(d.x, d.y, d.z, item->intensity << 5, models[item->type].start);
}
void drawModel(const Item* item, uint16* meshOverrides)
@@ -134,7 +218,10 @@ void drawModel(const Item* item, uint16* meshOverrides)
int32 intensity = item->intensity << 5;
if (intensity == 0) {
intensity = item->calcLighting(frame->box);
vec3i point = item->getRelative(frame->box.getCenter());
calcLightingDynamic(item->room, point);
} else {
calcLightingStatic(intensity);
}
int32 vis = boxIsVisible(&frame->box);
@@ -156,7 +243,7 @@ void drawModel(const Item* item, uint16* meshOverrides)
matrixFrame(frame->pos, frameAngles);
drawMesh(meshOverrides ? meshOverrides[0] : model->start, intensity);
drawMesh(meshOverrides ? meshOverrides[0] : model->start);
for (int32 i = 1; i < model->count; i++)
{
@@ -166,7 +253,7 @@ void drawModel(const Item* item, uint16* meshOverrides)
frameAngles += 2;
matrixFrame(node->pos, frameAngles);
drawMesh(meshOverrides ? meshOverrides[i] : (model->start + i), intensity);
drawMesh(meshOverrides ? meshOverrides[i] : (model->start + i));
node++;
}
@@ -209,21 +296,27 @@ void drawRoom(const Room* room)
enableClipping = true;
PROFILE_START();
transformRoom(data.vertices, info->verticesCount);
transformRoom(data.vertices, info->verticesCount, info->flags.water);
PROFILE_STOP(dbg_transform);
matrixPop();
PROFILE_START();
faceAddRoom(data.quads, info->quadsCount, data.triangles, info->trianglesCount, startVertex);
PROFILE_STOP(dbg_poly);
for (int32 i = 0; i < info->spritesCount; i++)
{
const RoomSprite* sprite = data.sprites + i;
faceAddSprite(sprite->pos.x, sprite->pos.y, sprite->pos.z, sprite->g << 5, sprite->index);
}
matrixPop();
for (int32 i = 0; i < info->meshesCount; i++)
{
const RoomMesh* mesh = data.meshes + i;
#ifdef NO_STATIC_MESHES
if (mesh->id != STATIC_MESH_GATE) continue;
#ifdef NO_STATIC_MESH_PLANTS
if (mesh->id < 10) continue;
#endif
const StaticMesh* staticMesh = staticMeshes + mesh->id;
@@ -243,8 +336,10 @@ void drawRoom(const Room* room)
int32 vis = boxIsVisible(&staticMesh->vbox);
if (vis != 0) {
enableClipping = vis < 0;
drawMesh(staticMesh->meshIndex, mesh->intensity << 5);
enableClipping = true;//vis < 0; // TODO wrong visibility BBox?
calcLightingStatic(mesh->intensity << 5);
drawMesh(staticMesh->meshIndex);
}
matrixPop();
@@ -277,103 +372,4 @@ void drawRooms()
flush();
}
#ifdef TEST
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
extern Vertex gVertices[MAX_VERTICES];
Rect testClip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
int32 testTile = 10; // 707 // 712
void drawTest() {
#ifdef _WIN32
Sleep(16);
#endif
int dx = 0;
int dy = 0;
if (keys & IK_LEFT) dy++;
if (keys & IK_RIGHT) dy--;
if (keys & IK_UP) dx--;
if (keys & IK_DOWN) dx++;
if (keys & IK_L) {
testClip.x0 += dx;
testClip.y0 += dy;
}
if (keys & IK_R) {
testClip.x1 += dx;
testClip.y1 += dy;
}
if (keys & IK_A) {
testTile++;
//Sleep(100);
}
if (keys & IK_B) {
testTile--;
//Sleep(100);
}
//testTile = (testTile + texturesCount) % texturesCount;
clip = testClip;
static int vidx = 0;
if (keys & IK_SELECT) {
vidx++;
//Sleep(100);
}
gVertices[(vidx + 0) % 4].x = -25;
gVertices[(vidx + 0) % 4].y = -25;
gVertices[(vidx + 1) % 4].x = 25;
gVertices[(vidx + 1) % 4].y = -25;
gVertices[(vidx + 2) % 4].x = 50;
gVertices[(vidx + 2) % 4].y = 25;
gVertices[(vidx + 3) % 4].x = -50;
gVertices[(vidx + 3) % 4].y = 25;
for (int i = 0; i < 4; i++)
{
gVertices[i].x += FRAME_WIDTH/2;
gVertices[i].y += FRAME_HEIGHT/2;
gVertices[i].z = 100;
gVertices[i].g = 16;
gVertices[i].clip = classify(gVertices[i], clip);
}
gVerticesCount = 4;
Index indices[] = { 0, 1, 2, 3, 0, 2, 3 };
faceAddQuad(testTile, indices, 0);
#ifdef _WIN32
for (int y = 0; y < FRAME_HEIGHT; y++)
{
for (int x = 0; x < FRAME_WIDTH; x++)
{
if (x == clip.x0 || x == clip.x1 - 1 || y == clip.y0 || y == clip.y1 - 1)
{
#ifdef MODE4
((uint8*)fb)[y * FRAME_WIDTH + x] = 255;
#else
((uint16*)fb)[y * FRAME_WIDTH + x] = 255;
#endif
}
}
}
#endif
flush();
}
#endif
#endif

View File

@@ -14,13 +14,11 @@ struct Enemy : Item
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
//
UNUSED(lara);
UNUSED(cinfo);
}
virtual void update()
{
updateAnim();
animProcess();
}
};

View File

@@ -9,25 +9,23 @@
#include "item.h"
#include "draw.h"
Lara* players[2];
Lara* getLara(const vec3i &pos)
{
UNUSED(pos); // TODO two players
return players[0]; // TODO find nearest player
}
struct Game
{
int32 animTexFrame;
void init()
{
loadLevel(LEVEL1_PKD);
set_seed_ctrl(osGetSystemTimeMS() * 3);
set_seed_draw(osGetSystemTimeMS() * 7);
animTexFrame = 0;
loadLevel(levelData);
}
void loadLevel(const void* data)
{
camera.init();
drawFree();
readLevel((uint8*)data);
// prepare rooms
@@ -39,34 +37,47 @@ struct Game
// prepare items
for (int32 i = 0; i < level.itemsCount; i++)
{
Item* item = items + i;
const ItemInfo* info = level.itemsInfo + i;
Item* item = items + i;
item->type = info->type;
item->intensity = info->intensity << 5;
item->intensity = info->intensity;
item->pos.x = info->pos.x + (rooms[info->roomIndex].info->x << 8);
item->pos.y = info->pos.y;
item->pos.z = info->pos.z + (rooms[info->roomIndex].info->z << 8);
item->angle.y = ((info->flags >> 14) - 2) * ANGLE_90;
item->flags.value = info->flags & 0x3FFF;
item->angle.y = (info->flags.angle - 2) * ANGLE_90;
item->flags.value = info->flags.value;
item->init(rooms + info->roomIndex);
if (item->type == ITEM_LARA)
{
camera.item = item;
camera.init(item);
camera.laraItem = item;
//#ifdef PROFILE
// debug
//resetItem(item, 0, vec3i(74588, 3072, 19673), 0); // level 1 (first darts)
//resetItem(item, 9, vec3i(49669, 7680, 57891), 0); // level 1 (first door)
//resetItem(item, 10, vec3i(43063, 7168, 61198), 0); // level 1 (transp)
//resetItem(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // level 1 (bridge)
//resetItem(item, 17, vec3i(16475, 6656, 59845), ANGLE_90); // level 1 (bear)
//resetItem(item, 26, vec3i(24475, 6912, 83505), ANGLE_90); // level 1 (switch timer)
//resetItem(item, 35, vec3i(35149, 2048, 74189), ANGLE_90); // level 1 (switch timer)
// gym
//resetItem(item, 13, vec3i(38953, 3328, 63961), ANGLE_90 + ANGLE_45); // pool
// level 1
//resetItem(item, 0, vec3i(74588, 3072, 19673), ANGLE_0); // first darts
//resetItem(item, 9, vec3i(49669, 7680, 57891), ANGLE_0); // first door
//resetItem(item, 10, vec3i(43063, 7168, 61198), ANGLE_0); // transp
//resetItem(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // bridge
//resetItem(item, 17, vec3i(16475, 6656, 59845), ANGLE_90); // bear
//resetItem(item, 26, vec3i(24475, 6912, 83505), ANGLE_90); // switch timer 1
//resetItem(item, 35, vec3i(35149, 2048, 74189), ANGLE_90); // switch timer 2
// level 2
//resetItem(item, 15, vec3i(66179, 0, 25920), -ANGLE_90 - ANGLE_45); // sprites
//resetItem(item, 19, vec3i(61018, 1024, 31214), ANGLE_180); // block
//resetItem(item, 14, vec3i(64026, 512, 20806), ANGLE_0); // key and puzzle
//resetItem(item, 5, vec3i(55644, 0, 29155), -ANGLE_90); // keyhole
//resetItem(item, 71, vec3i(12705, -768, 30195), -ANGLE_90); // puzzle
//resetItem(item, 63, vec3i(31055, -2048, 33406), ANGLE_0); // right room
//resetItem(item, 44, vec3i(27868, -1024, 29191), -ANGLE_90); // swing blades
// level 3a
//resetItem(item, 44, vec3i(73798, 2304, 9819), ANGLE_90); // uw gears
//#endif
camera.view.pos = camera.target.pos = item->pos;
@@ -75,6 +86,8 @@ struct Game
players[0] = (Lara*)item;
}
}
drawInit();
}
void resetItem(Item* item, int32 roomIndex, const vec3i &pos, int32 angleY)
@@ -99,11 +112,20 @@ struct Game
}
}
void nextFrame(int32 frames)
{
causticsFrame += frames;
animTexFrame += frames;
while (animTexFrame > 5)
{
animTexturesShift();
animTexFrame -= 5;
}
}
void update(int32 frames)
{
#ifdef TEST
return;
#endif
if (frames > MAX_UPDATE_FRAMES) {
frames = MAX_UPDATE_FRAMES;
}
@@ -114,6 +136,8 @@ struct Game
camera.update();
}
nextFrame(frames);
if (keys & IK_SELECT) {
mixer.playMusic(TRACK_13_WAV);
}
@@ -129,36 +153,22 @@ struct Game
clear();
#ifdef TEST
#ifdef __GBA__
VBlankIntrWait();
#endif
#ifdef PROFILE
dbg_transform = 0;
dbg_poly = 0;
dbg_flush = 0;
dbg_vert_count = 0;
dbg_poly_count = 0;
#endif
int32 cycles = 0;
PROFILE_START();
drawTest();
PROFILE_STOP(cycles);
drawNumber(cycles, TEXT_POSX, 32);
#else
#ifdef PROFILE
dbg_transform = 0;
dbg_poly = 0;
dbg_flush = 0;
dbg_vert_count = 0;
dbg_poly_count = 0;
#endif
drawRooms();
#ifdef PROFILE
drawNumber(dbg_transform, TEXT_POSX, 32);
drawNumber(dbg_poly, TEXT_POSX, 48);
drawNumber(dbg_flush, TEXT_POSX, 64);
drawNumber(dbg_vert_count, TEXT_POSX, 84);
drawNumber(dbg_poly_count, TEXT_POSX, 100);
#endif
drawRooms();
#ifdef PROFILE
drawNumber(dbg_transform, TEXT_POSX, 32);
drawNumber(dbg_poly, TEXT_POSX, 48);
drawNumber(dbg_flush, TEXT_POSX, 64);
drawNumber(dbg_vert_count, TEXT_POSX, 84);
drawNumber(dbg_poly_count, TEXT_POSX, 100);
#endif
drawNumber(fps, TEXT_POSX, 16);

View File

@@ -0,0 +1,319 @@
#ifndef H_INVENTORY
#define H_INVENTORY
#include "common.h"
enum StringID {
STR_PASSPORT
, STR_COMPASS
, STR_HOME
, STR_MAP
, STR_DETAIL
, STR_SOUND
, STR_CONTROLS
, STR_GAMMA
, STR_PISTOLS
, STR_SHOTGUN
, STR_MAGNUMS
, STR_UZIS
, STR_AMMO_PISTOLS
, STR_AMMO_SHOTGUN
, STR_AMMO_MAGNUMS
, STR_AMMO_UZIS
, STR_EXPLOSIVE
, STR_MEDIKIT_SMALL
, STR_MEDIKIT_BIG
, STR_PUZZLE
, STR_PUZZLE_GOLD_IDOL
, STR_PUZZLE_GOLD_BAR
, STR_PUZZLE_COG
, STR_PUZZLE_FUSE
, STR_PUZZLE_ANKH
, STR_PUZZLE_HORUS
, STR_PUZZLE_ANUBIS
, STR_PUZZLE_SCARAB
, STR_PUZZLE_PYRAMID
, STR_LEADBAR
, STR_KEY
, STR_KEY_SILVER
, STR_KEY_RUSTY
, STR_KEY_GOLD
, STR_KEY_SAPPHIRE
, STR_KEY_NEPTUNE
, STR_KEY_ATLAS
, STR_KEY_DAMOCLES
, STR_KEY_THOR
, STR_KEY_ORNATE
, STR_SCION
, STR_MAX
};
const char* InvNames[STR_MAX] = {
"Game"
, "Compass"
, "Lara's Home"
, "Map"
, "Detail Levels"
, "Sound"
, "Controls"
, "Gamma"
, "Pistols"
, "Shotgun"
, "Magnums"
, "Uzis"
, "Pistol Clips"
, "Shotgun Shells"
, "Magnum Clips"
, "Uzi Clips"
, "Explosive"
, "Small Medi Pack"
, "Large Medi Pack"
, "Puzzle"
, "Gold Idol"
, "Gold Bar"
, "Machine Cog"
, "Fuse"
, "Ankh"
, "Eye of Horus"
, "Seal of Anubis"
, "Scarab"
, "Pyramid Key"
, "Lead Bar"
, "Key"
, "Silver Key"
, "Rusty Key"
, "Gold Key"
, "Sapphire Key"
, "Neptune Key"
, "Atlas Key"
, "Damocles Key"
, "Thor Key"
, "Ornate Key"
, "Scion"
};
enum InvSlot {
// Items
SLOT_LEADBAR
, SLOT_KEY_ITEM_1
, SLOT_KEY_ITEM_2
, SLOT_KEY_ITEM_3
, SLOT_KEY_ITEM_4
, SLOT_PUZZLE_4
, SLOT_PUZZLE_3
, SLOT_PUZZLE_2
, SLOT_PUZZLE_1
, SLOT_SCION
// Inventory
, SLOT_COMPASS
, SLOT_MAP
, SLOT_PISTOLS
, SLOT_AMMO_PISTOLS
, SLOT_SHOTGUN
, SLOT_AMMO_SHOTGUN
, SLOT_MAGNUMS
, SLOT_AMMO_MAGNUMS
, SLOT_UZIS
, SLOT_AMMO_UZIS
, SLOT_EXPLOSIVE
, SLOT_MEDIKIT_BIG
, SLOT_MEDIKIT_SMALL
// Options
, SLOT_PASSPORT
, SLOT_DETAIL
, SLOT_SOUND
, SLOT_CONTROLS
, SLOT_GAMMA
, SLOT_HOME
, SLOT_MAX
};
struct InvItem
{
uint8 type;
uint8 sid;
// TODO params
};
const InvItem INV_SLOTS[SLOT_MAX] = {
{ ITEM_INV_LEADBAR , STR_LEADBAR }
, { ITEM_INV_KEY_ITEM_1 , STR_KEY }
, { ITEM_INV_KEY_ITEM_2 , STR_KEY }
, { ITEM_INV_KEY_ITEM_3 , STR_KEY }
, { ITEM_INV_KEY_ITEM_4 , STR_KEY }
, { ITEM_INV_PUZZLE_4 , STR_PUZZLE }
, { ITEM_INV_PUZZLE_3 , STR_PUZZLE }
, { ITEM_INV_PUZZLE_2 , STR_PUZZLE }
, { ITEM_INV_PUZZLE_1 , STR_PUZZLE }
, { ITEM_INV_SCION , STR_SCION }
, { ITEM_INV_COMPASS , STR_COMPASS }
, { ITEM_INV_MAP , STR_MAP }
, { ITEM_INV_PISTOLS , STR_PISTOLS }
, { ITEM_INV_AMMO_PISTOLS , STR_AMMO_PISTOLS }
, { ITEM_INV_SHOTGUN , STR_SHOTGUN }
, { ITEM_INV_AMMO_SHOTGUN , STR_AMMO_SHOTGUN }
, { ITEM_INV_MAGNUMS , STR_MAGNUMS }
, { ITEM_INV_AMMO_MAGNUMS , STR_AMMO_MAGNUMS }
, { ITEM_INV_UZIS , STR_UZIS }
, { ITEM_INV_AMMO_UZIS , STR_AMMO_UZIS }
, { ITEM_INV_EXPLOSIVE , STR_EXPLOSIVE }
, { ITEM_INV_MEDIKIT_BIG , STR_MEDIKIT_BIG }
, { ITEM_INV_MEDIKIT_SMALL , STR_MEDIKIT_SMALL }
, { ITEM_INV_PASSPORT , STR_PASSPORT }
, { ITEM_INV_DETAIL , STR_DETAIL }
, { ITEM_INV_SOUND , STR_SOUND }
, { ITEM_INV_CONTROLS , STR_CONTROLS }
, { ITEM_INV_GAMMA , STR_GAMMA }
, { ITEM_INV_HOME , STR_HOME }
};
struct Inventory
{
InvSlot useSlot;
int32 numKeys;
int32 counts[X_COUNT(INV_SLOTS)];
Inventory()
{
memset(counts, 0, sizeof(counts));
useSlot = SLOT_MAX;
numKeys = 0;
add(ITEM_INV_PASSPORT);
add(ITEM_INV_DETAIL);
add(ITEM_INV_SOUND);
add(ITEM_INV_CONTROLS);
//add(ITEM_INV_GAMMA);
//add(ITEM_INV_HOME);
add(ITEM_INV_COMPASS);
add(ITEM_INV_PISTOLS);
//add(ITEM_INV_KEY_ITEM_1);
//add(ITEM_INV_PUZZLE_1);
}
ItemType remapToInv(ItemType type)
{
switch (type)
{
case ITEM_PISTOLS : return ITEM_INV_PISTOLS;
case ITEM_SHOTGUN : return ITEM_INV_SHOTGUN;
case ITEM_MAGNUMS : return ITEM_INV_MAGNUMS;
case ITEM_UZIS : return ITEM_INV_UZIS;
case ITEM_AMMO_PISTOLS : return ITEM_INV_AMMO_PISTOLS;
case ITEM_AMMO_SHOTGUN : return ITEM_INV_AMMO_SHOTGUN;
case ITEM_AMMO_MAGNUMS : return ITEM_INV_AMMO_MAGNUMS;
case ITEM_AMMO_UZIS : return ITEM_INV_AMMO_UZIS;
case ITEM_MEDIKIT_SMALL : return ITEM_INV_MEDIKIT_SMALL;
case ITEM_MEDIKIT_BIG : return ITEM_INV_MEDIKIT_BIG;
case ITEM_PUZZLE_1 : return ITEM_INV_PUZZLE_1;
case ITEM_PUZZLE_2 : return ITEM_INV_PUZZLE_2;
case ITEM_PUZZLE_3 : return ITEM_INV_PUZZLE_3;
case ITEM_PUZZLE_4 : return ITEM_INV_PUZZLE_4;
case ITEM_LEADBAR : return ITEM_INV_LEADBAR;
case ITEM_KEY_ITEM_1 : return ITEM_INV_KEY_ITEM_1;
case ITEM_KEY_ITEM_2 : return ITEM_INV_KEY_ITEM_2;
case ITEM_KEY_ITEM_3 : return ITEM_INV_KEY_ITEM_3;
case ITEM_KEY_ITEM_4 : return ITEM_INV_KEY_ITEM_4;
case ITEM_SCION_PICKUP_QUALOPEC :
case ITEM_SCION_PICKUP_DROP :
case ITEM_SCION_PICKUP_HOLDER : return ITEM_INV_SCION;
default : return type;
}
}
InvSlot remapToSlot(ItemType type)
{
type = remapToInv(type);
for (int32 i = 0; i < X_COUNT(INV_SLOTS); i++)
{
if (INV_SLOTS[i].type == type)
return (InvSlot)i;
}
ASSERT(false);
return SLOT_COMPASS;
}
InvSlot remapHoleToSlot(ItemType type)
{
switch (type)
{
case ITEM_PUZZLEHOLE_1 : return SLOT_PUZZLE_1;
case ITEM_PUZZLEHOLE_2 : return SLOT_PUZZLE_2;
case ITEM_PUZZLEHOLE_3 : return SLOT_PUZZLE_3;
case ITEM_PUZZLEHOLE_4 : return SLOT_PUZZLE_4;
case ITEM_KEYHOLE_1 : return SLOT_KEY_ITEM_1;
case ITEM_KEYHOLE_2 : return SLOT_KEY_ITEM_2;
case ITEM_KEYHOLE_3 : return SLOT_KEY_ITEM_3;
case ITEM_KEYHOLE_4 : return SLOT_KEY_ITEM_4;
default : return SLOT_MAX;
}
}
void add(ItemType type, int32 count = 1)
{
InvSlot slot = remapToSlot(type);
counts[slot] += count;
// TODO check max
if (slot < SLOT_COMPASS) {
numKeys += count;
}
}
void remove(InvSlot slot, int32 count)
{
counts[slot] -= count;
if (slot < SLOT_COMPASS) {
numKeys -= count;
}
}
void show(Item* lara, Item* hole)
{
if (hole) {
useSlot = remapHoleToSlot((ItemType)hole->type);
}
}
bool applyItem(Item* hole)
{
#define CHECK_CASE(A, B) case A: { if (useSlot != B) return false; break; }
switch (hole->type)
{
CHECK_CASE(ITEM_PUZZLEHOLE_1, SLOT_PUZZLE_1);
CHECK_CASE(ITEM_PUZZLEHOLE_2, SLOT_PUZZLE_2);
CHECK_CASE(ITEM_PUZZLEHOLE_3, SLOT_PUZZLE_3);
CHECK_CASE(ITEM_PUZZLEHOLE_4, SLOT_PUZZLE_4);
CHECK_CASE(ITEM_KEYHOLE_1, SLOT_KEY_ITEM_1);
CHECK_CASE(ITEM_KEYHOLE_2, SLOT_KEY_ITEM_2);
CHECK_CASE(ITEM_KEYHOLE_3, SLOT_KEY_ITEM_3);
CHECK_CASE(ITEM_KEYHOLE_4, SLOT_KEY_ITEM_4);
default: return false;
}
remove(useSlot, 1);
useSlot = SLOT_MAX;
return true;
}
void draw()
{
//
}
};
Inventory inventory;
#endif

View File

@@ -5,61 +5,59 @@
#include "sound.h"
#include "camera.h"
#include "draw.h"
#include "room.h"
int32 curItemIndex;
#define GRAVITY 6
int16 angleDec(int16 angle, int32 value) {
if (angle < -value) {
return angle + value;
} else if (angle > value) {
return angle - value;
}
return 0;
X_INLINE int16 angleLerp(int16 a, int16 b, int32 w)
{
int16 d = b - a;
if (d > +w) return a + w;
if (d < -w) return a - w;
return b;
}
#define angleDec(angle, value) angleLerp(angle, 0, value)
Mixer::Sample* soundPlay(int16 id, const vec3i &pos)
{
int16 a = level.soundMap[id];
if (a == -1) {
if (a == -1)
return NULL;
}
const SoundInfo* b = level.soundsInfo + a;
if (b->chance && b->chance < xRand()) {
if (b->chance && b->chance < rand_draw())
return NULL;
}
vec3i d = pos - camera.target.pos;
if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) {
if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST)
return NULL;
}
int32 volume = b->volume - (phd_sqrt(dot(d, d)) << 2);
if (b->flags.gain) {
volume -= xRand() >> 2;
volume -= rand_draw() >> 2;
}
volume = X_MIN(volume, 0x7FFF) >> 9;
if (volume <= 0) {
if (volume <= 0)
return NULL;
}
int32 pitch = 128;
if (b->flags.pitch) {
pitch += ((xRand() * 13) >> 14) - 13;
pitch += ((rand_draw() * 13) >> 14) - 13;
}
int32 index = b->index;
if (b->flags.count > 1) {
index += (xRand() * b->flags.count) >> 15;
index += (rand_draw() * b->flags.count) >> 15;
}
const uint8 *data = level.soundData + level.soundOffsets[index];
@@ -68,9 +66,36 @@ Mixer::Sample* soundPlay(int16 id, const vec3i &pos)
memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header
data += 44;
if (id >= 148 + 25) {
pitch >>= 1; // GYM PC sample rate hack
}
return mixer.playSample(data, size, volume, pitch, b->flags.mode);
}
void soundStop(int16 id)
{
int16 a = level.soundMap[id];
if (a == -1)
return;
const SoundInfo* b = level.soundsInfo + a;
for (int32 i = 0; i < b->flags.count; i++)
{
int32 index = b->index + i;
const uint8 *data = level.soundData + level.soundOffsets[index];
int32 size;
memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header
data += 44;
mixer.stopSample(data);
}
}
void musicPlay(int32 track)
{
if (track > 25 && track < 57) // gym tutorial
@@ -189,15 +214,17 @@ void Item::animCmd(bool fx, const Anim* anim)
{
int32 cmd = *ptr++;
switch (cmd) {
switch (cmd)
{
case ANIM_CMD_NONE:
break;
case ANIM_CMD_OFFSET:
{
if (!fx)
{
int32 s = phd_sin(moveAngle);
int32 c = phd_cos(moveAngle);
int32 s = phd_sin(angle.y);
int32 c = phd_cos(angle.y);
int32 x = ptr[0];
int32 y = ptr[1];
int32 z = ptr[2];
@@ -208,7 +235,9 @@ void Item::animCmd(bool fx, const Anim* anim)
ptr += 3;
break;
}
case ANIM_CMD_JUMP:
{
if (!fx)
{
if (vSpeedHack) {
@@ -222,23 +251,37 @@ void Item::animCmd(bool fx, const Anim* anim)
}
ptr += 2;
break;
}
case ANIM_CMD_EMPTY:
{
if (!fx) {
weaponState = WEAPON_STATE_FREE;
}
break;
}
case ANIM_CMD_KILL:
if (!fx)
{
{
if (!fx) {
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
}
break;
}
case ANIM_CMD_SOUND:
if (fx && frameIndex == ptr[0])
{
{
if (fx && frameIndex == ptr[0]) {
soundPlay(ptr[1] & 0x03FFF, pos);
}
ptr += 2;
break;
}
case ANIM_CMD_EFFECT:
if (fx && frameIndex == ptr[0]) {
{
if (fx && frameIndex == ptr[0])
{
switch (ptr[1]) {
case FX_ROTATE_180 : angle.y += ANGLE_180; break;
/*
@@ -262,26 +305,42 @@ void Item::animCmd(bool fx, const Anim* anim)
}
ptr += 2;
break;
}
}
}
}
void Item::skipAnim()
void Item::animSkip(int32 stateBefore, int32 stateAfter, bool advance)
{
goalState = stateBefore;
vec3i p = pos;
while (state != goalState)
{
updateAnim(false);
animProcess(false);
}
if (advance) {
animProcess();
}
pos = p;
vSpeed = 0;
hSpeed = 0;
goalState = stateAfter;
}
void Item::updateAnim(bool movement)
#define ANIM_MOVE_LERP_POS (16)
#define ANIM_MOVE_LERP_ROT (2 * DEG2SHORT)
void Item::animProcess(bool movement)
{
if (models[type].count <= 0) {
return; // TODO sprite animation
}
ASSERT(models[type].count > 0);
const Anim* anim = level.anims + animIndex;
@@ -311,6 +370,41 @@ void Item::updateAnim(bool movement)
#endif
}
bool Item::animIsEnd(int32 offset) const
{
return frameIndex == level.anims[animIndex].frameEnd - offset;
}
bool Item::moveTo(const vec3i &point, Item* item, bool lerp)
{
// lerp position
vec3i p = item->getRelative(point);
if (!lerp)
{
pos = p;
angle = item->angle;
return true;
}
vec3i posDelta = p - pos;
int32 dist = phd_sqrt(X_SQR(posDelta.x) + X_SQR(posDelta.y) + X_SQR(posDelta.z));
if (dist > ANIM_MOVE_LERP_POS) {
pos += (posDelta * ANIM_MOVE_LERP_POS) / dist;
} else {
pos = p;
}
// lerp rotation
angle.x = angleLerp(angle.x, item->angle.x, ANIM_MOVE_LERP_ROT);
angle.y = angleLerp(angle.y, item->angle.y, ANIM_MOVE_LERP_ROT);
angle.z = angleLerp(angle.z, item->angle.z, ANIM_MOVE_LERP_ROT);
return (pos == p && angle == item->angle);
}
Item* Item::add(ItemType type, Room* room, const vec3i &pos, int32 angleY)
{
if (!Item::sFirstFree) {
@@ -324,7 +418,7 @@ Item* Item::add(ItemType type, Room* room, const vec3i &pos, int32 angleY)
item->type = type;
item->pos = pos;
item->angle.y = angleY;
item->intensity = 0;
item->intensity = 128;
item->init(room);
@@ -342,7 +436,7 @@ void Item::remove()
void Item::activate()
{
ASSERT(!flags.active)
//ASSERT(!flags.active)
flags.active = true;
@@ -389,62 +483,47 @@ void Item::updateRoom(int32 offset)
}
const Sector* sector = room->getSector(pos.x, pos.z);
floor = sector->getFloor(pos.x, pos.y, pos.z);
roomFloor = sector->getFloor(pos.x, pos.y, pos.z);
}
int32 Item::calcLighting(const Bounds& box) const
vec3i Item::getRelative(const vec3i &point) const
{
matrixPush();
Matrix &m = matrixGet();
m[0][3] = m[1][3] = m[2][3] = 0;
matrixSetIdentity();
matrixRotateYXZ(angle.x, angle.y, angle.z);
vec3i p((box.maxX + box.minX) >> 1,
(box.maxY + box.minY) >> 1,
(box.maxZ + box.minZ) >> 1);
vec3i p;
p.x = pos.x + (DP33(m[0], point) >> FIXED_SHIFT);
p.y = pos.y + (DP33(m[1], point) >> FIXED_SHIFT);
p.z = pos.z + (DP33(m[2], point) >> FIXED_SHIFT);
matrixTranslate(p);
p = vec3i(m[0][3] >> FIXED_SHIFT,
m[1][3] >> FIXED_SHIFT,
m[2][3] >> FIXED_SHIFT) + pos;
matrixPop();
const RoomInfo* info = room->info;
return p;
}
if (!info->lightsCount) {
return info->ambient << 5;
int32 Item::getWaterLevel()
{
const Sector* sector = room->getWaterSector(pos.x, pos.z);
if (sector) {
return sector->ceiling * 256;
}
int32 ambient = 8191 - (info->ambient << 5);
int32 maxLum = 0;
return WALL;
}
for (int i = 0; i < info->lightsCount; i++)
{
const Light* light = room->data.lights + i;
int32 Item::getWaterDepth()
{
const Sector* sector = room->getWaterSector(pos.x, pos.z);
// TODO preprocess align
vec3i pos;
pos.x = light->pos.x + (info->x << 8);
pos.y = light->pos.y;
pos.z = light->pos.z + (info->z << 8);
int32 radius = light->radius << 8;
int32 intensity = light->intensity << 5;
vec3i d = p - pos;
int32 dist = dot(d, d) >> 12;
int32 att = X_SQR(radius) >> 12;
int32 lum = (intensity * att) / (dist + att) + ambient;
if (lum > maxLum)
{
maxLum = lum;
}
if (sector) {
return sector->getFloor(pos.x, pos.y, pos.z) - (sector->ceiling * 256);
}
return 8191 - ((maxLum + ambient) >> 1);
return WALL;
}
#include "lara.h"
@@ -506,8 +585,7 @@ void Item::draw()
void Item::collide(Lara* lara, CollisionInfo* cinfo)
{
UNUSED(lara);
UNUSED(cinfo);
// empty
}
Item* Item::init(Room* room)
@@ -547,7 +625,7 @@ Item* Item::init(Room* room)
INIT_ITEM( NATLA , Natla );
INIT_ITEM( ADAM , Adam );
INIT_ITEM( TRAP_FLOOR , TrapFloor );
// INIT_ITEM( TRAP_SWING_BLADE , ??? );
INIT_ITEM( TRAP_SWING_BLADE , TrapSwingBlade );
// INIT_ITEM( TRAP_SPIKES , ??? );
// INIT_ITEM( TRAP_BOULDER , ??? );
INIT_ITEM( DART , Dart );
@@ -559,10 +637,10 @@ Item* Item::init(Room* room)
// INIT_ITEM( HAMMER_BLOCK , ??? );
// INIT_ITEM( LIGHTNING , ??? );
// INIT_ITEM( MOVING_OBJECT , ??? );
// INIT_ITEM( BLOCK_1 , ??? );
// INIT_ITEM( BLOCK_2 , ??? );
// INIT_ITEM( BLOCK_3 , ??? );
// INIT_ITEM( BLOCK_4 , ??? );
INIT_ITEM( BLOCK_1 , Block );
INIT_ITEM( BLOCK_2 , Block );
INIT_ITEM( BLOCK_3 , Block );
INIT_ITEM( BLOCK_4 , Block );
// INIT_ITEM( MOVING_BLOCK , ??? );
// INIT_ITEM( TRAP_CEILING_1 , ??? );
// INIT_ITEM( TRAP_CEILING_2 , ??? );
@@ -576,12 +654,12 @@ Item* Item::init(Room* room)
INIT_ITEM( DOOR_6 , Door );
INIT_ITEM( DOOR_7 , Door );
INIT_ITEM( DOOR_8 , Door );
// INIT_ITEM( TRAP_DOOR_1 , ??? );
// INIT_ITEM( TRAP_DOOR_2 , ??? );
INIT_ITEM( TRAP_DOOR_1 , TrapDoor );
INIT_ITEM( TRAP_DOOR_2 , TrapDoor );
// INIT_ITEM( UNUSED_3 , ??? );
// INIT_ITEM( BRIDGE_FLAT , ??? );
// INIT_ITEM( BRIDGE_TILT1 , ??? );
// INIT_ITEM( BRIDGE_TILT2 , ??? );
// INIT_ITEM( BRIDGE_TILT_1 , ??? );
// INIT_ITEM( BRIDGE_TILT_2 , ??? );
// INIT_ITEM( INV_PASSPORT , ??? );
// INIT_ITEM( INV_COMPASS , ??? );
// INIT_ITEM( INV_HOME , ??? );
@@ -629,10 +707,10 @@ Item* Item::init(Room* room)
// INIT_ITEM( INV_PUZZLE_2 , ??? );
// INIT_ITEM( INV_PUZZLE_3 , ??? );
// INIT_ITEM( INV_PUZZLE_4 , ??? );
// INIT_ITEM( PUZZLE_HOLE_1 , ??? );
// INIT_ITEM( PUZZLE_HOLE_2 , ??? );
// INIT_ITEM( PUZZLE_HOLE_3 , ??? );
// INIT_ITEM( PUZZLE_HOLE_4 , ??? );
INIT_ITEM( PUZZLEHOLE_1 , PuzzleHole );
INIT_ITEM( PUZZLEHOLE_2 , PuzzleHole );
INIT_ITEM( PUZZLEHOLE_3 , PuzzleHole );
INIT_ITEM( PUZZLEHOLE_4 , PuzzleHole );
// INIT_ITEM( PUZZLE_DONE_1 , ??? );
// INIT_ITEM( PUZZLE_DONE_2 , ??? );
// INIT_ITEM( PUZZLE_DONE_3 , ??? );
@@ -648,10 +726,10 @@ Item* Item::init(Room* room)
// INIT_ITEM( INV_KEY_ITEM_2 , ??? );
// INIT_ITEM( INV_KEY_ITEM_3 , ??? );
// INIT_ITEM( INV_KEY_ITEM_4 , ??? );
// INIT_ITEM( KEY_HOLE_1 , ??? );
// INIT_ITEM( KEY_HOLE_2 , ??? );
// INIT_ITEM( KEY_HOLE_3 , ??? );
// INIT_ITEM( KEY_HOLE_4 , ??? );
INIT_ITEM( KEYHOLE_1 , KeyHole );
INIT_ITEM( KEYHOLE_2 , KeyHole );
INIT_ITEM( KEYHOLE_3 , KeyHole );
INIT_ITEM( KEYHOLE_4 , KeyHole );
// INIT_ITEM( UNUSED_4 , ??? );
// INIT_ITEM( UNUSED_5 , ??? );
// INIT_ITEM( SCION_PICKUP_QUALOPEC , ??? );
@@ -681,16 +759,16 @@ Item* Item::init(Room* room)
// INIT_ITEM( UNUSED_13 , ??? );
// INIT_ITEM( UNUSED_14 , ??? );
INIT_ITEM( VIEW_TARGET , ViewTarget );
// INIT_ITEM( WATERFALL , ??? );
INIT_ITEM( WATERFALL , Waterfall );
// INIT_ITEM( NATLA_BULLET , ??? );
// INIT_ITEM( MUTANT_BULLET , ??? );
// INIT_ITEM( CENTAUR_BULLET , ??? );
// INIT_ITEM( UNUSED_15 , ??? );
// INIT_ITEM( UNUSED_16 , ??? );
// INIT_ITEM( LAVA_PARTICLE , ??? );
// INIT_ITEM( TRAP_LAVA_EMITTER , ??? );
INIT_ITEM( LAVA_EMITTER , LavaEmitter );
// INIT_ITEM( FLAME , ??? );
// INIT_ITEM( TRAP_FLAME_EMITTER , ??? );
// INIT_ITEM( FLAME_EMITTER , ??? );
// INIT_ITEM( TRAP_LAVA , ??? );
// INIT_ITEM( MUTANT_EGG_BIG , ??? );
// INIT_ITEM( BOAT , ??? );

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
Level level;
const Texture* textures;
const Sprite* sprites;
const uint8* tiles;
#ifndef MODE_PAL
@@ -16,13 +16,14 @@ IWRAM_DATA uint8 lightmap[256 * 32]; // IWRAM 8k
EWRAM_DATA Item items[MAX_ITEMS];
#define MAX_DYN_SECTORS 1024
#define MAX_DYN_SECTORS (1024*3)
int32 dynSectorsCount;
EWRAM_DATA Sector dynSectors[MAX_DYN_SECTORS]; // EWRAM 8k
EWRAM_DATA Texture textures[MAX_TEXTURES];
EWRAM_DATA Room rooms[MAX_ROOMS];
EWRAM_DATA Model models[MAX_MODELS];
EWRAM_DATA StaticMesh staticMeshes[MAX_STATIC_MESHES];
EWRAM_DATA FixedCamera cameras[MAX_CAMERAS];
Item* Item::sFirstActive;
Item* Item::sFirstFree;
@@ -93,7 +94,10 @@ void readLevel(const uint8* data)
tiles = level.tiles;
textures = level.textures;
// prepare textures (required by anim tex logic)
memcpy(textures, level.textures, level.texturesCount * sizeof(Texture));
sprites = level.sprites;
// prepare models // TODO prerocess
memset(models, 0, sizeof(models));
@@ -126,6 +130,9 @@ void readLevel(const uint8* data)
m->start = spriteSeq->start;
}
// prepare fixed cameras
memcpy(cameras, level.cameras, level.camerasCount * sizeof(FixedCamera));
// prepare free list
for (int32 i = MAX_ITEMS - 1; i >= level.itemsCount; i--)
{

View File

@@ -1,11 +1,13 @@
#if defined(_WIN32) || defined(__DOS__)
void* LEVEL1_PKD;
void* TRACK_13_WAV;
const void* TRACK_13_WAV;
const void* levelData;
#define LEVEL_NAME "LEVEL1.PKD"
#elif defined(__GBA__)
#include "LEVEL1_PKD.h"
#include "TRACK_13_WAV.h"
#include "LEVEL1_PKD.h"
const void* levelData = LEVEL1_PKD;
#elif defined(__TNS__)
void* LEVEL1_PHD;
const void* levelData;
#endif
#include "game.h"
@@ -41,11 +43,22 @@ int32 fpsCounter = 0;
memcpy(MEM_PAL_BG, palette, 256 * 2);
#endif
}
int32 osGetSystemTimeMS()
{
return GetTickCount();
}
#elif defined(__GBA__)
void paletteSet(const uint16* palette)
{
memcpy((uint16*)MEM_PAL_BG, palette, 256 * 2);
}
int32 osGetSystemTimeMS()
{
return 0; // TODO
}
#elif defined(__TNS__)
unsigned int osTime;
volatile unsigned int *timerBUS;
@@ -67,11 +80,16 @@ int32 fpsCounter = 0;
osTime = *timerCLK;
}
int GetTickCount()
int32 GetTickCount()
{
return (osTime - *timerCLK) / 33;
}
int32 osGetSystemTimeMS()
{
return *timerCLK / 33;
}
void paletteSet(uint16* palette)
{
memcpy((uint16*)0xC0000200, palette, 256 * 2);
@@ -419,7 +437,7 @@ int main(void) {
{
// level1
#if defined(_WIN32) || defined(__DOS__)
FILE *f = fopen("data/LEVEL1.PKD", "rb");
FILE *f = fopen("data/" LEVEL_NAME, "rb");
#elif defined(__TNS__)
FILE *f = fopen("/documents/OpenLara/LEVEL1.PHD.tns", "rb");
#else
@@ -430,12 +448,16 @@ int main(void) {
return 0;
}
fseek(f, 0, SEEK_END);
int32 size = ftell(f);
fseek(f, 0, SEEK_SET);
LEVEL1_PKD = new uint8[size];
fread(LEVEL1_PKD, 1, size, f);
fclose(f);
{
fseek(f, 0, SEEK_END);
int32 size = ftell(f);
fseek(f, 0, SEEK_SET);
uint8* data = new uint8[size];
fread(data, 1, size, f);
fclose(f);
levelData = data;
}
// track 13
#if defined(_WIN32) || defined(__DOS__)
@@ -448,16 +470,14 @@ int main(void) {
fseek(f, 0, SEEK_END);
int32 size = ftell(f);
fseek(f, 0, SEEK_SET);
TRACK_13_WAV = new uint8[size];
fread(TRACK_13_WAV, 1, size, f);
uint8* data = new uint8[size];
fread(data, 1, size, f);
fclose(f);
TRACK_13_WAV = data;
}
#endif
}
#elif defined(__GBA__)
// set low latency mode via WAITCNT register (thanks to GValiente)
REG_WSCNT = WS_ROM0_N2 | WS_ROM0_S1 | WS_PREFETCH;
//*(vu32*)(REG_BASE+0x0800) = 0x0E000020; // Undocumented - Internal Memory Control (R/W)
#endif
#if defined(_WIN32)
@@ -507,6 +527,30 @@ int main(void) {
//uint16 &GreenSwap = *(uint16*)0x4000002;
//GreenSwap = 1;
// set low latency mode via WAITCNT register (thanks to GValiente)
REG_WSCNT = WS_ROM0_N2 | WS_ROM0_S1 | WS_PREFETCH; // fast ROM
// Undocumented - Internal Memory Control (R/W)
#define MEM_CHECK_MAGIC 14021968
vu32& fastAccessReg = *(vu32*)(REG_BASE+0x0800);
fastAccessReg = 0x0E000020; // fast EWRAM
vu32* fastAccessMem = (vu32*)soundBufferA; // check EWRAM access
// write
for (int32 i = 0; i < 16; i++)
{
fastAccessMem[i] = MEM_CHECK_MAGIC + i;
}
// read
for (int32 i = 0; i < 16; i++)
{
if (fastAccessMem[i] != vu32(MEM_CHECK_MAGIC + i))
{
fastAccessReg = 0x0D000020; // device doesn't support this feature, revert reg value
}
}
soundInit();
game.init();

View File

@@ -3,6 +3,7 @@
#include "item.h"
#include "lara.h"
#include "inventory.h"
vec3i getBlockOffset(int16 angleY, int32 offset)
{
@@ -27,6 +28,31 @@ namespace Limits
Bounds( -200, 200, 0, 0, 312, 512 ),
vec3s( 10 * DEG2SHORT, 30 * DEG2SHORT, 10 * DEG2SHORT )
};
static const Limit SWITCH_UW = {
Bounds( -1024, 1024, -1024, 1024, -1024, 1024 ),
vec3s( 80 * DEG2SHORT, 80 * DEG2SHORT, 80 * DEG2SHORT )
};
static const Limit BLOCK = {
Bounds( -300, 300, 0, 0, -692, -512 ),
vec3s( 10 * DEG2SHORT, 30 * DEG2SHORT, 10 * DEG2SHORT )
};
static const Limit PICKUP = {
Bounds( -256, 256, -100, 100, -256, 100 ),
vec3s( 10 * DEG2SHORT, 0, 0 )
};
static const Limit PICKUP_UW = {
Bounds( -512, 512, -512, 512, -512, 512 ),
vec3s( 45 * DEG2SHORT, 45 * DEG2SHORT, 45 * DEG2SHORT )
};
static const Limit HOLE = {
Bounds( -200, 200, 0, 0, 312, 512 ),
vec3s( 10 * DEG2SHORT, 30 * DEG2SHORT, 10 * DEG2SHORT )
};
};
@@ -36,7 +62,7 @@ struct Object : Item
virtual void update()
{
updateAnim();
animProcess();
}
bool isActive()
@@ -88,6 +114,21 @@ struct ViewTarget : Object
};
struct Waterfall : Object
{
Waterfall(Room* room) : Object(room) {}
virtual void draw() {}
};
struct LavaEmitter : Object
{
LavaEmitter(Room* room) : Object(room) {}
virtual void draw() {}
};
struct Door : Object
{
enum {
@@ -117,13 +158,12 @@ struct Door : Object
}
}
updateAnim();
animProcess();
}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
UNUSED(lara);
UNUSED(cinfo);
// TODO door collision
}
void action(bool close)
@@ -160,6 +200,8 @@ struct Door : Object
nextRoom = sector->getNextRoom();
}
// TODO modify level.boxes
if (!behind && nextRoom) {
activate(close, true, nextRoom, pos.x, pos.z); // use sector from item pos
}
@@ -167,6 +209,32 @@ struct Door : Object
};
struct TrapDoor : Object
{
enum {
STATE_CLOSE,
STATE_OPEN,
};
TrapDoor(Room* room) : Object(room) {}
virtual void update()
{
if (isActive()) {
if (state == STATE_CLOSE) {
goalState = STATE_OPEN;
}
} else {
if (state == STATE_OPEN) {
goalState = STATE_CLOSE;
}
}
animProcess();
}
};
struct Switch : Object
{
enum {
@@ -189,12 +257,13 @@ struct Switch : Object
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
UNUSED(cinfo);
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION))
return;
if (lara->state != Lara::STOP)
if (lara->state != Lara::STATE_STOP)
return;
if (flags.status != ITEM_FLAGS_STATUS_NONE)
@@ -207,22 +276,13 @@ struct Switch : Object
ASSERT(state == STATE_DOWN || state == STATE_UP);
if (state == STATE_DOWN) {
lara->goalState = Lara::SWITCH_DOWN;
goalState = STATE_UP;
} else {
lara->goalState = Lara::SWITCH_UP;
goalState = STATE_DOWN;
}
bool isDown = (state == STATE_DOWN);
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
goalState = isDown ? STATE_UP : STATE_DOWN;
lara->animSkip(isDown ? Lara::STATE_SWITCH_DOWN : Lara::STATE_SWITCH_UP, Lara::STATE_STOP, true);
activate();
lara->skipAnim();
updateAnim();
lara->goalState = Lara::STOP;
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
lara->weaponState = WEAPON_STATE_BUSY;
}
bool use(int32 t)
@@ -254,9 +314,30 @@ struct SwitchWater : Switch
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
UNUSED(lara);
UNUSED(cinfo);
// TODO
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION))
return;
if (lara->state != Lara::STATE_UW_TREAD)
return;
if (!checkLimit(lara, Limits::SWITCH_UW))
return;
if (!lara->moveTo(vec3i(0, 0, 108), this, true))
return;
lara->vSpeed = 0; // underwater speed
goalState = (state == STATE_UP) ? STATE_DOWN : STATE_UP;
lara->animSkip(Lara::STATE_SWITCH_DOWN, Lara::STATE_UW_TREAD, true);
activate();
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
//TODO TR2+
//lara->weaponState = WEAPON_STATE_BUSY;
}
};
@@ -265,9 +346,9 @@ struct Key : Object
{
Key(Room* room) : Object(room) {}
bool use()
bool use(Item* lara)
{
if (flags.status == ITEM_FLAGS_STATUS_ACTIVE) // TODO check weapons
if (flags.status == ITEM_FLAGS_STATUS_ACTIVE && lara->weaponState == WEAPON_STATE_FREE) // TODO check weapons
{
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
return true;
@@ -290,6 +371,81 @@ struct Pickup : Object
}
return false;
}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
angle.y = lara->angle.y;
angle.z = 0;
if (lara->waterState == WATER_STATE_ABOVE || lara->waterState == WATER_STATE_WADE)
{
angle.x = 0;
if (!checkLimit(lara, Limits::PICKUP))
return;
if (lara->state == Lara::STATE_PICKUP)
{
if (!lara->animIsEnd(23))
return;
inventory.add((ItemType)type);
gSaveGame.pickups++;
room->remove(this);
flags.status = ITEM_FLAGS_STATUS_INVISIBLE;
}
else if (lara->state == Lara::STATE_STOP)
{
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION))
return;
if (!lara->moveTo(vec3i(0, 0, -100), this, false))
return;
lara->animSkip(Lara::STATE_PICKUP, Lara::STATE_STOP);
lara->weaponState = WEAPON_STATE_BUSY;
}
}
if (lara->waterState == WATER_STATE_UNDER)
{
angle.x = -25 * DEG2SHORT;
if (!checkLimit(lara, Limits::PICKUP_UW))
return;
if (lara->state == Lara::STATE_PICKUP)
{
if (!lara->animIsEnd(14))
return;
inventory.add((ItemType)type);
gSaveGame.pickups++;
room->remove(this);
flags.status = ITEM_FLAGS_STATUS_INVISIBLE;
}
else if (lara->state == Lara::STATE_UW_TREAD)
{
// TODO TR2+
//if (lara->weaponState != WEAPON_STATE_FREE)
// return;
if (!(lara->input & IN_ACTION))
return;
if (!lara->moveTo(vec3i(0, -200, -350), this, true))
return;
lara->animSkip(Lara::STATE_PICKUP, Lara::STATE_UW_TREAD);
// TODO TR2+
//lara->weaponState = WEAPON_STATE_BUSY; // TODO check CMD_EMPTY event
}
}
}
};
@@ -298,9 +454,9 @@ bool useSwitch(Item* item, int32 timer)
return ((Switch*)item)->use(timer);
}
bool useKey(Item* item)
bool useKey(Item* item, Item* lara)
{
return ((Key*)item)->use();
return ((Key*)item)->use(lara);
}
bool usePickup(Item* item)
@@ -309,6 +465,98 @@ bool usePickup(Item* item)
}
vec3i tmpPos;
struct Hole : Object // parent class for KeyHole and PuzzleHole
{
Hole(Room* room) : Object(room) {}
void apply(int32 offset, Lara* lara, Lara::State stateUse)
{
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (flags.status != ITEM_FLAGS_STATUS_NONE)
return;
if (lara->state != Lara::STATE_STOP || lara->animIndex != Lara::ANIM_STAND_NORMAL)
return;
if (!(lara->input & IN_ACTION) && (inventory.useSlot == SLOT_MAX))
return;
if (!checkLimit(lara, Limits::HOLE))
return;
if (inventory.useSlot == SLOT_MAX)
{
if (inventory.numKeys > 0) {
inventory.show(lara, this);
return;
}
} else {
if (inventory.applyItem(this))
{
lara->moveTo(vec3i(0, 0, offset), this, false);
lara->animSkip(stateUse, Lara::STATE_STOP);
lara->weaponState = WEAPON_STATE_BUSY;
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
return;
}
tmpPos.x = ~lara->pos.x;
inventory.useSlot = SLOT_MAX;
}
if (tmpPos != lara->pos)
{
tmpPos = lara->pos;
soundPlay(SND_NO, lara->pos);
}
}
};
struct KeyHole : Hole
{
KeyHole(Room* room) : Hole(room) {}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
apply(362, lara, Lara::STATE_USE_KEY);
}
};
struct PuzzleHole : Hole
{
PuzzleHole(Room* room) : Hole(room) {}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
if (lara->state == Lara::STATE_USE_PUZZLE)
{
if (!checkLimit(lara, Limits::HOLE))
return;
if (!lara->animIsEnd(28))
return;
switch (type) {
case ITEM_PUZZLEHOLE_1 : type = ITEM_PUZZLEHOLE_DONE_1; break;
case ITEM_PUZZLEHOLE_2 : type = ITEM_PUZZLEHOLE_DONE_2; break;
case ITEM_PUZZLEHOLE_3 : type = ITEM_PUZZLEHOLE_DONE_3; break;
case ITEM_PUZZLEHOLE_4 : type = ITEM_PUZZLEHOLE_DONE_4; break;
}
return;
}
apply(327, lara, Lara::STATE_USE_PUZZLE);
}
};
struct TrapFloor : Object
{
enum {
@@ -344,7 +592,7 @@ struct TrapFloor : Object
break;
}
updateAnim();
animProcess();
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
{
@@ -354,9 +602,9 @@ struct TrapFloor : Object
updateRoom();
if (state == STATE_FALL && pos.y >= floor)
if (state == STATE_FALL && pos.y >= roomFloor)
{
pos.y = floor;
pos.y = roomFloor;
vSpeed = 0;
flags.gravity = false;
goalState = STATE_DOWN;
@@ -365,6 +613,44 @@ struct TrapFloor : Object
};
struct TrapSwingBlade : Object
{
enum {
STATE_STATIC,
STATE_BEGIN,
STATE_SWING,
STATE_END,
};
TrapSwingBlade(Room* room) : Object(room)
{
flags.shadow = true;
}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
//
}
virtual void update()
{
if (isActive()) {
if (state == STATE_STATIC) {
goalState = STATE_SWING;
}
} else {
if (state == STATE_SWING) {
goalState = STATE_STATIC;
}
}
// TODO damage
animProcess();
}
};
struct Dart : Object
{
Dart(Room* room) : Object(room)
@@ -379,10 +665,10 @@ struct Dart : Object
{
// TODO collide with Lara
updateAnim();
animProcess();
updateRoom();
if (pos.y >= floor)
if (pos.y >= roomFloor)
{
// TODO create spark
remove();
@@ -420,12 +706,206 @@ struct TrapDartEmitter : Object
if (dart)
{
dart->intensity = 0;
dart->flags.status = ITEM_FLAGS_STATUS_ACTIVE;
dart->activate();
}
}
updateAnim();
animProcess();
}
};
struct Block : Object
{
enum {
STATE_NONE,
STATE_READY,
STATE_PUSH,
STATE_PULL,
};
Block(Room* room) : Object(room)
{
if (flags.status != ITEM_FLAGS_STATUS_INVISIBLE) {
updateFloor(-1024);
}
}
void updateFloor(int32 offset)
{
room->modify();
Sector* sector = (Sector*)room->getSector(pos.x, pos.z);
if (sector->floor == NO_FLOOR) {
sector->floor = sector->ceiling + (offset >> 8);
} else {
sector->floor += (offset >> 8);
if (sector->floor == sector->ceiling) {
sector->floor = NO_FLOOR;
}
}
// TODO modify level.boxes
}
bool checkBlocking()
{
const Sector* sector = room->getSector(pos.x, pos.z);
return (sector->floor == NO_FLOOR) || ((sector->floor << 8) + 1024 == pos.y);
}
bool checkObstacles(int32 x, int32 z, int32 height)
{
Room* nextRoom = room->getRoom(x, pos.y, z);
const Sector* sector = nextRoom->getSector(x, z);
int32 floor = pos.y;
int32 ceiling = pos.y - height;
if ((sector->floor << 8) != floor)
return false;
nextRoom = nextRoom->getRoom(x, ceiling, z);
sector = nextRoom->getSector(x, z);
if ((sector->ceiling << 8) > ceiling)
return false;
return true;
}
bool checkPush()
{
if (!checkBlocking())
return false;
vec3i offset = getBlockOffset(angle.y, -1024);
return checkObstacles(pos.x + offset.x, pos.z + offset.z, 1024);
}
bool checkPull(Item* lara)
{
if (!checkBlocking())
return false;
vec3i offset = getBlockOffset(angle.y, 1024);
if (!checkObstacles(pos.x + offset.x, pos.z + offset.z, 1024))
return false;
return checkObstacles(lara->pos.x + offset.x, lara->pos.z + offset.z, LARA_HEIGHT);
}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION))
return;
if (flags.status == ITEM_FLAGS_STATUS_ACTIVE)
return;
if (lara->pos.y != pos.y)
return;
uint16 quadrant = uint16(lara->angle.y + ANGLE_45) / ANGLE_90;
if (lara->state == Lara::STATE_BLOCK_READY)
{
if (!lara->animIsEnd(0))
return;
if (!checkLimit(lara, Limits::BLOCK))
return;
if (lara->input & IN_UP)
{
if (!checkPush())
return;
lara->goalState = Lara::STATE_BLOCK_PUSH;
goalState = STATE_PUSH;
}
else if (lara->input & IN_DOWN)
{
if (!checkPull(lara))
return;
lara->goalState = Lara::STATE_BLOCK_PULL;
goalState = STATE_PULL;
}
else
{
return;
}
updateFloor(1024);
activate();
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
animProcess();
lara->animProcess();
}
if (lara->state == Lara::STATE_STOP)
{
if (lara->input & (IN_UP | IN_DOWN))
return;
angle.y = quadrant * ANGLE_90;
if (!checkLimit(lara, Limits::BLOCK))
return;
lara->goalState = Lara::STATE_BLOCK_READY;
lara->angle.y = angle.y;
lara->alignWall(LARA_RADIUS);
lara->animProcess();
}
}
virtual void update()
{
if (flags.once)
{
updateFloor(1024);
remove();
return;
}
animProcess();
updateRoom(); // it'll get roomFloor and gLastFloorData
if (pos.y > roomFloor)
{
flags.gravity = true;
}
else if (flags.gravity)
{
flags.gravity = false;
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
pos.y = roomFloor;
// TODO EarthQuake + playSound 70 (Thor room)
}
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
{
deactivate();
flags.status = ITEM_FLAGS_STATUS_NONE;
updateFloor(-1024);
checkTrigger(gLastFloorData, NULL);
}
}
};

View File

@@ -65,8 +65,10 @@ SP_RDT = 12
ldrb indexB, [TILE, indexB]
add t, dtdx
// cheap non-accurate alpha test, skip pixels pair if both are transparent
orrs indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
// cheap non-accurate alpha test, skip pixels pair if one or both are transparent
ands indexA, #255
andnes indexB, #255
orrne indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
ldrneb indexA, [LMAP, indexA]
ldrneb indexB, [LMAP, indexB, lsr #8]
orrne indexA, indexB, lsl #8
@@ -206,19 +208,19 @@ rasterizeFTA_mode4_asm:
.align_left:
tst tmp, #1 // if (tmp & 1)
beq .align_right
ldrb indexB, [tmp, #-1]! // read pal index from VRAM (byte)
and indexA, t, #0xFF00
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
add t, dtdx
ldrb indexA, [TILE, indexA]
ldrb indexA, [LMAP, indexA]
cmp indexA, #0
ldrneb indexB, [tmp, #-1] // read pal index from VRAM (byte)
ldrneb indexA, [LMAP, indexA]
orrne indexB, indexA, lsl #8
strneh indexB, [tmp]
add tmp, #2
add tmp, #1
add t, dtdx
subs width, #1 // width--
beq .scanline_end // if (width == 0)
@@ -226,7 +228,6 @@ rasterizeFTA_mode4_asm:
.align_right:
tst width, #1
beq .align_block_4px
ldrb indexB, [tmp, width]
sub Rt, dtdx
and indexA, Rt, #0xFF00
@@ -236,6 +237,7 @@ rasterizeFTA_mode4_asm:
cmp indexA, #0
ldrneb indexA, [LMAP, indexA]
ldrneb indexB, [tmp, width]
orrne indexB, indexA, indexB, lsl #8
strneh indexB, [tmp, width]

View File

@@ -91,8 +91,10 @@ SP_RDT = 20
ldrb indexB, [TILE, indexB]
add t, dtdx
// cheap non-accurate alpha test, skip pixels pair if both are transparent
orrs indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
// cheap non-accurate alpha test, skip pixels pair if one or both are transparent
ands indexA, #255
andnes indexB, #255
orrne indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
ldrneb indexA, [LMAP, indexA]
ldrneb indexB, [LMAP, indexB, lsr #8]
orrne indexA, indexB, lsl #8
@@ -256,19 +258,25 @@ rasterizeGTA_mode4_asm:
.align_left:
tst ptr, #1 // if (ptr & 1)
beq .align_right
ldrb indexB, [ptr, #-1]! // read pal index from VRAM (byte)
bic LMAP, g, #255
add g, dgdx, asr #1
and indexA, t, #0xFF00
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
ldrb indexA, [TILE, indexA]
cmp indexA, #0
beq .skip_left
bic LMAP, g, #255
ldrb indexA, [LMAP, indexA]
ldrb indexB, [ptr, #-1] // read pal index from VRAM (byte)
orr indexB, indexA, lsl #8
strh indexB, [ptr], #2
strh indexB, [ptr]
.skip_left:
add ptr, #1
add t, dtdx
add g, dgdx, asr #1
subs width, #1 // width--
beq .scanline_end // if (width == 0)
@@ -276,15 +284,19 @@ rasterizeGTA_mode4_asm:
.align_right:
tst width, #1
beq .align_block_4px
ldrb indexB, [ptr, width]
subs width, #1 // width--
sub width, #1 // width--
mla Rti, width, dtdx, t // Rti = width * dtdx + t
and indexA, Rti, #0xFF00
orr indexA, Rti, lsr #24 // res = (t & 0xFF00) | (t >> 24)
ldrb indexA, [TILE, indexA]
cmp indexA, #0
beq .skip_right
asr Rgi, dgdx, #1
mla Rgi, width, Rgi, g // Rgi = width * (dgdx / 2) + g
bic LMAP, Rgi, #255
@@ -294,6 +306,8 @@ rasterizeGTA_mode4_asm:
orr indexB, indexA, indexB, lsl #8
strh indexB, [ptr, width]
.skip_right:
cmp width, #0 // width--
beq .scanline_end // if (width == 0)
.align_block_4px:

View File

@@ -5,6 +5,7 @@
extern uint8 lightmap[256 * 32];
extern const uint8* tile;
extern const Sprite* sprite;
#if defined(__GBA__)
#define USE_ASM
@@ -29,6 +30,7 @@ extern const uint8* tile;
#define rasterizeGT rasterizeGT_mode4_asm
#define rasterizeFTA rasterizeFTA_mode4_asm
#define rasterizeGTA rasterizeGTA_mode4_asm
#define rasterizeSprite rasterizeSprite_mode4_c
#else
#define rasterizeS rasterizeS_mode4_c
#define rasterizeF rasterizeF_mode4_c
@@ -37,6 +39,7 @@ extern const uint8* tile;
#define rasterizeGT rasterizeGT_mode4_c
#define rasterizeFTA rasterizeFTA_mode4_c
#define rasterizeGTA rasterizeGTA_mode4_c
#define rasterizeSprite rasterizeSprite_mode4_c
void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
{
@@ -517,7 +520,7 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
// 8-bit fractional part precision for Gouraud component
// has some artifacts but allow to save one reg for inner loop
// for aligned by 64k address of lightmap array
// with aligned by 64k address of lightmap array
while (1)
{
@@ -528,7 +531,7 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
if (N->v.y < L->v.y) return;
Lh = N->v.y - L->v.y;
Lx = L->v.x;
Lx = L->v.x;
Lg = L->v.g;
Lt = L->t.uv;
@@ -800,8 +803,295 @@ void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
{
rasterizeGT(pixel, L, R);
}
#ifdef ALIGNED_LIGHTMAP
ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned
#endif
int32 Lh = 0, Rh = 0;
int32 Lx, Rx, Lg, Rg, Ldx = 0, Rdx = 0, Ldg = 0, Rdg = 0;
uint32 Lt, Rt, Ldt, Rdt;
Ldt = 0;
Rdt = 0;
// 8-bit fractional part precision for Gouraud component
// has some artifacts but allow to save one reg for inner loop
// with aligned by 64k address of lightmap array
while (1)
{
while (!Lh)
{
const VertexUV* N = L->prev;
if (N->v.y < L->v.y) return;
Lh = N->v.y - L->v.y;
Lx = L->v.x;
Lg = L->v.g;
Lt = L->t.uv;
if (Lh > 1)
{
int32 tmp = FixedInvU(Lh);
Ldx = tmp * (N->v.x - Lx);
Ldg = tmp * (N->v.g - Lg) >> 8;
uint32 duv = N->t.uv - Lt;
uint32 du = tmp * int16(duv >> 16);
uint32 dv = tmp * int16(duv);
Ldt = (du & 0xFFFF0000) | (dv >> 16);
}
Lx <<= 16;
Lg <<= 8;
L = N;
}
while (!Rh)
{
const VertexUV* N = R->next;
if (N->v.y < R->v.y) return;
Rh = N->v.y - R->v.y;
Rx = R->v.x;
Rg = R->v.g;
Rt = R->t.uv;
if (Rh > 1)
{
int32 tmp = FixedInvU(Rh);
Rdx = tmp * (N->v.x - Rx);
Rdg = tmp * (N->v.g - Rg) >> 8;
uint32 duv = N->t.uv - Rt;
uint32 du = tmp * int16(duv >> 16);
uint32 dv = tmp * int16(duv);
Rdt = (du & 0xFFFF0000) | (dv >> 16);
}
Rx <<= 16;
Rg <<= 8;
R = N;
}
int32 h = X_MIN(Lh, Rh);
Lh -= h;
Rh -= h;
while (h--)
{
int32 x1 = Lx >> 16;
int32 x2 = Rx >> 16;
int32 width = x2 - x1;
if (width > 0)
{
int32 tmp = FixedInvU(width);
int32 dgdx = tmp * (Rg - Lg) >> 15;
uint32 duv = Rt - Lt;
uint32 u = tmp * int16(duv >> 16);
uint32 v = tmp * int16(duv);
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
int32 g = Lg;
uint32 t = Lt;
volatile uint8* ptr = (uint8*)pixel + x1;
if (intptr_t(ptr) & 1)
{
ptr--;
uint8 indexB = tile[(t & 0xFF00) | (t >> 24)];
if (indexB) {
*(uint16*)ptr = *ptr | (lightmap[(g >> 8 << 8) | indexB] << 8);
}
ptr += 2;
t += dtdx;
g += dgdx >> 1;
width--;
}
if (width & 1)
{
uint32 tmp = Rt - dtdx;
uint8 indexA = tile[(tmp & 0xFF00) | (tmp >> 24)];
if (indexA) {
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | lightmap[(Rg >> 8 << 8) | indexA];
}
}
#ifdef ALIGNED_LIGHTMAP
g += intptr_t(lightmap);
#endif
width >>= 1;
while (width--)
{
#ifdef ALIGNED_LIGHTMAP
uint8 indexA = tile[(t & 0xFF00) | (t >> 24)];
t += dtdx;
uint8 indexB = tile[(t & 0xFF00) | (t >> 24)];
t += dtdx;
g += dgdx;
if (indexA && indexB) {
const uint8* LMAP = (uint8*)(g >> 8 << 8);
*(uint16*)ptr = LMAP[indexA] | (LMAP[indexB] << 8);
}
#else
uint8 indexA = tile[(t & 0xFF00) | (t >> 24)];
t += dtdx;
uint8 indexB = tile[(t & 0xFF00) | (t >> 24)];
t += dtdx;
g += dgdx;
if (indexA && indexB) {
*(uint16*)ptr = lightmap[(g >> 8 << 8) | indexA] | (lightmap[(g >> 8 << 8) | indexB] << 8);
}
#endif
ptr += 2;
}
}
pixel += VRAM_WIDTH;
Lx += Ldx;
Rx += Rdx;
Lg += Ldg;
Rg += Rdg;
Lt += Ldt;
Rt += Rdt;
}
}
}
#endif
// TODO ARM version
void rasterizeSprite_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
{
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
int32 w = R->v.x - L->v.x;
if (w <= 0) return;
int32 h = R->v.y - L->v.y;
if (h <= 0) return;
int32 u = L->t.u << 8;
int32 v = L->t.v << 8;
int32 du = (R->t.u << 8) / w;
int32 dv = (R->t.v << 8) / h;
if (L->v.y < 0)
{
pixel -= L->v.y * VRAM_WIDTH;
v -= L->v.y * dv;
h += L->v.y;
}
if (R->v.y > FRAME_HEIGHT)
{
h -= R->v.y - FRAME_HEIGHT;
}
uint8* ptr = (uint8*)pixel;
if (h <= 0) return;
ptr += L->v.x;
if (L->v.x < 0)
{
ptr -= L->v.x;
u -= L->v.x * du;
w += L->v.x;
}
if (R->v.x > FRAME_WIDTH)
{
w -= R->v.x - FRAME_WIDTH;
}
if (w <= 0) return;
bool alignL = intptr_t(ptr) & 1;
if (alignL)
{
ptr--;
w--;
}
bool alignR = w & 1;
if (alignR)
{
w--;
}
w >>= 1;
for (int32 y = 0; y < h; y++)
{
const uint8* xtile = tile + (v & 0xFF00);
volatile uint8* xptr = ptr;
int32 xu = u;
if (alignL)
{
uint8 indexB = ft_lightmap[xtile[xu >> 8]];
if (indexB) {
*(uint16*)xptr = *xptr | (indexB << 8);
}
xptr += 2;
xu += du;
}
for (int32 x = 0; x < w; x++)
{
uint8 indexA = ft_lightmap[xtile[xu >> 8]];
xu += du;
uint8 indexB = ft_lightmap[xtile[xu >> 8]];
xu += du;
if (indexA | indexB)
{
if (indexA == 0) indexA = xptr[0];
if (indexB == 0) indexB = xptr[1];
*(uint16*)xptr = indexA | (indexB << 8);
}
xptr += 2;
}
if (alignR)
{
uint8 indexA = ft_lightmap[xtile[xu >> 8]];
if (indexA) {
*(uint16*)xptr = indexA | (xptr[1] << 8);
}
}
v += dv;
ptr += FRAME_WIDTH;
}
}
#endif

View File

@@ -34,10 +34,16 @@ uint16 palette[256]; // IWRAM 0.5k
#endif
extern uint8 lightmap[256 * 32];
extern const Texture* textures;
extern Texture textures[MAX_TEXTURES];
extern const Sprite* sprites;
extern const uint8* tiles;
extern int32 lightAmbient;
extern int32 caustics[MAX_CAUSTICS];
extern int32 causticsRand[MAX_CAUSTICS];
extern int32 causticsFrame;
const uint8* tile;
const Sprite* sprite;
uint32 gVerticesCount = 0;
int32 gFacesCount = 0; // 1 is reserved as OT terminator
@@ -72,10 +78,11 @@ bool transformBoxRect(const Bounds* box, Rect* rect)
*rect = Rect( INT_MAX, INT_MAX, INT_MIN, INT_MIN );
for (int32 i = 0; i < 8; i++) {
for (int32 i = 0; i < 8; i++)
{
int32 z = DP43(m[2], v[i]);
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { // TODO znear clip
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) {
continue;
}
@@ -122,6 +129,13 @@ int32 boxIsVisible(const Bounds* box)
return rectIsVisible(&rect);
}
X_INLINE int32 classify(const Vertex &v, const Rect &clip) {
return (v.x < clip.x0 ? 1 : 0) |
(v.x > clip.x1 ? 2 : 0) |
(v.y < clip.y0 ? 4 : 0) |
(v.y > clip.y1 ? 8 : 0);
}
void transform(int32 vx, int32 vy, int32 vz, int32 vg)
{
ASSERT(gVerticesCount < MAX_VERTICES);
@@ -132,26 +146,16 @@ void transform(int32 vx, int32 vy, int32 vz, int32 vg)
int32 z = DP43c(m[2], vx, vy, vz);
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) // TODO znear clip
if (z < VIEW_MIN_F || z >= VIEW_MAX_F)
{
res.clip = 16;
res.clip = 32;
return;
}
int32 x = DP43c(m[0], vx, vy, vz);
int32 y = DP43c(m[1], vx, vy, vz);
int32 fogZ = z >> FIXED_SHIFT;
res.z = fogZ;
if (fogZ > FOG_MIN)
{
vg += (fogZ - FOG_MIN) << FOG_SHIFT;
if (vg > 8191) {
vg = 8191;
}
}
res.z = z >> FIXED_SHIFT;
res.g = vg >> 8;
PERSPECTIVE(x, y, z);
@@ -162,10 +166,10 @@ void transform(int32 vx, int32 vy, int32 vz, int32 vg)
res.x = x + (FRAME_WIDTH >> 1);
res.y = y + (FRAME_HEIGHT >> 1);
res.clip = enableClipping ? classify(res, viewport) : 0;
res.clip = classify(res, viewport); // enableClipping ? classify(res, viewport) : 0; TODO fix clip boxes for static meshes
}
void transformRoomVertex(const RoomVertex* v)
void transformRoomVertex(const RoomVertex* v, int32 caustics)
{
int32 vx = v->x << 10;
int32 vz = v->z << 10;
@@ -178,7 +182,7 @@ void transformRoomVertex(const RoomVertex* v)
if (vz < frustumAABB.minZ || vz > frustumAABB.maxZ ||
vx < frustumAABB.minX || vx > frustumAABB.maxX)
{
res.clip = 16;
res.clip = 32;
return;
}
#endif
@@ -189,10 +193,13 @@ void transformRoomVertex(const RoomVertex* v)
int32 z = DP43c(m[2], vx, vy, vz);
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) // TODO znear clip
if (z < VIEW_MIN_F || z >= VIEW_MAX_F)
{
if (z < VIEW_MIN_F) z = VIEW_MIN_F;
if (z >= VIEW_MAX_F) z = VIEW_MAX_F;
res.clip = 16;
return;
} else {
res.clip = 0;
}
int32 fogZ = z >> FIXED_SHIFT;
@@ -200,6 +207,10 @@ void transformRoomVertex(const RoomVertex* v)
int32 vg = v->g << 5;
if (caustics) {
vg = X_CLAMP(vg + caustics, 0, 8191);
}
if (fogZ > FOG_MIN)
{
vg += (fogZ - FOG_MIN) << FOG_SHIFT;
@@ -221,23 +232,32 @@ void transformRoomVertex(const RoomVertex* v)
res.x = x + (FRAME_WIDTH >> 1);
res.y = y + (FRAME_HEIGHT >> 1);
res.clip = classify(res, viewport);
res.clip |= classify(res, viewport);
}
void transformRoom(const RoomVertex* vertices, int32 vCount)
void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics)
{
int32 causticsValue = 0;
for (int32 i = 0; i < vCount; i++)
{
transformRoomVertex(vertices);
if (applyCaustics) {
causticsValue = caustics[(causticsRand[i & (MAX_CAUSTICS - 1)] + causticsFrame) & (MAX_CAUSTICS - 1)];
}
transformRoomVertex(vertices, causticsValue);
vertices++;
}
}
void transformMesh(const vec3s* vertices, int32 vCount, uint16 intensity)
void transformMesh(const vec3s* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal)
{
// TODO calc lighting for vNormal
for (int32 i = 0; i < vCount; i++)
{
transform(vertices->x, vertices->y, vertices->z, intensity);
ASSERT(!vIntensity || (vIntensity[i] + lightAmbient >= 0)); // ohhh, use X_CLAMP...
transform(vertices->x, vertices->y, vertices->z, vIntensity ? X_MIN(vIntensity[i] + lightAmbient, 8191) : lightAmbient);
vertices++;
}
}
@@ -313,7 +333,7 @@ void rasterize(const Face* face, const VertexUV *top)
#else
if (face->flags & FACE_COLORED) {
if (face->flags & FACE_FLAT) {
if (face->flags & FACE_SHADOW) {
if (face->flags & FACE_SPRITE) {
rasterizeS(pixel, top, top);
} else {
rasterizeF(pixel, top, top, face->flags & FACE_TEXTURE);
@@ -322,7 +342,9 @@ void rasterize(const Face* face, const VertexUV *top)
rasterizeG(pixel, top, top, face->flags & FACE_TEXTURE);
}
} else {
if (enableAlphaTest) {
if (face->flags & FACE_SPRITE) {
rasterizeSprite(pixel, top, top + 1);
} else if (enableAlphaTest) {
if (face->flags & FACE_FLAT) {
rasterizeFTA(pixel, top, top);
} else {
@@ -475,6 +497,14 @@ void drawPoly(Face* face, VertexUV* v)
rasterize(face, top);
}
void drawSprite(Face* face, VertexUV* v)
{
sprite = sprites + face->indices[1];
tile = tiles + (sprite->tile << 16);
rasterize(face, v);
}
void drawGlyph(const Sprite *sprite, int32 x, int32 y)
{
int32 w = sprite->r - sprite->l;
@@ -536,14 +566,17 @@ void drawGlyph(const Sprite *sprite, int32 x, int32 y)
}
}
X_INLINE void faceAddToOTable(Face* face, int32 depth)
X_INLINE Face* faceAdd(int32 depth)
{
ASSERT(depth < OT_SIZE);
Face* face = gFaces + gFacesCount++;
face->next = otFaces[depth];
otFaces[depth] = face;
if (depth < otMin) otMin = depth;
if (depth > otMax) otMax = depth;
return face;
}
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
@@ -556,17 +589,15 @@ void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
const Vertex* v3 = v + indices[2];
const Vertex* v4 = v + indices[3];
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16 || v4->clip == 16)
if (v1->clip & v2->clip & v3->clip & v4->clip)
return;
if (enableClipping)
{
if (v1->clip & v2->clip & v3->clip & v4->clip)
return;
int32 clip = (v1->clip | v2->clip | v3->clip | v4->clip);
if (clip & 32)
return;
if (v1->clip | v2->clip | v3->clip | v4->clip) {
flags |= FACE_CLIPPED;
}
if (clip) {
flags |= FACE_CLIPPED;
}
if (v1->g == v2->g && v1->g == v3->g && v1->g == v4->g) {
@@ -575,19 +606,12 @@ void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
int32 depth = X_MAX(v1->z, X_MAX(v2->z, X_MAX(v3->z, v4->z))) >> OT_SHIFT;
// z-bias hack for the shadow plane
if (flags & FACE_SHADOW) {
depth = X_MAX(0, depth - 8);
}
Face *f = gFaces + gFacesCount++;
faceAddToOTable(f, depth);
f->flags = uint16(flags);
f->indices[0] = startVertex + indices[0];
f->indices[1] = startVertex + indices[1];
f->indices[2] = startVertex + indices[2];
f->indices[3] = startVertex + indices[3];
Face* f = faceAdd(depth);
f->flags = uint16(flags);
f->indices[0] = v1 - gVertices;
f->indices[1] = v2 - gVertices;
f->indices[2] = v3 - gVertices;
f->indices[3] = v4 - gVertices;
}
void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
@@ -599,17 +623,16 @@ void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
const Vertex* v2 = v + indices[1];
const Vertex* v3 = v + indices[2];
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16)
if (v1->clip & v2->clip & v3->clip)
return;
if (enableClipping)
{
if (v1->clip & v2->clip & v3->clip)
return;
int32 clip = (v1->clip | v2->clip | v3->clip);
if (v1->clip | v2->clip | v3->clip) {
flags |= FACE_CLIPPED;
}
if (clip & 32)
return;
if (clip) {
flags |= FACE_CLIPPED;
}
if (v1->g == v2->g && v1->g == v3->g) {
@@ -618,13 +641,84 @@ void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
int32 depth = X_MAX(v1->z, X_MAX(v2->z, v3->z)) >> OT_SHIFT;
Face *f = gFaces + gFacesCount++;
faceAddToOTable(f, depth);
Face* f = faceAdd(depth);
f->flags = uint16(flags | FACE_TRIANGLE);
f->indices[0] = v1 - gVertices;
f->indices[1] = v2 - gVertices;
f->indices[2] = v3 - gVertices;
}
f->flags = uint16(flags | FACE_TRIANGLE);
f->indices[0] = startVertex + indices[0];
f->indices[1] = startVertex + indices[1];
f->indices[2] = startVertex + indices[2];
void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index)
{
ASSERT(gVerticesCount + 1 < MAX_VERTICES);
const Matrix &m = matrixGet();
int32 z = DP43c(m[2], vx, vy, vz);
if (z < VIEW_MIN_F || z >= VIEW_MAX_F)
{
return;
}
int32 x = DP43c(m[0], vx, vy, vz);
int32 y = DP43c(m[1], vx, vy, vz);
const Sprite* sprite = sprites + index;
int32 l = x + (sprite->l << FIXED_SHIFT);
int32 r = x + (sprite->r << FIXED_SHIFT);
int32 t = y + (sprite->t << FIXED_SHIFT);
int32 b = y + (sprite->b << FIXED_SHIFT);
PERSPECTIVE(l, t, z);
l += (FRAME_WIDTH >> 1);
if (l >= FRAME_WIDTH) return;
t += (FRAME_HEIGHT >> 1);
if (t >= FRAME_HEIGHT) return;
PERSPECTIVE(r, b, z);
r += (FRAME_WIDTH >> 1);
if (r < 0) return;
b += (FRAME_HEIGHT >> 1);
if (b < 0) return;
if (l == r) return;
if (t == b) return;
int32 fogZ = z >> FIXED_SHIFT;
if (fogZ > FOG_MIN)
{
vg += (fogZ - FOG_MIN) << FOG_SHIFT;
if (vg > 8191) {
vg = 8191;
}
}
vg >>= 8;
Vertex &v1 = gVertices[gVerticesCount++];
v1.x = l;
v1.y = t;
//v1.z = z;
v1.g = vg;
Vertex &v2 = gVertices[gVerticesCount++];
v2.x = r;
v2.y = b;
//v2.z = z;
//v2.g = g;
ASSERT(v2.x >= v1.x);
ASSERT(v2.y >= v1.y);
Face* f = faceAdd(fogZ >> OT_SHIFT);
f->flags = uint16(FACE_SPRITE);
f->indices[0] = gVerticesCount - 2;
f->indices[1] = index;
}
void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex)
@@ -666,6 +760,7 @@ void flush()
if (gFacesCount)
{
PROFILE_START();
for (int32 i = otMax; i >= otMin; i--)
{
if (!otFaces[i]) continue;
@@ -678,34 +773,51 @@ void flush()
uint32 flags = face->flags;
if (!(flags & FACE_COLORED))
{
const Texture &tex = textures[face->flags & FACE_TEXTURE];
tile = tiles + (tex.tile << 16);
if (flags == FACE_SPRITE) {
const Sprite &sprite = sprites[face->indices[1]];
v[0].t.uv = tex.uv0;
v[1].t.uv = tex.uv1;
v[2].t.uv = tex.uv2;
v[3].t.uv = tex.uv3;
enableAlphaTest = (tex.attribute == 1);
}
v[0].v = gVertices[face->indices[0] + 0];
v[0].t.u = sprite.u;
v[0].t.v = sprite.v;
v[1].v = gVertices[face->indices[0] + 1];
v[1].t.u = sprite.w;
v[1].t.v = sprite.h;
v[0].v = gVertices[face->indices[0]];
v[1].v = gVertices[face->indices[1]];
v[2].v = gVertices[face->indices[2]];
if (!(flags & FACE_TRIANGLE)) {
v[3].v = gVertices[face->indices[3]];
}
ASSERT(v[0].v.x <= v[1].v.x);
ASSERT(v[0].v.y <= v[1].v.y);
if (flags & FACE_CLIPPED) {
drawPoly(face, v);
drawSprite(face, v);
} else {
if (flags & FACE_TRIANGLE) {
drawTriangle(face, v);
} else {
drawQuad(face, v);
if (!(flags & FACE_COLORED))
{
const Texture &tex = textures[flags & FACE_TEXTURE];
tile = tiles + (tex.tile << 16);
v[0].t.uv = tex.uv0;
v[1].t.uv = tex.uv1;
v[2].t.uv = tex.uv2;
v[3].t.uv = tex.uv3;
enableAlphaTest = (tex.attribute == 1);
}
};
v[0].v = gVertices[face->indices[0]];
v[1].v = gVertices[face->indices[1]];
v[2].v = gVertices[face->indices[2]];
if (!(flags & FACE_TRIANGLE)) {
v[3].v = gVertices[face->indices[3]];
}
if (flags & FACE_CLIPPED) {
drawPoly(face, v);
} else {
if (flags & FACE_TRIANGLE) {
drawTriangle(face, v);
} else {
drawQuad(face, v);
}
};
}
face = face->next;
} while (face);

View File

@@ -2,6 +2,28 @@
#define H_ROOM
#include "common.h"
#include "camera.h"
void animTexturesShift()
{
const int16* data = level.animTexData;
int32 texRangesCount = *data++;
for (int32 i = 0; i < texRangesCount; i++)
{
int32 count = *data++;
Texture tmp = textures[*data];
while (count > 0)
{
textures[data[0]] = textures[data[1]];
data++;
count--;
}
textures[*data++] = tmp;
}
}
int32 getBridgeFloor(const Item* item, int32 x, int32 z)
{
@@ -22,7 +44,7 @@ int32 getBridgeFloor(const Item* item, int32 x, int32 z)
h &= 1023;
return item->pos.y + ((item->type == ITEM_BRIDGE_TILT1) ? (h >> 2) : (h >> 1));
return item->pos.y + ((item->type == ITEM_BRIDGE_TILT_1) ? (h >> 2) : (h >> 1));
}
int32 getTrapDoorFloor(const Item* item, int32 x, int32 z)
@@ -79,8 +101,8 @@ void getItemFloorCeiling(const Item* item, int32 x, int32 y, int32 z, int32* flo
break;
}
case ITEM_BRIDGE_FLAT:
case ITEM_BRIDGE_TILT1:
case ITEM_BRIDGE_TILT2:
case ITEM_BRIDGE_TILT_1:
case ITEM_BRIDGE_TILT_2:
{
h = getBridgeFloor(item, x, z);
break;
@@ -119,14 +141,14 @@ const Sector* Sector::getSectorBelow(int32 posX, int32 posZ) const
{
if (roomBelow == NO_ROOM)
return this;
return rooms[roomBelow].getSector(posX, posZ);
return rooms[roomBelow].getSector(posX, posZ)->getSectorBelow(posX, posZ);
}
const Sector* Sector::getSectorAbove(int32 posX, int32 posZ) const
{
if (roomAbove == NO_ROOM)
return this;
return rooms[roomAbove].getSector(posX, posZ);
return rooms[roomAbove].getSector(posX, posZ)->getSectorAbove(posX, posZ);
}
int32 Sector::getFloor(int32 x, int32 y, int32 z) const
@@ -291,14 +313,49 @@ void Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int
}
const Sector* Room::getSector(int32 posX, int32 posZ) const
const Sector* Room::getSector(int32 x, int32 z) const
{
int32 sx = X_CLAMP((posX - (info->x << 8)) >> 10, 0, info->xSectors - 1);
int32 sz = X_CLAMP((posZ - (info->z << 8)) >> 10, 0, info->zSectors - 1);
int32 sx = X_CLAMP((x - (info->x << 8)) >> 10, 0, info->xSectors - 1);
int32 sz = X_CLAMP((z - (info->z << 8)) >> 10, 0, info->zSectors - 1);
return sectors + sx * info->zSectors + sz;
}
const Sector* Room::getWaterSector(int32 x, int32 z) const
{
const Room* room = this;
const Sector* sector = room->getSector(x, z);
// go up to the air
if (room->info->flags.water)
{
while (sector->roomAbove != NO_ROOM)
{
room = rooms + sector->roomAbove;
if (!room->info->flags.water) {
return sector;
}
sector = room->getSector(x, z);
}
return sector;
}
// go down to the water
while (sector->roomBelow != NO_ROOM)
{
room = rooms + sector->roomBelow;
sector = room->getSector(x, z);
if (room->info->flags.water) {
return sector;
}
}
return NULL;
}
Room* Room::getRoom(int32 x, int32 y, int32 z)
{
const Sector* sector = getSector(x, z);
@@ -329,16 +386,6 @@ Room* Room::getRoom(int32 x, int32 y, int32 z)
return room;
}
int32 Room::getWaterLevel()
{
return WALL; // TODO
}
int32 Room::getWaterDepth()
{
return WALL; // TODO
}
bool Room::checkPortal(const Portal* portal)
{
vec3i d;
@@ -598,10 +645,61 @@ void Room::remove(Item* item)
}
}
void checkCamera(const FloorData* fd)
{
if (camera.mode == CAMERA_MODE_OBJECT)
return;
while (1)
{
FloorData::TriggerCommand triggerCmd = (fd++)->triggerCmd;
switch (triggerCmd.action)
{
case TRIGGER_ACTION_ACTIVATE_CAMERA:
{
triggerCmd.end = (fd++)->triggerCmd.end;
if (triggerCmd.args != camera.lastIndex)
break;
camera.index = triggerCmd.args;
if (camera.timer < 0 || camera.mode == CAMERA_MODE_LOOK || camera.mode == CAMERA_MODE_COMBAT)
{
camera.timer = -1;
break;
}
camera.mode = CAMERA_MODE_FIXED;
break;
}
case TRIGGER_ACTION_CAMERA_TARGET:
{
if (camera.mode == CAMERA_MODE_LOOK || camera.mode == CAMERA_MODE_COMBAT)
break;
ASSERT(triggerCmd.args < level.itemsCount);
camera.lookAtItem = items + triggerCmd.args;
break;
}
case TRIGGER_ACTION_FLYBY:
{
triggerCmd.end = (fd++)->triggerCmd.end;
break;
}
}
if (triggerCmd.end) break;
};
}
void checkTrigger(const FloorData* fd, Item* lara)
{
if (!fd) return;
if (!fd)
return;
if (fd->cmd.func == FLOOR_TYPE_LAVA)
{
@@ -609,6 +707,7 @@ void checkTrigger(const FloorData* fd, Item* lara)
if (fd->cmd.end)
return;
fd++;
}
@@ -616,8 +715,9 @@ void checkTrigger(const FloorData* fd, Item* lara)
FloorData::TriggerInfo info = (fd++)->triggerInfo;
Item* switchItem = NULL;
Item* keyItem = NULL;
Item* pickupItem = NULL;
Item* cameraItem = NULL;
checkCamera(fd);
if (!lara && cmd.type != TRIGGER_TYPE_OBJECT)
return;
@@ -631,37 +731,48 @@ void checkTrigger(const FloorData* fd, Item* lara)
case TRIGGER_TYPE_PAD:
case TRIGGER_TYPE_ANTIPAD:
if (lara->pos.y != lara->floor)
{
if (lara->pos.y != lara->roomFloor)
return;
break;
}
case TRIGGER_TYPE_SWITCH:
{
switchItem = items + fd->triggerCmd.args;
if (!useSwitch(switchItem, info.timer))
return;
fd++;
break;
}
case TRIGGER_TYPE_KEY:
keyItem = items + fd->triggerCmd.args;
if (!useKey(keyItem))
{
Item* keyItem = items + fd->triggerCmd.args;
if (!useKey(keyItem, lara))
return;
fd++;
break;
}
case TRIGGER_TYPE_PICKUP:
pickupItem = items + fd->triggerCmd.args;
{
Item* pickupItem = items + fd->triggerCmd.args;
if (!usePickup(pickupItem))
return;
fd++;
break;
}
case TRIGGER_TYPE_OBJECT:
return;
case TRIGGER_TYPE_COMBAT:
// TODO unused?
{
if (lara->weaponState != WEAPON_STATE_READY)
return;
break;
}
case TRIGGER_TYPE_DUMMY:
return;
@@ -674,15 +785,18 @@ void checkTrigger(const FloorData* fd, Item* lara)
switch (triggerCmd.action)
{
case TRIGGER_ACTION_ACTIVATE_OBJECT: {
case TRIGGER_ACTION_ACTIVATE_OBJECT:
{
ASSERT(triggerCmd.args < level.itemsCount);
Item* item = items + triggerCmd.args;
if (item->flags.once)
break;
item->timer = info.timer;
if (item->timer != 1)
if (item->timer != 1) {
item->timer *= 30;
}
if (cmd.type == TRIGGER_TYPE_SWITCH) {
item->flags.mask ^= info.mask;
@@ -707,8 +821,40 @@ void checkTrigger(const FloorData* fd, Item* lara)
}
case TRIGGER_ACTION_ACTIVATE_CAMERA:
// TODO fixed camera
{
FloorData::TriggerCommand cam = (fd++)->triggerCmd;
triggerCmd.end = cam.end;
if (cameras[triggerCmd.args].flags.once)
break;
camera.index = triggerCmd.args;
if (camera.mode == CAMERA_MODE_LOOK || camera.mode == CAMERA_MODE_COMBAT)
break;
if (cmd.type == TRIGGER_TYPE_COMBAT)
break;
if (cmd.type == TRIGGER_TYPE_SWITCH && (switchItem->state == 1) && (info.timer != 0))
break;
if (cmd.type == TRIGGER_TYPE_SWITCH || camera.index != camera.lastIndex)
{
camera.timer = cam.timer;
if (camera.timer != 1) {
camera.timer *= 30;
}
if (cam.once) {
cameras[camera.index].flags.once = true;
}
camera.speed = (cam.speed << 3) + 1;
camera.mode = lara ? CAMERA_MODE_FIXED : CAMERA_MODE_OBJECT;
}
break;
}
case TRIGGER_ACTION_FLOW:
// TODO flow
@@ -727,14 +873,17 @@ void checkTrigger(const FloorData* fd, Item* lara)
break;
case TRIGGER_ACTION_CAMERA_TARGET:
// TODO change fixed camera target
{
cameraItem = items + triggerCmd.args;
break;
}
case TRIGGER_ACTION_END:
// TODO go to the next level
break;
case TRIGGER_ACTION_SOUNDTRACK: {
case TRIGGER_ACTION_SOUNDTRACK:
{
int32 track = doTutorial(lara, triggerCmd.args);
if (track == 0) break;
@@ -764,7 +913,8 @@ void checkTrigger(const FloorData* fd, Item* lara)
// TODO effect
break;
case TRIGGER_ACTION_SECRET: {
case TRIGGER_ACTION_SECRET:
{
if ((gSaveGame.secrets >> triggerCmd.args) & 1)
break;
@@ -777,6 +927,7 @@ void checkTrigger(const FloorData* fd, Item* lara)
break;
case TRIGGER_ACTION_FLYBY:
triggerCmd.end = (fd++)->triggerCmd.end;
break;
case TRIGGER_ACTION_CUTSCENE:
@@ -785,6 +936,11 @@ void checkTrigger(const FloorData* fd, Item* lara)
if (triggerCmd.end) break;
};
if (cameraItem && (camera.mode == CAMERA_MODE_FIXED || camera.mode == CAMERA_MODE_OBJECT))
{
camera.lookAtItem = cameraItem;
}
}
#endif

View File

@@ -105,8 +105,6 @@ struct Mixer
void fill(uint8* bufferA, uint8* bufferB, int32 count)
{
UNUSED(bufferB);
if ((channelsCount == 0) && !music.data)
{
dmaFill(bufferA, SND_ENCODE(0), count);
@@ -178,9 +176,8 @@ struct Mixer
}
}
if (channelsCount >= SND_CHANNELS) {
if (channelsCount >= SND_CHANNELS)
return NULL;
}
#ifdef USE_9BIT_SOUND
// expand 8 to 9-bit
@@ -197,6 +194,19 @@ struct Mixer
return sample;
}
void stopSample(const uint8* data)
{
int32 i = channelsCount;
while (--i >= 0)
{
if (channels[i].data == data)
{
channels[i] = channels[--channelsCount];
}
}
}
void playMusic(const void* data)
{
music.data = (uint8*)data + 16;