10 enemies in demo
This commit is contained in:
@@ -12,12 +12,18 @@
|
|||||||
|
|
||||||
#include <renderer/3d/mesh/dynamic/dynamic_mesh.hpp>
|
#include <renderer/3d/mesh/dynamic/dynamic_mesh.hpp>
|
||||||
#include <renderer/3d/pipeline/dynamic/dynpip_options.hpp>
|
#include <renderer/3d/pipeline/dynamic/dynpip_options.hpp>
|
||||||
|
#include <renderer/3d/mesh/dynamic/animation_sequence_callback.hpp>
|
||||||
#include "states/game/renderer/renderer_dynamic_pair.hpp"
|
#include "states/game/renderer/renderer_dynamic_pair.hpp"
|
||||||
#include "states/game/terrain/heightmap.hpp"
|
#include "states/game/terrain/heightmap.hpp"
|
||||||
#include <renderer/renderer.hpp>
|
#include <renderer/renderer.hpp>
|
||||||
|
#include <engine.hpp>
|
||||||
|
#include "./enemy_info.hpp"
|
||||||
|
|
||||||
|
using Tyra::AnimationSequenceCallback;
|
||||||
|
using Tyra::Audio;
|
||||||
using Tyra::DynamicMesh;
|
using Tyra::DynamicMesh;
|
||||||
using Tyra::DynPipOptions;
|
using Tyra::DynPipOptions;
|
||||||
|
using Tyra::Engine;
|
||||||
using Tyra::Renderer;
|
using Tyra::Renderer;
|
||||||
using Tyra::TextureRepository;
|
using Tyra::TextureRepository;
|
||||||
using Tyra::Vec4;
|
using Tyra::Vec4;
|
||||||
@@ -26,7 +32,7 @@ namespace Demo {
|
|||||||
|
|
||||||
class Enemy {
|
class Enemy {
|
||||||
public:
|
public:
|
||||||
Enemy(TextureRepository* repo);
|
Enemy(Engine* engine, const EnemyInfo& info);
|
||||||
~Enemy();
|
~Enemy();
|
||||||
|
|
||||||
DynamicMesh* mesh;
|
DynamicMesh* mesh;
|
||||||
@@ -36,7 +42,19 @@ class Enemy {
|
|||||||
void update(const Heightmap& heightmap, const Vec4& playerPosition);
|
void update(const Heightmap& heightmap, const Vec4& playerPosition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<u32> walkSequence;
|
||||||
|
std::vector<u32> fightSequence;
|
||||||
|
|
||||||
void allocateOptions();
|
void allocateOptions();
|
||||||
|
void walk(const Heightmap& heightmap, const Vec4& positionDiff);
|
||||||
|
void animationCallback(const AnimationSequenceCallback& callback);
|
||||||
|
void fight();
|
||||||
|
|
||||||
|
bool isWalking = true;
|
||||||
|
bool isFighting = false;
|
||||||
|
|
||||||
|
Audio* audio;
|
||||||
|
EnemyInfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Demo
|
} // namespace Demo
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 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>
|
||||||
|
#include <audsrv.h>
|
||||||
|
|
||||||
|
using Tyra::DynamicMesh;
|
||||||
|
using Tyra::Texture;
|
||||||
|
using Tyra::Vec4;
|
||||||
|
|
||||||
|
namespace Demo {
|
||||||
|
|
||||||
|
struct EnemyInfo {
|
||||||
|
u8 adpcmChannel;
|
||||||
|
audsrv_adpcm_t* adpcmSample;
|
||||||
|
DynamicMesh* motherMesh;
|
||||||
|
Texture* bodyTexture;
|
||||||
|
Texture* clothTexture;
|
||||||
|
Vec4 spawnPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Demo
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licensed under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "states/game/terrain/heightmap.hpp"
|
||||||
|
#include "./enemy.hpp"
|
||||||
|
#include <tyra>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using Tyra::DynamicMesh;
|
||||||
|
using Tyra::Engine;
|
||||||
|
using Tyra::Texture;
|
||||||
|
using Tyra::TextureRepository;
|
||||||
|
using Tyra::Vec4;
|
||||||
|
|
||||||
|
namespace Demo {
|
||||||
|
|
||||||
|
class EnemyManager {
|
||||||
|
public:
|
||||||
|
EnemyManager(Engine* engine, const Heightmap& heightmap);
|
||||||
|
~EnemyManager();
|
||||||
|
|
||||||
|
void update(const Heightmap& heightmap, const Vec4& playerPosition);
|
||||||
|
|
||||||
|
std::vector<RendererDynamicPair*> getPairs() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextureRepository* textureRepo;
|
||||||
|
std::vector<Enemy*> enemies;
|
||||||
|
DynamicMesh* motherMesh;
|
||||||
|
Texture* bodyTexture;
|
||||||
|
Texture* clothTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Demo
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
#include "./terrain/terrain.hpp"
|
#include "./terrain/terrain.hpp"
|
||||||
#include "./skybox/skybox.hpp"
|
#include "./skybox/skybox.hpp"
|
||||||
#include "./debug_object.hpp"
|
#include "./debug_object.hpp"
|
||||||
#include "./enemy/enemy.hpp"
|
#include "./enemy/enemy_manager.hpp"
|
||||||
|
|
||||||
namespace Demo {
|
namespace Demo {
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ class GameState : public State<GlobalStateType> {
|
|||||||
|
|
||||||
GameRenderer renderer;
|
GameRenderer renderer;
|
||||||
Player* player;
|
Player* player;
|
||||||
Enemy* enemy;
|
EnemyManager* enemyManager;
|
||||||
Terrain* terrain;
|
Terrain* terrain;
|
||||||
Skybox* skybox;
|
Skybox* skybox;
|
||||||
DebugObject* dbgObj;
|
DebugObject* dbgObj;
|
||||||
|
|||||||
@@ -9,38 +9,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "states/game/enemy/enemy.hpp"
|
#include "states/game/enemy/enemy.hpp"
|
||||||
#include "loaders/3d/obj_loader/obj_loader.hpp"
|
#include <functional>
|
||||||
#include <file/file_utils.hpp>
|
#include "debug/debug.hpp"
|
||||||
|
|
||||||
using Tyra::FileUtils;
|
|
||||||
using Tyra::Math;
|
using Tyra::Math;
|
||||||
using Tyra::ObjLoader;
|
|
||||||
using Tyra::ObjLoaderOptions;
|
|
||||||
|
|
||||||
namespace Demo {
|
namespace Demo {
|
||||||
|
|
||||||
Enemy::Enemy(TextureRepository* repo) {
|
Enemy::Enemy(Engine* engine, const EnemyInfo& t_info) {
|
||||||
ObjLoader loader;
|
info = t_info;
|
||||||
|
|
||||||
ObjLoaderOptions objOptions;
|
mesh = new DynamicMesh(*info.motherMesh);
|
||||||
objOptions.animation.count = 6;
|
|
||||||
objOptions.flipUVs = true;
|
|
||||||
objOptions.scale = 250.0F;
|
|
||||||
|
|
||||||
auto* data = loader.load(FileUtils::fromCwd("game/models/zombie/zombie.obj"),
|
auto* bodyMaterial = mesh->getMaterialByName("BodyMaterial");
|
||||||
objOptions);
|
auto* clothMaterial = mesh->getMaterialByName("ClothMaterial");
|
||||||
data->normalsEnabled = false;
|
|
||||||
mesh = new DynamicMesh(*data);
|
|
||||||
|
|
||||||
delete data;
|
TYRA_ASSERT(bodyMaterial != nullptr && clothMaterial != nullptr,
|
||||||
|
"Body and cloth materials not found!");
|
||||||
|
|
||||||
mesh->playAnimation(0, mesh->frames.size() - 1);
|
info.bodyTexture->addLink(bodyMaterial->id);
|
||||||
mesh->setAnimSpeed(0.1F);
|
info.clothTexture->addLink(clothMaterial->id);
|
||||||
|
|
||||||
repo->addByMesh(mesh, FileUtils::fromCwd("game/models/zombie/"), "png");
|
float r = Math::randomf(64.0F, 128.0F);
|
||||||
|
float g = Math::randomf(64.0F, 128.0F);
|
||||||
|
float b = Math::randomf(64.0F, 128.0F);
|
||||||
|
|
||||||
|
bodyMaterial->ambient.set(r, g, b);
|
||||||
|
clothMaterial->ambient.set(r, g, b);
|
||||||
|
|
||||||
|
walkSequence = {0, 1, 2};
|
||||||
|
fightSequence = {3, 4, 5};
|
||||||
|
|
||||||
|
mesh->setPosition(info.spawnPoint);
|
||||||
|
|
||||||
|
mesh->animation.setSequence(walkSequence);
|
||||||
|
mesh->animation.loop = true;
|
||||||
|
mesh->animation.setCallback(
|
||||||
|
std::bind(&Enemy::animationCallback, this, std::placeholders::_1));
|
||||||
mesh->translation.translateY(-5.0F);
|
mesh->translation.translateY(-5.0F);
|
||||||
|
|
||||||
|
audio = &engine->audio;
|
||||||
|
audio->adpcm.setVolume(50, info.adpcmChannel);
|
||||||
|
|
||||||
allocateOptions();
|
allocateOptions();
|
||||||
|
|
||||||
pair = new RendererDynamicPair{mesh, options};
|
pair = new RendererDynamicPair{mesh, options};
|
||||||
@@ -58,14 +68,10 @@ void Enemy::update(const Heightmap& heightmap, const Vec4& playerPosition) {
|
|||||||
auto diff = *enemyPosition - playerPosition;
|
auto diff = *enemyPosition - playerPosition;
|
||||||
auto ang = Math::atan2(diff.x, diff.z);
|
auto ang = Math::atan2(diff.x, diff.z);
|
||||||
|
|
||||||
if (diff.length() > 30.0F) {
|
if (diff.length() > 110.0F) {
|
||||||
diff.normalize();
|
walk(heightmap, diff);
|
||||||
const float speed = 1.5F;
|
} else {
|
||||||
auto nextPos = *enemyPosition - diff * speed;
|
fight();
|
||||||
nextPos.y = heightmap.getHeightOffset(nextPos) - 60.0F;
|
|
||||||
|
|
||||||
mesh->translation.identity();
|
|
||||||
mesh->translation.translate(nextPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float naturalRotation = 3.1F;
|
const float naturalRotation = 3.1F;
|
||||||
@@ -73,7 +79,43 @@ void Enemy::update(const Heightmap& heightmap, const Vec4& playerPosition) {
|
|||||||
ang += naturalRotation;
|
ang += naturalRotation;
|
||||||
mesh->rotation.rotateByAngle(ang, Vec4(0.0F, 1.0F, 0.0F, 0.0F));
|
mesh->rotation.rotateByAngle(ang, Vec4(0.0F, 1.0F, 0.0F, 0.0F));
|
||||||
|
|
||||||
mesh->animate();
|
mesh->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::walk(const Heightmap& heightmap, const Vec4& positionDiff) {
|
||||||
|
if (isFighting) {
|
||||||
|
mesh->animation.setSequence(walkSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
isFighting = false;
|
||||||
|
isWalking = true;
|
||||||
|
|
||||||
|
auto* enemyPosition = mesh->getPosition();
|
||||||
|
auto normalized = positionDiff;
|
||||||
|
normalized.normalize();
|
||||||
|
const float speed = 2.5F;
|
||||||
|
auto nextPos = *enemyPosition - normalized * speed;
|
||||||
|
nextPos.y = heightmap.getHeightOffset(nextPos) - 60.0F;
|
||||||
|
|
||||||
|
mesh->translation.identity();
|
||||||
|
mesh->translation.translate(nextPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::fight() {
|
||||||
|
if (isWalking) {
|
||||||
|
mesh->animation.setSequence(fightSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
isFighting = true;
|
||||||
|
isWalking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enemy::animationCallback(const AnimationSequenceCallback& callback) {
|
||||||
|
if (callback == AnimationSequenceCallback::AnimationSequenceCallback_Loop) {
|
||||||
|
if (isFighting) {
|
||||||
|
audio->adpcm.tryPlay(info.adpcmSample, info.adpcmChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Enemy::allocateOptions() { options = new DynPipOptions(); }
|
void Enemy::allocateOptions() { options = new DynPipOptions(); }
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licensed under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "states/game/enemy/enemy_manager.hpp"
|
||||||
|
#include "loaders/3d/obj_loader/obj_loader.hpp"
|
||||||
|
#include <file/file_utils.hpp>
|
||||||
|
#include <functional>
|
||||||
|
#include "debug/debug.hpp"
|
||||||
|
|
||||||
|
using Tyra::FileUtils;
|
||||||
|
using Tyra::Math;
|
||||||
|
using Tyra::ObjLoader;
|
||||||
|
using Tyra::ObjLoaderOptions;
|
||||||
|
|
||||||
|
namespace Demo {
|
||||||
|
|
||||||
|
EnemyManager::EnemyManager(Engine* engine, const Heightmap& heightmap) {
|
||||||
|
textureRepo = &engine->renderer.core.texture.repository;
|
||||||
|
|
||||||
|
ObjLoader loader;
|
||||||
|
ObjLoaderOptions objOptions;
|
||||||
|
objOptions.animation.count = 6;
|
||||||
|
objOptions.flipUVs = true;
|
||||||
|
objOptions.scale = 250.0F;
|
||||||
|
|
||||||
|
auto* data = loader.load(FileUtils::fromCwd("game/models/zombie/zombie.obj"),
|
||||||
|
objOptions);
|
||||||
|
data->normalsEnabled = false;
|
||||||
|
motherMesh = new DynamicMesh(*data);
|
||||||
|
|
||||||
|
delete data;
|
||||||
|
|
||||||
|
bodyTexture = textureRepo->add(
|
||||||
|
FileUtils::fromCwd("game/models/zombie/BodyMaterial.png"));
|
||||||
|
|
||||||
|
clothTexture = textureRepo->add(
|
||||||
|
FileUtils::fromCwd("game/models/zombie/ClothMaterial.png"));
|
||||||
|
|
||||||
|
auto* sample = engine->audio.adpcm.load(
|
||||||
|
FileUtils::fromCwd("game/models/zombie/punch.adpcm"));
|
||||||
|
|
||||||
|
const int enemyCount = 10;
|
||||||
|
for (int i = 0; i < enemyCount; i++) {
|
||||||
|
EnemyInfo info;
|
||||||
|
info.adpcmChannel = 9 + i;
|
||||||
|
info.adpcmSample = sample;
|
||||||
|
info.motherMesh = motherMesh;
|
||||||
|
info.clothTexture = clothTexture;
|
||||||
|
info.bodyTexture = bodyTexture;
|
||||||
|
info.spawnPoint =
|
||||||
|
Vec4(Math::randomf(heightmap.leftUp.x, heightmap.rightDown.x), 0.0F,
|
||||||
|
Math::randomf(heightmap.leftUp.z, heightmap.rightDown.z), 1.0F);
|
||||||
|
enemies.push_back(new Enemy(engine, info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnemyManager::~EnemyManager() {
|
||||||
|
for (auto* enemy : enemies) {
|
||||||
|
delete enemy;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete motherMesh;
|
||||||
|
|
||||||
|
textureRepo->free(bodyTexture->id);
|
||||||
|
textureRepo->free(clothTexture->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RendererDynamicPair*> EnemyManager::getPairs() const {
|
||||||
|
std::vector<RendererDynamicPair*> result;
|
||||||
|
|
||||||
|
for (auto* enemy : enemies) {
|
||||||
|
result.push_back(enemy->pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnemyManager::update(const Heightmap& heightmap,
|
||||||
|
const Vec4& playerPosition) {
|
||||||
|
for (auto* enemy : enemies) {
|
||||||
|
enemy->update(heightmap, playerPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Demo
|
||||||
@@ -37,8 +37,8 @@ void GameState::onStart() {
|
|||||||
|
|
||||||
auto* repository = &engine->renderer.core.texture.repository;
|
auto* repository = &engine->renderer.core.texture.repository;
|
||||||
player = new Player(engine);
|
player = new Player(engine);
|
||||||
enemy = new Enemy(repository);
|
|
||||||
terrain = new Terrain(repository);
|
terrain = new Terrain(repository);
|
||||||
|
enemyManager = new EnemyManager(engine, terrain->heightmap);
|
||||||
skybox = new Skybox(repository);
|
skybox = new Skybox(repository);
|
||||||
dbgObj = new DebugObject(repository);
|
dbgObj = new DebugObject(repository);
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ GlobalStateType GameState::onFinish() {
|
|||||||
if (!initialized) return STATE_EXIT;
|
if (!initialized) return STATE_EXIT;
|
||||||
|
|
||||||
delete player;
|
delete player;
|
||||||
delete enemy;
|
delete enemyManager;
|
||||||
delete terrain;
|
delete terrain;
|
||||||
delete skybox;
|
delete skybox;
|
||||||
delete dbgObj;
|
delete dbgObj;
|
||||||
@@ -59,7 +59,7 @@ GlobalStateType GameState::onFinish() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameState::update() {
|
void GameState::update() {
|
||||||
if (fpsChecker++ > 100) {
|
if (fpsChecker++ > 50) {
|
||||||
TYRA_LOG("FPS: ", engine->info.getFps());
|
TYRA_LOG("FPS: ", engine->info.getFps());
|
||||||
fpsChecker = 0;
|
fpsChecker = 0;
|
||||||
}
|
}
|
||||||
@@ -71,13 +71,13 @@ void GameState::update() {
|
|||||||
dbgObj->setPosition(*cameraInfo.looksAt);
|
dbgObj->setPosition(*cameraInfo.looksAt);
|
||||||
|
|
||||||
player->update(terrain->heightmap);
|
player->update(terrain->heightmap);
|
||||||
enemy->update(terrain->heightmap, player->getPosition());
|
enemyManager->update(terrain->heightmap, player->getPosition());
|
||||||
|
|
||||||
renderer.clear();
|
renderer.clear();
|
||||||
{
|
{
|
||||||
renderer.add(skybox->pair);
|
renderer.add(skybox->pair);
|
||||||
renderer.add(player->pair);
|
renderer.add(player->pair);
|
||||||
renderer.add(enemy->pair);
|
renderer.add(enemyManager->getPairs());
|
||||||
renderer.add(terrain->pair);
|
renderer.add(terrain->pair);
|
||||||
renderer.add(dbgObj->pair);
|
renderer.add(dbgObj->pair);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Player::Player(Engine* engine)
|
|||||||
pad = &engine->pad;
|
pad = &engine->pad;
|
||||||
position = Vec4(3.0F, 50.0F, 0.0F);
|
position = Vec4(3.0F, 50.0F, 0.0F);
|
||||||
camera.lookAt = Vec4(0.0F, 0.0F, -30.0F);
|
camera.lookAt = Vec4(0.0F, 0.0F, -30.0F);
|
||||||
speed = 3.5F;
|
speed = 5.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player() { delete pair; }
|
Player::~Player() { delete pair; }
|
||||||
|
|||||||
@@ -115,59 +115,6 @@ void Weapon::update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// float tX = 0.0F;
|
|
||||||
// float tY = -3.0F;
|
|
||||||
// float tZ = -10.0F;
|
|
||||||
|
|
||||||
// float rY = 0.1F;
|
|
||||||
// float rZ = -4.3F;
|
|
||||||
|
|
||||||
// void Weapon::debugPosition(Pad* pad) {
|
|
||||||
// const auto& leftJoy = pad->getLeftJoyPad();
|
|
||||||
// const auto& rightJoy = pad->getRightJoyPad();
|
|
||||||
// const float offset = 0.05F;
|
|
||||||
|
|
||||||
// if (leftJoy.v <= 100) {
|
|
||||||
// rY -= offset;
|
|
||||||
// } else if (leftJoy.v >= 200) {
|
|
||||||
// rY += offset;
|
|
||||||
// }
|
|
||||||
// if (leftJoy.h <= 100) {
|
|
||||||
// rZ -= offset;
|
|
||||||
// } else if (leftJoy.h >= 200) {
|
|
||||||
// rZ += offset;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (rightJoy.h <= 100) {
|
|
||||||
// tY -= offset;
|
|
||||||
// } else if (rightJoy.h >= 200) {
|
|
||||||
// tY += offset;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (rightJoy.v <= 100) {
|
|
||||||
// tZ -= offset;
|
|
||||||
// } else if (rightJoy.v >= 200) {
|
|
||||||
// tZ += offset;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (pad->getPressed().Circle) {
|
|
||||||
// tX -= offset;
|
|
||||||
// } else if (pad->getPressed().Cross) {
|
|
||||||
// tX += offset;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mesh->rotation.identity();
|
|
||||||
// mesh->rotation.rotateY(rY);
|
|
||||||
// mesh->rotation.rotateZ(rZ);
|
|
||||||
|
|
||||||
// mesh->translation.identity();
|
|
||||||
// mesh->translation.translateX(tX);
|
|
||||||
// mesh->translation.translateY(tY);
|
|
||||||
// mesh->translation.translateZ(tZ);
|
|
||||||
|
|
||||||
// TYRA_LOG("tX: ", tX, " tY: ", tY, " tZ: ", tZ, " rY: ", rY, " rZ: ", rZ);
|
|
||||||
// }
|
|
||||||
|
|
||||||
void Weapon::allocateOptions() {
|
void Weapon::allocateOptions() {
|
||||||
options = new StaPipOptions();
|
options = new StaPipOptions();
|
||||||
options->textureMappingType = Tyra::TyraNearest;
|
options->textureMappingType = Tyra::TyraNearest;
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ class Math {
|
|||||||
static float cos(float x);
|
static float cos(float x);
|
||||||
static float asin(float x);
|
static float asin(float x);
|
||||||
static float atan2(float y, float x);
|
static float atan2(float y, float x);
|
||||||
static float mod(float x, float y);
|
static float mod(const float& x, const float& y);
|
||||||
static float acos(float x);
|
static float acos(const float& x);
|
||||||
static float sin(float x);
|
static float sin(const float& x);
|
||||||
static float tan(float x);
|
static float tan(const float& x);
|
||||||
static float invSqrt(float x);
|
static float invSqrt(const float& x);
|
||||||
|
static float randomf(const float& min, const float& max);
|
||||||
|
static int randomi(const int& min, const int& max);
|
||||||
static bool equalf(const float& a, const float& b,
|
static bool equalf(const float& a, const float& b,
|
||||||
const float& epsilon = 0.00001F);
|
const float& epsilon = 0.00001F);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licensed under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Tyra {
|
||||||
|
|
||||||
|
enum AnimationSequenceCallback {
|
||||||
|
/** On frame change */
|
||||||
|
AnimationSequenceCallback_NextFrame,
|
||||||
|
/** When animation in loop = false will end */
|
||||||
|
AnimationSequenceCallback_End,
|
||||||
|
/** When animation in loop = true will start from beginning */
|
||||||
|
AnimationSequenceCallback_Loop
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Tyra
|
||||||
@@ -11,8 +11,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../mesh_frame.hpp"
|
#include "../mesh_frame.hpp"
|
||||||
#include "../mesh_material_frame.hpp"
|
#include "./dynamic_mesh_animation.hpp"
|
||||||
#include "./dynamic_mesh_anim_state.hpp"
|
|
||||||
#include "../mesh.hpp"
|
#include "../mesh.hpp"
|
||||||
|
|
||||||
namespace Tyra {
|
namespace Tyra {
|
||||||
@@ -25,36 +24,15 @@ class DynamicMesh : public Mesh {
|
|||||||
|
|
||||||
std::vector<MeshFrame*> frames;
|
std::vector<MeshFrame*> frames;
|
||||||
|
|
||||||
DynamicMeshAnimState animState;
|
DynamicMeshAnimation animation;
|
||||||
|
|
||||||
/** @returns bounding box object of current frame. */
|
/** @returns bounding box object of current frame. */
|
||||||
const BBox& getCurrentBoundingBox() const {
|
const BBox& getCurrentBoundingBox() const {
|
||||||
return *frames[animState.currentFrame]->bbox;
|
return *frames[animation.getState().currentFrame]->bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loop in one frame */
|
/** Update animation */
|
||||||
void playAnimation(const u32& t_frame);
|
inline void update() { animation.update(); }
|
||||||
|
|
||||||
/** Play animation in loop from startFrame to endFrame */
|
|
||||||
void playAnimation(const u32& t_startFrame, const u32& t_endFrame);
|
|
||||||
|
|
||||||
/** Play animation from startFrame to endFrame and after loop in stayFrame
|
|
||||||
*/
|
|
||||||
void playAnimation(const u32& t_startFrame, const u32& t_endFrame,
|
|
||||||
const u32& t_stayFrame);
|
|
||||||
|
|
||||||
void setAnimSpeed(const float& t_value) { animState.speed = t_value; }
|
|
||||||
|
|
||||||
void animate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this class loaded mesh data first.
|
|
||||||
* Meshes which use loadFrom() method have false there.
|
|
||||||
*/
|
|
||||||
const u8& isStayAnimationSet() const { return animState.isStayFrameSet; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void initAnimation();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Tyra
|
} // namespace Tyra
|
||||||
|
|||||||
@@ -15,16 +15,10 @@
|
|||||||
|
|
||||||
namespace Tyra {
|
namespace Tyra {
|
||||||
|
|
||||||
typedef struct {
|
struct DynamicMeshAnimState {
|
||||||
u32 startFrame;
|
|
||||||
u32 endFrame;
|
|
||||||
u32 stayFrame;
|
|
||||||
u8 isStayFrameSet;
|
|
||||||
float speed;
|
|
||||||
float interpolation;
|
float interpolation;
|
||||||
u32 animType;
|
|
||||||
u32 currentFrame;
|
u32 currentFrame;
|
||||||
u32 nextFrame;
|
u32 nextFrame;
|
||||||
} DynamicMeshAnimState;
|
};
|
||||||
|
|
||||||
} // namespace Tyra
|
} // namespace Tyra
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 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 "./dynamic_mesh_anim_state.hpp"
|
||||||
|
#include "./animation_sequence_callback.hpp"
|
||||||
|
#include "../mesh_frame.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Tyra {
|
||||||
|
|
||||||
|
class DynamicMeshAnimation {
|
||||||
|
public:
|
||||||
|
DynamicMeshAnimation();
|
||||||
|
~DynamicMeshAnimation();
|
||||||
|
|
||||||
|
bool loop;
|
||||||
|
float speed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update animation.
|
||||||
|
* Should be called every frame if you want animation running.
|
||||||
|
*/
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/** Set animation sequence (indices of frames) */
|
||||||
|
void setSequence(const std::vector<u32>& sequence);
|
||||||
|
|
||||||
|
/** Start animation from beginning */
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set animation callback.
|
||||||
|
* It will push animation info on every update() call.
|
||||||
|
*/
|
||||||
|
void setCallback(
|
||||||
|
const std::function<void(const AnimationSequenceCallback&)>& callback);
|
||||||
|
|
||||||
|
const DynamicMeshAnimState& getState() const;
|
||||||
|
|
||||||
|
void resetAll(const std::vector<MeshFrame*>& frames);
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32 framesCount;
|
||||||
|
u32 currentFrameSequenceIndex;
|
||||||
|
DynamicMeshAnimState state;
|
||||||
|
|
||||||
|
std::function<void(const AnimationSequenceCallback&)> callback;
|
||||||
|
std::vector<u32> sequence;
|
||||||
|
|
||||||
|
void updateLoopState(AnimationSequenceCallback* callbackInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true Frame changed
|
||||||
|
* @return false No changes
|
||||||
|
*/
|
||||||
|
bool updateNoLoopState(AnimationSequenceCallback* callbackInfo);
|
||||||
|
|
||||||
|
u32 getNextSequenceIndexFrom(const u32& index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Tyra
|
||||||
@@ -29,6 +29,9 @@ class Mesh {
|
|||||||
|
|
||||||
M4x4 translation, rotation, scale;
|
M4x4 translation, rotation, scale;
|
||||||
|
|
||||||
|
/** nullptr if not found */
|
||||||
|
MeshMaterial* getMaterialByName(const std::string& name);
|
||||||
|
|
||||||
std::vector<MeshMaterial*> materials;
|
std::vector<MeshMaterial*> materials;
|
||||||
|
|
||||||
M4x4 getModelMatrix() const;
|
M4x4 getModelMatrix() const;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class DynamicPipeline : public Renderer3DPipeline {
|
|||||||
|
|
||||||
DynPipColorBag* getColorBag(MeshMaterial* material) const;
|
DynPipColorBag* getColorBag(MeshMaterial* material) const;
|
||||||
|
|
||||||
DynPipTextureBag* getTextureBag(MeshMaterial* material,
|
DynPipTextureBag* getTextureBag(Texture* texture,
|
||||||
MeshMaterialFrame* materialFrameFrom,
|
MeshMaterialFrame* materialFrameFrom,
|
||||||
MeshMaterialFrame* materialFrameTo,
|
MeshMaterialFrame* materialFrameTo,
|
||||||
const u32& startIndex);
|
const u32& startIndex);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Texture {
|
|||||||
* Returns index of link.
|
* Returns index of link.
|
||||||
* -1 if not found.
|
* -1 if not found.
|
||||||
* @param t_id
|
* @param t_id
|
||||||
* For 3D: MeshMaterial material id.
|
* For 3D: MeshMaterial id.
|
||||||
* For 2D: Sprite id.
|
* For 2D: Sprite id.
|
||||||
*/
|
*/
|
||||||
const s32 getIndexOfLink(const u32& t_id) const;
|
const s32 getIndexOfLink(const u32& t_id) const;
|
||||||
@@ -68,11 +68,8 @@ class Texture {
|
|||||||
// Other
|
// Other
|
||||||
// ----
|
// ----
|
||||||
|
|
||||||
/** Assign texture to mesh and mesh material. */
|
/** Assign texture to Sprite.Id or MeshMaterial.Id. */
|
||||||
void addLink(const u32& t_meshId, const u32& t_materialId);
|
void addLink(const u32& t_id);
|
||||||
|
|
||||||
/** Assign texture to sprite. */
|
|
||||||
void addLink(const u32& t_spriteId);
|
|
||||||
|
|
||||||
u32 getTextureSize() const;
|
u32 getTextureSize() const;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licensed under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./engine.hpp"
|
||||||
|
#include "./debug/debug.hpp"
|
||||||
|
#include "./file/file_utils.hpp"
|
||||||
|
#include "./loaders/3d/md2_loader/md2_loader.hpp"
|
||||||
|
#include "./loaders/3d/obj_loader/obj_loader.hpp"
|
||||||
|
#include "./loaders/texture/png_loader.hpp"
|
||||||
|
#include "./packet2/packet2_tyra_utils.hpp"
|
||||||
|
#include "./physics/ray.hpp"
|
||||||
|
#include "./renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp"
|
||||||
|
#include "./renderer/3d/pipeline/static/static_pipeline.hpp"
|
||||||
|
#include "./renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp"
|
||||||
|
#include "./renderer/3d/mesh/dynamic/dynamic_mesh.hpp"
|
||||||
|
#include "./renderer/3d/mesh/static/static_mesh.hpp"
|
||||||
|
#include "./thread/threading.hpp"
|
||||||
|
#include "./time/timer.hpp"
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "math/math.hpp"
|
#include "math/math.hpp"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
extern volatile const u32 TYRA_MATH_ATAN_TABLE[9] alignas(sizeof(float)) = {
|
extern volatile const u32 TYRA_MATH_ATAN_TABLE[9] alignas(sizeof(float)) = {
|
||||||
0x3f7ffff5, 0xbeaaa61c, 0x3e4c40a6, 0xbe0e6c63, 0x3dc577df,
|
0x3f7ffff5, 0xbeaaa61c, 0x3e4c40a6, 0xbe0e6c63, 0x3dc577df,
|
||||||
@@ -91,7 +92,7 @@ float Math::cos(float x) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Math::invSqrt(float x) { return 1.0F / sqrt(x); }
|
float Math::invSqrt(const float& x) { return 1.0F / sqrt(x); }
|
||||||
|
|
||||||
float Math::atan2(float y, float x) {
|
float Math::atan2(float y, float x) {
|
||||||
float r;
|
float r;
|
||||||
@@ -185,6 +186,17 @@ float Math::atan2(float y, float x) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Math::randomf(const float& min, const float& max) {
|
||||||
|
float random = ((float)rand()) / (float)RAND_MAX;
|
||||||
|
float diff = max - min;
|
||||||
|
float r = random * diff;
|
||||||
|
return min + r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Math::randomi(const int& min, const int& max) {
|
||||||
|
return rand() % (max - min + 1) + min;
|
||||||
|
}
|
||||||
|
|
||||||
float Math::asin(float x) {
|
float Math::asin(float x) {
|
||||||
float r;
|
float r;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
@@ -248,7 +260,7 @@ bool Math::equalf(const float& a, const float& b, const float& epsilon) {
|
|||||||
return fabs(a - b) < epsilon;
|
return fabs(a - b) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Math::mod(float x, float y) {
|
float Math::mod(const float& x, const float& y) {
|
||||||
/*
|
/*
|
||||||
* Portable fmod(x,y) implementation for systems
|
* Portable fmod(x,y) implementation for systems
|
||||||
* that don't have it. Adapted from code found here:
|
* that don't have it. Adapted from code found here:
|
||||||
@@ -270,14 +282,14 @@ float Math::mod(float x, float y) {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Math::acos(float x) {
|
float Math::acos(const float& x) {
|
||||||
float y = sqrt(1.0f - x * x);
|
float y = sqrt(1.0f - x * x);
|
||||||
float t = atan2(y, x);
|
float t = atan2(y, x);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Math::sin(float x) { return cos(x - HALF_PI); }
|
float Math::sin(const float& x) { return cos(x - HALF_PI); }
|
||||||
|
|
||||||
float Math::tan(float x) { return sin(x) / cos(x); }
|
float Math::tan(const float& x) { return sin(x) / cos(x); }
|
||||||
|
|
||||||
} // namespace Tyra
|
} // namespace Tyra
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ DynamicMesh::DynamicMesh(const MeshBuilderData& data) : Mesh(data) {
|
|||||||
frames.push_back(new MeshFrame(data, i));
|
frames.push_back(new MeshFrame(data, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
initAnimation();
|
animation.resetAll(frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicMesh::DynamicMesh(const DynamicMesh& mesh) : Mesh(mesh) {
|
DynamicMesh::DynamicMesh(const DynamicMesh& mesh) : Mesh(mesh) {
|
||||||
@@ -34,7 +34,7 @@ DynamicMesh::DynamicMesh(const DynamicMesh& mesh) : Mesh(mesh) {
|
|||||||
frames.push_back(new MeshFrame(*mesh.frames[i]));
|
frames.push_back(new MeshFrame(*mesh.frames[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
initAnimation();
|
animation.resetAll(frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicMesh::~DynamicMesh() {
|
DynamicMesh::~DynamicMesh() {
|
||||||
@@ -43,71 +43,4 @@ DynamicMesh::~DynamicMesh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicMesh::initAnimation() {
|
|
||||||
animState.startFrame = 0;
|
|
||||||
animState.endFrame = 0;
|
|
||||||
animState.interpolation = 0.0F;
|
|
||||||
animState.animType = 0;
|
|
||||||
animState.currentFrame = 0;
|
|
||||||
animState.stayFrame = 0;
|
|
||||||
animState.isStayFrameSet = false;
|
|
||||||
animState.nextFrame = 0;
|
|
||||||
animState.speed = 0.1F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicMesh::playAnimation(const u32& t_frame) {
|
|
||||||
playAnimation(t_frame, t_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicMesh::playAnimation(const u32& t_startFrame,
|
|
||||||
const u32& t_endFrame) {
|
|
||||||
TYRA_ASSERT(frames.size() > 0,
|
|
||||||
"Cant play animation, because no mesh data was loaded!");
|
|
||||||
TYRA_ASSERT(frames.size() != 1,
|
|
||||||
"Cant play animation, because this mesh have only one frame.");
|
|
||||||
TYRA_ASSERT(
|
|
||||||
t_endFrame < frames.size(),
|
|
||||||
"End frame value is too high. Valid range: (0, getFramesCount()-1)");
|
|
||||||
animState.startFrame = t_startFrame;
|
|
||||||
animState.endFrame = t_endFrame;
|
|
||||||
if (animState.currentFrame == t_startFrame)
|
|
||||||
animState.nextFrame = t_endFrame;
|
|
||||||
else
|
|
||||||
animState.nextFrame = t_startFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicMesh::playAnimation(const u32& t_startFrame, const u32& t_endFrame,
|
|
||||||
const u32& t_stayFrame) {
|
|
||||||
TYRA_ASSERT(frames.size() > 0,
|
|
||||||
"Cant play animation, because no mesh data was loaded!");
|
|
||||||
TYRA_ASSERT(frames.size() != 1,
|
|
||||||
"Cant play animation, because this mesh have only one frame.");
|
|
||||||
TYRA_ASSERT(
|
|
||||||
t_endFrame < frames.size(),
|
|
||||||
"End frame value is too high. Valid range: (0, getFramesCount()-1)");
|
|
||||||
animState.startFrame = t_startFrame;
|
|
||||||
animState.endFrame = t_endFrame;
|
|
||||||
animState.isStayFrameSet = true;
|
|
||||||
animState.stayFrame = t_stayFrame;
|
|
||||||
animState.nextFrame = t_startFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DynamicMesh::animate() {
|
|
||||||
animState.interpolation += animState.speed;
|
|
||||||
if (animState.interpolation >= 1.0F) {
|
|
||||||
animState.interpolation = 0.0F;
|
|
||||||
animState.currentFrame = animState.nextFrame;
|
|
||||||
if (++animState.nextFrame > animState.endFrame) {
|
|
||||||
if (animState.isStayFrameSet) {
|
|
||||||
animState.isStayFrameSet = false;
|
|
||||||
animState.nextFrame = animState.stayFrame;
|
|
||||||
animState.startFrame = animState.stayFrame;
|
|
||||||
animState.endFrame = animState.stayFrame;
|
|
||||||
} else {
|
|
||||||
animState.nextFrame = animState.startFrame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Tyra
|
} // namespace Tyra
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
# _____ ____ ___
|
||||||
|
# | \/ ____| |___|
|
||||||
|
# | | | \ | |
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Copyright 2022, tyra - https://github.com/h4570/tyra
|
||||||
|
# Licensed under Apache License 2.0
|
||||||
|
# Sandro Sobczyński <sandro.sobczynski@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "math/m4x4.hpp"
|
||||||
|
#include "renderer/3d/mesh/dynamic/dynamic_mesh_animation.hpp"
|
||||||
|
#include "debug/debug.hpp"
|
||||||
|
|
||||||
|
namespace Tyra {
|
||||||
|
|
||||||
|
DynamicMeshAnimation::DynamicMeshAnimation() {
|
||||||
|
callback = nullptr;
|
||||||
|
currentFrameSequenceIndex = 0;
|
||||||
|
framesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMeshAnimation::~DynamicMeshAnimation() {}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::resetAll(const std::vector<MeshFrame*>& frames) {
|
||||||
|
framesCount = frames.size();
|
||||||
|
speed = 0.1F;
|
||||||
|
loop = true;
|
||||||
|
|
||||||
|
state.interpolation = 0.0F;
|
||||||
|
state.currentFrame = 0;
|
||||||
|
state.nextFrame = 0;
|
||||||
|
|
||||||
|
sequence.clear();
|
||||||
|
for (std::size_t i = 0; i < frames.size(); i++) {
|
||||||
|
sequence.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::setSequence(const std::vector<u32>& t_sequence) {
|
||||||
|
TYRA_ASSERT(framesCount != 1,
|
||||||
|
"Cant set sequence, because this mesh have only one frame.");
|
||||||
|
|
||||||
|
TYRA_ASSERT(sequence.size() > 0,
|
||||||
|
"Cant set sequence, because sequence is empty.");
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < t_sequence.size(); i++) {
|
||||||
|
TYRA_ASSERT(t_sequence[i] < framesCount && t_sequence[i] >= 0,
|
||||||
|
"Cant set sequence, because value: ", t_sequence[i],
|
||||||
|
" At index: ", i, " Is out of range!");
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence = t_sequence;
|
||||||
|
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
const DynamicMeshAnimState& DynamicMeshAnimation::getState() const {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::update() {
|
||||||
|
AnimationSequenceCallback callbackInfo =
|
||||||
|
AnimationSequenceCallback::AnimationSequenceCallback_NextFrame;
|
||||||
|
bool sendCallback = true;
|
||||||
|
|
||||||
|
state.interpolation += speed;
|
||||||
|
|
||||||
|
if (state.interpolation >= 1.0F) {
|
||||||
|
state.interpolation = 0.0F;
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
updateLoopState(&callbackInfo);
|
||||||
|
} else {
|
||||||
|
auto anythingChanged = updateNoLoopState(&callbackInfo);
|
||||||
|
if (!anythingChanged) {
|
||||||
|
sendCallback = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback != nullptr && sendCallback) callback(callbackInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::restart() {
|
||||||
|
currentFrameSequenceIndex = 0;
|
||||||
|
|
||||||
|
auto firstIndex = sequence[0];
|
||||||
|
auto secondIndex = sequence.size() > 1 ? sequence[1] : firstIndex;
|
||||||
|
|
||||||
|
state.currentFrame = sequence[firstIndex];
|
||||||
|
state.nextFrame = sequence[secondIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::updateLoopState(
|
||||||
|
AnimationSequenceCallback* callbackInfo) {
|
||||||
|
auto n1SequenceIndex = getNextSequenceIndexFrom(currentFrameSequenceIndex);
|
||||||
|
|
||||||
|
state.currentFrame = state.nextFrame;
|
||||||
|
|
||||||
|
auto isN1SequenceIndexEndOfSequence = n1SequenceIndex == sequence.size() - 1;
|
||||||
|
if (isN1SequenceIndexEndOfSequence) {
|
||||||
|
*callbackInfo = AnimationSequenceCallback::AnimationSequenceCallback_Loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.nextFrame = sequence[getNextSequenceIndexFrom(n1SequenceIndex)];
|
||||||
|
currentFrameSequenceIndex = n1SequenceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynamicMeshAnimation::updateNoLoopState(
|
||||||
|
AnimationSequenceCallback* callbackInfo) {
|
||||||
|
if (state.currentFrame == state.nextFrame) {
|
||||||
|
return false; // Animation is finished.
|
||||||
|
}
|
||||||
|
|
||||||
|
auto n1SequenceIndex = getNextSequenceIndexFrom(currentFrameSequenceIndex);
|
||||||
|
|
||||||
|
state.currentFrame = state.nextFrame;
|
||||||
|
|
||||||
|
auto isN1SequenceIndexEndOfSequence = n1SequenceIndex == sequence.size() - 1;
|
||||||
|
if (isN1SequenceIndexEndOfSequence) {
|
||||||
|
state.nextFrame = sequence[sequence.size() - 1];
|
||||||
|
*callbackInfo = AnimationSequenceCallback::AnimationSequenceCallback_End;
|
||||||
|
currentFrameSequenceIndex = sequence.size() - 1;
|
||||||
|
} else {
|
||||||
|
state.nextFrame = sequence[getNextSequenceIndexFrom(n1SequenceIndex)];
|
||||||
|
currentFrameSequenceIndex = n1SequenceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynamicMeshAnimation::getNextSequenceIndexFrom(const u32& index) const {
|
||||||
|
return index == sequence.size() - 1 ? 0 : index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMeshAnimation::setCallback(
|
||||||
|
const std::function<void(const AnimationSequenceCallback&)>& t_callback) {
|
||||||
|
callback = t_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tyra
|
||||||
@@ -46,6 +46,16 @@ Mesh::Mesh(const Mesh& mesh) {
|
|||||||
|
|
||||||
M4x4 Mesh::getModelMatrix() const { return translation * rotation * scale; }
|
M4x4 Mesh::getModelMatrix() const { return translation * rotation * scale; }
|
||||||
|
|
||||||
|
MeshMaterial* Mesh::getMaterialByName(const std::string& name) {
|
||||||
|
for (auto* material : materials) {
|
||||||
|
if (material->name == name) {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Mesh::~Mesh() {
|
Mesh::~Mesh() {
|
||||||
for (u32 i = 0; i < materials.size(); i++) {
|
for (u32 i = 0; i < materials.size(); i++) {
|
||||||
delete materials[i];
|
delete materials[i];
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
|
|||||||
PipelineDirLightsBag* dirLights = nullptr;
|
PipelineDirLightsBag* dirLights = nullptr;
|
||||||
|
|
||||||
if (options->frustumCulling == PipelineFrustumCulling_Simple) {
|
if (options->frustumCulling == PipelineFrustumCulling_Simple) {
|
||||||
auto* frameTo = mesh->frames[mesh->animState.nextFrame];
|
auto* frameTo = mesh->frames[mesh->animation.getState().nextFrame];
|
||||||
if (frameTo->bbox->isInFrustum(
|
if (frameTo->bbox->isInFrustum(
|
||||||
rendererCore->renderer3D.frustumPlanes.getAll(), model) ==
|
rendererCore->renderer3D.frustumPlanes.getAll(), model) ==
|
||||||
CoreBBoxFrustum::OUTSIDE_FRUSTUM) {
|
CoreBBoxFrustum::OUTSIDE_FRUSTUM) {
|
||||||
@@ -84,8 +84,8 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
|
|||||||
|
|
||||||
for (u32 i = 0; i < mesh->materials.size(); i++) {
|
for (u32 i = 0; i < mesh->materials.size(); i++) {
|
||||||
auto* material = mesh->materials[i];
|
auto* material = mesh->materials[i];
|
||||||
auto* frameFrom = material->frames[mesh->animState.currentFrame];
|
auto* frameFrom = material->frames[mesh->animation.getState().currentFrame];
|
||||||
auto* frameTo = material->frames[mesh->animState.nextFrame];
|
auto* frameTo = material->frames[mesh->animation.getState().nextFrame];
|
||||||
|
|
||||||
auto partSize = core.getMaxVertCountByParams(
|
auto partSize = core.getMaxVertCountByParams(
|
||||||
options && options->lighting, material->frames[0]->textureCoords);
|
options && options->lighting, material->frames[0]->textureCoords);
|
||||||
@@ -97,6 +97,13 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
|
|||||||
setBuffersColorBag(buffers, colorBag);
|
setBuffersColorBag(buffers, colorBag);
|
||||||
u8 isPartInitialized = false;
|
u8 isPartInitialized = false;
|
||||||
|
|
||||||
|
auto* texture =
|
||||||
|
rendererCore->texture.repository.getBySpriteOrMesh(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?");
|
||||||
|
|
||||||
for (u32 k = 0; k < partsCount; k++) {
|
for (u32 k = 0; k < partsCount; k++) {
|
||||||
auto& buffer = buffers[bufferIndex];
|
auto& buffer = buffers[bufferIndex];
|
||||||
|
|
||||||
@@ -107,7 +114,7 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
|
|||||||
u32 startIndex = k * partSize;
|
u32 startIndex = k * partSize;
|
||||||
|
|
||||||
addVertices(frameFrom, frameTo, &buffer, startIndex);
|
addVertices(frameFrom, frameTo, &buffer, startIndex);
|
||||||
buffer.texture = getTextureBag(material, frameFrom, frameTo, startIndex);
|
buffer.texture = getTextureBag(texture, frameFrom, frameTo, startIndex);
|
||||||
buffer.lighting = getLightingBag(frameFrom, frameTo, &model, options,
|
buffer.lighting = getLightingBag(frameFrom, frameTo, &model, options,
|
||||||
dirLights, startIndex);
|
dirLights, startIndex);
|
||||||
|
|
||||||
@@ -180,7 +187,7 @@ void DynamicPipeline::setBuffersDefaultVars(DynPipBag* buffers,
|
|||||||
DynPipInfoBag* infoBag) {
|
DynPipInfoBag* infoBag) {
|
||||||
for (u32 i = 0; i < buffersCount; i++) {
|
for (u32 i = 0; i < buffersCount; i++) {
|
||||||
buffers[i].info = infoBag;
|
buffers[i].info = infoBag;
|
||||||
buffers[i].interpolation = mesh->animState.interpolation;
|
buffers[i].interpolation = mesh->animation.getState().interpolation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,19 +241,13 @@ DynPipColorBag* DynamicPipeline::getColorBag(MeshMaterial* material) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DynPipTextureBag* DynamicPipeline::getTextureBag(
|
DynPipTextureBag* DynamicPipeline::getTextureBag(
|
||||||
MeshMaterial* material, MeshMaterialFrame* materialFrameFrom,
|
Texture* texture, MeshMaterialFrame* materialFrameFrom,
|
||||||
MeshMaterialFrame* materialFrameTo, const u32& startIndex) {
|
MeshMaterialFrame* materialFrameTo, const u32& startIndex) {
|
||||||
if (!materialFrameFrom->textureCoords) return nullptr;
|
if (!materialFrameFrom->textureCoords) return nullptr;
|
||||||
|
|
||||||
auto* result = new DynPipTextureBag();
|
auto* result = new DynPipTextureBag();
|
||||||
|
|
||||||
result->texture =
|
result->texture = texture;
|
||||||
rendererCore->texture.repository.getBySpriteOrMesh(material->id);
|
|
||||||
|
|
||||||
TYRA_ASSERT(
|
|
||||||
result->texture, "Texture for material: ", material->name,
|
|
||||||
"Id: ", material->id,
|
|
||||||
"Was not found in texture repository! Did you forget to add texture?");
|
|
||||||
|
|
||||||
result->coordinatesFrom = &materialFrameFrom->textureCoords[startIndex];
|
result->coordinatesFrom = &materialFrameFrom->textureCoords[startIndex];
|
||||||
result->coordinatesTo = &materialFrameTo->textureCoords[startIndex];
|
result->coordinatesTo = &materialFrameTo->textureCoords[startIndex];
|
||||||
|
|||||||
Reference in New Issue
Block a user