From 5f71f6d355761ff55ed9efd2abaccb2ba5f8bb07 Mon Sep 17 00:00:00 2001 From: Spoike Date: Thu, 11 Nov 2010 18:22:49 +0000 Subject: [PATCH] Portals, skyspheres, particles, lighting, texture clamps work. git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3651 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/p_script.c | 5 + engine/client/quakedef.h | 10 +- engine/client/r_surf.c | 5 +- engine/client/render.h | 13 +- engine/client/renderer.c | 6 +- engine/common/com_mesh.c | 11 +- engine/common/gl_q2bsp.c | 5 +- engine/d3d/d3d_backend.c | 434 +++++++++++++++++++++++++++++++++++---- engine/d3d/d3d_image.c | 35 ++-- engine/d3d/vid_d3d.c | 15 +- engine/gl/gl_backend.c | 4 +- engine/gl/gl_rmain.c | 3 +- engine/gl/gl_shader.c | 1 + engine/gl/gl_warp.c | 31 ++- engine/gl/glquake.h | 8 - engine/gl/shader.h | 2 + 16 files changed, 486 insertions(+), 102 deletions(-) diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 34ba691e4..860de1035 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -518,6 +518,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) namepostfix = "_blend"; defaultshader = "{\n" + "nomipmaps\n" "{\n" "map $diffuse\n" "blendfunc blend\n" @@ -532,6 +533,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) namepostfix = "_bc"; defaultshader = "{\n" + "nomipmaps\n" "{\n" "map $diffuse\n" "blendfunc GL_SRC_COLOR GL_ONE_MINUS_SRC_COLOR\n" @@ -546,6 +548,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) namepostfix = "_add"; defaultshader = "{\n" + "nomipmaps\n" "{\n" "map $diffuse\n" "blendfunc GL_SRC_ALPHA GL_ONE\n" @@ -560,6 +563,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) namepostfix = "_invmod"; defaultshader = "{\n" + "nomipmaps\n" "{\n" "map $diffuse\n" "blendfunc GL_ZERO GL_ONE_MINUS_SRC_COLOR\n" @@ -574,6 +578,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) namepostfix = "_sub"; defaultshader = "{\n" + "nomipmaps\n" "{\n" "map $diffuse\n" "blendfunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_COLOR\n" diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 6ddeb1d62..ff5febb64 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -132,7 +132,6 @@ extern "C" { #include "net.h" #include "protocol.h" #include "cmd.h" -#if 1//ndef SERVERONLY #include "wad.h" #include "screen.h" #include "sbar.h" @@ -140,17 +139,10 @@ extern "C" { #include "merged.h" #include "render.h" #include "client.h" -#endif +#include "gl_model.h" #include "vm.h" - -//#if defined(GLQUAKE) -#include "gl_model.h" -//#else -//#include "model.h" -//#endif - #ifdef PEXT_BULLETENS #include "r_bulleten.h" #endif diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 77e42d12d..fc84ee12d 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2082,7 +2082,7 @@ void Surf_DrawWorld (void) RSpeedRemark(); #ifdef Q2BSPS - if (currententity->model->fromgame == fg_quake2 || currententity->model->fromgame == fg_quake3) + if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) { int leafnum; int clientarea; @@ -2132,7 +2132,8 @@ void Surf_DrawWorld (void) /*FIXME: move this away*/ - Surf_LessenStains(); + if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife) + Surf_LessenStains(); Surf_CleanChains(); } diff --git a/engine/client/render.h b/engine/client/render.h index 2559e6dea..81cd91e7a 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -31,6 +31,9 @@ extern int r_framecount; struct msurface_s; struct batch_s; +struct model_s; +struct texnums_s; +struct texture_s; static const texid_t r_nulltex = {0}; #define TEXVALID(t) ((t).num!=0) @@ -155,16 +158,16 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; - //gl_alias.c void R_GAlias_DrawBatch(struct batch_s *batch); void R_GAlias_GenerateBatches(entity_t *e, struct batch_s **batches); -void R_LightArraysByte(vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3_t *normals); +void R_LightArraysByte_BGR(vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3_t *normals); void R_LightArrays(vecV_t *coords, vec4_t *colours, int vertcount, vec3_t *normals); +void R_DrawSkyChain (struct batch_s *batch); /*called from the backend, and calls back into it*/ +struct texnums_s R_InitSky (struct texture_s *mt, qbyte *src); /*generate q1 sky texnums*/ + //r_surf.c -struct model_s; -struct msurface_s; void Surf_DrawWorld(void); void Surf_GenBrushBatches(struct batch_s **batches, entity_t *ent); void Surf_StainSurf(struct msurface_s *surf, float *parms); @@ -412,7 +415,7 @@ extern cvar_t r_xflip; #endif extern cvar_t gl_maxdist; -extern cvar_t gl_clear; +extern cvar_t r_clear; extern cvar_t gl_poly; extern cvar_t gl_affinemodels; extern cvar_t gl_nohwblend; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a4f3e0ce1..382152f5d 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -266,6 +266,8 @@ cvar_t gl_lightmap_shift = SCVARF ("gl_lightmap_shift", "0", cvar_t gl_load24bit = SCVARF ("gl_load24bit", "1", CVAR_ARCHIVE); +cvar_t r_clear = CVARAF("r_clear","0", + "gl_clear", 0); cvar_t gl_max_size = SCVARF ("gl_max_size", "1024", CVAR_RENDERERLATCH); cvar_t gl_maxshadowlights = SCVARF ("gl_maxshadowlights", "2", CVAR_ARCHIVE); @@ -369,9 +371,6 @@ void GLRenderer_Init(void) Cvar_Register (&r_mirroralpha, GLRENDEREROPTIONS); Cvar_Register (&r_norefresh, GLRENDEREROPTIONS); - - Cvar_Register (&gl_clear, GLRENDEREROPTIONS); - Cvar_Register (&gl_affinemodels, GLRENDEREROPTIONS); Cvar_Register (&gl_nohwblend, GLRENDEREROPTIONS); Cvar_Register (&r_flashblend, GLRENDEREROPTIONS); @@ -604,6 +603,7 @@ void Renderer_Init(void) Cvar_Register (&r_fastskycolour, GRAPHICALNICETIES); Cvar_Register (&r_wateralpha, GRAPHICALNICETIES); + Cvar_Register (&r_clear, GLRENDEREROPTIONS); Cvar_Register (&gl_max_size, GLRENDEREROPTIONS); Cvar_Register (&gl_maxdist, GLRENDEREROPTIONS); Cvar_Register (&gl_miptexLevel, GRAPHICALNICETIES); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 68113d85a..31b7ae976 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -898,7 +898,7 @@ avec3_t shadelight; #include #endif -void R_LightArraysByte(vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3_t *normals) +void R_LightArraysByte_BGR(vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3_t *normals) { extern cvar_t r_vertexdlights; int i; @@ -908,8 +908,13 @@ void R_LightArraysByte(vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3 byte_vec4_t ambientlightb; byte_vec4_t shadelightb; - VectorScale(ambientlight, 255, ambientlightb); - VectorScale(shadelight, 255, shadelightb); + for (i = 0; i < 3; i++) + { + l = ambientlight[2-i]*255; + ambientlightb[i] = bound(0, l, 255); + l = shadelight[2-i]*255; + shadelightb[i] = bound(0, l, 255); + } if (ambientlightb[0] == shadelightb[0] && ambientlightb[1] == shadelightb[1] && ambientlightb[2] == shadelightb[2]) { diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index e8e7af8e5..72f506cfd 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -1364,7 +1364,7 @@ qboolean CMod_LoadFaces (lump_t *l) i = LittleLong(in->lightofs); if (i == -1) out->samples = NULL; -#ifdef GLQUAKE +#if defined(GLQUAKE) || defined(D3DQUAKE) else if (qrenderer == QR_OPENGL || qrenderer == QR_DIRECT3D) out->samples = loadmodel->lightdata + i; #endif @@ -3835,7 +3835,8 @@ q2cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned loadmodel->funcs.NativeContents = CM_NativeContents; break; -#if defined(GLQUAKE) +#if defined(GLQUAKE) || defined(D3DQUAKE) + case QR_DIRECT3D: case QR_OPENGL: // load into heap #ifndef SERVERONLY diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 35d1c6daa..d456ef7ad 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -128,6 +128,7 @@ typedef struct unsigned int lastpasscount; texid_t curtex[MAX_TMUS]; + unsigned int tmuflags[MAX_TMUS]; mesh_t **meshlist; unsigned int nummeshes; @@ -494,7 +495,6 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) case T_GEN_ANIMMAP: BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes].ptr); break; - /*fixme*/ case T_GEN_SINGLEMAP: BindTexture(tu, pass->anim_frames[0].ptr); break; @@ -513,18 +513,39 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) break; } - /*lightmaps don't use mipmaps*/ - if (pass->flags & SHADER_PASS_NOMIPMAP) + + if ((pass->flags ^ shaderstate.tmuflags[tu]) & SHADER_PASS_CLAMP) { - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + shaderstate.tmuflags[tu] ^= SHADER_PASS_CLAMP; + if (pass->flags & SHADER_PASS_CLAMP) + { + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); + } + else + { + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP); + } } - else + if ((pass->flags ^ shaderstate.tmuflags[tu]) & SHADER_PASS_NOMIPMAP) { - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + shaderstate.tmuflags[tu] ^= SHADER_PASS_NOMIPMAP; + /*lightmaps don't use mipmaps*/ + if (pass->flags & SHADER_PASS_NOMIPMAP) + { + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + else + { + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(pD3DDev9, tu, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } } switch (pass->blendmode) @@ -689,7 +710,7 @@ static void colourgenbyte(const shaderpass_t *pass, int cnt, const byte_vec4_t * } else { - R_LightArraysByte(mesh->xyz_array, dst, cnt, mesh->normals_array); + R_LightArraysByte_BGR(mesh->xyz_array, dst, cnt, mesh->normals_array); } break; case RGB_GEN_WAVE: @@ -855,10 +876,10 @@ static unsigned int BE_GenerateColourMods(unsigned int vertcount, const shaderpa } } else if (m->colors4f_array && - (pass->rgbgen == RGB_GEN_VERTEX) || + ((pass->rgbgen == RGB_GEN_VERTEX) || (pass->rgbgen == RGB_GEN_EXACT_VERTEX) || (pass->rgbgen == RGB_GEN_ONE_MINUS_VERTEX) || - (pass->alphagen == ALPHA_GEN_VERTEX)) + (pass->alphagen == ALPHA_GEN_VERTEX))) { for (vertcount = 0, mno = 0; mno < shaderstate.nummeshes; mno++) { @@ -1396,6 +1417,33 @@ static qboolean BE_DrawMeshChain_SetupPass(shaderpass_t *pass, unsigned int vert return true; } +static void BE_Cull(unsigned int cullflags) +{ + cullflags |= r_refdef.flipcull; + if (shaderstate.curcull != cullflags) + { + shaderstate.curcull = cullflags; + if (shaderstate.curcull & 1) + { + if (shaderstate.curcull & SHADER_CULL_FRONT) + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CW); + else if (shaderstate.curcull & SHADER_CULL_BACK) + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CCW); + else + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_NONE); + } + else + { + if (shaderstate.curcull & SHADER_CULL_FRONT) + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CCW); + else if (shaderstate.curcull & SHADER_CULL_BACK) + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CW); + else + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_NONE); + } + } +} + static void BE_DrawMeshChain_Internal(void) { unsigned int vertcount, idxcount, idxfirst; @@ -1406,16 +1454,7 @@ static void BE_DrawMeshChain_Internal(void) unsigned int passno = 0; shaderpass_t *pass = shaderstate.curshader->passes; - if (shaderstate.curcull != (shaderstate.curshader->flags & (SHADER_CULL_FRONT | SHADER_CULL_BACK))) - { - shaderstate.curcull = shaderstate.curshader->flags & (SHADER_CULL_FRONT | SHADER_CULL_BACK); - if (shaderstate.curcull & SHADER_CULL_FRONT) - IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CCW); - else if (shaderstate.curcull & SHADER_CULL_BACK) - IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_CW); - else - IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CULLMODE, D3DCULL_NONE); - } + BE_Cull(shaderstate.curshader->flags & (SHADER_CULL_FRONT | SHADER_CULL_BACK)); for (mno = 0, vertcount = 0, idxcount = 0; mno < shaderstate.nummeshes; mno++) { @@ -1452,18 +1491,36 @@ static void BE_DrawMeshChain_Internal(void) } d3dcheck(IDirect3DIndexBuffer9_Unlock(shaderstate.dynidx_buff)); d3dcheck(IDirect3DDevice9_SetIndices(pD3DDev9, shaderstate.dynidx_buff)); - - /*now go through and flush each pass*/ - for (passno = 0; passno < shaderstate.curshader->numpasses; passno += pass->numMergedPasses) + + if (shaderstate.mode == BEM_DEPTHONLY) { - if (!BE_DrawMeshChain_SetupPass(pass+passno, vertcount)) - continue; -#ifdef BENCH - shaderstate.bench.draws++; - if (shaderstate.bench.clamp && shaderstate.bench.clamp < shaderstate.bench.draws) - continue; -#endif + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_COLORWRITEENABLE, 0); + /*deactivate any extras*/ + for (passno = 0; passno < shaderstate.lastpasscount; ) + { + d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, 5+passno, NULL, 0, 0)); + BindTexture(passno, NULL); + d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, passno, D3DTSS_COLOROP, D3DTOP_DISABLE)); + passno++; + } + shaderstate.lastpasscount = 0; d3dcheck(IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, 0, vertcount, idxfirst, idxcount/3)); + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_ALPHA); + } + else + { + /*now go through and flush each pass*/ + for (passno = 0; passno < shaderstate.curshader->numpasses; passno += pass->numMergedPasses) + { + if (!BE_DrawMeshChain_SetupPass(pass+passno, vertcount)) + continue; + #ifdef BENCH + shaderstate.bench.draws++; + if (shaderstate.bench.clamp && shaderstate.bench.clamp < shaderstate.bench.draws) + continue; + #endif + d3dcheck(IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, 0, 0, vertcount, idxfirst, idxcount/3)); + } } } @@ -1712,6 +1769,8 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) float mv[16]; float m[16]; + shaderstate.curentity = e; + m[0] = e->axis[0][0]; m[1] = e->axis[0][1]; m[2] = e->axis[0][2]; @@ -1808,7 +1867,7 @@ static void BE_RotateForEntity (const entity_t *e, const model_t *mod) } } -static void BE_SubmitBatch(batch_t *batch) +void BE_SubmitBatch(batch_t *batch) { shaderstate.nummeshes = batch->meshes - batch->firstmesh; if (!shaderstate.nummeshes) @@ -1818,8 +1877,8 @@ static void BE_SubmitBatch(batch_t *batch) return; if (shaderstate.curentity != batch->ent) { - shaderstate.curentity = batch->ent; BE_RotateForEntity(batch->ent, batch->ent->model); + shaderstate.curtime = r_refdef.time - shaderstate.curentity->shaderTime; } shaderstate.meshlist = batch->mesh + batch->firstmesh; shaderstate.curshader = batch->shader; @@ -1845,6 +1904,7 @@ void BE_DrawMesh_List(shader_t *shader, int nummeshes, mesh_t **meshlist, vbo_t void BE_DrawMesh_Single(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums) { + shaderstate.curtime = realtime; shaderstate.curshader = shader; shaderstate.curtexnums = texnums?texnums:&shader->defaulttextures; shaderstate.curlightmap = r_nulltex; @@ -2073,8 +2133,8 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist) if (batch->shader->flags & SHADER_SKY) { -// if (shaderstate.mode == BEM_STANDARD) -// R_DrawSkyChain (batch); + if (shaderstate.mode == BEM_STANDARD) + R_DrawSkyChain (batch); continue; } @@ -2082,6 +2142,298 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist) } } + +/*generates a new modelview matrix, as well as vpn vectors*/ +static void R_MirrorMatrix(plane_t *plane) +{ + float mirror[16]; + float view[16]; + float result[16]; + + vec3_t pnorm; + VectorNegate(plane->normal, pnorm); + + mirror[0] = 1-2*pnorm[0]*pnorm[0]; + mirror[1] = -2*pnorm[0]*pnorm[1]; + mirror[2] = -2*pnorm[0]*pnorm[2]; + mirror[3] = 0; + + mirror[4] = -2*pnorm[1]*pnorm[0]; + mirror[5] = 1-2*pnorm[1]*pnorm[1]; + mirror[6] = -2*pnorm[1]*pnorm[2] ; + mirror[7] = 0; + + mirror[8] = -2*pnorm[2]*pnorm[0]; + mirror[9] = -2*pnorm[2]*pnorm[1]; + mirror[10] = 1-2*pnorm[2]*pnorm[2]; + mirror[11] = 0; + + mirror[12] = -2*pnorm[0]*plane->dist; + mirror[13] = -2*pnorm[1]*plane->dist; + mirror[14] = -2*pnorm[2]*plane->dist; + mirror[15] = 1; + + view[0] = vpn[0]; + view[1] = vpn[1]; + view[2] = vpn[2]; + view[3] = 0; + + view[4] = -vright[0]; + view[5] = -vright[1]; + view[6] = -vright[2]; + view[7] = 0; + + view[8] = vup[0]; + view[9] = vup[1]; + view[10] = vup[2]; + view[11] = 0; + + view[12] = r_refdef.vieworg[0]; + view[13] = r_refdef.vieworg[1]; + view[14] = r_refdef.vieworg[2]; + view[15] = 1; + + VectorMA(r_refdef.vieworg, 0.25, plane->normal, r_refdef.pvsorigin); + + Matrix4_Multiply(mirror, view, result); + + vpn[0] = result[0]; + vpn[1] = result[1]; + vpn[2] = result[2]; + + vright[0] = -result[4]; + vright[1] = -result[5]; + vright[2] = -result[6]; + + vup[0] = result[8]; + vup[1] = result[9]; + vup[2] = result[10]; + + r_refdef.vieworg[0] = result[12]; + r_refdef.vieworg[1] = result[13]; + r_refdef.vieworg[2] = result[14]; +} +static entity_t *R_NearestPortal(plane_t *plane) +{ + int i; + entity_t *best = NULL; + float dist, bestd = 0; + for (i = 0; i < cl_numvisedicts; i++) + { + if (cl_visedicts[i].rtype == RT_PORTALSURFACE) + { + dist = DotProduct(cl_visedicts[i].origin, plane->normal)-plane->dist; + dist = fabs(dist); + if (dist < 64 && (!best || dist < bestd)) + best = &cl_visedicts[i]; + } + } + return best; +} + +static void TransformCoord(vec3_t in, vec3_t planea[3], vec3_t planeo, vec3_t viewa[3], vec3_t viewo, vec3_t result) +{ + int i; + vec3_t local; + vec3_t transformed; + float d; + + local[0] = in[0] - planeo[0]; + local[1] = in[1] - planeo[1]; + local[2] = in[2] - planeo[2]; + + VectorClear(transformed); + for ( i = 0 ; i < 3 ; i++ ) + { + d = DotProduct(local, planea[i]); + VectorMA(transformed, d, viewa[i], transformed); + } + + result[0] = transformed[0] + viewo[0]; + result[1] = transformed[1] + viewo[1]; + result[2] = transformed[2] + viewo[2]; +} +static void TransformDir(vec3_t in, vec3_t planea[3], vec3_t viewa[3], vec3_t result) +{ + int i; + float d; + vec3_t tmp; + + VectorCopy(in, tmp); + + VectorClear(result); + for ( i = 0 ; i < 3 ; i++ ) + { + d = DotProduct(tmp, planea[i]); + VectorMA(result, d, viewa[i], result); + } +} +static R_RenderScene(void) +{ + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)r_refdef.m_projection); + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view); + R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); + Surf_DrawWorld(); +} + +static void R_DrawPortal(batch_t *batch, batch_t **blist) +{ + entity_t *view; + float glplane[4]; + plane_t plane; + refdef_t oldrefdef; + mesh_t *mesh = batch->mesh[batch->firstmesh]; + int sort; + + if (r_refdef.recurse) + return; + + VectorCopy(mesh->normals_array[0], plane.normal); + plane.dist = DotProduct(mesh->xyz_array[0], plane.normal); + + //if we're too far away from the surface, don't draw anything + if (batch->shader->flags & SHADER_AGEN_PORTAL) + { + /*there's a portal alpha blend on that surface, that fades out after this distance*/ + if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist > batch->shader->portaldist) + return; + } + //if we're behind it, then also don't draw anything. + if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < 0) + return; + + view = R_NearestPortal(&plane); + //if (!view) + // return; + + oldrefdef = r_refdef; + r_refdef.recurse = true; + + r_refdef.externalview = true; + + if (!view || VectorCompare(view->origin, view->oldorigin)) + { + r_refdef.flipcull ^= true; + R_MirrorMatrix(&plane); + } + else + { + float d; + vec3_t paxis[3], porigin, vaxis[3], vorg; + void PerpendicularVector( vec3_t dst, const vec3_t src ); + + /*calculate where the surface is meant to be*/ + VectorCopy(mesh->normals_array[0], paxis[0]); + PerpendicularVector(paxis[1], paxis[0]); + CrossProduct(paxis[0], paxis[1], paxis[2]); + d = DotProduct(view->origin, plane.normal) - plane.dist; + VectorMA(view->origin, -d, paxis[0], porigin); + + /*grab the camera origin*/ + VectorNegate(view->axis[0], vaxis[0]); + VectorNegate(view->axis[1], vaxis[1]); + VectorCopy(view->axis[2], vaxis[2]); + VectorCopy(view->oldorigin, vorg); + + VectorCopy(vorg, r_refdef.pvsorigin); + + /*rotate it a bit*/ + RotatePointAroundVector(vaxis[1], vaxis[0], view->axis[1], sin(realtime)*4); + CrossProduct(vaxis[0], vaxis[1], vaxis[2]); + + TransformCoord(oldrefdef.vieworg, paxis, porigin, vaxis, vorg, r_refdef.vieworg); + TransformDir(vpn, paxis, vaxis, vpn); + TransformDir(vright, paxis, vaxis, vright); + TransformDir(vup, paxis, vaxis, vup); + } + Matrix4_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); + VectorAngles(vpn, vup, r_refdef.viewangles); + VectorCopy(r_refdef.vieworg, r_origin); + +/*FIXME: the batch stuff should be done in renderscene*/ + + /*fixup the first mesh index*/ + for (sort = 0; sort < SHADER_SORT_COUNT; sort++) + for (batch = blist[sort]; batch; batch = batch->next) + { + batch->firstmesh = batch->meshes; + } + + /*FIXME: can we get away with stenciling the screen?*/ + /*Add to frustum culling instead of clip planes?*/ + glplane[0] = plane.normal[0]; + glplane[1] = plane.normal[1]; + glplane[2] = plane.normal[2]; + glplane[3] = -plane.dist; + IDirect3DDevice9_SetClipPlane(pD3DDev9, 0, glplane); + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0); + R_RenderScene(); + IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_CLIPPLANEENABLE, 0); + + for (sort = 0; sort < SHADER_SORT_COUNT; sort++) + for (batch = blist[sort]; batch; batch = batch->next) + { + batch->firstmesh = 0; + } + r_refdef = oldrefdef; + + /*broken stuff*/ + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (r_refdef.vieworg, r_origin); + + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)r_refdef.m_projection); + IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view); + R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); +} + +static void BE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist) +{ + batch_t *batch, *old; + int i; + /*attempt to draw portal shaders*/ + if (shaderstate.mode == BEM_STANDARD) + { + for (i = 0; i < 2; i++) + { + for (batch = i?dynamiclist:worldlist[SHADER_SORT_PORTAL]; batch; batch = batch->next) + { + if (batch->meshes == batch->firstmesh) + continue; + + if (batch->buildmeshes) + batch->buildmeshes(batch); + else + batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; + + + /*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/ + BE_SelectMode(BEM_DEPTHONLY, 0); + for (old = worldlist[SHADER_SORT_PORTAL]; old && old != batch; old = old->next) + { + if (old->meshes == old->firstmesh) + continue; + BE_SubmitBatch(old); + } + if (!old) + { + for (old = dynamiclist; old != batch; old = old->next) + { + if (old->meshes == old->firstmesh) + continue; + BE_SubmitBatch(old); + } + } + BE_SelectMode(BEM_STANDARD, 0); + + R_DrawPortal(batch, worldlist); + + /*clear depth again*/ + IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0); + } + } + } +} + void BE_SubmitMeshes (qboolean drawworld, batch_t **blist) { model_t *model = cl.worldmodel; @@ -2091,8 +2443,8 @@ void BE_SubmitMeshes (qboolean drawworld, batch_t **blist) { if (drawworld) { -// if (i == SHADER_SORT_PORTAL && !r_noportals.ival && !r_refdef.recurse) -// BE_SubmitMeshesPortals(model->batches, blist[i]); + if (i == SHADER_SORT_PORTAL /*&& !r_noportals.ival*/ && !r_refdef.recurse) + BE_SubmitMeshesPortals(model->batches, blist[i]); BE_SubmitMeshesSortList(model->batches[i]); } @@ -2105,6 +2457,8 @@ void BE_DrawWorld (qbyte *vis) batch_t *batches[SHADER_SORT_COUNT]; RSpeedLocals(); + shaderstate.curentity = NULL; + if (!r_refdef.recurse) { if (shaderstate.wbatch > shaderstate.maxwbatches) @@ -2119,8 +2473,6 @@ void BE_DrawWorld (qbyte *vis) BE_GenModelBatches(batches); - shaderstate.curtime = realtime; - if (vis) { BE_UploadLightmaps(false); diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index 752bbbed1..9e35d590d 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -198,7 +198,7 @@ static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_32(d3dtexture_t *tex, unsigned in return (LPDIRECT3DBASETEXTURE9)newsurf; } -static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned char *data, int width, int height, int flags, enum uploadfmt fmt) +static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned char *data, unsigned int *pal32, int width, int height, int flags, enum uploadfmt fmt) { static unsigned trans[1024*1024]; int i, s; @@ -218,11 +218,11 @@ static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned cha p = data[i]; noalpha = true; if (p > 255-vid.fullbright) - trans[i] = d_8to24rgbtable[p]; + trans[i] = pal32[p]; else { noalpha = false; - trans[i] = d_8to24rgbtable[p] & 0x00ffffff; + trans[i] = pal32[p] & 0x00ffffff; } } } @@ -238,7 +238,7 @@ static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned cha trans[i] = 0; } else - trans[i] = d_8to24rgbtable[p]; + trans[i] = pal32[p]; } switch(fmt) @@ -291,14 +291,14 @@ static LPDIRECT3DBASETEXTURE9 D3D9_LoadTexture_8(d3dtexture_t *tex, unsigned cha { for (i=(s&~3)-4 ; i>=0 ; i-=4) { - trans[i] = d_8to24rgbtable[data[i]]; - trans[i+1] = d_8to24rgbtable[data[i+1]]; - trans[i+2] = d_8to24rgbtable[data[i+2]]; - trans[i+3] = d_8to24rgbtable[data[i+3]]; + trans[i] = pal32[data[i]]; + trans[i+1] = pal32[data[i+1]]; + trans[i+2] = pal32[data[i+2]]; + trans[i+3] = pal32[data[i+3]]; } for (i=s&~3 ; itex.ptr = D3D9_LoadTexture_8(tex, data, (unsigned int *)palette32, width, height, flags, TF_SOLID8); + return tex->tex; } texid_t D3D9_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags) { - return r_nulltex; + unsigned int pal32[256]; + int i; + for (i = 0; i < 256; i++) + { + pal32[i] = 0x00000000 | + (palette24[i*3+2]<<24) | + (palette24[i*3+1]<<8) | + (palette24[i*3+0]<<0); + } + return D3D9_LoadTexture8Pal32(identifier, width, height, data, pal32, flags); } #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index d44cd2953..d8b9bd28e 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1122,17 +1122,24 @@ static void D3D9_SetupViewPort(void) screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; - Matrix4_Projection_Inf(r_refdef.m_projection, fov_x, fov_y, gl_mindist.value); + /*view matrix*/ Matrix4_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); + d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view)); - IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)r_refdef.m_projection); - IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view); + /*d3d projection matricies scale depth to 0 to 1*/ + Matrix4_Projection_Inf(r_refdef.m_projection, fov_x, fov_y, gl_mindist.value/2); + d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_PROJECTION, (D3DMATRIX*)r_refdef.m_projection)); + /*ogl projection matricies scale depth to -1 to 1, and I would rather my code used consistant culling*/ + Matrix4_Projection_Inf(r_refdef.m_projection, fov_x, fov_y, gl_mindist.value); } static void (D3D9_R_RenderView) (void) { D3D9_SetupViewPort(); - d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0)); + if (r_clear.ival && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) + d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0)); + else + d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0)); R_SetFrustum (r_refdef.m_projection, r_refdef.m_view); RQ_BeginFrame(); Surf_DrawWorld(); diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a011852f7..bd9c21e87 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -327,7 +327,7 @@ extern cvar_t r_glsl_offsetmapping, r_noportals; #endif static void BE_SendPassBlendAndDepth(unsigned int sbits); -static void BE_SubmitBatch(batch_t *batch); +void BE_SubmitBatch(batch_t *batch); struct { //internal state @@ -2641,7 +2641,7 @@ void BE_DrawPolys(qboolean decalsset) BE_DrawMesh_Single(cl_stris[i].shader, &m, NULL, &cl_stris[i].shader->defaulttextures); } } -static void BE_SubmitBatch(batch_t *batch) +void BE_SubmitBatch(batch_t *batch) { model_t *model = cl.worldmodel; int lm; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 56d3a9e15..4951b972a 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -74,7 +74,6 @@ cvar_t r_norefresh = SCVAR("r_norefresh","0"); extern cvar_t gl_part_flame; extern cvar_t r_bloom; -cvar_t gl_clear = SCVAR("gl_clear","0"); cvar_t gl_affinemodels = SCVAR("gl_affinemodels","0"); cvar_t gl_playermip = SCVAR("gl_playermip","0"); cvar_t gl_reporttjunctions = SCVAR("gl_reporttjunctions","0"); @@ -1404,7 +1403,7 @@ void R_Clear (void) /*tbh, this entire function should be in the backend*/ GL_ForceDepthWritable(); { - if (gl_clear.value && !r_secondaryview && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) + if (r_clear.ival && !r_secondaryview && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else qglClear (GL_DEPTH_BUFFER_BIT); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 434fb6d56..873296de1 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -1122,6 +1122,7 @@ static void Shaderpass_ClampMap (shader_t *shader, shaderpass_t *pass, char **pt pass->tcgen = TC_GEN_BASE; pass->anim_frames[0] = Shader_FindImage (token, flags | IF_CLAMP); pass->texgen = T_GEN_SINGLEMAP; + pass->flags |= SHADER_PASS_CLAMP; if (!TEXVALID(pass->anim_frames[0])) { diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 6da83e2d2..cd28d5ed1 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -458,6 +458,9 @@ static void GL_SkyForceDepth(batch_t *batch) static void GL_DrawSkySphere (batch_t *batch, shader_t *shader) { + static entity_t skyent; + batch_t b; + mesh_t *m; float time = cl.gametime+realtime-cl.gametimemark; float skydist = gl_maxdist.value; @@ -465,18 +468,28 @@ static void GL_DrawSkySphere (batch_t *batch, shader_t *shader) skydist=gl_skyboxdist.value; skydist/=16; - #ifdef GLQUAKE - BE_SelectEntity(&r_worldentity); - //scale sky sphere and place around view origin. - qglPushMatrix(); - qglTranslatef(r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2]); - qglScalef(skydist, skydist, skydist); + VectorCopy(r_refdef.vieworg, skyent.origin); + skyent.axis[0][0] = skydist; + skyent.axis[0][1] = 0; + skyent.axis[0][3] = 0; + skyent.axis[1][0] = 0; + skyent.axis[1][1] = skydist; + skyent.axis[1][2] = 0; + skyent.axis[2][0] = 0; + skyent.axis[2][1] = 0; + skyent.axis[2][2] = skydist; + skyent.scale = 1; //FIXME: We should use the skybox clipping code and split the sphere into 6 sides. gl_skyspherecalc(2); - BE_DrawMesh_Single(shader, &skymesh, NULL, &batch->shader->defaulttextures); - qglPopMatrix(); - #endif + b = *batch; + b.meshes = 1; + b.firstmesh = 0; + m = &skymesh; + b.mesh = &m; + b.ent = &skyent; + b.shader = shader; + BE_SubmitBatch(&b); } diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 6fb395597..cc5b38f9a 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -291,14 +291,6 @@ void FTE_DEPRECATED R_BackendInit(void); void FTE_DEPRECATED R_IBrokeTheArrays(void); #endif - - -// -// gl_warp.c -// -void R_DrawSkyChain (batch_t *batch); /*called from the backend, and calls back into it*/ -texnums_t R_InitSky (texture_t *mt, qbyte *src); /*generate q1 sky texnums*/ - // // gl_draw.c // diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 96c666cdb..4bbf529d8 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -211,6 +211,7 @@ typedef struct shaderpass_s { enum { SHADER_PASS_NOMIPMAP = 1<<1, + SHADER_PASS_CLAMP = 1<<2, SHADER_PASS_NOCOLORARRAY = 1<< 3, //FIXME: remove these @@ -402,6 +403,7 @@ void BE_SelectMode(backendmode_t mode, unsigned int flags); Rules for using a list: Every mesh must be part of the same VBO, shader, lightmap, and must have the same pointers set*/ void BE_DrawMesh_List(shader_t *shader, int nummeshes, mesh_t **mesh, vbo_t *vbo, texnums_t *texnums); void BE_DrawMesh_Single(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums); +void BE_SubmitBatch(batch_t *batch); batch_t *BE_GetTempBatch(void); //Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required