2001-05-11 01:01:27 +00:00
|
|
|
/*
|
|
|
|
gl_sky_clip.c
|
|
|
|
|
|
|
|
sky polygons
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-06-19 22:05:13 +00:00
|
|
|
#include <stdlib.h>
|
2001-05-11 01:01:27 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
2011-08-25 13:35:20 +00:00
|
|
|
#if defined(_WIN32) && defined(HAVE_MALLOC_H)
|
2007-03-22 23:20:57 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2001-05-11 01:01:27 +00:00
|
|
|
#include <stdarg.h>
|
2002-03-03 06:03:51 +00:00
|
|
|
#include <stdlib.h>
|
2001-05-11 01:01:27 +00:00
|
|
|
|
2013-01-22 05:09:41 +00:00
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2001-08-22 11:00:25 +00:00
|
|
|
#include "QF/cvar.h"
|
|
|
|
#include "QF/render.h"
|
|
|
|
#include "QF/sys.h"
|
2001-07-22 02:06:02 +00:00
|
|
|
#include "QF/GL/defines.h"
|
|
|
|
#include "QF/GL/funcs.h"
|
|
|
|
#include "QF/GL/qf_sky.h"
|
|
|
|
#include "QF/GL/qf_vid.h"
|
|
|
|
|
2012-02-14 08:28:09 +00:00
|
|
|
#include "r_internal.h"
|
2001-06-24 09:25:55 +00:00
|
|
|
|
2002-03-03 06:03:51 +00:00
|
|
|
#include "compat.h"
|
|
|
|
|
2001-05-11 01:01:27 +00:00
|
|
|
#define BOX_WIDTH 2056
|
|
|
|
|
|
|
|
/* cube face to sky texture offset conversion */
|
2012-09-12 23:36:28 +00:00
|
|
|
// see gl_sky.c for naming: rt bk up lf ft dn
|
|
|
|
static const int skytex_offs[] = { 0, 1, 4, 2, 3, 5 };
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
/* convert axis and face distance into face */
|
|
|
|
static const int faces_table[3][6] = {
|
|
|
|
{-1, 0, 0, -1, 3, 3},
|
|
|
|
{-1, 4, 4, -1, 1, 1},
|
|
|
|
{-1, 2, 2, -1, 5, 5},
|
|
|
|
};
|
|
|
|
|
|
|
|
/* convert face magic bit mask to index into visit array */
|
|
|
|
static const int faces_bit_magic[] = { 2, 1, -1, 0, 3, -1, 4, -1 };
|
|
|
|
|
|
|
|
/* axis the cube face cuts (also index into vec3_t and n % 3 for 0 <= n < 6) */
|
|
|
|
static const int face_axis[] = { 0, 1, 2, 0, 1, 2 };
|
|
|
|
|
|
|
|
/* offset on the axis the cube face cuts */
|
|
|
|
static const vec_t face_offset[] = { 1024, 1024, 1024, -1024, -1024, -1024 };
|
|
|
|
|
|
|
|
/* cube face */
|
|
|
|
struct face_def {
|
|
|
|
int tex; // texture to bind to
|
|
|
|
glpoly_t poly; // describe the polygon of this face
|
|
|
|
float verts[32][VERTEXSIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct visit_def {
|
|
|
|
int face; // face being visited
|
|
|
|
int leave; // vertex departed through
|
|
|
|
};
|
|
|
|
|
|
|
|
/* our cube */
|
|
|
|
struct box_def {
|
|
|
|
/* keep track of which cube faces we visit and in what order */
|
|
|
|
struct visit_def visited_faces[9];
|
|
|
|
int face_visits[6];
|
|
|
|
int face_count;
|
|
|
|
/* the cube faces */
|
|
|
|
struct face_def face[6];
|
|
|
|
};
|
|
|
|
|
2001-09-01 08:57:04 +00:00
|
|
|
|
2001-05-21 15:59:02 +00:00
|
|
|
|
2001-05-11 01:01:27 +00:00
|
|
|
/*
|
|
|
|
determine_face
|
|
|
|
|
|
|
|
return the face of the cube which v hits first
|
|
|
|
0 +x
|
|
|
|
1 +y
|
|
|
|
2 +z
|
|
|
|
3 -x
|
|
|
|
4 -y
|
|
|
|
5 -z
|
|
|
|
Also scales v so it touches that face.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
determine_face (vec3_t v)
|
|
|
|
{
|
|
|
|
float m;
|
2001-09-01 08:57:04 +00:00
|
|
|
float a[3];
|
2001-05-11 01:01:27 +00:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
m = a[0] = fabs (v[0]);
|
|
|
|
a[1] = fabs (v[1]);
|
|
|
|
a[2] = fabs (v[2]);
|
|
|
|
if (a[1] > m) {
|
|
|
|
m = a[1];
|
|
|
|
i = 1;
|
|
|
|
}
|
|
|
|
if (a[2] > m) {
|
|
|
|
m = a[2];
|
|
|
|
i = 2;
|
|
|
|
}
|
|
|
|
if (!m) {
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("You are speared by a sky poly edge");
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
|
|
|
if (v[i] < 0)
|
|
|
|
i += 3;
|
|
|
|
VectorScale (v, 1024 / m, v);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
find_intersect (for want of a better name)
|
|
|
|
|
|
|
|
finds the point of intersection of the plane formed by the eye and the two
|
|
|
|
points on the cube and the edge of the cube defined by the two faces.
|
|
|
|
Currently, this will break if the two points are not on adjoining cube
|
|
|
|
faces (ie either on opposing faces or the same face).
|
|
|
|
|
|
|
|
The equation for the point of intersection of a line and a plane is:
|
|
|
|
|
|
|
|
(x - p).n
|
|
|
|
y = x - _________ v
|
|
|
|
v.n
|
|
|
|
|
|
|
|
where n is the normal to the plane, p is a point on the plane, x is a
|
|
|
|
point on the line, and v is the direction vector of the line. n is found
|
|
|
|
by (x1 - e) cross (x2 - e) and p is taken to be e (e = eye coords) for
|
|
|
|
simplicity. However, because e is at 0,0,0, this simplifies to n = x1
|
|
|
|
cross x2 and p = 0,0,0, so the equation above simplifies to:
|
|
|
|
|
|
|
|
x.n
|
|
|
|
y = x - ___ v
|
|
|
|
v.n
|
|
|
|
*/
|
|
|
|
static int
|
2002-01-03 18:18:45 +00:00
|
|
|
find_intersect (int face1, const vec3_t x1, int face2, const vec3_t x2,
|
|
|
|
vec3_t y)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
2001-09-01 08:57:04 +00:00
|
|
|
int axis;
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t n; // normal to the plane formed by the
|
2001-09-01 08:57:04 +00:00
|
|
|
// eye and the two points on the cube.
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t x = { 0, 0, 0 }; // point on cube edge of adjoining
|
2001-09-01 08:57:04 +00:00
|
|
|
// faces. always on an axis plane.
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t v = { 0, 0, 0 }; // direction vector of cube edge.
|
|
|
|
// always +ve
|
|
|
|
vec_t x_n, v_n; // x.n and v.n
|
|
|
|
vec3_t t;
|
|
|
|
|
|
|
|
x[face_axis[face1]] = face_offset[face1];
|
|
|
|
x[face_axis[face2]] = face_offset[face2];
|
|
|
|
|
|
|
|
axis = 3 - ((face_axis[face1]) + (face_axis[face2]));
|
|
|
|
v[axis] = 1;
|
|
|
|
|
|
|
|
CrossProduct (x1, x2, n);
|
|
|
|
|
|
|
|
x_n = DotProduct (x, n);
|
|
|
|
v_n = DotProduct (v, n);
|
|
|
|
VectorScale (v, x_n / v_n, t);
|
|
|
|
VectorSubtract (x, t, y);
|
|
|
|
|
|
|
|
return axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
find_cube_vertex
|
|
|
|
|
|
|
|
get the coords of the vertex common to the three specified faces of the
|
|
|
|
cube. NOTE: this WILL break if the three faces do not share a common
|
|
|
|
vertex. ie works = ((face1 % 3 != face2 % 3)
|
|
|
|
&& (face2 % 3 != face3 % 3)
|
|
|
|
&& (face1 % 3 != face3 % 3))
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
find_cube_vertex (int face1, int face2, int face3, vec3_t v)
|
|
|
|
{
|
|
|
|
v[face_axis[face1]] = face_offset[face1];
|
|
|
|
v[face_axis[face2]] = face_offset[face2];
|
|
|
|
v[face_axis[face3]] = face_offset[face3];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set_vertex
|
|
|
|
|
|
|
|
add the vertex to the polygon describing the face of the cube. Offsets
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
the vertex relative to r_refdef.frame.position so the cube is always centered
|
2001-05-11 01:01:27 +00:00
|
|
|
on the player and also calculates the texture coordinates of the vertex
|
|
|
|
(wish I could find a cleaner way of calculating s and t).
|
|
|
|
*/
|
|
|
|
static void
|
2002-01-03 18:18:45 +00:00
|
|
|
set_vertex (struct box_def *box, int face, int ind, const vec3_t v)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorAdd (v, r_refdef.frame.position, box->face[face].poly.verts[ind]);
|
2001-05-11 01:01:27 +00:00
|
|
|
switch (face) {
|
|
|
|
case 0:
|
2001-10-06 00:31:57 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 - v[1] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 - v[2] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2001-10-06 00:31:57 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 + v[0] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 - v[2] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2012-09-12 23:36:28 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 - v[1] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 + v[0] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2001-10-06 00:31:57 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 + v[1] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 - v[2] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2001-10-06 00:31:57 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 - v[0] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 - v[2] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2012-09-12 23:36:28 +00:00
|
|
|
box->face[face].poly.verts[ind][3] = (1024 - v[1] + 4) / BOX_WIDTH;
|
|
|
|
box->face[face].poly.verts[ind][4] = (1024 - v[0] + 4) / BOX_WIDTH;
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
add_vertex
|
|
|
|
|
|
|
|
append a vertex to the poly vertex list.
|
|
|
|
*/
|
2002-01-04 03:25:30 +00:00
|
|
|
static inline void
|
2002-01-03 18:18:45 +00:00
|
|
|
add_vertex (struct box_def *box, int face, const vec3_t v)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
|
|
|
set_vertex (box, face, box->face[face].poly.numverts++, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
insert_cube_vertices
|
|
|
|
|
|
|
|
insert the given cube vertices into the vertex list of the poly in the
|
|
|
|
correct location.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
insert_cube_vertices (struct box_def *box, struct visit_def visit, int count,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int face = visit.face;
|
|
|
|
int ind = visit.leave + 1;
|
2001-09-01 08:57:04 +00:00
|
|
|
va_list args;
|
|
|
|
vec3_t **v;
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
va_start (args, count);
|
|
|
|
v = (vec3_t **) alloca (count * sizeof (vec3_t *));
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
v[i] = va_arg (args, vec3_t *);
|
|
|
|
}
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
if (ind == box->face[face].poly.numverts) {
|
2002-04-30 16:37:11 +00:00
|
|
|
// the vertex the sky poly left this cube face through is very
|
2001-10-02 06:58:44 +00:00
|
|
|
// conveniently the last vertex of the face poly. this means we can
|
2002-04-30 16:37:11 +00:00
|
|
|
// just append the vertices
|
2001-05-11 01:01:27 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
add_vertex (box, face, *v[i]);
|
|
|
|
} else {
|
2001-10-02 06:58:44 +00:00
|
|
|
// we have to insert the cube vertices into the face poly vertex list
|
2001-05-11 01:01:27 +00:00
|
|
|
glpoly_t *p = &box->face[face].poly;
|
|
|
|
int c = p->numverts - ind;
|
|
|
|
const int vert_size = sizeof (p->verts[0]);
|
|
|
|
|
|
|
|
memmove (p->verts[ind + count], p->verts[ind], c * vert_size);
|
|
|
|
p->numverts += count;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
set_vertex (box, face, ind + i, *v[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
cross_cube_edge
|
|
|
|
|
|
|
|
add the vertex formed by the poly edge crossing the cube edge to the
|
|
|
|
polygon for the two faces on that edge. Actually, the two faces define
|
|
|
|
the edge :). The poly edge is going from face 1 to face 2 (for
|
|
|
|
enter/leave purposes).
|
|
|
|
*/
|
|
|
|
static void
|
2002-01-03 18:18:45 +00:00
|
|
|
cross_cube_edge (struct box_def *box, int face1, const vec3_t v1, int face2,
|
|
|
|
const vec3_t v2)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
|
|
|
int axis;
|
|
|
|
int face = -1;
|
2001-09-01 08:57:04 +00:00
|
|
|
vec3_t l;
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
axis = find_intersect (face1, v1, face2, v2, l);
|
|
|
|
if (l[axis] > 1024)
|
|
|
|
face = axis;
|
|
|
|
else if (l[axis] < -1024)
|
|
|
|
face = axis + 3;
|
|
|
|
if (face >= 0) {
|
|
|
|
vec3_t x;
|
|
|
|
|
|
|
|
VectorAdd (v1, v2, x);
|
|
|
|
VectorScale (x, 0.5, x);
|
|
|
|
cross_cube_edge (box, face1, v1, face, x);
|
|
|
|
cross_cube_edge (box, face, x, face2, v2);
|
|
|
|
} else {
|
|
|
|
struct visit_def *visit = box->visited_faces;
|
|
|
|
|
|
|
|
visit[box->face_count - 1].leave = box->face[face1].poly.numverts;
|
|
|
|
visit[box->face_count].face = face2;
|
|
|
|
box->face_count++;
|
|
|
|
box->face_visits[face2]++;
|
|
|
|
|
|
|
|
add_vertex (box, face1, l);
|
|
|
|
add_vertex (box, face2, l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
process_corners
|
|
|
|
|
|
|
|
egad, veddy complicated :)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
process_corners (struct box_def *box)
|
|
|
|
{
|
|
|
|
int i;
|
2001-09-01 08:57:04 +00:00
|
|
|
int center = -1, max_visit = 0;
|
|
|
|
struct visit_def *visit = box->visited_faces;
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
if (visit[box->face_count - 1].face == visit[0].face) {
|
|
|
|
box->face_count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (max_visit < box->face_visits[i]) {
|
|
|
|
max_visit = box->face_visits[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (box->face_count) {
|
2001-09-10 00:57:11 +00:00
|
|
|
case 1: // a
|
|
|
|
case 2: // b
|
|
|
|
case 8: // f
|
2001-05-11 01:01:27 +00:00
|
|
|
// no corners
|
|
|
|
return;
|
2001-09-10 00:57:11 +00:00
|
|
|
case 3: // g
|
2001-05-11 01:01:27 +00:00
|
|
|
// one corner, no edges
|
|
|
|
{
|
|
|
|
vec3_t v;
|
|
|
|
|
|
|
|
find_cube_vertex (visit[0].face, visit[1].face, visit[2].face,
|
|
|
|
v);
|
|
|
|
insert_cube_vertices (box, visit[0], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[1], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[2], 1, v);
|
|
|
|
}
|
|
|
|
break;
|
2001-09-10 00:57:11 +00:00
|
|
|
case 4: // c d j n
|
2002-09-23 06:18:48 +00:00
|
|
|
if (max_visit > 1) // c d
|
2001-05-11 01:01:27 +00:00
|
|
|
return;
|
|
|
|
if (abs (visit[2].face - visit[0].face) == 3
|
|
|
|
&& abs (visit[3].face - visit[1].face) == 3) {
|
2002-09-23 06:18:48 +00:00
|
|
|
// 4 vertices, n
|
2001-05-11 01:01:27 +00:00
|
|
|
int sum, diff;
|
|
|
|
vec3_t v[4];
|
|
|
|
|
2001-10-02 06:58:44 +00:00
|
|
|
sum = visit[0].face + visit[1].face + visit[2].face +
|
2001-05-11 01:01:27 +00:00
|
|
|
visit[3].face;
|
|
|
|
diff = visit[1].face - visit[0].face;
|
|
|
|
sum %= 3;
|
|
|
|
diff = (diff + 6) % 6;
|
|
|
|
|
|
|
|
center = faces_table[sum][diff];
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
find_cube_vertex (visit[i].face, visit[(i + 1) & 3].face,
|
|
|
|
center, v[i]);
|
|
|
|
add_vertex (box, center, v[i]);
|
|
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
insert_cube_vertices (box, visit[i], 2, v[i],
|
|
|
|
v[(i - 1) & 3]);
|
|
|
|
} else {
|
2002-09-23 06:18:48 +00:00
|
|
|
// 2 vertices, j
|
2001-05-11 01:01:27 +00:00
|
|
|
int l_f, t_f, r_f, b_f;
|
|
|
|
vec3_t v_l, v_r;
|
|
|
|
|
|
|
|
if (abs (visit[2].face - visit[0].face) == 3) {
|
|
|
|
l_f = 0;
|
|
|
|
t_f = 1;
|
|
|
|
r_f = 2;
|
|
|
|
b_f = 3;
|
|
|
|
} else if (abs (visit[3].face - visit[1].face) == 3) {
|
|
|
|
l_f = 1;
|
|
|
|
t_f = 2;
|
|
|
|
r_f = 3;
|
|
|
|
b_f = 0;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
find_cube_vertex (visit[l_f].face, visit[t_f].face,
|
|
|
|
visit[b_f].face, v_l);
|
|
|
|
find_cube_vertex (visit[r_f].face, visit[t_f].face,
|
|
|
|
visit[b_f].face, v_r);
|
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[t_f], 2, v_r, v_l);
|
|
|
|
insert_cube_vertices (box, visit[b_f], 2, v_l, v_r);
|
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[l_f], 1, v_l);
|
|
|
|
insert_cube_vertices (box, visit[r_f], 1, v_r);
|
|
|
|
}
|
|
|
|
break;
|
2001-09-10 00:57:11 +00:00
|
|
|
case 5: // h m
|
2001-05-11 01:01:27 +00:00
|
|
|
if (max_visit > 1) {
|
2002-09-23 06:18:48 +00:00
|
|
|
// one vertex, h
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t v;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
// don't need to check the 5th visit
|
|
|
|
if (visit[(i + 2) % 5].face == visit[(i + 4) % 5].face)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
find_cube_vertex (visit[i].face, visit[(i + 1) % 5].face,
|
|
|
|
visit[(i + 2) % 5].face, v);
|
|
|
|
insert_cube_vertices (box, visit[i], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[(i + 1) % 5], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[(i + 4) % 5], 1, v);
|
|
|
|
} else {
|
2002-09-23 06:18:48 +00:00
|
|
|
// 3 vertices, m
|
2001-05-11 01:01:27 +00:00
|
|
|
unsigned int sel =
|
|
|
|
(((abs (visit[2].face - visit[0].face) == 3) << 2) |
|
2001-10-01 21:52:05 +00:00
|
|
|
((abs (visit[3].face - visit[1].face) == 3) << 1) |
|
|
|
|
((abs (visit[4].face - visit[2].face) == 3) << 0));
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t v[3];
|
|
|
|
|
|
|
|
center = faces_bit_magic[sel];
|
2001-10-18 16:42:14 +00:00
|
|
|
// Sys_Printf ("%02o %d %d %d %d %d %d\n", sel, center,
|
2001-05-11 01:01:27 +00:00
|
|
|
// visit[0].face,
|
|
|
|
// visit[1].face, visit[2].face, visit[3].face,
|
|
|
|
// visit[4].face);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
find_cube_vertex (visit[center].face,
|
|
|
|
visit[(center + 1 + i) % 5].face,
|
|
|
|
visit[(center + 2 + i) % 5].face, v[i]);
|
|
|
|
insert_cube_vertices (box, visit[center], 3, v[0], v[1], v[2]);
|
|
|
|
insert_cube_vertices (box, visit[(center + 1) % 5], 1, v[0]);
|
|
|
|
insert_cube_vertices (box, visit[(center + 2) % 5], 2, v[1],
|
|
|
|
v[0]);
|
|
|
|
insert_cube_vertices (box, visit[(center + 3) % 5], 2, v[2],
|
|
|
|
v[1]);
|
|
|
|
insert_cube_vertices (box, visit[(center + 4) % 5], 1, v[2]);
|
|
|
|
}
|
|
|
|
break;
|
2002-09-23 06:18:48 +00:00
|
|
|
case 6: // e k l o
|
2001-09-10 00:57:11 +00:00
|
|
|
if (max_visit > 2) // e
|
2001-05-11 01:01:27 +00:00
|
|
|
return;
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
|
// don't need to check the last point
|
|
|
|
if (visit[(i + 3) % 6].face == visit[(i + 5) % 6].face
|
|
|
|
|| visit[(i + 2) % 6].face == visit[(i + 5) % 6].face)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (visit[(i + 3) % 6].face == visit[(i + 5) % 6].face) {
|
2002-09-23 06:18:48 +00:00
|
|
|
// adjacant vertices, l o
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t v[2];
|
|
|
|
|
2002-09-23 06:18:48 +00:00
|
|
|
if (visit[(i + 0) % 6].face == visit[(i + 2) % 6].face) // o
|
|
|
|
return;
|
|
|
|
// l
|
2001-09-10 00:57:11 +00:00
|
|
|
find_cube_vertex (visit[i].face,
|
|
|
|
visit[(i + 1) % 6].face,
|
|
|
|
visit[(i + 5) % 6].face, v[0]);
|
2001-05-11 01:01:27 +00:00
|
|
|
find_cube_vertex (visit[(i + 1) % 6].face,
|
|
|
|
visit[(i + 2) % 6].face,
|
|
|
|
visit[(i + 3) % 6].face, v[1]);
|
|
|
|
|
2001-09-10 00:57:11 +00:00
|
|
|
insert_cube_vertices (box, visit[(i + 5) % 6], 2, v[0], v[1]);
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[i], 1, v[0]);
|
|
|
|
insert_cube_vertices (box, visit[(i + 1) % 6], 2, v[1], v[0]);
|
|
|
|
insert_cube_vertices (box, visit[(i + 2) % 6], 1, v[1]);
|
|
|
|
} else {
|
2002-09-23 06:18:48 +00:00
|
|
|
// opposing vertices, k
|
2001-05-11 01:01:27 +00:00
|
|
|
vec3_t v[2];
|
|
|
|
|
|
|
|
find_cube_vertex (visit[i].face, visit[(i + 1) % 6].face,
|
|
|
|
visit[(i + 2) % 6].face, v[0]);
|
|
|
|
find_cube_vertex (visit[(i + 3) % 6].face,
|
|
|
|
visit[(i + 4) % 6].face,
|
|
|
|
visit[(i + 5) % 6].face, v[1]);
|
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[i], 1, v[0]);
|
|
|
|
insert_cube_vertices (box, visit[(i + 1) % 6], 1, v[0]);
|
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[(i + 3) % 6], 1, v[1]);
|
|
|
|
insert_cube_vertices (box, visit[(i + 4) % 6], 1, v[1]);
|
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[(i + 2) % 6], 1, v[1]);
|
|
|
|
insert_cube_vertices (box, visit[(i + 5) % 6], 1, v[0]);
|
|
|
|
}
|
|
|
|
break;
|
2001-09-10 00:57:11 +00:00
|
|
|
case 7: // i
|
2001-05-11 01:01:27 +00:00
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
// don't need to check the last point
|
2002-10-02 01:58:29 +00:00
|
|
|
if (visit[(i + 2) % 7].face == visit[(i + 4) % 7].face
|
|
|
|
&& visit[(i + 4) % 7].face == visit[(i + 6) % 7].face)
|
2001-05-11 01:01:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
vec3_t v;
|
|
|
|
|
2002-10-02 01:58:29 +00:00
|
|
|
find_cube_vertex (visit[i].face, visit[(i + 1) % 7].face,
|
|
|
|
visit[(i + 2) % 7].face, v);
|
2001-05-11 01:01:27 +00:00
|
|
|
|
|
|
|
insert_cube_vertices (box, visit[i], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[(i + 1) % 7], 1, v);
|
|
|
|
insert_cube_vertices (box, visit[(i + 6) % 7], 1, v);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
render_box
|
|
|
|
|
|
|
|
draws all faces of the cube with 3 or more vertices.
|
|
|
|
*/
|
|
|
|
static void
|
2002-01-03 18:18:45 +00:00
|
|
|
render_box (const struct box_def *box)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (box->face[i].poly.numverts <= 2)
|
|
|
|
continue;
|
2001-06-26 02:26:46 +00:00
|
|
|
qfglBindTexture (GL_TEXTURE_2D, box->face[i].tex);
|
|
|
|
qfglBegin (GL_POLYGON);
|
2001-05-11 01:01:27 +00:00
|
|
|
for (j = 0; j < box->face[i].poly.numverts; j++) {
|
2001-06-26 02:26:46 +00:00
|
|
|
qfglTexCoord2fv (box->face[i].poly.verts[j] + 3);
|
|
|
|
qfglVertex3fv (box->face[i].poly.verts[j]);
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
2001-06-26 02:26:46 +00:00
|
|
|
qfglEnd ();
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2002-01-03 18:18:45 +00:00
|
|
|
R_DrawSkyBoxPoly (const glpoly_t *poly)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct box_def box;
|
|
|
|
|
|
|
|
/* projected vertex and face of the previous sky poly vertex */
|
|
|
|
vec3_t last_v;
|
|
|
|
int prev_face;
|
|
|
|
|
|
|
|
/* projected vertex and face of the current sky poly vertex */
|
|
|
|
vec3_t v;
|
|
|
|
int face;
|
|
|
|
|
|
|
|
memset (&box, 0, sizeof (box));
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
box.face[i].tex = SKY_TEX + skytex_offs[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poly->numverts >= 32) {
|
|
|
|
Sys_Error ("too many verts!");
|
|
|
|
}
|
|
|
|
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorSubtract (poly->verts[poly->numverts - 1], r_refdef.frame.position, last_v);
|
2001-05-11 01:01:27 +00:00
|
|
|
prev_face = determine_face (last_v);
|
|
|
|
|
|
|
|
box.visited_faces[0].face = prev_face;
|
|
|
|
box.face_count = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < poly->numverts; i++) {
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorSubtract (poly->verts[i], r_refdef.frame.position, v);
|
2001-05-11 01:01:27 +00:00
|
|
|
face = determine_face (v);
|
|
|
|
if (face != prev_face) {
|
|
|
|
if ((face_axis[face]) == (face_axis[prev_face])) {
|
|
|
|
int x_face;
|
|
|
|
vec3_t x;
|
|
|
|
|
|
|
|
VectorAdd (v, last_v, x);
|
|
|
|
VectorScale (x, 0.5, x);
|
|
|
|
x_face = determine_face (x);
|
|
|
|
|
|
|
|
cross_cube_edge (&box, prev_face, last_v, x_face, x);
|
|
|
|
cross_cube_edge (&box, x_face, x, face, v);
|
|
|
|
} else {
|
|
|
|
cross_cube_edge (&box, prev_face, last_v, face, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_vertex (&box, face, v);
|
|
|
|
|
|
|
|
VectorCopy (v, last_v);
|
|
|
|
prev_face = face;
|
|
|
|
}
|
|
|
|
|
|
|
|
process_corners (&box);
|
|
|
|
|
|
|
|
render_box (&box);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
EmitSkyPolys (float speedscale, const instsurf_t *sc)
|
2001-09-03 06:12:10 +00:00
|
|
|
{
|
2001-11-25 08:00:16 +00:00
|
|
|
float length, s, t;
|
2001-09-03 06:12:10 +00:00
|
|
|
float *v;
|
|
|
|
int i;
|
2001-11-25 08:00:16 +00:00
|
|
|
glpoly_t *p;
|
2001-09-03 06:12:10 +00:00
|
|
|
vec3_t dir;
|
2021-07-15 12:38:12 +00:00
|
|
|
msurface_t *surf = sc->surface;
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
vec4f_t origin = r_refdef.frame.position;
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
//FIXME transform/color
|
2021-07-15 12:38:12 +00:00
|
|
|
for (p = surf->polys; p; p = p->next) {
|
2001-09-03 06:12:10 +00:00
|
|
|
qfglBegin (GL_POLYGON);
|
|
|
|
for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) {
|
2022-03-07 18:47:36 +00:00
|
|
|
VectorSubtract (v, origin, dir);
|
2001-11-25 08:00:16 +00:00
|
|
|
dir[2] *= 3.0; // flatten the sphere
|
2001-09-03 06:12:10 +00:00
|
|
|
|
|
|
|
length = DotProduct (dir, dir);
|
2001-11-25 08:00:16 +00:00
|
|
|
length = 2.953125 / sqrt (length);
|
2001-09-03 06:12:10 +00:00
|
|
|
|
|
|
|
dir[0] *= length;
|
|
|
|
dir[1] *= length;
|
|
|
|
|
2001-11-25 07:41:17 +00:00
|
|
|
s = speedscale + dir[0];
|
|
|
|
t = speedscale + dir[1];
|
2001-09-03 06:12:10 +00:00
|
|
|
|
|
|
|
qfglTexCoord2f (s, t);
|
|
|
|
qfglVertex3fv (v);
|
|
|
|
}
|
|
|
|
qfglEnd ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
static inline void
|
2002-01-03 18:18:45 +00:00
|
|
|
draw_poly (const glpoly_t *poly)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
qfglBegin (GL_POLYGON);
|
|
|
|
for (i = 0; i < poly->numverts; i++) {
|
|
|
|
qfglVertex3fv (poly->verts[i]);
|
|
|
|
}
|
|
|
|
qfglEnd ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
draw_black_sky_polys (const instsurf_t *sky_chain)
|
2001-05-11 01:01:27 +00:00
|
|
|
{
|
2011-12-17 10:14:14 +00:00
|
|
|
const instsurf_t *sc = sky_chain;
|
2001-07-22 02:06:02 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
qfglDisable (GL_BLEND);
|
|
|
|
qfglDisable (GL_TEXTURE_2D);
|
|
|
|
qfglColor3ubv (color_black);
|
|
|
|
while (sc) {
|
2011-12-17 10:14:14 +00:00
|
|
|
glpoly_t *p = sc->surface->polys;
|
2001-07-22 02:06:02 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform) {
|
|
|
|
qfglPushMatrix ();
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
qfglLoadMatrixf ((vec_t*)&sc->transform[0]);//FIXME
|
2011-12-17 10:14:14 +00:00
|
|
|
}
|
2001-10-03 02:51:30 +00:00
|
|
|
while (p) {
|
|
|
|
draw_poly (p);
|
|
|
|
p = p->next;
|
2001-07-22 02:06:02 +00:00
|
|
|
}
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform)
|
2012-01-24 03:08:12 +00:00
|
|
|
qfglPopMatrix ();
|
2011-12-17 10:14:14 +00:00
|
|
|
sc = sc->tex_chain;
|
2001-07-22 02:06:02 +00:00
|
|
|
}
|
2001-10-03 02:51:30 +00:00
|
|
|
qfglEnable (GL_TEXTURE_2D);
|
|
|
|
qfglEnable (GL_BLEND);
|
|
|
|
qfglColor3ubv (color_white);
|
|
|
|
}
|
2001-07-22 02:06:02 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
draw_skybox_sky_polys (const instsurf_t *sky_chain)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
2011-12-17 10:14:14 +00:00
|
|
|
const instsurf_t *sc = sky_chain;
|
2001-05-11 01:01:27 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
qfglDepthMask (GL_FALSE);
|
|
|
|
qfglDisable (GL_DEPTH_TEST);
|
|
|
|
while (sc) {
|
2011-12-17 10:14:14 +00:00
|
|
|
glpoly_t *p = sc->surface->polys;
|
2001-10-03 02:51:30 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
//FIXME transform/color
|
2001-10-03 02:51:30 +00:00
|
|
|
while (p) {
|
|
|
|
R_DrawSkyBoxPoly (p);
|
|
|
|
p = p->next;
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
2011-12-17 10:14:14 +00:00
|
|
|
sc = sc->tex_chain;
|
2001-10-03 02:51:30 +00:00
|
|
|
}
|
|
|
|
qfglEnable (GL_DEPTH_TEST);
|
|
|
|
qfglDepthMask (GL_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
draw_skydome_sky_polys (const instsurf_t *sky_chain)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
|
|
|
// this function is not yet implemented so just draw black
|
|
|
|
draw_black_sky_polys (sky_chain);
|
|
|
|
}
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
draw_id_sky_polys (const instsurf_t *sky_chain)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
2011-12-17 10:14:14 +00:00
|
|
|
const instsurf_t *sc = sky_chain;
|
2001-10-03 02:51:30 +00:00
|
|
|
float speedscale;
|
|
|
|
|
2012-02-14 08:28:09 +00:00
|
|
|
speedscale = vr_data.realtime / 16;
|
2001-11-25 07:41:17 +00:00
|
|
|
speedscale -= floor (speedscale);
|
2001-10-03 02:51:30 +00:00
|
|
|
|
2012-02-17 09:33:07 +00:00
|
|
|
qfglBindTexture (GL_TEXTURE_2D, gl_solidskytexture);
|
2001-10-03 02:51:30 +00:00
|
|
|
while (sc) {
|
|
|
|
EmitSkyPolys (speedscale, sc);
|
2011-12-17 10:14:14 +00:00
|
|
|
sc = sc->tex_chain;
|
2001-10-03 02:51:30 +00:00
|
|
|
}
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_multipass) {
|
2001-10-03 02:51:30 +00:00
|
|
|
sc = sky_chain;
|
|
|
|
|
2012-02-14 08:28:09 +00:00
|
|
|
speedscale = vr_data.realtime / 8;
|
2001-11-25 07:41:17 +00:00
|
|
|
speedscale -= floor (speedscale);
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2012-02-17 09:33:07 +00:00
|
|
|
qfglBindTexture (GL_TEXTURE_2D, gl_alphaskytexture);
|
2001-09-03 06:12:10 +00:00
|
|
|
while (sc) {
|
|
|
|
EmitSkyPolys (speedscale, sc);
|
2011-12-17 10:14:14 +00:00
|
|
|
sc = sc->tex_chain;
|
2001-09-03 06:12:10 +00:00
|
|
|
}
|
2001-10-03 02:51:30 +00:00
|
|
|
}
|
|
|
|
}
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
static void
|
2011-12-17 10:14:14 +00:00
|
|
|
draw_z_sky_polys (const instsurf_t *sky_chain)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
2011-12-17 10:14:14 +00:00
|
|
|
const instsurf_t *sc = sky_chain;
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
qfglColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
|
|
qfglDisable (GL_BLEND);
|
|
|
|
qfglDisable (GL_TEXTURE_2D);
|
|
|
|
qfglColor3ubv (color_black);
|
|
|
|
while (sc) {
|
2011-12-17 10:14:14 +00:00
|
|
|
glpoly_t *p = sc->surface->polys;
|
2001-09-03 06:12:10 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform) {
|
|
|
|
qfglPushMatrix ();
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
qfglLoadMatrixf ((vec_t*)&sc->transform[0]);//FIXME
|
2011-12-17 10:14:14 +00:00
|
|
|
}
|
2001-10-03 02:51:30 +00:00
|
|
|
while (p) {
|
|
|
|
draw_poly (p);
|
|
|
|
p = p->next;
|
2001-09-03 06:12:10 +00:00
|
|
|
}
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform)
|
|
|
|
qfglPopMatrix ();
|
|
|
|
sc = sc->tex_chain;
|
2001-10-03 02:51:30 +00:00
|
|
|
}
|
|
|
|
qfglColor3ubv (color_white);
|
|
|
|
qfglEnable (GL_TEXTURE_2D);
|
|
|
|
qfglEnable (GL_BLEND);
|
|
|
|
qfglColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
}
|
2001-05-11 01:01:27 +00:00
|
|
|
|
2001-10-03 02:51:30 +00:00
|
|
|
void
|
2012-02-22 07:32:34 +00:00
|
|
|
gl_R_DrawSkyChain (const instsurf_t *sky_chain)
|
2001-10-03 02:51:30 +00:00
|
|
|
{
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_clip > 2) {
|
2001-10-03 02:51:30 +00:00
|
|
|
draw_black_sky_polys (sky_chain);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-17 09:33:07 +00:00
|
|
|
if (gl_skyloaded) {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_clip) {
|
2001-10-03 02:51:30 +00:00
|
|
|
draw_skybox_sky_polys (sky_chain);
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
2002-06-14 19:25:32 +00:00
|
|
|
draw_z_sky_polys (sky_chain);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
} else if (gl_sky_clip == 2) {
|
2001-10-03 02:51:30 +00:00
|
|
|
draw_id_sky_polys (sky_chain);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
} else if (gl_sky_clip) {
|
2002-06-14 19:25:32 +00:00
|
|
|
// XXX not properly implemented
|
2001-10-03 02:51:30 +00:00
|
|
|
draw_skydome_sky_polys (sky_chain);
|
2002-06-14 19:25:32 +00:00
|
|
|
//draw_z_sky_polys (sky_chain);
|
|
|
|
} else {
|
|
|
|
draw_z_sky_polys (sky_chain);
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|
2001-11-25 08:00:16 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_debug) {
|
2011-12-17 10:14:14 +00:00
|
|
|
const instsurf_t *sc;
|
2002-01-03 18:18:45 +00:00
|
|
|
|
|
|
|
qfglDisable (GL_TEXTURE_2D);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_debug & 1) {
|
2002-01-03 18:18:45 +00:00
|
|
|
sc = sky_chain;
|
|
|
|
qfglColor3ub (255, 255, 255);
|
|
|
|
while (sc) {
|
2011-12-17 10:14:14 +00:00
|
|
|
glpoly_t *p = sc->surface->polys;
|
2002-01-03 18:18:45 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform) {
|
|
|
|
qfglPushMatrix ();
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
qfglLoadMatrixf ((vec_t*)&sc->transform[0]);//FIXME
|
2011-12-17 10:14:14 +00:00
|
|
|
}
|
2002-01-03 18:18:45 +00:00
|
|
|
while (p) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
qfglBegin (GL_LINE_LOOP);
|
|
|
|
for (i = 0; i < p->numverts; i++) {
|
|
|
|
qfglVertex3fv (p->verts[i]);
|
|
|
|
}
|
|
|
|
qfglEnd ();
|
|
|
|
p = p->next;
|
|
|
|
}
|
2012-01-24 03:08:12 +00:00
|
|
|
if (sc->transform)
|
|
|
|
qfglPopMatrix ();
|
2011-12-17 10:14:14 +00:00
|
|
|
sc = sc->tex_chain;
|
2001-09-09 21:27:09 +00:00
|
|
|
}
|
|
|
|
}
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_debug & 2) {
|
2002-01-03 18:18:45 +00:00
|
|
|
sc = sky_chain;
|
|
|
|
qfglColor3ub (0, 255, 0);
|
|
|
|
qfglBegin (GL_POINTS);
|
|
|
|
while (sc) {
|
2011-12-17 10:14:14 +00:00
|
|
|
glpoly_t *p = sc->surface->polys;
|
2002-01-03 18:18:45 +00:00
|
|
|
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform) {
|
|
|
|
qfglPushMatrix ();
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
qfglLoadMatrixf ((vec_t*)&sc->transform[0]);//FIXME
|
2011-12-17 10:14:14 +00:00
|
|
|
}
|
2002-01-03 18:18:45 +00:00
|
|
|
while (p) {
|
|
|
|
int i;
|
|
|
|
vec3_t x, c = { 0, 0, 0 };
|
|
|
|
|
|
|
|
for (i = 0; i < p->numverts; i++) {
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorSubtract (p->verts[i], r_refdef.frame.position, x);
|
2002-01-03 18:18:45 +00:00
|
|
|
VectorAdd (x, c, c);
|
|
|
|
}
|
|
|
|
VectorScale (c, 1.0 / p->numverts, c);
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorAdd (c, r_refdef.frame.position, c);
|
2002-01-03 18:18:45 +00:00
|
|
|
qfglVertex3fv (c);
|
|
|
|
p = p->next;
|
|
|
|
}
|
2011-12-17 10:14:14 +00:00
|
|
|
if (sc->transform)
|
|
|
|
qfglPopMatrix ();
|
|
|
|
sc = sc->tex_chain;
|
2001-09-09 21:27:09 +00:00
|
|
|
}
|
2002-01-03 18:18:45 +00:00
|
|
|
qfglEnd ();
|
2001-09-09 21:27:09 +00:00
|
|
|
}
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (gl_sky_debug & 4) {
|
2012-02-17 09:33:07 +00:00
|
|
|
if (gl_skyloaded) {
|
2002-01-03 18:18:45 +00:00
|
|
|
int i, j;
|
|
|
|
|
|
|
|
qfglColor3ub (255, 0, 0);
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
vec3_t v;
|
|
|
|
|
|
|
|
qfglBegin (GL_LINE_LOOP);
|
|
|
|
for (j = 0; j < 4; j++) {
|
2012-02-17 09:33:07 +00:00
|
|
|
VectorScale (&gl_skyvec[i][j][2], 1.0 / 128.0, v);
|
[renderer] Clean up use of vup/vright/vpn
This moves the common camera setup code out of the individual drivers,
and completely removes vup/vright/vpn from the non-software renderers.
This has highlighted the craziness around AngleVectors with it putting
+X forward, -Y right and +Z up. The main issue with this is it requires
a 90 degree pre-rotation about the Z axis to get the camera pointing in
the right direction, and that's for the native sw renderer (vulkan needs
a 90 degree pre-rotation about X, and gl and glsl need to invert an
axis, too), though at least it's just a matrix swizzle and vector
negation. However, it does mean the camera matrices can't be used
directly.
Also rename vpn to vfwd (still abbreviated, but fwd is much clearer in
meaning (to me, at least) than pn (plane normal, I guess, but which
way?)).
2022-03-14 00:34:24 +00:00
|
|
|
VectorAdd (v, r_refdef.frame.position, v);
|
2002-01-03 18:18:45 +00:00
|
|
|
qfglVertex3fv (v);
|
|
|
|
}
|
|
|
|
qfglEnd ();
|
|
|
|
}
|
2001-09-09 21:27:09 +00:00
|
|
|
}
|
|
|
|
}
|
2002-01-03 18:18:45 +00:00
|
|
|
qfglColor3ubv (color_white);
|
|
|
|
qfglEnable (GL_TEXTURE_2D);
|
2001-09-09 21:27:09 +00:00
|
|
|
}
|
2001-05-11 01:01:27 +00:00
|
|
|
}
|