1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

GBA: free camera, portals visibility system

This commit is contained in:
Timur Gagiev 2020-08-17 07:42:21 +03:00
parent c430b393e3
commit 9e1234fc62
5 changed files with 687 additions and 217 deletions

View File

@ -3,76 +3,64 @@
#include "common.h"
uint16 camRotY = 16 << 8;
#define CAM_SPEED (1 << 2)
#define CAM_ROT_SPEED (1 << 8)
#define CAM_ROT_X_MAX int16(85 * 0x8000 / 180)
int32 camSinY;
int32 camCosY;
struct Camera {
vec3i pos;
int16 rotX, rotY;
int32 room;
int32 camX = 75162;
int32 camY = 3072 - 1024;
int32 camZ = 5000;
void init() {
pos.x = 75162;
pos.y = 2048;
pos.z = 5000;
Rect clip;
#ifdef _WIN32
#define CAM_SPEED (1 << 2)
#define CAM_ROT_SPEED (1 << 2)
#else
#define CAM_SPEED (1 << 6)
#define CAM_ROT_SPEED (1 << 8)
#endif
void updateCamera() {
if (keys[IK_LEFT]) camRotY -= CAM_ROT_SPEED;
if (keys[IK_RIGHT]) camRotY += CAM_ROT_SPEED;
{
ALIGN4 ObjAffineSource src;
ALIGN4 ObjAffineDest dst;
src.sX = 0x0100;
src.sY = 0x0100;
src.theta = camRotY;
ObjAffineSet(&src, &dst, 1, 2);
camCosY = dst.pd << 8;
camSinY = dst.pc << 8;
rotX = 0;
rotY = 16 << 8;
}
int32 dx = camSinY;
int32 dz = camCosY;
void update() {
if (keys[IK_UP]) rotX -= CAM_ROT_SPEED;
if (keys[IK_DOWN]) rotX += CAM_ROT_SPEED;
if (keys[IK_LEFT]) rotY -= CAM_ROT_SPEED;
if (keys[IK_RIGHT]) rotY += CAM_ROT_SPEED;
dx *= CAM_SPEED;
dz *= CAM_SPEED;
rotX = clamp(rotX, -CAM_ROT_X_MAX, CAM_ROT_X_MAX);
dx >>= 16;
dz >>= 16;
matrixSetView(pos, rotX, rotY);
if (keys[IK_UP]) {
camX += int32(dx);
camZ += int32(dz);
Matrix &m = matrixGet();
if (keys[IK_R]) {
pos.x += m[0].x * CAM_SPEED >> 10;
pos.y += m[0].y * CAM_SPEED >> 10;
pos.z += m[0].z * CAM_SPEED >> 10;
}
if (keys[IK_L]) {
pos.x -= m[0].x * CAM_SPEED >> 10;
pos.y -= m[0].y * CAM_SPEED >> 10;
pos.z -= m[0].z * CAM_SPEED >> 10;
}
if (keys[IK_A]) {
pos.x += m[2].x * CAM_SPEED >> 10;
pos.y += m[2].y * CAM_SPEED >> 10;
pos.z += m[2].z * CAM_SPEED >> 10;
}
if (keys[IK_B]) {
pos.x -= m[2].x * CAM_SPEED >> 10;
pos.y -= m[2].y * CAM_SPEED >> 10;
pos.z -= m[2].z * CAM_SPEED >> 10;
}
room = getRoomIndex(room, pos);
}
};
if (keys[IK_DOWN]) {
camX -= int32(dx);
camZ -= int32(dz);
}
if (keys[IK_L]) {
camX -= int32(dz);
camZ += int32(dx);
}
if (keys[IK_R]) {
camX += int32(dz);
camZ -= int32(dx);
}
if (keys[IK_A]) camY -= CAM_SPEED;
if (keys[IK_B]) camY += CAM_SPEED;
clip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
}
Camera camera;
#endif

View File

@ -70,32 +70,6 @@ typedef int16 Index;
#define dmaCopy(src,dst,size) memcpy(dst,src,size)
#define ALIGN4
struct ObjAffineSource {
int16 sX;
int16 sY;
uint16 theta;
};
struct ObjAffineDest {
int16 pa;
int16 pb;
int16 pc;
int16 pd;
};
static void ObjAffineSet(ObjAffineSource *source, ObjAffineDest *dest, int32 num, int32 offset) {
float ang = (source->theta >> 8) * PI / 128.0f;
int32 c = int32(cosf(ang) * 16384.0f);
int32 s = int32(sinf(ang) * 16384.0f);
dest->pa = ( source->sX * c) >> 14;
dest->pb = (-source->sX * s) >> 14;
dest->pc = ( source->sY * s) >> 14;
dest->pd = ( source->sY * c) >> 14;
}
#else
#define ALIGN4 __attribute__ ((aligned (4)))
#endif
@ -114,6 +88,23 @@ enum InputKey {
extern bool keys[IK_MAX];
struct vec3i {
int32 x, y, z;
vec3i() = default;
INLINE vec3i(int32 x, int32 y, int32 z) : x(x), y(y), z(z) {}
};
struct vec3s {
int16 x, y, z;
};
struct vec4i {
int32 x, y, z, w;
};
typedef vec4i Matrix[3];
struct Quad {
Index indices[4];
uint16 flags;
@ -131,7 +122,7 @@ struct Room {
};
struct Vertex {
int16 x, y, z;
vec3s pos;
uint16 lighting;
};
@ -141,13 +132,9 @@ struct Room {
};
struct Portal {
struct Vertex {
int16 x, y, z;
};
uint16 roomIndex;
Vertex n;
Vertex v[4];
vec3s n;
vec3s v[4];
};
struct Sector {
@ -193,17 +180,27 @@ struct Room {
struct Node {
uint32 flags;
int32 x, y, z;
vec3i pos;
};
struct Model {
uint16 type;
uint16 index;
uint32 type;
uint16 mCount;
uint16 mStart;
uint32 node;
uint32 frame;
uint16 animation;
uint16 paddding;
};
#define FILE_MODEL_SIZE (sizeof(Model) - 2) // -padding
struct Entity {
uint16 type;
uint16 room;
vec3i pos;
int16 rotation;
uint16 flags;
};
struct Texture {
@ -249,9 +246,16 @@ struct Face {
int8 indices[4];
};
#define FIXED_SHIFT 14
#define FOV_SHIFT 7
#define MAX_MATRICES 8
#define MAX_MODELS 64
#define MAX_ENTITY 190
#define MAX_VERTICES 1024
#define MAX_FACES 384
#define MAX_DIST (16 * 1024)
#define MIN_DIST ((32) << FIXED_SHIFT)
#define MAX_DIST ((16 * 1024) << FIXED_SHIFT)
#define FACE_TRIANGLE 0x8000
#define FACE_COLORED 0x4000
@ -259,17 +263,34 @@ struct Face {
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define SQR(x) ((x) * (x))
#define DP43(a,b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z + (a).w)
#define DP33(a,b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z)
int32 clamp(int32 x, int32 a, int32 b);
int32 phd_sin(int32 x);
int32 phd_cos(int32 x);
Matrix& matrixGet();
void matrixPush();
void matrixPop();
void matrixTranslate(const vec3i &offset);
void matrixTranslateAbs(const vec3i &offset);
void matrixRotate(int16 rotX, int16 rotY, int16 rotZ);
void matrixSetView(const vec3i &pos, int16 rotX, int16 rotY);
void drawGlyph(const Sprite *sprite, int32 x, int32 y);
void drawNumber(int32 number, int32 x, int32 y);
void clear();
void transform(int32 vx, int32 vy, int32 vz, int32 vg, int32 x, int32 y, int32 z);
void transform(const vec3s &v, int32 vg);
void faceAddTriangle(uint16 flags, const Index* indices, int32 startVertex);
void faceAddQuad(uint16 flags, const Index* indices, int32 startVertex);
void flush();
void initRender();
void readLevel(const uint8 *data);
const Room::Sector* getSector(int32 roomIndex, int32 x, int32 z);
int32 getRoomIndex(int32 roomIndex, const vec3i &pos);
#endif

View File

@ -15,7 +15,8 @@ const uint8* tiles[15];
ALIGN4 uint8 lightmap[256 * 32];
uint16 roomsCount;
const Room* rooms;
const uint16* floors;
uint32 texturesCount;
const Texture* textures;
@ -29,27 +30,60 @@ const uint8* meshData;
const uint32* meshOffsets;
const int32* nodes;
const Model* models;
uint32 modelsCount;
EWRAM_DATA Model models[MAX_MODELS];
EWRAM_DATA int16 modelsMap[MAX_ENTITY];
uint32 entitiesCount;
const Entity* entities;
// -----------------------------------
struct RoomDesc {
Rect clip;
bool visible;
int32 x, z;
uint16 vCount;
uint16 qCount;
uint16 tCount;
uint16 pCount;
uint16 zSectors;
uint16 xSectors;
const Room::Vertex* vertices;
const Quad* quads;
const Triangle* triangles;
const Room::Portal* portals;
const Room::Sector* sectors;
INLINE void reset() {
visible = false;
clip = { FRAME_WIDTH, FRAME_HEIGHT, 0, 0 };
}
};
EWRAM_DATA RoomDesc roomDescs[64];
EWRAM_DATA RoomDesc rooms[64];
int32 visRoomsCount;
int32 visRooms[16];
#define ROOM_VISIBLE (1 << 15)
#define ENTITY_LARA 0
#define SEQ_GLYPH 190
enum FloorType {
FLOOR_TYPE_NONE,
FLOOR_TYPE_PORTAL,
FLOOR_TYPE_FLOOR,
FLOOR_TYPE_CEILING,
};
#define SEQ_GLYPH_ID 190
int32 seqGlyphs;
int32 entityLara;
extern uint32 gVerticesCount;
extern Rect clip;
void readLevel(const uint8 *data) { // TODO non-hardcode level loader
tilesCount = *((uint32*)(data + 4));
@ -58,7 +92,9 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
}
roomsCount = *((uint16*)(data + 720908));
rooms = (Room*)(data + 720908 + 2);
const Room* roomsPtr = (Room*)(data + 720908 + 2);
floors = (uint16*)(data + 899492 + 4);
texturesCount = *((uint32*)(data + 1271686));
textures = (Texture*)(data + 1271686 + 4);
@ -73,7 +109,11 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
nodes = (int32*)(data + 990318);
models = (Model*)(data + 1270670);
modelsCount = *((uint32*)(data + 1270666));
const uint8* modelsPtr = (uint8*)(data + 1270666 + 4);
entitiesCount = *((uint32*)(data + 1319252));
entities = (Entity*)(data + 1319252 + 4);
// prepare lightmap
const uint8* f_lightmap = data + 1320576;
@ -97,17 +137,31 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
SetPalette(palette);
#endif
#endif
// prepare models
for (uint32 i = 0; i < modelsCount; i++) {
dmaCopy(modelsPtr, models + i, sizeof(Model)); // sizeof(Model) is faster than FILE_MODEL_SIZE
modelsPtr += FILE_MODEL_SIZE;
modelsMap[models[i].type] = i;
}
// prepare entities
for (uint32 i = 0; i < entitiesCount; i++) {
if (entities[i].type == ENTITY_LARA) {
entityLara = i;
break;
}
}
// prepare glyphs
for (uint32 i = 0; i < spritesSeqCount; i++) {
if (spritesSeq[i].type == SEQ_GLYPH_ID) {
if (spritesSeq[i].type == SEQ_GLYPH) {
seqGlyphs = i;
break;
}
}
// prepare rooms
uint8 *ptr = (uint8*)rooms;
uint8 *ptr = (uint8*)roomsPtr;
for (uint16 roomIndex = 0; roomIndex < roomsCount; roomIndex++) {
const Room *room = (Room*)ptr;
@ -117,7 +171,8 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
memcpy(&dataSize, &room->dataSize, sizeof(dataSize));
uint8* skipPtr = ptr + dataSize * 2;
RoomDesc &desc = roomDescs[roomIndex];
RoomDesc &desc = rooms[roomIndex];
desc.reset();
// offset
memcpy(&desc.x, &room->info.x, sizeof(room->info.x));
@ -149,12 +204,12 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
desc.portals = (Room::Portal*)ptr;
ptr += sizeof(Room::Portal) * desc.pCount;
uint16 zSectors = *((uint16*)ptr);
desc.zSectors = *((uint16*)ptr);
ptr += 2;
uint16 xSectors = *((uint16*)ptr);
desc.xSectors = *((uint16*)ptr);
ptr += 2;
//sectors = (Room::Sector*)sectors;
ptr += sizeof(Room::Sector) * zSectors * xSectors;
desc.sectors = (Room::Sector*)ptr;
ptr += sizeof(Room::Sector) * desc.zSectors * desc.xSectors;
//ambient = *((uint16*)ptr);
ptr += 2;
@ -171,42 +226,19 @@ void readLevel(const uint8 *data) { // TODO non-hardcode level loader
ptr += 2 + 2; // skip alternateRoom and flags
}
camera.init();
camera.room = entities[entityLara].room;
}
void drawRoom(int16 roomIndex) {
RoomDesc &room = roomDescs[roomIndex];
int32 dx = -camX + room.x;
int32 dy = -camY;
int32 dz = -camZ + room.z;
int32 startVertex = gVerticesCount;
const Room::Vertex* vertices = room.vertices;
for (uint16 i = 0; i < room.vCount; i++) {
const Room::Vertex &v = vertices[i];
transform(v.x, v.y, v.z, v.lighting, dx, dy, dz);
}
const Quad* quads = room.quads;
for (uint16 i = 0; i < room.qCount; i++) {
faceAddQuad(quads[i].flags, quads[i].indices, startVertex);
}
const Triangle* triangles = room.triangles;
for (uint16 i = 0; i < room.tCount; i++) {
faceAddTriangle(triangles[i].flags, triangles[i].indices, startVertex);
}
}
void drawMesh(int16 meshIndex, int32 x, int32 y, int32 z) {
void drawMesh(int16 meshIndex) {
uint32 offset = meshOffsets[meshIndex];
const uint8* ptr = meshData + offset;
ptr += 2 * 5; // skip [cx, cy, cz, radius, flags]
int16 vCount = *(int16*)ptr; ptr += 2;
const int16* vertices = (int16*)ptr;
const vec3s* vertices = (vec3s*)ptr;
ptr += vCount * 3 * sizeof(int16);
int16 nCount = *(int16*)ptr; ptr += 2;
@ -231,14 +263,8 @@ void drawMesh(int16 meshIndex, int32 x, int32 y, int32 z) {
int32 startVertex = gVerticesCount;
int32 dx = x - camX;
int32 dy = y - camY;
int32 dz = z - camZ;
const int16* v = vertices;
for (uint16 i = 0; i < vCount; i++) {
transform(v[0], v[1], v[2], 4096, dx, dy, dz);
v += 3;
transform(*vertices++, 4096);
}
for (int i = 0; i < rCount; i++) {
@ -258,7 +284,7 @@ void drawMesh(int16 meshIndex, int32 x, int32 y, int32 z) {
}
}
void drawModel(int32 modelIndex, int32 x, int32 y, int32 z) {
void drawModel(int32 modelIndex) {
const Model* model = models + modelIndex;
// non-aligned access
@ -271,37 +297,35 @@ void drawModel(int32 modelIndex, int32 x, int32 y, int32 z) {
const Node* n = bones;
struct StackItem {
int32 x, y, z;
} stack[4];
StackItem *s = stack;
drawMesh(model->mStart, x, y, z);
drawMesh(model->mStart);
for (int i = 1; i < model->mCount; i++) {
if (n->flags & 1) {
s--;
x = s->x;
y = s->y;
z = s->z;
matrixPop();
}
if (n->flags & 2) {
s->x = x;
s->y = y;
s->z = z;
s++;
matrixPush();
}
x += n->x;
y += n->y;
z += n->z;
matrixTranslate(n->pos);
n++;
drawMesh(model->mStart + i, x, y, z);
drawMesh(model->mStart + i);
}
}
void drawEntity(int32 entityIndex) {
const Entity &e = entities[entityIndex];
matrixPush();
matrixTranslateAbs(vec3i(e.pos.x, e.pos.y - 512, e.pos.z)); // TODO animation
drawModel(modelsMap[e.type]);
matrixPop();
}
void drawNumber(int32 number, int32 x, int32 y) {
const int32 widths[] = { 12, 8, 10, 10, 10, 10, 10, 10, 10, 10 };
@ -314,4 +338,223 @@ void drawNumber(int32 number, int32 x, int32 y) {
}
}
void drawRoom(int16 roomIndex) {
RoomDesc &room = rooms[roomIndex];
clip = room.clip;
int32 startVertex = gVerticesCount;
matrixPush();
matrixTranslateAbs(vec3i(room.x, 0, room.z));
const Room::Vertex* vertex = room.vertices;
for (uint16 i = 0; i < room.vCount; i++) {
transform(vertex->pos, vertex->lighting);
vertex++;
}
matrixPop();
const Quad* quads = room.quads;
for (uint16 i = 0; i < room.qCount; i++) {
faceAddQuad(quads[i].flags, quads[i].indices, startVertex);
}
const Triangle* triangles = room.triangles;
for (uint16 i = 0; i < room.tCount; i++) {
faceAddTriangle(triangles[i].flags, triangles[i].indices, startVertex);
}
if (roomIndex == entityLara) { // TODO draw all entities in the room
drawEntity(entityLara);
}
room.reset();
flush();
}
const Room::Sector* getSector(int32 roomIndex, int32 x, int32 z) {
RoomDesc &room = rooms[roomIndex];
int32 sx = clamp((x - room.x) >> 10, 0, room.xSectors);
int32 sz = clamp((z - room.z) >> 10, 0, room.zSectors);
return room.sectors + sx * room.zSectors + sz;
}
int32 getRoomIndex(int32 roomIndex, const vec3i &pos) {
const Room::Sector *sector = getSector(roomIndex, pos.x, pos.z);
if (sector->floorIndex) {
const uint16 *data = floors + sector->floorIndex;
int16 type = *data++;
if (type == FLOOR_TYPE_FLOOR) {
data++;
type = *data++;
}
if (type == FLOOR_TYPE_CEILING) {
data++;
type = *data++;
}
if ((type & 0xFF) == FLOOR_TYPE_PORTAL) {
roomIndex = *data;
}
}
while (sector->roomAbove != 0xFF && pos.y < (sector->ceiling << 8)) {
roomIndex = sector->roomAbove;
sector = getSector(roomIndex, pos.x, pos.z);
}
while (sector->roomBelow != 0xFF && pos.y >= (sector->floor << 8)) {
roomIndex = sector->roomBelow;
sector = getSector(roomIndex, pos.x, pos.z);
}
return roomIndex;
}
bool checkPortal(int32 roomIndex, const Room::Portal &portal) {
RoomDesc &room = rooms[roomIndex];
vec3i d;
d.x = portal.v[0].x - camera.pos.x + room.x;
d.y = portal.v[0].y - camera.pos.y;
d.z = portal.v[0].z - camera.pos.z + room.z;
if (DP33(portal.n, d) >= 0) {
return false;
}
int32 x0 = room.clip.x1;
int32 y0 = room.clip.y1;
int32 x1 = room.clip.x0;
int32 y1 = room.clip.y0;
int32 znear = 0, zfar = 0;
Matrix &m = matrixGet();
vec3i pv[4];
for (int32 i = 0; i < 4; i++) {
const vec3s &v = portal.v[i];
int32 x = DP43(m[0], v);
int32 y = DP43(m[1], v);
int32 z = DP43(m[2], v);
pv[i].x = x;
pv[i].y = y;
pv[i].z = z;
if (z <= MIN_DIST) {
znear++;
continue;
}
if (z >= MAX_DIST) {
zfar++;
}
if (z != 0) {
z >>= FOV_SHIFT;
x = MyDiv(x, z) + (FRAME_WIDTH / 2);
y = MyDiv(y, z) + (FRAME_HEIGHT / 2);
} else {
x = (x > 0) ? clip.x1 : clip.x0;
y = (y > 0) ? clip.y1 : clip.y0;
}
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
if (znear == 4 || zfar == 4) return false;
if (znear) {
vec3i *a = pv;
vec3i *b = pv + 3;
for (int32 i = 0; i < 4; i++) {
if ((a->z < 0) ^ (b->z < 0)) {
if (a->x < 0 && b->x < 0) {
x0 = 0;
} else if (a->x > 0 && b->x > 0) {
x1 = FRAME_WIDTH;
} else {
x0 = 0;
x1 = FRAME_WIDTH;
}
if (a->y < 0 && b->y < 0) {
y0 = 0;
} else if (a->y > 0 && b->y > 0) {
y1 = FRAME_HEIGHT;
} else {
y0 = 0;
y1 = FRAME_HEIGHT;
}
}
b = a;
a++;
}
}
if (x0 < room.clip.x0) x0 = room.clip.x0;
if (x1 > room.clip.x1) x1 = room.clip.x1;
if (y0 < room.clip.y0) y0 = room.clip.y0;
if (y1 > room.clip.y1) y1 = room.clip.y1;
if (x0 >= x1 || y0 >= y1) return false;
RoomDesc &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) {
RoomDesc &room = rooms[roomIndex];
matrixPush();
matrixTranslateAbs(vec3i(room.x, 0, room.z));
for (int32 i = 0; i < room.pCount; i++) {
const Room::Portal &portal = room.portals[i];
if (checkPortal(roomIndex, portal)) {
getVisibleRooms(portal.roomIndex);
}
}
matrixPop();
}
void drawRooms() {
rooms[camera.room].clip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
visRoomsCount = 0;
visRooms[visRoomsCount++] = camera.room;
getVisibleRooms(camera.room);
while (visRoomsCount--) {
drawRoom(visRooms[visRoomsCount]);
}
}
#endif

View File

@ -16,6 +16,7 @@
#include "common.h"
#include "level.h"
#include "camera.h"
#ifdef _WIN32
uint8* LEVEL1_PHD;
@ -37,19 +38,14 @@ int32 fpsCounter = 0;
void update(int32 frames) {
for (int32 i = 0; i < frames; i++) {
updateCamera();
camera.update();
}
}
void render() {
clear();
drawRoom(6);
flush();
drawRoom(0);
drawModel(0, 75162, 3072 - 512, 5000 + 1024);
flush();
drawRooms();
drawNumber(fps, WIDTH, 16);
}
@ -57,7 +53,7 @@ void render() {
#ifdef _WIN32
HDC hDC;
void VBlankIntrWait() {
void blit() {
#ifdef USE_MODE_5
for (int i = 0; i < WIDTH * HEIGHT; i++) {
uint16 c = ((uint16*)fb)[i];
@ -146,16 +142,22 @@ int main(void) {
MSG msg;
int startTime = GetTickCount();
int lastTime = -15;
do {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
update(1);
int time = GetTickCount() - startTime;
update((time - lastTime) / 16);
lastTime = time;
render();
VBlankIntrWait();
blit();
}
} while (msg.message != WM_QUIT);

View File

@ -21,10 +21,6 @@ extern uint8 lightmap[256 * 32];
extern const uint8* tiles[15];
extern const Texture* textures;
extern Rect clip;
extern int32 camSinY;
extern int32 camCosY;
uint32 gVerticesCount = 0;
EWRAM_DATA Vertex gVertices[MAX_VERTICES];
@ -35,6 +31,238 @@ Face* gFacesSorted[MAX_FACES];
const uint8* curTile;
uint16 mipMask;
Rect clip;
const int16 sin_table[] = { // 1025
0x0000, 0x0019, 0x0032, 0x004B, 0x0065, 0x007E, 0x0097, 0x00B0,
0x00C9, 0x00E2, 0x00FB, 0x0114, 0x012E, 0x0147, 0x0160, 0x0179,
0x0192, 0x01AB, 0x01C4, 0x01DD, 0x01F7, 0x0210, 0x0229, 0x0242,
0x025B, 0x0274, 0x028D, 0x02A6, 0x02C0, 0x02D9, 0x02F2, 0x030B,
0x0324, 0x033D, 0x0356, 0x036F, 0x0388, 0x03A1, 0x03BB, 0x03D4,
0x03ED, 0x0406, 0x041F, 0x0438, 0x0451, 0x046A, 0x0483, 0x049C,
0x04B5, 0x04CE, 0x04E7, 0x0500, 0x051A, 0x0533, 0x054C, 0x0565,
0x057E, 0x0597, 0x05B0, 0x05C9, 0x05E2, 0x05FB, 0x0614, 0x062D,
0x0646, 0x065F, 0x0678, 0x0691, 0x06AA, 0x06C3, 0x06DC, 0x06F5,
0x070E, 0x0727, 0x0740, 0x0759, 0x0772, 0x078B, 0x07A4, 0x07BD,
0x07D6, 0x07EF, 0x0807, 0x0820, 0x0839, 0x0852, 0x086B, 0x0884,
0x089D, 0x08B6, 0x08CF, 0x08E8, 0x0901, 0x0919, 0x0932, 0x094B,
0x0964, 0x097D, 0x0996, 0x09AF, 0x09C7, 0x09E0, 0x09F9, 0x0A12,
0x0A2B, 0x0A44, 0x0A5C, 0x0A75, 0x0A8E, 0x0AA7, 0x0AC0, 0x0AD8,
0x0AF1, 0x0B0A, 0x0B23, 0x0B3B, 0x0B54, 0x0B6D, 0x0B85, 0x0B9E,
0x0BB7, 0x0BD0, 0x0BE8, 0x0C01, 0x0C1A, 0x0C32, 0x0C4B, 0x0C64,
0x0C7C, 0x0C95, 0x0CAE, 0x0CC6, 0x0CDF, 0x0CF8, 0x0D10, 0x0D29,
0x0D41, 0x0D5A, 0x0D72, 0x0D8B, 0x0DA4, 0x0DBC, 0x0DD5, 0x0DED,
0x0E06, 0x0E1E, 0x0E37, 0x0E4F, 0x0E68, 0x0E80, 0x0E99, 0x0EB1,
0x0ECA, 0x0EE2, 0x0EFB, 0x0F13, 0x0F2B, 0x0F44, 0x0F5C, 0x0F75,
0x0F8D, 0x0FA5, 0x0FBE, 0x0FD6, 0x0FEE, 0x1007, 0x101F, 0x1037,
0x1050, 0x1068, 0x1080, 0x1099, 0x10B1, 0x10C9, 0x10E1, 0x10FA,
0x1112, 0x112A, 0x1142, 0x115A, 0x1173, 0x118B, 0x11A3, 0x11BB,
0x11D3, 0x11EB, 0x1204, 0x121C, 0x1234, 0x124C, 0x1264, 0x127C,
0x1294, 0x12AC, 0x12C4, 0x12DC, 0x12F4, 0x130C, 0x1324, 0x133C,
0x1354, 0x136C, 0x1384, 0x139C, 0x13B4, 0x13CC, 0x13E4, 0x13FB,
0x1413, 0x142B, 0x1443, 0x145B, 0x1473, 0x148B, 0x14A2, 0x14BA,
0x14D2, 0x14EA, 0x1501, 0x1519, 0x1531, 0x1549, 0x1560, 0x1578,
0x1590, 0x15A7, 0x15BF, 0x15D7, 0x15EE, 0x1606, 0x161D, 0x1635,
0x164C, 0x1664, 0x167C, 0x1693, 0x16AB, 0x16C2, 0x16DA, 0x16F1,
0x1709, 0x1720, 0x1737, 0x174F, 0x1766, 0x177E, 0x1795, 0x17AC,
0x17C4, 0x17DB, 0x17F2, 0x180A, 0x1821, 0x1838, 0x184F, 0x1867,
0x187E, 0x1895, 0x18AC, 0x18C3, 0x18DB, 0x18F2, 0x1909, 0x1920,
0x1937, 0x194E, 0x1965, 0x197C, 0x1993, 0x19AA, 0x19C1, 0x19D8,
0x19EF, 0x1A06, 0x1A1D, 0x1A34, 0x1A4B, 0x1A62, 0x1A79, 0x1A90,
0x1AA7, 0x1ABE, 0x1AD4, 0x1AEB, 0x1B02, 0x1B19, 0x1B30, 0x1B46,
0x1B5D, 0x1B74, 0x1B8A, 0x1BA1, 0x1BB8, 0x1BCE, 0x1BE5, 0x1BFC,
0x1C12, 0x1C29, 0x1C3F, 0x1C56, 0x1C6C, 0x1C83, 0x1C99, 0x1CB0,
0x1CC6, 0x1CDD, 0x1CF3, 0x1D0A, 0x1D20, 0x1D36, 0x1D4D, 0x1D63,
0x1D79, 0x1D90, 0x1DA6, 0x1DBC, 0x1DD3, 0x1DE9, 0x1DFF, 0x1E15,
0x1E2B, 0x1E42, 0x1E58, 0x1E6E, 0x1E84, 0x1E9A, 0x1EB0, 0x1EC6,
0x1EDC, 0x1EF2, 0x1F08, 0x1F1E, 0x1F34, 0x1F4A, 0x1F60, 0x1F76,
0x1F8C, 0x1FA2, 0x1FB7, 0x1FCD, 0x1FE3, 0x1FF9, 0x200F, 0x2024,
0x203A, 0x2050, 0x2065, 0x207B, 0x2091, 0x20A6, 0x20BC, 0x20D1,
0x20E7, 0x20FD, 0x2112, 0x2128, 0x213D, 0x2153, 0x2168, 0x217D,
0x2193, 0x21A8, 0x21BE, 0x21D3, 0x21E8, 0x21FE, 0x2213, 0x2228,
0x223D, 0x2253, 0x2268, 0x227D, 0x2292, 0x22A7, 0x22BC, 0x22D2,
0x22E7, 0x22FC, 0x2311, 0x2326, 0x233B, 0x2350, 0x2365, 0x237A,
0x238E, 0x23A3, 0x23B8, 0x23CD, 0x23E2, 0x23F7, 0x240B, 0x2420,
0x2435, 0x244A, 0x245E, 0x2473, 0x2488, 0x249C, 0x24B1, 0x24C5,
0x24DA, 0x24EF, 0x2503, 0x2518, 0x252C, 0x2541, 0x2555, 0x2569,
0x257E, 0x2592, 0x25A6, 0x25BB, 0x25CF, 0x25E3, 0x25F8, 0x260C,
0x2620, 0x2634, 0x2648, 0x265C, 0x2671, 0x2685, 0x2699, 0x26AD,
0x26C1, 0x26D5, 0x26E9, 0x26FD, 0x2711, 0x2724, 0x2738, 0x274C,
0x2760, 0x2774, 0x2788, 0x279B, 0x27AF, 0x27C3, 0x27D6, 0x27EA,
0x27FE, 0x2811, 0x2825, 0x2838, 0x284C, 0x2860, 0x2873, 0x2886,
0x289A, 0x28AD, 0x28C1, 0x28D4, 0x28E7, 0x28FB, 0x290E, 0x2921,
0x2935, 0x2948, 0x295B, 0x296E, 0x2981, 0x2994, 0x29A7, 0x29BB,
0x29CE, 0x29E1, 0x29F4, 0x2A07, 0x2A1A, 0x2A2C, 0x2A3F, 0x2A52,
0x2A65, 0x2A78, 0x2A8B, 0x2A9D, 0x2AB0, 0x2AC3, 0x2AD6, 0x2AE8,
0x2AFB, 0x2B0D, 0x2B20, 0x2B33, 0x2B45, 0x2B58, 0x2B6A, 0x2B7D,
0x2B8F, 0x2BA1, 0x2BB4, 0x2BC6, 0x2BD8, 0x2BEB, 0x2BFD, 0x2C0F,
0x2C21, 0x2C34, 0x2C46, 0x2C58, 0x2C6A, 0x2C7C, 0x2C8E, 0x2CA0,
0x2CB2, 0x2CC4, 0x2CD6, 0x2CE8, 0x2CFA, 0x2D0C, 0x2D1E, 0x2D2F,
0x2D41, 0x2D53, 0x2D65, 0x2D76, 0x2D88, 0x2D9A, 0x2DAB, 0x2DBD,
0x2DCF, 0x2DE0, 0x2DF2, 0x2E03, 0x2E15, 0x2E26, 0x2E37, 0x2E49,
0x2E5A, 0x2E6B, 0x2E7D, 0x2E8E, 0x2E9F, 0x2EB0, 0x2EC2, 0x2ED3,
0x2EE4, 0x2EF5, 0x2F06, 0x2F17, 0x2F28, 0x2F39, 0x2F4A, 0x2F5B,
0x2F6C, 0x2F7D, 0x2F8D, 0x2F9E, 0x2FAF, 0x2FC0, 0x2FD0, 0x2FE1,
0x2FF2, 0x3002, 0x3013, 0x3024, 0x3034, 0x3045, 0x3055, 0x3066,
0x3076, 0x3087, 0x3097, 0x30A7, 0x30B8, 0x30C8, 0x30D8, 0x30E8,
0x30F9, 0x3109, 0x3119, 0x3129, 0x3139, 0x3149, 0x3159, 0x3169,
0x3179, 0x3189, 0x3199, 0x31A9, 0x31B9, 0x31C8, 0x31D8, 0x31E8,
0x31F8, 0x3207, 0x3217, 0x3227, 0x3236, 0x3246, 0x3255, 0x3265,
0x3274, 0x3284, 0x3293, 0x32A3, 0x32B2, 0x32C1, 0x32D0, 0x32E0,
0x32EF, 0x32FE, 0x330D, 0x331D, 0x332C, 0x333B, 0x334A, 0x3359,
0x3368, 0x3377, 0x3386, 0x3395, 0x33A3, 0x33B2, 0x33C1, 0x33D0,
0x33DF, 0x33ED, 0x33FC, 0x340B, 0x3419, 0x3428, 0x3436, 0x3445,
0x3453, 0x3462, 0x3470, 0x347F, 0x348D, 0x349B, 0x34AA, 0x34B8,
0x34C6, 0x34D4, 0x34E2, 0x34F1, 0x34FF, 0x350D, 0x351B, 0x3529,
0x3537, 0x3545, 0x3553, 0x3561, 0x356E, 0x357C, 0x358A, 0x3598,
0x35A5, 0x35B3, 0x35C1, 0x35CE, 0x35DC, 0x35EA, 0x35F7, 0x3605,
0x3612, 0x3620, 0x362D, 0x363A, 0x3648, 0x3655, 0x3662, 0x366F,
0x367D, 0x368A, 0x3697, 0x36A4, 0x36B1, 0x36BE, 0x36CB, 0x36D8,
0x36E5, 0x36F2, 0x36FF, 0x370C, 0x3718, 0x3725, 0x3732, 0x373F,
0x374B, 0x3758, 0x3765, 0x3771, 0x377E, 0x378A, 0x3797, 0x37A3,
0x37B0, 0x37BC, 0x37C8, 0x37D5, 0x37E1, 0x37ED, 0x37F9, 0x3805,
0x3812, 0x381E, 0x382A, 0x3836, 0x3842, 0x384E, 0x385A, 0x3866,
0x3871, 0x387D, 0x3889, 0x3895, 0x38A1, 0x38AC, 0x38B8, 0x38C3,
0x38CF, 0x38DB, 0x38E6, 0x38F2, 0x38FD, 0x3909, 0x3914, 0x391F,
0x392B, 0x3936, 0x3941, 0x394C, 0x3958, 0x3963, 0x396E, 0x3979,
0x3984, 0x398F, 0x399A, 0x39A5, 0x39B0, 0x39BB, 0x39C5, 0x39D0,
0x39DB, 0x39E6, 0x39F0, 0x39FB, 0x3A06, 0x3A10, 0x3A1B, 0x3A25,
0x3A30, 0x3A3A, 0x3A45, 0x3A4F, 0x3A59, 0x3A64, 0x3A6E, 0x3A78,
0x3A82, 0x3A8D, 0x3A97, 0x3AA1, 0x3AAB, 0x3AB5, 0x3ABF, 0x3AC9,
0x3AD3, 0x3ADD, 0x3AE6, 0x3AF0, 0x3AFA, 0x3B04, 0x3B0E, 0x3B17,
0x3B21, 0x3B2A, 0x3B34, 0x3B3E, 0x3B47, 0x3B50, 0x3B5A, 0x3B63,
0x3B6D, 0x3B76, 0x3B7F, 0x3B88, 0x3B92, 0x3B9B, 0x3BA4, 0x3BAD,
0x3BB6, 0x3BBF, 0x3BC8, 0x3BD1, 0x3BDA, 0x3BE3, 0x3BEC, 0x3BF5,
0x3BFD, 0x3C06, 0x3C0F, 0x3C17, 0x3C20, 0x3C29, 0x3C31, 0x3C3A,
0x3C42, 0x3C4B, 0x3C53, 0x3C5B, 0x3C64, 0x3C6C, 0x3C74, 0x3C7D,
0x3C85, 0x3C8D, 0x3C95, 0x3C9D, 0x3CA5, 0x3CAD, 0x3CB5, 0x3CBD,
0x3CC5, 0x3CCD, 0x3CD5, 0x3CDD, 0x3CE4, 0x3CEC, 0x3CF4, 0x3CFB,
0x3D03, 0x3D0B, 0x3D12, 0x3D1A, 0x3D21, 0x3D28, 0x3D30, 0x3D37,
0x3D3F, 0x3D46, 0x3D4D, 0x3D54, 0x3D5B, 0x3D63, 0x3D6A, 0x3D71,
0x3D78, 0x3D7F, 0x3D86, 0x3D8D, 0x3D93, 0x3D9A, 0x3DA1, 0x3DA8,
0x3DAF, 0x3DB5, 0x3DBC, 0x3DC2, 0x3DC9, 0x3DD0, 0x3DD6, 0x3DDD,
0x3DE3, 0x3DE9, 0x3DF0, 0x3DF6, 0x3DFC, 0x3E03, 0x3E09, 0x3E0F,
0x3E15, 0x3E1B, 0x3E21, 0x3E27, 0x3E2D, 0x3E33, 0x3E39, 0x3E3F,
0x3E45, 0x3E4A, 0x3E50, 0x3E56, 0x3E5C, 0x3E61, 0x3E67, 0x3E6C,
0x3E72, 0x3E77, 0x3E7D, 0x3E82, 0x3E88, 0x3E8D, 0x3E92, 0x3E98,
0x3E9D, 0x3EA2, 0x3EA7, 0x3EAC, 0x3EB1, 0x3EB6, 0x3EBB, 0x3EC0,
0x3EC5, 0x3ECA, 0x3ECF, 0x3ED4, 0x3ED8, 0x3EDD, 0x3EE2, 0x3EE7,
0x3EEB, 0x3EF0, 0x3EF4, 0x3EF9, 0x3EFD, 0x3F02, 0x3F06, 0x3F0A,
0x3F0F, 0x3F13, 0x3F17, 0x3F1C, 0x3F20, 0x3F24, 0x3F28, 0x3F2C,
0x3F30, 0x3F34, 0x3F38, 0x3F3C, 0x3F40, 0x3F43, 0x3F47, 0x3F4B,
0x3F4F, 0x3F52, 0x3F56, 0x3F5A, 0x3F5D, 0x3F61, 0x3F64, 0x3F68,
0x3F6B, 0x3F6E, 0x3F72, 0x3F75, 0x3F78, 0x3F7B, 0x3F7F, 0x3F82,
0x3F85, 0x3F88, 0x3F8B, 0x3F8E, 0x3F91, 0x3F94, 0x3F97, 0x3F99,
0x3F9C, 0x3F9F, 0x3FA2, 0x3FA4, 0x3FA7, 0x3FAA, 0x3FAC, 0x3FAF,
0x3FB1, 0x3FB4, 0x3FB6, 0x3FB8, 0x3FBB, 0x3FBD, 0x3FBF, 0x3FC1,
0x3FC4, 0x3FC6, 0x3FC8, 0x3FCA, 0x3FCC, 0x3FCE, 0x3FD0, 0x3FD2,
0x3FD4, 0x3FD5, 0x3FD7, 0x3FD9, 0x3FDB, 0x3FDC, 0x3FDE, 0x3FE0,
0x3FE1, 0x3FE3, 0x3FE4, 0x3FE6, 0x3FE7, 0x3FE8, 0x3FEA, 0x3FEB,
0x3FEC, 0x3FED, 0x3FEF, 0x3FF0, 0x3FF1, 0x3FF2, 0x3FF3, 0x3FF4,
0x3FF5, 0x3FF6, 0x3FF7, 0x3FF7, 0x3FF8, 0x3FF9, 0x3FFA, 0x3FFA,
0x3FFB, 0x3FFC, 0x3FFC, 0x3FFD, 0x3FFD, 0x3FFE, 0x3FFE, 0x3FFE,
0x3FFF, 0x3FFF, 0x3FFF, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000
};
int32 phd_sin(int32 x)
{
x &= 0xFFFF;
bool neg = (x > 0x8000);
x &= 0x7FFF;
if (x >= 0x4000) {
x = 0x8000 - x;
}
x = sin_table[x >> 4];
return neg ? -x : x;
}
int32 phd_cos(int32 x)
{
return phd_sin(x + 0x4000);
}
Matrix matrixStack[MAX_MATRICES];
int32 matrixStackIndex = 0;
vec3i viewPos;
Matrix& matrixGet() {
return matrixStack[matrixStackIndex];
}
void matrixPush() {
#ifdef _WIN32
if (matrixStackIndex >= MAX_MATRICES - 1) {
DebugBreak();
return;
}
#endif
Matrix &a = matrixStack[matrixStackIndex++];
Matrix &b = matrixStack[matrixStackIndex];
memcpy(b, a, sizeof(Matrix));
}
void matrixPop() {
#ifdef _WIN32
if (matrixStackIndex <= 0) {
DebugBreak();
return;
}
#endif
matrixStackIndex--;
}
void matrixTranslate(const vec3i &offset) {
Matrix &m = matrixGet();
m[0].w += DP33(m[0], offset);
m[1].w += DP33(m[1], offset);
m[2].w += DP33(m[2], offset);
}
void matrixTranslateAbs(const vec3i &offset) {
vec3i d;
d.x = offset.x - viewPos.x;
d.y = offset.y - viewPos.y;
d.z = offset.z - viewPos.z;
Matrix &m = matrixGet();
m[0].w = DP33(m[0], d);
m[1].w = DP33(m[1], d);
m[2].w = DP33(m[2], d);
}
void matrixRotate(int16 rotX, int16 rotY, int16 rotZ) {}
void matrixSetView(const vec3i &pos, int16 rotX, int16 rotY) {
int32 sx = phd_sin(rotX);
int32 cx = phd_cos(rotX);
int32 sy = phd_sin(rotY);
int32 cy = phd_cos(rotY);
Matrix &m = matrixGet();
m[0].x = cy;
m[0].y = 0;
m[0].z = -sy;
m[0].w = pos.x;
m[1].x = (sx * sy) >> FIXED_SHIFT;
m[1].y = cx;
m[1].z = (sx * cy) >> FIXED_SHIFT;
m[1].w = pos.y;
m[2].x = (cx * sy) >> FIXED_SHIFT;
m[2].y = -sx;
m[2].z = (cx * cy) >> FIXED_SHIFT;
m[2].w = pos.z;
viewPos = pos;
}
int32 clamp(int32 x, int32 a, int32 b) {
return x < a ? a : (x > b ? b : x);
}
@ -65,67 +293,49 @@ INLINE void sortVertices(Vertex *&t, Vertex *&m, Vertex *&o, Vertex *&b) {
if (m->y > o->y) swap(m, o);
}
int32 classify(const Vertex* v) {
INLINE int32 classify(const Vertex* v) {
return (v->x < clip.x0 ? 1 : 0) |
(v->x > clip.x1 ? 2 : 0) |
(v->y < clip.y0 ? 4 : 0) |
(v->y > clip.y1 ? 8 : 0);
}
void transform(int32 vx, int32 vy, int32 vz, int32 vg, int32 x, int32 y, int32 z) {
void transform(const vec3s &v, int32 vg) {
#ifdef _WIN32
if (gVerticesCount >= MAX_VERTICES) {
DebugBreak();
return;
}
#endif
const Matrix &m = matrixStack[matrixStackIndex];
Vertex &res = gVertices[gVerticesCount++];
int32 px = vx + x;
int32 pz = vz + z;
int32 cz = px * camSinY + pz * camCosY;
cz >>= 16;
int32 cz = DP43(m[2], v);
// znear / zfar clip
if (cz < 32 || cz > MAX_DIST) {
if (cz < MIN_DIST || cz >= MAX_DIST) {
res.z = -1;
return;
}
int32 py = vy + y;
int32 cx = DP43(m[0], v);
int32 cy = DP43(m[1], v);
#if 0
int32 cx = (px * camCosY - pz * camSinY) >> 16;
int32 cy = py;
uint32 czInv = MyDiv(1 << 16, uint32(cz));
cx = cx * czInv;
cy = cy * czInv;
#else
int32 cx = px * camCosY - pz * camSinY;
int32 cy = py << 16;
cx = MyDiv(cx, cz);
cy = MyDiv(cy, cz);
#endif
cy = cy * FRAME_WIDTH / FRAME_HEIGHT;
cx = clamp(cx, -2 << 16, 2 << 16);
cy = clamp(cy, -2 << 16, 2 << 16);
res.x = ( ( (1 << 16) + cx ) * (FRAME_WIDTH / 2) ) >> 16;
res.y = ( ( (1 << 16) + cy ) * (FRAME_HEIGHT / 2) ) >> 16;
res.z = cz;
res.clip = classify(&res);
int32 fog = vg - ((cz * cz) >> 15);
int32 fog = (8191 - vg) - (SQR(cz >> FIXED_SHIFT) >> 15);
if (fog < 0) {
fog = 0;
}
cz >>= FOV_SHIFT;
cx = MyDiv(cx, cz) + (FRAME_WIDTH / 2);
cy = MyDiv(cy, cz) + (FRAME_HEIGHT / 2);
cz >>= (FIXED_SHIFT - FOV_SHIFT);
res.x = cx;
res.y = cy;
res.z = cz;
res.clip = classify(&res);
res.g = uint32(255 - (fog >> 5)) >> 3;
}
@ -830,6 +1040,9 @@ void faceAddQuad(uint16 flags, const Index* indices, int32 startVertex) {
if (v1->z < 0 || v2->z < 0 || v3->z < 0 || v4->z < 0)
return;
if (!(v1->g | v2->g | v3->g | v4->g))
return;
if (checkBackface(v1, v2, v3))
return;
@ -865,6 +1078,9 @@ void faceAddTriangle(uint16 flags, const Index* indices, int32 startVertex) {
if (v1->z < 0 || v2->z < 0 || v3->z < 0)
return;
if (!(v1->g | v2->g | v3->g))
return;
if (checkBackface(v1, v2, v3))
return;