828 lines
21 KiB
C
828 lines
21 KiB
C
|
#include "pch.c"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <time.h>
|
||
|
#include "mazedlg.h"
|
||
|
#include <assert.h>
|
||
|
|
||
|
MazeView vw;
|
||
|
MazeSolution sol;
|
||
|
|
||
|
MazeOptions maze_options =
|
||
|
{
|
||
|
FALSE, // depth_test
|
||
|
RENDER_FLAT, // render mode (WALLS)
|
||
|
RENDER_FLAT, // render mode (FLOOR)
|
||
|
RENDER_FLAT, // render mode (CEILING)
|
||
|
FALSE, // frame_count
|
||
|
FALSE, // top_view
|
||
|
TRUE, // eye_view
|
||
|
FALSE, // single_step
|
||
|
FALSE, // all_alpha
|
||
|
FALSE, // bDither
|
||
|
1 // nrats
|
||
|
};
|
||
|
|
||
|
float gfAspect = 1.0f; // aspect ratio
|
||
|
|
||
|
#define SST_NEW_MAZE 0
|
||
|
#define SST_MAZE_GROW 1
|
||
|
#define SST_SOLVING 2
|
||
|
#define SST_MAZE_SHRINK 3
|
||
|
#define SST_ROTATE 4
|
||
|
|
||
|
int solve_state = SST_NEW_MAZE;
|
||
|
|
||
|
// Table of textures used. The first entries contain 1 texture for each main
|
||
|
// surface, followed by textures used for various objects
|
||
|
TEXTURE all_textures[NUM_TEXTURES];
|
||
|
|
||
|
// Environment associated with the texture (repetition, palette rotation,..)
|
||
|
// For now, have one for each of the textures in all_textures. But, this
|
||
|
// could be a per-object thing.
|
||
|
TEX_ENV gTexEnv[NUM_TEXTURES];
|
||
|
|
||
|
// texture environment mode
|
||
|
int gTexEnvMode;
|
||
|
|
||
|
// Texture resources for the main surfaces
|
||
|
TEX_RES gTexResSurf[NUM_DEF_SURFACE_TEXTURES] = {
|
||
|
{TEX_BMP, IDB_BRICK}, // default textures
|
||
|
{TEX_BMP, IDB_WOOD},
|
||
|
{TEX_BMP, IDB_CASTLE},
|
||
|
{TEX_A8, IDB_CURL4}, // mandelbrot textures
|
||
|
{TEX_A8, IDB_BHOLE4},
|
||
|
{TEX_A8, IDB_SNOWFLAK},
|
||
|
{TEX_A8, IDB_SWIRLX4}
|
||
|
};
|
||
|
|
||
|
// Texture resources for objects
|
||
|
TEX_RES gTexResObject[NUM_OBJECT_TEXTURES] = {
|
||
|
{TEX_A8, IDB_START},
|
||
|
{TEX_A8, IDB_END},
|
||
|
{TEX_A8, IDB_RAT},
|
||
|
{TEX_A8, IDB_AD},
|
||
|
{TEX_BMP, IDB_COVER}
|
||
|
};
|
||
|
SSContext gssc;
|
||
|
|
||
|
void maze_Init( void *data );
|
||
|
void RotateTexturePalettes( TEX_ENV *pTexEnv, int count, int iRot );
|
||
|
|
||
|
enum {
|
||
|
TIMER_START = 0,
|
||
|
TIMER_STOP
|
||
|
};
|
||
|
|
||
|
void Draw(void)
|
||
|
{
|
||
|
GLbitfield mask;
|
||
|
|
||
|
mask = 0;
|
||
|
if (maze_options.depth_test)
|
||
|
{
|
||
|
mask |= GL_DEPTH_BUFFER_BIT;
|
||
|
}
|
||
|
if (maze_options.render[FLOOR] == RENDER_NONE ||
|
||
|
maze_options.render[CEILING] == RENDER_NONE ||
|
||
|
maze_options.render[WALLS] == RENDER_NONE ||
|
||
|
maze_height < 1.0f)
|
||
|
{
|
||
|
mask |= GL_COLOR_BUFFER_BIT;
|
||
|
}
|
||
|
if (mask != 0)
|
||
|
{
|
||
|
glClear(mask);
|
||
|
}
|
||
|
|
||
|
// Rotate the palettes of any paletted texures by 1
|
||
|
RotateTexturePalettes( gTexEnv, NUM_TEXTURES, 1 );
|
||
|
|
||
|
if (maze_options.eye_view)
|
||
|
{
|
||
|
DrawMaze(&vw);
|
||
|
}
|
||
|
|
||
|
if (maze_options.top_view)
|
||
|
{
|
||
|
DrawTopView(&vw);
|
||
|
}
|
||
|
|
||
|
glFlush();
|
||
|
}
|
||
|
|
||
|
MazeGoal maze_goals[MAX_GOALS];
|
||
|
int ngoals;
|
||
|
|
||
|
Object special_obj[MAX_SPECIALS];
|
||
|
|
||
|
#define MAX_LETTERS 3
|
||
|
Object letters_obj[MAX_LETTERS];
|
||
|
|
||
|
typedef struct _Rat
|
||
|
{
|
||
|
Object obj;
|
||
|
MazeView vw;
|
||
|
MazeSolution sol;
|
||
|
} Rat;
|
||
|
Rat rats[MAX_RATS];
|
||
|
|
||
|
void NewMazeList(void)
|
||
|
{
|
||
|
glNewList(maze_walls_list, GL_COMPILE);
|
||
|
DrawMazeWalls();
|
||
|
glEndList();
|
||
|
}
|
||
|
|
||
|
void UpdateRatPosition(Rat *rat)
|
||
|
{
|
||
|
MoveObject(&rat->obj, rat->vw.pos.x, rat->vw.pos.y);
|
||
|
// Invert the angle because view angles move opposite to
|
||
|
// object angles
|
||
|
rat->obj.ang = FaAdd(0, -rat->vw.ang);
|
||
|
}
|
||
|
|
||
|
// Simple routines to pick cells at random while guaranteeing
|
||
|
// that those cells are unoccupied
|
||
|
|
||
|
static int rnd_cells[MAZE_CELLS];
|
||
|
static int nrnd_cells;
|
||
|
|
||
|
void InitRandomCells(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
nrnd_cells = MAZE_CELLS;
|
||
|
for (i = 0; i < nrnd_cells; i++)
|
||
|
{
|
||
|
rnd_cells[i] = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PickRandomCell(IntPt2 *pos)
|
||
|
{
|
||
|
int idx, t;
|
||
|
|
||
|
#if DBG
|
||
|
if (nrnd_cells == 0)
|
||
|
{
|
||
|
MessageBox(GetDesktopWindow(), TEXT("Out of random cells"),
|
||
|
NULL, MB_OK);
|
||
|
pos->x = 0;
|
||
|
pos->y = 0;
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
idx = rand() % nrnd_cells;
|
||
|
nrnd_cells--;
|
||
|
t = rnd_cells[idx];
|
||
|
rnd_cells[idx] = rnd_cells[nrnd_cells];
|
||
|
pos->x = t % MAZE_GRID;
|
||
|
pos->y = t / MAZE_GRID;
|
||
|
}
|
||
|
|
||
|
void RemoveRandomCell(IntPt2 *pos)
|
||
|
{
|
||
|
int i, idx;
|
||
|
|
||
|
for (i = 0; i < nrnd_cells; i++)
|
||
|
{
|
||
|
idx = rnd_cells[i];
|
||
|
if ((idx % MAZE_GRID) == pos->x &&
|
||
|
(idx / MAZE_GRID) == pos->y)
|
||
|
{
|
||
|
nrnd_cells--;
|
||
|
rnd_cells[i] = rnd_cells[nrnd_cells];
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NewMaze(void)
|
||
|
{
|
||
|
IntPt2 cell, start_cell;
|
||
|
int i, nspecials, nads;
|
||
|
static BOOL firstMaze = TRUE;
|
||
|
|
||
|
// If not in full screen mode, move the maze window around after it's solved
|
||
|
if( !gbTurboMode && !firstMaze )
|
||
|
ss_RandomWindowPos();
|
||
|
|
||
|
InitRandomCells();
|
||
|
|
||
|
if (!InitMaze(&start_cell, maze_goals, &ngoals))
|
||
|
{
|
||
|
printf("InitMaze failed\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
RemoveRandomCell(&start_cell);
|
||
|
cell.x = maze_goals[GOAL_END].clx;
|
||
|
cell.y = maze_goals[GOAL_END].cly;
|
||
|
RemoveRandomCell(&cell);
|
||
|
|
||
|
nspecials = rand() % MAX_SPECIALS;
|
||
|
for (i = 0; i < nspecials; i++)
|
||
|
{
|
||
|
PickRandomCell(&cell);
|
||
|
maze_goals[ngoals].clx = cell.x;
|
||
|
maze_goals[ngoals].cly = cell.y;
|
||
|
maze_goals[ngoals].user = &special_obj[i];
|
||
|
|
||
|
special_obj[i].w = FMAZE_CELL_SIZE/4;
|
||
|
special_obj[i].h = FxFltVal(.25);
|
||
|
special_obj[i].z = special_obj[i].h;
|
||
|
special_obj[i].col = 15;
|
||
|
special_obj[i].draw_style = DRAW_SPECIAL;
|
||
|
special_obj[i].draw_arg = rand() % SPECIAL_ARG_COUNT;
|
||
|
special_obj[i].ang = FaDeg(0);
|
||
|
special_obj[i].user1 = (rand() % 6)+2;
|
||
|
special_obj[i].user2 = rand() % 5;
|
||
|
special_obj[i].user3 = 0;
|
||
|
PlaceObject(&special_obj[i],
|
||
|
CellToMfx(maze_goals[ngoals].clx)+FMAZE_CELL_SIZE/2,
|
||
|
CellToMfx(maze_goals[ngoals].cly)+FMAZE_CELL_SIZE/2);
|
||
|
ngoals++;
|
||
|
}
|
||
|
while (i < MAX_SPECIALS)
|
||
|
{
|
||
|
special_obj[i].cell = NULL;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
nads = (rand() % (MAX_LETTERS*2))-MAX_LETTERS+1;
|
||
|
for (i = 0; i < nads; i++)
|
||
|
{
|
||
|
PickRandomCell(&cell);
|
||
|
|
||
|
letters_obj[i].w = FMAZE_CELL_SIZE/3;
|
||
|
letters_obj[i].h = FxFltVal(.33);
|
||
|
letters_obj[i].z = FxFltVal(.5);
|
||
|
letters_obj[i].col = 15;
|
||
|
letters_obj[i].draw_style = DRAW_POLYGON;
|
||
|
letters_obj[i].pTexEnv = &gTexEnv[ TEX_AD ];
|
||
|
letters_obj[i].ang = FaDeg(0);
|
||
|
PlaceObject(&letters_obj[i],
|
||
|
CellToMfx(cell.x)+FMAZE_CELL_SIZE/2,
|
||
|
CellToMfx(cell.y)+FMAZE_CELL_SIZE/2);
|
||
|
}
|
||
|
while (i < MAX_LETTERS)
|
||
|
{
|
||
|
letters_obj[i].cell = NULL;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < maze_options.nrats; i++)
|
||
|
{
|
||
|
PickRandomCell(&cell);
|
||
|
|
||
|
rats[i].obj.w = FMAZE_CELL_SIZE/4;
|
||
|
rats[i].obj.h = FxFltVal(.125);
|
||
|
rats[i].obj.z = rats[i].obj.h;
|
||
|
rats[i].obj.col = 16;
|
||
|
rats[i].obj.draw_style = DRAW_POLYGON;
|
||
|
rats[i].obj.pTexEnv = &gTexEnv[ TEX_RAT ];
|
||
|
SolveMazeStart(&rats[i].vw, &maze_cells[0][0], MAZE_GRID, MAZE_GRID,
|
||
|
&cell, SOL_DIR_LEFT,
|
||
|
NULL, 0,
|
||
|
(rand() % 1000) > 500 ? SOL_TURN_LEFT : SOL_TURN_RIGHT,
|
||
|
&rats[i].sol);
|
||
|
// Need to force this to NULL when a new maze is generated so
|
||
|
// that moving doesn't try to use old maze data
|
||
|
rats[i].obj.cell = NULL;
|
||
|
UpdateRatPosition(&rats[i]);
|
||
|
}
|
||
|
|
||
|
NewMazeList();
|
||
|
|
||
|
SolveMazeStart(&vw, &maze_cells[0][0], MAZE_GRID, MAZE_GRID,
|
||
|
&start_cell, SOL_DIR_RIGHT,
|
||
|
maze_goals, ngoals,
|
||
|
(rand() % 1000) > 500 ? SOL_TURN_LEFT : SOL_TURN_RIGHT,
|
||
|
&sol);
|
||
|
|
||
|
solve_state = SST_MAZE_GROW;
|
||
|
firstMaze = FALSE;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************\
|
||
|
* Step
|
||
|
*
|
||
|
* Main draw proc
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
static MazeGoal *found_goal = NULL;
|
||
|
static int rot_step;
|
||
|
|
||
|
void Step(void *data)
|
||
|
{
|
||
|
int i;
|
||
|
MazeGoal *goal;
|
||
|
|
||
|
switch(solve_state)
|
||
|
{
|
||
|
case SST_NEW_MAZE:
|
||
|
view_rot = 0;
|
||
|
maze_height = 0.0f;
|
||
|
NewMaze();
|
||
|
break;
|
||
|
|
||
|
case SST_SOLVING:
|
||
|
for (i = 0; i < maze_options.nrats; i++)
|
||
|
{
|
||
|
SolveMazeStep(&rats[i].vw, &rats[i].sol);
|
||
|
UpdateRatPosition(&rats[i]);
|
||
|
}
|
||
|
|
||
|
goal = SolveMazeStep(&vw, &sol);
|
||
|
if (goal == &maze_goals[GOAL_END])
|
||
|
{
|
||
|
solve_state = SST_MAZE_SHRINK;
|
||
|
}
|
||
|
else if (goal != NULL)
|
||
|
{
|
||
|
solve_state = SST_ROTATE;
|
||
|
found_goal = goal;
|
||
|
rot_step = 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SST_MAZE_GROW:
|
||
|
maze_height += .025f;
|
||
|
if (maze_height >= 1.0f)
|
||
|
{
|
||
|
solve_state = SST_SOLVING;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SST_MAZE_SHRINK:
|
||
|
maze_height -= .025f;
|
||
|
if (maze_height <= 0.0f)
|
||
|
{
|
||
|
solve_state = SST_NEW_MAZE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SST_ROTATE:
|
||
|
view_rot += 10.0;
|
||
|
if (++rot_step == 18)
|
||
|
{
|
||
|
Object *sp_obj;
|
||
|
|
||
|
sp_obj = (Object *)found_goal->user;
|
||
|
RemoveObject(sp_obj);
|
||
|
|
||
|
solve_state = SST_SOLVING;
|
||
|
ngoals--;
|
||
|
if (found_goal < maze_goals+ngoals)
|
||
|
{
|
||
|
memmove(found_goal, found_goal+1,
|
||
|
sizeof(MazeGoal)*(size_t)((ULONG_PTR)(ngoals-(found_goal-maze_goals))));
|
||
|
}
|
||
|
SolveMazeSetGoals(&sol, maze_goals, ngoals);
|
||
|
found_goal = NULL;
|
||
|
|
||
|
if (view_rot >= 360.0)
|
||
|
{
|
||
|
view_rot = 0.0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
view_rot = 180.0;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Draw();
|
||
|
|
||
|
for (i = 0; i < MAX_SPECIALS; i++)
|
||
|
{
|
||
|
// Increment rotations of any specials still present in the maze
|
||
|
if (special_obj[i].cell != NULL)
|
||
|
{
|
||
|
special_obj[i].ang = FaAdd(special_obj[i].ang,
|
||
|
FaDeg(special_obj[i].user1));
|
||
|
special_obj[i].user3 += special_obj[i].user2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UpdateModes(void)
|
||
|
{
|
||
|
if (maze_options.depth_test)
|
||
|
{
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**************************************************************************\
|
||
|
* Reshape
|
||
|
*
|
||
|
* - called on resize, expose
|
||
|
* - always called on app startup
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void
|
||
|
Reshape(int width, int height, void *data )
|
||
|
{
|
||
|
gfAspect = height == 0 ? 1.0f: (float) width / (float) height;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* VerifyTextureFiles
|
||
|
*
|
||
|
* Check that any user specified textures are valid
|
||
|
* - MUST be called at ss_Init, or any error msgs will not display properly
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void VerifyTextureFiles(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
ss_DisableTextureErrorMsgs();
|
||
|
|
||
|
for (i = 0; i < NUM_SURFACES; i++) {
|
||
|
if( gTexInfo[i].bTex && !gTexInfo[i].bDefTex ) {
|
||
|
if( !ss_VerifyTextureFile( &gTexInfo[i].texFile ) )
|
||
|
// use default texture
|
||
|
gTexInfo[i].bDefTex = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* CalcRep
|
||
|
*
|
||
|
* Figure out repetion based on size.
|
||
|
*
|
||
|
* - Use 128 pixels as a unit repetition reference
|
||
|
* - Size is always a power of 2
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
static int
|
||
|
CalcRep( int size )
|
||
|
{
|
||
|
double pow2;
|
||
|
int pow2ref = 8;
|
||
|
int rep;
|
||
|
|
||
|
pow2 = log((double)size) / log((double)2.0);
|
||
|
rep = 1 + pow2ref - (int)pow2;
|
||
|
return rep;
|
||
|
}
|
||
|
|
||
|
//mf: tradeoff
|
||
|
#define MAX_TEX_DIM 128
|
||
|
//#define MAX_TEX_DIM 256
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* CalcTexRep
|
||
|
*
|
||
|
* Figure out texture repetition based on texture size.
|
||
|
*
|
||
|
* - mf: ? double for walls/ceiling ?
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
static void
|
||
|
CalcTexRep( TEXTURE *pTex, IPOINT2D *pTexRep )
|
||
|
{
|
||
|
if( pTex->width >= MAX_TEX_DIM )
|
||
|
pTexRep->x = 1;
|
||
|
else
|
||
|
pTexRep->x = CalcRep( pTex->width );
|
||
|
|
||
|
if( pTex->height >= MAX_TEX_DIM )
|
||
|
pTexRep->y = 1;
|
||
|
else
|
||
|
pTexRep->y = CalcRep( pTex->height );
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* LoadTextures
|
||
|
*
|
||
|
* Load textures from .bmp files or from embedded resources, using
|
||
|
* global texture info structure.
|
||
|
*
|
||
|
* For now, this also sets render modes, since if texturing is off for a
|
||
|
* surface, we always use RENDER_FLAT
|
||
|
*
|
||
|
* History:
|
||
|
* - Nov. 95 [marcfo] : Creation
|
||
|
* - Jan. 96 [marcfo] : Load surface and object textures separately. The 3
|
||
|
* surface textures occupy the first locations of the all_textures[]
|
||
|
* array, and the object textures follow.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
static void
|
||
|
LoadTextures(void)
|
||
|
{
|
||
|
int i;
|
||
|
TEXTURE *pTex = all_textures;
|
||
|
TEX_ENV *pTexEnv = gTexEnv;
|
||
|
TEX_RES *pTexRes;
|
||
|
|
||
|
assert( (NUM_SURFACES + NUM_OBJECT_TEXTURES) == NUM_TEXTURES );
|
||
|
|
||
|
// load surface textures (wall, floor, ceiling)
|
||
|
|
||
|
for (i = 0; i < NUM_SURFACES; i++, pTex++, pTexEnv++) {
|
||
|
maze_options.render[i] = RENDER_FLAT;
|
||
|
if( gTexInfo[i].bTex ) {
|
||
|
pTexEnv->pTex = pTex;
|
||
|
pTexEnv->bTransp = FALSE;
|
||
|
|
||
|
// Load user or default texture for the surface
|
||
|
|
||
|
if( !gTexInfo[i].bDefTex &&
|
||
|
ss_LoadTextureFile( &gTexInfo[i].texFile, pTex )) {
|
||
|
} else
|
||
|
{
|
||
|
// Load default resource texture
|
||
|
|
||
|
pTexRes = &gTexResSurf[ gTexInfo[i].iDefTex ];
|
||
|
if( !ss_LoadTextureResource( pTexRes, pTex ) )
|
||
|
continue;
|
||
|
|
||
|
if( ss_PalettedTextureEnabled() &&
|
||
|
(pTexRes->type == TEX_A8) )
|
||
|
{
|
||
|
pTexEnv->bPalRot = TRUE;
|
||
|
pTexEnv->iPalRot = ss_iRand( 0xff );
|
||
|
} else
|
||
|
pTexEnv->bPalRot = FALSE;
|
||
|
}
|
||
|
|
||
|
maze_options.render[i] = RENDER_TEXTURED;
|
||
|
|
||
|
// Figure out texture repetition
|
||
|
CalcTexRep( pTex, &pTexEnv->texRep );
|
||
|
// We would have to set texture parameters per object here,
|
||
|
// but we just use default ones already set by ss_LoadTexture*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// load object textures
|
||
|
|
||
|
pTexRes = gTexResObject;
|
||
|
for( i = 0; i < NUM_OBJECT_TEXTURES; i++, pTex++, pTexEnv++, pTexRes++ ) {
|
||
|
if( ss_LoadTextureResource( pTexRes, pTex ) )
|
||
|
pTexEnv->pTex = pTex;
|
||
|
else
|
||
|
pTexEnv->pTex = NULL;
|
||
|
|
||
|
pTexEnv->bTransp = FALSE;
|
||
|
|
||
|
// For now we don't do palrot's on any of the object textures
|
||
|
pTexEnv->bPalRot = FALSE;
|
||
|
// No repetition
|
||
|
pTexEnv->texRep.x = pTexEnv->texRep.y = 1;
|
||
|
}
|
||
|
|
||
|
// Set transparency for some of the textures
|
||
|
ss_SetTextureTransparency( gTexEnv[TEX_START].pTex, 0.42f, FALSE );
|
||
|
ss_SetTextureTransparency( gTexEnv[TEX_END].pTex, 0.4f, FALSE );
|
||
|
ss_SetTextureTransparency( gTexEnv[TEX_AD].pTex, 0.4f, FALSE );
|
||
|
|
||
|
#if 0
|
||
|
// Enough already with the transparency!
|
||
|
ss_SetTextureTransparency( &all_textures[TEX_COVER], 0.6f, FALSE );
|
||
|
ss_SetTextureTransparency( &all_textures[TEX_WALL], 0.5f, FALSE );
|
||
|
#endif
|
||
|
|
||
|
// Enable transparency for some of the texture environments
|
||
|
gTexEnv[TEX_START].bTransp = TRUE;
|
||
|
gTexEnv[TEX_END].bTransp = TRUE;
|
||
|
gTexEnv[TEX_AD].bTransp = TRUE;
|
||
|
}
|
||
|
|
||
|
void UseTextureEnv( TEX_ENV *pTexEnv )
|
||
|
{
|
||
|
static HTEXTURE hCurTex = (HTEXTURE) -1;
|
||
|
HTEXTURE hTex = pTexEnv->pTex;
|
||
|
|
||
|
// We cache the current texture for 'no texture object' case
|
||
|
|
||
|
if( !ss_TextureObjectsEnabled() &&
|
||
|
(hCurTex == hTex) )
|
||
|
return; // same texture, no need to send it down
|
||
|
|
||
|
// Make this texture current
|
||
|
|
||
|
ss_SetTexture( hTex );
|
||
|
|
||
|
// Set texture palette if necessary
|
||
|
|
||
|
if( pTexEnv->bPalRot &&
|
||
|
!ss_TextureObjectsEnabled() &&
|
||
|
ss_PalettedTextureEnabled() ) {
|
||
|
|
||
|
// We need to send down the (rotated) palette
|
||
|
ss_SetTexturePalette( hTex, pTexEnv->iPalRot );
|
||
|
}
|
||
|
|
||
|
hCurTex = hTex;
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* RotateTexturePalettes
|
||
|
*
|
||
|
* If paletted texturing is enabled, go through the supplied list of texture
|
||
|
* environments, and if any have a palette, increment its rotation by the
|
||
|
* supplied iRot value.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void
|
||
|
RotateTexturePalettes( TEX_ENV *pTexEnv, int count, int iRot )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if( !ss_PalettedTextureEnabled() || !pTexEnv )
|
||
|
return;
|
||
|
|
||
|
|
||
|
for( ; count; count--, pTexEnv++ ) {
|
||
|
|
||
|
if( !pTexEnv->pTex || !pTexEnv->pTex->pal )
|
||
|
continue;
|
||
|
|
||
|
if( pTexEnv->bPalRot ) {
|
||
|
// increment palette rotation
|
||
|
pTexEnv->iPalRot += iRot;
|
||
|
if( pTexEnv->iPalRot >= pTexEnv->pTex->pal_size )
|
||
|
pTexEnv->iPalRot = 0;
|
||
|
// Only send down the new palette if texture objects are enabled,
|
||
|
// since otherwise it will be sent down when texture is
|
||
|
// 'made current'
|
||
|
if( ss_TextureObjectsEnabled() ) {
|
||
|
ss_SetTexturePalette( pTexEnv->pTex, pTexEnv->iPalRot );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* InitStretchInfo
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
static void
|
||
|
InitStretchInfo( STRETCH_INFO *pStretch )
|
||
|
{
|
||
|
ISIZE screen;
|
||
|
|
||
|
pStretch->baseWidth = 320;
|
||
|
pStretch->baseHeight = 200;
|
||
|
pStretch->bRatioMode = FALSE;
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* SetFloaterInfo
|
||
|
*
|
||
|
* Set the size and position of the floating child window
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
|
||
|
static void
|
||
|
SetFloaterInfo( ISIZE *pParentSize, CHILD_INFO *pChild )
|
||
|
{
|
||
|
float hdtvAspect = 9.0f / 16.0f;
|
||
|
ISIZE *pChildSize = &pChild->size;
|
||
|
|
||
|
// Set width according to user-specified size
|
||
|
// (giSize range is 0..100)
|
||
|
// set min size as 1/3 parent width
|
||
|
pChildSize->width =
|
||
|
(int) ((0.333f + 2.0f*giSize/300.0f) * pParentSize->width);
|
||
|
|
||
|
// Scale height for hdtv aspect ratio
|
||
|
pChildSize->height = (int) (hdtvAspect * pChildSize->width + 0.5f);
|
||
|
// Ensure height not too big
|
||
|
SS_CLAMP_TO_RANGE2( pChildSize->height, 0, pParentSize->height );
|
||
|
|
||
|
pChild->pos.x = (pParentSize->width - pChildSize->width) / 2;
|
||
|
pChild->pos.y = (pParentSize->height - pChildSize->height) / 2;
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* ss_Init
|
||
|
*
|
||
|
* Initialize - called on first entry into ss.
|
||
|
* Called BEFORE gl is initialized!
|
||
|
* Just do basic stuff here, like set up callbacks, verify dialog stuff, etc.
|
||
|
*
|
||
|
* Fills global SSContext structure with required data, and returns ptr
|
||
|
* to it.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
SSContext *
|
||
|
ss_Init( void )
|
||
|
{
|
||
|
getIniSettings();
|
||
|
|
||
|
VerifyTextureFiles();
|
||
|
|
||
|
// Set callbacks
|
||
|
|
||
|
ss_InitFunc( maze_Init );
|
||
|
ss_UpdateFunc( Step );
|
||
|
ss_ReshapeFunc( Reshape );
|
||
|
|
||
|
gssc.depthType = (maze_options.depth_test) ? SS_DEPTH16 : SS_DEPTH_NONE;
|
||
|
|
||
|
// Currently stretch and floater mutex
|
||
|
gssc.bDoubleBuf = TRUE; // will get turned off if stretch used
|
||
|
if( gbTurboMode ) {
|
||
|
// We stretch out the drawing area to the full size of the main window
|
||
|
gssc.bFloater = FALSE;
|
||
|
gssc.bStretch = TRUE;
|
||
|
InitStretchInfo( &gssc.stretchInfo );
|
||
|
} else {
|
||
|
// A static centered floating window is created in the main window
|
||
|
FLOATER_INFO *pFloater = &gssc.floaterInfo;
|
||
|
|
||
|
gssc.bFloater = TRUE;
|
||
|
gssc.bStretch = FALSE;
|
||
|
pFloater->bMotion = FALSE;
|
||
|
pFloater->ChildSizeFunc = SetFloaterInfo;
|
||
|
}
|
||
|
|
||
|
return &gssc;
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* maze_Init
|
||
|
*
|
||
|
* Initializes OpenGL state
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
void
|
||
|
maze_Init( void *data )
|
||
|
{
|
||
|
float fv4[4];
|
||
|
|
||
|
if (!FxInitialize(FA_TABLE_SIZE, 0))
|
||
|
{
|
||
|
printf("FxInit failed\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
glShadeModel( GL_FLAT );
|
||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||
|
|
||
|
glClearDepth(1);
|
||
|
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||
|
|
||
|
if( (giImageQual == IMAGEQUAL_DEFAULT) || gbTurboMode ) {
|
||
|
maze_options.bDither = FALSE;
|
||
|
glDisable( GL_DITHER );
|
||
|
} else {
|
||
|
maze_options.bDither = TRUE;
|
||
|
glEnable( GL_DITHER );
|
||
|
}
|
||
|
|
||
|
// Load textures and set render modes
|
||
|
LoadTextures();
|
||
|
|
||
|
fv4[0] = MAZE_SIZE/2.0f;
|
||
|
fv4[1] = MAZE_SIZE/2.0f;
|
||
|
fv4[2] = 10.0f;
|
||
|
fv4[3] = 1.0f;
|
||
|
glLightfv(GL_LIGHT0, GL_POSITION, fv4);
|
||
|
glEnable(GL_LIGHT0);
|
||
|
|
||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
|
|
||
|
// Check which texture environment function to use for objects
|
||
|
if( ss_fOnGL11() )
|
||
|
gTexEnvMode = GL_REPLACE;
|
||
|
else
|
||
|
gTexEnvMode = GL_MODULATE;
|
||
|
|
||
|
maze_walls_list = glGenLists(1);
|
||
|
|
||
|
UpdateModes();
|
||
|
}
|