aboutsummaryrefslogtreecommitdiff
#include "game.h"
#include "math/vector3f.h"
#include "math/vector2f.h"
#include "math/matrix4x4.h"
#include "input.h"
#include "util/util.h"
#include "util/util_time.h"
#include "light.h"
#include "renderer/renderer.h"
#include <SDL2/SDL.h>

/**
    TODO:   Shadows
            Texture Atlases
            Memory management

            +improve skybox
            |
            +->fog
            +->day/night

            +mouse picking (is it working perfectly?)

            +add cell shading?

            improve math package
            repair gui on renderer.c
            improve shape loading (tangent generation) (normal generation)
            improve normal mapping
**/

void LoadResources(game_t *game);
void Draw(game_t *game);
void ProcessInput(game_t *game);
void CleanUp(game_t *game);

int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);

    game_t game;
    game.gameState = RUNNING;
    game.window = Window_Create("Test", WINDOW_WIDTH, WINDOW_HEIGHT);

	GLenum err = glewInit();
    if(err != GLEW_OK) {
		fputs(glewGetErrorString(err), stderr);
        Util_FatalError("Glew could no be started!");
	}

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    SDL_GL_SetSwapInterval(1);
    // glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

    game.shaderProgram.ID = Shader_CompileShaders("resources/shaders/shader.vert",
                                                  "resources/shaders/shader.frag");

    game.terrainProgram.ID = Shader_CompileShaders("resources/shaders/terrainShader.vert",
                                                   "resources/shaders/terrainShader.frag");

    game.skyboxProgram.ID = Shader_CompileShaders("resources/shaders/skyboxShader.vert",
                                                  "resources/shaders/skyboxShader.frag");
    glUseProgram(game.shaderProgram.ID);

    Camera_Init(&game.camera);
    game.camera.projectionMatrix = mat4_perspective(60.0f, WINDOW_ASPECT_RATIO, 0.1f, 900.0f);

    LoadResources(&game);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    Time_Init();
    Time_SetMaxFramesPerSecond(60);
    while(game.gameState != EXIT)
    {
        Time_Begin();
        ProcessInput(&game);
        Player_Update(&game.player, game.terrain);
        Draw(&game);

        float FPS = Time_End();

        if( !( Time_GetCountedFrames() % (int)FPS ) )
            fprintf(stderr, "FPS: %.4f\n", FPS);
    }

    Window_Destroy(game.window);
    CleanUp(&game);
    SDL_Quit();
    return 0;
}

void CleanUp(game_t *game)
{
    Shape_Free(game->entsShape);
    Shape_Free(game->sky.cube);

    Texture_Destroy(game->entsTexture);
    Texture_Destroy(game->sky.texture);

    Texture_Destroy(game->normalMap);
    Texture_Destroy(game->defaultNormalMap);

    Terrain_Destroy(game->terrain);

    Shader_Destroy(game->shaderProgram.ID);
    Shader_Destroy(game->terrainProgram.ID);
    Shader_Destroy(game->skyboxProgram.ID);

    Render_Quit();
}

void LoadResources(game_t *game)
{
    Render_Init();
    Uint32 start = SDL_GetTicks();

    game->entsShape = Shape_LoadOBJ("resources/barrel.obj");
    game->entsTexture = Texture_Create2D("resources/textures/barrel.png");

    Player_Init(&game->player);
    game->player.entity.texture = game->entsTexture;
    game->player.entity.shape = game->entsShape;

    {
        vec3_t position = { 0.0f, 3.0f, 0.0f };
        float rotation[3] = { 0.0f, 0.0f, 0.0f };
        game->ents[0].position = position;
        game->ents[0].rotX = rotation[0];
        game->ents[0].rotY = rotation[1];
        game->ents[0].rotZ = rotation[2];
        game->ents[0].shape = game->entsShape;
        game->ents[0].texture = game->entsTexture;
    }

    {
        vec3_t position = { -400.0f, 0.0f, -400.0f };
        GLuint blendmap = Texture_Create2D("resources/textures/blendmap.png");
        TerrainTexturePack pack =
        {
            {
                Texture_Create2D("resources/textures/soil1.png"),
                Texture_Create2D("resources/textures/soil2.png"),
                Texture_Create2D("resources/textures/soil4.png"),
                Texture_Create2D("resources/textures/soil3.png"),
            }
        };
        game->terrain = Terrain_Create(800, 800, "resources/textures/heightmap.png", blendmap, &pack);
        game->terrain->position = position;
    }

    {
        game->sky.rotation = 0.0f;
        game->sky.cube = Shape_MakeSkyBox(500.0f);
        const char *paths[6] =
        {
            "resources/textures/right.png",
            "resources/textures/left.png",
            "resources/textures/top.png",
            "resources/textures/bottom.png",
            "resources/textures/back.png",
            "resources/textures/front.png"
        };
        game->sky.texture = Texture_CreateCubeMap(paths);
    }

    /* Shader Layouts */

    Shader_Layout *layout = &game->shaderProgram;
    layout->Texture = Shader_GetUniformLocation(layout->ID, "Texture");
    layout->modelToWorld = Shader_GetUniformLocation(layout->ID, "M_model");
    layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
    layout->lightPosition = Shader_GetUniformLocation(layout->ID, "lightPosition");
    layout->lightColor = Shader_GetUniformLocation(layout->ID, "lightColor");
    layout->lightAttenuation = Shader_GetUniformLocation(layout->ID, "attenuation");
    layout->Normal_Map = Shader_GetUniformLocation(layout->ID, "normalMap");

    layout = &game->terrainProgram;
    layout->modelToWorld = Shader_GetUniformLocation(layout->ID, "M_model");
    layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
    layout->lightPosition = Shader_GetUniformLocation(layout->ID, "lightPosition");
    layout->lightColor = Shader_GetUniformLocation(layout->ID, "lightColor");
    layout->lightAttenuation = Shader_GetUniformLocation(layout->ID, "attenuation");

    layout->extra0 = Shader_GetUniformLocation(layout->ID, "Texture_Background");
    layout->extra1 = Shader_GetUniformLocation(layout->ID, "Texture_R");
    layout->extra2 = Shader_GetUniformLocation(layout->ID, "Texture_G");
    layout->extra3 = Shader_GetUniformLocation(layout->ID, "Texture_B");
    layout->extra4 = Shader_GetUniformLocation(layout->ID, "Texture_BlendMap");

    layout = &game->skyboxProgram;
    layout->totalTransform = Shader_GetUniformLocation(layout->ID, "M_MVP");
    layout->Texture = Shader_GetUniformLocation(layout->ID, "cubeMap");

    game->normalMap = Texture_Create2D("resources/textures/normal_map.png");
    game->defaultNormalMap = Texture_Create2D("resources/textures/default_normal_map.png");

    fprintf(stderr, "Loading time: %u (ms)\n", SDL_GetTicks() - start);
}

void Draw(game_t *game)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /*We upload all the light vectors*/
    static const light_t diffuseLight[1] =
    {
        /* Sun Light */
        { {5.0f, 40.0f, 2.0f}, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f} },
        /* Other lights
        { {10.0f, 20.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },
        { {20.0f, 20.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },
        { {30.0f, 20.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 0.01f, 0.002f} },*/
    };

    Shader_SetUniformVec3(game->shaderProgram.ID, "World_eyePosition", (float*)&game->camera.position);
    Render_LoadLights(&game->shaderProgram, diffuseLight, 1);

    glActiveTexture(GL_TEXTURE13);
    glBindTexture(GL_TEXTURE_2D, game->normalMap);

    glUniform1i(game->shaderProgram.Normal_Map, 13);

    mat4_t viewMatrix, projectedViewMatrix;

    viewMatrix = Camera_GetModelToViewMatrix(&game->camera);
    projectedViewMatrix = mat4_mul(&game->camera.projectionMatrix, &viewMatrix);

    Render_DrawEntity(&game->shaderProgram, &projectedViewMatrix, &game->player.entity);
    Render_DrawEntity(&game->shaderProgram, &projectedViewMatrix, &game->ents[0]);

    glUseProgram(game->terrainProgram.ID);

    Shader_SetUniformVec3(game->terrainProgram.ID, "World_eyePosition", (float*)&game->camera.position);
    Render_LoadLights(&game->terrainProgram, diffuseLight, 1);

    Render_DrawTerrain(&game->terrainProgram, &projectedViewMatrix, game->terrain);

    glUseProgram(game->skyboxProgram.ID);
    Render_DrawSky(&game->skyboxProgram, &viewMatrix, &game->camera.projectionMatrix, &game->sky);

    glUseProgram(game->shaderProgram.ID);

    Window_Update(game->window);
}

void ProcessInput(game_t *game)
{
    static vec2_t mousePosition;
    SDL_Event e;
    while(SDL_PollEvent(&e))
    {
        switch(e.type)
        {
        case SDL_QUIT:
            game->gameState = EXIT;
            break;

        case SDL_MOUSEMOTION:
            mousePosition.x = (GLfloat) e.motion.x;
            mousePosition.y = (GLfloat) e.motion.y;
            Camera_MouseUpdate(&game->camera, &mousePosition);
            break;

        case SDL_KEYDOWN:
            Input_PressKey(e.key.keysym.scancode);
            break;

        case SDL_KEYUP:
            Input_ReleaseKey(e.key.keysym.scancode);
            break;
        }

        if(Input_isKeyPressed(SDL_SCANCODE_UP))
            Camera_Move_Foward(&game->camera);

        if(Input_isKeyPressed(SDL_SCANCODE_DOWN))
            Camera_Move_Backward(&game->camera);

        if(Input_isKeyPressed(SDL_SCANCODE_LEFT))
            Camera_Move_Left(&game->camera);

        if(Input_isKeyPressed(SDL_SCANCODE_RIGHT))
            Camera_Move_Right(&game->camera);

        if(Input_isKeyPressed(SDL_SCANCODE_ESCAPE))
            game->gameState = EXIT;
    }
}