summary refs log tree commit diff
path: root/third_party/gldc/src/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/gldc/src/state.c')
-rw-r--r--third_party/gldc/src/state.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/third_party/gldc/src/state.c b/third_party/gldc/src/state.c
new file mode 100644
index 0000000..a9b2a72
--- /dev/null
+++ b/third_party/gldc/src/state.c
@@ -0,0 +1,236 @@
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "private.h"
+
+GLboolean STATE_DIRTY = GL_TRUE;
+
+GLboolean DEPTH_TEST_ENABLED = GL_FALSE;
+GLboolean DEPTH_MASK_ENABLED = GL_FALSE;
+
+GLboolean CULLING_ENABLED = GL_FALSE;
+
+GLboolean FOG_ENABLED        = GL_FALSE;
+GLboolean ALPHA_TEST_ENABLED = GL_FALSE;
+
+GLboolean SCISSOR_TEST_ENABLED = GL_FALSE;
+GLenum SHADE_MODEL = PVR_SHADE_GOURAUD;
+
+GLboolean BLEND_ENABLED = GL_FALSE;
+
+GLboolean TEXTURES_ENABLED = GL_FALSE;
+GLboolean AUTOSORT_ENABLED = GL_FALSE;
+
+static struct {
+    int x;
+    int y;
+    int width;
+    int height;
+    GLboolean applied;
+} scissor_rect = {0, 0, 640, 480, false};
+
+void _glInitContext() {
+    scissor_rect.x = 0;
+    scissor_rect.y = 0;
+    scissor_rect.width  = vid_mode->width;
+    scissor_rect.height = vid_mode->height;
+}
+
+/* Depth Testing */
+void glClearDepth(float depth) {
+    /* We reverse because using invW means that farther Z == lower number */
+    pvr_set_zclip(MIN(1.0f - depth, PVR_MIN_Z));
+}
+
+void glScissor(int x, int y, int width, int height) {
+
+    if(scissor_rect.x == x &&
+        scissor_rect.y == y &&
+        scissor_rect.width == width &&
+        scissor_rect.height == height) {
+        return;
+    }
+
+    scissor_rect.x = x;
+    scissor_rect.y = y;
+    scissor_rect.width = width;
+    scissor_rect.height = height;
+    scissor_rect.applied = false;
+    STATE_DIRTY = GL_TRUE; // FIXME: do we need this?
+
+    _glApplyScissor(false);
+}
+
+/* Setup the hardware user clip rectangle.
+
+   The minimum clip rectangle is a 32x32 area which is dependent on the tile
+   size use by the tile accelerator. The PVR swithes off rendering to tiles
+   outside or inside the defined rectangle dependant upon the 'clipmode'
+   bits in the polygon header.
+
+   Clip rectangles therefore must have a size that is some multiple of 32.
+
+    glScissor(0, 0, 32, 32) allows only the 'tile' in the lower left
+    hand corner of the screen to be modified and glScissor(0, 0, 0, 0)
+    disallows modification to all 'tiles' on the screen.
+
+    We call this in the following situations:
+
+     - glEnable(GL_SCISSOR_TEST) is called
+     - glScissor() is called
+     - After glKosSwapBuffers()
+
+    This ensures that a clip command is added to every vertex list
+    at the right place, either when enabling the scissor test, or
+    when the scissor test changes.
+*/
+void _glApplyScissor(int force) {
+    /* Don't do anyting if clipping is disabled */
+    if(!SCISSOR_TEST_ENABLED) {
+        return;
+    }
+
+    /* Don't apply if we already applied - nothing changed */
+    if(scissor_rect.applied && !force) {
+        return;
+    }
+
+    PVRTileClipCommand c;
+
+    int miny, maxx, maxy;
+
+    int scissor_width  = MAX(MIN(scissor_rect.width,  vid_mode->width),  0);
+    int scissor_height = MAX(MIN(scissor_rect.height, vid_mode->height), 0);
+
+    /* force the origin to the lower left-hand corner of the screen */
+    miny = (vid_mode->height - scissor_height) - scissor_rect.y;
+    maxx = (scissor_width + scissor_rect.x);
+    maxy = (scissor_height + miny);
+
+    /* load command structure while mapping screen coords to TA tiles */
+    c.flags = PVR_CMD_USERCLIP;
+    c.d1 = c.d2 = c.d3 = 0;
+
+    uint16_t vw = vid_mode->width >> 5;
+    uint16_t vh = vid_mode->height >> 5;
+
+    c.sx = CLAMP(scissor_rect.x >> 5, 0, vw);
+    c.sy = CLAMP(miny >> 5, 0, vh);
+    c.ex = CLAMP((maxx >> 5) - 1, 0, vw);
+    c.ey = CLAMP((maxy >> 5) - 1, 0, vh);
+
+    aligned_vector_push_back(&OP_LIST.vector, &c, 1);
+    aligned_vector_push_back(&PT_LIST.vector, &c, 1);
+    aligned_vector_push_back(&TR_LIST.vector, &c, 1);
+
+    scissor_rect.applied = true;
+}
+
+Viewport VIEWPORT;
+
+/* Set the GL viewport */
+void glViewport(int x, int y, int width, int height) {
+    VIEWPORT.hwidth  = width  *  0.5f;
+    VIEWPORT.hheight = height * -0.5f;
+    VIEWPORT.x_plus_hwidth  = x + width  * 0.5f;
+    VIEWPORT.y_plus_hheight = y + height * 0.5f;
+}
+
+
+void apply_poly_header(PolyHeader* dst, PolyList* activePolyList) {
+    const TextureObject *tx1 = TEXTURE_ACTIVE;
+    uint32_t txr_base;
+    TRACE();
+
+    int list_type = activePolyList->list_type;
+    int gen_color_clamp = PVR_CLRCLAMP_DISABLE;
+
+    int gen_culling = CULLING_ENABLED    ? PVR_CULLING_CW : PVR_CULLING_SMALL;
+    int depth_comp  = DEPTH_TEST_ENABLED ? PVR_DEPTHCMP_GEQUAL : PVR_DEPTHCMP_ALWAYS;
+    int depth_write = DEPTH_MASK_ENABLED ? PVR_DEPTHWRITE_ENABLE : PVR_DEPTHWRITE_DISABLE;
+
+    int gen_shading   = SHADE_MODEL;
+    int gen_clip_mode = SCISSOR_TEST_ENABLED       ? PVR_USERCLIP_INSIDE : PVR_USERCLIP_DISABLE;
+    int gen_fog_type  = FOG_ENABLED                ? PVR_FOG_TABLE : PVR_FOG_DISABLE;
+
+    int gen_alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? PVR_ALPHA_ENABLE : PVR_ALPHA_DISABLE;
+    int blend_src = PVR_BLEND_SRCALPHA;
+    int blend_dst = PVR_BLEND_INVSRCALPHA;
+
+    if (list_type == PVR_LIST_OP_POLY) {
+        /* Opaque polys are always one/zero */
+        blend_src  = PVR_BLEND_ONE;
+        blend_dst  = PVR_BLEND_ZERO;
+    } else if (list_type == PVR_LIST_PT_POLY) {
+        /* Punch-through polys require fixed blending and depth modes */
+        blend_src  = PVR_BLEND_SRCALPHA;
+        blend_dst  = PVR_BLEND_INVSRCALPHA;
+        depth_comp = PVR_DEPTHCMP_LEQUAL;
+    } else if (list_type == PVR_LIST_TR_POLY && AUTOSORT_ENABLED) {
+        /* Autosort mode requires this mode for transparent polys */
+        depth_comp = PVR_DEPTHCMP_GEQUAL;
+    }
+
+    int txr_enable, txr_alpha;
+    if (!TEXTURES_ENABLED || !tx1 || !tx1->data) {
+        /* Disable all texturing to start with */
+        txr_enable = PVR_TEXTURE_DISABLE;
+    } else {
+        txr_alpha  = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? PVR_TXRALPHA_ENABLE : PVR_TXRALPHA_DISABLE;
+        txr_enable = PVR_TEXTURE_ENABLE;
+    }
+
+    /* The base values for CMD */
+    dst->cmd = PVR_CMD_POLYHDR;
+    dst->cmd |= txr_enable << 3;
+    /* Force bits 18 and 19 on to switch to 6 triangle strips */
+    dst->cmd |= 0xC0000;
+
+    /* Or in the list type, shading type, color and UV formats */
+    dst->cmd |= (list_type             << PVR_TA_CMD_TYPE_SHIFT)     & PVR_TA_CMD_TYPE_MASK;
+    dst->cmd |= (PVR_CLRFMT_ARGBPACKED << PVR_TA_CMD_CLRFMT_SHIFT)   & PVR_TA_CMD_CLRFMT_MASK;
+    dst->cmd |= (gen_shading           << PVR_TA_CMD_SHADE_SHIFT)    & PVR_TA_CMD_SHADE_MASK;
+    dst->cmd |= (PVR_UVFMT_32BIT       << PVR_TA_CMD_UVFMT_SHIFT)    & PVR_TA_CMD_UVFMT_MASK;
+    dst->cmd |= (gen_clip_mode         << PVR_TA_CMD_USERCLIP_SHIFT) & PVR_TA_CMD_USERCLIP_MASK;
+
+    /* Polygon mode 1 */
+    dst->mode1  = (depth_comp  << PVR_TA_PM1_DEPTHCMP_SHIFT)   & PVR_TA_PM1_DEPTHCMP_MASK;
+    dst->mode1 |= (gen_culling << PVR_TA_PM1_CULLING_SHIFT)    & PVR_TA_PM1_CULLING_MASK;
+    dst->mode1 |= (depth_write << PVR_TA_PM1_DEPTHWRITE_SHIFT) & PVR_TA_PM1_DEPTHWRITE_MASK;
+    dst->mode1 |= (txr_enable  << PVR_TA_PM1_TXRENABLE_SHIFT)  & PVR_TA_PM1_TXRENABLE_MASK;
+
+    /* Polygon mode 2 */
+    dst->mode2  = (blend_src       << PVR_TA_PM2_SRCBLEND_SHIFT) & PVR_TA_PM2_SRCBLEND_MASK;
+    dst->mode2 |= (blend_dst       << PVR_TA_PM2_DSTBLEND_SHIFT) & PVR_TA_PM2_DSTBLEND_MASK;
+    dst->mode2 |= (gen_fog_type    << PVR_TA_PM2_FOG_SHIFT)      & PVR_TA_PM2_FOG_MASK;
+    dst->mode2 |= (gen_color_clamp << PVR_TA_PM2_CLAMP_SHIFT)    & PVR_TA_PM2_CLAMP_MASK;
+    dst->mode2 |= (gen_alpha       << PVR_TA_PM2_ALPHA_SHIFT)    & PVR_TA_PM2_ALPHA_MASK;
+
+    if (txr_enable == PVR_TEXTURE_DISABLE) {
+        dst->mode3 = 0;
+    } else {
+        GLuint filter = PVR_FILTER_NEAREST;
+        if (tx1->minFilter == GL_LINEAR && tx1->magFilter == GL_LINEAR) filter = PVR_FILTER_BILINEAR;
+
+        dst->mode2 |= (txr_alpha                << PVR_TA_PM2_TXRALPHA_SHIFT) & PVR_TA_PM2_TXRALPHA_MASK;
+        dst->mode2 |= (filter                   << PVR_TA_PM2_FILTER_SHIFT)   & PVR_TA_PM2_FILTER_MASK;
+        dst->mode2 |= (tx1->mipmap_bias         << PVR_TA_PM2_MIPBIAS_SHIFT)  & PVR_TA_PM2_MIPBIAS_MASK;
+        dst->mode2 |= (PVR_TXRENV_MODULATEALPHA << PVR_TA_PM2_TXRENV_SHIFT)   & PVR_TA_PM2_TXRENV_MASK;
+
+        dst->mode2 |= (DimensionFlag(tx1->width)  << PVR_TA_PM2_USIZE_SHIFT) & PVR_TA_PM2_USIZE_MASK;
+        dst->mode2 |= (DimensionFlag(tx1->height) << PVR_TA_PM2_VSIZE_SHIFT) & PVR_TA_PM2_VSIZE_MASK;
+
+        /* Polygon mode 3 */
+        dst->mode3  = (GL_FALSE   << PVR_TA_PM3_MIPMAP_SHIFT) & PVR_TA_PM3_MIPMAP_MASK;
+        dst->mode3 |= (tx1->color << PVR_TA_PM3_TXRFMT_SHIFT) & PVR_TA_PM3_TXRFMT_MASK;
+
+        /* Convert the texture address */
+        txr_base = (uint32_t)tx1->data;
+        txr_base = (txr_base & 0x00fffff8) >> 3;
+        dst->mode3 |= txr_base;
+    }
+
+    dst->d1 = dst->d2 = 0xffffffff;
+    dst->d3 = dst->d4 = 0xffffffff;
+}