tutorial 04

This commit is contained in:
h4570
2022-08-22 23:23:51 +02:00
parent 4fa65fc535
commit d469e78747
26 changed files with 400 additions and 96 deletions
+2 -4
View File
@@ -1,7 +1,5 @@
------------ Tyra's v2.0 roadmap to publish on GitHub ------------ ------------ 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, - [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, 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) - [Tutorials] 8. Render skybox, and show that stdPipOptions.noClipChecks must be set to false, to turn on clip algorithms (prevent glitches)
- audio
- own game - own game
- how to cook audio,textures,obj
- usb - usb
- [General] Check all left TODOs -> Github issues - [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 - [General] smart pointers and std::array instead of raw pointers
- [renderer] fog - [renderer] fog
- [General] CI in Github via docker image - [General] CI in Github via docker image
- [renderer] bbox parts optimization
- [md2] refactor - [md2] refactor
- [2D] Add zbuffer support (z-index) - [2D] Add zbuffer support (z-index)
- [3DUtility] Add zbuffer support (z-index) - [3DUtility] Add zbuffer support (z-index)
- [2D] Fixed font support - [2D] Fixed font support
- [File] Async file loading - [File] Async file loading
- [obj] Add multicolor support to obj - [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 - [tyrdat] Custom 3D data file with precalculated bboxes with support of async loading
- [Renderer] Interlacing, a potem resolution 640x448 - [Renderer] Interlacing, a potem resolution 640x448
- [General] Add cpp lint checker in GitHub - [General] Add cpp lint checker in GitHub
@@ -13,6 +13,7 @@
#include "../../loader.hpp" #include "../../loader.hpp"
#include "../builder/mesh_builder_data.hpp" #include "../builder/mesh_builder_data.hpp"
#include <string> #include <string>
#include <memory>
namespace Tyra { namespace Tyra {
@@ -24,13 +25,12 @@ struct MD2LoaderOptions {
/** Class responsible for loading & parsing Quake's II ".md2" 3D files */ /** Class responsible for loading & parsing Quake's II ".md2" 3D files */
class MD2Loader : public Loader { class MD2Loader : public Loader {
public: public:
MD2Loader(); static std::unique_ptr<MeshBuilderData> load(const char* fullpath);
~MD2Loader(); static std::unique_ptr<MeshBuilderData> load(const char* fullpath,
MD2LoaderOptions options);
MeshBuilderData* load(const char* fullpath); static std::unique_ptr<MeshBuilderData> load(const std::string& fullpath);
MeshBuilderData* load(const char* fullpath, MD2LoaderOptions options); static std::unique_ptr<MeshBuilderData> load(const std::string& fullpath,
MeshBuilderData* load(const std::string& fullpath); MD2LoaderOptions options);
MeshBuilderData* load(const std::string& fullpath, MD2LoaderOptions options);
}; };
} // namespace Tyra } // namespace Tyra
+14 -16
View File
@@ -38,32 +38,30 @@ struct MaterialVertexCount {
/** Class responsible for loading & parsing obj files */ /** Class responsible for loading & parsing obj files */
class ObjLoader : public Loader { class ObjLoader : public Loader {
public: public:
ObjLoader(); static std::unique_ptr<MeshBuilderData> load(const char* fullpath);
~ObjLoader(); static std::unique_ptr<MeshBuilderData> load(const char* fullpath,
const ObjLoaderOptions& options);
std::unique_ptr<MeshBuilderData> load(const char* fullpath); static std::unique_ptr<MeshBuilderData> load(const std::string& fullpath);
std::unique_ptr<MeshBuilderData> load(const char* fullpath, static std::unique_ptr<MeshBuilderData> load(const std::string& fullpath,
const ObjLoaderOptions& options); const ObjLoaderOptions& options);
std::unique_ptr<MeshBuilderData> load(const std::string& fullpath);
std::unique_ptr<MeshBuilderData> load(const std::string& fullpath,
const ObjLoaderOptions& options);
private: private:
void addOutputMaterialsAndFrames( static void addOutputMaterialsAndFrames(
MeshBuilderData* output, const tinyobj::attrib_t& attrib, MeshBuilderData* output, const tinyobj::attrib_t& attrib,
const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::shape_t>& shapes,
const std::vector<tinyobj::material_t>& materials, const u16& framesCount, const std::vector<tinyobj::material_t>& materials, const u16& framesCount,
std::vector<MaterialVertexCount>& materialVertexCounts); std::vector<MaterialVertexCount>& materialVertexCounts);
std::vector<MaterialVertexCount> scan( static std::vector<MaterialVertexCount> scan(
const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::shape_t>& shapes,
const std::vector<tinyobj::material_t>& materials); const std::vector<tinyobj::material_t>& materials);
void importFrame(MeshBuilderData* output, const tinyobj::attrib_t& attrib, static void importFrame(MeshBuilderData* output,
const std::vector<tinyobj::shape_t>& shapes, const tinyobj::attrib_t& attrib,
const std::vector<tinyobj::material_t>& materials, const std::vector<tinyobj::shape_t>& shapes,
const u16& frameIndex, const float& scale, const std::vector<tinyobj::material_t>& materials,
const bool& invertY, const u16& count); const u16& frameIndex, const float& scale,
const bool& invertY, const u16& count);
}; };
} // namespace Tyra } // namespace Tyra
+4 -4
View File
@@ -16,10 +16,10 @@ namespace Tyra {
class Loader { class Loader {
protected: protected:
std::string getFilenameFromPath(const std::string& path); static std::string getFilenameFromPath(const std::string& path);
std::string getPathFromFilename(const std::string& path); static std::string getPathFromFilename(const std::string& path);
std::string getFilenameWithoutExtension(const std::string& filename); static std::string getFilenameWithoutExtension(const std::string& filename);
std::string getExtensionOfFilename(const std::string& filename); static std::string getExtensionOfFilename(const std::string& filename);
}; };
} // namespace Tyra } // namespace Tyra
@@ -39,13 +39,16 @@ class DynamicPipeline : public Renderer3DPipeline {
void onUse(); void onUse();
void onFrameEnd();
void onUseEnd(); void onUseEnd();
/** /**
* Render dynamic model. * Render dynamic model.
* This render() method is a bridge to core.render() method. * 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); void render(const DynamicMesh* mesh, const DynPipOptions* options = nullptr);
private: private:
@@ -33,6 +33,7 @@ class MinecraftPipeline : public Renderer3DPipeline {
void onUse(); void onUse();
void onUseEnd(); void onUseEnd();
void onFrameEnd();
/** /**
* @brief Render voxels * @brief Render voxels
@@ -21,6 +21,7 @@ class Renderer3DPipeline {
virtual void setRenderer(RendererCore* core) = 0; virtual void setRenderer(RendererCore* core) = 0;
virtual void onUse() = 0; virtual void onUse() = 0;
virtual void onFrameEnd() = 0;
virtual void onUseEnd() = 0; virtual void onUseEnd() = 0;
std::function<void(Renderer3DPipeline*)> onDestroy; std::function<void(Renderer3DPipeline*)> onDestroy;
}; };
@@ -28,7 +28,8 @@ class StaPipCore {
void init(RendererCore* t_core); void init(RendererCore* t_core);
/** Render 3D via "bags" */ /** 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) */ /** Get max vert count of VU1 qbuffer (for optimizations) */
u32 getMaxVertCountByParams(const bool& isSingleColor, u32 getMaxVertCountByParams(const bool& isSingleColor,
@@ -0,0 +1,48 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#pragma once
#include <tamtypes.h>
#include "core/bag/packaging/stapip_bag_packages_bbox.hpp"
#include "renderer/3d/mesh/mesh.hpp"
#include <memory>
#include <vector>
namespace Tyra {
struct StapipBagBBoxesCacheItem {
u32 vu1MaxVertCount;
u32 frameId;
std::unique_ptr<StaPipBagPackagesBBox> 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<StapipBagBBoxesCacheItem> storage;
};
} // namespace Tyra
@@ -17,6 +17,7 @@
#include "renderer/3d/mesh/static/static_mesh.hpp" #include "renderer/3d/mesh/static/static_mesh.hpp"
#include "./core/stapip_core.hpp" #include "./core/stapip_core.hpp"
#include "./stapip_options.hpp" #include "./stapip_options.hpp"
#include "./stapip_bag_bboxes_cacher.hpp"
namespace Tyra { namespace Tyra {
@@ -38,17 +39,19 @@ class StaticPipeline : public Renderer3DPipeline {
void setRenderer(RendererCore* core); void setRenderer(RendererCore* core);
void onUse(); void onUse();
void onUseEnd(); void onUseEnd();
void onFrameEnd();
/** /**
* Render static model * Render static model
* This render() method is a bridge to core.render() method. * 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); void render(const StaticMesh* mesh, const StaPipOptions* options = nullptr);
private: private:
StapipBagBBoxesCacher cacher;
RendererCore* rendererCore; RendererCore* rendererCore;
Vec4* colorsCache; Vec4* colorsCache;
@@ -65,6 +68,7 @@ class StaticPipeline : public Renderer3DPipeline {
const MeshMaterialFrame* materialFrame); const MeshMaterialFrame* materialFrame);
StaPipLightingBag* getLightingBag(const MeshMaterialFrame* materialFrame, StaPipLightingBag* getLightingBag(const MeshMaterialFrame* materialFrame,
PipelineDirLightsBag* dirLightsBag,
M4x4* model, M4x4* model,
const StaPipOptions* options) const; const StaPipOptions* options) const;
+6 -2
View File
@@ -23,12 +23,16 @@ class Renderer3D {
Renderer3DUtility utility; Renderer3DUtility utility;
void init(RendererCore* core);
/** Deinitialize previous pipeline and initialize new pipeline */ /** Deinitialize previous pipeline and initialize new pipeline */
void usePipeline(Renderer3DPipeline* pipeline); void usePipeline(Renderer3DPipeline* pipeline);
void usePipeline(Renderer3DPipeline& pipeline); void usePipeline(Renderer3DPipeline& pipeline);
/** Called by engine */
void init(RendererCore* core);
/** Called by engine */
void onFrameEnd();
private: private:
Renderer3DPipeline* currentPipeline; Renderer3DPipeline* currentPipeline;
void onDestroy(Renderer3DPipeline* pipeline); void onDestroy(Renderer3DPipeline* pipeline);
+2 -2
View File
@@ -22,8 +22,8 @@ class RendererSettings {
height(448.0F), height(448.0F),
interlacedHeightF(height / 2), interlacedHeightF(height / 2),
near(0.1F), near(0.1F),
far(4096.0F), far(8192.0F),
projectionScale(4096.0F), projectionScale(8192.0F),
aspectRatio(width / height), aspectRatio(width / height),
interlacedHeightUI(static_cast<unsigned int>(interlacedHeightF)) {} interlacedHeightUI(static_cast<unsigned int>(interlacedHeightF)) {}
~RendererSettings(); ~RendererSettings();
@@ -70,25 +70,21 @@ typedef struct {
s16 t; s16 t;
} texCoord_t; } texCoord_t;
MD2Loader::MD2Loader() {} std::unique_ptr<MeshBuilderData> MD2Loader::load(const char* fullpath) {
MD2Loader::~MD2Loader() {}
MeshBuilderData* MD2Loader::load(const char* fullpath) {
return load(fullpath, MD2LoaderOptions()); return load(fullpath, MD2LoaderOptions());
} }
MeshBuilderData* MD2Loader::load(const std::string& fullpath) { std::unique_ptr<MeshBuilderData> MD2Loader::load(const std::string& fullpath) {
return load(fullpath.c_str(), MD2LoaderOptions()); return load(fullpath.c_str(), MD2LoaderOptions());
} }
MeshBuilderData* MD2Loader::load(const std::string& fullpath, std::unique_ptr<MeshBuilderData> MD2Loader::load(const std::string& fullpath,
MD2LoaderOptions options) { MD2LoaderOptions options) {
return load(fullpath.c_str(), options); return load(fullpath.c_str(), options);
} }
MeshBuilderData* MD2Loader::load(const char* fullpath, std::unique_ptr<MeshBuilderData> MD2Loader::load(const char* fullpath,
MD2LoaderOptions options) { MD2LoaderOptions options) {
std::string path = fullpath; std::string path = fullpath;
TYRA_ASSERT(!path.empty(), "Provided path is empty!"); TYRA_ASSERT(!path.empty(), "Provided path is empty!");
@@ -123,7 +119,7 @@ MeshBuilderData* MD2Loader::load(const char* fullpath,
fclose(file); fclose(file);
auto result = new MeshBuilderData(); auto result = std::make_unique<MeshBuilderData>();
auto* material = new MeshBuilderMaterialData(); auto* material = new MeshBuilderMaterialData();
material->name = getFilenameWithoutExtension(filename); material->name = getFilenameWithoutExtension(filename);
@@ -24,10 +24,6 @@
namespace Tyra { namespace Tyra {
ObjLoader::ObjLoader() {}
ObjLoader::~ObjLoader() {}
std::unique_ptr<MeshBuilderData> ObjLoader::load(const char* fullpath) { std::unique_ptr<MeshBuilderData> ObjLoader::load(const char* fullpath) {
return load(fullpath, ObjLoaderOptions()); return load(fullpath, ObjLoaderOptions());
} }
@@ -51,9 +51,13 @@ void DynamicPipeline::onUseEnd() {
core.deallocateOnUse(); core.deallocateOnUse();
} }
void DynamicPipeline::render(const DynamicMesh& mesh, void DynamicPipeline::onFrameEnd() {}
const DynPipOptions* options) {
render(&mesh, options); 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, void DynamicPipeline::render(const DynamicMesh* mesh,
@@ -78,6 +78,8 @@ void MinecraftPipeline::onUseEnd() {
manager.deallocateOnUse(); manager.deallocateOnUse();
} }
void MinecraftPipeline::onFrameEnd() {}
void MinecraftPipeline::initBBox() { void MinecraftPipeline::initBBox() {
const auto& block = manager.getBlockData(); const auto& block = manager.getBlockData();
bbox = new RenderBBox(block.vertices, block.count); bbox = new RenderBBox(block.vertices, block.count);
@@ -72,7 +72,8 @@ u32 StaPipCore::getMaxVertCountByParams(const bool& isSingleColor,
->getMaxVertCount(isSingleColor, qbufferRenderer.getBufferSize()); ->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; if (bag->count <= 0) return;
bool frustumCull = bool frustumCull =
@@ -105,32 +106,20 @@ void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox) {
TYRA_ASSERT(!(!frustumCull && bag->info->fullClipChecks == true), TYRA_ASSERT(!(!frustumCull && bag->info->fullClipChecks == true),
"Full clip checks are not supported with frustum culling = off!"); "Full clip checks are not supported with frustum culling = off!");
u32 maxVertCount = getMaxVertCountByBag(bag);
setMaxVertCount(maxVertCount); setMaxVertCount(maxVertCount);
StaPipBagPackagesBBox* renderBbox = nullptr;
CoreBBoxFrustum frustumCheck = OUTSIDE_FRUSTUM; CoreBBoxFrustum frustumCheck = OUTSIDE_FRUSTUM;
if (frustumCull) { if (frustumCull) {
if (!bbox) frustumCheck = bbox->getMainBBox()->clipFrustumCheck(
renderBbox =
new StaPipBagPackagesBBox(bag->vertices, bag->count, maxVertCount);
else
renderBbox = bbox;
frustumCheck = renderBbox->getMainBBox()->clipFrustumCheck(
rendererCore->renderer3D.frustumPlanes.getAll(), *bag->info->model); rendererCore->renderer3D.frustumPlanes.getAll(), *bag->info->model);
if (frustumCheck == OUTSIDE_FRUSTUM) { if (frustumCheck == OUTSIDE_FRUSTUM) {
if (!bbox) {
delete renderBbox;
}
return; return;
} }
} }
packager.setRenderBBox(renderBbox); packager.setRenderBBox(bbox);
M4x4 mvp; M4x4 mvp;
@@ -199,10 +188,6 @@ void StaPipCore::render(StaPipBag* bag, StaPipBagPackagesBBox* bbox) {
} }
} }
if (frustumCull && !bbox) {
delete renderBbox;
}
if (texBuffers) delete texBuffers; if (texBuffers) delete texBuffers;
qbufferRenderer.flushBuffers(); qbufferRenderer.flushBuffers();
@@ -0,0 +1,64 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#include "renderer/3d/pipeline/static/stapip_bag_bboxes_cacher.hpp"
#include <algorithm>
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<StaPipBagPackagesBBox>(
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
@@ -11,7 +11,7 @@
#include "renderer/3d/pipeline/static/static_pipeline.hpp" #include "renderer/3d/pipeline/static/static_pipeline.hpp"
#include "debug/debug.hpp" #include "debug/debug.hpp"
#include "renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp" #include "renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp"
#include <memory>
namespace Tyra { namespace Tyra {
StaticPipeline::StaticPipeline() {} StaticPipeline::StaticPipeline() {}
@@ -39,9 +39,13 @@ void StaticPipeline::onUseEnd() {
core.deallocateOnUse(); core.deallocateOnUse();
} }
void StaticPipeline::render(const StaticMesh& mesh, void StaticPipeline::onFrameEnd() { cacher.onFrameEnd(); }
const StaPipOptions* options) {
render(&mesh, options); 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, void StaticPipeline::render(const StaticMesh* mesh,
@@ -55,6 +59,7 @@ void StaticPipeline::render(const StaticMesh* mesh,
auto model = mesh->getModelMatrix(); auto model = mesh->getModelMatrix();
auto* infoBag = getInfoBag(mesh, options, &model); auto* infoBag = getInfoBag(mesh, options, &model);
auto dirLightsBag = std::make_unique<PipelineDirLightsBag>(true);
TYRA_ASSERT( TYRA_ASSERT(
!(options->frustumCulling != PipelineFrustumCulling_Precise && !(options->frustumCulling != PipelineFrustumCulling_Precise &&
@@ -85,11 +90,21 @@ void StaticPipeline::render(const StaticMesh* mesh,
bag.info = infoBag; bag.info = infoBag;
bag.color = getColorBag(material, materialFrame); bag.color = getColorBag(material, materialFrame);
bag.texture = getTextureBag(material, materialFrame); bag.texture = getTextureBag(material, materialFrame);
bag.lighting = getLightingBag(materialFrame, &model, options); bag.lighting =
core.render(&bag); 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); deallocDrawBags(&bag, material);
} }
delete infoBag; delete infoBag;
if (optionsManuallyAllocated) delete options; if (optionsManuallyAllocated) delete options;
@@ -156,18 +171,15 @@ StaPipTextureBag* StaticPipeline::getTextureBag(
} }
StaPipLightingBag* StaticPipeline::getLightingBag( StaPipLightingBag* StaticPipeline::getLightingBag(
const MeshMaterialFrame* materialFrame, M4x4* model, const MeshMaterialFrame* materialFrame, PipelineDirLightsBag* dirLightsBag,
const StaPipOptions* options) const { M4x4* model, const StaPipOptions* options) const {
if (!materialFrame->normals || options == nullptr || if (!materialFrame->normals || options == nullptr ||
options->lighting == nullptr) options->lighting == nullptr)
return nullptr; return nullptr;
auto* result = new StaPipLightingBag(); auto* result = new StaPipLightingBag();
// TODO: Make it once per rendering, very redundant
auto* dirLightsBag = new PipelineDirLightsBag(true);
result->dirLights = dirLightsBag; result->dirLights = dirLightsBag;
result->lightMatrix = model; result->lightMatrix = model;
result->dirLights->setLightsManually( result->dirLights->setLightsManually(
@@ -194,7 +206,6 @@ void StaticPipeline::deallocDrawBags(StaPipBag* bag,
} }
if (bag->lighting) { if (bag->lighting) {
delete bag->lighting->dirLights; // TODO
delete bag->lighting; delete bag->lighting;
} }
+6
View File
@@ -19,6 +19,12 @@ Renderer3D::~Renderer3D() {}
void Renderer3D::init(RendererCore* core) { utility.init(core); } void Renderer3D::init(RendererCore* core) { utility.init(core); }
void Renderer3D::onFrameEnd() {
if (currentPipeline != nullptr) {
currentPipeline->onFrameEnd();
}
}
void Renderer3D::usePipeline(Renderer3DPipeline& pipeline) { void Renderer3D::usePipeline(Renderer3DPipeline& pipeline) {
usePipeline(&pipeline); usePipeline(&pipeline);
} }
+4 -1
View File
@@ -27,6 +27,9 @@ void Renderer::beginFrame(const CameraInfo3D& cameraInfo) {
core.beginFrame(cameraInfo); core.beginFrame(cameraInfo);
} }
void Renderer::endFrame() { core.endFrame(); } void Renderer::endFrame() {
core.endFrame();
renderer3D.onFrameEnd();
}
} // namespace Tyra } // namespace Tyra
@@ -44,6 +44,8 @@ class Tutorial03 : public Game {
* - Minecraft (this one) * - Minecraft (this one)
* - Static (for static 3D objects) * - Static (for static 3D objects)
* - Dynamic (for dynamic 3D objects) * - Dynamic (for dynamic 3D objects)
*
* You can create your own VU1 programs and create your custom pipelines!
*/ */
MinecraftPipeline mcpip; MinecraftPipeline mcpip;
+44
View File
@@ -0,0 +1,44 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#pragma once
#include <tyra>
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
+10 -1
View File
@@ -12,6 +12,7 @@
#include <tyra> #include <tyra>
#include <memory.h> #include <memory.h>
#include "./camera.hpp"
namespace Tyra { namespace Tyra {
@@ -28,8 +29,16 @@ class Tutorial04 : public Game {
Engine* engine; Engine* engine;
std::unique_ptr<StaticMesh> mesh; Camera camera;
/** 3D pipeline used for rendering static meshes */
StaticPipeline stapip;
/** Options for static pipeline */
StaPipOptions renderOptions; StaPipOptions renderOptions;
/** Mesh with de_dust2 */
std::unique_ptr<StaticMesh> mesh;
}; };
} // namespace Tyra } // namespace Tyra
+85
View File
@@ -0,0 +1,85 @@
/*
# _____ ____ ___
# | \/ ____| |___|
# | | | \ | |
#-----------------------------------------------------------------------
# Copyright 2022, tyra - https://github.com/h4570/tyra
# Licensed under Apache License 2.0
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
*/
#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
+45 -6
View File
@@ -13,25 +13,64 @@
namespace Tyra { namespace Tyra {
Tutorial04::Tutorial04(Engine* t_engine) : engine(t_engine) {} Tutorial04::Tutorial04(Engine* t_engine)
: engine(t_engine), camera(&t_engine->pad) {}
Tutorial04::~Tutorial04() { Tutorial04::~Tutorial04() {
engine->renderer.getTextureRepository().freeByMesh(mesh.get()); 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() { void Tutorial04::loadMesh() {
ObjLoader loader;
ObjLoaderOptions options; ObjLoaderOptions options;
options.flipUVs = true;
options.scale = 200.0F; 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 <material name>"
*/
auto data =
ObjLoader::load(FileUtils::fromCwd("de_dust2/de_dust2.obj"), options);
/** Create mesh with loaded data */
mesh = std::make_unique<StaticMesh>(data.get()); mesh = std::make_unique<StaticMesh>(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( engine->renderer.getTextureRepository().addByMesh(
mesh.get(), FileUtils::fromCwd("de_dust2/"), "png"); mesh.get(), FileUtils::fromCwd("de_dust2/"), "png");
} }