You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

422 lines
11 KiB

// Some defaults for the game layout
#define DEBUG_DRAW true
#define VIEWPORT_WIDTH 1920
#define VIEWPORT_HEIGHT 1080
#define CONE_ANGLE 30
#define VSYNC_ENABLED true
#define DATA_DIR "../data"
#define DEFAULT_SCENE_FILE "hashmap_scene.json"
#define SCENE_SCHEMA_FILE "scene_schema.json"
#define HEXMAP_SCHEMA_FILE "hexmap_schema.json"
#define MAX_ENTITIES 1000
#include <vector>
#if defined(_WIN32)
#include <windows.h>
#include <Winuser.h>
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
// TODO: replace aixlog with simpler logging
#if defined(_WIN32)
#pragma warning(push)
#pragma warning(disable : 4003)
#endif
#include "aixlog.hpp"
#include "gooey.h"
#include "hexgame.h"
#include "mesh.h"
#include "platform_wait_for_vblank.h"
#include "renderer.h"
#include "scene_loader.h"
#include "util.h"
using std::vector;
static game_state* g_game_state;
static render_state* g_render_state;
static vector<Point> g_polygon_select_vertices = {Point(), Point(), Point(), Point()};
bool
loadSceneFromJson(game_state* s, render_state* rs)
{
bool ret = true;
slSceneDoc* sd = slLoadFile(DATA_DIR, DEFAULT_SCENE_FILE, SCENE_SCHEMA_FILE);
if (sd != nullptr) {
game_state* gs = g_game_state;
render_state* rs = g_render_state;
if (!slParseEntities(sd, gs->entities, gs->entity_count, MAX_ENTITIES, DATA_DIR)) {
LOG(ERROR) << "Error loading Entities, exiting\n";
ret = false;
}
slParseCamera(sd, rs->cam);
slParseHexGrid(sd, gs->grid, rs->palette_image);
if (slCreateHexRenderGroups(gs->grid, rs)) {
if (gs->grid.gridT == HASH_MAP) {
if (!slParseGridHashMap(gs->grid, DATA_DIR, HEXMAP_SCHEMA_FILE))
ret = false;
}
if (!hgInit(gs->grid, rs->filled_hex_render_group, rs->hex_line_render_group))
ret = false;
} else {
LOG(ERROR) << "Error creating hexgrid render groups\n";
ret = false;
}
if (!slParseLights(sd, rs->lights, rs->num_lights, rs->max_lights)) {
LOG(ERROR) << "Error loading lights, exiting\n";
ret = false;
}
} else {
ret = false;
}
slFreeSceneDoc(sd);
return ret;
}
bool
init()
{
// init global game state
g_game_state = UTIL_ALLOC(1, game_state);
g_game_state->entities = UTIL_ALLOC(MAX_ENTITIES, Entity);
// TODO: I think this is necessary because we're using calloc to initialize gamestate
// which contains the hashtable.
g_game_state->grid.hex_map = std::unordered_map<Hex, hex_info, hex_hashfunc>();
// NOTE: testing hex_add
g_game_state->grid.draw_mode = NONE;
// TODO: maybe add this as an option to scene json?
g_game_state->grid.normal = v3f(0.f, 0.f, 1.f);
// init global render state
g_render_state = UTIL_ALLOC(1, render_state);
g_render_state->is_debug_draw = DEBUG_DRAW;
g_render_state->viewport_dims = v2i(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
LOG(ERROR) << "Error, SDL_Init: " << SDL_GetError() << "\n";
return false;
}
if (!renInit(g_render_state)) {
LOG(ERROR) << "Unable to initialize graphics, exiting\n";
return false;
}
if (!gooInit(g_render_state->handles, g_render_state->viewport_dims)) {
LOG(ERROR) << "Fooey, No Gooey!\n";
return false;
}
if (!meInitAssimp()) {
LOG(ERROR) << "Error initializing assimp\n";
return false;
}
if (!loadSceneFromJson(g_game_state, g_render_state)) {
LOG(ERROR) << "Error loading scene\n";
return false;
}
if (!renCreateScene(g_render_state, g_game_state->entities, g_game_state->entity_count))
{
LOG(ERROR) << "Error in vertex data, exiting\n";
return false;
}
#if defined(_WIN32)
LOG(DEBUG) << "TODO: Test SDL_Delay frame timer in win32\n";
if (!platform_init(g_render_state->handles.window)) {
LOG(ERROR) << "Couldn't get SDL platform info, exiting\n";
return false;
}
#endif
return true;
}
v2i
mapMouseToViewport(int32 x, int32 y)
{
v2i coords;
coords.x = x;
coords.y = g_render_state->viewport_dims.y - y;
return coords;
}
void
startDrawHelper(int32 x, int32 y)
{
hgResetHexes(g_game_state->grid);
v2i dims = g_render_state->viewport_dims;
v2f v = cameraUnproject(g_render_state->cam, x, y, dims.x, dims.y);
hex_info *hex = hgGetSingleHex(g_game_state->grid, v.x, v.y);
if (hex) {
hex->selected = true;
g_game_state->grid.start_hex = g_game_state->grid.current_hex = hex;
}
}
void
handleMouseDown(SDL_MouseButtonEvent &e)
{
game_state* gs = g_game_state;
render_state* rs = g_render_state;
v2i coords = mapMouseToViewport(e.x, e.y);
v2i dims = rs->viewport_dims;
switch (gs->grid.draw_mode) {
case FILL:
startDrawHelper(coords.x, coords.y);
break;
case LINE:
startDrawHelper(coords.x, coords.y);
break;
case CONE_FILL:
startDrawHelper(coords.x, coords.y);
break;
case PATHFINDING:
break;
case ADD_HEXES: {
v3f ray = cameraCreateRay(rs->cam, coords, dims);
v3f xsect;
if (cameraIntersectPlane(rs->cam, ray, gs->grid.position, gs->grid.normal, xsect))
hgAddHex(gs->grid, xsect, rs->filled_hex_render_group, rs->hex_line_render_group);
break;
}
case REMOVE_HEXES: {
v3f ray = cameraCreateRay(rs->cam, coords, dims);
v3f xsect;
if (cameraIntersectPlane(rs->cam, ray, gs->grid.position, gs->grid.normal, xsect))
hgRemoveHex(gs->grid, xsect, rs->filled_hex_render_group, rs->hex_line_render_group);
break;
}
case NONE:
default:
v2f v = cameraUnproject(rs->cam, coords.x, coords.y, dims.x, dims.y);
hex_info *hxi = hgGetSingleHex(gs->grid, v.x, v.y);
if (hxi) {
hxi->selected = !hxi->selected;
gs->grid.start_hex = gs->grid.current_hex = hxi;
}
break;
}
}
void
handleMouseMove(SDL_MouseMotionEvent &e)
{
game_state* gs = g_game_state;
render_state* rs = g_render_state;
v2i coords = mapMouseToViewport(e.x, e.y);
v2i dims = rs->viewport_dims;
v2f v = cameraUnproject(rs->cam, coords.x, coords.y, dims.x, dims.y);
switch (gs->grid.draw_mode) {
case FILL:
hgUpdateHexFill(gs->grid, v.x, v.y);
break;
case LINE:
hgUpdateHexLineDraw(gs->grid, v.x, v.y);
break;
case CONE_FILL:
hgUpdateHexConeFill(gs->grid, v.x, v.y, CONE_ANGLE, g_polygon_select_vertices);
break;
case PATHFINDING:
break;
case ADD_HEXES: {
if (gs->grid.is_selecting) {
v3f ray = cameraCreateRay(rs->cam, coords, dims);
v3f xsect;
if (cameraIntersectPlane(rs->cam, ray, gs->grid.position, gs->grid.normal, xsect))
hgAddHex(gs->grid, xsect, rs->filled_hex_render_group, rs->hex_line_render_group);
}
break;
}
case REMOVE_HEXES: {
if (gs->grid.is_selecting) {
v3f ray = cameraCreateRay(rs->cam, coords, dims);
v3f xsect;
if (cameraIntersectPlane(rs->cam, ray, gs->grid.position, gs->grid.normal, xsect))
hgRemoveHex(gs->grid, xsect, rs->filled_hex_render_group, rs->hex_line_render_group);
}
break;
}
case NONE:
default:
break;
}
}
bool
processSDLEvents()
{
SDL_Event e;
bool run = true;
while (SDL_PollEvent(&e)) {
// let gooey have event
// TODO: need to check for both io.WantCaptureKeyboard and io.WantCaptureMouse
// to fix bug with 'ESC' not passing through while in imgui
bool gooey_wants = gooProcessEvent(e);
game_state* gs = g_game_state;
switch (e.type) {
case SDL_QUIT:
run = false;
break;
case SDL_KEYDOWN:
switch (e.key.keysym.sym) {
case SDLK_ESCAPE: run = false; break;
case SDLK_e: gs->is_moveforward = true; break;
case SDLK_s: gs->is_moveleft = true; break;
case SDLK_d: gs->is_movebackward = true; break;
case SDLK_f: gs->is_moveright = true; break;
case SDLK_SPACE: gs->is_moveup = true; break;
case SDLK_c: gs->is_movedown = true; break;
case SDLK_r: gs->is_rotateCW = true; break;
case SDLK_w: gs->is_rotateCCW = true; break;
}
break;
case SDL_KEYUP:
switch (e.key.keysym.sym) {
case SDLK_e: gs->is_moveforward = false; break;
case SDLK_s: gs->is_moveleft = false; break;
case SDLK_d: gs->is_movebackward = false; break;
case SDLK_f: gs->is_moveright = false; break;
case SDLK_SPACE: gs->is_moveup = false; break;
case SDLK_c: gs->is_movedown = false; break;
case SDLK_r: gs->is_rotateCW = false; break;
case SDLK_w: gs->is_rotateCCW = false; break;
}
break;
case SDL_MOUSEBUTTONDOWN:
if (!gooey_wants) {
if (e.button.button == SDL_BUTTON_LEFT) {
gs->grid.is_selecting = true;
handleMouseDown(e.button);
} else if (e.button.button == SDL_BUTTON_RIGHT) {
gs->is_camera_rotate = true;
}
}
break;
case SDL_MOUSEBUTTONUP:
if (!gooey_wants) {
if (e.button.button == SDL_BUTTON_LEFT)
gs->grid.is_selecting = false;
else if (e.button.button == SDL_BUTTON_RIGHT)
gs->is_camera_rotate = false;
}
break;
case SDL_MOUSEMOTION:
if (!gooey_wants && gs->grid.is_selecting)
handleMouseMove(e.motion);
else if(!gooey_wants && gs->is_camera_rotate)
cameraRotate(g_render_state->cam, e.motion.xrel, e.motion.yrel);
break;
default:
break;
}
}
return run;
}
bool
cleanUp(SDL_Handles &handles)
{
gooFree();
renFreeBuffers(g_render_state); // renderer.h
for (SDL_Surface *surface : handles.texSurfaces)
SDL_FreeSurface(surface);
meShutdownAssimp(); // mesh.h
SDL_GL_DeleteContext(handles.glContext);
SDL_DestroyWindow(handles.window);
SDL_Quit();
game_state* gs = g_game_state;
for (uint i = 0; i < gs->entity_count; i++) {
meFreeMeshGroup(gs->entities[i].mesh_group);
rgFree(gs->entities[i].ren_group);
}
utilSafeFree(gs->entities);
utilSafeFree(g_render_state);
utilSafeFree(g_game_state);
return true;
}
#if defined(_WIN32)
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
#else
int main(int argc, char* argv[])
#endif
{
#if defined(_WIN32)
AixLog::Log::init<AixLog::SinkOutputDebugString>(AixLog::Severity::trace, AixLog::Type::normal);
#else
AixLog::Log::init<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::normal);
#endif
LOG(INFO) << "Application started\n";
if (!init()) {
LOG(ERROR) << "failed init, exiting\n";
return -1;
}
// main loop
const uint TARGET_FPS = 60;
const uint FRAME_DELAY = 1000 / TARGET_FPS;
uint frameStart, frameTime;
while (processSDLEvents()) {
frameStart = SDL_GetTicks();
game_state* gs = g_game_state;
render_state* rs = g_render_state;
cameraMove(rs->cam, gs->is_moveup, gs->is_moveleft, gs->is_movedown, gs->is_moveright,
gs->is_moveforward, gs->is_movebackward);
renRenderFrame(rs, gs->grid, gs->entities, gs->entity_count);
if (rs->is_debug_draw && gs->grid.draw_mode == CONE_FILL)
renRenderDebug(rs, g_polygon_select_vertices);
gooRender(gs, rs);
SDL_GL_SwapWindow(rs->handles.window);
// TODO: test SDL_Delay on Win32
//platform_wait_for_vblank(VSYNC_ENABLED);
frameTime = SDL_GetTicks() - frameStart;
if (FRAME_DELAY > frameTime)
SDL_Delay(FRAME_DELAY - frameTime);
}
cleanUp(g_render_state->handles);
LOG(INFO) << "Application exiting\n";
return 0;
}