#include 
#include 
#include 
#include 
using std::cout;
using std::endl;

#include "game_jam_game.hpp"
#include "input.hpp"
#include "render.hpp"
#include "texture.hpp"
#include "audio.hpp"

GameJamGame::GameJamGame()
: state (TitleScreen)
, musicPlaying ()
{
    /**
     * Init audio and start playing background music.
     */

    snd_stream_init();
    sndoggvorbis_init();

    /**
     * Populate cache.
     */

    Reload();
}

StaticMesh GameJamGame::LoadStaticMesh(std::string const & sMeshName,
                                       std::string const & sMeshFile,
                                       std::string const & sTextureFile,
                                       uint32_t textureWidth,
                                       uint32_t textureHeight)
{
    cout << "Loading static mesh: " << sMeshName << " (" << sMeshFile << ", " << sTextureFile << ")..." << endl;

    auto it = staticMeshes.find(sMeshName);

    if(it != staticMeshes.end())
    {
        cout << sMeshName << " was cached" << endl;
        return it->second;
    }

    cout << sMeshName << " was not cached - loading." << endl;

    StaticMesh sm = StaticMesh::LoadFromFile(sMeshFile);
    sm.SetTexture(LoadTexture(sTextureFile, textureWidth, textureHeight), textureWidth, textureHeight);
    staticMeshes[sMeshName] = sm;
    return sm;
}

SkeletalMesh GameJamGame::LoadSkeletalMesh(std::string const & sMeshName,
                                           std::string const & sMeshFile,
                                           std::string const & sSkeletonFile,
                                           std::string const & sTextureFile,
                                           uint32_t textureWidth,
                                           uint32_t textureHeight)
{
    cout << "Loading skeletal mesh: " << sMeshName << " (" << sMeshFile << ", " << sSkeletonFile << ", " << sTextureFile << ")..." << endl;

    auto it = skeletalMeshes.find(sMeshName);

    if(it != skeletalMeshes.end())
    {
        cout << sMeshName << " was cached" << endl;
        return it->second;
    }

    cout << sMeshName << " was not cached - loading." << endl;

    SkeletalMesh sm = SkeletalMesh::LoadFromFile(sMeshFile, sSkeletonFile, sTextureFile, 512, 512);
    skeletalMeshes[sMeshName] = sm;
    return sm;
}

void * GameJamGame::LoadTexture(std::string const & sTextureFile,
                                uint32_t width,
                                uint32_t height)
{
    cout << "Loading texture: " << sTextureFile << "..." << endl;

    auto it = textures.find(sTextureFile);

    if(it != textures.end())
    {
        cout << sTextureFile << " was cached" << endl;
        return it->second;
    }

    cout << sTextureFile << " was not cached - loading." << endl;

    pvr_ptr_t tex;
    load_texture(&tex, 512 * 512 * 2, sTextureFile.c_str());
    textures[sTextureFile] = tex;

    cout << sTextureFile << " loaded" << endl;
    return static_cast(tex);
}

tSharedAnimation GameJamGame::LoadAnimation(std::string const & sAnimationName, std::string const & sAnimationFile)
{
    cout << "Loading animation: " << sAnimationName << endl;

    auto it = animations.find(sAnimationName);

    if(it != animations.end())
    {
        cout << sAnimationName << " was cached" << endl;
        return it->second;
    }

    cout << sAnimationFile << " was not cached - loading." << endl;

    tSharedAnimation animation = std::make_shared();
    animation->LoadFromFile(sAnimationFile);
    animations[sAnimationName] = animation;
    
    cout << sAnimationFile << " loaded" << endl;
    return animation;
}

void GameJamGame::Reload()
{
    titleScreen = LoadTexture("rd/title.png", 512, 512);

    camera = Camera(Vector(0, 6, -5));

    //skeleton = LoadSkeletalMesh("skeleton", "rd/test.ross_mesh", "rd/test.ross_skel", "rd/test.ross_anim", "rd/skeleton.png", 512, 512);

    /**
     * Populate dungeon with rooms:
     */

    dungeon.Reset();

    for(size_t i = 1; i <= 4; ++i)
    {
        std::stringstream ss;
        ss << "room" << i;

        Room room;

        Room::RoomData data;
        data.id = i;
        
        switch(data.id)
        {
            case 1:
                data.halfWidth = 3.5f;
                data.halfHeight = 2.5f;

                data.playerStarts[0] = Vector(0, 0, 0);
                data.playerStarts[1] = Vector(0, 0, 2.3f);
                break;

            case 2:
                data.halfWidth = 1.75f;
                data.halfHeight = 5.35f;

                data.playerStarts[0] = Vector(0, 0, -5.9f);
                data.playerStarts[1] = Vector(0, 0, 5.75f);
                break;

            case 3:
                data.halfWidth = 5.0f;
                data.halfHeight = 2.75f;

                data.playerStarts[0] = Vector(0, 0, -2.3f);
                data.playerStarts[1] = Vector(0, 0, 2.3f);
                break;

            case 4:
                data.halfWidth = 10.5f;
                data.halfHeight = 11.5f;

                data.playerStarts[0] = Vector(0, 0, -10.5f);
                break;

            default:
                data.halfWidth = 5.0f;
                data.halfHeight = 2.75f;

                data.playerStarts[0] = Vector(0, 0, 0);
                break;
        }

        /**
        data.underdemonMesh = LoadStaticMesh("underdemon", "rd/goblin.ross_mesh", "rd/goblin.png", 512, 512);
        data.skeletonMesh = LoadStaticMesh("skeleton", "rd/skeleton.ross_mesh", "rd/skeleton.png", 512, 512);
        data.knightMesh = LoadStaticMesh("knight", "rd/knight.ross_mesh", "rd/knight.png", 512, 512);
        **/

        data.underdemonMesh = LoadSkeletalMesh("goblin", "rd/goblin.ross_mesh", "rd/ross.ross_skel", "rd/goblin.png", 512, 512);
        data.skeletonMesh = LoadSkeletalMesh("skeleton", "rd/skeleton.ross_mesh", "rd/skeleton.ross_skel", "rd/skeleton.png", 512, 512);
        data.knightMesh = LoadSkeletalMesh("knight", "rd/knight.ross_mesh", "rd/ross.ross_skel", "rd/knight.png", 512, 512);

        data.rossMesh = LoadSkeletalMesh("ross", "rd/ross.ross_mesh", "rd/ross.ross_skel", "rd/ross.png", 512, 512);
        data.allyMesh = LoadSkeletalMesh("ally", "rd/ally.ross_mesh", "rd/ross.ross_skel", "rd/ally.png", 512, 512);
        data.doorMesh = LoadStaticMesh("door", "rd/door.ross_mesh", "rd/dungeon.png", 512, 512);
        data.boxMesh = LoadStaticMesh("box", "rd/box.ross_mesh", "rd/box.png", 256, 256);
        StaticMesh roomMesh = LoadStaticMesh(ss.str(), "rd/" + ss.str() + ".ross_mesh", "rd/dungeon.png", 512, 512);

        data.playerIdle = LoadAnimation("player_idle", "rd/ross_idle.ross_anim");
        data.playerWalk = LoadAnimation("player_walk", "rd/ross_walk.ross_anim");
        data.playerRun = LoadAnimation("player_run", "rd/ross_run.ross_anim");
        data.playerAttack = LoadAnimation("player_attack", "rd/ross_attack.ross_anim");

        data.enemyWalk = data.playerWalk;

        room.SetRoomData(data);
        room.SetStaticMesh(roomMesh);
        dungeon.AddRoom(i, room);
    }

    dungeon.SetCurrentRoom(1, 0, false);

    cout << "Finished reloading - memory usage:" << endl;
    malloc_stats();
}

GameJamGame::~GameJamGame()
{
    sndoggvorbis_stop();
    sndoggvorbis_shutdown();
    snd_stream_shutdown();
}

void GameJamGame::Process(float deltaTime, Input * pInput)
{
    /**
     * Cap delta time at 1s.
     */

    if(deltaTime > 1)
    {
        deltaTime = 1;
    }

    cont_state_t * st = pInput->pFirstControllerState;

    if(st != NULL)
    {
        static bool startPressed;

        if(st->buttons & CONT_START)
        {
            if(startPressed == false)
            {
                startPressed = true;
            }
        }
        else if(startPressed == true)
        {
            if(state == Gameplay)
            {
                state = TitleScreen;

                if(musicPlaying == false)
                {
                    sndoggvorbis_start("/rd/bgmusic.ogg", 1 /* loop */);   
                    musicPlaying = true;
                }
            }
            else if(state == TitleScreen)
            {
                Reload();
                state = Gameplay;
            }

            startPressed = false;
        }

        if(state == TitleScreen || state == Gameplay)
        {
            static bool yPressed;

            if(st->buttons & CONT_Y)
            {
                if(yPressed == false)
                {
                    yPressed = true;
                }
            }
            else if(yPressed == true)
            {
                if(musicPlaying == false)
                {
                    sndoggvorbis_start("/rd/bgmusic.ogg", 1 /* loop */);
                    musicPlaying = true;
                }
                else
                {
                    sndoggvorbis_stop();
                    musicPlaying = false;
                }

                yPressed = false;
            }
        }
    }

    if(state == Gameplay)
    {
        camera.Process(deltaTime, pInput);
        dungeon.Process(deltaTime, pInput);

        camera.SetTarget(dungeon.GetCameraFocalPoint());
        camera.SetElevation(dungeon.GetCameraElevation());
   }
}

void GameJamGame::Draw()
{
    if(state == TitleScreen)
    {
        static float const w = 640;
        static float const h = 480;

        static tQuads quads {

            Quad(Vertex(0, 0, 1, 0, 0),
                 Vertex(w, 0, 1, 1, 0),
                 Vertex(0, h, 1, 0, 1),
                 Vertex(w, h, 1, 1, 1))
        };

        render::begin_frame();
        pvr_list_begin(PVR_LIST_OP_POLY);
        render::draw_textured_quads(quads, titleScreen, 512, 512);
        pvr_list_finish();
        render::end_frame();
    }
    else if(state == Gameplay)
    {
        /**
         * Apply the current view projection matrix.
         */

        Matrix const & vp = camera.GetViewProjection();
        dungeon.SetViewProjection(vp);

        /**
         * Draw entities.
         */

        render::begin_frame();
        pvr_list_begin(PVR_LIST_OP_POLY);

        dungeon.Draw();

        pvr_list_finish();
        render::end_frame();
    }
}
    

Dundee

code.compare();

// What?

Welcome to code.compare(); - Dundee's fortnightly coding meet-up! Share and compare code with developers of all backgrounds and skill levels, have a chat, and get some fresh ideas and tips.

// Why?

Coders are continually learning, experimenting and finding better ways to build cool things.

Often this requires deep focus, but now and then it helps to get a fresh perspective and work together in a social setting.

This is why we started code.compare();!

// When?


code.compare(); runs:

  -> Every fortnight
  -> on the second and fourth Wednesday each month
  -> from 6:30pm to 8:30pm

// Where?

Dundee MakerSpace
10 Douglas Street,
Digital IT Centre,
Dundee,
DD1 5AJ,
United Kingdom

// How?

void comeAlong()
{
    coder.contact("rosskilgariff@gmail.com");

    coder.bring(laptop, project);

    coder.chatWith(otherCoders);

    coder.compare(code).with(otherCoders.code);

    coder.eat(SNACKS);

    if (coder.isFeeling(SUPPORTIVE | TALENTED))
    {
        coder.help(otherCoders);
    }

    coder.have(FUN);
}

// Pay What You Want!

code.compare(); is run by volunteers, and donations are welcome!

If you'd like to donate using paypal, use this:

...or if you prefer to donate in-person, there's always a cash box at the door. Aside from buying snacks, all donations go to our host organisation - Dundee MakerSpace.

Run by ross.codes and Dundee MakerSpace