98e75f2d |
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 | #include <math.h> |
41 | #include "Gfx_1.3.h" |
42 | #include "Util.h" |
43 | #include "Combine.h" |
44 | #include "3dmath.h" |
45 | #include "Debugger.h" |
46 | #include "TexCache.h" |
47 | #include "DepthBufferRender.h" |
48 | |
49 | #define Vj rdp.vtxbuf2[j] |
50 | #define Vi rdp.vtxbuf2[i] |
51 | |
52 | VERTEX *vtx_list1[32]; // vertex indexing |
53 | VERTEX *vtx_list2[32]; |
54 | |
55 | // |
56 | // util_init - initialize data for the functions in this file |
57 | // |
58 | |
59 | void util_init () |
60 | { |
61 | for (int i=0; i<32; i++) |
62 | { |
63 | vtx_list1[i] = &rdp.vtx1[i]; |
64 | vtx_list2[i] = &rdp.vtx2[i]; |
65 | } |
66 | } |
67 | |
68 | static wxUint32 u_cull_mode = 0; |
69 | |
70 | //software backface culling. Gonetz |
71 | // mega modifications by Dave2001 |
72 | int cull_tri(VERTEX **v) // type changed to VERTEX** [Dave2001] |
73 | { |
74 | int i; |
75 | |
76 | if (v[0]->scr_off & v[1]->scr_off & v[2]->scr_off) |
77 | { |
78 | LRDP (" clipped\n"); |
79 | return TRUE; |
80 | } |
81 | |
82 | // Triangle can't be culled, if it need clipping |
83 | int draw = FALSE; |
84 | |
85 | for (i=0; i<3; i++) |
86 | { |
87 | if (!v[i]->screen_translated) |
88 | { |
89 | v[i]->sx = rdp.view_trans[0] + v[i]->x_w * rdp.view_scale[0] + rdp.offset_x; |
90 | v[i]->sy = rdp.view_trans[1] + v[i]->y_w * rdp.view_scale[1] + rdp.offset_y; |
91 | v[i]->sz = rdp.view_trans[2] + v[i]->z_w * rdp.view_scale[2]; |
92 | v[i]->screen_translated = 1; |
93 | } |
94 | if (v[i]->w < 0.01f) //need clip_z. can't be culled now |
95 | draw = 1; |
96 | } |
97 | |
98 | u_cull_mode = (rdp.flags & CULLMASK); |
99 | if (draw || u_cull_mode == 0 || u_cull_mode == CULLMASK) //no culling set |
100 | { |
101 | u_cull_mode >>= CULLSHIFT; |
102 | return FALSE; |
103 | } |
104 | |
105 | #define SW_CULLING |
106 | #ifdef SW_CULLING |
107 | #if 1 // H.Morii - faster float comparisons with zero area check added |
108 | |
109 | const float x1 = v[0]->sx - v[1]->sx; |
110 | const float y1 = v[0]->sy - v[1]->sy; |
111 | const float x2 = v[2]->sx - v[1]->sx; |
112 | const float y2 = v[2]->sy - v[1]->sy; |
113 | const float area = y1*x2 - x1*y2; |
114 | |
115 | const int iarea = *(int*)&area; |
116 | const unsigned int mode = (u_cull_mode << 19UL); |
117 | u_cull_mode >>= CULLSHIFT; |
118 | |
119 | if ((iarea & 0x7FFFFFFF) == 0) |
120 | { |
121 | LRDP (" zero area triangles\n"); |
122 | return TRUE; |
123 | } |
124 | |
125 | if ((rdp.flags & CULLMASK) && ((int)(iarea ^ mode)) >= 0) |
126 | { |
127 | LRDP (" culled\n"); |
128 | return TRUE; |
129 | } |
130 | #else |
131 | |
132 | float x1 = v[0]->sx - v[1]->sx; |
133 | float y1 = v[0]->sy - v[1]->sy; |
134 | float x2 = v[2]->sx - v[1]->sx; |
135 | float y2 = v[2]->sy - v[1]->sy; |
136 | |
137 | u_cull_mode >>= CULLSHIFT; |
138 | switch (u_cull_mode) |
139 | { |
140 | case 1: // cull front |
141 | // if ((x1*y2 - y1*x2) < 0.0f) //counter-clockwise, positive |
142 | if ((y1*x2-x1*y2) < 0.0f) //counter-clockwise, positive |
143 | { |
144 | LRDP (" culled!\n"); |
145 | return TRUE; |
146 | } |
147 | return FALSE; |
148 | case 2: // cull back |
149 | // if ((x1*y2 - y1*x2) >= 0.0f) //clockwise, negative |
150 | if ((y1*x2-x1*y2) >= 0.0f) //clockwise, negative |
151 | { |
152 | LRDP (" culled!\n"); |
153 | return TRUE; |
154 | } |
155 | return FALSE; |
156 | } |
157 | #endif |
158 | #endif |
159 | |
160 | return FALSE; |
161 | } |
162 | |
163 | |
164 | void apply_shade_mods (VERTEX *v) |
165 | { |
166 | float col[4]; |
167 | wxUint32 mod; |
168 | memcpy (col, rdp.col, 16); |
169 | |
170 | if (rdp.cmb_flags) |
171 | { |
172 | if (v->shade_mod == 0) |
173 | v->color_backup = *(wxUint32*)(&(v->b)); |
174 | else |
175 | *(wxUint32*)(&(v->b)) = v->color_backup; |
176 | mod = rdp.cmb_flags; |
177 | if (mod & CMB_SET) |
178 | { |
179 | if (col[0] > 1.0f) col[0] = 1.0f; |
180 | if (col[1] > 1.0f) col[1] = 1.0f; |
181 | if (col[2] > 1.0f) col[2] = 1.0f; |
182 | if (col[0] < 0.0f) col[0] = 0.0f; |
183 | if (col[1] < 0.0f) col[1] = 0.0f; |
184 | if (col[2] < 0.0f) col[2] = 0.0f; |
185 | v->r = (wxUint8)(255.0f * col[0]); |
186 | v->g = (wxUint8)(255.0f * col[1]); |
187 | v->b = (wxUint8)(255.0f * col[2]); |
188 | } |
189 | if (mod & CMB_A_SET) |
190 | { |
191 | if (col[3] > 1.0f) col[3] = 1.0f; |
192 | if (col[3] < 0.0f) col[3] = 0.0f; |
193 | v->a = (wxUint8)(255.0f * col[3]); |
194 | } |
195 | if (mod & CMB_SETSHADE_SHADEALPHA) |
196 | { |
197 | v->r = v->g = v->b = v->a; |
198 | } |
199 | if (mod & CMB_MULT_OWN_ALPHA) |
200 | { |
201 | float percent = v->a / 255.0f; |
202 | v->r = (wxUint8)(v->r * percent); |
203 | v->g = (wxUint8)(v->g * percent); |
204 | v->b = (wxUint8)(v->b * percent); |
205 | } |
206 | if (mod & CMB_MULT) |
207 | { |
208 | if (col[0] > 1.0f) col[0] = 1.0f; |
209 | if (col[1] > 1.0f) col[1] = 1.0f; |
210 | if (col[2] > 1.0f) col[2] = 1.0f; |
211 | if (col[0] < 0.0f) col[0] = 0.0f; |
212 | if (col[1] < 0.0f) col[1] = 0.0f; |
213 | if (col[2] < 0.0f) col[2] = 0.0f; |
214 | v->r = (wxUint8)(v->r * col[0]); |
215 | v->g = (wxUint8)(v->g * col[1]); |
216 | v->b = (wxUint8)(v->b * col[2]); |
217 | } |
218 | if (mod & CMB_A_MULT) |
219 | { |
220 | if (col[3] > 1.0f) col[3] = 1.0f; |
221 | if (col[3] < 0.0f) col[3] = 0.0f; |
222 | v->a = (wxUint8)(v->a * col[3]); |
223 | } |
224 | if (mod & CMB_SUB) |
225 | { |
226 | int r = v->r - (int)(255.0f * rdp.coladd[0]); |
227 | int g = v->g - (int)(255.0f * rdp.coladd[1]); |
228 | int b = v->b - (int)(255.0f * rdp.coladd[2]); |
229 | if (r < 0) r = 0; |
230 | if (g < 0) g = 0; |
231 | if (b < 0) b = 0; |
232 | v->r = (wxUint8)r; |
233 | v->g = (wxUint8)g; |
234 | v->b = (wxUint8)b; |
235 | } |
236 | if (mod & CMB_A_SUB) |
237 | { |
238 | int a = v->a - (int)(255.0f * rdp.coladd[3]); |
239 | if (a < 0) a = 0; |
240 | v->a = (wxUint8)a; |
241 | } |
242 | if (mod & CMB_ADD) |
243 | { |
244 | int r = v->r + (int)(255.0f * rdp.coladd[0]); |
245 | int g = v->g + (int)(255.0f * rdp.coladd[1]); |
246 | int b = v->b + (int)(255.0f * rdp.coladd[2]); |
247 | if (r > 255) r = 255; |
248 | if (g > 255) g = 255; |
249 | if (b > 255) b = 255; |
250 | v->r = (wxUint8)r; |
251 | v->g = (wxUint8)g; |
252 | v->b = (wxUint8)b; |
253 | } |
254 | if (mod & CMB_A_ADD) |
255 | { |
256 | int a = v->a + (int)(255.0f * rdp.coladd[3]); |
257 | if (a > 255) a = 255; |
258 | v->a = (wxUint8)a; |
259 | } |
260 | if (mod & CMB_COL_SUB_OWN) |
261 | { |
262 | int r = (wxUint8)(255.0f * rdp.coladd[0]) - v->r; |
263 | int g = (wxUint8)(255.0f * rdp.coladd[1]) - v->g; |
264 | int b = (wxUint8)(255.0f * rdp.coladd[2]) - v->b; |
265 | if (r < 0) r = 0; |
266 | if (g < 0) g = 0; |
267 | if (b < 0) b = 0; |
268 | v->r = (wxUint8)r; |
269 | v->g = (wxUint8)g; |
270 | v->b = (wxUint8)b; |
271 | } |
272 | v->shade_mod = cmb.shade_mod_hash; |
273 | } |
274 | if (rdp.cmb_flags_2 & CMB_INTER) |
275 | { |
276 | v->r = (wxUint8)(rdp.col_2[0] * rdp.shade_factor * 255.0f + v->r * (1.0f - rdp.shade_factor)); |
277 | v->g = (wxUint8)(rdp.col_2[1] * rdp.shade_factor * 255.0f + v->g * (1.0f - rdp.shade_factor)); |
278 | v->b = (wxUint8)(rdp.col_2[2] * rdp.shade_factor * 255.0f + v->b * (1.0f - rdp.shade_factor)); |
279 | v->shade_mod = cmb.shade_mod_hash; |
280 | } |
281 | } |
282 | |
283 | static int dzdx = 0; |
284 | static int deltaZ = 0; |
285 | VERTEX **org_vtx; |
286 | |
287 | void draw_tri (VERTEX **vtx, wxUint16 linew) |
288 | { |
289 | deltaZ = dzdx = 0; |
290 | if (linew == 0 && (fb_depth_render_enabled || (rdp.rm & 0xC00) == 0xC00)) |
291 | { |
292 | float X0 = vtx[0]->sx / rdp.scale_x; |
293 | float Y0 = vtx[0]->sy / rdp.scale_y; |
294 | float X1 = vtx[1]->sx / rdp.scale_x; |
295 | float Y1 = vtx[1]->sy / rdp.scale_y; |
296 | float X2 = vtx[2]->sx / rdp.scale_x; |
297 | float Y2 = vtx[2]->sy / rdp.scale_y; |
298 | float diffy_02 = Y0 - Y2; |
299 | float diffy_12 = Y1 - Y2; |
300 | float diffx_02 = X0 - X2; |
301 | float diffx_12 = X1 - X2; |
302 | |
303 | float denom = (diffx_02 * diffy_12 - diffx_12 * diffy_02); |
304 | if(denom*denom > 0.0f) |
305 | { |
306 | float diffz_02 = vtx[0]->sz - vtx[2]->sz; |
307 | float diffz_12 = vtx[1]->sz - vtx[2]->sz; |
308 | float fdzdx = (diffz_02 * diffy_12 - diffz_12 * diffy_02) / denom; |
309 | if ((rdp.rm & 0xC00) == 0xC00) { |
310 | // Calculate deltaZ per polygon for Decal z-mode |
311 | float fdzdy = (diffz_02 * diffx_12 - diffz_12 * diffx_02) / denom; |
312 | float fdz = fabs(fdzdx) + fabs(fdzdy); |
313 | if ((settings.hacks & hack_Zelda) && (rdp.rm & 0x800)) |
314 | fdz *= 4.0f; // Decal mode in Zelda sometimes needs mutiplied deltaZ to work correct, e.g. roads |
315 | deltaZ = max(8, (int)fdz); |
316 | } |
317 | dzdx = (int)(fdzdx * 65536.0); |
318 | } |
319 | } |
320 | |
321 | org_vtx = vtx; |
322 | |
323 | for (int i=0; i<3; i++) |
324 | { |
325 | VERTEX *v = vtx[i]; |
326 | |
327 | if (v->uv_calculated != rdp.tex_ctr) |
328 | { |
329 | #ifdef EXTREME_LOGGING |
330 | FRDP(" * CALCULATING VERTEX U/V: %d\n", v->number); |
331 | #endif |
332 | v->uv_calculated = rdp.tex_ctr; |
333 | |
334 | if (!(rdp.geom_mode & 0x00020000)) |
335 | { |
336 | if (!(rdp.geom_mode & 0x00000200)) |
337 | { |
338 | if (rdp.geom_mode & 0x00000004) // flat shading |
339 | { |
340 | int flag = min(2, (rdp.cmd1 >> 24) & 3); |
341 | v->a = vtx[flag]->a; |
342 | v->b = vtx[flag]->b; |
343 | v->g = vtx[flag]->g; |
344 | v->r = vtx[flag]->r; |
345 | #ifdef EXTREME_LOGGING |
346 | FRDP(" * Flat shaded, flag%d - r: %d, g: %d, b: %d, a: %d\n", flag, v->r, v->g, v->b, v->a); |
347 | #endif |
348 | } |
349 | else // prim color |
350 | { |
351 | #ifdef EXTREME_LOGGING |
352 | FRDP(" * Prim shaded %08lx\n", rdp.prim_color); |
353 | #endif |
354 | v->a = (wxUint8)(rdp.prim_color & 0xFF); |
355 | v->b = (wxUint8)((rdp.prim_color >> 8) & 0xFF); |
356 | v->g = (wxUint8)((rdp.prim_color >> 16) & 0xFF); |
357 | v->r = (wxUint8)((rdp.prim_color >> 24) & 0xFF); |
358 | } |
359 | } |
360 | } |
361 | |
362 | // Fix texture coordinates |
363 | if (!v->uv_scaled) |
364 | { |
365 | v->ou *= rdp.tiles[rdp.cur_tile].s_scale; |
366 | v->ov *= rdp.tiles[rdp.cur_tile].t_scale; |
367 | v->uv_scaled = 1; |
368 | if (!rdp.Persp_en) |
369 | { |
370 | // v->oow = v->w = 1.0f; |
371 | v->ou *= 0.5f; |
372 | v->ov *= 0.5f; |
373 | } |
374 | } |
375 | v->u1 = v->u0 = v->ou; |
376 | v->v1 = v->v0 = v->ov; |
377 | |
378 | if (rdp.tex >= 1 && rdp.cur_cache[0]) |
379 | { |
380 | if (rdp.aTBuffTex[0]) |
381 | { |
382 | v->u0 += rdp.aTBuffTex[0]->u_shift + rdp.aTBuffTex[0]->tile_uls; |
383 | v->v0 += rdp.aTBuffTex[0]->v_shift + rdp.aTBuffTex[0]->tile_ult; |
384 | } |
385 | |
386 | if (rdp.tiles[rdp.cur_tile].shift_s) |
387 | { |
388 | if (rdp.tiles[rdp.cur_tile].shift_s > 10) |
389 | v->u0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s)); |
390 | else |
391 | v->u0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_s); |
392 | } |
393 | if (rdp.tiles[rdp.cur_tile].shift_t) |
394 | { |
395 | if (rdp.tiles[rdp.cur_tile].shift_t > 10) |
396 | v->v0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t)); |
397 | else |
398 | v->v0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_t); |
399 | } |
400 | |
401 | if (rdp.aTBuffTex[0]) |
402 | { |
403 | if (rdp.aTBuffTex[0]->tile_uls != (int)rdp.tiles[rdp.cur_tile].f_ul_s) |
404 | v->u0 -= rdp.tiles[rdp.cur_tile].f_ul_s; |
405 | if (rdp.aTBuffTex[0]->tile_ult != (int)rdp.tiles[rdp.cur_tile].f_ul_t || (settings.hacks&hack_Megaman)) |
406 | v->v0 -= rdp.tiles[rdp.cur_tile].f_ul_t; //required for megaman (boss special attack) |
407 | v->u0 *= rdp.aTBuffTex[0]->u_scale; |
408 | v->v0 *= rdp.aTBuffTex[0]->v_scale; |
409 | #ifdef EXTREME_LOGGING |
410 | FRDP("tbuff_tex t0: (%f, %f)->(%f, %f)\n", v->ou, v->ov, v->u0, v->v0); |
411 | #endif |
412 | } |
413 | else |
414 | { |
415 | v->u0 -= rdp.tiles[rdp.cur_tile].f_ul_s; |
416 | v->v0 -= rdp.tiles[rdp.cur_tile].f_ul_t; |
417 | v->u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * v->u0; |
418 | v->v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * v->v0; |
419 | } |
420 | v->u0_w = v->u0 / v->w; |
421 | v->v0_w = v->v0 / v->w; |
422 | } |
423 | |
424 | if (rdp.tex >= 2 && rdp.cur_cache[1]) |
425 | { |
426 | if (rdp.aTBuffTex[1]) |
427 | { |
428 | v->u1 += rdp.aTBuffTex[1]->u_shift + rdp.aTBuffTex[1]->tile_uls; |
429 | v->v1 += rdp.aTBuffTex[1]->v_shift + rdp.aTBuffTex[1]->tile_ult; |
430 | } |
431 | if (rdp.tiles[rdp.cur_tile+1].shift_s) |
432 | { |
433 | if (rdp.tiles[rdp.cur_tile+1].shift_s > 10) |
434 | v->u1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s)); |
435 | else |
436 | v->u1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_s); |
437 | } |
438 | if (rdp.tiles[rdp.cur_tile+1].shift_t) |
439 | { |
440 | if (rdp.tiles[rdp.cur_tile+1].shift_t > 10) |
441 | v->v1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t)); |
442 | else |
443 | v->v1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_t); |
444 | } |
445 | |
446 | if (rdp.aTBuffTex[1]) |
447 | { |
448 | if (rdp.aTBuffTex[1]->tile_uls != (int)rdp.tiles[rdp.cur_tile].f_ul_s) |
449 | v->u1 -= rdp.tiles[rdp.cur_tile].f_ul_s; |
450 | v->u1 *= rdp.aTBuffTex[1]->u_scale; |
451 | v->v1 *= rdp.aTBuffTex[1]->v_scale; |
452 | #ifdef EXTREME_LOGGING |
453 | FRDP("tbuff_tex t1: (%f, %f)->(%f, %f)\n", v->ou, v->ov, v->u1, v->v1); |
454 | #endif |
455 | } |
456 | else |
457 | { |
458 | v->u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s; |
459 | v->v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t; |
460 | v->u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * v->u1; |
461 | v->v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * v->v1; |
462 | } |
463 | |
464 | v->u1_w = v->u1 / v->w; |
465 | v->v1_w = v->v1 / v->w; |
466 | } |
467 | // FRDP(" * CALCULATING VERTEX U/V: %d u0: %f, v0: %f, u1: %f, v1: %f\n", v->number, v->u0, v->v0, v->u1, v->v1); |
468 | } |
469 | #ifdef EXTREME_LOGGING |
470 | FRDP("draw_tri. v[%d] ou=%f, ov = %f\n", i, v->ou, v->ov); |
471 | #endif |
472 | if (v->shade_mod != cmb.shade_mod_hash) |
473 | apply_shade_mods (v); |
474 | } //for |
475 | |
476 | rdp.clip = 0; |
477 | |
478 | if ((vtx[0]->scr_off & 16) || |
479 | (vtx[1]->scr_off & 16) || |
480 | (vtx[2]->scr_off & 16)) |
481 | rdp.clip |= CLIP_WMIN; |
482 | |
483 | vtx[0]->not_zclipped = vtx[1]->not_zclipped = vtx[2]->not_zclipped = 1; |
484 | |
485 | if (rdp.cur_cache[0] && (rdp.tex & 1) && (rdp.cur_cache[0]->splits > 1) && !rdp.aTBuffTex[0] && !rdp.clip) |
486 | { |
487 | int index,i,j, min_256,max_256, cur_256,left_256,right_256; |
488 | float percent; |
489 | |
490 | min_256 = min((int)vtx[0]->u0,(int)vtx[1]->u0); // bah, don't put two mins on one line |
491 | min_256 = min(min_256,(int)vtx[2]->u0) >> 8; // or it will be calculated twice |
492 | |
493 | max_256 = max((int)vtx[0]->u0,(int)vtx[1]->u0); // not like it makes much difference |
494 | max_256 = max(max_256,(int)vtx[2]->u0) >> 8; // anyway :P |
495 | |
496 | for (cur_256=min_256; cur_256<=max_256; cur_256++) |
497 | { |
498 | left_256 = cur_256 << 8; |
499 | right_256 = (cur_256+1) << 8; |
500 | |
501 | // Set vertex buffers |
502 | rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1 |
503 | rdp.vtxbuf2 = rdp.vtx2; |
504 | rdp.vtx_buffer = 0; |
505 | rdp.n_global = 3; |
506 | index = 0; |
507 | |
508 | // ** Left plane ** |
509 | for (i=0; i<3; i++) |
510 | { |
511 | j = i+1; |
512 | if (j == 3) j = 0; |
513 | |
514 | VERTEX *v1 = vtx[i]; |
515 | VERTEX *v2 = vtx[j]; |
516 | |
517 | if (v1->u0 >= left_256) |
518 | { |
519 | if (v2->u0 >= left_256) // Both are in, save the last one |
520 | { |
521 | rdp.vtxbuf[index] = *v2; |
522 | rdp.vtxbuf[index].u0 -= left_256; |
523 | rdp.vtxbuf[index++].v0 += cur_256 * rdp.cur_cache[0]->splitheight; |
524 | } |
525 | else // First is in, second is out, save intersection |
526 | { |
527 | percent = (left_256 - v1->u0) / (v2->u0 - v1->u0); |
528 | rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent; |
529 | rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent; |
530 | rdp.vtxbuf[index].z = v1->z + (v2->z - v1->z) * percent; |
531 | rdp.vtxbuf[index].w = v1->w + (v2->w - v1->w) * percent; |
532 | rdp.vtxbuf[index].f = v1->f + (v2->f - v1->f) * percent; |
533 | rdp.vtxbuf[index].u0 = 0.5f; |
534 | rdp.vtxbuf[index].v0 = v1->v0 + (v2->v0 - v1->v0) * percent + |
535 | cur_256 * rdp.cur_cache[0]->splitheight; |
536 | rdp.vtxbuf[index].u1 = v1->u1 + (v2->u1 - v1->u1) * percent; |
537 | rdp.vtxbuf[index].v1 = v1->v1 + (v2->v1 - v1->v1) * percent; |
538 | rdp.vtxbuf[index].b = (wxUint8)(v1->b + (v2->b - v1->b) * percent); |
539 | rdp.vtxbuf[index].g = (wxUint8)(v1->g + (v2->g - v1->g) * percent); |
540 | rdp.vtxbuf[index].r = (wxUint8)(v1->r + (v2->r - v1->r) * percent); |
541 | rdp.vtxbuf[index++].a = (wxUint8)(v1->a + (v2->a - v1->a) * percent); |
542 | } |
543 | } |
544 | else |
545 | { |
546 | //if (v2->u0 < left_256) // Both are out, save nothing |
547 | if (v2->u0 >= left_256) // First is out, second is in, save intersection & in point |
548 | { |
549 | percent = (left_256 - v2->u0) / (v1->u0 - v2->u0); |
550 | rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent; |
551 | rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent; |
552 | rdp.vtxbuf[index].z = v2->z + (v1->z - v2->z) * percent; |
553 | rdp.vtxbuf[index].w = v2->w + (v1->w - v2->w) * percent; |
554 | rdp.vtxbuf[index].f = v2->f + (v1->f - v2->f) * percent; |
555 | rdp.vtxbuf[index].u0 = 0.5f; |
556 | rdp.vtxbuf[index].v0 = v2->v0 + (v1->v0 - v2->v0) * percent + |
557 | cur_256 * rdp.cur_cache[0]->splitheight; |
558 | rdp.vtxbuf[index].u1 = v2->u1 + (v1->u1 - v2->u1) * percent; |
559 | rdp.vtxbuf[index].v1 = v2->v1 + (v1->v1 - v2->v1) * percent; |
560 | rdp.vtxbuf[index].b = (wxUint8)(v2->b + (v1->b - v2->b) * percent); |
561 | rdp.vtxbuf[index].g = (wxUint8)(v2->g + (v1->g - v2->g) * percent); |
562 | rdp.vtxbuf[index].r = (wxUint8)(v2->r + (v1->r - v2->r) * percent); |
563 | rdp.vtxbuf[index++].a = (wxUint8)(v2->a + (v1->a - v2->a) * percent); |
564 | |
565 | // Save the in point |
566 | rdp.vtxbuf[index] = *v2; |
567 | rdp.vtxbuf[index].u0 -= left_256; |
568 | rdp.vtxbuf[index++].v0 += cur_256 * rdp.cur_cache[0]->splitheight; |
569 | } |
570 | } |
571 | } |
572 | rdp.n_global = index; |
573 | |
574 | rdp.vtxbuf = rdp.vtx2; // now vtx1 holds the value, & vtx2 is the destination |
575 | rdp.vtxbuf2 = rdp.vtx1; |
576 | rdp.vtx_buffer ^= 1; |
577 | index = 0; |
578 | |
579 | for (i=0; i<rdp.n_global; i++) |
580 | { |
581 | j = i+1; |
582 | if (j == rdp.n_global) j = 0; |
583 | |
584 | VERTEX *v1 = &rdp.vtxbuf2[i]; |
585 | VERTEX *v2 = &rdp.vtxbuf2[j]; |
586 | |
587 | // ** Right plane ** |
588 | if (v1->u0 <= right_256) |
589 | { |
590 | if (v2->u0 <= right_256) // Both are in, save the last one |
591 | { |
592 | rdp.vtxbuf[index] = *v2; |
593 | rdp.vtxbuf[index++].not_zclipped = 0; |
594 | } |
595 | else // First is in, second is out, save intersection |
596 | { |
597 | percent = (right_256 - v1->u0) / (v2->u0 - v1->u0); |
598 | rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent; |
599 | rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent; |
600 | rdp.vtxbuf[index].z = v1->z + (v2->z - v1->z) * percent; |
601 | rdp.vtxbuf[index].w = v1->w + (v2->w - v1->w) * percent; |
602 | rdp.vtxbuf[index].f = v1->f + (v2->f - v1->f) * percent; |
603 | rdp.vtxbuf[index].u0 = 255.5f; |
604 | rdp.vtxbuf[index].v0 = v1->v0 + (v2->v0 - v1->v0) * percent; |
605 | rdp.vtxbuf[index].u1 = v1->u1 + (v2->u1 - v1->u1) * percent; |
606 | rdp.vtxbuf[index].v1 = v1->v1 + (v2->v1 - v1->v1) * percent; |
607 | rdp.vtxbuf[index].b = (wxUint8)(v1->b + (v2->b - v1->b) * percent); |
608 | rdp.vtxbuf[index].g = (wxUint8)(v1->g + (v2->g - v1->g) * percent); |
609 | rdp.vtxbuf[index].r = (wxUint8)(v1->r + (v2->r - v1->r) * percent); |
610 | rdp.vtxbuf[index].a = (wxUint8)(v1->a + (v2->a - v1->a) * percent); |
611 | rdp.vtxbuf[index++].not_zclipped = 0; |
612 | } |
613 | } |
614 | else |
615 | { |
616 | //if (v2->u0 > 256.0f) // Both are out, save nothing |
617 | if (v2->u0 <= right_256) // First is out, second is in, save intersection & in point |
618 | { |
619 | percent = (right_256 - v2->u0) / (v1->u0 - v2->u0); |
620 | rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent; |
621 | rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent; |
622 | rdp.vtxbuf[index].z = v2->z + (v1->z - v2->z) * percent; |
623 | rdp.vtxbuf[index].w = v2->w + (v1->w - v2->w) * percent; |
624 | rdp.vtxbuf[index].f = v2->f + (v1->f - v2->f) * percent; |
625 | rdp.vtxbuf[index].u0 = 255.5f; |
626 | rdp.vtxbuf[index].v0 = v2->v0 + (v1->v0 - v2->v0) * percent; |
627 | rdp.vtxbuf[index].u1 = v2->u1 + (v1->u1 - v2->u1) * percent; |
628 | rdp.vtxbuf[index].v1 = v2->v1 + (v1->v1 - v2->v1) * percent; |
629 | rdp.vtxbuf[index].b = (wxUint8)(v2->b + (v1->b - v2->b) * percent); |
630 | rdp.vtxbuf[index].g = (wxUint8)(v2->g + (v1->g - v2->g) * percent); |
631 | rdp.vtxbuf[index].r = (wxUint8)(v2->r + (v1->r - v2->r) * percent); |
632 | rdp.vtxbuf[index].a = (wxUint8)(v2->a + (v1->a - v2->a) * percent); |
633 | rdp.vtxbuf[index++].not_zclipped = 0; |
634 | |
635 | // Save the in point |
636 | rdp.vtxbuf[index] = *v2; |
637 | rdp.vtxbuf[index++].not_zclipped = 0; |
638 | } |
639 | } |
640 | } |
641 | rdp.n_global = index; |
642 | |
643 | do_triangle_stuff (linew, TRUE); |
644 | } |
645 | } |
646 | else |
647 | { |
648 | // Set vertex buffers |
649 | rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1 |
650 | rdp.vtxbuf2 = rdp.vtx2; |
651 | rdp.vtx_buffer = 0; |
652 | rdp.n_global = 3; |
653 | |
654 | rdp.vtxbuf[0] = *vtx[0]; |
655 | rdp.vtxbuf[0].number = 1; |
656 | rdp.vtxbuf[1] = *vtx[1]; |
657 | rdp.vtxbuf[1].number = 2; |
658 | rdp.vtxbuf[2] = *vtx[2]; |
659 | rdp.vtxbuf[2].number = 4; |
660 | |
661 | do_triangle_stuff (linew, FALSE); |
662 | } |
663 | } |
664 | |
665 | #define interp2p(a, b, r) (a + (b - a) * r) |
666 | |
667 | //* |
668 | static void InterpolateColors(VERTEX & va, VERTEX & vb, VERTEX & res, float percent) |
669 | { |
670 | res.b = (wxUint8)interp2p(va.b, vb.b, percent); |
671 | res.g = (wxUint8)interp2p(va.g, vb.g, percent);; |
672 | res.r = (wxUint8)interp2p(va.r, vb.r, percent);; |
673 | res.a = (wxUint8)interp2p(va.a, vb.a, percent);; |
674 | res.f = interp2p(va.f, vb.f, percent);; |
675 | } |
676 | //*/ |
677 | // |
678 | // clip_w - clips aint the z-axis |
679 | // |
680 | static void clip_w (int interpolate_colors) |
681 | { |
682 | int i,j,index,n=rdp.n_global; |
683 | float percent; |
684 | // Swap vertex buffers |
685 | VERTEX *tmp = rdp.vtxbuf2; |
686 | rdp.vtxbuf2 = rdp.vtxbuf; |
687 | rdp.vtxbuf = tmp; |
688 | rdp.vtx_buffer ^= 1; |
689 | index = 0; |
690 | |
691 | // Check the vertices for clipping |
692 | for (i=0; i<n; i++) |
693 | { |
694 | j = i+1; |
695 | if (j == 3) j = 0; |
696 | |
697 | if (Vi.w >= 0.01f) |
698 | { |
699 | if (Vj.w >= 0.01f) // Both are in, save the last one |
700 | { |
701 | rdp.vtxbuf[index] = Vj; |
702 | rdp.vtxbuf[index++].not_zclipped = 1; |
703 | } |
704 | else // First is in, second is out, save intersection |
705 | { |
706 | percent = (-Vi.w) / (Vj.w - Vi.w); |
707 | rdp.vtxbuf[index].not_zclipped = 0; |
708 | rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent; |
709 | rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent; |
710 | rdp.vtxbuf[index].z = Vi.z + (Vj.z - Vi.z) * percent; |
711 | rdp.vtxbuf[index].w = 0.01f; |
712 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
713 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
714 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
715 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
716 | if (interpolate_colors) |
717 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
718 | else |
719 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
720 | } |
721 | } |
722 | else |
723 | { |
724 | //if (Vj.w < 0.01f) // Both are out, save nothing |
725 | if (Vj.w >= 0.01f) // First is out, second is in, save intersection & in point |
726 | { |
727 | percent = (-Vj.w) / (Vi.w - Vj.w); |
728 | rdp.vtxbuf[index].not_zclipped = 0; |
729 | rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent; |
730 | rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent; |
731 | rdp.vtxbuf[index].z = Vj.z + (Vi.z - Vj.z) * percent; |
732 | rdp.vtxbuf[index].w = 0.01f; |
733 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
734 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
735 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
736 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
737 | if (interpolate_colors) |
738 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
739 | else |
740 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
741 | |
742 | // Save the in point |
743 | rdp.vtxbuf[index] = Vj; |
744 | rdp.vtxbuf[index++].not_zclipped = 1; |
745 | } |
746 | } |
747 | } |
748 | rdp.n_global = index; |
749 | } |
750 | |
751 | static void render_tri (wxUint16 linew, int old_interpolate); |
752 | |
753 | void do_triangle_stuff (wxUint16 linew, int old_interpolate) // what else?? do the triangle stuff :P (to keep from writing code twice) |
754 | { |
755 | int i; |
756 | |
757 | if (rdp.clip & CLIP_WMIN) |
758 | clip_w (old_interpolate); |
759 | |
760 | float maxZ = (rdp.zsrc != 1) ? rdp.view_trans[2] + rdp.view_scale[2] : rdp.prim_depth; |
761 | |
762 | wxUint8 no_clip = 2; |
763 | for (i=0; i<rdp.n_global; i++) |
764 | { |
765 | if (rdp.vtxbuf[i].not_zclipped)// && rdp.zsrc != 1) |
766 | { |
767 | #ifdef EXTREME_LOGGING |
768 | FRDP (" * NOT ZCLIPPPED: %d\n", rdp.vtxbuf[i].number); |
769 | #endif |
770 | rdp.vtxbuf[i].x = rdp.vtxbuf[i].sx; |
771 | rdp.vtxbuf[i].y = rdp.vtxbuf[i].sy; |
772 | rdp.vtxbuf[i].z = rdp.vtxbuf[i].sz; |
773 | rdp.vtxbuf[i].q = rdp.vtxbuf[i].oow; |
774 | rdp.vtxbuf[i].u0 = rdp.vtxbuf[i].u0_w; |
775 | rdp.vtxbuf[i].v0 = rdp.vtxbuf[i].v0_w; |
776 | rdp.vtxbuf[i].u1 = rdp.vtxbuf[i].u1_w; |
777 | rdp.vtxbuf[i].v1 = rdp.vtxbuf[i].v1_w; |
778 | } |
779 | else |
780 | { |
781 | #ifdef EXTREME_LOGGING |
782 | FRDP (" * ZCLIPPED: %d\n", rdp.vtxbuf[i].number); |
783 | #endif |
784 | rdp.vtxbuf[i].q = 1.0f / rdp.vtxbuf[i].w; |
785 | rdp.vtxbuf[i].x = rdp.view_trans[0] + rdp.vtxbuf[i].x * rdp.vtxbuf[i].q * rdp.view_scale[0] + rdp.offset_x; |
786 | rdp.vtxbuf[i].y = rdp.view_trans[1] + rdp.vtxbuf[i].y * rdp.vtxbuf[i].q * rdp.view_scale[1] + rdp.offset_y; |
787 | rdp.vtxbuf[i].z = rdp.view_trans[2] + rdp.vtxbuf[i].z * rdp.vtxbuf[i].q * rdp.view_scale[2]; |
788 | if (rdp.tex >= 1) |
789 | { |
790 | rdp.vtxbuf[i].u0 *= rdp.vtxbuf[i].q; |
791 | rdp.vtxbuf[i].v0 *= rdp.vtxbuf[i].q; |
792 | } |
793 | if (rdp.tex >= 2) |
794 | { |
795 | rdp.vtxbuf[i].u1 *= rdp.vtxbuf[i].q; |
796 | rdp.vtxbuf[i].v1 *= rdp.vtxbuf[i].q; |
797 | } |
798 | } |
799 | |
800 | if (rdp.zsrc == 1) |
801 | rdp.vtxbuf[i].z = rdp.prim_depth; |
802 | |
803 | // Don't remove clipping, or it will freeze |
804 | if (rdp.vtxbuf[i].x > rdp.clip_max_x) rdp.clip |= CLIP_XMAX; |
805 | if (rdp.vtxbuf[i].x < rdp.clip_min_x) rdp.clip |= CLIP_XMIN; |
806 | if (rdp.vtxbuf[i].y > rdp.clip_max_y) rdp.clip |= CLIP_YMAX; |
807 | if (rdp.vtxbuf[i].y < rdp.clip_min_y) rdp.clip |= CLIP_YMIN; |
808 | if (rdp.vtxbuf[i].z > maxZ) rdp.clip |= CLIP_ZMAX; |
809 | if (rdp.vtxbuf[i].z < 0.0f) rdp.clip |= CLIP_ZMIN; |
810 | no_clip &= rdp.vtxbuf[i].screen_translated; |
811 | } |
812 | if (no_clip) |
813 | rdp.clip = 0; |
814 | else |
815 | { |
816 | if (!settings.clip_zmin) |
817 | rdp.clip &= ~CLIP_ZMIN; |
818 | if (!settings.clip_zmax) |
819 | rdp.clip &= ~CLIP_ZMAX; |
820 | } |
821 | render_tri (linew, old_interpolate); |
822 | } |
823 | |
824 | void do_triangle_stuff_2 (wxUint16 linew) |
825 | { |
826 | rdp.clip = 0; |
827 | |
828 | for (int i=0; i<rdp.n_global; i++) |
829 | { |
830 | // Don't remove clipping, or it will freeze |
831 | if (rdp.vtxbuf[i].x > rdp.clip_max_x) rdp.clip |= CLIP_XMAX; |
832 | if (rdp.vtxbuf[i].x < rdp.clip_min_x) rdp.clip |= CLIP_XMIN; |
833 | if (rdp.vtxbuf[i].y > rdp.clip_max_y) rdp.clip |= CLIP_YMAX; |
834 | if (rdp.vtxbuf[i].y < rdp.clip_min_y) rdp.clip |= CLIP_YMIN; |
835 | } |
836 | |
837 | render_tri (linew, TRUE); |
838 | } |
839 | |
840 | __inline wxUint8 real_to_char(double x) |
841 | { |
842 | return (wxUint8)(((int)floor(x+0.5))&0xFF); |
843 | } |
844 | |
845 | //* |
846 | static void InterpolateColors2(VERTEX & va, VERTEX & vb, VERTEX & res, float percent) |
847 | { |
848 | float w = 1.0f/(va.oow + (vb.oow-va.oow) * percent); |
849 | // res.oow = va.oow + (vb.oow-va.oow) * percent; |
850 | // res.q = res.oow; |
851 | float ba = va.b * va.oow; |
852 | float bb = vb.b * vb.oow; |
853 | res.b = real_to_char(interp2p(ba, bb, percent) * w); |
854 | float ga = va.g * va.oow; |
855 | float gb = vb.g * vb.oow; |
856 | res.g = real_to_char(interp2p(ga, gb, percent) * w); |
857 | float ra = va.r * va.oow; |
858 | float rb = vb.r * vb.oow; |
859 | res.r = real_to_char(interp2p(ra, rb, percent) * w); |
860 | float aa = va.a * va.oow; |
861 | float ab = vb.a * vb.oow; |
862 | res.a = real_to_char(interp2p(aa, ab, percent) * w); |
863 | float fa = va.f * va.oow; |
864 | float fb = vb.f * vb.oow; |
865 | res.f = interp2p(fa, fb, percent) * w; |
866 | /* |
867 | float u0a = va.u0_w * va.oow; |
868 | float u0b = vb.u0_w * vb.oow; |
869 | res.u0 = (u0a + (u0b - u0a) * percent) * w; |
870 | float v0a = va.v0_w * va.oow; |
871 | float v0b = vb.v0_w * vb.oow; |
872 | res.v0 = (v0a + (v0b - v0a) * percent) * w; |
873 | float u1a = va.u1_w * va.oow; |
874 | float u1b = vb.u1_w * vb.oow; |
875 | res.u1 = (u1a + (u1b - u1a) * percent) * w; |
876 | float v1a = va.v1_w * va.oow; |
877 | float v1b = vb.v1_w * vb.oow; |
878 | res.v1 = (v1a + (v1b - v1a) * percent) * w; |
879 | */ |
880 | } |
881 | //*/ |
882 | |
883 | typedef struct { |
884 | float d; //*SEB* was doubles |
885 | float x; |
886 | float y; |
887 | } LineEuqationType; |
888 | |
889 | static float EvaLine(LineEuqationType &li, float x, float y) //*SEB* all double before |
890 | { |
891 | return li.x*x+li.y*y+li.d; |
892 | } |
893 | |
894 | static void Create1LineEq(LineEuqationType &l, VERTEX &v1, VERTEX &v2, VERTEX &v3) |
895 | { |
896 | // Line between (x1,y1) to (x2,y2) |
897 | l.x = v2.sy-v1.sy; |
898 | l.y = v1.sx-v2.sx; |
899 | l.d = -(l.x*v2.sx+(l.y)*v2.sy); |
900 | if (EvaLine(l,v3.sx,v3.sy)*v3.oow < 0) |
901 | { |
902 | l.x = -l.x; |
903 | l.y = -l.y; |
904 | l.d = -l.d; |
905 | } |
906 | } |
907 | |
908 | |
909 | __inline float interp3p(float a, float b, float c, float r1, float r2) //*SEB* r1 and r2 and function was double |
910 | { |
911 | return (a)+(((b)+((c)-(b))*(r2))-(a))*(r1); |
912 | } |
913 | /* |
914 | #define interp3p(a, b, c, r1, r2) \ |
915 | (a+(((b)+((c)-(b))*(r2))-(a))*(r1)) |
916 | */ |
917 | |
918 | static void InterpolateColors3(VERTEX &v1, VERTEX &v2, VERTEX &v3, VERTEX &out) //*SEB* all double before |
919 | { |
920 | |
921 | LineEuqationType line; |
922 | Create1LineEq(line, v2, v3, v1); |
923 | |
924 | float aDot = (out.x*line.x + out.y*line.y); |
925 | float bDot = (v1.sx*line.x + v1.sy*line.y); |
926 | |
927 | float scale1 = ( - line.d - aDot) / ( bDot - aDot ); |
928 | |
929 | float tx = out.x + scale1 * (v1.sx - out.x); |
930 | float ty = out.y + scale1 * (v1.sy - out.y); |
931 | |
932 | float s1 = 101.0, s2 = 101.0; |
933 | float den = tx - v1.sx; |
934 | if (fabsf(den) > 1.0) |
935 | s1 = (out.x-v1.sx)/den; |
936 | if (s1 > 100.0f) |
937 | s1 = (out.y-v1.sy)/(ty-v1.sy); |
938 | |
939 | den = v3.sx - v2.sx; |
940 | if (fabsf(den) > 1.0) |
941 | s2 = (tx-v2.sx)/den; |
942 | if (s2 > 100.0f) |
943 | s2 =(ty-v2.sy)/(v3.sy-v2.sy); |
944 | |
945 | float w = 1.0/interp3p(v1.oow,v2.oow,v3.oow,s1,s2); |
946 | |
947 | out.r = real_to_char(interp3p(v1.r*v1.oow,v2.r*v2.oow,v3.r*v3.oow,s1,s2)*w); |
948 | out.g = real_to_char(interp3p(v1.g*v1.oow,v2.g*v2.oow,v3.g*v3.oow,s1,s2)*w); |
949 | out.b = real_to_char(interp3p(v1.b*v1.oow,v2.b*v2.oow,v3.b*v3.oow,s1,s2)*w); |
950 | out.a = real_to_char(interp3p(v1.a*v1.oow,v2.a*v2.oow,v3.a*v3.oow,s1,s2)*w); |
951 | out.f = (float)(interp3p(v1.f*v1.oow,v2.f*v2.oow,v3.f*v3.oow,s1,s2)*w); |
952 | /* |
953 | out.u0 = interp3p(v1.u0_w*v1.oow,v2.u0_w*v2.oow,v3.u0_w*v3.oow,s1,s2)/oow; |
954 | out.v0 = interp3p(v1.v0_w*v1.oow,v2.v0_w*v2.oow,v3.v0_w*v3.oow,s1,s2)/oow; |
955 | out.u1 = interp3p(v1.u1_w*v1.oow,v2.u1_w*v2.oow,v3.u1_w*v3.oow,s1,s2)/oow; |
956 | out.v1 = interp3p(v1.v1_w*v1.oow,v2.v1_w*v2.oow,v3.v1_w*v3.oow,s1,s2)/oow; |
957 | */ |
958 | } |
959 | |
960 | static void CalculateLOD(VERTEX *v, int n) |
961 | { |
962 | //rdp.update |= UPDATE_TEXTURE; |
963 | /* |
964 | if (rdp.lod_calculated) |
965 | { |
966 | float detailmax; |
967 | if (dc0_detailmax < 0.5) |
968 | detailmax = rdp.lod_fraction; |
969 | else |
970 | detailmax = 1.0f - rdp.lod_fraction; |
971 | grTexDetailControl (GR_TMU0, dc0_lodbias, dc0_detailscale, detailmax); |
972 | if (num_tmu == 2) |
973 | grTexDetailControl (GR_TMU1, dc1_lodbias, dc1_detailscale, detailmax); |
974 | return; |
975 | } |
976 | */ |
977 | float deltaS, deltaT; |
978 | float deltaX, deltaY; |
979 | float deltaTexels, deltaPixels, lodFactor = 0; //*SEB* double before |
980 | float intptr; //*SEB* double before |
981 | float s_scale = rdp.tiles[rdp.cur_tile].width / 255.0f; |
982 | float t_scale = rdp.tiles[rdp.cur_tile].height / 255.0f; |
983 | if (settings.lodmode == 1) |
984 | { |
985 | deltaS = (v[1].u0/v[1].q - v[0].u0/v[0].q) * s_scale; |
986 | deltaT = (v[1].v0/v[1].q - v[0].v0/v[0].q) * t_scale; |
987 | deltaTexels = sqrt( deltaS * deltaS + deltaT * deltaT ); |
988 | |
989 | deltaX = (v[1].x - v[0].x)/rdp.scale_x; |
990 | deltaY = (v[1].y - v[0].y)/rdp.scale_y; |
991 | deltaPixels = sqrt( deltaX * deltaX + deltaY * deltaY ); |
992 | |
993 | lodFactor = deltaTexels / deltaPixels; |
994 | } |
995 | else |
996 | { |
997 | int i, j; |
998 | for (i = 0; i < n; i++) |
999 | { |
1000 | j = (i < n-1) ? i + 1 : 0; |
1001 | |
1002 | deltaS = (v[j].u0/v[j].q - v[i].u0/v[i].q) * s_scale; |
1003 | deltaT = (v[j].v0/v[j].q - v[i].v0/v[i].q) * t_scale; |
1004 | // deltaS = v[j].ou - v[i].ou; |
1005 | // deltaT = v[j].ov - v[i].ov; |
1006 | deltaTexels = sqrt( deltaS * deltaS + deltaT * deltaT ); |
1007 | |
1008 | deltaX = (v[j].x - v[i].x)/rdp.scale_x; |
1009 | deltaY = (v[j].y - v[i].y)/rdp.scale_y; |
1010 | deltaPixels = sqrt( deltaX * deltaX + deltaY * deltaY ); |
1011 | |
1012 | lodFactor += deltaTexels / deltaPixels; |
1013 | } |
1014 | // Divide by n (n edges) to find average |
1015 | lodFactor = lodFactor / n; |
1016 | } |
1017 | int ilod = (int)lodFactor; |
1018 | int lod_tile = min((int)(log10f((float)ilod)/log10f(2.0f)), rdp.cur_tile + rdp.mipmap_level); |
1019 | float lod_fraction = 1.0f; |
1020 | if (lod_tile < rdp.cur_tile + rdp.mipmap_level) |
1021 | { |
1022 | lod_fraction = max((float)modff(lodFactor / powf(2.,lod_tile),&intptr), (float)rdp.prim_lodmin / 255.0f); |
1023 | } |
1024 | float detailmax; |
1025 | if (cmb.dc0_detailmax < 0.5f) |
1026 | detailmax = lod_fraction; |
1027 | else |
1028 | detailmax = 1.0f - lod_fraction; |
1029 | grTexDetailControl (GR_TMU0, cmb.dc0_lodbias, cmb.dc0_detailscale, detailmax); |
1030 | if (voodoo.num_tmu == 2) |
1031 | grTexDetailControl (GR_TMU1, cmb.dc1_lodbias, cmb.dc1_detailscale, detailmax); |
1032 | FRDP("CalculateLOD factor: %f, tile: %d, lod_fraction: %f\n", (float)lodFactor, lod_tile, lod_fraction); |
1033 | } |
1034 | |
1035 | float ScaleZ(float z) |
1036 | { |
1037 | if (settings.n64_z_scale) |
1038 | { |
1039 | int iz = (int)(z*8.0f+0.5f); |
1040 | if (iz < 0) iz = 0; |
1041 | else if (iz >= 0x40000) iz = 0x40000 - 1; |
1042 | return (float)zLUT[iz]; |
1043 | } |
1044 | if (z < 0.0f) return 0.0f; |
1045 | z *= 1.9f; |
1046 | if (z > 65534.0f) return 65534.0f; |
1047 | return z; |
1048 | } |
1049 | |
1050 | static void DepthBuffer(VERTEX * vtx, int n) |
1051 | { |
1052 | if (fb_depth_render_enabled && !(settings.hacks&hack_RE2) && dzdx && (rdp.flags & ZBUF_UPDATE)) |
1053 | { |
1054 | vertexi v[12]; |
1055 | if (u_cull_mode == 1) //cull front |
1056 | { |
1057 | for(int i=0; i<n; i++) |
1058 | { |
1059 | v[i].x = (int)((vtx[n-i-1].x-rdp.offset_x) / rdp.scale_x * 65536.0); |
1060 | v[i].y = (int)((vtx[n-i-1].y-rdp.offset_y) / rdp.scale_y * 65536.0); |
1061 | v[i].z = (int)(vtx[n-i-1].z * 65536.0); |
1062 | } |
1063 | } |
1064 | else |
1065 | { |
1066 | for(int i=0; i<n; i++) |
1067 | { |
1068 | v[i].x = (int)((vtx[i].x-rdp.offset_x) / rdp.scale_x * 65536.0); |
1069 | v[i].y = (int)((vtx[i].y-rdp.offset_y) / rdp.scale_y * 65536.0); |
1070 | v[i].z = (int)(vtx[i].z * 65536.0); |
1071 | } |
1072 | } |
1073 | Rasterize(v, n, dzdx); |
1074 | } |
1075 | for(int i=0; i<n; i++) |
1076 | vtx[i].z = ScaleZ(vtx[i].z); |
1077 | } |
1078 | |
1079 | /* |
1080 | std::ofstream loga; |
1081 | #define LOGG(x) loga.open("glide_log.txt",std::ios::app); loga << x; loga.flush(); loga.close(); |
1082 | __inline void FRDP2(char *fmt, ...) |
1083 | { |
1084 | va_list ap; |
1085 | va_start(ap, fmt); |
1086 | vsprintf(out_buf, fmt, ap); |
1087 | LOGG(out_buf); |
1088 | va_end(ap); |
1089 | } |
1090 | //*/ |
1091 | //#define LOGG(x) |
1092 | //#define FRDP2(x) |
1093 | |
1094 | |
1095 | void clip_tri(int interpolate_colors) |
1096 | { |
1097 | int i,j,index,n=rdp.n_global; |
1098 | float percent; |
1099 | |
1100 | // Check which clipping is needed |
1101 | if (rdp.clip & CLIP_XMAX) // right of the screen |
1102 | { |
1103 | // Swap vertex buffers |
1104 | VERTEX *tmp = rdp.vtxbuf2; |
1105 | rdp.vtxbuf2 = rdp.vtxbuf; |
1106 | rdp.vtxbuf = tmp; |
1107 | rdp.vtx_buffer ^= 1; |
1108 | index = 0; |
1109 | |
1110 | // Check the vertices for clipping |
1111 | for (i=0; i<n; i++) |
1112 | { |
1113 | j = i+1; |
1114 | if (j == n) j = 0; |
1115 | |
1116 | if (Vi.x <= rdp.clip_max_x) |
1117 | { |
1118 | if (Vj.x <= rdp.clip_max_x) // Both are in, save the last one |
1119 | { |
1120 | rdp.vtxbuf[index++] = Vj; |
1121 | } |
1122 | else // First is in, second is out, save intersection |
1123 | { |
1124 | percent = (rdp.clip_max_x - Vi.x) / (Vj.x - Vi.x); |
1125 | rdp.vtxbuf[index].x = rdp.clip_max_x; |
1126 | rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent; |
1127 | rdp.vtxbuf[index].z = Vi.z + (Vj.z - Vi.z) * percent; |
1128 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1129 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1130 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1131 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1132 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1133 | if (interpolate_colors) |
1134 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1135 | else |
1136 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 8; |
1137 | } |
1138 | } |
1139 | else |
1140 | { |
1141 | //if (Vj.x > rdp.clip_max_x) // Both are out, save nothing |
1142 | if (Vj.x <= rdp.clip_max_x) // First is out, second is in, save intersection & in point |
1143 | { |
1144 | percent = (rdp.clip_max_x - Vj.x) / (Vi.x - Vj.x); |
1145 | rdp.vtxbuf[index].x = rdp.clip_max_x; |
1146 | rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent; |
1147 | rdp.vtxbuf[index].z = Vj.z + (Vi.z - Vj.z) * percent; |
1148 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1149 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1150 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1151 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1152 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1153 | if (interpolate_colors) |
1154 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1155 | else |
1156 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 8; |
1157 | |
1158 | // Save the in point |
1159 | rdp.vtxbuf[index++] = Vj; |
1160 | } |
1161 | } |
1162 | } |
1163 | n = index; |
1164 | } |
1165 | if (rdp.clip & CLIP_XMIN) // left of the screen |
1166 | { |
1167 | // Swap vertex buffers |
1168 | VERTEX *tmp = rdp.vtxbuf2; |
1169 | rdp.vtxbuf2 = rdp.vtxbuf; |
1170 | rdp.vtxbuf = tmp; |
1171 | rdp.vtx_buffer ^= 1; |
1172 | index = 0; |
1173 | |
1174 | // Check the vertices for clipping |
1175 | for (i=0; i<n; i++) |
1176 | { |
1177 | j = i+1; |
1178 | if (j == n) j = 0; |
1179 | |
1180 | if (Vi.x >= rdp.clip_min_x) |
1181 | { |
1182 | if (Vj.x >= rdp.clip_min_x) // Both are in, save the last one |
1183 | { |
1184 | rdp.vtxbuf[index++] = Vj; |
1185 | } |
1186 | else // First is in, second is out, save intersection |
1187 | { |
1188 | percent = (rdp.clip_min_x - Vi.x) / (Vj.x - Vi.x); |
1189 | rdp.vtxbuf[index].x = rdp.clip_min_x; |
1190 | rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent; |
1191 | rdp.vtxbuf[index].z = Vi.z + (Vj.z - Vi.z) * percent; |
1192 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1193 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1194 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1195 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1196 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1197 | if (interpolate_colors) |
1198 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1199 | else |
1200 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 8; |
1201 | } |
1202 | } |
1203 | else |
1204 | { |
1205 | //if (Vj.x < rdp.clip_min_x) // Both are out, save nothing |
1206 | if (Vj.x >= rdp.clip_min_x) // First is out, second is in, save intersection & in point |
1207 | { |
1208 | percent = (rdp.clip_min_x - Vj.x) / (Vi.x - Vj.x); |
1209 | rdp.vtxbuf[index].x = rdp.clip_min_x; |
1210 | rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent; |
1211 | rdp.vtxbuf[index].z = Vj.z + (Vi.z - Vj.z) * percent; |
1212 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1213 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1214 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1215 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1216 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1217 | if (interpolate_colors) |
1218 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1219 | else |
1220 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 8; |
1221 | |
1222 | // Save the in point |
1223 | rdp.vtxbuf[index++] = Vj; |
1224 | } |
1225 | } |
1226 | } |
1227 | n = index; |
1228 | } |
1229 | if (rdp.clip & CLIP_YMAX) // top of the screen |
1230 | { |
1231 | // Swap vertex buffers |
1232 | VERTEX *tmp = rdp.vtxbuf2; |
1233 | rdp.vtxbuf2 = rdp.vtxbuf; |
1234 | rdp.vtxbuf = tmp; |
1235 | rdp.vtx_buffer ^= 1; |
1236 | index = 0; |
1237 | |
1238 | // Check the vertices for clipping |
1239 | for (i=0; i<n; i++) |
1240 | { |
1241 | j = i+1; |
1242 | if (j == n) j = 0; |
1243 | |
1244 | if (Vi.y <= rdp.clip_max_y) |
1245 | { |
1246 | if (Vj.y <= rdp.clip_max_y) // Both are in, save the last one |
1247 | { |
1248 | rdp.vtxbuf[index++] = Vj; |
1249 | } |
1250 | else // First is in, second is out, save intersection |
1251 | { |
1252 | percent = (rdp.clip_max_y - Vi.y) / (Vj.y - Vi.y); |
1253 | rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent; |
1254 | rdp.vtxbuf[index].y = rdp.clip_max_y; |
1255 | rdp.vtxbuf[index].z = Vi.z + (Vj.z - Vi.z) * percent; |
1256 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1257 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1258 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1259 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1260 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1261 | if (interpolate_colors) |
1262 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1263 | else |
1264 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 16; |
1265 | } |
1266 | } |
1267 | else |
1268 | { |
1269 | //if (Vj.y > rdp.clip_max_y) // Both are out, save nothing |
1270 | if (Vj.y <= rdp.clip_max_y) // First is out, second is in, save intersection & in point |
1271 | { |
1272 | percent = (rdp.clip_max_y - Vj.y) / (Vi.y - Vj.y); |
1273 | rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent; |
1274 | rdp.vtxbuf[index].y = rdp.clip_max_y; |
1275 | rdp.vtxbuf[index].z = Vj.z + (Vi.z - Vj.z) * percent; |
1276 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1277 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1278 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1279 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1280 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1281 | if (interpolate_colors) |
1282 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1283 | else |
1284 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 16; |
1285 | |
1286 | // Save the in point |
1287 | rdp.vtxbuf[index++] = Vj; |
1288 | } |
1289 | } |
1290 | } |
1291 | n = index; |
1292 | } |
1293 | if (rdp.clip & CLIP_YMIN) // bottom of the screen |
1294 | { |
1295 | // Swap vertex buffers |
1296 | VERTEX *tmp = rdp.vtxbuf2; |
1297 | rdp.vtxbuf2 = rdp.vtxbuf; |
1298 | rdp.vtxbuf = tmp; |
1299 | rdp.vtx_buffer ^= 1; |
1300 | index = 0; |
1301 | |
1302 | // Check the vertices for clipping |
1303 | for (i=0; i<n; i++) |
1304 | { |
1305 | j = i+1; |
1306 | if (j == n) j = 0; |
1307 | |
1308 | if (Vi.y >= rdp.clip_min_y) |
1309 | { |
1310 | if (Vj.y >= rdp.clip_min_y) // Both are in, save the last one |
1311 | { |
1312 | rdp.vtxbuf[index++] = Vj; |
1313 | } |
1314 | else // First is in, second is out, save intersection |
1315 | { |
1316 | percent = (rdp.clip_min_y - Vi.y) / (Vj.y - Vi.y); |
1317 | rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent; |
1318 | rdp.vtxbuf[index].y = rdp.clip_min_y; |
1319 | rdp.vtxbuf[index].z = Vi.z + (Vj.z - Vi.z) * percent; |
1320 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1321 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1322 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1323 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1324 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1325 | if (interpolate_colors) |
1326 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1327 | else |
1328 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 16; |
1329 | } |
1330 | } |
1331 | else |
1332 | { |
1333 | //if (Vj.y < rdp.clip_min_y) // Both are out, save nothing |
1334 | if (Vj.y >= rdp.clip_min_y) // First is out, second is in, save intersection & in point |
1335 | { |
1336 | percent = (rdp.clip_min_y - Vj.y) / (Vi.y - Vj.y); |
1337 | rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent; |
1338 | rdp.vtxbuf[index].y = rdp.clip_min_y; |
1339 | rdp.vtxbuf[index].z = Vj.z + (Vi.z - Vj.z) * percent; |
1340 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1341 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1342 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1343 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1344 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1345 | if (interpolate_colors) |
1346 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1347 | else |
1348 | rdp.vtxbuf[index++].number = Vi.number | Vj.number | 16; |
1349 | |
1350 | // Save the in point |
1351 | rdp.vtxbuf[index++] = Vj; |
1352 | } |
1353 | } |
1354 | } |
1355 | n = index; |
1356 | } |
1357 | if (rdp.clip & CLIP_ZMAX) // far plane |
1358 | { |
1359 | // Swap vertex buffers |
1360 | VERTEX *tmp = rdp.vtxbuf2; |
1361 | rdp.vtxbuf2 = rdp.vtxbuf; |
1362 | rdp.vtxbuf = tmp; |
1363 | rdp.vtx_buffer ^= 1; |
1364 | index = 0; |
1365 | float maxZ = rdp.view_trans[2] + rdp.view_scale[2]; |
1366 | |
1367 | // Check the vertices for clipping |
1368 | for (i=0; i<n; i++) |
1369 | { |
1370 | j = i+1; |
1371 | if (j == n) j = 0; |
1372 | |
1373 | if (Vi.z < maxZ) |
1374 | { |
1375 | if (Vj.z < maxZ) // Both are in, save the last one |
1376 | { |
1377 | rdp.vtxbuf[index++] = Vj; |
1378 | } |
1379 | else // First is in, second is out, save intersection |
1380 | { |
1381 | percent = (maxZ - Vi.z) / (Vj.z - Vi.z); |
1382 | rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent; |
1383 | rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent; |
1384 | rdp.vtxbuf[index].z = maxZ - 0.001f; |
1385 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1386 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1387 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1388 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1389 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1390 | if (interpolate_colors) |
1391 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1392 | else |
1393 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
1394 | } |
1395 | } |
1396 | else |
1397 | { |
1398 | //if (Vj.z > maxZ) // Both are out, save nothing |
1399 | if (Vj.z < maxZ) // First is out, second is in, save intersection & in point |
1400 | { |
1401 | percent = (maxZ - Vj.z) / (Vi.z - Vj.z); |
1402 | rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent; |
1403 | rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent; |
1404 | rdp.vtxbuf[index].z = maxZ - 0.001f;; |
1405 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1406 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1407 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1408 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1409 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1410 | if (interpolate_colors) |
1411 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1412 | else |
1413 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
1414 | |
1415 | // Save the in point |
1416 | rdp.vtxbuf[index++] = Vj; |
1417 | } |
1418 | } |
1419 | } |
1420 | n = index; |
1421 | } |
1422 | /* |
1423 | if (rdp.clip & CLIP_ZMIN) // near Z |
1424 | { |
1425 | // Swap vertex buffers |
1426 | VERTEX *tmp = rdp.vtxbuf2; |
1427 | rdp.vtxbuf2 = rdp.vtxbuf; |
1428 | rdp.vtxbuf = tmp; |
1429 | rdp.vtx_buffer ^= 1; |
1430 | index = 0; |
1431 | |
1432 | // Check the vertices for clipping |
1433 | for (i=0; i<n; i++) |
1434 | { |
1435 | j = i+1; |
1436 | if (j == n) j = 0; |
1437 | |
1438 | if (Vi.z >= 0.0f) |
1439 | { |
1440 | if (Vj.z >= 0.0f) // Both are in, save the last one |
1441 | { |
1442 | rdp.vtxbuf[index++] = Vj; |
1443 | } |
1444 | else // First is in, second is out, save intersection |
1445 | { |
1446 | percent = (-Vi.z) / (Vj.z - Vi.z); |
1447 | rdp.vtxbuf[index].x = Vi.x + (Vj.x - Vi.x) * percent; |
1448 | rdp.vtxbuf[index].y = Vi.y + (Vj.y - Vi.y) * percent; |
1449 | rdp.vtxbuf[index].z = 0.0f; |
1450 | rdp.vtxbuf[index].q = Vi.q + (Vj.q - Vi.q) * percent; |
1451 | rdp.vtxbuf[index].u0 = Vi.u0 + (Vj.u0 - Vi.u0) * percent; |
1452 | rdp.vtxbuf[index].v0 = Vi.v0 + (Vj.v0 - Vi.v0) * percent; |
1453 | rdp.vtxbuf[index].u1 = Vi.u1 + (Vj.u1 - Vi.u1) * percent; |
1454 | rdp.vtxbuf[index].v1 = Vi.v1 + (Vj.v1 - Vi.v1) * percent; |
1455 | if (interpolate_colors) |
1456 | InterpolateColors(Vi, Vj, rdp.vtxbuf[index++], percent); |
1457 | else |
1458 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
1459 | } |
1460 | } |
1461 | else |
1462 | { |
1463 | //if (Vj.z < 0.0f) // Both are out, save nothing |
1464 | if (Vj.z >= 0.0f) // First is out, second is in, save intersection & in point |
1465 | { |
1466 | percent = (-Vj.z) / (Vi.z - Vj.z); |
1467 | rdp.vtxbuf[index].x = Vj.x + (Vi.x - Vj.x) * percent; |
1468 | rdp.vtxbuf[index].y = Vj.y + (Vi.y - Vj.y) * percent; |
1469 | rdp.vtxbuf[index].z = 0.0f;; |
1470 | rdp.vtxbuf[index].q = Vj.q + (Vi.q - Vj.q) * percent; |
1471 | rdp.vtxbuf[index].u0 = Vj.u0 + (Vi.u0 - Vj.u0) * percent; |
1472 | rdp.vtxbuf[index].v0 = Vj.v0 + (Vi.v0 - Vj.v0) * percent; |
1473 | rdp.vtxbuf[index].u1 = Vj.u1 + (Vi.u1 - Vj.u1) * percent; |
1474 | rdp.vtxbuf[index].v1 = Vj.v1 + (Vi.v1 - Vj.v1) * percent; |
1475 | if (interpolate_colors) |
1476 | InterpolateColors(Vj, Vi, rdp.vtxbuf[index++], percent); |
1477 | else |
1478 | rdp.vtxbuf[index++].number = Vi.number | Vj.number; |
1479 | |
1480 | // Save the in point |
1481 | rdp.vtxbuf[index++] = Vj; |
1482 | } |
1483 | } |
1484 | } |
1485 | n = index; |
1486 | } |
1487 | */ |
1488 | rdp.n_global = n; |
1489 | } |
1490 | |
1491 | static void render_tri (wxUint16 linew, int old_interpolate) |
1492 | { |
1493 | if (rdp.clip) |
1494 | clip_tri(old_interpolate); |
1495 | int n = rdp.n_global; |
1496 | if (n < 3) |
1497 | { |
1498 | FRDP (" * render_tri: n < 3\n"); |
1499 | return; |
1500 | } |
1501 | int i,j; |
1502 | //* |
1503 | if ((rdp.clip & CLIP_ZMIN) && (rdp.othermode_l & 0x00000030)) |
1504 | { |
1505 | |
1506 | int to_render = FALSE; |
1507 | for (i = 0; i < n; i++) |
1508 | { |
1509 | if (rdp.vtxbuf[i].z >= 0.0f) |
1510 | { |
1511 | to_render = TRUE; |
1512 | break; |
1513 | } |
1514 | } |
1515 | if (!to_render) //all z < 0 |
1516 | { |
1517 | FRDP (" * render_tri: all z < 0\n"); |
1518 | return; |
1519 | } |
1520 | } |
1521 | //*/ |
1522 | if (rdp.clip && !old_interpolate) |
1523 | { |
1524 | for (i = 0; i < n; i++) |
1525 | { |
1526 | float percent = 101.0f; |
1527 | VERTEX * v1 = 0, * v2 = 0; |
1528 | switch (rdp.vtxbuf[i].number&7) |
1529 | { |
1530 | case 1: |
1531 | case 2: |
1532 | case 4: |
1533 | continue; |
1534 | break; |
1535 | case 3: |
1536 | v1 = org_vtx[0]; |
1537 | v2 = org_vtx[1]; |
1538 | break; |
1539 | case 5: |
1540 | v1 = org_vtx[0]; |
1541 | v2 = org_vtx[2]; |
1542 | break; |
1543 | case 6: |
1544 | v1 = org_vtx[1]; |
1545 | v2 = org_vtx[2]; |
1546 | break; |
1547 | case 7: |
1548 | InterpolateColors3(*org_vtx[0], *org_vtx[1], *org_vtx[2], rdp.vtxbuf[i]); |
1549 | continue; |
1550 | break; |
1551 | } |
1552 | switch (rdp.vtxbuf[i].number&24) |
1553 | { |
1554 | case 8: |
1555 | percent = (rdp.vtxbuf[i].x-v1->sx)/(v2->sx-v1->sx); |
1556 | break; |
1557 | case 16: |
1558 | percent = (rdp.vtxbuf[i].y-v1->sy)/(v2->sy-v1->sy); |
1559 | break; |
1560 | default: |
1561 | { |
1562 | float d = (v2->sx-v1->sx); |
1563 | if (fabs(d) > 1.0) |
1564 | percent = (rdp.vtxbuf[i].x-v1->sx)/d; |
1565 | if (percent > 100.0f) |
1566 | percent = (rdp.vtxbuf[i].y-v1->sy)/(v2->sy-v1->sy); |
1567 | } |
1568 | } |
1569 | InterpolateColors2(*v1, *v2, rdp.vtxbuf[i], percent); |
1570 | } |
1571 | } |
1572 | /* |
1573 | if (rdp.clip) |
1574 | { |
1575 | LOGG("Colors before clipping:\n"); |
1576 | unsigned int k; |
1577 | for(k=0; k<3; k++) |
1578 | { |
1579 | FRDP2("V%d: r=%d, g=%d, b=%d, a=%d, f=%d\n", k, org_vtx[k]->r, org_vtx[k]->g, org_vtx[k]->b, org_vtx[k]->a, (short)org_vtx[k]->f); |
1580 | } |
1581 | FRDP("Got %d vertex after clipping\n", n); |
1582 | for(k=0; k<n; k++) |
1583 | { |
1584 | FRDP("V%d: r=%d, g=%d, b=%d, a=%d, f=%d\n", k, rdp.vtxbuf[k].r, rdp.vtxbuf[k].g, rdp.vtxbuf[k].b, rdp.vtxbuf[k].a, (short)rdp.vtxbuf[k].f); |
1585 | } |
1586 | } |
1587 | */ |
1588 | |
1589 | ConvertCoordsConvert (rdp.vtxbuf, n); |
1590 | if (rdp.fog_mode == RDP::fog_enabled) |
1591 | { |
1592 | for (i = 0; i < n; i++) |
1593 | { |
1594 | rdp.vtxbuf[i].f = 1.0f/max(4.0f, rdp.vtxbuf[i].f); |
1595 | } |
1596 | } |
1597 | else if (rdp.fog_mode == RDP::fog_blend) |
1598 | { |
1599 | float fog = 1.0f/max(1, rdp.fog_color&0xFF); |
1600 | for (i = 0; i < n; i++) |
1601 | { |
1602 | rdp.vtxbuf[i].f = fog; |
1603 | } |
1604 | } |
1605 | else if (rdp.fog_mode == RDP::fog_blend_inverse) |
1606 | { |
1607 | float fog = 1.0f/max(1, (~rdp.fog_color)&0xFF); |
1608 | for (i = 0; i < n; i++) |
1609 | { |
1610 | rdp.vtxbuf[i].f = fog; |
1611 | } |
1612 | } |
1613 | |
1614 | if (settings.lodmode > 0 && rdp.cur_tile < rdp.mipmap_level) |
1615 | CalculateLOD(rdp.vtxbuf, n); |
1616 | |
1617 | cmb.cmb_ext_use = cmb.tex_cmb_ext_use = 0; |
1618 | |
1619 | /* |
1620 | if (rdp.tbuff_tex) |
1621 | { |
1622 | for (int k = 0; k < 3; k++) |
1623 | { |
1624 | FRDP("v%d %f->%f, width: %d. height: %d, tex_width: %d, tex_height: %d, lr_u: %f, lr_v: %f\n", k, vv0[k], pv[k]->v1, rdp.tbuff_tex->width, rdp.tbuff_tex->height, rdp.tbuff_tex->tex_width, rdp.tbuff_tex->tex_height, rdp.tbuff_tex->lr_u, rdp.tbuff_tex->lr_v); |
1625 | } |
1626 | } |
1627 | */ |
1628 | if (fullscreen) |
1629 | { |
1630 | if (settings.wireframe) |
1631 | { |
1632 | SetWireframeCol (); |
1633 | for (i=0; i<n; i++) |
1634 | { |
1635 | j = i+1; |
1636 | if (j == n) j = 0; |
1637 | grDrawLine (&rdp.vtxbuf[i], &rdp.vtxbuf[j]); |
1638 | } |
1639 | } |
1640 | else |
1641 | { |
1642 | |
1643 | // VERTEX ** pv = rdp.vtx_buffer?(vtx_list2):(vtx_list1); |
1644 | // for (int k = 0; k < n; k ++) |
1645 | // FRDP ("DRAW[%d]: v.x = %f, v.y = %f, v.z = %f, v.u = %f, v.v = %f\n", k, pv[k]->x, pv[k]->y, pv[k]->z, pv[k]->coord[rdp.t0<<1], pv[k]->coord[(rdp.t0<<1)+1]); |
1646 | // pv[k]->y = settings.res_y - pv[k]->y; |
1647 | |
1648 | if (linew > 0) |
1649 | { |
1650 | VERTEX *V0 = &rdp.vtxbuf[0]; |
1651 | VERTEX *V1 = &rdp.vtxbuf[1]; |
1652 | if (fabs(V0->x - V1->x) < 0.01 && fabs(V0->y - V1->y) < 0.01) |
1653 | V1 = &rdp.vtxbuf[2]; |
1654 | V0->z = ScaleZ(V0->z); |
1655 | V1->z = ScaleZ(V1->z); |
1656 | VERTEX v[4]; |
1657 | v[0] = *V0; |
1658 | v[1] = *V0; |
1659 | v[2] = *V1; |
1660 | v[3] = *V1; |
1661 | float width = linew * 0.25f; |
1662 | if (fabs(V0->y - V1->y) < 0.0001) |
1663 | { |
1664 | v[0].x = v[1].x = V0->x; |
1665 | v[2].x = v[3].x = V1->x; |
1666 | |
1667 | width *= rdp.scale_y; |
1668 | v[0].y = v[2].y = V0->y - width; |
1669 | v[1].y = v[3].y = V0->y + width; |
1670 | } |
1671 | else if (fabs(V0->x - V1->x) < 0.0001) |
1672 | { |
1673 | v[0].y = v[1].y = V0->y; |
1674 | v[2].y = v[3].y = V1->y; |
1675 | |
1676 | width *= rdp.scale_x; |
1677 | v[0].x = v[2].x = V0->x - width; |
1678 | v[1].x = v[3].x = V0->x + width; |
1679 | } |
1680 | else |
1681 | { |
1682 | float dx = V1->x - V0->x; |
1683 | float dy = V1->y - V0->y; |
1684 | float len = sqrtf(dx*dx + dy*dy); |
1685 | float wx = dy * width * rdp.scale_x / len; |
1686 | float wy = dx * width * rdp.scale_y / len; |
1687 | v[0].x = V0->x + wx; |
1688 | v[0].y = V0->y - wy; |
1689 | v[1].x = V0->x - wx; |
1690 | v[1].y = V0->y + wy; |
1691 | v[2].x = V1->x + wx; |
1692 | v[2].y = V1->y - wy; |
1693 | v[3].x = V1->x - wx; |
1694 | v[3].y = V1->y + wy; |
1695 | } |
1696 | grDrawTriangle(&v[0], &v[1], &v[2]); |
1697 | grDrawTriangle(&v[1], &v[2], &v[3]); |
1698 | } |
1699 | else |
1700 | { |
1701 | DepthBuffer(rdp.vtxbuf, n); |
1702 | if ((rdp.rm & 0xC10) == 0xC10) |
1703 | grDepthBiasLevel (-deltaZ); |
1704 | grDrawVertexArray (GR_TRIANGLE_FAN, n, rdp.vtx_buffer?(&vtx_list2):(&vtx_list1)); |
1705 | } |
1706 | } |
1707 | } |
1708 | |
1709 | if (_debugger.capture) add_tri (rdp.vtxbuf, n, TRI_TRIANGLE); |
1710 | } |
1711 | |
1712 | void add_tri (VERTEX *v, int n, int type) |
1713 | { |
1714 | //FRDP ("ENTER (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)\n", v[0].x, v[0].y, v[0].w, |
1715 | // v[1].x, v[1].y, v[1].w, v[2].x, v[2].y, v[2].w); |
1716 | |
1717 | // Debug capture |
1718 | if (_debugger.capture) |
1719 | { |
1720 | rdp.debug_n ++; |
1721 | |
1722 | TRI_INFO *info = new TRI_INFO; |
1723 | info->nv = n; |
1724 | info->v = new VERTEX [n]; |
1725 | memcpy (info->v, v, sizeof(VERTEX)*n); |
1726 | info->cycle_mode = rdp.cycle_mode; |
1727 | info->cycle1 = rdp.cycle1; |
1728 | info->cycle2 = rdp.cycle2; |
1729 | info->uncombined = rdp.uncombined; |
1730 | info->geom_mode = rdp.geom_mode; |
1731 | info->othermode_h = rdp.othermode_h; |
1732 | info->othermode_l = rdp.othermode_l; |
1733 | info->tri_n = rdp.tri_n; |
1734 | info->type = type; |
1735 | |
1736 | for (int i=0; i<2; i++) |
1737 | { |
1738 | int j = rdp.cur_tile+i; |
1739 | if (i == 0) |
1740 | info->t[i].tmu = rdp.t0; |
1741 | else |
1742 | info->t[i].tmu = rdp.t1; |
1743 | info->t[i].cur_cache[0] = rdp.cur_cache_n[rdp.t0]; |
1744 | info->t[i].cur_cache[1] = rdp.cur_cache_n[rdp.t1]; |
1745 | info->t[i].format = rdp.tiles[j].format; |
1746 | info->t[i].size = rdp.tiles[j].size; |
1747 | info->t[i].width = rdp.tiles[j].width; |
1748 | info->t[i].height = rdp.tiles[j].height; |
1749 | info->t[i].line = rdp.tiles[j].line; |
1750 | info->t[i].palette = rdp.tiles[j].palette; |
1751 | info->t[i].clamp_s = rdp.tiles[j].clamp_s; |
1752 | info->t[i].clamp_t = rdp.tiles[j].clamp_t; |
1753 | info->t[i].mirror_s = rdp.tiles[j].mirror_s; |
1754 | info->t[i].mirror_t = rdp.tiles[j].mirror_t; |
1755 | info->t[i].shift_s = rdp.tiles[j].shift_s; |
1756 | info->t[i].shift_t = rdp.tiles[j].shift_t; |
1757 | info->t[i].mask_s = rdp.tiles[j].mask_s; |
1758 | info->t[i].mask_t = rdp.tiles[j].mask_t; |
1759 | info->t[i].ul_s = rdp.tiles[j].ul_s; |
1760 | info->t[i].ul_t = rdp.tiles[j].ul_t; |
1761 | info->t[i].lr_s = rdp.tiles[j].lr_s; |
1762 | info->t[i].lr_t = rdp.tiles[j].lr_t; |
1763 | info->t[i].t_ul_s = rdp.tiles[7].t_ul_s; |
1764 | info->t[i].t_ul_t = rdp.tiles[7].t_ul_t; |
1765 | info->t[i].t_lr_s = rdp.tiles[7].t_lr_s; |
1766 | info->t[i].t_lr_t = rdp.tiles[7].t_lr_t; |
1767 | info->t[i].scale_s = rdp.tiles[j].s_scale; |
1768 | info->t[i].scale_t = rdp.tiles[j].t_scale; |
1769 | } |
1770 | |
1771 | info->fog_color = rdp.fog_color; |
1772 | info->fill_color = rdp.fill_color; |
1773 | info->prim_color = rdp.prim_color; |
1774 | info->blend_color = rdp.blend_color; |
1775 | info->env_color = rdp.env_color; |
1776 | info->prim_lodmin = rdp.prim_lodmin; |
1777 | info->prim_lodfrac = rdp.prim_lodfrac; |
1778 | |
1779 | info->pNext = _debugger.tri_list; |
1780 | _debugger.tri_list = info; |
1781 | |
1782 | if (_debugger.tri_last == NULL) |
1783 | _debugger.tri_last = _debugger.tri_list; |
1784 | } |
1785 | } |
1786 | |
1787 | void update_scissor () |
1788 | { |
1789 | if (rdp.update & UPDATE_SCISSOR) |
1790 | { |
1791 | rdp.update ^= UPDATE_SCISSOR; |
1792 | |
1793 | // KILL the floating point error with 0.01f |
1794 | rdp.scissor.ul_x = (wxUint32)max(min((rdp.scissor_o.ul_x * rdp.scale_x + rdp.offset_x + 0.01f),settings.res_x),0); |
1795 | rdp.scissor.lr_x = (wxUint32)max(min((rdp.scissor_o.lr_x * rdp.scale_x + rdp.offset_x + 0.01f),settings.res_x),0); |
1796 | rdp.scissor.ul_y = (wxUint32)max(min((rdp.scissor_o.ul_y * rdp.scale_y + rdp.offset_y + 0.01f),settings.res_y),0); |
1797 | rdp.scissor.lr_y = (wxUint32)max(min((rdp.scissor_o.lr_y * rdp.scale_y + rdp.offset_y + 0.01f),settings.res_y),0); |
1798 | //grClipWindow specifies the hardware clipping window. Any pixels outside the clipping window are rejected. |
1799 | //Values are inclusive for minimum x and y values and exclusive for maximum x and y values. |
1800 | // grClipWindow (rdp.scissor.ul_x?rdp.scissor.ul_x+1:0, rdp.scissor.ul_y?rdp.scissor.ul_y+1:0, rdp.scissor.lr_x, rdp.scissor.lr_y); |
1801 | if (fullscreen) |
1802 | grClipWindow (rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); |
1803 | FRDP (" |- scissor - (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, |
1804 | rdp.scissor.lr_x, rdp.scissor.lr_y); |
1805 | } |
1806 | } |
1807 | |
1808 | // |
1809 | // update - update states if they need it |
1810 | // |
1811 | |
1812 | typedef struct |
1813 | { |
1814 | unsigned int c2_m2b:2; |
1815 | unsigned int c1_m2b:2; |
1816 | unsigned int c2_m2a:2; |
1817 | unsigned int c1_m2a:2; |
1818 | unsigned int c2_m1b:2; |
1819 | unsigned int c1_m1b:2; |
1820 | unsigned int c2_m1a:2; |
1821 | unsigned int c1_m1a:2; |
1822 | } rdp_blender_setting; |
1823 | |
1824 | void update () |
1825 | { |
1826 | LRDP ("-+ update called\n"); |
1827 | // Check for rendermode changes |
1828 | // Z buffer |
1829 | if (rdp.render_mode_changed & 0x00000C30) |
1830 | { |
1831 | FRDP (" |- render_mode_changed zbuf - decal: %s, update: %s, compare: %s\n", |
1832 | str_yn[(rdp.othermode_l & 0x00000400)?1:0], |
1833 | str_yn[(rdp.othermode_l&0x00000020)?1:0], |
1834 | str_yn[(rdp.othermode_l&0x00000010)?1:0]); |
1835 | |
1836 | rdp.render_mode_changed &= ~0x00000C30; |
1837 | rdp.update |= UPDATE_ZBUF_ENABLED; |
1838 | |
1839 | // Update? |
1840 | if ((rdp.othermode_l & 0x00000020)) |
1841 | rdp.flags |= ZBUF_UPDATE; |
1842 | else |
1843 | rdp.flags &= ~ZBUF_UPDATE; |
1844 | |
1845 | // Compare? |
1846 | if (rdp.othermode_l & 0x00000010) |
1847 | rdp.flags |= ZBUF_COMPARE; |
1848 | else |
1849 | rdp.flags &= ~ZBUF_COMPARE; |
1850 | } |
1851 | |
1852 | // Alpha compare |
1853 | if (rdp.render_mode_changed & 0x00001000) |
1854 | { |
1855 | FRDP (" |- render_mode_changed alpha compare - on: %s\n", |
1856 | str_yn[(rdp.othermode_l&0x00001000)?1:0]); |
1857 | rdp.render_mode_changed &= ~0x00001000; |
1858 | rdp.update |= UPDATE_ALPHA_COMPARE; |
1859 | |
1860 | if (rdp.othermode_l & 0x00001000) |
1861 | rdp.flags |= ALPHA_COMPARE; |
1862 | else |
1863 | rdp.flags &= ~ALPHA_COMPARE; |
1864 | } |
1865 | |
1866 | if (rdp.render_mode_changed & 0x00002000) // alpha cvg sel |
1867 | { |
1868 | FRDP (" |- render_mode_changed alpha cvg sel - on: %s\n", |
1869 | str_yn[(rdp.othermode_l&0x00002000)?1:0]); |
1870 | rdp.render_mode_changed &= ~0x00002000; |
1871 | rdp.update |= UPDATE_COMBINE; |
1872 | rdp.update |= UPDATE_ALPHA_COMPARE; |
1873 | } |
1874 | |
1875 | // Force blend |
1876 | if (rdp.render_mode_changed & 0xFFFF0000) |
1877 | { |
1878 | FRDP (" |- render_mode_changed force_blend - %08lx\n", rdp.othermode_l&0xFFFF0000); |
1879 | rdp.render_mode_changed &= 0x0000FFFF; |
1880 | |
1881 | rdp.fbl_a0 = (wxUint8)((rdp.othermode_l>>30)&0x3); |
1882 | rdp.fbl_b0 = (wxUint8)((rdp.othermode_l>>26)&0x3); |
1883 | rdp.fbl_c0 = (wxUint8)((rdp.othermode_l>>22)&0x3); |
1884 | rdp.fbl_d0 = (wxUint8)((rdp.othermode_l>>18)&0x3); |
1885 | rdp.fbl_a1 = (wxUint8)((rdp.othermode_l>>28)&0x3); |
1886 | rdp.fbl_b1 = (wxUint8)((rdp.othermode_l>>24)&0x3); |
1887 | rdp.fbl_c1 = (wxUint8)((rdp.othermode_l>>20)&0x3); |
1888 | rdp.fbl_d1 = (wxUint8)((rdp.othermode_l>>16)&0x3); |
1889 | |
1890 | rdp.update |= UPDATE_COMBINE; |
1891 | } |
1892 | |
1893 | // Combine MUST go before texture |
1894 | if ((rdp.update & UPDATE_COMBINE) && rdp.allow_combine) |
1895 | { |
1896 | TBUFF_COLOR_IMAGE * aTBuff[2] = {0, 0}; |
1897 | if (rdp.aTBuffTex[0]) |
1898 | aTBuff[rdp.aTBuffTex[0]->tile] = rdp.aTBuffTex[0]; |
1899 | if (rdp.aTBuffTex[1]) |
1900 | aTBuff[rdp.aTBuffTex[1]->tile] = rdp.aTBuffTex[1]; |
1901 | rdp.aTBuffTex[0] = aTBuff[0]; |
1902 | rdp.aTBuffTex[1] = aTBuff[1]; |
1903 | |
1904 | LRDP (" |-+ update_combine\n"); |
1905 | Combine (); |
1906 | } |
1907 | |
1908 | if (rdp.update & UPDATE_TEXTURE) // note: UPDATE_TEXTURE and UPDATE_COMBINE are the same |
1909 | { |
1910 | rdp.tex_ctr ++; |
1911 | if (rdp.tex_ctr == 0xFFFFFFFF) |
1912 | rdp.tex_ctr = 0; |
1913 | |
1914 | TexCache (); |
1915 | if (rdp.noise == RDP::noise_none) |
1916 | rdp.update ^= UPDATE_TEXTURE; |
1917 | } |
1918 | |
1919 | if (fullscreen) |
1920 | { |
1921 | // Z buffer |
1922 | if (rdp.update & UPDATE_ZBUF_ENABLED) |
1923 | { |
1924 | // already logged above |
1925 | rdp.update ^= UPDATE_ZBUF_ENABLED; |
1926 | |
1927 | if (((rdp.flags & ZBUF_ENABLED) || rdp.zsrc == 1) && rdp.cycle_mode < 2) |
1928 | { |
1929 | if (rdp.flags & ZBUF_COMPARE) |
1930 | { |
1931 | switch ((rdp.rm & 0xC00)>>10) { |
1932 | case 0: |
1933 | grDepthBiasLevel(0); |
1934 | grDepthBufferFunction (settings.zmode_compare_less ? GR_CMP_LESS : GR_CMP_LEQUAL); |
1935 | break; |
1936 | case 1: |
1937 | grDepthBiasLevel(-4); |
1938 | grDepthBufferFunction (settings.zmode_compare_less ? GR_CMP_LESS : GR_CMP_LEQUAL); |
1939 | break; |
1940 | case 2: |
1941 | grDepthBiasLevel(settings.ucode == 7 ? -4 : 0); |
1942 | grDepthBufferFunction (GR_CMP_LESS); |
1943 | break; |
1944 | case 3: |
1945 | // will be set dynamically per polygon |
1946 | //grDepthBiasLevel(-deltaZ); |
1947 | grDepthBufferFunction (GR_CMP_LEQUAL); |
1948 | break; |
1949 | } |
1950 | } |
1951 | else |
1952 | { |
1953 | grDepthBiasLevel(0); |
1954 | grDepthBufferFunction (GR_CMP_ALWAYS); |
1955 | } |
1956 | |
1957 | if (rdp.flags & ZBUF_UPDATE) |
1958 | grDepthMask (FXTRUE); |
1959 | else |
1960 | grDepthMask (FXFALSE); |
1961 | } |
1962 | else |
1963 | { |
1964 | grDepthBiasLevel(0); |
1965 | grDepthBufferFunction (GR_CMP_ALWAYS); |
1966 | grDepthMask (FXFALSE); |
1967 | } |
1968 | } |
1969 | |
1970 | // Alpha compare |
1971 | if (rdp.update & UPDATE_ALPHA_COMPARE) |
1972 | { |
1973 | // already logged above |
1974 | rdp.update ^= UPDATE_ALPHA_COMPARE; |
1975 | |
1976 | // if (rdp.acmp == 1 && !(rdp.othermode_l & 0x00002000) && !force_full_alpha) |
1977 | // if (rdp.acmp == 1 && !(rdp.othermode_l & 0x00002000) && (rdp.blend_color&0xFF)) |
1978 | if (rdp.acmp == 1 && !(rdp.othermode_l & 0x00002000) && (!(rdp.othermode_l & 0x00004000) || (rdp.blend_color&0xFF))) |
1979 | { |
1980 | wxUint8 reference = (wxUint8)(rdp.blend_color&0xFF); |
1981 | grAlphaTestFunction (reference ? GR_CMP_GEQUAL : GR_CMP_GREATER); |
1982 | grAlphaTestReferenceValue (reference); |
1983 | FRDP (" |- alpha compare: blend: %02lx\n", reference); |
1984 | } |
1985 | else |
1986 | { |
1987 | if (rdp.flags & ALPHA_COMPARE) |
1988 | { |
1989 | if ((rdp.othermode_l & 0x5000) != 0x5000) |
1990 | { |
1991 | grAlphaTestFunction (GR_CMP_GEQUAL); |
1992 | grAlphaTestReferenceValue (0x20);//0xA0); |
1993 | LRDP (" |- alpha compare: 0x20\n"); |
1994 | } |
1995 | else |
1996 | { |
1997 | grAlphaTestFunction (GR_CMP_GREATER); |
1998 | if (rdp.acmp == 3) |
1999 | { |
2000 | grAlphaTestReferenceValue ((wxUint8)(rdp.blend_color&0xFF)); |
2001 | FRDP (" |- alpha compare: blend: %02lx\n", rdp.blend_color&0xFF); |
2002 | } |
2003 | else |
2004 | { |
2005 | grAlphaTestReferenceValue (0x00); |
2006 | LRDP (" |- alpha compare: 0x00\n"); |
2007 | } |
2008 | } |
2009 | } |
2010 | else |
2011 | { |
2012 | grAlphaTestFunction (GR_CMP_ALWAYS); |
2013 | LRDP (" |- alpha compare: none\n"); |
2014 | } |
2015 | } |
2016 | if (rdp.acmp == 3 && rdp.cycle_mode < 2) |
2017 | { |
2018 | if (grStippleModeExt != 0) |
2019 | { |
2020 | if (settings.old_style_adither || rdp.alpha_dither_mode != 3) { |
2021 | LRDP (" |- alpha compare: dither\n"); |
2022 | grStippleModeExt(settings.stipple_mode); |
2023 | } |
2024 | else |
2025 | grStippleModeExt(GR_STIPPLE_DISABLE); |
2026 | } |
2027 | } |
2028 | else |
2029 | { |
2030 | if (grStippleModeExt) |
2031 | { |
2032 | //LRDP (" |- alpha compare: dither disabled\n"); |
2033 | grStippleModeExt(GR_STIPPLE_DISABLE); |
2034 | } |
2035 | } |
2036 | } |
2037 | // Cull mode (leave this in for z-clipped triangles) |
2038 | if (rdp.update & UPDATE_CULL_MODE) |
2039 | { |
2040 | rdp.update ^= UPDATE_CULL_MODE; |
2041 | wxUint32 mode = (rdp.flags & CULLMASK) >> CULLSHIFT; |
2042 | FRDP (" |- cull_mode - mode: %s\n", str_cull[mode]); |
2043 | switch (mode) |
2044 | { |
2045 | case 0: // cull none |
2046 | case 3: // cull both |
2047 | grCullMode(GR_CULL_DISABLE); |
2048 | break; |
2049 | case 1: // cull front |
2050 | // grCullMode(GR_CULL_POSITIVE); |
2051 | grCullMode(GR_CULL_NEGATIVE); |
2052 | break; |
2053 | case 2: // cull back |
2054 | // grCullMode (GR_CULL_NEGATIVE); |
2055 | grCullMode (GR_CULL_POSITIVE); |
2056 | break; |
2057 | } |
2058 | } |
2059 | |
2060 | //Added by Gonetz. |
2061 | if (settings.fog && (rdp.update & UPDATE_FOG_ENABLED)) |
2062 | { |
2063 | rdp.update ^= UPDATE_FOG_ENABLED; |
2064 | |
2065 | wxUint16 blender = (wxUint16)(rdp.othermode_l >> 16); |
2066 | if (rdp.flags & FOG_ENABLED) |
2067 | { |
2068 | rdp_blender_setting &bl = *(rdp_blender_setting*)(&(blender)); |
2069 | if((rdp.fog_multiplier > 0) && (bl.c1_m1a==3 || bl.c1_m2a == 3 || bl.c2_m1a == 3 || bl.c2_m2a == 3)) |
2070 | { |
2071 | grFogColorValue(rdp.fog_color); |
2072 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
2073 | rdp.fog_mode = RDP::fog_enabled; |
2074 | LRDP("fog enabled \n"); |
2075 | } |
2076 | else |
2077 | { |
2078 | LRDP("fog disabled in blender\n"); |
2079 | rdp.fog_mode = RDP::fog_disabled; |
2080 | grFogMode (GR_FOG_DISABLE); |
2081 | } |
2082 | } |
2083 | else if (blender == 0xc410 || blender == 0xc411 || blender == 0xf500) |
2084 | { |
2085 | grFogColorValue(rdp.fog_color); |
2086 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
2087 | rdp.fog_mode = RDP::fog_blend; |
2088 | LRDP("fog blend \n"); |
2089 | } |
2090 | else if (blender == 0x04d1) |
2091 | { |
2092 | grFogColorValue(rdp.fog_color); |
2093 | grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); |
2094 | rdp.fog_mode = RDP::fog_blend_inverse; |
2095 | LRDP("fog blend \n"); |
2096 | } |
2097 | else |
2098 | { |
2099 | LRDP("fog disabled\n"); |
2100 | rdp.fog_mode = RDP::fog_disabled; |
2101 | grFogMode (GR_FOG_DISABLE); |
2102 | } |
2103 | } |
2104 | } |
2105 | |
2106 | if (rdp.update & UPDATE_VIEWPORT) |
2107 | { |
2108 | rdp.update ^= UPDATE_VIEWPORT; |
2109 | if (fullscreen) |
2110 | { |
2111 | float scale_x = (float)fabs(rdp.view_scale[0]); |
2112 | float scale_y = (float)fabs(rdp.view_scale[1]); |
2113 | |
2114 | rdp.clip_min_x = max((rdp.view_trans[0] - scale_x + rdp.offset_x) / rdp.clip_ratio, 0.0f); |
2115 | rdp.clip_min_y = max((rdp.view_trans[1] - scale_y + rdp.offset_y) / rdp.clip_ratio, 0.0f); |
2116 | rdp.clip_max_x = min((rdp.view_trans[0] + scale_x + rdp.offset_x) * rdp.clip_ratio, settings.res_x); |
2117 | rdp.clip_max_y = min((rdp.view_trans[1] + scale_y + rdp.offset_y) * rdp.clip_ratio, settings.res_y); |
2118 | |
2119 | FRDP (" |- viewport - (%d, %d, %d, %d)\n", (wxUint32)rdp.clip_min_x, (wxUint32)rdp.clip_min_y, (wxUint32)rdp.clip_max_x, (wxUint32)rdp.clip_max_y); |
2120 | if (!rdp.scissor_set) |
2121 | { |
2122 | rdp.scissor.ul_x = (wxUint32)rdp.clip_min_x; |
2123 | rdp.scissor.lr_x = (wxUint32)rdp.clip_max_x; |
2124 | rdp.scissor.ul_y = (wxUint32)rdp.clip_min_y; |
2125 | rdp.scissor.lr_y = (wxUint32)rdp.clip_max_y; |
2126 | grClipWindow (rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); |
2127 | } |
2128 | } |
2129 | } |
2130 | |
2131 | if (rdp.update & UPDATE_SCISSOR) |
2132 | update_scissor (); |
2133 | |
2134 | LRDP (" + update end\n"); |
2135 | } |
2136 | |
2137 | void set_message_combiner () |
2138 | { |
2139 | grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, |
2140 | GR_COMBINE_FACTOR_ONE, |
2141 | GR_COMBINE_LOCAL_NONE, |
2142 | GR_COMBINE_OTHER_TEXTURE, |
2143 | FXFALSE); |
2144 | grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER, |
2145 | GR_COMBINE_FACTOR_ONE, |
2146 | GR_COMBINE_LOCAL_NONE, |
2147 | GR_COMBINE_OTHER_TEXTURE, |
2148 | FXFALSE); |
2149 | if (settings.buff_clear && (settings.show_fps & 0x08)) |
2150 | grAlphaBlendFunction (GR_BLEND_SRC_ALPHA, |
2151 | GR_BLEND_ONE_MINUS_SRC_ALPHA, |
2152 | GR_BLEND_ZERO, |
2153 | GR_BLEND_ZERO); |
2154 | else |
2155 | grAlphaBlendFunction (GR_BLEND_ONE, |
2156 | GR_BLEND_ZERO, |
2157 | GR_BLEND_ZERO, |
2158 | GR_BLEND_ZERO); |
2159 | grAlphaTestFunction (GR_CMP_ALWAYS); |
2160 | if (grStippleModeExt) |
2161 | { |
2162 | grStippleModeExt(GR_STIPPLE_DISABLE); |
2163 | } |
2164 | grTexFilterMode (0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR); |
2165 | grTexCombine (GR_TMU1, |
2166 | GR_COMBINE_FUNCTION_NONE, |
2167 | GR_COMBINE_FACTOR_NONE, |
2168 | GR_COMBINE_FUNCTION_NONE, |
2169 | GR_COMBINE_FACTOR_NONE, |
2170 | FXFALSE, FXFALSE); |
2171 | grTexCombine (GR_TMU0, |
2172 | GR_COMBINE_FUNCTION_LOCAL, |
2173 | GR_COMBINE_FACTOR_NONE, |
2174 | GR_COMBINE_FUNCTION_LOCAL, |
2175 | GR_COMBINE_FACTOR_NONE, |
2176 | FXFALSE, FXFALSE); |
2177 | grTexSource(GR_TMU0, |
2178 | voodoo.tex_min_addr[GR_TMU0] + offset_font, |
2179 | GR_MIPMAPLEVELMASK_BOTH, |
2180 | &fontTex); |
2181 | grFogMode (GR_FOG_DISABLE); |
2182 | } |
2183 | |