1 /* $Id: render.c,v 1.16 2003/04/24 18:15:36 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
13 */
14
15 /*
16 *
17 * FIXME: put description here
18 *
19 * Old Log:
20 * Revision 1.9 1995/11/20 17:17:48 allender
21 * *** empty log message ***
22 *
23 * Revision 1.8 1995/10/26 14:08:35 allender
24 * added assigment for physics optimization
25 *
26 * Revision 1.7 1995/09/22 14:28:46 allender
27 * changed render_zoom to make game match PC aspect
28 *
29 * Revision 1.6 1995/08/14 14:35:54 allender
30 * change transparency to 0
31 *
32 * Revision 1.5 1995/08/12 11:32:02 allender
33 * removed #ifdef NEWDEMO -- always in
34 *
35 * Revision 1.4 1995/07/05 16:48:31 allender
36 * kitchen stuff
37 *
38 * Revision 1.3 1995/06/23 10:22:54 allender
39 * fix outline mode
40 *
41 * Revision 1.2 1995/06/16 16:11:18 allender
42 * changed sort func to accept const parameters
43 *
44 * Revision 1.1 1995/05/16 15:30:24 allender
45 * Initial revision
46 *
47 * Revision 2.5 1995/12/19 15:31:36 john
48 * Made stereo mode only record 1 eye in demo.
49 *
50 * Revision 2.4 1995/03/20 18:15:53 john
51 * Added code to not store the normals in the segment structure.
52 *
53 * Revision 2.3 1995/03/13 16:11:05 john
54 * Maybe fixed bug that lighting didn't work with vr helmets.
55 *
56 * Revision 2.2 1995/03/09 15:33:49 john
57 * Fixed bug with iglasses timeout too long, and objects
58 * disappearing from left eye.
59 *
60 * Revision 2.1 1995/03/06 15:23:59 john
61 * New screen techniques.
62 *
63 * Revision 2.0 1995/02/27 11:31:01 john
64 * New version 2.0, which has no anonymous unions, builds with
65 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
66 *
67 * Revision 1.252 1995/02/22 13:49:38 allender
68 * remove anonymous unions from object structure
69 *
70 * Revision 1.251 1995/02/11 15:07:26 matt
71 * Took out code which was mostly intended as part of a larger renderer
72 * change which never happened. This new code was causing problems with
73 * the level 4 control center.
74 *
75 * Revision 1.250 1995/02/07 16:28:53 matt
76 * Fixed problem with new code
77 *
78 * Revision 1.249 1995/02/06 14:38:58 matt
79 * Took out some code that didn't compile when editor in
80 *
81 * Revision 1.248 1995/02/06 13:45:25 matt
82 * Structural changes, plus small sorting improvements
83 *
84 * Revision 1.247 1995/02/02 15:59:26 matt
85 * Changed assert to int3.
86 *
87 * Revision 1.246 1995/02/01 21:02:27 matt
88 * Added partial fix for rendering bugs
89 * Ripped out laser hack system
90 *
91 * Revision 1.245 1995/01/20 15:14:30 matt
92 * Added parens to fix precedence bug
93 *
94 * Revision 1.244 1995/01/14 19:16:59 john
95 * First version of new bitmap paging code.
96 *
97 * Revision 1.243 1995/01/03 20:19:25 john
98 * Pretty good working version of game save.
99 *
100 * Revision 1.242 1994/12/29 13:51:05 john
101 * Made the floating reticle draw in the spot
102 * regardless of the eye offset.
103 *
104 * Revision 1.241 1994/12/23 15:02:55 john
105 * Tweaked floating reticle.
106 *
107 * Revision 1.240 1994/12/23 14:27:45 john
108 * Changed offset of floating reticle to line up with
109 * lasers a bit better.
110 *
111 * Revision 1.239 1994/12/23 14:22:50 john
112 * Added floating reticle for VR helments.
113 *
114 * Revision 1.238 1994/12/13 14:07:50 matt
115 * Fixed tmap_num2 bug in search mode
116 *
117 * Revision 1.237 1994/12/11 00:45:53 matt
118 * Fixed problem when object sort buffer got full
119 *
120 * Revision 1.236 1994/12/09 18:46:06 matt
121 * Added a little debugging
122 *
123 * Revision 1.235 1994/12/09 14:59:16 matt
124 * Added system to attach a fireball to another object for rendering purposes,
125 * so the fireball always renders on top of (after) the object.
126 *
127 * Revision 1.234 1994/12/08 15:46:54 matt
128 * Fixed buffer overflow that caused seg depth screwup
129 *
130 * Revision 1.233 1994/12/08 11:51:53 matt
131 * Took out some unused stuff
132 *
133 * Revision 1.232 1994/12/06 16:31:48 mike
134 * fix detriangulation problems.
135 *
136 * Revision 1.231 1994/12/05 15:32:51 matt
137 * Changed an assert to an int3 & return
138 *
139 * Revision 1.230 1994/12/04 17:28:04 matt
140 * Got rid of unused no_render_flag array, and took out box clear when searching
141 *
142 * Revision 1.229 1994/12/04 15:51:14 matt
143 * Fixed linear tmap transition for objects
144 *
145 * Revision 1.228 1994/12/03 20:16:50 matt
146 * Turn off window clip for objects
147 *
148 * Revision 1.227 1994/12/03 14:48:00 matt
149 * Restored some default settings
150 *
151 * Revision 1.226 1994/12/03 14:44:32 matt
152 * Fixed another difficult bug in the window clip system
153 *
154 * Revision 1.225 1994/12/02 13:19:56 matt
155 * Fixed rect clears at terminus of rendering
156 * Made a bunch of debug code compile out
157 *
158 * Revision 1.224 1994/12/02 11:58:21 matt
159 * Fixed window clip bug
160 *
161 * Revision 1.223 1994/11/28 21:50:42 mike
162 * optimizations.
163 *
164 * Revision 1.222 1994/11/28 01:32:15 mike
165 * turn off window clearing.
166 *
167 * Revision 1.221 1994/11/27 23:11:52 matt
168 * Made changes for new mprintf calling convention
169 *
170 * Revision 1.220 1994/11/20 15:58:55 matt
171 * Don't migrate the control center, since it doesn't move out of its segment
172 *
173 * Revision 1.219 1994/11/19 23:54:36 mike
174 * change window colors.
175 *
176 * Revision 1.218 1994/11/19 15:20:25 mike
177 * rip out unused code and data
178 *
179 * Revision 1.217 1994/11/18 13:21:24 mike
180 * Clear only view portals into rest of world based on value of Clear_window.
181 *
182 * Revision 1.216 1994/11/15 17:02:10 matt
183 * Re-added accidentally deleted variable
184 *
185 * Revision 1.215 1994/11/15 16:51:50 matt
186 * Made rear view only switch to rear cockpit if cockpit on in front view
187 *
188 * Revision 1.214 1994/11/14 20:47:57 john
189 * Attempted to strip out all the code in the game
190 * directory that uses any ui code.
191 *
192 * Revision 1.213 1994/11/11 15:37:07 mike
193 * write orange for background to show render bugs.
194 *
195 * Revision 1.212 1994/11/09 22:57:18 matt
196 * Keep tract of depth of segments rendered, for detail level optimization
197 *
198 * Revision 1.211 1994/11/01 23:40:14 matt
199 * Elegantly handler buffer getting full
200 *
201 * Revision 1.210 1994/10/31 22:28:13 mike
202 * Fix detriangulation bug.
203 *
204 * Revision 1.209 1994/10/31 11:48:56 mike
205 * Optimize detriangulation, speedup of about 4% in many cases, 0% in many.
206 *
207 * Revision 1.208 1994/10/30 20:08:34 matt
208 * For endlevel: added big explosion at tunnel exit; made lights in tunnel
209 * go out; made more explosions on walls.
210 *
211 * Revision 1.207 1994/10/27 14:14:35 matt
212 * Don't do light flash during endlevel sequence
213 *
214 * Revision 1.206 1994/10/11 12:05:42 mike
215 * Improve detriangulation.
216 *
217 * Revision 1.205 1994/10/07 15:27:00 john
218 * Commented out the code that moves your eye
219 * forward.
220 *
221 * Revision 1.204 1994/10/05 16:07:38 mike
222 * Don't detriangulate sides if in player's segment. Prevents player going behind a wall,
223 * though there are cases in which it would be ok to detriangulate these.
224 *
225 * Revision 1.203 1994/10/03 12:44:05 matt
226 * Took out unreferenced code
227 *
228 * Revision 1.202 1994/09/28 14:08:45 john
229 * Added Zoom stuff back in, but ifdef'd it out.
230 *
231 * Revision 1.201 1994/09/25 23:41:49 matt
232 * Changed the object load & save code to read/write the structure fields one
233 * at a time (rather than the whole structure at once). This mean that the
234 * object structure can be changed without breaking the load/save functions.
235 * As a result of this change, the local_object data can be and has been
236 * incorporated into the object array. Also, timeleft is now a property
237 * of all objects, and the object structure has been otherwise cleaned up.
238 *
239 * Revision 1.200 1994/09/25 15:50:10 mike
240 * Integrate my debug changes which shows how many textures were rendered
241 * this frame.
242 *
243 * Revision 1.199 1994/09/25 15:45:22 matt
244 * Added OBJ_LIGHT, a type of object that casts light
245 * Added generalized lifeleft, and moved it to local_object
246 *
247 * Revision 1.198 1994/09/15 21:23:32 matt
248 * Changed system to keep track of whether & what cockpit is up
249 *
250 * Revision 1.197 1994/09/15 16:30:12 mike
251 * Comment out call to object_render_targets, which did nothing.
252 *
253 * Revision 1.196 1994/09/07 22:25:51 matt
254 * Don't migrate through semi-transparent walls
255 *
256 * Revision 1.195 1994/09/07 19:16:21 mike
257 * Homing missile.
258 *
259 * Revision 1.194 1994/08/31 20:54:17 matt
260 * Don't do flash effect while whiting out
261 *
262 * Revision 1.193 1994/08/23 17:20:12 john
263 * Added rear-view cockpit.
264 *
265 * Revision 1.192 1994/08/22 14:36:35 john
266 * Made R key make a "reverse" view render.
267 *
268 * Revision 1.191 1994/08/19 20:09:26 matt
269 * Added end-of-level cut scene with external scene
270 *
271 * Revision 1.190 1994/08/10 19:56:17 john
272 * Changed font stuff; Took out old menu; messed up lots of
273 * other stuff like game sequencing messages, etc.
274 *
275 * Revision 1.189 1994/08/10 14:45:05 john
276 * *** empty log message ***
277 *
278 * Revision 1.188 1994/08/09 16:04:06 john
279 * Added network players to editor.
280 *
281 * Revision 1.187 1994/08/05 17:07:05 john
282 * Made lasers be two objects, one drawing after the other
283 * all the time.
284 *
285 * Revision 1.186 1994/08/05 10:07:57 matt
286 * Disable window check checking (i.e., always use window check)
287 *
288 * Revision 1.185 1994/08/04 19:11:30 matt
289 * Changed a bunch of vecmat calls to use multiple-function routines, and to
290 * allow the use of C macros for some functions
291 *
292 * Revision 1.184 1994/08/04 00:21:14 matt
293 * Cleaned up fvi & physics error handling; put in code to make sure objects
294 * are in correct segment; simplified segment finding for objects and points
295 *
296 * Revision 1.183 1994/08/02 19:04:28 matt
297 * Cleaned up vertex list functions
298 *
299 * Revision 1.182 1994/07/29 15:13:33 matt
300 * When window check turned off, cut render depth in half
301 *
302 * Revision 1.181 1994/07/29 11:03:50 matt
303 * Use highest_segment_index instead of num_segments so render works from
304 * the editor
305 *
306 * Revision 1.180 1994/07/29 10:04:34 mike
307 * Update Cursegp when an object is selected.
308 *
309 * Revision 1.179 1994/07/25 00:02:50 matt
310 * Various changes to accomodate new 3d, which no longer takes point numbers
311 * as parms, and now only takes pointers to points.
312 *
313 * Revision 1.178 1994/07/24 14:37:49 matt
314 * Added angles for player head
315 *
316 * Revision 1.177 1994/07/20 19:08:07 matt
317 * If in editor, don't move eye from center of viewer object
318 *
319 *
320 */
321
322 #ifdef HAVE_CONFIG_H
323 #include <conf.h>
324 #endif
325
326 #include <stdlib.h>
327 #include <stdio.h>
328 #include <string.h>
329
330 #include "pa_enabl.h" //$$POLY_ACC
331 #include "inferno.h"
332 #include "segment.h"
333 #include "error.h"
334 #include "bm.h"
335 #include "texmap.h"
336 #include "mono.h"
337 #include "render.h"
338 #include "game.h"
339 #include "object.h"
340 #include "laser.h"
341 #include "textures.h"
342 #include "screens.h"
343 #include "segpoint.h"
344 #include "wall.h"
345 #include "texmerge.h"
346 #include "physics.h"
347 #include "3d.h"
348 #include "gameseg.h"
349 #include "vclip.h"
350 #include "lighting.h"
351 #include "cntrlcen.h"
352 #include "newdemo.h"
353 #include "automap.h"
354 #include "endlevel.h"
355 #include "key.h"
356 #include "newmenu.h"
357 #include "u_mem.h"
358 #include "piggy.h"
359
360 #ifdef OGL
361 #include "ogl_init.h"
362 #endif
363
364 #define INITIAL_LOCAL_LIGHT (F1_0/4) // local light value in segment of occurence (of light emission)
365
366 #ifdef EDITOR
367 #include "editor/editor.h"
368 #endif
369
370 #if defined(POLY_ACC)
371 #include "poly_acc.h"
372 #endif
373
374 //used for checking if points have been rotated
375 int Clear_window_color=-1;
376 int Clear_window=2; // 1 = Clear whole background window, 2 = clear view portals into rest of world, 0 = no clear
377
378 int RL_framecount=-1;
379 short Rotated_last[MAX_VERTICES];
380
381 // When any render function needs to know what's looking at it, it should
382 // access Viewer members.
383 object * Viewer = NULL;
384
385 vms_vector Viewer_eye; //valid during render
386
387 int N_render_segs;
388
389 #ifndef MACINTOSH
390 fix Render_zoom = 0x9000; //the player's zoom factor
391 #else
392 fix Render_zoom = 0xB000;
393 #endif
394
395 #ifndef NDEBUG
396 ubyte object_rendered[MAX_OBJECTS];
397 #endif
398
399 #define DEFAULT_RENDER_DEPTH 16
400 int Render_depth=DEFAULT_RENDER_DEPTH; //how many segments deep to render
401
402 int Detriangulation_on = 1; // 1 = allow rendering of triangulated side as a quad, 0 = don't allow
403
404 #ifdef EDITOR
405 int Render_only_bottom=0;
406 int Bottom_bitmap_num = 9;
407 #endif
408
409 fix Face_reflectivity = (F1_0/2);
410
411 #if 0 //this stuff could probably just be deleted
412
413 int inc_render_depth(void)
414 {
415 return ++Render_depth;
416 }
417
418 int dec_render_depth(void)
419 {
420 return Render_depth==1?Render_depth:--Render_depth;
421 }
422
423 int reset_render_depth(void)
424 {
425 return Render_depth = DEFAULT_RENDER_DEPTH;
426 }
427
428 #endif
429
430 #ifdef EDITOR
431 int _search_mode = 0; //true if looking for curseg,side,face
432 short _search_x,_search_y; //pixel we're looking at
433 int found_seg,found_side,found_face,found_poly;
434 #else
435 #define _search_mode 0
436 #endif
437
438 #ifdef NDEBUG //if no debug code, set these vars to constants
439
440 #define Outline_mode 0
441 #define Show_only_curside 0
442
443 #else
444
445 int Outline_mode=0,Show_only_curside=0;
446
toggle_outline_mode(void)447 int toggle_outline_mode(void)
448 {
449 return Outline_mode = !Outline_mode;
450 }
451
toggle_show_only_curside(void)452 int toggle_show_only_curside(void)
453 {
454 return Show_only_curside = !Show_only_curside;
455 }
456
draw_outline(int nverts,g3s_point ** pointlist)457 void draw_outline(int nverts,g3s_point **pointlist)
458 {
459 int i;
460
461 gr_setcolor(BM_XRGB(63,63,63));
462
463 for (i=0;i<nverts-1;i++)
464 g3_draw_line(pointlist[i],pointlist[i+1]);
465
466 g3_draw_line(pointlist[i],pointlist[0]);
467
468 }
469 #endif
470
471 grs_canvas * reticle_canvas = NULL;
472
free_reticle_canvas()473 void free_reticle_canvas()
474 {
475 if (reticle_canvas) {
476 d_free( reticle_canvas->cv_bitmap.bm_data );
477 d_free( reticle_canvas );
478 reticle_canvas = NULL;
479 }
480 }
481
482 extern void show_reticle(int force_big);
483
484 // Draw the reticle in 3D for head tracking
draw_3d_reticle(fix eye_offset)485 void draw_3d_reticle(fix eye_offset)
486 {
487 g3s_point reticle_points[4];
488 g3s_uvl uvl[4];
489 g3s_point *pointlist[4];
490 int i;
491 vms_vector v1, v2;
492 grs_canvas *saved_canvas;
493 int saved_interp_method;
494
495 // if (!Use_player_head_angles) return;
496
497 for (i=0; i<4; i++ ) {
498 pointlist[i] = &reticle_points[i];
499 uvl[i].l = MAX_LIGHT;
500 }
501 uvl[0].u = 0; uvl[0].v = 0;
502 uvl[1].u = F1_0; uvl[1].v = 0;
503 uvl[2].u = F1_0; uvl[2].v = F1_0;
504 uvl[3].u = 0; uvl[3].v = F1_0;
505
506 vm_vec_scale_add( &v1, &Viewer->pos, &Viewer->orient.fvec, F1_0*4 );
507 vm_vec_scale_add2(&v1,&Viewer->orient.rvec,eye_offset);
508
509 vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
510 vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
511 g3_rotate_point(&reticle_points[0],&v2);
512
513 vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
514 vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
515 g3_rotate_point(&reticle_points[1],&v2);
516
517 vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
518 vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
519 g3_rotate_point(&reticle_points[2],&v2);
520
521 vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
522 vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
523 g3_rotate_point(&reticle_points[3],&v2);
524
525 if ( reticle_canvas == NULL ) {
526 reticle_canvas = gr_create_canvas(64,64);
527 if ( !reticle_canvas )
528 Error( "Couldn't malloc reticle_canvas" );
529 atexit( free_reticle_canvas );
530 reticle_canvas->cv_bitmap.bm_handle = 0;
531 reticle_canvas->cv_bitmap.bm_flags = BM_FLAG_TRANSPARENT;
532 }
533
534 saved_canvas = grd_curcanv;
535 gr_set_current_canvas(reticle_canvas);
536 gr_clear_canvas( TRANSPARENCY_COLOR ); // Clear to Xparent
537 show_reticle(1);
538 gr_set_current_canvas(saved_canvas);
539
540 saved_interp_method=Interpolation_method;
541 Interpolation_method = 3; // The best, albiet slowest.
542 g3_draw_tmap(4,pointlist,uvl,&reticle_canvas->cv_bitmap);
543 Interpolation_method = saved_interp_method;
544 }
545
546
547 extern fix Seismic_tremor_magnitude;
548
549 fix flash_scale;
550
551 #define FLASH_CYCLE_RATE f1_0
552
553 fix Flash_rate = FLASH_CYCLE_RATE;
554
555 //cycle the flashing light for when mine destroyed
flash_frame()556 void flash_frame()
557 {
558 static fixang flash_ang=0;
559
560 if (!Control_center_destroyed && !Seismic_tremor_magnitude)
561 return;
562
563 if (Endlevel_sequence)
564 return;
565
566 if (PaletteBlueAdd > 10 ) //whiting out
567 return;
568
569 // flash_ang += fixmul(FLASH_CYCLE_RATE,FrameTime);
570 if (Seismic_tremor_magnitude) {
571 fix added_flash;
572
573 added_flash = abs(Seismic_tremor_magnitude);
574 if (added_flash < F1_0)
575 added_flash *= 16;
576
577 flash_ang += fixmul(Flash_rate, fixmul(FrameTime, added_flash+F1_0));
578 fix_fastsincos(flash_ang,&flash_scale,NULL);
579 flash_scale = (flash_scale + F1_0*3)/4; // gets in range 0.5 to 1.0
580 } else {
581 flash_ang += fixmul(Flash_rate,FrameTime);
582 fix_fastsincos(flash_ang,&flash_scale,NULL);
583 flash_scale = (flash_scale + f1_0)/2;
584 if (Difficulty_level == 0)
585 flash_scale = (flash_scale+F1_0*3)/4;
586 }
587
588
589 }
590
591 // ----------------------------------------------------------------------------
592 // Render a face.
593 // It would be nice to not have to pass in segnum and sidenum, but
594 // they are used for our hideously hacked in headlight system.
595 // vp is a pointer to vertex ids.
596 // tmap1, tmap2 are texture map ids. tmap2 is the pasty one.
render_face(int segnum,int sidenum,int nv,short * vp,int tmap1,int tmap2,uvl * uvlp,int wid_flags)597 void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp, int wid_flags)
598 {
599 // -- Using new headlight system...fix face_light;
600 grs_bitmap *bm;
601 #ifdef OGL
602 grs_bitmap *bm2 = NULL;
603 #endif
604
605 fix reflect;
606 uvl uvl_copy[8];
607 int i;
608 g3s_point *pointlist[8];
609
610 Assert(nv <= 8);
611
612 for (i=0; i<nv; i++) {
613 uvl_copy[i] = uvlp[i];
614 pointlist[i] = &Segment_points[vp[i]];
615 }
616
617 //handle cloaked walls
618 if (wid_flags & WID_CLOAKED_FLAG) {
619 int wall_num = Segments[segnum].sides[sidenum].wall_num;
620 Assert(wall_num != -1);
621 Gr_scanline_darkening_level = Walls[wall_num].cloak_value;
622 gr_setcolor(BM_XRGB(0,0,0)); //set to black (matters for s3)
623
624 g3_draw_poly(nv,pointlist); //draw as flat poly
625
626 Gr_scanline_darkening_level = GR_FADE_LEVELS;
627
628 return;
629 }
630
631 // -- Using new headlight system...face_light = -vm_vec_dot(&Viewer->orient.fvec,norm);
632
633 if (tmap1 >= NumTextures) {
634 mprintf((0,"Invalid tmap number %d, NumTextures=%d, changing to 0\n",tmap1,NumTextures));
635
636 #ifndef RELEASE
637 Int3();
638 #endif
639
640 Segments[segnum].sides[sidenum].tmap_num = 0;
641 }
642
643 #ifdef OGL
644 if (ogl_alttexmerge){
645 PIGGY_PAGE_IN(Textures[tmap1]);
646 bm = &GameBitmaps[Textures[tmap1].index];
647 if (tmap2){
648 PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]);
649 bm2 = &GameBitmaps[Textures[tmap2&0x3FFF].index];
650 }
651 if (bm2 && (bm2->bm_flags&BM_FLAG_SUPER_TRANSPARENT)){
652 bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
653 bm2 = NULL;
654 }
655 } else
656 #endif
657
658 // New code for overlapping textures...
659 if (tmap2 != 0) {
660 bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
661 } else {
662 bm = &GameBitmaps[Textures[tmap1].index];
663 PIGGY_PAGE_IN(Textures[tmap1]);
664 }
665
666 Assert( !(bm->bm_flags & BM_FLAG_PAGED_OUT) );
667
668 //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect)/2.0 + 0.5);
669 //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect));
670
671 reflect = Face_reflectivity; // f1_0; //until we figure this stuff out...
672
673 //set light values for each vertex & build pointlist
674 {
675 int i;
676
677 // -- Using new headlight system...face_light = fixmul(face_light,reflect);
678
679 for (i=0;i<nv;i++) {
680
681 //the uvl struct has static light already in it
682
683 //scale static light for destruction effect
684 if (Control_center_destroyed || Seismic_tremor_magnitude) //make lights flash
685 uvl_copy[i].l = fixmul(flash_scale,uvl_copy[i].l);
686
687 //add in dynamic light (from explosions, etc.)
688 uvl_copy[i].l += Dynamic_light[vp[i]];
689
690 //add in light from player's headlight
691 // -- Using new headlight system...uvl_copy[i].l += compute_headlight_light(&Segment_points[vp[i]].p3_vec,face_light);
692
693 //saturate at max value
694 if (uvl_copy[i].l > MAX_LIGHT)
695 uvl_copy[i].l = MAX_LIGHT;
696
697 }
698 }
699
700 #ifdef EDITOR
701 if ((Render_only_bottom) && (sidenum == WBOTTOM))
702 g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,&GameBitmaps[Textures[Bottom_bitmap_num].index]);
703 else
704 #endif
705
706 #ifdef OGL
707 if (bm2){
708 g3_draw_tmap_2(nv,pointlist,(g3s_uvl *) uvl_copy,bm,bm2,((tmap2&0xC000)>>14) & 3);
709 }else
710 #endif
711 g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,bm);
712
713 #ifndef NDEBUG
714 if (Outline_mode) draw_outline(nv, pointlist);
715 #endif
716 }
717
718 #ifdef EDITOR
719 // ----------------------------------------------------------------------------
720 // Only called if editor active.
721 // Used to determine which face was clicked on.
check_face(int segnum,int sidenum,int facenum,int nv,short * vp,int tmap1,int tmap2,uvl * uvlp)722 void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp)
723 {
724 int i;
725
726 if (_search_mode) {
727 int save_lighting;
728 grs_bitmap *bm;
729 uvl uvl_copy[8];
730 g3s_point *pointlist[4];
731
732 if (tmap2 > 0 )
733 bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
734 else
735 bm = &GameBitmaps[Textures[tmap1].index];
736
737 for (i=0; i<nv; i++) {
738 uvl_copy[i] = uvlp[i];
739 pointlist[i] = &Segment_points[vp[i]];
740 }
741
742 gr_setcolor(0);
743 gr_pixel(_search_x,_search_y); //set our search pixel to color zero
744 gr_setcolor(1); //and render in color one
745 save_lighting = Lighting_on;
746 Lighting_on = 2;
747 //g3_draw_poly(nv,vp);
748 g3_draw_tmap(nv,pointlist, (g3s_uvl *)uvl_copy, bm);
749 Lighting_on = save_lighting;
750
751 if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) == 1) {
752 found_seg = segnum;
753 found_side = sidenum;
754 found_face = facenum;
755 }
756 }
757 }
758 #endif
759
760 fix Tulate_min_dot = (F1_0/4);
761 //--unused-- fix Tulate_min_ratio = (2*F1_0);
762 fix Min_n0_n1_dot = (F1_0*15/16);
763
764 extern int contains_flare(segment *segp, int sidenum);
765 extern fix Obj_light_xlate[16];
766
767 // -----------------------------------------------------------------------------------
768 // Render a side.
769 // Check for normal facing. If so, render faces on side dictated by sidep->type.
render_side(segment * segp,int sidenum)770 void render_side(segment *segp, int sidenum)
771 {
772 short vertnum_list[4];
773 side *sidep = &segp->sides[sidenum];
774 vms_vector tvec;
775 fix v_dot_n0, v_dot_n1;
776 uvl temp_uvls[3];
777 fix min_dot, max_dot;
778 vms_vector normals[2];
779 int wid_flags;
780
781
782 wid_flags = WALL_IS_DOORWAY(segp,sidenum);
783
784 if (!(wid_flags & WID_RENDER_FLAG)) //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL)
785 return;
786
787 #ifdef COMPACT_SEGS
788 get_side_normals(segp, sidenum, &normals[0], &normals[1] );
789 #else
790 normals[0] = segp->sides[sidenum].normals[0];
791 normals[1] = segp->sides[sidenum].normals[1];
792 #endif
793
794 // ========== Mark: Here is the change...beginning here: ==========
795
796 if (sidep->type == SIDE_IS_QUAD) {
797
798 vm_vec_sub(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
799
800 // -- Old, slow way -- // Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
801 // -- Old, slow way -- // deal with it, get the dot product.
802 // -- Old, slow way -- if (sidep->type == SIDE_IS_TRI_13)
803 // -- Old, slow way -- vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
804 // -- Old, slow way -- else
805 // -- Old, slow way -- vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
806
807 get_side_verts(vertnum_list,segp-Segments,sidenum);
808 v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
809
810 // -- flare creates point -- {
811 // -- flare creates point -- int flare_index;
812 // -- flare creates point --
813 // -- flare creates point -- flare_index = contains_flare(segp, sidenum);
814 // -- flare creates point --
815 // -- flare creates point -- if (flare_index != -1) {
816 // -- flare creates point -- int tri;
817 // -- flare creates point -- fix u, v, l;
818 // -- flare creates point -- vms_vector *hit_point;
819 // -- flare creates point -- short vertnum_list[4];
820 // -- flare creates point --
821 // -- flare creates point -- hit_point = &Objects[flare_index].pos;
822 // -- flare creates point --
823 // -- flare creates point -- find_hitpoint_uv( &u, &v, &l, hit_point, segp, sidenum, 0); // last parm means always use face 0.
824 // -- flare creates point --
825 // -- flare creates point -- get_side_verts(vertnum_list, segp-Segments, sidenum);
826 // -- flare creates point --
827 // -- flare creates point -- g3_rotate_point(&Segment_points[MAX_VERTICES-1], hit_point);
828 // -- flare creates point --
829 // -- flare creates point -- for (tri=0; tri<4; tri++) {
830 // -- flare creates point -- short tri_verts[3];
831 // -- flare creates point -- uvl tri_uvls[3];
832 // -- flare creates point --
833 // -- flare creates point -- tri_verts[0] = vertnum_list[tri];
834 // -- flare creates point -- tri_verts[1] = vertnum_list[(tri+1) % 4];
835 // -- flare creates point -- tri_verts[2] = MAX_VERTICES-1;
836 // -- flare creates point --
837 // -- flare creates point -- tri_uvls[0] = sidep->uvls[tri];
838 // -- flare creates point -- tri_uvls[1] = sidep->uvls[(tri+1)%4];
839 // -- flare creates point -- tri_uvls[2].u = u;
840 // -- flare creates point -- tri_uvls[2].v = v;
841 // -- flare creates point -- tri_uvls[2].l = F1_0;
842 // -- flare creates point --
843 // -- flare creates point -- render_face(segp-Segments, sidenum, 3, tri_verts, sidep->tmap_num, sidep->tmap_num2, tri_uvls, &normals[0]);
844 // -- flare creates point -- }
845 // -- flare creates point --
846 // -- flare creates point -- return;
847 // -- flare creates point -- }
848 // -- flare creates point -- }
849
850 if (v_dot_n0 >= 0) {
851 render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
852 #ifdef EDITOR
853 check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
854 #endif
855 }
856 } else {
857 // Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
858 // deal with it, get the dot product.
859 if (sidep->type == SIDE_IS_TRI_13)
860 vm_vec_normalized_dir_quick(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
861 else
862 vm_vec_normalized_dir_quick(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
863
864 get_side_verts(vertnum_list,segp-Segments,sidenum);
865
866 v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
867
868 // ========== Mark: The change ends here. ==========
869
870 // Although this side has been triangulated, because it is not planar, see if it is acceptable
871 // to render it as a single quadrilateral. This is a function of how far away the viewer is, how non-planar
872 // the face is, how normal to the surfaces the view is.
873 // Now, if both dot products are close to 1.0, then render two triangles as a single quad.
874 v_dot_n1 = vm_vec_dot(&tvec, &normals[1]);
875
876 if (v_dot_n0 < v_dot_n1) {
877 min_dot = v_dot_n0;
878 max_dot = v_dot_n1;
879 } else {
880 min_dot = v_dot_n1;
881 max_dot = v_dot_n0;
882 }
883
884 // Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio))
885 if (Detriangulation_on && ((min_dot+F1_0/256 > max_dot) || ((Viewer->segnum != segp-Segments) && (min_dot > Tulate_min_dot) && (max_dot < min_dot*2)))) {
886 fix n0_dot_n1;
887
888 // The other detriangulation code doesn't deal well with badly non-planar sides.
889 n0_dot_n1 = vm_vec_dot(&normals[0], &normals[1]);
890 if (n0_dot_n1 < Min_n0_n1_dot)
891 goto im_so_ashamed;
892
893 render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
894 #ifdef EDITOR
895 check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
896 #endif
897 } else {
898 im_so_ashamed: ;
899 if (sidep->type == SIDE_IS_TRI_02) {
900 if (v_dot_n0 >= 0) {
901 render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
902 #ifdef EDITOR
903 check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
904 #endif
905 }
906
907 if (v_dot_n1 >= 0) {
908 temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[2]; temp_uvls[2] = sidep->uvls[3];
909 vertnum_list[1] = vertnum_list[2]; vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0, 2, 3 on side
910 render_face(segp-Segments, sidenum, 3, &vertnum_list[0], sidep->tmap_num, sidep->tmap_num2, temp_uvls, wid_flags);
911 #ifdef EDITOR
912 check_face(segp-Segments, sidenum, 1, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
913 #endif
914 }
915 } else if (sidep->type == SIDE_IS_TRI_13) {
916 if (v_dot_n1 >= 0) {
917 render_face(segp-Segments, sidenum, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, &sidep->uvls[1], wid_flags); // rendering 1,2,3, so just skip 0
918 #ifdef EDITOR
919 check_face(segp-Segments, sidenum, 1, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
920 #endif
921 }
922
923 if (v_dot_n0 >= 0) {
924 temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[1]; temp_uvls[2] = sidep->uvls[3];
925 vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0,1,3
926 render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, temp_uvls, wid_flags);
927 #ifdef EDITOR
928 check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
929 #endif
930 }
931
932 } else
933 #ifdef __DJGPP__
934 Error("Illegal side type in render_side, type = %i, segment # = %li, side # = %i\n", sidep->type, segp-Segments, sidenum);
935 #else
936 Error("Illegal side type in render_side, type = %i, segment # = %i, side # = %i\n", sidep->type, segp-Segments, sidenum);
937 #endif
938 }
939 }
940
941 }
942
943 #ifdef EDITOR
render_object_search(object * obj)944 void render_object_search(object *obj)
945 {
946 int changed=0;
947
948 //note that we draw each pixel object twice, since we cannot control
949 //what color the object draws in, so we try color 0, then color 1,
950 //in case the object itself is rendering color 0
951
952 gr_setcolor(0);
953 gr_pixel(_search_x,_search_y); //set our search pixel to color zero
954 render_object(obj);
955 if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 0)
956 changed=1;
957
958 gr_setcolor(1);
959 gr_pixel(_search_x,_search_y); //set our search pixel to color zero
960 render_object(obj);
961 if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 1)
962 changed=1;
963
964 if (changed) {
965 if (obj->segnum != -1)
966 Cursegp = &Segments[obj->segnum];
967 found_seg = -(obj-Objects+1);
968 }
969 }
970 #endif
971
972 extern ubyte DemoDoingRight,DemoDoingLeft;
973
do_render_object(int objnum,int window_num)974 void do_render_object(int objnum, int window_num)
975 {
976 #ifdef EDITOR
977 int save_3d_outline=0;
978 #endif
979 object *obj = &Objects[objnum];
980 int count = 0;
981 int n;
982
983 Assert(objnum < MAX_OBJECTS);
984
985 #ifndef NDEBUG
986 if (object_rendered[objnum]) { //already rendered this...
987 Int3(); //get Matt!!!
988 return;
989 }
990
991 object_rendered[objnum] = 1;
992 #endif
993
994 if (Newdemo_state==ND_STATE_PLAYBACK)
995 {
996 if ((DemoDoingLeft==6 || DemoDoingRight==6) && Objects[objnum].type==OBJ_PLAYER)
997 {
998 // A nice fat hack: keeps the player ship from showing up in the
999 // small extra view when guiding a missile in the big window
1000
1001 mprintf ((0,"Returning from render_object prematurely...\n"));
1002 return;
1003 }
1004 }
1005
1006 // Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so
1007 // that the guided missile system will know what objects to look at.
1008 // I didn't know we had guided missiles before the release of D1. --MK
1009 if ((Objects[objnum].type == OBJ_ROBOT) || (Objects[objnum].type == OBJ_PLAYER)) {
1010 //Assert(Window_rendered_data[window_num].rendered_objects < MAX_RENDERED_OBJECTS);
1011 // This peculiar piece of code makes us keep track of the most recently rendered objects, which
1012 // are probably the higher priority objects, without overflowing the buffer
1013 if (Window_rendered_data[window_num].num_objects >= MAX_RENDERED_OBJECTS) {
1014 Int3();
1015 Window_rendered_data[window_num].num_objects /= 2;
1016 }
1017 Window_rendered_data[window_num].rendered_objects[Window_rendered_data[window_num].num_objects++] = objnum;
1018 }
1019
1020 if ((count++ > MAX_OBJECTS) || (obj->next == objnum)) {
1021 Int3(); // infinite loop detected
1022 obj->next = -1; // won't this clean things up?
1023 return; // get out of this infinite loop!
1024 }
1025
1026 //g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size);
1027
1028 //check for editor object
1029
1030 #ifdef EDITOR
1031 if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index) {
1032 save_3d_outline = g3d_interp_outline;
1033 g3d_interp_outline=1;
1034 }
1035 #endif
1036
1037 #ifdef EDITOR
1038 if (_search_mode)
1039 render_object_search(obj);
1040 else
1041 #endif
1042 //NOTE LINK TO ABOVE
1043 render_object(obj);
1044
1045 for (n=obj->attached_obj;n!=-1;n=Objects[n].ctype.expl_info.next_attach) {
1046
1047 Assert(Objects[n].type == OBJ_FIREBALL);
1048 Assert(Objects[n].control_type == CT_EXPLOSION);
1049 Assert(Objects[n].flags & OF_ATTACHED);
1050
1051 render_object(&Objects[n]);
1052 }
1053
1054
1055 #ifdef EDITOR
1056 if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index)
1057 g3d_interp_outline = save_3d_outline;
1058 #endif
1059
1060
1061 //DEBUG mprintf( (0, "%d ", objnum ));
1062
1063 }
1064
1065 #ifndef NDEBUG
1066 int draw_boxes=0;
1067 int window_check=1,draw_edges=0,new_seg_sorting=1,pre_draw_segs=0;
1068 int no_migrate_segs=1,migrate_objects=1,behind_check=1;
1069 int check_window_check=0;
1070 #else
1071 #define draw_boxes 0
1072 #define window_check 1
1073 #define draw_edges 0
1074 #define new_seg_sorting 1
1075 #define pre_draw_segs 0
1076 #define no_migrate_segs 1
1077 #define migrate_objects 1
1078 #define behind_check 1
1079 #define check_window_check 0
1080 #endif
1081
1082 //increment counter for checking if points rotated
1083 //This must be called at the start of the frame if rotate_list() will be used
render_start_frame()1084 void render_start_frame()
1085 {
1086 RL_framecount++;
1087
1088 if (RL_framecount==0) { //wrap!
1089
1090 memset(Rotated_last,0,sizeof(Rotated_last)); //clear all to zero
1091 RL_framecount=1; //and set this frame to 1
1092 }
1093 }
1094
1095 //Given a lit of point numbers, rotate any that haven't been rotated this frame
rotate_list(int nv,short * pointnumlist)1096 g3s_codes rotate_list(int nv,short *pointnumlist)
1097 {
1098 int i,pnum;
1099 g3s_point *pnt;
1100 g3s_codes cc;
1101
1102 cc.and = 0xff; cc.or = 0;
1103
1104 for (i=0;i<nv;i++) {
1105
1106 pnum = pointnumlist[i];
1107
1108 pnt = &Segment_points[pnum];
1109
1110 if (Rotated_last[pnum] != RL_framecount) {
1111
1112 g3_rotate_point(pnt,&Vertices[pnum]);
1113
1114 Rotated_last[pnum] = RL_framecount;
1115 }
1116
1117 cc.and &= pnt->p3_codes;
1118 cc.or |= pnt->p3_codes;
1119 }
1120
1121 return cc;
1122
1123 }
1124
1125 //Given a lit of point numbers, project any that haven't been projected
project_list(int nv,short * pointnumlist)1126 void project_list(int nv,short *pointnumlist)
1127 {
1128 int i,pnum;
1129
1130 for (i=0;i<nv;i++) {
1131
1132 pnum = pointnumlist[i];
1133
1134 if (!(Segment_points[pnum].p3_flags & PF_PROJECTED))
1135
1136 g3_project_point(&Segment_points[pnum]);
1137
1138 }
1139 }
1140
1141
1142 // -----------------------------------------------------------------------------------
render_segment(int segnum,int window_num)1143 void render_segment(int segnum, int window_num)
1144 {
1145 segment *seg = &Segments[segnum];
1146 g3s_codes cc;
1147 int sn;
1148
1149 Assert(segnum!=-1 && segnum<=Highest_segment_index);
1150
1151 cc=rotate_list(8,seg->verts);
1152
1153 if (! cc.and) { //all off screen?
1154
1155 //mprintf( (0, "!"));
1156 //DEBUG mprintf( (0, "[Segment %d: ", segnum ));
1157
1158 // set_segment_local_light_value(segnum,INITIAL_LOCAL_LIGHT);
1159
1160 if (Viewer->type!=OBJ_ROBOT)
1161 Automap_visited[segnum]=1;
1162
1163 for (sn=0; sn<MAX_SIDES_PER_SEGMENT; sn++)
1164 render_side(seg, sn);
1165 }
1166
1167 //draw any objects that happen to be in this segment
1168
1169 //sort objects!
1170 //object_sort_segment_objects( seg );
1171
1172 #ifndef NDEBUG
1173 if (!migrate_objects) {
1174 int objnum;
1175 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
1176 do_render_object(objnum, window_num);
1177 }
1178 #endif
1179
1180 //DEBUG mprintf( (0, "]\n", segnum ));
1181
1182 }
1183
1184 // ----- This used to be called when Show_only_curside was set.
1185 // ----- It is wholly and superiorly replaced by render_side.
1186 // -- //render one side of one segment
1187 // -- void render_seg_side(segment *seg,int _side)
1188 // -- {
1189 // -- g3s_codes cc;
1190 // -- short vertnum_list[4];
1191 // --
1192 // -- cc=g3_rotate_list(8,&seg->verts);
1193 // --
1194 // -- if (! cc.and) { //all off screen?
1195 // -- int fn,pn,i;
1196 // -- side *s;
1197 // -- face *f;
1198 // -- poly *p;
1199 // --
1200 // -- s=&seg->sides[_side];
1201 // --
1202 // -- for (f=s->faces,fn=s->num_faces;fn;fn--,f++)
1203 // -- for (p=f->polys,pn=f->num_polys;pn;pn--,p++) {
1204 // -- grs_bitmap *tmap;
1205 // --
1206 // -- for (i=0;i<p->num_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]];
1207 // --
1208 // -- if (p->tmap_num >= NumTextures) {
1209 // -- Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures);
1210 // -- p->tmap_num = 0; //change it permanantly
1211 // -- }
1212 // --
1213 // -- tmap = Textures[p->tmap_num];
1214 // --
1215 // -- g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal);
1216 // --
1217 // -- if (Outline_mode) draw_outline(p->num_vertices,vertnum_list);
1218 // -- }
1219 // -- }
1220 // --
1221 // -- }
1222
1223 #define CROSS_WIDTH i2f(8)
1224 #define CROSS_HEIGHT i2f(8)
1225
1226 #ifndef NDEBUG
1227
1228 //draw outline for curside
outline_seg_side(segment * seg,int _side,int edge,int vert)1229 void outline_seg_side(segment *seg,int _side,int edge,int vert)
1230 {
1231 g3s_codes cc;
1232
1233 cc=rotate_list(8,seg->verts);
1234
1235 if (! cc.and) { //all off screen?
1236 side *s;
1237 g3s_point *pnt;
1238
1239 s=&seg->sides[_side];
1240
1241 //render curedge of curside of curseg in green
1242
1243 gr_setcolor(BM_XRGB(0,63,0));
1244 g3_draw_line(&Segment_points[seg->verts[Side_to_verts[_side][edge]]],&Segment_points[seg->verts[Side_to_verts[_side][(edge+1)%4]]]);
1245
1246 //draw a little cross at the current vert
1247
1248 pnt = &Segment_points[seg->verts[Side_to_verts[_side][vert]]];
1249
1250 g3_project_point(pnt); //make sure projected
1251
1252 // gr_setcolor(BM_XRGB(0,0,63));
1253 // gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
1254 // gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
1255
1256 gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT);
1257 gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
1258 gr_line(pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
1259 gr_line(pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT,pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy);
1260 }
1261 }
1262
1263 #endif
1264
1265 #if 0 //this stuff could probably just be deleted
1266
1267 #define DEFAULT_PERSPECTIVE_DEPTH 6
1268
1269 int Perspective_depth=DEFAULT_PERSPECTIVE_DEPTH; //how many levels deep to render in perspective
1270
1271 int inc_perspective_depth(void)
1272 {
1273 return ++Perspective_depth;
1274
1275 }
1276
1277 int dec_perspective_depth(void)
1278 {
1279 return Perspective_depth==1?Perspective_depth:--Perspective_depth;
1280
1281 }
1282
1283 int reset_perspective_depth(void)
1284 {
1285 return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH;
1286
1287 }
1288 #endif
1289
1290 typedef struct window {
1291 short left,top,right,bot;
1292 } window;
1293
code_window_point(fix x,fix y,window * w)1294 ubyte code_window_point(fix x,fix y,window *w)
1295 {
1296 ubyte code=0;
1297
1298 if (x <= w->left) code |= 1;
1299 if (x >= w->right) code |= 2;
1300
1301 if (y <= w->top) code |= 4;
1302 if (y >= w->bot) code |= 8;
1303
1304 return code;
1305 }
1306
1307 #ifndef NDEBUG
draw_window_box(int color,short left,short top,short right,short bot)1308 void draw_window_box(int color,short left,short top,short right,short bot)
1309 {
1310 short l,t,r,b;
1311
1312 gr_setcolor(color);
1313
1314 l=left; t=top; r=right; b=bot;
1315
1316 if ( r<0 || b<0 || l>=grd_curcanv->cv_bitmap.bm_w || (t>=grd_curcanv->cv_bitmap.bm_h && b>=grd_curcanv->cv_bitmap.bm_h))
1317 return;
1318
1319 if (l<0) l=0;
1320 if (t<0) t=0;
1321 if (r>=grd_curcanv->cv_bitmap.bm_w) r=grd_curcanv->cv_bitmap.bm_w-1;
1322 if (b>=grd_curcanv->cv_bitmap.bm_h) b=grd_curcanv->cv_bitmap.bm_h-1;
1323
1324 gr_line(i2f(l),i2f(t),i2f(r),i2f(t));
1325 gr_line(i2f(r),i2f(t),i2f(r),i2f(b));
1326 gr_line(i2f(r),i2f(b),i2f(l),i2f(b));
1327 gr_line(i2f(l),i2f(b),i2f(l),i2f(t));
1328
1329 }
1330 #endif
1331
1332 int matt_find_connect_side(int seg0,int seg1);
1333
1334 #ifndef NDEBUG
1335 char visited2[MAX_SEGMENTS];
1336 #endif
1337
1338 unsigned char visited[MAX_SEGMENTS];
1339 short Render_list[MAX_RENDER_SEGS];
1340 short Seg_depth[MAX_RENDER_SEGS]; //depth for each seg in Render_list
1341 ubyte processed[MAX_RENDER_SEGS]; //whether each entry has been processed
1342 int lcnt_save,scnt_save;
1343 //@@short *persp_ptr;
1344 short render_pos[MAX_SEGMENTS]; //where in render_list does this segment appear?
1345 //ubyte no_render_flag[MAX_RENDER_SEGS];
1346 window render_windows[MAX_RENDER_SEGS];
1347
1348 short render_obj_list[MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS][OBJS_PER_SEG];
1349
1350 //for objects
1351
1352
1353
1354 #define RED BM_XRGB(63,0,0)
1355 #define WHITE BM_XRGB(63,63,63)
1356
1357 //Given two sides of segment, tell the two verts which form the
1358 //edge between them
1359 short Two_sides_to_edge[6][6][2] = {
1360 { {-1,-1}, {3,7}, {-1,-1}, {2,6}, {6,7}, {2,3} },
1361 { {3,7}, {-1,-1}, {0,4}, {-1,-1}, {4,7}, {0,3} },
1362 { {-1,-1}, {0,4}, {-1,-1}, {1,5}, {4,5}, {0,1} },
1363 { {2,6}, {-1,-1}, {1,5}, {-1,-1}, {5,6}, {1,2} },
1364 { {6,7}, {4,7}, {4,5}, {5,6}, {-1,-1}, {-1,-1} },
1365 { {2,3}, {0,3}, {0,1}, {1,2}, {-1,-1}, {-1,-1} }
1366 };
1367
1368 //given an edge specified by two verts, give the two sides on that edge
1369 int Edge_to_sides[8][8][2] = {
1370 { {-1,-1}, {2,5}, {-1,-1}, {1,5}, {1,2}, {-1,-1}, {-1,-1}, {-1,-1} },
1371 { {2,5}, {-1,-1}, {3,5}, {-1,-1}, {-1,-1}, {2,3}, {-1,-1}, {-1,-1} },
1372 { {-1,-1}, {3,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {0,3}, {-1,-1} },
1373 { {1,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {0,1} },
1374 { {1,2}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {1,4} },
1375 { {-1,-1}, {2,3}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {3,4}, {-1,-1} },
1376 { {-1,-1}, {-1,-1}, {0,3}, {-1,-1}, {-1,-1}, {3,4}, {-1,-1}, {0,4} },
1377 { {-1,-1}, {-1,-1}, {-1,-1}, {0,1}, {1,4}, {-1,-1}, {0,4}, {-1,-1} },
1378 };
1379
1380 //@@//perform simple check on tables
1381 //@@check_check()
1382 //@@{
1383 //@@ int i,j;
1384 //@@
1385 //@@ for (i=0;i<8;i++)
1386 //@@ for (j=0;j<8;j++)
1387 //@@ Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] &&
1388 //@@ Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]);
1389 //@@
1390 //@@ for (i=0;i<6;i++)
1391 //@@ for (j=0;j<6;j++)
1392 //@@ Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] &&
1393 //@@ Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]);
1394 //@@
1395 //@@
1396 //@@}
1397
1398
1399 //given an edge, tell what side is on that edge
find_seg_side(segment * seg,short * verts,int notside)1400 int find_seg_side(segment *seg,short *verts,int notside)
1401 {
1402 int i;
1403 int vv0=-1,vv1=-1;
1404 int side0,side1;
1405 int *eptr;
1406 int v0,v1;
1407 short *vp;
1408
1409 //@@ check_check();
1410
1411 v0 = verts[0];
1412 v1 = verts[1];
1413 vp = seg->verts;
1414
1415 for (i=0; i<8; i++) {
1416 int svv = *vp++; // seg->verts[i];
1417
1418 if (vv0==-1 && svv == v0) {
1419 vv0 = i;
1420 if (vv1 != -1)
1421 break;
1422 }
1423
1424 if (vv1==-1 && svv == v1) {
1425 vv1 = i;
1426 if (vv0 != -1)
1427 break;
1428 }
1429 }
1430
1431 Assert(vv0!=-1 && vv1!=-1);
1432
1433 eptr = Edge_to_sides[vv0][vv1];
1434
1435 side0 = eptr[0];
1436 side1 = eptr[1];
1437
1438 Assert(side0!=-1 && side1!=-1);
1439
1440 if (side0 != notside) {
1441 Assert(side1==notside);
1442 return side0;
1443 }
1444 else {
1445 Assert(side0==notside);
1446 return side1;
1447 }
1448
1449 }
1450
1451 //find the two segments that join a given seg though two sides, and
1452 //the sides of those segments the abut.
find_joining_side_norms(vms_vector * norm0_0,vms_vector * norm0_1,vms_vector * norm1_0,vms_vector * norm1_1,vms_vector ** pnt0,vms_vector ** pnt1,segment * seg,int s0,int s1)1453 int find_joining_side_norms(vms_vector *norm0_0,vms_vector *norm0_1,vms_vector *norm1_0,vms_vector *norm1_1,vms_vector **pnt0,vms_vector **pnt1,segment *seg,int s0,int s1)
1454 {
1455 segment *seg0,*seg1;
1456 short edge_verts[2];
1457 int notside0,notside1;
1458 int edgeside0,edgeside1;
1459
1460 Assert(s0!=-1 && s1!=-1);
1461
1462 seg0 = &Segments[seg->children[s0]];
1463 seg1 = &Segments[seg->children[s1]];
1464
1465 edge_verts[0] = seg->verts[Two_sides_to_edge[s0][s1][0]];
1466 edge_verts[1] = seg->verts[Two_sides_to_edge[s0][s1][1]];
1467
1468 Assert(edge_verts[0]!=-1 && edge_verts[1]!=-1);
1469
1470 notside0 = find_connect_side(seg,seg0);
1471 Assert(notside0 != -1);
1472 notside1 = find_connect_side(seg,seg1);
1473 Assert(notside1 != -1);
1474
1475 edgeside0 = find_seg_side(seg0,edge_verts,notside0);
1476 edgeside1 = find_seg_side(seg1,edge_verts,notside1);
1477
1478 //deal with the case where an edge is shared by more than two segments
1479
1480 //@@ if (IS_CHILD(seg0->children[edgeside0])) {
1481 //@@ segment *seg00;
1482 //@@ int notside00;
1483 //@@
1484 //@@ seg00 = &Segments[seg0->children[edgeside0]];
1485 //@@
1486 //@@ if (seg00 != seg1) {
1487 //@@
1488 //@@ notside00 = find_connect_side(seg0,seg00);
1489 //@@ Assert(notside00 != -1);
1490 //@@
1491 //@@ edgeside0 = find_seg_side(seg00,edge_verts,notside00);
1492 //@@ seg0 = seg00;
1493 //@@ }
1494 //@@
1495 //@@ }
1496 //@@
1497 //@@ if (IS_CHILD(seg1->children[edgeside1])) {
1498 //@@ segment *seg11;
1499 //@@ int notside11;
1500 //@@
1501 //@@ seg11 = &Segments[seg1->children[edgeside1]];
1502 //@@
1503 //@@ if (seg11 != seg0) {
1504 //@@ notside11 = find_connect_side(seg1,seg11);
1505 //@@ Assert(notside11 != -1);
1506 //@@
1507 //@@ edgeside1 = find_seg_side(seg11,edge_verts,notside11);
1508 //@@ seg1 = seg11;
1509 //@@ }
1510 //@@ }
1511
1512 // if ( IS_CHILD(seg0->children[edgeside0]) ||
1513 // IS_CHILD(seg1->children[edgeside1]))
1514 // return 0;
1515
1516 #ifdef COMPACT_SEGS
1517 get_side_normals(seg0, edgeside0, norm0_0, norm0_1 );
1518 get_side_normals(seg1, edgeside1, norm1_0, norm1_1 );
1519 #else
1520 *norm0_0 = seg0->sides[edgeside0].normals[0];
1521 *norm0_1 = seg0->sides[edgeside0].normals[1];
1522 *norm1_0 = seg1->sides[edgeside1].normals[0];
1523 *norm1_1 = seg1->sides[edgeside1].normals[1];
1524 #endif
1525
1526 *pnt0 = &Vertices[seg0->verts[Side_to_verts[edgeside0][seg0->sides[edgeside0].type==3?1:0]]];
1527 *pnt1 = &Vertices[seg1->verts[Side_to_verts[edgeside1][seg1->sides[edgeside1].type==3?1:0]]];
1528
1529 return 1;
1530 }
1531
1532 //see if the order matters for these two children.
1533 //returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0
compare_children(segment * seg,short c0,short c1)1534 int compare_children(segment *seg,short c0,short c1)
1535 {
1536 vms_vector norm0_0,norm0_1,*pnt0,temp;
1537 vms_vector norm1_0,norm1_1,*pnt1;
1538 fix d0_0,d0_1,d1_0,d1_1,d0,d1;
1539 int t;
1540
1541 if (Side_opposite[c0] == c1) return 0;
1542
1543 Assert(c0!=-1 && c1!=-1);
1544
1545 //find normals of adjoining sides
1546
1547 t = find_joining_side_norms(&norm0_0,&norm0_1,&norm1_0,&norm1_1,&pnt0,&pnt1,seg,c0,c1);
1548
1549 //if (!t)
1550 // return 0;
1551
1552 vm_vec_sub(&temp,&Viewer_eye,pnt0);
1553 d0_0 = vm_vec_dot(&norm0_0,&temp);
1554 d0_1 = vm_vec_dot(&norm0_1,&temp);
1555
1556 vm_vec_sub(&temp,&Viewer_eye,pnt1);
1557 d1_0 = vm_vec_dot(&norm1_0,&temp);
1558 d1_1 = vm_vec_dot(&norm1_1,&temp);
1559
1560 d0 = (d0_0 < 0 || d0_1 < 0)?-1:1;
1561 d1 = (d1_0 < 0 || d1_1 < 0)?-1:1;
1562
1563 if (d0 < 0 && d1 < 0)
1564 return 0;
1565
1566 if (d0 < 0)
1567 return 1;
1568 else if (d1 < 0)
1569 return -1;
1570 else
1571 return 0;
1572
1573 }
1574
1575 int ssc_total=0,ssc_swaps=0;
1576
1577 //short the children of segment to render in the correct order
1578 //returns non-zero if swaps were made
sort_seg_children(segment * seg,int n_children,short * child_list)1579 int sort_seg_children(segment *seg,int n_children,short *child_list)
1580 {
1581 int i,j;
1582 int r;
1583 int made_swaps,count;
1584
1585 if (n_children == 0) return 0;
1586
1587 ssc_total++;
1588
1589 //for each child, compare with other children and see if order matters
1590 //if order matters, fix if wrong
1591
1592 count = 0;
1593
1594 do {
1595 made_swaps = 0;
1596
1597 for (i=0;i<n_children-1;i++)
1598 for (j=i+1;child_list[i]!=-1 && j<n_children;j++)
1599 if (child_list[j]!=-1) {
1600 r = compare_children(seg,child_list[i],child_list[j]);
1601
1602 if (r == 1) {
1603 int temp = child_list[i];
1604 child_list[i] = child_list[j];
1605 child_list[j] = temp;
1606 made_swaps=1;
1607 }
1608 }
1609
1610 } while (made_swaps && ++count<n_children);
1611
1612 if (count)
1613 ssc_swaps++;
1614
1615 return count;
1616 }
1617
add_obj_to_seglist(int objnum,int listnum)1618 void add_obj_to_seglist(int objnum,int listnum)
1619 {
1620 int i,checkn,marker;
1621
1622 checkn = listnum;
1623
1624 //first, find a slot
1625
1626 //mprintf((0,"adding obj %d to %d",objnum,listnum));
1627
1628 do {
1629
1630 for (i=0;render_obj_list[checkn][i] >= 0;i++);
1631
1632 Assert(i < OBJS_PER_SEG);
1633
1634 marker = render_obj_list[checkn][i];
1635
1636 if (marker != -1) {
1637 checkn = -marker;
1638 //Assert(checkn < MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
1639 if (checkn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
1640 Int3();
1641 return;
1642 }
1643 }
1644
1645 } while (marker != -1);
1646
1647 //mprintf((0," slot %d,%d",checkn,i));
1648
1649
1650 //now we have found a slot. put object in it
1651
1652 if (i != OBJS_PER_SEG-1) {
1653
1654 render_obj_list[checkn][i] = objnum;
1655 render_obj_list[checkn][i+1] = -1;
1656 }
1657 else { //chain to additional list
1658 int lookn;
1659
1660 //find an available sublist
1661
1662 for (lookn=MAX_RENDER_SEGS;render_obj_list[lookn][0]!=-1 && lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;lookn++);
1663
1664 //Assert(lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
1665 if (lookn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
1666 Int3();
1667 return;
1668 }
1669
1670 render_obj_list[checkn][i] = -lookn;
1671 render_obj_list[lookn][0] = objnum;
1672 render_obj_list[lookn][1] = -1;
1673
1674 }
1675
1676 //mprintf((0," added!\n"));
1677
1678 }
1679 #ifdef __sun__
1680 // the following is a drop-in replacement for the broken libc qsort on solaris
1681 // taken from http://www.snippets.org/snippets/portable/RG_QSORT+C.php3
1682
1683 #define qsort qsort_dropin
1684
1685 /******************************************************************/
1686 /* qsort.c -- Non-Recursive ANSI Quicksort function */
1687 /* Public domain by Raymond Gardner, Englewood CO February 1991 */
1688 /******************************************************************/
1689 #define COMP(a, b) ((*comp)((void *)(a), (void *)(b)))
1690 #define T 7 // subfiles of <= T elements will be insertion sorteded (T >= 3)
1691 #define SWAP(a, b) (swap_bytes((char *)(a), (char *)(b), size))
1692
swap_bytes(char * a,char * b,size_t nbytes)1693 static void swap_bytes(char *a, char *b, size_t nbytes)
1694 {
1695 char tmp;
1696 do {
1697 tmp = *a; *a++ = *b; *b++ = tmp;
1698 } while ( --nbytes );
1699 }
1700
qsort(void * basep,size_t nelems,size_t size,int (* comp)(const void *,const void *))1701 void qsort(void *basep, size_t nelems, size_t size,
1702 int (*comp)(const void *, const void *))
1703 {
1704 char *stack[40], **sp; /* stack and stack pointer */
1705 char *i, *j, *limit; /* scan and limit pointers */
1706 size_t thresh; /* size of T elements in bytes */
1707 char *base; /* base pointer as char * */
1708 base = (char *)basep; /* set up char * base pointer */
1709 thresh = T * size; /* init threshold */
1710 sp = stack; /* init stack pointer */
1711 limit = base + nelems * size;/* pointer past end of array */
1712 for ( ;; ) { /* repeat until break... */
1713 if ( limit - base > thresh ) { /* if more than T elements */
1714 /* swap base with middle */
1715 SWAP((((limit-base)/size)/2)*size+base, base);
1716 i = base + size; /* i scans left to right */
1717 j = limit - size; /* j scans right to left */
1718 if ( COMP(i, j) > 0 ) /* Sedgewick's */
1719 SWAP(i, j); /* three-element sort */
1720 if ( COMP(base, j) > 0 ) /* sets things up */
1721 SWAP(base, j); /* so that */
1722 if ( COMP(i, base) > 0 ) /* *i <= *base <= *j */
1723 SWAP(i, base); /* *base is pivot element */
1724 for ( ;; ) { /* loop until break */
1725 do /* move i right */
1726 i += size; /* until *i >= pivot */
1727 while ( COMP(i, base) < 0 );
1728 do /* move j left */
1729 j -= size; /* until *j <= pivot */
1730 while ( COMP(j, base) > 0 );
1731 if ( i > j ) /* if pointers crossed */
1732 break; /* break loop */
1733 SWAP(i, j); /* else swap elements, keep scanning*/
1734 }
1735 SWAP(base, j); /* move pivot into correct place */
1736 if ( j - base > limit - i ) { /* if left subfile larger */
1737 sp[0] = base; /* stack left subfile base */
1738 sp[1] = j; /* and limit */
1739 base = i; /* sort the right subfile */
1740 } else { /* else right subfile larger*/
1741 sp[0] = i; /* stack right subfile base */
1742 sp[1] = limit; /* and limit */
1743 limit = j; /* sort the left subfile */
1744 }
1745 sp += 2; /* increment stack pointer */
1746 } else { /* else subfile is small, use insertion sort */
1747 for ( j = base, i = j+size; i < limit; j = i, i += size )
1748 for ( ; COMP(j, j+size) > 0; j -= size ) {
1749 SWAP(j, j+size);
1750 if ( j == base )
1751 break;
1752 }
1753 if ( sp != stack ) { /* if any entries on stack */
1754 sp -= 2; /* pop the base and limit */
1755 base = sp[0];
1756 limit = sp[1];
1757 } else /* else stack empty, done */
1758 break;
1759 }
1760 }
1761 }
1762 #endif // __sun__ qsort drop-in replacement
1763
1764 #define SORT_LIST_SIZE 100
1765
1766 typedef struct sort_item {
1767 int objnum;
1768 fix dist;
1769 } sort_item;
1770
1771 sort_item sort_list[SORT_LIST_SIZE];
1772 int n_sort_items;
1773
1774 //compare function for object sort.
sort_func(const sort_item * a,const sort_item * b)1775 int sort_func(const sort_item *a,const sort_item *b)
1776 {
1777 fix delta_dist;
1778 object *obj_a,*obj_b;
1779
1780 delta_dist = a->dist - b->dist;
1781
1782 obj_a = &Objects[a->objnum];
1783 obj_b = &Objects[b->objnum];
1784
1785 if (abs(delta_dist) < (obj_a->size + obj_b->size)) { //same position
1786
1787 //these two objects are in the same position. see if one is a fireball
1788 //or laser or something that should plot on top. Don't do this for
1789 //the afterburner blobs, though.
1790
1791 if (obj_a->type == OBJ_WEAPON || (obj_a->type == OBJ_FIREBALL && obj_a->id != VCLIP_AFTERBURNER_BLOB))
1792 if (!(obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL))
1793 return -1; //a is weapon, b is not, so say a is closer
1794 else; //both are weapons
1795 else
1796 if (obj_b->type == OBJ_WEAPON || (obj_b->type == OBJ_FIREBALL && obj_b->id != VCLIP_AFTERBURNER_BLOB))
1797 return 1; //b is weapon, a is not, so say a is farther
1798
1799 //no special case, fall through to normal return
1800 }
1801
1802 return delta_dist; //return distance
1803 }
1804
build_object_lists(int n_segs)1805 void build_object_lists(int n_segs)
1806 {
1807 int nn;
1808
1809 //mprintf((0,"build n_segs=%d",n_segs));
1810
1811 for (nn=0;nn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;nn++)
1812 render_obj_list[nn][0] = -1;
1813
1814 for (nn=0;nn<n_segs;nn++) {
1815 int segnum;
1816
1817 segnum = Render_list[nn];
1818
1819 //mprintf((0,"nn=%d seg=%d ",nn,segnum));
1820
1821 if (segnum != -1) {
1822 int objnum;
1823 object *obj;
1824
1825 for (objnum=Segments[segnum].objects;objnum!=-1;objnum = obj->next) {
1826 int new_segnum,did_migrate,list_pos;
1827
1828 obj = &Objects[objnum];
1829
1830 Assert( obj->segnum == segnum );
1831
1832 if (obj->flags & OF_ATTACHED)
1833 continue; //ignore this object
1834
1835 new_segnum = segnum;
1836 list_pos = nn;
1837
1838 //mprintf((0,"objnum=%d ",objnum));
1839 if (obj->type != OBJ_CNTRLCEN && !(obj->type==OBJ_ROBOT && obj->id==65)) //don't migrate controlcen
1840 do {
1841 segmasks m;
1842
1843 did_migrate = 0;
1844
1845 m = get_seg_masks(&obj->pos,new_segnum,obj->size);
1846
1847 if (m.sidemask) {
1848 int sn,sf;
1849
1850 for (sn=0,sf=1;sn<6;sn++,sf<<=1)
1851 if (m.sidemask & sf) {
1852 segment *seg = &Segments[new_segnum];
1853
1854 if (WALL_IS_DOORWAY(seg,sn) & WID_FLY_FLAG) { //can explosion migrate through
1855 int child = seg->children[sn];
1856 int checknp;
1857
1858 for (checknp=list_pos;checknp--;)
1859 if (Render_list[checknp] == child) {
1860 //mprintf((0,"mig from %d to %d ",new_segnum,child));
1861 new_segnum = child;
1862 list_pos = checknp;
1863 did_migrate = 1;
1864 }
1865 }
1866 }
1867 }
1868
1869 } while (0); //while (did_migrate);
1870
1871 add_obj_to_seglist(objnum,list_pos);
1872
1873 }
1874
1875 }
1876 }
1877
1878 //mprintf((0,"done build "));
1879
1880 //now that there's a list for each segment, sort the items in those lists
1881 for (nn=0;nn<n_segs;nn++) {
1882 int segnum;
1883
1884 segnum = Render_list[nn];
1885
1886 //mprintf((0,"nn=%d seg=%d ",nn,segnum));
1887
1888 if (segnum != -1) {
1889 int t,lookn,i,n;
1890
1891 //first count the number of objects & copy into sort list
1892
1893 lookn = nn;
1894 i = n_sort_items = 0;
1895 while ((t=render_obj_list[lookn][i++])!=-1)
1896 if (t<0)
1897 {lookn = -t; i=0;}
1898 else
1899 if (n_sort_items < SORT_LIST_SIZE-1) { //add if room
1900 sort_list[n_sort_items].objnum = t;
1901 //NOTE: maybe use depth, not dist - quicker computation
1902 sort_list[n_sort_items].dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
1903 n_sort_items++;
1904 }
1905 else { //no room for object
1906 int ii;
1907
1908 #ifndef NDEBUG
1909 FILE *tfile=fopen("sortlist.out","wt");
1910
1911 //I find this strange, so I'm going to write out
1912 //some information to look at later
1913 if (tfile) {
1914 for (ii=0;ii<SORT_LIST_SIZE;ii++) {
1915 int objnum = sort_list[ii].objnum;
1916
1917 fprintf(tfile,"Obj %3d Type = %2d Id = %2d Dist = %08x Segnum = %3d\n",
1918 objnum,Objects[objnum].type,Objects[objnum].id,sort_list[ii].dist,Objects[objnum].segnum);
1919 }
1920 fclose(tfile);
1921 }
1922 #endif
1923
1924 Int3(); //Get Matt!!!
1925
1926 //Now try to find a place for this object by getting rid
1927 //of an object we don't care about
1928
1929 for (ii=0;ii<SORT_LIST_SIZE;ii++) {
1930 int objnum = sort_list[ii].objnum;
1931 object *obj = &Objects[objnum];
1932 int type = obj->type;
1933
1934 //replace debris & fireballs
1935 if (type == OBJ_DEBRIS || type == OBJ_FIREBALL) {
1936 fix dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
1937
1938 //don't replace same kind of object unless new
1939 //one is closer
1940
1941 if (Objects[t].type != type || dist < sort_list[ii].dist) {
1942 sort_list[ii].objnum = t;
1943 sort_list[ii].dist = dist;
1944 break;
1945 }
1946 }
1947 }
1948
1949 Int3(); //still couldn't find a slot
1950 }
1951
1952
1953 //now call qsort
1954 #if defined(__WATCOMC__) || defined(MACINTOSH)
1955 qsort(sort_list,n_sort_items,sizeof(*sort_list),
1956 sort_func);
1957 #else
1958 qsort(sort_list,n_sort_items,sizeof(*sort_list),
1959 (int (*)(const void*,const void*))sort_func);
1960 #endif
1961
1962 //now copy back into list
1963
1964 lookn = nn;
1965 i = 0;
1966 n = n_sort_items;
1967 while ((t=render_obj_list[lookn][i])!=-1 && n>0)
1968 if (t<0)
1969 {lookn = -t; i=0;}
1970 else
1971 render_obj_list[lookn][i++] = sort_list[--n].objnum;
1972 render_obj_list[lookn][i] = -1; //mark (possibly new) end
1973 }
1974 }
1975 }
1976
1977 int Use_player_head_angles = 0;
1978 vms_angvec Player_head_angles;
1979
1980 extern int Num_tmaps_drawn;
1981 extern int Total_pixels;
1982 //--unused-- int Total_num_tmaps_drawn=0;
1983
1984 int Rear_view=0;
1985 extern ubyte RenderingType;
1986
1987 void start_lighting_frame(object *viewer);
1988
1989 #ifdef JOHN_ZOOM
1990 fix Zoom_factor=F1_0;
1991 #endif
1992 //renders onto current canvas
render_frame(fix eye_offset,int window_num)1993 void render_frame(fix eye_offset, int window_num)
1994 {
1995 int start_seg_num;
1996
1997 #if defined(POLY_ACC)
1998 //$$ not needed for Verite, probably optional for ViRGE. pa_flush();
1999 #endif
2000
2001 //Total_num_tmaps_drawn += Num_tmaps_drawn;
2002 //if ((FrameCount > 0) && (Total_num_tmaps_drawn))
2003 // mprintf((0, "Frame: %4i, total = %6i, Avg = %7.3f, Avgpix=%7.3f\n", Num_tmaps_drawn, Total_num_tmaps_drawn, (float) Total_num_tmaps_drawn/FrameCount, (float) Total_pixels/Total_num_tmaps_drawn));
2004 //Num_tmaps_drawn = 0;
2005
2006 if (Endlevel_sequence) {
2007 render_endlevel_frame(eye_offset);
2008 FrameCount++;
2009 return;
2010 }
2011
2012 #ifdef NEWDEMO
2013 if ( Newdemo_state == ND_STATE_RECORDING && eye_offset >= 0 ) {
2014
2015 // mprintf ((0,"Objnum=%d objtype=%d objid=%d\n",Viewer-Objects,Viewer->type,Viewer->id));
2016
2017 if (RenderingType==0)
2018 newdemo_record_start_frame(FrameCount, FrameTime );
2019 if (RenderingType!=255)
2020 newdemo_record_viewer_object(Viewer);
2021 }
2022 #endif
2023
2024 //Here:
2025
2026 start_lighting_frame(Viewer); //this is for ugly light-smoothing hack
2027
2028 g3_start_frame();
2029
2030 Viewer_eye = Viewer->pos;
2031
2032 // if (Viewer->type == OBJ_PLAYER && (Cockpit_mode!=CM_REAR_VIEW))
2033 // vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
2034
2035 if (eye_offset) {
2036 vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
2037 }
2038
2039 #ifdef EDITOR
2040 if (Function_mode==FMODE_EDITOR)
2041 Viewer_eye = Viewer->pos;
2042 #endif
2043
2044 start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
2045
2046 if (start_seg_num==-1)
2047 start_seg_num = Viewer->segnum;
2048
2049 if (Viewer==ConsoleObject && Use_player_head_angles) {
2050 vms_matrix headm,viewm;
2051 vm_angles_2_matrix(&headm,&Player_head_angles);
2052 vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
2053 g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
2054 //@@} else if ((Cockpit_mode==CM_REAR_VIEW) && (Viewer==ConsoleObject)) {
2055 } else if (Rear_view && (Viewer==ConsoleObject)) {
2056 vms_matrix headm,viewm;
2057 Player_head_angles.p = Player_head_angles.b = 0;
2058 Player_head_angles.h = 0x7fff;
2059 vm_angles_2_matrix(&headm,&Player_head_angles);
2060 vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
2061 g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
2062 } else {
2063 #ifdef JOHN_ZOOM
2064 if (keyd_pressed[KEY_RSHIFT] ) {
2065 Zoom_factor += FrameTime*4;
2066 if (Zoom_factor > F1_0*5 ) Zoom_factor=F1_0*5;
2067 } else {
2068 Zoom_factor -= FrameTime*4;
2069 if (Zoom_factor < F1_0 ) Zoom_factor = F1_0;
2070 }
2071 g3_set_view_matrix(&Viewer_eye,&Viewer->orient,fixdiv(Render_zoom,Zoom_factor));
2072 #else
2073 g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
2074 #endif
2075 }
2076
2077 if (Clear_window == 1) {
2078 if (Clear_window_color == -1)
2079 Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7);
2080 gr_clear_canvas(Clear_window_color);
2081 }
2082 #ifndef NDEBUG
2083 if (Show_only_curside)
2084 gr_clear_canvas(Clear_window_color);
2085 #endif
2086
2087 render_mine(start_seg_num, eye_offset, window_num);
2088
2089 if (Use_player_head_angles )
2090 draw_3d_reticle(eye_offset);
2091
2092 g3_end_frame();
2093
2094 //RenderingType=0;
2095
2096 // -- Moved from here by MK, 05/17/95, wrong if multiple renders/frame! FrameCount++; //we have rendered a frame
2097 }
2098
2099 int first_terminal_seg;
2100
update_rendered_data(int window_num,object * viewer,int rear_view_flag,int user)2101 void update_rendered_data(int window_num, object *viewer, int rear_view_flag, int user)
2102 {
2103 Assert(window_num < MAX_RENDERED_WINDOWS);
2104 Window_rendered_data[window_num].frame = FrameCount;
2105 Window_rendered_data[window_num].viewer = viewer;
2106 Window_rendered_data[window_num].rear_view = rear_view_flag;
2107 Window_rendered_data[window_num].user = user;
2108 }
2109
2110 //build a list of segments to be rendered
2111 //fills in Render_list & N_render_segs
build_segment_list(int start_seg_num,int window_num)2112 void build_segment_list(int start_seg_num, int window_num)
2113 {
2114 int lcnt,scnt,ecnt;
2115 int l,c;
2116 int ch;
2117
2118 memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1));
2119 memset(render_pos, -1, sizeof(render_pos[0])*(Highest_segment_index+1));
2120 //memset(no_render_flag, 0, sizeof(no_render_flag[0])*(MAX_RENDER_SEGS));
2121 memset(processed, 0, sizeof(processed));
2122
2123 #ifndef NDEBUG
2124 memset(visited2, 0, sizeof(visited2[0])*(Highest_segment_index+1));
2125 #endif
2126
2127 lcnt = scnt = 0;
2128
2129 Render_list[lcnt] = start_seg_num; visited[start_seg_num]=1;
2130 Seg_depth[lcnt] = 0;
2131 lcnt++;
2132 ecnt = lcnt;
2133 render_pos[start_seg_num] = 0;
2134
2135 #ifndef NDEBUG
2136 if (pre_draw_segs)
2137 render_segment(start_seg_num, window_num);
2138 #endif
2139
2140 render_windows[0].left=render_windows[0].top=0;
2141 render_windows[0].right=grd_curcanv->cv_bitmap.bm_w-1;
2142 render_windows[0].bot=grd_curcanv->cv_bitmap.bm_h-1;
2143
2144 //breadth-first renderer
2145
2146 //build list
2147
2148 for (l=0;l<Render_depth;l++) {
2149
2150 //while (scnt < ecnt) {
2151 for (scnt=0;scnt < ecnt;scnt++) {
2152 int rotated,segnum;
2153 window *check_w;
2154 short child_list[MAX_SIDES_PER_SEGMENT]; //list of ordered sides to process
2155 int n_children; //how many sides in child_list
2156 segment *seg;
2157
2158 if (processed[scnt])
2159 continue;
2160
2161 processed[scnt]=1;
2162
2163 segnum = Render_list[scnt];
2164 check_w = &render_windows[scnt];
2165
2166 #ifndef NDEBUG
2167 if (draw_boxes)
2168 draw_window_box(RED,check_w->left,check_w->top,check_w->right,check_w->bot);
2169 #endif
2170
2171 if (segnum == -1) continue;
2172
2173 seg = &Segments[segnum];
2174 rotated=0;
2175
2176 //look at all sides of this segment.
2177 //tricky code to look at sides in correct order follows
2178
2179 for (c=n_children=0;c<MAX_SIDES_PER_SEGMENT;c++) { //build list of sides
2180 int wid;
2181
2182 wid = WALL_IS_DOORWAY(seg, c);
2183
2184 ch=seg->children[c];
2185
2186 if ( (window_check || !visited[ch]) && (wid & WID_RENDPAST_FLAG) ) {
2187 if (behind_check) {
2188 byte *sv = Side_to_verts[c];
2189 ubyte codes_and=0xff;
2190 int i;
2191
2192 rotate_list(8,seg->verts);
2193 rotated=1;
2194
2195 for (i=0;i<4;i++)
2196 codes_and &= Segment_points[seg->verts[sv[i]]].p3_codes;
2197
2198 if (codes_and & CC_BEHIND) continue;
2199
2200 }
2201 child_list[n_children++] = c;
2202 }
2203 }
2204
2205 //now order the sides in some magical way
2206
2207 if (new_seg_sorting)
2208 sort_seg_children(seg,n_children,child_list);
2209
2210 //for (c=0;c<MAX_SIDES_PER_SEGMENT;c++) {
2211 // ch=seg->children[c];
2212
2213 for (c=0;c<n_children;c++) {
2214 int siden;
2215
2216 siden = child_list[c];
2217 ch=seg->children[siden];
2218 //if ( (window_check || !visited[ch])&& (WALL_IS_DOORWAY(seg, c))) {
2219 {
2220 if (window_check) {
2221 int i;
2222 ubyte codes_and_3d,codes_and_2d;
2223 short _x,_y,min_x=32767,max_x=-32767,min_y=32767,max_y=-32767;
2224 int no_proj_flag=0; //a point wasn't projected
2225
2226 if (rotated<2) {
2227 if (!rotated)
2228 rotate_list(8,seg->verts);
2229 project_list(8,seg->verts);
2230 rotated=2;
2231 }
2232
2233 for (i=0,codes_and_3d=codes_and_2d=0xff;i<4;i++) {
2234 int p = seg->verts[Side_to_verts[siden][i]];
2235 g3s_point *pnt = &Segment_points[p];
2236
2237 if (! (pnt->p3_flags&PF_PROJECTED)) {no_proj_flag=1; break;}
2238
2239 _x = f2i(pnt->p3_sx);
2240 _y = f2i(pnt->p3_sy);
2241
2242 codes_and_3d &= pnt->p3_codes;
2243 codes_and_2d &= code_window_point(_x,_y,check_w);
2244
2245 #ifndef NDEBUG
2246 if (draw_edges) {
2247 gr_setcolor(BM_XRGB(31,0,31));
2248 gr_line(pnt->p3_sx,pnt->p3_sy,
2249 Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sx,
2250 Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sy);
2251 }
2252 #endif
2253
2254 if (_x < min_x) min_x = _x;
2255 if (_x > max_x) max_x = _x;
2256
2257 if (_y < min_y) min_y = _y;
2258 if (_y > max_y) max_y = _y;
2259
2260 }
2261
2262 #ifndef NDEBUG
2263 if (draw_boxes)
2264 draw_window_box(WHITE,min_x,min_y,max_x,max_y);
2265 #endif
2266
2267 if (no_proj_flag || (!codes_and_3d && !codes_and_2d)) { //maybe add this segment
2268 int rp = render_pos[ch];
2269 window *new_w = &render_windows[lcnt];
2270
2271 if (no_proj_flag) *new_w = *check_w;
2272 else {
2273 new_w->left = max(check_w->left,min_x);
2274 new_w->right = min(check_w->right,max_x);
2275 new_w->top = max(check_w->top,min_y);
2276 new_w->bot = min(check_w->bot,max_y);
2277 }
2278
2279 //see if this seg already visited, and if so, does current window
2280 //expand the old window?
2281 if (rp != -1) {
2282 if (new_w->left < render_windows[rp].left ||
2283 new_w->top < render_windows[rp].top ||
2284 new_w->right > render_windows[rp].right ||
2285 new_w->bot > render_windows[rp].bot) {
2286
2287 new_w->left = min(new_w->left,render_windows[rp].left);
2288 new_w->right = max(new_w->right,render_windows[rp].right);
2289 new_w->top = min(new_w->top,render_windows[rp].top);
2290 new_w->bot = max(new_w->bot,render_windows[rp].bot);
2291
2292 if (no_migrate_segs) {
2293 //no_render_flag[lcnt] = 1;
2294 Render_list[lcnt] = -1;
2295 render_windows[rp] = *new_w; //get updated window
2296 processed[rp] = 0; //force reprocess
2297 goto no_add;
2298 }
2299 else
2300 Render_list[rp]=-1;
2301 }
2302 else goto no_add;
2303 }
2304
2305 #ifndef NDEBUG
2306 if (draw_boxes)
2307 draw_window_box(5,new_w->left,new_w->top,new_w->right,new_w->bot);
2308 #endif
2309
2310 render_pos[ch] = lcnt;
2311 Render_list[lcnt] = ch;
2312 Seg_depth[lcnt] = l;
2313 lcnt++;
2314 if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
2315 visited[ch] = 1;
2316
2317 #ifndef NDEBUG
2318 if (pre_draw_segs)
2319 render_segment(ch, window_num);
2320 #endif
2321 no_add:
2322 ;
2323
2324 }
2325 }
2326 else {
2327 Render_list[lcnt] = ch;
2328 Seg_depth[lcnt] = l;
2329 lcnt++;
2330 if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
2331 visited[ch] = 1;
2332 }
2333 }
2334 }
2335 }
2336
2337 scnt = ecnt;
2338 ecnt = lcnt;
2339
2340 }
2341 done_list:
2342
2343 lcnt_save = lcnt;
2344 scnt_save = scnt;
2345
2346 first_terminal_seg = scnt;
2347 N_render_segs = lcnt;
2348
2349 }
2350
2351 //renders onto current canvas
render_mine(int start_seg_num,fix eye_offset,int window_num)2352 void render_mine(int start_seg_num,fix eye_offset, int window_num)
2353 {
2354 #ifndef NDEBUG
2355 int i;
2356 #endif
2357 int nn;
2358
2359 // Initialize number of objects (actually, robots!) rendered this frame.
2360 Window_rendered_data[window_num].num_objects = 0;
2361
2362 #ifdef LASER_HACK
2363 Hack_nlasers = 0;
2364 #endif
2365
2366 #ifndef NDEBUG
2367 for (i=0;i<=Highest_object_index;i++)
2368 object_rendered[i] = 0;
2369 #endif
2370
2371 //set up for rendering
2372
2373 render_start_frame();
2374
2375
2376 #if defined(EDITOR) && !defined(NDEBUG)
2377 if (Show_only_curside) {
2378 rotate_list(8,Cursegp->verts);
2379 render_side(Cursegp,Curside);
2380 goto done_rendering;
2381 }
2382 #endif
2383
2384
2385 #ifdef EDITOR
2386 if (_search_mode) {
2387 //lcnt = lcnt_save;
2388 //scnt = scnt_save;
2389 }
2390 else
2391 #endif
2392 //NOTE LINK TO ABOVE!!
2393 build_segment_list(start_seg_num, window_num); //fills in Render_list & N_render_segs
2394
2395 //render away
2396
2397 #ifndef NDEBUG
2398 if (!window_check) {
2399 Window_clip_left = Window_clip_top = 0;
2400 Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
2401 Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1;
2402 }
2403 #endif
2404
2405 #ifndef NDEBUG
2406 if (!(_search_mode)) {
2407 int i;
2408
2409 for (i=0;i<N_render_segs;i++) {
2410 int segnum;
2411
2412 segnum = Render_list[i];
2413
2414 if (segnum != -1)
2415 {
2416 if (visited2[segnum])
2417 Int3(); //get Matt
2418 else
2419 visited2[segnum] = 1;
2420 }
2421 }
2422 }
2423 #endif
2424
2425 if (!(_search_mode))
2426 build_object_lists(N_render_segs);
2427
2428 if (eye_offset<=0) // Do for left eye or zero.
2429 set_dynamic_light();
2430
2431 if (!_search_mode && Clear_window == 2) {
2432 if (first_terminal_seg < N_render_segs) {
2433 int i;
2434
2435 if (Clear_window_color == -1)
2436 Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7);
2437
2438 gr_setcolor(Clear_window_color);
2439
2440 for (i=first_terminal_seg; i<N_render_segs; i++) {
2441 if (Render_list[i] != -1) {
2442 #ifndef NDEBUG
2443 if ((render_windows[i].left == -1) || (render_windows[i].top == -1) || (render_windows[i].right == -1) || (render_windows[i].bot == -1))
2444 Int3();
2445 else
2446 #endif
2447 //NOTE LINK TO ABOVE!
2448 gr_rect(render_windows[i].left, render_windows[i].top, render_windows[i].right, render_windows[i].bot);
2449 }
2450 }
2451 }
2452 }
2453
2454 for (nn=N_render_segs;nn--;) {
2455 int segnum;
2456 int objnp;
2457
2458 // Interpolation_method = 0;
2459 segnum = Render_list[nn];
2460 Current_seg_depth = Seg_depth[nn];
2461
2462 //if (!no_render_flag[nn])
2463 if (segnum!=-1 && (_search_mode || visited[segnum]!=255)) {
2464 //set global render window vars
2465
2466 if (window_check) {
2467 Window_clip_left = render_windows[nn].left;
2468 Window_clip_top = render_windows[nn].top;
2469 Window_clip_right = render_windows[nn].right;
2470 Window_clip_bot = render_windows[nn].bot;
2471 }
2472
2473 //mprintf((0," %d",segnum));
2474
2475 render_segment(segnum, window_num);
2476 visited[segnum]=255;
2477
2478 if (window_check) { //reset for objects
2479 Window_clip_left = Window_clip_top = 0;
2480 Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
2481 Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1;
2482 }
2483
2484 if (migrate_objects) {
2485 //int n_expl_objs=0,expl_objs[5],i;
2486 int listnum;
2487 int save_linear_depth = Max_linear_depth;
2488
2489 Max_linear_depth = Max_linear_depth_objects;
2490
2491 listnum = nn;
2492
2493 //mprintf((0,"render objs seg %d",segnum));
2494
2495 for (objnp=0;render_obj_list[listnum][objnp]!=-1;) {
2496 int ObjNumber = render_obj_list[listnum][objnp];
2497
2498 if (ObjNumber >= 0) {
2499
2500 //mprintf( (0, "Type: %d\n", Objects[ObjNumber].type ));
2501
2502 //if (Objects[ObjNumber].type == OBJ_FIREBALL && n_expl_objs<5) {
2503 // expl_objs[n_expl_objs++] = ObjNumber;
2504 //} else
2505 #ifdef LASER_HACK
2506 if ( (Objects[ObjNumber].type==OBJ_WEAPON) && //if its a weapon
2507 (Objects[ObjNumber].lifeleft==Laser_max_time ) && // and its in it's first frame
2508 (Hack_nlasers< MAX_HACKED_LASERS) && // and we have space for it
2509 (Objects[ObjNumber].laser_info.parent_num>-1) && // and it has a parent
2510 ((Viewer-Objects)==Objects[ObjNumber].laser_info.parent_num) // and it's parent is the viewer
2511 ) {
2512 Hack_laser_list[Hack_nlasers++] = ObjNumber; //then make it draw after everything else.
2513 //mprintf( (0, "O%d ", ObjNumber ));
2514 } else
2515 #endif
2516 do_render_object(ObjNumber, window_num); // note link to above else
2517
2518 objnp++;
2519 }
2520 else {
2521
2522 listnum = -ObjNumber;
2523 objnp = 0;
2524
2525 }
2526
2527 }
2528
2529 //for (i=0;i<n_expl_objs;i++)
2530 // do_render_object(expl_objs[i], window_num);
2531
2532 //mprintf((0,"done seg %d\n",segnum));
2533
2534 Max_linear_depth = save_linear_depth;
2535
2536 }
2537
2538 }
2539 }
2540
2541 //mprintf((0,"\n"));
2542
2543
2544 #ifdef LASER_HACK
2545 // Draw the hacked lasers last
2546 for (i=0; i < Hack_nlasers; i++ ) {
2547 //mprintf( (0, "D%d ", Hack_laser_list[i] ));
2548 do_render_object(Hack_laser_list[i], window_num);
2549 }
2550 #endif
2551
2552 // -- commented out by mk on 09/14/94...did i do a good thing?? object_render_targets();
2553
2554 #ifdef EDITOR
2555 #ifndef NDEBUG
2556 //draw curedge stuff
2557 if (Outline_mode) outline_seg_side(Cursegp,Curside,Curedge,Curvert);
2558 #endif
2559
2560 done_rendering:
2561 ;
2562
2563 #endif
2564
2565 }
2566 #ifdef EDITOR
2567
2568 extern int render_3d_in_big_window;
2569
2570 //finds what segment is at a given x&y - seg,side,face are filled in
2571 //works on last frame rendered. returns true if found
2572 //if seg<0, then an object was found, and the object number is -seg-1
find_seg_side_face(short x,short y,int * seg,int * side,int * face,int * poly)2573 int find_seg_side_face(short x,short y,int *seg,int *side,int *face,int *poly)
2574 {
2575 _search_mode = -1;
2576
2577 _search_x = x; _search_y = y;
2578
2579 found_seg = -1;
2580
2581 if (render_3d_in_big_window) {
2582 grs_canvas temp_canvas;
2583
2584 gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
2585 LargeView.ev_canv->cv_bitmap.bm_w,LargeView.ev_canv->cv_bitmap.bm_h);
2586
2587 gr_set_current_canvas(&temp_canvas);
2588
2589 render_frame(0, 0);
2590 }
2591 else {
2592 gr_set_current_canvas(&VR_render_sub_buffer[0]); //render off-screen
2593 render_frame(0, 0);
2594 }
2595
2596 _search_mode = 0;
2597
2598 *seg = found_seg;
2599 *side = found_side;
2600 *face = found_face;
2601 *poly = found_poly;
2602
2603 // mprintf((0,"found seg=%d, side=%d, face=%d, poly=%d\n",found_seg,found_side,found_face,found_poly));
2604
2605 return (found_seg!=-1);
2606
2607 }
2608
2609 #endif
2610