Wrapper.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. #include "Wrapper.h"
  2. #include <fstream>
  3. #include <cstring>
  4. #include <iostream>
  5. using namespace std;
  6. DummyClient DummyClient::dummy;
  7. IClient* Engine::client = &DummyClient::dummy;
  8. GLFWwindow* Engine::window = nullptr;
  9. GLuint Engine::vShader = 0;
  10. GLuint Engine::fShader = 0;
  11. GLuint Engine::program = 0;
  12. GLuint Engine::postVba = 0;
  13. GLuint Engine::postVbo = 0;
  14. GLuint Engine::postVShader = 0;
  15. GLuint Engine::postFShader = 0;
  16. GLuint Engine::postProgram = 0;
  17. GLuint Engine::frameBuffer = 0;
  18. GLuint Engine::frameTexture = 0;
  19. GLuint Engine::depthTexture = 0;
  20. int Engine::scale = 1;
  21. int Engine::width = 0;
  22. int Engine::height = 0;
  23. bool Engine::init(int width, int height, const char* name)
  24. {
  25. Engine::width = width;
  26. Engine::height = height;
  27. updateScale();
  28. if(!glfwInit())
  29. {
  30. cout << "could not initialize GLFW" << endl;
  31. return false;
  32. }
  33. glfwDefaultWindowHints();
  34. glfwWindowHint(GLFW_VISIBLE, 0);
  35. glfwWindowHint(GLFW_RESIZABLE, 1);
  36. window = glfwCreateWindow(width, height, name, nullptr, nullptr);
  37. if(!window)
  38. {
  39. cout << "could not create window" << endl;
  40. glfwTerminate();
  41. return false;
  42. }
  43. glfwMakeContextCurrent(window);
  44. glfwSwapInterval(1);
  45. glfwShowWindow(window);
  46. GLenum err = glewInit();
  47. if(GLEW_OK != err)
  48. {
  49. cout << "could not initialize GLEW: " << glewGetErrorString(err) << endl;
  50. return false;
  51. }
  52. cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
  53. vShader = 0;
  54. fShader = 0;
  55. program = createProgram("shader/vertex.vs", "shader/fragment.fs", vShader, program);
  56. if(program == 0)
  57. {
  58. if(vShader != 0)
  59. {
  60. glDeleteShader(vShader);
  61. }
  62. if(fShader != 0)
  63. {
  64. glDeleteShader(fShader);
  65. }
  66. glfwDestroyWindow(window);
  67. glfwTerminate();
  68. return false;
  69. }
  70. postVShader = 0;
  71. postFShader = 0;
  72. postProgram = createProgram("shader/postVertex.vs", "shader/postFragment.fs", postVShader, postFShader);
  73. if(postProgram == 0)
  74. {
  75. if(postVShader != 0)
  76. {
  77. glDeleteShader(postVShader);
  78. }
  79. if(postFShader != 0)
  80. {
  81. glDeleteShader(postFShader);
  82. }
  83. glfwDestroyWindow(window);
  84. glfwTerminate();
  85. return false;
  86. }
  87. glfwSetKeyCallback(window, onKeyEvent);
  88. glfwSetMouseButtonCallback(window, onMouseClick);
  89. glfwSetFramebufferSizeCallback(window, onWindowResize);
  90. //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  91. //glfwSetCursorPosCallback(window, onMouseMove);
  92. return true;
  93. }
  94. void Engine::start(IClient* client)
  95. {
  96. if(client != nullptr)
  97. {
  98. Engine::client = client;
  99. }
  100. generateFramebuffer();
  101. generatePostData();
  102. glEnable(GL_CULL_FACE);
  103. glDepthFunc(GL_LEQUAL);
  104. uint64_t newTime = glfwGetTimerValue();
  105. uint64_t oldTime = newTime;
  106. uint64_t lag = 0;
  107. while(!glfwWindowShouldClose(window))
  108. {
  109. oldTime = newTime;
  110. newTime = glfwGetTimerValue();
  111. lag += newTime - oldTime;
  112. int ticksPerFrame = 0;
  113. while(lag >= NANOS_PER_TICK)
  114. {
  115. lag -= NANOS_PER_TICK;
  116. Engine::client->tick();
  117. ticksPerFrame++;
  118. if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
  119. {
  120. long skip = lag / NANOS_PER_TICK;
  121. lag -= skip * NANOS_PER_TICK;
  122. if(skip > 0)
  123. {
  124. cout << "skipped " << skip << " game ticks " << lag << endl;
  125. }
  126. break;
  127. }
  128. }
  129. // draw scene in framebuffer
  130. glActiveTexture(GL_TEXTURE0);
  131. glUseProgram(program);
  132. glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  133. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  134. glEnable(GL_DEPTH_TEST);
  135. Engine::client->renderTick((float) lag / NANOS_PER_TICK);
  136. // draw textured framebuffer
  137. glActiveTexture(GL_TEXTURE1);
  138. glBindTexture(GL_TEXTURE_2D, frameTexture);
  139. glActiveTexture(GL_TEXTURE2);
  140. glBindTexture(GL_TEXTURE_2D, depthTexture);
  141. glUseProgram(postProgram);
  142. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  143. glClear(GL_COLOR_BUFFER_BIT);
  144. glDisable(GL_DEPTH_TEST);
  145. glBindVertexArray(postVba);
  146. glBindBuffer(GL_ARRAY_BUFFER, postVbo);
  147. glDrawArrays(GL_TRIANGLES, 0, 6);
  148. glfwSwapBuffers(window);
  149. glfwPollEvents();
  150. }
  151. destroyPostData();
  152. glDeleteFramebuffers(1, &frameBuffer);
  153. glDeleteShader(vShader);
  154. glDeleteShader(fShader);
  155. glDeleteProgram(program);
  156. glDeleteShader(postVShader);
  157. glDeleteShader(postFShader);
  158. glDeleteProgram(postProgram);
  159. glfwDestroyWindow(window);
  160. glfwTerminate();
  161. }
  162. void Engine::stop()
  163. {
  164. glfwSetWindowShouldClose(window, 1);
  165. }
  166. GLchar* Engine::readFile(const char* name)
  167. {
  168. ifstream in;
  169. in.open(name);
  170. if(!in.fail())
  171. {
  172. int size = 128;
  173. int index = 0;
  174. GLchar* content = new GLchar[size];
  175. while(true)
  176. {
  177. GLchar c = in.get();
  178. if(in.eof())
  179. {
  180. break;
  181. }
  182. if(index >= size - 1)
  183. {
  184. GLchar* newContent = new GLchar[size * 2];
  185. memcpy(newContent, content, size);
  186. size *= 2;
  187. delete[] content;
  188. content = newContent;
  189. }
  190. content[index] = c;
  191. index++;
  192. }
  193. content[index] = '\0';
  194. index++;
  195. in.close();
  196. return content;
  197. }
  198. return nullptr;
  199. }
  200. bool Engine::checkShaderErrors(const char* name, GLuint shader)
  201. {
  202. bool returnValue = false;
  203. cout << "compiling " << name << " shader ..." << endl;
  204. GLenum error = glGetError();
  205. if(error)
  206. {
  207. cout << "error: " << glGetError() << endl;
  208. returnValue = true;
  209. }
  210. else
  211. {
  212. cout << "no error occured ..." << endl;
  213. }
  214. GLint compiled[1];
  215. glGetShaderiv(shader, GL_COMPILE_STATUS, compiled);
  216. if(compiled[0])
  217. {
  218. cout << name << " shader successfully compiled" << endl;
  219. }
  220. else
  221. {
  222. cout << name << "compiling of " << name << " failed:" << endl;
  223. GLchar buffer[512];
  224. GLsizei bufferSize = 512;
  225. GLsizei charsUsed = 0;
  226. glGetShaderInfoLog(shader, bufferSize, &charsUsed, buffer);
  227. // glGetProgramInfoLog should be null terminated ...
  228. buffer[bufferSize - 1] = '\0';
  229. cout << buffer << endl;
  230. returnValue = true;
  231. }
  232. return returnValue;
  233. }
  234. GLuint Engine::compileProgram(GLuint& vShader, GLuint& fShader, const GLchar* v, const GLchar* f)
  235. {
  236. vShader = glCreateShader(GL_VERTEX_SHADER);
  237. glShaderSource(vShader, 1, &v, nullptr);
  238. glCompileShader(vShader);
  239. if(checkShaderErrors("vertex", vShader))
  240. {
  241. return 0;
  242. }
  243. fShader = glCreateShader(GL_FRAGMENT_SHADER);
  244. glShaderSource(fShader, 1, &f, nullptr);
  245. glCompileShader(fShader);
  246. if(checkShaderErrors("fragment", fShader))
  247. {
  248. return 0;
  249. }
  250. GLuint program = glCreateProgram();
  251. glAttachShader(program, vShader);
  252. glAttachShader(program, fShader);
  253. glLinkProgram(program);
  254. cout << "linking shaders to program ..." << endl;
  255. GLenum error = glGetError();
  256. if(error)
  257. {
  258. cout << "error: " << glGetError() << endl;
  259. return 0;
  260. }
  261. else
  262. {
  263. cout << "no error occured ..." << endl;
  264. }
  265. GLint compiled[1];
  266. glGetProgramiv(program, GL_LINK_STATUS, compiled);
  267. if(compiled[0])
  268. {
  269. cout << "shaders successfully linked" << endl;
  270. }
  271. else
  272. {
  273. cout << "linking of shaders failed:" << endl;
  274. GLchar buffer[512];
  275. GLsizei bufferSize = 512;
  276. GLsizei charsUsed = 0;
  277. glGetProgramInfoLog(program, bufferSize, &charsUsed, buffer);
  278. // glGetProgramInfoLog should be null terminated ...
  279. buffer[bufferSize - 1] = '\0';
  280. cout << buffer << endl;
  281. return 0;
  282. }
  283. return program;
  284. }
  285. GLuint Engine::createProgram(const char* v, const char* f, GLuint& vShader, GLuint& fShader)
  286. {
  287. GLchar* vertex = readFile(v);
  288. if(vertex == nullptr)
  289. {
  290. cout << "cannot read " << v << endl;
  291. return 0;
  292. }
  293. GLchar* fragment = readFile(f);
  294. if(fragment == nullptr)
  295. {
  296. cout << "cannot read " << f << endl;
  297. delete[] vertex;
  298. return 0;
  299. }
  300. GLuint program = compileProgram(vShader, fShader, vertex, fragment);
  301. delete[] vertex;
  302. delete[] fragment;
  303. return program;
  304. }
  305. void Engine::onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods)
  306. {
  307. client->onKeyEvent(key, scancode, action, mods);
  308. }
  309. void Engine::onMouseClick(GLFWwindow* w, int button, int action, int mods)
  310. {
  311. client->onMouseClick(button, action, mods);
  312. }
  313. void Engine::onWindowResize(GLFWwindow* w, int width, int height)
  314. {
  315. glViewport(0, 0, width, height);
  316. Engine::width = width;
  317. Engine::height = height;
  318. updateScale();
  319. glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  320. glBindTexture(GL_TEXTURE_2D, frameTexture);
  321. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  322. glBindTexture(GL_TEXTURE_2D, 0);
  323. glBindRenderbuffer(GL_RENDERBUFFER, depthTexture);
  324. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
  325. glBindRenderbuffer(GL_RENDERBUFFER, 0);
  326. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  327. }
  328. void Engine::updateScale()
  329. {
  330. scale = 1;
  331. while(width / (scale + 1) >= 400 && height / (scale + 1) >= 300)
  332. {
  333. scale++;
  334. }
  335. }
  336. int Engine::getScale()
  337. {
  338. return scale;
  339. }
  340. int Engine::getWidth()
  341. {
  342. return width;
  343. }
  344. int Engine::getHeight()
  345. {
  346. return height;
  347. }
  348. GLint Engine::getUniformLocation(const GLchar* name)
  349. {
  350. return glGetUniformLocation(program, name);
  351. }
  352. void Engine::setMatrix(GLint location, const GLfloat* m)
  353. {
  354. glUniformMatrix4fv(location, 1, 0, m);
  355. }
  356. void Engine::setInt(GLint location, GLint i)
  357. {
  358. glUniform1i(location, i);
  359. }
  360. void Engine::setFloat(GLint location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4)
  361. {
  362. glUniform4f(location, f1, f2, f3, f4);
  363. }
  364. void Engine::printError()
  365. {
  366. GLenum error = glGetError();
  367. switch(error)
  368. {
  369. case GL_NO_ERROR:
  370. cout << "> No error has been recorded." << endl;
  371. break;
  372. case GL_INVALID_ENUM:
  373. cout << "> An unacceptable value is specified for an enumerated argument." << endl;
  374. break;
  375. case GL_INVALID_VALUE:
  376. cout << "> A numeric argument is out of range." << endl;
  377. break;
  378. case GL_INVALID_OPERATION:
  379. cout << "> The specified operation is not allowed in the current state." << endl;
  380. break;
  381. case GL_INVALID_FRAMEBUFFER_OPERATION:
  382. cout << "> The framebuffer object is not complete." << endl;
  383. break;
  384. case GL_OUT_OF_MEMORY:
  385. cout << "> There is not enough memory left to execute the command." << endl;
  386. break;
  387. case GL_STACK_UNDERFLOW:
  388. cout << "> An attempt has been made to perform an operation that would cause an internal stack to underflow." << endl;
  389. break;
  390. case GL_STACK_OVERFLOW:
  391. cout << "> An attempt has been made to perform an operation that would cause an internal stack to overflow." << endl;
  392. break;
  393. default:
  394. cout << "> Unknown OpenGL error: " << error << endl;
  395. }
  396. }
  397. void Engine::generateFramebuffer()
  398. {
  399. glGenFramebuffers(1, &frameBuffer);
  400. glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  401. glGenTextures(1, &frameTexture);
  402. glBindTexture(GL_TEXTURE_2D, frameTexture);
  403. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  404. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  405. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  406. glBindTexture(GL_TEXTURE_2D, 0);
  407. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameTexture, 0);
  408. glGenTextures(1, &depthTexture);
  409. glBindTexture(GL_TEXTURE_2D, depthTexture);
  410. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
  411. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  412. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  413. glBindTexture(GL_TEXTURE_2D, 0);
  414. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
  415. if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  416. {
  417. cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
  418. }
  419. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  420. }
  421. void Engine::generatePostData()
  422. {
  423. glGenVertexArrays(1, &postVba);
  424. glBindVertexArray(postVba);
  425. glGenBuffers(1, &postVbo);
  426. glBindBuffer(GL_ARRAY_BUFFER, postVbo);
  427. glVertexAttribPointer(0, 2, GL_FLOAT, 0, sizeof(float) * 4, (GLvoid*) 0);
  428. glEnableVertexAttribArray(0);
  429. glVertexAttribPointer(1, 2, GL_FLOAT, 0, sizeof(float) * 4, (GLvoid*) (sizeof(float) * 2));
  430. glEnableVertexAttribArray(1);
  431. float data[] =
  432. {
  433. -1.0f, 1.0f, 0.0f, 1.0f,
  434. -1.0f, -1.0f, 0.0f, 0.0f,
  435. 1.0f, -1.0f, 1.0f, 0.0f,
  436. -1.0f, 1.0f, 0.0f, 1.0f,
  437. 1.0f, -1.0f, 1.0f, 0.0f,
  438. 1.0f, 1.0f, 1.0f, 1.0f
  439. };
  440. glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 24, data, GL_STATIC_DRAW);
  441. }
  442. void Engine::destroyPostData()
  443. {
  444. glDeleteVertexArrays(1, &postVba);
  445. glDeleteBuffers(1, &postVbo);
  446. }