10 enemies in demo

This commit is contained in:
h4570
2022-08-12 23:40:26 +02:00
parent 2054dba4ec
commit 8829bf3035
23 changed files with 596 additions and 224 deletions
+7 -5
View File
@@ -27,11 +27,13 @@ class Math {
static float cos(float x);
static float asin(float x);
static float atan2(float y, float x);
static float mod(float x, float y);
static float acos(float x);
static float sin(float x);
static float tan(float x);
static float invSqrt(float x);
static float mod(const float& x, const float& y);
static float acos(const float& x);
static float sin(const float& x);
static float tan(const 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,
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
#include "../mesh_frame.hpp"
#include "../mesh_material_frame.hpp"
#include "./dynamic_mesh_anim_state.hpp"
#include "./dynamic_mesh_animation.hpp"
#include "../mesh.hpp"
namespace Tyra {
@@ -25,36 +24,15 @@ class DynamicMesh : public Mesh {
std::vector<MeshFrame*> frames;
DynamicMeshAnimState animState;
DynamicMeshAnimation animation;
/** @returns bounding box object of current frame. */
const BBox& getCurrentBoundingBox() const {
return *frames[animState.currentFrame]->bbox;
return *frames[animation.getState().currentFrame]->bbox;
}
/** Loop in one frame */
void playAnimation(const u32& t_frame);
/** 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();
/** Update animation */
inline void update() { animation.update(); }
};
} // namespace Tyra
@@ -15,16 +15,10 @@
namespace Tyra {
typedef struct {
u32 startFrame;
u32 endFrame;
u32 stayFrame;
u8 isStayFrameSet;
float speed;
struct DynamicMeshAnimState {
float interpolation;
u32 animType;
u32 currentFrame;
u32 nextFrame;
} DynamicMeshAnimState;
};
} // 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
+3
View File
@@ -29,6 +29,9 @@ class Mesh {
M4x4 translation, rotation, scale;
/** nullptr if not found */
MeshMaterial* getMaterialByName(const std::string& name);
std::vector<MeshMaterial*> materials;
M4x4 getModelMatrix() const;
@@ -66,7 +66,7 @@ class DynamicPipeline : public Renderer3DPipeline {
DynPipColorBag* getColorBag(MeshMaterial* material) const;
DynPipTextureBag* getTextureBag(MeshMaterial* material,
DynPipTextureBag* getTextureBag(Texture* texture,
MeshMaterialFrame* materialFrameFrom,
MeshMaterialFrame* materialFrameTo,
const u32& startIndex);
@@ -55,7 +55,7 @@ class Texture {
* Returns index of link.
* -1 if not found.
* @param t_id
* For 3D: MeshMaterial material id.
* For 3D: MeshMaterial id.
* For 2D: Sprite id.
*/
const s32 getIndexOfLink(const u32& t_id) const;
@@ -68,11 +68,8 @@ class Texture {
// Other
// ----
/** Assign texture to mesh and mesh material. */
void addLink(const u32& t_meshId, const u32& t_materialId);
/** Assign texture to sprite. */
void addLink(const u32& t_spriteId);
/** Assign texture to Sprite.Id or MeshMaterial.Id. */
void addLink(const u32& t_id);
u32 getTextureSize() const;
+27
View File
@@ -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"
+17 -5
View File
@@ -13,6 +13,7 @@
#endif
#include "math/math.hpp"
#include <stdlib.h>
extern volatile const u32 TYRA_MATH_ATAN_TABLE[9] alignas(sizeof(float)) = {
0x3f7ffff5, 0xbeaaa61c, 0x3e4c40a6, 0xbe0e6c63, 0x3dc577df,
@@ -91,7 +92,7 @@ float Math::cos(float x) {
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 r;
@@ -185,6 +186,17 @@ float Math::atan2(float y, float x) {
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 r;
asm volatile(
@@ -248,7 +260,7 @@ bool Math::equalf(const float& a, const float& b, const float& 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
* that don't have it. Adapted from code found here:
@@ -270,14 +282,14 @@ float Math::mod(float x, float y) {
return f;
}
float Math::acos(float x) {
float Math::acos(const float& x) {
float y = sqrt(1.0f - x * x);
float t = atan2(y, x);
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
@@ -26,7 +26,7 @@ DynamicMesh::DynamicMesh(const MeshBuilderData& data) : Mesh(data) {
frames.push_back(new MeshFrame(data, i));
}
initAnimation();
animation.resetAll(frames);
}
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]));
}
initAnimation();
animation.resetAll(frames);
}
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
@@ -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
+10
View File
@@ -46,6 +46,16 @@ Mesh::Mesh(const Mesh& mesh) {
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() {
for (u32 i = 0; i < materials.size(); i++) {
delete materials[i];
@@ -62,7 +62,7 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
PipelineDirLightsBag* dirLights = nullptr;
if (options->frustumCulling == PipelineFrustumCulling_Simple) {
auto* frameTo = mesh->frames[mesh->animState.nextFrame];
auto* frameTo = mesh->frames[mesh->animation.getState().nextFrame];
if (frameTo->bbox->isInFrustum(
rendererCore->renderer3D.frustumPlanes.getAll(), model) ==
CoreBBoxFrustum::OUTSIDE_FRUSTUM) {
@@ -84,8 +84,8 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
for (u32 i = 0; i < mesh->materials.size(); i++) {
auto* material = mesh->materials[i];
auto* frameFrom = material->frames[mesh->animState.currentFrame];
auto* frameTo = material->frames[mesh->animState.nextFrame];
auto* frameFrom = material->frames[mesh->animation.getState().currentFrame];
auto* frameTo = material->frames[mesh->animation.getState().nextFrame];
auto partSize = core.getMaxVertCountByParams(
options && options->lighting, material->frames[0]->textureCoords);
@@ -97,6 +97,13 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
setBuffersColorBag(buffers, colorBag);
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++) {
auto& buffer = buffers[bufferIndex];
@@ -107,7 +114,7 @@ void DynamicPipeline::render(DynamicMesh* mesh, const DynPipOptions* options) {
u32 startIndex = k * partSize;
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,
dirLights, startIndex);
@@ -180,7 +187,7 @@ void DynamicPipeline::setBuffersDefaultVars(DynPipBag* buffers,
DynPipInfoBag* infoBag) {
for (u32 i = 0; i < buffersCount; i++) {
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(
MeshMaterial* material, MeshMaterialFrame* materialFrameFrom,
Texture* texture, MeshMaterialFrame* materialFrameFrom,
MeshMaterialFrame* materialFrameTo, const u32& startIndex) {
if (!materialFrameFrom->textureCoords) return nullptr;
auto* result = new DynPipTextureBag();
result->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->texture = texture;
result->coordinatesFrom = &materialFrameFrom->textureCoords[startIndex];
result->coordinatesTo = &materialFrameTo->textureCoords[startIndex];