diff --git a/engine/inc/renderer/core/texture/models/texture.hpp b/engine/inc/renderer/core/texture/models/texture.hpp index ce58589..a74d48b 100644 --- a/engine/inc/renderer/core/texture/models/texture.hpp +++ b/engine/inc/renderer/core/texture/models/texture.hpp @@ -62,7 +62,8 @@ class Texture { /** Set texture wrapping */ void setWrapSettings(const TextureWrap t_horizontal, - const TextureWrap t_vertical); + const TextureWrap t_vertical, int minu = 0, int minv = 0, + int maxu = 0, int maxv = 0); // ---- // Other @@ -96,9 +97,10 @@ class Texture { void print(const std::string& name) const { print(name.c_str()); } std::string getPrint(const char* name = nullptr) const; + void setDefaultWrapSettings(); + private: void setPsm(); - void setDefaultWrapSettings(); texwrap_t wrap; }; diff --git a/engine/inc/renderer/core/texture/renderer_core_texture.hpp b/engine/inc/renderer/core/texture/renderer_core_texture.hpp index 98a05b5..6792959 100644 --- a/engine/inc/renderer/core/texture/renderer_core_texture.hpp +++ b/engine/inc/renderer/core/texture/renderer_core_texture.hpp @@ -29,6 +29,12 @@ class RendererCoreTexture { RendererCoreTextureBuffers useTexture(const Texture* t_tex); + /** + * Called by user after changing texture wrap settings + * Updates texture packet without reallocate it + */ + RendererCoreTextureBuffers updateTextureInfo(const Texture* t_tex); + /** Called by renderer during initialization */ void init(RendererCoreGS* gs, Path3* path3); diff --git a/engine/inc/renderer/core/texture/texture_repository.hpp b/engine/inc/renderer/core/texture/texture_repository.hpp index 519b3cc..e2eaf4d 100644 --- a/engine/inc/renderer/core/texture/texture_repository.hpp +++ b/engine/inc/renderer/core/texture/texture_repository.hpp @@ -16,6 +16,7 @@ #include "./models/texture.hpp" #include "renderer/3d/mesh/mesh.hpp" #include "renderer/core/2d/sprite/sprite.hpp" +#include "./renderer_core_texture_buffers.hpp" #include "loaders/texture/base/texture_loader_selector.hpp" #include @@ -25,6 +26,8 @@ class TextureRepository { TextureRepository(); ~TextureRepository(); + void init(std::vector* textureBuffers); + /** Returns all repository textures. */ std::vector* getAll() { return &textures; } @@ -99,6 +102,13 @@ class TextureRepository { void freeByMesh(const Mesh& mesh); void freeByMesh(const Mesh* mesh); + /** + * remove texture buffer id if exist. + * Texture buffer is NOT destructed. + * easy way to create another texture buffer. + */ + int removeBufferId(const u32& t_texId); + /** * Remove texture from repository. * Texture is NOT destructed. @@ -110,6 +120,7 @@ class TextureRepository { void removeByIndex(const u32& t_index); std::vector textures; + std::vector* textureBuffers; TextureLoaderSelector texLoaderSelector; }; } // namespace Tyra diff --git a/engine/src/loaders/texture/png_loader.cpp b/engine/src/loaders/texture/png_loader.cpp index b1b2e6a..54b61f0 100644 --- a/engine/src/loaders/texture/png_loader.cpp +++ b/engine/src/loaders/texture/png_loader.cpp @@ -211,10 +211,6 @@ void PngLoader::handle8bppPalletized(TextureBuilderData* result, auto* pixel = static_cast(result->data); struct PngClut* clut = (struct PngClut*)result->clut; - for (int i = numPallete; i < 256; i++) { - memset(&clut[i], 0, sizeof(clut[i])); - } - for (int i = 0; i < numPallete; i++) { clut[i].r = palette[i].red; clut[i].g = palette[i].green; @@ -273,10 +269,6 @@ void PngLoader::handle4bppPalletized(TextureBuilderData* result, auto* pixel = static_cast(result->data); struct PngClut* clut = (struct PngClut*)result->clut; - for (int i = numPallete; i < 16; i++) { - memset(&clut[i], 0, sizeof(clut[i])); - } - for (int i = 0; i < numPallete; i++) { clut[i].r = palette[i].red; clut[i].g = palette[i].green; diff --git a/engine/src/renderer/core/paths/path3/path3.cpp b/engine/src/renderer/core/paths/path3/path3.cpp index 42c956a..83431a3 100644 --- a/engine/src/renderer/core/paths/path3/path3.cpp +++ b/engine/src/renderer/core/paths/path3/path3.cpp @@ -65,20 +65,20 @@ void Path3::sendTexture(const Texture* texture, const RendererCoreTextureBuffers& texBuffers) { packet2_reset(texturePacket, false); - int coreWidth = texBuffers.core->width <= 64 ? 64 : texBuffers.core->width; - packet2_update(texturePacket, - draw_texture_transfer(texturePacket->base, texture->core->data, - texture->getWidth(), - texture->getHeight(), texture->core->psm, - texBuffers.core->address, coreWidth)); + packet2_update( + texturePacket, + draw_texture_transfer(texturePacket->base, texture->core->data, + texture->getWidth(), texture->getHeight(), + texture->core->psm, texBuffers.core->address, + texBuffers.core->width)); if (texBuffers.clut != nullptr) { auto* clut = texture->clut; - int clutWidth = texBuffers.clut->width <= 64 ? 64 : texBuffers.clut->width; - packet2_update(texturePacket, - draw_texture_transfer(texturePacket->next, clut->data, - clut->width, clut->height, clut->psm, - texBuffers.clut->address, clutWidth)); + packet2_update( + texturePacket, + draw_texture_transfer(texturePacket->next, clut->data, clut->width, + clut->height, clut->psm, texBuffers.clut->address, + texBuffers.clut->width)); } packet2_chain_open_cnt(texturePacket, 0, 0, 0); diff --git a/engine/src/renderer/core/texture/models/texture.cpp b/engine/src/renderer/core/texture/models/texture.cpp index a0cb309..0941ce5 100644 --- a/engine/src/renderer/core/texture/models/texture.cpp +++ b/engine/src/renderer/core/texture/models/texture.cpp @@ -19,8 +19,18 @@ namespace Tyra { +namespace TyraTexture { +u32 textureCounter = 1; +std::vector deletedIDs; +} // namespace TyraTexture + Texture::Texture(TextureBuilderData* t_data) { - id = rand() % 1000000; + if (TyraTexture::deletedIDs.empty() == false) { + id = TyraTexture::deletedIDs.front(); + TyraTexture::deletedIDs.erase(TyraTexture::deletedIDs.begin()); + } else { + id = TyraTexture::textureCounter++; + } name = t_data->name; @@ -50,6 +60,7 @@ Texture::Texture(TextureBuilderData* t_data) { } Texture::~Texture() { + TyraTexture::deletedIDs.push_back(id); if (links.size() > 0) links.clear(); if (core) delete core; if (clut) delete clut; @@ -167,9 +178,14 @@ void Texture::setDefaultWrapSettings() { } void Texture::setWrapSettings(const TextureWrap t_horizontal, - const TextureWrap t_vertical) { + const TextureWrap t_vertical, int minu, int minv, + int maxu, int maxv) { wrap.horizontal = t_horizontal; wrap.vertical = t_vertical; + wrap.minu = minu; + wrap.minv = minv; + wrap.maxu = maxu; + wrap.maxv = maxv; } void Texture::addLink(const u32& t_id) { diff --git a/engine/src/renderer/core/texture/renderer_core_texture.cpp b/engine/src/renderer/core/texture/renderer_core_texture.cpp index 999effc..2918e09 100644 --- a/engine/src/renderer/core/texture/renderer_core_texture.cpp +++ b/engine/src/renderer/core/texture/renderer_core_texture.cpp @@ -19,6 +19,7 @@ RendererCoreTexture::~RendererCoreTexture() {} void RendererCoreTexture::init(RendererCoreGS* t_gs, Path3* t_path3) { gs = t_gs; sender.init(t_path3, t_gs); + repository.init(¤tAllocations); path3 = t_path3; initClut(); } @@ -56,6 +57,17 @@ RendererCoreTextureBuffers RendererCoreTexture::useTexture( return newTexBuffer; } +RendererCoreTextureBuffers RendererCoreTexture::updateTextureInfo( + const Texture* t_tex) { + TYRA_ASSERT(t_tex != nullptr, "Provided nullptr texture!"); + + auto allocated = getAllocatedBuffersByTextureId(t_tex->id); + TYRA_ASSERT(allocated.id != 0, "Can't update an unallocated texture!"); + + path3->sendTexture(t_tex, allocated); + return allocated; +} + RendererCoreTextureBuffers RendererCoreTexture::getAllocatedBuffersByTextureId( const u32& t_id) { for (u32 i = 0; i < currentAllocations.size(); i++) diff --git a/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp b/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp index 56c90e5..8e94476 100644 --- a/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp +++ b/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp @@ -58,7 +58,9 @@ texbuffer_t* RendererCoreTextureSender::allocateTextureCore( auto* result = new texbuffer_t; const auto* core = t_texture->core; - result->width = t_texture->getWidth(); + int coreWidth = core->width <= 64 ? 64 : core->width; + + result->width = coreWidth; result->psm = core->psm; result->info.components = core->components; @@ -77,7 +79,9 @@ texbuffer_t* RendererCoreTextureSender::allocateTextureClut( auto* result = new texbuffer_t; const auto* clut = t_texture->clut; - result->width = clut->width; + int clutWidth = clut->width <= 64 ? 64 : clut->width; + + result->width = clutWidth; result->psm = clut->psm; result->info.components = clut->components; diff --git a/engine/src/renderer/core/texture/texture_repository.cpp b/engine/src/renderer/core/texture/texture_repository.cpp index 726504d..3ad2645 100644 --- a/engine/src/renderer/core/texture/texture_repository.cpp +++ b/engine/src/renderer/core/texture/texture_repository.cpp @@ -22,6 +22,11 @@ TextureRepository::~TextureRepository() { } } +void TextureRepository::init( + std::vector* t_textureBuffers) { + textureBuffers = t_textureBuffers; +} + Texture* TextureRepository::getBySpriteId(const u32& t_id) const { for (u32 i = 0; i < textures.size(); i++) { if (textures[i]->isLinkedWith(t_id)) return textures[i]; @@ -57,10 +62,20 @@ void TextureRepository::removeByIndex(const u32& t_index) { textures.erase(textures.begin() + t_index); } +int TextureRepository::removeBufferId(const u32& t_texId) { + for (u32 i = 0; i < textureBuffers->size(); i++) + if ((*textureBuffers)[i].id == t_texId) { + (*textureBuffers)[i].id = -1; + return 0; + } + return -1; +} + void TextureRepository::removeById(const u32& t_texId) { s32 index = getIndexOf(t_texId); TYRA_ASSERT(index != -1, "Cant remove texture, because it was not found!"); removeByIndex(index); + removeBufferId(t_texId); } void TextureRepository::freeByMesh(const Mesh& mesh) { @@ -93,6 +108,7 @@ void TextureRepository::free(const u32& t_texId) { TYRA_ASSERT(index != -1, "Cant remove texture, because it was not found!"); removeByIndex(index); + removeBufferId(t_texId); delete tex; } @@ -116,7 +132,7 @@ void TextureRepository::addByMesh(const Mesh* mesh, const char* directory, if (dirFixed.back() != '/' && dirFixed.back() != ':') dirFixed += "/"; for (u32 i = 0; i < mesh->materials.size(); i++) { - if (!mesh->materials[i]->textureName.has_value()) { + if (!mesh->materials[i]->textureName.has_value()) { continue; } diff --git a/tutorials/11-texture-region-repeat/Makefile b/tutorials/11-texture-region-repeat/Makefile new file mode 100644 index 0000000..081fcc6 --- /dev/null +++ b/tutorials/11-texture-region-repeat/Makefile @@ -0,0 +1,24 @@ +TARGET := tutorial_11.elf +ENGINEDIR := ../../engine + +#The Directories, Source, Includes, Objects, Binary and Resources +SRCDIR := src +INCDIR := inc +BUILDDIR := obj +TARGETDIR := bin +RESDIR := res +SRCEXT := cpp +VSMEXT := vsm +VCLEXT := vcl +VCLPPEXT := vclpp +DEPEXT := d +OBJEXT := o + +#Flags, Libraries and Includes +CFLAGS := +LIB := +LIBDIRS := +INC := -I$(INCDIR) +INCDEP := -I$(INCDIR) + +include ../Makefile.tutorials-base \ No newline at end of file diff --git a/tutorials/11-texture-region-repeat/bin/.gitignore b/tutorials/11-texture-region-repeat/bin/.gitignore new file mode 100644 index 0000000..44c5ea8 --- /dev/null +++ b/tutorials/11-texture-region-repeat/bin/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/tutorials/11-texture-region-repeat/inc/tutorial_11.hpp b/tutorials/11-texture-region-repeat/inc/tutorial_11.hpp new file mode 100644 index 0000000..0e8879d --- /dev/null +++ b/tutorials/11-texture-region-repeat/inc/tutorial_11.hpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2024, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +class Tutorial11 : public Game { + public: + explicit Tutorial11(Engine* engine); + ~Tutorial11(); + + void init(); + void loop(); + + private: + void setDrawData(); + void loadBags(); + + void setTextureRegionRepeat(); + void setTextureDefaultWrap(); + + const u8 MAX_TILES = 4; + u8 TILE_COL = 0; + u8 TILE_ROW = 0; + + u8 shouldFlipTextureSettings = false; + float limitTimeToFlip = 2.00f; + float elapsedTime = 0; + + Engine* engine; + + Vec4 cameraPosition, cameraLookAt; + M4x4 translation, rotation, scale, model; + Texture* UVCheckerTex; + + std::array vertices; + std::array colors; + std::array uvMap; + + StaticPipeline stapip; + std::unique_ptr bag; + std::unique_ptr infoBag; + std::unique_ptr colorBag; + std::unique_ptr texBag; +}; + +} // namespace Tyra diff --git a/tutorials/11-texture-region-repeat/obj/.gitignore b/tutorials/11-texture-region-repeat/obj/.gitignore new file mode 100644 index 0000000..44c5ea8 --- /dev/null +++ b/tutorials/11-texture-region-repeat/obj/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/tutorials/11-texture-region-repeat/res/.gitignore b/tutorials/11-texture-region-repeat/res/.gitignore new file mode 100644 index 0000000..44c5ea8 --- /dev/null +++ b/tutorials/11-texture-region-repeat/res/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/tutorials/11-texture-region-repeat/run.ps1 b/tutorials/11-texture-region-repeat/run.ps1 new file mode 100644 index 0000000..74646cc --- /dev/null +++ b/tutorials/11-texture-region-repeat/run.ps1 @@ -0,0 +1,4 @@ +$ConfigFile = Join-Path $PSScriptRoot '../../windows-pcsx2.ps1' +. $ConfigFile + +RunPCSX2 diff --git a/tutorials/11-texture-region-repeat/src/main.cpp b/tutorials/11-texture-region-repeat/src/main.cpp new file mode 100644 index 0000000..4518901 --- /dev/null +++ b/tutorials/11-texture-region-repeat/src/main.cpp @@ -0,0 +1,24 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2024, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include "engine.hpp" +#include "tutorial_11.hpp" + +/** + * In this tutorial we will learn: + * - How to use texture in repeate mode of GS + */ + +int main() { + Tyra::Engine engine; + Tyra::Tutorial11 game(&engine); + engine.run(&game); + return 0; +} diff --git a/tutorials/11-texture-region-repeat/src/tutorial_11.cpp b/tutorials/11-texture-region-repeat/src/tutorial_11.cpp new file mode 100644 index 0000000..03508a7 --- /dev/null +++ b/tutorials/11-texture-region-repeat/src/tutorial_11.cpp @@ -0,0 +1,178 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2024, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include +#include "tutorial_11.hpp" + +namespace Tyra { + +Tutorial11::Tutorial11(Engine* t_engine) : engine(t_engine) { + translation = M4x4::Identity; + rotation = M4x4::Identity; + scale = M4x4::Identity; + model = M4x4::Identity; + + rotation.rotateY(Math::PI); +} + +Tutorial11::~Tutorial11() {} + +void Tutorial11::init() { + stapip.setRenderer(&engine->renderer.core); + + cameraPosition = Vec4(0.0F, 0.0F, -10.0F); + cameraLookAt.unit(); + + UVCheckerTex = engine->renderer.getTextureRepository().add( + FileUtils::fromCwd("uv_checker.png")); + + setDrawData(); + loadBags(); +} + +void Tutorial11::loop() { + const auto deltaTime = + std::min(1.0f / static_cast(engine->info.getFps()), + static_cast(1.0 / 60.0f)); + elapsedTime += deltaTime; + + if (elapsedTime > limitTimeToFlip) { + elapsedTime -= limitTimeToFlip; + shouldFlipTextureSettings = !shouldFlipTextureSettings; + shouldFlipTextureSettings ? setTextureRegionRepeat() + : setTextureDefaultWrap(); + + // Update texture packet info after change wrap settings + engine->renderer.core.texture.updateTextureInfo(UVCheckerTex); + } + + model = translation * rotation * scale; + + engine->renderer.beginFrame(CameraInfo3D(&cameraPosition, &cameraLookAt)); + { + engine->renderer.renderer3D.usePipeline(stapip); + + /** + * Lets draw manually via "bags". + * You can do the same thing with dynamic pipeline. + */ + stapip.core.render(bag.get()); + } + engine->renderer.endFrame(); +} + +void Tutorial11::setDrawData() { + vertices = { + // Tri 1 + Vec4(-3.0F, -3.0F, 0.0F), + Vec4(3.0F, -3.0F, 0.0F), + Vec4(-3.0F, 3.0F, 0.0F), + + // Tri 2 + Vec4(3.0F, -3.0F, 0.0F), + Vec4(-3.0F, 3.0F, 0.0F), + Vec4(3.0F, 3.0F, 0.0F), + }; + + colors = { + Color(128.0F, 128.0F, 128.0F), Color(128.0F, 128.0F, 128.0F), + Color(128.0F, 128.0F, 128.0F), Color(128.0F, 128.0F, 128.0F), + Color(128.0F, 128.0F, 128.0F), Color(128.0F, 128.0F, 128.0F), + }; + + setTextureDefaultWrap(); +} + +void Tutorial11::setTextureDefaultWrap() { + uvMap = {Vec4(0.0f, 1.0F, 1.0F, 0.0f), Vec4(0.0f + 1, 1.0F, 1.0F, 0.0f), + Vec4(0.0f, 0.0f, 1.0F, 0.0f), + + Vec4(0.0f + 1, 1.0F, 1.0F, 0.0f), Vec4(0.0f, 0.0f, 1.0F, 0.0f), + Vec4(0.0f + 1.0F, 0.0f, 1.0F, 0.0f)}; + + TYRA_LOG("Reseting texture wrap settings"); + UVCheckerTex->setDefaultWrapSettings(); +} + +void Tutorial11::setTextureRegionRepeat() { + const float _scale = 1.0f / (float)MAX_TILES; + const Vec4 scale = + Vec4(MAX_TILES > 0 ? _scale * MAX_TILES : _scale, + MAX_TILES > 0 ? _scale * MAX_TILES : _scale, 1.0f, 0.0f); + + uvMap = { + Vec4(TILE_COL, TILE_ROW + 1.0F, 1.0F, 0.0f) * scale, + Vec4(TILE_COL + 1, TILE_ROW + 1.0F, 1.0F, 0.0f) * scale, + Vec4(TILE_COL, TILE_ROW, 1.0F, 0.0f) * scale, + + Vec4(TILE_COL + 1, TILE_ROW + 1.0F, 1.0F, 0.0f) * scale, + Vec4(TILE_COL, TILE_ROW, 1.0F, 0.0f) * scale, + Vec4(TILE_COL + 1.0F, TILE_ROW, 1.0F, 0.0f) * scale, + }; + + const auto tileW = (UVCheckerTex->getWidth() * _scale) - 1; + const auto tileH = (UVCheckerTex->getHeight() * _scale) - 1; + const auto tileU = TILE_COL * tileW + TILE_COL; + const auto tileV = TILE_ROW * tileH + TILE_ROW; + + int minu = tileW; + int minv = tileH; + int maxu = tileU; + int maxv = tileV; + + TYRA_LOG("Changing the texture wraping..."); + UVCheckerTex->setWrapSettings(TextureWrap::RegionRepeat, + TextureWrap::RegionRepeat, minu, minv, maxu, + maxv); + + TILE_COL++; + if (TILE_COL >= MAX_TILES) { + TILE_COL %= MAX_TILES; + TILE_ROW = (TILE_ROW + 1) % MAX_TILES; + } +} + +void Tutorial11::loadBags() { + /** + * Create info bag and fill it with model matrix and shading type. + * Keep rest of the options as default. + */ + infoBag = std::make_unique(); + infoBag->model = &model; + infoBag->shadingType = TyraShadingGouraud; + infoBag->textureMappingType = TyraNearest; + + /** Create colors bag and set data pointer */ + colorBag = std::make_unique(); + colorBag->many = colors.begin(); + + texBag = std::make_unique(); + texBag.get()->texture = UVCheckerTex; + texBag.get()->coordinates = uvMap.data(); + + /** + * Create main bag and set: + * - vertices data + * - vertices count + * - pointers to other bags + * + * You can add here lighting and texture bag as well. + * If you want to have deeper look of this feature, please + * read static_pipeline.cpp code file. + */ + bag = std::make_unique(); + bag->color = colorBag.get(); + bag->texture = texBag.get(); + bag->info = infoBag.get(); + bag->vertices = vertices.begin(); + bag->count = vertices.size(); +} + +} // namespace Tyra