Base refactor
This commit is contained in:
@ -3,13 +3,6 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Defines
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(DAWN_DEBUG_BUILD true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
else()
|
||||
set(DAWN_DEBUG_BUILD false CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
endif()
|
||||
|
||||
# Includes
|
||||
add_subdirectory(hosts)
|
||||
add_subdirectory(targets)
|
@ -7,7 +7,7 @@
|
||||
if(WIN32)
|
||||
set(DAWN_BUILD_HOST "build-host-win32")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
set(DAWN_BUILD_HOST "build-host-linux64")
|
||||
set(DAWN_BUILD_HOST "build-host-linux")
|
||||
elseif(UNIX AND APPLE)
|
||||
set(DAWN_BUILD_HOST "build-host-osx")
|
||||
endif()
|
||||
|
4
cmake/hosts/README.md
Normal file
4
cmake/hosts/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# CMake Hosts
|
||||
CMake Hosts help the build system define how a HOST (Not the target/client) does
|
||||
its building. Host would be the system you are using, right now, to do the build
|
||||
with.
|
@ -1,45 +0,0 @@
|
||||
find_path(ALUT_INCLUDE_DIR AL/alut.h
|
||||
HINTS
|
||||
ENV ALUTDIR
|
||||
PATHS
|
||||
"/usr"
|
||||
"/usr/local"
|
||||
"~/Library/Frameworks"
|
||||
"/Library/Frameworks"
|
||||
"/opt"
|
||||
"$ENV{PROGRAMFILES}/alut"
|
||||
"$ENV{PROGRAMFILES}/freealut"
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
alut
|
||||
freealut
|
||||
)
|
||||
|
||||
# Search for the library
|
||||
FIND_LIBRARY(ALUT_LIBRARY
|
||||
NAMES
|
||||
alut freealut
|
||||
HINTS
|
||||
ENV ALUTDIR
|
||||
PATHS
|
||||
"/usr"
|
||||
"/usr/local"
|
||||
"~/Library/Frameworks"
|
||||
"/Library/Frameworks"
|
||||
"/opt"
|
||||
"$ENV{PROGRAMFILES}/alut"
|
||||
"$ENV{PROGRAMFILES}/freealut"
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
lib32
|
||||
lib64
|
||||
libs
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
|
||||
ALUT
|
||||
REQUIRED_VARS ALUT_LIBRARY ALUT_INCLUDE_DIR
|
||||
)
|
||||
|
||||
mark_as_advanced(ALUT_LIBRARY ALUT_INCLUDE_DIR)
|
40
cmake/targets/README.md
Normal file
40
cmake/targets/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# CMake Targets
|
||||
CMake Targets decide what you are intending to build. Targets are (usually) a
|
||||
specific system, like vita, 3ds, switch, or a specific OS with a library, e.g.
|
||||
targetting vulkan on linux vs targetting opengl on linux, or targetting opengl
|
||||
on windows, etc.
|
||||
|
||||
In addition the target also decides what project(s) to build. Usually this is
|
||||
just the specific game and/or systems to be built, so if you are building a VN
|
||||
game the target would need to let the build system know you want to rollup the
|
||||
VN parts of the engine also.
|
||||
|
||||
Note this is one of the very few build args that is required during the
|
||||
configuration of cmake to make it build properly, failure to specify a target
|
||||
will result in a build error.
|
||||
|
||||
```
|
||||
-DDAWN_BUILD_TARGET=target-helloworld-linux64-glfw
|
||||
```
|
||||
|
||||
## Target Systems
|
||||
- vita
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
- emscripten (Web)
|
||||
|
||||
## Target Libraries
|
||||
- vita (Includes OGL)
|
||||
- glfw (Includes OGL)
|
||||
- sdl2 (Includes OGL)
|
||||
|
||||
## Target games
|
||||
- liminal
|
||||
- helloworld
|
||||
|
||||
## Target Arcitectures
|
||||
- vita (form of armv7)
|
||||
- linux (x64 only)
|
||||
- windows (x64 only)
|
||||
- osx (targetting arm64 currently)
|
@ -4,7 +4,7 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnhelloworld CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_LINUX64 true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_LINUX true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "HelloWorld" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_ARCHIVE true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnliminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_BUILD_HOST_LIBS "" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_EMSCRIPTEN true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Liminal" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_VISUAL_NOVEL true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
|
||||
set(DAWN_EMSCRIPTEN_FLAGS "" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnliminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_LINUX64 true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Liminal" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_VISUAL_NOVEL true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnliminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_OSX true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Liminal" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_VISUAL_NOVEL true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnliminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_WIN32 true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Liminal" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_VISUAL_NOVEL true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnrose CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_LINUX64 true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Rose" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
set(DAWN_BUILDING dawnrose CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_WIN32 true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_GLFW true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_TARGET_NAME "Rose" CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -1,7 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# set(DAWN_BUILDING dawntools CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
||||
set(DAWN_BUILD_TOOLS true CACHE INTERNAL ${DAWN_CACHE_TARGET})
|
@ -9,13 +9,13 @@ set(
|
||||
CACHE INTERNAL ${DAWN_CACHE_TARGET}
|
||||
)
|
||||
|
||||
# Change what we are building. Pulled from the cmake/targets dir.
|
||||
if(DEFINED DAWN_BUILDING)
|
||||
add_subdirectory(${DAWN_BUILDING})
|
||||
endif()
|
||||
# Build Project
|
||||
add_executable(${DAWN_TARGET_NAME})
|
||||
|
||||
# Definitions
|
||||
add_subdirectory(dawndefs)
|
||||
# Change what we are building. Pulled from the cmake/targets dir.
|
||||
# if(DEFINED DAWN_BUILDING)
|
||||
# add_subdirectory(${DAWN_BUILDING})
|
||||
# endif()
|
||||
|
||||
# Validate game project includes the target name
|
||||
if(DEFINED DAWN_TARGET_NAME)
|
||||
@ -25,8 +25,8 @@ if(DEFINED DAWN_TARGET_NAME)
|
||||
# Compile entry targets
|
||||
if(DAWN_TARGET_WIN32)
|
||||
add_subdirectory(dawnwin32)
|
||||
elseif(DAWN_TARGET_LINUX64)
|
||||
add_subdirectory(dawnlinux64)
|
||||
elseif(DAWN_TARGET_LINUX)
|
||||
add_subdirectory(dawnlinux)
|
||||
elseif(DAWN_TARGET_OSX)
|
||||
add_subdirectory(dawnosx)
|
||||
elseif(DAWN_TARGET_VITA)
|
||||
@ -55,7 +55,7 @@ if(DEFINED DAWN_TARGET_NAME)
|
||||
endif()
|
||||
|
||||
if(DAWN_TARGET_ARCHIVE)
|
||||
add_subdirectory(dawnarchiveasset)
|
||||
# add_subdirectory(dawnarchiveasset)
|
||||
else()
|
||||
add_subdirectory(dawnfileasset)
|
||||
endif()
|
||||
|
@ -18,26 +18,26 @@ target_include_directories(${DAWN_TARGET_NAME}
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(asset)
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(display)
|
||||
# add_subdirectory(asset)
|
||||
# add_subdirectory(audio)
|
||||
# add_subdirectory(display)
|
||||
add_subdirectory(game)
|
||||
add_subdirectory(games)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(prefab)
|
||||
add_subdirectory(physics)
|
||||
add_subdirectory(save)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(state)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(util)
|
||||
# add_subdirectory(games)
|
||||
# add_subdirectory(input)
|
||||
# add_subdirectory(locale)
|
||||
# add_subdirectory(prefab)
|
||||
# add_subdirectory(physics)
|
||||
# add_subdirectory(save)
|
||||
# add_subdirectory(scene)
|
||||
# add_subdirectory(state)
|
||||
# add_subdirectory(time)
|
||||
# add_subdirectory(util)
|
||||
|
||||
# Definitions
|
||||
target_compile_definitions(${DAWN_TARGET_NAME}
|
||||
PUBLIC
|
||||
DAWN_DEBUG_BUILD=${DAWN_DEBUG_BUILD}
|
||||
)
|
||||
# target_compile_definitions(${DAWN_TARGET_NAME}
|
||||
# PUBLIC
|
||||
# DAWN_DEBUG_BUILD=${DAWN_DEBUG_BUILD}
|
||||
# )
|
||||
|
||||
# Tests
|
||||
target_link_libraries(dawntests
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AssetManager.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
Asset::Asset(const std::string name) : name(name) {
|
||||
assertTrue(name.size() > 0, "Asset::Asset: Name cannot be empty");
|
||||
}
|
||||
|
||||
Asset::~Asset() {
|
||||
this->loaded = false;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "state/StateEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AssetManager;
|
||||
|
||||
class Asset {
|
||||
public:
|
||||
const std::string name;
|
||||
bool_t loaded = false;
|
||||
StateEvent<> eventLoaded;
|
||||
|
||||
/**
|
||||
* Create an abstract Asset object.
|
||||
*
|
||||
* @param name Name of the asset.
|
||||
*/
|
||||
Asset(const std::string name);
|
||||
|
||||
/**
|
||||
* Virtual function that will be called by the asset manager on a
|
||||
* synchronous basis. This will only trigger if the blocks are false and
|
||||
* the loaded is also false.
|
||||
*/
|
||||
virtual void updateSync() = 0;
|
||||
|
||||
/**
|
||||
* Virtual function called by the asset manager asynchronously every tick.
|
||||
* This will only trigger if blocks are false and the loaded state is also
|
||||
* false.
|
||||
*/
|
||||
virtual void updateAsync() = 0;
|
||||
|
||||
/**
|
||||
* Dispose the asset item.
|
||||
*/
|
||||
virtual ~Asset();
|
||||
};
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AssetManager.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void AssetManager::init() {
|
||||
|
||||
}
|
||||
|
||||
void AssetManager::update() {
|
||||
this->syncTick();
|
||||
}
|
||||
|
||||
void AssetManager::queueLoad(const std::vector<std::shared_ptr<Asset>> assets) {
|
||||
assetsToLoad.insert(this->assetsToLoad.end(), assets.begin(), assets.end());
|
||||
}
|
||||
|
||||
void AssetManager::queueLoad(const std::shared_ptr<Asset> &asset) {
|
||||
this->assetsToLoad.push_back(asset);
|
||||
}
|
||||
|
||||
void AssetManager::queueUnload(
|
||||
const std::vector<std::shared_ptr<Asset>> &assets
|
||||
) {
|
||||
std::cout <<
|
||||
"Asset list was queued to unload, but is not yet implemented" <<
|
||||
std::endl;
|
||||
assetsToUnload.insert(assetsToUnload.end(), assets.begin(), assets.end());
|
||||
}
|
||||
|
||||
void AssetManager::queueUnload(const std::shared_ptr<Asset> &asset) {
|
||||
std::cout <<
|
||||
"Asset was queued to unload, but is not yet implemented" <<
|
||||
std::endl;
|
||||
this->assetsToUnload.push_back(asset);
|
||||
}
|
||||
|
||||
void AssetManager::queueSwap(
|
||||
const std::vector<std::shared_ptr<Asset>> &newAssets,
|
||||
const std::vector<std::shared_ptr<Asset>> &oldAssets
|
||||
) {
|
||||
std::vector<std::shared_ptr<Asset>> unload;
|
||||
std::vector<std::shared_ptr<Asset>> load;
|
||||
|
||||
// Determine assets to unload.
|
||||
std::for_each(oldAssets.begin(), oldAssets.end(), [&](const auto &asset){
|
||||
auto it = std::find(newAssets.begin(), newAssets.end(), asset);
|
||||
if(it == newAssets.end()) unload.push_back(asset);
|
||||
});
|
||||
|
||||
// Determine assets to load
|
||||
std::for_each(newAssets.begin(), newAssets.end(), [&](const auto &asset){
|
||||
auto it = std::find(oldAssets.begin(), oldAssets.end(), asset);
|
||||
if(it == oldAssets.end()) load.push_back(asset);
|
||||
});
|
||||
|
||||
this->queueUnload(unload);
|
||||
this->queueLoad(load);
|
||||
}
|
||||
|
||||
void AssetManager::syncTick() {
|
||||
std::erase_if(assetsToLoad, [&](auto &asset){
|
||||
if(asset->loaded) {
|
||||
asset->eventLoaded.invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
asset->updateSync();
|
||||
asset->updateAsync();//TODO: Make Async
|
||||
|
||||
if(asset->loaded) {
|
||||
asset->eventLoaded.invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
return asset->loaded;
|
||||
});
|
||||
}
|
||||
|
||||
void AssetManager::syncLoad() {
|
||||
while(this->assetsToLoad.size() > 0) {
|
||||
this->syncTick();
|
||||
}
|
||||
}
|
||||
|
||||
AssetManager::~AssetManager() {
|
||||
this->assets.clear();
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "Asset.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AssetManager {
|
||||
private:
|
||||
/** List of pointers to assets, mapped by their asset key. */
|
||||
std::map<std::string, std::shared_ptr<Asset>> assets;
|
||||
std::vector<std::shared_ptr<Asset>> assetsToLoad;
|
||||
std::vector<std::shared_ptr<Asset>> assetsToUnload;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes this asset manager so it can begin accepting assets.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Updates the asset manager.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Queue a loading of a list of assets. Does not actually begin loading.
|
||||
*
|
||||
* @param assets Assets to load.
|
||||
*/
|
||||
void queueLoad(const std::vector<std::shared_ptr<Asset>> assets);
|
||||
|
||||
/**
|
||||
* Queue a loading of a single asset. Does not actually begin loading.
|
||||
*
|
||||
* @param asset Asset to load.
|
||||
*/
|
||||
void queueLoad(const std::shared_ptr<Asset> &asset);
|
||||
|
||||
/**
|
||||
* Takes a list of lists to queue to unload. Does not immediately unload.
|
||||
*
|
||||
* @param assets Assets to unload.
|
||||
*/
|
||||
void queueUnload(const std::vector<std::shared_ptr<Asset>> &assets);
|
||||
|
||||
/**
|
||||
* Takes a single asset to queue to unload. Does not immediately unload.
|
||||
*
|
||||
* @param assets Assets to unload.
|
||||
*/
|
||||
void queueUnload(const std::shared_ptr<Asset> &assets);
|
||||
|
||||
/**
|
||||
* Queues load and unload based on the difference between two sets of
|
||||
* assets. This is mostly used to perform a scene change.
|
||||
*
|
||||
* @param newAssets New list of assets to maintain.
|
||||
* @param oldAssets Old list of assets to no longer maintain.
|
||||
*/
|
||||
void queueSwap(
|
||||
const std::vector<std::shared_ptr<Asset>> &newAssets,
|
||||
const std::vector<std::shared_ptr<Asset>> &oldAssets
|
||||
);
|
||||
|
||||
/**
|
||||
* Ticks the asset manager, synchronously.
|
||||
*/
|
||||
void syncTick();
|
||||
|
||||
/**
|
||||
* Loads everything that isn't loaded, blocks the current thread until
|
||||
* that has finished.
|
||||
*/
|
||||
void syncLoad();
|
||||
|
||||
/**
|
||||
* Creates and queue an asset to load.
|
||||
*
|
||||
* @param name Name of the asset to load.
|
||||
* @return The asset element to be loaded.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> get(std::string name) {
|
||||
assertTrue(
|
||||
name.size() > 0, "AssetManager::get: name must be greater than 0"
|
||||
);
|
||||
|
||||
auto existing = this->assets.find(name);
|
||||
if(existing != this->assets.end()) {
|
||||
return dynamic_pointer_cast<T>(existing->second);
|
||||
}
|
||||
auto asset = std::make_shared<T>(name);
|
||||
this->assets[name] = asset;
|
||||
return asset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Both gets an asset, and puts it into the load queue.
|
||||
*
|
||||
* @param name Name of the asset to load.
|
||||
* @return The asset element to be loaded.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> getAndLoad(std::string name) {
|
||||
auto asset = this->get<T>(name);
|
||||
this->queueLoad(asset);
|
||||
return asset;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void unload(std::shared_ptr<T> asset) {
|
||||
assertUnreachable("AssetManager::unload: NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
void unload(std::string name) {
|
||||
assertUnreachable("AssetManager::unload: NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the asset manager, and all attached assets.
|
||||
*/
|
||||
~AssetManager();
|
||||
};
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Asset.cpp
|
||||
IAssetLoader.cpp
|
||||
AssetManager.cpp
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(assets)
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "IAssetLoader.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
IAssetLoader::IAssetLoader(const std::string fileName) : fileName(fileName) {
|
||||
assertTrue(
|
||||
fileName.size() > 0,
|
||||
"IAssetLoader::IAssetLoader: fileName must be greater than 0"
|
||||
);
|
||||
}
|
||||
|
||||
size_t IAssetLoader::setPosition(const size_t position) {
|
||||
assertTrue(
|
||||
position >= 0,
|
||||
"IAssetLoader::setPosition: position must be greater than or equal to 0"
|
||||
);
|
||||
this->rewind();
|
||||
return this->skip(position);
|
||||
}
|
||||
|
||||
IAssetLoader::~IAssetLoader() {
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "assert/assert.hpp"
|
||||
|
||||
#define ASSET_LOADER_BUFFER_SIZE 32768
|
||||
|
||||
#if !defined(DAWN_ASSET_LOCATION)
|
||||
#error Asset Archive Location has not been defined.
|
||||
#endif
|
||||
|
||||
namespace Dawn {
|
||||
class IAssetLoader {
|
||||
protected:
|
||||
std::string fileName;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a new asset loader. Asset Loaders can be used to load data from
|
||||
* a file in a myriad of ways.
|
||||
*
|
||||
* @param fileName File name of the asset that is to be loaded.
|
||||
*/
|
||||
IAssetLoader(const std::string fileName);
|
||||
|
||||
/**
|
||||
* Platform-centric method to open a file buffer to an asset.
|
||||
*/
|
||||
virtual void open() = 0;
|
||||
|
||||
/**
|
||||
* Closes the previously ppened asset.
|
||||
* @return 0 if successful, otherwise false.
|
||||
*/
|
||||
virtual int32_t close() = 0;
|
||||
|
||||
/**
|
||||
* Read bytes from buffer.
|
||||
* @param buffer Pointer to a ubyte array to buffer data into.
|
||||
* @param size Length of the data buffer (How many bytes to read).
|
||||
* @return The count of bytes read.
|
||||
*/
|
||||
virtual size_t read(uint8_t *buffer, const size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Get the size of the asset.
|
||||
* @return The size of the asset in bytes.
|
||||
*/
|
||||
virtual size_t getSize() = 0;
|
||||
|
||||
/**
|
||||
* Skips the read head forward to a given position.
|
||||
*
|
||||
* @param n Count of bytes to progress the read head by.
|
||||
* @return Count of bytes progressed.
|
||||
*/
|
||||
virtual size_t skip(const size_t n) = 0;
|
||||
|
||||
/**
|
||||
* Rewind the read head to the beginning of the file.
|
||||
*/
|
||||
virtual void rewind() = 0;
|
||||
|
||||
/**
|
||||
* Sets the absolute position of the read head within the buffer of the
|
||||
* file.
|
||||
*
|
||||
* @param absolutePosition Absolute position to set the read head to.
|
||||
*/
|
||||
size_t setPosition(const size_t absolutePosition);
|
||||
|
||||
/**
|
||||
* Returns the current position of the read head.
|
||||
*
|
||||
* @return The current read head position.
|
||||
*/
|
||||
virtual size_t getPosition() = 0;
|
||||
|
||||
/**
|
||||
* Run a callback for each byte within the asset. The callback will
|
||||
* receive each byte individually.
|
||||
*
|
||||
* @tparam T Type of instance to run callback against.
|
||||
* @param instance Instance of the object to run the callback against.
|
||||
* @param callback Callback method on the class to run the callback for.
|
||||
* @return The count of bytes read.
|
||||
*/
|
||||
template<class T>
|
||||
size_t loadBufferedCallback(
|
||||
std::function<bool_t(uint8_t n)> callback
|
||||
) {
|
||||
uint8_t buffer[1024];
|
||||
size_t read, length;
|
||||
int32_t i;
|
||||
bool_t result;
|
||||
|
||||
assertNotNull(callback, "Callback cannot be null.");
|
||||
|
||||
// Open the buffer.
|
||||
this->open();
|
||||
|
||||
// Reset length size
|
||||
length = 0;
|
||||
|
||||
// Buffer from input
|
||||
while((read = this->read(buffer, 1024)) != 0) {
|
||||
for(i = 0; i < read; i++) {
|
||||
result = callback(buffer[i]);
|
||||
if(!result) {
|
||||
length += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!result) break;
|
||||
length += read;
|
||||
}
|
||||
|
||||
// Close the buffer
|
||||
this->close();
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the asset loader.
|
||||
*/
|
||||
virtual ~IAssetLoader();
|
||||
};
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AudioAsset.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
AudioAsset::AudioAsset(const std::string name) :
|
||||
Asset(name),
|
||||
loader(name + ".audio")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AudioAsset::updateSync() {
|
||||
if(this->state != AUDIO_ASSET_LOAD_STATE_DATA_READ) return;
|
||||
|
||||
// THIS WILL DEFINITELY CHANGE
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_COMPLETE;
|
||||
this->loaded = true;
|
||||
}
|
||||
|
||||
void AudioAsset::updateAsync() {
|
||||
if(this->state != AUDIO_ASSET_LOAD_STATE_INITIAL) return;
|
||||
char *start, *end;
|
||||
char buffer[1024];
|
||||
|
||||
// Open asset for reading
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_OPENING;
|
||||
this->loader.open();
|
||||
|
||||
// Parse header data.
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_READING_HEADER;
|
||||
this->loader.read((uint8_t *)buffer, 1024);
|
||||
|
||||
// Channel count
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_READING_CHANNEL_COUNT;
|
||||
start = buffer;
|
||||
end = strchr(start, '|');
|
||||
*end = '\0';
|
||||
this->channelCount = atoi(start);
|
||||
assertTrue(this->channelCount > 0, "Channel count must be greater than 0");
|
||||
|
||||
// Sample Rate
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_READING_SAMPLE_RATE;
|
||||
start = end + 1;
|
||||
end = strchr(start, '|');
|
||||
*end = '\0';
|
||||
this->sampleRate = (uint32_t)strtoul(start, NULL, 10);
|
||||
assertTrue(this->sampleRate > 0, "Sample rate must be greater than 0");
|
||||
|
||||
// Number of samples per channel
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_READING_SAMPLES_PER_CHANNEL;
|
||||
start = end + 1;
|
||||
end = strchr(start, '|');
|
||||
*end = '\0';
|
||||
this->samplesPerChannel = atoi(start);
|
||||
assertTrue(
|
||||
this->samplesPerChannel > 0,
|
||||
"Samples per channel must be greater than 0"
|
||||
);
|
||||
|
||||
// Total Data Length
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_READING_DATA_LENGTH;
|
||||
start = end + 1;
|
||||
end = strchr(start, '|');
|
||||
*end = '\0';
|
||||
this->bufferSize = (size_t)atoll(start);
|
||||
assertTrue(this->bufferSize > 0, "Buffer size must be greater than 0");
|
||||
|
||||
// Determine frame size
|
||||
this->frameSize = sizeof(int16_t) * this->channelCount;
|
||||
|
||||
// Indicated start of data
|
||||
this->state = AUDIO_ASSET_LOAD_STATE_DATA_READ;
|
||||
this->bufferStart = end - buffer;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../Asset.hpp"
|
||||
#include "asset/AssetLoader.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class AudioSource;
|
||||
|
||||
enum AudioAssetLoadState {
|
||||
AUDIO_ASSET_LOAD_STATE_INITIAL,
|
||||
AUDIO_ASSET_LOAD_STATE_OPENING,
|
||||
AUDIO_ASSET_LOAD_STATE_READING_HEADER,
|
||||
AUDIO_ASSET_LOAD_STATE_READING_CHANNEL_COUNT,
|
||||
AUDIO_ASSET_LOAD_STATE_READING_SAMPLE_RATE,
|
||||
AUDIO_ASSET_LOAD_STATE_READING_SAMPLES_PER_CHANNEL,
|
||||
AUDIO_ASSET_LOAD_STATE_READING_DATA_LENGTH,
|
||||
AUDIO_ASSET_LOAD_STATE_DATA_READ,
|
||||
AUDIO_ASSET_LOAD_STATE_COMPLETE
|
||||
};
|
||||
|
||||
class AudioAsset : public Asset {
|
||||
protected:
|
||||
AssetLoader loader;
|
||||
enum AudioAssetLoadState state = AUDIO_ASSET_LOAD_STATE_INITIAL;
|
||||
|
||||
int32_t channelCount;
|
||||
uint32_t sampleRate;
|
||||
int32_t samplesPerChannel;
|
||||
size_t bufferSize;
|
||||
size_t bufferStart;
|
||||
size_t frameSize;
|
||||
|
||||
public:
|
||||
AudioAsset(const std::string name);
|
||||
|
||||
void updateSync() override;
|
||||
void updateAsync() override;
|
||||
|
||||
friend class AudioSource;
|
||||
};
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
AudioAsset.cpp
|
||||
LanguageAsset.cpp
|
||||
TextureAsset.cpp
|
||||
TrueTypeAsset.cpp
|
||||
)
|
@ -1,86 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "LanguageAsset.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
LanguageAsset::LanguageAsset(const std::string name) :
|
||||
Asset(name),
|
||||
loader(name + ".language")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LanguageAsset::updateSync() {
|
||||
|
||||
}
|
||||
|
||||
void LanguageAsset::updateAsync() {
|
||||
assertTrue(
|
||||
this->state == LANGUAGE_ASSET_LOAD_STATE_INITIAL,
|
||||
"State must be initial"
|
||||
);
|
||||
|
||||
// Open Asset
|
||||
this->state = LANGUAGE_ASSET_LOAD_STATE_OPENING;
|
||||
this->loader.open();
|
||||
|
||||
// Get Length
|
||||
size_t len = this->loader.getSize();
|
||||
|
||||
// Create buffer
|
||||
this->state = LANGUAGE_ASSET_LOAD_STATE_CREATING_BUFFER;
|
||||
size_t position = 0;
|
||||
|
||||
// Loop over CSV
|
||||
while(position < len) {
|
||||
this->loader.read(buffer, 1024);
|
||||
|
||||
// Get strings
|
||||
uint8_t *keyStart = buffer;
|
||||
uint8_t *keyEnd = (uint8_t*)strchr((char*)keyStart, '|');
|
||||
*keyEnd = '\0';
|
||||
uint8_t *valueStart = keyEnd + 1;
|
||||
uint8_t *valueEnd = (uint8_t*)strchr((char*)valueStart, '|');
|
||||
|
||||
// Load value positions
|
||||
struct AssetLanguageValue value;
|
||||
value.begin = position + (size_t)(valueStart - buffer);
|
||||
value.length = (size_t)(valueEnd - valueStart);
|
||||
|
||||
// Prepare for next string.
|
||||
position = position + (size_t)(valueEnd - buffer + 1);
|
||||
this->loader.setPosition(position);
|
||||
|
||||
// Store strings.
|
||||
std::string key((char *)keyStart);
|
||||
this->values[key] = value;
|
||||
}
|
||||
|
||||
this->state = LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ;
|
||||
this->loaded = true;
|
||||
}
|
||||
|
||||
std::string LanguageAsset::getValue(const std::string key) {
|
||||
assertTrue(
|
||||
this->state == LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ,
|
||||
"State must be LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ"
|
||||
);
|
||||
assertMapHasKey(this->values, key, "Key does not exist");
|
||||
assertTrue(
|
||||
this->values[key].begin >= 0 && this->values[key].length > 0,
|
||||
"Value is invalid"
|
||||
);
|
||||
|
||||
// Get the positions
|
||||
struct AssetLanguageValue value = this->values[key];
|
||||
|
||||
this->loader.setPosition(value.begin);
|
||||
this->loader.read(buffer, value.length);
|
||||
buffer[value.length] = '\0';
|
||||
|
||||
return std::string((char *)buffer, value.length + 1);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../Asset.hpp"
|
||||
#include "asset/AssetLoader.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct AssetLanguageValue {
|
||||
size_t begin;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
enum LangageAssetLoadState {
|
||||
LANGUAGE_ASSET_LOAD_STATE_INITIAL,
|
||||
LANGUAGE_ASSET_LOAD_STATE_OPENING,
|
||||
LANGUAGE_ASSET_LOAD_STATE_CREATING_BUFFER,
|
||||
LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ
|
||||
};
|
||||
|
||||
class LanguageAsset : public Asset {
|
||||
protected:
|
||||
AssetLoader loader;
|
||||
enum LangageAssetLoadState state = LANGUAGE_ASSET_LOAD_STATE_INITIAL;
|
||||
std::map<std::string, struct AssetLanguageValue> values;
|
||||
uint8_t buffer[1024];
|
||||
|
||||
public:
|
||||
LanguageAsset(const std::string name);
|
||||
void updateSync() override;
|
||||
void updateAsync() override;
|
||||
std::string getValue(const std::string key);
|
||||
};
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "TextureAsset.hpp"
|
||||
#include "util/memory.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
TextureAsset::TextureAsset(const std::string name) :
|
||||
Asset(name),
|
||||
loader(name + ".texture"),
|
||||
texture()
|
||||
{
|
||||
}
|
||||
|
||||
void TextureAsset::updateSync() {
|
||||
if(this->state != TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF) return;
|
||||
|
||||
this->state = TEXTURE_ASSET_LOAD_STATE_BUFFERING_TEXTURE;
|
||||
this->texture.setSize(
|
||||
this->width, this->height, this->format, TEXTURE_DATA_FORMAT_UNSIGNED_BYTE
|
||||
);
|
||||
this->texture.buffer(this->colors);
|
||||
|
||||
this->texture.wrapModeX = this->wrapModeX;
|
||||
this->texture.wrapModeY = this->wrapModeY;
|
||||
this->texture.filterModeMin = this->filterModeMin;
|
||||
this->texture.filterModeMag = this->filterModeMag;
|
||||
|
||||
this->state = TEXTURE_ASSET_LOAD_STATE_COMPLETE;
|
||||
this->loaded = true;
|
||||
}
|
||||
|
||||
void TextureAsset::updateAsync() {
|
||||
if(this->state != TEXTURE_ASSET_LOAD_STATE_INITIAL) return;
|
||||
this->state = TEXTURE_ASSET_LOAD_STATE_OPENING;
|
||||
this->loader.open();
|
||||
this->buffer = memoryAllocate<uint8_t>(this->loader.getSize());
|
||||
this->loader.read(this->buffer, this->loader.getSize());
|
||||
this->loader.close();
|
||||
this->state = TEXTURE_ASSET_LOAD_STATE_PARSING_HEADER;
|
||||
|
||||
// Parse header data.
|
||||
char integer[256];
|
||||
size_t j = 0, i = 0;
|
||||
enum TextureAssetHeaderParseState parseState =
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION
|
||||
;
|
||||
while(true) {
|
||||
if(parseState == TEXTURE_ASSET_HEADER_PARSE_STATE_END) break;
|
||||
|
||||
auto c = this->buffer[i++];
|
||||
if(c != '|') {
|
||||
integer[j++] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
integer[j] = '\0';
|
||||
|
||||
switch(parseState) {
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION: {
|
||||
auto compared = strcmp(integer, "DT_2.00");
|
||||
assertTrue(compared == 0, "Invalid version");
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH: {
|
||||
this->width = atoi(integer);
|
||||
assertTrue(this->width > 0, "Invalid width");
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT: {
|
||||
this->height = atoi(integer);
|
||||
assertTrue(this->height > 0, "Invalid height");
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT: {
|
||||
this->format = (enum TextureFormat)atoi(integer);
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X: {
|
||||
this->wrapModeX = (enum TextureWrapMode)atoi(integer);
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y: {
|
||||
this->wrapModeY = (enum TextureWrapMode)atoi(integer);
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN: {
|
||||
this->filterModeMin = (enum TextureFilterMode)atoi(integer);
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG;
|
||||
break;
|
||||
}
|
||||
|
||||
case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG: {
|
||||
this->filterModeMag = (enum TextureFilterMode)atoi(integer);
|
||||
j = 0;
|
||||
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_END;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid parse state");
|
||||
}
|
||||
}
|
||||
|
||||
this->colors = (uint8_t*)((void *)(this->buffer + i));
|
||||
this->state = TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF;
|
||||
}
|
||||
|
||||
TextureAsset::~TextureAsset() {
|
||||
if(this->buffer != nullptr) {
|
||||
memoryFree(this->buffer);
|
||||
this->buffer = nullptr;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../Asset.hpp"
|
||||
#include "asset/AssetLoader.hpp"
|
||||
#include "display/Texture.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum TextureAssetHeaderParseState {
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG,
|
||||
TEXTURE_ASSET_HEADER_PARSE_STATE_END
|
||||
};
|
||||
|
||||
enum TextureAssetLoadState {
|
||||
TEXTURE_ASSET_LOAD_STATE_INITIAL,
|
||||
TEXTURE_ASSET_LOAD_STATE_OPENING,
|
||||
TEXTURE_ASSET_LOAD_STATE_PARSING_HEADER,
|
||||
TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF,
|
||||
TEXTURE_ASSET_LOAD_STATE_BUFFERING_TEXTURE,
|
||||
TEXTURE_ASSET_LOAD_STATE_COMPLETE,
|
||||
};
|
||||
|
||||
class TextureAsset : public Asset {
|
||||
protected:
|
||||
AssetLoader loader;
|
||||
uint8_t *buffer = nullptr;
|
||||
int32_t width = -1, height = -1;
|
||||
uint8_t *colors;
|
||||
enum TextureAssetLoadState state = TEXTURE_ASSET_LOAD_STATE_INITIAL;
|
||||
enum TextureFormat format;
|
||||
enum TextureWrapMode wrapModeX;
|
||||
enum TextureWrapMode wrapModeY;
|
||||
enum TextureFilterMode filterModeMin;
|
||||
enum TextureFilterMode filterModeMag;
|
||||
|
||||
public:
|
||||
Texture texture;
|
||||
|
||||
/**
|
||||
* Constructs a texture asset loader. You should instead use the parent
|
||||
* asset managers' abstracted load method
|
||||
*
|
||||
* @param name File name asset to load, omitting the extension.
|
||||
*/
|
||||
TextureAsset(const std::string name);
|
||||
|
||||
void updateSync() override;
|
||||
void updateAsync() override;
|
||||
|
||||
/**
|
||||
* Dispose / Cleanup the texture asset. Will also dispose the underlying
|
||||
* texture itself.
|
||||
*/
|
||||
~TextureAsset();
|
||||
};
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "TrueTypeAsset.hpp"
|
||||
#include "asset/AssetManager.hpp"
|
||||
#include "util/memory.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
TrueTypeAsset::TrueTypeAsset(const std::string name) :
|
||||
Asset(name),
|
||||
loader(name + ".truetype")
|
||||
{
|
||||
this->locks.onLockRemoved = [&](usagelockid_t id){
|
||||
auto texture = this->textureByLock[id];
|
||||
|
||||
assertNotNull(texture, "Texture cannot be null");
|
||||
|
||||
std::vector<usagelockid_t> &lbt = this->locksByTexture[texture];
|
||||
auto it0 = std::find(lbt.begin(), lbt.end(), id);
|
||||
assertTrue(it0 != lbt.end(), "Could not remove locksByTexture[texture]");
|
||||
lbt.erase(it0);
|
||||
|
||||
auto it1 = this->textureByLock.find(id);
|
||||
assertTrue(
|
||||
it1 != this->textureByLock.end(), "Could not remove textureByLock"
|
||||
);
|
||||
this->textureByLock.erase(it1);
|
||||
|
||||
if(lbt.empty()) {
|
||||
auto it2 = locksByTexture.find(texture);
|
||||
assertTrue(
|
||||
it2 != locksByTexture.end(), "Could not remove locksByTexture"
|
||||
);
|
||||
locksByTexture.erase(it2);
|
||||
|
||||
std::erase_if(textureByStyle, [&](const auto &item){
|
||||
auto const& [key, value] = item;
|
||||
return value == texture;
|
||||
});
|
||||
|
||||
std::erase(textures, texture);
|
||||
delete texture;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void TrueTypeAsset::updateSync() {
|
||||
|
||||
}
|
||||
|
||||
void TrueTypeAsset::updateAsync() {
|
||||
if(this->state != TRUE_TYPE_ASSET_STATE_INITIAL) return;
|
||||
|
||||
this->state = TRUE_TYPE_ASSET_STATE_OPEN;
|
||||
this->loader.open();
|
||||
|
||||
this->state = TRUE_TYPE_ASSET_STATE_VALIDATE_HEADER;
|
||||
|
||||
uint8_t buffer[64];
|
||||
this->loader.rewind();
|
||||
size_t read = this->loader.read(buffer, sizeof(char) * 6);
|
||||
assertTrue(read == (6 * sizeof(char)), "Could not read header");
|
||||
buffer[6] = '\0';
|
||||
|
||||
// Confirm "DE_TTF"
|
||||
assertTrue(
|
||||
std::string((char *)buffer) == "DE_TTF",
|
||||
"Header is invalid (Missing DE_TTF)"
|
||||
);
|
||||
|
||||
// Vertical bar
|
||||
this->loader.read(buffer, 1);
|
||||
assertTrue(
|
||||
buffer[0] == '|',
|
||||
"Header is invalid (Missing first vertical bar)"
|
||||
);
|
||||
|
||||
// Read version
|
||||
this->state = TRUE_TYPE_ASSET_STATE_VALIDATE_VERSION;
|
||||
read = this->loader.read(buffer, sizeof(char) * 5);
|
||||
assertTrue(buffer[0] == '3', "Version is invalid 3");
|
||||
assertTrue(buffer[1] == '.', "Version is invalid .");
|
||||
assertTrue(buffer[2] == '0', "Version is invalid 0(1)");
|
||||
assertTrue(buffer[3] == '0', "Version is invalid 0(2)");
|
||||
assertTrue(
|
||||
buffer[4] == '|',
|
||||
"Version is invalid (Missing second vertical bar)"
|
||||
);
|
||||
|
||||
// Read the count of font styles / variants.
|
||||
size_t styleListBegin = this->loader.getPosition();
|
||||
this->state = TRUE_TYPE_ASSET_STATE_READ_VARIANT_COUNT;
|
||||
read = this->loader.read(buffer, 64);
|
||||
assertTrue(read > 0, "Could not read variant count");
|
||||
|
||||
// Get position of vertical bar.
|
||||
size_t i = 0;
|
||||
while(buffer[i] != '|' && i < 64) i++;
|
||||
assertTrue(buffer[i] == '|', "Could not find vertical bar");
|
||||
styleListBegin += i + 1;
|
||||
buffer[i] = '\0';
|
||||
|
||||
int32_t count = atoi((char *)buffer);
|
||||
assertTrue(count > 0, "Invalid variant count");
|
||||
|
||||
// Now begin parsing each font style.
|
||||
this->state = TRUE_TYPE_ASSET_STATE_READ_VARIANT;
|
||||
assetStyles.clear();
|
||||
while(assetStyles.size() != count) {
|
||||
struct TrueTypeAssetStyle style;
|
||||
|
||||
// Buffer
|
||||
this->loader.setPosition(styleListBegin);
|
||||
read = this->loader.read(buffer, 32);
|
||||
assertTrue(read == 32, "Could not read variant");
|
||||
|
||||
// Read style
|
||||
i = 0;
|
||||
while(buffer[i] != ':' && i < 64) i++;
|
||||
buffer[i] = '\0';
|
||||
style.style = atoi((char *)buffer);
|
||||
styleListBegin += i + 1;
|
||||
|
||||
// Buffer
|
||||
this->loader.setPosition(styleListBegin);
|
||||
read = this->loader.read(buffer, 32);
|
||||
assertTrue(read == 32, "Could not read variant style");
|
||||
|
||||
// Read length
|
||||
i = 0;
|
||||
while(buffer[i] != '|' && i < 64) i++;
|
||||
buffer[i] = '\0';
|
||||
styleListBegin += i + 1;
|
||||
style.dataSize = atol((char *)buffer);
|
||||
|
||||
// Push
|
||||
assetStyles.push_back(style);
|
||||
}
|
||||
|
||||
// Now we are at the first byte of the first style.
|
||||
this->state = TRUE_TYPE_ASSET_STATE_ADJUSTING_OFFSETS;
|
||||
std::for_each(
|
||||
assetStyles.begin(),
|
||||
assetStyles.end(),
|
||||
[&](struct TrueTypeAssetStyle &style){
|
||||
style.dataOffset = styleListBegin;
|
||||
styleListBegin += style.dataSize;
|
||||
styleListBegin += 1;
|
||||
}
|
||||
);
|
||||
|
||||
// Init FreeType
|
||||
this->state = TRUE_TYPE_ASSET_STATE_INIT_FREETYPE;
|
||||
int32_t ret = FT_Init_FreeType(&fontLibrary);
|
||||
assertTrue(ret == 0, "Could not init FreeType");
|
||||
|
||||
// Done parsing!
|
||||
this->state = TRUE_TYPE_ASSET_STATE_READY;
|
||||
this->loaded = true;
|
||||
}
|
||||
|
||||
usagelockid_t TrueTypeAsset::lock(const struct TrueTypeFaceTextureStyle style) {
|
||||
assertTrue(this->state == TRUE_TYPE_ASSET_STATE_READY, "Asset is not ready");
|
||||
|
||||
// Try and find an existing texture that matches this style
|
||||
auto it = this->textureByStyle.find(style);
|
||||
TrueTypeFaceTexture *texture = nullptr;
|
||||
|
||||
if(it == this->textureByStyle.end()) {
|
||||
// Does not exist, Find asset style
|
||||
auto itAssetStyle = std::find_if(
|
||||
assetStyles.begin(),
|
||||
assetStyles.end(),
|
||||
[&](const struct TrueTypeAssetStyle &assetStyle) {
|
||||
return assetStyle.style == style.style;
|
||||
}
|
||||
);
|
||||
assertTrue(
|
||||
itAssetStyle != this->assetStyles.end(),
|
||||
"Could not find asset style"
|
||||
);
|
||||
|
||||
// Create and read buffer.
|
||||
uint8_t *dataBuffer = memoryAllocate<uint8_t>(itAssetStyle->dataSize);
|
||||
this->loader.rewind();
|
||||
this->loader.setPosition(itAssetStyle->dataOffset);
|
||||
auto read = this->loader.read(dataBuffer, itAssetStyle->dataSize);
|
||||
assertTrue(read == itAssetStyle->dataSize, "Could not read data");
|
||||
|
||||
// Create the face
|
||||
FT_Face face;
|
||||
auto ret = FT_New_Memory_Face(
|
||||
this->fontLibrary,
|
||||
(FT_Byte*)dataBuffer,
|
||||
itAssetStyle->dataSize,
|
||||
0,
|
||||
&face
|
||||
);
|
||||
assertTrue(ret == 0, "Could not create face");
|
||||
texture = new TrueTypeFaceTexture(face, style);
|
||||
memoryFree(dataBuffer);
|
||||
|
||||
this->textures.push_back(texture);
|
||||
this->textureByStyle[style] = texture;
|
||||
} else {
|
||||
// Exists
|
||||
texture = it->second;
|
||||
}
|
||||
|
||||
auto lock = this->locks.createLock();
|
||||
this->textureByLock[lock] = texture;
|
||||
this->locksByTexture[texture].push_back(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
TrueTypeFaceTexture * TrueTypeAsset::getTexture(const usagelockid_t id) {
|
||||
auto it = this->textureByLock.find(id);
|
||||
assertTrue(it != this->textureByLock.end(), "Could not find texture");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void TrueTypeAsset::unlock(const usagelockid_t id) {
|
||||
this->locks.removeLock(id);
|
||||
}
|
||||
|
||||
TrueTypeAsset::~TrueTypeAsset() {
|
||||
std::for_each(
|
||||
this->textures.begin(),
|
||||
this->textures.end(),
|
||||
[](TrueTypeFaceTexture *texture){
|
||||
delete texture;
|
||||
}
|
||||
);
|
||||
|
||||
FT_Done_FreeType(this->fontLibrary);
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../Asset.hpp"
|
||||
#include "asset/AssetLoader.hpp"
|
||||
#include "util/flag.hpp"
|
||||
#include "display/font/truetype/TrueTypeFaceTexture.hpp"
|
||||
#include "util/UsageLock.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum TrueTypeAssetState {
|
||||
TRUE_TYPE_ASSET_STATE_INITIAL,
|
||||
TRUE_TYPE_ASSET_STATE_OPEN,
|
||||
TRUE_TYPE_ASSET_STATE_VALIDATE_HEADER,
|
||||
TRUE_TYPE_ASSET_STATE_VALIDATE_VERSION,
|
||||
TRUE_TYPE_ASSET_STATE_READ_VARIANT_COUNT,
|
||||
TRUE_TYPE_ASSET_STATE_READ_VARIANT,
|
||||
TRUE_TYPE_ASSET_STATE_ADJUSTING_OFFSETS,
|
||||
TRUE_TYPE_ASSET_STATE_INIT_FREETYPE,
|
||||
TRUE_TYPE_ASSET_STATE_READY
|
||||
};
|
||||
|
||||
struct TrueTypeAssetStyle {
|
||||
flag_t style;
|
||||
size_t dataSize;
|
||||
size_t dataOffset;
|
||||
};
|
||||
|
||||
class TrueTypeAsset : public Asset {
|
||||
protected:
|
||||
UsageLock locks;
|
||||
AssetLoader loader;
|
||||
FT_Library fontLibrary;
|
||||
enum TrueTypeAssetState state = TRUE_TYPE_ASSET_STATE_INITIAL;
|
||||
std::vector<struct TrueTypeAssetStyle> assetStyles;
|
||||
std::vector<TrueTypeFaceTexture*> textures;
|
||||
std::map<usagelockid_t, TrueTypeFaceTexture*> textureByLock;
|
||||
std::map<struct TrueTypeFaceTextureStyle, TrueTypeFaceTexture*>
|
||||
textureByStyle
|
||||
;
|
||||
std::map<TrueTypeFaceTexture*, std::vector<usagelockid_t>> locksByTexture;
|
||||
|
||||
public:
|
||||
TrueTypeAsset(const std::string name);
|
||||
void updateSync() override;
|
||||
void updateAsync() override;
|
||||
|
||||
/**
|
||||
* Create a lock for a specific style. Locks will ensure that the font is
|
||||
* held loaded until it is no longer required.
|
||||
*
|
||||
* @param style Style to lock.
|
||||
* @return A unique lock ID for this style.
|
||||
*/
|
||||
usagelockid_t lock(const struct TrueTypeFaceTextureStyle style);
|
||||
|
||||
/**
|
||||
* Get a texture by a previous lock ID.
|
||||
*
|
||||
* @param lock Lock to get the texture of.
|
||||
* @return Matching texture by this ID.
|
||||
*/
|
||||
TrueTypeFaceTexture * getTexture(const usagelockid_t lock);
|
||||
|
||||
/**
|
||||
* Releases a previously held font lock.
|
||||
*
|
||||
* @param lock Lock to release/unlock.
|
||||
*/
|
||||
void unlock(const usagelockid_t lock);
|
||||
|
||||
~TrueTypeAsset();
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
IAudioManager.cpp
|
||||
)
|
@ -1,14 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "IAudioManager.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
IAudioManager::IAudioManager() {
|
||||
}
|
||||
|
||||
IAudioManager::~IAudioManager() {
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "assert/assert.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class DawnGame;
|
||||
|
||||
class IAudioManager {
|
||||
public:
|
||||
/**
|
||||
* Construct a new IAudioManager.
|
||||
*/
|
||||
IAudioManager();
|
||||
|
||||
/**
|
||||
* Initializes the audio manager system.
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Ticks/Update the audio manager system.
|
||||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
/**
|
||||
* Deinitializes the audio manager system.
|
||||
*/
|
||||
virtual ~IAudioManager();
|
||||
};
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
RenderPipeline.cpp
|
||||
Tileset.cpp
|
||||
Color.cpp
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(font)
|
||||
add_subdirectory(mesh)
|
||||
add_subdirectory(shader)
|
@ -1,83 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "util/parser/TypeParsers.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct Color Color::fromString(const std::string str) {
|
||||
// Convert to lowercase
|
||||
auto lower = stringToLowercase(str);
|
||||
|
||||
if(stringIncludes(lower, "cornflower")) {
|
||||
return COLOR_CORNFLOWER_BLUE;
|
||||
|
||||
} else if(stringIncludes(lower, "magenta")) {
|
||||
return COLOR_MAGENTA;
|
||||
|
||||
} else if(stringIncludes(lower, "white")) {
|
||||
return COLOR_WHITE;
|
||||
|
||||
} else if(stringIncludes(lower, "black")) {
|
||||
return COLOR_BLACK;
|
||||
|
||||
} else if(stringIncludes(lower, "red")) {
|
||||
return COLOR_RED;
|
||||
|
||||
} else if(stringIncludes(lower, "green")) {
|
||||
return COLOR_GREEN;
|
||||
|
||||
} else if(stringIncludes(lower, "blue")) {
|
||||
return COLOR_BLUE;
|
||||
|
||||
} else if(stringIncludes(lower, "transparent")) {
|
||||
return COLOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
// Hex code?
|
||||
if(lower[0] == '#') {
|
||||
// Remove the hash
|
||||
lower = lower.substr(1);
|
||||
|
||||
// Convert to RGB
|
||||
if(lower.length() == 3) {
|
||||
// Convert to 6 digit hex
|
||||
lower = lower[0] + lower[0] + lower[1] + lower[1] + lower[2] + lower[2];
|
||||
}
|
||||
|
||||
// Convert to RGB
|
||||
return {
|
||||
(float_t)std::stoi(lower.substr(0, 2), nullptr, 16) / 255.0f,
|
||||
(float_t)std::stoi(lower.substr(2, 2), nullptr, 16) / 255.0f,
|
||||
(float_t)std::stoi(lower.substr(4, 2), nullptr, 16) / 255.0f,
|
||||
1.0f
|
||||
};
|
||||
}
|
||||
|
||||
// Split by comma
|
||||
auto splitByComma = stringSplit(str, ",");
|
||||
if(splitByComma.size() == 3) {
|
||||
// RGB
|
||||
return {
|
||||
(float_t)std::stof(splitByComma[0]),
|
||||
(float_t)std::stof(splitByComma[1]),
|
||||
(float_t)std::stof(splitByComma[2]),
|
||||
1.0f
|
||||
};
|
||||
} else if(splitByComma.size() == 4) {
|
||||
// RGBA
|
||||
return {
|
||||
(float_t)std::stof(splitByComma[0]),
|
||||
(float_t)std::stof(splitByComma[1]),
|
||||
(float_t)std::stof(splitByComma[2]),
|
||||
(float_t)std::stof(splitByComma[3])
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Parse other kinds of colors
|
||||
assertUnreachable("Failed to find a color match for %s", str);
|
||||
return {};
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "util/string.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct ColorU8 {
|
||||
uint8_t r, g, b, a;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct Color {
|
||||
/**
|
||||
* Returns a color from a string.
|
||||
*
|
||||
* @param str String to parse.
|
||||
* @return Color parsed.
|
||||
*/
|
||||
static struct Color fromString(const std::string str);
|
||||
|
||||
float_t r, g, b, a;
|
||||
|
||||
const struct Color& operator = (const struct Color &val) {
|
||||
this->r = val.r;
|
||||
this->g = val.g;
|
||||
this->b = val.b;
|
||||
this->a = val.a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct Color operator * (const float_t &x) {
|
||||
return {
|
||||
r * x,
|
||||
g * x,
|
||||
b * x,
|
||||
a * x
|
||||
};
|
||||
}
|
||||
|
||||
struct Color operator - (const struct Color &color) {
|
||||
return {
|
||||
r - color.r,
|
||||
g - color.g,
|
||||
b - color.b,
|
||||
a - color.a
|
||||
};
|
||||
}
|
||||
|
||||
struct Color operator + (const struct Color &color) {
|
||||
return {
|
||||
r + color.r,
|
||||
g + color.g,
|
||||
b + color.b,
|
||||
a + color.a
|
||||
};
|
||||
}
|
||||
|
||||
const bool_t operator == (const struct Color &other) {
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
|
||||
operator struct ColorU8() const {
|
||||
return {
|
||||
(uint8_t)(r * 255),
|
||||
(uint8_t)(g * 255),
|
||||
(uint8_t)(b * 255),
|
||||
(uint8_t)(a * 255)
|
||||
};
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#define COLOR_DEF(r,g,b,a) { r, g, b, a }
|
||||
#define COLOR_WHITE COLOR_DEF(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
#define COLOR_RED COLOR_DEF(1.0f, 0, 0, 1.0f)
|
||||
#define COLOR_GREEN COLOR_DEF(0, 1.0f, 0, 1.0f)
|
||||
#define COLOR_BLUE COLOR_DEF(0, 0, 1.0f, 1.0f)
|
||||
#define COLOR_BLACK COLOR_DEF(0, 0, 0, 1.0f)
|
||||
#define COLOR_MAGENTA COLOR_DEF(1.0f, 0, 1.0f, 1.0f)
|
||||
#define COLOR_DARK_GREY COLOR_DEF(0.2f, 0.2f, 0.2f, 1.0f)
|
||||
#define COLOR_LIGHT_GREY COLOR_DEF(0.8f, 0.8f, 0.8f, 1.0f)
|
||||
#define COLOR_CORNFLOWER_BLUE COLOR_DEF(0.4f, 0.6f, 0.9f, 1.0f)
|
||||
#define COLOR_WHITE_TRANSPARENT COLOR_DEF(1.0f, 1.0f, 1.0f, 0.0f)
|
||||
#define COLOR_BLACK_TRANSPARENT COLOR_DEF(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
#define COLOR_TRANSPARENT COLOR_WHITE_TRANSPARENT
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/RenderTarget.hpp"
|
||||
|
||||
#define RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST FLAG_DEFINE(0)
|
||||
#define RENDER_MANAGER_RENDER_FLAG_BLEND FLAG_DEFINE(1)
|
||||
|
||||
namespace Dawn {
|
||||
class DawnGame;
|
||||
class RenderPipeline;
|
||||
class ShaderManager;
|
||||
|
||||
class IRenderManager : public std::enable_shared_from_this<IRenderManager> {
|
||||
protected:
|
||||
flag_t renderFlags = 0;
|
||||
|
||||
public:
|
||||
std::weak_ptr<DawnGame> game;
|
||||
|
||||
/**
|
||||
* Default constructor for a render manager instance.
|
||||
*
|
||||
* @param game Game that this render manager belongs to.
|
||||
*/
|
||||
IRenderManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary render target (the backbuffer) that draws directly
|
||||
* to the screen.
|
||||
*
|
||||
* @return Shared pointer to the backbuffer render target.
|
||||
*/
|
||||
virtual std::shared_ptr<RenderTarget> getBackBuffer() = 0;
|
||||
|
||||
/**
|
||||
* Returns the current render pipeline intended to be used for rendering
|
||||
* the currently active scene on the game instance.
|
||||
*
|
||||
* @return Reference to the currently active main scene render pipeline.
|
||||
*/
|
||||
virtual std::shared_ptr<RenderPipeline> getRenderPipeline() = 0;
|
||||
|
||||
/**
|
||||
* Returns the shader manager that this render manager uses.
|
||||
*
|
||||
* @return Reference to the shader manager.
|
||||
*/
|
||||
virtual std::shared_ptr<ShaderManager> getShaderManager() = 0;
|
||||
|
||||
/**
|
||||
* Sets the render flags for the render manager to use.
|
||||
*
|
||||
* @param renderFlags Render flags to use.
|
||||
*/
|
||||
virtual void setRenderFlags(const flag_t renderFlags) = 0;
|
||||
|
||||
/**
|
||||
* Initialize / Start the Render Manager.
|
||||
*
|
||||
* @param game Game instance this render manager belongs to.
|
||||
*/
|
||||
virtual void init(const std::weak_ptr<DawnGame> game) = 0;
|
||||
|
||||
/**
|
||||
* Perform a synchronous frame update on the render manager.
|
||||
*/
|
||||
virtual void update() = 0;
|
||||
|
||||
/**
|
||||
* Clean up the render manager.
|
||||
*/
|
||||
virtual ~IRenderManager() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/Color.hpp"
|
||||
#include "state/StateOwner.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum TextureFormat {
|
||||
TEXTURE_FORMAT_R = 1,
|
||||
TEXTURE_FORMAT_RG = 2,
|
||||
TEXTURE_FORMAT_RGB = 3,
|
||||
TEXTURE_FORMAT_RGBA = 4
|
||||
};
|
||||
|
||||
enum TextureWrapMode {
|
||||
TEXTURE_WRAP_MODE_REPEAT = 0,
|
||||
TEXTURE_WRAP_MODE_MIRRORED_REPEAT = 1,
|
||||
TEXTURE_WRAP_MODE_CLAMP_TO_EDGE = 2,
|
||||
TEXTURE_WRAP_MODE_CLAMP_TO_BORDER = 3
|
||||
};
|
||||
|
||||
enum TextureFilterMode {
|
||||
TEXTURE_FILTER_MODE_NEAREST = 0,
|
||||
TEXTURE_FILTER_MODE_LINEAR = 1
|
||||
};
|
||||
|
||||
enum TextureDataFormat {
|
||||
TEXTURE_DATA_FORMAT_UNSIGNED_BYTE = 0,
|
||||
TEXTURE_DATA_FORMAT_FLOAT = 1
|
||||
};
|
||||
|
||||
class ITexture : public StateOwner {
|
||||
protected:
|
||||
bool_t texturePropertiesNeedUpdating = true;
|
||||
|
||||
public:
|
||||
StateProperty<enum TextureWrapMode> wrapModeX;
|
||||
StateProperty<enum TextureWrapMode> wrapModeY;
|
||||
StateProperty<enum TextureFilterMode> filterModeMin;
|
||||
StateProperty<enum TextureFilterMode> filterModeMag;
|
||||
StateProperty<enum TextureFilterMode> mipmapFilterModeMin;
|
||||
StateProperty<enum TextureFilterMode> mipmapFilterModeMag;
|
||||
|
||||
ITexture() :
|
||||
wrapModeX(TEXTURE_WRAP_MODE_CLAMP_TO_EDGE),
|
||||
wrapModeY(TEXTURE_WRAP_MODE_CLAMP_TO_EDGE),
|
||||
filterModeMin(TEXTURE_FILTER_MODE_LINEAR),
|
||||
filterModeMag(TEXTURE_FILTER_MODE_LINEAR),
|
||||
mipmapFilterModeMin(TEXTURE_FILTER_MODE_NEAREST),
|
||||
mipmapFilterModeMag(TEXTURE_FILTER_MODE_NEAREST)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of the texture.
|
||||
*
|
||||
* @return Width of the texture.
|
||||
*/
|
||||
virtual int32_t getWidth() = 0;
|
||||
|
||||
/**
|
||||
* Returns the height of the texture.
|
||||
*
|
||||
* @return Height of the texture.
|
||||
*/
|
||||
virtual int32_t getHeight() = 0;
|
||||
|
||||
/**
|
||||
* Initializes a texture.
|
||||
*
|
||||
* @param width Width of the texture (in pixels).
|
||||
* @param height Height of the texture (in pixels).
|
||||
* @param format Data format of the texture to use.
|
||||
* @param dataFormat Data format of the texture to use.
|
||||
*/
|
||||
virtual void setSize(
|
||||
const int32_t width,
|
||||
const int32_t height,
|
||||
const enum TextureFormat format,
|
||||
const enum TextureDataFormat dataFormat
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Fill a texture with a single color. This is stupidly costly.
|
||||
*
|
||||
* @param color Color to fill.
|
||||
*/
|
||||
virtual void fill(const struct Color) = 0;
|
||||
virtual void fill(const uint8_t) = 0;
|
||||
|
||||
/**
|
||||
* Returns true only when the texture has been loaded, sized and put on
|
||||
* the gpu for rendering.
|
||||
*
|
||||
* @return True if ready, otherwise false.
|
||||
*/
|
||||
virtual bool_t isReady() = 0;
|
||||
|
||||
/**
|
||||
* Buffer pixel data onto the GPU. Pixel buffering is rather costly so
|
||||
* avoid doing this too often.
|
||||
*
|
||||
* @param pixels Array of pixels you're trying to buffer.
|
||||
* @return The amount of bytes buffered to the texture.
|
||||
*/
|
||||
virtual void buffer(const struct ColorU8 pixels[]) = 0;
|
||||
virtual void buffer(const uint8_t pixels[]) = 0;
|
||||
|
||||
virtual ~ITexture() {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "RenderPipeline.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
#include "scene/components/scene/SubSceneController.hpp"
|
||||
|
||||
#if DAWN_DEBUG_BUILD
|
||||
#include "scene/debug/SceneDebugLine.hpp"
|
||||
#endif
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
RenderPipeline::RenderPipeline() {
|
||||
}
|
||||
|
||||
void RenderPipeline::init(const std::weak_ptr<RenderManager> renderManager) {
|
||||
this->renderManager = renderManager;
|
||||
shaderBuffer.init();
|
||||
}
|
||||
|
||||
void RenderPipeline::render() {
|
||||
auto rm = renderManager.lock();
|
||||
assertNotNull(rm, "RenderManager cannot be null");
|
||||
auto game = rm->game.lock();
|
||||
assertNotNull(game, "Game cannot be null");
|
||||
|
||||
if(game->scene != nullptr) {
|
||||
renderScene(game->scene);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPipeline::renderScene(const std::shared_ptr<Scene> scene) {
|
||||
assertNotNull(scene, "Scene cannot be null");
|
||||
auto rm = renderManager.lock();
|
||||
assertNotNull(rm, "RenderManager cannot be null");
|
||||
|
||||
// Render subscenes first.
|
||||
auto subSceneControllers = scene->findComponents<SubSceneController>();
|
||||
auto itSubScene = subSceneControllers.begin();
|
||||
while(itSubScene != subSceneControllers.end()) {
|
||||
auto subScene = (*itSubScene)->subScene;
|
||||
if(subScene == nullptr) {
|
||||
++itSubScene;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(
|
||||
(*itSubScene)->onlyUpdateUnpaused &&
|
||||
scene->game.lock()->timeManager.isPaused
|
||||
) {
|
||||
++itSubScene;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderScene(subScene);
|
||||
++itSubScene;
|
||||
}
|
||||
|
||||
// Now render backbuffers.
|
||||
auto backBuffer = rm->getBackBuffer();
|
||||
auto cameras = scene->findComponents<Camera>();
|
||||
std::shared_ptr<Camera> backBufferCamera;
|
||||
|
||||
// First, render all non-backbuffer cameras.
|
||||
auto it = cameras.begin();
|
||||
while(it != cameras.end()) {
|
||||
auto cameraTarget = (*it)->getRenderTarget();
|
||||
|
||||
// Leave the backbuffer camera(s) to last, so we skip them. we do this so
|
||||
// that children framebuffers contain the CURRENT frame, not LAST frame.
|
||||
if(cameraTarget == nullptr) {
|
||||
++it;
|
||||
continue;
|
||||
} else if(cameraTarget == backBuffer) {
|
||||
backBufferCamera = *it;
|
||||
} else {
|
||||
renderSceneCamera(scene, *it);
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
// Now render the backbuffer camera.
|
||||
if(backBufferCamera == nullptr) return;
|
||||
renderSceneCamera(scene, backBufferCamera);
|
||||
}
|
||||
|
||||
void RenderPipeline::renderSceneCamera(
|
||||
const std::shared_ptr<Scene> scene,
|
||||
const std::shared_ptr<Camera> camera
|
||||
) {
|
||||
auto rm = renderManager.lock();
|
||||
assertNotNull(rm, "RenderManager cannot be null");
|
||||
|
||||
std::vector<struct ShaderPassItem>::iterator itPassItem;
|
||||
|
||||
assertNotNull(scene, "Scene cannot be null");
|
||||
assertNotNull(camera, "Camera cannot be null");
|
||||
|
||||
// Create a new render ID. Long story short this is a really dirty way of
|
||||
// not sending parameters to shaders more than we need.
|
||||
renderId--;
|
||||
|
||||
// Get the render target.
|
||||
auto renderTarget = camera->getRenderTarget();
|
||||
assertNotNull(renderTarget, "Camera must have a render target");
|
||||
|
||||
// Update shader parameter buffers with current knowledge
|
||||
struct RenderPipelineShaderBufferData shaderBufferData;
|
||||
shaderBufferData.projection = camera->getProjection();
|
||||
shaderBufferData.view = camera->item.lock()->getWorldTransform();
|
||||
shaderBuffer.buffer(&shaderBufferData);
|
||||
|
||||
// Prepare a render context. This is just a nice way of letting renderables
|
||||
// know a bit about what is happening, they can choose to use this data to
|
||||
// render themselves differently.
|
||||
struct IRenderableContext context = {
|
||||
scene,
|
||||
camera,
|
||||
shared_from_this()
|
||||
};
|
||||
|
||||
// Get the list of things to render first.
|
||||
std::vector<struct ShaderPassItem> shaderPassItems;
|
||||
|
||||
// Renderables
|
||||
auto renderables = scene->findComponents<IRenderable>();
|
||||
auto itRenderables = renderables.begin();
|
||||
while(itRenderables != renderables.end()) {
|
||||
vectorAppend(shaderPassItems, (*itRenderables)->getRenderPasses(context));
|
||||
++itRenderables;
|
||||
}
|
||||
|
||||
// Inject index into each item
|
||||
itPassItem = shaderPassItems.begin();
|
||||
while(itPassItem != shaderPassItems.end()) {
|
||||
itPassItem->index = itPassItem;
|
||||
++itPassItem;
|
||||
}
|
||||
|
||||
// Now we've queued everything, let's sort the rendering queue by the priority
|
||||
std::sort(
|
||||
shaderPassItems.begin(),
|
||||
shaderPassItems.end(),
|
||||
[](struct ShaderPassItem &a, struct ShaderPassItem &b) {
|
||||
if(a.priority == b.priority) {
|
||||
// Compare indexes if w is same.
|
||||
if(a.w == b.w) return a.index < b.index;
|
||||
return a.w < b.w;
|
||||
}
|
||||
return a.priority < b.priority;
|
||||
}
|
||||
);
|
||||
|
||||
// Now we've sorted everything! Let's actually start rendering.
|
||||
std::shared_ptr<Shader> boundShader;
|
||||
std::map<textureslot_t, Texture*> boundTextures;
|
||||
std::map<shaderbufferlocation_t, shaderbufferslot_t> boundBuffers;
|
||||
shaderbufferslot_t slot;
|
||||
|
||||
// TODO: This will be editable!
|
||||
renderTarget->bind();
|
||||
renderTarget->clear(
|
||||
RENDER_TARGET_CLEAR_FLAG_DEPTH |
|
||||
RENDER_TARGET_CLEAR_FLAG_COLOR
|
||||
);
|
||||
|
||||
// Shader items
|
||||
itPassItem = shaderPassItems.begin();
|
||||
while(itPassItem != shaderPassItems.end()) {
|
||||
auto item = *itPassItem;
|
||||
|
||||
// Bind the program.
|
||||
if(boundShader != item.shader) {
|
||||
boundShader = item.shader;
|
||||
boundShader->bind();
|
||||
}
|
||||
|
||||
// Bind the textures to the slots
|
||||
auto itTextureSlot = item.textureSlots.begin();
|
||||
while(itTextureSlot != item.textureSlots.end()) {
|
||||
// Assert texture isn't null, just don't include it.
|
||||
assertNotNull(itTextureSlot->second, "Texture cannot be null (omit)");
|
||||
|
||||
if(boundTextures[itTextureSlot->first] != itTextureSlot->second) {
|
||||
itTextureSlot->second->bind(itTextureSlot->first);
|
||||
boundTextures[itTextureSlot->first] = itTextureSlot->second;
|
||||
}
|
||||
++itTextureSlot;
|
||||
}
|
||||
|
||||
// Bind the buffers to their slots
|
||||
slot = 0;
|
||||
auto itBufferSlot = item.parameterBuffers.begin();
|
||||
while(itBufferSlot != item.parameterBuffers.end()) {
|
||||
auto location = itBufferSlot->first;
|
||||
auto buff = itBufferSlot->second;
|
||||
boundBuffers[itBufferSlot->first] = slot;
|
||||
buff->bind(slot);
|
||||
slot++;
|
||||
++itBufferSlot;
|
||||
}
|
||||
|
||||
// Now set each of the parameters. Nothing exciting here.
|
||||
auto itColors = item.colorValues.begin();
|
||||
while(itColors != item.colorValues.end()) {
|
||||
item.shader->setColor(itColors->first, itColors->second);
|
||||
++itColors;
|
||||
}
|
||||
|
||||
auto itBool = item.boolValues.begin();
|
||||
while(itBool != item.boolValues.end()) {
|
||||
item.shader->setBoolean(itBool->first, itBool->second);
|
||||
++itBool;
|
||||
}
|
||||
|
||||
auto itMat = item.matrixValues.begin();
|
||||
while(itMat != item.matrixValues.end()) {
|
||||
item.shader->setMatrix(itMat->first, itMat->second);
|
||||
++itMat;
|
||||
}
|
||||
|
||||
auto itVec3 = item.vec3Values.begin();
|
||||
while(itVec3 != item.vec3Values.end()) {
|
||||
item.shader->setVector3(itVec3->first, itVec3->second);
|
||||
++itVec3;
|
||||
}
|
||||
|
||||
auto itText = item.textureValues.begin();
|
||||
while(itText != item.textureValues.end()) {
|
||||
item.shader->setTexture(itText->first, itText->second);
|
||||
++itText;
|
||||
}
|
||||
|
||||
auto itBuffer = item.parameterBuffers.begin();
|
||||
while(itBuffer != item.parameterBuffers.end()) {
|
||||
item.shader->setParameterBuffer(
|
||||
itBuffer->first, boundBuffers[itBuffer->first]
|
||||
);
|
||||
++itBuffer;
|
||||
}
|
||||
|
||||
auto itFloat = item.floatValues.begin();
|
||||
while(itFloat != item.floatValues.end()) {
|
||||
item.shader->setFloat(itFloat->first, itFloat->second);
|
||||
++itFloat;
|
||||
}
|
||||
|
||||
// Set Render flags
|
||||
rm->setRenderFlags(item.renderFlags);
|
||||
|
||||
// Thank god that's done, now just draw the damn mesh.
|
||||
item.mesh->draw(item.drawMode, item.start, item.count);
|
||||
++itPassItem;
|
||||
}
|
||||
}
|
||||
|
||||
RenderPipeline::~RenderPipeline() {
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/IRenderManager.hpp"
|
||||
#include "display/shader/ShaderPass.hpp"
|
||||
#include "scene/components/display/IRenderable.hpp"
|
||||
#include "display/shader/buffers/RenderPipelineShaderBuffer.hpp"
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class RenderManager;
|
||||
|
||||
class RenderPipeline : public std::enable_shared_from_this<RenderPipeline> {
|
||||
private:
|
||||
int_fast16_t renderId = -1;
|
||||
|
||||
public:
|
||||
std::weak_ptr<RenderManager> renderManager;
|
||||
RenderPipelineShaderBuffer shaderBuffer;
|
||||
|
||||
/**
|
||||
* Constructs a new RenderPipeline. Render Pipelines are my attempt to
|
||||
* create both a flexible, but standard way to allow the individual games
|
||||
* to decide how they want to render the common scene-item models.
|
||||
*/
|
||||
RenderPipeline();
|
||||
|
||||
/**
|
||||
* Initialize the render pipeline.
|
||||
*
|
||||
* @param renderManager Parent render manager this pipeline belongs to.
|
||||
*/
|
||||
virtual void init(const std::weak_ptr<RenderManager> renderManager);
|
||||
|
||||
/**
|
||||
* Renders the games' currently active scene, and all of its' cameras.
|
||||
*/
|
||||
virtual void render();
|
||||
|
||||
/**
|
||||
* Render a specific scene, usually just called for the currently active
|
||||
* scene, but in future this could include sub-scenes.
|
||||
*
|
||||
* @param scene Scene to render.
|
||||
*/
|
||||
virtual void renderScene(const std::shared_ptr<Scene> scene);
|
||||
|
||||
/**
|
||||
* Render a specific camera on a specific scene.
|
||||
*
|
||||
* @param scene Scene to render.
|
||||
* @param camera Camera within the scene to render.
|
||||
*/
|
||||
virtual void renderSceneCamera(
|
||||
const std::shared_ptr<Scene> scene,
|
||||
const std::shared_ptr<Camera> camera
|
||||
);
|
||||
|
||||
/**
|
||||
* Cleanup a render pipeline that has been initialized.
|
||||
*/
|
||||
virtual ~RenderPipeline();
|
||||
};
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "util/flag.hpp"
|
||||
#include "display/Color.hpp"
|
||||
#include "state/StateEvent.hpp"
|
||||
|
||||
#define RENDER_TARGET_CLEAR_FLAG_COLOR FLAG_DEFINE(0)
|
||||
#define RENDER_TARGET_CLEAR_FLAG_DEPTH FLAG_DEFINE(1)
|
||||
|
||||
namespace Dawn {
|
||||
class RenderTarget {
|
||||
public:
|
||||
StateEvent<
|
||||
RenderTarget&,
|
||||
const float_t,
|
||||
const float_t
|
||||
> eventRenderTargetResized;
|
||||
|
||||
/**
|
||||
* Return the width of the render target.
|
||||
*
|
||||
* @return The width of the render target.
|
||||
*/
|
||||
virtual float_t getWidth() = 0;
|
||||
|
||||
/**
|
||||
* Return the height of the render target.
|
||||
*
|
||||
* @return The height of the render target.
|
||||
*/
|
||||
virtual float_t getHeight() = 0;
|
||||
|
||||
/**
|
||||
* Returns the scale (as in pixel density) of the render target. This is
|
||||
* typically 1.0f, but on high DPI displays this may be 2.0f or higher.
|
||||
*
|
||||
* @return The scale of the render target.
|
||||
*/
|
||||
virtual float_t getScale() = 0;
|
||||
|
||||
/**
|
||||
* Sets the clear color of the render target when the clear method for
|
||||
* the color buffer is requested.
|
||||
*
|
||||
* @param color Color to use for the clear operation.
|
||||
*/
|
||||
virtual void setClearColor(const struct Color color) = 0;
|
||||
|
||||
/**
|
||||
* Request the existing data in the render target to be cleared out. We
|
||||
* typically assume the render target can support multiple buffer types,
|
||||
* so you can opt to only clear certain buffer types.
|
||||
*
|
||||
* @param clearFlags Flags to request what is going to be cleared.
|
||||
*/
|
||||
virtual void clear(const flag8_t clearFlags) = 0;
|
||||
|
||||
/**
|
||||
* Bind the render target for rendering to. The proceeding render requests
|
||||
* will want to render to this render target directly. In future I may
|
||||
* see if we can have multiple render targets bound at once to make this
|
||||
* operation perform faster.
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
};
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Tileset.hpp"
|
||||
#include "assert/assert.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct Tile Tileset::getTile(const int32_t tile) {
|
||||
assertTrue(tile >= 0, "Tile must be greater than or equal to 0");
|
||||
assertTrue(tile < this->tiles.size(), "Tile is out of bounds");
|
||||
return this->tiles[tile];
|
||||
}
|
||||
|
||||
TilesetGrid::TilesetGrid() {
|
||||
|
||||
}
|
||||
|
||||
TilesetGrid::TilesetGrid(
|
||||
Texture &texture,
|
||||
const int32_t columns,
|
||||
const int32_t rows
|
||||
) : TilesetGrid(
|
||||
columns, rows,
|
||||
texture.getWidth(), texture.getHeight(),
|
||||
0, 0,
|
||||
0, 0
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
TilesetGrid::TilesetGrid(
|
||||
const int32_t columns,
|
||||
const int32_t rows,
|
||||
const int32_t w,
|
||||
const int32_t h,
|
||||
const int32_t gapX,
|
||||
const int32_t gapY,
|
||||
const int32_t borderX,
|
||||
const int32_t borderY
|
||||
) {
|
||||
assertTrue(columns >= 1, "Columns must be greater than or equal to 1");
|
||||
assertTrue(rows >= 1, "Rows must be greater than or equal to 1");
|
||||
assertTrue(w >= 1, "Width must be greater than or equal to 1");
|
||||
assertTrue(h >= 1, "Height must be greater than or equal to 1");
|
||||
assertTrue(gapX >= 0, "GapX must be greater than or equal to 0");
|
||||
assertTrue(gapY >= 0, "GapY must be greater than or equal to 0");
|
||||
assertTrue(borderX >= 0, "BorderX must be greater than or equal to 0");
|
||||
assertTrue(borderY >= 0, "BorderY must be greater than or equal to 0");
|
||||
assertTrue(w >= (columns + (gapX * columns) + borderX + borderX), "Width is too small");
|
||||
assertTrue(h >= (rows + (gapY * rows) + borderY + borderY), "Height is too small");
|
||||
|
||||
this->rows = rows;
|
||||
this->columns = columns;
|
||||
|
||||
// Calculate division sizes (pixels)
|
||||
this->divX = (w - (borderX * 2) - (gapX * (columns - 1))) / columns;
|
||||
this->divY = (h - (borderY * 2) - (gapY * (rows - 1))) / rows;
|
||||
|
||||
// Calculate the division sizes (units)
|
||||
const float_t tdivX = (float_t)this->divX / (float_t)w;
|
||||
const float_t tdivY = (float_t)this->divY / (float_t)h;
|
||||
|
||||
struct Tile tile;
|
||||
for(int32_t y = 0; y < rows; y++) {
|
||||
for(int32_t x = 0; x < columns; x++) {
|
||||
tile.uv0.x = (borderX + ((float_t)this->divX * x) + (gapX * x)) / w;
|
||||
tile.uv1.x = tile.uv0.x + tdivX;
|
||||
|
||||
tile.uv0.y = (borderY + ((float_t)this->divY * y) + (gapY * y)) / h;
|
||||
tile.uv1.y = tile.uv0.y + tdivY;
|
||||
this->tiles.push_back(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_t TilesetGrid::getTileWidth(const int32_t tile) {
|
||||
return this->divX;
|
||||
}
|
||||
|
||||
float_t TilesetGrid::getTileHeight(const int32_t tile) {
|
||||
return this->divY;
|
||||
}
|
||||
|
||||
struct Tile TilesetGrid::getTileFromGrid(
|
||||
const int32_t column,
|
||||
const int32_t row
|
||||
) {
|
||||
assertTrue(row > 0 && row < this->rows, "Row is out of bounds");
|
||||
assertTrue(column > 0 && column < this->columns, "Column is out of bounds");
|
||||
return this->getTile(row + (column * this->rows));
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "display/Texture.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct Tile {
|
||||
glm::vec2 uv0;
|
||||
glm::vec2 uv1;
|
||||
};
|
||||
|
||||
struct Tileset {
|
||||
public:
|
||||
std::vector<struct Tile> tiles;
|
||||
|
||||
/**
|
||||
* Returns the tile at the given tile index.
|
||||
*
|
||||
* @param tile Tile index to get.
|
||||
* @return Tile at that index.
|
||||
*/
|
||||
struct Tile getTile(const int32_t tile);
|
||||
|
||||
/**
|
||||
* Returns the width of an individual tile.
|
||||
*
|
||||
* @param tile The tile to get the width of.
|
||||
* @return The tile width.
|
||||
*/
|
||||
virtual float_t getTileWidth(const int32_t tile) = 0;
|
||||
|
||||
/**
|
||||
* Returns the height of an individual tile.
|
||||
*
|
||||
* @param tile The tile to get the height of.
|
||||
* @return The tile height.
|
||||
*/
|
||||
virtual float_t getTileHeight(const int32_t tile) = 0;
|
||||
};
|
||||
|
||||
struct TilesetGrid : public Tileset{
|
||||
public:
|
||||
int32_t rows;
|
||||
int32_t columns;
|
||||
int32_t divX;
|
||||
int32_t divY;
|
||||
|
||||
/**
|
||||
* Constructs a new Tileset Grid.
|
||||
*/
|
||||
TilesetGrid();
|
||||
|
||||
/**
|
||||
* Constructs a new Tileset Grid from a texture.
|
||||
*
|
||||
* @param texture Texture to use.
|
||||
* @param columns Columns in the grid.
|
||||
* @param rows Rows in the grid.
|
||||
*/
|
||||
TilesetGrid(
|
||||
Texture &texture,
|
||||
const int32_t columns,
|
||||
const int32_t rows
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructs a new Tileset Grid.
|
||||
*
|
||||
* @param columns How many columns in the grid of tiles.
|
||||
* @param rows How many rows in the grid of tiles.
|
||||
* @param w Width of the grid.
|
||||
* @param h Height of te grid.
|
||||
* @param gapX Gap / Gutter between tiles.
|
||||
* @param gapY Gap / Gutter between tiles.
|
||||
* @param borderX Border at the edge of the grid before the first tiles.
|
||||
* @param borderY Border at the edge of the grid before the first tiles.
|
||||
*/
|
||||
TilesetGrid(
|
||||
const int32_t columns,
|
||||
const int32_t rows,
|
||||
const int32_t w,
|
||||
const int32_t h,
|
||||
const int32_t gapX,
|
||||
const int32_t gapY,
|
||||
const int32_t borderX,
|
||||
const int32_t borderY
|
||||
);
|
||||
|
||||
float_t getTileWidth(const int32_t tile) override;
|
||||
float_t getTileHeight(const int32_t tile) override;
|
||||
|
||||
/**
|
||||
* Returns the tile at a given grid position.
|
||||
*
|
||||
* @param column Column (0 indexed) to get the tile of.
|
||||
* @param row Row (0 indexed) to get the tile of.
|
||||
* @return Tile at this grid position.
|
||||
*/
|
||||
struct Tile getTileFromGrid(const int32_t column, const int32_t row);
|
||||
};
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(truetype)
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
TrueTypeFaceTexture.cpp
|
||||
)
|
@ -1,109 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "TrueTypeFaceTexture.hpp"
|
||||
#include "util/memory.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
TrueTypeFaceTexture::TrueTypeFaceTexture(
|
||||
const FT_Face face,
|
||||
const struct TrueTypeFaceTextureStyle style
|
||||
) :
|
||||
face(face),
|
||||
style(style)
|
||||
{
|
||||
assertTrue(style.fontSize < 256, "Font size cannot be greater than 256");
|
||||
|
||||
// Set freetype font size prior to baking.
|
||||
if(FT_Set_Pixel_Sizes(face, 0, style.fontSize)) {
|
||||
assertUnreachable("Failed to set font size");
|
||||
}
|
||||
|
||||
size_t w = 0, h = 0;
|
||||
FT_ULong c;
|
||||
|
||||
// First pass, determine the textures' dimensions.
|
||||
for(c = TRUE_TYPE_CHAR_BEGIN; c < TRUE_TYPE_CHAR_END; c++) {
|
||||
// Load the character
|
||||
auto ret = FT_Load_Char(face, c, ~FT_LOAD_RENDER);
|
||||
if(ret) {
|
||||
assertUnreachable("Failed to load character (0)");
|
||||
}
|
||||
|
||||
if(face->glyph->bitmap.width == 0 || face->glyph->bitmap.rows == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Update the width and height
|
||||
w = mathMax<size_t>(w, face->glyph->bitmap.width);
|
||||
h += face->glyph->bitmap.rows;
|
||||
}
|
||||
|
||||
assertTrue(w > 0, "Width cannot be less than or equal to 0");
|
||||
assertTrue(h > 0, "Height cannot be less than or equal to 0");
|
||||
|
||||
// Now buffer pixels to the texture
|
||||
float_t y = 0;
|
||||
|
||||
// I'd love to just buffer straight to the GPU, but it seems that is a bit
|
||||
// unstable right now.
|
||||
uint8_t *buffer = (uint8_t *)memoryAllocateEmpty(w * h, sizeof(uint8_t));
|
||||
|
||||
size_t offset = 0;
|
||||
for(c = TRUE_TYPE_CHAR_BEGIN; c < TRUE_TYPE_CHAR_END; c++) {
|
||||
// Load the character
|
||||
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
||||
assertUnreachable("Failed to load character (1)");
|
||||
}
|
||||
|
||||
// Store the character information
|
||||
const struct TrueTypeCharacter info = {
|
||||
.advanceX = (float_t)(face->glyph->advance.x >> 6),
|
||||
.advanceY = (float_t)(face->glyph->advance.y >> 6),
|
||||
.bitmapSize = glm::vec2(
|
||||
face->glyph->bitmap.width,
|
||||
face->glyph->bitmap.rows
|
||||
),
|
||||
.bitmapPosition = glm::vec2(
|
||||
face->glyph->bitmap_left,
|
||||
-face->glyph->bitmap_top
|
||||
),
|
||||
.textureY = y
|
||||
};
|
||||
this->characterData[c] = info;
|
||||
|
||||
// Buffer the pixels, oh dear GOD there has to be a more efficient way.
|
||||
for(int32_t i = 0; i < face->glyph->bitmap.rows; i++) {
|
||||
memoryCopy(
|
||||
(void *)(face->glyph->bitmap.buffer + (i * face->glyph->bitmap.width)),
|
||||
(void *)(buffer + offset),
|
||||
face->glyph->bitmap.width * sizeof(uint8_t)
|
||||
);
|
||||
offset += w * sizeof(uint8_t);
|
||||
assertTrue(offset <= (w * h * sizeof(uint8_t)), "Buffer overflow");
|
||||
}
|
||||
y += face->glyph->bitmap.rows;
|
||||
}
|
||||
|
||||
this->texture.setSize(
|
||||
w, h,
|
||||
TEXTURE_FORMAT_R,
|
||||
TEXTURE_DATA_FORMAT_UNSIGNED_BYTE
|
||||
);
|
||||
this->texture.buffer(buffer);
|
||||
memoryFree(buffer);
|
||||
}
|
||||
|
||||
struct TrueTypeCharacter TrueTypeFaceTexture::getCharacterData(
|
||||
const FT_ULong c
|
||||
) {
|
||||
return this->characterData[c];
|
||||
}
|
||||
|
||||
TrueTypeFaceTexture::~TrueTypeFaceTexture() {
|
||||
FT_Done_Face(this->face);
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include "util/flag.hpp"
|
||||
#include "display/Texture.hpp"
|
||||
|
||||
#define TRUE_TYPE_CHAR_BEGIN 0x00
|
||||
#define TRUE_TYPE_CHAR_END 0xFF
|
||||
|
||||
#define TRUE_TYPE_VARIANT_BOLD FLAG_DEFINE(0)
|
||||
#define TRUE_TYPE_VARIANT_ITALICS FLAG_DEFINE(1)
|
||||
|
||||
#define TRUE_TYPE_DECORATION_STRIKETHROUGH FLAG_DEFINE(0)
|
||||
#define TRUE_TYPE_DECORATION_UNDERLINE FLAG_DEFINE(1)
|
||||
|
||||
namespace Dawn {
|
||||
class TrueTypeAsset;
|
||||
|
||||
struct TrueTypeCharacter {
|
||||
float_t advanceX;
|
||||
float_t advanceY;
|
||||
glm::vec2 bitmapSize;
|
||||
glm::vec2 bitmapPosition;
|
||||
float_t textureY;
|
||||
};
|
||||
|
||||
struct TrueTypeFaceTextureStyle {
|
||||
uint32_t fontSize;
|
||||
flag_t style;
|
||||
|
||||
/**
|
||||
* Overload for the less than operator.
|
||||
*
|
||||
* @param r Right hand side of the operator.
|
||||
* @return True if the left hand side is less than the right hand side.
|
||||
*/
|
||||
bool operator < (const struct TrueTypeFaceTextureStyle& r) const {
|
||||
return std::tie(fontSize, style) < std::tie(r.fontSize, r.style);
|
||||
}
|
||||
};
|
||||
|
||||
class TrueTypeFaceTexture {
|
||||
public:
|
||||
const FT_Face face;
|
||||
const struct TrueTypeFaceTextureStyle style;
|
||||
std::map<FT_ULong, struct TrueTypeCharacter> characterData;
|
||||
Texture texture;
|
||||
|
||||
/**
|
||||
* Construct a new New True Type Face Texture object
|
||||
*
|
||||
* @param face The freetype face object.
|
||||
* @param style Style that this font has, used for locking.
|
||||
*/
|
||||
TrueTypeFaceTexture(
|
||||
const FT_Face face,
|
||||
const struct TrueTypeFaceTextureStyle style
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the character data for the given character.
|
||||
*
|
||||
* @param c Character to get data for.
|
||||
* @return The Character data for the given character.
|
||||
*/
|
||||
struct TrueTypeCharacter getCharacterData(const FT_ULong c);
|
||||
|
||||
/**
|
||||
* Destroys this true type face texture.
|
||||
*/
|
||||
virtual ~TrueTypeFaceTexture();
|
||||
|
||||
friend class TrueTypeAsset;
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
CapsuleMesh.cpp
|
||||
CubeMesh.cpp
|
||||
TriangleMesh.cpp
|
||||
QuadMesh.cpp
|
||||
SphereMesh.cpp
|
||||
)
|
@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "CapsuleMesh.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void CapsuleMesh::calculateRing(
|
||||
const int32_t segments,
|
||||
const float_t height,
|
||||
const float_t radius,
|
||||
const float_t dr,
|
||||
const float_t y,
|
||||
const float_t dy,
|
||||
std::vector<glm::vec3> &positions
|
||||
) {
|
||||
float_t segIncr = 1.0f / (float_t)(segments - 1);
|
||||
for(int32_t s = 0; s < segments; s++ ) {
|
||||
float_t x = cosf(MATH_PI * 2 * s * segIncr) * dr;
|
||||
float_t z = sinf(MATH_PI * 2 * s * segIncr) * dr;
|
||||
positions.emplace_back(glm::vec3(radius * x, radius * y + height * dy, radius * z ));
|
||||
}
|
||||
}
|
||||
|
||||
void CapsuleMesh::create(
|
||||
Mesh &mesh,
|
||||
const float_t radius,
|
||||
const float_t height
|
||||
) {
|
||||
std::vector<glm::vec3> positions;
|
||||
std::vector<meshindice_t> indices;
|
||||
|
||||
const int32_t slices = 12;
|
||||
const int32_t segments = 12;
|
||||
const int32_t ringsBody = slices + 1;
|
||||
const int32_t ringsTotal = slices + ringsBody;
|
||||
|
||||
positions.reserve(segments * ringsTotal);
|
||||
indices.reserve((segments - 1) * (ringsTotal - 1) * 6);
|
||||
|
||||
const float_t bodyIncr = 1.0f / (float_t)(ringsBody - 1);
|
||||
const float_t ringIncr = 1.0f / (float_t)(slices - 1);
|
||||
for(int32_t r = 0; r < slices / 2; r++) {
|
||||
calculateRing(
|
||||
segments,
|
||||
height,
|
||||
radius,
|
||||
sinf(MATH_PI * r * ringIncr),
|
||||
sinf(MATH_PI * (r * ringIncr - 0.5f)),
|
||||
-0.5f,
|
||||
positions
|
||||
);
|
||||
}
|
||||
|
||||
for(int32_t r = 0; r < ringsBody; r++ ) {
|
||||
calculateRing(
|
||||
segments,
|
||||
height,
|
||||
radius,
|
||||
1.0f,
|
||||
0.0f,
|
||||
r * bodyIncr - 0.5f,
|
||||
positions
|
||||
);
|
||||
}
|
||||
|
||||
for(int32_t r = slices / 2; r < slices; r++) {
|
||||
calculateRing(
|
||||
segments,
|
||||
height,
|
||||
radius,
|
||||
sinf(MATH_PI * r * ringIncr),
|
||||
sinf(MATH_PI * (r * ringIncr - 0.5f)),
|
||||
0.5f,
|
||||
positions
|
||||
);
|
||||
}
|
||||
|
||||
for(int32_t r = 0; r < ringsTotal - 1; r++ ) {
|
||||
for(int32_t s = 0; s < segments - 1; s++ ) {
|
||||
indices.push_back( (uint32_t)(r * segments + ( s + 1 )) );
|
||||
indices.push_back( (uint32_t)(r * segments + ( s + 0 )) );
|
||||
indices.push_back( (uint32_t)(( r + 1 ) * segments + ( s + 1 )) );
|
||||
|
||||
indices.push_back( (uint32_t)(( r + 1 ) * segments + ( s + 0 )) );
|
||||
indices.push_back( (uint32_t)(( r + 1 ) * segments + ( s + 1 )) );
|
||||
indices.push_back( (uint32_t)(r * segments + s) );
|
||||
}
|
||||
}
|
||||
|
||||
mesh.createBuffers(positions.size(), indices.size());
|
||||
mesh.bufferPositions(0, positions.data(), positions.size());
|
||||
mesh.bufferIndices(0, indices.data(), indices.size());
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class CapsuleMesh {
|
||||
protected:
|
||||
/**
|
||||
* Calculates a ring of vertices within a capsule.
|
||||
*
|
||||
* @param segments Count of segments in the ring.
|
||||
* @param height Height of the ring.
|
||||
* @param radius Radius of the ring.
|
||||
* @param dr The delta radius of the ring.
|
||||
* @param y The y position of the ring.
|
||||
* @param dy The delta y position of the ring.
|
||||
* @param positions The positions vector to push the positions to.
|
||||
*/
|
||||
static void calculateRing(
|
||||
const int32_t segments,
|
||||
const float_t height,
|
||||
const float_t radius,
|
||||
const float_t dr,
|
||||
const float_t y,
|
||||
const float_t dy,
|
||||
std::vector<glm::vec3> &positions
|
||||
);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a capsule mesh.
|
||||
*
|
||||
* @param mesh Mesh to instanciate.
|
||||
* @param radius Radius of the capsule.
|
||||
* @param height Height of the capsule.
|
||||
*/
|
||||
static void create(
|
||||
Mesh &mesh,
|
||||
const float_t radius,
|
||||
const float_t height
|
||||
);
|
||||
};
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "CubeMesh.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void CubeMesh::buffer(
|
||||
Mesh &mesh,
|
||||
const glm::vec3 pos,
|
||||
const glm::vec3 size,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
) {
|
||||
glm::vec3 positions[CUBE_VERTICE_COUNT] = {
|
||||
pos,
|
||||
glm::vec3(pos.x+size.x, pos.y, pos.z),
|
||||
glm::vec3(pos.x, pos.y+size.y, pos.z),
|
||||
glm::vec3(pos.x+size.x, pos.y+size.y, pos.z),
|
||||
|
||||
glm::vec3(pos.x, pos.y, pos.z+size.z),
|
||||
glm::vec3(pos.x+size.x, pos.y, pos.z+size.z),
|
||||
glm::vec3(pos.x, pos.y+size.y, pos.z+size.z),
|
||||
pos + size
|
||||
};
|
||||
|
||||
glm::vec2 coordinates[CUBE_VERTICE_COUNT] = {
|
||||
glm::vec2(0, 0),
|
||||
glm::vec2(1, 0),
|
||||
glm::vec2(0, 1),
|
||||
glm::vec2(1, 1),
|
||||
|
||||
glm::vec2(0, 0),
|
||||
glm::vec2(1, 0),
|
||||
glm::vec2(0, 1),
|
||||
glm::vec2(1, 1)
|
||||
};
|
||||
|
||||
meshindice_t indices[CUBE_INDICE_COUNT] = {
|
||||
// Back
|
||||
verticeStart, verticeStart + 1, verticeStart + 3,
|
||||
verticeStart, verticeStart + 2, verticeStart + 3,
|
||||
|
||||
// Right
|
||||
verticeStart + 1, verticeStart + 5, verticeStart + 7,
|
||||
verticeStart + 1, verticeStart + 3, verticeStart + 7,
|
||||
|
||||
// Left
|
||||
verticeStart + 4, verticeStart, verticeStart + 2,
|
||||
verticeStart + 4, verticeStart + 6, verticeStart + 2,
|
||||
|
||||
// Front
|
||||
verticeStart + 5, verticeStart + 4, verticeStart + 6,
|
||||
verticeStart + 5, verticeStart + 7, verticeStart + 6,
|
||||
|
||||
// Top
|
||||
verticeStart + 7, verticeStart + 2, verticeStart + 6,
|
||||
verticeStart + 7, verticeStart + 3, verticeStart + 2,
|
||||
|
||||
// Bottom
|
||||
verticeStart + 1, verticeStart, verticeStart + 4,
|
||||
verticeStart + 1, verticeStart + 4, verticeStart + 5
|
||||
};
|
||||
|
||||
mesh.bufferPositions(verticeStart, positions, CUBE_VERTICE_COUNT);
|
||||
mesh.bufferCoordinates(verticeStart, coordinates, CUBE_VERTICE_COUNT);
|
||||
mesh.bufferIndices(indiceStart, indices, CUBE_INDICE_COUNT);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
#define CUBE_VERTICE_COUNT 8
|
||||
#define CUBE_INDICE_COUNT 36
|
||||
|
||||
namespace Dawn {
|
||||
class CubeMesh {
|
||||
public:
|
||||
/**
|
||||
* Buffers cube mesh vertices onto a mesh.
|
||||
*
|
||||
* @param mesh Mesh to buffer onto.
|
||||
* @param pos Position of the cube.
|
||||
* @param size Size of the cube.
|
||||
* @param verticeStart Starting vertice index.
|
||||
* @param indiceStart Starting indice index.
|
||||
*/
|
||||
static void buffer(
|
||||
Mesh &mesh,
|
||||
const glm::vec3 pos,
|
||||
const glm::vec3 size,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
);
|
||||
};
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "QuadMesh.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void QuadMesh::bufferQuadMeshWithZ(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const float_t z,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
) {
|
||||
glm::vec3 positions[QUAD_VERTICE_COUNT] = {
|
||||
glm::vec3(xy0, z),
|
||||
glm::vec3(xy1.x, xy0.y, z),
|
||||
glm::vec3(xy0.x, xy1.y, z),
|
||||
glm::vec3(xy1, z)
|
||||
};
|
||||
glm::vec2 coordinates[QUAD_VERTICE_COUNT] = {
|
||||
uv0, glm::vec2(uv1.x, uv0.y),
|
||||
glm::vec2(uv0.x, uv1.y), uv1
|
||||
};
|
||||
meshindice_t indices[QUAD_INDICE_COUNT] = {
|
||||
verticeStart, verticeStart + 1, verticeStart + 2,
|
||||
verticeStart + 1, verticeStart + 2, verticeStart + 3
|
||||
};
|
||||
|
||||
mesh.bufferPositions(verticeStart, positions, QUAD_VERTICE_COUNT);
|
||||
mesh.bufferCoordinates(verticeStart, coordinates, QUAD_VERTICE_COUNT);
|
||||
mesh.bufferIndices(indiceStart, indices, QUAD_INDICE_COUNT);
|
||||
}
|
||||
|
||||
void QuadMesh::bufferQuadMesh(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
) {
|
||||
QuadMesh::bufferQuadMeshWithZ(
|
||||
mesh, xy0, uv0, xy1, uv1, 0, verticeStart, indiceStart
|
||||
);
|
||||
}
|
||||
|
||||
void QuadMesh::bufferCoordinates(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 uv1,
|
||||
const int32_t verticeStart
|
||||
) {
|
||||
glm::vec2 coordinates[QUAD_VERTICE_COUNT] = {
|
||||
uv0, glm::vec2(uv1.x, uv0.y),
|
||||
glm::vec2(uv0.x, uv1.y), uv1
|
||||
};
|
||||
mesh.bufferCoordinates(verticeStart, coordinates, QUAD_VERTICE_COUNT);
|
||||
}
|
||||
|
||||
void QuadMesh::bufferPositions(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 xy1,
|
||||
const int32_t verticeStart
|
||||
) {
|
||||
glm::vec3 positions[QUAD_VERTICE_COUNT] = {
|
||||
glm::vec3(xy0, 0),
|
||||
glm::vec3(xy1.x, xy0.y, 0),
|
||||
glm::vec3(xy0.x, xy1.y, 0),
|
||||
glm::vec3(xy1, 0)
|
||||
};
|
||||
mesh.bufferPositions(verticeStart, positions, QUAD_VERTICE_COUNT);
|
||||
}
|
||||
|
||||
void QuadMesh::initQuadMesh(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const float_t z
|
||||
) {
|
||||
mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
|
||||
QuadMesh::bufferQuadMeshWithZ(mesh, xy0, uv0, xy1, uv1, z, 0, 0);
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
#define QUAD_VERTICE_COUNT 4
|
||||
#define QUAD_INDICE_COUNT 6
|
||||
#define QUAD_INDICE_PER_QUAD 2
|
||||
|
||||
namespace Dawn {
|
||||
class QuadMesh {
|
||||
public:
|
||||
/**
|
||||
* Buffers the vertices of a quad onto a primitive.
|
||||
*
|
||||
* @param mesh The primitive to buffer to.
|
||||
* @param xy0 The lower X and Y coordinate.
|
||||
* @param uv0 The lower Xand Y texture coordinate.
|
||||
* @param xy1 The higher X and Y coordinate.
|
||||
* @param uv1 The higher X and Y texture coordinate.
|
||||
* @param z The Z position of the coordinates.
|
||||
* @param verticeStart Start vertice to buffer to.
|
||||
* @param indiceStart Start indice to buffer to.
|
||||
*/
|
||||
static void bufferQuadMeshWithZ(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const float_t z,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffers the vertices of a quad onto a primitive.
|
||||
*
|
||||
* @param mesh The primitive to buffer to.
|
||||
* @param xy0 The lower X and Y coordinate.
|
||||
* @param uv0 The lower Xand Y texture coordinate.
|
||||
* @param xy1 The higher X and Y coordinate.
|
||||
* @param uv1 The higher X and Y texture coordinate.
|
||||
* @param verticeStart Start vertice to buffer to.
|
||||
* @param indiceStart Start indice to buffer to.
|
||||
*/
|
||||
static void bufferQuadMesh(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const int32_t verticeStart,
|
||||
const int32_t indiceStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffers texture coordinates on to an already initialized quad mesh.
|
||||
*
|
||||
* @param mesh Mesh to buffer the texture coordinates on to.
|
||||
* @param uv0 Lower X and Y coordinates.
|
||||
* @param uv1 Upper X and Y coordinates.
|
||||
* @param verticeStart Start vertice to buffer in to.
|
||||
*/
|
||||
static void bufferCoordinates(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 uv1,
|
||||
const int32_t verticeStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffers the positions of a quad onto a primitive.
|
||||
*
|
||||
* @param mesh The primitive to buffer to.
|
||||
* @param xy0 The lower X and Y coordinate.
|
||||
* @param xy1 The higher X and Y coordinate.
|
||||
* @param verticeStart Start vertice to buffer to.
|
||||
*/
|
||||
static void bufferPositions(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 xy1,
|
||||
const int32_t verticeStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes a mesh to be a single quad.
|
||||
*
|
||||
* @param mesh The primitive to buffer to.
|
||||
* @param xy0 The lower X and Y coordinate.
|
||||
* @param uv0 The lower Xand Y texture coordinate.
|
||||
* @param xy1 The higher X and Y coordinate.
|
||||
* @param uv1 The higher X and Y texture coordinate.
|
||||
* @param z The Z position of the coordinates.
|
||||
*/
|
||||
static void initQuadMesh(
|
||||
Mesh &mesh,
|
||||
const glm::vec2 xy0,
|
||||
const glm::vec2 uv0,
|
||||
const glm::vec2 xy1,
|
||||
const glm::vec2 uv1,
|
||||
const float_t z
|
||||
);
|
||||
};
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SphereMesh.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void SphereMesh::createSphere(
|
||||
Mesh &mesh,
|
||||
const float_t radius,
|
||||
const int32_t slices,
|
||||
const int32_t stacks
|
||||
) {
|
||||
std::vector<glm::vec3> positions;
|
||||
|
||||
// Create vertices
|
||||
int32_t c = 0;
|
||||
for (int32_t i = 0; i <= stacks; i++) {
|
||||
float_t phi = MATH_PI * i / stacks;
|
||||
float_t cosPhi = cos(phi);
|
||||
float_t sinPhi = sin(phi);
|
||||
|
||||
for (int32_t j = 0; j <= slices; j++) {
|
||||
float_t theta = 2 * MATH_PI * j / slices;
|
||||
float_t cosTheta = cos(theta);
|
||||
float_t sinTheta = sin(theta);
|
||||
|
||||
glm::vec3 v;
|
||||
v.x = radius * sinPhi * cosTheta;
|
||||
v.y = radius * sinPhi * sinTheta;
|
||||
v.z = radius * cosPhi;
|
||||
|
||||
positions.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Create indices
|
||||
std::vector<meshindice_t> indices;
|
||||
for (int32_t i = 0; i < stacks; i++) {
|
||||
for (int32_t j = 0; j < slices; j++) {
|
||||
meshindice_t p1 = i * (slices + 1) + j;
|
||||
meshindice_t p2 = p1 + slices + 1;
|
||||
|
||||
indices.push_back(p1);
|
||||
indices.push_back(p2);
|
||||
indices.push_back(p1 + 1);
|
||||
|
||||
indices.push_back(p1 + 1);
|
||||
indices.push_back(p2);
|
||||
indices.push_back(p2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
mesh.createBuffers(positions.size(), indices.size());
|
||||
mesh.bufferPositions(0, positions.data(), positions.size());
|
||||
mesh.bufferIndices(0, indices.data(), indices.size());
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class SphereMesh {
|
||||
public:
|
||||
/**
|
||||
* Creates a sphere mesh.
|
||||
*
|
||||
* @param mesh Mesh to instanciate.
|
||||
* @param radius Radius of the sphere.
|
||||
* @param slices How many horizontal slices to make.
|
||||
* @param stacks How many vertical stacks to make.
|
||||
*/
|
||||
static void createSphere(
|
||||
Mesh &mesh,
|
||||
const float_t radius,
|
||||
const int32_t slices,
|
||||
const int32_t stacks
|
||||
);
|
||||
};
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "display/mesh/TriangleMesh.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void TriangleMesh::createTriangleMesh(Mesh &mesh) {
|
||||
glm::vec3 positions[3] = {
|
||||
glm::vec3(-0.5f, -0.5f, 0),
|
||||
glm::vec3(0.5f, -0.5f, 0),
|
||||
glm::vec3(0, 0.5f, 0)
|
||||
};
|
||||
|
||||
glm::vec2 coordinates[3] = {
|
||||
glm::vec2(0, 0),
|
||||
glm::vec2(0, 1),
|
||||
glm::vec2(1, 0)
|
||||
};
|
||||
|
||||
meshindice_t indices[3] = {
|
||||
0, 1, 2
|
||||
};
|
||||
|
||||
mesh.createBuffers(3, 3);
|
||||
mesh.bufferPositions(0, positions, 3);
|
||||
mesh.bufferCoordinates(0, coordinates, 3);
|
||||
mesh.bufferIndices(0, indices, 3);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class TriangleMesh {
|
||||
public:
|
||||
/**
|
||||
* Initializes a mesh to hold a single triangle.
|
||||
*
|
||||
* @param mesh Mesh to initialize as a triangle.
|
||||
*/
|
||||
static void createTriangleMesh(Mesh &mesh);
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
ShaderManager.cpp
|
||||
)
|
@ -1,112 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/Texture.hpp"
|
||||
#include "display/shader/ShaderParameterBuffer.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
template<typename T>
|
||||
class IShader {
|
||||
public:
|
||||
int32_t shaderId = -1;
|
||||
int_fast16_t renderId = 0;
|
||||
|
||||
/**
|
||||
* Compile all programs for this shader.
|
||||
*/
|
||||
virtual void compile() = 0;
|
||||
|
||||
/**
|
||||
* Attaches the supplied shader as the current shader.
|
||||
*/
|
||||
virtual void bind() = 0;
|
||||
|
||||
/**
|
||||
* Binds a shader buffer to a specific slot.
|
||||
*
|
||||
* @param slot Slot to bind the buffer to.
|
||||
* @param buffer Buffer to bind.
|
||||
*/
|
||||
template<typename J>
|
||||
void setParameterBuffer(
|
||||
const shaderbufferslot_t slot,
|
||||
const ShaderParameterBuffer<J> &buffer
|
||||
);
|
||||
|
||||
/**
|
||||
* Set's a specific shader parameter to a matrix.
|
||||
*
|
||||
* @param parameter parameter on the shader to set.
|
||||
* @param matrix Matrix to apply.
|
||||
*/
|
||||
virtual void setMatrix(
|
||||
const T parameter,
|
||||
const glm::mat4 matrix
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Attaches a boolean to a shader.
|
||||
*
|
||||
* @param parameter parameter to set.
|
||||
* @param value Value to set.
|
||||
*/
|
||||
virtual void setBoolean(
|
||||
const T parameter,
|
||||
const bool_t value
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Set a color on to the shader.
|
||||
*
|
||||
* @param parameter parameter to set the color to.
|
||||
* @param color Color to set.
|
||||
*/
|
||||
virtual void setColor(
|
||||
const T parameter,
|
||||
const struct Color color
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Set a 3D vector on to the shader.
|
||||
*
|
||||
* @param parameter parameter to set the vector to.
|
||||
* @param vector Vector to set.
|
||||
*/
|
||||
virtual void setVector3(
|
||||
const T parameter,
|
||||
const glm::vec3 vector
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Attaches a texture to the currently bound shader.
|
||||
*
|
||||
* @param parameter parameter to set the texture on to.
|
||||
* @param texture Texture slot to bind to the parameter.
|
||||
*/
|
||||
virtual void setTexture(
|
||||
const T parameter,
|
||||
const textureslot_t texture
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Sets a floating point value to the shader.
|
||||
*
|
||||
* @param parameter Paramater to set the float ont o.
|
||||
* @param Float to bind.
|
||||
*/
|
||||
virtual void setFloat(
|
||||
const T parameter,
|
||||
const float_t value
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Destroys/Cleans up the shader.
|
||||
*/
|
||||
virtual ~IShader() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
template<typename L>
|
||||
class IShaderParameterBuffer {
|
||||
public:
|
||||
/**
|
||||
* Initializes this shader parameter buffer.
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Bind this shader buffer to the supplied location.
|
||||
*
|
||||
* @param location Location to bind this buffer to.
|
||||
*/
|
||||
virtual void bind(const L location) = 0;
|
||||
};
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "ShaderManager.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
ShaderManager::ShaderManager() {
|
||||
this->nextId = 0;
|
||||
this->nextLock = 0;
|
||||
}
|
||||
|
||||
ShaderManager::~ShaderManager() {
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/shader/Shader.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
typedef int64_t shaderlock_t;
|
||||
typedef int16_t shaderid_t;
|
||||
|
||||
class ShaderManager {
|
||||
private:
|
||||
int32_t nextId;
|
||||
shaderlock_t nextLock;
|
||||
std::map<shaderid_t, std::shared_ptr<Shader>> shaders;
|
||||
std::map<shaderlock_t, shaderid_t> shaderLocks;
|
||||
std::map<shaderid_t, std::vector<shaderlock_t>> shaderLocksByShader;
|
||||
|
||||
/**
|
||||
* Returns the shader id for the given shader type, or -1 if it is not
|
||||
* loaded.
|
||||
*
|
||||
* @return The shader id for the shader, or -1 if it is not loaded.
|
||||
*/
|
||||
template<class T>
|
||||
shaderid_t getShaderId() {
|
||||
auto it = shaders.begin();
|
||||
while(it != shaders.end()) {
|
||||
auto asT = std::dynamic_pointer_cast<T>(it->second);
|
||||
if(asT != nullptr) return asT->shaderId;
|
||||
++it;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new shader manager.
|
||||
*/
|
||||
ShaderManager();
|
||||
|
||||
/**
|
||||
* Locks a shader of the given type. If the shader is not already loaded,
|
||||
* it will be loaded. If the shader is already loaded, it will be
|
||||
* returned.
|
||||
*
|
||||
* @return The shader lock for the shader of the given type.
|
||||
*/
|
||||
template<class T>
|
||||
shaderlock_t lockShader() {
|
||||
auto shaderId = this->getShaderId<T>();
|
||||
if(shaderId == -1) {
|
||||
auto shader = std::make_shared<T>();
|
||||
shader->compile();
|
||||
shader->shaderId = this->nextId++;
|
||||
this->shaders[shader->shaderId] = shader;
|
||||
shaderId = shader->shaderId;
|
||||
}
|
||||
|
||||
shaderlock_t lock = this->nextLock++;
|
||||
this->shaderLocks[lock] = shaderId;
|
||||
this->shaderLocksByShader[shaderId].push_back(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shader for the given lock.
|
||||
*
|
||||
* @param lock The shader lock.
|
||||
* @return The shader for the given lock.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> getShader(shaderlock_t lock) {
|
||||
auto shaderId = this->shaderLocks[lock];
|
||||
return std::static_pointer_cast<T>(this->shaders[shaderId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the shader for the given lock. This will unload any shader
|
||||
* that is no longer in use.
|
||||
*
|
||||
* @param lock Lock to release.
|
||||
*/
|
||||
template<class T>
|
||||
void releaseShader(shaderlock_t lock) {
|
||||
auto shaderId = this->shaderLocks[lock];
|
||||
this->shaderLocks.erase(lock);
|
||||
|
||||
auto& locks = this->shaderLocksByShader[shaderId];
|
||||
auto it = std::find(locks.begin(), locks.end(), lock);
|
||||
if(it != locks.end()) locks.erase(it);
|
||||
|
||||
if(locks.size() == 0) {
|
||||
this->shaderLocksByShader.erase(shaderId);
|
||||
this->shaders.erase(shaderId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the shader manager.
|
||||
*/
|
||||
~ShaderManager();
|
||||
};
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/shader/Shader.hpp"
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct ShaderPassItem;
|
||||
|
||||
struct ShaderPassItem {
|
||||
std::shared_ptr<Shader> shader;
|
||||
int32_t priority = 0;
|
||||
std::vector<struct ShaderPassItem>::iterator index;
|
||||
|
||||
Mesh *mesh;
|
||||
int32_t start = 0;
|
||||
int32_t count = -1;
|
||||
float_t w = 0;
|
||||
flag_t renderFlags = RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST;
|
||||
enum MeshDrawMode drawMode = MESH_DRAW_MODE_TRIANGLES;
|
||||
|
||||
// Parameters
|
||||
std::map<shaderparameter_t, struct Color> colorValues;
|
||||
std::map<shaderparameter_t, bool_t> boolValues;
|
||||
std::map<shaderparameter_t, glm::mat4> matrixValues;
|
||||
std::map<shaderparameter_t, glm::vec3> vec3Values;
|
||||
std::map<shaderparameter_t, textureslot_t> textureValues;
|
||||
std::map<shaderparameter_t, float_t> floatValues;
|
||||
std::map<shaderbufferlocation_t, IShaderParameterBuffer<shaderbufferslot_t>*> parameterBuffers;
|
||||
|
||||
// Textures
|
||||
std::map<textureslot_t, Texture*> textureSlots;
|
||||
};
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
template<typename ...T>
|
||||
class Event {
|
||||
private:
|
||||
std::hashmap<int32_t, std::function<void(T...)>> callback;
|
||||
int32_t nextEventId = 0;
|
||||
|
||||
public:
|
||||
int32_t listen(const std::function <void(T...)> &callback) {
|
||||
this->callback.insert(std::make_pair(this->nextEventId, callback));
|
||||
return this->nextEventId++;
|
||||
}
|
||||
|
||||
void unlisten(int32_t id) {
|
||||
this->callback.erase(id);
|
||||
}
|
||||
|
||||
void trigger(T... args) {
|
||||
for(auto &it : this->callback) {
|
||||
it.second(args...);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
DawnGame.cpp
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Game.cpp
|
||||
)
|
@ -1,54 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
DawnGame::DawnGame(const std::weak_ptr<DawnHost> host) :
|
||||
host(host),
|
||||
inputManager(),
|
||||
saveManager(this)
|
||||
{
|
||||
renderManager = std::make_shared<RenderManager>();
|
||||
}
|
||||
|
||||
int32_t DawnGame::init() {
|
||||
this->assetManager.init();
|
||||
this->renderManager->init(weak_from_this());
|
||||
this->scene = dawnGameGetInitialScene(weak_from_this());
|
||||
return DAWN_GAME_INIT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t DawnGame::update(float_t delta) {
|
||||
this->assetManager.update();
|
||||
this->inputManager.update();
|
||||
this->timeManager.update(delta);
|
||||
|
||||
if(this->scene != nullptr) this->scene->update();
|
||||
|
||||
this->renderManager->update();
|
||||
|
||||
if(this->sceneToCutTo != nullptr) {
|
||||
this->scene = nullptr;
|
||||
this->scene = this->sceneToCutTo;
|
||||
this->sceneToCutTo = nullptr;
|
||||
}
|
||||
|
||||
if(this->closeRequested) {
|
||||
return DAWN_GAME_UPDATE_RESULT_EXIT;
|
||||
}
|
||||
|
||||
return DAWN_GAME_UPDATE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void DawnGame::sceneCutover(std::shared_ptr<Scene> scene) {
|
||||
if(scene == nullptr) scene = this->scene;
|
||||
this->sceneToCutTo = scene;
|
||||
}
|
||||
|
||||
void DawnGame::close() {
|
||||
this->closeRequested = true;
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "scene/Scene.hpp"
|
||||
#include "display/RenderManager.hpp"
|
||||
#include "asset/AssetManager.hpp"
|
||||
#include "input/InputManager.hpp"
|
||||
#include "time/TimeManager.hpp"
|
||||
#include "input/InputBinds.hpp"
|
||||
#include "save/SaveManager.hpp"
|
||||
|
||||
#define DAWN_GAME_INIT_RESULT_SUCCESS 0
|
||||
#define DAWN_GAME_UPDATE_RESULT_SUCCESS 0
|
||||
#define DAWN_GAME_UPDATE_RESULT_EXIT 1
|
||||
|
||||
namespace Dawn {
|
||||
class DawnHost;
|
||||
|
||||
class DawnGame : public std::enable_shared_from_this<DawnGame> {
|
||||
private:
|
||||
std::shared_ptr<Scene> sceneToCutTo;
|
||||
bool_t closeRequested = false;
|
||||
|
||||
public:
|
||||
const std::weak_ptr<DawnHost> host;
|
||||
std::shared_ptr<Scene> scene;
|
||||
AssetManager assetManager;
|
||||
TimeManager timeManager;
|
||||
std::shared_ptr<RenderManager> renderManager;
|
||||
InputManager inputManager;
|
||||
SaveManager saveManager;
|
||||
|
||||
/**
|
||||
* Construct a new game instance.
|
||||
*
|
||||
* @param host Host that executed this game instantiation.
|
||||
*/
|
||||
DawnGame(const std::weak_ptr<DawnHost> host);
|
||||
|
||||
/**
|
||||
* Initialize the game. This is performed by the host at a time that is
|
||||
* deemed to have the host ready for the game's initialization. This will
|
||||
* return an initialize result, where DAWN_GAME_INIT_RESULT_SUCCESS is
|
||||
* the only "successful" result, anything else is deemed a failure state.
|
||||
*
|
||||
* @param host Pointer to the host that is running this game.
|
||||
* @return The game initialize result.
|
||||
*/
|
||||
int32_t init();
|
||||
|
||||
/**
|
||||
* Performs a game update operation. This operation should occur exactly
|
||||
* once per frame, synchronously on the main thread. Updates can only
|
||||
* have two valid exit results, either DAWN_GAME_UPDATE_RESULT_SUCCESS for
|
||||
* a successful update, and request that we continue to update, or
|
||||
* DAWN_GAME_UPDATE_RESULT_EXIT for a successful update but to request
|
||||
* that no more update operations occur. Any other result is considered a
|
||||
* failure state.
|
||||
*
|
||||
* @param delta Time delta to tick the game by.
|
||||
* @return The game update result.
|
||||
*/
|
||||
int32_t update(float_t delta);
|
||||
|
||||
/**
|
||||
* Changes to a new scene, will dispose the currently active scene as part
|
||||
* of that process. This assumes the other scene has already been loaded
|
||||
* and staged.
|
||||
*
|
||||
* @param scene Scene to cut over to.
|
||||
*/
|
||||
void sceneCutover(std::shared_ptr<Scene> scene);
|
||||
|
||||
/**
|
||||
* Gracefully requests that the game should be closed as soon as possible.
|
||||
*/
|
||||
void close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Unimplemented by default, required by the game as the basic entry point
|
||||
* for which scene should be used by default.
|
||||
*
|
||||
* @param game Game that is requesting this scene.
|
||||
* @return Pointer to a scene that you wish to have as the default scene.
|
||||
*/
|
||||
std::shared_ptr<Scene> dawnGameGetInitialScene(std::weak_ptr<DawnGame> game);
|
||||
}
|
31
src/dawn/game/Game.cpp
Normal file
31
src/dawn/game/Game.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Game.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
Game::Game() {
|
||||
|
||||
}
|
||||
|
||||
void Game::init() {
|
||||
renderHost.init();
|
||||
inputManager.init(shared_from_this());
|
||||
}
|
||||
|
||||
void Game::update() {
|
||||
renderHost.update();
|
||||
}
|
||||
|
||||
bool_t Game::isCloseRequested() {
|
||||
return (
|
||||
renderHost.isCloseRequested()
|
||||
);
|
||||
}
|
||||
|
||||
Game::~Game() {
|
||||
|
||||
}
|
46
src/dawn/game/Game.hpp
Normal file
46
src/dawn/game/Game.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "display/RenderHost.hpp"
|
||||
#include "input/InputManager.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class Game : public std::enable_shared_from_this<Game> {
|
||||
public:
|
||||
RenderHost renderHost;
|
||||
InputManager inputManager;
|
||||
|
||||
/**
|
||||
* Constructs the game instance, does not initialize anything.
|
||||
*/
|
||||
Game();
|
||||
|
||||
/**
|
||||
* Initialize the game and all of its components.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Performs a single update tick on the game engine, and in turn all of
|
||||
* the game's sub systems.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Returns whether the game has been requested to gracefully close at the
|
||||
* next available opportunity.
|
||||
*
|
||||
* @return True if the game should close.
|
||||
*/
|
||||
bool_t isCloseRequested();
|
||||
|
||||
/**
|
||||
* Deconstructs the game instance, does not deinitialize anything.
|
||||
*/
|
||||
virtual ~Game();
|
||||
};
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirs
|
||||
# add_subdirectory(poker)
|
||||
add_subdirectory(tictactoe)
|
||||
|
||||
if(DAWN_VISUAL_NOVEL)
|
||||
add_subdirectory(vn)
|
||||
endif()
|
@ -1,20 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Card.cpp
|
||||
PokerPot.cpp
|
||||
PokerPlayer.cpp
|
||||
PokerGame.cpp
|
||||
PokerWinning.cpp
|
||||
PokerTurn.cpp
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
if(DAWN_VISUAL_NOVEL)
|
||||
add_subdirectory(visualnovel)
|
||||
endif()
|
@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Card.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void Card::fillDeck(std::vector<struct Card> *deck) {
|
||||
assertNotNull(deck);
|
||||
|
||||
for(uint8_t i = 0; i < CARD_DECK_SIZE; i++) {
|
||||
deck->push_back(Card(i));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t Card::contains(std::vector<struct Card> *deck, struct Card c) {
|
||||
assertNotNull(deck);
|
||||
|
||||
auto it = deck->begin();
|
||||
while(it != deck->end()) {
|
||||
if(it->cardValue == c.cardValue) return (int32_t)(it - deck->begin());
|
||||
++it;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t Card::containsNumber(
|
||||
std::vector<struct Card> *deck,
|
||||
enum CardValue number
|
||||
) {
|
||||
assertNotNull(deck);
|
||||
assertTrue(number < CARD_COUNT_PER_SUIT);
|
||||
|
||||
auto it = deck->begin();
|
||||
while(it != deck->end()) {
|
||||
if(it->getValue() == number) return (int32_t)(it - deck->begin());
|
||||
++it;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<struct Card> Card::countPairs(
|
||||
std::vector<struct Card> *deck,
|
||||
enum CardValue val
|
||||
) {
|
||||
std::vector<struct Card> pairs;
|
||||
|
||||
assertNotNull(deck);
|
||||
assertTrue(deck->size() > 0);
|
||||
|
||||
auto it = deck->begin();
|
||||
while(it != deck->end()) {
|
||||
if(it->getValue() == val) pairs.push_back(*it);
|
||||
++it;
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
bool_t Card::cardSorter(struct Card left, struct Card right) {
|
||||
return left.cardValue < right.cardValue;
|
||||
}
|
||||
|
||||
void Card::sort(std::vector<struct Card> *deck) {
|
||||
assertNotNull(deck);
|
||||
assertTrue(deck->size() > 1);
|
||||
std::sort(deck->begin(), deck->end(), &Card::cardSorter);
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "assert/assert.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum CardSuit {
|
||||
CARD_CLUBS = 0,
|
||||
CARD_DIAMONDS = 1,
|
||||
CARD_HEARTS = 2,
|
||||
CARD_SPADES = 3,
|
||||
|
||||
CARD_SUIT_INVALUD = 0xFF
|
||||
};
|
||||
|
||||
enum CardValue {
|
||||
CARD_TWO = 0,
|
||||
CARD_THREE = 1,
|
||||
CARD_FOUR = 2,
|
||||
CARD_FIVE = 3,
|
||||
CARD_SIX = 4,
|
||||
CARD_SEVEN = 5,
|
||||
CARD_EIGHT = 6,
|
||||
CARD_NINE = 7,
|
||||
CARD_TEN = 8,
|
||||
CARD_JACK = 9,
|
||||
CARD_QUEEN = 10,
|
||||
CARD_KING = 11,
|
||||
CARD_ACE = 12,
|
||||
|
||||
CARD_VALUE_INVALD = 0xFF
|
||||
};
|
||||
|
||||
/** Count of cards in each suit */
|
||||
#define CARD_COUNT_PER_SUIT 13
|
||||
|
||||
/** Count of suits */
|
||||
#define CARD_SUIT_COUNT 4
|
||||
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE CARD_COUNT_PER_SUIT*CARD_SUIT_COUNT
|
||||
|
||||
struct Card {
|
||||
public:
|
||||
uint8_t cardValue;
|
||||
|
||||
/**
|
||||
* Shuffles a hand / deck
|
||||
*
|
||||
* @param deck Array of cards to shuffle.
|
||||
*/
|
||||
static void shuffle(std::vector<struct Card> *deck);
|
||||
|
||||
/**
|
||||
* Fills a vector with all of the cards in a deck, in order.
|
||||
*
|
||||
* @param deck Deck to fill.
|
||||
*/
|
||||
static void fillDeck(std::vector<struct Card> *deck);
|
||||
|
||||
/**
|
||||
* Check if an array of cards contains a specific card.
|
||||
*
|
||||
* @param deck Deck/Hand/Array of cards to check.
|
||||
* @param card Card to look for
|
||||
* @returns The index within the array that the card is. -1 if not found.
|
||||
*/
|
||||
static int32_t contains(std::vector<struct Card> *deck, struct Card card);
|
||||
|
||||
/**
|
||||
* Check if the array of cards contains a specific number.
|
||||
*
|
||||
* @param deck Array of cards to check
|
||||
* @param number The number to look for.
|
||||
* @returns The index that the first card is. -1 if not found.
|
||||
*/
|
||||
static int32_t containsNumber(
|
||||
std::vector<struct Card> *deck,
|
||||
enum CardValue number
|
||||
);
|
||||
|
||||
/**
|
||||
* Counts the amount of times a card's number appears within the given
|
||||
* hand.
|
||||
*
|
||||
* @param deck The hand to check
|
||||
* @param val Value of pairs to find.
|
||||
* @return Card pairs in the deck.
|
||||
*/
|
||||
static std::vector<struct Card> countPairs(
|
||||
std::vector<struct Card> *deck,
|
||||
enum CardValue val
|
||||
);
|
||||
|
||||
static bool_t cardSorter(struct Card left, struct Card right);
|
||||
|
||||
/**
|
||||
* Sort a hand of cards. Cards are ordered in descending weight, aces are
|
||||
* high. Cards will be grouped by their suits, e.g. CARD_CLUBS_TWO will
|
||||
* appear before CARD_DIAMONDS_KING.
|
||||
*
|
||||
* @param deck Hand of cards to sort.
|
||||
*/
|
||||
static void sort(std::vector<struct Card> *deck);
|
||||
|
||||
Card(CardSuit suit, CardValue num) :
|
||||
cardValue((suit * CARD_COUNT_PER_SUIT) + num)
|
||||
{
|
||||
if(suit == CARD_SUIT_INVALUD || num == CARD_VALUE_INVALD) {
|
||||
this->cardValue = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
Card(uint8_t cv) : cardValue(cv) {
|
||||
// assertTrue(cv < CARD_DECK_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of a given card.
|
||||
* @returns The card number.
|
||||
*/
|
||||
CardValue getValue() {
|
||||
return (CardValue)(cardValue % CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the suit of a given card.
|
||||
* @returns The suit.
|
||||
*/
|
||||
CardSuit getSuit() {
|
||||
return (CardSuit)(cardValue / CARD_COUNT_PER_SUIT);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerGame::PokerGame(std::weak_ptr<SceneItem> item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
void PokerGame::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
|
||||
this->players = this->getScene()->findComponents<PokerPlayer>();
|
||||
assertTrue(this->players.size() > 0);
|
||||
this->newGame();
|
||||
}
|
||||
|
||||
void PokerGame::newGame() {
|
||||
this->newRound();
|
||||
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->setChips(POKER_PLAYER_CHIPS_DEFAULT);
|
||||
player->isOut = false;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->setDealer(0x00);
|
||||
}
|
||||
|
||||
void PokerGame::newRound() {
|
||||
this->deck.clear();
|
||||
Card::fillDeck(&this->deck);
|
||||
|
||||
this->smallBlind = POKER_BLIND_SMALL_DEFAULT;
|
||||
this->bigBlind = POKER_BLIND_BIG_DEFAULT;
|
||||
this->grave.clear();
|
||||
this->community.clear();
|
||||
this->pots.clear();
|
||||
this->pots.push_back(PokerPot());
|
||||
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->hand.clear();
|
||||
player->currentBet = 0;
|
||||
player->isFolded = false;
|
||||
player->isShowingHand = false;
|
||||
player->hasBetThisRound = false;
|
||||
player->timesRaised = 0;
|
||||
player->currentBet = 0;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->setDealer(this->dealerIndex + 0x01);
|
||||
}
|
||||
|
||||
void PokerGame::newBettingRound() {
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
player->hasBetThisRound = false;
|
||||
player->timesRaised = 0;
|
||||
++it;
|
||||
}
|
||||
|
||||
this->betterIndex = this->bigBlindIndex;
|
||||
this->betterIndex = this->getNextBetterIndex();
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getNextBetterIndex() {
|
||||
uint8_t j, i;
|
||||
for(i = 0; i < this->players.size(); i++) {
|
||||
j = (i + this->betterIndex) % this->players.size();
|
||||
auto player = this->players[j];
|
||||
if(player->needsToBetThisRound()) return j;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void PokerGame::takeBlinds() {
|
||||
auto playerSmallBlind = this->players[this->smallBlindIndex];
|
||||
auto playerBigBlind = this->players[this->bigBlindIndex];
|
||||
|
||||
playerSmallBlind->bet(this->smallBlind);
|
||||
playerBigBlind->bet(this->bigBlind);
|
||||
|
||||
playerSmallBlind->hasBetThisRound = false;
|
||||
playerBigBlind->hasBetThisRound = false;
|
||||
}
|
||||
|
||||
void PokerGame::setDealer(uint8_t dealer) {
|
||||
uint8_t i, k;
|
||||
PokerPlayer *player;
|
||||
bool_t foundDealer;
|
||||
bool_t foundSmall;
|
||||
|
||||
foundDealer = false;
|
||||
foundSmall = false;
|
||||
this->dealerIndex = dealer;
|
||||
|
||||
for(i = 0; i < this->players.size(); i++) {
|
||||
k = (dealer + i) % this->players.size();
|
||||
player = this->players[k];
|
||||
if(player->isOut) continue;
|
||||
if(!foundDealer) {
|
||||
this->dealerIndex = k;
|
||||
foundDealer = true;
|
||||
} else if(!foundSmall) {
|
||||
this->smallBlindIndex = k;
|
||||
foundSmall = true;
|
||||
} else {
|
||||
this->bigBlindIndex = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getRemainingBettersCount() {
|
||||
uint8_t count = 0;
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
if((*it)->needsToBetThisRound()) count++;
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getRemainingPlayersCount() {
|
||||
uint8_t count = 0;
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
if(!player->isFolded && !player->isOut) count++;
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int32_t PokerGame::getCurrentCallValue() {
|
||||
assertTrue(this->pots.size() > 0);
|
||||
return this->pots.back().call;
|
||||
}
|
||||
|
||||
void PokerGame::burnCard() {
|
||||
assertTrue(this->deck.size() > 0);
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
this->grave.push_back(card);
|
||||
}
|
||||
|
||||
void PokerGame::dealCard(PokerPlayer *player) {
|
||||
assertTrue(this->deck.size() > 0);
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
player->hand.push_back(card);
|
||||
}
|
||||
|
||||
void PokerGame::dealToEveryone(uint8_t count) {
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
this->dealCard(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PokerGame::turn(uint8_t count) {
|
||||
assertTrue(this->deck.size() >= count);
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
auto card = this->deck.back();
|
||||
this->deck.pop_back();
|
||||
this->community.push_back(card);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PokerGame::getCountOfCardsToTurn() {
|
||||
switch(this->community.size()) {
|
||||
case 0x00:
|
||||
return POKER_FLOP_CARD_COUNT;
|
||||
|
||||
case 0x03:
|
||||
return POKER_TURN_CARD_COUNT;
|
||||
|
||||
case 0x04:
|
||||
return POKER_RIVER_CARD_COUNT;
|
||||
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerPlayer.hpp"
|
||||
|
||||
/** The default blind cost for the big blind. */
|
||||
#define POKER_BLIND_BIG_DEFAULT 600
|
||||
/** The default blind cost for the small blind. (Defaults half big blind) */
|
||||
#define POKER_BLIND_SMALL_DEFAULT (POKER_BLIND_BIG_DEFAULT/2)
|
||||
|
||||
/** How many cards are dealt for the flop, turn and river */
|
||||
#define POKER_FLOP_CARD_COUNT 3
|
||||
#define POKER_TURN_CARD_COUNT 1
|
||||
#define POKER_RIVER_CARD_COUNT 1
|
||||
|
||||
namespace Dawn {
|
||||
class PokerGame : public SceneItemComponent {
|
||||
protected:
|
||||
std::vector<struct Card> deck;
|
||||
std::vector<struct Card> grave;
|
||||
std::vector<struct Card> community;
|
||||
uint8_t dealerIndex;
|
||||
uint8_t smallBlindIndex;
|
||||
uint8_t bigBlindIndex;
|
||||
int32_t smallBlind = POKER_BLIND_SMALL_DEFAULT;
|
||||
int32_t bigBlind = POKER_BLIND_BIG_DEFAULT;
|
||||
|
||||
public:
|
||||
std::vector<PokerPlayer*> players;
|
||||
std::vector<struct PokerPot> pots;
|
||||
uint8_t betterIndex;
|
||||
|
||||
PokerGame(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
|
||||
void newGame();
|
||||
void newRound();
|
||||
void newBettingRound();
|
||||
void takeBlinds();
|
||||
void setBlinds(int32_t small, int32_t big);
|
||||
uint8_t getRemainingBettersCount();
|
||||
int32_t getCurrentCallValue();
|
||||
uint8_t getNextBetterIndex();
|
||||
void setDealer(uint8_t dealer);
|
||||
void newDealer();
|
||||
void burnCard();
|
||||
void dealCard(PokerPlayer *player);
|
||||
void dealToEveryone(uint8_t count);
|
||||
void turn(uint8_t count);
|
||||
uint8_t getCountOfCardsToTurn();
|
||||
uint8_t getRemainingPlayersCount();
|
||||
|
||||
friend class PokerPlayer;
|
||||
};
|
||||
}
|
@ -1,450 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerPlayer.hpp"
|
||||
#include "PokerGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerPlayer::PokerPlayer(std::weak_ptr<SceneItem> item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
void PokerPlayer::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
this->pokerGame = this->getScene()->findComponent<PokerGame>();
|
||||
}
|
||||
|
||||
void PokerPlayer::addChips(int32_t chips) {
|
||||
assertTrue(chips > 0);
|
||||
|
||||
this->chips += chips;
|
||||
if(this->chips > 0) this->isOut = false;
|
||||
eventChipsChanged.invoke();
|
||||
}
|
||||
|
||||
void PokerPlayer::setChips(int32_t chips) {
|
||||
this->chips = 0;
|
||||
this->addChips(chips);
|
||||
}
|
||||
|
||||
bool_t PokerPlayer::needsToBetThisRound() {
|
||||
if(this->isFolded) return false;
|
||||
if(this->chips <= 0) return false;
|
||||
if(!this->hasBetThisRound) return true;
|
||||
if(this->currentBet < this->pokerGame->getCurrentCallValue()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PokerPlayer::bet(struct PokerPot *pot, int32_t chips) {
|
||||
assertNotNull(pot);
|
||||
assertTrue(chips >= 0);
|
||||
assertTrue(!this->isFolded);
|
||||
assertTrue(!this->isOut);
|
||||
this->setChips(this->chips - chips);
|
||||
this->currentBet += chips;
|
||||
this->hasBetThisRound = true;
|
||||
if(chips > 0) {
|
||||
this->timesRaised++;
|
||||
} else {
|
||||
this->timesRaised = 0;
|
||||
}
|
||||
|
||||
pot->chips += chips;
|
||||
pot->call = mathMax<int32_t>(pot->call, this ->currentBet);
|
||||
|
||||
auto existing = std::find(pot->players.begin(), pot->players.end(), this);
|
||||
if(existing == pot->players.end()) pot->players.push_back(this);
|
||||
}
|
||||
|
||||
void PokerPlayer::bet(int32_t chips) {
|
||||
assertTrue(this->pokerGame->pots.size() > 0);
|
||||
this->bet(&this->pokerGame->pots.back(), chips);
|
||||
}
|
||||
|
||||
void PokerPlayer::fold() {
|
||||
this->isFolded = true;
|
||||
this->hasBetThisRound = true;
|
||||
this->timesRaised = 0;
|
||||
}
|
||||
|
||||
bool_t PokerPlayer::canCheck() {
|
||||
return this->pokerGame->getCurrentCallValue() <= this->currentBet;
|
||||
}
|
||||
|
||||
struct PokerTurn PokerPlayer::getAITurn() {
|
||||
struct PokerTurn turn;
|
||||
float_t confidence;
|
||||
int32_t callBet;
|
||||
float_t potOdds;
|
||||
|
||||
// Can the player do anything?
|
||||
if(this->isFolded || this->isOut) {
|
||||
turn.type = POKER_TURN_TYPE_OUT;
|
||||
return turn;
|
||||
}
|
||||
|
||||
// The following logic is heavily inspired by;
|
||||
// https://github.com/gorel/C-Poker-AI/blob/master/src/common/pokerai.c
|
||||
// But with some changes and smarts added by me. The original source code will
|
||||
// essentially just run a crap tun of simulated games and get the times that
|
||||
// they are expected to win from those games, but I'm just going to use the
|
||||
// odds of the winning hand.
|
||||
|
||||
|
||||
// Is this preflop?
|
||||
if(this->pokerGame->community.size() == 0) {
|
||||
assertTrue(this->hand.size() == POKER_PLAYER_HAND_SIZE_MAX);
|
||||
|
||||
// Get the hand weight
|
||||
auto cardNumber0 = this->hand[0].getValue();
|
||||
auto suitNumber0 = this->hand[0].getSuit();
|
||||
auto cardNumber1 = this->hand[1].getValue();
|
||||
auto suitNumber1 = this->hand[1].getSuit();
|
||||
|
||||
// Get delta between cards
|
||||
auto i = (uint8_t)mathAbs<int8_t>(
|
||||
(int8_t)cardNumber0 - (int8_t)cardNumber1
|
||||
);
|
||||
|
||||
// Get card weight
|
||||
confidence = (float_t)cardNumber0 + (float_t)cardNumber1;
|
||||
if(cardNumber0 == cardNumber1) {// Pairs
|
||||
confidence += 6;
|
||||
} else if(suitNumber0 == suitNumber1) {// Same suit
|
||||
confidence += 4;
|
||||
}
|
||||
|
||||
// Get difference from cards for guessing flush
|
||||
if(i > 4) {
|
||||
confidence -= 4;
|
||||
} else if(i > 2) {
|
||||
confidence -= i;
|
||||
}
|
||||
|
||||
// Get the confidence delta 0-1
|
||||
confidence = confidence / 30.0f;
|
||||
|
||||
// This may change in future, but I was finding the AI did not want to bet
|
||||
// during the preflop enough, this curves the AI to want to preflop call
|
||||
// often.
|
||||
confidence = easeOutCubic(confidence);
|
||||
} else {
|
||||
// Simulate my hand being the winning hand, use that as the confidence
|
||||
auto winning = this->getWinning();
|
||||
confidence = PokerWinning::getWinningTypeConfidence(winning.type);
|
||||
}
|
||||
|
||||
// Now we know how confident the AI is, let's put a chip value to that weight
|
||||
// How many chips to call?
|
||||
callBet = this->getCallBet();
|
||||
|
||||
// Do they need chips to call, or is it possible to check?
|
||||
if(callBet > 0) {
|
||||
potOdds = (float_t)callBet / (
|
||||
(float_t)callBet +
|
||||
(float_t)this->getSumOfChips()
|
||||
);
|
||||
} else {
|
||||
potOdds = 1.0f / (float_t)this->pokerGame->getRemainingBettersCount();
|
||||
}
|
||||
|
||||
// Now determine the expected ROI
|
||||
auto expectedGain = confidence / potOdds;
|
||||
|
||||
// Now get a random 0-100
|
||||
auto random = randomGenerate<int32_t>() % 100;
|
||||
|
||||
// Determine the max bet that the AI is willing to make
|
||||
auto maxBet = (int32_t)((float_t)this->chips / 1.75f) - (random / 2);
|
||||
maxBet -= callBet;
|
||||
|
||||
// Determine what's a good bluff bet.
|
||||
auto bluffBet = random * maxBet / 100 / 2;
|
||||
|
||||
// Now prep the output
|
||||
auto isBluff = false;
|
||||
auto amount = 0;
|
||||
|
||||
// Now the actual AI can happen. This is basically a weight to confidence
|
||||
// ratio. The higher the gains and the confidence then the more likely the AI
|
||||
// is to betting. There are also bluff chances within here.
|
||||
if(expectedGain < 0.8f && confidence < 0.8f) {
|
||||
if(random < 85) {
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if((expectedGain < 1.0f && confidence < 0.85f) || confidence < 0.1f) {
|
||||
if(random < 80) {
|
||||
amount = 0;
|
||||
} else if(random < 5) {
|
||||
amount = callBet;
|
||||
isBluff = true;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if((expectedGain < 1.3f && confidence < 0.9f) || confidence < 0.5f) {
|
||||
if(random < 60 || confidence < 0.5f) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else if(confidence < 0.95f || this->pokerGame->community.size() < 4) {
|
||||
if(random < 20) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else {
|
||||
amount = (this->chips - callBet) * 9 / 10;
|
||||
}
|
||||
|
||||
// TODO: We can nicely round the amounts here to get us to a more "human"
|
||||
// number.
|
||||
|
||||
// If this is the first round... make it a lot less likely I'll bet
|
||||
if(this->pokerGame->community.size() == 0 && amount > callBet) {
|
||||
if(random > 5) amount = callBet;
|
||||
}
|
||||
|
||||
// Did we actually bet?
|
||||
if(amount > 0) {
|
||||
std::cout << "AI is betting " << amount << " chips, bluff:" << isBluff << std::endl;
|
||||
|
||||
// Let's not get caught in a raising loop with AI.
|
||||
if(this->timesRaised >= POKER_PLAYER_MAX_RAISES) {
|
||||
amount = callBet;
|
||||
}
|
||||
|
||||
amount = mathMax<int32_t>(amount, callBet);
|
||||
turn = PokerTurn::bet(this, amount);
|
||||
turn.confidence = confidence;
|
||||
} else if(this->canCheck()) {
|
||||
turn = PokerTurn::bet(this, 0);
|
||||
turn.confidence = 1;
|
||||
} else {
|
||||
turn = PokerTurn::fold(this);
|
||||
turn.confidence = 1 - confidence;
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
int32_t PokerPlayer::getCallBet() {
|
||||
return this->pokerGame->getCurrentCallValue() - this->currentBet;
|
||||
}
|
||||
|
||||
int32_t PokerPlayer::getSumOfChips() {
|
||||
int32_t count = 0;
|
||||
auto it = this->pokerGame->pots.begin();
|
||||
while(it != this->pokerGame->pots.end()) {
|
||||
if(std::find(it->players.begin(), it->players.end(), this) != it->players.end()) {
|
||||
count += it->chips;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
struct PokerWinning PokerPlayer::getWinning() {
|
||||
struct PokerWinning winning;
|
||||
struct Card card(0x00);
|
||||
uint8_t i, j;
|
||||
int32_t index;
|
||||
enum CardValue number, look;
|
||||
enum CardSuit suit;
|
||||
std::vector<struct Card> pairs;
|
||||
|
||||
winning.player = this;
|
||||
|
||||
// Get the full poker hand (should be a 7 card hand, but MAY not be)
|
||||
for(i = 0; i < this->pokerGame->community.size(); i++) {
|
||||
winning.full.push_back(this->pokerGame->community[i]);
|
||||
}
|
||||
for(i = 0; i < this->hand.size(); i++) {
|
||||
winning.full.push_back(this->hand[i]);
|
||||
}
|
||||
Card::sort(&winning.full);
|
||||
|
||||
//////////////////////// Now look for the winning set ////////////////////////
|
||||
|
||||
// Royal / Straight Flush
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];
|
||||
number = card.getValue();
|
||||
if(number < CARD_FIVE) continue;
|
||||
|
||||
suit = card.getSuit();
|
||||
|
||||
winning.set.clear();
|
||||
winning.set.push_back(card);
|
||||
|
||||
// Now look for the matching cards (Reverse order to order from A to 10)
|
||||
for(j = 1; j <= 4; j++) {
|
||||
// Ace low.
|
||||
look = (
|
||||
number == CARD_FIVE && j == 4 ?
|
||||
(enum CardValue)CARD_ACE :
|
||||
(enum CardValue)(number - j)
|
||||
);
|
||||
index = Card::contains(&winning.full, Card(suit, look));
|
||||
if(index == -1) break;
|
||||
winning.set.push_back(winning.full[index]);
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
|
||||
|
||||
// Add self to array
|
||||
winning.type = (
|
||||
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
|
||||
POKER_WINNING_TYPE_STRAIGHT_FLUSH
|
||||
);
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Four of a kind.
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];
|
||||
number = card.getValue();
|
||||
pairs = Card::countPairs(&winning.full, number);
|
||||
if(pairs.size() < CARD_SUIT_COUNT) continue;
|
||||
|
||||
winning.set = pairs;
|
||||
winning.type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Full House
|
||||
winning.set.clear();
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
// Check we haven't already added this card.
|
||||
card = winning.full[i];
|
||||
if(Card::contains(&winning.set, card) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
number = card.getValue();
|
||||
pairs = Card::countPairs(&winning.full, number);
|
||||
|
||||
// Did we find either two pair or three pair?
|
||||
if(pairs.size() != 2 && pairs.size() != 3) continue;
|
||||
if(winning.set.size() == 3) {//Clamp to 5 max.
|
||||
pairs.pop_back();
|
||||
}
|
||||
|
||||
// Copy found pairs.
|
||||
for(j = 0; j < pairs.size(); j++) {
|
||||
winning.set.push_back(pairs[j]);
|
||||
}
|
||||
|
||||
// Winned?
|
||||
if(winning.set.size() != POKER_WINNING_SET_SIZE) continue;
|
||||
winning.type = POKER_WINNING_TYPE_FULL_HOUSE;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Flush (5 same suit)
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];
|
||||
suit = card.getSuit();
|
||||
|
||||
winning.set.clear();
|
||||
winning.set.push_back(card);
|
||||
|
||||
for(j = i+1; j < winning.full.size(); j++) {
|
||||
if(winning.full[j].getSuit() != suit) continue;
|
||||
winning.set.push_back(winning.full[j]);
|
||||
if(winning.set.size() == POKER_WINNING_SET_SIZE) break;
|
||||
}
|
||||
if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
|
||||
winning.type = POKER_WINNING_TYPE_FLUSH;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Straight (sequence any suit)
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];
|
||||
number = card.getValue();
|
||||
if(number < CARD_FIVE) continue;
|
||||
|
||||
winning.set.clear();
|
||||
winning.set.push_back(card);
|
||||
|
||||
for(j = 1; j <= 4; j++) {
|
||||
// Ace low.
|
||||
look = (
|
||||
number == CARD_FIVE && j == 4 ?
|
||||
(enum CardValue)CARD_ACE :
|
||||
(enum CardValue)(number - j)
|
||||
);
|
||||
index = Card::containsNumber(&winning.full, look);
|
||||
if(index == -1) break;
|
||||
winning.set.push_back(winning.full[index]);
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning.set.size() < POKER_WINNING_SET_SIZE) continue;
|
||||
winning.type = POKER_WINNING_TYPE_STRAIGHT;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Three of a kind
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];
|
||||
number = card.getValue();
|
||||
pairs = Card::countPairs(&winning.full, number);
|
||||
if(pairs.size() != 3) continue;
|
||||
|
||||
winning.set = pairs;
|
||||
winning.type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Two Pair
|
||||
winning.set.clear();
|
||||
for(i = 0; i < winning.full.size(); i++) {
|
||||
card = winning.full[i];// Check we haven't already added this card.
|
||||
if(
|
||||
winning.set.size() > 0 &&
|
||||
Card::contains(&winning.set, card) != -1
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
number = card.getValue();
|
||||
pairs = Card::countPairs(&winning.full, number);
|
||||
if(pairs.size() != 2) continue;
|
||||
for(j = 0; j < pairs.size(); j++) {
|
||||
winning.set.push_back(pairs[j]);
|
||||
}
|
||||
if(winning.set.size() != 4) continue;
|
||||
winning.type = POKER_WINNING_TYPE_TWO_PAIR;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// Pair
|
||||
if(winning.set.size() == 2) {
|
||||
winning.type = POKER_WINNING_TYPE_PAIR;
|
||||
winning.fillRemaining();
|
||||
return winning;
|
||||
}
|
||||
|
||||
// High card
|
||||
winning.set.clear();
|
||||
winning.fillRemaining();
|
||||
winning.type = POKER_WINNING_TYPE_HIGH_CARD;
|
||||
return winning;
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "Card.hpp"
|
||||
#include "PokerPot.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
#include "display/animation/Easing.hpp"
|
||||
#include "PokerWinning.hpp"
|
||||
#include "PokerTurn.hpp"
|
||||
#include "util/random.hpp"
|
||||
|
||||
#define POKER_PLAYER_CHIPS_DEFAULT 10000
|
||||
|
||||
/** Maximum cards a players' hand can hold */
|
||||
#define POKER_PLAYER_HAND_SIZE_MAX 2
|
||||
|
||||
#define POKER_PLAYER_MAX_RAISES 0x02
|
||||
|
||||
namespace Dawn {
|
||||
class PokerGame;
|
||||
|
||||
class PokerPlayer : public SceneItemComponent {
|
||||
public:
|
||||
PokerGame *pokerGame;
|
||||
int32_t chips = 0;
|
||||
int32_t currentBet = 0;
|
||||
uint8_t timesRaised = 0;
|
||||
bool_t isFolded = false;
|
||||
bool_t isOut = false;
|
||||
bool_t hasBetThisRound = false;
|
||||
bool_t isShowingHand = false;
|
||||
bool_t isHuman = false;
|
||||
std::vector<struct Card> hand;
|
||||
|
||||
Event<> eventChipsChanged;
|
||||
|
||||
/**
|
||||
* Creates a PokerPlayer instance.
|
||||
*
|
||||
* @param item Item that this poker player belongs to.
|
||||
*/
|
||||
PokerPlayer(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/** Override for scene item component event for init */
|
||||
void onStart() override;
|
||||
|
||||
/**
|
||||
* Adds chips to the player. This will also update the players' state.
|
||||
*
|
||||
* @param chips Count of chips to add.
|
||||
*/
|
||||
void addChips(int32_t chips);
|
||||
|
||||
/**
|
||||
* Sets the chips a player has.
|
||||
*
|
||||
* @param chips Chips to set to the player.
|
||||
*/
|
||||
void setChips(int32_t chips);
|
||||
|
||||
/**
|
||||
* Returns true if the player still needs to bet this betting round.
|
||||
*
|
||||
* @return True if betting is still required by this player.
|
||||
*/
|
||||
bool_t needsToBetThisRound();
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the pot.
|
||||
*
|
||||
* @param pot Poker pot to bet in to.
|
||||
* @param amount The amount of chips the player is betting.
|
||||
*/
|
||||
void bet(struct PokerPot *pot, int32_t amount);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the current pot.
|
||||
*
|
||||
* @param amount The amount of chips the player is betting.
|
||||
*/
|
||||
void bet(int32_t amount);
|
||||
|
||||
/**
|
||||
* Player folds.
|
||||
*/
|
||||
void fold();
|
||||
|
||||
/**
|
||||
* Returns the AI result for a turn done by a non human player.
|
||||
*
|
||||
* @return Some information about the move the player is trying to perform
|
||||
*/
|
||||
struct PokerTurn getAITurn();
|
||||
|
||||
/**
|
||||
* Calculates and returns the winning state for a given player
|
||||
*
|
||||
* @return The winning state for this current players hand.
|
||||
*/
|
||||
struct PokerWinning getWinning();
|
||||
|
||||
/**
|
||||
* Returns the sum of chips in the pot(s) that the specified player is in.
|
||||
* This does not consider the pot, player or hand, just the pure sum of
|
||||
* chips.
|
||||
*
|
||||
* @return The sum of chips from the pots the player is within.
|
||||
*/
|
||||
int32_t getSumOfChips();
|
||||
|
||||
/**
|
||||
* Get the bet necessary for a specific player to make a call. This takes
|
||||
* the players current bet and the bet necessary to call into the pot and
|
||||
* will return the difference.
|
||||
*
|
||||
* @return The count of chips needed to call into the current active pot.
|
||||
*/
|
||||
int32_t getCallBet();
|
||||
|
||||
/**
|
||||
* Returns whether or not the player can check, or if they need to either
|
||||
* fold, call or bet.
|
||||
*
|
||||
* @return True if they can check.
|
||||
*/
|
||||
bool_t canCheck();
|
||||
};
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerPot.hpp"
|
||||
#include "PokerGame.hpp"
|
||||
#include "PokerPlayer.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
void PokerPotWinning::award() {
|
||||
auto it = this->winners.begin();
|
||||
while(it != this->winners.end()) {
|
||||
if(it == this->winners.begin()) {
|
||||
(*it)->addChips(this->chipsEach + this->chipsOverflow);
|
||||
} else {
|
||||
(*it)->addChips(this->chipsEach);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
struct PokerPotWinning PokerPot::getWinners(PokerGame *game) {
|
||||
struct PokerPotWinning winning;
|
||||
|
||||
winning.pot = this;
|
||||
|
||||
// Calculate the winnings first.
|
||||
auto it = this->players.begin();
|
||||
while(it != this->players.end()) {
|
||||
auto player = *it;
|
||||
|
||||
if(player->isOut || player->isFolded) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
winning.participants.push_back(player);
|
||||
winning.winnings[player] = player->getWinning();
|
||||
++it;
|
||||
}
|
||||
|
||||
// Compare participating players
|
||||
auto it2 = winning.participants.begin();
|
||||
while(it2 != winning.participants.end()) {
|
||||
auto playerLeft = *it2;
|
||||
auto winnerLeft = &winning.winnings[playerLeft];
|
||||
bool_t isWinner = true;
|
||||
enum CardValue highNumber = CARD_VALUE_INVALD;
|
||||
enum CardValue number = CARD_VALUE_INVALD;
|
||||
struct Card highCard(0xFF);
|
||||
struct Card card(0xFF);
|
||||
|
||||
auto it3 = winning.participants.begin();
|
||||
while(it3 != winning.participants.end()) {
|
||||
if(it2 == it3) {
|
||||
++it3;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto playerRight = *it3;
|
||||
auto winnerRight = &winning.winnings[playerRight];
|
||||
|
||||
// Am I the better hand / Is it the better hand?
|
||||
if(winnerLeft->type < winnerRight->type) {
|
||||
++it3;
|
||||
continue;
|
||||
}
|
||||
if(winnerLeft->type > winnerRight->type) {
|
||||
isWinner = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Equal, compare hands.
|
||||
card = PokerWinning::compare(winnerLeft, winnerRight);
|
||||
if(card.cardValue == 0xFF) {
|
||||
isWinner = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine high card.
|
||||
number = card.getValue();
|
||||
if(
|
||||
highNumber == CARD_VALUE_INVALD ||
|
||||
number == CARD_ACE ||
|
||||
number > highNumber
|
||||
) {
|
||||
highCard = card;
|
||||
highNumber = number;
|
||||
}
|
||||
++it3;
|
||||
}
|
||||
|
||||
if(!isWinner) {
|
||||
++it2;
|
||||
continue;
|
||||
}
|
||||
|
||||
winnerLeft->kicker = highCard;
|
||||
winning.winners.push_back(playerLeft);
|
||||
++it2;
|
||||
}
|
||||
|
||||
winning.chipsEach = this->chips / (int32_t)winning.winners.size();
|
||||
winning.chipsOverflow = this->chips - (
|
||||
winning.chipsEach * (int32_t)winning.winners.size()
|
||||
);
|
||||
|
||||
return winning;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerWinning.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer;
|
||||
class PokerGame;
|
||||
struct PokerPot;
|
||||
|
||||
struct PokerPotWinning {
|
||||
public:
|
||||
std::map<PokerPlayer*,struct PokerWinning> winnings;
|
||||
std::vector<PokerPlayer*> winners;
|
||||
std::vector<PokerPlayer*> participants;
|
||||
struct PokerPot *pot;
|
||||
int32_t chipsEach;
|
||||
int32_t chipsOverflow;
|
||||
|
||||
void award();
|
||||
};
|
||||
|
||||
struct PokerPot {
|
||||
public:
|
||||
int32_t chips;
|
||||
int32_t call;
|
||||
std::vector<PokerPlayer*> players;
|
||||
|
||||
struct PokerPotWinning getWinners(PokerGame *game);
|
||||
};
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerTurn.hpp"
|
||||
#include "PokerPlayer.hpp"
|
||||
#include "PokerGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct PokerTurn PokerTurn::bet(PokerPlayer *player, int32_t chips) {
|
||||
struct PokerTurn turn;
|
||||
int32_t i;
|
||||
|
||||
assertNotNull(player);
|
||||
assertTrue(chips >= 0);
|
||||
|
||||
turn.player = player;
|
||||
turn.confidence = 1;
|
||||
|
||||
if(chips == 0) {
|
||||
turn.type = POKER_TURN_TYPE_CHECK;
|
||||
turn.chips = 0;
|
||||
} else if(player->chips <= chips) {
|
||||
turn.chips = player->chips;
|
||||
turn.type = POKER_TURN_TYPE_ALL_IN;
|
||||
} else {
|
||||
turn.chips = chips;
|
||||
turn.type = POKER_TURN_TYPE_BET;
|
||||
i = player->pokerGame->getCurrentCallValue();
|
||||
|
||||
if(chips == (i - player->currentBet)) {
|
||||
turn.type = POKER_TURN_TYPE_CALL;
|
||||
}
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
struct PokerTurn PokerTurn::fold(PokerPlayer *player) {
|
||||
struct PokerTurn turn;
|
||||
turn.player = player;
|
||||
turn.chips = 0;
|
||||
turn.confidence = 1;
|
||||
turn.type = POKER_TURN_TYPE_FOLD;
|
||||
return turn;
|
||||
}
|
||||
|
||||
void PokerTurn::action() {
|
||||
assertNotNull(this->player);
|
||||
|
||||
switch(this->type) {
|
||||
case POKER_TURN_TYPE_BET:
|
||||
case POKER_TURN_TYPE_CALL:
|
||||
case POKER_TURN_TYPE_ALL_IN:
|
||||
this->player->bet(this->chips);
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_CHECK:
|
||||
player->bet(0);
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_FOLD:
|
||||
player->fold();
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer;
|
||||
|
||||
enum PokerTurnType {
|
||||
POKER_TURN_TYPE_OUT,
|
||||
POKER_TURN_TYPE_FOLD,
|
||||
POKER_TURN_TYPE_BET,
|
||||
POKER_TURN_TYPE_CALL,
|
||||
POKER_TURN_TYPE_CHECK,
|
||||
POKER_TURN_TYPE_ALL_IN
|
||||
};
|
||||
|
||||
struct PokerTurn {
|
||||
public:
|
||||
/** What type of action the turn is */
|
||||
enum PokerTurnType type;
|
||||
/** How many chips they did in their turn (if applicable) */
|
||||
int32_t chips;
|
||||
/** How confident the AI is about their turn. 0 = none, 1 = full */
|
||||
float_t confidence;
|
||||
/** Player that this action belongs to */
|
||||
PokerPlayer *player;
|
||||
|
||||
/**
|
||||
* Generate a turn action for betting as a player.
|
||||
*
|
||||
* @param player Player index who is betting.
|
||||
* @param chips Chips to raise by.
|
||||
* @return A turn for a bet action.
|
||||
*/
|
||||
static struct PokerTurn bet(PokerPlayer *player, int32_t chips);
|
||||
|
||||
/**
|
||||
* Return a turn action for the given player to fold.
|
||||
*
|
||||
* @return A turn for a fold action.
|
||||
*/
|
||||
static struct PokerTurn fold(PokerPlayer *player);
|
||||
|
||||
/**
|
||||
* Actions / Performs this turn against the defined player.
|
||||
*/
|
||||
void action();
|
||||
};
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerWinning.hpp"
|
||||
#include "PokerPlayer.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
float_t PokerWinning::getWinningTypeConfidence(enum PokerWinningType type) {
|
||||
switch(type) {
|
||||
case POKER_WINNING_TYPE_ROYAL_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_ROYAL_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH;
|
||||
case POKER_WINNING_TYPE_FOUR_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_FULL_HOUSE:
|
||||
return POKER_WINNING_CONFIDENCE_FULL_HOUSE;
|
||||
case POKER_WINNING_TYPE_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT;
|
||||
case POKER_WINNING_TYPE_THREE_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_TWO_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_TWO_PAIR;
|
||||
case POKER_WINNING_TYPE_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_PAIR;
|
||||
default:
|
||||
return POKER_WINNING_CONFIDENCE_HIGH_CARD;
|
||||
}
|
||||
}
|
||||
|
||||
struct Card PokerWinning::compare(
|
||||
struct PokerWinning *left,
|
||||
struct PokerWinning *right
|
||||
) {
|
||||
assertNotNull(left);
|
||||
assertNotNull(right);
|
||||
|
||||
uint8_t i;
|
||||
enum CardValue number = CARD_VALUE_INVALD;
|
||||
enum CardValue highNumberLeft = CARD_VALUE_INVALD;
|
||||
enum CardValue highNumberRight = CARD_VALUE_INVALD;
|
||||
struct Card card(0xFF), highCardLeft(0xFF), highCardRight(0xFF);
|
||||
int32_t index;
|
||||
uint8_t countCardsSame;
|
||||
|
||||
countCardsSame = 0;
|
||||
|
||||
for(i = 0; i < left->set.size(); i++) {
|
||||
card = left->set[i];
|
||||
number = card.getValue();
|
||||
// Quick check
|
||||
if(highNumberLeft != CARD_VALUE_INVALD && number < highNumberLeft) continue;
|
||||
|
||||
// Check if this number is within the other hand or not
|
||||
index = Card::containsNumber(&right->set, number);
|
||||
if(index != -1) {
|
||||
// This number IS within the other hand, let's check that the EXACT card
|
||||
// is a match/isn't a match.
|
||||
index = Card::contains(&right->set, card);
|
||||
|
||||
// Exact card match
|
||||
if(index != -1) {
|
||||
countCardsSame++;
|
||||
continue;
|
||||
}
|
||||
// Not exact card match.. ?
|
||||
}
|
||||
|
||||
if(
|
||||
highNumberLeft == CARD_VALUE_INVALD ||
|
||||
number == CARD_ACE ||
|
||||
highNumberLeft < number
|
||||
) {
|
||||
highNumberLeft = number;
|
||||
highCardLeft = card;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < right->set.size(); i++) {
|
||||
card = right->set[i];
|
||||
number = card.getValue();
|
||||
if(highNumberRight != CARD_VALUE_INVALD && number < highNumberRight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
index = Card::containsNumber(&left->set, number);
|
||||
if(index != -1) {
|
||||
index = Card::contains(&left->set, card);
|
||||
if(index != -1) continue;
|
||||
}
|
||||
|
||||
if(
|
||||
highNumberRight == CARD_VALUE_INVALD ||
|
||||
number == CARD_ACE || highNumberRight < number
|
||||
) {
|
||||
highNumberRight = number;
|
||||
highCardRight = card;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(countCardsSame == left->set.size()) {
|
||||
for(i = 0; i < left->set.size(); i++) {
|
||||
card = left->set[i];
|
||||
number = card.getValue();
|
||||
if(
|
||||
highNumberLeft == CARD_VALUE_INVALD ||
|
||||
number == CARD_ACE ||
|
||||
highNumberLeft < number
|
||||
) {
|
||||
highNumberLeft = number;
|
||||
highCardLeft = card;
|
||||
}
|
||||
}
|
||||
return highCardLeft;
|
||||
}
|
||||
|
||||
if(highCardLeft.cardValue == CARD_VALUE_INVALD) return 0xFF;
|
||||
if(highNumberLeft < highNumberRight) return 0xFF;
|
||||
return highCardLeft;// Greater or Equal to.
|
||||
}
|
||||
|
||||
void PokerWinning::fillRemaining() {
|
||||
uint8_t i, highest, current;
|
||||
struct Card highestCard(0x00);
|
||||
struct Card currentCard(0x00);
|
||||
|
||||
// Set the kicker
|
||||
this->kicker = 0xFF;
|
||||
|
||||
// Fill the remaining cards
|
||||
while(this->set.size() < POKER_WINNING_SET_SIZE) {
|
||||
highest = 0xFF;
|
||||
|
||||
for(i = 0; i < this->full.size(); i++) {
|
||||
currentCard = this->full[i];
|
||||
if(Card::contains(&this->set, currentCard) != -1) continue;
|
||||
|
||||
if(highest == 0xFF) {
|
||||
highestCard = currentCard;
|
||||
highest = highestCard.getValue();
|
||||
} else {
|
||||
current = currentCard.getValue();
|
||||
if(current != CARD_ACE && current < highest) continue;
|
||||
highestCard = currentCard;
|
||||
highest = current;
|
||||
}
|
||||
}
|
||||
|
||||
if(highest == 0xFF) break;
|
||||
this->set.push_back(highestCard);
|
||||
}
|
||||
Card::sort(&this->set);
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "Card.hpp"
|
||||
|
||||
#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1.0f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 0.99f
|
||||
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 0.9f
|
||||
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 0.85f
|
||||
#define POKER_WINNING_CONFIDENCE_FLUSH 0.8f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT 0.7f
|
||||
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 0.5f
|
||||
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 0.4f
|
||||
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f
|
||||
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f
|
||||
|
||||
/** How many cards in the winning set */
|
||||
#define POKER_WINNING_SET_SIZE 5
|
||||
|
||||
namespace Dawn {
|
||||
class PokerPlayer;
|
||||
|
||||
enum PokerWinningType {
|
||||
POKER_WINNING_TYPE_NULL,
|
||||
POKER_WINNING_TYPE_ROYAL_FLUSH,
|
||||
POKER_WINNING_TYPE_STRAIGHT_FLUSH,
|
||||
POKER_WINNING_TYPE_FOUR_OF_A_KIND,
|
||||
POKER_WINNING_TYPE_FULL_HOUSE,
|
||||
POKER_WINNING_TYPE_FLUSH,
|
||||
POKER_WINNING_TYPE_STRAIGHT,
|
||||
POKER_WINNING_TYPE_THREE_OF_A_KIND,
|
||||
POKER_WINNING_TYPE_TWO_PAIR,
|
||||
POKER_WINNING_TYPE_PAIR,
|
||||
POKER_WINNING_TYPE_HIGH_CARD
|
||||
};
|
||||
|
||||
struct PokerWinning {
|
||||
public:
|
||||
/**
|
||||
* Get the confidence of the bet for a given winning type.
|
||||
*
|
||||
* @param type Winning type type.
|
||||
* @return The confidence.
|
||||
*/
|
||||
static float_t getWinningTypeConfidence(enum PokerWinningType type);
|
||||
|
||||
/**
|
||||
* Compares two winning sets. The returned card is the kicker if the LEFT
|
||||
* side is the winner. If LEFT is not a winner then 0xFF will be returned.
|
||||
*
|
||||
* @param left Left winning set.
|
||||
* @param right Right winning set.
|
||||
* @return The kicker card from left's hand or 0xFF if not the winner.
|
||||
*/
|
||||
static struct Card compare(
|
||||
struct PokerWinning *left,
|
||||
struct PokerWinning *right
|
||||
);
|
||||
|
||||
/** Winning Type */
|
||||
enum PokerWinningType type;
|
||||
/** The full set of both the dealer and player's hand */
|
||||
std::vector<struct Card> full;
|
||||
/** Holds the winning set */
|
||||
std::vector<struct Card> set;
|
||||
/** If there was a kicker card it will be here */
|
||||
struct Card kicker;
|
||||
/* The player this winning state belongs to */
|
||||
PokerPlayer *player;
|
||||
|
||||
PokerWinning() : kicker(0xFF) {}
|
||||
|
||||
/**
|
||||
* Fills the remaining cards for a given poker player winning hand.
|
||||
* Essentially this will just take the highest cards and slot them into
|
||||
* the array. This also sorts the cards.
|
||||
*
|
||||
* @param winning Pointer to the poker winning to fill out.
|
||||
*/
|
||||
void fillRemaining();
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
PokerDetermineBetterEvent.cpp
|
||||
)
|
@ -1,142 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
#define POKER_DEAL_EVENT_CARD_COUNT 2
|
||||
|
||||
namespace Dawn {
|
||||
class PokerAIBetEvent : public PokerGameEvent {
|
||||
protected:
|
||||
IVisualNovelEvent * eventFold = nullptr;
|
||||
IVisualNovelEvent * eventBet = nullptr;
|
||||
IVisualNovelEvent * eventCall = nullptr;
|
||||
IVisualNovelEvent * eventCheck = nullptr;
|
||||
IVisualNovelEvent * eventAllIn = nullptr;
|
||||
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
|
||||
auto better = this->pokerGame->getNextBetterIndex();
|
||||
this->pokerGame->betterIndex = better;
|
||||
auto player = this->pokerGame->players[better];
|
||||
this->turn = player->getAITurn();
|
||||
this->turn.action();
|
||||
|
||||
switch(this->turn.type) {
|
||||
case POKER_TURN_TYPE_FOLD:
|
||||
this->then(this->eventFold);
|
||||
this->eventFold = nullptr;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_BET:
|
||||
this->then(this->eventBet);
|
||||
this->eventBet = nullptr;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_CALL:
|
||||
this->then(this->eventCall);
|
||||
this->eventCall = nullptr;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_CHECK:
|
||||
this->then(this->eventCheck);
|
||||
this->eventCheck = nullptr;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_ALL_IN:
|
||||
this->then(this->eventAllIn);
|
||||
this->eventAllIn = nullptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t better;
|
||||
struct PokerTurn turn;
|
||||
|
||||
PokerAIBetEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that is triggered when the action was a folded event.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenFolded(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventFold = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that is triggered when the action was a bet event.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenBetting(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventBet = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that is triggered when the action was a call event.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenCalling(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventCall = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that is triggered when the action was a check event.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenChecking(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventCheck = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event that is triggered when the action was an all-in event.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenAllIn(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventAllIn = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
~PokerAIBetEvent() {
|
||||
if(this->eventFold != nullptr) delete this->eventFold;
|
||||
if(this->eventBet != nullptr) delete this->eventBet;
|
||||
if(this->eventCall != nullptr) delete this->eventCall;
|
||||
if(this->eventCheck != nullptr) delete this->eventCheck;
|
||||
if(this->eventAllIn != nullptr) delete this->eventAllIn;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
#define POKER_DEAL_EVENT_CARD_COUNT 2
|
||||
|
||||
namespace Dawn {
|
||||
class PokerDealEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "Dealing to everyone" << std::endl;
|
||||
this->pokerGame->dealToEveryone(POKER_DEAL_EVENT_CARD_COUNT);
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerDealEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PokerDetermineBetterEvent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PokerDetermineBetterEvent::PokerDetermineBetterEvent(VisualNovelManager *man) :
|
||||
PokerGameEvent(man)
|
||||
{
|
||||
std::cout << "Inited determine better" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void PokerDetermineBetterEvent::onStart(IVisualNovelEvent *previous) {
|
||||
PokerGameEvent::onStart(previous);
|
||||
|
||||
std::cout << "better evt" << std::endl;
|
||||
|
||||
if(this->pokerGame->getRemainingPlayersCount() <= 1) {
|
||||
this->then(this->eventEveryoneFolded);
|
||||
this->eventEveryoneFolded = nullptr;
|
||||
std::cout << "Everyone folded" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t nextBetterIndex = this->pokerGame->getNextBetterIndex();
|
||||
if(nextBetterIndex == 0xFF) {
|
||||
if(this->pokerGame->getCountOfCardsToTurn() == 0xFF) {
|
||||
this->then(this->eventBettingFinished);
|
||||
this->eventBettingFinished = nullptr;
|
||||
std::cout << "Betting Finished" << std::endl;
|
||||
} else {
|
||||
this->then(this->eventTurn);
|
||||
this->eventTurn = nullptr;
|
||||
std::cout << "Turn Time?" << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto nextBetter = this->pokerGame->players[nextBetterIndex];
|
||||
if(nextBetter->isHuman) {
|
||||
this->then(this->eventHumanBet);
|
||||
this->eventHumanBet = nullptr;
|
||||
std::cout << "Human Better" << std::endl;
|
||||
} else {
|
||||
this->then(this->eventAiBet);
|
||||
this->eventAiBet = nullptr;
|
||||
std::cout << "AI Better" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t PokerDetermineBetterEvent::onUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PokerDetermineBetterEvent::onEnd() {
|
||||
}
|
||||
|
||||
PokerDetermineBetterEvent::~PokerDetermineBetterEvent() {
|
||||
if(this->eventEveryoneFolded != nullptr) delete this->eventEveryoneFolded;
|
||||
if(this->eventBettingFinished != nullptr) delete this->eventBettingFinished;
|
||||
if(this->eventTurn != nullptr) delete this->eventTurn;
|
||||
if(this->eventAiBet != nullptr) delete this->eventAiBet;
|
||||
if(this->eventHumanBet != nullptr) delete this->eventHumanBet;
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerDetermineBetterEvent : public PokerGameEvent {
|
||||
protected:
|
||||
IVisualNovelEvent * eventEveryoneFolded = nullptr;
|
||||
IVisualNovelEvent * eventBettingFinished = nullptr;
|
||||
IVisualNovelEvent * eventTurn = nullptr;
|
||||
IVisualNovelEvent * eventAiBet = nullptr;
|
||||
IVisualNovelEvent * eventHumanBet = nullptr;
|
||||
|
||||
void onStart(IVisualNovelEvent *previous) override;
|
||||
bool_t onUpdate() override;
|
||||
void onEnd() override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a better determine event.
|
||||
*
|
||||
* @param manager VN manager that this event belongs to.
|
||||
*/
|
||||
PokerDetermineBetterEvent(VisualNovelManager *manager);
|
||||
|
||||
/**
|
||||
* Sets the event that is triggered when everyone is folded.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenEveryoneFolded(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventEveryoneFolded = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event that is triggered after everyone has finished betting.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenBettingFinished(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventBettingFinished = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event to trigger when all betting is finished and its time to turn the
|
||||
* next set of community cards.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenTurn(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventTurn = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event to trigger when its an AI's turn to bet.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenAiBet(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventAiBet = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event to trigger when its a human's turn to bet.
|
||||
*
|
||||
* @param event Event to trigger.
|
||||
* @return The event that was passed in.
|
||||
*/
|
||||
template<class T>
|
||||
T * whenHumanBet(T *event) {
|
||||
assertNotNull(event);
|
||||
this->eventHumanBet = event;
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose override for the event.
|
||||
*/
|
||||
~PokerDetermineBetterEvent();
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "visualnovel/VisualNovelManager.hpp"
|
||||
#include "poker/PokerGame.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerGameEvent : public IVisualNovelEvent {
|
||||
protected:
|
||||
PokerGame *pokerGame;
|
||||
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
pokerGame = this->manager->getScene()->findComponent<PokerGame>();
|
||||
assertNotNull(pokerGame);
|
||||
}
|
||||
|
||||
public:
|
||||
PokerGameEvent(VisualNovelManager *manager) :
|
||||
IVisualNovelEvent(manager)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerNewBettingRoundEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "New Betting Round" << std::endl;
|
||||
this->pokerGame->newBettingRound();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerNewBettingRoundEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerNewGameEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "New Game" << std::endl;
|
||||
this->pokerGame->newGame();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerNewGameEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerNewRoundEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "New Round" << std::endl;
|
||||
this->pokerGame->newRound();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerNewRoundEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerTakeBlindsEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "Take Blinds" << std::endl;
|
||||
this->pokerGame->takeBlinds();
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
PokerTakeBlindsEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerTurnEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
|
||||
this->cardsTurned = this->pokerGame->getCountOfCardsToTurn();
|
||||
assertTrue(this->cardsTurned != 0xFF);
|
||||
|
||||
this->pokerGame->turn(this->cardsTurned);
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t cardsTurned;
|
||||
|
||||
PokerTurnEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PokerGameEvent.hpp"
|
||||
#include "poker/PokerPot.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PokerWinnerEvent : public PokerGameEvent {
|
||||
protected:
|
||||
void onStart(IVisualNovelEvent *previous) override {
|
||||
PokerGameEvent::onStart(previous);
|
||||
std::cout << "Poker Winning" << std::endl;
|
||||
|
||||
// Calculate
|
||||
auto it = this->pokerGame->pots.begin();
|
||||
while(it != this->pokerGame->pots.end()) {
|
||||
auto pot = &(*it);
|
||||
this->winnings[pot] = pot->getWinners(this->pokerGame);
|
||||
++it;
|
||||
}
|
||||
|
||||
// Award
|
||||
auto it2 = this->winnings.begin();
|
||||
while(it2 != this->winnings.end()) {
|
||||
it2->second.award();
|
||||
it2++;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t onUpdate() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void onEnd() override {
|
||||
}
|
||||
|
||||
public:
|
||||
std::map<struct PokerPot*, struct PokerPotWinning> winnings;
|
||||
|
||||
PokerWinnerEvent(VisualNovelManager *manager) : PokerGameEvent(manager) {
|
||||
}
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
TicTacToeLogic.cpp
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user