Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / DepthBufferRender.cpp
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, mri@penti.sit.fi
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 #ifdef HAVE_GLES
85 // using float should be faster than int in fact, especialy if using NEON
86 static float right_height, left_height;
87 static float right_x, right_dxdy, left_x, left_dxdy;
88 static float left_z, left_dzdy;
89
90 __inline float iceil(int x)
91 {
92         return cellf((float)x*(1.0f/65536.0f));
93 }
94 __inline float i2float(int x)
95 {
96         return (float)x*(1.0f/65536.0f);
97 }
98 __inline int float2i(float x)
99 {
100         return x*65536.0f;
101 }
102
103 #else
104
105 static int right_height, left_height;
106 static int right_x, right_dxdy, left_x, left_dxdy;
107 static int left_z, left_dzdy;
108
109 __inline int imul16(int x, int y)        // (x * y) >> 16
110 {
111     return (((long long)x) * ((long long)y)) >> 16;
112 }
113
114 __inline int imul14(int x, int y)        // (x * y) >> 14
115 {
116     return (((long long)x) * ((long long)y)) >> 14;
117 }
118 __inline int idiv16(int x, int y)        // (x << 16) / y
119 {
120     //x = (((long long)x) << 16) / ((long long)y);
121  /*   
122   eax = x;
123   ebx = y;
124   edx = x;
125   (x << 16) | ()
126    */ 
127 #if !defined(__GNUC__) && !defined(NO_ASM)
128   __asm {
129         mov   eax, x
130         mov   ebx, y
131         mov   edx,eax   
132         sar   edx,16
133         shl   eax,16    
134         idiv  ebx  
135         mov   x, eax
136     }
137 #elif !defined(NO_ASM)
138     int reminder;
139     asm ("idivl %[divisor]"
140           : "=a" (x), "=d" (reminder)
141           : [divisor] "g" (y), "d" (x >> 16), "a" (x << 16));
142 #else
143         x = (((long long)x) << 16) / ((long long)y);
144 #endif
145     return x;
146 }
147
148 __inline int iceil(int x)
149 {
150   x +=  0xffff;
151   return (x >> 16);
152 }
153 #endif
154
155 static void RightSection(void)
156 {
157   // Walk backwards trough the vertex array
158   
159   vertexi * v2, * v1 = right_vtx;
160   if(right_vtx > start_vtx) v2 = right_vtx-1;     
161   else                      v2 = end_vtx;         // Wrap to end of array
162   right_vtx = v2;
163   
164   // v1 = top vertex
165   // v2 = bottom vertex 
166   
167   // Calculate number of scanlines in this section
168   
169   right_height = iceil(v2->y) - iceil(v1->y);
170   if(right_height <= 0) return;
171   
172   // Guard against possible div overflows
173   
174   #ifdef HAVE_GLES
175   right_dxdy  = i2float(v2->x - v1->x)/i2float(v2->y - v1->y);
176   #else
177   if(right_height > 1) {
178     // OK, no worries, we have a section that is at least
179     // one pixel high. Calculate slope as usual.
180     
181     int height = v2->y - v1->y;
182     right_dxdy  = idiv16(v2->x - v1->x, height);
183   }
184   else {
185     // Height is less or equal to one pixel.
186     // Calculate slope = width * 1/height
187     // using 18:14 bit precision to avoid overflows.
188     
189     int inv_height = (0x10000 << 14) / (v2->y - v1->y);  
190     right_dxdy = imul14(v2->x - v1->x, inv_height);
191   }
192   #endif
193   
194   // Prestep initial values
195   
196   #ifdef HAVE_GLES
197   float prestep = iceil(v1->y) - i2float(v1->y);
198   right_x = i2float(v1->x) + prestep*right_dxdy;
199   #else
200   int prestep = (iceil(v1->y) << 16) - v1->y;
201   right_x = v1->x + imul16(prestep, right_dxdy);
202   #endif
203 }
204
205 static void LeftSection(void)
206 {
207   // Walk forward trough the vertex array
208   
209   vertexi * v2, * v1 = left_vtx;
210   if(left_vtx < end_vtx) v2 = left_vtx+1;
211   else                   v2 = start_vtx;      // Wrap to start of array
212   left_vtx = v2;
213   
214   // v1 = top vertex
215   // v2 = bottom vertex 
216   
217   // Calculate number of scanlines in this section
218   
219   left_height = iceil(v2->y) - iceil(v1->y);
220   if(left_height <= 0) return;
221   
222   // Guard against possible div overflows
223   
224   #ifdef HAVE_GLES
225   float invheight = 1.0f/i2float(v2->y - v1->y)
226   left_dxdy  = i2float(v2->x - v1->x)*invheight;
227   left_dzdy  = i2float(v2->z - v1->z)*invheight;
228   #else
229   if(left_height > 1) {
230     // OK, no worries, we have a section that is at least
231     // one pixel high. Calculate slope as usual.
232     
233     int height = v2->y - v1->y;
234     left_dxdy = idiv16(v2->x - v1->x, height);
235     left_dzdy = idiv16(v2->z - v1->z, height);
236   }
237   else {
238     // Height is less or equal to one pixel.
239     // Calculate slope = width * 1/height
240     // using 18:14 bit precision to avoid overflows.
241     
242     int inv_height = (0x10000 << 14) / (v2->y - v1->y);
243     left_dxdy = imul14(v2->x - v1->x, inv_height);
244     left_dzdy = imul14(v2->z - v1->z, inv_height);
245   }
246   #endif
247   
248   // Prestep initial values
249   
250   #ifdef HAVE_GLES
251   float prestep = iceil(v1->y) - i2float(v1->y);
252   left_x = i2float(v1->x) + prestep*left_dxdy;
253   left_z = i2float(v1->z) + prestep*left_dzdy;
254   #else
255   int prestep = (iceil(v1->y) << 16) - v1->y;
256   left_x = v1->x + imul16(prestep, left_dxdy);
257   left_z = v1->z + imul16(prestep, left_dzdy);
258   #endif
259 }
260
261
262 void Rasterize(vertexi * vtx, int vertices, int dzdx)
263 {
264   start_vtx = vtx;        // First vertex in array
265   
266   // Search trough the vtx array to find min y, max y
267   // and the location of these structures.
268   
269   vertexi * min_vtx = vtx;
270   max_vtx = vtx;
271   
272   int min_y = vtx->y;
273   int max_y = vtx->y;
274   
275   vtx++;
276   
277   for(int n=1; n<vertices; n++) {
278     if(vtx->y < min_y) {
279       min_y = vtx->y;
280       min_vtx = vtx;
281     }
282     else
283       if(vtx->y > max_y) {
284         max_y = vtx->y;
285         max_vtx = vtx;
286       }
287       vtx++;
288   }
289   
290   // OK, now we know where in the array we should start and
291   // where to end while scanning the edges of the polygon
292   
293   left_vtx  = min_vtx;    // Left side starting vertex
294   right_vtx = min_vtx;    // Right side starting vertex
295   end_vtx   = vtx-1;      // Last vertex in array
296   
297   // Search for the first usable right section
298   
299   do {
300     if(right_vtx == max_vtx) return;
301     RightSection();
302   } while(right_height <= 0);
303   
304   // Search for the first usable left section
305   
306   do {
307     if(left_vtx == max_vtx) return;
308     LeftSection();
309   } while(left_height <= 0);
310   
311   wxUint16 * destptr = (wxUint16*)(gfx.RDRAM+rdp.zimg);
312   int y1 = iceil(min_y);
313   if (y1 >= (int)rdp.scissor_o.lr_y) return;
314   int shift;
315   
316   for(;;)
317   {
318     int x1 = iceil(left_x);
319     if (x1 < (int)rdp.scissor_o.ul_x)
320       x1 = rdp.scissor_o.ul_x;
321     int width = iceil(right_x) - x1;
322     if (x1+width >= (int)rdp.scissor_o.lr_x)
323       width = rdp.scissor_o.lr_x - x1 - 1;
324
325     if(width > 0 && y1 >= (int)rdp.scissor_o.ul_y) {
326   
327         
328       // Prestep initial z
329       
330           #ifdef HAVE_GLES
331       float z = left_z + (x1 - left_x)*dzdx;
332           #else
333       int prestep = (x1 << 16) - left_x;
334       int z = left_z + imul16(prestep, dzdx);
335           #endif
336       
337       shift = x1 + y1*rdp.zi_width;
338       //draw to depth buffer
339       int trueZ;
340       int idx;
341       wxUint16 encodedZ;
342       for (int x = 0; x < width; x++)
343       {
344                 #ifdef HAVE_GLES
345                 trueZ = (int)(z*8.0f);
346                 #else
347         trueZ = z/8192;
348                 #endif
349         if (trueZ < 0) trueZ = 0;
350         else if (trueZ > 0x3FFFF) trueZ = 0x3FFFF;
351         encodedZ = zLUT[trueZ];
352         idx = (shift+x)^1;
353         if(encodedZ < destptr[idx]) 
354           destptr[idx] = encodedZ;
355         z += dzdx;
356       }
357     }
358     
359     //destptr += rdp.zi_width;
360     y1++;
361     if (y1 >= (int)rdp.scissor_o.lr_y) return;
362     
363     // Scan the right side
364     
365     if(--right_height <= 0) {               // End of this section?
366       do {
367         if(right_vtx == max_vtx) return;
368         RightSection();
369       } while(right_height <= 0);
370     }
371     else 
372       right_x += right_dxdy;
373     
374     // Scan the left side
375     
376     if(--left_height <= 0) {                // End of this section?
377       do {
378         if(left_vtx == max_vtx) return;
379         LeftSection();
380       } while(left_height <= 0);
381     }
382     else {
383       left_x += left_dxdy;
384       left_z += left_dzdy;
385     }
386   }
387 }