2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Rendering Stuff
*
*/
2012-11-11 22:12:51 +00:00
# include <algorithm>
2014-10-02 03:02:34 +00:00
# include <bitset>
2014-08-20 01:28:22 +00:00
# include <limits>
2006-03-20 17:12:09 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
2011-02-14 21:27:07 +00:00
# include <math.h>
2006-03-20 17:12:09 +00:00
# include "inferno.h"
# include "segment.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "bm.h"
# include "texmap.h"
# include "render.h"
2014-08-12 02:28:03 +00:00
# include "render_state.h"
2006-03-20 17:12:09 +00:00
# include "game.h"
# include "object.h"
# include "laser.h"
# include "textures.h"
# include "screens.h"
# include "segpoint.h"
# include "wall.h"
# include "texmerge.h"
# include "physics.h"
# include "3d.h"
# include "gameseg.h"
# include "vclip.h"
# include "lighting.h"
# include "cntrlcen.h"
# include "newdemo.h"
# include "automap.h"
# include "endlevel.h"
# include "key.h"
# include "newmenu.h"
# include "u_mem.h"
# include "piggy.h"
2011-02-14 21:27:07 +00:00
# include "timer.h"
2011-02-23 16:46:39 +00:00
# include "effects.h"
# include "playsave.h"
2006-03-20 17:12:09 +00:00
# ifdef OGL
# include "ogl_init.h"
# endif
2013-03-03 19:41:09 +00:00
# include "args.h"
2006-03-20 17:12:09 +00:00
2014-09-13 22:05:52 +00:00
# include "compiler-integer_sequence.h"
2014-07-30 02:52:36 +00:00
# include "compiler-range_for.h"
2014-09-08 03:31:05 +00:00
# include "partial_range.h"
2014-07-30 02:52:36 +00:00
# include "segiter.h"
2006-03-20 17:12:09 +00:00
# ifdef EDITOR
# include "editor/editor.h"
2013-03-16 03:10:55 +00:00
# include "editor/esegment.h"
2006-03-20 17:12:09 +00:00
# endif
2012-11-11 22:12:51 +00:00
using std : : min ;
using std : : max ;
2008-04-06 20:23:28 +00:00
// (former) "detail level" values
2008-11-21 16:09:41 +00:00
# ifdef OGL
int Render_depth = MAX_RENDER_SEGS ; //how many segments deep to render
# else
2008-04-06 20:23:28 +00:00
int Render_depth = 20 ; //how many segments deep to render
2008-11-21 16:09:41 +00:00
# endif
2014-09-20 23:47:27 +00:00
unsigned Max_linear_depth = 50 ; // Deepest segment at which linear interpolation will be used.
2008-04-06 20:23:28 +00:00
int Max_linear_depth_objects = 20 ;
2006-03-20 17:12:09 +00:00
//used for checking if points have been rotated
int Clear_window_color = - 1 ;
int Clear_window = 2 ; // 1 = Clear whole background window, 2 = clear view portals into rest of world, 0 = no clear
2014-08-20 01:28:22 +00:00
static uint16_t s_current_generation ;
2006-03-20 17:12:09 +00:00
// When any render function needs to know what's looking at it, it should
// access Viewer members.
object * Viewer = NULL ;
vms_vector Viewer_eye ; //valid during render
fix Render_zoom = 0x9000 ; //the player's zoom factor
# ifndef NDEBUG
2014-10-02 03:02:34 +00:00
static std : : bitset < MAX_OBJECTS > object_rendered ;
2006-03-20 17:12:09 +00:00
# endif
# ifdef EDITOR
int Render_only_bottom = 0 ;
int Bottom_bitmap_num = 9 ;
# endif
2007-12-29 14:18:49 +00:00
//Global vars for window clip test
int Window_clip_left , Window_clip_top , Window_clip_right , Window_clip_bot ;
2006-03-20 17:12:09 +00:00
# ifdef EDITOR
int _search_mode = 0 ; //true if looking for curseg,side,face
short _search_x , _search_y ; //pixel we're looking at
int found_seg , found_side , found_face , found_poly ;
# else
2014-07-30 03:03:33 +00:00
static const int _search_mode = 0 ;
2006-03-20 17:12:09 +00:00
# endif
# ifdef NDEBUG //if no debug code, set these vars to constants
2014-07-30 03:03:33 +00:00
static const int Outline_mode = 0 , Show_only_curside = 0 ;
2006-03-20 17:12:09 +00:00
# else
int Outline_mode = 0 , Show_only_curside = 0 ;
int toggle_outline_mode ( void )
{
return Outline_mode = ! Outline_mode ;
}
int toggle_show_only_curside ( void )
{
return Show_only_curside = ! Show_only_curside ;
}
2013-07-14 22:41:04 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-07-14 22:41:04 +00:00
# ifndef NDEBUG
2014-11-16 19:14:51 +00:00
static void draw_outline ( int nverts , cg3s_point * const * const pointlist )
2006-03-20 17:12:09 +00:00
{
int i ;
gr_setcolor ( BM_XRGB ( 63 , 63 , 63 ) ) ;
for ( i = 0 ; i < nverts - 1 ; i + + )
2014-11-13 03:19:52 +00:00
g3_draw_line ( * pointlist [ i ] , * pointlist [ i + 1 ] ) ;
2006-03-20 17:12:09 +00:00
2014-11-13 03:19:52 +00:00
g3_draw_line ( * pointlist [ i ] , * pointlist [ 0 ] ) ;
2006-03-20 17:12:09 +00:00
}
# endif
fix flash_scale ;
# define FLASH_CYCLE_RATE f1_0
2013-08-17 16:09:44 +00:00
static const fix Flash_rate = FLASH_CYCLE_RATE ;
2006-03-20 17:12:09 +00:00
//cycle the flashing light for when mine destroyed
void flash_frame ( )
{
static fixang flash_ang = 0 ;
if ( ! Control_center_destroyed & & ! Seismic_tremor_magnitude )
return ;
if ( Endlevel_sequence )
return ;
if ( PaletteBlueAdd > 10 ) //whiting out
return ;
// flash_ang += fixmul(FLASH_CYCLE_RATE,FrameTime);
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Seismic_tremor_magnitude ) {
fix added_flash ;
added_flash = abs ( Seismic_tremor_magnitude ) ;
if ( added_flash < F1_0 )
added_flash * = 16 ;
flash_ang + = fixmul ( Flash_rate , fixmul ( FrameTime , added_flash + F1_0 ) ) ;
fix_fastsincos ( flash_ang , & flash_scale , NULL ) ;
flash_scale = ( flash_scale + F1_0 * 3 ) / 4 ; // gets in range 0.5 to 1.0
2013-03-03 01:03:33 +00:00
} else
# endif
{
2006-03-20 17:12:09 +00:00
flash_ang + = fixmul ( Flash_rate , FrameTime ) ;
fix_fastsincos ( flash_ang , & flash_scale , NULL ) ;
flash_scale = ( flash_scale + f1_0 ) / 2 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Difficulty_level = = 0 )
flash_scale = ( flash_scale + F1_0 * 3 ) / 4 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
}
2013-08-18 17:53:50 +00:00
static inline int is_alphablend_eclip ( int eclip_num )
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-18 17:53:50 +00:00
if ( eclip_num = = ECLIP_NUM_FORCE_FIELD )
return 1 ;
2013-03-03 01:03:33 +00:00
# endif
2013-08-18 17:53:50 +00:00
return eclip_num = = ECLIP_NUM_FUELCEN ;
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
// Render a face.
// It would be nice to not have to pass in segnum and sidenum, but
// they are used for our hideously hacked in headlight system.
// vp is a pointer to vertex ids.
// tmap1, tmap2 are texture map ids. tmap2 is the pasty one.
2014-09-13 22:05:52 +00:00
static void render_face ( segnum_t segnum , int sidenum , unsigned nv , const array < int , 4 > & vp , int tmap1 , int tmap2 , array < g3s_uvl , 4 > uvl_copy , WALL_IS_DOORWAY_result_t wid_flags )
2006-03-20 17:12:09 +00:00
{
grs_bitmap * bm ;
# ifdef OGL
grs_bitmap * bm2 = NULL ;
# endif
2014-09-13 00:34:18 +00:00
array < g3s_lrgb , 4 > dyn_light ;
2014-11-16 19:14:51 +00:00
array < cg3s_point * , 4 > pointlist ;
2006-03-20 17:12:09 +00:00
2014-11-15 03:10:06 +00:00
Assert ( nv < = pointlist . size ( ) ) ;
2006-03-20 17:12:09 +00:00
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < nv ; i + + ) {
2014-09-13 00:34:18 +00:00
dyn_light [ i ] . r = dyn_light [ i ] . g = dyn_light [ i ] . b = uvl_copy [ i ] . l ;
2006-03-20 17:12:09 +00:00
pointlist [ i ] = & Segment_points [ vp [ i ] ] ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
//handle cloaked walls
if ( wid_flags & WID_CLOAKED_FLAG ) {
2014-09-21 22:11:51 +00:00
auto wall_num = Segments [ segnum ] . sides [ sidenum ] . wall_num ;
Assert ( wall_num ! = wall_none ) ;
2011-02-23 16:46:39 +00:00
gr_settransblend ( Walls [ wall_num ] . cloak_value , GR_BLEND_NORMAL ) ;
2006-03-20 17:12:09 +00:00
gr_setcolor ( BM_XRGB ( 0 , 0 , 0 ) ) ; // set to black (matters for s3)
g3_draw_poly ( nv , pointlist ) ; // draw as flat poly
2011-02-23 16:46:39 +00:00
gr_settransblend ( GR_FADE_OFF , GR_BLEND_NORMAL ) ;
2006-03-20 17:12:09 +00:00
return ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( tmap1 > = NumTextures ) {
2008-04-06 20:23:28 +00:00
# ifndef RELEASE
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
2008-04-06 20:23:28 +00:00
# endif
2006-03-20 17:12:09 +00:00
Segments [ segnum ] . sides [ sidenum ] . tmap_num = 0 ;
}
# ifdef OGL
2013-11-10 17:16:55 +00:00
if ( ! GameArg . DbgUseOldTextureMerge ) {
2006-03-20 17:12:09 +00:00
PIGGY_PAGE_IN ( Textures [ tmap1 ] ) ;
bm = & GameBitmaps [ Textures [ tmap1 ] . index ] ;
if ( tmap2 ) {
PIGGY_PAGE_IN ( Textures [ tmap2 & 0x3FFF ] ) ;
bm2 = & GameBitmaps [ Textures [ tmap2 & 0x3FFF ] . index ] ;
}
2007-06-10 16:21:53 +00:00
if ( bm2 & & ( bm2 - > bm_flags & BM_FLAG_SUPER_TRANSPARENT ) ) {
2006-03-20 17:12:09 +00:00
bm = texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
bm2 = NULL ;
}
2007-06-10 16:21:53 +00:00
} else
2006-03-20 17:12:09 +00:00
# endif
// New code for overlapping textures...
if ( tmap2 ! = 0 ) {
bm = texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
} else {
bm = & GameBitmaps [ Textures [ tmap1 ] . index ] ;
PIGGY_PAGE_IN ( Textures [ tmap1 ] ) ;
}
Assert ( ! ( bm - > bm_flags & BM_FLAG_PAGED_OUT ) ) ;
//set light values for each vertex & build pointlist
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < nv ; i + + )
2006-03-20 17:12:09 +00:00
{
2011-09-26 23:31:19 +00:00
//the uvl struct has static light already in it
//scale static light for destruction effect
if ( Control_center_destroyed | | Seismic_tremor_magnitude ) //make lights flash
uvl_copy [ i ] . l = fixmul ( flash_scale , uvl_copy [ i ] . l ) ;
//add in dynamic light (from explosions, etc.)
uvl_copy [ i ] . l + = ( Dynamic_light [ vp [ i ] ] . r + Dynamic_light [ vp [ i ] ] . g + Dynamic_light [ vp [ i ] ] . b ) / 3 ;
//saturate at max value
if ( uvl_copy [ i ] . l > MAX_LIGHT )
uvl_copy [ i ] . l = MAX_LIGHT ;
// And now the same for the ACTUAL (rgb) light we want to use
//scale static light for destruction effect
if ( Seismic_tremor_magnitude ) //make lights flash
dyn_light [ i ] . r = dyn_light [ i ] . g = dyn_light [ i ] . b = fixmul ( flash_scale , uvl_copy [ i ] . l ) ;
else if ( Control_center_destroyed ) //make lights flash
2011-04-07 20:32:51 +00:00
{
2011-09-26 23:31:19 +00:00
if ( PlayerCfg . DynLightColor ) // let the mine glow red a little
2011-04-07 20:32:51 +00:00
{
2011-09-26 23:31:19 +00:00
dyn_light [ i ] . r = fixmul ( flash_scale > = f0_5 * 1.5 ? flash_scale : f0_5 * 1.5 , uvl_copy [ i ] . l ) ;
dyn_light [ i ] . g = dyn_light [ i ] . b = fixmul ( flash_scale , uvl_copy [ i ] . l ) ;
2011-04-07 20:32:51 +00:00
}
2011-09-26 23:31:19 +00:00
else
dyn_light [ i ] . r = dyn_light [ i ] . g = dyn_light [ i ] . b = fixmul ( flash_scale , uvl_copy [ i ] . l ) ;
2006-03-20 17:12:09 +00:00
}
2011-09-26 23:31:19 +00:00
// add light color
dyn_light [ i ] . r + = Dynamic_light [ vp [ i ] ] . r ;
dyn_light [ i ] . g + = Dynamic_light [ vp [ i ] ] . g ;
dyn_light [ i ] . b + = Dynamic_light [ vp [ i ] ] . b ;
// saturate at max value
if ( dyn_light [ i ] . r > MAX_LIGHT )
dyn_light [ i ] . r = MAX_LIGHT ;
if ( dyn_light [ i ] . g > MAX_LIGHT )
dyn_light [ i ] . g = MAX_LIGHT ;
if ( dyn_light [ i ] . b > MAX_LIGHT )
dyn_light [ i ] . b = MAX_LIGHT ;
2013-04-18 10:08:51 +00:00
if ( PlayerCfg . AlphaEffects ) // due to additive blending, transparent sprites will become invivible in font of white surfaces (lamps). Fix that with a little desaturation
{
dyn_light [ i ] . r * = .93 ;
dyn_light [ i ] . g * = .93 ;
dyn_light [ i ] . b * = .93 ;
}
2006-03-20 17:12:09 +00:00
}
2013-08-18 17:53:50 +00:00
if ( PlayerCfg . AlphaEffects & & is_alphablend_eclip ( TmapInfo [ tmap1 ] . eclip_num ) ) // set nice transparency/blending for some special effects (if we do more, we should maybe use switch here)
2011-02-23 16:46:39 +00:00
gr_settransblend ( GR_FADE_OFF , GR_BLEND_ADDITIVE_C ) ;
2006-03-20 17:12:09 +00:00
# ifdef EDITOR
if ( ( Render_only_bottom ) & & ( sidenum = = WBOTTOM ) )
2014-11-13 03:44:04 +00:00
g3_draw_tmap ( nv , pointlist , uvl_copy , dyn_light , GameBitmaps [ Textures [ Bottom_bitmap_num ] . index ] ) ;
2006-03-20 17:12:09 +00:00
else
# endif
# ifdef OGL
if ( bm2 ) {
2011-04-07 20:32:51 +00:00
g3_draw_tmap_2 ( nv , pointlist , uvl_copy , dyn_light , bm , bm2 , ( ( tmap2 & 0xC000 ) > > 14 ) & 3 ) ;
2006-03-20 17:12:09 +00:00
} else
# endif
2014-11-13 03:44:04 +00:00
g3_draw_tmap ( nv , pointlist , uvl_copy , dyn_light , * bm ) ;
2006-03-20 17:12:09 +00:00
2011-02-23 16:46:39 +00:00
gr_settransblend ( GR_FADE_OFF , GR_BLEND_NORMAL ) ; // revert any transparency/blending setting back to normal
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2014-11-15 03:10:06 +00:00
if ( Outline_mode ) draw_outline ( nv , & pointlist [ 0 ] ) ;
2006-03-20 17:12:09 +00:00
# endif
}
// ----------------------------------------------------------------------------
// Only called if editor active.
// Used to determine which face was clicked on.
2014-09-13 22:05:52 +00:00
static void check_face ( segnum_t segnum , int sidenum , int facenum , unsigned nv , const array < int , 4 > & vp , int tmap1 , int tmap2 , const array < g3s_uvl , 4 > & uvl_copy )
2006-03-20 17:12:09 +00:00
{
2014-09-12 23:13:32 +00:00
# ifdef EDITOR
2006-03-20 17:12:09 +00:00
if ( _search_mode ) {
int save_lighting ;
2014-09-13 00:34:18 +00:00
array < g3s_lrgb , 4 > dyn_light { } ;
2014-11-16 19:14:51 +00:00
array < cg3s_point * , 4 > pointlist ;
2012-04-15 14:15:21 +00:00
# ifndef OGL
2006-03-20 17:12:09 +00:00
grs_bitmap * bm ;
if ( tmap2 > 0 )
bm = texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
else
bm = & GameBitmaps [ Textures [ tmap1 ] . index ] ;
2012-04-15 14:15:21 +00:00
# endif
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < nv ; i + + ) {
2014-09-13 00:34:18 +00:00
dyn_light [ i ] . r = dyn_light [ i ] . g = dyn_light [ i ] . b = uvl_copy [ i ] . l ;
2006-03-20 17:12:09 +00:00
pointlist [ i ] = & Segment_points [ vp [ i ] ] ;
}
gr_setcolor ( 0 ) ;
2012-04-15 05:45:45 +00:00
# ifdef OGL
ogl_end_frame ( ) ;
# endif
2006-03-20 17:12:09 +00:00
gr_pixel ( _search_x , _search_y ) ; //set our search pixel to color zero
2012-04-15 05:45:45 +00:00
# ifdef OGL
ogl_start_frame ( ) ;
# endif
2006-03-20 17:12:09 +00:00
gr_setcolor ( 1 ) ; //and render in color one
2012-04-15 05:45:45 +00:00
save_lighting = Lighting_on ;
Lighting_on = 2 ;
# ifdef OGL
2014-11-15 03:10:06 +00:00
g3_draw_poly ( nv , pointlist ) ;
2012-04-15 05:45:45 +00:00
# else
2014-11-15 03:10:06 +00:00
g3_draw_tmap ( nv , pointlist , uvl_copy , dyn_light , * bm ) ;
2012-04-15 05:45:45 +00:00
# endif
Lighting_on = save_lighting ;
2006-03-20 17:12:09 +00:00
if ( gr_ugpixel ( & grd_curcanv - > cv_bitmap , _search_x , _search_y ) = = 1 ) {
found_seg = segnum ;
found_side = sidenum ;
found_face = facenum ;
}
}
2014-09-12 23:13:32 +00:00
# else
( void ) segnum ;
( void ) sidenum ;
( void ) facenum ;
( void ) nv ;
( void ) vp ;
( void ) tmap1 ;
( void ) tmap2 ;
2014-09-13 00:34:18 +00:00
( void ) uvl_copy ;
2006-03-20 17:12:09 +00:00
# endif
2014-09-12 23:13:32 +00:00
}
2014-09-13 22:05:52 +00:00
template < std : : size_t . . . N >
static inline void check_render_face ( index_sequence < N . . . > , segnum_t segnum , int sidenum , unsigned facenum , const array < int , 4 > & ovp , int tmap1 , int tmap2 , const array < uvl , 4 > & uvlp , WALL_IS_DOORWAY_result_t wid_flags , const std : : size_t nv )
2014-09-12 23:13:32 +00:00
{
2014-09-13 22:05:52 +00:00
const array < int , 4 > vp { { ovp [ N ] . . . } } ;
const array < g3s_uvl , 4 > uvl_copy { {
{ uvlp [ N ] . u , uvlp [ N ] . v , uvlp [ N ] . l } . . .
} } ;
2014-09-13 00:34:18 +00:00
render_face ( segnum , sidenum , nv , vp , tmap1 , tmap2 , uvl_copy , wid_flags ) ;
check_face ( segnum , sidenum , facenum , nv , vp , tmap1 , tmap2 , uvl_copy ) ;
2014-09-12 23:13:32 +00:00
}
2006-03-20 17:12:09 +00:00
2014-09-13 22:05:52 +00:00
template < std : : size_t N0 , std : : size_t N1 , std : : size_t N2 , std : : size_t N3 >
static inline void check_render_face ( index_sequence < N0 , N1 , N2 , N3 > is , segnum_t segnum , int sidenum , unsigned facenum , array < int , 4 > & vp , int tmap1 , int tmap2 , const array < uvl , 4 > & uvlp , WALL_IS_DOORWAY_result_t wid_flags )
{
check_render_face ( is , segnum , sidenum , facenum , vp , tmap1 , tmap2 , uvlp , wid_flags , 4 ) ;
}
/* Avoid default constructing final element of uvl_copy; if any members
* are default constructed , gcc zero initializes all members .
*/
template < std : : size_t N0 , std : : size_t N1 , std : : size_t N2 >
static inline void check_render_face ( index_sequence < N0 , N1 , N2 > is , segnum_t segnum , int sidenum , unsigned facenum , array < int , 4 > & vp , int tmap1 , int tmap2 , const array < uvl , 4 > & uvlp , WALL_IS_DOORWAY_result_t wid_flags )
{
check_render_face ( index_sequence < N0 , N1 , N2 , 3 > ( ) , segnum , sidenum , facenum , vp , tmap1 , tmap2 , uvlp , wid_flags , 3 ) ;
}
2014-07-30 03:03:33 +00:00
static const fix Tulate_min_dot = ( F1_0 / 4 ) ;
2006-03-20 17:12:09 +00:00
//--unused-- fix Tulate_min_ratio = (2*F1_0);
2014-07-30 03:03:33 +00:00
static const fix Min_n0_n1_dot = ( F1_0 * 15 / 16 ) ;
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------------
// Render a side.
// Check for normal facing. If so, render faces on side dictated by sidep->type.
2014-10-02 03:02:34 +00:00
static void render_side ( const vcsegptridx_t segp , int sidenum )
2006-03-20 17:12:09 +00:00
{
2014-10-02 03:02:34 +00:00
auto sidep = & segp - > sides [ sidenum ] ;
2006-07-11 16:14:17 +00:00
fix min_dot , max_dot ;
vms_vector normals [ 2 ] ;
2014-09-06 22:26:11 +00:00
auto wid_flags = WALL_IS_DOORWAY ( segp , sidenum ) ;
2006-03-20 17:12:09 +00:00
if ( ! ( wid_flags & WID_RENDER_FLAG ) ) //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL)
return ;
normals [ 0 ] = segp - > sides [ sidenum ] . normals [ 0 ] ;
normals [ 1 ] = segp - > sides [ sidenum ] . normals [ 1 ] ;
2014-08-16 17:42:23 +00:00
side_vertnum_list_t vertnum_list ;
2014-10-02 03:02:34 +00:00
get_side_verts ( vertnum_list , segp , sidenum ) ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
// Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
// deal with it, get the dot product.
2014-11-13 03:14:36 +00:00
const unsigned which_vertnum =
# if defined(DXX_BUILD_DESCENT_II)
/* Silly, but consistent with how it was at release */
( sidep - > get_type ( ) = = SIDE_IS_QUAD ) ? 0 :
2013-03-03 01:03:33 +00:00
# endif
2014-11-13 03:14:36 +00:00
( sidep - > get_type ( ) = = SIDE_IS_TRI_13 )
? 1
: 0 ;
const auto tvec = vm_vec_normalized_quick ( vm_vec_sub ( Viewer_eye , Vertices [ vertnum_list [ which_vertnum ] ] ) ) ;
const auto v_dot_n0 = vm_vec_dot ( tvec , normals [ 0 ] ) ;
2006-03-20 17:12:09 +00:00
// ========== Mark: Here is the change...beginning here: ==========
2014-09-13 22:05:52 +00:00
index_sequence < 0 , 1 , 2 , 3 > is_quad ;
2014-09-06 22:36:58 +00:00
if ( sidep - > get_type ( ) = = SIDE_IS_QUAD ) {
2006-03-20 17:12:09 +00:00
if ( v_dot_n0 > = 0 ) {
2014-10-02 03:02:34 +00:00
check_render_face ( is_quad , segp , sidenum , 0 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
}
} else {
// ========== Mark: The change ends here. ==========
// Although this side has been triangulated, because it is not planar, see if it is acceptable
// to render it as a single quadrilateral. This is a function of how far away the viewer is, how non-planar
// the face is, how normal to the surfaces the view is.
// Now, if both dot products are close to 1.0, then render two triangles as a single quad.
2014-11-13 03:14:36 +00:00
const auto v_dot_n1 = vm_vec_dot ( tvec , normals [ 1 ] ) ;
2006-03-20 17:12:09 +00:00
if ( v_dot_n0 < v_dot_n1 ) {
min_dot = v_dot_n0 ;
max_dot = v_dot_n1 ;
} else {
min_dot = v_dot_n1 ;
max_dot = v_dot_n0 ;
}
// Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio))
2014-10-02 03:02:34 +00:00
if ( DETRIANGULATION & & ( ( min_dot + F1_0 / 256 > max_dot ) | | ( ( Viewer - > segnum ! = segp ) & & ( min_dot > Tulate_min_dot ) & & ( max_dot < min_dot * 2 ) ) ) ) {
2006-03-20 17:12:09 +00:00
fix n0_dot_n1 ;
// The other detriangulation code doesn't deal well with badly non-planar sides.
2014-09-28 21:11:48 +00:00
n0_dot_n1 = vm_vec_dot ( normals [ 0 ] , normals [ 1 ] ) ;
2006-03-20 17:12:09 +00:00
if ( n0_dot_n1 < Min_n0_n1_dot )
goto im_so_ashamed ;
2014-10-02 03:02:34 +00:00
check_render_face ( is_quad , segp , sidenum , 0 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
} else {
im_so_ashamed : ;
2014-09-06 22:36:58 +00:00
if ( sidep - > get_type ( ) = = SIDE_IS_TRI_02 ) {
2006-03-20 17:12:09 +00:00
if ( v_dot_n0 > = 0 ) {
2014-10-02 03:02:34 +00:00
check_render_face ( index_sequence < 0 , 1 , 2 > ( ) , segp , sidenum , 0 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
}
if ( v_dot_n1 > = 0 ) {
2014-09-13 22:05:52 +00:00
// want to render from vertices 0, 2, 3 on side
2014-10-02 03:02:34 +00:00
check_render_face ( index_sequence < 0 , 2 , 3 > ( ) , segp , sidenum , 1 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
}
2014-09-06 22:36:58 +00:00
} else if ( sidep - > get_type ( ) = = SIDE_IS_TRI_13 ) {
2006-03-20 17:12:09 +00:00
if ( v_dot_n1 > = 0 ) {
2014-09-13 22:05:52 +00:00
// rendering 1,2,3, so just skip 0
2014-10-02 03:02:34 +00:00
check_render_face ( index_sequence < 1 , 2 , 3 > ( ) , segp , sidenum , 1 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
}
if ( v_dot_n0 > = 0 ) {
2014-09-13 22:05:52 +00:00
// want to render from vertices 0,1,3
2014-10-02 03:02:34 +00:00
check_render_face ( index_sequence < 0 , 1 , 3 > ( ) , segp , sidenum , 0 , vertnum_list , sidep - > tmap_num , sidep - > tmap_num2 , sidep - > uvls , wid_flags ) ;
2006-03-20 17:12:09 +00:00
}
} else
2014-09-06 22:36:58 +00:00
throw side : : illegal_type ( segp , sidep ) ;
2006-03-20 17:12:09 +00:00
}
}
}
# ifdef EDITOR
2014-10-02 03:02:34 +00:00
static void render_object_search ( const vobjptridx_t obj )
2006-03-20 17:12:09 +00:00
{
int changed = 0 ;
//note that we draw each pixel object twice, since we cannot control
//what color the object draws in, so we try color 0, then color 1,
//in case the object itself is rendering color 0
2013-01-17 05:14:44 +00:00
gr_setcolor ( 0 ) ; //set our search pixel to color zero
2012-04-15 05:45:45 +00:00
# ifdef OGL
ogl_end_frame ( ) ;
2013-01-17 05:14:44 +00:00
// For OpenGL we use gr_rect instead of gr_pixel,
// because in some implementations (like my Macbook Pro 5,1)
// point smoothing can't be turned off.
// Point smoothing would change the pixel to dark grey, but it MUST be black.
// Making a 3x3 rectangle wouldn't matter
// (but it only seems to draw a single pixel anyway)
gr_rect ( _search_x - 1 , _search_y - 1 , _search_x + 1 , _search_y + 1 ) ;
2012-04-15 05:45:45 +00:00
ogl_start_frame ( ) ;
2013-01-17 05:14:44 +00:00
# else
gr_pixel ( _search_x , _search_y ) ;
2012-04-15 05:45:45 +00:00
# endif
2006-03-20 17:12:09 +00:00
render_object ( obj ) ;
if ( gr_ugpixel ( & grd_curcanv - > cv_bitmap , _search_x , _search_y ) ! = 0 )
changed = 1 ;
gr_setcolor ( 1 ) ;
2012-04-15 05:45:45 +00:00
# ifdef OGL
ogl_end_frame ( ) ;
2013-01-17 05:14:44 +00:00
gr_rect ( _search_x - 1 , _search_y - 1 , _search_x + 1 , _search_y + 1 ) ;
2012-04-15 05:45:45 +00:00
ogl_start_frame ( ) ;
2013-01-17 05:14:44 +00:00
# else
gr_pixel ( _search_x , _search_y ) ;
2012-04-15 05:45:45 +00:00
# endif
2006-03-20 17:12:09 +00:00
render_object ( obj ) ;
if ( gr_ugpixel ( & grd_curcanv - > cv_bitmap , _search_x , _search_y ) ! = 1 )
changed = 1 ;
if ( changed ) {
2013-12-26 22:21:16 +00:00
if ( obj - > segnum ! = segment_none )
2006-03-20 17:12:09 +00:00
Cursegp = & Segments [ obj - > segnum ] ;
2014-06-28 04:13:42 +00:00
found_seg = - ( static_cast < short > ( obj ) + 1 ) ;
2006-03-20 17:12:09 +00:00
}
}
# endif
2014-10-02 03:02:34 +00:00
static void do_render_object ( const vobjptridx_t obj , int window_num )
2006-03-20 17:12:09 +00:00
{
# ifdef EDITOR
int save_3d_outline = 0 ;
# endif
int count = 0 ;
2014-01-11 23:02:43 +00:00
Assert ( obj < MAX_OBJECTS ) ;
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2014-01-11 23:02:43 +00:00
if ( object_rendered [ obj ] ) { //already rendered this...
2006-03-20 17:12:09 +00:00
Int3 ( ) ; //get Matt!!!
return ;
}
2014-10-02 03:02:34 +00:00
object_rendered [ obj ] = true ;
2006-03-20 17:12:09 +00:00
# endif
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Newdemo_state = = ND_STATE_PLAYBACK )
{
2014-01-11 23:02:43 +00:00
if ( ( DemoDoingLeft = = 6 | | DemoDoingRight = = 6 ) & & obj - > type = = OBJ_PLAYER )
2006-03-20 17:12:09 +00:00
{
// A nice fat hack: keeps the player ship from showing up in the
// small extra view when guiding a missile in the big window
return ;
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
// Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so
// that the guided missile system will know what objects to look at.
// I didn't know we had guided missiles before the release of D1. --MK
2014-01-11 23:02:43 +00:00
if ( ( obj - > type = = OBJ_ROBOT ) | | ( obj - > type = = OBJ_PLAYER ) ) {
Window_rendered_data [ window_num ] . rendered_robots . emplace_back ( obj ) ;
2006-03-20 17:12:09 +00:00
}
2014-01-11 23:02:43 +00:00
if ( ( count + + > MAX_OBJECTS ) | | ( obj - > next = = obj ) ) {
2006-03-20 17:12:09 +00:00
Int3 ( ) ; // infinite loop detected
2013-12-26 22:21:16 +00:00
obj - > next = object_none ; // won't this clean things up?
2006-03-20 17:12:09 +00:00
return ; // get out of this infinite loop!
}
//g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size);
//check for editor object
# ifdef EDITOR
2014-01-11 23:02:43 +00:00
if ( EditorWindow & & obj = = Cur_object_index ) {
2006-03-20 17:12:09 +00:00
save_3d_outline = g3d_interp_outline ;
g3d_interp_outline = 1 ;
}
# endif
# ifdef EDITOR
if ( _search_mode )
render_object_search ( obj ) ;
else
# endif
//NOTE LINK TO ABOVE
render_object ( obj ) ;
2013-12-29 04:28:07 +00:00
for ( objnum_t n = obj - > attached_obj ; n ! = object_none ; n = Objects [ n ] . ctype . expl_info . next_attach ) {
2006-03-20 17:12:09 +00:00
Assert ( Objects [ n ] . type = = OBJ_FIREBALL ) ;
Assert ( Objects [ n ] . control_type = = CT_EXPLOSION ) ;
Assert ( Objects [ n ] . flags & OF_ATTACHED ) ;
render_object ( & Objects [ n ] ) ;
}
# ifdef EDITOR
2014-01-11 23:02:43 +00:00
if ( EditorWindow & & obj = = Cur_object_index )
2006-03-20 17:12:09 +00:00
g3d_interp_outline = save_3d_outline ;
# endif
}
//increment counter for checking if points rotated
//This must be called at the start of the frame if rotate_list() will be used
void render_start_frame ( )
{
2014-08-20 01:28:22 +00:00
if ( s_current_generation = = std : : numeric_limits < decltype ( s_current_generation ) > : : max ( ) )
{
Segment_points = { } ;
s_current_generation = 0 ;
2006-03-20 17:12:09 +00:00
}
2014-08-20 01:28:22 +00:00
+ + s_current_generation ;
2006-03-20 17:12:09 +00:00
}
//Given a lit of point numbers, rotate any that haven't been rotated this frame
2014-10-26 03:24:09 +00:00
g3s_codes rotate_list ( std : : size_t nv , const int * pointnumlist )
2006-03-20 17:12:09 +00:00
{
int i , pnum ;
g3s_codes cc ;
for ( i = 0 ; i < nv ; i + + ) {
pnum = pointnumlist [ i ] ;
2014-10-02 03:02:35 +00:00
auto & pnt = Segment_points [ pnum ] ;
if ( pnt . p3_last_generation ! = s_current_generation )
2011-02-14 21:27:07 +00:00
{
2014-10-02 03:02:35 +00:00
pnt . p3_last_generation = s_current_generation ;
2011-02-14 21:27:07 +00:00
if ( cheats . acid )
{
float f = ( float ) timer_query ( ) / F1_0 ;
vms_vector tmpv = Vertices [ pnum ] ;
tmpv . x + = fl2f ( sinf ( f * 2.0f + f2fl ( tmpv . x ) ) ) ;
tmpv . y + = fl2f ( sinf ( f * 3.0f + f2fl ( tmpv . y ) ) ) ;
tmpv . z + = fl2f ( sinf ( f * 5.0f + f2fl ( tmpv . z ) ) ) ;
2014-10-02 03:02:35 +00:00
g3_rotate_point ( pnt , tmpv ) ;
2011-02-14 21:27:07 +00:00
}
else
2014-10-02 03:02:35 +00:00
g3_rotate_point ( pnt , Vertices [ pnum ] ) ;
2006-03-20 17:12:09 +00:00
}
2014-10-02 03:02:35 +00:00
cc . uand & = pnt . p3_codes ;
cc . uor | = pnt . p3_codes ;
2006-03-20 17:12:09 +00:00
}
return cc ;
}
//Given a lit of point numbers, project any that haven't been projected
2014-08-16 18:14:00 +00:00
static void project_list ( array < int , 8 > & pointnumlist )
2006-03-20 17:12:09 +00:00
{
2014-08-16 18:14:00 +00:00
range_for ( auto pnum , pointnumlist )
{
2006-03-20 17:12:09 +00:00
if ( ! ( Segment_points [ pnum ] . p3_flags & PF_PROJECTED ) )
2014-11-13 03:21:33 +00:00
g3_project_point ( Segment_points [ pnum ] ) ;
2006-03-20 17:12:09 +00:00
}
}
// -----------------------------------------------------------------------------------
2014-09-03 01:39:24 +00:00
# if !defined(OGL)
2013-12-29 04:28:07 +00:00
static void render_segment ( segnum_t segnum , int window_num )
2006-03-20 17:12:09 +00:00
{
segment * seg = & Segments [ segnum ] ;
int sn ;
2013-12-26 22:21:16 +00:00
Assert ( segnum ! = segment_none & & segnum < = Highest_segment_index ) ;
2014-08-16 18:14:11 +00:00
g3s_codes cc = rotate_list ( seg - > verts ) ;
2012-11-02 17:08:58 +00:00
if ( ! cc . uand ) { //all off screen?
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Viewer - > type ! = OBJ_ROBOT )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
Automap_visited [ segnum ] = 1 ;
for ( sn = 0 ; sn < MAX_SIDES_PER_SEGMENT ; sn + + )
render_side ( seg , sn ) ;
}
//draw any objects that happen to be in this segment
//sort objects!
//object_sort_segment_objects( seg );
}
2013-10-26 19:14:51 +00:00
# endif
2006-03-20 17:12:09 +00:00
// ----- This used to be called when Show_only_curside was set.
// ----- It is wholly and superiorly replaced by render_side.
// -- //render one side of one segment
// -- void render_seg_side(segment *seg,int _side)
// -- {
// -- g3s_codes cc;
// -- short vertnum_list[4];
// --
// -- cc=g3_rotate_list(8,&seg->verts);
// --
2012-11-02 17:08:58 +00:00
// -- if (! cc.uand) { //all off screen?
2006-03-20 17:12:09 +00:00
// -- int fn,pn,i;
// -- side *s;
// -- face *f;
// -- poly *p;
// --
// -- s=&seg->sides[_side];
// --
// -- for (f=s->faces,fn=s->num_faces;fn;fn--,f++)
// -- for (p=f->polys,pn=f->num_polys;pn;pn--,p++) {
// -- grs_bitmap *tmap;
// --
// -- for (i=0;i<p->num_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]];
// --
// -- if (p->tmap_num >= NumTextures) {
// -- Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures);
// -- p->tmap_num = 0; //change it permanantly
// -- }
// --
// -- tmap = Textures[p->tmap_num];
// --
// -- g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal);
// --
// -- if (Outline_mode) draw_outline(p->num_vertices,vertnum_list);
// -- }
// -- }
// --
// -- }
2014-07-30 03:03:33 +00:00
static const fix CROSS_WIDTH = i2f ( 8 ) ;
static const fix CROSS_HEIGHT = i2f ( 8 ) ;
2006-03-20 17:12:09 +00:00
2014-08-18 00:11:51 +00:00
# ifdef EDITOR
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
//draw outline for curside
2014-10-02 03:02:34 +00:00
static void outline_seg_side ( const vcsegptr_t seg , int _side , int edge , int vert )
2006-03-20 17:12:09 +00:00
{
2014-08-16 18:14:11 +00:00
g3s_codes cc = rotate_list ( seg - > verts ) ;
2006-03-20 17:12:09 +00:00
2012-11-02 17:08:58 +00:00
if ( ! cc . uand ) { //all off screen?
2006-03-20 17:12:09 +00:00
g3s_point * pnt ;
//render curedge of curside of curseg in green
gr_setcolor ( BM_XRGB ( 0 , 63 , 0 ) ) ;
2014-11-13 03:19:52 +00:00
g3_draw_line ( Segment_points [ seg - > verts [ Side_to_verts [ _side ] [ edge ] ] ] , Segment_points [ seg - > verts [ Side_to_verts [ _side ] [ ( edge + 1 ) % 4 ] ] ] ) ;
2006-03-20 17:12:09 +00:00
//draw a little cross at the current vert
pnt = & Segment_points [ seg - > verts [ Side_to_verts [ _side ] [ vert ] ] ] ;
2014-11-13 03:21:33 +00:00
g3_project_point ( * pnt ) ; //make sure projected
2006-03-20 17:12:09 +00:00
// gr_setcolor(BM_XRGB(0,0,63));
// gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
// gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
gr_line ( pnt - > p3_sx - CROSS_WIDTH , pnt - > p3_sy , pnt - > p3_sx , pnt - > p3_sy - CROSS_HEIGHT ) ;
gr_line ( pnt - > p3_sx , pnt - > p3_sy - CROSS_HEIGHT , pnt - > p3_sx + CROSS_WIDTH , pnt - > p3_sy ) ;
gr_line ( pnt - > p3_sx + CROSS_WIDTH , pnt - > p3_sy , pnt - > p3_sx , pnt - > p3_sy + CROSS_HEIGHT ) ;
gr_line ( pnt - > p3_sx , pnt - > p3_sy + CROSS_HEIGHT , pnt - > p3_sx - CROSS_WIDTH , pnt - > p3_sy ) ;
}
}
2014-08-18 00:11:51 +00:00
# endif
2006-03-20 17:12:09 +00:00
# endif
#if 0 //this stuff could probably just be deleted
# define DEFAULT_PERSPECTIVE_DEPTH 6
int Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH ; //how many levels deep to render in perspective
int inc_perspective_depth ( void )
{
return + + Perspective_depth ;
}
int dec_perspective_depth ( void )
{
return Perspective_depth = = 1 ? Perspective_depth : - - Perspective_depth ;
}
int reset_perspective_depth ( void )
{
return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH ;
}
# endif
2013-10-27 22:00:14 +00:00
static ubyte code_window_point ( fix x , fix y , rect * w )
2006-03-20 17:12:09 +00:00
{
ubyte code = 0 ;
if ( x < = w - > left ) code | = 1 ;
if ( x > = w - > right ) code | = 2 ;
if ( y < = w - > top ) code | = 4 ;
if ( y > = w - > bot ) code | = 8 ;
return code ;
}
# ifndef NDEBUG
char visited2 [ MAX_SEGMENTS ] ;
# endif
2012-12-02 18:57:09 +00:00
struct visited_twobit_array_t : visited_segment_multibit_array_t < 2 > { } ;
2006-03-20 17:12:09 +00:00
int lcnt_save , scnt_save ;
# define RED BM_XRGB(63,0,0)
# define WHITE BM_XRGB(63,63,63)
//Given two sides of segment, tell the two verts which form the
//edge between them
2014-08-08 02:51:31 +00:00
typedef array < int_fast8_t , 2 > se_array0 ;
typedef array < se_array0 , 6 > se_array1 ;
typedef array < se_array1 , 6 > se_array2 ;
static const se_array2 Two_sides_to_edge = { {
2014-10-04 15:04:44 +00:00
{ { { { edge_none , edge_none } } , { { 3 , 7 } } , { { edge_none , edge_none } } , { { 2 , 6 } } , { { 6 , 7 } } , { { 2 , 3 } } } } ,
{ { { { 3 , 7 } } , { { edge_none , edge_none } } , { { 0 , 4 } } , { { edge_none , edge_none } } , { { 4 , 7 } } , { { 0 , 3 } } } } ,
{ { { { edge_none , edge_none } } , { { 0 , 4 } } , { { edge_none , edge_none } } , { { 1 , 5 } } , { { 4 , 5 } } , { { 0 , 1 } } } } ,
{ { { { 2 , 6 } } , { { edge_none , edge_none } } , { { 1 , 5 } } , { { edge_none , edge_none } } , { { 5 , 6 } } , { { 1 , 2 } } } } ,
{ { { { 6 , 7 } } , { { 4 , 7 } } , { { 4 , 5 } } , { { 5 , 6 } } , { { edge_none , edge_none } } , { { edge_none , edge_none } } } } ,
{ { { { 2 , 3 } } , { { 0 , 3 } } , { { 0 , 1 } } , { { 1 , 2 } } , { { edge_none , edge_none } } , { { edge_none , edge_none } } } }
2014-08-08 02:51:31 +00:00
} } ;
2006-03-20 17:12:09 +00:00
//given an edge specified by two verts, give the two sides on that edge
2014-08-08 02:51:31 +00:00
typedef array < int_fast8_t , 2 > es_array0 ;
typedef array < es_array0 , 8 > es_array1 ;
typedef array < es_array1 , 8 > es_array2 ;
static const es_array2 Edge_to_sides = { {
2014-10-04 15:04:44 +00:00
{ { { { side_none , side_none } } , { { 2 , 5 } } , { { side_none , side_none } } , { { 1 , 5 } } , { { 1 , 2 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } } } ,
{ { { { 2 , 5 } } , { { side_none , side_none } } , { { 3 , 5 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 2 , 3 } } , { { side_none , side_none } } , { { side_none , side_none } } } } ,
{ { { { side_none , side_none } } , { { 3 , 5 } } , { { side_none , side_none } } , { { 0 , 5 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 0 , 3 } } , { { side_none , side_none } } } } ,
{ { { { 1 , 5 } } , { { side_none , side_none } } , { { 0 , 5 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 0 , 1 } } } } ,
{ { { { 1 , 2 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 2 , 4 } } , { { side_none , side_none } } , { { 1 , 4 } } } } ,
{ { { { side_none , side_none } } , { { 2 , 3 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 2 , 4 } } , { { side_none , side_none } } , { { 3 , 4 } } , { { side_none , side_none } } } } ,
{ { { { side_none , side_none } } , { { side_none , side_none } } , { { 0 , 3 } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 3 , 4 } } , { { side_none , side_none } } , { { 0 , 4 } } } } ,
{ { { { side_none , side_none } } , { { side_none , side_none } } , { { side_none , side_none } } , { { 0 , 1 } } , { { 1 , 4 } } , { { side_none , side_none } } , { { 0 , 4 } } , { { side_none , side_none } } } } ,
2014-08-08 02:51:31 +00:00
} } ;
2006-03-20 17:12:09 +00:00
//@@//perform simple check on tables
//@@check_check()
//@@{
//@@ int i,j;
//@@
//@@ for (i=0;i<8;i++)
//@@ for (j=0;j<8;j++)
//@@ Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] &&
//@@ Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]);
//@@
//@@ for (i=0;i<6;i++)
//@@ for (j=0;j<6;j++)
//@@ Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] &&
//@@ Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]);
//@@
//@@
//@@}
//given an edge, tell what side is on that edge
2014-10-02 03:02:34 +00:00
static int find_seg_side ( const vcsegptr_t seg , const array < int , 2 > & verts , unsigned notside )
2006-03-20 17:12:09 +00:00
{
2014-08-12 03:08:39 +00:00
if ( notside > = MAX_SIDES_PER_SEGMENT )
throw std : : logic_error ( " invalid notside " ) ;
2006-03-20 17:12:09 +00:00
int side0 , side1 ;
int v0 , v1 ;
//@@ check_check();
v0 = verts [ 0 ] ;
v1 = verts [ 1 ] ;
2014-08-16 17:59:36 +00:00
auto b = begin ( seg - > verts ) ;
auto e = end ( seg - > verts ) ;
auto iv0 = e ;
auto iv1 = e ;
for ( auto i = b ; ; )
{
if ( iv0 = = e & & * i = = v0 )
{
iv0 = i ;
if ( iv1 ! = e )
2006-03-20 17:12:09 +00:00
break ;
}
2014-08-16 17:59:36 +00:00
if ( iv1 = = e & & * i = = v1 )
{
iv1 = i ;
if ( iv0 ! = e )
2006-03-20 17:12:09 +00:00
break ;
}
2014-08-16 17:59:36 +00:00
if ( + + i = = e )
2014-10-04 15:04:44 +00:00
return side_none ;
2006-03-20 17:12:09 +00:00
}
2014-08-16 17:59:36 +00:00
const auto & eptr = Edge_to_sides [ std : : distance ( b , iv0 ) ] [ std : : distance ( b , iv1 ) ] ;
2006-03-20 17:12:09 +00:00
side0 = eptr [ 0 ] ;
side1 = eptr [ 1 ] ;
2014-10-04 15:04:44 +00:00
Assert ( side0 ! = side_none & & side1 ! = side_none ) ;
2006-03-20 17:12:09 +00:00
if ( side0 ! = notside ) {
Assert ( side1 = = notside ) ;
return side0 ;
}
else {
Assert ( side0 = = notside ) ;
return side1 ;
}
}
//find the two segments that join a given seg though two sides, and
//the sides of those segments the abut.
2014-10-02 03:02:34 +00:00
static int find_joining_side_norms ( const vms_vector * & norm0_0 , const vms_vector * & norm0_1 , const vms_vector * & norm1_0 , const vms_vector * & norm1_1 , const vms_vector * & pnt0 , const vms_vector * & pnt1 , const vcsegptridx_t seg , int s0 , int s1 )
2006-03-20 17:12:09 +00:00
{
2014-10-04 15:04:44 +00:00
Assert ( s0 ! = side_none & & s1 ! = side_none ) ;
2006-03-20 17:12:09 +00:00
2014-08-12 02:58:08 +00:00
const array < int , 2 > edge_verts = {
{ seg - > verts [ Two_sides_to_edge [ s0 ] [ s1 ] [ 0 ] ] , seg - > verts [ Two_sides_to_edge [ s0 ] [ s1 ] [ 1 ] ] }
} ;
if ( edge_verts [ 0 ] = = - 1 | | edge_verts [ 1 ] = = - 1 )
throw std : : logic_error ( " invalid edge vert " ) ;
2014-10-02 03:02:34 +00:00
auto seg0 = vsegptridx ( seg - > children [ s0 ] ) ;
2014-09-06 04:06:18 +00:00
auto edgeside0 = find_seg_side ( seg0 , edge_verts , find_connect_side ( seg , seg0 ) ) ;
2014-10-04 15:04:44 +00:00
if ( edgeside0 = = side_none ) return 0 ;
2014-10-02 03:02:34 +00:00
auto seg1 = vsegptridx ( seg - > children [ s1 ] ) ;
2014-09-06 04:06:18 +00:00
auto edgeside1 = find_seg_side ( seg1 , edge_verts , find_connect_side ( seg , seg1 ) ) ;
2014-10-04 15:04:44 +00:00
if ( edgeside1 = = side_none ) return 0 ;
2006-03-20 17:12:09 +00:00
2014-09-06 04:01:32 +00:00
norm0_0 = & seg0 - > sides [ edgeside0 ] . normals [ 0 ] ;
norm0_1 = & seg0 - > sides [ edgeside0 ] . normals [ 1 ] ;
norm1_0 = & seg1 - > sides [ edgeside1 ] . normals [ 0 ] ;
norm1_1 = & seg1 - > sides [ edgeside1 ] . normals [ 1 ] ;
2006-03-20 17:12:09 +00:00
2014-11-21 03:28:41 +00:00
auto v = [ ] ( vsegptr_t seg , int edgeside ) {
auto & side = seg - > sides [ edgeside ] ;
auto sv = Side_to_verts [ edgeside ] [ side . get_type ( ) = = SIDE_IS_TRI_13 ? 1 : 0 ] ;
return & Vertices [ seg - > verts [ sv ] ] ;
} ;
pnt0 = v ( seg0 , edgeside0 ) ;
pnt1 = v ( seg1 , edgeside1 ) ;
2006-03-20 17:12:09 +00:00
return 1 ;
}
//see if the order matters for these two children.
//returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0
2014-10-02 03:02:34 +00:00
static int compare_children ( const vcsegptridx_t seg , short c0 , short c1 )
2006-03-20 17:12:09 +00:00
{
2014-09-06 04:01:32 +00:00
const vms_vector * norm0_0 , * norm0_1 , * pnt0 , * norm1_0 , * norm1_1 , * pnt1 ;
2006-07-11 16:14:17 +00:00
int t ;
2006-03-20 17:12:09 +00:00
if ( Side_opposite [ c0 ] = = c1 ) return 0 ;
2014-10-04 15:04:44 +00:00
Assert ( c0 ! = side_none & & c1 ! = side_none ) ;
2006-03-20 17:12:09 +00:00
//find normals of adjoining sides
2014-09-06 04:01:32 +00:00
t = find_joining_side_norms ( norm0_0 , norm0_1 , norm1_0 , norm1_1 , pnt0 , pnt1 , seg , c0 , c1 ) ;
2006-03-20 17:12:09 +00:00
2010-07-17 11:57:07 +00:00
if ( ! t ) // can happen - 4D rooms!
return 0 ;
2006-03-20 17:12:09 +00:00
2014-10-29 03:24:31 +00:00
const auto temp = vm_vec_sub ( Viewer_eye , * pnt0 ) ;
2014-09-28 21:11:48 +00:00
if ( vm_vec_dot ( * norm0_0 , temp ) < 0 | | vm_vec_dot ( * norm0_1 , temp ) < 0 )
2014-09-06 04:01:32 +00:00
{
2014-10-29 03:24:31 +00:00
const auto temp = vm_vec_sub ( Viewer_eye , * pnt1 ) ;
2014-09-28 21:11:48 +00:00
if ( vm_vec_dot ( * norm1_0 , temp ) < 0 | | vm_vec_dot ( * norm1_1 , temp ) < 0 )
2014-09-06 04:01:32 +00:00
return 0 ;
2006-03-20 17:12:09 +00:00
return 1 ;
2014-09-06 04:01:32 +00:00
}
2006-03-20 17:12:09 +00:00
else
return 0 ;
}
2014-09-08 03:31:05 +00:00
typedef uint_fast8_t sidenum_t ;
2006-03-20 17:12:09 +00:00
//short the children of segment to render in the correct order
//returns non-zero if swaps were made
2014-10-02 03:02:34 +00:00
static void sort_seg_children ( const vcsegptridx_t seg , uint_fast32_t n_children , array < sidenum_t , MAX_SIDES_PER_SEGMENT > & child_list )
2006-03-20 17:12:09 +00:00
{
int made_swaps , count ;
2014-09-08 03:31:05 +00:00
if ( n_children = = 0 ) return ;
2006-03-20 17:12:09 +00:00
//for each child, compare with other children and see if order matters
//if order matters, fix if wrong
count = 0 ;
2014-09-08 03:31:05 +00:00
auto predicate = [ seg , & made_swaps ] ( sidenum_t a , sidenum_t b )
{
return compare_children ( seg , a , b ) ? ( made_swaps = 1 , true ) : false ;
} ;
auto r = partial_range ( child_list , n_children ) ;
2006-03-20 17:12:09 +00:00
do {
made_swaps = 0 ;
2014-09-08 03:31:05 +00:00
std : : sort ( r . begin ( ) , r . end ( ) , predicate ) ;
2006-03-20 17:12:09 +00:00
} while ( made_swaps & & + + count < n_children ) ;
}
2014-11-21 03:16:00 +00:00
static void add_obj_to_seglist ( render_state_t & rstate , objnum_t objnum , segnum_t segnum )
2006-03-20 17:12:09 +00:00
{
2014-11-21 03:16:00 +00:00
auto p = rstate . render_seg_map . emplace ( segnum , render_state_t : : per_segment_state_t { } ) ;
auto & o = p . first - > second . objects ;
if ( p . second )
o . reserve ( 16 ) ;
o . emplace_back ( render_state_t : : per_segment_state_t : : distant_object { objnum } ) ;
2006-03-20 17:12:09 +00:00
}
2014-11-21 03:29:28 +00:00
struct render_compare_context_t
2013-12-22 22:03:07 +00:00
{
2014-11-21 03:29:28 +00:00
struct element
{
fix64 dist_squared ;
2014-11-21 03:31:39 +00:00
# if defined(DXX_BUILD_DESCENT_II)
object * objp ;
# endif
2014-11-21 03:29:28 +00:00
} ;
typedef array < element , MAX_OBJECTS > array_t ;
array_t a ;
array_t : : reference operator [ ] ( std : : size_t i ) { return a [ i ] ; }
array_t : : const_reference operator [ ] ( std : : size_t i ) const { return a [ i ] ; }
render_compare_context_t ( const render_state_t : : per_segment_state_t & segstate )
{
range_for ( auto t , segstate . objects )
{
auto objp = & Objects [ t . objnum ] ;
auto & e = ( * this ) [ t . objnum ] ;
2014-11-21 03:31:39 +00:00
# if defined(DXX_BUILD_DESCENT_II)
e . objp = objp ;
# endif
2014-11-21 03:29:28 +00:00
e . dist_squared = vm_vec_dist2 ( objp - > pos , Viewer_eye ) ;
}
}
2013-12-22 22:03:07 +00:00
} ;
2006-03-20 17:12:09 +00:00
//compare function for object sort.
2014-11-21 03:29:28 +00:00
static bool compare_func ( const render_compare_context_t & c , const render_state_t : : per_segment_state_t : : distant_object & a , const render_state_t : : per_segment_state_t : : distant_object & b )
2006-03-20 17:12:09 +00:00
{
2014-11-21 03:29:28 +00:00
fix64 delta_dist_squared = c [ a . objnum ] . dist_squared - c [ b . objnum ] . dist_squared ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-11-21 03:31:39 +00:00
const auto obj_a = c [ a . objnum ] . objp ;
const auto obj_b = c [ b . objnum ] . objp ;
2006-03-20 17:12:09 +00:00
2014-11-12 03:04:23 +00:00
auto abs_delta_dist_squared = std : : abs ( delta_dist_squared ) ;
fix combined_size = obj_a - > size + obj_b - > size ;
/*
* First check without squaring . If true , the square can be
* skipped .
*/
if ( abs_delta_dist_squared < combined_size | | abs_delta_dist_squared < ( combined_size * combined_size ) )
{ //same position
2006-03-20 17:12:09 +00:00
//these two objects are in the same position. see if one is a fireball
//or laser or something that should plot on top. Don't do this for
//the afterburner blobs, though.
if ( obj_a - > type = = OBJ_WEAPON | | ( obj_a - > type = = OBJ_FIREBALL & & obj_a - > id ! = VCLIP_AFTERBURNER_BLOB ) )
if ( ! ( obj_b - > type = = OBJ_WEAPON | | obj_b - > type = = OBJ_FIREBALL ) )
2014-11-13 03:07:58 +00:00
return true ; //a is weapon, b is not, so say a is closer
2006-03-20 17:12:09 +00:00
else ; //both are weapons
else
if ( obj_b - > type = = OBJ_WEAPON | | ( obj_b - > type = = OBJ_FIREBALL & & obj_b - > id ! = VCLIP_AFTERBURNER_BLOB ) )
2014-11-13 03:07:58 +00:00
return false ; //b is weapon, a is not, so say a is farther
2006-03-20 17:12:09 +00:00
//no special case, fall through to normal return
}
2013-03-03 01:03:33 +00:00
# endif
2014-11-13 03:07:58 +00:00
return delta_dist_squared < 0 ; //return distance
2006-03-20 17:12:09 +00:00
}
2014-11-21 03:29:28 +00:00
static void sort_segment_object_list ( render_state_t : : per_segment_state_t & segstate )
{
render_compare_context_t context ( segstate ) ;
typedef render_state_t : : per_segment_state_t : : distant_object distant_object ;
const auto predicate = [ & context ] ( const distant_object & a , const distant_object & b ) { return compare_func ( context , a , b ) ; } ;
auto & v = segstate . objects ;
std : : sort ( v . begin ( ) , v . end ( ) , predicate ) ;
}
2014-09-07 23:39:38 +00:00
static void build_object_lists ( render_state_t & rstate )
2006-03-20 17:12:09 +00:00
{
int nn ;
2014-09-07 23:39:38 +00:00
for ( nn = 0 ; nn < rstate . N_render_segs ; nn + + ) {
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none ) {
2014-07-30 02:52:36 +00:00
range_for ( auto obj , objects_in ( Segments [ segnum ] ) )
{
2013-12-29 04:28:07 +00:00
int list_pos ;
2012-04-17 07:20:14 +00:00
if ( obj - > type = = OBJ_NONE )
continue ;
2006-03-20 17:12:09 +00:00
Assert ( obj - > segnum = = segnum ) ;
if ( obj - > flags & OF_ATTACHED )
continue ; //ignore this object
2014-11-20 03:00:36 +00:00
auto new_segnum = segnum ;
2006-03-20 17:12:09 +00:00
list_pos = nn ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
int did_migrate ;
if ( obj - > type ! = OBJ_CNTRLCEN ) //don't migrate controlcen
# elif defined(DXX_BUILD_DESCENT_II)
const int did_migrate = 0 ;
2013-10-07 23:52:33 +00:00
if ( obj - > type ! = OBJ_CNTRLCEN & & ! ( obj - > type = = OBJ_ROBOT & & get_robot_id ( obj ) = = 65 ) ) //don't migrate controlcen
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
do {
segmasks m ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
did_migrate = 0 ;
# endif
2014-10-26 21:28:38 +00:00
m = get_seg_masks ( obj - > pos , new_segnum , obj - > size , __FILE__ , __LINE__ ) ;
2006-03-20 17:12:09 +00:00
if ( m . sidemask ) {
int sn , sf ;
for ( sn = 0 , sf = 1 ; sn < 6 ; sn + + , sf < < = 1 )
if ( m . sidemask & sf ) {
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
segment * seg = & Segments [ obj - > segnum ] ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
segment * seg = & Segments [ new_segnum ] ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( WALL_IS_DOORWAY ( seg , sn ) & WID_FLY_FLAG ) { //can explosion migrate through
int child = seg - > children [ sn ] ;
int checknp ;
for ( checknp = list_pos ; checknp - - ; )
2014-08-12 02:28:03 +00:00
if ( rstate . Render_list [ checknp ] = = child ) {
2006-03-20 17:12:09 +00:00
new_segnum = child ;
list_pos = checknp ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
did_migrate = 1 ;
# endif
2006-03-20 17:12:09 +00:00
}
}
}
}
2013-03-03 01:03:33 +00:00
} while ( did_migrate ) ;
2014-11-21 03:16:00 +00:00
add_obj_to_seglist ( rstate , obj , new_segnum ) ;
2006-03-20 17:12:09 +00:00
}
}
}
//now that there's a list for each segment, sort the items in those lists
2014-09-07 23:39:38 +00:00
for ( nn = 0 ; nn < rstate . N_render_segs ; nn + + ) {
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none ) {
2014-11-21 03:29:28 +00:00
sort_segment_object_list ( rstate . render_seg_map [ segnum ] ) ;
2006-03-20 17:12:09 +00:00
}
}
}
//--unused-- int Total_num_tmaps_drawn=0;
int Rear_view = 0 ;
# ifdef JOHN_ZOOM
fix Zoom_factor = F1_0 ;
# endif
//renders onto current canvas
void render_frame ( fix eye_offset , int window_num )
{
if ( Endlevel_sequence ) {
render_endlevel_frame ( eye_offset ) ;
return ;
}
if ( Newdemo_state = = ND_STATE_RECORDING & & eye_offset > = 0 ) {
if ( RenderingType = = 0 )
2008-10-16 17:27:02 +00:00
newdemo_record_start_frame ( FrameTime ) ;
2006-03-20 17:12:09 +00:00
if ( RenderingType ! = 255 )
newdemo_record_viewer_object ( Viewer ) ;
}
//Here:
start_lighting_frame ( Viewer ) ; //this is for ugly light-smoothing hack
g3_start_frame ( ) ;
Viewer_eye = Viewer - > pos ;
2010-01-28 00:04:29 +00:00
// if (Viewer->type == OBJ_PLAYER && (PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW))
2006-03-20 17:12:09 +00:00
// vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
if ( eye_offset ) {
2014-09-28 21:43:14 +00:00
vm_vec_scale_add2 ( Viewer_eye , Viewer - > orient . rvec , eye_offset ) ;
2006-03-20 17:12:09 +00:00
}
# ifdef EDITOR
2012-03-19 06:09:26 +00:00
if ( EditorWindow )
2006-03-20 17:12:09 +00:00
Viewer_eye = Viewer - > pos ;
# endif
2014-10-22 02:46:03 +00:00
auto start_seg_num = find_point_seg ( Viewer_eye , Viewer - > segnum ) ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
if ( start_seg_num = = segment_none )
2006-03-20 17:12:09 +00:00
start_seg_num = Viewer - > segnum ;
2008-11-14 16:56:40 +00:00
if ( Rear_view & & ( Viewer = = ConsoleObject ) ) {
2014-10-01 02:28:42 +00:00
vms_matrix headm ;
2014-11-13 03:14:03 +00:00
vms_angvec Player_head_angles ;
2006-03-20 17:12:09 +00:00
Player_head_angles . p = Player_head_angles . b = 0 ;
Player_head_angles . h = 0x7fff ;
2014-10-01 02:28:42 +00:00
vm_angles_2_matrix ( headm , Player_head_angles ) ;
2014-10-01 02:28:42 +00:00
const auto viewm = vm_matrix_x_matrix ( Viewer - > orient , headm ) ;
2014-10-26 22:01:00 +00:00
g3_set_view_matrix ( Viewer_eye , viewm , Render_zoom ) ;
2006-03-20 17:12:09 +00:00
} else {
# ifdef JOHN_ZOOM
if ( keyd_pressed [ KEY_RSHIFT ] ) {
Zoom_factor + = FrameTime * 4 ;
if ( Zoom_factor > F1_0 * 5 ) Zoom_factor = F1_0 * 5 ;
} else {
Zoom_factor - = FrameTime * 4 ;
if ( Zoom_factor < F1_0 ) Zoom_factor = F1_0 ;
}
2014-10-26 22:01:00 +00:00
g3_set_view_matrix ( Viewer_eye , Viewer - > orient , fixdiv ( Render_zoom , Zoom_factor ) ) ;
2006-03-20 17:12:09 +00:00
# else
2014-10-26 22:01:00 +00:00
g3_set_view_matrix ( Viewer_eye , Viewer - > orient , Render_zoom ) ;
2006-03-20 17:12:09 +00:00
# endif
}
if ( Clear_window = = 1 ) {
if ( Clear_window_color = = - 1 )
Clear_window_color = BM_XRGB ( 0 , 0 , 0 ) ; //BM_XRGB(31, 15, 7);
gr_clear_canvas ( Clear_window_color ) ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
if ( Show_only_curside )
gr_clear_canvas ( Clear_window_color ) ;
# endif
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
render_mine ( start_seg_num , eye_offset , window_num ) ;
g3_end_frame ( ) ;
//RenderingType=0;
// -- Moved from here by MK, 05/17/95, wrong if multiple renders/frame! FrameCount++; //we have rendered a frame
}
2014-11-23 21:53:45 +00:00
static int first_terminal_seg ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-10-02 03:02:34 +00:00
void update_rendered_data ( int window_num , const vobjptr_t viewer , int rear_view_flag )
2006-03-20 17:12:09 +00:00
{
Assert ( window_num < MAX_RENDERED_WINDOWS ) ;
2012-05-14 17:06:28 +00:00
Window_rendered_data [ window_num ] . time = timer_query ( ) ;
2006-03-20 17:12:09 +00:00
Window_rendered_data [ window_num ] . viewer = viewer ;
Window_rendered_data [ window_num ] . rear_view = rear_view_flag ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//build a list of segments to be rendered
//fills in Render_list & N_render_segs
2014-08-12 02:28:03 +00:00
static void build_segment_list ( render_state_t & rstate , visited_twobit_array_t & visited , short start_seg_num , int window_num )
2006-03-20 17:12:09 +00:00
{
int lcnt , scnt , ecnt ;
2014-09-08 03:31:05 +00:00
int l ;
2006-03-20 17:12:09 +00:00
2014-08-12 02:28:03 +00:00
rstate . render_pos . fill ( - 1 ) ;
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
memset ( visited2 , 0 , sizeof ( visited2 [ 0 ] ) * ( Highest_segment_index + 1 ) ) ;
# endif
lcnt = scnt = 0 ;
2014-08-12 02:28:03 +00:00
rstate . Render_list [ lcnt ] = start_seg_num ;
visited [ start_seg_num ] = 1 ;
2014-11-23 21:53:45 +00:00
rstate . render_seg_map [ start_seg_num ] . Seg_depth = 0 ;
2006-03-20 17:12:09 +00:00
lcnt + + ;
ecnt = lcnt ;
2014-08-12 02:28:03 +00:00
rstate . render_pos [ start_seg_num ] = 0 ;
rstate . render_windows [ 0 ] . left = rstate . render_windows [ 0 ] . top = 0 ;
rstate . render_windows [ 0 ] . right = grd_curcanv - > cv_bitmap . bm_w - 1 ;
rstate . render_windows [ 0 ] . bot = grd_curcanv - > cv_bitmap . bm_h - 1 ;
2006-03-20 17:12:09 +00:00
//breadth-first renderer
//build list
for ( l = 0 ; l < Render_depth ; l + + ) {
for ( scnt = 0 ; scnt < ecnt ; scnt + + ) {
2014-08-12 02:28:03 +00:00
int rotated ;
2014-09-08 03:31:05 +00:00
array < sidenum_t , MAX_SIDES_PER_SEGMENT > child_list ; //list of ordered sides to process
2006-03-20 17:12:09 +00:00
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ scnt ] ;
2014-08-12 02:28:03 +00:00
rect * check_w = & rstate . render_windows [ scnt ] ;
2013-12-26 22:21:16 +00:00
if ( segnum = = segment_none ) continue ;
2006-03-20 17:12:09 +00:00
2014-11-23 21:53:45 +00:00
auto & srsm = rstate . render_seg_map [ segnum ] ;
auto & processed = srsm . processed ;
if ( processed )
continue ;
processed = true ;
2014-10-02 03:02:34 +00:00
auto seg = vsegptridx ( segnum ) ;
2006-03-20 17:12:09 +00:00
rotated = 0 ;
//look at all sides of this segment.
//tricky code to look at sides in correct order follows
2014-09-08 03:31:05 +00:00
uint_fast32_t n_children = 0 ; //how many sides in child_list
for ( uint_fast32_t c = 0 ; c < MAX_SIDES_PER_SEGMENT ; c + + ) { //build list of sides
2014-09-06 22:26:11 +00:00
auto wid = WALL_IS_DOORWAY ( seg , c ) ;
2014-09-03 01:33:46 +00:00
if ( wid & WID_RENDPAST_FLAG )
{
2006-03-20 17:12:09 +00:00
rotated = 1 ;
2014-09-04 01:51:03 +00:00
ubyte codes_and = rotate_list ( seg - > verts ) . uor ;
if ( codes_and & CC_BEHIND )
{
2014-08-12 03:01:43 +00:00
range_for ( auto i , Side_to_verts [ c ] )
codes_and & = Segment_points [ seg - > verts [ i ] ] . p3_codes ;
2006-03-20 17:12:09 +00:00
if ( codes_and & CC_BEHIND ) continue ;
}
child_list [ n_children + + ] = c ;
}
}
//now order the sides in some magical way
sort_seg_children ( seg , n_children , child_list ) ;
2014-09-08 03:31:05 +00:00
for ( uint_fast32_t c = 0 ; c < n_children ; c + + ) {
2006-03-20 17:12:09 +00:00
int siden ;
siden = child_list [ c ] ;
2014-09-08 03:31:05 +00:00
auto ch = seg - > children [ siden ] ;
2006-03-20 17:12:09 +00:00
{
2014-09-03 01:33:46 +00:00
{
2006-03-20 17:12:09 +00:00
int i ;
ubyte codes_and_3d , codes_and_2d ;
short _x , _y , min_x = 32767 , max_x = - 32767 , min_y = 32767 , max_y = - 32767 ;
int no_proj_flag = 0 ; //a point wasn't projected
if ( rotated < 2 ) {
if ( ! rotated )
2014-08-16 18:14:00 +00:00
rotate_list ( seg - > verts ) ;
project_list ( seg - > verts ) ;
2006-03-20 17:12:09 +00:00
rotated = 2 ;
}
for ( i = 0 , codes_and_3d = codes_and_2d = 0xff ; i < 4 ; i + + ) {
int p = seg - > verts [ Side_to_verts [ siden ] [ i ] ] ;
g3s_point * pnt = & Segment_points [ p ] ;
if ( ! ( pnt - > p3_flags & PF_PROJECTED ) ) { no_proj_flag = 1 ; break ; }
_x = f2i ( pnt - > p3_sx ) ;
_y = f2i ( pnt - > p3_sy ) ;
codes_and_3d & = pnt - > p3_codes ;
codes_and_2d & = code_window_point ( _x , _y , check_w ) ;
if ( _x < min_x ) min_x = _x ;
if ( _x > max_x ) max_x = _x ;
if ( _y < min_y ) min_y = _y ;
if ( _y > max_y ) max_y = _y ;
}
if ( no_proj_flag | | ( ! codes_and_3d & & ! codes_and_2d ) ) { //maybe add this segment
2014-08-12 02:28:03 +00:00
auto rp = rstate . render_pos [ ch ] ;
rect * new_w = & rstate . render_windows [ lcnt ] ;
2006-03-20 17:12:09 +00:00
if ( no_proj_flag ) * new_w = * check_w ;
else {
new_w - > left = max ( check_w - > left , min_x ) ;
new_w - > right = min ( check_w - > right , max_x ) ;
new_w - > top = max ( check_w - > top , min_y ) ;
new_w - > bot = min ( check_w - > bot , max_y ) ;
}
//see if this seg already visited, and if so, does current window
//expand the old window?
if ( rp ! = - 1 ) {
2014-08-12 02:28:03 +00:00
if ( new_w - > left < rstate . render_windows [ rp ] . left | |
new_w - > top < rstate . render_windows [ rp ] . top | |
new_w - > right > rstate . render_windows [ rp ] . right | |
new_w - > bot > rstate . render_windows [ rp ] . bot ) {
2006-03-20 17:12:09 +00:00
2014-08-12 02:28:03 +00:00
new_w - > left = min ( new_w - > left , rstate . render_windows [ rp ] . left ) ;
new_w - > right = max ( new_w - > right , rstate . render_windows [ rp ] . right ) ;
new_w - > top = min ( new_w - > top , rstate . render_windows [ rp ] . top ) ;
new_w - > bot = max ( new_w - > bot , rstate . render_windows [ rp ] . bot ) ;
2006-03-20 17:12:09 +00:00
2014-09-03 01:35:06 +00:00
{
2006-03-20 17:12:09 +00:00
//no_render_flag[lcnt] = 1;
2014-11-23 21:53:45 +00:00
rstate . render_seg_map [ rstate . Render_list [ lcnt ] ] . processed = false ; //force reprocess
2014-08-12 02:28:03 +00:00
rstate . Render_list [ lcnt ] = segment_none ;
rstate . render_windows [ rp ] = * new_w ; //get updated window
2006-03-20 17:12:09 +00:00
goto no_add ;
}
}
else goto no_add ;
}
2014-08-12 02:28:03 +00:00
rstate . render_pos [ ch ] = lcnt ;
rstate . Render_list [ lcnt ] = ch ;
2014-11-23 21:53:45 +00:00
rstate . render_seg_map [ ch ] . Seg_depth = l ;
2006-03-20 17:12:09 +00:00
lcnt + + ;
2008-04-06 20:23:28 +00:00
if ( lcnt > = MAX_RENDER_SEGS ) { goto done_list ; }
2006-03-20 17:12:09 +00:00
visited [ ch ] = 1 ;
no_add :
;
}
}
}
}
}
scnt = ecnt ;
ecnt = lcnt ;
}
done_list :
lcnt_save = lcnt ;
scnt_save = scnt ;
first_terminal_seg = scnt ;
2014-09-07 23:39:38 +00:00
rstate . N_render_segs = lcnt ;
2006-03-20 17:12:09 +00:00
}
//renders onto current canvas
2013-12-29 04:28:07 +00:00
void render_mine ( segnum_t start_seg_num , fix eye_offset , int window_num )
2006-03-20 17:12:09 +00:00
{
int nn ;
2014-08-12 02:28:03 +00:00
render_state_t rstate ;
2006-03-20 17:12:09 +00:00
// Initialize number of objects (actually, robots!) rendered this frame.
2013-12-25 23:47:30 +00:00
Window_rendered_data [ window_num ] . rendered_robots . clear ( ) ;
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2014-10-02 03:02:34 +00:00
object_rendered = { } ;
2006-03-20 17:12:09 +00:00
# endif
//set up for rendering
render_start_frame ( ) ;
2012-12-02 18:57:09 +00:00
visited_twobit_array_t visited ;
2006-03-20 17:12:09 +00:00
2006-04-03 04:10:55 +00:00
# if defined(EDITOR)
2006-03-20 17:12:09 +00:00
if ( Show_only_curside ) {
2014-08-16 18:14:00 +00:00
rotate_list ( Cursegp - > verts ) ;
2006-03-20 17:12:09 +00:00
render_side ( Cursegp , Curside ) ;
goto done_rendering ;
}
# endif
# ifdef EDITOR
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( _search_mode | | eye_offset > 0 )
# elif defined(DXX_BUILD_DESCENT_II)
if ( _search_mode )
# endif
{
2006-03-20 17:12:09 +00:00
//lcnt = lcnt_save;
//scnt = scnt_save;
}
else
# endif
//NOTE LINK TO ABOVE!!
2014-08-12 02:28:03 +00:00
build_segment_list ( rstate , visited , start_seg_num , window_num ) ; //fills in Render_list & N_render_segs
2006-03-20 17:12:09 +00:00
//render away
# ifndef NDEBUG
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( ! ( _search_mode | | eye_offset > 0 ) )
# elif defined(DXX_BUILD_DESCENT_II)
if ( ! ( _search_mode ) )
# endif
{
2014-09-07 23:39:38 +00:00
for ( uint_fast32_t i = 0 ; i < rstate . N_render_segs ; i + + ) {
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ i ] ;
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none )
2006-03-20 17:12:09 +00:00
{
if ( visited2 [ segnum ] )
Int3 ( ) ; //get Matt
else
visited2 [ segnum ] = 1 ;
}
}
}
# endif
if ( ! ( _search_mode ) )
2014-09-07 23:39:38 +00:00
build_object_lists ( rstate ) ;
2006-03-20 17:12:09 +00:00
2013-04-18 09:56:18 +00:00
if ( eye_offset < = 0 ) // Do for left eye or zero.
2014-08-12 02:28:03 +00:00
set_dynamic_light ( rstate ) ;
2006-03-20 17:12:09 +00:00
if ( ! _search_mode & & Clear_window = = 2 ) {
2014-09-07 23:39:38 +00:00
if ( first_terminal_seg < rstate . N_render_segs ) {
2006-03-20 17:12:09 +00:00
if ( Clear_window_color = = - 1 )
Clear_window_color = BM_XRGB ( 0 , 0 , 0 ) ; //BM_XRGB(31, 15, 7);
gr_setcolor ( Clear_window_color ) ;
2014-09-07 23:39:38 +00:00
for ( uint_fast32_t i = first_terminal_seg ; i < rstate . N_render_segs ; i + + ) {
2014-08-12 02:28:03 +00:00
if ( rstate . Render_list [ i ] ! = segment_none ) {
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2014-08-12 02:28:03 +00:00
if ( ( rstate . render_windows [ i ] . left = = - 1 ) | | ( rstate . render_windows [ i ] . top = = - 1 ) | | ( rstate . render_windows [ i ] . right = = - 1 ) | | ( rstate . render_windows [ i ] . bot = = - 1 ) )
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
else
# endif
//NOTE LINK TO ABOVE!
2014-08-12 02:28:03 +00:00
gr_rect ( rstate . render_windows [ i ] . left , rstate . render_windows [ i ] . top , rstate . render_windows [ i ] . right , rstate . render_windows [ i ] . bot ) ;
2006-03-20 17:12:09 +00:00
}
}
}
}
2009-01-30 11:50:25 +00:00
# ifndef OGL
2014-09-07 23:39:38 +00:00
for ( nn = rstate . N_render_segs ; nn - - ; ) {
2006-03-20 17:12:09 +00:00
// Interpolation_method = 0;
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2014-11-23 21:53:45 +00:00
Current_seg_depth = rstate . render_seg_map [ segnum ] . Seg_depth ;
2006-03-20 17:12:09 +00:00
//if (!no_render_flag[nn])
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | visited [ segnum ] ! = 3 ) ) {
2006-03-20 17:12:09 +00:00
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-08-12 02:28:03 +00:00
Window_clip_left = rstate . render_windows [ nn ] . left ;
Window_clip_top = rstate . render_windows [ nn ] . top ;
Window_clip_right = rstate . render_windows [ nn ] . right ;
Window_clip_bot = rstate . render_windows [ nn ] . bot ;
2006-03-20 17:12:09 +00:00
}
render_segment ( segnum , window_num ) ;
2013-12-31 21:24:25 +00:00
visited [ segnum ] = 3 ;
2006-03-20 17:12:09 +00:00
2014-09-03 01:33:46 +00:00
{ //reset for objects
2006-03-20 17:12:09 +00:00
Window_clip_left = Window_clip_top = 0 ;
Window_clip_right = grd_curcanv - > cv_bitmap . bm_w - 1 ;
Window_clip_bot = grd_curcanv - > cv_bitmap . bm_h - 1 ;
}
2014-09-03 01:35:56 +00:00
{
2006-03-20 17:12:09 +00:00
//int n_expl_objs=0,expl_objs[5],i;
int save_linear_depth = Max_linear_depth ;
Max_linear_depth = Max_linear_depth_objects ;
2014-11-21 03:16:00 +00:00
range_for ( auto & v , rstate . render_seg_map [ segnum ] . objects )
{
do_render_object ( v . objnum , window_num ) ; // note link to above else
2006-03-20 17:12:09 +00:00
}
Max_linear_depth = save_linear_depth ;
}
}
}
2009-01-30 11:50:25 +00:00
# else
// Sorting elements for Alpha - 3 passes
// First Pass: render opaque level geometry + transculent level geometry with high Alpha-Test func
2014-09-07 23:39:38 +00:00
for ( nn = rstate . N_render_segs ; nn - - ; )
2009-01-30 11:50:25 +00:00
{
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2014-11-23 21:53:45 +00:00
Current_seg_depth = rstate . render_seg_map [ segnum ] . Seg_depth ;
2009-01-30 11:50:25 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | eye_offset > 0 | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# endif
2009-01-30 11:50:25 +00:00
{
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-08-12 02:28:03 +00:00
Window_clip_left = rstate . render_windows [ nn ] . left ;
Window_clip_top = rstate . render_windows [ nn ] . top ;
Window_clip_right = rstate . render_windows [ nn ] . right ;
Window_clip_bot = rstate . render_windows [ nn ] . bot ;
2009-01-30 11:50:25 +00:00
}
// render segment
{
segment * seg = & Segments [ segnum ] ;
int sn ;
2013-12-26 22:21:16 +00:00
Assert ( segnum ! = segment_none & & segnum < = Highest_segment_index ) ;
2014-08-16 18:14:11 +00:00
g3s_codes cc = rotate_list ( seg - > verts ) ;
2009-01-30 11:50:25 +00:00
2012-11-02 17:08:58 +00:00
if ( ! cc . uand ) { //all off screen?
2009-01-30 11:50:25 +00:00
if ( Viewer - > type ! = OBJ_ROBOT )
Automap_visited [ segnum ] = 1 ;
for ( sn = 0 ; sn < MAX_SIDES_PER_SEGMENT ; sn + + )
2014-09-02 22:15:07 +00:00
{
auto wid = WALL_IS_DOORWAY ( seg , sn ) ;
if ( wid = = WID_TRANSPARENT_WALL | | wid = = WID_TRANSILLUSORY_WALL
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-09-02 22:15:07 +00:00
| | ( wid & WID_CLOAKED_FLAG )
2013-03-03 01:03:33 +00:00
# endif
)
2009-01-30 11:50:25 +00:00
{
glAlphaFunc ( GL_GEQUAL , 0.8 ) ;
render_side ( seg , sn ) ;
glAlphaFunc ( GL_GEQUAL , 0.02 ) ;
}
else
render_side ( seg , sn ) ;
2014-09-02 22:15:07 +00:00
}
2009-01-30 11:50:25 +00:00
}
}
2013-12-31 21:24:25 +00:00
visited [ segnum ] = 3 ;
2009-01-30 11:50:25 +00:00
}
}
2012-12-02 18:57:09 +00:00
visited . clear ( ) ;
2009-01-30 11:50:25 +00:00
// Second Pass: Objects
2014-09-07 23:39:38 +00:00
for ( nn = rstate . N_render_segs ; nn - - ; )
2009-01-30 11:50:25 +00:00
{
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2014-11-23 21:53:45 +00:00
Current_seg_depth = rstate . render_seg_map [ segnum ] . Seg_depth ;
2009-01-30 11:50:25 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | eye_offset > 0 | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# endif
2009-01-30 11:50:25 +00:00
{
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-08-12 02:28:03 +00:00
Window_clip_left = rstate . render_windows [ nn ] . left ;
Window_clip_top = rstate . render_windows [ nn ] . top ;
Window_clip_right = rstate . render_windows [ nn ] . right ;
Window_clip_bot = rstate . render_windows [ nn ] . bot ;
2009-01-30 11:50:25 +00:00
}
2013-12-31 21:24:25 +00:00
visited [ segnum ] = 3 ;
2009-01-30 11:50:25 +00:00
2014-09-03 01:33:46 +00:00
{ //reset for objects
2009-01-30 11:50:25 +00:00
Window_clip_left = Window_clip_top = 0 ;
Window_clip_right = grd_curcanv - > cv_bitmap . bm_w - 1 ;
Window_clip_bot = grd_curcanv - > cv_bitmap . bm_h - 1 ;
}
// render objects
{
int save_linear_depth = Max_linear_depth ;
Max_linear_depth = Max_linear_depth_objects ;
2014-11-21 03:16:00 +00:00
range_for ( auto & v , rstate . render_seg_map [ segnum ] . objects )
2009-01-30 11:50:25 +00:00
{
2014-11-21 03:16:00 +00:00
do_render_object ( v . objnum , window_num ) ; // note link to above else
2009-01-30 11:50:25 +00:00
}
Max_linear_depth = save_linear_depth ;
}
}
}
2012-12-02 18:57:09 +00:00
visited . clear ( ) ;
2009-01-30 11:50:25 +00:00
// Third Pass - Render Transculent level geometry with normal Alpha-Func
2014-09-07 23:39:38 +00:00
for ( nn = rstate . N_render_segs ; nn - - ; )
2009-01-30 11:50:25 +00:00
{
2014-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ nn ] ;
2014-11-23 21:53:45 +00:00
Current_seg_depth = rstate . render_seg_map [ segnum ] . Seg_depth ;
2009-01-30 11:50:25 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | eye_offset > 0 | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none & & ( _search_mode | | visited [ segnum ] ! = 3 ) )
2013-03-03 01:03:33 +00:00
# endif
2009-01-30 11:50:25 +00:00
{
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-08-12 02:28:03 +00:00
Window_clip_left = rstate . render_windows [ nn ] . left ;
Window_clip_top = rstate . render_windows [ nn ] . top ;
Window_clip_right = rstate . render_windows [ nn ] . right ;
Window_clip_bot = rstate . render_windows [ nn ] . bot ;
2009-01-30 11:50:25 +00:00
}
// render segment
{
segment * seg = & Segments [ segnum ] ;
int sn ;
2013-12-26 22:21:16 +00:00
Assert ( segnum ! = segment_none & & segnum < = Highest_segment_index ) ;
2014-08-16 18:14:11 +00:00
g3s_codes cc = rotate_list ( seg - > verts ) ;
2009-01-30 11:50:25 +00:00
2012-11-02 17:08:58 +00:00
if ( ! cc . uand ) { //all off screen?
2009-01-30 11:50:25 +00:00
if ( Viewer - > type ! = OBJ_ROBOT )
Automap_visited [ segnum ] = 1 ;
for ( sn = 0 ; sn < MAX_SIDES_PER_SEGMENT ; sn + + )
2014-09-02 22:15:07 +00:00
{
auto wid = WALL_IS_DOORWAY ( seg , sn ) ;
if ( wid = = WID_TRANSPARENT_WALL | | wid = = WID_TRANSILLUSORY_WALL
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-09-02 22:15:07 +00:00
| | ( wid & WID_CLOAKED_FLAG )
2013-03-03 01:03:33 +00:00
# endif
)
2009-01-30 11:50:25 +00:00
render_side ( seg , sn ) ;
2014-09-02 22:15:07 +00:00
}
2009-01-30 11:50:25 +00:00
}
}
2013-12-31 21:24:25 +00:00
visited [ segnum ] = 3 ;
2009-01-30 11:50:25 +00:00
}
}
# endif
2006-03-20 17:12:09 +00:00
// -- commented out by mk on 09/14/94...did i do a good thing?? object_render_targets();
# ifdef EDITOR
# ifndef NDEBUG
//draw curedge stuff
if ( Outline_mode ) outline_seg_side ( Cursegp , Curside , Curedge , Curvert ) ;
# endif
done_rendering :
;
# endif
}
# ifdef EDITOR
//finds what segment is at a given x&y - seg,side,face are filled in
//works on last frame rendered. returns true if found
//if seg<0, then an object was found, and the object number is -seg-1
int find_seg_side_face ( short x , short y , int * seg , int * side , int * face , int * poly )
{
_search_mode = - 1 ;
_search_x = x ; _search_y = y ;
found_seg = - 1 ;
if ( render_3d_in_big_window ) {
2012-03-31 04:38:14 +00:00
gr_set_current_canvas ( LargeView . ev_canv ) ;
2006-03-20 17:12:09 +00:00
render_frame ( 0 , 0 ) ;
}
else {
2012-03-31 04:38:14 +00:00
gr_set_current_canvas ( Canv_editor_game ) ;
2006-03-20 17:12:09 +00:00
render_frame ( 0 , 0 ) ;
}
_search_mode = 0 ;
* seg = found_seg ;
* side = found_side ;
* face = found_face ;
* poly = found_poly ;
return ( found_seg ! = - 1 ) ;
}
# endif