123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- #include "GameEngine.h"
- #include "Key.h"
- #include "Mouse.h"
- #include <cmath>
- Clock GameEngine::tps;
- Clock GameEngine::fps;
- InitFunction GameEngine::init = nullptr;
- TickFunction GameEngine::tick = nullptr;
- RenderTickFunction GameEngine::renderTick = nullptr;
- GLuint GameEngine::vShader = 0;
- GLuint GameEngine::fShader = 0;
- GLFWwindow* GameEngine::window = nullptr;
- GLuint GameEngine::program = 0;
- int GameEngine::scale = 1;
- int GameEngine::width = 0;
- int GameEngine::height = 0;
- float GameEngine::fovY = 60;
- float GameEngine::nearClip = 0.1f;
- float GameEngine::farClip = 1000.0f;
- Matrix3D GameEngine::proj;
- Camera GameEngine::camera;
- DirectRenderer GameEngine::directRenderer;
- GLint GameEngine::unifProjMatrix = 0;
- GLint GameEngine::unifViewMatrix = 0;
- GLint GameEngine::unifUseTexture = 0;
- GLint GameEngine::unifUseColor = 0;
- GLint GameEngine::unifUseMixColor = 0;
- GLint GameEngine::unifMixColorLoc = 0;
- Camera& GameEngine::getCamera()
- {
- return camera;
- }
- DirectRenderer& GameEngine::getDirectRenderer()
- {
- return directRenderer;
- }
- void GameEngine::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);
- }
- Key::release(key);
- }
- else if(action == GLFW_PRESS)
- {
- Key::press(key);
- }
- }
- void GameEngine::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
- {*/
- Mouse::press(button);
- //}
- }
- else if(action == GLFW_RELEASE)
- {
- Mouse::release(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;
- }
- }
- }*/
- void GameEngine::onWindowResize(GLFWwindow* w, int width, int height)
- {
- glViewport(0, 0, width, height);
- GameEngine::width = width;
- GameEngine::height = height;
- updateScale();
- }
- GLchar* GameEngine::readFile(const char* name)
- {
- ifstream in;
- in.open(name);
- if(!in.fail())
- {
- int size = 128;
- int index = 0;
- GLchar* content = new GLchar[size];
-
- while(true)
- {
- GLchar c = in.get();
- if(in.eof())
- {
- break;
- }
- if(index >= size - 1)
- {
- GLchar* newContent = new GLchar[size * 2];
- memcpy(newContent, content, size);
- size *= 2;
- delete[] content;
- content = newContent;
- }
- content[index] = c;
- index++;
- }
-
- content[index] = '\0';
- index++;
-
- in.close();
- return content;
- }
- return nullptr;
- }
- bool GameEngine::checkShaderErrors(const char* name, GLuint shader)
- {
- bool returnValue = false;
-
- cout << "compiling " << name << " shader ..." << endl;
- GLenum error = glGetError();
- if(error)
- {
- cout << "error: " << glGetError() << endl;
- returnValue = true;
- }
- else
- {
- cout << "no error occured ..." << endl;
- }
-
- GLint compiled[1];
- glGetShaderiv(shader, GL_COMPILE_STATUS, compiled);
- if(compiled[0])
- {
- cout << name << " shader successfully compiled" << endl;
- }
- else
- {
- cout << name << "compiling of " << name << " failed:" << endl;
- GLchar buffer[512];
- GLsizei bufferSize = 512;
- GLsizei charsUsed = 0;
- glGetShaderInfoLog(shader, bufferSize, &charsUsed, buffer);
- // glGetProgramInfoLog should be null terminated ...
- buffer[bufferSize - 1] = '\0';
- cout << buffer << endl;
- returnValue = true;
- }
- return returnValue;
- }
- GLuint GameEngine::compileProgram(const GLchar* vertex, const GLchar* fragment)
- {
- vShader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vShader, 1, &vertex, nullptr);
- glCompileShader(vShader);
- if(checkShaderErrors("vertex", vShader))
- {
- return 0;
- }
-
- fShader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fShader, 1, &fragment, nullptr);
- glCompileShader(fShader);
- if(checkShaderErrors("fragment", fShader))
- {
- return 0;
- }
- GLuint program = glCreateProgram();
- glAttachShader(program, vShader);
- glAttachShader(program, fShader);
- glLinkProgram(program);
-
- cout << "linking shaders to program ..." << endl;
- GLenum error = glGetError();
- if(error)
- {
- cout << "error: " << glGetError() << endl;
- return 0;
- }
- else
- {
- cout << "no error occured ..." << endl;
- }
- GLint compiled[1];
- glGetProgramiv(program, GL_LINK_STATUS, compiled);
- if(compiled[0])
- {
- cout << "shaders successfully linked" << endl;
- }
- else
- {
- cout << "linking of shaders failed:" << endl;
- GLchar buffer[512];
- GLsizei bufferSize = 512;
- GLsizei charsUsed = 0;
- glGetProgramInfoLog(program, bufferSize, &charsUsed, buffer);
- // glGetProgramInfoLog should be null terminated ...
- buffer[bufferSize - 1] = '\0';
- cout << buffer << endl;
- return 0;
- }
-
- glUseProgram(program);
- return program;
- }
- GLuint GameEngine::createProgram()
- {
- GLchar* vertex = readFile("shader/vertex.vs");
- if(vertex == nullptr)
- {
- cout << "cannot read vertex.vs" << endl;
- return 0;
- }
- GLchar* fragment = readFile("shader/fragment.fs");
- if(fragment == nullptr)
- {
- cout << "cannot read fragment.fs" << endl;
- delete[] vertex;
- return 0;
- }
-
- GLuint program = compileProgram(vertex, fragment);
- delete[] vertex;
- delete[] fragment;
- return program;
- }
- void GameEngine::updateProjection()
- {
- float q = 1.0f / tanf((0.5f * fovY) * M_PI / 180.0f);
- proj.set(0, 0, (q * height) / width);
- proj.set(1, 1, q);
- proj.set(2, 2, (nearClip + farClip) / (nearClip - farClip));
- proj.set(3, 2, -1.0f);
- proj.set(2, 3, (2.0f * nearClip * farClip) / (nearClip - farClip));
- proj.set(3, 3, 0);
-
- glUniformMatrix4fv(unifProjMatrix, 1, 0, proj.getValues());
- }
- void GameEngine::updateView(Matrix3D& m)
- {
- glUniformMatrix4fv(unifViewMatrix, 1, 0, m.getValues());
- }
- void GameEngine::onInit()
- {
- Key::init();
- Mouse::init();
- init();
-
- unifProjMatrix = glGetUniformLocation(program, "projMatrix");
- unifViewMatrix = glGetUniformLocation(program, "viewMatrix");
- unifUseTexture = glGetUniformLocation(program, "useTexture");
- unifUseColor = glGetUniformLocation(program, "useColor");
- unifUseMixColor = glGetUniformLocation(program, "useMixColor");
- unifMixColorLoc = glGetUniformLocation(program, "mixColor");
-
- directRenderer.init();
- }
- void GameEngine::onTick()
- {
- tick();
- Key::tick();
- Mouse::tick();
- }
- void GameEngine::start(int width, int height, const char* name, InitFunction init, TickFunction tick, RenderTickFunction renderTick)
- {
- GameEngine::width = width;
- GameEngine::height = height;
- GameEngine::init = init;
- GameEngine::tick = tick;
- GameEngine::renderTick = renderTick;
- updateScale();
-
- if(!glfwInit())
- {
- cout << "could not initialize GLFW" << endl;
- return;
- }
- glfwDefaultWindowHints();
- glfwWindowHint(GLFW_VISIBLE, 0);
- glfwWindowHint(GLFW_RESIZABLE, 1);
- window = glfwCreateWindow(width, height, name, nullptr, nullptr);
- if(!window)
- {
- cout << "could not create window" << endl;
- glfwTerminate();
- return;
- }
- glfwSetKeyCallback(window, onKeyEvent);
- glfwSetFramebufferSizeCallback(window, onWindowResize);
- glfwSetMouseButtonCallback(window, onMouseClick);
- //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- //glfwSetCursorPosCallback(window, onMouseMove);
- glfwMakeContextCurrent(window);
- glfwSwapInterval(1);
- glfwShowWindow(window);
- GLenum err = glewInit();
- if(GLEW_OK != err)
- {
- cout << "could not initialize GLEW: " << glewGetErrorString(err) << endl;
- return;
- }
- cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
- program = createProgram();
- if(program == 0)
- {
- onTerm();
- return;
- }
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LEQUAL);
- onInit();
-
- uint64_t newTime = glfwGetTimerValue();
- uint64_t oldTime = newTime;
- uint64_t 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;
- tps.update();
- onTick();
- ticksPerFrame++;
- if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
- {
- long skip = lag / NANOS_PER_TICK;
- lag -= skip * NANOS_PER_TICK;
- if(skip > 0)
- {
- cout << "skipped " << skip << " game ticks " << lag << endl;
- }
- break;
- }
- }
- updateProjection();
- fps.update();
- renderTick((float) lag / NANOS_PER_TICK);
- glfwSwapBuffers(window);
- glfwPollEvents();
- }
-
- onTerm();
- }
- void GameEngine::onTerm()
- {
- if(vShader != 0)
- {
- glDeleteShader(vShader);
- }
- if(fShader != 0)
- {
- glDeleteShader(fShader);
- }
- if(program != 0)
- {
- glDeleteProgram(program);
- }
- glfwDestroyWindow(window);
- glfwTerminate();
- }
- void GameEngine::setTextureEnabled(bool use)
- {
- glUniform1i(unifUseTexture, use);
- }
- void GameEngine::setColorEnabled(bool use)
- {
- glUniform1i(unifUseColor, use);
- }
- void GameEngine::setMixColorEnabled(bool use)
- {
- glUniform1i(unifUseMixColor, use);
- }
- void GameEngine::setMixColor(float r, float g, float b, float a)
- {
- glUniform4f(unifMixColorLoc, r, g, b, a);
- }
- void GameEngine::setUseBlending(bool use)
- {
- if(use)
- {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glBlendEquation(GL_FUNC_ADD);
- }
- else
- {
- glDisable(GL_BLEND);
- }
- }
- void GameEngine::printError()
- {
- GLenum error = glGetError();
- switch(error)
- {
- case GL_NO_ERROR:
- cout << "> No error has been recorded." << endl;
- break;
- case GL_INVALID_ENUM:
- cout << "> An unacceptable value is specified for an enumerated argument." << endl;
- break;
- case GL_INVALID_VALUE:
- cout << "> A numeric argument is out of range." << endl;
- break;
- case GL_INVALID_OPERATION:
- cout << "> The specified operation is not allowed in the current state." << endl;
- break;
- case GL_INVALID_FRAMEBUFFER_OPERATION:
- cout << "> The framebuffer object is not complete." << endl;
- break;
- case GL_OUT_OF_MEMORY:
- cout << "> There is not enough memory left to execute the command." << endl;
- break;
- case GL_STACK_UNDERFLOW:
- cout << "> An attempt has been made to perform an operation that would cause an internal stack to underflow." << endl;
- break;
- case GL_STACK_OVERFLOW:
- cout << "> An attempt has been made to perform an operation that would cause an internal stack to overflow." << endl;
- break;
- default:
- cout << "> Unknown OpenGL error: " << error << endl;
- }
- }
- void GameEngine::stop()
- {
- glfwSetWindowShouldClose(window, 1);
- }
- void GameEngine::updateScale()
- {
- scale = 1;
- while(width / (scale + 1) >= 400 && height / (scale + 1) >= 300)
- {
- scale++;
- }
- }
- double GameEngine::getTicksPerSecond()
- {
- return tps.getUpdatesPerSecond();
- }
- double GameEngine::getFramesPerSecond()
- {
- return fps.getUpdatesPerSecond();
- }
|