275 lines
6.6 KiB
C
275 lines
6.6 KiB
C
/*
|
|
startuptest.c : Previews Hexen STARTUP screens for GZDoom mods.
|
|
Requires SDL2 and SDL2_mixer.
|
|
(C)2021 Marisa the Magician, UnSX Team.
|
|
Released under the MIT License.
|
|
*/
|
|
|
|
#define _POSIX_C_SOURCE 199309L
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_mixer.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
|
|
SDL_Window *w = 0;
|
|
SDL_Surface *ws = 0, *st = 0;
|
|
|
|
Mix_Music *startmus = 0;
|
|
Mix_Chunk *ticksnd = 0, *dripsnd = 0;
|
|
|
|
#define ST_MAX_NOTCHES 32
|
|
#define ST_NOTCH_WIDTH 16
|
|
#define ST_NOTCH_HEIGHT 23
|
|
#define ST_PROGRESS_X 64
|
|
#define ST_PROGRESS_Y 441
|
|
|
|
#define ST_NETPROGRESS_X 288
|
|
#define ST_NETPROGRESS_Y 32
|
|
#define ST_NETNOTCH_WIDTH 4 // 8 in vanilla hexen
|
|
#define ST_NETNOTCH_HEIGHT 16
|
|
#define ST_MAX_NETNOTCHES 8
|
|
|
|
SDL_Color pal[16], pals[16] = {{0,0,0,0xFF}};
|
|
Uint8 startup[640*480], notch[ST_NOTCH_WIDTH*ST_NOTCH_HEIGHT], netnotch[ST_NETNOTCH_WIDTH*ST_NETNOTCH_HEIGHT];
|
|
int donet = 0;
|
|
|
|
int ReadFiles( const char *s, const char *n, const char *nn )
|
|
{
|
|
FILE *f = fopen(s,"rb");
|
|
if ( !f )
|
|
{
|
|
fprintf(stderr,"Could not open startup file: %s\n",strerror(errno));
|
|
return 1;
|
|
}
|
|
// read palette
|
|
for ( int i=0; i<16; i++ )
|
|
{
|
|
fread(&pal[i],1,3,f);
|
|
pal[i].r <<= 2;
|
|
pal[i].g <<= 2;
|
|
pal[i].b <<= 2;
|
|
pal[i].a = 0xFF;
|
|
}
|
|
// read image
|
|
memset(&startup[0],0,640*480);
|
|
for ( int i=0; i<4; i++ ) for ( int j=0; j<(640*480); j+=8 )
|
|
{
|
|
Uint8 bits;
|
|
fread(&bits,1,1,f);
|
|
startup[j] |= ((bits>>7)&1)<<i;
|
|
startup[j+1] |= ((bits>>6)&1)<<i;
|
|
startup[j+2] |= ((bits>>5)&1)<<i;
|
|
startup[j+3] |= ((bits>>4)&1)<<i;
|
|
startup[j+4] |= ((bits>>3)&1)<<i;
|
|
startup[j+5] |= ((bits>>2)&1)<<i;
|
|
startup[j+6] |= ((bits>>1)&1)<<i;
|
|
startup[j+7] |= (bits&1)<<i;
|
|
}
|
|
fclose(f);
|
|
// read notch
|
|
memset(¬ch[0],0,ST_NOTCH_WIDTH*ST_NOTCH_HEIGHT);
|
|
f = fopen(n,"rb");
|
|
if ( !f )
|
|
{
|
|
fprintf(stderr,"Could not open notch file: %s\n",strerror(errno));
|
|
return 1;
|
|
}
|
|
for ( int i=0; i<(ST_NOTCH_WIDTH*ST_NOTCH_HEIGHT); i+=2 )
|
|
{
|
|
Uint8 bits;
|
|
fread(&bits,1,1,f);
|
|
notch[i] = (bits>>4)&0xF;
|
|
notch[i+1] = bits&0xF;
|
|
}
|
|
fclose(f);
|
|
// read netnotch
|
|
memset(&netnotch[0],0,ST_NETNOTCH_WIDTH*ST_NETNOTCH_HEIGHT);
|
|
if ( !donet ) return 0;
|
|
f = fopen(nn,"rb");
|
|
if ( !f )
|
|
{
|
|
fprintf(stderr,"Could not open netnotch file: %s\n",strerror(errno));
|
|
return 1;
|
|
}
|
|
for ( int i=0; i<(ST_NETNOTCH_WIDTH*ST_NETNOTCH_HEIGHT); i+=2 )
|
|
{
|
|
Uint8 bits;
|
|
fread(&bits,1,1,f);
|
|
netnotch[i] = (bits>>4)&0xF;
|
|
netnotch[i+1] = bits&0xF;
|
|
}
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
enum EStartupState
|
|
{
|
|
STATE_FADEIN,
|
|
STATE_NOTCH,
|
|
STATE_NETNOTCH,
|
|
STATE_WAIT
|
|
};
|
|
|
|
double gametime;
|
|
|
|
#define NANOS_SEC 1000000000L
|
|
|
|
long ticker( void )
|
|
{
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC_RAW,&ts);
|
|
return ts.tv_nsec+ts.tv_sec*NANOS_SEC;
|
|
}
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
if ( (argc > 1) && !strcmp(argv[1],"-n") ) donet = 1;
|
|
if ( argc < 3+donet*2 )
|
|
{
|
|
fprintf(stderr, "usage: startuptest <startup path> <notch path> [music path] [tick path]\n"
|
|
" startuptest -n <startup path> <notch path> <netnotch path> [music path] [tick path] [drip path]\n");
|
|
return 1;
|
|
}
|
|
if ( ReadFiles(argv[1+donet],argv[2+donet],donet?argv[4]:"") )
|
|
return 1;
|
|
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
|
|
w = SDL_CreateWindow("STARTUP TEST",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,480,SDL_WINDOW_SHOWN);
|
|
ws = SDL_GetWindowSurface(w);
|
|
st = SDL_CreateRGBSurface(0,640,480,8,0,0,0,0);
|
|
SDL_SetSurfaceBlendMode(st,SDL_BLENDMODE_NONE);
|
|
SDL_SetPaletteColors(st->format->palette,&pals[0],0,16);
|
|
Mix_Init(MIX_INIT_FLAC|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG);
|
|
Mix_OpenAudio(48000,MIX_DEFAULT_FORMAT,2,4096);
|
|
if ( argc > 3+donet*2 ) startmus = Mix_LoadMUS(argv[3+donet*2]);
|
|
if ( argc > 4+donet*2 ) ticksnd = Mix_LoadWAV(argv[4+donet*2]);
|
|
if ( donet && (argc > 7) ) dripsnd = Mix_LoadWAV(argv[7]);
|
|
SDL_Event e;
|
|
int active = 1;
|
|
long tick, tock;
|
|
if ( startmus ) Mix_PlayMusic(startmus,-1);
|
|
// first blit
|
|
SDL_LockSurface(st);
|
|
memcpy(st->pixels,&startup[0],640*480);
|
|
SDL_UnlockSurface(st);
|
|
int state = STATE_FADEIN;
|
|
int fadestep = 0;
|
|
int ncnt = 0;
|
|
while ( active )
|
|
{
|
|
tick = ticker();
|
|
while ( SDL_PollEvent(&e) ) if ( (e.type == SDL_QUIT)
|
|
|| ((e.type == SDL_KEYDOWN)
|
|
&& (e.key.keysym.sym == SDLK_ESCAPE)) ) active = 0;
|
|
switch ( state )
|
|
{
|
|
case STATE_FADEIN:
|
|
switch ( fadestep )
|
|
{
|
|
case 0:
|
|
if ( gametime > .125 )
|
|
{
|
|
fadestep = 1;
|
|
gametime = 0.;
|
|
}
|
|
break;
|
|
case 1:
|
|
ncnt++;
|
|
for ( int i=0; i<16; i++ )
|
|
{
|
|
pals[i].r = (pal[i].r*ncnt)/8;
|
|
pals[i].g = (pal[i].g*ncnt)/8;
|
|
pals[i].b = (pal[i].b*ncnt)/8;
|
|
}
|
|
SDL_SetPaletteColors(st->format->palette,&pals[0],0,16);
|
|
fadestep = 0;
|
|
gametime = 0.;
|
|
if ( ncnt >= 8 )
|
|
{
|
|
ncnt = 0;
|
|
state = STATE_NOTCH;
|
|
gametime = -1.;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case STATE_NOTCH:
|
|
switch ( fadestep )
|
|
{
|
|
case 0:
|
|
if ( gametime > 1. )
|
|
{
|
|
fadestep++;
|
|
gametime = (float)ncnt/(ST_MAX_NOTCHES);
|
|
gametime = powf(gametime,.25)*.9;
|
|
}
|
|
break;
|
|
case 1:
|
|
if ( ticksnd ) Mix_PlayChannel(0,ticksnd,0);
|
|
SDL_LockSurface(st);
|
|
// draw notch
|
|
for ( int i=0; i<ST_NOTCH_HEIGHT; i++ )
|
|
memcpy((Uint8*)st->pixels+(ST_PROGRESS_Y+i)*640+ST_PROGRESS_X+ST_NOTCH_WIDTH*ncnt,¬ch[0]+ST_NOTCH_WIDTH*i,ST_NOTCH_WIDTH);
|
|
SDL_UnlockSurface(st);
|
|
ncnt++;
|
|
if ( ncnt >= ST_MAX_NOTCHES ) fadestep = 2;
|
|
else fadestep = 0;
|
|
break;
|
|
case 2:
|
|
if ( donet ) state = STATE_NETNOTCH;
|
|
else state = STATE_WAIT;
|
|
fadestep = 0;
|
|
gametime = 0.;
|
|
ncnt = 0;
|
|
break;
|
|
}
|
|
break;
|
|
case STATE_NETNOTCH:
|
|
switch ( fadestep )
|
|
{
|
|
case 0:
|
|
if ( gametime > 1. )
|
|
{
|
|
fadestep++;
|
|
gametime = 0.;
|
|
}
|
|
break;
|
|
case 1:
|
|
if ( dripsnd ) Mix_PlayChannel(0,dripsnd,0);
|
|
SDL_LockSurface(st);
|
|
// draw netnotch
|
|
for ( int i=0; i<ST_NETNOTCH_HEIGHT; i++ )
|
|
memcpy((Uint8*)st->pixels+(ST_NETPROGRESS_Y+i)*640+ST_NETPROGRESS_X+ST_NETNOTCH_WIDTH*ncnt,&netnotch[0]+ST_NETNOTCH_WIDTH*i,ST_NETNOTCH_WIDTH);
|
|
SDL_UnlockSurface(st);
|
|
ncnt++;
|
|
if ( ncnt >= ST_MAX_NETNOTCHES ) fadestep = 2;
|
|
else fadestep = 0;
|
|
break;
|
|
case 2:
|
|
state = STATE_WAIT;
|
|
fadestep = 0;
|
|
gametime = 0.;
|
|
break;
|
|
}
|
|
break;
|
|
case STATE_WAIT:
|
|
// wow it's literally nothing
|
|
break;
|
|
}
|
|
SDL_BlitSurface(st,0,ws,0);
|
|
SDL_UpdateWindowSurface(w);
|
|
tock = ticker();
|
|
gametime += (float)(tock-tick)/NANOS_SEC;
|
|
}
|
|
if ( startmus ) Mix_HaltMusic();
|
|
if ( dripsnd ) Mix_FreeChunk(dripsnd);
|
|
if ( ticksnd ) Mix_FreeChunk(ticksnd);
|
|
if ( startmus ) Mix_FreeMusic(startmus);
|
|
Mix_Quit();
|
|
SDL_FreeSurface(st);
|
|
SDL_DestroyWindow(w);
|
|
SDL_Quit();
|
|
return 0;
|
|
}
|