mkfont: auto-offset by 1,1 when full outline is enabled mkfont: better handling of glyph offsets fuzz: added Child of Ash palette
255 lines
5.2 KiB
C
255 lines
5.2 KiB
C
/*
|
|
fuzz.c : Fancy software filter.
|
|
I was bored.
|
|
(C)2016 Marisa Kirisame, UnSX Team.
|
|
Released under the MIT license.
|
|
*/
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_ttf.h>
|
|
#include <time.h>
|
|
|
|
#ifndef FUZZ_FONT_PATH
|
|
#error please define FUZZ_FONT_PATH with the absolute path to a bitmap font
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
float r,g,b,a;
|
|
} rgbfpx_t;
|
|
|
|
typedef struct
|
|
{
|
|
Uint8 r,g,b,a;
|
|
} __attribute__((packed)) rgb8px_t;
|
|
|
|
float t = 0.f;
|
|
const int fw = 640, fh = 480;
|
|
|
|
float rn( float sdx, float sdy )
|
|
{
|
|
return cosf(sdy*3874.8674f+sdx*6783.5325f)*2737.8474f;
|
|
}
|
|
|
|
float fract( float x )
|
|
{
|
|
return x-floorf(x);
|
|
}
|
|
|
|
SDL_Window *w;
|
|
SDL_Surface *ws, *fz;
|
|
|
|
rgbfpx_t *fl1, *fl2, *fl3;
|
|
const int fw1 = 320, fw2 = 160, fw3 = 80, fh1 = 240, fh2 = 120, fh3 = 60;
|
|
|
|
rgbfpx_t layers[3] =
|
|
{
|
|
// Void
|
|
{0.71f,0.67f,0.95f,1.f},
|
|
{0.66f,0.84f,0.73f,1.f},
|
|
{0.95f,0.73f,0.81f,1.f}
|
|
// SWWM GZ
|
|
//{0.91f,0.87f,1.95f,1.f},
|
|
//{0.66f,1.84f,0.73f,1.f},
|
|
//{1.35f,0.73f,1.21f,1.f}
|
|
// RED ONI
|
|
//{0.61f,0.77f,0.85f,1.f},
|
|
//{0.86f,0.64f,0.63f,1.f},
|
|
//{1.25f,0.33f,0.41f,1.f}
|
|
// RED-EYED RAMPAGE
|
|
//{1.81f,0.97f,0.75f,1.f},
|
|
//{0.36f,0.64f,0.93f,1.f},
|
|
//{1.25f,0.33f,0.41f,1.f}
|
|
// RED STAR OF INNOCENCE
|
|
//{1.31f,0.87f,1.25f,1.f},
|
|
//{0.76f,0.64f,0.63f,1.f},
|
|
//{1.25f,1.13f,0.21f,1.f}
|
|
// CHILD OF ASH
|
|
//{0.71f,0.97f,1.05f,1.f},
|
|
//{0.96f,0.74f,0.63f,1.f},
|
|
//{0.95f,0.93f,1.21f,1.f}
|
|
};
|
|
float speed[3] =
|
|
{
|
|
1.3526f,
|
|
0.7843f,
|
|
0.3725f
|
|
};
|
|
|
|
void mklayer1( void )
|
|
{
|
|
for ( int y=0; y<fh1; y++ )
|
|
{
|
|
float rg;
|
|
for ( int x=0; x<fw1; x++ )
|
|
{
|
|
rg = 2.f*fabsf(fract(rn(x,y)+t*speed[0])-0.5f);
|
|
fl1[x+y*fw1].r = layers[0].r*rg;
|
|
fl1[x+y*fw1].g = layers[0].g*rg;
|
|
fl1[x+y*fw1].b = layers[0].b*rg;
|
|
fl1[x+y*fw1].a = layers[0].a*rg;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mklayer2( void )
|
|
{
|
|
for ( int y=0; y<fh2; y++ )
|
|
{
|
|
float rg;
|
|
for ( int x=0; x<fw2; x++ )
|
|
{
|
|
rg = 2.f*fabsf(fract(rn(x,y)+t*speed[1])-0.5f);
|
|
fl2[x+y*fw2].r = layers[1].r*rg;
|
|
fl2[x+y*fw2].g = layers[1].g*rg;
|
|
fl2[x+y*fw2].b = layers[1].b*rg;
|
|
fl2[x+y*fw2].a = layers[1].a*rg;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mklayer3( void )
|
|
{
|
|
for ( int y=0; y<fh3; y++ )
|
|
{
|
|
float rg;
|
|
for ( int x=0; x<fw3; x++ )
|
|
{
|
|
rg = 2.f*fabsf(fract(rn(x,y)+t*speed[2])-0.5f);
|
|
fl3[x+y*fw3].r = layers[2].r*rg;
|
|
fl3[x+y*fw3].g = layers[2].g*rg;
|
|
fl3[x+y*fw3].b = layers[2].b*rg;
|
|
fl3[x+y*fw3].a = layers[2].a*rg;
|
|
}
|
|
}
|
|
}
|
|
|
|
float clamp( float a, float l, float h )
|
|
{
|
|
return (a>h)?h:(a>l)?a:l;
|
|
}
|
|
|
|
void mergedown( void )
|
|
{
|
|
rgbfpx_t twofivefive = {255.f,255.f,255.f,255.f};
|
|
#pragma omp parallel for
|
|
for ( int y=0; y<fh; y++ )
|
|
{
|
|
int y1, y2, y3;
|
|
rgb8px_t *stripe;
|
|
rgbfpx_t merged;
|
|
y1 = y>>1;
|
|
y2 = y>>2;
|
|
y3 = y>>3;
|
|
stripe = (rgb8px_t*)((Uint8*)fz->pixels+y*fz->pitch);
|
|
for ( int x=0; x<fw; x++ )
|
|
{
|
|
int x1, x2, x3;
|
|
x1 = x>>1;
|
|
x2 = x>>2;
|
|
x3 = x>>3;
|
|
// gcc is stupid
|
|
asm( "movaps %1,%%xmm0\n"
|
|
"mulps %2,%%xmm0\n"
|
|
"mulps %3,%%xmm0\n"
|
|
"mulps %4,%%xmm0\n"
|
|
"movaps %%xmm0,%0\n"
|
|
:"=m"(merged)
|
|
:"m"(fl1[x1+y1*fw1]),"m"(fl2[x2+y2*fw2]),
|
|
"m"(fl3[x3+y3*fw3]),"m"(twofivefive));
|
|
stripe[x].r = clamp(merged.r,0,255);
|
|
stripe[x].g = clamp(merged.g,0,255);
|
|
stripe[x].b = clamp(merged.b,0,255);
|
|
stripe[x].a = clamp(merged.a,0,255);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define TMAX 64
|
|
int ti = 0;
|
|
float ts = 0.f, tl[TMAX] = {0.f};
|
|
|
|
float avg_fps( float nt )
|
|
{
|
|
ts = ts-tl[ti]+nt;
|
|
tl[ti] = nt;
|
|
if ( ++ti == TMAX ) ti = 0;
|
|
return ts/TMAX;
|
|
}
|
|
|
|
#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( void )
|
|
{
|
|
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
|
|
w = SDL_CreateWindow("Fuzz",SDL_WINDOWPOS_UNDEFINED,
|
|
SDL_WINDOWPOS_UNDEFINED,fw,fh,SDL_WINDOW_SHOWN);
|
|
ws = SDL_GetWindowSurface(w);
|
|
fz = SDL_CreateRGBSurface(0,fw,fh,32,0xFF,0xFF00,0xFF0000,0xFF000000);
|
|
SDL_SetSurfaceBlendMode(fz,SDL_BLENDMODE_NONE);
|
|
fl1 = malloc(sizeof(rgbfpx_t)*fw1*fh1);
|
|
fl2 = malloc(sizeof(rgbfpx_t)*fw2*fh2);
|
|
fl3 = malloc(sizeof(rgbfpx_t)*fw3*fh3);
|
|
TTF_Init();
|
|
TTF_Font *fon = TTF_OpenFont(FUZZ_FONT_PATH,16);
|
|
if ( !fon )
|
|
{
|
|
fprintf(stderr,"Could not open font '%s'.\n",FUZZ_FONT_PATH);
|
|
TTF_Quit();
|
|
free(fl3);
|
|
free(fl2);
|
|
free(fl1);
|
|
SDL_FreeSurface(fz);
|
|
SDL_DestroyWindow(w);
|
|
SDL_Quit();
|
|
return 1;
|
|
}
|
|
SDL_Event e;
|
|
SDL_Color fpscol = {160,0,0,255};
|
|
int active = 1;
|
|
long tick, tock;
|
|
float frame = 0.f, fps = NAN, fpsmin = INFINITY, fpsmax = -INFINITY,
|
|
fpsavg = 0.f;
|
|
char fpst[16];
|
|
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;
|
|
mklayer1();
|
|
mklayer2();
|
|
mklayer3();
|
|
mergedown();
|
|
SDL_BlitSurface(fz,0,ws,0);
|
|
snprintf(fpst,15,"%.2f FPS",fps);
|
|
SDL_Surface *txt = TTF_RenderText_Blended(fon,fpst,fpscol);
|
|
SDL_BlitSurface(txt,0,ws,0);
|
|
SDL_FreeSurface(txt);
|
|
SDL_UpdateWindowSurface(w);
|
|
tock = ticker();
|
|
frame = (float)(tock-tick)/NANOS_SEC;
|
|
fps = 1.f/frame;
|
|
fpsavg = avg_fps(fps);
|
|
if ( fps > fpsmax ) fpsmax = fps;
|
|
if ( fps < fpsmin ) fpsmin = fps;
|
|
printf("FPS: %.2f (%.2f min, %.2f max, %.2f avg)\n",fps,
|
|
fpsmin,fpsmax,fpsavg);
|
|
t += frame;
|
|
}
|
|
TTF_CloseFont(fon);
|
|
TTF_Quit();
|
|
free(fl3);
|
|
free(fl2);
|
|
free(fl1);
|
|
SDL_FreeSurface(fz);
|
|
SDL_DestroyWindow(w);
|
|
SDL_Quit();
|
|
return 0;
|
|
}
|