implement ripplemaps. currently requires explicit mod support to use properly.
fix hexen2 conchars fix audio sample mixups fix recent beam-related crashes. added orthographic bsp culling routines. fix crash on vid_restart. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4050 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
757b50efa1
commit
4db8b46c4b
31 changed files with 3533 additions and 181 deletions
|
@ -2698,6 +2698,11 @@ void CL_LinkPacketEntities (void)
|
|||
if (ent->flags & Q2RF_EXTERNALMODEL)
|
||||
ent->externalmodelview = ~0;
|
||||
|
||||
/* if (le->origin[2] < r_refdef.waterheight != le->lastorigin[2] < r_refdef.waterheight)
|
||||
{
|
||||
P_RunParticleEffectTypeString(le->origin, NULL, 1, "te_watertransition");
|
||||
}
|
||||
*/
|
||||
// set colormap
|
||||
if (state->colormap && (state->colormap <= MAX_CLIENTS)
|
||||
&& (gl_nocolors.value == -1 || (ent->model/* && state->modelindex == cl_playerindex*/)))
|
||||
|
@ -4157,7 +4162,37 @@ void CL_SwapEntityLists(void)
|
|||
cl_numstrisvert = 0;
|
||||
cl_numstris = 0;
|
||||
}
|
||||
/*
|
||||
static void CL_WaterSplashes(void)
|
||||
{
|
||||
int i;
|
||||
entity_t *ent;
|
||||
vec3_t org;
|
||||
|
||||
static unsigned int ltime;
|
||||
unsigned int ntime = cl.time*1000;
|
||||
if (ntime - ltime < 200)
|
||||
return;
|
||||
ltime = ntime;
|
||||
|
||||
for (i = 0; i < cl_numvisedicts; i++)
|
||||
{
|
||||
ent = &cl_visedicts[i];
|
||||
|
||||
if (ent->model)
|
||||
{
|
||||
if (ent->origin[2] + ent->model->mins[2] < r_refdef.waterheight &&
|
||||
ent->origin[2] + ent->model->maxs[2] > r_refdef.waterheight)
|
||||
{
|
||||
org[0] = ent->origin[0];
|
||||
org[1] = ent->origin[1];
|
||||
org[2] = r_refdef.waterheight;
|
||||
P_RunParticleEffectTypeString(org, NULL, 1, "te_watertransition");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
void CL_EmitEntities (void)
|
||||
{
|
||||
if (cls.state != ca_active)
|
||||
|
@ -4181,6 +4216,8 @@ void CL_EmitEntities (void)
|
|||
CL_LinkPacketEntities ();
|
||||
CL_LinkProjectiles ();
|
||||
CL_UpdateTEnts ();
|
||||
|
||||
// CL_WaterSplashes();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3094,9 +3094,6 @@ void CL_Init (void)
|
|||
#endif
|
||||
#ifdef CSQC_DAT
|
||||
CSQC_RegisterCvarsAndThings();
|
||||
#endif
|
||||
#if defined(CSQC_DAT) || defined(MENU_DAT)
|
||||
PF_Common_RegisterCvars();
|
||||
#endif
|
||||
Cvar_Register (&host_speeds, cl_controlgroup);
|
||||
Cvar_Register (&developer, cl_controlgroup);
|
||||
|
|
|
@ -314,12 +314,7 @@ void CL_AssociateEffect_f(void)
|
|||
CL_RegisterParticles();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_ParseTEnts
|
||||
=================
|
||||
*/
|
||||
void CL_InitTEnts (void)
|
||||
void CL_InitTEntSounds (void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(tentsfx)/sizeof(tentsfx[0]); i++)
|
||||
|
@ -329,6 +324,18 @@ void CL_InitTEnts (void)
|
|||
else
|
||||
*tentsfx[i].sfx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_ParseTEnts
|
||||
=================
|
||||
*/
|
||||
void CL_InitTEnts (void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(tentsfx)/sizeof(tentsfx[0]); i++)
|
||||
*tentsfx[i].sfx = NULL;
|
||||
|
||||
Cmd_AddCommand("r_effect", CL_AssociateEffect_f);
|
||||
Cmd_AddCommand("r_trail", CL_AssociateEffect_f);
|
||||
|
@ -513,6 +520,8 @@ CL_ClearTEnts
|
|||
*/
|
||||
void CL_ClearTEnts (void)
|
||||
{
|
||||
CL_ClearTEntParticleState();
|
||||
|
||||
cl_beams_max = 0;
|
||||
BZ_Free(cl_beams);
|
||||
cl_beams = NULL;
|
||||
|
@ -618,8 +627,12 @@ beam_t *CL_NewBeam (int entity, int tag)
|
|||
{
|
||||
if (i == cl_beams_max)
|
||||
{
|
||||
cl_beams_max = (i+1)*2;
|
||||
cl_beams = BZ_Realloc(cl_beams, cl_beams_max*sizeof(*cl_beams));
|
||||
int nm = (i+1)*2;
|
||||
CL_ClearTEntParticleState();
|
||||
|
||||
cl_beams = BZ_Realloc(cl_beams, nm*sizeof(*cl_beams));
|
||||
memset(cl_beams + cl_beams_max, 0, sizeof(*cl_beams)*(nm-cl_beams_max));
|
||||
cl_beams_max = nm;
|
||||
}
|
||||
|
||||
beams_running++;
|
||||
|
|
|
@ -991,6 +991,7 @@ void DropPunchAngle (int pnum);
|
|||
//
|
||||
void CL_RegisterParticles(void);
|
||||
void CL_InitTEnts (void);
|
||||
void CL_InitTEntSounds (void);
|
||||
void CL_ClearTEnts (void);
|
||||
void CL_ClearTEntParticleState (void);
|
||||
void CL_ClearCustomTEnts(void);
|
||||
|
|
|
@ -142,7 +142,7 @@ typedef struct skytris_s {
|
|||
//these is the required render state for each particle
|
||||
//dynamic per-particle stuff isn't important. only static state.
|
||||
typedef struct {
|
||||
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_DECAL} type;
|
||||
enum {PT_NORMAL, PT_SPARK, PT_SPARKFAN, PT_TEXTUREDSPARK, PT_BEAM, PT_CDECAL, PT_UDECAL} type;
|
||||
|
||||
blendmode_t blendmode;
|
||||
shader_t *shader;
|
||||
|
@ -1181,8 +1181,10 @@ static void P_ParticleEffect_f(void)
|
|||
ptype->looks.type = PT_SPARKFAN;
|
||||
else if (!strcmp(value, "texturedspark"))
|
||||
ptype->looks.type = PT_TEXTUREDSPARK;
|
||||
else if (!strcmp(value, "decal"))
|
||||
ptype->looks.type = PT_DECAL;
|
||||
else if (!strcmp(value, "decal") || !strcmp(value, "cdecal"))
|
||||
ptype->looks.type = PT_CDECAL;
|
||||
else if (!strcmp(value, "udecal"))
|
||||
ptype->looks.type = PT_UDECAL;
|
||||
else
|
||||
ptype->looks.type = PT_NORMAL;
|
||||
settype = true;
|
||||
|
@ -1805,9 +1807,14 @@ static void P_ImportEffectInfo_f(void)
|
|||
ptype->count = atof(arg[1]);
|
||||
else if (!strcmp(arg[0], "type") && args == 2)
|
||||
{
|
||||
if (!strcmp(arg[1], "decal"))
|
||||
if (!strcmp(arg[1], "decal") || !strcmp(arg[1], "cdecal"))
|
||||
{
|
||||
ptype->looks.type = PT_DECAL;
|
||||
ptype->looks.type = PT_CDECAL;
|
||||
ptype->looks.blendmode = BM_INVMOD;
|
||||
}
|
||||
else if (!strcmp(arg[1], "udecal"))
|
||||
{
|
||||
ptype->looks.type = PT_UDECAL;
|
||||
ptype->looks.blendmode = BM_INVMOD;
|
||||
}
|
||||
else if (!strcmp(arg[1], "alphastatic"))
|
||||
|
@ -2923,7 +2930,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
|
|||
{
|
||||
PScript_EffectSpawned(ptype, org, dir, 0, count);
|
||||
|
||||
if (ptype->looks.type == PT_DECAL)
|
||||
if (ptype->looks.type == PT_CDECAL)
|
||||
{
|
||||
clippeddecal_t *d;
|
||||
int decalcount;
|
||||
|
@ -4601,6 +4608,79 @@ static void R_AddClippedDecal(scenetris_t *t, clippeddecal_t *d, plooks_t *type)
|
|||
t->numidx += 3;
|
||||
}
|
||||
|
||||
static void R_AddUnclippedDecal(scenetris_t *t, particle_t *p, plooks_t *type)
|
||||
{
|
||||
float x, y;
|
||||
vec3_t sdir, tdir;
|
||||
|
||||
if (cl_numstrisvert+4 > cl_maxstrisvert)
|
||||
{
|
||||
cl_maxstrisvert+=64*4;
|
||||
cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert);
|
||||
cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert);
|
||||
cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert);
|
||||
}
|
||||
|
||||
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+0]);
|
||||
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+1]);
|
||||
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+2]);
|
||||
Vector4Copy(p->rgba, cl_strisvertc[cl_numstrisvert+3]);
|
||||
|
||||
Vector2Set(cl_strisvertt[cl_numstrisvert+0], p->s1, p->t1);
|
||||
Vector2Set(cl_strisvertt[cl_numstrisvert+1], p->s1, p->t2);
|
||||
Vector2Set(cl_strisvertt[cl_numstrisvert+2], p->s2, p->t2);
|
||||
Vector2Set(cl_strisvertt[cl_numstrisvert+3], p->s2, p->t1);
|
||||
|
||||
// if (p->vel[1] == 1)
|
||||
{
|
||||
VectorSet(sdir, 1, 0, 0);
|
||||
VectorSet(tdir, 0, 1, 0);
|
||||
}
|
||||
|
||||
if (p->angle)
|
||||
{
|
||||
x = sin(p->angle)*p->scale;
|
||||
y = cos(p->angle)*p->scale;
|
||||
|
||||
cl_strisvertv[cl_numstrisvert+0][0] = p->org[0] - x*sdir[0] - y*tdir[0];
|
||||
cl_strisvertv[cl_numstrisvert+0][1] = p->org[1] - x*sdir[1] - y*tdir[1];
|
||||
cl_strisvertv[cl_numstrisvert+0][2] = p->org[2] - x*sdir[2] - y*tdir[2];
|
||||
cl_strisvertv[cl_numstrisvert+1][0] = p->org[0] - y*sdir[0] + x*tdir[0];
|
||||
cl_strisvertv[cl_numstrisvert+1][1] = p->org[1] - y*sdir[1] + x*tdir[1];
|
||||
cl_strisvertv[cl_numstrisvert+1][2] = p->org[2] - y*sdir[2] + x*tdir[2];
|
||||
cl_strisvertv[cl_numstrisvert+2][0] = p->org[0] + x*sdir[0] + y*tdir[0];
|
||||
cl_strisvertv[cl_numstrisvert+2][1] = p->org[1] + x*sdir[1] + y*tdir[1];
|
||||
cl_strisvertv[cl_numstrisvert+2][2] = p->org[2] + x*sdir[2] + y*tdir[2];
|
||||
cl_strisvertv[cl_numstrisvert+3][0] = p->org[0] + y*sdir[0] - x*tdir[0];
|
||||
cl_strisvertv[cl_numstrisvert+3][1] = p->org[1] + y*sdir[1] - x*tdir[1];
|
||||
cl_strisvertv[cl_numstrisvert+3][2] = p->org[2] + y*sdir[2] - x*tdir[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorMA(p->org, -p->scale, tdir, cl_strisvertv[cl_numstrisvert+0]);
|
||||
VectorMA(p->org, -p->scale, sdir, cl_strisvertv[cl_numstrisvert+1]);
|
||||
VectorMA(p->org, p->scale, tdir, cl_strisvertv[cl_numstrisvert+2]);
|
||||
VectorMA(p->org, p->scale, sdir, cl_strisvertv[cl_numstrisvert+3]);
|
||||
}
|
||||
|
||||
if (cl_numstrisidx+6 > cl_maxstrisidx)
|
||||
{
|
||||
cl_maxstrisidx += 64*6;
|
||||
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
|
||||
}
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 0;
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 1;
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 2;
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 0;
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 2;
|
||||
cl_strisidx[cl_numstrisidx++] = (cl_numstrisvert - t->firstvert) + 3;
|
||||
|
||||
cl_numstrisvert += 4;
|
||||
|
||||
t->numvert += 4;
|
||||
t->numidx += 6;
|
||||
}
|
||||
|
||||
static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type)
|
||||
{
|
||||
float scale, x, y;
|
||||
|
@ -4863,7 +4943,10 @@ static void PScript_DrawParticleTypes (void)
|
|||
else
|
||||
bdraw = GL_DrawParticleBeam;
|
||||
break;
|
||||
case PT_DECAL:
|
||||
case PT_CDECAL:
|
||||
break;
|
||||
case PT_UDECAL:
|
||||
tdraw = R_AddUnclippedDecal;
|
||||
break;
|
||||
case PT_NORMAL:
|
||||
pdraw = GL_DrawTexturedParticle;
|
||||
|
|
|
@ -1632,10 +1632,7 @@ static void QCBUILTIN PF_cs_pointcontents(progfuncs_t *prinst, struct globalvars
|
|||
|
||||
v = G_VECTOR(OFS_PARM0);
|
||||
|
||||
if (!cl.worldmodel)
|
||||
return FTECONTENTS_EMPTY;
|
||||
|
||||
cont = World_PointContents(w, v);
|
||||
cont = cl.worldmodel?World_PointContents(w, v):FTECONTENTS_EMPTY;
|
||||
if (cont & FTECONTENTS_SOLID)
|
||||
G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID;
|
||||
else if (cont & FTECONTENTS_SKY)
|
||||
|
|
|
@ -1512,6 +1512,75 @@ start:
|
|||
goto start;
|
||||
}
|
||||
|
||||
static void Surf_OrthoRecursiveWorldNode (mnode_t *node, unsigned int clipflags)
|
||||
{
|
||||
//when rendering as ortho the front and back sides are technically equal. the only culling comes from frustum culling.
|
||||
|
||||
int c, side, clipped;
|
||||
mplane_t *plane, *clipplane;
|
||||
msurface_t *surf, **mark;
|
||||
mleaf_t *pleaf;
|
||||
double dot;
|
||||
|
||||
if (node->contents == Q1CONTENTS_SOLID)
|
||||
return; // solid
|
||||
|
||||
if (node->visframe != r_visframecount)
|
||||
return;
|
||||
|
||||
for (c = 0, clipplane = frustum; c < FRUSTUMPLANES; c++, clipplane++)
|
||||
{
|
||||
if (!(clipflags & (1 << c)))
|
||||
continue; // don't need to clip against it
|
||||
|
||||
clipped = BOX_ON_PLANE_SIDE (node->minmaxs, node->minmaxs + 3, clipplane);
|
||||
if (clipped == 2)
|
||||
return;
|
||||
else if (clipped == 1)
|
||||
clipflags -= (1<<c); // node is entirely on screen
|
||||
}
|
||||
|
||||
// if a leaf node, draw stuff
|
||||
if (node->contents < 0)
|
||||
{
|
||||
pleaf = (mleaf_t *)node;
|
||||
|
||||
mark = pleaf->firstmarksurface;
|
||||
c = pleaf->nummarksurfaces;
|
||||
|
||||
if (c)
|
||||
{
|
||||
do
|
||||
{
|
||||
(*mark++)->visframe = r_framecount;
|
||||
} while (--c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// recurse down the children
|
||||
Surf_OrthoRecursiveWorldNode (node->children[0], clipflags);
|
||||
Surf_OrthoRecursiveWorldNode (node->children[1], clipflags);
|
||||
|
||||
// draw stuff
|
||||
c = node->numsurfaces;
|
||||
|
||||
if (c)
|
||||
{
|
||||
surf = cl.worldmodel->surfaces + node->firstsurface;
|
||||
|
||||
for ( ; c ; c--, surf++)
|
||||
{
|
||||
if (surf->visframe != r_framecount)
|
||||
continue;
|
||||
|
||||
Surf_RenderDynamicLightmaps (surf);
|
||||
surf->sbatch->mesh[surf->sbatch->meshes++] = surf->mesh;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q2BSPS
|
||||
static void Surf_RecursiveQ2WorldNode (mnode_t *node)
|
||||
{
|
||||
|
@ -2168,7 +2237,10 @@ void Surf_DrawWorld (void)
|
|||
if (!(r_novis.ival & 2))
|
||||
VectorCopy (r_refdef.vieworg, modelorg);
|
||||
|
||||
Surf_RecursiveWorldNode (cl.worldmodel->nodes, 0x1f);
|
||||
if (r_refdef.useperspective)
|
||||
Surf_RecursiveWorldNode (cl.worldmodel->nodes, 0x1f);
|
||||
else
|
||||
Surf_OrthoRecursiveWorldNode (cl.worldmodel->nodes, 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ typedef struct
|
|||
int currentplayernum;
|
||||
|
||||
float time;
|
||||
// float waterheight; //updated by the renderer. stuff sitting at this height generate ripple effects
|
||||
|
||||
float m_projection[16];
|
||||
float m_view[16];
|
||||
|
@ -240,7 +241,7 @@ void GLR_InitTextures (void);
|
|||
void GLR_InitEfrags (void);
|
||||
void GLR_RenderView (void); // must set r_refdef first
|
||||
// called whenever r_refdef or vid change
|
||||
void GLR_DrawPortal(struct batch_s *batch, struct batch_s **blist);
|
||||
void GLR_DrawPortal(struct batch_s *batch, struct batch_s **blist, int portaltype);
|
||||
|
||||
void GLR_PreNewMap(void);
|
||||
void GLR_NewMap (void);
|
||||
|
@ -410,8 +411,7 @@ extern cvar_t r_shadow_realtime_dlight, r_shadow_realtime_dlight_shadows;
|
|||
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_shadows;
|
||||
extern cvar_t r_mirroralpha;
|
||||
extern cvar_t r_wateralpha;
|
||||
extern cvar_t r_water_refract;
|
||||
extern cvar_t r_water_reflect;
|
||||
extern cvar_t r_waterstyle;
|
||||
extern cvar_t r_dynamic;
|
||||
extern cvar_t r_novis;
|
||||
extern cvar_t r_netgraph;
|
||||
|
|
|
@ -326,8 +326,7 @@ cvar_t r_shadow_realtime_dlight_shadows = SCVARF ("r_shadow_realtime_dlight_sha
|
|||
cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0", 0);
|
||||
cvar_t r_sun_dir = SCVAR ("r_sun_dir", "0.2 0.5 0.8");
|
||||
cvar_t r_sun_colour = SCVARF ("r_sun_colour", "0 0 0", CVAR_ARCHIVE);
|
||||
cvar_t r_water_refract = CVARF ("r_water_refract", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM);
|
||||
cvar_t r_water_reflect = CVARF ("r_water_reflect", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM);
|
||||
cvar_t r_waterstyle = CVARF ("r_waterstyle", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM);
|
||||
|
||||
cvar_t r_vertexdlights = SCVAR ("r_vertexdlights", "0");
|
||||
|
||||
|
@ -578,8 +577,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register (&r_shadow_realtime_world_lightmaps, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_sun_dir, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_sun_colour, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_water_refract, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_water_reflect, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_waterstyle, GRAPHICALNICETIES);
|
||||
|
||||
Cvar_Register(&scr_viewsize, SCREENOPTIONS);
|
||||
Cvar_Register(&scr_fov, SCREENOPTIONS);
|
||||
|
|
|
@ -879,6 +879,8 @@ void S_Startup (void)
|
|||
sound_started = !!sndcardinfo;
|
||||
|
||||
S_ClearRaw();
|
||||
|
||||
CL_InitTEntSounds();
|
||||
}
|
||||
|
||||
void SNDDMA_SetUnderWater(qboolean underwater)
|
||||
|
@ -1753,7 +1755,7 @@ void S_UpdateAmbientSounds (soundcardinfo_t *sc)
|
|||
{
|
||||
newmusic = S_PrecacheSound(nexttrack);
|
||||
|
||||
if (!newmusic->failedload)
|
||||
if (newmusic && !newmusic->failedload)
|
||||
{
|
||||
chan->sfx = newmusic;
|
||||
chan->rate = 1<<PITCHSHIFT;
|
||||
|
|
|
@ -745,7 +745,7 @@ unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point)
|
|||
transformed[2] = DotProduct(point, axis[2]);
|
||||
return Q1BSP_HullPointContents(&model->hulls[0], transformed);
|
||||
}
|
||||
if (1)
|
||||
if (!model->firstmodelsurface)
|
||||
{
|
||||
return Q1BSP_TranslateContents(Q1_ModelPointContents(model->nodes, point));
|
||||
}
|
||||
|
|
|
@ -957,7 +957,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
|
|||
|
||||
texnums_t *skin;
|
||||
|
||||
if (r_refdef.externalview && e->flags & Q2RF_WEAPONMODEL)
|
||||
if ((r_refdef.externalview || r_refdef.recurse) && e->flags & Q2RF_WEAPONMODEL)
|
||||
return;
|
||||
|
||||
/*switch model if we're the player model, and the player skin says a new model*/
|
||||
|
|
|
@ -121,8 +121,9 @@ struct {
|
|||
texid_t tex_sourcedepth;
|
||||
int fbo_depthless;
|
||||
int fbo_reflection;
|
||||
texid_t tex_reflection;
|
||||
texid_t tex_refraction;
|
||||
texid_t tex_reflection; /*basically a portal rendered to texture*/
|
||||
texid_t tex_refraction; /*the (culled) underwater view*/
|
||||
texid_t tex_ripplemap; /*temp image for waves and things.*/
|
||||
|
||||
qboolean force2d;
|
||||
int currenttmu;
|
||||
|
@ -169,6 +170,8 @@ struct {
|
|||
texid_t fogtexture;
|
||||
texid_t normalisationcubemap;
|
||||
float fogfar;
|
||||
|
||||
batch_t **mbatches; //model batches (ie: not world)
|
||||
};
|
||||
|
||||
//exterior state (paramters)
|
||||
|
@ -670,6 +673,7 @@ void GLBE_SetupVAO(vbo_t *vbo, unsigned vaodynamic)
|
|||
shaderstate.sourcevbo = vbo;
|
||||
shaderstate.pendingvertexvbo = shaderstate.sourcevbo->coord.gl.vbo;
|
||||
shaderstate.pendingvertexpointer = shaderstate.sourcevbo->coord.gl.addr;
|
||||
shaderstate.colourarraytype = GL_FLOAT;
|
||||
|
||||
shaderstate.currentvao = vbo->vao;
|
||||
qglBindVertexArray(vbo->vao);
|
||||
|
@ -876,19 +880,6 @@ void R_IBrokeTheArrays(void)
|
|||
RevertToKnownState();
|
||||
}
|
||||
|
||||
void GL_FlushBackEnd(void)
|
||||
{
|
||||
memset(&shaderstate, 0, sizeof(shaderstate));
|
||||
shaderstate.curcull = ~0;
|
||||
}
|
||||
void R_BackendInit(void)
|
||||
{
|
||||
}
|
||||
qboolean R_MeshWillExceed(mesh_t *mesh)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
//called from gl_shadow
|
||||
void BE_SetupForShadowMap(void)
|
||||
|
@ -1026,6 +1017,9 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
|
|||
case T_GEN_REFRACTION:
|
||||
t = shaderstate.tex_refraction;
|
||||
break;
|
||||
case T_GEN_RIPPLEMAP:
|
||||
t = shaderstate.tex_ripplemap;
|
||||
break;
|
||||
}
|
||||
GL_LazyBind(tmu, GL_TEXTURE_2D, t);
|
||||
}
|
||||
|
@ -3550,7 +3544,7 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
|
|||
}
|
||||
GLBE_SelectMode(BEM_STANDARD);
|
||||
|
||||
GLR_DrawPortal(batch, worldlist);
|
||||
GLR_DrawPortal(batch, worldlist, 0);
|
||||
|
||||
/*clear depth again*/
|
||||
GL_ForceDepthWritable();
|
||||
|
@ -3600,9 +3594,9 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT))
|
||||
if (batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP))
|
||||
{
|
||||
//these two flags require rendering some view as an fbo
|
||||
//these flags require rendering some view as an fbo
|
||||
if (r_refdef.recurse)
|
||||
return;
|
||||
|
||||
|
@ -3610,39 +3604,70 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
{
|
||||
if (!shaderstate.tex_reflection.num)
|
||||
{
|
||||
shaderstate.tex_reflection = GL_AllocNewTexture("***tex_reflection***", vid.pixelwidth, vid.pixelheight);
|
||||
shaderstate.tex_reflection = GL_AllocNewTexture("***tex_reflection***", vid.pixelwidth/2, vid.pixelheight/2);
|
||||
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection);
|
||||
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
GL_ForceDepthWritable();
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_reflection, true);
|
||||
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
|
||||
GL_ForceDepthWritable();
|
||||
qglClear(GL_DEPTH_BUFFER_BIT);
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches);
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches, 1);
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, false);
|
||||
qglViewport (0, 0, vid.pixelwidth, vid.pixelheight);
|
||||
}
|
||||
if (batch->shader->flags & SHADER_HASREFRACT)
|
||||
{
|
||||
if (!shaderstate.tex_refraction.num)
|
||||
{
|
||||
shaderstate.tex_refraction = GL_AllocNewTexture("***tex_refraction***", vid.pixelwidth, vid.pixelheight);
|
||||
shaderstate.tex_refraction = GL_AllocNewTexture("***tex_refraction***", vid.pixelwidth/2, vid.pixelheight/2);
|
||||
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction);
|
||||
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
GL_ForceDepthWritable();
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_refraction, true);
|
||||
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
|
||||
GL_ForceDepthWritable();
|
||||
qglClear(GL_DEPTH_BUFFER_BIT);
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches);
|
||||
GLR_DrawPortal(batch, cl.worldmodel->batches, 2);
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, false);
|
||||
|
||||
qglViewport (0, 0, vid.pixelwidth, vid.pixelheight);
|
||||
}
|
||||
if (batch->shader->flags & SHADER_HASRIPPLEMAP)
|
||||
{
|
||||
if (!shaderstate.tex_ripplemap.num)
|
||||
{
|
||||
shaderstate.tex_ripplemap = GL_AllocNewTexture("***tex_ripplemap***", vid.pixelwidth/2, vid.pixelheight/2);
|
||||
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap);
|
||||
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_ripplemap, false);
|
||||
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
|
||||
qglClearColor(0, 0, 0, 0);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// r_refdef.waterheight = DotProduct(batch->mesh[0]->xyz_array[0], batch->mesh[0]->normals_array[0]);
|
||||
|
||||
r_refdef.recurse = true; //paranoid, should stop potential infinite loops
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE);
|
||||
r_refdef.recurse = false;
|
||||
GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, false);
|
||||
|
||||
qglViewport (0, 0, vid.pixelwidth, vid.pixelheight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3650,7 +3675,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
|
|||
}
|
||||
}
|
||||
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, batch_t **blist, int start, int stop)
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop)
|
||||
{
|
||||
model_t *model = cl.worldmodel;
|
||||
int i;
|
||||
|
@ -3660,11 +3685,11 @@ void GLBE_SubmitMeshes (qboolean drawworld, batch_t **blist, int start, int stop
|
|||
if (drawworld)
|
||||
{
|
||||
if (i == SHADER_SORT_PORTAL && !r_noportals.ival && !r_refdef.recurse)
|
||||
GLBE_SubmitMeshesPortals(model->batches, blist[i]);
|
||||
GLBE_SubmitMeshesPortals(model->batches, shaderstate.mbatches[i]);
|
||||
|
||||
GLBE_SubmitMeshesSortList(model->batches[i]);
|
||||
}
|
||||
GLBE_SubmitMeshesSortList(blist[i]);
|
||||
GLBE_SubmitMeshesSortList(shaderstate.mbatches[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3736,9 +3761,12 @@ batch_t *GLBE_GetTempBatch(void)
|
|||
void GLBE_BaseEntTextures(void)
|
||||
{
|
||||
batch_t *batches[SHADER_SORT_COUNT];
|
||||
batch_t **ob = shaderstate.mbatches;
|
||||
shaderstate.mbatches = batches;
|
||||
BE_GenModelBatches(batches);
|
||||
GLBE_SubmitMeshes(false, batches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
shaderstate.mbatches = ob;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3762,7 +3790,7 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
|
|||
//create an unnamed depth buffer
|
||||
qglGenRenderbuffersEXT(1, &drb);
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, drb);
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth, vid.pixelheight);
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth/2, vid.pixelheight/2);
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb);
|
||||
// qglDeleteRenderbuffersEXT(1, &drb);
|
||||
|
||||
|
@ -3790,7 +3818,7 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
|
|||
}
|
||||
}
|
||||
|
||||
void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
||||
void GLBE_DrawLightPrePass(qbyte *vis)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
if (!shaderstate.initeddepthnorm)
|
||||
|
@ -3814,7 +3842,7 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
|||
}
|
||||
/*do portals*/
|
||||
BE_SelectMode(BEM_STANDARD);
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
|
||||
|
||||
BE_SelectMode(BEM_DEPTHNORM);
|
||||
if (!shaderstate.depthnormshader)
|
||||
|
@ -3823,8 +3851,6 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
|||
return;
|
||||
}
|
||||
|
||||
#define GL_RGBA16F_ARB 0x881A
|
||||
#define GL_RGBA32F_ARB 0x8814
|
||||
if (!TEXVALID(shaderstate.tex_normals))
|
||||
{
|
||||
shaderstate.tex_normals = GL_AllocNewTexture("***prepass normals***", vid.pixelwidth, vid.pixelheight);
|
||||
|
@ -3883,7 +3909,7 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
|||
}
|
||||
|
||||
/*draw surfaces that can be drawn this way*/
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
|
||||
|
||||
/*reconfigure - now drawing diffuse light info using the previous fb image as a source image*/
|
||||
shaderstate.tex_sourcecol = shaderstate.tex_normals;
|
||||
|
@ -3895,7 +3921,7 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
|||
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
/*now draw the prelights*/
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT);
|
||||
|
||||
/*final reconfigure - now drawing final surface data onto true framebuffer*/
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
@ -3904,12 +3930,12 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
|
|||
|
||||
/*now draw the postlight passes (this includes blended stuff which will NOT be lit)*/
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_SKY, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_SKY, SHADER_SORT_NEAREST);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
/*regular lighting now*/
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(vis, batches);
|
||||
Sh_DrawLights(vis);
|
||||
#endif
|
||||
|
||||
shaderstate.tex_sourcecol = r_nulltex;
|
||||
|
@ -3922,7 +3948,9 @@ void GLBE_DrawWorld (qbyte *vis)
|
|||
{
|
||||
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps;
|
||||
batch_t *batches[SHADER_SORT_COUNT];
|
||||
batch_t **ob = shaderstate.mbatches;
|
||||
RSpeedLocals();
|
||||
shaderstate.mbatches = batches;
|
||||
|
||||
GL_DoSwap();
|
||||
|
||||
|
@ -4003,7 +4031,7 @@ void GLBE_DrawWorld (qbyte *vis)
|
|||
#ifdef RTLIGHTS
|
||||
if (r_lightprepass.ival)
|
||||
{
|
||||
GLBE_DrawLightPrePass(vis, batches);
|
||||
GLBE_DrawLightPrePass(vis);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -4014,20 +4042,20 @@ void GLBE_DrawWorld (qbyte *vis)
|
|||
BE_SelectMode(BEM_STANDARD);
|
||||
|
||||
RSpeedRemark();
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
|
||||
RSpeedEnd(RSPEED_WORLD);
|
||||
}
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
RSpeedRemark();
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
Sh_DrawLights(vis, batches);
|
||||
Sh_DrawLights(vis);
|
||||
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
||||
#endif
|
||||
|
||||
shaderstate.identitylighting = 1;
|
||||
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_DECAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_DECAL, SHADER_SORT_NEAREST);
|
||||
|
||||
/* if (r_refdef.gfog_alpha)
|
||||
{
|
||||
|
@ -4039,12 +4067,14 @@ void GLBE_DrawWorld (qbyte *vis)
|
|||
}
|
||||
else
|
||||
{
|
||||
GLBE_SubmitMeshes(false, batches, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
}
|
||||
|
||||
BE_SelectEntity(&r_worldentity);
|
||||
shaderstate.curtime = shaderstate.updatetime = realtime;
|
||||
|
||||
shaderstate.identitylighting = 1;
|
||||
|
||||
shaderstate.mbatches = ob;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -420,7 +420,6 @@ void GLDraw_Init (void)
|
|||
memset(gltexturetablebuckets, 0, sizeof(gltexturetablebuckets));
|
||||
Hash_InitTable(&gltexturetable, sizeof(gltexturetablebuckets)/sizeof(gltexturetablebuckets[0]), gltexturetablebuckets);
|
||||
|
||||
GL_FlushBackEnd();
|
||||
// GL_FlushSkinCache();
|
||||
TRACE(("dbg: GLDraw_ReInit: GL_GAliasFlushSkinCache\n"));
|
||||
GL_GAliasFlushSkinCache();
|
||||
|
|
|
@ -776,8 +776,9 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
|
|||
outbuf = BZ_Malloc(8*8*256*8);
|
||||
|
||||
out = outbuf;
|
||||
i = 0;
|
||||
/*read the low chars*/
|
||||
for (i = 0; i < 8*8*(iso88591?2:1); i+=1)
|
||||
for (; i < 8*8*1; i+=1)
|
||||
{
|
||||
if (i&(1<<3))
|
||||
in = tempchars + (i>>3)*16*8*8+(i&7)*32*8 - 256*4+128;
|
||||
|
@ -786,15 +787,42 @@ static texid_t Font_LoadHexen2Conchars(qboolean iso88591)
|
|||
for (x = 0; x < 16*8; x++)
|
||||
*out++ = *in++;
|
||||
}
|
||||
/*read the high chars*/
|
||||
for (; i < 8*8*2; i+=1)
|
||||
if (iso88591)
|
||||
{
|
||||
if (i&(1<<3))
|
||||
in = tempchars+128*128 + ((i>>3)&15)*16*8*8+(i&7)*32*8 - 256*4+128;
|
||||
else
|
||||
in = tempchars+128*128 + ((i>>3)&15)*16*8*8+(i&7)*32*8;
|
||||
for (x = 0; x < 16*8; x++)
|
||||
*out++ = *in++;
|
||||
/*read the non 8859-1 quake-compat control chars*/
|
||||
for (; i < 8*8*1 + 16; i+=1)
|
||||
{
|
||||
if (i&(1<<3))
|
||||
in = tempchars+128*128 + ((i>>3)&7)*16*8*8+(i&7)*32*8 - 256*4+128;
|
||||
else
|
||||
in = tempchars+128*128 + ((i>>3)&7)*16*8*8+(i&7)*32*8;
|
||||
for (x = 0; x < 16*8; x++)
|
||||
*out++ = *in++;
|
||||
}
|
||||
|
||||
/*read the final low chars (final if 8859-1 anyway)*/
|
||||
for (; i < 8*8*2; i+=1)
|
||||
{
|
||||
if (i&(1<<3))
|
||||
in = tempchars + (i>>3)*16*8*8+(i&7)*32*8 - 256*4+128;
|
||||
else
|
||||
in = tempchars + (i>>3)*16*8*8+(i&7)*32*8;
|
||||
for (x = 0; x < 16*8; x++)
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*read the high chars*/
|
||||
for (; i < 8*8*2; i+=1)
|
||||
{
|
||||
if (i&(1<<3))
|
||||
in = tempchars+128*128 + ((i>>3)&15)*16*8*8+(i&7)*32*8 - 256*4+128;
|
||||
else
|
||||
in = tempchars+128*128 + ((i>>3)&15)*16*8*8+(i&7)*32*8;
|
||||
for (x = 0; x < 16*8; x++)
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
FS_FreeFile(tempchars);
|
||||
|
||||
|
@ -846,7 +874,7 @@ static texid_t Font_LoadDefaultConchars(void)
|
|||
tex = Font_LoadQuakeConchars();
|
||||
if (TEXVALID(tex))
|
||||
return tex;
|
||||
tex = Font_LoadHexen2Conchars(false);
|
||||
tex = Font_LoadHexen2Conchars(true);
|
||||
if (TEXVALID(tex))
|
||||
return tex;
|
||||
tex = Font_LoadFallbackConchars();
|
||||
|
@ -1065,7 +1093,7 @@ struct font_s *Font_LoadFont(int height, char *fontfilename)
|
|||
|
||||
if (!strcmp(fontfilename, "gfx/hexen2"))
|
||||
{
|
||||
f->singletexture = Font_LoadHexen2Conchars(true);
|
||||
f->singletexture = Font_LoadHexen2Conchars(false);
|
||||
defaultplane = DEFAULTPLANE;
|
||||
}
|
||||
if (!TEXVALID(f->singletexture))
|
||||
|
|
|
@ -32,6 +32,7 @@ struct world_s;
|
|||
|
||||
typedef enum {
|
||||
SHADER_SORT_NONE,
|
||||
SHADER_SORT_RIPPLE,
|
||||
SHADER_SORT_PRELIGHT,
|
||||
SHADER_SORT_PORTAL,
|
||||
SHADER_SORT_SKY,
|
||||
|
|
|
@ -437,7 +437,7 @@ void R_SetupGL (void)
|
|||
else
|
||||
{
|
||||
if (gl_maxdist.value>=1)
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -fov_x/2, fov_x/2, fov_y/2, -fov_y/2, -gl_maxdist.value, gl_maxdist.value);
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, -gl_maxdist.value, gl_maxdist.value);
|
||||
else
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, r_refdef.vrect.width, 0, r_refdef.vrect.height, -9999, 9999);
|
||||
}
|
||||
|
@ -637,7 +637,7 @@ static void TransformDir(vec3_t in, vec3_t planea[3], vec3_t viewa[3], vec3_t re
|
|||
VectorMA(result, d, viewa[i], result);
|
||||
}
|
||||
}
|
||||
void GLR_DrawPortal(batch_t *batch, batch_t **blist)
|
||||
void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype)
|
||||
{
|
||||
entity_t *view;
|
||||
GLdouble glplane[4];
|
||||
|
@ -663,7 +663,6 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist)
|
|||
if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < 0)
|
||||
return;
|
||||
|
||||
view = R_NearestPortal(&plane);
|
||||
//if (!view)
|
||||
// return;
|
||||
|
||||
|
@ -672,7 +671,20 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist)
|
|||
|
||||
r_refdef.externalview = true;
|
||||
|
||||
if (!view || VectorCompare(view->origin, view->oldorigin))
|
||||
if (portaltype == 1)
|
||||
{
|
||||
/*explicit mirror*/
|
||||
r_refdef.flipcull ^= true;
|
||||
R_MirrorMatrix(&plane);
|
||||
}
|
||||
else if (portaltype == 2)
|
||||
{
|
||||
/*refraction image (same view, just with things culled*/
|
||||
r_refdef.externalview = false;
|
||||
VectorNegate(plane.normal, plane.normal);
|
||||
plane.dist = -plane.dist;
|
||||
}
|
||||
else if (!(view = R_NearestPortal(&plane)) || VectorCompare(view->origin, view->oldorigin))
|
||||
{
|
||||
r_refdef.flipcull ^= true;
|
||||
R_MirrorMatrix(&plane);
|
||||
|
|
|
@ -766,6 +766,8 @@ static void Shader_Sort ( shader_t *shader, shaderpass_t *pass, char **ptr )
|
|||
shader->sort = SHADER_SORT_BLEND;
|
||||
else if ( !Q_stricmp( token, "lpp_light" ) )
|
||||
shader->sort = SHADER_SORT_PRELIGHT;
|
||||
else if ( !Q_stricmp( token, "ripple" ) )
|
||||
shader->sort = SHADER_SORT_RIPPLE;
|
||||
else
|
||||
{
|
||||
shader->sort = atoi ( token );
|
||||
|
@ -2205,6 +2207,12 @@ static qboolean ShaderPass_MapGen (shader_t *shader, shaderpass_t *pass, char *t
|
|||
pass->texgen = T_GEN_REFRACTION;
|
||||
pass->tcgen = TC_GEN_BASE; //FIXME: moo!
|
||||
}
|
||||
else if (!Q_stricmp (tname, "$ripplemap"))
|
||||
{
|
||||
shader->flags |= SHADER_HASRIPPLEMAP;
|
||||
pass->texgen = T_GEN_RIPPLEMAP;
|
||||
pass->tcgen = TC_GEN_BASE; //FIXME: moo!
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
|
@ -4196,73 +4204,114 @@ void Shader_DefaultBSPQ1(char *shortname, shader_t *s, const void *args)
|
|||
|
||||
if (!builtin && (*shortname == '*'))
|
||||
{
|
||||
if ((r_water_refract.ival || r_water_reflect.ival) && !r_fastturb.ival && strncmp(shortname, "*lava", 5))
|
||||
int wstyle;
|
||||
if (r_wateralpha.value == 0)
|
||||
wstyle = -1;
|
||||
else if (r_fastturb.ival)
|
||||
wstyle = 0;
|
||||
else if (gl_config.arb_shader_objects && r_waterstyle.ival>0 && !r_fastturb.ival && strncmp(shortname, "*lava", 5))
|
||||
wstyle = r_waterstyle.ival; //r_waterstyle does not apply to lava, and requires glsl and stuff
|
||||
else
|
||||
wstyle = 1;
|
||||
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
switch(wstyle)
|
||||
{
|
||||
case -1: //invisible
|
||||
builtin = (
|
||||
"{\n"
|
||||
"map $currentrender\n"
|
||||
"sort blend\n"
|
||||
"surfaceparm nodraw\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
break;
|
||||
case 0: //fastturb
|
||||
builtin = (
|
||||
"{\n"
|
||||
"map $normalmap\n"
|
||||
"sort blend\n"
|
||||
"{\n"
|
||||
"map $whiteimage\n"
|
||||
"rgbgen const $r_fastturbcolour\n"
|
||||
"}\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
case 1: //vanilla style
|
||||
builtin = (
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"sort blend\n" /*make sure it always has the same sort order, so switching on/off wateralpha doesn't break stuff*/
|
||||
"program defaultwarp\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"tcmod turb 0.02 0.1 0.5 0.1\n"
|
||||
"if r_wateralpha != 1\n"
|
||||
"[\n"
|
||||
"alphagen const $r_wateralpha\n"
|
||||
"blendfunc gl_src_alpha gl_one_minus_src_alpha\n"
|
||||
"]\n"
|
||||
"}\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
"if r_water_reflect\n"
|
||||
"[\n"
|
||||
);
|
||||
break;
|
||||
case 2: //refraction of the underwater surface, with a fresnel
|
||||
builtin = (
|
||||
"{\n"
|
||||
"{\n"
|
||||
"map $currentrender\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $normalmap\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"}\n"
|
||||
"program altwater#FRESNEL=4\n"
|
||||
"}\n"
|
||||
);
|
||||
break;
|
||||
case 3: //ripples
|
||||
builtin = (
|
||||
"{\n"
|
||||
"{\n"
|
||||
"map $currentrender\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $normalmap\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $ripplemap\n"
|
||||
"}\n"
|
||||
"program altwater#RIPPLEMAP#FRESNEL=4\n"
|
||||
"}\n"
|
||||
);
|
||||
break;
|
||||
case 4: //reflections
|
||||
builtin = (
|
||||
"{\n"
|
||||
"{\n"
|
||||
"map $currentrender\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $normalmap\n"
|
||||
"}\n"
|
||||
"{\n"
|
||||
"map $reflection\n"
|
||||
"}\n"
|
||||
"program altwater#REFLECT#FRESNEL=4\n"
|
||||
"][\n"
|
||||
"program altwater#FRESNEL=4\n"
|
||||
"]\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
//q1 water
|
||||
else if (r_wateralpha.value == 0)
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
"sort blend\n"
|
||||
"surfaceparm nodraw\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
else if (r_fastturb.ival)
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
"sort blend\n"
|
||||
"{\n"
|
||||
"map $whiteimage\n"
|
||||
"rgbgen const $r_fastturbcolour\n"
|
||||
"{\n"
|
||||
"map $ripplemap\n"
|
||||
"}\n"
|
||||
"program altwater#REFLECT#RIPPLEMAP#FRESNEL=4\n"
|
||||
"}\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin = (
|
||||
"{\n"
|
||||
"sort blend\n" /*make sure it always has the same sort order, so switching on/off wateralpha doesn't break stuff*/
|
||||
"program defaultwarp\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"tcmod turb 0.02 0.1 0.5 0.1\n"
|
||||
"if r_wateralpha != 1\n"
|
||||
"[\n"
|
||||
"alphagen const $r_wateralpha\n"
|
||||
"blendfunc gl_src_alpha gl_one_minus_src_alpha\n"
|
||||
"]\n"
|
||||
"}\n"
|
||||
"surfaceparm nodlight\n"
|
||||
"}\n"
|
||||
);
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!builtin && !strncmp(shortname, "sky", 3))
|
||||
|
|
|
@ -2749,10 +2749,10 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
|
|||
Sh_DrawEntLighting(dl, colour);
|
||||
}
|
||||
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, batch_t **blist, int start, int stop);
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop);
|
||||
void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, qboolean usedepth);
|
||||
|
||||
void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours, batch_t **batches)
|
||||
void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
|
||||
{
|
||||
#ifdef GLQUAKE
|
||||
static mesh_t mesh;
|
||||
|
@ -2822,7 +2822,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours, batch_t **batches)
|
|||
|
||||
BE_SelectMode(BEM_CREPUSCULAR);
|
||||
BE_SelectDLight(dl, colours);
|
||||
GLBE_SubmitMeshes(true, batches, SHADER_SORT_PORTAL, SHADER_SORT_BLEND);
|
||||
GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_BLEND);
|
||||
|
||||
GLBE_RenderToTexture(crepuscular_texture_id, r_nulltex, r_nulltex, false);
|
||||
|
||||
|
@ -2894,7 +2894,7 @@ void Com_ParseVector(char *str, vec3_t out)
|
|||
out[2] = atof(com_token);
|
||||
}
|
||||
|
||||
void Sh_DrawLights(qbyte *vis, batch_t **mbatches)
|
||||
void Sh_DrawLights(qbyte *vis)
|
||||
{
|
||||
vec3_t colour;
|
||||
dlight_t *dl;
|
||||
|
@ -2969,7 +2969,7 @@ void Sh_DrawLights(qbyte *vis, batch_t **mbatches)
|
|||
continue; //just switch these off.
|
||||
|
||||
if (dl->flags & LFLAG_CREPUSCULAR)
|
||||
Sh_DrawCrepuscularLight(dl, colour, mbatches);
|
||||
Sh_DrawCrepuscularLight(dl, colour);
|
||||
else if (((i >= RTL_FIRST)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || dl->flags & LFLAG_NOSHADOWS)
|
||||
{
|
||||
Sh_DrawShadowlessLight(dl, colour, vis);
|
||||
|
@ -3014,7 +3014,7 @@ void Sh_DrawLights(qbyte *vis, batch_t **mbatches)
|
|||
{
|
||||
VectorNormalize(sundir);
|
||||
VectorMA(r_origin, 1000, sundir, sun.origin);
|
||||
Sh_DrawCrepuscularLight(&sun, colour, mbatches);
|
||||
Sh_DrawCrepuscularLight(&sun, colour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,7 +313,6 @@ void GL_MTBind(int tmu, int target, texid_t texnum); /*use this if you're going
|
|||
void GL_LazyBind(int tmu, int target, texid_t texnum); /*use this if you don't care about the active tmu, only that it is bound on that tmu (does not guarentee glActiveTexture) (ie: no glTexImage etc)*/
|
||||
void GL_CullFace(unsigned int sflags);
|
||||
void GL_TexEnv(GLenum mode);
|
||||
void GL_FlushBackEnd (void);
|
||||
|
||||
// Multitexture
|
||||
#define GL_TEXTURE0_SGIS 0x835E
|
||||
|
@ -355,7 +354,6 @@ void GL_DoSwap (void);
|
|||
// gl_backend.c
|
||||
//
|
||||
#ifdef GLQUAKE
|
||||
void FTE_DEPRECATED R_BackendInit(void);
|
||||
void FTE_DEPRECATED R_IBrokeTheArrays(void);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -707,5 +707,9 @@ typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
|
|||
#define GL_TEXTURE_MAX_LEVEL 0x813d
|
||||
#endif
|
||||
|
||||
#ifndef GL_RGBA16F_ARB
|
||||
#define GL_RGBA16F_ARB 0x881A
|
||||
#define GL_RGBA32F_ARB 0x8814
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -229,6 +229,7 @@ typedef struct shaderpass_s {
|
|||
|
||||
T_GEN_REFLECTION, //reflection image (mirror-as-fbo)
|
||||
T_GEN_REFRACTION, //refraction image (portal-as-fbo)
|
||||
T_GEN_RIPPLEMAP, //ripplemap image (water surface distortions-as-fbo)
|
||||
|
||||
T_GEN_SOURCECUBE, //used for render-to-texture targets
|
||||
|
||||
|
@ -421,7 +422,8 @@ struct shader_s
|
|||
SHADER_STATICDATA = 1 << 18, //set if true: no deforms, no tcgen, rgbgen=identitylighting, alphagen=identity, tmu0=st + tmu1=lm(if available) for every pass, no norms
|
||||
SHADER_HASREFLECT = 1 << 19, //says that we need to generate a reflection image first
|
||||
SHADER_HASREFRACT = 1 << 20, //says that we need to generate a refraction image first
|
||||
SHADER_HASNORMALMAP = 1 << 21 //says that we need to load a normalmap texture
|
||||
SHADER_HASNORMALMAP = 1 << 21, //says that we need to load a normalmap texture
|
||||
SHADER_HASRIPPLEMAP = 1 << 22, //water surface disturbances for water splashes
|
||||
} flags;
|
||||
|
||||
program_t *prog;
|
||||
|
@ -465,7 +467,6 @@ void Shader_DefaultCinematic(char *shortname, shader_t *s, const void *args);
|
|||
void Shader_DefaultScript(char *shortname, shader_t *s, const void *args);
|
||||
|
||||
void Shader_DoReload(void);
|
||||
void R_BackendInit (void);
|
||||
void Shader_Shutdown (void);
|
||||
qboolean Shader_Init (void);
|
||||
void Shader_NeedReload(qboolean rescanfs);
|
||||
|
@ -497,6 +498,7 @@ void GLBE_DrawWorld (qbyte *vis);
|
|||
qboolean GLBE_LightCullModel(vec3_t org, model_t *model);
|
||||
void GLBE_SelectEntity(entity_t *ent);
|
||||
void GLBE_SelectDLight(dlight_t *dl, vec3_t colour);
|
||||
void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop);
|
||||
#endif
|
||||
#ifdef D3DQUAKE
|
||||
void D3DBE_Init(void);
|
||||
|
@ -535,7 +537,7 @@ void D3DBE_BaseEntTextures(void);
|
|||
//prebuilds shadow volumes
|
||||
void Sh_PreGenerateLights(void);
|
||||
//Draws lights, called from the backend
|
||||
void Sh_DrawLights(qbyte *vis, batch_t **mbatches);
|
||||
void Sh_DrawLights(qbyte *vis);
|
||||
void SH_FreeShadowMesh(struct shadowmesh_s *sm);
|
||||
void Sh_Shutdown(void);
|
||||
//Draws the depth of ents in the world near the current light
|
||||
|
|
|
@ -3145,6 +3145,12 @@ qbyte *SV_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsiz
|
|||
vec3_t org;
|
||||
int leavepvs = false;
|
||||
|
||||
if (r_novis.ival)
|
||||
{
|
||||
memset(pvs, 0xff, (sv.world.worldmodel->numleafs+31)>>3);
|
||||
return pvs;
|
||||
}
|
||||
|
||||
for (; client; client = client->controlled)
|
||||
{
|
||||
if (client->viewent)
|
||||
|
|
|
@ -470,7 +470,7 @@ void SV_DropClient (client_t *drop)
|
|||
case GT_PROGS:
|
||||
if (svprogfuncs)
|
||||
{
|
||||
if (drop->state == cs_spawned)
|
||||
if (drop->state == cs_spawned && host_initialized)
|
||||
{
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype == GT_Q1QVM)
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
//modifier: REFLECT
|
||||
//modifier: REFLECT (s_t2 is a reflection instead of diffusemap)
|
||||
//modifier: STRENGTH (0.1 = fairly gentle, 0.2 = big waves)
|
||||
//modifier: FRESNEL (5=water)
|
||||
//modifier: TXSCALE (0.2 - wave strength)
|
||||
//modifier: RIPPLEMAP (s_t3 contains a ripplemap
|
||||
//modifier: TINT (some colour value)
|
||||
|
||||
#ifndef FRESNEL
|
||||
#define FRESNEL 5.0
|
||||
#endif
|
||||
#ifndef STRENGTH
|
||||
#define STRENGTH 0.1
|
||||
#endif
|
||||
#ifndef TXSCALE
|
||||
#define TXSCALE 0.2
|
||||
#endif
|
||||
#ifndef TINT
|
||||
#define TINT vec3(0.7, 0.8, 0.7)
|
||||
#endif
|
||||
|
||||
varying vec2 tc;
|
||||
varying vec4 tf;
|
||||
|
@ -21,9 +38,9 @@ void main (void)
|
|||
#ifdef FRAGMENT_SHADER
|
||||
uniform sampler2D s_t0; //refract
|
||||
uniform sampler2D s_t1; //normalmap
|
||||
uniform sampler2D s_t2; //diffuse
|
||||
#ifdef REFLECT
|
||||
uniform sampler2D s_t3; //reflect
|
||||
uniform sampler2D s_t2; //diffuse/reflection
|
||||
#ifdef RIPPLEMAP
|
||||
uniform sampler2D s_t3; //ripplemap
|
||||
#endif
|
||||
|
||||
uniform float e_time;
|
||||
|
@ -39,27 +56,29 @@ void main (void)
|
|||
ntc.t = tc.t + sin(tc.s+e_time)*0.125;
|
||||
|
||||
//generate the two wave patterns from the normalmap
|
||||
n = (texture2D(s_t1, 0.2*tc + vec2(e_time*0.1, 0)).xyz);
|
||||
n += (texture2D(s_t1, 0.2*tc - vec2(0, e_time*0.097)).xyz);
|
||||
n = (texture2D(s_t1, TXSCALE*tc + vec2(e_time*0.1, 0)).xyz);
|
||||
n += (texture2D(s_t1, TXSCALE*tc - vec2(0, e_time*0.097)).xyz);
|
||||
n -= 1.0 - 4.0/256.0;
|
||||
|
||||
n = normalize(n);
|
||||
|
||||
#if 1//def REFRACT
|
||||
refr = texture2D(s_t0, stc + n.st*0.2).rgb;
|
||||
#else
|
||||
refr = texture2D(s_t2, ntc).xyz;
|
||||
#endif
|
||||
#ifdef REFLECT
|
||||
refl = texture2D(s_t3, stc - n.st*0.2).rgb;
|
||||
#else
|
||||
refl = texture2D(s_t2, ntc).xyz;
|
||||
#ifdef RIPPLEMAP
|
||||
n += texture2D(s_t3, stc)*3;
|
||||
#endif
|
||||
|
||||
//the fresnel term decides how transparent the water should be
|
||||
f = pow(1.0-abs(dot(n, normalize(eye))), float(FRESNEL));
|
||||
f = pow(1.0-abs(dot(normalize(n), normalize(eye))), float(FRESNEL));
|
||||
|
||||
refr = texture2D(s_t0, stc + n.st*STRENGTH).rgb * TINT;
|
||||
#ifdef REFLECT
|
||||
refl = texture2D(s_t2, stc - n.st*STRENGTH).rgb;
|
||||
#else
|
||||
refl = texture2D(s_t2, ntc).xyz;
|
||||
#endif
|
||||
// refl += 0.1*pow(dot(n, vec3(0.0,0.0,1.0)), 64.0);
|
||||
|
||||
fres = refr * (1.0-f) + refl*f;
|
||||
|
||||
// fres = texture2D(s_t2, stc).xyz;
|
||||
|
||||
gl_FragColor = vec4(fres, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
|
150
engine/sw/sw.h
Normal file
150
engine/sw/sw.h
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
texcom_t com;
|
||||
|
||||
char name[64];
|
||||
int width;
|
||||
int height;
|
||||
int pitch;
|
||||
unsigned int data[1];
|
||||
} swimage_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile unsigned int readpoint; //the command queue point its reading from
|
||||
void *thread;
|
||||
|
||||
#ifdef _DEBUG
|
||||
float idletime;
|
||||
float activetime;
|
||||
#endif
|
||||
|
||||
unsigned int interlaceline;
|
||||
unsigned int interlacemod;
|
||||
unsigned int threadnum; //for relocating viewport info
|
||||
unsigned int *vpdbuf;
|
||||
unsigned int *vpcbuf;
|
||||
unsigned int vpwidth;
|
||||
unsigned int vpheight;
|
||||
qintptr_t vpcstride;
|
||||
} swthread_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec4_t vcoord;
|
||||
vec2_t tccoord;
|
||||
vec2_t lmcoord;
|
||||
byte_vec4_t colour;
|
||||
unsigned int clipflags; /*1=left,2=right,4=top,8=bottom,16=near*/
|
||||
} swvert_t;
|
||||
|
||||
swthread_t *SWRast_CreateThread(int tno);
|
||||
|
||||
|
||||
enum wqcmd_e
|
||||
{
|
||||
WTC_DIE,
|
||||
WTC_SYNC,
|
||||
WTC_NEWFRAME,
|
||||
WTC_NOOP,
|
||||
WTC_VIEWPORT,
|
||||
WTC_TRIFAN,
|
||||
WTC_TRISOUP
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CLIP_LEFT_FLAG = 1,
|
||||
CLIP_RIGHT_FLAG = 2,
|
||||
CLIP_TOP_FLAG = 4,
|
||||
CLIP_BOTTOM_FLAG = 8,
|
||||
CLIP_NEAR_FLAG = 16
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char align[16];
|
||||
|
||||
struct wqcom_s
|
||||
{
|
||||
enum wqcmd_e command;
|
||||
unsigned int cmdsize;
|
||||
} com;
|
||||
struct
|
||||
{
|
||||
struct wqcom_s com;
|
||||
|
||||
swimage_t *texture;
|
||||
int numverts;
|
||||
swvert_t verts[1];
|
||||
} trifan;
|
||||
struct
|
||||
{
|
||||
struct wqcom_s com;
|
||||
|
||||
swimage_t *texture;
|
||||
int numverts;
|
||||
int numidx;
|
||||
swvert_t verts[1];
|
||||
} trisoup;
|
||||
struct
|
||||
{
|
||||
struct wqcom_s com;
|
||||
unsigned int *cbuf;
|
||||
unsigned int *dbuf;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
qintptr_t stride;
|
||||
unsigned int interlace;
|
||||
unsigned int framenum;
|
||||
|
||||
qboolean cleardepth;
|
||||
qboolean clearcolour;
|
||||
} viewport;
|
||||
} wqcom_t;
|
||||
|
||||
|
||||
|
||||
void SWRast_EndCommand(wqcom_t *com);
|
||||
wqcom_t *SWRast_BeginCommand(int cmdtype, unsigned int size);
|
||||
void SWRast_Sync(void);
|
||||
|
||||
|
||||
|
||||
qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette);
|
||||
void SW_VID_DeInit(void);
|
||||
void SW_VID_SetPalette(unsigned char *palette);
|
||||
void SW_VID_ShiftPalette(unsigned char *palette);
|
||||
char *SW_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidheight);
|
||||
void SW_VID_SetWindowCaption(char *msg);
|
||||
void SW_VID_SwapBuffers(void);
|
||||
void SW_VID_UpdateViewport(wqcom_t *com);
|
||||
|
||||
|
||||
|
||||
|
||||
texid_tf SW_LoadTexture(char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
|
||||
texid_tf SW_LoadTexture8Pal24(char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags);
|
||||
texid_tf SW_LoadTexture8Pal32(char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags);
|
||||
texid_tf SW_LoadCompressed(char *name);
|
||||
texid_tf SW_FindTexture(char *identifier);
|
||||
texid_tf SW_AllocNewTexture(char *identifier, int w, int h);
|
||||
void SW_Upload(texid_t tex, char *name, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
|
||||
void SW_DestroyTexture(texid_t tex);
|
||||
|
||||
|
||||
void SWBE_SelectMode(backendmode_t mode);
|
||||
void SWBE_DrawMesh_List(shader_t *shader, int nummeshes, struct mesh_s **mesh, struct vbo_s *vbo, struct texnums_s *texnums, unsigned int be_flags);
|
||||
void SWBE_DrawMesh_Single(shader_t *shader, struct mesh_s *meshchain, struct vbo_s *vbo, struct texnums_s *texnums, unsigned int be_flags);
|
||||
void SWBE_SubmitBatch(struct batch_s *batch);
|
||||
struct batch_s *SWBE_GetTempBatch(void);
|
||||
void SWBE_DrawWorld(qbyte *vis);
|
||||
void SWBE_Init(void);
|
||||
void SWBE_GenBrushModelVBO(struct model_s *mod);
|
||||
void SWBE_ClearVBO(struct vbo_s *vbo);
|
||||
void SWBE_UploadAllLightmaps(void);
|
||||
void SWBE_SelectEntity(struct entity_s *ent);
|
||||
void SWBE_SelectDLight(struct dlight_s *dl, vec3_t colour);
|
||||
qboolean SWBE_LightCullModel(vec3_t org, struct model_s *model);
|
||||
void SWBE_Set2D(void);
|
654
engine/sw/sw_backend.c
Normal file
654
engine/sw/sw_backend.c
Normal file
|
@ -0,0 +1,654 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef SWQUAKE
|
||||
#include "sw.h"
|
||||
#include "shader.h"
|
||||
#include "glquake.h"
|
||||
|
||||
vecV_t vertbuf[65535];
|
||||
|
||||
static struct
|
||||
{
|
||||
int foo;
|
||||
int numrthreads;
|
||||
void *threads[4];
|
||||
backendmode_t mode;
|
||||
|
||||
float m_mvp[16];
|
||||
|
||||
entity_t *curentity;
|
||||
shader_t *curshader;
|
||||
|
||||
float curtime;
|
||||
//this stuff should probably be moved out of the backend
|
||||
int wbatch;
|
||||
int maxwbatches;
|
||||
batch_t *wbatches;
|
||||
} shaderstate;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//start generic tables
|
||||
#define frand() (rand()*(1.0/RAND_MAX))
|
||||
#define FTABLE_SIZE 1024
|
||||
#define FTABLE_CLAMP(x) (((int)((x)*FTABLE_SIZE) & (FTABLE_SIZE-1)))
|
||||
#define FTABLE_EVALUATE(table,x) (table ? table[FTABLE_CLAMP(x)] : frand()*((x)-floor(x)))
|
||||
|
||||
static float r_sintable[FTABLE_SIZE];
|
||||
static float r_triangletable[FTABLE_SIZE];
|
||||
static float r_squaretable[FTABLE_SIZE];
|
||||
static float r_sawtoothtable[FTABLE_SIZE];
|
||||
static float r_inversesawtoothtable[FTABLE_SIZE];
|
||||
|
||||
static float *FTableForFunc ( unsigned int func )
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case SHADER_FUNC_SIN:
|
||||
return r_sintable;
|
||||
|
||||
case SHADER_FUNC_TRIANGLE:
|
||||
return r_triangletable;
|
||||
|
||||
case SHADER_FUNC_SQUARE:
|
||||
return r_squaretable;
|
||||
|
||||
case SHADER_FUNC_SAWTOOTH:
|
||||
return r_sawtoothtable;
|
||||
|
||||
case SHADER_FUNC_INVERSESAWTOOTH:
|
||||
return r_inversesawtoothtable;
|
||||
}
|
||||
|
||||
//bad values allow us to crash (so I can debug em)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void BE_InitTables(void)
|
||||
{
|
||||
int i;
|
||||
double t;
|
||||
for (i = 0; i < FTABLE_SIZE; i++)
|
||||
{
|
||||
t = (double)i / (double)FTABLE_SIZE;
|
||||
|
||||
r_sintable[i] = sin(t * 2*M_PI);
|
||||
|
||||
if (t < 0.25)
|
||||
r_triangletable[i] = t * 4.0;
|
||||
else if (t < 0.75)
|
||||
r_triangletable[i] = 2 - 4.0 * t;
|
||||
else
|
||||
r_triangletable[i] = (t - 0.75) * 4.0 - 1.0;
|
||||
|
||||
if (t < 0.5)
|
||||
r_squaretable[i] = 1.0f;
|
||||
else
|
||||
r_squaretable[i] = -1.0f;
|
||||
|
||||
r_sawtoothtable[i] = t;
|
||||
r_inversesawtoothtable[i] = 1.0 - t;
|
||||
}
|
||||
}
|
||||
#define R_FastSin(x) sin((x)*(2*M_PI)) //fixme: use r_sintable instead!
|
||||
|
||||
//end generic tables
|
||||
////////////////////////////////////////////////////////////////
|
||||
//start matrix functions
|
||||
|
||||
typedef vec3_t mat3_t[3];
|
||||
static mat3_t axisDefault={{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1}};
|
||||
|
||||
static void Matrix3_Transpose (mat3_t in, mat3_t out)
|
||||
{
|
||||
out[0][0] = in[0][0];
|
||||
out[1][1] = in[1][1];
|
||||
out[2][2] = in[2][2];
|
||||
|
||||
out[0][1] = in[1][0];
|
||||
out[0][2] = in[2][0];
|
||||
out[1][0] = in[0][1];
|
||||
out[1][2] = in[2][1];
|
||||
out[2][0] = in[0][2];
|
||||
out[2][1] = in[1][2];
|
||||
}
|
||||
static void Matrix3_Multiply_Vec3 (mat3_t a, vec3_t b, vec3_t product)
|
||||
{
|
||||
product[0] = a[0][0]*b[0] + a[0][1]*b[1] + a[0][2]*b[2];
|
||||
product[1] = a[1][0]*b[0] + a[1][1]*b[1] + a[1][2]*b[2];
|
||||
product[2] = a[2][0]*b[0] + a[2][1]*b[1] + a[2][2]*b[2];
|
||||
}
|
||||
|
||||
static int Matrix3_Compare(mat3_t in, mat3_t out)
|
||||
{
|
||||
return memcmp(in, out, sizeof(mat3_t));
|
||||
}
|
||||
|
||||
//end matrix functions
|
||||
////////////////////////////////////////////////////////////////
|
||||
//start xyz
|
||||
|
||||
static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *dst, const mesh_t *mesh)
|
||||
{
|
||||
float *table;
|
||||
int j, k;
|
||||
float args[4];
|
||||
float deflect;
|
||||
switch (deformv->type)
|
||||
{
|
||||
default:
|
||||
case DEFORMV_NONE:
|
||||
if (src != dst)
|
||||
memcpy(dst, src, sizeof(*src)*cnt);
|
||||
break;
|
||||
|
||||
case DEFORMV_WAVE:
|
||||
if (!mesh->normals_array)
|
||||
{
|
||||
if (src != dst)
|
||||
memcpy(dst, src, sizeof(*src)*cnt);
|
||||
return;
|
||||
}
|
||||
args[0] = deformv->func.args[0];
|
||||
args[1] = deformv->func.args[1];
|
||||
args[3] = deformv->func.args[2] + deformv->func.args[3] * shaderstate.curtime;
|
||||
table = FTableForFunc(deformv->func.type);
|
||||
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
{
|
||||
deflect = deformv->args[0] * (src[j][0]+src[j][1]+src[j][2]) + args[3];
|
||||
deflect = FTABLE_EVALUATE(table, deflect) * args[1] + args[0];
|
||||
|
||||
// Deflect vertex along its normal by wave amount
|
||||
VectorMA(src[j], deflect, mesh->normals_array[j], dst[j]);
|
||||
}
|
||||
break;
|
||||
|
||||
case DEFORMV_NORMAL:
|
||||
//normal does not actually move the verts, but it does change the normals array
|
||||
//we don't currently support that.
|
||||
if (src != dst)
|
||||
memcpy(dst, src, sizeof(*src)*cnt);
|
||||
/*
|
||||
args[0] = deformv->args[1] * shaderstate.curtime;
|
||||
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
{
|
||||
args[1] = normalsArray[j][2] * args[0];
|
||||
|
||||
deflect = deformv->args[0] * R_FastSin(args[1]);
|
||||
normalsArray[j][0] *= deflect;
|
||||
deflect = deformv->args[0] * R_FastSin(args[1] + 0.25);
|
||||
normalsArray[j][1] *= deflect;
|
||||
VectorNormalizeFast(normalsArray[j]);
|
||||
}
|
||||
*/ break;
|
||||
|
||||
case DEFORMV_MOVE:
|
||||
table = FTableForFunc(deformv->func.type);
|
||||
deflect = deformv->func.args[2] + shaderstate.curtime * deformv->func.args[3];
|
||||
deflect = FTABLE_EVALUATE(table, deflect) * deformv->func.args[1] + deformv->func.args[0];
|
||||
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
VectorMA(src[j], deflect, deformv->args, dst[j]);
|
||||
break;
|
||||
|
||||
case DEFORMV_BULGE:
|
||||
args[0] = deformv->args[0]/(2*M_PI);
|
||||
args[1] = deformv->args[1];
|
||||
args[2] = shaderstate.curtime * deformv->args[2]/(2*M_PI);
|
||||
|
||||
for (j = 0; j < cnt; j++)
|
||||
{
|
||||
deflect = R_FastSin(mesh->st_array[j][0]*args[0] + args[2])*args[1];
|
||||
dst[j][0] = src[j][0]+deflect*mesh->normals_array[j][0];
|
||||
dst[j][1] = src[j][1]+deflect*mesh->normals_array[j][1];
|
||||
dst[j][2] = src[j][2]+deflect*mesh->normals_array[j][2];
|
||||
}
|
||||
break;
|
||||
|
||||
case DEFORMV_AUTOSPRITE:
|
||||
if (mesh->numindexes < 6)
|
||||
break;
|
||||
|
||||
for (j = 0; j < cnt-3; j+=4, src+=4, dst+=4)
|
||||
{
|
||||
vec3_t mid, d;
|
||||
float radius;
|
||||
mid[0] = 0.25*(src[0][0] + src[1][0] + src[2][0] + src[3][0]);
|
||||
mid[1] = 0.25*(src[0][1] + src[1][1] + src[2][1] + src[3][1]);
|
||||
mid[2] = 0.25*(src[0][2] + src[1][2] + src[2][2] + src[3][2]);
|
||||
VectorSubtract(src[0], mid, d);
|
||||
radius = 2*VectorLength(d);
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
dst[k][0] = mid[0] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[0+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[0+1]);
|
||||
dst[k][1] = mid[1] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[4+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[4+1]);
|
||||
dst[k][2] = mid[2] + radius*((mesh->st_array[k][0]-0.5)*r_refdef.m_view[8+0]-(mesh->st_array[k][1]-0.5)*r_refdef.m_view[8+1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DEFORMV_AUTOSPRITE2:
|
||||
if (mesh->numindexes < 6)
|
||||
break;
|
||||
|
||||
for (k = 0; k < mesh->numindexes; k += 6)
|
||||
{
|
||||
int long_axis, short_axis;
|
||||
vec3_t axis;
|
||||
float len[3];
|
||||
mat3_t m0, m1, m2, result;
|
||||
float *quad[4];
|
||||
vec3_t rot_centre, tv;
|
||||
|
||||
quad[0] = (float *)(dst + mesh->indexes[k+0]);
|
||||
quad[1] = (float *)(dst + mesh->indexes[k+1]);
|
||||
quad[2] = (float *)(dst + mesh->indexes[k+2]);
|
||||
|
||||
for (j = 2; j >= 0; j--)
|
||||
{
|
||||
quad[3] = (float *)(dst + mesh->indexes[k+3+j]);
|
||||
if (!VectorEquals (quad[3], quad[0]) &&
|
||||
!VectorEquals (quad[3], quad[1]) &&
|
||||
!VectorEquals (quad[3], quad[2]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build a matrix were the longest axis of the billboard is the Y-Axis
|
||||
VectorSubtract(quad[1], quad[0], m0[0]);
|
||||
VectorSubtract(quad[2], quad[0], m0[1]);
|
||||
VectorSubtract(quad[2], quad[1], m0[2]);
|
||||
len[0] = DotProduct(m0[0], m0[0]);
|
||||
len[1] = DotProduct(m0[1], m0[1]);
|
||||
len[2] = DotProduct(m0[2], m0[2]);
|
||||
|
||||
if ((len[2] > len[1]) && (len[2] > len[0]))
|
||||
{
|
||||
if (len[1] > len[0])
|
||||
{
|
||||
long_axis = 1;
|
||||
short_axis = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
long_axis = 0;
|
||||
short_axis = 1;
|
||||
}
|
||||
}
|
||||
else if ((len[1] > len[2]) && (len[1] > len[0]))
|
||||
{
|
||||
if (len[2] > len[0])
|
||||
{
|
||||
long_axis = 2;
|
||||
short_axis = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
long_axis = 0;
|
||||
short_axis = 2;
|
||||
}
|
||||
}
|
||||
else //if ( (len[0] > len[1]) && (len[0] > len[2]) )
|
||||
{
|
||||
if (len[2] > len[1])
|
||||
{
|
||||
long_axis = 2;
|
||||
short_axis = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
long_axis = 1;
|
||||
short_axis = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (DotProduct(m0[long_axis], m0[short_axis]))
|
||||
{
|
||||
VectorNormalize2(m0[long_axis], axis);
|
||||
VectorCopy(axis, m0[1]);
|
||||
|
||||
if (axis[0] || axis[1])
|
||||
{
|
||||
VectorVectors(m0[1], m0[2], m0[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorVectors(m0[1], m0[0], m0[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorNormalize2(m0[long_axis], axis);
|
||||
VectorNormalize2(m0[short_axis], m0[0]);
|
||||
VectorCopy(axis, m0[1]);
|
||||
CrossProduct(m0[0], m0[1], m0[2]);
|
||||
}
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
rot_centre[j] = (quad[0][j] + quad[1][j] + quad[2][j] + quad[3][j]) * 0.25;
|
||||
|
||||
if (shaderstate.curentity)
|
||||
{
|
||||
VectorAdd(shaderstate.curentity->origin, rot_centre, tv);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy(rot_centre, tv);
|
||||
}
|
||||
VectorSubtract(r_origin, tv, tv);
|
||||
|
||||
// filter any longest-axis-parts off the camera-direction
|
||||
deflect = -DotProduct(tv, axis);
|
||||
|
||||
VectorMA(tv, deflect, axis, m1[2]);
|
||||
VectorNormalizeFast(m1[2]);
|
||||
VectorCopy(axis, m1[1]);
|
||||
CrossProduct(m1[1], m1[2], m1[0]);
|
||||
|
||||
Matrix3_Transpose(m1, m2);
|
||||
Matrix3_Multiply(m2, m0, result);
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
VectorSubtract(quad[j], rot_centre, tv);
|
||||
Matrix3_Multiply_Vec3(result, tv, quad[j]);
|
||||
VectorAdd(rot_centre, quad[j], quad[j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// case DEFORMV_PROJECTION_SHADOW:
|
||||
// break;
|
||||
}
|
||||
}
|
||||
//end xyz
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void SWBE_SelectMode(backendmode_t mode)
|
||||
{
|
||||
}
|
||||
|
||||
void SWBE_TransformVerticies(swvert_t *v, mesh_t *mesh)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
int i;
|
||||
|
||||
vecV_t *xyz;
|
||||
|
||||
/*generate vertex blends*/
|
||||
if (mesh->xyz2_array)
|
||||
{
|
||||
xyz = vertbuf;
|
||||
for (i = 0; i < mesh->numvertexes; i++)
|
||||
{
|
||||
VectorInterpolate(mesh->xyz_array[i], mesh->xyz_blendw[1], mesh->xyz2_array[i], xyz[i]);
|
||||
}
|
||||
}
|
||||
/*else if (skeletal)
|
||||
{
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
xyz = mesh->xyz_array;
|
||||
}
|
||||
|
||||
/*now apply any shader deforms*/
|
||||
if (shaderstate.curshader->numdeforms)
|
||||
{
|
||||
deformgen(&shaderstate.curshader->deforms[0], mesh->numvertexes, xyz, vertbuf, mesh);
|
||||
xyz = vertbuf;
|
||||
for (i = 1; i < shaderstate.curshader->numdeforms; i++)
|
||||
{
|
||||
deformgen(&shaderstate.curshader->deforms[i], mesh->numvertexes, xyz, xyz, mesh);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < mesh->numvertexes; i++, v++)
|
||||
{
|
||||
Matrix4x4_CM_Transform34(shaderstate.m_mvp, xyz[i], v->vcoord);
|
||||
|
||||
if (v->vcoord[3] != 1)
|
||||
{
|
||||
v->vcoord[0] /= v->vcoord[3];
|
||||
v->vcoord[1] /= v->vcoord[3];
|
||||
v->vcoord[2] /= v->vcoord[3];
|
||||
}
|
||||
v->vcoord[0] = (v->vcoord[0]+1)/2 * vid.pixelwidth;
|
||||
if (v->vcoord[0] < 0)
|
||||
v->clipflags = CLIP_LEFT_FLAG;
|
||||
else
|
||||
v->clipflags = 0;
|
||||
if (v->vcoord[0] > vid.pixelwidth-1)
|
||||
v->clipflags |= CLIP_RIGHT_FLAG;
|
||||
v->vcoord[1] = (v->vcoord[1]+1)/2 * vid.pixelheight;
|
||||
if (v->vcoord[1] < temp1.value)
|
||||
v->clipflags |= CLIP_TOP_FLAG;
|
||||
if (v->vcoord[1] > vid.pixelheight-1)
|
||||
v->clipflags |= CLIP_BOTTOM_FLAG;
|
||||
v->vcoord[2] = (v->vcoord[2]+1)/2;
|
||||
if (v->vcoord[3] < 0)
|
||||
v->clipflags |= CLIP_NEAR_FLAG;
|
||||
if (v->vcoord[2] >= 1)
|
||||
v->vcoord[2] = 1;
|
||||
|
||||
Vector2Copy(mesh->st_array[i], v->tccoord);
|
||||
|
||||
// v->colour[0] = mesh->colors4b_array[i][0];
|
||||
// v->colour[1] = mesh->colors4b_array[i][1];
|
||||
// v->colour[2] = mesh->colors4b_array[i][2];
|
||||
// v->colour[3] = mesh->colors4b_array[i][3];
|
||||
}
|
||||
}
|
||||
void SWBE_DrawMesh_Single(shader_t *shader, mesh_t *mesh, struct vbo_s *vbo, struct texnums_s *texnums, unsigned int be_flags)
|
||||
{
|
||||
wqcom_t *com;
|
||||
|
||||
shaderstate.curshader = shader;
|
||||
|
||||
if (mesh->istrifan)
|
||||
{
|
||||
com = SWRast_BeginCommand(WTC_TRIFAN, mesh->numvertexes*sizeof(swvert_t) + sizeof(com->trifan) - sizeof(com->trifan.verts));
|
||||
|
||||
com->trifan.texture = texnums->base.ptr;
|
||||
com->trifan.numverts = mesh->numvertexes;
|
||||
|
||||
SWBE_TransformVerticies(com->trifan.verts, mesh);
|
||||
|
||||
SWRast_EndCommand(com);
|
||||
}
|
||||
else
|
||||
{
|
||||
com = SWRast_BeginCommand(WTC_TRISOUP, (mesh->numvertexes*sizeof(swvert_t)) + sizeof(com->trisoup) - sizeof(com->trisoup.verts) + (sizeof(index_t)*mesh->numindexes));
|
||||
|
||||
com->trisoup.texture = texnums->base.ptr;
|
||||
com->trisoup.numverts = mesh->numvertexes;
|
||||
com->trisoup.numidx = mesh->numindexes;
|
||||
|
||||
SWBE_TransformVerticies(com->trisoup.verts, mesh);
|
||||
memcpy(com->trisoup.verts + mesh->numvertexes, mesh->indexes, sizeof(index_t)*mesh->numindexes);
|
||||
|
||||
SWRast_EndCommand(com);
|
||||
}
|
||||
}
|
||||
void SWBE_DrawMesh_List(shader_t *shader, int nummeshes, struct mesh_s **mesh, struct vbo_s *vbo, struct texnums_s *texnums, unsigned int be_flags)
|
||||
{
|
||||
while(nummeshes-->0)
|
||||
{
|
||||
SWBE_DrawMesh_Single(shader, *mesh++, vbo, texnums, be_flags);
|
||||
}
|
||||
}
|
||||
void SWBE_SubmitBatch(struct batch_s *batch)
|
||||
{
|
||||
int m;
|
||||
SWBE_SelectEntity(batch->ent);
|
||||
for (m = 0; m < batch->meshes; m++)
|
||||
{
|
||||
SWBE_DrawMesh_Single(batch->shader, batch->mesh[m], batch->vbo, batch->skin?batch->skin:&batch->shader->defaulttextures, batch->flags);
|
||||
}
|
||||
}
|
||||
struct batch_s *SWBE_GetTempBatch(void)
|
||||
{
|
||||
if (shaderstate.wbatch >= shaderstate.maxwbatches)
|
||||
{
|
||||
shaderstate.wbatch++;
|
||||
return NULL;
|
||||
}
|
||||
return &shaderstate.wbatches[shaderstate.wbatch++];
|
||||
}
|
||||
|
||||
static void SWBE_SubmitMeshesSortList(batch_t *sortlist)
|
||||
{
|
||||
batch_t *batch;
|
||||
for (batch = sortlist; batch; batch = batch->next)
|
||||
{
|
||||
if (batch->meshes == batch->firstmesh)
|
||||
continue;
|
||||
|
||||
if (batch->flags & BEF_NODLIGHT)
|
||||
if (shaderstate.mode == BEM_LIGHT || shaderstate.mode == BEM_SMAPLIGHT)
|
||||
continue;
|
||||
if (batch->flags & BEF_NOSHADOWS)
|
||||
if (shaderstate.mode == BEM_STENCIL)
|
||||
continue;
|
||||
|
||||
if (batch->buildmeshes)
|
||||
batch->buildmeshes(batch);
|
||||
else if (batch->texture)
|
||||
batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
|
||||
|
||||
if (batch->shader->flags & SHADER_NODRAW)
|
||||
continue;
|
||||
if (batch->shader->flags & SHADER_NODLIGHT)
|
||||
if (shaderstate.mode == BEM_LIGHT || shaderstate.mode == BEM_SMAPLIGHT)
|
||||
continue;
|
||||
if (batch->shader->flags & SHADER_SKY)
|
||||
{
|
||||
if (shaderstate.mode == BEM_STANDARD || shaderstate.mode == BEM_DEPTHDARK)
|
||||
{
|
||||
if (!batch->shader->prog)
|
||||
{
|
||||
R_DrawSkyChain (batch);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (shaderstate.mode != BEM_FOG && shaderstate.mode != BEM_CREPUSCULAR)
|
||||
continue;
|
||||
}
|
||||
|
||||
SWBE_SubmitBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
void SWBE_SubmitMeshes (qboolean drawworld, batch_t **blist, int start, int stop)
|
||||
{
|
||||
model_t *model = cl.worldmodel;
|
||||
int i;
|
||||
|
||||
for (i = start; i <= stop; i++)
|
||||
{
|
||||
if (drawworld)
|
||||
{
|
||||
// if (i == SHADER_SORT_PORTAL && !r_noportals.ival && !r_refdef.recurse)
|
||||
// SWBE_SubmitMeshesPortals(model->batches, blist[i]);
|
||||
|
||||
SWBE_SubmitMeshesSortList(model->batches[i]);
|
||||
}
|
||||
SWBE_SubmitMeshesSortList(blist[i]);
|
||||
}
|
||||
}
|
||||
void SWBE_Set2D(void)
|
||||
{
|
||||
extern cvar_t gl_screenangle;
|
||||
float ang, rad, w, h;
|
||||
float tmp[16];
|
||||
float tmp2[16];
|
||||
ang = (gl_screenangle.value>0?(gl_screenangle.value+45):(gl_screenangle.value-45))/90;
|
||||
ang = (int)ang * 90;
|
||||
if (ang)
|
||||
{ /*more expensive maths*/
|
||||
rad = (ang * M_PI) / 180;
|
||||
|
||||
w = fabs(cos(rad)) * (vid.width) + fabs(sin(rad)) * (vid.height);
|
||||
h = fabs(sin(rad)) * (vid.width) + fabs(cos(rad)) * (vid.height);
|
||||
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, w/-2.0f, w/2.0f, h/2.0f, h/-2.0f, -99999, 99999);
|
||||
|
||||
Matrix4x4_Identity(tmp);
|
||||
Matrix4_Multiply(Matrix4x4_CM_NewTranslation((vid.width/-2.0f), (vid.height/-2.0f), 0), tmp, tmp2);
|
||||
Matrix4_Multiply(Matrix4x4_CM_NewRotation(-ang, 0, 0, 1), tmp2, r_refdef.m_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0)
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, 0, vid.height, 0, 99999);
|
||||
else
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, vid.height, 0, 0, 99999);
|
||||
Matrix4x4_Identity(r_refdef.m_view);
|
||||
}
|
||||
|
||||
memcpy(shaderstate.m_mvp, r_refdef.m_projection, sizeof(shaderstate.m_mvp));
|
||||
}
|
||||
void SWBE_DrawWorld(qbyte *vis)
|
||||
{
|
||||
batch_t *batches[SHADER_SORT_COUNT];
|
||||
|
||||
if (!r_refdef.recurse)
|
||||
{
|
||||
if (shaderstate.wbatch + 50 > shaderstate.maxwbatches)
|
||||
{
|
||||
int newm = shaderstate.wbatch + 100;
|
||||
shaderstate.wbatches = BZ_Realloc(shaderstate.wbatches, newm * sizeof(*shaderstate.wbatches));
|
||||
memset(shaderstate.wbatches + shaderstate.maxwbatches, 0, (newm - shaderstate.maxwbatches) * sizeof(*shaderstate.wbatches));
|
||||
shaderstate.maxwbatches = newm;
|
||||
}
|
||||
|
||||
shaderstate.wbatch = 0;
|
||||
}
|
||||
BE_GenModelBatches(batches);
|
||||
// R_GenDlightBatches(batches);
|
||||
|
||||
shaderstate.curentity = NULL;
|
||||
SWBE_SelectEntity(&r_worldentity);
|
||||
|
||||
SWBE_SubmitMeshes(vis!=NULL, batches, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
|
||||
|
||||
SWBE_Set2D();
|
||||
}
|
||||
void SWBE_Init(void)
|
||||
{
|
||||
BE_InitTables();
|
||||
}
|
||||
void SWBE_GenBrushModelVBO(struct model_s *mod)
|
||||
{
|
||||
}
|
||||
void SWBE_ClearVBO(struct vbo_s *vbo)
|
||||
{
|
||||
}
|
||||
void SWBE_UploadAllLightmaps(void)
|
||||
{
|
||||
}
|
||||
void SWBE_SelectEntity(struct entity_s *ent)
|
||||
{
|
||||
float modelmatrix[16];
|
||||
float modelviewmatrix[16];
|
||||
|
||||
if (shaderstate.curentity == ent)
|
||||
return;
|
||||
shaderstate.curentity = ent;
|
||||
|
||||
R_RotateForEntity(modelmatrix, modelviewmatrix, shaderstate.curentity, shaderstate.curentity->model);
|
||||
Matrix4_Multiply(r_refdef.m_projection, modelviewmatrix, shaderstate.m_mvp);
|
||||
}
|
||||
void SWBE_SelectDLight(struct dlight_s *dl, vec3_t colour)
|
||||
{
|
||||
}
|
||||
qboolean SWBE_LightCullModel(vec3_t org, struct model_s *model)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
122
engine/sw/sw_image.c
Normal file
122
engine/sw/sw_image.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef SWQUAKE
|
||||
#include "sw.h"
|
||||
|
||||
|
||||
|
||||
texid_tf SW_AllocNewTexture(char *identifier, int w, int h)
|
||||
{
|
||||
texid_t n;
|
||||
swimage_t *img;
|
||||
if (w & 3)
|
||||
return r_nulltex;
|
||||
img = BZ_Malloc(sizeof(*img) - sizeof(img->data) + (w * h * 4));
|
||||
|
||||
Q_strncpy(img->name, identifier, sizeof(img->name));
|
||||
img->width = w;
|
||||
img->height = h;
|
||||
img->pitch = w;
|
||||
|
||||
n.ptr = img;
|
||||
n.ref = &img->com;
|
||||
return n;
|
||||
}
|
||||
texid_tf SW_FindTexture(char *identifier)
|
||||
{
|
||||
return r_nulltex;
|
||||
}
|
||||
|
||||
void SW_RGBToBGR(swimage_t *img)
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *d = img->data;
|
||||
for (y = 0; y < img->height; y++)
|
||||
{
|
||||
for (x = 0; x < img->width; x++)
|
||||
{
|
||||
d[x] = (d[x]&0xff00ff00) | ((d[x]&0xff)<<16) | ((d[x]&0xff0000)>>16);
|
||||
}
|
||||
d += img->pitch;
|
||||
}
|
||||
}
|
||||
void SW_Upload32(swimage_t *img, int w, int h, unsigned int *data)
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *out = img->data;
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
out[x] = *data++;
|
||||
}
|
||||
out += img->pitch;
|
||||
}
|
||||
SW_RGBToBGR(img);
|
||||
}
|
||||
void SW_Upload8(swimage_t *img, int w, int h, unsigned char *data)
|
||||
{
|
||||
int x, y;
|
||||
unsigned int *out = img->data;
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
out[x] = d_8to24rgbtable[*data++];
|
||||
}
|
||||
out += img->pitch;
|
||||
}
|
||||
SW_RGBToBGR(img);
|
||||
}
|
||||
|
||||
texid_tf SW_LoadTexture(char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags)
|
||||
{
|
||||
texid_t img = SW_FindTexture(identifier);
|
||||
if (!img.ptr)
|
||||
img = SW_AllocNewTexture(identifier, width, height);
|
||||
switch(fmt)
|
||||
{
|
||||
case TF_SOLID8:
|
||||
SW_Upload8(img.ptr, width, height, data);
|
||||
break;
|
||||
case TF_TRANS8:
|
||||
SW_Upload8(img.ptr, width, height, data);
|
||||
break;
|
||||
case TF_TRANS8_FULLBRIGHT:
|
||||
SW_Upload8(img.ptr, width, height, data);
|
||||
break;
|
||||
case TF_RGBA32:
|
||||
SW_Upload32(img.ptr, width, height, data);
|
||||
break;
|
||||
default:
|
||||
//shouldn't happen, so I'm gonna leak
|
||||
Con_Printf("SW_LoadTexture: unsupported format %i\n", fmt);
|
||||
return r_nulltex;
|
||||
}
|
||||
return img;
|
||||
}
|
||||
texid_tf SW_LoadTexture8Pal24(char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags)
|
||||
{
|
||||
return r_nulltex;
|
||||
}
|
||||
texid_tf SW_LoadTexture8Pal32(char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags)
|
||||
{
|
||||
return r_nulltex;
|
||||
}
|
||||
texid_tf SW_LoadCompressed(char *name)
|
||||
{
|
||||
return r_nulltex;
|
||||
}
|
||||
void SW_Upload(texid_t tex, char *name, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags)
|
||||
{
|
||||
}
|
||||
void SW_DestroyTexture(texid_t tex)
|
||||
{
|
||||
swimage_t *img = tex.ptr;
|
||||
|
||||
/*make sure its not in use by the renderer*/
|
||||
SWRast_Sync();
|
||||
|
||||
/*okay, it can be killed*/
|
||||
BZ_Free(img);
|
||||
}
|
||||
#endif
|
994
engine/sw/sw_rast.c
Normal file
994
engine/sw/sw_rast.c
Normal file
|
@ -0,0 +1,994 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef SWQUAKE
|
||||
#include "sw.h"
|
||||
#include "gl_draw.h"
|
||||
#include "shader.h"
|
||||
#include "renderque.h"
|
||||
#include "glquake.h"
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
//no need to do anything
|
||||
#elif defined(_MSC_VER)
|
||||
#define restrict __restrict
|
||||
#else
|
||||
#define restrict
|
||||
#endif
|
||||
|
||||
/*
|
||||
Our software rendering basically works like this:
|
||||
|
||||
main thread builds command:
|
||||
command contains vertex data in the command block
|
||||
main thread runs the vertex programs (much like q3) and performs matrix transforms (much like d3d)
|
||||
|
||||
worker threads read each command sequentially:
|
||||
clip to viewport
|
||||
|
||||
division of labour between worker threads works by interlacing.
|
||||
each thread gets a different set of scanlines to render.
|
||||
we can also trivially implement interlacing with this method
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define MAXWORKERTHREADS 64
|
||||
static swthread_t swthreads[MAXWORKERTHREADS];
|
||||
|
||||
cvar_t sw_interlace = CVAR("sw_interlace", "0");
|
||||
cvar_t sw_threads = CVAR("sw_threads", "0");
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int numthreads;
|
||||
qbyte queue[1024*1024*8];
|
||||
volatile unsigned int pos;
|
||||
} wq;
|
||||
#define WQ_MASK (sizeof(wq.queue)-1)
|
||||
|
||||
static void WT_Triangle(swthread_t *th, swimage_t *img, swvert_t *v1, swvert_t *v2, swvert_t *v3)
|
||||
{
|
||||
unsigned int tpix;
|
||||
#define SPAN_ST
|
||||
#define SPAN_Z
|
||||
#define PLOT_PIXEL(o) \
|
||||
{ \
|
||||
if (*zb >= z) \
|
||||
{ \
|
||||
*zb = z; \
|
||||
tpix = img->data[ \
|
||||
((unsigned)(s*img->width)%img->width) \
|
||||
+ (((unsigned)(t*img->height)%img->height) * img->width) \
|
||||
]; \
|
||||
if (tpix&0xff000000) \
|
||||
o = tpix; \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef MSVCWORKSPROPERLY
|
||||
#include "sw_spans.h"
|
||||
#else
|
||||
/*
|
||||
this file is expected to be #included as the body of a real function
|
||||
to define create a new pixel shader, define PLOT_PIXEL(outval) at the top of your function and you're good to go
|
||||
|
||||
//modifiers:
|
||||
SPAN_ST - interpolates S+T across the span. access with 'sc' and 'tc'
|
||||
affine... no perspective correction.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
swvert_t *vt;
|
||||
int y;
|
||||
int secondhalf;
|
||||
int xl,xld, xr,xrd;
|
||||
#ifdef SPAN_ST
|
||||
float sl,sld, sd;
|
||||
float tl,tld, td;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
unsigned int zl,zld, zd;
|
||||
#endif
|
||||
unsigned int *restrict outbuf;
|
||||
unsigned int *restrict ti;
|
||||
int i;
|
||||
const swvert_t *vlt,*vlb,*vrt,*vrb;
|
||||
int spanlen;
|
||||
int numspans;
|
||||
unsigned int *vplout;
|
||||
int dx, dy;
|
||||
int recalcside;
|
||||
int interlace;
|
||||
|
||||
float fdx1,fdy1,fdx2,fdy2,fz,d1,d2;
|
||||
|
||||
if (!img)
|
||||
return;
|
||||
|
||||
/*we basically render a diamond
|
||||
that is, the single triangle is split into two triangles, outwards towards the midpoint and inwards to the final position.
|
||||
*/
|
||||
|
||||
/*reorder the verticies for height*/
|
||||
if (v1->vcoord[1] > v2->vcoord[1])
|
||||
{
|
||||
vt = v1;
|
||||
v1 = v2;
|
||||
v2 = vt;
|
||||
}
|
||||
if (v1->vcoord[1] > v3->vcoord[1])
|
||||
{
|
||||
vt = v1;
|
||||
v1 = v3;
|
||||
v3 = vt;
|
||||
}
|
||||
if (v2->vcoord[1] > v3->vcoord[1])
|
||||
{
|
||||
vt = v3;
|
||||
v3 = v2;
|
||||
v2 = vt;
|
||||
}
|
||||
|
||||
{
|
||||
const swvert_t *v[3];
|
||||
|
||||
v[0] = v1;
|
||||
v[1] = v2;
|
||||
v[2] = v3;
|
||||
|
||||
//reject triangles with any point offscreen, for now
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (v[i]->vcoord[0] < 0 || v[i]->vcoord[0] >= th->vpwidth)
|
||||
return;
|
||||
if (v[i]->vcoord[1] < 0 || v[i]->vcoord[1] >= th->vpheight)
|
||||
return;
|
||||
if (v[i]->vcoord[2] < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (v[i]->vcoord[1] > v[i+1]->vcoord[1])
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fdx1 = v2->vcoord[0] - v1->vcoord[0];
|
||||
fdy1 = v2->vcoord[1] - v1->vcoord[1];
|
||||
|
||||
fdx2 = v3->vcoord[0] - v1->vcoord[0];
|
||||
fdy2 = v3->vcoord[1] - v1->vcoord[1];
|
||||
|
||||
fz = fdx1*fdy2 - fdx2*fdy1;
|
||||
|
||||
if (fz == 0)
|
||||
{
|
||||
//weird angle...
|
||||
return;
|
||||
}
|
||||
|
||||
fz = 1.0 / fz;
|
||||
fdx1 *= fz;
|
||||
fdy1 *= fz;
|
||||
fdx2 *= fz;
|
||||
fdy2 *= fz;
|
||||
|
||||
#ifdef SPAN_ST //affine
|
||||
d1 = v2->tccoord[0] - v1->tccoord[0];
|
||||
d2 = v3->tccoord[0] - v1->tccoord[0];
|
||||
sld = fdx1*d2 - fdx2*d1;
|
||||
sd = fdy2*d1 - fdy1*d2;
|
||||
|
||||
d1 = v2->tccoord[1] - v1->tccoord[1];
|
||||
d2 = v3->tccoord[1] - v1->tccoord[1];
|
||||
tld = fdx1*d2 - fdx2*d1;
|
||||
td = fdy2*d1 - fdy1*d2;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
d1 = (v2->vcoord[2] - v1->vcoord[2])*UINT_MAX;
|
||||
d2 = (v3->vcoord[2] - v1->vcoord[2])*UINT_MAX;
|
||||
zld = fdx1*d2 - fdx2*d1;
|
||||
zd = fdy2*d1 - fdy1*d2;
|
||||
#endif
|
||||
|
||||
ti = img->data;
|
||||
|
||||
y = v1->vcoord[1];
|
||||
|
||||
for (secondhalf = 0; secondhalf <= 1; secondhalf++)
|
||||
{
|
||||
if (secondhalf)
|
||||
{
|
||||
if (numspans < 0)
|
||||
{
|
||||
interlace = -numspans;
|
||||
y+=interlace;
|
||||
numspans-=interlace;
|
||||
|
||||
xl += xld*interlace;
|
||||
xr += xrd*interlace;
|
||||
vplout += th->vpcstride*interlace;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl += sld*interlace;
|
||||
tl += tld*interlace;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl += zld*interlace;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*v2->v3*/
|
||||
if (fz <= 0)
|
||||
{
|
||||
vlt = v2;
|
||||
//vrt == v1;
|
||||
vlb = v3;
|
||||
//vrb == v3;
|
||||
|
||||
recalcside = 1;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sld -= sd*xld/(float)(1<<16);
|
||||
tld -= td*xld/(float)(1<<16);
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zld -= zd*xld/(float)(1<<16);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//vlt == v1;
|
||||
vrt = v2;
|
||||
///vlb == v3;
|
||||
vrb = v3;
|
||||
|
||||
recalcside = 2;
|
||||
}
|
||||
|
||||
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
|
||||
numspans = v3->vcoord[1] - y;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlt = v1;
|
||||
vrt = v1;
|
||||
/*v1->v2*/
|
||||
if (fz < 0)
|
||||
{
|
||||
vlb = v2;
|
||||
vrb = v3;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlb = v3;
|
||||
vrb = v2;
|
||||
}
|
||||
recalcside = 3;
|
||||
|
||||
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
|
||||
numspans = v2->vcoord[1] - y;
|
||||
}
|
||||
|
||||
if (recalcside & 1)
|
||||
{
|
||||
dx = (vlb->vcoord[0] - vlt->vcoord[0]);
|
||||
dy = (vlb->vcoord[1] - vlt->vcoord[1]);
|
||||
if (dy > 0)
|
||||
xld = (dx<<16) / dy;
|
||||
else
|
||||
xld = 0;
|
||||
xl = (int)vlt->vcoord[0]<<16;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl = vlt->tccoord[0];
|
||||
sld = sld + sd*xld/(float)(1<<16);
|
||||
tl = vlt->tccoord[1];
|
||||
tld = tld + td*xld/(float)(1<<16);
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl = vlt->vcoord[2]*UINT_MAX;
|
||||
zld = zld + zd*xld/(float)(1<<16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (recalcside & 2)
|
||||
{
|
||||
dx = (vrb->vcoord[0] - vrt->vcoord[0]);
|
||||
dy = (vrb->vcoord[1] - vrt->vcoord[1]);
|
||||
if (dy)
|
||||
xrd = (dx<<16) / dy;
|
||||
else
|
||||
xrd = 0;
|
||||
xr = (int)vrt->vcoord[0]<<16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (y + numspans >= th->vpheight)
|
||||
numspans = th->vpheight - y - 1;
|
||||
|
||||
if (numspans <= 0)
|
||||
continue;
|
||||
|
||||
|
||||
vplout = th->vpcbuf + y * th->vpcstride; //this is a pointer to the left of the viewport buffer.
|
||||
|
||||
interlace = ((y + th->interlaceline) % th->interlacemod);
|
||||
if (interlace)
|
||||
{
|
||||
if (interlace > numspans)
|
||||
{
|
||||
interlace = numspans;
|
||||
y+=interlace;
|
||||
}
|
||||
else
|
||||
{
|
||||
y+=interlace;
|
||||
numspans-=interlace;
|
||||
}
|
||||
xl += xld*interlace;
|
||||
xr += xrd*interlace;
|
||||
vplout += th->vpcstride*interlace;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl += sld*interlace;
|
||||
tl += tld*interlace;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl += zld*interlace;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; numspans > 0;
|
||||
numspans -= th->interlacemod
|
||||
,xl += xld*th->interlacemod
|
||||
,xr += xrd*th->interlacemod
|
||||
,vplout += th->vpcstride*th->interlacemod
|
||||
,y += th->interlacemod
|
||||
|
||||
#ifdef SPAN_ST
|
||||
,sl += sld*th->interlacemod
|
||||
,tl += tld*th->interlacemod
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
,zl += zld*th->interlacemod
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef SPAN_ST
|
||||
float s = sl;
|
||||
float t = tl;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
unsigned int z = zl;
|
||||
unsigned int *restrict zb = th->vpdbuf + y * th->vpwidth + (xl>>16);
|
||||
#endif
|
||||
|
||||
spanlen = (xr - xl)>>16;
|
||||
outbuf = vplout + (xl>>16);
|
||||
|
||||
while(spanlen-->=0)
|
||||
{
|
||||
PLOT_PIXEL(*outbuf);
|
||||
outbuf++;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
s += sd;
|
||||
t += td;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
z += zd;
|
||||
zb++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPAN_ST
|
||||
#undef PLOT_PIXEL
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void WT_Clip_Top(swvert_t *out, swvert_t *in, swvert_t *result)
|
||||
{
|
||||
float frac;
|
||||
frac = (0 - in->vcoord[1]) /
|
||||
(out->vcoord[1] - in->vcoord[1]);
|
||||
VectorInterpolate(in->vcoord, frac, out->vcoord, result->vcoord);
|
||||
result->vcoord[1] = 0;
|
||||
Vector2Interpolate(in->tccoord, frac, out->tccoord, result->tccoord);
|
||||
}
|
||||
static void WT_Clip_Bottom(swvert_t *out, swvert_t *in, swvert_t *result)
|
||||
{
|
||||
float frac;
|
||||
frac = (vid.pixelheight-1 - in->vcoord[1]) /
|
||||
(out->vcoord[1] - in->vcoord[1]);
|
||||
VectorInterpolate(in->vcoord, frac, out->vcoord, result->vcoord);
|
||||
result->vcoord[1] = vid.pixelheight-1;
|
||||
Vector2Interpolate(in->tccoord, frac, out->tccoord, result->tccoord);
|
||||
}
|
||||
static void WT_Clip_Left(swvert_t *out, swvert_t *in, swvert_t *result)
|
||||
{
|
||||
float frac;
|
||||
frac = (0 - in->vcoord[0]) /
|
||||
(out->vcoord[0] - in->vcoord[0]);
|
||||
VectorInterpolate(in->vcoord, frac, out->vcoord, result->vcoord);
|
||||
result->vcoord[0] = 0;
|
||||
Vector2Interpolate(in->tccoord, frac, out->tccoord, result->tccoord);
|
||||
}
|
||||
static void WT_Clip_Right(swvert_t *out, swvert_t *in, swvert_t *result)
|
||||
{
|
||||
float frac;
|
||||
frac = (vid.pixelwidth-1 - in->vcoord[0]) /
|
||||
(out->vcoord[0] - in->vcoord[0]);
|
||||
VectorInterpolate(in->vcoord, frac, out->vcoord, result->vcoord);
|
||||
result->vcoord[0] = vid.pixelwidth-1;
|
||||
Vector2Interpolate(in->tccoord, frac, out->tccoord, result->tccoord);
|
||||
}
|
||||
static void WT_Clip_Near(swvert_t *out, swvert_t *in, swvert_t *result)
|
||||
{
|
||||
extern cvar_t temp1;
|
||||
double frac;
|
||||
frac = (temp1.value - in->vcoord[2]) /
|
||||
(out->vcoord[2] - in->vcoord[2]);
|
||||
VectorInterpolate(in->vcoord, frac, out->vcoord, result->vcoord);
|
||||
result->vcoord[2] = temp1.value;
|
||||
Vector2Interpolate(in->tccoord, frac, out->tccoord, result->tccoord);
|
||||
}
|
||||
|
||||
static int WT_ClipPoly(int incount, swvert_t *inv, swvert_t *outv, int flag, void (*clip)(swvert_t *out, swvert_t *in, swvert_t *result))
|
||||
{
|
||||
int p, c;
|
||||
int result = 0;
|
||||
int pf, cf;
|
||||
if (incount < 3)
|
||||
return 0;
|
||||
|
||||
for (p = incount - 1, c = 0; c < incount; p = c, c++)
|
||||
{
|
||||
pf = inv[p].clipflags & flag;
|
||||
cf = inv[c].clipflags & flag;
|
||||
|
||||
if (pf && cf)
|
||||
continue; //both clipped, skip it now
|
||||
if (pf ^ cf)
|
||||
{
|
||||
//crossed... emit a new vertex on the boundary
|
||||
if (cf) //new is offscreen
|
||||
clip(&inv[c], &inv[p], &outv[result]);
|
||||
else
|
||||
clip(&inv[p], &inv[c], &outv[result]);
|
||||
outv[result].clipflags = 0;
|
||||
|
||||
if (outv[result].vcoord[0] < 0)
|
||||
outv[result].clipflags = CLIP_LEFT_FLAG;
|
||||
if (outv[result].vcoord[0] > vid.pixelwidth-1)
|
||||
outv[result].clipflags |= CLIP_RIGHT_FLAG;
|
||||
if (outv[result].vcoord[1] < 0)
|
||||
outv[result].clipflags |= CLIP_TOP_FLAG;
|
||||
if (outv[result].vcoord[1] > vid.pixelheight-1)
|
||||
outv[result].clipflags |= CLIP_BOTTOM_FLAG;
|
||||
|
||||
result++;
|
||||
}
|
||||
if (!cf)
|
||||
{
|
||||
outv[result] = inv[c];
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void WT_ClipTriangle(swthread_t *th, swimage_t *img, swvert_t *v1, swvert_t *v2, swvert_t *v3)
|
||||
{
|
||||
unsigned int cflags;
|
||||
swvert_t final[2][64];
|
||||
int list = 0;
|
||||
int i;
|
||||
int count;
|
||||
|
||||
if (v1->clipflags & v2->clipflags & v3->clipflags)
|
||||
return; //all verticies are off at least one single side
|
||||
|
||||
cflags = v1->clipflags | v2->clipflags | v3->clipflags;
|
||||
|
||||
if (!cflags)
|
||||
{
|
||||
//no clipping to be done
|
||||
WT_Triangle(th, img, v1, v2, v3);
|
||||
return;
|
||||
}
|
||||
|
||||
final[list][0] = *v1;
|
||||
final[list][1] = *v2;
|
||||
final[list][2] = *v3;
|
||||
count = 3;
|
||||
|
||||
if (cflags & CLIP_NEAR_FLAG)
|
||||
{
|
||||
count = WT_ClipPoly(count, final[list], final[list^1], CLIP_NEAR_FLAG, WT_Clip_Near);
|
||||
list ^= 1;
|
||||
}
|
||||
if (cflags & CLIP_TOP_FLAG)
|
||||
{
|
||||
count = WT_ClipPoly(count, final[list], final[list^1], CLIP_TOP_FLAG, WT_Clip_Top);
|
||||
list ^= 1;
|
||||
}
|
||||
if (cflags & CLIP_BOTTOM_FLAG)
|
||||
{
|
||||
count = WT_ClipPoly(count, final[list], final[list^1], CLIP_BOTTOM_FLAG, WT_Clip_Bottom);
|
||||
list ^= 1;
|
||||
}
|
||||
if (cflags & CLIP_LEFT_FLAG)
|
||||
{
|
||||
count = WT_ClipPoly(count, final[list], final[list^1], CLIP_LEFT_FLAG, WT_Clip_Left);
|
||||
list ^= 1;
|
||||
}
|
||||
if (cflags & CLIP_RIGHT_FLAG)
|
||||
{
|
||||
count = WT_ClipPoly(count, final[list], final[list^1], CLIP_RIGHT_FLAG, WT_Clip_Right);
|
||||
list ^= 1;
|
||||
}
|
||||
|
||||
for (i = 2; i < count; i++)
|
||||
{
|
||||
WT_Triangle(th, img, &final[list][0], &final[list][i-1], &final[list][i]);
|
||||
}
|
||||
}
|
||||
|
||||
void WQ_ClearBuffer(swthread_t *t, unsigned int *mbuf, qintptr_t stride, unsigned int clearval)
|
||||
{
|
||||
int y;
|
||||
int x;
|
||||
unsigned int *buf;
|
||||
|
||||
for (y = t->interlaceline; y < t->vpheight; y += t->interlacemod)
|
||||
{
|
||||
buf = mbuf + stride*y;
|
||||
for (x = 0; x < (t->vpwidth & ~15);)
|
||||
{
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
buf[x++] = clearval;
|
||||
}
|
||||
for (; x < t->vpwidth; )
|
||||
buf[x++] = clearval;
|
||||
}
|
||||
}
|
||||
|
||||
qboolean WT_HandleCommand(swthread_t *t, wqcom_t *com)
|
||||
{
|
||||
index_t *idx;
|
||||
int i;
|
||||
switch(com->com.command)
|
||||
{
|
||||
case WTC_DIE:
|
||||
t->readpoint += com->com.cmdsize;
|
||||
return 1;
|
||||
case WTC_NOOP:
|
||||
break;
|
||||
case WTC_NEWFRAME:
|
||||
break;
|
||||
case WTC_VIEWPORT:
|
||||
t->vpcbuf = com->viewport.cbuf;
|
||||
t->vpdbuf = com->viewport.dbuf;
|
||||
t->vpwidth = com->viewport.width;
|
||||
t->vpheight = com->viewport.height;
|
||||
t->vpcstride = com->viewport.stride;
|
||||
if (!wq.numthreads)
|
||||
{
|
||||
t->interlacemod = com->viewport.interlace; //this many vthreads
|
||||
t->interlaceline = com->viewport.framenum%com->viewport.interlace; //this vthread
|
||||
}
|
||||
else
|
||||
{
|
||||
t->interlacemod = wq.numthreads*com->viewport.interlace; //this many vthreads
|
||||
t->interlaceline = (t->threadnum*com->viewport.interlace) + (com->viewport.framenum%com->viewport.interlace); //this vthread
|
||||
}
|
||||
|
||||
if (com->viewport.clearcolour)
|
||||
{
|
||||
WQ_ClearBuffer(t, t->vpcbuf, t->vpcstride, 0);
|
||||
}
|
||||
if (com->viewport.cleardepth)
|
||||
{
|
||||
WQ_ClearBuffer(t, t->vpdbuf, t->vpwidth, ~0u);
|
||||
}
|
||||
break;
|
||||
case WTC_TRIFAN:
|
||||
for (i = 2; i < com->trifan.numverts; i++)
|
||||
{
|
||||
WT_ClipTriangle(t, com->trifan.texture, &com->trifan.verts[0], &com->trifan.verts[i-1], &com->trifan.verts[i]);
|
||||
}
|
||||
break;
|
||||
case WTC_TRISOUP:
|
||||
idx = (index_t*)(com->trisoup.verts + com->trisoup.numverts);
|
||||
for (i = 0; i < com->trisoup.numidx; i+=3, idx+=3)
|
||||
{
|
||||
WT_ClipTriangle(t, com->trisoup.texture, &com->trisoup.verts[idx[0]], &com->trisoup.verts[idx[1]], &com->trisoup.verts[idx[2]]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Sys_Printf("Unknown render command!\n");
|
||||
break;
|
||||
}
|
||||
t->readpoint += com->com.cmdsize;
|
||||
return false;
|
||||
}
|
||||
|
||||
int WT_Main(void *ptr)
|
||||
{
|
||||
wqcom_t *com;
|
||||
swthread_t *t = ptr;
|
||||
for(;;)
|
||||
{
|
||||
if (t->readpoint == wq.pos)
|
||||
{
|
||||
Sys_Sleep(0);
|
||||
continue;
|
||||
}
|
||||
com = (wqcom_t*)&wq.queue[t->readpoint & WQ_MASK];
|
||||
if (WT_HandleCommand(t, com))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void SWRast_EndCommand(wqcom_t *com)
|
||||
{
|
||||
wq.pos += com->com.cmdsize;
|
||||
|
||||
if (!wq.numthreads)
|
||||
{
|
||||
//immediate mode
|
||||
WT_HandleCommand(swthreads, com);
|
||||
}
|
||||
}
|
||||
wqcom_t *SWRast_BeginCommand(int cmdtype, unsigned int size)
|
||||
{
|
||||
wqcom_t *com;
|
||||
//round the command size up, so we always have space for a noop/wrap if needed
|
||||
size = (size + sizeof(com->align)) & ~(sizeof(com->align)-1);
|
||||
|
||||
//generate a noop if we don't have enough space for the command
|
||||
if ((wq.pos&WQ_MASK) + size > sizeof(wq.queue))
|
||||
{
|
||||
// SWRast_Sync();
|
||||
com = (wqcom_t *)&wq.queue[wq.pos&WQ_MASK];
|
||||
com->com.cmdsize = sizeof(wq.queue) - wq.pos&WQ_MASK;
|
||||
com->com.command = WTC_NOOP;
|
||||
SWRast_EndCommand(com);
|
||||
}
|
||||
|
||||
com = (wqcom_t *)&wq.queue[wq.pos&WQ_MASK];
|
||||
com->com.cmdsize = size;
|
||||
com->com.command = cmdtype;
|
||||
|
||||
return com;
|
||||
}
|
||||
void SWRast_Sync(void)
|
||||
{
|
||||
int i;
|
||||
swthread_t *t;
|
||||
|
||||
for (i = 0; i < wq.numthreads; i++)
|
||||
{
|
||||
t = &swthreads[i];
|
||||
while (t->readpoint != wq.pos)
|
||||
;
|
||||
}
|
||||
|
||||
//all worker threads are up to speed
|
||||
}
|
||||
void SWRast_CreateThreadPool(int numthreads)
|
||||
{
|
||||
int i = 0;
|
||||
swthread_t *t;
|
||||
wq.pos = 0;
|
||||
numthreads = ((numthreads > MAXWORKERTHREADS)?MAXWORKERTHREADS:numthreads);
|
||||
#ifdef MULTITHREAD
|
||||
for (; i < numthreads; i++)
|
||||
{
|
||||
t = &swthreads[i];
|
||||
t->threadnum = i;
|
||||
t->readpoint = wq.pos;
|
||||
t->thread = Sys_CreateThread(WT_Main, t, THREADP_NORMAL, 0);
|
||||
if (!t->thread)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
wq.numthreads = i;
|
||||
}
|
||||
void SWRast_TerminateThreadPool(void)
|
||||
{
|
||||
int i;
|
||||
wqcom_t *com = SWRast_BeginCommand(WTC_DIE, sizeof(com->com));
|
||||
SWRast_EndCommand(com);
|
||||
#ifdef MULTITHREAD
|
||||
for (i = 0; i < wq.numthreads; i++)
|
||||
{
|
||||
Sys_WaitOnThread(swthreads[i].thread);
|
||||
}
|
||||
#endif
|
||||
wq.numthreads = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SW_Draw_Init(void)
|
||||
{
|
||||
R2D_Init();
|
||||
|
||||
R_InitFlashblends();
|
||||
}
|
||||
void SW_Draw_Shutdown(void)
|
||||
{
|
||||
}
|
||||
void SW_R_Init(void)
|
||||
{
|
||||
SWRast_CreateThreadPool(sw_threads.ival);
|
||||
sw_threads.modified = false;
|
||||
}
|
||||
void SW_R_DeInit(void)
|
||||
{
|
||||
SWRast_TerminateThreadPool();
|
||||
}
|
||||
void SW_R_RenderView(void)
|
||||
{
|
||||
extern cvar_t gl_screenangle;
|
||||
extern cvar_t gl_mindist;
|
||||
vec3_t newa;
|
||||
int tmpvisents = cl_numvisedicts; /*world rendering is allowed to add additional ents, but we don't want to keep them for recursive views*/
|
||||
if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
|
||||
r_refdef.flags |= Q2RDF_NOWORLDMODEL;
|
||||
|
||||
// R_SetupGL ();
|
||||
|
||||
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
|
||||
VectorCopy (r_refdef.vieworg, r_origin);
|
||||
if (r_refdef.useperspective)
|
||||
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection, r_refdef.fov_x, r_refdef.fov_y, gl_mindist.value);
|
||||
else
|
||||
{
|
||||
if (gl_maxdist.value>=1)
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, -r_refdef.fov_x/2, r_refdef.fov_x/2, -r_refdef.fov_y/2, r_refdef.fov_y/2, -gl_maxdist.value, gl_maxdist.value);
|
||||
else
|
||||
Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, r_refdef.vrect.width, 0, r_refdef.vrect.height, -9999, 9999);
|
||||
}
|
||||
VectorCopy(r_refdef.viewangles, newa);
|
||||
newa[0] = r_refdef.viewangles[0];
|
||||
newa[1] = r_refdef.viewangles[1];
|
||||
newa[2] = r_refdef.viewangles[2] + gl_screenangle.value;
|
||||
Matrix4x4_CM_ModelViewMatrix(r_refdef.m_view, newa, r_refdef.vieworg);
|
||||
|
||||
R_SetFrustum (r_refdef.m_projection, r_refdef.m_view);
|
||||
|
||||
RQ_BeginFrame();
|
||||
|
||||
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
|
||||
{
|
||||
Surf_DrawWorld (); // adds static entities to the list
|
||||
}
|
||||
else
|
||||
SWBE_DrawWorld(NULL);
|
||||
|
||||
S_ExtraUpdate (); // don't let sound get messed up if going slow
|
||||
|
||||
// R_DrawDecals();
|
||||
|
||||
R_RenderDlights ();
|
||||
|
||||
RQ_RenderBatchClear();
|
||||
|
||||
cl_numvisedicts = tmpvisents;
|
||||
}
|
||||
void SW_R_NewMap(void)
|
||||
{
|
||||
char namebuf[MAX_QPATH];
|
||||
extern cvar_t host_mapname, r_shadow_realtime_dlight, r_shadow_realtime_world;
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
d_lightstylevalue[i] = 264; // normal light value
|
||||
|
||||
memset (&r_worldentity, 0, sizeof(r_worldentity));
|
||||
AngleVectors(r_worldentity.angles, r_worldentity.axis[0], r_worldentity.axis[1], r_worldentity.axis[2]);
|
||||
VectorInverse(r_worldentity.axis[1]);
|
||||
r_worldentity.model = cl.worldmodel;
|
||||
Vector4Set(r_worldentity.shaderRGBAf, 1, 1, 1, 1);
|
||||
|
||||
|
||||
COM_StripExtension(COM_SkipPath(cl.worldmodel->name), namebuf, sizeof(namebuf));
|
||||
Cvar_Set(&host_mapname, namebuf);
|
||||
|
||||
Surf_DeInit();
|
||||
|
||||
r_viewleaf = NULL;
|
||||
r_viewcluster = -1;
|
||||
r_oldviewcluster = 0;
|
||||
r_viewcluster2 = -1;
|
||||
|
||||
Mod_ParseInfoFromEntityLump(cl.worldmodel, cl.worldmodel->entities, cl.worldmodel->name);
|
||||
|
||||
P_ClearParticles ();
|
||||
Surf_WipeStains();
|
||||
CL_RegisterParticles();
|
||||
Surf_BuildLightmaps ();
|
||||
|
||||
|
||||
#ifdef VM_UI
|
||||
UI_Reset();
|
||||
#endif
|
||||
|
||||
TP_NewMap();
|
||||
R_SetSky(cl.skyname);
|
||||
|
||||
#ifdef MAP_PROC
|
||||
if (cl.worldmodel->fromgame == fg_doom3)
|
||||
D3_GenerateAreas(cl.worldmodel);
|
||||
#endif
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival)
|
||||
{
|
||||
R_LoadRTLights();
|
||||
if (rtlights_first == rtlights_max)
|
||||
R_ImportRTLights(cl.worldmodel->entities);
|
||||
}
|
||||
Sh_PreGenerateLights();
|
||||
#endif
|
||||
}
|
||||
void SW_R_PreNewMap(void)
|
||||
{
|
||||
}
|
||||
void SW_SCR_UpdateScreen(void)
|
||||
{
|
||||
wqcom_t *com;
|
||||
|
||||
extern cvar_t gl_screenangle;
|
||||
float w = vid.width, h = vid.height;
|
||||
|
||||
r_refdef.time = realtime;
|
||||
|
||||
SWBE_Set2D();
|
||||
|
||||
SWRast_Sync();
|
||||
SW_VID_SwapBuffers();
|
||||
if (sw_threads.modified)
|
||||
{
|
||||
SWRast_TerminateThreadPool();
|
||||
SWRast_CreateThreadPool(sw_threads.ival);
|
||||
sw_threads.modified = false;
|
||||
}
|
||||
|
||||
com = SWRast_BeginCommand(WTC_VIEWPORT, sizeof(com->viewport));
|
||||
com->viewport.interlace = bound(0, sw_interlace.ival, 15)+1;
|
||||
com->viewport.clearcolour = r_clear.ival;
|
||||
com->viewport.cleardepth = true;
|
||||
SW_VID_UpdateViewport(com);
|
||||
SWRast_EndCommand(com);
|
||||
|
||||
Shader_DoReload();
|
||||
|
||||
//FIXME: playfilm/editor+q3ui
|
||||
if (vid.recalc_refdef)
|
||||
SCR_CalcRefdef ();
|
||||
SCR_SetUpToDrawConsole ();
|
||||
|
||||
if (cls.state == ca_active)
|
||||
{
|
||||
if (!CSQC_DrawView())
|
||||
V_RenderView ();
|
||||
|
||||
R2D_PolyBlend ();
|
||||
R2D_BrightenScreen();
|
||||
}
|
||||
|
||||
SCR_DrawTwoDimensional(0, 0);
|
||||
|
||||
V_UpdatePalette (false);
|
||||
}
|
||||
|
||||
rendererinfo_t swrendererinfo =
|
||||
{
|
||||
"Software Renderer",
|
||||
{
|
||||
"sw",
|
||||
"Software",
|
||||
"SoftRast",
|
||||
},
|
||||
QR_SOFTWARE,
|
||||
|
||||
SW_Draw_Init,
|
||||
SW_Draw_Shutdown,
|
||||
|
||||
SW_LoadTexture,
|
||||
SW_LoadTexture8Pal24,
|
||||
SW_LoadTexture8Pal32,
|
||||
SW_LoadCompressed,
|
||||
SW_FindTexture,
|
||||
SW_AllocNewTexture,
|
||||
SW_Upload,
|
||||
SW_DestroyTexture,
|
||||
|
||||
SW_R_Init,
|
||||
SW_R_DeInit,
|
||||
SW_R_RenderView,
|
||||
|
||||
SW_R_NewMap,
|
||||
SW_R_PreNewMap,
|
||||
|
||||
Surf_AddStain,
|
||||
Surf_LessenStains,
|
||||
|
||||
RMod_Init,
|
||||
RMod_Shutdown,
|
||||
RMod_ClearAll,
|
||||
RMod_ForName,
|
||||
RMod_FindName,
|
||||
RMod_Extradata,
|
||||
RMod_TouchModel,
|
||||
|
||||
RMod_NowLoadExternal,
|
||||
RMod_Think,
|
||||
Mod_GetTag,
|
||||
Mod_TagNumForName,
|
||||
Mod_SkinNumForName,
|
||||
Mod_FrameNumForName,
|
||||
Mod_FrameDuration,
|
||||
|
||||
|
||||
SW_VID_Init,
|
||||
SW_VID_DeInit,
|
||||
SW_VID_SetPalette,
|
||||
SW_VID_ShiftPalette,
|
||||
SW_VID_GetRGBInfo,
|
||||
SW_VID_SetWindowCaption,
|
||||
|
||||
SW_SCR_UpdateScreen,
|
||||
|
||||
SWBE_SelectMode,
|
||||
SWBE_DrawMesh_List,
|
||||
SWBE_DrawMesh_Single,
|
||||
SWBE_SubmitBatch,
|
||||
SWBE_GetTempBatch,
|
||||
SWBE_DrawWorld,
|
||||
SWBE_Init,
|
||||
SWBE_GenBrushModelVBO,
|
||||
SWBE_ClearVBO,
|
||||
SWBE_UploadAllLightmaps,
|
||||
SWBE_SelectEntity,
|
||||
SWBE_SelectDLight,
|
||||
SWBE_LightCullModel,
|
||||
|
||||
"no more"
|
||||
};
|
||||
#endif
|
323
engine/sw/sw_spans.h
Normal file
323
engine/sw/sw_spans.h
Normal file
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
this file is expected to be #included as the body of a real function
|
||||
to define create a new pixel shader, define PLOT_PIXEL(outval) at the top of your function and you're good to go
|
||||
|
||||
//modifiers:
|
||||
SPAN_ST - interpolates S+T across the span. access with 'sc' and 'tc'
|
||||
affine... no perspective correction.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
swvert_t *vt;
|
||||
int y;
|
||||
int secondhalf;
|
||||
int xl,xld, xr,xrd;
|
||||
#ifdef SPAN_ST
|
||||
float sl,sld, sd;
|
||||
float tl,tld, td;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
unsigned int zl,zld, zd;
|
||||
#endif
|
||||
unsigned int *restrict outbuf;
|
||||
unsigned int *restrict ti;
|
||||
int i;
|
||||
const swvert_t *vlt,*vlb,*vrt,*vrb;
|
||||
int spanlen;
|
||||
int numspans;
|
||||
unsigned int *vplout;
|
||||
int dx, dy;
|
||||
int recalcside;
|
||||
int interlace;
|
||||
|
||||
float fdx1,fdy1,fdx2,fdy2,fz,d1,d2;
|
||||
|
||||
if (!img)
|
||||
return;
|
||||
|
||||
/*we basically render a diamond
|
||||
that is, the single triangle is split into two triangles, outwards towards the midpoint and inwards to the final position.
|
||||
*/
|
||||
|
||||
/*reorder the verticies for height*/
|
||||
if (v1->vcoord[1] > v2->vcoord[1])
|
||||
{
|
||||
vt = v1;
|
||||
v1 = v2;
|
||||
v2 = vt;
|
||||
}
|
||||
if (v1->vcoord[1] > v3->vcoord[1])
|
||||
{
|
||||
vt = v1;
|
||||
v1 = v3;
|
||||
v3 = vt;
|
||||
}
|
||||
if (v2->vcoord[1] > v3->vcoord[1])
|
||||
{
|
||||
vt = v3;
|
||||
v3 = v2;
|
||||
v2 = vt;
|
||||
}
|
||||
|
||||
{
|
||||
const swvert_t *v[3];
|
||||
|
||||
v[0] = v1;
|
||||
v[1] = v2;
|
||||
v[2] = v3;
|
||||
|
||||
//reject triangles with any point offscreen, for now
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (v[i]->vcoord[0] < 0 || v[i]->vcoord[0] >= th->vpwidth)
|
||||
return;
|
||||
if (v[i]->vcoord[1] < 0 || v[i]->vcoord[1] >= th->vpheight)
|
||||
return;
|
||||
if (v[i]->vcoord[2] < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
if (v[i]->vcoord[1] > v[i+1]->vcoord[1])
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fdx1 = v2->vcoord[0] - v1->vcoord[0];
|
||||
fdy1 = v2->vcoord[1] - v1->vcoord[1];
|
||||
|
||||
fdx2 = v3->vcoord[0] - v1->vcoord[0];
|
||||
fdy2 = v3->vcoord[1] - v1->vcoord[1];
|
||||
|
||||
fz = fdx1*fdy2 - fdx2*fdy1;
|
||||
|
||||
if (fz == 0)
|
||||
{
|
||||
//weird angle...
|
||||
return;
|
||||
}
|
||||
|
||||
fz = 1.0 / fz;
|
||||
fdx1 *= fz;
|
||||
fdy1 *= fz;
|
||||
fdx2 *= fz;
|
||||
fdy2 *= fz;
|
||||
|
||||
#ifdef SPAN_ST //affine
|
||||
d1 = v2->tccoord[0] - v1->tccoord[0];
|
||||
d2 = v3->tccoord[0] - v1->tccoord[0];
|
||||
sld = fdx1*d2 - fdx2*d1;
|
||||
sd = fdy2*d1 - fdy1*d2;
|
||||
|
||||
d1 = v2->tccoord[1] - v1->tccoord[1];
|
||||
d2 = v3->tccoord[1] - v1->tccoord[1];
|
||||
tld = fdx1*d2 - fdx2*d1;
|
||||
td = fdy2*d1 - fdy1*d2;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
d1 = (v2->vcoord[2] - v1->vcoord[2])*UINT_MAX;
|
||||
d2 = (v3->vcoord[2] - v1->vcoord[2])*UINT_MAX;
|
||||
zld = fdx1*d2 - fdx2*d1;
|
||||
zd = fdy2*d1 - fdy1*d2;
|
||||
#endif
|
||||
|
||||
ti = img->data;
|
||||
|
||||
y = v1->vcoord[1];
|
||||
|
||||
for (secondhalf = 0; secondhalf <= 1; secondhalf++)
|
||||
{
|
||||
if (secondhalf)
|
||||
{
|
||||
if (numspans < 0)
|
||||
{
|
||||
interlace = -numspans;
|
||||
y+=interlace;
|
||||
numspans-=interlace;
|
||||
|
||||
xl += xld*interlace;
|
||||
xr += xrd*interlace;
|
||||
vplout += th->vpcstride*interlace;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl += sld*interlace;
|
||||
tl += tld*interlace;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl += zld*interlace;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*v2->v3*/
|
||||
if (fz <= 0)
|
||||
{
|
||||
vlt = v2;
|
||||
//vrt == v1;
|
||||
vlb = v3;
|
||||
//vrb == v3;
|
||||
|
||||
recalcside = 1;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sld -= sd*xld/(float)(1<<16);
|
||||
tld -= td*xld/(float)(1<<16);
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zld -= zd*xld/(float)(1<<16);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//vlt == v1;
|
||||
vrt = v2;
|
||||
///vlb == v3;
|
||||
vrb = v3;
|
||||
|
||||
recalcside = 2;
|
||||
}
|
||||
|
||||
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
|
||||
numspans = v3->vcoord[1] - y;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlt = v1;
|
||||
vrt = v1;
|
||||
/*v1->v2*/
|
||||
if (fz < 0)
|
||||
{
|
||||
vlb = v2;
|
||||
vrb = v3;
|
||||
}
|
||||
else
|
||||
{
|
||||
vlb = v3;
|
||||
vrb = v2;
|
||||
}
|
||||
recalcside = 3;
|
||||
|
||||
//flip the triangle to keep it facing the screen (we swapped the verts almost randomly)
|
||||
numspans = v2->vcoord[1] - y;
|
||||
}
|
||||
|
||||
if (recalcside & 1)
|
||||
{
|
||||
dx = (vlb->vcoord[0] - vlt->vcoord[0]);
|
||||
dy = (vlb->vcoord[1] - vlt->vcoord[1]);
|
||||
if (dy > 0)
|
||||
xld = (dx<<16) / dy;
|
||||
else
|
||||
xld = 0;
|
||||
xl = (int)vlt->vcoord[0]<<16;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl = vlt->tccoord[0];
|
||||
sld = sld + sd*xld/(float)(1<<16);
|
||||
tl = vlt->tccoord[1];
|
||||
tld = tld + td*xld/(float)(1<<16);
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl = vlt->vcoord[2]*UINT_MAX;
|
||||
zld = zld + zd*xld/(float)(1<<16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (recalcside & 2)
|
||||
{
|
||||
dx = (vrb->vcoord[0] - vrt->vcoord[0]);
|
||||
dy = (vrb->vcoord[1] - vrt->vcoord[1]);
|
||||
if (dy)
|
||||
xrd = (dx<<16) / dy;
|
||||
else
|
||||
xrd = 0;
|
||||
xr = (int)vrt->vcoord[0]<<16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (y + numspans >= th->vpheight)
|
||||
numspans = th->vpheight - y - 1;
|
||||
|
||||
if (numspans <= 0)
|
||||
continue;
|
||||
|
||||
|
||||
vplout = th->vpcbuf + y * th->vpcstride; //this is a pointer to the left of the viewport buffer.
|
||||
|
||||
interlace = ((y + th->interlaceline) % th->interlacemod);
|
||||
if (interlace)
|
||||
{
|
||||
if (interlace > numspans)
|
||||
{
|
||||
interlace = numspans;
|
||||
y+=interlace;
|
||||
}
|
||||
else
|
||||
{
|
||||
y+=interlace;
|
||||
numspans-=interlace;
|
||||
}
|
||||
xl += xld*interlace;
|
||||
xr += xrd*interlace;
|
||||
vplout += th->vpcstride*interlace;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
sl += sld*interlace;
|
||||
tl += tld*interlace;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
zl += zld*interlace;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; numspans > 0;
|
||||
numspans -= th->interlacemod
|
||||
,xl += xld*th->interlacemod
|
||||
,xr += xrd*th->interlacemod
|
||||
,vplout += th->vpcstride*th->interlacemod
|
||||
,y += th->interlacemod
|
||||
|
||||
#ifdef SPAN_ST
|
||||
,sl += sld*th->interlacemod
|
||||
,tl += tld*th->interlacemod
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
,zl += zld*th->interlacemod
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef SPAN_ST
|
||||
float s = sl;
|
||||
float t = tl;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
unsigned int z = zl;
|
||||
unsigned int *restrict zb = th->vpdbuf + y * th->vpwidth + (xl>>16);
|
||||
#endif
|
||||
|
||||
spanlen = (xr - xl)>>16;
|
||||
outbuf = vplout + (xl>>16);
|
||||
|
||||
while(spanlen-->=0)
|
||||
{
|
||||
PLOT_PIXEL(*outbuf);
|
||||
outbuf++;
|
||||
|
||||
#ifdef SPAN_ST
|
||||
s += sd;
|
||||
t += td;
|
||||
#endif
|
||||
#ifdef SPAN_Z
|
||||
z += zd;
|
||||
zb++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPAN_ST
|
||||
#undef PLOT_PIXEL
|
761
engine/sw/sw_vidwin.c
Normal file
761
engine/sw/sw_vidwin.c
Normal file
|
@ -0,0 +1,761 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef SWQUAKE
|
||||
#include "sw.h"
|
||||
|
||||
#include "winquake.h"
|
||||
/*Fixup outdated windows headers*/
|
||||
#ifndef WM_XBUTTONDOWN
|
||||
#define WM_XBUTTONDOWN 0x020B
|
||||
#define WM_XBUTTONUP 0x020C
|
||||
#endif
|
||||
#ifndef MK_XBUTTON1
|
||||
#define MK_XBUTTON1 0x0020
|
||||
#endif
|
||||
#ifndef MK_XBUTTON2
|
||||
#define MK_XBUTTON2 0x0040
|
||||
#endif
|
||||
// copied from DarkPlaces in an attempt to grab more buttons
|
||||
#ifndef MK_XBUTTON3
|
||||
#define MK_XBUTTON3 0x0080
|
||||
#endif
|
||||
#ifndef MK_XBUTTON4
|
||||
#define MK_XBUTTON4 0x0100
|
||||
#endif
|
||||
#ifndef MK_XBUTTON5
|
||||
#define MK_XBUTTON5 0x0200
|
||||
#endif
|
||||
#ifndef MK_XBUTTON6
|
||||
#define MK_XBUTTON6 0x0400
|
||||
#endif
|
||||
#ifndef MK_XBUTTON7
|
||||
#define MK_XBUTTON7 0x0800
|
||||
#endif
|
||||
#ifndef WM_INPUT
|
||||
#define WM_INPUT 255
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct dibinfo
|
||||
{
|
||||
BITMAPINFOHEADER header;
|
||||
RGBQUAD acolors[256];
|
||||
} dibinfo_t;
|
||||
|
||||
//struct
|
||||
//{
|
||||
HBITMAP hDIBSection;
|
||||
qbyte *pDIBBase;
|
||||
|
||||
HDC mainhDC;
|
||||
HDC hdcDIBSection;
|
||||
HGDIOBJ previously_selected_GDI_obj;
|
||||
|
||||
int framenumber;
|
||||
void *screenbuffer;
|
||||
qintptr_t screenpitch;
|
||||
int window_x, window_y;
|
||||
unsigned int *depthbuffer;
|
||||
struct
|
||||
{
|
||||
qboolean isfullscreen;
|
||||
} w32sw;
|
||||
HWND mainwindow;
|
||||
|
||||
void DIB_Shutdown(void)
|
||||
{
|
||||
if (depthbuffer)
|
||||
{
|
||||
BZ_Free(depthbuffer);
|
||||
depthbuffer = NULL;
|
||||
}
|
||||
|
||||
if (hdcDIBSection)
|
||||
{
|
||||
SelectObject(hdcDIBSection, previously_selected_GDI_obj);
|
||||
DeleteDC(hdcDIBSection);
|
||||
hdcDIBSection = NULL;
|
||||
}
|
||||
|
||||
if (hDIBSection)
|
||||
{
|
||||
DeleteObject(hDIBSection);
|
||||
hDIBSection = NULL;
|
||||
pDIBBase = NULL;
|
||||
}
|
||||
|
||||
if (mainhDC)
|
||||
{
|
||||
ReleaseDC(mainwindow, mainhDC);
|
||||
mainhDC = 0;
|
||||
}
|
||||
}
|
||||
qboolean DIB_Init(void)
|
||||
{
|
||||
dibinfo_t dibheader;
|
||||
BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
|
||||
int i;
|
||||
|
||||
memset( &dibheader, 0, sizeof( dibheader ) );
|
||||
|
||||
/*
|
||||
** grab a DC
|
||||
*/
|
||||
if ( !mainhDC )
|
||||
{
|
||||
if ( ( mainhDC = GetDC( mainwindow ) ) == NULL )
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** fill in the BITMAPINFO struct
|
||||
*/
|
||||
pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
pbmiDIB->bmiHeader.biWidth = vid.pixelwidth;
|
||||
pbmiDIB->bmiHeader.biHeight = vid.pixelheight;
|
||||
pbmiDIB->bmiHeader.biPlanes = 1;
|
||||
pbmiDIB->bmiHeader.biBitCount = 32;
|
||||
pbmiDIB->bmiHeader.biCompression = BI_RGB;
|
||||
pbmiDIB->bmiHeader.biSizeImage = 0;
|
||||
pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
|
||||
pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
|
||||
pbmiDIB->bmiHeader.biClrUsed = 0;
|
||||
pbmiDIB->bmiHeader.biClrImportant = 0;
|
||||
|
||||
/*
|
||||
** fill in the palette
|
||||
*/
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
dibheader.acolors[i].rgbRed = ( d_8to24rgbtable[i] >> 0 ) & 0xff;
|
||||
dibheader.acolors[i].rgbGreen = ( d_8to24rgbtable[i] >> 8 ) & 0xff;
|
||||
dibheader.acolors[i].rgbBlue = ( d_8to24rgbtable[i] >> 16 ) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
** create the DIB section
|
||||
*/
|
||||
hDIBSection = CreateDIBSection( mainhDC,
|
||||
pbmiDIB,
|
||||
DIB_RGB_COLORS,
|
||||
(void**)&pDIBBase,
|
||||
NULL,
|
||||
0 );
|
||||
|
||||
if ( hDIBSection == NULL )
|
||||
{
|
||||
Con_Printf( "DIB_Init() - CreateDIBSection failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pbmiDIB->bmiHeader.biHeight < 0)
|
||||
{
|
||||
// bottom up
|
||||
screenbuffer = pDIBBase + ( vid.pixelheight - 1 ) * vid.pixelwidth * 4;
|
||||
screenpitch = -(int)vid.pixelwidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
// top down
|
||||
screenbuffer = pDIBBase;
|
||||
screenpitch = vid.pixelwidth;
|
||||
}
|
||||
|
||||
/*
|
||||
** clear the DIB memory buffer
|
||||
*/
|
||||
memset( pDIBBase, 0, vid.pixelwidth * vid.pixelheight * 4);
|
||||
|
||||
if ( ( hdcDIBSection = CreateCompatibleDC( mainhDC ) ) == NULL )
|
||||
{
|
||||
Con_Printf( "DIB_Init() - CreateCompatibleDC failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
if ( ( previously_selected_GDI_obj = SelectObject( hdcDIBSection, hDIBSection ) ) == NULL )
|
||||
{
|
||||
Con_Printf( "DIB_Init() - SelectObject failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
depthbuffer = BZ_Malloc(vid.pixelwidth * vid.pixelheight * sizeof(*depthbuffer));
|
||||
if (depthbuffer)
|
||||
return true;
|
||||
|
||||
fail:
|
||||
DIB_Shutdown();
|
||||
return false;
|
||||
}
|
||||
void DIB_SwapBuffers(void)
|
||||
{
|
||||
// extern float usingstretch;
|
||||
|
||||
// if (usingstretch == 1)
|
||||
BitBlt( mainhDC,
|
||||
0, 0,
|
||||
vid.pixelwidth,
|
||||
vid.pixelheight,
|
||||
hdcDIBSection,
|
||||
0, 0,
|
||||
SRCCOPY );
|
||||
/* else
|
||||
StretchBlt( mainhDC, //Why is StretchBlt not optimised for a scale of 2? Surly that would be a frequently used quantity?
|
||||
0, 0,
|
||||
vid.width*usingstretch,
|
||||
vid.height*usingstretch,
|
||||
hdcDIBSection,
|
||||
0, 0,
|
||||
vid.width, vid.height,
|
||||
SRCCOPY );
|
||||
*/
|
||||
}
|
||||
|
||||
extern int window_width;
|
||||
extern int window_height;
|
||||
void SWV_UpdateWindowStatus(void)
|
||||
{
|
||||
POINT p;
|
||||
RECT nr;
|
||||
RECT WindowRect;
|
||||
GetClientRect(mainwindow, &nr);
|
||||
|
||||
//if its bad then we're probably minimised
|
||||
if (nr.right <= nr.left)
|
||||
return;
|
||||
if (nr.bottom <= nr.top)
|
||||
return;
|
||||
|
||||
WindowRect = nr;
|
||||
p.x = 0;
|
||||
p.y = 0;
|
||||
ClientToScreen(mainwindow, &p);
|
||||
window_x = p.x;
|
||||
window_y = p.y;
|
||||
window_width = WindowRect.right - WindowRect.left;
|
||||
window_height = WindowRect.bottom - WindowRect.top;
|
||||
|
||||
window_rect.left = window_x;
|
||||
window_rect.top = window_y;
|
||||
window_rect.right = window_x + window_width;
|
||||
window_rect.bottom = window_y + window_height;
|
||||
window_center_x = (window_rect.left + window_rect.right) / 2;
|
||||
window_center_y = (window_rect.top + window_rect.bottom) / 2;
|
||||
|
||||
IN_UpdateClipCursor ();
|
||||
}
|
||||
|
||||
|
||||
qboolean SWAppActivate(BOOL fActive, BOOL minimize)
|
||||
/****************************************************************************
|
||||
*
|
||||
* Function: AppActivate
|
||||
* Parameters: fActive - True if app is activating
|
||||
*
|
||||
* Description: If the application is activating, then swap the system
|
||||
* into SYSPAL_NOSTATIC mode so that our palettes will display
|
||||
* correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
{
|
||||
static BOOL sound_active;
|
||||
|
||||
if (ActiveApp == fActive && Minimized == minimize)
|
||||
return false; //so windows doesn't crash us over and over again.
|
||||
|
||||
ActiveApp = fActive;
|
||||
Minimized = minimize;
|
||||
|
||||
// enable/disable sound on focus gain/loss
|
||||
if (!ActiveApp && sound_active)
|
||||
{
|
||||
S_BlockSound ();
|
||||
sound_active = false;
|
||||
}
|
||||
else if (ActiveApp && !sound_active)
|
||||
{
|
||||
S_UnblockSound ();
|
||||
sound_active = true;
|
||||
}
|
||||
|
||||
IN_UpdateGrabs(false, ActiveApp);
|
||||
|
||||
/*
|
||||
if (fActive)
|
||||
{
|
||||
if (modestate != MS_WINDOWED)
|
||||
{
|
||||
if (vid_canalttab && vid_wassuspended) {
|
||||
vid_wassuspended = false;
|
||||
ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN);
|
||||
ShowWindow(mainwindow, SW_SHOWNORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fActive)
|
||||
{
|
||||
if (modestate != MS_WINDOWED)
|
||||
{
|
||||
if (vid_canalttab) {
|
||||
ChangeDisplaySettings (NULL, 0);
|
||||
vid_wassuspended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
LONG WINAPI MainWndProc (
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
LONG lRet = 0;
|
||||
int fActive, fMinimized, temp;
|
||||
HDC hdc;
|
||||
PAINTSTRUCT ps;
|
||||
extern unsigned int uiWheelMessage;
|
||||
// static int recursiveflag;
|
||||
|
||||
if ( uMsg == uiWheelMessage ) {
|
||||
uMsg = WM_MOUSEWHEEL;
|
||||
wParam <<= 16;
|
||||
}
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
|
||||
// Check for maximize being hit
|
||||
switch (wParam & ~0x0F)
|
||||
{
|
||||
case SC_MAXIMIZE:
|
||||
Cbuf_AddText("vid_fullscreen 1;vid_restart\n", RESTRICT_LOCAL);
|
||||
// if minimized, bring up as a window before going fullscreen,
|
||||
// so MGL will have the right state to restore
|
||||
/* if (Minimized)
|
||||
{
|
||||
force_mode_set = true;
|
||||
VID_SetMode (vid_modenum, vid_curpal);
|
||||
force_mode_set = false;
|
||||
}
|
||||
|
||||
VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
|
||||
*/ break;
|
||||
|
||||
case SC_SCREENSAVE:
|
||||
case SC_MONITORPOWER:
|
||||
if (w32sw.isfullscreen)
|
||||
{
|
||||
// don't call DefWindowProc() because we don't want to start
|
||||
// the screen saver fullscreen
|
||||
break;
|
||||
}
|
||||
|
||||
// fall through windowed and allow the screen saver to start
|
||||
|
||||
default:
|
||||
// if (!vid_initializing)
|
||||
// {
|
||||
// S_BlockSound ();
|
||||
// }
|
||||
|
||||
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
// if (!vid_initializing)
|
||||
// {
|
||||
// S_UnblockSound ();
|
||||
// }
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOVE:
|
||||
SWV_UpdateWindowStatus ();
|
||||
|
||||
// if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized)
|
||||
// VID_RememberWindowPos ();
|
||||
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
SWV_UpdateWindowStatus ();
|
||||
/* Minimized = false;
|
||||
|
||||
if (!(wParam & SIZE_RESTORED))
|
||||
{
|
||||
if (wParam & SIZE_MINIMIZED)
|
||||
Minimized = true;
|
||||
}
|
||||
|
||||
if (!Minimized && !w32sw.isfullscreen)
|
||||
{
|
||||
int nt, nl;
|
||||
int nw, nh;
|
||||
qboolean move = false;
|
||||
RECT r;
|
||||
GetClientRect (hWnd, &r);
|
||||
nw = (int)(r.right - r.left)&~3;
|
||||
nh = (int)(r.bottom - r.top)&~3;
|
||||
|
||||
window_width = nw;
|
||||
window_height = nh;
|
||||
VID2_UpdateWindowStatus();
|
||||
|
||||
if (nw < 320)
|
||||
{
|
||||
move = true;
|
||||
nw = 320;
|
||||
}
|
||||
if (nh < 200)
|
||||
{
|
||||
move = true;
|
||||
nh = 200;
|
||||
}
|
||||
if (nh > MAXHEIGHT)
|
||||
{
|
||||
move = true;
|
||||
nh = MAXHEIGHT;
|
||||
}
|
||||
if ((r.right - r.left) & 3)
|
||||
move = true;
|
||||
if ((r.bottom - r.top) & 3)
|
||||
move = true;
|
||||
|
||||
GetWindowRect (hWnd, &r);
|
||||
nl = r.left;
|
||||
nt = r.top;
|
||||
r.left =0;
|
||||
r.top = 0;
|
||||
r.right = nw*usingstretch;
|
||||
r.bottom = nh*usingstretch;
|
||||
AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW, FALSE, 0);
|
||||
vid.recalc_refdef = true;
|
||||
if (move)
|
||||
MoveWindow(hWnd, nl, nt, r.right - r.left, r.bottom - r.top, true);
|
||||
else
|
||||
{
|
||||
if (vid.width != nw || vid.height != nh)
|
||||
{
|
||||
M_RemoveAllMenus(); //can cause probs
|
||||
DIB_Shutdown();
|
||||
vid.conwidth = vid.width = nw;//vid_stretch.value;
|
||||
vid.conheight = vid.height = nh;///vid_stretch.value;
|
||||
|
||||
DIB_Init( &vid.buffer, &vid.rowbytes );
|
||||
vid.conbuffer = vid.buffer;
|
||||
vid.conrowbytes = vid.rowbytes;
|
||||
|
||||
if (VID_AllocBuffers(vid.width, vid.height, r_pixbytes))
|
||||
D_InitCaches (vid_surfcache, vid_surfcachesize);
|
||||
|
||||
SCR_UpdateWholeScreen();
|
||||
}
|
||||
else
|
||||
SCR_UpdateWholeScreen();
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
break;
|
||||
|
||||
case WM_SYSCHAR:
|
||||
// keep Alt-Space from happening
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
fActive = LOWORD(wParam);
|
||||
fMinimized = (BOOL) HIWORD(wParam);
|
||||
SWAppActivate(!(fActive == WA_INACTIVE), fMinimized);
|
||||
|
||||
// fix the leftover Alt from any Alt-Tab or the like that switched us away
|
||||
// ClearAllStates ();
|
||||
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
hdc = BeginPaint(hWnd, &ps);
|
||||
|
||||
// if (!in_mode_set && host_initialized)
|
||||
// SCR_UpdateWholeScreen ();
|
||||
|
||||
EndPaint(hWnd, &ps);
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
// if (!vid_initializing)
|
||||
IN_TranslateKeyEvent(wParam, lParam, true, 0);
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
// if (!vid_initializing)
|
||||
IN_TranslateKeyEvent(wParam, lParam, false, 0);
|
||||
break;
|
||||
|
||||
// this is complicated because Win32 seems to pack multiple mouse events into
|
||||
// one update sometimes, so we always check all states and look for events
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_XBUTTONDOWN:
|
||||
case WM_XBUTTONUP:
|
||||
// if (!vid_initializing)
|
||||
{
|
||||
temp = 0;
|
||||
|
||||
if (wParam & MK_LBUTTON)
|
||||
temp |= 1;
|
||||
|
||||
if (wParam & MK_RBUTTON)
|
||||
temp |= 2;
|
||||
|
||||
if (wParam & MK_MBUTTON)
|
||||
temp |= 4;
|
||||
|
||||
// extra buttons
|
||||
if (wParam & MK_XBUTTON1)
|
||||
temp |= 8;
|
||||
|
||||
if (wParam & MK_XBUTTON2)
|
||||
temp |= 16;
|
||||
|
||||
if (wParam & MK_XBUTTON3)
|
||||
temp |= 32;
|
||||
|
||||
if (wParam & MK_XBUTTON4)
|
||||
temp |= 64;
|
||||
|
||||
if (wParam & MK_XBUTTON5)
|
||||
temp |= 128;
|
||||
|
||||
if (wParam & MK_XBUTTON6)
|
||||
temp |= 256;
|
||||
|
||||
if (wParam & MK_XBUTTON7)
|
||||
temp |= 512;
|
||||
|
||||
IN_MouseEvent (temp);
|
||||
}
|
||||
break;
|
||||
// JACK: This is the mouse wheel with the Intellimouse
|
||||
// Its delta is either positive or neg, and we generate the proper
|
||||
// Event.
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
if ((short) HIWORD(wParam) > 0)
|
||||
{
|
||||
Key_Event(0, K_MWHEELUP, 0, true);
|
||||
Key_Event(0, K_MWHEELUP, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event(0, K_MWHEELDOWN, 0, true);
|
||||
Key_Event(0, K_MWHEELDOWN, 0, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_INPUT:
|
||||
// raw input handling
|
||||
IN_RawInput_Read((HANDLE)lParam);
|
||||
break;
|
||||
/* case WM_DISPLAYCHANGE:
|
||||
if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode)
|
||||
{
|
||||
force_mode_set = true;
|
||||
VID_SetMode (vid_modenum, vid_curpal);
|
||||
force_mode_set = false;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
case WM_CLOSE:
|
||||
// this causes Close in the right-click task bar menu not to work, but right
|
||||
// now bad things happen if Close is handled in that case (garbage and a
|
||||
// crash on Win95)
|
||||
// if (!vid_initializing)
|
||||
{
|
||||
if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
|
||||
MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
|
||||
{
|
||||
Cbuf_AddText("\nquit\n", RESTRICT_LOCAL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MM_MCINOTIFY:
|
||||
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* pass all unhandled messages to DefWindowProc */
|
||||
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
||||
/* return 0 if handled message, 1 if not */
|
||||
return lRet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** VID_CreateWindow
|
||||
*/
|
||||
#define WINDOW_CLASS_NAME FULLENGINENAME
|
||||
#define WINDOW_TITLE_NAME FULLENGINENAME
|
||||
|
||||
|
||||
void VID_CreateWindow(int width, int height, qboolean fullscreen)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
RECT r;
|
||||
int x, y, w, h;
|
||||
int exstyle;
|
||||
int stylebits;
|
||||
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
exstyle = WS_EX_TOPMOST;
|
||||
stylebits = WS_POPUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
exstyle = 0;
|
||||
stylebits = WS_OVERLAPPEDWINDOW;
|
||||
}
|
||||
|
||||
/* Register the frame class */
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = (WNDPROC)MainWndProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = global_hInstance;
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
|
||||
wc.hbrBackground = (void *)COLOR_GRAYTEXT;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.lpszClassName = WINDOW_CLASS_NAME;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
r.left = 0;
|
||||
r.top = 0;
|
||||
r.right = width;
|
||||
r.bottom = height;
|
||||
|
||||
AdjustWindowRectEx (&r, stylebits, FALSE, exstyle);
|
||||
|
||||
window_rect = r;
|
||||
|
||||
w = r.right - r.left;
|
||||
h = r.bottom - r.top;
|
||||
x = 0;//vid_xpos.value;
|
||||
y = 0;//vid_ypos.value;
|
||||
|
||||
mainwindow = CreateWindowEx(
|
||||
exstyle,
|
||||
WINDOW_CLASS_NAME,
|
||||
WINDOW_TITLE_NAME,
|
||||
stylebits,
|
||||
x, y, w, h,
|
||||
NULL,
|
||||
NULL,
|
||||
global_hInstance,
|
||||
NULL);
|
||||
|
||||
if (!mainwindow)
|
||||
Sys_Error("Couldn't create window");
|
||||
|
||||
ShowWindow(mainwindow, SW_SHOWNORMAL);
|
||||
UpdateWindow(mainwindow);
|
||||
SetForegroundWindow(mainwindow);
|
||||
SetFocus(mainwindow);
|
||||
|
||||
SWV_UpdateWindowStatus();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SW_VID_UpdateViewport(wqcom_t *com)
|
||||
{
|
||||
com->viewport.cbuf = screenbuffer;
|
||||
com->viewport.dbuf = depthbuffer;
|
||||
com->viewport.width = vid.pixelwidth;
|
||||
com->viewport.height = vid.pixelheight;
|
||||
com->viewport.stride = screenpitch;
|
||||
com->viewport.framenum = framenumber;
|
||||
|
||||
/* com->viewport.buf = pDIBBase;
|
||||
com->viewport.width = vid.pixelwidth;
|
||||
com->viewport.height = vid.pixelheight;
|
||||
com->viewport.stride = vid.pixelwidth;
|
||||
com->viewport.framenum = framenumber;*/
|
||||
}
|
||||
|
||||
void SW_VID_SwapBuffers(void)
|
||||
{
|
||||
extern cvar_t vid_conautoscale;
|
||||
DIB_SwapBuffers();
|
||||
framenumber++;
|
||||
|
||||
IN_UpdateGrabs(false, ActiveApp);
|
||||
|
||||
// memset( pDIBBase, 0, vid.pixelwidth * vid.pixelheight * 4);
|
||||
|
||||
|
||||
if (window_width != vid.pixelwidth || window_height != vid.pixelheight)
|
||||
{
|
||||
DIB_Shutdown();
|
||||
vid.pixelwidth = window_width;
|
||||
vid.pixelheight = window_height;
|
||||
if (!DIB_Init())
|
||||
Sys_Error("resize reinitialization error");
|
||||
|
||||
Cvar_ForceCallback(&vid_conautoscale);
|
||||
}
|
||||
}
|
||||
|
||||
qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette)
|
||||
{
|
||||
vid.pixelwidth = info->width;
|
||||
vid.pixelheight = info->height;
|
||||
|
||||
VID_CreateWindow(vid.pixelwidth, vid.pixelheight, false);
|
||||
|
||||
if (!DIB_Init())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
void SW_VID_DeInit(void)
|
||||
{
|
||||
DIB_Shutdown();
|
||||
DestroyWindow(mainwindow);
|
||||
}
|
||||
void SW_VID_SetPalette(unsigned char *palette)
|
||||
{
|
||||
}
|
||||
void SW_VID_ShiftPalette(unsigned char *palette)
|
||||
{
|
||||
}
|
||||
char *SW_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidheight)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void SW_VID_SetWindowCaption(char *msg)
|
||||
{
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue