summaryrefslogtreecommitdiff
path: root/src/code/z_viszbuffer.c
blob: 77bd5a934af884094f5e51f692826c7bd08bea29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
 * This file implements a framebuffer effect relying on the depth buffer (Z buffer).
 * It merely allows LERPing between two colors (from color2 to color1), using the Z buffer bytes (interpreted as either
 * ia16 or rgba16 depending on the type being 0 or not) as the factor.
 *
 * Z buffer values are two bytes each. They are floating point, which makes the effect not that interesting for an
 * actual application as that doesn't map well to be interpreted as ia16 or rgba16, though some discontinuous gradients
 * can be seen.
 *
 * The bit layout of Z buffer values is:
 * 0bEEEM_MMMM_MMMM_MMDD
 * Where E is the 3 exponent bits, M is the 11 mantissa bits,
 * and D is 2 of the 4 dz value bits (the remaining two are stored in the "hidden" 9th bit of each byte).
 * In 3D space, Z values increase from front (near plane) to back (far plane).
 *
 * Interpreted as ia16:
 * 0bIIII_IIII_AAAA_AAAA
 * The intensity channel takes its value from the exponent bits and the high mantissa bits, so it continuously increases
 * from front to back.
 * The alpha channel mostly takes its value from the lowest mantissa bits, so it increases from front to back but also
 * rolls over frequently.
 * This can be observed in-game by setting color1 to white and color2 to black.
 * From front to back, the intensity gradient is a continuous increase.
 * The alpha is ignored due to the render mode VisZBuffer uses.
 *
 * Interpreted as rgba16:
 * 0bRRRR_RGGG_GGBB_BBBA
 * The red channel mostly takes its value from the exponent bits, so it continuously increases from front to back.
 * The green channel takes its value from the middle mantissa bits, so it increases from front to back but also rolls
 * over frequently.
 * The blue channel mostly takes its value from the lowest mantissa bits, so it increases from front to back and also
 * rolls over even more frequently.
 * This can be observed in-game by setting color1 to white and color2 to black.
 * From front to back, the gradients for each color channel are then:
 * - red: continuous increase
 * - green: discontinuous succession of continuous increases
 * - blue: like green but even higher frequency
 */

#include "vis.h"

#include "color.h"
#include "gfx.h"

#include "ultra64.h"
#include <stdbool.h>

// z-buffer
extern u16 D_0E000000[];

void VisZBuffer_Init(VisZBuffer* this) {
    this->params.type = 0;
    this->params.setScissor = false;
    this->params.color1.r = 255;
    this->params.color1.g = 255;
    this->params.color1.b = 255;
    this->params.color1.a = 255;

    // clang-format off
    this->params.color2.r = 0; \
    this->params.color2.g = 0; \
    this->params.color2.b = 0; \
    this->params.color2.a = 255;
    // clang-format on
}

void VisZBuffer_Destroy(VisZBuffer* this) {
}

void VisZBuffer_Draw(VisZBuffer* this, Gfx** gfxP) {
    Gfx* gfx = *gfxP;
    s32 pad;
    u16* tex = D_0E000000;
    s32 fmt = this->params.type == 0 ? G_IM_FMT_IA : G_IM_FMT_RGBA;
    s32 y;
    s32 height = TMEM_SIZE / (SCREEN_WIDTH * G_IM_SIZ_16b_BYTES);

    gDPPipeSync(gfx++);
    if (this->params.setScissor == true) {
        gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    }

    gDPSetOtherMode(gfx++,
                    G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE |
                        G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
                    G_AC_NONE | G_ZS_PRIM | G_RM_OPA_SURF | G_RM_OPA_SURF2);
    gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT,
                      PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT);

    gDPSetColor(gfx++, G_SETPRIMCOLOR, this->params.color1.rgba);
    gDPSetColor(gfx++, G_SETENVCOLOR, this->params.color2.rgba);

    for (y = 0; y <= SCREEN_HEIGHT - height; y += height) {
        gDPLoadTextureBlock(gfx++, tex, fmt, G_IM_SIZ_16b, SCREEN_WIDTH, height, 0, G_TX_NOMIRROR | G_TX_CLAMP,
                            G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);

        gSPTextureRectangle(gfx++, 0, y << 2, SCREEN_WIDTH << 2, (y + height) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
                            1 << 10);
        tex += SCREEN_WIDTH * height;
    }

    gDPPipeSync(gfx++);
    *gfxP = gfx;
}