finished tutorial 7
This commit is contained in:
+1
-3
@@ -1,11 +1,10 @@
|
||||
------------ Tyra's v2.0 roadmap to publish on GitHub ------------
|
||||
|
||||
- [Tutorials] 5
|
||||
- [Tutorials] 6
|
||||
- [Tutorials] 7
|
||||
- [Tutorials] 8
|
||||
- [Tutorials] 9.
|
||||
|
||||
- [Renderer] Check ee clipping on de_dust2, add decimate to de_dust2?
|
||||
- [General] Check all left TODOs -> Github issues
|
||||
- [General] Readme Credits: clipping, obj loader
|
||||
- [Video] How to setup environment
|
||||
@@ -19,7 +18,6 @@
|
||||
- [Demo] BBox constructors
|
||||
- [General] Add cpp lint checker in GitHub / static code analysis
|
||||
- [General] Smart pointers and std::array instead of raw pointers
|
||||
- [Renderer] Check ee clipping on de_dust2, add decimate to de_dust2?
|
||||
- [General] Control generated id to avoid duplication. Maybe Just increment from 0? Add interface IIdentificable?
|
||||
- [renderer] fog
|
||||
- [General] CI in Github via docker image
|
||||
|
||||
@@ -22,7 +22,7 @@ class MeshMaterial {
|
||||
explicit MeshMaterial(const MeshMaterial& material);
|
||||
~MeshMaterial();
|
||||
|
||||
u8 isMother, lightmapFlag;
|
||||
bool isMother, lightmapFlag;
|
||||
|
||||
u32 id;
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class DynamicPipeline : public Renderer3DPipeline {
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
RendererCore* rendererCore;
|
||||
|
||||
@@ -48,7 +48,7 @@ class StaticPipeline : public Renderer3DPipeline {
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
StapipBagBBoxesCacher cacher;
|
||||
|
||||
@@ -53,6 +53,10 @@ class Color {
|
||||
void operator-=(const float& v);
|
||||
void operator*=(const float& v);
|
||||
void operator/=(const float& v);
|
||||
Color operator+(const float& v) const;
|
||||
Color operator-(const float& v) const;
|
||||
Color operator*(const float& v) const;
|
||||
Color operator/(const float& v) const;
|
||||
|
||||
inline void set(const Color& v) { copy(this, v.rgba); }
|
||||
inline void set(const float* v) { copy(this, v); }
|
||||
|
||||
@@ -30,11 +30,11 @@ MeshMaterial::MeshMaterial(const MeshBuilderData& data,
|
||||
id = rand() % 1000000;
|
||||
|
||||
if (data.lightMapEnabled) {
|
||||
lightmapFlag = false;
|
||||
lightmapFlag = true;
|
||||
TYRA_ASSERT(material->frames[0]->colors != nullptr,
|
||||
"Colors faces are required");
|
||||
} else {
|
||||
lightmapFlag = true;
|
||||
lightmapFlag = false;
|
||||
}
|
||||
|
||||
ambient.set(material->ambient);
|
||||
|
||||
@@ -112,9 +112,10 @@ void DynamicPipeline::render(const DynamicMesh* mesh,
|
||||
auto* texture =
|
||||
rendererCore->texture.repository.getByMeshMaterialId(material->id);
|
||||
|
||||
TYRA_ASSERT(
|
||||
texture, "Texture for material: ", material->name, "Id: ", material->id,
|
||||
"Was not found in texture repository! Did you forget to add texture?");
|
||||
TYRA_ASSERT(texture, "Texture for material: ", material->name,
|
||||
"Id: ", material->id,
|
||||
"Was not found in texture repository! Did you forget to add "
|
||||
"texture or disable texture coords loading in mesh?");
|
||||
|
||||
for (u32 k = 0; k < partsCount; k++) {
|
||||
auto& buffer = buffers[bufferIndex];
|
||||
|
||||
@@ -96,7 +96,7 @@ void StaticPipeline::render(const StaticMesh* mesh,
|
||||
u32 maxVertCount = core.getMaxVertCountByBag(&bag);
|
||||
|
||||
StaPipBagPackagesBBox* bbox = nullptr;
|
||||
if (bag.info->frustumCulling == PipelineFrustumCulling_Precise) {
|
||||
if (bag.info->frustumCulling == PipelineInfoBagFrustumCulling_Precise) {
|
||||
bbox = cacher.getBBoxesByMesh(materialFrame, maxVertCount);
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ StaPipColorBag* StaticPipeline::getColorBag(
|
||||
auto* result = new StaPipColorBag();
|
||||
|
||||
if (material->lightmapFlag) {
|
||||
result->single = &material->ambient;
|
||||
} else {
|
||||
result->many = materialFrame->colors;
|
||||
} else {
|
||||
result->single = &material->ambient;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -160,10 +160,10 @@ StaPipTextureBag* StaticPipeline::getTextureBag(
|
||||
result->texture =
|
||||
rendererCore->texture.repository.getByMeshMaterialId(material->id);
|
||||
|
||||
TYRA_ASSERT(
|
||||
result->texture, "Texture for material: ", material->name,
|
||||
TYRA_ASSERT(result->texture, "Texture for material: ", material->name,
|
||||
"Id: ", material->id,
|
||||
"Was not found in texture repository! Did you forget to add texture?");
|
||||
"Was not found in texture repository! Did you forget to add "
|
||||
"texture or disable texture coords loading in mesh?");
|
||||
|
||||
result->coordinates = materialFrame->textureCoords;
|
||||
|
||||
|
||||
@@ -47,6 +47,30 @@ void Color::operator/=(const float& v) {
|
||||
a /= v;
|
||||
}
|
||||
|
||||
Color Color::operator+(const float& v) const {
|
||||
Color result = *this;
|
||||
result += v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Color Color::operator-(const float& v) const {
|
||||
Color result = *this;
|
||||
result -= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Color Color::operator*(const float& v) const {
|
||||
Color result = *this;
|
||||
result *= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Color Color::operator/(const float& v) const {
|
||||
Color result = *this;
|
||||
result /= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Color::set(const float& t_r, const float& t_g, const float& t_b,
|
||||
const float& t_a) {
|
||||
r = t_r;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
TARGET := tutorial_02.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
|
||||
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
# _____ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# 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 Tutorial02 : public Game {
|
||||
public:
|
||||
Tutorial02(Engine* engine);
|
||||
~Tutorial02();
|
||||
|
||||
void init();
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void loadTexture();
|
||||
void loadSprite();
|
||||
|
||||
Engine* engine;
|
||||
|
||||
Sprite sprite;
|
||||
};
|
||||
|
||||
} // namespace Tyra
|
||||
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -0,0 +1,4 @@
|
||||
$ConfigFile = Join-Path $PSScriptRoot '../../windows-pcsx2.ps1'
|
||||
. $ConfigFile
|
||||
|
||||
RunPCSX2
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
# _____ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||
# Licensed under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include "engine.hpp"
|
||||
#include "tutorial_02.hpp"
|
||||
|
||||
/**
|
||||
* In this tutorial we will learn how to:
|
||||
* - Load png file and create texture from it
|
||||
* - Create sprite class
|
||||
* - Clear screen and render sprite
|
||||
*/
|
||||
|
||||
int main() {
|
||||
Tyra::Engine engine;
|
||||
Tyra::Tutorial02 game(&engine);
|
||||
engine.run(&game);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
# _____ ____ ___
|
||||
# | \/ ____| |___|
|
||||
# | | | \ | |
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||
# Licensed under Apache License 2.0
|
||||
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||
*/
|
||||
|
||||
#include <tyra>
|
||||
#include "tutorial_02.hpp"
|
||||
|
||||
namespace Tyra {
|
||||
|
||||
Tutorial02::Tutorial02(Engine* t_engine) : engine(t_engine) {}
|
||||
|
||||
Tutorial02::~Tutorial02() {
|
||||
engine->renderer.getTextureRepository().freeBySprite(sprite);
|
||||
}
|
||||
|
||||
void Tutorial02::init() {
|
||||
engine->renderer.setClearScreenColor(Color(32.0F, 32.0F, 32.0F));
|
||||
|
||||
/** Sprite contains rectangle information. */
|
||||
loadSprite();
|
||||
|
||||
/** Texture contains png image. */
|
||||
loadTexture();
|
||||
}
|
||||
|
||||
void Tutorial02::loop() {
|
||||
auto& renderer = engine->renderer;
|
||||
|
||||
/** Begin frame will clear our screen. */
|
||||
renderer.beginFrame();
|
||||
|
||||
/** Render sprite. */
|
||||
renderer.renderer2D.render(sprite);
|
||||
|
||||
/** End frame will perform vsync. */
|
||||
renderer.endFrame();
|
||||
}
|
||||
|
||||
void Tutorial02::loadSprite() {
|
||||
const auto& screenSettings = engine->renderer.core.getSettings();
|
||||
|
||||
sprite.mode = SpriteMode::MODE_STRETCH;
|
||||
|
||||
/** Let's scale it down */
|
||||
sprite.size = Vec2(256.0F, 128.0F);
|
||||
|
||||
/** Set it in screen center */
|
||||
sprite.position =
|
||||
Vec2(screenSettings.getWidth() / 2.0F - sprite.size.x / 2.0F,
|
||||
screenSettings.getHeight() / 2.0F - sprite.size.y / 2.0F);
|
||||
|
||||
TYRA_LOG("Sprite created!");
|
||||
}
|
||||
|
||||
void Tutorial02::loadTexture() {
|
||||
/**
|
||||
* Renderer has high layer functions,
|
||||
* which allows to render:
|
||||
* - Sprite (2D)
|
||||
* - Mesh (3D)
|
||||
*
|
||||
* It uses ONLY low layer functions which are in renderer.core
|
||||
*/
|
||||
auto& renderer = engine->renderer;
|
||||
|
||||
/**
|
||||
* TextureRepository is a repository of textures.
|
||||
* It is a singleton class, with all game textures.
|
||||
* We are linking these textures with sprite's (2D) and mesh (3D) materials.
|
||||
*/
|
||||
auto& textureRepository = renderer.getTextureRepository();
|
||||
|
||||
/**
|
||||
* Texture is stored in "res" directory.
|
||||
* Content of "res" directory is automatically copied into
|
||||
* "bin" directory, which contains our final game.
|
||||
*
|
||||
* File utils automatically add's device prefix to the path,
|
||||
* based on current working directory.
|
||||
*
|
||||
* In PS2 world:
|
||||
* - USB has a "mass:" prefix
|
||||
* - Our PC in PS2Link has a "host:" prefix
|
||||
* - Our PC in PCSX2 has a "host:" prefix
|
||||
*/
|
||||
auto filepath = FileUtils::fromCwd("tyra.png");
|
||||
|
||||
/**
|
||||
* Tyra supports following PNG formats:
|
||||
* 32bpp (RGBA)
|
||||
* 24bpp (RGB)
|
||||
* 8bpp, palletized (RGBA)
|
||||
* 4bpp, palletized (RGBA)
|
||||
*
|
||||
* 8bpp and 4bpp are the fastest.
|
||||
* All of these formats can be easily exported via GIMP.
|
||||
*/
|
||||
auto* texture = textureRepository.add(filepath);
|
||||
|
||||
/** Let's assign this texture to sprite. */
|
||||
texture->addLink(sprite.id);
|
||||
|
||||
TYRA_LOG("Texture loaded!");
|
||||
}
|
||||
|
||||
} // namespace Tyra
|
||||
@@ -36,7 +36,7 @@ void Tutorial01::init() {
|
||||
* Every function has infinite number of various-typed arguments.
|
||||
*/
|
||||
|
||||
short positiveNumber = -1; // Change it to -1 and see what happen!
|
||||
short positiveNumber = 1; // Change it to -1 and see what happen!
|
||||
|
||||
TYRA_LOG("Hello world!");
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ void Tutorial05::loop() {
|
||||
{
|
||||
engine->renderer.renderer3D.usePipeline(dynpip);
|
||||
|
||||
dynpip.render(zombieMesh.get(), renderOptions);
|
||||
dynpip.render(zombieMesh.get());
|
||||
dynpip.render(warriorMesh.get(), renderOptions);
|
||||
}
|
||||
engine->renderer.endFrame();
|
||||
|
||||
@@ -24,6 +24,8 @@ class Tutorial06 : public Game {
|
||||
|
||||
private:
|
||||
Engine* engine;
|
||||
|
||||
audsrv_adpcm_t* sample;
|
||||
};
|
||||
|
||||
} // namespace Tyra
|
||||
|
||||
@@ -17,8 +17,31 @@ Tutorial06::Tutorial06(Engine* t_engine) : engine(t_engine) {}
|
||||
|
||||
Tutorial06::~Tutorial06() {}
|
||||
|
||||
void Tutorial06::init() {}
|
||||
void Tutorial06::init() {
|
||||
/** 16bit 22kHz wav file */
|
||||
engine->audio.song.load(FileUtils::fromCwd("kayah-supermenka.wav"));
|
||||
engine->audio.song.inLoop = true;
|
||||
engine->audio.song.setVolume(60);
|
||||
engine->audio.song.play();
|
||||
|
||||
void Tutorial06::loop() {}
|
||||
/** 16bit 22kHz wav file converted to adpcm sample */
|
||||
sample = engine->audio.adpcm.load(FileUtils::fromCwd("shoot.adpcm"));
|
||||
/** Set volume for channel 0 */
|
||||
engine->audio.adpcm.setVolume(30, 0);
|
||||
}
|
||||
|
||||
void Tutorial06::loop() {
|
||||
engine->renderer.beginFrame();
|
||||
{
|
||||
/** Play ADPCM if (X) button is clicked! */
|
||||
if (engine->pad.getClicked().Cross) {
|
||||
/** Try to play sample in channel 0 */
|
||||
if (engine->audio.adpcm.tryPlay(sample, 0) == ADPCM_CHANNEL_USED) {
|
||||
TYRA_WARN("Channel is busy, please use another channel!");
|
||||
}
|
||||
}
|
||||
}
|
||||
engine->renderer.endFrame();
|
||||
}
|
||||
|
||||
} // namespace Tyra
|
||||
|
||||
@@ -23,7 +23,25 @@ class Tutorial07 : public Game {
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void loadMeshWithLightmap();
|
||||
void setDirectionalLightsOptions();
|
||||
void setLightmap(MeshBuilderData* data);
|
||||
void switchBetweenLightmapAndDirectional();
|
||||
|
||||
int counter, switcher;
|
||||
|
||||
Engine* engine;
|
||||
|
||||
Vec4 cameraPosition, cameraLookAt;
|
||||
|
||||
StaticPipeline stapip;
|
||||
StaPipOptions renderOptions;
|
||||
std::unique_ptr<StaticMesh> mesh;
|
||||
|
||||
PipelineLightingOptions renderLightingOptions;
|
||||
Color directionalAmbientColor;
|
||||
std::array<Color, 3> directionalColors;
|
||||
std::array<Vec4, 3> directionalDirections;
|
||||
};
|
||||
|
||||
} // namespace Tyra
|
||||
|
||||
@@ -13,12 +13,143 @@
|
||||
|
||||
namespace Tyra {
|
||||
|
||||
Tutorial07::Tutorial07(Engine* t_engine) : engine(t_engine) {}
|
||||
Tutorial07::Tutorial07(Engine* t_engine) : engine(t_engine) {
|
||||
counter = 101;
|
||||
switcher = 0;
|
||||
}
|
||||
|
||||
Tutorial07::~Tutorial07() {}
|
||||
|
||||
void Tutorial07::init() {}
|
||||
void Tutorial07::init() {
|
||||
engine->renderer.setClearScreenColor(Color(32.0F, 32.0F, 32.0F));
|
||||
|
||||
void Tutorial07::loop() {}
|
||||
stapip.setRenderer(&engine->renderer.core);
|
||||
|
||||
cameraPosition = Vec4(0.0F, 0.0F, -10.0F);
|
||||
cameraLookAt.unit();
|
||||
|
||||
/**
|
||||
* Directional lights are dynamic lights with infinite range.
|
||||
*
|
||||
* Lightmap is a fast, pregenerated lightmap for a mesh.
|
||||
* It is very useful for meshes like terrain, buildings, etc..
|
||||
*
|
||||
* Lightmap in PS2 world is done by old school color-per-vertex.
|
||||
*/
|
||||
|
||||
loadMeshWithLightmap();
|
||||
setDirectionalLightsOptions();
|
||||
}
|
||||
|
||||
void Tutorial07::loop() {
|
||||
switchBetweenLightmapAndDirectional();
|
||||
|
||||
/** Rotate the mesh to see the effect static vs dynamic lights */
|
||||
mesh->rotation.rotateY(0.05F);
|
||||
|
||||
engine->renderer.beginFrame(CameraInfo3D(&cameraPosition, &cameraLookAt));
|
||||
{
|
||||
engine->renderer.renderer3D.usePipeline(stapip);
|
||||
|
||||
/** Switch between dynamic directional lights / static lightmap */
|
||||
if (switcher == 0) {
|
||||
stapip.render(mesh.get(), renderOptions);
|
||||
} else {
|
||||
stapip.render(mesh.get());
|
||||
}
|
||||
}
|
||||
engine->renderer.endFrame();
|
||||
}
|
||||
|
||||
void Tutorial07::loadMeshWithLightmap() {
|
||||
ObjLoaderOptions options;
|
||||
options.scale = 2.0F;
|
||||
|
||||
auto data = ObjLoader::load(FileUtils::fromCwd("cup.obj"), options);
|
||||
|
||||
/**
|
||||
* We don't want to load texture coordinates,
|
||||
* because this obj file has no texture.
|
||||
*
|
||||
* Anyways you can use texture as well.
|
||||
*/
|
||||
data->textureCoordsEnabled = false;
|
||||
|
||||
/** Lets add lightmap manually */
|
||||
setLightmap(data.get());
|
||||
|
||||
mesh = std::make_unique<StaticMesh>(data.get());
|
||||
mesh->translation.translateY(-1.0F);
|
||||
mesh->rotation.rotateX(1.0F);
|
||||
}
|
||||
|
||||
void Tutorial07::setDirectionalLightsOptions() {
|
||||
// Set ambient color
|
||||
directionalAmbientColor.set(16.0F, 32.0F, 16.0F);
|
||||
|
||||
// Reset colors and directions
|
||||
for (int i = 0; i < 3; i++) {
|
||||
directionalColors[i].set(0.0F, 0.0F, 0.0F, 1.0F);
|
||||
directionalDirections[i].set(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
// Set light and direction 1
|
||||
directionalDirections[0].set(-1.0F, 0.3F, 0.3F);
|
||||
directionalColors[0].set(16.0F, 16.0F, 96.0F);
|
||||
|
||||
// Set light and direction 2
|
||||
directionalDirections[1].set(0.0F, -1.0F, 1.0F);
|
||||
directionalColors[1].set(96.0F, 16.0F, 16.0F);
|
||||
|
||||
// Set render options
|
||||
renderLightingOptions.ambientColor = &directionalAmbientColor;
|
||||
renderLightingOptions.directionalColors = directionalColors.begin();
|
||||
renderLightingOptions.directionalDirections = directionalDirections.begin();
|
||||
renderOptions.shadingType = TyraShadingGouraud;
|
||||
renderOptions.blendingEnabled = true;
|
||||
renderOptions.lighting = &renderLightingOptions;
|
||||
}
|
||||
|
||||
void Tutorial07::setLightmap(MeshBuilderData* data) {
|
||||
/** Information for mesh, that data has lightmap */
|
||||
data->lightMapEnabled = true;
|
||||
|
||||
/** This object file has only 1 material */
|
||||
auto* material = data->materials[0];
|
||||
|
||||
/** Static mesh so 1 frame */
|
||||
auto* frame = material->frames[0];
|
||||
|
||||
/**
|
||||
* You can load your pregenerated lightmap here.
|
||||
* In tutorial we will generate some random lightmap.
|
||||
*
|
||||
* Dont worry about dynamic allocation,
|
||||
* it will be handled by Mesh class.
|
||||
*/
|
||||
frame->colors = new Color[frame->count];
|
||||
for (u32 i = 0; i < frame->count; i++) {
|
||||
auto randomLight = 0.1F + ((2.0F + frame->vertices[i].x) / 4.0F);
|
||||
frame->colors[i] = material->ambient * randomLight;
|
||||
frame->colors[i].a = 128.0F;
|
||||
}
|
||||
}
|
||||
|
||||
void Tutorial07::switchBetweenLightmapAndDirectional() {
|
||||
if (counter++ > 100) {
|
||||
counter = 0;
|
||||
switcher = !switcher;
|
||||
|
||||
auto* material = mesh->materials[0];
|
||||
|
||||
if (switcher == 0) {
|
||||
material->lightmapFlag = false;
|
||||
TYRA_LOG("Directional lights!");
|
||||
} else {
|
||||
material->lightmapFlag = true;
|
||||
TYRA_LOG("Lightmap!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tyra
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* In this tutorial we will learn:
|
||||
* - How to render skybox and what is "ALLPASS" rendering method
|
||||
* - How to render debug lines and bboxes
|
||||
* - How to get available RAM and FPS count
|
||||
*/
|
||||
|
||||
int main() {
|
||||
|
||||
Reference in New Issue
Block a user