File WidgetVertexOutputHelpers.c

File List > engine > src > gameframework > layers > UI > WidgetVertexOutputHelpers.c

Go to the documentation of this file

#include "WidgetVertexOutputHelpers.h"
#include <stdlib.h>
#include <string.h>
#include "AssertLib.h"
#include "DrawContext.h"

static bool bClipRegionSet = false;
GeomRect gClipRect = { 0,0,0,0 };

void SetWidgetQuadColour(WidgetQuad* pQuad, float r, float g, float b, float a)
{
    for (int i = 0; i < 4; i++)
    {
        pQuad->v[i].r = r;
        pQuad->v[i].g = g;
        pQuad->v[i].b = b;
        pQuad->v[i].a = a;
    }
}

void SetClipRect(GeomRect clipRect)
{
    memcpy(gClipRect, clipRect, sizeof(GeomRect));
    bClipRegionSet = true;
}

void UnsetClipRect()
{
    bClipRegionSet = false;
}

void PopulateWidgetQuadWholeSprite(WidgetQuad* pQuad, AtlasSprite* pSprt)
{
    vec2 tl = { 0,0 };
    vec2 br = { pSprt->widthPx, pSprt->heightPx };
    PopulateWidgetQuad(pQuad, pSprt, tl, br);
}

void PopulateWidgetQuad(WidgetQuad* pQuad, AtlasSprite* pSprt, vec2 subSpriteTL, vec2 subSpriteBR)
{
    float subSpriteHeight = subSpriteBR[1] - subSpriteTL[1];
    float subSpriteWidth = subSpriteBR[0] - subSpriteTL[0];

    float uPerPxl = (pSprt->bottomRightUV_U - pSprt->topLeftUV_U) / (float)pSprt->widthPx;
    float vPerPxl = (pSprt->topLeftUV_V - pSprt->bottomRightUV_V) / (float)pSprt->heightPx;
    vec2 subSpriteTopLefUV = {
        pSprt->topLeftUV_U + subSpriteTL[0] * uPerPxl,
        pSprt->topLeftUV_V - subSpriteTL[1] * vPerPxl
    };
    vec2 subSpriteBottomRightUV = {
        subSpriteTopLefUV[0] + uPerPxl * subSpriteWidth,
        subSpriteTopLefUV[1] - vPerPxl * subSpriteHeight
    };

    pQuad->v[VL_TL].x = 0.0f;
    pQuad->v[VL_TL].y = 0.0f;
    pQuad->v[VL_TL].u = subSpriteTopLefUV[0];
    pQuad->v[VL_TL].v = subSpriteTopLefUV[1];
    pQuad->v[VL_TL].r = 1.0f; pQuad->v[VL_TL].g = 1.0f; pQuad->v[VL_TL].b = 1.0f; pQuad->v[VL_TL].a = 1.0f;

    pQuad->v[VL_TR].x = subSpriteWidth;
    pQuad->v[VL_TR].y = 0.0f;
    pQuad->v[VL_TR].u = subSpriteBottomRightUV[0];
    pQuad->v[VL_TR].v = subSpriteTopLefUV[1];
    pQuad->v[VL_TR].r = 1.0f; pQuad->v[VL_TR].g = 1.0f; pQuad->v[VL_TR].b = 1.0f; pQuad->v[VL_TR].a = 1.0f;

    pQuad->v[VL_BR].x = subSpriteWidth;
    pQuad->v[VL_BR].y = subSpriteHeight;
    pQuad->v[VL_BR].u = subSpriteBottomRightUV[0];
    pQuad->v[VL_BR].v = subSpriteBottomRightUV[1];
    pQuad->v[VL_BR].r = 1.0f; pQuad->v[VL_BR].g = 1.0f; pQuad->v[VL_BR].b = 1.0f; pQuad->v[VL_BR].a = 1.0f;

    pQuad->v[VL_BL].x = 0.0f;
    pQuad->v[VL_BL].y = subSpriteHeight;
    pQuad->v[VL_BL].u = subSpriteTopLefUV[0];
    pQuad->v[VL_BL].v = subSpriteBottomRightUV[1];
    pQuad->v[VL_BL].r = 1.0f; pQuad->v[VL_BL].g = 1.0f; pQuad->v[VL_BL].b = 1.0f; pQuad->v[VL_BL].a = 1.0f;

}

static bool AllCornerOutsideOfRegion(WidgetQuad* pQuad)
{
    int count = 0;
    for (int i = 0; i < VT_NUM; i++)
    {
        if (!Ge_PointInAABB(pQuad->v[i].x, pQuad->v[i].y, gClipRect))
        {
            count++;
        }
    }
    return count == 4;
}

static float ClipUV(float p0, float p1, float uv0, float uv1, float midpos)
{
    //EASSERT(p1 > p0);
    //EASSERT(midpos >= p0 && midpos <= p1);
    float s = p1 - p0;
    float s2 = midpos - p0;
    float t = s2 / s;
    float us = uv1 - uv0;
    return uv0 + (us)*t;
}

static bool ClipQuad(WidgetQuad* pQuad)
{
    if (AllCornerOutsideOfRegion(pQuad))
    {
        /*
            IF A QUAD IS GREATER THAN THE SIZE OF THE CANVAS IN BOTH DIMENSIONS IT WILL BE CLIPPED!!
        */
        return false;
    }
    for (int i = 0; i < VT_NUM; i++)
    {
        WidgetVertex* pVert = &pQuad->v[i];
        if (pVert->x < gClipRect[0])
        {
            EASSERT(i == VL_TL || i == VL_BL);
            pVert->u = ClipUV(pQuad->v[VL_TL].x, pQuad->v[VL_TR].x, pQuad->v[VL_TL].u, pQuad->v[VL_TR].u, gClipRect[0]);
            pVert->x = gClipRect[0];
        }
        if (pVert->x > gClipRect[2])
        {
            EASSERT(i == VL_TR || i == VL_BR);
            pVert->u = ClipUV(pQuad->v[VL_TL].x, pQuad->v[VL_TR].x, pQuad->v[VL_TL].u, pQuad->v[VL_TR].u, gClipRect[2]);
            pVert->x = gClipRect[2];
        }
        if (pVert->y < gClipRect[1])
        {
            EASSERT(i == VL_TL || i == VL_TR);
            pVert->v = ClipUV(pQuad->v[VL_TL].y, pQuad->v[VL_BL].y, pQuad->v[VL_TL].v, pQuad->v[VL_BL].v, gClipRect[1]);
            pVert->y = gClipRect[1];
        }
        if (pVert->y > gClipRect[3])
        {
            EASSERT(i == VL_BL || i == VL_BR);
            pVert->v = ClipUV(pQuad->v[VL_TL].y, pQuad->v[VL_BL].y, pQuad->v[VL_TL].v, pQuad->v[VL_BL].v, gClipRect[3]);
            pVert->y = gClipRect[3];
        }
    }
    return true;
}

void* OutputWidgetQuad(VECTOR(WidgetVertex) pOutVerts, const WidgetQuad* pQuad)
{
    WidgetQuad cpy;
    memcpy(&cpy, pQuad, sizeof(WidgetQuad));

    if (bClipRegionSet)
    {
        if (!ClipQuad(&cpy))
        {
            return pOutVerts;
        }
    }

    const int numIndices = 6;
    const WidgetQuadVertexLocation indices[6] = {
        VL_TL,
        VL_TR,
        VL_BL,
        VL_TR,
        VL_BR,
        VL_BL
    };
    for (int i = 0; i < numIndices; i++)
    {
        int index = indices[i];
        pOutVerts = VectorPush(pOutVerts, &cpy.v[index]);
    }
    return pOutVerts;
}

void* OutputWidgetQuads(VECTOR(WidgetVertex) pOutVerts, const WidgetQuad* pQuads, int num)
{
    for (int i = 0; i < num; i++)
    {
        pOutVerts = OutputWidgetQuad(pOutVerts, &pQuads[i]);
    }
    return pOutVerts;
}


void TranslateWidgetQuad(vec2 vector, WidgetQuad* pOutQuad)
{
    for (int i = 0; i < 4; i++)
    {
        pOutQuad->v[i].x += vector[0];
        pOutQuad->v[i].y += vector[1];
    }
}

// keeps TL where it is and sets a new size, expanding to the right and downwards
void SizeWidgetQuad(vec2 size, WidgetQuad* pOutQuad)
{
    pOutQuad->v[VL_TR].x = pOutQuad->v[VL_TL].x + size[0];
    pOutQuad->v[VL_BR].x = pOutQuad->v[VL_BL].x + size[0];

    pOutQuad->v[VL_BL].y = pOutQuad->v[VL_TL].y + size[1];
    pOutQuad->v[VL_BR].y = pOutQuad->v[VL_TR].y + size[1];
}

float WidgetQuadWidth(const WidgetQuad* pInQuad)
{
    return pInQuad->v[VL_TR].x - pInQuad->v[VL_TL].x;
}

float WidgetQuadHeight(const WidgetQuad* pInQuad)
{
    return pInQuad->v[VL_BR].y - pInQuad->v[VL_TR].y;
}

void ScaleWidgetQuad(float scaleX, float scaleY, WidgetQuad* pOutQuad)
{
    float w = WidgetQuadWidth(pOutQuad);
    float h = WidgetQuadHeight(pOutQuad);
    float newW = w * scaleX;
    float newH = h * scaleY;
    vec2 sz = { newW, newH };
    SizeWidgetQuad(sz, pOutQuad);
}