#if !defined(LD_GAME_CORE_H_)
#define LD_GAME_CORE_H_

typedef struct World World;

typedef struct G_Camera G_Camera;
struct G_Camera {
	V3f x, y, z;
	V3f p;

	F32 fov;
	F32 nearp, farp;

	Mat4x4FInv proj;
};

#define TILE_SIZE 1.0

typedef enum G_EDITOR_MODE G_EDITOR_MODE;
enum G_EDITOR_MODE {
  G_EDITOR_MODE_TILE,
  G_EDITOR_MODE_PROP,
  G_EDITOR_MODE_HITBOX,
  G_EDITOR_MODE_POI,
};

typedef struct G_Editor G_Editor;
struct G_Editor {
  bool enabled;
  U32 currentLevel;
  S32 currentAsset;
  G_EDITOR_MODE mode;
  V2f cursor;
  V2f dragStart;
};

typedef struct G_State G_State;
struct G_State {
	M_Arena *arena;

	D_Context draw;
	G_Camera camera;

  G_Editor editor;
  World *world;
};

typedef U32 G_OutfitDirection;
enum {
	G_OUTFIT_DIR_FRONT = 0,
	G_OUTFIT_DIR_SIDE,
	G_OUTFIT_DIR_BACK,

	G_OUTFIT_DIR_FLIPPED = (1 << 16)
};

typedef union G_OutfitSet G_OutfitSet;
union G_OutfitSet {
	struct {
		U32 base;
		U32 eyes;
		U32 face;
		U32 hair;
		U32 hat;
		U32 shirt;
		U32 shoes;
		U32 trousers;
	};

	U32 e[8];
};

typedef struct G_Outfit G_Outfit;
struct G_Outfit {
	D_Animation state; // .id in here isn't used for drawing

	G_OutfitDirection dir;

	union {
		struct {
			G_OutfitSet front;
			G_OutfitSet side;
			G_OutfitSet back;
		};

		G_OutfitSet e[3];
	};
};

function void G_ImagesLoad(G_State *game);
function void G_PipelinesLoad(G_State *game);
function void G_AudioLoad(G_State *game);

function void G_CalculateCamera(G_Camera *camera, F32 aspect);

// Assumes 'calculate' has been called
function V3f G_CameraUnprojectAt(G_Camera *camera, V2f clip, F32 z);
function V3f G_CameraUnproject(G_Camera *camera, V2f clip);

function R3f G_CameraBounds(G_Camera *camera);

#include "world.h"
#include "aabb.h"
#include "player.h"
#include "nav.h"
#include "npc.h"

#endif  // LD_GAME_CORE_H_
