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