mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
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:
parent
761a7546dd
commit
0ea15c3f82
5 changed files with 652 additions and 24 deletions
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue