mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-30 07:31:13 +00:00
fb86222fc7
tweaked shadowmaps. now seems faster than stencil shadows. cubemap orientation should now match other engines. tweaked terrain. rtlights work. added pvs tests for embedded terrain. sections are now saved in chunks instead, which should mean windows doesn't have a panic attack at 16 million files in a single directory. hurrah. first pass at realigning menu options to cope with variable-width fonts. still need to do pure-text items. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4514 fc73d0e0-1445-4013-8a0c-d673dee63da5
2463 lines
73 KiB
C
2463 lines
73 KiB
C
#include "quakedef.h"
|
|
#include "winquake.h"
|
|
#include "pr_common.h"
|
|
#include "gl_draw.h"
|
|
#include "shader.h"
|
|
#include "glquake.h"
|
|
#include <string.h>
|
|
|
|
|
|
refdef_t r_refdef;
|
|
vec3_t r_origin, vpn, vright, vup;
|
|
entity_t r_worldentity;
|
|
entity_t *currententity; //nnggh
|
|
int r_framecount;
|
|
struct texture_s *r_notexture_mip;
|
|
|
|
r_config_t r_config;
|
|
|
|
qboolean r_blockvidrestart;
|
|
int r_regsequence;
|
|
|
|
int rspeeds[RSPEED_MAX];
|
|
int rquant[RQUANT_MAX];
|
|
|
|
void R_InitParticleTexture (void);
|
|
|
|
qboolean vid_isfullscreen;
|
|
|
|
#define VIDCOMMANDGROUP "Video config"
|
|
#define GRAPHICALNICETIES "Graphical Nicaties" //or eyecandy, which ever you prefer.
|
|
#define GLRENDEREROPTIONS "GL Renderer Options"
|
|
#define SCREENOPTIONS "Screen Options"
|
|
|
|
unsigned int d_8to24rgbtable[256];
|
|
|
|
extern int gl_anisotropy_factor;
|
|
|
|
// callbacks used for cvars
|
|
void SCR_Viewsize_Callback (struct cvar_s *var, char *oldvalue);
|
|
void SCR_Fov_Callback (struct cvar_s *var, char *oldvalue);
|
|
#if defined(GLQUAKE)
|
|
void GL_Mipcap_Callback (struct cvar_s *var, char *oldvalue);
|
|
void GL_Texturemode_Callback (struct cvar_s *var, char *oldvalue);
|
|
void GL_Texturemode2d_Callback (struct cvar_s *var, char *oldvalue);
|
|
void GL_Texture_Anisotropic_Filtering_Callback (struct cvar_s *var, char *oldvalue);
|
|
#endif
|
|
|
|
cvar_t _vid_wait_override = CVARAF ("vid_wait", "0",
|
|
"_vid_wait_override", CVAR_ARCHIVE);
|
|
|
|
cvar_t _windowed_mouse = CVARF ("_windowed_mouse","1",
|
|
CVAR_ARCHIVE);
|
|
|
|
cvar_t con_ocranaleds = CVAR ("con_ocranaleds", "2");
|
|
|
|
cvar_t cl_cursor = CVAR ("cl_cursor", "");
|
|
cvar_t cl_cursorsize = CVAR ("cl_cursorsize", "32");
|
|
cvar_t cl_cursorbias = CVAR ("cl_cursorbias", "4");
|
|
|
|
cvar_t gl_nocolors = CVARF ("gl_nocolors", "0", CVAR_ARCHIVE);
|
|
cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable particle emitting from models. Mainly used for torch and flame effects.");
|
|
|
|
//opengl library, blank means try default.
|
|
static cvar_t gl_driver = CVARF ("gl_driver", "",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t gl_shadeq1_name = CVAR ("gl_shadeq1_name", "*");
|
|
extern cvar_t r_vertexlight;
|
|
|
|
cvar_t mod_md3flags = CVAR ("mod_md3flags", "1");
|
|
|
|
cvar_t r_ambient = CVARF ("r_ambient", "0",
|
|
CVAR_CHEAT);
|
|
cvar_t r_bloodstains = CVARF ("r_bloodstains", "1", CVAR_ARCHIVE);
|
|
cvar_t r_bouncysparks = CVARFD ("r_bouncysparks", "0",
|
|
CVAR_ARCHIVE,
|
|
"Enables particle interaction with world surfaces, allowing for bouncy particles.");
|
|
cvar_t r_drawentities = CVAR ("r_drawentities", "1");
|
|
cvar_t r_drawflat = CVARF ("r_drawflat", "0",
|
|
CVAR_ARCHIVE | CVAR_SEMICHEAT | CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
|
|
cvar_t r_wireframe = CVARF ("r_wireframe", "0",
|
|
CVAR_CHEAT);
|
|
cvar_t r_refract_fbo = CVARD ("r_refract_fbo", "1", "Use an fbo for refraction. If 0, just renders as a portal and uses a copy of the current framebuffer.");
|
|
cvar_t gl_miptexLevel = CVAR ("gl_miptexLevel", "0");
|
|
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
|
|
cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0");
|
|
cvar_t r_dynamic = CVARF ("r_dynamic", IFMINIMAL("0","1"),
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_fastturb = CVARF ("r_fastturb", "0",
|
|
CVAR_SHADERSYSTEM);
|
|
cvar_t r_fastsky = CVARF ("r_fastsky", "0",
|
|
CVAR_ARCHIVE | CVAR_SHADERSYSTEM);
|
|
cvar_t r_fastskycolour = CVARF ("r_fastskycolour", "0",
|
|
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
|
|
cvar_t r_fb_bmodels = CVARAF("r_fb_bmodels", "1",
|
|
"gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH);
|
|
cvar_t r_fb_models = CVARAF ("r_fb_models", "1",
|
|
"gl_fb_models", CVAR_SEMICHEAT);
|
|
cvar_t r_skin_overlays = SCVARF ("r_skin_overlays", "1",
|
|
CVAR_SEMICHEAT|CVAR_RENDERERLATCH);
|
|
cvar_t r_coronas = SCVARF ("r_coronas", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_flashblend = SCVARF ("gl_flashblend", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_flashblendscale = SCVARF ("gl_flashblendscale", "0.35",
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_floorcolour = CVARAF ("r_floorcolour", "64 64 128",
|
|
"r_floorcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
|
|
cvar_t r_floortexture = SCVARF ("r_floortexture", "",
|
|
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
|
|
cvar_t r_fullbright = SCVARF ("r_fullbright", "0",
|
|
CVAR_CHEAT|CVAR_SHADERSYSTEM);
|
|
cvar_t r_fullbrightSkins = SCVARF ("r_fullbrightSkins", "0.8", /*don't default to 1, as it looks a little ugly (too bright), but don't default to 0 either because then you're handicapped in the dark*/
|
|
CVAR_SEMICHEAT|CVAR_SHADERSYSTEM);
|
|
cvar_t r_lightmap_saturation = SCVAR ("r_lightmap_saturation", "1");
|
|
cvar_t r_lightstylesmooth = CVARF ("r_lightstylesmooth", "0", CVAR_ARCHIVE);
|
|
cvar_t r_lightstylesmooth_limit = SCVAR ("r_lightstylesmooth_limit", "2");
|
|
cvar_t r_lightstylespeed = SCVAR ("r_lightstylespeed", "10");
|
|
cvar_t r_loadlits = CVARF ("r_loadlit", "1", CVAR_ARCHIVE);
|
|
cvar_t r_menutint = SCVARF ("r_menutint", "0.68 0.4 0.13",
|
|
CVAR_RENDERERCALLBACK);
|
|
cvar_t r_netgraph = SCVAR ("r_netgraph", "0");
|
|
cvar_t r_nolerp = CVARF ("r_nolerp", "0", CVAR_ARCHIVE);
|
|
cvar_t r_noframegrouplerp = CVARF ("r_noframegrouplerp", "0", CVAR_ARCHIVE);
|
|
cvar_t r_nolightdir = CVARF ("r_nolightdir", "0", CVAR_ARCHIVE);
|
|
cvar_t r_novis = CVARF ("r_novis", "0", CVAR_ARCHIVE);
|
|
cvar_t r_part_rain = CVARFD ("r_part_rain", "0",
|
|
CVAR_ARCHIVE,
|
|
"Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects.");
|
|
cvar_t r_skyboxname = SCVARF ("r_skybox", "",
|
|
CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
|
|
cvar_t r_speeds = SCVAR ("r_speeds", "0");
|
|
cvar_t r_stainfadeammount = SCVAR ("r_stainfadeammount", "1");
|
|
cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1");
|
|
cvar_t r_stains = CVARFC("r_stains", IFMINIMAL("0","0.75"),
|
|
CVAR_ARCHIVE,
|
|
Cvar_Limiter_ZeroToOne_Callback);
|
|
cvar_t r_postprocshader = CVARD("r_postprocshader", "", "Specifies a shader to use as a post-processing shader");
|
|
cvar_t r_wallcolour = CVARAF ("r_wallcolour", "128 128 128",
|
|
"r_wallcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);//FIXME: broken
|
|
cvar_t r_walltexture = CVARF ("r_walltexture", "",
|
|
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); //FIXME: broken
|
|
cvar_t r_wateralpha = CVARF ("r_wateralpha", "1",
|
|
CVAR_ARCHIVE | CVAR_SHADERSYSTEM);
|
|
cvar_t r_waterwarp = CVARF ("r_waterwarp", "1",
|
|
CVAR_ARCHIVE);
|
|
|
|
cvar_t r_replacemodels = CVARF ("r_replacemodels", IFMINIMAL("","md3 md2"),
|
|
CVAR_ARCHIVE);
|
|
|
|
//otherwise it would defeat the point.
|
|
cvar_t scr_allowsnap = CVARF ("scr_allowsnap", "1",
|
|
CVAR_NOTFROMSERVER);
|
|
cvar_t scr_centersbar = CVAR ("scr_centersbar", "2");
|
|
cvar_t scr_centertime = CVAR ("scr_centertime", "2");
|
|
cvar_t scr_chatmodecvar = CVAR ("scr_chatmode", "0");
|
|
cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7",
|
|
Cvar_Limiter_ZeroToOne_Callback);
|
|
cvar_t scr_consize = CVAR ("scr_consize", "0.5");
|
|
cvar_t scr_conspeed = CVAR ("scr_conspeed", "300");
|
|
// 10 - 170
|
|
cvar_t scr_fov = CVARFC("fov", "90",
|
|
CVAR_ARCHIVE,
|
|
SCR_Fov_Callback);
|
|
cvar_t scr_printspeed = SCVAR ("scr_printspeed", "8");
|
|
cvar_t scr_showpause = SCVAR ("showpause", "1");
|
|
cvar_t scr_showturtle = SCVAR ("showturtle", "0");
|
|
cvar_t scr_turtlefps = SCVAR ("scr_turtlefps", "10");
|
|
cvar_t scr_sshot_compression = SCVAR ("scr_sshot_compression", "75");
|
|
cvar_t scr_sshot_type = SCVAR ("scr_sshot_type", "jpg");
|
|
cvar_t scr_viewsize = CVARFC("viewsize", "100",
|
|
CVAR_ARCHIVE,
|
|
SCR_Viewsize_Callback);
|
|
|
|
#ifdef ANDROID
|
|
cvar_t vid_conautoscale = CVARF ("vid_conautoscale", "2",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK);
|
|
#else
|
|
cvar_t vid_conautoscale = CVARFD ("vid_conautoscale", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, "Changes the 2d scale, including hud, console, and fonts. To specify an explicit font size, divide the desired 'point' size by 8 to get the scale. High values will be clamped to maintain at least a 320*200 virtual size.");
|
|
#endif
|
|
cvar_t vid_conheight = CVARF ("vid_conheight", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t vid_conwidth = CVARF ("vid_conwidth", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK);
|
|
//see R_RestartRenderer_f for the effective default 'if (newr.renderer == -1)'.
|
|
cvar_t vid_renderer = CVARF ("vid_renderer", "",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
|
|
cvar_t vid_bpp = CVARF ("vid_bpp", "32",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t vid_desktopsettings = CVARF ("vid_desktopsettings", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
#ifdef NACL
|
|
cvar_t vid_fullscreen = CVARF ("vid_fullscreen", "0",
|
|
CVAR_ARCHIVE);
|
|
#else
|
|
//these cvars will be given their names when they're registered, based upon whether -plugin was used. this means code can always use vid_fullscreen without caring, but gets saved properly.
|
|
cvar_t vid_fullscreen = CVARAF (NULL, "1", "vid_fullscreen",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t vid_fullscreen_alternative = CVARF (NULL, "1",
|
|
CVAR_ARCHIVE);
|
|
#endif
|
|
cvar_t vid_height = CVARF ("vid_height", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t vid_multisample = CVARF ("vid_multisample", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t vid_refreshrate = CVARF ("vid_displayfrequency", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t vid_wndalpha = CVAR ("vid_wndalpha", "1");
|
|
//more readable defaults to match conwidth/conheight.
|
|
cvar_t vid_width = CVARF ("vid_width", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
|
|
cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context.");
|
|
cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain.");
|
|
|
|
extern cvar_t r_dodgytgafiles;
|
|
extern cvar_t r_dodgypcxfiles;
|
|
extern cvar_t r_drawentities;
|
|
extern cvar_t r_drawviewmodel;
|
|
extern cvar_t r_drawworld;
|
|
extern cvar_t r_fullbright;
|
|
cvar_t r_mirroralpha = SCVARF("r_mirroralpha","1", CVAR_CHEAT|CVAR_SHADERSYSTEM);
|
|
extern cvar_t r_netgraph;
|
|
extern cvar_t r_norefresh;
|
|
extern cvar_t r_novis;
|
|
extern cvar_t r_speeds;
|
|
extern cvar_t r_waterwarp;
|
|
|
|
#ifdef ANDROID
|
|
//on android, these numbers seem to be generating major weirdness, so disable these.
|
|
cvar_t r_polygonoffset_submodel_factor = SCVAR("r_polygonoffset_submodel_factor", "0");
|
|
cvar_t r_polygonoffset_submodel_offset = SCVAR("r_polygonoffset_submodel_offset", "0");
|
|
#else
|
|
cvar_t r_polygonoffset_submodel_factor = SCVAR("r_polygonoffset_submodel_factor", "0.05");
|
|
cvar_t r_polygonoffset_submodel_offset = SCVAR("r_polygonoffset_submodel_offset", "25");
|
|
#endif
|
|
|
|
cvar_t r_polygonoffset_stencil_factor = SCVAR("r_polygonoffset_stencil_factor", "0.01");
|
|
cvar_t r_polygonoffset_stencil_offset = SCVAR("r_polygonoffset_stencil_offset", "1");
|
|
|
|
rendererstate_t currentrendererstate;
|
|
|
|
#if defined(GLQUAKE)
|
|
cvar_t gl_workaround_ati_shadersource = CVARD ("gl_workaround_ati_shadersource", "1", "Work around ATI driver bugs in the glShaderSource function. Can safely be enabled with other drivers too.");
|
|
cvar_t vid_gl_context_version = SCVAR ("vid_gl_context_version", "");
|
|
cvar_t vid_gl_context_forwardcompatible = SCVAR ("vid_gl_context_forwardcompatible", "0");
|
|
cvar_t vid_gl_context_compatibility = SCVAR ("vid_gl_context_compatibility", "1");
|
|
cvar_t vid_gl_context_debug = SCVAR ("vid_gl_context_debug", "0"); //for my ati drivers, debug 1 only works if version >= 3
|
|
cvar_t vid_gl_context_es2 = SCVAR ("vid_gl_context_es2", "0"); //requires version set correctly, no debug, no compat
|
|
#endif
|
|
|
|
#if defined(GLQUAKE) || defined(D3DQUAKE)
|
|
cvar_t gl_ati_truform = CVAR ("gl_ati_truform", "0");
|
|
cvar_t gl_ati_truform_type = CVAR ("gl_ati_truform_type", "1");
|
|
cvar_t gl_ati_truform_tesselation = CVAR ("gl_ati_truform_tesselation", "3");
|
|
cvar_t gl_blend2d = CVAR ("gl_blend2d", "1");
|
|
cvar_t gl_blendsprites = CVAR ("gl_blendsprites", "0");
|
|
cvar_t r_deluxemapping = CVARAF ("r_deluxemapping", "0", "r_glsl_deluxemapping",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH);
|
|
cvar_t gl_compress = CVARF ("gl_compress", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t gl_conback = CVARFC ("gl_conback", "",
|
|
CVAR_RENDERERCALLBACK, R2D_Conback_Callback);
|
|
cvar_t gl_detail = CVARF ("gl_detail", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t gl_detailscale = CVAR ("gl_detailscale", "5");
|
|
cvar_t gl_font = CVARFD ("gl_font", "",
|
|
CVAR_RENDERERCALLBACK, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n"
|
|
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n"
|
|
"TTF fonts may be loaded from your windows directory. \'gl_font cour:couri\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text."
|
|
));
|
|
cvar_t gl_lateswap = CVAR ("gl_lateswap", "0");
|
|
cvar_t gl_lerpimages = CVARF ("gl_lerpimages", "1", CVAR_ARCHIVE);
|
|
//cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "",
|
|
// CVAR_ARCHIVE);
|
|
cvar_t gl_load24bit = SCVARF ("gl_load24bit", "1",
|
|
CVAR_ARCHIVE);
|
|
|
|
cvar_t r_clear = CVARAF("r_clear","0",
|
|
"gl_clear", 0);
|
|
cvar_t gl_max_size = SCVARF ("gl_max_size", "2048", CVAR_RENDERERLATCH);
|
|
cvar_t gl_maxshadowlights = SCVARF ("gl_maxshadowlights", "2",
|
|
CVAR_ARCHIVE);
|
|
cvar_t gl_menutint_shader = SCVAR ("gl_menutint_shader", "1");
|
|
|
|
//by setting to 64 or something, you can use this as a wallhack
|
|
cvar_t gl_mindist = SCVARF ("gl_mindist", "4",
|
|
CVAR_CHEAT);
|
|
|
|
cvar_t gl_motionblur = SCVARF ("gl_motionblur", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t gl_motionblurscale = SCVAR ("gl_motionblurscale", "1");
|
|
cvar_t gl_overbright = CVARFC ("gl_overbright", "1",
|
|
CVAR_ARCHIVE,
|
|
Surf_RebuildLightmap_Callback);
|
|
cvar_t gl_overbright_all = SCVARF ("gl_overbright_all", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t gl_picmip = CVARF ("gl_picmip", "0", CVAR_ARCHIVE);
|
|
cvar_t gl_picmip2d = CVARF ("gl_picmip2d", "0", CVAR_ARCHIVE);
|
|
cvar_t gl_nohwblend = SCVAR ("gl_nohwblend","1");
|
|
cvar_t gl_savecompressedtex = SCVAR ("gl_savecompressedtex", "0");
|
|
cvar_t gl_schematics = SCVAR ("gl_schematics", "0");
|
|
cvar_t gl_skyboxdist = SCVAR ("gl_skyboxdist", "0"); //0 = guess.
|
|
cvar_t gl_smoothcrosshair = SCVAR ("gl_smoothcrosshair", "1");
|
|
cvar_t gl_maxdist = SCVAR("gl_maxdist", "8192");
|
|
|
|
#ifdef SPECULAR
|
|
cvar_t gl_specular = CVARF ("gl_specular", "1", CVAR_ARCHIVE);
|
|
cvar_t gl_specular_fallback = CVARF ("gl_specular_fallback", "0.05", CVAR_ARCHIVE|CVAR_RENDERERLATCH);
|
|
#endif
|
|
|
|
// The callbacks are not in D3D yet (also ugly way of seperating this)
|
|
#ifdef GLQUAKE
|
|
cvar_t gl_texture_anisotropic_filtering = CVARFC("gl_texture_anisotropic_filtering", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
|
|
GL_Texture_Anisotropic_Filtering_Callback);
|
|
cvar_t gl_texturemode = CVARFC("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
|
|
GL_Texturemode_Callback);
|
|
cvar_t gl_mipcap = CVARFC("d_mipcap", "0 1000",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
|
|
GL_Mipcap_Callback);
|
|
cvar_t gl_texturemode2d = CVARFC("gl_texturemode2d", "GL_LINEAR",
|
|
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
|
|
GL_Texturemode2d_Callback);
|
|
#endif
|
|
|
|
cvar_t vid_triplebuffer = CVARAF ("vid_triplebuffer", "1",
|
|
"gl_triplebuffer", CVAR_ARCHIVE);
|
|
|
|
cvar_t r_noportals = SCVAR ("r_noportals", "0");
|
|
cvar_t dpcompat_psa_ungroup = SCVAR ("dpcompat_psa_ungroup", "0");
|
|
cvar_t r_noaliasshadows = SCVARF ("r_noaliasshadows", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_shadows = SCVARF ("r_shadows", "0",
|
|
CVAR_ARCHIVE);
|
|
cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground.");
|
|
cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism.");
|
|
|
|
cvar_t r_shadow_bumpscale_basetexture = SCVAR ("r_shadow_bumpscale_basetexture", "4");
|
|
cvar_t r_shadow_bumpscale_bumpmap = SCVAR ("r_shadow_bumpscale_bumpmap", "10");
|
|
|
|
cvar_t r_glsl_offsetmapping = CVARF ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM);
|
|
cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04");
|
|
cvar_t r_glsl_offsetmapping_reliefmapping = CVARF("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM);
|
|
cvar_t r_glsl_turbscale = CVARF ("r_glsl_turbscale", "1", CVAR_ARCHIVE);
|
|
|
|
cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections");
|
|
cvar_t r_slimestyle = CVARFD ("r_slimestyle", "", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only slime. If empty, defers to r_waterstyle.");
|
|
cvar_t r_lavastyle = CVARFD ("r_lavastyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle.");
|
|
|
|
cvar_t r_vertexdlights = SCVAR ("r_vertexdlights", "0");
|
|
|
|
cvar_t vid_preservegamma = SCVAR ("vid_preservegamma", "0");
|
|
cvar_t vid_hardwaregamma = CVARFD ("vid_hardwaregamma", "1",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=loadtime-gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma.");
|
|
cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0",
|
|
CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Apply gamma ramps upon the desktop rather than the window.");
|
|
|
|
cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces) is typically more realistic, while 1 (matching FitzQuake and others) is more common.");
|
|
|
|
extern cvar_t gl_dither;
|
|
cvar_t gl_screenangle = SCVAR("gl_screenangle", "0");
|
|
|
|
#endif
|
|
|
|
#if defined(GLQUAKE) || defined(D3DQUAKE)
|
|
void GLD3DRenderer_Init(void)
|
|
{
|
|
Cvar_Register (&gl_mindist, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_load24bit, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_blendsprites, GLRENDEREROPTIONS);
|
|
}
|
|
#endif
|
|
|
|
#if defined(GLQUAKE)
|
|
void GLRenderer_Init(void)
|
|
{
|
|
//gl-specific video vars
|
|
Cvar_Register (&gl_workaround_ati_shadersource, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_gl_context_version, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_gl_context_debug, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_gl_context_forwardcompatible, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_gl_context_compatibility, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_gl_context_es2, GLRENDEREROPTIONS);
|
|
|
|
//screen
|
|
Cvar_Register (&vid_preservegamma, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_hardwaregamma, GLRENDEREROPTIONS);
|
|
Cvar_Register (&vid_desktopgamma, GLRENDEREROPTIONS);
|
|
|
|
//renderer
|
|
Cvar_Register (&r_norefresh, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_affinemodels, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_nohwblend, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_nocolors, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_finish, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_lateswap, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_lerpimages, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_postprocshader, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&dpcompat_psa_ungroup, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_noframegrouplerp, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_noportals, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_noaliasshadows, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_maxshadowlights, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_reporttjunctions, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_motionblur, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_motionblurscale, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_deluxemapping, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_glsl_offsetmapping, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_glsl_offsetmapping_scale, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_glsl_offsetmapping_reliefmapping, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_glsl_turbscale, GRAPHICALNICETIES);
|
|
|
|
|
|
#ifdef R_XFLIP
|
|
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
|
|
#endif
|
|
Cvar_Register (&gl_specular, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_specular_fallback, GRAPHICALNICETIES);
|
|
|
|
// Cvar_Register (&gl_lightmapmode, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_picmip, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_picmip2d, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_mipcap, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_texturemode, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_texturemode2d, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_savecompressedtex, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_compress, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_detail, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_detailscale, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_overbright, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_overbright_all, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_dither, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_fog_exp2, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_ati_truform, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_ati_truform_type, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_ati_truform_tesselation, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&gl_screenangle, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_skyboxdist, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&r_wallcolour, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_floorcolour, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_walltexture, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_floortexture, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&r_vertexdlights, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_schematics, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&r_vertexlight, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_blend2d, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&gl_menutint_shader, GLRENDEREROPTIONS);
|
|
|
|
R_BloomRegister();
|
|
}
|
|
#endif
|
|
|
|
void R_InitTextures (void)
|
|
{
|
|
int x,y, m;
|
|
qbyte *dest;
|
|
static char r_notexture_mip_mem[(sizeof(texture_t) + 16*16+8*8+4*4+2*2)];
|
|
|
|
// create a simple checkerboard texture for the default
|
|
r_notexture_mip = (texture_t*)r_notexture_mip_mem;
|
|
|
|
r_notexture_mip->width = r_notexture_mip->height = 16;
|
|
r_notexture_mip->offsets[0] = sizeof(texture_t);
|
|
r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
|
|
r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
|
|
r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
|
|
|
|
for (m=0 ; m<4 ; m++)
|
|
{
|
|
dest = (qbyte *)r_notexture_mip + r_notexture_mip->offsets[m];
|
|
for (y=0 ; y< (16>>m) ; y++)
|
|
for (x=0 ; x< (16>>m) ; x++)
|
|
{
|
|
if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
|
|
*dest++ = 0;
|
|
else
|
|
*dest++ = 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void R_SetRenderer_f (void);
|
|
void R_ReloadRenderer_f (void);
|
|
|
|
void Renderer_Init(void)
|
|
{
|
|
#ifdef AVAIL_JPEGLIB
|
|
LibJPEG_Init();
|
|
#endif
|
|
#ifdef AVAIL_PNGLIB
|
|
LibPNG_Init();
|
|
#endif
|
|
|
|
currentrendererstate.renderer = NULL;
|
|
qrenderer = QR_NONE;
|
|
|
|
r_blockvidrestart = true;
|
|
Cmd_AddCommand("setrenderer", R_SetRenderer_f);
|
|
Cmd_AddCommand("vid_restart", R_RestartRenderer_f);
|
|
Cmd_AddCommand("vid_reload", R_ReloadRenderer_f);
|
|
|
|
#ifdef RTLIGHTS
|
|
Cmd_AddCommand ("r_editlights_reload", R_ReloadRTLights_f);
|
|
Cmd_AddCommand ("r_editlights_save", R_SaveRTLights_f);
|
|
Cvar_Register (&r_editlights_import_radius, "Realtime Light editing/importing");
|
|
Cvar_Register (&r_editlights_import_ambient, "Realtime Light editing/importing");
|
|
Cvar_Register (&r_editlights_import_diffuse, "Realtime Light editing/importing");
|
|
Cvar_Register (&r_editlights_import_specular, "Realtime Light editing/importing");
|
|
|
|
#endif
|
|
Cmd_AddCommand("r_dumpshaders", Shader_WriteOutGenerics_f);
|
|
|
|
#if defined(GLQUAKE) || defined(D3DQUAKE)
|
|
GLD3DRenderer_Init();
|
|
#endif
|
|
#if defined(GLQUAKE)
|
|
GLRenderer_Init();
|
|
#endif
|
|
|
|
#ifdef SWQUAKE
|
|
{
|
|
extern cvar_t sw_interlace;
|
|
extern cvar_t sw_vthread;
|
|
extern cvar_t sw_fthreads;
|
|
Cvar_Register(&sw_interlace, "Software Rendering Options");
|
|
Cvar_Register(&sw_vthread, "Software Rendering Options");
|
|
Cvar_Register(&sw_fthreads, "Software Rendering Options");
|
|
}
|
|
#endif
|
|
|
|
Cvar_Register (&gl_conback, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_novis, GLRENDEREROPTIONS);
|
|
|
|
//but register ALL vid_ commands.
|
|
Cvar_Register (&gl_driver, GLRENDEREROPTIONS);
|
|
Cvar_Register (&_vid_wait_override, VIDCOMMANDGROUP);
|
|
Cvar_Register (&_windowed_mouse, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_renderer, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_wndalpha, VIDCOMMANDGROUP);
|
|
|
|
#ifndef NACL
|
|
if (COM_CheckParm("-plugin"))
|
|
{
|
|
vid_fullscreen.name = "vid_fullscreen_embedded";
|
|
vid_fullscreen_alternative.name = "vid_fullscreen_standalone";
|
|
}
|
|
else
|
|
{
|
|
vid_fullscreen.name = "vid_fullscreen_standalone";
|
|
vid_fullscreen_alternative.name = "vid_fullscreen_embedded";
|
|
}
|
|
Cvar_Register (&vid_fullscreen_alternative, VIDCOMMANDGROUP);
|
|
#endif
|
|
Cvar_Register (&vid_fullscreen, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_bpp, VIDCOMMANDGROUP);
|
|
|
|
Cvar_Register (&vid_conwidth, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_conheight, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_conautoscale, VIDCOMMANDGROUP);
|
|
|
|
Cvar_Register (&vid_triplebuffer, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_width, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_height, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_refreshrate, VIDCOMMANDGROUP);
|
|
Cvar_Register (&vid_multisample, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&vid_desktopsettings, VIDCOMMANDGROUP);
|
|
|
|
Cvar_Register (&r_mirroralpha, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_skyboxname, GRAPHICALNICETIES);
|
|
Cbuf_AddText("alias sky r_skybox\n", RESTRICT_LOCAL); /*alternative name for users*/
|
|
|
|
Cvar_Register(&r_dodgytgafiles, "Bug fixes");
|
|
Cvar_Register(&r_dodgypcxfiles, "Bug fixes");
|
|
Cvar_Register(&r_loadlits, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_lightstylesmooth, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_lightstylesmooth_limit, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_lightstylespeed, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register(&r_stains, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_stainfadetime, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_stainfadeammount, GRAPHICALNICETIES);
|
|
Cvar_Register(&r_lightprepass, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_coronas, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_flashblend, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_flashblendscale, GRAPHICALNICETIES);
|
|
|
|
Sh_RegisterCvars();
|
|
|
|
Cvar_Register (&r_waterstyle, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_lavastyle, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_wireframe, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_refract_fbo, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_stereo_separation, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_stereo_method, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register(&scr_viewsize, SCREENOPTIONS);
|
|
Cvar_Register(&scr_fov, SCREENOPTIONS);
|
|
// Cvar_Register(&scr_chatmodecvar, SCREENOPTIONS);
|
|
|
|
Cvar_Register (&scr_sshot_type, SCREENOPTIONS);
|
|
Cvar_Register (&scr_sshot_compression, SCREENOPTIONS);
|
|
|
|
Cvar_Register(&cl_cursor, SCREENOPTIONS);
|
|
Cvar_Register(&cl_cursorsize, SCREENOPTIONS);
|
|
Cvar_Register(&cl_cursorbias, SCREENOPTIONS);
|
|
|
|
|
|
//screen
|
|
Cvar_Register (&gl_font, GRAPHICALNICETIES);
|
|
Cvar_Register (&scr_conspeed, SCREENOPTIONS);
|
|
Cvar_Register (&scr_conalpha, SCREENOPTIONS);
|
|
Cvar_Register (&scr_showturtle, SCREENOPTIONS);
|
|
Cvar_Register (&scr_turtlefps, SCREENOPTIONS);
|
|
Cvar_Register (&scr_showpause, SCREENOPTIONS);
|
|
Cvar_Register (&scr_centertime, SCREENOPTIONS);
|
|
Cvar_Register (&scr_printspeed, SCREENOPTIONS);
|
|
Cvar_Register (&scr_allowsnap, SCREENOPTIONS);
|
|
Cvar_Register (&scr_consize, SCREENOPTIONS);
|
|
Cvar_Register (&scr_centersbar, SCREENOPTIONS);
|
|
|
|
Cvar_Register(&r_bloodstains, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register(&r_fullbrightSkins, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&mod_md3flags, GRAPHICALNICETIES);
|
|
|
|
|
|
//renderer
|
|
Cvar_Register (&r_fullbright, SCREENOPTIONS);
|
|
Cvar_Register (&r_drawentities, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_drawviewmodel, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_drawviewmodelinvis, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_waterwarp, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_speeds, SCREENOPTIONS);
|
|
Cvar_Register (&r_netgraph, SCREENOPTIONS);
|
|
|
|
Cvar_Register (&r_dynamic, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_lightmap_saturation, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_nolerp, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_nolightdir, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_fastturb, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_fastsky, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_fastskycolour, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_wateralpha, GRAPHICALNICETIES);
|
|
Cvar_Register (&gl_shadeq1_name, GLRENDEREROPTIONS);
|
|
|
|
Cvar_Register (&r_clear, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_max_size, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_maxdist, GLRENDEREROPTIONS);
|
|
Cvar_Register (&gl_miptexLevel, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_drawflat, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_menutint, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_fb_bmodels, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_fb_models, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES);
|
|
Cvar_Register (&r_shadows, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_replacemodels, GRAPHICALNICETIES);
|
|
|
|
Cvar_Register (&r_showbboxes, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_polygonoffset_submodel_factor, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_polygonoffset_submodel_offset, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_polygonoffset_stencil_factor, GLRENDEREROPTIONS);
|
|
Cvar_Register (&r_polygonoffset_stencil_offset, GLRENDEREROPTIONS);
|
|
|
|
// misc
|
|
Cvar_Register(&con_ocranaleds, "Console controls");
|
|
|
|
P_InitParticleSystem();
|
|
R_InitTextures();
|
|
}
|
|
|
|
qboolean Renderer_Started(void)
|
|
{
|
|
return !!currentrendererstate.renderer;
|
|
}
|
|
|
|
void Renderer_Start(void)
|
|
{
|
|
r_blockvidrestart = false;
|
|
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
|
|
|
|
//renderer = none && currentrendererstate.bpp == -1 means we've never applied any mode at all
|
|
//if we currently have none, we do actually need to apply it still
|
|
if (qrenderer == QR_NONE && *vid_renderer.string)
|
|
{
|
|
Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL);
|
|
}
|
|
if (!currentrendererstate.renderer)
|
|
{ //we still failed. Try again, but use the default renderer.
|
|
Cvar_Set(&vid_renderer, "");
|
|
Cmd_ExecuteString("vid_restart\n", RESTRICT_LOCAL);
|
|
}
|
|
if (!currentrendererstate.renderer)
|
|
Sys_Error("No renderer was set!\n");
|
|
|
|
if (qrenderer == QR_NONE)
|
|
Con_Printf("Use the setrenderer command to use a gui\n");
|
|
}
|
|
|
|
|
|
void (*Draw_Init) (void);
|
|
void (*Draw_Shutdown) (void);
|
|
|
|
void (*R_Init) (void);
|
|
void (*R_DeInit) (void);
|
|
void (*R_RenderView) (void); // must set r_refdef first
|
|
|
|
void (*R_NewMap) (void);
|
|
void (*R_PreNewMap) (void);
|
|
|
|
qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
|
|
void (*VID_DeInit) (void);
|
|
char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
|
|
void (*VID_SetWindowCaption) (char *msg);
|
|
|
|
void (*SCR_UpdateScreen) (void);
|
|
|
|
r_qrenderer_t qrenderer;
|
|
char *q_renderername = "Non-Selected renderer";
|
|
|
|
|
|
|
|
rendererinfo_t dedicatedrendererinfo = {
|
|
//ALL builds need a 'none' renderer, as 0.
|
|
"No renderer",
|
|
{
|
|
"none",
|
|
"dedicated",
|
|
"terminal",
|
|
"sv"
|
|
},
|
|
QR_NONE,
|
|
|
|
NULL, //Draw_Init;
|
|
NULL, //Draw_Shutdown;
|
|
|
|
NULL, //R_LoadTexture
|
|
NULL, //R_LoadTexture8Pal24
|
|
NULL, //R_LoadTexture8Pal32
|
|
NULL, //R_LoadCompressed
|
|
NULL, //R_FindTexture
|
|
NULL, //R_AllocNewTexture
|
|
NULL, //R_Upload
|
|
NULL, //R_DestroyTexture
|
|
|
|
NULL, //R_Init;
|
|
NULL, //R_DeInit;
|
|
NULL, //R_RenderView;
|
|
|
|
NULL, //R_NewMap;
|
|
NULL, //R_PreNewMap
|
|
|
|
NULL, //VID_Init,
|
|
NULL, //VID_DeInit,
|
|
NULL, //VID_ApplyGammaRamps,
|
|
NULL, //VID_GetRGBInfo,
|
|
|
|
|
|
NULL, //set caption
|
|
|
|
NULL, //SCR_UpdateScreen;
|
|
|
|
/*backend*/
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
""
|
|
};
|
|
rendererinfo_t *pdedicatedrendererinfo = &dedicatedrendererinfo;
|
|
|
|
#ifdef GLQUAKE
|
|
extern rendererinfo_t openglrendererinfo;
|
|
rendererinfo_t eglrendererinfo;
|
|
#endif
|
|
#ifdef D3DQUAKE
|
|
rendererinfo_t d3d9rendererinfo;
|
|
rendererinfo_t d3d11rendererinfo;
|
|
#endif
|
|
#ifdef SWQUAKE
|
|
rendererinfo_t swrendererinfo;
|
|
#endif
|
|
|
|
rendererinfo_t *rendererinfo[] =
|
|
{
|
|
#ifndef NPQTV
|
|
&dedicatedrendererinfo,
|
|
#endif
|
|
#ifdef GLQUAKE
|
|
&openglrendererinfo,
|
|
&eglrendererinfo,
|
|
#endif
|
|
#ifdef D3DQUAKE
|
|
&d3d9rendererinfo,
|
|
&d3d11rendererinfo,
|
|
#endif
|
|
#ifdef SWQUAKE
|
|
&swrendererinfo,
|
|
#endif
|
|
};
|
|
|
|
|
|
void R_SetRenderer(rendererinfo_t *ri)
|
|
{
|
|
currentrendererstate.renderer = ri;
|
|
if (!ri)
|
|
ri = &dedicatedrendererinfo;
|
|
|
|
qrenderer = ri->rtype;
|
|
q_renderername = ri->name[0];
|
|
|
|
Draw_Init = ri->Draw_Init;
|
|
Draw_Shutdown = ri->Draw_Shutdown;
|
|
|
|
R_Init = ri->R_Init;
|
|
R_DeInit = ri->R_DeInit;
|
|
R_RenderView = ri->R_RenderView;
|
|
R_NewMap = ri->R_NewMap;
|
|
R_PreNewMap = ri->R_PreNewMap;
|
|
|
|
VID_Init = ri->VID_Init;
|
|
VID_DeInit = ri->VID_DeInit;
|
|
VID_GetRGBInfo = ri->VID_GetRGBInfo;
|
|
VID_SetWindowCaption = ri->VID_SetWindowCaption;
|
|
|
|
SCR_UpdateScreen = ri->SCR_UpdateScreen;
|
|
}
|
|
|
|
qbyte default_quakepal[768] =
|
|
{
|
|
0,0,0,15,15,15,31,31,31,47,47,47,63,63,63,75,75,75,91,91,91,107,107,107,123,123,123,139,139,139,155,155,155,171,171,171,187,187,187,203,203,203,219,219,219,235,235,235,15,11,7,23,15,11,31,23,11,39,27,15,47,35,19,55,43,23,63,47,23,75,55,27,83,59,27,91,67,31,99,75,31,107,83,31,115,87,31,123,95,35,131,103,35,143,111,35,11,11,15,19,19,27,27,27,39,39,39,51,47,47,63,55,55,75,63,63,87,71,71,103,79,79,115,91,91,127,99,99,
|
|
139,107,107,151,115,115,163,123,123,175,131,131,187,139,139,203,0,0,0,7,7,0,11,11,0,19,19,0,27,27,0,35,35,0,43,43,7,47,47,7,55,55,7,63,63,7,71,71,7,75,75,11,83,83,11,91,91,11,99,99,11,107,107,15,7,0,0,15,0,0,23,0,0,31,0,0,39,0,0,47,0,0,55,0,0,63,0,0,71,0,0,79,0,0,87,0,0,95,0,0,103,0,0,111,0,0,119,0,0,127,0,0,19,19,0,27,27,0,35,35,0,47,43,0,55,47,0,67,
|
|
55,0,75,59,7,87,67,7,95,71,7,107,75,11,119,83,15,131,87,19,139,91,19,151,95,27,163,99,31,175,103,35,35,19,7,47,23,11,59,31,15,75,35,19,87,43,23,99,47,31,115,55,35,127,59,43,143,67,51,159,79,51,175,99,47,191,119,47,207,143,43,223,171,39,239,203,31,255,243,27,11,7,0,27,19,0,43,35,15,55,43,19,71,51,27,83,55,35,99,63,43,111,71,51,127,83,63,139,95,71,155,107,83,167,123,95,183,135,107,195,147,123,211,163,139,227,179,151,
|
|
171,139,163,159,127,151,147,115,135,139,103,123,127,91,111,119,83,99,107,75,87,95,63,75,87,55,67,75,47,55,67,39,47,55,31,35,43,23,27,35,19,19,23,11,11,15,7,7,187,115,159,175,107,143,163,95,131,151,87,119,139,79,107,127,75,95,115,67,83,107,59,75,95,51,63,83,43,55,71,35,43,59,31,35,47,23,27,35,19,19,23,11,11,15,7,7,219,195,187,203,179,167,191,163,155,175,151,139,163,135,123,151,123,111,135,111,95,123,99,83,107,87,71,95,75,59,83,63,
|
|
51,67,51,39,55,43,31,39,31,23,27,19,15,15,11,7,111,131,123,103,123,111,95,115,103,87,107,95,79,99,87,71,91,79,63,83,71,55,75,63,47,67,55,43,59,47,35,51,39,31,43,31,23,35,23,15,27,19,11,19,11,7,11,7,255,243,27,239,223,23,219,203,19,203,183,15,187,167,15,171,151,11,155,131,7,139,115,7,123,99,7,107,83,0,91,71,0,75,55,0,59,43,0,43,31,0,27,15,0,11,7,0,0,0,255,11,11,239,19,19,223,27,27,207,35,35,191,43,
|
|
43,175,47,47,159,47,47,143,47,47,127,47,47,111,47,47,95,43,43,79,35,35,63,27,27,47,19,19,31,11,11,15,43,0,0,59,0,0,75,7,0,95,7,0,111,15,0,127,23,7,147,31,7,163,39,11,183,51,15,195,75,27,207,99,43,219,127,59,227,151,79,231,171,95,239,191,119,247,211,139,167,123,59,183,155,55,199,195,55,231,227,87,127,191,255,171,231,255,215,255,255,103,0,0,139,0,0,179,0,0,215,0,0,255,0,0,255,243,147,255,247,199,255,255,255,159,91,83
|
|
};
|
|
qbyte default_conchar[11356] =
|
|
{
|
|
#include "lhfont.h"
|
|
};
|
|
|
|
qboolean R_ApplyRenderer_Load (rendererstate_t *newr);
|
|
void D3DSucks(void)
|
|
{
|
|
SCR_DeInit();
|
|
|
|
if (!R_ApplyRenderer_Load(NULL))//¤trendererstate))
|
|
Sys_Error("Failed to reload content after mode switch\n");
|
|
}
|
|
|
|
void R_ShutdownRenderer(void)
|
|
{
|
|
|
|
CL_AllowIndependantSendCmd(false); //FIXME: figure out exactly which parts are going to affect the model loading.
|
|
|
|
P_Shutdown();
|
|
Mod_Shutdown(false);
|
|
|
|
IN_Shutdown();
|
|
|
|
if (R_DeInit)
|
|
{
|
|
TRACE(("dbg: R_ApplyRenderer: R_DeInit\n"));
|
|
R_DeInit();
|
|
}
|
|
|
|
if (Draw_Shutdown)
|
|
Draw_Shutdown();
|
|
|
|
if (VID_DeInit)
|
|
{
|
|
TRACE(("dbg: R_ApplyRenderer: VID_DeInit\n"));
|
|
VID_DeInit();
|
|
}
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: SCR_DeInit\n"));
|
|
SCR_DeInit();
|
|
|
|
COM_FlushTempoaryPacks();
|
|
|
|
W_Shutdown();
|
|
if (h2playertranslations)
|
|
BZ_Free(h2playertranslations);
|
|
h2playertranslations = NULL;
|
|
if (host_basepal)
|
|
BZ_Free(host_basepal);
|
|
host_basepal = NULL;
|
|
Surf_ClearLightmaps();
|
|
|
|
RQ_Shutdown();
|
|
|
|
S_Shutdown(false);
|
|
}
|
|
|
|
void R_GenPaletteLookup(void)
|
|
{
|
|
int r,g,b,i;
|
|
unsigned char *pal = host_basepal;
|
|
for (i=0 ; i<256 ; i++)
|
|
{
|
|
r = pal[0];
|
|
g = pal[1];
|
|
b = pal[2];
|
|
pal += 3;
|
|
|
|
d_8to24rgbtable[i] = (255<<24) + (r<<0) + (g<<8) + (b<<16);
|
|
}
|
|
d_8to24rgbtable[255] &= 0xffffff; // 255 is transparent
|
|
}
|
|
|
|
qboolean R_ApplyRenderer (rendererstate_t *newr)
|
|
{
|
|
if (newr->bpp == -1)
|
|
return false;
|
|
if (!newr->renderer)
|
|
return false;
|
|
|
|
R_ShutdownRenderer();
|
|
|
|
if (qrenderer == QR_NONE)
|
|
{
|
|
if (newr->renderer->rtype == qrenderer && currentrendererstate.renderer)
|
|
return true; //no point
|
|
|
|
Sys_CloseTerminal ();
|
|
}
|
|
|
|
R_SetRenderer(newr->renderer);
|
|
|
|
return R_ApplyRenderer_Load(newr);
|
|
}
|
|
qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
|
|
{
|
|
int i, j;
|
|
extern model_t *loadmodel;
|
|
|
|
Cache_Flush();
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: old renderer closed\n"));
|
|
|
|
pmove.numphysent = 0;
|
|
|
|
memset(&r_config, 0, sizeof(r_config));
|
|
|
|
if (qrenderer != QR_NONE) //graphics stuff only when not dedicated
|
|
{
|
|
qbyte *data;
|
|
#ifndef CLIENTONLY
|
|
isDedicated = false;
|
|
#endif
|
|
if (newr)
|
|
Con_Printf("Setting mode %i*%i*%i*%i %s\n", newr->width, newr->height, newr->bpp, newr->rate, newr->renderer->description);
|
|
|
|
if (host_basepal)
|
|
BZ_Free(host_basepal);
|
|
host_basepal = (qbyte *)FS_LoadMallocFile ("gfx/palette.lmp");
|
|
if (!host_basepal)
|
|
host_basepal = (qbyte *)FS_LoadMallocFile ("wad/playpal");
|
|
if (!host_basepal)
|
|
{
|
|
qbyte *pcx=NULL;
|
|
host_basepal = BZ_Malloc(768);
|
|
pcx = COM_LoadTempFile("pics/colormap.pcx");
|
|
if (!pcx || !ReadPCXPalette(pcx, com_filesize, host_basepal))
|
|
{
|
|
memcpy(host_basepal, default_quakepal, 768);
|
|
}
|
|
else
|
|
{
|
|
//if (ReadPCXData(pcx, com_filesize, 256, VID_GRADES, colormap))
|
|
goto q2colormap; //skip the colormap.lmp file as we already read it
|
|
}
|
|
}
|
|
|
|
{
|
|
qbyte *colormap = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp");
|
|
if (!colormap)
|
|
{
|
|
vid.fullbright=0;
|
|
}
|
|
else
|
|
{
|
|
j = VID_GRADES-1;
|
|
data = colormap + j*256;
|
|
vid.fullbright = 0;
|
|
for (i = 255; i >= 0; i--)
|
|
{
|
|
if (colormap[i] == data[i])
|
|
vid.fullbright++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
BZ_Free(colormap);
|
|
}
|
|
|
|
if (h2playertranslations)
|
|
BZ_Free(h2playertranslations);
|
|
h2playertranslations = FS_LoadMallocFile ("gfx/player.lmp");
|
|
|
|
if (vid.fullbright < 2)
|
|
vid.fullbright = 0; //transparent colour doesn't count.
|
|
|
|
q2colormap:
|
|
R_GenPaletteLookup();
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: Palette loaded\n"));
|
|
|
|
if (newr)
|
|
if (!VID_Init(newr, host_basepal))
|
|
{
|
|
return false;
|
|
}
|
|
TRACE(("dbg: R_ApplyRenderer: vid applied\n"));
|
|
|
|
W_LoadWadFile("gfx.wad");
|
|
TRACE(("dbg: R_ApplyRenderer: wad loaded\n"));
|
|
Draw_Init();
|
|
TRACE(("dbg: R_ApplyRenderer: draw inited\n"));
|
|
R_Init();
|
|
RQ_Init();
|
|
R_InitParticleTexture ();
|
|
TRACE(("dbg: R_ApplyRenderer: renderer inited\n"));
|
|
SCR_Init();
|
|
TRACE(("dbg: R_ApplyRenderer: screen inited\n"));
|
|
Sbar_Flush();
|
|
|
|
IN_ReInit();
|
|
}
|
|
else
|
|
{
|
|
#ifdef CLIENTONLY
|
|
Sys_Error("Tried setting dedicated mode\n");
|
|
//we could support this, but there's no real reason to actually do so.
|
|
|
|
//fixme: despite the checks in the setrenderer command, we can still get here via a config using vid_renderer.
|
|
#else
|
|
TRACE(("dbg: R_ApplyRenderer: isDedicated = true\n"));
|
|
isDedicated = true;
|
|
if (cls.state)
|
|
{
|
|
int os = sv.state;
|
|
sv.state = ss_dead; //prevents server from being killed off too.
|
|
CL_Disconnect();
|
|
sv.state = os;
|
|
}
|
|
Sys_InitTerminal();
|
|
Con_PrintToSys();
|
|
#endif
|
|
}
|
|
TRACE(("dbg: R_ApplyRenderer: initing mods\n"));
|
|
Mod_Init(false);
|
|
|
|
// host_hunklevel = Hunk_LowMark();
|
|
|
|
if (R_PreNewMap)
|
|
if (cl.worldmodel)
|
|
{
|
|
TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n"));
|
|
R_PreNewMap();
|
|
}
|
|
|
|
#ifndef CLIENTONLY
|
|
if (sv.world.worldmodel)
|
|
{
|
|
wedict_t *ent;
|
|
#ifdef Q2SERVER
|
|
q2edict_t *q2ent;
|
|
#endif
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: reloading server map\n"));
|
|
sv.world.worldmodel = Mod_ForName (sv.modelname, false);
|
|
TRACE(("dbg: R_ApplyRenderer: loaded\n"));
|
|
if (sv.world.worldmodel->needload)
|
|
{
|
|
SV_Error("Bsp went missing on render restart\n");
|
|
}
|
|
TRACE(("dbg: R_ApplyRenderer: doing that funky phs thang\n"));
|
|
SV_CalcPHS ();
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: clearing world\n"));
|
|
World_ClearWorld (&sv.world);
|
|
|
|
if (svs.gametype == GT_PROGS)
|
|
{
|
|
for (i = 0; i < MAX_MODELS; i++)
|
|
{
|
|
if (sv.strings.model_precache[i] && *sv.strings.model_precache[i] && (!strcmp(sv.strings.model_precache[i] + strlen(sv.strings.model_precache[i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
|
|
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
|
|
else
|
|
sv.models[i] = NULL;
|
|
}
|
|
|
|
ent = sv.world.edicts;
|
|
// ent->v->model = PR_NewString(svprogfuncs, sv.worldmodel->name); //FIXME: is this a problem for normal ents?
|
|
for (i=0 ; i<sv.world.num_edicts ; i++)
|
|
{
|
|
ent = (wedict_t*)EDICT_NUM(svprogfuncs, i);
|
|
if (!ent)
|
|
continue;
|
|
if (ent->isfree)
|
|
continue;
|
|
|
|
if (ent->area.prev)
|
|
{
|
|
ent->area.prev = ent->area.next = NULL;
|
|
World_LinkEdict (&sv.world, ent, false); // relink ents so touch functions continue to work.
|
|
}
|
|
}
|
|
}
|
|
#ifdef Q2SERVER
|
|
else if (svs.gametype == GT_QUAKE2)
|
|
{
|
|
for (i = 0; i < MAX_MODELS; i++)
|
|
{
|
|
if (sv.strings.configstring[Q2CS_MODELS+i] && *sv.strings.configstring[Q2CS_MODELS+i] && (!strcmp(sv.strings.configstring[Q2CS_MODELS+i] + strlen(sv.strings.configstring[Q2CS_MODELS+i]) - 4, ".bsp") || i-1 < sv.world.worldmodel->numsubmodels))
|
|
sv.models[i] = Mod_FindName(sv.strings.configstring[Q2CS_MODELS+i]);
|
|
else
|
|
sv.models[i] = NULL;
|
|
}
|
|
|
|
q2ent = ge->edicts;
|
|
for (i=0 ; i<ge->num_edicts ; i++, q2ent = (q2edict_t *)((char *)q2ent + ge->edict_size))
|
|
{
|
|
if (!q2ent)
|
|
continue;
|
|
if (!q2ent->inuse)
|
|
continue;
|
|
|
|
if (q2ent->area.prev)
|
|
{
|
|
q2ent->area.prev = q2ent->area.next = NULL;
|
|
WorldQ2_LinkEdict (&sv.world, q2ent); // relink ents so touch functions continue to work.
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
SV_UnspawnServer();
|
|
}
|
|
#endif
|
|
#ifdef PLUGINS
|
|
Plug_ResChanged();
|
|
#endif
|
|
Cvar_ForceCallback(&r_particlesystem);
|
|
|
|
CL_InitDlights();
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
|
|
if (cl.worldmodel)
|
|
{
|
|
cl.worldmodel = NULL;
|
|
CL_ClearEntityLists(); //shouldn't really be needed, but we're paranoid
|
|
|
|
//FIXME: this code should not be here. call CL_LoadModels instead? that does csqc loading etc though. :s
|
|
TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
|
|
for (i=1 ; i<MAX_MODELS ; i++)
|
|
{
|
|
if (!cl.model_name[i][0])
|
|
break;
|
|
|
|
cl.model_precache[i] = NULL;
|
|
TRACE(("dbg: R_ApplyRenderer: reloading model %s\n", cl.model_name[i]));
|
|
|
|
#ifdef Q2CLIENT //skip vweps
|
|
if (cls.protocol == CP_QUAKE2 && *cl.model_name[i] == '#')
|
|
cl.model_precache[i] = NULL;
|
|
else
|
|
#endif
|
|
cl.model_precache[i] = Mod_ForName (cl.model_name[i], false);
|
|
|
|
if (!cl.model_precache[i] && i == 1)
|
|
{
|
|
Con_Printf ("\nThe required model file '%s' could not be found.\n\n"
|
|
, cl.model_name[i]);
|
|
Con_Printf ("You may need to download or purchase a client "
|
|
"pack in order to play on this server.\n\n");
|
|
CL_Disconnect ();
|
|
#ifdef VM_UI
|
|
UI_Reset();
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (i=0; i < MAX_VWEP_MODELS; i++)
|
|
{
|
|
if (*cl.model_name_vwep[i])
|
|
cl.model_precache_vwep[i] = Mod_ForName (cl.model_name_vwep[i], false);
|
|
else
|
|
cl.model_precache_vwep[i] = NULL;
|
|
}
|
|
|
|
#ifdef CSQC_DAT
|
|
for (i=1 ; i<MAX_CSMODELS ; i++)
|
|
{
|
|
if (!cl.model_csqcname[i][0])
|
|
break;
|
|
|
|
cl.model_csqcprecache[i] = NULL;
|
|
TRACE(("dbg: R_ApplyRenderer: reloading csqc model %s\n", cl.model_csqcname[i]));
|
|
cl.model_csqcprecache[i] = Mod_ForName (cl.model_csqcname[i], false);
|
|
|
|
if (!cl.model_csqcprecache[i])
|
|
{
|
|
Con_Printf ("\nThe required model file '%s' could not be found.\n\n"
|
|
, cl.model_csqcname[i]);
|
|
Con_Printf ("You may need to download or purchase a client "
|
|
"pack in order to play on this server.\n\n");
|
|
CL_Disconnect ();
|
|
#ifdef VM_UI
|
|
UI_Reset();
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
loadmodel = cl.worldmodel = cl.model_precache[1];
|
|
TRACE(("dbg: R_ApplyRenderer: done the models\n"));
|
|
if (loadmodel->needload)
|
|
{
|
|
CL_Disconnect ();
|
|
#ifdef VM_UI
|
|
UI_Reset();
|
|
#endif
|
|
memcpy(¤trendererstate, newr, sizeof(currentrendererstate));
|
|
return true;
|
|
}
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: checking any wad textures\n"));
|
|
Mod_NowLoadExternal();
|
|
TRACE(("dbg: R_ApplyRenderer: R_NewMap\n"));
|
|
R_NewMap();
|
|
TRACE(("dbg: R_ApplyRenderer: efrags\n"));
|
|
for (i = 0; i < cl.num_statics; i++) //make the static entities reappear.
|
|
{
|
|
cl_static_entities[i].ent.model = NULL;
|
|
if (cl_static_entities[i].mdlidx < 0)
|
|
{
|
|
if (cl_static_entities[i].mdlidx > -MAX_CSMODELS)
|
|
cl_static_entities[i].ent.model = cl.model_csqcprecache[-cl_static_entities[i].mdlidx];
|
|
}
|
|
else
|
|
{
|
|
if (cl_static_entities[i].mdlidx < MAX_MODELS)
|
|
cl_static_entities[i].ent.model = cl.model_precache[cl_static_entities[i].mdlidx];
|
|
}
|
|
}
|
|
|
|
Skin_FlushAll();
|
|
|
|
#ifdef CSQC_DAT
|
|
CSQC_RendererRestarted();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef VM_UI
|
|
UI_Reset();
|
|
#endif
|
|
}
|
|
|
|
if (newr && qrenderer != QR_NONE)
|
|
{
|
|
Con_Printf("%s renderer initialized\n", newr->renderer->description);
|
|
}
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: S_Restart_f\n"));
|
|
if (!isDedicated)
|
|
S_DoRestart();
|
|
|
|
TRACE(("dbg: R_ApplyRenderer: done\n"));
|
|
|
|
if (newr)
|
|
memcpy(¤trendererstate, newr, sizeof(currentrendererstate));
|
|
return true;
|
|
}
|
|
|
|
void R_ReloadRenderer_f (void)
|
|
{
|
|
//reloads textures without destroying video context.
|
|
R_ApplyRenderer_Load(NULL);
|
|
}
|
|
|
|
#define DEFAULT_WIDTH 640
|
|
#define DEFAULT_HEIGHT 480
|
|
#define DEFAULT_BPP 32
|
|
|
|
void R_RestartRenderer_f (void)
|
|
{
|
|
int i, j;
|
|
rendererstate_t oldr;
|
|
rendererstate_t newr;
|
|
if (r_blockvidrestart)
|
|
{
|
|
Con_Printf("Ignoring vid_restart from config\n");
|
|
return;
|
|
}
|
|
|
|
M_Shutdown();
|
|
memset(&newr, 0, sizeof(newr));
|
|
|
|
TRACE(("dbg: R_RestartRenderer_f\n"));
|
|
|
|
Media_CaptureDemoEnd();
|
|
|
|
Cvar_ApplyLatches(CVAR_RENDERERLATCH);
|
|
|
|
newr.width = vid_width.value;
|
|
newr.height = vid_height.value;
|
|
|
|
newr.triplebuffer = vid_triplebuffer.value;
|
|
newr.multisample = vid_multisample.value;
|
|
newr.bpp = vid_bpp.value;
|
|
newr.fullscreen = vid_fullscreen.value;
|
|
newr.rate = vid_refreshrate.value;
|
|
newr.stereo = (r_stereo_method.ival == 1);
|
|
|
|
if (!*_vid_wait_override.string || _vid_wait_override.value < 0)
|
|
newr.wait = -1;
|
|
else
|
|
newr.wait = _vid_wait_override.value;
|
|
|
|
Q_strncpyz(newr.glrenderer, gl_driver.string, sizeof(newr.glrenderer));
|
|
|
|
newr.renderer = NULL;
|
|
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
|
|
{
|
|
if (!rendererinfo[i]->description)
|
|
continue; //not valid in this build. :(
|
|
for (j = 4-1; j >= 0; j--)
|
|
{
|
|
if (!rendererinfo[i]->name[j])
|
|
continue;
|
|
if (!stricmp(rendererinfo[i]->name[j], vid_renderer.string))
|
|
{
|
|
newr.renderer = rendererinfo[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!newr.renderer)
|
|
{
|
|
int i;
|
|
if (*vid_renderer.string)
|
|
Con_Printf("vid_renderer \"%s\" unsupported. Using default.\n", vid_renderer.string);
|
|
else
|
|
Con_DPrintf("vid_renderer unset. Using default.\n");
|
|
|
|
//gotta do this after main hunk is saved off.
|
|
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
|
|
{
|
|
if (rendererinfo[i]->name[0] && stricmp(rendererinfo[i]->name[0], "none"))
|
|
{
|
|
Cmd_ExecuteString(va("setrenderer %s\n", rendererinfo[i]->name[0]), RESTRICT_LOCAL);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// use desktop settings if set to 0 and not dedicated
|
|
if (newr.renderer->rtype != QR_NONE)
|
|
{
|
|
int dbpp, dheight, dwidth, drate;
|
|
extern qboolean isPlugin;
|
|
|
|
if ((!newr.fullscreen && !vid_desktopsettings.value && !isPlugin) || !Sys_GetDesktopParameters(&dwidth, &dheight, &dbpp, &drate))
|
|
{
|
|
// force default values for systems not supporting desktop parameters
|
|
dwidth = DEFAULT_WIDTH;
|
|
dheight = DEFAULT_HEIGHT;
|
|
dbpp = DEFAULT_BPP;
|
|
drate = 0;
|
|
}
|
|
|
|
if (vid_desktopsettings.value)
|
|
{
|
|
newr.width = dwidth;
|
|
newr.height = dheight;
|
|
newr.bpp = dbpp;
|
|
newr.rate = drate;
|
|
}
|
|
else
|
|
{
|
|
if (newr.width <= 0 || newr.height <= 0)
|
|
{
|
|
newr.width = dwidth;
|
|
newr.height = dheight;
|
|
}
|
|
|
|
if (newr.bpp <= 0)
|
|
newr.bpp = dbpp;
|
|
}
|
|
}
|
|
|
|
TRACE(("dbg: R_RestartRenderer_f renderer %i\n", newr.renderer));
|
|
|
|
memcpy(&oldr, ¤trendererstate, sizeof(rendererstate_t));
|
|
if (!R_ApplyRenderer(&newr))
|
|
{
|
|
TRACE(("dbg: R_RestartRenderer_f failed\n"));
|
|
if (R_ApplyRenderer(&oldr))
|
|
{
|
|
TRACE(("dbg: R_RestartRenderer_f old restored\n"));
|
|
Con_Printf(CON_ERROR "Video mode switch failed. Old mode restored.\n"); //go back to the old mode, the new one failed.
|
|
}
|
|
else
|
|
{
|
|
qboolean failed = true;
|
|
|
|
if (newr.rate != 0)
|
|
{
|
|
Con_Printf(CON_NOTICE "Trying default refresh rate\n");
|
|
newr.rate = 0;
|
|
failed = !R_ApplyRenderer(&newr);
|
|
}
|
|
|
|
if (failed && newr.width != DEFAULT_WIDTH && newr.height != DEFAULT_HEIGHT)
|
|
{
|
|
Con_Printf(CON_NOTICE "Trying %i*%i\n", DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
|
newr.width = DEFAULT_WIDTH;
|
|
newr.height = DEFAULT_HEIGHT;
|
|
failed = !R_ApplyRenderer(&newr);
|
|
}
|
|
|
|
if (failed)
|
|
{
|
|
newr.renderer = &dedicatedrendererinfo;
|
|
if (R_ApplyRenderer(&newr))
|
|
{
|
|
TRACE(("dbg: R_RestartRenderer_f going to dedicated\n"));
|
|
Con_Printf(CON_ERROR "Video mode switch failed. Old mode wasn't supported either. Console forced.\n\nChange the following vars to something useable, and then use the setrenderer command.\n");
|
|
Con_Printf("%s: %s\n", vid_width.name, vid_width.string);
|
|
Con_Printf("%s: %s\n", vid_height.name, vid_height.string);
|
|
Con_Printf("%s: %s\n", vid_bpp.name, vid_bpp.string);
|
|
Con_Printf("%s: %s\n", vid_refreshrate.name, vid_refreshrate.string);
|
|
Con_Printf("%s: %s\n", vid_renderer.name, vid_renderer.string);
|
|
Con_Printf("%s: %s\n", gl_driver.name, gl_driver.string);
|
|
}
|
|
else
|
|
Sys_Error("Couldn't fall back to previous renderer\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
|
|
SCR_EndLoadingPlaque();
|
|
|
|
TRACE(("dbg: R_RestartRenderer_f success\n"));
|
|
M_Reinit();
|
|
}
|
|
|
|
void R_SetRenderer_f (void)
|
|
{
|
|
int i, j;
|
|
int best;
|
|
char *param = Cmd_Argv(1);
|
|
if (Cmd_Argc() == 1 || !stricmp(param, "help"))
|
|
{
|
|
Con_Printf ("\nValid setrenderer parameters are:\n");
|
|
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
|
|
{
|
|
if (rendererinfo[i]->description)
|
|
Con_Printf("%s: %s\n", rendererinfo[i]->name[0], rendererinfo[i]->description);
|
|
}
|
|
return;
|
|
}
|
|
|
|
best = -1;
|
|
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
|
|
{
|
|
if (!rendererinfo[i]->description)
|
|
continue; //not valid in this build. :(
|
|
for (j = 4-1; j >= 0; j--)
|
|
{
|
|
if (!rendererinfo[i]->name[j])
|
|
continue;
|
|
if (!stricmp(rendererinfo[i]->name[j], param))
|
|
{
|
|
best = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CLIENTONLY
|
|
if (best == 0)
|
|
{
|
|
Con_Printf("Client-only builds cannot use dedicated modes.\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (best == -1)
|
|
{
|
|
Con_Printf("setrenderer: parameter not supported (%s)\n", param);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (Cmd_Argc() == 3)
|
|
Cvar_Set(&vid_bpp, Cmd_Argv(2));
|
|
}
|
|
|
|
Cvar_Set(&vid_renderer, param);
|
|
|
|
if (!r_blockvidrestart)
|
|
R_RestartRenderer_f();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
================
|
|
R_GetSpriteFrame
|
|
================
|
|
*/
|
|
mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
|
|
{
|
|
msprite_t *psprite;
|
|
mspritegroup_t *pspritegroup;
|
|
mspriteframe_t *pspriteframe;
|
|
int i, numframes, frame;
|
|
float *pintervals, fullinterval, targettime, time;
|
|
|
|
psprite = currententity->model->meshinfo;
|
|
frame = currententity->framestate.g[FS_REG].frame[0];
|
|
|
|
if ((frame >= psprite->numframes) || (frame < 0))
|
|
{
|
|
Con_DPrintf ("R_DrawSprite: no such frame %d (%s)\n", frame, currententity->model->name);
|
|
frame = 0;
|
|
}
|
|
|
|
if (psprite->frames[frame].type == SPR_SINGLE)
|
|
{
|
|
pspriteframe = psprite->frames[frame].frameptr;
|
|
}
|
|
else if (psprite->frames[frame].type == SPR_ANGLED)
|
|
{
|
|
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
|
pspriteframe = pspritegroup->frames[(int)((r_refdef.viewangles[1]-currententity->angles[1])/360*8 + 0.5-4)&7];
|
|
}
|
|
else
|
|
{
|
|
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
|
pintervals = pspritegroup->intervals;
|
|
numframes = pspritegroup->numframes;
|
|
fullinterval = pintervals[numframes-1];
|
|
|
|
time = currententity->framestate.g[FS_REG].frametime[0];
|
|
|
|
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
|
// are positive, so we don't have to worry about division by 0
|
|
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
|
|
|
for (i=0 ; i<(numframes-1) ; i++)
|
|
{
|
|
if (pintervals[i] > targettime)
|
|
break;
|
|
}
|
|
|
|
pspriteframe = pspritegroup->frames[i];
|
|
}
|
|
|
|
return pspriteframe;
|
|
}
|
|
|
|
/*
|
|
void MYgluPerspective(double fovx, double fovy, double zNear, double zFar)
|
|
{
|
|
Matrix4_Projection_Far(r_refdef.m_projection, fovx, fovy, zNear, zFar);
|
|
}
|
|
|
|
void GL_InfinatePerspective(double fovx, double fovy,
|
|
double zNear)
|
|
{
|
|
// nudge infinity in just slightly for lsb slop
|
|
float nudge = 1;// - 1.0 / (1<<23);
|
|
|
|
double xmin, xmax, ymin, ymax;
|
|
|
|
ymax = zNear * tan( fovy * M_PI / 360.0 );
|
|
ymin = -ymax;
|
|
|
|
xmax = zNear * tan( fovx * M_PI / 360.0 );
|
|
xmin = -xmax;
|
|
|
|
r_projection_matrix[0] = (2*zNear) / (xmax - xmin);
|
|
r_projection_matrix[4] = 0;
|
|
r_projection_matrix[8] = (xmax + xmin) / (xmax - xmin);
|
|
r_projection_matrix[12] = 0;
|
|
|
|
r_projection_matrix[1] = 0;
|
|
r_projection_matrix[5] = (2*zNear) / (ymax - ymin);
|
|
r_projection_matrix[9] = (ymax + ymin) / (ymax - ymin);
|
|
r_projection_matrix[13] = 0;
|
|
|
|
r_projection_matrix[2] = 0;
|
|
r_projection_matrix[6] = 0;
|
|
r_projection_matrix[10] = -1 * nudge;
|
|
r_projection_matrix[14] = -2*zNear * nudge;
|
|
|
|
r_projection_matrix[3] = 0;
|
|
r_projection_matrix[7] = 0;
|
|
r_projection_matrix[11] = -1;
|
|
r_projection_matrix[15] = 0;
|
|
}
|
|
|
|
void GL_ParallelPerspective(double xmin, double xmax, double ymax, double ymin,
|
|
double znear, double zfar)
|
|
{
|
|
r_projection_matrix[0] = 2/(xmax-xmin);
|
|
r_projection_matrix[4] = 0;
|
|
r_projection_matrix[8] = 0;
|
|
r_projection_matrix[12] = (xmax+xmin)/(xmax-xmin);
|
|
|
|
r_projection_matrix[1] = 0;
|
|
r_projection_matrix[5] = 2/(ymax-ymin);
|
|
r_projection_matrix[9] = 0;
|
|
r_projection_matrix[13] = (ymax+ymin)/(ymax-ymin);
|
|
|
|
r_projection_matrix[2] = 0;
|
|
r_projection_matrix[6] = 0;
|
|
r_projection_matrix[10] = -2/(zfar-znear);
|
|
r_projection_matrix[14] = (zfar+znear)/(zfar-znear);
|
|
|
|
r_projection_matrix[3] = 0;
|
|
r_projection_matrix[7] = 0;
|
|
r_projection_matrix[11] = 0;
|
|
r_projection_matrix[15] = 1;
|
|
}
|
|
*/
|
|
|
|
|
|
/*
|
|
===============
|
|
R_TextureAnimation
|
|
|
|
Returns the proper texture for a given time and base texture
|
|
===============
|
|
*/
|
|
texture_t *R_TextureAnimation (int frame, texture_t *base)
|
|
{
|
|
int reletive;
|
|
int count;
|
|
|
|
if (frame)
|
|
{
|
|
if (base->alternate_anims)
|
|
base = base->alternate_anims;
|
|
}
|
|
|
|
if (!base->anim_total)
|
|
return base;
|
|
|
|
reletive = (int)(cl.time*10) % base->anim_total;
|
|
|
|
count = 0;
|
|
while (base->anim_min > reletive || base->anim_max <= reletive)
|
|
{
|
|
base = base->anim_next;
|
|
if (!base)
|
|
Sys_Error ("R_TextureAnimation: broken cycle");
|
|
if (++count > 100)
|
|
Sys_Error ("R_TextureAnimation: infinite cycle");
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int r_viewcontents;
|
|
mleaf_t *r_viewleaf, *r_oldviewleaf;
|
|
mleaf_t *r_viewleaf2, *r_oldviewleaf2;
|
|
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
|
|
int r_visframecount;
|
|
mleaf_t *r_vischain; // linked list of visible leafs
|
|
static qbyte curframevis[MAX_MAP_LEAFS/8];
|
|
|
|
/*
|
|
===============
|
|
R_MarkLeaves
|
|
===============
|
|
*/
|
|
#ifdef Q3BSPS
|
|
qbyte *R_MarkLeaves_Q3 (void)
|
|
{
|
|
static qbyte *vis;
|
|
int i;
|
|
|
|
int cluster;
|
|
mleaf_t *leaf;
|
|
mnode_t *node;
|
|
|
|
if (r_oldviewcluster == r_viewcluster && !r_novis.value && r_viewcluster != -1)
|
|
return vis;
|
|
|
|
// development aid to let you run around and see exactly where
|
|
// the pvs ends
|
|
// if (r_lockpvs->value)
|
|
// return;
|
|
|
|
r_vischain = NULL;
|
|
r_visframecount++;
|
|
r_oldviewcluster = r_viewcluster;
|
|
|
|
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis )
|
|
{
|
|
// mark everything
|
|
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
{
|
|
if (!leaf->nummarksurfaces)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
#if 1
|
|
for (node = (mnode_t*)leaf; node; node = node->parent)
|
|
{
|
|
if (node->visframe == r_visframecount)
|
|
break;
|
|
node->visframe = r_visframecount;
|
|
}
|
|
#else
|
|
leaf->visframe = r_visframecount;
|
|
leaf->vischain = r_vischain;
|
|
r_vischain = leaf;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, curframevis, sizeof(curframevis));
|
|
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
{
|
|
cluster = leaf->cluster;
|
|
if (cluster == -1 || !leaf->nummarksurfaces)
|
|
{
|
|
continue;
|
|
}
|
|
if (vis[cluster>>3] & (1<<(cluster&7)))
|
|
{
|
|
#if 1
|
|
for (node = (mnode_t*)leaf; node; node = node->parent)
|
|
{
|
|
if (node->visframe == r_visframecount)
|
|
break;
|
|
node->visframe = r_visframecount;
|
|
}
|
|
#else
|
|
leaf->visframe = r_visframecount;
|
|
leaf->vischain = r_vischain;
|
|
r_vischain = leaf;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
return vis;
|
|
}
|
|
#endif
|
|
|
|
#ifdef Q2BSPS
|
|
qbyte *R_MarkLeaves_Q2 (void)
|
|
{
|
|
static qbyte *vis;
|
|
mnode_t *node;
|
|
int i;
|
|
|
|
int cluster;
|
|
mleaf_t *leaf;
|
|
|
|
int c;
|
|
|
|
if (r_refdef.forcevis)
|
|
{
|
|
vis = r_refdef.forcedvis;
|
|
|
|
r_oldviewcluster = 0;
|
|
r_oldviewcluster2 = 0;
|
|
}
|
|
else
|
|
{
|
|
if (r_oldviewcluster == r_viewcluster && r_oldviewcluster2 == r_viewcluster2)
|
|
return vis;
|
|
|
|
r_oldviewcluster = r_viewcluster;
|
|
r_oldviewcluster2 = r_viewcluster2;
|
|
|
|
if (r_novis.ival == 2)
|
|
return vis;
|
|
|
|
if (r_novis.ival || r_viewcluster == -1 || !cl.worldmodel->vis)
|
|
{
|
|
// mark everything
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
|
|
cl.worldmodel->leafs[i].visframe = r_visframecount;
|
|
for (i=0 ; i<cl.worldmodel->numnodes ; i++)
|
|
cl.worldmodel->nodes[i].visframe = r_visframecount;
|
|
return vis;
|
|
}
|
|
|
|
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, curframevis, sizeof(curframevis));
|
|
// may have to combine two clusters because of solid water boundaries
|
|
if (r_viewcluster2 != r_viewcluster)
|
|
{
|
|
vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, NULL, sizeof(curframevis));
|
|
c = (cl.worldmodel->numleafs+31)/32;
|
|
for (i=0 ; i<c ; i++)
|
|
((int *)curframevis)[i] |= ((int *)vis)[i];
|
|
vis = curframevis;
|
|
}
|
|
}
|
|
|
|
r_visframecount++;
|
|
|
|
for (i=0,leaf=cl.worldmodel->leafs ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
{
|
|
cluster = leaf->cluster;
|
|
if (cluster == -1)
|
|
continue;
|
|
if (vis[cluster>>3] & (1<<(cluster&7)))
|
|
{
|
|
node = (mnode_t *)leaf;
|
|
do
|
|
{
|
|
if (node->visframe == r_visframecount)
|
|
break;
|
|
node->visframe = r_visframecount;
|
|
node = node->parent;
|
|
} while (node);
|
|
}
|
|
}
|
|
return vis;
|
|
}
|
|
#endif
|
|
|
|
qbyte *R_CalcVis_Q1 (void)
|
|
{
|
|
unsigned int i;
|
|
static qbyte *vis;
|
|
r_visframecount++;
|
|
if (r_oldviewleaf == r_viewleaf && r_oldviewleaf2 == r_viewleaf2)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
r_oldviewleaf = r_viewleaf;
|
|
r_oldviewleaf2 = r_viewleaf2;
|
|
|
|
if (r_novis.ival&1)
|
|
{
|
|
vis = curframevis;
|
|
memset (vis, 0xff, (cl.worldmodel->numleafs+7)>>3);
|
|
}
|
|
else if (r_viewleaf2 && r_viewleaf2 != r_viewleaf)
|
|
{
|
|
int c;
|
|
Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf2, curframevis, sizeof(curframevis));
|
|
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, NULL, sizeof(curframevis));
|
|
c = (cl.worldmodel->numleafs+31)/32;
|
|
for (i=0 ; i<c ; i++)
|
|
((int *)curframevis)[i] |= ((int *)vis)[i];
|
|
vis = curframevis;
|
|
}
|
|
else
|
|
vis = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, curframevis, sizeof(curframevis));
|
|
}
|
|
return vis;
|
|
}
|
|
|
|
qbyte *R_MarkLeaves_Q1 (void)
|
|
{
|
|
static qbyte fatvis[2][MAX_MAP_LEAFS/8];
|
|
static qbyte *cvis[2];
|
|
qbyte *vis;
|
|
mnode_t *node;
|
|
int i;
|
|
qboolean portal = r_refdef.recurse;
|
|
|
|
//for portals to work, we need two sets of any pvs caches
|
|
//this means lights can still check pvs at the end of the frame despite recursing in the mean time
|
|
//however, we still need to invalidate the cache because we only have one 'visframe' field in nodes.
|
|
|
|
if (r_refdef.forcevis)
|
|
{
|
|
vis = cvis[portal] = r_refdef.forcedvis;
|
|
|
|
r_oldviewleaf = NULL;
|
|
r_oldviewleaf2 = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (!portal)
|
|
{
|
|
if (((r_oldviewleaf == r_viewleaf && r_oldviewleaf2 == r_viewleaf2) && !r_novis.ival) || r_novis.ival & 2)
|
|
return cvis[portal];
|
|
|
|
r_oldviewleaf = r_viewleaf;
|
|
r_oldviewleaf2 = r_viewleaf2;
|
|
}
|
|
else
|
|
{
|
|
r_oldviewleaf = NULL;
|
|
r_oldviewleaf2 = NULL;
|
|
}
|
|
|
|
if (r_novis.ival)
|
|
{
|
|
vis = cvis[portal] = fatvis[portal];
|
|
memset (fatvis[portal], 0xff, (cl.worldmodel->numleafs+7)>>3);
|
|
|
|
r_oldviewleaf = NULL;
|
|
r_oldviewleaf2 = NULL;
|
|
}
|
|
else if (r_viewleaf2 && r_viewleaf2 != r_viewleaf)
|
|
{
|
|
int c;
|
|
Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf2, fatvis[portal], sizeof(fatvis[portal]));
|
|
vis = cvis[portal] = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, NULL, 0);
|
|
c = (cl.worldmodel->numleafs+31)/32;
|
|
for (i=0 ; i<c ; i++)
|
|
((int *)fatvis[portal])[i] |= ((int *)vis)[i];
|
|
|
|
vis = cvis[portal] = fatvis[portal];
|
|
}
|
|
else
|
|
{
|
|
vis = cvis[portal] = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, fatvis[portal], sizeof(fatvis[portal]));
|
|
}
|
|
}
|
|
|
|
r_visframecount++;
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
|
|
{
|
|
if (vis[i>>3] & (1<<(i&7)))
|
|
{
|
|
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
|
|
do
|
|
{
|
|
if (node->visframe == r_visframecount)
|
|
break;
|
|
node->visframe = r_visframecount;
|
|
node = node->parent;
|
|
} while (node);
|
|
}
|
|
}
|
|
return vis;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
R_CullBox
|
|
|
|
Returns true if the box is completely outside the frustom
|
|
=================
|
|
*/
|
|
qboolean R_CullBox (vec3_t mins, vec3_t maxs)
|
|
{
|
|
//this isn't very precise.
|
|
//checking each plane individually can be problematic
|
|
//if you have a large object behind the view, it can cross multiple planes, and be infront of each one at some point, yet should still be outside the view.
|
|
//this is quite noticable with terrain where the potential height of a section is essentually infinite.
|
|
//note that this is not a concern for spheres, just boxes.
|
|
int i;
|
|
|
|
for (i = 0; i < r_refdef.frustum_numplanes; i++)
|
|
if (BOX_ON_PLANE_SIDE (mins, maxs, &r_refdef.frustum[i]) == 2)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
qboolean R_CullSphere (vec3_t org, float radius)
|
|
{
|
|
//four frustrum planes all point inwards in an expanding 'cone'.
|
|
int i;
|
|
float d;
|
|
|
|
for (i = 0; i < r_refdef.frustum_numplanes; i++)
|
|
{
|
|
d = DotProduct(r_refdef.frustum[i].normal, org)-r_refdef.frustum[i].dist;
|
|
if (d <= -radius)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
qboolean R_CullEntityBox(entity_t *e, vec3_t modmins, vec3_t modmaxs)
|
|
{
|
|
int i;
|
|
vec3_t wmin, wmax;
|
|
|
|
#if 1
|
|
float mrad = 0, v;
|
|
|
|
if (e->axis[0][0]==1 && e->axis[0][1]==0 && e->axis[0][2]==0 &&
|
|
e->axis[1][0]==0 && e->axis[1][1]==1 && e->axis[1][2]==0 &&
|
|
e->axis[2][0]==0 && e->axis[2][1]==0 && e->axis[2][2]==1)
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
wmin[i] = e->origin[i]+modmins[i]*e->scale;
|
|
wmax[i] = e->origin[i]+modmaxs[i]*e->scale;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
v = fabs(modmins[i]);
|
|
if (mrad < v)
|
|
mrad = v;
|
|
v = fabs(modmaxs[i]);
|
|
if (mrad < v)
|
|
mrad = v;
|
|
}
|
|
mrad *= e->scale;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
wmin[i] = e->origin[i]-mrad;
|
|
wmax[i] = e->origin[i]+mrad;
|
|
}
|
|
}
|
|
#else
|
|
float fmin, fmax;
|
|
|
|
//convert the model's bbox to the expanded maximum size of the entity, as drawn with this model.
|
|
//The result is an axial box, which we pass to R_CullBox
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
fmin = DotProduct(modmins, e->axis[i]);
|
|
fmax = DotProduct(modmaxs, e->axis[i]);
|
|
|
|
if (fmin > -16)
|
|
fmin = -16;
|
|
if (fmax < 16)
|
|
fmax = 16;
|
|
|
|
if (fmin < fmax)
|
|
{
|
|
wmin[i] = e->origin[i]+fmin;
|
|
wmax[i] = e->origin[i]+fmax;
|
|
}
|
|
else
|
|
{ //box went inside out
|
|
wmin[i] = e->origin[i]+fmax;
|
|
wmax[i] = e->origin[i]+fmin;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return R_CullBox(wmin, wmax);
|
|
}
|
|
|
|
|
|
|
|
|
|
int SignbitsForPlane (mplane_t *out)
|
|
{
|
|
int bits, j;
|
|
|
|
// for fast box on planeside test
|
|
|
|
bits = 0;
|
|
for (j=0 ; j<3 ; j++)
|
|
{
|
|
if (out->normal[j] < 0)
|
|
bits |= 1<<j;
|
|
}
|
|
return bits;
|
|
}
|
|
#if 1
|
|
void R_SetFrustum (float projmat[16], float viewmat[16])
|
|
{
|
|
float scale;
|
|
int i;
|
|
float mvp[16];
|
|
|
|
if (r_novis.ival & 4)
|
|
return;
|
|
|
|
Matrix4_Multiply(projmat, viewmat, mvp);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (i & 1)
|
|
{
|
|
r_refdef.frustum[i].normal[0] = mvp[3] + mvp[0+i/2];
|
|
r_refdef.frustum[i].normal[1] = mvp[7] + mvp[4+i/2];
|
|
r_refdef.frustum[i].normal[2] = mvp[11] + mvp[8+i/2];
|
|
r_refdef.frustum[i].dist = mvp[15] + mvp[12+i/2];
|
|
}
|
|
else
|
|
{
|
|
r_refdef.frustum[i].normal[0] = mvp[3] - mvp[0+i/2];
|
|
r_refdef.frustum[i].normal[1] = mvp[7] - mvp[4+i/2];
|
|
r_refdef.frustum[i].normal[2] = mvp[11] - mvp[8+i/2];
|
|
r_refdef.frustum[i].dist = mvp[15] - mvp[12+i/2];
|
|
}
|
|
|
|
scale = 1/sqrt(DotProduct(r_refdef.frustum[i].normal, r_refdef.frustum[i].normal));
|
|
r_refdef.frustum[i].normal[0] *= scale;
|
|
r_refdef.frustum[i].normal[1] *= scale;
|
|
r_refdef.frustum[i].normal[2] *= scale;
|
|
r_refdef.frustum[i].dist *= -scale;
|
|
|
|
r_refdef.frustum[i].type = PLANE_ANYZ;
|
|
r_refdef.frustum[i].signbits = SignbitsForPlane (&r_refdef.frustum[i]);
|
|
}
|
|
|
|
r_refdef.frustum_numplanes = 4;
|
|
|
|
if (r_refdef.recurse)
|
|
return;
|
|
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14];
|
|
|
|
scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal));
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].dist *= -scale;
|
|
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[4]);
|
|
|
|
r_refdef.frustum_numplanes++;
|
|
|
|
//do far plane
|
|
//fog will not logically not actually reach 0, though precision issues will force it. we cut off at an exponant of -500
|
|
if (r_refdef.gfog_rgbd[3]
|
|
#ifdef TERRAIN
|
|
&& cl.worldmodel && cl.worldmodel->type == mod_heightmap
|
|
#else
|
|
&& 0
|
|
#endif
|
|
)
|
|
{
|
|
float culldist;
|
|
float fog;
|
|
extern cvar_t r_fog_exp2;
|
|
|
|
/*Documentation: the GLSL/GL will do this maths:
|
|
float dist = 1024;
|
|
if (r_fog_exp2.ival)
|
|
fog = pow(2, -r_refdef.gfog_rgbd[3] * r_refdef.gfog_rgbd[3] * dist * dist * 1.442695);
|
|
else
|
|
fog = pow(2, -r_refdef.gfog_rgbd[3] * dist * 1.442695);
|
|
*/
|
|
|
|
//the fog factor cut-off where its pointless to allow it to get closer to 0 (0 is technically infinite)
|
|
fog = 2/255.0f;
|
|
|
|
//figure out the eyespace distance required to reach that fog value
|
|
culldist = log(fog);
|
|
if (r_fog_exp2.ival)
|
|
culldist = sqrt(culldist / (-r_refdef.gfog_rgbd[3] * r_refdef.gfog_rgbd[3]));
|
|
else
|
|
culldist = culldist / (-r_refdef.gfog_rgbd[3]);
|
|
//anything drawn beyond this point is fully obscured by fog
|
|
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] = mvp[3] - mvp[2];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] = mvp[7] - mvp[6];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] = mvp[11] - mvp[10];
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].dist = mvp[15] - mvp[14];
|
|
|
|
scale = 1/sqrt(DotProduct(r_refdef.frustum[r_refdef.frustum_numplanes].normal, r_refdef.frustum[r_refdef.frustum_numplanes].normal));
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[0] *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[1] *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].normal[2] *= scale;
|
|
// r_refdef.frustum[r_refdef.frustum_numplanes].dist *= scale;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].dist = DotProduct(r_origin, r_refdef.frustum[r_refdef.frustum_numplanes].normal)-culldist;
|
|
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].type = PLANE_ANYZ;
|
|
r_refdef.frustum[r_refdef.frustum_numplanes].signbits = SignbitsForPlane (&r_refdef.frustum[r_refdef.frustum_numplanes]);
|
|
r_refdef.frustum_numplanes++;
|
|
}
|
|
}
|
|
#else
|
|
void R_SetFrustum (void)
|
|
{
|
|
int i;
|
|
|
|
if (r_novis.ival & 4)
|
|
return;
|
|
|
|
/* removed - assumes fov_x == fov_y
|
|
if (r_refdef.fov_x == 90)
|
|
{
|
|
// front side is visible
|
|
|
|
VectorAdd (vpn, vright, frustum[0].normal);
|
|
VectorSubtract (vpn, vright, frustum[1].normal);
|
|
|
|
VectorAdd (vpn, vup, frustum[2].normal);
|
|
VectorSubtract (vpn, vup, frustum[3].normal);
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
|
|
// rotate VPN right by FOV_X/2 degrees
|
|
RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
|
|
// rotate VPN left by FOV_X/2 degrees
|
|
RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
|
|
// rotate VPN up by FOV_X/2 degrees
|
|
RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
|
|
// rotate VPN down by FOV_X/2 degrees
|
|
RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
|
|
}
|
|
|
|
for (i=0 ; i<4 ; i++)
|
|
{
|
|
frustum[i].type = PLANE_ANYZ;
|
|
frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
|
|
frustum[i].signbits = SignbitsForPlane (&frustum[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "glquake.h"
|
|
|
|
//we could go for nice smooth round particles... but then we would loose a little bit of the chaotic nature of the particles.
|
|
static qbyte dottexture[8][8] =
|
|
{
|
|
{0,0,0,0,0,0,0,0},
|
|
{0,0,0,1,1,0,0,0},
|
|
{0,0,1,1,1,1,0,0},
|
|
{0,1,1,1,1,1,1,0},
|
|
{0,1,1,1,1,1,1,0},
|
|
{0,0,1,1,1,1,0,0},
|
|
{0,0,0,1,1,0,0,0},
|
|
{0,0,0,0,0,0,0,0},
|
|
};
|
|
static qbyte exptexture[16][16] =
|
|
{
|
|
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
|
{0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0},
|
|
{0,0,0,1,1,1,1,1,3,1,1,2,1,0,0,0},
|
|
{0,0,0,1,1,1,1,4,4,4,5,4,2,1,1,0},
|
|
{0,0,1,1,6,5,5,8,6,8,3,6,3,2,1,0},
|
|
{0,0,1,5,6,7,5,6,8,8,8,3,3,1,0,0},
|
|
{0,0,0,1,6,8,9,9,9,9,4,6,3,1,0,0},
|
|
{0,0,2,1,7,7,9,9,9,9,5,3,1,0,0,0},
|
|
{0,0,2,4,6,8,9,9,9,9,8,6,1,0,0,0},
|
|
{0,0,2,2,3,5,6,8,9,8,8,4,4,1,0,0},
|
|
{0,0,1,2,4,1,8,7,8,8,6,5,4,1,0,0},
|
|
{0,1,1,1,7,8,1,6,7,5,4,7,1,0,0,0},
|
|
{0,1,2,1,1,5,1,3,4,3,1,1,0,0,0,0},
|
|
{0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0},
|
|
{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
|
|
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
|
};
|
|
|
|
texid_t particletexture; // little dot for particles
|
|
texid_t particlecqtexture; // little dot for particles
|
|
texid_t explosiontexture;
|
|
texid_t balltexture;
|
|
texid_t beamtexture;
|
|
texid_t ptritexture;
|
|
void R_InitParticleTexture (void)
|
|
{
|
|
#define PARTICLETEXTURESIZE 64
|
|
int x,y;
|
|
float dx, dy, d;
|
|
qbyte data[PARTICLETEXTURESIZE*PARTICLETEXTURESIZE][4];
|
|
|
|
//
|
|
// particle texture
|
|
//
|
|
for (x=0 ; x<8 ; x++)
|
|
{
|
|
for (y=0 ; y<8 ; y++)
|
|
{
|
|
data[y*8+x][0] = 255;
|
|
data[y*8+x][1] = 255;
|
|
data[y*8+x][2] = 255;
|
|
data[y*8+x][3] = dottexture[x][y]*255;
|
|
}
|
|
}
|
|
|
|
TEXASSIGN(particletexture, R_LoadTexture32("", 8, 8, data, IF_NOMIPMAP|IF_NOPICMIP));
|
|
|
|
|
|
//
|
|
// particle triangle texture
|
|
//
|
|
|
|
// clear to transparent white
|
|
for (x = 0; x < 32 * 32; x++)
|
|
{
|
|
data[x][0] = 255;
|
|
data[x][1] = 255;
|
|
data[x][2] = 255;
|
|
data[x][3] = 0;
|
|
}
|
|
//draw a circle in the top left.
|
|
for (x=0 ; x<16 ; x++)
|
|
{
|
|
for (y=0 ; y<16 ; y++)
|
|
{
|
|
if ((x - 7.5) * (x - 7.5) + (y - 7.5) * (y - 7.5) <= 8 * 8)
|
|
data[y*32+x][3] = 255;
|
|
}
|
|
}
|
|
|
|
particlecqtexture = R_LoadTexture32("", 32, 32, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
|
|
|
|
|
|
|
|
|
|
for (x=0 ; x<16 ; x++)
|
|
{
|
|
for (y=0 ; y<16 ; y++)
|
|
{
|
|
data[y*16+x][0] = 255;
|
|
data[y*16+x][1] = 255;
|
|
data[y*16+x][2] = 255;
|
|
data[y*16+x][3] = exptexture[x][y]*255/9.0;
|
|
}
|
|
}
|
|
explosiontexture = R_LoadTexture32("fte_fuzzyparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
|
|
for (x=0 ; x<16 ; x++)
|
|
{
|
|
for (y=0 ; y<16 ; y++)
|
|
{
|
|
data[y*16+x][0] = exptexture[x][y]*255/9.0;
|
|
data[y*16+x][1] = exptexture[x][y]*255/9.0;
|
|
data[y*16+x][2] = exptexture[x][y]*255/9.0;
|
|
data[y*16+x][3] = exptexture[x][y]*255/9.0;
|
|
}
|
|
}
|
|
R_LoadTexture32("fte_bloodparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
|
|
memset(data, 255, sizeof(data));
|
|
for (y = 0;y < PARTICLETEXTURESIZE;y++)
|
|
{
|
|
dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1);
|
|
for (x = 0;x < PARTICLETEXTURESIZE;x++)
|
|
{
|
|
dx = (x - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1);
|
|
d = 256 * (1 - (dx*dx+dy*dy));
|
|
d = bound(0, d, 255);
|
|
data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d;
|
|
}
|
|
}
|
|
balltexture = R_LoadTexture32("balltexture", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
|
|
memset(data, 255, sizeof(data));
|
|
for (y = 0;y < PARTICLETEXTURESIZE;y++)
|
|
{
|
|
dy = (y - 0.5f*PARTICLETEXTURESIZE) / (PARTICLETEXTURESIZE*0.5f-1);
|
|
d = 256 * (1 - (dy*dy));
|
|
d = bound(0, d, 255);
|
|
for (x = 0;x < PARTICLETEXTURESIZE;x++)
|
|
{
|
|
data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d;
|
|
}
|
|
}
|
|
beamtexture = R_LoadTexture32("", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
|
|
for (y = 0;y < PARTICLETEXTURESIZE;y++)
|
|
{
|
|
dy = y / (PARTICLETEXTURESIZE*0.5f-1);
|
|
d = 256 * (1 - (dy*dy));
|
|
d = bound(0, d, 255);
|
|
for (x = 0;x < PARTICLETEXTURESIZE;x++)
|
|
{
|
|
dx = x / (PARTICLETEXTURESIZE*0.5f-1);
|
|
d = 256 * (1 - (dx+dy));
|
|
d = bound(0, d, 255);
|
|
data[y*PARTICLETEXTURESIZE+x][0] = (qbyte) d;
|
|
data[y*PARTICLETEXTURESIZE+x][1] = (qbyte) d;
|
|
data[y*PARTICLETEXTURESIZE+x][2] = (qbyte) d;
|
|
data[y*PARTICLETEXTURESIZE+x][3] = (qbyte) d/2;
|
|
}
|
|
}
|
|
ptritexture = R_LoadTexture32("", PARTICLETEXTURESIZE, PARTICLETEXTURESIZE, data, IF_NOMIPMAP|IF_NOPICMIP);
|
|
}
|
|
|