add miniaudio; add tilesheet; add audio test
This commit is contained in:
parent
d683587d58
commit
d1fbdb1898
|
@ -11,8 +11,10 @@ set(ENGINE_NAME tinyengine)
|
|||
|
||||
aux_source_directory(src/tinyengine ENGINE_SRC)
|
||||
aux_source_directory(src/component ENGINE_SRC)
|
||||
aux_source_directory(src/tinyengine/ecs ENGINE_SRC)
|
||||
aux_source_directory(libs/glad/src ENGINE_SRC)
|
||||
aux_source_directory(libs/stb_image ENGINE_SRC)
|
||||
aux_source_directory(libs/miniaudio/ ENGINE_SRC)
|
||||
|
||||
add_library(${ENGINE_NAME} STATIC ${ENGINE_SRC})
|
||||
|
||||
|
@ -24,7 +26,7 @@ add_subdirectory(libs/glfw)
|
|||
target_include_directories(
|
||||
${ENGINE_NAME}
|
||||
PRIVATE include/tinyengine
|
||||
PUBLIC libs/glad/include libs/stb_image # /usr/local/Cellar/glm/0.9.9.8/include
|
||||
PUBLIC libs/glad/include libs/stb_image libs/miniaudio # /usr/local/Cellar/glm/0.9.9.8/include
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
|
@ -51,6 +53,7 @@ target_compile_options(
|
|||
# space sector
|
||||
################
|
||||
aux_source_directory(src/game GAME_SRC)
|
||||
aux_source_directory(src/game/stages GAME_SRC)
|
||||
add_executable(${PROJECT_NAME} ${GAME_SRC})
|
||||
|
||||
target_include_directories(
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 481 B |
Binary file not shown.
After Width: | Height: | Size: 889 B |
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include "tinyengine/tinyengine.hpp"
|
||||
|
||||
class GameLogoScence final: public Scence {
|
||||
public:
|
||||
void OnInit() override;
|
||||
void OnRender() override;
|
||||
|
||||
private:
|
||||
Camera camera;
|
||||
float initTime_;
|
||||
Unique<Sound> sound_;
|
||||
bool soundPlayed_;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "tool.hpp"
|
||||
#include "log.hpp"
|
||||
#include "libmath.hpp"
|
||||
|
||||
class Audio final {
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
};
|
||||
|
||||
class Sound final {
|
||||
public:
|
||||
Sound(const std::string& filename);
|
||||
~Sound();
|
||||
|
||||
void Play();
|
||||
void Pause();
|
||||
void Stop();
|
||||
void SetVolume(float volume);
|
||||
void EnableLoop();
|
||||
void DisableLoop();
|
||||
|
||||
private:
|
||||
ma_sound sound_;
|
||||
};
|
|
@ -13,7 +13,7 @@ public:
|
|||
|
||||
private:
|
||||
Mat44 viewMat_;
|
||||
Point position_;
|
||||
Point scale_;
|
||||
Point position_ = {0, 0};
|
||||
Point scale_ = {1, 1};
|
||||
bool dirty_ = false;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
_Pragma("once")
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "pool.hpp"
|
||||
|
||||
using ComponentId = unsigned int;
|
||||
|
||||
class Component {
|
||||
public:
|
||||
friend class Pool<Component>;
|
||||
|
||||
virtual ~Component() = default;
|
||||
inline bool IsAlive() const { return alive_; }
|
||||
virtual void Release() = 0;
|
||||
|
||||
private:
|
||||
bool alive_;
|
||||
};
|
||||
|
||||
class ComponentIdx final {
|
||||
public:
|
||||
template <typename T>
|
||||
static ComponentId Get() {
|
||||
static_assert(std::is_base_of_v<Component, T> && !std::is_same_v<Component, T>);
|
||||
static ComponentId id = count_ ++;
|
||||
return id;
|
||||
}
|
||||
|
||||
inline static ComponentId GetCount() { return count_; }
|
||||
|
||||
private:
|
||||
static ComponentId count_;
|
||||
};
|
||||
|
||||
struct ComponentPool{
|
||||
};
|
||||
|
||||
extern std::unordered_map<ComponentId, Pool<Component>> gComponentPool;
|
|
@ -0,0 +1,46 @@
|
|||
_Pragma("once")
|
||||
|
||||
#include "pool.hpp"
|
||||
#include "component.hpp"
|
||||
|
||||
class Entity;
|
||||
|
||||
class Context final {
|
||||
public:
|
||||
friend class Entity;
|
||||
Entity* CreateEntity();
|
||||
|
||||
bool HasEntity(Entity* entity);
|
||||
Pool<Entity>::ElemContainer& GetEntities();
|
||||
void DestroyEntity(Entity* entity);
|
||||
int GetEntityNum() const;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T* CreateComponent(Args... args) {
|
||||
ComponentId id = ComponentIdx::Get<T>();
|
||||
auto it = gComponentPool.find(id);
|
||||
if (it != gComponentPool.end()) {
|
||||
return it->second.Create<T>(args...);
|
||||
} else {
|
||||
gComponentPool[id] = Pool<Component>();
|
||||
return gComponentPool[id].Create<T>(args...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DestroyComponent(T* elem) {
|
||||
DestroyComponentById(elem, ComponentIdx::Get<T>());
|
||||
}
|
||||
|
||||
inline void DestroyComponentById(Component* elem, int id) {
|
||||
auto it = gComponentPool.find(id);
|
||||
if (it != gComponentPool.end()) {
|
||||
gComponentPool[id].Destroy(elem);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Pool<Entity> entities_;
|
||||
|
||||
void onComponentUpdate(Entity*, ComponentId, Component*);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
_Pragma("once")
|
||||
|
||||
#include "entity.hpp"
|
||||
#include "component.hpp"
|
||||
#include "context.hpp"
|
|
@ -0,0 +1,135 @@
|
|||
_Pragma("once")
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "pool.hpp"
|
||||
#include "component.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
class Entity final {
|
||||
public:
|
||||
friend class Pool<Entity>;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void Add(Args... args) {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Add(): entity is die, can't add component." << std::endl;
|
||||
} else {
|
||||
T* comp = context_->CreateComponent<T>(args...);
|
||||
components_[ComponentIdx::Get<T>()] = comp;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Init(Context* context) {
|
||||
context_ = context;
|
||||
}
|
||||
inline void Release() {
|
||||
components_.clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* Get() const {
|
||||
if constexpr (!std::is_base_of_v<Component, T>) {
|
||||
std::cout << "Entity::Get() const: the type T is not inherit from Component" << std::endl;
|
||||
return nullptr;
|
||||
} else {
|
||||
return (T*)Get(ComponentIdx::Get<T>());
|
||||
}
|
||||
}
|
||||
|
||||
Component* Get(ComponentId id) const {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Get(id) const: entity is die, can't get anything from it." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
auto it = components_.find(id);
|
||||
if (it == components_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Use() {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Use() const: entity is die, can't get anything from it." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
auto it = components_.find(ComponentIdx::Get<T>());
|
||||
if (it == components_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return (T*)it->second;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void Replace(Args... args) {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Replace() const: entity is die, can't replace component." << std::endl;
|
||||
} else {
|
||||
auto it = components_.find(ComponentIdx::Get<T>());
|
||||
if (it != components_.end()) {
|
||||
T* c = (T*)it->second;
|
||||
c->Init(args...);
|
||||
} else {
|
||||
Add<T>(args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Remove() {
|
||||
Remove(ComponentIdx::Get<T>());
|
||||
}
|
||||
|
||||
inline void Remove(ComponentId id) {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Remove() const: entity is die, can't remove anything from it." << std::endl;
|
||||
} else {
|
||||
auto it = components_.find(id);
|
||||
if (it != components_.end()) {
|
||||
context_->DestroyComponentById(it->second, id);
|
||||
components_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ... Types>
|
||||
bool Has() const {
|
||||
if (!alive_) {
|
||||
std::cout << "Entity::Has() const: entity is die, can't query." << std::endl;
|
||||
return false;
|
||||
}
|
||||
return hasIter<Types ...>();
|
||||
}
|
||||
|
||||
inline bool Has(ComponentId id) const {
|
||||
return components_.find(id) != components_.end();
|
||||
}
|
||||
|
||||
inline void Reset() {
|
||||
for (ComponentId i = 0; i < ComponentIdx::GetCount(); i++) {
|
||||
auto it = components_.find(i);
|
||||
if (it != components_.end()) {
|
||||
components_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsAlive() const { return alive_; }
|
||||
|
||||
private:
|
||||
std::unordered_map<ComponentId, Component*> components_;
|
||||
bool alive_;
|
||||
Context* context_ = nullptr;
|
||||
|
||||
template <typename T, typename ... Types>
|
||||
bool hasIter() const {
|
||||
if constexpr (sizeof...(Types) == 0) {
|
||||
return Get<T>();
|
||||
} else {
|
||||
return Get<T>() && hasIter<Types ...>();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -6,6 +6,7 @@
|
|||
#include "inner_bmpfont.hpp"
|
||||
#include "event.hpp"
|
||||
#include "tool.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
class Engine final {
|
||||
public:
|
||||
|
|
|
@ -143,3 +143,20 @@ inline Mat44 CreateOrthoMat(float left, float right,
|
|||
0, 0, 0, 1,
|
||||
});
|
||||
}
|
||||
|
||||
inline Point GetCenterAlign(const Rect& parent, const Size& child) {
|
||||
return Point{parent.x + (parent.w - child.w) / 2.0f,
|
||||
parent.y + (parent.h - child.h) / 2.0f};
|
||||
}
|
||||
|
||||
inline Mat44 CreateSRT(const Point& pos, const Point& scale, float degree) {
|
||||
float theta = Radians(degree);
|
||||
float sinTheta = std::sin(theta),
|
||||
cosTheta = std::cos(theta);
|
||||
return Mat44({
|
||||
scale.x * cosTheta, scale.y * sinTheta, 0, pos.x,
|
||||
-scale.x * sinTheta, scale.y * cosTheta, 0, pos.y,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <limits>
|
||||
#include <cassert>
|
||||
|
||||
#include "miniaudio.h"
|
||||
|
||||
#ifdef USE_GLM
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
_Pragma("once")
|
||||
|
||||
#include "pch.hpp"
|
||||
|
||||
/*
|
||||
* Memory Pool.
|
||||
* To use this pool, your class must have:
|
||||
* * `bool alive_` member
|
||||
* * let Pool be it's friend class
|
||||
* * `void Init(...)` function to init your object
|
||||
* * `void Release()` function to release your object
|
||||
*/
|
||||
template <typename T>
|
||||
class Pool {
|
||||
public:
|
||||
using ElemContainer = std::vector<T*>;
|
||||
|
||||
Pool(size_t capacity = 20) {
|
||||
datas_.reserve(capacity);
|
||||
}
|
||||
~Pool() {
|
||||
for (size_t i = 0; i < datas_.size(); i++)
|
||||
delete datas_[i];
|
||||
while (!cache_.empty()) {
|
||||
delete cache_.top();
|
||||
cache_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U = T, typename... Args>
|
||||
U* Create(Args... args) {
|
||||
static_assert(std::is_base_of_v<T, U>);
|
||||
if (GetReuseableNum() > 0) {
|
||||
U* elem = (U*)cache_.top();
|
||||
elem->Init(args ...);
|
||||
elem->alive_ = true;
|
||||
cache_.pop();
|
||||
datas_.push_back(elem);
|
||||
return elem;
|
||||
} else {
|
||||
U* elem = new U;
|
||||
datas_.push_back(elem);
|
||||
elem->Init(args ...);
|
||||
elem->alive_ = true;
|
||||
return (U*)datas_.back();
|
||||
}
|
||||
}
|
||||
|
||||
void Destroy(T* elem) {
|
||||
auto it = std::find(datas_.begin(),
|
||||
datas_.end(),
|
||||
elem);
|
||||
if (it != datas_.end()) {
|
||||
(*it)->alive_ = false;
|
||||
(*it)->Release();
|
||||
cache_.push(*it);
|
||||
datas_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<T*>& GetElems() { return datas_; }
|
||||
|
||||
int GetNum() const { return datas_.size(); }
|
||||
int GetReuseableNum() const { return cache_.size(); }
|
||||
|
||||
private:
|
||||
ElemContainer datas_;
|
||||
std::stack<T*> cache_;
|
||||
};
|
|
@ -5,9 +5,22 @@
|
|||
#include "glhelpfunc.hpp"
|
||||
#include "shader.hpp"
|
||||
#include "camera.hpp"
|
||||
#include "tilesheet.hpp"
|
||||
|
||||
struct Vertex {
|
||||
Point pos;
|
||||
Point texcoord;
|
||||
};
|
||||
|
||||
class Renderer final {
|
||||
public:
|
||||
enum FlipFlag {
|
||||
NoFlip = 0,
|
||||
Vertical = 0x01,
|
||||
Horizontal = 0x02,
|
||||
Both = 0x03,
|
||||
};
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
static void SetClearColor(const Color&);
|
||||
|
@ -16,7 +29,21 @@ public:
|
|||
static void DrawLine(const Point& p1, const Point& p2);
|
||||
static void DrawRect(const Rect& rect);
|
||||
static void FillRect(const Rect& rect);
|
||||
static void DrawTexture(const Texture& texture, const Mat44& transform, const Color& color = Color{1, 1, 1, 1});
|
||||
static void DrawTile(const Tile& tile,
|
||||
const Point& pos,
|
||||
const Size& size = {0, 0},
|
||||
float degree = 0,
|
||||
FlipFlag flip = NoFlip);
|
||||
static void DrawTexture(const Texture* texture,
|
||||
const Rect* srcrect,
|
||||
const Point& pos,
|
||||
const Size& size = Size{0, 0},
|
||||
float degree = 0,
|
||||
FlipFlag flip = NoFlip);
|
||||
static void DrawTexture(const Texture* texture,
|
||||
const Rect* rect,
|
||||
const Mat44& transform,
|
||||
const Color& color = Color{1, 1, 1, 1});
|
||||
static void SetViewport(int x, int y, int w, int h);
|
||||
static const Color& GetDrawColor();
|
||||
static void SetCamera(Camera& camera);
|
||||
|
@ -24,4 +51,9 @@ public:
|
|||
|
||||
private:
|
||||
static Color color_;
|
||||
|
||||
static void drawRectFrag(const Texture* texture,
|
||||
const std::array<Vertex, 6>& vertices,
|
||||
const Mat44& transform,
|
||||
const Color& color);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "texture.hpp"
|
||||
|
||||
struct Tile {
|
||||
Texture* texture;
|
||||
Rect rect;
|
||||
Size size;
|
||||
};
|
||||
|
||||
class TileSheet final {
|
||||
public:
|
||||
TileSheet(const std::string& filename, int x, int y);
|
||||
|
||||
const Tile GetTile(int x, int y);
|
||||
Texture* GetTexture() { return texture_.get(); }
|
||||
|
||||
private:
|
||||
Unique<Texture> texture_;
|
||||
Size size_;
|
||||
};
|
|
@ -9,3 +9,5 @@
|
|||
#include "texture.hpp"
|
||||
#include "tool.hpp"
|
||||
#include "inner_bmpfont.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "tilesheet.hpp"
|
||||
|
|
|
@ -13,3 +13,7 @@ using Ref = std::shared_ptr<T>;
|
|||
#else
|
||||
#define FATAL_ERROR(msg)
|
||||
#endif
|
||||
|
||||
inline float GetTime() {
|
||||
return glfwGetTime();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef GAME_DEBUG
|
||||
#define MA_DEBUG_OUTPUT
|
||||
#endif
|
||||
|
||||
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
|
||||
#define MA_ENABLE_COREAUDIO
|
||||
#define MA_NO_FLAC
|
||||
#define MA_NO_MP3
|
||||
#define MA_NO_ENCODING
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "miniaudio.h"
|
File diff suppressed because it is too large
Load Diff
1
pack.sh
1
pack.sh
|
@ -7,3 +7,4 @@ fi
|
|||
mkdir output
|
||||
cp ./build/SpaceSector output
|
||||
cp -r ./assets output
|
||||
rm -rf ./output/assets/test
|
||||
|
|
|
@ -1,24 +1,3 @@
|
|||
#include "tinyengine/engine.hpp"
|
||||
#include "tinyengine/event.hpp"
|
||||
#include "tinyengine/camera.hpp"
|
||||
#include "game/stages/gamelogo.hpp"
|
||||
|
||||
class WelcomeScene final: public Scence {
|
||||
public:
|
||||
void OnInit() override {
|
||||
Log("init scence");
|
||||
camera.Move(Point{0, 0});
|
||||
camera.Scale(Point{1, 1});
|
||||
}
|
||||
|
||||
void OnUpdate(float dt) override {
|
||||
}
|
||||
|
||||
void OnQuit() override {
|
||||
Log("quit scence");
|
||||
}
|
||||
|
||||
private:
|
||||
Camera camera;
|
||||
};
|
||||
|
||||
RUN_WINDOW("Space Sector", 1024, 720, WelcomeScene)
|
||||
RUN_WINDOW("Space Sector", 1024, 720, GameLogoScence)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#include "game/stages/gamelogo.hpp"
|
||||
|
||||
constexpr float TitlePixel = 40.0f;
|
||||
constexpr float AuthorInfoPixel = 20.0f;
|
||||
const char* Title = "1M GAMES DEV";
|
||||
const char* AuthorInfo = "MADE BY VISUALGMQ";
|
||||
|
||||
void GameLogoScence::OnInit() {
|
||||
Renderer::SetClearColor(Color{0, 0, 0, 255});
|
||||
initTime_ = GetTime();
|
||||
sound_.reset(new Sound("assets/1mgame_sound.wav"));
|
||||
soundPlayed_ = false;
|
||||
}
|
||||
|
||||
void GameLogoScence::OnRender() {
|
||||
float duration = GetTime() - initTime_;
|
||||
if (duration > 2 && !soundPlayed_) {
|
||||
sound_->Play();
|
||||
soundPlayed_ = true;
|
||||
}
|
||||
if (duration < 3) {
|
||||
engine.GetInnerBmpFont().Render(Title,
|
||||
TitlePixel,
|
||||
Point{0, -25} +
|
||||
GetCenterAlign(Rect{0, 0,
|
||||
engine.GetWindowSize().w,
|
||||
engine.GetWindowSize().h},
|
||||
Size{TitlePixel * strlen(Title), TitlePixel}),
|
||||
Color{1, 1, 1, 1});
|
||||
engine.GetInnerBmpFont().Render(AuthorInfo,
|
||||
AuthorInfoPixel,
|
||||
Point{0, 25} +
|
||||
GetCenterAlign(Rect{0, 0,
|
||||
engine.GetWindowSize().w,
|
||||
engine.GetWindowSize().h},
|
||||
Size{AuthorInfoPixel * strlen(AuthorInfo), AuthorInfoPixel}),
|
||||
Color{0.5, 0.5, 0.5, 1});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#include "audio.hpp"
|
||||
|
||||
ma_engine AudioEngine;
|
||||
|
||||
void Audio::Init() {
|
||||
ma_result result;
|
||||
result = ma_engine_init(NULL, &AudioEngine);
|
||||
if (result != MA_SUCCESS) {
|
||||
FATAL_ERROR("sound system init failed");
|
||||
}
|
||||
ma_engine_start(&AudioEngine);
|
||||
}
|
||||
|
||||
void Audio::Shutdown() {
|
||||
ma_engine_stop(&AudioEngine);
|
||||
}
|
||||
|
||||
Sound::Sound(const std::string& filename) {
|
||||
ma_result result;
|
||||
result = ma_sound_init_from_file(&AudioEngine,
|
||||
filename.c_str(),
|
||||
0,
|
||||
NULL, NULL,
|
||||
&sound_);
|
||||
if (result != MA_SUCCESS) {
|
||||
Log("%s sound load failed!", filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::Play() {
|
||||
ma_sound_start(&sound_);
|
||||
}
|
||||
|
||||
void Sound::Pause() {
|
||||
}
|
||||
|
||||
void Sound::Stop() {
|
||||
ma_sound_stop(&sound_);
|
||||
}
|
||||
|
||||
Sound::~Sound() {
|
||||
ma_sound_uninit(&sound_);
|
||||
}
|
||||
|
||||
void Sound::SetVolume(float volume) {
|
||||
ma_sound_set_volume(&sound_, Clamp(0.0f, 10.0f, volume));
|
||||
}
|
||||
|
||||
void Sound::EnableLoop() {
|
||||
ma_sound_set_looping(&sound_, true);
|
||||
}
|
||||
|
||||
void Sound::DisableLoop() {
|
||||
ma_sound_set_looping(&sound_, false);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include "ecs/component.hpp"
|
||||
#include "ecs/context.hpp"
|
||||
|
||||
ComponentId ComponentIdx::count_ = 0;
|
||||
|
||||
std::unordered_map<ComponentId, Pool<Component>> gComponentPool;
|
|
@ -0,0 +1,29 @@
|
|||
#include "ecs/context.hpp"
|
||||
#include "ecs/entity.hpp"
|
||||
|
||||
Pool<Entity>::ElemContainer& Context::GetEntities() {
|
||||
return entities_.GetElems();
|
||||
}
|
||||
|
||||
void Context::DestroyEntity(Entity* entity) {
|
||||
for (size_t i = 0; i < ComponentIdx::GetCount(); i++) {
|
||||
if (entity->Has(i)) {
|
||||
DestroyComponentById(entity->Get(i), i);
|
||||
}
|
||||
}
|
||||
entities_.Destroy(entity);
|
||||
}
|
||||
|
||||
int Context::GetEntityNum() const {
|
||||
return entities_.GetNum();
|
||||
}
|
||||
|
||||
bool Context::HasEntity(Entity* entity) {
|
||||
auto& entities = entities_.GetElems();
|
||||
return std::find(entities.begin(), entities.end(), entity) !=
|
||||
entities.end();
|
||||
}
|
||||
|
||||
Entity* Context::CreateEntity() {
|
||||
return entities_.Create(this);
|
||||
}
|
|
@ -39,7 +39,11 @@ void Engine::Init(const std::string& title, const Size& size, Scence* scence) {
|
|||
Renderer::SetViewport(0, 0, width, height);
|
||||
|
||||
Renderer::Init();
|
||||
Log("render system init OK");
|
||||
Renderer::SetClearColor(Color{0.1, 0.1, 0.1, 1});
|
||||
|
||||
Audio::Init();
|
||||
Log("sound system init OK");
|
||||
|
||||
scence_.reset(scence);
|
||||
scence_->OnInit();
|
||||
|
@ -75,6 +79,7 @@ void Engine::PollEvent() {
|
|||
}
|
||||
|
||||
void Engine::Shutdown() {
|
||||
Audio::Shutdown();
|
||||
if (scence_)
|
||||
scence_->OnQuit();
|
||||
glfwDestroyWindow(window_);
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
#include "renderer.hpp"
|
||||
#include "libmath.hpp"
|
||||
#include "engine.hpp"
|
||||
|
||||
Color Renderer::color_ = {255, 255, 255, 255};
|
||||
|
||||
struct Vertex {
|
||||
float x;
|
||||
float y;
|
||||
float texCoordX;
|
||||
float texCoordY;
|
||||
};
|
||||
|
||||
struct {
|
||||
GLuint vbo;
|
||||
GLuint vao;
|
||||
|
@ -20,16 +12,15 @@ struct {
|
|||
Unique<Texture> WhiteTexture;
|
||||
Camera* camera = nullptr;
|
||||
|
||||
Vertex rectVertices[6] = {
|
||||
{0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{1.0f, 0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, 0.0f, 0.0f},
|
||||
const std::array<Vertex, 6> vertices = {
|
||||
Vertex{-0.5f, 0.5f, 0.0f, 1.0f},
|
||||
Vertex{ 0.5f,-0.5f, 1.0f, 0.0f},
|
||||
Vertex{-0.5f,-0.5f, 0.0f, 0.0f},
|
||||
|
||||
{0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
{1.0f, 0.0f, 1.0f, 0.0f}
|
||||
Vertex{-0.5f, 0.5f, 0.0f, 1.0f},
|
||||
Vertex{ 0.5f, 0.5f, 1.0f, 1.0f},
|
||||
Vertex{ 0.5f,-0.5f, 1.0f, 0.0f}
|
||||
};
|
||||
|
||||
} Context;
|
||||
|
||||
void createWhiteTexture() {
|
||||
|
@ -86,6 +77,8 @@ void setShaderOrtho() {
|
|||
}
|
||||
|
||||
void Renderer::Init() {
|
||||
GL_CALL(glEnable(GL_BLEND));
|
||||
GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
createWhiteTexture();
|
||||
initRenderContext();
|
||||
initShader("assets/shaders/vertex.shader",
|
||||
|
@ -128,41 +121,93 @@ void Renderer::DrawRect(const Rect& rect) {
|
|||
}
|
||||
|
||||
void Renderer::FillRect(const Rect& rect) {
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, Context.vbo));
|
||||
GL_CALL(glBindVertexArray(Context.vao));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER,
|
||||
sizeof(Context.rectVertices),
|
||||
Context.rectVertices,
|
||||
GL_STATIC_DRAW));
|
||||
Context.shader->Use();
|
||||
Context.WhiteTexture->Bind();
|
||||
Context.shader->SetMat4("model", Mat44({
|
||||
rect.w, 0, 0, rect.x,
|
||||
0, rect.h, 0, rect.y,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
}));
|
||||
Context.shader->SetInt("Texture", 0);
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 6));
|
||||
drawRectFrag(nullptr,
|
||||
Context.vertices,
|
||||
CreateSRT(Point{rect.x + rect.w / 2, rect.y + rect.h / 2},
|
||||
Point{rect.w, rect.h},
|
||||
0),
|
||||
Renderer::color_);
|
||||
}
|
||||
|
||||
void Renderer::DrawTexture(const Texture& texture,
|
||||
void Renderer::DrawTile(const Tile& tile,
|
||||
const Point& pos,
|
||||
const Size& size,
|
||||
float degree,
|
||||
Renderer::FlipFlag flip) {
|
||||
if (size.w == 0 && size.h == 0) {
|
||||
DrawTexture(tile.texture, &tile.rect, pos, tile.size, degree, flip);
|
||||
} else {
|
||||
DrawTexture(tile.texture, &tile.rect, pos, size, degree, flip);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawTexture(const Texture* texture,
|
||||
const Rect* srcrect,
|
||||
const Point& pos,
|
||||
const Size& size,
|
||||
float degree,
|
||||
FlipFlag flip) {
|
||||
if (texture) {
|
||||
auto scale = size;
|
||||
if (size.w == 0 && size.h == 0) {
|
||||
scale = texture->GetSize();
|
||||
}
|
||||
if (flip & Vertical) {
|
||||
scale.h *= -1;
|
||||
}
|
||||
if (flip & Horizontal) {
|
||||
scale.w *= -1;
|
||||
}
|
||||
DrawTexture(texture, srcrect, CreateSRT(pos, scale, degree));
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawTexture(const Texture* texture,
|
||||
const Rect* rect,
|
||||
const Mat44& transform,
|
||||
const Color& color) {
|
||||
if (!texture) return;
|
||||
auto& size = texture->GetSize();
|
||||
if (!rect) {
|
||||
drawRectFrag(texture, Context.vertices, transform, color);
|
||||
} else {
|
||||
auto vertices = Context.vertices;
|
||||
vertices[0].texcoord = Point{rect->x / size.w,
|
||||
(rect->y + rect->h) / size.h};
|
||||
vertices[1].texcoord = Point{(rect->x + rect->w) / size.w,
|
||||
rect->y / size.h};
|
||||
vertices[2].texcoord = Point{rect->x / size.w, rect->y / size.h};
|
||||
vertices[3].texcoord = vertices[0].texcoord;
|
||||
vertices[4].texcoord = Point{(rect->x + rect->w) / size.w,
|
||||
(rect->y + rect->h) / size.h};
|
||||
vertices[5].texcoord = vertices[1].texcoord;
|
||||
drawRectFrag(texture, vertices, transform, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::drawRectFrag(const Texture* texture,
|
||||
const std::array<Vertex, 6>& vertices,
|
||||
const Mat44& transform,
|
||||
const Color& color) {
|
||||
Context.shader->Use();
|
||||
Context.shader->SetInt("Texture", 0);
|
||||
texture.Bind(0);
|
||||
if (texture) {
|
||||
texture->Bind(0);
|
||||
} else {
|
||||
Context.WhiteTexture->Bind(0);
|
||||
}
|
||||
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, Context.vbo));
|
||||
GL_CALL(glBindVertexArray(Context.vao));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER,
|
||||
sizeof(Context.rectVertices),
|
||||
Context.rectVertices,
|
||||
sizeof(Vertex) * vertices.size(),
|
||||
vertices.data(),
|
||||
GL_STATIC_DRAW));
|
||||
|
||||
Renderer::SetDrawColor(color);
|
||||
Context.shader->SetMat4("model", transform);
|
||||
GL_CALL(glDrawArrays(GL_TRIANGLES, 0, 6));
|
||||
|
||||
}
|
||||
|
||||
void Renderer::Clear() {
|
||||
|
|
|
@ -3,17 +3,22 @@
|
|||
Texture::Texture(const std::string& filename) {
|
||||
int w, h, channels;
|
||||
unsigned char* data = stbi_load(filename.c_str(), &w, &h, &channels, 0);
|
||||
if (channels == 4) {
|
||||
format_ = GL_RGBA;
|
||||
}else if (channels == 3) {
|
||||
format_ = GL_RGB;
|
||||
if (!data) {
|
||||
Log("%s load failed!", filename.c_str());
|
||||
texture_ = 0;
|
||||
} else {
|
||||
if (channels == 4) {
|
||||
format_ = GL_RGBA;
|
||||
}else if (channels == 3) {
|
||||
format_ = GL_RGB;
|
||||
}
|
||||
size_.x = w;
|
||||
size_.y = h;
|
||||
|
||||
createFromPixels(data, w, h, format_);
|
||||
|
||||
stbi_image_free(data);
|
||||
}
|
||||
size_.x = w;
|
||||
size_.y = h;
|
||||
|
||||
createFromPixels(data, w, h, format_);
|
||||
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
Texture::Texture(const unsigned char* data, int w, int h, GLenum format) {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#include "tilesheet.hpp"
|
||||
|
||||
TileSheet::TileSheet(const std::string& filename, int x, int y) {
|
||||
texture_.reset(new Texture(filename));
|
||||
size_.x = x;
|
||||
size_.y = y;
|
||||
}
|
||||
|
||||
const Tile TileSheet::GetTile(int x, int y) {
|
||||
Size size = texture_->GetSize() / size_;
|
||||
return {texture_.get(),
|
||||
Rect{size.w * x, size.h * y, size.w, size.h},
|
||||
size};
|
||||
}
|
|
@ -9,3 +9,4 @@ endmacro()
|
|||
AddTest(math math.cpp ${ENGINE_NAME})
|
||||
AddTest(renderer renderer.cpp ${ENGINE_NAME})
|
||||
AddTest(innerBmpFont innerBmpFont.cpp ${ENGINE_NAME})
|
||||
AddTest(audio audio.cpp ${ENGINE_NAME})
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#include "tinyengine/tinyengine.hpp"
|
||||
|
||||
class TestAudio : public Scence {
|
||||
public:
|
||||
void OnInit() override {
|
||||
sound_.reset(new Sound("assets/test/goodbyESAKA.wav"));
|
||||
sound_->SetVolume(10);
|
||||
sound_->Play();
|
||||
}
|
||||
|
||||
void OnRender() override {
|
||||
}
|
||||
|
||||
void OnQuit() override {
|
||||
sound_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
Unique<Sound> sound_;
|
||||
};
|
||||
|
||||
RUN_WINDOW("test renderer", 1024, 720, TestAudio)
|
|
@ -5,7 +5,16 @@ class TestRenderer: public Scence {
|
|||
public:
|
||||
void OnInit() override {
|
||||
dirt_.reset(new Texture("assets/test/dirt.png"));
|
||||
start_.reset(new Texture("assets/test/start.bmp"));
|
||||
start_.reset(new Texture("assets/test/start.png"));
|
||||
tilesheet_.reset(new TileSheet("assets/test/tilesheet.png", 8, 1));
|
||||
degree_ = 0;
|
||||
}
|
||||
|
||||
void OnUpdate(float second) override {
|
||||
if (degree_ > 360) {
|
||||
degree_ -= 360;
|
||||
}
|
||||
degree_ += 40 * second;
|
||||
}
|
||||
|
||||
void OnRender() override {
|
||||
|
@ -15,14 +24,26 @@ public:
|
|||
|
||||
Renderer::SetDrawColor(Color{0, 1, 0});
|
||||
Renderer::FillRect(Rect{100, 100, 50, 75});
|
||||
|
||||
Renderer::DrawTexture(*dirt_, CreateTextureTransform(dirt_->GetSize(), Point{50, 50}));
|
||||
Renderer::DrawTexture(*start_, CreateTextureTransform(dirt_->GetSize(), Point{100, 50}));
|
||||
|
||||
Renderer::DrawTexture(dirt_.get(), nullptr, CreateSRT(Point{50, 50}, dirt_->GetSize(), 0));
|
||||
Renderer::DrawTexture(start_.get(), nullptr, Point{100, 50}, Size{0, 0}, degree_);
|
||||
|
||||
Renderer::DrawTexture(tilesheet_->GetTexture(), nullptr, Point{100, 100});
|
||||
Renderer::DrawTexture(tilesheet_->GetTexture(), nullptr, Point{100, 116}, Size{0, 0}, 0, Renderer::Horizontal);
|
||||
Renderer::DrawTexture(tilesheet_->GetTexture(), nullptr, Point{100, 132}, Size{0, 0}, 0, Renderer::Vertical);
|
||||
Renderer::DrawTexture(tilesheet_->GetTexture(), nullptr, Point{100, 148}, Size{0, 0}, 0, Renderer::Both);
|
||||
Size tileSize = {16, 16};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
Rect rect{i * 16.0f, 0, 16, 16};
|
||||
Renderer::DrawTile(tilesheet_->GetTile(i, 0), Point{50 + 16.0f * i, 200}, Size{0, 0}, degree_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Unique<Texture> dirt_;
|
||||
Unique<Texture> start_;
|
||||
Unique<TileSheet> tilesheet_;
|
||||
float degree_;
|
||||
};
|
||||
|
||||
RUN_WINDOW("test renderer", 1024, 720, TestRenderer)
|
||||
|
|
Reference in New Issue