sw and gl fisheye patches from Arkadi Shishlov (arkadi@it.lv). I don't

think /I/ can play that way (dizzy:)
This commit is contained in:
Bill Currie 2003-01-15 16:53:34 +00:00
parent 761a7546dd
commit 0ea15c3f82
5 changed files with 652 additions and 24 deletions

View file

@ -46,7 +46,7 @@ QFGL_DONT_NEED (void, glBitmap, (GLsizei width, GLsizei height, GLfloat xorig, G
QFGL_DONT_NEED (void, glBlendColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
QFGL_DONT_NEED (void, glBlendEquation, (GLenum mode))
QFGL_NEED (void, glBlendFunc, (GLenum sfactor, GLenum dfactor))
QFGL_DONT_NEED (void, glCallList, (GLuint list))
QFGL_NEED (void, glCallList, (GLuint list))
QFGL_DONT_NEED (void, glCallLists, (GLsizei n, GLenum type, const GLvoid * lists))
QFGL_NEED (void, glClear, (GLbitfield mask))
QFGL_NEED (void, glClearAccum, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
@ -108,10 +108,10 @@ QFGL_DONT_NEED (void, glCopyPixels, (GLint x, GLint y, GLsizei width, GLsizei he
QFGL_DONT_NEED (void, glCopyTexImage1D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border))
QFGL_DONT_NEED (void, glCopyTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border))
QFGL_DONT_NEED (void, glCopyTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width))
QFGL_DONT_NEED (void, glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height))
QFGL_NEED (void, glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height))
QFGL_DONT_NEED (void, glCopyTexSubImage3D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height))
QFGL_NEED (void, glCullFace, (GLenum mode))
QFGL_DONT_NEED (void, glDeleteLists, (GLuint list, GLsizei range))
QFGL_NEED (void, glDeleteLists, (GLuint list, GLsizei range))
QFGL_NEED (void, glDeleteTextures, (GLsizei n, const GLuint * textures))
QFGL_NEED (void, glDepthFunc, (GLenum func))
QFGL_NEED (void, glDepthMask, (GLboolean flag))
@ -151,8 +151,8 @@ QFGL_DONT_NEED (void, glFogi, (GLenum pname, GLint param))
QFGL_DONT_NEED (void, glFogiv, (GLenum pname, const GLint * params))
QFGL_DONT_NEED (void, glFrontFace, (GLenum mode))
QFGL_NEED (void, glFrustum, (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val))
QFGL_DONT_NEED (GLuint, glGenLists, (GLsizei range))
QFGL_DONT_NEED (void, glGenTextures, (GLsizei n, GLuint * textures))
QFGL_NEED (GLuint, glGenLists, (GLsizei range))
QFGL_NEED (void, glGenTextures, (GLsizei n, GLuint * textures))
QFGL_DONT_NEED (void, glGetBooleanv, (GLenum pname, GLboolean * params))
QFGL_DONT_NEED (void, glGetClipPlane, (GLenum plane, GLdouble * equation))
QFGL_DONT_NEED (void, glGetColorTable, (GLenum target, GLenum format, GLenum type, GLvoid * table))
@ -162,7 +162,7 @@ QFGL_DONT_NEED (void, glGetConvolutionFilter, (GLenum target, GLenum format, GLe
QFGL_DONT_NEED (void, glGetConvolutionParameterfv, (GLenum target, GLenum pname, GLfloat * params))
QFGL_DONT_NEED (void, glGetConvolutionParameteriv, (GLenum target, GLenum pname, GLint * params))
QFGL_DONT_NEED (void, glGetDoublev, (GLenum pname, GLdouble * params))
QFGL_DONT_NEED (GLenum, glGetError, (void))
QFGL_NEED (GLenum, glGetError, (void))
QFGL_NEED (void, glGetFloatv, (GLenum pname, GLfloat * params))
QFGL_DONT_NEED (void, glGetHistogram, (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid * values))
QFGL_DONT_NEED (void, glGetHistogramParameterfv, (GLenum target, GLenum pname, GLfloat * params))
@ -246,7 +246,7 @@ QFGL_NEED (void, glMatrixMode, (GLenum mode))
QFGL_DONT_NEED (void, glMinmax, (GLenum target, GLenum internalformat, GLboolean sink))
QFGL_DONT_NEED (void, glMultMatrixd, (const GLdouble * m))
QFGL_DONT_NEED (void, glMultMatrixf, (const GLfloat * m))
QFGL_DONT_NEED (void, glNewList, (GLuint list, GLenum mode))
QFGL_NEED (void, glNewList, (GLuint list, GLenum mode))
QFGL_DONT_NEED (void, glNormal3b, (GLbyte nx, GLbyte ny, GLbyte nz))
QFGL_DONT_NEED (void, glNormal3bv, (const GLbyte * v))
QFGL_DONT_NEED (void, glNormal3d, (GLdouble nx, GLdouble ny, GLdouble nz))
@ -347,7 +347,7 @@ QFGL_DONT_NEED (void, glTexCoord2s, (GLshort s, GLshort t))
QFGL_DONT_NEED (void, glTexCoord2sv, (const GLshort * v))
QFGL_DONT_NEED (void, glTexCoord3d, (GLdouble s, GLdouble t, GLdouble r))
QFGL_DONT_NEED (void, glTexCoord3dv, (const GLdouble * v))
QFGL_DONT_NEED (void, glTexCoord3f, (GLfloat s, GLfloat t, GLfloat r))
QFGL_NEED (void, glTexCoord3f, (GLfloat s, GLfloat t, GLfloat r))
QFGL_DONT_NEED (void, glTexCoord3fv, (const GLfloat * v))
QFGL_DONT_NEED (void, glTexCoord3i, (GLint s, GLint t, GLint r))
QFGL_DONT_NEED (void, glTexCoord3iv, (const GLint * v))
@ -370,14 +370,14 @@ QFGL_DONT_NEED (void, glTexGend, (GLenum coord, GLenum pname, GLdouble param))
QFGL_DONT_NEED (void, glTexGendv, (GLenum coord, GLenum pname, const GLdouble * params))
QFGL_DONT_NEED (void, glTexGenf, (GLenum coord, GLenum pname, GLfloat param))
QFGL_DONT_NEED (void, glTexGenfv, (GLenum coord, GLenum pname, const GLfloat * params))
QFGL_DONT_NEED (void, glTexGeni, (GLenum coord, GLenum pname, GLint param))
QFGL_NEED (void, glTexGeni, (GLenum coord, GLenum pname, GLint param))
QFGL_DONT_NEED (void, glTexGeniv, (GLenum coord, GLenum pname, const GLint * params))
QFGL_DONT_NEED (void, glTexImage1D, (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid * pixels))
QFGL_NEED (void, glTexImage2D, (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels))
QFGL_DONT_NEED (void, glTexImage3D, (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * pixels))
QFGL_NEED (void, glTexParameterf, (GLenum target, GLenum pname, GLfloat param))
QFGL_NEED (void, glTexParameterfv, (GLenum target, GLenum pname, const GLfloat * params))
QFGL_DONT_NEED (void, glTexParameteri, (GLenum target, GLenum pname, GLint param))
QFGL_NEED (void, glTexParameteri, (GLenum target, GLenum pname, GLint param))
QFGL_DONT_NEED (void, glTexParameteriv, (GLenum target, GLenum pname, const GLint * params))
QFGL_DONT_NEED (void, glTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid * pixels))
QFGL_NEED (void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * pixels))
@ -388,7 +388,7 @@ QFGL_DONT_NEED (void, glVertex2d, (GLdouble x, GLdouble y))
QFGL_DONT_NEED (void, glVertex2dv, (const GLdouble * v))
QFGL_NEED (void, glVertex2f, (GLfloat x, GLfloat y))
QFGL_NEED (void, glVertex2fv, (const GLfloat * v))
QFGL_DONT_NEED (void, glVertex2i, (GLint x, GLint y))
QFGL_NEED (void, glVertex2i, (GLint x, GLint y))
QFGL_DONT_NEED (void, glVertex2iv, (const GLint * v))
QFGL_DONT_NEED (void, glVertex2s, (GLshort x, GLshort y))
QFGL_DONT_NEED (void, glVertex2sv, (const GLshort * v))

View file

@ -90,6 +90,9 @@ extern struct cvar_s *scr_centertime;
extern struct cvar_s *scr_consize;
extern struct cvar_s *scr_conspeed;
extern struct cvar_s *scr_fov;
extern struct cvar_s *scr_fisheye;
extern struct cvar_s *scr_fviews;
extern struct cvar_s *scr_ffov;
extern struct cvar_s *scr_printspeed;
extern struct cvar_s *scr_showpause;
extern struct cvar_s *scr_showram;

View file

@ -66,6 +66,8 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "r_local.h"
#include "view.h"
#include "GL/gl.h"
entity_t r_worldentity;
qboolean r_cache_thrash; // compatability
@ -305,17 +307,16 @@ MYgluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear,
xmin = ymin * aspect;
xmax = -xmin;
//printf ("glFrustum (%f, %f, %f, %f)\n", xmin, xmax, ymin, ymax);
qfglFrustum (xmin, xmax, ymin, ymax, zNear, zFar);
}
static void
R_SetupGL (void)
R_SetupGL_Viewport_and_Perspective (void)
{
float screenaspect;
int x, x2, y2, y, w, h;
R_SetFrustum ();
// set up viewpoint
qfglMatrixMode (GL_PROJECTION);
qfglLoadIdentity ();
@ -343,11 +344,19 @@ R_SetupGL (void)
w = x2 - x;
h = y - y2;
}
//printf("glViewport(%d, %d, %d, %d)\n", glx + x, gly + y2, w, h);
qfglViewport (glx + x, gly + y2, w, h);
screenaspect = (float) r_refdef.vrect.width / r_refdef.vrect.height;
MYgluPerspective (r_refdef.fov_y, screenaspect, r_nearclip->value,
r_farclip->value);
}
static void
R_SetupGL (void)
{
R_SetFrustum ();
R_SetupGL_Viewport_and_Perspective ();
if (mirror) {
if (mirror_plane->normal[2])
@ -481,12 +490,12 @@ R_Mirror (void)
}
/*
R_RenderView
R_RenderView_
r_refdef must be set before the first call
*/
void
R_RenderView (void)
static void
R_RenderView_ (void)
{
if (r_norefresh->int_val)
return;
@ -511,3 +520,297 @@ R_RenderView (void)
if (r_zgraph->int_val)
R_ZGraph ();
}
// Algorithm:
// Draw up to six views, one in each direction.
// Save the picture to cube map texture, use GL_ARB_texture_cube_map.
// Create FPOLYCNTxFPOLYCNT polygons sized flat grid.
// Baseing on field of view, tie cube map texture to grid using
// translation function to map texture coordinates to fixed/regular
// grid vertices coordinates.
// Render view. Fisheye is done.
static void R_RenderViewFishEye (void);
void
R_RenderView (void)
{
if(!scr_fisheye->int_val)
R_RenderView_ ();
else
R_RenderViewFishEye ();
}
#define BOX_FRONT 0
#define BOX_RIGHT 1
#define BOX_BEHIND 2
#define BOX_LEFT 3
#define BOX_TOP 4
#define BOX_BOTTOM 5
#define FPOLYCNT 16
struct xyz {
float x, y, z;
};
static struct xyz FisheyeLookupTbl[FPOLYCNT+1][FPOLYCNT+1];
static GLuint cube_map_tex;
static GLint gl_cube_map_size;
static GLint gl_cube_map_step;
static const GLenum box2cube_map[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
};
static void
R_BuildFisheyeLookup (int width, int height, float fov)
{
int x, y;
struct xyz *v;
for (y = 0; y <= height; y += gl_cube_map_step) {
for (x = 0; x <= width; x += gl_cube_map_step) {
float dx = x - width/2;
float dy = y - height/2;
float yaw = sqrt(dx*dx+dy*dy)*fov/width;
float roll = atan2(dy, dx);
// X is a first index and Y is a second, because later
// when we draw QUAD_STRIPes we need next Y vertix coordinate.
v = &FisheyeLookupTbl[x/gl_cube_map_step][y/gl_cube_map_step];
v->x = sin(yaw) * cos(roll);
v->y = -sin(yaw) * sin(roll);
v->z = cos(yaw);
}
}
}
#define CHKGLERR(s) \
do { \
GLint err = qfglGetError(); \
if (err != GL_NO_ERROR) printf ("%s: gl error %d\n", s, (int)err); \
} while (0);
#define NO(x) \
do { \
if (x < 0) x += 360; \
else if (x >= 360) x -= 360; \
} while (0)
static void
R_RenderCubeSide (int side)
{
float pitch, n_pitch;
float yaw, n_yaw;
float roll, n_roll;
float s_roll;
pitch = n_pitch = r_refdef.viewangles[PITCH];
yaw = n_yaw = r_refdef.viewangles[YAW];
// setting ROLL for now to 0, correct roll handling
// requre more exhaustive changes in rotation
// TODO: implement via matrix
//roll = n_roll = r_refdef.viewangles[ROLL];
s_roll = r_refdef.viewangles[ROLL];
roll = n_roll = 0;
//roll -= scr_fviews->int_val*10;
//n_roll = roll;
switch (side) {
case BOX_FRONT: break;
case BOX_RIGHT:
n_pitch = roll;
n_yaw -= 90;
n_roll = -pitch;
break;
case BOX_LEFT:
n_pitch = -roll;
n_yaw += 90;
n_roll = pitch;
//static int f = 0;
//if (!(f++%100)) printf("%4d %4d %4d | %4d %4d %4d\n",
//(int)pitch, (int)yaw, (int)roll,
//(int)n_pitch, (int)n_yaw, (int)n_roll);
break;
case BOX_TOP:
n_pitch -= 90;
break;
case BOX_BOTTOM:
n_pitch += 90;
break;
case BOX_BEHIND:
n_pitch = -pitch;
n_yaw += 180;
break;
}
NO(n_pitch); NO(n_yaw); NO(n_roll);
r_refdef.viewangles[PITCH] = n_pitch;
r_refdef.viewangles[YAW] = n_yaw;
r_refdef.viewangles[ROLL] = n_roll;
R_RenderView_ ();
qfglEnable(GL_TEXTURE_CUBE_MAP_ARB);
qfglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_tex);
qfglCopyTexSubImage2D (box2cube_map[side], 0, 0, 0, 0, 0,
gl_cube_map_size, gl_cube_map_size);
//CHKGLERR ("qfglCopyTexSubImage2D");
qfglDisable(GL_TEXTURE_CUBE_MAP_ARB);
r_refdef.viewangles[PITCH] = pitch;
r_refdef.viewangles[YAW] = yaw;
r_refdef.viewangles[ROLL] = s_roll;
}
static qboolean gl_cube_map_capable = false;
static GLint gl_cube_map_maxtex;
static GLuint fisheye_grid;
static int
R_InitFishEyeOnce (void)
{
static qboolean fisheye_init_once_completed = false;
if (fisheye_init_once_completed) return 1;
Con_Printf ("GL_ARB_texture_cube_map ");
if (QFGL_ExtensionPresent ("GL_ARB_texture_cube_map")) {
qfglGetIntegerv (GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &gl_cube_map_maxtex);
Con_Printf ("present, max texture size %d.\n", (int)gl_cube_map_maxtex);
gl_cube_map_capable = true;
} else {
Con_Printf ("not found.\n");
}
fisheye_init_once_completed = true;
return 1;
}
static int
R_InitFishEye (void)
{
int width = vid.width;
int height = vid.height;
int fov = scr_ffov->int_val;
int views = scr_fviews->int_val;
static int pwidth = -1;
static int pheight = -1;
static int pfov = -1;
static int pviews = -1;
int i, x, y, min_wh, wh_changed = 0;
if (!R_InitFishEyeOnce()) return 0;
if (!gl_cube_map_capable) return 0;
// There is a problem when max texture size is bigger than
// min(width, height), it shows up as black fat stripes at the edges
// of box polygons, probably due to missing texture fragment. Try
// to play in 640x480 with gl_cube_map_size == 512.
if (pwidth != width || pheight != height) {
wh_changed = 1;
min_wh = (height < width) ? height : width;
gl_cube_map_size = gl_cube_map_maxtex;
while (gl_cube_map_size > min_wh)
gl_cube_map_size /= 2;
gl_cube_map_step = gl_cube_map_size/FPOLYCNT;
}
if (pviews != views) {
qfglEnable (GL_TEXTURE_CUBE_MAP_ARB);
if (pviews != -1)
qfglDeleteTextures (1, &cube_map_tex);
pviews = views;
qfglGenTextures (1, &cube_map_tex);
qfglBindTexture (GL_TEXTURE_CUBE_MAP_ARB, cube_map_tex);
for (i = 0; i < 6; ++i) {
qfglTexImage2D (box2cube_map[i], 0, 3, gl_cube_map_size, gl_cube_map_size,
0, GL_RGB, GL_UNSIGNED_SHORT, NULL);
}
qfglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qfglTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qfglDisable (GL_TEXTURE_CUBE_MAP_ARB);
}
if (wh_changed || pfov != fov) {
if (pfov != -1)
qfglDeleteLists (fisheye_grid, 1);
pwidth = width;
pheight = height;
pfov = fov;
R_BuildFisheyeLookup (gl_cube_map_size, gl_cube_map_size, ((float)fov)*M_PI/180.0);
fisheye_grid = qfglGenLists (1);
qfglNewList (fisheye_grid, GL_COMPILE);
qfglLoadIdentity ();
qfglTranslatef (-gl_cube_map_size/2, -gl_cube_map_size/2, -gl_cube_map_size/2);
qfglDisable (GL_DEPTH_TEST);
qfglCullFace (GL_BACK);
qfglClear (GL_COLOR_BUFFER_BIT);
qfglEnable(GL_TEXTURE_CUBE_MAP_ARB);
qfglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_tex);
qfglBegin(GL_QUAD_STRIP);
for (y = 0; y < gl_cube_map_size; y += gl_cube_map_step) {
for (x = 0; x <= gl_cube_map_size; x += gl_cube_map_step) { // quad_strip, X should be inclusive
struct xyz *v = &FisheyeLookupTbl[x/gl_cube_map_step][y/gl_cube_map_step+1];
qfglTexCoord3f (v->x, v->y, v->z); qfglVertex2i (x, y+gl_cube_map_step);
--v;
qfglTexCoord3f (v->x, v->y, v->z); qfglVertex2i (x, y);
}
}
qfglEnd ();
qfglDisable (GL_TEXTURE_CUBE_MAP_ARB);
qfglEnable (GL_DEPTH_TEST);
qfglEndList ();
}
return 1;
}
static void
R_RenderViewFishEye (void)
{
float s_fov_x, s_fov_y;
int s_vid_w, s_vid_h, s_rect_w, s_rect_h, s_gl_w, s_gl_h;
if (!R_InitFishEye()) return;
// save values
s_fov_x = r_refdef.fov_x;
s_fov_y = r_refdef.fov_y;
s_vid_w = vid.width;
s_vid_h = vid.height;
s_rect_w = r_refdef.vrect.width;
s_rect_h = r_refdef.vrect.height;
s_gl_w = glwidth;
s_gl_h = glheight;
// the view should be square
r_refdef.fov_x = r_refdef.fov_y = 90;
vid.width = vid.height =
r_refdef.vrect.height = r_refdef.vrect.width =
glwidth = glheight = gl_cube_map_size;
switch (scr_fviews->int_val) {
case 6: R_RenderCubeSide (BOX_BEHIND);
case 5: R_RenderCubeSide (BOX_BOTTOM);
case 4: R_RenderCubeSide (BOX_TOP);
case 3: R_RenderCubeSide (BOX_LEFT);
case 2: R_RenderCubeSide (BOX_RIGHT);
default: R_RenderCubeSide (BOX_FRONT);
}
// restore
r_refdef.fov_x = s_fov_x;
r_refdef.fov_y = s_fov_y;
vid.width = s_vid_w;
vid.height = s_vid_h;
r_refdef.vrect.width = s_rect_w;
r_refdef.vrect.height = s_rect_h;
glwidth = s_gl_w;
glheight = s_gl_h;
R_SetupGL_Viewport_and_Perspective ();
qfglMatrixMode (GL_MODELVIEW);
qfglCallList (fisheye_grid);
}

View file

@ -131,6 +131,9 @@ cvar_t *scr_centertime;
cvar_t *scr_consize;
cvar_t *scr_conspeed;
cvar_t *scr_fov;
cvar_t *scr_fisheye;
cvar_t *scr_fviews;
cvar_t *scr_ffov;
cvar_t *scr_printspeed;
cvar_t *scr_showpause;
cvar_t *scr_showram;
@ -193,6 +196,24 @@ r_particles_nearclip_f (cvar_t *var)
r_farclip->value));
}
static void
scr_fisheye_f (cvar_t *var)
{
if (var->int_val)
Cvar_Set (scr_fov, "90");
}
static void
scr_ffov_f (cvar_t *var)
{
if (var->value < 130)
Cvar_Set (scr_fviews, "3");
else if (var->value < 220)
Cvar_Set (scr_fviews, "5");
else
Cvar_Set (scr_fviews, "6");
}
void
R_Init_Cvars (void)
{
@ -355,7 +376,7 @@ R_Init_Cvars (void)
"Toggles drawing of particles.");
r_particles_max = Cvar_Get ("r_particles_max", "2048", CVAR_ARCHIVE,
r_particles_max_f, "Maximum amount of "
"particles to display. No maximum, minimum "
"particles to display. No maximum, minimum "
"is 0.");
r_particles_nearclip = Cvar_Get ("r_particles_nearclip", "32",
CVAR_ARCHIVE, r_particles_nearclip_f,
@ -396,7 +417,14 @@ R_Init_Cvars (void)
scr_conspeed = Cvar_Get ("scr_conspeed", "300", CVAR_NONE, NULL,
"How quickly the console scrolls up or down");
scr_fov = Cvar_Get ("fov", "90", CVAR_NONE, NULL, "Your field of view in "
"degrees. Smaller than 90 zooms in.");
"degrees. Smaller than 90 zooms in. Don't touch in "
"fisheye mode, use ffov instead.");
scr_fisheye = Cvar_Get ("fisheye", "0", CVAR_NONE, scr_fisheye_f,
"Toggles fisheye mode.");
scr_fviews = Cvar_Get ("fviews", "6", CVAR_NONE, NULL, "The number of "
"fisheye views.");
scr_ffov = Cvar_Get ("ffov", "180", CVAR_NONE, scr_ffov_f, "Your field of "
"view in degrees in fisheye mode.");
scr_printspeed = Cvar_Get ("scr_printspeed", "8", CVAR_NONE, NULL,
"How fast the text is displayed at the end of "
"the single player episodes");

View file

@ -37,6 +37,9 @@ static __attribute__ ((unused)) const char rcsid[] =
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <math.h>
@ -326,11 +329,11 @@ R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect)
r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
r_refdef.aliasvrect.height;
pixelAspect = aspect;
pixelAspect = (float)r_refdef.vrect.height/(float)r_refdef.vrect.width;
xOrigin = r_refdef.xOrigin;
yOrigin = r_refdef.yOrigin;
screenAspect = r_refdef.vrect.width * pixelAspect / r_refdef.vrect.height;
screenAspect = 1.0;
// 320*200 1.0 pixelAspect = 1.6 screenAspect
// 320*240 1.0 pixelAspect = 1.3333 screenAspect
// proper 320*200 pixelAspect = 0.8333333
@ -742,7 +745,7 @@ R_DrawBEntitiesOnList (void)
r_clipflags = clipflags;
R_DrawSolidClippedSubmodelPolygons (clmodel);
} else {
// falls entirely in one leaf, so we just put
// falls entirely in one leaf, so we just put
// all the edges in the edge list and let 1/z
// sorting handle drawing order
R_DrawSubmodelPolygons (clmodel, clipflags);
@ -930,6 +933,8 @@ R_RenderView_ (void)
R_HighFPPrecision ();
}
static void R_RenderViewFishEye (void);
void
R_RenderView (void)
{
@ -949,7 +954,10 @@ R_RenderView (void)
if ((long) (&r_warpbuffer) & 3)
Sys_Error ("Globals are missaligned");
R_RenderView_ ();
if (!scr_fisheye->int_val)
R_RenderView_ ();
else
R_RenderViewFishEye ();
}
void
@ -963,3 +971,289 @@ R_InitTurb (void)
// AMP2 not 20
}
}
#define BOX_FRONT 0
#define BOX_BEHIND 2
#define BOX_LEFT 3
#define BOX_RIGHT 1
#define BOX_TOP 4
#define BOX_BOTTOM 5
#define DEG(x) (x / M_PI * 180.0)
#define RAD(x) (x * M_PI / 180.0)
struct my_coords
{
double x, y, z;
};
struct my_angles
{
double yaw, pitch, roll;
};
static void
x_rot (struct my_coords *c, double pitch)
{
double nx, ny, nz;
nx = c->x;
ny = (c->y * cos(pitch)) - (c->z * sin(pitch));
nz = (c->y * sin(pitch)) + (c->z * cos(pitch));
c->x = nx; c->y = ny; c->z = nz;
}
static void
y_rot (struct my_coords *c, double yaw)
{
double nx, ny, nz;
nx = (c->x * cos(yaw)) - (c->z * sin(yaw));
ny = c->y;
nz = (c->x * sin(yaw)) + (c->z * cos(yaw));
c->x = nx; c->y = ny; c->z = nz;
}
static void
z_rot (struct my_coords *c, double roll)
{
double nx, ny, nz;
nx = (c->x * cos(roll)) - (c->y * sin(roll));
ny = (c->x * sin(roll)) + (c->y * cos(roll));
nz = c->z;
c->x = nx; c->y = ny; c->z = nz;
}
static void
my_get_angles (struct my_coords *in_o, struct my_coords *in_u, struct my_angles *a)
{
double rad_yaw, rad_pitch;
struct my_coords o, u;
a->pitch = 0.0;
a->yaw = 0.0;
a->roll = 0.0;
// make a copy of the coords
o.x = in_o->x; o.y = in_o->y; o.z = in_o->z;
u.x = in_u->x; u.y = in_u->y; u.z = in_u->z;
// special case when looking straight up or down
if ((o.x == 0.0) && (o.z == 0.0)) {
a->yaw = 0.0;
if (o.y > 0.0) { a->pitch = -90.0; a->roll = 180.0 - DEG(atan2(u.x, u.z)); } // down
else { a->pitch = 90.0; a->roll = DEG(atan2(u.x, u.z)); } // up
return;
}
// get yaw angle and then rotate o and u so that yaw = 0
rad_yaw = atan2 (-o.x, o.z);
a->yaw = DEG (rad_yaw);
y_rot (&o, -rad_yaw);
y_rot (&u, -rad_yaw);
// get pitch and then rotate o and u so that pitch = 0
rad_pitch = atan2 (-o.y, o.z);
a->pitch = DEG (rad_pitch);
x_rot (&o, -rad_pitch);
x_rot (&u, -rad_pitch);
// get roll
a->roll = DEG (-atan2(u.x, u.y));
}
static void
get_ypr (double yaw, double pitch, double roll, int side, struct my_angles *a)
{
struct my_coords o, u;
// get 'o' (observer) and 'u' ('this_way_up') depending on box side
switch(side) {
case BOX_FRONT:
o.x = 0.0; o.y = 0.0; o.z = 1.0;
u.x = 0.0; u.y = 1.0; u.z = 0.0;
break;
case BOX_BEHIND:
o.x = 0.0; o.y = 0.0; o.z = -1.0;
u.x = 0.0; u.y = 1.0; u.z = 0.0;
break;
case BOX_LEFT:
o.x = -1.0; o.y = 0.0; o.z = 0.0;
u.x = -1.0; u.y = 1.0; u.z = 0.0;
break;
case BOX_RIGHT:
o.x = 1.0; o.y = 0.0; o.z = 0.0;
u.x = 0.0; u.y = 1.0; u.z = 0.0;
break;
case BOX_TOP:
o.x = 0.0; o.y = -1.0; o.z = 0.0;
u.x = 0.0; u.y = 0.0; u.z = -1.0;
break;
case BOX_BOTTOM:
o.x = 0.0; o.y = 1.0; o.z = 0.0;
u.x = 0.0; u.y = 0.0; u.z = -1.0;
break;
}
z_rot (&o, roll); z_rot (&u, roll);
x_rot (&o, pitch); x_rot (&u, pitch);
y_rot (&o, yaw); y_rot (&u, yaw);
my_get_angles (&o, &u, a);
// normalise angles
while (a->yaw < 0.0) a->yaw += 360.0;
while (a->yaw > 360.0) a->yaw -= 360.0;
while (a->pitch < 0.0) a->pitch += 360.0;
while (a->pitch > 360.0) a->pitch -= 360.0;
while (a->roll < 0.0) a->roll += 360.0;
while (a->roll > 360.0) a->roll -= 360.0;
}
static void
fisheyelookuptable (byte **buf, int width, int height, byte *scrp, double fov)
{
int x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
double dx = x-width/2;
double dy = -(y-height/2);
double yaw = sqrt(dx*dx+dy*dy)*fov/((double)width);
double roll = -atan2(dy, dx);
double sx = sin(yaw) * cos(roll);
double sy = sin(yaw) * sin(roll);
double sz = cos(yaw);
// determine which side of the box we need
double abs_x = fabs(sx);
double abs_y = fabs(sy);
double abs_z = fabs(sz);
int side;
double xs = 0, ys = 0;
if (abs_x > abs_y) {
if (abs_x > abs_z) { side = ((sx > 0.0) ? BOX_RIGHT : BOX_LEFT); }
else { side = ((sz > 0.0) ? BOX_FRONT : BOX_BEHIND); }
} else {
if (abs_y > abs_z) { side = ((sy > 0.0) ? BOX_TOP : BOX_BOTTOM); }
else { side = ((sz > 0.0) ? BOX_FRONT : BOX_BEHIND); }
}
#define RC(x) ((x / 2.06) + 0.5)
#define R2(x) ((x / 2.03) + 0.5)
// scale up our vector [x,y,z] to the box
switch(side) {
case BOX_FRONT: xs = RC( sx / sz); ys = R2( sy / sz); break;
case BOX_BEHIND: xs = RC(-sx / -sz); ys = R2( sy / -sz); break;
case BOX_LEFT: xs = RC( sz / -sx); ys = R2( sy / -sx); break;
case BOX_RIGHT: xs = RC(-sz / sx); ys = R2( sy / sx); break;
case BOX_TOP: xs = RC( sx / sy); ys = R2( sz / -sy); break; //bot
case BOX_BOTTOM: xs = RC(-sx / sy); ys = R2( sz / -sy); break; //top??
}
if (xs < 0.0) xs = 0.0;
if (xs >= 1.0) xs = 0.999;
if (ys < 0.0) ys = 0.0;
if (ys >= 1.0) ys = 0.999;
*buf++ = scrp+(((int)(xs*(double)width))+
((int)(ys*(double)height))*width)+
side*width*height;
}
}
}
static void
rendercopy (void *dest)
{
void *p = vid.buffer;
// XXX
vid.buffer = dest;
R_RenderView_ ();
vid.buffer = p;
}
static void
renderside (byte* bufs, double yaw, double pitch, double roll, int side)
{
struct my_angles a;
get_ypr (RAD(yaw), RAD(pitch), RAD(roll), side, &a);
if (side == BOX_RIGHT) { a.roll = -a.roll; a.pitch = -a.pitch; }
if (side == BOX_LEFT) { a.roll = -a.roll; a.pitch = -a.pitch; }
if (side == BOX_TOP) { a.yaw += 180.0; a.pitch = 180.0 - a.pitch; }
r_refdef.viewangles[YAW] = a.yaw;
r_refdef.viewangles[PITCH] = a.pitch;
r_refdef.viewangles[ROLL] = a.roll;
rendercopy (bufs);
}
static void
renderlookup (byte **offs, byte* bufs)
{
byte *p = (byte*)vid.buffer;
int x, y;
for (y = 0; y < vid.height; y++) {
for (x = 0; x < vid.width; x++, offs++)
p[x] = **offs;
p += vid.rowbytes;
}
}
static void
R_RenderViewFishEye (void)
{
int width = vid.width; //r_refdef.vrect.width;
int height = vid.height; //r_refdef.vrect.height;
int scrsize = width*height;
int fov = scr_ffov->int_val;
int views = scr_fviews->int_val;
double yaw = r_refdef.viewangles[YAW];
double pitch = r_refdef.viewangles[PITCH];
double roll = 0; //r_refdef.viewangles[ROLL];
static int pwidth = -1;
static int pheight = -1;
static int pfov = -1;
static int pviews = -1;
static byte *scrbufs = NULL;
static byte **offs = NULL;
if (fov < 1) fov = 1;
if (pwidth != width || pheight != height || pfov != fov) {
if (scrbufs) free (scrbufs);
if (offs) free (offs);
scrbufs = malloc (scrsize*6); // front|right|back|left|top|bottom
SYS_CHECKMEM (scrbufs);
offs = malloc (scrsize*sizeof(byte*));
SYS_CHECKMEM (offs);
pwidth = width;
pheight = height;
pfov = fov;
fisheyelookuptable (offs, width, height, scrbufs, ((double)fov)*M_PI/180.0);
}
if (views != pviews) {
pviews = views;
memset (scrbufs, 0, scrsize*6);
}
switch (views) {
case 6: renderside (scrbufs+scrsize*2, yaw, pitch, roll, BOX_BEHIND);
case 5: renderside (scrbufs+scrsize*5, yaw, pitch, roll, BOX_BOTTOM);
case 4: renderside (scrbufs+scrsize*4, yaw, pitch, roll, BOX_TOP);
case 3: renderside (scrbufs+scrsize*3, yaw, pitch, roll, BOX_LEFT);
case 2: renderside (scrbufs+scrsize, yaw, pitch, roll, BOX_RIGHT);
default: renderside (scrbufs, yaw, pitch, roll, BOX_FRONT);
}
r_refdef.viewangles[YAW] = yaw;
r_refdef.viewangles[PITCH] = pitch;
r_refdef.viewangles[ROLL] = roll;
renderlookup (offs, scrbufs);
}