WinUAE/od-win32/hq2x_d3d.cpp
2022-04-28 21:34:35 +03:00

204 lines
8.6 KiB
C++

/*
* Hq2x scaler pixel shader version support code by Mitja Gros (Mitja.Gros@gmail.com)
*
* Original OpenGL-HQ rendering code
* Copyright (C) 2004-2005 Jörg Walter <jwalt@garni.ch>
*
* 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 the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hq2x_d3d.h"
#include <math.h>
#define fmax(x,y) ((x)>(y)?(x):(y))
#define fmin(x,y) ((x)<(y)?(x):(y))
#define R 1
#define T 2
#define RT 4
#define RT2 8
#define L 16
#define LB2 32
#define LT2 64
#define LT 128
#define LB 256
#define B 512
#define RB2 1024
#define RB 2048
#define NODIAG 0x90
#define H 1
#define V 2
#define D 4
#define hmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,R,L),RT,LT),RT2,LT2),RB,LB),RB2,LB2)
#define vmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,T,B),RT,RB),RT2,RB2),LT,LB),LT2,LB2)
#define NO_BORDER(x) ((b&(x)) == 0)
#define IS_BORDER(x) ((b&(x)) == (x))
#define SETINTERP(percentage_inside) setinterp(xcenter,ycenter,percentage_inside, \
NO_BORDER(R),NO_BORDER(T),NO_BORDER(RT), \
IS_BORDER(R),IS_BORDER(T),IS_BORDER(RT), \
texture+((x+(border%16)*HQ2X_RESOLUTION+y*16*HQ2X_RESOLUTION+(border&~15)*HQ2X_RESOLUTION*HQ2X_RESOLUTION)*4))
static float sign(float a) {
return (a < 0.0f ? -1.0f : 1.0f);
}
/*
This function calculates what percentage of a rectangle intersected by a line lies near the center of the
cordinate system. It is mathematically exact, and well-tested for xcenter > 0 and ycenter > 0 (it's only
used that way). It should be correct for other cases as well, but well... famous last words :)
*/
static float intersect_any(float xcenter, float ycenter, float xsize, float ysize, float yoffset, float gradient) {
float g = (float)fabs(gradient)*xsize/ysize;
float o = -((yoffset-ycenter) + gradient*xcenter)/ysize*sign(ycenter)*sign(yoffset)-g*0.5f+0.5f;
float yl = o, yr = o+g, xb = -o/g, xt = (1-o)/g;
float area = 1.0;
if (yl >= 1.0) xt = xb = area = 0.0;
else if (yl > 0.0) {
area = 1.0f-yl;
xb = 0.0;
}
else if (yr <= 0.0) yl = yr = area = 1.0;
else yl = o+xb*g;
if (xt <= 0.0) yr = yl = area = 0.0;
else if (xt < 1.0) {
area *= xt;
yr = 1.0;
}
else if (xb >= 1.0) xb = xt = area = 1.0;
else xt = (yr-o)/g;
area -= (xt-xb)*(yr-yl)/2;
return area;
}
static float intersect_h(float xcenter, float ycenter, float xsize, float ysize) {
return (float)fmax(0.0f,fmin(1.0f,(0.55f-fabs(xcenter)+xsize/2.0f)/xsize));
}
static float intersect_any_h(float xcenter, float ycenter, float xsize, float ysize, float yoffset, float gradient) {
float hinside = intersect_h(xcenter,ycenter,xsize,ysize);
return hinside*hinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
}
static float intersect_v(float xcenter, float ycenter, float xsize, float ysize) {
return (float)fmax(0.0f,fmin(1.0f,(0.55f-fabs(ycenter)+ysize/2.0f)/ysize));
}
static float intersect_any_v(float xcenter, float ycenter, float xsize, float ysize, float yoffset, float gradient) {
float vinside = intersect_v(xcenter,ycenter,xsize,ysize);
return vinside*vinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
}
static float intersect_hv(float xcenter, float ycenter, float xsize, float ysize) {
float hinside = intersect_h(xcenter,ycenter,xsize,ysize);
float vinside = intersect_v(xcenter,ycenter,xsize,ysize);
return (1-hinside)*(1-vinside)+hinside*vinside;
}
/* FIXME: not sure if this is correct, but it is rare enough and most likely near enough. fixes welcome :) */
static float intersect_any_hv(float xcenter, float ycenter, float xsize, float ysize, float yoffset, float gradient) {
float hvinside = intersect_hv(xcenter,ycenter,xsize,ysize);
return hvinside*hvinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
}
static float intersect_hvd(float xcenter, float ycenter, float xsize, float ysize) {
return intersect_h(xcenter,ycenter,xsize,ysize)*intersect_v(xcenter,ycenter,xsize,ysize);
}
static void setinterp(float xcenter, float ycenter, float percentage_inside, int i1, int i2, int i3, int o1, int o2, int o3, unsigned char *factors) {
float d0, d1, d2, d3, percentage_outside, totaldistance_i, totaldistance_o;
xcenter = (float)fabs(xcenter);
ycenter = (float)fabs(ycenter);
d0 = (1-xcenter)*(1-ycenter);
d1 = xcenter*(1-ycenter);
d2 = (1-xcenter)*ycenter;
d3 = xcenter*ycenter;
if (i1 && i2) i3 = 0;
if (o1 && o2) o3 = 0;
percentage_outside = 1.0f-percentage_inside;
totaldistance_i = d0+i1*d1+i2*d2+i3*d3;
totaldistance_o = o1*d1+o2*d2+o3*d3+1e-12f; /* +1e-12: prevent division by zero */
factors[1] = (unsigned char)(((d1/totaldistance_i*percentage_inside*i1)+(d1/totaldistance_o*percentage_outside*o1))*255+.5);
factors[2] = (unsigned char)(((d2/totaldistance_i*percentage_inside*i2)+(d2/totaldistance_o*percentage_outside*o2))*255+.5);
factors[3] = (unsigned char)(((d3/totaldistance_i*percentage_inside*i3)+(d3/totaldistance_o*percentage_outside*o3))*255+.5);
factors[0] = 255-factors[1]-factors[2]-factors[3];/*(unsigned char)((d0/totaldistance_i*percentage_inside)*255+.5);*/
}
/* Wanna have gcc fun? #define this as a macro, get a fast machine and go fetch a coffe or two. See how it is used to get an idea why.
I aborted compilation after 5 minutes of CPU time on an Athlon64 3700+. */
static int swap_bits(int num, int bit1, int bit2) {
return ((num & ~(bit1|bit2))|((num&bit1)?bit2:0)|((num&bit2)?bit1:0));
}
// width, height == rwidth, rheight
// outwidth, outheight == width, height
void BuildHq2xLookupTexture(int outWidth, int outHeight, int rwidth, int rheight, unsigned char* texture)
{
float xsize, ysize;
int border, y, x;
unsigned char table[4096] = HQ2X_D3D_TABLE_DATA;
xsize = (float)rwidth / (float)outWidth;
ysize = (float)rheight / (float)outHeight;
for (border = 0; border < 4096; border++) {
for (y = 0; y < HQ2X_RESOLUTION; y++) {
for (x = 0; x < HQ2X_RESOLUTION; x++) {
float xcenter = (float)(fabs((((float)x)+0.5f) / (float)(HQ2X_RESOLUTION)-0.5f)/0.958f);
float ycenter = (float)(fabs((((float)y)+0.5f) / (float)(HQ2X_RESOLUTION)-0.5f)/0.958f);
int sx = (x < HQ2X_RESOLUTION/2?-1:1);
int sy = (y < HQ2X_RESOLUTION/2?-1:1);
int b = (sy > 0?(sx > 0?border:hmirror(border)):(sx > 0?vmirror(border):vmirror(hmirror(border))));
if ((table[b] & NODIAG) == NODIAG) {
if (table[b] & H) {
if (table[b] & V) {
if (table[b] & D) SETINTERP(intersect_hvd(xcenter,ycenter,xsize,ysize));
else SETINTERP(intersect_hv(xcenter,ycenter,xsize,ysize));
} else {
SETINTERP(intersect_h(xcenter,ycenter,xsize,ysize));
}
} else if (table[b] & V) {
SETINTERP(intersect_v(xcenter,ycenter,xsize,ysize));
} else {
SETINTERP(1.0);
}
} else {
float yoff = (float)((table[b]&4?1:-1)*(((table[b] >> 3) & 3) + 1.0f)/4.0f);
float grad = (float)((table[b]&32?1:-1)*(((table[b] >> 6) & 3) + 1.0f)/2.0f);
if (table[b] & H) {
if (table[b] & V) {
SETINTERP(intersect_any_hv(xcenter,ycenter,xsize,ysize,yoff,grad));
} else {
SETINTERP(intersect_any_h(xcenter,ycenter,xsize,ysize,yoff,grad));
}
} else if (table[b] & V) {
SETINTERP(intersect_any_v(xcenter,ycenter,xsize,ysize,yoff,grad));
} else {
SETINTERP(intersect_any(xcenter,ycenter,xsize,ysize,yoff,grad));
}
}
}
}
}
}