DOSBox-X
|
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 along 00018 * with this program; if not, write to the Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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