From 09dd6703182ff9c30ce9a98e9ad245fc9bda7aa2 Mon Sep 17 00:00:00 2001 From: XProger Date: Sun, 31 Oct 2021 05:32:20 +0300 Subject: [PATCH] #368 #370 enemies navigation, LOD support for trap floor, Gamma adjust for GBA, armcpp and Big-Endian support for 3DO, turn off animation lerp for distant objects, hide enemy corpse after 10 secs, fix some issues with sorting polys --- src/platform/gba/OpenLara.vcxproj | 1 + src/platform/gba/camera.h | 701 ++++++++++---------- src/platform/gba/common.cpp | 178 ++++-- src/platform/gba/common.h | 916 ++++++++++++++++++--------- src/platform/gba/draw.h | 354 ++++++++--- src/platform/gba/enemy.h | 913 +++++++++++++++++++++++--- src/platform/gba/game.h | 124 ++-- src/platform/gba/inventory.h | 4 +- src/platform/gba/item.h | 243 +++---- src/platform/gba/lara.h | 246 ++++--- src/platform/gba/level.h | 564 ++--------------- src/platform/gba/main.cpp | 114 ++-- src/platform/gba/nav.h | 227 +++++++ src/platform/gba/object.h | 149 +++-- src/platform/gba/rasterizer_mode13.h | 108 ++-- src/platform/gba/rasterizer_mode4.h | 103 ++- src/platform/gba/render.cpp | 341 +++++----- src/platform/gba/room.h | 837 ++++++++++++++++++++++-- src/platform/gba/sound.h | 5 + 19 files changed, 3997 insertions(+), 2131 deletions(-) create mode 100644 src/platform/gba/nav.h diff --git a/src/platform/gba/OpenLara.vcxproj b/src/platform/gba/OpenLara.vcxproj index 9a3f0608..7282438d 100644 --- a/src/platform/gba/OpenLara.vcxproj +++ b/src/platform/gba/OpenLara.vcxproj @@ -21,6 +21,7 @@ + diff --git a/src/platform/gba/camera.h b/src/platform/gba/camera.h index 6811b88f..a2a0480d 100644 --- a/src/platform/gba/camera.h +++ b/src/platform/gba/camera.h @@ -12,490 +12,443 @@ #define CAMERA_ANGLE_COMBAT ANGLE(-10) #define CAMERA_ANGLE_MAX ANGLE(85) -enum CameraMode +void Camera::init(ItemObj* lara) { - CAMERA_MODE_FREE, - CAMERA_MODE_FOLLOW, - CAMERA_MODE_COMBAT, - CAMERA_MODE_LOOK, - CAMERA_MODE_FIXED, - CAMERA_MODE_OBJECT, - CAMERA_MODE_CUTSCENE, -}; - -struct Camera -{ - Location view; - Location target; - - int32 targetDist; - int16 targetAngleX; - int16 targetAngleY; + ASSERT(lara->extraL); - int16 angleX; - int16 angleY; + target.pos = lara->pos; + target.pos.y -= 1024; + target.room = lara->room; - AABB frustumBase; + view = target; + view.pos.z -= 100; - Item* laraItem; - Item* lastItem; - Item* lookAtItem; + targetDist = CAM_DIST_FOLLOW; + targetAngle = _vec3s(0, 0, 0); + angle = _vec3s(0, 0, 0); - int32 speed; - int32 timer; - int32 index; - int32 lastIndex; + laraItem = lara; + lastItem = NULL; + lookAtItem = NULL; - CameraMode mode; + speed = 1; + timer = 0; + index = -1; + lastIndex = -1; - bool modeSwitch; - bool lastFixed; - bool center; + mode = CAMERA_MODE_FOLLOW; - void init(Item* lara) - { - ASSERT(lara->extraL); + modeSwitch = false; + lastFixed = false; + center = false; +} - target.pos = lara->pos; - target.pos.y -= 1024; - target.room = lara->room; +Location Camera::getLocationForAngle(int32 angle, int32 distH, int32 distV) +{ + Location res; + res.pos.x = target.pos.x - (distH * phd_sin(angle) >> FIXED_SHIFT); + res.pos.y = target.pos.y + (distV); + res.pos.z = target.pos.z - (distH * phd_cos(angle) >> FIXED_SHIFT); + res.room = target.room; + return res; +} + +void Camera::clip(Location &loc) +{ + const Sector* sector = loc.room->getSector(loc.pos.x, loc.pos.z); + + int32 floor = sector->getFloor(loc.pos.x, loc.pos.y, loc.pos.z); + if (floor != WALL && loc.pos.y > floor - 128) { + loc.pos.y = floor - 128; + } - view = target; - view.pos.z -= 100; + int32 ceiling = sector->getCeiling(loc.pos.x, loc.pos.y, loc.pos.z); + if (ceiling != WALL && loc.pos.y < ceiling + 128) { + loc.pos.y = ceiling + 128; + } - angleX = 0; - angleY = 0; + // TODO clip walls? +} - targetAngleX = 0; - targetAngleY = 0; - targetDist = CAM_DIST_FOLLOW; +Location Camera::getBestLocation(bool clip) +{ + int32 distH = targetDist * phd_cos(targetAngle.x) >> FIXED_SHIFT; + int32 distV = targetDist * phd_sin(targetAngle.x) >> FIXED_SHIFT; - laraItem = lara; - lastItem = NULL; - lookAtItem = NULL; + Location best = getLocationForAngle(targetAngle.y, distH, distV); - speed = 1; - timer = 0; - index = -1; - lastIndex = -1; + if (trace(target, best, true)) + return best; - mode = CAMERA_MODE_FOLLOW; + if (clip && best.pos != target.pos) + return best; - modeSwitch = false; - lastFixed = false; - center = false; - } + int32 dist = fastLength(target.pos.x - best.pos.x, target.pos.z - best.pos.z); - void updateFree() - { - matrixSetView(view.pos, angleX, angleY); + if (dist > 768) + return best; - Matrix &m = matrixGet(); + int32 minDist = INT_MAX; - if (keys & IK_UP) angleX -= CAM_ROT_SPEED; - if (keys & IK_DOWN) angleX += CAM_ROT_SPEED; - if (keys & IK_LEFT) angleY -= CAM_ROT_SPEED; - if (keys & IK_RIGHT) angleY += CAM_ROT_SPEED; + for (int32 i = 0; i < 4; i++) + { + Location tmpDest = getLocationForAngle(i * ANGLE_90, distH, distV); + Location tmpView = view; - angleX = X_CLAMP(angleX, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX); + if (!trace(target, tmpDest, true) || !trace(tmpDest, tmpView, false)) + continue; - if (keys & IK_A) - { - 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; - } + dist = fastLength(view.pos.x - tmpDest.pos.x, view.pos.z - tmpDest.pos.z); - if (keys & IK_B) + if (dist < minDist) { - 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; + minDist = dist; + best = tmpDest; } - - view.room = view.room->getRoom(view.pos.x, view.pos.y, view.pos.z); } - Location getLocationForAngle(int32 angle, int32 distH, int32 distV) - { - Location res; - res.pos.x = target.pos.x - (distH * phd_sin(angle) >> FIXED_SHIFT); - res.pos.y = target.pos.y + (distV); - res.pos.z = target.pos.z - (distH * phd_cos(angle) >> FIXED_SHIFT); - res.room = target.room; - return res; - } + return best; +} - void clip(Location &loc) - { - const Sector* sector = loc.room->getSector(loc.pos.x, loc.pos.z); - - int32 floor = sector->getFloor(loc.pos.x, loc.pos.y, loc.pos.z); - if (floor != WALL && loc.pos.y > floor - 128) { - loc.pos.y = floor - 128; - } +void Camera::move(Location &to, int32 speed) +{ + clip(to); - int32 ceiling = sector->getCeiling(loc.pos.x, loc.pos.y, loc.pos.z); - if (ceiling != WALL && loc.pos.y < ceiling + 128) { - loc.pos.y = ceiling + 128; - } + vec3i d = to.pos - view.pos; - // TODO clip walls? + if (speed > 1) { + d /= speed; } - Location getBestLocation(bool clip) - { - int32 distH = targetDist * phd_cos(targetAngleX) >> FIXED_SHIFT; - int32 distV = targetDist * phd_sin(targetAngleX) >> FIXED_SHIFT; - - Location best = getLocationForAngle(targetAngleY, distH, distV); - - if (trace(target, best, true)) - return best; + view.pos += d; + view.room = to.room->getRoom(view.pos.x, view.pos.y, view.pos.z); +} - if (clip && best.pos != target.pos) - return best; - - int32 distQ = X_SQR(target.pos.x - best.pos.x) + X_SQR(target.pos.z - best.pos.z); - - if (distQ > X_SQR(768)) - return best; - - int32 minDistQ = INT_MAX; - - for (int32 i = 0; i < 4; i++) - { - Location tmpDest = getLocationForAngle(i * ANGLE_90, distH, distV); - Location tmpView = view; +void Camera::updateFree() +{ + matrixSetView(view.pos, angle.x, angle.y); - if (!trace(target, tmpDest, true) || !trace(tmpDest, tmpView, false)) - continue; + Matrix &m = matrixGet(); - distQ = X_SQR(view.pos.x - tmpDest.pos.x) + X_SQR(view.pos.z - tmpDest.pos.z); + if (keys & IK_UP) angle.x -= CAM_ROT_SPEED; + if (keys & IK_DOWN) angle.x += CAM_ROT_SPEED; + if (keys & IK_LEFT) angle.y -= CAM_ROT_SPEED; + if (keys & IK_RIGHT) angle.y += CAM_ROT_SPEED; - if (distQ < minDistQ) - { - minDistQ = distQ; - best = tmpDest; - } - } + angle.x = X_CLAMP(angle.x, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX); - return best; + if (keys & IK_A) + { + view.pos.x += m.e20 * CAM_SPEED >> 10; + view.pos.y += m.e21 * CAM_SPEED >> 10; + view.pos.z += m.e22 * CAM_SPEED >> 10; } - void move(Location &to, int32 speed) + if (keys & IK_B) { - clip(to); - - vec3i d = to.pos - view.pos; + view.pos.x -= m.e20 * CAM_SPEED >> 10; + view.pos.y -= m.e21 * CAM_SPEED >> 10; + view.pos.z -= m.e22 * CAM_SPEED >> 10; + } - if (speed > 1) { - d /= speed; - } + view.room = view.room->getRoom(view.pos.x, view.pos.y, view.pos.z); +} - view.pos += d; - view.room = to.room->getRoom(view.pos.x, view.pos.y, view.pos.z); +void Camera::updateFollow(ItemObj* item) +{ + if (targetAngle.x == 0) { + targetAngle.x = CAMERA_ANGLE_FOLLOW; } - void updateFollow(Item* item) - { - if (targetAngleX == 0) { - targetAngleX = CAMERA_ANGLE_FOLLOW; - } + targetAngle.x = X_CLAMP(targetAngle.x + item->angle.x, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX); + targetAngle.y += item->angle.y; - targetAngleX = X_CLAMP(targetAngleX + item->angle.x, -CAMERA_ANGLE_MAX, CAMERA_ANGLE_MAX); - targetAngleY += item->angle.y; + Location best = getBestLocation(false); - Location best = getBestLocation(false); + move(best, lastFixed ? speed : 12); +} - move(best, lastFixed ? speed : 12); - } - - void updateCombat(Item* item) - { - ASSERT(item->type == ITEM_LARA); +void Camera::updateCombat(ItemObj* item) +{ + ASSERT(item->type == ITEM_LARA); - targetAngleX = item->angle.x + CAMERA_ANGLE_COMBAT; - targetAngleY = item->angle.y; + targetAngle.x = item->angle.x + CAMERA_ANGLE_COMBAT; + targetAngle.y = item->angle.y; - if (item->extraL->armR.target || item->extraL->armL.target) - { - int32 aX = item->extraL->armR.angleAim.x + item->extraL->armL.angleAim.x; - int32 aY = item->extraL->armR.angleAim.y + item->extraL->armL.angleAim.y; + if (item->extraL->armR.target || item->extraL->armL.target) + { + int32 aX = item->extraL->armR.angleAim.x + item->extraL->armL.angleAim.x; + int32 aY = item->extraL->armR.angleAim.y + item->extraL->armL.angleAim.y; - if (item->extraL->armR.target && item->extraL->armL.target) { - targetAngleX += aX >> 1; - targetAngleY += aY >> 1; - } else { - targetAngleX += aX; - targetAngleY += aY; - } + if (item->extraL->armR.target && item->extraL->armL.target) { + targetAngle.x += aX >> 1; + targetAngle.y += aY >> 1; } else { - targetAngleX += item->extraL->head.angle.x + item->extraL->torso.angle.x; - targetAngleY += item->extraL->head.angle.y + item->extraL->torso.angle.y; + targetAngle.x += aX; + targetAngle.y += aY; } + } else { + targetAngle.x += item->extraL->head.angle.x + item->extraL->torso.angle.x; + targetAngle.y += item->extraL->head.angle.y + item->extraL->torso.angle.y; + } - targetDist = CAM_DIST_COMBAT; + targetDist = CAM_DIST_COMBAT; - Location best = getBestLocation(true); + Location best = getBestLocation(true); - move(best, speed); - } + move(best, speed); +} - void updateLook(Item* item) - { - ASSERT(item->type == ITEM_LARA); +void Camera::updateLook(ItemObj* item) +{ + ASSERT(item->type == ITEM_LARA); - targetAngleX = item->extraL->head.angle.x + item->extraL->torso.angle.x + item->angle.x; - targetAngleY = item->extraL->head.angle.y + item->extraL->torso.angle.y + item->angle.y; - targetDist = lookAtItem ? CAM_DIST_FOLLOW : CAM_DIST_LOOK; + targetAngle.x = item->extraL->head.angle.x + item->extraL->torso.angle.x + item->angle.x; + targetAngle.y = item->extraL->head.angle.y + item->extraL->torso.angle.y + item->angle.y; + targetDist = lookAtItem ? CAM_DIST_FOLLOW : CAM_DIST_LOOK; - Location best = getBestLocation(true); + Location best = getBestLocation(true); - move(best, speed); - } + move(best, speed); +} - void updateFixed() - { - const FixedCamera* cam = cameras + index; +void Camera::updateFixed() +{ + const FixedCamera* cam = level.cameras + index; - Location best; - best.pos = cam->pos; - best.room = rooms + cam->roomIndex; + Location best; + best.pos = cam->pos; + best.room = rooms + cam->roomIndex; - lastFixed = true; - move(best, 1); + lastFixed = true; + move(best, 1); - if (timer != 0) - { - timer--; - if (timer == 0) { - timer = -1; - } + if (timer != 0) + { + timer--; + if (timer == 0) { + timer = -1; } } +} - void lookAt(int32 offset) - { - int32 dx = lookAtItem->pos.x - laraItem->pos.x; - int32 dz = lookAtItem->pos.z - laraItem->pos.z; +void Camera::lookAt(int32 offset) +{ + int32 dx = lookAtItem->pos.x - laraItem->pos.x; + int32 dz = lookAtItem->pos.z - laraItem->pos.z; - int16 ay = int16(phd_atan(dz, dx) - laraItem->angle.y) >> 1; + int16 ay = int16(phd_atan(dz, dx) - laraItem->angle.y) >> 1; - if (abs(ay) >= LARA_LOOK_ANGLE_Y) - { - lookAtItem = NULL; - return; - } + if (abs(ay) >= LARA_LOOK_ANGLE_Y) + { + lookAtItem = NULL; + return; + } - const Bounds& box = lookAtItem->getBoundingBox(true); + const AABBs& box = lookAtItem->getBoundingBox(true); - offset -= lookAtItem->pos.y + ((box.minY + box.maxY) >> 1); + offset -= lookAtItem->pos.y + ((box.minY + box.maxY) >> 1); - int16 ax = int16(phd_atan(phd_sqrt(X_SQR(dx) + X_SQR(dz)), offset)) >> 1; + int16 ax = int16(phd_atan(phd_sqrt(X_SQR(dx) + X_SQR(dz)), offset)) >> 1; - if (ax < LARA_LOOK_ANGLE_MIN || ax > LARA_LOOK_ANGLE_MAX) - { - lookAtItem = NULL; - return; - } + if (ax < LARA_LOOK_ANGLE_MIN || ax > LARA_LOOK_ANGLE_MAX) + { + lookAtItem = NULL; + return; + } - laraItem->extraL->head.angle.x = angleLerp(laraItem->extraL->head.angle.x, ax, LARA_LOOK_TURN_SPEED); - laraItem->extraL->head.angle.y = angleLerp(laraItem->extraL->head.angle.y, ay, LARA_LOOK_TURN_SPEED); + laraItem->extraL->head.angle.x = angleLerp(laraItem->extraL->head.angle.x, ax, LARA_LOOK_TURN_SPEED); + laraItem->extraL->head.angle.y = angleLerp(laraItem->extraL->head.angle.y, ay, LARA_LOOK_TURN_SPEED); - laraItem->extraL->torso.angle = laraItem->extraL->head.angle; + laraItem->extraL->torso.angle = laraItem->extraL->head.angle; - lookAtItem->flags.animated = true; // use as once flag - mode = CAMERA_MODE_LOOK; - } + lookAtItem->flags.animated = true; // use as once flag + mode = CAMERA_MODE_LOOK; +} - void update() +void Camera::update() +{ + if (keys & IK_START) { - if (keys & IK_START) + if (!modeSwitch) { - if (!modeSwitch) - { - modeSwitch = true; - if (mode != CAMERA_MODE_FREE) { - mode = CAMERA_MODE_FREE; - } else { - mode = CAMERA_MODE_FOLLOW; - } + modeSwitch = true; + if (mode != CAMERA_MODE_FREE) { + mode = CAMERA_MODE_FREE; + } else { + mode = CAMERA_MODE_FOLLOW; } - } else { - modeSwitch = false; } + } else { + modeSwitch = false; + } - if (mode == CAMERA_MODE_FREE) - { - updateFree(); - prepareFrustum(); - matrixSetView(view.pos, angleX, angleY); - return; - } + if (mode == CAMERA_MODE_FREE) + { + updateFree(); + prepareFrustum(); + matrixSetView(view.pos, angle.x, angle.y); + return; + } - bool isFixed = false; - Item* item = laraItem; + bool isFixed = false; + ItemObj* item = laraItem; - if (lookAtItem && (mode == CAMERA_MODE_FIXED || mode == CAMERA_MODE_OBJECT)) - { - isFixed = true; - item = lookAtItem; - } - - ASSERT(item); + if (lookAtItem && (mode == CAMERA_MODE_FIXED || mode == CAMERA_MODE_OBJECT)) + { + isFixed = true; + item = lookAtItem; + } - target.room = item->room; - target.pos.x = item->pos.x; - target.pos.z = item->pos.z; + ASSERT(item); - const Bounds &box = item->getBoundingBox(true); + target.room = item->room; + target.pos.x = item->pos.x; + target.pos.z = item->pos.z; - int32 y = item->pos.y; - if (isFixed) { - y += (box.minY + box.maxY) >> 1; - } else { - y += box.maxY + ((box.minY - box.maxY) * 3 >> 2); - } + const AABBs &box = item->getBoundingBox(true); - if (!isFixed && lookAtItem) { - lookAt(y); - } + int32 y = item->pos.y; + if (isFixed) { + y += (box.minY + box.maxY) >> 1; + } else { + y += box.maxY + ((box.minY - box.maxY) * 3 >> 2); + } - if (mode == CAMERA_MODE_LOOK || mode == CAMERA_MODE_COMBAT) - { - y -= 256; + if (!isFixed && lookAtItem) { + lookAt(y); + } - if (lastFixed) { - target.pos.y = 0; - speed = 1; - } else { - target.pos.y += (y - target.pos.y) >> 2; - speed = (mode == CAMERA_MODE_LOOK) ? 4 : 8; - } + if (mode == CAMERA_MODE_LOOK || mode == CAMERA_MODE_COMBAT) + { + y -= 256; + if (lastFixed) { + target.pos.y = 0; + speed = 1; } else { - - if (center) - { - int32 offset = (box.minZ + box.maxZ) >> 1; - target.pos.x += (phd_sin(item->angle.y) * offset) >> FIXED_SHIFT; - target.pos.z += (phd_cos(item->angle.y) * offset) >> FIXED_SHIFT; - } - - lastFixed ^= isFixed; - - if (lastFixed) { - target.pos.y = y; - speed = 1; - } else { - target.pos.y += (y - target.pos.y) >> 2; - } + target.pos.y += (y - target.pos.y) >> 2; + speed = (mode == CAMERA_MODE_LOOK) ? 4 : 8; } - switch (mode) + } else { + + if (center) { - case CAMERA_MODE_FOLLOW : updateFollow(item); break; - case CAMERA_MODE_COMBAT : updateCombat(item); break; - case CAMERA_MODE_LOOK : updateLook(item); break; - default : updateFixed(); + int32 offset = (box.minZ + box.maxZ) >> 1; + target.pos.x += (phd_sin(item->angle.y) * offset) >> FIXED_SHIFT; + target.pos.z += (phd_cos(item->angle.y) * offset) >> FIXED_SHIFT; } - lastFixed = isFixed; - lastIndex = index; + lastFixed = (int32(lastFixed) ^ int32(isFixed)) != 0; // armcpp 3DO compiler (lastFixed ^= isFixed) - if (mode != CAMERA_MODE_OBJECT || timer == -1) - { - mode = CAMERA_MODE_FOLLOW; - index = -1; - lastItem = lookAtItem; - lookAtItem = NULL; - targetAngleX = 0; - targetAngleY = 0; - targetDist = CAM_DIST_FOLLOW; - center = false; + if (lastFixed) { + target.pos.y = y; + speed = 1; + } else { + target.pos.y += (y - target.pos.y) >> 2; } + } - vec3i dir = target.pos - view.pos; - anglesFromVector(dir.x, dir.y, dir.z, angleX, angleY); + switch (mode) + { + case CAMERA_MODE_FOLLOW : updateFollow(item); break; + case CAMERA_MODE_COMBAT : updateCombat(item); break; + case CAMERA_MODE_LOOK : updateLook(item); break; + default : updateFixed(); + } - prepareFrustum(); + lastFixed = isFixed; + lastIndex = index; - matrixSetView(view.pos, angleX, angleY); + if (mode != CAMERA_MODE_OBJECT || timer == -1) + { + mode = CAMERA_MODE_FOLLOW; + index = -1; + lastItem = lookAtItem; + lookAtItem = NULL; + targetAngle.x = 0; + targetAngle.y = 0; + targetDist = CAM_DIST_FOLLOW; + center = false; } - void prepareFrustum() - { - matrixSetIdentity(); - matrixRotateYXZ(angleX, angleY, 0); - - 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); - } + vec3i dir = target.pos - view.pos; + anglesFromVector(dir.x, dir.y, dir.z, angle.x, angle.y); - 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; - } + prepareFrustum(); - void updateFrustum(int32 offsetX, int32 offsetY, int32 offsetZ) + matrixSetView(view.pos, angle.x, angle.y); +} + +void Camera::prepareFrustum() +{ + matrixSetIdentity(); + matrixRotateYXZ(angle.x, angle.y, angle.z); + + static const vec3i v[5] = { + // near plane + { 0, 0, 0 }, + // far plane + { -FRUSTUM_FAR_X, -FRUSTUM_FAR_Y, FRUSTUM_FAR_Z }, + { FRUSTUM_FAR_X, -FRUSTUM_FAR_Y, FRUSTUM_FAR_Z }, + { -FRUSTUM_FAR_X, FRUSTUM_FAR_Y, FRUSTUM_FAR_Z }, + { 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++) { - 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; + int32 x = DP43(m.e00, m.e01, m.e02, m.e03, v[i].x, v[i].y, v[i].z) >> FIXED_SHIFT; + int32 y = DP43(m.e10, m.e11, m.e12, m.e13, v[i].x, v[i].y, v[i].z) >> FIXED_SHIFT; + int32 z = DP43(m.e20, m.e21, m.e22, m.e23, v[i].x, v[i].y, v[i].z) >> 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); } - void toCombat() - { - if (mode == CAMERA_MODE_FREE) - return; + 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; +} - if (mode == CAMERA_MODE_CUTSCENE) - return; +void Camera::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; +} + +void Camera::toCombat() +{ + if (mode == CAMERA_MODE_FREE) + return; - if (mode == CAMERA_MODE_LOOK) - return; + if (mode == CAMERA_MODE_CUTSCENE) + return; - mode = CAMERA_MODE_COMBAT; - } -}; + if (mode == CAMERA_MODE_LOOK) + return; -Camera* gCamera; -Camera viewCameras[MAX_PLAYERS]; + mode = CAMERA_MODE_COMBAT; +} #endif diff --git a/src/platform/gba/common.cpp b/src/platform/gba/common.cpp index e810bce7..df98ad59 100644 --- a/src/platform/gba/common.cpp +++ b/src/platform/gba/common.cpp @@ -1,11 +1,12 @@ #include "common.h" uint32 keys; -AABB frustumAABB; -Rect viewport; -vec3i cameraViewPos; +AABBi frustumAABB; +RectMinMax viewport; +vec3i cameraViewPos; +vec3i cameraViewOffset; Matrix matrixStack[MAX_MATRICES]; -int32 matrixStackIndex = 0; +int32 matrixStackIndex = 0; const FloorData* gLastFloorData; FloorData gLastFloorSlant; @@ -46,7 +47,8 @@ int32 rand_draw() return X_RAND(rand_seed_draw); } -EWRAM_DATA uint16 divTable[DIV_TABLE_SIZE] = { // must be at EWRAM start +#ifdef USE_DIV_TABLE +EWRAM_DATA divTableInt divTable[DIV_TABLE_SIZE] = { // must be at EWRAM start 0xFFFF, 0xFFFF, 0x8000, 0x5555, 0x4000, 0x3333, 0x2AAA, 0x2492, 0x2000, 0x1C71, 0x1999, 0x1745, 0x1555, 0x13B1, 0x1249, 0x1111, 0x1000, 0x0F0F, 0x0E38, 0x0D79, 0x0CCC, 0x0C30, 0x0BA2, 0x0B21, @@ -176,6 +178,7 @@ EWRAM_DATA uint16 divTable[DIV_TABLE_SIZE] = { // must be at EWRAM start 0x0041, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040 }; +#endif const int16 sinTable[1025] = { // ROM 0x0000, 0x0019, 0x0032, 0x004B, 0x0065, 0x007E, 0x0097, 0x00B0, @@ -651,19 +654,19 @@ void anglesFromVector(int32 x, int32 y, int32 z, int16 &angleX, int16 &angleY) } } -Bounds boxRotate(const Bounds &box, int16 angle) +AABBs boxRotate(const AABBs &box, int16 angle) { if (angle == ANGLE_90) { - return Bounds( box.minZ, box.maxZ, box.minY, box.maxY, -box.maxX, -box.minX ); + return AABBs( box.minZ, box.maxZ, box.minY, box.maxY, -box.maxX, -box.minX ); } else if (angle == -ANGLE_90) { - return Bounds( -box.maxZ, -box.minZ, box.minY, box.maxY, box.minX, box.maxX ); + return AABBs( -box.maxZ, -box.minZ, box.minY, box.maxY, box.minX, box.maxX ); } else if (angle == ANGLE_180) { - return Bounds( -box.maxX, -box.minX, box.minY, box.maxY, -box.maxZ, -box.minZ ); + return AABBs( -box.maxX, -box.minX, box.minY, box.maxY, -box.maxZ, -box.minZ ); } return box; } -void boxTranslate(Bounds &box, const vec3i &offset) +void boxTranslate(AABBs &box, const vec3i &offset) { box.minX += offset.x; box.maxX += offset.x; @@ -673,21 +676,21 @@ void boxTranslate(Bounds &box, const vec3i &offset) box.maxZ += offset.z; } -bool boxIntersect(const Bounds &a, const Bounds &b) +bool boxIntersect(const AABBs &a, const AABBs &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 Bounds &a, const vec3i &p) +bool boxContains(const AABBs &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 Bounds &a, const Bounds &b) +vec3i boxPushOut(const AABBs &a, const AABBs &b) { int32 ax = b.maxX - a.minX; int32 bx = a.maxX - b.minX; @@ -703,6 +706,7 @@ vec3i boxPushOut(const Bounds &a, const Bounds &b) } /* +#ifdef USE_DIV_TABLE void initDivTable() { uint16 divTable[DIV_TABLE_SIZE]; @@ -723,6 +727,7 @@ void initDivTable() } printf("};\n"); } +#endif */ X_INLINE int16 lerpAngle(int16 a, int16 b, int32 t) @@ -738,12 +743,30 @@ X_INLINE int16 lerpAngle(int16 a, int16 b, int32 t) return a + ((d * t) >> FIXED_SHIFT); } +X_INLINE int16 lerpAngleSlow(int16 a, int16 b, int32 mul, int32 div) +{ + int32 d = b - a; + + if (d > 0x8000) { + d -= 0x10000; + } else if (d < -0x8000) { + d += 0x10000; + } + + return a + d * mul / div; +} + void matrixTranslate(int32 x, int32 y, int32 z) { Matrix &m = matrixGet(); - m[0][3] += DP33c(m[0], x, y, z); - m[1][3] += DP33c(m[1], x, y, z); - m[2][3] += DP33c(m[2], x, y, z); + + int32 dx = DP33(m.e00, m.e01, m.e02, x, y, z); + int32 dy = DP33(m.e10, m.e11, m.e12, x, y, z); + int32 dz = DP33(m.e20, m.e21, m.e22, x, y, z); + + m.e03 += dx; + m.e13 += dy; + m.e23 += dz; } void matrixTranslateAbs(int32 x, int32 y, int32 z) @@ -752,10 +775,14 @@ void matrixTranslateAbs(int32 x, int32 y, int32 z) y -= cameraViewPos.y; z -= cameraViewPos.z; + cameraViewOffset.x = x; + cameraViewOffset.y = y; + cameraViewOffset.z = z; + Matrix &m = matrixGet(); - m[0][3] = DP33c(m[0], x, y, z); - m[1][3] = DP33c(m[1], x, y, z); - m[2][3] = DP33c(m[2], x, y, z); + m.e03 = DP33(m.e00, m.e01, m.e02, x, y, z); + m.e13 = DP33(m.e10, m.e11, m.e12, x, y, z); + m.e23 = DP33(m.e20, m.e21, m.e22, x, y, z); } void matrixRotateX(int32 angle) @@ -765,9 +792,9 @@ void matrixRotateX(int32 angle) int32 s = phd_sin(angle); int32 c = phd_cos(angle); - X_ROTXY(m[0][2], m[0][1], s, c); - X_ROTXY(m[1][2], m[1][1], s, c); - X_ROTXY(m[2][2], m[2][1], s, c); + X_ROTXY(m.e02, m.e01, s, c); + X_ROTXY(m.e12, m.e11, s, c); + X_ROTXY(m.e22, m.e21, s, c); } void matrixRotateY(int32 angle) @@ -777,9 +804,9 @@ void matrixRotateY(int32 angle) int32 s = phd_sin(angle); int32 c = phd_cos(angle); - X_ROTXY(m[0][0], m[0][2], s, c); - X_ROTXY(m[1][0], m[1][2], s, c); - X_ROTXY(m[2][0], m[2][2], s, c); + X_ROTXY(m.e00, m.e02, s, c); + X_ROTXY(m.e10, m.e12, s, c); + X_ROTXY(m.e20, m.e22, s, c); } void matrixRotateZ(int32 angle) @@ -789,9 +816,9 @@ void matrixRotateZ(int32 angle) int32 s = phd_sin(angle); int32 c = phd_cos(angle); - X_ROTXY(m[0][1], m[0][0], s, c); - X_ROTXY(m[1][1], m[1][0], s, c); - X_ROTXY(m[2][1], m[2][0], s, c); + X_ROTXY(m.e01, m.e00, s, c); + X_ROTXY(m.e11, m.e10, s, c); + X_ROTXY(m.e21, m.e20, s, c); } void matrixRotateYXZ(int32 angleX, int32 angleY, int32 angleZ) @@ -868,12 +895,19 @@ void matrixFrameLerp(const vec3s &pos, const uint32* anglesA, const uint32* angl matrixTranslate(pos.x, pos.y, pos.z); -#if 0 // TODO oh, damn Gimbal Lock! - if (aX != bX) aX = lerpAngle(aX, bX, t); - if (aY != bY) aY = lerpAngle(aY, bY, t); - if (aZ != bZ) aZ = lerpAngle(aZ, bZ, t); +#if defined(ANIM_LERP_ANGLE) // TODO oh, damn Gimbal Lock! + #if 0 + int32 t = (delta << FIXED_SHIFT) / rate; + if (aX != bX) aX = lerpAngle(aX, bX, t); + if (aY != bY) aY = lerpAngle(aY, bY, t); + if (aZ != bZ) aZ = lerpAngle(aZ, bZ, t); + #else + if (aX != bX) aX = lerpAngleSlow(aX, bX, delta, rate); + if (aY != bY) aY = lerpAngleSlow(aY, bY, delta, rate); + if (aZ != bZ) aZ = lerpAngleSlow(aZ, bZ, delta, rate); + #endif matrixRotateYXZ(aX, aY, aZ); -#else +#elif defined(ANIM_LERP_MATRIX) matrixPush(); matrixRotateYXZ(bX, bY, bZ); Matrix &m = matrixGet(); @@ -882,6 +916,8 @@ void matrixFrameLerp(const vec3s &pos, const uint32* anglesA, const uint32* angl matrixRotateYXZ(aX, aY, aZ); matrixLerp(m, delta, rate); +#else + #error animation lerp type is undefined #endif } @@ -889,20 +925,20 @@ void matrixSetIdentity() { Matrix &m = matrixGet(); - m[0][0] = 0x4000; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; + m.e00 = 0x4000; + m.e01 = 0; + m.e02 = 0; + m.e03 = 0; - m[1][0] = 0; - m[1][1] = 0x4000; - m[1][2] = 0; - m[1][3] = 0; + m.e10 = 0; + m.e11 = 0x4000; + m.e12 = 0; + m.e13 = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 0x4000; - m[2][3] = 0; + m.e20 = 0; + m.e21 = 0; + m.e22 = 0x4000; + m.e23 = 0; } void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY) @@ -914,31 +950,32 @@ void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY) Matrix &m = matrixGet(); - m[0][0] = cy; - m[0][1] = 0; - m[0][2] = -sy; - m[0][3] = 0; + m.e00 = cy; + m.e01 = 0; + m.e02 = -sy; + m.e03 = 0; - m[1][0] = (sx * sy) >> FIXED_SHIFT; - m[1][1] = cx; - m[1][2] = (sx * cy) >> FIXED_SHIFT; - m[1][3] = 0; + m.e10 = (sx * sy) >> FIXED_SHIFT; + m.e11 = cx; + m.e12 = (sx * cy) >> FIXED_SHIFT; + m.e13 = 0; - m[2][0] = (cx * sy) >> FIXED_SHIFT; - m[2][1] = -sx; - m[2][2] = (cx * cy) >> FIXED_SHIFT; - m[2][3] = 0; + m.e20 = (cx * sy) >> FIXED_SHIFT; + m.e21 = -sx; + m.e22 = (cx * cy) >> FIXED_SHIFT; + m.e23 = 0; cameraViewPos = pos; + cameraViewOffset = _vec3i(0, 0, 0); } void CollisionInfo::setSide(CollisionInfo::SideType st, int32 floor, int32 ceiling) { SlantType slantType; - if (gLastFloorSlant.slantX == 0 && gLastFloorSlant.slantZ == 0) { + if (FD_SLANT_X(gLastFloorSlant) == 0 && FD_SLANT_Z(gLastFloorSlant) == 0) { slantType = SLANT_NONE; - } else if (abs(gLastFloorSlant.slantX) < 3 && abs(gLastFloorSlant.slantZ) < 3) { + } else if (abs(FD_SLANT_X(gLastFloorSlant)) < 3 && abs(FD_SLANT_Z(gLastFloorSlant)) < 3) { slantType = SLANT_LOW; } else { slantType = SLANT_HIGH; @@ -958,4 +995,27 @@ void CollisionInfo::setSide(CollisionInfo::SideType st, int32 floor, int32 ceili s->slantType = slantType; s->floor = floor; s->ceiling = ceiling; +} + +void setGamma(int32 value) +{ + if (value == 0) { + osSetPalette(level.palette); + return; + } + + uint16 pal[256]; + for (int32 i = 0; i < 256; i++) + { + int32 r = 31 & (level.palette[i]); + int32 g = 31 & (level.palette[i] >> 5); + int32 b = 31 & (level.palette[i] >> 10); + + r = X_MIN(31, r + (((r * r >> 2) - r) * value >> 8)); + g = X_MIN(31, g + (((g * g >> 2) - g) * value >> 8)); + b = X_MIN(31, b + (((b * b >> 2) - b) * value >> 8)); + + pal[i] = r | (g << 5) | (b << 10); + } + osSetPalette(pal); } \ No newline at end of file diff --git a/src/platform/gba/common.h b/src/platform/gba/common.h index 1b0847ca..594e5ee5 100644 --- a/src/platform/gba/common.h +++ b/src/platform/gba/common.h @@ -8,54 +8,86 @@ // #define PROFILE_SOUNDTIME #endif -#define IWRAM_MATRIX_LERP - #if defined(_WIN32) #define MODE4 //#define MODE13 -#elif defined(__GBA__) - #define MODE4 - //#define USE_9BIT_SOUND -#elif defined(__TNS__) - #define MODE13 -#elif defined(__DOS__) - #define MODE13 -#else - #error unsupported platform -#endif - -#define NO_STATIC_MESH_PLANTS + #define USE_DIV_TABLE -#if defined(_WIN32) #define _CRT_SECURE_NO_WARNINGS #include #elif defined(__GBA__) + #define MODE4 + #define USE_DIV_TABLE + #define ROM_READ + //#define USE_9BIT_SOUND + #include #elif defined(__TNS__) + #define MODE13 + #define USE_DIV_TABLE + #include #elif defined(__DOS__) + #define MODE13 + #define USE_DIV_TABLE + #include #include #include #include #include +#elif defined(__3DO__) + #define MODEHW + #define USE_DIV_TABLE // TODO_3DO remove + #define CPU_BIG_ENDIAN + + #define MAX_RAM (800 * 1024) + #define MAX_VRAM (640 * 1024) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + //#include +#else + #error unsupported platform +#endif + +#if !defined(__3DO__) + #include #endif -#include -#include +#include "stdio.h" // TODO_3DO armcpp bug? + #include #include #include -//#define DEBUG_FACES - -#if defined(MODE4) - #define MODE_PAL +#if defined(MODEHW) + #ifdef __3DO__ + #define FRAME_WIDTH 320 + #define FRAME_HEIGHT 240 + #endif +#elif defined(MODE4) #define VRAM_WIDTH 120 // in shorts (240 bytes) #define FRAME_WIDTH 240 #define FRAME_HEIGHT 160 #elif defined(MODE13) - #define MODE_PAL #define VRAM_WIDTH 160 // in shorts (320 bytes) #define FRAME_WIDTH 320 @@ -66,12 +98,56 @@ #endif #endif +// Optimization flags ========================================================= +#ifdef __GBA__ +// hide dead enemies after a while to reduce the number of polygons on the screen + #define HIDE_CORPSES (30*10) // 10 sec +// replace trap flor geometry by two flat quads in the static state + #define LOD_TRAP_FLOOR +// disable some plants environment to reduce overdraw of transparent geometry + #define NO_STATIC_MESH_PLANTS +// disable anim interpolation if item projected box is less than + #define LOD_ANIM (FRAME_HEIGHT / 4) +// use IWRAM_CODE section that faster for matrix interpolation (GBA only) + #define IWRAM_MATRIX_LERP +// the maximum of active enemies + #define MAX_ENEMIES 3 +#endif + #define MAX_ENEMIES 3 +#ifdef __3DO__ +// hide dead enemies after a while to reduce the number of polygons on the screen + #define HIDE_CORPSES (30*10) // 10 sec +// replace trap flor geometry by two flat quads in the static state + #define LOD_TRAP_FLOOR +// disable matrix interpolation + //#define NO_ANIM_LERP + #define ANIM_LERP_ANGLE +// the maximum navigation iterations per simulation tick + #define NAV_STEPS 1 +// the maximum of active enemies + #define MAX_ENEMIES 3 +#endif + +#ifndef NAV_STEPS + #define NAV_STEPS 5 +#endif + +#ifndef MAX_ENEMIES + #define MAX_ENEMIES 8 +#endif + +#ifndef ANIM_LERP_ANGLE + #define ANIM_LERP_MATRIX +#endif + +// ============================================================================ + #if defined(_MSC_VER) #define X_INLINE inline #define X_NOINLINE __declspec(noinline) #define ALIGN4 __declspec(align(4)) #define ALIGN16 __declspec(align(16)) -#elif defined(__WATCOMC__) +#elif defined(__WATCOMC__) || defined(__3DO__) #define X_INLINE inline #define X_NOINLINE __declspec(noinline) #define ALIGN4 @@ -83,17 +159,30 @@ #define ALIGN16 __attribute__((aligned(16))) #endif +#if defined(__3DO__) +typedef size_t intptr_t; +typedef uint32 divTableInt; +#else typedef signed char int8; typedef signed short int16; typedef signed int int32; -typedef signed long long int64; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; -typedef unsigned long long uint64; +typedef uint16 divTableInt; +#endif + typedef int16 Index; -#ifndef __GBA__ +#if defined(__3DO__) +X_INLINE int32 abs(int32 x) { + return (x >= 0) ? x : -x; +} +#endif + +#ifdef __GBA__ + #define ARM_CODE __attribute__((target("arm"))) +#else #define ARM_CODE #define THUMB_CODE #define IWRAM_DATA @@ -103,8 +192,6 @@ typedef int16 Index; #define EWRAM_CODE #define dmaCopy(src,dst,size) memcpy(dst,src,size) -#else - #define ARM_CODE __attribute__((target("arm"))) #endif #if defined(_WIN32) @@ -123,9 +210,6 @@ typedef int16 Index; #if defined(_WIN32) extern uint16 fb[VRAM_WIDTH * FRAME_HEIGHT]; - #ifdef MODE_PAL - extern uint16 MEM_PAL_BG[256]; - #endif #elif defined(__GBA__) extern uint32 fb; #elif defined(__TNS__) @@ -135,8 +219,10 @@ typedef int16 Index; #endif // system -int32 osGetSystemTimeMS(); -void osJoyVibrate(int32 index, int32 L, int32 R); +extern int32 osGetSystemTimeMS(); +extern void osJoyVibrate(int32 index, int32 L, int32 R); +extern void osSetPalette(const uint16* palette); +extern void osLoadLevel(const char* name); #ifdef PROFILING #define PROFILE_FRAME\ @@ -158,27 +244,37 @@ void osJoyVibrate(int32 index, int32 L, int32 R); PROFILE_FRAME, CNT_MAX, PROFILE_STAGES, - PROFILE_SOUND, + PROFILE_SOUND }; #elif defined(PROFILE_SOUNDTIME) enum ProfileCounterId { PROFILE_SOUND, CNT_MAX, PROFILE_FRAME, - PROFILE_STAGES, + PROFILE_STAGES }; #else enum ProfileCounterId { PROFILE_STAGES, CNT_MAX, PROFILE_FRAME, - PROFILE_SOUND, + PROFILE_SOUND }; #endif extern uint32 gCounters[CNT_MAX]; + + #if defined(__3DO__) // should be first, armcpp bug (#elif) + extern int32 g_timer; + + #define PROFILE_START() {\ + g_timer = osGetSystemTimeMS();\ + } - #if defined(_WIN32) + #define PROFILE_STOP(value) {\ + value += (osGetSystemTimeMS() - g_timer);\ + } + #elif defined(_WIN32) extern LARGE_INTEGER g_timer; extern LARGE_INTEGER g_current; @@ -206,10 +302,9 @@ void osJoyVibrate(int32 index, int32 L, int32 R); value += REG_TM2CNT_L;\ REG_TM2CNT_H = 0;\ } - #else - #define PROFILE_START() - #define PROFILE_STOP(value) + #define PROFILE_START() aaa + #define PROFILE_STOP(value) bbb #endif struct ProfileCounter @@ -237,11 +332,9 @@ void osJoyVibrate(int32 index, int32 L, int32 R); #endif #ifdef __TNS__ - void paletteSet(unsigned short* palette); + void osSetPalette(uint16* palette); #endif -#define STATIC_MESH_GATE 10 - #define STATIC_MESH_FLAG_NO_COLLISION 1 #define STATIC_MESH_FLAG_VISIBLE 2 @@ -285,12 +378,19 @@ extern int32 fps; #define SND_DECODE(x) ((x) - 128) #define SND_MIN -128 #define SND_MAX 127 +#elif defined(__3DO__) + #define SND_SAMPLES 1024 + #define SND_OUTPUT_FREQ 11025 + #define SND_SAMPLE_FREQ 11025 + #define SND_ENCODE(x) ((x) + 128) + #define SND_DECODE(x) ((x) - 128) + #define SND_MIN -128 + #define SND_MAX 127 #endif #define MAX_UPDATE_FRAMES 10 #define MAX_PLAYERS 1 // TODO 2 players for non-potato platforms -#define MAX_ENEMIES 8 #define MAX_SPHERES 32 #define MAX_MATRICES 8 #define MAX_ROOMS 139 // LEVEL7A @@ -300,12 +400,14 @@ extern int32 fps; #define MAX_STATIC_MESHES 50 #define MAX_CAMERAS 16 #define MAX_BOXES 1024 -#define MAX_VERTICES (4*1024) +#define MAX_VERTICES (5*1024) #define MAX_TEXTURES 1536 -#define MAX_FACES 1024 +#define MAX_FACES 2048 #define MAX_ROOM_LIST 16 +#define MAX_PORTALS 16 #define MAX_CAUSTICS 32 #define MAX_RAND_TABLE 32 +#define MAX_DYN_SECTORS (1024*3) #define FOV_SHIFT 3 #define FOG_SHIFT 1 @@ -321,6 +423,7 @@ extern int32 fps; #define FACE_TRIANGLE 0x8000 #define FACE_COLORED 0x4000 #define FACE_CLIPPED 0x2000 +#define FACE_CCW FACE_CLIPPED // 3DO only #define FACE_FLAT 0x1000 #define FACE_SPRITE 0x0800 #define FACE_SHADOW (FACE_COLORED | FACE_FLAT | FACE_SPRITE) @@ -339,6 +442,9 @@ extern int32 fps; #define ANGLE_90 (0x10000 / 4) // != 90 * ANGLE_1 !!! #define ANGLE_180 -(0x10000 / 2) // INT16_MIN #define ANGLE(x) ((x) * ANGLE_1) +#define ANGLE_SHIFT_45 13 +#define ANGLE_SHIFT_90 14 +#define ANGLE_SHIFT_180 15 #define X_CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x))) #define X_MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -355,17 +461,17 @@ extern int32 fps; y = _y;\ } -#define DP43c(a,bx,by,bz) ((a).x * bx + (a).y * by + (a).z * bz + (a).w) -#define DP33c(a,bx,by,bz) ((a).x * bx + (a).y * by + (a).z * bz) - -#define DP43(a,b) DP43c(a, b.x, b.y, b.z) -#define DP33(a,b) DP33c(a, b.x, b.y, b.z) - +#define DP43(ax,ay,az,aw,bx,by,bz) (ax * bx + ay * by + az * bz + aw) +#define DP33(ax,ay,az,bx,by,bz) (ax * bx + ay * by + az * bz) +#ifdef USE_DIV_TABLE #define DIV_TABLE_SIZE 1024 #define FixedInvS(x) ((x < 0) ? -divTable[abs(x)] : divTable[x]) #define FixedInvU(x) divTable[x] +extern divTableInt divTable[DIV_TABLE_SIZE]; +#endif + #define OT_SHIFT 4 #define OT_SIZE ((VIEW_MAX_F >> (FIXED_SHIFT + OT_SHIFT)) + 1) @@ -378,13 +484,14 @@ enum InputKey { IK_LEFT = (1 << 3), IK_A = (1 << 4), IK_B = (1 << 5), - IK_L = (1 << 6), - IK_R = (1 << 7), - IK_START = (1 << 8), - IK_SELECT = (1 << 9), + IK_C = (1 << 6), + IK_L = (1 << 7), + IK_R = (1 << 8), + IK_START = (1 << 9), + IK_SELECT = (1 << 10) }; -// action keys (Item::input) +// action keys (ItemObj::input) enum { IN_LEFT = (1 << 1), IN_RIGHT = (1 << 2), @@ -394,34 +501,46 @@ enum { IN_WALK = (1 << 6), IN_ACTION = (1 << 7), IN_WEAPON = (1 << 8), - IN_LOOK = (1 << 9), + IN_LOOK = (1 << 9) }; struct vec3s { int16 x, y, z; - vec3s() {} - X_INLINE vec3s(int16 x, int16 y, int16 z) : x(x), y(y), z(z) {} + X_INLINE static vec3s create(int16 x, int16 y, int16 z) { + vec3s r; + r.x = x; + r.y = y; + r.z = z; + return r; + } - X_INLINE vec3s operator + (const vec3s &v) const { return vec3s(x + v.x, y + v.y, z + v.z); } - X_INLINE vec3s operator - (const vec3s &v) const { return vec3s(x - v.x, y - v.y, z - v.z); } + X_INLINE vec3s operator + (const vec3s &v) const { return create(x + v.x, y + v.y, z + v.z); } + X_INLINE vec3s operator - (const vec3s &v) const { return create(x - v.x, y - v.y, z - v.z); } X_INLINE bool operator == (const vec3s &v) { return x == v.x && y == v.y && z == v.z; } X_INLINE bool operator != (const vec3s &v) { return x != v.x || y != v.y || z != v.z; } X_INLINE vec3s& operator += (const vec3s &v) { x += v.x; y += v.y; z += v.z; return *this; } X_INLINE vec3s& operator -= (const vec3s &v) { x -= v.x; y -= v.y; z -= v.z; return *this; } }; +#define _vec3s(x,y,z) vec3s::create(x, y, z) + + struct vec3i { int32 x, y, z; - vec3i() {}; - X_INLINE vec3i(int32 s) : x(s), y(s), z(s) {} - X_INLINE vec3i(int32 x, int32 y, int32 z) : x(x), y(y), z(z) {} - X_INLINE vec3i(vec3s &v) : x(v.x), y(v.y), z(v.z) {} - X_INLINE vec3i operator + (const vec3i &v) const { return vec3i(x + v.x, y + v.y, z + v.z); } - X_INLINE vec3i operator - (const vec3i &v) const { return vec3i(x - v.x, y - v.y, z - v.z); } - X_INLINE vec3i operator * (int32 s) const { return vec3i(x * s, y * s, z * s); } - X_INLINE vec3i operator / (int32 s) const { return vec3i(x / s, y / s, z / s); } + X_INLINE static vec3i create(int32 x, int32 y, int32 z) { + vec3i r; + r.x = x; + r.y = y; + r.z = z; + return r; + } + + X_INLINE vec3i operator + (const vec3i &v) const { return create(x + v.x, y + v.y, z + v.z); } + X_INLINE vec3i operator - (const vec3i &v) const { return create(x - v.x, y - v.y, z - v.z); } + X_INLINE vec3i operator * (int32 s) const { return create(x * s, y * s, z * s); } + X_INLINE vec3i operator / (int32 s) const { return create(x / s, y / s, z / s); } X_INLINE bool operator == (const vec3i &v) const { return x == v.x && y == v.y && z == v.z; } X_INLINE bool operator != (const vec3i &v) const { return x != v.x || y != v.y || z != v.z; } X_INLINE vec3i& operator += (const vec3i &v) { x += v.x; y += v.y; z += v.z; return *this; } @@ -430,6 +549,8 @@ struct vec3i { X_INLINE vec3i& operator /= (int32 s) { x /= s; y /= s; z /= s; return *this; } }; +#define _vec3i(x,y,z) vec3i::create(x, y, z) + struct vec4i { int32 x, y, z, w; @@ -439,11 +560,31 @@ struct vec4i { } }; -typedef vec4i Matrix[3]; +#ifdef __3DO__ + #define F16_SHIFT (16 - FIXED_SHIFT) // for fix14<->fix16 conversion + #define DOT_SHIFT (FIXED_SHIFT + FIXED_SHIFT - 16 - F16_SHIFT) +#endif + +struct Matrix +{ +#ifdef __3DO__ + int32 e00, e10, e20; + int32 e01, e11, e21; + int32 e02, e12, e22; + int32 e03, e13, e23; +#else + int32 e00, e01, e02, e03; + int32 e10, e11, e12, e13; + int32 e20, e21, e22, e23; +#endif +}; struct Quad { Index indices[4]; uint16 flags; +#ifdef __3DO__ + uint16 _unused; +#endif }; struct Triangle { @@ -451,40 +592,35 @@ struct Triangle { uint16 flags; }; -struct Rect { +struct RectMinMax { int32 x0; int32 y0; int32 x1; int32 y1; - Rect() {} - Rect(int32 x0, int32 y0, int32 x1, int32 y1) : x0(x0), y0(y0), x1(x1), y1(y1) {} -}; - -struct Vertex { // 8 - int16 x, y, z; - uint8 g, clip; + RectMinMax() {} + RectMinMax(int32 x0, int32 y0, int32 x1, int32 y1) : x0(x0), y0(y0), x1(x1), y1(y1) {} }; -union UV { - struct { uint16 v, u; }; - uint32 uv; -}; - -struct VertexUV { - Vertex v; - UV t; - VertexUV* prev; - VertexUV* next; +union TexCoord +{ + struct { uint16 v, u; } uv; + uint32 t; }; -struct Face { // 12 - Face* next; +#ifdef __3DO__ +typedef CCB Face; +#else +struct Face +{ + Face* next; uint16 flags; - int16 indices[4]; + int16 indices[4]; }; +#endif -struct Bounds { +struct AABBs +{ int16 minX; int16 maxX; int16 minY; @@ -492,16 +628,17 @@ struct Bounds { int16 minZ; int16 maxZ; - X_INLINE Bounds() {} - X_INLINE Bounds(int16 minX, int16 maxX, int16 minY, int16 maxY, int16 minZ, int16 maxZ) : + X_INLINE AABBs() {} + X_INLINE AABBs(int16 minX, int16 maxX, int16 minY, int16 maxY, int16 minZ, int16 maxZ) : minX(minX), maxX(maxX), minY(minY), maxY(maxY), minZ(minZ), maxZ(maxZ) {} X_INLINE vec3i getCenter() const { - return vec3i((maxX + minX) >> 1, (maxY + minY) >> 1, (maxZ + minZ) >> 1); + return _vec3i((maxX + minX) >> 1, (maxY + minY) >> 1, (maxZ + minZ) >> 1); } }; -struct AABB { +struct AABBi +{ int32 minX; int32 maxX; int32 minY; @@ -510,31 +647,51 @@ struct AABB { int32 maxZ; }; -struct Sphere { +struct Sphere +{ vec3i center; int32 radius; }; struct Room; -struct RoomVertex { +struct RoomVertex +{ int8 x, y, z; uint8 g; }; -struct RoomSprite { +struct RoomSprite +{ vec3s pos; uint8 g; uint8 index; }; -struct Portal { +struct MeshVertex +{ +#ifdef __3DO__ + int16 y, x, _unused, z; +#else + int16 x, y, z; +#endif +}; + +struct Portal +{ +#ifdef __3DO__ + uint32 roomIndex; + uint32 normalMask; + vec3i v[4]; +#else uint16 roomIndex; vec3s n; vec3s v[4]; +#endif }; -struct Sector { +struct Sector +{ uint16 floorIndex; uint16 boxIndex; uint8 roomBelow; @@ -557,14 +714,17 @@ struct Light uint8 intensity; }; +#define STATIC_MESH_ID(flags) ((flags) & 0x3F) +#define STATIC_MESH_ROT(flags) ((((flags) >> 6) - 2) * ANGLE_90) + struct RoomMesh { vec3s pos; uint8 intensity; - uint8 id:6, rot:2; + uint8 flags; }; -struct Item; +struct ItemObj; struct RoomData { @@ -578,6 +738,8 @@ struct RoomData const RoomMesh* meshes; }; +#define ROOM_FLAG_WATER(x) ((x) & 1) + struct RoomInfo { int16 x; @@ -600,12 +762,7 @@ struct RoomInfo uint8 xSectors; uint8 zSectors; uint8 alternateRoom; - union { - uint8 value; - struct { - uint8 water:1, :7; - }; - } flags; + uint8 flags; RoomData data; }; @@ -613,27 +770,31 @@ struct RoomInfo struct CollisionInfo; struct Room { - Item* firstItem; + ItemObj* firstItem; const RoomInfo* info; const Sector* sectors; // == info->sectors (const) by default (see roomModify) RoomData data; - Rect clip; + RectMinMax clip; uint8 _reserved; bool visible; void modify(); void reset(); - void add(Item* item); - void remove(Item* item); + void add(ItemObj* item); + void remove(ItemObj* item); const Sector* getSector(int32 x, int32 z) const; const Sector* getWaterSector(int32 x, int32 z) const; Room* getRoom(int32 x, int32 y, int32 z); bool collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height); +#ifdef __3DO__ + bool checkPortal(const Portal* portal, vec3i* points); +#else bool checkPortal(const Portal* portal); +#endif Room** addVisibleRoom(Room** list); Room** addNearRoom(Room** list, int32 x, int32 y, int32 z); Room** getNearRooms(const vec3i &pos, int32 radius, int32 height); @@ -646,10 +807,10 @@ enum NodeFlag { NODE_FLAG_PUSH = (1 << 1), NODE_FLAG_ROTX = (1 << 2), NODE_FLAG_ROTY = (1 << 3), - NODE_FLAG_ROTZ = (1 << 4), + NODE_FLAG_ROTZ = (1 << 4) }; -struct Node { +struct ModelNode { uint16 flags; vec3s pos; }; @@ -668,6 +829,11 @@ struct Mesh { vec3s center; int16 radius; uint16 flags; + int16 vCount; + int16 rCount; + int16 tCount; + int16 crCount; + int16 ctCount; // data... }; @@ -675,8 +841,8 @@ struct StaticMesh { uint16 id; uint16 meshIndex; uint16 flags; - Bounds vbox; - Bounds cbox; + AABBs vbox; + AABBs cbox; }; struct SoundInfo @@ -684,9 +850,8 @@ struct SoundInfo uint16 index; uint16 volume; uint16 chance; - union { - struct { uint16 mode:2, count:4, unused:6, camera:1, pitch:1, gain:1, :1; }; - uint16 value; + struct { + uint16 mode:2, count:4, unused:6, camera:1, pitch:1, gain:1, :1; } flags; }; @@ -721,25 +886,42 @@ struct AnimRange { }; struct AnimFrame { - Bounds box; + AABBs box; vec3s pos; uint16 angles[1]; }; -struct Texture { +struct Texture +{ +#ifdef __3DO__ + uint8* data; + uint8* plut; + uint32 pre0; + uint32 pre1; + uint8 wShift; + uint8 hShift; + uint16 flip; +#else uint16 attribute; - uint16 tile:14, :2; + uint16 tile; uint32 uv0; uint32 uv1; uint32 uv2; uint32 uv3; +#endif }; -struct Sprite { +struct Sprite +{ +#ifdef __3DO__ + uint32 texture; + int32 l, t, r, b; +#else uint16 tile; uint8 u, v; uint8 w, h; int16 l, t, r, b; +#endif }; struct SpriteSeq { @@ -752,23 +934,25 @@ struct SpriteSeq { struct FixedCamera { vec3i pos; int16 roomIndex; - union { - uint16 value; - struct { - uint16 timer:8, once:1, speed:5, :2; - }; + struct { + uint16 timer:8, once:1, speed:5, :2; } flags; }; -struct ItemInfo -{ +struct ItemObjFlags { + uint16 save:1, gravity:1, active:1, status:2, collision:1, injured:1, animated:1, once:1, mask:5, reverse:1, shadow:1; // TODO +}; + +struct ItemObjInfo { uint8 type; uint8 roomIndex; vec3s pos; uint16 intensity; - struct { - uint16 value:14, angle:2; - } flags; + + union { + ItemObjFlags flags; + uint16 value; + } params; }; #define ITEM_FLAGS_MASK_ALL 0x1F @@ -778,7 +962,7 @@ struct ItemInfo #define ITEM_FLAGS_STATUS_INACTIVE 2 #define ITEM_FLAGS_STATUS_INVISIBLE 3 -#define FILE_ITEM_SIZE (sizeof(ItemInfo) - 2) +#define FILE_ITEM_SIZE (sizeof(ItemObjInfo) - 2) struct CollisionInfo; struct Lara; @@ -838,7 +1022,7 @@ struct Lara; E( BLOCK_4 ) \ E( MOVING_BLOCK ) \ E( TRAP_CEILING ) \ - E( UNUSED_3 ) \ + E( TRAP_FLOOR_LOD ) \ E( SWITCH ) \ E( SWITCH_WATER ) \ E( DOOR_1 ) \ @@ -851,7 +1035,7 @@ struct Lara; E( DOOR_8 ) \ E( TRAP_DOOR_1 ) \ E( TRAP_DOOR_2 ) \ - E( UNUSED_4 ) \ + E( TRAP_DOOR_LOD ) \ E( BRIDGE_FLAT ) \ E( BRIDGE_TILT_1 ) \ E( BRIDGE_TILT_2 ) \ @@ -986,27 +1170,106 @@ enum ItemType { #undef DECL_ENUM -struct Camera; - struct Location { Room* room; vec3i pos; }; -struct Navigation +enum CameraMode { + CAMERA_MODE_FREE, + CAMERA_MODE_FOLLOW, + CAMERA_MODE_COMBAT, + CAMERA_MODE_LOOK, + CAMERA_MODE_FIXED, + CAMERA_MODE_OBJECT, + CAMERA_MODE_CUTSCENE +}; + +struct Camera { + Location view; + Location target; + + int32 targetDist; + vec3s targetAngle; + + vec3s angle; + + AABBi frustumBase; + + ItemObj* laraItem; + ItemObj* lastItem; + ItemObj* lookAtItem; + + int32 speed; + int32 timer; + int32 index; + int32 lastIndex; + + CameraMode mode; + + bool modeSwitch; + bool lastFixed; + bool center; + + void init(ItemObj* lara); + Location getLocationForAngle(int32 angle, int32 distH, int32 distV); + void clip(Location &loc); + Location getBestLocation(bool clip); + void move(Location &to, int32 speed); + void updateFree(); + void updateFollow(ItemObj* item); + void updateCombat(ItemObj* item); + void updateLook(ItemObj* item); + void updateFixed(); + void lookAt(int32 offset); + void update(); + void prepareFrustum(); + void updateFrustum(int32 offsetX, int32 offsetY, int32 offsetZ); + void toCombat(); +}; + +enum ZoneType +{ + ZONE_GROUND_1, + ZONE_GROUND_2, + ZONE_FLY, + ZONE_MAX +}; + +struct Nav { struct Cell { - int16 zone; - int16 weight; - int16 end; - int16 next; + uint16 boxIndex; + uint16 weight; + uint16 end; + uint16 next; }; - Cell* cells[MAX_BOXES]; + Cell cells[MAX_BOXES]; + uint32 cellsCount; + + uint32 zoneType; + uint32 weight; + + uint32 endBox; + uint32 nextBox; + uint32 headBox; + uint32 tailBox; + int32 stepHeight; + int32 dropHeight; + int32 vSpeed; + uint32 mask; + + vec3i pos; + + void init(uint32 boxIndex); + void search(uint16 zone, const uint16* zones); + vec3i getWaypoint(uint32 boxIndex, const vec3i &from); }; -enum WeaponState { +enum WeaponState +{ WEAPON_STATE_FREE, WEAPON_STATE_BUSY, WEAPON_STATE_DRAW, @@ -1014,7 +1277,8 @@ enum WeaponState { WEAPON_STATE_READY }; -enum Weapon { +enum Weapon +{ WEAPON_PISTOLS, WEAPON_MAGNUMS, WEAPON_UZIS, @@ -1033,7 +1297,8 @@ enum Weapon { WEAPON_MAX }; -struct WeaponParams { +struct WeaponParams +{ ItemType modelType; ItemType animType; uint16 damage; @@ -1052,13 +1317,15 @@ struct WeaponParams { int16 armMaxY; }; -enum LaraArm { +enum LaraArm +{ LARA_ARM_R, LARA_ARM_L, - LARA_ARM_MAX, + LARA_ARM_MAX }; -enum { +enum LaraJoint +{ JOINT_HIPS = 0, JOINT_LEG_L1, JOINT_LEG_L2, @@ -1077,7 +1344,8 @@ enum { JOINT_MAX }; -struct ExtraInfoLara { +struct ExtraInfoLara +{ int16 swimTimer; uint8 weaponState; uint8 vSpeedHack; @@ -1099,7 +1367,8 @@ struct ExtraInfoLara { vec3s angle; } torso; - struct Arm { + struct Arm + { vec3s angle; vec3s angleAim; @@ -1113,7 +1382,7 @@ struct ExtraInfoLara { int16 intensity; } flash; - Item* target; + ItemObj* target; bool aim; bool useBasis; @@ -1122,40 +1391,50 @@ struct ExtraInfoLara { Arm armR; Arm armL; - Camera* camera; + Camera camera; uint16 meshes[JOINT_MAX]; - uint16 ammo[WEAPON_MAX]; + uint16 ammo[WEAPON_MAX]; // TODO make global - Navigation nav; + Nav nav; + + bool dozy; }; extern ExtraInfoLara playersExtra[MAX_PLAYERS]; struct Enemy; -struct ExtraInfoEnemy { +enum EnemyMood +{ + MOOD_SLEEP, + MOOD_STALK, + MOOD_ATTACK, + MOOD_ESCAPE +}; + +struct ExtraInfoEnemy +{ int16 rotHead; int16 rotNeck; + int16 maxTurn; + int16 _reserved; + Enemy* enemy; - Navigation nav; + Nav nav; }; -struct Item { +struct ItemObj +{ Room* room; vec3i pos; vec3s angle; - - union { - struct { - uint16 save:1, gravity:1, active:1, status:2, collision:1, dozy:1, animated:1, once:1, mask:5, reverse:1, shadow:1; // TODO - }; - uint16 value; - } flags; + + ItemObjFlags flags; int16 vSpeed; int16 hSpeed; @@ -1172,17 +1451,21 @@ struct Item { uint8 goalState; uint8 waterState; - int16 headOffset; // enemies only - int16 aggression; + uint16 headOffset; // enemies only + uint16 aggression; // enemies only int16 health; union { int16 timer; int16 oxygen; // Lara only - int16 radius; // enemies only + int16 radius; // enemies only TODO }; - uint16 input; // Lara only + union { + uint16 input; // Lara only + uint16 mood; // enemies only + int16 corpseTimer; // enemies only + }; int16 turnSpeed; uint8 type; @@ -1198,13 +1481,13 @@ struct Item { ExtraInfoEnemy* extraE; }; - Item* nextItem; - Item* nextActive; + ItemObj* nextItem; + ItemObj* nextActive; - static Item* sFirstActive; - static Item* sFirstFree; + static ItemObj* sFirstActive; + static ItemObj* sFirstFree; - static Item* add(ItemType type, Room* room, const vec3i &pos, int32 angleY); + static ItemObj* add(ItemType type, Room* room, const vec3i &pos, int32 angleY); void remove(); void fxBubbles(Room *fxRoom, int32 fxJoint, const vec3i &fxOffset); @@ -1215,7 +1498,7 @@ struct Item { int32 getFrames(const AnimFrame* &frameA, const AnimFrame* &frameB, int32 &animFrameRate) const; const AnimFrame* getFrame() const; - const Bounds& getBoundingBox(bool lerp) const; + const AABBs& getBoundingBox(bool lerp) const; void move(); const Anim* animSet(int32 newAnimIndex, bool resetState, int32 frameOffset = 0); const Anim* animChange(const Anim* anim); @@ -1224,7 +1507,7 @@ struct Item { void animProcess(bool movement = true); bool animIsEnd(int32 offset) const; void animHit(int32 dirX, int32 dirZ, int32 hitTimer); - bool moveTo(const vec3i &point, Item* item, bool lerp); + bool moveTo(const vec3i &point, ItemObj* item, bool lerp); void updateRoom(int32 offset = 0); @@ -1247,10 +1530,10 @@ struct Item { uint32 updateHitMask(Lara* lara, CollisionInfo* cinfo); - Item* init(Room* room); + ItemObj* init(Room* room); - X_INLINE Item() {} - Item(Room* room); + X_INLINE ItemObj() {} + ItemObj(Room* room); virtual void activate(); virtual void deactivate(); virtual void hit(int32 damage, const vec3i &point, int32 soundId); @@ -1259,7 +1542,8 @@ struct Item { virtual void draw(); }; -struct SaveGame { +struct SaveGame +{ struct TrackFlags { uint8 once:1, mask:5, :2; }; @@ -1272,50 +1556,34 @@ struct SaveGame { uint32 ammoUsed; uint32 kills; TrackFlags tracks[64]; + uint32 flipped; + int32 gamma; }; -struct Settings { +struct Settings +{ struct Controls { bool retarget; } controls; }; -union FloorData { // 2 bytes - uint16 value; - - union Command { - struct { - uint16 func:5, tri:3, type:7, end:1; - }; - struct { - int16 :5, a:5, b:5, :1; - } triangle; - } cmd; - - struct { - int8 slantX; - int8 slantZ; - }; - - struct { - uint16 a:4, b:4, c:4, d:4; - }; - - struct TriggerInfo { - uint16 timer:8, once:1, mask:5, :2; - } triggerInfo; +#define FD_SET_END(x,end) ((x) |= ((end) << 15)) +#define FD_END(x) ((x) >> 15) +#define FD_FLOOR_TYPE(x) ((x) & 0x1F) +#define FD_TRIGGER_TYPE(x) (((x) >> 8) & 0x7F) +#define FD_TIMER(x) ((x) & 0xFF) +#define FD_ONCE(x) (((x) >> 8) & 1) +#define FD_SPEED(x) (((x) >> 9) & 0x1F) +#define FD_MASK(x) (((x) >> 9) & 0x1F) +#define FD_ACTION(x) (((x) >> 10) & 0x1F) +#define FD_ARGS(x) ((x) & 0x03FF) +#define FD_SLANT_X(x) int8((x) & 0xFF) +#define FD_SLANT_Z(x) int8((x) >> 8) - union TriggerCommand { - struct { - uint16 args:10, action:5, end:1; - }; - struct { - uint16 timer:8, once:1, speed:5, :2; - }; - } triggerCmd; -}; +typedef uint16 FloorData; -enum FloorType { +enum FloorType +{ FLOOR_TYPE_NONE, FLOOR_TYPE_PORTAL, FLOOR_TYPE_FLOOR, @@ -1324,7 +1592,8 @@ enum FloorType { FLOOR_TYPE_LAVA }; -enum TriggerType { +enum TriggerType +{ TRIGGER_TYPE_ACTIVATE, TRIGGER_TYPE_PAD, TRIGGER_TYPE_SWITCH, @@ -1333,10 +1602,11 @@ enum TriggerType { TRIGGER_TYPE_OBJECT, TRIGGER_TYPE_ANTIPAD, TRIGGER_TYPE_COMBAT, - TRIGGER_TYPE_DUMMY, + TRIGGER_TYPE_DUMMY }; -enum TriggerAction { +enum TriggerAction +{ TRIGGER_ACTION_ACTIVATE_OBJECT, TRIGGER_ACTION_ACTIVATE_CAMERA, TRIGGER_ACTION_FLOW, @@ -1353,30 +1623,34 @@ enum TriggerAction { TRIGGER_ACTION_CUTSCENE }; -enum SlantType { +enum SlantType +{ SLANT_NONE, SLANT_LOW, SLANT_HIGH }; -enum WaterState { +enum WaterState +{ WATER_STATE_ABOVE, WATER_STATE_WADE, WATER_STATE_SURFACE, - WATER_STATE_UNDER, + WATER_STATE_UNDER }; -enum AnimCommand { +enum AnimCommand +{ ANIM_CMD_NONE, ANIM_CMD_OFFSET, ANIM_CMD_JUMP, ANIM_CMD_EMPTY, ANIM_CMD_KILL, ANIM_CMD_SOUND, - ANIM_CMD_EFFECT, + ANIM_CMD_EFFECT }; -enum EffectType { +enum EffectType +{ FX_NONE = -1, FX_ROTATE_180 , FX_FLOOR_SHAKE , @@ -1412,10 +1686,11 @@ enum EffectType { FX_ASSAULT_FINISH , FX_FOOTPRINT , // specific - FX_TR1_FLICKER = 16, + FX_TR1_FLICKER = 16 }; -enum { +enum SoundID +{ SND_NO = 2, SND_LANDING = 4, @@ -1491,7 +1766,7 @@ enum { SND_WINSTON_SCARED = 344, SND_WINSTON_WALK = 345, SND_WINSTON_PUSH = 346, - SND_WINSTON_TRAY = 347, + SND_WINSTON_TRAY = 347 }; #define LARA_LOOK_ANGLE_MAX ANGLE(22) @@ -1499,19 +1774,21 @@ enum { #define LARA_LOOK_ANGLE_Y ANGLE(44) #define LARA_LOOK_TURN_SPEED ANGLE(2) -enum CollisionType { +enum CollisionType +{ CT_NONE = 0, CT_FRONT = (1 << 0), CT_LEFT = (1 << 1), CT_RIGHT = (1 << 2), CT_CEILING = (1 << 3), CT_FRONT_CEILING = (1 << 4), - CT_FLOOR_CEILING = (1 << 5), + CT_FLOOR_CEILING = (1 << 5) }; struct CollisionInfo { - enum SideType { + enum SideType + { ST_MIDDLE, ST_FRONT, ST_LEFT, @@ -1561,18 +1838,20 @@ struct CollisionInfo X_INLINE void setAngle(int16 value) { angle = value; - quadrant = uint16(value + ANGLE_45) / ANGLE_90; + quadrant = uint16(value + ANGLE_45) >> ANGLE_SHIFT_90; } }; -struct Box { +struct Box +{ int8 minZ, maxZ; int8 minX, maxX; int16 floor; - int16 overlap; + uint16 overlap; }; -struct Level { +struct Level +{ uint32 magic; uint16 tilesCount; @@ -1593,26 +1872,26 @@ struct Level { const uint8* tiles; const RoomInfo* roomsInfo; const FloorData* floors; - const uint8* meshData; + const Mesh** meshes; const int32* meshOffsets; const Anim* anims; const AnimState* animStates; const AnimRange* animRanges; const int16* animCommands; - const Node* nodes; + const ModelNode* nodes; const uint16* animFrames; const Model* models; const StaticMesh* staticMeshes; - const Texture* textures; + Texture* textures; const Sprite* sprites; const SpriteSeq* spriteSequences; - const FixedCamera* cameras; + FixedCamera* cameras; uint32 soundSources; - const Box* boxes; + Box* boxes; const uint16* overlaps; - const uint16* zones[2][3]; + const uint16* zones[2][ZONE_MAX]; const int16* animTexData; - const ItemInfo* itemsInfo; + const ItemObjInfo* itemsInfo; uint32 cameraFrames; const uint16* soundMap; const SoundInfo* soundsInfo; @@ -1623,17 +1902,28 @@ struct Level { // used by enemies struct TargetInfo { - Item* target; + ItemObj* target; + vec3i waypoint; + vec3i pos; int16 angle; int16 rotHead; + int16 tilt; + int16 turn; + uint32 dist; + uint16 boxIndex; + uint16 boxIndexTarget; + uint16 zoneIndex; + uint16 zoneIndexTarget; bool aim; + bool canAttack; }; extern TargetInfo tinfo; extern Level level; -struct IMA_STATE { +struct IMA_STATE +{ int32 smp; int32 idx; }; @@ -1644,13 +1934,18 @@ struct IMA_STATE { y = (y / (z >> 6));\ } */ -#if defined(MODE13) +#if defined(MODEHW) + #define PERSPECTIVE(x, y, z) {\ + x = (x << 6) / (z >> 2);\ + y = (y << 6) / (z >> 2);\ + } +#elif defined(MODE13) #define PERSPECTIVE(x, y, z) {\ int32 dz = (z >> (FIXED_SHIFT + FOV_SHIFT - 1)) / 3;\ if (dz >= DIV_TABLE_SIZE) dz = DIV_TABLE_SIZE - 1;\ int32 d = FixedInvU(dz);\ - x = d * (x >> FIXED_SHIFT) >> 12;\ - y = d * (y >> FIXED_SHIFT) >> 12;\ + x = d * (x >> 14) >> 12;\ + y = d * (y >> 14) >> 12;\ } #elif defined(MODE4) #define PERSPECTIVE(x, y, z) {\ @@ -1671,16 +1966,16 @@ struct IMA_STATE { } #endif -extern uint16 divTable[DIV_TABLE_SIZE]; - // renderer internal extern uint32 keys; -extern AABB frustumAABB; -extern Rect viewport; -extern vec3i cameraViewPos; +extern AABBi frustumAABB; +extern RectMinMax viewport; +extern vec3i cameraViewPos; +extern vec3i cameraViewOffset; extern Matrix matrixStack[MAX_MATRICES]; -extern int32 matrixStackIndex; -extern int32 gVerticesCount; +extern int32 matrixStackIndex; +extern int32 gVerticesCount; +extern int32 gFacesCount; extern SaveGame gSaveGame; extern Settings gSettings; @@ -1690,13 +1985,15 @@ extern const FloorData* gLastFloorData; extern FloorData gLastFloorSlant; extern Room rooms[MAX_ROOMS]; -extern Model models[MAX_MODELS]; -extern const Mesh* meshes[MAX_MESHES]; -extern StaticMesh staticMeshes[MAX_STATIC_MESHES]; -extern FixedCamera cameras[MAX_CAMERAS]; +extern ItemObj items[MAX_ITEMS]; // level data extern bool enableClipping; +extern bool enableMaxSort; + +#ifdef __3DO__ +extern uint8* VRAM_TEX; +#endif template X_INLINE void swap(T &a, T &b) { @@ -1710,6 +2007,9 @@ void set_seed_draw(int32 seed); int32 rand_logic(); int32 rand_draw(); +#define RAND_LOGIC(r) (rand_logic() * (r) >> 15) +#define RAND_DRAW(r) (rand_draw() * (r) >> 15) + int32 phd_sin(int32 x); int32 phd_cos(int32 x); int32 phd_atan(int32 x, int32 y); @@ -1720,6 +2020,13 @@ X_INLINE int32 dot(const vec3i &a, const vec3i &b) return a.x * b.x + a.y * b.y + a.z * b.z; } +X_INLINE int32 fastLength(int32 dx, int32 dy) +{ + dx = abs(dx); + dy = abs(dy); + return (dx > dy) ? (dx + (dy >> 1)) : (dy + (dx >> 1)); +} + void anglesFromVector(int32 x, int32 y, int32 z, int16 &angleX, int16 &angleY); X_INLINE int16 angleLerp(int16 a, int16 b, int32 w) @@ -1732,11 +2039,11 @@ X_INLINE int16 angleLerp(int16 a, int16 b, int32 w) #define angleDec(angle, value) angleLerp(angle, 0, value) -Bounds boxRotate(const Bounds &box, int16 angle); -void boxTranslate(Bounds &box, const vec3i &offset); -bool boxIntersect(const Bounds &a, const Bounds &b); -bool boxContains(const Bounds &a, const vec3i &p); -vec3i boxPushOut(const Bounds &a, const Bounds &b); +AABBs boxRotate(const AABBs &box, int16 angle); +void boxTranslate(AABBs &box, const vec3i &offset); +bool boxIntersect(const AABBs &a, const AABBs &b); +bool boxContains(const AABBs &a, const vec3i &p); +vec3i boxPushOut(const AABBs &a, const AABBs &b); #define DECODE_ANGLES(a,x,y,z)\ x = (((uint16*)(a))[1] & 0x3FF0) << 2;\ @@ -1755,15 +2062,15 @@ vec3i boxPushOut(const Bounds &a, const Bounds &b); #define LERP_SLOW(a, b, mul, div) a = a + ((b - a) * mul / div) #define LERP_ROW(lerp_func, a, b, mul, div) \ - lerp_func(a[0], b[0], mul, div); \ - lerp_func(a[1], b[1], mul, div); \ - lerp_func(a[2], b[2], mul, div); \ - lerp_func(a[3], b[3], mul, div); + lerp_func(a##0, b##0, mul, div); \ + lerp_func(a##1, b##1, mul, div); \ + lerp_func(a##2, b##2, mul, div); \ + lerp_func(a##3, b##3, mul, div); #define LERP_MATRIX(lerp_func) \ - LERP_ROW(lerp_func, m[0], n[0], multiplier, divider); \ - LERP_ROW(lerp_func, m[1], n[1], multiplier, divider); \ - LERP_ROW(lerp_func, m[2], n[2], multiplier, divider); + LERP_ROW(lerp_func, m.e0, n.e0, multiplier, divider); \ + LERP_ROW(lerp_func, m.e1, n.e1, multiplier, divider); \ + LERP_ROW(lerp_func, m.e2, n.e2, multiplier, divider); X_INLINE Matrix& matrixGet() { @@ -1773,10 +2080,9 @@ X_INLINE Matrix& matrixGet() X_INLINE void matrixPush() { ASSERT(matrixStackIndex < MAX_MATRICES - 1); - Matrix &a = matrixStack[matrixStackIndex++]; Matrix &b = matrixStack[matrixStackIndex]; - memcpy(b, a, sizeof(Matrix)); + memcpy(&b, &a, sizeof(Matrix)); } X_INLINE void matrixPop() @@ -1787,22 +2093,22 @@ X_INLINE void matrixPop() X_INLINE void matrixSetBasis(Matrix &dst, const Matrix &src) { - dst[0].x = src[0].x; - dst[0].y = src[0].y; - dst[0].z = src[0].z; + dst.e00 = src.e00; + dst.e01 = src.e01; + dst.e02 = src.e02; - dst[1].x = src[1].x; - dst[1].y = src[1].y; - dst[1].z = src[1].z; + dst.e10 = src.e10; + dst.e11 = src.e11; + dst.e12 = src.e12; - dst[1].x = src[1].x; - dst[1].y = src[1].y; - dst[1].z = src[1].z; + dst.e10 = src.e10; + dst.e11 = src.e11; + dst.e12 = src.e12; } -X_INLINE vec3i matrixGetDir(Matrix &m) +X_INLINE vec3i matrixGetDir(const Matrix &m) { - return vec3i(m[2].x, m[2].y, m[2].z); + return _vec3i(m.e20, m.e21, m.e22); } void matrixTranslate(int32 x, int32 y, int32 z); @@ -1818,37 +2124,47 @@ void matrixFrameLerp(const vec3s &pos, const uint32* anglesA, const uint32* angl void matrixSetIdentity(); void matrixSetView(const vec3i &pos, int32 angleX, int32 angleY); -void paletteSet(const uint16* palette); - +void setGamma(int32 value); void drawGlyph(const Sprite *sprite, int32 x, int32 y); +void renderInit(); +void setViewport(const RectMinMax &vp); +void setPaletteIndex(int32 index); void clear(); -int32 rectIsVisible(const Rect* rect); -int32 boxIsVisible(const Bounds* box); -void transform(int32 vx, int32 vy, int32 vz, int32 vg); -bool transformBoxRect(const Bounds* box, Rect* rect); -void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics); -void transformMesh(const vec3s* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal); -void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex); -void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex); +int32 rectIsVisible(const RectMinMax* rect); +int32 boxIsVisible(const AABBs* box); +void transform(vec3i* points, int32 count); +bool transformBoxRect(const AABBs* box, RectMinMax* rect); +void transformRoom(const RoomVertex* vertices, int32 vCount, bool underwater); +void transformMesh(const MeshVertex* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal); +void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex32); +void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex32); +void faceAddShadow(int32 x, int32 z, int32 sx, int32 sz); void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index); +void faceAddGlyph(int32 vx, int32 vy, int32 index); void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex); void faceAddMesh(const Quad* rFaces, const Quad* crFaces, const Triangle* tFaces, const Triangle* ctFaces, int32 rCount, int32 crCount, int32 tCount, int32 ctCount, int32 startVertex); - void flush(); +void drawInit(); +void drawFree(); +void drawModel(const ItemObj* item); +void drawItem(const ItemObj* item); +void drawRooms(Camera* camera); + +void checkTrigger(const FloorData* fd, ItemObj* lara); void readLevel(const uint8 *data); bool trace(const Location &from, Location &to, bool accurate); Lara* getLara(const vec3i &pos); -bool useSwitch(Item* item, int32 timer); -bool useKey(Item* item, Item* lara); -bool usePickup(Item* item); +bool useSwitch(ItemObj* item, int32 timer); +bool useKey(ItemObj* item, ItemObj* lara); +bool usePickup(ItemObj* item); void musicPlay(int32 track); void musicStop(); -int32 doTutorial(Item* lara, int32 track); +int32 doTutorial(ItemObj* lara, int32 track); X_INLINE void dmaFill(void *dst, uint8 value, uint32 count) { diff --git a/src/platform/gba/draw.h b/src/platform/gba/draw.h index c93204ea..826204be 100644 --- a/src/platform/gba/draw.h +++ b/src/platform/gba/draw.h @@ -68,7 +68,7 @@ void calcLightingDynamic(const Room* room, const vec3i &point) Matrix &m = matrixGet(); - int32 fogZ = m[2].w >> FIXED_SHIFT; + int32 fogZ = m.e23 >> FIXED_SHIFT; if (fogZ > FOG_MIN) { lightAmbient += (fogZ - FOG_MIN) << FOG_SHIFT; lightAmbient = X_MIN(lightAmbient, 8191); @@ -81,7 +81,7 @@ void calcLightingStatic(int32 intensity) Matrix &m = matrixGet(); - int32 fogZ = m[2].w >> FIXED_SHIFT; + int32 fogZ = m.e23 >> FIXED_SHIFT; if (fogZ > FOG_MIN) { lightAmbient += (fogZ - FOG_MIN) << FOG_SHIFT; } @@ -89,11 +89,14 @@ void calcLightingStatic(int32 intensity) void drawNumber(int32 number, int32 x, int32 y) { +#ifdef __3DO__ + return; +#endif static const int32 widths[] = { 12, 8, 10, 10, 10, 10, 10, 10, 10, 10 }; - const Sprite* glyphSprites = level.sprites + models[ITEM_GLYPHS].start; + const Sprite* glyphSprites = level.sprites + level.models[ITEM_GLYPHS].start; while (number > 0) { @@ -103,40 +106,120 @@ void drawNumber(int32 number, int32 x, int32 y) } } +const static uint8 char_width[110] = { + 14, 11, 11, 11, 11, 11, 11, 13, 8, 11, 12, 11, 13, 13, 12, 11, 12, 12, 11, 12, 13, 13, 13, 12, 12, 11, // A-Z + 9, 9, 9, 9, 9, 9, 9, 9, 5, 9, 9, 5, 12, 10, 9, 9, 9, 8, 9, 8, 9, 9, 11, 9, 9, 9, // a-z + 12, 8, 10, 10, 10, 10, 10, 9, 10, 10, // 0-9 + 5, 5, 5, 11, 9, 7, 8, 6, 0, 7, 7, 3, 8, 8, 13, 7, 9, 4, 12, 12, + 7, 5, 7, 7, 7, 7, 7, 7, 7, 7, 16, 14, 14, 14, 16, 16, 16, 16, 16, 12, 14, 8, 8, 8, 8, 8, 8, 8 +}; + +static const uint8 char_map[102] = { + 0, 64, 66, 78, 77, 74, 78, 79, 69, 70, 92, 72, 63, 71, 62, 68, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 73, 73, 66, 74, 75, 65, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 80, 76, 81, 97, 98, 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 100, 101, 102, 67, 0, 0, 0, 0, 0, 0, 0 +}; + +X_INLINE int32 charRemap(char c) +{ + if (c < 11) + return c + 81; + if (c < 16) + return c + 91; + return char_map[c - 32]; +} + +int32 getTextWidth(const char* text) +{ + int32 w = 0; + + char c; + while (c = *text++) + { + if (c == ' ') { + w += 6; + continue; + } + w += char_width[charRemap(c)]; + } + + return w; +} + +enum TextAlign { + TEXT_ALIGN_LEFT, + TEXT_ALIGN_RIGHT, + TEXT_ALIGN_CENTER +}; + +void drawText(int32 x, int32 y, const char* text, TextAlign align) +{ + if (align == TEXT_ALIGN_CENTER) { + x += (FRAME_WIDTH - getTextWidth(text)) >> 1; + } + + char c; + while ((c = *text++)) + { + if (c == ' ') { + x += 6; + continue; + } + int32 index = charRemap(c); + faceAddGlyph(x, y, level.models[ITEM_GLYPHS].start + index); + x += char_width[index]; + } +} + void drawMesh(int32 meshIndex) { - const uint8* ptr = (uint8*)meshes[meshIndex] + sizeof(Mesh); + const uint8* ptr = (uint8*)level.meshes[meshIndex]; + + const Mesh* mesh = (Mesh*)ptr; ptr += sizeof(Mesh); - int16 vCount = *(int16*)ptr; ptr += 2; - const vec3s* vertices = (vec3s*)ptr; - ptr += vCount * 3 * sizeof(int16); + int16 vCount = mesh->vCount; + + bool hasNormals = true; + if (vCount < 0) { + hasNormals = false; + vCount = -vCount; + } + + const MeshVertex* vertices = (MeshVertex*)ptr; + ptr += vCount * sizeof(vertices[0]); + + Quad* rFaces = (Quad*)ptr; + ptr += mesh->rCount * sizeof(Quad); + + Triangle* tFaces = (Triangle*)ptr; + ptr += mesh->tCount * sizeof(Triangle); + + Quad* crFaces = (Quad*)ptr; + ptr += mesh->crCount * sizeof(Quad); + + Triangle* ctFaces = (Triangle*)ptr; + ptr += mesh->ctCount * sizeof(Triangle); const uint16* vIntensity = NULL; const vec3s* vNormal = NULL; - int16 nCount = *(int16*)ptr; ptr += 2; //const int16* normals = (int16*)ptr; - if (nCount > 0) { // normals + if (hasNormals) { // normals vNormal = (vec3s*)ptr; - ptr += nCount * 3 * sizeof(int16); + ptr += vCount * sizeof(vec3s); } else { // intensity vIntensity = (uint16*)ptr; ptr += vCount * sizeof(uint16); } - int16 rCount = *(int16*)ptr; ptr += 2; - Quad* rFaces = (Quad*)ptr; ptr += rCount * sizeof(Quad); - - int16 tCount = *(int16*)ptr; ptr += 2; - Triangle* tFaces = (Triangle*)ptr; ptr += tCount * sizeof(Triangle); - - int16 crCount = *(int16*)ptr; ptr += 2; - Quad* crFaces = (Quad*)ptr; ptr += crCount * sizeof(Quad); + int32 startVertex = gVerticesCount; - int16 ctCount = *(int16*)ptr; ptr += 2; - Triangle* ctFaces = (Triangle*)ptr; ptr += ctCount * sizeof(Triangle); + if (MAX_VERTICES - gVerticesCount < vCount) + return; - int32 startVertex = gVerticesCount; + if (MAX_FACES - gFacesCount < mesh->rCount + mesh->tCount + mesh->crCount + mesh->ctCount) + return; { PROFILE(CNT_TRANSFORM); @@ -145,11 +228,11 @@ void drawMesh(int32 meshIndex) { PROFILE(CNT_ADD); - faceAddMesh(rFaces, crFaces, tFaces, ctFaces, rCount, crCount, tCount, ctCount, startVertex); + faceAddMesh(rFaces, crFaces, tFaces, ctFaces, mesh->rCount, mesh->crCount, mesh->tCount, mesh->ctCount, startVertex); } } -void drawShadow(const Item* item, int32 size) +void drawShadow(const ItemObj* item, int32 size) { const Sector* sector = item->room->getSector(item->pos.x, item->pos.z); int32 floor = sector->getFloor(item->pos.x, item->pos.y, item->pos.z); @@ -159,31 +242,36 @@ void drawShadow(const Item* item, int32 size) enableClipping = true; - const Bounds& box = item->getBoundingBox(true); + const AABBs& box = item->getBoundingBox(true); int32 x = (box.maxX + box.minX) >> 1; int32 z = (box.maxZ + box.minZ) >> 1; int32 sx = (box.maxX - box.minX) * size >> 10; int32 sz = (box.maxZ - box.minZ) * size >> 10; - int32 sx2 = sx << 1; - int32 sz2 = sz << 1; - - int32 startVertex = gVerticesCount; - - int32 y = floor - item->pos.y; matrixPush(); - matrixTranslateAbs(item->pos.x, item->pos.y, item->pos.z); + matrixTranslateAbs(item->pos.x, floor, item->pos.z); matrixRotateY(item->angle.y); - transform(x - sx, y, z + sz2, 4096); - transform(x + sx, y, z + sz2, 4096); - transform(x + sx2, y, z + sz, 4096); - transform(x + sx2, y, z - sz, 4096); +#ifdef __3DO__ + faceAddShadow(x, z, sx, sz); +#else + int32 sx2 = sx << 1; + int32 sz2 = sz << 1; + + MeshVertex v[8] = { + { x - sx, 0, z + sz2 }, // 0 + { x + sx, 0, z + sz2 }, // 1 + { x + sx2, 0, z + sz }, // 2 + { x + sx2, 0, z - sz }, // 3 + { x + sx, 0, z - sz2 }, // 4 + { x - sx, 0, z - sz2 }, // 5 + { x - sx2, 0, z - sz }, // 6 + { x - sx2, 0, z + sz } // 7 + }; + + int32 startVertex32 = gVerticesCount; - transform(x + sx, y, z - sz2, 4096); - transform(x - sx, y, z - sz2, 4096); - transform(x - sx2, y, z - sz, 4096); - transform(x - sx2, y, z + sz, 4096); + transformMesh(v, 8, NULL, NULL); static const Index indices[] = { 0, 1, 2, 7, @@ -191,17 +279,17 @@ void drawShadow(const Item* item, int32 size) 6, 3, 4, 5 }; - faceAddQuad(FACE_SHADOW, indices + 0, startVertex); - faceAddQuad(FACE_SHADOW, indices + 4, startVertex); - faceAddQuad(FACE_SHADOW, indices + 8, startVertex); + faceAddQuad(FACE_SHADOW, indices + 0, startVertex32); + faceAddQuad(FACE_SHADOW, indices + 4, startVertex32); + faceAddQuad(FACE_SHADOW, indices + 8, startVertex32); +#endif matrixPop(); } -void drawSprite(const Item* item) +void drawSprite(const ItemObj* item) { - vec3i d = item->pos - cameraViewPos; - faceAddSprite(d.x, d.y, d.z, item->intensity << 5, models[item->type].start + item->frameIndex); + faceAddSprite(item->pos.x, item->pos.y, item->pos.z, item->intensity << 5, level.models[item->type].start + item->frameIndex); } void drawFlash(const ExtraInfoLara::Arm::Flash &flash) @@ -213,17 +301,17 @@ void drawFlash(const ExtraInfoLara::Arm::Flash &flash) int32 tmp = lightAmbient; calcLightingStatic(flash.intensity); - drawMesh(models[ITEM_MUZZLE_FLASH].start); + drawMesh(level.models[ITEM_MUZZLE_FLASH].start); lightAmbient = tmp; matrixPop(); } -void drawNodes(const Item* item, const AnimFrame* frameA) +void drawNodes(const ItemObj* item, const AnimFrame* frameA) { - const Model* model = models + item->type; - const Node* node = level.nodes + model->nodeIndex; + const Model* model = level.models + item->type; + const ModelNode* node = level.nodes + model->nodeIndex; int32 meshIndex = model->start; int32 meshCount = model->count; uint32 visibleMask = item->visibleMask; @@ -263,7 +351,7 @@ void drawNodes(const Item* item, const AnimFrame* frameA) } } -void drawNodesLerp(const Item* item, const AnimFrame* frameA, const AnimFrame* frameB, int32 frameDelta, int32 frameRate) +void drawNodesLerp(const ItemObj* item, const AnimFrame* frameA, const AnimFrame* frameB, int32 frameDelta, int32 frameRate) { if (frameDelta == 0) { @@ -271,8 +359,8 @@ void drawNodesLerp(const Item* item, const AnimFrame* frameA, const AnimFrame* f return; } - const Model* model = models + item->type; - const Node* node = level.nodes + model->nodeIndex; + const Model* model = level.models + item->type; + const ModelNode* node = level.nodes + model->nodeIndex; int32 meshIndex = model->start; int32 meshCount = model->count; uint32 visibleMask = item->visibleMask; @@ -321,12 +409,12 @@ void drawNodesLerp(const Item* item, const AnimFrame* frameA, const AnimFrame* f } } -#define DEF_TORSO_ANGLE vec3s(1216, -832, -192) +#define DEF_TORSO_ANGLE _vec3s(1216, -832, -192) -void drawLaraNodes(const Item* lara, const AnimFrame* frameA) +void drawLaraNodes(const ItemObj* lara, const AnimFrame* frameA) { - const Model* model = models + lara->type; - const Node* node = level.nodes + model->nodeIndex; + const Model* model = level.models + lara->type; + const ModelNode* node = level.nodes + model->nodeIndex; const ExtraInfoLara* extraL = lara->extraL; const uint16* mesh = extraL->meshes; @@ -401,10 +489,12 @@ void drawLaraNodes(const Item* lara, const AnimFrame* frameA) matrixTranslate(node->pos.x, node->pos.y, node->pos.z); node++; if (arm->useBasis) { // hands are rotated relative to the basis + #ifndef __3DO__ // TODO_3DO matrixSetBasis(matrixGet(), basis); + #endif matrixRotateYXZ(arm->angle.x, arm->angle.y, arm->angle.z); } - matrixFrame(vec3s(0, 0, 0), anglesArm[i]++); + matrixFrame(_vec3s(0, 0, 0), anglesArm[i]++); drawMesh(*mesh++); { // JOINT_ARM_2 @@ -433,7 +523,7 @@ void drawLaraNodes(const Item* lara, const AnimFrame* frameA) matrixPop(); } -void drawLaraNodesLerp(const Item* lara, const AnimFrame* frameA, const AnimFrame* frameB, int32 frameDelta, int32 frameRate) +void drawLaraNodesLerp(const ItemObj* lara, const AnimFrame* frameA, const AnimFrame* frameB, int32 frameDelta, int32 frameRate) { if (frameDelta == 0) { @@ -441,8 +531,8 @@ void drawLaraNodesLerp(const Item* lara, const AnimFrame* frameA, const AnimFram return; } - const Model* model = models + lara->type; - const Node* node = level.nodes + model->nodeIndex; + const Model* model = level.models + lara->type; + const ModelNode* node = level.nodes + model->nodeIndex; const ExtraInfoLara* extraL = lara->extraL; const uint16* mesh = extraL->meshes; @@ -533,16 +623,18 @@ void drawLaraNodesLerp(const Item* lara, const AnimFrame* frameA, const AnimFram matrixTranslate(node->pos.x, node->pos.y, node->pos.z); node++; if (arm->useBasis) { // hands are rotated relative to the basis + #ifndef __3DO__ // TODO_3DO matrixSetBasis(matrixGet(), basis); + #endif matrixRotateYXZ(arm->angle.x, arm->angle.y, arm->angle.z); } bool useLerp = frameRateArm[i] > 1; // armed hands always use frameRate == 1 (i.e. useLerp == false) if (useLerp) { - matrixFrameLerp(vec3s(0, 0, 0), anglesArmA[i]++, anglesArmB[i]++, frameDelta, frameRate); + matrixFrameLerp(_vec3s(0, 0, 0), anglesArmA[i]++, anglesArmB[i]++, frameDelta, frameRate); } else { - matrixFrame(vec3s(0, 0, 0), anglesArmA[i]++); + matrixFrame(_vec3s(0, 0, 0), anglesArmA[i]++); } drawMesh(*mesh++); @@ -580,20 +672,43 @@ void drawLaraNodesLerp(const Item* lara, const AnimFrame* frameA, const AnimFram matrixPop(); } -void drawModel(const Item* item) +void drawModel(const ItemObj* item) { const AnimFrame *frameA, *frameB; int32 frameRate; - int32 frameDelta = item->getFrames(frameA, frameB, frameRate); // TODO lerp + int32 frameDelta = item->getFrames(frameA, frameB, frameRate); + +#ifdef NO_ANIM_LERP + frameDelta = 0; +#endif matrixPush(); matrixTranslateAbs(item->pos.x, item->pos.y, item->pos.z); matrixRotateYXZ(item->angle.x, item->angle.y, item->angle.z); - int32 vis = boxIsVisible(&frameA->box); - if (vis != 0) + int32 vis; + RectMinMax rect; + if (transformBoxRect(&frameA->box, &rect)) { + vis = rectIsVisible(&rect); + } else { + vis = 0; + } + + if (vis) { + #ifndef NO_ANIM_LERP + #ifdef LOD_ANIM + if ((item->type != ITEM_LARA) && (item->type != ITEM_CRYSTAL)) + { + int32 d = X_MAX(rect.x1 - rect.x0, rect.y1 - rect.y0); + if (d < LOD_ANIM) { + frameDelta = 0; // don't use matrix interpolation for small objects on the screen + } + } + #endif + #endif + enableClipping = vis < 0; int32 intensity = item->intensity << 5; @@ -606,78 +721,109 @@ void drawModel(const Item* item) } // skip rooms portal clipping for objects - Rect oldViewport = viewport; - viewport = Rect( 0, 0, FRAME_WIDTH, FRAME_HEIGHT ); - if (item->type == ITEM_LARA) { drawLaraNodesLerp(item, frameA, frameB, frameDelta, frameRate); } else { drawNodesLerp(item, frameA, frameB, frameDelta, frameRate); } - - viewport = oldViewport; } matrixPop(); // shadow - if (vis != 0 && item->flags.shadow) { + if (vis && item->flags.shadow) { drawShadow(item, 160); // TODO per item shadow size } } -void drawItem(const Item* item) +void drawItem(const ItemObj* item) { - if (models[item->type].count > 0) { + if (level.models[item->type].count > 0) { drawModel(item); } else { drawSprite(item); } } -void drawRoom(const Room* room) +void drawRoom(const Room* room, Camera* camera) { - viewport = room->clip; + setViewport(room->clip); int32 startVertex = gVerticesCount; const RoomInfo* info = room->info; const RoomData& data = room->data; + if (MAX_VERTICES - gVerticesCount < info->verticesCount) + return; + + if (MAX_FACES - gFacesCount < info->quadsCount + info->trianglesCount) + return; + + int32 rx = info->x << 8; + int32 rz = info->z << 8; + matrixPush(); matrixTranslateAbs(info->x << 8, 0, info->z << 8); - gCamera->updateFrustum(info->x << 8, 0, info->z << 8); + camera->updateFrustum(info->x << 8, 0, info->z << 8); + + setPaletteIndex(ROOM_FLAG_WATER(info->flags) ? 1 : 0); enableClipping = true; +/* // show portals + for (int32 i = 0; i < info->portalsCount; i++) + { + RoomVertex pv[4]; + for (int32 j = 0; j < 4; j++) + { + pv[j].x = (data.portals[i].v[j].x + 1) >> 10; + pv[j].y = (data.portals[i].v[j].y + 1) >> 8; + pv[j].z = (data.portals[i].v[j].z + 1) >> 10; + } + Quad q; + q.flags = 171; + q.indices[0] = i * 4 + 0; + q.indices[1] = i * 4 + 1; + q.indices[2] = i * 4 + 2; + q.indices[3] = i * 4 + 3; + + transformRoom(pv, 4, 0); + faceAddRoom(&q, 1, NULL, 0, startVertex); + } + startVertex = gVerticesCount; +*/ + { PROFILE(CNT_TRANSFORM); - transformRoom(data.vertices, info->verticesCount, info->flags.water); + transformRoom(data.vertices, info->verticesCount, ROOM_FLAG_WATER(info->flags)); } { PROFILE(CNT_ADD); + enableMaxSort = true; faceAddRoom(data.quads, info->quadsCount, data.triangles, info->trianglesCount, startVertex); + enableMaxSort = false; } + matrixPop(); + for (int32 i = 0; i < info->spritesCount; i++) { const RoomSprite* sprite = data.sprites + i; - faceAddSprite(sprite->pos.x, sprite->pos.y, sprite->pos.z, sprite->g << 5, sprite->index); + faceAddSprite(sprite->pos.x + rx, sprite->pos.y, sprite->pos.z + rz, sprite->g << 5, sprite->index); } - matrixPop(); - for (int32 i = 0; i < info->meshesCount; i++) { const RoomMesh* mesh = data.meshes + i; #ifdef NO_STATIC_MESH_PLANTS - if (mesh->id < 10) continue; + if (STATIC_MESH_ID(mesh->flags) < 10) continue; #endif - const StaticMesh* staticMesh = staticMeshes + mesh->id; + const StaticMesh* staticMesh = level.staticMeshes + STATIC_MESH_ID(mesh->flags); if (!(staticMesh->flags & STATIC_MESH_FLAG_VISIBLE)) continue; // invisible @@ -688,11 +834,11 @@ void drawRoom(const Room* room) matrixPush(); matrixTranslateAbs(pos.x, pos.y, pos.z); - matrixRotateY((mesh->rot - 2) * ANGLE_90); + matrixRotateY(STATIC_MESH_ROT(mesh->flags)); int32 vis = boxIsVisible(&staticMesh->vbox); if (vis != 0) { - enableClipping = true;//vis < 0; // TODO wrong visibility BBox? + enableClipping =vis < 0; // TODO wrong visibility BBox? calcLightingStatic(mesh->intensity << 5); drawMesh(staticMesh->meshIndex); @@ -701,7 +847,7 @@ void drawRoom(const Room* room) matrixPop(); } - Item* item = room->firstItem; + ItemObj* item = room->firstItem; while (item) { if (item->flags.status != ITEM_FLAGS_STATUS_INVISIBLE) { @@ -711,21 +857,47 @@ void drawRoom(const Room* room) } } -void drawRooms() +void drawRooms(Camera* camera) { - gCamera->view.room->clip = Rect( 0, 0, FRAME_WIDTH, FRAME_HEIGHT ); + camera->view.room->clip = viewport; - Room** visRoom = gCamera->view.room->getVisibleRooms(); + Room** visRoom = camera->view.room->getVisibleRooms(); + // draw Lara first + for (int32 i = 0; i < MAX_PLAYERS; i++) + { + Lara* lara = players[i]; + if (lara) + { + lara->flags.status = ITEM_FLAGS_STATUS_NONE; + setPaletteIndex(ROOM_FLAG_WATER(lara->room->info->flags) ? 1 : 0); + lara->draw(); + lara->flags.status = ITEM_FLAGS_STATUS_INVISIBLE; // skip drawing in the general pass + } + } + + // draw rooms and objects while (*visRoom) { Room* room = *visRoom++; - - drawRoom(room); + drawRoom(room, camera); room->reset(); } + // reset visibility flags for Lara + for (int32 i = 0; i < MAX_PLAYERS; i++) + { + Lara* lara = players[i]; + if (lara) + { + lara->flags.status = ITEM_FLAGS_STATUS_NONE; + } + } + flush(); + + setPaletteIndex(0); + setViewport(camera->view.room->clip); } #endif diff --git a/src/platform/gba/enemy.h b/src/platform/gba/enemy.h index d1dc3686..f0cc7880 100644 --- a/src/platform/gba/enemy.h +++ b/src/platform/gba/enemy.h @@ -4,6 +4,9 @@ #include "common.h" #include "item.h" +#define ENEMY_TURN_FAST ANGLE(5) +#define ENEMY_TURN_SLOW ANGLE(2) + EWRAM_DATA ExtraInfoEnemy enemiesExtra[MAX_ENEMIES]; enum AggressionLevel @@ -14,9 +17,9 @@ enum AggressionLevel AGGRESSION_LVL_MAX = 0x7FFF, }; -struct Enemy : Item +struct Enemy : ItemObj { - Enemy(Room* room, int32 _health, int32 _radius, int32 _headOffset, int32 _aggression) : Item(room) + Enemy(Room* room, int32 _health, int32 _radius, int32 _headOffset, int32 _aggression) : ItemObj(room) { flags.shadow = true; @@ -24,8 +27,10 @@ struct Enemy : Item angle.y += (rand_logic() - 0x4000) >> 1; #endif + ASSERT(_radius < 512); + health = _health; - radius = _radius; + radius = _radius >> 1; headOffset = _headOffset; aggression = _aggression; } @@ -39,69 +44,77 @@ struct Enemy : Item if (!extraE) return; - if (extra->enemy) + if (extraE->enemy) { - extra->enemy->flags.status = ITEM_FLAGS_STATUS_INVISIBLE; - extra->enemy->disable(); + extraE->enemy->flags.status = ITEM_FLAGS_STATUS_INVISIBLE; + extraE->enemy->disable(); } - extra->enemy = this; - extra->rotHead = extra->rotNeck = 0; + extraE->enemy = this; + extraE->rotHead = extraE->rotNeck = 0; + extraE->maxTurn = 0; + extraE->nav.stepHeight = 256; + extraE->nav.dropHeight = -256; + extraE->nav.vSpeed = 0; + + initExtra(); - // TODO initialize enemy and navigation + const Sector* sector = room->getSector(pos.x, pos.z); + ASSERT(sector->boxIndex != NO_BOX); + extraE->nav.init(sector->boxIndex); } bool enable(bool forced) { - //return false; - if (extraE) return true; + int32 index = -1; + for (int32 i = 0; i < MAX_ENEMIES; i++) { if (!enemiesExtra[i].enemy) { - setExtra(enemiesExtra + i); - return true; + index = i; + break; } } - for (int32 i = 0; i < MAX_PLAYERS; i++) + if (index == -1) { - if (!players[i]) - continue; - - vec3i &viewPos = players[i]->extraL->camera->view.pos; + for (int32 i = 0; i < MAX_PLAYERS; i++) + { + if (!players[i]) + continue; - int32 index = -1; - int32 maxDistQ = 0; + vec3i &viewPos = players[i]->extraL->camera.view.pos; - if (!forced) - { - vec3i d = pos - viewPos; - maxDistQ = X_SQR(d.x >> 8) + X_SQR(d.y >> 8) + X_SQR(d.z >> 8); - } + int32 maxDistQ = 0; - for (int32 j = 0; j < MAX_ENEMIES; j++) - { - vec3i d = enemiesExtra[j].enemy->pos - viewPos; - int32 distQ = X_SQR(d.x >> 8) + X_SQR(d.y >> 8) + X_SQR(d.z >> 8); - if (distQ > maxDistQ) + if (!forced) { - maxDistQ = distQ; - index = j; + vec3i d = pos - viewPos; + maxDistQ = X_SQR(d.x >> 8) + X_SQR(d.y >> 8) + X_SQR(d.z >> 8); } - } - if (index != -1) - { - setExtra(enemiesExtra + index); - return true; + for (int32 j = 0; j < MAX_ENEMIES; j++) + { + vec3i d = enemiesExtra[j].enemy->pos - viewPos; + int32 distQ = X_SQR(d.x >> 8) + X_SQR(d.y >> 8) + X_SQR(d.z >> 8); + if (distQ > maxDistQ) + { + maxDistQ = distQ; + index = j; + } + } } } - return false; + if (index == -1) + return false; + + setExtra(enemiesExtra + index); + return true; } void disable() @@ -115,30 +128,444 @@ struct Enemy : Item { tinfo.target = getLara(pos); + if (tinfo.target->health <= 0) { + hitMask = 0; + } + + tinfo.tilt = 0; + tinfo.turn = 0; + tinfo.pos = pos; + if (health <= 0) { tinfo.angle = 0; tinfo.rotHead = 0; tinfo.aim = false; + tinfo.rotHead = 0; return; } int32 dx = tinfo.target->pos.x - pos.x; int32 dz = tinfo.target->pos.z - pos.z; - if (headOffset) { + if (headOffset) + { dx -= phd_sin(angle.y) * headOffset >> FIXED_SHIFT; dz -= phd_cos(angle.y) * headOffset >> FIXED_SHIFT; } - tinfo.angle = phd_atan(dz, dx) - angle.y; + int16 rot = phd_atan(dz, dx); + + tinfo.dist = fastLength(dx, dz); + tinfo.angle = rot - angle.y; tinfo.aim = (tinfo.angle > -ANGLE_90) && (tinfo.angle < ANGLE_90); - tinfo.rotHead = tinfo.aim ? tinfo.angle : 0; + tinfo.canAttack = tinfo.aim && (abs(tinfo.target->pos.y - pos.y) < 256); + tinfo.rotHead = (tinfo.aim && mood != MOOD_SLEEP) ? tinfo.angle : 0; + + // update navigation target + const uint16* zones = getZones(); + + tinfo.boxIndex = room->getSector(pos.x, pos.z)->boxIndex; + tinfo.boxIndexTarget = tinfo.target->room->getSector(tinfo.target->pos.x, tinfo.target->pos.z)->boxIndex; + tinfo.zoneIndex = zones[tinfo.boxIndex]; + tinfo.zoneIndexTarget = zones[tinfo.boxIndexTarget]; + + //@TODO blocking + } + + void updateMood() + { + //if (extraE->nav.cells[extraE->boxIndex].weight == ) //@TODO blocking + + if (mood != MOOD_ATTACK && extraE->nav.nextBox != NO_BOX && !checkZone(extraE->nav.endBox)) + { + bool inZone = checkZone(); + if (!inZone) { + mood = MOOD_SLEEP; + } + extraE->nav.nextBox = NO_BOX; + } + + uint32 nextMood = tinfo.target->health <= 0 ? MOOD_SLEEP : (flags.animated ? getMoodWild() : getMoodNormal()); + + flags.injured = false; + + if (mood != nextMood) + { + if (mood == MOOD_ATTACK) { + setNextBox(extraE->nav.endBox); + } + extraE->nav.nextBox = NO_BOX; + mood = nextMood; + } + + switch (mood) + { + case MOOD_SLEEP : moodSleep(); break; + case MOOD_STALK : moodStalk(); break; + case MOOD_ATTACK : moodAttack(); break; + case MOOD_ESCAPE : moodEscape(); break; + } + + if (extraE->nav.endBox == NO_BOX) { + setNextBox(tinfo.boxIndex); + } + } + + void moodSleep() + { + int32 boxIndex = getRandomBox(); + + if (!checkZone(boxIndex)) + return; + + if (checkStalk(boxIndex)) + { + mood = MOOD_STALK; + setNextBox(boxIndex); + return; + } + + if (extraE->nav.nextBox != NO_BOX) + return; + + setNextBox(boxIndex); + } + + void moodStalk() + { + if (extraE->nav.nextBox != NO_BOX && checkStalk(extraE->nav.nextBox)) + return; + + int32 boxIndex = getRandomBox(); + + if (!checkZone(boxIndex)) + return; + + if (checkStalk(boxIndex)) + { + setNextBox(boxIndex); + return; + } + + if (extraE->nav.nextBox != NO_BOX) + return; + + setNextBox(boxIndex); + + if (tinfo.zoneIndex != tinfo.zoneIndexTarget) { + mood = MOOD_SLEEP; + } + } + + void moodAttack() + { + if (rand_logic() >= aggression) + return; + + extraE->nav.pos = tinfo.target->pos; + extraE->nav.nextBox = tinfo.boxIndexTarget; + + if (extraE->nav.zoneType == ZONE_FLY) { + extraE->nav.pos.y += getFrame()->box.minY; // attack Laras head + } + } + + void moodEscape() + { + int32 boxIndex = getRandomBox(); + + if (!checkZone(boxIndex) || (extraE->nav.nextBox != NO_BOX)) + return; + + if (checkEscape(boxIndex)) + { + setNextBox(boxIndex); + return; + } + + if ((tinfo.zoneIndex != tinfo.zoneIndexTarget) || !checkStalk(boxIndex)) + return; + + mood = MOOD_STALK; + setNextBox(boxIndex); + } + + void updateNavigation() + { + tinfo.waypoint = extraE->nav.getWaypoint(tinfo.boxIndex, pos); + + int16 maxTurn = extraE->maxTurn; + + if (health <= 0 || !hSpeed || !maxTurn) + return; + + int32 dx = tinfo.waypoint.x - pos.x; + int32 dz = tinfo.waypoint.z - pos.z; + int16 turn = phd_atan(dz, dx) - angle.y; + int32 r = (hSpeed << FIXED_SHIFT) / maxTurn; //@DIV + int32 d = fastLength(dx, dz); + bool aim = (turn > -ANGLE_90) && (turn < ANGLE_90); + + if (!aim && (d < r)) + maxTurn >>= 1; + + tinfo.turn = X_CLAMP(turn, -maxTurn, maxTurn); + } + + void setNextBox(int16 boxIndex) + { + boxIndex &= 0x7FFF; + const Box* box = level.boxes + boxIndex; + + int32 bMinX = (box->minX << 10) + 512; + int32 bMaxX = (box->maxX << 10) - 512; + int32 bMinZ = (box->minZ << 10) + 512; + int32 bMaxZ = (box->maxZ << 10) - 512; + + extraE->nav.nextBox = boxIndex; + extraE->nav.pos.x = bMinX + RAND_LOGIC(bMaxX - bMinX); + extraE->nav.pos.z = bMinZ + RAND_LOGIC(bMaxZ - bMinZ); + extraE->nav.pos.y = box->floor; + if (extraE->nav.zoneType != ZONE_FLY) + extraE->nav.pos.y -= 384; + } + + uint32 getMoodWild() + { + bool inZone = checkZone(); + + if (mood == MOOD_SLEEP || mood == MOOD_STALK) + return inZone ? MOOD_ATTACK : (flags.injured ? MOOD_ESCAPE : mood); + + if (mood == MOOD_ATTACK) + return inZone ? mood : MOOD_SLEEP; + + return inZone ? MOOD_ATTACK : mood; + } + + uint32 getMoodNormal() + { + bool inZone = checkZone(); + + if (mood == MOOD_SLEEP || mood == MOOD_STALK) + { + if (flags.injured && (rand_logic() < 0x800 || !inZone)) + return MOOD_ESCAPE; + if (inZone) + return ((tinfo.dist < 3072) || (mood == MOOD_STALK && extraE->nav.nextBox == NO_BOX)) ? MOOD_ATTACK : MOOD_STALK; + return mood; + } + + if (mood == MOOD_ATTACK) + return (flags.injured && rand_logic() < 0x800) ? MOOD_ESCAPE : (!inZone ? MOOD_SLEEP : mood); + + return (inZone && rand_logic() < 0x100) ? MOOD_STALK : mood; + } + + X_INLINE bool checkZone() + { + return tinfo.zoneIndex == tinfo.zoneIndexTarget; + } + + X_INLINE int32 getRandomBox() + { + return extraE->nav.cells[RAND_LOGIC(extraE->nav.cellsCount)].boxIndex; + } + + bool checkZone(int16 boxIndex) + { + if (getZones()[boxIndex] != tinfo.zoneIndex) + return false; + + const Box &b = level.boxes[boxIndex]; + + //@TODO blocking + + return (pos.x <= (b.minX << 10)) || (pos.x >= ((b.maxX << 10) - 1)) || + (pos.z <= (b.minZ << 10)) || (pos.z >= ((b.maxZ << 10) - 1)); + } + + bool checkStalk(int16 boxIndex) + { + const Box &b = level.boxes[boxIndex]; + + int32 dx = (((b.minX + b.maxX) << 10) >> 1) - tinfo.target->pos.x; + int32 dz = (((b.minZ + b.maxZ) << 10) >> 1) - tinfo.target->pos.z; + + if (X_MAX(abs(dx), abs(dz)) > 3072) + return false; + + int32 qLara = (tinfo.target->angle.y >> 14) + 2; + int32 qBox = (dz > 0) ? ((dx > 0) ? 2 : 1) : ((dx > 0) ? 3 : 0); + + if (qLara == qBox) // Lara looks at this box + return false; + + if (abs(qLara - qBox) != 2) // Lara looks in the opposite direction + return true; + + dx = pos.x - tinfo.target->pos.x; + dz = pos.z - tinfo.target->pos.z; + + int32 qEnemy = (dz > 0) ? ((dx > 0) ? 2 : 1) : ((dx > 0) ? 3 : 0); + + return qLara != qEnemy; // Lara looks at enemy + } + + bool checkEscape(int16 boxIndex) + { + const Box &b = level.boxes[boxIndex]; + + int32 dx = (((b.minX + b.maxX) << 10) >> 1) - tinfo.target->pos.x; + int32 dz = (((b.minZ + b.maxZ) << 10) >> 1) - tinfo.target->pos.z; + + if (X_MAX(abs(dx), abs(dz)) < 5120) + return false; + + int32 px = pos.x - tinfo.target->pos.x; + int32 pz = pos.z - tinfo.target->pos.z; + + return !(((dx ^ px) & 0x80000000) && ((dz ^ pz) & 0x80000000)); + } + + const uint16* getZones() + { + return level.zones[gSaveGame.flipped][extraE->nav.zoneType]; + } + + void bite(int32 joint, const vec3i &offset, int32 damage) + { + if (!tinfo.target) + return; + + vec3i fxPos = pos + getJoint(joint, offset); + fxBlood(fxPos, 0, 0); + + tinfo.target->hit(damage, offset, 0); + } + + void updateLocation() + { + updateRoom(); + + bool badPos = false; + + if (extraE->nav.zoneType == ZONE_FLY) + { + int32 dy = X_CLAMP(tinfo.waypoint.y - pos.y, -extraE->nav.vSpeed, extraE->nav.vSpeed); + int32 y = pos.y + dy; + + const Sector* sector = room->getSector(pos.x, pos.z); + + int32 floor = sector->getFloor(pos.x, y, pos.z); + if (y > floor) + { + if (pos.y > floor) + { + pos.x = tinfo.pos.x; + pos.z = tinfo.pos.z; + dy = -extraE->nav.vSpeed; // go up + } else { + pos.y = floor; + dy = 0; + } + } + + int32 ceiling = sector->getCeiling(pos.x, y, pos.z); + if (y < ceiling) + { + if (pos.y < ceiling) + { + pos.x = tinfo.pos.x; + pos.z = tinfo.pos.z; + dy = extraE->nav.vSpeed; // go down + } else { + pos.y = ceiling; + dy = 0; + } + } + + // update vertical position + pos.y += dy; + + // update pitch + int32 pitch = 0; + if (hSpeed) { + pitch = phd_atan(hSpeed, -dy); + } + angle.x = angleLerp(angle.x, pitch, ANGLE_1); + + updateRoom(); + } else { + pos.y = X_MIN(pos.y, roomFloor); + + if (pos.y > roomFloor) { + pos.y = roomFloor; + } else if (roomFloor - pos.y > 64) { + pos.y += 64; + } else if (pos.y < roomFloor) { + pos.y = roomFloor; + } + } + + if (!badPos) // check for enemy vs enemy collision + { + ItemObj* item = room->firstItem; + while (item) + { + if (item->type != ITEM_LARA && item != this && item->health > 0 && item->flags.status == ITEM_FLAGS_STATUS_ACTIVE) + { + int32 dx = item->pos.x - pos.x; + int32 dz = item->pos.z - pos.z; + int32 d = fastLength(dx, dz); + + if ((d < (radius << 1)) && hSpeed) + { + tinfo.turn = ANGLE(8); + badPos = true; + break; + } + } + item = item->nextItem; + } + } + + if (!badPos) // check for wrong zone or wall + { + const uint16* zones = getZones(); + uint32 boxIndex = room->getSector(pos.x, pos.z)->boxIndex; + badPos = (boxIndex == NO_BOX) || (tinfo.zoneIndex != zones[boxIndex]); + } + + if (!badPos) // check for wrong height delta + { + int32 h = pos.y - roomFloor; + badPos = (h > extraE->nav.stepHeight) || (h < extraE->nav.dropHeight); + } + + if (badPos) + { + angle.y += tinfo.turn; // apply turn again for double rotation speed if blocked by something + pos = tinfo.pos; + + updateRoom(); + } + + #ifdef _DEBUG + {// TODO investigate enemies respawn + const Sector* sector = room->getSector(pos.x, pos.z); + ASSERT(sector->boxIndex != NO_BOX); + } + #endif } virtual void activate() { - Item::activate(); + if (health <= 0) + return; + + ItemObj::activate(); if (!enable(flags.status == ITEM_FLAGS_STATUS_NONE)) { flags.status = ITEM_FLAGS_STATUS_INVISIBLE; @@ -158,11 +585,16 @@ struct Enemy : Item } } else { gSaveGame.kills++; + #ifdef HIDE_CORPSES + corpseTimer = HIDE_CORPSES; + #endif } if (type != ITEM_MUMMY) { fxBlood(point, 0, 0); } + + flags.injured = true; } virtual void collide(Lara* lara, CollisionInfo* cinfo) @@ -191,32 +623,55 @@ struct Enemy : Item flags.status = ITEM_FLAGS_STATUS_ACTIVE; } + #ifdef HIDE_CORPSES + if ((health <= 0) && !corpseTimer--) + { + deactivate(); + flags.status = ITEM_FLAGS_STATUS_INVISIBLE; + } + #endif + if (!extraE) return; updateTargetInfo(); - logic(); + if (health > 0) + { + updateMood(); + updateNavigation(); + } - extraE->rotHead = angleLerp(extraE->rotHead, tinfo.rotHead, ANGLE(5)); + goalState = updateState(); animProcess(); + updateLocation(); + + extraE->rotHead = angleLerp(extraE->rotHead, tinfo.rotHead, ANGLE(5)); + angle.z += X_CLAMP((tinfo.tilt << 2) - angle.z, -ANGLE(3), ANGLE(3)); + angle.y += tinfo.turn; + if (flags.status == ITEM_FLAGS_STATUS_INACTIVE) { flags.collision = false; health = NOT_ENEMY; disable(); + #ifndef HIDE_CORPSES deactivate(); - return; + #endif } + } - // TODO collision, pathfinding - - updateRoom(); + virtual int32 updateState() + { + return goalState; } - virtual void logic() {} + virtual void initExtra() + { + // empty + } }; @@ -229,7 +684,10 @@ struct Doppelganger : Enemy struct Wolf : Enemy { enum { - HIT_MASK = 0x774F, // body, head, front legs + HIT_MASK = 0x774F, // body, head, front legs + DIST_STALK = 1023 * 3, + DIST_BITE = 345, + DIST_ATTACK = 1024 + 512, }; enum { @@ -256,7 +714,9 @@ struct Wolf : Enemy Wolf(Room* room) : Enemy(room, 6, 341, 375, AGGRESSION_LVL_2) { - frameIndex = level.anims[animIndex].frameEnd; + #ifndef PROFILING + frameIndex = level.anims[animIndex].frameEnd - 1; + #endif } virtual void hit(int32 damage, const vec3i &point, int32 soundId) @@ -264,20 +724,124 @@ struct Wolf : Enemy Enemy::hit(damage, point, SND_HIT_WOLF); if (health <= 0) { - animSet(models[type].animIndex + ANIM_DEATH + (rand_logic() % 3), true); + animSet(level.models[type].animIndex + ANIM_DEATH + RAND_LOGIC(3), true); } } - virtual void logic() + virtual int32 updateState() { if (health <= 0) - return; + return goalState; + + switch (state) + { + case STATE_STOP: { + return (nextState != STATE_NONE) ? nextState : STATE_WALK; + } + case STATE_WALK: { + extraE->maxTurn = ENEMY_TURN_SLOW; + tinfo.tilt = tinfo.turn >> 1; + + if (mood != MOOD_SLEEP) { + nextState = STATE_NONE; + return STATE_STALK; + } + if (rand_logic() < 0x20) { + nextState = STATE_SLEEP; + return STATE_STOP; + } + break; + } + case STATE_RUN: { + extraE->maxTurn = ENEMY_TURN_FAST; + tinfo.tilt = tinfo.turn; - // TODO + if (tinfo.aim && tinfo.dist < DIST_ATTACK) + { + if (tinfo.dist <= (DIST_ATTACK >> 1)) + { + nextState = STATE_NONE; + return STATE_ATTACK; + } + nextState = STATE_STALK; + return STATE_GROWL; + } + if (mood == MOOD_STALK && tinfo.dist < DIST_STALK) + { + nextState = STATE_STALK; + return STATE_GROWL; + } + if (mood == MOOD_SLEEP) + return STATE_GROWL; + break; + } + case STATE_STALK: { + extraE->maxTurn = ENEMY_TURN_SLOW; + + if (mood == MOOD_ESCAPE) + return STATE_RUN; + if (tinfo.dist < DIST_BITE && tinfo.canAttack && (tinfo.target->health > 0)) + return STATE_BITE; + if (tinfo.dist > DIST_STALK) + return STATE_RUN; + if (mood == MOOD_ATTACK && (!tinfo.aim || tinfo.dist > DIST_ATTACK)) + return STATE_RUN; + if (rand_logic() < 0x180) + { + nextState = STATE_HOWL; + return STATE_GROWL; + } + if (mood == MOOD_SLEEP) + return STATE_GROWL; + break; + } + case STATE_SLEEP: { + if ((mood == MOOD_ESCAPE) || checkZone()) + nextState = STATE_GROWL; + else if (rand_logic() < 0x20) + nextState = STATE_WALK; + else + break; + return STATE_STOP; + } + case STATE_GROWL: { + if (nextState != STATE_NONE) + return nextState; + if (mood == MOOD_ESCAPE) + return STATE_RUN; + if (tinfo.dist < DIST_BITE && tinfo.canAttack && (tinfo.target->health > 0)) + return STATE_BITE; + if (mood == MOOD_STALK) + return STATE_STALK; + if (mood == MOOD_SLEEP) + return STATE_STOP; + return STATE_RUN; + } + case STATE_ATTACK: { + tinfo.tilt = tinfo.turn; - if (state == STATE_SLEEP) { - goalState = STATE_STOP; + if (nextState == STATE_NONE && (hitMask & HIT_MASK)) { + bite(6, _vec3i(0, -14, 174), 50); + nextState = STATE_RUN; + } + return STATE_RUN; + } + case STATE_BITE: { + if (nextState == STATE_NONE && (hitMask & HIT_MASK)) { + bite(6, _vec3i(0, -14, 174), 100); + nextState = STATE_GROWL; + } + return STATE_RUN; + } } + + return goalState; + } + + virtual void initExtra() + { + extraE->nav.stepHeight = 256; + extraE->nav.dropHeight = -1024; } }; @@ -289,47 +853,179 @@ struct Bear : Enemy }; enum { - STATE_WALK, - STATE_STOP, - STATE_HIND, - STATE_RUN, - STATE_STAND, - STATE_GROWL, - STATE_BITE, - STATE_ATTACK, - STATE_EAT, - STATE_DEATH, + STATE_NONE = 0, // WTF? + STATE_WALK = 0, + STATE_STOP , + STATE_HIND , + STATE_RUN , + STATE_HOWL , + STATE_GROWL , + STATE_BITE , + STATE_ATTACK , + STATE_EAT , + STATE_DEATH , }; - Bear(Room* room) : Enemy(room, 20, 341, 500, AGGRESSION_LVL_3) {} + Bear(Room* room) : Enemy(room, 20, 341, 500, AGGRESSION_LVL_3) + { + flags.animated = true; // TODO WILD flag + } virtual void hit(int32 damage, const vec3i &point, int32 soundId) { Enemy::hit(damage, point, SND_HIT_BEAR); } - virtual void logic() + virtual int32 updateState() { if (health <= 0) { switch (state) { case STATE_HIND: - goalState = STATE_STAND; - break; + return STATE_HOWL; case STATE_WALK: case STATE_RUN: - goalState = STATE_STOP; - break; + return STATE_STOP; case STATE_STOP: - case STATE_STAND: - goalState = STATE_DEATH; - break; + flags.reverse = 0; // TODO special flag + return STATE_DEATH; + case STATE_HOWL: + flags.reverse = 1; + return STATE_DEATH; + case STATE_DEATH: + if (flags.reverse && (hitMask & HIT_MASK) && tinfo.target) // fall on Lara + { + tinfo.target->hit(200, _vec3i(0, 0, 0), 0); + flags.reverse = false; + } + return STATE_DEATH; + default: + return goalState; } - return; } - // TODO + // hold the injured flag until death + if (flags.injured) { + flags.reverse = 1; + } else { + flags.injured = flags.reverse; + } + + switch (state) + { + case STATE_WALK: { + extraE->maxTurn = ENEMY_TURN_SLOW; + + if (tinfo.target->health <= 0 && tinfo.aim && (hitMask & HIT_MASK)) + return nextState = STATE_STOP; // eat lara! >:E + + if (mood != MOOD_SLEEP) + { + if (mood == MOOD_ESCAPE) { + nextState = STATE_NONE; + } + return STATE_STOP; + } + + if (rand_logic() < 0x50) + { + nextState = STATE_GROWL; + return STATE_STOP; + } + break; + } + case STATE_STOP: { + if (tinfo.target->health <= 0) + return (tinfo.canAttack && tinfo.dist < 768) ? STATE_EAT : STATE_WALK; + if (nextState != STATE_NONE) + return nextState; + return (mood == MOOD_SLEEP) ? STATE_WALK : STATE_RUN; + } + case STATE_HIND: { + if (flags.injured) { + nextState = STATE_NONE; + return STATE_HOWL; + } + if (tinfo.aim && (hitMask & HIT_MASK)) + return STATE_HOWL; + if (mood == MOOD_ESCAPE) { + nextState = STATE_NONE; + return STATE_HOWL; + } + if (mood == MOOD_SLEEP || rand_logic() < 0x50) { + nextState = STATE_GROWL; + return STATE_HOWL; + } + if (tinfo.dist > 2048 || rand_logic() < 0x600) { + nextState = STATE_STOP; + return STATE_HOWL; + } + return STATE_HOWL; + } + case STATE_RUN: { + extraE->maxTurn = ENEMY_TURN_FAST; + + if (hitMask & HIT_MASK) { + tinfo.target->hit(3, pos, 0); + if (health >= 0) { + nextState = STATE_NONE; + } + } + + if (tinfo.target->health <= 0 || mood == MOOD_SLEEP) + return STATE_STOP; + + if (tinfo.aim && nextState == STATE_NONE) + { + if (tinfo.dist < 2048) + { + if (!flags.injured && (rand_logic() < 0x300)) + { + nextState = STATE_HOWL; + return STATE_STOP; + } + if (tinfo.dist < 1024) + return STATE_BITE; + } + } + break; + } + case STATE_HOWL: { + if (flags.injured) + { + nextState = STATE_NONE; + return STATE_STOP; + } + + if (nextState != STATE_NONE) + return nextState; + + if (mood == MOOD_SLEEP || mood == MOOD_ESCAPE) + return STATE_STOP; + + if (tinfo.canAttack && tinfo.dist < 600) + return STATE_ATTACK; + + return STATE_HIND; + } + case STATE_BITE: { + if ((nextState == STATE_NONE) && (hitMask & HIT_MASK)) { + bite(14, _vec3i(0, 96, 335), 200); + nextState = STATE_STOP; + } + break; + } + case STATE_ATTACK: { + if ((nextState == STATE_NONE) && (hitMask & HIT_MASK) && tinfo.target) { + tinfo.target->hit(400, _vec3i(0, 0, 0), 0); + nextState = STATE_HOWL; + } + break; + } + } + + return goalState; } }; @@ -347,7 +1043,7 @@ struct Bat : Enemy Bat(Room* room) : Enemy(room, 1, 102, 0, AGGRESSION_LVL_1) {} - virtual void logic() + virtual int32 updateState() { if (health <= 0) { @@ -355,16 +1051,40 @@ struct Bat : Enemy flags.gravity = (pos.y < roomFloor); if (flags.gravity) { - goalState = STATE_CIRCLING; - } else { - goalState = STATE_DEATH; - pos.y = roomFloor; + return STATE_CIRCLING; } - return; + pos.y = roomFloor; + return STATE_DEATH; + } + + switch (state) + { + case STATE_AWAKE: + return STATE_FLY; + case STATE_FLY: + if (hitMask) { + return STATE_ATTACK; + } + break; + case STATE_ATTACK: + if (!hitMask) { + mood = MOOD_SLEEP; + return STATE_FLY; + } + bite(4, _vec3i(0, 16, 45), 2); + break; } - // TODO + return goalState; + } + + virtual void initExtra() + { + extraE->nav.stepHeight = 20 * 1024; + extraE->nav.dropHeight = -20 * 1024; + extraE->nav.vSpeed = 16; + extraE->maxTurn = ANGLE(20); } }; @@ -372,6 +1092,17 @@ struct Bat : Enemy struct Crocodile : Enemy { Crocodile(Room* room) : Enemy(room, 20, 341, 600, AGGRESSION_LVL_2) {} + + virtual void initExtra() + { + if (type == ITEM_CROCODILE_LAND) { + extraE->nav.stepHeight = 256; + extraE->nav.dropHeight = -256; + } else { + extraE->nav.stepHeight = 20 * 1024; + extraE->nav.dropHeight = -20 * 1024; + } + } }; @@ -391,12 +1122,24 @@ struct Lion : Enemy { Enemy::hit(damage, point, (type == ITEM_PUMA) ? 0 : SND_HIT_LION); } + + virtual void initExtra() + { + extraE->nav.stepHeight = 256; + extraE->nav.dropHeight = -1024; + } }; struct Gorilla : Enemy { Gorilla(Room* room) : Enemy(room, 22, 341, 250, AGGRESSION_LVL_MAX) {} + + virtual void initExtra() + { + extraE->nav.stepHeight = 512; + extraE->nav.dropHeight = -1024; + } }; diff --git a/src/platform/gba/game.h b/src/platform/gba/game.h index 769efdb0..e99b625c 100644 --- a/src/platform/gba/game.h +++ b/src/platform/gba/game.h @@ -3,24 +3,35 @@ #include "common.h" #include "sound.h" -#include "level.h" #include "room.h" #include "camera.h" #include "item.h" #include "draw.h" +#include "nav.h" +#include "level.h" struct Game { int32 animTexFrame; - void init() + void init(const char* name) { + renderInit(); + gSettings.controls.retarget = true; + startLevel(name); + } + + void startLevel(const char* name) + { set_seed_logic(osGetSystemTimeMS() * 3); set_seed_draw(osGetSystemTimeMS() * 7); animTexFrame = 0; + dynSectorsCount = 0; + + osLoadLevel(name); loadLevel(levelData); } @@ -31,12 +42,14 @@ struct Game memset(&gSaveGame, 0, sizeof(gSaveGame)); - Item::sFirstActive = NULL; - Item::sFirstFree = NULL; + ItemObj::sFirstActive = NULL; + ItemObj::sFirstFree = NULL; gCurTrack = -1; + #ifdef ROM_READ dynSectorsCount = 0; + #endif readLevel((uint8*)data); @@ -51,13 +64,13 @@ struct Game { items[i].nextItem = items + i + 1; } - Item::sFirstFree = items + level.itemsCount; + ItemObj::sFirstFree = items + level.itemsCount; // init items for (int32 i = 0; i < level.itemsCount; i++) { - const ItemInfo* info = level.itemsInfo + i; - Item* item = items + i; + const ItemObjInfo* info = level.itemsInfo + i; + ItemObj* item = items + i; item->type = info->type; item->intensity = uint8(info->intensity); @@ -66,70 +79,71 @@ struct Game item->pos.y = info->pos.y; item->pos.z = info->pos.z + (rooms[info->roomIndex].info->z << 8); - item->angle.y = (info->flags.angle - 2) * ANGLE_90; - item->flags.value = info->flags.value; + item->angle.y = ((info->params.value >> 14) - 2) * ANGLE_90; + item->flags = info->params.flags; + item->flags.reverse = 0; + item->flags.shadow = 0; - if (item->type == ITEM_LARA) { + if (item->type == ITEM_LARA || item->type == ITEM_CUT_1) { players[0] = (Lara*)item; } item->init(rooms + info->roomIndex); - - if (item->type == ITEM_LARA || item->type == ITEM_CUT_1) - { - ASSERT(item->extraL); - - players[0] = (Lara*)item; - players[0]->extraL->camera = &viewCameras[0]; - players[0]->extraL->camera->init(item); - - // gym - //resetLara(item, 13, vec3i(38953, 3328, 63961), ANGLE_90 + ANGLE_45); // pool - // level 1 - //resetLara(item, 0, vec3i(74588, 3072, 19673), ANGLE_0); // first darts - //resetLara(item, 9, vec3i(49669, 7680, 57891), ANGLE_0); // first door - //resetLara(item, 10, vec3i(43063, 7168, 61198), ANGLE_0); // transp - //resetLara(item, 14, vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // bridge - //resetLara(item, 17, vec3i(16475, 6656, 59845), ANGLE_90); // bear - //resetLara(item, 26, vec3i(24475, 6912, 83505), ANGLE_90); // switch timer 1 - //resetLara(item, 35, vec3i(35149, 2048, 74189), ANGLE_90); // switch timer 2 - // level 2 - //resetLara(item, 15, vec3i(66179, 0, 25920), -ANGLE_90 - ANGLE_45); // sprites - //resetLara(item, 19, vec3i(61018, 1024, 31214), ANGLE_180); // block - //resetLara(item, 14, vec3i(64026, 512, 20806), ANGLE_0); // key and puzzle - //resetLara(item, 5, vec3i(55644, 0, 29155), -ANGLE_90); // keyhole - //resetLara(item, 71, vec3i(12705, -768, 30195), -ANGLE_90); // puzzle - //resetLara(item, 63, vec3i(31055, -2048, 33406), ANGLE_0); // right room - //resetLara(item, 44, vec3i(27868, -1024, 29191), -ANGLE_90); // swing blades - // level 3a - //resetLara(item, 44, vec3i(73798, 2304, 9819), ANGLE_90); // uw gears - } } + // gym + //resetLara(0, 8, _vec3i(55994, 0, 52603), ANGLE_90); // piano + //resetLara(0, 13, _vec3i(38953, 3328, 63961), ANGLE_90 + ANGLE_45); // pool + // level 1 + //resetLara(0, 0, _vec3i(74588, 3072, 19673), ANGLE_0); // first darts + //resetLara(0, 9, _vec3i(49669, 7680, 57891), ANGLE_0); // first door + //resetLara(0, 10, _vec3i(43063, 7168, 61198), ANGLE_0); // transp + //resetLara(0, 14, _vec3i(20215, 6656, 52942), ANGLE_90 + ANGLE_45); // bridge + //resetLara(0, 17, _vec3i(16475, 6656, 59845), ANGLE_90); // bear + //resetLara(0, 26, _vec3i(24475, 6912, 83505), ANGLE_90); // switch timer 1 + //resetLara(0, 35, _vec3i(35149, 2048, 74189), ANGLE_90); // switch timer 2 + // level 2 + //resetLara(0, 15, _vec3i(66179, 0, 25920), -ANGLE_90 - ANGLE_45); // sprites + //resetLara(0, 19, _vec3i(61018, 1024, 31214), ANGLE_180); // block + //resetLara(0, 14, _vec3i(64026, 512, 20806), ANGLE_0); // key and puzzle + //resetLara(0, 5, _vec3i(55644, 0, 29155), -ANGLE_90); // keyhole + //resetLara(0, 71, _vec3i(12705, -768, 30195), -ANGLE_90); // puzzle + //resetLara(0, 63, _vec3i(31055, -2048, 33406), ANGLE_0); // right room + //resetLara(0, 44, _vec3i(27868, -1024, 29191), -ANGLE_90); // swing blades + // level 3a + //resetLara(0, 44, _vec3i(73798, 2304, 9819), ANGLE_90); // uw gears + drawInit(); + + #ifdef __3DO__ + //players[0]->angle.y += ANGLE_180; + //players[0]->pos.x += 1024; + #endif } - void resetLara(Item* lara, int32 roomIndex, const vec3i &pos, int32 angleY) + void resetLara(int32 index, int32 roomIndex, const vec3i &pos, int32 angleY) { + Lara* lara = players[index]; + lara->room->remove(lara); lara->pos = pos; lara->angle.y = angleY; lara->health = LARA_MAX_HEALTH; - lara->extraL->camera->target.pos = lara->pos; - lara->extraL->camera->target.room = lara->room; - lara->extraL->camera->view = lara->extraL->camera->target; + lara->extraL->camera.target.pos = lara->pos; + lara->extraL->camera.target.room = lara->room; + lara->extraL->camera.view = lara->extraL->camera.target; rooms[roomIndex].add(lara); } void updateItems() { - Item* item = Item::sFirstActive; + ItemObj* item = ItemObj::sFirstActive; while (item) { - Item* next = item->nextActive; + ItemObj* next = item->nextActive; item->update(); item = next; } @@ -168,10 +182,6 @@ struct Game } nextFrame(frames); - - if (keys & IK_SELECT) { - musicPlay(4); - } } void render() @@ -181,25 +191,33 @@ struct Game { PROFILE(CNT_RENDER); + setViewport(RectMinMax(0, 0, FRAME_WIDTH, FRAME_HEIGHT)); + clear(); for (int32 i = 0; i < MAX_PLAYERS; i++) { - gCamera = players[0]->extraL->camera; - ASSERT(gCamera); // TODO set viewports for coop #ifndef PROFILE_SOUNDTIME - drawRooms(); + drawRooms(&players[i]->extraL->camera); #endif } + drawText(0, FRAME_HEIGHT - 8, "! early alpha version !", TEXT_ALIGN_CENTER); + flush(); + drawNumber(fps, TEXT_POSX, 16); } #ifdef PROFILING for (int32 i = 0; i < CNT_MAX; i++) { + #ifdef __3DO__ + extern void drawInt(int32 x, int32 y, int32 c); + drawInt(FRAME_WIDTH - 8, 4 + 24 + 8 + 8 * i, gCounters[i]); + #else drawNumber(gCounters[i], TEXT_POSX, 32 + i * 16); + #endif } #endif diff --git a/src/platform/gba/inventory.h b/src/platform/gba/inventory.h index 3e7504f0..6647239d 100644 --- a/src/platform/gba/inventory.h +++ b/src/platform/gba/inventory.h @@ -278,14 +278,14 @@ struct Inventory } } - void show(Item* lara, Item* hole) + void show(ItemObj* lara, ItemObj* hole) { if (hole) { useSlot = remapHoleToSlot((ItemType)hole->type); } } - bool applyItem(Item* hole) + bool applyItem(ItemObj* hole) { #define CHECK_CASE(A, B) case A: { if (useSlot != B) return false; break; } diff --git a/src/platform/gba/item.h b/src/platform/gba/item.h index 10d296f4..d079cf3f 100644 --- a/src/platform/gba/item.h +++ b/src/platform/gba/item.h @@ -4,7 +4,6 @@ #include "common.h" #include "sound.h" #include "camera.h" -#include "draw.h" #include "room.h" int32 curItemIndex; @@ -31,6 +30,9 @@ int32 alignOffset(int32 a, int32 b) Mixer::Sample* soundPlay(int16 id, const vec3i &pos) { +#ifdef __3DO__ + return NULL; +#endif // TODO gym // 0 -> 200 // 4 -> 204 @@ -45,7 +47,7 @@ Mixer::Sample* soundPlay(int16 id, const vec3i &pos) if (b->chance && b->chance < rand_draw()) return NULL; - vec3i d = pos - viewCameras[0].target.pos; // TODO find nearest camera for coop + vec3i d = pos - playersExtra[0].camera.target.pos; // TODO find nearest camera for coop if (abs(d.x) >= SND_MAX_DIST || abs(d.y) >= SND_MAX_DIST || abs(d.z) >= SND_MAX_DIST) return NULL; @@ -108,6 +110,9 @@ void soundStop(int16 id) void musicPlay(int32 track) { +#ifdef __3DO__ + return; +#endif if (track == 13) { gCurTrack = 0; } @@ -133,13 +138,13 @@ void musicStop() mixer.stopMusic(); } -int32 Item::getFrames(const AnimFrame* &frameA, const AnimFrame* &frameB, int32 &animFrameRate) const +int32 ItemObj::getFrames(const AnimFrame* &frameA, const AnimFrame* &frameB, int32 &animFrameRate) const { const Anim* anim = level.anims + animIndex; animFrameRate = anim->frameRate; - int32 frameSize = (sizeof(AnimFrame) >> 1) + (models[type].count << 1); + int32 frameSize = (sizeof(AnimFrame) >> 1) + (level.models[type].count << 1); int32 frame = frameIndex - anim->frameBegin; @@ -169,7 +174,7 @@ int32 Item::getFrames(const AnimFrame* &frameA, const AnimFrame* &frameB, int32 return frameDelta; } -const AnimFrame* Item::getFrame() const +const AnimFrame* ItemObj::getFrame() const { const AnimFrame *frameA, *frameB; @@ -179,9 +184,9 @@ const AnimFrame* Item::getFrame() const return (frameDelta <= (frameRate >> 1)) ? frameA : frameB; } -Bounds tmpBox; +AABBs tmpBox; -const Bounds& Item::getBoundingBox(bool lerp) const +const AABBs& ItemObj::getBoundingBox(bool lerp) const { if (!lerp) return getFrame()->box; @@ -210,7 +215,7 @@ const Bounds& Item::getBoundingBox(bool lerp) const return tmpBox; } -void Item::move() +void ItemObj::move() { const Anim* anim = level.anims + animIndex; @@ -238,7 +243,7 @@ void Item::move() pos.z += phd_cos(realAngle) * hSpeed >> FIXED_SHIFT; } -const Anim* Item::animSet(int32 newAnimIndex, bool resetState, int32 frameOffset) +const Anim* ItemObj::animSet(int32 newAnimIndex, bool resetState, int32 frameOffset) { const Anim* anim = level.anims + newAnimIndex; @@ -252,9 +257,9 @@ const Anim* Item::animSet(int32 newAnimIndex, bool resetState, int32 frameOffset return anim; } -const Anim* Item::animChange(const Anim* anim) +const Anim* ItemObj::animChange(const Anim* anim) { - if (!anim->statesCount || goalState == state) + if (goalState == state || !anim->statesCount) return anim; const AnimState* animState = level.animStates + anim->statesStart; @@ -269,10 +274,6 @@ const Anim* Item::animChange(const Anim* anim) { if ((frameIndex >= animRange->frameBegin) && (frameIndex <= animRange->frameEnd)) { - if ((type != ITEM_LARA) && (nextState == animState->state)) { - nextState = 0; - } - frameIndex = animRange->nextFrameIndex; animIndex = animRange->nextAnimIndex; anim = level.anims + animRange->nextAnimIndex; @@ -288,7 +289,7 @@ const Anim* Item::animChange(const Anim* anim) return anim; } -void Item::animCmd(bool fx, const Anim* anim) +void ItemObj::animCmd(bool fx, const Anim* anim) { if (!anim->commandsCount) return; @@ -386,7 +387,7 @@ void Item::animCmd(bool fx, const Anim* anim) case FX_LARA_BUBBLES : { - fxBubbles(room, JOINT_HEAD, vec3i(0, 0, 50)); + fxBubbles(room, JOINT_HEAD, _vec3i(0, 0, 50)); break; } @@ -418,7 +419,7 @@ void Item::animCmd(bool fx, const Anim* anim) } } -void Item::animSkip(int32 stateBefore, int32 stateAfter, bool advance) +void ItemObj::animSkip(int32 stateBefore, int32 stateAfter, bool advance) { goalState = stateBefore; @@ -443,9 +444,9 @@ void Item::animSkip(int32 stateBefore, int32 stateAfter, bool advance) #define ANIM_MOVE_LERP_POS (16) #define ANIM_MOVE_LERP_ROT ANGLE(2) -void Item::animProcess(bool movement) +void ItemObj::animProcess(bool movement) { - ASSERT(models[type].count > 0); + ASSERT(level.models[type].count > 0); const Anim* anim = level.anims + animIndex; @@ -455,6 +456,10 @@ void Item::animProcess(bool movement) anim = animChange(anim); + if ((type != ITEM_LARA) && (nextState == state)) { + nextState = 0; + } + if (frameIndex > anim->frameEnd) { animCmd(false, anim); @@ -463,6 +468,14 @@ void Item::animProcess(bool movement) animIndex = anim->nextAnimIndex; anim = level.anims + anim->nextAnimIndex; state = uint8(anim->state); + + if (type != ITEM_LARA) + { + goalState = state; + if (nextState == state) { + nextState = 0; + } + } } animCmd(true, anim); @@ -474,21 +487,21 @@ void Item::animProcess(bool movement) #endif } -bool Item::animIsEnd(int32 offset) const +bool ItemObj::animIsEnd(int32 offset) const { return frameIndex == level.anims[animIndex].frameEnd - offset; } -void Item::animHit(int32 dirX, int32 dirZ, int32 hitTimer) +void ItemObj::animHit(int32 dirX, int32 dirZ, int32 hitTimer) { ASSERT(type == ITEM_LARA); ASSERT(extraL != NULL); - extraL->hitQuadrant = uint16(angle.y - phd_atan(dirZ, dirX) + ANGLE_180 + ANGLE_45) / ANGLE_90; + extraL->hitQuadrant = uint16(angle.y - phd_atan(dirZ, dirX) + ANGLE_180 + ANGLE_45) >> ANGLE_SHIFT_90; extraL->hitTimer = hitTimer; } -bool Item::moveTo(const vec3i &point, Item* item, bool lerp) +bool ItemObj::moveTo(const vec3i &point, ItemObj* item, bool lerp) { // lerp position vec3i p = item->getRelative(point); @@ -518,15 +531,15 @@ bool Item::moveTo(const vec3i &point, Item* item, bool lerp) return (pos == p && angle == item->angle); } -Item* Item::add(ItemType type, Room* room, const vec3i &pos, int32 angleY) +ItemObj* ItemObj::add(ItemType type, Room* room, const vec3i &pos, int32 angleY) { - if (!Item::sFirstFree) { + if (!ItemObj::sFirstFree) { ASSERT(false); return NULL; } - Item* item = Item::sFirstFree; - Item::sFirstFree = item->nextItem; + ItemObj* item = ItemObj::sFirstFree; + ItemObj::sFirstFree = item->nextItem; item->type = type; item->pos = pos; @@ -538,7 +551,7 @@ Item* Item::add(ItemType type, Room* room, const vec3i &pos, int32 angleY) return item; } -void Item::remove() +void ItemObj::remove() { deactivate(); room->remove(this); @@ -549,28 +562,28 @@ void Item::remove() if (playersExtra[i].armL.target == this) playersExtra[i].armL.target = NULL; } - nextItem = Item::sFirstFree; - Item::sFirstFree = this; + nextItem = ItemObj::sFirstFree; + ItemObj::sFirstFree = this; } -void Item::activate() +void ItemObj::activate() { - ASSERT(!flags.active) + //ASSERT(!flags.active) TODO check LEVEL3B flags.active = true; - nextActive = Item::sFirstActive; - Item::sFirstActive = this; + nextActive = ItemObj::sFirstActive; + ItemObj::sFirstActive = this; } -void Item::deactivate() +void ItemObj::deactivate() { - Item* prev = NULL; - Item* curr = Item::sFirstActive; + ItemObj* prev = NULL; + ItemObj* curr = ItemObj::sFirstActive; while (curr) { - Item* next = curr->nextActive; + ItemObj* next = curr->nextActive; if (curr == this) { @@ -580,7 +593,7 @@ void Item::deactivate() if (prev) { prev->nextActive = next; } else { - Item::sFirstActive = next; + ItemObj::sFirstActive = next; } break; @@ -591,12 +604,12 @@ void Item::deactivate() } } -void Item::hit(int32 damage, const vec3i &point, int32 soundId) +void ItemObj::hit(int32 damage, const vec3i &point, int32 soundId) { // } -void Item::fxBubbles(Room *fxRoom, int32 fxJoint, const vec3i &fxOffset) +void ItemObj::fxBubbles(Room *fxRoom, int32 fxJoint, const vec3i &fxOffset) { int32 count = rand_draw() % 3; @@ -607,28 +620,28 @@ void Item::fxBubbles(Room *fxRoom, int32 fxJoint, const vec3i &fxOffset) for (int32 i = 0; i < count; i++) { - Item::add(ITEM_BUBBLE, fxRoom, fxPos, 0); + ItemObj::add(ITEM_BUBBLE, fxRoom, fxPos, 0); } } -void Item::fxRicochet(Room *fxRoom, const vec3i &fxPos, bool fxSound) +void ItemObj::fxRicochet(Room *fxRoom, const vec3i &fxPos, bool fxSound) { - Item* ricochet = Item::add(ITEM_RICOCHET, fxRoom, fxPos, 0); + ItemObj* ricochet = ItemObj::add(ITEM_RICOCHET, fxRoom, fxPos, 0); if (!ricochet) return; ricochet->timer = 4; - ricochet->frameIndex = rand_draw() % (-models[ricochet->type].count); + ricochet->frameIndex = rand_draw() % (-level.models[ricochet->type].count); if (fxSound) { soundPlay(SND_RICOCHET, ricochet->pos); } } -void Item::fxBlood(const vec3i &fxPos, int16 fxAngleY, int16 fxSpeed) +void ItemObj::fxBlood(const vec3i &fxPos, int16 fxAngleY, int16 fxSpeed) { - Item* blood = Item::add(ITEM_BLOOD, room, fxPos, fxAngleY); + ItemObj* blood = ItemObj::add(ITEM_BLOOD, room, fxPos, fxAngleY); if (!blood) return; @@ -638,9 +651,9 @@ void Item::fxBlood(const vec3i &fxPos, int16 fxAngleY, int16 fxSpeed) blood->flags.animated = true; } -void Item::fxSmoke(const vec3i &fxPos) +void ItemObj::fxSmoke(const vec3i &fxPos) { - Item* smoke = Item::add(ITEM_SMOKE, room, fxPos, 0); + ItemObj* smoke = ItemObj::add(ITEM_SMOKE, room, fxPos, 0); if (!smoke) return; @@ -649,7 +662,7 @@ void Item::fxSmoke(const vec3i &fxPos) smoke->flags.animated = true; } -void Item::fxSplash() +void ItemObj::fxSplash() { vec3i fxPos = pos; fxPos.y = getWaterLevel(); @@ -657,7 +670,7 @@ void Item::fxSplash() // TODO TR3+ for (int32 i = 0; i < 10; i++) { - Item* splash = Item::add(ITEM_SPLASH, room, fxPos, int16(rand_draw() - ANGLE_90) << 1); + ItemObj* splash = ItemObj::add(ITEM_SPLASH, room, fxPos, int16(rand_draw() - ANGLE_90) << 1); if (!splash) return; @@ -667,7 +680,7 @@ void Item::fxSplash() } } -void Item::updateRoom(int32 offset) +void ItemObj::updateRoom(int32 offset) { Room* nextRoom = room->getRoom(pos.x, pos.y + offset, pos.z); @@ -681,7 +694,7 @@ void Item::updateRoom(int32 offset) roomFloor = sector->getFloor(pos.x, pos.y, pos.z); } -vec3i Item::getRelative(const vec3i &point) const +vec3i ItemObj::getRelative(const vec3i &point) const { matrixPush(); @@ -691,16 +704,16 @@ vec3i Item::getRelative(const vec3i &point) const matrixRotateYXZ(angle.x, angle.y, angle.z); vec3i p; - p.x = pos.x + (DP33(m[0], point) >> FIXED_SHIFT); - p.y = pos.y + (DP33(m[1], point) >> FIXED_SHIFT); - p.z = pos.z + (DP33(m[2], point) >> FIXED_SHIFT); + p.x = pos.x + (DP33(m.e00, m.e01, m.e02, point.x, point.y, point.z) >> FIXED_SHIFT); + p.y = pos.y + (DP33(m.e10, m.e11, m.e12, point.x, point.y, point.z) >> FIXED_SHIFT); + p.z = pos.z + (DP33(m.e20, m.e21, m.e22, point.x, point.y, point.z) >> FIXED_SHIFT); matrixPop(); return p; } -int32 Item::getWaterLevel() const +int32 ItemObj::getWaterLevel() const { const Sector* sector = room->getWaterSector(pos.x, pos.z); if (sector) { @@ -714,7 +727,7 @@ int32 Item::getWaterLevel() const return WALL; } -int32 Item::getWaterDepth() const +int32 ItemObj::getWaterDepth() const { const Sector* sector = room->getWaterSector(pos.x, pos.z); @@ -724,7 +737,7 @@ int32 Item::getWaterDepth() const return WALL; } -int32 Item::getBridgeFloor(int32 x, int32 z) const +int32 ItemObj::getBridgeFloor(int32 x, int32 z) const { if (type == ITEM_BRIDGE_FLAT) return pos.y; @@ -745,7 +758,7 @@ int32 Item::getBridgeFloor(int32 x, int32 z) const return pos.y + ((type == ITEM_BRIDGE_TILT_1) ? (h >> 2) : (h >> 1)); } -int32 Item::getTrapDoorFloor(int32 x, int32 z) const +int32 ItemObj::getTrapDoorFloor(int32 x, int32 z) const { int32 dx = (pos.x >> 10) - (x >> 10); int32 dz = (pos.z >> 10) - (z >> 10); @@ -762,7 +775,7 @@ int32 Item::getTrapDoorFloor(int32 x, int32 z) const return WALL; } -int32 Item::getDrawBridgeFloor(int32 x, int32 z) const +int32 ItemObj::getDrawBridgeFloor(int32 x, int32 z) const { int32 dx = (pos.x >> 10) - (x >> 10); int32 dz = (pos.z >> 10) - (z >> 10); @@ -778,7 +791,7 @@ int32 Item::getDrawBridgeFloor(int32 x, int32 z) const return WALL; } -void Item::getItemFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int32* ceiling) const +void ItemObj::getItemFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int32* ceiling) const { int32 h = WALL; @@ -832,19 +845,21 @@ void Item::getItemFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int32* c } } -vec3i Item::getJoint(int32 jointIndex, const vec3i &offset) const +vec3i ItemObj::getJoint(int32 jointIndex, const vec3i &offset) const { - const Model* model = models + type; + const Model* model = level.models + type; const AnimFrame* frame = getFrame(); const uint32* frameAngles = (uint32*)(frame->angles + 1); + int32 oldStackIndex = matrixStackIndex; + matrixPush(); matrixSetIdentity(); matrixRotateYXZ(angle.x, angle.y, angle.z); - const Node* node = level.nodes + model->nodeIndex; + const ModelNode* node = level.nodes + model->nodeIndex; matrixFrame(frame->pos, frameAngles); @@ -865,21 +880,21 @@ vec3i Item::getJoint(int32 jointIndex, const vec3i &offset) const matrixTranslate(offset.x, offset.y, offset.z); Matrix &m = matrixGet(); - vec3i result = vec3i(m[0].w >> FIXED_SHIFT, m[1].w >> FIXED_SHIFT, m[2].w >> FIXED_SHIFT); + vec3i result = _vec3i(m.e03 >> FIXED_SHIFT, m.e13 >> FIXED_SHIFT, m.e23 >> FIXED_SHIFT); - matrixPop(); + matrixStackIndex = oldStackIndex; return result; } -int32 Item::getSpheres(Sphere* spheres, bool flag) const +int32 ItemObj::getSpheres(Sphere* spheres, bool flag) const { - const Model* model = models + type; + const Model* model = level.models + type; const AnimFrame* frame = getFrame(); const uint32* frameAngles = (uint32*)(frame->angles + 1); - const Mesh** meshPtr = meshes + model->start; + const Mesh** meshPtr = level.meshes + model->start; int32 x, y, z; @@ -897,7 +912,7 @@ int32 Item::getSpheres(Sphere* spheres, bool flag) const matrixRotateYXZ(angle.x, angle.y, angle.z); - const Node* node = level.nodes + model->nodeIndex; + const ModelNode* node = level.nodes + model->nodeIndex; matrixFrame(frame->pos, frameAngles); @@ -908,9 +923,9 @@ int32 Item::getSpheres(Sphere* spheres, bool flag) const const Mesh* mesh = *meshPtr; matrixTranslate(mesh->center.x, mesh->center.y, mesh->center.z); Matrix &m = matrixGet(); - sphere->center.x = x + (m[0].w >> FIXED_SHIFT); - sphere->center.y = y + (m[1].w >> FIXED_SHIFT); - sphere->center.z = z + (m[2].w >> FIXED_SHIFT); + sphere->center.x = x + (m.e03 >> FIXED_SHIFT); + sphere->center.y = y + (m.e13 >> FIXED_SHIFT); + sphere->center.z = z + (m.e23 >> FIXED_SHIFT); sphere->radius = mesh->radius; sphere++; meshPtr++; @@ -931,9 +946,9 @@ int32 Item::getSpheres(Sphere* spheres, bool flag) const const Mesh* mesh = *meshPtr; matrixTranslate(mesh->center.x, mesh->center.y, mesh->center.z); Matrix &m = matrixGet(); - sphere->center.x = x + (m[0].w >> FIXED_SHIFT); - sphere->center.y = y + (m[1].w >> FIXED_SHIFT); - sphere->center.z = z + (m[2].w >> FIXED_SHIFT); + sphere->center.x = x + (m.e03 >> FIXED_SHIFT); + sphere->center.y = y + (m.e13 >> FIXED_SHIFT); + sphere->center.z = z + (m.e23 >> FIXED_SHIFT); sphere->radius = mesh->radius; sphere++; meshPtr++; @@ -952,7 +967,7 @@ int32 Item::getSpheres(Sphere* spheres, bool flag) const #include "enemy.h" #include "object.h" -Item::Item(Room* room) +ItemObj::ItemObj(Room* room) { angle.x = 0; angle.z = 0; @@ -960,7 +975,7 @@ Item::Item(Room* room) hSpeed = 0; nextItem = NULL; nextActive = NULL; - animIndex = models[type].animIndex; + animIndex = level.models[type].animIndex; // ctor called on existing memory, type is already initialized frameIndex = level.anims[animIndex].frameBegin; state = uint8(level.anims[animIndex].state); nextState = state; @@ -999,23 +1014,27 @@ Item::Item(Room* room) room->add(this); } -void Item::update() +void ItemObj::update() { // } -void Item::draw() +void ItemObj::draw() { drawItem(this); } -void Item::collide(Lara* lara, CollisionInfo* cinfo) +void ItemObj::collide(Lara* lara, CollisionInfo* cinfo) { // empty } -uint32 Item::collideSpheres(Lara* lara) const +uint32 ItemObj::collideSpheres(Lara* lara) const { +#ifdef __3DO__ // TODO_3DO damn slow! + return 0xFFFFFFFF; +#endif + Sphere a[MAX_SPHERES]; Sphere b[MAX_SPHERES]; @@ -1047,10 +1066,10 @@ uint32 Item::collideSpheres(Lara* lara) const return mask; } -bool Item::collideBounds(Lara* lara, CollisionInfo* cinfo) const +bool ItemObj::collideBounds(Lara* lara, CollisionInfo* cinfo) const { - const Bounds &a = getBoundingBox(false); - const Bounds &b = lara->getBoundingBox(false); + const AABBs &a = getBoundingBox(false); + const AABBs &b = lara->getBoundingBox(false); int32 dy = lara->pos.y - pos.y; @@ -1075,7 +1094,7 @@ bool Item::collideBounds(Lara* lara, CollisionInfo* cinfo) const (pz <= a.maxZ + r); } -void Item::collidePush(Lara* lara, CollisionInfo* cinfo, bool enemyHit) const +void ItemObj::collidePush(Lara* lara, CollisionInfo* cinfo, bool enemyHit) const { int32 dx = lara->pos.x - pos.x; int32 dz = lara->pos.z - pos.z; @@ -1086,7 +1105,7 @@ void Item::collidePush(Lara* lara, CollisionInfo* cinfo, bool enemyHit) const int32 px = X_ROTX(dx, dz, s, c); int32 pz = X_ROTY(dx, dz, s, c); - const Bounds &box = getBoundingBox(false); + const AABBs &box = getBoundingBox(false); int32 minX = box.minX - cinfo->radius; int32 maxX = box.maxX + cinfo->radius; int32 minZ = box.minZ - cinfo->radius; @@ -1095,7 +1114,7 @@ void Item::collidePush(Lara* lara, CollisionInfo* cinfo, bool enemyHit) const if ((px < minX) || (px > maxX) || (pz < minZ) || (pz > maxZ)) return; - enemyHit &= cinfo->enemyHit && (box.maxY - box.minY) > 256; + enemyHit = enemyHit && cinfo->enemyHit && ((box.maxY - box.minY) > 256); int32 ax = px - minX; int32 bx = maxX - px; @@ -1147,10 +1166,10 @@ void Item::collidePush(Lara* lara, CollisionInfo* cinfo, bool enemyHit) const } } -void Item::collideRoom(int32 height, int32 yOffset) const +void ItemObj::collideRoom(int32 height, int32 yOffset) const { cinfo.type = CT_NONE; - cinfo.offset = vec3i(0, 0, 0); + cinfo.offset = _vec3i(0, 0, 0); vec3i p = pos; p.y += yOffset; @@ -1176,8 +1195,8 @@ void Item::collideRoom(int32 height, int32 yOffset) const CHECK_HEIGHT(p); cinfo.trigger = gLastFloorData; - cinfo.slantX = gLastFloorSlant.slantX; - cinfo.slantZ = gLastFloorSlant.slantZ; + cinfo.slantX = FD_SLANT_X(gLastFloorSlant); + cinfo.slantZ = FD_SLANT_Z(gLastFloorSlant); cinfo.setSide(CollisionInfo::ST_MIDDLE, floor, ceiling); @@ -1186,27 +1205,27 @@ void Item::collideRoom(int32 height, int32 yOffset) const switch (cinfo.quadrant) { case 0 : { - f = vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, R); - l = vec3i(-R, 0, R); - r = vec3i( R, 0, R); + f = _vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, R); + l = _vec3i(-R, 0, R); + r = _vec3i( R, 0, R); break; } case 1 : { - f = vec3i( R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT); - l = vec3i( R, 0, R); - r = vec3i( R, 0, -R); + f = _vec3i( R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT); + l = _vec3i( R, 0, R); + r = _vec3i( R, 0, -R); break; } case 2 : { - f = vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, -R); - l = vec3i( R, 0, -R); - r = vec3i(-R, 0, -R); + f = _vec3i((R * phd_sin(cinfo.angle)) >> FIXED_SHIFT, 0, -R); + l = _vec3i( R, 0, -R); + r = _vec3i(-R, 0, -R); break; } case 3 : { - f = vec3i(-R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT); - l = vec3i(-R, 0, -R); - r = vec3i(-R, 0, R); + f = _vec3i(-R, 0, (R * phd_cos(cinfo.angle)) >> FIXED_SHIFT); + l = _vec3i(-R, 0, -R); + r = _vec3i(-R, 0, R); break; } default : { @@ -1313,7 +1332,7 @@ void Item::collideRoom(int32 height, int32 yOffset) const } } -uint32 Item::updateHitMask(Lara* lara, CollisionInfo* cinfo) +uint32 ItemObj::updateHitMask(Lara* lara, CollisionInfo* cinfo) { hitMask = 0; @@ -1325,7 +1344,7 @@ uint32 Item::updateHitMask(Lara* lara, CollisionInfo* cinfo) return hitMask; } -Item* Item::init(Room* room) +ItemObj* ItemObj::init(Room* room) { #define INIT_ITEM(type, className) case ITEM_##type : return new (this) className(room) @@ -1379,8 +1398,8 @@ Item* Item::init(Room* room) INIT_ITEM( BLOCK_3 , Block ); INIT_ITEM( BLOCK_4 , Block ); // INIT_ITEM( MOVING_BLOCK , ??? ); - // INIT_ITEM( TRAP_CEILING_1 , ??? ); - // INIT_ITEM( TRAP_CEILING_2 , ??? ); + // INIT_ITEM( TRAP_CEILING , ??? ); + // INIT_ITEM( TRAP_FLOOR_LOD , ??? ); INIT_ITEM( SWITCH , Switch ); INIT_ITEM( SWITCH_WATER , SwitchWater ); INIT_ITEM( DOOR_1 , Door ); @@ -1393,7 +1412,7 @@ Item* Item::init(Room* room) INIT_ITEM( DOOR_8 , Door ); INIT_ITEM( TRAP_DOOR_1 , TrapDoor ); INIT_ITEM( TRAP_DOOR_2 , TrapDoor ); - // INIT_ITEM( UNUSED_3 , ??? ); + // INIT_ITEM( TRAP_DOOR_LOD , ??? ); // INIT_ITEM( BRIDGE_FLAT , ??? ); // INIT_ITEM( BRIDGE_TILT_1 , ??? ); // INIT_ITEM( BRIDGE_TILT_2 , ??? ); @@ -1519,7 +1538,7 @@ Item* Item::init(Room* room) // INIT_ITEM( GLYPHS , ??? ); } - return new (this) Item(room); + return new (this) ItemObj(room); } #endif diff --git a/src/platform/gba/lara.h b/src/platform/gba/lara.h index a34d0b7e..5810f646 100644 --- a/src/platform/gba/lara.h +++ b/src/platform/gba/lara.h @@ -223,7 +223,7 @@ const WeaponParams weaponParams[WEAPON_MAX] = { }, }; -struct Lara : Item +struct Lara : ItemObj { enum State { LARA_STATES(DECL_ENUM) @@ -354,7 +354,7 @@ struct Lara : Item Room** adjRoom = room->getAdjRooms(); while (*adjRoom) { - Item* item = (*adjRoom++)->firstItem; + ItemObj* item = (*adjRoom++)->firstItem; while (item) { @@ -608,12 +608,12 @@ struct Lara : Item bool s_checkLook() { if (input & IN_LOOK) { - gCamera->mode = CAMERA_MODE_LOOK; + extraL->camera.mode = CAMERA_MODE_LOOK; return true; } - - if (gCamera->mode == CAMERA_MODE_LOOK) { - gCamera->mode = CAMERA_MODE_FOLLOW; + + if (extraL->camera.mode == CAMERA_MODE_LOOK) { + extraL->camera.mode = CAMERA_MODE_FOLLOW; } return false; @@ -800,7 +800,7 @@ struct Lara : Item S_HANDLER( STATE_HANG ) { - gCamera->targetAngleX = ANGLE(-60); + extraL->camera.targetAngle.x = ANGLE(-60); s_ignoreEnemy(); if (input & IN_LEFT) { @@ -812,7 +812,7 @@ struct Lara : Item S_HANDLER( STATE_REACH ) { - gCamera->targetAngleY = ANGLE(85); + extraL->camera.targetAngle.y = ANGLE(85); s_checkFall(); } @@ -968,7 +968,7 @@ struct Lara : Item S_HANDLER( STATE_SLIDE ) { - gCamera->targetAngleX = ANGLE(-45); + extraL->camera.targetAngle.x = ANGLE(-45); if (input & IN_JUMP) { goalState = STATE_JUMP; @@ -977,7 +977,7 @@ struct Lara : Item S_HANDLER( STATE_JUMP_BACK ) { - gCamera->targetAngleY = ANGLE(135); + extraL->camera.targetAngle.y = ANGLE(135); if (s_checkFall()) return; @@ -1013,7 +1013,7 @@ struct Lara : Item S_HANDLER( STATE_HANG_LEFT ) { - gCamera->targetAngleX = ANGLE(-60); + extraL->camera.targetAngle.x = ANGLE(-60); s_ignoreEnemy(); @@ -1024,7 +1024,7 @@ struct Lara : Item S_HANDLER( STATE_HANG_RIGHT ) { - gCamera->targetAngleX = ANGLE(-60); + extraL->camera.targetAngle.x = ANGLE(-60); s_ignoreEnemy(); @@ -1105,25 +1105,25 @@ struct Lara : Item S_HANDLER( STATE_BLOCK_PUSH ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(35); - gCamera->center = true; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(35); + extraL->camera.center = true; s_ignoreEnemy(); } S_HANDLER( STATE_BLOCK_PULL ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(35); - gCamera->center = true; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(35); + extraL->camera.center = true; s_ignoreEnemy(); } S_HANDLER( STATE_BLOCK_READY ) { - gCamera->targetAngleY = ANGLE(75); + extraL->camera.targetAngle.y = ANGLE(75); s_ignoreEnemy(); @@ -1134,45 +1134,45 @@ struct Lara : Item S_HANDLER( STATE_PICKUP ) { - gCamera->targetAngleX = ANGLE(-15); - gCamera->targetAngleY = ANGLE(-130); - gCamera->targetDist = 1024; + extraL->camera.targetAngle.x = ANGLE(-15); + extraL->camera.targetAngle.y = ANGLE(-130); + extraL->camera.targetDist = 1024; s_ignoreEnemy(); } S_HANDLER( STATE_SWITCH_DOWN ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(80); - gCamera->targetDist = 1024; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(80); + extraL->camera.targetDist = 1024; s_ignoreEnemy(); } S_HANDLER( STATE_SWITCH_UP ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(80); - gCamera->targetDist = 1024; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(80); + extraL->camera.targetDist = 1024; s_ignoreEnemy(); } S_HANDLER( STATE_USE_KEY ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(-80); - gCamera->targetDist = 1024; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(-80); + extraL->camera.targetDist = 1024; s_ignoreEnemy(); } S_HANDLER( STATE_USE_PUZZLE ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(-80); - gCamera->targetDist = 1024; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(-80); + extraL->camera.targetDist = 1024; s_ignoreEnemy(); } @@ -1190,9 +1190,9 @@ struct Lara : Item S_HANDLER( STATE_SPECIAL ) { - gCamera->targetAngleX = ANGLE(-25); - gCamera->targetAngleY = ANGLE(170); - gCamera->center = true; + extraL->camera.targetAngle.x = ANGLE(-25); + extraL->camera.targetAngle.y = ANGLE(170); + extraL->camera.center = true; } S_HANDLER( STATE_SURF_BACK ) @@ -1279,7 +1279,7 @@ struct Lara : Item S_HANDLER( STATE_WATER_OUT ) { s_ignoreEnemy(); - gCamera->center = true; + extraL->camera.center = true; } S_HANDLER( STATE_CLIMB_START ) {} @@ -1303,7 +1303,7 @@ struct Lara : Item void c_applyOffset() { pos += cinfo.offset; - cinfo.offset = vec3i(0, 0, 0); + cinfo.offset = _vec3i(0, 0, 0); } void c_angle(int16 angleDelta) @@ -2660,7 +2660,7 @@ struct Lara : Item C_HANDLER( STATE_UNUSED_4 ) {} C_HANDLER( STATE_ZIPLINE ) {} - Lara(Room* room) : Item(room) + Lara(Room* room) : ItemObj(room) { int32 playerIndex = -1; @@ -2680,10 +2680,11 @@ struct Lara : Item extraL->weapon = extraL->goalWeapon = WEAPON_PISTOLS; // TODO LEVEL10A setWeaponState(WEAPON_STATE_FREE); - meshSwap(ITEM_LARA, 0xFFFFFFFF); - bool isHome = false; + //#ifndef PROFILING + extern int32 gLevelID; + bool isHome = gLevelID == 0; if (isHome) { meshSwap(ITEM_LARA_SPEC, JOINT_MASK_UPPER | JOINT_MASK_LOWER); @@ -2704,11 +2705,14 @@ struct Lara : Item //extraL->weapon = extraL->goalWeapon = WEAPON_SHOTGUN; } + animSet(ANIM_STAND, true, 0); + //#endif + health = LARA_MAX_HEALTH; oxygen = LARA_MAX_OXYGEN; flags.shadow = true; - animSet(ANIM_STAND, true, 0); + extraL->camera.init(this); } // update control @@ -2716,7 +2720,7 @@ struct Lara : Item { input = 0; - if (gCamera->mode == CAMERA_MODE_FREE) + if (extraL->camera.mode == CAMERA_MODE_FREE) return; if (keys & IK_LEFT) input |= IN_LEFT; @@ -2724,10 +2728,22 @@ struct Lara : Item if (keys & IK_UP) input |= IN_UP; if (keys & IK_DOWN) input |= IN_DOWN; + #ifdef __3DO__ + if (keys & IK_A) input |= IN_JUMP; + if (keys & IK_B) input |= IN_ACTION; + if (keys & IK_C) input |= IN_WEAPON; + + if ((keys & (IK_L | IK_R)) == (IK_L | IK_R)) { + input |= IN_UP | IN_DOWN; + } else { + if (keys & IK_L) input |= IN_LOOK; + if (keys & IK_R) input |= IN_WALK; + } + #else if (keys & IK_A) { if (keys & IK_L) { - if (extraL->weaponState != WEAPON_STATE_BUSY && extraL->ammo[WEAPON_PISTOLS] != 0) { + if (extraL->weaponState != WEAPON_STATE_BUSY) { input |= IN_WEAPON; } else { input |= IN_ACTION; @@ -2754,6 +2770,25 @@ struct Lara : Item input |= IN_WALK; } } + + if (keys & IK_SELECT) + { + int32 gamma = gSaveGame.gamma; + + if (keys & IK_R) { + gamma += 16; + } + + if (keys & IK_L) { + gamma -= 16; + } + + gamma = X_CLAMP(gamma, 0, 256); + if (gamma != gSaveGame.gamma) { + setGamma(gSaveGame.gamma = gamma); + } + } + #endif } void updateLook() @@ -2764,7 +2799,7 @@ struct Lara : Item vec3s &T = extraL->torso.angle; if (health <= 0) { - H = T = vec3s(0, 0, 0); + H = T = _vec3s(0, 0, 0); return; } @@ -2790,9 +2825,9 @@ struct Lara : Item return; } - if ((input & IN_LOOK) && gCamera->mode != CAMERA_MODE_FIXED) + if ((input & IN_LOOK) && extraL->camera.mode != CAMERA_MODE_FIXED) { - gCamera->lookAtItem = NULL; + extraL->camera.lookAtItem = NULL; if (input & IN_UP) { H.x -= LARA_LOOK_TURN_SPEED; @@ -2817,7 +2852,7 @@ struct Lara : Item return; } - if (gCamera->lastItem != NULL) + if (extraL->camera.lastItem != NULL) return; H.x = T.x = angleDec(H.x, abs(H.x) >> 3); @@ -2845,7 +2880,7 @@ struct Lara : Item int32 waterDepth = getWaterDepth(); if (waterDepth > LARA_WADE_MAX_DEPTH - 256) { - if (!room->info->flags.water) // go dive + if (!ROOM_FLAG_WATER(room->info->flags)) // go dive break; waterState = WATER_STATE_UNDER; @@ -2889,7 +2924,7 @@ struct Lara : Item case WATER_STATE_SURFACE: { - if (room->info->flags.water) + if (ROOM_FLAG_WATER(room->info->flags)) break; if (waterDist > LARA_WADE_MIN_DEPTH) { @@ -2911,7 +2946,7 @@ struct Lara : Item case WATER_STATE_UNDER: { - if (room->info->flags.water || flags.dozy) + if (ROOM_FLAG_WATER(room->info->flags) || extraL->dozy) break; if ((getWaterDepth() != WALL) && abs(waterDist) < 256) { @@ -3004,7 +3039,7 @@ struct Lara : Item pos.x += (phd_sin(extraL->moveAngle) * vSpeed) >> 16; pos.z += (phd_cos(extraL->moveAngle) * vSpeed) >> 16; - gCamera->targetAngleX = ANGLE(-22); + extraL->camera.targetAngle.x = ANGLE(-22); } void updateUnder() @@ -3092,7 +3127,7 @@ struct Lara : Item if (s.center.z <= s.radius) continue; - if (X_SQR(s.center.x) + X_SQR(s.center.y) > X_SQR(s.radius)) + if (fastLength(s.center.x, s.center.y) > s.radius) continue; int32 dist = s.center.z - s.radius; @@ -3141,7 +3176,7 @@ struct Lara : Item { const WeaponParams ¶ms = weaponParams[extraL->weapon]; int32 anim = (extraL->weapon == WEAPON_SHOTGUN) ? ANIM_SHOTGUN_DRAW : ANIM_PISTOLS_PICK; - R.animIndex = L.animIndex = models[params.animType].animIndex + anim; + R.animIndex = L.animIndex = level.models[params.animType].animIndex + anim; R.frameIndex = L.frameIndex = 0; } @@ -3178,7 +3213,7 @@ struct Lara : Item const Anim* animPtr = level.anims + arm->animIndex; int32 animLength = animPtr->frameEnd - animPtr->frameBegin; int32 frame = arm->frameIndex + 1; - int32 anim = arm->animIndex - models[params.animType].animIndex; + int32 anim = arm->animIndex - level.models[params.animType].animIndex; if (frame > animLength) { @@ -3195,8 +3230,8 @@ struct Lara : Item frame = 0; } - extraL->armR.angle = extraL->armL.angle = vec3s(0, 0, 0); - extraL->armR.animIndex = extraL->armL.animIndex = anim + models[params.animType].animIndex; + extraL->armR.angle = extraL->armL.angle = _vec3s(0, 0, 0); + extraL->armR.animIndex = extraL->armL.animIndex = anim + level.models[params.animType].animIndex; extraL->armR.frameIndex = extraL->armL.frameIndex = frame; } @@ -3212,7 +3247,7 @@ struct Lara : Item continue; int32 frame = arm->frameIndex; - int32 anim = arm->animIndex - models[params.animType].animIndex; + int32 anim = arm->animIndex - level.models[params.animType].animIndex; if (frame) { @@ -3244,7 +3279,7 @@ struct Lara : Item anim = ANIM_PISTOLS_AIM; } - arm->animIndex = anim + models[params.animType].animIndex; + arm->animIndex = anim + level.models[params.animType].animIndex; frame = level.anims[arm->animIndex].frameEnd - level.anims[arm->animIndex].frameBegin; } @@ -3265,7 +3300,7 @@ struct Lara : Item const Anim* animPtr = level.anims + arm.animIndex; int32 animLength = animPtr->frameEnd - animPtr->frameBegin; int32 frame = arm.frameIndex + 1; - int32 anim = arm.animIndex - models[params.animType].animIndex; + int32 anim = arm.animIndex - level.models[params.animType].animIndex; ASSERT(anim == ANIM_SHOTGUN_DRAW); @@ -3278,8 +3313,8 @@ struct Lara : Item setWeaponState(WEAPON_STATE_READY); } - extraL->armR.angle = extraL->armL.angle = vec3s(0, 0, 0); - extraL->armR.animIndex = extraL->armL.animIndex = anim + models[params.animType].animIndex; + extraL->armR.angle = extraL->armL.angle = _vec3s(0, 0, 0); + extraL->armR.animIndex = extraL->armL.animIndex = anim + level.models[params.animType].animIndex; extraL->armR.frameIndex = extraL->armL.frameIndex = frame; } @@ -3290,12 +3325,12 @@ struct Lara : Item ExtraInfoLara::Arm &arm = extraL->armR; int32 frame = arm.frameIndex; - int32 anim = arm.animIndex - models[params.animType].animIndex; + int32 anim = arm.animIndex - level.models[params.animType].animIndex; if (anim == ANIM_SHOTGUN_AIM) { if (frame == 0) { anim = ANIM_SHOTGUN_DRAW; - const Anim* animPtr = level.anims + models[params.animType].animIndex + anim; + const Anim* animPtr = level.anims + level.models[params.animType].animIndex + anim; frame = animPtr->frameEnd - animPtr->frameBegin; } else { frame--; @@ -3304,7 +3339,7 @@ struct Lara : Item frame++; if (frame > 12) { anim = ANIM_SHOTGUN_DRAW; - const Anim* animPtr = level.anims + models[params.animType].animIndex + anim; + const Anim* animPtr = level.anims + level.models[params.animType].animIndex + anim; frame = animPtr->frameEnd - animPtr->frameBegin; } } else if (anim == ANIM_SHOTGUN_DRAW) { @@ -3320,8 +3355,8 @@ struct Lara : Item } } - extraL->armR.angle = extraL->armL.angle = vec3s(0, 0, 0); - extraL->armR.animIndex = extraL->armL.animIndex = anim + models[params.animType].animIndex; + extraL->armR.angle = extraL->armL.angle = _vec3s(0, 0, 0); + extraL->armR.animIndex = extraL->armL.animIndex = anim + level.models[params.animType].animIndex; extraL->armR.frameIndex = extraL->armL.frameIndex = frame; } @@ -3376,7 +3411,7 @@ struct Lara : Item const Anim* animPtr = level.anims + arm->animIndex; int32 animLength = animPtr->frameEnd - animPtr->frameBegin; int32 frame = arm->frameIndex; - int32 anim = arm->animIndex - models[params.animType].animIndex; + int32 anim = arm->animIndex - level.models[params.animType].animIndex; if (((input & IN_ACTION) && !arm->target) || arm->aim) { @@ -3402,7 +3437,7 @@ struct Lara : Item if (frame == params.reloadTimer) { anim = ANIM_PISTOLS_AIM; - const Anim* animPtr = level.anims + anim + models[params.animType].animIndex; + const Anim* animPtr = level.anims + anim + level.models[params.animType].animIndex; frame = animPtr->frameEnd - animPtr->frameBegin; } } @@ -3410,14 +3445,14 @@ struct Lara : Item if (anim == ANIM_PISTOLS_FIRE) { anim = ANIM_PISTOLS_AIM; - const Anim* animPtr = level.anims + anim + models[params.animType].animIndex; + const Anim* animPtr = level.anims + anim + level.models[params.animType].animIndex; frame = animPtr->frameEnd - animPtr->frameBegin; } else if (frame) { frame--; }; } - arm->animIndex = anim + models[params.animType].animIndex; + arm->animIndex = anim + level.models[params.animType].animIndex; arm->frameIndex = frame; arm->useBasis = (anim == ANIM_PISTOLS_AIM && frame) || (anim == ANIM_PISTOLS_FIRE); } @@ -3437,7 +3472,7 @@ struct Lara : Item const Anim* animPtr = level.anims + arm->animIndex; int32 animLength = animPtr->frameEnd - animPtr->frameBegin; int32 frame = arm->frameIndex; - int32 anim = arm->animIndex - models[params.animType].animIndex; + int32 anim = arm->animIndex - level.models[params.animType].animIndex; bool aim = ((input & IN_ACTION) && !arm->target) || arm->aim; @@ -3450,12 +3485,12 @@ struct Lara : Item soundPlay(SND_SHOTGUN_RELOAD, pos); } else if (frame == params.reloadTimer) { anim = ANIM_SHOTGUN_AIM; - animPtr = level.anims + models[params.animType].animIndex + anim; + animPtr = level.anims + level.models[params.animType].animIndex + anim; frame = animPtr->frameEnd - animPtr->frameBegin; } else if ((animLength - frame < 10) && !aim) { anim = ANIM_SHOTGUN_AIM; frame = animLength - frame; // how many frames left for fire animation - animPtr = level.anims + models[params.animType].animIndex + anim; + animPtr = level.anims + level.models[params.animType].animIndex + anim; frame = animPtr->frameEnd - animPtr->frameBegin - frame; // offset aim frames from the end } break; @@ -3486,7 +3521,7 @@ struct Lara : Item } else { if (frame == 0) { anim = ANIM_SHOTGUN_DRAW; - animPtr = level.anims + models[params.animType].animIndex + anim; + animPtr = level.anims + level.models[params.animType].animIndex + anim; animLength = animPtr->frameEnd - animPtr->frameBegin; frame = animLength; } else { @@ -3498,7 +3533,7 @@ struct Lara : Item } R.useBasis = L.useBasis = false; - R.animIndex = L.animIndex = anim + models[params.animType].animIndex; + R.animIndex = L.animIndex = anim + level.models[params.animType].animIndex; R.frameIndex = L.frameIndex = frame; } @@ -3525,18 +3560,23 @@ struct Lara : Item if (!change) return; - if (extraL->weaponState == WEAPON_STATE_FREE) { - setWeaponState(WEAPON_STATE_DRAW); + if (extraL->weaponState == WEAPON_STATE_FREE) + { + if (extraL->ammo[WEAPON_PISTOLS] != 0) + { + setWeaponState(WEAPON_STATE_DRAW); + } } - if (extraL->weaponState == WEAPON_STATE_READY) { + if (extraL->weaponState == WEAPON_STATE_READY) + { setWeaponState(WEAPON_STATE_HOLSTER); } } - void weaponGetAimPoint(Item* target, Location &point) + void weaponGetAimPoint(ItemObj* target, Location &point) { - const Bounds &box = target->getBoundingBox(false); + const AABBs &box = target->getBoundingBox(false); vec3i p; p.x = (box.minX + box.maxX) >> 1; p.y = box.minY + (box.maxY - box.minY) / 3; @@ -3588,8 +3628,8 @@ struct Lara : Item if (abs(angleAim.x) <= params.aimX && abs(angleAim.y) <= params.aimY) { extraL->armR.aim = extraL->armL.aim = true; } else { - extraL->armR.aim &= abs(angleAim.x) <= params.armX && angleAim.y >= params.armMinY && angleAim.y <= params.armMaxY; - extraL->armL.aim &= abs(angleAim.x) <= params.armX && angleAim.y >= -params.armMaxY && angleAim.y <= -params.armMinY; + extraL->armR.aim = extraL->armR.aim && (abs(angleAim.x) <= params.armX) && (angleAim.y >= params.armMinY) && (angleAim.y <= params.armMaxY); + extraL->armL.aim = extraL->armR.aim && (abs(angleAim.x) <= params.armX) && (angleAim.y >= -params.armMaxY) && (angleAim.y <= -params.armMinY); } } else { extraL->armR.aim = extraL->armL.aim = false; @@ -3600,7 +3640,7 @@ struct Lara : Item void weaponFindTargets() { - if (!Item::sFirstActive) + if (!ItemObj::sFirstActive) return; const WeaponParams ¶ms = weaponParams[extraL->weapon]; @@ -3614,7 +3654,7 @@ struct Lara : Item from.pos.z = pos.z; from.room = room; - Item* item = Item::sFirstActive; + ItemObj* item = ItemObj::sFirstActive; do { if (item->health <= 0) @@ -3686,7 +3726,11 @@ struct Lara : Item return; if (health <= 0) + { + extraL->armR.animIndex = extraL->armL.animIndex = 0; + extraL->armR.useBasis = extraL->armL.useBasis = false; return; + } weaponUpdateState(); @@ -3694,7 +3738,7 @@ struct Lara : Item { case WEAPON_STATE_DRAW: { - gCamera->toCombat(); + extraL->camera.toCombat(); weaponDraw(); break; } @@ -3707,7 +3751,7 @@ struct Lara : Item case WEAPON_STATE_READY: { - gCamera->toCombat(); + extraL->camera.toCombat(); weaponUpdateTargets(); if (extraL->weapon < WEAPON_SHOTGUN) { @@ -3732,8 +3776,7 @@ struct Lara : Item virtual void update() { - gCamera = extraL->camera; - ASSERT(gCamera); + vec3i oldPos = pos; updateInput(); @@ -3777,16 +3820,30 @@ struct Lara : Item } updateRoom(offset); + const Sector* sector = room->getSector(pos.x, pos.z); + bool badPos = (sector->floor == NO_FLOOR); + + //if (!badPos) { + // int32 h = pos.y - roomFloor; + // badPos = (h > cinfo.gapPos) || (h < cinfo.gapNeg); + //} + + if (badPos) + { + pos = oldPos; + updateRoom(offset); + } + updateWeapon(); checkTrigger(cinfo.trigger, this); - extraL->camera->update(); + extraL->camera.update(); } void meshSwap(ItemType type, uint32 mask) { - int32 start = models[type].start; + int32 start = level.models[type].start; for (int32 i = 0; i < JOINT_MAX && mask; i++, mask >>= 1) { @@ -3851,8 +3908,11 @@ const Lara::Handler Lara::cHandlers[X_MAX] = { LARA_STATES(DECL_C_HANDLER) }; #undef S_HANDLER #undef C_HANDLER -int32 doTutorial(Item* lara, int32 track) +int32 doTutorial(ItemObj* lara, int32 track) { + if (!lara) + return track; + switch (track) { case 28 : diff --git a/src/platform/gba/level.h b/src/platform/gba/level.h index 16a010a8..585bc6d9 100644 --- a/src/platform/gba/level.h +++ b/src/platform/gba/level.h @@ -6,36 +6,30 @@ Level level; -const Sprite* sprites; -const uint8* tiles; - -#ifndef MODE_PAL -extern uint16 palette[256]; -#endif - +#ifndef MODEHW IWRAM_DATA uint8 lightmap[256 * 32]; // IWRAM 8k +#endif -EWRAM_DATA Item items[MAX_ITEMS]; +EWRAM_DATA ItemObj items[MAX_ITEMS]; -#define MAX_DYN_SECTORS (1024*3) -int32 dynSectorsCount; -EWRAM_DATA Sector dynSectors[MAX_DYN_SECTORS]; // EWRAM 8k +#ifdef ROM_READ EWRAM_DATA Texture textures[MAX_TEXTURES]; +EWRAM_DATA FixedCamera cameras[MAX_CAMERAS]; +EWRAM_DATA Box boxes[MAX_BOXES]; +#endif + EWRAM_DATA Room rooms[MAX_ROOMS]; EWRAM_DATA Model models[MAX_MODELS]; EWRAM_DATA const Mesh* meshes[MAX_MESHES]; EWRAM_DATA StaticMesh staticMeshes[MAX_STATIC_MESHES]; -EWRAM_DATA FixedCamera cameras[MAX_CAMERAS]; - -Item* Item::sFirstActive; -Item* Item::sFirstFree; -Room* roomsList[MAX_ROOM_LIST]; +ItemObj* ItemObj::sFirstActive; +ItemObj* ItemObj::sFirstFree; -void readLevel(const uint8* data) +void readLevel_GBA(const uint8* data) { memcpy(&level, data, sizeof(level)); - + { // fix level data offsets uint32* ptr = (uint32*)&level.palette; while (ptr <= (uint32*)&level.soundOffsets) @@ -62,21 +56,11 @@ void readLevel(const uint8* data) } } +#ifndef MODEHW // initialize global pointers -#ifdef MODE_PAL - paletteSet(level.palette); -#else - memcpy(palette, level.palette, sizeof(palette)); -#endif - + osSetPalette(level.palette); memcpy(lightmap, level.lightmap, sizeof(lightmap)); - - tiles = level.tiles; - - // prepare textures (required by anim tex logic) - memcpy(textures, level.textures, level.texturesCount * sizeof(Texture)); - - sprites = level.sprites; +#endif // prepare models // TODO prerocess memset(models, 0, sizeof(models)); @@ -85,12 +69,14 @@ void readLevel(const uint8* data) const Model* model = level.models + i; models[model->type] = *model; } + level.models = models; // prepare meshes for (int32 i = 0; i < level.meshesCount; i++) { - meshes[i] = (Mesh*)(level.meshData + level.meshOffsets[i]); + meshes[i] = (Mesh*)((uint8*)level.meshes + level.meshOffsets[i]); } + level.meshes = meshes; // prepare static meshes // TODO preprocess memset(staticMeshes, 0, sizeof(staticMeshes)); @@ -101,6 +87,7 @@ void readLevel(const uint8* data) ASSERT(staticMesh->id < MAX_STATIC_MESHES); staticMeshes[staticMesh->id] = *staticMesh; } + level.staticMeshes = staticMeshes; // prepare sprites // TODO preprocess for (int32 i = 0; i < level.spriteSequencesCount; i++) @@ -115,508 +102,33 @@ void readLevel(const uint8* data) m->start = spriteSeq->start; } - // prepare fixed cameras - memcpy(cameras, level.cameras, level.camerasCount * sizeof(FixedCamera)); -} - -#define TRACE_SHIFT 10 // trace precision - -#define TRACE_CHECK(r, x, y, z) \ -{ \ - const Sector* sector = r->getSector(x, z); \ - if (accurate) { \ - if (y > sector->getFloor(x, y, z) || y < sector->getCeiling(x, y, z)) \ - { \ - to.pos = p; \ - to.room = room; \ - return false; \ - } \ - } else { \ - if (y > (sector->floor << 8) || y < (sector->ceiling << 8)) \ - { \ - to.pos = p; \ - to.room = room; \ - return false; \ - } \ - } \ -} - -bool traceX(const Location &from, Location &to, bool accurate) -{ - vec3i d = to.pos - from.pos; - - if (!d.x) - return true; - - d.y = (d.y << TRACE_SHIFT) / d.x; - d.z = (d.z << TRACE_SHIFT) / d.x; - - vec3i p = from.pos; - - Room* room = from.room; - - if (d.x < 0) - { - d.x = 1024; - p.x &= ~1023; - p.y += d.y * (p.x - from.pos.x) >> TRACE_SHIFT; - p.z += d.z * (p.x - from.pos.x) >> TRACE_SHIFT; - - while (p.x > to.pos.x) - { - room = room->getRoom(p.x, p.y, p.z); - TRACE_CHECK(room, p.x, p.y, p.z); - - Room* nextRoom = room->getRoom(p.x - 1, p.y, p.z); - TRACE_CHECK(nextRoom, p.x - 1, p.y, p.z); - - room = nextRoom; - p -= d; - } - } - else - { - d.x = 1024; - p.x |= 1023; - p.y += d.y * (p.x - from.pos.x) >> TRACE_SHIFT; - p.z += d.z * (p.x - from.pos.x) >> TRACE_SHIFT; - - while (p.x < to.pos.x) - { - room = room->getRoom(p.x, p.y, p.z); - TRACE_CHECK(room, p.x, p.y, p.z); - - Room* nextRoom = room->getRoom(p.x + 1, p.y, p.z); - TRACE_CHECK(nextRoom, p.x + 1, p.y, p.z); - - room = nextRoom; - p += d; - } - } - - to.room = room; - - return true; -} - -bool traceZ(const Location &from, Location &to, bool accurate) -{ - vec3i d = to.pos - from.pos; - - if (!d.z) - return true; - - d.x = (d.x << TRACE_SHIFT) / d.z; - d.y = (d.y << TRACE_SHIFT) / d.z; - - vec3i p = from.pos; - - Room* room = from.room; - - if (d.z < 0) - { - d.z = 1024; - p.z &= ~1023; - p.x += d.x * (p.z - from.pos.z) >> TRACE_SHIFT; - p.y += d.y * (p.z - from.pos.z) >> TRACE_SHIFT; - - while (p.z > to.pos.z) - { - room = room->getRoom(p.x, p.y, p.z); - TRACE_CHECK(room, p.x, p.y, p.z); - - Room* nextRoom = room->getRoom(p.x, p.y, p.z - 1); - TRACE_CHECK(nextRoom, p.x, p.y, p.z - 1); - - room = nextRoom; - p -= d; - } - } - else - { - d.z = 1024; - p.z |= 1023; - p.x += d.x * (p.z - from.pos.z) >> TRACE_SHIFT; - p.y += d.y * (p.z - from.pos.z) >> TRACE_SHIFT; - - while (p.z < to.pos.z) - { - room = room->getRoom(p.x, p.y, p.z); - TRACE_CHECK(room, p.x, p.y, p.z); - - Room* nextRoom = room->getRoom(p.x, p.y, p.z + 1); - TRACE_CHECK(nextRoom, p.x, p.y, p.z + 1); - - room = nextRoom; - p += d; - } - } - - to.room = room; - - return true; -} - -#undef TRACE_CHECK - -bool trace(const Location &from, Location &to, bool accurate) -{ - int32 dx = abs(to.pos.x - from.pos.x); - int32 dz = abs(to.pos.z - from.pos.z); - int32 dy; - - bool res; +#ifdef ROM_READ + // prepare textures (required by anim tex logic) + memcpy(textures, level.textures, level.texturesCount * sizeof(Texture)); + level.textures = textures; - if (dz > dx) { - res = traceX(from, to, accurate); - if (!traceZ(from, to, accurate)) - return false; - } else { - res = traceZ(from, to, accurate); - if (!traceX(from, to, accurate)) - return false; - } + // prepare boxes + memcpy(boxes, level.boxes, level.boxesCount * sizeof(Box)); + level.boxes = boxes; - dy = to.pos.y - from.pos.y; + // prepare fixed cameras + memcpy(cameras, level.cameras, level.camerasCount * sizeof(FixedCamera)); + level.cameras = cameras; +#endif - if (dy) +#ifdef __3DO__ + for (int32 i = 0; i < level.texturesCount; i++) { - const Sector* sector = to.room->getSector(to.pos.x, to.pos.z); - - int32 h = sector->getFloor(to.pos.x, to.pos.y, to.pos.z); - if (to.pos.y <= h || from.pos.y >= h) - { - h = sector->getCeiling(to.pos.x, to.pos.y, to.pos.z); - if (to.pos.y >= h || from.pos.y <= h) - { - h = WALL; - } - } - - if (h != WALL) - { - to.pos.y = h; - h -= from.pos.y; - to.pos.x = from.pos.x + (to.pos.x - from.pos.x) * h / dy; - to.pos.z = from.pos.z + (to.pos.z - from.pos.z) * h / dy; - return false; - } - } - - return res; -} - -void checkCamera(const FloorData* fd) -{ - if (gCamera->mode == CAMERA_MODE_OBJECT) - return; - - bool checkItem = true; - - while (1) - { - FloorData::TriggerCommand triggerCmd = (fd++)->triggerCmd; - - switch (triggerCmd.action) - { - case TRIGGER_ACTION_ACTIVATE_CAMERA: - { - triggerCmd.end = (fd++)->triggerCmd.end; - - if (triggerCmd.args != gCamera->lastIndex) - { - gCamera->lookAtItem = NULL; - break; - } - - gCamera->index = triggerCmd.args; - - if (gCamera->timer < 0 || gCamera->mode == CAMERA_MODE_LOOK || gCamera->mode == CAMERA_MODE_COMBAT) - { - gCamera->timer = -1; - gCamera->lookAtItem = NULL; - break; - } - - gCamera->mode = CAMERA_MODE_FIXED; - checkItem = false; - break; - } - - case TRIGGER_ACTION_CAMERA_TARGET: - { - if (gCamera->mode == CAMERA_MODE_LOOK || gCamera->mode == CAMERA_MODE_COMBAT) - break; - - ASSERT(triggerCmd.args < level.itemsCount); - gCamera->lookAtItem = items + triggerCmd.args; - break; - } - - case TRIGGER_ACTION_FLYBY: - { - triggerCmd.end = (fd++)->triggerCmd.end; - break; - } - } - - if (triggerCmd.end) - break; - }; - - if (checkItem && gCamera->lookAtItem && gCamera->lookAtItem != gCamera->lastItem && gCamera->lookAtItem->flags.animated) { - gCamera->lookAtItem = NULL; + Texture* tex = level.textures + i; + tex->data += intptr_t(VRAM_TEX); + tex->plut += intptr_t(VRAM_TEX); } +#endif } -void checkTrigger(const FloorData* fd, Item* lara) +void readLevel(const uint8* data) { - 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* cameraItem = NULL; - - checkCamera(fd); - - 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->roomFloor) - return; - break; - } - - case TRIGGER_TYPE_SWITCH: - { - switchItem = items + fd->triggerCmd.args; - if (!useSwitch(switchItem, info.timer)) - return; - fd++; - break; - } - - case TRIGGER_TYPE_KEY: - { - Item* keyItem = items + fd->triggerCmd.args; - if (!useKey(keyItem, lara)) - return; - fd++; - break; - } - - case TRIGGER_TYPE_PICKUP: - { - Item* pickupItem = items + fd->triggerCmd.args; - if (!usePickup(pickupItem)) - return; - fd++; - break; - } - - case TRIGGER_TYPE_OBJECT: - return; - - case TRIGGER_TYPE_COMBAT: - { - if (lara->extraL->weaponState != WEAPON_STATE_READY) - return; - break; - } - - case TRIGGER_TYPE_DUMMY: - return; - } - } - - while (1) - { - FloorData::TriggerCommand triggerCmd = (fd++)->triggerCmd; - - switch (triggerCmd.action) - { - case TRIGGER_ACTION_ACTIVATE_OBJECT: - { - ASSERT(triggerCmd.args < level.itemsCount); - Item* item = items + triggerCmd.args; - - if (item->flags.once) - break; - - item->timer = info.timer; - if (item->timer != 1) { - 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->activate(); - - if (item->flags.status == ITEM_FLAGS_STATUS_NONE) { - item->flags.status = ITEM_FLAGS_STATUS_ACTIVE; - } - - break; - } - - case TRIGGER_ACTION_ACTIVATE_CAMERA: - { - FloorData::TriggerCommand cam = (fd++)->triggerCmd; - triggerCmd.end = cam.end; - - if (cameras[triggerCmd.args].flags.once) - break; - - gCamera->index = triggerCmd.args; - - if (gCamera->mode == CAMERA_MODE_LOOK || gCamera->mode == CAMERA_MODE_COMBAT) - break; - - if (cmd.type == TRIGGER_TYPE_COMBAT) - break; - - if (cmd.type == TRIGGER_TYPE_SWITCH && (switchItem->state == 1) && (info.timer != 0)) - break; - - if (cmd.type == TRIGGER_TYPE_SWITCH || gCamera->index != gCamera->lastIndex) - { - gCamera->timer = cam.timer; - if (gCamera->timer != 1) { - gCamera->timer *= 30; - } - - if (cam.once) { - cameras[gCamera->index].flags.once = true; - } - - gCamera->speed = (cam.speed << 3) + 1; - gCamera->mode = lara ? CAMERA_MODE_FIXED : CAMERA_MODE_OBJECT; - } - 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: - { - cameraItem = items + triggerCmd.args; - break; - } - - case TRIGGER_ACTION_END: - // TODO go to the next level - break; - - case TRIGGER_ACTION_SOUNDTRACK: - { - int32 track = doTutorial(lara, triggerCmd.args); - - if (track == 0) break; - - SaveGame::TrackFlags &flags = gSaveGame.tracks[track]; - - if (flags.once) - break; - - if (cmd.type == TRIGGER_TYPE_SWITCH) - flags.mask ^= info.mask; - else if (cmd.type == TRIGGER_TYPE_ANTIPAD) - flags.mask &= ~info.mask; - else - flags.mask |= info.mask; - - if (flags.mask == ITEM_FLAGS_MASK_ALL) { - flags.once |= info.once; - musicPlay(track); - } else { - musicStop(); - } - break; - } - - case TRIGGER_ACTION_EFFECT: - // TODO effect - break; - - case TRIGGER_ACTION_SECRET: - { - if (gSaveGame.secrets & (1 << triggerCmd.args)) - break; - gSaveGame.secrets |= (1 << triggerCmd.args); - musicPlay(13); - break; - } - - case TRIGGER_ACTION_CLEAR_BODIES: - break; - - case TRIGGER_ACTION_FLYBY: - triggerCmd.end = (fd++)->triggerCmd.end; - break; - - case TRIGGER_ACTION_CUTSCENE: - break; - } - - if (triggerCmd.end) - break; - }; - - if (cameraItem && (gCamera->mode == CAMERA_MODE_FIXED || gCamera->mode == CAMERA_MODE_OBJECT)) - { - gCamera->lookAtItem = cameraItem; - } + readLevel_GBA(data); } #endif diff --git a/src/platform/gba/main.cpp b/src/platform/gba/main.cpp index 94db3600..ebf567a3 100644 --- a/src/platform/gba/main.cpp +++ b/src/platform/gba/main.cpp @@ -1,11 +1,10 @@ #if defined(_WIN32) || defined(__DOS__) const void* TRACKS_IMA; const void* levelData; - #define LEVEL_NAME "LEVEL1.PKD" #elif defined(__GBA__) #include "TRACKS_IMA.h" - #include "LEVEL1_PKD.h" - const void* levelData = LEVEL1_PKD; + #include "LEVEL2_PKD.h" + const void* levelData = LEVEL2_PKD; #elif defined(__TNS__) const void* levelData; #endif @@ -19,11 +18,7 @@ int32 frameIndex = 0; int32 fpsCounter = 0; #if defined(_WIN32) - #ifdef MODE_PAL - uint32 SCREEN[FRAME_WIDTH * FRAME_HEIGHT]; - #else - uint32 SCREEN[VRAM_WIDTH * FRAME_HEIGHT]; - #endif + uint32 SCREEN[FRAME_WIDTH * FRAME_HEIGHT]; HWND hWnd; @@ -33,15 +28,11 @@ int32 fpsCounter = 0; #define WND_WIDTH 240*4 #define WND_HEIGHT 160*4 - #ifdef MODE_PAL - uint16 MEM_PAL_BG[256]; - #endif + uint16 MEM_PAL_BG[256]; - void paletteSet(const uint16* palette) + void osSetPalette(const uint16* palette) { - #ifdef MODE_PAL memcpy(MEM_PAL_BG, palette, 256 * 2); - #endif } int32 osGetSystemTimeMS() @@ -52,7 +43,7 @@ int32 fpsCounter = 0; void osJoyVibrate(int32 index, int32 L, int32 R) {} #elif defined(__GBA__) - void paletteSet(const uint16* palette) + void osSetPalette(const uint16* palette) { memcpy((uint16*)MEM_PAL_BG, palette, 256 * 2); } @@ -132,7 +123,7 @@ int32 fpsCounter = 0; void osJoyVibrate(int32 index, int32 L, int32 R) {} - void paletteSet(const uint16* palette) + void osSetPalette(const uint16* palette) { memcpy((uint16*)0xC0000200, palette, 256 * 2); } @@ -214,7 +205,7 @@ int32 fpsCounter = 0; "mov ax,03h" \ "int 10h"; - void paletteSet(const uint16* palette) + void osSetPalette(const uint16* palette) { outp(0x03C8, 0); for (int32 i = 0; i < 256; i++) @@ -393,21 +384,12 @@ void soundFill() HDC hDC; void blit() { -#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); -#else - 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), 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 } LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -429,10 +411,10 @@ LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { case VK_RIGHT : key = IK_RIGHT; break; case VK_DOWN : key = IK_DOWN; break; case VK_LEFT : key = IK_LEFT; break; - case 'Z' : key = IK_B; break; - case 'X' : key = IK_A; break; - case 'A' : key = IK_L; break; - case 'S' : key = IK_R; break; + case 'A' : key = IK_B; break; + case 'S' : key = IK_A; break; + case 'Q' : key = IK_L; break; + case 'W' : key = IK_R; break; case VK_RETURN : key = IK_START; break; case VK_SPACE : key = IK_SELECT; break; } @@ -471,21 +453,51 @@ void vblank() { #endif -int main(void) { +int32 gLevelID = 2; + +static const char* gLevelNames[] = { + "GYM", + "LEVEL1", + "LEVEL2", + "LEVEL3A", + "LEVEL3B", +// "LEVEL4", +// "LEVEL5", +// "LEVEL6", +// "LEVEL7A", +// "LEVEL7B", +// "LEVEL8A", +// "LEVEL8B", +// "LEVEL8C", +// "LEVEL10A", +// "LEVEL10B", +// "LEVEL10C" +}; + +void osLoadLevel(const char* name) +{ + mixer.stopMusic(); + mixer.stopSamples(); + #if defined(_WIN32) || defined(__TNS__) || defined(__DOS__) { // level1 + char buf[32]; + + delete[] levelData; + #if defined(_WIN32) || defined(__DOS__) - FILE *f = fopen("data/" LEVEL_NAME, "rb"); + sprintf(buf, "data/%s.PKD", name); #elif defined(__TNS__) - FILE *f = fopen("/documents/OpenLara/LEVEL1.PHD.tns", "rb"); + sprintf(buf, "/documents/OpenLara/%s.PKD.tns", name); #else #error #endif - if (!f) { - return 0; - } + FILE *f = fopen(buf, "rb"); + + if (!f) + return; { fseek(f, 0, SEEK_END); @@ -500,11 +512,11 @@ int main(void) { // track 13 #if defined(_WIN32) || defined(__DOS__) + if (!TRACKS_IMA) { FILE *f = fopen("data/TRACKS.IMA", "rb"); - if (!f) { - return 0; - } + if (!f) + return; fseek(f, 0, SEEK_END); int32 size = ftell(f); @@ -518,7 +530,9 @@ int main(void) { #endif } #endif +} +int main(void) { #if defined(_WIN32) RECT r = { 0, 0, WND_WIDTH, WND_HEIGHT }; @@ -534,12 +548,13 @@ int main(void) { soundInit(); - game.init(); + game.init(gLevelNames[gLevelID]); MSG msg; - int startTime = GetTickCount() - 33; - int lastFrame = 0; + int32 startTime = GetTickCount() - 33; + int32 lastFrame = 0; + uint32 oldKeys = 0; do { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { @@ -548,6 +563,15 @@ int main(void) { } else { int32 frame = (GetTickCount() - startTime) / 33; if (GetAsyncKeyState('R')) frame /= 10; + + if ((keys & IK_SELECT) && !(oldKeys & IK_SELECT)) + { + gLevelID = (gLevelID + 1) % (sizeof(gLevelNames) / sizeof(gLevelNames[0])); + game.startLevel(gLevelNames[gLevelID]); + lastFrame = frame - 1; + } + oldKeys = keys; + int32 count = frame - lastFrame; if (GetAsyncKeyState('T')) count *= 10; game.update(count); @@ -599,7 +623,7 @@ int main(void) { rumbleInit(); soundInit(); - game.init(); + game.init(gLevelNames[gLevelID]); uint16 mode = DCNT_BG2 | DCNT_PAGE; @@ -660,7 +684,7 @@ int main(void) { timerInit(); inputInit(); - game.init(); + game.init(gLevelNames[gLevelID]); int startTime = GetTickCount(); int lastTime = -16; @@ -696,7 +720,7 @@ int main(void) { videoAcquire(); inputAcquire(); - game.init(); + game.init(gLevelNames[gLevelID]); int32 lastFrameIndex = -1; diff --git a/src/platform/gba/nav.h b/src/platform/gba/nav.h new file mode 100644 index 00000000..136c7cff --- /dev/null +++ b/src/platform/gba/nav.h @@ -0,0 +1,227 @@ +#ifndef H_NAV +#define H_NAV + +#include "common.h" + +#define NAV_INDEX 0x3FFF +#define NAV_WEIGHT 0x7FFF +#define NAV_BLOCKED 0x8000 + +void Nav::init(uint32 boxIndex) +{ + switch (stepHeight) + { + case 256 : zoneType = ZONE_GROUND_1; break; + case 512 : zoneType = ZONE_GROUND_2; break; + default : zoneType = ZONE_FLY; + } + + weight = 0; + endBox = NO_BOX; + nextBox = NO_BOX; + + headBox = NO_BOX; + tailBox = NO_BOX; + + mask = 0x400; + + for (int32 i = 0; i < level.boxesCount; i++) + { + cells[i].end = NO_BOX; + cells[i].next = NO_BOX; + cells[i].weight = 0; + } + + const uint16* defZones = level.zones[0][zoneType]; + const uint16* altZones = level.zones[1][zoneType]; + + uint16 defZone = defZones[boxIndex]; + uint16 altZone = altZones[boxIndex]; + + cellsCount = 0; + Nav::Cell* cell = cells; + + for (int32 i = 0; i < level.boxesCount; i++) + { + if ((defZone == defZones[i]) || (altZone == altZones[i])) + { + (*cell++).boxIndex = i; + cellsCount++; + } + } + + ASSERT(cellsCount > 0); +} + +vec3i Nav::getWaypoint(uint32 boxIndex, const vec3i &from) +{ + if (nextBox != NO_BOX && nextBox != endBox) + { + endBox = nextBox; + + Nav::Cell &cell = cells[endBox]; + + if (cell.next == NO_BOX && tailBox != endBox) + { + cell.next = headBox; + + if (headBox == NO_BOX) { + tailBox = endBox; + } + + headBox = endBox; + } + + weight++; + cell.weight = weight; + cell.end = NO_BOX; + } + + if (headBox != NO_BOX) + { + const uint16* zones = level.zones[gSaveGame.flipped][zoneType]; + uint16 zone = zones[headBox]; + + for (int32 i = 0; (i < NAV_STEPS) && (headBox != NO_BOX); i++) + { + search(zone, zones); + } + } + + if (boxIndex == endBox) + return pos; + + vec3i wp = from; + + if (boxIndex == NO_BOX) + return wp; + + const Box* box = level.boxes + boxIndex; + + int32 bMinX = (box->minX << 10); + int32 bMaxX = (box->maxX << 10) - 1; + int32 bMinZ = (box->minZ << 10); + int32 bMaxZ = (box->maxZ << 10) - 1; + + int32 minX = bMinX; + int32 maxX = bMaxX; + int32 minZ = bMinZ; + int32 maxZ = bMaxZ; + + while ((boxIndex != NO_BOX) && !(level.boxes[boxIndex].overlap & mask)) + { + box = level.boxes + boxIndex; + + bMinX = (box->minX << 10); + bMaxX = (box->maxX << 10) - 1; + bMinZ = (box->minZ << 10); + bMaxZ = (box->maxZ << 10) - 1; + + if (from.x >= bMinX && from.x <= bMaxX && from.z >= bMinZ && from.z <= bMaxZ) + { + minX = bMinX; + maxX = bMaxX; + minZ = bMinZ; + maxZ = bMaxZ; + } else { + if ((wp.x < bMinX) || (wp.x > bMaxX)) + { + if ((wp.z < minZ) || (wp.z > maxZ)) + break; + wp.x = X_CLAMP(wp.x, bMinX + 512, bMaxX - 512); + minZ = X_MAX(minZ, bMinZ); + maxZ = X_MIN(maxZ, bMaxZ); + } + + if ((wp.z < bMinZ) || (wp.z > bMaxZ)) + { + if ((wp.x < minX) || (wp.x > maxX)) + break; + wp.z = X_CLAMP(wp.z, bMinZ + 512, bMaxZ - 512); + minX = X_MAX(minX, bMinX); + maxX = X_MIN(maxX, bMaxX); + } + } + + if (boxIndex == endBox) + { + wp.x = X_CLAMP(wp.x, bMinX + 512, bMaxX - 512); + wp.z = X_CLAMP(wp.z, bMinZ + 512, bMaxZ - 512); + break; + } + + boxIndex = cells[boxIndex].end; + } + + wp.y = box->floor - ((zoneType == ZONE_FLY) ? 384 : 0); // TODO check for 320 + + return wp; +} + +void Nav::search(uint16 zone, const uint16* zones) +{ + Nav::Cell &curr = cells[headBox]; + const Box &b = level.boxes[headBox]; + + uint16 overlapIndex = b.overlap & NAV_INDEX; + + bool end = false; + + do { + uint16 boxIndex = level.overlaps[overlapIndex++]; + + end = boxIndex & NAV_BLOCKED; + if (end) { + boxIndex &= NAV_INDEX; + } + + if (zone != zones[boxIndex]) + continue; + + int32 diff = level.boxes[boxIndex].floor - b.floor; + if (diff > stepHeight || diff < dropHeight) + continue; + + Nav::Cell &next = cells[boxIndex]; + + uint16 cWeight = curr.weight & NAV_WEIGHT; + uint16 nWeight = next.weight & NAV_WEIGHT; + + if (cWeight < nWeight) + continue; + + if (curr.weight & NAV_BLOCKED) + { + if (cWeight == nWeight) + continue; + + next.weight = curr.weight; + } + else + { + if ((cWeight == nWeight) && !(next.weight & NAV_BLOCKED)) + continue; + + if (level.boxes[boxIndex].overlap & mask) + { + next.weight = curr.weight | NAV_BLOCKED; + } + else + { + next.weight = curr.weight; + next.end = headBox; + } + } + + if (next.next == NO_BOX && boxIndex != tailBox) + { + cells[tailBox].next = boxIndex; + tailBox = boxIndex; + } + } while (!end); + + headBox = curr.next; + curr.next = NO_BOX; +} + +#endif diff --git a/src/platform/gba/object.h b/src/platform/gba/object.h index 39d2bdb6..8a7ef023 100644 --- a/src/platform/gba/object.h +++ b/src/platform/gba/object.h @@ -8,57 +8,56 @@ vec3i getBlockOffset(int16 angleY, int32 offset) { if (angleY == ANGLE_0) - return vec3i(0, 0, -offset); + return _vec3i(0, 0, -offset); if (angleY == ANGLE_180) - return vec3i(0, 0, offset); + return _vec3i(0, 0, offset); if (angleY == ANGLE_90) - return vec3i(-offset, 0, 0); - return vec3i(offset, 0, 0); + return _vec3i(-offset, 0, 0); + return _vec3i(offset, 0, 0); } struct Limit { - Bounds box; + AABBs box; vec3s angle; }; -namespace Limits -{ - static const Limit SWITCH = { - Bounds( -200, 200, 0, 0, 312, 512 ), - vec3s( ANGLE(10), ANGLE(30), ANGLE(10) ) - }; +// armcpp won't initialize structs - static const Limit SWITCH_UW = { - Bounds( -1024, 1024, -1024, 1024, -1024, 1024 ), - vec3s( ANGLE(80), ANGLE(80), ANGLE(80) ) - }; +int16 LIMIT_SWITCH[] = { + -200, 200, 0, 0, 312, 512, + ANGLE(10), ANGLE(30), ANGLE(10) +}; - static const Limit BLOCK = { - Bounds( -300, 300, 0, 0, -692, -512 ), - vec3s( ANGLE(10), ANGLE(30), ANGLE(10) ) - }; +int16 LIMIT_SWITCH_UW[] = { + -1024, 1024, -1024, 1024, -1024, 1024, + ANGLE(80), ANGLE(80), ANGLE(80) +}; - static const Limit PICKUP = { - Bounds( -256, 256, -100, 100, -256, 100 ), - vec3s( ANGLE(10), 0, 0 ) - }; +int16 LIMIT_BLOCK[] = { + -300, 300, 0, 0, -692, -512, + ANGLE(10), ANGLE(30), ANGLE(10) +}; - static const Limit PICKUP_UW = { - Bounds( -512, 512, -512, 512, -512, 512 ), - vec3s( ANGLE(45), ANGLE(45), ANGLE(45) ) - }; +int16 LIMIT_PICKUP[] = { + -256, 256, -100, 100, -256, 100, + ANGLE(10), 0, 0 +}; - static const Limit HOLE = { - Bounds( -200, 200, 0, 0, 312, 512 ), - vec3s( ANGLE(10), ANGLE(30), ANGLE(10) ) - }; +int16 LIMIT_PICKUP_UW[] = { + -512, 512, -512, 512, -512, 512, + ANGLE(45), ANGLE(45), ANGLE(45) +}; + +int16 LIMIT_HOLE[] = { + -200, 200, 0, 0, 312, 512, + ANGLE(10), ANGLE(30), ANGLE(10) }; -struct Object : Item +struct Object : ItemObj { - Object(Room* room) : Item(room) {} + Object(Room* room) : ItemObj(room) {} virtual void update() { @@ -81,13 +80,15 @@ struct Object : Item return flags.reverse == 0; } - bool checkLimit(Lara* lara, const Limit& limit) + bool checkLimit(Lara* lara, const int16* limitData) { + Limit* limit = (Limit*)limitData; + int16 ax = abs(lara->angle.x - angle.x); int16 ay = abs(lara->angle.y - angle.y); int16 az = abs(lara->angle.z - angle.z); - if (ax > limit.angle.x || ay > limit.angle.y || az > limit.angle.z) + if (ax > limit->angle.x || ay > limit->angle.y || az > limit->angle.z) return false; vec3i d = lara->pos - pos; @@ -97,11 +98,11 @@ struct Object : Item 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; + p.x = DP33(m.e00, m.e01, m.e02, d.x, d.y, d.z) >> FIXED_SHIFT; + p.y = DP33(m.e10, m.e11, m.e12, d.x, d.y, d.z) >> FIXED_SHIFT; + p.z = DP33(m.e20, m.e21, m.e22, d.x, d.y, d.z) >> FIXED_SHIFT; - return boxContains(limit.box, p); + return boxContains(limit->box, p); } void collideDefault(Lara* lara, CollisionInfo* cinfo) @@ -117,9 +118,9 @@ struct Object : Item }; -struct SpriteEffect : Item +struct SpriteEffect : ItemObj { - SpriteEffect(Room* room) : Item(room) + SpriteEffect(Room* room) : ItemObj(room) { tick = 0; timer = 0; @@ -138,7 +139,7 @@ struct SpriteEffect : Item if (flags.animated) { frameIndex++; - if (frameIndex >= -models[type].count) + if (frameIndex >= -level.models[type].count) { remove(); return; @@ -158,14 +159,14 @@ struct SpriteEffect : Item }; -struct Bubble : Item +struct Bubble : ItemObj { - Bubble(Room* room) : Item(room) + Bubble(Room* room) : ItemObj(room) { soundPlay(SND_BUBBLE, pos); - frameIndex = rand_draw() % (-models[type].count); + frameIndex = rand_draw() % (-level.models[type].count); vSpeed = -(10 + (rand_draw() % 6)); - angle = vec3s(0, 0, ANGLE_90); + angle = _vec3s(0, 0, ANGLE_90); activate(); roomFloor = getWaterLevel(); @@ -378,7 +379,7 @@ struct Switch : Object if (flags.status != ITEM_FLAGS_STATUS_NONE) return; - if (!checkLimit(lara, Limits::SWITCH)) + if (!checkLimit(lara, LIMIT_SWITCH)) return; lara->angle.y = angle.y; @@ -432,10 +433,10 @@ struct SwitchWater : Switch if (lara->state != Lara::STATE_UW_TREAD) return; - if (!checkLimit(lara, Limits::SWITCH_UW)) + if (!checkLimit(lara, LIMIT_SWITCH_UW)) return; - if (!lara->moveTo(vec3i(0, 0, 108), this, true)) + if (!lara->moveTo(_vec3i(0, 0, 108), this, true)) return; lara->vSpeed = 0; // underwater speed @@ -455,7 +456,7 @@ struct Key : Object { Key(Room* room) : Object(room) {} - bool use(Item* lara) + bool use(ItemObj* lara) { if (flags.status == ITEM_FLAGS_STATUS_ACTIVE && lara->extraL->weaponState == WEAPON_STATE_FREE) // TODO check weapons { @@ -493,7 +494,7 @@ struct Pickup : Object { angle.x = 0; - if (!checkLimit(lara, Limits::PICKUP)) + if (!checkLimit(lara, LIMIT_PICKUP)) return; if (lara->state == Lara::STATE_PICKUP) @@ -514,7 +515,7 @@ struct Pickup : Object if (!(lara->input & IN_ACTION)) return; - if (!lara->moveTo(vec3i(0, 0, -100), this, false)) + if (!lara->moveTo(_vec3i(0, 0, -100), this, false)) return; lara->animSkip(Lara::STATE_PICKUP, Lara::STATE_STOP); @@ -526,7 +527,7 @@ struct Pickup : Object { angle.x = ANGLE(-25); - if (!checkLimit(lara, Limits::PICKUP_UW)) + if (!checkLimit(lara, LIMIT_PICKUP_UW)) return; if (lara->state == Lara::STATE_PICKUP) @@ -548,7 +549,7 @@ struct Pickup : Object if (!(lara->input & IN_ACTION)) return; - if (!lara->moveTo(vec3i(0, -200, -350), this, true)) + if (!lara->moveTo(_vec3i(0, -200, -350), this, true)) return; lara->animSkip(Lara::STATE_PICKUP, Lara::STATE_UW_TREAD); @@ -561,17 +562,17 @@ struct Pickup : Object }; -bool useSwitch(Item* item, int32 timer) +bool useSwitch(ItemObj* item, int32 timer) { return ((Switch*)item)->use(timer); } -bool useKey(Item* item, Item* lara) +bool useKey(ItemObj* item, ItemObj* lara) { return ((Key*)item)->use(lara); } -bool usePickup(Item* item) +bool usePickup(ItemObj* item) { return ((Pickup*)item)->use(); } @@ -597,7 +598,7 @@ struct Hole : Object // parent class for KeyHole and PuzzleHole if (!(lara->input & IN_ACTION) && (inventory.useSlot == SLOT_MAX)) return; - if (!checkLimit(lara, Limits::HOLE)) + if (!checkLimit(lara, LIMIT_HOLE)) return; if (inventory.useSlot == SLOT_MAX) @@ -609,7 +610,7 @@ struct Hole : Object // parent class for KeyHole and PuzzleHole } else { if (inventory.applyItem(this)) { - lara->moveTo(vec3i(0, 0, offset), this, false); + lara->moveTo(_vec3i(0, 0, offset), this, false); lara->animSkip(stateUse, Lara::STATE_STOP); lara->extraL->weaponState = WEAPON_STATE_BUSY; flags.status = ITEM_FLAGS_STATUS_ACTIVE; @@ -648,7 +649,7 @@ struct PuzzleHole : Hole { if (lara->state == Lara::STATE_USE_PUZZLE) { - if (!checkLimit(lara, Limits::HOLE)) + if (!checkLimit(lara, LIMIT_HOLE)) return; if (!lara->animIsEnd(28)) @@ -712,7 +713,9 @@ struct TrapFloor : Object return; } - updateRoom(); + if (flags.gravity) { + updateRoom(); + } if (state == STATE_FALL && pos.y >= roomFloor) { @@ -722,6 +725,18 @@ struct TrapFloor : Object goalState = STATE_DOWN; } } + + virtual void draw() + { + int32 oldAnimIndex = animIndex; + if ((state == STATE_STATIC) && level.models[ITEM_TRAP_FLOOR_LOD].type) { + type = ITEM_TRAP_FLOOR_LOD; + animIndex = level.models[type].animIndex; + } + Object::draw(); + type = ITEM_TRAP_FLOOR; + animIndex = oldAnimIndex; + } }; @@ -750,7 +765,7 @@ struct TrapSwingBlade : Object if (!updateHitMask(lara, cinfo)) return; - vec3i offsetPos = vec3i((rand_logic() - 0x4000) >> 8, -256 - (rand_logic() >> 6), (rand_logic() - 0x4000) >> 8); + vec3i offsetPos = _vec3i((rand_logic() - 0x4000) >> 8, -256 - (rand_logic() >> 6), (rand_logic() - 0x4000) >> 8); int32 offsetAngle = (rand_logic() - 0x4000) >> 3; lara->fxBlood(lara->pos + offsetPos, lara->angle.y + offsetAngle, lara->hSpeed); @@ -832,7 +847,7 @@ struct TrapDartEmitter : Object p.y = -512; p += pos; - Item* dart = Item::add(ITEM_DART, room, p, angle.y); + ItemObj* dart = ItemObj::add(ITEM_DART, room, p, angle.y); if (dart) { @@ -922,7 +937,7 @@ struct Block : Object return checkObstacles(pos.x + offset.x, pos.z + offset.z, 1024); } - bool checkPull(Item* lara) + bool checkPull(ItemObj* lara) { if (!checkBlocking()) return false; @@ -949,14 +964,14 @@ struct Block : Object if (lara->pos.y != pos.y) return; - uint16 quadrant = uint16(lara->angle.y + ANGLE_45) / ANGLE_90; + uint16 quadrant = uint16(lara->angle.y + ANGLE_45) >> ANGLE_SHIFT_90; if (lara->state == Lara::STATE_BLOCK_READY) { if (!lara->animIsEnd(0)) return; - if (!checkLimit(lara, Limits::BLOCK)) + if (!checkLimit(lara, LIMIT_BLOCK)) return; if (lara->input & IN_UP) @@ -996,7 +1011,7 @@ struct Block : Object angle.y = quadrant * ANGLE_90; - if (!checkLimit(lara, Limits::BLOCK)) + if (!checkLimit(lara, LIMIT_BLOCK)) return; lara->goalState = Lara::STATE_BLOCK_READY; diff --git a/src/platform/gba/rasterizer_mode13.h b/src/platform/gba/rasterizer_mode13.h index 71423d27..677273b8 100644 --- a/src/platform/gba/rasterizer_mode13.h +++ b/src/platform/gba/rasterizer_mode13.h @@ -15,7 +15,7 @@ extern const uint8* tile; #define rasterizeGTA rasterizeGTA_mode13_c #define rasterizeSprite rasterizeSprite_mode13_c -void rasterizeS_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeS_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[0x1A00]; @@ -30,7 +30,7 @@ void rasterizeS_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; if (N->v.y < L->v.y) return; @@ -49,7 +49,7 @@ void rasterizeS_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; if (N->v.y < R->v.y) return; @@ -123,7 +123,7 @@ void rasterizeS_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeF_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index) +void rasterizeF_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index) { uint16 color = lightmap[(L->v.g << 8) | index]; color |= (color << 8); @@ -139,7 +139,7 @@ void rasterizeF_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; ASSERT(L->v.y >= 0); @@ -160,7 +160,7 @@ void rasterizeF_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; ASSERT(R->v.y >= 0); @@ -228,7 +228,7 @@ void rasterizeF_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in } } -void rasterizeG_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index) +void rasterizeG_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index) { int32 Lh = 0, Rh = 0; int32 Lx, Rx, Ldx = 0, Rdx = 0; @@ -240,7 +240,7 @@ void rasterizeG_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; if (N->v.y < L->v.y) return; @@ -262,7 +262,7 @@ void rasterizeG_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; if (N->v.y < R->v.y) return; @@ -350,7 +350,7 @@ void rasterizeG_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R, in } } -void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeFT_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[L->v.g << 8]; @@ -364,20 +364,20 @@ void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { int32 tmp = FixedInvU(Lh); Ldx = tmp * (N->v.x - Lx); - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -389,20 +389,20 @@ void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { int32 tmp = FixedInvU(Rh); Rdx = tmp * (N->v.x - Rx); - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -452,14 +452,17 @@ void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) width >>= 1; while (width--) { - uint16 p; - - p = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]]; + uint8 indexA = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; - p |= ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]] << 8; + uint8 indexB = ft_lightmap[tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; - *(uint16*)ptr = p; + #ifdef CPU_BIG_ENDIAN + *(uint16*)ptr = indexB | (indexA << 8); + #else + *(uint16*)ptr = indexA | (indexB << 8); + #endif + ptr += 2; } } @@ -474,7 +477,7 @@ void rasterizeFT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeGT_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { #ifdef ALIGNED_LIGHTMAP ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned @@ -494,14 +497,14 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { @@ -509,7 +512,7 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Ldx = tmp * (N->v.x - Lx); Ldg = tmp * (N->v.g - Lg) >> 8; - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -522,14 +525,14 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { @@ -537,7 +540,7 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Rdx = tmp * (N->v.x - Rx); Rdg = tmp * (N->v.g - Rg) >> 8; - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -600,20 +603,25 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) #ifdef ALIGNED_LIGHTMAP const uint8* LMAP = (uint8*)(g >> 8 << 8); - uint16 p = LMAP[tile[(t & 0xFF00) | (t >> 24)]]; + uint8 indexA = LMAP[tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; - p |= LMAP[tile[(t & 0xFF00) | (t >> 24)]] << 8; + uint8 indexB = LMAP[tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; g += dgdx; #else - uint16 p = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]]; + uint8 indexA = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; - p |= lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]] << 8; + uint8 indexB = lightmap[(g >> 8 << 8) | tile[(t & 0xFF00) | (t >> 24)]]; t += dtdx; g += dgdx; #endif - *(uint16*)ptr = p; + #ifdef CPU_BIG_ENDIAN + *(uint16*)ptr = indexB | (indexA << 8); + #else + *(uint16*)ptr = indexA | (indexB << 8); + #endif + ptr += 2; } } @@ -630,7 +638,7 @@ void rasterizeGT_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeFTA_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[L->v.g << 8]; @@ -644,20 +652,20 @@ void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { int32 tmp = FixedInvU(Lh); Ldx = tmp * (N->v.x - Lx); - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -669,20 +677,20 @@ void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { int32 tmp = FixedInvU(Rh); Rdx = tmp * (N->v.x - Rx); - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -744,8 +752,18 @@ void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) uint8 indexB = tile[(t & 0xFF00) | (t >> 24)]; t += dtdx; - if (indexA && indexB) { - *(uint16*)ptr = ft_lightmap[indexA] | (ft_lightmap[indexB] << 8); + + if (indexA && indexB) + { + indexA = ft_lightmap[indexA]; + indexB = ft_lightmap[indexB]; + + #ifdef CPU_BIG_ENDIAN + *(uint16*)ptr = indexB | (indexA << 8); + #else + *(uint16*)ptr = indexA | (indexB << 8); + #endif + }/* else if (indexA) { *(uint16*)ptr = (*(uint16*)ptr & 0xFF00) | ft_lightmap[indexA]; } else if (indexB) { @@ -766,12 +784,12 @@ void rasterizeFTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeGTA_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeGTA_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { - rasterizeGT(pixel, L, R); + rasterizeFTA(pixel, L, R); } -void rasterizeSprite_mode13_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeSprite_mode13_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { // TODO } diff --git a/src/platform/gba/rasterizer_mode4.h b/src/platform/gba/rasterizer_mode4.h index 1f3192e5..927de4f3 100644 --- a/src/platform/gba/rasterizer_mode4.h +++ b/src/platform/gba/rasterizer_mode4.h @@ -5,7 +5,6 @@ extern uint8 lightmap[256 * 32]; extern const uint8* tile; -extern const Sprite* sprite; #if defined(__GBA__) #define USE_ASM @@ -13,14 +12,14 @@ extern const Sprite* sprite; #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); + void rasterize_dummy(uint16* pixel, const VertexLink* L, const VertexLink* R); + void rasterizeS_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R); + void rasterizeF_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index); + void rasterizeG_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index); + void rasterizeFT_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R); + void rasterizeGT_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R); + void rasterizeFTA_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R); + void rasterizeGTA_mode4_asm(uint16* pixel, const VertexLink* L, const VertexLink* R); } #define rasterizeS rasterizeS_mode4_asm @@ -41,7 +40,7 @@ extern const Sprite* sprite; #define rasterizeGTA rasterizeGTA_mode4_c #define rasterizeSprite rasterizeSprite_mode4_c -void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeS_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[0x1A00]; @@ -56,7 +55,7 @@ void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; if (N->v.y < L->v.y) return; @@ -75,7 +74,7 @@ void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; if (N->v.y < R->v.y) return; @@ -137,8 +136,6 @@ void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) *ptr++ = index; width -= 2; } - - #undef SHADE } pixel += VRAM_WIDTH; @@ -149,7 +146,7 @@ void rasterizeS_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeF_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index) +void rasterizeF_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index) { uint16 color = lightmap[(L->v.g << 8) | index]; color |= (color << 8); @@ -165,7 +162,7 @@ void rasterizeF_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; ASSERT(L->v.y >= 0); @@ -186,7 +183,7 @@ void rasterizeF_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; ASSERT(R->v.y >= 0); @@ -256,7 +253,7 @@ void rasterizeF_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int } } -void rasterizeG_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int32 index) +void rasterizeG_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R, int32 index) { int32 Lh = 0, Rh = 0; int32 Lx, Rx, Ldx = 0, Rdx = 0; @@ -268,7 +265,7 @@ void rasterizeG_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* N = L->prev; if (N->v.y < L->v.y) return; @@ -290,7 +287,7 @@ void rasterizeG_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* N = R->next; if (N->v.y < R->v.y) return; @@ -380,7 +377,7 @@ void rasterizeG_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R, int } } -void rasterizeFT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeFT_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[L->v.g << 8]; @@ -394,20 +391,20 @@ void rasterizeFT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { int32 tmp = FixedInvU(Lh); Ldx = tmp * (N->v.x - Lx); - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -419,20 +416,20 @@ void rasterizeFT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { int32 tmp = FixedInvU(Rh); Rdx = tmp * (N->v.x - Rx); - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -506,7 +503,7 @@ void rasterizeFT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeGT_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { #ifdef ALIGNED_LIGHTMAP ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned @@ -526,14 +523,14 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { @@ -541,7 +538,7 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Ldx = tmp * (N->v.x - Lx); Ldg = tmp * (N->v.g - Lg) >> 8; - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -554,14 +551,14 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { @@ -569,7 +566,7 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Rdx = tmp * (N->v.x - Rx); Rdg = tmp * (N->v.g - Rg) >> 8; - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -664,7 +661,7 @@ void rasterizeGT_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeFTA_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[L->v.g << 8]; @@ -678,20 +675,20 @@ void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { int32 tmp = FixedInvU(Lh); Ldx = tmp * (N->v.x - Lx); - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -703,20 +700,20 @@ void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { int32 tmp = FixedInvU(Rh); Rdx = tmp * (N->v.x - Rx); - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -801,7 +798,7 @@ void rasterizeFTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) } } -void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeGTA_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { #ifdef ALIGNED_LIGHTMAP ASSERT((intptr_t(lightmap) & 0xFFFF) == 0); // lightmap should be 64k aligned @@ -821,14 +818,14 @@ void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) { while (!Lh) { - const VertexUV* N = L->prev; + const VertexLink* 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; + Lt = L->t.t; if (Lh > 1) { @@ -836,7 +833,7 @@ void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Ldx = tmp * (N->v.x - Lx); Ldg = tmp * (N->v.g - Lg) >> 8; - uint32 duv = N->t.uv - Lt; + uint32 duv = N->t.t - Lt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Ldt = (du & 0xFFFF0000) | (dv >> 16); @@ -849,14 +846,14 @@ void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) while (!Rh) { - const VertexUV* N = R->next; + const VertexLink* 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; + Rt = R->t.t; if (Rh > 1) { @@ -864,7 +861,7 @@ void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) Rdx = tmp * (N->v.x - Rx); Rdg = tmp * (N->v.g - Rg) >> 8; - uint32 duv = N->t.uv - Rt; + uint32 duv = N->t.t - Rt; uint32 du = tmp * int16(duv >> 16); uint32 dv = tmp * int16(duv); Rdt = (du & 0xFFFF0000) | (dv >> 16); @@ -980,7 +977,7 @@ void rasterizeGTA_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) #endif // TODO ARM version -void rasterizeSprite_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R) +void rasterizeSprite_mode4_c(uint16* pixel, const VertexLink* L, const VertexLink* R) { const uint8* ft_lightmap = &lightmap[L->v.g << 8]; @@ -990,14 +987,14 @@ void rasterizeSprite_mode4_c(uint16* pixel, const VertexUV* L, const VertexUV* R int32 h = R->v.y - L->v.y; if (h <= 0 || h >= DIV_TABLE_SIZE) return; - int32 u = L->t.u << 8; - int32 v = L->t.v << 8; + int32 u = L->t.uv.u << 8; + int32 v = L->t.uv.v << 8; int32 iw = FixedInvU(w); int32 ih = FixedInvU(h); - int32 du = (R->t.u << 8) * iw >> 16; - int32 dv = (R->t.v << 8) * ih >> 16; + int32 du = (R->t.uv.u << 8) * iw >> 16; + int32 dv = (R->t.uv.v << 8) * ih >> 16; if (L->v.y < 0) { diff --git a/src/platform/gba/render.cpp b/src/platform/gba/render.cpp index f1cb52f3..50b75135 100644 --- a/src/platform/gba/render.cpp +++ b/src/platform/gba/render.cpp @@ -1,5 +1,19 @@ #include "common.h" +struct Vertex +{ + int16 x, y, z; + uint8 g, clip; +}; + +struct VertexLink +{ + Vertex v; + TexCoord t; + VertexLink* prev; + VertexLink* next; +}; + #if defined(_WIN32) uint16 fb[VRAM_WIDTH * FRAME_HEIGHT]; #elif defined(__GBA__) @@ -15,10 +29,6 @@ #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 @@ -32,60 +42,69 @@ uint16 palette[256]; // IWRAM 0.5k #endif extern uint8 lightmap[256 * 32]; -extern Texture textures[MAX_TEXTURES]; -extern const Sprite* sprites; -extern const uint8* tiles; +extern Level level; extern int32 lightAmbient; extern int32 randTable[MAX_RAND_TABLE]; extern int32 caustics[MAX_CAUSTICS]; extern int32 causticsFrame; const uint8* tile; -const Sprite* sprite; -int32 gVerticesCount = 0; -int32 gFacesCount = 0; // 1 is reserved as OT terminator +int32 gVerticesCount; +int32 gFacesCount; EWRAM_DATA Vertex gVertices[MAX_VERTICES]; // EWRAM 16k EWRAM_DATA Face gFaces[MAX_FACES]; // EWRAM 5k -EWRAM_DATA Face* otFaces[OT_SIZE] = { 0 }; +EWRAM_DATA Face* otFaces[OT_SIZE]; + int32 otMin = OT_SIZE - 1; int32 otMax = 0; bool enableAlphaTest; bool enableClipping; +bool enableMaxSort; + +void setViewport(const RectMinMax &vp) +{ + viewport = vp; +} + +void setPaletteIndex(int32 index) +{ + // TODO +} -bool transformBoxRect(const Bounds* box, Rect* rect) +bool transformBoxRect(const AABBs* box, RectMinMax* rect) { const Matrix &m = matrixGet(); - if ((m[2][3] < VIEW_MIN_F) || (m[2][3] >= VIEW_MAX_F)) { + if ((m.e23 < VIEW_MIN_F) || (m.e23 >= 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 ) + _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 ); + *rect = RectMinMax( INT_MAX, INT_MAX, INT_MIN, INT_MIN ); for (int32 i = 0; i < 8; i++) { - int32 z = DP43(m[2], v[i]); + int32 z = DP43(m.e20, m.e21, m.e22, m.e23, v[i].x, v[i].y, v[i].z); if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { continue; } - int32 x = DP43(m[0], v[i]); - int32 y = DP43(m[1], v[i]); + int32 x = DP43(m.e00, m.e01, m.e02, m.e03, v[i].x, v[i].y, v[i].z); + int32 y = DP43(m.e10, m.e11, m.e12, m.e13, v[i].x, v[i].y, v[i].z); PERSPECTIVE(x, y, z); @@ -103,12 +122,12 @@ bool transformBoxRect(const Bounds* box, Rect* rect) return true; } -int32 rectIsVisible(const Rect* rect) +int32 rectIsVisible(const RectMinMax* rect) { if (rect->x0 > rect->x1 || - rect->x0 > viewport.x1 || - rect->x1 < viewport.x0 || - rect->y0 > viewport.y1 || + 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 || @@ -119,54 +138,23 @@ int32 rectIsVisible(const Rect* rect) return 1; // fully visible } -int32 boxIsVisible(const Bounds* box) +int32 boxIsVisible(const AABBs* box) { - Rect rect; + RectMinMax rect; if (!transformBoxRect(box, &rect)) return 0; // not visible return rectIsVisible(&rect); } -X_INLINE int32 classify(const Vertex &v, const Rect &clip) { + +X_INLINE int32 classify(const Vertex &v, const RectMinMax &clip) +{ return (v.x < clip.x0 ? 1 : 0) | (v.x > clip.x1 ? 2 : 0) | (v.y < clip.y0 ? 4 : 0) | (v.y > clip.y1 ? 8 : 0); } -void transform(int32 vx, int32 vy, int32 vz, int32 vg) -{ - ASSERT(gVerticesCount < MAX_VERTICES); - - Vertex &res = gVertices[gVerticesCount++]; - - const Matrix &m = matrixGet(); - - int32 z = DP43c(m[2], vx, vy, vz); - - if (z < VIEW_MIN_F || z >= VIEW_MAX_F) - { - res.clip = 32; - return; - } - - int32 x = DP43c(m[0], vx, vy, vz); - int32 y = DP43c(m[1], vx, vy, vz); - - res.z = z >> FIXED_SHIFT; - res.g = vg >> 8; - - PERSPECTIVE(x, y, z); - - x = X_CLAMP(x, -GUARD_BAND, GUARD_BAND); - y = X_CLAMP(y, -GUARD_BAND, GUARD_BAND); - - res.x = x + (FRAME_WIDTH >> 1); - res.y = y + (FRAME_HEIGHT >> 1); - - res.clip = classify(res, viewport); // enableClipping ? classify(res, viewport) : 0; TODO fix clip boxes for static meshes -} - void transformRoomVertex(const RoomVertex* v, int32 caustics) { int32 vx = v->x << 10; @@ -189,7 +177,13 @@ void transformRoomVertex(const RoomVertex* v, int32 caustics) const Matrix &m = matrixGet(); - int32 z = DP43c(m[2], vx, vy, vz); + int32 z = DP43(m.e20, m.e21, m.e22, m.e23, vx, vy, vz); + + if (z <= 0) + { + res.clip = 32; + return; + } if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { @@ -219,8 +213,8 @@ void transformRoomVertex(const RoomVertex* v, int32 caustics) res.g = vg >> 8; - int32 x = DP43c(m[0], vx, vy, vz); - int32 y = DP43c(m[1], vx, vy, vz); + int32 x = DP43(m.e00, m.e01, m.e02, m.e03, vx, vy, vz); + int32 y = DP43(m.e10, m.e11, m.e12, m.e13, vx, vy, vz); PERSPECTIVE(x, y, z); @@ -233,13 +227,46 @@ void transformRoomVertex(const RoomVertex* v, int32 caustics) res.clip |= classify(res, viewport); } -void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics) +void transformMeshVertex(int32 vx, int32 vy, int32 vz, int32 vg) +{ + ASSERT(gVerticesCount < MAX_VERTICES); + + Vertex &res = gVertices[gVerticesCount++]; + + const Matrix &m = matrixGet(); + + int32 z = DP43(m.e20, m.e21, m.e22, m.e23, vx, vy, vz); + + if (z < VIEW_MIN_F || z >= VIEW_MAX_F) + { + res.clip = 32; + return; + } + + int32 x = DP43(m.e00, m.e01, m.e02, m.e03, vx, vy, vz); + int32 y = DP43(m.e10, m.e11, m.e12, m.e13, vx, vy, vz); + + res.z = z >> FIXED_SHIFT; + res.g = vg >> 8; + + PERSPECTIVE(x, y, z); + + x = X_CLAMP(x, -GUARD_BAND, GUARD_BAND); + y = X_CLAMP(y, -GUARD_BAND, GUARD_BAND); + + res.x = x + (FRAME_WIDTH >> 1); + res.y = y + (FRAME_HEIGHT >> 1); + + res.clip = classify(res, viewport); // enableClipping ? classify(res, viewport) : 0; TODO fix clip boxes for static meshes +} + +void transformRoom(const RoomVertex* vertices, int32 vCount, bool underwater) { int32 causticsValue = 0; for (int32 i = 0; i < vCount; i++) { - if (applyCaustics) { + if (underwater) { causticsValue = caustics[(randTable[i & (MAX_RAND_TABLE - 1)] + causticsFrame) & (MAX_CAUSTICS - 1)]; } @@ -248,19 +275,19 @@ void transformRoom(const RoomVertex* vertices, int32 vCount, bool applyCaustics) } } -void transformMesh(const vec3s* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal) +void transformMesh(const MeshVertex* vertices, int32 vCount, const uint16* vIntensity, const vec3s* vNormal) { // TODO calc lighting for vNormal for (int32 i = 0; i < vCount; i++) { ASSERT(!vIntensity || (vIntensity[i] + lightAmbient >= 0)); // ohhh, use X_CLAMP... - transform(vertices->x, vertices->y, vertices->z, vIntensity ? X_MIN(vIntensity[i] + lightAmbient, 8191) : lightAmbient); + transformMeshVertex(vertices->x, vertices->y, vertices->z, vIntensity ? X_MIN(vIntensity[i] + lightAmbient, 8191) : lightAmbient); vertices++; } } -VertexUV* clipPoly(VertexUV* poly, VertexUV* tmp, int32 &pCount) +VertexLink* clipPoly(VertexLink* poly, VertexLink* 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) ) @@ -270,16 +297,16 @@ VertexUV* clipPoly(VertexUV* poly, VertexUV* tmp, int32 &pCount) int32 tb = (a->v.X - b->v.X);\ ASSERT(tb != 0);\ int32 t = ta / tb;\ - VertexUV* v = output + count++;\ + VertexLink* v = output + count++;\ v->v.X = edge;\ v->v.Y = LERP2(a->v.Y, b->v.Y, ta, tb);\ 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);\ + v->t.uv.u = LERP(a->t.uv.u, b->t.uv.u, t);\ + v->t.uv.v = LERP(a->t.uv.v, b->t.uv.v, t);\ } #define CLIP_XY(X, Y, X0, X1, input, output) {\ - const VertexUV *a, *b = input + pCount - 1;\ + const VertexLink *a, *b = input + pCount - 1;\ for (int32 i = 0; i < pCount; i++) {\ a = b;\ b = input + i;\ @@ -303,8 +330,8 @@ VertexUV* clipPoly(VertexUV* poly, VertexUV* tmp, int32 &pCount) int32 count = 0; - VertexUV *in = poly; - VertexUV *out = tmp; + VertexLink *in = poly; + VertexLink *out = tmp; // clip x CLIP_XY(x, y, viewport.x0, viewport.x1, in, out); @@ -319,7 +346,12 @@ VertexUV* clipPoly(VertexUV* poly, VertexUV* tmp, int32 &pCount) return in; } -void rasterize(const Face* face, const VertexUV *top) +void renderInit() +{ + // +} + +void rasterize(const Face* face, const VertexLink *top) { uint16* pixel = (uint16*)fb + top->v.y * VRAM_WIDTH; #ifdef DEBUG_OVERDRAW @@ -365,9 +397,9 @@ void rasterize(const Face* face, const VertexUV *top) #endif } -void drawTriangle(const Face* face, VertexUV *v) +void drawTriangle(const Face* face, VertexLink *v) { - VertexUV *v1 = v + 0, + VertexLink *v1 = v + 0, *v2 = v + 1, *v3 = v + 2; @@ -378,7 +410,7 @@ void drawTriangle(const Face* face, VertexUV *v) v2->prev = v1; v3->prev = v2; - const VertexUV* top = v1; + const VertexLink* top = v1; if (v1->v.y < v2->v.y) { if (v1->v.y < v3->v.y) { top = v1; @@ -396,9 +428,9 @@ void drawTriangle(const Face* face, VertexUV *v) rasterize(face, top); } -void drawQuad(const Face* face, VertexUV *v) +void drawQuad(const Face* face, VertexLink *v) { - VertexUV *v1 = v + 0, + VertexLink *v1 = v + 0, *v2 = v + 1, *v3 = v + 2, *v4 = v + 3; @@ -412,7 +444,7 @@ void drawQuad(const Face* face, VertexUV *v) v3->prev = v2; v4->prev = v3; - VertexUV* top; + VertexLink* top; if (v1->v.y < v2->v.y) { if (v1->v.y < v3->v.y) { @@ -431,9 +463,9 @@ void drawQuad(const Face* face, VertexUV *v) rasterize(face, top); } -void drawPoly(Face* face, VertexUV* v) +void drawPoly(Face* face, VertexLink* v) { - VertexUV tmp[16]; + VertexLink tmp[16]; int32 count = (face->flags & FACE_TRIANGLE) ? 3 : 4; @@ -467,7 +499,7 @@ void drawPoly(Face* face, VertexUV* v) return; } - VertexUV* top = v; + VertexLink* top = v; top->next = v + 1; top->prev = v + count - 1; @@ -475,7 +507,7 @@ void drawPoly(Face* face, VertexUV* v) for (int32 i = 1; i < count; i++) { - VertexUV *p = v + i; + VertexLink *p = v + i; p->next = v + (i + 1) % count; p->prev = v + (i - 1 + count) % count; @@ -496,11 +528,8 @@ void drawPoly(Face* face, VertexUV* v) rasterize(face, top); } -void drawSprite(Face* face, VertexUV* v) +void drawSprite(Face* face, VertexLink* v) { - sprite = sprites + face->indices[1]; - tile = tiles + (sprite->tile << 16); - rasterize(face, v); } @@ -514,44 +543,35 @@ void drawGlyph(const Sprite *sprite, int32 x, int32 y) int32 ix = x + sprite->l; int32 iy = y + sprite->t; -#if defined(MODE_PAL) uint16* pixel = (uint16*)fb + iy * VRAM_WIDTH + (ix >> 1); -#else - uint16* pixel = (uint16*)fb + iy * VRAM_WIDTH + ix; -#endif - const uint8* glyphData = tiles + (sprite->tile << 16) + 256 * sprite->v + sprite->u; + const uint16* glyphData = (uint16*)(level.tiles + (sprite->tile << 16) + 256 * sprite->v + sprite->u); while (h--) { - #if defined(MODE_PAL) - const uint8* p = glyphData; + const uint16* p = glyphData; for (int32 i = 0; i < (w / 2); i++) { - if (p[0] || p[1]) + if (p[0]) { - uint16 d = pixel[i]; - - if (p[0]) d = (d & 0xFF00) | p[0]; - if (p[1]) d = (d & 0x00FF) | (p[1] << 8); - - pixel[i] = d; + if (p[0] & 0x00FF) { + if (p[0] & 0xFF00) { + pixel[i] = p[0]; + } else { + pixel[i] = (pixel[i] & 0xFF00) | p[0]; + } + } else { + pixel[i] = (pixel[i] & 0x00FF) | p[0]; + } } - p += 2; - } - #else - for (int32 i = 0; i < w; i++) - { - if (glyphData[i] == 0) continue; - pixel[i] = palette[glyphData[i]]; + p++; } - #endif pixel += VRAM_WIDTH; - glyphData += 256; + glyphData += 256 / 2; } } @@ -594,7 +614,12 @@ void faceAddQuad(uint32 flags, const Index* indices, int32 startVertex) flags |= FACE_FLAT; } - int32 depth = X_MAX(v1->z, X_MAX(v2->z, X_MAX(v3->z, v4->z))) >> OT_SHIFT; + int32 depth; + if (enableMaxSort) { + depth = X_MAX(v1->z, X_MAX(v2->z, X_MAX(v3->z, v4->z))) >> OT_SHIFT; + } else { + depth = (v1->z + v2->z + v3->z + v4->z) >> (2 + OT_SHIFT); + } Face* f = faceAdd(depth); f->flags = uint16(flags); @@ -628,7 +653,12 @@ void faceAddTriangle(uint32 flags, const Index* indices, int32 startVertex) flags |= FACE_FLAT; } - int32 depth = X_MAX(v1->z, X_MAX(v2->z, v3->z)) >> OT_SHIFT; + int32 depth; + if (enableMaxSort) { + depth = X_MAX(v1->z, X_MAX(v2->z, v3->z)) >> OT_SHIFT; + } else { + depth = (v1->z + v2->z + v3->z + v3->z) >> (2 + OT_SHIFT); + } Face* f = faceAdd(depth); f->flags = uint16(flags | FACE_TRIANGLE); @@ -641,7 +671,11 @@ void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index) { const Matrix &m = matrixGet(); - int32 z = DP43c(m[2], vx, vy, vz); + vx -= cameraViewPos.x; + vy -= cameraViewPos.y; + vz -= cameraViewPos.z; + + int32 z = DP33(m.e20, m.e21, m.e22, vx, vy, vz); if (z < VIEW_MIN_F || z >= VIEW_MAX_F) { @@ -650,10 +684,10 @@ void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index) ASSERT(gFacesCount < MAX_FACES); - int32 x = DP43c(m[0], vx, vy, vz); - int32 y = DP43c(m[1], vx, vy, vz); + int32 x = DP33(m.e00, m.e01, m.e02, vx, vy, vz); + int32 y = DP33(m.e10, m.e11, m.e12, vx, vy, vz); - const Sprite* sprite = sprites + index; + const Sprite* sprite = level.sprites + index; int32 l = x + (sprite->l << FIXED_SHIFT); int32 r = x + (sprite->r << FIXED_SHIFT); @@ -714,40 +748,41 @@ void faceAddSprite(int32 vx, int32 vy, int32 vz, int32 vg, int32 index) f->indices[1] = index; } +void faceAddGlyph(int32 vx, int32 vy, int32 index) +{ + // +} + void faceAddRoom(const Quad* quads, int32 qCount, const Triangle* triangles, int32 tCount, int32 startVertex) { - for (uint16 i = 0; i < qCount; i++) { + for (int32 i = 0; i < qCount; i++) { faceAddQuad(quads[i].flags, quads[i].indices, startVertex); } - for (uint16 i = 0; i < tCount; i++) { + for (int32 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++) { + for (int32 i = 0; i < rCount; i++) { faceAddQuad(rFaces[i].flags, rFaces[i].indices, startVertex); } - for (int i = 0; i < crCount; i++) { + for (int32 i = 0; i < crCount; i++) { faceAddQuad(crFaces[i].flags | FACE_COLORED, crFaces[i].indices, startVertex); } - for (int i = 0; i < tCount; i++) { + for (int32 i = 0; i < tCount; i++) { faceAddTriangle(tFaces[i].flags, tFaces[i].indices, startVertex); } - for (int i = 0; i < ctCount; i++) { + for (int32 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) @@ -762,34 +797,36 @@ void flush() otFaces[i] = NULL; do { - VertexUV v[16]; - uint32 flags = face->flags; + VertexLink v[16]; + if (flags == FACE_SPRITE) { - const Sprite &sprite = sprites[face->indices[1]]; + const Sprite &sprite = level.sprites[face->indices[1]]; v[0].v = gVertices[face->indices[0] + 0]; - v[0].t.u = sprite.u; - v[0].t.v = sprite.v; + v[0].t.uv.u = sprite.u; + v[0].t.uv.v = sprite.v; v[1].v = gVertices[face->indices[0] + 1]; - v[1].t.u = sprite.w; - v[1].t.v = sprite.h; + v[1].t.uv.u = sprite.w; + v[1].t.uv.v = sprite.h; ASSERT(v[0].v.x <= v[1].v.x); ASSERT(v[0].v.y <= v[1].v.y); + tile = level.tiles + (level.sprites[face->indices[1]].tile << 16); + drawSprite(face, v); } else { if (!(flags & FACE_COLORED)) { - const Texture &tex = textures[flags & FACE_TEXTURE]; - tile = tiles + (tex.tile << 16); + const Texture &tex = level.textures[flags & FACE_TEXTURE]; + tile = level.tiles + (tex.tile << 16); - v[0].t.uv = tex.uv0; - v[1].t.uv = tex.uv1; - v[2].t.uv = tex.uv2; - v[3].t.uv = tex.uv3; + v[0].t.t = tex.uv0; + v[1].t.t = tex.uv1; + v[2].t.t = tex.uv2; + v[3].t.t = tex.uv3; enableAlphaTest = (tex.attribute == 1); } @@ -809,9 +846,8 @@ void flush() } else { drawQuad(face, v); } - }; + } } - face = face->next; } while (face); } @@ -820,15 +856,6 @@ void flush() 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 PROFILING #if !defined(PROFILE_FRAMETIME) && !defined(PROFILE_SOUNDTIME) gCounters[CNT_VERT] += gVerticesCount; diff --git a/src/platform/gba/room.h b/src/platform/gba/room.h index 2e257ad0..92328702 100644 --- a/src/platform/gba/room.h +++ b/src/platform/gba/room.h @@ -3,6 +3,13 @@ #include "common.h" +Room* roomsList[MAX_ROOM_LIST]; + +//#ifdef ROM_READ +int32 dynSectorsCount; +EWRAM_DATA Sector dynSectors[MAX_DYN_SECTORS]; // EWRAM 8k +//#endif + void animTexturesShift() { const int16* data = level.animTexData; @@ -13,14 +20,14 @@ void animTexturesShift() { int32 count = *data++; - Texture tmp = textures[*data]; + Texture tmp = level.textures[*data]; while (count > 0) { - textures[data[0]] = textures[data[1]]; + level.textures[data[0]] = level.textures[data[1]]; data++; count--; } - textures[*data++] = tmp; + level.textures[*data++] = tmp; } } @@ -46,18 +53,18 @@ int32 Sector::getFloor(int32 x, int32 y, int32 z) const int32 floor = lowerSector->floor << 8; - gLastFloorSlant.value = 0; + gLastFloorSlant = 0; if (lowerSector->floorIndex) { const FloorData* fd = level.floors + lowerSector->floorIndex; - FloorData::Command cmd = (fd++)->cmd; + uint16 cmd = *fd++; - if (cmd.func == FLOOR_TYPE_FLOOR) // found floor + if (FD_FLOOR_TYPE(cmd) == FLOOR_TYPE_FLOOR) // found floor { gLastFloorSlant = *fd; - int32 sx = fd->slantX; - int32 sz = fd->slantZ; + int32 sx = FD_SLANT_X(gLastFloorSlant); + int32 sz = FD_SLANT_Z(gLastFloorSlant); int32 dx = x & 1023; int32 dz = z & 1023; floor -= sx * (sx < 0 ? dx : (dx - 1023)) >> 2; @@ -79,18 +86,18 @@ int32 Sector::getCeiling(int32 x, int32 y, int32 z) const if (upperSector->floorIndex) { const FloorData* fd = level.floors + upperSector->floorIndex; - FloorData::Command cmd = (fd++)->cmd; + uint16 cmd = *fd++; - if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor + if (FD_FLOOR_TYPE(cmd) == FLOOR_TYPE_FLOOR) // skip floor { fd++; - cmd = (fd++)->cmd; + cmd = *fd++; } - if (cmd.func == FLOOR_TYPE_CEILING) // found ceiling + if (FD_FLOOR_TYPE(cmd) == FLOOR_TYPE_CEILING) // found ceiling { - int32 sx = fd->slantX; - int32 sz = fd->slantZ; + int32 sx = FD_SLANT_X(*fd); + int32 sz = FD_SLANT_Z(*fd); int32 dx = x & 1023; int32 dz = z & 1023; ceiling -= sx * (sx < 0 ? (dx - 1023) : dx) >> 2; @@ -117,28 +124,28 @@ Room* Sector::getNextRoom() const // - other const FloorData* fd = level.floors + floorIndex; - FloorData::Command cmd = (fd++)->cmd; + uint16 cmd = *fd++; - if (cmd.func == FLOOR_TYPE_FLOOR) // skip floor + if (FD_FLOOR_TYPE(cmd) == FLOOR_TYPE_FLOOR) // skip floor { - if (cmd.end) return NULL; + if (FD_END(cmd)) return NULL; fd++; - cmd = (fd++)->cmd; + cmd = *fd++; } - if (cmd.func == FLOOR_TYPE_CEILING) // skip ceiling + if (FD_FLOOR_TYPE(cmd) == FLOOR_TYPE_CEILING) // skip ceiling { - if (cmd.end) return NULL; + if (FD_END(cmd)) return NULL; fd++; - cmd = (fd++)->cmd; + cmd = *fd++; } - if (cmd.func != FLOOR_TYPE_PORTAL) // no portal + if (FD_FLOOR_TYPE(cmd) != FLOOR_TYPE_PORTAL) // no portal return NULL; - ASSERT(fd->value != NO_ROOM); + ASSERT(*fd != NO_ROOM); - return rooms + fd->value; + return rooms + *fd; } void Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int32* ceiling) const @@ -146,13 +153,13 @@ void Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int if (!floorIndex) return; - FloorData::Command cmd; + uint16 cmd; const FloorData* fd = level.floors + floorIndex; do { - cmd = (fd++)->cmd; + cmd = *fd++; - switch (cmd.func) + switch (FD_FLOOR_TYPE(cmd)) { case FLOOR_TYPE_PORTAL: case FLOOR_TYPE_FLOOR: @@ -169,22 +176,22 @@ void Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int } fd++; - FloorData::TriggerCommand trigger; + uint16 trigger; do { - trigger = (fd++)->triggerCmd; + trigger = *fd++; - if (trigger.action == TRIGGER_ACTION_ACTIVATE_OBJECT) + if (FD_ACTION(trigger) == TRIGGER_ACTION_ACTIVATE_OBJECT) { - items[trigger.args].getItemFloorCeiling(x, y, z, floor, ceiling); + items[FD_ARGS(trigger)].getItemFloorCeiling(x, y, z, floor, ceiling); } - if (trigger.action == TRIGGER_ACTION_ACTIVATE_CAMERA) + if (FD_ACTION(trigger) == TRIGGER_ACTION_ACTIVATE_CAMERA) { - trigger = (fd++)->triggerCmd; // skip camera index + trigger = *fd++; // skip camera index } - } while (!trigger.end); + } while (!FD_END(trigger)); break; } @@ -196,7 +203,7 @@ void Sector::getTriggerFloorCeiling(int32 x, int32 y, int32 z, int32* floor, int break; } - } while (!cmd.end); + } while (!FD_END(cmd)); } @@ -215,13 +222,13 @@ const Sector* Room::getWaterSector(int32 x, int32 z) const const Sector* sector = room->getSector(x, z); // go up to the air - if (room->info->flags.water) + if (ROOM_FLAG_WATER(room->info->flags)) { while (sector->roomAbove != NO_ROOM) { room = rooms + sector->roomAbove; - if (!room->info->flags.water) { + if (!ROOM_FLAG_WATER(room->info->flags)) { return sector; } @@ -236,7 +243,7 @@ const Sector* Room::getWaterSector(int32 x, int32 z) const room = rooms + sector->roomBelow; sector = room->getSector(x, z); - if (room->info->flags.water) { + if (ROOM_FLAG_WATER(room->info->flags)) { return sector; } } @@ -277,9 +284,9 @@ Room* Room::getRoom(int32 x, int32 y, int32 z) bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) { cinfo.staticHit = false; - cinfo.offset = vec3i(0); + cinfo.offset = _vec3i(0, 0, 0); - Bounds objBox; + AABBs objBox; objBox.minX = -cinfo.radius; objBox.maxX = cinfo.radius; objBox.minZ = -cinfo.radius; @@ -298,16 +305,16 @@ bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) const RoomMesh* mesh = room->data.meshes + i; #ifdef NO_STATIC_MESH_PLANTS - if (mesh->id < 10) + if (STATIC_MESH_ID(mesh->flags) < 10) continue; #endif - const StaticMesh* staticMesh = staticMeshes + mesh->id; + const StaticMesh* staticMesh = level.staticMeshes + STATIC_MESH_ID(mesh->flags); if (staticMesh->flags & STATIC_MESH_FLAG_NO_COLLISION) continue; - Bounds meshBox = boxRotate(staticMesh->cbox, (mesh->rot - 2) * ANGLE_90); + AABBs meshBox = boxRotate(staticMesh->cbox, STATIC_MESH_ROT(mesh->flags)); // TODO align RoomInfo::Mesh (room relative int16?) vec3i pos; @@ -336,7 +343,7 @@ bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) cinfo.offset.x = 0; cinfo.type = ((cinfo.offset.z > 0) ^ flip) ? CT_RIGHT : CT_LEFT; } else { - cinfo.offset = vec3i(0); + cinfo.offset = _vec3i(0, 0, 0); } } else { if (abs(cinfo.offset.x) > cinfo.radius) { @@ -348,7 +355,7 @@ bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) cinfo.offset.z = 0; cinfo.type = ((cinfo.offset.x > 0) ^ flip) ? CT_LEFT : CT_RIGHT; } else { - cinfo.offset = vec3i(0); + cinfo.offset = _vec3i(0, 0, 0); } } @@ -361,6 +368,180 @@ bool Room::collideStatic(CollisionInfo &cinfo, const vec3i &p, int32 height) return false; } +#ifdef __3DO__ +bool Room::checkPortal(const Portal* portal, vec3i* points) +{ + int32 x0 = clip.x1; + int32 y0 = clip.y1; + int32 x1 = clip.x0; + int32 y1 = clip.y0; + + int32 znear = 0, zfar = 0; + + for (int32 i = 0; i < 4; i++) + { + int32 x = points[i].x; + int32 y = points[i].y; + int32 z = points[i].z; + + if (z <= 0) { + points[i].x = -points[i].x; + points[i].y = -points[i].y; + znear++; + continue; + } + + if (z >= (VIEW_MAX_F >> FIXED_SHIFT)) { + zfar++; + } + + x += FRAME_WIDTH >> 1; + y += FRAME_HEIGHT >> 1; + + 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) + { + const vec3i *a = points; + const vec3i *b = points + 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) +{ + uint32 vis[MAX_PORTALS]; + vec3i vertices[MAX_PORTALS * 4]; + + int32 cx = cameraViewPos.x - (info->x << 8); + int32 cy = cameraViewPos.y; + int32 cz = cameraViewPos.z - (info->z << 8); + + const Portal* portal = data.portals; + vec3i* v = (vec3i*)vertices; + int32 vCount = 0; + + for (int32 i = 0; i < info->portalsCount; i++, portal++) + { + int32 axis = 0; + int32 x = (portal->v[0].x - cx) << F16_SHIFT; + if (x > 0) axis |= (2 << 0); + if (x < 0) axis |= (1 << 0); + int32 y = (portal->v[0].y - cy) << F16_SHIFT; + if (y > 0) axis |= (2 << 2); + if (y < 0) axis |= (1 << 2); + int32 z = (portal->v[0].z - cz) << F16_SHIFT; + if (z > 0) axis |= (2 << 4); + if (z < 0) axis |= (1 << 4); + + vis[i] = (portal->normalMask & axis); + + if (!vis[i]) + continue; + + v->x = x; + v->y = y; + v->z = z; + v++; + + v->x = (portal->v[1].x - cx) << F16_SHIFT; + v->y = (portal->v[1].y - cy) << F16_SHIFT; + v->z = (portal->v[1].z - cz) << F16_SHIFT; + v++; + + v->x = (portal->v[2].x - cx) << F16_SHIFT; + v->y = (portal->v[2].y - cy) << F16_SHIFT; + v->z = (portal->v[2].z - cz) << F16_SHIFT; + v++; + + v->x = (portal->v[3].x - cx) << F16_SHIFT; + v->y = (portal->v[3].y - cy) << F16_SHIFT; + v->z = (portal->v[3].z - cz) << F16_SHIFT; + v++; + + vCount += 4; + } + + if (!vCount) + return list; + + transform((vec3i*)vertices, vCount); + + portal = data.portals; + v = (vec3i*)vertices; + + for (int32 i = 0; i < info->portalsCount; i++, portal++) + { + if (!vis[i]) + continue; + + if (checkPortal(portal, v)) + { + Room* nextRoom = rooms + portal->roomIndex; + + list = nextRoom->addVisibleRoom(list); + + if (!nextRoom->visible) + { + nextRoom->visible = true; + *list++ = nextRoom; + } + } + + v += 4; + } + + return list; +} +#else bool Room::checkPortal(const Portal* portal) { vec3i d; @@ -368,8 +549,25 @@ bool Room::checkPortal(const Portal* portal) d.y = portal->v[0].y - cameraViewPos.y; d.z = portal->v[0].z - cameraViewPos.z + (info->z << 8); - if (DP33(portal->n, d) >= 0) + Matrix &m = matrixGet(); + + vec3i pv[4]; + +#ifdef __3DO__ + int32 axis = 0; + if (d.x > 0) axis |= (2 << 0); + if (d.x < 0) axis |= (1 << 0); + if (d.y > 0) axis |= (2 << 2); + if (d.y < 0) axis |= (1 << 2); + if (d.z > 0) axis |= (2 << 4); + if (d.z < 0) axis |= (1 << 4); + + if (!(portal->normalMask & axis)) return false; +#else + if (DP33(portal->n.x, portal->n.y, portal->n.z, d.x, d.y, d.z) >= 0) + return false; +#endif int32 x0 = clip.x1; int32 y0 = clip.y1; @@ -378,40 +576,39 @@ bool Room::checkPortal(const Portal* portal) 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 px = portal->v[i].x; + int32 py = portal->v[i].y; + int32 pz = portal->v[i].z; - int32 x = DP43(m[0], v); - int32 y = DP43(m[1], v); - int32 z = DP43(m[2], v); + int32 x = DP43(m.e00, m.e01, m.e02, m.e03, px, py, pz); + int32 y = DP43(m.e10, m.e11, m.e12, m.e13, px, py, pz); + int32 z = DP43(m.e20, m.e21, m.e22, m.e23, px, py, pz); pv[i].x = x; pv[i].y = y; pv[i].z = z; - if (z <= VIEW_MIN_F) { + if (z <= 0) { znear++; continue; } - if (z >= VIEW_MAX_F) { + if (z >= VIEW_MAX_F) + { z = VIEW_MAX_F; zfar++; } - if (z != 0) { + int32 dz = (z >> (FIXED_SHIFT + FOV_SHIFT + 1)); + if (dz > 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; + x = (x < 0) ? viewport.x0 : viewport.x1; + y = (y < 0) ? viewport.y0 : viewport.y1; } if (x < x0) x0 = x; @@ -499,12 +696,11 @@ Room** Room::addVisibleRoom(Room** list) return list; } +#endif Room** Room::getVisibleRooms() { - Room** list = roomsList; - - list = addVisibleRoom(list); + Room** list = addVisibleRoom(roomsList); *list++ = this; *list++ = NULL; @@ -516,7 +712,7 @@ Room** Room::getVisibleRooms() void Room::reset() { visible = false; - clip = Rect( FRAME_WIDTH, FRAME_HEIGHT, 0, 0 ); + clip = RectMinMax( FRAME_WIDTH, FRAME_HEIGHT, 0, 0 ); } Room** Room::addNearRoom(Room** list, int32 x, int32 y, int32 z) @@ -571,6 +767,7 @@ Room** Room::getAdjRooms() void Room::modify() { +//#ifdef ROM_READ if (sectors == data.sectors) { // convert room->sectors to mutable (non-ROM) data @@ -581,9 +778,10 @@ void Room::modify() //printf("dynSectors: %d\n", dynSectorsCount); ASSERT(dynSectorsCount <= MAX_DYN_SECTORS); } +//#endif } -void Room::add(Item* item) +void Room::add(ItemObj* item) { ASSERT(item && item->nextItem == NULL); @@ -592,16 +790,16 @@ void Room::add(Item* item) firstItem = item; } -void Room::remove(Item* item) +void Room::remove(ItemObj* item) { ASSERT(item && item->room == this); - Item* prev = NULL; - Item* curr = firstItem; + ItemObj* prev = NULL; + ItemObj* curr = firstItem; while (curr) { - Item* next = curr->nextItem; + ItemObj* next = curr->nextItem; if (curr == item) { @@ -621,4 +819,505 @@ void Room::remove(Item* item) } } +#define TRACE_SHIFT 10 // trace precision + +#define TRACE_CHECK(r, x, y, z) \ +{ \ + const Sector* sector = r->getSector(x, z); \ + if (accurate) { \ + if (y > sector->getFloor(x, y, z) || y < sector->getCeiling(x, y, z)) \ + { \ + to.pos = p; \ + to.room = room; \ + return false; \ + } \ + } else { \ + if (y > (sector->floor << 8) || y < (sector->ceiling << 8)) \ + { \ + to.pos = p; \ + to.room = room; \ + return false; \ + } \ + } \ +} + +bool traceX(const Location &from, Location &to, bool accurate) +{ + vec3i d = to.pos - from.pos; + + if (!d.x) + return true; + + d.y = (d.y << TRACE_SHIFT) / d.x; + d.z = (d.z << TRACE_SHIFT) / d.x; + + vec3i p = from.pos; + + Room* room = from.room; + + if (d.x < 0) + { + d.x = 1024; + p.x &= ~1023; + p.y += d.y * (p.x - from.pos.x) >> TRACE_SHIFT; + p.z += d.z * (p.x - from.pos.x) >> TRACE_SHIFT; + + while (p.x > to.pos.x) + { + room = room->getRoom(p.x, p.y, p.z); + TRACE_CHECK(room, p.x, p.y, p.z); + + Room* nextRoom = room->getRoom(p.x - 1, p.y, p.z); + TRACE_CHECK(nextRoom, p.x - 1, p.y, p.z); + + room = nextRoom; + p -= d; + } + } + else + { + d.x = 1024; + p.x |= 1023; + p.y += d.y * (p.x - from.pos.x) >> TRACE_SHIFT; + p.z += d.z * (p.x - from.pos.x) >> TRACE_SHIFT; + + while (p.x < to.pos.x) + { + room = room->getRoom(p.x, p.y, p.z); + TRACE_CHECK(room, p.x, p.y, p.z); + + Room* nextRoom = room->getRoom(p.x + 1, p.y, p.z); + TRACE_CHECK(nextRoom, p.x + 1, p.y, p.z); + + room = nextRoom; + p += d; + } + } + + to.room = room; + + return true; +} + +bool traceZ(const Location &from, Location &to, bool accurate) +{ + vec3i d = to.pos - from.pos; + + if (!d.z) + return true; + + d.x = (d.x << TRACE_SHIFT) / d.z; + d.y = (d.y << TRACE_SHIFT) / d.z; + + vec3i p = from.pos; + + Room* room = from.room; + + if (d.z < 0) + { + d.z = 1024; + p.z &= ~1023; + p.x += d.x * (p.z - from.pos.z) >> TRACE_SHIFT; + p.y += d.y * (p.z - from.pos.z) >> TRACE_SHIFT; + + while (p.z > to.pos.z) + { + room = room->getRoom(p.x, p.y, p.z); + TRACE_CHECK(room, p.x, p.y, p.z); + + Room* nextRoom = room->getRoom(p.x, p.y, p.z - 1); + TRACE_CHECK(nextRoom, p.x, p.y, p.z - 1); + + room = nextRoom; + p -= d; + } + } + else + { + d.z = 1024; + p.z |= 1023; + p.x += d.x * (p.z - from.pos.z) >> TRACE_SHIFT; + p.y += d.y * (p.z - from.pos.z) >> TRACE_SHIFT; + + while (p.z < to.pos.z) + { + room = room->getRoom(p.x, p.y, p.z); + TRACE_CHECK(room, p.x, p.y, p.z); + + Room* nextRoom = room->getRoom(p.x, p.y, p.z + 1); + TRACE_CHECK(nextRoom, p.x, p.y, p.z + 1); + + room = nextRoom; + p += d; + } + } + + to.room = room; + + return true; +} + +#undef TRACE_CHECK + +bool trace(const Location &from, Location &to, bool accurate) +{ + int32 dx = abs(to.pos.x - from.pos.x); + int32 dz = abs(to.pos.z - from.pos.z); + int32 dy; + + bool res; + + if (dz > dx) { + res = traceX(from, to, accurate); + if (!traceZ(from, to, accurate)) + return false; + } else { + res = traceZ(from, to, accurate); + if (!traceX(from, to, accurate)) + return false; + } + + dy = to.pos.y - from.pos.y; + + if (dy) + { + const Sector* sector = to.room->getSector(to.pos.x, to.pos.z); + + int32 h = sector->getFloor(to.pos.x, to.pos.y, to.pos.z); + if (to.pos.y <= h || from.pos.y >= h) + { + h = sector->getCeiling(to.pos.x, to.pos.y, to.pos.z); + if (to.pos.y >= h || from.pos.y <= h) + { + h = WALL; + } + } + + if (h != WALL) + { + to.pos.y = h; + h -= from.pos.y; + to.pos.x = from.pos.x + (to.pos.x - from.pos.x) * h / dy; + to.pos.z = from.pos.z + (to.pos.z - from.pos.z) * h / dy; + return false; + } + } + + return res; +} + +void checkCamera(const FloorData* fd, Camera* camera) +{ + bool lookAt = false; + + while (1) + { + uint16 triggerCmd = *fd++; + + switch (FD_ACTION(triggerCmd)) + { + case TRIGGER_ACTION_ACTIVATE_CAMERA: + { + FD_SET_END(triggerCmd, FD_END(*fd++)); + + if (FD_ARGS(triggerCmd) != camera->lastIndex) + { + camera->lookAtItem = NULL; + return; + } + + camera->index = FD_ARGS(triggerCmd); + + if (camera->timer < 0 || camera->mode == CAMERA_MODE_LOOK || camera->mode == CAMERA_MODE_COMBAT) + { + camera->timer = -1; + camera->lookAtItem = NULL; + return; + } + + camera->mode = CAMERA_MODE_FIXED; + lookAt = true; + break; + } + + case TRIGGER_ACTION_CAMERA_TARGET: + { + if (camera->mode == CAMERA_MODE_LOOK || camera->mode == CAMERA_MODE_COMBAT) + break; + + ASSERT(FD_ARGS(triggerCmd) < level.itemsCount); + camera->lookAtItem = items + FD_ARGS(triggerCmd); + break; + } + + case TRIGGER_ACTION_FLYBY: + { + FD_SET_END(triggerCmd, FD_END(*fd++)); + break; + } + } + + if (FD_END(triggerCmd)) + break; + }; + + if (!lookAt && camera->lookAtItem && camera->lookAtItem != camera->lastItem && camera->lookAtItem->flags.animated) { + camera->lookAtItem = NULL; + } +} + +void checkTrigger(const FloorData* fd, ItemObj* lara) +{ + if (!fd) + return; + + if (FD_FLOOR_TYPE(*fd) == FLOOR_TYPE_LAVA) + { + // TODO lava + + if (FD_END(*fd)) + return; + + fd++; + } + + uint16 cmd = *fd++; + uint16 data = *fd++; + + ItemObj* switchItem = NULL; + ItemObj* cameraItem = NULL; + + Camera* camera = lara ? &lara->extraL->camera : &playersExtra[0].camera; + + if (camera->mode != CAMERA_MODE_OBJECT) { + checkCamera(fd, camera); + } + + if (!lara && FD_TRIGGER_TYPE(cmd) != TRIGGER_TYPE_OBJECT) + return; + + if (lara) + { + switch (FD_TRIGGER_TYPE(cmd)) + { + case TRIGGER_TYPE_ACTIVATE: + break; + + case TRIGGER_TYPE_PAD: + case TRIGGER_TYPE_ANTIPAD: + { + if (lara->pos.y != lara->roomFloor) + return; + break; + } + + case TRIGGER_TYPE_SWITCH: + { + switchItem = items + FD_ARGS(*fd); + if (!useSwitch(switchItem, FD_TIMER(data))) + return; + fd++; + break; + } + + case TRIGGER_TYPE_KEY: + { + ItemObj* keyItem = items + FD_ARGS(*fd); + if (!useKey(keyItem, lara)) + return; + fd++; + break; + } + + case TRIGGER_TYPE_PICKUP: + { + ItemObj* pickupItem = items + FD_ARGS(*fd); + if (!usePickup(pickupItem)) + return; + fd++; + break; + } + + case TRIGGER_TYPE_OBJECT: + return; + + case TRIGGER_TYPE_COMBAT: + { + if (lara->extraL->weaponState != WEAPON_STATE_READY) + return; + break; + } + + case TRIGGER_TYPE_DUMMY: + return; + } + } + + while (1) + { + uint16 triggerCmd = *fd++; + + switch (FD_ACTION(triggerCmd)) + { + case TRIGGER_ACTION_ACTIVATE_OBJECT: + { + ASSERT(FD_ARGS(triggerCmd) < level.itemsCount); + ItemObj* item = items + FD_ARGS(triggerCmd); + + if (item->flags.once) + break; + + item->timer = FD_TIMER(data); + if (item->timer != 1) { + item->timer *= 30; + } + + if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_SWITCH) { + item->flags.mask ^= FD_MASK(data); + } else if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_ANTIPAD) { + item->flags.mask &= ~FD_MASK(data); + } else { + item->flags.mask |= FD_MASK(data); + } + + if (item->flags.mask != ITEM_FLAGS_MASK_ALL) + break; + + item->flags.once |= FD_ONCE(data); + + if (item->flags.active) + break; + + item->activate(); + + if ((item->flags.status == ITEM_FLAGS_STATUS_NONE) && item->flags.active) { + item->flags.status = ITEM_FLAGS_STATUS_ACTIVE; + } + + break; + } + + case TRIGGER_ACTION_ACTIVATE_CAMERA: + { + uint16 cam = *fd++; + FD_SET_END(triggerCmd, FD_END(cam)); + + if (level.cameras[FD_ARGS(triggerCmd)].flags.once) + break; + + camera->index = FD_ARGS(triggerCmd); + + if (camera->mode == CAMERA_MODE_LOOK || camera->mode == CAMERA_MODE_COMBAT) + break; + + if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_COMBAT) + break; + + if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_SWITCH && (switchItem->state == 1) && (FD_TIMER(data) != 0)) + break; + + if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_SWITCH || camera->index != camera->lastIndex) + { + camera->timer = FD_TIMER(cam); + if (camera->timer != 1) { + camera->timer *= 30; + } + + if (FD_ONCE(cam)) { + level.cameras[camera->index].flags.once = true; + } + + camera->speed = (FD_SPEED(cam) << 3) + 1; + camera->mode = lara ? CAMERA_MODE_FIXED : CAMERA_MODE_OBJECT; + } + 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: + { + cameraItem = items + FD_ARGS(triggerCmd); + break; + } + + case TRIGGER_ACTION_END: + // TODO go to the next level + break; + + case TRIGGER_ACTION_SOUNDTRACK: + { + int32 track = doTutorial(lara, FD_ARGS(triggerCmd)); + + if (track == 0) break; + + SaveGame::TrackFlags &flags = gSaveGame.tracks[track]; + + if (flags.once) + break; + + if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_SWITCH) + flags.mask ^= FD_MASK(data); + else if (FD_TRIGGER_TYPE(cmd) == TRIGGER_TYPE_ANTIPAD) + flags.mask &= ~FD_MASK(data); + else + flags.mask |= FD_MASK(data); + + if (flags.mask == ITEM_FLAGS_MASK_ALL) { + flags.once |= FD_ONCE(data); + musicPlay(track); + } else { + musicStop(); + } + break; + } + + case TRIGGER_ACTION_EFFECT: + // TODO effect + break; + + case TRIGGER_ACTION_SECRET: + { + if (gSaveGame.secrets & (1 << FD_ARGS(triggerCmd))) + break; + gSaveGame.secrets |= (1 << FD_ARGS(triggerCmd)); + musicPlay(13); + break; + } + + case TRIGGER_ACTION_CLEAR_BODIES: + break; + + case TRIGGER_ACTION_FLYBY: + FD_SET_END(triggerCmd, FD_END(*fd++)); + break; + + case TRIGGER_ACTION_CUTSCENE: + break; + } + + if (FD_END(triggerCmd)) + break; + }; + + if (cameraItem && (camera->mode == CAMERA_MODE_FIXED || camera->mode == CAMERA_MODE_OBJECT)) + { + camera->lookAtItem = cameraItem; + } +} + #endif diff --git a/src/platform/gba/sound.h b/src/platform/gba/sound.h index 4f8d6147..324a7cc5 100644 --- a/src/platform/gba/sound.h +++ b/src/platform/gba/sound.h @@ -121,6 +121,11 @@ struct Mixer } } + void stopSamples() + { + channelsCount = 0; + } + void playMusic(const void* data, int32 size) { music.data = (uint8*)data;