Add project+unproject csqc builtins, for converting between 2d and 3d space (eg cursor interactions).

This commit is contained in:
Shpoike 2021-03-18 09:06:29 +00:00
parent 43bf160e0c
commit ec2123f042
6 changed files with 436 additions and 30 deletions

View file

@ -466,13 +466,13 @@ GL_SetFrustum -- johnfitz -- written to replace MYgluPerspective
*/ */
#define NEARCLIP 4 #define NEARCLIP 4
float frustum_skew = 0.0; //used by r_stereo float frustum_skew = 0.0; //used by r_stereo
void GL_SetFrustum(float fovx, float fovy) /*void GL_SetFrustum(float fovx, float fovy)
{ {
float xmax, ymax; float xmax, ymax;
xmax = NEARCLIP * tan( fovx * M_PI / 360.0 ); xmax = NEARCLIP * tan( fovx * M_PI / 360.0 );
ymax = NEARCLIP * tan( fovy * M_PI / 360.0 ); ymax = NEARCLIP * tan( fovy * M_PI / 360.0 );
glFrustum(-xmax + frustum_skew, xmax + frustum_skew, -ymax, ymax, NEARCLIP, gl_farclip.value); glFrustum(-xmax + frustum_skew, xmax + frustum_skew, -ymax, ymax, NEARCLIP, gl_farclip.value);
} }*/
/* /*
============= =============
@ -485,7 +485,6 @@ void R_SetupGL (void)
//johnfitz -- rewrote this section //johnfitz -- rewrote this section
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
scale = CLAMP(1, (int)r_scale.value, 4); // ericw -- see R_ScaleView scale = CLAMP(1, (int)r_scale.value, 4); // ericw -- see R_ScaleView
glViewport (glx + r_refdef.vrect.x, glViewport (glx + r_refdef.vrect.x,
gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height, gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height,
@ -493,7 +492,19 @@ void R_SetupGL (void)
r_refdef.vrect.height / scale); r_refdef.vrect.height / scale);
//johnfitz //johnfitz
GL_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars #if 1
{
mat4_t mat;
Matrix4_ProjectionMatrix(r_fovx, r_fovy, NEARCLIP, gl_farclip.value, false, frustum_skew, 0, mat);
glLoadMatrixf(mat);
Matrix4_ViewMatrix(r_refdef.viewangles, r_refdef.vieworg, mat);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(mat);
}
#else
//glLoadIdentity ();
GL_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars
// glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right // glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right
@ -506,6 +517,7 @@ void R_SetupGL (void)
glRotatef (-r_refdef.viewangles[0], 0, 1, 0); glRotatef (-r_refdef.viewangles[0], 0, 1, 0);
glRotatef (-r_refdef.viewangles[1], 0, 0, 1); glRotatef (-r_refdef.viewangles[1], 0, 0, 1);
glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]);
#endif
// //
// set drawing parms // set drawing parms

View file

@ -586,3 +586,288 @@ fixed16_t Invert24To16(fixed16_t val)
(((double)0x10000 * (double)0x1000000 / (double)val) + 0.5); (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5);
} }
/*
===================
Various 4*4 matrix functions.
===================
*/
void Matrix4_Transform4(const mat4_t matrix, const vec4_t vector, vec4_t product)
{
product[0] = matrix[0]*vector[0] + matrix[4]*vector[1] + matrix[8]*vector[2] + matrix[12]*vector[3];
product[1] = matrix[1]*vector[0] + matrix[5]*vector[1] + matrix[9]*vector[2] + matrix[13]*vector[3];
product[2] = matrix[2]*vector[0] + matrix[6]*vector[1] + matrix[10]*vector[2] + matrix[14]*vector[3];
product[3] = matrix[3]*vector[0] + matrix[7]*vector[1] + matrix[11]*vector[2] + matrix[15]*vector[3];
}
void Matrix4_Multiply(const mat4_t a, const mat4_t b, mat4_t out)
{
out[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3];
out[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3];
out[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3];
out[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3];
out[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7];
out[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7];
out[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7];
out[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7];
out[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11];
out[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11];
out[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11];
out[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11];
out[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15];
out[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15];
out[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15];
out[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15];
}
/*
* Compute inverse of 4x4 transformation matrix.
* Code contributed by Jacques Leroy jle@star.be
* Return true for success, false for failure (singular matrix)
* Spike: This comes from mesa's GLU.
*/
qboolean Matrix4_Invert(const float *m, float *out)
{
/* NB. OpenGL Matrices are COLUMN major. */
#define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
#define MAT(m,r,c) (m)[(c)*4+(r)]
float wtmp[4][8];
float m0, m1, m2, m3, s;
float *r0, *r1, *r2, *r3;
r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
/* choose pivot - or die */
if (fabs(r3[0]) > fabs(r2[0]))
SWAP_ROWS(r3, r2)
if (fabs(r2[0]) > fabs(r1[0]))
SWAP_ROWS(r2, r1)
if (fabs(r1[0]) > fabs(r0[0]))
SWAP_ROWS(r1, r0)
if (0.0 == r0[0])
return false;
/* eliminate first variable */
m1 = r1[0] / r0[0];
m2 = r2[0] / r0[0];
m3 = r3[0] / r0[0];
s = r0[1];
r1[1] -= m1 * s;
r2[1] -= m2 * s;
r3[1] -= m3 * s;
s = r0[2];
r1[2] -= m1 * s;
r2[2] -= m2 * s;
r3[2] -= m3 * s;
s = r0[3];
r1[3] -= m1 * s;
r2[3] -= m2 * s;
r3[3] -= m3 * s;
s = r0[4];
if (s != 0.0) {
r1[4] -= m1 * s;
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r0[5];
if (s != 0.0) {
r1[5] -= m1 * s;
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r0[6];
if (s != 0.0) {
r1[6] -= m1 * s;
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r0[7];
if (s != 0.0) {
r1[7] -= m1 * s;
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/* choose pivot - or die */
if (fabs(r3[1]) > fabs(r2[1]))
SWAP_ROWS(r3, r2)
if (fabs(r2[1]) > fabs(r1[1]))
SWAP_ROWS(r2, r1)
if (0.0 == r1[1])
return false;
/* eliminate second variable */
m2 = r2[1] / r1[1];
m3 = r3[1] / r1[1];
r2[2] -= m2 * r1[2];
r3[2] -= m3 * r1[2];
r2[3] -= m2 * r1[3];
r3[3] -= m3 * r1[3];
s = r1[4];
if (0.0 != s) {
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r1[5];
if (0.0 != s) {
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r1[6];
if (0.0 != s) {
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r1[7];
if (0.0 != s) {
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
/* choose pivot - or die */
if (fabs(r3[2]) > fabs(r2[2]))
SWAP_ROWS(r3, r2)
if (0.0 == r2[2])
return false;
/* eliminate third variable */
m3 = r3[2] / r2[2];
r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
/* last check */
if (0.0 == r3[3])
return false;
s = 1.0 / r3[3]; /* now back substitute row 3 */
r3[4] *= s;
r3[5] *= s;
r3[6] *= s;
r3[7] *= s;
m2 = r2[3]; /* now back substitute row 2 */
s = 1.0 / r2[2];
r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
m1 = r1[3];
r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
m0 = r0[3];
r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
m1 = r1[2]; /* now back substitute row 1 */
s = 1.0 / r1[1];
r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
m0 = r0[2];
r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
m0 = r0[1]; /* now back substitute row 0 */
s = 1.0 / r0[0];
r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
MAT(out, 0, 0) = r0[4];
MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
MAT(out, 3, 3) = r3[7];
return true;
#undef MAT
#undef SWAP_ROWS
}
//FIXME: use these instead of all the glRotate etc calls, because why not.
void Matrix4_ViewMatrix(const vec3_t viewangles, const vec3_t vieworg, mat4_t out)
{ //directly compute an opengl view matrix. this is not the same as a model matrix (in part because the values are all negated).
float cp = cos(-viewangles[0] * M_PI / 180.0);
float sp = sin(-viewangles[0] * M_PI / 180.0);
float cy = cos(-viewangles[1] * M_PI / 180.0);
float sy = sin(-viewangles[1] * M_PI / 180.0);
float cr = cos(-viewangles[2] * M_PI / 180.0);
float sr = sin(-viewangles[2] * M_PI / 180.0);
out[0] = sr*sp*cy - cr*sy;
out[1] = -cr*sp*cy + sr*sy;
out[2] = -cp*cy;
out[3] = 0;
out[4] = -cr*cy - sr*sp*sy;
out[5] = sr*cy + cr*sp*sy;
out[6] = cp*sy;
out[7] = 0;
out[8] = -sr*cp;
out[9] = cr*cp;
out[10] = -sp;
out[11] = 0;
out[12] = - out[0]*vieworg[0] - out[4]*vieworg[1] - out[ 8]*vieworg[2];
out[13] = - out[1]*vieworg[0] - out[5]*vieworg[1] - out[ 9]*vieworg[2];
out[14] = - out[2]*vieworg[0] - out[6]*vieworg[1] - out[10]*vieworg[2];
out[15] = 1 - out[3]*vieworg[0] - out[7]*vieworg[1] - out[11]*vieworg[2];
}
//computes an orthographic projection matrix (mostly equivelent to glFrustum)
void Matrix4_ProjectionMatrix(float fovx, float fovy, float neard, float fard, qboolean d3d, float xskew, float yskew, mat4_t out)
{
double xmin, xmax, ymin, ymax;
double dn = (d3d?0:-1), df = 1;
xmax = neard * tan( fovx * M_PI / 360.0 );
xmin = -xmax;
ymax = neard * tan( fovy * M_PI / 360.0 );
ymin = -ymax;
xmax += xskew; //this stuff for r_stereo
xmin += xskew;
ymax += yskew;
ymin += yskew;
out[0] = (2*neard) / (xmax - xmin);
out[4] = 0;
out[8] = (xmax + xmin) / (xmax - xmin);
out[12] = 0;
out[1] = 0;
out[5] = (2*neard) / (ymax - ymin);
out[9] = (ymax + ymin) / (ymax - ymin);
out[13] = 0;
out[2] = 0;
out[6] = 0;
if (fard < neard)
{ //fiddle with the far clip plane to make it rather large
const double epsilon = 1.0/(1<<22);
out[10] = epsilon-1;
out[14] = (epsilon-(df-dn))*neard;
}
else
{
out[10] = (fard*df-neard*dn)/(neard-fard);
out[14] = ((df-dn)*fard*neard)/(neard-fard);
}
out[3] = 0;
out[7] = 0;
out[11] = -1;
out[15] = 0;
}

View file

@ -94,6 +94,12 @@ void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
void Matrix4_Transform4(const mat4_t matrix, const vec4_t vector, vec4_t product);
void Matrix4_Multiply(const mat4_t a, const mat4_t b, mat4_t out);
qboolean Matrix4_Invert(const mat4_t m, mat4_t out);
void Matrix4_ViewMatrix(const vec3_t viewangles, const vec3_t vieworg, mat4_t out);
void Matrix4_ProjectionMatrix(float fovx, float fovy, float neard, float fard, qboolean d3d, float xskew, float yskew, mat4_t out);
void FloorDivMod (double numer, double denom, int *quotient, void FloorDivMod (double numer, double denom, int *quotient,
int *rem); int *rem);
fixed16_t Invert24To16(fixed16_t val); fixed16_t Invert24To16(fixed16_t val);

View file

@ -6207,7 +6207,7 @@ static struct
} viewprops; } viewprops;
void V_CalcRefdef (void); void V_CalcRefdef (void);
static void PF_m_clearscene(void) static void PF_cl_clearscene(void)
{ {
if (cl_numvisedicts + 64 > cl_maxvisedicts) if (cl_numvisedicts + 64 > cl_maxvisedicts)
{ {
@ -6306,7 +6306,7 @@ enum
//VF_DP_MAINVIEW = 400, // defective. should be a viewid instead, allowing for per-view motionblur instead of disabling it outright //VF_DP_MAINVIEW = 400, // defective. should be a viewid instead, allowing for per-view motionblur instead of disabling it outright
//VF_DP_MINFPS_QUALITY = 401, //multiplier for lod and culling to try to reduce costs. //VF_DP_MINFPS_QUALITY = 401, //multiplier for lod and culling to try to reduce costs.
}; };
static void PF_m_getproperty(void) static void PF_cl_getproperty(void)
{ {
float s; float s;
int prop = G_FLOAT(OFS_PARM0); int prop = G_FLOAT(OFS_PARM0);
@ -6452,7 +6452,7 @@ static void PF_m_getproperty(void)
break; break;
} }
} }
static void PF_m_setproperty(void) static void PF_cl_setproperty(void)
{ {
int prop = G_FLOAT(OFS_PARM0); int prop = G_FLOAT(OFS_PARM0);
switch(prop) switch(prop)
@ -6577,7 +6577,7 @@ void R_RenderScene (void);
void SCR_DrawCrosshair (void); void SCR_DrawCrosshair (void);
float CalcFovy (float fov_x, float width, float height); float CalcFovy (float fov_x, float width, float height);
extern cvar_t scr_fov; extern cvar_t scr_fov;
static void PF_m_renderscene(void) static void PF_cl_computerefdef(void)
{ {
float s = PR_GetVMScale(); float s = PR_GetVMScale();
@ -6587,23 +6587,36 @@ static void PF_m_renderscene(void)
r_refdef.vrect.y = viewprops.rect_pos[1]*s; r_refdef.vrect.y = viewprops.rect_pos[1]*s;
r_refdef.vrect.width = viewprops.rect_size[0]*s; r_refdef.vrect.width = viewprops.rect_size[0]*s;
r_refdef.vrect.height = viewprops.rect_size[1]*s; r_refdef.vrect.height = viewprops.rect_size[1]*s;
if (r_refdef.vrect.width < 1 || r_refdef.vrect.height < 1)
return; //can't draw nuffin...
if (!viewprops.afov) if (viewprops.fov_x && viewprops.fov_y)
viewprops.afov = scr_fov.value;
if (r_refdef.vrect.width/r_refdef.vrect.height < 4/3)
{ {
r_refdef.fov_y = viewprops.afov; r_refdef.fov_x = viewprops.fov_x;
r_refdef.fov_x = CalcFovy(r_refdef.fov_y, r_refdef.vrect.height, r_refdef.vrect.width); r_refdef.fov_y = viewprops.fov_y;
} }
else else
{ {
r_refdef.fov_y = tan(viewprops.afov * M_PI / 360.0) * (3.0 / 4.0); if (!viewprops.afov)
r_refdef.fov_x = r_refdef.fov_y * r_refdef.vrect.width / r_refdef.vrect.height; viewprops.afov = scr_fov.value;
r_refdef.fov_x = atan(r_refdef.fov_x) * (360.0 / M_PI); if (r_refdef.vrect.width/r_refdef.vrect.height < 4/3)
r_refdef.fov_y = atan(r_refdef.fov_y) * (360.0 / M_PI); {
r_refdef.fov_y = viewprops.afov;
r_refdef.fov_x = CalcFovy(r_refdef.fov_y, r_refdef.vrect.height, r_refdef.vrect.width);
}
else
{
r_refdef.fov_y = tan(viewprops.afov * M_PI / 360.0) * (3.0 / 4.0);
r_refdef.fov_x = r_refdef.fov_y * r_refdef.vrect.width / r_refdef.vrect.height;
r_refdef.fov_x = atan(r_refdef.fov_x) * (360.0 / M_PI);
r_refdef.fov_y = atan(r_refdef.fov_y) * (360.0 / M_PI);
}
} }
}
static void PF_cl_renderscene(void)
{
PF_cl_computerefdef();
if (r_refdef.vrect.width < 1 || r_refdef.vrect.height < 1)
return; //can't draw nuffin...
R_SetupView (); R_SetupView ();
R_RenderScene (); R_RenderScene ();
if (r_refdef.drawworld) if (r_refdef.drawworld)
@ -6626,6 +6639,94 @@ static void PF_m_renderscene(void)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
} }
static void PF_cl_genProjectMatricies(mat4_t viewproj)
{
mat4_t view;
mat4_t proj;
extern cvar_t gl_farclip;
//note: we ignore r_waterwarp here (we don't really know if we're underwater or not here), and you're unlikely to want such warping for mouse clicks.
Matrix4_ProjectionMatrix(r_refdef.fov_x, r_refdef.fov_y, NEARCLIP, gl_farclip.value, false, 0, 0, proj);
Matrix4_ViewMatrix(r_refdef.viewangles, r_refdef.vieworg, view);
//combine
Matrix4_Multiply(proj, view, viewproj);
}
//vector(vector v) unproject
//Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty.
static void PF_cl_unproject(void)
{
mat4_t viewproj, viewproj_inv;
vec4_t pos, res;
float s = PR_GetVMScale();
VectorCopy(G_VECTOR(OFS_PARM0), pos);
PF_cl_computerefdef(); //determine correct vrect (in pixels), and compute fovxy accordingly. this could be cached...
PF_cl_genProjectMatricies(viewproj);
Matrix4_Invert(viewproj, viewproj_inv);
//convert virtual coords to (pixel) screenspace
pos[0] *= s;
pos[1] *= s;
//convert to viewport (0-1 within vrect)...
pos[0] = (pos[0]-r_refdef.vrect.x)/r_refdef.vrect.width;
pos[1] = (pos[1]-r_refdef.vrect.y)/r_refdef.vrect.height;
pos[1] = 1-pos[1]; //matricies for opengl are bottom-up.
//convert to clipspace (+/- 1)
pos[0] = pos[0]*2-1;
pos[1] = pos[1]*2-1;
pos[2] = pos[2]*2-1; //input_z==0 means near clip plane.
//don't allow 1 here as that causes issues with infinite far clip plane maths, and some DP mods abuse it with depth values much larger than 1.
if (pos[2] >= 1)
pos[2] = 0.999999;
//w coord is 1... yay 4*4 matricies.
pos[3] = 1;
//transform our point...
Matrix4_Transform4(viewproj_inv, pos, res);
//result is then res_xyz/res_w. we don't really care for interpolating texture projection...
VectorScale(res, 1/res[3], G_VECTOR(OFS_RETURN));
}
//vector(vector v) project
//Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty.
static void PF_cl_project(void)
{
mat_t viewproj[16];
vec4_t pos, res;
float s = PR_GetVMScale();
VectorCopy(G_VECTOR(OFS_PARM0), pos);
pos[3] = 1; //w is always 1.
PF_cl_computerefdef(); //determine correct vrect (in pixels), and compute fovxy accordingly. this could be cached...
PF_cl_genProjectMatricies(viewproj);
Matrix4_Transform4(viewproj, pos, res);
VectorScale(res, 1/res[3], res);
if (res[3] < 0)
res[2] *= -1; //oops... keep things behind us behind... this allows it to act as an error condition.
//clipspace to viewport
res[0] = (1+res[0])/2;
res[1] = (1+res[1])/2;
res[1] = 1-res[1]; //matricies for opengl are bottom-up.
//viewport to screenspace (0-1 within vrect)...
res[0] = r_refdef.vrect.x + r_refdef.vrect.width *res[0];
res[1] = r_refdef.vrect.y + r_refdef.vrect.height*res[1];
//screenspace to virtual
res[0] /= s;
res[1] /= s;
VectorCopy(res, G_VECTOR(OFS_RETURN));
}
static void PF_cs_setlistener(void) static void PF_cs_setlistener(void)
{ {
float *origin = G_VECTOR(OFS_PARM0); float *origin = G_VECTOR(OFS_PARM0);
@ -6990,20 +7091,20 @@ static struct
// {"clustertransfer", PF_clustertransfer, PF_NoCSQC, 0, PF_NoMenu, D("string(entity player, optional string newnode)", "Only functions in mapcluster mode. Initiate transfer of the player to a different node. Can take some time. If dest is specified, returns null on error. Otherwise returns the current/new target node (or null if not transferring).")}, // {"clustertransfer", PF_clustertransfer, PF_NoCSQC, 0, PF_NoMenu, D("string(entity player, optional string newnode)", "Only functions in mapcluster mode. Initiate transfer of the player to a different node. Can take some time. If dest is specified, returns null on error. Otherwise returns the current/new target node (or null if not transferring).")},
// {"modelframecount", PF_modelframecount, PF_modelframecount, 0, PF_NoMenu, D("float(float mdlidx)", "Retrieves the number of frames in the specified model.")}, // {"modelframecount", PF_modelframecount, PF_modelframecount, 0, PF_NoMenu, D("float(float mdlidx)", "Retrieves the number of frames in the specified model.")},
{"clearscene", PF_NoSSQC, PF_m_clearscene, 300, PF_m_clearscene,300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC) {"clearscene", PF_NoSSQC, PF_cl_clearscene, 300, PF_cl_clearscene,300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC)
{"addentities", PF_NoSSQC, PF_cs_addentities, 301, PF_NoMenu, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC) {"addentities", PF_NoSSQC, PF_cs_addentities, 301, PF_NoMenu, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC)
{"addentity", PF_NoSSQC, PF_cs_addentity, 302, PF_m_addentity,302, D("void(entity ent)", "Copies the entity fields into a new rentity for later rendering via addscene.")},// (EXT_CSQC) {"addentity", PF_NoSSQC, PF_cs_addentity, 302, PF_m_addentity,302, D("void(entity ent)", "Copies the entity fields into a new rentity for later rendering via addscene.")},// (EXT_CSQC)
// {"removeentity", PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("void(entity ent)", "Undoes all addentities added to the scene from the given entity, without removing ALL entities (useful for splitscreen/etc, readd modified versions as desired).")},// (EXT_CSQC) // {"removeentity", PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("void(entity ent)", "Undoes all addentities added to the scene from the given entity, without removing ALL entities (useful for splitscreen/etc, readd modified versions as desired).")},// (EXT_CSQC)
// {"addtrisoup_simple",PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("typedef float vec2[2];\ntypedef float vec3[3];\ntypedef float vec4[4];\ntypedef struct trisoup_simple_vert_s {vec3 xyz;vec2 st;vec4 rgba;} trisoup_simple_vert_t;\nvoid(string texturename, int flags, struct trisoup_simple_vert_s *verts, int *indexes, int numindexes)", "Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame.")}, // {"addtrisoup_simple",PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("typedef float vec2[2];\ntypedef float vec3[3];\ntypedef float vec4[4];\ntypedef struct trisoup_simple_vert_s {vec3 xyz;vec2 st;vec4 rgba;} trisoup_simple_vert_t;\nvoid(string texturename, int flags, struct trisoup_simple_vert_s *verts, int *indexes, int numindexes)", "Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame.")},
{"setproperty", PF_NoSSQC, PF_m_setproperty, 303, PF_m_setproperty,303, D("#define setviewprop setproperty\nfloat(float property, ...)", "Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats.")},// (EXT_CSQC) {"setproperty", PF_NoSSQC, PF_cl_setproperty, 303, PF_cl_setproperty,303, D("#define setviewprop setproperty\nfloat(float property, ...)", "Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats.")},// (EXT_CSQC)
{"renderscene", PF_NoSSQC, PF_m_renderscene, 304, PF_m_renderscene,304, D("void()", "Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy.\nThe scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame.\nYou may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView.")},// (EXT_CSQC) {"renderscene", PF_NoSSQC, PF_cl_renderscene, 304, PF_cl_renderscene,304, D("void()", "Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy.\nThe scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame.\nYou may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView.")},// (EXT_CSQC)
{"dynamiclight_add",PF_NoSSQC, PF_cs_addlight, 305, PF_NoMenu, D("float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags)", "Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up.")},// (EXT_CSQC) {"dynamiclight_add",PF_NoSSQC, PF_cs_addlight, 305, PF_NoMenu, D("float(vector org, float radius, vector lightcolours, optional float style, optional string cubemapname, optional float pflags)", "Adds a temporary dlight, ready to be drawn via addscene. Cubemap orientation will be read from v_forward/v_right/v_up.")},// (EXT_CSQC)
{"R_BeginPolygon", PF_NoSSQC, PF_R_PolygonBegin, 306, PF_R_PolygonBegin, 306, D("void(string texturename, optional float flags, optional float is2d)", "Specifies the shader to use for the following polygons, along with optional flags.\nIf is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects.")},// (EXT_CSQC_???) {"R_BeginPolygon", PF_NoSSQC, PF_R_PolygonBegin, 306, PF_R_PolygonBegin, 306, D("void(string texturename, optional float flags, optional float is2d)", "Specifies the shader to use for the following polygons, along with optional flags.\nIf is2d, the polygon will be drawn as soon as the EndPolygon call is made, rather than waiting for renderscene. This allows complex 2d effects.")},// (EXT_CSQC_???)
{"R_PolygonVertex", PF_NoSSQC, PF_R_PolygonVertex, 307, PF_R_PolygonVertex, 307, D("void(vector org, vector texcoords, vector rgb, float alpha)", "Specifies a polygon vertex with its various properties.")},// (EXT_CSQC_???) {"R_PolygonVertex", PF_NoSSQC, PF_R_PolygonVertex, 307, PF_R_PolygonVertex, 307, D("void(vector org, vector texcoords, vector rgb, float alpha)", "Specifies a polygon vertex with its various properties.")},// (EXT_CSQC_???)
{"R_EndPolygon", PF_NoSSQC, PF_R_PolygonEnd, 308, PF_R_PolygonEnd, 308, D("void()", "Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader.")}, {"R_EndPolygon", PF_NoSSQC, PF_R_PolygonEnd, 308, PF_R_PolygonEnd, 308, D("void()", "Ends the current polygon. At least 3 verticies must have been specified. You do not need to call beginpolygon if you wish to draw another polygon with the same shader.")},
{"getproperty", PF_NoSSQC, PF_m_getproperty, 309, PF_m_getproperty, 309, D("#define getviewprop getproperty\n__variant(float property)", "Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable.")},// (EXT_CSQC_1) {"getproperty", PF_NoSSQC, PF_cl_getproperty, 309, PF_cl_getproperty, 309, D("#define getviewprop getproperty\n__variant(float property)", "Retrieve a currently-set (typically view) property, allowing you to read the current viewport or other things. Due to cheat protection, certain values may be unretrievable.")},// (EXT_CSQC_1)
// {"unproject", PF_NoSSQC, PF_cl_unproject, 310, PF_NoMenu, D("vector (vector v)", "Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC) {"unproject", PF_NoSSQC, PF_cl_unproject, 310, PF_NoMenu, D("vector (vector v)", "Transform a 2d screen-space point (with depth) into a 3d world-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC)
// {"project", PF_NoSSQC, PF_cl_project, 311, PF_NoMenu, D("vector (vector v)", "Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC) {"project", PF_NoSSQC, PF_cl_project, 311, PF_NoMenu, D("vector (vector v)", "Transform a 3d world-space point into a 2d screen-space point, according the various origin+angle+fov etc settings set via setproperty.")},// (EXT_CSQC)
// {"drawtextfield", PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("void(vector pos, vector size, float alignflags, string text)", "Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3.")},// (EXT_CSQC) // {"drawtextfield", PF_NoSSQC, PF_FullCSQCOnly, 0, PF_NoMenu, D("void(vector pos, vector size, float alignflags, string text)", "Draws a multi-line block of text, including word wrapping and alignment. alignflags bits are RTLB, typically 3.")},// (EXT_CSQC)
// {"drawline", PF_NoSSQC, PF_FullCSQCOnly, 315, PF_NoMenu, D("void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag)", "Draws a 2d line between the two 2d points.")},// (EXT_CSQC) // {"drawline", PF_NoSSQC, PF_FullCSQCOnly, 315, PF_NoMenu, D("void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag)", "Draws a 2d line between the two 2d points.")},// (EXT_CSQC)
{"iscachedpic", PF_NoSSQC, PF_cl_iscachedpic, 316, PF_cl_iscachedpic,451, D("float(string name)", "Checks to see if the image is currently loaded. Engines might lie, or cache between maps.")},// (EXT_CSQC) {"iscachedpic", PF_NoSSQC, PF_cl_iscachedpic, 316, PF_cl_iscachedpic,451, D("float(string name)", "Checks to see if the image is currently loaded. Engines might lie, or cache between maps.")},// (EXT_CSQC)

View file

@ -55,10 +55,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT1_HLBSP 0x00000200 //hint to server to avoid messy error messages #define PEXT1_HLBSP 0x00000200 //hint to server to avoid messy error messages
#define PEXT1_Q2BSP 0x00020000 //hint to server to avoid messy error messages #define PEXT1_Q2BSP 0x00020000 //hint to server to avoid messy error messages
#define PEXT1_Q3BSP 0x00040000 //hint to server to avoid messy error messages #define PEXT1_Q3BSP 0x00040000 //hint to server to avoid messy error messages
//#define PEXT1_CUSTOMTEMPEFFECTS 0x00800000 //#define PEXT1_CUSTOMTEMPEFFECTS 0x00800000 //favour csqc instead.
//#define PEXT1_SPLITSCREEN 0x00100000 //#define PEXT1_SPLITSCREEN 0x00100000 //too much hassle for not enough users.
//#define PEXT1_SHOWPIC 0x04000000 //#define PEXT1_SHOWPIC 0x04000000 //favour csqc instead.
//#define PEXT1_CHUNKEDDOWNLOADS 0x20000000 //#define PEXT1_CHUNKEDDOWNLOADS 0x20000000 //favour DP's download protocol instead. its simpler and better established (though doesn't cope with packetloss so well).
#define PEXT1_CSQC 0x40000000 //(full)csqc additions, required for csqc ents+events. #define PEXT1_CSQC 0x40000000 //(full)csqc additions, required for csqc ents+events.
#define PEXT1_ACCEPTED_CLIENT (PEXT1_SUPPORTED_CLIENT|PEXT1_Q3BSP|PEXT1_Q2BSP|PEXT1_HLBSP) //pext1 flags that we can accept from a server (aka: partial support) #define PEXT1_ACCEPTED_CLIENT (PEXT1_SUPPORTED_CLIENT|PEXT1_Q3BSP|PEXT1_Q2BSP|PEXT1_HLBSP) //pext1 flags that we can accept from a server (aka: partial support)
#define PEXT1_SUPPORTED_CLIENT (PEXT1_CSQC) //pext1 flags that we advertise to servers (aka: full support) #define PEXT1_SUPPORTED_CLIENT (PEXT1_CSQC) //pext1 flags that we advertise to servers (aka: full support)
@ -73,7 +73,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT2_PREDINFO 0x00000020 //provides input acks and reworks stats such that clc_clientdata becomes redundant. #define PEXT2_PREDINFO 0x00000020 //provides input acks and reworks stats such that clc_clientdata becomes redundant.
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding, for more precise bboxes. #define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding, for more precise bboxes.
#define PEXT2_INFOBLOBS 0x00000080 //unbounded userinfo #define PEXT2_INFOBLOBS 0x00000080 //unbounded userinfo
#define PEXT2_ACCEPTED_CLIENT (PEXT2_SUPPORTED_CLIENT|PEXT2_NEWSIZEENCODING|PEXT2_PRYDONCURSOR|PEXT2_INFOBLOBS) //pext2 flags that we can parse, but don't want to advertise #define PEXT2_ACCEPTED_CLIENT (PEXT2_SUPPORTED_CLIENT|PEXT2_NEWSIZEENCODING|PEXT2_PRYDONCURSOR|PEXT2_INFOBLOBS) //pext2 flags that we can parse, but don't want to advertise (for demos)
#define PEXT2_SUPPORTED_CLIENT (PEXT2_SETANGLEDELTA|PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO) //pext2 flags that we understand+support #define PEXT2_SUPPORTED_CLIENT (PEXT2_SETANGLEDELTA|PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO) //pext2 flags that we understand+support
#define PEXT2_SUPPORTED_SERVER ( PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS |PEXT2_PREDINFO) #define PEXT2_SUPPORTED_SERVER ( PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS |PEXT2_PREDINFO)

View file

@ -147,6 +147,8 @@ typedef int fixed4_t;
typedef int fixed8_t; typedef int fixed8_t;
typedef int fixed16_t; typedef int fixed16_t;
typedef vec_t mat_t;
typedef mat_t mat4_t[4*4]; //this is bad form, to have an array typedef, as it will be passed as a pointer.
/*==========================================================================*/ /*==========================================================================*/