diff --git a/src/mips/psyqo/examples/cube/Makefile b/src/mips/psyqo/examples/cube/Makefile new file mode 100644 index 000000000..7779ecaab --- /dev/null +++ b/src/mips/psyqo/examples/cube/Makefile @@ -0,0 +1,12 @@ +TARGET = cube +TYPE = ps-exe + +SRCS = \ +cube.cpp \ + +ifeq ($(TEST),true) +CPPFLAGS = -Werror +endif +CXXFLAGS = -std=c++20 + +include ../../psyqo.mk diff --git a/src/mips/psyqo/examples/cube/cube.cpp b/src/mips/psyqo/examples/cube/cube.cpp new file mode 100644 index 000000000..9f42e6515 --- /dev/null +++ b/src/mips/psyqo/examples/cube/cube.cpp @@ -0,0 +1,254 @@ +/* + +MIT License + +Copyright (c) 2024 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "psyqo/application.hh" +#include "psyqo/gpu.hh" +#include "psyqo/trigonometry.hh" +#include "psyqo/gte-registers.hh" +#include "psyqo/gte-kernels.hh" +#include "psyqo/fixed-point.hh" +#include "psyqo/fragments.hh" +#include "psyqo/primitives/common.hh" +#include "psyqo/primitives/quads.hh" +#include "psyqo/vector.hh" +#include "psyqo/soft-math.hh" +#include "psyqo/scene.hh" + +using namespace psyqo::fixed_point_literals; +using namespace psyqo::trig_literals; + +static constexpr unsigned NUM_CUBE_VERTICES = 8; +static constexpr unsigned NUM_CUBE_FACES = 6; +static constexpr unsigned ORDERING_TABLE_SIZE = 240; + +typedef struct { + uint8_t vertices[4]; + psyqo::Color color; +} Face; + + +static constexpr psyqo::Matrix33 identity = {{ + {1.0_fp, 0.0_fp, 0.0_fp}, + {0.0_fp, 1.0_fp, 0.0_fp}, + {0.0_fp, 0.0_fp, 1.0_fp}, +}}; + +class Cube final : public psyqo::Application { + void prepare() override; + void createScene() override; + + public: + psyqo::Trig<> m_trig; +}; + +class CubeScene final : public psyqo::Scene { + + void start(StartReason reason) override; + void frame() override; + + psyqo::Angle m_rot = 0; + + // We need to create 2 OrderingTable objects since we can't reuse a single one for both + // framebuffers, as the previous one may not finish transfering in time. + psyqo::OrderingTable m_ots[2]; + + // Since we're using an ordering table, we need to sort fill commands as well, + // otherwise they'll draw over our beautiful cube. + psyqo::Fragments::SimpleFragment m_clear[2]; + + eastl::array, 6> m_quads; + + static constexpr psyqo::Color c_bg = {.r = 63, .g = 63, .b = 63}; + + + static constexpr psyqo::Vec3 c_cubeVertices[NUM_CUBE_VERTICES] = { + { .x = -0.05, .y = -0.05, .z = -0.05 }, + { .x = 0.05, .y = -0.05, .z = -0.05 }, + { .x = -0.05, .y = 0.05, .z = -0.05 }, + { .x = 0.05, .y = 0.05, .z = -0.05 }, + { .x = -0.05, .y = -0.05, .z = 0.05 }, + { .x = 0.05, .y = -0.05, .z = 0.05 }, + { .x = -0.05, .y = 0.05, .z = 0.05 }, + { .x = 0.05, .y = 0.05, .z = 0.05 } + }; + + + static constexpr Face c_cubeFaces[NUM_CUBE_FACES] = { + { .vertices = { 0, 1, 2, 3 }, .color = {0,0,255} }, + { .vertices = { 6, 7, 4, 5 }, .color = {0,255,0} }, + { .vertices = { 4, 5, 0, 1 }, .color = {0,255,255} }, + { .vertices = { 7, 6, 3, 2 }, .color = {255,0,0} }, + { .vertices = { 6, 4, 2, 0 }, .color = {255,0,255}}, + { .vertices = { 5, 7, 1, 3 }, .color = {255,255,0} } + }; +}; + +static Cube cube; +static CubeScene cubeScene; + +void Cube::prepare() { + psyqo::GPU::Configuration config; + config.set(psyqo::GPU::Resolution::W320) + .set(psyqo::GPU::VideoMode::AUTO) + .set(psyqo::GPU::ColorMode::C15BITS) + .set(psyqo::GPU::Interlace::PROGRESSIVE); + + gpu().initialize(config); +} + +void Cube::createScene() { + pushScene(&cubeScene); +} + +void CubeScene::start(StartReason reason) { + + // Clear the translation registers + psyqo::GTE::clear(); + psyqo::GTE::clear(); + psyqo::GTE::clear(); + + + // Set the screen offset in the GTE. (this is half the X and Y resolutions as standard) + psyqo::GTE::write(psyqo::FixedPoint<16>(160.0).raw()); + psyqo::GTE::write(psyqo::FixedPoint<16>(120.0).raw()); + + + // Write the projection plane distance. + psyqo::GTE::write(120); + + + // Set the scaling for Z averaging. + psyqo::GTE::write(ORDERING_TABLE_SIZE / 3); + psyqo::GTE::write(ORDERING_TABLE_SIZE / 4); + +} + +void CubeScene::frame() { + + eastl::array projected; + + // Get which frame we're currently drawing + int parity = gpu().getParity(); + + // Get our current ordering table and fill command + auto& ot = m_ots[parity]; + auto& clear = m_clear[parity]; + + // Chain the fill command accordingly to clear the buffer + gpu().getNextClear(clear.primitive, c_bg); + gpu().chain(clear); + + + // We want the cube to appear slightly further away, so we translate it by 512 on the Z-axis. + psyqo::GTE::write(512); + + // Here we're setting up the rotation for the spinning cube + // First, generate a rotation matrix for the X-axis and Y-axis + auto transform = psyqo::SoftMath::generateRotationMatrix33(m_rot, psyqo::SoftMath::Axis::X, cube.m_trig); + auto rot = psyqo::SoftMath::generateRotationMatrix33(m_rot, psyqo::SoftMath::Axis::Y, cube.m_trig); + + // Multiply the X and Y rotation matrices together + psyqo::SoftMath::multiplyMatrix33(transform, rot, &transform); + + // Generate a Z-axis rotation matrix (Empty, but it's here for your use) + psyqo::SoftMath::generateRotationMatrix33(0, 0, psyqo::SoftMath::Axis::Z, cube.m_trig); + + // Apply the combined rotation and write it to the pseudo register for the cube's rotation + psyqo::SoftMath::multiplyMatrix33(transform, rot, &transform); + psyqo::GTE::writeUnsafe(transform); + + + + int faceNum = 0; + + for(auto face : c_cubeFaces) { + + // We load the first 3 vertices into the GTE. We can't do all 4 at once because the GTE + // handles only 3 at a time... + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[0]]); + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[1]]); + psyqo::GTE::writeUnsafe(c_cubeVertices[face.vertices[2]]); + + // We perform rtpt (Perspective transformation) to the three verticies. + psyqo::GTE::Kernels::rtpt(); + + // Nclip determines the winding of the vertices, used to check which direction the face is pointing. + // Clockwise winding means the face is oriented towards us. + psyqo::GTE::Kernels::nclip(); + + // Read the result of nclip and skip rendering this face if it's not facing us + uint32_t mac0 = 0; + psyqo::GTE::read(&mac0); + if(mac0 <= 0) + continue; + + // Since the GTE can only handle 3 vertices at a time, we need to store our first vertex + // so we can write our last one. + psyqo::GTE::read(&projected[0].packed); + + // Write the last vertex + psyqo::GTE::writeSafe(c_cubeVertices[face.vertices[3]]); + + // Perform rtps (Perspective transformation) to the last vertice (rtpS - single, rtpT - triple). + psyqo::GTE::Kernels::rtps(); + + // Calculate the average Z for the z-Index to be put in the ordering table + psyqo::GTE::Kernels::avsz4(); + uint32_t zIndex = 0; + psyqo::GTE::read(&zIndex); + + + // If the Z-index is out of bounds for our ordering table, we skip rendering this face. + if(zIndex < 0 || zIndex >= ORDERING_TABLE_SIZE) + continue; + + // Read the 3 remaining vertices from the GTE + psyqo::GTE::read(&projected[1].packed); + psyqo::GTE::read(&projected[2].packed); + psyqo::GTE::read(&projected[3].packed); + + // Take a Quad fragment from our array, set its vertices, color and make it opaque + auto& quad = m_quads[faceNum]; + quad.primitive.setPointA(projected[0]); + quad.primitive.setPointB(projected[1]); + quad.primitive.setPointC(projected[2]); + quad.primitive.setPointD(projected[3]); + quad.primitive.setColor(face.color); + quad.primitive.setOpaque(); + + // Insert the Quad fragment into the ordering table at the calculated Z-index. + ot.insert(quad, zIndex); + faceNum++; + } + + // Send the entire ordering table as a DMA chain to the GPU. + gpu().chain(ot); + m_rot += 0.005_pi; +} + + +int main() {return cube.run();} + diff --git a/tools/vscode-extension/templates/psyqo/hello/compile_flags.txt b/tools/vscode-extension/templates/psyqo/hello/compile_flags.txt index 6f839ee03..a0d792fec 100644 --- a/tools/vscode-extension/templates/psyqo/hello/compile_flags.txt +++ b/tools/vscode-extension/templates/psyqo/hello/compile_flags.txt @@ -3,5 +3,5 @@ -fcoroutines-ts -I. -Ithird_party/nugget --Ithird_party/EASTL/include --Ithird_party/EABase/include/Common +-Ithird_party/nugget/third_party/EASTL/include +-Ithird_party/nugget/third_party/EABase/include/Common