DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/output/direct3d/hq2x_d3d.cpp
00001 /*
00002  *  Hq2x scaler pixel shader version support code by Mitja Gros (Mitja.Gros@gmail.com)
00003  *
00004  *  Original OpenGL-HQ rendering code
00005  *  Copyright (C) 2004-2005 Jorg Walter <jwalt@garni.ch>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020  */
00021 
00022 #include "hq2x_d3d.h"
00023 
00024 #if C_D3DSHADERS
00025 
00026 #define fmax(x,y) ((x)>(y)?(x):(y))
00027 #define fmin(x,y) ((x)<(y)?(x):(y))
00028 #define R 1
00029 #define T 2
00030 #define RT 4
00031 #define RT2 8
00032 #define L 16
00033 #define LB2 32
00034 #define LT2 64
00035 #define LT 128
00036 #define LB 256
00037 #define B 512
00038 #define RB2 1024
00039 #define RB 2048
00040 
00041 #define NODIAG 0x90
00042 #define H 1
00043 #define V 2
00044 #define D 4
00045 
00046 #define hmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,R,L),RT,LT),RT2,LT2),RB,LB),RB2,LB2)
00047 #define vmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,T,B),RT,RB),RT2,RB2),LT,LB),LT2,LB2)
00048 #define NO_BORDER(x) ((b&(x)) == 0)
00049 #define IS_BORDER(x) ((b&(x)) == (x))
00050 #define SETINTERP(percentage_inside) setinterp(xcenter,ycenter,percentage_inside, \
00051                         NO_BORDER(R),NO_BORDER(T),NO_BORDER(RT), \
00052                         IS_BORDER(R),IS_BORDER(T),IS_BORDER(RT), \
00053                         texture+((x+(border%16)*HQ2X_RESOLUTION+y*16*HQ2X_RESOLUTION+(border&~15)*HQ2X_RESOLUTION*HQ2X_RESOLUTION)*4))
00054 
00055 static double sign(double a) {
00056     return (a < 0?-1:1);
00057 }
00058 
00059 /*
00060  This function calculates what percentage of a rectangle intersected by a line lies near the center of the
00061  cordinate system. It is mathematically exact, and well-tested for xcenter > 0 and ycenter > 0 (it's only
00062  used that way). It should be correct for other cases as well, but well... famous last words :)
00063 */
00064 static double intersect_any(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) {
00065     double g = fabs(gradient)*xsize/ysize;
00066     double o = -((yoffset-ycenter) + gradient*xcenter)/ysize*sign(ycenter)*sign(yoffset)-g*0.5+0.5;
00067     double yl = o, yr = o+g, xb = -o/g, xt = (1-o)/g;
00068     double area = 1.0;
00069 
00070     if (yl >= 1.0) xt = xb = area = 0.0;
00071     else if (yl > 0.0) {
00072         area = 1.0-yl;
00073         xb = 0.0;
00074     }
00075     else if (yr <= 0.0) yl = yr = area = 1.0;
00076     else yl = o+xb*g;
00077 
00078     if (xt <= 0.0) yr = yl = area = 0.0;
00079     else if (xt < 1.0) {
00080         area *= xt;
00081         yr = 1.0;
00082     }
00083     else if (xb >= 1.0) xb = xt = area = 1.0;
00084     else xt = (yr-o)/g;
00085 
00086     area -= (xt-xb)*(yr-yl)/2;
00087 
00088     return area;
00089 }
00090 
00091 static double intersect_h(double xcenter, double ycenter, double xsize, double ysize) {
00092     (void)ycenter;//UNUSED
00093     (void)ysize;
00094     return fmax(0.0,fmin(1.0,(.55-fabs(xcenter)+xsize/2.0)/xsize));
00095 }
00096 
00097 static double intersect_any_h(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) {
00098     double hinside = intersect_h(xcenter,ycenter,xsize,ysize);
00099     return hinside*hinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
00100 }
00101 
00102 static double intersect_v(double xcenter, double ycenter, double xsize, double ysize) {
00103     (void)xsize;
00104     (void)ysize;
00105     (void)xcenter;
00106     return fmax(0.0,fmin(1.0,(.55-fabs(ycenter)+ysize/2.0)/ysize));
00107 }
00108 
00109 static double intersect_any_v(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) {
00110     double vinside = intersect_v(xcenter,ycenter,xsize,ysize);
00111     return vinside*vinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
00112 }
00113 
00114 static double intersect_hv(double xcenter, double ycenter, double xsize, double ysize) {
00115     double hinside = intersect_h(xcenter,ycenter,xsize,ysize);
00116     double vinside = intersect_v(xcenter,ycenter,xsize,ysize);
00117     return (1-hinside)*(1-vinside)+hinside*vinside;
00118 }
00119 
00120 /* FIXME: not sure if this is correct, but it is rare enough and most likely near enough. fixes welcome :) */
00121 static double intersect_any_hv(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) {
00122     double hvinside = intersect_hv(xcenter,ycenter,xsize,ysize);
00123     return hvinside*hvinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient);
00124 }
00125 
00126 static double intersect_hvd(double xcenter, double ycenter, double xsize, double ysize) {
00127     return intersect_h(xcenter,ycenter,xsize,ysize)*intersect_v(xcenter,ycenter,xsize,ysize);
00128 }
00129 
00130 static void setinterp(double xcenter, double ycenter, double percentage_inside, int i1, int i2, int i3, int o1, int o2, int o3, unsigned char *factors) {
00131     double d0, d1, d2, d3, percentage_outside, totaldistance_i, totaldistance_o;
00132     xcenter = fabs(xcenter);
00133     ycenter = fabs(ycenter);
00134     d0 = (1-xcenter)*(1-ycenter);
00135     d1 = xcenter*(1-ycenter);
00136     d2 = (1-xcenter)*ycenter;
00137     d3 = xcenter*ycenter;
00138     if (i1 && i2) i3 = 0;
00139     if (o1 && o2) o3 = 0;
00140     percentage_outside = 1.0-percentage_inside;
00141     totaldistance_i = d0+i1*d1+i2*d2+i3*d3;
00142     totaldistance_o = o1*d1+o2*d2+o3*d3+1e-12; /* +1e-12: prevent division by zero */
00143 
00144     factors[1] = (unsigned char)(((d1/totaldistance_i*percentage_inside*i1)+(d1/totaldistance_o*percentage_outside*o1))*255+.5);
00145     factors[2] = (unsigned char)(((d2/totaldistance_i*percentage_inside*i2)+(d2/totaldistance_o*percentage_outside*o2))*255+.5);
00146     factors[3] = (unsigned char)(((d3/totaldistance_i*percentage_inside*i3)+(d3/totaldistance_o*percentage_outside*o3))*255+.5);
00147     factors[0] = 255-factors[1]-factors[2]-factors[3];/*(unsigned char)((d0/totaldistance_i*percentage_inside)*255+.5);*/
00148 }
00149 
00150 /* 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.
00151    I aborted compilation after 5 minutes of CPU time on an Athlon64 3700+. */
00152 static int swap_bits(int num, int bit1, int bit2) {
00153     return ((num & ~(bit1|bit2))|((num&bit1)?bit2:0)|((num&bit2)?bit1:0));
00154 }
00155 
00156 
00157 // width, height == rwidth, rheight
00158 // outwidth, outheight == width, height
00159 void BuildHq2xLookupTexture(Bitu outWidth, Bitu outHeight, Bitu rwidth, Bitu rheight, Bit8u* texture)
00160 {
00161     double xsize, ysize;
00162     unsigned char table[4096] = HQ2X_D3D_TABLE_DATA;
00163 
00164     xsize = (double)rwidth / (double)outWidth;
00165     ysize = (double)rheight / (double)outHeight;
00166 
00167     for (int border = 0; border < 4096; border++) {
00168         for (int y = 0; y < HQ2X_RESOLUTION; y++) {
00169             for (int x = 0; x < HQ2X_RESOLUTION; x++) {
00170                 double xcenter = fabs((((double)x)+0.5) / (double)(HQ2X_RESOLUTION)-0.5)/0.958;
00171                 double ycenter = fabs((((double)y)+0.5) / (double)(HQ2X_RESOLUTION)-0.5)/0.958;
00172                 int sx = (x < HQ2X_RESOLUTION/2?-1:1);
00173                 int sy = (y < HQ2X_RESOLUTION/2?-1:1);
00174                 int b = (sy > 0?(sx > 0?border:hmirror(border)):(sx > 0?vmirror(border):vmirror(hmirror(border))));
00175 
00176                 if ((table[b] & NODIAG) == NODIAG) {
00177                     if (table[b] & H) {
00178                         if (table[b] & V) {
00179                             if (table[b] & D) SETINTERP(intersect_hvd(xcenter,ycenter,xsize,ysize));
00180                             else SETINTERP(intersect_hv(xcenter,ycenter,xsize,ysize));
00181                         } else {
00182                             SETINTERP(intersect_h(xcenter,ycenter,xsize,ysize));
00183                         }
00184                     } else if (table[b] & V) {
00185                         SETINTERP(intersect_v(xcenter,ycenter,xsize,ysize));
00186                     } else {
00187                         SETINTERP(1.0);
00188                     }
00189                 } else {
00190                     double yoff = (table[b]&4?1:-1)*(((table[b] >> 3) & 3) + 1)/4.0;
00191                     double grad = (table[b]&32?1:-1)*(((table[b] >> 6) & 3) + 1)/2.0;
00192                     if (table[b] & H) {
00193                         if (table[b] & V) {
00194                             SETINTERP(intersect_any_hv(xcenter,ycenter,xsize,ysize,yoff,grad));
00195                         } else {
00196                             SETINTERP(intersect_any_h(xcenter,ycenter,xsize,ysize,yoff,grad));
00197                         }
00198                     } else if (table[b] & V) {
00199                         SETINTERP(intersect_any_v(xcenter,ycenter,xsize,ysize,yoff,grad));
00200                     } else {
00201                         SETINTERP(intersect_any(xcenter,ycenter,xsize,ysize,yoff,grad));
00202                     }
00203                 }
00204 
00205             }
00206         }
00207     }
00208 }
00209 
00210 #endif