1 /* Stereograph 0.14, 08/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 InitMap(Renderer.left_change_map, 0, Base.Width, (float)(Texture.Width + 1)); 110 111 FillMapsLeftToRight(base_data); 112 113 if(Param.AA - 1) 114 { 115 if(Param.Zoom - 1) 116 return ZoomAAScan(stereo_data, texture_data); 117 else 118 return AAScan(stereo_data, texture_data); 119 } else if(Param.Zoom) 120 return ZoomScan(stereo_data, texture_data); 121 else 122 return NormalScan(stereo_data, texture_data); 123 } 124 125 126 /* intialize changemap internals */ 127 int InitMap(float *change_map, int a, int b, float v) 128 { 129 for( ; a < b; a++) 130 change_map[a] = v; 131 return 0; 132 } 133 134 135 /* set changevalues */ 136 int FillMapsLeftToRight(int *base_data) 137 { 138 int z, scanx, i_c; 139 float c; 140 141 /* advanced full centered perspective; reimplemented february 4th 2000 */ 142 /* added eyeshift february 11th 2000 */ 143 for (scanx = 0; scanx < (Base.Width + Texture.Width); scanx++) 144 { 145 if((scanx + (int)(c = GetChange(scanx, base_data))) > 0) { 146 i_c = (int) (scanx + c*(0.5 - Renderer.eyeshift)) + (Texture.Width*Renderer.eyeshift*2.0); 147 if (i_c < Base.Width) { 148 Renderer.right_change_map[i_c] = -c; 149 z = i_c + Renderer.right_change_map[i_c]; 150 if ((z >= 0) && (z < Base.Width)) 151 if (Renderer.left_change_map[z] > c) 152 Renderer.left_change_map[z] = c; 153 } 154 } 155 } 156 157 /* checking for construction errors - `black holes' */ 158 if (Renderer.left_change_map[0] > Texture.Width) 159 Renderer.left_change_map[0] = Texture.Width; 160 for (z = 1; z < Base.Width; z++) 161 if (Renderer.left_change_map[z] > Texture.Width) 162 Renderer.left_change_map[z] = Renderer.left_change_map[z - 1]; 163 return 0; 164 } 165 166 167 /* This is float because of high precision effects such as zoom'n'anti-aliasing */ 168 /* In a simple reference implementation an integer value should be suffisant */ 169 float GetChange(int x, int *base_data) 170 { 171 float s, b, d; 172 /* extracting out of 24 bit RGB data the brightness/intensitiy indicating information */ 173 /* value is extended from 0-255 up to 0-765 */ 174 s = ((base_data[x] & 255) + ((base_data[x] >> 8) & 255) + ((base_data[x] >> 16) & 255)) / 765.0; 175 d = Renderer.realdist - (float) Renderer.max_change_tex_width * s; 176 b = 1.0 / sqrt(Renderer.internal_a + 0.25 / (d * d)); 177 return b; 178 } 179 180 181 /* reference renderer without any special effects */ 182 int NormalScan(int *stereo_data, int *texture_data) 183 { 184 float z; 185 int scanx; 186 187 /* insert the texture at x */ 188 memcpy(stereo_data + Renderer.startx, texture_data, Texture.Width * sizeof(int)); 189 190 /* we've to scan into two directions, beginning @ startx */ 191 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 192 { 193 z = scanx + Renderer.right_change_map[scanx]; 194 if (((int) z >= Renderer.startx) && ((int) z < Base.Width)) 195 stereo_data[scanx] = stereo_data[(int) z]; 196 } 197 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 198 { 199 z = scanx + Renderer.right_change_map[scanx]; 200 if( ((int) z < Base.Width) && ((int) z >= 0)) 201 stereo_data[scanx] = stereo_data[(int) z]; 202 } 203 for (scanx = Renderer.startx; scanx >= 0; scanx--) 204 { 205 z = scanx + Renderer.left_change_map[scanx]; 206 /* 'cause of problems without the round function - internal round, it's a cut - it is NOT symmetric */ 207 if (z != ((int) z)) 208 z++; 209 if (((int) z >= 0) && ((int) z < Base.Width)) 210 stereo_data[scanx] = stereo_data[(int) z]; 211 } 212 return 0; 213 } 214 215 216 /* First and most effective of all special: anti-aliasing */ 217 int AAScan(int *stereo_data, int *texture_data) 218 { 219 int scanx,a; 220 float z; 221 int r, g, b; 222 223 /* insert the texture without any special fx */ 224 for (scanx = 0; scanx < Texture.Width; scanx++) 225 for (a = 0; a < Renderer.nfactor; a++) 226 Renderer.scanline[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 227 228 /* scanning... */ 229 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 230 { 231 z = scanx + Renderer.right_change_map[scanx]; 232 if ((z >= Renderer.startx) && (z < Base.Width)) 233 for (a = 0; a < Renderer.nfactor; a++) 234 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 235 else if (z > (Renderer.startx - 1) && (z < Renderer.startx)) 236 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 237 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 238 } 239 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 240 { 241 z = scanx + Renderer.right_change_map[scanx]; 242 if( (z < Base.Width) && (z >= 0)) 243 for (a = 0; a < Renderer.nfactor; a++) 244 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 245 } 246 for (scanx = Renderer.startx; scanx >= 0; scanx--) 247 { 248 z = scanx + Renderer.left_change_map[scanx]; 249 if((z < Base.Width) && (z >= 0)) 250 { 251 z *= Renderer.nfactor; 252 if (z != ((int) z)) 253 z++; 254 for (a = 0; a < Renderer.nfactor; a++) 255 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) z + a)]; 256 } 257 } 258 259 /* flush mem back into stereo_data, fixed */ 260 for (scanx = 0; scanx < Base.Width; scanx++) 261 { 262 stereo_data[scanx] = r = g = b = 0; 263 for (a = 0; a < Renderer.naa; a++) 264 { 265 r += Renderer.scanline[scanx * Renderer.naa + a] & 255; 266 g += (Renderer.scanline[scanx * Renderer.naa + a] >> 8) & 255; 267 b += (Renderer.scanline[scanx * Renderer.naa + a] >> 16) & 255; 268 } 269 stereo_data[scanx] += (r / Renderer.naa) & 255; 270 stereo_data[scanx] += ((g / Renderer.naa) & 255) << 8; 271 stereo_data[scanx] += ((b / Renderer.naa) & 255) << 16; 272 } 273 return 0; 274 } 275 276 277 /* Second effect: zoom */ 278 int ZoomScan(int *stereo_data, int *texture_data) 279 { 280 int scanx, a; 281 float z; 282 283 /* insert the texture without any special fx */ 284 for (scanx = 0; scanx < Texture.Width; scanx++) 285 for (a = 0; a < Renderer.nfactor; a++) 286 stereo_data[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 287 288 /* already scanning, nothing to prepare */ 289 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 290 { 291 z = scanx + Renderer.right_change_map[scanx]; 292 if ((z >= Renderer.startx) && (z < Base.Width)) 293 for (a = 0; a < Renderer.nfactor; a++) 294 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) (z * Renderer.nfactor) + a]; 295 else if ((z > (Renderer.startx - 1)) && (z < Renderer.startx)) 296 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 297 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[((int) (z * Renderer.nfactor) + a)]; 298 } 299 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 300 { 301 z = scanx + Renderer.right_change_map[scanx]; 302 if((z < Base.Width) && (z >= 0)) 303 for (a = 0; a < Renderer.nfactor; a++) 304 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) (z * Renderer.nfactor) + a]; 305 } 306 307 for (scanx = Renderer.startx; scanx >= 0; scanx--) 308 { 309 z = scanx + Renderer.left_change_map[scanx]; 310 if((z < Base.Width) && (z >= 0)) 311 { 312 z *= Renderer.nfactor; 313 if (z != ((int) z)) 314 z++; 315 for (a = 0; a < Renderer.nfactor; a++) 316 stereo_data[(scanx * Renderer.nfactor) + a] = stereo_data[(int) z + a]; /* attention : z is was already multiplied above!!! */ 317 } 318 } 319 320 /* fill the comple row down with the same values to construct square pixels */ 321 for (a = 1; a < Renderer.nfactor; a++) 322 memcpy(stereo_data + Stereo.Width*a, stereo_data, Stereo.Width * sizeof(int)); 323 return 0; 324 } 325 326 327 /* ZOOM'N'AA */ 328 /* Final effects: fx pair in cooperation */ 329 int ZoomAAScan(int *stereo_data, int *texture_data) 330 { 331 int scanx, a; 332 float z; 333 int r, g, b; 334 335 /* insert the texture without any special fx */ 336 /* the same as anti-aliasing implementation above */ 337 for (scanx = 0; scanx < Texture.Width; scanx++) 338 for (a = 0; a < Renderer.nfactor; a++) 339 Renderer.scanline[((scanx + Renderer.startx) * Renderer.nfactor) + a] = texture_data[scanx]; 340 341 /* scanning */ 342 for (scanx = Renderer.startx; scanx < (Renderer.startx + Texture.Width); scanx++) 343 { 344 z = scanx + Renderer.right_change_map[scanx]; 345 if ((z >= Renderer.startx) && (z < Base.Width)) 346 for (a = 0; a < Renderer.nfactor; a++) 347 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) (z * Renderer.nfactor) + a]; 348 else if (z > (Renderer.startx - 1) && (z < Renderer.startx)) 349 for (a = (-z + (float) Renderer.startx) * Renderer.nfactor; a < Renderer.nfactor; a++) 350 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[((int) (z * Renderer.nfactor) + a)]; 351 } 352 for (scanx = Renderer.startx + Texture.Width; scanx < Base.Width; scanx++) 353 { 354 z = scanx + Renderer.right_change_map[scanx]; 355 if ((z >= 0) && (z < Base.Width)) 356 for (a = 0; a < Renderer.nfactor; a++) 357 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) (z * Renderer.nfactor) + a]; 358 } 359 for (scanx = Renderer.startx; scanx >= 0; scanx--) 360 { 361 z = scanx + Renderer.left_change_map[scanx]; 362 if ((z >= 0) && (z < Base.Width)) 363 { 364 z *= Renderer.nfactor; 365 if (z != ((int) z)) 366 z++; 367 for (a = 0; a < Renderer.nfactor; a++) 368 Renderer.scanline[(scanx * Renderer.nfactor) + a] = Renderer.scanline[(int) z + a]; /* z was already multiplied above; */ 369 } 370 } 371 372 /* flush it down, fixed */ 373 for (scanx = 0; scanx < Stereo.Width; scanx++) 374 { 375 stereo_data[scanx] = r = g = b = 0; 376 for (a = 0; a < Renderer.naa; a++) 377 { 378 r += Renderer.scanline[scanx * Renderer.naa + a] & 255; 379 g += (Renderer.scanline[scanx * Renderer.naa + a] >> 8) & 255; 380 b += (Renderer.scanline[scanx * Renderer.naa + a] >> 16) & 255; 381 } 382 stereo_data[scanx] += (r / Renderer.naa) & 255; 383 stereo_data[scanx] += ((g / Renderer.naa) & 255) << 8; 384 stereo_data[scanx] += ((b / Renderer.naa) & 255) << 16; 385 } 386 387 388 /* fill it down to produce square pixels */ 389 for (a = 1; a < Renderer.nzoom; a++) 390 memcpy(stereo_data + Stereo.Width*a, stereo_data, Stereo.Width*sizeof(int)); 391 return 0; 392 } renderer.c contains code to make the program actually process data and stereograph it. |