1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 16:44:50 +02:00

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

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

View File

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

View File

@@ -5,16 +5,20 @@
#define CAM_SPEED (1 << 3) #define CAM_SPEED (1 << 3)
#define CAM_ROT_SPEED (1 << 9) #define CAM_ROT_SPEED (1 << 9)
#define CAM_ROT_X_MAX int16(85 * 0x8000 / 180)
#define CAM_DIST_FOLLOW (1024 + 512) #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 enum CameraMode
{ {
CAMERA_MODE_FREE = 0, CAMERA_MODE_FREE,
CAMERA_MODE_FOLLOW = 1, CAMERA_MODE_FOLLOW,
CAMERA_MODE_COMBAT = 2, CAMERA_MODE_COMBAT,
CAMERA_MODE_FIXED = 3, CAMERA_MODE_LOOK,
CAMERA_MODE_OBJECT = 4, CAMERA_MODE_FIXED,
CAMERA_MODE_OBJECT,
}; };
struct Camera struct Camera
@@ -27,37 +31,63 @@ struct Camera
Location view; Location view;
Location target; Location target;
int32 targetDist;
int16 targetAngleX; int16 targetAngleX;
int16 targetAngleY; int16 targetAngleY;
int16 targetDist;
int16 angleX; int16 angleX;
int16 angleY; int16 angleY;
AABB frustumBase; AABB frustumBase;
Item* item; Item* laraItem;
Item* lastItem;
Item* lookAtItem;
int32 speed;
int32 timer;
int32 index;
int32 lastIndex;
CameraMode mode; CameraMode mode;
bool modeSwitch;
void init() bool modeSwitch;
bool lastFixed;
bool center;
void init(Item* lara)
{ {
item = NULL; target.pos = lara->pos;
mode = CAMERA_MODE_FOLLOW; target.pos.y -= 1024;
modeSwitch = false; target.room = lara->room;
view = target;
view.pos.z -= 100;
angleX = 0; angleX = 0;
angleY = 0; angleY = 0;
view.pos = vec3i(0);
target.pos = view.pos;
targetDist = CAM_DIST_FOLLOW;
targetAngleX = 0; targetAngleX = 0;
targetAngleY = 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); matrixSetView(view.pos, angleX, angleY);
@@ -68,7 +98,7 @@ struct Camera
if (keys & IK_LEFT) angleY -= CAM_ROT_SPEED; if (keys & IK_LEFT) angleY -= CAM_ROT_SPEED;
if (keys & IK_RIGHT) 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) if (keys & IK_A)
{ {
@@ -133,6 +163,166 @@ struct Camera
return true; 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() void update()
{ {
if (keys & IK_START) if (keys & IK_START)
@@ -152,51 +342,98 @@ struct Camera
if (mode == CAMERA_MODE_FREE) if (mode == CAMERA_MODE_FREE)
{ {
freeControl(); updateFree();
prepareFrustum();
matrixSetView(view.pos, angleX, angleY);
updateRoom();
return;
} }
if (mode == CAMERA_MODE_FOLLOW && item) bool isFixed = false;
Item* item = laraItem;
if (lookAtItem && (mode == CAMERA_MODE_FIXED || mode == CAMERA_MODE_OBJECT))
{ {
int32 tx = item->pos.x; isFixed = true;
int32 ty = item->pos.y; item = lookAtItem;
int32 tz = item->pos.z; }
ASSERT(item);
target.room = item->room;
const Bounds &box = item->getBoundingBox(); const Bounds &box = item->getBoundingBox();
ty += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
target.pos.x = tx; int32 y = item->pos.y;
target.pos.y += (ty - target.pos.y) >> 2; if (isFixed) {
target.pos.z = tz; y += (box.minY + box.maxY) >> 1;
} else {
y += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
}
int16 angle = item->angle.y + targetAngleY; if (mode == CAMERA_MODE_LOOK || mode == CAMERA_MODE_COMBAT)
{
y -= 256;
int32 dy = targetDist * phd_sin(targetAngleX) >> FIXED_SHIFT; if (lastFixed) {
int32 dz = targetDist * phd_cos(targetAngleX) >> FIXED_SHIFT; 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;
int32 cx = target.pos.x - (phd_sin(angle) * dz >> FIXED_SHIFT); if (center)
int32 cy = target.pos.y - 256 + dy; {
int32 cz = target.pos.z - (phd_cos(angle) * dz >> FIXED_SHIFT); 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;
}
view.pos.x += (cx - view.pos.x) >> 2; lastFixed ^= isFixed;
view.pos.y += (cy - view.pos.y) >> 2;
view.pos.z += (cz - view.pos.z) >> 2;
updateRoom(); 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; vec3i dir = target.pos - view.pos;
anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY); anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY);
}
prepareFrustum(); prepareFrustum();
matrixSetView(view.pos, angleX, angleY); matrixSetView(view.pos, angleX, angleY);
updateRoom(); updateRoom();
// reset additional angles, Lara states can override it during the update proc
targetAngleX = 0;
targetAngleY = 0;
targetDist = CAM_DIST_FOLLOW;
} }
void prepareFrustum() void prepareFrustum()

View File

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

View File

@@ -12,6 +12,31 @@ EWRAM_DATA SaveGame gSaveGame;
const FloorData* gLastFloorData; const FloorData* gLastFloorData;
FloorData gLastFloorSlant; 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 const uint16 divTable[DIV_TABLE_SIZE] = { // ROM, not a big difference with IWRAM
0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492, 0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492,
0x2000, 0x1C71, 0x1999, 0x1745, 0x1555, 0x13B1, 0x1249, 0x1111, 0x2000, 0x1C71, 0x1999, 0x1745, 0x1555, 0x13B1, 0x1249, 0x1111,
@@ -805,7 +830,9 @@ void matrixFrame(const vec3i &pos, uint16* angles)
matrixRotateYXZ(angleX, angleY, angleZ); 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_SLOW(a, b, mul, div) a = a + (b - a) * mul / div
#define LERP_ROW(lerp_func, a, b, 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(); Matrix &m = matrixGet();
if (divider == 2) { if ((divider == 2) || ((divider == 4) && (multiplier == 2))) {
LERP_ROW(LERP_FAST, m[0], n[0], multiplier, divider); LERP_ROW(LERP_1, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_FAST, m[1], n[1], multiplier, divider); LERP_ROW(LERP_1, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_FAST, m[2], n[2], 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 { } else {
LERP_ROW(LERP_SLOW, m[0], n[0], multiplier, divider); LERP_ROW(LERP_3, m[0], n[0], multiplier, divider);
LERP_ROW(LERP_SLOW, m[1], n[1], multiplier, divider); LERP_ROW(LERP_3, m[1], n[1], multiplier, divider);
LERP_ROW(LERP_SLOW, m[2], n[2], 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() void matrixSetIdentity()

View File

@@ -29,7 +29,7 @@
//#define DEBUG_OVERDRAW //#define DEBUG_OVERDRAW
#endif #endif
#define NO_STATIC_MESHES #define NO_STATIC_MESH_PLANTS
#if defined(_WIN32) #if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
@@ -98,8 +98,6 @@
#define ALIGN16 __attribute__((aligned(16))) #define ALIGN16 __attribute__((aligned(16)))
#endif #endif
#define UNUSED(x) (void)(x)
typedef signed char int8; typedef signed char int8;
typedef signed short int16; typedef signed short int16;
typedef signed int int32; typedef signed int int32;
@@ -149,6 +147,9 @@ typedef int16 Index;
extern uint16 fb[VRAM_WIDTH * FRAME_HEIGHT]; extern uint16 fb[VRAM_WIDTH * FRAME_HEIGHT];
#endif #endif
// system
int32 osGetSystemTimeMS();
#ifdef PROFILE #ifdef PROFILE
#if defined(_WIN32) #if defined(_WIN32)
@@ -228,6 +229,13 @@ struct vec3s {
vec3s() {} vec3s() {}
X_INLINE vec3s(int16 x, int16 y, int16 z) : x(x), y(y), z(z) {} 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 { 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(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 - (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; }
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() {}
X_INLINE Bounds(int16 minX, int16 maxX, int16 minY, int16 maxY, int16 minZ, int16 maxZ) : 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) {} 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 { struct AABB {
@@ -327,10 +343,9 @@ struct RoomVertex {
}; };
struct RoomSprite { struct RoomSprite {
int16 x, y, z; vec3s pos;
uint8 g; uint8 g;
uint8 reserved; uint8 index;
uint16 texture;
}; };
struct Portal { struct Portal {
@@ -405,7 +420,12 @@ struct RoomInfo
uint8 xSectors; uint8 xSectors;
uint8 zSectors; uint8 zSectors;
uint8 alternateRoom; uint8 alternateRoom;
uint8 flags; union {
uint8 value;
struct {
uint8 water:1, :7;
};
} flags;
RoomData data; RoomData data;
}; };
@@ -427,7 +447,8 @@ struct Room {
void add(Item* item); void add(Item* item);
void remove(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); Room* getRoom(int32 x, int32 y, int32 z);
bool checkPortal(const Portal* portal); bool checkPortal(const Portal* portal);
Room** addVisibleRoom(Room** list); Room** addVisibleRoom(Room** list);
@@ -435,9 +456,6 @@ struct Room {
Room** getNearRooms(const vec3i &pos, int32 radius, int32 height); Room** getNearRooms(const vec3i &pos, int32 radius, int32 height);
Room** getAdjRooms(); Room** getAdjRooms();
Room** getVisibleRooms(); Room** getVisibleRooms();
int32 getWaterLevel();
int32 getWaterDepth();
}; };
struct Node { struct Node {
@@ -476,24 +494,17 @@ struct SoundInfo
struct Anim { struct Anim {
uint32 frameOffset; uint32 frameOffset;
uint8 frameRate; uint8 frameRate;
uint8 frameSize; uint8 frameSize;
uint16 state; uint16 state;
int32 speed; int32 speed;
int32 accel; int32 accel;
uint16 frameBegin; uint16 frameBegin;
uint16 frameEnd; uint16 frameEnd;
uint16 nextAnimIndex; uint16 nextAnimIndex;
uint16 nextFrameIndex; uint16 nextFrameIndex;
uint16 statesCount; uint16 statesCount;
uint16 statesStart; uint16 statesStart;
uint16 commandsCount; uint16 commandsCount;
uint16 commandsStart; uint16 commandsStart;
}; };
@@ -529,7 +540,7 @@ struct Texture {
struct Sprite { struct Sprite {
uint16 tile; uint16 tile;
uint8 u, v; uint8 u, v;
uint16 w, h; uint8 w, h;
int16 l, t, r, b; int16 l, t, r, b;
}; };
@@ -540,13 +551,26 @@ struct SpriteSeq {
int16 start; int16 start;
}; };
struct FixedCamera {
vec3i pos;
int16 roomIndex;
union {
uint16 value;
struct {
uint16 timer:8, once:1, speed:5, :2;
};
} flags;
};
struct ItemInfo struct ItemInfo
{ {
uint8 type; uint8 type;
uint8 roomIndex; uint8 roomIndex;
vec3s pos; vec3s pos;
uint16 intensity; uint16 intensity;
uint16 flags; struct {
uint16 value:14, angle:2;
} flags;
}; };
#define ITEM_FLAGS_MASK_ALL 0x1F #define ITEM_FLAGS_MASK_ALL 0x1F
@@ -631,8 +655,8 @@ struct Lara;
E( TRAP_DOOR_2 ) \ E( TRAP_DOOR_2 ) \
E( UNUSED_4 ) \ E( UNUSED_4 ) \
E( BRIDGE_FLAT ) \ E( BRIDGE_FLAT ) \
E( BRIDGE_TILT1 ) \ E( BRIDGE_TILT_1 ) \
E( BRIDGE_TILT2 ) \ E( BRIDGE_TILT_2 ) \
E( INV_PASSPORT ) \ E( INV_PASSPORT ) \
E( INV_COMPASS ) \ E( INV_COMPASS ) \
E( INV_HOME ) \ E( INV_HOME ) \
@@ -680,14 +704,14 @@ struct Lara;
E( INV_PUZZLE_2 ) \ E( INV_PUZZLE_2 ) \
E( INV_PUZZLE_3 ) \ E( INV_PUZZLE_3 ) \
E( INV_PUZZLE_4 ) \ E( INV_PUZZLE_4 ) \
E( PUZZLE_HOLE_1 ) \ E( PUZZLEHOLE_1 ) \
E( PUZZLE_HOLE_2 ) \ E( PUZZLEHOLE_2 ) \
E( PUZZLE_HOLE_3 ) \ E( PUZZLEHOLE_3 ) \
E( PUZZLE_HOLE_4 ) \ E( PUZZLEHOLE_4 ) \
E( PUZZLE_DONE_1 ) \ E( PUZZLEHOLE_DONE_1 ) \
E( PUZZLE_DONE_2 ) \ E( PUZZLEHOLE_DONE_2 ) \
E( PUZZLE_DONE_3 ) \ E( PUZZLEHOLE_DONE_3 ) \
E( PUZZLE_DONE_4 ) \ E( PUZZLEHOLE_DONE_4 ) \
E( LEADBAR ) \ E( LEADBAR ) \
E( INV_LEADBAR ) \ E( INV_LEADBAR ) \
E( MIDAS_HAND ) \ E( MIDAS_HAND ) \
@@ -699,10 +723,10 @@ struct Lara;
E( INV_KEY_ITEM_2 ) \ E( INV_KEY_ITEM_2 ) \
E( INV_KEY_ITEM_3 ) \ E( INV_KEY_ITEM_3 ) \
E( INV_KEY_ITEM_4 ) \ E( INV_KEY_ITEM_4 ) \
E( KEY_HOLE_1 ) \ E( KEYHOLE_1 ) \
E( KEY_HOLE_2 ) \ E( KEYHOLE_2 ) \
E( KEY_HOLE_3 ) \ E( KEYHOLE_3 ) \
E( KEY_HOLE_4 ) \ E( KEYHOLE_4 ) \
E( UNUSED_5 ) \ E( UNUSED_5 ) \
E( UNUSED_6 ) \ E( UNUSED_6 ) \
E( SCION_PICKUP_QUALOPEC ) \ E( SCION_PICKUP_QUALOPEC ) \
@@ -739,9 +763,9 @@ struct Lara;
E( UNUSED_16 ) \ E( UNUSED_16 ) \
E( UNUSED_17 ) \ E( UNUSED_17 ) \
E( LAVA_PARTICLE ) \ E( LAVA_PARTICLE ) \
E( TRAP_LAVA_EMITTER ) \ E( LAVA_EMITTER ) \
E( FLAME ) \ E( FLAME ) \
E( TRAP_FLAME_EMITTER ) \ E( FLAME_EMITTER ) \
E( TRAP_LAVA ) \ E( TRAP_LAVA ) \
E( MUTANT_EGG_BIG ) \ E( MUTANT_EGG_BIG ) \
E( BOAT ) \ E( BOAT ) \
@@ -772,7 +796,7 @@ struct Item {
union { union {
struct { 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; uint16 value;
} flags; } flags;
@@ -795,15 +819,18 @@ struct Item {
}; };
int16 moveAngle; int16 moveAngle;
int16 floor;
int16 turnSpeed; int16 turnSpeed;
int16 vSpeedHack;
uint16 input; uint16 input;
uint8 type; uint8 type;
uint8 intensity; uint8 intensity;
int16 roomFloor;
int16 vSpeedHack;
int16 swimTimer;
uint8 weaponState;
uint8 _reserved;
Item* nextItem; Item* nextItem;
Item* nextActive; Item* nextActive;
@@ -821,19 +848,42 @@ struct Item {
const Anim* animSet(int32 newAnimIndex, bool resetState, int32 frameOffset = 0); const Anim* animSet(int32 newAnimIndex, bool resetState, int32 frameOffset = 0);
const Anim* animChange(const Anim* anim); const Anim* animChange(const Anim* anim);
void animCmd(bool fx, 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); 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); Item* init(Room* room);
X_INLINE Item() {} X_INLINE Item() {}
Item(Room* room); Item(Room* room);
virtual void collide(Lara* lara, CollisionInfo* cinfo);
virtual void update(); virtual void update();
virtual void draw(); 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 struct SaveGame
@@ -843,6 +893,7 @@ struct SaveGame
}; };
uint8 secrets; uint8 secrets;
uint8 pickups;
TrackFlags tracks[64]; TrackFlags tracks[64];
}; };
@@ -927,9 +978,9 @@ enum SlantType {
enum WaterState { enum WaterState {
WATER_STATE_ABOVE, WATER_STATE_ABOVE,
WATER_STATE_WADE,
WATER_STATE_SURFACE, WATER_STATE_SURFACE,
WATER_STATE_UNDER, WATER_STATE_UNDER,
WATER_STATE_WADE,
}; };
enum AnimCommand { enum AnimCommand {
@@ -1076,8 +1127,10 @@ struct Level {
uint16 spriteSequencesCount; uint16 spriteSequencesCount;
uint16 soundSourcesCount; uint16 soundSourcesCount;
uint16 boxesCount; uint16 boxesCount;
uint16 texturesCount;
uint16 animTexDataSize; uint16 animTexDataSize;
uint16 itemsCount; uint16 itemsCount;
uint16 camerasCount;
uint16 cameraFramesCount; uint16 cameraFramesCount;
const uint16* palette; const uint16* palette;
@@ -1098,12 +1151,12 @@ struct Level {
const Texture* textures; const Texture* textures;
const Sprite* sprites; const Sprite* sprites;
const SpriteSeq* spriteSequences; const SpriteSeq* spriteSequences;
uint32 cameras; const FixedCamera* cameras;
uint32 soundSources; uint32 soundSources;
const Box* boxes; const Box* boxes;
const uint16* overlaps; const uint16* overlaps;
const uint16* zones[2][3]; const uint16* zones[2][3];
uint32 animTexData; const int16* animTexData;
const ItemInfo* itemsInfo; const ItemInfo* itemsInfo;
uint32 cameraFrames; uint32 cameraFrames;
const uint16* soundMap; const uint16* soundMap;
@@ -1177,9 +1230,12 @@ extern int32 fps;
#define MAX_MODELS ITEM_MAX #define MAX_MODELS ITEM_MAX
#define MAX_ROOMS 139 // LEVEL7A #define MAX_ROOMS 139 // LEVEL7A
#define MAX_STATIC_MESHES 50 #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_FACES 1024
#define MAX_ROOM_LIST 16 #define MAX_ROOM_LIST 16
#define MAX_CAUSTICS 32
#define FOV_SHIFT 3 #define FOV_SHIFT 3
#define FOG_SHIFT 1 #define FOG_SHIFT 1
@@ -1196,7 +1252,8 @@ extern int32 fps;
#define FACE_COLORED 0x4000 #define FACE_COLORED 0x4000
#define FACE_CLIPPED 0x2000 #define FACE_CLIPPED 0x2000
#define FACE_FLAT 0x1000 #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 FACE_TEXTURE 0x07FF
#define NO_ROOM 0xFF #define NO_ROOM 0xFF
@@ -1216,6 +1273,7 @@ extern int32 fps;
#define X_MIN(a,b) ((a) < (b) ? (a) : (b)) #define X_MIN(a,b) ((a) < (b) ? (a) : (b))
#define X_MAX(a,b) ((a) > (b) ? (a) : (b)) #define X_MAX(a,b) ((a) > (b) ? (a) : (b))
#define X_SQR(x) ((x) * (x)) #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 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) #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; b = tmp;
} }
X_INLINE int32 classify(const Vertex &v, const Rect &clip) { void set_seed_ctrl(int32 seed);
return (v.x < clip.x0 ? 1 : 0) | void set_seed_draw(int32 seed);
(v.x > clip.x1 ? 2 : 0) | int16 rand_ctrl();
(v.y < clip.y0 ? 4 : 0) | int16 rand_draw();
(v.y > clip.y1 ? 8 : 0);
}
int32 phd_sin(int32 x); int32 phd_sin(int32 x);
int32 phd_cos(int32 x); int32 phd_cos(int32 x);
@@ -1363,10 +1419,11 @@ int32 rectIsVisible(const Rect* rect);
int32 boxIsVisible(const Bounds* box); int32 boxIsVisible(const Bounds* box);
void transform(int32 vx, int32 vy, int32 vz, int32 vg); void transform(int32 vx, int32 vy, int32 vz, int32 vg);
bool transformBoxRect(const Bounds* box, Rect* rect); bool transformBoxRect(const Bounds* box, Rect* rect);
void transformRoom(const RoomVertex* vertices, int32 vCount); void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics);
void transformMesh(const vec3s* vertices, int32 vCount, uint16 intensity); void transformMesh(const vec3s* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal);
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex); void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
void faceAddTriangle(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 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); 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); Lara* getLara(const vec3i &pos);
bool useSwitch(Item* item, int32 timer); bool useSwitch(Item* item, int32 timer);
bool useKey(Item* item); bool useKey(Item* item, Item* lara);
bool usePickup(Item* item); bool usePickup(Item* item);
void musicPlay(int32 track); void musicPlay(int32 track);
@@ -1395,13 +1452,4 @@ X_INLINE void dmaFill(void *dst, uint8 value, uint32 count)
#endif #endif
} }
X_INLINE int16 xRand()
{
#ifdef __GBA__
return qran();
#else
return rand();
#endif
}
#endif #endif

View File

@@ -4,7 +4,85 @@
#include "common.h" #include "common.h"
#include "item.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) 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]; int32 offset = level.meshOffsets[meshIndex];
const uint8* ptr = level.meshData + offset; const uint8* ptr = level.meshData + offset;
@@ -33,12 +111,17 @@ void drawMesh(int16 meshIndex, uint16 intensity)
const vec3s* vertices = (vec3s*)ptr; const vec3s* vertices = (vec3s*)ptr;
ptr += vCount * 3 * sizeof(int16); ptr += vCount * 3 * sizeof(int16);
const uint16* vIntensity = NULL;
const vec3s* vNormal = NULL;
int16 nCount = *(int16*)ptr; ptr += 2; int16 nCount = *(int16*)ptr; ptr += 2;
//const int16* normals = (int16*)ptr; //const int16* normals = (int16*)ptr;
if (nCount > 0) { // normals if (nCount > 0) { // normals
vNormal = (vec3s*)ptr;
ptr += nCount * 3 * sizeof(int16); ptr += nCount * 3 * sizeof(int16);
} else { // intensity } else { // intensity
ptr += vCount * sizeof(int16); vIntensity = (uint16*)ptr;
ptr += vCount * sizeof(uint16);
} }
int16 rCount = *(int16*)ptr; ptr += 2; int16 rCount = *(int16*)ptr; ptr += 2;
@@ -56,7 +139,7 @@ void drawMesh(int16 meshIndex, uint16 intensity)
int32 startVertex = gVerticesCount; int32 startVertex = gVerticesCount;
PROFILE_START(); PROFILE_START();
transformMesh(vertices, vCount, intensity); transformMesh(vertices, vCount, vIntensity, vNormal);
PROFILE_STOP(dbg_transform); PROFILE_STOP(dbg_transform);
PROFILE_START(); PROFILE_START();
@@ -106,16 +189,17 @@ void drawShadow(const Item* item, int32 size)
6, 3, 4, 5 6, 3, 4, 5
}; };
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 0, startVertex); faceAddQuad(FACE_SHADOW, indices + 0, startVertex);
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 4, startVertex); faceAddQuad(FACE_SHADOW, indices + 4, startVertex);
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 8, startVertex); faceAddQuad(FACE_SHADOW, indices + 8, startVertex);
matrixPop(); matrixPop();
} }
void drawSprite(const Item* item) 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) void drawModel(const Item* item, uint16* meshOverrides)
@@ -134,7 +218,10 @@ void drawModel(const Item* item, uint16* meshOverrides)
int32 intensity = item->intensity << 5; int32 intensity = item->intensity << 5;
if (intensity == 0) { 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); int32 vis = boxIsVisible(&frame->box);
@@ -156,7 +243,7 @@ void drawModel(const Item* item, uint16* meshOverrides)
matrixFrame(frame->pos, frameAngles); 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++) for (int32 i = 1; i < model->count; i++)
{ {
@@ -166,7 +253,7 @@ void drawModel(const Item* item, uint16* meshOverrides)
frameAngles += 2; frameAngles += 2;
matrixFrame(node->pos, frameAngles); matrixFrame(node->pos, frameAngles);
drawMesh(meshOverrides ? meshOverrides[i] : (model->start + i), intensity); drawMesh(meshOverrides ? meshOverrides[i] : (model->start + i));
node++; node++;
} }
@@ -209,21 +296,27 @@ void drawRoom(const Room* room)
enableClipping = true; enableClipping = true;
PROFILE_START(); PROFILE_START();
transformRoom(data.vertices, info->verticesCount); transformRoom(data.vertices, info->verticesCount, info->flags.water);
PROFILE_STOP(dbg_transform); PROFILE_STOP(dbg_transform);
matrixPop();
PROFILE_START(); PROFILE_START();
faceAddRoom(data.quads, info->quadsCount, data.triangles, info->trianglesCount, startVertex); faceAddRoom(data.quads, info->quadsCount, data.triangles, info->trianglesCount, startVertex);
PROFILE_STOP(dbg_poly); 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++) for (int32 i = 0; i < info->meshesCount; i++)
{ {
const RoomMesh* mesh = data.meshes + i; const RoomMesh* mesh = data.meshes + i;
#ifdef NO_STATIC_MESHES #ifdef NO_STATIC_MESH_PLANTS
if (mesh->id != STATIC_MESH_GATE) continue; if (mesh->id < 10) continue;
#endif #endif
const StaticMesh* staticMesh = staticMeshes + mesh->id; const StaticMesh* staticMesh = staticMeshes + mesh->id;
@@ -243,8 +336,10 @@ void drawRoom(const Room* room)
int32 vis = boxIsVisible(&staticMesh->vbox); int32 vis = boxIsVisible(&staticMesh->vbox);
if (vis != 0) { if (vis != 0) {
enableClipping = vis < 0; enableClipping = true;//vis < 0; // TODO wrong visibility BBox?
drawMesh(staticMesh->meshIndex, mesh->intensity << 5);
calcLightingStatic(mesh->intensity << 5);
drawMesh(staticMesh->meshIndex);
} }
matrixPop(); matrixPop();
@@ -277,103 +372,4 @@ void drawRooms()
flush(); 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 #endif

View File

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

View File

@@ -9,25 +9,23 @@
#include "item.h" #include "item.h"
#include "draw.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 struct Game
{ {
int32 animTexFrame;
void init() void init()
{ {
loadLevel(LEVEL1_PKD); set_seed_ctrl(osGetSystemTimeMS() * 3);
set_seed_draw(osGetSystemTimeMS() * 7);
animTexFrame = 0;
loadLevel(levelData);
} }
void loadLevel(const void* data) void loadLevel(const void* data)
{ {
camera.init(); drawFree();
readLevel((uint8*)data); readLevel((uint8*)data);
// prepare rooms // prepare rooms
@@ -39,34 +37,47 @@ struct Game
// prepare items // prepare items
for (int32 i = 0; i < level.itemsCount; i++) for (int32 i = 0; i < level.itemsCount; i++)
{ {
Item* item = items + i;
const ItemInfo* info = level.itemsInfo + i; const ItemInfo* info = level.itemsInfo + i;
Item* item = items + i;
item->type = info->type; 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.x = info->pos.x + (rooms[info->roomIndex].info->x << 8);
item->pos.y = info->pos.y; item->pos.y = info->pos.y;
item->pos.z = info->pos.z + (rooms[info->roomIndex].info->z << 8); item->pos.z = info->pos.z + (rooms[info->roomIndex].info->z << 8);
item->angle.y = ((info->flags >> 14) - 2) * ANGLE_90; item->angle.y = (info->flags.angle - 2) * ANGLE_90;
item->flags.value = info->flags & 0x3FFF; item->flags.value = info->flags.value;
item->init(rooms + info->roomIndex); item->init(rooms + info->roomIndex);
if (item->type == ITEM_LARA) if (item->type == ITEM_LARA)
{ {
camera.item = item; camera.init(item);
camera.laraItem = item;
//#ifdef PROFILE //#ifdef PROFILE
// debug // gym
//resetItem(item, 0, vec3i(74588, 3072, 19673), 0); // level 1 (first darts) //resetItem(item, 13, vec3i(38953, 3328, 63961), ANGLE_90 + ANGLE_45); // pool
//resetItem(item, 9, vec3i(49669, 7680, 57891), 0); // level 1 (first door) // level 1
//resetItem(item, 10, vec3i(43063, 7168, 61198), 0); // level 1 (transp) //resetItem(item, 0, vec3i(74588, 3072, 19673), ANGLE_0); // first darts
//resetItem(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // level 1 (bridge) //resetItem(item, 9, vec3i(49669, 7680, 57891), ANGLE_0); // first door
//resetItem(item, 17, vec3i(16475, 6656, 59845), ANGLE_90); // level 1 (bear) //resetItem(item, 10, vec3i(43063, 7168, 61198), ANGLE_0); // transp
//resetItem(item, 26, vec3i(24475, 6912, 83505), ANGLE_90); // level 1 (switch timer) //resetItem(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // bridge
//resetItem(item, 35, vec3i(35149, 2048, 74189), ANGLE_90); // level 1 (switch timer) //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 //#endif
camera.view.pos = camera.target.pos = item->pos; camera.view.pos = camera.target.pos = item->pos;
@@ -75,6 +86,8 @@ struct Game
players[0] = (Lara*)item; players[0] = (Lara*)item;
} }
} }
drawInit();
} }
void resetItem(Item* item, int32 roomIndex, const vec3i &pos, int32 angleY) 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) void update(int32 frames)
{ {
#ifdef TEST
return;
#endif
if (frames > MAX_UPDATE_FRAMES) { if (frames > MAX_UPDATE_FRAMES) {
frames = MAX_UPDATE_FRAMES; frames = MAX_UPDATE_FRAMES;
} }
@@ -114,6 +136,8 @@ struct Game
camera.update(); camera.update();
} }
nextFrame(frames);
if (keys & IK_SELECT) { if (keys & IK_SELECT) {
mixer.playMusic(TRACK_13_WAV); mixer.playMusic(TRACK_13_WAV);
} }
@@ -129,18 +153,6 @@ struct Game
clear(); clear();
#ifdef TEST
#ifdef __GBA__
VBlankIntrWait();
#endif
int32 cycles = 0;
PROFILE_START();
drawTest();
PROFILE_STOP(cycles);
drawNumber(cycles, TEXT_POSX, 32);
#else
#ifdef PROFILE #ifdef PROFILE
dbg_transform = 0; dbg_transform = 0;
dbg_poly = 0; dbg_poly = 0;
@@ -159,8 +171,6 @@ struct Game
drawNumber(dbg_poly_count, TEXT_POSX, 100); drawNumber(dbg_poly_count, TEXT_POSX, 100);
#endif #endif
#endif
drawNumber(fps, TEXT_POSX, 16); drawNumber(fps, TEXT_POSX, 16);
} }
}; };

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,11 +1,13 @@
#if defined(_WIN32) || defined(__DOS__) #if defined(_WIN32) || defined(__DOS__)
void* LEVEL1_PKD; const void* TRACK_13_WAV;
void* TRACK_13_WAV; const void* levelData;
#define LEVEL_NAME "LEVEL1.PKD"
#elif defined(__GBA__) #elif defined(__GBA__)
#include "LEVEL1_PKD.h"
#include "TRACK_13_WAV.h" #include "TRACK_13_WAV.h"
#include "LEVEL1_PKD.h"
const void* levelData = LEVEL1_PKD;
#elif defined(__TNS__) #elif defined(__TNS__)
void* LEVEL1_PHD; const void* levelData;
#endif #endif
#include "game.h" #include "game.h"
@@ -41,11 +43,22 @@ int32 fpsCounter = 0;
memcpy(MEM_PAL_BG, palette, 256 * 2); memcpy(MEM_PAL_BG, palette, 256 * 2);
#endif #endif
} }
int32 osGetSystemTimeMS()
{
return GetTickCount();
}
#elif defined(__GBA__) #elif defined(__GBA__)
void paletteSet(const uint16* palette) void paletteSet(const uint16* palette)
{ {
memcpy((uint16*)MEM_PAL_BG, palette, 256 * 2); memcpy((uint16*)MEM_PAL_BG, palette, 256 * 2);
} }
int32 osGetSystemTimeMS()
{
return 0; // TODO
}
#elif defined(__TNS__) #elif defined(__TNS__)
unsigned int osTime; unsigned int osTime;
volatile unsigned int *timerBUS; volatile unsigned int *timerBUS;
@@ -67,11 +80,16 @@ int32 fpsCounter = 0;
osTime = *timerCLK; osTime = *timerCLK;
} }
int GetTickCount() int32 GetTickCount()
{ {
return (osTime - *timerCLK) / 33; return (osTime - *timerCLK) / 33;
} }
int32 osGetSystemTimeMS()
{
return *timerCLK / 33;
}
void paletteSet(uint16* palette) void paletteSet(uint16* palette)
{ {
memcpy((uint16*)0xC0000200, palette, 256 * 2); memcpy((uint16*)0xC0000200, palette, 256 * 2);
@@ -419,7 +437,7 @@ int main(void) {
{ {
// level1 // level1
#if defined(_WIN32) || defined(__DOS__) #if defined(_WIN32) || defined(__DOS__)
FILE *f = fopen("data/LEVEL1.PKD", "rb"); FILE *f = fopen("data/" LEVEL_NAME, "rb");
#elif defined(__TNS__) #elif defined(__TNS__)
FILE *f = fopen("/documents/OpenLara/LEVEL1.PHD.tns", "rb"); FILE *f = fopen("/documents/OpenLara/LEVEL1.PHD.tns", "rb");
#else #else
@@ -430,13 +448,17 @@ int main(void) {
return 0; return 0;
} }
{
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
int32 size = ftell(f); int32 size = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
LEVEL1_PKD = new uint8[size]; uint8* data = new uint8[size];
fread(LEVEL1_PKD, 1, size, f); fread(data, 1, size, f);
fclose(f); fclose(f);
levelData = data;
}
// track 13 // track 13
#if defined(_WIN32) || defined(__DOS__) #if defined(_WIN32) || defined(__DOS__)
{ {
@@ -448,16 +470,14 @@ int main(void) {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
int32 size = ftell(f); int32 size = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
TRACK_13_WAV = new uint8[size]; uint8* data = new uint8[size];
fread(TRACK_13_WAV, 1, size, f); fread(data, 1, size, f);
fclose(f); fclose(f);
TRACK_13_WAV = data;
} }
#endif #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 #endif
#if defined(_WIN32) #if defined(_WIN32)
@@ -507,6 +527,30 @@ int main(void) {
//uint16 &GreenSwap = *(uint16*)0x4000002; //uint16 &GreenSwap = *(uint16*)0x4000002;
//GreenSwap = 1; //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(); soundInit();
game.init(); game.init();

View File

@@ -3,6 +3,7 @@
#include "item.h" #include "item.h"
#include "lara.h" #include "lara.h"
#include "inventory.h"
vec3i getBlockOffset(int16 angleY, int32 offset) vec3i getBlockOffset(int16 angleY, int32 offset)
{ {
@@ -27,6 +28,31 @@ namespace Limits
Bounds( -200, 200, 0, 0, 312, 512 ), Bounds( -200, 200, 0, 0, 312, 512 ),
vec3s( 10 * DEG2SHORT, 30 * DEG2SHORT, 10 * DEG2SHORT ) 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() virtual void update()
{ {
updateAnim(); animProcess();
} }
bool isActive() 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 struct Door : Object
{ {
enum { enum {
@@ -117,13 +158,12 @@ struct Door : Object
} }
} }
updateAnim(); animProcess();
} }
virtual void collide(Lara* lara, CollisionInfo* cinfo) virtual void collide(Lara* lara, CollisionInfo* cinfo)
{ {
UNUSED(lara); // TODO door collision
UNUSED(cinfo);
} }
void action(bool close) void action(bool close)
@@ -160,6 +200,8 @@ struct Door : Object
nextRoom = sector->getNextRoom(); nextRoom = sector->getNextRoom();
} }
// TODO modify level.boxes
if (!behind && nextRoom) { if (!behind && nextRoom) {
activate(close, true, nextRoom, pos.x, pos.z); // use sector from item pos 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 struct Switch : Object
{ {
enum { enum {
@@ -189,12 +257,13 @@ struct Switch : Object
virtual void collide(Lara* lara, CollisionInfo* cinfo) virtual void collide(Lara* lara, CollisionInfo* cinfo)
{ {
UNUSED(cinfo); if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION)) if (!(lara->input & IN_ACTION))
return; return;
if (lara->state != Lara::STOP) if (lara->state != Lara::STATE_STOP)
return; return;
if (flags.status != ITEM_FLAGS_STATUS_NONE) if (flags.status != ITEM_FLAGS_STATUS_NONE)
@@ -207,22 +276,13 @@ struct Switch : Object
ASSERT(state == STATE_DOWN || state == STATE_UP); ASSERT(state == STATE_DOWN || state == STATE_UP);
if (state == STATE_DOWN) { bool isDown = (state == STATE_DOWN);
lara->goalState = Lara::SWITCH_DOWN;
goalState = STATE_UP;
} else {
lara->goalState = Lara::SWITCH_UP;
goalState = 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(); activate();
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
lara->skipAnim(); lara->weaponState = WEAPON_STATE_BUSY;
updateAnim();
lara->goalState = Lara::STOP;
} }
bool use(int32 t) bool use(int32 t)
@@ -254,9 +314,30 @@ struct SwitchWater : Switch
virtual void collide(Lara* lara, CollisionInfo* cinfo) virtual void collide(Lara* lara, CollisionInfo* cinfo)
{ {
UNUSED(lara); if (lara->weaponState != WEAPON_STATE_FREE)
UNUSED(cinfo); return;
// TODO
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) {} 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; flags.status = ITEM_FLAGS_STATUS_INACTIVE;
return true; return true;
@@ -290,6 +371,81 @@ struct Pickup : Object
} }
return false; 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); 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) 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 struct TrapFloor : Object
{ {
enum { enum {
@@ -344,7 +592,7 @@ struct TrapFloor : Object
break; break;
} }
updateAnim(); animProcess();
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE) if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
{ {
@@ -354,9 +602,9 @@ struct TrapFloor : Object
updateRoom(); updateRoom();
if (state == STATE_FALL && pos.y >= floor) if (state == STATE_FALL && pos.y >= roomFloor)
{ {
pos.y = floor; pos.y = roomFloor;
vSpeed = 0; vSpeed = 0;
flags.gravity = false; flags.gravity = false;
goalState = STATE_DOWN; 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 struct Dart : Object
{ {
Dart(Room* room) : Object(room) Dart(Room* room) : Object(room)
@@ -379,10 +665,10 @@ struct Dart : Object
{ {
// TODO collide with Lara // TODO collide with Lara
updateAnim(); animProcess();
updateRoom(); updateRoom();
if (pos.y >= floor) if (pos.y >= roomFloor)
{ {
// TODO create spark // TODO create spark
remove(); remove();
@@ -420,12 +706,206 @@ struct TrapDartEmitter : Object
if (dart) if (dart)
{ {
dart->intensity = 0;
dart->flags.status = ITEM_FLAGS_STATUS_ACTIVE; dart->flags.status = ITEM_FLAGS_STATUS_ACTIVE;
dart->activate(); dart->activate();
} }
} }
updateAnim(); animProcess();
}
};
struct Block : Object
{
enum {
STATE_NONE,
STATE_READY,
STATE_PUSH,
STATE_PULL,
};
Block(Room* room) : Object(room)
{
if (flags.status != ITEM_FLAGS_STATUS_INVISIBLE) {
updateFloor(-1024);
}
}
void updateFloor(int32 offset)
{
room->modify();
Sector* sector = (Sector*)room->getSector(pos.x, pos.z);
if (sector->floor == NO_FLOOR) {
sector->floor = sector->ceiling + (offset >> 8);
} else {
sector->floor += (offset >> 8);
if (sector->floor == sector->ceiling) {
sector->floor = NO_FLOOR;
}
}
// TODO modify level.boxes
}
bool checkBlocking()
{
const Sector* sector = room->getSector(pos.x, pos.z);
return (sector->floor == NO_FLOOR) || ((sector->floor << 8) + 1024 == pos.y);
}
bool checkObstacles(int32 x, int32 z, int32 height)
{
Room* nextRoom = room->getRoom(x, pos.y, z);
const Sector* sector = nextRoom->getSector(x, z);
int32 floor = pos.y;
int32 ceiling = pos.y - height;
if ((sector->floor << 8) != floor)
return false;
nextRoom = nextRoom->getRoom(x, ceiling, z);
sector = nextRoom->getSector(x, z);
if ((sector->ceiling << 8) > ceiling)
return false;
return true;
}
bool checkPush()
{
if (!checkBlocking())
return false;
vec3i offset = getBlockOffset(angle.y, -1024);
return checkObstacles(pos.x + offset.x, pos.z + offset.z, 1024);
}
bool checkPull(Item* lara)
{
if (!checkBlocking())
return false;
vec3i offset = getBlockOffset(angle.y, 1024);
if (!checkObstacles(pos.x + offset.x, pos.z + offset.z, 1024))
return false;
return checkObstacles(lara->pos.x + offset.x, lara->pos.z + offset.z, LARA_HEIGHT);
}
virtual void collide(Lara* lara, CollisionInfo* cinfo)
{
if (lara->weaponState != WEAPON_STATE_FREE)
return;
if (!(lara->input & IN_ACTION))
return;
if (flags.status == ITEM_FLAGS_STATUS_ACTIVE)
return;
if (lara->pos.y != pos.y)
return;
uint16 quadrant = uint16(lara->angle.y + ANGLE_45) / ANGLE_90;
if (lara->state == Lara::STATE_BLOCK_READY)
{
if (!lara->animIsEnd(0))
return;
if (!checkLimit(lara, Limits::BLOCK))
return;
if (lara->input & IN_UP)
{
if (!checkPush())
return;
lara->goalState = Lara::STATE_BLOCK_PUSH;
goalState = STATE_PUSH;
}
else if (lara->input & IN_DOWN)
{
if (!checkPull(lara))
return;
lara->goalState = Lara::STATE_BLOCK_PULL;
goalState = STATE_PULL;
}
else
{
return;
}
updateFloor(1024);
activate();
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
animProcess();
lara->animProcess();
}
if (lara->state == Lara::STATE_STOP)
{
if (lara->input & (IN_UP | IN_DOWN))
return;
angle.y = quadrant * ANGLE_90;
if (!checkLimit(lara, Limits::BLOCK))
return;
lara->goalState = Lara::STATE_BLOCK_READY;
lara->angle.y = angle.y;
lara->alignWall(LARA_RADIUS);
lara->animProcess();
}
}
virtual void update()
{
if (flags.once)
{
updateFloor(1024);
remove();
return;
}
animProcess();
updateRoom(); // it'll get roomFloor and gLastFloorData
if (pos.y > roomFloor)
{
flags.gravity = true;
}
else if (flags.gravity)
{
flags.gravity = false;
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
pos.y = roomFloor;
// TODO EarthQuake + playSound 70 (Thor room)
}
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
{
deactivate();
flags.status = ITEM_FLAGS_STATUS_NONE;
updateFloor(-1024);
checkTrigger(gLastFloorData, NULL);
}
} }
}; };

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
extern uint8 lightmap[256 * 32]; extern uint8 lightmap[256 * 32];
extern const uint8* tile; extern const uint8* tile;
extern const Sprite* sprite;
#if defined(__GBA__) #if defined(__GBA__)
#define USE_ASM #define USE_ASM
@@ -29,6 +30,7 @@ extern const uint8* tile;
#define rasterizeGT rasterizeGT_mode4_asm #define rasterizeGT rasterizeGT_mode4_asm
#define rasterizeFTA rasterizeFTA_mode4_asm #define rasterizeFTA rasterizeFTA_mode4_asm
#define rasterizeGTA rasterizeGTA_mode4_asm #define rasterizeGTA rasterizeGTA_mode4_asm
#define rasterizeSprite rasterizeSprite_mode4_c
#else #else
#define rasterizeS rasterizeS_mode4_c #define rasterizeS rasterizeS_mode4_c
#define rasterizeF rasterizeF_mode4_c #define rasterizeF rasterizeF_mode4_c
@@ -37,6 +39,7 @@ extern const uint8* tile;
#define rasterizeGT rasterizeGT_mode4_c #define rasterizeGT rasterizeGT_mode4_c
#define rasterizeFTA rasterizeFTA_mode4_c #define rasterizeFTA rasterizeFTA_mode4_c
#define rasterizeGTA rasterizeGTA_mode4_c #define rasterizeGTA rasterizeGTA_mode4_c
#define rasterizeSprite rasterizeSprite_mode4_c
void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) 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 // 8-bit fractional part precision for Gouraud component
// has some artifacts but allow to save one reg for inner loop // 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) while (1)
{ {
@@ -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) 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 #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 #endif

View File

@@ -34,10 +34,16 @@ uint16 palette[256]; // IWRAM 0.5k
#endif #endif
extern uint8 lightmap[256 * 32]; extern uint8 lightmap[256 * 32];
extern const Texture* textures; extern Texture textures[MAX_TEXTURES];
extern const Sprite* sprites;
extern const uint8* tiles; extern const uint8* tiles;
extern int32 lightAmbient;
extern int32 caustics[MAX_CAUSTICS];
extern int32 causticsRand[MAX_CAUSTICS];
extern int32 causticsFrame;
const uint8* tile; const uint8* tile;
const Sprite* sprite;
uint32 gVerticesCount = 0; uint32 gVerticesCount = 0;
int32 gFacesCount = 0; // 1 is reserved as OT terminator 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 ); *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]); 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; continue;
} }
@@ -122,6 +129,13 @@ int32 boxIsVisible(const Bounds* box)
return rectIsVisible(&rect); 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) void transform(int32 vx, int32 vy, int32 vz, int32 vg)
{ {
ASSERT(gVerticesCount < MAX_VERTICES); 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); 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; return;
} }
int32 x = DP43c(m[0], vx, vy, vz); int32 x = DP43c(m[0], vx, vy, vz);
int32 y = DP43c(m[1], vx, vy, vz); int32 y = DP43c(m[1], vx, vy, vz);
int32 fogZ = z >> FIXED_SHIFT; res.z = z >> FIXED_SHIFT;
res.z = fogZ;
if (fogZ > FOG_MIN)
{
vg += (fogZ - FOG_MIN) << FOG_SHIFT;
if (vg > 8191) {
vg = 8191;
}
}
res.g = vg >> 8; res.g = vg >> 8;
PERSPECTIVE(x, y, z); 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.x = x + (FRAME_WIDTH >> 1);
res.y = y + (FRAME_HEIGHT >> 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 vx = v->x << 10;
int32 vz = v->z << 10; int32 vz = v->z << 10;
@@ -178,7 +182,7 @@ void transformRoomVertex(const RoomVertex* v)
if (vz < frustumAABB.minZ || vz > frustumAABB.maxZ || if (vz < frustumAABB.minZ || vz > frustumAABB.maxZ ||
vx < frustumAABB.minX || vx > frustumAABB.maxX) vx < frustumAABB.minX || vx > frustumAABB.maxX)
{ {
res.clip = 16; res.clip = 32;
return; return;
} }
#endif #endif
@@ -189,10 +193,13 @@ void transformRoomVertex(const RoomVertex* v)
int32 z = DP43c(m[2], vx, vy, vz); 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; res.clip = 16;
return; } else {
res.clip = 0;
} }
int32 fogZ = z >> FIXED_SHIFT; int32 fogZ = z >> FIXED_SHIFT;
@@ -200,6 +207,10 @@ void transformRoomVertex(const RoomVertex* v)
int32 vg = v->g << 5; int32 vg = v->g << 5;
if (caustics) {
vg = X_CLAMP(vg + caustics, 0, 8191);
}
if (fogZ > FOG_MIN) if (fogZ > FOG_MIN)
{ {
vg += (fogZ - FOG_MIN) << FOG_SHIFT; vg += (fogZ - FOG_MIN) << FOG_SHIFT;
@@ -221,23 +232,32 @@ void transformRoomVertex(const RoomVertex* v)
res.x = x + (FRAME_WIDTH >> 1); res.x = x + (FRAME_WIDTH >> 1);
res.y = y + (FRAME_HEIGHT >> 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++) 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++; 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++) 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++; vertices++;
} }
} }
@@ -313,7 +333,7 @@ void rasterize(const Face* face, const VertexUV *top)
#else #else
if (face->flags & FACE_COLORED) { if (face->flags & FACE_COLORED) {
if (face->flags & FACE_FLAT) { if (face->flags & FACE_FLAT) {
if (face->flags & FACE_SHADOW) { if (face->flags & FACE_SPRITE) {
rasterizeS(pixel, top, top); rasterizeS(pixel, top, top);
} else { } else {
rasterizeF(pixel, top, top, face->flags & FACE_TEXTURE); 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); rasterizeG(pixel, top, top, face->flags & FACE_TEXTURE);
} }
} else { } else {
if (enableAlphaTest) { if (face->flags & FACE_SPRITE) {
rasterizeSprite(pixel, top, top + 1);
} else if (enableAlphaTest) {
if (face->flags & FACE_FLAT) { if (face->flags & FACE_FLAT) {
rasterizeFTA(pixel, top, top); rasterizeFTA(pixel, top, top);
} else { } else {
@@ -475,6 +497,14 @@ void drawPoly(Face* face, VertexUV* v)
rasterize(face, top); 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) void drawGlyph(const Sprite *sprite, int32 x, int32 y)
{ {
int32 w = sprite->r - sprite->l; 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); ASSERT(depth < OT_SIZE);
Face* face = gFaces + gFacesCount++;
face->next = otFaces[depth]; face->next = otFaces[depth];
otFaces[depth] = face; otFaces[depth] = face;
if (depth < otMin) otMin = depth; if (depth < otMin) otMin = depth;
if (depth > otMax) otMax = depth; if (depth > otMax) otMax = depth;
return face;
} }
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex) void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
@@ -556,18 +589,16 @@ void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
const Vertex* v3 = v + indices[2]; const Vertex* v3 = v + indices[2];
const Vertex* v4 = v + indices[3]; const Vertex* v4 = v + indices[3];
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16 || v4->clip == 16)
return;
if (enableClipping)
{
if (v1->clip & v2->clip & v3->clip & v4->clip) if (v1->clip & v2->clip & v3->clip & v4->clip)
return; return;
if (v1->clip | v2->clip | v3->clip | v4->clip) { int32 clip = (v1->clip | v2->clip | v3->clip | v4->clip);
if (clip & 32)
return;
if (clip) {
flags |= FACE_CLIPPED; flags |= FACE_CLIPPED;
} }
}
if (v1->g == v2->g && v1->g == v3->g && v1->g == v4->g) { if (v1->g == v2->g && v1->g == v3->g && v1->g == v4->g) {
flags |= FACE_FLAT; flags |= FACE_FLAT;
@@ -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; 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 Face* f = faceAdd(depth);
if (flags & FACE_SHADOW) {
depth = X_MAX(0, depth - 8);
}
Face *f = gFaces + gFacesCount++;
faceAddToOTable(f, depth);
f->flags = uint16(flags); f->flags = uint16(flags);
f->indices[0] = startVertex + indices[0]; f->indices[0] = v1 - gVertices;
f->indices[1] = startVertex + indices[1]; f->indices[1] = v2 - gVertices;
f->indices[2] = startVertex + indices[2]; f->indices[2] = v3 - gVertices;
f->indices[3] = startVertex + indices[3]; f->indices[3] = v4 - gVertices;
} }
void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex) void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
@@ -599,18 +623,17 @@ void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
const Vertex* v2 = v + indices[1]; const Vertex* v2 = v + indices[1];
const Vertex* v3 = v + indices[2]; const Vertex* v3 = v + indices[2];
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16)
return;
if (enableClipping)
{
if (v1->clip & v2->clip & v3->clip) if (v1->clip & v2->clip & v3->clip)
return; return;
if (v1->clip | v2->clip | v3->clip) { int32 clip = (v1->clip | v2->clip | v3->clip);
if (clip & 32)
return;
if (clip) {
flags |= FACE_CLIPPED; flags |= FACE_CLIPPED;
} }
}
if (v1->g == v2->g && v1->g == v3->g) { if (v1->g == v2->g && v1->g == v3->g) {
flags |= FACE_FLAT; flags |= FACE_FLAT;
@@ -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; int32 depth = X_MAX(v1->z, X_MAX(v2->z, v3->z)) >> OT_SHIFT;
Face *f = gFaces + gFacesCount++; Face* f = faceAdd(depth);
faceAddToOTable(f, depth);
f->flags = uint16(flags | FACE_TRIANGLE); f->flags = uint16(flags | FACE_TRIANGLE);
f->indices[0] = startVertex + indices[0]; f->indices[0] = v1 - gVertices;
f->indices[1] = startVertex + indices[1]; f->indices[1] = v2 - gVertices;
f->indices[2] = startVertex + indices[2]; f->indices[2] = v3 - gVertices;
}
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) void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex)
@@ -666,6 +760,7 @@ void flush()
if (gFacesCount) if (gFacesCount)
{ {
PROFILE_START(); PROFILE_START();
for (int32 i = otMax; i >= otMin; i--) for (int32 i = otMax; i >= otMin; i--)
{ {
if (!otFaces[i]) continue; if (!otFaces[i]) continue;
@@ -678,15 +773,31 @@ void flush()
uint32 flags = face->flags; uint32 flags = face->flags;
if (flags == FACE_SPRITE) {
const Sprite &sprite = sprites[face->indices[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;
ASSERT(v[0].v.x <= v[1].v.x);
ASSERT(v[0].v.y <= v[1].v.y);
drawSprite(face, v);
} else {
if (!(flags & FACE_COLORED)) if (!(flags & FACE_COLORED))
{ {
const Texture &tex = textures[face->flags & FACE_TEXTURE]; const Texture &tex = textures[flags & FACE_TEXTURE];
tile = tiles + (tex.tile << 16); tile = tiles + (tex.tile << 16);
v[0].t.uv = tex.uv0; v[0].t.uv = tex.uv0;
v[1].t.uv = tex.uv1; v[1].t.uv = tex.uv1;
v[2].t.uv = tex.uv2; v[2].t.uv = tex.uv2;
v[3].t.uv = tex.uv3; v[3].t.uv = tex.uv3;
enableAlphaTest = (tex.attribute == 1); enableAlphaTest = (tex.attribute == 1);
} }
@@ -706,6 +817,7 @@ void flush()
drawQuad(face, v); drawQuad(face, v);
} }
}; };
}
face = face->next; face = face->next;
} while (face); } while (face);

View File

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

View File

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