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