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>
2014-11-30 17:03:00 +00:00
# include <cstdlib>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <string.h>
2011-02-14 21:27:07 +00:00
# include <math.h>
2015-08-03 03:11:25 +00:00
# include "render_state.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"
# 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
2014-09-20 23:47:27 +00:00
unsigned Max_linear_depth = 50 ; // Deepest segment at which linear interpolation will be used.
2015-04-22 02:44:29 +00:00
# endif
2008-04-06 20:23:28 +00:00
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
2014-12-13 17:47:01 +00:00
static int found_side , found_face , found_poly ;
static segnum_t found_seg ;
static objnum_t found_obj ;
2006-03-20 17:12:09 +00:00
# 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
2015-03-26 00:29:39 +00:00
# ifdef EDITOR
2015-04-30 03:32:27 +00:00
const int Show_only_curside = 0 ;
2015-03-26 00:29:39 +00:00
# endif
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 ) ) ;
2015-02-05 03:03:50 +00:00
flash_scale = fix_fastsin ( flash_ang ) ;
2006-03-20 17:12:09 +00:00
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 ) ;
2015-02-05 03:03:50 +00:00
flash_scale = fix_fastsin ( flash_ang ) ;
2006-03-20 17:12:09 +00:00
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.
2015-10-18 21:01:18 +00:00
static void render_face ( const vcsegptridx_t segp , 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 ] ] ;
}
2015-01-18 01:58:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2015-10-18 21:01:18 +00:00
( void ) segp ;
2015-01-18 01:58:33 +00:00
( void ) wid_flags ;
2015-10-18 21:01:18 +00:00
# ifndef EDITOR
( void ) sidenum ;
# endif
2015-01-18 01:58:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
//handle cloaked walls
if ( wid_flags & WID_CLOAKED_FLAG ) {
2015-10-18 21:01:18 +00:00
auto wall_num = segp - > sides [ sidenum ] . wall_num ;
2014-09-21 22:11:51 +00:00
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 ) {
Int3 ( ) ;
2015-10-18 21:01:18 +00:00
return ;
2006-03-20 17:12:09 +00:00
}
# 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 ) ) {
2014-11-30 22:09:19 +00:00
bm = & texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
2006-03-20 17:12:09 +00:00
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 ) {
2014-11-30 22:09:19 +00:00
bm = & texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
2006-03-20 17:12:09 +00:00
} 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
}
2015-08-21 03:12:35 +00:00
bool alpha = false ;
if ( PlayerCfg . AlphaBlendEClips & & 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)
{
alpha = true ;
2011-02-23 16:46:39 +00:00
gr_settransblend ( GR_FADE_OFF , GR_BLEND_ADDITIVE_C ) ;
2015-08-21 03:12:35 +00:00
}
2011-02-23 16:46:39 +00:00
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
2015-08-21 03:12:35 +00:00
if ( alpha )
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 ;
2015-01-18 01:58:33 +00:00
# ifdef OGL
( void ) tmap1 ;
( void ) tmap2 ;
# else
2006-03-20 17:12:09 +00:00
grs_bitmap * bm ;
if ( tmap2 > 0 )
2014-11-30 22:09:19 +00:00
bm = & texmerge_get_cached_bitmap ( tmap1 , tmap2 ) ;
2006-03-20 17:12:09 +00:00
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
2014-11-30 22:09:18 +00:00
if ( gr_ugpixel ( grd_curcanv - > cv_bitmap , _search_x , _search_y ) = = 1 ) {
2006-03-20 17:12:09 +00:00
found_seg = segnum ;
2014-12-13 17:47:01 +00:00
found_obj = object_none ;
2006-03-20 17:12:09 +00:00
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 >
2015-10-18 21:01:18 +00:00
static inline void check_render_face ( index_sequence < N . . . > , const vcsegptridx_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 >
2015-10-18 21:01:18 +00:00
static inline void check_render_face ( index_sequence < N0 , N1 , N2 , N3 > is , const vcsegptridx_t segnum , int sidenum , unsigned facenum , const array < int , 4 > & vp , int tmap1 , int tmap2 , const array < uvl , 4 > & uvlp , WALL_IS_DOORWAY_result_t wid_flags )
2014-09-13 22:05:52 +00:00
{
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 >
2015-10-18 21:01:18 +00:00
static inline void check_render_face ( index_sequence < N0 , N1 , N2 > , const vcsegptridx_t segnum , int sidenum , unsigned facenum , const array < int , 4 > & vp , int tmap1 , int tmap2 , const array < uvl , 4 > & uvlp , WALL_IS_DOORWAY_result_t wid_flags )
2014-09-13 22:05:52 +00:00
{
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-12-14 05:23:00 +00:00
const auto vertnum_list = get_side_verts ( 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 ) ;
2014-11-30 22:09:18 +00:00
if ( gr_ugpixel ( grd_curcanv - > cv_bitmap , _search_x , _search_y ) ! = 0 )
2006-03-20 17:12:09 +00:00
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 ) ;
2014-11-30 22:09:18 +00:00
if ( gr_ugpixel ( grd_curcanv - > cv_bitmap , _search_x , _search_y ) ! = 1 )
2006-03-20 17:12:09 +00:00
changed = 1 ;
if ( changed ) {
2013-12-26 22:21:16 +00:00
if ( obj - > segnum ! = segment_none )
2015-07-13 01:09:37 +00:00
Cursegp = segptridx ( obj - > segnum ) ;
2014-12-13 17:47:01 +00:00
found_seg = segment_none ;
found_obj = obj ;
2006-03-20 17:12:09 +00:00
}
}
# endif
2014-12-13 04:11:12 +00:00
static void do_render_object ( const vobjptridx_t obj , window_rendered_data & window )
2006-03-20 17:12:09 +00:00
{
# ifdef EDITOR
int save_3d_outline = 0 ;
# endif
int count = 0 ;
# 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 ) ) {
2014-12-13 04:11:12 +00:00
window . 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 ) ;
2015-10-18 21:01:19 +00:00
for ( auto n = obj - > attached_obj ; n ! = object_none ; )
{
const auto & & o = vobjptridx ( n ) ;
2014-12-23 04:20:27 +00:00
Assert ( o - > type = = OBJ_FIREBALL ) ;
Assert ( o - > control_type = = CT_EXPLOSION ) ;
Assert ( o - > flags & OF_ATTACHED ) ;
2015-10-18 21:01:19 +00:00
n = o - > ctype . expl_info . next_attach ;
2006-03-20 17:12:09 +00:00
2014-12-23 04:20:27 +00:00
render_object ( o ) ;
2006-03-20 17:12:09 +00:00
}
# 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
{
g3s_codes cc ;
2015-10-18 21:01:18 +00:00
const auto current_generation = s_current_generation ;
const auto cheats_acid = cheats . acid ;
float f = likely ( ! cheats_acid )
? 0.0f /* unused */
: 2.0f * ( static_cast < float > ( timer_query ( ) ) / F1_0 ) ;
2006-03-20 17:12:09 +00:00
2015-02-05 03:03:49 +00:00
range_for ( const auto pnum , unchecked_partial_range ( pointnumlist , nv ) )
2014-12-13 16:57:09 +00:00
{
2014-10-02 03:02:35 +00:00
auto & pnt = Segment_points [ pnum ] ;
2015-10-18 21:01:18 +00:00
if ( pnt . p3_last_generation ! = current_generation )
2011-02-14 21:27:07 +00:00
{
2015-10-18 21:01:18 +00:00
pnt . p3_last_generation = current_generation ;
const auto & v = Vertices [ pnum ] ;
vertex tmpv ;
g3_rotate_point ( pnt , likely ( ! cheats_acid ) ? v : (
tmpv = v ,
tmpv . x + = fl2f ( sinf ( f + f2fl ( tmpv . x ) ) ) ,
tmpv . y + = fl2f ( sinf ( f * 1.5f + f2fl ( tmpv . y ) ) ) ,
tmpv . z + = fl2f ( sinf ( f * 2.5f + f2fl ( tmpv . z ) ) ) ,
tmpv
) ) ;
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
{
2015-02-05 03:03:49 +00:00
range_for ( const auto pnum , pointnumlist )
2014-08-16 18:14:00 +00:00
{
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)
2015-07-21 02:57:27 +00:00
static void render_segment ( const vcsegptridx_t seg )
2006-03-20 17:12:09 +00:00
{
int sn ;
2015-10-18 21:01:18 +00:00
if ( ! rotate_list ( seg - > verts ) . 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
2015-07-21 02:57:27 +00:00
Automap_visited [ seg ] = 1 ;
2006-03-20 17:12:09 +00:00
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-08-18 00:11:51 +00:00
# ifdef EDITOR
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2015-03-26 02:42:26 +00:00
const fix CROSS_WIDTH = i2f ( 8 ) ;
const fix CROSS_HEIGHT = i2f ( 8 ) ;
2006-03-20 17:12:09 +00:00
//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
{
2015-10-18 21:01:18 +00:00
if ( ! rotate_list ( seg - > verts ) . 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
2014-11-23 21:53:46 +00:00
static ubyte code_window_point ( fix x , fix y , const rect & w )
2006-03-20 17:12:09 +00:00
{
ubyte code = 0 ;
2014-11-23 21:53:46 +00:00
if ( x < = w . left ) code | = 1 ;
if ( x > = w . right ) code | = 2 ;
2006-03-20 17:12:09 +00:00
2014-11-23 21:53:46 +00:00
if ( y < = w . top ) code | = 4 ;
if ( y > = w . bot ) code | = 8 ;
2006-03-20 17:12:09 +00:00
return code ;
}
# ifndef NDEBUG
2015-10-18 21:01:18 +00:00
static array < char , MAX_SEGMENTS > visited2 ;
2006-03-20 17:12:09 +00:00
# endif
2015-08-12 03:11:46 +00:00
namespace {
2012-12-02 18:57:09 +00:00
struct visited_twobit_array_t : visited_segment_multibit_array_t < 2 > { } ;
2015-08-12 03:11:46 +00:00
}
2006-03-20 17:12:09 +00:00
int lcnt_save , scnt_save ;
//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
2015-01-17 18:31:39 +00:00
__attribute_warn_unused_result
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 ;
}
}
2015-01-17 18:31:39 +00:00
__attribute_warn_unused_result
static bool compare_child ( const vcsegptridx_t seg , const vcsegptridx_t cseg , const sidenum_fast_t edgeside )
{
const auto & cside = cseg - > sides [ edgeside ] ;
const auto & sv = Side_to_verts [ edgeside ] [ cside . get_type ( ) = = SIDE_IS_TRI_13 ? 1 : 0 ] ;
const auto & temp = vm_vec_sub ( Viewer_eye , Vertices [ seg - > verts [ sv ] ] ) ;
const auto & cnormal = cseg - > sides [ edgeside ] . normals ;
return vm_vec_dot ( cnormal [ 0 ] , temp ) < 0 | | vm_vec_dot ( cnormal [ 1 ] , temp ) < 0 ;
}
//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
__attribute_warn_unused_result
static bool compare_children ( const vcsegptridx_t seg , sidenum_fast_t s0 , sidenum_fast_t 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
2015-01-17 18:31:39 +00:00
if ( Side_opposite [ s0 ] = = s1 )
return false ;
//find normals of adjoining sides
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 ) ) ;
2015-01-17 18:31:39 +00:00
if ( edgeside0 = = side_none )
return false ;
auto r0 = compare_child ( seg , seg0 , edgeside0 ) ;
if ( ! r0 )
return r0 ;
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 ) ) ;
2015-01-17 18:31:39 +00:00
if ( edgeside1 = = side_none )
2015-01-17 04:31:17 +00:00
return false ;
2015-01-17 18:31:39 +00:00
return ! compare_child ( seg , seg1 , edgeside1 ) ;
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
2015-01-17 04:31:17 +00:00
typedef array < sidenum_fast_t , MAX_SIDES_PER_SEGMENT > sort_child_array_t ;
static void sort_seg_children ( const vcsegptridx_t seg , const partial_range_t < sort_child_array_t : : iterator > & r )
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
2015-01-17 04:31:17 +00:00
auto predicate = [ seg ] ( sidenum_fast_t a , sidenum_fast_t b )
2014-09-08 03:31:05 +00:00
{
2015-01-17 04:31:17 +00:00
return compare_children ( seg , a , b ) ;
2014-09-08 03:31:05 +00:00
} ;
std : : sort ( r . begin ( ) , r . end ( ) , predicate ) ;
2006-03-20 17:12:09 +00:00
}
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
}
2015-01-24 19:16:34 +00:00
namespace {
class 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 ;
2015-01-24 19:16:34 +00:00
public :
2014-11-21 03:29:28 +00:00
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 )
{
2015-02-05 03:03:49 +00:00
range_for ( const auto t , segstate . objects )
2014-11-21 03:29:28 +00:00
{
2015-09-15 02:48:04 +00:00
const auto & & objp = vobjptr ( t . objnum ) ;
2014-11-21 03:29:28 +00:00
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
2015-01-24 19:16:34 +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 ) )
2015-03-22 18:49:21 +00:00
{
2006-03-20 17:12:09 +00:00
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
2015-03-22 18:49:21 +00:00
//both are weapons
}
2006-03-20 17:12:09 +00:00
else
2015-03-22 18:49:21 +00:00
{
2006-03-20 17:12:09 +00:00
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
2015-03-22 18:49:21 +00:00
}
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 ;
2015-10-18 21:01:19 +00:00
const auto viewer = Viewer ;
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 ) {
2015-02-05 03:03:49 +00:00
range_for ( const auto obj , objects_in ( Segments [ segnum ] ) )
2014-07-30 02:52:36 +00:00
{
2013-12-29 04:28:07 +00:00
int list_pos ;
2012-04-17 07:20:14 +00:00
if ( obj - > type = = OBJ_NONE )
2015-10-18 21:01:19 +00:00
{
assert ( obj - > type ! = OBJ_NONE ) ;
continue ;
}
if ( unlikely ( obj = = viewer ) & & likely ( obj - > attached_obj = = object_none ) )
2012-04-17 07:20:14 +00:00
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
2015-07-12 01:04:17 +00:00
m = get_seg_masks ( obj - > pos , vcsegptr ( new_segnum ) , obj - > size ) ;
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)
2015-07-12 01:04:21 +00:00
const auto & & seg = vcsegptr ( obj - > segnum ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2015-07-12 01:04:21 +00:00
const auto & & seg = vcsegptr ( 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
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , partial_range ( rstate . Render_list , rstate . N_render_segs ) )
2014-12-13 16:57:09 +00:00
{
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
2014-12-13 04:11:21 +00:00
void render_frame ( fix eye_offset , window_rendered_data & window )
2006-03-20 17:12:09 +00:00
{
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 )
2014-12-23 04:20:27 +00:00
newdemo_record_viewer_object ( vobjptridx ( Viewer ) ) ;
2006-03-20 17:12:09 +00:00
}
//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-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 ;
2015-02-05 03:03:51 +00:00
const auto & & headm = vm_angles_2_matrix ( 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
2014-12-13 04:11:21 +00:00
render_mine ( start_seg_num , eye_offset , window ) ;
2006-03-20 17:12:09 +00:00
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-12-13 16:57:09 +00:00
static unsigned 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-12-13 04:11:04 +00:00
void update_rendered_data ( window_rendered_data & window , const vobjptr_t viewer , int rear_view_flag )
2006-03-20 17:12:09 +00:00
{
2014-12-13 04:11:04 +00:00
window . time = timer_query ( ) ;
window . viewer = viewer ;
window . rear_view = rear_view_flag ;
2006-03-20 17:12:09 +00:00
}
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
2015-10-18 21:01:18 +00:00
static void build_segment_list ( render_state_t & rstate , visited_twobit_array_t & visited , segnum_t start_seg_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
2015-10-18 21:01:18 +00:00
visited2 = { } ;
2006-03-20 17:12:09 +00:00
# endif
lcnt = scnt = 0 ;
2014-08-12 02:28:03 +00:00
rstate . Render_list [ lcnt ] = start_seg_num ;
visited [ start_seg_num ] = 1 ;
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 ;
2014-12-11 02:33:50 +00:00
{
auto & rsm_start_seg = rstate . render_seg_map [ start_seg_num ] ;
2014-12-13 16:54:16 +00:00
auto & rw = rsm_start_seg . render_window ;
2014-12-11 02:33:50 +00:00
rw . left = rw . top = 0 ;
rw . right = grd_curcanv - > cv_bitmap . bm_w - 1 ;
rw . 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-11-20 03:00:36 +00:00
auto segnum = rstate . Render_list [ scnt ] ;
2015-10-18 21:01:19 +00:00
if ( unlikely ( segnum = = segment_none ) )
{
assert ( 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 ;
2014-12-13 16:54:16 +00:00
const auto & check_w = srsm . render_window ;
2014-11-23 21:53:45 +00:00
processed = true ;
2014-10-02 03:02:34 +00:00
auto seg = vsegptridx ( segnum ) ;
2015-10-18 21:01:18 +00:00
const auto uor = rotate_list ( seg - > verts ) . uor & CC_BEHIND ;
2006-03-20 17:12:09 +00:00
//look at all sides of this segment.
//tricky code to look at sides in correct order follows
2015-01-17 04:31:17 +00:00
sort_child_array_t child_list ; //list of ordered sides to process
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 )
{
2015-10-18 21:01:18 +00:00
if ( auto codes_and = uor )
2014-09-04 01:51:03 +00:00
{
2015-02-05 03:03:49 +00:00
range_for ( const auto i , Side_to_verts [ c ] )
2014-08-12 03:01:43 +00:00
codes_and & = Segment_points [ seg - > verts [ i ] ] . p3_codes ;
2015-10-18 21:01:18 +00:00
if ( codes_and )
continue ;
2006-03-20 17:12:09 +00:00
}
child_list [ n_children + + ] = c ;
}
}
2015-01-17 04:31:17 +00:00
if ( ! n_children )
continue ;
2006-03-20 17:12:09 +00:00
//now order the sides in some magical way
2015-01-17 04:31:17 +00:00
const auto child_range = partial_range ( child_list , n_children ) ;
sort_seg_children ( seg , child_range ) ;
project_list ( seg - > verts ) ;
2015-02-05 03:03:49 +00:00
range_for ( const auto siden , child_range )
2015-01-17 04:31:17 +00:00
{
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
{
2015-01-17 04:31:17 +00:00
short min_x = 32767 , max_x = - 32767 , min_y = 32767 , max_y = - 32767 ;
2006-03-20 17:12:09 +00:00
int no_proj_flag = 0 ; //a point wasn't projected
2015-01-17 04:31:17 +00:00
uint8_t codes_and_3d = 0xff , codes_and_2d = codes_and_3d ;
2015-02-05 03:03:49 +00:00
range_for ( const auto i , Side_to_verts [ siden ] )
2015-01-17 04:31:17 +00:00
{
g3s_point * pnt = & Segment_points [ seg - > verts [ i ] ] ;
2006-03-20 17:12:09 +00:00
if ( ! ( pnt - > p3_flags & PF_PROJECTED ) ) { no_proj_flag = 1 ; break ; }
2015-01-17 04:31:17 +00:00
const int16_t _x = f2i ( pnt - > p3_sx ) , _y = f2i ( pnt - > p3_sy ) ;
2006-03-20 17:12:09 +00:00
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 ;
2015-01-17 04:31:17 +00:00
codes_and_3d & = pnt - > p3_codes ;
codes_and_2d & = code_window_point ( _x , _y , check_w ) ;
2006-03-20 17:12:09 +00:00
}
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 ] ;
2014-12-11 02:33:55 +00:00
rect nw ;
2006-03-20 17:12:09 +00:00
2014-12-11 02:33:55 +00:00
if ( no_proj_flag )
nw = check_w ;
2006-03-20 17:12:09 +00:00
else {
2014-12-11 02:33:55 +00:00
nw . left = max ( check_w . left , min_x ) ;
nw . right = min ( check_w . right , max_x ) ;
nw . top = max ( check_w . top , min_y ) ;
nw . bot = min ( check_w . bot , max_y ) ;
2006-03-20 17:12:09 +00:00
}
//see if this seg already visited, and if so, does current window
//expand the old window?
if ( rp ! = - 1 ) {
2014-12-13 16:54:16 +00:00
auto & old_w = rstate . render_seg_map [ rstate . Render_list [ rp ] ] . render_window ;
2014-12-11 02:33:55 +00:00
if ( nw . left < old_w . left | |
nw . top < old_w . top | |
nw . right > old_w . right | |
nw . bot > old_w . bot ) {
2006-03-20 17:12:09 +00:00
2014-12-11 02:33:55 +00:00
nw . left = min ( nw . left , old_w . left ) ;
nw . right = max ( nw . right , old_w . right ) ;
nw . top = min ( nw . top , old_w . top ) ;
nw . bot = max ( nw . bot , old_w . 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-12-08 01:02:08 +00:00
rstate . render_seg_map [ ch ] . processed = false ; //force reprocess
2014-08-12 02:28:03 +00:00
rstate . Render_list [ lcnt ] = segment_none ;
2014-12-11 02:33:55 +00:00
old_w = nw ; //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-12-13 16:54:16 +00:00
{
auto & chrsm = rstate . render_seg_map [ ch ] ;
chrsm . Seg_depth = l ;
chrsm . render_window = nw ;
}
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
2014-12-13 04:11:16 +00:00
void render_mine ( segnum_t start_seg_num , fix eye_offset , window_rendered_data & window )
2006-03-20 17:12:09 +00:00
{
2014-12-13 17:19:28 +00:00
using std : : advance ;
2014-08-12 02:28:03 +00:00
render_state_t rstate ;
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 ) ;
2014-12-13 16:57:09 +00:00
return ;
2006-03-20 17:12:09 +00:00
}
# 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-12-13 04:11:04 +00:00
build_segment_list ( rstate , visited , start_seg_num ) ; //fills in Render_list & N_render_segs
2006-03-20 17:12:09 +00:00
2014-12-13 16:57:09 +00:00
const auto render_range = partial_range ( rstate . Render_list , rstate . N_render_segs ) ;
2015-05-22 03:33:21 +00:00
const auto & & reversed_render_range = render_range . reversed ( ) ;
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
{
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , render_range )
2014-12-13 16:57:09 +00:00
{
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
2014-12-13 17:19:28 +00:00
if ( reversed_render_range . empty ( ) )
/* Impossible, but later code has undefined behavior if this
* happens
*/
return ;
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 ) ;
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , partial_range ( rstate . Render_list , first_terminal_seg , rstate . N_render_segs ) )
2014-12-13 16:57:09 +00:00
{
if ( segnum ! = segment_none ) {
const auto & rw = rstate . render_seg_map [ segnum ] . render_window ;
2006-03-20 17:12:09 +00:00
# ifndef NDEBUG
2014-12-11 02:33:50 +00:00
if ( rw . left = = - 1 | | rw . top = = - 1 | | rw . right = = - 1 | | rw . bot = = - 1 )
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
else
# endif
//NOTE LINK TO ABOVE!
2014-12-11 02:33:50 +00:00
gr_rect ( rw . left , rw . top , rw . right , rw . bot ) ;
2006-03-20 17:12:09 +00:00
}
}
}
}
2009-01-30 11:50:25 +00:00
# ifndef OGL
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , reversed_render_range )
2014-12-13 16:57:09 +00:00
{
2006-03-20 17:12:09 +00:00
// Interpolation_method = 0;
2014-12-11 02:33:50 +00:00
auto & srsm = rstate . render_seg_map [ segnum ] ;
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-12-13 17:18:07 +00:00
Current_seg_depth = srsm . Seg_depth ;
2014-09-03 01:33:46 +00:00
{
2014-12-13 16:54:16 +00:00
const auto & rw = srsm . render_window ;
2014-12-11 02:33:50 +00:00
Window_clip_left = rw . left ;
Window_clip_top = rw . top ;
Window_clip_right = rw . right ;
Window_clip_bot = rw . bot ;
2006-03-20 17:12:09 +00:00
}
2015-07-21 02:57:27 +00:00
render_segment ( vcsegptridx ( segnum ) ) ;
2013-12-31 21:24:25 +00:00
visited [ segnum ] = 3 ;
2014-12-13 17:18:07 +00:00
if ( srsm . objects . empty ( ) )
continue ;
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;
2015-04-22 02:44:29 +00:00
const auto save_linear_depth = exchange ( Max_linear_depth , Max_linear_depth_objects ) ;
2014-12-11 02:33:50 +00:00
range_for ( auto & v , srsm . objects )
2014-11-21 03:16:00 +00:00
{
2014-12-13 04:11:16 +00:00
do_render_object ( v . objnum , window ) ; // 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
2014-12-13 17:19:28 +00:00
struct render_subrange : partial_range_t < std : : reverse_iterator < segnum_t * > >
{
iterator * m_pbegin ;
render_subrange ( iterator i ) :
partial_range_t < iterator > ( i , std : : prev ( i ) ) ,
m_pbegin ( & m_begin )
{
}
/* Prevent pointing m_pbegin at m_begin of different instance */
render_subrange ( const render_subrange & rhs ) = delete ;
render_subrange & operator = ( const render_subrange & rhs ) = delete ;
void record ( iterator p , iterator & dummy )
{
* m_pbegin = m_end = p ;
m_pbegin = & dummy ;
}
} ;
struct render_ranges
{
typedef render_subrange : : iterator iterator ;
iterator dummy_write_only_begin ;
render_subrange reversed_object_render_range , reversed_alpha_segment_render_range ;
render_ranges ( iterator e ) :
reversed_object_render_range ( e ) ,
reversed_alpha_segment_render_range ( e )
{
}
void record_object ( iterator p )
{
reversed_object_render_range . record ( p , dummy_write_only_begin ) ;
}
void record_alpha ( iterator p )
{
reversed_alpha_segment_render_range . record ( p , dummy_write_only_begin ) ;
}
} ;
/* Initially empty */
render_ranges rr { reversed_render_range . end ( ) } ;
2009-01-30 11:50:25 +00:00
// Sorting elements for Alpha - 3 passes
// First Pass: render opaque level geometry + transculent level geometry with high Alpha-Test func
2014-12-13 16:57:09 +00:00
for ( auto iter = reversed_render_range . begin ( ) ; iter ! = reversed_render_range . end ( ) ; + + iter )
2009-01-30 11:50:25 +00:00
{
2014-12-13 16:57:09 +00:00
const auto segnum = * iter ;
2014-12-11 02:33:50 +00:00
auto & srsm = rstate . render_seg_map [ segnum ] ;
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
{
2014-12-13 17:18:07 +00:00
Current_seg_depth = srsm . Seg_depth ;
2014-12-13 17:19:28 +00:00
if ( ! srsm . objects . empty ( ) )
rr . record_object ( iter ) ;
2009-01-30 11:50:25 +00:00
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-12-13 16:54:16 +00:00
const auto & rw = srsm . render_window ;
2014-12-11 02:33:50 +00:00
Window_clip_left = rw . left ;
Window_clip_top = rw . top ;
Window_clip_right = rw . right ;
Window_clip_bot = rw . bot ;
2009-01-30 11:50:25 +00:00
}
// render segment
{
2015-07-12 01:04:21 +00:00
const auto & & seg = vcsegptridx ( segnum ) ;
2009-01-30 11:50:25 +00:00
int sn ;
2013-12-26 22:21:16 +00:00
Assert ( segnum ! = segment_none & & segnum < = Highest_segment_index ) ;
2015-10-18 21:01:18 +00:00
if ( ! rotate_list ( seg - > verts ) . 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 ) ;
2014-12-13 17:19:28 +00:00
rr . record_alpha ( iter ) ;
2009-01-30 11:50:25 +00:00
}
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-12-13 17:19:28 +00:00
advance ( rr . reversed_object_render_range . m_end , 1 ) ;
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , rr . reversed_object_render_range )
2009-01-30 11:50:25 +00:00
{
2014-12-11 02:33:50 +00:00
auto & srsm = rstate . render_seg_map [ segnum ] ;
2014-12-13 17:18:07 +00:00
if ( srsm . objects . empty ( ) )
continue ;
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
{
2014-12-13 17:18:07 +00:00
Current_seg_depth = srsm . Seg_depth ;
2009-01-30 11:50:25 +00:00
//set global render window vars
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
{
2014-12-13 17:18:07 +00:00
range_for ( auto & v , srsm . objects )
2009-01-30 11:50:25 +00:00
{
2014-12-13 04:11:16 +00:00
do_render_object ( v . objnum , window ) ; // note link to above else
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
// Third Pass - Render Transculent level geometry with normal Alpha-Func
2014-12-13 17:19:28 +00:00
advance ( rr . reversed_alpha_segment_render_range . m_end , 1 ) ;
2015-02-05 03:03:49 +00:00
range_for ( const auto segnum , rr . reversed_alpha_segment_render_range )
2009-01-30 11:50:25 +00:00
{
2014-12-11 02:33:50 +00:00
auto & srsm = rstate . render_seg_map [ segnum ] ;
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
{
2014-12-13 17:18:07 +00:00
Current_seg_depth = srsm . Seg_depth ;
2009-01-30 11:50:25 +00:00
//set global render window vars
2014-09-03 01:33:46 +00:00
{
2014-12-13 16:54:16 +00:00
const auto & rw = srsm . render_window ;
2014-12-11 02:33:50 +00:00
Window_clip_left = rw . left ;
Window_clip_top = rw . top ;
Window_clip_right = rw . right ;
Window_clip_bot = rw . bot ;
2009-01-30 11:50:25 +00:00
}
// render segment
{
2015-07-12 01:04:21 +00:00
const auto & & seg = vcsegptridx ( segnum ) ;
2009-01-30 11:50:25 +00:00
int sn ;
2013-12-26 22:21:16 +00:00
Assert ( segnum ! = segment_none & & segnum < = Highest_segment_index ) ;
2015-10-18 21:01:18 +00:00
if ( ! rotate_list ( seg - > verts ) . uand )
{ //all off screen?
2009-01-30 11:50:25 +00:00
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
# 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
2014-12-13 17:47:01 +00:00
int find_seg_side_face ( short x , short y , segnum_t & seg , objnum_t & obj , int & side , int & face , int & poly )
2006-03-20 17:12:09 +00:00
{
_search_mode = - 1 ;
_search_x = x ; _search_y = y ;
2014-12-13 17:47:01 +00:00
found_seg = segment_none ;
found_obj = object_none ;
2006-03-20 17:12:09 +00:00
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
}
else {
2012-03-31 04:38:14 +00:00
gr_set_current_canvas ( Canv_editor_game ) ;
2006-03-20 17:12:09 +00:00
}
2014-12-18 04:12:38 +00:00
render_frame ( 0 ) ;
2006-03-20 17:12:09 +00:00
_search_mode = 0 ;
2014-12-13 17:47:01 +00:00
seg = found_seg ;
obj = found_obj ;
side = found_side ;
face = found_face ;
poly = found_poly ;
return found_seg ! = segment_none | | found_obj ! = object_none ;
2006-03-20 17:12:09 +00:00
}
# endif