quakeforge/libs/video/renderer/gl/gl_fisheye.c

182 lines
4.4 KiB
C
Raw Normal View History

/*
gl_fisheye.c
GL fisheye rendering
Copyright (C) 2003 Arkadi Shishlov <arkadi@it.lv>
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
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
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "QF/cvar.h"
#include "QF/mathlib.h"
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/vid.h"
#include "QF/GL/defines.h"
#include "QF/GL/funcs.h"
#include "QF/GL/qf_draw.h"
#include "QF/GL/qf_fisheye.h"
#include "QF/GL/qf_vid.h"
#include "compat.h"
#include "r_internal.h"
#include "varrays.h"
#include "vid_gl.h"
// 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.
#define FPOLYCNT 128
struct xyz {
float x, y, z;
};
static struct xyz FisheyeLookupTbl[FPOLYCNT + 1][FPOLYCNT + 1];
//static GLint gl_cube_map_size;
static GLint gl_cube_map_step;
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_STRIPs we need next Y vertex 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);
static GLuint fisheye_grid;
void
gl_InitFisheye (void)
{
fisheye_grid = qfglGenLists (1);
}
static void
build_display_list (int width, int height, float fov)
{
int maxd = max (width, height);
gl_cube_map_step = maxd / FPOLYCNT;
R_BuildFisheyeLookup (width, height, fov * M_PI / 180.0);
qfglNewList (fisheye_grid, GL_COMPILE);
qfglDisable (GL_DEPTH_TEST);
qfglFrontFace (GL_CCW);
qfglClear (GL_COLOR_BUFFER_BIT);
for (int y = 0; y < height; y += gl_cube_map_step) {
qfglBegin (GL_QUAD_STRIP);
// quad_strip, so X is inclusive
for (int x = 0; x <= width; x += gl_cube_map_step) {
int xind = x / gl_cube_map_step;
int yind = y / gl_cube_map_step;
struct xyz *v = &FisheyeLookupTbl[xind][yind + 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 ();
}
qfglEnable (GL_DEPTH_TEST);
qfglEndList ();
CHKGLERR("build list");
}
void
gl_FisheyeScreen (framebuffer_t *fb)
{
static int pwidth = -1;
static int pheight = -1;
static float pfov = -1;
if (pwidth != r_refdef.vrect.width || pheight != r_refdef.vrect.height
|| pfov != scr_ffov) {
pwidth = r_refdef.vrect.width;
pheight = r_refdef.vrect.height;
pfov = scr_ffov;
build_display_list (pwidth, pheight, pfov);
}
gl_framebuffer_t *buffer = fb->buffer;
qfglMatrixMode (GL_PROJECTION);
qfglLoadIdentity ();
qfglOrtho (0, r_refdef.vrect.width, r_refdef.vrect.height, 0, -9999, 9999);
qfglMatrixMode (GL_MODELVIEW);
qfglLoadIdentity ();
qfglColor3ubv (color_white);
qfglEnable (GL_TEXTURE_CUBE_MAP_ARB);
qfglBindTexture (GL_TEXTURE_CUBE_MAP_ARB, buffer->color);
qfglCallList (fisheye_grid);
qfglDisable (GL_TEXTURE_CUBE_MAP_ARB);
CHKGLERR("fisheye");
}