|  | @@ -1,11 +1,230 @@
 | 
	
		
			
				|  |  | +#include <cmath>
 | 
	
		
			
				|  |  |  #include <cstdio>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "data/Array.h"
 | 
	
		
			
				|  |  | +#include "data/ArrayList.h"
 | 
	
		
			
				|  |  | +#include "math/Vector.h"
 | 
	
		
			
				|  |  | +#include "rendering/Shader.h"
 | 
	
		
			
				|  |  | +#include "rendering/VertexBuffer.h"
 | 
	
		
			
				|  |  |  #include "rendering/Window.h"
 | 
	
		
			
				|  |  | +#include "utils/Color.h"
 | 
	
		
			
				|  |  | +#include "utils/Logger.h"
 | 
	
		
			
				|  |  | +#include "utils/Random.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static Shader shader;
 | 
	
		
			
				|  |  | +static Buffer buffer;
 | 
	
		
			
				|  |  | +static VertexBuffer vertexBuffer;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +enum class Resource { NOTHING, CLAY, ORE, WHEAT, SHEEP, WOOD };
 | 
	
		
			
				|  |  | +static const Color4 RESOURCE_COLOR[] = {
 | 
	
		
			
				|  |  | +    Color4(160, 120, 0, 255),   Color4(220, 96, 0, 255),
 | 
	
		
			
				|  |  | +    Color4(128, 128, 128, 255), Color4(255, 200, 0, 255),
 | 
	
		
			
				|  |  | +    Color4(40, 200, 40, 255),   Color4(0, 120, 0, 255)};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const Vector2 MIN_BORDER(-0.9f, -0.9f);
 | 
	
		
			
				|  |  | +static const Vector2 MAX_BORDER(0.9f, 0.9f);
 | 
	
		
			
				|  |  | +static const Vector2 AREA = MAX_BORDER - MIN_BORDER;
 | 
	
		
			
				|  |  | +static const float RADIUS =
 | 
	
		
			
				|  |  | +    AREA[0] / (5.0f * 2.0f * cosf(30.0f * static_cast<float>(M_PI) / 180.0f));
 | 
	
		
			
				|  |  | +static const float LINE_LENGTH =
 | 
	
		
			
				|  |  | +    RADIUS * sinf(30.0f * static_cast<float>(M_PI) / 180.0f) * 2.0f;
 | 
	
		
			
				|  |  | +static const float WIDTH = AREA[0] / 5.0f;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void addTriangle(const Vector2 a, const Vector2 b, const Vector2 c,
 | 
	
		
			
				|  |  | +                        const Color4& color) {
 | 
	
		
			
				|  |  | +    buffer.add(a).add(color);
 | 
	
		
			
				|  |  | +    buffer.add(b).add(color);
 | 
	
		
			
				|  |  | +    buffer.add(c).add(color);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void addSquare(const Vector2 mid, float size, const Color4& color) {
 | 
	
		
			
				|  |  | +    size *= 0.5f;
 | 
	
		
			
				|  |  | +    Vector2 a = mid + Vector2(-size, size);
 | 
	
		
			
				|  |  | +    Vector2 b = mid + Vector2(size, size);
 | 
	
		
			
				|  |  | +    Vector2 c = mid + Vector2(-size, -size);
 | 
	
		
			
				|  |  | +    Vector2 d = mid + Vector2(size, -size);
 | 
	
		
			
				|  |  | +    addTriangle(a, b, c, color);
 | 
	
		
			
				|  |  | +    addTriangle(b, d, c, color);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct Hexagon {
 | 
	
		
			
				|  |  | +    Resource resource = Resource::NOTHING;
 | 
	
		
			
				|  |  | +    Vector2 mid;
 | 
	
		
			
				|  |  | +    Array<int, 6> corners;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Hexagon() : corners(-1) {
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    void addToBuffer() const {
 | 
	
		
			
				|  |  | +        Color4 color = RESOURCE_COLOR[static_cast<int>(resource)];
 | 
	
		
			
				|  |  | +        float angle = 2.0f * static_cast<float>(M_PI) / 6.0f;
 | 
	
		
			
				|  |  | +        for(int i = 0; i < 6; i++) {
 | 
	
		
			
				|  |  | +            Vector2 a(sinf(angle * static_cast<float>(i)) * RADIUS,
 | 
	
		
			
				|  |  | +                      cosf(angle * static_cast<float>(i)) * RADIUS);
 | 
	
		
			
				|  |  | +            Vector2 b(sinf(angle * static_cast<float>(i + 1)) * RADIUS,
 | 
	
		
			
				|  |  | +                      cosf(angle * static_cast<float>(i + 1)) * RADIUS);
 | 
	
		
			
				|  |  | +            addTriangle(a + mid, b + mid, mid, color);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getTopCorner() {
 | 
	
		
			
				|  |  | +        return mid + Vector2(0.0f, RADIUS);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getBottomCorner() {
 | 
	
		
			
				|  |  | +        return mid - Vector2(0.0f, RADIUS);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getLeftTopCorner() {
 | 
	
		
			
				|  |  | +        return mid - Vector2(WIDTH, -LINE_LENGTH) * 0.5f;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getLeftBottomCorner() {
 | 
	
		
			
				|  |  | +        return mid - Vector2(WIDTH, LINE_LENGTH) * 0.5f;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getRightTopCorner() {
 | 
	
		
			
				|  |  | +        return mid + Vector2(WIDTH, LINE_LENGTH) * 0.5f;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Vector2 getRightBottomCorner() {
 | 
	
		
			
				|  |  | +        return mid + Vector2(WIDTH, -LINE_LENGTH) * 0.5f;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static Array<Hexagon, 19> hexagons;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct Corner {
 | 
	
		
			
				|  |  | +    int player = 0;
 | 
	
		
			
				|  |  | +    Vector2 mid;
 | 
	
		
			
				|  |  | +    ArrayList<int, 3> hexagons;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    void addToBuffer() const {
 | 
	
		
			
				|  |  | +        addSquare(mid, 0.05f, Color4(255, 255, 255, 255));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static Array<Corner, 54> corners;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void initResources() {
 | 
	
		
			
				|  |  | +    for(int i = 0; i < 4; i++) {
 | 
	
		
			
				|  |  | +        hexagons[i].resource = Resource::WHEAT;
 | 
	
		
			
				|  |  | +        hexagons[i + 4].resource = Resource::WOOD;
 | 
	
		
			
				|  |  | +        hexagons[i + 8].resource = Resource::SHEEP;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for(int i = 0; i < 3; i++) {
 | 
	
		
			
				|  |  | +        hexagons[i + 12].resource = Resource::ORE;
 | 
	
		
			
				|  |  | +        hexagons[i + 15].resource = Resource::CLAY;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    hexagons[18].resource = Resource::NOTHING;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Random r(0);
 | 
	
		
			
				|  |  | +    for(int i = 0; i < hexagons.getLength(); i++) {
 | 
	
		
			
				|  |  | +        std::swap(hexagons[i], hexagons[r.next(i, hexagons.getLength() - 1)]);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void initHexagonMid() {
 | 
	
		
			
				|  |  | +    Vector2 mid = MIN_BORDER + AREA * 0.5f;
 | 
	
		
			
				|  |  | +    for(int i = 0; i < 3; i++) {
 | 
	
		
			
				|  |  | +        hexagons[i].mid = mid - Vector2(WIDTH * static_cast<float>(i - 1),
 | 
	
		
			
				|  |  | +                                        -RADIUS * 2.0f - LINE_LENGTH);
 | 
	
		
			
				|  |  | +        hexagons[i + 16].mid = mid - Vector2(WIDTH * static_cast<float>(i - 1),
 | 
	
		
			
				|  |  | +                                             RADIUS * 2.0f + LINE_LENGTH);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for(int i = 3; i < 7; i++) {
 | 
	
		
			
				|  |  | +        hexagons[i].mid = mid - Vector2(WIDTH * (static_cast<float>(i) - 4.5f),
 | 
	
		
			
				|  |  | +                                        -RADIUS - LINE_LENGTH * 0.5f);
 | 
	
		
			
				|  |  | +        hexagons[i + 9].mid =
 | 
	
		
			
				|  |  | +            mid - Vector2(WIDTH * (static_cast<float>(i) - 4.5f),
 | 
	
		
			
				|  |  | +                          RADIUS + LINE_LENGTH * 0.5f);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for(int i = 7; i < 12; i++) {
 | 
	
		
			
				|  |  | +        hexagons[i].mid =
 | 
	
		
			
				|  |  | +            mid - Vector2(WIDTH * static_cast<float>(i - 9), 0.0f);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void initCornerMid() {
 | 
	
		
			
				|  |  | +    for(int i = 0; i < hexagons.getLength(); i++) {
 | 
	
		
			
				|  |  | +        corners[i].mid = hexagons[i].getLeftTopCorner();
 | 
	
		
			
				|  |  | +        corners[i + 19].mid = hexagons[i].getLeftBottomCorner();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    corners[38].mid = hexagons[0].getTopCorner();
 | 
	
		
			
				|  |  | +    corners[39].mid = hexagons[1].getTopCorner();
 | 
	
		
			
				|  |  | +    corners[40].mid = hexagons[2].getTopCorner();
 | 
	
		
			
				|  |  | +    corners[41].mid = hexagons[16].getBottomCorner();
 | 
	
		
			
				|  |  | +    corners[42].mid = hexagons[17].getBottomCorner();
 | 
	
		
			
				|  |  | +    corners[43].mid = hexagons[18].getBottomCorner();
 | 
	
		
			
				|  |  | +    corners[44].mid = hexagons[0].getRightTopCorner();
 | 
	
		
			
				|  |  | +    corners[45].mid = hexagons[0].getRightBottomCorner();
 | 
	
		
			
				|  |  | +    corners[46].mid = hexagons[3].getRightTopCorner();
 | 
	
		
			
				|  |  | +    corners[47].mid = hexagons[3].getRightBottomCorner();
 | 
	
		
			
				|  |  | +    corners[48].mid = hexagons[7].getRightTopCorner();
 | 
	
		
			
				|  |  | +    corners[49].mid = hexagons[7].getRightBottomCorner();
 | 
	
		
			
				|  |  | +    corners[50].mid = hexagons[12].getRightTopCorner();
 | 
	
		
			
				|  |  | +    corners[51].mid = hexagons[12].getRightBottomCorner();
 | 
	
		
			
				|  |  | +    corners[52].mid = hexagons[16].getRightTopCorner();
 | 
	
		
			
				|  |  | +    corners[53].mid = hexagons[16].getRightBottomCorner();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int findCorner(const Vector2& mid) {
 | 
	
		
			
				|  |  | +    for(int i = 0; i < corners.getLength(); i++) {
 | 
	
		
			
				|  |  | +        if((mid - corners[i].mid).squareLength() < 0.00001f) {
 | 
	
		
			
				|  |  | +            return i;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void initHexagonCorners() {
 | 
	
		
			
				|  |  | +    for(Hexagon& h : hexagons) {
 | 
	
		
			
				|  |  | +        h.corners[0] = findCorner(h.getTopCorner());
 | 
	
		
			
				|  |  | +        h.corners[1] = findCorner(h.getBottomCorner());
 | 
	
		
			
				|  |  | +        h.corners[2] = findCorner(h.getLeftTopCorner());
 | 
	
		
			
				|  |  | +        h.corners[3] = findCorner(h.getLeftBottomCorner());
 | 
	
		
			
				|  |  | +        h.corners[4] = findCorner(h.getRightTopCorner());
 | 
	
		
			
				|  |  | +        h.corners[5] = findCorner(h.getRightBottomCorner());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for(int i = 0; i < hexagons.getLength(); i++) {
 | 
	
		
			
				|  |  | +        for(int c = 0; c < hexagons[c].corners.getLength(); c++) {
 | 
	
		
			
				|  |  | +            if(hexagons[i].corners[c] == -1) {
 | 
	
		
			
				|  |  | +                LOG_WARNING("Could not find a hexagon corner");
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                if(corners[hexagons[i].corners[c]].hexagons.add(i)) {
 | 
	
		
			
				|  |  | +                    LOG_WARNING("Corner hexagon overflow");
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void init() {
 | 
	
		
			
				|  |  | +    initResources();
 | 
	
		
			
				|  |  | +    initHexagonMid();
 | 
	
		
			
				|  |  | +    initCornerMid();
 | 
	
		
			
				|  |  | +    initHexagonCorners();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void buildBuffer() {
 | 
	
		
			
				|  |  | +    buffer.clear();
 | 
	
		
			
				|  |  | +    for(const Hexagon& h : hexagons) {
 | 
	
		
			
				|  |  | +        h.addToBuffer();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for(const Corner& c : corners) {
 | 
	
		
			
				|  |  | +        c.addToBuffer();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    vertexBuffer.setData(buffer, GL::BufferUsage::STATIC);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void tick() {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void render(float lag) {
 | 
	
		
			
				|  |  | +    GL::setViewport(Window::getSize()[0], Window::getSize()[1]);
 | 
	
		
			
				|  |  | +    shader.use();
 | 
	
		
			
				|  |  | +    vertexBuffer.draw(vertexBuffer.getSize() /
 | 
	
		
			
				|  |  | +                      static_cast<int>(sizeof(Vector2) + sizeof(Color4)));
 | 
	
		
			
				|  |  |      (void)lag;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -20,6 +239,14 @@ int main() {
 | 
	
		
			
				|  |  |          e.message.printLine();
 | 
	
		
			
				|  |  |          return 0;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    e = shader.compile("resources/vertex.vs", "resources/fragment.fs");
 | 
	
		
			
				|  |  | +    if(e.has()) {
 | 
	
		
			
				|  |  | +        e.message.printLine();
 | 
	
		
			
				|  |  | +        return 0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    vertexBuffer.init(VertexBuffer::Attributes().addFloat(2).addColor4());
 | 
	
		
			
				|  |  | +    init();
 | 
	
		
			
				|  |  | +    buildBuffer();
 | 
	
		
			
				|  |  |      Window::show();
 | 
	
		
			
				|  |  |      Window::run<shouldRun, tick, render>(10'000'000);
 | 
	
		
			
				|  |  |      return 0;
 |