A 2D tile-based sandbox game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Renderer.cc 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. #include "Renderer.h"
  2. #include <iostream>
  3. #include <stdio.h>
  4. #include <swan-common/constants.h>
  5. #include <string.h>
  6. // std::endian was originally in type_traits, was moved to bit
  7. #include <type_traits>
  8. #include <bit>
  9. #include "gl.h"
  10. #include "shaders.h"
  11. #include "GlWrappers.h"
  12. #include "TileAtlas.h"
  13. #include "util.h"
  14. namespace Cygnet {
  15. struct ChunkProg: public GlProgram {
  16. template<typename... T>
  17. ChunkProg(const T &... shaders): GlProgram(shaders...) { init(); }
  18. ~ChunkProg() { deinit(); }
  19. GLint camera = uniformLoc("camera");
  20. GLint pos = uniformLoc("pos");
  21. GLint vertex = attribLoc("vertex");
  22. GLint tileAtlas = uniformLoc("tileAtlas");
  23. GLint tileAtlasSize = uniformLoc("tileAtlasSize");
  24. GLint tiles = uniformLoc("tiles");
  25. GLuint vbo;
  26. static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT;
  27. static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH;
  28. static constexpr GLfloat vertexes[] = {
  29. 0.0f, 0.0f, // pos 0: top left
  30. 0.0f, ch, // pos 1: bottom left
  31. cw, ch, // pos 2: bottom right
  32. cw, ch, // pos 2: bottom right
  33. cw, 0.0f, // pos 3: top right
  34. 0.0f, 0.0f, // pos 0: top left
  35. };
  36. void enable() {
  37. glUseProgram(id());
  38. glCheck();
  39. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  40. glCheck();
  41. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
  42. glCheck();
  43. glEnableVertexAttribArray(vertex);
  44. glCheck();
  45. glUniform1i(tileAtlas, 0);
  46. glUniform1i(tiles, 1);
  47. }
  48. void disable() {
  49. glDisableVertexAttribArray(vertex);
  50. glCheck();
  51. }
  52. void init() {
  53. glGenBuffers(1, &vbo);
  54. glCheck();
  55. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  56. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  57. glCheck();
  58. }
  59. void deinit() {
  60. glDeleteBuffers(1, &vbo);
  61. glCheck();
  62. }
  63. };
  64. struct ChunkShadowProg: public GlProgram {
  65. template<typename... T>
  66. ChunkShadowProg(const T &... shaders): GlProgram(shaders...) { init(); }
  67. ~ChunkShadowProg() { deinit(); }
  68. GLint camera = uniformLoc("camera");
  69. GLint pos = uniformLoc("pos");
  70. GLint vertex = attribLoc("vertex");
  71. GLint tex = uniformLoc("tex");
  72. GLuint vbo;
  73. static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT;
  74. static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH;
  75. static constexpr GLfloat vertexes[] = {
  76. 0.0f, 0.0f, // pos 0: top left
  77. 0.0f, ch , // pos 1: bottom left
  78. cw, ch, // pos 2: bottom right
  79. cw, ch, // pos 2: bottom right
  80. cw, 0.0f, // pos 3: top right
  81. 0.0f, 0.0f, // pos 0: top left
  82. };
  83. void enable() {
  84. glUseProgram(id());
  85. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  86. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
  87. glEnableVertexAttribArray(vertex);
  88. glCheck();
  89. glUniform1i(tex, 0);
  90. }
  91. void disable() {
  92. glDisableVertexAttribArray(vertex);
  93. glCheck();
  94. }
  95. void init() {
  96. glGenBuffers(1, &vbo);
  97. glCheck();
  98. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  99. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  100. glCheck();
  101. }
  102. void deinit() {
  103. glDeleteBuffers(1, &vbo);
  104. glCheck();
  105. }
  106. };
  107. struct TileProg: public GlProgram {
  108. template<typename... T>
  109. TileProg(const T &... shaders): GlProgram(shaders...) { init(); }
  110. ~TileProg() { deinit(); }
  111. GLint camera = uniformLoc("camera");
  112. GLint transform = uniformLoc("transform");
  113. GLint vertex = attribLoc("vertex");
  114. GLint tileAtlas = uniformLoc("tileAtlas");
  115. GLint tileAtlasSize = uniformLoc("tileAtlasSize");
  116. GLint tileID = uniformLoc("tileID");
  117. GLuint vbo;
  118. static constexpr GLfloat vertexes[] = {
  119. 0.0f, 0.0f, // pos 0: top left
  120. 0.0f, 1.0f, // pos 1: bottom left
  121. 1.0f, 1.0f, // pos 2: bottom right
  122. 1.0f, 1.0f, // pos 2: bottom right
  123. 1.0f, 0.0f, // pos 3: top right
  124. 0.0f, 0.0f, // pos 0: top left
  125. };
  126. void enable() {
  127. glUseProgram(id());
  128. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  129. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
  130. glEnableVertexAttribArray(vertex);
  131. glCheck();
  132. glUniform1i(tileAtlas, 0);
  133. }
  134. void disable() {
  135. glDisableVertexAttribArray(vertex);
  136. glCheck();
  137. }
  138. void init() {
  139. glGenBuffers(1, &vbo);
  140. glCheck();
  141. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  142. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  143. glCheck();
  144. }
  145. void deinit() {
  146. glDeleteBuffers(1, &vbo);
  147. glCheck();
  148. }
  149. };
  150. struct SpriteProg: public GlProgram {
  151. template<typename... T>
  152. SpriteProg(const T &... shaders): GlProgram(shaders...) { init(); }
  153. ~SpriteProg() { deinit(); }
  154. GLint camera = uniformLoc("camera");
  155. GLint transform = uniformLoc("transform");
  156. GLint frameSize = uniformLoc("frameSize");
  157. GLint frameInfo = uniformLoc("frameInfo");
  158. GLint vertex = attribLoc("vertex");
  159. GLint tex = uniformLoc("tex");
  160. GLuint vbo;
  161. static constexpr GLfloat vertexes[] = {
  162. 0.0f, 0.0f, // pos 0: top left
  163. 0.0f, 1.0f, // pos 1: bottom left
  164. 1.0f, 1.0f, // pos 2: bottom right
  165. 1.0f, 1.0f, // pos 2: bottom right
  166. 1.0f, 0.0f, // pos 3: top right
  167. 0.0f, 0.0f, // pos 0: top left
  168. };
  169. void enable() {
  170. glUseProgram(id());
  171. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  172. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
  173. glEnableVertexAttribArray(vertex);
  174. glCheck();
  175. glUniform1i(tex, 0);
  176. }
  177. void disable() {
  178. glDisableVertexAttribArray(vertex);
  179. glCheck();
  180. }
  181. void init() {
  182. glGenBuffers(1, &vbo);
  183. glCheck();
  184. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  185. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  186. glCheck();
  187. }
  188. void deinit() {
  189. glDeleteBuffers(1, &vbo);
  190. glCheck();
  191. }
  192. };
  193. struct RectProg: public GlProgram {
  194. template<typename... T>
  195. RectProg(const T &... shaders): GlProgram(shaders...) { init(); }
  196. ~RectProg() { deinit(); }
  197. GLint camera = uniformLoc("camera");
  198. GLint pos = uniformLoc("pos");
  199. GLint size = uniformLoc("size");
  200. GLint vertex = attribLoc("vertex");
  201. GLuint vbo;
  202. static constexpr GLfloat vertexes[] = {
  203. 0.0f, 0.0f, // pos 0: top left
  204. 0.0f, 1.0f, // pos 1: bottom left
  205. 1.0f, 1.0f, // pos 2: bottom right
  206. 1.0f, 1.0f, // pos 2: bottom right
  207. 1.0f, 0.0f, // pos 3: top right
  208. 0.0f, 0.0f, // pos 0: top left
  209. };
  210. void enable() {
  211. glUseProgram(id());
  212. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  213. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
  214. glEnableVertexAttribArray(vertex);
  215. glCheck();
  216. }
  217. void disable() {
  218. glDisableVertexAttribArray(vertex);
  219. glCheck();
  220. }
  221. void init() {
  222. glGenBuffers(1, &vbo);
  223. glCheck();
  224. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  225. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  226. glCheck();
  227. }
  228. void deinit() {
  229. glDeleteBuffers(1, &vbo);
  230. glCheck();
  231. }
  232. };
  233. struct BlendProg: public GlProgram {
  234. template<typename... T>
  235. BlendProg(const T &... shaders): GlProgram(shaders...) { init(); }
  236. ~BlendProg() { deinit(); }
  237. GLint vertex = attribLoc("vertex");
  238. GLint texCoord = attribLoc("texCoord");
  239. GLint tex = uniformLoc("tex");
  240. GLuint vbo;
  241. static constexpr GLfloat vertexes[] = {
  242. -1.0f, -1.0f, 0.0f, 0.0f, // pos 0: top left
  243. -1.0f, 1.0f, 0.0f, 1.0f, // pos 1: bottom left
  244. 1.0f, 1.0f, 1.0f, 1.0f, // pos 2: bottom right
  245. 1.0f, 1.0f, 1.0f, 1.0f, // pos 2: bottom right
  246. 1.0f, -1.0f, 1.0f, 0.0f, // pos 3: top right
  247. -1.0f, -1.0f, 0.0f, 0.0f, // pos 0: top left
  248. };
  249. void enable() {
  250. glUseProgram(id());
  251. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  252. glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)0);
  253. glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));
  254. glEnableVertexAttribArray(vertex);
  255. glEnableVertexAttribArray(texCoord);
  256. glCheck();
  257. glUniform1i(tex, 0);
  258. glCheck();
  259. }
  260. void disable() {
  261. glDisableVertexAttribArray(vertex);
  262. glCheck();
  263. }
  264. void init() {
  265. glGenBuffers(1, &vbo);
  266. glCheck();
  267. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  268. glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
  269. glCheck();
  270. }
  271. void deinit() {
  272. glDeleteBuffers(1, &vbo);
  273. glCheck();
  274. }
  275. };
  276. struct RendererState {
  277. GlVxShader chunkVx{Shaders::chunkVx};
  278. GlFrShader chunkFr{Shaders::chunkFr};
  279. GlVxShader chunkShadowVx{Shaders::chunkShadowVx};
  280. GlFrShader chunkShadowFr{Shaders::chunkShadowFr};
  281. GlVxShader tileVx{Shaders::tileVx};
  282. GlFrShader tileFr{Shaders::tileFr};
  283. GlVxShader spriteVx{Shaders::spriteVx};
  284. GlFrShader spriteFr{Shaders::spriteFr};
  285. GlVxShader rectVx{Shaders::rectVx};
  286. GlFrShader rectFr{Shaders::rectFr};
  287. GlVxShader blendVx{Shaders::blendVx};
  288. GlFrShader blendFr{Shaders::blendFr};
  289. ChunkProg chunkProg{chunkVx, chunkFr};
  290. ChunkShadowProg chunkShadowProg{chunkShadowVx, chunkShadowFr};
  291. TileProg tileProg{tileVx, tileFr};
  292. SpriteProg spriteProg{spriteVx, spriteFr};
  293. RectProg rectProg{rectVx, rectFr};
  294. BlendProg blendProg{blendVx, blendFr};
  295. SwanCommon::Vec2i screenSize;
  296. GLuint offscreenFramebuffer = 0;
  297. GLuint offscreenTex = 0;
  298. GLuint atlasTex = 0;
  299. SwanCommon::Vec2 atlasTexSize;
  300. };
  301. Renderer::Renderer(): state_(std::make_unique<RendererState>()) {
  302. glGenTextures(1, &state_->atlasTex);
  303. glCheck();
  304. glGenTextures(1, &state_->offscreenTex);
  305. glCheck();
  306. }
  307. Renderer::~Renderer() {
  308. glDeleteFramebuffers(1, &state_->offscreenFramebuffer);
  309. glDeleteTextures(1, &state_->offscreenFramebuffer);
  310. glDeleteTextures(1, &state_->atlasTex);
  311. }
  312. void Renderer::draw(const RenderCamera &cam) {
  313. Mat3gf camMat;
  314. camMat.translate(-cam.pos);
  315. if (cam.size.y > cam.size.x) {
  316. float ratio = (float)cam.size.y / (float)cam.size.x;
  317. winScale_ = {1/ratio, 1};
  318. camMat.scale({cam.zoom * ratio, -cam.zoom});
  319. } else {
  320. float ratio = (float)cam.size.x / (float)cam.size.y;
  321. winScale_ = {1, 1/ratio};
  322. camMat.scale({cam.zoom, -cam.zoom * ratio});
  323. }
  324. auto &chunkProg = state_->chunkProg;
  325. auto &chunkShadowProg = state_->chunkShadowProg;
  326. auto &tileProg = state_->tileProg;
  327. auto &spriteProg = state_->spriteProg;
  328. auto &rectProg = state_->rectProg;
  329. auto &blendProg = state_->blendProg;
  330. if (state_->screenSize != cam.size) {
  331. state_->screenSize = cam.size;
  332. glBindTexture(GL_TEXTURE_2D, state_->offscreenTex);
  333. glCheck();
  334. glTexImage2D(
  335. GL_TEXTURE_2D, 0, GL_RGBA, cam.size.x, cam.size.y, 0,
  336. GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  337. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  338. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  339. glCheck();
  340. glGenFramebuffers(1, &state_->offscreenFramebuffer);
  341. glCheck();
  342. glBindFramebuffer(GL_FRAMEBUFFER, state_->offscreenFramebuffer);
  343. glCheck();
  344. glFramebufferTexture2D(
  345. GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  346. state_->offscreenTex, 0);
  347. glCheck();
  348. }
  349. glBindFramebuffer(GL_FRAMEBUFFER, state_->offscreenFramebuffer);
  350. glFramebufferTexture2D(
  351. GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  352. state_->offscreenTex, 0);
  353. glClearColor(0, 0, 0, 0);
  354. glClear(GL_COLOR_BUFFER_BIT);
  355. {
  356. chunkProg.enable();
  357. glUniformMatrix3fv(chunkProg.camera, 1, GL_TRUE, camMat.data());
  358. glCheck();
  359. glUniform2f(chunkProg.tileAtlasSize, state_->atlasTexSize.x, state_->atlasTexSize.y);
  360. glCheck();
  361. glActiveTexture(GL_TEXTURE0);
  362. glBindTexture(GL_TEXTURE_2D, state_->atlasTex);
  363. glCheck();
  364. glActiveTexture(GL_TEXTURE1);
  365. for (auto [pos, chunk]: drawChunks_) {
  366. glUniform2f(chunkProg.pos, pos.x, pos.y);
  367. glBindTexture(GL_TEXTURE_2D, chunk.tex);
  368. glDrawArrays(GL_TRIANGLES, 0, 6);
  369. glCheck();
  370. }
  371. drawChunks_.clear();
  372. chunkProg.disable();
  373. }
  374. {
  375. tileProg.enable();
  376. glUniformMatrix3fv(tileProg.camera, 1, GL_TRUE, camMat.data());
  377. glCheck();
  378. glUniform2f(tileProg.tileAtlasSize, state_->atlasTexSize.x, state_->atlasTexSize.y);
  379. glCheck();
  380. glActiveTexture(GL_TEXTURE0);
  381. glBindTexture(GL_TEXTURE_2D, state_->atlasTex);
  382. glCheck();
  383. glActiveTexture(GL_TEXTURE1);
  384. for (auto [mat, id]: drawTiles_) {
  385. glUniformMatrix3fv(tileProg.transform, 1, GL_TRUE, mat.data());
  386. glUniform1f(tileProg.tileID, id);
  387. glDrawArrays(GL_TRIANGLES, 0, 6);
  388. glCheck();
  389. }
  390. drawTiles_.clear();
  391. tileProg.disable();
  392. }
  393. {
  394. spriteProg.enable();
  395. glUniformMatrix3fv(spriteProg.camera, 1, GL_TRUE, camMat.data());
  396. glCheck();
  397. glActiveTexture(GL_TEXTURE0);
  398. for (auto [mat, frame, sprite]: drawSprites_) {
  399. glUniformMatrix3fv(spriteProg.transform, 1, GL_TRUE, mat.data());
  400. glUniform2f(spriteProg.frameSize, sprite.scale.x, sprite.scale.y);
  401. glUniform2f(spriteProg.frameInfo, sprite.frameCount, frame);
  402. glBindTexture(GL_TEXTURE_2D, sprite.tex);
  403. glDrawArrays(GL_TRIANGLES, 0, 6);
  404. glCheck();
  405. }
  406. drawSprites_.clear();
  407. spriteProg.disable();
  408. }
  409. {
  410. rectProg.enable();
  411. glUniformMatrix3fv(rectProg.camera, 1, GL_TRUE, camMat.data());
  412. glCheck();
  413. for (auto [pos, size]: drawRects_) {
  414. glUniform2f(rectProg.pos, pos.x, pos.y);
  415. glUniform2f(rectProg.size, size.x, size.y);
  416. glDrawArrays(GL_TRIANGLES, 0, 6);
  417. glCheck();
  418. }
  419. drawRects_.clear();
  420. rectProg.disable();
  421. }
  422. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  423. {
  424. blendProg.enable();
  425. glActiveTexture(GL_TEXTURE0);
  426. glBindTexture(GL_TEXTURE_2D, state_->offscreenTex);
  427. glDrawArrays(GL_TRIANGLES, 0, 6);
  428. glCheck();
  429. blendProg.disable();
  430. }
  431. {
  432. chunkShadowProg.enable();
  433. glUniformMatrix3fv(chunkShadowProg.camera, 1, GL_TRUE, camMat.data());
  434. glCheck();
  435. glActiveTexture(GL_TEXTURE0);
  436. for (auto [pos, shadow]: drawChunkShadows_) {
  437. glUniform2f(chunkShadowProg.pos, pos.x, pos.y);
  438. glBindTexture(GL_TEXTURE_2D, shadow.tex);
  439. glDrawArrays(GL_TRIANGLES, 0, 6);
  440. glCheck();
  441. }
  442. drawChunkShadows_.clear();
  443. chunkShadowProg.disable();
  444. }
  445. }
  446. void Renderer::uploadTileAtlas(const void *data, int width, int height) {
  447. glBindTexture(GL_TEXTURE_2D, state_->atlasTex);
  448. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  449. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  450. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  451. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  452. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  453. glCheck();
  454. state_->atlasTexSize = {
  455. (float)(int)(width / SwanCommon::TILE_SIZE),
  456. (float)(int)(height / SwanCommon::TILE_SIZE) };
  457. }
  458. void Renderer::modifyTile(TileID id, const void *data) {
  459. int w = (int)state_->atlasTexSize.x;
  460. int x = id % w;
  461. int y = id / w;
  462. glActiveTexture(GL_TEXTURE0);
  463. glBindTexture(GL_TEXTURE_2D, state_->atlasTex);
  464. glTexSubImage2D(
  465. GL_TEXTURE_2D, 0, x * SwanCommon::TILE_SIZE, y * SwanCommon::TILE_SIZE,
  466. SwanCommon::TILE_SIZE, SwanCommon::TILE_SIZE,
  467. GL_RGBA, GL_UNSIGNED_BYTE, data);
  468. glCheck();
  469. }
  470. RenderChunk Renderer::createChunk(
  471. TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) {
  472. RenderChunk chunk;
  473. glGenTextures(1, &chunk.tex);
  474. glCheck();
  475. glActiveTexture(GL_TEXTURE0);
  476. glBindTexture(GL_TEXTURE_2D, chunk.tex);
  477. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  478. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  479. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  480. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  481. glCheck();
  482. static_assert(
  483. std::endian::native == std::endian::big ||
  484. std::endian::native == std::endian::little,
  485. "Expected either big or little endian");
  486. if constexpr (std::endian::native == std::endian::little) {
  487. glTexImage2D(
  488. GL_TEXTURE_2D, 0, GL_RG,
  489. SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
  490. 0, GL_RG, GL_UNSIGNED_BYTE, tiles);
  491. glCheck();
  492. } else if constexpr (std::endian::native == std::endian::big) {
  493. uint8_t buf[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2];
  494. for (size_t y = 0; y < SwanCommon::CHUNK_HEIGHT; ++y) {
  495. for (size_t x = 0; x < SwanCommon::CHUNK_WIDTH; ++x) {
  496. size_t dst = y * SwanCommon::CHUNK_WIDTH * 2 + x * 2;
  497. size_t src = y * SwanCommon::CHUNK_WIDTH + x;
  498. buf[dst + 0] = tiles[src] & 0xff;
  499. buf[dst + 1] = (tiles[src] & 0xff00) >> 8;
  500. }
  501. }
  502. glTexImage2D(
  503. GL_TEXTURE_2D, 0, GL_RG,
  504. SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
  505. 0, GL_RG, GL_UNSIGNED_BYTE, buf);
  506. glCheck();
  507. }
  508. return chunk;
  509. }
  510. void Renderer::modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id) {
  511. glActiveTexture(GL_TEXTURE0);
  512. glBindTexture(GL_TEXTURE_2D, chunk.tex);
  513. glCheck();
  514. static_assert(
  515. std::endian::native == std::endian::big ||
  516. std::endian::native == std::endian::little,
  517. "Expected either big or little endian");
  518. if constexpr (std::endian::native == std::endian::little) {
  519. glTexSubImage2D(
  520. GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1,
  521. GL_RG, GL_UNSIGNED_BYTE, &id);
  522. } else if constexpr (std::endian::native == std::endian::big) {
  523. uint8_t buf[] = { (uint8_t)(id & 0xff), (uint8_t)((id & 0xff00) >> 8) };
  524. glTexSubImage2D(
  525. GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1,
  526. GL_RG, GL_UNSIGNED_BYTE, buf);
  527. }
  528. glCheck();
  529. }
  530. void Renderer::destroyChunk(RenderChunk chunk) {
  531. glDeleteTextures(1, &chunk.tex);
  532. glCheck();
  533. }
  534. RenderChunkShadow Renderer::createChunkShadow(
  535. uint8_t data[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) {
  536. RenderChunkShadow shadow;
  537. glGenTextures(1, &shadow.tex);
  538. glCheck();
  539. glActiveTexture(GL_TEXTURE0);
  540. glBindTexture(GL_TEXTURE_2D, shadow.tex);
  541. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  542. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  543. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  544. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  545. glCheck();
  546. glTexImage2D(
  547. GL_TEXTURE_2D, 0, GL_RED,
  548. SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
  549. 0, GL_RED, GL_UNSIGNED_BYTE, data);
  550. glCheck();
  551. return shadow;
  552. }
  553. void Renderer::modifyChunkShadow(
  554. RenderChunkShadow shadow,
  555. uint8_t data[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) {
  556. glActiveTexture(GL_TEXTURE0);
  557. glBindTexture(GL_TEXTURE_2D, shadow.tex);
  558. glTexImage2D(
  559. GL_TEXTURE_2D, 0, GL_RED,
  560. SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
  561. 0, GL_RED, GL_UNSIGNED_BYTE, data);
  562. glCheck();
  563. }
  564. void Renderer::destroyChunkShadow(RenderChunkShadow shadow) {
  565. glDeleteTextures(1, &shadow.tex);
  566. glCheck();
  567. }
  568. RenderSprite Renderer::createSprite(void *data, int width, int height, int fh) {
  569. RenderSprite sprite;
  570. sprite.scale = {
  571. (float)width / SwanCommon::TILE_SIZE,
  572. (float)fh / SwanCommon::TILE_SIZE };
  573. sprite.frameCount = height / fh;
  574. glGenTextures(1, &sprite.tex);
  575. glCheck();
  576. glActiveTexture(GL_TEXTURE0);
  577. glBindTexture(GL_TEXTURE_2D, sprite.tex);
  578. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  579. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  580. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  581. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  582. glCheck();
  583. glTexImage2D(
  584. GL_TEXTURE_2D, 0, GL_RGBA, width, height,
  585. 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  586. glCheck();
  587. return sprite;
  588. }
  589. RenderSprite Renderer::createSprite(void *data, int width, int height) {
  590. return createSprite(data, width, height, height);
  591. }
  592. void Renderer::destroySprite(RenderSprite sprite) {
  593. glDeleteTextures(1, &sprite.tex);
  594. }
  595. }