2016-06-28 06:00:03 +00:00
|
|
|
#include "Dengine/AssetManager.h"
|
2016-11-27 10:16:12 +00:00
|
|
|
#include "Dengine/Asteroid.h"
|
2016-07-16 13:27:52 +00:00
|
|
|
#include "Dengine/Common.h"
|
2016-07-09 10:46:04 +00:00
|
|
|
#include "Dengine/Debug.h"
|
2016-07-16 13:27:52 +00:00
|
|
|
#include "Dengine/Math.h"
|
2016-11-09 11:36:41 +00:00
|
|
|
#include "Dengine/MemoryArena.h"
|
2016-11-27 10:16:12 +00:00
|
|
|
#include "Dengine/OpenGL.h"
|
2016-07-24 12:19:25 +00:00
|
|
|
|
2016-08-16 16:21:02 +00:00
|
|
|
INTERNAL inline void processKey(KeyState *state, int action)
|
2016-08-04 08:19:02 +00:00
|
|
|
{
|
2016-08-16 16:21:02 +00:00
|
|
|
if (action == GLFW_PRESS || action == GLFW_RELEASE)
|
|
|
|
{
|
|
|
|
state->newHalfTransitionCount++;
|
|
|
|
}
|
2016-08-04 08:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
|
|
|
|
int mode)
|
2016-06-03 05:07:40 +00:00
|
|
|
{
|
2016-06-17 14:40:40 +00:00
|
|
|
GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window));
|
2016-06-05 07:54:41 +00:00
|
|
|
|
2016-12-18 08:48:14 +00:00
|
|
|
#if 1
|
2016-06-03 05:07:40 +00:00
|
|
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
|
|
|
{
|
|
|
|
glfwSetWindowShouldClose(window, GL_TRUE);
|
|
|
|
}
|
2016-12-18 08:48:14 +00:00
|
|
|
#endif
|
2016-06-04 06:36:37 +00:00
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
switch (key)
|
2016-06-04 06:36:37 +00:00
|
|
|
{
|
2016-08-04 08:19:02 +00:00
|
|
|
case GLFW_KEY_UP:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_up], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_DOWN:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_down], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_LEFT:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_left], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_RIGHT:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_right], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_LEFT_SHIFT:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_leftShift], action);
|
2016-08-10 11:52:05 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_ENTER:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_enter], action);
|
2016-08-10 11:52:05 +00:00
|
|
|
break;
|
|
|
|
case GLFW_KEY_BACKSPACE:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_backspace], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
2016-08-17 05:57:42 +00:00
|
|
|
case GLFW_KEY_TAB:
|
|
|
|
processKey(&game->input.keys[keycode_tab], action);
|
|
|
|
break;
|
2016-08-04 08:19:02 +00:00
|
|
|
default:
|
2016-08-10 11:52:05 +00:00
|
|
|
if (key >= ' ' && key <= '~')
|
|
|
|
{
|
2016-08-16 16:21:02 +00:00
|
|
|
i32 offset = 0;
|
|
|
|
if (key >= 'A' && key <= 'Z')
|
|
|
|
{
|
2016-11-25 07:03:25 +00:00
|
|
|
KeyState *leftShiftKey = &game->input.keys[keycode_leftShift];
|
|
|
|
if (!common_isSet(leftShiftKey->flags, keystateflag_ended_down))
|
2016-08-16 16:21:02 +00:00
|
|
|
offset = 'a' - 'A';
|
|
|
|
}
|
|
|
|
|
|
|
|
i32 glfwCodeToPlatformCode = (key - ' ') + offset;
|
|
|
|
processKey(&game->input.keys[glfwCodeToPlatformCode], action);
|
2016-08-10 11:52:05 +00:00
|
|
|
}
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
2016-06-04 06:36:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
INTERNAL void mouseCallback(GLFWwindow *window, double xPos, double yPos)
|
|
|
|
{
|
|
|
|
GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window));
|
|
|
|
|
|
|
|
// NOTE(doyle): x(0), y(0) of mouse starts from the top left of window
|
2016-08-04 11:17:16 +00:00
|
|
|
v2 windowSize = game->renderer.size;
|
|
|
|
f32 flipYPos = windowSize.h - CAST(f32) yPos;
|
|
|
|
game->input.mouseP = V2(CAST(f32) xPos, flipYPos);
|
2016-08-04 08:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERNAL void mouseButtonCallback(GLFWwindow *window, int button, int action,
|
|
|
|
int mods)
|
|
|
|
{
|
|
|
|
GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window));
|
|
|
|
|
2016-11-28 14:41:33 +00:00
|
|
|
switch (button)
|
2016-08-04 08:19:02 +00:00
|
|
|
{
|
|
|
|
case GLFW_MOUSE_BUTTON_LEFT:
|
2016-08-16 16:21:02 +00:00
|
|
|
processKey(&game->input.keys[keycode_mouseLeft], action);
|
2016-08-04 08:19:02 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
INTERNAL void scrollCallback(GLFWwindow *window, double xOffset, double yOffset)
|
|
|
|
{
|
|
|
|
}
|
2016-06-04 07:14:08 +00:00
|
|
|
|
2016-11-28 08:11:38 +00:00
|
|
|
INTERNAL void setGlfwWindowHints()
|
|
|
|
{
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
|
|
|
}
|
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
i32 main(void)
|
2016-06-03 05:07:40 +00:00
|
|
|
{
|
2016-11-30 10:21:28 +00:00
|
|
|
|
|
|
|
#ifdef DENGINE_DEBUG
|
|
|
|
common_unitTest();
|
|
|
|
#endif
|
|
|
|
|
2016-07-24 12:19:25 +00:00
|
|
|
/*
|
|
|
|
**************************
|
|
|
|
* INIT APPLICATION WINDOW
|
|
|
|
**************************
|
|
|
|
*/
|
2016-06-03 05:07:40 +00:00
|
|
|
glfwInit();
|
2016-11-28 08:11:38 +00:00
|
|
|
setGlfwWindowHints();
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-11-28 14:41:33 +00:00
|
|
|
OptimalArrayV2 vidList = {0};
|
|
|
|
common_optimalArrayV2Create(&vidList);
|
|
|
|
|
|
|
|
i32 windowWidth = 0;
|
|
|
|
i32 windowHeight = 0;
|
|
|
|
{ // Query Computer Video Resolutions
|
|
|
|
|
|
|
|
i32 numMonitors;
|
|
|
|
GLFWmonitor **monitors = glfwGetMonitors(&numMonitors);
|
|
|
|
GLFWmonitor *primaryMonitor = monitors[0];
|
|
|
|
|
|
|
|
i32 numModes;
|
|
|
|
const GLFWvidmode *modes = glfwGetVideoModes(primaryMonitor, &numModes);
|
|
|
|
|
|
|
|
i32 targetRefreshHz = 60;
|
|
|
|
f32 targetWindowRatio = 16.0f / 9.0f;
|
|
|
|
|
|
|
|
i32 targetPixelDensity = 1280 * 720;
|
|
|
|
i32 minPixelDensityDelta = 100000000;
|
|
|
|
|
|
|
|
printf("== Supported video modes ==\n");
|
|
|
|
for (i32 i = 0; i < numModes; i++)
|
|
|
|
{
|
|
|
|
GLFWvidmode mode = modes[i];
|
|
|
|
printf("width: %d, height: %d, rgb: %d, %d, %d, refresh: %d\n",
|
|
|
|
mode.width, mode.height, mode.redBits, mode.greenBits,
|
|
|
|
mode.blueBits, mode.refreshRate);
|
|
|
|
|
|
|
|
if (mode.refreshRate == targetRefreshHz)
|
|
|
|
{
|
|
|
|
i32 result = common_optimalArrayV2Push(
|
|
|
|
&vidList, V2i(mode.width, mode.height));
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
printf(
|
|
|
|
"common_optimalArrayV2Push(): Failed error code %d\n",
|
|
|
|
result);
|
|
|
|
ASSERT(INVALID_CODE_PATH);
|
|
|
|
}
|
|
|
|
|
|
|
|
f32 sizeRatio = (f32)mode.width / (f32)mode.height;
|
|
|
|
f32 delta = targetWindowRatio - sizeRatio;
|
|
|
|
if (delta < 0.1f)
|
|
|
|
{
|
|
|
|
i32 pixelDensity = mode.width * mode.height;
|
|
|
|
i32 densityDelta = ABS((pixelDensity - targetPixelDensity));
|
|
|
|
|
|
|
|
if (densityDelta < minPixelDensityDelta)
|
|
|
|
{
|
|
|
|
minPixelDensityDelta = densityDelta;
|
|
|
|
windowWidth = mode.width;
|
|
|
|
windowHeight = mode.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("== ==\n");
|
|
|
|
ASSERT(vidList.index > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (windowWidth == 0 || windowHeight == 0)
|
|
|
|
{
|
|
|
|
// NOTE(doyle): In this case just fallback to some value we hope is safe
|
|
|
|
windowWidth = 800;
|
|
|
|
windowHeight = 600;
|
|
|
|
}
|
2016-06-05 07:54:41 +00:00
|
|
|
|
2016-06-29 10:44:35 +00:00
|
|
|
GLFWwindow *window =
|
2016-07-17 13:45:59 +00:00
|
|
|
glfwCreateWindow(windowWidth, windowHeight, "Dengine", NULL, NULL);
|
2016-06-03 05:07:40 +00:00
|
|
|
|
|
|
|
if (!window)
|
|
|
|
{
|
2016-06-17 14:40:40 +00:00
|
|
|
printf("glfwCreateWindow() failed: Failed to create window\n");
|
2016-06-03 05:07:40 +00:00
|
|
|
glfwTerminate();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
|
2016-07-24 12:19:25 +00:00
|
|
|
/*
|
|
|
|
**************************
|
|
|
|
* INITIALISE OPENGL STATE
|
|
|
|
**************************
|
|
|
|
*/
|
2016-06-03 05:07:40 +00:00
|
|
|
/* Make GLEW use more modern technies for OGL on core profile*/
|
|
|
|
glewExperimental = GL_TRUE;
|
|
|
|
if (glewInit() != GLEW_OK)
|
|
|
|
{
|
2016-06-17 14:40:40 +00:00
|
|
|
printf("glewInit() failed: Failed to initialise GLEW\n");
|
2016-06-03 05:07:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2016-06-05 07:54:41 +00:00
|
|
|
// NOTE(doyle): glewInit() bug that sets the gl error flag after init
|
|
|
|
// regardless of success. Catch it once by calling glGetError
|
|
|
|
glGetError();
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-07-17 13:45:59 +00:00
|
|
|
i32 frameBufferWidth, frameBufferHeight;
|
|
|
|
glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight);
|
|
|
|
glViewport(0, 0, frameBufferWidth, frameBufferHeight);
|
2016-11-09 11:36:41 +00:00
|
|
|
v2 windowSize = V2i(frameBufferWidth, frameBufferHeight);
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
glfwSetKeyCallback(window, keyCallback);
|
|
|
|
glfwSetCursorPosCallback(window, mouseCallback);
|
|
|
|
glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
|
|
|
glfwSetScrollCallback(window, scrollCallback);
|
2016-06-04 07:14:08 +00:00
|
|
|
|
2016-08-04 08:19:02 +00:00
|
|
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
2016-06-09 05:49:03 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glEnable(GL_CULL_FACE);
|
2016-06-07 13:54:14 +00:00
|
|
|
|
2016-06-05 07:54:41 +00:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glCullFace(GL_BACK);
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-07-27 08:39:51 +00:00
|
|
|
/*
|
|
|
|
*******************
|
|
|
|
* INITIALISE GAME
|
|
|
|
*******************
|
|
|
|
*/
|
2016-11-28 14:41:33 +00:00
|
|
|
Memory memory = {0};
|
2016-11-25 02:17:24 +00:00
|
|
|
MemoryIndex persistentSize = MEGABYTES(32);
|
2016-11-27 06:26:23 +00:00
|
|
|
MemoryIndex transientSize = MEGABYTES(64);
|
2016-09-24 04:43:59 +00:00
|
|
|
|
|
|
|
memory.persistentSize = persistentSize;
|
|
|
|
memory.persistent = PLATFORM_MEM_ALLOC_(NULL, persistentSize, u8);
|
|
|
|
|
|
|
|
memory.transientSize = transientSize;
|
|
|
|
memory.transient = PLATFORM_MEM_ALLOC_(NULL, transientSize, u8);
|
|
|
|
|
2016-11-24 07:57:44 +00:00
|
|
|
MemoryArena_ gameArena = {0};
|
|
|
|
memory_arenaInit(&gameArena, memory.persistent, memory.persistentSize);
|
|
|
|
|
2016-11-28 14:41:33 +00:00
|
|
|
GameState *gameState = MEMORY_PUSH_STRUCT(&gameArena, GameState);
|
2016-11-24 07:57:44 +00:00
|
|
|
gameState->persistentArena = gameArena;
|
|
|
|
|
|
|
|
glfwSetWindowUserPointer(window, CAST(void *)(gameState));
|
2016-07-27 06:52:10 +00:00
|
|
|
|
2016-11-28 14:41:33 +00:00
|
|
|
{ // Load game icon
|
2016-11-28 08:11:38 +00:00
|
|
|
i32 width, height;
|
|
|
|
char *iconPath = "data/textures/Asteroids/icon.png";
|
|
|
|
u8 *pixels = asset_imageLoad(&width, &height, NULL, iconPath, FALSE);
|
|
|
|
|
|
|
|
if (pixels)
|
|
|
|
{
|
|
|
|
GLFWimage image = {width, height, pixels};
|
|
|
|
glfwSetWindowIcon(window, 1, &image);
|
|
|
|
asset_imageFree(pixels);
|
|
|
|
}
|
|
|
|
}
|
2016-11-28 14:41:33 +00:00
|
|
|
gameState->input.resolutionList = &vidList;
|
2016-11-28 08:11:38 +00:00
|
|
|
|
2016-07-24 12:19:25 +00:00
|
|
|
/*
|
|
|
|
*******************
|
2016-07-25 12:10:50 +00:00
|
|
|
* GAME LOOP
|
2016-07-24 12:19:25 +00:00
|
|
|
*******************
|
|
|
|
*/
|
2016-06-17 14:40:40 +00:00
|
|
|
f32 startTime = CAST(f32)(glfwGetTime());
|
2016-06-16 17:00:11 +00:00
|
|
|
f32 secondsElapsed = 0.0f; // Time between current frame and last frame
|
|
|
|
|
2016-06-17 06:32:59 +00:00
|
|
|
#if 0
|
2016-06-16 17:00:11 +00:00
|
|
|
// TODO(doyle): Get actual monitor refresh rate
|
2016-06-25 11:23:15 +00:00
|
|
|
f32 targetSecondsPerFrame = 1.0f / CAST(f32)(monitorRefreshHz);
|
2016-06-17 06:32:59 +00:00
|
|
|
#else
|
|
|
|
// TODO(doyle): http://gafferongames.com/game-physics/fix-your-timestep/
|
|
|
|
// NOTE(doyle): Prevent glfwSwapBuffer until a vertical retrace has
|
|
|
|
// occurred, i.e. limit framerate to monitor refresh rate
|
|
|
|
glfwSwapInterval(1);
|
|
|
|
#endif
|
2016-06-03 07:05:28 +00:00
|
|
|
|
2016-06-03 05:07:40 +00:00
|
|
|
while (!glfwWindowShouldClose(window))
|
|
|
|
{
|
|
|
|
/* Check and call events */
|
|
|
|
glfwPollEvents();
|
2016-06-05 07:54:41 +00:00
|
|
|
|
2016-06-03 05:07:40 +00:00
|
|
|
/* Rendering commands here*/
|
2016-11-28 06:47:15 +00:00
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
2016-06-03 07:05:28 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
2016-06-03 05:07:40 +00:00
|
|
|
|
2016-11-24 07:57:44 +00:00
|
|
|
asteroid_gameUpdateAndRender(gameState, &memory, windowSize,
|
2016-11-09 11:36:41 +00:00
|
|
|
secondsElapsed);
|
2016-07-24 12:19:25 +00:00
|
|
|
GL_CHECK_ERROR();
|
2016-06-03 05:07:40 +00:00
|
|
|
|
|
|
|
/* Swap the buffers */
|
|
|
|
glfwSwapBuffers(window);
|
2016-06-16 17:00:11 +00:00
|
|
|
|
2016-11-28 14:41:33 +00:00
|
|
|
f32 endTime = CAST(f32) glfwGetTime();
|
2016-06-16 17:00:11 +00:00
|
|
|
secondsElapsed = endTime - startTime;
|
|
|
|
|
2016-06-17 06:32:59 +00:00
|
|
|
#if 0
|
2016-06-16 17:00:11 +00:00
|
|
|
// TODO(doyle): Busy waiting, should sleep
|
|
|
|
while (secondsElapsed < targetSecondsPerFrame)
|
|
|
|
{
|
2016-06-25 11:23:15 +00:00
|
|
|
endTime = CAST(f32)(glfwGetTime());
|
2016-06-16 17:00:11 +00:00
|
|
|
secondsElapsed = endTime - startTime;
|
|
|
|
}
|
2016-06-17 06:32:59 +00:00
|
|
|
#endif
|
2016-06-16 17:00:11 +00:00
|
|
|
|
|
|
|
LOCAL_PERSIST f32 titleUpdateFrequencyInSeconds = 0.5f;
|
|
|
|
|
|
|
|
titleUpdateFrequencyInSeconds -= secondsElapsed;
|
|
|
|
if (titleUpdateFrequencyInSeconds <= 0)
|
|
|
|
{
|
|
|
|
f32 msPerFrame = secondsElapsed * 1000.0f;
|
|
|
|
f32 framesPerSecond = 1.0f / secondsElapsed;
|
2016-06-17 14:40:40 +00:00
|
|
|
|
2016-11-28 06:47:15 +00:00
|
|
|
i32 entityCount = 0;
|
|
|
|
GameWorldState *world =
|
|
|
|
ASTEROID_GET_STATE_DATA(gameState, GameWorldState);
|
|
|
|
|
|
|
|
if (world) entityCount = world->entityIndex;
|
|
|
|
|
2016-06-17 14:40:40 +00:00
|
|
|
char textBuffer[256];
|
2016-07-16 13:27:52 +00:00
|
|
|
snprintf(textBuffer, ARRAY_COUNT(textBuffer),
|
2016-09-23 09:36:18 +00:00
|
|
|
"Dengine | %f ms/f | %f fps | Entity Count: %d",
|
2016-11-28 06:47:15 +00:00
|
|
|
msPerFrame, framesPerSecond, entityCount);
|
2016-06-17 14:40:40 +00:00
|
|
|
|
|
|
|
glfwSetWindowTitle(window, textBuffer);
|
2016-06-16 17:00:11 +00:00
|
|
|
titleUpdateFrequencyInSeconds = 0.5f;
|
|
|
|
}
|
|
|
|
|
|
|
|
startTime = endTime;
|
2016-11-28 08:11:38 +00:00
|
|
|
|
|
|
|
StartMenuState *menuState =
|
|
|
|
ASTEROID_GET_STATE_DATA(gameState, StartMenuState);
|
|
|
|
if (menuState)
|
|
|
|
{
|
|
|
|
if (menuState->newResolutionRequest)
|
|
|
|
{
|
2016-11-28 14:41:33 +00:00
|
|
|
i32 index = menuState->resStringDisplayIndex;
|
|
|
|
windowSize = gameState->input.resolutionList->ptr[index];
|
|
|
|
|
2016-11-28 08:11:38 +00:00
|
|
|
glfwSetWindowSize(window, (i32)windowSize.w, (i32)windowSize.h);
|
2016-11-28 14:41:33 +00:00
|
|
|
glViewport(0, 0, (i32)windowSize.w, (i32)windowSize.h);
|
2016-11-28 08:11:38 +00:00
|
|
|
|
|
|
|
menuState->newResolutionRequest = FALSE;
|
|
|
|
}
|
|
|
|
}
|
2016-06-03 05:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glfwTerminate();
|
|
|
|
return 0;
|
|
|
|
}
|