mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 12:52:46 +00:00
20a2e7e06f
Again, gl/vulkan not working yet (on the assumption that sw would be trickier). Fisheye overrides water warp because updating the projection map every frame is far too expensive. I've added a post-process pass to the interface in order to hide the implementation details, but I'm not sure I'm happy about how the multi-pass rendering for cube maps is handled (or having the frame buffers as exposed as they are), but mainly because Vulkan will make implementation interesting.
166 lines
4.2 KiB
C
166 lines
4.2 KiB
C
/*
|
|
sw_fisheye.c
|
|
|
|
SW 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
|
|
#ifdef HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
#endif
|
|
|
|
#include <math.h>
|
|
|
|
#include "QF/cvar.h"
|
|
#include "QF/render.h"
|
|
|
|
#include "compat.h"
|
|
#include "r_internal.h"
|
|
#include "vid_internal.h"
|
|
#include "vid_sw.h"
|
|
|
|
static void
|
|
fisheyelookuptable (byte **buf, int width, int height, framebuffer_t *cube,
|
|
double fov)
|
|
{
|
|
int cube_size = cube->width;
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
double dx = x - width / 2;
|
|
double dy = -(y - height / 2);
|
|
double yaw = sqrt (dx * dx + dy * dy) * fov / 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) + 0.5)
|
|
#define R2(x) ((x / 2) + 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;
|
|
case BOX_BOTTOM: xs = RC( sx / -sy); ys = R2( sz / sy); break;
|
|
}
|
|
|
|
xs = bound (0, xs, 1);
|
|
ys = bound (0, ys, 1);
|
|
int sxs = xs * (cube_size - 1);
|
|
int sys = ys * (cube_size - 1);
|
|
sw_framebuffer_t *fb = cube[side].buffer;
|
|
*buf++ = fb->color + sys * fb->rowbytes + sxs;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
renderlookup (byte **offs)
|
|
{
|
|
framebuffer_t *fb = sw_ctx->framebuffer;
|
|
sw_framebuffer_t *swfb = fb->buffer;
|
|
byte *p = swfb->color;
|
|
unsigned x, y;
|
|
for (y = 0; y < fb->height; y++) {
|
|
for (x = 0; x < fb->width; x++, offs++)
|
|
p[x] = **offs;
|
|
p += swfb->rowbytes;
|
|
}
|
|
}
|
|
|
|
void
|
|
R_RenderFisheye (framebuffer_t *cube)
|
|
{
|
|
int width = r_refdef.vrect.width;
|
|
int height = r_refdef.vrect.height;
|
|
int fov = scr_ffov->int_val;
|
|
static int pwidth = -1;
|
|
static int pheight = -1;
|
|
static int pfov = -1;
|
|
static unsigned psize = -1;
|
|
static byte **offs = NULL;
|
|
|
|
if (fov < 1) fov = 1;
|
|
|
|
if (pwidth != width || pheight != height || pfov != fov
|
|
|| psize != cube->width) {
|
|
if (offs) free (offs);
|
|
offs = malloc (width*height*sizeof(byte*));
|
|
SYS_CHECKMEM (offs);
|
|
pwidth = width;
|
|
pheight = height;
|
|
pfov = fov;
|
|
psize = cube->width;
|
|
fisheyelookuptable (offs, width, height, cube, fov*M_PI/180.0);
|
|
}
|
|
#if 0
|
|
sw_framebuffer_t *fb = cube[0].buffer;
|
|
int rowbytes = fb->rowbytes;
|
|
int csize = cube[0].width;
|
|
for (int s = 0; s < 6; s++) {
|
|
fb = cube[s].buffer;
|
|
memset (fb->color, 31, csize);
|
|
memset (fb->color + (csize - 1) * rowbytes, 31, csize);
|
|
for (int y = 0; y < csize; y++) {
|
|
fb->color[y * rowbytes] = 31;
|
|
fb->color[y * rowbytes + csize - 1] = 31;
|
|
}
|
|
}
|
|
#endif
|
|
renderlookup (offs);
|
|
}
|