diff --git a/include/cpp3ds/Graphics/Texture.hpp b/include/cpp3ds/Graphics/Texture.hpp index 4eecab5..4a1062e 100644 --- a/include/cpp3ds/Graphics/Texture.hpp +++ b/include/cpp3ds/Graphics/Texture.hpp @@ -216,6 +216,13 @@ public : //////////////////////////////////////////////////////////// bool loadFromImage(const Image& image, const IntRect& area = IntRect()); +#ifndef EMULATION + bool loadFromPreprocessedFile(const std::string& filename, size_t width, size_t height, GPU_TEXCOLOR format); + bool loadFromPreprocessedMemory(void *data, size_t size, size_t width, size_t height, GPU_TEXCOLOR format, bool copyData = true); + + C3D_Tex* getNativeTexture() { return m_texture; } +#endif + //////////////////////////////////////////////////////////// /// \brief Return the size of the texture /// @@ -501,6 +508,7 @@ private : unsigned int m_texture; ///< Internal texture identifier #else C3D_Tex* m_texture; ///< Internal texture identifier + bool m_ownsData; ///< Check if this object owns the data and needs to free it #endif }; diff --git a/include/cpp3ds/Window/Game.hpp b/include/cpp3ds/Window/Game.hpp index cf199e2..f267700 100644 --- a/include/cpp3ds/Window/Game.hpp +++ b/include/cpp3ds/Window/Game.hpp @@ -24,7 +24,11 @@ public: void render(); void run(); void exit(); - Game(); +#ifdef EMULATION + Game(size_t gpuCommandBufSize = 0); +#else + Game(size_t gpuCommandBufSize = C3D_DEFAULT_CMDBUF_SIZE); +#endif virtual ~Game(); protected: Window windowTop, windowBottom; diff --git a/src/cpp3ds/Graphics/CitroHelpers.cpp b/src/cpp3ds/Graphics/CitroHelpers.cpp index e6eb744..fca9084 100644 --- a/src/cpp3ds/Graphics/CitroHelpers.cpp +++ b/src/cpp3ds/Graphics/CitroHelpers.cpp @@ -5,9 +5,9 @@ namespace C3D_MtxStack projectionMatrix, modelviewMatrix, textureMatrix; } -void CitroInit() +void CitroInit(size_t commandBufferSize) { - C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + C3D_Init(commandBufferSize); // Configure attributes for use with the vertex shader C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); diff --git a/src/cpp3ds/Graphics/CitroHelpers.hpp b/src/cpp3ds/Graphics/CitroHelpers.hpp index 79d6936..b2278b9 100644 --- a/src/cpp3ds/Graphics/CitroHelpers.hpp +++ b/src/cpp3ds/Graphics/CitroHelpers.hpp @@ -1,7 +1,7 @@ #pragma once #include -void CitroInit(); +void CitroInit(size_t commandBufferSize); void CitroDestroy(); void CitroBindUniforms(shaderProgram_s* program); void CitroUpdateMatrixStacks(); diff --git a/src/cpp3ds/Graphics/Texture.cpp b/src/cpp3ds/Graphics/Texture.cpp index 3438a1b..6265daa 100644 --- a/src/cpp3ds/Graphics/Texture.cpp +++ b/src/cpp3ds/Graphics/Texture.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "CitroHelpers.hpp" // Note: vertical flip flag set so 0,0 is top left of texture @@ -124,6 +126,7 @@ m_texture (nullptr), m_isSmooth (false), m_isRepeated (false), m_pixelsFlipped(false), +m_ownsData (true), m_cacheId (getUniqueId()) { @@ -138,6 +141,7 @@ m_texture (nullptr), m_isSmooth (copy.m_isSmooth), m_isRepeated (copy.m_isRepeated), m_pixelsFlipped(false), +m_ownsData (true), m_cacheId (getUniqueId()) { if (copy.m_texture) @@ -148,12 +152,11 @@ m_cacheId (getUniqueId()) //////////////////////////////////////////////////////////// Texture::~Texture() { - // Destroy the OpenGL texture - if (m_texture) - { + if (m_ownsData) C3D_TexDelete(m_texture); + + if (m_texture) delete m_texture; - } } @@ -295,6 +298,74 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area) } +//////////////////////////////////////////////////////////// +bool Texture::loadFromPreprocessedFile(const std::string& filename, size_t width, size_t height, GPU_TEXCOLOR format) +{ + if (filename.empty()) + return false; + + FileInputStream file; + file.open(filename); + + size_t size = file.getSize(); + void *data = malloc(size); + file.read(data, size); + + bool ret = loadFromPreprocessedMemory(data, size, width, height, format, true); + free(data); + return ret; +} + + +//////////////////////////////////////////////////////////// +bool Texture::loadFromPreprocessedMemory(void *data, size_t size, size_t width, size_t height, GPU_TEXCOLOR format, bool copyData) +{ + if (!data) + return false; + + m_ownsData = copyData; + m_size.x = width; + m_size.y = height; + m_actualSize = m_size; + m_pixelsFlipped = false; + + ensureGlContext(); + + // Create the citro3d texture, or delete if already created + if (!m_texture) + m_texture = new C3D_Tex(); + else + C3D_TexDelete(m_texture); + + if (!m_texture) + return false; + + if (copyData) + { + C3D_TexInit(m_texture, width, height, format); + C3D_TexUpload(m_texture, data); + } + else + m_texture->data = data; + + m_texture->size = size; + m_texture->fmt = format; + m_texture->height = height; + m_texture->width = width; + + C3D_TexSetWrap(m_texture, + m_isRepeated ? GPU_REPEAT : GPU_CLAMP_TO_EDGE, + m_isRepeated ? GPU_REPEAT : GPU_CLAMP_TO_EDGE); + C3D_TexSetFilter(m_texture, + m_isSmooth ? GPU_LINEAR : GPU_NEAREST, + m_isSmooth ? GPU_LINEAR : GPU_NEAREST); + + m_cacheId = getUniqueId(); + + return true; +} + + //////////////////////////////////////////////////////////// Vector2u Texture::getSize() const { @@ -312,9 +383,19 @@ Image Texture::copyToImage() const // Create an array of pixels std::vector pixels(m_size.x * m_size.y * 4); - u32 *data = (u32*)malloc(m_texture->size); + u32 *data = (u32*)linearAlloc(m_texture->size); - imageUntile32((u8*)data, (u8*)m_texture->data, 0, 0, m_texture->width, m_texture->height, m_texture->width, m_texture->height); + if (m_texture->width < 64 || m_texture->height < 64) + imageUntile32((u8*)data, (u8*)m_texture->data, 0, 0, m_texture->width, m_texture->height, m_texture->width, m_texture->height); + else + { + u32 dim = GX_BUFFER_DIM(m_texture->width, m_texture->height); + GX_DisplayTransfer((u32*)m_texture->data, dim, data, dim, TEXTURE_TRANSFER_FLAGS); + gspWaitForPPF(); + GSPGPU_FlushDataCache(data, m_texture->size); + for (int i = 0; i < m_texture->width * m_texture->height; ++i) + data[i] = __builtin_bswap32(data[i]); + } if ((m_size == m_actualSize) && !m_pixelsFlipped) { @@ -354,7 +435,7 @@ Image Texture::copyToImage() const Image image; image.create(m_size.x, m_size.y, &pixels[0]); - free(data); + linearFree(data); return image; } @@ -376,11 +457,37 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh if (pixels && m_texture) { - u8* dest = (u8*)m_texture->data; + if (m_texture->width < 64 || m_texture->height < 64) + { + u8* dest = (u8*)m_texture->data; - imageTile32(dest, pixels, x, y, width, height, m_texture->width, m_texture->height); + imageTile32(dest, pixels, x, y, width, height, m_texture->width, m_texture->height); - C3D_TexFlush(m_texture); + C3D_TexFlush(m_texture); + } + else + { + const u32 *pixels32 = reinterpret_cast(pixels); + u32 *data = (u32*)linearAlloc(m_texture->size); + u32 dim = GX_BUFFER_DIM(m_texture->width, m_texture->height); + + GX_DisplayTransfer((u32*)m_texture->data, dim, data, dim, TEXTURE_TRANSFER_FLAGS); + gspWaitForPPF(); + + for (int h = 0; h < height; ++h) + { + for (int w = 0; w < width; ++w) + { + data[(y+h)*m_texture->width+x+w] = __builtin_bswap32(pixels32[(h*width) + w]); + } + } + GSPGPU_FlushDataCache(data, m_texture->size); + + GX_DisplayTransfer(data, dim, (u32*)m_texture->data, dim, TEXTURE_TRANSFER_FLAGS | GX_TRANSFER_OUT_TILED(1)); + gspWaitForPPF(); + + linearFree(data); + } m_pixelsFlipped = false; m_cacheId = getUniqueId(); diff --git a/src/cpp3ds/Window/Game.cpp b/src/cpp3ds/Window/Game.cpp index 6c78b93..ee5c438 100644 --- a/src/cpp3ds/Window/Game.cpp +++ b/src/cpp3ds/Window/Game.cpp @@ -8,6 +8,8 @@ namespace cpp3ds { +// System font sheets to be fetched and released by Game +cpp3ds::Texture *system_font_textures = nullptr; //Apt hook cookie static aptHookCookie apt_hook_cookie; @@ -21,12 +23,12 @@ static void apt_clock_hook(APT_HookType hook, void* param) } -Game::Game() +Game::Game(size_t gpuCommandBufSize) : m_triggerExit(false) { if (!Console::isEnabled() && !Console::isEnabledBasic()) gfxInitDefault(); - CitroInit(); + CitroInit(gpuCommandBufSize); osSetSpeedupEnable(true); Service::enable(RomFS); I18n::getInstance(); // Init and load localization file(s) @@ -39,11 +41,27 @@ Game::Game() if (!Shader::Default.loadBinary(defaultShader.data, defaultShader.size, Shader::Vertex)){ err() << "Failed to load default_shader.vsh from cpp3ds core."; } + + // Load system font texture sheets + if (R_SUCCEEDED(fontEnsureMapped())) + { + TGLP_s* glyphInfo = fontGetGlyphInfo(); + system_font_textures = new cpp3ds::Texture[glyphInfo->nSheets]; + for (int i = 0; i < glyphInfo->nSheets; ++i) + { + system_font_textures[i].loadFromPreprocessedMemory( + fontGetGlyphSheetTex(i), glyphInfo->sheetSize, + glyphInfo->sheetWidth, glyphInfo->sheetHeight, + (GPU_TEXCOLOR)glyphInfo->sheetFmt, false); + system_font_textures[i].setSmooth(true); + } + } } Game::~Game() { + delete[] system_font_textures; Service::disable(All); CitroDestroy(); gfxExit(); diff --git a/src/emu3ds/Window/Game.cpp b/src/emu3ds/Window/Game.cpp index d687764..744ab8d 100644 --- a/src/emu3ds/Window/Game.cpp +++ b/src/emu3ds/Window/Game.cpp @@ -9,7 +9,7 @@ namespace cpp3ds { -Game::Game() +Game::Game(size_t gpuCommandBufSize) : m_triggerExit(false) { priv::ensureExtensionsInit();