diff --git a/src/Graphics/Graphics.cpp b/src/Graphics/Graphics.cpp index 8b0cc8c..ee85ec9 100644 --- a/src/Graphics/Graphics.cpp +++ b/src/Graphics/Graphics.cpp @@ -5,6 +5,7 @@ #include #include "Graphics.h" #include "../Utilities.h" +#include Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : m_screenWidth(screenWidth), m_screenHeight(screenHeight){ @@ -16,10 +17,19 @@ Graphics::Graphics(int screenWidth, int screenHeight, int startupScale) : m_scre SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(m_startupScreenWidth, m_startupScreenHeight, "test"); SetTargetFPS(60); + m_virtualScreen = LoadRenderTexture(screenWidth, screenHeight); m_origin = {0,0}; - m_virtualScreenLocalBounds = {0.0f, 0.0f, (float)m_virtualScreen.texture.width, -(float)m_virtualScreen.texture.height }; + m_virtualScreenLocalBounds = {0.0f, 0.0f, (float)m_virtualScreen.texture.width, (float)m_virtualScreen.texture.height }; m_virtualScreenWindowBounds = {0.0f, 0.0f, (float)m_windowWidth, (float)m_windowHeight}; + + 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)); + } + calculateScreenPositionInWindow(); } @@ -33,18 +43,26 @@ void Graphics::draw(StateManager* stateManager) { calculateScreenPositionInWindow(); } - BeginTextureMode(m_virtualScreen); stateManager->Draw(this); - - EndTextureMode(); - + copyBufferToGPU(); renderVirtualScreen(); } +void Graphics::copyBufferToGPU() { + Color* pixel_data = LoadImageColors(m_virtualScreenImageBuffer); + for (int i = 0; i < m_screenWidth * m_screenHeight; ++i) { + pixel_data[i] = GetColor(m_paletteByID[m_virtualScreenColorBuffer[i]]); + } + UpdateTexture(m_virtualScreen.texture, pixel_data); + UnloadImageColors(pixel_data); +} + void Graphics::renderVirtualScreen() { BeginDrawing(); ClearBackground(BLACK); DrawTexturePro(m_virtualScreen.texture, m_virtualScreenLocalBounds, m_virtualScreenWindowBounds, m_origin, 0.0f, WHITE); + DrawText(std::to_string(GetFPS()).c_str(), 10, 10, 30, YELLOW); + EndDrawing(); } @@ -164,32 +182,131 @@ void Graphics::bindMethods(pkpy::VM *vm) { } void Graphics::Clear(int paletteIndex) { - if(paletteIndex < 0 || paletteIndex >= m_paletteByID.size()) paletteIndex = 0; - ClearBackground(GetColor(m_paletteByID[paletteIndex])); + for (int y = 0; y < m_screenHeight; ++y) { + for (int x = 0; x < m_screenWidth; ++x) { + Pixel(x, y, paletteIndex); + } + } } void Graphics::Pixel(int x, int y, int paletteIndex) { - DrawPixel(x, y, GetColor(m_paletteByID[paletteIndex])); + paletteIndex = Clamp(paletteIndex, 0, m_paletteByID.size() - 1); + if(x < 0 || y < 0 || x >= m_screenWidth || y >= m_screenHeight) return; + + m_virtualScreenColorBuffer[y * m_screenWidth + x] = paletteIndex; } void Graphics::Circle(int x, int y, int radius, int paletteIndex) { - DrawCircle(x, y, radius, GetColor(m_paletteByID[paletteIndex])); + Ellipse(x, y, radius, radius, paletteIndex); } +void Graphics::Ellipse(int x, int y, int w, int h, int paletteIndex){ + + int x0 = x - w; + int y0 = y - h; + int x1 = x + w; + int y1 = y + h; + + if(x0 > x1 || y0 > y1) + return; + + int a = abs(x1 - x0), b = abs(y1 - y0), b1 = b & 1; + int dx = 4 * (1 - a) * b * b, dy = 4 * (b1 + 1) * a * a; + int err = dx + dy + b1 * a * a, e2; + + if (x0 > x1) { x0 = x1; x1 += a; } + if (y0 > y1) y0 = y1; + y0 += (b + 1) / 2; y1 = y0 - b1; + a *= 8 * a; b1 = 8 * b * b; + + int prevY = y0; + do + { + Pixel( x1, y0, paletteIndex); + Pixel( x0, y0, paletteIndex); + Pixel( x0, y1, paletteIndex); + Pixel( x1, y1, paletteIndex); + if(y0 != prevY && (y0 - y) != h){ + h_line(x1, y0, x - (x1 - x) + 1, paletteIndex); + h_line(x1, y - (y0 - y), x - (x1 - x) + 1, paletteIndex); + } + prevY = y0; + e2 = 2 * err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2 * err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + while (y0-y1 < b) + { /* too early stop of flat ellipses a=1 */ + Pixel( x0 - 1, y0, paletteIndex); /* -> finish tip of ellipse */ + Pixel( x1 + 1, y0++, paletteIndex); + Pixel( x0 - 1, y1, paletteIndex); + Pixel( x1 + 1, y1--, paletteIndex); + } + + + h_line(x - w, y, x + w, paletteIndex); +} + +void Graphics::EllipseBorder(int x, int y, int w, int h, int paletteIndex){ + + int x0 = x - w; + int y0 = y - h; + int x1 = x + w; + int y1 = y + h; + + if(x0 > x1 || y0 > y1) + return; + + int a = abs(x1 - x0), b = abs(y1 - y0), b1 = b & 1; + int dx = 4 * (1 - a) * b * b, dy = 4 * (b1 + 1) * a * a; + int err = dx + dy + b1 * a * a, e2; + + if (x0 > x1) { x0 = x1; x1 += a; } + if (y0 > y1) y0 = y1; + y0 += (b + 1) / 2; y1 = y0 - b1; + a *= 8 * a; b1 = 8 * b * b; + + do + { + Pixel( x1, y0, paletteIndex); + Pixel( x0, y0, paletteIndex); + Pixel( x0, y1, paletteIndex); + Pixel( x1, y1, paletteIndex); + + e2 = 2 * err; + if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */ + if (e2 >= dx || 2 * err > dy) { x0++; x1--; err += dx += b1; } /* x step */ + } while (x0 <= x1); + + while (y0-y1 < b) + { /* too early stop of flat ellipses a=1 */ + Pixel( x0 - 1, y0, paletteIndex); /* -> finish tip of ellipse */ + Pixel( x1 + 1, y0++, paletteIndex); + Pixel( x0 - 1, y1, paletteIndex); + Pixel( x1 + 1, y1--, paletteIndex); + } + +} + + + + void Graphics::Rect(int x, int y, int width, int height, int paletteIndex) { - DrawRectangle(x, y, width, height, GetColor(m_paletteByID[paletteIndex])); + for (int i = 0; i < height; ++i) { + h_line(x, y + i, x + width - 1, paletteIndex); + } +} + +void Graphics::RectBorder(int x, int y, int width, int height, int paletteIndex) { + h_line(x, y, x + width - 1, paletteIndex); + h_line(x, y + height - 1, x + width - 1, paletteIndex); + v_line(x, y + 1, y + height - 2, paletteIndex); + v_line(x + width - 1, y + 1, y + height - 2, paletteIndex); } void Graphics::Text(std::string s, int x, int y, int paletteIndex) { - DrawText(s.c_str(), x, y, 5, GetColor(m_paletteByID[paletteIndex])); -} -void Graphics::beginDraw() { - BeginTextureMode(m_virtualScreen); -} - -void Graphics::endDraw() { - EndTextureMode(); } void Graphics::updateVMVars(pkpy::VM* vm) { @@ -199,6 +316,35 @@ void Graphics::updateVMVars(pkpy::VM* vm) { vm->builtins->attr().set("height", pkpy::py_var(vm, m_screenHeight)); } +void Graphics::h_line(int x1, int y, int x2, int paletteIndex) { + if(y < 0 || y >= m_screenHeight) return; + int startX = x1; + int endX = x2; + if(x1 > x2){ + startX = x2; + endX = x1; + } + for (int i = startX; i <= endX; ++i) { + Pixel(i, y, paletteIndex); + } +} + +void Graphics::v_line(int x, int y1, int y2, int paletteIndex) { + if(x < 0 || x >= m_screenWidth) return; + int startY = y1; + int endY = y2; + if(y1 > y2){ + startY = y2; + endY = y1; + } + for (int i = startY; i <= endY; ++i) { + Pixel(x, i, paletteIndex); + } +} + + + + diff --git a/src/Graphics/Graphics.h b/src/Graphics/Graphics.h index ff2b01a..146f260 100644 --- a/src/Graphics/Graphics.h +++ b/src/Graphics/Graphics.h @@ -5,6 +5,7 @@ #include #include #include +#include class StateManager; @@ -21,13 +22,18 @@ private: Rectangle m_virtualScreenWindowBounds; // size of rect texture on window Vector2 m_origin; // position of rect texture on window Rectangle m_virtualScreenLocalBounds; // virtual screen bounds - RenderTexture2D m_virtualScreen; // actual pixel screen + RenderTexture2D m_virtualScreen; + std::vector m_virtualScreenColorBuffer; + Image m_virtualScreenImageBuffer; private: void renderVirtualScreen(); void calculateScreenPositionInWindow(); + void h_line(int x1, int y, int x2, int paletteIndex); + void v_line(int x, int y1, int y2, int paletteIndex); + public: // virtual screen int m_screenWidth = 0; @@ -46,8 +52,7 @@ public: void draw(StateManager* stateManager); - void beginDraw(); - void endDraw(); + void copyBufferToGPU(); void updateVMVars(pkpy::VM* vm); @@ -61,7 +66,10 @@ public: void Clear(int paletteIndex); void Pixel(int x, int y, int paletteIndex); void Circle(int x, int y, int radius, int paletteIndex); + void Ellipse(int x, int y, int width, int height, int paletteIndex); + 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); diff --git a/src/StateManager.cpp b/src/StateManager.cpp index 2a199b2..7432437 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.cpp @@ -20,14 +20,11 @@ void StateManager::RequestStateChange(StateManager::StateType state) { } if(m_currentState){ - // Game state needs ability to draw during code loading if(m_currentState == m_gameState){ - m_pycron->m_graphics->beginDraw(); m_currentState->OnEnter(); if(m_gameState->m_errorThrown){ m_pycron->m_graphics->Text(m_gameState->m_previousError, 2, 2, 59); } - m_pycron->m_graphics->endDraw(); }else{ m_currentState->OnEnter(); }