sdlbomber/src/gfx.c

924 lines
15 KiB
C

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bomber.h"
#include "gfx.h"
#define MAXCOLORS 256
int usedcolors = 0;
SDL_Surface* thescreen;
SDL_Color themap[256];
uchar* videomem;
int stride;
int mousex, mousey, mouseb;
uchar mustlock = 0, locked = 0;
uchar* block64;
int buttonstate = 0, buttondown = 0;
int mxpos, mypos;
int pressedcodes[KEYMAX], downcodes[KEYMAX], numpressed, numdown;
void dumpgfx() {
usedcolors = 0;
}
static int bestmatch(int red, int green, int blue) {
int i;
int bestcolor, bestdelta = 0;
int rdelta, gdelta, bdelta;
int delta;
i = 0;
bestcolor = -1;
while (i < usedcolors) {
rdelta = themap[i].r;
rdelta -= red;
rdelta *= rdelta;
gdelta = themap[i].g;
gdelta -= green;
gdelta *= gdelta;
bdelta = themap[i].b;
bdelta -= blue;
bdelta *= bdelta;
delta = rdelta + gdelta + bdelta;
if (bestcolor < 0 || delta < bestdelta) {
bestdelta = delta;
bestcolor = i;
}
i++;
}
return bestcolor;
}
static void updatemap(void) {
SDL_SetColors(thescreen, themap, 0, 256);
}
void createinout(gfxset* gs) {
uchar* p;
int i, j, counts[256];
uchar red, green, blue;
int cnt;
p = gs->gs_pic;
for (i = 0; i < 256; i++) counts[i] = 0;
i = gs->gs_xsize * gs->gs_ysize;
while (i--) counts[*p++]++;
cnt = 0;
gs->gs_inout[0] = 0;
for (i = 1; i < 256; i++) {
if (counts[i]) {
cnt++;
p = gs->gs_colormap + i + i + i;
red = *p++;
green = *p++;
blue = *p++;
for (j = 0; j < usedcolors; j++) {
if (red == themap[j].r && green == themap[j].g && blue == themap[j].b) {
gs->gs_inout[i] = j;
break;
}
}
if (j == usedcolors) {
if (usedcolors < MAXCOLORS) {
themap[j].r = red;
themap[j].g = green;
themap[j].b = blue;
gs->gs_inout[i] = usedcolors;
++usedcolors;
} else
gs->gs_inout[i] = bestmatch(red, green, blue);
}
}
}
updatemap();
}
static uchar* compressfig(uchar* put, gfxset* gs, int sourcex, int sourcey, int sizex, int sizey) {
int j, gswidth;
uchar *p, *p2, pixel, *map1;
int dx, dy;
gswidth = gs->gs_xsize;
map1 = gs->gs_inout;
p = gs->gs_pic + sourcex + gswidth * sourcey;
for (dy = 0; dy < sizey; dy++) {
p2 = p;
j = 0;
for (dx = 0; dx <= sizex; dx++) {
if (dx < sizex)
pixel = *p2;
else
pixel = 0;
++p2;
if (pixel)
++j;
else if (j) {
*put++ = j;
*put++ = dx - j;
*put++ = dy;
p2 -= j + 1;
while (j) *put++ = map1[*p2++], --j;
++p2;
}
}
p += gswidth;
}
*put++ = 0;
return put;
}
static void gfxfetchsingle(figure* fig, gfxset* gs, int sourcex, int sourcey, int sizex, int sizey) {
uchar *p, *p2;
int dx, dy;
/* uchar *map1; */
int gswidth;
int minx, miny, maxx, maxy;
int tx, ty;
/* map1=gs->gs_inout; */
gswidth = gs->gs_xsize;
p = gs->gs_pic + sourcex + gswidth * sourcey;
minx = miny = maxx = maxy = -1;
for (dy = 0; dy < sizey; dy++) {
p2 = p;
ty = sourcey + dy;
for (dx = 0; dx < sizex; dx++) {
if (!*p2++) continue;
if (miny == -1 || ty < miny) miny = ty;
if (maxy == -1 || ty > maxy) maxy = ty;
tx = sourcex + dx;
if (minx == -1 || tx < minx) minx = tx;
if (maxx == -1 || tx > maxx) maxx = tx;
}
p += gswidth;
}
if (minx == -1) {
minx = maxx = sourcex;
miny = maxy = sourcey;
}
fig->xdelta = minx - sourcex;
fig->ydelta = miny - sourcey;
sourcex = minx;
sourcey = miny;
fig->xsize = sizex = maxx - minx + 1;
fig->ysize = sizey = maxy - miny + 1;
p = compressfig(block64, gs, sourcex, sourcey, sizex, sizey);
fig->graphics = malloc(p - block64);
if (fig->graphics) memcpy(fig->graphics, block64, p - block64);
}
//(gfxset *gs,figure *fig,int sourcex,int sourcey,int sizex,int sizey)
void gfxfetch(gfxset* gs, figure* fig, int num) {
int x, y;
int xsize, ysize;
int fxsize, fysize;
unsigned char *p, *p2;
xsize = gs->gs_xsize;
ysize = gs->gs_ysize;
p2 = p = gs->gs_pic + xsize + 1;
fxsize = 2;
while (*p++ == 0) ++fxsize;
fysize = 2;
while (*p2 == 0) ++fysize, p2 += xsize;
x = fxsize;
y = 0;
while (num--) {
gfxfetchsingle(fig, gs, x, y, fxsize, fysize);
x += fxsize;
if (x > xsize - fxsize) {
x = 0;
y += fysize;
if (y > ysize - fysize) y = 0;
}
fig++;
}
}
void solidfetch(gfxset* gs, solid* dest) {
int xsize, ysize;
int i;
unsigned char *p, *map;
uchar* gfx;
memset(dest, 0, sizeof(solid));
xsize = gs->gs_xsize;
ysize = gs->gs_ysize;
i = xsize * ysize;
gfx = dest->graphics = malloc(i);
if (!gfx) return;
dest->xsize = xsize;
dest->ysize = ysize;
map = gs->gs_inout;
memcpy(gfx, gs->gs_pic, i);
p = gfx;
while (i--) {
if (*p) *p = map[*p];
++p;
}
}
void solidcopyany(solid* src, solid* dest, int destx, int desty, int sizex, int sizey) {
int xmax, ymax;
int j;
uchar *p1, *p2;
int w;
xmax = src->xsize;
ymax = src->ysize;
if (destx >= xmax || desty >= ymax || destx + sizex <= 0 || desty + sizey <= 0) return;
if (destx < 0) {
sizex += destx;
destx = 0;
}
if (desty < 0) {
sizey += desty;
desty = 0;
}
if (destx + sizex > xmax) sizex = xmax - destx;
if (desty + sizey > ymax) sizey = ymax - desty;
if (dest) {
w = dest->xsize;
p1 = dest->graphics + desty * w + destx;
} else {
gfxlock();
w = stride;
p1 = videomem + desty * stride + destx;
}
p2 = src->graphics + desty * xmax + destx;
for (j = 0; j < sizey; ++j) {
memcpy(p1, p2, sizex);
p1 += w;
p2 += xmax;
}
}
void solidcopy(solid* solid, int destx, int desty, int sizex, int sizey) {
solidcopyany(solid, 0, destx, desty, sizex, sizey);
}
void drawfigureany(int x, int y, figure* fig, solid* dest) {
int run;
int dx, dy;
int xsize, ysize;
int clipx, clipy, w;
unsigned char *pc, *p, *p2, *take;
take = fig->graphics;
if (dest) {
w = clipx = dest->xsize;
clipy = dest->ysize;
pc = dest->graphics;
} else {
gfxlock();
w = stride;
clipx = IXSIZE;
clipy = IYSIZE;
pc = videomem;
}
dx = fig->xdelta;
dy = fig->ydelta;
xsize = fig->xsize;
ysize = fig->ysize;
x += dx;
y += dy;
if (x >= 0 && y >= 0 && x <= clipx - xsize && y <= clipy - ysize) {
while ((run = *take++)) {
dx = *((signed char*) take);
++take;
dy = *((signed char*) take);
++take;
p = pc + w * (y + dy) + x + dx;
while (run--) *p++ = *take++;
}
} else {
while ((run = *take++)) {
dx = *((signed char*) take);
++take;
dy = *((signed char*) take);
++take;
dx += x;
dy += y;
p2 = take;
take += run;
if (dy < 0 || dy >= clipy) continue;
if (dx >= clipx) continue;
if (dx < 0) {
p2 -= dx;
run += dx;
dx = 0;
} else if (dx + run > clipx)
run = clipx - dx;
p = pc + w * dy + dx;
if (run) memcpy(p, p2, run);
}
}
}
void drawfigure(int destx, int desty, figure* fig) {
drawfigureany(destx, desty, fig, 0);
}
void copyup() {
gfxunlock();
SDL_UpdateRect(thescreen, 0, 0, 0, 0);
needwhole = 0;
}
void copyupxy(int x, int y) {
gfxunlock();
SDL_UpdateRect(thescreen, x, y, 24, 24);
}
void copyupxysize(int x, int y, int xsize, int ysize) {
gfxunlock();
SDL_UpdateRect(thescreen, x, y, xsize, ysize);
}
// static void set_color(int color, int red, int green, int blue) {
// themap[color].r=red;
// themap[color].g=green;
// themap[color].b=blue;
// }
void opengfx(void) {
unsigned long videoflags;
themap[0].r = 0;
themap[0].g = 0;
themap[0].b = 0;
usedcolors = 1;
block64 = malloc(65536);
if (!block64) {
printf("Couldn't allocate block64\n");
exit(50);
}
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
videoflags = SDL_SWSURFACE | SDL_HWPALETTE; //|SDL_FULLSCREEN;
thescreen = SDL_SetVideoMode(IXSIZE, IYSIZE, 8, videoflags);
if (thescreen == NULL) {
fprintf(stderr, "Couldn't set display mode: %s\n", SDL_GetError());
SDL_Quit();
exit(5);
}
stride = thescreen->pitch;
videomem = thescreen->pixels;
mustlock = SDL_MUSTLOCK(thescreen);
locked = 0;
SDL_ShowCursor(0);
}
void closegfx(void) {
SDL_Quit();
}
int checkpressed(int code) {
int *p, i;
i = numpressed;
p = pressedcodes;
while (i--)
if (*p++ == code) return 1;
return 0;
}
int checkdown(int code) {
int *p, i;
i = numdown;
p = downcodes;
while (i--)
if (*p++ == code) return 1;
return 0;
}
int checkbutton(int button) {
return buttonstate & (1 << button);
}
int checkbuttondown(int button) {
return buttondown & (1 << button);
}
int anydown(void) {
return numdown;
}
int takedown(void) {
int res = 0;
if (numdown) {
res = *downcodes;
--numdown;
if (numdown) memmove(downcodes, downcodes + 1, numdown * sizeof(int));
}
return res;
}
int firstdown(void) {
return *downcodes;
}
#define ENDMARK 0xaabacada
int sdlinoutnormal[] = {
SDLK_0,
'0',
SDLK_1,
'1',
SDLK_2,
'2',
SDLK_3,
'3',
SDLK_4,
'4',
SDLK_5,
'5',
SDLK_6,
'6',
SDLK_7,
'7',
SDLK_8,
'8',
SDLK_9,
'9',
SDLK_a,
'a',
SDLK_b,
'b',
SDLK_c,
'c',
SDLK_d,
'd',
SDLK_e,
'e',
SDLK_f,
'f',
SDLK_g,
'g',
SDLK_h,
'h',
SDLK_i,
'i',
SDLK_j,
'j',
SDLK_k,
'k',
SDLK_l,
'l',
SDLK_m,
'm',
SDLK_n,
'n',
SDLK_o,
'o',
SDLK_p,
'p',
SDLK_q,
'q',
SDLK_r,
'r',
SDLK_s,
's',
SDLK_t,
't',
SDLK_u,
'u',
SDLK_v,
'v',
SDLK_w,
'w',
SDLK_x,
'x',
SDLK_y,
'y',
SDLK_z,
'z',
SDLK_MINUS,
'-',
SDLK_EQUALS,
'=',
SDLK_LEFTBRACKET,
'[',
SDLK_RIGHTBRACKET,
']',
SDLK_SEMICOLON,
';',
SDLK_QUOTE,
'\'',
SDLK_SLASH,
'/',
SDLK_PERIOD,
'.',
SDLK_COMMA,
',',
SDLK_BACKQUOTE,
'`',
SDLK_BACKSPACE,
8,
SDLK_TAB,
9,
SDLK_DELETE,
MYDELETE,
SDLK_RETURN,
13,
SDLK_F1,
MYF1,
SDLK_F2,
MYF2,
SDLK_F3,
MYF3,
SDLK_F4,
MYF4,
SDLK_F5,
MYF5,
SDLK_F6,
MYF6,
SDLK_F7,
MYF7,
SDLK_F8,
MYF8,
SDLK_F9,
MYF9,
SDLK_F10,
MYF10,
SDLK_ESCAPE,
0x1b,
SDLK_LEFT,
MYLEFT,
SDLK_RIGHT,
MYRIGHT,
SDLK_UP,
MYUP,
SDLK_DOWN,
MYDOWN,
SDLK_PAGEUP,
MYPAGEUP,
SDLK_PAGEDOWN,
MYPAGEDOWN,
SDLK_SPACE,
' ',
SDLK_HOME,
MYHOME,
SDLK_END,
MYEND,
SDLK_LALT,
MYALTL,
SDLK_RALT,
MYALTR,
ENDMARK};
int sdlinoutshifted[] = {
SDLK_0,
')',
SDLK_1,
'!',
SDLK_2,
'@',
SDLK_3,
'#',
SDLK_4,
'$',
SDLK_5,
'%',
SDLK_6,
'^',
SDLK_7,
'&',
SDLK_8,
'*',
SDLK_9,
'(',
SDLK_a,
'A',
SDLK_b,
'B',
SDLK_c,
'C',
SDLK_d,
'D',
SDLK_e,
'E',
SDLK_f,
'F',
SDLK_g,
'G',
SDLK_h,
'H',
SDLK_i,
'I',
SDLK_j,
'J',
SDLK_k,
'K',
SDLK_l,
'L',
SDLK_m,
'M',
SDLK_n,
'N',
SDLK_o,
'O',
SDLK_p,
'P',
SDLK_q,
'Q',
SDLK_r,
'R',
SDLK_s,
'S',
SDLK_t,
'T',
SDLK_u,
'U',
SDLK_v,
'V',
SDLK_w,
'W',
SDLK_x,
'X',
SDLK_y,
'Y',
SDLK_z,
'Z',
SDLK_MINUS,
'_',
SDLK_EQUALS,
'+',
SDLK_LEFTBRACKET,
'{',
SDLK_RIGHTBRACKET,
'}',
SDLK_SEMICOLON,
':',
SDLK_QUOTE,
'"',
SDLK_SLASH,
'?',
SDLK_PERIOD,
'>',
SDLK_COMMA,
'<',
SDLK_BACKQUOTE,
'~',
SDLK_BACKSPACE,
8,
SDLK_TAB,
9,
SDLK_DELETE,
MYDELETE,
SDLK_RETURN,
13,
SDLK_F1,
MYF1 + MYSHIFTED,
SDLK_F2,
MYF2 + MYSHIFTED,
SDLK_F3,
MYF3 + MYSHIFTED,
SDLK_F4,
MYF4 + MYSHIFTED,
SDLK_F5,
MYF5 + MYSHIFTED,
SDLK_F6,
MYF6 + MYSHIFTED,
SDLK_F7,
MYF7 + MYSHIFTED,
SDLK_F8,
MYF8 + MYSHIFTED,
SDLK_F9,
MYF9 + MYSHIFTED,
SDLK_F10,
MYF10 + MYSHIFTED,
SDLK_ESCAPE,
0x1b,
SDLK_LEFT,
MYLEFT + MYSHIFTED,
SDLK_RIGHT,
MYRIGHT + MYSHIFTED,
SDLK_UP,
MYUP + MYSHIFTED,
SDLK_DOWN,
MYDOWN + MYSHIFTED,
SDLK_PAGEUP,
MYPAGEUP,
SDLK_PAGEDOWN,
MYPAGEDOWN,
SDLK_SPACE,
' ',
SDLK_HOME,
MYHOME,
SDLK_END,
MYEND,
SDLK_LALT,
MYALTL,
SDLK_RALT,
MYALTR,
ENDMARK};
static int looklist(int code, int* list) {
while ((unsigned int) *list != ENDMARK) {
if (*list == code) return list[1];
list += 2;
}
return -1;
}
static int mapkey(int code, int qual) {
if (qual & KMOD_SHIFT)
code = looklist(code, sdlinoutshifted);
else
code = looklist(code, sdlinoutnormal);
if (code < 0) return -1;
if (qual & KMOD_ALT) code |= MYALTED;
return code;
}
static void markkey(int code, int status) {
int i;
int* ip;
if (status) {
if (numdown < KEYMAX) downcodes[numdown++] = code;
ip = pressedcodes;
i = numpressed;
while (i)
if (*ip++ == code)
break;
else
i--;
if (!i && numpressed < KEYMAX) pressedcodes[numpressed++] = code;
} else {
i = numpressed;
ip = pressedcodes;
while (i)
if (*ip++ == code) {
*--ip = pressedcodes[--numpressed];
break;
} else
i--;
}
}
void pollinput(void) {
SDL_PollEvent(0);
}
void scaninput(void) {
SDL_Event event;
int key, mod;
static int bs = 0;
numdown = 0;
buttondown = 0;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
key = event.key.keysym.sym;
mod = event.key.keysym.mod;
markkey(mapkey(key, mod), 1);
break;
case SDL_KEYUP:
key = event.key.keysym.sym;
mod = event.key.keysym.mod;
markkey(mapkey(key, mod), 0);
break;
case SDL_MOUSEBUTTONUP:
bs &= ~(1 << (event.button.button - 1));
mousex = event.button.x >> 1;
mousey = event.button.y >> 1;
mouseb = bs;
break;
case SDL_MOUSEBUTTONDOWN:
bs |= 1 << (event.button.button - 1);
mousex = event.button.x >> 1;
mousey = event.button.y >> 1;
mouseb = bs;
break;
case SDL_MOUSEMOTION:
mousex = event.motion.x >> 1;
mousey = event.motion.y >> 1;
break;
case SDL_QUIT:
exitflag = 1;
break;
}
}
}
/*
void scaninput()
{
int i,*ip,code;
numdown=0;
buttondown=0;
while(XCheckMaskEvent(dp,~0,&event))
switch(event.type)
{
case KeyPress:
code=XLookupKeysym(keyevent,0);
if(numdown<KEYMAX)
downcodes[numdown++]=code;
ip=pressedcodes;
i=numpressed;
while(i)
if(*ip++==code) break;
else i--;
if(!i && numpressed<KEYMAX)
pressedcodes[numpressed++]=code;
break;
case KeyRelease:
code=XLookupKeysym(keyevent,0);
i=numpressed;
ip=pressedcodes;
while(i)
if(*ip++==code)
{
*--ip=pressedcodes[--numpressed];
break;
} else i--;
break;
case ButtonPress:
i=1<<buttonevent->button;
buttonstate|=i;
buttondown|=i;
break;
case ButtonRelease:
buttonstate&=~(1<<buttonevent->button);
break;
case MotionNotify:
mxpos=motionevent->x;
mypos=motionevent->y;
break;
case Expose:
copyup();
needwhole=0;
break;
case FocusOut:
numpressed=0;
break;
}
}
*/
static void drawrect(int x, int y, int xs, int ys, int c) {
uchar* p;
gfxlock();
p = videomem + y * stride + x;
while (ys--) {
memset(p, c, xs);
p += stride;
}
}
void greyrect(int x, int y, int xsize, int ysize) {
static int greycolor = -1;
if (greycolor == -1) greycolor = bestmatch(0, 0, 0x70);
drawrect(x, y, xsize, ysize, greycolor);
}
void clear() {
int j;
uchar* p;
gfxlock();
p = videomem;
for (j = 0; j < IYSIZE; ++j) {
memset(p, 0, IXSIZE);
p += stride;
}
}
void clearrect(int x, int y, int xsize, int ysize) {
drawrect(x, y, xsize, ysize, 0);
}
void gfxlock(void) {
if (locked || !mustlock) return;
if (SDL_LockSurface(thescreen) < 0) { fprintf(stderr, "Couldn't lock display surface: %s\n", SDL_GetError()); }
locked = 1;
}
void gfxunlock(void) {
if (!locked || !mustlock) return;
SDL_UnlockSurface(thescreen);
locked = 0;
}