stuff/startuptest.c
2022-01-01 20:50:20 +01:00

275 lines
6.6 KiB
C

/*
startuptest.c : Previews Hexen STARTUP screens for GZDoom mods.
Requires SDL2 and SDL2_mixer.
(C)2021 Marisa Kirisame, 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(&notch[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,&notch[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;
}