File Camera2D.c

File List > engine > src > gameframework > layers > Game2D > Camera2D.c

Go to the documentation of this file

#include "Camera2D.h"
#include "Game2DLayer.h"
#include "AssertLib.h"

void GetViewportWorldspaceTLBR(vec2 outTL, vec2 outBR, struct Transform2D* pCam, int windowW, int windowH)
{
    outTL[0] = pCam->position[0];
    outTL[1] = pCam->position[1];

    outTL[0] = -outTL[0];
    outTL[1] = -outTL[1];

    outBR[0] = outTL[0] + windowW / pCam->scale[0];
    outBR[1] = outTL[1] + windowH / pCam->scale[0];

}

void CenterCameraAt(float worldspaceX, float worldspaceY, struct Transform2D* pCam, int winWidth, int winHeight)
{
    vec2 tl, br;
    GetViewportWorldspaceTLBR(tl, br, pCam, winWidth, winHeight);
    pCam->position[0] = -(worldspaceX - (br[0] - tl[0]) / 2.0f);
    pCam->position[1] = -(worldspaceY - (br[1] - tl[1]) / 2.0f);
}

void GetCamWorldspaceCenter(struct Transform2D* pCam, int winWidth, int winHeight, vec2 outCenter)
{
    vec2 tl, br;
    vec2 add;
    GetViewportWorldspaceTLBR(tl, br, pCam, winWidth, winHeight);
    add[0] = (br[0] - tl[0]) / 2.0f;
    add[1] = (br[1] - tl[1]) / 2.0f;
    glm_vec2_add(tl, add, outCenter);
}

void GetWorldspacePos(int screenPosX, int screenPosY, int screenW, int screenH, struct Transform2D* pCam, vec2 outWorldspace)
{
    vec2 tl, br;
    GetViewportWorldspaceTLBR(tl, br, pCam, screenW, screenH);
    float fX = (float)screenPosX / (float)screenW;
    float fY = (float)screenPosY / (float)screenH;
    outWorldspace[0] = tl[0] + fX * (br[0] - tl[0]);
    outWorldspace[1] = tl[1] + fY * (br[1] - tl[1]);
}

void ScreenSpaceToWorldSpaceTransVector(vec2 screenSpaceTranslateVector, int screenW, int screenH, struct Transform2D* pCam, vec2 outWorldspace)
{
    vec2 tl, br;
    GetViewportWorldspaceTLBR(tl, br, pCam, screenW, screenH);
    vec2 norm = {
        screenSpaceTranslateVector[0] / screenW,
        screenSpaceTranslateVector[1] / screenH
    };
    outWorldspace[0] = norm[0] * (br[0] - tl[0]);
    outWorldspace[1] = norm[1] * (br[1] - tl[1]);
}

void ClampCameraToTileLayer(struct GameLayer2DData* pGameLayerData, int tileLayerNum)
{
    EASSERT(tileLayerNum >= 0 && tileLayerNum < VectorSize(pGameLayerData->tilemap.layers));
    pGameLayerData->cameraClampedToTilemapLayer = tileLayerNum;
}

void UpdateCameraClamp(struct GameLayer2DData* pGameLayerData)
{

    if(pGameLayerData->cameraClampedToTilemapLayer < 0)
    {
        return;
    }
    struct Transform2D* pCam = &pGameLayerData->camera;
    struct TileMapLayer* pTilemapLayer = &pGameLayerData->tilemap.layers[pGameLayerData->cameraClampedToTilemapLayer];
    vec2 tl = {
        pTilemapLayer->transform.position[0],
        pTilemapLayer->transform.position[1]
    };
    vec2 dims = {
        pTilemapLayer->widthTiles * pTilemapLayer->tileWidthPx,
        pTilemapLayer->heightTiles * pTilemapLayer->tileHeightPx,
    };
    vec2 br;
    glm_vec2_add(tl, dims, br);
    vec2 camTL, camBR;
    GetViewportWorldspaceTLBR(camTL, camBR, pCam, pGameLayerData->windowW, pGameLayerData->windowH);

    float tilemapW = br[0] - tl[0];
    float tilemapH = br[1] - tl[1];
    float viewportW = camBR[0] - camTL[0];
    float viewportH = camBR[1] - camTL[1];

    vec2 camCenter;
    GetCamWorldspaceCenter(pCam, pGameLayerData->windowW, pGameLayerData->windowH, camCenter);


    float xAdjust = 0.0f;
    float yAdjust = 0.0f;
    if(camTL[0] < tl[0])
    {
        xAdjust = tl[0] - camTL[0];
    }
    else if(camBR[0] > br[0])
    {
        xAdjust = br[0] - camBR[0];
    }

    if(camTL[1] < tl[1])
    {
        yAdjust = tl[1] - camTL[1];
    }
    else if(camBR[1] > br[1])
    {
        yAdjust = br[1] - camBR[1];
    }

    vec2 tmCentre; /* center of the tilemap in world space */
    vec2 tmHalfDims = 
    {
        dims[0] / 2.0f,
        dims[1] / 2.0f
    };
    glm_vec2_add(tl, tmHalfDims, tmCentre);

    /* if the tilemap is smaller than the viewport then cemtre the camera at the centre of the tilemap */
    if(tilemapW <= viewportW)
    {
        vec2 camCenter = {
            tmCentre[0],
            camCenter[1]
        };
        xAdjust = 0.0f;
        CenterCameraAt(camCenter[0], camCenter[1], pCam, pGameLayerData->windowW, pGameLayerData->windowH);
    }
    if(tilemapH <= viewportH)
    {
        vec2 camCenter = {
            camCenter[0],
            tmCentre[1]
        };
        yAdjust = 0.0f;
        CenterCameraAt(camCenter[0], camCenter[1], pCam, pGameLayerData->windowW, pGameLayerData->windowH);
    }


    pCam->position[0] -= xAdjust;
    pCam->position[1] -= yAdjust;
}