diff options
Diffstat (limited to 'source/sw_sird.c')
-rw-r--r-- | source/sw_sird.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/source/sw_sird.c b/source/sw_sird.c new file mode 100644 index 0000000..18afbc9 --- /dev/null +++ b/source/sw_sird.c @@ -0,0 +1,306 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +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 "sw_local.h" + +/* +** Start Added by Lewey +** +** This is where the real SIRDS code is +*/ + +//width of the repeating pattern. Increasing this will +//increase the quality of the SIRD by giving it more +//height levels. +// +//Make sure: ((R_SIRDw % 3) == 0) +// && (((R_SIRDw / 3) % R_SIRDExponents) == 0) +#define R_SIRDw 144 + +//height of the repeating pattern (not really important) +#define R_SIRDh 50 + +//maximum offset. This is the max number of pixels +//an item can be moved due to it's height, this is +//is also obviously then the number of different +//height layers you can have. A large R_SIRDw will +//make it harder and harder to see the image, a larger +//ratio of R_SIRDw (i.e. less than 3) will eventually +//cause your eyes to be unable to see the pattern. +#define R_SIRDmaxDiff (R_SIRDw / 3) + +//the number of lower powers to ignore +#define R_SIRDIgnoreExponents 5 + +//the number of exponents (after ignored ones) to have different +//height values (ones after it are rounded to the max difference) +#define R_SIRDExponents 6 + +//the number of height levels each exponent is given +#define R_SIRDstepsPerExponent (R_SIRDmaxDiff / R_SIRDExponents) + +//this is the z value of the sky, which logically should be 0, but +//for implimentation reasons is made very high. Not my doing by the +//way. If you move to a different platform, you may need to change this +#define R_SIRD_ZofSky 0x8ccc + +//this is the number of random numbers +//defined in "rand1k.h" +#define R_SIRDnumRand 103 + +//this hold the background pattern +byte r_SIRDBackground[R_SIRDw * R_SIRDh]; + +//these are the actual random numbers +byte r_SIRDrandValues[] = { +#include "rand1k.h" +}; + + +//Only used if id386 is false, this acts as a +// reverse bit-scanner, and uses a sort of binary +// search to find the index of the highest set bit. +//You could also expand the loop 4 times to remove +// the 'while' +#if !id386 || !( defined _MSC_VER ) +int UShortLog(int val) +{ + int mask = 0xff00; + int p = 0; + int b = 8; + while (b) + { + if (val & mask) + { + p += b; + b >>= 1; + mask &= (mask << b); + } + else + { + mask &= (mask << (b >> 1)); + mask >>= b; + b >>= 1; + } + } + return p; +} +#endif + +int R_SIRDZFunc(int sub) +{ + int e; + + //special case the sky. + if (sub == R_SIRD_ZofSky) + return 0; + +#if id386 && ( defined _MSC_VER ) + e = sub; + //calculate the log (base 2) of the number. In other + //words the index of the highest set bit. bsr is undefined + //if it's input is 0, so special case that. + if (e!=0) + { + __asm + { + mov ebx, e + bsr eax, ebx + mov e, eax + } + } +#else + e = UShortLog(sub); +#endif + + //clip the exponent + if (e < R_SIRDIgnoreExponents) + return 0; + + // based on the power, shift the z so that + // it's as high as it can get while still staying + // under 0x100 + if (e > 8) + { + sub >>= (e-8); + } + else + { + if (e < 8) + { + sub <<= (8-e); + } + } + + // Lower the power of the number, this helps scaling and removes + // small z values. + e -= R_SIRDIgnoreExponents; + + // contruct the height value. The power is used as the primary calculator, + // and then the extra bits are used to offset. In this way you + // get more detail than just the log of the z value, and it works + // as a pretty good approximation of it. + e *= R_SIRDstepsPerExponent; + e += ((sub * R_SIRDstepsPerExponent) >> 8); + + //make sure we stay under maximum height. + return ((e<=R_SIRDmaxDiff)? e : R_SIRDmaxDiff ); +} + +void R_ApplySIRDAlgorithum( void ) +{ + short* curz, *oldz; + short cz = 0, lastz = 0; + byte* curp; + byte* curbp, j = 0; + int x, y, i, zinc, k; + int mode = sw_drawsird->integer; + + //note of interest: I've made this static so that + //if you like you could make it not static and see + //what would happen if you didn't change the background + static int ji = 0; + + //create the background image to tile + //basically done by shifting the values around + //each time and xoring them with a randomly + //selected pixel + for (i=0; i<R_SIRDw * R_SIRDh; i++) + { + if ((i%R_SIRDnumRand)==0) + { + ji++; + ji %= R_SIRDnumRand; + j = r_SIRDrandValues[r_SIRDrandValues[ji] % R_SIRDnumRand]; + } + r_SIRDBackground[i] = r_SIRDrandValues[ (i%R_SIRDnumRand) ] ^ j; + } + + //if we are under water: + if ((r_dowarp) && (vid.width != WARP_WIDTH)) + { + //the rendering is only in the top left + //WARP_WIDTH by WARP_HEIGHT area, so scale the z-values + //to span over the whole screen + + + //why are we going backwards? so that we don't write over the + //values before we read from them + + zinc = ((WARP_WIDTH * 0x10000) / vid.width); + for (y=vid.height-1; y>=0; y--) + { + curz = (d_pzbuffer + (vid.width * y)); + oldz = (d_pzbuffer + (vid.width * ((y*WARP_HEIGHT)/vid.height) )); + k = (zinc * (vid.width-1)); + + for (x=vid.width-1; x>=0; x--) + { + curz[x] = oldz[k >> 16]; + k -= zinc; + } + } + } + + + //SIRDify each line + for (y=0; y<vid.height; y++) + { + curp = (vid.buffer + (vid.rowbytes * y)); + curz = (d_pzbuffer + (vid.width * y )); + + if (mode != 3) + { + // draw the SIRD + + // copy the background into the left most column + curbp = &(r_SIRDBackground[ R_SIRDw * (y % R_SIRDh) ]); + for (x=0; x<R_SIRDw; x++) + { + *curp = *curbp; + curp++; + curbp++; + } + + lastz = 0; + cz = 0; + curz += R_SIRDw; + curbp = curp - R_SIRDw; + + // now calculate the SIRD + for (x=R_SIRDw; x<vid.width; x++) + { + //only call the z-function with a new + //value, it is slow so this saves quite + //some time. + if (lastz != *curz) + { + lastz = *curz; + + //convert from z to height offset + cz = ( mode == 2 ) ? R_SIRDmaxDiff - R_SIRDZFunc(lastz) : R_SIRDZFunc(lastz); + + //the "height offset" used in making SIRDS + //can be considered an adjustment of the + //frequency of repetition in the pattern. + //so here we are copying from bp to p, and so + //it simply increases or decreases the distance + //between the two. + curbp = (curp - R_SIRDw + cz); + } + + *curp = *curbp; + + curp++; + curbp++; + curz++; + } + } + else + { + //if we are just drawing the height map + //this lets you see which layers are used to + //create the SIRD + // + //NOTE: even though it may sort of look like + //a grey-scale height map, that is merely a + //coincidence because of how the colours are + //organized in the pallette. + + for (x=0; x<vid.width; x++) + { + if (lastz != *curz) + { + lastz = *curz; + cz = R_SIRDZFunc(*curz); + } + + *curp = cz; + + curp++; + curz++; + } + } + } +} + +/* +** End Added by Lewey +*/ |