summaryrefslogtreecommitdiff
path: root/source/sw_sird.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/sw_sird.c')
-rw-r--r--source/sw_sird.c306
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
+*/