#include "GameEngine.h" #include "Control.h" static GLuint program; static GLuint vShader; static GLuint fShader; static WindowResize windowResize; static MouseMove mouseMove; static int activeFocus = 0; static double oldMouseX = 0; static double oldMouseY = 0; static void flushOutput() { fflush(stdout); } static void onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods) { if(action == GLFW_RELEASE) { if(key == GLFW_KEY_ESCAPE) { activeFocus = 0; glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } keyRelease(key); } if(action == GLFW_PRESS) { keyPress(key); } } static void onMouseClick(GLFWwindow* w, int button, int action, int mods) { if(action == GLFW_PRESS) { if(!activeFocus) { glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); oldMouseX = 0; oldMouseY = 0; activeFocus = 1; } else { mousePress(button); } } else if(action == GLFW_RELEASE) { mouseRelease(button); } } static void onMouseMove(GLFWwindow* w, double x, double y) { if(activeFocus) { if(oldMouseX == 0 && oldMouseY == 0) { oldMouseX = x; oldMouseY = y; } else { mouseMove(x - oldMouseX, y - oldMouseY); oldMouseX = x; oldMouseY = y; } } } static void onWindowResize(GLFWwindow* w, int width, int height) { glViewport(0, 0, width, height); windowResize(width, height); } static GLchar* readFile(char* name) { FILE* file = fopen(name, "r"); if(file != NULL) { int size = 128; int index = 0; GLchar* content = malloc(sizeof(GLchar) * size); while(1) { int c = fgetc(file); if(c == EOF) { break; } if(index >= size) { size *= 2; content = realloc(content, size); } content[index] = c; index++; } if(index >= size) { size++; content = realloc(content, size); } content[index] = '\0'; index++; fclose(file); return content; } return NULL; } int checkShaderErrors(char* name, GLuint shader) { int returnValue = 0; printf("compiling %s shader ...\n", name); GLenum error = glGetError(); if(error) { fprintf(stderr, "error: %u\n", glGetError()); returnValue = 1; } else { printf("no error occured ...\n"); } GLint compiled[1]; glGetShaderiv(shader, GL_COMPILE_STATUS, compiled); if(compiled[0]) { printf("%s shader successfully compiled\n", name); } else { fprintf(stderr, "compiling of %s shader failed:\n", name); GLchar buffer[512]; GLsizei bufferSize = 512; GLsizei charsUsed = 0; glGetShaderInfoLog(shader, bufferSize, &charsUsed, buffer); buffer[bufferSize - 1] = '\0'; fprintf(stderr, "%s\n", buffer); returnValue = 1; } return returnValue; } static GLuint compileProgram(const GLchar* vertex, const GLchar* fragment) { vShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vShader, 1, &vertex, NULL); glCompileShader(vShader); if(checkShaderErrors("vertex", vShader)) { return 0; } fShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fShader, 1, &fragment, NULL); glCompileShader(fShader); if(checkShaderErrors("fragment", fShader)) { return 0; } GLuint program = glCreateProgram(); glAttachShader(program, vShader); glAttachShader(program, fShader); glLinkProgram(program); printf("linking shaders to program ...\n"); GLenum error = glGetError(); if(error) { fprintf(stderr, "error: %u\n", glGetError()); return 0; } else { printf("no error occured ...\n"); } GLint compiled[1]; glGetProgramiv(program, GL_LINK_STATUS, compiled); if(compiled[0]) { printf("shaders successfully linked\n"); } else { fprintf(stderr, "linking of shaders failed:\n"); GLchar buffer[512]; GLsizei bufferSize = 512; GLsizei charsUsed = 0; glGetProgramInfoLog(program, bufferSize, &charsUsed, buffer); buffer[bufferSize - 1] = '\0'; fprintf(stderr, "%s\n", buffer); return 0; } glUseProgram(program); return program; } static GLuint createProgram() { GLchar* vertex = readFile("shader/vertex.vs"); if(vertex == NULL) { fprintf(stderr, "cannot read vertex.vs\n"); return 0; } GLchar* fragment = readFile("shader/fragment.fs"); if(fragment == NULL) { fprintf(stderr, "cannot read fragment.fs\n"); free(vertex); return 0; } GLuint program = compileProgram(vertex, fragment); flushOutput(); free(vertex); free(fragment); return program; } static void onTerm(GLFWwindow* window) { glfwDestroyWindow(window); glfwTerminate(); } int startGame(char* name, InitFunction init, TickFunction tick, RenderTickFunction renderTick, WindowResize inWindowResize, MouseMove move) { if(!glfwInit()) { fprintf(stderr, "could not initialize GLFW"); return 1; } windowResize = inWindowResize; mouseMove = move; glfwDefaultWindowHints(); glfwWindowHint(GLFW_VISIBLE, 0); glfwWindowHint(GLFW_RESIZABLE, 1); GLFWwindow* window = glfwCreateWindow(640, 480, name, NULL, NULL); if(!window) { fprintf(stderr, "could not create window"); glfwTerminate(); return 1; } glfwSetKeyCallback(window, onKeyEvent); glfwSetFramebufferSizeCallback(window, onWindowResize); glfwSetMouseButtonCallback(window, onMouseClick); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); activeFocus = 1; glfwSetCursorPosCallback(window, onMouseMove); glfwMakeContextCurrent(window); glfwSwapInterval(1); glfwShowWindow(window); GLenum err = glewInit(); if(GLEW_OK != err) { fprintf(stderr, "Could not initialize GLEW: %s\n", glewGetErrorString(err)); return 1; } printf("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); program = createProgram(); if(program == 0) { onTerm(window); return 1; } // glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); init(program); // printf("%lu\n", glfwGetTimerFrequency()); // printf("%lu\n", glfwGetTimerValue()); // printf("%lu\n", glfwGetTimerValue()); long newTime = glfwGetTimerValue(); long oldTime = newTime; long lag = 0; while(!glfwWindowShouldClose(window)) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); oldTime = newTime; newTime = glfwGetTimerValue(); lag += newTime - oldTime; int ticksPerFrame = 0; while(lag >= NANOS_PER_TICK) { lag -= NANOS_PER_TICK; controlTick(); tick(program); ticksPerFrame++; if(ticksPerFrame >= MAX_TICKS_PER_FRAME) { long skip = lag / NANOS_PER_TICK; lag -= skip * NANOS_PER_TICK; if(skip > 0) { printf("skipped %ld game ticks %ld\n", skip, lag); } break; } } renderTick(program, (float)lag / NANOS_PER_TICK); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteShader(vShader); glDeleteShader(fShader); glDeleteProgram(program); onTerm(window); return 0; } GLuint getProgram() { return program; }