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:
@@ -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>
|
||||
|
@@ -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()
|
||||
|
@@ -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;\
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -14,13 +14,11 @@ struct Enemy : Item
|
||||
virtual void collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
//
|
||||
UNUSED(lara);
|
||||
UNUSED(cinfo);
|
||||
}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
updateAnim();
|
||||
animProcess();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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);
|
||||
|
319
src/platform/gba/inventory.h
Normal file
319
src/platform/gba/inventory.h
Normal 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
|
@@ -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
@@ -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--)
|
||||
{
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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]
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user