1 /* Stereograph 0.16, 12/04/2000; 2 * renderer, stereographer's engine; 3 * Copyright (c) 2000 by Fabian Januszewski <fabian.linux@januszewski.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20 #define _GNU_SOURCE 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <math.h> 25 26 #include "renderer.h" 27 28 29 /* here we go... */ 30 31 struct GFX_DATA Base, Texture, Stereo; 32 struct RENDERER_DATA Renderer; 33 struct PARAMS Param; 34 35 36 /* 1st of all: send all releavant data (pointers) to foreign functions */ 37 int Get_GFX_Pointers(struct PARAMS **pParam, struct GFX_DATA **pBase, struct GFX_DATA **pTexture, struct GFX_DATA **pStereo) { 38 (*pParam) = &Param; 39 (*pBase) = &Base; 40 (*pTexture) = &Texture; 41 (*pStereo) = &Stereo; 42 return 0; 43 } 44 45 46 /* render a mere line */ 47 int ProcessLine(int base_line) { 48 return RenderLine(Base.Data + Base.Width * base_line, Texture.Data + Texture.Width * ((base_line + Param.Starty) % Texture.Height), Stereo.Data + Stereo.Width*base_line*Renderer.nzoom); 49 } 50 51 52 /* destroy memory reservations, internals; NOTE: Stereo also belongs to the renderer! */ 53 void Clear_Renderer(void) 54 { 55 free(Renderer.right_change_map); 56 free(Renderer.left_change_map); 57 free(Renderer.scanline); 58 free(Stereo.Data); 59 } 60 61 62 /* initialize internal rendering engine data */ 63 int Initialize_Renderer(void) 64 { 65 Renderer.startx = Param.Startx; 66 Renderer.max_change_tex_width = (int)((Texture.Width - 1) * Param.Front); 67 Renderer.right_change_map = (float*)malloc(sizeof(float) * (Base.Width + 1)); 68 Renderer.left_change_map = (float*)malloc(sizeof(float) * (Base.Width + 1)); 69 Renderer.naa = Param.AA + 0; 70 Renderer.nzoom = Param.Zoom + 0; 71 Renderer.realdist = Texture.Width * (Param.Distance + 1); 72 Renderer.internal_a = (1.0 / (Texture.Width * Texture.Width)) - (0.25 / (Renderer.realdist * Renderer.realdist)); 73 Renderer.eyeshift = Param.Eyeshift*0.5; 74 if( 75 ((Param.Distance + 1) > 1.0) && ((Param.Distance + 1) <= 9.0) && 76 (Renderer.eyeshift >= -0.5) && (Renderer.eyeshift <= 0.5) && 77 (Renderer.naa > 0) && (Renderer.naa <= 32) && 78 (Renderer.nzoom > 0) && (Renderer.nzoom <= 32) && 79 (Renderer.startx >= 0) && (Renderer.startx < (Base.Width - Texture.Width)) && 80 (Param.Starty >= 0) && 81 (Param.Front > 0.0) && (Param.Front <= 1.0) 82 ) { 83 Renderer.nfactor = Renderer.naa * Renderer.nzoom; 84 if(Param.AA - 1) 85 Renderer.scanline = (int*)malloc(sizeof(int) * (Base.Width * Renderer.nfactor)); 86 else 87 Renderer.scanline = NULL; 88 89 Stereo.Width = Base.Width * Renderer.nzoom; 90 Stereo.Height = Base.Height * Renderer.nzoom; 91 Stereo.Data = (int*)malloc(sizeof(int) * Stereo.Width * Stereo.Height); 92 93 if(Renderer.right_change_map && Renderer.left_change_map && Stereo.Data && Base.Data && Texture.Data) { 94 if(Base.Width >= Texture.Width) 95 return 0; 96 else 97 return -2; 98 } else 99 return -3; 100 } else { 101 return -1; 102 } 103 } 104 105 106 /* Render a mere line of data, may be completely independent of any gfx_data structure */ 107 int RenderLine(int *base_data, int *texture_data, int *stereo_data) 108 { 109 static int a = 0, aar_x, xaar_x = -1; 110 InitMap(Renderer.left_change_map, 0, Base.Width, (float)(Texture.Width + 1)); 111 112 FillMapsLeftToRight(base_data); 113 114 if(xaar_x == -1) 115 xaar_x = Renderer.startx; 116 a++; a %= 2; 117 if(a && Param.AAr) { 118 //aar_x = Stereo.Width - Texture.Width - 1; 119 /* tracing alternative startx */ 120 for (aar_x = Renderer.startx; (aar_x + Renderer.left_change_map[aar_x]) < (Stereo.Width - Texture.Width - 1); ) 121 aar_x += Renderer.left_change_map[aar_x]; 122 Renderer.startx = aar_x; 123 } else { 124 Renderer.startx = xaar_x; 125 } 126 if(Param.AA - 1) 127 { 128 if(Param.Zoom - 1) 129 return ZoomAAScan(stereo_data, texture_data); 130 else 131 return AAScan(stereo_data, texture_data);; 132 } else if(Param.Zoom) 133 return ZoomScan(stereo_data, texture_data); 134 else 135 return NormalScan(stereo_data, texture_data); 136 } 137 138 139 /* intialize changemap internals */ 140 int InitMap(float *change_map, int a, int b, float v) 141 { 142 for( ; a < b; a++) 143 change_map[a] = v; 144 return 0; 145 } 146 147 148 /* set changevalues */ 149 int FillMapsLeftToRight(int *base_data) 150 { 151 int z, scanx, i_c; 152 float c; 153 154 /* advanced full centered perspective; reimplemented february 4th 2000 */ 155 /* added eyeshift february 11th 2000 */ 156 for (scanx = 0; scanx < (Base.Width + Texture.Width); scanx++) 157 { 158 if((scanx + (int)(c = GetChange(scanx, base_data))) > 0) { 159 i_c = (int) (scanx + c*(0.5 - Renderer.eyeshift)) + (Texture.Width*Renderer.eyeshift*2.0); 160 if (i_c < Base.Width) { 161 Renderer.right_change_map[i_c] = -c; 162 z = i_c + Renderer.right_change_map[i_c]; 163 if ((z >= 0) && (z < Base.Width)) 164 if (Renderer.left_change_map[z] > c) 165 Renderer.left_change_map[z] = c; 166 } 167 } 168 } 169 170 /* checking for construction errors - `black holes' */ 171 if (Renderer.left_change_map[0] > Texture.Width) 172 Renderer.left_change_map[0] = Texture.Width; 173 for (z = 1; z < Base.Width; z++) 174 if (Renderer.left_change_map[z] > Texture.Width) 175 Renderer.left_change_map[z] = Renderer.left_change_map[z - 1]; 176 return 0; 177 } 178 179 180 /* This is float because of high precision effects such as zoom'n'anti-aliasing */ 181 /* In a simple reference implementation an integer value should be suffisant */ 182 float GetChange(int x, int *base_data) 183 { 184 float s, b, d; 185 /* extracting out of 24 bit RGB data the brightness/intensitiy indicating information */ 186 /* value is extended from 0-255 up to 0-765 */ 187 s = ((base_data[x] & 255) + ((base_data[x] >> 8) & 255) + ((base_data[x] >> 16) & 255)) / 765.0; 188 d = Renderer.realdist - (float) Renderer.max_change_tex_width * s; 189 b = 1.0 / sqrt(Renderer.internal_a + 0.25 / (d * d)); 190 return b; 191 } 192 193 194 /* reference renderer without any special effects */ 195 int NormalScan(int *stereo_data, int *texture_data) 196 { 197 float z; 198 int scanx; 199 200 /* insert the texture at x */ 201 memcpy(stereo_data + Renderer.startx, texture_data, Texture.Width * sizeof(int)); 202 203 /* we've to scan into two directions, beginning @ startx */ 204 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 205 { 206 z = scanx + Renderer.right_change_map[scanx]; 207 if (((int) z >= Renderer.startx) && ((int) z < Base.Width)) 208 stereo_data[scanx] = stereo_data[(int) z]; 209 } 210 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 211 { 212 z = scanx + Renderer.right_change_map[scanx]; 213 if( ((int) z < Base.Width) && ((int) z >= 0)) 214 stereo_data[scanx] = stereo_data[(int) z]; 215 } 216 for (scanx = Renderer.startx; scanx >= 0; scanx--) 217 { 218 z = scanx + Renderer.left_change_map[scanx]; 219 /* 'cause of problems without the round function - internal round, it's a cut - it is NOT symmetric */ 220 if (z != ((int) z)) 221 z++; 222 if (((int) z >= 0) && ((int) z < Base.Width)) 223 stereo_data[scanx] = stereo_data[(int) z]; 224 } 225 return 0; 226 } 227 228 229 /* First and most effective of all special: anti-aliasing */ 230 int AAScan(int *stereo_data, int *texture_data) 231 { 232 int scanx,a; 233 float z; 234 int r, g, b; 235 236 /* insert the texture without any special fx */ 237 for (scanx = 0; scanx < Texture.Width; scanx++) 238 for (a = 0; a < Renderer.nfactor; a++) 239 Renderer.scanline[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 240 241 /* scanning... */ 242 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 243 { 244 z = scanx + Renderer.right_change_map[scanx]; 245 if ((z >= Renderer.startx) && (z < Base.Width)) 246 for (a = 0; a < Renderer.nfactor; a++) 247 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 248 else if (z > (Renderer.startx - 1) && (z < Renderer.startx)) 249 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 250 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 251 } 252 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 253 { 254 z = scanx + Renderer.right_change_map[scanx]; 255 if( (z < Base.Width) && (z >= 0)) 256 for (a = 0; a < Renderer.nfactor; a++) 257 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 258 } 259 for (scanx = Renderer.startx; scanx >= 0; scanx--) 260 { 261 z = scanx + Renderer.left_change_map[scanx]; 262 if((z < Base.Width) && (z >= 0)) 263 { 264 z *= Renderer.nfactor; 265 if (z != ((int) z)) 266 z++; 267 for (a = 0; a < Renderer.nfactor; a++) 268 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) z + a)]; 269 } 270 } 271 272 /* flush mem back into stereo_data, fixed */ 273 for (scanx = 0; scanx < Base.Width; scanx++) 274 { 275 stereo_data[scanx] = r = g = b = 0; 276 for (a = 0; a < Renderer.naa; a++) 277 { 278 r += Renderer.scanline[scanx * Renderer.naa + a] & 255; 279 g += (Renderer.scanline[scanx * Renderer.naa + a] >> 8) & 255; 280 b += (Renderer.scanline[scanx * Renderer.naa + a] >> 16) & 255; 281 } 282 stereo_data[scanx] += (r / Renderer.naa) & 255; 283 stereo_data[scanx] += ((g / Renderer.naa) & 255) << 8; 284 stereo_data[scanx] += ((b / Renderer.naa) & 255) << 16; 285 } 286 return 0; 287 } 288 289 290 /* Second effect: zoom */ 291 int ZoomScan(int *stereo_data, int *texture_data) 292 { 293 int scanx, a; 294 float z; 295 296 /* insert the texture without any special fx */ 297 for (scanx = 0; scanx < Texture.Width; scanx++) 298 for (a = 0; a < Renderer.nfactor; a++) 299 stereo_data[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 300 301 /* already scanning, nothing to prepare */ 302 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 303 { 304 z = scanx + Renderer.right_change_map[scanx]; 305 if ((z >= Renderer.startx) && (z < Base.Width)) 306 for (a = 0; a < Renderer.nfactor; a++) 307 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) (z * Renderer.nfactor) + a]; 308 else if ((z > (Renderer.startx - 1)) && (z < Renderer.startx)) 309 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 310 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[((int) (z * Renderer.nfactor) + a)]; 311 } 312 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 313 { 314 z = scanx + Renderer.right_change_map[scanx]; 315 if((z < Base.Width) && (z >= 0)) 316 for (a = 0; a < Renderer.nfactor; a++) 317 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) (z * Renderer.nfactor) + a]; 318 } 319 320 for (scanx = Renderer.startx; scanx >= 0; scanx--) 321 { 322 z = scanx + Renderer.left_change_map[scanx]; 323 if((z < Base.Width) && (z >= 0)) 324 { 325 z *= Renderer.nfactor; 326 if (z != ((int) z)) 327 z++; 328 for (a = 0; a < Renderer.nfactor; a++) 329 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) z + a]; /* attention : z is was already multiplied above!!! */ 330 } 331 } 332 333 /* fill the comple row down with the same values to construct square pixels */ 334 for (a = 1; a < Renderer.nfactor; a++) 335 memcpy(stereo_data + Stereo.Width*a, stereo_data, Stereo.Width * sizeof(int)); 336 return 0; 337 } 338 339 340 /* ZOOM'N'AA */ 341 /* Final effects: fx pair in cooperation */ 342 int ZoomAAScan(int *stereo_data, int *texture_data) 343 { 344 int scanx, a; 345 float z; 346 int r, g, b; 347 348 /* insert the texture without any special fx */ 349 /* the same as anti-aliasing implementation above */ 350 for (scanx = 0; scanx < Texture.Width; scanx++) 351 for (a = 0; a < Renderer.nfactor; a++) 352 Renderer.scanline[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 353 354 /* scanning */ 355 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 356 { 357 z = scanx + Renderer.right_change_map[scanx]; 358 if ((z >= Renderer.startx) && (z < Base.Width)) 359 for (a = 0; a < Renderer.nfactor; a++) 360 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) (z * Renderer.nfactor) + a]; 361 else if (z > (Renderer.startx - 1) && (z < Renderer.startx)) 362 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 363 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 364 } 365 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 366 { 367 z = scanx + Renderer.right_change_map[scanx]; 368 if ((z >= 0) && (z < Base.Width)) 369 for (a = 0; a < Renderer.nfactor; a++) 370 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) (z * Renderer.nfactor) + a]; 371 } 372 for (scanx = Renderer.startx; scanx >= 0; scanx--) 373 { 374 z = scanx + Renderer.left_change_map[scanx]; 375 if ((z >= 0) && (z < Base.Width)) 376 { 377 z *= Renderer.nfactor; 378 if (z != ((int) z)) 379 z++; 380 for (a = 0; a < Renderer.nfactor; a++) 381 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) z + a]; /* z was already multiplied above; */ 382 } 383 } 384 385 /* flush it down, fixed */ 386 for (scanx = 0; scanx < Stereo.Width; scanx++) 387 { 388 stereo_data[scanx] = r = g = b = 0; 389 for (a = 0; a < Renderer.naa; a++) 390 { 391 r += Renderer.scanline[scanx * Renderer.naa + a] & 255; 392 g += (Renderer.scanline[scanx * Renderer.naa + a] >> 8) & 255; 393 b += (Renderer.scanline[scanx * Renderer.naa + a] >> 16) & 255; 394 } 395 stereo_data[scanx] += (r / Renderer.naa) & 255; 396 stereo_data[scanx] += ((g / Renderer.naa) & 255) << 8; 397 stereo_data[scanx] += ((b / Renderer.naa) & 255) << 16; 398 } 399 400 401 /* fill it down to produce square pixels */ 402 for (a = 1; a < Renderer.nzoom; a++) 403 memcpy(stereo_data + Stereo.Width*a, stereo_data, Stereo.Width*sizeof(int)); 404 return 0; 405 } renderer.c contains code to make the program actually process data and stereograph it. |