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:
Spoike 2012-05-14 01:41:08 +00:00
parent 757b50efa1
commit 4db8b46c4b
31 changed files with 3533 additions and 181 deletions

View File

@ -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();
}

View File

@ -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);

View File

@ -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++;

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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));
}

View File

@ -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*/

View File

@ -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)
@ -3822,9 +3850,7 @@ void GLBE_DrawLightPrePass(qbyte *vis, batch_t **batches)
BE_SelectMode(BEM_STANDARD);
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

View File

@ -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();

View File

@ -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))

View File

@ -32,6 +32,7 @@ struct world_s;
typedef enum {
SHADER_SORT_NONE,
SHADER_SORT_RIPPLE,
SHADER_SORT_PRELIGHT,
SHADER_SORT_PORTAL,
SHADER_SORT_SKY,

View File

@ -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);

View File

@ -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))

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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