Skip to content

Commit

Permalink
Merge pull request #1791 from nicolasnoble/vscode-extension-cube-and-arm
Browse files Browse the repository at this point in the history
VSCode extension work
  • Loading branch information
nicolasnoble authored Oct 24, 2024
2 parents 0fdfcd3 + e120a3d commit bc029a7
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 3 deletions.
4 changes: 3 additions & 1 deletion tools/vscode-extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ The panel will have the ability to install the tools on the most popular platfor
- The extension is currently only targeting Windows, Linux Ubuntu, Arch Linux, and MacOS. It may work on more platforms, but it's not guaranteed, and won't be as automated as it is on the supported platforms.
- Only Windows and Linux Ubuntu have been thoroughly tested for now.
- The extension will not work from the browser as it requires running external tools. It may work in a remote SSH session, but it's not been tested.
- The PCSX-Redux dependency is currently only available on x86_64 platforms, and may possibly work on M1/M2 Macs.
- Linux requires libfuse2 to be installed, for AppImages like the PCSX-Redux dependency to work.
- The PCSX-Redux workflow won't check for system-wide installations, and will always install the dependency locally.

### Changelog

- 0.3.8
- Added automatic setup of Python virtual environments in order to reflect the changes in ps1-bare-metal.
- Fixed compile_flags.txt in template file.
- Added psyqo cube example.
- Added download support for Darwin ARM64 (M1/M2/etc) for PCSX-Redux.
- 0.3.7
- Bumping gcc to 14.2.0
- Bumping binutils to 2.43
Expand Down
10 changes: 8 additions & 2 deletions tools/vscode-extension/pcsx-redux.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ const updateInfo = {
infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-linux-x64/',
fileType: 'zip'
},
darwin: {
darwin_Intel: {
infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-macos-x64/',
fileType: 'dmg'
},
darwin_Arm: {
infoBase: 'https://distrib.app/storage/manifests/pcsx-redux/dev-macos-arm/',
fileType: 'dmg'
}
}

Expand Down Expand Up @@ -101,7 +105,9 @@ exports.install = async () => {
}
}

const updateInfoForPlatform = updateInfo[process.platform]
const darwinArch = process.arch === 'arm64' ? 'Arm' : 'Intel'
const platform = process.platform === 'darwin' ? 'darwin_' + darwinArch : process.platform
const updateInfoForPlatform = updateInfo[platform]
const outputDir =
process.platform === 'win32'
? vscode.Uri.joinPath(globalStorageUri, 'pcsx-redux').fsPath
Expand Down
27 changes: 27 additions & 0 deletions tools/vscode-extension/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,33 @@ const templates = {
)
}
},
psyqo_cube: {
name: 'PSYQo Cube',
category: 'PSYQo SDK',
description: 'A project featuring a rotating cube using the PSYQo SDK.',
url: 'https://github.com/pcsx-redux/nugget/tree/main/psyqo#how',
examples:
'https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/psyqo/examples',
requiredTools: ['git', 'make', 'toolchain'],
recommendedTools: ['gdb', 'debugger', 'redux'],
create: async function (fullPath, name, progressReporter) {
const git = await createGitRepository(
fullPath,
psyqoTemplate,
progressReporter
)
await copyTemplateDirectory(
git,
fullPath,
name,
[
path.join(extensionUri.fsPath, 'templates', 'common'),
path.join(extensionUri.fsPath, 'templates', 'psyqo', 'cube')
],
{ projectName: name, isCMake: false }
)
}
},
psyq_netyaroze: {
name: 'Net Yaroze Sprite',
category: 'Psy-Q SDK',
Expand Down
7 changes: 7 additions & 0 deletions tools/vscode-extension/templates/psyqo/cube/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
TARGET = {{projectName}}
TYPE = ps-exe

SRCS = \
main.cpp

include third_party/nugget/psyqo/psyqo.mk
7 changes: 7 additions & 0 deletions tools/vscode-extension/templates/psyqo/cube/compile_flags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-m32
-std=c++20
-fcoroutines-ts
-I.
-Ithird_party/nugget
-Ithird_party/nugget/third_party/EASTL/include
-Ithird_party/nugget/third_party/EABase/include/Common
197 changes: 197 additions & 0 deletions tools/vscode-extension/templates/psyqo/cube/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
{{=<% %>=}}#include "psyqo/application.hh"
#include "psyqo/fixed-point.hh"
#include "psyqo/fragments.hh"
#include "psyqo/gpu.hh"
#include "psyqo/gte-kernels.hh"
#include "psyqo/gte-registers.hh"
#include "psyqo/primitives/common.hh"
#include "psyqo/primitives/quads.hh"
#include "psyqo/scene.hh"
#include "psyqo/soft-math.hh"
#include "psyqo/trigonometry.hh"
#include "psyqo/vector.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<ORDERING_TABLE_SIZE> 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<psyqo::Prim::FastFill> m_clear[2];

eastl::array<psyqo::Fragments::SimpleFragment<psyqo::Prim::Quad>, 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::Register::TRX, psyqo::GTE::Unsafe>();
psyqo::GTE::clear<psyqo::GTE::Register::TRY, psyqo::GTE::Unsafe>();
psyqo::GTE::clear<psyqo::GTE::Register::TRZ, psyqo::GTE::Unsafe>();

// Set the screen offset in the GTE. (this is half the X and Y resolutions as standard)
psyqo::GTE::write<psyqo::GTE::Register::OFX, psyqo::GTE::Unsafe>(psyqo::FixedPoint<16>(160.0).raw());
psyqo::GTE::write<psyqo::GTE::Register::OFY, psyqo::GTE::Unsafe>(psyqo::FixedPoint<16>(120.0).raw());

// Write the projection plane distance.
psyqo::GTE::write<psyqo::GTE::Register::H, psyqo::GTE::Unsafe>(120);

// Set the scaling for Z averaging.
psyqo::GTE::write<psyqo::GTE::Register::ZSF3, psyqo::GTE::Unsafe>(ORDERING_TABLE_SIZE / 3);
psyqo::GTE::write<psyqo::GTE::Register::ZSF4, psyqo::GTE::Unsafe>(ORDERING_TABLE_SIZE / 4);
}

void CubeScene::frame() {
eastl::array<psyqo::Vertex, 4> 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<psyqo::GTE::Register::TRZ, psyqo::GTE::Unsafe>(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<psyqo::GTE::PseudoRegister::Rotation>(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<psyqo::GTE::PseudoRegister::V0>(c_cubeVertices[face.vertices[0]]);
psyqo::GTE::writeUnsafe<psyqo::GTE::PseudoRegister::V1>(c_cubeVertices[face.vertices[1]]);
psyqo::GTE::writeUnsafe<psyqo::GTE::PseudoRegister::V2>(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
int32_t mac0 = 0;
psyqo::GTE::read<psyqo::GTE::Register::MAC0>(reinterpret_cast<uint32_t *>(&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<psyqo::GTE::Register::SXY0>(&projected[0].packed);

// Write the last vertex
psyqo::GTE::writeSafe<psyqo::GTE::PseudoRegister::V0>(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();
int32_t zIndex = 0;
psyqo::GTE::read<psyqo::GTE::Register::OTZ>(reinterpret_cast<uint32_t *>(&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<psyqo::GTE::Register::SXY0>(&projected[1].packed);
psyqo::GTE::read<psyqo::GTE::Register::SXY1>(&projected[2].packed);
psyqo::GTE::read<psyqo::GTE::Register::SXY2>(&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(); }

0 comments on commit bc029a7

Please sign in to comment.