diff --git a/CMakeLists.txt b/CMakeLists.txt index f37d0dd..a3f2a2c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,8 @@ add_library(${PROJECT_NAME} STATIC source/utils.cpp source/c3d.cpp source/ctru.cpp - source/iron.cpp + source/iron/iron.cpp + source/iron/drawlist.cpp source/maths/mat.cpp ) target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/include/amethyst/c3d.hpp b/include/amethyst/c3d.hpp index 9415015..39dcf95 100755 --- a/include/amethyst/c3d.hpp +++ b/include/amethyst/c3d.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ class c3d { int width() const { return m_width; } int height() const { return m_height; } + ivec2 size() const { return ivec2(m_width, m_height); } void clear() { C3D_RenderTargetClear(m_target, C3D_CLEAR_ALL, 0, 0); } void startDraw() { C3D_FrameDrawOn(m_target); } @@ -83,5 +85,57 @@ class c3d { 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); + static void depthTest(bool on, GPU_TESTFUNC func = GPU_GREATER, + GPU_WRITEMASK mask = GPU_WRITE_ALL); + static void disableScissor(); + static void enableScissor(const ivec4 rect); + /** + * Buf cfg die permutation at runtime berechnet + */ + static void bufCfg(void* ptr, int stride, int shader_attribs); + /** + * Klassische config bei der man selber die permutation eintragen muss + */ + static void bufCfg(void* ptr, int stride, int shader_attribs, + u64 permutation); + /** + * Hacky funktion um die permutation automatisch at compile time zu berechnen, + * falls diese immer gleich bleibt. + * In der <> steht die anzahl der shader input werte + * usage: c3d::bufCfg<3>(data, sizeof(vertex)); + */ + template + constexpr static void bufCfg(void* ptr, int stride) { + auto buf = C3D_GetBufInfo(); + BufInfo_Init(buf); + constexpr int pm = permutation(attribs); + BufInfo_Add(buf, ptr, stride, attribs, pm); + } + + static int drawcalls() { return m_drawcalls; } + + private: + static int m_drawcalls; + static int m__dc__; + + /** + * Funktion die anhand von **ac** genau den permu station wert für BufInfo + * ausrechnet wie z.B + * ``` + * ac = 3 -> 0x210 + * ac = 4 -> 0x3210 + * ``` + */ + constexpr static u64 permutation(int ac) { + u64 ret = 0; + if (ac < 1 || ac > 15) { + throw std::runtime_error("[amy] " + std::to_string(ac) + + " is out of range (1...15)!"); + } + for (int i = 0; i < ac; i++) { + ret = (ret << 4) | (ac - 1 - i); + } + return ret; + } }; } // namespace amy \ No newline at end of file diff --git a/include/amethyst/iron.hpp b/include/amethyst/iron.hpp index 7a9bfdf..0b04a40 100644 --- a/include/amethyst/iron.hpp +++ b/include/amethyst/iron.hpp @@ -26,6 +26,7 @@ class iron { u32 color = 0; }; class command { + public: command() = default; using ref = up; command& add(const u16& idx) { @@ -58,7 +59,7 @@ class iron { void merge(drawlist* list); command::ref newCommand(); - void push(commad* cmd); + void push(command ::ref cmd); void clear(); void drawSolid(); @@ -74,7 +75,7 @@ class iron { static void init(); static void newFrame(); static void drawOn(c3d::screen* screen); - static void draw(const std::vector& data); + static void draw(const std::vector& data); private: static void setupShader(); diff --git a/include/amethyst/texture.hpp b/include/amethyst/texture.hpp index ab33674..3b8bd7f 100755 --- a/include/amethyst/texture.hpp +++ b/include/amethyst/texture.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace amy { class texture : public asset { @@ -14,17 +15,20 @@ class texture : public asset { void load(cstr& path); void unload(); - int w() const { return m_w; } - int& w() { return m_w; } - int h() const { return m_h; } - int& h() { return m_h; } + int w() const { return m_size.x; } + int& w() { return m_size.x; } + int h() const { return m_size.y; } + int& h() { return m_size.y; } + ivec2 size() const { return m_size; } + ivec2& size() { return m_size; } - C3D_Tex* getTex() { return m_loaded ? &m_tex : nullptr; } + C3D_Tex* ptr() { return m_loaded ? &m_tex : nullptr; } + + void bind(int reg = 0); private: C3D_Tex m_tex; - int m_w = 0; - int m_h = 0; + ivec2 m_size; bool m_loaded = false; }; } // namespace amy \ No newline at end of file diff --git a/include/amethyst/types.hpp b/include/amethyst/types.hpp index 532e2e0..01fda51 100644 --- a/include/amethyst/types.hpp +++ b/include/amethyst/types.hpp @@ -1,7 +1,10 @@ #pragma once +#include +#include #include #include +#include #include #include #include diff --git a/poc/CMakeLists.txt b/poc/CMakeLists.txt new file mode 100644 index 0000000..e39e0b6 --- /dev/null +++ b/poc/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.22) + +add_subdirectory(c3d_permutation) \ No newline at end of file diff --git a/poc/README.md b/poc/README.md new file mode 100644 index 0000000..135c42f --- /dev/null +++ b/poc/README.md @@ -0,0 +1,3 @@ +# Proof of concepts + +This folder contains some proof of concept tests. \ No newline at end of file diff --git a/poc/c3d_permutation/CMakeLists.txt b/poc/c3d_permutation/CMakeLists.txt new file mode 100644 index 0000000..dcbe662 --- /dev/null +++ b/poc/c3d_permutation/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.22) + +project(c3d-permutation) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED true) + +add_executable(c3d-permutation source/main.cpp) \ No newline at end of file diff --git a/poc/c3d_permutation/README.md b/poc/c3d_permutation/README.md new file mode 100644 index 0000000..ef7cc18 --- /dev/null +++ b/poc/c3d_permutation/README.md @@ -0,0 +1,10 @@ +# Citro3D Shader Buf info Permutation calculation + +```cpp +// Why do +BufInfo_Add(buf, data, sizeof(data[0]), 3, 0x210); +BufInfo_Add(buf, data, sizeof(data[0]), 4, 0x3210); +// if we can do +BufInfo_Add(buf, data, sizeof(data[0]), 3, permutation(3)); +BufInfo_Add(buf, data, sizeof(data[0]), 3, permutation(4)); +``` diff --git a/poc/c3d_permutation/source/main.cpp b/poc/c3d_permutation/source/main.cpp new file mode 100644 index 0000000..2bd6e39 --- /dev/null +++ b/poc/c3d_permutation/source/main.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +using u64 = unsigned long long; + +constexpr u64 permutation(int ac) { + u64 ret = 0; + if (ac < 1 || ac > 15) { + throw std::runtime_error("[amy] " + std::to_string(ac) + + " is out of range (1...15)!"); + } + for (int i = 0; i < ac; i++) { + ret = (ret << 4) | (ac - 1 - i); + } + return ret; +} + +int main(int argc, char** argv) { + int v = 3; + if (argc == 2) { + v = std::stoi(argv[1]); + } else { + std::cout << "No input provided! using example..." << std::endl; + } + std::cout << std::format("{} -> {:#x} ({})", v, permutation(v), + permutation(v)) + << std::endl; + return 0; +} \ No newline at end of file diff --git a/source/c3d.cpp b/source/c3d.cpp index d2aead5..83a76c2 100755 --- a/source/c3d.cpp +++ b/source/c3d.cpp @@ -12,6 +12,8 @@ const auto DISPLAY_TRANSFER_FLAGS = GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO); C3D_TexEnv* c3d::frag::m_env = nullptr; +int c3d::m_drawcalls = 0; +int c3d::m__dc__ = 0; void c3d::init() { C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); } @@ -19,9 +21,13 @@ void c3d::deinit() { C3D_Fini(); } void c3d::startFrame(bool sync) { C3D_FrameBegin(sync ? C3D_FRAME_SYNCDRAW : C3D_FRAME_NONBLOCK); + m__dc__ = 0; } -void c3d::endFrame() { C3D_FrameEnd(0); } +void c3d::endFrame() { + C3D_FrameEnd(0); + m_drawcalls = m__dc__; +} c3d::screen* c3d::createScreen(gfxScreen_t screen, gfx3dSide_t side) { auto t = C3D_RenderTargetCreate(240, screen == GFX_TOP ? 400 : 320, @@ -39,7 +45,8 @@ c3d::shader::~shader() {} void c3d::shader::load(const std::string& path) { auto code = utils::loadFile2Mem(path); if (!code.size()) { - throw std::runtime_error("[amy] shader: unable to load " + path); + throw std::runtime_error( + std::format("[amy] unsable to load shader ({})", path)); } load(code); } @@ -58,6 +65,10 @@ void c3d::shader::compile(const std::string& code) { } void c3d::shader::use() { + C3D_BindProgram(&m_program); + // for some reason i need both ??? + // code works perfectly without C3D_BindProgram + // but nor withour shaderProgramUse ... shaderProgramUse(&m_program); C3D_SetAttrInfo(&m_info); } @@ -92,10 +103,32 @@ void c3d::frag::edit(int id) { void c3d::drawArrays(int start, int count, GPU_Primitive_t prim) { C3D_DrawArrays(prim, start, count); + m__dc__++; } void c3d::drawElements(int count, const void* idx_ptr, int type, GPU_Primitive_t prim) { C3D_DrawElements(prim, count, type, idx_ptr); + m__dc__++; +} + +void c3d::depthTest(bool on, GPU_TESTFUNC func, GPU_WRITEMASK mask) { + C3D_DepthTest(on, func, mask); +} + +void c3d::disableScissor() { C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); } + +void c3d::enableScissor(const ivec4 rect) { + C3D_SetScissor(GPU_SCISSOR_NORMAL, rect.x, rect.y, rect.z, rect.w); +} + +void c3d::bufCfg(void* ptr, int stride, int shader_attribs, u64 permutation) { + auto buf = C3D_GetBufInfo(); + BufInfo_Init(buf); + BufInfo_Add(buf, ptr, stride, shader_attribs, permutation); +} + +void c3d::bufCfg(void* ptr, int stride, int shader_attribs) { + bufCfg(ptr, stride, shader_attribs, permutation(shader_attribs)); } } // namespace amy \ No newline at end of file diff --git a/source/iron/drawlist.cpp b/source/iron/drawlist.cpp new file mode 100644 index 0000000..c884bb4 --- /dev/null +++ b/source/iron/drawlist.cpp @@ -0,0 +1,5 @@ +#include + +namespace amy { +void iron::drawlist::merge(iron::drawlist* list) {} +} // namespace amy \ No newline at end of file diff --git a/source/iron.cpp b/source/iron/iron.cpp similarity index 61% rename from source/iron.cpp rename to source/iron/iron.cpp index 94a4e6b..ed3656d 100644 --- a/source/iron.cpp +++ b/source/iron/iron.cpp @@ -60,6 +60,41 @@ void iron::drawOn(c3d::screen* screen) { m_shader->setMat4(uLocProj, m_mtx); } +void iron::draw(const std::vector& data) { + // disable depthtest cause we have no z buffer + c3d::depthTest(false); + fragConfig(); + size_t i = 0; + while (i < data.size()) { + texture* tex = data[i]->tex; + if (!tex) { + i++; + continue; + } + auto scissorOn = data[i]->scissorOn; + auto scissor = data[i]->scissorRect; + auto start = i; + // Loop until a statgechange and copy all data into vertex/index buf + while (i < data.size() && scissorOn == data[i]->scissorOn && + scissor == data[i]->scissorRect && tex == data[i]->tex) { + auto c = data[i].get(); + for (int j = 0; j < c->indexBuf.size(); j++) { + m_ibuf[m_idx++] = m_vtx + c->indexBuf[i]; + } + for (int j = 0; j < c->vertexBuf.size(); j++) { + m_vbuf[m_vtx++] = c->vertexBuf[i]; + } + i++; + } + ///// SCISSOR LOGIC BEG ///// + ///// SCISSOR LOGIC END ///// + tex->bind(); + c3d::bufCfg<3>(m_vbuf.data(), sizeof(vertex)); + c3d::drawElements(i - start, m_ibuf.data() + start); + } + c3d::depthTest(true); +} + void iron::setupShader() { m_shader = new c3d::shader(); m_shader->compile(__ironshader__); diff --git a/source/texture.cpp b/source/texture.cpp index ea24741..b071007 100755 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -51,24 +51,24 @@ void texture::load(cstr& path) { } int bpp = img.bpp(); - m_w = img.width(); - if (utils::isSingleBitNum(m_w)) { - m_w = utils::nextPow2(m_w); + m_size.x = img.width(); + if (utils::isSingleBitNum(m_size.x)) { + m_size.x = utils::nextPow2(m_size.x); } - m_h = img.width(); - if (utils::isSingleBitNum(m_h)) { - m_h = utils::nextPow2(m_h); + m_size.y = img.height(); + if (utils::isSingleBitNum(m_size.y)) { + m_size.y = utils::nextPow2(m_size.y); } auto filter = GPU_NEAREST; auto format = image2TexFmt(img.fmt()); - C3D_TexInit(&m_tex, (u16)m_w, (u16)m_h, format); + C3D_TexInit(&m_tex, (u16)m_size.x, (u16)m_size.y, format); C3D_TexSetFilter(&m_tex, filter, filter); // Using std::fill_n instead cause i hate this error lines // under the memset func in my editor std::fill_n((unsigned char*)m_tex.data, m_tex.size, 0); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { - int dst_pos = tile3dsTex(x, y, m_w) * bpp; + int dst_pos = tile3dsTex(x, y, m_size.x) * bpp; int src_pos = (y * img.width() + x) * bpp; /// Best idea i had for (int i = 0; i < bpp; i++) { @@ -81,4 +81,6 @@ void texture::load(cstr& path) { C3D_TexSetWrap(&m_tex, GPU_REPEAT, GPU_REPEAT); m_loaded = true; } + +void texture::bind(int reg) { C3D_TexBind(reg, &m_tex); } } // namespace amy \ No newline at end of file