~ubuntu-branches/ubuntu/precise/mupen64plus/precise

« back to all changes in this revision

Viewing changes to glide64/DepthBufferRender.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sven Eckelmann
  • Date: 2009-09-08 22:17:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090908221700-yela0ckgc1xwiqtn
Tags: upstream-1.5+dfsg1
ImportĀ upstreamĀ versionĀ 1.5+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
*   Glide64 - Glide video plugin for Nintendo 64 emulators.
 
3
*   Copyright (c) 2002  Dave2001
 
4
*   Copyright (c) 2008  GĆ¼nther <guenther.emu@freenet.de>
 
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
 
17
*   Licence along with this program; if not, write to the Free
 
18
*   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 
19
*   Boston, MA  02110-1301, USA
 
20
*/
 
21
 
 
22
//****************************************************************
 
23
//
 
24
// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
 
25
// Project started on December 29th, 2001
 
26
//
 
27
// To modify Glide64:
 
28
// * 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.
 
29
// * 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.
 
30
//
 
31
// Official Glide64 development channel: #Glide64 on EFnet
 
32
//
 
33
//****************************************************************
 
34
//
 
35
// Software rendering into N64 depth buffer
 
36
// Idea and N64 depth value format by Orkin
 
37
// Polygon rasterization algorithm is taken from FATMAP2 engine by Mats Byggmastar, mri@penti.sit.fi
 
38
//
 
39
// Created by Gonetz, Dec 2004
 
40
//
 
41
//****************************************************************
 
42
 
 
43
#include "Gfx1.3.h"
 
44
#include "rdp.h"
 
45
#include "DepthBufferRender.h"
 
46
 
 
47
WORD * zLUT = 0;
 
48
 
 
49
void ZLUT_init()
 
50
{
 
51
    if (zLUT)
 
52
      return;
 
53
    zLUT = new WORD[0x40000];
 
54
    for(int i=0; i<0x40000; i++)
 
55
    {
 
56
         DWORD exponent = 0;
 
57
         DWORD testbit = 1 << 17;
 
58
         while((i & testbit) && (exponent < 7))
 
59
           {
 
60
          exponent++;
 
61
          testbit = 1 << (17 - exponent);
 
62
           }
 
63
         
 
64
         DWORD mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff;
 
65
         zLUT[i] = (WORD)(((exponent << 11) | mantissa) << 2);
 
66
    }
 
67
    /*
 
68
    for(i=0; i<0x40000; i++)
 
69
    {
 
70
       int j = i + 1;
 
71
       WORD z = zLUT[i];
 
72
       while (zLUT[i] == zLUT[j])
 
73
         j++;
 
74
       int w = (j - i) >> 2;
 
75
       if (w > 0)
 
76
       {
 
77
         int k;
 
78
         for (k = 1; k < 4; k++)
 
79
           for (int t = 0; t < w; t++)
 
80
             zLUT[i+k*w+t] = z + k;
 
81
         i = j - 1;
 
82
       }
 
83
    }
 
84
    */
 
85
}
 
86
 
 
87
void ZLUT_release()
 
88
{
 
89
  delete[] zLUT;
 
90
  zLUT = 0;
 
91
}
 
92
 
 
93
static vertexi * max_vtx;                   // Max y vertex (ending vertex)
 
94
static vertexi * start_vtx, * end_vtx;      // First and last vertex in array
 
95
static vertexi * right_vtx, * left_vtx;     // Current right and left vertex
 
96
 
 
97
static int right_height, left_height;
 
98
static int right_x, right_dxdy, left_x, left_dxdy;
 
99
static int left_z, left_dzdy;
 
100
 
 
101
__inline int iceil(int x)
 
102
{
 
103
    x +=  0xffff;
 
104
    return (x >> 16);
 
105
}
 
106
 
 
107
__inline int imul16(int x, int y)        // (x * y) >> 16
 
108
{
 
109
    return (((long long)x) * ((long long)y)) >> 16;
 
110
}
 
111
 
 
112
__inline int imul14(int x, int y)        // (x * y) >> 14
 
113
{
 
114
    return (((long long)x) * ((long long)y)) >> 14;
 
115
}
 
116
 
 
117
/*
 
118
int idiv16(int x, int y);        // (x << 16) / y
 
119
#pragma aux idiv16 = \
 
120
    " mov   edx,eax    "\
 
121
    " sar   edx,16     "\
 
122
    " shl   eax,16     "\
 
123
    " idiv  ebx        "\
 
124
    parm [eax] [ebx] modify exact [eax edx] value [eax]
 
125
*/
 
126
__inline int idiv16(int x, int y)        // (x << 16) / y
 
127
{
 
128
    //x = (((long long)x) << 16) / ((long long)y);
 
129
#if !defined(__GNUC__) && !defined(NO_ASM)
 
130
  __asm {
 
131
        mov   eax, x
 
132
        mov   ebx, y
 
133
        mov   edx,eax   
 
134
        sar   edx,16
 
135
        shl   eax,16    
 
136
        idiv  ebx  
 
137
        mov   x, eax
 
138
    }
 
139
#elif !defined(NO_ASM)
 
140
    int reminder;
 
141
    asm ("idivl %[divisor]"
 
142
          : "=a" (x), "=d" (reminder)
 
143
          : [divisor] "g" (y), "d" (x >> 16), "a" (x << 16));
 
144
#endif
 
145
    return x;
 
146
}
 
147
 
 
148
 
 
149
static void RightSection(void)
 
150
{
 
151
    // Walk backwards trough the vertex array
 
152
 
 
153
    vertexi * v2, * v1 = right_vtx;
 
154
    if(right_vtx > start_vtx) v2 = right_vtx-1;     
 
155
    else                      v2 = end_vtx;         // Wrap to end of array
 
156
    right_vtx = v2;
 
157
 
 
158
    // v1 = top vertex
 
159
    // v2 = bottom vertex 
 
160
 
 
161
    // Calculate number of scanlines in this section
 
162
 
 
163
    right_height = iceil(v2->y) - iceil(v1->y);
 
164
    if(right_height <= 0) return;
 
165
 
 
166
    // Guard against possible div overflows
 
167
 
 
168
    if(right_height > 1) {
 
169
        // OK, no worries, we have a section that is at least
 
170
        // one pixel high. Calculate slope as usual.
 
171
 
 
172
        int height = v2->y - v1->y;
 
173
        right_dxdy  = idiv16(v2->x - v1->x, height);
 
174
    }
 
175
    else {
 
176
        // Height is less or equal to one pixel.
 
177
        // Calculate slope = width * 1/height
 
178
        // using 18:14 bit precision to avoid overflows.
 
179
 
 
180
        int inv_height = (0x10000 << 14) / (v2->y - v1->y);  
 
181
        right_dxdy = imul14(v2->x - v1->x, inv_height);
 
182
    }
 
183
 
 
184
    // Prestep initial values
 
185
 
 
186
    int prestep = (iceil(v1->y) << 16) - v1->y;
 
187
    right_x = v1->x + imul16(prestep, right_dxdy);
 
188
}
 
189
 
 
190
static void LeftSection(void)
 
191
{
 
192
    // Walk forward trough the vertex array
 
193
 
 
194
    vertexi * v2, * v1 = left_vtx;
 
195
    if(left_vtx < end_vtx) v2 = left_vtx+1;
 
196
    else                   v2 = start_vtx;      // Wrap to start of array
 
197
    left_vtx = v2;
 
198
 
 
199
    // v1 = top vertex
 
200
    // v2 = bottom vertex 
 
201
 
 
202
    // Calculate number of scanlines in this section
 
203
 
 
204
    left_height = iceil(v2->y) - iceil(v1->y);
 
205
    if(left_height <= 0) return;
 
206
 
 
207
    // Guard against possible div overflows
 
208
 
 
209
    if(left_height > 1) {
 
210
        // OK, no worries, we have a section that is at least
 
211
        // one pixel high. Calculate slope as usual.
 
212
 
 
213
        int height = v2->y - v1->y;
 
214
        left_dxdy = idiv16(v2->x - v1->x, height);
 
215
        left_dzdy = idiv16(v2->z - v1->z, height);
 
216
    }
 
217
    else {
 
218
        // Height is less or equal to one pixel.
 
219
        // Calculate slope = width * 1/height
 
220
        // using 18:14 bit precision to avoid overflows.
 
221
 
 
222
        int inv_height = (0x10000 << 14) / (v2->y - v1->y);
 
223
        left_dxdy = imul14(v2->x - v1->x, inv_height);
 
224
        left_dzdy = imul14(v2->z - v1->z, inv_height);
 
225
    }
 
226
 
 
227
    // Prestep initial values
 
228
 
 
229
    int prestep = (iceil(v1->y) << 16) - v1->y;
 
230
    left_x = v1->x + imul16(prestep, left_dxdy);
 
231
    left_z = v1->z + imul16(prestep, left_dzdy);
 
232
}
 
233
 
 
234
 
 
235
void Rasterize(vertexi * vtx, int vertices, int dzdx)
 
236
{
 
237
    start_vtx = vtx;        // First vertex in array
 
238
 
 
239
    // Search trough the vtx array to find min y, max y
 
240
    // and the location of these structures.
 
241
 
 
242
    vertexi * min_vtx = vtx;
 
243
    max_vtx = vtx;
 
244
 
 
245
    int min_y = vtx->y;
 
246
    int max_y = vtx->y;
 
247
 
 
248
    vtx++;
 
249
 
 
250
    for(int n=1; n<vertices; n++) {
 
251
        if(vtx->y < min_y) {
 
252
            min_y = vtx->y;
 
253
            min_vtx = vtx;
 
254
        }
 
255
        else
 
256
        if(vtx->y > max_y) {
 
257
            max_y = vtx->y;
 
258
            max_vtx = vtx;
 
259
        }
 
260
        vtx++;
 
261
    }
 
262
 
 
263
    // OK, now we know where in the array we should start and
 
264
    // where to end while scanning the edges of the polygon
 
265
 
 
266
    left_vtx  = min_vtx;    // Left side starting vertex
 
267
    right_vtx = min_vtx;    // Right side starting vertex
 
268
    end_vtx   = vtx-1;      // Last vertex in array
 
269
 
 
270
    // Search for the first usable right section
 
271
 
 
272
    do {
 
273
        if(right_vtx == max_vtx) return;
 
274
        RightSection();
 
275
    } while(right_height <= 0);
 
276
 
 
277
    // Search for the first usable left section
 
278
 
 
279
    do {
 
280
        if(left_vtx == max_vtx) return;
 
281
        LeftSection();
 
282
    } while(left_height <= 0);
 
283
 
 
284
    WORD * destptr = (WORD*)(gfx.RDRAM+rdp.zimg);
 
285
    int y1 = iceil(min_y);
 
286
    int shift;
 
287
    //destptr += iceil(min_y) * rdp.zi_width;
 
288
 
 
289
    for(;;)
 
290
    {
 
291
        int x1 = iceil(left_x);
 
292
        int width = iceil(right_x) - x1;
 
293
 
 
294
        if(width > 0) {
 
295
 
 
296
            // Prestep initial color intensity i
 
297
    
 
298
            if (y1 >= rdp.zi_lry) return;
 
299
            //if (x1+width > rdp.zi_lrx) width = rdp.zi_lrx-x1;
 
300
            int prestep = (x1 << 16) - left_x;
 
301
            int z = left_z + imul16(prestep, dzdx);
 
302
 
 
303
//            if (y1 > max_y) return;
 
304
//          FRDP("Depth render. x1: %d, y1: %d, width: %d\n", x1, y1, width);
 
305
            shift = x1 + y1*rdp.zi_width;
 
306
//            if (shift + width > rdp.zi_nb_pixels)
 
307
//              return;
 
308
            //draw to depth buffer
 
309
            int trueZ;
 
310
            int idx;
 
311
            WORD encodedZ;
 
312
            for (int x = 0; x < width; x++)
 
313
            {
 
314
                trueZ = z/8192;
 
315
                if (trueZ < 0) trueZ = 0;
 
316
                else if (trueZ > 0x3FFFF) trueZ = 0x3FFFF;
 
317
                encodedZ = zLUT[trueZ];
 
318
                idx = (shift+x)^1;
 
319
                if(encodedZ < destptr[idx]) 
 
320
                  destptr[idx] = encodedZ;
 
321
                z += dzdx;
 
322
            }
 
323
        }
 
324
 
 
325
        //destptr += rdp.zi_width;
 
326
        y1++;
 
327
 
 
328
        // Scan the right side
 
329
 
 
330
        if(--right_height <= 0) {               // End of this section?
 
331
            do {
 
332
                if(right_vtx == max_vtx) return;
 
333
                RightSection();
 
334
            } while(right_height <= 0);
 
335
        }
 
336
        else 
 
337
            right_x += right_dxdy;
 
338
 
 
339
        // Scan the left side
 
340
 
 
341
        if(--left_height <= 0) {                // End of this section?
 
342
            do {
 
343
                if(left_vtx == max_vtx) return;
 
344
                LeftSection();
 
345
            } while(left_height <= 0);
 
346
        }
 
347
        else {
 
348
            left_x += left_dxdy;
 
349
            left_z += left_dzdy;
 
350
        }
 
351
    }
 
352
}
 
353