-
Notifications
You must be signed in to change notification settings - Fork 4
/
raster-shader-plain-solid-fill.js
131 lines (112 loc) · 4.87 KB
/
raster-shader-plain-solid-fill.js
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
* 2019-2022 Tarpeeksi Hyvae Soft
*
* Software: Retro n-gon renderer
*
*/
import { color_index } from "../../core/color";
// The n-gon and render state must fulfill the following criteria:
// - No texture
// - No pixel shader
// - No alpha operations
// - No auxiliary buffers
// - Depth buffering enabled
export function plain_solid_fill({
ngon,
leftEdges,
rightEdges,
numLeftEdges,
numRightEdges,
pixelBuffer32,
})
{
const usePalette = Rngon.internalState.usePalette;
const pixelBufferImage = Rngon.internalState.pixelBuffer;
const pixelBufferClamped8 = pixelBufferImage.data;
const pixelBufferWidth = pixelBufferImage.width;
const depthBuffer = (Rngon.internalState.useDepthBuffer? Rngon.internalState.depthBuffer.data : null);
const material = ngon.material;
let curLeftEdgeIdx = 0;
let curRightEdgeIdx = 0;
let leftEdge = leftEdges[curLeftEdgeIdx];
let rightEdge = rightEdges[curRightEdgeIdx];
if (!numLeftEdges || !numRightEdges) return;
const ngonStartY = leftEdges[0].top;
const ngonEndY = leftEdges[numLeftEdges-1].bottom;
// Rasterize the n-gon in horizontal pixel spans over its height.
for (let y = ngonStartY; y < ngonEndY; y++)
{
const spanStartX = Math.min(pixelBufferWidth, Math.max(0, Math.round(leftEdge.start.x)));
const spanEndX = Math.min(pixelBufferWidth, Math.max(0, Math.ceil(rightEdge.start.x)));
const spanWidth = ((spanEndX - spanStartX) + 1);
if (spanWidth > 0)
{
const deltaDepth = ((rightEdge.start.depth - leftEdge.start.depth) / spanWidth);
let iplDepth = (leftEdge.start.depth - deltaDepth);
const deltaShade = ((rightEdge.start.shade - leftEdge.start.shade) / spanWidth);
let iplShade = (leftEdge.start.shade - deltaShade);
const deltaInvW = ((rightEdge.start.invW - leftEdge.start.invW) / spanWidth);
let iplInvW = (leftEdge.start.invW - deltaInvW);
let pixelBufferIdx = ((spanStartX + y * pixelBufferWidth) - 1);
// Draw the span into the pixel buffer.
for (let x = spanStartX; x < spanEndX; x++)
{
// Update values that're interpolated horizontally along the span.
iplDepth += deltaDepth;
iplShade += deltaShade;
iplInvW += deltaInvW;
pixelBufferIdx++;
const depth = (iplDepth / iplInvW);
if (depthBuffer[pixelBufferIdx] <= depth) continue;
if (usePalette)
{
pixelBufferClamped8[pixelBufferIdx] = material.color.index;
}
else
{
// The color we'll write into the pixel buffer for this pixel; assuming
// it passes the alpha test, the depth test, etc.
const shade = (material.renderVertexShade? iplShade : 1);
const red = (material.color.red * shade);
const green = (material.color.green * shade);
const blue = (material.color.blue * shade);
// If shade is > 1, the color values may exceed 255, in which case we write into
// the clamped 8-bit view to get 'free' clamping.
if (shade > 1)
{
const idx = (pixelBufferIdx * 4);
pixelBufferClamped8[idx+0] = red;
pixelBufferClamped8[idx+1] = green;
pixelBufferClamped8[idx+2] = blue;
pixelBufferClamped8[idx+3] = 255;
}
else
{
pixelBuffer32[pixelBufferIdx] = (
(255 << 24) +
(blue << 16) +
(green << 8) +
red
);
}
}
depthBuffer[pixelBufferIdx] = depth;
}
}
// Update values that're interpolated vertically along the edges.
{
leftEdge.start.x += leftEdge.delta.x;
leftEdge.start.depth += leftEdge.delta.depth;
leftEdge.start.shade += leftEdge.delta.shade;
leftEdge.start.invW += leftEdge.delta.invW;
rightEdge.start.x += rightEdge.delta.x;
rightEdge.start.depth += rightEdge.delta.depth;
rightEdge.start.shade += rightEdge.delta.shade;
rightEdge.start.invW += rightEdge.delta.invW;
}
// We can move onto the next edge when we're at the end of the current one.
if (y === (leftEdge.bottom - 1)) leftEdge = leftEdges[++curLeftEdgeIdx];
if (y === (rightEdge.bottom - 1)) rightEdge = rightEdges[++curRightEdgeIdx];
}
return true;
}