Load Fonts in A8 format, Fix Freeze with BMF

This commit is contained in:
2025-12-22 11:41:54 +01:00
parent 4cf3685832
commit 468a112274
7 changed files with 62 additions and 40 deletions

View File

@@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED true)
option(AMY_GOD_DEV "Turn this on if you think you are god" OFF) option(AMY_GOD_DEV "Turn this on if you think you are god" OFF)
# THis option should be disabled if you use STB_IMAGE in you main project # THis option should be disabled if you use STB_IMAGE in you main project
set(AMY_BUILD_STB_IMAGE CACHE BOOL 0) set(AMY_BUILD_STB_IMAGE 0)
set(AMY_BUILD_STB_TRUETYPE 1) set(AMY_BUILD_STB_TRUETYPE 1)
set(AMY_WITH_MPG123 "Include MP3 Support" CACHE BOOL 1) set(AMY_WITH_MPG123 "Include MP3 Support" CACHE BOOL 1)

View File

@@ -11,18 +11,18 @@ class Example : public Amy::App {
Top = C3D::CreateScreen(GFX_TOP); Top = C3D::CreateScreen(GFX_TOP);
Mgr = new Amy::AssetMgr(); Mgr = new Amy::AssetMgr();
Iron::Init(); Iron::Init();
Mgr->AutoLoad("icon", "romfs:/icon.png");
auto fnt = Iron::Font::New(); auto fnt = Iron::Font::New();
fnt->LoadBMF("romfs:/ComicNeue.png"); fnt->LoadBMF("romfs:/ComicNeue.png");
Mgr->AutoLoad("icon", "romfs:/icon.png");
Mgr->Add("font", fnt); Mgr->Add("font", fnt);
// Mgr->AutoLoad("font", "romfs:/ComicNeue.ttf"); // Mgr->AutoLoad("font", "romfs:/ComicNeue.ttf");
dl = new Iron::Drawlist(); dl = Iron::Drawlist::New();
dl->SetFont(Mgr->Get<Iron::Font>("font")); dl->SetFont(Mgr->Get<Iron::Font>("font"));
} }
~Example() { ~Example() {
dl.reset();
delete Top; delete Top;
delete dl;
delete Mgr; delete Mgr;
Iron::Exit(); Iron::Exit();
C3D::Deinit(); C3D::Deinit();
@@ -59,7 +59,7 @@ class Example : public Amy::App {
Iron::NewFrame(); Iron::NewFrame();
Iron::DrawOn(Top); Iron::DrawOn(Top);
Iron::Draw(*dl); Iron::Draw(dl->Data());
dl->Clear(); dl->Clear();
C3D::EndFrame(); C3D::EndFrame();
Amy::GTrace::End("Main"); Amy::GTrace::End("Main");
@@ -67,7 +67,7 @@ class Example : public Amy::App {
C3D::Screen* Top; C3D::Screen* Top;
Amy::AssetMgr* Mgr; Amy::AssetMgr* Mgr;
Iron::Drawlist* dl; Iron::Drawlist::Ref dl = nullptr;
}; };
int main() { int main() {

View File

@@ -70,7 +70,7 @@ class Iron {
struct Codepoint { struct Codepoint {
ui Cp = 0; ui Cp = 0;
fvec4 Uv; fvec4 Uv;
Texture::Ref Tex; Texture::Ref Tex = nullptr;
fvec2 Size; fvec2 Size;
float Offset = 0; // Unused?? float Offset = 0; // Unused??
bool Valid = true; bool Valid = true;
@@ -213,7 +213,7 @@ class Iron {
private: private:
static void pSetupShader(); static void pSetupShader();
static void pFragConfig(); static void pFragConfig(GPU_TEXCOLOR clr);
static void pInitSolidTex(); static void pInitSolidTex();
static bool pCheckSize(size_t idx, size_t vtx); static bool pCheckSize(size_t idx, size_t vtx);

View File

@@ -69,15 +69,14 @@ void C3D::Shader::Load(const std::vector<uc>& data) {
} }
void C3D::Shader::Compile(const std::string& code) { void C3D::Shader::Compile(const std::string& code) {
auto ret = Pica::AssembleCode(code.c_str()); Load(Pica::AssembleCode(code.c_str()));
Load(ret);
} }
void C3D::Shader::Use() { void C3D::Shader::Use() {
// C3D_BindProgram(&pProgram);
// code works perfectly without C3D_BindProgram // code works perfectly without C3D_BindProgram
// but nor withour shaderProgramUse ... // but nor without shaderProgramUse ...
shaderProgramUse(&pProgram); shaderProgramUse(&pProgram);
C3D_BindProgram(&pProgram);
C3D_SetAttrInfo(&pInfo); C3D_SetAttrInfo(&pInfo);
} }

View File

@@ -92,6 +92,17 @@ int Image::GetBppOfFmt(const Image::Format& fmt) {
void Image::Convert(Image& img, const Format& dst) { void Image::Convert(Image& img, const Format& dst) {
if (img.pFmt == dst) { if (img.pFmt == dst) {
return; return;
} else if (img.pFmt == RGBA && dst == A8) {
std::vector<uc> cpy = img.pBuffer;
img.pBuffer.resize(img.pW * img.pH);
for (int y = 0; y < img.pH; y++) {
for (int x = 0; x < img.pW; x++) {
int src = (y * img.pW + x) * 4;
int dst = (y * img.pW + x);
img.pBuffer[dst] = cpy[src + 3];
}
}
img.pFmt = A8;
} else if (img.pFmt == RGB && dst == BGR) { } else if (img.pFmt == RGB && dst == BGR) {
Utils::Image::ReverseBuf(img.pBuffer, img.pW, img.pH, 3); Utils::Image::ReverseBuf(img.pBuffer, img.pW, img.pH, 3);
img.pFmt = BGR; img.pFmt = BGR;

View File

@@ -12,12 +12,14 @@ namespace Amy {
// Dont read this code please ... tnaks // Dont read this code please ... tnaks
void Iron::Font::LoadBMF(ksr path) { void Iron::Font::LoadBMF(ksr path) {
Image img(path); Image img(path);
if (img.Width() != img.Height() || img.Bpp() != 4) { img.Convert(Image::A8);
if (img.Width() != img.Height() || img.Bpp() != 1 || img.Width() <= 0 ||
img.Height() <= 0) {
throw std::runtime_error( throw std::runtime_error(
"[Amy] Font: BMF is not in rgba or not 1x1 dimensioned!"); "[Amy] Font: BMF is not in rgba or not 1x1 dimensioned!");
} }
auto base = Amy::Texture::New(); auto base = Amy::Texture::New();
base->Load(img.GetBuffer(), img.Width(), img.Height(), img.Bpp()); base->Load(img.GetBuffer(), img.Width(), img.Height(), img.Bpp(), img.Fmt());
base->Unloadable(false); base->Unloadable(false);
PxHeight = img.Height() / 16; PxHeight = img.Height() / 16;
for (int i = 0; i < img.Height(); i += PxHeight) { for (int i = 0; i < img.Height(); i += PxHeight) {
@@ -26,25 +28,26 @@ void Iron::Font::LoadBMF(ksr path) {
Amy::Texture::Ref tex = Amy::Texture::New(); Amy::Texture::Ref tex = Amy::Texture::New();
for (int y = i; y < i + PxHeight; y++) { for (int y = i; y < i + PxHeight; y++) {
for (int x = j; x < j + PxHeight; x++) { for (int x = j; x < j + PxHeight; x++) {
if (img.GetBuffer()[((y * img.Width() + x) * 4) + 3] != 0) { if (img.GetBuffer()[y * img.Width() + x] != 0) {
maxw = std::max(maxw, x - j); maxw = std::max(maxw, x - j);
} }
} }
} }
maxw++;
tex->Load(base->Ptr(), base->Size(), base->Uv());
Codepoint cp; Codepoint cp;
cp.Valid = maxw != 0;
cp.Cp = (i / PxHeight) * 16 + (j / PxHeight); cp.Cp = (i / PxHeight) * 16 + (j / PxHeight);
cp.Offset = 0.f; cp.Offset = 0.f;
cp.Size = fvec2(maxw, PxHeight); if (cp.Valid) {
cp.Tex = tex; tex->Load(base->Ptr(), base->Size(), base->Uv());
cp.Uv = fvec4(float(j) / float(img.Width()), cp.Size = fvec2(maxw + 1, PxHeight);
1.f - float(i) / float(img.Height()), cp.Tex = tex;
float(j + maxw) / float(img.Width()), cp.Uv = fvec4(float(j) / float(img.Width()),
1.f - float(i + PxHeight) / float(img.Height())); 1.f - float(i) / float(img.Height()),
cp.Valid = maxw != 0; float(j + maxw + 1) / float(img.Width()),
1.f - float(i + PxHeight) / float(img.Height()));
Textures.push_back(tex);
}
pCodeMap[(i / PxHeight) * 16 + (j / PxHeight)] = cp; pCodeMap[(i / PxHeight) * 16 + (j / PxHeight)] = cp;
Textures.push_back(tex);
} }
} }
} }
@@ -81,7 +84,7 @@ void Iron::Font::LoadTTF(const vec<uc>& data, int size) {
// Cache to not render same codepoint tex twice // Cache to not render same codepoint tex twice
std::map<u32, int> buf_cache; std::map<u32, int> buf_cache;
std::vector<u8> font_tex(texszs * texszs * 4, 0); std::vector<u8> font_tex(texszs * texszs, 0);
auto tex = Texture::New(); auto tex = Texture::New();
fvec2 off; fvec2 off;
@@ -147,12 +150,8 @@ void Iron::Font::LoadTTF(const vec<uc>& data, int size) {
for (int y = 0; y < h; ++y) { for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { for (int x = 0; x < w; ++x) {
int map_pos = ((static_cast<int>(off.y) + y) * texszs + int map_pos = ((static_cast<int>(off.y) + y) * texszs +
(static_cast<int>(off.x) + x)) * (static_cast<int>(off.x) + x));
4; font_tex[map_pos] = bitmap[x + y * w];
font_tex[map_pos + 0] = 255;
font_tex[map_pos + 1] = 255;
font_tex[map_pos + 2] = 255;
font_tex[map_pos + 3] = bitmap[x + y * w];
} }
} }
@@ -171,7 +170,7 @@ void Iron::Font::LoadTTF(const vec<uc>& data, int size) {
void Iron::Font::pMakeAtlas(bool final, vec<uc>& font_tex, int texszs, void Iron::Font::pMakeAtlas(bool final, vec<uc>& font_tex, int texszs,
Texture::Ref tex) { Texture::Ref tex) {
tex->Load(font_tex, texszs, texszs); tex->Load(font_tex, texszs, texszs, 1, Amy::Image::A8);
Textures.push_back(tex); Textures.push_back(tex);
} }

View File

@@ -80,14 +80,14 @@ void Iron::DrawOn(C3D::Screen* screen) {
void Iron::Draw(const std::vector<Iron::Command::Ref>& data) { void Iron::Draw(const std::vector<Iron::Command::Ref>& data) {
// disable depthtest cause we have no z buffer // disable depthtest cause we have no z buffer
C3D::DepthTest(false); C3D::DepthTest(false);
pFragConfig();
size_t i = 0; size_t i = 0;
while (i < data.size()) { while (i < data.size()) {
Texture::Ref tex = data[i]->Tex; Texture::Ref tex = data[i]->Tex;
if (!tex) { if (!tex || !tex->Ptr()) {
i++; i++;
continue; continue;
} }
pFragConfig(tex->Ptr()->fmt);
auto scissorOn = data[i]->ScissorOn; auto scissorOn = data[i]->ScissorOn;
auto scissor = data[i]->ScissorRect; auto scissor = data[i]->ScissorRect;
auto start = m_idx; auto start = m_idx;
@@ -133,17 +133,30 @@ void Iron::pSetupShader() {
uLocProj = m_shader->loc("projection"); uLocProj = m_shader->loc("projection");
} }
void Iron::pFragConfig() { void Iron::pFragConfig(GPU_TEXCOLOR clr) {
C3D::Frag::Edit(); C3D::Frag::Edit();
C3D::Frag::Src(C3D_Both, GPU_TEXTURE0); switch (clr) {
C3D::Frag::Func(C3D_Both, GPU_MODULATE); case GPU_A4:
case GPU_A8:
case GPU_L4:
case GPU_L8:
C3D::Frag::Src(C3D_Alpha, GPU_TEXTURE0);
C3D::Frag::Func(C3D_RGB, GPU_REPLACE);
C3D::Frag::Func(C3D_Alpha, GPU_MODULATE);
break;
default:
C3D::Frag::Src(C3D_Both, GPU_TEXTURE0);
C3D::Frag::Func(C3D_Both, GPU_MODULATE);
break;
}
} }
void Iron::pInitSolidTex() { void Iron::pInitSolidTex() {
// i know there is a lot of memory wasted :( // i know there is a lot of memory wasted :(
std::vector<uc> pixels(16 * 16 * 4, 0xff); std::vector<uc> pixels(16 * 16, 0xff);
m_solid = Texture::New(); m_solid = Texture::New();
m_solid->Load(pixels, 16, 16); m_solid->Load(pixels, 16, 16, 1, Amy::Image::A8);
if (!m_solid->Ptr()) { if (!m_solid->Ptr()) {
throw Error("white tex failed to load!"); throw Error("white tex failed to load!");
} }