Add rendering functions (crashes)
This commit is contained in:
@@ -46,9 +46,16 @@ class example : public amy::app {
|
|||||||
public:
|
public:
|
||||||
example() {
|
example() {
|
||||||
amy::ctru::init();
|
amy::ctru::init();
|
||||||
|
consoleInit(GFX_BOTTOM, NULL);
|
||||||
amy::c3d::init();
|
amy::c3d::init();
|
||||||
m_top = amy::c3d::createScreen(GFX_TOP, GFX_LEFT);
|
m_top = amy::c3d::createScreen(GFX_TOP, GFX_LEFT);
|
||||||
amy::iron::init();
|
amy::iron::init();
|
||||||
|
dl = new amy::iron::drawlist();
|
||||||
|
dl->drawSolid();
|
||||||
|
// throw std::runtime_error(std::format(
|
||||||
|
// "solid tex: {:#08x}\nsize: {}\nptr: {:#08x}",
|
||||||
|
// (amy::ui)amy::iron::whiteTex(), amy::iron::whiteTex()->size(),
|
||||||
|
// (amy::ui)amy::iron::whiteTex()->ptr()));
|
||||||
};
|
};
|
||||||
~example() {
|
~example() {
|
||||||
amy::c3d::deleteScreen(m_top);
|
amy::c3d::deleteScreen(m_top);
|
||||||
@@ -59,13 +66,17 @@ class example : public amy::app {
|
|||||||
amy::c3d::startFrame();
|
amy::c3d::startFrame();
|
||||||
m_top->startDraw();
|
m_top->startDraw();
|
||||||
m_top->clear();
|
m_top->clear();
|
||||||
|
dl->drawRectFilled(0, 50, 0xff00ff00);
|
||||||
amy::iron::newFrame();
|
amy::iron::newFrame();
|
||||||
amy::iron::drawOn(m_top);
|
amy::iron::drawOn(m_top);
|
||||||
|
amy::iron::draw(dl->data());
|
||||||
|
dl->clear();
|
||||||
amy::c3d::endFrame();
|
amy::c3d::endFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
amy::c3d::screen* m_top = nullptr;
|
amy::c3d::screen* m_top = nullptr;
|
||||||
|
amy::iron::drawlist* dl = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ class c3d {
|
|||||||
static void deleteScreen(screen* screen);
|
static void deleteScreen(screen* screen);
|
||||||
static void drawArrays(int start, int count,
|
static void drawArrays(int start, int count,
|
||||||
GPU_Primitive_t prim = GPU_TRIANGLES);
|
GPU_Primitive_t prim = GPU_TRIANGLES);
|
||||||
static void drawElements(int count, const void* idx_ptr, int type = GPU_SHORT,
|
static void drawElements(int count, const void* idx_ptr,
|
||||||
|
int type = C3D_UNSIGNED_SHORT,
|
||||||
GPU_Primitive_t prim = GPU_TRIANGLES);
|
GPU_Primitive_t prim = GPU_TRIANGLES);
|
||||||
static void depthTest(bool on, GPU_TESTFUNC func = GPU_GREATER,
|
static void depthTest(bool on, GPU_TESTFUNC func = GPU_GREATER,
|
||||||
GPU_WRITEMASK mask = GPU_WRITE_ALL);
|
GPU_WRITEMASK mask = GPU_WRITE_ALL);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <amethyst/c3d.hpp>
|
#include <amethyst/c3d.hpp>
|
||||||
#include <amethyst/linearAlloc.hpp>
|
#include <amethyst/linearAlloc.hpp>
|
||||||
#include <amethyst/maths/mat.hpp>
|
#include <amethyst/maths/mat.hpp>
|
||||||
#include <amethyst/maths/vec.hpp>
|
#include <amethyst/maths/vec.hpp>
|
||||||
|
#include <amethyst/rect.hpp>
|
||||||
#include <amethyst/texture.hpp>
|
#include <amethyst/texture.hpp>
|
||||||
#include <amethyst/types.hpp>
|
#include <amethyst/types.hpp>
|
||||||
|
|
||||||
@@ -12,18 +12,23 @@ namespace amy {
|
|||||||
class iron {
|
class iron {
|
||||||
public:
|
public:
|
||||||
struct vertex {
|
struct vertex {
|
||||||
vertex(float x, float y, float u, float v, u32 clr) {
|
vertex(float x, float y, float u, float v, ui clr) {
|
||||||
pos.x = x;
|
pos.x = x;
|
||||||
pos.y = y;
|
pos.y = y;
|
||||||
uv.x = x;
|
uv.x = x;
|
||||||
uv.y = y;
|
uv.y = y;
|
||||||
color = clr;
|
color = clr;
|
||||||
}
|
}
|
||||||
|
vertex(const fvec2& pos, const fvec2& uv, ui clr) {
|
||||||
|
this->pos = pos;
|
||||||
|
this->uv = uv;
|
||||||
|
this->color = clr;
|
||||||
|
}
|
||||||
vertex() {}
|
vertex() {}
|
||||||
|
|
||||||
amy::fvec2 pos;
|
amy::fvec2 pos;
|
||||||
amy::fvec2 uv;
|
amy::fvec2 uv;
|
||||||
u32 color = 0;
|
ui color = 0;
|
||||||
};
|
};
|
||||||
class command {
|
class command {
|
||||||
public:
|
public:
|
||||||
@@ -57,6 +62,8 @@ class iron {
|
|||||||
drawlist(drawlist&&) noexcept = default;
|
drawlist(drawlist&&) noexcept = default;
|
||||||
drawlist& operator=(drawlist&&) noexcept = default;
|
drawlist& operator=(drawlist&&) noexcept = default;
|
||||||
|
|
||||||
|
std::vector<command::ref>& data() { return m_data; }
|
||||||
|
|
||||||
void merge(drawlist* list);
|
void merge(drawlist* list);
|
||||||
command::ref newCommand();
|
command::ref newCommand();
|
||||||
void push(command ::ref cmd);
|
void push(command ::ref cmd);
|
||||||
@@ -65,9 +72,56 @@ class iron {
|
|||||||
void drawSolid();
|
void drawSolid();
|
||||||
void drawTex(texture* tex) { m_tex = tex; }
|
void drawTex(texture* tex) { m_tex = tex; }
|
||||||
|
|
||||||
|
/** Draw Api */
|
||||||
|
void drawRect(const fvec2& pos, const fvec2& size, ui color,
|
||||||
|
int thickness = 1);
|
||||||
|
void drawRectFilled(const fvec2& pos, const fvec2& size, ui color);
|
||||||
|
void drawTriangle(const fvec2& a, const fvec2& b, const fvec2& c, ui color,
|
||||||
|
int thickness = 1);
|
||||||
|
void drawTriangleFilled(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
ui color);
|
||||||
|
void drawCircle(const fvec2& center, float radius, ui color, int segments,
|
||||||
|
int thickness = 1);
|
||||||
|
void drawCircleFilled(const fvec2& center, float radius, ui color,
|
||||||
|
int segments);
|
||||||
|
void drawText(const fvec2& pos, const std::string& text, ui color);
|
||||||
|
void drawTextEx(const fvec2& pos, const std::string& text, ui color,
|
||||||
|
ui flags, const fvec2& box = 0);
|
||||||
|
void drawLine(const fvec2& a, const fvec2& b, ui color, int thickness = 1);
|
||||||
|
void drawPolyLine(const std::vector<fvec2>& points, ui color, ui flags = 0,
|
||||||
|
int thickness = 1);
|
||||||
|
void drawConvexPolyFilled(const std::vector<fvec2>& points, ui color);
|
||||||
|
|
||||||
|
/** Path api */
|
||||||
|
void pathAdd(const fvec2& pos) { m_path.push_back(std::move(pos)); }
|
||||||
|
void pathClear() { m_path.clear(); }
|
||||||
|
void pathReserve(size_t count) { m_path.reserve(m_path.size() + count); }
|
||||||
|
void pathStroke(ui color, int thickness = 1, ui flags = 0) {
|
||||||
|
drawPolyLine(m_path, color, flags, thickness);
|
||||||
|
pathClear();
|
||||||
|
}
|
||||||
|
void pathFill(ui color) { drawConvexPolyFilled(m_path, color); }
|
||||||
|
void pathArcToN(const fvec2& c, float radius, float a_min, float a_max,
|
||||||
|
int segments);
|
||||||
|
void pathFastArcToN(const fvec2& c, float radius, float a_min, float a_max,
|
||||||
|
int segments);
|
||||||
|
void pathRect(const fvec2& a, const fvec2& b, float rounding = 0.f);
|
||||||
|
void pathRectEx(const fvec2& a, const fvec2& b, float rounfing, ui flags);
|
||||||
|
|
||||||
|
void pushClipRect(const fvec4& clip) { clipRects.push(clip); }
|
||||||
|
void popClipRect() {
|
||||||
|
if (!clipRects.empty()) clipRects.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::vector<command::ref>&() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void clipCmd(command* ptr);
|
||||||
std::vector<command::ref> m_data;
|
std::vector<command::ref> m_data;
|
||||||
texture* m_tex;
|
std::vector<fvec2> m_path;
|
||||||
|
texture* m_tex = nullptr;
|
||||||
|
std::stack<fvec4> clipRects;
|
||||||
|
int m_layer = 0;
|
||||||
};
|
};
|
||||||
iron() = default;
|
iron() = default;
|
||||||
~iron() = default;
|
~iron() = default;
|
||||||
@@ -76,10 +130,28 @@ class iron {
|
|||||||
static void newFrame();
|
static void newFrame();
|
||||||
static void drawOn(c3d::screen* screen);
|
static void drawOn(c3d::screen* screen);
|
||||||
static void draw(const std::vector<command::ref>& data);
|
static void draw(const std::vector<command::ref>& data);
|
||||||
|
static texture* whiteTex() { return m_solid; }
|
||||||
|
|
||||||
|
/** Static renderer utility funcs */
|
||||||
|
|
||||||
|
static void rotateCorner(fvec2& pos, float s, float c);
|
||||||
|
static rect primRect(const fvec2& pos, const fvec2& size, float angle = 0.f);
|
||||||
|
static rect primLine(const fvec2& a, const fvec2& b, int thickness = 1);
|
||||||
|
static void cmdQuad(command* cmd, const rect& q, const rect& uv, ui color);
|
||||||
|
static void cmdTriangle(command* cmd, const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, ui clr);
|
||||||
|
static void cmdConvexPolyFilled(command* cmd,
|
||||||
|
const std::vector<fvec2>& points, ui clr,
|
||||||
|
texture* tex);
|
||||||
|
static bool inBox(const fvec2& pos, const fvec2& size, const fvec4& area);
|
||||||
|
static bool inBox(const fvec2& pos, const fvec4& area);
|
||||||
|
static bool inBox(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
const fvec4& area);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void setupShader();
|
static void setupShader();
|
||||||
static void fragConfig();
|
static void fragConfig();
|
||||||
|
static void initSolidTex();
|
||||||
|
|
||||||
static std::vector<vertex, linearAllocator<vertex>> m_vbuf;
|
static std::vector<vertex, linearAllocator<vertex>> m_vbuf;
|
||||||
static std::vector<u16, linearAllocator<u16>> m_ibuf;
|
static std::vector<u16, linearAllocator<u16>> m_ibuf;
|
||||||
@@ -87,5 +159,6 @@ class iron {
|
|||||||
static c3d::shader* m_shader;
|
static c3d::shader* m_shader;
|
||||||
static mat4 m_mtx;
|
static mat4 m_mtx;
|
||||||
static int m_idx, m_vtx;
|
static int m_idx, m_vtx;
|
||||||
|
static texture* m_solid;
|
||||||
};
|
};
|
||||||
} // namespace amy
|
} // namespace amy
|
||||||
61
include/amethyst/rect.hpp
Normal file
61
include/amethyst/rect.hpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <amethyst/types.hpp>
|
||||||
|
|
||||||
|
namespace amy {
|
||||||
|
class rect {
|
||||||
|
public:
|
||||||
|
rect() : m_top(0), m_bot(0) {}
|
||||||
|
~rect() = default;
|
||||||
|
rect(const fvec4& t, const fvec4& b) : m_top(t), m_bot(b) {}
|
||||||
|
rect(const fvec2& tl, const fvec2& tr, const fvec2& bl, const fvec2& br)
|
||||||
|
: m_top(tl, tr), m_bot(bl, br) {}
|
||||||
|
rect(const fvec4& duv)
|
||||||
|
: m_top(duv.x, duv.y, duv.z, duv.y), m_bot(duv.x, duv.w, duv.z, duv.w) {}
|
||||||
|
|
||||||
|
fvec2 topLeft() const { return fvec2(m_top.x, m_top.y); }
|
||||||
|
fvec2 topRight() const { return fvec2(m_top.z, m_top.w); }
|
||||||
|
fvec2 botLeft() const { return fvec2(m_bot.x, m_bot.y); }
|
||||||
|
fvec2 botRight() const { return fvec2(m_bot.z, m_bot.w); }
|
||||||
|
|
||||||
|
fvec4 top() const { return m_top; }
|
||||||
|
fvec4& top() { return m_top; }
|
||||||
|
fvec4 bot() const { return m_bot; }
|
||||||
|
fvec4& bot() { return m_bot; }
|
||||||
|
|
||||||
|
rect& topLeft(const fvec2& v) {
|
||||||
|
m_top.x = v.x;
|
||||||
|
m_top.y = v.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect& topRight(const fvec2& v) {
|
||||||
|
m_top.z = v.x;
|
||||||
|
m_top.w = v.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect& botLeft(const fvec2& v) {
|
||||||
|
m_bot.x = v.x;
|
||||||
|
m_bot.y = v.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect& botRight(const fvec2& v) {
|
||||||
|
m_bot.z = v.x;
|
||||||
|
m_bot.w = v.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapVec2XY() {
|
||||||
|
m_top.SwapXY();
|
||||||
|
m_top.SwapZW();
|
||||||
|
m_bot.SwapXY();
|
||||||
|
m_bot.SwapZW();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
fvec4 m_top;
|
||||||
|
fvec4 m_bot;
|
||||||
|
};
|
||||||
|
} // namespace amy
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <amethyst/asset.hpp>
|
#include <amethyst/asset.hpp>
|
||||||
#include <amethyst/image.hpp>
|
#include <amethyst/image.hpp>
|
||||||
|
#include <amethyst/rect.hpp>
|
||||||
#include <amethyst/types.hpp>
|
#include <amethyst/types.hpp>
|
||||||
|
|
||||||
namespace amy {
|
namespace amy {
|
||||||
@@ -13,6 +14,8 @@ class texture : public asset {
|
|||||||
texture(cstr& path);
|
texture(cstr& path);
|
||||||
~texture();
|
~texture();
|
||||||
void load(cstr& path);
|
void load(cstr& path);
|
||||||
|
void load(const std::vector<uc>& pixels, int w, int h, int bpp = 4,
|
||||||
|
image::format fmt = image::RGBA);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
int w() const { return m_size.x; }
|
int w() const { return m_size.x; }
|
||||||
@@ -21,6 +24,7 @@ class texture : public asset {
|
|||||||
int& h() { return m_size.y; }
|
int& h() { return m_size.y; }
|
||||||
ivec2 size() const { return m_size; }
|
ivec2 size() const { return m_size; }
|
||||||
ivec2& size() { return m_size; }
|
ivec2& size() { return m_size; }
|
||||||
|
rect& uv() { return m_uv; }
|
||||||
|
|
||||||
C3D_Tex* ptr() { return m_loaded ? &m_tex : nullptr; }
|
C3D_Tex* ptr() { return m_loaded ? &m_tex : nullptr; }
|
||||||
|
|
||||||
@@ -29,6 +33,7 @@ class texture : public asset {
|
|||||||
private:
|
private:
|
||||||
C3D_Tex m_tex;
|
C3D_Tex m_tex;
|
||||||
ivec2 m_size;
|
ivec2 m_size;
|
||||||
|
rect m_uv;
|
||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
};
|
};
|
||||||
} // namespace amy
|
} // namespace amy
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <amethyst/maths/vec.hpp>
|
#include <amethyst/maths/vec.hpp>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <numbers>
|
||||||
|
#include <stack>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -1,5 +1,271 @@
|
|||||||
#include <amethyst/iron.hpp>
|
#include <amethyst/iron.hpp>
|
||||||
|
|
||||||
|
/** Setup for everything (oder so) */
|
||||||
|
enum LiPathRectFlags_ : amy::ui {
|
||||||
|
LiPathRectFlags_None = 0,
|
||||||
|
LiPathRectFlags_KeepTopLeft = (1 << 0),
|
||||||
|
LiPathRectFlags_KeepTopRight = (1 << 1),
|
||||||
|
LiPathRectFlags_KeepBotRight = (1 << 2),
|
||||||
|
LiPathRectFlags_KeepBotLeft = (1 << 3),
|
||||||
|
LiPathRectFlags_KeepTop = (1 << 0) | (1 << 1),
|
||||||
|
LiPathRectFlags_KeepBot = (1 << 2) | (1 << 3),
|
||||||
|
LiPathRectFlags_KeepLeft = (1 << 0) | (1 << 3),
|
||||||
|
LiPathRectFlags_KeepRight = (1 << 1) | (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
namespace amy {
|
namespace amy {
|
||||||
void iron::drawlist::merge(iron::drawlist* list) {}
|
constexpr auto __pi = std::numbers::pi;
|
||||||
|
|
||||||
|
void iron::drawlist::merge(iron::drawlist* list) {
|
||||||
|
for (size_t i = 0; i < list->m_data.size(); i++) {
|
||||||
|
m_data.push_back(std::move(list->m_data[i]));
|
||||||
|
}
|
||||||
|
list->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::clear() { m_data.clear(); }
|
||||||
|
|
||||||
|
iron::command::ref iron::drawlist::newCommand() {
|
||||||
|
auto ret = std::make_unique<command>();
|
||||||
|
ret->layer = m_layer;
|
||||||
|
ret->index = m_data.size();
|
||||||
|
ret->tex = m_tex;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::clipCmd(command* ptr) {
|
||||||
|
if (!clipRects.empty()) {
|
||||||
|
ptr->scissorOn = true;
|
||||||
|
ptr->scissorRect = ivec4(clipRects.top());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::push(command::ref cmd) {
|
||||||
|
m_data.push_back(std::move(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawSolid() { m_tex = iron::whiteTex(); }
|
||||||
|
|
||||||
|
void iron::drawlist::pathArcToN(const fvec2& c, float radius, float a_min,
|
||||||
|
float a_max, int segments) {
|
||||||
|
// pathAdd(c)
|
||||||
|
pathReserve(segments + 1);
|
||||||
|
for (int i = 0; i < segments; i++) {
|
||||||
|
float a = a_min + ((float)i / (float)segments) * (a_max - a_min);
|
||||||
|
pathAdd(fvec2(c.x + std::cos(a) * radius, c.y + std::sin(a) * radius));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::pathFastArcToN(const fvec2& c, float r, float amin,
|
||||||
|
float amax, int s) {
|
||||||
|
/**
|
||||||
|
* Funcion with less division overhead
|
||||||
|
* Usefull for stuff where a lot of calculations are required
|
||||||
|
*/
|
||||||
|
float d = (amax - amin) / s;
|
||||||
|
pathReserve(s + 1);
|
||||||
|
for (int i = 0; i <= s; i++) {
|
||||||
|
float a = amin + i * d;
|
||||||
|
pathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::pathRect(const fvec2& a, const fvec2& b, float rounding) {
|
||||||
|
if (rounding == 0.f) {
|
||||||
|
pathAdd(a);
|
||||||
|
pathAdd(fvec2(b.x, a.y));
|
||||||
|
pathAdd(b);
|
||||||
|
pathAdd(fvec2(a.x, b.y));
|
||||||
|
} else {
|
||||||
|
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
|
||||||
|
/** Calculate Optimal segment count automatically */
|
||||||
|
float corner = __pi * 0.5f;
|
||||||
|
int segments = std::max(3, int(std::ceil(corner / (6.0f * __pi / 180.0f))));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Correctly render filled shapes with Paths API
|
||||||
|
* The Commands need to be setup clockwise
|
||||||
|
*/
|
||||||
|
/** Top Left */
|
||||||
|
pathAdd(fvec2(a.x + r, a.y));
|
||||||
|
pathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments);
|
||||||
|
/** Top Right */
|
||||||
|
pathAdd(fvec2(b.x, b.y - r));
|
||||||
|
pathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments);
|
||||||
|
/** Bottom Right */
|
||||||
|
pathAdd(fvec2(a.x + r, b.y));
|
||||||
|
pathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments);
|
||||||
|
/** Bottom Left */
|
||||||
|
pathAdd(fvec2(a.x, a.y + r));
|
||||||
|
pathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f,
|
||||||
|
segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::pathRectEx(const fvec2& a, const fvec2& b, float rounding,
|
||||||
|
ui flags) {
|
||||||
|
if (rounding == 0.f) {
|
||||||
|
pathAdd(a);
|
||||||
|
pathAdd(fvec2(b.x, a.y));
|
||||||
|
pathAdd(b);
|
||||||
|
pathAdd(fvec2(a.x, b.y));
|
||||||
|
} else {
|
||||||
|
float r = std::min({rounding, (b.x - a.x) * 0.5f, (b.y - a.y) * 0.5f});
|
||||||
|
/** Calculate Optimal segment count automatically */
|
||||||
|
float corner = __pi * 0.5f;
|
||||||
|
int segments = std::max(3, int(std::ceil(corner / (6.0f * __pi / 180.0f))));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Correctly render filled shapes with Paths API
|
||||||
|
* The Commands need to be setup clockwise
|
||||||
|
*/
|
||||||
|
/** Top Left */
|
||||||
|
if (flags & LiPathRectFlags_KeepTopLeft) {
|
||||||
|
pathAdd(a);
|
||||||
|
} else {
|
||||||
|
pathAdd(fvec2(a.x + r, a.y));
|
||||||
|
pathFastArcToN(fvec2(b.x - r, a.y + r), r, -__pi / 2.0f, 0.0f, segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Top Right */
|
||||||
|
if (flags & LiPathRectFlags_KeepTopRight) {
|
||||||
|
pathAdd(fvec2(b.x, a.y));
|
||||||
|
} else {
|
||||||
|
pathAdd(fvec2(b.x, b.y - r));
|
||||||
|
pathFastArcToN(fvec2(b.x - r, b.y - r), r, 0.0f, __pi / 2.0f, segments);
|
||||||
|
}
|
||||||
|
/** Bottom Right */
|
||||||
|
if (flags & LiPathRectFlags_KeepBotRight) {
|
||||||
|
pathAdd(b);
|
||||||
|
} else {
|
||||||
|
pathAdd(fvec2(a.x + r, b.y));
|
||||||
|
pathFastArcToN(fvec2(a.x + r, b.y - r), r, __pi / 2.0f, __pi, segments);
|
||||||
|
}
|
||||||
|
/** Bottom Left */
|
||||||
|
if (flags & LiPathRectFlags_KeepBotLeft) {
|
||||||
|
pathAdd(fvec2(a.x, b.y));
|
||||||
|
} else {
|
||||||
|
pathAdd(fvec2(a.x, a.y + r));
|
||||||
|
pathFastArcToN(fvec2(a.x + r, a.y + r), r, __pi, 3.0f * __pi / 2.0f,
|
||||||
|
segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawRect(const fvec2& pos, const fvec2& size, ui color,
|
||||||
|
int thickness) {
|
||||||
|
pathRect(pos, pos + size);
|
||||||
|
pathStroke(color, thickness, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawRectFilled(const fvec2& pos, const fvec2& size,
|
||||||
|
ui color) {
|
||||||
|
pathRect(pos, pos + size);
|
||||||
|
pathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawTriangle(const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, ui color, int thickness) {
|
||||||
|
pathAdd(a);
|
||||||
|
pathAdd(b);
|
||||||
|
pathAdd(c);
|
||||||
|
pathStroke(color, thickness, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawTriangleFilled(const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, ui color) {
|
||||||
|
pathAdd(a);
|
||||||
|
pathAdd(b);
|
||||||
|
pathAdd(c);
|
||||||
|
pathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawCircle(const fvec2& center, float rad, ui color,
|
||||||
|
int segments, int thickness) {
|
||||||
|
if (segments <= 0) {
|
||||||
|
// Auto Segment
|
||||||
|
} else {
|
||||||
|
float am = (__pi * 2.0f) * ((float)segments) / (float)segments;
|
||||||
|
pathArcToN(center, rad, 0.f, am, segments);
|
||||||
|
}
|
||||||
|
drawSolid(); // Only Solid Color Supported
|
||||||
|
pathStroke(color, thickness, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawCircleFilled(const fvec2& center, float rad, ui color,
|
||||||
|
int segments) {
|
||||||
|
if (segments <= 0) {
|
||||||
|
// Auto Segment
|
||||||
|
} else {
|
||||||
|
float am = (__pi * 2.0f) * ((float)segments) / (float)segments;
|
||||||
|
pathArcToN(center, rad, 0.f, am, segments);
|
||||||
|
}
|
||||||
|
pathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawPolyLine(const std::vector<fvec2>& points, ui clr,
|
||||||
|
ui flags, int thickness) {
|
||||||
|
if (points.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
drawSolid();
|
||||||
|
auto cmd = newCommand();
|
||||||
|
bool close = (flags & (1 << 0));
|
||||||
|
int num_points = close ? (int)points.size() : (int)points.size() - 1;
|
||||||
|
if (flags & (1 << 1)) {
|
||||||
|
// TODO: Find a way to draw less garbage looking lines
|
||||||
|
} else {
|
||||||
|
// Non antialiased lines look awful when rendering with thickness != 1
|
||||||
|
for (int i = 0; i < num_points; i++) {
|
||||||
|
int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
|
||||||
|
auto line = primLine(points[i], points[j], thickness);
|
||||||
|
cmdQuad(cmd.get(), line, fvec4(0.f, 1.f, 1.f, 0.f), clr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push(std::move(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawConvexPolyFilled(const std::vector<fvec2>& points,
|
||||||
|
ui clr) {
|
||||||
|
if (points.size() < 3) {
|
||||||
|
return; // Need at least three points
|
||||||
|
}
|
||||||
|
auto cmd = newCommand();
|
||||||
|
cmdConvexPolyFilled(cmd.get(), points, clr, m_tex);
|
||||||
|
push(std::move(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawText(const fvec2& pos, const std::string& text,
|
||||||
|
ui color) {
|
||||||
|
/*if (!pCurrentFont) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<Command::Ref> cmds;
|
||||||
|
pCurrentFont->CmdTextEx(cmds, pos, color, pFontScale, text);
|
||||||
|
for (size_t i = 0; i < cmds.size(); i++) {
|
||||||
|
cmds[i]->Index = pDrawList.size();
|
||||||
|
cmds[i]->Layer = Layer;
|
||||||
|
AddCommand(std::move(cmds[i]));
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawTextEx(const fvec2& p, const std::string& text,
|
||||||
|
ui color, ui flags, const fvec2& box) {
|
||||||
|
/*if (!pCurrentFont) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<Command::Ref> cmds;
|
||||||
|
pCurrentFont->CmdTextEx(cmds, p, color, pFontScale, text, flags, box);
|
||||||
|
for (size_t i = 0; i < cmds.size(); i++) {
|
||||||
|
cmds[i]->Index = pDrawList.size();
|
||||||
|
cmds[i]->Layer = Layer;
|
||||||
|
AddCommand(std::move(cmds[i]));
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::drawlist::drawLine(const fvec2& a, const fvec2& b, ui color, int t) {
|
||||||
|
pathAdd(a);
|
||||||
|
pathAdd(b);
|
||||||
|
pathStroke(color, t);
|
||||||
|
}
|
||||||
} // namespace amy
|
} // namespace amy
|
||||||
@@ -1,4 +1,17 @@
|
|||||||
#include <amethyst/iron.hpp>
|
#include <amethyst/iron.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define catch2() \
|
||||||
|
; \
|
||||||
|
({ \
|
||||||
|
std::cout << std::format("{}:{}", __FILE__, __LINE__) << std::endl; \
|
||||||
|
while (aptMainLoop()) { \
|
||||||
|
hidScanInput(); \
|
||||||
|
if (hidKeysDown() & KEY_A) { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
namespace amy {
|
namespace amy {
|
||||||
const char* __ironshader__ = R"(; LI7 Shader
|
const char* __ironshader__ = R"(; LI7 Shader
|
||||||
@@ -35,17 +48,26 @@ const char* __ironshader__ = R"(; LI7 Shader
|
|||||||
mov out_color, r1
|
mov out_color, r1
|
||||||
end
|
end
|
||||||
.end)";
|
.end)";
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
unsigned char li_shader[] = {
|
||||||
|
0x44, 0x56, 0x4c, 0x42, 0x1, 0x0, 0x0, 0x0, 0xa4, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x50, 0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x1, 0xf0, 0x7, 0x4e, 0x2, 0x8, 0x2, 0x8, 0x3, 0x18, 0x2, 0x8, 0x4, 0x28, 0x2, 0x8, 0x5, 0x38, 0x2, 0x8, 0x6, 0x10, 0x40, 0x4c, 0x7, 0xf1, 0x27, 0x22, 0x8, 0x10, 0x21, 0x4c, 0x0, 0x0, 0x0, 0x88, 0xac, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x61, 0xc3, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0xaf, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xd5, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x56, 0x4c, 0x45, 0x2, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x2, 0x0, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x1, 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x2, 0x0, 0x1, 0x0, 0xf, 0x0, 0x0, 0x0, 0x3, 0x0, 0x2, 0x0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x13, 0x0, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
size_t li_shader_size = 0x124;
|
||||||
std::vector<iron::vertex, linearAllocator<iron::vertex>> iron::m_vbuf;
|
std::vector<iron::vertex, linearAllocator<iron::vertex>> iron::m_vbuf;
|
||||||
std::vector<u16, linearAllocator<u16>> iron::m_ibuf;
|
std::vector<u16, linearAllocator<u16>> iron::m_ibuf;
|
||||||
int iron::uLocProj = 0;
|
int iron::uLocProj = 0;
|
||||||
c3d::shader* iron::m_shader = nullptr;
|
c3d::shader* iron::m_shader = nullptr;
|
||||||
mat4 iron::m_mtx;
|
mat4 iron::m_mtx;
|
||||||
int iron::m_idx = 0, iron::m_vtx = 0;
|
int iron::m_idx = 0, iron::m_vtx = 0;
|
||||||
|
texture* iron::m_solid = nullptr;
|
||||||
|
|
||||||
void iron::init() {
|
void iron::init() {
|
||||||
setupShader();
|
setupShader();
|
||||||
m_vbuf.resize(4 * 4096);
|
m_vbuf.resize(4 * 4096);
|
||||||
m_ibuf.resize(6 * 4096);
|
m_ibuf.resize(6 * 4096);
|
||||||
|
initSolidTex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void iron::newFrame() {
|
void iron::newFrame() {
|
||||||
@@ -53,11 +75,16 @@ void iron::newFrame() {
|
|||||||
m_vtx = 0;
|
m_vtx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
C3D_Mtx m;
|
||||||
|
|
||||||
void iron::drawOn(c3d::screen* screen) {
|
void iron::drawOn(c3d::screen* screen) {
|
||||||
m_shader->use();
|
m_shader->use();
|
||||||
|
Mtx_Identity(&m);
|
||||||
|
Mtx_OrthoTilt(&m, 0.f, (float)screen->width(), (float)screen->height(), 0.f,
|
||||||
|
1.f, -1.f, false);
|
||||||
m_mtx = mat4::ortho(0.f, (float)screen->width(), (float)screen->height(), 0.f,
|
m_mtx = mat4::ortho(0.f, (float)screen->width(), (float)screen->height(), 0.f,
|
||||||
1.f, -1.f);
|
1.f, -1.f);
|
||||||
m_shader->setMat4(uLocProj, m_mtx);
|
m_shader->setMat4(uLocProj, &m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void iron::draw(const std::vector<iron::command::ref>& data) {
|
void iron::draw(const std::vector<iron::command::ref>& data) {
|
||||||
@@ -74,10 +101,12 @@ void iron::draw(const std::vector<iron::command::ref>& data) {
|
|||||||
auto scissorOn = data[i]->scissorOn;
|
auto scissorOn = data[i]->scissorOn;
|
||||||
auto scissor = data[i]->scissorRect;
|
auto scissor = data[i]->scissorRect;
|
||||||
auto start = i;
|
auto start = i;
|
||||||
|
|
||||||
// Loop until a statgechange and copy all data into vertex/index buf
|
// Loop until a statgechange and copy all data into vertex/index buf
|
||||||
while (i < data.size() && scissorOn == data[i]->scissorOn &&
|
while (i < data.size() && scissorOn == data[i]->scissorOn &&
|
||||||
scissor == data[i]->scissorRect && tex == data[i]->tex) {
|
scissor == data[i]->scissorRect && tex == data[i]->tex) {
|
||||||
auto c = data[i].get();
|
auto c = data[i].get();
|
||||||
|
|
||||||
for (int j = 0; j < c->indexBuf.size(); j++) {
|
for (int j = 0; j < c->indexBuf.size(); j++) {
|
||||||
m_ibuf[m_idx++] = m_vtx + c->indexBuf[i];
|
m_ibuf[m_idx++] = m_vtx + c->indexBuf[i];
|
||||||
}
|
}
|
||||||
@@ -97,7 +126,8 @@ void iron::draw(const std::vector<iron::command::ref>& data) {
|
|||||||
|
|
||||||
void iron::setupShader() {
|
void iron::setupShader() {
|
||||||
m_shader = new c3d::shader();
|
m_shader = new c3d::shader();
|
||||||
m_shader->compile(__ironshader__);
|
m_shader->load("romfs:/shaders/lithium.shbin");
|
||||||
|
// m_shader->compile(__ironshader__);
|
||||||
m_shader->input(GPU_FLOAT, 2); // pos
|
m_shader->input(GPU_FLOAT, 2); // pos
|
||||||
m_shader->input(GPU_FLOAT, 2); // uv
|
m_shader->input(GPU_FLOAT, 2); // uv
|
||||||
m_shader->input(GPU_UNSIGNED_BYTE, 4); // color
|
m_shader->input(GPU_UNSIGNED_BYTE, 4); // color
|
||||||
@@ -109,4 +139,126 @@ void iron::fragConfig() {
|
|||||||
c3d::frag::src(C3D_Both, GPU_TEXTURE0);
|
c3d::frag::src(C3D_Both, GPU_TEXTURE0);
|
||||||
c3d::frag::func(C3D_Both, GPU_MODULATE);
|
c3d::frag::func(C3D_Both, GPU_MODULATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iron::initSolidTex() {
|
||||||
|
// i know there is a lot of memory wasted :(
|
||||||
|
std::vector<uc> pixels(16 * 16 * 4, 0xff);
|
||||||
|
m_solid = new texture();
|
||||||
|
m_solid->load(pixels, 16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iron::inBox(const fvec2& pos, const fvec2& size, const fvec4& area) {
|
||||||
|
return (pos.x + size.x >= area.x && pos.y + size.y >= area.y &&
|
||||||
|
pos.x <= area.z && pos.y <= area.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iron::inBox(const fvec2& pos, const fvec4& area) {
|
||||||
|
return (pos.x > area.x && pos.x < area.x + area.z && pos.y > area.y &&
|
||||||
|
pos.y < area.y + area.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iron::inBox(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
const fvec4& area) {
|
||||||
|
return ((a.x < area.z && b.x < area.z && c.x < area.z) ||
|
||||||
|
(a.y < area.w && b.y < area.w && c.y < area.w) ||
|
||||||
|
(a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::rotateCorner(fvec2& pos, float s, float c) {
|
||||||
|
float x = pos.x * c - pos.y * s;
|
||||||
|
float y = pos.y * c - pos.x * s;
|
||||||
|
pos = fvec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect iron::primRect(const fvec2& pos, const fvec2& size, float angle) {
|
||||||
|
fvec2 c = size * 0.5f; // Center
|
||||||
|
fvec2 corner[4] = {
|
||||||
|
fvec2(-c.x, -c.y),
|
||||||
|
fvec2(-c.x + size.x, -c.y),
|
||||||
|
fvec2(-c.x, -c.y + size.y),
|
||||||
|
fvec2(-c.x + size.x, -c.y + size.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only rotate if required
|
||||||
|
if (angle != 0.f) {
|
||||||
|
float s = std::sin(angle);
|
||||||
|
float co = std::cos(angle);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
rotateCorner(corner[i], s, co);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Result
|
||||||
|
return rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c,
|
||||||
|
corner[3] + pos + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect iron::primLine(const fvec2& a, const fvec2& b, int thickness) {
|
||||||
|
// Using the vec maths api makes the code as short as it is
|
||||||
|
fvec2 dir = a - b;
|
||||||
|
float len = dir.Len();
|
||||||
|
fvec2 unit_dir = dir / len;
|
||||||
|
fvec2 perpendicular(-unit_dir.y, unit_dir.x);
|
||||||
|
fvec2 off = perpendicular * ((float)thickness * 0.5f);
|
||||||
|
|
||||||
|
return rect(a + off, b + off, a - off, b - off);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::cmdQuad(command* cmd, const rect& q, const rect& uv, ui color) {
|
||||||
|
cmd->add(0).add(1).add(2);
|
||||||
|
cmd->add(0).add(2).add(3);
|
||||||
|
cmd->add(vertex(q.botRight(), uv.botRight(), color));
|
||||||
|
cmd->add(vertex(q.topRight(), uv.topRight(), color));
|
||||||
|
cmd->add(vertex(q.topLeft(), uv.topLeft(), color));
|
||||||
|
cmd->add(vertex(q.botLeft(), uv.botLeft(), color));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::cmdTriangle(command* cmd, const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, ui color) {
|
||||||
|
cmd->add(2).add(1).add(0); // reverse cause otherwise invisible
|
||||||
|
cmd->add(vertex(a, fvec2(0, 1), color));
|
||||||
|
cmd->add(vertex(b, fvec2(1, 1), color));
|
||||||
|
cmd->add(vertex(c, fvec2(1, 0), color));
|
||||||
|
}
|
||||||
|
|
||||||
|
void iron::cmdConvexPolyFilled(command* cmd, const std::vector<fvec2>& points,
|
||||||
|
ui color, texture* tex) {
|
||||||
|
if (points.size() < 3 || tex == nullptr) {
|
||||||
|
#ifdef AMY_GOD_DEV
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
throw std::runtime_error("[amy] iron: trying to render convex poly with " +
|
||||||
|
std::to_string(points.size()) +
|
||||||
|
" points and texture " + std::to_string((ui)tex));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Support for Custom Textures (UV calculation)
|
||||||
|
float minX = points[0].x, minY = points[0].y;
|
||||||
|
float maxX = minX, maxY = minY;
|
||||||
|
// Check for the max and min Positions
|
||||||
|
for (const auto& it : points) {
|
||||||
|
if (it.x < minX) minX = it.x;
|
||||||
|
if (it.y < minY) minY = it.y;
|
||||||
|
if (it.x > maxX) maxX = it.x;
|
||||||
|
if (it.y > maxY) maxY = it.y;
|
||||||
|
}
|
||||||
|
// Get Short defines for UV
|
||||||
|
// (Bottom Right is not required)
|
||||||
|
auto uv_tl = tex->uv().topLeft();
|
||||||
|
auto uv_tr = tex->uv().topRight();
|
||||||
|
auto uv_bl = tex->uv().botLeft();
|
||||||
|
|
||||||
|
// Render
|
||||||
|
for (int i = 2; i < (int)points.size(); i++) {
|
||||||
|
cmd->add(0).add(i).add(i - 1);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < (int)points.size(); i++) {
|
||||||
|
// Calculate U and V coords
|
||||||
|
float u =
|
||||||
|
uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
|
||||||
|
float v =
|
||||||
|
uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
|
||||||
|
cmd->add(vertex(points[i], fvec2(u, v), color));
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace amy
|
} // namespace amy
|
||||||
@@ -44,35 +44,42 @@ void texture::unload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void texture::load(cstr& path) {
|
void texture::load(cstr& path) {
|
||||||
unload();
|
|
||||||
image img(path);
|
image img(path);
|
||||||
if (img.width() > 1024 || img.height() > 1024) {
|
if (img.width() > 1024 || img.height() > 1024) {
|
||||||
throw std::runtime_error("Max Texture Size is 1024x1024!");
|
throw std::runtime_error("Max Texture Size is 1024x1024!");
|
||||||
}
|
}
|
||||||
|
load(img.getBuffer(), img.width(), img.height(), img.bpp(), img.fmt());
|
||||||
|
}
|
||||||
|
|
||||||
int bpp = img.bpp();
|
void texture::load(const std::vector<uc>& pixels, int w, int h, int bpp,
|
||||||
m_size.x = img.width();
|
image::format fmt) {
|
||||||
|
if (w > 1024 || h > 1024) {
|
||||||
|
throw std::runtime_error("Max Texture Size is 1024x1024!");
|
||||||
|
}
|
||||||
|
unload();
|
||||||
|
|
||||||
|
m_size.x = w;
|
||||||
if (utils::isSingleBitNum(m_size.x)) {
|
if (utils::isSingleBitNum(m_size.x)) {
|
||||||
m_size.x = utils::nextPow2(m_size.x);
|
m_size.x = utils::nextPow2(m_size.x);
|
||||||
}
|
}
|
||||||
m_size.y = img.height();
|
m_size.y = h;
|
||||||
if (utils::isSingleBitNum(m_size.y)) {
|
if (utils::isSingleBitNum(m_size.y)) {
|
||||||
m_size.y = utils::nextPow2(m_size.y);
|
m_size.y = utils::nextPow2(m_size.y);
|
||||||
}
|
}
|
||||||
auto filter = GPU_NEAREST;
|
auto filter = GPU_NEAREST;
|
||||||
auto format = image2TexFmt(img.fmt());
|
auto format = image2TexFmt(fmt);
|
||||||
C3D_TexInit(&m_tex, (u16)m_size.x, (u16)m_size.y, format);
|
C3D_TexInit(&m_tex, (u16)m_size.x, (u16)m_size.y, format);
|
||||||
C3D_TexSetFilter(&m_tex, filter, filter);
|
C3D_TexSetFilter(&m_tex, filter, filter);
|
||||||
// Using std::fill_n instead cause i hate this error lines
|
// Using std::fill_n instead cause i hate this error lines
|
||||||
// under the memset func in my editor
|
// under the memset func in my editor
|
||||||
std::fill_n((unsigned char*)m_tex.data, m_tex.size, 0);
|
std::fill_n((unsigned char*)m_tex.data, m_tex.size, 0);
|
||||||
for (int x = 0; x < img.width(); x++) {
|
for (int x = 0; x < w; x++) {
|
||||||
for (int y = 0; y < img.height(); y++) {
|
for (int y = 0; y < h; y++) {
|
||||||
int dst_pos = tile3dsTex(x, y, m_size.x) * bpp;
|
int dst_pos = tile3dsTex(x, y, m_size.x) * bpp;
|
||||||
int src_pos = (y * img.width() + x) * bpp;
|
int src_pos = (y * w + x) * bpp;
|
||||||
/// Best idea i had
|
/// Best idea i had
|
||||||
for (int i = 0; i < bpp; i++) {
|
for (int i = 0; i < bpp; i++) {
|
||||||
((u8*)m_tex.data)[dst_pos + bpp - 1 - i] = img[src_pos + i];
|
((u8*)m_tex.data)[dst_pos + bpp - 1 - i] = pixels[src_pos + i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user