GameEngine.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #include "GameEngine.h"
  2. #include "Control.h"
  3. static GLuint program;
  4. static GLuint vShader;
  5. static GLuint fShader;
  6. static WindowResize windowResize;
  7. static MouseMove mouseMove;
  8. static int activeFocus = 0;
  9. static double oldMouseX = 0;
  10. static double oldMouseY = 0;
  11. static void flushOutput() {
  12. fflush(stdout);
  13. }
  14. static void onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods) {
  15. if(action == GLFW_RELEASE) {
  16. if(key == GLFW_KEY_ESCAPE) {
  17. activeFocus = 0;
  18. glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  19. }
  20. keyRelease(key);
  21. }
  22. if(action == GLFW_PRESS) {
  23. keyPress(key);
  24. }
  25. }
  26. static void onMouseClick(GLFWwindow* w, int button, int action, int mods) {
  27. if(action == GLFW_PRESS) {
  28. if(!activeFocus) {
  29. glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  30. oldMouseX = 0;
  31. oldMouseY = 0;
  32. activeFocus = 1;
  33. } else {
  34. mousePress(button);
  35. }
  36. } else if(action == GLFW_RELEASE) {
  37. mouseRelease(button);
  38. }
  39. }
  40. static void onMouseMove(GLFWwindow* w, double x, double y) {
  41. if(activeFocus) {
  42. if(oldMouseX == 0 && oldMouseY == 0) {
  43. oldMouseX = x;
  44. oldMouseY = y;
  45. } else {
  46. mouseMove(x - oldMouseX, y - oldMouseY);
  47. oldMouseX = x;
  48. oldMouseY = y;
  49. }
  50. }
  51. }
  52. static void onWindowResize(GLFWwindow* w, int width, int height) {
  53. glViewport(0, 0, width, height);
  54. windowResize(width, height);
  55. }
  56. static GLchar* readFile(char* name) {
  57. FILE* file = fopen(name, "r");
  58. if(file != NULL) {
  59. int size = 128;
  60. int index = 0;
  61. GLchar* content = malloc(sizeof(GLchar) * size);
  62. while(1) {
  63. int c = fgetc(file);
  64. if(c == EOF) {
  65. break;
  66. }
  67. if(index >= size) {
  68. size *= 2;
  69. content = realloc(content, size);
  70. }
  71. content[index] = c;
  72. index++;
  73. }
  74. if(index >= size) {
  75. size++;
  76. content = realloc(content, size);
  77. }
  78. content[index] = '\0';
  79. index++;
  80. fclose(file);
  81. return content;
  82. }
  83. return NULL;
  84. }
  85. int checkShaderErrors(char* name, GLuint shader) {
  86. int returnValue = 0;
  87. printf("compiling %s shader ...\n", name);
  88. GLenum error = glGetError();
  89. if(error) {
  90. fprintf(stderr, "error: %u\n", glGetError());
  91. returnValue = 1;
  92. } else {
  93. printf("no error occured ...\n");
  94. }
  95. GLint compiled[1];
  96. glGetShaderiv(shader, GL_COMPILE_STATUS, compiled);
  97. if(compiled[0]) {
  98. printf("%s shader successfully compiled\n", name);
  99. } else {
  100. fprintf(stderr, "compiling of %s shader failed:\n", name);
  101. GLchar buffer[512];
  102. GLsizei bufferSize = 512;
  103. GLsizei charsUsed = 0;
  104. glGetShaderInfoLog(shader, bufferSize, &charsUsed, buffer);
  105. buffer[bufferSize - 1] = '\0';
  106. fprintf(stderr, "%s\n", buffer);
  107. returnValue = 1;
  108. }
  109. return returnValue;
  110. }
  111. static GLuint compileProgram(const GLchar* vertex, const GLchar* fragment) {
  112. vShader = glCreateShader(GL_VERTEX_SHADER);
  113. glShaderSource(vShader, 1, &vertex, NULL);
  114. glCompileShader(vShader);
  115. if(checkShaderErrors("vertex", vShader)) {
  116. return 0;
  117. }
  118. fShader = glCreateShader(GL_FRAGMENT_SHADER);
  119. glShaderSource(fShader, 1, &fragment, NULL);
  120. glCompileShader(fShader);
  121. if(checkShaderErrors("fragment", fShader)) {
  122. return 0;
  123. }
  124. GLuint program = glCreateProgram();
  125. glAttachShader(program, vShader);
  126. glAttachShader(program, fShader);
  127. glLinkProgram(program);
  128. printf("linking shaders to program ...\n");
  129. GLenum error = glGetError();
  130. if(error) {
  131. fprintf(stderr, "error: %u\n", glGetError());
  132. return 0;
  133. } else {
  134. printf("no error occured ...\n");
  135. }
  136. GLint compiled[1];
  137. glGetProgramiv(program, GL_LINK_STATUS, compiled);
  138. if(compiled[0]) {
  139. printf("shaders successfully linked\n");
  140. } else {
  141. fprintf(stderr, "linking of shaders failed:\n");
  142. GLchar buffer[512];
  143. GLsizei bufferSize = 512;
  144. GLsizei charsUsed = 0;
  145. glGetProgramInfoLog(program, bufferSize, &charsUsed, buffer);
  146. buffer[bufferSize - 1] = '\0';
  147. fprintf(stderr, "%s\n", buffer);
  148. return 0;
  149. }
  150. glUseProgram(program);
  151. return program;
  152. }
  153. static GLuint createProgram() {
  154. GLchar* vertex = readFile("shader/vertex.vs");
  155. if(vertex == NULL) {
  156. fprintf(stderr, "cannot read vertex.vs\n");
  157. return 0;
  158. }
  159. GLchar* fragment = readFile("shader/fragment.fs");
  160. if(fragment == NULL) {
  161. fprintf(stderr, "cannot read fragment.fs\n");
  162. free(vertex);
  163. return 0;
  164. }
  165. GLuint program = compileProgram(vertex, fragment);
  166. flushOutput();
  167. free(vertex);
  168. free(fragment);
  169. return program;
  170. }
  171. static void onTerm(GLFWwindow* window) {
  172. glfwDestroyWindow(window);
  173. glfwTerminate();
  174. }
  175. int startGame(char* name, InitFunction init, TickFunction tick, RenderTickFunction renderTick,
  176. WindowResize inWindowResize, MouseMove move) {
  177. if(!glfwInit()) {
  178. fprintf(stderr, "could not initialize GLFW");
  179. return 1;
  180. }
  181. windowResize = inWindowResize;
  182. mouseMove = move;
  183. glfwDefaultWindowHints();
  184. glfwWindowHint(GLFW_VISIBLE, 0);
  185. glfwWindowHint(GLFW_RESIZABLE, 1);
  186. GLFWwindow* window = glfwCreateWindow(640, 480, name, NULL, NULL);
  187. if(!window) {
  188. fprintf(stderr, "could not create window");
  189. glfwTerminate();
  190. return 1;
  191. }
  192. glfwSetKeyCallback(window, onKeyEvent);
  193. glfwSetFramebufferSizeCallback(window, onWindowResize);
  194. glfwSetMouseButtonCallback(window, onMouseClick);
  195. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  196. activeFocus = 1;
  197. glfwSetCursorPosCallback(window, onMouseMove);
  198. glfwMakeContextCurrent(window);
  199. glfwSwapInterval(1);
  200. glfwShowWindow(window);
  201. GLenum err = glewInit();
  202. if(GLEW_OK != err) {
  203. fprintf(stderr, "Could not initialize GLEW: %s\n", glewGetErrorString(err));
  204. return 1;
  205. }
  206. printf("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
  207. program = createProgram();
  208. if(program == 0) {
  209. onTerm(window);
  210. return 1;
  211. }
  212. // glEnable(GL_CULL_FACE);
  213. glEnable(GL_DEPTH_TEST);
  214. glDepthFunc(GL_LEQUAL);
  215. init(program);
  216. // printf("%lu\n", glfwGetTimerFrequency());
  217. // printf("%lu\n", glfwGetTimerValue());
  218. // printf("%lu\n", glfwGetTimerValue());
  219. long newTime = glfwGetTimerValue();
  220. long oldTime = newTime;
  221. long lag = 0;
  222. while(!glfwWindowShouldClose(window)) {
  223. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  224. oldTime = newTime;
  225. newTime = glfwGetTimerValue();
  226. lag += newTime - oldTime;
  227. int ticksPerFrame = 0;
  228. while(lag >= NANOS_PER_TICK) {
  229. lag -= NANOS_PER_TICK;
  230. controlTick();
  231. tick(program);
  232. ticksPerFrame++;
  233. if(ticksPerFrame >= MAX_TICKS_PER_FRAME) {
  234. long skip = lag / NANOS_PER_TICK;
  235. lag -= skip * NANOS_PER_TICK;
  236. if(skip > 0) {
  237. printf("skipped %ld game ticks %ld\n", skip, lag);
  238. }
  239. break;
  240. }
  241. }
  242. renderTick(program, (float)lag / NANOS_PER_TICK);
  243. glfwSwapBuffers(window);
  244. glfwPollEvents();
  245. }
  246. glDeleteShader(vShader);
  247. glDeleteShader(fShader);
  248. glDeleteProgram(program);
  249. onTerm(window);
  250. return 0;
  251. }
  252. GLuint getProgram() {
  253. return program;
  254. }