2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/portal/portdraw.c,v 1.119 2000/02/19 13:18:57 toml Exp $
10 // dynamic portal/cell-based renderer
39 extern mxs_vector portal_camera_loc
;
40 extern bool show_lightmap
;
56 // Here's the current placement of textures applied to medium
58 PortalCellMotion portal_cell_motion
[MAX_CELL_MOTION
];
60 // We can fiddle this up and down to vary the level of detail.
61 // Higher means more texels. Right now it only affects MIP mapping.
62 // The expected range is 0.8-1.5; the default setting is just what looks
63 // good to me without clobbering the frame rate.
64 float portal_detail_level
= 1.90;
67 #define VISOBJ_NULL (-1)
70 // If this is on, we blow off the usual rendering and use these flags.
71 // Each face is a solid, flat polygons, with a white wireframe outline.
76 #include <dbmem.h> // must be last header!
77 bool draw_solid_by_MIP_level
= FALSE
;
78 bool draw_solid_by_cell
= FALSE
;
79 bool draw_solid_wireframe
= FALSE
;
80 bool draw_solid_by_poly_flags
= FALSE
;
81 bool draw_solid_by_cell_flags
= FALSE
;
82 bool draw_wireframe_around_tmap
= FALSE
;
83 bool draw_wireframe_around_poly
= FALSE
;
84 uint polygon_cell_color
;
85 uint _polygon_cell_flags_color
;
87 #define COLOR_WHITE 0x1ffffff
90 r3s_point
*cur_ph
; // list of pointers to r3s_points for current pool
91 Vector
*cur_pool
; // list of untransformed vectors
93 ushort
*cur_anim_light_index_list
;
94 extern int cur_cell_num
;
96 extern ulong fog_r3_color
; // from portal.c
98 bool portal_clip_poly
= TRUE
;
99 bool portal_render_from_texture
= FALSE
;
102 extern int stat_num_poly_drawn
;
103 extern int stat_num_poly_raw
;
104 extern int stat_num_poly_considered
;
105 extern int stat_num_backface_tests
;
108 ///// determine if a surface is visible /////
109 // This rejects if it is backfacing
110 // right now we use the r3d, which is slow; we should compute
111 // the polygon normal once and use that, and eventually use
112 // the normal cache and make it superfast
116 // is there a reason this isn't a bool?
117 int check_surface_visible(PortalCell
*cell
, PortalPolygonCore
*poly
, int voff
)
119 // evaluate the plane equation for this surface
121 extern mxs_vector portal_camera_loc
;
122 int plane
= poly
->planeid
;
123 PortalPlane
*p
= &cell
->plane_list
[plane
];
124 float dist
= mx_dot_vec(&portal_camera_loc
, &p
->normal
)
127 STAT(++stat_num_backface_tests
;)
132 static double portal_detail_2
, dot_clamp_2
;
133 static double pixel_scale
, pixel_scale_2
;
134 static double premul
, premul2
; // premul2 != premul*premul, not named premul_2
135 void portal_mip_setup(float zoom
)
137 portal_detail_2
= portal_detail_level
* portal_detail_level
;
138 pixel_scale
= zoom
* grd_bm
.w
* (1.0 / 128.0);
139 pixel_scale_2
= pixel_scale
* pixel_scale
;
141 dot_clamp_2
= dot_clamp
* dot_clamp
;
143 premul
= pixel_scale
* portal_detail_level
;
144 premul2
= pixel_scale_2
* portal_detail_2
* dot_clamp_2
;
148 //////////////////////////////////////////////////////////////////
150 ///// render a single region /////
152 bool show_region
, show_portal
, linear_map
=FALSE
;
153 extern void draw_objects_in_node(int n
);
155 uchar
*r_vertex_list
;//, *r_vertex_lighting;
158 // get a transformed vector. since we haven't implemented the cache
159 // yet, we always do it. since the r3d doesn't implement o2c, we just
160 // have to transform two points and subtract them. This will change.
162 mxs_vector
*get_cached_vector(mxs_vector
*where
, mxs_vector
*v
)
164 r3_rotate_o2c(where
, v
);
166 return where
; // should copy it into cache
169 // our 3x3 texture perspective correction matrix
171 // tables mapping lighting values from 0..255 (which is how
172 // we store them in polygons) into floating point 'i' values
173 // appropriate for clipping.
175 float light_mapping
[256];
176 float light_mapping_dithered
[256];
179 int max_draw_polys
= 1024;
181 extern grs_bitmap
*get_cached_surface(PortalPolygonRenderInfo
*render
,
182 PortalLightMap
*lt
, grs_bitmap
*texture
,
187 /* ----- /-/-/-/-/-/-/-/-/ <<< (((((( /\ )))))) >>> \-\-\-\-\-\-\-\-\ ----- *\
189 This draws a wireframe around one polygon (it doesn't have to be
190 one that's normally rendered).
192 \* ----- \-\-\-\-\-\-\-\-\ <<< (((((( \/ )))))) >>> /-/-/-/-/-/-/-/-/ ----- */
193 void draw_polygon_wireframe(r3s_phandle
*points
, int num_points
, uint color
)
197 r3_set_color(guiScreenColor(color
));
198 r3_set_line_context(R3_LN_FLAT
);
201 for (p1
= 0; p1
< num_points
; p1
++) {
202 r3_draw_line(points
[p1
], points
[p2
]);
209 void draw_polygon_vertices(r3s_phandle
*points
, int num_points
, uint color
)
213 r3_set_color(guiScreenColor(color
));
215 num_points
= r3_clip_polygon(num_points
, points
, &points
);
219 // find center point of polygon
222 for (p1
= 0; p1
< num_points
; p1
++) {
223 cx
+= points
[p1
]->grp
.sx
;
224 cy
+= points
[p1
]->grp
.sy
;
230 // now draw all the vertices, displaced towards the center
232 for (p1
= 0; p1
< num_points
; p1
++) {
233 r3s_point temp
= *points
[p1
];
235 double dx
= (cx
- temp
.grp
.sx
);
236 double dy
= (cy
- temp
.grp
.sy
);
237 double len
= sqrt(dx
*dx
+ dy
*dy
);
238 // displace by at most 3, and at least len/2
240 if (len
/2 < fix_make(VERT_DIST
,0)) {
241 temp
.grp
.sx
= temp
.grp
.sx
+ dx
/2;
242 temp
.grp
.sy
= temp
.grp
.sy
+ dy
/2;
244 temp
.grp
.sx
= temp
.grp
.sx
+ (dx
/len
) * fix_make(VERT_DIST
,0);
245 temp
.grp
.sy
= temp
.grp
.sy
+ (dy
/len
) * fix_make(VERT_DIST
,0);
248 r3_draw_point(&temp
);
254 /* ----- /-/-/-/-/-/-/-/-/ <<< (((((( /\ )))))) >>> \-\-\-\-\-\-\-\-\ ----- *\
256 When we're showing the polygons in the visualization tools, each
257 visible face is a flat, unshaded polygon with a wireframe border.
259 The context constants come from x:\prj\tech\libsrc\r3d\prim.h.
261 \* ----- \-\-\-\-\-\-\-\-\ <<< (((((( \/ )))))) >>> /-/-/-/-/-/-/-/-/ ----- */
262 void draw_polygon_outline(PortalPolygonCore
*poly
, r3s_phandle
*points
,
263 uint polygon_color
, uint outline_color
)
265 int num_points
= poly
->num_vertices
;
267 // Here's our polygon.
268 r3_set_clipmode(R3_CLIP
);
269 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_UNLIT
| R3_PL_SOLID
);
270 r3_set_color(guiScreenColor(polygon_color
));
272 r3_draw_poly(poly
->num_vertices
, points
);
274 // And here go the lines.
275 draw_polygon_wireframe(points
, num_points
, outline_color
);
279 /* ----- /-/-/-/-/-/-/-/-/ <<< (((((( /\ )))))) >>> \-\-\-\-\-\-\-\-\ ----- *\
281 The only difference between one visualization tool and the next is
282 the color of the polygons. We return TRUE if we draw a flat poly.
284 \* ----- \-\-\-\-\-\-\-\-\ <<< (((((( \/ )))))) >>> /-/-/-/-/-/-/-/-/ ----- */
285 bool poly_outline_by_flags(PortalPolygonCore
*poly
, r3s_phandle
*points
,
288 if (draw_solid_by_MIP_level
) {
290 int light_level
= 32;
291 for (i
= MIP_level
; i
< 4; i
++)
293 draw_polygon_outline(poly
, points
,
294 uiRGB(light_level
, light_level
, light_level
),
295 uiRGB(light_level
+ 48, light_level
+ 48,
300 if (draw_solid_by_cell
) {
301 //draw_polygon_outline(poly, points, cur_cell->refs ? COLOR_WHITE : polygon_cell_color, COLOR_WHITE);
302 draw_polygon_outline(poly
, points
, polygon_cell_color
, COLOR_WHITE
);
306 if (draw_solid_wireframe
) {
307 draw_polygon_outline(poly
, points
, 0, COLOR_WHITE
);
311 if (draw_solid_by_poly_flags
) {
312 draw_polygon_outline(poly
, points
, poly
->flags
, COLOR_WHITE
);
316 if (draw_solid_by_cell_flags
) {
317 draw_polygon_outline(poly
, points
, _polygon_cell_flags_color
,
328 extern int portal_clip_num
;
331 extern BOOL g_zbuffer
;
333 extern int portal_hack_blend
;
337 #define TEST_TEXTURE 1
339 extern ushort
portal_color_convert(ushort
);
341 static r3s_point bt_verts
[4];
342 static r3s_phandle bt_vlist
[4] = { bt_verts
+0, bt_verts
+1, bt_verts
+2, bt_verts
+3 };
344 static grs_bitmap blend_texture
;
345 void portal_do_blendtest(void)
349 ushort blend_tex_out
[16];
351 r3s_texture texture
= portal_get_texture(TEST_TEXTURE
);
353 if (!g_lgd3d
) return;
357 r3_set_texture(texture
);
359 bt_verts
[0].p
.z
= bt_verts
[1].p
.z
=
360 bt_verts
[2].p
.z
= bt_verts
[3].p
.z
= 1.0;
361 bt_verts
[0].grp
.w
= bt_verts
[1].grp
.w
=
362 bt_verts
[2].grp
.w
= bt_verts
[3].grp
.w
= 1.0;
364 bt_verts
[0].grp
.sx
= bt_verts
[3].grp
.sx
= fix_make(10,0);
365 bt_verts
[1].grp
.sx
= bt_verts
[2].grp
.sx
= fix_make(60,0);
366 bt_verts
[0].grp
.sy
= bt_verts
[1].grp
.sy
= fix_make(10,0);
367 bt_verts
[2].grp
.sy
= bt_verts
[3].grp
.sy
= fix_make(60,0);
369 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_GOURAUD
);
370 bt_verts
[0].grp
.i
= bt_verts
[1].grp
.i
= 0;
371 bt_verts
[2].grp
.i
= bt_verts
[3].grp
.i
= 1.0;
373 bt_verts
[0].grp
.u
= bt_verts
[3].grp
.u
= 0;
374 bt_verts
[1].grp
.u
= bt_verts
[2].grp
.u
= 1;
375 bt_verts
[0].grp
.v
= bt_verts
[1].grp
.v
= 0;
376 bt_verts
[2].grp
.v
= bt_verts
[3].grp
.v
= 1;
378 r3_draw_poly(4, bt_vlist
);
380 bt_verts
[0].grp
.sx
= bt_verts
[3].grp
.sx
= fix_make(10+80,0);
381 bt_verts
[1].grp
.sx
= bt_verts
[2].grp
.sx
= fix_make(60+80,0);
383 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_UNLIT
);
384 r3_draw_poly(4, bt_vlist
);
386 bt_verts
[0].grp
.u
= bt_verts
[3].grp
.u
= 0.25 * 0.5;
387 bt_verts
[1].grp
.u
= bt_verts
[2].grp
.u
= 0.25 * 0.5;
388 bt_verts
[0].grp
.v
= bt_verts
[1].grp
.v
= 0.25 * 0.5;
389 bt_verts
[2].grp
.v
= bt_verts
[3].grp
.v
= 1 - 0.25*1.5;
391 // build lightmap texture in device space
392 gr_init_bitmap(&blend_texture
, (char *) blend_tex_out
, BMT_FLAT32
, 0, 4, 4);
394 /* @TODO: figger out what todo.
395 blend_tex_out[0] = portal_color_convert(0);
396 blend_tex_out[4] = portal_color_convert(15+15*32+15*32*32);
397 blend_tex_out[8] = portal_color_convert(31+31*32+31*32*32);
399 blend_tex_out
[2] = blend_tex_out
[1] = blend_tex_out
[0];
400 blend_tex_out
[6] = blend_tex_out
[5] = blend_tex_out
[4];
401 blend_tex_out
[10] = blend_tex_out
[9] = blend_tex_out
[8];
402 blend_tex_out
[12] = blend_tex_out
[8];
404 lgd3d_blend_multiply(portal_hack_blend
);
405 lgd3d_set_blend(TRUE
);
406 lgd3d_set_alpha(0.5);
407 r3_set_texture(&blend_texture
);
408 r3_draw_poly(4, bt_vlist
);
409 lgd3d_blend_normal();
410 lgd3d_set_blend(FALSE
);
411 lgd3d_set_alpha(1.0);
415 lgd3d_unload_texture(&blend_texture
);
417 ushort blend_tex_out
[16];
419 r3s_texture texture
= portal_get_texture(TEST_TEXTURE
);
421 if (!g_lgd3d
) return;
425 r3_set_texture(texture
);
427 bt_verts
[0].p
.z
= bt_verts
[1].p
.z
=
428 bt_verts
[2].p
.z
= bt_verts
[3].p
.z
= 1.0;
429 bt_verts
[0].grp
.w
= bt_verts
[1].grp
.w
=
430 bt_verts
[2].grp
.w
= bt_verts
[3].grp
.w
= 1.0;
432 bt_verts
[0].grp
.sx
= bt_verts
[3].grp
.sx
= fix_make(10,0);
433 bt_verts
[1].grp
.sx
= bt_verts
[2].grp
.sx
= fix_make(60,0);
434 bt_verts
[0].grp
.sy
= bt_verts
[1].grp
.sy
= fix_make(10,0);
435 bt_verts
[2].grp
.sy
= bt_verts
[3].grp
.sy
= fix_make(60,0);
437 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_GOURAUD
);
438 bt_verts
[0].grp
.i
= bt_verts
[1].grp
.i
= 0;
439 bt_verts
[2].grp
.i
= bt_verts
[3].grp
.i
= 1.0;
441 bt_verts
[0].grp
.u
= bt_verts
[3].grp
.u
= 0;
442 bt_verts
[1].grp
.u
= bt_verts
[2].grp
.u
= 1;
443 bt_verts
[0].grp
.v
= bt_verts
[1].grp
.v
= 0;
444 bt_verts
[2].grp
.v
= bt_verts
[3].grp
.v
= 1;
446 r3_draw_poly(4, bt_vlist
);
448 bt_verts
[0].grp
.sx
= bt_verts
[3].grp
.sx
= fix_make(10+80,0);
449 bt_verts
[1].grp
.sx
= bt_verts
[2].grp
.sx
= fix_make(60+80,0);
451 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_UNLIT
);
452 r3_draw_poly(4, bt_vlist
);
454 bt_verts
[0].grp
.u
= bt_verts
[3].grp
.u
= 0.25 * 0.5;
455 bt_verts
[1].grp
.u
= bt_verts
[2].grp
.u
= 0.25 * 0.5;
456 bt_verts
[0].grp
.v
= bt_verts
[1].grp
.v
= 0.25 * 0.5;
457 bt_verts
[2].grp
.v
= bt_verts
[3].grp
.v
= 1 - 0.25*1.5;
459 // build lightmap texture in device space
460 gr_init_bitmap(&blend_texture
, (char *) blend_tex_out
, BMT_FLAT16
, 0, 4, 4);
462 blend_tex_out
[0] = portal_color_convert(0);
463 blend_tex_out
[4] = portal_color_convert(15+15*32+15*32*32);
464 blend_tex_out
[8] = portal_color_convert(31+31*32+31*32*32);
465 blend_tex_out
[2] = blend_tex_out
[1] = blend_tex_out
[0];
466 blend_tex_out
[6] = blend_tex_out
[5] = blend_tex_out
[4];
467 blend_tex_out
[10] = blend_tex_out
[9] = blend_tex_out
[8];
468 blend_tex_out
[12] = blend_tex_out
[8];
470 lgd3d_blend_multiply(portal_hack_blend
);
471 lgd3d_set_blend(TRUE
);
472 lgd3d_set_alpha(0.5);
473 r3_set_texture(&blend_texture
);
474 r3_draw_poly(4, bt_vlist
);
475 lgd3d_blend_normal();
476 lgd3d_set_blend(FALSE
);
477 lgd3d_set_alpha(1.0);
481 lgd3d_unload_texture(&blend_texture
);
488 extern void do_poly_linear(r3s_texture tex
, int n
, r3s_phandle
*vpl
, fix u_offset
, fix v_offset
);
490 // compute the P,M,N vectors and hand them to portal-tmappers
492 void compute_tmapping(PortalPolygonRenderInfo
*render
, uchar not_light
,
493 PortalLightMap
*lt
, r3s_point
*anchor_point
)
495 // compute texture mapping data by getting our u,v vectors,
496 // the anchor point, and the translation values, and translating
497 // the anchor point by the translation lengths
498 mxs_vector u_vec
, v_vec
, pt
;
501 usc
= ((float) render
->u_base
) * 1.0 / (16.0*256.0); // u translation
502 vsc
= ((float) render
->v_base
) * 1.0 / (16.0*256.0); // v translation
505 usc
-= ((float) lt
->base_u
) * 0.25;
506 vsc
-= ((float) lt
->base_v
) * 0.25;
509 get_cached_vector(&u_vec
, &render
->tex_u
);
510 get_cached_vector(&v_vec
, &render
->tex_v
);
511 mx_scale_add_vec(&pt
, &anchor_point
->p
, &u_vec
, -usc
);
512 mx_scale_add_vec(&pt
, &pt
, &v_vec
, -vsc
);
514 // This gives us our 3x3 texture perspective correction matrix.
515 g2pt_calc_uvw_deltas(&pt
, &u_vec
, &v_vec
);
520 int compute_mip3(PortalPolygonRenderInfo
*render
, PortalPlane
*p
)
522 // this is the fast way, which doesn't need to take a sqrt
523 // the slow way, which makes some sense, appears at end of file
526 mx_sub_vec(&eye
, &portal_camera_loc
, &render
->center
);
528 a
= mx_mag2_vec(&eye
);
529 b
= mx_dot_vec(&eye
, &p
->normal
);
531 if (b
* b
>= a
*dot_clamp_2
) {
532 d
= premul
* b
* render
->texture_mag
;
533 // do first test because it doesn't require multiplies
534 if (d
>= a
) return 0;
535 // now binary search the remaining ones
537 return d
>= a
*0.125 ? 3 : 4;
539 return d
>= a
*0.5 ? 1 : 2;
541 d
= premul2
* render
->texture_mag
* render
->texture_mag
;
542 if (d
>= a
) return 0;
544 return d
>= a
*0.125*0.125 ? 3 : 4;
546 return d
>= a
*0.5*0.5 ? 1 : 2;
550 int compute_mip(PortalPolygonRenderInfo
*render
, PortalPlane
*p
)
555 mx_sub_vec(&eye
, &portal_camera_loc
, &render
->center
);
556 dist
= mx_mag_vec(&eye
);
558 k
= mx_dot_vec(&eye
, &p
->normal
); // k/dist == foreshortening amount
560 // estimate distance to nearest point
561 dist
= dist
- render
->texture_mag
*2*(1-k
/dist
);
562 if (dist
<= 0) return 0;
564 // compute foreshortening amount, note this uses post-modified
565 // dist, which is geometrically correct if the post-modified dist
566 // weren't an approximation
568 if (k
> 1.0) k
= 1.0;
570 sz
= premul
* render
->texture_mag
/ dist
;
572 if (k
< dot_clamp
) k
= dot_clamp
;
575 if (sz
>= 1.0) return 0;
576 if (sz
>= 0.5) return 1;
577 if (sz
>= 0.25) return 2;
578 if (sz
>= 0.125) return 3;
582 extern void render_background_hack_clipped(int n
, r3s_phandle
*vlist
);
583 extern int portbg_clip_sky(int, r3s_phandle
*, r3s_phandle
**);
585 // from portal.c. True if we are drawing new-style sky
586 extern BOOL bRenderNewSky
;
588 void draw_background_hack(int n
, r3s_phandle
*vlist
)
590 r3s_point
*ph
= cur_ph
;
591 Vector
*pool
= cur_pool
;
592 PortalCell
*cell
= cur_cell
;
593 ushort
*anim_light_index_list
= cur_anim_light_index_list
;
595 uchar
*vertex_list
= r_vertex_list
;
597 render_background_hack_clipped(n
,vlist
);
602 cur_anim_light_index_list
= anim_light_index_list
;
604 r_vertex_list
= vertex_list
;
607 extern int portal_sky_id
;
608 extern int portal_sky_spans
;
610 // returns FALSE if it was totally transparent; return TRUE if it was
611 // non-transparent, even if not visible (e.g. clipped away)
613 bool draw_surface(PortalPolygonCore
*poly
, PortalPolygonRenderInfo
*render
,
614 PortalLightMap
*lt
, int voff
, void *clip
)
617 int desired_mip
, mip_level
;
620 fix corner_u_offset
, corner_v_offset
;
622 bool position_from_motion
= FALSE
;
623 r3s_phandle vlist
[MAX_VERT
], *valid3d
, *final
;
625 // get the raw, unlit texture
626 texture
= portal_get_texture(render
->texture_id
);
627 // It is our impression (wsf) that this only happens for the sky hack:
628 if (!texture
&& !bRenderNewSky
) {
629 n
= poly
->num_vertices
;
630 for (i
=0; i
< n
; ++i
)
631 vlist
[i
] = &cur_ph
[r_vertex_list
[voff
+ i
]];
633 // clip against the view cone
634 n2
= r3_clip_polygon(n
, vlist
, &valid3d
);
635 if (n2
<= 2) { END_PROF
; return TRUE
; }
636 STAT(++stat_num_poly_considered
;)
638 if (portal_clip_poly
) {
639 // clip against the portal
640 n3
= portclip_clip_polygon(n2
, valid3d
, &final
, clip
);
641 if (n3
<= 2) { END_PROF
; return TRUE
; }
648 draw_background_hack(n3
, final
);
649 return FALSE
; // an invisible portal, or background hack
652 not_light
= (lt
== NULL
) || (poly
->flags
& RENDER_DOESNT_LIGHT
);
654 // prepare the vertex list
655 n
= poly
->num_vertices
;
656 if (n
> MAX_VERT
) Error(1, "draw_surface: too many vertices.\n");
658 for (i
=0; i
< n
; ++i
)
659 vlist
[i
] = &cur_ph
[r_vertex_list
[voff
+ i
]];
661 // clip against the view cone
662 n2
= r3_clip_polygon(n
, vlist
, &valid3d
);
663 if (n2
<= 2) { END_PROF
; return TRUE
; }
664 STAT(++stat_num_poly_considered
;)
666 if (portal_clip_poly
) {
667 // clip against the portal
668 n3
= portclip_clip_polygon(n2
, valid3d
, &final
, clip
);
669 if (n3
<= 2) { END_PROF
; return TRUE
; }
675 if (portal_clip_num
) { // only true if it's the sky
676 n3
= portbg_clip_sky(n3
, final
, &final
);
679 desired_mip
= compute_mip(render
, &cur_cell
->plane_list
[poly
->planeid
]);
681 while (desired_mip
> 0) {
682 if (texture
[1].w
== 0) break; // not enough mip levels
687 sc
= 64 >> mip_level
; // texture->w;
691 ++stat_num_poly_drawn
;
692 if (stat_num_poly_drawn
> max_draw_polys
) return TRUE
;
696 if (poly_outline_by_flags(poly
, vlist
, mip_level
)) {
703 if (texture
->w
& (texture
->w
- 1))
704 Error(1, "Texture non-power-of-two in w!\n");
705 if (texture
->h
& (texture
->h
- 1))
706 Error(1, "Texture non-power-of-two in h!\n");
709 if ((poly
->motion_index
)
710 && (portal_cell_motion
[poly
->motion_index
].in_motion
)) {
711 mxs_vector u_vec
, v_vec
, pt
;
713 portal_position_portal_texture(&u_vec
, &v_vec
, &pt
,
714 &(cur_pool
[r_vertex_list
[voff
+ render
->texture_anchor
]]),
715 render
, &cur_cell
->plane_list
[poly
->planeid
],
716 &portal_cell_motion
[poly
->motion_index
]);
718 g2pt_calc_uvw_deltas(&pt
, &u_vec
, &v_vec
);
719 position_from_motion
= TRUE
;
721 compute_tmapping(render
, not_light
, lt
, vlist
[render
->texture_anchor
]);
723 // rescale based on mipmap scaling
724 for(i
=0; i
< 3; ++i
) {
725 g2pt_tmap_data
[3*i
] *= sc
;
726 g2pt_tmap_data
[3*i
+1] *= sc
;
729 // bug: if not lighting, don't deref 'lt'!!!
731 corner_u_offset
= corner_v_offset
= 0;
734 corner_u_offset
= corner_v_offset
= fix_make(2, 0);
735 // go get it from surface cache or light it or whatever
736 tex
= get_cached_surface(render
, lt
, texture
, mip_level
);
739 // This should only happen if the lightmap is too big, which
740 // should only happen when someone's fiddling with the texture
741 // scale in the editor.
743 corner_u_offset
= corner_v_offset
= 0;
750 if ((render
->texture_id
== portal_sky_id
) && !bRenderNewSky
)
752 switch (ptsky_type
) {
754 portal_sky_spans
+= ptsky_calc_spans(n3
, final
);
760 else if (portal_sky_spans
> 0)
762 ptsky_render_stars();
763 portal_sky_spans
= 0;
767 do_poly_linear(tex
, n3
, final
, corner_u_offset
, corner_v_offset
);
769 g2pt_poly_perspective_uv(tex
, n3
, final
,
770 corner_u_offset
, corner_v_offset
, FALSE
);
774 if (draw_wireframe_around_tmap
)
775 draw_polygon_wireframe(vlist
, poly
->num_vertices
, COLOR_WHITE
);
777 if (draw_wireframe_around_tmap
) {
778 draw_polygon_wireframe(final
, n3
, COLOR_WHITE
+2);
779 draw_polygon_vertices(final
, n3
, COLOR_WHITE
);
789 void draw_wireframe(PortalPolygonCore
*p
, int voff
, uint color
)
794 r3_set_color(guiScreenColor(color
));
796 for (i
=0; i
< n
; ++i
) {
797 r3_draw_line(&cur_ph
[r_vertex_list
[voff
+i
]],
798 &cur_ph
[r_vertex_list
[voff
+j
]]);
804 void draw_cell_wireframe(PortalCell
*cell
, uint color
)
809 r3_set_clipmode(NEED_CLIP(cell
) ? R3_CLIP
: R3_NO_CLIP
);
812 for (i
=0; i
< cell
->num_polys
; ++i
) {
813 draw_wireframe(&cell
->poly_list
[i
], voff
, color
);
814 voff
+= cell
->poly_list
[i
].num_vertices
;
820 //// A hacked system for mapping distance in water to a clut id
822 static water_clut
[32] =
824 0,0,1,1, 2,2,3,3, 4,4,5,5, 5,6,6,6,
825 7,7,7,8, 8,8,9,9, 9,10,10,10, 10,11,11,11
828 int compute_water_clut(mxs_real water_start
, mxs_real water_end
)
833 // compute the clut to use after passing through water
834 // at distance water_start to water_end
836 len
= (water_end
- water_start
)*10.0;
838 if (len
> 255) len
= 255;
839 if (len
< 0) len
= 0;
841 return water_clut
[len
>> 3];
843 // explicitly force the clut to an amount at a middling
844 // distance under the old system
845 return water_clut
[64 >> 3];
849 static void draw_many_objects(void);
851 extern bool background_needs_clut
;
852 extern uchar background_clut
[];
853 extern bool g2pt_span_clip
;
855 // preload lightmaps for a single region
856 void portal_preload_lightmaps(int cell
)
862 PortalPolygonCore
*poly
;
863 PortalPolygonRenderInfo
*render
;
864 PortalLightMap
*light
;
867 n
= r
->num_render_polys
;
868 light
= r
->light_list
;
870 if (r
->num_full_bright
|| portal_render_from_texture
|| (n
==0) || (light
==NULL
))
875 render
= r
->render_list
;
880 cur_anim_light_index_list
= r
->anim_light_index_list
;
881 r_vertex_list
= r
->vertex_list
;
882 light_bitmask
= r
->changed_anim_light_bitmask
;
885 if (light
->anim_light_bitmask
& light_bitmask
)
886 porthw_uncache_lightmap(render
);
888 if (!(poly
->flags
& RENDER_DOESNT_LIGHT
))
889 if (check_surface_visible(r
, poly
, voff
))
890 porthw_preload_lightmap(render
, light
);
892 voff
+= poly
->num_vertices
;
897 r
->changed_anim_light_bitmask
= 0;
901 extern void draw_surface_lgd3d(
902 PortalPolygonCore
*poly
,
903 PortalPolygonRenderInfo
*render
,
908 BOOL portal_draw_lgd3d
= TRUE
;
909 BOOL portal_punt_draw_surface
= FALSE
;
911 static void check_and_draw_surface(
912 PortalPolygonCore
*poly
,
913 PortalPolygonRenderInfo
*render
,
914 PortalLightMap
*light
,
918 if ((!portal_punt_draw_surface
) && check_surface_visible(r
, poly
, voff
))
920 draw_surface_lgd3d(poly
, render
, light
, voff
, CLIP_DATA(r
));
922 draw_surface(poly
, render
, light
, voff
, CLIP_DATA(r
));
926 /* ----- /-/-/-/-/-/-/-/-/ <<< (((((( /\ )))))) >>> \-\-\-\-\-\-\-\-\ ----- *\
930 \* ----- \-\-\-\-\-\-\-\-\ <<< (((((( \/ )))))) >>> /-/-/-/-/-/-/-/-/ ----- */
931 extern void uncache_surface(PortalPolygonRenderInfo
*);
932 void draw_region(int cell
)
935 PortalCell
*r
= WR_CELL(cell
);
936 int n
= r
->num_render_polys
;
938 PortalPolygonCore
*poly
= r
->poly_list
;
939 PortalPolygonRenderInfo
*render
= r
->render_list
;
940 PortalLightMap
*light
= r
->light_list
;
944 if (r
->num_full_bright
|| portal_render_from_texture
)
945 light
= NULL
; // disable lighting if any light_brights shining on
947 // maybe i fixed this now, but it's a waste of time probably
948 // if (!n && OBJECTS(r) == 0) { END_PROF; return; }
950 // copy common data into globals for efficient communicating
951 // someday we should inline the function "draw_surface" and
952 // then get rid of these globals
957 cur_anim_light_index_list
= r
->anim_light_index_list
;
958 r_vertex_list
= r
->vertex_list
;
960 r_clip
= CLIP_DATA(r
);
962 // if we end in water, then we have to do a clut for
963 // this water which we haven't already added to our clut list
964 // note that you probably need to read the clut tree document
965 // to understand what's going on here.
967 if (r
->medium
== 255)
968 g2pt_clut
= pt_clut_list
[255]; // background?
971 int mot
= r
->motion_index
;
975 clut
= pt_motion_haze_clut
[mot
];
978 clut
= pt_medium_haze_clut
[r
->medium
];
981 temp
.clut_id
= clut
+ compute_water_clut(ZWATER(r
), DIST(r
));
983 // this is a bit bogus, we shoud really do per-poly not per-cell
984 temp
.next
= CLUT(r
).clut_id
? &CLUT(r
) : 0;
985 g2pt_clut
= pt_get_clut(&temp
);
986 } else if (CLUT(r
).clut_id
) {
987 g2pt_clut
= pt_get_clut(&CLUT(r
));
993 // if span clipping, draw the objects first
994 if (g2pt_span_clip
&& OBJECTS(r
) >= 0)
995 // at least one object
998 if (!n
&& !(r
->flags
& CELL_OBSCURED
)) goto skip_poly_draw
;
1001 stat_num_poly_raw
+= n
;
1004 // setup our default clip parameters (since we don't use
1005 // primitives, just the clipper, this isn't set automagically).
1006 // we could set it once elsewhere, and if we have self-lit polys
1007 // we might want to set it every poly. setting it here makes
1008 // us interact safely with object rendering.
1009 r3_set_clip_flags(0);
1013 // The other polygon outline tools are handled in draw_surface().
1014 if (draw_solid_by_cell
|| draw_wireframe_around_poly
) {
1015 polygon_cell_color
= (((uint
) (r
->sphere_center
.x
* 85.12737321727
1016 - r
->sphere_center
.y
* 123.33228937433)
1017 ^ (uint
)(r
->sphere_center
.z
* 311.22029342383)
1018 ^ r
->num_portal_polys
1019 ^ (r
->num_render_polys
<< 8)
1020 ^ (r
->num_polys
<< 12)
1021 ^ r
->num_vertices
) & 0xffffff) | 0x1000000;
1024 if (draw_solid_by_cell_flags
)
1025 _polygon_cell_flags_color
= (r
->flags
) << 8;
1029 // now draw all the polygons
1032 r3_set_clipmode(NEED_CLIP(r
) ? R3_CLIP
: R3_NO_CLIP
);
1035 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_UNLIT
);
1037 lgd3d_set_fog_enable(!!(CELL_FLAGS(r
) & CELL_FOG
));
1041 uint light_bitmask
= r
->changed_anim_light_bitmask
;
1044 if (light
->anim_light_bitmask
& light_bitmask
)
1045 uncache_surface(render
);
1047 check_and_draw_surface(poly
, render
, light
, voff
, r
);
1048 voff
+= poly
->num_vertices
;
1053 r
->changed_anim_light_bitmask
= 0;
1056 check_and_draw_surface(poly
, render
, NULL
, voff
, r
);
1057 voff
+= poly
->num_vertices
;
1063 // In hardware, if we're not going to draw terrain here then we
1064 // need to set the z for this cell the old-fashioned way.
1065 if (g_lgd3d
&& (r
->flags
& CELL_OBSCURED
)) {
1066 r3s_phandle vlist
[MAX_VERT
];
1067 int i
, num_vertices
;
1071 if (r->flags & CELL_FOGGED_OUT) {
1072 color = fog_r3_color;
1073 r->flags &= ~CELL_FOGGED_OUT;
1076 r3_set_color(guiScreenColor(color
));
1078 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_UNLIT
| R3_PL_SOLID
);
1080 voff
= r
->portal_vertex_list
;
1081 poly
= r
->portal_poly_list
;
1082 n
= r
->num_portal_polys
;
1084 lgd3d_disable_palette();
1087 num_vertices
= poly
->num_vertices
;
1089 if (check_surface_visible(r
, poly
, voff
)) {
1090 for (i
= 0; i
< num_vertices
; ++i
)
1091 vlist
[i
] = &cur_ph
[r_vertex_list
[voff
+ i
]];
1093 r3_draw_poly(num_vertices
, vlist
);
1096 voff
+= num_vertices
;
1100 lgd3d_enable_palette();
1108 if (r
->flags
& (CELL_RENDER_WIREFRAME
| CELL_RENDER_WIREFRAME_ONCE
)
1109 || draw_wireframe_around_poly
) {
1110 draw_cell_wireframe(r
, COLOR_WHITE
);
1111 r
->flags
&= ~CELL_RENDER_WIREFRAME_ONCE
;
1115 if (!g2pt_span_clip
&& OBJECTS(r
) >= 0)
1116 draw_many_objects();
1119 portal_sfx_callback(cell
);
1124 extern void draw_surface_multitexture(
1125 PortalPolygonCore
*poly
,
1126 PortalPolygonRenderInfo
*render
,
1131 extern void draw_surface_lightmap_only(
1132 PortalPolygonCore
*poly
,
1133 PortalPolygonRenderInfo
*render
,
1138 extern void draw_surface_texture_only(
1139 PortalPolygonCore
*poly
,
1140 PortalPolygonRenderInfo
*render
,
1144 BOOL portal_multitexture
= FALSE
;
1145 extern bool punt_hardware_lighting
;
1147 void draw_region_lgd3d(int cell
)
1150 PortalCell
*r
= WR_CELL(cell
);
1151 int n
= r
->num_render_polys
;
1153 PortalPolygonCore
*poly
= r
->poly_list
;
1154 PortalPolygonRenderInfo
*render
= r
->render_list
;
1155 PortalLightMap
*light
= r
->light_list
;
1157 // copy common data into globals for efficient communicating
1158 // someday we should inline the function "draw_surface" and
1159 // then get rid of these globals
1162 cur_pool
= r
->vpool
;
1164 r_vertex_list
= r
->vertex_list
;
1166 r_clip
= CLIP_DATA(r
);
1168 if (!n
&& !(r
->flags
& CELL_OBSCURED
)) goto skip_poly_draw1
;
1171 stat_num_poly_raw
+= n
;
1174 // setup our default clip parameters (since we don't use
1175 // primitives, just the clipper, this isn't set automagically).
1176 // we could set it once elsewhere, and if we have self-lit polys
1177 // we might want to set it every poly. setting it here makes
1178 // us interact safely with object rendering.
1179 r3_set_clip_flags(0);
1183 // The other polygon outline tools are handled in draw_surface().
1184 if (draw_solid_by_cell
|| draw_wireframe_around_poly
) {
1185 polygon_cell_color
= (((uint
) (r
->sphere_center
.x
* 85.12737321727
1186 - r
->sphere_center
.y
* 123.33228937433)
1187 ^ (uint
)(r
->sphere_center
.z
* 311.22029342383)
1188 ^ r
->num_portal_polys
1189 ^ (r
->num_render_polys
<< 8)
1190 ^ (r
->num_polys
<< 12)
1191 ^ r
->num_vertices
) & 0xffffff) | 0x1000000;
1194 if (draw_solid_by_cell_flags
)
1195 _polygon_cell_flags_color
= (r
->flags
) << 8;
1199 // now draw all the polygons
1202 r3_set_clipmode(NEED_CLIP(r
) ? R3_CLIP
: R3_NO_CLIP
);
1206 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_UNLIT
);
1208 lgd3d_set_fog_enable(!!(CELL_FLAGS(r
) & CELL_FOG
));
1209 if (portal_multitexture
)
1210 { // we're doing single pass, multi-texturing!
1213 if (check_surface_visible(r
, poly
, voff
))
1214 draw_surface_multitexture(poly
, render
, light
, voff
, CLIP_DATA(r
));
1216 voff
+= poly
->num_vertices
;
1222 { // two pass, texture first
1224 if ((!portal_punt_draw_surface
) && check_surface_visible(r
, poly
, voff
))
1225 draw_surface_texture_only(poly
, render
, voff
, CLIP_DATA(r
));
1226 voff
+= poly
->num_vertices
;
1231 // if we're not zbuffering, we need to do lightmaps immediately;
1232 // otherwise they get done in a completely seperate pass
1233 // (see draw_region_lightmap_only())
1234 if ((!g_zbuffer
)&&(!punt_hardware_lighting
))
1236 n
= r
->num_render_polys
;
1237 poly
= r
->poly_list
;
1238 render
= r
->render_list
;
1241 lgd3d_blend_multiply(portal_hack_blend
);
1242 lgd3d_set_blend(TRUE
);
1244 lgd3d_set_alpha(0.5);
1247 if (!(poly
->flags
& RENDER_DOESNT_LIGHT
))
1248 if (check_surface_visible(r
, poly
, voff
))
1249 draw_surface_lightmap_only(poly
, render
, light
, voff
, CLIP_DATA(r
));
1251 voff
+= poly
->num_vertices
;
1256 lgd3d_blend_normal();
1257 lgd3d_set_blend(FALSE
);
1259 lgd3d_set_alpha(1.0);
1265 // In hardware, if we're not going to draw terrain here then we
1266 // need to set the z for this portal the old-fashioned way.
1267 if (g_lgd3d
&& (r
->flags
& CELL_OBSCURED
)) {
1268 r3s_phandle vlist
[MAX_VERT
];
1269 int i
, num_vertices
;
1273 if (r->flags & CELL_FOGGED_OUT) {
1274 color = fog_r3_color;
1275 r->flags &= ~CELL_FOGGED_OUT;
1278 // r3_set_color(guiScreenColor(color));
1279 r3_set_color( color
);
1281 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_UNLIT
| R3_PL_SOLID
);
1283 voff
= r
->portal_vertex_list
;
1284 poly
= r
->portal_poly_list
;
1285 n
= r
->num_portal_polys
;
1287 lgd3d_disable_palette();
1290 num_vertices
= poly
->num_vertices
;
1292 if (check_surface_visible(r
, poly
, voff
)) {
1293 for (i
= 0; i
< num_vertices
; ++i
)
1294 vlist
[i
] = &cur_ph
[r_vertex_list
[voff
+ i
]];
1296 r3_draw_poly(num_vertices
, vlist
);
1299 voff
+= num_vertices
;
1303 lgd3d_enable_palette();
1311 if (r
->flags
& (CELL_RENDER_WIREFRAME
| CELL_RENDER_WIREFRAME_ONCE
)
1312 || draw_wireframe_around_poly
) {
1313 draw_cell_wireframe(r
, COLOR_WHITE
);
1314 r
->flags
&= ~CELL_RENDER_WIREFRAME_ONCE
;
1318 if (OBJECTS(r
) >= 0)
1319 draw_many_objects();
1322 portal_sfx_callback(cell
);
1327 void draw_region_lightmap_only(int cell
)
1330 PortalCell
*r
= WR_CELL(cell
);
1331 int n
= r
->num_render_polys
;
1333 PortalPolygonCore
*poly
= r
->poly_list
;
1334 PortalPolygonRenderInfo
*render
= r
->render_list
;
1335 PortalLightMap
*light
= r
->light_list
;
1337 if (r
->num_full_bright
|| portal_render_from_texture
|| (light
==NULL
))
1340 // copy common data into globals for efficient communicating
1341 // someday we should inline the function "draw_surface" and
1342 // then get rid of these globals
1345 cur_pool
= r
->vpool
;
1347 cur_anim_light_index_list
= r
->anim_light_index_list
;
1348 r_vertex_list
= r
->vertex_list
;
1350 r_clip
= CLIP_DATA(r
);
1353 stat_num_poly_raw
+= n
;
1356 r3_set_clip_flags(0);
1359 r3_set_clipmode(NEED_CLIP(r
) ? R3_CLIP
: R3_NO_CLIP
);
1361 r3_set_polygon_context(R3_PL_POLYGON
| R3_PL_TEXTURE
| R3_PL_UNLIT
);
1363 lgd3d_set_fog_enable(!!(CELL_FLAGS(r
) & CELL_FOG
));
1366 if (!(poly
->flags
& RENDER_DOESNT_LIGHT
))
1367 if (check_surface_visible(r
, poly
, voff
))
1368 draw_surface_lightmap_only(poly
, render
, light
, voff
, CLIP_DATA(r
));
1370 voff
+= poly
->num_vertices
;
1383 // can't be bigger than 64 due to sorting limitation!
1384 // see sBlockedBits below!
1385 #define MAX_SORTED_OBJS 64
1387 Position
* portal_object_pos_default(ObjID obj
)
1389 static Position pos
;
1393 Position
* (*portal_object_pos
)(ObjID obj
) = portal_object_pos_default
;
1395 static int obj_compare(ObjVisibleID p
, ObjVisibleID q
)
1397 extern mxs_vector portal_camera_loc
;
1398 ObjID x
= vis_objs
[p
].obj
;
1399 ObjID y
= vis_objs
[q
].obj
;
1401 // compute distance from camera
1405 dist1
= mx_dist2_vec(&portal_camera_loc
, &portal_object_pos(x
)->loc
.vec
);
1406 dist2
= mx_dist2_vec(&portal_camera_loc
, &portal_object_pos(y
)->loc
.vec
);
1411 return dist1
> dist2
;
1414 typedef struct sBlockedBits
1419 // nByte !! yields 0 or 1:
1420 // nSetBit is nBit shifted by 32 if nByte is 1, else not shifted
1421 #define SetBlockedBit(bits, nBit) \
1422 nByte = !!(nBit>>32); \
1423 nSetBit = nBit>>(nByte<<5); \
1424 bits.Bits[nByte] |= nSetBit
1426 // Assumes bit is set:
1427 #define ResetBlockedBit(bits, nBit) \
1428 nByte = !!(nBit>>32); \
1429 nSetBit = nBit>>(nByte<<5); \
1430 bits.Bits[nByte] ^= nSetBit
1432 // Just stuff a 0 there.
1433 #define ZeroBlockedBit(bits, nBit) \
1434 nByte = !!(nBit>>32); \
1435 nSetBit = nBit>>(nByte<<5); \
1436 bits.Bits[nByte] &= ~nSetBit
1438 // Returns last rvalue in sequence, and performs operations first to last:
1439 #define IsBitSet(bits, nBit) \
1440 (nByte = !!(nBit>>32), \
1441 nSetBit = nBit>>(nByte<<5), \
1442 bits.Bits[nByte] & nSetBit)
1444 void topological_sort(ObjVisibleID
*obj_list
, int n
)
1449 ulong nByte
; // Helper for macros
1450 ulong nSetBit
; // Helper for macros
1452 sBlockedBits blocked
[MAX_SORTED_OBJS
];
1455 // used to be this, which gave us at most 32 objects we could sort:
1456 // ulong blocked[MAX_SORTED_OBJS];
1458 ObjVisibleID my_list
[MAX_SORTED_OBJS
];
1460 // we should special case 2 (and maybe 3) objects!
1462 if (n
> MAX_SORTED_OBJS
) n
= MAX_SORTED_OBJS
;
1464 memcpy(my_list
, obj_list
, sizeof(my_list
[0])*n
);
1466 memset(blocked
, 0, sizeof(sBlockedBits
)*MAX_SORTED_OBJS
);
1468 // Well, it turns out player is always in way of camera. Because we're hardware, we only
1469 // really need to sort objects that are alpha, yet this sorter sorts ALL objects, which is
1470 // unnecessary. We should move sorting into rendobj level, and only sort alpha objects.
1473 // collect all n^2 comparison data
1474 for (x
=0; x
< n
; ++x
) {
1475 b
.Bits
[0] = b
.Bits
[1] = 0;
1476 for (y
=0; y
< n
; ++y
) {
1477 if (x
!= y
&& portal_object_blocks(vis_objs
[obj_list
[y
]].obj
,
1478 vis_objs
[obj_list
[x
]].obj
)) {
1479 // check if they form a cycle
1480 // if (y < x && (blocked[y] & (1 << x))) {
1481 if (y
< x
&& IsBitSet(blocked
[y
], (1<<x
))) {
1482 // they do, so they're too close to each other...
1483 // compare their centers: dist-x > dist-y ???
1484 if (obj_compare(obj_list
[x
],obj_list
[y
]) > 0) {
1485 // y is closer, so no x blocks y
1486 ResetBlockedBit(blocked
[y
],(1<<x
));
1487 SetBlockedBit(b
, (1<<y
));
1488 // blocked[y] ^= 1 << x;
1489 // b |= 1 << y; // yes y blocks x
1491 // else say x blocks y (already coded), and no y blocks x
1493 // no cycle, so y blocks x
1494 SetBlockedBit(b
, (1<<y
));
1501 // ok, now we know everything. search for somebody who is
1503 for (i
=0; i
< n
; ++i
) {
1505 for (j
=0; j
< n
; ++j
)
1506 if (my_list
[j
] != VISOBJ_NULL
&& !blocked
[j
].Bits
[0] && !blocked
[j
].Bits
[1])
1507 // if (my_list[j] != VISOBJ_NULL && !blocked[j])
1509 // nobody is unblocked... oops... must break cycle
1510 // we should use farthest guy, but let's just hack it
1512 // mprintf("Breaking object-sorting cycle.\n");
1515 for (j
=0; j
< n
; ++j
)
1516 if (my_list
[j
] != VISOBJ_NULL
)
1518 Error(1, "Ran out of objects inside object sorter.");
1521 obj_list
[i
] = my_list
[j
];
1522 my_list
[j
] = VISOBJ_NULL
;
1523 blocked
[j
].Bits
[0] = blocked
[j
].Bits
[1] = 0;
1525 // unblock anybody this guy blocked
1528 for (j
=0; j
< n
; ++j
)
1529 ZeroBlockedBit(blocked
[j
], nVal
);
1530 // if (blocked[j] & b)
1535 extern bool obj_dealt
[]; // HACK: need real object dealt flags
1536 extern bool obj_hide
[]; // HACK
1537 void core_render_object(ObjVisibleID id
, uchar
*clut
)
1539 if (!obj_hide
[vis_objs
[id
].obj
])
1540 portal_render_object(vis_objs
[id
].obj
, clut
, vis_objs
[id
].fragment
);
1541 obj_dealt
[vis_objs
[id
].obj
] = 0;
1544 extern long (*portal_get_time
)(void);
1545 extern int stat_num_object_ms
;
1546 bool disable_topsort
;
1547 static void draw_many_objects(void)
1549 PortalCell
*r
= cur_cell
;
1550 ObjVisibleID id
= OBJECTS(r
);
1551 uchar
*clut
= g2pt_clut
;
1552 ObjVisibleID obj_list
[MAX_SORTED_OBJS
];
1555 if (portal_sky_spans
> 0)
1556 ptsky_render_stars();
1559 stat_num_object_ms
-= portal_get_time();
1562 // reset the polygon context so the fact we
1563 // stuffed the r3_clip_flags won't screw us up...
1564 // there must be a better way to do this...
1566 r3_set_polygon_context(0);
1568 // because portal goes behind r3d's back to access g2 directly,
1569 // we need to set this flag as well
1570 r3d_do_setup
= TRUE
;
1573 // put the first MAX_SORTED_OBJS in an array
1575 while (id
>= 0 && num
< MAX_SORTED_OBJS
) {
1576 if (!obj_hide
[vis_objs
[id
].obj
])
1577 obj_list
[num
++] = id
;
1579 obj_dealt
[vis_objs
[id
].obj
] = 0;
1580 id
= vis_objs
[id
].next_visobj
;
1583 // if there are still more objects, just render 'em
1586 Warning(("draw_many_objects: Too many objects to sort.\n"));
1587 core_render_object(id
, clut
);
1588 id
= vis_objs
[id
].next_visobj
;
1591 // now sort and draw the remaining objects
1594 core_render_object(obj_list
[0], clut
);
1597 // wsf: if we're in hardware, don't need to sort all objects. We're moving sort
1598 // into rendobj level, and only sorting alpha objects, that don't write into z-buffer.
1599 if (!disable_topsort
&& !g_lgd3d
)
1600 topological_sort(obj_list
, num
);
1602 // the order of drawing should depend on render_back_to_front-ness
1603 for (i
=num
-1; i
>= 0; --i
)
1604 core_render_object(obj_list
[i
], clut
);
1608 stat_num_object_ms
+= portal_get_time();
1611 // restore g2pt_clut in case object rendering trashed it
1615 BOOL
sphere_intersects_plane(mxs_vector
*center
, float radius
, PortalPlane
*p
)
1617 // compute distance from sphere center to plane
1618 float dist
= mx_dot_vec(center
, &p
->normal
) + p
->plane_constant
;
1620 // if sphere is at least radius away, don't bother
1624 // if sphere is at least radius _behind_ the plane, we don't need
1625 // to draw anything, but (a) that should never happen, and (b) we
1626 // don't have a distinct return value to indicate it, anyway
1631 #define FLOAT_PTR_NEG(x) (* (int *) (x) < -0.005)
1633 BOOL
bbox_intersects_plane(mxs_vector
*bbox_min
, mxs_vector
*bbox_max
,
1639 // find the point as far _behind_ the plane as possible
1641 if (FLOAT_PTR_NEG(&p
->normal
.x
))
1642 temp
.x
= bbox_max
->x
;
1644 temp
.x
= bbox_min
->x
;
1646 if (FLOAT_PTR_NEG(&p
->normal
.y
))
1647 temp
.y
= bbox_max
->y
;
1649 temp
.y
= bbox_min
->y
;
1651 if (FLOAT_PTR_NEG(&p
->normal
.z
))
1652 temp
.z
= bbox_max
->z
;
1654 temp
.z
= bbox_min
->z
;
1656 dist
= mx_dot_vec(&temp
, &p
->normal
) + p
->plane_constant
;
1663 static int num_pushed
;
1665 void portal_push_clip_planes(
1666 mxs_vector
*bbox_min
, mxs_vector
*bbox_max
,
1667 mxs_vector
*sphere_center
, float radius
)
1669 int i
,plane_count
= cur_cell
->num_planes
;
1670 PortalPlane
*pl
= cur_cell
->plane_list
;
1673 for (i
=0; i
< plane_count
; ++i
, ++pl
) {
1675 if (sphere_center
&& !sphere_intersects_plane(sphere_center
, radius
, pl
))
1677 if (bbox_min
&& !bbox_intersects_plane(bbox_min
, bbox_max
, pl
))
1683 p
.d
= pl
->plane_constant
+0.002;
1684 r3_push_clip_plane(&p
);
1688 void portal_pop_clip_planes(void)
1691 for (i
=0; i
< num_pushed
; ++i
)
1692 r3_pop_clip_plane();
1696 ////////// code that could probably be deleted /////////
1698 // (old palette-based lighting stuff)
1700 static float rescale(float val
, float *map
)
1702 // find where 'val' is from 0..32
1706 if (val
== 1.0) return 1.0;
1708 for (i
=0; val
>= map
[i
]; ++i
);
1709 // ok, now val < map[i]
1712 // map[i] <= val < map[i+1]
1714 // now determine where val occurs if it were linear interpolated
1715 // map[i] + where * (map[j] - map[i]) == val
1717 where
= (val
- map
[i
]) / (map
[i
+1] - map
[i
]);
1718 return (where
+ i
) / 32.0;
1722 // is any of this used in the new regime?
1723 uchar length_mapping
[1024];
1724 void init_portal_shading(int dark
, int light
)
1728 float last
, step
, cur
, val
;
1731 // map 0 -> dark + 0.5
1732 // map 128 -> light + 0.5
1734 // i/128 * (light - dark) + dark + 0.5
1736 // except we want to remap them to account for
1737 // nonlinearity; i/128 -> 0..1, but now we want
1738 // to deal with the fact that the output device
1739 // really takes x (0..1) and computes
1740 // a decaying series, 0.1 ^ (1-x), which outputs
1743 // Closed form this seems messy, so I'll use a lookup
1746 // first compute the table which decays the way the
1747 // real thing decays
1750 // cur * step^32 == 0.1
1752 // step = (0.1)^1/32
1754 step
= pow(0.1, 1.0/32);
1756 for (i
=32; i
>= 0; --i
) {
1757 // rescale it from 0.1--1.0 into 0.0--1.0
1758 val
= (cur
-0.1)/0.9;
1765 for (i
=0; i
< 128; ++i
)
1767 (rescale((float) i
/ 128.0, map
) * (light
- dark
)
1768 + dark
+ 0.5) * 65536;
1770 last
= light_mapping
[i
-1];
1771 for ( ; i
< 256; ++i
)
1772 light_mapping
[i
] = last
;
1774 for (i
=0; i
< 256; ++i
)
1775 light_mapping_dithered
[i
] = light_mapping
[i
]*2;
1777 for (i
=1; i
<= 16; ++i
)
1778 length_mapping
[i
] = i
-1;
1781 for (; i
< 1024; ++i
) {
1782 if (i
>= (4 << j
)) ++j
;
1783 if (i
>= (3 << j
)) length_mapping
[i
] = (j
+5)*2+1;
1784 else length_mapping
[i
] = (j
+5)*2;
1789 ///// find the clipping data for a portal /////
1790 // returns TRUE if poly non empty
1791 // we save away info about the final polygon shape
1792 // in case we end up needing more info; e.g. the
1793 // water comes back and checks out the average z depth
1795 static r3s_phandle port_vr
[MAX_VERT
], *port_p
;
1798 ClipData
*PortalGetClipInfo(PortalCell
*cell
, PortalPolygonCore
*poly
,
1799 int voff
, void *clip
)
1801 int i
, n
= poly
->num_vertices
;
1802 uchar
*vlist
= cell
->vertex_list
+ voff
;
1805 Error(1, "PortalGetClipInfo: Portal has too many vertices.\n");
1807 for (i
=0; i
< n
; ++i
)
1808 port_vr
[i
] = &cur_ph
[*vlist
++];
1810 n
= r3_clip_polygon(n
, port_vr
, &port_p
);
1816 return PortalClipFromPolygon(n
, port_p
, clip
);
1819 mxs_real
compute_portal_z(void)
1824 for (i
=0; i
< port_n
; ++i
)
1825 z
+= port_p
[i
]->p
.z
;
1827 // compute the average
1830 return (z
> 0.1 ? z
: 0.1);