]> icculus.org git repositories - btb/d2x.git/blob - main/render.c
properly render cloaked walls in OpenGL (fixes #1608)
[btb/d2x.git] / main / render.c
1 /* $Id: render.c,v 1.19 2004-05-11 01:53:34 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  * Rendering Stuff
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
447 int toggle_outline_mode(void)
448 {
449         return Outline_mode = !Outline_mode;
450 }
451
452 int toggle_show_only_curside(void)
453 {
454         return Show_only_curside = !Show_only_curside;
455 }
456
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
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
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
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.
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 #ifdef OGL
623                 g3_draw_transp_poly(nv,pointlist);  // draw as flat poly
624 #else
625                 gr_setcolor(BM_XRGB(0,0,0));        // set to black (matters for s3)
626
627                 g3_draw_poly(nv,pointlist);         // draw as flat poly
628 #endif
629
630                 Gr_scanline_darkening_level = GR_FADE_LEVELS;
631
632                 return;
633         }
634
635         // -- Using new headlight system...face_light = -vm_vec_dot(&Viewer->orient.fvec,norm);
636
637         if (tmap1 >= NumTextures) {
638                 mprintf((0,"Invalid tmap number %d, NumTextures=%d, changing to 0\n",tmap1,NumTextures));
639
640         #ifndef RELEASE
641                 Int3();
642         #endif
643
644                 Segments[segnum].sides[sidenum].tmap_num = 0;
645         }
646
647 #ifdef OGL
648         if (ogl_alttexmerge){
649                 PIGGY_PAGE_IN(Textures[tmap1]);
650                 bm = &GameBitmaps[Textures[tmap1].index];
651                 if (tmap2){
652                         PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]);
653                         bm2 = &GameBitmaps[Textures[tmap2&0x3FFF].index];
654                 }
655                 if (bm2 && (bm2->bm_flags&BM_FLAG_SUPER_TRANSPARENT)){
656                         bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
657                         bm2 = NULL;
658                 }
659         } else
660 #endif
661
662                 // New code for overlapping textures...
663                 if (tmap2 != 0) {
664                         bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
665                 } else {
666                         bm = &GameBitmaps[Textures[tmap1].index];
667                         PIGGY_PAGE_IN(Textures[tmap1]);
668                 }
669
670         Assert( !(bm->bm_flags & BM_FLAG_PAGED_OUT) );
671
672         //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect)/2.0 + 0.5);
673         //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect));
674
675         reflect = Face_reflectivity;            // f1_0;        //until we figure this stuff out...
676
677         //set light values for each vertex & build pointlist
678         {
679                 int i;
680
681                 // -- Using new headlight system...face_light = fixmul(face_light,reflect);
682
683                 for (i=0;i<nv;i++) {
684
685                         //the uvl struct has static light already in it
686
687                         //scale static light for destruction effect
688                         if (Control_center_destroyed || Seismic_tremor_magnitude)       //make lights flash
689                                 uvl_copy[i].l = fixmul(flash_scale,uvl_copy[i].l);
690
691                         //add in dynamic light (from explosions, etc.)
692                         uvl_copy[i].l += Dynamic_light[vp[i]];
693
694                         //add in light from player's headlight
695                         // -- Using new headlight system...uvl_copy[i].l += compute_headlight_light(&Segment_points[vp[i]].p3_vec,face_light);
696
697                         //saturate at max value
698                         if (uvl_copy[i].l > MAX_LIGHT)
699                                 uvl_copy[i].l = MAX_LIGHT;
700
701                 }
702         }
703
704 #ifdef EDITOR
705         if ((Render_only_bottom) && (sidenum == WBOTTOM))
706                 g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,&GameBitmaps[Textures[Bottom_bitmap_num].index]);
707         else
708 #endif
709
710 #ifdef OGL
711                 if (bm2){
712                         g3_draw_tmap_2(nv,pointlist,(g3s_uvl *) uvl_copy,bm,bm2,((tmap2&0xC000)>>14) & 3);
713                 }else
714 #endif
715                         g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,bm);
716
717 #ifndef NDEBUG
718         if (Outline_mode) draw_outline(nv, pointlist);
719 #endif
720 }
721
722 #ifdef EDITOR
723 // ----------------------------------------------------------------------------
724 //      Only called if editor active.
725 //      Used to determine which face was clicked on.
726 void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp)
727 {
728         int     i;
729
730         if (_search_mode) {
731                 int save_lighting;
732                 grs_bitmap *bm;
733                 uvl uvl_copy[8];
734                 g3s_point *pointlist[4];
735
736                 if (tmap2 > 0 )
737                         bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
738                 else
739                         bm = &GameBitmaps[Textures[tmap1].index];
740
741                 for (i=0; i<nv; i++) {
742                         uvl_copy[i] = uvlp[i];
743                         pointlist[i] = &Segment_points[vp[i]];
744                 }
745
746                 gr_setcolor(0);
747                 gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
748                 gr_setcolor(1);                                 //and render in color one
749  save_lighting = Lighting_on;
750  Lighting_on = 2;
751                 //g3_draw_poly(nv,vp);
752                 g3_draw_tmap(nv,pointlist, (g3s_uvl *)uvl_copy, bm);
753  Lighting_on = save_lighting;
754
755                 if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) == 1) {
756                         found_seg = segnum;
757                         found_side = sidenum;
758                         found_face = facenum;
759                 }
760         }
761 }
762 #endif
763
764 fix     Tulate_min_dot = (F1_0/4);
765 //--unused-- fix        Tulate_min_ratio = (2*F1_0);
766 fix     Min_n0_n1_dot   = (F1_0*15/16);
767
768 extern int contains_flare(segment *segp, int sidenum);
769 extern fix      Obj_light_xlate[16];
770
771 // -----------------------------------------------------------------------------------
772 //      Render a side.
773 //      Check for normal facing.  If so, render faces on side dictated by sidep->type.
774 void render_side(segment *segp, int sidenum)
775 {
776         short                   vertnum_list[4];
777         side                    *sidep = &segp->sides[sidenum];
778         vms_vector      tvec;
779         fix                     v_dot_n0, v_dot_n1;
780         uvl                     temp_uvls[3];
781         fix                     min_dot, max_dot;
782         vms_vector  normals[2];
783         int                     wid_flags;
784
785
786         wid_flags = WALL_IS_DOORWAY(segp,sidenum);
787
788         if (!(wid_flags & WID_RENDER_FLAG))             //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL)
789                 return;
790
791 #ifdef COMPACT_SEGS
792         get_side_normals(segp, sidenum, &normals[0], &normals[1] );
793 #else
794         normals[0] = segp->sides[sidenum].normals[0];
795         normals[1] = segp->sides[sidenum].normals[1];
796 #endif
797
798         //      ========== Mark: Here is the change...beginning here: ==========
799
800         if (sidep->type == SIDE_IS_QUAD) {
801
802                 vm_vec_sub(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
803
804                 // -- Old, slow way --  //      Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
805                 // -- Old, slow way --  //      deal with it, get the dot product.
806                 // -- Old, slow way --  if (sidep->type == SIDE_IS_TRI_13)
807                 // -- Old, slow way --          vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
808                 // -- Old, slow way --  else
809                 // -- Old, slow way --          vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
810
811                 get_side_verts(vertnum_list,segp-Segments,sidenum);
812                 v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
813
814 // -- flare creates point -- {
815 // -- flare creates point --    int     flare_index;
816 // -- flare creates point -- 
817 // -- flare creates point --    flare_index = contains_flare(segp, sidenum);
818 // -- flare creates point -- 
819 // -- flare creates point --    if (flare_index != -1) {
820 // -- flare creates point --            int                     tri;
821 // -- flare creates point --            fix                     u, v, l;
822 // -- flare creates point --            vms_vector      *hit_point;
823 // -- flare creates point --            short                   vertnum_list[4];
824 // -- flare creates point -- 
825 // -- flare creates point --            hit_point = &Objects[flare_index].pos;
826 // -- flare creates point -- 
827 // -- flare creates point --            find_hitpoint_uv( &u, &v, &l, hit_point, segp, sidenum, 0);     //      last parm means always use face 0.
828 // -- flare creates point -- 
829 // -- flare creates point --            get_side_verts(vertnum_list, segp-Segments, sidenum);
830 // -- flare creates point -- 
831 // -- flare creates point --            g3_rotate_point(&Segment_points[MAX_VERTICES-1], hit_point);
832 // -- flare creates point -- 
833 // -- flare creates point --            for (tri=0; tri<4; tri++) {
834 // -- flare creates point --                    short   tri_verts[3];
835 // -- flare creates point --                    uvl     tri_uvls[3];
836 // -- flare creates point -- 
837 // -- flare creates point --                    tri_verts[0] = vertnum_list[tri];
838 // -- flare creates point --                    tri_verts[1] = vertnum_list[(tri+1) % 4];
839 // -- flare creates point --                    tri_verts[2] = MAX_VERTICES-1;
840 // -- flare creates point -- 
841 // -- flare creates point --                    tri_uvls[0] = sidep->uvls[tri];
842 // -- flare creates point --                    tri_uvls[1] = sidep->uvls[(tri+1)%4];
843 // -- flare creates point --                    tri_uvls[2].u = u;
844 // -- flare creates point --                    tri_uvls[2].v = v;
845 // -- flare creates point --                    tri_uvls[2].l = F1_0;
846 // -- flare creates point -- 
847 // -- flare creates point --                    render_face(segp-Segments, sidenum, 3, tri_verts, sidep->tmap_num, sidep->tmap_num2, tri_uvls, &normals[0]);
848 // -- flare creates point --            }
849 // -- flare creates point -- 
850 // -- flare creates point --    return;
851 // -- flare creates point --    }
852 // -- flare creates point -- }
853
854                 if (v_dot_n0 >= 0) {
855                         render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
856                         #ifdef EDITOR
857                         check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
858                         #endif
859                 }
860         } else {
861                 //      Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
862                 //      deal with it, get the dot product.
863                 if (sidep->type == SIDE_IS_TRI_13)
864                         vm_vec_normalized_dir_quick(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
865                 else
866                         vm_vec_normalized_dir_quick(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
867
868                 get_side_verts(vertnum_list,segp-Segments,sidenum);
869
870                 v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
871
872                 //      ========== Mark: The change ends here. ==========
873
874                 //      Although this side has been triangulated, because it is not planar, see if it is acceptable
875                 //      to render it as a single quadrilateral.  This is a function of how far away the viewer is, how non-planar
876                 //      the face is, how normal to the surfaces the view is.
877                 //      Now, if both dot products are close to 1.0, then render two triangles as a single quad.
878                 v_dot_n1 = vm_vec_dot(&tvec, &normals[1]);
879
880                 if (v_dot_n0 < v_dot_n1) {
881                         min_dot = v_dot_n0;
882                         max_dot = v_dot_n1;
883                 } else {
884                         min_dot = v_dot_n1;
885                         max_dot = v_dot_n0;
886                 }
887
888                 //      Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio))
889                 if (Detriangulation_on && ((min_dot+F1_0/256 > max_dot) || ((Viewer->segnum != segp-Segments) &&  (min_dot > Tulate_min_dot) && (max_dot < min_dot*2)))) {
890                         fix     n0_dot_n1;
891
892                         //      The other detriangulation code doesn't deal well with badly non-planar sides.
893                         n0_dot_n1 = vm_vec_dot(&normals[0], &normals[1]);
894                         if (n0_dot_n1 < Min_n0_n1_dot)
895                                 goto im_so_ashamed;
896
897                         render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
898                         #ifdef EDITOR
899                         check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
900                         #endif
901                 } else {
902 im_so_ashamed: ;
903                         if (sidep->type == SIDE_IS_TRI_02) {
904                                 if (v_dot_n0 >= 0) {
905                                         render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, wid_flags);
906                                         #ifdef EDITOR
907                                         check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
908                                         #endif
909                                 }
910
911                                 if (v_dot_n1 >= 0) {
912                                         temp_uvls[0] = sidep->uvls[0];          temp_uvls[1] = sidep->uvls[2];          temp_uvls[2] = sidep->uvls[3];
913                                         vertnum_list[1] = vertnum_list[2];      vertnum_list[2] = vertnum_list[3];      // want to render from vertices 0, 2, 3 on side
914                                         render_face(segp-Segments, sidenum, 3, &vertnum_list[0], sidep->tmap_num, sidep->tmap_num2, temp_uvls, wid_flags);
915                                         #ifdef EDITOR
916                                         check_face(segp-Segments, sidenum, 1, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
917                                         #endif
918                                 }
919                         } else if (sidep->type ==  SIDE_IS_TRI_13) {
920                                 if (v_dot_n1 >= 0) {
921                                         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
922                                         #ifdef EDITOR
923                                         check_face(segp-Segments, sidenum, 1, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
924                                         #endif
925                                 }
926
927                                 if (v_dot_n0 >= 0) {
928                                         temp_uvls[0] = sidep->uvls[0];          temp_uvls[1] = sidep->uvls[1];          temp_uvls[2] = sidep->uvls[3];
929                                         vertnum_list[2] = vertnum_list[3];              // want to render from vertices 0,1,3
930                                         render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, temp_uvls, wid_flags);
931                                         #ifdef EDITOR
932                                         check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
933                                         #endif
934                                 }
935
936                         } else
937 #ifdef __DJGPP__
938                                 Error("Illegal side type in render_side, type = %i, segment # = %li, side # = %i\n", sidep->type, segp-Segments, sidenum);
939 #else
940                                 Error("Illegal side type in render_side, type = %i, segment # = %i, side # = %i\n", sidep->type, segp-Segments, sidenum);
941 #endif
942                 }
943         }
944
945 }
946
947 #ifdef EDITOR
948 void render_object_search(object *obj)
949 {
950         int changed=0;
951
952         //note that we draw each pixel object twice, since we cannot control
953         //what color the object draws in, so we try color 0, then color 1,
954         //in case the object itself is rendering color 0
955
956         gr_setcolor(0);
957         gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
958         render_object(obj);
959         if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 0)
960                 changed=1;
961
962         gr_setcolor(1);
963         gr_pixel(_search_x,_search_y);  //set our search pixel to color zero
964         render_object(obj);
965         if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 1)
966                 changed=1;
967
968         if (changed) {
969                 if (obj->segnum != -1)
970                         Cursegp = &Segments[obj->segnum];
971                 found_seg = -(obj-Objects+1);
972         }
973 }
974 #endif
975
976 extern ubyte DemoDoingRight,DemoDoingLeft;
977
978 void do_render_object(int objnum, int window_num)
979 {
980         #ifdef EDITOR
981         int save_3d_outline=0;
982         #endif
983         object *obj = &Objects[objnum];
984         int count = 0;
985         int n;
986
987         Assert(objnum < MAX_OBJECTS);
988
989         #ifndef NDEBUG
990         if (object_rendered[objnum]) {          //already rendered this...
991                 Int3();         //get Matt!!!
992                 return;
993         }
994
995         object_rendered[objnum] = 1;
996         #endif
997
998    if (Newdemo_state==ND_STATE_PLAYBACK)  
999          {
1000           if ((DemoDoingLeft==6 || DemoDoingRight==6) && Objects[objnum].type==OBJ_PLAYER)
1001                 {
1002                         // A nice fat hack: keeps the player ship from showing up in the
1003                         // small extra view when guiding a missile in the big window
1004                         
1005                         mprintf ((0,"Returning from render_object prematurely...\n"));
1006                         return; 
1007                 }
1008          }
1009
1010         //      Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so
1011         //      that the guided missile system will know what objects to look at.
1012         //      I didn't know we had guided missiles before the release of D1. --MK
1013         if ((Objects[objnum].type == OBJ_ROBOT) || (Objects[objnum].type == OBJ_PLAYER)) {
1014                 //Assert(Window_rendered_data[window_num].rendered_objects < MAX_RENDERED_OBJECTS);
1015                 //      This peculiar piece of code makes us keep track of the most recently rendered objects, which
1016                 //      are probably the higher priority objects, without overflowing the buffer
1017                 if (Window_rendered_data[window_num].num_objects >= MAX_RENDERED_OBJECTS) {
1018                         Int3();
1019                         Window_rendered_data[window_num].num_objects /= 2;
1020                 }
1021                 Window_rendered_data[window_num].rendered_objects[Window_rendered_data[window_num].num_objects++] = objnum;
1022         }
1023
1024         if ((count++ > MAX_OBJECTS) || (obj->next == objnum)) {
1025                 Int3();                                 // infinite loop detected
1026                 obj->next = -1;         // won't this clean things up?
1027                 return;                                 // get out of this infinite loop!
1028         }
1029
1030                 //g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size);
1031
1032         //check for editor object
1033
1034         #ifdef EDITOR
1035         if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index) {
1036                 save_3d_outline = g3d_interp_outline;
1037                 g3d_interp_outline=1;
1038         }
1039         #endif
1040
1041         #ifdef EDITOR
1042         if (_search_mode)
1043                 render_object_search(obj);
1044         else
1045         #endif
1046                 //NOTE LINK TO ABOVE
1047                 render_object(obj);
1048
1049         for (n=obj->attached_obj;n!=-1;n=Objects[n].ctype.expl_info.next_attach) {
1050
1051                 Assert(Objects[n].type == OBJ_FIREBALL);
1052                 Assert(Objects[n].control_type == CT_EXPLOSION);
1053                 Assert(Objects[n].flags & OF_ATTACHED);
1054
1055                 render_object(&Objects[n]);
1056         }
1057
1058
1059         #ifdef EDITOR
1060         if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index)
1061                 g3d_interp_outline = save_3d_outline;
1062         #endif
1063
1064
1065         //DEBUG mprintf( (0, "%d ", objnum ));
1066
1067 }
1068
1069 #ifndef NDEBUG
1070 int     draw_boxes=0;
1071 int window_check=1,draw_edges=0,new_seg_sorting=1,pre_draw_segs=0;
1072 int no_migrate_segs=1,migrate_objects=1,behind_check=1;
1073 int check_window_check=0;
1074 #else
1075 #define draw_boxes                      0
1076 #define window_check                    1
1077 #define draw_edges                      0
1078 #define new_seg_sorting         1
1079 #define pre_draw_segs           0
1080 #define no_migrate_segs         1
1081 #define migrate_objects         1
1082 #define behind_check                    1
1083 #define check_window_check      0
1084 #endif
1085
1086 //increment counter for checking if points rotated
1087 //This must be called at the start of the frame if rotate_list() will be used
1088 void render_start_frame()
1089 {
1090         RL_framecount++;
1091
1092         if (RL_framecount==0) {         //wrap!
1093
1094                 memset(Rotated_last,0,sizeof(Rotated_last));            //clear all to zero
1095                 RL_framecount=1;                                                                                        //and set this frame to 1
1096         }
1097 }
1098
1099 //Given a lit of point numbers, rotate any that haven't been rotated this frame
1100 g3s_codes rotate_list(int nv,short *pointnumlist)
1101 {
1102         int i,pnum;
1103         g3s_point *pnt;
1104         g3s_codes cc;
1105
1106         cc.and = 0xff;  cc.or = 0;
1107
1108         for (i=0;i<nv;i++) {
1109
1110                 pnum = pointnumlist[i];
1111
1112                 pnt = &Segment_points[pnum];
1113
1114                 if (Rotated_last[pnum] != RL_framecount) {
1115
1116                         g3_rotate_point(pnt,&Vertices[pnum]);
1117
1118                         Rotated_last[pnum] = RL_framecount;
1119                 }
1120
1121                 cc.and &= pnt->p3_codes;
1122                 cc.or  |= pnt->p3_codes;
1123         }
1124
1125         return cc;
1126
1127 }
1128
1129 //Given a lit of point numbers, project any that haven't been projected
1130 void project_list(int nv,short *pointnumlist)
1131 {
1132         int i,pnum;
1133
1134         for (i=0;i<nv;i++) {
1135
1136                 pnum = pointnumlist[i];
1137
1138                 if (!(Segment_points[pnum].p3_flags & PF_PROJECTED))
1139
1140                         g3_project_point(&Segment_points[pnum]);
1141
1142         }
1143 }
1144
1145
1146 // -----------------------------------------------------------------------------------
1147 void render_segment(int segnum, int window_num)
1148 {
1149         segment         *seg = &Segments[segnum];
1150         g3s_codes       cc;
1151         int                     sn;
1152
1153         Assert(segnum!=-1 && segnum<=Highest_segment_index);
1154
1155         cc=rotate_list(8,seg->verts);
1156
1157         if (! cc.and) {         //all off screen?
1158
1159 //mprintf( (0, "!"));
1160                 //DEBUG mprintf( (0, "[Segment %d: ", segnum ));
1161
1162                 // set_segment_local_light_value(segnum,INITIAL_LOCAL_LIGHT);
1163
1164       if (Viewer->type!=OBJ_ROBOT)
1165                 Automap_visited[segnum]=1;
1166
1167                 for (sn=0; sn<MAX_SIDES_PER_SEGMENT; sn++)
1168                         render_side(seg, sn);
1169         }
1170
1171         //draw any objects that happen to be in this segment
1172
1173         //sort objects!
1174         //object_sort_segment_objects( seg );
1175                 
1176         #ifndef NDEBUG
1177         if (!migrate_objects) {
1178                 int objnum;
1179                 for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
1180                         do_render_object(objnum, window_num);
1181         }
1182         #endif
1183
1184         //DEBUG mprintf( (0, "]\n", segnum ));
1185
1186 }
1187
1188 // ----- This used to be called when Show_only_curside was set.
1189 // ----- It is wholly and superiorly replaced by render_side.
1190 // -- //render one side of one segment
1191 // -- void render_seg_side(segment *seg,int _side)
1192 // -- {
1193 // --   g3s_codes cc;
1194 // --   short vertnum_list[4];
1195 // -- 
1196 // --   cc=g3_rotate_list(8,&seg->verts);
1197 // -- 
1198 // --   if (! cc.and) {         //all off screen?
1199 // --           int fn,pn,i;
1200 // --           side *s;
1201 // --           face *f;
1202 // --           poly *p;
1203 // -- 
1204 // --           s=&seg->sides[_side];
1205 // -- 
1206 // --           for (f=s->faces,fn=s->num_faces;fn;fn--,f++)
1207 // --                   for (p=f->polys,pn=f->num_polys;pn;pn--,p++) {
1208 // --                           grs_bitmap *tmap;
1209 // --   
1210 // --                           for (i=0;i<p->num_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]];
1211 // --   
1212 // --                           if (p->tmap_num >= NumTextures) {
1213 // --                                   Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures);
1214 // --                                   p->tmap_num = 0;                //change it permanantly
1215 // --                           }
1216 // --   
1217 // --                           tmap = Textures[p->tmap_num];
1218 // --   
1219 // --                           g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal);
1220 // --   
1221 // --                           if (Outline_mode) draw_outline(p->num_vertices,vertnum_list);
1222 // --                   }
1223 // --           }
1224 // -- 
1225 // -- }
1226
1227 #define CROSS_WIDTH  i2f(8)
1228 #define CROSS_HEIGHT i2f(8)
1229
1230 #ifndef NDEBUG
1231
1232 //draw outline for curside
1233 void outline_seg_side(segment *seg,int _side,int edge,int vert)
1234 {
1235         g3s_codes cc;
1236
1237         cc=rotate_list(8,seg->verts);
1238
1239         if (! cc.and) {         //all off screen?
1240                 side *s;
1241                 g3s_point *pnt;
1242
1243                 s=&seg->sides[_side];
1244
1245                 //render curedge of curside of curseg in green
1246
1247                 gr_setcolor(BM_XRGB(0,63,0));
1248                 g3_draw_line(&Segment_points[seg->verts[Side_to_verts[_side][edge]]],&Segment_points[seg->verts[Side_to_verts[_side][(edge+1)%4]]]);
1249
1250                 //draw a little cross at the current vert
1251
1252                 pnt = &Segment_points[seg->verts[Side_to_verts[_side][vert]]];
1253
1254                 g3_project_point(pnt);          //make sure projected
1255
1256 //              gr_setcolor(BM_XRGB(0,0,63));
1257 //              gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
1258 //              gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
1259
1260                 gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT);
1261                 gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
1262                 gr_line(pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
1263                 gr_line(pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT,pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy);
1264         }
1265 }
1266
1267 #endif
1268
1269 #if 0           //this stuff could probably just be deleted
1270
1271 #define DEFAULT_PERSPECTIVE_DEPTH 6
1272
1273 int Perspective_depth=DEFAULT_PERSPECTIVE_DEPTH;        //how many levels deep to render in perspective
1274
1275 int inc_perspective_depth(void)
1276 {
1277         return ++Perspective_depth;
1278
1279 }
1280
1281 int dec_perspective_depth(void)
1282 {
1283         return Perspective_depth==1?Perspective_depth:--Perspective_depth;
1284
1285 }
1286
1287 int reset_perspective_depth(void)
1288 {
1289         return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH;
1290
1291 }
1292 #endif
1293
1294 typedef struct window {
1295         short left,top,right,bot;
1296 } window;
1297
1298 ubyte code_window_point(fix x,fix y,window *w)
1299 {
1300         ubyte code=0;
1301
1302         if (x <= w->left)  code |= 1;
1303         if (x >= w->right) code |= 2;
1304
1305         if (y <= w->top) code |= 4;
1306         if (y >= w->bot) code |= 8;
1307
1308         return code;
1309 }
1310
1311 #ifndef NDEBUG
1312 void draw_window_box(int color,short left,short top,short right,short bot)
1313 {
1314         short l,t,r,b;
1315
1316         gr_setcolor(color);
1317
1318         l=left; t=top; r=right; b=bot;
1319
1320         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))
1321                 return;
1322
1323         if (l<0) l=0;
1324         if (t<0) t=0;
1325         if (r>=grd_curcanv->cv_bitmap.bm_w) r=grd_curcanv->cv_bitmap.bm_w-1;
1326         if (b>=grd_curcanv->cv_bitmap.bm_h) b=grd_curcanv->cv_bitmap.bm_h-1;
1327
1328         gr_line(i2f(l),i2f(t),i2f(r),i2f(t));
1329         gr_line(i2f(r),i2f(t),i2f(r),i2f(b));
1330         gr_line(i2f(r),i2f(b),i2f(l),i2f(b));
1331         gr_line(i2f(l),i2f(b),i2f(l),i2f(t));
1332
1333 }
1334 #endif
1335
1336 int matt_find_connect_side(int seg0,int seg1);
1337
1338 #ifndef NDEBUG
1339 char visited2[MAX_SEGMENTS];
1340 #endif
1341
1342 unsigned char visited[MAX_SEGMENTS];
1343 short Render_list[MAX_RENDER_SEGS];
1344 short Seg_depth[MAX_RENDER_SEGS];               //depth for each seg in Render_list
1345 ubyte processed[MAX_RENDER_SEGS];               //whether each entry has been processed
1346 int     lcnt_save,scnt_save;
1347 //@@short *persp_ptr;
1348 short render_pos[MAX_SEGMENTS]; //where in render_list does this segment appear?
1349 //ubyte no_render_flag[MAX_RENDER_SEGS];
1350 window render_windows[MAX_RENDER_SEGS];
1351
1352 short render_obj_list[MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS][OBJS_PER_SEG];
1353
1354 //for objects
1355
1356
1357
1358 #define RED   BM_XRGB(63,0,0)
1359 #define WHITE BM_XRGB(63,63,63)
1360
1361 //Given two sides of segment, tell the two verts which form the 
1362 //edge between them
1363 short Two_sides_to_edge[6][6][2] = {
1364         { {-1,-1}, {3,7}, {-1,-1}, {2,6}, {6,7}, {2,3} },
1365         { {3,7}, {-1,-1}, {0,4}, {-1,-1}, {4,7}, {0,3} },
1366         { {-1,-1}, {0,4}, {-1,-1}, {1,5}, {4,5}, {0,1} },
1367         { {2,6}, {-1,-1}, {1,5}, {-1,-1}, {5,6}, {1,2} },
1368         { {6,7}, {4,7}, {4,5}, {5,6}, {-1,-1}, {-1,-1} },
1369         { {2,3}, {0,3}, {0,1}, {1,2}, {-1,-1}, {-1,-1} }
1370 };
1371
1372 //given an edge specified by two verts, give the two sides on that edge
1373 int Edge_to_sides[8][8][2] = {
1374         { {-1,-1}, {2,5}, {-1,-1}, {1,5}, {1,2}, {-1,-1}, {-1,-1}, {-1,-1} },
1375         { {2,5}, {-1,-1}, {3,5}, {-1,-1}, {-1,-1}, {2,3}, {-1,-1}, {-1,-1} },
1376         { {-1,-1}, {3,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {0,3}, {-1,-1} },
1377         { {1,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {0,1} },
1378         { {1,2}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {1,4} },
1379         { {-1,-1}, {2,3}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {3,4}, {-1,-1} },
1380         { {-1,-1}, {-1,-1}, {0,3}, {-1,-1}, {-1,-1}, {3,4}, {-1,-1}, {0,4} },
1381         { {-1,-1}, {-1,-1}, {-1,-1}, {0,1}, {1,4}, {-1,-1}, {0,4}, {-1,-1} },
1382 };
1383
1384 //@@//perform simple check on tables
1385 //@@check_check()
1386 //@@{
1387 //@@    int i,j;
1388 //@@
1389 //@@    for (i=0;i<8;i++)
1390 //@@            for (j=0;j<8;j++)
1391 //@@                    Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] && 
1392 //@@                                    Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]);
1393 //@@
1394 //@@    for (i=0;i<6;i++)
1395 //@@            for (j=0;j<6;j++)
1396 //@@                    Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] && 
1397 //@@                                    Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]);
1398 //@@
1399 //@@
1400 //@@}
1401
1402
1403 //given an edge, tell what side is on that edge
1404 int find_seg_side(segment *seg,short *verts,int notside)
1405 {
1406         int i;
1407         int vv0=-1,vv1=-1;
1408         int side0,side1;
1409         int *eptr;
1410         int     v0,v1;
1411         short   *vp;
1412
1413 //@@    check_check();
1414
1415         v0 = verts[0];
1416         v1 = verts[1];
1417         vp = seg->verts;
1418
1419         for (i=0; i<8; i++) {
1420                 int svv = *vp++;        // seg->verts[i];
1421
1422                 if (vv0==-1 && svv == v0) {
1423                         vv0 = i;
1424                         if (vv1 != -1)
1425                                 break;
1426                 }
1427
1428                 if (vv1==-1 && svv == v1) {
1429                         vv1 = i;
1430                         if (vv0 != -1)
1431                                 break;
1432                 }
1433         }
1434
1435         Assert(vv0!=-1 && vv1!=-1);
1436
1437         eptr = Edge_to_sides[vv0][vv1];
1438
1439         side0 = eptr[0];
1440         side1 = eptr[1];
1441
1442         Assert(side0!=-1 && side1!=-1);
1443
1444         if (side0 != notside) {
1445                 Assert(side1==notside);
1446                 return side0;
1447         }
1448         else {
1449                 Assert(side0==notside);
1450                 return side1;
1451         }
1452
1453 }
1454
1455 //find the two segments that join a given seg though two sides, and
1456 //the sides of those segments the abut. 
1457 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)
1458 {
1459         segment *seg0,*seg1;
1460         short edge_verts[2];
1461         int notside0,notside1;
1462         int edgeside0,edgeside1;
1463
1464         Assert(s0!=-1 && s1!=-1);
1465
1466         seg0 = &Segments[seg->children[s0]];
1467         seg1 = &Segments[seg->children[s1]];
1468
1469         edge_verts[0] = seg->verts[Two_sides_to_edge[s0][s1][0]];
1470         edge_verts[1] = seg->verts[Two_sides_to_edge[s0][s1][1]];
1471
1472         Assert(edge_verts[0]!=-1 && edge_verts[1]!=-1);
1473
1474         notside0 = find_connect_side(seg,seg0);
1475         Assert(notside0 != -1);
1476         notside1 = find_connect_side(seg,seg1);
1477         Assert(notside1 != -1);
1478
1479         edgeside0 = find_seg_side(seg0,edge_verts,notside0);
1480         edgeside1 = find_seg_side(seg1,edge_verts,notside1);
1481
1482         //deal with the case where an edge is shared by more than two segments
1483
1484 //@@    if (IS_CHILD(seg0->children[edgeside0])) {
1485 //@@            segment *seg00;
1486 //@@            int notside00;
1487 //@@
1488 //@@            seg00 = &Segments[seg0->children[edgeside0]];
1489 //@@
1490 //@@            if (seg00 != seg1) {
1491 //@@
1492 //@@                    notside00 = find_connect_side(seg0,seg00);
1493 //@@                    Assert(notside00 != -1);
1494 //@@
1495 //@@                    edgeside0 = find_seg_side(seg00,edge_verts,notside00);
1496 //@@                    seg0 = seg00;
1497 //@@            }
1498 //@@
1499 //@@    }
1500 //@@
1501 //@@    if (IS_CHILD(seg1->children[edgeside1])) {
1502 //@@            segment *seg11;
1503 //@@            int notside11;
1504 //@@
1505 //@@            seg11 = &Segments[seg1->children[edgeside1]];
1506 //@@
1507 //@@            if (seg11 != seg0) {
1508 //@@                    notside11 = find_connect_side(seg1,seg11);
1509 //@@                    Assert(notside11 != -1);
1510 //@@
1511 //@@                    edgeside1 = find_seg_side(seg11,edge_verts,notside11);
1512 //@@                    seg1 = seg11;
1513 //@@            }
1514 //@@    }
1515
1516 //      if ( IS_CHILD(seg0->children[edgeside0]) ||
1517 //                IS_CHILD(seg1->children[edgeside1])) 
1518 //              return 0;
1519
1520         #ifdef COMPACT_SEGS
1521                 get_side_normals(seg0, edgeside0, norm0_0, norm0_1 );
1522                 get_side_normals(seg1, edgeside1, norm1_0, norm1_1 );
1523         #else 
1524                 *norm0_0 = seg0->sides[edgeside0].normals[0];
1525                 *norm0_1 = seg0->sides[edgeside0].normals[1];
1526                 *norm1_0 = seg1->sides[edgeside1].normals[0];
1527                 *norm1_1 = seg1->sides[edgeside1].normals[1];
1528         #endif
1529
1530         *pnt0 = &Vertices[seg0->verts[Side_to_verts[edgeside0][seg0->sides[edgeside0].type==3?1:0]]];
1531         *pnt1 = &Vertices[seg1->verts[Side_to_verts[edgeside1][seg1->sides[edgeside1].type==3?1:0]]];
1532
1533         return 1;
1534 }
1535
1536 //see if the order matters for these two children.
1537 //returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0
1538 int compare_children(segment *seg,short c0,short c1)
1539 {
1540         vms_vector norm0_0,norm0_1,*pnt0,temp;
1541         vms_vector norm1_0,norm1_1,*pnt1;
1542         fix d0_0,d0_1,d1_0,d1_1,d0,d1;
1543 int t;
1544
1545         if (Side_opposite[c0] == c1) return 0;
1546
1547         Assert(c0!=-1 && c1!=-1);
1548
1549         //find normals of adjoining sides
1550
1551         t = find_joining_side_norms(&norm0_0,&norm0_1,&norm1_0,&norm1_1,&pnt0,&pnt1,seg,c0,c1);
1552
1553 //if (!t)
1554 // return 0;
1555
1556         vm_vec_sub(&temp,&Viewer_eye,pnt0);
1557         d0_0 = vm_vec_dot(&norm0_0,&temp);
1558         d0_1 = vm_vec_dot(&norm0_1,&temp);
1559
1560         vm_vec_sub(&temp,&Viewer_eye,pnt1);
1561         d1_0 = vm_vec_dot(&norm1_0,&temp);
1562         d1_1 = vm_vec_dot(&norm1_1,&temp);
1563
1564         d0 = (d0_0 < 0 || d0_1 < 0)?-1:1;
1565         d1 = (d1_0 < 0 || d1_1 < 0)?-1:1;
1566
1567         if (d0 < 0 && d1 < 0)
1568                 return 0;
1569
1570         if (d0 < 0)
1571                 return 1;
1572         else if (d1 < 0)
1573                 return -1;
1574         else
1575                 return 0;
1576
1577 }
1578
1579 int ssc_total=0,ssc_swaps=0;
1580
1581 //short the children of segment to render in the correct order
1582 //returns non-zero if swaps were made
1583 int sort_seg_children(segment *seg,int n_children,short *child_list)
1584 {
1585         int i,j;
1586         int r;
1587         int made_swaps,count;
1588
1589         if (n_children == 0) return 0;
1590
1591  ssc_total++;
1592
1593         //for each child,  compare with other children and see if order matters
1594         //if order matters, fix if wrong
1595
1596         count = 0;
1597
1598         do {
1599                 made_swaps = 0;
1600
1601                 for (i=0;i<n_children-1;i++)
1602                         for (j=i+1;child_list[i]!=-1 && j<n_children;j++)
1603                                 if (child_list[j]!=-1) {
1604                                         r = compare_children(seg,child_list[i],child_list[j]);
1605
1606                                         if (r == 1) {
1607                                                 int temp = child_list[i];
1608                                                 child_list[i] = child_list[j];
1609                                                 child_list[j] = temp;
1610                                                 made_swaps=1;
1611                                         }
1612                                 }
1613
1614         } while (made_swaps && ++count<n_children);
1615
1616  if (count)
1617   ssc_swaps++;
1618
1619         return count;
1620 }
1621
1622 void add_obj_to_seglist(int objnum,int listnum)
1623 {
1624         int i,checkn,marker;
1625
1626         checkn = listnum;
1627
1628         //first, find a slot
1629
1630 //mprintf((0,"adding obj %d to %d",objnum,listnum));
1631
1632         do {
1633
1634                 for (i=0;render_obj_list[checkn][i] >= 0;i++);
1635         
1636                 Assert(i < OBJS_PER_SEG);
1637         
1638                 marker = render_obj_list[checkn][i];
1639
1640                 if (marker != -1) {
1641                         checkn = -marker;
1642                         //Assert(checkn < MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
1643                         if (checkn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
1644                                 Int3();
1645                                 return;
1646                         }
1647                 }
1648
1649         } while (marker != -1);
1650
1651 //mprintf((0,"  slot %d,%d",checkn,i));
1652
1653
1654         //now we have found a slot.  put object in it
1655
1656         if (i != OBJS_PER_SEG-1) {
1657
1658                 render_obj_list[checkn][i] = objnum;
1659                 render_obj_list[checkn][i+1] = -1;
1660         }
1661         else {                          //chain to additional list
1662                 int lookn;
1663
1664                 //find an available sublist
1665
1666                 for (lookn=MAX_RENDER_SEGS;render_obj_list[lookn][0]!=-1 && lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;lookn++);
1667
1668                 //Assert(lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
1669                 if (lookn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
1670                         Int3();
1671                         return;
1672                 }
1673
1674                 render_obj_list[checkn][i] = -lookn;
1675                 render_obj_list[lookn][0] = objnum;
1676                 render_obj_list[lookn][1] = -1;
1677
1678         }
1679
1680 //mprintf((0,"  added!\n"));
1681
1682 }
1683 #ifdef __sun__
1684 // the following is a drop-in replacement for the broken libc qsort on solaris
1685 // taken from http://www.snippets.org/snippets/portable/RG_QSORT+C.php3
1686
1687 #define qsort qsort_dropin
1688
1689 /******************************************************************/
1690 /* qsort.c  --  Non-Recursive ANSI Quicksort function             */
1691 /* Public domain by Raymond Gardner, Englewood CO  February 1991  */
1692 /******************************************************************/
1693 #define  COMP(a, b)  ((*comp)((void *)(a), (void *)(b)))
1694 #define  T 7 // subfiles of <= T elements will be insertion sorteded (T >= 3)
1695 #define  SWAP(a, b)  (swap_bytes((char *)(a), (char *)(b), size))
1696
1697 static void swap_bytes(char *a, char *b, size_t nbytes)
1698 {
1699    char tmp;
1700    do {
1701       tmp = *a; *a++ = *b; *b++ = tmp;
1702    } while ( --nbytes );
1703 }
1704
1705 void qsort(void *basep, size_t nelems, size_t size,
1706                             int (*comp)(const void *, const void *))
1707 {
1708    char *stack[40], **sp;       /* stack and stack pointer        */
1709    char *i, *j, *limit;         /* scan and limit pointers        */
1710    size_t thresh;               /* size of T elements in bytes    */
1711    char *base;                  /* base pointer as char *         */
1712    base = (char *)basep;        /* set up char * base pointer     */
1713    thresh = T * size;           /* init threshold                 */
1714    sp = stack;                  /* init stack pointer             */
1715    limit = base + nelems * size;/* pointer past end of array      */
1716    for ( ;; ) {                 /* repeat until break...          */
1717       if ( limit - base > thresh ) {  /* if more than T elements  */
1718                                       /*   swap base with middle  */
1719          SWAP((((limit-base)/size)/2)*size+base, base);
1720          i = base + size;             /* i scans left to right    */
1721          j = limit - size;            /* j scans right to left    */
1722          if ( COMP(i, j) > 0 )        /* Sedgewick's              */
1723             SWAP(i, j);               /*    three-element sort    */
1724          if ( COMP(base, j) > 0 )     /*        sets things up    */
1725             SWAP(base, j);            /*            so that       */
1726          if ( COMP(i, base) > 0 )     /*      *i <= *base <= *j   */
1727             SWAP(i, base);            /* *base is pivot element   */
1728          for ( ;; ) {                 /* loop until break         */
1729             do                        /* move i right             */
1730                i += size;             /*        until *i >= pivot */
1731             while ( COMP(i, base) < 0 );
1732             do                        /* move j left              */
1733                j -= size;             /*        until *j <= pivot */
1734             while ( COMP(j, base) > 0 );
1735             if ( i > j )              /* if pointers crossed      */
1736                break;                 /*     break loop           */
1737             SWAP(i, j);       /* else swap elements, keep scanning*/
1738          }
1739          SWAP(base, j);         /* move pivot into correct place  */
1740          if ( j - base > limit - i ) {  /* if left subfile larger */
1741             sp[0] = base;             /* stack left subfile base  */
1742             sp[1] = j;                /*    and limit             */
1743             base = i;                 /* sort the right subfile   */
1744          } else {                     /* else right subfile larger*/
1745             sp[0] = i;                /* stack right subfile base */
1746             sp[1] = limit;            /*    and limit             */
1747             limit = j;                /* sort the left subfile    */
1748          }
1749          sp += 2;                     /* increment stack pointer  */
1750       } else {      /* else subfile is small, use insertion sort  */
1751          for ( j = base, i = j+size; i < limit; j = i, i += size )
1752             for ( ; COMP(j, j+size) > 0; j -= size ) {
1753                SWAP(j, j+size);
1754                if ( j == base )
1755                   break;
1756             }
1757          if ( sp != stack ) {         /* if any entries on stack  */
1758             sp -= 2;                  /* pop the base and limit   */
1759             base = sp[0];
1760             limit = sp[1];
1761          } else                       /* else stack empty, done   */
1762             break;
1763       }
1764    }
1765 }
1766 #endif // __sun__ qsort drop-in replacement
1767
1768 #define SORT_LIST_SIZE 100
1769
1770 typedef struct sort_item {
1771         int objnum;
1772         fix dist;
1773 } sort_item;
1774
1775 sort_item sort_list[SORT_LIST_SIZE];
1776 int n_sort_items;
1777
1778 //compare function for object sort. 
1779 int sort_func(const sort_item *a,const sort_item *b)
1780 {
1781         fix delta_dist;
1782         object *obj_a,*obj_b;
1783
1784         delta_dist = a->dist - b->dist;
1785
1786         obj_a = &Objects[a->objnum];
1787         obj_b = &Objects[b->objnum];
1788
1789         if (abs(delta_dist) < (obj_a->size + obj_b->size)) {            //same position
1790
1791                 //these two objects are in the same position.  see if one is a fireball
1792                 //or laser or something that should plot on top.  Don't do this for
1793                 //the afterburner blobs, though.
1794
1795                 if (obj_a->type == OBJ_WEAPON || (obj_a->type == OBJ_FIREBALL && obj_a->id != VCLIP_AFTERBURNER_BLOB))
1796                         if (!(obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL))
1797                                 return -1;      //a is weapon, b is not, so say a is closer
1798                         else;                           //both are weapons 
1799                 else
1800                         if (obj_b->type == OBJ_WEAPON || (obj_b->type == OBJ_FIREBALL && obj_b->id != VCLIP_AFTERBURNER_BLOB))
1801                                 return 1;       //b is weapon, a is not, so say a is farther
1802
1803                 //no special case, fall through to normal return
1804         }
1805
1806         return delta_dist;      //return distance
1807 }
1808
1809 void build_object_lists(int n_segs)
1810 {
1811         int nn;
1812
1813 //mprintf((0,"build n_segs=%d",n_segs));
1814
1815         for (nn=0;nn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;nn++)
1816                 render_obj_list[nn][0] = -1;
1817
1818         for (nn=0;nn<n_segs;nn++) {
1819                 int segnum;
1820
1821                 segnum = Render_list[nn];
1822
1823 //mprintf((0,"nn=%d seg=%d ",nn,segnum));
1824
1825                 if (segnum != -1) {
1826                         int objnum;
1827                         object *obj;
1828
1829                         for (objnum=Segments[segnum].objects;objnum!=-1;objnum = obj->next) {
1830                                 int new_segnum,did_migrate,list_pos;
1831
1832                                 obj = &Objects[objnum];
1833
1834                                 Assert( obj->segnum == segnum );
1835
1836                                 if (obj->flags & OF_ATTACHED)
1837                                         continue;               //ignore this object
1838
1839                                 new_segnum = segnum;
1840                                 list_pos = nn;
1841
1842 //mprintf((0,"objnum=%d ",objnum));
1843                                 if (obj->type != OBJ_CNTRLCEN && !(obj->type==OBJ_ROBOT && obj->id==65))                //don't migrate controlcen
1844                                 do {
1845                                         segmasks m;
1846
1847                                         did_migrate = 0;
1848         
1849                                         m = get_seg_masks(&obj->pos,new_segnum,obj->size);
1850         
1851                                         if (m.sidemask) {
1852                                                 int sn,sf;
1853
1854                                                 for (sn=0,sf=1;sn<6;sn++,sf<<=1)
1855                                                         if (m.sidemask & sf) {
1856                                                                 segment *seg = &Segments[new_segnum];
1857                 
1858                                                                 if (WALL_IS_DOORWAY(seg,sn) & WID_FLY_FLAG) {           //can explosion migrate through
1859                                                                         int child = seg->children[sn];
1860                                                                         int checknp;
1861                 
1862                                                                         for (checknp=list_pos;checknp--;)
1863                                                                                 if (Render_list[checknp] == child) {
1864 //mprintf((0,"mig from %d to %d ",new_segnum,child));
1865                                                                                         new_segnum = child;
1866                                                                                         list_pos = checknp;
1867                                                                                         did_migrate = 1;
1868                                                                                 }
1869                                                                 }
1870                                                         }
1871                                         }
1872         
1873                                 } while (0);    //while (did_migrate);
1874
1875                                 add_obj_to_seglist(objnum,list_pos);
1876         
1877                         }
1878
1879                 }
1880         }
1881
1882 //mprintf((0,"done build "));
1883
1884         //now that there's a list for each segment, sort the items in those lists
1885         for (nn=0;nn<n_segs;nn++) {
1886                 int segnum;
1887
1888                 segnum = Render_list[nn];
1889
1890 //mprintf((0,"nn=%d seg=%d ",nn,segnum));
1891
1892                 if (segnum != -1) {
1893                         int t,lookn,i,n;
1894
1895                         //first count the number of objects & copy into sort list
1896
1897                         lookn = nn;
1898                         i = n_sort_items = 0;
1899                         while ((t=render_obj_list[lookn][i++])!=-1)
1900                                 if (t<0)
1901                                         {lookn = -t; i=0;}
1902                                 else
1903                                         if (n_sort_items < SORT_LIST_SIZE-1) {          //add if room
1904                                                 sort_list[n_sort_items].objnum = t;
1905                                                 //NOTE: maybe use depth, not dist - quicker computation
1906                                                 sort_list[n_sort_items].dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
1907                                                 n_sort_items++;
1908                                         }
1909                                         else {                  //no room for object
1910                                                 int ii;
1911
1912                                                 #ifndef NDEBUG
1913                                                 FILE *tfile=fopen("sortlist.out","wt");
1914
1915                                                 //I find this strange, so I'm going to write out
1916                                                 //some information to look at later
1917                                                 if (tfile) {
1918                                                         for (ii=0;ii<SORT_LIST_SIZE;ii++) {
1919                                                                 int objnum = sort_list[ii].objnum;
1920
1921                                                                 fprintf(tfile,"Obj %3d  Type = %2d  Id = %2d  Dist = %08x  Segnum = %3d\n",
1922                                                                         objnum,Objects[objnum].type,Objects[objnum].id,sort_list[ii].dist,Objects[objnum].segnum);
1923                                                         }
1924                                                         fclose(tfile);
1925                                                 }
1926                                                 #endif
1927
1928                                                 Int3(); //Get Matt!!!
1929
1930                                                 //Now try to find a place for this object by getting rid
1931                                                 //of an object we don't care about
1932
1933                                                 for (ii=0;ii<SORT_LIST_SIZE;ii++) {
1934                                                         int objnum = sort_list[ii].objnum;
1935                                                         object *obj = &Objects[objnum];
1936                                                         int type = obj->type;
1937
1938                                                         //replace debris & fireballs
1939                                                         if (type == OBJ_DEBRIS || type == OBJ_FIREBALL) {
1940                                                                 fix dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
1941
1942                                                                 //don't replace same kind of object unless new 
1943                                                                 //one is closer
1944
1945                                                                 if (Objects[t].type != type || dist < sort_list[ii].dist) {
1946                                                                         sort_list[ii].objnum = t;
1947                                                                         sort_list[ii].dist = dist;
1948                                                                         break;
1949                                                                 }
1950                                                         }
1951                                                 }
1952
1953                                                 Int3(); //still couldn't find a slot
1954                                         }
1955
1956
1957                         //now call qsort
1958                 #if defined(__WATCOMC__) || defined(MACINTOSH)
1959                         qsort(sort_list,n_sort_items,sizeof(*sort_list),
1960                                    sort_func);
1961                 #else
1962                         qsort(sort_list,n_sort_items,sizeof(*sort_list),
1963                                         (int (*)(const void*,const void*))sort_func);
1964                 #endif  
1965
1966                         //now copy back into list
1967
1968                         lookn = nn;
1969                         i = 0;
1970                         n = n_sort_items;
1971                         while ((t=render_obj_list[lookn][i])!=-1 && n>0)
1972                                 if (t<0)
1973                                         {lookn = -t; i=0;}
1974                                 else
1975                                         render_obj_list[lookn][i++] = sort_list[--n].objnum;
1976                         render_obj_list[lookn][i] = -1; //mark (possibly new) end
1977                 }
1978         }
1979 }
1980
1981 int Use_player_head_angles = 0;
1982 vms_angvec Player_head_angles;
1983
1984 extern int Num_tmaps_drawn;
1985 extern int Total_pixels;
1986 //--unused-- int Total_num_tmaps_drawn=0;
1987
1988 int Rear_view=0;
1989 extern ubyte RenderingType;
1990
1991 void start_lighting_frame(object *viewer);
1992
1993 #ifdef JOHN_ZOOM
1994 fix Zoom_factor=F1_0;
1995 #endif
1996 //renders onto current canvas
1997 void render_frame(fix eye_offset, int window_num)
1998 {
1999         int start_seg_num;
2000
2001 #if defined(POLY_ACC)
2002 //$$ not needed for Verite, probably optional for ViRGE.    pa_flush();
2003 #endif
2004
2005 //Total_num_tmaps_drawn += Num_tmaps_drawn;
2006 //if ((FrameCount > 0) && (Total_num_tmaps_drawn))
2007 //      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));
2008 //Num_tmaps_drawn = 0;
2009
2010         if (Endlevel_sequence) {
2011                 render_endlevel_frame(eye_offset);
2012                 FrameCount++;
2013                 return;
2014         }
2015
2016 #ifdef NEWDEMO
2017         if ( Newdemo_state == ND_STATE_RECORDING && eye_offset >= 0 )   {
2018      
2019           //    mprintf ((0,"Objnum=%d objtype=%d objid=%d\n",Viewer-Objects,Viewer->type,Viewer->id));
2020                 
2021       if (RenderingType==0)
2022                 newdemo_record_start_frame(FrameCount, FrameTime );
2023       if (RenderingType!=255)
2024                 newdemo_record_viewer_object(Viewer);
2025         }
2026 #endif
2027   
2028    //Here:
2029
2030         start_lighting_frame(Viewer);           //this is for ugly light-smoothing hack
2031   
2032         g3_start_frame();
2033
2034         Viewer_eye = Viewer->pos;
2035
2036 //      if (Viewer->type == OBJ_PLAYER && (Cockpit_mode!=CM_REAR_VIEW))
2037 //              vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
2038
2039         if (eye_offset) {
2040                 vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
2041         }
2042
2043         #ifdef EDITOR
2044         if (Function_mode==FMODE_EDITOR)
2045                 Viewer_eye = Viewer->pos;
2046         #endif
2047
2048         start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
2049
2050         if (start_seg_num==-1)
2051                 start_seg_num = Viewer->segnum;
2052
2053         if (Viewer==ConsoleObject && Use_player_head_angles) {
2054                 vms_matrix headm,viewm;
2055                 vm_angles_2_matrix(&headm,&Player_head_angles);
2056                 vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
2057                 g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
2058         //@@} else if ((Cockpit_mode==CM_REAR_VIEW) && (Viewer==ConsoleObject)) {
2059         } else if (Rear_view && (Viewer==ConsoleObject)) {
2060                 vms_matrix headm,viewm;
2061                 Player_head_angles.p = Player_head_angles.b = 0;
2062                 Player_head_angles.h = 0x7fff;
2063                 vm_angles_2_matrix(&headm,&Player_head_angles);
2064                 vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
2065                 g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
2066         } else  {
2067 #ifdef JOHN_ZOOM
2068                 if (keyd_pressed[KEY_RSHIFT] )  {
2069                         Zoom_factor += FrameTime*4;
2070                         if (Zoom_factor > F1_0*5 ) Zoom_factor=F1_0*5;
2071                 } else {
2072                         Zoom_factor -= FrameTime*4;
2073                         if (Zoom_factor < F1_0 ) Zoom_factor = F1_0;
2074                 }
2075                 g3_set_view_matrix(&Viewer_eye,&Viewer->orient,fixdiv(Render_zoom,Zoom_factor));
2076 #else
2077                 g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
2078 #endif
2079         }
2080
2081         if (Clear_window == 1) {
2082                 if (Clear_window_color == -1)
2083                         Clear_window_color = BM_XRGB(0, 0, 0);  //BM_XRGB(31, 15, 7);
2084                 gr_clear_canvas(Clear_window_color);
2085         }
2086         #ifndef NDEBUG
2087         if (Show_only_curside)
2088                 gr_clear_canvas(Clear_window_color);
2089         #endif
2090
2091         render_mine(start_seg_num, eye_offset, window_num);
2092
2093         if (Use_player_head_angles ) 
2094                 draw_3d_reticle(eye_offset);
2095
2096         g3_end_frame();
2097
2098    //RenderingType=0;
2099
2100         // -- Moved from here by MK, 05/17/95, wrong if multiple renders/frame! FrameCount++;           //we have rendered a frame
2101 }
2102
2103 int first_terminal_seg;
2104
2105 void update_rendered_data(int window_num, object *viewer, int rear_view_flag, int user)
2106 {
2107         Assert(window_num < MAX_RENDERED_WINDOWS);
2108         Window_rendered_data[window_num].frame = FrameCount;
2109         Window_rendered_data[window_num].viewer = viewer;
2110         Window_rendered_data[window_num].rear_view = rear_view_flag;
2111         Window_rendered_data[window_num].user = user;
2112 }
2113
2114 //build a list of segments to be rendered
2115 //fills in Render_list & N_render_segs
2116 void build_segment_list(int start_seg_num, int window_num)
2117 {
2118         int     lcnt,scnt,ecnt;
2119         int     l,c;
2120         int     ch;
2121
2122         memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1));
2123         memset(render_pos, -1, sizeof(render_pos[0])*(Highest_segment_index+1));
2124         //memset(no_render_flag, 0, sizeof(no_render_flag[0])*(MAX_RENDER_SEGS));
2125         memset(processed, 0, sizeof(processed));
2126
2127         #ifndef NDEBUG
2128         memset(visited2, 0, sizeof(visited2[0])*(Highest_segment_index+1));
2129         #endif
2130
2131         lcnt = scnt = 0;
2132
2133         Render_list[lcnt] = start_seg_num; visited[start_seg_num]=1;
2134         Seg_depth[lcnt] = 0;
2135         lcnt++;
2136         ecnt = lcnt;
2137         render_pos[start_seg_num] = 0;
2138
2139         #ifndef NDEBUG
2140         if (pre_draw_segs)
2141                 render_segment(start_seg_num, window_num);
2142         #endif
2143
2144         render_windows[0].left=render_windows[0].top=0;
2145         render_windows[0].right=grd_curcanv->cv_bitmap.bm_w-1;
2146         render_windows[0].bot=grd_curcanv->cv_bitmap.bm_h-1;
2147
2148         //breadth-first renderer
2149
2150         //build list
2151
2152         for (l=0;l<Render_depth;l++) {
2153
2154                 //while (scnt < ecnt) {
2155                 for (scnt=0;scnt < ecnt;scnt++) {
2156                         int rotated,segnum;
2157                         window *check_w;
2158                         short child_list[MAX_SIDES_PER_SEGMENT];                //list of ordered sides to process
2159                         int n_children;                                                                         //how many sides in child_list
2160                         segment *seg;
2161
2162                         if (processed[scnt])
2163                                 continue;
2164
2165                         processed[scnt]=1;
2166
2167                         segnum = Render_list[scnt];
2168                         check_w = &render_windows[scnt];
2169
2170                         #ifndef NDEBUG
2171                         if (draw_boxes)
2172                                 draw_window_box(RED,check_w->left,check_w->top,check_w->right,check_w->bot);
2173                         #endif
2174
2175                         if (segnum == -1) continue;
2176
2177                         seg = &Segments[segnum];
2178                         rotated=0;
2179
2180                         //look at all sides of this segment.
2181                         //tricky code to look at sides in correct order follows
2182
2183                         for (c=n_children=0;c<MAX_SIDES_PER_SEGMENT;c++) {              //build list of sides
2184                                 int wid;
2185
2186                                 wid = WALL_IS_DOORWAY(seg, c);
2187
2188                                 ch=seg->children[c];
2189
2190                                 if ( (window_check || !visited[ch]) && (wid & WID_RENDPAST_FLAG) ) {
2191                                         if (behind_check) {
2192                                                 sbyte *sv = Side_to_verts[c];
2193                                                 ubyte codes_and=0xff;
2194                                                 int i;
2195
2196                                                 rotate_list(8,seg->verts);
2197                                                 rotated=1;
2198
2199                                                 for (i=0;i<4;i++)
2200                                                         codes_and &= Segment_points[seg->verts[sv[i]]].p3_codes;
2201
2202                                                 if (codes_and & CC_BEHIND) continue;
2203
2204                                         }
2205                                         child_list[n_children++] = c;
2206                                 }
2207                         }
2208
2209                         //now order the sides in some magical way
2210
2211                         if (new_seg_sorting)
2212                                 sort_seg_children(seg,n_children,child_list);
2213
2214                         //for (c=0;c<MAX_SIDES_PER_SEGMENT;c++) {
2215                         //      ch=seg->children[c];
2216
2217                         for (c=0;c<n_children;c++) {
2218                                 int siden;
2219
2220                                 siden = child_list[c];
2221                                 ch=seg->children[siden];
2222                                 //if ( (window_check || !visited[ch])&& (WALL_IS_DOORWAY(seg, c))) {
2223                                 {
2224                                         if (window_check) {
2225                                                 int i;
2226                                                 ubyte codes_and_3d,codes_and_2d;
2227                                                 short _x,_y,min_x=32767,max_x=-32767,min_y=32767,max_y=-32767;
2228                                                 int no_proj_flag=0;     //a point wasn't projected
2229
2230                                                 if (rotated<2) {
2231                                                         if (!rotated)
2232                                                                 rotate_list(8,seg->verts);
2233                                                         project_list(8,seg->verts);
2234                                                         rotated=2;
2235                                                 }
2236
2237                                                 for (i=0,codes_and_3d=codes_and_2d=0xff;i<4;i++) {
2238                                                         int p = seg->verts[Side_to_verts[siden][i]];
2239                                                         g3s_point *pnt = &Segment_points[p];
2240
2241                                                         if (! (pnt->p3_flags&PF_PROJECTED)) {no_proj_flag=1; break;}
2242
2243                                                         _x = f2i(pnt->p3_sx);
2244                                                         _y = f2i(pnt->p3_sy);
2245
2246                                                         codes_and_3d &= pnt->p3_codes;
2247                                                         codes_and_2d &= code_window_point(_x,_y,check_w);
2248
2249                                                         #ifndef NDEBUG
2250                                                         if (draw_edges) {
2251                                                                 gr_setcolor(BM_XRGB(31,0,31));
2252                                                                 gr_line(pnt->p3_sx,pnt->p3_sy,
2253                                                                         Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sx,
2254                                                                         Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sy);
2255                                                         }
2256                                                         #endif
2257
2258                                                         if (_x < min_x) min_x = _x;
2259                                                         if (_x > max_x) max_x = _x;
2260
2261                                                         if (_y < min_y) min_y = _y;
2262                                                         if (_y > max_y) max_y = _y;
2263
2264                                                 }
2265
2266                                                 #ifndef NDEBUG
2267                                                 if (draw_boxes)
2268                                                         draw_window_box(WHITE,min_x,min_y,max_x,max_y);
2269                                                 #endif
2270
2271                                                 if (no_proj_flag || (!codes_and_3d && !codes_and_2d)) { //maybe add this segment
2272                                                         int rp = render_pos[ch];
2273                                                         window *new_w = &render_windows[lcnt];
2274
2275                                                         if (no_proj_flag) *new_w = *check_w;
2276                                                         else {
2277                                                                 new_w->left  = max(check_w->left,min_x);
2278                                                                 new_w->right = min(check_w->right,max_x);
2279                                                                 new_w->top   = max(check_w->top,min_y);
2280                                                                 new_w->bot   = min(check_w->bot,max_y);
2281                                                         }
2282
2283                                                         //see if this seg already visited, and if so, does current window
2284                                                         //expand the old window?
2285                                                         if (rp != -1) {
2286                                                                 if (new_w->left < render_windows[rp].left ||
2287                                                                                  new_w->top < render_windows[rp].top ||
2288                                                                                  new_w->right > render_windows[rp].right ||
2289                                                                                  new_w->bot > render_windows[rp].bot) {
2290
2291                                                                         new_w->left  = min(new_w->left,render_windows[rp].left);
2292                                                                         new_w->right = max(new_w->right,render_windows[rp].right);
2293                                                                         new_w->top   = min(new_w->top,render_windows[rp].top);
2294                                                                         new_w->bot   = max(new_w->bot,render_windows[rp].bot);
2295
2296                                                                         if (no_migrate_segs) {
2297                                                                                 //no_render_flag[lcnt] = 1;
2298                                                                                 Render_list[lcnt] = -1;
2299                                                                                 render_windows[rp] = *new_w;            //get updated window
2300                                                                                 processed[rp] = 0;              //force reprocess
2301                                                                                 goto no_add;
2302                                                                         }
2303                                                                         else
2304                                                                                 Render_list[rp]=-1;
2305                                                                 }
2306                                                                 else goto no_add;
2307                                                         }
2308
2309                                                         #ifndef NDEBUG
2310                                                         if (draw_boxes)
2311                                                                 draw_window_box(5,new_w->left,new_w->top,new_w->right,new_w->bot);
2312                                                         #endif
2313
2314                                                         render_pos[ch] = lcnt;
2315                                                         Render_list[lcnt] = ch;
2316                                                         Seg_depth[lcnt] = l;
2317                                                         lcnt++;
2318                                                         if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
2319                                                         visited[ch] = 1;
2320
2321                                                         #ifndef NDEBUG
2322                                                         if (pre_draw_segs)
2323                                                                 render_segment(ch, window_num);
2324                                                         #endif
2325 no_add:
2326         ;
2327
2328                                                 }
2329                                         }
2330                                         else {
2331                                                 Render_list[lcnt] = ch;
2332                                                 Seg_depth[lcnt] = l;
2333                                                 lcnt++;
2334                                                 if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
2335                                                 visited[ch] = 1;
2336                                         }
2337                                 }
2338                         }
2339                 }
2340
2341                 scnt = ecnt;
2342                 ecnt = lcnt;
2343
2344         }
2345 done_list:
2346
2347         lcnt_save = lcnt;
2348         scnt_save = scnt;
2349
2350         first_terminal_seg = scnt;
2351         N_render_segs = lcnt;
2352
2353 }
2354
2355 //renders onto current canvas
2356 void render_mine(int start_seg_num,fix eye_offset, int window_num)
2357 {
2358 #ifndef NDEBUG
2359         int             i;
2360 #endif
2361         int             nn;
2362
2363         //      Initialize number of objects (actually, robots!) rendered this frame.
2364         Window_rendered_data[window_num].num_objects = 0;
2365
2366 #ifdef LASER_HACK
2367         Hack_nlasers = 0;
2368 #endif
2369
2370         #ifndef NDEBUG
2371         for (i=0;i<=Highest_object_index;i++)
2372                 object_rendered[i] = 0;
2373         #endif
2374
2375         //set up for rendering
2376
2377         render_start_frame();
2378
2379
2380         #if defined(EDITOR) && !defined(NDEBUG)
2381         if (Show_only_curside) {
2382                 rotate_list(8,Cursegp->verts);
2383                 render_side(Cursegp,Curside);
2384                 goto done_rendering;
2385         }
2386         #endif
2387
2388
2389         #ifdef EDITOR
2390         if (_search_mode)       {
2391                 //lcnt = lcnt_save;
2392                 //scnt = scnt_save;
2393         }
2394         else
2395         #endif
2396                 //NOTE LINK TO ABOVE!!
2397                 build_segment_list(start_seg_num, window_num);          //fills in Render_list & N_render_segs
2398
2399         //render away
2400
2401         #ifndef NDEBUG
2402         if (!window_check) {
2403                 Window_clip_left  = Window_clip_top = 0;
2404                 Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
2405                 Window_clip_bot   = grd_curcanv->cv_bitmap.bm_h-1;
2406         }
2407         #endif
2408
2409         #ifndef NDEBUG
2410         if (!(_search_mode)) {
2411                 int i;
2412
2413                 for (i=0;i<N_render_segs;i++) {
2414                         int segnum;
2415
2416                         segnum = Render_list[i];
2417
2418                         if (segnum != -1)
2419                         {
2420                                 if (visited2[segnum])
2421                                         Int3();         //get Matt
2422                                 else
2423                                         visited2[segnum] = 1;
2424                         }
2425                 }
2426         }
2427         #endif
2428
2429         if (!(_search_mode))
2430                 build_object_lists(N_render_segs);
2431
2432         if (eye_offset<=0)              // Do for left eye or zero.
2433                 set_dynamic_light();
2434
2435         if (!_search_mode && Clear_window == 2) {
2436                 if (first_terminal_seg < N_render_segs) {
2437                         int i;
2438
2439                         if (Clear_window_color == -1)
2440                                 Clear_window_color = BM_XRGB(0, 0, 0);  //BM_XRGB(31, 15, 7);
2441         
2442                         gr_setcolor(Clear_window_color);
2443         
2444                         for (i=first_terminal_seg; i<N_render_segs; i++) {
2445                                 if (Render_list[i] != -1) {
2446                                         #ifndef NDEBUG
2447                                         if ((render_windows[i].left == -1) || (render_windows[i].top == -1) || (render_windows[i].right == -1) || (render_windows[i].bot == -1))
2448                                                 Int3();
2449                                         else
2450                                         #endif
2451                                                 //NOTE LINK TO ABOVE!
2452                                                 gr_rect(render_windows[i].left, render_windows[i].top, render_windows[i].right, render_windows[i].bot);
2453                                 }
2454                         }
2455                 }
2456         }
2457
2458         for (nn=N_render_segs;nn--;) {
2459                 int segnum;
2460                 int objnp;
2461
2462                 // Interpolation_method = 0;
2463                 segnum = Render_list[nn];
2464                 Current_seg_depth = Seg_depth[nn];
2465
2466                 //if (!no_render_flag[nn])
2467                 if (segnum!=-1 && (_search_mode || visited[segnum]!=255)) {
2468                         //set global render window vars
2469
2470                         if (window_check) {
2471                                 Window_clip_left  = render_windows[nn].left;
2472                                 Window_clip_top   = render_windows[nn].top;
2473                                 Window_clip_right = render_windows[nn].right;
2474                                 Window_clip_bot   = render_windows[nn].bot;
2475                         }
2476
2477                         //mprintf((0," %d",segnum));
2478
2479                         render_segment(segnum, window_num);
2480                         visited[segnum]=255;
2481
2482                         if (window_check) {             //reset for objects
2483                                 Window_clip_left  = Window_clip_top = 0;
2484                                 Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
2485                                 Window_clip_bot   = grd_curcanv->cv_bitmap.bm_h-1;
2486                         }
2487
2488                         if (migrate_objects) {
2489                                 //int n_expl_objs=0,expl_objs[5],i;
2490                                 int listnum;
2491                                 int save_linear_depth = Max_linear_depth;
2492
2493                                 Max_linear_depth = Max_linear_depth_objects;
2494
2495                                 listnum = nn;
2496
2497                                 //mprintf((0,"render objs seg %d",segnum));
2498
2499                                 for (objnp=0;render_obj_list[listnum][objnp]!=-1;)      {
2500                                         int ObjNumber = render_obj_list[listnum][objnp];
2501
2502                                         if (ObjNumber >= 0) {
2503
2504                                                 //mprintf( (0, "Type: %d\n", Objects[ObjNumber].type ));
2505         
2506                                                 //if (Objects[ObjNumber].type == OBJ_FIREBALL && n_expl_objs<5) {
2507                                                 //      expl_objs[n_expl_objs++] = ObjNumber;
2508                                                 //} else
2509                                                 #ifdef LASER_HACK
2510                                                 if (    (Objects[ObjNumber].type==OBJ_WEAPON) &&                                                                //if its a weapon
2511                                                                 (Objects[ObjNumber].lifeleft==Laser_max_time ) &&       //  and its in it's first frame
2512                                                                 (Hack_nlasers< MAX_HACKED_LASERS) &&                                                                    //  and we have space for it
2513                                                                 (Objects[ObjNumber].laser_info.parent_num>-1) &&                                        //  and it has a parent
2514                                                                 ((Viewer-Objects)==Objects[ObjNumber].laser_info.parent_num)    //  and it's parent is the viewer
2515                                                    )            {
2516                                                         Hack_laser_list[Hack_nlasers++] = ObjNumber;                                                            //then make it draw after everything else.
2517                                                         //mprintf( (0, "O%d ", ObjNumber ));
2518                                                 } else  
2519                                                 #endif
2520                                                         do_render_object(ObjNumber, window_num);        // note link to above else
2521
2522                                                 objnp++;
2523                                         }
2524                                         else {
2525
2526                                                 listnum = -ObjNumber;
2527                                                 objnp = 0;
2528
2529                                         }
2530
2531                                 }
2532
2533                                 //for (i=0;i<n_expl_objs;i++)
2534                                 //      do_render_object(expl_objs[i], window_num);
2535
2536                                 //mprintf((0,"done seg %d\n",segnum));
2537
2538                                 Max_linear_depth = save_linear_depth;
2539
2540                         }
2541
2542                 }
2543         }
2544
2545         //mprintf((0,"\n"));
2546
2547                                                                 
2548 #ifdef LASER_HACK                                                               
2549         // Draw the hacked lasers last
2550         for (i=0; i < Hack_nlasers; i++ )       {
2551                 //mprintf( (0, "D%d ", Hack_laser_list[i] ));
2552                 do_render_object(Hack_laser_list[i], window_num);
2553         }
2554 #endif
2555
2556         // -- commented out by mk on 09/14/94...did i do a good thing??  object_render_targets();
2557
2558 #ifdef EDITOR
2559         #ifndef NDEBUG
2560         //draw curedge stuff
2561         if (Outline_mode) outline_seg_side(Cursegp,Curside,Curedge,Curvert);
2562         #endif
2563
2564 done_rendering:
2565         ;
2566
2567 #endif
2568
2569 }
2570 #ifdef EDITOR
2571
2572 extern int render_3d_in_big_window;
2573
2574 //finds what segment is at a given x&y -  seg,side,face are filled in
2575 //works on last frame rendered. returns true if found
2576 //if seg<0, then an object was found, and the object number is -seg-1
2577 int find_seg_side_face(short x,short y,int *seg,int *side,int *face,int *poly)
2578 {
2579         _search_mode = -1;
2580
2581         _search_x = x; _search_y = y;
2582
2583         found_seg = -1;
2584
2585         if (render_3d_in_big_window) {
2586                 grs_canvas temp_canvas;
2587
2588                 gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
2589                         LargeView.ev_canv->cv_bitmap.bm_w,LargeView.ev_canv->cv_bitmap.bm_h);
2590
2591                 gr_set_current_canvas(&temp_canvas);
2592
2593                 render_frame(0, 0);
2594         }
2595         else {
2596                 gr_set_current_canvas(&VR_render_sub_buffer[0]);        //render off-screen
2597                 render_frame(0, 0);
2598         }
2599
2600         _search_mode = 0;
2601
2602         *seg = found_seg;
2603         *side = found_side;
2604         *face = found_face;
2605         *poly = found_poly;
2606
2607 //      mprintf((0,"found seg=%d, side=%d, face=%d, poly=%d\n",found_seg,found_side,found_face,found_poly));
2608
2609         return (found_seg!=-1);
2610
2611 }
2612
2613 #endif