From c3a0e936c85bcc35f6b6b262268271c98e19dba2 Mon Sep 17 00:00:00 2001 From: tobid7 Date: Sat, 22 Nov 2025 14:55:01 +0100 Subject: [PATCH] # Additions - libpicasso (shader compiling) - linearAllocator template (for std::vector) - palladium vec and mat api - iron (2d renderer) --- .gitmodules | 3 + CMakeLists.txt | 5 + example/source/main.cpp | 60 +++++--- include/amethyst/c3d.hpp | 11 ++ include/amethyst/iron.hpp | 44 ++++++ include/amethyst/linearAlloc.hpp | 36 +++++ include/amethyst/maths/mat.hpp | 144 ++++++++++++++++++ include/amethyst/maths/vec.hpp | 60 ++++++++ include/amethyst/maths/vec2.hpp | 174 ++++++++++++++++++++++ include/amethyst/maths/vec3.hpp | 210 ++++++++++++++++++++++++++ include/amethyst/maths/vec4.hpp | 244 +++++++++++++++++++++++++++++++ source/c3d.cpp | 29 +++- source/iron.cpp | 77 ++++++++++ source/maths/mat.cpp | 121 +++++++++++++++ vendor/libpicasso | 1 + 15 files changed, 1200 insertions(+), 19 deletions(-) create mode 100644 .gitmodules create mode 100644 include/amethyst/iron.hpp create mode 100644 include/amethyst/linearAlloc.hpp create mode 100644 include/amethyst/maths/mat.hpp create mode 100644 include/amethyst/maths/vec.hpp create mode 100644 include/amethyst/maths/vec2.hpp create mode 100644 include/amethyst/maths/vec3.hpp create mode 100644 include/amethyst/maths/vec4.hpp create mode 100644 source/iron.cpp create mode 100644 source/maths/mat.cpp create mode 160000 vendor/libpicasso diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..de2365a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/libpicasso"] + path = vendor/libpicasso + url = https://github.com/npid7/libpicasso.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8609a28..2331a22 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ project(amethyst) option(AMY_BUILD_3DS "Build for 3ds" ON) option(AMY_GOD_DEV "Turn this on if you think you are god" OFF) +add_subdirectory(vendor/libpicasso) + add_library(${PROJECT_NAME} STATIC source/amethyst.cpp source/image.cpp @@ -13,8 +15,11 @@ add_library(${PROJECT_NAME} STATIC source/utils.cpp source/c3d.cpp source/ctru.cpp + source/iron.cpp + source/maths/mat.cpp ) target_include_directories(${PROJECT_NAME} PUBLIC include) +target_link_libraries(${PROJECT_NAME} PUBLIC pica::pica) if(${AMY_BUILD_3DS}) target_link_libraries(${PROJECT_NAME} PUBLIC m z ctru citro3d) target_compile_definitions(${PROJECT_NAME} PUBLIC AMY_3DS) diff --git a/example/source/main.cpp b/example/source/main.cpp index b81bf16..e72fd3e 100755 --- a/example/source/main.cpp +++ b/example/source/main.cpp @@ -1,5 +1,46 @@ +#include "amethyst/iron.hpp" #include +const char* shader_ = R"(; Example PICA200 vertex shader + +; Uniforms +.fvec projection[4] + +; Constants +.constf myconst(0.0, 1.0, -1.0, 0.1) +.constf myconst2(0.3, 0.0, 0.0, 0.0) +.alias zeros myconst.xxxx ; Vector full of zeros +.alias ones myconst.yyyy ; Vector full of ones + +; Outputs +.out outpos position +.out outclr color + +; Inputs (defined as aliases for convenience) +.alias inpos v0 +.alias inclr v1 + +.bool test + +.proc main + ; Force the w component of inpos to be 1.0 + mov r0.xyz, inpos + mov r0.w, ones + + ; outpos = projectionMatrix * inpos + dp4 outpos.x, projection[0], r0 + dp4 outpos.y, projection[1], r0 + dp4 outpos.z, projection[2], r0 + dp4 outpos.w, projection[3], r0 + + ; outclr = inclr + mov outclr, inclr + + ; We're finished + end +.end +)"; + static C3D_Mtx projection; int main() { @@ -7,28 +48,11 @@ int main() { amy::ctru::init(); amy::c3d::init(); auto top = amy::c3d::createScreen(GFX_TOP, GFX_LEFT); - auto shader = new amy::c3d::shader("romfs:/shaders/shader2d.shbin"); - shader->input(GPU_FLOAT, 3); - shader->input(GPU_FLOAT, 3); - amy::c3d::frag::edit(); - amy::c3d::frag::src(C3D_Both); - amy::c3d::frag::func(C3D_Both, GPU_REPLACE); - Mtx_Identity(&projection); - Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true); + amy::iron::init(); while (aptMainLoop()) { amy::c3d::startFrame(); top->startDraw(); top->clear(); - shader->use(); - shader->setMat4(0, &projection); - C3D_ImmDrawBegin(GPU_TRIANGLES); - C3D_ImmSendAttrib(200, 200, 0.5, 0); - C3D_ImmSendAttrib(1, 0, 0, 1); - C3D_ImmSendAttrib(100, 40, 0.5, 0); - C3D_ImmSendAttrib(0, 1, 0, 1); - C3D_ImmSendAttrib(300, 40, 0.5, 0); - C3D_ImmSendAttrib(0, 0, 1, 1); - C3D_ImmDrawEnd(); amy::c3d::endFrame(); } amy::c3d::deleteScreen(top); diff --git a/include/amethyst/c3d.hpp b/include/amethyst/c3d.hpp index 8ae17dc..9415015 100755 --- a/include/amethyst/c3d.hpp +++ b/include/amethyst/c3d.hpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include namespace amy { @@ -36,13 +38,18 @@ class c3d { class shader : public asset { public: shader(const std::string& path); + shader() {} ~shader(); void load(const std::string& path); + void load(const std::vector& data); + void compile(const std::string& code); void use(); void input(int reg, GPU_FORMATS f, int num); void input(GPU_FORMATS f, int num) { input(m_reg++, f, num); } void setMat4(int loc, C3D_Mtx* m); + void setMat4(int loc, const mat4& m); + int loc(const std::string& name); private: C3D_AttrInfo m_info; @@ -72,5 +79,9 @@ class c3d { static void endFrame(); static screen* createScreen(gfxScreen_t screen, gfx3dSide_t side = GFX_LEFT); static void deleteScreen(screen* screen); + static void drawArrays(int start, int count, + GPU_Primitive_t prim = GPU_TRIANGLES); + static void drawElements(int count, const void* idx_ptr, int type = GPU_SHORT, + GPU_Primitive_t prim = GPU_TRIANGLES); }; } // namespace amy \ No newline at end of file diff --git a/include/amethyst/iron.hpp b/include/amethyst/iron.hpp new file mode 100644 index 0000000..29af761 --- /dev/null +++ b/include/amethyst/iron.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace amy { +class iron { + public: + struct vertex { + vertex(float x, float y, float u, float v, u32 clr) { + pos.x = x; + pos.y = y; + uv.x = x; + uv.y = y; + color = clr; + } + vertex() {} + + amy::fvec2 pos; + amy::fvec2 uv; + u32 color = 0; + }; + iron() = default; + ~iron() = default; + + static void init(); + static void newFrame(); + static void drawOn(c3d::screen* screen); + + private: + static void setupShader(); + static void fragConfig(); + + static std::vector> m_vbuf; + static std::vector> m_ibuf; + static int uLocProj; + static c3d::shader* m_shader; + static mat4 m_mtx; + static int m_idx, m_vtx; +}; +} // namespace amy \ No newline at end of file diff --git a/include/amethyst/linearAlloc.hpp b/include/amethyst/linearAlloc.hpp new file mode 100644 index 0000000..ff2098a --- /dev/null +++ b/include/amethyst/linearAlloc.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include <3ds.h> + +#include +#include + +// Custom C++ Allocator class to interface with libctru linear heap memory +// based on this guide: +// https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/ + +namespace amy { +template +class linearAllocator { + public: + using value_type = T; + linearAllocator() = default; + template + constexpr linearAllocator(const linearAllocator&) noexcept {} + + T* allocate(std::size_t n) { + if (n > std::allocator_traits::max_size(*this)) { + throw std::bad_alloc(); + } + return static_cast(linearAlloc(n * sizeof(T))); + } + void deallocate(T* p, std::size_t) noexcept { linearFree(p); } + + friend bool operator==(const linearAllocator, const linearAllocator) { + return true; + } + friend bool operator!=(const linearAllocator, const linearAllocator) { + return false; + } +}; +} // namespace amy \ No newline at end of file diff --git a/include/amethyst/maths/mat.hpp b/include/amethyst/maths/mat.hpp new file mode 100644 index 0000000..13f3782 --- /dev/null +++ b/include/amethyst/maths/mat.hpp @@ -0,0 +1,144 @@ +#pragma once + +/* +MIT License + +Copyright (c) 2024 - 2025 tobid7 + +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 +#include +#include +#include + +namespace amy { +namespace numbers { +constexpr float Tau = std::numbers::pi * 2.f; +} +constexpr float Radians(float v) { return v * (numbers::Tau / 360.0f); } +/** + * Minimal Mtx4 Lib that precomputes + * basic stuff stuff at compiletime + * + * This Lib includes Patches for work with Citro3D as well + * + * @note That this is not a full Matrix Library + */ + +struct mat4 { + std::array m; + constexpr mat4() : m{} {} + constexpr static mat4 diagonal(float x, float y, float z, float w) { + mat4 ret; + ret(0, 0) = x; + ret(1, 1) = y; + ret(2, 2) = z; + ret(3, 3) = w; + return ret; + } + constexpr static mat4 identity() { return diagonal(1, 1, 1, 1); } + + constexpr float* ptr() { return m.data(); } + constexpr const float* ptr() const { return m.data(); } + + constexpr float& operator()(int row, int col) { +#ifdef __3DS__ + // 3ds is full reverse order iirc + return m[row * 4 + (3 - col)]; +#else + return m[col * 4 + row]; +#endif + } + constexpr float operator()(int row, int col) const { +#ifdef __3DS__ + // 3ds is full reverse order iirc + return m[row * 4 + (3 - col)]; +#else + return m[col * 4 + row]; +#endif + } + + constexpr mat4 operator*(const mat4& v) const { + mat4 ret; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float t = 0.f; + for (int k = 0; k < 4; k++) { + t += (*this)(i, k) * v(k, j); + } + ret(i, j) = t; + } + } + return ret; + } + + constexpr mat4& operator*=(const mat4& v) { + *this = *this * v; + return *this; + } + + constexpr static mat4 translate(float x, float y, float z) { + mat4 ret = identity(); + ret(0, 3) = x; + ret(1, 3) = y; + ret(2, 3) = z; + return ret; + } + + constexpr static mat4 scale(float x, float y, float z) { + mat4 ret; + ret(0, 0) = x; + ret(1, 1) = y; + ret(2, 2) = z; + ret(3, 3) = 1.f; + return ret; + } + + constexpr static mat4 ortho(float l, float r, float b, float t, float n, + float f) { + mat4 ret; +#ifdef __3DS__ // Patch to rotate the Matrix correctly + ret(0, 1) = 2.f / (t - b); + ret(0, 3) = (b + t) / (b - t); + ret(1, 0) = 2.f / (l - r); + ret(1, 3) = (l + r) / (r - l); + ret(2, 2) = 1.f / (n - f); + ret(2, 3) = 0.5f * (n + f) / (n - f) - 0.5f; +#else + ret(0, 0) = 2.0f / (r - l); + ret(0, 3) = -(r + l) / (r - l); + ret(1, 1) = 2.0f / (t - b); + ret(1, 3) = -(t + b) / (t - b); + ret(2, 2) = -2.0f / (f - n); + ret(2, 3) = -(f + n) / (f - n); +#endif + ret(3, 3) = 1.f; + return ret; + } + + static mat4 rotate(fvec3 axis, float a); + static mat4 rotateX(float a); + static mat4 rotateY(float a); + static mat4 rotateZ(float a); + static mat4 perspective(float fov, float aspect, float n, float f); + static mat4 lookAt(const fvec3& pos, const fvec3& center, const fvec3& up); +}; +} // namespace amy \ No newline at end of file diff --git a/include/amethyst/maths/vec.hpp b/include/amethyst/maths/vec.hpp new file mode 100644 index 0000000..10d84a5 --- /dev/null +++ b/include/amethyst/maths/vec.hpp @@ -0,0 +1,60 @@ +#pragma once + +/* +MIT License + +Copyright (c) 2024 - 2025 tobid7 + +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 +#include +#include +#include + +/** Define Formatters for C++ 20 */ + +/** + * WHY DOES MSVC ALWAYS NEED THESE EXTRA THINGS + */ + +template +struct std::formatter, CharT> : std::formatter { + template + auto format(const amy::vec2 &v, FormatContext &ctx) const { + return std::format_to(ctx.out(), "{}, {}", v.x, v.y); + } +}; + +template +struct std::formatter, CharT> : std::formatter { + template + auto format(const amy::vec3 &v, FormatContext &ctx) const { + return std::format_to(ctx.out(), "{}, {}, {}", v.x, v.y, v.z); + } +}; + +template +struct std::formatter, CharT> : std::formatter { + template + auto format(const amy::vec4 &v, FormatContext &ctx) const { + return std::format_to(ctx.out(), "{}, {}, {}, {}", v.x, v.y, v.z, v.w); + } +}; \ No newline at end of file diff --git a/include/amethyst/maths/vec2.hpp b/include/amethyst/maths/vec2.hpp new file mode 100644 index 0000000..8c7e170 --- /dev/null +++ b/include/amethyst/maths/vec2.hpp @@ -0,0 +1,174 @@ +#pragma once + +/* +MIT License +Copyright (c) 2024 - 2025 tobid7 + +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. + */ + +// This file is generated by lazyvec 2.0.0 + +#include + +namespace amy { +template class vec2 { +public: + T x; + T y; + + // Constructors + + constexpr vec2() : x(0), y(0) {} + template constexpr vec2(T1 v) { + x = (T)v; + y = (T)v; + } + + template constexpr vec2(const vec2 &v) { + x = (T)v.x; + y = (T)v.y; + } + + constexpr explicit vec2(T x, T y) : x(x), y(y) {} + + // Operations + + template vec2 &operator+=(T1 v) { + x += (T)v; + y += (T)v; + return *this; + } + + template vec2 &operator+=(const vec2 &v) { + x += (T)v.x; + y += (T)v.y; + return *this; + } + + template vec2 operator+(T1 v) const { + return vec2(x + (T)v, y + (T)v); + } + + template vec2 operator+(const vec2 &v) const { + return vec2(x + (T)v.x, y + (T)v.y); + } + + template vec2 &operator-=(T1 v) { + x -= (T)v; + y -= (T)v; + return *this; + } + + template vec2 &operator-=(const vec2 &v) { + x -= (T)v.x; + y -= (T)v.y; + return *this; + } + + template vec2 operator-(T1 v) const { + return vec2(x - (T)v, y - (T)v); + } + + template vec2 operator-(const vec2 &v) const { + return vec2(x - (T)v.x, y - (T)v.y); + } + + template vec2 &operator*=(T1 v) { + x *= (T)v; + y *= (T)v; + return *this; + } + + template vec2 &operator*=(const vec2 &v) { + x *= (T)v.x; + y *= (T)v.y; + return *this; + } + + template vec2 operator*(T1 v) const { + return vec2(x * (T)v, y * (T)v); + } + + template vec2 operator*(const vec2 &v) const { + return vec2(x * (T)v.x, y * (T)v.y); + } + + template vec2 &operator/=(T1 v) { + x /= (T)v; + y /= (T)v; + return *this; + } + + template vec2 &operator/=(const vec2 &v) { + x /= (T)v.x; + y /= (T)v.y; + return *this; + } + + template vec2 operator/(T1 v) const { + return vec2(x / (T)v, y / (T)v); + } + + template vec2 operator/(const vec2 &v) const { + return vec2(x / (T)v.x, y / (T)v.y); + } + + // Generic Operations + + vec2 operator-() const { return vec2(-x, -y); } + template bool operator==(const vec2 &v) const { + return x == (T)v.x && y == (T)v.y; + } + template bool operator!=(const vec2 &v) const { + return !(*this == v); + } + + // Functions + + double Len() const { return std::sqrt(SqLen()); } + double SqLen() const { return x * x + y * y; } + + template double Distance(const vec2 &v) const { + return (*this - v).Len(); + } + + vec2 Normalize() const { + double l = Len(); + if (l == 0) { + return *this; + } + return *this / (T)l; + } + + template T Dot(const vec2 &v) const { + return x * (T)v.x + y * (T)v.y; + } + + // Swap Functions + void SwapXY() { + T t = x; + x = y; + y = t; + } +}; +using fvec2 = vec2; +using ivec2 = vec2; +using dvec2 = vec2; +} // namespace amy diff --git a/include/amethyst/maths/vec3.hpp b/include/amethyst/maths/vec3.hpp new file mode 100644 index 0000000..504c6cb --- /dev/null +++ b/include/amethyst/maths/vec3.hpp @@ -0,0 +1,210 @@ +#pragma once + +/* +MIT License +Copyright (c) 2024 - 2025 tobid7 + +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. + */ + +// This file is generated by lazyvec 2.0.0 + +#include +// Extended includes (rename if you use other filenames/paths) +#include + +namespace amy { +template class vec3 { +public: + T x; + T y; + T z; + + // Constructors + + constexpr vec3() : x(0), y(0), z(0) {} + template constexpr vec3(T1 v) { + x = (T)v; + y = (T)v; + z = (T)v; + } + + template constexpr vec3(const vec3 &v) { + x = (T)v.x; + y = (T)v.y; + z = (T)v.z; + } + + constexpr explicit vec3(T x, T y, T z) : x(x), y(y), z(z) {} + + // Extended Constructors + template constexpr explicit vec3(const vec2 &xy, T1 z) { + { + x = (T)xy.x; + y = (T)xy.y; + this->z = (T)z; + } + } + + // Operations + + template vec3 &operator+=(T1 v) { + x += (T)v; + y += (T)v; + z += (T)v; + return *this; + } + + template vec3 &operator+=(const vec3 &v) { + x += (T)v.x; + y += (T)v.y; + z += (T)v.z; + return *this; + } + + template vec3 operator+(T1 v) const { + return vec3(x + (T)v, y + (T)v, z + (T)v); + } + + template vec3 operator+(const vec3 &v) const { + return vec3(x + (T)v.x, y + (T)v.y, z + (T)v.z); + } + + template vec3 &operator-=(T1 v) { + x -= (T)v; + y -= (T)v; + z -= (T)v; + return *this; + } + + template vec3 &operator-=(const vec3 &v) { + x -= (T)v.x; + y -= (T)v.y; + z -= (T)v.z; + return *this; + } + + template vec3 operator-(T1 v) const { + return vec3(x - (T)v, y - (T)v, z - (T)v); + } + + template vec3 operator-(const vec3 &v) const { + return vec3(x - (T)v.x, y - (T)v.y, z - (T)v.z); + } + + template vec3 &operator*=(T1 v) { + x *= (T)v; + y *= (T)v; + z *= (T)v; + return *this; + } + + template vec3 &operator*=(const vec3 &v) { + x *= (T)v.x; + y *= (T)v.y; + z *= (T)v.z; + return *this; + } + + template vec3 operator*(T1 v) const { + return vec3(x * (T)v, y * (T)v, z * (T)v); + } + + template vec3 operator*(const vec3 &v) const { + return vec3(x * (T)v.x, y * (T)v.y, z * (T)v.z); + } + + template vec3 &operator/=(T1 v) { + x /= (T)v; + y /= (T)v; + z /= (T)v; + return *this; + } + + template vec3 &operator/=(const vec3 &v) { + x /= (T)v.x; + y /= (T)v.y; + z /= (T)v.z; + return *this; + } + + template vec3 operator/(T1 v) const { + return vec3(x / (T)v, y / (T)v, z / (T)v); + } + + template vec3 operator/(const vec3 &v) const { + return vec3(x / (T)v.x, y / (T)v.y, z / (T)v.z); + } + + // Generic Operations + + vec3 operator-() const { return vec3(-x, -y, -z); } + template bool operator==(const vec3 &v) const { + return x == (T)v.x && y == (T)v.y && z == (T)v.z; + } + template bool operator!=(const vec3 &v) const { + return !(*this == v); + } + + // Functions + + double Len() const { return std::sqrt(SqLen()); } + double SqLen() const { return x * x + y * y + z * z; } + + template double Distance(const vec3 &v) const { + return (*this - v).Len(); + } + + vec3 Normalize() const { + double l = Len(); + if (l == 0) { + return *this; + } + return *this / (T)l; + } + + template T Dot(const vec3 &v) const { + return x * (T)v.x + y * (T)v.y + z * (T)v.z; + } + + template vec3 Cross(const vec3 &v) const { + return vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); + } + + // Swap Functions + void SwapXY() { + T t = x; + x = y; + y = t; + } + void SwapXZ() { + T t = x; + x = z; + z = t; + } + void SwapYZ() { + T t = y; + y = z; + z = t; + } +}; +using fvec3 = vec3; +using ivec3 = vec3; +using dvec3 = vec3; +} // namespace amy diff --git a/include/amethyst/maths/vec4.hpp b/include/amethyst/maths/vec4.hpp new file mode 100644 index 0000000..5e5b374 --- /dev/null +++ b/include/amethyst/maths/vec4.hpp @@ -0,0 +1,244 @@ +#pragma once + +/* +MIT License +Copyright (c) 2024 - 2025 tobid7 + +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. + */ + +// This file is generated by lazyvec 2.0.0 + +#include +// Extended includes (rename if you use other filenames/paths) +#include +#include + +namespace amy { +template class vec4 { +public: + T x; + T y; + T z; + T w; + + // Constructors + + constexpr vec4() : x(0), y(0), z(0), w(0) {} + template constexpr vec4(T1 v) { + x = (T)v; + y = (T)v; + z = (T)v; + w = (T)v; + } + + template constexpr vec4(const vec4 &v) { + x = (T)v.x; + y = (T)v.y; + z = (T)v.z; + w = (T)v.w; + } + + constexpr explicit vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {} + + // Extended Constructors + template + constexpr explicit vec4(const vec2 &xy, const vec2 &zw) { + { + x = (T)xy.x; + y = (T)xy.y; + z = (T)zw.x; + w = (T)zw.y; + } + } + + template constexpr explicit vec4(const vec3 &xyz, T1 w) { + { + x = (T)xyz.x; + y = (T)xyz.y; + z = (T)xyz.z; + this->w = (T)w; + } + } + + // Operations + + template vec4 &operator+=(T1 v) { + x += (T)v; + y += (T)v; + z += (T)v; + w += (T)v; + return *this; + } + + template vec4 &operator+=(const vec4 &v) { + x += (T)v.x; + y += (T)v.y; + z += (T)v.z; + w += (T)v.w; + return *this; + } + + template vec4 operator+(T1 v) const { + return vec4(x + (T)v, y + (T)v, z + (T)v, w + (T)v); + } + + template vec4 operator+(const vec4 &v) const { + return vec4(x + (T)v.x, y + (T)v.y, z + (T)v.z, w + (T)v.w); + } + + template vec4 &operator-=(T1 v) { + x -= (T)v; + y -= (T)v; + z -= (T)v; + w -= (T)v; + return *this; + } + + template vec4 &operator-=(const vec4 &v) { + x -= (T)v.x; + y -= (T)v.y; + z -= (T)v.z; + w -= (T)v.w; + return *this; + } + + template vec4 operator-(T1 v) const { + return vec4(x - (T)v, y - (T)v, z - (T)v, w - (T)v); + } + + template vec4 operator-(const vec4 &v) const { + return vec4(x - (T)v.x, y - (T)v.y, z - (T)v.z, w - (T)v.w); + } + + template vec4 &operator*=(T1 v) { + x *= (T)v; + y *= (T)v; + z *= (T)v; + w *= (T)v; + return *this; + } + + template vec4 &operator*=(const vec4 &v) { + x *= (T)v.x; + y *= (T)v.y; + z *= (T)v.z; + w *= (T)v.w; + return *this; + } + + template vec4 operator*(T1 v) const { + return vec4(x * (T)v, y * (T)v, z * (T)v, w * (T)v); + } + + template vec4 operator*(const vec4 &v) const { + return vec4(x * (T)v.x, y * (T)v.y, z * (T)v.z, w * (T)v.w); + } + + template vec4 &operator/=(T1 v) { + x /= (T)v; + y /= (T)v; + z /= (T)v; + w /= (T)v; + return *this; + } + + template vec4 &operator/=(const vec4 &v) { + x /= (T)v.x; + y /= (T)v.y; + z /= (T)v.z; + w /= (T)v.w; + return *this; + } + + template vec4 operator/(T1 v) const { + return vec4(x / (T)v, y / (T)v, z / (T)v, w / (T)v); + } + + template vec4 operator/(const vec4 &v) const { + return vec4(x / (T)v.x, y / (T)v.y, z / (T)v.z, w / (T)v.w); + } + + // Generic Operations + + vec4 operator-() const { return vec4(-x, -y, -z, -w); } + template bool operator==(const vec4 &v) const { + return x == (T)v.x && y == (T)v.y && z == (T)v.z && w == (T)v.w; + } + template bool operator!=(const vec4 &v) const { + return !(*this == v); + } + + // Functions + + double Len() const { return std::sqrt(SqLen()); } + double SqLen() const { return x * x + y * y + z * z + w * w; } + + template double Distance(const vec4 &v) const { + return (*this - v).Len(); + } + + vec4 Normalize() const { + double l = Len(); + if (l == 0) { + return *this; + } + return *this / (T)l; + } + + template T Dot(const vec4 &v) const { + return x * (T)v.x + y * (T)v.y + z * (T)v.z + w * (T)v.w; + } + + // Swap Functions + void SwapXY() { + T t = x; + x = y; + y = t; + } + void SwapXZ() { + T t = x; + x = z; + z = t; + } + void SwapXW() { + T t = x; + x = w; + w = t; + } + void SwapYZ() { + T t = y; + y = z; + z = t; + } + void SwapYW() { + T t = y; + y = w; + w = t; + } + void SwapZW() { + T t = z; + z = w; + w = t; + } +}; +using fvec4 = vec4; +using ivec4 = vec4; +using dvec4 = vec4; +} // namespace amy diff --git a/source/c3d.cpp b/source/c3d.cpp index b38c48c..d2aead5 100755 --- a/source/c3d.cpp +++ b/source/c3d.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace amy { @@ -40,13 +41,22 @@ void c3d::shader::load(const std::string& path) { if (!code.size()) { throw std::runtime_error("[amy] shader: unable to load " + path); } - m_code = DVLB_ParseFile((u32*)&code[0], code.size()); + load(code); +} + +void c3d::shader::load(const std::vector& data) { + m_code = DVLB_ParseFile((u32*)&data[0], data.size()); shaderProgramInit(&m_program); shaderProgramSetVsh(&m_program, &m_code->DVLE[0]); C3D_BindProgram(&m_program); AttrInfo_Init(&m_info); } +void c3d::shader::compile(const std::string& code) { + auto ret = Pica::AssembleCode(code.c_str()); + load(ret); +} + void c3d::shader::use() { shaderProgramUse(&m_program); C3D_SetAttrInfo(&m_info); @@ -56,6 +66,14 @@ void c3d::shader::setMat4(int loc, C3D_Mtx* m) { C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, m); } +void c3d::shader::setMat4(int loc, const mat4& m) { + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, (const C3D_Mtx*)&m); +} + +int c3d::shader::loc(const std::string& name) { + return shaderInstanceGetUniformLocation(m_program.vertexShader, name.c_str()); +} + void c3d::shader::input(int reg, GPU_FORMATS f, int num) { AttrInfo_AddLoader(&m_info, reg, f, num); } @@ -71,4 +89,13 @@ void c3d::frag::edit(int id) { m_env = C3D_GetTexEnv(id); C3D_TexEnvInit(m_env); } + +void c3d::drawArrays(int start, int count, GPU_Primitive_t prim) { + C3D_DrawArrays(prim, start, count); +} + +void c3d::drawElements(int count, const void* idx_ptr, int type, + GPU_Primitive_t prim) { + C3D_DrawElements(prim, count, type, idx_ptr); +} } // namespace amy \ No newline at end of file diff --git a/source/iron.cpp b/source/iron.cpp new file mode 100644 index 0000000..94a4e6b --- /dev/null +++ b/source/iron.cpp @@ -0,0 +1,77 @@ +#include + +namespace amy { +const char* __ironshader__ = R"(; LI7 Shader +; Constants +.constf myconst(0.0, 1.0, 0.00392156862745, 0.0) +.alias ones myconst.yyyy ; Vector full of ones + +; Uniforms +.fvec projection[4] + +; Outputs +.out out_position position +.out out_color color +.out out_uv texcoord0 + +; Inputs +.alias in_xy v0 +.alias in_uvc v1 +.alias in_col v2 + +.entry vmain +.proc vmain + mov r0.xy, in_xy.xy + mov r0.w, ones + + dp4 out_position.x, projection[0], r0 + dp4 out_position.y, projection[1], r0 + dp4 out_position.z, projection[2], r0 + dp4 out_position.w, projection[3], r0 + + mov out_uv, in_uvc.xy + + mul r1, myconst.zzzz, in_col + mov out_color, r1 + end +.end)"; +std::vector> iron::m_vbuf; +std::vector> iron::m_ibuf; +int iron::uLocProj = 0; +c3d::shader* iron::m_shader = nullptr; +mat4 iron::m_mtx; +int iron::m_idx = 0, iron::m_vtx = 0; + +void iron::init() { + setupShader(); + m_vbuf.resize(4 * 4096); + m_ibuf.resize(6 * 4096); +} + +void iron::newFrame() { + m_idx = 0; + m_vtx = 0; +} + +void iron::drawOn(c3d::screen* screen) { + m_shader->use(); + m_mtx = mat4::ortho(0.f, (float)screen->width(), (float)screen->height(), 0.f, + 1.f, -1.f); + m_shader->setMat4(uLocProj, m_mtx); +} + +void iron::setupShader() { + m_shader = new c3d::shader(); + m_shader->compile(__ironshader__); + m_shader->input(GPU_FLOAT, 2); // pos + m_shader->input(GPU_FLOAT, 2); // uv + m_shader->input(GPU_UNSIGNED_BYTE, 4); // color + uLocProj = m_shader->loc("projection"); +} + +void iron::fragConfig() { + c3d::frag::edit(); + c3d::frag::src(C3D_Both, GPU_TEXTURE0); + c3d::frag::func(C3D_Both, GPU_MODULATE); +} +} // namespace amy \ No newline at end of file diff --git a/source/maths/mat.cpp b/source/maths/mat.cpp new file mode 100644 index 0000000..47e194b --- /dev/null +++ b/source/maths/mat.cpp @@ -0,0 +1,121 @@ +/* +MIT License + +Copyright (c) 2024 - 2025 tobid7 + +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 + +namespace amy { +mat4 mat4::rotateX(float a) { + float c = std::cos(a); + float s = std::sin(a); + mat4 ret = identity(); + ret(1, 1) = c; + ret(1, 2) = -s; + ret(2, 1) = s; + ret(2, 2) = c; + return ret; +} + +mat4 mat4::rotateY(float a) { + float c = std::cos(a); + float s = std::sin(a); + mat4 ret = identity(); + ret(0, 0) = c; + ret(0, 2) = s; + ret(2, 0) = -s; + ret(2, 2) = c; + return ret; +} + +mat4 mat4::rotateZ(float a) { + float c = std::cos(a); + float s = std::sin(a); + mat4 ret = identity(); + ret(0, 0) = c; + ret(0, 1) = -s; + ret(1, 0) = s; + ret(1, 1) = c; + return ret; +} + +mat4 mat4::rotate(fvec3 axis, float a) { + float s = std::sin(a); + float c = std::cos(a); + float t = 1.f - c; + axis = axis.Normalize(); + float x = axis.x; + float y = axis.y; + float z = axis.z; + mat4 ret = identity(); + ret(0, 0) = t * x * x + c; + ret(0, 1) = t * x * y - z * s; + ret(0, 2) = t * x * z + y * s; + + ret(1, 0) = t * x * y + z * s; + ret(1, 1) = t * y * y + c; + ret(1, 2) = t * y * z - x * s; + + ret(2, 0) = t * x * z - y * s; + ret(2, 1) = t * y * z + x * s; + ret(2, 2) = t * z * z + c; + return ret; +} + +mat4 mat4::perspective(float fov, float aspect, float n, float f) { + float _fov = std::tan(fov / 2.f); + mat4 ret; + ret(0, 0) = 1.f / (aspect * _fov); + ret(1, 1) = 1.f / _fov; +#ifdef __3DS__ + ret(2, 3) = f * n / (n - f); + ret(2, 2) = -(-1.f) * n / (n - f); +#else + ret(2, 2) = -(f + n) / (f - n); + ret(2, 3) = -(2.f * f * n) / (f - n); +#endif + ret(3, 2) = -1.f; + ret(3, 3) = 0.0f; + return ret; +} + +mat4 mat4::lookAt(const fvec3& pos, const fvec3& center, const fvec3& up) { + auto f = fvec3(center - pos).Normalize(); + auto s = f.Cross(up).Normalize(); + auto u = s.Cross(f); + + mat4 ret = identity(); + ret(0, 0) = s.x; + ret(0, 1) = s.y; + ret(0, 2) = s.z; + ret(1, 0) = u.x; + ret(1, 1) = u.y; + ret(1, 2) = u.z; + ret(2, 0) = -f.x; + ret(2, 1) = -f.y; + ret(2, 2) = -f.z; + ret(0, 3) = -s.Dot(pos); + ret(1, 3) = -u.Dot(pos); + ret(2, 3) = f.Dot(pos); + return ret; +} +} // namespace amy \ No newline at end of file diff --git a/vendor/libpicasso b/vendor/libpicasso new file mode 160000 index 0000000..5d47f32 --- /dev/null +++ b/vendor/libpicasso @@ -0,0 +1 @@ +Subproject commit 5d47f32928a62795255e3dcecf8edba5274ae758