Main.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include <cmath>
  2. #include <cstdio>
  3. #include "data/Array.h"
  4. #include "data/ArrayList.h"
  5. #include "data/List.h"
  6. #include "math/Vector.h"
  7. #include "rendering/Shader.h"
  8. #include "rendering/VertexBuffer.h"
  9. #include "rendering/Window.h"
  10. #include "utils/Color.h"
  11. #include "utils/Logger.h"
  12. #include "utils/Random.h"
  13. static Shader shader;
  14. static Buffer buffer;
  15. static VertexBuffer vertexBuffer;
  16. enum class Resource { NOTHING, CLAY, ORE, WHEAT, SHEEP, WOOD };
  17. static const Color4 RESOURCE_COLOR[] = {
  18. Color4(160, 120, 0, 255), Color4(220, 96, 0, 255),
  19. Color4(128, 128, 128, 255), Color4(255, 200, 0, 255),
  20. Color4(40, 200, 40, 255), Color4(0, 120, 0, 255)};
  21. static const Vector2 MIN_BORDER(-0.9f, -0.9f);
  22. static const Vector2 MAX_BORDER(0.9f, 0.9f);
  23. static const Vector2 AREA = MAX_BORDER - MIN_BORDER;
  24. static const float RADIUS =
  25. AREA[0] / (5.0f * 2.0f * cosf(30.0f * static_cast<float>(M_PI) / 180.0f));
  26. static const float LINE_LENGTH =
  27. RADIUS * sinf(30.0f * static_cast<float>(M_PI) / 180.0f) * 2.0f;
  28. static const float WIDTH = AREA[0] / 5.0f;
  29. static void addTriangle(const Vector2 a, const Vector2 b, const Vector2 c,
  30. const Color4& color) {
  31. buffer.add(a).add(color);
  32. buffer.add(b).add(color);
  33. buffer.add(c).add(color);
  34. }
  35. static void addSquare(const Vector2 mid, float size, const Color4& color) {
  36. size *= 0.5f;
  37. Vector2 a = mid + Vector2(-size, size);
  38. Vector2 b = mid + Vector2(size, size);
  39. Vector2 c = mid + Vector2(-size, -size);
  40. Vector2 d = mid + Vector2(size, -size);
  41. addTriangle(a, b, c, color);
  42. addTriangle(b, d, c, color);
  43. }
  44. struct Hexagon {
  45. Resource resource = Resource::NOTHING;
  46. Vector2 mid;
  47. Array<int, 6> corners;
  48. Hexagon() : corners(-1) {
  49. }
  50. void addToBuffer() const {
  51. Color4 color = RESOURCE_COLOR[static_cast<int>(resource)];
  52. float angle = 2.0f * static_cast<float>(M_PI) / 6.0f;
  53. for(int i = 0; i < 6; i++) {
  54. Vector2 a(sinf(angle * static_cast<float>(i)) * RADIUS,
  55. cosf(angle * static_cast<float>(i)) * RADIUS);
  56. Vector2 b(sinf(angle * static_cast<float>(i + 1)) * RADIUS,
  57. cosf(angle * static_cast<float>(i + 1)) * RADIUS);
  58. addTriangle(a + mid, b + mid, mid, color);
  59. }
  60. }
  61. Vector2 getTopCorner() const {
  62. return mid + Vector2(0.0f, RADIUS);
  63. }
  64. Vector2 getBottomCorner() const {
  65. return mid - Vector2(0.0f, RADIUS);
  66. }
  67. Vector2 getLeftTopCorner() const {
  68. return mid - Vector2(WIDTH, -LINE_LENGTH) * 0.5f;
  69. }
  70. Vector2 getLeftBottomCorner() const {
  71. return mid - Vector2(WIDTH, LINE_LENGTH) * 0.5f;
  72. }
  73. Vector2 getRightTopCorner() const {
  74. return mid + Vector2(WIDTH, LINE_LENGTH) * 0.5f;
  75. }
  76. Vector2 getRightBottomCorner() const {
  77. return mid + Vector2(WIDTH, -LINE_LENGTH) * 0.5f;
  78. }
  79. };
  80. static Array<Hexagon, 19> hexagons;
  81. struct Corner {
  82. int player = -1;
  83. Vector2 mid;
  84. ArrayList<int, 3> hexagons;
  85. ArrayList<int, 3> paths;
  86. void addToBuffer() const {
  87. addSquare(mid, 0.05f, Color4(255, 255, 255, 255));
  88. }
  89. };
  90. static Array<Corner, 54> corners;
  91. struct Path {
  92. int player = -1;
  93. Vector2 from;
  94. Vector2 to;
  95. int cornerA = -1;
  96. int cornerB = -1;
  97. void addToBuffer() const {
  98. Vector2 diff = to - from;
  99. Vector2 normal(diff[1], -diff[0]);
  100. normal.normalize();
  101. normal *= 0.01f;
  102. Vector2 a = from + normal;
  103. Vector2 b = from - normal;
  104. Vector2 c = to + normal;
  105. Vector2 d = to - normal;
  106. addTriangle(a, c, b, Color4(255, 255, 255, 255));
  107. addTriangle(c, d, b, Color4(255, 255, 255, 255));
  108. }
  109. Vector2 getMid() const {
  110. return (to + from) * 0.5f;
  111. }
  112. };
  113. static List<Path> paths;
  114. static void initResources() {
  115. for(int i = 0; i < 4; i++) {
  116. hexagons[i].resource = Resource::WHEAT;
  117. hexagons[i + 4].resource = Resource::WOOD;
  118. hexagons[i + 8].resource = Resource::SHEEP;
  119. }
  120. for(int i = 0; i < 3; i++) {
  121. hexagons[i + 12].resource = Resource::ORE;
  122. hexagons[i + 15].resource = Resource::CLAY;
  123. }
  124. hexagons[18].resource = Resource::NOTHING;
  125. Random r(0);
  126. for(int i = 0; i < hexagons.getLength(); i++) {
  127. std::swap(hexagons[i], hexagons[r.next(i, hexagons.getLength() - 1)]);
  128. }
  129. }
  130. static void initHexagonMid() {
  131. Vector2 mid = MIN_BORDER + AREA * 0.5f;
  132. for(int i = 0; i < 3; i++) {
  133. hexagons[i].mid = mid - Vector2(WIDTH * static_cast<float>(i - 1),
  134. -RADIUS * 2.0f - LINE_LENGTH);
  135. hexagons[i + 16].mid = mid - Vector2(WIDTH * static_cast<float>(i - 1),
  136. RADIUS * 2.0f + LINE_LENGTH);
  137. }
  138. for(int i = 3; i < 7; i++) {
  139. hexagons[i].mid = mid - Vector2(WIDTH * (static_cast<float>(i) - 4.5f),
  140. -RADIUS - LINE_LENGTH * 0.5f);
  141. hexagons[i + 9].mid =
  142. mid - Vector2(WIDTH * (static_cast<float>(i) - 4.5f),
  143. RADIUS + LINE_LENGTH * 0.5f);
  144. }
  145. for(int i = 7; i < 12; i++) {
  146. hexagons[i].mid =
  147. mid - Vector2(WIDTH * static_cast<float>(i - 9), 0.0f);
  148. }
  149. }
  150. static void initCornerMid() {
  151. for(int i = 0; i < hexagons.getLength(); i++) {
  152. corners[i].mid = hexagons[i].getLeftTopCorner();
  153. corners[i + 19].mid = hexagons[i].getLeftBottomCorner();
  154. }
  155. corners[38].mid = hexagons[0].getTopCorner();
  156. corners[39].mid = hexagons[1].getTopCorner();
  157. corners[40].mid = hexagons[2].getTopCorner();
  158. corners[41].mid = hexagons[16].getBottomCorner();
  159. corners[42].mid = hexagons[17].getBottomCorner();
  160. corners[43].mid = hexagons[18].getBottomCorner();
  161. corners[44].mid = hexagons[0].getRightTopCorner();
  162. corners[45].mid = hexagons[0].getRightBottomCorner();
  163. corners[46].mid = hexagons[3].getRightTopCorner();
  164. corners[47].mid = hexagons[3].getRightBottomCorner();
  165. corners[48].mid = hexagons[7].getRightTopCorner();
  166. corners[49].mid = hexagons[7].getRightBottomCorner();
  167. corners[50].mid = hexagons[12].getRightTopCorner();
  168. corners[51].mid = hexagons[12].getRightBottomCorner();
  169. corners[52].mid = hexagons[16].getRightTopCorner();
  170. corners[53].mid = hexagons[16].getRightBottomCorner();
  171. }
  172. static int findCorner(const Vector2& mid) {
  173. for(int i = 0; i < corners.getLength(); i++) {
  174. if((mid - corners[i].mid).squareLength() < 0.00001f) {
  175. return i;
  176. }
  177. }
  178. return -1;
  179. }
  180. static void initHexagonCorners() {
  181. for(Hexagon& h : hexagons) {
  182. h.corners[0] = findCorner(h.getTopCorner());
  183. h.corners[1] = findCorner(h.getBottomCorner());
  184. h.corners[2] = findCorner(h.getLeftTopCorner());
  185. h.corners[3] = findCorner(h.getLeftBottomCorner());
  186. h.corners[4] = findCorner(h.getRightTopCorner());
  187. h.corners[5] = findCorner(h.getRightBottomCorner());
  188. }
  189. for(int i = 0; i < hexagons.getLength(); i++) {
  190. for(int c = 0; c < hexagons[c].corners.getLength(); c++) {
  191. if(hexagons[i].corners[c] == -1) {
  192. LOG_WARNING("Could not find a hexagon corner");
  193. } else {
  194. if(corners[hexagons[i].corners[c]].hexagons.add(i)) {
  195. LOG_WARNING("Corner hexagon overflow");
  196. }
  197. }
  198. }
  199. }
  200. }
  201. static bool doesPathExist(const Path& p) {
  202. Vector2 mid = p.getMid();
  203. for(const Path& po : paths) {
  204. if((mid - po.getMid()).squareLength() < 0.0001f) {
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. static void initPaths() {
  211. for(int i = 0; i < corners.getLength(); i++) {
  212. for(int k = 0; k < corners.getLength(); k++) {
  213. if(i == k || (corners[i].mid - corners[k].mid).length() >=
  214. LINE_LENGTH * 1.01f) {
  215. continue;
  216. }
  217. Path p;
  218. p.from = corners[i].mid;
  219. p.to = corners[k].mid;
  220. if(doesPathExist(p)) {
  221. continue;
  222. }
  223. paths.add(p);
  224. }
  225. }
  226. LOG_INFO(
  227. StringBuffer<256>("Got ").append(paths.getLength()).append(" paths"));
  228. }
  229. static void initCornerPaths() {
  230. for(int c = 0; c < corners.getLength(); c++) {
  231. for(int i = 0; i < paths.getLength(); i++) {
  232. Vector2 mid = paths[i].getMid();
  233. if((corners[c].mid - mid).length() >= RADIUS) {
  234. continue;
  235. }
  236. if(corners[c].paths.add(i)) {
  237. LOG_WARNING("Corner path overflow");
  238. }
  239. if(paths[i].cornerA == -1) {
  240. paths[i].cornerA = c;
  241. } else if(paths[i].cornerB == -1) {
  242. paths[i].cornerB = c;
  243. } else {
  244. LOG_WARNING("Path got too much corners");
  245. }
  246. }
  247. }
  248. for(const Path& p : paths) {
  249. if(p.cornerA == -1 || p.cornerB == -1) {
  250. LOG_WARNING("Path is missing corners");
  251. }
  252. }
  253. }
  254. static void init() {
  255. initResources();
  256. initHexagonMid();
  257. initCornerMid();
  258. initHexagonCorners();
  259. initPaths();
  260. initCornerPaths();
  261. }
  262. static void buildBuffer() {
  263. buffer.clear();
  264. for(const Hexagon& h : hexagons) {
  265. h.addToBuffer();
  266. }
  267. for(const Corner& c : corners) {
  268. c.addToBuffer();
  269. }
  270. for(const Path& p : paths) {
  271. p.addToBuffer();
  272. }
  273. vertexBuffer.setData(buffer, GL::BufferUsage::STATIC);
  274. }
  275. static void tick() {
  276. }
  277. static void render(float lag) {
  278. GL::setViewport(Window::getSize()[0], Window::getSize()[1]);
  279. shader.use();
  280. vertexBuffer.draw(vertexBuffer.getSize() /
  281. static_cast<int>(sizeof(Vector2) + sizeof(Color4)));
  282. (void)lag;
  283. }
  284. static bool shouldRun() {
  285. return !Window::shouldClose();
  286. }
  287. int main() {
  288. Error e = Window::open(
  289. Window::Options(4, 6, IntVector2(400, 300), false, "Catan Simulator"));
  290. if(e.has()) {
  291. e.message.printLine();
  292. return 0;
  293. }
  294. e = shader.compile("resources/vertex.vs", "resources/fragment.fs");
  295. if(e.has()) {
  296. e.message.printLine();
  297. return 0;
  298. }
  299. vertexBuffer.init(VertexBuffer::Attributes().addFloat(2).addColor4());
  300. init();
  301. buildBuffer();
  302. Window::show();
  303. Window::run<shouldRun, tick, render>(10'000'000);
  304. return 0;
  305. }