Initial Commit
This commit is contained in:
35
source/amethyst.cpp
Executable file
35
source/amethyst.cpp
Executable file
@@ -0,0 +1,35 @@
|
||||
#include <amethyst.hpp>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef AMY_3DS
|
||||
#include <3ds.h>
|
||||
|
||||
void NpiD7CxxExceptionHandler() {
|
||||
gfxInitDefault();
|
||||
consoleInit(GFX_TOP, nullptr);
|
||||
std::cout << "[C++ Error Handler]" << std::endl;
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << "\n\n" << e.what() << std::endl;
|
||||
}
|
||||
aptSetHomeAllowed(false);
|
||||
aptSetSleepAllowed(false);
|
||||
while (aptMainLoop()) {
|
||||
hidScanInput();
|
||||
if (hidKeysDown() & KEY_START) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace amy {
|
||||
void registerCxxExceptionHandler() {
|
||||
#ifdef AMY_3DS
|
||||
std::set_terminate(NpiD7CxxExceptionHandler);
|
||||
#endif
|
||||
}
|
||||
} // namespace amy
|
||||
74
source/c3d.cpp
Executable file
74
source/c3d.cpp
Executable file
@@ -0,0 +1,74 @@
|
||||
#include <citro3d.h>
|
||||
|
||||
#include <amethyst/c3d.hpp>
|
||||
#include <amethyst/utils.hpp>
|
||||
|
||||
namespace amy {
|
||||
|
||||
const auto DISPLAY_TRANSFER_FLAGS =
|
||||
GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) |
|
||||
GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
|
||||
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) |
|
||||
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO);
|
||||
C3D_TexEnv* c3d::frag::m_env = nullptr;
|
||||
|
||||
void c3d::init() { C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); }
|
||||
|
||||
void c3d::deinit() { C3D_Fini(); }
|
||||
|
||||
void c3d::startFrame(bool sync) {
|
||||
C3D_FrameBegin(sync ? C3D_FRAME_SYNCDRAW : C3D_FRAME_NONBLOCK);
|
||||
}
|
||||
|
||||
void c3d::endFrame() { C3D_FrameEnd(0); }
|
||||
|
||||
c3d::screen* c3d::createScreen(gfxScreen_t screen, gfx3dSide_t side) {
|
||||
auto t = C3D_RenderTargetCreate(240, screen == GFX_TOP ? 400 : 320,
|
||||
GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
||||
C3D_RenderTargetSetOutput(t, screen, side, DISPLAY_TRANSFER_FLAGS);
|
||||
return new c3d::screen(t);
|
||||
}
|
||||
|
||||
void c3d::deleteScreen(c3d::screen* screen) { delete screen; }
|
||||
|
||||
c3d::shader::shader(const std::string& path) { load(path); }
|
||||
|
||||
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);
|
||||
}
|
||||
m_code = DVLB_ParseFile((u32*)&code[0], code.size());
|
||||
shaderProgramInit(&m_program);
|
||||
shaderProgramSetVsh(&m_program, &m_code->DVLE[0]);
|
||||
C3D_BindProgram(&m_program);
|
||||
AttrInfo_Init(&m_info);
|
||||
}
|
||||
|
||||
void c3d::shader::use() {
|
||||
shaderProgramUse(&m_program);
|
||||
C3D_SetAttrInfo(&m_info);
|
||||
}
|
||||
|
||||
void c3d::shader::setMat4(int loc, C3D_Mtx* m) {
|
||||
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, loc, m);
|
||||
}
|
||||
|
||||
void c3d::shader::input(int reg, GPU_FORMATS f, int num) {
|
||||
AttrInfo_AddLoader(&m_info, reg, f, num);
|
||||
}
|
||||
|
||||
void c3d::frag::src(C3D_TexEnvMode mode, GPU_TEVSRC s1, GPU_TEVSRC s2,
|
||||
GPU_TEVSRC s3) {
|
||||
C3D_TexEnvSrc(m_env, mode, s1, s2, s3);
|
||||
}
|
||||
void c3d::frag::func(C3D_TexEnvMode mode, GPU_COMBINEFUNC func) {
|
||||
C3D_TexEnvFunc(m_env, mode, func);
|
||||
}
|
||||
void c3d::frag::edit(int id) {
|
||||
m_env = C3D_GetTexEnv(id);
|
||||
C3D_TexEnvInit(m_env);
|
||||
}
|
||||
} // namespace amy
|
||||
16
source/ctru.cpp
Normal file
16
source/ctru.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <3ds.h>
|
||||
|
||||
#include <amethyst/ctru.hpp>
|
||||
|
||||
namespace amy {
|
||||
namespace ctru {
|
||||
void init(unsigned int srvs) {
|
||||
if (srvs & romfs) {
|
||||
romfsInit();
|
||||
}
|
||||
if (srvs & gfx_def) {
|
||||
gfxInitDefault();
|
||||
}
|
||||
}
|
||||
} // namespace ctru
|
||||
} // namespace amy
|
||||
149
source/image.cpp
Executable file
149
source/image.cpp
Executable file
@@ -0,0 +1,149 @@
|
||||
#include <amethyst/image.hpp>
|
||||
#include <amethyst/utils.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
// #define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
namespace amy {
|
||||
void image::load(cstr& path) {
|
||||
int c = 0;
|
||||
uc* buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 4);
|
||||
if (c == 3) {
|
||||
// Releoading the Image with tree channels requestet
|
||||
// Still need to find a better way for this :(
|
||||
stbi_image_free(buf);
|
||||
buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 3);
|
||||
m_buffer.assign(buf, buf + (m_w * m_h * 3));
|
||||
m_fmt = RGB;
|
||||
stbi_image_free(buf);
|
||||
} else if (c == 4) {
|
||||
m_buffer.assign(buf, buf + (m_w * m_h * 4));
|
||||
m_fmt = RGBA;
|
||||
stbi_image_free(buf);
|
||||
} else {
|
||||
throw std::runtime_error(path + " is using an unsupported image format!");
|
||||
}
|
||||
}
|
||||
|
||||
void image::load(const std::vector<uc>& data) {
|
||||
int c = 0;
|
||||
uc* buf =
|
||||
stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 4);
|
||||
if (c == 3) {
|
||||
// Releoading the Image with tree channels requestet
|
||||
// Still need to find a better way for this :(
|
||||
stbi_image_free(buf);
|
||||
buf = stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 3);
|
||||
m_buffer.assign(buf, buf + (m_w * m_h * 3));
|
||||
m_fmt = RGB;
|
||||
stbi_image_free(buf);
|
||||
} else if (m_fmt == 4) {
|
||||
m_buffer.assign(buf, buf + (m_w * m_h * 4));
|
||||
m_fmt = RGBA;
|
||||
stbi_image_free(buf);
|
||||
} else {
|
||||
throw std::runtime_error("image mem using an unsupported image format!");
|
||||
}
|
||||
}
|
||||
|
||||
void image::copy(const std::vector<uc>& pixels, int w, int h,
|
||||
const format& fmt) {
|
||||
int f = getBppOfFmt(fmt);
|
||||
if (pixels.size() != static_cast<size_t>(w * h * f)) {
|
||||
throw std::runtime_error("Connot copy image due to size error!");
|
||||
}
|
||||
m_fmt = fmt;
|
||||
m_w = w;
|
||||
m_h = h;
|
||||
m_buffer.clear();
|
||||
m_buffer.resize(w * h * f);
|
||||
for (size_t i = 0; i < m_buffer.size(); i++) {
|
||||
m_buffer[i] = pixels[i];
|
||||
}
|
||||
}
|
||||
|
||||
int image::getBppOfFmt(const image::format& fmt) {
|
||||
switch (fmt) {
|
||||
case RGBA:
|
||||
case ABGR:
|
||||
case BGRA:
|
||||
return 4;
|
||||
break;
|
||||
case RGB:
|
||||
case BGR:
|
||||
return 3;
|
||||
break;
|
||||
case RGB565:
|
||||
return 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0; // Unknown
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void image::convert(image& img, const format& dst) {
|
||||
if (img.m_fmt == dst) {
|
||||
return;
|
||||
} else if (img.m_fmt == RGB && dst == BGR) {
|
||||
utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 3);
|
||||
img.m_fmt = BGR;
|
||||
} else if (img.m_fmt == RGB && dst == RGBA) {
|
||||
utils::image::addAlphaChannel(img.m_buffer, img.m_w, img.m_h);
|
||||
img.m_fmt = RGBA;
|
||||
} else if (img.m_fmt == RGBA && dst == RGB) {
|
||||
utils::image::removeAlphaChannel(img.m_buffer, img.m_w, img.m_h);
|
||||
img.m_fmt = RGB;
|
||||
} else if (img.m_fmt == RGBA && dst == ABGR) {
|
||||
utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 4);
|
||||
img.m_fmt = ABGR;
|
||||
} else if (img.m_fmt == RGB && dst == ABGR) {
|
||||
convert(img, RGBA);
|
||||
convert(img, ABGR);
|
||||
} else if (img.m_fmt == RGBA && dst == RGB565) {
|
||||
convert(img, RGB);
|
||||
convert(img, RGB565);
|
||||
} else if (img.m_fmt == RGB && dst == RGB565) {
|
||||
// Inlined make pixel 565 func
|
||||
auto f = [](uc r, uc g,
|
||||
uc b) -> unsigned short {
|
||||
unsigned short _r = (r >> 3);
|
||||
unsigned short _g = (g >> 2);
|
||||
unsigned short _b = (b >> 3);
|
||||
return (_r << 11) | (_g << 5) | _b;
|
||||
};
|
||||
std::vector<uc> cpy = img.m_buffer;
|
||||
img.m_buffer.resize(img.m_w * img.m_h * 2);
|
||||
for (int y = 0; y < img.m_w; y++) {
|
||||
for (int x = 0; x < img.m_h; x++) {
|
||||
int src = (y * img.m_w + x) * 3;
|
||||
int dst = (y * img.m_w + x) * 2;
|
||||
unsigned short new_px = f(cpy[src + 0], cpy[src + 1], cpy[src + 2]);
|
||||
img.m_buffer[dst + 0] = new_px >> 8;
|
||||
img.m_buffer[dst + 1] = new_px & 0xff;
|
||||
}
|
||||
}
|
||||
img.m_fmt = RGB565;
|
||||
}
|
||||
}
|
||||
|
||||
void image::retile(image& img,
|
||||
std::function<ui(int x, int y, int w)> src,
|
||||
std::function<ui(int x, int y, int w)> dst) {
|
||||
std::vector<uc> cpy = img.m_buffer;
|
||||
/** could use fmt here but for 565 that woulnt work as it is not supported by
|
||||
* file loading where fmt is used */
|
||||
int bpp = img.bpp();
|
||||
for (int y = 0; y < img.m_h; y++) {
|
||||
for (int x = 0; x < img.m_w; x++) {
|
||||
int src_idx = src(x, y, img.m_w);
|
||||
int dst_idx = dst(x, y, img.m_w);
|
||||
for (int i = 0; i < bpp; i++) {
|
||||
img.m_buffer[dst_idx + i] = cpy[src_idx + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace amy
|
||||
7
source/renderer.cpp
Executable file
7
source/renderer.cpp
Executable file
@@ -0,0 +1,7 @@
|
||||
#include <amethyst/renderer.hpp>
|
||||
|
||||
namespace amy {
|
||||
Renderer::Renderer() {}
|
||||
|
||||
Renderer::~Renderer() {}
|
||||
} // namespace amy
|
||||
84
source/texture.cpp
Executable file
84
source/texture.cpp
Executable file
@@ -0,0 +1,84 @@
|
||||
#include <3ds.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <amethyst/image.hpp>
|
||||
#include <amethyst/texture.hpp>
|
||||
#include <amethyst/utils.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace amy {
|
||||
ui tile3dsTex(int x, int y, int w) {
|
||||
return ((((y >> 3) * ((int)w >> 3) + (x >> 3)) << 6) +
|
||||
((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) |
|
||||
((x & 4) << 2) | ((y & 4) << 3)));
|
||||
}
|
||||
|
||||
GPU_TEXCOLOR image2TexFmt(const image::format& fmt) {
|
||||
switch (fmt) {
|
||||
case image::RGB:
|
||||
return GPU_RGB8;
|
||||
break;
|
||||
case image::RGBA:
|
||||
return GPU_RGBA8;
|
||||
break;
|
||||
case image::RGB565:
|
||||
return GPU_RGB565;
|
||||
break;
|
||||
default:
|
||||
// Dummy
|
||||
return GPU_A4;
|
||||
throw std::runtime_error(
|
||||
"[amy] texture: Unsupported texture format used!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
texture::texture(cstr& path) { load(path); }
|
||||
|
||||
texture::~texture() { unload(); }
|
||||
|
||||
void texture::unload() {
|
||||
if (m_loaded) {
|
||||
C3D_TexDelete(&m_tex);
|
||||
m_loaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
void texture::load(cstr& path) {
|
||||
unload();
|
||||
image img(path);
|
||||
if (img.width() > 1024 || img.height() > 1024) {
|
||||
throw std::runtime_error("Max Texture Size is 1024x1024!");
|
||||
}
|
||||
|
||||
int bpp = img.bpp();
|
||||
m_w = img.width();
|
||||
if (utils::isSingleBitNum(m_w)) {
|
||||
m_w = utils::nextPow2(m_w);
|
||||
}
|
||||
m_h = img.width();
|
||||
if (utils::isSingleBitNum(m_h)) {
|
||||
m_h = utils::nextPow2(m_h);
|
||||
}
|
||||
auto filter = GPU_NEAREST;
|
||||
auto format = image2TexFmt(img.fmt());
|
||||
C3D_TexInit(&m_tex, (u16)m_w, (u16)m_h, 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 src_pos = (y * img.width() + x) * bpp;
|
||||
/// Best idea i had
|
||||
for (int i = 0; i < bpp; i++) {
|
||||
((u8*)m_tex.data)[dst_pos + bpp - 1 - i] = img[src_pos + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
C3D_TexFlush(&m_tex);
|
||||
m_tex.border = 0x00000000;
|
||||
C3D_TexSetWrap(&m_tex, GPU_REPEAT, GPU_REPEAT);
|
||||
m_loaded = true;
|
||||
}
|
||||
} // namespace amy
|
||||
92
source/utils.cpp
Executable file
92
source/utils.cpp
Executable file
@@ -0,0 +1,92 @@
|
||||
#include <amethyst/utils.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace amy {
|
||||
namespace utils {
|
||||
ui fastHash(cstr& s) {
|
||||
ui hash = 5381;
|
||||
for (auto& it : s) {
|
||||
hash = (hash * 33) + static_cast<uc>(it);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
vec<uc> loadFile2Mem(cstr& path) {
|
||||
std::ifstream iff(path, std::ios::binary);
|
||||
if (!iff) {
|
||||
return vec<uc>();
|
||||
}
|
||||
iff.seekg(0, std::ios::end);
|
||||
size_t szs = iff.tellg();
|
||||
iff.seekg(0, std::ios::beg);
|
||||
vec<uc> res(szs, 0);
|
||||
iff.read(reinterpret_cast<char*>(res.data()), res.size());
|
||||
iff.close();
|
||||
return res;
|
||||
}
|
||||
|
||||
ui hashMemory(cvec<uc>& data) {
|
||||
ui hash = 4477;
|
||||
for (auto& it : data) {
|
||||
hash = (hash * 33) + it;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
ui nextPow2(ui v) {
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return (v >= 64 ? v : 64);
|
||||
}
|
||||
|
||||
bool isSingleBitNum(ui v) { return v && !(v & (v - 1)); }
|
||||
|
||||
namespace image {
|
||||
void reverseBuf(vec<uc>& buf, int w, int h, int c) {
|
||||
vec<uc> cpy = buf;
|
||||
for (int x = 0; x < w; x++) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
int pos = (y * w + x) * c;
|
||||
for (size_t i = 0; i < c; i++) {
|
||||
buf[pos + c - 1 - i] = cpy[pos + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeAlphaChannel(vec<uc>& buf, int w, int h) {
|
||||
vec<uc> cpy = buf;
|
||||
buf.resize(w * h * 3);
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int src = (y * w + x) * 4;
|
||||
int dst = (y * w + x) * 3;
|
||||
buf[dst + 0] = cpy[src + 0];
|
||||
buf[dst + 1] = cpy[src + 1];
|
||||
buf[dst + 2] = cpy[src + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addAlphaChannel(vec<uc>& buf, int w, int h) {
|
||||
vec<uc> cpy = buf;
|
||||
buf.resize(w * h * 4);
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int src = (y * w + x) * 3;
|
||||
int dst = (y * w + x) * 4;
|
||||
buf[dst + 0] = cpy[src + 0];
|
||||
buf[dst + 1] = cpy[src + 1];
|
||||
buf[dst + 2] = cpy[src + 2];
|
||||
buf[dst + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace image
|
||||
} // namespace utils
|
||||
} // namespace amy
|
||||
Reference in New Issue
Block a user