diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 783b56be..9f4e3119 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ if(DAWN_TARGET STREQUAL "linux-x64-glfw") add_subdirectory(dawnlinux) add_subdirectory(dawnglfw) add_subdirectory(dawnopengl) - add_subdirectory(dawnpoker) + # add_subdirectory(dawnpoker) else() message(FATAL_ERROR "You need to define an entry target") endif() diff --git a/src/dawn/CMakeLists.txt b/src/dawn/CMakeLists.txt index 1cc36339..67dbdae7 100644 --- a/src/dawn/CMakeLists.txt +++ b/src/dawn/CMakeLists.txt @@ -8,6 +8,7 @@ target_link_libraries(${DAWN_TARGET_NAME} PUBLIC glm archive_static + freetype ) # Includes @@ -29,6 +30,7 @@ add_subdirectory(game) add_subdirectory(locale) add_subdirectory(prefab) # add_subdirectory(physics) +add_subdirectory(poker) add_subdirectory(save) add_subdirectory(scene) # add_subdirectory(state) diff --git a/src/dawn/display/font/CMakeLists.txt b/src/dawn/display/font/CMakeLists.txt new file mode 100644 index 00000000..e92f0a96 --- /dev/null +++ b/src/dawn/display/font/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +target_sources(${DAWN_TARGET_NAME} + PRIVATE + TrueTypeTexture.cpp +) diff --git a/src/dawn/display/font/TrueTypeCharacter.hpp b/src/dawn/display/font/TrueTypeCharacter.hpp new file mode 100644 index 00000000..f4e04451 --- /dev/null +++ b/src/dawn/display/font/TrueTypeCharacter.hpp @@ -0,0 +1,16 @@ +// 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 { + struct TrueTypeCharacter { + glm::vec2 advance; + glm::vec2 size; + glm::vec2 offset; + glm::vec4 quad; + }; +} \ No newline at end of file diff --git a/src/dawn/display/font/TrueTypeTexture.cpp b/src/dawn/display/font/TrueTypeTexture.cpp new file mode 100644 index 00000000..dee30e0c --- /dev/null +++ b/src/dawn/display/font/TrueTypeTexture.cpp @@ -0,0 +1,198 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "TrueTypeTexture.hpp" +#include "assert/assert.hpp" +#include "util/Math.hpp" +#include "display/mesh/QuadMesh.hpp" + +using namespace Dawn; + +TrueTypeTexture::TrueTypeTexture(const uint32_t fontSize) : + fontSize(fontSize) +{ + assertTrue(fontSize > 0, "Font size cannot be zero"); + texture = std::make_shared(); +} + +void TrueTypeTexture::setFace(const FT_Face face) { + this->face = face; + assertTrue(fontSize < 256, "Font size cannot be greater than 256"); + + // Set freetype font size prior to baking. + auto ret = FT_Set_Pixel_Sizes(face, 0, fontSize); + if(ret != 0) { + assertUnreachable("Failed to set font size %i", ret); + } + + // Set the texture size + texture->setSize( + fontSize * 24, + fontSize * 24, + TextureFormat::R, + TextureDataFormat::UNSIGNED_BYTE + ); + + // Texture buffer + uint8_t *buffer = new uint8_t[texture->getWidth() * texture->getHeight()]; + // Fill with zeros + std::memset(buffer, 0, texture->getWidth() * texture->getHeight()); + + size_t offset = 0; + struct TrueTypeCharacter info; + int32_t textureX = 0, textureY = 0; + int32_t rowHeight = 0; + + // Character sets + std::vector characterBlocks; + // Latin + for(wchar_t c = 0x0020; c < 0x007F; c++) characterBlocks.push_back(c); + // Latin-1 Supplement + for(wchar_t c = 0x00A0; c < 0x00FF; c++) characterBlocks.push_back(c); + // Latin Extended-A + for(wchar_t c = 0x0100; c < 0x017F; c++) characterBlocks.push_back(c); + // Latin Extended-B + for(wchar_t c = 0x0180; c < 0x024F; c++) characterBlocks.push_back(c); + // Hiragana + for(wchar_t c = 0x3040; c < 0x309F; c++) characterBlocks.push_back(c); + // Katakana + for(wchar_t c = 0x30A0; c < 0x30FF; c++) characterBlocks.push_back(c); + + // For each character in the character set + for(wchar_t c : characterBlocks) { + // Load the character + if(FT_Load_Char(face, c, FT_LOAD_RENDER)) { + assertUnreachable("Failed to load character (1)"); + } + + // Store the character information + info.advance.x = (float_t)(face->glyph->advance.x >> 6); + info.advance.y = (float_t)(face->glyph->advance.y >> 6); + info.size = glm::vec2(face->glyph->bitmap.width, face->glyph->bitmap.rows); + + // Determine the texture position + if(textureX + face->glyph->bitmap.width >= texture->getWidth()) { + textureX = 0; + textureY += rowHeight + 2;// Tiny gap between rows + rowHeight = face->glyph->bitmap.rows; + } else { + rowHeight = Math::max(rowHeight, face->glyph->bitmap.rows); + } + + // Set the quad positions + info.offset = glm::vec2( + face->glyph->bitmap_left, + -face->glyph->bitmap_top + ); + info.quad = glm::vec4( + textureX, + textureY, + textureX + face->glyph->bitmap.width, + textureY + face->glyph->bitmap.rows + ) / glm::vec4( + texture->getWidth(), + texture->getHeight(), + texture->getWidth(), + texture->getHeight() + ); + + // Store the cached character data. + this->characterData[c] = info; + + // Determine pixel offset. + offset = textureX + (textureY * texture->getWidth()); + assertTrue( + offset + (face->glyph->bitmap.rows * texture->getWidth()) <= + texture->getWidth() * texture->getHeight(), + "Font texture buffer overflow will occur." + ); + + // Buffer pixels, we have to do this one row at a time due to the + // differences in width between the glyph and the texture. + const size_t countPerRow = face->glyph->bitmap.width; + int32_t i = 0; + while(i != face->glyph->bitmap.rows) { + std::memcpy( + buffer + offset + (i * texture->getWidth()), + face->glyph->bitmap.buffer + (i * countPerRow), + countPerRow + ); + i++; + } + + // Increment textureX + textureX += face->glyph->bitmap.width + 2;// I add a tiny gap between chars + } + + this->texture->buffer(buffer); + delete[] buffer; +} + +struct TrueTypeCharacter TrueTypeTexture::getCharacterData(wchar_t c) { + return this->characterData[c]; +} + +glm::vec2 TrueTypeTexture::bufferStringToMesh( + std::shared_ptr mesh, + const std::wstring text, + glm::vec2 &position, + bool_t flipY +) { + assertNotNull(mesh, "Mesh must be supplied and not null"); + assertTrue(text.size() > 0, "Text must be at least one character long."); + + // Create mesh buffers + mesh->createBuffers( + text.length() * QUAD_VERTICE_COUNT, + text.length() * QUAD_INDICE_COUNT + ); + + // Foreach char + size_t i = 0; + glm::vec2 size = { 0, 0 }; + for(wchar_t c : text) { + // Get the character data + auto info = this->getCharacterData(c); + + // Buffer the quad + glm::vec4 quad = glm::vec4( + position.x, + position.y, + position.x + info.size.x, + position.y + info.size.y + ); + if(flipY) { + QuadMesh::buffer( + mesh, + quad, + glm::vec4( + info.quad.x, + info.quad.w, + info.quad.z, + info.quad.y + ), + i * QUAD_VERTICE_COUNT, + i * QUAD_INDICE_COUNT + ); + } else { + QuadMesh::buffer( + mesh, + quad, + info.quad, + i * QUAD_VERTICE_COUNT, + i * QUAD_INDICE_COUNT + ); + } + position += info.advance; + size += info.advance; + + i++; + } + + return size; +} + +TrueTypeTexture::~TrueTypeTexture() { +} diff --git a/src/dawn/display/font/TrueTypeTexture.hpp b/src/dawn/display/font/TrueTypeTexture.hpp new file mode 100644 index 00000000..ece25333 --- /dev/null +++ b/src/dawn/display/font/TrueTypeTexture.hpp @@ -0,0 +1,66 @@ +// 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 "TrueTypeCharacter.hpp" +#include "display/mesh/Mesh.hpp" +#include +#include FT_FREETYPE_H + +namespace Dawn { + class TrueTypeTexture final { + private: + FT_Face face; + + public: + uint32_t fontSize; + std::shared_ptr texture; + std::unordered_map characterData; + + /** + * Construct a new New True Type Face Texture object + * + * @param fontSize Size of the font. + */ + TrueTypeTexture(const uint32_t fontSize); + + /** + * Sets the face for this texture. + * + * @param face Face to set. + */ + void setFace(const FT_Face face); + + /** + * 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(wchar_t c); + + /** + * Buffers a string to the given mesh. + * + * @param mesh Mesh to buffer to. + * @param text Text to buffer. + * @param position Position to buffer to. + * @param flipY Whether or not to flip the Y axis. + * @return The size of the string. + */ + glm::vec2 bufferStringToMesh( + std::shared_ptr mesh, + const std::wstring text, + glm::vec2 &position, + bool_t flipY = false + ); + + /** + * Destroys this true type face texture. + */ + ~TrueTypeTexture(); + }; +} \ No newline at end of file diff --git a/src/dawnpoker/poker/CMakeLists.txt b/src/dawn/poker/CMakeLists.txt similarity index 100% rename from src/dawnpoker/poker/CMakeLists.txt rename to src/dawn/poker/CMakeLists.txt diff --git a/src/dawnpoker/poker/Card.cpp b/src/dawn/poker/Card.cpp similarity index 100% rename from src/dawnpoker/poker/Card.cpp rename to src/dawn/poker/Card.cpp diff --git a/src/dawnpoker/poker/Card.hpp b/src/dawn/poker/Card.hpp similarity index 100% rename from src/dawnpoker/poker/Card.hpp rename to src/dawn/poker/Card.hpp diff --git a/src/dawnpoker/poker/PokerGame.cpp b/src/dawn/poker/PokerGame.cpp similarity index 80% rename from src/dawnpoker/poker/PokerGame.cpp rename to src/dawn/poker/PokerGame.cpp index eb26ee12..0782a00c 100644 --- a/src/dawnpoker/poker/PokerGame.cpp +++ b/src/dawn/poker/PokerGame.cpp @@ -7,8 +7,26 @@ using namespace Dawn; +std::shared_ptr PokerGame::addNewPlayer() { + auto player = std::make_shared( + weak_from_this(), this->players.size() + ); + assertFalse(this->players.size() == PLAYER_COUNT_MAX, "Too many players."); + this->players.push_back(player); + return player; +} + +std::shared_ptr PokerGame::getCurrentBetter() { + auto nextIndex = this->getNextBetterIndex(); + if(nextIndex == 0xFF) return nullptr; + return this->players[nextIndex]; +} + void PokerGame::newGame() { + assertTrue(this->players.size() >= PLAYER_COUNT_MIN, "Not enough players."); this->newRound(); + this->smallBlind = POKER_BLIND_SMALL_DEFAULT; + this->bigBlind = POKER_BLIND_BIG_DEFAULT; auto it = this->players.begin(); while(it != this->players.end()) { @@ -25,13 +43,15 @@ 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()); + this->hasFlopped = false; + this->hasTurned = false; + this->hasRivered = false; + auto it = this->players.begin(); while(it != this->players.end()) { auto player = *it; @@ -159,8 +179,10 @@ void PokerGame::dealToEveryone(const uint8_t count) { } void PokerGame::turn(const uint8_t count) { - assertTrue(this->deck.size() >= count, "Not enough cards to turn."); - for(uint8_t i = 0; i < count; i++) { + uint8_t c = count; + if(c == 0xFF) c = this->getCountOfCardsToTurn(); + assertTrue(this->deck.size() >= c, "Not enough cards to turn."); + for(uint8_t i = 0; i < c; i++) { auto card = this->deck.back(); this->deck.pop_back(); this->community.push_back(card); @@ -168,17 +190,8 @@ void PokerGame::turn(const uint8_t count) { } 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; - } + if(!this->hasFlopped) return 3; + if(!this->hasTurned) return 1; + if(!this->hasRivered) return 1; + assertUnreachable("No more cards to turn."); } \ No newline at end of file diff --git a/src/dawnpoker/poker/PokerGame.hpp b/src/dawn/poker/PokerGame.hpp similarity index 81% rename from src/dawnpoker/poker/PokerGame.hpp rename to src/dawn/poker/PokerGame.hpp index fbc79d64..beeb99cf 100644 --- a/src/dawnpoker/poker/PokerGame.hpp +++ b/src/dawn/poker/PokerGame.hpp @@ -16,8 +16,11 @@ #define POKER_TURN_CARD_COUNT 1 #define POKER_RIVER_CARD_COUNT 1 +#define PLAYER_COUNT_MAX 8 +#define PLAYER_COUNT_MIN 2 + namespace Dawn { - class PokerGame { + class PokerGame : public std::enable_shared_from_this { protected: std::vector deck; std::vector grave; @@ -27,12 +30,28 @@ namespace Dawn { int32_t smallBlind = POKER_BLIND_SMALL_DEFAULT; int32_t bigBlind = POKER_BLIND_BIG_DEFAULT; + bool_t hasFlopped = false; + bool_t hasTurned = false; + bool_t hasRivered = false; + public: std::vector> players; std::vector pots; std::vector community; uint8_t betterIndex; + /** + * Creates and adds a new player to the game. + */ + std::shared_ptr addNewPlayer(); + + /** + * Returns the player that is currently the better. + * + * @return The player that is currently the better. + */ + std::shared_ptr getCurrentBetter(); + /** * Starts a new game of poker. */ @@ -103,13 +122,17 @@ namespace Dawn { /** * Deals a card to each player. + * + * @param count The count of cards to deal. */ void dealToEveryone(const uint8_t count); /** * Deals a card to the community. + * + * @param count The count of cards to turn. */ - void turn(const uint8_t count); + void turn(const uint8_t count = 0xFF); /** * Returns the count of cards that need to be turned. diff --git a/src/dawnpoker/poker/PokerPlayer.cpp b/src/dawn/poker/PokerPlayer.cpp similarity index 98% rename from src/dawnpoker/poker/PokerPlayer.cpp rename to src/dawn/poker/PokerPlayer.cpp index 993bd1ca..c09fd776 100644 --- a/src/dawnpoker/poker/PokerPlayer.cpp +++ b/src/dawn/poker/PokerPlayer.cpp @@ -11,8 +11,12 @@ using namespace Dawn; -PokerPlayer::PokerPlayer(std::weak_ptr pokerGame) { +PokerPlayer::PokerPlayer( + const std::weak_ptr pokerGame, + const uint8_t playerIndex +) { this->pokerGame = pokerGame; + this->playerIndex = playerIndex; this->chips = POKER_PLAYER_CHIPS_DEFAULT; } @@ -68,7 +72,6 @@ void PokerPlayer::bet(const int32_t chips) { auto pg = this->pokerGame.lock(); assertNotNull(pg, "PokerGame has become invalid."); assertTrue(pg->pots.size() > 0, "PokerGame has no pots?"); - assertUnreachable("Bugged"); this->bet(pg->pots.back(), chips); } diff --git a/src/dawnpoker/poker/PokerPlayer.hpp b/src/dawn/poker/PokerPlayer.hpp similarity index 94% rename from src/dawnpoker/poker/PokerPlayer.hpp rename to src/dawn/poker/PokerPlayer.hpp index eba2cfff..35f597bc 100644 --- a/src/dawnpoker/poker/PokerPlayer.hpp +++ b/src/dawn/poker/PokerPlayer.hpp @@ -23,6 +23,7 @@ namespace Dawn { class PokerPlayer : public std::enable_shared_from_this { public: std::weak_ptr pokerGame; + uint8_t playerIndex; int32_t chips = 0; int32_t currentBet = 0; uint8_t timesRaised = 0; @@ -39,8 +40,12 @@ namespace Dawn { * Constructor for the PokerPlayer class. * * @param pokerGame Poker game this player is a part of. + * @param playerIndex Index of the player in the game. */ - PokerPlayer(std::weak_ptr pokerGame); + PokerPlayer( + const std::weak_ptr pokerGame, + const uint8_t playerIndex + ); /** * Adds chips to the player. This will also update the players' state. diff --git a/src/dawnpoker/poker/PokerPot.cpp b/src/dawn/poker/PokerPot.cpp similarity index 100% rename from src/dawnpoker/poker/PokerPot.cpp rename to src/dawn/poker/PokerPot.cpp diff --git a/src/dawnpoker/poker/PokerPot.hpp b/src/dawn/poker/PokerPot.hpp similarity index 100% rename from src/dawnpoker/poker/PokerPot.hpp rename to src/dawn/poker/PokerPot.hpp diff --git a/src/dawnpoker/poker/PokerTurn.cpp b/src/dawn/poker/PokerTurn.cpp similarity index 100% rename from src/dawnpoker/poker/PokerTurn.cpp rename to src/dawn/poker/PokerTurn.cpp diff --git a/src/dawnpoker/poker/PokerTurn.hpp b/src/dawn/poker/PokerTurn.hpp similarity index 91% rename from src/dawnpoker/poker/PokerTurn.hpp rename to src/dawn/poker/PokerTurn.hpp index 179c7a8c..d1a414c7 100644 --- a/src/dawnpoker/poker/PokerTurn.hpp +++ b/src/dawn/poker/PokerTurn.hpp @@ -9,13 +9,13 @@ namespace Dawn { class PokerPlayer; - enum class PokerTurnType { - Out, - Fold, - Bet, - Call, - Check, - AllIn + enum class PokerTurnType : uint8_t { + Out = 0, + Fold = 1, + Bet = 2, + Call = 3, + Check = 4, + AllIn = 5 }; struct PokerTurn { diff --git a/src/dawnpoker/poker/PokerWinning.cpp b/src/dawn/poker/PokerWinning.cpp similarity index 100% rename from src/dawnpoker/poker/PokerWinning.cpp rename to src/dawn/poker/PokerWinning.cpp diff --git a/src/dawnpoker/poker/PokerWinning.hpp b/src/dawn/poker/PokerWinning.hpp similarity index 100% rename from src/dawnpoker/poker/PokerWinning.hpp rename to src/dawn/poker/PokerWinning.hpp diff --git a/src/dawn/ui/elements/UILabel.hpp b/src/dawn/ui/elements/UILabel.hpp new file mode 100644 index 00000000..0b28d959 --- /dev/null +++ b/src/dawn/ui/elements/UILabel.hpp @@ -0,0 +1,17 @@ +// Copyright (c) 2024 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "ui/UIAlignableElement.hpp" + +namespace Dawn { + class UILabel final : public UIAlignableElement { + protected: + void getSelfQuads(UICanvas &ctx) override; + + public: + std::shared_ptr font; + }; +} \ No newline at end of file diff --git a/src/dawnpoker/scenes/TestScene.cpp b/src/dawnpoker/scenes/TestScene.cpp index 79875b88..3e38799d 100644 --- a/src/dawnpoker/scenes/TestScene.cpp +++ b/src/dawnpoker/scenes/TestScene.cpp @@ -10,6 +10,15 @@ #include "component/display/material/SimpleTexturedMaterial.hpp" #include "display/mesh/CubeMesh.hpp" +#include "component/ui/UICanvas.hpp" +#include "ui/elements/UIRectangle.hpp" +// #include "ui/elements/UILabel.hpp" +#include "ui/UIMenu.hpp" +#include "ui/container/UIRowContainer.hpp" +#include "ui/container/UIPaddingContainer.hpp" + +#include "poker/PokerGame.hpp" + using namespace Dawn; void Dawn::testScene(Scene &s) { @@ -26,4 +35,58 @@ void Dawn::testScene(Scene &s) { cubeRenderer->mesh = cubeMesh; cubeMesh->createBuffers(CUBE_VERTICE_COUNT, CUBE_INDICE_COUNT); CubeMesh::buffer(cubeMesh, glm::vec3(0,0,0), glm::vec3(1, 1, 1), 0, 0); + + auto canvasItem = s.createSceneItem(); + auto canvas = canvasItem->addComponent(); + + auto container = std::make_shared(); + container->align = { 32, 32, UI_ALIGN_SIZE_AUTO, UI_ALIGN_SIZE_AUTO }; + container->alignX = UIAlignmentType::START; + container->alignY = UIAlignmentType::START; + canvas->addElement(container); + + auto rect = std::make_shared(); + rect->align = { 0, 0, 32, 32 }; + rect->alignX = UIAlignmentType::START; + rect->alignY = UIAlignmentType::START; + rect->color = COLOR_MAGENTA; + container->appendChild(rect); + + // auto game = std::make_shared(); + // auto player0 = game->addNewPlayer(); + // auto player1 = game->addNewPlayer(); + // auto player2 = game->addNewPlayer(); + // auto player3 = game->addNewPlayer(); + // game->newGame(); + // game->takeBlinds(); + // game->dealToEveryone(2); + + // std::shared_ptr player; + // while((player = game->getCurrentBetter()) != nullptr) { + // auto turn = player->getAITurn(); + // std::cout << "Player " << (int)player->playerIndex << " is taking turn: " << (int)turn.type << std::endl; + // turn.action(); + // } + + // std::cout << "Reveal flop" << std::endl; + // game->burnCard(); + // game->turn(); + + // game->newBettingRound(); + // while((player = game->getCurrentBetter()) != nullptr) { + // auto turn = player->getAITurn(); + // std::cout << "Player " << (int)player->playerIndex << " is taking turn: " << (int)turn.type << std::endl; + // turn.action(); + // } + + // std::cout << "Reveal turn" << std::endl; + // game->burnCard(); + // game->turn(); + + // game->newBettingRound(); + // while((player = game->getCurrentBetter()) != nullptr) { + // auto turn = player->getAITurn(); + // std::cout << "Player " << (int)player->playerIndex << " is taking turn: " << (int)turn.type << std::endl; + // turn.action(); + // } } \ No newline at end of file