Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-video-glide64mk2/src/Glide64/DepthBufferRender.cpp
2 views
1
/*
2
* Glide64 - Glide video plugin for Nintendo 64 emulators.
3
* Copyright (c) 2002 Dave2001
4
* Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*/
20
21
//****************************************************************
22
//
23
// Glide64 - Glide Plugin for Nintendo 64 emulators
24
// Project started on December 29th, 2001
25
//
26
// Authors:
27
// Dave2001, original author, founded the project in 2001, left it in 2002
28
// Gugaman, joined the project in 2002, left it in 2002
29
// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30
// Hiroshi 'KoolSmoky' Morii, joined the project in 2007
31
//
32
//****************************************************************
33
//
34
// To modify Glide64:
35
// * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
36
// * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
37
//
38
//****************************************************************
39
//
40
// Software rendering into N64 depth buffer
41
// Idea and N64 depth value format by Orkin
42
// Polygon rasterization algorithm is taken from FATMAP2 engine by Mats Byggmastar, [email protected]
43
//
44
// Created by Gonetz, Dec 2004
45
//
46
//****************************************************************
47
48
#include "Gfx_1.3.h"
49
#include "rdp.h"
50
#include "DepthBufferRender.h"
51
52
wxUint16 * zLUT = 0;
53
54
void ZLUT_init()
55
{
56
if (zLUT)
57
return;
58
zLUT = new wxUint16[0x40000];
59
for(int i=0; i<0x40000; i++)
60
{
61
wxUint32 exponent = 0;
62
wxUint32 testbit = 1 << 17;
63
while((i & testbit) && (exponent < 7))
64
{
65
exponent++;
66
testbit = 1 << (17 - exponent);
67
}
68
69
wxUint32 mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff;
70
zLUT[i] = (wxUint16)(((exponent << 11) | mantissa) << 2);
71
}
72
}
73
74
void ZLUT_release()
75
{
76
delete[] zLUT;
77
zLUT = 0;
78
}
79
80
static vertexi * max_vtx; // Max y vertex (ending vertex)
81
static vertexi * start_vtx, * end_vtx; // First and last vertex in array
82
static vertexi * right_vtx, * left_vtx; // Current right and left vertex
83
84
static int right_height, left_height;
85
static int right_x, right_dxdy, left_x, left_dxdy;
86
static int left_z, left_dzdy;
87
88
__inline int imul16(int x, int y) // (x * y) >> 16
89
{
90
return (((long long)x) * ((long long)y)) >> 16;
91
}
92
93
__inline int imul14(int x, int y) // (x * y) >> 14
94
{
95
return (((long long)x) * ((long long)y)) >> 14;
96
}
97
__inline int idiv16(int x, int y) // (x << 16) / y
98
{
99
//x = (((long long)x) << 16) / ((long long)y);
100
/*
101
eax = x;
102
ebx = y;
103
edx = x;
104
(x << 16) | ()
105
*/
106
#if !defined(__GNUC__) && !defined(NO_ASM)
107
__asm {
108
mov eax, x
109
mov ebx, y
110
mov edx,eax
111
sar edx,16
112
shl eax,16
113
idiv ebx
114
mov x, eax
115
}
116
#elif !defined(NO_ASM)
117
int reminder;
118
asm ("idivl %[divisor]"
119
: "=a" (x), "=d" (reminder)
120
: [divisor] "g" (y), "d" (x >> 16), "a" (x << 16));
121
#else
122
x = (((long long)x) << 16) / ((long long)y);
123
#endif
124
return x;
125
}
126
127
__inline int iceil(int x)
128
{
129
x += 0xffff;
130
return (x >> 16);
131
}
132
133
static void RightSection(void)
134
{
135
// Walk backwards trough the vertex array
136
137
vertexi * v2, * v1 = right_vtx;
138
if(right_vtx > start_vtx) v2 = right_vtx-1;
139
else v2 = end_vtx; // Wrap to end of array
140
right_vtx = v2;
141
142
// v1 = top vertex
143
// v2 = bottom vertex
144
145
// Calculate number of scanlines in this section
146
147
right_height = iceil(v2->y) - iceil(v1->y);
148
if(right_height <= 0) return;
149
150
// Guard against possible div overflows
151
152
if(right_height > 1) {
153
// OK, no worries, we have a section that is at least
154
// one pixel high. Calculate slope as usual.
155
156
int height = v2->y - v1->y;
157
right_dxdy = idiv16(v2->x - v1->x, height);
158
}
159
else {
160
// Height is less or equal to one pixel.
161
// Calculate slope = width * 1/height
162
// using 18:14 bit precision to avoid overflows.
163
164
int inv_height = (0x10000 << 14) / (v2->y - v1->y);
165
right_dxdy = imul14(v2->x - v1->x, inv_height);
166
}
167
168
// Prestep initial values
169
170
int prestep = (iceil(v1->y) << 16) - v1->y;
171
right_x = v1->x + imul16(prestep, right_dxdy);
172
}
173
174
static void LeftSection(void)
175
{
176
// Walk forward trough the vertex array
177
178
vertexi * v2, * v1 = left_vtx;
179
if(left_vtx < end_vtx) v2 = left_vtx+1;
180
else v2 = start_vtx; // Wrap to start of array
181
left_vtx = v2;
182
183
// v1 = top vertex
184
// v2 = bottom vertex
185
186
// Calculate number of scanlines in this section
187
188
left_height = iceil(v2->y) - iceil(v1->y);
189
if(left_height <= 0) return;
190
191
// Guard against possible div overflows
192
193
if(left_height > 1) {
194
// OK, no worries, we have a section that is at least
195
// one pixel high. Calculate slope as usual.
196
197
int height = v2->y - v1->y;
198
left_dxdy = idiv16(v2->x - v1->x, height);
199
left_dzdy = idiv16(v2->z - v1->z, height);
200
}
201
else {
202
// Height is less or equal to one pixel.
203
// Calculate slope = width * 1/height
204
// using 18:14 bit precision to avoid overflows.
205
206
int inv_height = (0x10000 << 14) / (v2->y - v1->y);
207
left_dxdy = imul14(v2->x - v1->x, inv_height);
208
left_dzdy = imul14(v2->z - v1->z, inv_height);
209
}
210
211
// Prestep initial values
212
213
int prestep = (iceil(v1->y) << 16) - v1->y;
214
left_x = v1->x + imul16(prestep, left_dxdy);
215
left_z = v1->z + imul16(prestep, left_dzdy);
216
}
217
218
219
void Rasterize(vertexi * vtx, int vertices, int dzdx)
220
{
221
start_vtx = vtx; // First vertex in array
222
223
// Search trough the vtx array to find min y, max y
224
// and the location of these structures.
225
226
vertexi * min_vtx = vtx;
227
max_vtx = vtx;
228
229
int min_y = vtx->y;
230
int max_y = vtx->y;
231
232
vtx++;
233
234
for(int n=1; n<vertices; n++) {
235
if(vtx->y < min_y) {
236
min_y = vtx->y;
237
min_vtx = vtx;
238
}
239
else
240
if(vtx->y > max_y) {
241
max_y = vtx->y;
242
max_vtx = vtx;
243
}
244
vtx++;
245
}
246
247
// OK, now we know where in the array we should start and
248
// where to end while scanning the edges of the polygon
249
250
left_vtx = min_vtx; // Left side starting vertex
251
right_vtx = min_vtx; // Right side starting vertex
252
end_vtx = vtx-1; // Last vertex in array
253
254
// Search for the first usable right section
255
256
do {
257
if(right_vtx == max_vtx) return;
258
RightSection();
259
} while(right_height <= 0);
260
261
// Search for the first usable left section
262
263
do {
264
if(left_vtx == max_vtx) return;
265
LeftSection();
266
} while(left_height <= 0);
267
268
wxUint16 * destptr = (wxUint16*)(gfx.RDRAM+rdp.zimg);
269
int y1 = iceil(min_y);
270
if (y1 >= (int)rdp.scissor_o.lr_y) return;
271
int shift;
272
273
for(;;)
274
{
275
int x1 = iceil(left_x);
276
if (x1 < (int)rdp.scissor_o.ul_x)
277
x1 = rdp.scissor_o.ul_x;
278
int width = iceil(right_x) - x1;
279
if (x1+width >= (int)rdp.scissor_o.lr_x)
280
width = rdp.scissor_o.lr_x - x1 - 1;
281
282
if(width > 0 && y1 >= (int)rdp.scissor_o.ul_y) {
283
284
// Prestep initial z
285
286
int prestep = (x1 << 16) - left_x;
287
int z = left_z + imul16(prestep, dzdx);
288
289
shift = x1 + y1*rdp.zi_width;
290
//draw to depth buffer
291
int trueZ;
292
int idx;
293
wxUint16 encodedZ;
294
for (int x = 0; x < width; x++)
295
{
296
trueZ = z/8192;
297
if (trueZ < 0) trueZ = 0;
298
else if (trueZ > 0x3FFFF) trueZ = 0x3FFFF;
299
encodedZ = zLUT[trueZ];
300
idx = (shift+x)^1;
301
if(encodedZ < destptr[idx])
302
destptr[idx] = encodedZ;
303
z += dzdx;
304
}
305
}
306
307
//destptr += rdp.zi_width;
308
y1++;
309
if (y1 >= (int)rdp.scissor_o.lr_y) return;
310
311
// Scan the right side
312
313
if(--right_height <= 0) { // End of this section?
314
do {
315
if(right_vtx == max_vtx) return;
316
RightSection();
317
} while(right_height <= 0);
318
}
319
else
320
right_x += right_dxdy;
321
322
// Scan the left side
323
324
if(--left_height <= 0) { // End of this section?
325
do {
326
if(left_vtx == max_vtx) return;
327
LeftSection();
328
} while(left_height <= 0);
329
}
330
else {
331
left_x += left_dxdy;
332
left_z += left_dzdy;
333
}
334
}
335
}
336
337