home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * spred.c
- *
- * The sprite editor for the Sprite support system, main module.
- **********************************************************************
- This file is part of
-
- STK -- The sprite toolkit -- version 1.1
-
- Copyright (C) Jari Karjala 1991
-
- The sprite toolkit (STK) is a FreeWare toolkit for creating high
- resolution sprite graphics with PCompatible hardware. This toolkit
- is provided as is without any warranty or such thing. See the file
- COPYING for further information.
-
- **********************************************************************/
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <math.h>
- #include <graphics.h>
-
- #include "grtypes.h"
- #include "gr.h"
- #include "mouse.h"
-
- #include "spred.h"
- #include "spredio.h"
- #include "spredfio.h"
-
- #define TRUE 1
- #define FALSE 0
- #define FILE_EXTENSION ".smp"
-
- /**********************************************************************
- * Temporary map for various transformations
- **********************************************************************/
- SPRED_MAP temp_map;
-
- /**********************************************************************
- * The user supplied width, height of the sprite
- **********************************************************************/
- int width=0, height=0;
-
- /**********************************************************************
- * FATAL ERROR: Close graphics, print error and exit.
- **********************************************************************/
- void error(char *s,...)
- {
- char buf[100];
- va_list argptr;
-
- va_start(argptr,s);
- vsprintf(buf,s,argptr);
- va_end(argptr);
-
- closegraph();
- fputs(buf, stderr);
- exit(10);
- }
-
- /**********************************************************************
- * Prints explanation for the error code returned by the sprite file IO
- * Return: the parameter e
- **********************************************************************/
- int file_error(int e, char *filename)
- {
- static char *msgs[] = {
- "Error in closing file %s",
- "Sprite file is not complete",
- "Cannot find file %s",
- ""
- };
-
- message(msgs[3+e], filename);
- return e;
- }
-
- /**********************************************************************
- * Inverts the givent sprite's active bitmap
- **********************************************************************/
- void invert(SPRED_DATA *sdp)
- {
- int i,j;
-
- for(i=0; i<sdp->w; i++)
- for(j=0; j<sdp->h; j++)
- if (sdp->maps[sdp->map][i][j] == DOT_FOREGROUND)
- sdp->maps[sdp->map][i][j] = DOT_BACKGROUND;
- else
- sdp->maps[sdp->map][i][j] = DOT_FOREGROUND;
- }
-
- /**********************************************************************
- * Rotate the given sprites active bitmap 90 degrees anticlockwise
- **********************************************************************/
- void rotate_90(SPRED_DATA *sdp)
- {
- int i,j, lim, tmp;
-
- if (sdp->w > sdp->h)
- lim = sdp->h-1;
- else
- lim = sdp->w-1;
-
- for(i=0; i<(lim+1)/2; i++)
- for(j=0; j<(lim+1)/2; j++) {
- tmp = sdp->maps[sdp->map][i][j];
-
- sdp->maps[sdp->map][i][j]
- = sdp->maps[sdp->map][lim - j][i];
-
- sdp->maps[sdp->map][lim - j][i]
- = sdp->maps[sdp->map][lim - i][lim - j];
-
- sdp->maps[sdp->map][lim - i][lim - j]
- = sdp->maps[sdp->map][j][lim - i];
-
- sdp->maps[sdp->map][j][lim - i]
- = tmp;
- }
- }
-
- /**********************************************************************
- * Rotate the active map 'angle' degrees anticlockwise.
- * The transformation is done in reverse order, ie the points in the
- * destination bitmap are projected into the source bitmap. This
- * usually produces better rotations.
- * NOTE: uses the global temp_map
- **********************************************************************/
- void rotate(SPRED_DATA *sdp, double angle)
- {
- int i,j, i1,j1;
- double s,c,xo,yo;
-
- angle = M_PI*angle/180;
- s = sin(angle);
- c = cos(angle);
- xo = (sdp->w - 1)/2.0;
- yo = (sdp->h - 1)/2.0;
- for(i=0; i < sdp->w; i++)
- for(j=0; j < sdp->h; j++) {
- i1 = (c*(i - xo) - s*(j - yo)) + xo;
- j1 = (s*(i - xo) + c*(j - yo)) + yo;
- if (i1>=0 && i1<sdp->w && j1>=0 && j1<sdp->h)
- temp_map[i][j] = sdp->maps[sdp->map][i1][j1];
- else
- temp_map[i][j] = DOT_BACKGROUND;
- }
- memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
- }
-
- /**********************************************************************
- * Make part of the given sprite's active map fatter.
- * If a point's color is 'mid' and it has a neighbour which is in color
- * 'border', then the point's color is changed to 'border'.
- * NOTE: uses the global temp_map
- **********************************************************************/
- void make_fatter(SPRED_DATA *sdp, int mid, int border)
- {
- int i,j;
-
- for(i=0; i < sdp->w; i++)
- for(j=0; j < sdp->h; j++) {
- if ( sdp->maps[sdp->map][i][j]==mid
- && ( (i > 0 && sdp->maps[sdp->map][i-1][j]==border)
- ||(j > 0 && sdp->maps[sdp->map][i][j-1]==border)
- ||(i < sdp->w-1 && sdp->maps[sdp->map][i+1][j]==border)
- ||(j < sdp->h-1 && sdp->maps[sdp->map][i][j+1]==border)))
- temp_map[i][j] = border;
- else
- temp_map[i][j] = sdp->maps[sdp->map][i][j];
- }
- memcpy(sdp->maps[sdp->map], temp_map, sizeof(temp_map));
- }
-
-
- /**********************************************************************
- * Load the sprite from the given file. If filename is a null string,
- * then the sdp->name is used.
- **********************************************************************/
- void load(SPRED_DATA *sdp, char *filename)
- {
- sdp->w = width;
- sdp->h = height;
- if (filename[0]!='\0')
- strcpy(sdp->name, filename);
- if (strrchr(sdp->name, '.')==NULL)
- strcat(sdp->name, FILE_EXTENSION);
- message("Loading %s", sdp->name);
- if (file_error(load_sprite(sdp), sdp->name)==0)
- message("File: %s Size: %dx%d", sdp->name, sdp->w, sdp->h);
- else if ((sdp->w | sdp->h) == 0) {
- sdp->w = 32;
- sdp->h = 24;
- }
- draw_screen(sdp);
- }
-
- /**********************************************************************
- * Edit the given sprite. The screen must be in graphics mode and
- * the mouse interface must be functional.
- *
- * Return: 0 if normal exit with save, negative if quit
- **********************************************************************/
- int spred_edit(SPRED_DATA *sdp, int filec, char **filev)
- {
- char buf[SPR_NAME_LEN];
- MSG msg;
- int x,y, ox, oy, i,j, tmp, quit, curfile;
- static double angle = 30.0;
-
- sdp->map = SPR_SHAPE;
-
- curfile = 0;
- load(sdp, filev[curfile]);
-
- quit = FALSE;
- ox = oy = -1;
- while (!quit) {
- msg=get_msg(sdp, &x,&y);
- switch (msg) {
- case MSG_QUIT:
- quit = TRUE;
- break;
-
- case MSG_EXIT:
- if (file_error(save_sprite(sdp), sdp->name)==0)
- quit = TRUE;
- break;
-
- case MSG_SAVE:
- message("Give the save filename [%s]:", sdp->name);
- if (gr_gets(buf, SPR_NAME_LEN)!=NULL) {
- if (buf[0]!='\0')
- strcpy(sdp->name, buf);
- if (strrchr(sdp->name, '.')==NULL)
- strcat(sdp->name, FILE_EXTENSION);
- message("Saving %s", sdp->name);
- file_error(save_sprite(sdp), sdp->name);
- }
- else
- message("");
- break;
-
- case MSG_LOAD:
- message("Give the load filename [%s]:", sdp->name);
- if (gr_gets(buf, SPR_NAME_LEN)!=NULL)
- load(sdp, buf);
- else
- message("");
- break;
-
- case MSG_NEXT:
- if (curfile+1 < filec)
- load(sdp, filev[++curfile]);
- else
- message("No more sprites");
- break;
-
- case MSG_PREV:
- if (curfile > 0)
- load(sdp, filev[--curfile]);
- else
- message("No previous sprites");
- break;
-
- case MSG_CLEAR:
- memset(sdp->maps[sdp->map], DOT_BACKGROUND,sizeof(SPRED_MAP));
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_COPY_TO_SHAPE:
- memcpy(sdp->maps[SPR_SHAPE], sdp->maps[SPR_MASK],
- sizeof(sdp->maps[sdp->map]));
- sdp->map = SPR_SHAPE;
- invert(sdp);
- draw_map(sdp, SPR_SHAPE);
- break;
-
- case MSG_COPY_TO_MASK:
- memcpy(sdp->maps[SPR_MASK], sdp->maps[SPR_SHAPE],
- sizeof(sdp->maps[sdp->map]));
- sdp->map = SPR_MASK;
- invert(sdp);
- draw_map(sdp, SPR_MASK);
- break;
-
- case MSG_ACTIVATE_MASK:
- sdp->map = SPR_MASK;
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_ACTIVATE_SHAPE:
- sdp->map = SPR_SHAPE;
- draw_map(sdp, sdp->map);
- break;
-
- /***** Point drawing functions *****/
- case MSG_BTN1_CLICK: /** set point **/
- sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
- draw_point(sdp, x, y, sdp->map);
- message("Last point: X=%d Y=%d", x,y);
- break;
-
- case MSG_BTN2_CLICK: /** flip point **/
- if (x!=ox || y!=oy) {
- if (sdp->maps[sdp->map][x][y] == DOT_FOREGROUND)
- sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
- else
- sdp->maps[sdp->map][x][y] = DOT_FOREGROUND;
- draw_point(sdp, x, y, sdp->map);
- }
- message("Last point: X=%d Y=%d", x,y);
- break;
-
- case MSG_BTN3_CLICK: /** clear point **/
- sdp->maps[sdp->map][x][y] = DOT_BACKGROUND;
- draw_point(sdp, x, y, sdp->map);
- message("Last point: X=%d Y=%d", x,y);
- break;
-
-
- /***** Image manipulation commands *****/
- case MSG_INVERT:
- invert(sdp);
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_OVERLAY:
- draw_map(sdp, sdp->map | DOT_OVERLAY);
- break;
-
- case MSG_ROTATE90:
- rotate_90(sdp);
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_ROTATE:
- message("Give rotation angle [%.1lf]:", angle);
- if (gr_gets(buf, sizeof(buf))!=NULL) {
- if (buf[0]!='\0')
- angle = atof(buf);
- rotate(sdp, angle);
- draw_map(sdp, sdp->map);
- }
- message("");
- break;
-
- case MSG_HFLIP:
- for(i=0; i<sdp->w/2; i++)
- for(j=0; j<sdp->h; j++) {
- tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
- sdp->maps[sdp->map][sdp->w - i - 1][j]
- = sdp->maps[sdp->map][i][j];
- sdp->maps[sdp->map][i][j] = tmp;
- }
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_VFLIP:
- for(i=0; i<sdp->w; i++)
- for(j=0; j<sdp->h/2; j++) {
- tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
- sdp->maps[sdp->map][i][sdp->h - j - 1]
- = sdp->maps[sdp->map][i][j];
- sdp->maps[sdp->map][i][j] = tmp;
- }
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_HMIRROR:
- for(i=0; i<sdp->w/2; i++)
- for(j=0; j<sdp->h; j++) {
- tmp = sdp->maps[sdp->map][sdp->w - i - 1][j];
- if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
- sdp->maps[sdp->map][sdp->w - i - 1][j]
- = sdp->maps[sdp->map][i][j];
- if (tmp==DOT_FOREGROUND)
- sdp->maps[sdp->map][i][j] = tmp;
- }
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_VMIRROR:
- for(i=0; i<sdp->w; i++)
- for(j=0; j<sdp->h/2; j++) {
- tmp = sdp->maps[sdp->map][i][sdp->h - j - 1];
- if (sdp->maps[sdp->map][i][j]==DOT_FOREGROUND)
- sdp->maps[sdp->map][i][sdp->h - j - 1]
- = sdp->maps[sdp->map][i][j];
- if (tmp==DOT_FOREGROUND)
- sdp->maps[sdp->map][i][j] = tmp;
- }
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_FATTER:
- make_fatter(sdp, DOT_BACKGROUND, DOT_FOREGROUND);
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_THINNER:
- make_fatter(sdp, DOT_FOREGROUND, DOT_BACKGROUND);
- draw_map(sdp, sdp->map);
- break;
-
- case MSG_NONE:
- break;
-
- default:
- message("Message %d not implemented", msg, x, y);
- }
- ox = x;
- oy = y;
- }
-
- return -(msg == MSG_QUIT);
- }
-
-
- /**********************************************************************
- * The sprite to be edited. Must be global, since the structure
- * take about 20 kBytes. It is automatically initialized to zero.
- **********************************************************************/
- SPRED_DATA sd;
-
- void main(int argc, char **argv)
- {
- int i,j;
-
- puts("SPRED -- Sprite editor v1.1 -- Copyright (C) 1991 Jari Karjala");
-
- if (argc<2 || (argc==2 && argv[1][0]=='-'))
- error("\nUSAGE: SPRED [-WxH] sprite[.ext] [...]\n");
-
- /** get size if given **/
- if (argc>2 && argv[1][0]=='-') {
- if (sscanf(&argv[1][1], "%dx%d", &width, &height)!=2)
- error("Illegal width/height format, use WxH, eg 32x24");
- if (width > MAX_SPRITE_WIDTH || height > MAX_SPRITE_HEIGHT)
- error("Sprite too large, max size %dx%d",
- MAX_SPRITE_WIDTH, MAX_SPRITE_HEIGHT);
- argc--;
- argv++;
- }
-
- gr_detect(GR_TYPE_SPR, &i, &j);
- if (i == -1) {
- puts("Unsupported graphics mode, sorry!");
- exit(1);
- }
- gr_start(&i, &j);
- if (mouse_initialize()==0)
- error("No mouse driver found, cannot continue");
- mouse_set_pointer_xy(gr_max_x/2, 3*gr_max_y/4);
-
- if (spred_edit(&sd, argc-1, argv+1) < 0)
- exit(1); /** some error, or quit **/
-
- exit(0);
- }
-