1
0
Fork 0
forked from fte/fteqw
fteqw/engine/sw/sw_backend.c
Spoike 8d09710ed1 lightprepass is functional again. still diffuse lighting only. supports shadowmaps but no other weird light info.
added 'pkg' console command. will still need more tweaking.
r_renderscale < 0 means nearest filtering (may need a vid_restart for that to take effect though).
fteqccgui: added 'make installer' options.
fteqcc: fix framemacro issue that was breaking due to invalid dupes in hipnotic's code
cl_lerp_smooth: by default now enabled for singleplayer as well as just demos. this smooths out platforms etc.
q2 demos: explicitly recognise .dm2 extension, to try to avoid issues.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5024 fc73d0e0-1445-4013-8a0c-d673dee63da5
2016-11-20 20:52:41 +00:00

694 lines
18 KiB
C

#include "quakedef.h"
#ifdef SWQUAKE
#include "sw.h"
#include "shader.h"
#include "glquake.h"
vecV_t vertbuf[65535];
swimage_t sw_nulltex =
{
1, 1, 0, 0, 0, 0
};
static struct
{
int foo;
int numrthreads;
void *threads[4];
backendmode_t mode;
float m_mvp[16];
vec4_t viewplane;
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)
{
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++)
{
VectorCopy(xyz[i], v->vcoord);
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];
}
}
static void SWBE_DrawMesh_Internal(shader_t *shader, mesh_t *mesh, struct vbo_s *vbo, struct texnums_s *texnums, unsigned int be_flags)
{
wqcom_t *com;
if (!texnums)
{
// if (shader->numdefaulttextures)
// texnums = shader->defaulttextures + ;
// else
texnums = shader->defaulttextures;
}
shaderstate.curshader = shader;
if (mesh->istrifan)
{
com = SWRast_BeginCommand(&commandqueue, WTC_TRIFAN, mesh->numvertexes*sizeof(swvert_t) + sizeof(com->trifan) - sizeof(com->trifan.verts));
if (texnums->base)
com->trifan.texture = texnums->base->ptr;
else
com->trifan.texture = &sw_nulltex;
com->trifan.numverts = mesh->numvertexes;
SWBE_TransformVerticies(com->trifan.verts, mesh);
SWRast_EndCommand(&commandqueue, com);
}
else
{
com = SWRast_BeginCommand(&commandqueue, WTC_TRISOUP, (mesh->numvertexes*sizeof(swvert_t)) + sizeof(com->trisoup) - sizeof(com->trisoup.verts) + (sizeof(index_t)*mesh->numindexes));
if (texnums->base)
com->trisoup.texture = texnums->base->ptr;
else
com->trisoup.texture = &sw_nulltex;
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(&commandqueue, 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_Internal(shader, *mesh++, vbo, texnums, be_flags);
}
}
void SWBE_DrawMesh_Single(shader_t *shader, mesh_t *mesh, struct vbo_s *vbo, unsigned int be_flags)
{
SWBE_DrawMesh_Internal(shader, mesh, vbo, NULL, be_flags);
}
void SWBE_SubmitBatch(struct batch_s *batch)
{
int m;
SWBE_SelectEntity(batch->ent);
for (m = 0; m < batch->meshes; m++)
{
SWBE_DrawMesh_Internal(batch->shader, batch->mesh[m], batch->vbo, batch->skin, 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)
continue;
if (batch->flags & BEF_NOSHADOWS)
if (shaderstate.mode == BEM_STENCIL)
continue;
if (batch->buildmeshes)
batch->buildmeshes(batch);
if (batch->shader->flags & SHADER_NODRAW)
continue;
if (batch->shader->flags & SHADER_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
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 (batch_t **worldbatches, batch_t **blist, int start, int stop)
{
int i;
for (i = start; i <= stop; i++)
{
if (worldbatches)
{
// if (i == SHADER_SORT_PORTAL && !r_noportals.ival && !r_refdef.recurse)
// SWBE_SubmitMeshesPortals(worldbatches, blist[i]);
SWBE_SubmitMeshesSortList(worldbatches[i]);
}
SWBE_SubmitMeshesSortList(blist[i]);
}
}
static void SWBE_UpdateUniforms(void)
{
wqcom_t *com;
com = SWRast_BeginCommand(&commandqueue, WTC_UNIFORMS, sizeof(com->uniforms));
memcpy(com->uniforms.u.matrix, shaderstate.m_mvp, sizeof(com->uniforms.u.matrix));
Vector4Copy(shaderstate.viewplane, com->uniforms.u.viewplane);
SWRast_EndCommand(&commandqueue, com);
}
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));
shaderstate.viewplane[0] = -r_refdef.m_view[0*4+2];
shaderstate.viewplane[1] = -r_refdef.m_view[1*4+2];
shaderstate.viewplane[2] = -r_refdef.m_view[2*4+2];
VectorNormalize(shaderstate.viewplane);
VectorScale(shaderstate.viewplane, 1.0/99999, shaderstate.viewplane);
shaderstate.viewplane[3] = DotProduct(vec3_origin, shaderstate.viewplane);// - 0.5;
SWBE_UpdateUniforms();
}
void SWBE_DrawWorld(batch_t **worldbatches)
{
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, NULL, shaderstate.mode);
// R_GenDlightBatches(batches);
shaderstate.curentity = NULL;
SWBE_SelectEntity(&r_worldentity);
SWBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_NEAREST);
SWBE_Set2D();
}
void SWBE_Init(void)
{
memset(&sh_config, 0, sizeof(sh_config));
sh_config.texfmt[PTI_BGRA8] = true;
sh_config.texfmt[PTI_BGRX8] = true;
sh_config.texfmt[PTI_RGBA8] = true;
sh_config.texfmt[PTI_RGBX8] = true;
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];
vec3_t vieworg;
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);
shaderstate.viewplane[0] = vpn[0];//-modelviewmatrix[0];//0*4+2];
shaderstate.viewplane[1] = vpn[1];//-modelviewmatrix[1];//1*4+2];
shaderstate.viewplane[2] = vpn[2];//-modelviewmatrix[2];//2*4+2];
VectorNormalize(shaderstate.viewplane);
VectorScale(shaderstate.viewplane, 1.0/8192, shaderstate.viewplane);
vieworg[0] = modelviewmatrix[3*4+0];
vieworg[1] = modelviewmatrix[3*4+1];
vieworg[2] = modelviewmatrix[3*4+2];
VectorMA(r_refdef.vieworg, 256, shaderstate.viewplane, vieworg);
shaderstate.viewplane[3] = DotProduct(vieworg, shaderstate.viewplane);
SWBE_UpdateUniforms();
}
qboolean SWBE_SelectDLight(struct dlight_s *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode)
{
return false;
}
qboolean SWBE_LightCullModel(vec3_t org, struct model_s *model)
{
return false;
}
void SWBE_RenderToTextureUpdate2d(qboolean destchanged)
{
}
#endif