diff --git a/ROADMAP.txt b/ROADMAP.txt index 5bda416..16fb3a6 100644 --- a/ROADMAP.txt +++ b/ROADMAP.txt @@ -1,7 +1,5 @@ ------------ Tyra's v2.0 roadmap to publish on GitHub ------------ -- [Tutorials] 4. Mesh rendering - explain staticPipeline, render .obj file via Mesh class, explain that this is high-level -abstract 3D object class, and what it have (animation etc) - [Tutorials] 5. Manual rendering via staticPipeline - via Render3DBag (core.render()), render simple poly, explain that this is lower-level abstract rendering, it have the all the features as Mesh rendering, @@ -13,7 +11,9 @@ because Mesh rendering uses only core.render() - [Tutorials] 8. Render skybox, and show that stdPipOptions.noClipChecks must be set to false, to turn on clip algorithms (prevent glitches) +- audio - own game +- how to cook audio,textures,obj - usb - [General] Check all left TODOs -> Github issues @@ -25,14 +25,12 @@ because Mesh rendering uses only core.render() - [General] smart pointers and std::array instead of raw pointers - [renderer] fog - [General] CI in Github via docker image -- [renderer] bbox parts optimization - [md2] refactor - [2D] Add zbuffer support (z-index) - [3DUtility] Add zbuffer support (z-index) - [2D] Fixed font support - [File] Async file loading - [obj] Add multicolor support to obj -- [Obj] Improve obj importing for multiple usemtl with same names - [tyrdat] Custom 3D data file with precalculated bboxes with support of async loading - [Renderer] Interlacing, a potem resolution 640x448 - [General] Add cpp lint checker in GitHub diff --git a/engine/inc/loaders/3d/md2_loader/md2_loader.hpp b/engine/inc/loaders/3d/md2_loader/md2_loader.hpp index 918be52..da6d9a4 100644 --- a/engine/inc/loaders/3d/md2_loader/md2_loader.hpp +++ b/engine/inc/loaders/3d/md2_loader/md2_loader.hpp @@ -13,6 +13,7 @@ #include "../../loader.hpp" #include "../builder/mesh_builder_data.hpp" #include +#include namespace Tyra { @@ -24,13 +25,12 @@ struct MD2LoaderOptions { /** Class responsible for loading & parsing Quake's II ".md2" 3D files */ class MD2Loader : public Loader { public: - MD2Loader(); - ~MD2Loader(); - - MeshBuilderData* load(const char* fullpath); - MeshBuilderData* load(const char* fullpath, MD2LoaderOptions options); - MeshBuilderData* load(const std::string& fullpath); - MeshBuilderData* load(const std::string& fullpath, MD2LoaderOptions options); + static std::unique_ptr load(const char* fullpath); + static std::unique_ptr load(const char* fullpath, + MD2LoaderOptions options); + static std::unique_ptr load(const std::string& fullpath); + static std::unique_ptr load(const std::string& fullpath, + MD2LoaderOptions options); }; } // namespace Tyra diff --git a/engine/inc/loaders/3d/obj_loader/obj_loader.hpp b/engine/inc/loaders/3d/obj_loader/obj_loader.hpp index febef5d..6282f91 100644 --- a/engine/inc/loaders/3d/obj_loader/obj_loader.hpp +++ b/engine/inc/loaders/3d/obj_loader/obj_loader.hpp @@ -38,32 +38,30 @@ struct MaterialVertexCount { /** Class responsible for loading & parsing obj files */ class ObjLoader : public Loader { public: - ObjLoader(); - ~ObjLoader(); - - std::unique_ptr load(const char* fullpath); - std::unique_ptr load(const char* fullpath, - const ObjLoaderOptions& options); - std::unique_ptr load(const std::string& fullpath); - std::unique_ptr load(const std::string& fullpath, - const ObjLoaderOptions& options); + static std::unique_ptr load(const char* fullpath); + static std::unique_ptr load(const char* fullpath, + const ObjLoaderOptions& options); + static std::unique_ptr load(const std::string& fullpath); + static std::unique_ptr load(const std::string& fullpath, + const ObjLoaderOptions& options); private: - void addOutputMaterialsAndFrames( + static void addOutputMaterialsAndFrames( MeshBuilderData* output, const tinyobj::attrib_t& attrib, const std::vector& shapes, const std::vector& materials, const u16& framesCount, std::vector& materialVertexCounts); - std::vector scan( + static std::vector scan( const std::vector& shapes, const std::vector& materials); - void importFrame(MeshBuilderData* output, const tinyobj::attrib_t& attrib, - const std::vector& shapes, - const std::vector& materials, - const u16& frameIndex, const float& scale, - const bool& invertY, const u16& count); + static void importFrame(MeshBuilderData* output, + const tinyobj::attrib_t& attrib, + const std::vector& shapes, + const std::vector& materials, + const u16& frameIndex, const float& scale, + const bool& invertY, const u16& count); }; } // namespace Tyra diff --git a/engine/inc/loaders/loader.hpp b/engine/inc/loaders/loader.hpp index e0658cb..5aac03b 100644 --- a/engine/inc/loaders/loader.hpp +++ b/engine/inc/loaders/loader.hpp @@ -16,10 +16,10 @@ namespace Tyra { class Loader { protected: - std::string getFilenameFromPath(const std::string& path); - std::string getPathFromFilename(const std::string& path); - std::string getFilenameWithoutExtension(const std::string& filename); - std::string getExtensionOfFilename(const std::string& filename); + static std::string getFilenameFromPath(const std::string& path); + static std::string getPathFromFilename(const std::string& path); + static std::string getFilenameWithoutExtension(const std::string& filename); + static std::string getExtensionOfFilename(const std::string& filename); }; } // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp b/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp index 3d936c8..725f9df 100644 --- a/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp +++ b/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp @@ -39,13 +39,16 @@ class DynamicPipeline : public Renderer3DPipeline { void onUse(); + void onFrameEnd(); + void onUseEnd(); /** * Render dynamic model. * This render() method is a bridge to core.render() method. */ - void render(const DynamicMesh& mesh, const DynPipOptions* options = nullptr); + void render(const DynamicMesh* mesh); + void render(const DynamicMesh* mesh, const DynPipOptions& options); void render(const DynamicMesh* mesh, const DynPipOptions* options = nullptr); private: diff --git a/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp b/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp index 7aaa14d..a89a312 100644 --- a/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp +++ b/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp @@ -33,6 +33,7 @@ class MinecraftPipeline : public Renderer3DPipeline { void onUse(); void onUseEnd(); + void onFrameEnd(); /** * @brief Render voxels diff --git a/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp b/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp index c5abeea..ef6f26a 100644 --- a/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp +++ b/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp @@ -21,6 +21,7 @@ class Renderer3DPipeline { virtual void setRenderer(RendererCore* core) = 0; virtual void onUse() = 0; + virtual void onFrameEnd() = 0; virtual void onUseEnd() = 0; std::function onDestroy; }; diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp index 21e961b..0ebfc3e 100644 --- a/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp @@ -28,7 +28,8 @@ class StaPipCore { void init(RendererCore* t_core); /** Render 3D via "bags" */ - void render(StaPipBag* bag, StaPipBagPackagesBBox* bbox = nullptr); + void render(StaPipBag* bag, StaPipBagPackagesBBox* bbox, + const u32& maxVertCount); /** Get max vert count of VU1 qbuffer (for optimizations) */ u32 getMaxVertCountByParams(const bool& isSingleColor, diff --git a/engine/inc/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.hpp b/engine/inc/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.hpp new file mode 100644 index 0000000..774bfa5 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.hpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "core/bag/packaging/stapip_bag_packages_bbox.hpp" +#include "renderer/3d/mesh/mesh.hpp" +#include +#include + +namespace Tyra { + +struct StapipBagBBoxesCacheItem { + u32 vu1MaxVertCount; + u32 frameId; + std::unique_ptr bboxes; + int framesLeftToDestroy; +}; + +class StapipBagBBoxesCacher { + public: + StapipBagBBoxesCacher(); + ~StapipBagBBoxesCacher(); + + const int cacheFramesCount = 50; + const int cacheSecondsCount = 5; + + void onFrameEnd(); + + StaPipBagPackagesBBox* getBBoxesByMesh(const MeshMaterialFrame* frame, + const u32& maxVertCount); + + private: + StapipBagBBoxesCacheItem* getCache(const u32& maxVertCount, + const u32& frameId); + + std::vector storage; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp b/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp index 9ee9a80..fdcd96a 100644 --- a/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp +++ b/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp @@ -17,6 +17,7 @@ #include "renderer/3d/mesh/static/static_mesh.hpp" #include "./core/stapip_core.hpp" #include "./stapip_options.hpp" +#include "./stapip_bag_bboxes_cacher.hpp" namespace Tyra { @@ -38,17 +39,19 @@ class StaticPipeline : public Renderer3DPipeline { void setRenderer(RendererCore* core); void onUse(); - void onUseEnd(); + void onFrameEnd(); /** * Render static model * This render() method is a bridge to core.render() method. */ - void render(const StaticMesh& mesh, const StaPipOptions* options = nullptr); + void render(const StaticMesh* mesh); + void render(const StaticMesh* mesh, const StaPipOptions& options); void render(const StaticMesh* mesh, const StaPipOptions* options = nullptr); private: + StapipBagBBoxesCacher cacher; RendererCore* rendererCore; Vec4* colorsCache; @@ -65,6 +68,7 @@ class StaticPipeline : public Renderer3DPipeline { const MeshMaterialFrame* materialFrame); StaPipLightingBag* getLightingBag(const MeshMaterialFrame* materialFrame, + PipelineDirLightsBag* dirLightsBag, M4x4* model, const StaPipOptions* options) const; diff --git a/engine/inc/renderer/3d/renderer_3d.hpp b/engine/inc/renderer/3d/renderer_3d.hpp index dd5d92f..7825f8c 100644 --- a/engine/inc/renderer/3d/renderer_3d.hpp +++ b/engine/inc/renderer/3d/renderer_3d.hpp @@ -23,12 +23,16 @@ class Renderer3D { Renderer3DUtility utility; - void init(RendererCore* core); - /** Deinitialize previous pipeline and initialize new pipeline */ void usePipeline(Renderer3DPipeline* pipeline); void usePipeline(Renderer3DPipeline& pipeline); + /** Called by engine */ + void init(RendererCore* core); + + /** Called by engine */ + void onFrameEnd(); + private: Renderer3DPipeline* currentPipeline; void onDestroy(Renderer3DPipeline* pipeline); diff --git a/engine/inc/renderer/renderer_settings.hpp b/engine/inc/renderer/renderer_settings.hpp index cec7937..6da8777 100644 --- a/engine/inc/renderer/renderer_settings.hpp +++ b/engine/inc/renderer/renderer_settings.hpp @@ -22,8 +22,8 @@ class RendererSettings { height(448.0F), interlacedHeightF(height / 2), near(0.1F), - far(4096.0F), - projectionScale(4096.0F), + far(8192.0F), + projectionScale(8192.0F), aspectRatio(width / height), interlacedHeightUI(static_cast(interlacedHeightF)) {} ~RendererSettings(); diff --git a/engine/src/loaders/3d/md2_loader/md2_loader.cpp b/engine/src/loaders/3d/md2_loader/md2_loader.cpp index 0a96936..7309379 100644 --- a/engine/src/loaders/3d/md2_loader/md2_loader.cpp +++ b/engine/src/loaders/3d/md2_loader/md2_loader.cpp @@ -70,25 +70,21 @@ typedef struct { s16 t; } texCoord_t; -MD2Loader::MD2Loader() {} - -MD2Loader::~MD2Loader() {} - -MeshBuilderData* MD2Loader::load(const char* fullpath) { +std::unique_ptr MD2Loader::load(const char* fullpath) { return load(fullpath, MD2LoaderOptions()); } -MeshBuilderData* MD2Loader::load(const std::string& fullpath) { +std::unique_ptr MD2Loader::load(const std::string& fullpath) { return load(fullpath.c_str(), MD2LoaderOptions()); } -MeshBuilderData* MD2Loader::load(const std::string& fullpath, - MD2LoaderOptions options) { +std::unique_ptr MD2Loader::load(const std::string& fullpath, + MD2LoaderOptions options) { return load(fullpath.c_str(), options); } -MeshBuilderData* MD2Loader::load(const char* fullpath, - MD2LoaderOptions options) { +std::unique_ptr MD2Loader::load(const char* fullpath, + MD2LoaderOptions options) { std::string path = fullpath; TYRA_ASSERT(!path.empty(), "Provided path is empty!"); @@ -123,7 +119,7 @@ MeshBuilderData* MD2Loader::load(const char* fullpath, fclose(file); - auto result = new MeshBuilderData(); + auto result = std::make_unique(); auto* material = new MeshBuilderMaterialData(); material->name = getFilenameWithoutExtension(filename); diff --git a/engine/src/loaders/3d/obj_loader/obj_loader.cpp b/engine/src/loaders/3d/obj_loader/obj_loader.cpp index f7f2346..dd7e890 100644 --- a/engine/src/loaders/3d/obj_loader/obj_loader.cpp +++ b/engine/src/loaders/3d/obj_loader/obj_loader.cpp @@ -24,10 +24,6 @@ namespace Tyra { -ObjLoader::ObjLoader() {} - -ObjLoader::~ObjLoader() {} - std::unique_ptr ObjLoader::load(const char* fullpath) { return load(fullpath, ObjLoaderOptions()); } diff --git a/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp b/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp index bcc5164..2315dc8 100644 --- a/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp +++ b/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp @@ -51,9 +51,13 @@ void DynamicPipeline::onUseEnd() { core.deallocateOnUse(); } -void DynamicPipeline::render(const DynamicMesh& mesh, - const DynPipOptions* options) { - render(&mesh, options); +void DynamicPipeline::onFrameEnd() {} + +void DynamicPipeline::render(const DynamicMesh* mesh) { render(mesh, nullptr); } + +void DynamicPipeline::render(const DynamicMesh* mesh, + const DynPipOptions& options) { + render(mesh, &options); } void DynamicPipeline::render(const DynamicMesh* mesh, diff --git a/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp b/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp index 557d3c0..a4cdd80 100644 --- a/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp +++ b/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp @@ -78,6 +78,8 @@ void MinecraftPipeline::onUseEnd() { manager.deallocateOnUse(); } +void MinecraftPipeline::onFrameEnd() {} + void MinecraftPipeline::initBBox() { const auto& block = manager.getBlockData(); bbox = new RenderBBox(block.vertices, block.count); diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp index 753160e..9073087 100644 --- a/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp @@ -72,7 +72,8 @@ u32 StaPipCore::getMaxVertCountByParams(const bool& isSingleColor, ->getMaxVertCount(isSingleColor, qbufferRenderer.getBufferSize()); } -void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox) { +void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox, + const u32& maxVertCount) { if (bag->count <= 0) return; bool frustumCull = @@ -105,32 +106,20 @@ void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox) { TYRA_ASSERT(!(!frustumCull && bag->info->fullClipChecks == true), "Full clip checks are not supported with frustum culling = off!"); - u32 maxVertCount = getMaxVertCountByBag(bag); setMaxVertCount(maxVertCount); - StaPipBagPackagesBBox* renderBbox = nullptr; - CoreBBoxFrustum frustumCheck = OUTSIDE_FRUSTUM; if (frustumCull) { - if (!bbox) - renderBbox = - new StaPipBagPackagesBBox(bag->vertices, bag->count, maxVertCount); - else - renderBbox = bbox; - - frustumCheck = renderBbox->getMainBBox()->clipFrustumCheck( + frustumCheck = bbox->getMainBBox()->clipFrustumCheck( rendererCore->renderer3D.frustumPlanes.getAll(), *bag->info->model); if (frustumCheck == OUTSIDE_FRUSTUM) { - if (!bbox) { - delete renderBbox; - } return; } } - packager.setRenderBBox(renderBbox); + packager.setRenderBBox(bbox); M4x4 mvp; @@ -199,10 +188,6 @@ void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox) { } } - if (frustumCull && !bbox) { - delete renderBbox; - } - if (texBuffers) delete texBuffers; qbufferRenderer.flushBuffers(); diff --git a/engine/src/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.cpp b/engine/src/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.cpp new file mode 100644 index 0000000..3ef3703 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.cpp @@ -0,0 +1,64 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.hpp" +#include + +namespace Tyra { + +StapipBagBBoxesCacher::StapipBagBBoxesCacher() {} + +StapipBagBBoxesCacher::~StapipBagBBoxesCacher() {} + +void StapipBagBBoxesCacher::onFrameEnd() { + for (auto& item : storage) { + if (item.framesLeftToDestroy > 0) { + item.framesLeftToDestroy--; + } + } + + storage.erase(std::remove_if(storage.begin(), storage.end(), + [](const StapipBagBBoxesCacheItem& item) { + return item.framesLeftToDestroy <= 0; + }), + storage.end()); +} + +StaPipBagPackagesBBox* StapipBagBBoxesCacher::getBBoxesByMesh( + const MeshMaterialFrame* frame, const u32& maxVertCount) { + auto* cache = getCache(maxVertCount, frame->id); + + if (cache) { + cache->framesLeftToDestroy = cacheFramesCount * cacheSecondsCount; + return cache->bboxes.get(); + } + + auto bboxes = std::make_unique( + frame->vertices, frame->count, maxVertCount); + + storage.push_back( + StapipBagBBoxesCacheItem{maxVertCount, frame->id, std::move(bboxes), + cacheFramesCount * cacheSecondsCount}); + + return storage.back().bboxes.get(); +} + +StapipBagBBoxesCacheItem* StapipBagBBoxesCacher::getCache( + const u32& maxVertCount, const u32& frameId) { + for (auto& item : storage) { + if (item.vu1MaxVertCount == maxVertCount && item.frameId == frameId) { + return &item; + } + } + + return nullptr; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp b/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp index 5a7d24f..f87824c 100644 --- a/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp +++ b/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp @@ -11,7 +11,7 @@ #include "renderer/3d/pipeline/static/static_pipeline.hpp" #include "debug/debug.hpp" #include "renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp" - +#include namespace Tyra { StaticPipeline::StaticPipeline() {} @@ -39,9 +39,13 @@ void StaticPipeline::onUseEnd() { core.deallocateOnUse(); } -void StaticPipeline::render(const StaticMesh& mesh, - const StaPipOptions* options) { - render(&mesh, options); +void StaticPipeline::onFrameEnd() { cacher.onFrameEnd(); } + +void StaticPipeline::render(const StaticMesh* mesh) { render(mesh, nullptr); } + +void StaticPipeline::render(const StaticMesh* mesh, + const StaPipOptions& options) { + render(mesh, &options); } void StaticPipeline::render(const StaticMesh* mesh, @@ -55,6 +59,7 @@ void StaticPipeline::render(const StaticMesh* mesh, auto model = mesh->getModelMatrix(); auto* infoBag = getInfoBag(mesh, options, &model); + auto dirLightsBag = std::make_unique(true); TYRA_ASSERT( !(options->frustumCulling != PipelineFrustumCulling_Precise && @@ -85,11 +90,21 @@ void StaticPipeline::render(const StaticMesh* mesh, bag.info = infoBag; bag.color = getColorBag(material, materialFrame); bag.texture = getTextureBag(material, materialFrame); - bag.lighting = getLightingBag(materialFrame, &model, options); - core.render(&bag); + bag.lighting = + getLightingBag(materialFrame, dirLightsBag.get(), &model, options); + + u32 maxVertCount = core.getMaxVertCountByBag(&bag); + + StaPipBagPackagesBBox* bbox = nullptr; + if (bag.info->frustumCulling == PipelineFrustumCulling_Precise) { + bbox = cacher.getBBoxesByMesh(materialFrame, maxVertCount); + } + + core.render(&bag, bbox, maxVertCount); deallocDrawBags(&bag, material); } + delete infoBag; if (optionsManuallyAllocated) delete options; @@ -156,18 +171,15 @@ StaPipTextureBag* StaticPipeline::getTextureBag( } StaPipLightingBag* StaticPipeline::getLightingBag( - const MeshMaterialFrame* materialFrame, M4x4* model, - const StaPipOptions* options) const { + const MeshMaterialFrame* materialFrame, PipelineDirLightsBag* dirLightsBag, + M4x4* model, const StaPipOptions* options) const { if (!materialFrame->normals || options == nullptr || options->lighting == nullptr) return nullptr; auto* result = new StaPipLightingBag(); - // TODO: Make it once per rendering, very redundant - auto* dirLightsBag = new PipelineDirLightsBag(true); result->dirLights = dirLightsBag; - result->lightMatrix = model; result->dirLights->setLightsManually( @@ -194,7 +206,6 @@ void StaticPipeline::deallocDrawBags(StaPipBag* bag, } if (bag->lighting) { - delete bag->lighting->dirLights; // TODO delete bag->lighting; } diff --git a/engine/src/renderer/3d/renderer_3d.cpp b/engine/src/renderer/3d/renderer_3d.cpp index 8531315..b227acd 100644 --- a/engine/src/renderer/3d/renderer_3d.cpp +++ b/engine/src/renderer/3d/renderer_3d.cpp @@ -19,6 +19,12 @@ Renderer3D::~Renderer3D() {} void Renderer3D::init(RendererCore* core) { utility.init(core); } +void Renderer3D::onFrameEnd() { + if (currentPipeline != nullptr) { + currentPipeline->onFrameEnd(); + } +} + void Renderer3D::usePipeline(Renderer3DPipeline& pipeline) { usePipeline(&pipeline); } diff --git a/engine/src/renderer/renderer.cpp b/engine/src/renderer/renderer.cpp index 8537d6a..3a94ec5 100644 --- a/engine/src/renderer/renderer.cpp +++ b/engine/src/renderer/renderer.cpp @@ -27,6 +27,9 @@ void Renderer::beginFrame(const CameraInfo3D& cameraInfo) { core.beginFrame(cameraInfo); } -void Renderer::endFrame() { core.endFrame(); } +void Renderer::endFrame() { + core.endFrame(); + renderer3D.onFrameEnd(); +} } // namespace Tyra diff --git a/tutorials/03-minecraft/inc/tutorial_03.hpp b/tutorials/03-minecraft/inc/tutorial_03.hpp index ff8f612..25dd628 100644 --- a/tutorials/03-minecraft/inc/tutorial_03.hpp +++ b/tutorials/03-minecraft/inc/tutorial_03.hpp @@ -44,6 +44,8 @@ class Tutorial03 : public Game { * - Minecraft (this one) * - Static (for static 3D objects) * - Dynamic (for dynamic 3D objects) + * + * You can create your own VU1 programs and create your custom pipelines! */ MinecraftPipeline mcpip; diff --git a/tutorials/04-de_dust2/inc/camera.hpp b/tutorials/04-de_dust2/inc/camera.hpp new file mode 100644 index 0000000..2f24ebc --- /dev/null +++ b/tutorials/04-de_dust2/inc/camera.hpp @@ -0,0 +1,44 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +namespace Tyra { + +class Camera { + public: + Camera(Pad* pad); + ~Camera(); + + Vec4 lookAt; + Vec4 position; + + /** + * Result variable of unit circle calculation + * This is needed for rotation about the camera lookAt + * https://www.geogebra.org/m/cNEtsbvC + */ + Vec4 unitCircle; + + CameraInfo3D getCameraInfo() { return CameraInfo3D(&position, &lookAt); } + + void update(); + + private: + void updatePosition(); + void updateLookAt(); + + Pad* pad; + float circleRotation, circleLength, speed, lookAtHeight; +}; + +} // namespace Tyra diff --git a/tutorials/04-de_dust2/inc/tutorial_04.hpp b/tutorials/04-de_dust2/inc/tutorial_04.hpp index 9131a95..c07a86f 100644 --- a/tutorials/04-de_dust2/inc/tutorial_04.hpp +++ b/tutorials/04-de_dust2/inc/tutorial_04.hpp @@ -12,6 +12,7 @@ #include #include +#include "./camera.hpp" namespace Tyra { @@ -28,8 +29,16 @@ class Tutorial04 : public Game { Engine* engine; - std::unique_ptr mesh; + Camera camera; + + /** 3D pipeline used for rendering static meshes */ + StaticPipeline stapip; + + /** Options for static pipeline */ StaPipOptions renderOptions; + + /** Mesh with de_dust2 */ + std::unique_ptr mesh; }; } // namespace Tyra diff --git a/tutorials/04-de_dust2/src/camera.cpp b/tutorials/04-de_dust2/src/camera.cpp new file mode 100644 index 0000000..e8702b7 --- /dev/null +++ b/tutorials/04-de_dust2/src/camera.cpp @@ -0,0 +1,85 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "camera.hpp" + +namespace Tyra { + +Camera::Camera(Pad* t_pad) + : lookAt(0.0F), + position(-2000.0F, 0.0F, -6000.0F), + pad(t_pad), + circleRotation(-5.0F), + circleLength(30.0F), + speed(20.0F), + lookAtHeight(-4.0F) {} + +Camera::~Camera() {} + +void Camera::update() { + updatePosition(); + updateLookAt(); +} + +/** + * Move camera position via left joystick + */ +void Camera::updatePosition() { + const auto& leftJoy = pad->getLeftJoyPad(); + + auto direction = Vec4(unitCircle).getNormalized() * speed; + + if (leftJoy.v <= 100) { + position.x += direction.x; + position.z += direction.z; + } else if (leftJoy.v >= 200) { + position.x += -direction.x; + position.z += -direction.z; + } + + if (leftJoy.h <= 100) { + position.x += direction.z; + position.z += -direction.x; + } else if (leftJoy.h >= 200) { + position.x += -direction.z; + position.z += direction.x; + } + + /** Camera height */ + position.y = 700.0F; +} + +/** + * Move camera lookAt position via right joystick + */ +void Camera::updateLookAt() { + const float rotationOffset = 0.045F; + const float heightOffset = 2.0F; + const auto& rightJoy = pad->getRightJoyPad(); + + if (rightJoy.h <= 100) { + circleRotation -= rotationOffset; + } else if (rightJoy.h >= 200) { + circleRotation += rotationOffset; + } + + if (rightJoy.v <= 100) { + lookAtHeight -= heightOffset; + } else if (rightJoy.v >= 200) { + lookAtHeight += heightOffset; + } + + unitCircle.x = Math::sin(circleRotation) * circleLength; + unitCircle.y = lookAtHeight; + unitCircle.z = Math::cos(circleRotation) * circleLength; + + lookAt = unitCircle + position; +} +} // namespace Tyra diff --git a/tutorials/04-de_dust2/src/tutorial_04.cpp b/tutorials/04-de_dust2/src/tutorial_04.cpp index ec573f7..ab804df 100644 --- a/tutorials/04-de_dust2/src/tutorial_04.cpp +++ b/tutorials/04-de_dust2/src/tutorial_04.cpp @@ -13,25 +13,64 @@ namespace Tyra { -Tutorial04::Tutorial04(Engine* t_engine) : engine(t_engine) {} +Tutorial04::Tutorial04(Engine* t_engine) + : engine(t_engine), camera(&t_engine->pad) {} Tutorial04::~Tutorial04() { engine->renderer.getTextureRepository().freeByMesh(mesh.get()); } -void Tutorial04::init() { loadMesh(); } +void Tutorial04::init() { + stapip.setRenderer(&engine->renderer.core); + loadMesh(); +} -void Tutorial04::loop() {} +void Tutorial04::loop() { + /** Update camera's lookAt and position */ + camera.update(); + + engine->renderer.beginFrame(camera.getCameraInfo()); + { + /** Upload static pipeline's VU1 programs */ + engine->renderer.renderer3D.usePipeline(stapip); + + /** + * Render de_dust2. + * + * As you see there are clipping issues (visual glitches). + * If you want to know how to fix it, please + * watch video tutorial. + */ + stapip.render(mesh.get(), renderOptions); + } + engine->renderer.endFrame(); +} void Tutorial04::loadMesh() { - ObjLoader loader; ObjLoaderOptions options; - options.flipUVs = true; options.scale = 200.0F; - auto data = loader.load(FileUtils::fromCwd("de_dust2/de_dust2.obj"), options); + /** + * Load mesh data + * Texture names are the material names "usemtl " + */ + auto data = + ObjLoader::load(FileUtils::fromCwd("de_dust2/de_dust2.obj"), options); + + /** Create mesh with loaded data */ mesh = std::make_unique(data.get()); + /** + * Disable frustum culling in render options, + * because it not make sense to perform + * frustum check on entire map (which will be always visible) + */ + renderOptions.frustumCulling = Tyra::PipelineFrustumCulling_None; + + /** + * Function which load all textures into texture repository, + * based on material names. + */ engine->renderer.getTextureRepository().addByMesh( mesh.get(), FileUtils::fromCwd("de_dust2/"), "png"); }