fteqw/engine/d3d/d3d_backend.c
Spoike e6d1ae1a8f more cleanups: csqc now shares collision code with ssqc. Still lacks physics.
gl_rsurf.c has been split into gl specific and generic code - the d3d renderer can now draw the world.
ifdef removed the old server-side mvd playback which had been disabled all this time anyway.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3426 fc73d0e0-1445-4013-8a0c-d673dee63da5
2009-11-07 13:29:15 +00:00

412 lines
11 KiB
C

#include "quakedef.h"
#ifdef D3DQUAKE
#include "shader.h"
#include <d3d9.h>
extern LPDIRECT3DDEVICE9 pD3DDev9;
typedef struct
{
shader_t *curshader;
texnums_t *curtexnums;
texid_t curlightmap;
texid_t curdeluxmap;
} d3dbackend_t;
static d3dbackend_t d3dbackend;
extern int be_maxpasses;
void BE_Init(void)
{
be_maxpasses = 1;
}
static void D3DBE_ApplyShaderBits(unsigned int bits)
{
if (bits & SBITS_BLEND_BITS)
{
int src;
int dst;
switch(bits & SBITS_SRCBLEND_BITS)
{
case SBITS_SRCBLEND_ZERO: src = D3DBLEND_ZERO; break;
case SBITS_SRCBLEND_ONE: src = D3DBLEND_ONE; break;
case SBITS_SRCBLEND_DST_COLOR: src = D3DBLEND_DESTCOLOR; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_COLOR: src = D3DBLEND_INVDESTCOLOR; break;
case SBITS_SRCBLEND_SRC_ALPHA: src = D3DBLEND_SRCALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_SRC_ALPHA: src = D3DBLEND_INVSRCALPHA; break;
case SBITS_SRCBLEND_DST_ALPHA: src = D3DBLEND_DESTALPHA; break;
case SBITS_SRCBLEND_ONE_MINUS_DST_ALPHA: src = D3DBLEND_INVDESTALPHA; break;
case SBITS_SRCBLEND_ALPHA_SATURATE: src = D3DBLEND_SRCALPHASAT; break;
default: Sys_Error("Bad shader blend src\n"); return;
}
switch(bits & SBITS_DSTBLEND_BITS)
{
case SBITS_DSTBLEND_ZERO: dst = D3DBLEND_ZERO; break;
case SBITS_DSTBLEND_ONE: dst = D3DBLEND_ONE; break;
case SBITS_DSTBLEND_SRC_ALPHA: dst = D3DBLEND_SRCALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dst = D3DBLEND_INVSRCALPHA; break;
case SBITS_DSTBLEND_DST_ALPHA: dst = D3DBLEND_DESTALPHA; break;
case SBITS_DSTBLEND_ONE_MINUS_DST_ALPHA: dst = D3DBLEND_INVDESTALPHA; break;
case SBITS_DSTBLEND_SRC_COLOR: dst = D3DBLEND_SRCCOLOR; break;
case SBITS_DSTBLEND_ONE_MINUS_SRC_COLOR: dst = D3DBLEND_INVSRCCOLOR; break;
default: Sys_Error("Bad shader blend dst\n"); return;
}
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHABLENDENABLE, TRUE);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRCBLEND, src);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_DESTBLEND, dst);
}
else
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHABLENDENABLE, FALSE);
switch(bits & SBITS_ATEST_BITS)
{
case SBITS_ATEST_NONE:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, FALSE);
// IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 0);
// IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, 0);
break;
case SBITS_ATEST_GT0:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 0);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_GREATER);
break;
case SBITS_ATEST_LT128:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 128);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_LESS);
break;
case SBITS_ATEST_GE128:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHATESTENABLE, TRUE);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAREF, 128);
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
break;
}
if(bits & SBITS_MISC_DEPTHWRITE)
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZWRITEENABLE, TRUE);
else
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZWRITEENABLE, FALSE);
if(bits & SBITS_MISC_NODEPTHTEST)
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZENABLE, FALSE);
else
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZENABLE, TRUE);
switch(bits & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY))
{
default:
case 0:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
break;
case SBITS_MISC_DEPTHEQUALONLY:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_EQUAL);
break;
case SBITS_MISC_DEPTHCLOSERONLY:
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_ZFUNC, D3DCMP_LESS);
break;
}
}
unsigned int workingbuffer[65536];
static void BE_DrawMeshChain_Internal(mesh_t *meshchain)
{
float *xyz;
unsigned int *colour;
float *st[1];
unsigned int fmt = 0;
unsigned int stride;
int i;
if (!d3dbackend.curshader)
return;
if (!d3dbackend.curtexnums)
return;
stride = 0;
memset(workingbuffer, 0, sizeof(workingbuffer));
xyz = (float*)(workingbuffer+stride);
stride += 3;
fmt |= D3DFVF_XYZ;
colour = (unsigned int*)(workingbuffer+stride);
stride += 1;
fmt |= D3DFVF_DIFFUSE;
st[0] = (float*)(workingbuffer+stride);
stride += 2;
fmt |= D3DFVF_TEX1;
D3DBE_ApplyShaderBits(d3dbackend.curshader->passes[0].shaderbits);
IDirect3DDevice9_SetFVF(pD3DDev9, fmt);
switch(d3dbackend.curshader->passes[0].texgen)
{
default:
case T_GEN_DIFFUSE:
IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curtexnums->base.ptr);
break;
case T_GEN_SINGLEMAP:
IDirect3DDevice9_SetTexture (pD3DDev9, 0, d3dbackend.curshader->passes[0].anim_frames[0].ptr);
break;
}
switch(d3dbackend.curshader->passes[1].texgen)
{
case T_GEN_LIGHTMAP:
IDirect3DDevice9_SetTexture (pD3DDev9, 1, d3dbackend.curlightmap.ptr);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLORARG2, D3DTA_CURRENT);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
break;
default:
IDirect3DDevice9_SetTexture (pD3DDev9, 1, NULL);
IDirect3DDevice9_SetTextureStageState(pD3DDev9, 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
break;
}
if (meshchain->colors4b_array)
{
/*I'm guessing I ought to create a temp vertex buffer for this*/
for (; meshchain; meshchain = meshchain->next)
{
for (i = 0; i < meshchain->numvertexes; i++)
{
VectorCopy(meshchain->xyz_array[i], (xyz+stride*i));
*(colour+stride*i) = ((unsigned int)meshchain->colors4b_array[i][3]<<24) | ((unsigned int)meshchain->colors4b_array[i][0]<<16) | ((unsigned int)meshchain->colors4b_array[i][1]<<8) | ((unsigned int)meshchain->colors4b_array[i][2]);
Vector2Copy(meshchain->st_array[i], (st[0]+stride*i));
}
IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4);
}
}
else
{
/*I'm guessing I ought to create a temp vertex buffer for this*/
for (; meshchain; meshchain = meshchain->next)
{
for (i = 0; i < meshchain->numvertexes; i++)
{
VectorCopy(meshchain->xyz_array[i], (xyz+stride*i));
*(colour+stride*i) = 0xffffffff;//*(unsigned int*)meshchain->colors4b_array[i];
Vector2Copy(meshchain->st_array[i], (st[0]+stride*i));
}
IDirect3DDevice9_DrawIndexedPrimitiveUP(pD3DDev9, D3DPT_TRIANGLELIST, 0, meshchain->numvertexes, meshchain->numindexes/3, meshchain->indexes, D3DFMT_QINDEX, workingbuffer, stride*4);
}
}
}
void BE_DrawMeshChain(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, texnums_t *texnums)
{
d3dbackend.curshader = shader;
d3dbackend.curtexnums = texnums;
BE_DrawMeshChain_Internal(meshchain);
}
void BE_SelectMode(backendmode_t mode, unsigned int flags)
{
}
/*Generates an optimised vbo for each of the given model's textures*/
void BE_GenBrushModelVBO(model_t *mod)
{
}
/*Wipes a vbo*/
void BE_ClearVBO(vbo_t *vbo)
{
}
/*upload all lightmaps at the start to reduce lags*/
void BE_UploadAllLightmaps(void)
{
}
static void DrawSurfaceChain(msurface_t *s, shader_t *shader, vbo_t *vbo)
{ //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying.
int i;
mesh_t *ml, *m;
if (!vbo)
return;
d3dbackend.curshader = shader;
d3dbackend.curtexnums = &shader->defaulttextures;
ml = NULL;
for (; s ; s=s->texturechain)
{
m = s->mesh;
if (!m) //urm.
continue;
if (m->numvertexes <= 1)
continue;
if (s->lightmaptexturenum < 0)
{
//pull out the surfaces with no lightmap info
m->next = ml;
ml = m;
}
else
{
//surfaces that do have a lightmap
m->next = lightmap[s->lightmaptexturenum]->meshchain;
lightmap[s->lightmaptexturenum]->meshchain = m;
}
}
if (ml)
{
//draw the lightmapless surfaces
BE_DrawMeshChain_Internal(ml);
}
//and then draw the lit chains
for (i = 0; i < numlightmaps; i++)
{
if (!lightmap[i] || !lightmap[i]->meshchain)
continue;
/*
if (lightmap[i]->modified)
{
glRect_t *theRect;
lightmap[i]->modified = false;
theRect = &lightmap[i]->rectchange;
GL_Bind(lightmap_textures[i]);
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
lightmap[i]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
theRect->l = LMBLOCK_WIDTH;
theRect->t = LMBLOCK_HEIGHT;
theRect->h = 0;
theRect->w = 0;
checkerror();
if (lightmap[i]->deluxmodified)
{
lightmap[i]->deluxmodified = false;
theRect = &lightmap[i]->deluxrectchange;
GL_Bind(deluxmap_textures[i]);
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
lightmap[i]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
theRect->l = LMBLOCK_WIDTH;
theRect->t = LMBLOCK_HEIGHT;
theRect->h = 0;
theRect->w = 0;
checkerror();
}
}
*/
d3dbackend.curlightmap = lightmap_textures[i];
d3dbackend.curdeluxmap = deluxmap_textures[i];
BE_DrawMeshChain_Internal(lightmap[i]->meshchain);
lightmap[i]->meshchain = NULL;
}
}
static void BE_BaseTextureChain(msurface_t *first)
{
texture_t *t, *tex;
shader_t *shader;
t = first->texinfo->texture;
tex = R_TextureAnimation (t);
//TEMP: use shader as an input parameter, not tex.
shader = tex->shader;
if (!shader)
{
shader = R_RegisterShader_Lightmap(tex->name);
tex->shader = shader;
}
DrawSurfaceChain(first, shader, &t->vbo);
}
void BE_BaseEntTextures(void)
{
extern model_t *currentmodel;
int i;
entity_t *ent;
if (!r_drawentities.ival)
return;
// draw sprites seperately, because of alpha blending
for (i=0 ; i<cl_numvisedicts ; i++)
{
ent = &cl_visedicts[i];
if (!ent->model)
continue;
if (ent->model->needload)
continue;
// if (!PPL_ShouldDraw())
// continue;
switch(ent->model->type)
{
case mod_brush:
// BaseBrushTextures(ent);
break;
case mod_alias:
R_DrawGAliasModel (ent, BEM_STANDARD);
break;
}
}
}
void BE_SubmitMeshes (void)
{
texture_t *t;
msurface_t *s;
int i;
model_t *model = cl.worldmodel;
unsigned int fl;
for (i=0 ; i<model->numtextures ; i++)
{
t = model->textures[i];
if (!t)
continue;
s = t->texturechain;
if (!s)
continue;
fl = s->texinfo->texture->shader->flags;
BE_BaseTextureChain(s);
}
BE_BaseEntTextures();
}
void BE_DrawWorld (qbyte *vis)
{
RSpeedLocals();
//make sure the world draws correctly
r_worldentity.shaderRGBAf[0] = 1;
r_worldentity.shaderRGBAf[1] = 1;
r_worldentity.shaderRGBAf[2] = 1;
r_worldentity.shaderRGBAf[3] = 1;
r_worldentity.axis[0][0] = 1;
r_worldentity.axis[1][1] = 1;
r_worldentity.axis[2][2] = 1;
BE_SelectMode(BEM_STANDARD, 0);
RSpeedRemark();
BE_SubmitMeshes();
RSpeedEnd(RSPEED_WORLD);
}
#endif