mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-06 13:16:52 +02:00
GBA animation, states & collision from fixed 30 fps branch, sound mixer, rotate90 mode (120x160), asm scanline rasterizer, move from libgba to libtonc
This commit is contained in:
@@ -26,6 +26,7 @@ SOURCES := .
|
||||
INCLUDES := include
|
||||
DATA := data
|
||||
MUSIC :=
|
||||
LIBTONC := $(DEVKITPRO)/libtonc
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
@@ -48,14 +49,14 @@ LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lmm -lgba
|
||||
LIBS := -lmm -ltonc
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBGBA)
|
||||
LIBDIRS := $(LIBGBA) $(LIBTONC)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
|
@@ -25,8 +25,15 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="camera.h" />
|
||||
<ClInclude Include="collision.h" />
|
||||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="draw.h" />
|
||||
<ClInclude Include="enemy.h" />
|
||||
<ClInclude Include="game.h" />
|
||||
<ClInclude Include="item.h" />
|
||||
<ClInclude Include="lara.h" />
|
||||
<ClInclude Include="level.h" />
|
||||
<ClInclude Include="sound.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
@@ -105,6 +112,7 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -139,6 +147,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@@ -6,61 +6,160 @@
|
||||
#define CAM_SPEED (1 << 3)
|
||||
#define CAM_ROT_SPEED (1 << 9)
|
||||
#define CAM_ROT_X_MAX int16(85 * 0x8000 / 180)
|
||||
#define CAM_DIST_FOLLOW (1024 + 512)
|
||||
|
||||
struct Camera {
|
||||
vec3i pos;
|
||||
int16 rotX, rotY;
|
||||
enum CameraMode
|
||||
{
|
||||
CAMERA_MODE_FREE = 0,
|
||||
CAMERA_MODE_FOLLOW = 1,
|
||||
CAMERA_MODE_COMBAT = 2,
|
||||
CAMERA_MODE_FIXED = 3,
|
||||
};
|
||||
|
||||
struct Camera
|
||||
{
|
||||
vec3i viewPos;
|
||||
vec3i targetPos;
|
||||
|
||||
int16 targetAngleX;
|
||||
int16 targetAngleY;
|
||||
int16 targetDist;
|
||||
|
||||
int16 angleX;
|
||||
int16 angleY;
|
||||
int32 room;
|
||||
|
||||
void init() {
|
||||
pos.x = 75162;
|
||||
pos.y = 2048;
|
||||
pos.z = 5000;
|
||||
Item* item;
|
||||
|
||||
rotX = 0;
|
||||
rotY = 16 << 8;
|
||||
CameraMode mode;
|
||||
bool modeSwitch;
|
||||
|
||||
//rotX = -0x1000;
|
||||
//rotY = int16(0x8000);
|
||||
void init()
|
||||
{
|
||||
item = NULL;
|
||||
mode = CAMERA_MODE_FOLLOW;
|
||||
modeSwitch = false;
|
||||
|
||||
viewPos.x = 75162;
|
||||
viewPos.y = 2048;
|
||||
viewPos.z = 5000;
|
||||
|
||||
targetPos = viewPos;
|
||||
targetAngleX = 0;
|
||||
targetAngleY = 0;
|
||||
targetDist = CAM_DIST_FOLLOW;
|
||||
|
||||
angleX = 0;
|
||||
angleY = 16 << 8;
|
||||
|
||||
//angleX = -0x1000;
|
||||
//angleY = int16(0x8000);
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (keys[IK_UP]) rotX -= CAM_ROT_SPEED;
|
||||
if (keys[IK_DOWN]) rotX += CAM_ROT_SPEED;
|
||||
if (keys[IK_LEFT]) rotY -= CAM_ROT_SPEED;
|
||||
if (keys[IK_RIGHT]) rotY += CAM_ROT_SPEED;
|
||||
|
||||
rotX = clamp(rotX, -CAM_ROT_X_MAX, CAM_ROT_X_MAX);
|
||||
|
||||
matrixSetView(pos.x, pos.y, pos.z, rotX, rotY);
|
||||
void freeControl()
|
||||
{
|
||||
matrixSetView(viewPos, angleX, angleY);
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
if (keys[IK_R]) {
|
||||
pos.x += m[0].x * CAM_SPEED >> 10;
|
||||
pos.y += m[0].y * CAM_SPEED >> 10;
|
||||
pos.z += m[0].z * CAM_SPEED >> 10;
|
||||
if (keys & IK_UP) angleX -= CAM_ROT_SPEED;
|
||||
if (keys & IK_DOWN) angleX += CAM_ROT_SPEED;
|
||||
if (keys & IK_LEFT) angleY -= CAM_ROT_SPEED;
|
||||
if (keys & IK_RIGHT) angleY += CAM_ROT_SPEED;
|
||||
|
||||
angleX = X_CLAMP(angleX, -CAM_ROT_X_MAX, CAM_ROT_X_MAX);
|
||||
|
||||
if (keys & IK_A)
|
||||
{
|
||||
viewPos.x += m[2].x * CAM_SPEED >> 10;
|
||||
viewPos.y += m[2].y * CAM_SPEED >> 10;
|
||||
viewPos.z += m[2].z * CAM_SPEED >> 10;
|
||||
}
|
||||
|
||||
if (keys[IK_L]) {
|
||||
pos.x -= m[0].x * CAM_SPEED >> 10;
|
||||
pos.y -= m[0].y * CAM_SPEED >> 10;
|
||||
pos.z -= m[0].z * CAM_SPEED >> 10;
|
||||
if (keys & IK_B)
|
||||
{
|
||||
viewPos.x -= m[2].x * CAM_SPEED >> 10;
|
||||
viewPos.y -= m[2].y * CAM_SPEED >> 10;
|
||||
viewPos.z -= m[2].z * CAM_SPEED >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (keys[IK_A]) {
|
||||
pos.x += m[2].x * CAM_SPEED >> 10;
|
||||
pos.y += m[2].y * CAM_SPEED >> 10;
|
||||
pos.z += m[2].z * CAM_SPEED >> 10;
|
||||
void updateRoom()
|
||||
{
|
||||
room = getRoomIndex(room, viewPos.x, viewPos.y, viewPos.z);
|
||||
const RoomInfo::Sector* sector = getSector(room, viewPos.x, viewPos.z);
|
||||
int32 floor = getFloor(sector, viewPos.x, viewPos.y, viewPos.z);
|
||||
int32 ceiling = getCeiling(sector, viewPos.x, viewPos.y, viewPos.z) - 256;
|
||||
|
||||
if (floor != WALL) {
|
||||
viewPos.y = X_MIN(viewPos.y, floor - 256);
|
||||
}
|
||||
|
||||
if (keys[IK_B]) {
|
||||
pos.x -= m[2].x * CAM_SPEED >> 10;
|
||||
pos.y -= m[2].y * CAM_SPEED >> 10;
|
||||
pos.z -= m[2].z * CAM_SPEED >> 10;
|
||||
if (ceiling != WALL)
|
||||
{
|
||||
viewPos.y = X_MAX(viewPos.y, ceiling + 256);
|
||||
}
|
||||
}
|
||||
|
||||
room = getRoomIndex(room, &pos);
|
||||
void update()
|
||||
{
|
||||
if (keys & IK_START)
|
||||
{
|
||||
if (!modeSwitch)
|
||||
{
|
||||
modeSwitch = true;
|
||||
if (mode != CAMERA_MODE_FREE) {
|
||||
mode = CAMERA_MODE_FREE;
|
||||
} else {
|
||||
mode = CAMERA_MODE_FOLLOW;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modeSwitch = false;
|
||||
}
|
||||
|
||||
if (mode == CAMERA_MODE_FREE)
|
||||
{
|
||||
freeControl();
|
||||
}
|
||||
|
||||
if (mode == CAMERA_MODE_FOLLOW && item) {
|
||||
int32 tx = item->pos.x;
|
||||
int32 ty = item->pos.y;
|
||||
int32 tz = item->pos.z;
|
||||
|
||||
const Box &box = getBoundingBox(item);
|
||||
ty += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
|
||||
|
||||
targetPos.x = tx;
|
||||
targetPos.y += (ty - targetPos.y) >> 2;
|
||||
targetPos.z = tz;
|
||||
|
||||
int16 angle = item->angleY + targetAngleY;
|
||||
|
||||
int32 dy = targetDist * phd_sin(targetAngleX) >> FIXED_SHIFT;
|
||||
int32 dz = targetDist * phd_cos(targetAngleX) >> FIXED_SHIFT;
|
||||
|
||||
int32 cx = targetPos.x - (phd_sin(angle) * dz >> FIXED_SHIFT);
|
||||
int32 cy = targetPos.y - 256 + dy;
|
||||
int32 cz = targetPos.z - (phd_cos(angle) * dz >> FIXED_SHIFT);
|
||||
|
||||
viewPos.x += (cx - viewPos.x) >> 2;
|
||||
viewPos.y += (cy - viewPos.y) >> 2;
|
||||
viewPos.z += (cz - viewPos.z) >> 2;
|
||||
|
||||
updateRoom();
|
||||
|
||||
anglesFromVector(targetPos.x - viewPos.x, targetPos.y - viewPos.y, targetPos.z - viewPos.z, angleX, angleY);
|
||||
}
|
||||
|
||||
matrixSetView(viewPos, angleX, angleY);
|
||||
|
||||
updateRoom();
|
||||
|
||||
targetAngleX = 0;
|
||||
targetAngleY = 0;
|
||||
targetDist = CAM_DIST_FOLLOW;
|
||||
}
|
||||
};
|
||||
|
||||
|
334
src/platform/gba/collision.h
Normal file
334
src/platform/gba/collision.h
Normal file
@@ -0,0 +1,334 @@
|
||||
#ifndef H_COLLISION
|
||||
#define H_COLLISION
|
||||
|
||||
#include "common.h"
|
||||
|
||||
enum CollisionType {
|
||||
CT_NONE = 0,
|
||||
CT_FRONT = (1 << 0),
|
||||
CT_LEFT = (1 << 1),
|
||||
CT_RIGHT = (1 << 2),
|
||||
CT_CEILING = (1 << 3),
|
||||
CT_FRONT_CEILING = (1 << 4),
|
||||
CT_FLOOR_CEILING = (1 << 5),
|
||||
};
|
||||
|
||||
struct CollisionInfo {
|
||||
|
||||
enum SideType {
|
||||
ST_MIDDLE,
|
||||
ST_FRONT,
|
||||
ST_LEFT,
|
||||
ST_RIGHT,
|
||||
ST_MAX
|
||||
};
|
||||
|
||||
struct Side {
|
||||
int32 floor;
|
||||
int32 ceiling;
|
||||
SlantType slantType;
|
||||
};
|
||||
|
||||
int16 *trigger;
|
||||
|
||||
Side m;
|
||||
Side f;
|
||||
Side l;
|
||||
Side r;
|
||||
|
||||
int32 radius;
|
||||
|
||||
int32 gapPos;
|
||||
int32 gapNeg;
|
||||
int32 gapCeiling;
|
||||
|
||||
vec3i offset;
|
||||
vec3i pos;
|
||||
|
||||
int16 angle;
|
||||
int16 quadrant;
|
||||
|
||||
CollisionType type;
|
||||
|
||||
int8 slantX;
|
||||
int8 slantZ;
|
||||
|
||||
bool enemyPush;
|
||||
bool enemyHit;
|
||||
bool staticHit;
|
||||
bool stopOnSlant;
|
||||
bool stopOnLava;
|
||||
|
||||
void setSide(SideType st, int32 floor, int32 ceiling)
|
||||
{
|
||||
SlantType slantType;
|
||||
|
||||
if (floorSlant.slantX == 0 && floorSlant.slantZ == 0) {
|
||||
slantType = SLANT_NONE;
|
||||
} else if (abs(floorSlant.slantX) < 3 && abs(floorSlant.slantZ) < 3) {
|
||||
slantType = SLANT_LOW;
|
||||
} else {
|
||||
slantType = SLANT_HIGH;
|
||||
}
|
||||
|
||||
if (st != ST_MIDDLE) {
|
||||
if (stopOnSlant && floor < 0 && slantType == SLANT_HIGH) {
|
||||
floor -= 0x7FFF;
|
||||
} else if (stopOnSlant && floor > 0 && slantType == SLANT_HIGH) {
|
||||
floor = 512;
|
||||
}/* TODO lava else if (stopOnLava && floor > 0 && trigger && FloorData(*(uint16*)trigger).cmd.func == FloorData::LAVA) {
|
||||
floor = 512;
|
||||
}*/
|
||||
}
|
||||
|
||||
Side *s = &m + st;
|
||||
s->slantType = slantType;
|
||||
s->floor = floor;
|
||||
s->ceiling = ceiling;
|
||||
}
|
||||
};
|
||||
|
||||
CollisionInfo cinfo;
|
||||
|
||||
int32 alignOffset(int32 a, int32 b)
|
||||
{
|
||||
int32 ca = a / 1024;
|
||||
int32 cb = b / 1024;
|
||||
|
||||
if (ca == cb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
a &= 1023;
|
||||
|
||||
if (ca < cb) {
|
||||
return 1025 - a;
|
||||
}
|
||||
|
||||
return -(a + 1);
|
||||
}
|
||||
|
||||
bool collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) {
|
||||
/*
|
||||
cinfo.staticHit = false;
|
||||
cinfo.offset = vec3i(0);
|
||||
|
||||
BoxV2 objBox(v2pos - vec3i(cinfo.radius, height, cinfo.radius),
|
||||
v2pos + vec3i(cinfo.radius, 0, cinfo.radius));
|
||||
|
||||
// TODO: check linked rooms
|
||||
for (int j = 0; j < level->roomsCount; j++) {
|
||||
const TR::Room &room = level->rooms[j];
|
||||
|
||||
for (int i = 0; i < room.meshesCount; i++) {
|
||||
TR::Room::Mesh &m = room.meshes[i];
|
||||
TR::StaticMesh &sm = level->staticMeshes[m.meshIndex];
|
||||
|
||||
if (sm.flags & 1) continue;
|
||||
|
||||
BoxV2 meshBox = sm.getBox(true);
|
||||
meshBox.rotate90(m.rotation.value / ANGLE_90);
|
||||
meshBox.translate(m.pos);
|
||||
|
||||
if (!objBox.intersect(meshBox)) continue;
|
||||
|
||||
cinfo.offset = meshBox.pushOut2D(objBox);
|
||||
|
||||
bool flip = (cinfo.quadrant > 1);
|
||||
|
||||
if (cinfo.quadrant & 1) {
|
||||
if (abs(cinfo.offset.z) > cinfo.radius) {
|
||||
cinfo.offset.z = cinfo.pos.z - p.z;
|
||||
cinfo.type = CT_FRONT;
|
||||
} else if (cinfo.offset.z != 0) {
|
||||
cinfo.offset.x = 0;
|
||||
cinfo.type = ((cinfo.offset.z > 0) ^ flip) ? CT_RIGHT : CT_LEFT;
|
||||
} else {
|
||||
cinfo.offset = vec3i(0);
|
||||
}
|
||||
} else {
|
||||
if (abs(cinfo.offset.x) > cinfo.radius) {
|
||||
cinfo.offset.x = cinfo.pos.x - p.x;
|
||||
cinfo.type = CT_FRONT;
|
||||
} else if (cinfo.offset.x != 0) {
|
||||
cinfo.offset.z = 0;
|
||||
cinfo.type = ((cinfo.offset.x > 0) ^ flip) ? CT_LEFT : CT_RIGHT;
|
||||
} else {
|
||||
cinfo.offset = vec3i(0);
|
||||
}
|
||||
}
|
||||
|
||||
cinfo.staticHit = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void collideRoom(Item* item, int32 height, int32 yOffset = 0)
|
||||
{
|
||||
cinfo.type = CT_NONE;
|
||||
cinfo.offset = vec3i(0, 0, 0);
|
||||
|
||||
vec3i p = item->pos;
|
||||
p.y += yOffset;
|
||||
|
||||
int32 y = p.y - height;
|
||||
|
||||
int32 cy = y - 160;
|
||||
|
||||
int32 floor, ceiling;
|
||||
|
||||
#define CHECK_HEIGHT(v) {\
|
||||
int32 roomIndex = getRoomIndex(item->room, v.x, cy, v.z);\
|
||||
const RoomInfo::Sector* sector = getSector(roomIndex, v.x, v.z);\
|
||||
floor = getFloor(sector, v.x, cy, v.z);\
|
||||
if (floor != WALL) floor -= p.y;\
|
||||
ceiling = getCeiling(sector, v.x, cy, v.z);\
|
||||
if (ceiling != WALL) ceiling -= y;\
|
||||
}
|
||||
|
||||
// middle
|
||||
CHECK_HEIGHT(p);
|
||||
|
||||
//cinfo.trigger = floorTrigger; TODO
|
||||
cinfo.slantX = floorSlant.slantX;
|
||||
cinfo.slantZ = floorSlant.slantZ;
|
||||
|
||||
cinfo.setSide(CollisionInfo::ST_MIDDLE, floor, ceiling);
|
||||
|
||||
vec3i f, l, r;
|
||||
int32 R = cinfo.radius;
|
||||
|
||||
switch (cinfo.quadrant) {
|
||||
case 0 : {
|
||||
f = vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, R);
|
||||
l = vec3i(-R, 0, R);
|
||||
r = vec3i( R, 0, R);
|
||||
break;
|
||||
}
|
||||
case 1 : {
|
||||
f = vec3i( R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT);
|
||||
l = vec3i( R, 0, R);
|
||||
r = vec3i( R, 0, -R);
|
||||
break;
|
||||
}
|
||||
case 2 : {
|
||||
f = vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, -R);
|
||||
l = vec3i( R, 0, -R);
|
||||
r = vec3i(-R, 0, -R);
|
||||
break;
|
||||
}
|
||||
case 3 : {
|
||||
f = vec3i(-R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT);
|
||||
l = vec3i(-R, 0, -R);
|
||||
r = vec3i(-R, 0, R);
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
f.x = f.y = f.z = 0;
|
||||
l.x = l.y = l.z = 0;
|
||||
r.x = r.y = r.z = 0;
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
f += p;
|
||||
l += p;
|
||||
r += p;
|
||||
|
||||
vec3i delta;
|
||||
delta.x = cinfo.pos.x - p.x;
|
||||
delta.y = cinfo.pos.y - p.y;
|
||||
delta.z = cinfo.pos.z - p.z;
|
||||
|
||||
// front
|
||||
CHECK_HEIGHT(f);
|
||||
cinfo.setSide(CollisionInfo::ST_FRONT, floor, ceiling);
|
||||
|
||||
// left
|
||||
CHECK_HEIGHT(l);
|
||||
cinfo.setSide(CollisionInfo::ST_LEFT, floor, ceiling);
|
||||
|
||||
// right
|
||||
CHECK_HEIGHT(r);
|
||||
cinfo.setSide(CollisionInfo::ST_RIGHT, floor, ceiling);
|
||||
|
||||
// static objects
|
||||
collideStatic(cinfo, p, height);
|
||||
|
||||
// check middle
|
||||
if (cinfo.m.floor == WALL)
|
||||
{
|
||||
cinfo.offset = delta;
|
||||
cinfo.type = CT_FRONT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cinfo.m.floor <= cinfo.m.ceiling)
|
||||
{
|
||||
cinfo.offset = delta;
|
||||
cinfo.type = CT_FLOOR_CEILING;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cinfo.m.ceiling >= 0)
|
||||
{
|
||||
cinfo.offset.y = cinfo.m.ceiling;
|
||||
cinfo.type = CT_CEILING;
|
||||
}
|
||||
|
||||
// front
|
||||
if (cinfo.f.floor > cinfo.gapPos ||
|
||||
cinfo.f.floor < cinfo.gapNeg ||
|
||||
cinfo.f.ceiling > cinfo.gapCeiling)
|
||||
{
|
||||
if (cinfo.quadrant & 1)
|
||||
{
|
||||
cinfo.offset.x = alignOffset(f.x, p.x);
|
||||
cinfo.offset.z = delta.z;
|
||||
} else {
|
||||
cinfo.offset.x = delta.x;
|
||||
cinfo.offset.z = alignOffset(f.z, p.z);
|
||||
}
|
||||
|
||||
cinfo.type = CT_FRONT;
|
||||
return;
|
||||
}
|
||||
|
||||
// front ceiling
|
||||
if (cinfo.f.ceiling >= cinfo.gapCeiling)
|
||||
{
|
||||
cinfo.offset = delta;
|
||||
cinfo.type = CT_FRONT_CEILING;
|
||||
return;
|
||||
}
|
||||
|
||||
// left
|
||||
if (cinfo.l.floor > cinfo.gapPos || cinfo.l.floor < cinfo.gapNeg)
|
||||
{
|
||||
if (cinfo.quadrant & 1) {
|
||||
cinfo.offset.z = alignOffset(l.z, f.z);
|
||||
} else {
|
||||
cinfo.offset.x = alignOffset(l.x, f.x);
|
||||
}
|
||||
cinfo.type = CT_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// right
|
||||
if (cinfo.r.floor > cinfo.gapPos || cinfo.r.floor < cinfo.gapNeg)
|
||||
{
|
||||
if (cinfo.quadrant & 1) {
|
||||
cinfo.offset.z = alignOffset(r.z, f.z);
|
||||
} else {
|
||||
cinfo.offset.x = alignOffset(r.x, f.x);
|
||||
}
|
||||
cinfo.type = CT_RIGHT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,11 +1,144 @@
|
||||
#include "common.h"
|
||||
|
||||
uint16 divTable[DIV_TABLE_SIZE]; // IWRAM 0.5 kb
|
||||
Rect clip;
|
||||
vec3i viewPos;
|
||||
Matrix matrixStack[MAX_MATRICES];
|
||||
int32 matrixStackIndex = 0;
|
||||
|
||||
const int16 sin_table[1025] = { // IWRAM 2 kb
|
||||
uint32 keys;
|
||||
|
||||
const uint16 divTable[DIV_TABLE_SIZE] = {
|
||||
0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492,
|
||||
0x2000, 0x1C71, 0x1999, 0x1745, 0x1555, 0x13B1, 0x1249, 0x1111,
|
||||
0x1000, 0x0F0F, 0x0E38, 0x0D79, 0x0CCC, 0x0C30, 0x0BA2, 0x0B21,
|
||||
0x0AAA, 0x0A3D, 0x09D8, 0x097B, 0x0924, 0x08D3, 0x0888, 0x0842,
|
||||
0x0800, 0x07C1, 0x0787, 0x0750, 0x071C, 0x06EB, 0x06BC, 0x0690,
|
||||
0x0666, 0x063E, 0x0618, 0x05F4, 0x05D1, 0x05B0, 0x0590, 0x0572,
|
||||
0x0555, 0x0539, 0x051E, 0x0505, 0x04EC, 0x04D4, 0x04BD, 0x04A7,
|
||||
0x0492, 0x047D, 0x0469, 0x0456, 0x0444, 0x0432, 0x0421, 0x0410,
|
||||
0x0400, 0x03F0, 0x03E0, 0x03D2, 0x03C3, 0x03B5, 0x03A8, 0x039B,
|
||||
0x038E, 0x0381, 0x0375, 0x0369, 0x035E, 0x0353, 0x0348, 0x033D,
|
||||
0x0333, 0x0329, 0x031F, 0x0315, 0x030C, 0x0303, 0x02FA, 0x02F1,
|
||||
0x02E8, 0x02E0, 0x02D8, 0x02D0, 0x02C8, 0x02C0, 0x02B9, 0x02B1,
|
||||
0x02AA, 0x02A3, 0x029C, 0x0295, 0x028F, 0x0288, 0x0282, 0x027C,
|
||||
0x0276, 0x0270, 0x026A, 0x0264, 0x025E, 0x0259, 0x0253, 0x024E,
|
||||
0x0249, 0x0243, 0x023E, 0x0239, 0x0234, 0x0230, 0x022B, 0x0226,
|
||||
0x0222, 0x021D, 0x0219, 0x0214, 0x0210, 0x020C, 0x0208, 0x0204,
|
||||
0x0200, 0x01FC, 0x01F8, 0x01F4, 0x01F0, 0x01EC, 0x01E9, 0x01E5,
|
||||
0x01E1, 0x01DE, 0x01DA, 0x01D7, 0x01D4, 0x01D0, 0x01CD, 0x01CA,
|
||||
0x01C7, 0x01C3, 0x01C0, 0x01BD, 0x01BA, 0x01B7, 0x01B4, 0x01B2,
|
||||
0x01AF, 0x01AC, 0x01A9, 0x01A6, 0x01A4, 0x01A1, 0x019E, 0x019C,
|
||||
0x0199, 0x0197, 0x0194, 0x0192, 0x018F, 0x018D, 0x018A, 0x0188,
|
||||
0x0186, 0x0183, 0x0181, 0x017F, 0x017D, 0x017A, 0x0178, 0x0176,
|
||||
0x0174, 0x0172, 0x0170, 0x016E, 0x016C, 0x016A, 0x0168, 0x0166,
|
||||
0x0164, 0x0162, 0x0160, 0x015E, 0x015C, 0x015A, 0x0158, 0x0157,
|
||||
0x0155, 0x0153, 0x0151, 0x0150, 0x014E, 0x014C, 0x014A, 0x0149,
|
||||
0x0147, 0x0146, 0x0144, 0x0142, 0x0141, 0x013F, 0x013E, 0x013C,
|
||||
0x013B, 0x0139, 0x0138, 0x0136, 0x0135, 0x0133, 0x0132, 0x0130,
|
||||
0x012F, 0x012E, 0x012C, 0x012B, 0x0129, 0x0128, 0x0127, 0x0125,
|
||||
0x0124, 0x0123, 0x0121, 0x0120, 0x011F, 0x011E, 0x011C, 0x011B,
|
||||
0x011A, 0x0119, 0x0118, 0x0116, 0x0115, 0x0114, 0x0113, 0x0112,
|
||||
0x0111, 0x010F, 0x010E, 0x010D, 0x010C, 0x010B, 0x010A, 0x0109,
|
||||
0x0108, 0x0107, 0x0106, 0x0105, 0x0104, 0x0103, 0x0102, 0x0101,
|
||||
0x0100, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FB, 0x00FA, 0x00F9,
|
||||
0x00F8, 0x00F7, 0x00F6, 0x00F5, 0x00F4, 0x00F3, 0x00F2, 0x00F1,
|
||||
0x00F0, 0x00F0, 0x00EF, 0x00EE, 0x00ED, 0x00EC, 0x00EB, 0x00EA,
|
||||
0x00EA, 0x00E9, 0x00E8, 0x00E7, 0x00E6, 0x00E5, 0x00E5, 0x00E4,
|
||||
0x00E3, 0x00E2, 0x00E1, 0x00E1, 0x00E0, 0x00DF, 0x00DE, 0x00DE,
|
||||
0x00DD, 0x00DC, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D8,
|
||||
0x00D7, 0x00D6, 0x00D6, 0x00D5, 0x00D4, 0x00D4, 0x00D3, 0x00D2,
|
||||
0x00D2, 0x00D1, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CD,
|
||||
0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C9, 0x00C8,
|
||||
0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C4, 0x00C3,
|
||||
0x00C3, 0x00C2, 0x00C1, 0x00C1, 0x00C0, 0x00C0, 0x00BF, 0x00BF,
|
||||
0x00BE, 0x00BD, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 0x00BB, 0x00BA,
|
||||
0x00BA, 0x00B9, 0x00B9, 0x00B8, 0x00B8, 0x00B7, 0x00B7, 0x00B6,
|
||||
0x00B6, 0x00B5, 0x00B5, 0x00B4, 0x00B4, 0x00B3, 0x00B3, 0x00B2,
|
||||
0x00B2, 0x00B1, 0x00B1, 0x00B0, 0x00B0, 0x00AF, 0x00AF, 0x00AE,
|
||||
0x00AE, 0x00AD, 0x00AD, 0x00AC, 0x00AC, 0x00AC, 0x00AB, 0x00AB,
|
||||
0x00AA, 0x00AA, 0x00A9, 0x00A9, 0x00A8, 0x00A8, 0x00A8, 0x00A7,
|
||||
0x00A7, 0x00A6, 0x00A6, 0x00A5, 0x00A5, 0x00A5, 0x00A4, 0x00A4,
|
||||
0x00A3, 0x00A3, 0x00A3, 0x00A2, 0x00A2, 0x00A1, 0x00A1, 0x00A1,
|
||||
0x00A0, 0x00A0, 0x009F, 0x009F, 0x009F, 0x009E, 0x009E, 0x009D,
|
||||
0x009D, 0x009D, 0x009C, 0x009C, 0x009C, 0x009B, 0x009B, 0x009A,
|
||||
0x009A, 0x009A, 0x0099, 0x0099, 0x0099, 0x0098, 0x0098, 0x0098,
|
||||
0x0097, 0x0097, 0x0097, 0x0096, 0x0096, 0x0095, 0x0095, 0x0095,
|
||||
0x0094, 0x0094, 0x0094, 0x0093, 0x0093, 0x0093, 0x0092, 0x0092,
|
||||
0x0092, 0x0091, 0x0091, 0x0091, 0x0090, 0x0090, 0x0090, 0x0090,
|
||||
0x008F, 0x008F, 0x008F, 0x008E, 0x008E, 0x008E, 0x008D, 0x008D,
|
||||
0x008D, 0x008C, 0x008C, 0x008C, 0x008C, 0x008B, 0x008B, 0x008B,
|
||||
0x008A, 0x008A, 0x008A, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088,
|
||||
0x0088, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086,
|
||||
0x0086, 0x0086, 0x0085, 0x0085, 0x0085, 0x0084, 0x0084, 0x0084,
|
||||
0x0084, 0x0083, 0x0083, 0x0083, 0x0083, 0x0082, 0x0082, 0x0082,
|
||||
0x0082, 0x0081, 0x0081, 0x0081, 0x0081, 0x0080, 0x0080, 0x0080,
|
||||
0x0080, 0x007F, 0x007F, 0x007F, 0x007F, 0x007E, 0x007E, 0x007E,
|
||||
0x007E, 0x007D, 0x007D, 0x007D, 0x007D, 0x007C, 0x007C, 0x007C,
|
||||
0x007C, 0x007B, 0x007B, 0x007B, 0x007B, 0x007A, 0x007A, 0x007A,
|
||||
0x007A, 0x007A, 0x0079, 0x0079, 0x0079, 0x0079, 0x0078, 0x0078,
|
||||
0x0078, 0x0078, 0x0078, 0x0077, 0x0077, 0x0077, 0x0077, 0x0076,
|
||||
0x0076, 0x0076, 0x0076, 0x0076, 0x0075, 0x0075, 0x0075, 0x0075,
|
||||
0x0075, 0x0074, 0x0074, 0x0074, 0x0074, 0x0073, 0x0073, 0x0073,
|
||||
0x0073, 0x0073, 0x0072, 0x0072, 0x0072, 0x0072, 0x0072, 0x0071,
|
||||
0x0071, 0x0071, 0x0071, 0x0071, 0x0070, 0x0070, 0x0070, 0x0070,
|
||||
0x0070, 0x0070, 0x006F, 0x006F, 0x006F, 0x006F, 0x006F, 0x006E,
|
||||
0x006E, 0x006E, 0x006E, 0x006E, 0x006D, 0x006D, 0x006D, 0x006D,
|
||||
0x006D, 0x006D, 0x006C, 0x006C, 0x006C, 0x006C, 0x006C, 0x006B,
|
||||
0x006B, 0x006B, 0x006B, 0x006B, 0x006B, 0x006A, 0x006A, 0x006A,
|
||||
0x006A, 0x006A, 0x006A, 0x0069, 0x0069, 0x0069, 0x0069, 0x0069,
|
||||
0x0069, 0x0068, 0x0068, 0x0068, 0x0068, 0x0068, 0x0068, 0x0067,
|
||||
0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0066, 0x0066, 0x0066,
|
||||
0x0066, 0x0066, 0x0066, 0x0065, 0x0065, 0x0065, 0x0065, 0x0065,
|
||||
0x0065, 0x0064, 0x0064, 0x0064, 0x0064, 0x0064, 0x0064, 0x0064,
|
||||
0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0063, 0x0062, 0x0062,
|
||||
0x0062, 0x0062, 0x0062, 0x0062, 0x0062, 0x0061, 0x0061, 0x0061,
|
||||
0x0061, 0x0061, 0x0061, 0x0061, 0x0060, 0x0060, 0x0060, 0x0060,
|
||||
0x0060, 0x0060, 0x0060, 0x005F, 0x005F, 0x005F, 0x005F, 0x005F,
|
||||
0x005F, 0x005F, 0x005E, 0x005E, 0x005E, 0x005E, 0x005E, 0x005E,
|
||||
0x005E, 0x005E, 0x005D, 0x005D, 0x005D, 0x005D, 0x005D, 0x005D,
|
||||
0x005D, 0x005C, 0x005C, 0x005C, 0x005C, 0x005C, 0x005C, 0x005C,
|
||||
0x005C, 0x005B, 0x005B, 0x005B, 0x005B, 0x005B, 0x005B, 0x005B,
|
||||
0x005B, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A, 0x005A,
|
||||
0x005A, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059, 0x0059,
|
||||
0x0059, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058,
|
||||
0x0058, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057, 0x0057,
|
||||
0x0057, 0x0057, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0055, 0x0055, 0x0055, 0x0055, 0x0055,
|
||||
0x0055, 0x0055, 0x0055, 0x0055, 0x0054, 0x0054, 0x0054, 0x0054,
|
||||
0x0054, 0x0054, 0x0054, 0x0054, 0x0054, 0x0053, 0x0053, 0x0053,
|
||||
0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0053, 0x0052, 0x0052,
|
||||
0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052, 0x0052,
|
||||
0x0051, 0x0051, 0x0051, 0x0051, 0x0051, 0x0051, 0x0051, 0x0051,
|
||||
0x0051, 0x0051, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050,
|
||||
0x0050, 0x0050, 0x0050, 0x0050, 0x004F, 0x004F, 0x004F, 0x004F,
|
||||
0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x004E, 0x004E,
|
||||
0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E, 0x004E,
|
||||
0x004E, 0x004D, 0x004D, 0x004D, 0x004D, 0x004D, 0x004D, 0x004D,
|
||||
0x004D, 0x004D, 0x004D, 0x004D, 0x004C, 0x004C, 0x004C, 0x004C,
|
||||
0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004C, 0x004B,
|
||||
0x004B, 0x004B, 0x004B, 0x004B, 0x004B, 0x004B, 0x004B, 0x004B,
|
||||
0x004B, 0x004B, 0x004A, 0x004A, 0x004A, 0x004A, 0x004A, 0x004A,
|
||||
0x004A, 0x004A, 0x004A, 0x004A, 0x004A, 0x004A, 0x0049, 0x0049,
|
||||
0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049, 0x0049,
|
||||
0x0049, 0x0049, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048,
|
||||
0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0047,
|
||||
0x0047, 0x0047, 0x0047, 0x0047, 0x0047, 0x0047, 0x0047, 0x0047,
|
||||
0x0047, 0x0047, 0x0047, 0x0047, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045,
|
||||
0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0045, 0x0044, 0x0044,
|
||||
0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044, 0x0044,
|
||||
0x0044, 0x0044, 0x0044, 0x0044, 0x0043, 0x0043, 0x0043, 0x0043,
|
||||
0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043, 0x0043,
|
||||
0x0043, 0x0043, 0x0043, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042,
|
||||
0x0042, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042, 0x0042,
|
||||
0x0042, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041,
|
||||
0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041,
|
||||
0x0041, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040,
|
||||
0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040
|
||||
};
|
||||
|
||||
const int16 sinTable[1025] = {
|
||||
0x0000, 0x0019, 0x0032, 0x004B, 0x0065, 0x007E, 0x0097, 0x00B0,
|
||||
0x00C9, 0x00E2, 0x00FB, 0x0114, 0x012E, 0x0147, 0x0160, 0x0179,
|
||||
0x0192, 0x01AB, 0x01C4, 0x01DD, 0x01F7, 0x0210, 0x0229, 0x0242,
|
||||
@@ -136,6 +269,271 @@ const int16 sin_table[1025] = { // IWRAM 2 kb
|
||||
0x3FFF, 0x3FFF, 0x3FFF, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000
|
||||
};
|
||||
|
||||
const int16 atanTable[2050] = {
|
||||
0x0000, 0x0005, 0x000A, 0x000F, 0x0014, 0x0019, 0x001F, 0x0024,
|
||||
0x0029, 0x002E, 0x0033, 0x0038, 0x003D, 0x0042, 0x0047, 0x004C,
|
||||
0x0051, 0x0057, 0x005C, 0x0061, 0x0066, 0x006B, 0x0070, 0x0075,
|
||||
0x007A, 0x007F, 0x0084, 0x008A, 0x008F, 0x0094, 0x0099, 0x009E,
|
||||
0x00A3, 0x00A8, 0x00AD, 0x00B2, 0x00B7, 0x00BC, 0x00C2, 0x00C7,
|
||||
0x00CC, 0x00D1, 0x00D6, 0x00DB, 0x00E0, 0x00E5, 0x00EA, 0x00EF,
|
||||
0x00F4, 0x00FA, 0x00FF, 0x0104, 0x0109, 0x010E, 0x0113, 0x0118,
|
||||
0x011D, 0x0122, 0x0127, 0x012C, 0x0131, 0x0137, 0x013C, 0x0141,
|
||||
0x0146, 0x014B, 0x0150, 0x0155, 0x015A, 0x015F, 0x0164, 0x0169,
|
||||
0x016F, 0x0174, 0x0179, 0x017E, 0x0183, 0x0188, 0x018D, 0x0192,
|
||||
0x0197, 0x019C, 0x01A1, 0x01A6, 0x01AC, 0x01B1, 0x01B6, 0x01BB,
|
||||
0x01C0, 0x01C5, 0x01CA, 0x01CF, 0x01D4, 0x01D9, 0x01DE, 0x01E3,
|
||||
0x01E9, 0x01EE, 0x01F3, 0x01F8, 0x01FD, 0x0202, 0x0207, 0x020C,
|
||||
0x0211, 0x0216, 0x021B, 0x0220, 0x0226, 0x022B, 0x0230, 0x0235,
|
||||
0x023A, 0x023F, 0x0244, 0x0249, 0x024E, 0x0253, 0x0258, 0x025D,
|
||||
0x0262, 0x0268, 0x026D, 0x0272, 0x0277, 0x027C, 0x0281, 0x0286,
|
||||
0x028B, 0x0290, 0x0295, 0x029A, 0x029F, 0x02A4, 0x02A9, 0x02AF,
|
||||
0x02B4, 0x02B9, 0x02BE, 0x02C3, 0x02C8, 0x02CD, 0x02D2, 0x02D7,
|
||||
0x02DC, 0x02E1, 0x02E6, 0x02EB, 0x02F0, 0x02F6, 0x02FB, 0x0300,
|
||||
0x0305, 0x030A, 0x030F, 0x0314, 0x0319, 0x031E, 0x0323, 0x0328,
|
||||
0x032D, 0x0332, 0x0337, 0x033C, 0x0341, 0x0347, 0x034C, 0x0351,
|
||||
0x0356, 0x035B, 0x0360, 0x0365, 0x036A, 0x036F, 0x0374, 0x0379,
|
||||
0x037E, 0x0383, 0x0388, 0x038D, 0x0392, 0x0397, 0x039C, 0x03A2,
|
||||
0x03A7, 0x03AC, 0x03B1, 0x03B6, 0x03BB, 0x03C0, 0x03C5, 0x03CA,
|
||||
0x03CF, 0x03D4, 0x03D9, 0x03DE, 0x03E3, 0x03E8, 0x03ED, 0x03F2,
|
||||
0x03F7, 0x03FC, 0x0401, 0x0407, 0x040C, 0x0411, 0x0416, 0x041B,
|
||||
0x0420, 0x0425, 0x042A, 0x042F, 0x0434, 0x0439, 0x043E, 0x0443,
|
||||
0x0448, 0x044D, 0x0452, 0x0457, 0x045C, 0x0461, 0x0466, 0x046B,
|
||||
0x0470, 0x0475, 0x047A, 0x047F, 0x0484, 0x0489, 0x048E, 0x0494,
|
||||
0x0499, 0x049E, 0x04A3, 0x04A8, 0x04AD, 0x04B2, 0x04B7, 0x04BC,
|
||||
0x04C1, 0x04C6, 0x04CB, 0x04D0, 0x04D5, 0x04DA, 0x04DF, 0x04E4,
|
||||
0x04E9, 0x04EE, 0x04F3, 0x04F8, 0x04FD, 0x0502, 0x0507, 0x050C,
|
||||
0x0511, 0x0516, 0x051B, 0x0520, 0x0525, 0x052A, 0x052F, 0x0534,
|
||||
0x0539, 0x053E, 0x0543, 0x0548, 0x054D, 0x0552, 0x0557, 0x055C,
|
||||
0x0561, 0x0566, 0x056B, 0x0570, 0x0575, 0x057A, 0x057F, 0x0584,
|
||||
0x0589, 0x058E, 0x0593, 0x0598, 0x059D, 0x05A2, 0x05A7, 0x05AC,
|
||||
0x05B1, 0x05B6, 0x05BB, 0x05C0, 0x05C5, 0x05CA, 0x05CF, 0x05D4,
|
||||
0x05D9, 0x05DE, 0x05E3, 0x05E8, 0x05ED, 0x05F2, 0x05F7, 0x05FC,
|
||||
0x0601, 0x0606, 0x060B, 0x0610, 0x0615, 0x061A, 0x061F, 0x0624,
|
||||
0x0629, 0x062E, 0x0633, 0x0638, 0x063D, 0x0642, 0x0647, 0x064C,
|
||||
0x0651, 0x0656, 0x065B, 0x0660, 0x0665, 0x066A, 0x066E, 0x0673,
|
||||
0x0678, 0x067D, 0x0682, 0x0687, 0x068C, 0x0691, 0x0696, 0x069B,
|
||||
0x06A0, 0x06A5, 0x06AA, 0x06AF, 0x06B4, 0x06B9, 0x06BE, 0x06C3,
|
||||
0x06C8, 0x06CD, 0x06D2, 0x06D7, 0x06DC, 0x06E1, 0x06E5, 0x06EA,
|
||||
0x06EF, 0x06F4, 0x06F9, 0x06FE, 0x0703, 0x0708, 0x070D, 0x0712,
|
||||
0x0717, 0x071C, 0x0721, 0x0726, 0x072B, 0x0730, 0x0735, 0x0739,
|
||||
0x073E, 0x0743, 0x0748, 0x074D, 0x0752, 0x0757, 0x075C, 0x0761,
|
||||
0x0766, 0x076B, 0x0770, 0x0775, 0x077A, 0x077E, 0x0783, 0x0788,
|
||||
0x078D, 0x0792, 0x0797, 0x079C, 0x07A1, 0x07A6, 0x07AB, 0x07B0,
|
||||
0x07B5, 0x07B9, 0x07BE, 0x07C3, 0x07C8, 0x07CD, 0x07D2, 0x07D7,
|
||||
0x07DC, 0x07E1, 0x07E6, 0x07EB, 0x07EF, 0x07F4, 0x07F9, 0x07FE,
|
||||
0x0803, 0x0808, 0x080D, 0x0812, 0x0817, 0x081C, 0x0820, 0x0825,
|
||||
0x082A, 0x082F, 0x0834, 0x0839, 0x083E, 0x0843, 0x0848, 0x084C,
|
||||
0x0851, 0x0856, 0x085B, 0x0860, 0x0865, 0x086A, 0x086F, 0x0873,
|
||||
0x0878, 0x087D, 0x0882, 0x0887, 0x088C, 0x0891, 0x0896, 0x089A,
|
||||
0x089F, 0x08A4, 0x08A9, 0x08AE, 0x08B3, 0x08B8, 0x08BD, 0x08C1,
|
||||
0x08C6, 0x08CB, 0x08D0, 0x08D5, 0x08DA, 0x08DF, 0x08E3, 0x08E8,
|
||||
0x08ED, 0x08F2, 0x08F7, 0x08FC, 0x0901, 0x0905, 0x090A, 0x090F,
|
||||
0x0914, 0x0919, 0x091E, 0x0922, 0x0927, 0x092C, 0x0931, 0x0936,
|
||||
0x093B, 0x093F, 0x0944, 0x0949, 0x094E, 0x0953, 0x0958, 0x095C,
|
||||
0x0961, 0x0966, 0x096B, 0x0970, 0x0975, 0x0979, 0x097E, 0x0983,
|
||||
0x0988, 0x098D, 0x0992, 0x0996, 0x099B, 0x09A0, 0x09A5, 0x09AA,
|
||||
0x09AE, 0x09B3, 0x09B8, 0x09BD, 0x09C2, 0x09C6, 0x09CB, 0x09D0,
|
||||
0x09D5, 0x09DA, 0x09DE, 0x09E3, 0x09E8, 0x09ED, 0x09F2, 0x09F6,
|
||||
0x09FB, 0x0A00, 0x0A05, 0x0A0A, 0x0A0E, 0x0A13, 0x0A18, 0x0A1D,
|
||||
0x0A22, 0x0A26, 0x0A2B, 0x0A30, 0x0A35, 0x0A39, 0x0A3E, 0x0A43,
|
||||
0x0A48, 0x0A4D, 0x0A51, 0x0A56, 0x0A5B, 0x0A60, 0x0A64, 0x0A69,
|
||||
0x0A6E, 0x0A73, 0x0A77, 0x0A7C, 0x0A81, 0x0A86, 0x0A8B, 0x0A8F,
|
||||
0x0A94, 0x0A99, 0x0A9E, 0x0AA2, 0x0AA7, 0x0AAC, 0x0AB1, 0x0AB5,
|
||||
0x0ABA, 0x0ABF, 0x0AC4, 0x0AC8, 0x0ACD, 0x0AD2, 0x0AD7, 0x0ADB,
|
||||
0x0AE0, 0x0AE5, 0x0AE9, 0x0AEE, 0x0AF3, 0x0AF8, 0x0AFC, 0x0B01,
|
||||
0x0B06, 0x0B0B, 0x0B0F, 0x0B14, 0x0B19, 0x0B1E, 0x0B22, 0x0B27,
|
||||
0x0B2C, 0x0B30, 0x0B35, 0x0B3A, 0x0B3F, 0x0B43, 0x0B48, 0x0B4D,
|
||||
0x0B51, 0x0B56, 0x0B5B, 0x0B60, 0x0B64, 0x0B69, 0x0B6E, 0x0B72,
|
||||
0x0B77, 0x0B7C, 0x0B80, 0x0B85, 0x0B8A, 0x0B8F, 0x0B93, 0x0B98,
|
||||
0x0B9D, 0x0BA1, 0x0BA6, 0x0BAB, 0x0BAF, 0x0BB4, 0x0BB9, 0x0BBD,
|
||||
0x0BC2, 0x0BC7, 0x0BCB, 0x0BD0, 0x0BD5, 0x0BD9, 0x0BDE, 0x0BE3,
|
||||
0x0BE7, 0x0BEC, 0x0BF1, 0x0BF5, 0x0BFA, 0x0BFF, 0x0C03, 0x0C08,
|
||||
0x0C0D, 0x0C11, 0x0C16, 0x0C1B, 0x0C1F, 0x0C24, 0x0C29, 0x0C2D,
|
||||
0x0C32, 0x0C37, 0x0C3B, 0x0C40, 0x0C45, 0x0C49, 0x0C4E, 0x0C53,
|
||||
0x0C57, 0x0C5C, 0x0C60, 0x0C65, 0x0C6A, 0x0C6E, 0x0C73, 0x0C78,
|
||||
0x0C7C, 0x0C81, 0x0C86, 0x0C8A, 0x0C8F, 0x0C93, 0x0C98, 0x0C9D,
|
||||
0x0CA1, 0x0CA6, 0x0CAB, 0x0CAF, 0x0CB4, 0x0CB8, 0x0CBD, 0x0CC2,
|
||||
0x0CC6, 0x0CCB, 0x0CCF, 0x0CD4, 0x0CD9, 0x0CDD, 0x0CE2, 0x0CE6,
|
||||
0x0CEB, 0x0CF0, 0x0CF4, 0x0CF9, 0x0CFD, 0x0D02, 0x0D07, 0x0D0B,
|
||||
0x0D10, 0x0D14, 0x0D19, 0x0D1E, 0x0D22, 0x0D27, 0x0D2B, 0x0D30,
|
||||
0x0D34, 0x0D39, 0x0D3E, 0x0D42, 0x0D47, 0x0D4B, 0x0D50, 0x0D54,
|
||||
0x0D59, 0x0D5E, 0x0D62, 0x0D67, 0x0D6B, 0x0D70, 0x0D74, 0x0D79,
|
||||
0x0D7D, 0x0D82, 0x0D87, 0x0D8B, 0x0D90, 0x0D94, 0x0D99, 0x0D9D,
|
||||
0x0DA2, 0x0DA6, 0x0DAB, 0x0DAF, 0x0DB4, 0x0DB9, 0x0DBD, 0x0DC2,
|
||||
0x0DC6, 0x0DCB, 0x0DCF, 0x0DD4, 0x0DD8, 0x0DDD, 0x0DE1, 0x0DE6,
|
||||
0x0DEA, 0x0DEF, 0x0DF3, 0x0DF8, 0x0DFC, 0x0E01, 0x0E05, 0x0E0A,
|
||||
0x0E0F, 0x0E13, 0x0E18, 0x0E1C, 0x0E21, 0x0E25, 0x0E2A, 0x0E2E,
|
||||
0x0E33, 0x0E37, 0x0E3C, 0x0E40, 0x0E45, 0x0E49, 0x0E4E, 0x0E52,
|
||||
0x0E56, 0x0E5B, 0x0E5F, 0x0E64, 0x0E68, 0x0E6D, 0x0E71, 0x0E76,
|
||||
0x0E7A, 0x0E7F, 0x0E83, 0x0E88, 0x0E8C, 0x0E91, 0x0E95, 0x0E9A,
|
||||
0x0E9E, 0x0EA3, 0x0EA7, 0x0EAC, 0x0EB0, 0x0EB4, 0x0EB9, 0x0EBD,
|
||||
0x0EC2, 0x0EC6, 0x0ECB, 0x0ECF, 0x0ED4, 0x0ED8, 0x0EDC, 0x0EE1,
|
||||
0x0EE5, 0x0EEA, 0x0EEE, 0x0EF3, 0x0EF7, 0x0EFC, 0x0F00, 0x0F04,
|
||||
0x0F09, 0x0F0D, 0x0F12, 0x0F16, 0x0F1B, 0x0F1F, 0x0F23, 0x0F28,
|
||||
0x0F2C, 0x0F31, 0x0F35, 0x0F3A, 0x0F3E, 0x0F42, 0x0F47, 0x0F4B,
|
||||
0x0F50, 0x0F54, 0x0F58, 0x0F5D, 0x0F61, 0x0F66, 0x0F6A, 0x0F6E,
|
||||
0x0F73, 0x0F77, 0x0F7C, 0x0F80, 0x0F84, 0x0F89, 0x0F8D, 0x0F91,
|
||||
0x0F96, 0x0F9A, 0x0F9F, 0x0FA3, 0x0FA7, 0x0FAC, 0x0FB0, 0x0FB5,
|
||||
0x0FB9, 0x0FBD, 0x0FC2, 0x0FC6, 0x0FCA, 0x0FCF, 0x0FD3, 0x0FD7,
|
||||
0x0FDC, 0x0FE0, 0x0FE5, 0x0FE9, 0x0FED, 0x0FF2, 0x0FF6, 0x0FFA,
|
||||
0x0FFF, 0x1003, 0x1007, 0x100C, 0x1010, 0x1014, 0x1019, 0x101D,
|
||||
0x1021, 0x1026, 0x102A, 0x102E, 0x1033, 0x1037, 0x103B, 0x1040,
|
||||
0x1044, 0x1048, 0x104D, 0x1051, 0x1055, 0x105A, 0x105E, 0x1062,
|
||||
0x1067, 0x106B, 0x106F, 0x1073, 0x1078, 0x107C, 0x1080, 0x1085,
|
||||
0x1089, 0x108D, 0x1092, 0x1096, 0x109A, 0x109E, 0x10A3, 0x10A7,
|
||||
0x10AB, 0x10B0, 0x10B4, 0x10B8, 0x10BC, 0x10C1, 0x10C5, 0x10C9,
|
||||
0x10CE, 0x10D2, 0x10D6, 0x10DA, 0x10DF, 0x10E3, 0x10E7, 0x10EB,
|
||||
0x10F0, 0x10F4, 0x10F8, 0x10FD, 0x1101, 0x1105, 0x1109, 0x110E,
|
||||
0x1112, 0x1116, 0x111A, 0x111F, 0x1123, 0x1127, 0x112B, 0x1130,
|
||||
0x1134, 0x1138, 0x113C, 0x1140, 0x1145, 0x1149, 0x114D, 0x1151,
|
||||
0x1156, 0x115A, 0x115E, 0x1162, 0x1166, 0x116B, 0x116F, 0x1173,
|
||||
0x1177, 0x117C, 0x1180, 0x1184, 0x1188, 0x118C, 0x1191, 0x1195,
|
||||
0x1199, 0x119D, 0x11A1, 0x11A6, 0x11AA, 0x11AE, 0x11B2, 0x11B6,
|
||||
0x11BB, 0x11BF, 0x11C3, 0x11C7, 0x11CB, 0x11CF, 0x11D4, 0x11D8,
|
||||
0x11DC, 0x11E0, 0x11E4, 0x11E9, 0x11ED, 0x11F1, 0x11F5, 0x11F9,
|
||||
0x11FD, 0x1202, 0x1206, 0x120A, 0x120E, 0x1212, 0x1216, 0x121A,
|
||||
0x121F, 0x1223, 0x1227, 0x122B, 0x122F, 0x1233, 0x1237, 0x123C,
|
||||
0x1240, 0x1244, 0x1248, 0x124C, 0x1250, 0x1254, 0x1259, 0x125D,
|
||||
0x1261, 0x1265, 0x1269, 0x126D, 0x1271, 0x1275, 0x127A, 0x127E,
|
||||
0x1282, 0x1286, 0x128A, 0x128E, 0x1292, 0x1296, 0x129A, 0x129F,
|
||||
0x12A3, 0x12A7, 0x12AB, 0x12AF, 0x12B3, 0x12B7, 0x12BB, 0x12BF,
|
||||
0x12C3, 0x12C7, 0x12CC, 0x12D0, 0x12D4, 0x12D8, 0x12DC, 0x12E0,
|
||||
0x12E4, 0x12E8, 0x12EC, 0x12F0, 0x12F4, 0x12F8, 0x12FC, 0x1301,
|
||||
0x1305, 0x1309, 0x130D, 0x1311, 0x1315, 0x1319, 0x131D, 0x1321,
|
||||
0x1325, 0x1329, 0x132D, 0x1331, 0x1335, 0x1339, 0x133D, 0x1341,
|
||||
0x1345, 0x1349, 0x134D, 0x1351, 0x1355, 0x135A, 0x135E, 0x1362,
|
||||
0x1366, 0x136A, 0x136E, 0x1372, 0x1376, 0x137A, 0x137E, 0x1382,
|
||||
0x1386, 0x138A, 0x138E, 0x1392, 0x1396, 0x139A, 0x139E, 0x13A2,
|
||||
0x13A6, 0x13AA, 0x13AE, 0x13B2, 0x13B6, 0x13BA, 0x13BE, 0x13C2,
|
||||
0x13C6, 0x13CA, 0x13CE, 0x13D2, 0x13D6, 0x13DA, 0x13DE, 0x13E2,
|
||||
0x13E6, 0x13E9, 0x13ED, 0x13F1, 0x13F5, 0x13F9, 0x13FD, 0x1401,
|
||||
0x1405, 0x1409, 0x140D, 0x1411, 0x1415, 0x1419, 0x141D, 0x1421,
|
||||
0x1425, 0x1429, 0x142D, 0x1431, 0x1435, 0x1439, 0x143D, 0x1440,
|
||||
0x1444, 0x1448, 0x144C, 0x1450, 0x1454, 0x1458, 0x145C, 0x1460,
|
||||
0x1464, 0x1468, 0x146C, 0x1470, 0x1473, 0x1477, 0x147B, 0x147F,
|
||||
0x1483, 0x1487, 0x148B, 0x148F, 0x1493, 0x1497, 0x149B, 0x149E,
|
||||
0x14A2, 0x14A6, 0x14AA, 0x14AE, 0x14B2, 0x14B6, 0x14BA, 0x14BE,
|
||||
0x14C1, 0x14C5, 0x14C9, 0x14CD, 0x14D1, 0x14D5, 0x14D9, 0x14DD,
|
||||
0x14E0, 0x14E4, 0x14E8, 0x14EC, 0x14F0, 0x14F4, 0x14F8, 0x14FB,
|
||||
0x14FF, 0x1503, 0x1507, 0x150B, 0x150F, 0x1513, 0x1516, 0x151A,
|
||||
0x151E, 0x1522, 0x1526, 0x152A, 0x152D, 0x1531, 0x1535, 0x1539,
|
||||
0x153D, 0x1541, 0x1544, 0x1548, 0x154C, 0x1550, 0x1554, 0x1558,
|
||||
0x155B, 0x155F, 0x1563, 0x1567, 0x156B, 0x156E, 0x1572, 0x1576,
|
||||
0x157A, 0x157E, 0x1581, 0x1585, 0x1589, 0x158D, 0x1591, 0x1594,
|
||||
0x1598, 0x159C, 0x15A0, 0x15A4, 0x15A7, 0x15AB, 0x15AF, 0x15B3,
|
||||
0x15B7, 0x15BA, 0x15BE, 0x15C2, 0x15C6, 0x15C9, 0x15CD, 0x15D1,
|
||||
0x15D5, 0x15D8, 0x15DC, 0x15E0, 0x15E4, 0x15E8, 0x15EB, 0x15EF,
|
||||
0x15F3, 0x15F7, 0x15FA, 0x15FE, 0x1602, 0x1606, 0x1609, 0x160D,
|
||||
0x1611, 0x1614, 0x1618, 0x161C, 0x1620, 0x1623, 0x1627, 0x162B,
|
||||
0x162F, 0x1632, 0x1636, 0x163A, 0x163E, 0x1641, 0x1645, 0x1649,
|
||||
0x164C, 0x1650, 0x1654, 0x1658, 0x165B, 0x165F, 0x1663, 0x1666,
|
||||
0x166A, 0x166E, 0x1671, 0x1675, 0x1679, 0x167D, 0x1680, 0x1684,
|
||||
0x1688, 0x168B, 0x168F, 0x1693, 0x1696, 0x169A, 0x169E, 0x16A1,
|
||||
0x16A5, 0x16A9, 0x16AC, 0x16B0, 0x16B4, 0x16B7, 0x16BB, 0x16BF,
|
||||
0x16C2, 0x16C6, 0x16CA, 0x16CD, 0x16D1, 0x16D5, 0x16D8, 0x16DC,
|
||||
0x16E0, 0x16E3, 0x16E7, 0x16EB, 0x16EE, 0x16F2, 0x16F6, 0x16F9,
|
||||
0x16FD, 0x1700, 0x1704, 0x1708, 0x170B, 0x170F, 0x1713, 0x1716,
|
||||
0x171A, 0x171D, 0x1721, 0x1725, 0x1728, 0x172C, 0x1730, 0x1733,
|
||||
0x1737, 0x173A, 0x173E, 0x1742, 0x1745, 0x1749, 0x174C, 0x1750,
|
||||
0x1754, 0x1757, 0x175B, 0x175E, 0x1762, 0x1766, 0x1769, 0x176D,
|
||||
0x1770, 0x1774, 0x1778, 0x177B, 0x177F, 0x1782, 0x1786, 0x1789,
|
||||
0x178D, 0x1791, 0x1794, 0x1798, 0x179B, 0x179F, 0x17A2, 0x17A6,
|
||||
0x17AA, 0x17AD, 0x17B1, 0x17B4, 0x17B8, 0x17BB, 0x17BF, 0x17C2,
|
||||
0x17C6, 0x17C9, 0x17CD, 0x17D1, 0x17D4, 0x17D8, 0x17DB, 0x17DF,
|
||||
0x17E2, 0x17E6, 0x17E9, 0x17ED, 0x17F0, 0x17F4, 0x17F7, 0x17FB,
|
||||
0x17FE, 0x1802, 0x1806, 0x1809, 0x180D, 0x1810, 0x1814, 0x1817,
|
||||
0x181B, 0x181E, 0x1822, 0x1825, 0x1829, 0x182C, 0x1830, 0x1833,
|
||||
0x1837, 0x183A, 0x183E, 0x1841, 0x1845, 0x1848, 0x184C, 0x184F,
|
||||
0x1853, 0x1856, 0x185A, 0x185D, 0x1860, 0x1864, 0x1867, 0x186B,
|
||||
0x186E, 0x1872, 0x1875, 0x1879, 0x187C, 0x1880, 0x1883, 0x1887,
|
||||
0x188A, 0x188E, 0x1891, 0x1894, 0x1898, 0x189B, 0x189F, 0x18A2,
|
||||
0x18A6, 0x18A9, 0x18AD, 0x18B0, 0x18B3, 0x18B7, 0x18BA, 0x18BE,
|
||||
0x18C1, 0x18C5, 0x18C8, 0x18CC, 0x18CF, 0x18D2, 0x18D6, 0x18D9,
|
||||
0x18DD, 0x18E0, 0x18E3, 0x18E7, 0x18EA, 0x18EE, 0x18F1, 0x18F5,
|
||||
0x18F8, 0x18FB, 0x18FF, 0x1902, 0x1906, 0x1909, 0x190C, 0x1910,
|
||||
0x1913, 0x1917, 0x191A, 0x191D, 0x1921, 0x1924, 0x1928, 0x192B,
|
||||
0x192E, 0x1932, 0x1935, 0x1938, 0x193C, 0x193F, 0x1943, 0x1946,
|
||||
0x1949, 0x194D, 0x1950, 0x1953, 0x1957, 0x195A, 0x195D, 0x1961,
|
||||
0x1964, 0x1968, 0x196B, 0x196E, 0x1972, 0x1975, 0x1978, 0x197C,
|
||||
0x197F, 0x1982, 0x1986, 0x1989, 0x198C, 0x1990, 0x1993, 0x1996,
|
||||
0x199A, 0x199D, 0x19A0, 0x19A4, 0x19A7, 0x19AA, 0x19AE, 0x19B1,
|
||||
0x19B4, 0x19B8, 0x19BB, 0x19BE, 0x19C2, 0x19C5, 0x19C8, 0x19CC,
|
||||
0x19CF, 0x19D2, 0x19D5, 0x19D9, 0x19DC, 0x19DF, 0x19E3, 0x19E6,
|
||||
0x19E9, 0x19ED, 0x19F0, 0x19F3, 0x19F6, 0x19FA, 0x19FD, 0x1A00,
|
||||
0x1A04, 0x1A07, 0x1A0A, 0x1A0D, 0x1A11, 0x1A14, 0x1A17, 0x1A1B,
|
||||
0x1A1E, 0x1A21, 0x1A24, 0x1A28, 0x1A2B, 0x1A2E, 0x1A31, 0x1A35,
|
||||
0x1A38, 0x1A3B, 0x1A3E, 0x1A42, 0x1A45, 0x1A48, 0x1A4B, 0x1A4F,
|
||||
0x1A52, 0x1A55, 0x1A58, 0x1A5C, 0x1A5F, 0x1A62, 0x1A65, 0x1A69,
|
||||
0x1A6C, 0x1A6F, 0x1A72, 0x1A76, 0x1A79, 0x1A7C, 0x1A7F, 0x1A83,
|
||||
0x1A86, 0x1A89, 0x1A8C, 0x1A8F, 0x1A93, 0x1A96, 0x1A99, 0x1A9C,
|
||||
0x1A9F, 0x1AA3, 0x1AA6, 0x1AA9, 0x1AAC, 0x1AB0, 0x1AB3, 0x1AB6,
|
||||
0x1AB9, 0x1ABC, 0x1AC0, 0x1AC3, 0x1AC6, 0x1AC9, 0x1ACC, 0x1ACF,
|
||||
0x1AD3, 0x1AD6, 0x1AD9, 0x1ADC, 0x1ADF, 0x1AE3, 0x1AE6, 0x1AE9,
|
||||
0x1AEC, 0x1AEF, 0x1AF2, 0x1AF6, 0x1AF9, 0x1AFC, 0x1AFF, 0x1B02,
|
||||
0x1B05, 0x1B09, 0x1B0C, 0x1B0F, 0x1B12, 0x1B15, 0x1B18, 0x1B1C,
|
||||
0x1B1F, 0x1B22, 0x1B25, 0x1B28, 0x1B2B, 0x1B2E, 0x1B32, 0x1B35,
|
||||
0x1B38, 0x1B3B, 0x1B3E, 0x1B41, 0x1B44, 0x1B48, 0x1B4B, 0x1B4E,
|
||||
0x1B51, 0x1B54, 0x1B57, 0x1B5A, 0x1B5D, 0x1B61, 0x1B64, 0x1B67,
|
||||
0x1B6A, 0x1B6D, 0x1B70, 0x1B73, 0x1B76, 0x1B79, 0x1B7D, 0x1B80,
|
||||
0x1B83, 0x1B86, 0x1B89, 0x1B8C, 0x1B8F, 0x1B92, 0x1B95, 0x1B98,
|
||||
0x1B9C, 0x1B9F, 0x1BA2, 0x1BA5, 0x1BA8, 0x1BAB, 0x1BAE, 0x1BB1,
|
||||
0x1BB4, 0x1BB7, 0x1BBA, 0x1BBD, 0x1BC1, 0x1BC4, 0x1BC7, 0x1BCA,
|
||||
0x1BCD, 0x1BD0, 0x1BD3, 0x1BD6, 0x1BD9, 0x1BDC, 0x1BDF, 0x1BE2,
|
||||
0x1BE5, 0x1BE8, 0x1BEB, 0x1BEE, 0x1BF2, 0x1BF5, 0x1BF8, 0x1BFB,
|
||||
0x1BFE, 0x1C01, 0x1C04, 0x1C07, 0x1C0A, 0x1C0D, 0x1C10, 0x1C13,
|
||||
0x1C16, 0x1C19, 0x1C1C, 0x1C1F, 0x1C22, 0x1C25, 0x1C28, 0x1C2B,
|
||||
0x1C2E, 0x1C31, 0x1C34, 0x1C37, 0x1C3A, 0x1C3D, 0x1C40, 0x1C43,
|
||||
0x1C46, 0x1C49, 0x1C4C, 0x1C4F, 0x1C52, 0x1C55, 0x1C58, 0x1C5B,
|
||||
0x1C5E, 0x1C61, 0x1C64, 0x1C67, 0x1C6A, 0x1C6D, 0x1C70, 0x1C73,
|
||||
0x1C76, 0x1C79, 0x1C7C, 0x1C7F, 0x1C82, 0x1C85, 0x1C88, 0x1C8B,
|
||||
0x1C8E, 0x1C91, 0x1C94, 0x1C97, 0x1C9A, 0x1C9D, 0x1CA0, 0x1CA3,
|
||||
0x1CA6, 0x1CA9, 0x1CAC, 0x1CAF, 0x1CB2, 0x1CB5, 0x1CB8, 0x1CBB,
|
||||
0x1CBE, 0x1CC1, 0x1CC3, 0x1CC6, 0x1CC9, 0x1CCC, 0x1CCF, 0x1CD2,
|
||||
0x1CD5, 0x1CD8, 0x1CDB, 0x1CDE, 0x1CE1, 0x1CE4, 0x1CE7, 0x1CEA,
|
||||
0x1CED, 0x1CF0, 0x1CF3, 0x1CF5, 0x1CF8, 0x1CFB, 0x1CFE, 0x1D01,
|
||||
0x1D04, 0x1D07, 0x1D0A, 0x1D0D, 0x1D10, 0x1D13, 0x1D16, 0x1D18,
|
||||
0x1D1B, 0x1D1E, 0x1D21, 0x1D24, 0x1D27, 0x1D2A, 0x1D2D, 0x1D30,
|
||||
0x1D33, 0x1D35, 0x1D38, 0x1D3B, 0x1D3E, 0x1D41, 0x1D44, 0x1D47,
|
||||
0x1D4A, 0x1D4D, 0x1D4F, 0x1D52, 0x1D55, 0x1D58, 0x1D5B, 0x1D5E,
|
||||
0x1D61, 0x1D64, 0x1D66, 0x1D69, 0x1D6C, 0x1D6F, 0x1D72, 0x1D75,
|
||||
0x1D78, 0x1D7B, 0x1D7D, 0x1D80, 0x1D83, 0x1D86, 0x1D89, 0x1D8C,
|
||||
0x1D8E, 0x1D91, 0x1D94, 0x1D97, 0x1D9A, 0x1D9D, 0x1DA0, 0x1DA2,
|
||||
0x1DA5, 0x1DA8, 0x1DAB, 0x1DAE, 0x1DB1, 0x1DB3, 0x1DB6, 0x1DB9,
|
||||
0x1DBC, 0x1DBF, 0x1DC2, 0x1DC4, 0x1DC7, 0x1DCA, 0x1DCD, 0x1DD0,
|
||||
0x1DD3, 0x1DD5, 0x1DD8, 0x1DDB, 0x1DDE, 0x1DE1, 0x1DE3, 0x1DE6,
|
||||
0x1DE9, 0x1DEC, 0x1DEF, 0x1DF1, 0x1DF4, 0x1DF7, 0x1DFA, 0x1DFD,
|
||||
0x1DFF, 0x1E02, 0x1E05, 0x1E08, 0x1E0B, 0x1E0D, 0x1E10, 0x1E13,
|
||||
0x1E16, 0x1E19, 0x1E1B, 0x1E1E, 0x1E21, 0x1E24, 0x1E26, 0x1E29,
|
||||
0x1E2C, 0x1E2F, 0x1E32, 0x1E34, 0x1E37, 0x1E3A, 0x1E3D, 0x1E3F,
|
||||
0x1E42, 0x1E45, 0x1E48, 0x1E4A, 0x1E4D, 0x1E50, 0x1E53, 0x1E55,
|
||||
0x1E58, 0x1E5B, 0x1E5E, 0x1E60, 0x1E63, 0x1E66, 0x1E69, 0x1E6B,
|
||||
0x1E6E, 0x1E71, 0x1E74, 0x1E76, 0x1E79, 0x1E7C, 0x1E7F, 0x1E81,
|
||||
0x1E84, 0x1E87, 0x1E8A, 0x1E8C, 0x1E8F, 0x1E92, 0x1E94, 0x1E97,
|
||||
0x1E9A, 0x1E9D, 0x1E9F, 0x1EA2, 0x1EA5, 0x1EA8, 0x1EAA, 0x1EAD,
|
||||
0x1EB0, 0x1EB2, 0x1EB5, 0x1EB8, 0x1EBA, 0x1EBD, 0x1EC0, 0x1EC3,
|
||||
0x1EC5, 0x1EC8, 0x1ECB, 0x1ECD, 0x1ED0, 0x1ED3, 0x1ED5, 0x1ED8,
|
||||
0x1EDB, 0x1EDE, 0x1EE0, 0x1EE3, 0x1EE6, 0x1EE8, 0x1EEB, 0x1EEE,
|
||||
0x1EF0, 0x1EF3, 0x1EF6, 0x1EF8, 0x1EFB, 0x1EFE, 0x1F00, 0x1F03,
|
||||
0x1F06, 0x1F08, 0x1F0B, 0x1F0E, 0x1F10, 0x1F13, 0x1F16, 0x1F18,
|
||||
0x1F1B, 0x1F1E, 0x1F20, 0x1F23, 0x1F26, 0x1F28, 0x1F2B, 0x1F2E,
|
||||
0x1F30, 0x1F33, 0x1F36, 0x1F38, 0x1F3B, 0x1F3D, 0x1F40, 0x1F43,
|
||||
0x1F45, 0x1F48, 0x1F4B, 0x1F4D, 0x1F50, 0x1F53, 0x1F55, 0x1F58,
|
||||
0x1F5A, 0x1F5D, 0x1F60, 0x1F62, 0x1F65, 0x1F68, 0x1F6A, 0x1F6D,
|
||||
0x1F6F, 0x1F72, 0x1F75, 0x1F77, 0x1F7A, 0x1F7C, 0x1F7F, 0x1F82,
|
||||
0x1F84, 0x1F87, 0x1F8A, 0x1F8C, 0x1F8F, 0x1F91, 0x1F94, 0x1F97,
|
||||
0x1F99, 0x1F9C, 0x1F9E, 0x1FA1, 0x1FA4, 0x1FA6, 0x1FA9, 0x1FAB,
|
||||
0x1FAE, 0x1FB0, 0x1FB3, 0x1FB6, 0x1FB8, 0x1FBB, 0x1FBD, 0x1FC0,
|
||||
0x1FC3, 0x1FC5, 0x1FC8, 0x1FCA, 0x1FCD, 0x1FCF, 0x1FD2, 0x1FD5,
|
||||
0x1FD7, 0x1FDA, 0x1FDC, 0x1FDF, 0x1FE1, 0x1FE4, 0x1FE6, 0x1FE9,
|
||||
0x1FEC, 0x1FEE, 0x1FF1, 0x1FF3, 0x1FF6, 0x1FF8, 0x1FFB, 0x1FFD,
|
||||
0x2000, 0x2000,
|
||||
};
|
||||
|
||||
const int32 atanOctant[] = {
|
||||
0, -16384, -65535, 49152, -32768, 16384, 32768, -49152
|
||||
};
|
||||
|
||||
|
||||
int32 phd_sin(int32 x)
|
||||
{
|
||||
x &= 0xFFFF;
|
||||
@@ -146,7 +544,7 @@ int32 phd_sin(int32 x)
|
||||
x = 0x8000 - x;
|
||||
}
|
||||
|
||||
x = sin_table[x >> 4];
|
||||
x = sinTable[x >> 4];
|
||||
|
||||
return neg ? -x : x;
|
||||
}
|
||||
@@ -156,17 +554,86 @@ int32 phd_cos(int32 x)
|
||||
return phd_sin(x + 0x4000);
|
||||
}
|
||||
|
||||
int32 clamp(int32 x, int32 a, int32 b) {
|
||||
return x < a ? a : (x > b ? b : x);
|
||||
int32 phd_atan(int32 x, int32 y)
|
||||
{
|
||||
if (x == 0 && y == 0)
|
||||
return 0;
|
||||
|
||||
int32 o = 0;
|
||||
|
||||
if (x < 0) {
|
||||
o += 4;
|
||||
x = -x;
|
||||
}
|
||||
|
||||
void initLUT() {
|
||||
if (y < 0) {
|
||||
o += 2;
|
||||
y = -y;
|
||||
}
|
||||
|
||||
if (y > x) {
|
||||
o++;
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
return abs(atanTable[(y << 11) / x] + atanOctant[o]);
|
||||
}
|
||||
|
||||
uint32 phd_sqrt(uint32 x)
|
||||
{
|
||||
uint32 m = 0x40000000;
|
||||
uint32 y = 0;
|
||||
uint32 z = 0;
|
||||
|
||||
do {
|
||||
y += m;
|
||||
|
||||
if (y > x) {
|
||||
y = z;
|
||||
} else {
|
||||
x -= y;
|
||||
y = m | z;
|
||||
}
|
||||
|
||||
z = y >> 1;
|
||||
} while (m >>= 2);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
void anglesFromVector(int32 x, int32 y, int32 z, int16 &angleX, int16 &angleY)
|
||||
{
|
||||
angleY = phd_atan(z, x);
|
||||
angleX = phd_atan(phd_sqrt(x * x + z * z), y);
|
||||
|
||||
if ((y > 0 && angleX > 0) || (y < 0 && angleX < 0))
|
||||
{
|
||||
angleX = -angleX;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void initDivTable()
|
||||
{
|
||||
uint16 divTable[DIV_TABLE_SIZE];
|
||||
|
||||
divTable[0] = 0xFFFF;
|
||||
divTable[1] = 0xFFFF;
|
||||
for (uint32 i = 2; i < DIV_TABLE_SIZE; i++) {
|
||||
divTable[i] = (1 << 16) / i;
|
||||
}
|
||||
|
||||
ASSERT((DIV_TABLE_SIZE & 8) == 0)
|
||||
|
||||
printf("const uint16 divTable[DIV_TABLE_SIZE] = {\n");
|
||||
for (int i = 0; i < DIV_TABLE_SIZE; i += 8) {
|
||||
printf(" 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X, 0x%04X,\n",
|
||||
divTable[i + 0], divTable[i + 1], divTable[i + 2], divTable[i + 3],
|
||||
divTable[i + 4], divTable[i + 5], divTable[i + 6], divTable[i + 7]);
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
*/
|
||||
|
||||
Matrix& matrixGet()
|
||||
{
|
||||
@@ -188,22 +655,17 @@ void matrixPop()
|
||||
matrixStackIndex--;
|
||||
}
|
||||
|
||||
void matrixTranslate(int32 x, int32 y, int32 z)
|
||||
void matrixTranslate(const vec3i &pos)
|
||||
{
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
vec3i offset(x, y, z);
|
||||
m[0][3] += DP33(m[0], offset);
|
||||
m[1][3] += DP33(m[1], offset);
|
||||
m[2][3] += DP33(m[2], offset);
|
||||
m[0][3] += DP33(m[0], pos);
|
||||
m[1][3] += DP33(m[1], pos);
|
||||
m[2][3] += DP33(m[2], pos);
|
||||
}
|
||||
|
||||
void matrixTranslateAbs(int32 x, int32 y, int32 z)
|
||||
void matrixTranslateAbs(const vec3i &pos)
|
||||
{
|
||||
vec3i d;
|
||||
d.x = x - viewPos.x;
|
||||
d.y = y - viewPos.y;
|
||||
d.z = z - viewPos.z;
|
||||
vec3i d = pos - viewPos;
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
m[0][3] = DP33(m[0], d);
|
||||
@@ -290,17 +752,41 @@ void matrixRotateYXZ(int32 angleX, int32 angleY, int32 angleZ)
|
||||
if (angleZ) matrixRotateZ(angleZ);
|
||||
}
|
||||
|
||||
void matrixFrame(int32 x, int32 y, int32 z, uint16* angles)
|
||||
#define LERP_FAST(a, b, mul, div) a = (a + b) >> 1
|
||||
#define LERP_SLOW(a, b, mul, div) a = a + (b - a) * mul / div
|
||||
|
||||
#define LERP_ROW(lerp_func, a, b, mul, div) \
|
||||
lerp_func(a[0], b[0], mul, div); \
|
||||
lerp_func(a[1], b[1], mul, div); \
|
||||
lerp_func(a[2], b[2], mul, div); \
|
||||
lerp_func(a[3], b[3], mul, div);
|
||||
|
||||
void matrixLerp(const Matrix &n, int32 multiplier, int32 divider)
|
||||
{
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
if (divider == 2) {
|
||||
LERP_ROW(LERP_FAST, m[0], n[0], multiplier, divider);
|
||||
LERP_ROW(LERP_FAST, m[1], n[1], multiplier, divider);
|
||||
LERP_ROW(LERP_FAST, m[2], n[2], multiplier, divider);
|
||||
} else {
|
||||
LERP_ROW(LERP_SLOW, m[0], n[0], multiplier, divider);
|
||||
LERP_ROW(LERP_SLOW, m[1], n[1], multiplier, divider);
|
||||
LERP_ROW(LERP_SLOW, m[2], n[2], multiplier, divider);
|
||||
}
|
||||
}
|
||||
|
||||
void matrixFrame(const vec3i &pos, uint16* angles)
|
||||
{
|
||||
int32 angleX = (angles[1] & 0x3FF0) << 2;
|
||||
int32 angleY = (angles[1] & 0x000F) << 12 | (angles[0] & 0xFC00) >> 4;
|
||||
int32 angleZ = (angles[0] & 0x03FF) << 6;
|
||||
|
||||
matrixTranslate(x, y, z);
|
||||
matrixTranslate(pos);
|
||||
matrixRotateYXZ(angleX, angleY, angleZ);
|
||||
}
|
||||
|
||||
void matrixSetView(int32 x, int32 y, int32 z, int32 angleX, int32 angleY)
|
||||
void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY)
|
||||
{
|
||||
int32 sx = phd_sin(angleX);
|
||||
int32 cx = phd_cos(angleX);
|
||||
@@ -309,22 +795,37 @@ void matrixSetView(int32 x, int32 y, int32 z, int32 angleX, int32 angleY)
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
m[0][0] = cy;
|
||||
m[0][1] = 0;
|
||||
m[0][2] = -sy;
|
||||
m[0][3] = x;
|
||||
#ifdef ROTATE90_MODE
|
||||
m[1][0] = -(cy);
|
||||
m[1][1] = -(0);
|
||||
m[1][2] = -(-sy);
|
||||
m[1][3] = pos.x;
|
||||
|
||||
m[1][0] = (sx * sy) >> FIXED_SHIFT;
|
||||
m[1][1] = cx;
|
||||
m[1][2] = (sx * cy) >> FIXED_SHIFT;
|
||||
m[1][3] = y;
|
||||
m[0][0] = (sx * sy) >> FIXED_SHIFT;
|
||||
m[0][1] = cx;
|
||||
m[0][2] = (sx * cy) >> FIXED_SHIFT;
|
||||
m[0][3] = pos.y;
|
||||
|
||||
m[2][0] = (cx * sy) >> FIXED_SHIFT;
|
||||
m[2][1] = -sx;
|
||||
m[2][2] = (cx * cy) >> FIXED_SHIFT;
|
||||
m[2][3] = z;
|
||||
m[2][3] = pos.z;
|
||||
#else
|
||||
m[0][0] = cy;
|
||||
m[0][1] = 0;
|
||||
m[0][2] = -sy;
|
||||
m[0][3] = pos.x;
|
||||
|
||||
viewPos.x = x;
|
||||
viewPos.y = y;
|
||||
viewPos.z = z;
|
||||
m[1][0] = (sx * sy) >> FIXED_SHIFT;
|
||||
m[1][1] = cx;
|
||||
m[1][2] = (sx * cy) >> FIXED_SHIFT;
|
||||
m[1][3] = pos.y;
|
||||
|
||||
m[2][0] = (cx * sy) >> FIXED_SHIFT;
|
||||
m[2][1] = -sx;
|
||||
m[2][2] = (cx * cy) >> FIXED_SHIFT;
|
||||
m[2][3] = pos.z;
|
||||
#endif
|
||||
|
||||
viewPos = pos;
|
||||
}
|
@@ -3,20 +3,13 @@
|
||||
|
||||
//#define TEST
|
||||
//#define PROFILE
|
||||
#define ROTATE90_MODE
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <windows.h>
|
||||
#elif defined(__GBA__)
|
||||
#include <gba_console.h>
|
||||
#include <gba_video.h>
|
||||
#include <gba_timers.h>
|
||||
#include <gba_interrupt.h>
|
||||
#include <gba_systemcalls.h>
|
||||
#include <gba_input.h>
|
||||
#include <gba_dma.h>
|
||||
#include <gba_affine.h>
|
||||
#include <fade.h>
|
||||
#include <tonc.h>
|
||||
#elif defined(__TNS__)
|
||||
#include <os.h>
|
||||
#endif
|
||||
@@ -30,25 +23,24 @@
|
||||
//#define DEBUG_FACES
|
||||
|
||||
#if defined(__TNS__)
|
||||
#define WIDTH SCREEN_WIDTH
|
||||
#define HEIGHT SCREEN_HEIGHT
|
||||
#define FRAME_WIDTH WIDTH
|
||||
#define FRAME_HEIGHT HEIGHT
|
||||
#define FOV_SHIFT 8
|
||||
#define FRAME_WIDTH SCREEN_WIDTH
|
||||
#define FRAME_HEIGHT SCREEN_HEIGHT
|
||||
#else
|
||||
#ifdef ROTATE90_MODE
|
||||
#define FRAME_WIDTH 160
|
||||
#define FRAME_HEIGHT 120
|
||||
#else
|
||||
#define WIDTH 160
|
||||
#define HEIGHT 128
|
||||
#define FRAME_WIDTH 160
|
||||
#define FRAME_HEIGHT 128
|
||||
#define FOV_SHIFT 7
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define INLINE inline
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#define X_INLINE inline
|
||||
#define X_NOINLINE __declspec(noinline)
|
||||
#elif defined(__GBA__) || defined(__TNS__)
|
||||
#define INLINE __attribute__((always_inline)) inline
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#define X_INLINE __attribute__((always_inline)) inline
|
||||
#define X_NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
typedef signed char int8;
|
||||
@@ -60,12 +52,6 @@ typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int16 Index;
|
||||
|
||||
#define PI 3.14159265358979323846f
|
||||
#define PIH (PI * 0.5f)
|
||||
#define PI2 (PI * 2.0f)
|
||||
#define DEG2RAD (PI / 180.0f)
|
||||
#define RAD2DEG (180.0f / PI)
|
||||
|
||||
#ifdef __GBA__
|
||||
#define ARM_CODE __attribute__((target("arm")))
|
||||
#define THUMB_CODE __attribute__((target("thumb")))
|
||||
@@ -88,10 +74,10 @@ typedef int16 Index;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define ALIGN4 __declspec(align(4))
|
||||
#elif defined(__GBA__)
|
||||
#define ALIGN4 __attribute__((aligned(4)))
|
||||
#elif defined(__TNS__)
|
||||
#define ALIGN16 __declspec(align(16))
|
||||
#elif defined(__GBA__) || defined(__TNS__)
|
||||
#define ALIGN4 __attribute__((aligned(4)))
|
||||
#define ALIGN16 __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -100,6 +86,14 @@ typedef int16 Index;
|
||||
#define ASSERT(x)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern uint16 fb[FRAME_WIDTH * FRAME_HEIGHT];
|
||||
#elif defined(__GBA__)
|
||||
extern uint32 fb;
|
||||
#elif defined(__TNS__)
|
||||
extern uint16 fb[FRAME_WIDTH * FRAME_HEIGHT];
|
||||
#endif
|
||||
|
||||
#ifdef PROFILE
|
||||
#if defined(_WIN32)
|
||||
|
||||
@@ -124,13 +118,13 @@ typedef int16 Index;
|
||||
#endif
|
||||
|
||||
#define PROFILE_START() {\
|
||||
REG_TM0CNT_L = 0;\
|
||||
REG_TM0CNT_H = (1 << 7) | TIMER_FREQ_DIV;\
|
||||
REG_TM2CNT_L = 0;\
|
||||
REG_TM2CNT_H = (1 << 7) | TIMER_FREQ_DIV;\
|
||||
}
|
||||
|
||||
#define PROFILE_STOP(value) {\
|
||||
value += REG_TM0CNT_L;\
|
||||
REG_TM0CNT_H = 0;\
|
||||
value += REG_TM2CNT_L;\
|
||||
REG_TM2CNT_H = 0;\
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -147,34 +141,42 @@ typedef int16 Index;
|
||||
#endif
|
||||
|
||||
enum InputKey {
|
||||
IK_UP,
|
||||
IK_RIGHT,
|
||||
IK_DOWN,
|
||||
IK_LEFT,
|
||||
IK_A,
|
||||
IK_B,
|
||||
IK_L,
|
||||
IK_R,
|
||||
IK_MAX
|
||||
IK_NONE = 0,
|
||||
IK_UP = (1 << 0),
|
||||
IK_RIGHT = (1 << 1),
|
||||
IK_DOWN = (1 << 2),
|
||||
IK_LEFT = (1 << 3),
|
||||
IK_A = (1 << 4),
|
||||
IK_B = (1 << 5),
|
||||
IK_L = (1 << 6),
|
||||
IK_R = (1 << 7),
|
||||
IK_START = (1 << 8),
|
||||
IK_SELECT = (1 << 9),
|
||||
};
|
||||
|
||||
extern bool keys[IK_MAX];
|
||||
struct vec3s {
|
||||
int16 x, y, z;
|
||||
|
||||
vec3s() = default;
|
||||
X_INLINE vec3s(int16 x, int16 y, int16 z) : x(x), y(y), z(z) {}
|
||||
};
|
||||
|
||||
struct vec3i {
|
||||
int32 x, y, z;
|
||||
|
||||
vec3i() = default;
|
||||
INLINE vec3i(int32 x, int32 y, int32 z) : x(x), y(y), z(z) {}
|
||||
};
|
||||
|
||||
struct vec3s {
|
||||
int16 x, y, z;
|
||||
X_INLINE vec3i(int32 x, int32 y, int32 z) : x(x), y(y), z(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) { 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; }
|
||||
};
|
||||
|
||||
struct vec4i {
|
||||
int32 x, y, z, w;
|
||||
|
||||
INLINE int32& operator [] (int32 index) const {
|
||||
X_INLINE int32& operator [] (int32 index) const {
|
||||
ASSERT(index >= 0 && index <= 3);
|
||||
return ((int32*)this)[index];
|
||||
}
|
||||
@@ -192,6 +194,37 @@ struct Triangle {
|
||||
uint16 flags;
|
||||
};
|
||||
|
||||
struct Rect {
|
||||
int32 x0;
|
||||
int32 y0;
|
||||
int32 x1;
|
||||
int32 y1;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
int16 x, y, z;
|
||||
uint8 g, clip;
|
||||
};
|
||||
|
||||
union UV {
|
||||
struct { uint16 v, u; };
|
||||
uint32 uv;
|
||||
};
|
||||
|
||||
struct VertexUV {
|
||||
Vertex v;
|
||||
UV t;
|
||||
VertexUV *prev;
|
||||
VertexUV *next;
|
||||
};
|
||||
|
||||
struct Face {
|
||||
Face* next;
|
||||
uint16 flags;
|
||||
int16 start;
|
||||
int8 indices[4];
|
||||
};
|
||||
|
||||
struct Box {
|
||||
int16 minX;
|
||||
int16 maxX;
|
||||
@@ -227,11 +260,10 @@ struct RoomInfo {
|
||||
int8 ceiling;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
// int32 x, y, z;
|
||||
// uint16 intensity;
|
||||
// uint32 radius;
|
||||
uint8 dummy[18];
|
||||
struct Light { // TODO align struct
|
||||
uint8 pos[12];
|
||||
int16 intensity;
|
||||
uint8 radius[4];
|
||||
};
|
||||
|
||||
struct Mesh {
|
||||
@@ -262,6 +294,32 @@ struct RoomInfo {
|
||||
*/
|
||||
};
|
||||
|
||||
struct Room {
|
||||
Rect clip;
|
||||
uint8 firstItem;
|
||||
bool visible;
|
||||
|
||||
// TODO leave in ROM
|
||||
int32 x, z;
|
||||
uint16 vCount;
|
||||
uint16 qCount;
|
||||
uint16 tCount;
|
||||
uint16 pCount;
|
||||
uint16 lCount;
|
||||
uint16 mCount;
|
||||
uint16 zSectors;
|
||||
uint16 xSectors;
|
||||
uint16 ambient;
|
||||
|
||||
const RoomInfo::Vertex* vertices;
|
||||
const Quad* quads;
|
||||
const Triangle* triangles;
|
||||
const RoomInfo::Portal* portals;
|
||||
const RoomInfo::Sector* sectors;
|
||||
const RoomInfo::Light* lights;
|
||||
const RoomInfo::Mesh* meshes;
|
||||
};
|
||||
|
||||
struct Node {
|
||||
uint32 flags;
|
||||
vec3i pos;
|
||||
@@ -296,7 +354,7 @@ struct ItemInfo { // 24
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint16 gravity:1; // TODO
|
||||
uint16 gravity:1, shadow:1; // TODO
|
||||
};
|
||||
uint16 value;
|
||||
} flags;
|
||||
@@ -306,12 +364,12 @@ struct ItemInfo { // 24
|
||||
|
||||
#define FILE_ITEM_SIZE (sizeof(ItemInfo) - 2)
|
||||
|
||||
struct Item : ItemInfo { // 24 + 20 = 44
|
||||
struct Item : ItemInfo { // 24 + 28 = 52
|
||||
int16 angleX;
|
||||
int16 angleZ;
|
||||
|
||||
uint16 vSpeed;
|
||||
uint16 hSpeed;
|
||||
int16 vSpeed;
|
||||
int16 hSpeed;
|
||||
|
||||
uint16 animIndex;
|
||||
uint16 frameIndex;
|
||||
@@ -319,11 +377,28 @@ struct Item : ItemInfo { // 24 + 20 = 44
|
||||
uint8 state;
|
||||
uint8 nextState;
|
||||
uint8 goalState;
|
||||
uint8 timer;
|
||||
uint8 waterState;
|
||||
|
||||
uint16 health;
|
||||
uint16 timer;
|
||||
|
||||
int16 moveAngle;
|
||||
uint8 nextItem;
|
||||
uint8 nextActive;
|
||||
|
||||
int16 turnSpeed;
|
||||
int16 vSpeedHack;
|
||||
};
|
||||
|
||||
struct SoundInfo
|
||||
{
|
||||
uint16 index;
|
||||
uint16 volume;
|
||||
uint16 chance;
|
||||
union {
|
||||
struct { uint16 mode:2, count:4, unused:6, camera:1, pitch:1, gain:1, :1; };
|
||||
uint16 value;
|
||||
} flags;
|
||||
};
|
||||
|
||||
struct Anim {
|
||||
@@ -343,14 +418,27 @@ struct Anim {
|
||||
uint16 nextAnimIndex;
|
||||
uint16 nextFrameIndex;
|
||||
|
||||
uint16 scCount;
|
||||
uint16 scOffset;
|
||||
uint16 statesCount;
|
||||
uint16 statesStart;
|
||||
|
||||
uint16 acCount;
|
||||
uint16 animCommand;
|
||||
uint16 commandsCount;
|
||||
uint16 commandsStart;
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
struct AnimState {
|
||||
uint16 state;
|
||||
uint16 rangesCount;
|
||||
uint16 rangesStart;
|
||||
};
|
||||
|
||||
struct AnimRange {
|
||||
uint16 frameBegin;
|
||||
uint16 frameEnd;
|
||||
uint16 nextAnimIndex;
|
||||
uint16 nextFrameIndex;
|
||||
};
|
||||
|
||||
struct AnimFrame {
|
||||
Box box;
|
||||
vec3s pos;
|
||||
uint16 angles[1];
|
||||
@@ -379,52 +467,367 @@ struct SpriteSeq {
|
||||
int16 sStart;
|
||||
};
|
||||
|
||||
struct Rect {
|
||||
int32 x0;
|
||||
int32 y0;
|
||||
int32 x1;
|
||||
int32 y1;
|
||||
union FloorData { // 2 bytes
|
||||
uint16 value;
|
||||
|
||||
union Command {
|
||||
struct {
|
||||
uint16 func:5, tri:3, sub:7, end:1;
|
||||
};
|
||||
struct {
|
||||
int16 :5, a:5, b:5, :1;
|
||||
} triangle;
|
||||
} cmd;
|
||||
|
||||
struct {
|
||||
int8 slantX;
|
||||
int8 slantZ;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
int16 x, y, z;
|
||||
uint8 g, clip;
|
||||
struct {
|
||||
uint16 a:4, b:4, c:4, d:4;
|
||||
};
|
||||
|
||||
union UV {
|
||||
struct { uint16 v, u; };
|
||||
uint32 uv;
|
||||
struct TriggerInfo {
|
||||
uint16 timer:8, once:1, mask:5, :2;
|
||||
} triggerInfo;
|
||||
|
||||
union TriggerCommand {
|
||||
struct {
|
||||
uint16 args:10, action:5, end:1;
|
||||
};
|
||||
struct {
|
||||
uint16 timer:8, once:1, speed:5, :2;
|
||||
};
|
||||
} triggerCmd;
|
||||
};
|
||||
|
||||
struct VertexUV {
|
||||
Vertex v;
|
||||
UV t;
|
||||
enum FloorType {
|
||||
FLOOR_TYPE_NONE,
|
||||
FLOOR_TYPE_PORTAL,
|
||||
FLOOR_TYPE_FLOOR,
|
||||
FLOOR_TYPE_CEILING,
|
||||
FLOOR_TYPE_TRIGGER,
|
||||
FLOOR_TYPE_LAVA
|
||||
};
|
||||
|
||||
struct Face {
|
||||
uint16 flags;
|
||||
int16 depth;
|
||||
int16 start;
|
||||
int8 indices[4];
|
||||
enum TriggerAction {
|
||||
TRIGGER_ACTION_ACTIVATE,
|
||||
TRIGGER_ACTION_CAMERA_SWITCH,
|
||||
TRIGGER_ACTION_FLOW,
|
||||
TRIGGER_ACTION_FLIP,
|
||||
TRIGGER_ACTION_FLIP_ON,
|
||||
TRIGGER_ACTION_FLIP_OFF,
|
||||
TRIGGER_ACTION_CAMERA_TARGET,
|
||||
TRIGGER_ACTION_END,
|
||||
TRIGGER_ACTION_SOUNDTRACK,
|
||||
TRIGGER_ACTION_EFFECT,
|
||||
TRIGGER_ACTION_SECRET,
|
||||
TRIGGER_ACTION_CLEAR_BODIES,
|
||||
TRIGGER_ACTION_FLYBY,
|
||||
TRIGGER_ACTION_CUTSCENE
|
||||
};
|
||||
|
||||
enum SlantType {
|
||||
SLANT_NONE,
|
||||
SLANT_LOW,
|
||||
SLANT_HIGH
|
||||
};
|
||||
|
||||
enum WaterState {
|
||||
WATER_STATE_ABOVE,
|
||||
WATER_STATE_SURFACE,
|
||||
WATER_STATE_UNDER,
|
||||
WATER_STATE_WADE,
|
||||
};
|
||||
|
||||
enum AnimCommand {
|
||||
ANIM_CMD_NONE,
|
||||
ANIM_CMD_OFFSET,
|
||||
ANIM_CMD_JUMP,
|
||||
ANIM_CMD_EMPTY,
|
||||
ANIM_CMD_KILL,
|
||||
ANIM_CMD_SOUND,
|
||||
ANIM_CMD_EFFECT,
|
||||
};
|
||||
|
||||
enum EffectType {
|
||||
FX_NONE = -1,
|
||||
FX_ROTATE_180 ,
|
||||
FX_FLOOR_SHAKE ,
|
||||
FX_LARA_NORMAL ,
|
||||
FX_LARA_BUBBLES ,
|
||||
FX_FINISH_LEVEL ,
|
||||
FX_EARTHQUAKE ,
|
||||
FX_FLOOD ,
|
||||
FX_UNK1 ,
|
||||
FX_STAIRS2SLOPE ,
|
||||
FX_UNK3 ,
|
||||
FX_UNK4 ,
|
||||
FX_EXPLOSION ,
|
||||
FX_LARA_HANDSFREE ,
|
||||
FX_FLIP_MAP ,
|
||||
FX_DRAW_RIGHTGUN ,
|
||||
FX_DRAW_LEFTGUN ,
|
||||
FX_SHOT_RIGHTGUN ,
|
||||
FX_SHOT_LEFTGUN ,
|
||||
FX_MESH_SWAP_1 ,
|
||||
FX_MESH_SWAP_2 ,
|
||||
FX_MESH_SWAP_3 ,
|
||||
FX_INV_ON ,
|
||||
FX_INV_OFF ,
|
||||
FX_DYN_ON ,
|
||||
FX_DYN_OFF ,
|
||||
FX_STATUE_FX ,
|
||||
FX_RESET_HAIR ,
|
||||
FX_BOILER_FX ,
|
||||
FX_ASSAULT_RESET ,
|
||||
FX_ASSAULT_STOP ,
|
||||
FX_ASSAULT_START ,
|
||||
FX_ASSAULT_FINISH ,
|
||||
FX_FOOTPRINT ,
|
||||
// specific
|
||||
FX_TR1_FLICKER = 16,
|
||||
};
|
||||
|
||||
#define ITEM_TYPES(E) \
|
||||
E( LARA ) \
|
||||
E( LARA_PISTOLS ) \
|
||||
E( LARA_SHOTGUN ) \
|
||||
E( LARA_MAGNUMS ) \
|
||||
E( LARA_UZIS ) \
|
||||
E( LARA_SPEC ) \
|
||||
E( DOPPELGANGER ) \
|
||||
E( WOLF ) \
|
||||
E( BEAR ) \
|
||||
E( BAT ) \
|
||||
E( CROCODILE_LAND ) \
|
||||
E( CROCODILE_WATER ) \
|
||||
E( LION_MALE ) \
|
||||
E( LION_FEMALE ) \
|
||||
E( PUMA ) \
|
||||
E( GORILLA ) \
|
||||
E( RAT_LAND ) \
|
||||
E( RAT_WATER ) \
|
||||
E( REX ) \
|
||||
E( RAPTOR ) \
|
||||
E( MUTANT_1 ) \
|
||||
E( MUTANT_2 ) \
|
||||
E( MUTANT_3 ) \
|
||||
E( CENTAUR ) \
|
||||
E( MUMMY ) \
|
||||
E( UNUSED_1 ) \
|
||||
E( UNUSED_2 ) \
|
||||
E( LARSON ) \
|
||||
E( PIERRE ) \
|
||||
E( SKATEBOARD ) \
|
||||
E( SKATEBOY ) \
|
||||
E( COWBOY ) \
|
||||
E( MR_T ) \
|
||||
E( NATLA ) \
|
||||
E( GIANT_MUTANT ) \
|
||||
E( TRAP_FLOOR ) \
|
||||
E( TRAP_SWING_BLADE ) \
|
||||
E( TRAP_SPIKES ) \
|
||||
E( TRAP_BOULDER ) \
|
||||
E( DART ) \
|
||||
E( TRAP_DART_EMITTER ) \
|
||||
E( DRAWBRIDGE ) \
|
||||
E( TRAP_SLAM ) \
|
||||
E( TRAP_SWORD ) \
|
||||
E( HAMMER_HANDLE ) \
|
||||
E( HAMMER_BLOCK ) \
|
||||
E( LIGHTNING ) \
|
||||
E( MOVING_OBJECT ) \
|
||||
E( BLOCK_1 ) \
|
||||
E( BLOCK_2 ) \
|
||||
E( BLOCK_3 ) \
|
||||
E( BLOCK_4 ) \
|
||||
E( MOVING_BLOCK ) \
|
||||
E( TRAP_CEILING_1 ) \
|
||||
E( TRAP_CEILING_2 ) \
|
||||
E( SWITCH ) \
|
||||
E( SWITCH_WATER ) \
|
||||
E( DOOR_1 ) \
|
||||
E( DOOR_2 ) \
|
||||
E( DOOR_3 ) \
|
||||
E( DOOR_4 ) \
|
||||
E( DOOR_5 ) \
|
||||
E( DOOR_6 ) \
|
||||
E( DOOR_7 ) \
|
||||
E( DOOR_8 ) \
|
||||
E( TRAP_DOOR_1 ) \
|
||||
E( TRAP_DOOR_2 ) \
|
||||
E( UNUSED_3 ) \
|
||||
E( BRIDGE_1 ) \
|
||||
E( BRIDGE_2 ) \
|
||||
E( BRIDGE_3 ) \
|
||||
E( INV_PASSPORT ) \
|
||||
E( INV_COMPASS ) \
|
||||
E( INV_HOME ) \
|
||||
E( GEARS_1 ) \
|
||||
E( GEARS_2 ) \
|
||||
E( GEARS_3 ) \
|
||||
E( CUT_1 ) \
|
||||
E( CUT_2 ) \
|
||||
E( CUT_3 ) \
|
||||
E( CUT_4 ) \
|
||||
E( INV_PASSPORT_CLOSED ) \
|
||||
E( INV_MAP ) \
|
||||
E( CRYSTAL ) \
|
||||
E( PISTOLS ) \
|
||||
E( SHOTGUN ) \
|
||||
E( MAGNUMS ) \
|
||||
E( UZIS ) \
|
||||
E( AMMO_PISTOLS ) \
|
||||
E( AMMO_SHOTGUN ) \
|
||||
E( AMMO_MAGNUMS ) \
|
||||
E( AMMO_UZIS ) \
|
||||
E( EXPLOSIVE ) \
|
||||
E( MEDIKIT_SMALL ) \
|
||||
E( MEDIKIT_BIG ) \
|
||||
E( INV_DETAIL ) \
|
||||
E( INV_SOUND ) \
|
||||
E( INV_CONTROLS ) \
|
||||
E( INV_GAMMA ) \
|
||||
E( INV_PISTOLS ) \
|
||||
E( INV_SHOTGUN ) \
|
||||
E( INV_MAGNUMS ) \
|
||||
E( INV_UZIS ) \
|
||||
E( INV_AMMO_PISTOLS ) \
|
||||
E( INV_AMMO_SHOTGUN ) \
|
||||
E( INV_AMMO_MAGNUMS ) \
|
||||
E( INV_AMMO_UZIS ) \
|
||||
E( INV_EXPLOSIVE ) \
|
||||
E( INV_MEDIKIT_SMALL ) \
|
||||
E( INV_MEDIKIT_BIG ) \
|
||||
E( PUZZLE_1 ) \
|
||||
E( PUZZLE_2 ) \
|
||||
E( PUZZLE_3 ) \
|
||||
E( PUZZLE_4 ) \
|
||||
E( INV_PUZZLE_1 ) \
|
||||
E( INV_PUZZLE_2 ) \
|
||||
E( INV_PUZZLE_3 ) \
|
||||
E( INV_PUZZLE_4 ) \
|
||||
E( PUZZLE_HOLE_1 ) \
|
||||
E( PUZZLE_HOLE_2 ) \
|
||||
E( PUZZLE_HOLE_3 ) \
|
||||
E( PUZZLE_HOLE_4 ) \
|
||||
E( PUZZLE_DONE_1 ) \
|
||||
E( PUZZLE_DONE_2 ) \
|
||||
E( PUZZLE_DONE_3 ) \
|
||||
E( PUZZLE_DONE_4 ) \
|
||||
E( LEADBAR ) \
|
||||
E( INV_LEADBAR ) \
|
||||
E( MIDAS_HAND ) \
|
||||
E( KEY_ITEM_1 ) \
|
||||
E( KEY_ITEM_2 ) \
|
||||
E( KEY_ITEM_3 ) \
|
||||
E( KEY_ITEM_4 ) \
|
||||
E( INV_KEY_ITEM_1 ) \
|
||||
E( INV_KEY_ITEM_2 ) \
|
||||
E( INV_KEY_ITEM_3 ) \
|
||||
E( INV_KEY_ITEM_4 ) \
|
||||
E( KEY_HOLE_1 ) \
|
||||
E( KEY_HOLE_2 ) \
|
||||
E( KEY_HOLE_3 ) \
|
||||
E( KEY_HOLE_4 ) \
|
||||
E( UNUSED_4 ) \
|
||||
E( UNUSED_5 ) \
|
||||
E( SCION_PICKUP_QUALOPEC ) \
|
||||
E( SCION_PICKUP_DROP ) \
|
||||
E( SCION_TARGET ) \
|
||||
E( SCION_PICKUP_HOLDER ) \
|
||||
E( SCION_HOLDER ) \
|
||||
E( UNUSED_6 ) \
|
||||
E( UNUSED_7 ) \
|
||||
E( INV_SCION ) \
|
||||
E( EXPLOSION ) \
|
||||
E( UNUSED_8 ) \
|
||||
E( WATER_SPLASH ) \
|
||||
E( UNUSED_9 ) \
|
||||
E( BUBBLE ) \
|
||||
E( UNUSED_10 ) \
|
||||
E( UNUSED_11 ) \
|
||||
E( BLOOD ) \
|
||||
E( UNUSED_12 ) \
|
||||
E( SMOKE ) \
|
||||
E( CENTAUR_STATUE ) \
|
||||
E( CABIN ) \
|
||||
E( MUTANT_EGG_SMALL ) \
|
||||
E( RICOCHET ) \
|
||||
E( SPARKLES ) \
|
||||
E( MUZZLE_FLASH ) \
|
||||
E( UNUSED_13 ) \
|
||||
E( UNUSED_14 ) \
|
||||
E( VIEW_TARGET ) \
|
||||
E( WATERFALL ) \
|
||||
E( NATLA_BULLET ) \
|
||||
E( MUTANT_BULLET ) \
|
||||
E( CENTAUR_BULLET ) \
|
||||
E( UNUSED_16 ) \
|
||||
E( UNUSED_17 ) \
|
||||
E( LAVA_PARTICLE ) \
|
||||
E( TRAP_LAVA_EMITTER ) \
|
||||
E( FLAME ) \
|
||||
E( TRAP_FLAME_EMITTER ) \
|
||||
E( TRAP_LAVA ) \
|
||||
E( MUTANT_EGG_BIG ) \
|
||||
E( BOAT ) \
|
||||
E( EARTHQUAKE ) \
|
||||
E( UNUSED_18 ) \
|
||||
E( UNUSED_19 ) \
|
||||
E( UNUSED_20 ) \
|
||||
E( UNUSED_21 ) \
|
||||
E( UNUSED_22 ) \
|
||||
E( LARA_BRAID ) \
|
||||
E( GLYPHS )
|
||||
|
||||
#define DECL_ENUM(v) ITEM_##v,
|
||||
|
||||
enum ItemTypes {
|
||||
ITEM_TYPES(DECL_ENUM)
|
||||
ITEM_MAX
|
||||
};
|
||||
|
||||
#undef DECL_ENUM
|
||||
|
||||
extern int32 fps;
|
||||
|
||||
#ifdef PROFILE
|
||||
extern uint32 dbg_transform;
|
||||
extern uint32 dbg_poly;
|
||||
extern uint32 dbg_sort;
|
||||
extern uint32 dbg_flush;
|
||||
extern uint32 dbg_vert_count;
|
||||
extern uint32 dbg_poly_count;
|
||||
#endif
|
||||
|
||||
#define DIV_TABLE_SIZE 256
|
||||
#define FixedInvS(x) ((x < 0) ? -divTable[abs(x)] : divTable[x])
|
||||
#define FixedInvU(x) divTable[x]
|
||||
|
||||
extern uint16 divTable[DIV_TABLE_SIZE];
|
||||
|
||||
#define FIXED_SHIFT 14
|
||||
|
||||
#define SND_MAX_DIST (8 * 1024)
|
||||
#define SND_SHIFT 2
|
||||
#define SND_CHANNELS (1 << SND_SHIFT)
|
||||
#define SND_FIXED_SHIFT 8
|
||||
#define SND_VOL_SHIFT 15
|
||||
#define SND_PITCH_SHIFT 7
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define SND_SAMPLES 1024
|
||||
#define SND_OUTPUT_FREQ 22050
|
||||
#define SND_SAMPLE_FREQ 22050
|
||||
#define SND_ENCODE(x) ((x) + 128)
|
||||
#define SND_DECODE(x) ((x) - 128)
|
||||
#elif defined(__GBA__)
|
||||
#define SND_SAMPLES 176
|
||||
#define SND_OUTPUT_FREQ 10512
|
||||
#define SND_SAMPLE_FREQ 22050
|
||||
#define SND_ENCODE(x) (x)
|
||||
#define SND_DECODE(x) ((x) - 128)
|
||||
#endif
|
||||
|
||||
#define MAX_UPDATE_FRAMES 10
|
||||
|
||||
#define FOV_SHIFT 3
|
||||
#define MAX_MATRICES 8
|
||||
#define MAX_MODELS 64
|
||||
#define MAX_ITEMS 256
|
||||
@@ -441,53 +844,134 @@ extern uint16 divTable[DIV_TABLE_SIZE];
|
||||
#define FACE_COLORED 0x4000
|
||||
#define FACE_CLIPPED 0x2000
|
||||
#define FACE_FLAT 0x1000
|
||||
#define FACE_TEXTURE 0x0FFF
|
||||
#define FACE_SHADOW 0x0800
|
||||
#define FACE_TEXTURE 0x07FF
|
||||
|
||||
#define NO_ROOM 0xFF
|
||||
#define NO_ITEM 0xFF
|
||||
#define NO_MODEL 0xFF
|
||||
#define WALL (-127 * 256)
|
||||
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define SQR(x) ((x) * (x))
|
||||
#define DEG2SHORT (0x10000 / 360)
|
||||
#define ANGLE_0 0
|
||||
#define ANGLE_1 DEG2SHORT
|
||||
#define ANGLE_45 0x2000 // != 45 * DEG2SHORT !!!
|
||||
#define ANGLE_90 0x4000
|
||||
#define ANGLE_180 0x8000
|
||||
|
||||
#define X_CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
|
||||
#define X_MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define X_MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define X_SQR(x) ((x) * (x))
|
||||
|
||||
#define DP43(a,b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z + (a).w)
|
||||
#define DP33(a,b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z)
|
||||
|
||||
#define ITEM_LARA 0
|
||||
#define ITEM_WOLF 7
|
||||
#define ITEM_BEAR 8
|
||||
#define ITEM_BAT 9
|
||||
#define ITEM_CRYSTAL 83
|
||||
#define DIV_TABLE_SIZE 1024
|
||||
#define FixedInvS(x) ((x < 0) ? -divTable[abs(x)] : divTable[x])
|
||||
#define FixedInvU(x) divTable[x]
|
||||
|
||||
#define OT_SHIFT 4
|
||||
#define OT_SIZE ((VIEW_MAX_F >> (FIXED_SHIFT + OT_SHIFT)) + 1)
|
||||
|
||||
/*
|
||||
#define PERSPECTIVE(x, y, z) {\
|
||||
x = (x / (z >> 7));\
|
||||
y = (y / (z >> 6));\
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
#define PERSPECTIVE(x, y, z) {\
|
||||
int32 dz = (z >> (FIXED_SHIFT + FOV_SHIFT - 1)) / 3;\
|
||||
if (dz >= DIV_TABLE_SIZE) dz = DIV_TABLE_SIZE - 1;\
|
||||
int32 d = FixedInvU(dz);\
|
||||
x = d * (x >> FIXED_SHIFT) >> 12;\
|
||||
y = d * (y >> FIXED_SHIFT) >> 13;\
|
||||
}
|
||||
#else
|
||||
#define PERSPECTIVE(x, y, z) {\
|
||||
int32 dz = z >> (FIXED_SHIFT + FOV_SHIFT);\
|
||||
if (dz >= DIV_TABLE_SIZE) dz = DIV_TABLE_SIZE - 1;\
|
||||
int32 d = FixedInvU(dz);\
|
||||
x = d * (x >> FIXED_SHIFT) >> 12;\
|
||||
y = d * (y >> FIXED_SHIFT) >> 12;\
|
||||
}
|
||||
#endif
|
||||
|
||||
extern const uint16 divTable[DIV_TABLE_SIZE];
|
||||
|
||||
// renderer internal
|
||||
extern Rect clip;
|
||||
extern vec3i viewPos;
|
||||
extern Matrix matrixStack[MAX_MATRICES];
|
||||
extern int32 matrixStackIndex;
|
||||
extern uint32 gVerticesCount;
|
||||
extern uint32 keys;
|
||||
|
||||
// level data
|
||||
extern const Anim* anims;
|
||||
extern const AnimState* animStates;
|
||||
extern const AnimRange* animRanges;
|
||||
extern const uint16* animFrames;
|
||||
|
||||
extern int32 modelsCount;
|
||||
extern Model models[MAX_MODELS];
|
||||
extern uint8 modelsMap[MAX_ITEMS];
|
||||
extern uint8 staticMeshesMap[MAX_MESHES];
|
||||
|
||||
template <class T>
|
||||
X_INLINE void swap(T &a, T &b) {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
X_INLINE int32 classify(const Vertex* v, const Rect &clip) {
|
||||
return (v->x < clip.x0 ? 1 : 0) |
|
||||
(v->x > clip.x1 ? 2 : 0) |
|
||||
(v->y < clip.y0 ? 4 : 0) |
|
||||
(v->y > clip.y1 ? 8 : 0);
|
||||
}
|
||||
|
||||
int32 clamp(int32 x, int32 a, int32 b);
|
||||
int32 phd_sin(int32 x);
|
||||
int32 phd_cos(int32 x);
|
||||
int32 phd_atan(int32 x, int32 y);
|
||||
uint32 phd_sqrt(uint32 x);
|
||||
|
||||
void initLUT();
|
||||
X_INLINE int32 dot(const vec3i &a, const vec3i &b)
|
||||
{
|
||||
return X_SQR(a.x) + X_SQR(a.y) + X_SQR(a.z);
|
||||
}
|
||||
|
||||
void anglesFromVector(int32 x, int32 y, int32 z, int16 &angleX, int16 &angleY);
|
||||
|
||||
AnimFrame* getFrame(const Item* item, const Model* model);
|
||||
const Box& getBoundingBox(const Item* item);
|
||||
|
||||
Matrix& matrixGet();
|
||||
void matrixPush();
|
||||
void matrixPop();
|
||||
void matrixTranslate(int32 x, int32 y, int32 z);
|
||||
void matrixTranslateAbs(int32 x, int32 y, int32 z);
|
||||
void matrixTranslate(const vec3i &pos);
|
||||
void matrixTranslateAbs(const vec3i &pos);
|
||||
void matrixRotateX(int32 angle);
|
||||
void matrixRotateY(int32 angle);
|
||||
void matrixRotateZ(int32 angle);
|
||||
void matrixRotateYXZ(int32 angleX, int32 angleY, int32 angleZ);
|
||||
void matrixFrame(int32 x, int32 y, int32 z, uint16* angles);
|
||||
void matrixSetView(int32 x, int32 y, int32 z, int32 angleX, int32 angleY);
|
||||
void matrixFrame(const vec3i &pos, uint16* angles);
|
||||
void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY);
|
||||
|
||||
void drawGlyph(const Sprite *sprite, int32 x, int32 y);
|
||||
|
||||
void clear();
|
||||
bool rectIsVisible(const Rect* rect);
|
||||
bool boxIsVisible(const Box* box);
|
||||
void transform(const vec3s &v, int32 vg);
|
||||
bool transformBoxRect(const Box* box, Rect* rect);
|
||||
void transformRoom(const RoomInfo::Vertex* vertices, int32 vCount);
|
||||
void transformMesh(const vec3s* vertices, int32 vCount, uint16 intensity);
|
||||
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
|
||||
void faceAddTriangle(uint32 flags, const Index* indices, 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);
|
||||
|
||||
@@ -495,6 +979,26 @@ void flush();
|
||||
|
||||
void readLevel(const uint8 *data);
|
||||
const RoomInfo::Sector* getSector(int32 roomIndex, int32 x, int32 z);
|
||||
int32 getRoomIndex(int32 roomIndex, const vec3i* pos);
|
||||
int32 getRoomIndex(int32 roomIndex, int32 x, int32 y, int32 z);
|
||||
|
||||
X_INLINE void dmaFill(void *dst, uint8 value, uint32 count)
|
||||
{
|
||||
ASSERT((count & 3) == 0);
|
||||
#ifdef __GBA__
|
||||
vu32 v = value;
|
||||
dma3_fill(dst, v, count);
|
||||
#else
|
||||
memset(dst, value, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
X_INLINE int16 xRand()
|
||||
{
|
||||
#ifdef __GBA__
|
||||
return qran();
|
||||
#else
|
||||
return rand();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,2 +1,2 @@
|
||||
make
|
||||
./NO\$GBA.exe C:\\Projects\\OpenLara\\src\\platform\\gba\\OpenLara.elf
|
||||
./mGBA.exe C:\\Projects\\OpenLara\\src\\platform\\gba\\OpenLara.gba
|
||||
|
474
src/platform/gba/draw.h
Normal file
474
src/platform/gba/draw.h
Normal file
@@ -0,0 +1,474 @@
|
||||
#ifndef H_DRAW
|
||||
#define H_DRAW
|
||||
|
||||
#include "common.h"
|
||||
#include "item.h"
|
||||
|
||||
int32 seqGlyphs;
|
||||
|
||||
void drawNumber(int32 number, int32 x, int32 y)
|
||||
{
|
||||
const int32 widths[] = {
|
||||
12, 8, 10, 10, 10, 10, 10, 10, 10, 10
|
||||
};
|
||||
|
||||
const Sprite *glyphSprites = sprites + spritesSeq[seqGlyphs].sStart;
|
||||
|
||||
while (number > 0)
|
||||
{
|
||||
x -= widths[number % 10];
|
||||
drawGlyph(glyphSprites + 52 + (number % 10), x, y);
|
||||
number /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void drawMesh(int16 meshIndex, uint16 intensity)
|
||||
{
|
||||
int32 offset = meshOffsets[meshIndex];
|
||||
const uint8* ptr = meshData + offset;
|
||||
|
||||
ptr += 2 * 5; // skip [cx, cy, cz, radius, flags]
|
||||
|
||||
int16 vCount = *(int16*)ptr; ptr += 2;
|
||||
const vec3s* vertices = (vec3s*)ptr;
|
||||
ptr += vCount * 3 * sizeof(int16);
|
||||
|
||||
int16 nCount = *(int16*)ptr; ptr += 2;
|
||||
//const int16* normals = (int16*)ptr;
|
||||
if (nCount > 0) { // normals
|
||||
ptr += nCount * 3 * sizeof(int16);
|
||||
} else { // intensity
|
||||
ptr += vCount * sizeof(int16);
|
||||
}
|
||||
|
||||
int16 rCount = *(int16*)ptr; ptr += 2;
|
||||
Quad* rFaces = (Quad*)ptr; ptr += rCount * sizeof(Quad);
|
||||
|
||||
int16 tCount = *(int16*)ptr; ptr += 2;
|
||||
Triangle* tFaces = (Triangle*)ptr; ptr += tCount * sizeof(Triangle);
|
||||
|
||||
int16 crCount = *(int16*)ptr; ptr += 2;
|
||||
Quad* crFaces = (Quad*)ptr; ptr += crCount * sizeof(Quad);
|
||||
|
||||
int16 ctCount = *(int16*)ptr; ptr += 2;
|
||||
Triangle* ctFaces = (Triangle*)ptr; ptr += ctCount * sizeof(Triangle);
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
PROFILE_START();
|
||||
transformMesh(vertices, vCount, intensity);
|
||||
PROFILE_STOP(dbg_transform);
|
||||
|
||||
PROFILE_START();
|
||||
faceAddMesh(rFaces, crFaces, tFaces, ctFaces, rCount, crCount, tCount, ctCount, startVertex);
|
||||
PROFILE_STOP(dbg_poly);
|
||||
}
|
||||
|
||||
void drawShadow(const Item* item)
|
||||
{
|
||||
const RoomInfo::Sector* sector = getSector(item->room, item->pos.x, item->pos.z);
|
||||
int32 floor = getFloor(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
if (floor == WALL)
|
||||
return;
|
||||
|
||||
int32 shadowSize = 160; // TODO per item
|
||||
|
||||
const Box& box = getBoundingBox(item);
|
||||
int32 x = (box.maxX + box.minX) >> 1;
|
||||
int32 z = (box.maxZ + box.minZ) >> 1;
|
||||
int32 sx = (box.maxX - box.minX) * shadowSize >> 10;
|
||||
int32 sz = (box.maxZ - box.minZ) * shadowSize >> 10;
|
||||
int32 sx2 = sx << 1;
|
||||
int32 sz2 = sz << 1;
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
int32 y = floor - item->pos.y;
|
||||
|
||||
transform(vec3s(x - sx, y, z + sz2), 4096);
|
||||
transform(vec3s(x + sx, y, z + sz2), 4096);
|
||||
transform(vec3s(x + sx2, y, z + sz), 4096);
|
||||
transform(vec3s(x + sx2, y, z - sz), 4096);
|
||||
|
||||
transform(vec3s(x + sx, y, z - sz2), 4096);
|
||||
transform(vec3s(x - sx, y, z - sz2), 4096);
|
||||
transform(vec3s(x - sx2, y, z - sz), 4096);
|
||||
transform(vec3s(x - sx2, y, z + sz), 4096);
|
||||
|
||||
static const Index indices[] = {
|
||||
0, 1, 2, 7,
|
||||
7, 2, 3, 6,
|
||||
6, 3, 4, 5
|
||||
};
|
||||
|
||||
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 0, startVertex);
|
||||
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 4, startVertex);
|
||||
faceAddQuad(FACE_COLORED | FACE_FLAT | FACE_SHADOW, indices + 8, startVertex);
|
||||
}
|
||||
|
||||
void drawItem(const Item* item)
|
||||
{
|
||||
int32 modelIndex = modelsMap[item->type];
|
||||
if (modelIndex == NO_MODEL) {
|
||||
return; // TODO sprite items
|
||||
}
|
||||
|
||||
const Model* model = models + modelIndex;
|
||||
|
||||
if (model->mCount == 1 && meshOffsets[model->mStart] == 0)
|
||||
return;
|
||||
|
||||
AnimFrame* frame = getFrame(item, model);
|
||||
uint16* frameAngles = frame->angles + 1;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(item->pos);
|
||||
matrixRotateYXZ(item->angleX, item->angleY, item->angleZ);
|
||||
|
||||
int32 intensity = item->intensity;
|
||||
|
||||
if (intensity == 0xFFFF) {
|
||||
intensity = itemCalcLighting(item, frame->box);
|
||||
}
|
||||
|
||||
bool isVisible = boxIsVisible(&frame->box);
|
||||
if (isVisible)
|
||||
{
|
||||
// non-aligned access (TODO)
|
||||
uint32 nodeIndex;
|
||||
memcpy(&nodeIndex, &model->nodeIndex, sizeof(nodeIndex));
|
||||
Node nodes[32];
|
||||
memcpy(nodes, nodesPtr + nodeIndex, (model->mCount - 1) * sizeof(Node));
|
||||
|
||||
const Node* node = nodes;
|
||||
|
||||
matrixFrame(frame->pos, frameAngles);
|
||||
|
||||
drawMesh(model->mStart, intensity);
|
||||
|
||||
for (int32 i = 1; i < model->mCount; i++)
|
||||
{
|
||||
if (node->flags & 1) matrixPop();
|
||||
if (node->flags & 2) matrixPush();
|
||||
|
||||
frameAngles += 2;
|
||||
matrixFrame(node->pos, frameAngles);
|
||||
|
||||
drawMesh(model->mStart + i, intensity);
|
||||
|
||||
node++;
|
||||
}
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
|
||||
// shadow
|
||||
if (isVisible & item->flags.shadow) {
|
||||
matrixPush();
|
||||
matrixTranslateAbs(item->pos);
|
||||
matrixRotateY(item->angleY);
|
||||
|
||||
drawShadow(item);
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
}
|
||||
|
||||
void drawRoom(const Room* room)
|
||||
{
|
||||
clip = room->clip;
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(vec3i(room->x, 0, room->z));
|
||||
|
||||
PROFILE_START();
|
||||
transformRoom(room->vertices, room->vCount);
|
||||
PROFILE_STOP(dbg_transform);
|
||||
|
||||
matrixPop();
|
||||
|
||||
PROFILE_START();
|
||||
faceAddRoom(room->quads, room->qCount, room->triangles, room->tCount, startVertex);
|
||||
|
||||
for (int32 i = 0; i < room->mCount; i++)
|
||||
{
|
||||
const RoomInfo::Mesh* mesh = room->meshes + i;
|
||||
const StaticMesh* staticMesh = staticMeshes + staticMeshesMap[mesh->staticMeshId];
|
||||
|
||||
if (!(staticMesh->flags & 2)) continue; // invisible
|
||||
|
||||
// TODO align RoomInfo::Mesh (room relative int16?)
|
||||
vec3i pos;
|
||||
memcpy(&pos, &mesh->pos, sizeof(pos));
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(pos);
|
||||
matrixRotateY(mesh->rotation);
|
||||
|
||||
if (boxIsVisible(&staticMesh->vbox)) {
|
||||
drawMesh(staticMesh->meshIndex, mesh->intensity);
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
int32 itemIndex = room->firstItem;
|
||||
while (itemIndex != NO_ITEM)
|
||||
{
|
||||
drawItem(items + itemIndex);
|
||||
itemIndex = items[itemIndex].nextItem;
|
||||
}
|
||||
PROFILE_STOP(dbg_poly);
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
bool checkPortal(int32 roomIndex, const RoomInfo::Portal* portal)
|
||||
{
|
||||
Room &room = rooms[roomIndex];
|
||||
|
||||
vec3i d;
|
||||
d.x = portal->v[0].x - camera.viewPos.x + room.x;
|
||||
d.y = portal->v[0].y - camera.viewPos.y;
|
||||
d.z = portal->v[0].z - camera.viewPos.z + room.z;
|
||||
|
||||
if (DP33(portal->n, d) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 x0 = room.clip.x1;
|
||||
int32 y0 = room.clip.y1;
|
||||
int32 x1 = room.clip.x0;
|
||||
int32 y1 = room.clip.y0;
|
||||
|
||||
int32 znear = 0, zfar = 0;
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
vec3i pv[4];
|
||||
|
||||
for (int32 i = 0; i < 4; i++)
|
||||
{
|
||||
const vec3s &v = portal->v[i];
|
||||
|
||||
int32 x = DP43(m[0], v);
|
||||
int32 y = DP43(m[1], v);
|
||||
int32 z = DP43(m[2], v);
|
||||
|
||||
pv[i].x = x;
|
||||
pv[i].y = y;
|
||||
pv[i].z = z;
|
||||
|
||||
if (z <= VIEW_MIN_F) {
|
||||
znear++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z >= VIEW_MAX_F) {
|
||||
zfar++;
|
||||
}
|
||||
|
||||
if (z != 0) {
|
||||
PERSPECTIVE(x, y, z);
|
||||
|
||||
x += FRAME_WIDTH >> 1;
|
||||
y += FRAME_HEIGHT >> 1;
|
||||
} else {
|
||||
x = (x > 0) ? clip.x1 : clip.x0;
|
||||
y = (y > 0) ? clip.y1 : clip.y0;
|
||||
}
|
||||
|
||||
if (x < x0) x0 = x;
|
||||
if (x > x1) x1 = x;
|
||||
if (y < y0) y0 = y;
|
||||
if (y > y1) y1 = y;
|
||||
}
|
||||
|
||||
if (znear == 4 || zfar == 4) return false;
|
||||
|
||||
if (znear) {
|
||||
vec3i *a = pv;
|
||||
vec3i *b = pv + 3;
|
||||
for (int32 i = 0; i < 4; i++) {
|
||||
if ((a->z < 0) ^ (b->z < 0)) {
|
||||
if (a->x < 0 && b->x < 0) {
|
||||
x0 = 0;
|
||||
} else if (a->x > 0 && b->x > 0) {
|
||||
x1 = FRAME_WIDTH;
|
||||
} else {
|
||||
x0 = 0;
|
||||
x1 = FRAME_WIDTH;
|
||||
}
|
||||
|
||||
if (a->y < 0 && b->y < 0) {
|
||||
y0 = 0;
|
||||
} else if (a->y > 0 && b->y > 0) {
|
||||
y1 = FRAME_HEIGHT;
|
||||
} else {
|
||||
y0 = 0;
|
||||
y1 = FRAME_HEIGHT;
|
||||
}
|
||||
}
|
||||
b = a;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
if (x0 < room.clip.x0) x0 = room.clip.x0;
|
||||
if (x1 > room.clip.x1) x1 = room.clip.x1;
|
||||
if (y0 < room.clip.y0) y0 = room.clip.y0;
|
||||
if (y1 > room.clip.y1) y1 = room.clip.y1;
|
||||
|
||||
if (x0 >= x1 || y0 >= y1) return false;
|
||||
|
||||
Room &nextRoom = rooms[portal->roomIndex];
|
||||
|
||||
if (x0 < nextRoom.clip.x0) nextRoom.clip.x0 = x0;
|
||||
if (x1 > nextRoom.clip.x1) nextRoom.clip.x1 = x1;
|
||||
if (y0 < nextRoom.clip.y0) nextRoom.clip.y0 = y0;
|
||||
if (y1 > nextRoom.clip.y1) nextRoom.clip.y1 = y1;
|
||||
|
||||
if (!nextRoom.visible) {
|
||||
nextRoom.visible = true;
|
||||
visRooms[visRoomsCount++] = portal->roomIndex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getVisibleRooms(int32 roomIndex)
|
||||
{
|
||||
const Room* room = rooms + roomIndex;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(vec3i(room->x, 0, room->z));
|
||||
|
||||
for (int32 i = 0; i < room->pCount; i++)
|
||||
{
|
||||
const RoomInfo::Portal* portal = room->portals + i;
|
||||
|
||||
if (checkPortal(roomIndex, portal))
|
||||
{
|
||||
getVisibleRooms(portal->roomIndex);
|
||||
}
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
void roomReset(Room* room)
|
||||
{
|
||||
room->visible = false;
|
||||
room->clip = { FRAME_WIDTH, FRAME_HEIGHT, 0, 0 };
|
||||
}
|
||||
|
||||
void drawRooms()
|
||||
{
|
||||
rooms[camera.room].clip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||
visRoomsCount = 0;
|
||||
visRooms[visRoomsCount++] = camera.room;
|
||||
|
||||
getVisibleRooms(camera.room);
|
||||
|
||||
while (visRoomsCount--)
|
||||
{
|
||||
Room* room = rooms + visRooms[visRoomsCount];
|
||||
drawRoom(room);
|
||||
roomReset(room);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
|
||||
|
||||
extern Vertex gVertices[MAX_VERTICES];
|
||||
|
||||
void drawTest() {
|
||||
static Rect testClip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||
static int32 testTile = 10; // 707 // 712
|
||||
|
||||
#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)
|
||||
((uint16*)fb)[y * FRAME_WIDTH + x] = 255;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
19
src/platform/gba/enemy.h
Normal file
19
src/platform/gba/enemy.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef H_ENEMY
|
||||
#define H_ENEMY
|
||||
|
||||
struct Bat
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct Wolf
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct Bear
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
#endif
|
160
src/platform/gba/game.h
Normal file
160
src/platform/gba/game.h
Normal file
@@ -0,0 +1,160 @@
|
||||
#ifndef H_GAME
|
||||
#define H_GAME
|
||||
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "level.h"
|
||||
#include "camera.h"
|
||||
#include "item.h"
|
||||
#include "lara.h"
|
||||
#include "draw.h"
|
||||
|
||||
struct Game
|
||||
{
|
||||
void init()
|
||||
{
|
||||
loadLevel(LEVEL1_PHD);
|
||||
}
|
||||
|
||||
void loadLevel(const void* data)
|
||||
{
|
||||
camera.init();
|
||||
|
||||
readLevel((uint8*)LEVEL1_PHD);
|
||||
|
||||
// prepare rooms
|
||||
for (int32 i = 0; i < roomsCount; i++)
|
||||
{
|
||||
roomReset(rooms + i);
|
||||
}
|
||||
|
||||
// prepare items
|
||||
for (int32 i = 0; i < itemsCount; i++)
|
||||
{
|
||||
Item* item = items + i;
|
||||
|
||||
itemInit(item);
|
||||
|
||||
if (item->room > -1) {
|
||||
roomItemAdd(item->room, i);
|
||||
}
|
||||
|
||||
if (item->type == ITEM_LARA) {
|
||||
camera.item = item;
|
||||
|
||||
// debug
|
||||
//resetItem(i, 14, vec3i(20215, 6656, 52942), 0); // level 1 (bridge)
|
||||
//resetItem(i, 26, vec3i(24475, 6912, 83505), 90 * DEG2SHORT); // level 1 (switch timer)
|
||||
|
||||
camera.room = item->room;
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
if (item->type == ITEM_LARA ||
|
||||
item->type == ITEM_WOLF ||
|
||||
item->type == ITEM_BEAR ||
|
||||
item->type == ITEM_BAT ||
|
||||
item->type == ITEM_CRYSTAL)
|
||||
{
|
||||
activateItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare glyphs
|
||||
for (int32 i = 0; i < spritesSeqCount; i++) {
|
||||
if (spritesSeq[i].type == ITEM_GLYPHS) {
|
||||
seqGlyphs = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resetItem(int32 itemIndex, int32 roomIndex, const vec3i &pos, int32 angleY)
|
||||
{
|
||||
roomItemRemove(itemIndex);
|
||||
|
||||
Item* item = items + itemIndex;
|
||||
item->pos = vec3i(20215, 6656, 52942);
|
||||
item->angleY = angleY;
|
||||
item->health = LARA_MAX_HEALTH;
|
||||
|
||||
roomItemAdd(roomIndex, itemIndex);
|
||||
}
|
||||
|
||||
void updateItems()
|
||||
{
|
||||
curItemIndex = firstActive;
|
||||
while (curItemIndex != NO_ITEM)
|
||||
{
|
||||
Item* item = items + curItemIndex;
|
||||
|
||||
if (item->type == ITEM_LARA) {
|
||||
Lara* lara = (Lara*)item;
|
||||
lara->update();
|
||||
} else {
|
||||
itemControl(item);
|
||||
}
|
||||
|
||||
curItemIndex = item->nextActive;
|
||||
}
|
||||
}
|
||||
|
||||
void update(int32 frames)
|
||||
{
|
||||
if (frames > MAX_UPDATE_FRAMES) {
|
||||
frames = MAX_UPDATE_FRAMES;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < frames; i++) {
|
||||
updateItems();
|
||||
camera.update();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
int32 TEXT_POSX = FRAME_HEIGHT;
|
||||
#else
|
||||
int32 TEXT_POSX = FRAME_WIDTH;
|
||||
#endif
|
||||
|
||||
void render()
|
||||
{
|
||||
clear();
|
||||
|
||||
#ifdef TEST
|
||||
#ifdef __GBA__
|
||||
VBlankIntrWait();
|
||||
#endif
|
||||
|
||||
int32 cycles = 0;
|
||||
PROFILE_START();
|
||||
drawTest();
|
||||
PROFILE_STOP(cycles);
|
||||
|
||||
drawNumber(cycles, TEXT_POSX, 32);
|
||||
#else
|
||||
#ifdef PROFILE
|
||||
dbg_transform = 0;
|
||||
dbg_poly = 0;
|
||||
dbg_flush = 0;
|
||||
dbg_vert_count = 0;
|
||||
dbg_poly_count = 0;
|
||||
#endif
|
||||
|
||||
drawRooms();
|
||||
|
||||
#ifdef PROFILE
|
||||
drawNumber(dbg_transform, TEXT_POSX, 32);
|
||||
drawNumber(dbg_poly, TEXT_POSX, 48);
|
||||
drawNumber(dbg_flush, TEXT_POSX, 64);
|
||||
drawNumber(dbg_vert_count, TEXT_POSX, 84);
|
||||
drawNumber(dbg_poly_count, TEXT_POSX, 100);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
drawNumber(fps, TEXT_POSX, 16);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
384
src/platform/gba/item.h
Normal file
384
src/platform/gba/item.h
Normal file
@@ -0,0 +1,384 @@
|
||||
#ifndef H_ITEM
|
||||
#define H_ITEM
|
||||
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "camera.h"
|
||||
|
||||
int32 curItemIndex;
|
||||
|
||||
#define GRAVITY 6
|
||||
|
||||
int16 angleDec(int16 angle, int32 value) {
|
||||
if (angle < -value) {
|
||||
return angle + value;
|
||||
} else if (angle > value) {
|
||||
return angle - value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
AnimFrame* getFrame(const Item* item, const Model* model)
|
||||
{
|
||||
const Anim* anim = anims + item->animIndex;
|
||||
|
||||
int32 frameSize = sizeof(AnimFrame) / 2 + model->mCount * 2;
|
||||
int32 frameIndex = (item->frameIndex - anim->frameBegin) / anim->frameRate; // TODO fixed div? check the range
|
||||
|
||||
return (AnimFrame*)(animFrames + anim->frameOffset / 2 + frameIndex * frameSize);
|
||||
}
|
||||
|
||||
const Box& getBoundingBox(const Item* item)
|
||||
{
|
||||
const Model* model = models + modelsMap[item->type];
|
||||
AnimFrame* frame = getFrame(item, model);
|
||||
return frame->box;
|
||||
}
|
||||
|
||||
Sound::Sample* soundPlay(int16 id, const vec3i &pos)
|
||||
{
|
||||
int16 a = soundMap[id];
|
||||
|
||||
if (a == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const SoundInfo* b = soundInfos + a;
|
||||
|
||||
if (b->chance && b->chance < xRand()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec3i d = pos - camera.targetPos;
|
||||
|
||||
if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32 volume = b->volume - (phd_sqrt(dot(d, d)) << 2);
|
||||
|
||||
if (b->flags.gain) {
|
||||
volume -= xRand() >> 2;
|
||||
}
|
||||
|
||||
if (volume <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
volume = X_MIN(volume, 0x7FFF);
|
||||
|
||||
int32 pitch = 128;
|
||||
|
||||
if (b->flags.pitch) {
|
||||
pitch += ((xRand() * 13) >> 14) - 13;
|
||||
}
|
||||
|
||||
int32 index = b->index;
|
||||
if (b->flags.count > 1) {
|
||||
index += (xRand() * b->flags.count) >> 15;
|
||||
}
|
||||
|
||||
const uint8 *data = soundData + soundOffsets[index];
|
||||
|
||||
int32 size;
|
||||
memcpy(&size, data + 40, 4); // TODO preprocess and remove wave header
|
||||
data += 44;
|
||||
|
||||
return sound.play(data, size, volume, pitch, b->flags.mode);
|
||||
}
|
||||
|
||||
void move(Item* item, const Anim* anim)
|
||||
{
|
||||
int32 speed = anim->speed;
|
||||
|
||||
if (item->flags.gravity)
|
||||
{
|
||||
speed += anim->accel * (item->frameIndex - anim->frameBegin - 1);
|
||||
item->hSpeed -= speed >> 16;
|
||||
speed += anim->accel;
|
||||
item->hSpeed += speed >> 16;
|
||||
|
||||
item->vSpeed += (item->vSpeed < 128) ? GRAVITY : 1;
|
||||
|
||||
item->pos.y += item->vSpeed;
|
||||
} else {
|
||||
speed += anim->accel * (item->frameIndex - anim->frameBegin);
|
||||
|
||||
item->hSpeed = speed >> 16;
|
||||
}
|
||||
|
||||
item->pos.x += phd_sin(item->moveAngle) * item->hSpeed >> FIXED_SHIFT;
|
||||
item->pos.z += phd_cos(item->moveAngle) * item->hSpeed >> FIXED_SHIFT;
|
||||
}
|
||||
|
||||
const Anim* animSet(Item* item, int32 animIndex, bool resetState, int32 frameOffset = 0) {
|
||||
const Anim* anim = anims + animIndex;
|
||||
|
||||
item->animIndex = animIndex;
|
||||
item->frameIndex = anim->frameBegin + frameOffset;
|
||||
|
||||
if (resetState) {
|
||||
item->state = item->goalState = anim->state;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
const Anim* animChange(Item* item, const Anim* anim)
|
||||
{
|
||||
if (!anim->statesCount || item->goalState == item->state)
|
||||
return anim;
|
||||
|
||||
const AnimState* animState = animStates + anim->statesStart;
|
||||
|
||||
for (int32 i = 0; i < anim->statesCount; i++)
|
||||
{
|
||||
if (item->goalState == animState->state)
|
||||
{
|
||||
const AnimRange* animRange = animRanges + animState->rangesStart;
|
||||
|
||||
for (int32 j = 0; j < animState->rangesCount; j++)
|
||||
{
|
||||
if ((item->frameIndex >= animRange->frameBegin) && (item->frameIndex <= animRange->frameEnd))
|
||||
{
|
||||
if ((item->type != ITEM_LARA) && (item->nextState == animState->state)) {
|
||||
item->nextState = 0;
|
||||
}
|
||||
|
||||
item->frameIndex = animRange->nextFrameIndex;
|
||||
item->animIndex = animRange->nextAnimIndex;
|
||||
anim = anims + animRange->nextAnimIndex;
|
||||
item->state = anim->state;
|
||||
return anim;
|
||||
}
|
||||
animRange++;
|
||||
}
|
||||
}
|
||||
animState++;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
void animCmd(bool fx, Item* item, const Anim* anim)
|
||||
{
|
||||
if (!anim->commandsCount) return;
|
||||
|
||||
const int16 *ptr = animCommands + anim->commandsStart;
|
||||
|
||||
for (int32 i = 0; i < anim->commandsCount; i++)
|
||||
{
|
||||
int32 cmd = *ptr++;
|
||||
|
||||
switch (cmd) {
|
||||
case ANIM_CMD_NONE:
|
||||
break;
|
||||
case ANIM_CMD_OFFSET:
|
||||
{
|
||||
if (!fx)
|
||||
{
|
||||
int32 s = phd_sin(item->moveAngle);
|
||||
int32 c = phd_cos(item->moveAngle);
|
||||
int32 x = ptr[0];
|
||||
int32 y = ptr[1];
|
||||
int32 z = ptr[2];
|
||||
item->pos.x += (c * x + s * z) >> FIXED_SHIFT;
|
||||
item->pos.y += y;
|
||||
item->pos.z += (c * z - s * x) >> FIXED_SHIFT;
|
||||
}
|
||||
ptr += 3;
|
||||
break;
|
||||
}
|
||||
case ANIM_CMD_JUMP:
|
||||
if (!fx)
|
||||
{
|
||||
if (item->vSpeedHack) {
|
||||
item->vSpeed = item->vSpeedHack;
|
||||
item->vSpeedHack = 0;
|
||||
} else {
|
||||
item->vSpeed = ptr[0];
|
||||
}
|
||||
item->hSpeed = ptr[1];
|
||||
item->flags.gravity = true;
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
case ANIM_CMD_EMPTY:
|
||||
break;
|
||||
case ANIM_CMD_KILL:
|
||||
break;
|
||||
case ANIM_CMD_SOUND:
|
||||
if (fx && item->frameIndex == ptr[0])
|
||||
{
|
||||
soundPlay(ptr[1] & 0x03FFF, item->pos);
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
case ANIM_CMD_EFFECT:
|
||||
if (fx && item->frameIndex == ptr[0]) {
|
||||
switch (ptr[1]) {
|
||||
case FX_ROTATE_180 : item->angleY -= ANGLE_180; break;
|
||||
/*
|
||||
case FX_FLOOR_SHAKE : ASSERT(false);
|
||||
case FX_LARA_NORMAL : animation.setAnim(ANIM_STAND); break;
|
||||
case FX_LARA_BUBBLES : doBubbles(); break;
|
||||
case FX_LARA_HANDSFREE : break;//meshSwap(1, level->extra.weapons[wpnCurrent], BODY_LEG_L1 | BODY_LEG_R1); break;
|
||||
case FX_DRAW_RIGHTGUN : drawGun(true); break;
|
||||
case FX_DRAW_LEFTGUN : drawGun(false); break;
|
||||
case FX_SHOT_RIGHTGUN : game->addMuzzleFlash(this, LARA_RGUN_JOINT, LARA_RGUN_OFFSET, 1 + camera->cameraIndex); break;
|
||||
case FX_SHOT_LEFTGUN : game->addMuzzleFlash(this, LARA_LGUN_JOINT, LARA_LGUN_OFFSET, 1 + camera->cameraIndex); break;
|
||||
case FX_MESH_SWAP_1 :
|
||||
case FX_MESH_SWAP_2 :
|
||||
case FX_MESH_SWAP_3 : Character::cmdEffect(fx);
|
||||
case 26 : break; // TODO TR2 reset_hair
|
||||
case 32 : break; // TODO TR3 footprint
|
||||
default : LOG("unknown effect command %d (anim %d)\n", fx, animation.index); ASSERT(false);
|
||||
*/
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animUpdate(Item* item)
|
||||
{
|
||||
if (modelsMap[item->type] == NO_MODEL)
|
||||
return;
|
||||
|
||||
const Anim* anim = anims + item->animIndex;
|
||||
|
||||
item->frameIndex++;
|
||||
|
||||
anim = animChange(item, anim);
|
||||
|
||||
if (item->frameIndex > anim->frameEnd)
|
||||
{
|
||||
animCmd(false, item, anim);
|
||||
|
||||
item->frameIndex = anim->nextFrameIndex;
|
||||
item->animIndex = anim->nextAnimIndex;
|
||||
anim = anims + anim->nextAnimIndex;
|
||||
item->state = anim->state;
|
||||
}
|
||||
|
||||
animCmd(true, item, anim);
|
||||
|
||||
move(item, anim);
|
||||
}
|
||||
|
||||
int32 calcLight(const vec3i &pos, int32 roomIndex)
|
||||
{
|
||||
Room* room = rooms + roomIndex;
|
||||
|
||||
if (!room->lCount) {
|
||||
return room->ambient;
|
||||
}
|
||||
|
||||
int32 ambient = 8191 - room->ambient;
|
||||
int32 intensity = 0;
|
||||
|
||||
for (int i = 0; i < room->lCount; i++)
|
||||
{
|
||||
const RoomInfo::Light* light = room->lights + i;
|
||||
|
||||
// TODO preprocess align
|
||||
vec3i lpos;
|
||||
int32 lradius;
|
||||
memcpy(&lpos, &light->pos[0], sizeof(lpos));
|
||||
memcpy(&lradius, &light->radius[0], sizeof(lradius));
|
||||
|
||||
vec3i d = pos - lpos;
|
||||
int32 dist = dot(d, d) >> 12;
|
||||
int32 att = X_SQR(lradius) >> 12;
|
||||
|
||||
int32 lum = (light->intensity * att) / (dist + att) + ambient;
|
||||
|
||||
if (lum > intensity)
|
||||
{
|
||||
intensity = lum;
|
||||
}
|
||||
}
|
||||
|
||||
return 8191 - ((intensity + ambient) >> 1);
|
||||
}
|
||||
|
||||
int32 itemCalcLighting(const Item* item, const Box& box)
|
||||
{
|
||||
matrixPush();
|
||||
Matrix &m = matrixGet();
|
||||
m[0][3] = m[1][3] = m[2][3] = 0;
|
||||
matrixRotateYXZ(item->angleX, item->angleY, item->angleZ);
|
||||
|
||||
vec3i v((box.maxX + box.minX) >> 1,
|
||||
(box.maxY + box.minY) >> 1,
|
||||
(box.maxZ + box.minZ) >> 1);
|
||||
|
||||
matrixTranslate(v);
|
||||
|
||||
v = vec3i(m[0][3] >> FIXED_SHIFT,
|
||||
m[1][3] >> FIXED_SHIFT,
|
||||
m[2][3] >> FIXED_SHIFT) + item->pos;
|
||||
matrixPop();
|
||||
|
||||
return calcLight(v, item->room);
|
||||
}
|
||||
|
||||
void itemControl(Item* item)
|
||||
{
|
||||
animUpdate(item);
|
||||
}
|
||||
|
||||
void itemInit(Item* item)
|
||||
{
|
||||
item->angleX = 0;
|
||||
item->angleZ = 0;
|
||||
item->vSpeed = 0;
|
||||
item->hSpeed = 0;
|
||||
item->nextItem = NO_ITEM;
|
||||
item->nextActive = NO_ITEM;
|
||||
item->animIndex = models[modelsMap[item->type]].animIndex;
|
||||
item->frameIndex = anims[item->animIndex].frameBegin;
|
||||
item->state = anims[item->animIndex].state;
|
||||
item->nextState = item->state;
|
||||
item->goalState = item->state;
|
||||
item->flags.gravity = false;
|
||||
item->flags.shadow = true;
|
||||
|
||||
switch (item->type) {
|
||||
case ITEM_LARA : item->health = 1000; break;
|
||||
case ITEM_DOPPELGANGER : item->health = 1000; break;
|
||||
case ITEM_WOLF : item->health = 6; break;
|
||||
case ITEM_BEAR : item->health = 20; break;
|
||||
case ITEM_BAT : item->health = 1; break;
|
||||
case ITEM_CROCODILE_LAND : item->health = 20; break;
|
||||
case ITEM_CROCODILE_WATER : item->health = 20; break;
|
||||
case ITEM_LION_MALE : item->health = 30; break;
|
||||
case ITEM_LION_FEMALE : item->health = 25; break;
|
||||
case ITEM_PUMA : item->health = 45; break;
|
||||
case ITEM_GORILLA : item->health = 22; break;
|
||||
case ITEM_RAT_LAND : item->health = 5; break;
|
||||
case ITEM_RAT_WATER : item->health = 5; break;
|
||||
case ITEM_REX : item->health = 100; break;
|
||||
case ITEM_RAPTOR : item->health = 20; break;
|
||||
case ITEM_MUTANT_1 : item->health = 50; break;
|
||||
case ITEM_MUTANT_2 : item->health = 50; break;
|
||||
case ITEM_MUTANT_3 : item->health = 50; break;
|
||||
case ITEM_CENTAUR : item->health = 120; break;
|
||||
case ITEM_MUMMY : item->health = 18; break;
|
||||
case ITEM_LARSON : item->health = 50; break;
|
||||
case ITEM_PIERRE : item->health = 70; break;
|
||||
case ITEM_SKATEBOY : item->health = 125; break;
|
||||
case ITEM_COWBOY : item->health = 150; break;
|
||||
case ITEM_MR_T : item->health = 200; break;
|
||||
case ITEM_NATLA : item->health = 400; break;
|
||||
case ITEM_GIANT_MUTANT : item->health = 500; break;
|
||||
default :
|
||||
item->health = 0;
|
||||
item->flags.shadow = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
2044
src/platform/gba/lara.h
Normal file
2044
src/platform/gba/lara.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,9 @@
|
||||
#define H_LEVEL
|
||||
|
||||
#include "common.h"
|
||||
#include "camera.h"
|
||||
|
||||
#define GRAVITY 6
|
||||
|
||||
// level file data -------------------
|
||||
int32 tilesCount;
|
||||
//int32 tilesCount;
|
||||
extern const uint8* tiles;
|
||||
|
||||
extern uint16 palette[256];
|
||||
@@ -27,11 +24,20 @@ const int32* meshOffsets;
|
||||
|
||||
const int32* nodesPtr;
|
||||
|
||||
int32 animsCount;
|
||||
//int32 animsCount;
|
||||
const Anim* anims;
|
||||
|
||||
int32 framesCount;
|
||||
const uint16* frames;
|
||||
//int32 animStatesCount;
|
||||
const AnimState* animStates;
|
||||
|
||||
//int32 animRangesCount;
|
||||
const AnimRange* animRanges;
|
||||
|
||||
//int32 animCommandsCount;
|
||||
const int16* animCommands;
|
||||
|
||||
//int32 animFramesCount;
|
||||
const uint16* animFrames;
|
||||
|
||||
int32 modelsCount;
|
||||
EWRAM_DATA Model models[MAX_MODELS];
|
||||
@@ -43,34 +49,19 @@ const StaticMesh* staticMeshes;
|
||||
|
||||
int32 itemsCount;
|
||||
EWRAM_DATA Item items[MAX_ITEMS];
|
||||
|
||||
const uint16* soundMap;
|
||||
|
||||
//int32 soundInfosCount;
|
||||
const SoundInfo* soundInfos;
|
||||
|
||||
//int32 soundDataSize;
|
||||
const uint8* soundData;
|
||||
|
||||
//int32 soundOffsetsCount;
|
||||
const uint32* soundOffsets;
|
||||
// -----------------------------------
|
||||
|
||||
struct Room {
|
||||
Rect clip;
|
||||
uint8 firstItem;
|
||||
bool visible;
|
||||
|
||||
// TODO leave in ROM
|
||||
int32 x, z;
|
||||
uint16 vCount;
|
||||
uint16 qCount;
|
||||
uint16 tCount;
|
||||
uint16 pCount;
|
||||
uint16 lCount;
|
||||
uint16 mCount;
|
||||
uint16 zSectors;
|
||||
uint16 xSectors;
|
||||
uint16 ambient;
|
||||
|
||||
const RoomInfo::Vertex* vertices;
|
||||
const Quad* quads;
|
||||
const Triangle* triangles;
|
||||
const RoomInfo::Portal* portals;
|
||||
const RoomInfo::Sector* sectors;
|
||||
const RoomInfo::Light* lights;
|
||||
const RoomInfo::Mesh* meshes;
|
||||
};
|
||||
|
||||
int16 roomsCount;
|
||||
EWRAM_DATA Room rooms[64];
|
||||
|
||||
@@ -80,41 +71,24 @@ int32 visRoomsCount;
|
||||
int32 visRooms[16];
|
||||
|
||||
#define ROOM_VISIBLE (1 << 15)
|
||||
#define SEQ_GLYPH 190
|
||||
|
||||
enum FloorType {
|
||||
FLOOR_TYPE_NONE,
|
||||
FLOOR_TYPE_PORTAL,
|
||||
FLOOR_TYPE_FLOOR,
|
||||
FLOOR_TYPE_CEILING,
|
||||
};
|
||||
|
||||
int32 seqGlyphs;
|
||||
|
||||
extern uint32 gVerticesCount;
|
||||
extern Rect clip;
|
||||
|
||||
void roomReset(int32 roomIndex)
|
||||
{
|
||||
Room* room = rooms + roomIndex;
|
||||
|
||||
room->visible = false;
|
||||
room->clip = { FRAME_WIDTH, FRAME_HEIGHT, 0, 0 };
|
||||
}
|
||||
|
||||
void roomItemAdd(int32 roomIndex, int32 itemIndex)
|
||||
{
|
||||
ASSERT(items[itemIndex].nextItem == NO_ITEM);
|
||||
|
||||
Item* item = items + itemIndex;
|
||||
Room* room = rooms + roomIndex;
|
||||
|
||||
items[itemIndex].nextItem = room->firstItem;
|
||||
ASSERT(item->nextItem == NO_ITEM);
|
||||
|
||||
item->room = roomIndex;
|
||||
item->nextItem = room->firstItem;
|
||||
room->firstItem = itemIndex;
|
||||
}
|
||||
|
||||
void roomItemRemove(int32 roomIndex, int32 itemIndex)
|
||||
void roomItemRemove(int32 itemIndex)
|
||||
{
|
||||
Room* room = rooms + roomIndex;
|
||||
Item* item = items + itemIndex;
|
||||
Room* room = rooms + item->room;
|
||||
item->room = NO_ROOM;
|
||||
|
||||
int32 prevIndex = NO_ITEM;
|
||||
int32 index = room->firstItem;
|
||||
@@ -174,8 +148,28 @@ void deactivateItem(int32 itemIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void fixLightmap(int32 palIndex)
|
||||
{
|
||||
uint16 color = palette[palIndex];
|
||||
|
||||
int32 r = 0x1F & (color);
|
||||
int32 g = 0x1F & (color >> 5);
|
||||
int32 b = 0x1F & (color >> 10);
|
||||
|
||||
for (int32 i = 0; i < 32; i++)
|
||||
{
|
||||
int32 lum = 31 - i;
|
||||
|
||||
int32 lumR = X_CLAMP((r * lum) / 14, 0, 31);
|
||||
int32 lumG = X_CLAMP((g * lum) / 14, 0, 31);
|
||||
int32 lumB = X_CLAMP((b * lum) / 14, 0, 31);
|
||||
|
||||
palette[lightmap[i * 256 + palIndex]] = lumR | (lumG << 5) | (lumB << 10);
|
||||
}
|
||||
}
|
||||
|
||||
void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_OFF alignment bytes
|
||||
tilesCount = *((int32*)(data + 4));
|
||||
// tilesCount = *((int32*)(data + 4));
|
||||
tiles = data + 8;
|
||||
|
||||
#define MDL_OFF 2
|
||||
@@ -189,13 +183,25 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader, added *_O
|
||||
meshData = data + 908172 + 4;
|
||||
meshOffsets = (int32*)(data + 975724 + 4);
|
||||
|
||||
animsCount = *((int32*)(data + 976596));
|
||||
// animsCount = *((int32*)(data + 976596));
|
||||
anims = (Anim*)(data + 976596 + 4);
|
||||
ASSERT((intptr_t)anims % 4 == 0);
|
||||
|
||||
framesCount = *((int32*)(data + 992990));
|
||||
frames = (uint16*)(data + 992990 + 4);
|
||||
ASSERT((intptr_t)frames % 2 == 0);
|
||||
// animStatesCount = *((int32*)(data + 985464));
|
||||
animStates = (AnimState*)(data + 985464 + 4);
|
||||
ASSERT((intptr_t)animStates % 2 == 0);
|
||||
|
||||
// animRangesCount = *((int32*)(data + 986872));
|
||||
animRanges = (AnimRange*)(data + 986872 + 4);
|
||||
ASSERT((intptr_t)animRanges % 2 == 0);
|
||||
|
||||
// animCommandsCount = *((int32*)(data + 988868));
|
||||
animCommands = (int16*)(data + 988868 + 4);
|
||||
ASSERT((intptr_t)animCommands % 2 == 0);
|
||||
|
||||
// animFramesCount = *((int32*)(data + 992990));
|
||||
animFrames = (uint16*)(data + 992990 + 4);
|
||||
ASSERT((intptr_t)animFrames % 2 == 0);
|
||||
|
||||
nodesPtr = (int32*)(data + 990318);
|
||||
|
||||
@@ -218,6 +224,18 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader, added *_O
|
||||
itemsCount = *((int32*)(data + 1319252 + MDL_OFF + ITM_OFF));
|
||||
const uint8* itemsPtr = (data + 1319252 + 4 + MDL_OFF + ITM_OFF);
|
||||
|
||||
soundMap = (uint16*)(data + 1329540 + MDL_OFF + ITM_OFF);
|
||||
|
||||
// soundInfosCount = *((int32*)(data + 1330052 + MDL_OFF + ITM_OFF));
|
||||
soundInfos = (SoundInfo*)(data + 1330052 + 4 + MDL_OFF + ITM_OFF);
|
||||
|
||||
// soundDataSize = *((int32*)(data + 1330624 + MDL_OFF + ITM_OFF));
|
||||
soundData = (uint8*)(data + 1330624 + 4 + MDL_OFF + ITM_OFF);
|
||||
|
||||
// soundOffsetsCount = *((int32*)(data + 2533294 + MDL_OFF + ITM_OFF));
|
||||
soundOffsets = (uint32*)(data + 2533294 + 4 + MDL_OFF + ITM_OFF);
|
||||
|
||||
memset(items, 0, sizeof(items));
|
||||
for (int32 i = 0; i < itemsCount; i++) {
|
||||
memcpy(items + i, itemsPtr, FILE_ITEM_SIZE);
|
||||
itemsPtr += FILE_ITEM_SIZE;
|
||||
@@ -235,12 +253,21 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader, added *_O
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
#if defined(_WIN32) || defined(__GBA__)
|
||||
// grayscale palette
|
||||
//uint8 c = ((p[0] + p[1] + p[2]) / 3) >> 1;
|
||||
//palette[i] = c | (c << 5) | (c << 10);
|
||||
|
||||
palette[i] = (p[0] >> 1) | ((p[1] >> 1) << 5) | ((p[2] >> 1) << 10);
|
||||
#elif defined(__TNS__)
|
||||
palette[i] = (p[2] >> 1) | ((p[1] >> 1) << 5) | ((p[0] >> 1) << 10);
|
||||
#endif
|
||||
p += 3;
|
||||
}
|
||||
palette[0] = 0; // black or transparent
|
||||
|
||||
// TODO preprocess fix Laras palette
|
||||
fixLightmap(6); // boots
|
||||
fixLightmap(14); // skin
|
||||
|
||||
// prepare rooms
|
||||
uint8* ptr = (uint8*)roomsPtr;
|
||||
@@ -255,7 +282,6 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader, added *_O
|
||||
uint8* skipPtr = ptr + dataSize * 2;
|
||||
|
||||
Room &desc = rooms[roomIndex];
|
||||
roomReset(roomIndex);
|
||||
|
||||
desc.firstItem = NO_ITEM;
|
||||
|
||||
@@ -327,485 +353,321 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader, added *_O
|
||||
{
|
||||
staticMeshesMap[staticMeshes[i].id] = i;
|
||||
}
|
||||
|
||||
// prepare items
|
||||
for (int32 i = 0; i < itemsCount; i++) {
|
||||
Item* item = items + i;
|
||||
|
||||
item->angleX = 0;
|
||||
item->angleZ = 0;
|
||||
item->vSpeed = 0;
|
||||
item->hSpeed = 0;
|
||||
item->nextItem = NO_ITEM;
|
||||
item->nextActive = NO_ITEM;
|
||||
item->animIndex = models[modelsMap[item->type]].animIndex;
|
||||
item->frameIndex = anims[item->animIndex].frameBegin;
|
||||
item->state = anims[item->animIndex].state;
|
||||
item->nextState = item->state;
|
||||
item->goalState = item->state;
|
||||
item->intensity = 4096; // TODO lighting
|
||||
|
||||
item->flags.gravity = 0;
|
||||
|
||||
if (item->room > -1) {
|
||||
roomItemAdd(item->room, i);
|
||||
}
|
||||
|
||||
if (item->type == ITEM_LARA) {
|
||||
activateItem(i);
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
if (item->type == ITEM_WOLF ||
|
||||
item->type == ITEM_BEAR ||
|
||||
item->type == ITEM_BAT ||
|
||||
item->type == ITEM_CRYSTAL)
|
||||
int32 getBridgeFloor(const Item* item, int32 x, int32 z)
|
||||
{
|
||||
activateItem(i);
|
||||
}
|
||||
if (item->type == ITEM_BRIDGE_1) {
|
||||
return item->pos.y;
|
||||
}
|
||||
|
||||
// prepare glyphs
|
||||
for (int32 i = 0; i < spritesSeqCount; i++) {
|
||||
if (spritesSeq[i].type == SEQ_GLYPH) {
|
||||
seqGlyphs = i;
|
||||
int32 h;
|
||||
if (item->angleY == ANGLE_0) {
|
||||
h = 1024 - x;
|
||||
} else if (item->angleY == -ANGLE_180) {
|
||||
h = x;
|
||||
} else if (item->angleY == ANGLE_90) {
|
||||
h = z;
|
||||
} else {
|
||||
h = 1024 - z;
|
||||
}
|
||||
|
||||
h &= 1023;
|
||||
|
||||
return item->pos.y + ((item->type == ITEM_BRIDGE_2) ? (h >> 2) : (h >> 1));
|
||||
}
|
||||
|
||||
int32 getTrapDoorFloor(const Item* item, int32 x, int32 z)
|
||||
{
|
||||
int32 dx = (item->pos.x >> 10) - (x >> 10);
|
||||
int32 dz = (item->pos.z >> 10) - (z >> 10);
|
||||
|
||||
if (((dx == 0) && (dz == 0)) ||
|
||||
((dx == 0) && (dz == 1) && (item->angleY == ANGLE_0)) ||
|
||||
((dx == 0) && (dz == -1) && (item->angleY == -ANGLE_180)) ||
|
||||
((dx == 1) && (dz == 0) && (item->angleY == ANGLE_90)) ||
|
||||
((dx == -1) && (dz == 0) && (item->angleY == -ANGLE_90)))
|
||||
{
|
||||
return item->pos.y;
|
||||
}
|
||||
|
||||
return WALL;
|
||||
}
|
||||
|
||||
int32 getDrawBridgeFloor(const Item* item, int32 x, int32 z)
|
||||
{
|
||||
int32 dx = (item->pos.x >> 10) - (x >> 10);
|
||||
int32 dz = (item->pos.z >> 10) - (z >> 10);
|
||||
|
||||
if (((dx == 0) && ((dz == -1) || (dz == -2)) && (item->angleY == ANGLE_0)) ||
|
||||
((dx == 0) && ((dz == 1) || (dz == 2)) && (item->angleY == -ANGLE_180)) ||
|
||||
((dz == 0) && ((dx == -1) || (dz == -2)) && (item->angleY == ANGLE_90)) ||
|
||||
((dz == 0) && ((dx == 1) || (dz == 2)) && (item->angleY == -ANGLE_90)))
|
||||
{
|
||||
return item->pos.y;
|
||||
}
|
||||
|
||||
return WALL;
|
||||
}
|
||||
|
||||
void getItemFloorData(const Item* item, int32 x, int32 y, int32 z, int32* floor, int32* ceiling)
|
||||
{
|
||||
int32 h = WALL;
|
||||
|
||||
switch (item->type)
|
||||
{
|
||||
case ITEM_TRAP_FLOOR:
|
||||
{
|
||||
if (item->state == 0 || item->state == 1) {
|
||||
h = item->pos.y - 512;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
camera.init();
|
||||
camera.room = 0;
|
||||
}
|
||||
|
||||
void drawMesh(int16 meshIndex, uint16 intensity) {
|
||||
int32 offset = meshOffsets[meshIndex];
|
||||
const uint8* ptr = meshData + offset;
|
||||
|
||||
ptr += 2 * 5; // skip [cx, cy, cz, radius, flags]
|
||||
|
||||
int16 vCount = *(int16*)ptr; ptr += 2;
|
||||
const vec3s* vertices = (vec3s*)ptr;
|
||||
ptr += vCount * 3 * sizeof(int16);
|
||||
|
||||
int16 nCount = *(int16*)ptr; ptr += 2;
|
||||
//const int16* normals = (int16*)ptr;
|
||||
if (nCount > 0) { // normals
|
||||
ptr += nCount * 3 * sizeof(int16);
|
||||
} else { // intensity
|
||||
ptr += vCount * sizeof(int16);
|
||||
}
|
||||
|
||||
int16 rCount = *(int16*)ptr; ptr += 2;
|
||||
Quad* rFaces = (Quad*)ptr; ptr += rCount * sizeof(Quad);
|
||||
|
||||
int16 tCount = *(int16*)ptr; ptr += 2;
|
||||
Triangle* tFaces = (Triangle*)ptr; ptr += tCount * sizeof(Triangle);
|
||||
|
||||
int16 crCount = *(int16*)ptr; ptr += 2;
|
||||
Quad* crFaces = (Quad*)ptr; ptr += crCount * sizeof(Quad);
|
||||
|
||||
int16 ctCount = *(int16*)ptr; ptr += 2;
|
||||
Triangle* ctFaces = (Triangle*)ptr; ptr += ctCount * sizeof(Triangle);
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
PROFILE_START();
|
||||
transformMesh(vertices, vCount, intensity);
|
||||
PROFILE_STOP(dbg_transform);
|
||||
|
||||
PROFILE_START();
|
||||
faceAddMesh(rFaces, crFaces, tFaces, ctFaces, rCount, crCount, tCount, ctCount, startVertex);
|
||||
PROFILE_STOP(dbg_poly);
|
||||
}
|
||||
|
||||
Frame* getFrame(const Item* item, const Model* model)
|
||||
case ITEM_DRAWBRIDGE:
|
||||
{
|
||||
const Anim* anim = anims + item->animIndex;
|
||||
|
||||
int32 frameSize = sizeof(Frame) / 2 + model->mCount * 2;
|
||||
int32 frameIndex = (item->frameIndex - anim->frameBegin) / anim->frameRate;//* FixedInvU(anim->frameRate) >> 16;
|
||||
|
||||
return (Frame*)(frames + anim->frameOffset / 2 + frameIndex * frameSize);
|
||||
if (item->state == 1) {
|
||||
h = getDrawBridgeFloor(item, x, z);
|
||||
}
|
||||
|
||||
void drawItem(const Item* item) {
|
||||
int32 modelIndex = modelsMap[item->type];
|
||||
if (modelIndex == NO_MODEL) {
|
||||
return; // TODO sprite items
|
||||
break;
|
||||
}
|
||||
|
||||
const Model* model = models + modelIndex;
|
||||
|
||||
if (model->mCount == 1 && meshOffsets[model->mStart] == 0) return;
|
||||
|
||||
Frame* frame = getFrame(item, model);
|
||||
uint16* frameAngles = frame->angles + 1;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(item->pos.x, item->pos.y, item->pos.z);
|
||||
matrixRotateYXZ(item->angleX, item->angleY, item->angleZ);
|
||||
|
||||
if (boxIsVisible(&frame->box)) {
|
||||
// non-aligned access (TODO)
|
||||
uint32 nodeIndex;
|
||||
memcpy(&nodeIndex, &model->nodeIndex, sizeof(nodeIndex));
|
||||
Node nodes[32];
|
||||
memcpy(nodes, nodesPtr + nodeIndex, (model->mCount - 1) * sizeof(Node));
|
||||
|
||||
const Node* node = nodes;
|
||||
|
||||
matrixFrame(frame->pos.x, frame->pos.y, frame->pos.z, frameAngles);
|
||||
|
||||
drawMesh(model->mStart, item->intensity);
|
||||
|
||||
for (int32 i = 1; i < model->mCount; i++)
|
||||
case ITEM_BRIDGE_1:
|
||||
case ITEM_BRIDGE_2:
|
||||
case ITEM_BRIDGE_3:
|
||||
{
|
||||
if (node->flags & 1) matrixPop();
|
||||
if (node->flags & 2) matrixPush();
|
||||
|
||||
frameAngles += 2;
|
||||
matrixFrame(node->pos.x, node->pos.y, node->pos.z, frameAngles);
|
||||
|
||||
drawMesh(model->mStart + i, item->intensity);
|
||||
|
||||
node++;
|
||||
h = getBridgeFloor(item, x, z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
void drawNumber(int32 number, int32 x, int32 y) {
|
||||
const int32 widths[] = { 12, 8, 10, 10, 10, 10, 10, 10, 10, 10 };
|
||||
|
||||
const Sprite *glyphSprites = sprites + spritesSeq[seqGlyphs].sStart;
|
||||
|
||||
while (number > 0) {
|
||||
x -= widths[number % 10];
|
||||
drawGlyph(glyphSprites + 52 + (number % 10), x, y);
|
||||
number /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void drawRoom(int32 roomIndex) {
|
||||
const Room* room = rooms + roomIndex;
|
||||
|
||||
clip = room->clip;
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(room->x, 0, room->z);
|
||||
|
||||
PROFILE_START();
|
||||
transformRoom(room->vertices, room->vCount);
|
||||
PROFILE_STOP(dbg_transform);
|
||||
|
||||
matrixPop();
|
||||
|
||||
PROFILE_START();
|
||||
faceAddRoom(room->quads, room->qCount, room->triangles, room->tCount, startVertex);
|
||||
|
||||
for (int32 i = 0; i < room->mCount; i++)
|
||||
case ITEM_TRAP_DOOR_1:
|
||||
case ITEM_TRAP_DOOR_2:
|
||||
{
|
||||
const RoomInfo::Mesh* mesh = room->meshes + i;
|
||||
const StaticMesh* staticMesh = staticMeshes + staticMeshesMap[mesh->staticMeshId];
|
||||
|
||||
if (!(staticMesh->flags & 2)) continue; // invisible
|
||||
|
||||
// TODO align RoomInfo::Mesh (room relative int16?)
|
||||
vec3i pos;
|
||||
memcpy(&pos, &mesh->pos, sizeof(pos));
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(pos.x, pos.y, pos.z);
|
||||
matrixRotateY(mesh->rotation);
|
||||
|
||||
if (boxIsVisible(&staticMesh->vbox)) {
|
||||
drawMesh(staticMesh->meshIndex, mesh->intensity);
|
||||
if (item->state == 0) {
|
||||
h = getTrapDoorFloor(item, x, z);
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
int32 itemIndex = room->firstItem;
|
||||
while (itemIndex != NO_ITEM)
|
||||
if ((floor && (h >= *floor)) || (ceiling && (h <= *ceiling)))
|
||||
{
|
||||
drawItem(items + itemIndex);
|
||||
itemIndex = items[itemIndex].nextItem;
|
||||
h = WALL;
|
||||
}
|
||||
PROFILE_STOP(dbg_poly);
|
||||
|
||||
roomReset(roomIndex);
|
||||
|
||||
flush();
|
||||
}
|
||||
default : return;
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* getSector(int32 roomIndex, int32 x, int32 z) {
|
||||
if (floor && (y <= h))
|
||||
{
|
||||
*floor = h;
|
||||
}
|
||||
|
||||
if (ceiling && (y > h))
|
||||
{
|
||||
*ceiling = h + 256;
|
||||
}
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* getSector(int32 roomIndex, int32 x, int32 z)
|
||||
{
|
||||
Room &room = rooms[roomIndex];
|
||||
|
||||
int32 sx = clamp((x - room.x) >> 10, 0, room.xSectors - 1);
|
||||
int32 sz = clamp((z - room.z) >> 10, 0, room.zSectors - 1);
|
||||
int32 sx = X_CLAMP((x - room.x) >> 10, 0, room.xSectors - 1);
|
||||
int32 sz = X_CLAMP((z - room.z) >> 10, 0, room.zSectors - 1);
|
||||
|
||||
return room.sectors + sx * room.zSectors + sz;
|
||||
}
|
||||
|
||||
int32 getRoomIndex(int32 roomIndex, const vec3i* pos) {
|
||||
const RoomInfo::Sector *sector = getSector(roomIndex, pos->x, pos->z);
|
||||
|
||||
if (sector->floorIndex) {
|
||||
const uint16 *data = floors + sector->floorIndex;
|
||||
int16 type = *data++;
|
||||
|
||||
if (type == FLOOR_TYPE_FLOOR) {
|
||||
data++;
|
||||
type = *data++;
|
||||
const RoomInfo::Sector* getSectorBelow(const RoomInfo::Sector* sector, int32 x, int32 z)
|
||||
{
|
||||
while (sector->roomBelow != NO_ROOM)
|
||||
{
|
||||
Room* room = rooms + sector->roomBelow;
|
||||
int32 sx = (x - room->x) >> 10;
|
||||
int32 sz = (z - room->z) >> 10;
|
||||
sector = room->sectors + sx * room->zSectors + sz;
|
||||
}
|
||||
return sector;
|
||||
}
|
||||
|
||||
if (type == FLOOR_TYPE_CEILING) {
|
||||
data++;
|
||||
type = *data++;
|
||||
const RoomInfo::Sector* getSectorAbove(const RoomInfo::Sector* sector, int32 x, int32 z)
|
||||
{
|
||||
while (sector->roomAbove != NO_ROOM)
|
||||
{
|
||||
Room* room = rooms + sector->roomAbove;
|
||||
int32 sx = (x - room->x) >> 10;
|
||||
int32 sz = (z - room->z) >> 10;
|
||||
sector = room->sectors + sx * room->zSectors + sz;
|
||||
}
|
||||
return sector;
|
||||
}
|
||||
|
||||
if ((type & 0xFF) == FLOOR_TYPE_PORTAL) {
|
||||
roomIndex = *data;
|
||||
}
|
||||
int32 getRoomIndex(int32 roomIndex, int32 x, int32 y, int32 z)
|
||||
{
|
||||
const RoomInfo::Sector* sector = getSector(roomIndex, x, z);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!sector->floorIndex)
|
||||
break;
|
||||
|
||||
// always in this order
|
||||
// - floor
|
||||
// - ceiling
|
||||
// - portal
|
||||
// - other
|
||||
|
||||
FloorData* fd = (FloorData*)(floors + sector->floorIndex);
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor
|
||||
{
|
||||
if (cmd.end) break;
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
while (sector->roomAbove != NO_ROOM && pos->y < (sector->ceiling << 8)) {
|
||||
if (cmd.func == FLOOR_TYPE_CEILING) // skip ceiling
|
||||
{
|
||||
if (cmd.end) break;
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
if (cmd.func != FLOOR_TYPE_PORTAL) // no portal
|
||||
break;
|
||||
|
||||
roomIndex = fd->value;
|
||||
sector = getSector(roomIndex, x, z);
|
||||
};
|
||||
|
||||
while (sector->roomAbove != NO_ROOM && y < (sector->ceiling << 8))
|
||||
{
|
||||
roomIndex = sector->roomAbove;
|
||||
sector = getSector(roomIndex, pos->x, pos->z);
|
||||
sector = getSector(roomIndex, x, z);
|
||||
}
|
||||
|
||||
while (sector->roomBelow != 0xFF && pos->y >= (sector->floor << 8)) {
|
||||
while (sector->roomBelow != NO_ROOM && y >= (sector->floor << 8))
|
||||
{
|
||||
roomIndex = sector->roomBelow;
|
||||
sector = getSector(roomIndex, pos->x, pos->z);
|
||||
sector = getSector(roomIndex, x, z);
|
||||
}
|
||||
|
||||
return roomIndex;
|
||||
}
|
||||
|
||||
bool checkPortal(int32 roomIndex, const RoomInfo::Portal* portal) {
|
||||
Room &room = rooms[roomIndex];
|
||||
|
||||
vec3i d;
|
||||
d.x = portal->v[0].x - camera.pos.x + room.x;
|
||||
d.y = portal->v[0].y - camera.pos.y;
|
||||
d.z = portal->v[0].z - camera.pos.z + room.z;
|
||||
|
||||
if (DP33(portal->n, d) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 x0 = room.clip.x1;
|
||||
int32 y0 = room.clip.y1;
|
||||
int32 x1 = room.clip.x0;
|
||||
int32 y1 = room.clip.y0;
|
||||
|
||||
int32 znear = 0, zfar = 0;
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
vec3i pv[4];
|
||||
|
||||
for (int32 i = 0; i < 4; i++) {
|
||||
const vec3s &v = portal->v[i];
|
||||
|
||||
int32 x = DP43(m[0], v);
|
||||
int32 y = DP43(m[1], v);
|
||||
int32 z = DP43(m[2], v);
|
||||
|
||||
pv[i].x = x;
|
||||
pv[i].y = y;
|
||||
pv[i].z = z;
|
||||
|
||||
if (z <= VIEW_MIN_F) {
|
||||
znear++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z >= VIEW_MAX_F) {
|
||||
zfar++;
|
||||
}
|
||||
|
||||
if (z != 0) {
|
||||
z >>= FOV_SHIFT;
|
||||
x = (x / z) + (FRAME_WIDTH / 2);
|
||||
y = (y / z) + (FRAME_HEIGHT / 2);
|
||||
} else {
|
||||
x = (x > 0) ? clip.x1 : clip.x0;
|
||||
y = (y > 0) ? clip.y1 : clip.y0;
|
||||
}
|
||||
|
||||
if (x < x0) x0 = x;
|
||||
if (x > x1) x1 = x;
|
||||
if (y < y0) y0 = y;
|
||||
if (y > y1) y1 = y;
|
||||
}
|
||||
|
||||
if (znear == 4 || zfar == 4) return false;
|
||||
|
||||
if (znear) {
|
||||
vec3i *a = pv;
|
||||
vec3i *b = pv + 3;
|
||||
for (int32 i = 0; i < 4; i++) {
|
||||
if ((a->z < 0) ^ (b->z < 0)) {
|
||||
if (a->x < 0 && b->x < 0) {
|
||||
x0 = 0;
|
||||
} else if (a->x > 0 && b->x > 0) {
|
||||
x1 = FRAME_WIDTH;
|
||||
} else {
|
||||
x0 = 0;
|
||||
x1 = FRAME_WIDTH;
|
||||
}
|
||||
|
||||
if (a->y < 0 && b->y < 0) {
|
||||
y0 = 0;
|
||||
} else if (a->y > 0 && b->y > 0) {
|
||||
y1 = FRAME_HEIGHT;
|
||||
} else {
|
||||
y0 = 0;
|
||||
y1 = FRAME_HEIGHT;
|
||||
}
|
||||
}
|
||||
b = a;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
if (x0 < room.clip.x0) x0 = room.clip.x0;
|
||||
if (x1 > room.clip.x1) x1 = room.clip.x1;
|
||||
if (y0 < room.clip.y0) y0 = room.clip.y0;
|
||||
if (y1 > room.clip.y1) y1 = room.clip.y1;
|
||||
|
||||
if (x0 >= x1 || y0 >= y1) return false;
|
||||
|
||||
Room &nextRoom = rooms[portal->roomIndex];
|
||||
|
||||
if (x0 < nextRoom.clip.x0) nextRoom.clip.x0 = x0;
|
||||
if (x1 > nextRoom.clip.x1) nextRoom.clip.x1 = x1;
|
||||
if (y0 < nextRoom.clip.y0) nextRoom.clip.y0 = y0;
|
||||
if (y1 > nextRoom.clip.y1) nextRoom.clip.y1 = y1;
|
||||
|
||||
if (!nextRoom.visible) {
|
||||
nextRoom.visible = true;
|
||||
visRooms[visRoomsCount++] = portal->roomIndex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getVisibleRooms(int32 roomIndex)
|
||||
void getTriggerFloorData(const RoomInfo::Sector* sector, int32 x, int32 y, int32 z, int32* floor, int32* ceiling)
|
||||
{
|
||||
const Room* room = rooms + roomIndex;
|
||||
if (!sector->floorIndex)
|
||||
return;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(room->x, 0, room->z);
|
||||
FloorData::Command cmd;
|
||||
FloorData* fd = (FloorData*)(floors + sector->floorIndex);
|
||||
|
||||
for (int32 i = 0; i < room->pCount; i++)
|
||||
do {
|
||||
cmd = (fd++)->cmd;
|
||||
|
||||
switch (cmd.func)
|
||||
{
|
||||
const RoomInfo::Portal* portal = room->portals + i;
|
||||
|
||||
if (checkPortal(roomIndex, portal))
|
||||
case FLOOR_TYPE_PORTAL:
|
||||
case FLOOR_TYPE_FLOOR:
|
||||
case FLOOR_TYPE_CEILING:
|
||||
{
|
||||
getVisibleRooms(portal->roomIndex);
|
||||
}
|
||||
fd++;
|
||||
break;
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
void drawRooms()
|
||||
case FLOOR_TYPE_TRIGGER:
|
||||
{
|
||||
rooms[camera.room].clip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||
visRoomsCount = 0;
|
||||
visRooms[visRoomsCount++] = camera.room;
|
||||
fd++;
|
||||
FloorData::TriggerCommand trigger;
|
||||
|
||||
getVisibleRooms(camera.room);
|
||||
do {
|
||||
trigger = (fd++)->triggerCmd;
|
||||
|
||||
while (visRoomsCount--)
|
||||
if (trigger.action == TRIGGER_ACTION_ACTIVATE)
|
||||
{
|
||||
drawRoom(visRooms[visRoomsCount]);
|
||||
}
|
||||
getItemFloorData(items + trigger.args, x, y, z, floor, ceiling);
|
||||
}
|
||||
|
||||
void move(Item* item, const Anim* anim)
|
||||
if (trigger.action == TRIGGER_ACTION_CAMERA_SWITCH)
|
||||
{
|
||||
int32 speed = anim->speed;
|
||||
trigger = (fd++)->triggerCmd; // skip camera index
|
||||
}
|
||||
|
||||
if (item->flags.gravity)
|
||||
} while (!trigger.end);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOOR_TYPE_LAVA:
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!cmd.end);
|
||||
}
|
||||
|
||||
FloorData floorSlant;
|
||||
|
||||
int32 getFloor(const RoomInfo::Sector* sector, int32 x, int32 y, int32 z)
|
||||
{
|
||||
speed += anim->accel * (item->frameIndex - anim->frameBegin - 1);
|
||||
item->hSpeed -= speed >> 16;
|
||||
speed += anim->accel;
|
||||
item->hSpeed += speed >> 16;
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(sector, x, z);
|
||||
|
||||
item->vSpeed += (item->vSpeed < 128) ? GRAVITY : 1;
|
||||
int32 floor = lowerSector->floor << 8;
|
||||
|
||||
item->pos.y += item->vSpeed;
|
||||
} else {
|
||||
speed += anim->accel * (item->frameIndex - anim->frameBegin);
|
||||
floorSlant.value = 0;
|
||||
|
||||
item->hSpeed = speed >> 16;
|
||||
}
|
||||
|
||||
item->pos.x += phd_sin(item->angleY) * item->hSpeed >> FIXED_SHIFT;
|
||||
item->pos.z += phd_cos(item->angleY) * item->hSpeed >> FIXED_SHIFT;
|
||||
}
|
||||
|
||||
void animChange(Item* item, const Anim* anim)
|
||||
if (lowerSector->floorIndex)
|
||||
{
|
||||
if (!anim->scCount) return;
|
||||
// check state change
|
||||
}
|
||||
FloorData* fd = (FloorData*)(floors + lowerSector->floorIndex);
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
void animCommand(bool fx, Item* item, const Anim* anim)
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // found floor
|
||||
{
|
||||
if (!anim->acCount) return;
|
||||
// check animation command
|
||||
floorSlant = *fd;
|
||||
int32 sx = fd->slantX;
|
||||
int32 sz = fd->slantZ;
|
||||
int32 dx = x & 1023;
|
||||
int32 dz = z & 1023;
|
||||
floor -= sx * (sx < 0 ? dx : (dx - 1023)) >> 2;
|
||||
floor -= sz * (sz < 0 ? dz : (dz - 1023)) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
const Anim* animSet(Item* item, int32 animIndex, int32 frameIndex)
|
||||
getTriggerFloorData(lowerSector, x, y, z, &floor, NULL);
|
||||
|
||||
return floor;
|
||||
}
|
||||
|
||||
int32 getCeiling(const RoomInfo::Sector* sector, int32 x, int32 y, int32 z)
|
||||
{
|
||||
item->animIndex = animIndex;
|
||||
item->frameIndex = frameIndex;
|
||||
item->state = anims[animIndex].state;
|
||||
const RoomInfo::Sector* upperSector = getSectorAbove(sector, x, z);
|
||||
|
||||
return anims + animIndex;
|
||||
}
|
||||
int32 ceiling = upperSector->ceiling << 8;
|
||||
|
||||
void animUpdate(Item* item)
|
||||
if (upperSector->floorIndex)
|
||||
{
|
||||
const Anim* anim = anims + item->animIndex;
|
||||
FloorData* fd = (FloorData*)(floors + upperSector->floorIndex);
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
item->frameIndex++;
|
||||
|
||||
animChange(item, anim);
|
||||
|
||||
if (item->frameIndex > anim->frameEnd)
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor
|
||||
{
|
||||
animCommand(false, item, anim);
|
||||
anim = animSet(item, anim->nextAnimIndex, anim->nextFrameIndex);
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
animCommand(true, item, anim);
|
||||
|
||||
//move(item, anim);
|
||||
}
|
||||
|
||||
void updateItems()
|
||||
if (cmd.func == FLOOR_TYPE_CEILING) // found ceiling
|
||||
{
|
||||
int32 itemIndex = firstActive;
|
||||
while (itemIndex != NO_ITEM)
|
||||
{
|
||||
Item* item = items + itemIndex;
|
||||
|
||||
if (modelsMap[item->type] != NO_MODEL) {
|
||||
animUpdate(item);
|
||||
int32 sx = fd->slantX;
|
||||
int32 sz = fd->slantZ;
|
||||
int32 dx = x & 1023;
|
||||
int32 dz = z & 1023;
|
||||
ceiling -= sx * (sx < 0 ? (dx - 1023) : dx) >> 2;
|
||||
ceiling += sz * (sz < 0 ? dz : (dz - 1023)) >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
itemIndex = item->nextActive;
|
||||
}
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(sector, x, z);
|
||||
|
||||
getTriggerFloorData(lowerSector, x, y, z, NULL, &ceiling);
|
||||
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,27 +1,28 @@
|
||||
#include "common.h"
|
||||
#include "level.h"
|
||||
#include "camera.h"
|
||||
#if defined(_WIN32)
|
||||
void* LEVEL1_PHD;
|
||||
#elif defined(__GBA__)
|
||||
#include "LEVEL1_PHD.h"
|
||||
#elif defined(__TNS__)
|
||||
void* LEVEL1_PHD;
|
||||
#endif
|
||||
|
||||
#include "game.h"
|
||||
|
||||
Game game;
|
||||
|
||||
#if defined(_WIN32)
|
||||
uint8* LEVEL1_PHD;
|
||||
uint32 SCREEN[FRAME_WIDTH * FRAME_HEIGHT];
|
||||
|
||||
uint32 SCREEN[WIDTH * HEIGHT];
|
||||
|
||||
extern uint16 fb[WIDTH * HEIGHT];
|
||||
HWND hWnd;
|
||||
|
||||
LARGE_INTEGER g_timer;
|
||||
LARGE_INTEGER g_current;
|
||||
|
||||
#define WND_SCALE 4
|
||||
#define WND_WIDTH 240*4
|
||||
#define WND_HEIGHT 160*4
|
||||
#elif defined(__GBA__)
|
||||
#include "LEVEL1_PHD.h"
|
||||
|
||||
extern uint32 fb;
|
||||
//
|
||||
#elif defined(__TNS__)
|
||||
uint8* LEVEL1_PHD;
|
||||
|
||||
extern uint16 fb[WIDTH * HEIGHT];
|
||||
|
||||
unsigned int osTime;
|
||||
volatile unsigned int *timerBUS;
|
||||
volatile unsigned int *timerCLK;
|
||||
@@ -78,8 +79,6 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
bool keys[IK_MAX] = {};
|
||||
|
||||
int32 fps;
|
||||
int32 frameIndex = 0;
|
||||
int32 fpsCounter = 0;
|
||||
@@ -87,188 +86,146 @@ int32 fpsCounter = 0;
|
||||
#ifdef PROFILE
|
||||
uint32 dbg_transform;
|
||||
uint32 dbg_poly;
|
||||
uint32 dbg_sort;
|
||||
uint32 dbg_flush;
|
||||
uint32 dbg_vert_count;
|
||||
uint32 dbg_poly_count;
|
||||
#endif
|
||||
|
||||
void update(int32 frames) {
|
||||
for (int32 i = 0; i < frames; i++) {
|
||||
updateItems();
|
||||
camera.update();
|
||||
EWRAM_DATA ALIGN16 uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
||||
uint32 curSoundBuffer = 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HWAVEOUT waveOut;
|
||||
WAVEFORMATEX waveFmt = { WAVE_FORMAT_PCM, 1, SND_OUTPUT_FREQ, SND_OUTPUT_FREQ, 1, 8, sizeof(waveFmt) };
|
||||
WAVEHDR waveBuf[2];
|
||||
|
||||
void soundInit() {
|
||||
sound.init();
|
||||
|
||||
if (waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, (INT_PTR)hWnd, 0, CALLBACK_WINDOW) != MMSYSERR_NOERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&waveBuf, 0, sizeof(waveBuf));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
WAVEHDR *waveHdr = waveBuf + i;
|
||||
waveHdr->dwBufferLength = SND_SAMPLES;
|
||||
waveHdr->lpData = (LPSTR)(soundBuffer + i * SND_SAMPLES);
|
||||
waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex);
|
||||
void soundFill() {
|
||||
WAVEHDR *waveHdr = waveBuf + curSoundBuffer;
|
||||
waveOutUnprepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
sound.fill((uint8*)waveHdr->lpData, SND_SAMPLES);
|
||||
waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
curSoundBuffer ^= 1;
|
||||
}
|
||||
#elif defined(__GBA__)
|
||||
void soundInit()
|
||||
{
|
||||
sound.init();
|
||||
|
||||
extern Vertex gVertices[MAX_VERTICES];
|
||||
|
||||
INLINE int32 classify(const Vertex* v) {
|
||||
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);
|
||||
REG_SOUNDCNT_X = SSTAT_ENABLE;
|
||||
REG_SOUNDCNT_H = SDS_ATMR0 | SDS_A100 | SDS_AL | SDS_AR | SDS_ARESET;
|
||||
REG_TM0D = 65536 - (16777216 / SND_OUTPUT_FREQ);
|
||||
REG_TM0CNT = TM_ENABLE;
|
||||
REG_DMA1DAD = (u32)®_FIFO_A;
|
||||
}
|
||||
|
||||
void drawTest() {
|
||||
static Rect testClip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||
static int32 testTile = 707; // 712
|
||||
|
||||
#ifdef _WIN32
|
||||
Sleep(16);
|
||||
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
|
||||
if (GetAsyncKeyState(VK_LEFT)) dx--;
|
||||
if (GetAsyncKeyState(VK_RIGHT)) dx++;
|
||||
if (GetAsyncKeyState(VK_UP)) dy--;
|
||||
if (GetAsyncKeyState(VK_DOWN)) dy++;
|
||||
|
||||
if (GetAsyncKeyState('T')) {
|
||||
testClip.x0 += dx;
|
||||
testClip.y0 += dy;
|
||||
void soundFill()
|
||||
{
|
||||
if (curSoundBuffer == 1) {
|
||||
REG_DMA1CNT = 0;
|
||||
REG_DMA1SAD = (u32)soundBuffer;
|
||||
REG_DMA1CNT = DMA_DST_FIXED | DMA_REPEAT | DMA_16 | DMA_AT_FIFO | DMA_ENABLE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState('B')) {
|
||||
testClip.x1 += dx;
|
||||
testClip.y1 += dy;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState('U')) {
|
||||
testTile += dx;
|
||||
if (testTile < 0) testTile = 0;
|
||||
if (testTile >= texturesCount) testTile = texturesCount - 1;
|
||||
sound.fill(soundBuffer + curSoundBuffer * SND_SAMPLES, SND_SAMPLES);
|
||||
curSoundBuffer ^= 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
clip = testClip;
|
||||
|
||||
gVertices[0].x = 50 + 50;
|
||||
gVertices[0].y = 50;
|
||||
|
||||
gVertices[1].x = FRAME_WIDTH - 50 - 50;
|
||||
gVertices[1].y = 50;
|
||||
|
||||
gVertices[2].x = FRAME_WIDTH - 50;
|
||||
gVertices[2].y = FRAME_HEIGHT - 50;
|
||||
|
||||
gVertices[3].x = 50;
|
||||
gVertices[3].y = FRAME_HEIGHT - 50;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
gVertices[i].z = 100;
|
||||
gVertices[i].g = 128;
|
||||
gVertices[i].clip = classify(gVertices + i);
|
||||
}
|
||||
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)
|
||||
fb[y * FRAME_WIDTH + x] = 255;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
flush();
|
||||
}
|
||||
#endif
|
||||
|
||||
void render() {
|
||||
clear();
|
||||
|
||||
#ifdef TEST
|
||||
#ifdef __GBA__
|
||||
VBlankIntrWait();
|
||||
#endif
|
||||
|
||||
int32 cycles = 0;
|
||||
PROFILE_START();
|
||||
drawTest();
|
||||
PROFILE_STOP(cycles);
|
||||
|
||||
drawNumber(cycles, FRAME_WIDTH, 32);
|
||||
#else
|
||||
#ifdef PROFILE
|
||||
dbg_transform = 0;
|
||||
dbg_poly = 0;
|
||||
dbg_sort = 0;
|
||||
dbg_flush = 0;
|
||||
dbg_vert_count = 0;
|
||||
dbg_poly_count = 0;
|
||||
#endif
|
||||
|
||||
drawRooms();
|
||||
|
||||
#ifdef PROFILE
|
||||
drawNumber(dbg_transform, FRAME_WIDTH, 32);
|
||||
drawNumber(dbg_poly, FRAME_WIDTH, 48);
|
||||
drawNumber(dbg_sort, FRAME_WIDTH, 64);
|
||||
drawNumber(dbg_flush, FRAME_WIDTH, 80);
|
||||
drawNumber(dbg_vert_count, FRAME_WIDTH, 96);
|
||||
drawNumber(dbg_poly_count, FRAME_WIDTH, 112);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
drawNumber(fps, FRAME_WIDTH, 16);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
HDC hDC;
|
||||
|
||||
void blit() {
|
||||
for (int i = 0; i < WIDTH * HEIGHT; i++) {
|
||||
#ifdef ROTATE90_MODE
|
||||
for (int i = 0; i < FRAME_WIDTH * FRAME_HEIGHT; i++) {
|
||||
int32 x = FRAME_HEIGHT - (i % FRAME_HEIGHT) - 1;
|
||||
int32 y = i / FRAME_HEIGHT;
|
||||
uint16 c = ((uint16*)fb)[x * FRAME_WIDTH + y];
|
||||
SCREEN[i] = (((c << 3) & 0xFF) << 16) | ((((c >> 5) << 3) & 0xFF) << 8) | ((c >> 10 << 3) & 0xFF) | 0xFF000000;
|
||||
}
|
||||
const BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), FRAME_HEIGHT, -FRAME_WIDTH, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
|
||||
StretchDIBits(hDC, 0, 0, WND_WIDTH, WND_HEIGHT, 0, 0, FRAME_HEIGHT, FRAME_WIDTH, SCREEN, &bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
#else
|
||||
for (int i = 0; i < FRAME_WIDTH * FRAME_HEIGHT; i++) {
|
||||
uint16 c = ((uint16*)fb)[i];
|
||||
SCREEN[i] = (((c << 3) & 0xFF) << 16) | ((((c >> 5) << 3) & 0xFF) << 8) | ((c >> 10 << 3) & 0xFF) | 0xFF000000;
|
||||
}
|
||||
|
||||
const BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), WIDTH, -HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
|
||||
StretchDIBits(hDC, 0, 0, 240 * WND_SCALE, 160 * WND_SCALE, 0, 0, WIDTH, HEIGHT, SCREEN, &bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
const BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), FRAME_WIDTH, -FRAME_HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
|
||||
StretchDIBits(hDC, 0, 0, WND_WIDTH, WND_HEIGHT, 0, 0, FRAME_WIDTH, FRAME_HEIGHT, SCREEN, &bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||
#endif
|
||||
}
|
||||
|
||||
LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (msg) {
|
||||
case WM_DESTROY :
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_KEYDOWN :
|
||||
case WM_KEYUP : {
|
||||
InputKey key = IK_MAX;
|
||||
case WM_KEYUP :
|
||||
{
|
||||
InputKey key = IK_NONE;
|
||||
switch (wParam) {
|
||||
case VK_UP : key = IK_UP; break;
|
||||
case VK_RIGHT : key = IK_RIGHT; break;
|
||||
case VK_DOWN : key = IK_DOWN; break;
|
||||
case VK_LEFT : key = IK_LEFT; break;
|
||||
case 'Z' : key = IK_A; break;
|
||||
case 'X' : key = IK_B; break;
|
||||
case 'Z' : key = IK_B; break;
|
||||
case 'X' : key = IK_A; break;
|
||||
case 'A' : key = IK_L; break;
|
||||
case 'S' : key = IK_R; break;
|
||||
case VK_RETURN : key = IK_START; break;
|
||||
case VK_SPACE : key = IK_SELECT; break;
|
||||
}
|
||||
if (key != IK_MAX) {
|
||||
keys[key] = msg != WM_KEYUP;
|
||||
|
||||
if (msg != WM_KEYUP) {
|
||||
keys |= key;
|
||||
} else {
|
||||
keys &= ~key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MM_WOM_DONE :
|
||||
{
|
||||
soundFill();
|
||||
break;
|
||||
}
|
||||
|
||||
default :
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__GBA__)
|
||||
|
||||
void vblank() {
|
||||
frameIndex++;
|
||||
soundFill();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
#if defined(_WIN32) || defined(__TNS__)
|
||||
{
|
||||
@@ -293,27 +250,26 @@ int main(void) {
|
||||
}
|
||||
#elif defined(__GBA__)
|
||||
// set low latency mode via WAITCNT register (thanks to GValiente)
|
||||
#define REG_WAITCNT_NV *(u16*)(REG_BASE + 0x0204)
|
||||
REG_WAITCNT_NV |= (0x0008 | 0x0010 | 0x4000);
|
||||
REG_WSCNT = WS_ROM0_N2 | WS_ROM0_S1 | WS_PREFETCH;
|
||||
#endif
|
||||
|
||||
initLUT();
|
||||
|
||||
readLevel(LEVEL1_PHD);
|
||||
game.init();
|
||||
|
||||
#if defined(_WIN32)
|
||||
RECT r = { 0, 0, 240 * WND_SCALE, 160 * WND_SCALE };
|
||||
RECT r = { 0, 0, WND_WIDTH, WND_HEIGHT };
|
||||
|
||||
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
|
||||
int wx = (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2;
|
||||
int wy = (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2;
|
||||
|
||||
HWND hWnd = CreateWindow("static", "OpenLara GBA", WS_OVERLAPPEDWINDOW, wx + r.left, wy + r.top, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0);
|
||||
hWnd = CreateWindow("static", "OpenLara GBA", WS_OVERLAPPEDWINDOW, wx + r.left, wy + r.top, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0);
|
||||
hDC = GetDC(hWnd);
|
||||
|
||||
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&wndProc);
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
|
||||
soundInit();
|
||||
|
||||
MSG msg;
|
||||
|
||||
int startTime = GetTickCount() - 33;
|
||||
@@ -326,51 +282,68 @@ int main(void) {
|
||||
} else {
|
||||
|
||||
int frame = (GetTickCount() - startTime) / 33;
|
||||
update(frame - lastFrame);
|
||||
game.update(frame - lastFrame);
|
||||
lastFrame = frame;
|
||||
|
||||
render();
|
||||
game.render();
|
||||
|
||||
blit();
|
||||
}
|
||||
} while (msg.message != WM_QUIT);
|
||||
|
||||
#elif defined(__GBA__)
|
||||
irqInit();
|
||||
irqSet(IRQ_VBLANK, vblank);
|
||||
irqEnable(IRQ_VBLANK);
|
||||
irq_init(NULL);
|
||||
irq_add(II_VBLANK, vblank);
|
||||
irq_enable(II_VBLANK);
|
||||
|
||||
uint16 mode = BG2_ON | BACKBUFFER;
|
||||
// Undocumented - Green Swap trick for fake-AA feature (thanks to GValiente)
|
||||
// https://mgba-emu.github.io/gbatek/#4000002h---undocumented---green-swap-rw
|
||||
//uint16 &GreenSwap = *(uint16*)0x4000002;
|
||||
//GreenSwap = 1;
|
||||
|
||||
mode |= MODE_5;
|
||||
soundInit();
|
||||
|
||||
uint16 mode = DCNT_MODE5 | DCNT_BG2 | DCNT_PAGE;
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
REG_BG2PA = 0;
|
||||
REG_BG2PB = (1 << 8);
|
||||
REG_BG2PC = -(1 << 7);
|
||||
REG_BG2PD = 0;
|
||||
REG_BG2Y = (FRAME_HEIGHT << 8) - 128;
|
||||
#else
|
||||
REG_BG2PA = 256 - 64 - 16 - 4 - 1;
|
||||
REG_BG2PD = 256 - 48 - 2;
|
||||
#endif
|
||||
|
||||
int32 lastFrameIndex = -1;
|
||||
|
||||
while (1) {
|
||||
//VBlankIntrWait();
|
||||
REG_DISPCNT = (mode ^= DCNT_PAGE);
|
||||
|
||||
SetMode(mode ^= BACKBUFFER);
|
||||
fb ^= 0xA000;
|
||||
|
||||
scanKeys();
|
||||
uint16 key = keysDown() | keysHeld();
|
||||
keys[IK_UP] = (key & KEY_UP);
|
||||
keys[IK_RIGHT] = (key & KEY_RIGHT);
|
||||
keys[IK_DOWN] = (key & KEY_DOWN);
|
||||
keys[IK_LEFT] = (key & KEY_LEFT);
|
||||
keys[IK_A] = (key & KEY_A);
|
||||
keys[IK_B] = (key & KEY_B);
|
||||
keys[IK_L] = (key & KEY_L);
|
||||
keys[IK_R] = (key & KEY_R);
|
||||
{ // input
|
||||
keys = 0;
|
||||
key_poll();
|
||||
if (key_is_down(KEY_UP)) keys |= IK_UP;
|
||||
if (key_is_down(KEY_RIGHT)) keys |= IK_RIGHT;
|
||||
if (key_is_down(KEY_DOWN)) keys |= IK_DOWN;
|
||||
if (key_is_down(KEY_LEFT)) keys |= IK_LEFT;
|
||||
if (key_is_down(KEY_A)) keys |= IK_A;
|
||||
if (key_is_down(KEY_B)) keys |= IK_B;
|
||||
if (key_is_down(KEY_L)) keys |= IK_L;
|
||||
if (key_is_down(KEY_R)) keys |= IK_R;
|
||||
if (key_is_down(KEY_START)) keys |= IK_START;
|
||||
if (key_is_down(KEY_SELECT)) keys |= IK_SELECT;
|
||||
}
|
||||
|
||||
int32 frame = frameIndex / 2;
|
||||
update(frame - lastFrameIndex);
|
||||
game.update(frame - lastFrameIndex);
|
||||
lastFrameIndex = frame;
|
||||
|
||||
render();
|
||||
game.render();
|
||||
|
||||
fpsCounter++;
|
||||
if (frameIndex >= 60) {
|
||||
@@ -400,6 +373,9 @@ int main(void) {
|
||||
|
||||
while (1)
|
||||
{
|
||||
{
|
||||
keys = 0;
|
||||
|
||||
inputUpdate();
|
||||
|
||||
if (keyDown(KEY_NSPIRE_ESC))
|
||||
@@ -412,27 +388,25 @@ int main(void) {
|
||||
float tx = float(touchReport.x) / float(touchInfo->width) * 2.0f - 1.0f;
|
||||
float ty = float(touchReport.y) / float(touchInfo->height) * 2.0f - 1.0f;
|
||||
|
||||
keys[IK_LEFT] = tx < -0.5f;
|
||||
keys[IK_RIGHT] = tx > 0.5f;
|
||||
keys[IK_UP] = ty > 0.5f;
|
||||
keys[IK_DOWN] = ty < -0.5f;
|
||||
} else {
|
||||
keys[IK_LEFT] =
|
||||
keys[IK_RIGHT] =
|
||||
keys[IK_UP] =
|
||||
keys[IK_DOWN] = false;
|
||||
if (tx < -0.5f) keys |= IK_LEFT;
|
||||
if (tx > 0.5f) keys |= IK_RIGHT;
|
||||
if (ty > 0.5f) keys |= IK_UP;
|
||||
if (ty < -0.5f) keys |= IK_DOWN];
|
||||
}
|
||||
|
||||
keys[IK_A] = keyDown(KEY_NSPIRE_2);
|
||||
keys[IK_B] = keyDown(KEY_NSPIRE_3);
|
||||
keys[IK_L] = keyDown(KEY_NSPIRE_7);
|
||||
keys[IK_R] = keyDown(KEY_NSPIRE_9);
|
||||
if (keyDown(KEY_NSPIRE_2)) keys |= IK_A;
|
||||
if (keyDown(KEY_NSPIRE_3)) keys |= IK_B;
|
||||
if (keyDown(KEY_NSPIRE_7)) keys |= IK_L;
|
||||
if (keyDown(KEY_NSPIRE_9)) keys |= IK_R;
|
||||
if (keyDown(KEY_NSPIRE_ENTER)) keys |= IK_START;
|
||||
if (keyDown(KEY_NSPIRE_SPACE)) keys |= IK_SELECT;
|
||||
}
|
||||
|
||||
int time = GetTickCount() - startTime;
|
||||
update((time - lastTime) / 16);
|
||||
game.update((time - lastTime) / 16);
|
||||
lastTime = time;
|
||||
|
||||
render();
|
||||
game.render();
|
||||
|
||||
lcd_blit(fb, SCR_320x240_8);
|
||||
//msleep(16);
|
||||
|
396
src/platform/gba/rasterizer.s
Normal file
396
src/platform/gba/rasterizer.s
Normal file
@@ -0,0 +1,396 @@
|
||||
.section .iwram
|
||||
.arm
|
||||
|
||||
// Thanks to Gericom
|
||||
|
||||
.macro LIGHTMAP_INDEX res, g
|
||||
and \res, \g, #0x1F00 // res = g & 0x1F00
|
||||
.endm
|
||||
|
||||
.macro LIGHTMAP_OFFSET res, index, lightmap
|
||||
add \res, \res, \lightmap // res += lightmap
|
||||
.endm
|
||||
|
||||
.macro FETCH_LIGHTMAP res, index, lightmap
|
||||
ldrb \res, [\lightmap, \index] // res = lightmap[index]
|
||||
.endm
|
||||
|
||||
.macro FETCH_TILE res, uv, tile
|
||||
and \res, \uv, #0xFF00
|
||||
orr \res, \res, \uv, lsr #24 // res = (uv & 0xFF00) | (uv >> 24)
|
||||
ldrb \res, [\tile, \res] // res = tile[res]
|
||||
.endm
|
||||
|
||||
.macro FETCH_PALETTE res, idx, pal
|
||||
mov \res, \idx, lsl #1
|
||||
ldrh \res, [\pal, \res] // res = pal[index]
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXEL buf, col, off
|
||||
strh \col, [\buf, #\off] // buf[off/2] = col
|
||||
.endm
|
||||
|
||||
.macro INC_PIXEL buf, col, off
|
||||
ldrh \col, [\buf, #\off]
|
||||
add \col, \col, #4
|
||||
strh \col, [\buf, #\off] // buf[off/2] = col
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXEL_A buf, col, off
|
||||
cmp \col, #0 // if (col != 0)
|
||||
strneh \col, [\buf, #\off] // buf[off/2] = col
|
||||
.endm
|
||||
|
||||
.macro CHECK_WIDTH width, stack
|
||||
subs \width, \width, #1
|
||||
ldmmifd sp!, \stack // if (--width < 0) return
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_F width, pix0, pix1, stack
|
||||
PUT_PIXEL r0, r2, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
PUT_PIXEL r0, r2, \pix1
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_G width, pix0, pix1, stack
|
||||
// r2 - g
|
||||
// r3 - dgdx
|
||||
// r11 - palette
|
||||
// lr - lightmap
|
||||
LIGHTMAP_INDEX r6, r2
|
||||
FETCH_LIGHTMAP r6, r6, lr
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
|
||||
PUT_PIXEL r0, r6, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
PUT_PIXEL r0, r6, \pix1
|
||||
|
||||
add r2, r2, r3 // g += dgdx
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_FT width, pix0, pix1, stack
|
||||
FETCH_TILE r6, r2, r12
|
||||
FETCH_LIGHTMAP r6, r6, lr
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL r0, r6, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
add r2, r2, r3 // t += dtdx
|
||||
|
||||
FETCH_TILE r6, r2, r12
|
||||
FETCH_LIGHTMAP r6, r6, lr
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL r0, r6, \pix1
|
||||
|
||||
add r2, r2, r3 // t += dtdx
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_GT width, pix0, pix1, stack
|
||||
LIGHTMAP_INDEX r7, r2
|
||||
LIGHTMAP_OFFSET r7, r7, lr
|
||||
|
||||
FETCH_TILE r6, r3, r12
|
||||
FETCH_LIGHTMAP r6, r6, r7
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL r0, r6, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
add r3, r3, r5 // t += dtdx
|
||||
|
||||
FETCH_TILE r6, r3, r12
|
||||
FETCH_LIGHTMAP r6, r6, r7
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL r0, r6, \pix1
|
||||
|
||||
add r3, r3, r5 // t += dtdx
|
||||
add r2, r2, r4 // g += dgdx
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_FTA width, pix0, pix1, stack
|
||||
FETCH_TILE r6, r2, r12
|
||||
FETCH_LIGHTMAP r6, r6, lr
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL_A r0, r6, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
add r2, r2, r3 // t += dtdx
|
||||
|
||||
FETCH_TILE r6, r2, r12
|
||||
FETCH_LIGHTMAP r6, r6, lr
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL_A r0, r6, \pix1
|
||||
|
||||
add r2, r2, r3 // t += dtdx
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_GTA width, pix0, pix1, stack
|
||||
LIGHTMAP_INDEX r7, r2
|
||||
LIGHTMAP_OFFSET r7, r7, lr
|
||||
|
||||
FETCH_TILE r6, r3, r12
|
||||
FETCH_LIGHTMAP r6, r6, r7
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL_A r0, r6, \pix0
|
||||
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
add r3, r3, r5 // t += dtdx
|
||||
|
||||
FETCH_TILE r6, r3, r12
|
||||
FETCH_LIGHTMAP r6, r6, r7
|
||||
FETCH_PALETTE r6, r6, r11
|
||||
PUT_PIXEL_A r0, r6, \pix1
|
||||
|
||||
add r3, r3, r5 // t += dtdx
|
||||
add r2, r2, r4 // g += dgdx
|
||||
.endm
|
||||
|
||||
.macro SCANLINE buf, width, func, stack
|
||||
sub \width, \width, #1 //--width
|
||||
1:
|
||||
\func \width, 0, 2, "\stack" // 0, 1
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
\func \width, 4, 6, "\stack" // 2, 3
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
\func \width, 8, 10, "\stack" // 4, 5
|
||||
CHECK_WIDTH \width, "\stack"
|
||||
|
||||
\func \width, 12, 14, "\stack" // 6, 7
|
||||
|
||||
add \buf, \buf, #16 // buf += 8px
|
||||
|
||||
subs \width, \width, #1
|
||||
bpl 1b
|
||||
ldmfd sp!, \stack
|
||||
.endm
|
||||
|
||||
.global scanlineF_asm
|
||||
scanlineF_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = color
|
||||
stmfd sp!, {lr}
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_F, "{pc}"
|
||||
|
||||
.global scanlineG_asm
|
||||
scanlineG_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = g
|
||||
// r3 = dgdx
|
||||
stmfd sp!, {r6,r11,lr}
|
||||
ldr lr,= ft_lightmap
|
||||
ldr r11,= palette
|
||||
ldr lr, [lr] // ft_lightmap = *ft_lightmap
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_G, "{r6,r11,pc}"
|
||||
|
||||
.global scanlineFT_asm
|
||||
scanlineFT_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = t
|
||||
// r3 = dtdx
|
||||
stmfd sp!, {r6,r7,r11,lr}
|
||||
ldr r11,= palette
|
||||
ldr r12,= tile
|
||||
ldr lr,= ft_lightmap
|
||||
ldr r12, [r12] // tile = *tile
|
||||
ldr lr, [lr] // ft_lightmap = *ft_lightmap
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_FT, "{r6,r7,r11,pc}"
|
||||
|
||||
.global scanlineGT_asm
|
||||
scanlineGT_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = g
|
||||
// r3 = t
|
||||
stmfd sp!, {r4,r5,r6,r7,r11,lr}
|
||||
stack_offset = 6 * 4
|
||||
dgdx = stack_offset + 0
|
||||
dtdx = stack_offset + 4
|
||||
ldr r4, [sp, #dgdx]
|
||||
ldr r5, [sp, #dtdx]
|
||||
ldr r11,= palette
|
||||
ldr r12,= tile
|
||||
ldr lr,= lightmap
|
||||
ldr r12, [r12]
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_GT, "{r4,r5,r6,r7,r11,pc}"
|
||||
|
||||
.global scanlineFTA_asm
|
||||
scanlineFTA_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = t
|
||||
// r3 = dtdx
|
||||
stmfd sp!, {r6,r7,r11,lr}
|
||||
ldr r11,= palette
|
||||
ldr r12,= tile
|
||||
ldr lr,= ft_lightmap
|
||||
ldr r12, [r12] // tile = *tile
|
||||
ldr lr, [lr] // ft_lightmap = *ft_lightmap
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_FTA, "{r6,r7,r11,pc}"
|
||||
|
||||
.global scanlineGTA_asm
|
||||
scanlineGTA_asm:
|
||||
// r0 = pixel
|
||||
// r1 = width
|
||||
// r2 = g
|
||||
// r3 = t
|
||||
stmfd sp!, {r4,r5,r6,r7,r11,lr}
|
||||
stack_offset = 6 * 4
|
||||
dgdx = stack_offset + 0
|
||||
dtdx = stack_offset + 4
|
||||
ldr r4, [sp, #dgdx]
|
||||
ldr r5, [sp, #dtdx]
|
||||
ldr r11,= palette
|
||||
ldr r12,= tile
|
||||
ldr lr,= lightmap
|
||||
ldr r12, [r12]
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_GTA, "{r4,r5,r6,r7,r11,pc}"
|
||||
|
||||
|
||||
|
||||
//------------ WORK IN PROGRESS ---------------
|
||||
|
||||
.macro CHECK_WIDTH_INNER width
|
||||
subs \width, \width, #1
|
||||
bmi 2f // if (--width < 0) return
|
||||
.endm
|
||||
|
||||
.macro PUT_PIXELS_F_INNER buf, width, color, pix0, pix1
|
||||
PUT_PIXEL \buf, \color, \pix0
|
||||
|
||||
CHECK_WIDTH_INNER \width
|
||||
|
||||
PUT_PIXEL \buf, \color, \pix1
|
||||
.endm
|
||||
|
||||
.macro SCANLINE_INNER buf, width, color, func
|
||||
sub \width, \width, #1 //--width
|
||||
3:
|
||||
\func \buf, \width, \color, 0, 2 // 0, 1
|
||||
CHECK_WIDTH_INNER \width
|
||||
|
||||
\func \buf, \width, \color, 4, 6 // 2, 3
|
||||
CHECK_WIDTH_INNER \width
|
||||
|
||||
\func \buf, \width, \color, 8, 10 // 4, 5
|
||||
CHECK_WIDTH_INNER \width
|
||||
|
||||
\func \buf, \width, \color, 12, 14 // 6, 7
|
||||
|
||||
add \buf, \buf, #16 // buf += 8px
|
||||
|
||||
subs \width, \width, #1
|
||||
bpl 3b
|
||||
.endm
|
||||
|
||||
|
||||
.global rasterizeF_inner_asm
|
||||
rasterizeF_inner_asm:
|
||||
// r0 = pixel
|
||||
// r1 = L edge
|
||||
// r2 = R edge
|
||||
// r3 = color
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,lr}
|
||||
// ip - h
|
||||
ldr ip, [r1] // ip = L.h
|
||||
ldr lr, [r2] // lr = R.h
|
||||
cmp lr, ip
|
||||
movlt r4, lr // if (R.h < L.h) h = R.h
|
||||
movge r4, ip // else h = L.h
|
||||
sub ip, ip, r4
|
||||
sub lr, lr, r4
|
||||
str ip, [r1] // L.h -= h
|
||||
str lr, [r2] // R.h -= h
|
||||
|
||||
ldr ip, [r1, #4] // ip = L.x
|
||||
ldr lr, [r2, #4] // lr = R.x
|
||||
ldr r7, [r1, #16] // r1 = L.dx
|
||||
ldr r8, [r2, #16] // r2 = R.dx
|
||||
|
||||
sub r4, r4, #1
|
||||
1:
|
||||
lsr r6, ip, #16 // r6 = x1 = (L.x >> 16)
|
||||
rsbs r5, r6, lr, lsr #16 // r5 = width = (R.x >> 16) - r6
|
||||
ble 2f // if (width <= 0) go next scanline
|
||||
|
||||
add r6, r0, r6, lsl #1 // r6 = pixel + x1
|
||||
|
||||
SCANLINE_INNER r6, r5, r3, PUT_PIXELS_F_INNER
|
||||
|
||||
2:
|
||||
add ip, ip, r7 // L.x += L.dx
|
||||
add lr, lr, r8 // R.x += R.dx
|
||||
add r0, r0, #320 // pixel += FRAME_WIDTH (160)
|
||||
|
||||
subs r4, r4, #1
|
||||
bpl 1b
|
||||
str ip, [r1, #4]
|
||||
str lr, [r2, #4]
|
||||
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,pc}
|
||||
|
||||
|
||||
/* TODO
|
||||
.global rasterizeF_asm
|
||||
rasterizeF_asm:
|
||||
// r0 = pixel
|
||||
// r1 = L edge
|
||||
// r2 = R edge
|
||||
// r3 = palIndex -> color
|
||||
|
||||
// r4 - Lh
|
||||
// r5 - Lx
|
||||
// r6 - Ldx
|
||||
// r7 - Rh
|
||||
// r8 - Rx
|
||||
// r9 - Rdx
|
||||
// x1 - asr
|
||||
// r12 - width
|
||||
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,lr}
|
||||
|
||||
ldr lr,= lightmap
|
||||
ldr r12,= palette
|
||||
|
||||
// uint16 color = palette[lightmap[(L.top->v.g << 8) | palIndex]];
|
||||
ldr r6, [r1, #28] // r6 = L.top
|
||||
ldrb r6, [r6, #6] // r6 = L.top->v.g
|
||||
orr r3, r3, r6, lsl #8 // r3 = (L.top->v.g << 8) | palIndex
|
||||
ldrb r3, [lr, r3] // r3 = lightmap[r3]
|
||||
add r3, r12, r3, lsl #1 // r3 = palette + r6
|
||||
ldrh r3, [r3] // r3 = palette[r3] // color
|
||||
|
||||
1:
|
||||
2:
|
||||
ldr r7, [r1]
|
||||
cmp r7, #0
|
||||
ldreq r7, [r1, #28]
|
||||
ldreq r7, [r7, #12]
|
||||
|
||||
|
||||
beq 2b
|
||||
|
||||
|
||||
|
||||
|
||||
SCANLINE r0, r1, PUT_PIXELS_F, "{r4,r5,r6,r7,r11,pc}"
|
||||
|
||||
b 1b
|
||||
*/
|
118
src/platform/gba/sound.h
Normal file
118
src/platform/gba/sound.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef H_SOUND
|
||||
#define H_SOUND
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct Sound
|
||||
{
|
||||
enum SoundMode {
|
||||
UNIQUE,
|
||||
REPLAY,
|
||||
LOOP,
|
||||
};
|
||||
|
||||
struct Sample
|
||||
{
|
||||
const uint8* data;
|
||||
int32 size;
|
||||
int32 pos;
|
||||
int32 inc;
|
||||
int32 volume;
|
||||
|
||||
X_INLINE void fill(int16* buffer, int32 count)
|
||||
{
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] += SND_DECODE(data[pos >> SND_FIXED_SHIFT]) * volume >> SND_VOL_SHIFT;
|
||||
|
||||
pos += inc;
|
||||
if (pos >= size)
|
||||
{
|
||||
// TODO LOOP
|
||||
data = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sample channels[SND_CHANNELS];
|
||||
int32 channelsCount;
|
||||
|
||||
void fill(uint8* buffer, int32 count)
|
||||
{
|
||||
if (channelsCount == 0)
|
||||
{
|
||||
dmaFill(buffer, SND_ENCODE(0), count);
|
||||
return;
|
||||
}
|
||||
|
||||
int16 tmp[SND_SAMPLES];
|
||||
dmaFill(tmp, 0, sizeof(tmp));
|
||||
|
||||
int32 ch = channelsCount;
|
||||
while (ch--)
|
||||
{
|
||||
Sample* sample = channels + ch;
|
||||
|
||||
sample->fill(tmp, count);
|
||||
|
||||
if (!sample->data) {
|
||||
channels[ch] = channels[--channelsCount];
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] = SND_ENCODE(X_CLAMP(tmp[i], -128, 127));
|
||||
}
|
||||
}
|
||||
|
||||
#define CALC_INC (((SND_SAMPLE_FREQ << SND_FIXED_SHIFT) / SND_OUTPUT_FREQ) * pitch >> SND_PITCH_SHIFT)
|
||||
|
||||
Sample* play(const uint8* data, int32 size, int32 volume, int32 pitch, int32 mode)
|
||||
{
|
||||
if (mode == UNIQUE || mode == REPLAY)
|
||||
{
|
||||
for (int32 i = 0; i < channelsCount; i++)
|
||||
{
|
||||
Sample* sample = channels + i;
|
||||
|
||||
if (sample->data != data)
|
||||
continue;
|
||||
|
||||
sample->inc = CALC_INC;
|
||||
sample->volume = volume;
|
||||
|
||||
if (mode == REPLAY)
|
||||
{
|
||||
sample->pos = 0;
|
||||
}
|
||||
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
|
||||
if (channelsCount >= SND_CHANNELS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Sample* sample = channels + channelsCount++;
|
||||
sample->data = data;
|
||||
sample->size = size << SND_FIXED_SHIFT;
|
||||
sample->pos = 0;
|
||||
sample->inc = CALC_INC;
|
||||
sample->volume = volume + 1;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
channelsCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Sound sound;
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user