From f788fffac72e65fbff2c804d0aa0ef58f9d120e3 Mon Sep 17 00:00:00 2001 From: Bobby Lucero Date: Fri, 10 May 2024 15:17:47 -0400 Subject: [PATCH] Added font drawing support, and one font --- CMakeLists.txt | 11 +++- python/main.py | 5 +- python/particles.py | 1 + python/triangles.py | 5 +- resources/fonts/main.font | 113 ++++++++++++++++++++++++++++++++++++++ src/Graphics/Font.cpp | 67 ++++++++++++++++++++++ src/Graphics/Font.h | 25 +++++++++ src/Graphics/Graphics.cpp | 35 +++++++++--- src/Graphics/Graphics.h | 11 +++- src/StateManager.cpp | 10 ++-- 10 files changed, 263 insertions(+), 20 deletions(-) create mode 100644 resources/fonts/main.font create mode 100644 src/Graphics/Font.cpp create mode 100644 src/Graphics/Font.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b3291ca..4dbc43a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(FETCHCONTENT_QUIET FALSE) set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples set(BUILD_GAMES OFF CACHE BOOL "" FORCE) # don't build the supplied example games +#raylib FetchContent_Declare( raylib GIT_REPOSITORY "https://github.com/raysan5/raylib.git" @@ -18,6 +19,10 @@ FetchContent_Declare( FetchContent_MakeAvailable(raylib) +#json +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_MakeAvailable(json) + # Adding our source files file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_LIST_DIR}/sources/*.c") # Define PROJECT_SOURCES as a list of all source files set(PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/sources/") # Define PROJECT_INCLUDE to be the path to the include directory of the project @@ -34,13 +39,15 @@ add_executable(Pycron src/main.cpp src/StateManager.h src/State.h src/States/GameState.cpp - src/States/GameState.h) + src/States/GameState.h + src/Graphics/Font.cpp + src/Graphics/Font.h) add_subdirectory(dependencies/pocketpy) # Declaring our executable target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE}) -target_link_libraries(${PROJECT_NAME} PRIVATE raylib pocketpy) +target_link_libraries(${PROJECT_NAME} PRIVATE raylib nlohmann_json::nlohmann_json pocketpy) # Setting ASSETS_PATH diff --git a/python/main.py b/python/main.py index 60b0001..a162207 100644 --- a/python/main.py +++ b/python/main.py @@ -6,6 +6,7 @@ class Palette(Scene): def __init__(self): super().__init__() + self.title = "Palette" def update(self): pass @@ -43,8 +44,8 @@ def update(): if(not scenes[current_scene].paused): scenes[current_scene].update() scenes[current_scene].draw() - - text(scenes[current_scene].title, 2, 15, 63) + text("if(x != 22.252f && y % 2 == 0) { break; }", 2, 40, 32) + #text("Test" + scenes[current_scene].title, 2, 15, 32) diff --git a/python/particles.py b/python/particles.py index c4b708c..70b9e70 100644 --- a/python/particles.py +++ b/python/particles.py @@ -50,6 +50,7 @@ class Particles(Scene): self.waterParts.append(Particle(width/2, height/2, rnd(-1, 1), rnd(-1, 1))) self.counter = 0 + self.title = "Particles" def update(self): diff --git a/python/triangles.py b/python/triangles.py index ade8996..1e6fd1f 100644 --- a/python/triangles.py +++ b/python/triangles.py @@ -7,7 +7,7 @@ def draw_line(x0, y0, x1, y1, c): y0 = int(y0) x1 = int(x1) y1 = int(y1) - "Bresenham's line algorithm" + dx = abs(x1 - x0) dy = abs(y1 - y0) x, y = x0, y0 @@ -61,6 +61,7 @@ class Triangles(Scene): self.count = 0 self.tpo3 = (2 * 3.141592654)/3 self.skip = False + self.title = "Flying Triangles" @@ -76,7 +77,7 @@ class Triangles(Scene): y = rnd(0, height) c = 0 if(rnd(0,9) < 5): - c = get_pixel(x,y-3) + c = get_pixel(x -3 ,y-3) else: c = 0 diff --git a/resources/fonts/main.font b/resources/fonts/main.font new file mode 100644 index 0000000..6e1f757 --- /dev/null +++ b/resources/fonts/main.font @@ -0,0 +1,113 @@ +{ + "asciiTable": { + "1234567": "11111100010101000100010101000111111", + "32": "00000000000000000000000000000000000", + + "33": "00100001000010000100001000000000100", + "34": "01010010100000000000000000000000000", + "35": "01010111110101001010111110101000000", + "36": "00100011111010001110001011111000100", + "37": "11001110010001000100010001001110011", + "38": "00100010100101001100100101001001101", + "39": "00100001000000000000000000000000000", + "40": "00100010000100001000010000100000100", + "41": "00100000100001000010000100001000100", + "42": "01010001000101000000000000000000000", + "43": "00000001000010011111001000010000000", + "44": "00000000000000000000000000010001000", + "45": "00000000000000011111000000000000000", + "46": "00000000000000000000000000000000100", + "47": "00010000100010000100001000100001000", + + "48": "01110100011000110001100011000101110", + "49": "00100011000010000100001000010011111", + "50": "01110100010000100010001000100011111", + "51": "01110100010000100110000011000101110", + "52": "00010001100101010010111110001000010", + "53": "11111100001111000001000010000111110", + "54": "01110100001111010001100011000101110", + "55": "11111000010000100010000100010000100", + "56": "01110100011000101110100011000101110", + "57": "01110100011000110001011110000101110", + + "58": "00000000000010000000000000010000000", + "59": "00000000000010000000000000010001000", + "60": "00000001000100010000010000010000000", + "61": "00000000001111100000111110000000000", + "62": "00000001000001000001000100010000000", + "63": "01110100010000100010001000000000100", + "64": "01111100011011110101101111000001111", + + + "65": "01110100011000110001111111000110001", + "66": "11110100011111010001100011000111110", + "67": "00111010001000010000100001000001111", + "68": "11100100101000110001100011000111110", + "69": "01111100001111010000100001000001111", + "70": "01111100001111010000100001000010000", + "71": "01110100011000010111100011000101110", + "72": "10001100011111110001100011000110001", + "73": "11111001000010000100001000010011111", + "74": "11111000010000100001000010001011100", + "75": "10001100011001011100100101000110001", + "76": "10000100001000010000100001000001111", + "77": "01010101011010110101101011010110001", + "78": "11100100101000110001100011000110001", + "79": "01110100011000110001100011000101110", + "80": "11110100011000110001111101000010000", + "81": "01110100011000110001101011001001101", + "82": "11110100011000110001111101000110001", + "83": "01111100001000001110000010000111110", + "84": "11111001000010000100001000010000100", + "85": "10001100011000110001100011000101110", + "86": "10001100011000110001100010101000100", + "87": "10001100011010110101101011010101010", + "88": "10001100010101000100010101000110001", + "89": "10001100011000101010001000010000100", + "90": "11111000010001000100010001000011111", + + "91": "01100010000100001000010000100001100", + "92": "01000010000010000100001000001000010", + "93": "00110000100001000010000100001000110", + "94": "00100010101000100000000000000000000", + "95": "00000000000000000000000000000011111", + "96": "01000001000000000000000000000000000", + + "97": "00000000000111000001011111000101111", + "98": "10000100001111010001100011000111110", + "99": "00000000000111010000100001000001110", + "100": "00001000010111110001100011000101111", + "101": "00000000000111010001111111000001110", + "102": "00000001110100011111010000100001000", + "103": "00000000000111010001011110000101110", + "104": "00000100001000011110100011000110001", + "105": "00000001000000001100001000010000100", + "106": "00000001000000001100001000010011000", + "107": "00000100001001010100110001010010010", + "108": "00000001000010000100001000010000010", + "109": "00000000001111010101101011010110101", + "110": "00000000001011011001100011000110001", + "111": "00000000000111010001100011000101110", + "112": "00000000001111010001100011111010000", + "113": "00000000000111110001100010111100001", + "114": "00000000001011011000100001000010000", + "115": "00000000000111110000011100000111110", + "116": "01000010001111001000010000100000110", + "117": "00000000001000110001100011001101101", + "118": "00000000001000110001100010101000100", + "119": "00000000001000110101101011010101010", + "120": "00000000001000101010001000101010001", + "121": "00000100011000110001011110000101110", + "122": "00000000001111100010001000100011111", + + + + "123": "01100010000100011000010000100001100", + "124": "00100001000010000100001000010000100", + "125": "00110000100001000011000100001000110", + "126": "00000000000100010101000100000000000" + + }, + "height": 7, + "width": 5 +} \ No newline at end of file diff --git a/src/Graphics/Font.cpp b/src/Graphics/Font.cpp new file mode 100644 index 0000000..c223393 --- /dev/null +++ b/src/Graphics/Font.cpp @@ -0,0 +1,67 @@ +// +// Created by Bobby on 5/10/2024. +// + +#include "Font.h" +#include +#include +#include +#include + +using json = nlohmann::json; + +PixelFont::PixelFont(int width, int height, std::string path) : m_width(width), m_height(height), m_filePath(std::move(path)){ + std::cout << Dump() << std::endl; + ReadFontFile(); +} + + +int PixelFont::GetWidth() { + return this->m_width; +} + +int PixelFont::GetHeight() { + return this->m_height; +} + +std::string PixelFont::Dump() { + json j; + j["width"] = this->m_width; + j["height"] = this->m_height; + for(const auto& pair : this->m_asciiTable){ + j["asciiTable"][std::to_string(pair.first)] = pair.second; + } + return j.dump(4); +} + + +void PixelFont::ReadFontFile() { + std::ifstream json_file(m_filePath); + if(!json_file.is_open()){ + std::cerr << "Could not open font file: " << m_filePath << std::endl; + return; + } + + std::stringstream buffer; + buffer << json_file.rdbuf(); + json data = json::parse(buffer.str()); + + this->m_width = data["width"].template get(); + this->m_height = data["height"].template get(); + json asciiJson = data["asciiTable"]; + + for(auto it = asciiJson.begin(); it != asciiJson.end(); ++it){ + int key = std::stoi(it.key()); + m_asciiTable[key] = it.value(); + } +} + + +std::string PixelFont::GetCharData(int asciiValue) { + if(!m_asciiTable.count(asciiValue)){ + return m_asciiTable[MISSING_CHAR]; + } + + return m_asciiTable[asciiValue]; +} + diff --git a/src/Graphics/Font.h b/src/Graphics/Font.h new file mode 100644 index 0000000..77f5ce8 --- /dev/null +++ b/src/Graphics/Font.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +class PixelFont { +private: + int m_width; + int m_height; + std::string m_filePath; + std::unordered_map m_asciiTable; + + const int MISSING_CHAR = 1234567; + +public: + PixelFont(int width, int height, std::string path); + +public: + int GetWidth(); + int GetHeight(); + std::string GetCharData(int asciiValue); + std::string Dump(); + void ReadFontFile(); +}; diff --git a/src/Graphics/Graphics.cpp b/src/Graphics/Graphics.cpp index 838ea3b..fb53514 100644 --- a/src/Graphics/Graphics.cpp +++ b/src/Graphics/Graphics.cpp @@ -2,13 +2,18 @@ // Created by Bobby Lucero on 4/20/24. // -#include #include "Graphics.h" #include "../Utilities.h" #include +#include + Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : m_screenWidth(screenWidth), m_screenHeight(screenHeight){ + + m_NormalFont = new PixelFont(5, 7, "resources/fonts/main.font"); + m_currentFont = m_NormalFont; + m_startupScreenWidth = screenWidth * startupScale; m_startupScreenHeight = screenHeight * startupScale; m_windowWidth = m_startupScreenWidth; @@ -25,16 +30,19 @@ Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : m_scre m_virtualScreenImageBuffer = GenImageColor(m_screenWidth, m_screenHeight, BLACK); m_virtualScreenColorBuffer = {}; - - for (int i = 0; i < screenWidth * screenHeight; ++i) { - m_virtualScreenColorBuffer.push_back(GetRandomValue(0, 5)); - } + m_virtualScreenColorBuffer.resize(screenWidth * screenHeight); calculateScreenPositionInWindow(); + +} + +Graphics::~Graphics() { + delete m_NormalFont; + m_NormalFont = nullptr; + m_currentFont = nullptr; } void Graphics::draw(StateManager* stateManager) { - m_windowShouldClose = WindowShouldClose(); if (IsWindowResized()) { @@ -320,8 +328,19 @@ void Graphics::RectBorder(int x, int y, int width, int height, int paletteIndex) v_line(x + width - 1, y + 1, y + height - 2, paletteIndex); } -void Graphics::Text(std::string s, int x, int y, int paletteIndex) { +void Graphics::Text(const std::string& s, int x, int y, int paletteIndex) { + for (int i = 0; i < s.size(); ++i) { + char c = s[i]; + std::string bitData = m_currentFont->GetCharData((int)c); + + //std::cout << c << ": " << (int)c << " = " << bitData << std::endl; + for (int j = 0; j < bitData.size(); ++j) { + if(bitData[j] == '1') + Pixel(x + (j % m_currentFont->GetWidth()) + ((m_currentFont->GetWidth() + 1) * i), y + (j / m_currentFont->GetWidth()), paletteIndex); + + } + } } void Graphics::updateVMVars(pkpy::VM* vm) { @@ -512,3 +531,5 @@ void Graphics::swap(float &a, float &b) { + + diff --git a/src/Graphics/Graphics.h b/src/Graphics/Graphics.h index 6fe1ab4..8b18e5d 100644 --- a/src/Graphics/Graphics.h +++ b/src/Graphics/Graphics.h @@ -2,11 +2,14 @@ #include "raylib.h" #include "pocketpy/vm.h" #include "../StateManager.h" +#include "Font.h" + #include #include #include #include + class StateManager; class Graphics { @@ -25,6 +28,8 @@ private: RenderTexture2D m_virtualScreen; std::vector m_virtualScreenColorBuffer; Image m_virtualScreenImageBuffer; + PixelFont* m_currentFont; + PixelFont* m_NormalFont; static void swap(float &a, float &b); @@ -35,8 +40,7 @@ private: void h_line(int x1, int y, int x2, int paletteIndex); void v_line(int x, int y1, int y2, int paletteIndex); - void fillBottomFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex); - void fillTopFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex); + public: // virtual screen int m_screenWidth = 0; @@ -52,6 +56,7 @@ public: public: Graphics(int screenWidth, int screenHeight, int startupScale); + ~Graphics(); void draw(StateManager* stateManager); @@ -73,7 +78,7 @@ public: void EllipseBorder(int x, int y, int width, int height, int paletteIndex); void Rect(int x, int y, int width, int height, int paletteIndex); void RectBorder(int x, int y, int width, int height, int paletteIndex); - void Text(std::string s, int x, int y, int paletteIndex); + void Text(const std::string& s, int x, int y, int paletteIndex); void Triangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, int paletteIndex); int GetPixel(int x, int y); diff --git a/src/StateManager.cpp b/src/StateManager.cpp index 7432437..daaef33 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.cpp @@ -10,6 +10,12 @@ StateManager::StateManager(Pycron *pycron) : m_pycron(pycron){ RequestStateChange(GAME); } +StateManager::~StateManager() { + m_currentState = nullptr; + delete m_gameState; +} + + void StateManager::RequestStateChange(StateManager::StateType state) { if(m_currentState){ m_currentState->OnExit(); @@ -47,7 +53,3 @@ void StateManager::Draw(Graphics *graphics) { } } -StateManager::~StateManager() { - m_currentState = nullptr; - delete m_gameState; -}