فهرست منبع

refactoring, tps and fps clock

Kajetan Johannes Hammerle 5 سال پیش
والد
کامیت
2f3f409bf0
13فایلهای تغییر یافته به همراه455 افزوده شده و 108 حذف شده
  1. 0 1
      MainServer.cpp
  2. 2 2
      Makefile
  3. 39 26
      client/Client.cpp
  4. 2 0
      client/Client.h
  5. 34 0
      engine/Clock.cpp
  6. 24 0
      engine/Clock.h
  7. 195 44
      engine/DirectRenderer.cpp
  8. 51 0
      engine/DirectRenderer.h
  9. 29 0
      engine/GameEngine.cpp
  10. 10 32
      engine/GameEngine.h
  11. 7 2
      engine/Texture.cpp
  12. 2 1
      engine/Texture.h
  13. 60 0
      engine/Utils.h

+ 0 - 1
MainServer.cpp

@@ -1,5 +1,4 @@
 #include <iostream>
-#include "Texture.h"
 
 using namespace std;
 

+ 2 - 2
Makefile

@@ -22,8 +22,8 @@ client: client/*.cpp client/*.h
 run_server: game_server
 	./game_server
 	
-game_server: MainServer.cpp Image.cpp Image.h
-	g++ $(VERSION) -o $@ MainServer.cpp Image.cpp -lpng
+game_server: MainServer.cpp
+	g++ $(VERSION) -o $@ MainServer.cpp
 	
 clean:
 	rm -f game_server game_client

+ 39 - 26
client/Client.cpp

@@ -157,14 +157,9 @@ void Client::init()
     Key::map(KEY_CAM_DOWN, GLFW_KEY_J);
 }
 
-uint64_t oldTime = -1;
-
-uint64_t count = 0;
-uint64_t sum = 0;
-
 void Client::tick()
 {
-    Camera& c = GameEngine::getCamera();
+    /*Camera& c = GameEngine::getCamera();
     
     c.storePosition();
     c.storeAngles();
@@ -213,38 +208,56 @@ void Client::tick()
     }
     
     c.setPosition(position.getX(), position.getY(), position.getZ());
-    c.setAngles(lengthAngle, widthAngle);
-    //cout << "tick" << endl;
-    
-    cout << (1000000000.0 * count ) / sum << endl;
+    c.setAngles(lengthAngle, widthAngle);*/
 }
 
 void Client::renderTick(float lag)
 {
-    uint64_t t = glfwGetTimerValue();
-    if(oldTime == -1)
-    {
-        oldTime = t;
-    }
-    else
-    {
-        sum += t - oldTime;
-        count++;
-        oldTime = t;
-    }
     
-    GameEngine::getCamera().updateView(lag);
-    texture.bind();
+    
+    //GameEngine::getCamera().updateView(lag);
+    //texture.bind();
+    
+    /*GameEngine::setTextureEnabled(false);
+    GameEngine::setColorEnabled(true);
+    
+    GameEngine::getDirectRenderer().prepare();
+    GameEngine::getDirectRenderer().drawRectangle(0, 0, 200, 300, 0, 0, 1, 1, Color::getColor(255, 0, 0));
+    GameEngine::getDirectRenderer().drawRectangle(200, 0, 400, 300, 0, 0, 1, 1, Color::getColor(0, 255, 0));
+    GameEngine::getDirectRenderer().drawRectangle(400, 0, 600, 300, 0, 0, 1, 1, Color::getColor(0, 0, 255));
+    
     GameEngine::setTextureEnabled(true);
-    //GameEngine::setColorEnabled(true);
+    GameEngine::setColorEnabled(true);
+    
+    string wusi;
+    GameEngine::setUseBlending(true);
+    
+    float y = 30;
+    y = GameEngine::getDirectRenderer().drawString(30, y, true, wusi);
+    
+    wusi = "FPS: " + to_string(GameEngine::getFramesPerSecond());
+    y = GameEngine::getDirectRenderer().drawString(30, y, true, wusi);
+    
+    wusi = "TPS: " + to_string(GameEngine::getTicksPerSecond());
+    y = GameEngine::getDirectRenderer().drawString(30, y, true, wusi);*/
+    
+    GameEngine::setTextureEnabled(true);
+    GameEngine::setColorEnabled(true);
+    GameEngine::setUseBlending(true);
     GameEngine::getDirectRenderer().prepare();
-    GameEngine::getDirectRenderer().drawRectangle(0, 0, 300, 300, 0, 0, 1, 1, 1, 0, 0, 1);
+    string fps = "FPS: " + to_string(GameEngine::getFramesPerSecond());
+    GameEngine::getDirectRenderer().drawString(30, 30, true, fps);
     //tmesh.draw();
     //cout << "renderTick" << endl;
 }
 
 void Client::start()
 {
-    GameEngine::start(640, 480, "Test Game", init, tick, renderTick);
+    GameEngine::start(1024, 620, "Test Game", init, tick, renderTick);
+    
+    for(char c = 'a'; c <= 'z'; c++)
+    {
+        cout << "&" << c << "O";
+    }
 }
 

+ 2 - 0
client/Client.h

@@ -6,6 +6,8 @@
 #include "../math/Vector3D.h"
 #include "../engine/Texture.h"
 
+using namespace std;
+
 class Client
 {
 public:

+ 34 - 0
engine/Clock.cpp

@@ -0,0 +1,34 @@
+#include "Clock.h"
+
+Clock::Clock()
+{
+    for(int i = 0; i < SIZE; i++)
+    {
+        time[i] = 0;
+    }
+}
+
+Clock::Clock(const Clock& orig)
+{
+}
+
+Clock::~Clock()
+{
+}
+
+void Clock::update()
+{
+    uint64_t t = glfwGetTimerValue();
+    time[index] = t - oldTime;
+    oldTime = t;
+    
+    sum += time[index];
+    index = (index + 1) & (SIZE - 1);
+    sum -= time[index];
+}
+
+double Clock::getUpdatesPerSecond()
+{
+    return (1000000000.0 * (SIZE - 1)) / sum;
+}
+

+ 24 - 0
engine/Clock.h

@@ -0,0 +1,24 @@
+#ifndef CLOCK_H
+#define CLOCK_H
+
+#include <GLFW/glfw3.h>
+
+class Clock
+{
+public:
+    Clock();
+    Clock(const Clock& orig);
+    virtual ~Clock();
+    
+    void update();
+    double getUpdatesPerSecond();
+private:
+    static const int SIZE = 256;
+    uint64_t oldTime = 0;
+    uint64_t time[SIZE];
+    uint64_t sum = 0;
+    unsigned int index = 0;
+};
+
+#endif
+

+ 195 - 44
engine/DirectRenderer.cpp

@@ -1,4 +1,8 @@
+#include "DirectRenderer.h"
 #include "GameEngine.h"
+#include <cmath>
+
+Texture DirectRenderer::FONTS[FONTS_LENGTH];
 
 DirectRenderer::DirectRenderer()
 {
@@ -16,6 +20,19 @@ DirectRenderer::~DirectRenderer()
 
 void DirectRenderer::init()
 {
+    if(!FONTS[0].isLoaded())
+    {
+        FONTS[0].load("resources/font8x8.png");
+    }
+    if(!FONTS[1].isLoaded())
+    {
+        FONTS[1].load("resources/font16x16.png");
+    }
+    if(!FONTS[2].isLoaded())
+    {
+        FONTS[2].load("resources/font24x24.png");
+    }
+    
     glGenVertexArrays(1, &vba);
     glGenBuffers(1, &vbo);
 
@@ -23,13 +40,13 @@ void DirectRenderer::init()
     glBindBuffer(GL_ARRAY_BUFFER, vbo);
 
     glEnableVertexAttribArray(0);
-    glVertexAttribPointer(0, 3, GL_FLOAT, false, 36, (GLvoid*) 0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, false, 24, (GLvoid*) 0);
 
     glEnableVertexAttribArray(1);  
-    glVertexAttribPointer(1, 4, GL_FLOAT, false, 36, (GLvoid*) 12);
+    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, 24, (GLvoid*) 12);
     
     glEnableVertexAttribArray(2);  
-    glVertexAttribPointer(2, 2, GL_FLOAT, false, 36, (GLvoid*) 28);
+    glVertexAttribPointer(2, 2, GL_FLOAT, false, 24, (GLvoid*) 16);
 }
 
 void DirectRenderer::prepare()
@@ -48,13 +65,10 @@ void DirectRenderer::prepare()
     glUniformMatrix4fv(GameEngine::unifProjMatrix, 1, 0, proj.getValues());
 }
 
-void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float maxY,
-            float tMinX, float tMinY, float tMaxX, float tMaxY,
-            float r, float g, float b, float a)
+void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY, IntColor c)
 {
     glBindBuffer(GL_ARRAY_BUFFER, vbo);
         
-    offset += OBJECT_LENGTH;
     if(offset + OBJECT_LENGTH >= BUFFER_LENGTH)
     {
         offset = 0;
@@ -69,55 +83,192 @@ void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float max
     buffer[0] = minX;
     buffer[1] = maxY;
     buffer[2] = 0.0f;
-    buffer[3] = r;
-    buffer[4] = g;
-    buffer[5] = b;
-    buffer[6] = a;
-    buffer[7] = tMinX;
-    buffer[8] = tMaxY;
+    buffer[3] = *((float*) (&c));
+    buffer[4] = tMinX;
+    buffer[5] = tMaxY;
+    
+    buffer[6] = maxX;
+    buffer[7] = maxY;
+    buffer[8] = 0.0f;
+    buffer[9] = *((float*) (&c));
+    buffer[10] = tMaxX;
+    buffer[11] = tMaxY;
     
-    buffer[9] = maxX;
-    buffer[10] = maxY;
-    buffer[11] = 0.0f;
-    buffer[12] = r;
-    buffer[13] = g;
-    buffer[14] = b;
-    buffer[15] = a;
-    buffer[16] = tMaxX;
-    buffer[17] = tMaxY;
+    buffer[12] = minX;
+    buffer[13] = minY;
+    buffer[14] = 0.0f;
+    buffer[15] = *((float*) (&c));
+    buffer[16] = tMinX;
+    buffer[17] = tMinY;
     
-    buffer[18] = minX;
+    buffer[18] = maxX;
     buffer[19] = minY;
     buffer[20] = 0.0f;
-    buffer[21] = r;
-    buffer[22] = g;
-    buffer[23] = b;
-    buffer[24] = a;
-    buffer[25] = tMinX;
-    buffer[26] = tMinY;
-    
-    buffer[27] = maxX;
-    buffer[28] = minY;
-    buffer[29] = 0.0f;
-    buffer[30] = r;
-    buffer[31] = g;
-    buffer[32] = b;
-    buffer[33] = a;
-    buffer[34] = tMaxX;
-    buffer[35] = tMinY;
+    buffer[21] = *((float*) (&c));
+    buffer[22] = tMaxX;
+    buffer[23] = tMinY;
 
     glUnmapBuffer(GL_ARRAY_BUFFER);
 
     glBindVertexArray(vba);
     glDrawArrays(GL_TRIANGLE_STRIP, offset / (OBJECT_LENGTH / 4), 4);
+    offset += OBJECT_LENGTH;
 }
 
-void DirectRenderer::drawColoredRectangle(float minX, float minY, float maxX, float maxY, float r, float g, float b, float a)
+void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float maxY, IntColor c)
 {
-    drawRectangle(minX, minY, maxX, maxY, 0.0f, 0.0f, 0.0f, 0.0f, r, g, b, a);
+    drawRectangle(minX, minY, maxX, maxY, 0.0f, 0.0f, 0.0f, 0.0f, c);
 }
 
-void DirectRenderer::drawTexturedRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY)
+void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY)
 {
-    drawRectangle(minX, minY, maxX, maxY, tMinX, tMinY, tMaxX, tMaxY, 0.0f, 0.0f, 0.0f, 0.0f);
-}
+    drawRectangle(minX, minY, maxX, maxY, tMinX, tMinY, tMaxX, tMaxY, 0);
+}
+
+float DirectRenderer::drawString(float x, float y, bool shadow, string& s)
+{
+    int size = s.length() * OBJECT_LENGTH * (shadow + 1);
+    
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+        
+    if(offset + size >= BUFFER_LENGTH)
+    {
+        offset = 0;
+        glBufferData(GL_ARRAY_BUFFER, BUFFER_LENGTH, NULL, GL_STREAM_DRAW);
+    }
+    
+    float* buffer = (float*) glMapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+    if(buffer == NULL)
+    {
+        return y;
+    }
+
+    int index = 0;
+    if(shadow)
+    {
+        addString(x + SHADOW_STEP, y + SHADOW_STEP, index, buffer, Color::DARK_COLORS, s);
+    }
+    y = addString(x, y, index, buffer, Color::COLORS, s);
+
+    glUnmapBuffer(GL_ARRAY_BUFFER);
+
+    glBindVertexArray(vba);
+    FONTS[min(GameEngine::scale - 1, FONTS_LENGTH - 1)].bind();
+    glDrawArrays(GL_TRIANGLE_STRIP, offset / (OBJECT_LENGTH / 4), (index + 1) / 6);
+    offset += size;
+    
+    return y;
+}
+
+float DirectRenderer::addString(float x, float y, int& index, float* data, const IntColor* color, string& s)
+{
+    int l = min((int) s.length(), static_cast<int>(MAX_STRING_LENGTH));
+    
+    //x = roundf(x / GameEngine::scale) * GameEngine::scale;
+    //y = roundf(y / GameEngine::scale) * GameEngine::scale;
+        
+    float oldX = x;
+    float currentColor = *((float*) (&(color[Color::COLOR_AMOUNT - 1])));
+
+    for(int pos = 0; pos < l; pos++)
+    {
+        char c = s[pos];
+        if(c == COLOR_CHAR)
+        {
+            pos++;
+            if(pos < l)
+            {
+                int index = s[pos] - 'a';
+                if(index >= 0 && index < Color::COLOR_AMOUNT)
+                {
+                    currentColor = *((float*) (&(color[index])));
+                }
+            }
+            continue;
+        }
+        else if(c == '\n')
+        {
+            y += FONT_SIZE + LINE_STEP;
+            x = oldX;
+            continue;
+        }
+
+        float tMinX = (c & 0xF) * 0.0625f;
+        float tMinY = (c >> 4) * 0.0625f;
+        float tMaxX = tMinX + 0.0625f;
+        float tMaxY = tMinY + 0.0625f;
+        float maxX = x + FONT_SIZE;
+        float maxY = y + FONT_SIZE;
+        
+        data[index++] = x;
+        data[index++] = maxY;
+        data[index++] = 0.0f;
+        data[index++] = currentColor;
+        data[index++] = tMinX;
+        data[index++] = tMaxY;
+        
+        data[index++] = maxX;
+        data[index++] = maxY;
+        data[index++] = 0.0f;
+        data[index++] = currentColor;
+        data[index++] = tMaxX;
+        data[index++] = tMaxY;
+        
+        data[index++] = x;
+        data[index++] = y;
+        data[index++] = 0.0f;
+        data[index++] = currentColor;
+        data[index++] = tMinX;
+        data[index++] = tMinY;
+        
+        data[index++] = maxX;
+        data[index++] = y;
+        data[index++] = 0.0f;
+        data[index++] = currentColor;
+        data[index++] = tMaxX;
+        data[index++] = tMinY;
+        
+        x += FONT_SIZE;
+    }
+    return y + FONT_SIZE + LINE_STEP;
+}
+
+/*  
+    public Rectangle getSize(String s)
+    {
+        int length = 0;
+        int counter = 0;
+        for(int i = 0; i < s.length(); i++)
+        {
+            switch(s.charAt(i))
+            {
+                case '\n':
+                    counter++;
+                    break;
+                case COLOR_CHAR:
+                    i++;
+                    break;
+                default:
+                    length++;
+            }
+        }
+        return new Rectangle(FONT_SIZE * length, (FONT_SIZE + LINE_STEP) * counter);
+    }
+    
+    public Rectangle getSize(int w, int h)
+    {
+        return new Rectangle(FONT_SIZE * w, (FONT_SIZE + LINE_STEP) * h);
+    }
+    
+    public float getHeight()
+    {
+        return FONT_SIZE + LINE_STEP;
+    }
+    
+    public float getWidth()
+    {
+        return FONT_SIZE;
+    }
+ 
+ 
+ */

+ 51 - 0
engine/DirectRenderer.h

@@ -0,0 +1,51 @@
+#ifndef DIRECTRENDERER_H
+#define DIRECTRENDERER_H
+
+#include "../math/Matrix3D.h"
+#include "Texture.h"
+#include "Utils.h"
+
+using namespace std;
+
+class DirectRenderer
+{
+public:
+    DirectRenderer();
+    DirectRenderer(const DirectRenderer& orig);
+    virtual ~DirectRenderer();
+
+    void prepare();
+    void drawRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY, IntColor c);
+    void drawRectangle(float minX, float minY, float maxX, float maxY, IntColor c);
+    void drawRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY);
+    
+    float drawString(float x, float y, bool shadow, string& s);
+
+    void init();
+private:
+    float addString(float x, float y, int& index, float* data, const IntColor* color, string& s);
+    
+    static const int FONTS_LENGTH = 3;
+    static Texture FONTS[FONTS_LENGTH];
+    
+    static const char COLOR_CHAR = '&';
+
+    static const unsigned int FONT_SIZE = 8;
+    static const unsigned int LINE_STEP = 1;
+    static const unsigned int SHADOW_STEP = 1;
+    static const unsigned int MAX_STRING_LENGTH = 1024;
+    
+    static const int OBJECT_LENGTH = 96;
+    static const int BUFFER_LENGTH = 256 * 1024 * OBJECT_LENGTH;
+
+    GLuint vba = 0;
+    GLuint vbo = 0;
+
+    unsigned int offset = BUFFER_LENGTH - OBJECT_LENGTH;
+
+    Matrix3D view;
+    Matrix3D proj;
+};
+
+#endif
+

+ 29 - 0
engine/GameEngine.cpp

@@ -3,6 +3,9 @@
 #include "Mouse.h"
 #include <cmath>
 
+Clock GameEngine::tps;
+Clock GameEngine::fps;
+
 InitFunction GameEngine::init = nullptr;
 TickFunction GameEngine::tick = nullptr;
 RenderTickFunction GameEngine::renderTick = nullptr;
@@ -380,6 +383,7 @@ void GameEngine::start(int width, int height, const char* name, InitFunction ini
         {
             lag -= NANOS_PER_TICK;
 
+            tps.update();
             onTick();
             ticksPerFrame++;
 
@@ -396,6 +400,7 @@ void GameEngine::start(int width, int height, const char* name, InitFunction ini
         }
 
         updateProjection();
+        fps.update();
         renderTick((float) lag / NANOS_PER_TICK);
 
         glfwSwapBuffers(window);
@@ -443,6 +448,20 @@ void GameEngine::setMixColor(float r, float g, float b, float a)
     glUniform4f(unifMixColorLoc, r, g, b, a);
 }
 
+void GameEngine::setUseBlending(bool use)
+{
+    if(use)
+    {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glBlendEquation(GL_FUNC_ADD);
+    }
+    else
+    {
+        glDisable(GL_BLEND);
+    }
+}
+
 void GameEngine::printError()
 {
     GLenum error = glGetError();
@@ -491,3 +510,13 @@ void GameEngine::updateScale()
     }
 }
 
+double GameEngine::getTicksPerSecond()
+{
+    return tps.getUpdatesPerSecond();
+}
+
+double GameEngine::getFramesPerSecond()
+{
+    return fps.getUpdatesPerSecond();
+}
+

+ 10 - 32
engine/GameEngine.h

@@ -10,6 +10,8 @@
 #include "../math/Matrix3D.h"
 #include "Camera.h"
 #include "Texture.h"
+#include "DirectRenderer.h"
+#include "Clock.h"
 
 using namespace std;
 
@@ -33,9 +35,14 @@ public:
     static void setColorEnabled(bool use);
     static void setMixColorEnabled(bool use);
     static void setMixColor(float r, float g, float b, float a);
+    
+    static void setUseBlending(bool use);
 
     static void printError();
     static void stop();
+    
+    static double getTicksPerSecond();
+    static double getFramesPerSecond();
 
     friend Camera;
     friend Texture;
@@ -61,6 +68,9 @@ private:
 
     static void updateScale();
 
+    static Clock tps;
+    static Clock fps;
+    
     static InitFunction init;
     static TickFunction tick;
     static RenderTickFunction renderTick;
@@ -92,37 +102,5 @@ private:
     static GLint unifMixColorLoc;
 };
 
-class DirectRenderer
-{
-public:
-    DirectRenderer();
-    DirectRenderer(const DirectRenderer& orig);
-    virtual ~DirectRenderer();
-
-    void prepare();
-    void drawRectangle(float minX, float minY, float maxX, float maxY,
-            float tMinX, float tMinY, float tMaxX, float tMaxY,
-            float r, float g, float b, float a);
-    void drawColoredRectangle(float minX, float minY, float maxX, float maxY,
-            float r, float g, float b, float a);
-    void drawTexturedRectangle(float minX, float minY, float maxX, float maxY,
-            float tMinX, float tMinY, float tMaxX, float tMaxY);
-
-    friend GameEngine;
-private:
-    void init();
-
-    static const int OBJECT_LENGTH = 144;
-    static const int BUFFER_LENGTH = 256 * 1024 * OBJECT_LENGTH;
-
-    GLuint vba = 0;
-    GLuint vbo = 0;
-
-    unsigned int offset = BUFFER_LENGTH - OBJECT_LENGTH;
-
-    Matrix3D view;
-    Matrix3D proj;
-};
-
 #endif
 

+ 7 - 2
engine/Texture.cpp

@@ -28,11 +28,11 @@ Texture::~Texture()
 
 bool Texture::load(const char* path)
 {
-    if(isLoaded)
+    if(loaded)
     {
         return false;
     }
-    isLoaded = true;
+    loaded = true;
     FILE* file = fopen(path, "r");
     if(file == NULL)
     {
@@ -165,3 +165,8 @@ void Texture::bind()
     }
 }
 
+bool Texture::isLoaded()
+{
+    return loaded;
+}
+

+ 2 - 1
engine/Texture.h

@@ -14,11 +14,12 @@ public:
     
     bool load(const char* path);
     void bind();
+    bool isLoaded();
 private:
     bool load(const char* path, FILE* file);
     void initGL();
     
-    bool isLoaded = false;
+    bool loaded = false;
     
     unsigned int width = 0;
     unsigned int height = 0;

+ 60 - 0
engine/Utils.h

@@ -3,5 +3,65 @@
 
 float interpolate(float lag, float from, float to);
 
+typedef unsigned int IntColor;
+
+namespace Color
+{
+    constexpr IntColor getColor(unsigned int r, unsigned int g, unsigned int b)
+    {
+        return ((r & 0xFF) << 0) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | 0xFF000000;
+    }
+
+    constexpr IntColor getDarkerColor(unsigned int r, unsigned int g, unsigned int b)
+    {
+        r *= 0.5;
+        g *= 0.5;
+        b *= 0.5;
+        return ((r & 0xFF) << 0) | ((g & 0xFF) << 8) | ((b & 0xFF) << 16) | 0xFF000000;
+    }
+
+    constexpr int COLOR_AMOUNT = 16;
+    
+    constexpr IntColor COLORS[COLOR_AMOUNT]
+    {
+        getColor(0, 0, 0),
+        getColor(0, 0, 170),
+        getColor(0, 170, 0),
+        getColor(0, 170, 170),
+        getColor(170, 0, 0),
+        getColor(170, 0, 170),
+        getColor(255, 170, 0),
+        getColor(170, 170, 170),
+        getColor(85, 85, 85),
+        getColor(85, 85, 255),
+        getColor(85, 255, 85),
+        getColor(85, 255, 255),
+        getColor(255, 85, 85),
+        getColor(255, 85, 255),
+        getColor(255, 255, 85),
+        getColor(255, 255, 255)
+    };
+
+    constexpr IntColor DARK_COLORS[COLOR_AMOUNT]
+    {
+        getDarkerColor(0, 0, 0),
+        getDarkerColor(0, 0, 170),
+        getDarkerColor(0, 170, 0),
+        getDarkerColor(0, 170, 170),
+        getDarkerColor(170, 0, 0),
+        getDarkerColor(170, 0, 170),
+        getDarkerColor(255, 170, 0),
+        getDarkerColor(170, 170, 170),
+        getDarkerColor(85, 85, 85),
+        getDarkerColor(85, 85, 255),
+        getDarkerColor(85, 255, 85),
+        getDarkerColor(85, 255, 255),
+        getDarkerColor(255, 85, 85),
+        getDarkerColor(255, 85, 255),
+        getDarkerColor(255, 255, 85),
+        getDarkerColor(255, 255, 255)
+    };
+}
+
 #endif