Final before release

This commit is contained in:
2025-04-07 22:18:28 +02:00
parent bc0795ed29
commit febb6f3f80
10 changed files with 104 additions and 43 deletions

Binary file not shown.

View File

@@ -6,6 +6,7 @@
namespace psxsplash {
// Camera class for managing 3D position and rotation.
class Camera {
public:
Camera();

View File

@@ -1,3 +1,4 @@
#pragma once
#include <psyqo/matrix.hh>
namespace psxsplash {

View File

@@ -30,11 +30,12 @@ class PSXSplash final : public psyqo::Application {
void createScene() override;
public:
psyqo::Font<> m_font;
psyqo::AdvancedPad m_input;
psxsplash::SplashPackLoader m_loader;
static constexpr uint8_t m_stickDeadzone = 0x30;
psyqo::Font<> m_font;
psyqo::AdvancedPad m_input;
static constexpr uint8_t m_stickDeadzone = 0x30;
};
class MainScene final : public psyqo::Scene {
@@ -49,12 +50,17 @@ class MainScene final : public psyqo::Scene {
static constexpr psyqo::FixedPoint<12> moveSpeed = 0.002_fp;
static constexpr psyqo::Angle rotSpeed = 0.01_pi;
bool m_sprinting = 0;
static constexpr psyqo::FixedPoint<12> sprintSpeed = 0.003_fp;
bool m_sprinting = false;
static constexpr psyqo::FixedPoint<12> sprintSpeed = 0.01_fp;
bool m_freecam = false;
psyqo::FixedPoint<12> pheight = 0.0_fp;
bool m_renderSelect = false;
};
PSXSplash psxSplash;
PSXSplash app;
MainScene mainScene;
} // namespace
@@ -78,11 +84,32 @@ void PSXSplash::createScene() {
}
void MainScene::start(StartReason reason) {
psxSplash.m_loader.LoadSplashpack(_binary_output_bin_start);
app.m_loader.LoadSplashpack(_binary_output_bin_start);
psxsplash::Renderer::GetInstance().SetCamera(m_mainCamera);
}
psyqo::FixedPoint<12> pheight = 0.0_fp;
m_mainCamera.SetPosition(static_cast<psyqo::FixedPoint<12>>(app.m_loader.playerStartPos.x),
static_cast<psyqo::FixedPoint<12>>(app.m_loader.playerStartPos.y),
static_cast<psyqo::FixedPoint<12>>(app.m_loader.playerStartPos.z));
pheight = psyqo::FixedPoint<12>(app.m_loader.playerHeight);
app.m_input.setOnEvent(
eastl::function<void(psyqo::AdvancedPad::Event)>{[this](const psyqo::AdvancedPad::Event& event) {
if (event.pad != psyqo::AdvancedPad::Pad::Pad1a) return;
if (app.m_loader.navmeshes.empty()) return;
if (event.type == psyqo::AdvancedPad::Event::ButtonPressed) {
if (event.button == psyqo::AdvancedPad::Button::Triangle) {
m_freecam = !m_freecam;
} else if (event.button == psyqo::AdvancedPad::Button::Square) {
m_renderSelect = !m_renderSelect;
}
}
}});
if (app.m_loader.navmeshes.empty()) {
m_freecam = true;
}
}
void MainScene::frame() {
uint32_t beginFrame = gpu().now();
@@ -96,62 +123,68 @@ void MainScene::frame() {
mainScene.m_lastFrameCounter = currentFrameCounter;
uint8_t rightX = psxSplash.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 0);
uint8_t rightY = psxSplash.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 1);
uint8_t rightX = app.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 0);
uint8_t rightY = app.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 1);
uint8_t leftX = psxSplash.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 2);
uint8_t leftY = psxSplash.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 3);
uint8_t leftX = app.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 2);
uint8_t leftY = app.m_input.getAdc(psyqo::AdvancedPad::Pad::Pad1a, 3);
int16_t rightXOffset = (int16_t)rightX - 0x80;
int16_t rightYOffset = (int16_t)rightY - 0x80;
int16_t leftXOffset = (int16_t)leftX - 0x80;
int16_t leftYOffset = (int16_t)leftY - 0x80;
if(__builtin_abs(leftXOffset) < psxSplash.m_stickDeadzone &&
__builtin_abs(leftYOffset) < psxSplash.m_stickDeadzone) {
if (__builtin_abs(leftXOffset) < app.m_stickDeadzone &&
__builtin_abs(leftYOffset) < app.m_stickDeadzone) {
m_sprinting = false;
}
if(psxSplash.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::L3)) {
if (app.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::L3)) {
m_sprinting = true;
}
psyqo::FixedPoint<12> speed = m_sprinting ? sprintSpeed : moveSpeed;
if (__builtin_abs(rightXOffset) > psxSplash.m_stickDeadzone) {
if (__builtin_abs(rightXOffset) > app.m_stickDeadzone) {
camRotY += (rightXOffset * rotSpeed * deltaTime) >> 7;
}
if (__builtin_abs(rightYOffset) > psxSplash.m_stickDeadzone) {
if (__builtin_abs(rightYOffset) > app.m_stickDeadzone) {
camRotX -= (rightYOffset * rotSpeed * deltaTime) >> 7;
camRotX = eastl::clamp(camRotX, -0.5_pi, 0.5_pi);
}
m_mainCamera.SetRotation(camRotX, camRotY, camRotZ);
if (__builtin_abs(leftYOffset) > psxSplash.m_stickDeadzone) {
if (__builtin_abs(leftYOffset) > app.m_stickDeadzone) {
psyqo::FixedPoint<12> forward = -(leftYOffset * speed * deltaTime) >> 7;
m_mainCamera.MoveX((m_trig.sin(camRotY) * forward));
m_mainCamera.MoveZ((m_trig.cos(camRotY) * forward));
}
if (__builtin_abs(leftXOffset) > psxSplash.m_stickDeadzone) {
psyqo::FixedPoint<12> strafe = -(leftXOffset * speed * deltaTime) >> 7;
if (__builtin_abs(leftXOffset) > app.m_stickDeadzone) {
psyqo::FixedPoint<12> strafe = -(leftXOffset * speed * deltaTime) >> 7;
m_mainCamera.MoveX(-(m_trig.cos(camRotY) * strafe));
m_mainCamera.MoveZ((m_trig.sin(camRotY) * strafe));
}
if(psxSplash.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::L1)) {
pheight += 0.01_fp;
if (app.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::L1)) {
m_mainCamera.MoveY(speed * deltaTime);
}
if(psxSplash.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::R1)) {
pheight -= 0.01_fp;
if (app.m_input.isButtonPressed(psyqo::AdvancedPad::Pad::Pad1a, psyqo::AdvancedPad::Button::R1)) {
m_mainCamera.MoveY(-speed * deltaTime);
}
psyqo::Vec3 adjustedPosition =
psxsplash::ComputeNavmeshPosition(m_mainCamera.GetPosition(), *psxSplash.m_loader.navmeshes[0], -0.05_fp);
m_mainCamera.SetPosition(adjustedPosition.x, adjustedPosition.y, adjustedPosition.z);
if (!m_freecam) {
psyqo::Vec3 adjustedPosition =
psxsplash::ComputeNavmeshPosition(m_mainCamera.GetPosition(), *app.m_loader.navmeshes[0], -pheight);
m_mainCamera.SetPosition(adjustedPosition.x, adjustedPosition.y, adjustedPosition.z);
}
psxsplash::Renderer::GetInstance().Render(psxSplash.m_loader.gameObjects);
// psxsplash::Renderer::getInstance().renderNavmeshPreview(*psxSplash.m_loader.navmeshes[0], true);
psxSplash.m_font.chainprintf(gpu(), {{.x = 2, .y = 2}}, {{.r = 0xff, .g = 0xff, .b = 0xff}}, "FPS: %i",
if (!m_renderSelect) {
psxsplash::Renderer::GetInstance().Render(app.m_loader.gameObjects);
} else {
psxsplash::Renderer::GetInstance().RenderNavmeshPreview(*app.m_loader.navmeshes[0], true);
}
app.m_font.chainprintf(gpu(), {{.x = 2, .y = 2}}, {{.r = 0xff, .g = 0xff, .b = 0xff}}, "FPS: %i",
gpu().getRefreshRate() / deltaTime);
gpu().pumpCallbacks();
@@ -159,4 +192,4 @@ void MainScene::frame() {
uint32_t spent = endFrame - beginFrame;
}
int main() { return psxSplash.run(); }
int main() { return app.run(); }

View File

@@ -7,6 +7,9 @@
using namespace psyqo::fixed_point_literals;
// FIXME: This entire file uses hard FixedPoint scaling of 100. This is not ideal.
// It would be better to move the fixedpoint precision to 19 instead.
namespace psxsplash {
psyqo::FixedPoint<12> DotProduct2D(const psyqo::Vec2& a, const psyqo::Vec2& b) { return a.x * b.x + a.y * b.y; }

View File

@@ -1,6 +1,6 @@
#pragma once
#include "psyqo/gte-registers.hh"
#include <psyqo/vector.hh>
namespace psxsplash {

View File

@@ -1,5 +1,6 @@
#include "renderer.hh"
#include <EASTL/array.h>
#include <EASTL/vector.h>
#include <cstdint>
@@ -14,9 +15,7 @@
#include <psyqo/trigonometry.hh>
#include <psyqo/vector.hh>
#include "EASTL/array.h"
#include "gtemath.hh"
#include "splashpack.hh"
using namespace psyqo::fixed_point_literals;
using namespace psyqo::trig_literals;
@@ -46,7 +45,6 @@ void psxsplash::Renderer::Init(psyqo::GPU &gpuInstance) {
void psxsplash::Renderer::SetCamera(psxsplash::Camera &camera) { m_currentCamera = &camera; }
void psxsplash::Renderer::Render(eastl::vector<GameObject *> &objects) {
psyqo::Kernel::assert(m_currentCamera != nullptr, "PSXSPLASH: Tried to render without an active camera");
@@ -189,6 +187,10 @@ void psxsplash::Renderer::RenderNavmeshPreview(psxsplash::Navmesh navmesh, bool
zIndex = eastl::max(eastl::max(sz0, sz1), sz2);
if (zIndex < 0 || zIndex >= ORDERING_TABLE_SIZE) continue;
read<Register::SXY0>(&projected[0].packed);
read<Register::SXY1>(&projected[1].packed);
read<Register::SXY2>(&projected[2].packed);
auto &prim = balloc.allocateFragment<psyqo::Prim::Triangle>();
prim.primitive.pointA = projected[0];
@@ -244,6 +246,11 @@ void psxsplash::Renderer::recursiveSubdivideAndRender(Tri &tri, eastl::array<psy
if (maxIterations == 0 || ((width < 512 && height < 256 && !leavingScreenSpace))) {
auto &balloc = m_ballocs[m_gpu.getParity()];
// The 20 is some headroom just in case
if (balloc.remaining() < sizeof(psyqo::Prim::GouraudTexturedTriangle) + 20) {
return;
}
auto &prim = balloc.allocateFragment<psyqo::Prim::GouraudTexturedTriangle>();
prim.primitive.pointA = projected[0];
@@ -252,7 +259,7 @@ void psxsplash::Renderer::recursiveSubdivideAndRender(Tri &tri, eastl::array<psy
prim.primitive.uvA = tri.uvA;
prim.primitive.uvB = tri.uvB;
prim.primitive.uvC = tri.uvC; // uvC remains UVCoordsPadded.
prim.primitive.uvC = tri.uvC;
prim.primitive.tpage = tri.tpage;
psyqo::PrimPieces::ClutIndex clut(tri.clutX, tri.clutY);
prim.primitive.clutIndex = clut;
@@ -265,7 +272,8 @@ void psxsplash::Renderer::recursiveSubdivideAndRender(Tri &tri, eastl::array<psy
return;
}
// Subdivide the triangle
// FIXME: This is slow. The optimal way to do this would be to export the triangles from unity such that
// the edge between v0 and v1 is always the longest edge. This way we can always split the triangle optimally.
auto distanceSq = [](const psyqo::Vertex &a, const psyqo::Vertex &b) -> uint32_t {
int dx = a.x - b.x;
int dy = a.y - b.y;

View File

@@ -16,7 +16,7 @@
#include "camera.hh"
#include "gameobject.hh"
#include "splashpack.hh"
#include "navmesh.hh"
namespace psxsplash {
@@ -25,6 +25,7 @@ class Renderer final {
Renderer(const Renderer&) = delete;
Renderer& operator=(const Renderer&) = delete;
// FIXME: I have no idea how to precompute the required sizes of these. It would be best to allocate them based on the scene
static constexpr size_t ORDERING_TABLE_SIZE = 2048 * 3;
static constexpr size_t BUMP_ALLOCATOR_SIZE = 8096 * 24;

View File

@@ -6,6 +6,8 @@
#include "gameobject.hh"
#include "mesh.hh"
#include "psyqo/fixed-point.hh"
#include "psyqo/gte-registers.hh"
#include "renderer.hh"
namespace psxsplash {
@@ -17,7 +19,10 @@ struct SPLASHPACKFileHeader {
uint16_t navmeshCount;
uint16_t textureAtlasCount;
uint16_t clutCount;
uint16_t pad[2];
psyqo::GTE::PackedVec3 playerStartPos;
psyqo::GTE::PackedVec3 playerStartRot;
psyqo::FixedPoint<12, uint16_t> playerHeight;
uint16_t pad[1];
};
struct SPLASHPACKTextureAtlas {
@@ -39,6 +44,10 @@ void SplashPackLoader::LoadSplashpack(uint8_t *data) {
psxsplash::SPLASHPACKFileHeader *header = reinterpret_cast<psxsplash::SPLASHPACKFileHeader *>(data);
psyqo::Kernel::assert(memcmp(header->magic, "SP", 2) == 0, "Splashpack has incorrect magic");
playerStartPos = header->playerStartPos;
playerStartRot = header->playerStartRot;
playerHeight = header->playerHeight;
gameObjects.reserve(header->gameObjectCount);
navmeshes.reserve(header->navmeshCount);

View File

@@ -6,6 +6,7 @@
#include "gameobject.hh"
#include "navmesh.hh"
#include "psyqo/fixed-point.hh"
namespace psxsplash {
@@ -13,6 +14,10 @@ class SplashPackLoader {
public:
eastl::vector<GameObject *> gameObjects;
eastl::vector<Navmesh *> navmeshes;
psyqo::GTE::PackedVec3 playerStartPos, playerStartRot;
psyqo::FixedPoint<12, uint16_t> playerHeight;
void LoadSplashpack(uint8_t *data);
};