mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
GBA/DOS version update
This commit is contained in:
parent
a4eac0afa1
commit
7e8c9d5e59
@ -33,10 +33,11 @@ LIBTONC := $(DEVKITPRO)/libtonc
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -save-temps -O3 -D__GBA__\
|
||||
CFLAGS := -g -Wall -O3 -D__GBA__\
|
||||
-mcpu=arm7tdmi -mtune=arm7tdmi\
|
||||
-fomit-frame-pointer\
|
||||
-ffast-math\
|
||||
-Wno-class-memaccess\
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
@ -151,14 +152,13 @@ soundbank.bin soundbank.h : $(AUDIOFILES)
|
||||
#---------------------------------------------------------------------------------
|
||||
@mmutil $^ -osoundbank.bin -hsoundbank.h
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# This rule links in binary data with the .bin extension
|
||||
#---------------------------------------------------------------------------------
|
||||
%.PHD.o %_PHD.h : %.PHD
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
%.WAV.o %_WAV.h : %.WAV
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
-include $(DEPSDIR)/*.d
|
||||
|
@ -20,8 +20,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="common.cpp" />
|
||||
<ClCompile Include="render.iwram.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="render.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="camera.h" />
|
||||
@ -33,6 +33,11 @@
|
||||
<ClInclude Include="item.h" />
|
||||
<ClInclude Include="lara.h" />
|
||||
<ClInclude Include="level.h" />
|
||||
<ClInclude Include="object.h" />
|
||||
<ClInclude Include="rasterizer_mode13.h" />
|
||||
<ClInclude Include="rasterizer_mode4.h" />
|
||||
<ClInclude Include="rasterizer_mode5.h" />
|
||||
<ClInclude Include="room.h" />
|
||||
<ClInclude Include="sound.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
@ -14,12 +14,18 @@ enum CameraMode
|
||||
CAMERA_MODE_FOLLOW = 1,
|
||||
CAMERA_MODE_COMBAT = 2,
|
||||
CAMERA_MODE_FIXED = 3,
|
||||
CAMERA_MODE_OBJECT = 4,
|
||||
};
|
||||
|
||||
struct Camera
|
||||
{
|
||||
vec3i viewPos;
|
||||
vec3i targetPos;
|
||||
struct Location {
|
||||
Room* room;
|
||||
vec3i pos;
|
||||
};
|
||||
|
||||
Location view;
|
||||
Location target;
|
||||
|
||||
int16 targetAngleX;
|
||||
int16 targetAngleY;
|
||||
@ -27,7 +33,8 @@ struct Camera
|
||||
|
||||
int16 angleX;
|
||||
int16 angleY;
|
||||
int32 room;
|
||||
|
||||
AABB frustumBase;
|
||||
|
||||
Item* item;
|
||||
|
||||
@ -40,25 +47,19 @@ struct Camera
|
||||
mode = CAMERA_MODE_FOLLOW;
|
||||
modeSwitch = false;
|
||||
|
||||
viewPos.x = 75162;
|
||||
viewPos.y = 2048;
|
||||
viewPos.z = 5000;
|
||||
angleX = 0;
|
||||
angleY = 0;
|
||||
|
||||
targetPos = viewPos;
|
||||
view.pos = vec3i(0);
|
||||
target.pos = view.pos;
|
||||
targetDist = CAM_DIST_FOLLOW;
|
||||
targetAngleX = 0;
|
||||
targetAngleY = 0;
|
||||
targetDist = CAM_DIST_FOLLOW;
|
||||
|
||||
angleX = 0;
|
||||
angleY = 16 << 8;
|
||||
|
||||
//angleX = -0x1000;
|
||||
//angleY = int16(0x8000);
|
||||
}
|
||||
|
||||
void freeControl()
|
||||
{
|
||||
matrixSetView(viewPos, angleX, angleY);
|
||||
matrixSetView(view.pos, angleX, angleY);
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
@ -71,36 +72,67 @@ struct Camera
|
||||
|
||||
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;
|
||||
view.pos.x += m[2].x * CAM_SPEED >> 10;
|
||||
view.pos.y += m[2].y * CAM_SPEED >> 10;
|
||||
view.pos.z += m[2].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;
|
||||
view.pos.x -= m[2].x * CAM_SPEED >> 10;
|
||||
view.pos.y -= m[2].y * CAM_SPEED >> 10;
|
||||
view.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;
|
||||
view.room = view.room->getRoom(view.pos.x, view.pos.y, view.pos.z);
|
||||
|
||||
const RoomInfo::Sector* sector = view.room->getSector(view.pos.x, view.pos.z);
|
||||
int32 floor = sector->getFloor(view.pos.x, view.pos.y, view.pos.z);
|
||||
int32 ceiling = sector->getCeiling(view.pos.x, view.pos.y, view.pos.z) - 256;
|
||||
|
||||
if (floor != WALL) {
|
||||
viewPos.y = X_MIN(viewPos.y, floor - 256);
|
||||
view.pos.y = X_MIN(view.pos.y, floor - 256);
|
||||
}
|
||||
|
||||
if (ceiling != WALL)
|
||||
{
|
||||
viewPos.y = X_MAX(viewPos.y, ceiling + 256);
|
||||
view.pos.y = X_MAX(view.pos.y, ceiling + 256);
|
||||
}
|
||||
}
|
||||
|
||||
int32 traceX()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32 traceZ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool trace()
|
||||
{
|
||||
int32 dx = abs(view.pos.x - target.pos.x);
|
||||
int32 dz = abs(view.pos.z - target.pos.z);
|
||||
|
||||
int32 tx, tz;
|
||||
|
||||
if (dx < dz) {
|
||||
tx = traceX();
|
||||
tz = traceZ();
|
||||
if (tz == 0) return false;
|
||||
} else {
|
||||
tz = traceZ();
|
||||
tx = traceX();
|
||||
if (tx == 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
if (keys & IK_START)
|
||||
@ -123,46 +155,108 @@ struct Camera
|
||||
freeControl();
|
||||
}
|
||||
|
||||
if (mode == CAMERA_MODE_FOLLOW && item) {
|
||||
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);
|
||||
const Box &box = item->getBoundingBox();
|
||||
ty += box.maxY + ((box.minY - box.maxY) * 3 >> 2);
|
||||
|
||||
targetPos.x = tx;
|
||||
targetPos.y += (ty - targetPos.y) >> 2;
|
||||
targetPos.z = tz;
|
||||
target.pos.x = tx;
|
||||
target.pos.y += (ty - target.pos.y) >> 2;
|
||||
target.pos.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);
|
||||
int32 cx = target.pos.x - (phd_sin(angle) * dz >> FIXED_SHIFT);
|
||||
int32 cy = target.pos.y - 256 + dy;
|
||||
int32 cz = target.pos.z - (phd_cos(angle) * dz >> FIXED_SHIFT);
|
||||
|
||||
viewPos.x += (cx - viewPos.x) >> 2;
|
||||
viewPos.y += (cy - viewPos.y) >> 2;
|
||||
viewPos.z += (cz - viewPos.z) >> 2;
|
||||
view.pos.x += (cx - view.pos.x) >> 2;
|
||||
view.pos.y += (cy - view.pos.y) >> 2;
|
||||
view.pos.z += (cz - view.pos.z) >> 2;
|
||||
|
||||
updateRoom();
|
||||
|
||||
anglesFromVector(targetPos.x - viewPos.x, targetPos.y - viewPos.y, targetPos.z - viewPos.z, angleX, angleY);
|
||||
vec3i dir = target.pos - view.pos;
|
||||
anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY);
|
||||
}
|
||||
|
||||
matrixSetView(viewPos, angleX, angleY);
|
||||
prepareFrustum();
|
||||
|
||||
matrixSetView(view.pos, angleX, angleY);
|
||||
|
||||
updateRoom();
|
||||
|
||||
// reset additional angles, Lara states can override it during the update proc
|
||||
targetAngleX = 0;
|
||||
targetAngleY = 0;
|
||||
targetDist = CAM_DIST_FOLLOW;
|
||||
}
|
||||
|
||||
void prepareFrustum()
|
||||
{
|
||||
matrixSetIdentity();
|
||||
matrixRotateY(angleY);
|
||||
matrixRotateX(angleX);
|
||||
|
||||
static const vec3i v[5] = {
|
||||
// near plane
|
||||
vec3i( 0, 0, 0 ),
|
||||
// far plane
|
||||
vec3i( -FRUSTUM_FAR_X, -FRUSTUM_FAR_Y, FRUSTUM_FAR_Z ),
|
||||
vec3i( FRUSTUM_FAR_X, -FRUSTUM_FAR_Y, FRUSTUM_FAR_Z ),
|
||||
vec3i( -FRUSTUM_FAR_X, FRUSTUM_FAR_Y, FRUSTUM_FAR_Z ),
|
||||
vec3i( FRUSTUM_FAR_X, FRUSTUM_FAR_Y, FRUSTUM_FAR_Z )
|
||||
};
|
||||
|
||||
const Matrix &m = matrixGet();
|
||||
|
||||
frustumBase.minX = 0xFFFFFFF;
|
||||
frustumBase.maxX = -0xFFFFFFF;
|
||||
frustumBase.minY = 0xFFFFFFF;
|
||||
frustumBase.maxY = -0xFFFFFFF;
|
||||
frustumBase.minZ = 0xFFFFFFF;
|
||||
frustumBase.maxZ = -0xFFFFFFF;
|
||||
|
||||
for (int32 i = 0; i < 5; i++)
|
||||
{
|
||||
int32 x = DP43(m[0], v[i]) >> FIXED_SHIFT;
|
||||
int32 y = DP43(m[1], v[i]) >> FIXED_SHIFT;
|
||||
int32 z = DP43(m[2], v[i]) >> FIXED_SHIFT;
|
||||
|
||||
frustumBase.minX = X_MIN(frustumBase.minX, x);
|
||||
frustumBase.maxX = X_MAX(frustumBase.maxX, x);
|
||||
frustumBase.minY = X_MIN(frustumBase.minY, y);
|
||||
frustumBase.maxY = X_MAX(frustumBase.maxY, y);
|
||||
frustumBase.minZ = X_MIN(frustumBase.minZ, z);
|
||||
frustumBase.maxZ = X_MAX(frustumBase.maxZ, z);
|
||||
}
|
||||
|
||||
frustumBase.minX += view.pos.x - 1024;
|
||||
frustumBase.maxX += view.pos.x + 1024;
|
||||
frustumBase.minY += view.pos.y - 1024;
|
||||
frustumBase.maxY += view.pos.y + 1024;
|
||||
frustumBase.minZ += view.pos.z - 1024;
|
||||
frustumBase.maxZ += view.pos.z + 1024;
|
||||
}
|
||||
|
||||
void updateFrustum(int32 offsetX, int32 offsetY, int32 offsetZ)
|
||||
{
|
||||
frustumAABB.minX = frustumBase.minX - offsetX;
|
||||
frustumAABB.maxX = frustumBase.maxX - offsetX;
|
||||
frustumAABB.minY = frustumBase.minY - offsetY;
|
||||
frustumAABB.maxY = frustumBase.maxY - offsetY;
|
||||
frustumAABB.minZ = frustumBase.minZ - offsetZ;
|
||||
frustumAABB.maxZ = frustumBase.maxZ - offsetZ;
|
||||
}
|
||||
};
|
||||
|
||||
Camera camera;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -13,8 +13,8 @@ enum CollisionType {
|
||||
CT_FLOOR_CEILING = (1 << 5),
|
||||
};
|
||||
|
||||
struct CollisionInfo {
|
||||
|
||||
struct CollisionInfo
|
||||
{
|
||||
enum SideType {
|
||||
ST_MIDDLE,
|
||||
ST_FRONT,
|
||||
@ -23,13 +23,14 @@ struct CollisionInfo {
|
||||
ST_MAX
|
||||
};
|
||||
|
||||
struct Side {
|
||||
struct Side
|
||||
{
|
||||
int32 floor;
|
||||
int32 ceiling;
|
||||
SlantType slantType;
|
||||
};
|
||||
|
||||
int16 *trigger;
|
||||
const FloorData* trigger;
|
||||
|
||||
Side m;
|
||||
Side f;
|
||||
@ -63,9 +64,9 @@ struct CollisionInfo {
|
||||
{
|
||||
SlantType slantType;
|
||||
|
||||
if (floorSlant.slantX == 0 && floorSlant.slantZ == 0) {
|
||||
if (gLastFloorSlant.slantX == 0 && gLastFloorSlant.slantZ == 0) {
|
||||
slantType = SLANT_NONE;
|
||||
} else if (abs(floorSlant.slantX) < 3 && abs(floorSlant.slantZ) < 3) {
|
||||
} else if (abs(gLastFloorSlant.slantX) < 3 && abs(gLastFloorSlant.slantZ) < 3) {
|
||||
slantType = SLANT_LOW;
|
||||
} else {
|
||||
slantType = SLANT_HIGH;
|
||||
@ -108,31 +109,49 @@ int32 alignOffset(int32 a, int32 b)
|
||||
return -(a + 1);
|
||||
}
|
||||
|
||||
bool collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) {
|
||||
/*
|
||||
bool collideStatic(Room* room, 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));
|
||||
Box objBox;
|
||||
objBox.minX = -cinfo.radius;
|
||||
objBox.maxX = cinfo.radius;
|
||||
objBox.minZ = -cinfo.radius;
|
||||
objBox.maxZ = cinfo.radius;
|
||||
objBox.minY = -height;
|
||||
objBox.maxY = 0;
|
||||
|
||||
// TODO: check linked rooms
|
||||
for (int j = 0; j < level->roomsCount; j++) {
|
||||
const TR::Room &room = level->rooms[j];
|
||||
Room** nearRoom = room->getNearRooms(p, cinfo.radius, height);
|
||||
|
||||
for (int i = 0; i < room.meshesCount; i++) {
|
||||
TR::Room::Mesh &m = room.meshes[i];
|
||||
TR::StaticMesh &sm = level->staticMeshes[m.meshIndex];
|
||||
while (*nearRoom)
|
||||
{
|
||||
const Room* room = *nearRoom++;
|
||||
|
||||
if (sm.flags & 1) continue;
|
||||
for (int i = 0; i < room->mCount; i++)
|
||||
{
|
||||
const RoomInfo::Mesh* mesh = room->meshes + i;
|
||||
|
||||
BoxV2 meshBox = sm.getBox(true);
|
||||
meshBox.rotate90(m.rotation.value / ANGLE_90);
|
||||
meshBox.translate(m.pos);
|
||||
#ifdef NO_STATIC_MESHES
|
||||
if (mesh->staticMeshId != STATIC_MESH_GATE) continue;
|
||||
#endif
|
||||
|
||||
if (!objBox.intersect(meshBox)) continue;
|
||||
const StaticMesh* staticMesh = staticMeshes + staticMeshesMap[mesh->staticMeshId];
|
||||
|
||||
cinfo.offset = meshBox.pushOut2D(objBox);
|
||||
if (staticMesh->flags & 1) continue;
|
||||
|
||||
Box meshBox = boxRotate(staticMesh->cbox, mesh->rotation);
|
||||
|
||||
// TODO align RoomInfo::Mesh (room relative int16?)
|
||||
vec3i pos;
|
||||
memcpy(&pos, &(mesh->pos[0]), sizeof(pos));
|
||||
pos -= p;
|
||||
|
||||
boxTranslate(meshBox, pos);
|
||||
|
||||
if (!boxIntersect(meshBox, objBox)) continue;
|
||||
|
||||
cinfo.offset = boxPushOut(meshBox, objBox);
|
||||
|
||||
bool flip = (cinfo.quadrant > 1);
|
||||
|
||||
@ -163,7 +182,7 @@ bool collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -182,20 +201,20 @@ void collideRoom(Item* item, int32 height, int32 yOffset = 0)
|
||||
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);\
|
||||
const Room* room = item->room->getRoom(v.x, cy, v.z);\
|
||||
const RoomInfo::Sector* sector = room->getSector(v.x, v.z);\
|
||||
floor = sector->getFloor(v.x, cy, v.z);\
|
||||
if (floor != WALL) floor -= p.y;\
|
||||
ceiling = getCeiling(sector, v.x, cy, v.z);\
|
||||
ceiling = sector->getCeiling(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.trigger = gLastFloorData;
|
||||
cinfo.slantX = gLastFloorSlant.slantX;
|
||||
cinfo.slantZ = gLastFloorSlant.slantZ;
|
||||
|
||||
cinfo.setSide(CollisionInfo::ST_MIDDLE, floor, ceiling);
|
||||
|
||||
@ -257,7 +276,7 @@ void collideRoom(Item* item, int32 height, int32 yOffset = 0)
|
||||
cinfo.setSide(CollisionInfo::ST_RIGHT, floor, ceiling);
|
||||
|
||||
// static objects
|
||||
collideStatic(cinfo, p, height);
|
||||
collideStatic(item->room, cinfo, p, height);
|
||||
|
||||
// check middle
|
||||
if (cinfo.m.floor == WALL)
|
||||
|
@ -1,11 +1,16 @@
|
||||
#include "common.h"
|
||||
|
||||
Rect clip;
|
||||
vec3i viewPos;
|
||||
uint32 keys;
|
||||
AABB frustumAABB;
|
||||
Rect viewport;
|
||||
vec3i cameraViewPos;
|
||||
Matrix matrixStack[MAX_MATRICES];
|
||||
int32 matrixStackIndex = 0;
|
||||
|
||||
uint32 keys;
|
||||
SaveGame gSaveGame;
|
||||
|
||||
const FloorData* gLastFloorData;
|
||||
FloorData gLastFloorSlant;
|
||||
|
||||
const uint16 divTable[DIV_TABLE_SIZE] = {
|
||||
0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492,
|
||||
@ -612,6 +617,57 @@ void anglesFromVector(int32 x, int32 y, int32 z, int16 &angleX, int16 &angleY)
|
||||
}
|
||||
}
|
||||
|
||||
Box boxRotate(const Box &box, int16 angle)
|
||||
{
|
||||
if (angle == ANGLE_90) {
|
||||
return Box( box.minZ, box.maxZ, box.minY, box.maxY, -box.maxX, -box.minX );
|
||||
} else if (angle == -ANGLE_90) {
|
||||
return Box( -box.maxZ, -box.minZ, box.minY, box.maxY, box.minX, box.maxX );
|
||||
} else if (angle == ANGLE_180) {
|
||||
return Box( -box.maxX, -box.minX, box.minY, box.maxY, -box.maxZ, -box.minZ );
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
void boxTranslate(Box &box, const vec3i &offset)
|
||||
{
|
||||
box.minX += offset.x;
|
||||
box.maxX += offset.x;
|
||||
box.minY += offset.y;
|
||||
box.maxY += offset.y;
|
||||
box.minZ += offset.z;
|
||||
box.maxZ += offset.z;
|
||||
}
|
||||
|
||||
bool boxIntersect(const Box &a, const Box &b)
|
||||
{
|
||||
return !(a.maxX <= b.minX || a.minX >= b.maxX ||
|
||||
a.maxY <= b.minY || a.minY >= b.maxY ||
|
||||
a.maxZ <= b.minZ || a.minZ >= b.maxZ);
|
||||
}
|
||||
|
||||
bool boxContains(const Box &a, const vec3i &p)
|
||||
{
|
||||
return !(a.minX > p.x || a.maxX < p.x ||
|
||||
a.minY > p.y || a.maxY < p.y ||
|
||||
a.minZ > p.z || a.maxZ < p.z);
|
||||
}
|
||||
|
||||
vec3i boxPushOut(const Box &a, const Box &b)
|
||||
{
|
||||
int32 ax = b.maxX - a.minX;
|
||||
int32 bx = a.maxX - b.minX;
|
||||
int32 az = b.maxZ - a.minZ;
|
||||
int32 bz = a.maxZ - b.minZ;
|
||||
|
||||
vec3i p;
|
||||
p.y = 0;
|
||||
p.x = (ax < bx) ? -ax : bx;
|
||||
p.z = (az < bz) ? -az : bz;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
void initDivTable()
|
||||
{
|
||||
@ -635,26 +691,6 @@ void initDivTable()
|
||||
}
|
||||
*/
|
||||
|
||||
Matrix& matrixGet()
|
||||
{
|
||||
return matrixStack[matrixStackIndex];
|
||||
}
|
||||
|
||||
void matrixPush()
|
||||
{
|
||||
ASSERT(matrixStackIndex < MAX_MATRICES - 1);
|
||||
|
||||
Matrix &a = matrixStack[matrixStackIndex++];
|
||||
Matrix &b = matrixStack[matrixStackIndex];
|
||||
memcpy(b, a, sizeof(Matrix));
|
||||
}
|
||||
|
||||
void matrixPop()
|
||||
{
|
||||
ASSERT(matrixStackIndex > 0);
|
||||
matrixStackIndex--;
|
||||
}
|
||||
|
||||
void matrixTranslate(const vec3i &pos)
|
||||
{
|
||||
Matrix &m = matrixGet();
|
||||
@ -665,7 +701,7 @@ void matrixTranslate(const vec3i &pos)
|
||||
|
||||
void matrixTranslateAbs(const vec3i &pos)
|
||||
{
|
||||
vec3i d = pos - viewPos;
|
||||
vec3i d = pos - cameraViewPos;
|
||||
|
||||
Matrix &m = matrixGet();
|
||||
m[0][3] = DP33(m[0], d);
|
||||
@ -752,6 +788,23 @@ void matrixRotateYXZ(int32 angleX, int32 angleY, int32 angleZ)
|
||||
if (angleZ) matrixRotateZ(angleZ);
|
||||
}
|
||||
|
||||
void matrixRotateZXY(int32 angleX, int32 angleY, int32 angleZ)
|
||||
{
|
||||
if (angleZ) matrixRotateZ(angleZ);
|
||||
if (angleX) matrixRotateX(angleX);
|
||||
if (angleY) matrixRotateY(angleY);
|
||||
}
|
||||
|
||||
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(pos);
|
||||
matrixRotateYXZ(angleX, angleY, angleZ);
|
||||
}
|
||||
|
||||
#define LERP_FAST(a, b, mul, div) a = (a + b) >> 1
|
||||
#define LERP_SLOW(a, b, mul, div) a = a + (b - a) * mul / div
|
||||
|
||||
@ -776,14 +829,36 @@ void matrixLerp(const Matrix &n, int32 multiplier, int32 divider)
|
||||
}
|
||||
}
|
||||
|
||||
void matrixFrame(const vec3i &pos, uint16* angles)
|
||||
void matrixSetIdentity()
|
||||
{
|
||||
int32 angleX = (angles[1] & 0x3FF0) << 2;
|
||||
int32 angleY = (angles[1] & 0x000F) << 12 | (angles[0] & 0xFC00) >> 4;
|
||||
int32 angleZ = (angles[0] & 0x03FF) << 6;
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
matrixTranslate(pos);
|
||||
matrixRotateYXZ(angleX, angleY, angleZ);
|
||||
#ifdef ROTATE90_MODE
|
||||
m[0][0] = 0;
|
||||
m[0][1] = 0x4000;
|
||||
m[0][2] = 0;
|
||||
m[0][3] = 0;
|
||||
|
||||
m[1][0] = -0x4000;
|
||||
m[1][1] = 0;
|
||||
m[1][2] = 0;
|
||||
m[1][3] = 0;
|
||||
#else
|
||||
m[0][0] = 0x4000;
|
||||
m[0][1] = 0;
|
||||
m[0][2] = 0;
|
||||
m[0][3] = 0;
|
||||
|
||||
m[1][0] = 0;
|
||||
m[1][1] = 0x4000;
|
||||
m[1][2] = 0;
|
||||
m[1][3] = 0;
|
||||
#endif
|
||||
|
||||
m[2][0] = 0;
|
||||
m[2][1] = 0;
|
||||
m[2][2] = 0x4000;
|
||||
m[2][3] = 0;
|
||||
}
|
||||
|
||||
void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY)
|
||||
@ -796,36 +871,31 @@ void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY)
|
||||
Matrix &m = matrixGet();
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
m[1][0] = -(cy);
|
||||
m[1][1] = -(0);
|
||||
m[1][2] = -(-sy);
|
||||
m[1][3] = pos.x;
|
||||
|
||||
m[0][0] = (sx * sy) >> FIXED_SHIFT;
|
||||
m[0][1] = cx;
|
||||
m[0][2] = (sx * cy) >> FIXED_SHIFT;
|
||||
m[0][3] = pos.y;
|
||||
m[0][3] = 0;
|
||||
|
||||
m[2][0] = (cx * sy) >> FIXED_SHIFT;
|
||||
m[2][1] = -sx;
|
||||
m[2][2] = (cx * cy) >> FIXED_SHIFT;
|
||||
m[2][3] = pos.z;
|
||||
m[1][0] = -cy;
|
||||
m[1][1] = 0;
|
||||
m[1][2] = sy;
|
||||
m[1][3] = 0;
|
||||
#else
|
||||
m[0][0] = cy;
|
||||
m[0][1] = 0;
|
||||
m[0][2] = -sy;
|
||||
m[0][3] = pos.x;
|
||||
m[0][3] = 0;
|
||||
|
||||
m[1][0] = (sx * sy) >> FIXED_SHIFT;
|
||||
m[1][1] = cx;
|
||||
m[1][2] = (sx * cy) >> FIXED_SHIFT;
|
||||
m[1][3] = pos.y;
|
||||
m[1][3] = 0;
|
||||
#endif
|
||||
|
||||
m[2][0] = (cx * sy) >> FIXED_SHIFT;
|
||||
m[2][1] = -sx;
|
||||
m[2][2] = (cx * cy) >> FIXED_SHIFT;
|
||||
m[2][3] = pos.z;
|
||||
#endif
|
||||
m[2][3] = 0;
|
||||
|
||||
viewPos = pos;
|
||||
}
|
||||
cameraViewPos = pos;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
BIN
src/platform/gba/data/TRACK_13.WAV
Normal file
BIN
src/platform/gba/data/TRACK_13.WAV
Normal file
Binary file not shown.
@ -1,2 +1,4 @@
|
||||
mv render.cpp render.iwram.cpp
|
||||
make
|
||||
mv render.iwram.cpp render.cpp
|
||||
./mGBA.exe C:\\Projects\\OpenLara\\src\\platform\\gba\\OpenLara.gba
|
||||
|
3
src/platform/gba/deploy_dos.bat
Normal file
3
src/platform/gba/deploy_dos.bat
Normal file
@ -0,0 +1,3 @@
|
||||
rm *.obj
|
||||
wcl386.exe *.cpp -fe=OpenLara.exe -i="C:\WATCOM/h" -w4 -e25 -zq -ox -d2 -6r -bt=dos -fo=.obj -zmf -xd -l=pmodew
|
||||
C:\Dosbox\dosbox -conf dosbox.conf OpenLara.exe
|
@ -5,6 +5,7 @@
|
||||
#include "item.h"
|
||||
|
||||
int32 seqGlyphs;
|
||||
extern AABB fastClipAABB;
|
||||
|
||||
void drawNumber(int32 number, int32 x, int32 y)
|
||||
{
|
||||
@ -12,7 +13,7 @@ void drawNumber(int32 number, int32 x, int32 y)
|
||||
12, 8, 10, 10, 10, 10, 10, 10, 10, 10
|
||||
};
|
||||
|
||||
const Sprite *glyphSprites = sprites + spritesSeq[seqGlyphs].sStart;
|
||||
const Sprite* glyphSprites = sprites + spritesSeq[seqGlyphs].sStart;
|
||||
|
||||
while (number > 0)
|
||||
{
|
||||
@ -64,21 +65,19 @@ void drawMesh(int16 meshIndex, uint16 intensity)
|
||||
PROFILE_STOP(dbg_poly);
|
||||
}
|
||||
|
||||
void drawShadow(const Item* item)
|
||||
void drawShadow(const Item* item, int32 size)
|
||||
{
|
||||
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);
|
||||
const RoomInfo::Sector* sector = item->room->getSector(item->pos.x, item->pos.z);
|
||||
int32 floor = sector->getFloor(item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
if (floor == WALL)
|
||||
return;
|
||||
|
||||
int32 shadowSize = 160; // TODO per item
|
||||
|
||||
const Box& box = getBoundingBox(item);
|
||||
const Box& box = item->getBoundingBox();
|
||||
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 sx = (box.maxX - box.minX) * size >> 10;
|
||||
int32 sz = (box.maxZ - box.minZ) * size >> 10;
|
||||
int32 sx2 = sx << 1;
|
||||
int32 sz2 = sz << 1;
|
||||
|
||||
@ -116,12 +115,11 @@ void drawItem(const Item* item)
|
||||
|
||||
const Model* model = models + modelIndex;
|
||||
|
||||
if (model->mCount == 1 && meshOffsets[model->mStart] == 0)
|
||||
return;
|
||||
|
||||
AnimFrame* frame = getFrame(item, model);
|
||||
AnimFrame* frame = item->getFrame(model);
|
||||
uint16* frameAngles = frame->angles + 1;
|
||||
|
||||
camera.updateFrustum(item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(item->pos);
|
||||
matrixRotateYXZ(item->angleX, item->angleY, item->angleZ);
|
||||
@ -129,12 +127,24 @@ void drawItem(const Item* item)
|
||||
int32 intensity = item->intensity;
|
||||
|
||||
if (intensity == 0xFFFF) {
|
||||
intensity = itemCalcLighting(item, frame->box);
|
||||
intensity = item->calcLighting(frame->box);
|
||||
}
|
||||
|
||||
bool isVisible = boxIsVisible(&frame->box);
|
||||
if (isVisible)
|
||||
int32 vis = boxIsVisible(&frame->box);
|
||||
if (vis != 0)
|
||||
{
|
||||
enableClipping = vis < 0;
|
||||
|
||||
if (item->type == ITEM_BAT ||
|
||||
item->type == ITEM_TRAP_FLOOR) // some objects have the wrong AABB // TODO preprocess
|
||||
{
|
||||
enableClipping = true;
|
||||
}
|
||||
|
||||
// skip rooms portal clipping for objects
|
||||
Rect oldViewport = viewport;
|
||||
viewport = Rect( 0, 0, FRAME_WIDTH, FRAME_HEIGHT );
|
||||
|
||||
// non-aligned access (TODO)
|
||||
uint32 nodeIndex;
|
||||
memcpy(&nodeIndex, &model->nodeIndex, sizeof(nodeIndex));
|
||||
@ -159,17 +169,21 @@ void drawItem(const Item* item)
|
||||
|
||||
node++;
|
||||
}
|
||||
|
||||
viewport = oldViewport;
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
|
||||
// shadow
|
||||
if (isVisible & item->flags.shadow) {
|
||||
if (vis != 0 && item->flags.shadow)
|
||||
{
|
||||
matrixPush();
|
||||
matrixTranslateAbs(item->pos);
|
||||
matrixRotateY(item->angleY);
|
||||
|
||||
drawShadow(item);
|
||||
enableClipping = true;
|
||||
drawShadow(item, 160); // TODO per item shadow size
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
@ -177,13 +191,17 @@ void drawItem(const Item* item)
|
||||
|
||||
void drawRoom(const Room* room)
|
||||
{
|
||||
clip = room->clip;
|
||||
viewport = room->clip;
|
||||
|
||||
int32 startVertex = gVerticesCount;
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(vec3i(room->x, 0, room->z));
|
||||
|
||||
camera.updateFrustum(room->x, 0, room->z);
|
||||
|
||||
enableClipping = true;
|
||||
|
||||
PROFILE_START();
|
||||
transformRoom(room->vertices, room->vCount);
|
||||
PROFILE_STOP(dbg_transform);
|
||||
@ -192,193 +210,64 @@ void drawRoom(const Room* room)
|
||||
|
||||
PROFILE_START();
|
||||
faceAddRoom(room->quads, room->qCount, room->triangles, room->tCount, startVertex);
|
||||
PROFILE_STOP(dbg_poly);
|
||||
|
||||
for (int32 i = 0; i < room->mCount; i++)
|
||||
{
|
||||
const RoomInfo::Mesh* mesh = room->meshes + i;
|
||||
|
||||
#ifdef NO_STATIC_MESHES
|
||||
if (mesh->staticMeshId != STATIC_MESH_GATE) continue;
|
||||
#endif
|
||||
|
||||
const StaticMesh* staticMesh = staticMeshes + staticMeshesMap[mesh->staticMeshId];
|
||||
|
||||
if (!(staticMesh->flags & 2)) continue; // invisible
|
||||
|
||||
// TODO align RoomInfo::Mesh (room relative int16?)
|
||||
|
||||
// TODO align RoomInfo::Mesh (room relative int16?)
|
||||
vec3i pos;
|
||||
memcpy(&pos, &mesh->pos, sizeof(pos));
|
||||
memcpy(&pos, &(mesh->pos[0]), sizeof(pos));
|
||||
|
||||
camera.updateFrustum(pos.x, pos.y, pos.z);
|
||||
|
||||
matrixPush();
|
||||
matrixTranslateAbs(pos);
|
||||
matrixRotateY(mesh->rotation);
|
||||
|
||||
if (boxIsVisible(&staticMesh->vbox)) {
|
||||
int32 vis = boxIsVisible(&staticMesh->vbox);
|
||||
if (vis != 0) {
|
||||
enableClipping = vis < 0;
|
||||
drawMesh(staticMesh->meshIndex, mesh->intensity);
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
}
|
||||
|
||||
int32 itemIndex = room->firstItem;
|
||||
while (itemIndex != NO_ITEM)
|
||||
Item* item = room->firstItem;
|
||||
while (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 (item->flags.status != ITEM_FLAGS_STATUS_INVISIBLE) {
|
||||
item->draw();
|
||||
}
|
||||
|
||||
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;
|
||||
item = item->nextItem;
|
||||
}
|
||||
|
||||
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;
|
||||
camera.view.room->clip = Rect( 0, 0, FRAME_WIDTH, FRAME_HEIGHT );
|
||||
|
||||
getVisibleRooms(camera.room);
|
||||
Room** visRoom = camera.view.room->getVisibleRooms();
|
||||
|
||||
while (visRoomsCount--)
|
||||
while (*visRoom)
|
||||
{
|
||||
Room* room = rooms + visRooms[visRoomsCount];
|
||||
Room* room = *visRoom++;
|
||||
|
||||
drawRoom(room);
|
||||
roomReset(room);
|
||||
room->reset();
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
@ -386,10 +275,10 @@ 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
|
||||
Rect testClip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||
int32 testTile = 10; // 707 // 712
|
||||
|
||||
void drawTest() {
|
||||
#ifdef _WIN32
|
||||
Sleep(16);
|
||||
#endif
|
||||
@ -445,12 +334,13 @@ void drawTest() {
|
||||
gVertices[(vidx + 3) % 4].x = -50;
|
||||
gVertices[(vidx + 3) % 4].y = 25;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
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);
|
||||
gVertices[i].clip = classify(gVertices[i], clip);
|
||||
}
|
||||
gVerticesCount = 4;
|
||||
|
||||
@ -459,10 +349,18 @@ void drawTest() {
|
||||
faceAddQuad(testTile, indices, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
for (int y = 0; y < FRAME_HEIGHT; y++) {
|
||||
for (int x = 0; x < FRAME_WIDTH; x++) {
|
||||
for (int y = 0; y < FRAME_HEIGHT; y++)
|
||||
{
|
||||
for (int x = 0; x < FRAME_WIDTH; x++)
|
||||
{
|
||||
if (x == clip.x0 || x == clip.x1 - 1 || y == clip.y0 || y == clip.y1 - 1)
|
||||
{
|
||||
#ifdef MODE4
|
||||
((uint8*)fb)[y * FRAME_WIDTH + x] = 255;
|
||||
#else
|
||||
((uint16*)fb)[y * FRAME_WIDTH + x] = 255;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,19 +1,75 @@
|
||||
#ifndef H_ENEMY
|
||||
#define H_ENEMY
|
||||
|
||||
struct Bat
|
||||
{
|
||||
#include "item.h"
|
||||
|
||||
struct Enemy : Item
|
||||
{
|
||||
Enemy(Room* room, int32 hp) : Item(room)
|
||||
{
|
||||
flags.shadow = true;
|
||||
health = hp;
|
||||
}
|
||||
|
||||
virtual void collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
//
|
||||
UNUSED(lara);
|
||||
UNUSED(cinfo);
|
||||
}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
updateAnim();
|
||||
}
|
||||
};
|
||||
|
||||
struct Wolf
|
||||
{
|
||||
|
||||
struct Wolf : Enemy
|
||||
{
|
||||
Wolf(Room* room) : Enemy(room, 6) {}
|
||||
};
|
||||
|
||||
struct Bear
|
||||
{
|
||||
|
||||
struct Bear : Enemy
|
||||
{
|
||||
Bear(Room* room) : Enemy(room, 20) {}
|
||||
};
|
||||
|
||||
|
||||
struct Bat : Enemy
|
||||
{
|
||||
Bat(Room* room) : Enemy(room, 1) {}
|
||||
};
|
||||
|
||||
/*
|
||||
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_SKATER : 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;
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
@ -4,11 +4,19 @@
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "level.h"
|
||||
#include "room.h"
|
||||
#include "camera.h"
|
||||
#include "item.h"
|
||||
#include "lara.h"
|
||||
#include "draw.h"
|
||||
|
||||
Lara* players[2];
|
||||
|
||||
Lara* getLara(const vec3i &pos)
|
||||
{
|
||||
UNUSED(pos); // TODO two players
|
||||
return players[0]; // TODO find nearest player
|
||||
}
|
||||
|
||||
struct Game
|
||||
{
|
||||
void init()
|
||||
@ -20,12 +28,12 @@ struct Game
|
||||
{
|
||||
camera.init();
|
||||
|
||||
readLevel((uint8*)LEVEL1_PHD);
|
||||
readLevel((uint8*)data);
|
||||
|
||||
// prepare rooms
|
||||
for (int32 i = 0; i < roomsCount; i++)
|
||||
{
|
||||
roomReset(rooms + i);
|
||||
rooms[i].reset();
|
||||
}
|
||||
|
||||
// prepare items
|
||||
@ -33,92 +41,91 @@ struct Game
|
||||
{
|
||||
Item* item = items + i;
|
||||
|
||||
itemInit(item);
|
||||
item->init(rooms + item->startRoomIndex);
|
||||
|
||||
if (item->room > -1) {
|
||||
roomItemAdd(item->room, i);
|
||||
}
|
||||
|
||||
if (item->type == ITEM_LARA) {
|
||||
if (item->type == ITEM_LARA)
|
||||
{
|
||||
camera.item = item;
|
||||
|
||||
//#ifdef PROFILE
|
||||
// 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)
|
||||
//resetItem(item, 0, vec3i(74588, 3072, 19673), 0); // level 1 (first darts)
|
||||
//resetItem(item, 9, vec3i(49669, 7680, 57891), 0); // level 1 (first door)
|
||||
//resetItem(item, 10, vec3i(43063, 7168, 61198), 0); // level 1 (transp)
|
||||
//resetItem(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // level 1 (bridge)
|
||||
//resetItem(item, 17, vec3i(16475, 6656, 59845), ANGLE_90); // level 1 (bear)
|
||||
//resetItem(item, 26, vec3i(24475, 6912, 83505), ANGLE_90); // level 1 (switch timer)
|
||||
//resetItem(item, 35, vec3i(35149, 2048, 74189), ANGLE_90); // level 1 (switch timer)
|
||||
//#endif
|
||||
|
||||
camera.room = item->room;
|
||||
}
|
||||
camera.view.pos = camera.target.pos = item->pos;
|
||||
camera.view.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);
|
||||
players[0] = (Lara*)item;
|
||||
}
|
||||
}
|
||||
|
||||
// prepare glyphs
|
||||
for (int32 i = 0; i < spritesSeqCount; i++) {
|
||||
if (spritesSeq[i].type == ITEM_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)
|
||||
void resetItem(Item* item, int32 roomIndex, const vec3i &pos, int32 angleY)
|
||||
{
|
||||
roomItemRemove(itemIndex);
|
||||
item->room->remove(item);
|
||||
|
||||
Item* item = items + itemIndex;
|
||||
item->pos = vec3i(20215, 6656, 52942);
|
||||
item->pos = pos;
|
||||
item->angleY = angleY;
|
||||
item->health = LARA_MAX_HEALTH;
|
||||
|
||||
roomItemAdd(roomIndex, itemIndex);
|
||||
rooms[roomIndex].add(item);
|
||||
}
|
||||
|
||||
void updateItems()
|
||||
{
|
||||
curItemIndex = firstActive;
|
||||
while (curItemIndex != NO_ITEM)
|
||||
Item* item = Item::sFirstActive;
|
||||
while (item)
|
||||
{
|
||||
Item* item = items + curItemIndex;
|
||||
|
||||
if (item->type == ITEM_LARA) {
|
||||
Lara* lara = (Lara*)item;
|
||||
lara->update();
|
||||
} else {
|
||||
itemControl(item);
|
||||
}
|
||||
|
||||
curItemIndex = item->nextActive;
|
||||
Item* next = item->nextActive;
|
||||
item->update();
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
void update(int32 frames)
|
||||
{
|
||||
#ifdef TEST
|
||||
return;
|
||||
#endif
|
||||
if (frames > MAX_UPDATE_FRAMES) {
|
||||
frames = MAX_UPDATE_FRAMES;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < frames; i++) {
|
||||
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
|
||||
if (keys & IK_SELECT) {
|
||||
mixer.playMusic(TRACK_13_WAV);
|
||||
}
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
#ifdef ROTATE90_MODE
|
||||
#define TEXT_POSX FRAME_HEIGHT
|
||||
#else
|
||||
#define TEXT_POSX FRAME_WIDTH
|
||||
#endif
|
||||
|
||||
clear();
|
||||
|
||||
#ifdef TEST
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "camera.h"
|
||||
#include "draw.h"
|
||||
|
||||
int32 curItemIndex;
|
||||
|
||||
@ -18,24 +19,7 @@ int16 angleDec(int16 angle, int32 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)
|
||||
Mixer::Sample* soundPlay(int16 id, const vec3i &pos)
|
||||
{
|
||||
int16 a = soundMap[id];
|
||||
|
||||
@ -49,7 +33,7 @@ Sound::Sample* soundPlay(int16 id, const vec3i &pos)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec3i d = pos - camera.targetPos;
|
||||
vec3i d = pos - camera.target.pos;
|
||||
|
||||
if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) {
|
||||
return NULL;
|
||||
@ -61,12 +45,12 @@ Sound::Sample* soundPlay(int16 id, const vec3i &pos)
|
||||
volume -= xRand() >> 2;
|
||||
}
|
||||
|
||||
volume = X_MIN(volume, 0x7FFF) >> 9;
|
||||
|
||||
if (volume <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
volume = X_MIN(volume, 0x7FFF);
|
||||
|
||||
int32 pitch = 128;
|
||||
|
||||
if (b->flags.pitch) {
|
||||
@ -78,77 +62,102 @@ Sound::Sample* soundPlay(int16 id, const vec3i &pos)
|
||||
index += (xRand() * b->flags.count) >> 15;
|
||||
}
|
||||
|
||||
const uint8 *data = soundData + soundOffsets[index];
|
||||
int32 offset;
|
||||
memcpy(&offset, soundOffsets + index, 4); // TODO preprocess and remove wave header
|
||||
|
||||
const uint8 *data = soundData + offset;//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);
|
||||
return mixer.playSample(data, size, volume, pitch, b->flags.mode);
|
||||
}
|
||||
|
||||
void move(Item* item, const Anim* anim)
|
||||
AnimFrame* Item::getFrame(const Model* model) const
|
||||
{
|
||||
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;
|
||||
int32 frameSize = sizeof(AnimFrame) / 2 + model->mCount * 2;
|
||||
int32 keyFrame = (frameIndex - anim->frameBegin) / anim->frameRate; // TODO fixed div? check the range
|
||||
|
||||
return (AnimFrame*)(animFrames + anim->frameOffset / 2 + keyFrame * frameSize);
|
||||
}
|
||||
|
||||
const Box& Item::getBoundingBox() const
|
||||
{
|
||||
const Model* model = models + modelsMap[type];
|
||||
AnimFrame* frame = getFrame(model);
|
||||
return frame->box;
|
||||
}
|
||||
|
||||
void Item::move()
|
||||
{
|
||||
const Anim* anim = anims + animIndex;
|
||||
|
||||
int32 s = anim->speed;
|
||||
|
||||
if (flags.gravity)
|
||||
{
|
||||
s += anim->accel * (frameIndex - anim->frameBegin - 1);
|
||||
hSpeed -= s >> 16;
|
||||
s += anim->accel;
|
||||
hSpeed += s >> 16;
|
||||
|
||||
vSpeed += (vSpeed < 128) ? GRAVITY : 1;
|
||||
|
||||
pos.y += vSpeed;
|
||||
} else {
|
||||
s += anim->accel * (frameIndex - anim->frameBegin);
|
||||
|
||||
hSpeed = s >> 16;
|
||||
}
|
||||
|
||||
int16 angle = (type == ITEM_LARA) ? moveAngle : angleY;
|
||||
|
||||
pos.x += phd_sin(angle) * hSpeed >> FIXED_SHIFT;
|
||||
pos.z += phd_cos(angle) * hSpeed >> FIXED_SHIFT;
|
||||
}
|
||||
|
||||
const Anim* Item::animSet(int32 newAnimIndex, bool resetState, int32 frameOffset)
|
||||
{
|
||||
const Anim* anim = anims + newAnimIndex;
|
||||
|
||||
animIndex = newAnimIndex;
|
||||
frameIndex = anim->frameBegin + frameOffset;
|
||||
|
||||
if (resetState) {
|
||||
item->state = item->goalState = anim->state;
|
||||
state = goalState = uint8(anim->state);
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
const Anim* animChange(Item* item, const Anim* anim)
|
||||
const Anim* Item::animChange(const Anim* anim)
|
||||
{
|
||||
if (!anim->statesCount || item->goalState == item->state)
|
||||
if (!anim->statesCount || goalState == state)
|
||||
return anim;
|
||||
|
||||
const AnimState* animState = animStates + anim->statesStart;
|
||||
|
||||
for (int32 i = 0; i < anim->statesCount; i++)
|
||||
{
|
||||
if (item->goalState == animState->state)
|
||||
if (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 ((frameIndex >= animRange->frameBegin) && (frameIndex <= animRange->frameEnd))
|
||||
{
|
||||
if ((item->type != ITEM_LARA) && (item->nextState == animState->state)) {
|
||||
item->nextState = 0;
|
||||
if ((type != ITEM_LARA) && (nextState == animState->state)) {
|
||||
nextState = 0;
|
||||
}
|
||||
|
||||
item->frameIndex = animRange->nextFrameIndex;
|
||||
item->animIndex = animRange->nextAnimIndex;
|
||||
frameIndex = animRange->nextFrameIndex;
|
||||
animIndex = animRange->nextAnimIndex;
|
||||
anim = anims + animRange->nextAnimIndex;
|
||||
item->state = anim->state;
|
||||
state = uint8(anim->state);
|
||||
return anim;
|
||||
}
|
||||
animRange++;
|
||||
@ -160,7 +169,7 @@ const Anim* animChange(Item* item, const Anim* anim)
|
||||
return anim;
|
||||
}
|
||||
|
||||
void animCmd(bool fx, Item* item, const Anim* anim)
|
||||
void Item::animCmd(bool fx, const Anim* anim)
|
||||
{
|
||||
if (!anim->commandsCount) return;
|
||||
|
||||
@ -177,14 +186,14 @@ void animCmd(bool fx, Item* item, const Anim* anim)
|
||||
{
|
||||
if (!fx)
|
||||
{
|
||||
int32 s = phd_sin(item->moveAngle);
|
||||
int32 c = phd_cos(item->moveAngle);
|
||||
int32 s = phd_sin(moveAngle);
|
||||
int32 c = phd_cos(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;
|
||||
pos.x += (c * x + s * z) >> FIXED_SHIFT;
|
||||
pos.y += y;
|
||||
pos.z += (c * z - s * x) >> FIXED_SHIFT;
|
||||
}
|
||||
ptr += 3;
|
||||
break;
|
||||
@ -192,32 +201,36 @@ void animCmd(bool fx, Item* item, const Anim* anim)
|
||||
case ANIM_CMD_JUMP:
|
||||
if (!fx)
|
||||
{
|
||||
if (item->vSpeedHack) {
|
||||
item->vSpeed = item->vSpeedHack;
|
||||
item->vSpeedHack = 0;
|
||||
if (vSpeedHack) {
|
||||
vSpeed = vSpeedHack;
|
||||
vSpeedHack = 0;
|
||||
} else {
|
||||
item->vSpeed = ptr[0];
|
||||
vSpeed = ptr[0];
|
||||
}
|
||||
item->hSpeed = ptr[1];
|
||||
item->flags.gravity = true;
|
||||
hSpeed = ptr[1];
|
||||
flags.gravity = true;
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
case ANIM_CMD_EMPTY:
|
||||
break;
|
||||
case ANIM_CMD_KILL:
|
||||
if (!fx)
|
||||
{
|
||||
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
|
||||
}
|
||||
break;
|
||||
case ANIM_CMD_SOUND:
|
||||
if (fx && item->frameIndex == ptr[0])
|
||||
if (fx && frameIndex == ptr[0])
|
||||
{
|
||||
soundPlay(ptr[1] & 0x03FFF, item->pos);
|
||||
soundPlay(ptr[1] & 0x03FFF, pos);
|
||||
}
|
||||
ptr += 2;
|
||||
break;
|
||||
case ANIM_CMD_EFFECT:
|
||||
if (fx && item->frameIndex == ptr[0]) {
|
||||
if (fx && frameIndex == ptr[0]) {
|
||||
switch (ptr[1]) {
|
||||
case FX_ROTATE_180 : item->angleY -= ANGLE_180; break;
|
||||
case FX_ROTATE_180 : angleY += ANGLE_180; break;
|
||||
/*
|
||||
case FX_FLOOR_SHAKE : ASSERT(false);
|
||||
case FX_LARA_NORMAL : animation.setAnim(ANIM_STAND); break;
|
||||
@ -243,35 +256,150 @@ void animCmd(bool fx, Item* item, const Anim* anim)
|
||||
}
|
||||
}
|
||||
|
||||
void animUpdate(Item* item)
|
||||
void Item::skipAnim()
|
||||
{
|
||||
if (modelsMap[item->type] == NO_MODEL)
|
||||
return;
|
||||
vec3i p = pos;
|
||||
|
||||
const Anim* anim = anims + item->animIndex;
|
||||
|
||||
item->frameIndex++;
|
||||
|
||||
anim = animChange(item, anim);
|
||||
|
||||
if (item->frameIndex > anim->frameEnd)
|
||||
while (state != goalState)
|
||||
{
|
||||
animCmd(false, item, anim);
|
||||
|
||||
item->frameIndex = anim->nextFrameIndex;
|
||||
item->animIndex = anim->nextAnimIndex;
|
||||
anim = anims + anim->nextAnimIndex;
|
||||
item->state = anim->state;
|
||||
updateAnim(false);
|
||||
}
|
||||
|
||||
animCmd(true, item, anim);
|
||||
|
||||
move(item, anim);
|
||||
pos = p;
|
||||
vSpeed = 0;
|
||||
hSpeed = 0;
|
||||
}
|
||||
|
||||
int32 calcLight(const vec3i &pos, int32 roomIndex)
|
||||
void Item::updateAnim(bool movement)
|
||||
{
|
||||
Room* room = rooms + roomIndex;
|
||||
if (modelsMap[type] == NO_MODEL)
|
||||
return;
|
||||
|
||||
const Anim* anim = anims + animIndex;
|
||||
|
||||
#ifndef STATIC_ITEMS
|
||||
frameIndex++;
|
||||
#endif
|
||||
|
||||
anim = animChange(anim);
|
||||
|
||||
if (frameIndex > anim->frameEnd)
|
||||
{
|
||||
animCmd(false, anim);
|
||||
|
||||
frameIndex = anim->nextFrameIndex;
|
||||
animIndex = anim->nextAnimIndex;
|
||||
anim = anims + anim->nextAnimIndex;
|
||||
state = uint8(anim->state);
|
||||
}
|
||||
|
||||
animCmd(true, anim);
|
||||
|
||||
#ifndef STATIC_ITEMS
|
||||
if (movement) {
|
||||
move();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Item* Item::add(ItemType type, Room* room, const vec3i &pos, int32 angleY)
|
||||
{
|
||||
if (!Item::sFirstFree) {
|
||||
ASSERT(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Item* item = Item::sFirstFree;
|
||||
Item::sFirstFree = item->nextItem;
|
||||
|
||||
item->type = type;
|
||||
item->pos = pos;
|
||||
item->angleY = angleY;
|
||||
item->intensity = -1;
|
||||
|
||||
item->init(room);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void Item::remove()
|
||||
{
|
||||
deactivate();
|
||||
room->remove(this);
|
||||
|
||||
nextItem = Item::sFirstFree;
|
||||
Item::sFirstFree = this;
|
||||
}
|
||||
|
||||
void Item::activate()
|
||||
{
|
||||
ASSERT(!flags.active)
|
||||
|
||||
flags.active = true;
|
||||
|
||||
nextActive = sFirstActive;
|
||||
sFirstActive = this;
|
||||
}
|
||||
|
||||
void Item::deactivate()
|
||||
{
|
||||
Item* prev = NULL;
|
||||
Item* curr = sFirstActive;
|
||||
|
||||
while (curr)
|
||||
{
|
||||
Item* next = curr->nextActive;
|
||||
|
||||
if (curr == this)
|
||||
{
|
||||
flags.active = false;
|
||||
nextActive = NULL;
|
||||
|
||||
if (prev) {
|
||||
prev->nextActive = next;
|
||||
} else {
|
||||
sFirstActive = next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
void Item::updateRoom(int32 offset)
|
||||
{
|
||||
Room* nextRoom = room->getRoom(pos.x, pos.y + offset, pos.z);
|
||||
|
||||
if (room != nextRoom)
|
||||
{
|
||||
room->remove(this);
|
||||
nextRoom->add(this);
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* sector = room->getSector(pos.x, pos.z);
|
||||
floor = sector->getFloor(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
int32 Item::calcLighting(const Box& box) const
|
||||
{
|
||||
matrixPush();
|
||||
Matrix &m = matrixGet();
|
||||
m[0][3] = m[1][3] = m[2][3] = 0;
|
||||
matrixRotateYXZ(angleX, angleY, angleZ);
|
||||
|
||||
vec3i p((box.maxX + box.minX) >> 1,
|
||||
(box.maxY + box.minY) >> 1,
|
||||
(box.maxZ + box.minZ) >> 1);
|
||||
|
||||
matrixTranslate(p);
|
||||
|
||||
p = vec3i(m[0][3] >> FIXED_SHIFT,
|
||||
m[1][3] >> FIXED_SHIFT,
|
||||
m[2][3] >> FIXED_SHIFT) + pos;
|
||||
matrixPop();
|
||||
|
||||
if (!room->lCount) {
|
||||
return room->ambient;
|
||||
@ -290,7 +418,7 @@ int32 calcLight(const vec3i &pos, int32 roomIndex)
|
||||
memcpy(&lpos, &light->pos[0], sizeof(lpos));
|
||||
memcpy(&lradius, &light->radius[0], sizeof(lradius));
|
||||
|
||||
vec3i d = pos - lpos;
|
||||
vec3i d = p - lpos;
|
||||
int32 dist = dot(d, d) >> 12;
|
||||
int32 att = X_SQR(lradius) >> 12;
|
||||
|
||||
@ -305,80 +433,241 @@ int32 calcLight(const vec3i &pos, int32 roomIndex)
|
||||
return 8191 - ((intensity + ambient) >> 1);
|
||||
}
|
||||
|
||||
int32 itemCalcLighting(const Item* item, const Box& box)
|
||||
#include "lara.h"
|
||||
#include "enemy.h"
|
||||
#include "object.h"
|
||||
|
||||
Item::Item(Room* room)
|
||||
{
|
||||
matrixPush();
|
||||
Matrix &m = matrixGet();
|
||||
m[0][3] = m[1][3] = m[2][3] = 0;
|
||||
matrixRotateYXZ(item->angleX, item->angleY, item->angleZ);
|
||||
angleX = 0;
|
||||
angleZ = 0;
|
||||
vSpeed = 0;
|
||||
hSpeed = 0;
|
||||
nextItem = NULL;
|
||||
nextActive = NULL;
|
||||
animIndex = models[modelsMap[type]].animIndex;
|
||||
frameIndex = anims[animIndex].frameBegin;
|
||||
state = uint8(anims[animIndex].state);
|
||||
nextState = state;
|
||||
goalState = state;
|
||||
|
||||
vec3i v((box.maxX + box.minX) >> 1,
|
||||
(box.maxY + box.minY) >> 1,
|
||||
(box.maxZ + box.minZ) >> 1);
|
||||
flags.save = true;
|
||||
flags.gravity = false;
|
||||
flags.active = false;
|
||||
flags.status = ITEM_FLAGS_STATUS_NONE;
|
||||
flags.collision = true;
|
||||
flags.custom = 0;
|
||||
flags.shadow = false;
|
||||
|
||||
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;
|
||||
if (flags.once) // once -> invisible
|
||||
{
|
||||
flags.status = ITEM_FLAGS_STATUS_INVISIBLE;
|
||||
flags.once = false;
|
||||
}
|
||||
|
||||
if (flags.mask == ITEM_FLAGS_MASK_ALL) // full set of mask -> reverse
|
||||
{
|
||||
flags.mask = 0;
|
||||
flags.active = true;
|
||||
flags.reverse = true;
|
||||
activate();
|
||||
}
|
||||
|
||||
ASSERT(type <= ITEM_MAX);
|
||||
|
||||
ASSERT(room);
|
||||
|
||||
room->add(this);
|
||||
}
|
||||
|
||||
void Item::update()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void Item::draw()
|
||||
{
|
||||
drawItem(this);
|
||||
}
|
||||
|
||||
void Item::collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
UNUSED(lara);
|
||||
UNUSED(cinfo);
|
||||
}
|
||||
|
||||
Item* Item::init(Room* room)
|
||||
{
|
||||
#define INIT_ITEM(type, className) case ITEM_##type : return new (this) className(room)
|
||||
|
||||
switch (type)
|
||||
{
|
||||
INIT_ITEM( LARA , Lara );
|
||||
// INIT_ITEM( DOPPELGANGER , ??? );
|
||||
INIT_ITEM( WOLF , Wolf );
|
||||
INIT_ITEM( BEAR , Bear );
|
||||
INIT_ITEM( BAT , Bat );
|
||||
// INIT_ITEM( CROCODILE_LAND , ??? );
|
||||
// INIT_ITEM( CROCODILE_WATER , ??? );
|
||||
// INIT_ITEM( LION_MALE , ??? );
|
||||
// INIT_ITEM( LION_FEMALE , ??? );
|
||||
// INIT_ITEM( PUMA , ??? );
|
||||
// INIT_ITEM( GORILLA , ??? );
|
||||
// INIT_ITEM( RAT_LAND , ??? );
|
||||
// INIT_ITEM( RAT_WATER , ??? );
|
||||
// INIT_ITEM( REX , ??? );
|
||||
// INIT_ITEM( RAPTOR , ??? );
|
||||
// INIT_ITEM( MUTANT_1 , ??? );
|
||||
// INIT_ITEM( MUTANT_2 , ??? );
|
||||
// INIT_ITEM( MUTANT_3 , ??? );
|
||||
// INIT_ITEM( CENTAUR , ??? );
|
||||
// INIT_ITEM( MUMMY , ??? );
|
||||
// INIT_ITEM( LARSON , ??? );
|
||||
// INIT_ITEM( PIERRE , ??? );
|
||||
// INIT_ITEM( SKATEBOARD , ??? );
|
||||
// INIT_ITEM( SKATER , ??? );
|
||||
// INIT_ITEM( COWBOY , ??? );
|
||||
// INIT_ITEM( MR_T , ??? );
|
||||
// INIT_ITEM( NATLA , ??? );
|
||||
// INIT_ITEM( GIANT_MUTANT , ??? );
|
||||
INIT_ITEM( TRAP_FLOOR , TrapFloor );
|
||||
// INIT_ITEM( TRAP_SWING_BLADE , ??? );
|
||||
// INIT_ITEM( TRAP_SPIKES , ??? );
|
||||
// INIT_ITEM( TRAP_BOULDER , ??? );
|
||||
INIT_ITEM( DART , Dart );
|
||||
INIT_ITEM( TRAP_DART_EMITTER , TrapDartEmitter );
|
||||
// INIT_ITEM( DRAWBRIDGE , ??? );
|
||||
// INIT_ITEM( TRAP_SLAM , ??? );
|
||||
// INIT_ITEM( TRAP_SWORD , ??? );
|
||||
// INIT_ITEM( HAMMER_HANDLE , ??? );
|
||||
// INIT_ITEM( HAMMER_BLOCK , ??? );
|
||||
// INIT_ITEM( LIGHTNING , ??? );
|
||||
// INIT_ITEM( MOVING_OBJECT , ??? );
|
||||
// INIT_ITEM( BLOCK_1 , ??? );
|
||||
// INIT_ITEM( BLOCK_2 , ??? );
|
||||
// INIT_ITEM( BLOCK_3 , ??? );
|
||||
// INIT_ITEM( BLOCK_4 , ??? );
|
||||
// INIT_ITEM( MOVING_BLOCK , ??? );
|
||||
// INIT_ITEM( TRAP_CEILING_1 , ??? );
|
||||
// INIT_ITEM( TRAP_CEILING_2 , ??? );
|
||||
INIT_ITEM( SWITCH , Switch );
|
||||
INIT_ITEM( SWITCH_WATER , SwitchWater );
|
||||
INIT_ITEM( DOOR_1 , Door );
|
||||
INIT_ITEM( DOOR_2 , Door );
|
||||
INIT_ITEM( DOOR_3 , Door );
|
||||
INIT_ITEM( DOOR_4 , Door );
|
||||
INIT_ITEM( DOOR_5 , Door );
|
||||
INIT_ITEM( DOOR_6 , Door );
|
||||
INIT_ITEM( DOOR_7 , Door );
|
||||
INIT_ITEM( DOOR_8 , Door );
|
||||
// INIT_ITEM( TRAP_DOOR_1 , ??? );
|
||||
// INIT_ITEM( TRAP_DOOR_2 , ??? );
|
||||
// INIT_ITEM( BRIDGE_FLAT , ??? );
|
||||
// INIT_ITEM( BRIDGE_TILT1 , ??? );
|
||||
// INIT_ITEM( BRIDGE_TILT2 , ??? );
|
||||
// INIT_ITEM( INV_PASSPORT , ??? );
|
||||
// INIT_ITEM( INV_COMPASS , ??? );
|
||||
// INIT_ITEM( INV_HOME , ??? );
|
||||
// INIT_ITEM( GEARS_1 , ??? );
|
||||
// INIT_ITEM( GEARS_2 , ??? );
|
||||
// INIT_ITEM( GEARS_3 , ??? );
|
||||
// INIT_ITEM( CUT_1 , ??? );
|
||||
// INIT_ITEM( CUT_2 , ??? );
|
||||
// INIT_ITEM( CUT_3 , ??? );
|
||||
// INIT_ITEM( CUT_4 , ??? );
|
||||
// INIT_ITEM( INV_PASSPORT_CLOSED , ??? );
|
||||
// INIT_ITEM( INV_MAP , ??? );
|
||||
// INIT_ITEM( CRYSTAL , ??? );
|
||||
INIT_ITEM( PISTOLS , Pickup );
|
||||
INIT_ITEM( SHOTGUN , Pickup );
|
||||
INIT_ITEM( MAGNUMS , Pickup );
|
||||
INIT_ITEM( UZIS , Pickup );
|
||||
INIT_ITEM( AMMO_PISTOLS , Pickup );
|
||||
INIT_ITEM( AMMO_SHOTGUN , Pickup );
|
||||
INIT_ITEM( AMMO_MAGNUMS , Pickup );
|
||||
INIT_ITEM( AMMO_UZIS , Pickup );
|
||||
INIT_ITEM( EXPLOSIVE , Pickup );
|
||||
INIT_ITEM( MEDIKIT_SMALL , Pickup );
|
||||
INIT_ITEM( MEDIKIT_BIG , Pickup );
|
||||
// INIT_ITEM( INV_DETAIL , ??? );
|
||||
// INIT_ITEM( INV_SOUND , ??? );
|
||||
// INIT_ITEM( INV_CONTROLS , ??? );
|
||||
// INIT_ITEM( INV_GAMMA , ??? );
|
||||
// INIT_ITEM( INV_PISTOLS , ??? );
|
||||
// INIT_ITEM( INV_SHOTGUN , ??? );
|
||||
// INIT_ITEM( INV_MAGNUMS , ??? );
|
||||
// INIT_ITEM( INV_UZIS , ??? );
|
||||
// INIT_ITEM( INV_AMMO_PISTOLS , ??? );
|
||||
// INIT_ITEM( INV_AMMO_SHOTGUN , ??? );
|
||||
// INIT_ITEM( INV_AMMO_MAGNUMS , ??? );
|
||||
// INIT_ITEM( INV_AMMO_UZIS , ??? );
|
||||
// INIT_ITEM( INV_EXPLOSIVE , ??? );
|
||||
// INIT_ITEM( INV_MEDIKIT_SMALL , ??? );
|
||||
// INIT_ITEM( INV_MEDIKIT_BIG , ??? );
|
||||
INIT_ITEM( PUZZLE_1 , Pickup );
|
||||
INIT_ITEM( PUZZLE_2 , Pickup );
|
||||
INIT_ITEM( PUZZLE_3 , Pickup );
|
||||
INIT_ITEM( PUZZLE_4 , Pickup );
|
||||
// INIT_ITEM( INV_PUZZLE_1 , ??? );
|
||||
// INIT_ITEM( INV_PUZZLE_2 , ??? );
|
||||
// INIT_ITEM( INV_PUZZLE_3 , ??? );
|
||||
// INIT_ITEM( INV_PUZZLE_4 , ??? );
|
||||
// INIT_ITEM( PUZZLE_HOLE_1 , ??? );
|
||||
// INIT_ITEM( PUZZLE_HOLE_2 , ??? );
|
||||
// INIT_ITEM( PUZZLE_HOLE_3 , ??? );
|
||||
// INIT_ITEM( PUZZLE_HOLE_4 , ??? );
|
||||
// INIT_ITEM( PUZZLE_DONE_1 , ??? );
|
||||
// INIT_ITEM( PUZZLE_DONE_2 , ??? );
|
||||
// INIT_ITEM( PUZZLE_DONE_3 , ??? );
|
||||
// INIT_ITEM( PUZZLE_DONE_4 , ??? );
|
||||
INIT_ITEM( LEADBAR , Pickup );
|
||||
// INIT_ITEM( INV_LEADBAR , ??? );
|
||||
// INIT_ITEM( MIDAS_HAND , ??? );
|
||||
INIT_ITEM( KEY_ITEM_1 , Pickup );
|
||||
INIT_ITEM( KEY_ITEM_2 , Pickup );
|
||||
INIT_ITEM( KEY_ITEM_3 , Pickup );
|
||||
INIT_ITEM( KEY_ITEM_4 , Pickup );
|
||||
// INIT_ITEM( INV_KEY_ITEM_1 , ??? );
|
||||
// INIT_ITEM( INV_KEY_ITEM_2 , ??? );
|
||||
// INIT_ITEM( INV_KEY_ITEM_3 , ??? );
|
||||
// INIT_ITEM( INV_KEY_ITEM_4 , ??? );
|
||||
// INIT_ITEM( KEY_HOLE_1 , ??? );
|
||||
// INIT_ITEM( KEY_HOLE_2 , ??? );
|
||||
// INIT_ITEM( KEY_HOLE_3 , ??? );
|
||||
// INIT_ITEM( KEY_HOLE_4 , ??? );
|
||||
// INIT_ITEM( SCION_PICKUP_QUALOPEC , ??? );
|
||||
INIT_ITEM( SCION_PICKUP_DROP , Pickup );
|
||||
INIT_ITEM( SCION_TARGET , ViewTarget );
|
||||
// INIT_ITEM( SCION_PICKUP_HOLDER , ??? );
|
||||
// INIT_ITEM( SCION_HOLDER , ??? );
|
||||
// INIT_ITEM( INV_SCION , ??? );
|
||||
// INIT_ITEM( EXPLOSION , ??? );
|
||||
// INIT_ITEM( WATER_SPLASH , ??? );
|
||||
// INIT_ITEM( BUBBLE , ??? );
|
||||
// INIT_ITEM( BLOOD , ??? );
|
||||
// INIT_ITEM( SMOKE , ??? );
|
||||
// INIT_ITEM( CENTAUR_STATUE , ??? );
|
||||
// INIT_ITEM( CABIN , ??? );
|
||||
// INIT_ITEM( MUTANT_EGG_SMALL , ??? );
|
||||
// INIT_ITEM( RICOCHET , ??? );
|
||||
// INIT_ITEM( SPARKLES , ??? );
|
||||
// INIT_ITEM( MUZZLE_FLASH , ??? );
|
||||
INIT_ITEM( VIEW_TARGET , ViewTarget );
|
||||
// INIT_ITEM( WATERFALL , ??? );
|
||||
// INIT_ITEM( NATLA_BULLET , ??? );
|
||||
// INIT_ITEM( MUTANT_BULLET , ??? );
|
||||
// INIT_ITEM( CENTAUR_BULLET , ??? );
|
||||
// INIT_ITEM( LAVA_PARTICLE , ??? );
|
||||
// INIT_ITEM( TRAP_LAVA_EMITTER , ??? );
|
||||
// INIT_ITEM( FLAME , ??? );
|
||||
// INIT_ITEM( TRAP_FLAME_EMITTER , ??? );
|
||||
// INIT_ITEM( TRAP_LAVA , ??? );
|
||||
// INIT_ITEM( MUTANT_EGG_BIG , ??? );
|
||||
// INIT_ITEM( BOAT , ??? );
|
||||
// INIT_ITEM( EARTHQUAKE , ??? );
|
||||
}
|
||||
|
||||
return new (this) Item(room);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,20 +6,6 @@
|
||||
#include "collision.h"
|
||||
#include "camera.h"
|
||||
|
||||
uint32 input;
|
||||
|
||||
enum {
|
||||
IN_LEFT = (1 << 1),
|
||||
IN_RIGHT = (1 << 2),
|
||||
IN_UP = (1 << 3),
|
||||
IN_DOWN = (1 << 4),
|
||||
IN_JUMP = (1 << 5),
|
||||
IN_WALK = (1 << 6),
|
||||
IN_ACTION = (1 << 7),
|
||||
IN_WEAPON = (1 << 8),
|
||||
IN_LOOK = (1 << 9),
|
||||
};
|
||||
|
||||
#define LARA_STATES(E) \
|
||||
E( WALK ) \
|
||||
E( RUN ) \
|
||||
@ -213,7 +199,7 @@ struct Lara : Item
|
||||
ANIM_SWITCH_BIG_UP = 196,
|
||||
ANIM_PUSH_BUTTON = 197,
|
||||
|
||||
ANIM_UW_ROLL = 203,
|
||||
ANIM_UW_ROLL = 203,
|
||||
};
|
||||
|
||||
typedef void (Lara::*Handler)();
|
||||
@ -228,6 +214,29 @@ struct Lara : Item
|
||||
|
||||
void updateCollision()
|
||||
{
|
||||
Room** adjRoom = room->getAdjRooms();
|
||||
while (*adjRoom)
|
||||
{
|
||||
Item* item = (*adjRoom++)->firstItem;
|
||||
|
||||
while (item)
|
||||
{
|
||||
if (item->flags.status != ITEM_FLAGS_STATUS_INVISIBLE)
|
||||
{
|
||||
if (item->flags.collision)
|
||||
{
|
||||
vec3i d = pos - item->pos;
|
||||
|
||||
if (abs(d.x) < 4096 && abs(d.y) < 4096 && abs(d.z) < 4096)
|
||||
{
|
||||
item->collide(this, &cinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
item = item->nextItem;
|
||||
}
|
||||
}
|
||||
|
||||
(this->*cHandlers[state])();
|
||||
}
|
||||
|
||||
@ -250,8 +259,8 @@ struct Lara : Item
|
||||
angle = ANGLE_90;
|
||||
} else if (angle >= -ANGLE_90 - threshold && angle <= -ANGLE_90 + threshold) {
|
||||
angle = -ANGLE_90;
|
||||
} else if (angle >= (ANGLE_180 - 1) - threshold || angle <= -(ANGLE_180 - 1) + threshold) {
|
||||
angle = -ANGLE_180;
|
||||
} else if (angle >= -(ANGLE_180 + 1 + threshold) || angle <= (ANGLE_180 + 1 + threshold)) {
|
||||
angle = ANGLE_180;
|
||||
}
|
||||
|
||||
return (angle & (ANGLE_90 - 1)) > 0;
|
||||
@ -267,7 +276,7 @@ struct Lara : Item
|
||||
case ANGLE_0 : pos.z = z + 1024 + LARA_RADIUS; break;
|
||||
case ANGLE_90 : pos.x = x + 1024 + LARA_RADIUS; break;
|
||||
case -ANGLE_90 : pos.x = x - LARA_RADIUS; break;
|
||||
case -ANGLE_180 : pos.z = z - LARA_RADIUS; break;
|
||||
case ANGLE_180 : pos.z = z - LARA_RADIUS; break;
|
||||
default : ASSERT(false);
|
||||
}
|
||||
}
|
||||
@ -280,9 +289,9 @@ struct Lara : Item
|
||||
int32 y = pos.y - LARA_HEIGHT;
|
||||
int32 z = pos.z + (phd_cos(angle) >> (FIXED_SHIFT - 8));
|
||||
|
||||
int32 roomIndex = getRoomIndex(room, x, y, z);
|
||||
const RoomInfo::Sector* sector = getSector(roomIndex, x, z);
|
||||
int16 floor = getFloor(sector, x, y, z);
|
||||
Room* roomFront = room->getRoom(x, y, z);
|
||||
const RoomInfo::Sector* sector = roomFront->getSector(x, z);
|
||||
int16 floor = sector->getFloor(x, y, z);
|
||||
|
||||
if (floor != WALL) {
|
||||
floor -= pos.y;
|
||||
@ -298,7 +307,7 @@ struct Lara : Item
|
||||
|
||||
const Model* model = models + modelIndex;
|
||||
|
||||
AnimFrame* frame = getFrame(this, model);
|
||||
AnimFrame* frame = getFrame(model);
|
||||
|
||||
return frame->box;
|
||||
}
|
||||
@ -308,43 +317,10 @@ struct Lara : Item
|
||||
return health <= 0;
|
||||
}
|
||||
|
||||
void updateRoom(int32 itemIndex, int32 height)
|
||||
{
|
||||
int16 nextRoom = getRoomIndex(room, pos.x, pos.y + height, pos.z);
|
||||
if (room != nextRoom) {
|
||||
roomItemRemove(itemIndex);
|
||||
roomItemAdd(nextRoom, itemIndex);
|
||||
room = nextRoom;
|
||||
}
|
||||
}
|
||||
|
||||
int32 getWaterLevel(int32 roomIndex)
|
||||
{
|
||||
/*
|
||||
RoomInfo::Sector* sector = getWaterLevelSector(roomIndex, pos.x, pos.z);
|
||||
|
||||
if (sector) {
|
||||
return sector->ceiling * 256;
|
||||
}
|
||||
*/
|
||||
return WALL;
|
||||
}
|
||||
|
||||
int32 getWaterDepth(int32 roomIndex)
|
||||
{
|
||||
/*
|
||||
RoomInfo::Sector* sector = getWaterLevelSector(roomIndex, pos.x, pos.z);
|
||||
|
||||
if (sector) {
|
||||
return getFloor(sector, pos.x, pos.y, pos.z) - (sector->ceiling * 256);
|
||||
}
|
||||
*/
|
||||
return WALL;
|
||||
}
|
||||
|
||||
// state control
|
||||
bool s_checkFront(int16 angle)
|
||||
{
|
||||
UNUSED(angle); // TODO
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
@ -406,7 +382,7 @@ struct Lara : Item
|
||||
{
|
||||
if ((state == RUN) || (state == STOP))
|
||||
{
|
||||
animSet(this, ANIM_STAND_ROLL_BEGIN, true, 2);
|
||||
animSet(ANIM_STAND_ROLL_BEGIN, true, 2);
|
||||
goalState = STOP;
|
||||
return true;
|
||||
}
|
||||
@ -493,7 +469,7 @@ struct Lara : Item
|
||||
} else {
|
||||
s_RUN();
|
||||
}
|
||||
} else if ((input & IN_DOWN) && s_checkFront(-ANGLE_180)) {
|
||||
} else if ((input & IN_DOWN) && s_checkFront(ANGLE_180)) {
|
||||
if (input & IN_WALK) {
|
||||
s_BACK();
|
||||
} else {
|
||||
@ -632,7 +608,7 @@ struct Lara : Item
|
||||
goalState = LEFT_JUMP;
|
||||
} else if ((input & IN_RIGHT) && getFront(ANGLE_90) >= -LARA_STEP_HEIGHT) {
|
||||
goalState = RIGHT_JUMP;
|
||||
} else if ((input & IN_DOWN) && getFront(-ANGLE_180) >= -LARA_STEP_HEIGHT) {
|
||||
} else if ((input & IN_DOWN) && getFront(ANGLE_180) >= -LARA_STEP_HEIGHT) {
|
||||
goalState = BACK_JUMP;
|
||||
}
|
||||
s_checkFall();
|
||||
@ -685,7 +661,7 @@ struct Lara : Item
|
||||
|
||||
S_HANDLER( STEP_RIGHT )
|
||||
{
|
||||
if (checkDeath() || (input & (IN_WALK | IN_LEFT)) != (IN_WALK | IN_LEFT))
|
||||
if (checkDeath() || (input & (IN_WALK | IN_RIGHT)) != (IN_WALK | IN_RIGHT))
|
||||
{
|
||||
goalState = STOP;
|
||||
}
|
||||
@ -753,7 +729,6 @@ struct Lara : Item
|
||||
S_HANDLER( HANG_LEFT )
|
||||
{
|
||||
camera.targetAngleX = -60 * DEG2SHORT;
|
||||
camera.targetAngleY = -10 * DEG2SHORT;
|
||||
|
||||
s_ignoreEnemy();
|
||||
|
||||
@ -766,7 +741,6 @@ struct Lara : Item
|
||||
S_HANDLER( HANG_RIGHT )
|
||||
{
|
||||
camera.targetAngleX = -60 * DEG2SHORT;
|
||||
camera.targetAngleY = 10 * DEG2SHORT;
|
||||
|
||||
s_ignoreEnemy();
|
||||
|
||||
@ -908,9 +882,7 @@ struct Lara : Item
|
||||
|
||||
// collision control
|
||||
void c_applyOffset() {
|
||||
pos.x += cinfo.offset.x;
|
||||
pos.y += cinfo.offset.y;
|
||||
pos.z += cinfo.offset.z;
|
||||
pos += cinfo.offset;
|
||||
cinfo.offset = vec3i(0, 0, 0);
|
||||
}
|
||||
|
||||
@ -926,7 +898,7 @@ struct Lara : Item
|
||||
return false;
|
||||
}
|
||||
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
goalState = state;
|
||||
hSpeed = 0;
|
||||
vSpeed = 0;
|
||||
@ -988,7 +960,7 @@ struct Lara : Item
|
||||
angleX += 2 * DEG2SHORT;
|
||||
}
|
||||
|
||||
int32 waterDepth = getWaterDepth(room);
|
||||
int32 waterDepth = room->getWaterDepth();
|
||||
|
||||
if (waterDepth == WALL) {
|
||||
vSpeed = 0;
|
||||
@ -996,7 +968,7 @@ struct Lara : Item
|
||||
} else if (waterDepth <= 512) {
|
||||
waterState = WATER_STATE_WADE;
|
||||
|
||||
animSet(this, ANIM_SWIM_STAND, true);
|
||||
animSet(ANIM_SWIM_STAND, true);
|
||||
goalState = STOP;
|
||||
|
||||
angleX = 0;
|
||||
@ -1004,10 +976,6 @@ struct Lara : Item
|
||||
hSpeed = 0;
|
||||
vSpeed = 0;
|
||||
flags.gravity = false;
|
||||
/* TODO
|
||||
RoomInfo::Sector* sector = getSector(roomIndex, pos.x, pos.y, pos.z);
|
||||
pos.y = getFloor(sector, pos.x, pos.y, pos.z);
|
||||
*/
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1044,23 +1012,23 @@ struct Lara : Item
|
||||
} else if (cinfo.slantX < -2) {
|
||||
angle = ANGLE_90;
|
||||
} else if (cinfo.slantZ > 2) {
|
||||
angle = -ANGLE_180;
|
||||
angle = ANGLE_180;
|
||||
} else {
|
||||
angle = 0;
|
||||
}
|
||||
|
||||
if (abs(angle - angleY) <= ANGLE_90) {
|
||||
if (state != SLIDE) {
|
||||
animSet(this, ANIM_SLIDE_FORTH, true);
|
||||
animSet(ANIM_SLIDE_FORTH, true);
|
||||
}
|
||||
moveAngle = angle;
|
||||
angleY = angle;
|
||||
} else {
|
||||
if (state != SLIDE_BACK) {
|
||||
animSet(this, ANIM_SLIDE_BACK, true);
|
||||
animSet(ANIM_SLIDE_BACK, true);
|
||||
}
|
||||
moveAngle = angle;
|
||||
angleY = angle - ANGLE_180;
|
||||
angleY = angle + ANGLE_180;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1075,7 +1043,7 @@ struct Lara : Item
|
||||
return false;
|
||||
}
|
||||
|
||||
animSet(this, fallAnimIndex, true);
|
||||
animSet(fallAnimIndex, true);
|
||||
|
||||
vSpeed = 0;
|
||||
flags.gravity = true;
|
||||
@ -1094,7 +1062,7 @@ struct Lara : Item
|
||||
/* TODO
|
||||
v2floor = pos.y;
|
||||
|
||||
checkTrigger(cinfo.trigger, false);
|
||||
checkTrigger(cinfo.trigger, this);
|
||||
*/
|
||||
pos.y = y;
|
||||
|
||||
@ -1120,15 +1088,15 @@ struct Lara : Item
|
||||
case ANGLE_0 : z += 256; break;
|
||||
case ANGLE_90 : x += 256; break;
|
||||
case -ANGLE_90 : x -= 256; break;
|
||||
case -ANGLE_180 : z -= 256; break;
|
||||
case ANGLE_180 : z -= 256; break;
|
||||
}
|
||||
|
||||
int32 roomIndex = getRoomIndex(room, x, y, z);
|
||||
const RoomInfo::Sector* sector = getSector(roomIndex, x, z);
|
||||
int32 floor = getFloor(sector, x, y, z);
|
||||
Room* roomBelow = room->getRoom(x, y, z);
|
||||
const RoomInfo::Sector* sector = roomBelow->getSector(x, z);
|
||||
int32 floor = sector->getFloor(x, y, z);
|
||||
|
||||
if (floor != WALL) {
|
||||
int32 ceiling = getCeiling(sector, x, y, z);
|
||||
int32 ceiling = sector->getCeiling(x, y, z);
|
||||
|
||||
floor -= y;
|
||||
ceiling -= y;
|
||||
@ -1168,31 +1136,32 @@ struct Lara : Item
|
||||
if (cinfo.f.floor >= -640 && cinfo.f.floor <= -384) {
|
||||
if (c_checkSpace()) return false;
|
||||
|
||||
animSet(this, ANIM_CLIMB_2, true);
|
||||
animSet(ANIM_CLIMB_2, true);
|
||||
state = HANG_UP;
|
||||
|
||||
pos.y += 512 + cinfo.f.floor;
|
||||
} else if (cinfo.f.floor >= -896 && cinfo.f.floor <= -640) {
|
||||
if (c_checkSpace()) return false;
|
||||
|
||||
animSet(this, ANIM_CLIMB_3, true);
|
||||
animSet(ANIM_CLIMB_3, true);
|
||||
state = HANG_UP;
|
||||
|
||||
pos.y += 768 + cinfo.f.floor;
|
||||
} else if (cinfo.f.floor >= -1920 && cinfo.f.floor <= -896) {
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
goalState = UP_JUMP;
|
||||
vSpeedHack = -int32(phd_sqrt(-2 * GRAVITY * (cinfo.f.floor + 800)) + 3);
|
||||
animUpdate(this);
|
||||
|
||||
updateAnim();
|
||||
} /* TODO for main branch
|
||||
else if ((waterState != WATER_STATE_WADE) && (cinfo.f.floor <= -1920) && (cinfo.l.floor <= -1920) && (cinfo.r.floor <= -1920) && (cinfo.m.ceiling <= -1158)) {
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
goalState = UP_JUMP;
|
||||
vSpeedHack = -116;
|
||||
animUpdate(this);
|
||||
}
|
||||
else if (((cinfo.f.floor < -1024) && (cinfo.f.ceiling >= 506)) || (cinfo.m.ceiling <= -518) && c_checkClimbStart()) {
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
goalState = CLIMB_START;
|
||||
processAnimation();
|
||||
}*/ else {
|
||||
@ -1228,12 +1197,12 @@ struct Lara : Item
|
||||
if (state == REACH)
|
||||
{
|
||||
if (c_checkSwing()) {
|
||||
animSet(this, ANIM_HANG_SWING, true);
|
||||
animSet(ANIM_HANG_SWING, true);
|
||||
} else {
|
||||
animSet(this, ANIM_HANG, true);
|
||||
animSet(ANIM_HANG, true);
|
||||
}
|
||||
} else {
|
||||
animSet(this, ANIM_HANG, true, 12);
|
||||
animSet(ANIM_HANG, true, 12);
|
||||
}
|
||||
|
||||
cinfo.offset.y = cinfo.f.floor - getBounds().minY;
|
||||
@ -1260,7 +1229,7 @@ struct Lara : Item
|
||||
hSpeed = 2;
|
||||
vSpeed = 1;
|
||||
|
||||
animSet(this, ANIM_FALL_FORTH, true);
|
||||
animSet(ANIM_FALL_FORTH, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1287,7 +1256,7 @@ struct Lara : Item
|
||||
|
||||
angleY += h - 5;
|
||||
|
||||
updateRoom(curItemIndex, -LARA_HEIGHT / 2);
|
||||
updateRoom(-LARA_HEIGHT / 2);
|
||||
|
||||
alignWall();
|
||||
|
||||
@ -1302,7 +1271,7 @@ struct Lara : Item
|
||||
}
|
||||
game->waterDrop(pos, 128.0f, 0.2f);
|
||||
*/
|
||||
animSet(this, ANIM_WATER_OUT, true);
|
||||
animSet(ANIM_WATER_OUT, true);
|
||||
|
||||
waterState = WATER_STATE_ABOVE;
|
||||
goalState = STOP;
|
||||
@ -1335,7 +1304,7 @@ struct Lara : Item
|
||||
if (c_checkCeiling()) return;
|
||||
|
||||
if (c_checkWall()) {
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
}
|
||||
|
||||
if (c_checkSlide()) return;
|
||||
@ -1352,7 +1321,7 @@ struct Lara : Item
|
||||
} else if (state == FORWARD_JUMP && (input & IN_UP) && !(input & IN_WALK)) {
|
||||
goalState = RUN;
|
||||
} else if (state == FALL) {
|
||||
animSet(this, ANIM_LANDING, true);
|
||||
animSet(ANIM_LANDING, true);
|
||||
} else {
|
||||
goalState = STOP;
|
||||
}
|
||||
@ -1364,7 +1333,7 @@ struct Lara : Item
|
||||
flags.gravity = false;
|
||||
|
||||
if (state == FORWARD_JUMP) {
|
||||
animUpdate(this);
|
||||
updateAnim();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1388,8 +1357,8 @@ struct Lara : Item
|
||||
vSpeed = 1;
|
||||
}
|
||||
} else if (!slide && ((cinfo.type == CT_FRONT) || (cinfo.type == CT_FRONT_CEILING))) {
|
||||
animSet(this, ANIM_SMASH_JUMP, true, 1);
|
||||
moveAngle -= ANGLE_180;
|
||||
animSet(ANIM_SMASH_JUMP, true, 1);
|
||||
moveAngle += ANGLE_180;
|
||||
hSpeed /= 4;
|
||||
if (vSpeed <= 0) {
|
||||
vSpeed = 1;
|
||||
@ -1482,7 +1451,7 @@ struct Lara : Item
|
||||
moveAngle = angleY + angleDelta;
|
||||
|
||||
if (health <= 0 || !(input & IN_ACTION)) {
|
||||
animSet(this, ANIM_FALL_HANG, true, 9);
|
||||
animSet(ANIM_FALL_HANG, true, 9);
|
||||
|
||||
cinfo.offset.y = cinfo.f.floor - getBounds().minY + 2;
|
||||
c_applyOffset();
|
||||
@ -1499,7 +1468,7 @@ struct Lara : Item
|
||||
if (noFloor || (cinfo.type != CT_FRONT) || (cinfo.m.ceiling >= 0) || abs(cinfo.r.floor - cinfo.l.floor) >= LARA_HANG_SLANT)
|
||||
{
|
||||
if (state != HANG) {
|
||||
animSet(this, ANIM_HANG, true, 21);
|
||||
animSet(ANIM_HANG, true, 21);
|
||||
}
|
||||
pos = cinfo.pos;
|
||||
return;
|
||||
@ -1532,11 +1501,11 @@ struct Lara : Item
|
||||
|
||||
if (c_checkWall()) {
|
||||
if (frameIndex >= 29 && frameIndex <= 47) {
|
||||
animSet(this, ANIM_STAND_RIGHT, false);
|
||||
animSet(ANIM_STAND_RIGHT, false);
|
||||
} else if ((frameIndex >= 22 && frameIndex <= 28) || (frameIndex >= 48 && frameIndex <= 57)) {
|
||||
animSet(this, ANIM_STAND_LEFT, false);
|
||||
animSet(ANIM_STAND_LEFT, false);
|
||||
} else {
|
||||
animSet(this, ANIM_STAND, false);
|
||||
animSet(ANIM_STAND, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1545,18 +1514,18 @@ struct Lara : Item
|
||||
// descend
|
||||
if (cinfo.m.floor > 128) {
|
||||
if (frameIndex >= 28 && frameIndex <= 45) {
|
||||
animSet(this, ANIM_WALK_DESCEND_RIGHT, false);
|
||||
animSet(ANIM_WALK_DESCEND_RIGHT, false);
|
||||
} else {
|
||||
animSet(this, ANIM_WALK_DESCEND_LEFT, false);
|
||||
animSet(ANIM_WALK_DESCEND_LEFT, false);
|
||||
}
|
||||
}
|
||||
|
||||
// ascend
|
||||
if (cinfo.m.floor >= -LARA_STEP_HEIGHT && cinfo.m.floor < -128) {
|
||||
if (frameIndex >= 27 && frameIndex <= 44) {
|
||||
animSet(this, ANIM_WALK_ASCEND_RIGHT, false);
|
||||
animSet(ANIM_WALK_ASCEND_RIGHT, false);
|
||||
} else {
|
||||
animSet(this, ANIM_WALK_ASCEND_LEFT, false);
|
||||
animSet(ANIM_WALK_ASCEND_LEFT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1584,12 +1553,12 @@ struct Lara : Item
|
||||
angleZ = 0;
|
||||
|
||||
if (cinfo.f.slantType == SLANT_NONE && cinfo.f.floor < -LARA_SMASH_HEIGHT && frameIndex < 22) {
|
||||
animSet(this, frameIndex < 10 ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT, false);
|
||||
animSet(frameIndex < 10 ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT, false);
|
||||
state = SPLAT;
|
||||
return;
|
||||
}
|
||||
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
}
|
||||
|
||||
if (c_checkFall(LARA_STEP_HEIGHT)) return;
|
||||
@ -1597,9 +1566,9 @@ struct Lara : Item
|
||||
// ascend
|
||||
if (cinfo.m.floor >= -LARA_STEP_HEIGHT && cinfo.m.floor < -128) {
|
||||
if (frameIndex >= 3 && frameIndex <= 14) {
|
||||
animSet(this, ANIM_RUN_ASCEND_RIGHT, false);
|
||||
animSet(ANIM_RUN_ASCEND_RIGHT, false);
|
||||
} else {
|
||||
animSet(this, ANIM_RUN_ASCEND_LEFT, false);
|
||||
animSet(ANIM_RUN_ASCEND_LEFT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1648,7 +1617,7 @@ struct Lara : Item
|
||||
vSpeed = 0;
|
||||
flags.gravity = false;
|
||||
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
|
||||
cinfo.gapPos = -WALL;
|
||||
cinfo.gapNeg = -LARA_STEP_HEIGHT;
|
||||
@ -1662,7 +1631,7 @@ struct Lara : Item
|
||||
if (c_checkFall(200, ANIM_FALL_BACK)) return;
|
||||
|
||||
if (c_checkWall()) {
|
||||
animSet(this, ANIM_STAND, false);
|
||||
animSet(ANIM_STAND, false);
|
||||
}
|
||||
|
||||
pos.y += cinfo.m.floor;
|
||||
@ -1753,7 +1722,7 @@ struct Lara : Item
|
||||
collideRoom(this, LARA_HEIGHT, 0);
|
||||
|
||||
if (cinfo.m.ceiling > -100) {
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
pos = cinfo.pos;
|
||||
hSpeed = 0;
|
||||
vSpeed = 0;
|
||||
@ -1766,7 +1735,7 @@ struct Lara : Item
|
||||
vSpeed = 0;
|
||||
flags.gravity = false;
|
||||
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
|
||||
cinfo.gapPos = (waterState == WATER_STATE_WADE) ? -WALL : LARA_STEP_HEIGHT;
|
||||
cinfo.gapNeg = -LARA_STEP_HEIGHT;
|
||||
@ -1779,15 +1748,15 @@ struct Lara : Item
|
||||
|
||||
if (c_checkWall())
|
||||
{
|
||||
animSet(this, ANIM_STAND, true);
|
||||
animSet(ANIM_STAND, true);
|
||||
}
|
||||
|
||||
if (cinfo.m.floor > 128 && cinfo.m.floor < LARA_STEP_HEIGHT)
|
||||
{
|
||||
if (frameIndex < 568) {
|
||||
animSet(this, ANIM_BACK_DESCEND_LEFT, false);
|
||||
animSet(ANIM_BACK_DESCEND_LEFT, false);
|
||||
} else {
|
||||
animSet(this, ANIM_BACK_DESCEND_RIGHT, false);
|
||||
animSet(ANIM_BACK_DESCEND_RIGHT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1824,7 +1793,7 @@ struct Lara : Item
|
||||
|
||||
C_HANDLER( ROLL_END )
|
||||
{
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
c_roll();
|
||||
}
|
||||
|
||||
@ -1836,7 +1805,7 @@ struct Lara : Item
|
||||
|
||||
C_HANDLER( BACK_JUMP )
|
||||
{
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
c_jump();
|
||||
}
|
||||
|
||||
@ -1860,7 +1829,7 @@ struct Lara : Item
|
||||
|
||||
C_HANDLER( FALL_BACK )
|
||||
{
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
c_jump();
|
||||
}
|
||||
|
||||
@ -1876,7 +1845,7 @@ struct Lara : Item
|
||||
|
||||
C_HANDLER( SLIDE_BACK )
|
||||
{
|
||||
c_angle(-ANGLE_180);
|
||||
c_angle(ANGLE_180);
|
||||
c_slide();
|
||||
}
|
||||
|
||||
@ -1985,6 +1954,15 @@ struct Lara : Item
|
||||
c_default();
|
||||
}
|
||||
|
||||
Lara(Room* room) : Item(room)
|
||||
{
|
||||
health = LARA_MAX_HEALTH;
|
||||
oxygen = LARA_MAX_OXYGEN;
|
||||
flags.shadow = true;
|
||||
|
||||
activate();
|
||||
}
|
||||
|
||||
// update control
|
||||
void updateInput()
|
||||
{
|
||||
@ -2003,7 +1981,7 @@ struct Lara : Item
|
||||
if ((keys & (IK_L | IK_R)) == (IK_L | IK_R)) input |= IN_LOOK;
|
||||
}
|
||||
|
||||
void update()
|
||||
virtual void update()
|
||||
{
|
||||
updateInput();
|
||||
|
||||
@ -2021,14 +1999,15 @@ struct Lara : Item
|
||||
turnSpeed = angleDec(turnSpeed, 2 * DEG2SHORT);
|
||||
angleY += turnSpeed;
|
||||
|
||||
animUpdate(this);
|
||||
|
||||
updateAnim();
|
||||
|
||||
updateCollision();
|
||||
|
||||
updateRoom(curItemIndex, -LARA_HEIGHT / 2);
|
||||
updateRoom(-LARA_HEIGHT / 2);
|
||||
|
||||
//updateWeapon();
|
||||
//checkTrigger(cinfo.trigger, false);
|
||||
|
||||
checkTrigger(cinfo.trigger, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,8 @@ extern const uint8* tiles;
|
||||
|
||||
extern uint16 palette[256];
|
||||
extern uint8 lightmap[256 * 32];
|
||||
const uint16* floors;
|
||||
|
||||
const FloorData* floors;
|
||||
|
||||
int32 texturesCount;
|
||||
extern const Texture* textures;
|
||||
@ -60,95 +61,21 @@ const uint8* soundData;
|
||||
|
||||
//int32 soundOffsetsCount;
|
||||
const uint32* soundOffsets;
|
||||
|
||||
#define MAX_DYN_SECTORS 1024
|
||||
int32 dynSectorsCount;
|
||||
EWRAM_DATA RoomInfo::Sector dynSectors[MAX_DYN_SECTORS]; // EWRAM 8k
|
||||
// -----------------------------------
|
||||
|
||||
int16 roomsCount;
|
||||
EWRAM_DATA Room rooms[64];
|
||||
|
||||
int32 firstActive = NO_ITEM;
|
||||
Item* Item::sFirstActive;
|
||||
Item* Item::sFirstFree;
|
||||
|
||||
int32 visRoomsCount;
|
||||
int32 visRooms[16];
|
||||
Room* roomsList[MAX_ROOM_LIST];
|
||||
|
||||
#define ROOM_VISIBLE (1 << 15)
|
||||
|
||||
void roomItemAdd(int32 roomIndex, int32 itemIndex)
|
||||
{
|
||||
Item* item = items + itemIndex;
|
||||
Room* room = rooms + roomIndex;
|
||||
|
||||
ASSERT(item->nextItem == NO_ITEM);
|
||||
|
||||
item->room = roomIndex;
|
||||
item->nextItem = room->firstItem;
|
||||
room->firstItem = itemIndex;
|
||||
}
|
||||
|
||||
void roomItemRemove(int32 itemIndex)
|
||||
{
|
||||
Item* item = items + itemIndex;
|
||||
Room* room = rooms + item->room;
|
||||
item->room = NO_ROOM;
|
||||
|
||||
int32 prevIndex = NO_ITEM;
|
||||
int32 index = room->firstItem;
|
||||
|
||||
while (index != NO_ITEM)
|
||||
{
|
||||
int32 next = items[index].nextItem;
|
||||
|
||||
if (index == itemIndex)
|
||||
{
|
||||
items[index].nextItem = NO_ITEM;
|
||||
|
||||
if (prevIndex == NO_ITEM) {
|
||||
room->firstItem = next;
|
||||
} else {
|
||||
items[prevIndex].nextItem = next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prevIndex = index;
|
||||
index = next;
|
||||
}
|
||||
}
|
||||
|
||||
void activateItem(int32 itemIndex)
|
||||
{
|
||||
items[itemIndex].nextActive = firstActive;
|
||||
firstActive = itemIndex;
|
||||
}
|
||||
|
||||
void deactivateItem(int32 itemIndex)
|
||||
{
|
||||
int32 prevIndex = NO_ITEM;
|
||||
int32 index = firstActive;
|
||||
|
||||
while (index != NO_ITEM)
|
||||
{
|
||||
int32 next = items[index].nextActive;
|
||||
|
||||
if (index == itemIndex)
|
||||
{
|
||||
items[index].nextItem = NO_ITEM;
|
||||
|
||||
if (prevIndex == NO_ITEM) {
|
||||
firstActive = next;
|
||||
} else {
|
||||
items[prevIndex].nextActive = next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prevIndex = index;
|
||||
index = next;
|
||||
}
|
||||
}
|
||||
|
||||
void fixLightmap(int32 palIndex)
|
||||
void fixLightmap(uint16* palette, int32 palIndex)
|
||||
{
|
||||
uint16 color = palette[palIndex];
|
||||
|
||||
@ -168,7 +95,13 @@ void fixLightmap(int32 palIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_OFF alignment bytes
|
||||
void readLevel(const uint8* data) // TODO non-hardcode level loader, added *_OFF alignment bytes
|
||||
{
|
||||
Item::sFirstActive = NULL;
|
||||
Item::sFirstFree = NULL;
|
||||
|
||||
dynSectorsCount = 0;
|
||||
|
||||
// tilesCount = *((int32*)(data + 4));
|
||||
tiles = data + 8;
|
||||
|
||||
@ -178,7 +111,7 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
roomsCount = *((int16*)(data + 720908));
|
||||
const RoomInfo* roomsPtr = (RoomInfo*)(data + 720908 + 2);
|
||||
|
||||
floors = (uint16*)(data + 899492 + 4);
|
||||
floors = (FloorData*)(data + 899492 + 4);
|
||||
|
||||
meshData = data + 908172 + 4;
|
||||
meshOffsets = (int32*)(data + 975724 + 4);
|
||||
@ -229,7 +162,7 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
// 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));
|
||||
// int32 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));
|
||||
@ -237,22 +170,38 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
|
||||
memset(items, 0, sizeof(items));
|
||||
for (int32 i = 0; i < itemsCount; i++) {
|
||||
memcpy(items + i, itemsPtr, FILE_ITEM_SIZE);
|
||||
memcpy(&items[i].type, itemsPtr, FILE_ITEM_SIZE);
|
||||
itemsPtr += FILE_ITEM_SIZE;
|
||||
}
|
||||
|
||||
// prepare free list
|
||||
for (int32 i = MAX_ITEMS - 1; i >= itemsCount; i--)
|
||||
{
|
||||
items[i].nextItem = items + i + 1;
|
||||
}
|
||||
Item::sFirstFree = items + itemsCount;
|
||||
|
||||
// prepare lightmap
|
||||
const uint8* f_lightmap = data + 1320576 + MDL_OFF + ITM_OFF;
|
||||
memcpy(lightmap, f_lightmap, sizeof(lightmap));
|
||||
|
||||
// TODO preprocess
|
||||
for (int i = 0; i < 32; i++) {
|
||||
lightmap[i * 256] = 0;
|
||||
}
|
||||
|
||||
// prepare palette
|
||||
const uint8* f_palette = data + 1328768 + MDL_OFF + ITM_OFF;
|
||||
|
||||
const uint8* p = f_palette;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
#ifdef MODE_PAL
|
||||
uint16 palette[256];
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 256; i++) // TODO preprocess
|
||||
{
|
||||
#if defined(_WIN32) || defined(__GBA__)
|
||||
#if defined(_WIN32) || defined(__GBA__) || defined(__DOS__)
|
||||
// grayscale palette
|
||||
//uint8 c = ((p[0] + p[1] + p[2]) / 3) >> 1;
|
||||
//palette[i] = c | (c << 5) | (c << 10);
|
||||
@ -266,8 +215,12 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
palette[0] = 0; // black or transparent
|
||||
|
||||
// TODO preprocess fix Laras palette
|
||||
fixLightmap(6); // boots
|
||||
fixLightmap(14); // skin
|
||||
fixLightmap(palette, 6); // boots
|
||||
fixLightmap(palette, 14); // skin
|
||||
|
||||
#ifdef MODE_PAL
|
||||
paletteSet(palette);
|
||||
#endif
|
||||
|
||||
// prepare rooms
|
||||
uint8* ptr = (uint8*)roomsPtr;
|
||||
@ -283,7 +236,7 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
|
||||
Room &desc = rooms[roomIndex];
|
||||
|
||||
desc.firstItem = NO_ITEM;
|
||||
desc.firstItem = NULL;
|
||||
|
||||
// offset
|
||||
memcpy(&desc.x, &room->x, sizeof(room->x));
|
||||
@ -320,6 +273,7 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
desc.xSectors = *((uint16*)ptr);
|
||||
ptr += 2;
|
||||
desc.sectors = (RoomInfo::Sector*)ptr;
|
||||
desc.sectorsOrig = desc.sectors;
|
||||
ptr += sizeof(RoomInfo::Sector) * desc.zSectors * desc.xSectors;
|
||||
|
||||
desc.ambient = *((uint16*)ptr);
|
||||
@ -355,319 +309,4 @@ void readLevel(const uint8* data) { // TODO non-hardcode level loader, added *_O
|
||||
}
|
||||
}
|
||||
|
||||
int32 getBridgeFloor(const Item* item, int32 x, int32 z)
|
||||
{
|
||||
if (item->type == ITEM_BRIDGE_1) {
|
||||
return item->pos.y;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
case ITEM_DRAWBRIDGE:
|
||||
{
|
||||
if (item->state == 1) {
|
||||
h = getDrawBridgeFloor(item, x, z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ITEM_BRIDGE_1:
|
||||
case ITEM_BRIDGE_2:
|
||||
case ITEM_BRIDGE_3:
|
||||
{
|
||||
h = getBridgeFloor(item, x, z);
|
||||
break;
|
||||
}
|
||||
case ITEM_TRAP_DOOR_1:
|
||||
case ITEM_TRAP_DOOR_2:
|
||||
{
|
||||
if (item->state == 0) {
|
||||
h = getTrapDoorFloor(item, x, z);
|
||||
}
|
||||
|
||||
if ((floor && (h >= *floor)) || (ceiling && (h <= *ceiling)))
|
||||
{
|
||||
h = WALL;
|
||||
}
|
||||
}
|
||||
default : return;
|
||||
}
|
||||
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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, x, z);
|
||||
}
|
||||
|
||||
while (sector->roomBelow != NO_ROOM && y >= (sector->floor << 8))
|
||||
{
|
||||
roomIndex = sector->roomBelow;
|
||||
sector = getSector(roomIndex, x, z);
|
||||
}
|
||||
|
||||
return roomIndex;
|
||||
}
|
||||
|
||||
void getTriggerFloorData(const RoomInfo::Sector* sector, int32 x, int32 y, int32 z, int32* floor, int32* ceiling)
|
||||
{
|
||||
if (!sector->floorIndex)
|
||||
return;
|
||||
|
||||
FloorData::Command cmd;
|
||||
FloorData* fd = (FloorData*)(floors + sector->floorIndex);
|
||||
|
||||
do {
|
||||
cmd = (fd++)->cmd;
|
||||
|
||||
switch (cmd.func)
|
||||
{
|
||||
case FLOOR_TYPE_PORTAL:
|
||||
case FLOOR_TYPE_FLOOR:
|
||||
case FLOOR_TYPE_CEILING:
|
||||
{
|
||||
fd++;
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOOR_TYPE_TRIGGER:
|
||||
{
|
||||
fd++;
|
||||
FloorData::TriggerCommand trigger;
|
||||
|
||||
do {
|
||||
trigger = (fd++)->triggerCmd;
|
||||
|
||||
if (trigger.action == TRIGGER_ACTION_ACTIVATE)
|
||||
{
|
||||
getItemFloorData(items + trigger.args, x, y, z, floor, ceiling);
|
||||
}
|
||||
|
||||
if (trigger.action == TRIGGER_ACTION_CAMERA_SWITCH)
|
||||
{
|
||||
trigger = (fd++)->triggerCmd; // skip camera index
|
||||
}
|
||||
|
||||
} 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)
|
||||
{
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(sector, x, z);
|
||||
|
||||
int32 floor = lowerSector->floor << 8;
|
||||
|
||||
floorSlant.value = 0;
|
||||
|
||||
if (lowerSector->floorIndex)
|
||||
{
|
||||
FloorData* fd = (FloorData*)(floors + lowerSector->floorIndex);
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // found floor
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
getTriggerFloorData(lowerSector, x, y, z, &floor, NULL);
|
||||
|
||||
return floor;
|
||||
}
|
||||
|
||||
int32 getCeiling(const RoomInfo::Sector* sector, int32 x, int32 y, int32 z)
|
||||
{
|
||||
const RoomInfo::Sector* upperSector = getSectorAbove(sector, x, z);
|
||||
|
||||
int32 ceiling = upperSector->ceiling << 8;
|
||||
|
||||
if (upperSector->floorIndex)
|
||||
{
|
||||
FloorData* fd = (FloorData*)(floors + upperSector->floorIndex);
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor
|
||||
{
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_CEILING) // found ceiling
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(sector, x, z);
|
||||
|
||||
getTriggerFloorData(lowerSector, x, y, z, NULL, &ceiling);
|
||||
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,9 @@
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32) || defined(__DOS__)
|
||||
void* LEVEL1_PHD;
|
||||
void* TRACK_13_WAV;
|
||||
#elif defined(__GBA__)
|
||||
#include "LEVEL1_PHD.h"
|
||||
#include "TRACK_13_WAV.h"
|
||||
#elif defined(__TNS__)
|
||||
void* LEVEL1_PHD;
|
||||
#endif
|
||||
@ -10,8 +12,16 @@
|
||||
|
||||
Game game;
|
||||
|
||||
int32 fps;
|
||||
int32 frameIndex = 0;
|
||||
int32 fpsCounter = 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
uint32 SCREEN[FRAME_WIDTH * FRAME_HEIGHT];
|
||||
#ifdef MODE_PAL
|
||||
uint32 SCREEN[FRAME_WIDTH * FRAME_HEIGHT];
|
||||
#else
|
||||
uint32 SCREEN[VRAM_WIDTH * FRAME_HEIGHT];
|
||||
#endif
|
||||
|
||||
HWND hWnd;
|
||||
|
||||
@ -20,8 +30,22 @@ Game game;
|
||||
|
||||
#define WND_WIDTH 240*4
|
||||
#define WND_HEIGHT 160*4
|
||||
|
||||
#ifdef MODE_PAL
|
||||
uint16 MEM_PAL_BG[256];
|
||||
#endif
|
||||
|
||||
void paletteSet(uint16* palette)
|
||||
{
|
||||
#ifdef MODE_PAL
|
||||
memcpy(MEM_PAL_BG, palette, 256 * 2);
|
||||
#endif
|
||||
}
|
||||
#elif defined(__GBA__)
|
||||
//
|
||||
void paletteSet(uint16* palette)
|
||||
{
|
||||
memcpy((uint16*)MEM_PAL_BG, palette, 256 * 2);
|
||||
}
|
||||
#elif defined(__TNS__)
|
||||
unsigned int osTime;
|
||||
volatile unsigned int *timerBUS;
|
||||
@ -48,16 +72,20 @@ Game game;
|
||||
return (osTime - *timerCLK) / 33;
|
||||
}
|
||||
|
||||
void SetPalette(unsigned short* palette)
|
||||
void paletteSet(uint16* palette)
|
||||
{
|
||||
unsigned short *palReg = (unsigned short*)0xC0000200;
|
||||
memcpy(palReg, palette, 256 * 2);
|
||||
memcpy((uint16*)0xC0000200, palette, 256 * 2);
|
||||
}
|
||||
|
||||
touchpad_info_t* touchInfo;
|
||||
touchpad_report_t touchReport;
|
||||
uint8 inputData[0x20];
|
||||
|
||||
bool keyDown(const t_key &key)
|
||||
{
|
||||
return (*(short*)(inputData + key.tpad_row)) & key.tpad_col;
|
||||
}
|
||||
|
||||
void inputInit()
|
||||
{
|
||||
touchInfo = is_touchpad ? touchpad_getinfo() : NULL;
|
||||
@ -65,24 +93,154 @@ Game game;
|
||||
|
||||
void inputUpdate()
|
||||
{
|
||||
keys = 0;
|
||||
|
||||
if (touchInfo)
|
||||
{
|
||||
touchpad_scan(&touchReport);
|
||||
}
|
||||
|
||||
memcpy(inputData, (void*)0x900E0000, 0x20);
|
||||
|
||||
if (touchInfo && touchReport.contact)
|
||||
{
|
||||
float tx = float(touchReport.x) / float(touchInfo->width) * 2.0f - 1.0f;
|
||||
float ty = float(touchReport.y) / float(touchInfo->height) * 2.0f - 1.0f;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#elif defined(__DOS__)
|
||||
#define KB_ESC 1
|
||||
#define KB_A 30
|
||||
#define KB_S 31
|
||||
#define KB_Z 44
|
||||
#define KB_X 45
|
||||
#define KB_UP 72
|
||||
#define KB_LEFT 75
|
||||
#define KB_RIGHT 77
|
||||
#define KB_DOWN 80
|
||||
#define KB_ENTER 20
|
||||
#define KB_TAB 15
|
||||
|
||||
#define DOS_ISR __interrupt __far
|
||||
|
||||
#define PIT_TIMER 0x08
|
||||
#define PIT_KEYBOARD 0x09
|
||||
|
||||
|
||||
void (DOS_ISR *old_timerISR)();
|
||||
void (DOS_ISR *old_keyISR)();
|
||||
|
||||
bool keyState[128];
|
||||
|
||||
void setVideoMode();
|
||||
#pragma aux setVideoMode = \
|
||||
"mov ax,13h" \
|
||||
"int 10h";
|
||||
|
||||
void setTextMode();
|
||||
#pragma aux setTextMode = \
|
||||
"mov ax,03h" \
|
||||
"int 10h";
|
||||
|
||||
void paletteSet(uint16* palette)
|
||||
{
|
||||
outp(0x03C8, 0);
|
||||
for (int32 i = 0; i < 256; i++)
|
||||
{
|
||||
uint16 c = *palette++;
|
||||
outp(0x03C9, (c & 0x1F) << 1);
|
||||
outp(0x03C9, ((c >> 5) & 0x1F) << 1);
|
||||
outp(0x03C9, ((c >> 10) & 0x1F) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool keyDown(const t_key &key)
|
||||
void DOS_ISR timerISR()
|
||||
{
|
||||
return (*(short*)(inputData + key.tpad_row)) & key.tpad_col;
|
||||
frameIndex++;
|
||||
|
||||
outp(0x20, 0x20);
|
||||
}
|
||||
|
||||
void videoAcquire()
|
||||
{
|
||||
setVideoMode();
|
||||
|
||||
old_timerISR = _dos_getvect(PIT_TIMER);
|
||||
_dos_setvect(PIT_TIMER, timerISR);
|
||||
|
||||
uint32 divisor = 1193182 / 60;
|
||||
outp(0x43, 0x36);
|
||||
outp(0x40, divisor & 0xFF);
|
||||
outp(0x40, divisor >> 8);
|
||||
}
|
||||
|
||||
void videoRelease()
|
||||
{
|
||||
_dos_setvect(PIT_TIMER, old_timerISR);
|
||||
setTextMode();
|
||||
}
|
||||
|
||||
void waitVBlank()
|
||||
{
|
||||
while ((inp(0x03DA) & 0x08));
|
||||
while (!(inp(0x03DA) & 0x08));
|
||||
}
|
||||
|
||||
void blit()
|
||||
{
|
||||
memcpy((uint8*)0xA0000, fb, VRAM_WIDTH * FRAME_HEIGHT * 2);
|
||||
}
|
||||
|
||||
void DOS_ISR keyISR()
|
||||
{
|
||||
uint32 scancode = inp(0x60);
|
||||
|
||||
if (scancode != 0xE0) {
|
||||
keyState[scancode & 0x7F] = ((scancode & 0x80) == 0);
|
||||
}
|
||||
|
||||
outp(0x20, 0x20);
|
||||
}
|
||||
|
||||
void inputAcquire()
|
||||
{
|
||||
old_keyISR = _dos_getvect(PIT_KEYBOARD);
|
||||
_dos_setvect(PIT_KEYBOARD, keyISR);
|
||||
}
|
||||
|
||||
void inputRelease()
|
||||
{
|
||||
_dos_setvect(PIT_KEYBOARD, old_keyISR);
|
||||
}
|
||||
|
||||
void inputUpdate()
|
||||
{
|
||||
keys = 0;
|
||||
if (keyState[KB_UP]) keys |= IK_UP;
|
||||
if (keyState[KB_RIGHT]) keys |= IK_RIGHT;
|
||||
if (keyState[KB_DOWN]) keys |= IK_DOWN;
|
||||
if (keyState[KB_LEFT]) keys |= IK_LEFT;
|
||||
if (keyState[KB_X]) keys |= IK_A;
|
||||
if (keyState[KB_Z]) keys |= IK_B;
|
||||
if (keyState[KB_A]) keys |= IK_L;
|
||||
if (keyState[KB_S]) keys |= IK_R;
|
||||
if (keyState[KB_ENTER]) keys |= IK_START;
|
||||
if (keyState[KB_TAB]) keys |= IK_SELECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32 fps;
|
||||
int32 frameIndex = 0;
|
||||
int32 fpsCounter = 0;
|
||||
|
||||
#ifdef PROFILE
|
||||
uint32 dbg_transform;
|
||||
uint32 dbg_poly;
|
||||
@ -91,7 +249,11 @@ int32 fpsCounter = 0;
|
||||
uint32 dbg_poly_count;
|
||||
#endif
|
||||
|
||||
EWRAM_DATA ALIGN16 uint8 soundBuffer[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
||||
EWRAM_DATA ALIGN16 uint8 soundBufferA[2 * SND_SAMPLES + 32]; // 32 bytes of silence for DMA overrun while interrupt
|
||||
#ifdef USE_9BIT_SOUND
|
||||
EWRAM_DATA ALIGN16 uint8 soundBufferB[2 * SND_SAMPLES + 32]; // for 9-bit mixer support via Direct Mixer B channel
|
||||
#endif
|
||||
|
||||
uint32 curSoundBuffer = 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
@ -100,7 +262,7 @@ WAVEFORMATEX waveFmt = { WAVE_FORMAT_PCM, 1, SND_OUTPUT_FREQ, SND_OUTPUT_FREQ, 1
|
||||
WAVEHDR waveBuf[2];
|
||||
|
||||
void soundInit() {
|
||||
sound.init();
|
||||
mixer.init();
|
||||
|
||||
if (waveOutOpen(&waveOut, WAVE_MAPPER, &waveFmt, (INT_PTR)hWnd, 0, CALLBACK_WINDOW) != MMSYSERR_NOERROR) {
|
||||
return;
|
||||
@ -110,7 +272,7 @@ void soundInit() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
WAVEHDR *waveHdr = waveBuf + i;
|
||||
waveHdr->dwBufferLength = SND_SAMPLES;
|
||||
waveHdr->lpData = (LPSTR)(soundBuffer + i * SND_SAMPLES);
|
||||
waveHdr->lpData = (LPSTR)(soundBufferA + i * SND_SAMPLES);
|
||||
waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
}
|
||||
@ -119,7 +281,7 @@ void soundInit() {
|
||||
void soundFill() {
|
||||
WAVEHDR *waveHdr = waveBuf + curSoundBuffer;
|
||||
waveOutUnprepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
sound.fill((uint8*)waveHdr->lpData, SND_SAMPLES);
|
||||
mixer.fill((uint8*)waveHdr->lpData, NULL, SND_SAMPLES);
|
||||
waveOutPrepareHeader(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
waveOutWrite(waveOut, waveHdr, sizeof(WAVEHDR));
|
||||
curSoundBuffer ^= 1;
|
||||
@ -127,24 +289,41 @@ void soundFill() {
|
||||
#elif defined(__GBA__)
|
||||
void soundInit()
|
||||
{
|
||||
sound.init();
|
||||
mixer.init();
|
||||
|
||||
REG_SOUNDCNT_X = SSTAT_ENABLE;
|
||||
REG_SOUNDCNT_H = SDS_ATMR0 | SDS_A100 | SDS_AL | SDS_AR | SDS_ARESET;
|
||||
#ifdef USE_9BIT_SOUND
|
||||
REG_SOUNDCNT_H |= SDS_BTMR0 | SDS_B100 | SDS_BL | SDS_BR | SDS_BRESET;
|
||||
#endif
|
||||
REG_TM0D = 65536 - (16777216 / SND_OUTPUT_FREQ);
|
||||
REG_TM0CNT = TM_ENABLE;
|
||||
REG_DMA1DAD = (u32)®_FIFO_A;
|
||||
#ifdef USE_9BIT_SOUND
|
||||
REG_DMA2DAD = (u32)®_FIFO_B;
|
||||
#endif
|
||||
}
|
||||
|
||||
void soundFill()
|
||||
{
|
||||
if (curSoundBuffer == 1) {
|
||||
REG_DMA1CNT = 0;
|
||||
REG_DMA1SAD = (u32)soundBuffer;
|
||||
REG_DMA1SAD = (u32)soundBufferA;
|
||||
REG_DMA1CNT = DMA_DST_FIXED | DMA_REPEAT | DMA_16 | DMA_AT_FIFO | DMA_ENABLE;
|
||||
#ifdef USE_9BIT_SOUND
|
||||
REG_DMA2CNT = 0;
|
||||
REG_DMA2SAD = (u32)soundBufferB;
|
||||
REG_DMA2CNT = DMA_DST_FIXED | DMA_REPEAT | DMA_16 | DMA_AT_FIFO | DMA_ENABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
sound.fill(soundBuffer + curSoundBuffer * SND_SAMPLES, SND_SAMPLES);
|
||||
mixer.fill(soundBufferA + curSoundBuffer * SND_SAMPLES,
|
||||
#ifdef USE_9BIT_SOUND
|
||||
soundBufferB + curSoundBuffer * SND_SAMPLES,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
SND_SAMPLES);
|
||||
curSoundBuffer ^= 1;
|
||||
}
|
||||
#endif
|
||||
@ -153,7 +332,14 @@ void soundFill()
|
||||
HDC hDC;
|
||||
|
||||
void blit() {
|
||||
#ifdef ROTATE90_MODE
|
||||
#ifdef MODE_PAL
|
||||
for (int i = 0; i < FRAME_WIDTH * FRAME_HEIGHT; i++) {
|
||||
uint16 c = MEM_PAL_BG[((uint8*)fb)[i]];
|
||||
SCREEN[i] = (((c << 3) & 0xFF) << 16) | ((((c >> 5) << 3) & 0xFF) << 8) | ((c >> 10 << 3) & 0xFF) | 0xFF000000;
|
||||
}
|
||||
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);
|
||||
#elif defined(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;
|
||||
@ -163,11 +349,11 @@ void blit() {
|
||||
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++) {
|
||||
for (int i = 0; i < VRAM_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), FRAME_WIDTH, -FRAME_HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
|
||||
const BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), VRAM_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
|
||||
}
|
||||
@ -180,8 +366,10 @@ LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_KEYDOWN :
|
||||
case WM_KEYUP :
|
||||
case WM_KEYDOWN :
|
||||
case WM_KEYUP :
|
||||
case WM_SYSKEYUP :
|
||||
case WM_SYSKEYDOWN :
|
||||
{
|
||||
InputKey key = IK_NONE;
|
||||
switch (wParam) {
|
||||
@ -197,7 +385,7 @@ LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
case VK_SPACE : key = IK_SELECT; break;
|
||||
}
|
||||
|
||||
if (msg != WM_KEYUP) {
|
||||
if (msg != WM_KEYUP && msg != WM_SYSKEYUP) {
|
||||
keys |= key;
|
||||
} else {
|
||||
keys &= ~key;
|
||||
@ -227,9 +415,10 @@ void vblank() {
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
#if defined(_WIN32) || defined(__TNS__)
|
||||
#if defined(_WIN32) || defined(__TNS__) || defined(__DOS__)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
// level1
|
||||
#if defined(_WIN32) || defined(__DOS__)
|
||||
FILE *f = fopen("data/LEVEL1.PHD", "rb");
|
||||
#elif defined(__TNS__)
|
||||
FILE *f = fopen("/documents/OpenLara/LEVEL1.PHD.tns", "rb");
|
||||
@ -247,14 +436,29 @@ int main(void) {
|
||||
LEVEL1_PHD = new uint8[size];
|
||||
fread(LEVEL1_PHD, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
// track 13
|
||||
#if defined(_WIN32) || defined(__DOS__)
|
||||
{
|
||||
FILE *f = fopen("data/TRACK_13.WAV", "rb");
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
int32 size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
TRACK_13_WAV = new uint8[size];
|
||||
fread(TRACK_13_WAV, 1, size, f);
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#elif defined(__GBA__)
|
||||
// set low latency mode via WAITCNT register (thanks to GValiente)
|
||||
REG_WSCNT = WS_ROM0_N2 | WS_ROM0_S1 | WS_PREFETCH;
|
||||
#endif
|
||||
|
||||
game.init();
|
||||
|
||||
#if defined(_WIN32)
|
||||
RECT r = { 0, 0, WND_WIDTH, WND_HEIGHT };
|
||||
|
||||
@ -270,6 +474,8 @@ int main(void) {
|
||||
|
||||
soundInit();
|
||||
|
||||
game.init();
|
||||
|
||||
MSG msg;
|
||||
|
||||
int startTime = GetTickCount() - 33;
|
||||
@ -280,7 +486,6 @@ int main(void) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
|
||||
int frame = (GetTickCount() - startTime) / 33;
|
||||
game.update(frame - lastFrame);
|
||||
lastFrame = frame;
|
||||
@ -303,17 +508,25 @@ int main(void) {
|
||||
|
||||
soundInit();
|
||||
|
||||
uint16 mode = DCNT_MODE5 | DCNT_BG2 | DCNT_PAGE;
|
||||
game.init();
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
uint16 mode = DCNT_BG2 | DCNT_PAGE;
|
||||
|
||||
#ifdef MODE4
|
||||
mode |= DCNT_MODE4;
|
||||
REG_BG2PA = (1 << 8);
|
||||
REG_BG2PD = (1 << 8);
|
||||
#elif defined(ROTATE90_MODE)
|
||||
mode |= DCNT_MODE5;
|
||||
REG_BG2PA = 0;
|
||||
REG_BG2PB = (1 << 8);
|
||||
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;
|
||||
mode |= DCNT_MODE5;
|
||||
REG_BG2PA = (1 << 7);
|
||||
REG_BG2PD = (1 << 7);
|
||||
#endif
|
||||
|
||||
int32 lastFrameIndex = -1;
|
||||
@ -365,41 +578,19 @@ int main(void) {
|
||||
timerInit();
|
||||
inputInit();
|
||||
|
||||
game.init();
|
||||
|
||||
int startTime = GetTickCount();
|
||||
int lastTime = -16;
|
||||
int fpsTime = startTime;
|
||||
|
||||
memset(keys, 0, sizeof(keys));
|
||||
|
||||
while (1)
|
||||
{
|
||||
inputUpdate();
|
||||
|
||||
if (keyDown(KEY_NSPIRE_ESC))
|
||||
{
|
||||
keys = 0;
|
||||
|
||||
inputUpdate();
|
||||
|
||||
if (keyDown(KEY_NSPIRE_ESC))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (touchInfo && touchReport.contact)
|
||||
{
|
||||
float tx = float(touchReport.x) / float(touchInfo->width) * 2.0f - 1.0f;
|
||||
float ty = float(touchReport.y) / float(touchInfo->height) * 2.0f - 1.0f;
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
int time = GetTickCount() - startTime;
|
||||
@ -419,5 +610,44 @@ int main(void) {
|
||||
fpsTime = lastTime - ((lastTime - fpsTime) - 1000);
|
||||
}
|
||||
}
|
||||
#elif defined(__DOS__)
|
||||
videoAcquire();
|
||||
inputAcquire();
|
||||
|
||||
game.init();
|
||||
|
||||
int32 lastFrameIndex = -1;
|
||||
|
||||
//int extraFrame = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
inputUpdate();
|
||||
|
||||
if (keyState[KB_ESC])
|
||||
break;
|
||||
|
||||
int32 frame = frameIndex / 2;
|
||||
game.update(frame - lastFrameIndex);
|
||||
lastFrameIndex = frame;
|
||||
|
||||
game.render();
|
||||
|
||||
fpsCounter++;
|
||||
if (frameIndex >= 60) {
|
||||
frameIndex -= 60;
|
||||
lastFrameIndex -= 30;
|
||||
|
||||
fps = fpsCounter;
|
||||
|
||||
fpsCounter = 0;
|
||||
}
|
||||
|
||||
blit();
|
||||
}
|
||||
|
||||
inputRelease();
|
||||
videoRelease();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
432
src/platform/gba/object.h
Normal file
432
src/platform/gba/object.h
Normal file
@ -0,0 +1,432 @@
|
||||
#ifndef H_OBJECT
|
||||
#define H_OBJECT
|
||||
|
||||
#include "item.h"
|
||||
#include "lara.h"
|
||||
|
||||
vec3i getBlockOffset(int16 angleY, int32 offset)
|
||||
{
|
||||
if (angleY == ANGLE_0)
|
||||
return vec3i(0, 0, -offset);
|
||||
if (angleY == ANGLE_180)
|
||||
return vec3i(0, 0, offset);
|
||||
if (angleY == ANGLE_90)
|
||||
return vec3i(-offset, 0, 0);
|
||||
return vec3i(offset, 0, 0);
|
||||
}
|
||||
|
||||
struct Limit
|
||||
{
|
||||
Box box;
|
||||
vec3s angle;
|
||||
};
|
||||
|
||||
namespace Limits
|
||||
{
|
||||
static const Limit SWITCH = {
|
||||
Box( -200, 200, 0, 0, 312, 512 ),
|
||||
vec3s( 10 * DEG2SHORT, 30 * DEG2SHORT, 10 * DEG2SHORT )
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct Object : Item
|
||||
{
|
||||
Object(Room* room) : Item(room) {}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
bool isActive()
|
||||
{
|
||||
if ((flags.mask != ITEM_FLAGS_MASK_ALL) || (timer == -1))
|
||||
return flags.reverse == 1;
|
||||
|
||||
if (timer == 0)
|
||||
return flags.reverse == 0;
|
||||
|
||||
timer--;
|
||||
|
||||
if (timer == 0)
|
||||
timer = -1;
|
||||
|
||||
return flags.reverse == 0;
|
||||
}
|
||||
|
||||
bool checkLimit(Lara* lara, const Limit& limit)
|
||||
{
|
||||
int16 ax = abs(lara->angleX - angleX);
|
||||
int16 ay = abs(lara->angleY - angleY);
|
||||
int16 az = abs(lara->angleZ - angleZ);
|
||||
|
||||
if (ax > limit.angle.x || ay > limit.angle.y || az > limit.angle.z)
|
||||
return false;
|
||||
|
||||
vec3i d = lara->pos - pos;
|
||||
|
||||
matrixSetIdentity();
|
||||
matrixRotateZXY(-angleX, -angleY, -angleZ);
|
||||
const Matrix &m = matrixGet();
|
||||
|
||||
vec3i p;
|
||||
p.x = DP33(m[0], d) >> FIXED_SHIFT;
|
||||
p.y = DP33(m[1], d) >> FIXED_SHIFT;
|
||||
p.z = DP33(m[2], d) >> FIXED_SHIFT;
|
||||
|
||||
return boxContains(limit.box, p);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ViewTarget : Object
|
||||
{
|
||||
ViewTarget(Room* room) : Object(room) {}
|
||||
|
||||
virtual void draw() {}
|
||||
};
|
||||
|
||||
|
||||
struct Door : Object
|
||||
{
|
||||
enum {
|
||||
STATE_CLOSE,
|
||||
STATE_OPEN,
|
||||
};
|
||||
|
||||
Door(Room* room) : Object(room)
|
||||
{
|
||||
flags.collision = true;
|
||||
action(true);
|
||||
}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
if (isActive()) {
|
||||
if (state == STATE_CLOSE) {
|
||||
goalState = STATE_OPEN;
|
||||
} else {
|
||||
action(false);
|
||||
}
|
||||
} else {
|
||||
if (state == STATE_OPEN) {
|
||||
goalState = STATE_CLOSE;
|
||||
} else {
|
||||
action(true);
|
||||
}
|
||||
}
|
||||
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
virtual void collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
UNUSED(lara);
|
||||
UNUSED(cinfo);
|
||||
}
|
||||
|
||||
void action(bool close)
|
||||
{
|
||||
vec3i nextPos = getBlockOffset(angleY, 1);
|
||||
nextPos.x = pos.x + (nextPos.x << 10);
|
||||
nextPos.z = pos.z + (nextPos.z << 10);
|
||||
|
||||
activate(close, false, room, nextPos.x, nextPos.z); // use the sector behind the door
|
||||
|
||||
// TODO flip rooms
|
||||
}
|
||||
|
||||
void activate(bool close, bool behind, Room* room, int32 x, int32 z)
|
||||
{
|
||||
room->modify(); // make room->sectors dynamic (non ROM)
|
||||
|
||||
RoomInfo::Sector* sector = (RoomInfo::Sector*)room->getSector(x, z); // now we can modify room sectors
|
||||
|
||||
Room* nextRoom;
|
||||
|
||||
if (close) {
|
||||
nextRoom = sector->getNextRoom();
|
||||
|
||||
sector->floorIndex = 0;
|
||||
sector->boxIndex = NO_BOX;
|
||||
sector->roomBelow = NO_ROOM;
|
||||
sector->floor = NO_FLOOR;
|
||||
sector->roomAbove = NO_ROOM;
|
||||
sector->ceiling = NO_FLOOR;
|
||||
} else {
|
||||
*sector = room->sectorsOrig[sector - room->sectors];
|
||||
|
||||
nextRoom = sector->getNextRoom();
|
||||
}
|
||||
|
||||
if (!behind && nextRoom) {
|
||||
activate(close, true, nextRoom, pos.x, pos.z); // use sector from item pos
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Switch : Object
|
||||
{
|
||||
enum {
|
||||
STATE_UP,
|
||||
STATE_DOWN,
|
||||
};
|
||||
|
||||
Switch(Room* room) : Object(room) {}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
flags.mask |= ITEM_FLAGS_MASK_ALL;
|
||||
if (!isActive())
|
||||
{
|
||||
goalState = STATE_DOWN;
|
||||
timer = 0;
|
||||
}
|
||||
Object::update();
|
||||
}
|
||||
|
||||
virtual void collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
UNUSED(cinfo);
|
||||
|
||||
if (!(lara->input & IN_ACTION))
|
||||
return;
|
||||
|
||||
if (lara->state != Lara::STOP)
|
||||
return;
|
||||
|
||||
if (flags.status != ITEM_FLAGS_STATUS_NONE)
|
||||
return;
|
||||
|
||||
if (!checkLimit(lara, Limits::SWITCH))
|
||||
return;
|
||||
|
||||
lara->angleY = angleY;
|
||||
|
||||
ASSERT(state == STATE_DOWN || state == STATE_UP);
|
||||
|
||||
if (state == STATE_DOWN) {
|
||||
lara->goalState = Lara::SWITCH_DOWN;
|
||||
goalState = STATE_UP;
|
||||
} else {
|
||||
lara->goalState = Lara::SWITCH_UP;
|
||||
goalState = STATE_DOWN;
|
||||
}
|
||||
|
||||
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
|
||||
activate();
|
||||
|
||||
lara->skipAnim();
|
||||
|
||||
updateAnim();
|
||||
|
||||
lara->goalState = Lara::STOP;
|
||||
}
|
||||
|
||||
bool use(int32 t)
|
||||
{
|
||||
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
|
||||
{
|
||||
if (t > 0 && state == Switch::STATE_UP)
|
||||
{
|
||||
if (t != 1) {
|
||||
t *= 30;
|
||||
}
|
||||
timer = t;
|
||||
flags.status = ITEM_FLAGS_STATUS_ACTIVE;
|
||||
} else {
|
||||
deactivate();
|
||||
flags.status = ITEM_FLAGS_STATUS_NONE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct SwitchWater : Switch
|
||||
{
|
||||
SwitchWater(Room* room) : Switch(room) {}
|
||||
|
||||
virtual void collide(Lara* lara, CollisionInfo* cinfo)
|
||||
{
|
||||
UNUSED(lara);
|
||||
UNUSED(cinfo);
|
||||
// TODO
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Key : Object
|
||||
{
|
||||
Key(Room* room) : Object(room) {}
|
||||
|
||||
bool use()
|
||||
{
|
||||
if (flags.status == ITEM_FLAGS_STATUS_ACTIVE) // TODO check weapons
|
||||
{
|
||||
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Pickup : Object
|
||||
{
|
||||
Pickup(Room* room) : Object(room) {}
|
||||
|
||||
bool use()
|
||||
{
|
||||
if (flags.status == ITEM_FLAGS_STATUS_INVISIBLE)
|
||||
{
|
||||
flags.status = ITEM_FLAGS_STATUS_INACTIVE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool useSwitch(Item* item, int32 timer)
|
||||
{
|
||||
return ((Switch*)item)->use(timer);
|
||||
}
|
||||
|
||||
bool useKey(Item* item)
|
||||
{
|
||||
return ((Key*)item)->use();
|
||||
}
|
||||
|
||||
bool usePickup(Item* item)
|
||||
{
|
||||
return ((Pickup*)item)->use();
|
||||
}
|
||||
|
||||
|
||||
struct TrapFloor : Object
|
||||
{
|
||||
enum {
|
||||
STATE_STATIC,
|
||||
STATE_SHAKE,
|
||||
STATE_FALL,
|
||||
STATE_DOWN,
|
||||
};
|
||||
|
||||
TrapFloor(Room* room) : Object(room) {}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case STATE_STATIC:
|
||||
if (getLara(pos)->pos.y != pos.y - 512)
|
||||
{
|
||||
flags.status = ITEM_FLAGS_STATUS_NONE;
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
goalState = STATE_SHAKE;
|
||||
break;
|
||||
case STATE_SHAKE:
|
||||
goalState = STATE_FALL;
|
||||
break;
|
||||
case STATE_FALL:
|
||||
if (goalState != STATE_DOWN)
|
||||
{
|
||||
flags.gravity = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
updateAnim();
|
||||
|
||||
if (flags.status == ITEM_FLAGS_STATUS_INACTIVE)
|
||||
{
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
updateRoom();
|
||||
|
||||
if (state == STATE_FALL && pos.y >= floor)
|
||||
{
|
||||
pos.y = floor;
|
||||
vSpeed = 0;
|
||||
flags.gravity = false;
|
||||
goalState = STATE_DOWN;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Dart : Object
|
||||
{
|
||||
Dart(Room* room) : Object(room)
|
||||
{
|
||||
flags.shadow = true;
|
||||
|
||||
soundPlay(SND_DART, pos);
|
||||
// TODO create smoke
|
||||
}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
// TODO collide with Lara
|
||||
|
||||
updateAnim();
|
||||
updateRoom();
|
||||
|
||||
if (pos.y >= floor)
|
||||
{
|
||||
// TODO create spark
|
||||
remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TrapDartEmitter : Object
|
||||
{
|
||||
enum {
|
||||
STATE_IDLE,
|
||||
STATE_FIRE
|
||||
};
|
||||
|
||||
TrapDartEmitter(Room* room) : Object(room) {}
|
||||
|
||||
virtual void update()
|
||||
{
|
||||
goalState = isActive() ? STATE_FIRE : STATE_IDLE;
|
||||
|
||||
if (state == STATE_IDLE && state == goalState)
|
||||
{
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == STATE_FIRE && frameIndex == anims[animIndex].frameBegin)
|
||||
{
|
||||
vec3i p = getBlockOffset(angleY, 412);
|
||||
p.y = -512;
|
||||
p += pos;
|
||||
|
||||
Item* dart = Item::add(ITEM_DART, room, p, angleY);
|
||||
|
||||
if (dart)
|
||||
{
|
||||
dart->flags.status = ITEM_FLAGS_STATUS_ACTIVE;
|
||||
dart->activate();
|
||||
}
|
||||
}
|
||||
|
||||
updateAnim();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
296
src/platform/gba/rasterizeFTA_mode4.s
Normal file
296
src/platform/gba/rasterizeFTA_mode4.s
Normal file
@ -0,0 +1,296 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
LMAP .req r3
|
||||
|
||||
TILE .req r4
|
||||
tmp .req r5
|
||||
N .req r6
|
||||
Lh .req r7
|
||||
Rh .req r8
|
||||
|
||||
Lx .req ip
|
||||
Rx .req lr
|
||||
Lt .req r9
|
||||
Rt .req r10
|
||||
h .req r11
|
||||
|
||||
Ldx .req h
|
||||
Rdx .req h
|
||||
|
||||
Ldt .req h
|
||||
Rdt .req h
|
||||
|
||||
indexA .req Lh
|
||||
indexB .req Rh
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
|
||||
inv .req Lh
|
||||
DIVLUT .req N
|
||||
DIVLUTi .req L
|
||||
width .req N
|
||||
t .req L
|
||||
dtdx .req R
|
||||
|
||||
duv .req R
|
||||
du .req L
|
||||
dv .req R
|
||||
|
||||
Lduv .req h
|
||||
Ldu .req N
|
||||
Ldv .req h
|
||||
|
||||
Rduv .req h
|
||||
Rdu .req N
|
||||
Rdv .req h
|
||||
|
||||
SP_LDX = 0
|
||||
SP_LDT = 4
|
||||
SP_RDX = 8
|
||||
SP_RDT = 12
|
||||
|
||||
.macro PUT_PIXELS
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // indexA = t.v * 256 + t.u
|
||||
ldrb indexA, [TILE, indexA]
|
||||
add t, dtdx
|
||||
|
||||
and indexB, t, #0xFF00
|
||||
orr indexB, t, lsr #24 // indexB = t.v * 256 + t.u
|
||||
ldrb indexB, [TILE, indexB]
|
||||
add t, dtdx
|
||||
|
||||
// cheap non-accurate alpha test, skip pixels pair if both are transparent
|
||||
orrs indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
|
||||
ldrneb indexA, [LMAP, indexA]
|
||||
ldrneb indexB, [LMAP, indexB, lsr #8]
|
||||
orrne indexA, indexB, lsl #8
|
||||
strneh indexA, [tmp]
|
||||
add tmp, #2
|
||||
.endm
|
||||
|
||||
.global rasterizeFTA_mode4_asm
|
||||
rasterizeFTA_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
sub sp, #16 // reserve stack space for [Ldx, Ldt, Rdx, Rdt]
|
||||
|
||||
ldr LMAP, =lightmap
|
||||
ldrb tmp, [L, #VERTEX_G]
|
||||
add LMAP, tmp, lsl #8 // tmp = (L->v.g << 8)
|
||||
|
||||
ldr TILE, =tile
|
||||
ldr TILE, [TILE]
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
ldr Lt, [L, #VERTEX_T] // Lt = L->t
|
||||
mov L, N // L = N
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
|
||||
lsl tmp, Lh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [L, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
str Ldx, [sp, #SP_LDX] // store Ldx to stack
|
||||
|
||||
ldr Lduv, [L, #VERTEX_T]
|
||||
sub Lduv, Lt // Lduv = N->v.t - Lt
|
||||
asr Ldu, Lduv, #16
|
||||
mul Ldu, tmp // Rdu = tmp * int16(Lduv >> 16)
|
||||
lsl Ldv, Lduv, #16
|
||||
asr Ldv, #16
|
||||
mul Ldv, tmp // Rdv = tmp * int16(Lduv);
|
||||
lsr Ldu, #16
|
||||
lsl Ldu, #16
|
||||
orr Ldt, Ldu, Ldv, lsr #16 // Ldt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Ldt, [sp, #SP_LDT] // store Ldt to stack
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
ldr Rt, [R, #VERTEX_T] // Rt = R->t
|
||||
mov R, N // R = N
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
|
||||
lsl tmp, Rh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [R, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
str Rdx, [sp, #SP_RDX] // store Rdx to stack
|
||||
|
||||
ldr Rduv, [R, #VERTEX_T]
|
||||
sub Rduv, Rt // Rduv = N->v.t - Rt
|
||||
asr Rdu, Rduv, #16
|
||||
mul Rdu, tmp // Rdu = tmp * int16(Rduv >> 16)
|
||||
lsl Rdv, Rduv, #16
|
||||
asr Rdv, #16
|
||||
mul Rdv, tmp // Rdv = tmp * int16(Rduv);
|
||||
lsr Rdu, #16
|
||||
lsl Rdu, #16
|
||||
orr Rdt, Rdu, Rdv, lsr #16 // Rdt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Rdt, [sp, #SP_RDT] // store Rdt to stack
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
stmfd sp!, {L,R,Lh,Rh} // sp-16
|
||||
|
||||
.scanline_start:
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add tmp, pixel, tmp // tmp = pixel + x1
|
||||
|
||||
ldr DIVLUTi, =divTable
|
||||
lsl inv, width, #1
|
||||
ldrh inv, [DIVLUTi, inv] // inv = FixedInvU(width)
|
||||
|
||||
sub duv, Rt, Lt // duv = Rt - Lt
|
||||
asr du, duv, #16
|
||||
mul du, inv // du = inv * int16(duv >> 16)
|
||||
lsl dv, duv, #16
|
||||
asr dv, #16
|
||||
mul dv, inv // dv = inv * int16(duv);
|
||||
lsr du, #16
|
||||
lsl du, #16
|
||||
orr dtdx, du, dv, lsr #16 // dtdx = (du & 0xFFFF0000) | (dv >> 16)
|
||||
|
||||
mov t, Lt // t = Lt
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst tmp, #1 // if (tmp & 1)
|
||||
beq .align_right
|
||||
ldrb indexB, [tmp, #-1]! // read pal index from VRAM (byte)
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
add t, dtdx
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
cmp indexA, #0
|
||||
ldrneb indexA, [LMAP, indexA]
|
||||
orrne indexB, indexA, lsl #8
|
||||
strneh indexB, [tmp]
|
||||
add tmp, #2
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block_4px
|
||||
ldrb indexB, [tmp, width]
|
||||
|
||||
sub Rt, dtdx
|
||||
and indexA, Rt, #0xFF00
|
||||
orr indexA, Rt, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
add Rt, dtdx
|
||||
ldrb indexA, [TILE, indexA]
|
||||
|
||||
cmp indexA, #0
|
||||
ldrneb indexA, [LMAP, indexA]
|
||||
orrne indexB, indexA, indexB, lsl #8
|
||||
strneh indexB, [tmp, width]
|
||||
|
||||
subs width, #1 // width--
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block_4px:
|
||||
tst width, #2
|
||||
beq .align_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #2
|
||||
beq .scanline_end
|
||||
|
||||
.align_block_8px:
|
||||
tst width, #4
|
||||
beq .scanlin_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #4
|
||||
beq .scanline_end
|
||||
|
||||
.scanlin_block_8px:
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #8
|
||||
bne .scanlin_block_8px
|
||||
|
||||
.scanline_end:
|
||||
ldr tmp, [sp, #(SP_LDX + 16)]
|
||||
add Lx, tmp // Lx += Ldx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDT + 16)]
|
||||
add Lt, tmp // Lt += Ldt from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDX + 16)]
|
||||
add Rx, tmp // Rx += Rdx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDT + 16)]
|
||||
add Rt, tmp // Rt += Rdt from stack
|
||||
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {L,R,Lh,Rh} // sp+16
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
add sp, #16 // revert reserved space for [Ldx, Ldt, Rdx, Rdt]
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
290
src/platform/gba/rasterizeFT_mode4.s
Normal file
290
src/platform/gba/rasterizeFT_mode4.s
Normal file
@ -0,0 +1,290 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
LMAP .req r3
|
||||
|
||||
TILE .req r4
|
||||
tmp .req r5
|
||||
N .req r6
|
||||
Lh .req r7
|
||||
Rh .req r8
|
||||
|
||||
Lx .req ip
|
||||
Rx .req lr
|
||||
Lt .req r9
|
||||
Rt .req r10
|
||||
h .req r11
|
||||
|
||||
Ldx .req h
|
||||
Rdx .req h
|
||||
|
||||
Ldt .req h
|
||||
Rdt .req h
|
||||
|
||||
indexA .req Lh
|
||||
indexB .req Rh
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
|
||||
inv .req Lh
|
||||
DIVLUT .req N
|
||||
DIVLUTi .req L
|
||||
width .req N
|
||||
t .req L
|
||||
dtdx .req R
|
||||
|
||||
duv .req R
|
||||
du .req L
|
||||
dv .req R
|
||||
|
||||
Lduv .req h
|
||||
Ldu .req N
|
||||
Ldv .req h
|
||||
|
||||
Rduv .req h
|
||||
Rdu .req N
|
||||
Rdv .req h
|
||||
|
||||
SP_LDX = 0
|
||||
SP_LDT = 4
|
||||
SP_RDX = 8
|
||||
SP_RDT = 12
|
||||
|
||||
.macro PUT_PIXELS
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // indexA = t.v * 256 + t.u
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
add t, dtdx
|
||||
|
||||
and indexB, t, #0xFF00
|
||||
orr indexB, t, lsr #24 // indexB = t.v * 256 + t.u
|
||||
ldrb indexB, [TILE, indexB]
|
||||
ldrb indexB, [LMAP, indexB]
|
||||
add t, dtdx
|
||||
|
||||
orr indexA, indexB, lsl #8
|
||||
strh indexA, [tmp], #2
|
||||
.endm
|
||||
|
||||
.global rasterizeFT_mode4_asm
|
||||
rasterizeFT_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
sub sp, #16 // reserve stack space for [Ldx, Ldt, Rdx, Rdt]
|
||||
|
||||
ldr LMAP, =lightmap
|
||||
ldrb tmp, [L, #VERTEX_G]
|
||||
add LMAP, tmp, lsl #8 // tmp = (L->v.g << 8)
|
||||
|
||||
ldr TILE, =tile
|
||||
ldr TILE, [TILE]
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
ldr Lt, [L, #VERTEX_T] // Lt = L->t
|
||||
mov L, N // L = N
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
|
||||
lsl tmp, Lh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [L, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
str Ldx, [sp, #SP_LDX] // store Ldx to stack
|
||||
|
||||
ldr Lduv, [L, #VERTEX_T]
|
||||
sub Lduv, Lt // Lduv = N->v.t - Lt
|
||||
asr Ldu, Lduv, #16
|
||||
mul Ldu, tmp // Rdu = tmp * int16(Lduv >> 16)
|
||||
lsl Ldv, Lduv, #16
|
||||
asr Ldv, #16
|
||||
mul Ldv, tmp // Rdv = tmp * int16(Lduv);
|
||||
lsr Ldu, #16
|
||||
lsl Ldu, #16
|
||||
orr Ldt, Ldu, Ldv, lsr #16 // Ldt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Ldt, [sp, #SP_LDT] // store Ldt to stack
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
ldr Rt, [R, #VERTEX_T] // Rt = R->t
|
||||
mov R, N // R = N
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
|
||||
lsl tmp, Rh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [R, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
str Rdx, [sp, #SP_RDX] // store Rdx to stack
|
||||
|
||||
ldr Rduv, [R, #VERTEX_T]
|
||||
sub Rduv, Rt // Rduv = N->v.t - Rt
|
||||
asr Rdu, Rduv, #16
|
||||
mul Rdu, tmp // Rdu = tmp * int16(Rduv >> 16)
|
||||
lsl Rdv, Rduv, #16
|
||||
asr Rdv, #16
|
||||
mul Rdv, tmp // Rdv = tmp * int16(Rduv);
|
||||
lsr Rdu, #16
|
||||
lsl Rdu, #16
|
||||
orr Rdt, Rdu, Rdv, lsr #16 // Rdt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Rdt, [sp, #SP_RDT] // store Rdt to stack
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
stmfd sp!, {L,R,Lh,Rh} // sp-16
|
||||
|
||||
.scanline_start:
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add tmp, pixel, tmp // tmp = pixel + x1
|
||||
|
||||
ldr DIVLUTi, =divTable
|
||||
lsl inv, width, #1
|
||||
ldrh inv, [DIVLUTi, inv] // inv = FixedInvU(width)
|
||||
|
||||
sub duv, Rt, Lt // duv = Rt - Lt
|
||||
asr du, duv, #16
|
||||
mul du, inv // du = inv * int16(duv >> 16)
|
||||
lsl dv, duv, #16
|
||||
asr dv, #16
|
||||
mul dv, inv // dv = inv * int16(duv);
|
||||
lsr du, #16
|
||||
lsl du, #16
|
||||
orr dtdx, du, dv, lsr #16 // dtdx = (du & 0xFFFF0000) | (dv >> 16)
|
||||
|
||||
mov t, Lt // t = Lt
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst tmp, #1 // if (tmp & 1)
|
||||
beq .align_right
|
||||
ldrb indexB, [tmp, #-1]! // read pal index from VRAM (byte)
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, lsl #8
|
||||
strh indexB, [tmp], #2
|
||||
add t, dtdx
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block_4px
|
||||
ldrb indexB, [tmp, width]
|
||||
|
||||
subs width, #1 // width--
|
||||
|
||||
sub Rt, dtdx
|
||||
and indexA, Rt, #0xFF00
|
||||
orr indexA, Rt, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
add Rt, dtdx
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, indexB, lsl #8
|
||||
strh indexB, [tmp, width]
|
||||
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block_4px:
|
||||
tst width, #2
|
||||
beq .align_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #2
|
||||
beq .scanline_end
|
||||
|
||||
.align_block_8px:
|
||||
tst width, #4
|
||||
beq .scanlin_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #4
|
||||
beq .scanline_end
|
||||
|
||||
.scanlin_block_8px:
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #8
|
||||
bne .scanlin_block_8px
|
||||
|
||||
.scanline_end:
|
||||
ldr tmp, [sp, #(SP_LDX + 16)]
|
||||
add Lx, tmp // Lx += Ldx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDT + 16)]
|
||||
add Lt, tmp // Lt += Ldt from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDX + 16)]
|
||||
add Rx, tmp // Rx += Rdx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDT + 16)]
|
||||
add Rt, tmp // Rt += Rdt from stack
|
||||
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {L,R,Lh,Rh} // sp+16
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
add sp, #16 // revert reserved space for [Ldx, Ldt, Rdx, Rdt]
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
156
src/platform/gba/rasterizeF_mode4.s
Normal file
156
src/platform/gba/rasterizeF_mode4.s
Normal file
@ -0,0 +1,156 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
index .req r3
|
||||
Lh .req r4
|
||||
Rh .req r5
|
||||
Lx .req ip
|
||||
Rx .req lr
|
||||
Ldx .req r6
|
||||
Rdx .req r7
|
||||
N .req r8
|
||||
tmp .req r9
|
||||
DIVLUT .req r10
|
||||
width .req r11
|
||||
h .req N
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
LMAP .req Lx
|
||||
pair .req DIVLUT
|
||||
blocks .req DIVLUT
|
||||
|
||||
.global rasterizeF_mode4_asm
|
||||
rasterizeF_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
|
||||
ldr LMAP, =lightmap
|
||||
|
||||
ldrb tmp, [L, #VERTEX_G]
|
||||
orr tmp, index, tmp, lsl #8 // tmp = index | (L->v.g << 8)
|
||||
ldrb index, [LMAP, tmp] // tmp = lightmap[tmp]
|
||||
orr index, index, lsl #8
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
ldr DIVLUT, =divTable
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
lsl tmp, Lh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [N, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
mov L, N // L = N
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
lsl tmp, Rh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [N, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
mov R, N // R = N
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
.scanline_start:
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add tmp, pixel, tmp // tmp = pixel + x1
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst tmp, #1 // if (tmp & 1)
|
||||
beq .align_right
|
||||
ldrb pair, [tmp, #-1]! // *tmp++ = (*tmp & 0x00FF) | (index << 8);
|
||||
orr pair, index, lsl #8
|
||||
strh pair, [tmp], #2
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block
|
||||
ldrb pair, [tmp, width]
|
||||
subs width, #1 // width--
|
||||
lsl pair, #8
|
||||
orr pair, index, lsr #8
|
||||
strh pair, [tmp, width]
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block:
|
||||
// 8px alignment
|
||||
lsr blocks, width, #1
|
||||
and blocks, blocks, #3 // blocks = (width / 2) % 4
|
||||
rsbs blocks, blocks, #2
|
||||
add pc, blocks, lsl #2 // pc += (2 - blocks) * 4
|
||||
|
||||
strh index, [tmp], #2 // if (width % 4) == 3
|
||||
strh index, [tmp], #2 // if (width % 4) == 2
|
||||
strh index, [tmp], #2 // if (width % 4) == 1
|
||||
|
||||
lsrs blocks, width, #3 // blocks = (width / 2) / 4
|
||||
beq .scanline_end // if (blocks == 0) no 8px blocks
|
||||
|
||||
.scanline_block_8px:
|
||||
strh index, [tmp], #2
|
||||
strh index, [tmp], #2
|
||||
strh index, [tmp], #2
|
||||
strh index, [tmp], #2
|
||||
subs blocks, #1
|
||||
bne .scanline_block_8px
|
||||
|
||||
.scanline_end:
|
||||
add Lx, Ldx // Lx += Ldx
|
||||
add Rx, Rdx // Rx += Rdx
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
358
src/platform/gba/rasterizeGTA_mode4.s
Normal file
358
src/platform/gba/rasterizeGTA_mode4.s
Normal file
@ -0,0 +1,358 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
|
||||
Lh .req r3
|
||||
Rh .req r4
|
||||
|
||||
Lx .req r5
|
||||
Rx .req r6
|
||||
|
||||
Lg .req r7
|
||||
Rg .req r8
|
||||
|
||||
Lt .req r9
|
||||
Rt .req r10
|
||||
|
||||
tmp .req r11
|
||||
N .req r12
|
||||
|
||||
TILE .req lr
|
||||
|
||||
h .req N
|
||||
|
||||
LMAP .req tmp
|
||||
|
||||
Ldx .req h
|
||||
Rdx .req h
|
||||
|
||||
Ldg .req h
|
||||
Rdg .req h
|
||||
|
||||
Ldt .req h
|
||||
Rdt .req h
|
||||
|
||||
indexA .req Lh
|
||||
indexB .req Rh
|
||||
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
|
||||
inv .req Lh
|
||||
DIVLUT .req N
|
||||
DIVLUTi .req tmp
|
||||
|
||||
ptr .req Lx
|
||||
width .req Rx
|
||||
|
||||
g .req Lg
|
||||
dgdx .req Rg
|
||||
|
||||
t .req Lt
|
||||
dtdx .req Rt
|
||||
|
||||
duv .req R
|
||||
du .req L
|
||||
dv .req R
|
||||
|
||||
Lduv .req N
|
||||
Ldu .req TILE
|
||||
Ldv .req N
|
||||
|
||||
Rduv .req N
|
||||
Rdu .req TILE
|
||||
Rdv .req N
|
||||
|
||||
Rti .req tmp
|
||||
Rgi .req tmp
|
||||
|
||||
SP_LDX = 0
|
||||
SP_LDG = 4
|
||||
SP_LDT = 8
|
||||
SP_RDX = 12
|
||||
SP_RDG = 16
|
||||
SP_RDT = 20
|
||||
|
||||
.macro PUT_PIXELS
|
||||
bic LMAP, g, #255
|
||||
add g, dgdx
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // indexA = t.v * 256 + t.u
|
||||
ldrb indexA, [TILE, indexA]
|
||||
add t, dtdx
|
||||
|
||||
and indexB, t, #0xFF00
|
||||
orr indexB, t, lsr #24 // indexB = t.v * 256 + t.u
|
||||
ldrb indexB, [TILE, indexB]
|
||||
add t, dtdx
|
||||
|
||||
// cheap non-accurate alpha test, skip pixels pair if both are transparent
|
||||
orrs indexB, indexA, indexB, lsl #8 // indexB = indexA | (indexB << 8)
|
||||
ldrneb indexA, [LMAP, indexA]
|
||||
ldrneb indexB, [LMAP, indexB, lsr #8]
|
||||
orrne indexA, indexB, lsl #8
|
||||
strneh indexA, [ptr]
|
||||
add ptr, #2
|
||||
.endm
|
||||
|
||||
.global rasterizeGTA_mode4_asm
|
||||
rasterizeGTA_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
sub sp, #24 // reserve stack space for [Ldx, Ldg, Ldt, Rdx, Rdg, Rdt]
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
ldrb Lg, [L, #VERTEX_G] // Lg = L->v.g
|
||||
ldr Lt, [L, #VERTEX_T] // Lt = L->t
|
||||
mov L, N // L = N
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
|
||||
lsl tmp, Lh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [L, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
str Ldx, [sp, #SP_LDX] // store Ldx to stack
|
||||
|
||||
ldrb Ldg, [L, #VERTEX_G]
|
||||
sub Ldg, Lg
|
||||
mul Ldg, tmp // Ldg = tmp * (N->v.g - Lg)
|
||||
asr Ldg, #8 // 8-bit for fractional part
|
||||
str Ldg, [sp, #SP_LDG] // store Ldg to stack
|
||||
|
||||
ldr Lduv, [L, #VERTEX_T]
|
||||
sub Lduv, Lt // Lduv = N->v.t - Lt
|
||||
asr Ldu, Lduv, #16
|
||||
mul Ldu, tmp // Rdu = tmp * int16(Lduv >> 16)
|
||||
lsl Ldv, Lduv, #16
|
||||
asr Ldv, #16
|
||||
mul Ldv, tmp // Rdv = tmp * int16(Lduv);
|
||||
lsr Ldu, #16
|
||||
lsl Ldu, #16
|
||||
orr Ldt, Ldu, Ldv, lsr #16 // Ldt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Ldt, [sp, #SP_LDT] // store Ldt to stack
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
|
||||
ldr LMAP, =lightmap // !!! lightmap should be 64k aligned
|
||||
add Lg, LMAP, Lg, lsl #8 // Lg is address in lightmap array
|
||||
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
ldrb Rg, [R, #VERTEX_G] // Rg = R->v.g
|
||||
ldr Rt, [R, #VERTEX_T] // Rt = R->t
|
||||
mov R, N // R = N
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
|
||||
lsl tmp, Rh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [R, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
str Rdx, [sp, #SP_RDX] // store Rdx to stack
|
||||
|
||||
ldrb Rdg, [R, #VERTEX_G]
|
||||
sub Rdg, Rg
|
||||
mul Rdg, tmp // Rdg = tmp * (N->v.g - Rg)
|
||||
asr Rdg, #8 // 8-bit for fractional part
|
||||
str Rdg, [sp, #SP_RDG] // store Ldg to stack
|
||||
|
||||
ldr Rduv, [R, #VERTEX_T]
|
||||
sub Rduv, Rt // Rduv = N->v.t - Rt
|
||||
asr Rdu, Rduv, #16
|
||||
mul Rdu, tmp // Rdu = tmp * int16(Rduv >> 16)
|
||||
lsl Rdv, Rduv, #16
|
||||
asr Rdv, #16
|
||||
mul Rdv, tmp // Rdv = tmp * int16(Rduv);
|
||||
lsr Rdu, #16
|
||||
lsl Rdu, #16
|
||||
orr Rdt, Rdu, Rdv, lsr #16 // Rdt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Rdt, [sp, #SP_RDT] // store Rdt to stack
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
|
||||
ldr LMAP, =lightmap // !!! lightmap should be 64k aligned
|
||||
add Rg, LMAP, Rg, lsl #8 // Rg is address in lightmap array
|
||||
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
ldr TILE, =tile
|
||||
ldr TILE, [TILE]
|
||||
|
||||
stmfd sp!, {L,R,Lh,Rh} // sp-16
|
||||
|
||||
.scanline_start:
|
||||
stmfd sp!, {Lx,Rx,Lg,Rg,Lt,Rt} // sp-24
|
||||
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add ptr, pixel, tmp // ptr = pixel + x1
|
||||
|
||||
ldr DIVLUTi, =divTable
|
||||
lsl inv, width, #1
|
||||
ldrh inv, [DIVLUTi, inv] // inv = FixedInvU(width)
|
||||
|
||||
sub dgdx, Rg, Lg // dgdx = Rg - Lg
|
||||
mul dgdx, inv // dgdx *= FixedInvU(width)
|
||||
asr dgdx, #15 // dgdx >>= 15
|
||||
// g == Lg (alias)
|
||||
|
||||
sub duv, Rt, Lt // duv = Rt - Lt
|
||||
asr du, duv, #16
|
||||
mul du, inv // du = inv * int16(duv >> 16)
|
||||
lsl dv, duv, #16
|
||||
asr dv, #16
|
||||
mul dv, inv // dv = inv * int16(duv);
|
||||
lsr du, #16
|
||||
lsl du, #16
|
||||
orr dtdx, du, dv, lsr #16 // dtdx = (du & 0xFFFF0000) | (dv >> 16)
|
||||
// t == Lt (alias)
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst ptr, #1 // if (ptr & 1)
|
||||
beq .align_right
|
||||
ldrb indexB, [ptr, #-1]! // read pal index from VRAM (byte)
|
||||
|
||||
bic LMAP, g, #255
|
||||
add g, dgdx, asr #1
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, lsl #8
|
||||
strh indexB, [ptr], #2
|
||||
add t, dtdx
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block_4px
|
||||
ldrb indexB, [ptr, width]
|
||||
|
||||
subs width, #1 // width--
|
||||
|
||||
mla Rti, width, dtdx, t // Rti = width * dtdx + t
|
||||
and indexA, Rti, #0xFF00
|
||||
orr indexA, Rti, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
ldrb indexA, [TILE, indexA]
|
||||
|
||||
asr Rgi, dgdx, #1
|
||||
mla Rgi, width, Rgi, g // Rgi = width * (dgdx / 2) + g
|
||||
bic LMAP, Rgi, #255
|
||||
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, indexB, lsl #8
|
||||
strh indexB, [ptr, width]
|
||||
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block_4px:
|
||||
tst width, #2
|
||||
beq .align_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #2
|
||||
beq .scanline_end
|
||||
|
||||
.align_block_8px:
|
||||
tst width, #4
|
||||
beq .scanlin_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #4
|
||||
beq .scanline_end
|
||||
|
||||
.scanlin_block_8px:
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #8
|
||||
bne .scanlin_block_8px
|
||||
|
||||
.scanline_end:
|
||||
ldmfd sp!, {Lx,Rx,Lg,Rg,Lt,Rt} // sp+24
|
||||
|
||||
ldr tmp, [sp, #(SP_LDX + 16)]
|
||||
add Lx, tmp // Lx += Ldx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDG + 16)]
|
||||
add Lg, tmp // Lg += Ldg from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDT + 16)]
|
||||
add Lt, tmp // Lt += Ldt from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDX + 16)]
|
||||
add Rx, tmp // Rx += Rdx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDG + 16)]
|
||||
add Rg, tmp // Rg += Rdg from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDT + 16)]
|
||||
add Rt, tmp // Rt += Rdt from stack
|
||||
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {L,R,Lh,Rh} // sp+16
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
add sp, #24 // revert reserved space for [Ldx, Ldg, Ldt, Rdx, Rdg, Rdt]
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
355
src/platform/gba/rasterizeGT_mode4.s
Normal file
355
src/platform/gba/rasterizeGT_mode4.s
Normal file
@ -0,0 +1,355 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
|
||||
Lh .req r3
|
||||
Rh .req r4
|
||||
|
||||
Lx .req r5
|
||||
Rx .req r6
|
||||
|
||||
Lg .req r7
|
||||
Rg .req r8
|
||||
|
||||
Lt .req r9
|
||||
Rt .req r10
|
||||
|
||||
tmp .req r11
|
||||
N .req r12
|
||||
|
||||
TILE .req lr
|
||||
|
||||
h .req N
|
||||
|
||||
LMAP .req tmp
|
||||
|
||||
Ldx .req h
|
||||
Rdx .req h
|
||||
|
||||
Ldg .req h
|
||||
Rdg .req h
|
||||
|
||||
Ldt .req h
|
||||
Rdt .req h
|
||||
|
||||
indexA .req Lh
|
||||
indexB .req Rh
|
||||
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
|
||||
inv .req Lh
|
||||
DIVLUT .req N
|
||||
DIVLUTi .req tmp
|
||||
|
||||
ptr .req Lx
|
||||
width .req Rx
|
||||
|
||||
g .req Lg
|
||||
dgdx .req Rg
|
||||
|
||||
t .req Lt
|
||||
dtdx .req Rt
|
||||
|
||||
duv .req R
|
||||
du .req L
|
||||
dv .req R
|
||||
|
||||
Lduv .req N
|
||||
Ldu .req TILE
|
||||
Ldv .req N
|
||||
|
||||
Rduv .req N
|
||||
Rdu .req TILE
|
||||
Rdv .req N
|
||||
|
||||
Rti .req tmp
|
||||
Rgi .req tmp
|
||||
|
||||
SP_LDX = 0
|
||||
SP_LDG = 4
|
||||
SP_LDT = 8
|
||||
SP_RDX = 12
|
||||
SP_RDG = 16
|
||||
SP_RDT = 20
|
||||
|
||||
.macro PUT_PIXELS
|
||||
bic LMAP, g, #255
|
||||
add g, dgdx
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // indexA = t.v * 256 + t.u
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
add t, dtdx
|
||||
|
||||
and indexB, t, #0xFF00
|
||||
orr indexB, t, lsr #24 // indexB = t.v * 256 + t.u
|
||||
ldrb indexB, [TILE, indexB]
|
||||
ldrb indexB, [LMAP, indexB]
|
||||
add t, dtdx
|
||||
|
||||
orr indexA, indexB, lsl #8
|
||||
strh indexA, [ptr], #2
|
||||
.endm
|
||||
|
||||
.global rasterizeGT_mode4_asm
|
||||
rasterizeGT_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
sub sp, #24 // reserve stack space for [Ldx, Ldg, Ldt, Rdx, Rdg, Rdt]
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
ldrb Lg, [L, #VERTEX_G] // Lg = L->v.g
|
||||
ldr Lt, [L, #VERTEX_T] // Lt = L->t
|
||||
mov L, N // L = N
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
|
||||
lsl tmp, Lh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [L, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
str Ldx, [sp, #SP_LDX] // store Ldx to stack
|
||||
|
||||
ldrb Ldg, [L, #VERTEX_G]
|
||||
sub Ldg, Lg
|
||||
mul Ldg, tmp // Ldg = tmp * (N->v.g - Lg)
|
||||
asr Ldg, #8 // 8-bit for fractional part
|
||||
str Ldg, [sp, #SP_LDG] // store Ldg to stack
|
||||
|
||||
ldr Lduv, [L, #VERTEX_T]
|
||||
sub Lduv, Lt // Lduv = N->v.t - Lt
|
||||
asr Ldu, Lduv, #16
|
||||
mul Ldu, tmp // Rdu = tmp * int16(Lduv >> 16)
|
||||
lsl Ldv, Lduv, #16
|
||||
asr Ldv, #16
|
||||
mul Ldv, tmp // Rdv = tmp * int16(Lduv);
|
||||
lsr Ldu, #16
|
||||
lsl Ldu, #16
|
||||
orr Ldt, Ldu, Ldv, lsr #16 // Ldt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Ldt, [sp, #SP_LDT] // store Ldt to stack
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
|
||||
ldr LMAP, =lightmap // !!! lightmap should be 64k aligned
|
||||
add Lg, LMAP, Lg, lsl #8 // Lg is address in lightmap array
|
||||
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
ldrb Rg, [R, #VERTEX_G] // Rg = R->v.g
|
||||
ldr Rt, [R, #VERTEX_T] // Rt = R->t
|
||||
mov R, N // R = N
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
|
||||
lsl tmp, Rh, #1
|
||||
ldr DIVLUT, =divTable
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [R, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
str Rdx, [sp, #SP_RDX] // store Rdx to stack
|
||||
|
||||
ldrb Rdg, [R, #VERTEX_G]
|
||||
sub Rdg, Rg
|
||||
mul Rdg, tmp // Rdg = tmp * (N->v.g - Rg)
|
||||
asr Rdg, #8 // 8-bit for fractional part
|
||||
str Rdg, [sp, #SP_RDG] // store Ldg to stack
|
||||
|
||||
ldr Rduv, [R, #VERTEX_T]
|
||||
sub Rduv, Rt // Rduv = N->v.t - Rt
|
||||
asr Rdu, Rduv, #16
|
||||
mul Rdu, tmp // Rdu = tmp * int16(Rduv >> 16)
|
||||
lsl Rdv, Rduv, #16
|
||||
asr Rdv, #16
|
||||
mul Rdv, tmp // Rdv = tmp * int16(Rduv);
|
||||
lsr Rdu, #16
|
||||
lsl Rdu, #16
|
||||
orr Rdt, Rdu, Rdv, lsr #16 // Rdt = (Rdu & 0xFFFF0000) | (Rdv >> 16)
|
||||
str Rdt, [sp, #SP_RDT] // store Rdt to stack
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
|
||||
ldr LMAP, =lightmap // !!! lightmap should be 64k aligned
|
||||
add Rg, LMAP, Rg, lsl #8 // Rg is address in lightmap array
|
||||
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
ldr TILE, =tile
|
||||
ldr TILE, [TILE]
|
||||
|
||||
stmfd sp!, {L,R,Lh,Rh} // sp-16
|
||||
|
||||
.scanline_start:
|
||||
stmfd sp!, {Lx,Rx,Lg,Rg,Lt,Rt} // sp-24
|
||||
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add ptr, pixel, tmp // ptr = pixel + x1
|
||||
|
||||
ldr DIVLUTi, =divTable
|
||||
lsl inv, width, #1
|
||||
ldrh inv, [DIVLUTi, inv] // inv = FixedInvU(width)
|
||||
|
||||
sub dgdx, Rg, Lg // dgdx = Rg - Lg
|
||||
mul dgdx, inv // dgdx *= FixedInvU(width)
|
||||
asr dgdx, #15 // dgdx >>= 15
|
||||
// g == Lg (alias)
|
||||
|
||||
sub duv, Rt, Lt // duv = Rt - Lt
|
||||
asr du, duv, #16
|
||||
mul du, inv // du = inv * int16(duv >> 16)
|
||||
lsl dv, duv, #16
|
||||
asr dv, #16
|
||||
mul dv, inv // dv = inv * int16(duv);
|
||||
lsr du, #16
|
||||
lsl du, #16
|
||||
orr dtdx, du, dv, lsr #16 // dtdx = (du & 0xFFFF0000) | (dv >> 16)
|
||||
// t == Lt (alias)
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst ptr, #1 // if (ptr & 1)
|
||||
beq .align_right
|
||||
ldrb indexB, [ptr, #-1]! // read pal index from VRAM (byte)
|
||||
|
||||
bic LMAP, g, #255
|
||||
add g, dgdx, asr #1
|
||||
|
||||
and indexA, t, #0xFF00
|
||||
orr indexA, t, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
ldrb indexA, [TILE, indexA]
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, lsl #8
|
||||
strh indexB, [ptr], #2
|
||||
add t, dtdx
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block_4px
|
||||
ldrb indexB, [ptr, width]
|
||||
|
||||
subs width, #1 // width--
|
||||
|
||||
mla Rti, width, dtdx, t // Rti = width * dtdx + t
|
||||
and indexA, Rti, #0xFF00
|
||||
orr indexA, Rti, lsr #24 // res = (t & 0xFF00) | (t >> 24)
|
||||
ldrb indexA, [TILE, indexA]
|
||||
|
||||
asr Rgi, dgdx, #1
|
||||
mla Rgi, width, Rgi, g // Rgi = width * (dgdx / 2) + g
|
||||
bic LMAP, Rgi, #255
|
||||
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
|
||||
orr indexB, indexA, indexB, lsl #8
|
||||
strh indexB, [ptr, width]
|
||||
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block_4px:
|
||||
tst width, #2
|
||||
beq .align_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #2
|
||||
beq .scanline_end
|
||||
|
||||
.align_block_8px:
|
||||
tst width, #4
|
||||
beq .scanlin_block_8px
|
||||
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #4
|
||||
beq .scanline_end
|
||||
|
||||
.scanlin_block_8px:
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #8
|
||||
bne .scanlin_block_8px
|
||||
|
||||
.scanline_end:
|
||||
ldmfd sp!, {Lx,Rx,Lg,Rg,Lt,Rt} // sp+24
|
||||
|
||||
ldr tmp, [sp, #(SP_LDX + 16)]
|
||||
add Lx, tmp // Lx += Ldx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDG + 16)]
|
||||
add Lg, tmp // Lg += Ldg from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDT + 16)]
|
||||
add Lt, tmp // Lt += Ldt from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDX + 16)]
|
||||
add Rx, tmp // Rx += Rdx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDG + 16)]
|
||||
add Rg, tmp // Rg += Rdg from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDT + 16)]
|
||||
add Rt, tmp // Rt += Rdt from stack
|
||||
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {L,R,Lh,Rh} // sp+16
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
add sp, #24 // revert reserved space for [Ldx, Ldg, Ldt, Rdx, Rdg, Rdt]
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
213
src/platform/gba/rasterizeG_mode4.s
Normal file
213
src/platform/gba/rasterizeG_mode4.s
Normal file
@ -0,0 +1,213 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
index .req r3
|
||||
DIVLUT .req r4
|
||||
tmp .req r5
|
||||
N .req r6
|
||||
Lh .req r7
|
||||
Rh .req r8
|
||||
Lx .req ip
|
||||
Rx .req lr
|
||||
Lg .req r9
|
||||
Rg .req r10
|
||||
h .req r11
|
||||
Ldx .req h
|
||||
Rdx .req Ldx
|
||||
Ldg .req Ldx
|
||||
Rdg .req Ldx
|
||||
color .req N
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
LMAP .req index
|
||||
pair .req Lh
|
||||
width .req Rh
|
||||
g .req L
|
||||
dgdx .req R
|
||||
|
||||
SP_LDX = 0
|
||||
SP_LDG = 4
|
||||
SP_RDX = 8
|
||||
SP_RDG = 12
|
||||
|
||||
.macro PUT_PIXELS
|
||||
lsr color, g, #16
|
||||
ldrb color, [LMAP, color, lsl #8]
|
||||
orr color, color, lsl #8
|
||||
strh color, [tmp], #2
|
||||
add g, dgdx
|
||||
.endm
|
||||
|
||||
.global rasterizeG_mode4_asm
|
||||
rasterizeG_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
sub sp, #16 // reserve stack space for [Ldx, Ldg, Rdx, Rdg]
|
||||
|
||||
ldr tmp, =lightmap
|
||||
add LMAP, index, tmp // LMAP = lightmap + index
|
||||
ldr DIVLUT, =divTable
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
ldrb Lg, [L, #VERTEX_G] // Lg = L->v.g
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
lsl tmp, Lh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [N, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
str Ldx, [sp, #SP_LDX] // store Ldx to stack
|
||||
|
||||
ldrb Ldg, [N, #VERTEX_G]
|
||||
sub Ldg, Lg
|
||||
mul Ldg, tmp // Ldg = tmp * (N->v.g - Lg)
|
||||
str Ldg, [sp, #SP_LDG] // store Ldg to stack
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
lsl Lg, #16 // Lg <<= 16
|
||||
mov L, N // L = N
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
ldrb Rg, [R, #VERTEX_G] // Rg = R->v.g
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
lsl tmp, Rh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [N, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
str Rdx, [sp, #SP_RDX] // store Rdx to stack
|
||||
|
||||
ldrb Rdg, [N, #VERTEX_G]
|
||||
sub Rdg, Rg
|
||||
mul Rdg, tmp // Rdg = tmp * (N->v.g - Rg)
|
||||
str Rdg, [sp, #SP_RDG] // store Rdg to stack
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
lsl Rg, #16 // Rg <<= 16
|
||||
mov R, N // R = N
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
stmfd sp!, {L,R,Lh,Rh} // sp-16
|
||||
|
||||
.scanline_start:
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
sub dgdx, Rg, Lg
|
||||
asr dgdx, #5 // dgdx = (Rg - Lg) >> 5
|
||||
lsl g, width, #1
|
||||
ldrh g, [DIVLUT, g]
|
||||
mul dgdx, g // dgdx *= FixedInvU(width)
|
||||
asr dgdx, #10 // dgdx >>= 10
|
||||
mov g, Lg // g = Lg
|
||||
|
||||
add tmp, pixel, tmp // tmp = pixel + x1
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst tmp, #1 // if (tmp & 1)
|
||||
beq .align_right
|
||||
ldrb pair, [tmp, #-1]! // read pal index from VRAM (byte)
|
||||
|
||||
lsr color, g, #16
|
||||
ldrb color, [LMAP, color, lsl #8]
|
||||
orr pair, color, lsl #8
|
||||
strh pair, [tmp], #2
|
||||
add g, dgdx, asr #1
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .align_block
|
||||
ldrb pair, [tmp, width]
|
||||
|
||||
subs width, #1 // width--
|
||||
|
||||
lsr color, Rg, #16
|
||||
ldrb color, [LMAP, color, lsl #8]
|
||||
orr pair, color, pair, lsl #8
|
||||
strh pair, [tmp, width]
|
||||
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.align_block:
|
||||
tst width, #2
|
||||
beq .scanline_block_4px
|
||||
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #2 // width -= 2;
|
||||
beq .scanline_end // if (width == 0)
|
||||
|
||||
.scanline_block_4px:
|
||||
PUT_PIXELS
|
||||
PUT_PIXELS
|
||||
|
||||
subs width, #4
|
||||
bne .scanline_block_4px
|
||||
|
||||
.scanline_end:
|
||||
ldr tmp, [sp, #(SP_LDX + 16)]
|
||||
add Lx, tmp // Lx += Ldx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_LDG + 16)]
|
||||
add Lg, tmp // Lg += Ldg from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDX + 16)]
|
||||
add Rx, tmp // Rx += Rdx from stack
|
||||
|
||||
ldr tmp, [sp, #(SP_RDG + 16)]
|
||||
add Rg, tmp // Rg += Rdg from stack
|
||||
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {L,R,Lh,Rh} // sp+16
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
add sp, #16 // revert reserved space for [Ldx, Ldg, Rdx, Rdg]
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
152
src/platform/gba/rasterizeS_mode4.s
Normal file
152
src/platform/gba/rasterizeS_mode4.s
Normal file
@ -0,0 +1,152 @@
|
||||
#include "rasterizer.inc"
|
||||
|
||||
pixel .req r0
|
||||
L .req r1
|
||||
R .req r2
|
||||
LMAP .req r3
|
||||
Lh .req r4
|
||||
Rh .req r5
|
||||
Lx .req ip
|
||||
Rx .req lr
|
||||
Ldx .req r6
|
||||
Rdx .req r7
|
||||
N .req r8
|
||||
tmp .req r9
|
||||
DIVLUT .req r10
|
||||
width .req r11
|
||||
h .req N
|
||||
Ry1 .req tmp
|
||||
Ry2 .req Rh
|
||||
Ly1 .req tmp
|
||||
Ly2 .req Lh
|
||||
pair .req DIVLUT
|
||||
indexA .req Lh
|
||||
indexB .req DIVLUT
|
||||
|
||||
.shadow_lightmap:
|
||||
.word lightmap + 0x1A00
|
||||
|
||||
.global rasterizeS_mode4_asm
|
||||
rasterizeS_mode4_asm:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,lr}
|
||||
|
||||
ldr LMAP, .shadow_lightmap
|
||||
|
||||
mov Lh, #0 // Lh = 0
|
||||
mov Rh, #0 // Rh = 0
|
||||
|
||||
.loop:
|
||||
ldr DIVLUT, =divTable
|
||||
|
||||
.calc_left_start:
|
||||
cmp Lh, #0
|
||||
bne .calc_left_end // if (Lh != 0) end with left
|
||||
ldr N, [L, #VERTEX_PREV] // N = L->prev
|
||||
ldrsh Ly1, [L, #VERTEX_Y] // Ly1 = L->v.y
|
||||
ldrsh Ly2, [N, #VERTEX_Y] // Ly2 = N->v.y
|
||||
subs Lh, Ly2, Ly1 // Lh = Ly2 - Ly1
|
||||
blt .exit // if (Lh < 0) return
|
||||
ldrsh Lx, [L, #VERTEX_X] // Lx = L->v.x
|
||||
cmp Lh, #1 // if (Lh <= 1) skip Ldx calc
|
||||
ble .skip_left_dx
|
||||
lsl tmp, Lh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Lh)
|
||||
|
||||
ldrsh Ldx, [N, #VERTEX_X]
|
||||
sub Ldx, Lx
|
||||
mul Ldx, tmp // Ldx = tmp * (N->v.x - Lx)
|
||||
|
||||
.skip_left_dx:
|
||||
lsl Lx, #16 // Lx <<= 16
|
||||
mov L, N // L = N
|
||||
b .calc_left_start
|
||||
.calc_left_end:
|
||||
|
||||
.calc_right_start:
|
||||
cmp Rh, #0
|
||||
bne .calc_right_end // if (Rh != 0) end with right
|
||||
ldr N, [R, #VERTEX_NEXT] // N = R->next
|
||||
ldrsh Ry1, [R, #VERTEX_Y] // Ry1 = R->v.y
|
||||
ldrsh Ry2, [N, #VERTEX_Y] // Ry2 = N->v.y
|
||||
subs Rh, Ry2, Ry1 // Rh = Ry2 - Ry1
|
||||
blt .exit // if (Rh < 0) return
|
||||
ldrsh Rx, [R, #VERTEX_X] // Rx = R->v.x
|
||||
cmp Rh, #1 // if (Rh <= 1) skip Rdx calc
|
||||
ble .skip_right_dx
|
||||
lsl tmp, Rh, #1
|
||||
ldrh tmp, [DIVLUT, tmp] // tmp = FixedInvU(Rh)
|
||||
|
||||
ldrsh Rdx, [N, #VERTEX_X]
|
||||
sub Rdx, Rx
|
||||
mul Rdx, tmp // Rdx = tmp * (N->v.x - Rx)
|
||||
|
||||
.skip_right_dx:
|
||||
lsl Rx, #16 // Rx <<= 16
|
||||
mov R, N // R = N
|
||||
b .calc_right_start
|
||||
.calc_right_end:
|
||||
|
||||
cmp Rh, Lh // if (Rh < Lh)
|
||||
movlt h, Rh // h = Rh
|
||||
movge h, Lh // else h = Lh
|
||||
sub Lh, h // Lh -= h
|
||||
sub Rh, h // Rh -= h
|
||||
|
||||
stmfd sp!, {Lh}
|
||||
|
||||
.scanline_start:
|
||||
asr tmp, Lx, #16 // x1 = (Lx >> 16)
|
||||
rsbs width, tmp, Rx, asr #16 // width = (Rx >> 16) - x1
|
||||
ble .scanline_end // if (width <= 0) go next scanline
|
||||
|
||||
add tmp, pixel, tmp // tmp = pixel + x1
|
||||
|
||||
// 2 bytes alignment (VRAM write requirement)
|
||||
.align_left:
|
||||
tst tmp, #1
|
||||
beq .align_right
|
||||
|
||||
ldrh pair, [tmp, #-1]!
|
||||
ldrb indexA, [LMAP, pair, lsr #8]
|
||||
and pair, #0xFF
|
||||
orr pair, indexA, lsl #8
|
||||
strh pair, [tmp], #2
|
||||
|
||||
subs width, #1 // width--;
|
||||
beq .scanline_end
|
||||
|
||||
.align_right:
|
||||
tst width, #1
|
||||
beq .scanline
|
||||
ldrb pair, [tmp, width]
|
||||
subs width, #1 // width--
|
||||
and indexA, pair, #0xFF
|
||||
ldrb indexA, [LMAP, indexA]
|
||||
orr pair, indexA, pair, lsl #8
|
||||
strh pair, [tmp, width]
|
||||
beq .scanline_end // width == 0
|
||||
|
||||
.scanline:
|
||||
ldrh pair, [tmp]
|
||||
ldrb indexA, [LMAP, pair, lsr #8]
|
||||
and pair, #0xFF
|
||||
ldrb indexB, [LMAP, pair]
|
||||
orr pair, indexB, indexA, lsl #8
|
||||
strh pair, [tmp], #2
|
||||
|
||||
subs width, #2
|
||||
bne .scanline
|
||||
|
||||
.scanline_end:
|
||||
add Lx, Ldx // Lx += Ldx
|
||||
add Rx, Rdx // Rx += Rdx
|
||||
add pixel, #VRAM_STRIDE // pixel += FRAME_WIDTH (240)
|
||||
|
||||
subs h, #1
|
||||
bne .scanline_start
|
||||
|
||||
ldmfd sp!, {Lh}
|
||||
b .loop
|
||||
|
||||
.exit:
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11,pc}
|
3
src/platform/gba/rasterize_dummy.s
Normal file
3
src/platform/gba/rasterize_dummy.s
Normal file
@ -0,0 +1,3 @@
|
||||
.global rasterize_dummy
|
||||
rasterize_dummy:
|
||||
bx lr
|
17
src/platform/gba/rasterizer.inc
Normal file
17
src/platform/gba/rasterizer.inc
Normal file
@ -0,0 +1,17 @@
|
||||
.section .iwram
|
||||
.arm
|
||||
|
||||
.equ VERTEX_X, 0
|
||||
.equ VERTEX_Y, 2
|
||||
.equ VERTEX_Z, 4
|
||||
.equ VERTEX_G, 6
|
||||
.equ VERTEX_CLIP, 7
|
||||
.equ VERTEX_T, 8
|
||||
.equ VERTEX_PREV, 12
|
||||
.equ VERTEX_NEXT, 16
|
||||
|
||||
#ifdef __TNS__
|
||||
.equ VRAM_STRIDE, 320
|
||||
#else
|
||||
.equ VRAM_STRIDE, 240
|
||||
#endif
|
@ -1,396 +0,0 @@
|
||||
.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
|
||||
*/
|
773
src/platform/gba/rasterizer_mode13.h
Normal file
773
src/platform/gba/rasterizer_mode13.h
Normal file
@ -0,0 +1,773 @@
|
||||
#ifndef H_RASTERIZER_MODE13
|
||||
#define H_RASTERIZER_MODE13
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern uint8 lightmap[256 * 32];
|
||||
extern const uint8* tile;
|
||||
|
||||
#define rasterizeS rasterizeS_mode13_c
|
||||
#define rasterizeF rasterizeF_mode13_c
|
||||
#define rasterizeG rasterizeG_mode13_c
|
||||
#define rasterizeFT rasterizeFT_mode13_c
|
||||
#define rasterizeGT rasterizeGT_mode13_c
|
||||
#define rasterizeFTA rasterizeFTA_mode13_c
|
||||
#define rasterizeGTA rasterizeGTA_mode13_c
|
||||
|
||||
void rasterizeS_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[0x1A00];
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
volatile uint16* ptr = pixel + (x1 >> 1);
|
||||
|
||||
if (x1 & 1)
|
||||
{
|
||||
uint16 p = ptr[0];
|
||||
|
||||
uint16 index = ft_lightmap[p >> 8];
|
||||
|
||||
ptr[0] = (p & 0x00FF) | (index << 8);
|
||||
ptr++;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint16 p = ptr[width >> 1];
|
||||
|
||||
uint16 index = ft_lightmap[p & 0xFF];
|
||||
|
||||
ptr[width >> 1] = (p & 0xFF00) | index;
|
||||
width--;
|
||||
}
|
||||
|
||||
while (width)
|
||||
{
|
||||
uint16 p = *ptr;
|
||||
|
||||
uint16 index = ft_lightmap[p & 0xFF];
|
||||
index |= ft_lightmap[p >> 8] << 8;
|
||||
|
||||
*ptr++ = index;
|
||||
width -= 2;
|
||||
}
|
||||
|
||||
#undef SHADE
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeF_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
uint16 color = lightmap[(L->v.g << 8) | index];
|
||||
color |= (color << 8);
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
ASSERT(L->v.y >= 0);
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
ASSERT(R->v.y >= 0);
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
*ptr++ = uint8(color);
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
ptr[width - 1] = uint8(color);
|
||||
}
|
||||
|
||||
if (width & 2)
|
||||
{
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
width >>= 2;
|
||||
while (width--)
|
||||
{
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeG_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
int32 Lg, Rg, Ldg = 0, Rdg = 0;
|
||||
|
||||
const uint8* ft_lightmap = lightmap + index;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
int32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * ((Rg - Lg) >> 5) >> 10;
|
||||
|
||||
int32 g = Lg;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
*ptr++ = ft_lightmap[g >> 16 << 8];
|
||||
g += dgdx >> 1;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
ptr[width - 1] = ft_lightmap[Rg >> 16 << 8];
|
||||
}
|
||||
|
||||
if (width & 2)
|
||||
{
|
||||
uint8 p = ft_lightmap[g >> 16 << 8];
|
||||
g += dgdx;
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
width >>= 2;
|
||||
while (width--)
|
||||
{
|
||||
uint8 p;
|
||||
|
||||
p = ft_lightmap[g >> 16 << 8];
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
g += dgdx;
|
||||
ptr += 2;
|
||||
|
||||
p = ft_lightmap[g >> 16 << 8];
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
g += dgdx;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
uint32 dtdx = (du & 0xFFFF0000) | (dv >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
*ptr++ = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
ptr[width - 1] = ft_lightmap[tile[(tmp & 0xFF00) | (tmp >> 24)]];
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
while (width--)
|
||||
{
|
||||
uint16 p;
|
||||
|
||||
p = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
|
||||
*(uint16*)ptr = p;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned
|
||||
#endif
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Lg, Rg, Ldx = 0, Rdx = 0, Ldg = 0, Rdg = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
// 8-bit fractional part precision for Gouraud component
|
||||
// has some artifacts but allow to save one reg for inner loop
|
||||
// for aligned by 64k address of lightmap array
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg) >> 8;
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 8;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg) >> 8;
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 8;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
int32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * (Rg - Lg) >> 15;
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = tmp * int16(duv >> 16);
|
||||
uint32 v = tmp * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
int32 g = Lg;
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
*ptr++ = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
g += dgdx >> 1;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
ptr[width - 1] = lightmap[(Rg >> 8 << 8) | tile[(tmp & 0xFF00) | (tmp >> 24)]];
|
||||
}
|
||||
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
g += intptr_t(lightmap);
|
||||
#endif
|
||||
|
||||
width >>= 1;
|
||||
|
||||
while (width--)
|
||||
{
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
const uint8* LMAP = (uint8*)(g >> 8 << 8);
|
||||
|
||||
uint16 p = LMAP[tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= LMAP[tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
g += dgdx;
|
||||
#else
|
||||
uint16 p = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
g += dgdx;
|
||||
#endif
|
||||
|
||||
*(uint16*)ptr = p;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
uint32 dtdx = (du & 0xFFFF0000) | (dv >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
uint8 p = tile[(t & 0xFF00) | (t >> 24)];
|
||||
if (p) {
|
||||
*ptr = ft_lightmap[p];
|
||||
}
|
||||
ptr++;
|
||||
t += dtdx;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
uint8 p = tile[(tmp & 0xFF00) | (tmp >> 24)];
|
||||
if (p) {
|
||||
ptr[width - 1] = ft_lightmap[p];
|
||||
}
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
while (width--)
|
||||
{
|
||||
uint8 indexA = tile[(t & 0xFF00) | (t >> 24)];
|
||||
t += dtdx;
|
||||
uint8 indexB = tile[(t & 0xFF00) | (t >> 24)];
|
||||
t += dtdx;
|
||||
|
||||
if (indexA && indexB) {
|
||||
*(uint16*)ptr = ft_lightmap[indexA] | (ft_lightmap[indexB] << 8);
|
||||
}/* else if (indexA) {
|
||||
*(uint16*)ptr = (*(uint16*)ptr & 0xFF00) | ft_lightmap[indexA];
|
||||
} else if (indexB) {
|
||||
*(uint16*)ptr = (*(uint16*)ptr & 0x00FF) | (ft_lightmap[indexB] << 8);
|
||||
}*/
|
||||
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
rasterizeGT(pixel, L, R);
|
||||
}
|
||||
|
||||
#endif
|
807
src/platform/gba/rasterizer_mode4.h
Normal file
807
src/platform/gba/rasterizer_mode4.h
Normal file
@ -0,0 +1,807 @@
|
||||
#ifndef H_RASTERIZER_MODE4
|
||||
#define H_RASTERIZER_MODE4
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern uint8 lightmap[256 * 32];
|
||||
extern const uint8* tile;
|
||||
|
||||
#if defined(__GBA__)
|
||||
#define USE_ASM
|
||||
#endif
|
||||
|
||||
#ifdef USE_ASM
|
||||
extern "C" {
|
||||
void rasterize_dummy(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
void rasterizeS_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
void rasterizeF_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index);
|
||||
void rasterizeG_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index);
|
||||
void rasterizeFT_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
void rasterizeGT_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
void rasterizeFTA_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
void rasterizeGTA_mode4_asm(uint16* pixel, const VertexUV* L, const VertexUV* R);
|
||||
}
|
||||
|
||||
#define rasterizeS rasterizeS_mode4_asm
|
||||
#define rasterizeF rasterizeF_mode4_asm
|
||||
#define rasterizeG rasterizeG_mode4_asm
|
||||
#define rasterizeFT rasterizeFT_mode4_asm
|
||||
#define rasterizeGT rasterizeGT_mode4_asm
|
||||
#define rasterizeFTA rasterizeFTA_mode4_asm
|
||||
#define rasterizeGTA rasterizeGTA_mode4_asm
|
||||
#else
|
||||
#define rasterizeS rasterizeS_mode4_c
|
||||
#define rasterizeF rasterizeF_mode4_c
|
||||
#define rasterizeG rasterizeG_mode4_c
|
||||
#define rasterizeFT rasterizeFT_mode4_c
|
||||
#define rasterizeGT rasterizeGT_mode4_c
|
||||
#define rasterizeFTA rasterizeFTA_mode4_c
|
||||
#define rasterizeGTA rasterizeGTA_mode4_c
|
||||
|
||||
void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[0x1A00];
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
volatile uint16* ptr = pixel + (x1 >> 1);
|
||||
|
||||
if (x1 & 1)
|
||||
{
|
||||
uint16 p = ptr[0];
|
||||
|
||||
uint16 index = ft_lightmap[p >> 8];
|
||||
|
||||
ptr[0] = (p & 0x00FF) | (index << 8);
|
||||
ptr++;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint16 p = ptr[width >> 1];
|
||||
|
||||
uint16 index = ft_lightmap[p & 0xFF];
|
||||
|
||||
ptr[width >> 1] = (p & 0xFF00) | index;
|
||||
width--;
|
||||
}
|
||||
|
||||
while (width)
|
||||
{
|
||||
uint16 p = *ptr;
|
||||
|
||||
uint16 index = ft_lightmap[p & 0xFF];
|
||||
index |= ft_lightmap[p >> 8] << 8;
|
||||
|
||||
*ptr++ = index;
|
||||
width -= 2;
|
||||
}
|
||||
|
||||
#undef SHADE
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeF_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
uint16 color = lightmap[(L->v.g << 8) | index];
|
||||
color |= (color << 8);
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
ASSERT(L->v.y >= 0);
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
ASSERT(R->v.y >= 0);
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
ptr--;
|
||||
*(uint16*)ptr = *ptr | (color << 8);
|
||||
ptr += 2;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | (color >> 8);
|
||||
}
|
||||
|
||||
if (width & 2)
|
||||
{
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
width >>= 2;
|
||||
while (width--)
|
||||
{
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
*(uint16*)ptr = color;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeG_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
int32 Lg, Rg, Ldg = 0, Rdg = 0;
|
||||
|
||||
const uint8* ft_lightmap = lightmap + index;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
int32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * ((Rg - Lg) >> 5) >> 10;
|
||||
|
||||
int32 g = Lg;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
ptr--;
|
||||
*(uint16*)ptr = *ptr | (ft_lightmap[g >> 16 << 8] << 8);
|
||||
g += dgdx >> 1;
|
||||
ptr += 2;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | ft_lightmap[Rg >> 16 << 8];
|
||||
}
|
||||
|
||||
if (width & 2)
|
||||
{
|
||||
uint8 p = ft_lightmap[g >> 16 << 8];
|
||||
g += dgdx;
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
width >>= 2;
|
||||
while (width--)
|
||||
{
|
||||
uint8 p;
|
||||
|
||||
p = ft_lightmap[g >> 16 << 8];
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
g += dgdx;
|
||||
ptr += 2;
|
||||
|
||||
p = ft_lightmap[g >> 16 << 8];
|
||||
*(uint16*)ptr = p | (p << 8);
|
||||
g += dgdx;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
uint32 dtdx = (du & 0xFFFF0000) | (dv >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
ptr--;
|
||||
*(uint16*)ptr = *ptr | (ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]] << 8);
|
||||
ptr += 2;
|
||||
t += dtdx;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | ft_lightmap[tile[(tmp & 0xFF00) | (tmp >> 24)]];
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
while (width--)
|
||||
{
|
||||
uint16 p;
|
||||
|
||||
p = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
|
||||
*(uint16*)ptr = p;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned
|
||||
#endif
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Lg, Rg, Ldx = 0, Rdx = 0, Ldg = 0, Rdg = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
// 8-bit fractional part precision for Gouraud component
|
||||
// has some artifacts but allow to save one reg for inner loop
|
||||
// for aligned by 64k address of lightmap array
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg) >> 8;
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 8;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg) >> 8;
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 8;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
int32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * (Rg - Lg) >> 15;
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = tmp * int16(duv >> 16);
|
||||
uint32 v = tmp * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
int32 g = Lg;
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
ptr--;
|
||||
*(uint16*)ptr = *ptr | (lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]] << 8);
|
||||
ptr += 2;
|
||||
t += dtdx;
|
||||
g += dgdx >> 1;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | lightmap[(Rg >> 8 << 8) | tile[(tmp & 0xFF00) | (tmp >> 24)]];
|
||||
}
|
||||
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
g += intptr_t(lightmap);
|
||||
#endif
|
||||
|
||||
width >>= 1;
|
||||
|
||||
while (width--)
|
||||
{
|
||||
#ifdef ALIGNED_LIGHTMAP
|
||||
const uint8* LMAP = (uint8*)(g >> 8 << 8);
|
||||
|
||||
uint16 p = LMAP[tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= LMAP[tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
g += dgdx;
|
||||
#else
|
||||
uint16 p = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]];
|
||||
t += dtdx;
|
||||
p |= lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]] << 8;
|
||||
t += dtdx;
|
||||
g += dgdx;
|
||||
#endif
|
||||
|
||||
*(uint16*)ptr = p;
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
uint32 dtdx = (du & 0xFFFF0000) | (dv >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
volatile uint8* ptr = (uint8*)pixel + x1;
|
||||
|
||||
if (intptr_t(ptr) & 1)
|
||||
{
|
||||
uint8 p = tile[(t & 0xFF00) | (t >> 24)];
|
||||
ptr--;
|
||||
if (p) {
|
||||
*(uint16*)ptr = *ptr | (ft_lightmap[p] << 8);
|
||||
}
|
||||
ptr += 2;
|
||||
t += dtdx;
|
||||
width--;
|
||||
}
|
||||
|
||||
if (width & 1)
|
||||
{
|
||||
uint32 tmp = Rt - dtdx;
|
||||
uint8 p = tile[(tmp & 0xFF00) | (tmp >> 24)];
|
||||
if (p) {
|
||||
*(uint16*)(ptr + width - 1) = (ptr[width] << 8) | ft_lightmap[p];
|
||||
}
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
while (width--)
|
||||
{
|
||||
uint8 indexA = tile[(t & 0xFF00) | (t >> 24)];
|
||||
t += dtdx;
|
||||
uint8 indexB = tile[(t & 0xFF00) | (t >> 24)];
|
||||
t += dtdx;
|
||||
|
||||
if (indexA && indexB) {
|
||||
*(uint16*)ptr = ft_lightmap[indexA] | (ft_lightmap[indexB] << 8);
|
||||
}/* else if (indexA) {
|
||||
*(uint16*)ptr = (*(uint16*)ptr & 0xFF00) | ft_lightmap[indexA];
|
||||
} else if (indexB) {
|
||||
*(uint16*)ptr = (*(uint16*)ptr & 0x00FF) | (ft_lightmap[indexB] << 8);
|
||||
}*/
|
||||
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
rasterizeGT(pixel, L, R);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
837
src/platform/gba/rasterizer_mode5.h
Normal file
837
src/platform/gba/rasterizer_mode5.h
Normal file
@ -0,0 +1,837 @@
|
||||
#ifndef H_RASTERIZER_MODE5
|
||||
#define H_RASTERIZER_MODE5
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define rasterizeS rasterizeS_mode5_c
|
||||
#define rasterizeF rasterizeF_mode5_c
|
||||
#define rasterizeG rasterizeG_mode5_c
|
||||
#define rasterizeFT rasterizeFT_mode5_c
|
||||
#define rasterizeGT rasterizeGT_mode5_c
|
||||
#define rasterizeFTA rasterizeFTA_mode5_c
|
||||
#define rasterizeGTA rasterizeGTA_mode5_c
|
||||
|
||||
extern uint16 palette[256];
|
||||
extern uint8 lightmap[256 * 32];
|
||||
extern const uint8* tile;
|
||||
|
||||
void rasterize_overdraw(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
while (width--)
|
||||
{
|
||||
*ptr++ += 0x1084;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeS_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
*ptr = (*ptr >> 1) & 0b11110111101111;
|
||||
ptr++;
|
||||
if (!--width) break;
|
||||
|
||||
*ptr = (*ptr >> 1) & 0b11110111101111;
|
||||
ptr++;
|
||||
if (!--width) break;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeF_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
uint32 color = palette[lightmap[(L->v.g << 8) | index]];
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Rx;
|
||||
int32 Lx;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
uint32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
|
||||
if (Rh > 1) {
|
||||
uint32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
switch (width & 7)
|
||||
{
|
||||
case 7: *ptr++ = color;
|
||||
case 6: *ptr++ = color;
|
||||
case 5: *ptr++ = color;
|
||||
case 4: *ptr++ = color;
|
||||
case 3: *ptr++ = color;
|
||||
case 2: *ptr++ = color;
|
||||
case 1: *ptr++ = color;
|
||||
}
|
||||
|
||||
int32 n = width >> 3;
|
||||
|
||||
while (n--) {
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
*ptr++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeG_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index)
|
||||
{
|
||||
const uint8* ft_lightmap = lightmap + index; // faster with global variable than local
|
||||
|
||||
int32 Lh = 0;
|
||||
int32 Rh = 0;
|
||||
int32 Ldx = 0;
|
||||
int32 Rdx = 0;
|
||||
int32 Lx;
|
||||
int32 Rx;
|
||||
int32 Lg;
|
||||
int32 Rg;
|
||||
int32 Ldg = 0;
|
||||
int32 Rdg = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
|
||||
if (Rh > 1) {
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
int32 d = FixedInvU(width);
|
||||
int32 dgdx = d * ((Rg - Lg) >> 5) >> 10;
|
||||
|
||||
int32 g = Lg;
|
||||
|
||||
while (1) // 2px per iteration (faster than 8px on C)
|
||||
{
|
||||
uint32 color = palette[ft_lightmap[(g >> 8) & 0x1F00]];
|
||||
|
||||
*ptr++ = color;
|
||||
if (!--width) break;
|
||||
|
||||
*ptr++ = color;
|
||||
if (!--width) break;
|
||||
|
||||
g += dgdx;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFT_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
int32 d = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = d * int16(duv >> 16);
|
||||
uint32 v = d * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
while (1)
|
||||
{
|
||||
*ptr++ = palette[ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGT_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Lg, Rg, Ldx = 0, Rdx = 0, Ldg = 0, Rdg = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * ((Rg - Lg) >> 5) >> 10;
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = tmp * int16(duv >> 16);
|
||||
uint32 v = tmp * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
int32 g = Lg;
|
||||
uint32 t = Lt;
|
||||
|
||||
while (1)
|
||||
{
|
||||
*ptr++ = palette[lightmap[((g >> 8) & 0x1F00) | tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
|
||||
*ptr++ = palette[lightmap[((g >> 8) & 0x1F00) | tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
|
||||
g += dgdx;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeFTA_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
const uint8* ft_lightmap = &lightmap[L->v.g << 8];
|
||||
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Ldx = 0, Rdx = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
int32 d = FixedInvU(width);
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = d * int16(duv >> 16);
|
||||
uint32 v = d * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
uint32 t = Lt;
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint16 p = palette[ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (p) *ptr = p;
|
||||
ptr++;
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rasterizeGTA_mode5_c(uint16* pixel, const VertexUV* L, const VertexUV* R)
|
||||
{
|
||||
int32 Lh = 0, Rh = 0;
|
||||
int32 Lx, Rx, Lg, Rg, Ldx = 0, Rdx = 0, Ldg = 0, Rdg = 0;
|
||||
uint32 Lt, Rt, Ldt, Rdt;
|
||||
Ldt = 0;
|
||||
Rdt = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (!Lh)
|
||||
{
|
||||
const VertexUV* N = L->prev;
|
||||
|
||||
if (N->v.y < L->v.y) return;
|
||||
|
||||
Lh = N->v.y - L->v.y;
|
||||
Lx = L->v.x;
|
||||
Lg = L->v.g;
|
||||
Lt = L->t.uv;
|
||||
|
||||
if (Lh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Lh);
|
||||
Ldx = tmp * (N->v.x - Lx);
|
||||
Ldg = tmp * (N->v.g - Lg);
|
||||
|
||||
uint32 duv = N->t.uv - Lt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Ldt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Lx <<= 16;
|
||||
Lg <<= 16;
|
||||
L = N;
|
||||
}
|
||||
|
||||
while (!Rh)
|
||||
{
|
||||
const VertexUV* N = R->next;
|
||||
|
||||
if (N->v.y < R->v.y) return;
|
||||
|
||||
Rh = N->v.y - R->v.y;
|
||||
Rx = R->v.x;
|
||||
Rg = R->v.g;
|
||||
Rt = R->t.uv;
|
||||
|
||||
if (Rh > 1)
|
||||
{
|
||||
int32 tmp = FixedInvU(Rh);
|
||||
Rdx = tmp * (N->v.x - Rx);
|
||||
Rdg = tmp * (N->v.g - Rg);
|
||||
|
||||
uint32 duv = N->t.uv - Rt;
|
||||
uint32 du = tmp * int16(duv >> 16);
|
||||
uint32 dv = tmp * int16(duv);
|
||||
Rdt = (du & 0xFFFF0000) | (dv >> 16);
|
||||
}
|
||||
|
||||
Rx <<= 16;
|
||||
Rg <<= 16;
|
||||
R = N;
|
||||
}
|
||||
|
||||
int32 h = X_MIN(Lh, Rh);
|
||||
Lh -= h;
|
||||
Rh -= h;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
int32 x1 = Lx >> 16;
|
||||
int32 x2 = Rx >> 16;
|
||||
|
||||
int32 width = x2 - x1;
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
uint16* ptr = pixel + x1;
|
||||
|
||||
uint32 tmp = FixedInvU(width);
|
||||
|
||||
int32 dgdx = tmp * ((Rg - Lg) >> 5) >> 10;
|
||||
|
||||
uint32 duv = Rt - Lt;
|
||||
uint32 u = tmp * int16(duv >> 16);
|
||||
uint32 v = tmp * int16(duv);
|
||||
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||
|
||||
int32 g = Lg;
|
||||
uint32 t = Lt;
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint16 p;
|
||||
p = palette[lightmap[((g >> 8) & 0x1F00) | tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (p) *ptr = p;
|
||||
ptr++;
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
|
||||
p = palette[lightmap[((g >> 8) & 0x1F00) | tile[(t & 0xFF00) | (t >> 24)]]];
|
||||
if (p) *ptr = p;
|
||||
ptr++;
|
||||
if (!--width) break;
|
||||
t += dtdx;
|
||||
|
||||
g += dgdx;
|
||||
}
|
||||
}
|
||||
|
||||
pixel += VRAM_WIDTH;
|
||||
|
||||
Lx += Ldx;
|
||||
Rx += Rdx;
|
||||
Lg += Ldg;
|
||||
Rg += Rdg;
|
||||
Lt += Ldt;
|
||||
Rt += Rdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
769
src/platform/gba/render.cpp
Normal file
769
src/platform/gba/render.cpp
Normal file
@ -0,0 +1,769 @@
|
||||
#include "common.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
uint16 fb[VRAM_WIDTH * FRAME_HEIGHT];
|
||||
#elif defined(__GBA__)
|
||||
uint32 fb = MEM_VRAM;
|
||||
#elif defined(__TNS__)
|
||||
uint16 fb[VRAM_WIDTH * FRAME_HEIGHT];
|
||||
#elif defined(__DOS__)
|
||||
uint16 fb[VRAM_WIDTH * FRAME_HEIGHT];
|
||||
#endif
|
||||
|
||||
#define PAL_COLOR_TRANSP 0x0000
|
||||
#define PAL_COLOR_BLACK 0x0421
|
||||
|
||||
#ifndef MODE_PAL
|
||||
uint16 palette[256]; // IWRAM 0.5k
|
||||
#endif
|
||||
|
||||
#if defined(__GBA__)
|
||||
#define ALIGNED_LIGHTMAP
|
||||
#endif
|
||||
|
||||
#if defined(MODE4)
|
||||
#include "rasterizer_mode4.h"
|
||||
#elif defined(MODE5)
|
||||
#include "rasterizer_mode5.h"
|
||||
#elif defined(MODE13)
|
||||
#include "rasterizer_mode13.h"
|
||||
#else
|
||||
#error no supported video mode set
|
||||
#endif
|
||||
|
||||
IWRAM_DATA uint8 lightmap[256 * 32]; // IWRAM 8k
|
||||
|
||||
const Texture* textures;
|
||||
const uint8* tiles;
|
||||
const uint8* tile;
|
||||
|
||||
uint32 gVerticesCount = 0;
|
||||
int32 gFacesCount = 0; // 1 is reserved as OT terminator
|
||||
|
||||
EWRAM_DATA Vertex gVertices[MAX_VERTICES]; // EWRAM 16k
|
||||
EWRAM_DATA Face gFaces[MAX_FACES]; // EWRAM 5k
|
||||
EWRAM_DATA Face* otFaces[OT_SIZE] = { 0 };
|
||||
int32 otMin = OT_SIZE - 1;
|
||||
int32 otMax = 0;
|
||||
|
||||
bool enableAlphaTest;
|
||||
bool enableClipping;
|
||||
|
||||
bool transformBoxRect(const Box* box, Rect* rect)
|
||||
{
|
||||
const Matrix &m = matrixGet();
|
||||
|
||||
if ((m[2][3] < VIEW_MIN_F) || (m[2][3] >= VIEW_MAX_F)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const vec3i v[8] = {
|
||||
vec3i( box->minX, box->minY, box->minZ ),
|
||||
vec3i( box->maxX, box->minY, box->minZ ),
|
||||
vec3i( box->minX, box->maxY, box->minZ ),
|
||||
vec3i( box->maxX, box->maxY, box->minZ ),
|
||||
vec3i( box->minX, box->minY, box->maxZ ),
|
||||
vec3i( box->maxX, box->minY, box->maxZ ),
|
||||
vec3i( box->minX, box->maxY, box->maxZ ),
|
||||
vec3i( box->maxX, box->maxY, box->maxZ )
|
||||
};
|
||||
|
||||
*rect = Rect( INT_MAX, INT_MAX, INT_MIN, INT_MIN );
|
||||
|
||||
for (int32 i = 0; i < 8; i++) {
|
||||
int32 z = DP43(m[2], v[i]);
|
||||
|
||||
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { // TODO znear clip
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 x = DP43(m[0], v[i]);
|
||||
int32 y = DP43(m[1], v[i]);
|
||||
|
||||
PERSPECTIVE(x, y, z);
|
||||
|
||||
if (x < rect->x0) rect->x0 = x;
|
||||
if (x > rect->x1) rect->x1 = x;
|
||||
if (y < rect->y0) rect->y0 = y;
|
||||
if (y > rect->y1) rect->y1 = y;
|
||||
}
|
||||
|
||||
rect->x0 += (FRAME_WIDTH / 2);
|
||||
rect->y0 += (FRAME_HEIGHT / 2);
|
||||
rect->x1 += (FRAME_WIDTH / 2);
|
||||
rect->y1 += (FRAME_HEIGHT / 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 rectIsVisible(const Rect* rect)
|
||||
{
|
||||
if (rect->x0 > rect->x1 ||
|
||||
rect->x0 > viewport.x1 ||
|
||||
rect->x1 < viewport.x0 ||
|
||||
rect->y0 > viewport.y1 ||
|
||||
rect->y1 < viewport.y0) return 0; // not visible
|
||||
|
||||
if (rect->x0 < viewport.x0 ||
|
||||
rect->x1 > viewport.x1 ||
|
||||
rect->y0 < viewport.y0 ||
|
||||
rect->y1 > viewport.y1) return -1; // clipped
|
||||
|
||||
return 1; // fully visible
|
||||
}
|
||||
|
||||
int32 boxIsVisible(const Box* box)
|
||||
{
|
||||
Rect rect;
|
||||
if (!transformBoxRect(box, &rect))
|
||||
return 0; // not visible
|
||||
return rectIsVisible(&rect);
|
||||
}
|
||||
|
||||
void transform(const vec3s &v, int32 vg)
|
||||
{
|
||||
ASSERT(gVerticesCount < MAX_VERTICES);
|
||||
|
||||
Vertex &res = gVertices[gVerticesCount++];
|
||||
|
||||
#if defined(MODE4) // TODO for all modes
|
||||
if (v.z < frustumAABB.minZ || v.z > frustumAABB.maxZ ||
|
||||
//v.y < frustumAABB.minY || v.y > frustumAABB.maxY ||
|
||||
v.x < frustumAABB.minX || v.x > frustumAABB.maxX)
|
||||
{
|
||||
res.clip = 16;
|
||||
res.z = -1;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const Matrix &m = matrixGet();
|
||||
|
||||
// TODO https://mikro.naprvyraz.sk/docs/Coding/1/3D-ROTAT.TXT
|
||||
int32 z = DP43(m[2], v);
|
||||
|
||||
if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { // TODO znear clip
|
||||
res.clip = 16;
|
||||
res.z = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int32 x = DP43(m[0], v);
|
||||
int32 y = DP43(m[1], v);
|
||||
|
||||
int32 fogZ = z >> FIXED_SHIFT;
|
||||
if (fogZ > FOG_MAX) {
|
||||
vg = 8191;
|
||||
} else if (fogZ > FOG_MIN) {
|
||||
vg += (fogZ - FOG_MIN) << FOG_SHIFT;
|
||||
if (vg > 8191) {
|
||||
vg = 8191;
|
||||
}
|
||||
}
|
||||
res.g = vg >> 8;
|
||||
|
||||
PERSPECTIVE(x, y, z);
|
||||
|
||||
x = X_CLAMP(x, -512, 511);
|
||||
y = X_CLAMP(y, -512, 511);
|
||||
|
||||
res.x = x + (FRAME_WIDTH >> 1);
|
||||
res.y = y + (FRAME_HEIGHT >> 1);
|
||||
res.z = fogZ;
|
||||
res.clip = enableClipping ? classify(res, viewport) : 0;
|
||||
}
|
||||
|
||||
void transformRoom(const RoomInfo::Vertex* vertex, int32 vCount)
|
||||
{
|
||||
// TODO per-sector clipping?
|
||||
for (int32 i = 0; i < vCount; i++)
|
||||
{
|
||||
transform(vertex->pos, vertex->lighting);
|
||||
vertex++;
|
||||
}
|
||||
}
|
||||
|
||||
void transformMesh(const vec3s* vertices, int32 vCount, uint16 intensity)
|
||||
{
|
||||
for (int32 i = 0; i < vCount; i++) {
|
||||
transform(*vertices++, intensity);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
void clipZ(int32 znear, VertexUV *output, int32 &count, const VertexUV *a, const VertexUV *b) {
|
||||
#define LERP2(a,b,t) int32((b) + (((a) - (b)) * t))
|
||||
|
||||
float t = (znear - b->v.sz) / float(a->v.sz - b->v.sz);
|
||||
VertexUV* v = output + count++;
|
||||
/*
|
||||
int32 ax = (a->v.x - (FRAME_WIDTH / 2)) * a->v.z;
|
||||
int32 ay = (a->v.y - (FRAME_HEIGHT / 2)) * a->v.z;
|
||||
int32 bx = (b->v.x - (FRAME_WIDTH / 2)) * b->v.z;
|
||||
int32 by = (b->v.y - (FRAME_HEIGHT / 2)) * b->v.z;
|
||||
int32 x = LERP2(ax, bx, t);
|
||||
int32 y = LERP2(ay, by, t);
|
||||
*/
|
||||
int32 x = LERP2(a->v.sx, b->v.sx, t);
|
||||
int32 y = LERP2(a->v.sy, b->v.sy, t);
|
||||
int32 z = LERP2(a->v.sz, b->v.sz, t);
|
||||
v->v.x = (x / znear) + (FRAME_WIDTH / 2);
|
||||
v->v.y = (y / znear) + (FRAME_HEIGHT / 2);
|
||||
v->v.g = LERP2(a->v.g, b->v.g, t);
|
||||
v->uv = (LERP2(a->uv & 0xFFFF, b->uv & 0xFFFF, t)) | (LERP2(a->uv >> 16, b->uv >> 16, t) << 16);
|
||||
}
|
||||
#endif
|
||||
VertexUV* clipPoly(VertexUV* poly, VertexUV* tmp, int32 &pCount) {
|
||||
#define LERP(a,b,t) (b + ((a - b) * t >> 12))
|
||||
#define LERP2(a,b,ta,tb) (b + (((a - b) * ta / tb) >> 12) )
|
||||
|
||||
#define CLIP_AXIS(X, Y, edge, output) {\
|
||||
int32 ta = (edge - b->v.X) << 12;\
|
||||
int32 tb = (a->v.X - b->v.X);\
|
||||
ASSERT(tb != 0);\
|
||||
int32 t = ta / tb;\
|
||||
VertexUV* v = output + count++;\
|
||||
v->v.X = edge;\
|
||||
v->v.Y = LERP2(a->v.Y, b->v.Y, ta, tb);\
|
||||
/*v->v.z = LERP(a->v.z, b->v.z, t);*/\
|
||||
v->v.g = LERP(a->v.g, b->v.g, t);\
|
||||
v->t.u = LERP(a->t.u, b->t.u, t);\
|
||||
v->t.v = LERP(a->t.v, b->t.v, t);\
|
||||
}
|
||||
|
||||
/* TODO
|
||||
#define CLIP_NEAR(znear, output) {\
|
||||
//clipZ(znear, output, count, a, b);\
|
||||
uint32 t = ((znear - b->v.z) << 16) / (a->v.z - b->v.z);\
|
||||
VertexUV* v = output + count++;\
|
||||
int32 ax = (a->v.x - (FRAME_WIDTH / 2)) * a->v.z;\
|
||||
int32 ay = (a->v.y - (FRAME_HEIGHT / 2)) * a->v.z;\
|
||||
int32 bx = (b->v.x - (FRAME_WIDTH / 2)) * b->v.z;\
|
||||
int32 by = (b->v.y - (FRAME_HEIGHT / 2)) * b->v.z;\
|
||||
int32 x = LERP(ax, bx, t);\
|
||||
int32 y = LERP(ay, by, t);\
|
||||
v->v.x = (x / znear) + (FRAME_WIDTH / 2);\
|
||||
v->v.y = (y / znear) + (FRAME_HEIGHT / 2);\
|
||||
v->v.z = LERP(a->v.z, b->v.z, t);\
|
||||
v->v.g = LERP(a->v.g, b->v.g, t);\
|
||||
v->uv = (LERP(a->uv & 0xFFFF, b->uv & 0xFFFF, t)) | (LERP(a->uv >> 16, b->uv >> 16, t) << 16);\
|
||||
}
|
||||
*/
|
||||
|
||||
#define CLIP_XY(X, Y, X0, X1, input, output) {\
|
||||
const VertexUV *a, *b = input + pCount - 1;\
|
||||
for (int32 i = 0; i < pCount; i++) {\
|
||||
a = b;\
|
||||
b = input + i;\
|
||||
if (a->v.X < X0) {\
|
||||
if (b->v.X < X0) continue;\
|
||||
CLIP_AXIS(X, Y, X0, output);\
|
||||
} else if (a->v.X > X1) {\
|
||||
if (b->v.X > X1) continue;\
|
||||
CLIP_AXIS(X, Y, X1, output);\
|
||||
}\
|
||||
if (b->v.X < X0) {\
|
||||
CLIP_AXIS(X, Y, X0, output);\
|
||||
} else if (b->v.X > X1) {\
|
||||
CLIP_AXIS(X, Y, X1, output);\
|
||||
} else {\
|
||||
output[count++] = *b;\
|
||||
}\
|
||||
}\
|
||||
if (count < 3) return NULL;\
|
||||
}
|
||||
|
||||
#define ZNEAR (VIEW_MIN_F << FIXED_SHIFT >> FOV_SHIFT)
|
||||
|
||||
#define CLIP_Z(input, output) {\
|
||||
const VertexUV *a, *b = input + pCount - 1;\
|
||||
for (int32 i = 0; i < pCount; i++) {\
|
||||
a = b;\
|
||||
b = input + i;\
|
||||
if (a->v.z < ZNEAR) {\
|
||||
if (b->v.z < ZNEAR) continue;\
|
||||
CLIP_NEAR(ZNEAR, output);\
|
||||
}\
|
||||
if (b->v.z < ZNEAR) {\
|
||||
CLIP_NEAR(ZNEAR, output);\
|
||||
} else {\
|
||||
output[count++] = *b;\
|
||||
}\
|
||||
}\
|
||||
if (count < 3) return NULL;\
|
||||
}
|
||||
|
||||
int32 count = 0;
|
||||
|
||||
VertexUV *in = poly;
|
||||
VertexUV *out = tmp;
|
||||
/*
|
||||
uint32 clipFlags = poly[0].v.clip | poly[1].v.clip | poly[2].v.clip;
|
||||
if (pCount > 3) {
|
||||
clipFlags |= poly[3].v.clip;
|
||||
}
|
||||
|
||||
if (clipFlags & 16) {
|
||||
CLIP_Z(in, out);
|
||||
swap(in, out);
|
||||
pCount = count;
|
||||
count = 0;
|
||||
}
|
||||
*/
|
||||
{//if (clipFlags & (1 | 2 | 4 | 8)) {
|
||||
// clip x
|
||||
CLIP_XY(x, y, viewport.x0, viewport.x1, in, out);
|
||||
|
||||
pCount = count;
|
||||
count = 0;
|
||||
|
||||
// clip y
|
||||
CLIP_XY(y, x, viewport.y0, viewport.y1, out, in);
|
||||
pCount = count;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
void rasterize(const Face* face, const VertexUV *top)
|
||||
{
|
||||
uint16* pixel = (uint16*)fb + top->v.y * VRAM_WIDTH;
|
||||
#ifdef DEBUG_OVERDRAW
|
||||
rasterize_overdraw(pixel, top, top);
|
||||
#else
|
||||
#if 0
|
||||
rasterizeG(pixel, top, top, (face->flags & FACE_TEXTURE) + 10);
|
||||
//rasterize_dummy(pixel, top, top);
|
||||
//rasterizeGT(pixel, top, top);
|
||||
#else
|
||||
if (face->flags & FACE_COLORED) {
|
||||
if (face->flags & FACE_FLAT) {
|
||||
if (face->flags & FACE_SHADOW) {
|
||||
rasterizeS(pixel, top, top);
|
||||
} else {
|
||||
rasterizeF(pixel, top, top, face->flags & FACE_TEXTURE);
|
||||
}
|
||||
} else {
|
||||
rasterizeG(pixel, top, top, face->flags & FACE_TEXTURE);
|
||||
}
|
||||
} else {
|
||||
if (enableAlphaTest) {
|
||||
if (face->flags & FACE_FLAT) {
|
||||
rasterizeFTA(pixel, top, top);
|
||||
} else {
|
||||
rasterizeGTA(pixel, top, top);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
rasterizeFT(pixel, top, top);
|
||||
#else
|
||||
if (face->flags & FACE_FLAT) {
|
||||
rasterizeFT(pixel, top, top);
|
||||
} else {
|
||||
rasterizeGT(pixel, top, top);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawTriangle(const Face* face, VertexUV *v)
|
||||
{
|
||||
VertexUV *v1 = v + 0,
|
||||
*v2 = v + 1,
|
||||
*v3 = v + 2;
|
||||
|
||||
v1->next = v2;
|
||||
v2->next = v3;
|
||||
v3->next = v1;
|
||||
v1->prev = v3;
|
||||
v2->prev = v1;
|
||||
v3->prev = v2;
|
||||
|
||||
const VertexUV* top = v1;
|
||||
if (v1->v.y < v2->v.y) {
|
||||
if (v1->v.y < v3->v.y) {
|
||||
top = v1;
|
||||
} else {
|
||||
top = v3;
|
||||
}
|
||||
} else {
|
||||
if (v2->v.y < v3->v.y) {
|
||||
top = v2;
|
||||
} else {
|
||||
top = v3;
|
||||
}
|
||||
}
|
||||
|
||||
rasterize(face, top);
|
||||
}
|
||||
|
||||
void drawQuad(const Face* face, VertexUV *v)
|
||||
{
|
||||
VertexUV *v1 = v + 0,
|
||||
*v2 = v + 1,
|
||||
*v3 = v + 2,
|
||||
*v4 = v + 3;
|
||||
|
||||
v1->next = v2;
|
||||
v2->next = v3;
|
||||
v3->next = v4;
|
||||
v4->next = v1;
|
||||
v1->prev = v4;
|
||||
v2->prev = v1;
|
||||
v3->prev = v2;
|
||||
v4->prev = v3;
|
||||
|
||||
VertexUV* top;
|
||||
|
||||
if (v1->v.y < v2->v.y) {
|
||||
if (v1->v.y < v3->v.y) {
|
||||
top = (v1->v.y < v4->v.y) ? v1 : v4;
|
||||
} else {
|
||||
top = (v3->v.y < v4->v.y) ? v3 : v4;
|
||||
}
|
||||
} else {
|
||||
if (v2->v.y < v3->v.y) {
|
||||
top = (v2->v.y < v4->v.y) ? v2 : v4;
|
||||
} else {
|
||||
top = (v3->v.y < v4->v.y) ? v3 : v4;
|
||||
}
|
||||
}
|
||||
|
||||
rasterize(face, top);
|
||||
}
|
||||
|
||||
void drawPoly(Face* face, VertexUV* v)
|
||||
{
|
||||
VertexUV tmp[16];
|
||||
|
||||
int32 count = (face->flags & FACE_TRIANGLE) ? 3 : 4;
|
||||
|
||||
v = clipPoly(v, tmp, count);
|
||||
|
||||
if (!v) return;
|
||||
|
||||
if (count <= 4)
|
||||
{
|
||||
face->indices[0] = 0;
|
||||
face->indices[1] = 1;
|
||||
face->indices[2] = 2;
|
||||
face->indices[3] = 3;
|
||||
|
||||
if (count == 3) {
|
||||
|
||||
if (v[0].v.y == v[1].v.y &&
|
||||
v[0].v.y == v[2].v.y)
|
||||
return;
|
||||
|
||||
drawTriangle(face, v);
|
||||
} else {
|
||||
|
||||
if (v[0].v.y == v[1].v.y &&
|
||||
v[0].v.y == v[2].v.y &&
|
||||
v[0].v.y == v[3].v.y)
|
||||
return;
|
||||
|
||||
drawQuad(face, v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
VertexUV* top = v;
|
||||
top->next = v + 1;
|
||||
top->prev = v + count - 1;
|
||||
|
||||
bool skip = true;
|
||||
|
||||
for (int32 i = 1; i < count; i++)
|
||||
{
|
||||
VertexUV *p = v + i;
|
||||
|
||||
p->next = v + (i + 1) % count;
|
||||
p->prev = v + (i - 1 + count) % count;
|
||||
|
||||
if (p->v.y != top->v.y)
|
||||
{
|
||||
if (p->v.y < top->v.y) {
|
||||
top = p;
|
||||
}
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
return; // zero height poly
|
||||
}
|
||||
|
||||
rasterize(face, top);
|
||||
}
|
||||
|
||||
void drawGlyph(const Sprite *sprite, int32 x, int32 y)
|
||||
{
|
||||
int32 w = sprite->r - sprite->l;
|
||||
int32 h = sprite->b - sprite->t;
|
||||
|
||||
w = (w >> 1) << 1; // make it even
|
||||
|
||||
int32 ix = x + sprite->l;
|
||||
int32 iy = y + sprite->t;
|
||||
|
||||
#if defined(MODE_PAL)
|
||||
uint16* pixel = (uint16*)fb + iy * VRAM_WIDTH + (ix >> 1);
|
||||
#elif defined(ROTATE90_MODE)
|
||||
uint16* pixel = (uint16*)fb + iy;
|
||||
#else
|
||||
uint16* pixel = (uint16*)fb + iy * VRAM_WIDTH + ix;
|
||||
#endif
|
||||
|
||||
const uint8* glyphData = tiles + (sprite->tile << 16) + 256 * sprite->v + sprite->u;
|
||||
|
||||
while (h--)
|
||||
{
|
||||
#if defined(MODE_PAL)
|
||||
const uint8* p = glyphData;
|
||||
|
||||
for (int32 i = 0; i < (w / 2); i++)
|
||||
{
|
||||
if (p[0] || p[1])
|
||||
{
|
||||
uint16 d = pixel[i];
|
||||
|
||||
if (p[0]) d = (d & 0xFF00) | p[0];
|
||||
if (p[1]) d = (d & 0x00FF) | (p[1] << 8);
|
||||
|
||||
pixel[i] = d;
|
||||
}
|
||||
|
||||
p += 2;
|
||||
}
|
||||
#else
|
||||
for (int32 i = 0; i < w; i++)
|
||||
{
|
||||
if (glyphData[i] == 0) continue;
|
||||
#ifdef ROTATE90_MODE
|
||||
pixel[(FRAME_HEIGHT - (ix + i) - 1) * FRAME_WIDTH] = palette[glyphData[i]];
|
||||
#else
|
||||
pixel[i] = palette[glyphData[i]];
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ROTATE90_MODE
|
||||
pixel += 1;
|
||||
#else
|
||||
pixel += VRAM_WIDTH;
|
||||
#endif
|
||||
|
||||
glyphData += 256;
|
||||
}
|
||||
}
|
||||
|
||||
X_INLINE void faceAddToOTable(Face* face, int32 depth)
|
||||
{
|
||||
ASSERT(depth < OT_SIZE);
|
||||
face->next = otFaces[depth];
|
||||
otFaces[depth] = face;
|
||||
|
||||
if (depth < otMin) otMin = depth;
|
||||
if (depth > otMax) otMax = depth;
|
||||
}
|
||||
|
||||
void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex)
|
||||
{
|
||||
ASSERT(gFacesCount < MAX_FACES);
|
||||
|
||||
const Vertex* v = gVertices + startVertex;
|
||||
const Vertex* v1 = v + indices[0];
|
||||
const Vertex* v2 = v + indices[1];
|
||||
const Vertex* v3 = v + indices[2];
|
||||
const Vertex* v4 = v + indices[3];
|
||||
|
||||
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16 || v4->clip == 16)
|
||||
return;
|
||||
|
||||
if (enableClipping)
|
||||
{
|
||||
if (v1->clip & v2->clip & v3->clip & v4->clip)
|
||||
return;
|
||||
|
||||
if (v1->clip | v2->clip | v3->clip | v4->clip) {
|
||||
flags |= FACE_CLIPPED;
|
||||
}
|
||||
}
|
||||
|
||||
if (v1->g == v2->g && v1->g == v3->g && v1->g == v4->g) {
|
||||
flags |= FACE_FLAT;
|
||||
}
|
||||
|
||||
int32 depth = X_MAX(v1->z, X_MAX(v2->z, X_MAX(v3->z, v4->z))) >> OT_SHIFT;
|
||||
|
||||
// z-bias hack for the shadow plane
|
||||
if (flags & FACE_SHADOW) {
|
||||
depth = X_MAX(0, depth - 8);
|
||||
}
|
||||
|
||||
Face *f = gFaces + gFacesCount++;
|
||||
faceAddToOTable(f, depth);
|
||||
|
||||
f->flags = uint16(flags);
|
||||
f->start = startVertex + indices[0];
|
||||
f->indices[0] = 0;
|
||||
f->indices[1] = indices[1] - indices[0];
|
||||
f->indices[2] = indices[2] - indices[0];
|
||||
f->indices[3] = indices[3] - indices[0];
|
||||
}
|
||||
|
||||
void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex)
|
||||
{
|
||||
ASSERT(gFacesCount < MAX_FACES);
|
||||
|
||||
const Vertex* v = gVertices + startVertex;
|
||||
const Vertex* v1 = v + indices[0];
|
||||
const Vertex* v2 = v + indices[1];
|
||||
const Vertex* v3 = v + indices[2];
|
||||
|
||||
if (v1->clip == 16 || v2->clip == 16 || v3->clip == 16)
|
||||
return;
|
||||
|
||||
if (enableClipping)
|
||||
{
|
||||
if (v1->clip & v2->clip & v3->clip)
|
||||
return;
|
||||
|
||||
if (v1->clip | v2->clip | v3->clip) {
|
||||
flags |= FACE_CLIPPED;
|
||||
}
|
||||
}
|
||||
|
||||
if (v1->g == v2->g && v1->g == v3->g) {
|
||||
flags |= FACE_FLAT;
|
||||
}
|
||||
|
||||
int32 depth = X_MAX(v1->z, X_MAX(v2->z, v3->z)) >> OT_SHIFT;
|
||||
|
||||
Face *f = gFaces + gFacesCount++;
|
||||
faceAddToOTable(f, depth);
|
||||
|
||||
f->flags = uint16(flags | FACE_TRIANGLE);
|
||||
f->start = startVertex + indices[0];
|
||||
f->indices[0] = 0;
|
||||
f->indices[1] = indices[1] - indices[0];
|
||||
f->indices[2] = indices[2] - indices[0];
|
||||
}
|
||||
|
||||
void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex)
|
||||
{
|
||||
for (uint16 i = 0; i < qCount; i++) {
|
||||
faceAddQuad(quads[i].flags, quads[i].indices, startVertex);
|
||||
}
|
||||
|
||||
for (uint16 i = 0; i < tCount; i++) {
|
||||
faceAddTriangle(triangles[i].flags, triangles[i].indices, 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)
|
||||
{
|
||||
for (int i = 0; i < rCount; i++) {
|
||||
faceAddQuad(rFaces[i].flags, rFaces[i].indices, startVertex);
|
||||
}
|
||||
|
||||
for (int i = 0; i < crCount; i++) {
|
||||
faceAddQuad(crFaces[i].flags | FACE_COLORED, crFaces[i].indices, startVertex);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tCount; i++) {
|
||||
faceAddTriangle(tFaces[i].flags, tFaces[i].indices, startVertex);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ctCount; i++) {
|
||||
faceAddTriangle(ctFaces[i].flags | FACE_COLORED, ctFaces[i].indices, startVertex);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FACES
|
||||
int32 gFacesCountMax, gVerticesCountMax;
|
||||
#endif
|
||||
|
||||
void flush()
|
||||
{
|
||||
if (gFacesCount)
|
||||
{
|
||||
PROFILE_START();
|
||||
for (int32 i = otMax; i >= otMin; i--)
|
||||
{
|
||||
if (!otFaces[i]) continue;
|
||||
|
||||
Face *face = otFaces[i];
|
||||
otFaces[i] = NULL;
|
||||
|
||||
do {
|
||||
VertexUV v[16];
|
||||
|
||||
uint32 flags = face->flags;
|
||||
|
||||
if (!(flags & FACE_COLORED))
|
||||
{
|
||||
const Texture &tex = textures[face->flags & FACE_TEXTURE];
|
||||
tile = tiles + (tex.tile << 16);
|
||||
|
||||
v[0].t.uv = ((tex.uv0 << 16) | (tex.uv0 >> 16)) & 0xFF00FF00; // TODO preprocess
|
||||
v[1].t.uv = ((tex.uv1 << 16) | (tex.uv1 >> 16)) & 0xFF00FF00; // TODO preprocess
|
||||
v[2].t.uv = ((tex.uv2 << 16) | (tex.uv2 >> 16)) & 0xFF00FF00; // TODO preprocess
|
||||
v[3].t.uv = ((tex.uv3 << 16) | (tex.uv3 >> 16)) & 0xFF00FF00; // TODO preprocess
|
||||
enableAlphaTest = (tex.attribute == 1);
|
||||
}
|
||||
|
||||
Vertex *p = gVertices + face->start;
|
||||
v[0].v = p[0];
|
||||
v[1].v = p[face->indices[1]];
|
||||
v[2].v = p[face->indices[2]];
|
||||
if (!(flags & FACE_TRIANGLE)) {
|
||||
v[3].v = p[face->indices[3]];
|
||||
}
|
||||
|
||||
if (flags & FACE_CLIPPED) {
|
||||
drawPoly(face, v);
|
||||
} else {
|
||||
if (flags & FACE_TRIANGLE) {
|
||||
drawTriangle(face, v);
|
||||
} else {
|
||||
drawQuad(face, v);
|
||||
}
|
||||
};
|
||||
|
||||
face = face->next;
|
||||
} while (face);
|
||||
}
|
||||
|
||||
PROFILE_STOP(dbg_flush);
|
||||
|
||||
otMin = OT_SIZE - 1;
|
||||
otMax = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FACES
|
||||
if ((gFacesCount > gFacesCountMax) || (gVerticesCount > gVerticesCountMax))
|
||||
{
|
||||
if (gFacesCount > gFacesCountMax) gFacesCountMax = gFacesCount;
|
||||
if (gVerticesCount > gVerticesCountMax) gVerticesCountMax = gVerticesCount;
|
||||
printf("v: %d f: %d\n", gVerticesCountMax, gFacesCountMax);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PROFILE
|
||||
dbg_vert_count += gVerticesCount;
|
||||
dbg_poly_count += gFacesCount;
|
||||
#endif
|
||||
|
||||
gVerticesCount = 0;
|
||||
gFacesCount = 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
dmaFill((void*)fb, 0, VRAM_WIDTH * FRAME_HEIGHT * 2);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
767
src/platform/gba/room.h
Normal file
767
src/platform/gba/room.h
Normal file
@ -0,0 +1,767 @@
|
||||
#ifndef H_ROOM
|
||||
#define H_ROOM
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int32 getBridgeFloor(const Item* item, int32 x, int32 z)
|
||||
{
|
||||
if (item->type == ITEM_BRIDGE_FLAT) {
|
||||
return item->pos.y;
|
||||
}
|
||||
|
||||
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_TILT1) ? (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 getItemFloorCeiling(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;
|
||||
}
|
||||
case ITEM_DRAWBRIDGE:
|
||||
{
|
||||
if (item->state == 1) {
|
||||
h = getDrawBridgeFloor(item, x, z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ITEM_BRIDGE_FLAT:
|
||||
case ITEM_BRIDGE_TILT1:
|
||||
case ITEM_BRIDGE_TILT2:
|
||||
{
|
||||
h = getBridgeFloor(item, x, z);
|
||||
break;
|
||||
}
|
||||
case ITEM_TRAP_DOOR_1:
|
||||
case ITEM_TRAP_DOOR_2:
|
||||
{
|
||||
if (item->state != 0)
|
||||
return;
|
||||
|
||||
h = getTrapDoorFloor(item, x, z);
|
||||
|
||||
if ((floor && (h >= *floor)) || (ceiling && (h <= *ceiling)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (h == WALL)
|
||||
return;
|
||||
|
||||
if (floor && (y <= h))
|
||||
{
|
||||
*floor = h;
|
||||
}
|
||||
|
||||
if (ceiling && (y > h))
|
||||
{
|
||||
*ceiling = h + 256;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const RoomInfo::Sector* RoomInfo::Sector::getSectorBelow(int32 posX, int32 posZ) const
|
||||
{
|
||||
if (roomBelow == NO_ROOM)
|
||||
return this;
|
||||
return rooms[roomBelow].getSector(posX, posZ);
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* RoomInfo::Sector::getSectorAbove(int32 posX, int32 posZ) const
|
||||
{
|
||||
if (roomAbove == NO_ROOM)
|
||||
return this;
|
||||
return rooms[roomAbove].getSector(posX, posZ);
|
||||
}
|
||||
|
||||
int32 RoomInfo::Sector::getFloor(int32 x, int32 y, int32 z) const
|
||||
{
|
||||
gLastFloorData = NULL;
|
||||
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(x, z);
|
||||
|
||||
int32 floor = lowerSector->floor << 8;
|
||||
|
||||
gLastFloorSlant.value = 0;
|
||||
|
||||
if (lowerSector->floorIndex)
|
||||
{
|
||||
const FloorData* fd = floors + lowerSector->floorIndex;
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // found floor
|
||||
{
|
||||
gLastFloorSlant = *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;
|
||||
}
|
||||
}
|
||||
|
||||
lowerSector->getTriggerFloorCeiling(x, y, z, &floor, NULL);
|
||||
|
||||
return floor;
|
||||
}
|
||||
|
||||
int32 RoomInfo::Sector::getCeiling(int32 x, int32 y, int32 z) const
|
||||
{
|
||||
const RoomInfo::Sector* upperSector = getSectorAbove(x, z);
|
||||
|
||||
int32 ceiling = upperSector->ceiling << 8;
|
||||
|
||||
if (upperSector->floorIndex)
|
||||
{
|
||||
const FloorData* fd = floors + upperSector->floorIndex;
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor
|
||||
{
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_CEILING) // found ceiling
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const RoomInfo::Sector* lowerSector = getSectorBelow(x, z);
|
||||
|
||||
lowerSector->getTriggerFloorCeiling(x, y, z, NULL, &ceiling);
|
||||
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
Room* RoomInfo::Sector::getNextRoom() const
|
||||
{
|
||||
if (!floorIndex)
|
||||
return NULL;
|
||||
|
||||
// always in this order
|
||||
// - floor
|
||||
// - ceiling
|
||||
// - portal
|
||||
// - other
|
||||
|
||||
const FloorData* fd = floors + floorIndex;
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor
|
||||
{
|
||||
if (cmd.end) return NULL;
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
if (cmd.func == FLOOR_TYPE_CEILING) // skip ceiling
|
||||
{
|
||||
if (cmd.end) return NULL;
|
||||
fd++;
|
||||
cmd = (fd++)->cmd;
|
||||
}
|
||||
|
||||
if (cmd.func != FLOOR_TYPE_PORTAL) // no portal
|
||||
return NULL;
|
||||
|
||||
ASSERT(fd->value != NO_ROOM);
|
||||
|
||||
return rooms + fd->value;
|
||||
}
|
||||
|
||||
void RoomInfo::Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int32* ceiling) const
|
||||
{
|
||||
if (!floorIndex)
|
||||
return;
|
||||
|
||||
FloorData::Command cmd;
|
||||
const FloorData* fd = floors + floorIndex;
|
||||
|
||||
do {
|
||||
cmd = (fd++)->cmd;
|
||||
|
||||
switch (cmd.func)
|
||||
{
|
||||
case FLOOR_TYPE_PORTAL:
|
||||
case FLOOR_TYPE_FLOOR:
|
||||
case FLOOR_TYPE_CEILING:
|
||||
{
|
||||
fd++;
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOOR_TYPE_TRIGGER:
|
||||
{
|
||||
if (floor && !gLastFloorData) {
|
||||
gLastFloorData = fd - 1;
|
||||
}
|
||||
|
||||
fd++;
|
||||
FloorData::TriggerCommand trigger;
|
||||
|
||||
do {
|
||||
trigger = (fd++)->triggerCmd;
|
||||
|
||||
if (trigger.action == TRIGGER_ACTION_ACTIVATE_OBJECT)
|
||||
{
|
||||
getItemFloorCeiling(items + trigger.args, x, y, z, floor, ceiling);
|
||||
}
|
||||
|
||||
if (trigger.action == TRIGGER_ACTION_ACTIVATE_CAMERA)
|
||||
{
|
||||
trigger = (fd++)->triggerCmd; // skip camera index
|
||||
}
|
||||
|
||||
} while (!trigger.end);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FLOOR_TYPE_LAVA:
|
||||
if (floor) {
|
||||
gLastFloorData = fd - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!cmd.end);
|
||||
}
|
||||
|
||||
|
||||
const RoomInfo::Sector* Room::getSector(int32 posX, int32 posZ) const
|
||||
{
|
||||
int32 sx = X_CLAMP((posX - x) >> 10, 0, xSectors - 1);
|
||||
int32 sz = X_CLAMP((posZ - z) >> 10, 0, zSectors - 1);
|
||||
|
||||
return sectors + sx * zSectors + sz;
|
||||
}
|
||||
|
||||
Room* Room::getRoom(int32 x, int32 y, int32 z)
|
||||
{
|
||||
const RoomInfo::Sector* sector = getSector(x, z);
|
||||
|
||||
Room* room = this;
|
||||
|
||||
while (1)
|
||||
{
|
||||
Room* nextRoom = sector->getNextRoom();
|
||||
if (!nextRoom)
|
||||
break;
|
||||
room = nextRoom;
|
||||
sector = room->getSector(x, z);
|
||||
};
|
||||
|
||||
while (sector->roomAbove != NO_ROOM && y < (sector->ceiling << 8))
|
||||
{
|
||||
room = rooms + sector->roomAbove;
|
||||
sector = room->getSector(x, z);
|
||||
}
|
||||
|
||||
while (sector->roomBelow != NO_ROOM && y >= (sector->floor << 8))
|
||||
{
|
||||
room = rooms + sector->roomBelow;
|
||||
sector = room->getSector(x, z);
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
int32 Room::getWaterLevel()
|
||||
{
|
||||
return WALL; // TODO
|
||||
}
|
||||
|
||||
int32 Room::getWaterDepth()
|
||||
{
|
||||
return WALL; // TODO
|
||||
}
|
||||
|
||||
bool Room::checkPortal(const RoomInfo::Portal* portal)
|
||||
{
|
||||
vec3i d;
|
||||
d.x = portal->v[0].x - cameraViewPos.x + x;
|
||||
d.y = portal->v[0].y - cameraViewPos.y;
|
||||
d.z = portal->v[0].z - cameraViewPos.z + z;
|
||||
|
||||
if (DP33(portal->n, d) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 x0 = clip.x1;
|
||||
int32 y0 = clip.y1;
|
||||
int32 x1 = clip.x0;
|
||||
int32 y1 = 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) ? viewport.x1 : viewport.x0;
|
||||
y = (y > 0) ? viewport.y1 : viewport.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 < clip.x0) x0 = clip.x0;
|
||||
if (x1 > clip.x1) x1 = clip.x1;
|
||||
if (y0 < clip.y0) y0 = clip.y0;
|
||||
if (y1 > clip.y1) y1 = 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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Room** Room::addVisibleRoom(Room** list)
|
||||
{
|
||||
matrixPush();
|
||||
matrixTranslateAbs(vec3i(x, 0, z));
|
||||
|
||||
for (int32 i = 0; i < pCount; i++)
|
||||
{
|
||||
const RoomInfo::Portal* portal = portals + i;
|
||||
|
||||
if (checkPortal(portal))
|
||||
{
|
||||
Room* nextRoom = rooms + portal->roomIndex;
|
||||
|
||||
list = nextRoom->addVisibleRoom(list);
|
||||
|
||||
if (!nextRoom->visible) {
|
||||
nextRoom->visible = true;
|
||||
*list++ = nextRoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrixPop();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Room** Room::getVisibleRooms()
|
||||
{
|
||||
Room** list = roomsList;
|
||||
|
||||
list = addVisibleRoom(list);
|
||||
*list++ = this;
|
||||
*list++ = NULL;
|
||||
|
||||
ASSERT(list - roomsList <= MAX_ROOM_LIST);
|
||||
|
||||
return roomsList;
|
||||
}
|
||||
|
||||
void Room::reset()
|
||||
{
|
||||
visible = false;
|
||||
clip = Rect( FRAME_WIDTH, FRAME_HEIGHT, 0, 0 );
|
||||
}
|
||||
|
||||
Room** Room::addNearRoom(Room** list, int32 x, int32 y, int32 z)
|
||||
{
|
||||
Room* nearRoom = getRoom(x, y, z);
|
||||
|
||||
int32 count = list - roomsList;
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
if (roomsList[i] == nearRoom) return list;
|
||||
}
|
||||
|
||||
*list++ = nearRoom;
|
||||
return list;
|
||||
}
|
||||
|
||||
Room** Room::getNearRooms(const vec3i &pos, int32 radius, int32 height)
|
||||
{
|
||||
Room** list = roomsList;
|
||||
|
||||
*list++ = this;
|
||||
|
||||
list = addNearRoom(list, pos.x - radius, pos.y, pos.z - radius);
|
||||
list = addNearRoom(list, pos.x + radius, pos.y, pos.z - radius);
|
||||
list = addNearRoom(list, pos.x + radius, pos.y, pos.z + radius);
|
||||
list = addNearRoom(list, pos.x - radius, pos.y, pos.z + radius);
|
||||
|
||||
list = addNearRoom(list, pos.x - radius, pos.y - height, pos.z - radius);
|
||||
list = addNearRoom(list, pos.x + radius, pos.y - height, pos.z - radius);
|
||||
list = addNearRoom(list, pos.x + radius, pos.y - height, pos.z + radius);
|
||||
list = addNearRoom(list, pos.x - radius, pos.y - height, pos.z + radius);
|
||||
|
||||
*list++ = NULL;
|
||||
|
||||
return roomsList;
|
||||
}
|
||||
|
||||
Room** Room::getAdjRooms()
|
||||
{
|
||||
Room** list = roomsList;
|
||||
|
||||
*list++ = this;
|
||||
for (int32 i = 0; i < pCount; i++)
|
||||
{
|
||||
*list++ = rooms + portals[i].roomIndex;
|
||||
}
|
||||
*list++ = NULL;
|
||||
|
||||
return roomsList;
|
||||
}
|
||||
|
||||
void Room::modify()
|
||||
{
|
||||
if (sectors == sectorsOrig) // TODO ROM only
|
||||
{
|
||||
// convert room->sectors to mutable (non-ROM) data
|
||||
sectors = dynSectors + dynSectorsCount;
|
||||
memcpy((RoomInfo::Sector*)sectors, sectorsOrig, xSectors * zSectors * sizeof(RoomInfo::Sector));
|
||||
|
||||
dynSectorsCount += xSectors * zSectors;
|
||||
//printf("dynSectors: %d\n", dynSectorsCount);
|
||||
ASSERT(dynSectorsCount <= MAX_DYN_SECTORS);
|
||||
}
|
||||
}
|
||||
|
||||
void Room::add(Item* item)
|
||||
{
|
||||
ASSERT(item && item->nextItem == NULL);
|
||||
|
||||
item->room = this;
|
||||
item->nextItem = firstItem;
|
||||
firstItem = item;
|
||||
}
|
||||
|
||||
void Room::remove(Item* item)
|
||||
{
|
||||
ASSERT(item && item->room == this);
|
||||
|
||||
item->room = NULL;
|
||||
|
||||
Item* prev = NULL;
|
||||
Item* curr = firstItem;
|
||||
|
||||
while (curr)
|
||||
{
|
||||
Item* next = curr->nextItem;
|
||||
|
||||
if (curr == item)
|
||||
{
|
||||
item->nextItem = NULL;
|
||||
|
||||
if (prev) {
|
||||
prev->nextItem = next;
|
||||
} else {
|
||||
firstItem = next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void checkTrigger(const FloorData* fd, Item* lara)
|
||||
{
|
||||
if (!fd) return;
|
||||
|
||||
if (fd->cmd.func == FLOOR_TYPE_LAVA)
|
||||
{
|
||||
// TODO lava
|
||||
|
||||
if (fd->cmd.end)
|
||||
return;
|
||||
fd++;
|
||||
}
|
||||
|
||||
FloorData::Command cmd = (fd++)->cmd;
|
||||
FloorData::TriggerInfo info = (fd++)->triggerInfo;
|
||||
|
||||
Item* switchItem = NULL;
|
||||
Item* keyItem = NULL;
|
||||
Item* pickupItem = NULL;
|
||||
|
||||
if (!lara && cmd.type != TRIGGER_TYPE_OBJECT)
|
||||
return;
|
||||
|
||||
if (lara)
|
||||
{
|
||||
switch (cmd.type)
|
||||
{
|
||||
case TRIGGER_TYPE_ACTIVATE:
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_PAD:
|
||||
case TRIGGER_TYPE_ANTIPAD:
|
||||
if (lara->pos.y != lara->floor)
|
||||
return;
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_SWITCH:
|
||||
switchItem = items + fd->triggerCmd.args;
|
||||
if (!useSwitch(switchItem, info.timer))
|
||||
return;
|
||||
fd++;
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_KEY:
|
||||
keyItem = items + fd->triggerCmd.args;
|
||||
if (!useKey(keyItem))
|
||||
return;
|
||||
fd++;
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_PICKUP:
|
||||
pickupItem = items + fd->triggerCmd.args;
|
||||
if (!usePickup(pickupItem))
|
||||
return;
|
||||
fd++;
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_OBJECT:
|
||||
return;
|
||||
|
||||
case TRIGGER_TYPE_COMBAT:
|
||||
// TODO unused?
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPE_DUMMY:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
FloorData::TriggerCommand triggerCmd = (fd++)->triggerCmd;
|
||||
|
||||
switch (triggerCmd.action)
|
||||
{
|
||||
case TRIGGER_ACTION_ACTIVATE_OBJECT: {
|
||||
Item* item = items + triggerCmd.args;
|
||||
|
||||
if (item->flags.once)
|
||||
break;
|
||||
|
||||
item->timer = info.timer;
|
||||
if (item->timer != 1)
|
||||
item->timer *= 30;
|
||||
|
||||
if (cmd.type == TRIGGER_TYPE_SWITCH) {
|
||||
item->flags.mask ^= info.mask;
|
||||
} else if (cmd.type == TRIGGER_TYPE_ANTIPAD) {
|
||||
item->flags.mask &= ~info.mask;
|
||||
} else {
|
||||
item->flags.mask |= info.mask;
|
||||
}
|
||||
|
||||
if (item->flags.mask != ITEM_FLAGS_MASK_ALL)
|
||||
break;
|
||||
|
||||
item->flags.once |= info.once;
|
||||
|
||||
if (item->flags.active)
|
||||
break;
|
||||
|
||||
item->flags.status = ITEM_FLAGS_STATUS_ACTIVE;
|
||||
|
||||
item->activate();
|
||||
break;
|
||||
}
|
||||
|
||||
case TRIGGER_ACTION_ACTIVATE_CAMERA:
|
||||
// TODO fixed camera
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_FLOW:
|
||||
// TODO flow
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_FLIP:
|
||||
// TODO flipmap
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_FLIP_ON:
|
||||
// TODO flipmap
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_FLIP_OFF:
|
||||
// TODO flipmap
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_CAMERA_TARGET:
|
||||
// TODO change fixed camera target
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_END:
|
||||
// TODO go to the next level
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_SOUNDTRACK:
|
||||
// TODO soundtrack
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_EFFECT:
|
||||
// TODO effect
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_SECRET: {
|
||||
if ((gSaveGame.secrets >> triggerCmd.args) & 1)
|
||||
break;
|
||||
|
||||
gSaveGame.secrets |= (1 << triggerCmd.args);
|
||||
mixer.playMusic(TRACK_13_WAV); // TODO play sample?
|
||||
break;
|
||||
}
|
||||
|
||||
case TRIGGER_ACTION_CLEAR_BODIES:
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_FLYBY:
|
||||
break;
|
||||
|
||||
case TRIGGER_ACTION_CUTSCENE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (triggerCmd.end) break;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -3,7 +3,26 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct Sound
|
||||
int16 IMA_INDEX[] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
};
|
||||
|
||||
int16 IMA_STEP[] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767
|
||||
};
|
||||
|
||||
struct Mixer
|
||||
{
|
||||
enum SoundMode {
|
||||
UNIQUE,
|
||||
@ -11,6 +30,52 @@ struct Sound
|
||||
LOOP,
|
||||
};
|
||||
|
||||
struct Music
|
||||
{
|
||||
const uint8* data;
|
||||
int32 size;
|
||||
int32 pos;
|
||||
int32 smp;
|
||||
int32 idx;
|
||||
|
||||
X_INLINE int32 getSample(uint32 n)
|
||||
{
|
||||
int32 step = IMA_STEP[idx];
|
||||
int32 index = n & 7;
|
||||
|
||||
idx = X_CLAMP(idx + IMA_INDEX[index], 0, 88);
|
||||
|
||||
int32 diff = (2 * index + 1) * step >> 3;
|
||||
|
||||
if (n & 8) {
|
||||
smp = X_MAX(smp - diff, -32768);
|
||||
} else {
|
||||
smp = X_MIN(smp + diff, 32767);
|
||||
}
|
||||
|
||||
return smp >> 1;
|
||||
}
|
||||
|
||||
X_INLINE void fill(int32* buffer, int32 count)
|
||||
{
|
||||
for (int i = 0; i < count; i += 2)
|
||||
{
|
||||
uint32 n = data[pos];
|
||||
|
||||
pos++;
|
||||
if (pos >= size)
|
||||
{
|
||||
data = NULL;
|
||||
memset(buffer, 0, (count - i) * sizeof(buffer[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[i + 0] = getSample(n);
|
||||
buffer[i + 1] = getSample(n >> 4);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Sample
|
||||
{
|
||||
const uint8* data;
|
||||
@ -19,11 +84,11 @@ struct Sound
|
||||
int32 inc;
|
||||
int32 volume;
|
||||
|
||||
X_INLINE void fill(int16* buffer, int32 count)
|
||||
X_INLINE void fill(int32* buffer, int32 count)
|
||||
{
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] += SND_DECODE(data[pos >> SND_FIXED_SHIFT]) * volume >> SND_VOL_SHIFT;
|
||||
buffer[i] += SND_DECODE(data[pos >> SND_FIXED_SHIFT]) * volume;
|
||||
|
||||
pos += inc;
|
||||
if (pos >= size)
|
||||
@ -36,19 +101,29 @@ struct Sound
|
||||
}
|
||||
};
|
||||
|
||||
Music music;
|
||||
Sample channels[SND_CHANNELS];
|
||||
int32 channelsCount;
|
||||
|
||||
void fill(uint8* buffer, int32 count)
|
||||
void fill(uint8* bufferA, uint8* bufferB, int32 count)
|
||||
{
|
||||
if (channelsCount == 0)
|
||||
UNUSED(bufferB);
|
||||
|
||||
if ((channelsCount == 0) && !music.data)
|
||||
{
|
||||
dmaFill(buffer, SND_ENCODE(0), count);
|
||||
dmaFill(bufferA, SND_ENCODE(0), count);
|
||||
#ifdef USE_9BIT_SOUND
|
||||
dmaFill(bufferB, SND_ENCODE(0), count);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
int16 tmp[SND_SAMPLES];
|
||||
dmaFill(tmp, 0, sizeof(tmp));
|
||||
int32 tmp[SND_SAMPLES];
|
||||
if (music.data) {
|
||||
music.fill(tmp, count);
|
||||
} else {
|
||||
dmaFill(tmp, 0, sizeof(tmp));
|
||||
}
|
||||
|
||||
int32 ch = channelsCount;
|
||||
while (ch--)
|
||||
@ -64,13 +139,24 @@ struct Sound
|
||||
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
buffer[i] = SND_ENCODE(X_CLAMP(tmp[i], -128, 127));
|
||||
int32 samp = X_CLAMP(tmp[i] >> SND_VOL_SHIFT, SND_MIN, SND_MAX);
|
||||
|
||||
#if defined(_WIN32)
|
||||
bufferA[i] = SND_ENCODE(samp);
|
||||
#elif defined(__GBA__)
|
||||
#ifdef USE_9BIT_SOUND
|
||||
bufferA[i] = (samp >> 1);
|
||||
bufferB[i] = (samp >> 1) + (samp & 1); // TODO
|
||||
#else
|
||||
bufferA[i] = samp;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
Sample* playSample(const uint8* data, int32 size, int32 volume, int32 pitch, int32 mode)
|
||||
{
|
||||
if (mode == UNIQUE || mode == REPLAY)
|
||||
{
|
||||
@ -97,6 +183,11 @@ struct Sound
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_9BIT_SOUND
|
||||
// expand 8 to 9-bit
|
||||
volume <<= 1;
|
||||
#endif
|
||||
|
||||
Sample* sample = channels + channelsCount++;
|
||||
sample->data = data;
|
||||
sample->size = size << SND_FIXED_SHIFT;
|
||||
@ -107,12 +198,23 @@ struct Sound
|
||||
return sample;
|
||||
}
|
||||
|
||||
void playMusic(const void* data)
|
||||
{
|
||||
music.data = (uint8*)data + 16;
|
||||
music.size = *((int32*)data + 2);
|
||||
music.pos = 0;
|
||||
//music.volume = (1 << SND_VOL_SHIFT);
|
||||
music.smp = 0;
|
||||
music.idx = 0;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
channelsCount = 0;
|
||||
music.data = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
Sound sound;
|
||||
Mixer mixer;
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user