Initial source commit

This commit is contained in:
Tony Bark 2025-10-03 02:19:59 -04:00
commit f1384c11ee
335 changed files with 52715 additions and 0 deletions

View file

@ -0,0 +1,53 @@
ROOT_PATH = ../../..
COMPILE = g++ -g -I${ROOT_PATH} -c
LINK = g++ -I${ROOT_PATH}
MINOR_GEMS_SOURCES = \
${ROOT_PATH}/minorGems/io/file/linux/PathLinux.cpp \
#${ROOT_PATH}/minorGems/graphics/linux/ScreenGraphicsLinux.cpp \
#${ROOT_PATH}/minorGems/system/win32/ThreadWin32.cpp \
#${ROOT_PATH}/minorGems/system/linux/ThreadLinux.cpp \
MINOR_GEMS_OBJECTS = ${MINOR_GEMS_SOURCES:.cpp=.o}
LIBRARIES = -lSDL
all: screenCompress tileSet.tga characterSprite.tga
screenCompress: screenCompress.o landscape.o ${MINOR_GEMS_OBJECTS}
${LINK} -o screenCompress screenCompress.o landscape.o ${MINOR_GEMS_OBJECTS} ${LIBRARIES}
sdlTest: sdlTest.o
${LINK} -o sdlTest sdlTest.o ${MINOR_GEMS_OBJECTS} ${LIBRARIES} -lSDLmain
screenCompress.o: screenCompress.cpp landscape.h
landscape.o: landscape.cpp landscape.h
tileSet.tga: tileSet.png
convert tileSet.png tileSet.tga
characterSprite.tga: characterSprite.png
convert characterSprite.png characterSprite.tga
#
# Generic:
#
# Map all .cpp C++ and C files into .o object files
#
# $@ represents the name.o file
# $< represents the name.cpp file
#
.cpp.o:
${COMPILE} -o $@ $<
.c.o:
${COMPILE} -o $@ $<

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1 @@
g++ -I../../.. -o screenCompress screenCompress.cpp ../../../minorGems/graphics/linux/ScreenGraphicsLinux.cpp ../../../minorGems/io/file/linux/PathLinux.cpp landscape.o -lSDL

View file

@ -0,0 +1,442 @@
/*
* Modification History
*
* 2006-September-26 Jason Rohrer
* Switched to cosine interpolation.
* Added optimizations discovered with profiler. Reduced running time by 18%.
*/
#include "landscape.h"
#include <math.h>
#include <stdlib.h>
#include "minorGems/util/SimpleVector.h"
double landscape( double inX, double inY, double inT,
double inBaseFrequency, double inRoughness,
int inDetail ) {
if( inDetail < 0 ) {
return 0.0;
}
else {
// frequency of octave
double frequency = inBaseFrequency * pow( 2, inDetail );
double amplitude = pow( inRoughness, inDetail );
return amplitude * noise4d( inX * frequency,
inY * frequency,
// index different planes of noise
inDetail,
inT )
+ landscape( inX, inY, inT, inBaseFrequency, inRoughness,
inDetail - 1 );
}
}
double variableRoughnessLandscape( double inX, double inY, double inT,
double inBaseFrequency,
double inRoughnessChangeFrequency,
double inMinRoughness,
double inMaxRoughness,
int inDetail ) {
double roughnessFreqX = inX * inRoughnessChangeFrequency;
double roughnessFreqY = inY * inRoughnessChangeFrequency;
// use low-frequency noise 4d to select landscape roughness
// between 0 and 1
double roughness =
( noise4d( 6, roughnessFreqX, roughnessFreqY, inT ) + 1 ) / 2;
// move roughness into specified range
roughness =
roughness * ( inMaxRoughness - inMinRoughness ) +
inMinRoughness;
return landscape( inX, inY, inT, inBaseFrequency, roughness, inDetail );
}
int getRandomPoints( double inStartX, double inEndX,
double inStartY, double inEndY,
double inT,
double inSampleStepSize,
double inDensity,
double **outXCoordinates,
double **outYCoordinates ) {
SimpleVector<double> *xCoordinates = new SimpleVector<double>();
SimpleVector<double> *yCoordinates = new SimpleVector<double>();
// discretize startX and start Y so that sample grid for differently-placed
// windows always meshes
// use ceil to ensure that starting points are always inside the
// inStart/inEnd bounds
double discretizedStartX =
inSampleStepSize * ceil( inStartX / inSampleStepSize );
double discretizedStartY =
inSampleStepSize * ceil( inStartY / inSampleStepSize );
// put a point wherever we have a zero-crossing
double lastSample = 1;
for( double x=discretizedStartX; x<=inEndX; x+=inSampleStepSize ) {
for( double y=discretizedStartY; y<=inEndY; y+=inSampleStepSize ) {
double landscapeSample =
variableRoughnessLandscape(
30 * x + 1000, 30 * y + 1000, inT + 1000,
0.01, 0.001, 0.25, 0.65, 0 );
// shift landscape up to reduce chance of zero-crossing
landscapeSample = (1-inDensity) * 0.5 + 0.5 + landscapeSample ;
if( landscapeSample < 0 &&
lastSample >= 0 ||
landscapeSample >= 0 &&
landscapeSample < 0 ) {
// sign change
// hit
xCoordinates->push_back( x );
yCoordinates->push_back( y );
}
lastSample = landscapeSample;
}
}
*outXCoordinates = xCoordinates->getElementArray();
*outYCoordinates = yCoordinates->getElementArray();
int numPoints = xCoordinates->size();
delete xCoordinates;
delete yCoordinates;
return numPoints;
}
/**
* Computes a 32-bit random number.
* Use linear congruential method.
*
* @param inSeed the seed to use.
*/
// this is the readable version of the funcion
// it has been turned into a set of macros below
inline unsigned long random32_readable( unsigned long inSeed ) {
// this is the true hot-spot of the entire landscape function
// thus, optimization is warranted.
// multiplier = 3141592621
// use hex to avoid warnings
//unsigned long multiplier = 0xBB40E62D;
//unsigned long increment = 1;
// better:
// unsigned long multiplier = 196314165
// unsigned long increment = 907633515
// this will automatically be mod-ed by 2^32 because of the limit
// of the unsigned long type
// return multiplier * inSeed + increment;
//return 0xBB40E62D * inSeed + 1;
//return 196314165 * inSeed + 907633515;
//int n = ( inSeed << 13 ) ^ inSeed;
//return n * (n * n * 15731 + 789221) + 1376312589;
//const unsigned long Num1 = (inSeed * 0xFEA09B9DLU) + 1;
//const unsigned long Num2 = ((inSeed * 0xB89C8895LU) + 1) >> 16;
//return Num1 ^ Num2;
/*
unsigned int rseed=(inSeed*15064013)^(inSeed*99991+604322121)^(inSeed*45120321)^(inSeed*5034121+13);
const unsigned long Num1 = (inSeed * 0xFEA09B9DLU) + 1;
const unsigned long Num2 = ((inSeed * 0xB89C8895LU) + 1) >> 16;
rseed *= Num1 ^ Num2;
return rseed;
*/
const unsigned long Num1 = (inSeed * 0xFEA09B9DLU) + 1;
const unsigned long Num2 = ((inSeed^Num1) * 0x9C129511LU) + 1;
const unsigned long Num3 = (inSeed * 0x2512CFB8LU) + 1;
const unsigned long Num4 = ((inSeed^Num3) * 0xB89C8895LU) + 1;
const unsigned long Num5 = (inSeed * 0x6BF962C1LU) + 1;
const unsigned long Num6 = ((inSeed^Num5) * 0x4BF962C1LU) + 1;
return Num2 ^ (Num4 >> 11) ^ (Num6 >> 22);
}
// faster as a set of macros
#define Num1( inSeed ) \
( ( inSeed * 0xFEA09B9DLU ) + 1 )
#define Num2( inSeed ) \
( ( ( inSeed ^ Num1( inSeed ) ) * 0x9C129511LU ) + 1 )
#define Num3( inSeed ) \
( ( inSeed * 0x2512CFB8LU ) + 1 )
#define Num4( inSeed ) \
( ( ( inSeed ^ Num3( inSeed ) ) * 0xB89C8895LU ) + 1 )
#define Num5( inSeed ) \
( ( inSeed * 0x6BF962C1LU ) + 1 )
#define Num6( inSeed ) \
( ( ( inSeed ^ Num5( inSeed ) ) * 0x4BF962C1LU ) + 1 )
#define random32( inSeed ) \
( Num2( inSeed ) ^ (Num4( inSeed ) >> 11) ^ (Num6( inSeed ) >> 22) )
#define invMaxIntAsDouble 2.32830643708e-10
// 1/(x/2) = 2*(1/x)
//double invHalfMaxIntAsDouble = 2 * invMaxIntAsDouble;
// 2.32830643708e-10
//+ 2.32830643708e-10
//-------------------
// 4.65661287416e-10
#define invHalfMaxIntAsDouble 4.65661287416e-10
#define mixFour( x, y, z, t ) ( x ^ (y * 57) ^ (z * 131) ^ (t * 2383) )
/**
* Maps 4d integer coordinates into a [-1..1] noise space.
*
* @param x, y, z, t the 4d coordinates.
*
* @return a random value in the range [-1..1]
*/
// keep readable version around for reference
// it has been replaced by a macro below
inline double noise4dInt32_readable( unsigned long x,
unsigned long y,
unsigned long z,
unsigned long t ) {
//double maxIntAsDouble = 4294967295.0;
// modular addition automatic
// multiply x, y, z, and t by distinct primes to
// avoid correllations.
// using xor ( ^ ) here seems to avoid correllations that show
// up when using addition.
// mix x, y, z, and t
unsigned long randomSeed =
x ^
y * 57 ^
z * 131 ^
t * 2383;
// a random value between 0 and max unsigned long
unsigned long randomValue = random32( randomSeed );
// a random value between 0 and 2
double zeroTwoValue = randomValue * invHalfMaxIntAsDouble;
// a random value between -1 and 1
return zeroTwoValue - 1;
}
// noise4dInt32 function call itself was the slowest spot in code
// (found with profiler)
// turn into a set of macros
// matches original parameter format
#define noise4dInt32( x, y, z, t ) \
random32( mixFour( x, y, z, t ) ) \
* invHalfMaxIntAsDouble - 1
// problem: now that random32 is a macro, we are passing the unevaluated
// expression, ( x ^ (y * 57) ^ (z * 131) ^ (t * 2383) ), down into it.
// it is being evaluated 6 times within the depths of the random32 macro
// thus, we need to provide a new format where the caller can precompute
// the mix for us. This is even faster.
#define noise1dInt32( precomputedMix ) \
random32( precomputedMix ) \
* invHalfMaxIntAsDouble - 1
/*
* The following functions (blendNoiseNd) do 4d linear interpolation
* one dimension at a time.
*
* The end result is 8 calls to blendNoise1d (and 16 calls to noise4dInt32).
*
* This method was inspired by the functional implementations---I am
* decomposing a complicated problem into sub-problems that are easier
* to solve.
*/
// faster than f * b + (1-f) * a
// one less multiply
#define linearInterpolation( t, a, b ) ( a + t * ( b - a ) )
/**
* Blends 4d discrete (integer-parameter) noise function along one dimension
* with 3 fixed integer parameters.
*/
inline double blendNoise1d( double x,
unsigned long y,
unsigned long z,
unsigned long t ) {
double floorX = floor( x );
unsigned long floorIntX = (unsigned long)floorX;
if( floorX == x ) {
unsigned long precomputedMix = mixFour( floorIntX, y, z, t );
return noise1dInt32( precomputedMix );
}
else {
unsigned long ceilIntX = floorIntX + 1;
// cosine interpolation
// from http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
double ft = ( x - floorX ) * M_PI;
double f = ( 1 - cos( ft ) ) * .5;
// need to pre-store intermediate values because noise4dInt32 is a
// macro
// thus, we end up calling the noise1dInt32 function instead
unsigned long precomputedMix = mixFour( floorIntX, y, z, t );
double valueAtFloor = noise1dInt32( precomputedMix );
precomputedMix = mixFour( ceilIntX, y, z, t );
double valueAtCeiling = noise1dInt32( precomputedMix );
return linearInterpolation( f, valueAtFloor, valueAtCeiling );
}
}
/**
* Blends 4d discrete (integer-parameter) noise function along 2 dimensions
* with 2 fixed integer parameters.
*/
double blendNoise2d( double x,
double y,
unsigned long z,
unsigned long t ) {
double floorY = floor( y );
unsigned long floorIntY = (unsigned long)floorY;
if( floorY == y ) {
return blendNoise1d( x, floorIntY, z, t );
}
else {
unsigned long ceilIntY = floorIntY + 1;
// cosine interpolation
// from http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
double ft = ( y - floorY ) * M_PI;
double f = ( 1 - cos( ft ) ) * .5;
return ( f ) * blendNoise1d( x, ceilIntY, z, t ) +
( 1 - f ) * blendNoise1d( x, floorIntY, z, t );
}
}
/**
* Blends 4d discrete (integer-parameter) noise function along 3 dimensions
* with 1 fixed integer parameters.
*/
double blendNoise3d( double x,
double y,
double z,
unsigned long t ) {
double floorZ = floor( z );
unsigned long floorIntZ = (unsigned long)floorZ;
if( floorZ == z ) {
return blendNoise2d( x, y, floorIntZ, t );
}
else {
unsigned long ceilIntZ = floorIntZ + 1;
// cosine interpolation
// from http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
double ft = ( z - floorZ ) * M_PI;
double f = ( 1 - cos( ft ) ) * .5;
return ( f ) * blendNoise2d( x, y, ceilIntZ, t ) +
( 1 - f ) * blendNoise2d( x, y, floorIntZ, t );
}
}
/**
* Blends 4d discrete (integer-parameter) noise function along 4 dimensions.
*/
double noise4d( double x,
double y,
double z,
double t ) {
double floorT = floor( t );
unsigned long floorIntT = (unsigned long)floorT;
if( floorT == t ) {
return blendNoise3d( x, y, z, floorIntT );
}
else {
unsigned long ceilIntT = floorIntT + 1;
// cosine interpolation
// from http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
double ft = ( t - floorT ) * M_PI;
double f = ( 1 - cos( ft ) ) * .5;
return ( f ) * blendNoise3d( x, y, z, ceilIntT ) +
( 1 - f ) * blendNoise3d( x, y, z, floorIntT );
}
}

View file

@ -0,0 +1,97 @@
#ifndef LANDSCAPE_INCLUDED
#define LANDSCAPE_INCLUDED
/**
* Gets height samples from an "infinite" fractal landscape.
* The landscape can change over time by varying t.
*
* @param x the x coordinate of the sample.
* @param y the y coordinate of the sample.
* @param t the time of the sample.
* @param baseFrequency the frequency to use for the lowest detail component.
* @param inRoughness the roughness of the landscape (how much high frequencies
* are factored in). Should be in the range [0..1] with 0 making a very
* smooth landscape and 1 making a very rough landscape.
* @param detail the detail level. Larger numbers result in more
* detail. Defaults to 10.
*
* @return the height of the landscape at the sample point/time.
*/
double landscape( double inX, double inY, double inT,
double inBaseFrequency, double inRoughness,
int inDetail = 10 );
/**
* Samples height of a landscape that varies in roughness over the xy plane.
*
* @params same as for landscape, except:
* @param inRoughnessChangeFrequency the rate at which roughness changes
* over space. Should, in general, be less than inBaseFrequency.
* @param inMinRoughness the minimum roughness value, in the range [0..1].
* @param inMaxRoughness the maximum roughness value, in the range [0..1].
*
* @return same as for landscape.
*/
double variableRoughnessLandscape( double inX, double inY, double inT,
double inBaseFrequency,
double inRoughnessChangeFrequency,
double inMinRoughness,
double inMaxRoughness,
int inDetail );
/**
* Computes linearly-blended random values in the range [-1..1] from a
* 4d parameterized noise space.
*
* @param x, y, z, t the 4d floating-point coordinates.
*
* @return a blended random value in the range [-1..1].
*/
double noise4d( double x,
double y,
double z,
double t );
/**
* Gets a set of randomly-chosen (though stable) points in a given
* region of the landscape.
*
* @param inStartX, inEndX the x region.
* @param inStartY, inEndY the y region.
* @param inT the time.
* @param inSampleStepSize the step size in the sample grid.
* Higher values are faster but result in sparser distributions of points.
* @param inDensity the density of points, in the range [0,1].
* @param outXCoordinates pointer to where array of x coordinates should
* be returned. Array must be destroyed by caller.
* @param outYCoordinates pointer to where array of x coordinates should
* be returned. Array must be destroyed by caller.
*
* @return the number of points (the length of outXCoordinates).
*/
int getRandomPoints( double inStartX, double inEndX,
double inStartY, double inEndY,
double inT,
double inSampleStepSize,
double inDensity,
double **outXCoordinates,
double **outYCoordinates );
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

View file

@ -0,0 +1,798 @@
/*
* Modification History
*
* 2007-September-25 Jason Rohrer
* Created.
*/
#include "landscape.h"
#include "minorGems/graphics/Image.h"
#include "minorGems/graphics/converters/TGAImageConverter.h"
#include "minorGems/io/file/File.h"
#include "minorGems/io/file/FileInputStream.h"
// #include "minorGems/system/Thread.h"
#include <math.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
// for memcpy
#include <string.h>
// size of game image
int width = 100;
int height = 16;
// size of screen
int screenWidth = 640;
int screenHeight = 480;
// blow-up factor when projecting game onto screen
int blowUpFactor = 6;
//int blowUpFactor = 1;
char fullScreen = false;
double timeDelta = -0.1;
//double timeDelta = -0.0;
int mainFunction();
// must do this to prevent WinMain linker errors on win32
int main() {
mainFunction();
}
#include <SDL/SDL.h>
// the joystick to read from, or NULL if there's no available joystick
SDL_Joystick *joystick;
void catch_int(int sig_num) {
printf( "Quiting...\n" );
SDL_Quit();
exit( 0 );
signal( SIGINT, catch_int );
}
void blowupOntoScreen( Uint32 *inImage, int inWidth, int inHeight,
int inBlowFactor, SDL_Surface *inScreen ) {
int newWidth = inBlowFactor * inWidth;
int newHeight = inBlowFactor * inHeight;
int yOffset = ( inScreen->h - newHeight ) / 2;
int xOffset = ( inScreen->w - newWidth ) / 2;
int endY = yOffset + newHeight;
int endX = xOffset + newWidth;
Uint32 *pixels = (Uint32 *)( inScreen->pixels );
for( int y=yOffset; y<endY; y++ ) {
int imageY = ( y - yOffset ) / inBlowFactor;
for( int x=xOffset; x<endX; x++ ) {
int imageX = ( x - xOffset ) / inBlowFactor;
pixels[ y * inScreen->w + x ] =
inImage[ imageY * inWidth + imageX ];
}
}
}
// values in range 0..1
Image *tileImage;
int imageW, imageH;
// dimensions of one tile. TileImage contains 13 tiles, stacked vertically,
// with blank lines between tiles
int tileW = 8;
int tileH = 8;
int numTileSets;
// how wide the swath of a world is that uses a given tile set
int tileSetWorldSpan = 200;
// overlap during tile set transition
int tileSetWorldOverlap = 50;
// optimization (found with profiler)
// values in range 0..255
double *tileRed;
double *tileGreen;
double *tileBlue;
Image *spriteImage;
int spriteW = 8;
int spriteH = 8;
double *spriteRed;
double *spriteGreen;
double *spriteBlue;
int currentSpriteIndex = 2;
double playerX, playerY;
int playerRadius = spriteW / 2;
int seed = time( NULL );
inline char isBlocked( int inX, int inY ) {
// reduce to grid coordinates
int gridX = inX / tileW;
int gridY = inY / tileH;
// wall along far left and top
if( gridX <=0 || gridY <= 0 ) {
return true;
}
// make a grid of empty spaces from which blocks can be
// removed below to make a maze
if( gridX % 2 !=0 && gridY % 2 != 0 ) {
return false;
}
// blocks get denser as y increases
double threshold = 1 - gridY / 20.0;
double randValue = noise4d( gridX, gridY, seed, 0 );
return randValue > threshold;
}
char isSpriteTransparent( int inSpriteIndex ) {
// take transparent color from corner
return
spriteRed[ inSpriteIndex ] == spriteRed[ 0 ]
&&
spriteGreen[ inSpriteIndex ] == spriteGreen[ 0 ]
&&
spriteBlue[ inSpriteIndex ] == spriteBlue[ 0 ];
}
Uint32 sampleFromWorld( int inX, int inY, double inWeight = 1.0 ) {
// consider sampling from sprite
// player position centered on sprint left-to-right
int spriteX = (int)( inX - playerX + spriteW / 2 );
// player position at sprite's feet
int spriteY = (int)( inY - playerY + spriteH - 1);
if( spriteX >= 0 && spriteX < spriteW
&&
spriteY >= 0 && spriteY < spriteH ) {
int spriteIndex = spriteY * spriteW + spriteX;
// skip to appropriate sprite fram
spriteIndex += currentSpriteIndex * spriteW * ( spriteH + 1 );
if( !isSpriteTransparent( spriteIndex ) ) {
unsigned char r =
(unsigned char)(
inWeight * spriteRed[ spriteIndex ] );
unsigned char g =
(unsigned char)(
inWeight * spriteGreen[ spriteIndex ] );
unsigned char b =
(unsigned char)(
inWeight * spriteBlue[ spriteIndex ] );
return r << 16 | g << 8 | b;
}
}
int tileIndex;
if( !isBlocked( inX, inY ) ) {
// empty tile
tileIndex = 0;
}
else {
int neighborsBlockedBinary = 0;
if( isBlocked( inX, inY - tileH ) ) {
// top
neighborsBlockedBinary = neighborsBlockedBinary | 1;
}
if( isBlocked( inX + tileW, inY ) ) {
// right
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 1;
}
if( isBlocked( inX, inY + tileH ) ) {
// bottom
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 2;
}
if( isBlocked( inX - tileW, inY ) ) {
// left
neighborsBlockedBinary = neighborsBlockedBinary | 1 << 3;
}
// skip empty tile, treat as tile index
neighborsBlockedBinary += 1;
tileIndex = neighborsBlockedBinary;
}
// pick a tile set
int netWorldSpan = tileSetWorldSpan + tileSetWorldOverlap;
int tileSet = inX / netWorldSpan;
int overhang = inX % netWorldSpan;
if( inX < 0 ) {
// fix to a constant tile set below 0
overhang = 0;
tileSet = 0;
}
// is there blending with next tile set?
int blendTileSet = tileSet + 1;
double blendWeight = 0;
if( overhang > tileSetWorldSpan ) {
blendWeight = ( overhang - tileSetWorldSpan ) /
(double) tileSetWorldOverlap;
}
// else 100% blend of our first tile set
tileSet = tileSet % numTileSets;
blendTileSet = blendTileSet % numTileSets;
// make sure not negative
if( tileSet < 0 ) {
tileSet += numTileSets;
}
if( blendTileSet < 0 ) {
blendTileSet += numTileSets;
}
// sample from tile image
int imageY = inY % tileH;
int imageX = inX % tileW;
if( imageX < 0 ) {
imageX += tileW;
}
if( imageY < 0 ) {
imageY += tileH;
}
// offset to top left corner of tile
int tileImageOffset = tileIndex * ( tileH + 1 ) * imageW
+ tileSet * (tileW + 1);
int blendTileImageOffset = tileIndex * ( tileH + 1 ) * imageW
+ blendTileSet * (tileW + 1);
int imageIndex = tileImageOffset + imageY * imageW + imageX;
int blendImageIndex = blendTileImageOffset + imageY * imageW + imageX;
unsigned char r =
(unsigned char)(
inWeight * (
(1-blendWeight) * tileRed[ imageIndex ] +
blendWeight * tileRed[ blendImageIndex ] ) );
unsigned char g =
(unsigned char)(
inWeight * (
(1-blendWeight) * tileGreen[ imageIndex ] +
blendWeight * tileGreen[ blendImageIndex ] ) );
unsigned char b =
(unsigned char)(
inWeight * (
(1-blendWeight) * tileBlue[ imageIndex ] +
blendWeight * tileBlue[ blendImageIndex ] ) );
return r << 16 | g << 8 | b;
}
char getKeyDown( int inKeyCode ) {
SDL_PumpEvents();
Uint8 *keys = SDL_GetKeyState( NULL );
return keys[ inKeyCode ] == SDL_PRESSED;
}
char getHatDown( Uint8 inHatPosition ) {
if( joystick == NULL ) {
return false;
}
SDL_JoystickUpdate();
Uint8 hatPosition = SDL_JoystickGetHat( joystick, 1 );
if( hatPosition & inHatPosition ) {
return true;
}
else {
return false;
}
}
Image *readTGA( char *inFileName ) {
File tileFile( NULL, inFileName );
FileInputStream tileStream( &tileFile );
TGAImageConverter converter;
return converter.deformatImage( &tileStream );
}
int mainFunction() {
// let catch_int handle interrupt (^c)
signal( SIGINT, catch_int );
// read in map tile
tileImage = readTGA( "tileSet.tga" );
imageW = tileImage->getWidth();
imageH = tileImage->getHeight();
numTileSets = (imageW + 1) / (tileW + 1);
int imagePixelCount = imageW * imageH;
tileRed = new double[ imagePixelCount ];
tileGreen = new double[ imagePixelCount ];
tileBlue = new double[ imagePixelCount ];
for( int i=0; i<imagePixelCount; i++ ) {
tileRed[i] = 255 * tileImage->getChannel(0)[ i ];
tileGreen[i] = 255 * tileImage->getChannel(1)[ i ];
tileBlue[i] = 255 * tileImage->getChannel(2)[ i ];
}
// read in map tile
spriteImage = readTGA( "characterSprite.tga" );
imagePixelCount = spriteImage->getWidth() * spriteImage->getHeight();
spriteRed = new double[ imagePixelCount ];
spriteGreen = new double[ imagePixelCount ];
spriteBlue = new double[ imagePixelCount ];
for( int i=0; i<imagePixelCount; i++ ) {
spriteRed[i] = 255 * spriteImage->getChannel(0)[ i ];
spriteGreen[i] = 255 * spriteImage->getChannel(1)[ i ];
spriteBlue[i] = 255 * spriteImage->getChannel(2)[ i ];
}
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK |
SDL_INIT_NOPARACHUTE ) < 0 ) {
printf( "Couldn't initialize SDL: %s\n", SDL_GetError() );
return -1;
}
SDL_ShowCursor( SDL_DISABLE );
Uint32 flags = SDL_HWSURFACE | SDL_DOUBLEBUF;
if( fullScreen ) {
flags = flags | SDL_FULLSCREEN;
}
SDL_Surface *screen = SDL_SetVideoMode( screenWidth, screenHeight,
32,
flags );
if ( screen == NULL ) {
printf( "Couldn't set %dx%dx32 video mode: %s\n", screenWidth,
screenHeight,
SDL_GetError() );
return-1;
}
// try to open joystick
int numJoysticks = SDL_NumJoysticks();
printf( "Found %d joysticks\n", numJoysticks );
if( numJoysticks > 0 ) {
// open first one by default
joystick = SDL_JoystickOpen( 1 );
if( joystick == NULL ) {
printf( "Couldn't open joystick 1: %s\n", SDL_GetError() );
}
int numHats = SDL_JoystickNumHats( joystick );
if( numHats <= 0 ) {
printf( "No d-pad found on joystick\n" );
SDL_JoystickClose( joystick );
joystick = NULL;
}
}
else {
joystick = NULL;
}
Uint32 *pixels = (Uint32 *)( screen->pixels );
Uint32 *gameImage = new Uint32[ width * height ];
// first, fill the whole thing with black
SDL_FillRect(screen, NULL, 0x00000000);
// small area in center that we actually draw in, black around it
int yOffset = ( screenHeight - height * blowUpFactor ) / 2;
int xOffset = ( screenWidth - width * blowUpFactor ) / 2;
double dX = 0;
double dY = 0;
int frameCount = 0;
unsigned long startTime = time( NULL );
char done = false;
double maxWorldX = 0;
double minWorldX = 0;
// start player position
playerX = tileW;
//playerX = 0;
dX = tileW;
playerY = 0 + height/2;
dY = 0;
while( !done ) {
char someBlocksDrawn = false;
for( int y=0; y<height; y++ ) {
for( int x=0; x<width; x++ ) {
// offset into center
int gameImageIndex = y * width + x;
//int worldX = (int)( pow( x / 2.0, 1.4 ) );
// compression based on distance of pixel column from player
double trueDistanceFromPlayer = dX + x - playerX;
double maxDistance = width - 1;
// cap it so that we don't force tan into infinity below
double cappedDistanceFromPlayer = trueDistanceFromPlayer;
if( cappedDistanceFromPlayer > maxDistance ) {
cappedDistanceFromPlayer = maxDistance;
}
if( cappedDistanceFromPlayer < -maxDistance ) {
cappedDistanceFromPlayer = -maxDistance;
}
// the world position we will sample from
double worldX = x;
// zone around player where no x compression happens
int noCompressZone = 10;
if( trueDistanceFromPlayer > noCompressZone ) {
worldX =
x +
//(width/8) *
// use true distance as a factor so that compression
// continues at constant rate after we pass capped
// distance
// otherwise, compression stops after capped distance
// Still... constant rate looks weird, so avoid
// it by not letting it pass capped distance
trueDistanceFromPlayer / 2 *
( pow( tan( ( ( cappedDistanceFromPlayer -
noCompressZone ) /
(double)( width - noCompressZone ) ) *
M_PI / 2 ), 2) );
/*
trueDistanceFromPlayer / 2 *
( tan( ( cappedDistanceFromPlayer /
(double)( width - 0.5 ) ) * M_PI / 2 ) );
*/
// simpler formula
// actually, this does not approach 0 as
// cappedDistanceFromPlayer approaches 0, so use tan
// instead
// ( trueDistanceFromPlayer / 2 ) * 100
// / pow( ( width - cappedDistanceFromPlayer ), 1.6 );
}
else if( trueDistanceFromPlayer < - noCompressZone ) {
worldX =
x +
//(width/8) *
trueDistanceFromPlayer / 2 *
( pow( tan( ( ( - cappedDistanceFromPlayer -
noCompressZone ) /
(double)( width - noCompressZone ) ) *
M_PI / 2 ), 2) );
/*
trueDistanceFromPlayer / 2 *
( tan( ( - cappedDistanceFromPlayer /
(double)( width - 0.5 ) ) * M_PI / 2 ) );
*/
//( trueDistanceFromPlayer / 2 ) * 50
/// ( width + cappedDistanceFromPlayer );
}
else {
// inside no-compresison zone
worldX = x;
}
//int worldX = x;
worldX += dX;
if( worldX > maxWorldX ) {
maxWorldX = worldX;
}
if( worldX < minWorldX ) {
minWorldX = worldX;
}
int worldY = (int)floor( y + dY );
// linear interpolation of two samples for worldX
int intWorldX = (int)floor( worldX );
double bWeight = worldX - intWorldX;
double aWeight = 1 - bWeight;
Uint32 sampleA =
sampleFromWorld( intWorldX, worldY, aWeight );
Uint32 sampleB =
sampleFromWorld( intWorldX + 1, worldY, bWeight );
Uint32 combined = sampleB + sampleA;
gameImage[ y * width + x ] = combined;
}
}
// check if we need to lock the screen
if( SDL_MUSTLOCK( screen ) ) {
if( SDL_LockSurface( screen ) < 0 ) {
printf( "Couldn't lock screen: %s\n", SDL_GetError() );
}
}
blowupOntoScreen( gameImage, width, height, blowUpFactor, screen );
// unlock the screen if necessary
if ( SDL_MUSTLOCK(screen) ) {
SDL_UnlockSurface(screen);
}
if( ( screen->flags & SDL_DOUBLEBUF ) == SDL_DOUBLEBUF ) {
// need to flip buffer
SDL_Flip( screen );
printf( "double\n" );
}
else {
// just update center
//SDL_UpdateRect( screen, yOffset, xOffset, width, height );
SDL_Flip( screen );
}
int moveDelta = 1;
if( getKeyDown( SDLK_LEFT ) || getHatDown( SDL_HAT_LEFT ) ) {
if( currentSpriteIndex == 6 ) {
currentSpriteIndex = 7;
}
else {
currentSpriteIndex = 6;
}
if( !isBlocked( (int)( playerX - moveDelta ), (int)playerY ) ) {
playerX -= moveDelta;
if( playerX < 0 ) {
// undo
playerX += moveDelta;
}
else {
// update screen position
dX -= moveDelta;
}
}
}
else if( getKeyDown( SDLK_RIGHT ) || getHatDown( SDL_HAT_RIGHT )) {
if( currentSpriteIndex == 2 ) {
currentSpriteIndex = 3;
}
else {
currentSpriteIndex = 2;
}
if( !isBlocked( (int)( playerX + moveDelta ), (int)playerY ) ) {
dX += moveDelta;
playerX += moveDelta;
}
}
else if( getKeyDown( SDLK_UP ) || getHatDown( SDL_HAT_UP ) ) {
if( currentSpriteIndex == 0 ) {
currentSpriteIndex = 1;
}
else {
currentSpriteIndex = 0;
}
if( !isBlocked( (int)playerX, (int)( playerY - moveDelta ) ) ) {
playerY -= moveDelta;
if( playerY < 0 ) {
// undo
playerY += moveDelta;
}
else {
// update screen position
dY -= moveDelta;
}
}
}
else if( getKeyDown( SDLK_DOWN ) || getHatDown( SDL_HAT_DOWN )) {
if( currentSpriteIndex == 4 ) {
currentSpriteIndex = 5;
}
else {
currentSpriteIndex = 4;
}
if( !isBlocked( (int)playerX, (int)( playerY + moveDelta ) ) ) {
dY += moveDelta;
playerY += moveDelta;
}
}
// check for events to quit
SDL_Event event;
while( SDL_PollEvent(&event) ) {
switch( event.type ) {
case SDL_KEYDOWN:
switch( event.key.keysym.sym ) {
case SDLK_q:
done = true;
break;
}
break;
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
//t +=0.25;
frameCount ++;
// player position on screen inches forward
dX += timeDelta;
//dX -= 1;
// stop after player has gone off right end of screen
if( playerX - dX > width ) {
dX = playerX - width;
}
}
unsigned long netTime = time( NULL ) - startTime;
double frameRate = frameCount / (double)netTime;
printf( "Max world x = %f\n", maxWorldX );
printf( "Min world x = %f\n", minWorldX );
printf( "Frame rate = %f fps (%d frames)\n", frameRate, frameCount );
fflush( stdout );
delete tileImage;
delete [] tileRed;
delete [] tileGreen;
delete [] tileBlue;
delete spriteImage;
delete [] spriteRed;
delete [] spriteGreen;
delete [] spriteBlue;
if( joystick != NULL ) {
SDL_JoystickClose( joystick );
}
SDL_Quit();
}

View file

@ -0,0 +1,110 @@
// FIXME:
// why does this end up with a blank, white screen after 5 seconds
// while the demo code (testsprite) works fine?
// Does it only happen on win32
#include <math.h>
#include <signal.h>
#include <stdlib.h>
// for memcpy
#include <string.h>
#include <signal.h>
#include <stdio.h>
void catch_int(int sig_num) {
printf( "Quiting...\n" );
//currentStep = numSteps;
exit( 0 );
signal( SIGINT, catch_int );
}
// if SDL.h is included before our main function, the linker complains
// about missing WinMain
// This fixes it
int mainFunction();
int main() {
mainFunction();
}
#include <SDL/SDL.h>
int mainFunction() {
// let catch_int handle interrupt (^c)
signal( SIGINT, catch_int );
int w = 640;
int h = 480;
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE ) < 0 ) {
printf( "Couldn't initialize SDL: %s\n", SDL_GetError() );
return -1;
}
SDL_Surface *screen = SDL_SetVideoMode( w, h,
32,
SDL_SWSURFACE );
if ( screen == NULL ) {
printf( "Couldn't set %dx%dx32 video mode: %s\n", w, h,
SDL_GetError() );
return-1;
}
Uint32 *buffer = (Uint32 *)( screen->pixels );
char white = false;
char done = false;
while( !done ) {
if( white ) {
SDL_FillRect(screen, NULL, 0x00FFFFFF);
}
else {
SDL_FillRect(screen, NULL, 0x00000000);
}
/*
for( int y=0; y<h; y++ ) {
for( int x=0; x<w; x++ ) {
if( white ) {
buffer[ y * w + x ] = 0x00FFFFFF;
}
else {
buffer[ y * w + x ] = 0x00000000;
}
}
}
*/
white = ! white;
//SDL_UpdateRect( screen, 0, 0, w, h );
SDL_Flip( screen );
// check for events to quit
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_KEYDOWN:
/* Any keypress quits the app... */
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB