14144 lines
317 KiB
C
14144 lines
317 KiB
C
/*
|
||
tuxpaint.c
|
||
|
||
Tux Paint - A simple drawing program for children.
|
||
|
||
Copyright (c) 2004 by Bill Kendrick
|
||
bill@newbreedsoftware.com
|
||
http://www.newbreedsoftware.com/tuxpaint/
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
||
June 14, 2002 - November 26, 2004
|
||
*/
|
||
|
||
|
||
#define VER_VERSION "0.9.15"
|
||
#define VER_DATE "2004-11-26"
|
||
|
||
|
||
//#define VIDEO_BPP 15 // saves memory
|
||
//#define VIDEO_BPP 16 // causes discoloration
|
||
//#define VIDEO_BPP 24 // compromise
|
||
#define VIDEO_BPP 32 // might be fastest, if conversion funcs removed
|
||
|
||
|
||
/* #define DEBUG */
|
||
/* #define LOW_QUALITY_THUMBNAILS */
|
||
/* #define LOW_QUALITY_COLOR_SELECTOR */
|
||
/* #define LOW_QUALITY_STAMP_OUTLINE */
|
||
/* #define LOW_QUALITY_FLOOD_FILL */
|
||
/* #define NO_PROMPT_SHADOWS */
|
||
/* #define USE_HWSURFACE */
|
||
|
||
/* Use high quality 4x filter when scaling stamps up: */
|
||
/* #define USE_HQ4X */
|
||
|
||
|
||
/* Disable fancy cursors in fullscreen mode, to avoid SDL bug: */
|
||
#define LARGE_CURSOR_FULLSCREEN_BUG
|
||
|
||
#define HEIGHTOFFSET (((WINDOW_HEIGHT - 480) / 48) * 48)
|
||
#define TOOLOFFSET (HEIGHTOFFSET / 48 * 2)
|
||
#define PROMPTOFFSETX (WINDOW_WIDTH - 640) / 2
|
||
#define PROMPTOFFSETY (HEIGHTOFFSET / 2)
|
||
|
||
/////////////////////////////////////////////////////////////////////
|
||
// hide all scale-related values here
|
||
|
||
typedef struct scaleparams {
|
||
unsigned numer, denom;
|
||
} scaleparams;
|
||
static scaleparams scaletable[] = {
|
||
{ 1,256}, // 0.00390625
|
||
{ 3,512}, // 0.005859375
|
||
{ 1,128}, // 0.0078125
|
||
{ 3,256}, // 0.01171875
|
||
{ 1, 64}, // 0.015625
|
||
{ 3,128}, // 0.0234375
|
||
{ 1, 32}, // 0.03125
|
||
{ 3, 64}, // 0.046875
|
||
{ 1, 16}, // 0.0625
|
||
{ 3, 32}, // 0.09375
|
||
{ 1, 8}, // 0.125
|
||
{ 3, 16}, // 0.1875
|
||
{ 1, 4}, // 0.25
|
||
{ 3, 8}, // 0.375
|
||
{ 1, 2}, // 0.5
|
||
{ 3, 4}, // 0.75
|
||
{ 1, 1}, // 1
|
||
{ 3, 2}, // 1.5
|
||
{ 2, 1}, // 2
|
||
{ 3, 1}, // 3
|
||
{ 4, 1}, // 4
|
||
{ 6, 1}, // 6
|
||
{ 8, 1}, // 8
|
||
{ 12, 1}, // 12
|
||
{ 16, 1}, // 16
|
||
{ 24, 1}, // 24
|
||
{ 32, 1}, // 32
|
||
{ 48, 1}, // 48
|
||
};
|
||
|
||
#define HARD_MIN_STAMP_SIZE 0 // bottom of scaletable
|
||
#define HARD_MAX_STAMP_SIZE (sizeof scaletable / sizeof scaletable[0] - 1)
|
||
|
||
#define MIN_STAMP_SIZE (state_stamps[cur_stamp]->min)
|
||
#define MAX_STAMP_SIZE (state_stamps[cur_stamp]->max)
|
||
|
||
#define CAN_USE_HQ4X (scaletable[state_stamps[cur_stamp]->size] == (scaleparams){4,1})
|
||
// to scale some offset, in pixels, like the current stamp is scaled
|
||
#define SCALE_LIKE_STAMP(x) ( ((x) * scaletable[state_stamps[cur_stamp]->size].numer + scaletable[state_stamps[cur_stamp]->size].denom-1) / scaletable[state_stamps[cur_stamp]->size].denom )
|
||
// pixel dimensions of the current stamp, as scaled
|
||
#define CUR_STAMP_W SCALE_LIKE_STAMP(img_stamps[cur_stamp]->w)
|
||
#define CUR_STAMP_H SCALE_LIKE_STAMP(img_stamps[cur_stamp]->h)
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
// #define MAX_FILES 2048 /* Max. # of files in a dir. to worry about... */
|
||
|
||
#define REPEAT_SPEED 300 /* Initial repeat speed for scrollbars */
|
||
#define CURSOR_BLINK_SPEED 500 /* Initial repeat speed for cursor */
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <math.h>
|
||
#include <time.h>
|
||
|
||
#ifdef USE_HQ4X
|
||
#include "hqxx.h"
|
||
#include "hq3x.h"
|
||
#include "hq4x.h"
|
||
#endif
|
||
|
||
#include <locale.h>
|
||
#include <iconv.h>
|
||
|
||
#ifndef OLD_UPPERCASE_CODE
|
||
#include <wctype.h>
|
||
#endif
|
||
|
||
#ifdef WIN32_OLD
|
||
/* The following are required by libintl.h, so must be defined first: */
|
||
#define LC_MESSAGES 1729
|
||
#define HAVE_LC_MESSAGES 1
|
||
#define ENABLE_NLS 1
|
||
#define HAVE_LOCALE_H 1
|
||
#define HAVE_GETTEXT 1
|
||
#define HAVE_DCGETTEXT 1
|
||
#endif
|
||
|
||
#if defined(sun) && defined(__svr4__)
|
||
/* Solaris needs locale.h */
|
||
#endif
|
||
|
||
#include <libintl.h>
|
||
#ifndef gettext_noop
|
||
#define gettext_noop(String) String
|
||
#endif
|
||
|
||
|
||
#ifdef DEBUG
|
||
#define gettext(String) debug_gettext(String)
|
||
#endif
|
||
|
||
|
||
#ifndef M_PI
|
||
#define M_PI 3.14159265
|
||
#endif
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
|
||
|
||
|
||
#ifndef WIN32
|
||
#include <unistd.h>
|
||
#include <dirent.h>
|
||
#ifdef __BEOS__
|
||
#include "BeOS_print.h"
|
||
// workaround dirent handling bug in TuxPaint code
|
||
typedef struct safer_dirent {
|
||
dev_t d_dev;
|
||
dev_t d_pdev;
|
||
ino_t d_ino;
|
||
ino_t d_pino;
|
||
unsigned short d_reclen;
|
||
char d_name[NAME_MAX];
|
||
} safer_dirent;
|
||
#define dirent safer_dirent
|
||
#endif
|
||
#ifdef __APPLE__
|
||
#include "macosx_print.h"
|
||
#endif
|
||
#else
|
||
#include "win32_dirent.h"
|
||
#include "win32_print.h"
|
||
#include <io.h>
|
||
#include <direct.h>
|
||
|
||
|
||
/* Enables win32 apps to get a GNU compatible locale string */
|
||
extern char* g_win32_getlocale(void);
|
||
|
||
/* Set this to 0 during developement and testing in Visual-Studio
|
||
Set this to 1 to make the final executable */
|
||
|
||
#if 1
|
||
|
||
#define DOC_PREFIX "docs/"
|
||
#define DATA_PREFIX "data/"
|
||
#define LOCALEDIR "locale"
|
||
|
||
#else
|
||
|
||
#define DOC_PREFIX "../../docs/"
|
||
#define DATA_PREFIX "../../data/"
|
||
#define LOCALEDIR "../../locale"
|
||
|
||
#endif /* 1/0 */
|
||
|
||
#define mkdir(path,access) _mkdir(path)
|
||
#define strcasecmp stricmp
|
||
#define strncasecmp strnicmp
|
||
#define snprintf _snprintf
|
||
#define S_ISDIR(i) ((i&_S_IFDIR)!=0)
|
||
#define alloca _alloca
|
||
|
||
#endif /* WIN32 */
|
||
|
||
#include <errno.h>
|
||
#include <sys/stat.h>
|
||
|
||
#include "SDL.h"
|
||
#ifndef _SDL_H
|
||
#error "---------------------------------------------------"
|
||
#error "If you installed SDL from a package, be sure to get"
|
||
#error "the development package, as well!"
|
||
#error "(e.g., 'libsdl1.2-devel.rpm')"
|
||
#error "---------------------------------------------------"
|
||
#endif
|
||
|
||
#include "SDL_image.h"
|
||
#ifndef _IMG_h
|
||
#error "---------------------------------------------------"
|
||
#error "If you installed SDL_image from a package, be sure"
|
||
#error "to get the development package, as well!"
|
||
#error "(e.g., 'libsdl-image1.2-devel.rpm')"
|
||
#error "---------------------------------------------------"
|
||
#endif
|
||
|
||
#include "SDL_ttf.h"
|
||
#ifndef _SDLttf_h
|
||
#error "---------------------------------------------------"
|
||
#error "If you installed SDL_ttf from a package, be sure"
|
||
#error "to get the development package, as well!"
|
||
#error "(e.g., 'libsdl-ttf1.2-devel.rpm')"
|
||
#error "---------------------------------------------------"
|
||
#endif
|
||
|
||
#ifndef NOSOUND
|
||
#include "SDL_mixer.h"
|
||
#ifndef _MIXER_H_
|
||
#error "---------------------------------------------------"
|
||
#error "If you installed SDL_mixer from a package, be sure"
|
||
#error "to get the development package, as well!"
|
||
#error "(e.g., 'libsdl-mixer1.2-devel.rpm')"
|
||
#error "---------------------------------------------------"
|
||
#endif
|
||
#endif
|
||
|
||
#ifndef SAVE_AS_BMP
|
||
#include <png.h>
|
||
#define FNAME_EXTENSION ".png"
|
||
#ifndef PNG_H
|
||
#error "---------------------------------------------------"
|
||
#error "If you installed the PNG libraries from a package,"
|
||
#error "be sure to get the development package, as well!"
|
||
#error "(e.g., 'libpng2-devel.rpm')"
|
||
#error "---------------------------------------------------"
|
||
#endif
|
||
#else
|
||
#define FNAME_EXTENSION ".bmp"
|
||
#endif
|
||
|
||
#define THUMB_W ((WINDOW_WIDTH - 96 - 96) / 4)
|
||
#define THUMB_H (((48 * 7 + 40 + HEIGHTOFFSET) - 72) / 4)
|
||
|
||
#include "tools.h"
|
||
#include "titles.h"
|
||
#include "colors.h"
|
||
#include "shapes.h"
|
||
#include "magic.h"
|
||
#include "sounds.h"
|
||
#include "tip_tux.h"
|
||
#include "great.h"
|
||
|
||
|
||
#include "watch.xbm"
|
||
#include "watch-mask.xbm"
|
||
|
||
#include "hand.xbm"
|
||
#include "hand-mask.xbm"
|
||
|
||
#include "wand.xbm"
|
||
#include "wand-mask.xbm"
|
||
|
||
#include "insertion.xbm"
|
||
#include "insertion-mask.xbm"
|
||
|
||
#include "brush.xbm"
|
||
#include "brush-mask.xbm"
|
||
|
||
#include "crosshair.xbm"
|
||
#include "crosshair-mask.xbm"
|
||
|
||
#include "rotate.xbm"
|
||
#include "rotate-mask.xbm"
|
||
|
||
#include "up.xbm"
|
||
#include "up-mask.xbm"
|
||
|
||
#include "down.xbm"
|
||
#include "down-mask.xbm"
|
||
|
||
#include "tiny.xbm"
|
||
#include "tiny-mask.xbm"
|
||
|
||
#include "arrow.xbm"
|
||
#include "arrow-mask.xbm"
|
||
|
||
|
||
|
||
#ifdef WIN32
|
||
/*
|
||
The SDL stderr redirection trick doesn't seem to work for perror().
|
||
This does pretty much the same thing.
|
||
*/
|
||
static void win32_perror(const char * const str)
|
||
{
|
||
if ( str && *str )
|
||
fprintf(stderr,"%s : ",str);
|
||
fprintf(stderr,
|
||
"%s [%d]\n",
|
||
(errno<_sys_nerr)?_sys_errlist[errno]:"unknown",errno );
|
||
}
|
||
#define perror win32_perror
|
||
#endif
|
||
|
||
|
||
#ifndef WIN32
|
||
#ifdef __GNUC__
|
||
// This version has strict type checking for safety.
|
||
// See the "unnecessary" pointer comparison. (from Linux)
|
||
#define min(x,y) ({ \
|
||
typeof(x) _x = (x); \
|
||
typeof(y) _y = (y); \
|
||
(void) (&_x == &_y); \
|
||
_x < _y ? _x : _y; })
|
||
#define max(x,y) ({ \
|
||
typeof(x) _x = (x); \
|
||
typeof(y) _y = (y); \
|
||
(void) (&_x == &_y); \
|
||
_x > _y ? _x : _y; })
|
||
#else
|
||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||
#endif
|
||
#endif
|
||
|
||
#define clamp(lo,value,hi) (min(max(value,lo),hi))
|
||
|
||
|
||
// since gcc-2.5
|
||
#ifdef __GNUC__
|
||
#define NORETURN __attribute__((__noreturn__))
|
||
#define FUNCTION __attribute__((__const__)) // no access to global mem, even via ptr, and no side effect
|
||
#else
|
||
#define NORETURN
|
||
#define FUNCTION
|
||
#endif
|
||
|
||
#if !defined(restrict) && __STDC_VERSION__ < 199901
|
||
#if __GNUC__ > 2 || __GNUC_MINOR__ >= 92
|
||
#define restrict __restrict__
|
||
#else
|
||
#warning No restrict keyword?
|
||
#define restrict
|
||
#endif
|
||
#endif
|
||
|
||
#if __GNUC__ > 2 || __GNUC_MINOR__ >= 96
|
||
// won't alias anything, and aligned enough for anything
|
||
#define MALLOC __attribute__ ((__malloc__))
|
||
// no side effect, may read globals
|
||
#define PURE __attribute__ ((__pure__))
|
||
// tell gcc what to expect: if(unlikely(err)) die(err);
|
||
#define likely(x) __builtin_expect(!!(x),1)
|
||
#define unlikely(x) __builtin_expect(!!(x),0)
|
||
#define expected(x,y) __builtin_expect((x),(y))
|
||
#else
|
||
#define MALLOC
|
||
#define PURE
|
||
#define likely(x) (x)
|
||
#define unlikely(x) (x)
|
||
#define expected(x,y) (x)
|
||
#endif
|
||
|
||
|
||
/* Unfortunately, there is a bug in SDL_ttf-2.0.6, the current version
|
||
that causes a segmentation fault if an attempt is made to call
|
||
TTF_OpenFont() with the filename of a font that doesn't exist. This
|
||
is an old and well documented bug that is fixed in CVS.
|
||
*/
|
||
static TTF_Font *BUGFIX_TTF_OpenFont206(const char * const file, int ptsize)
|
||
{
|
||
FILE *fp;
|
||
|
||
if ((fp = fopen(file, "rb")) == NULL) return NULL;
|
||
fclose(fp);
|
||
return TTF_OpenFont(file, ptsize);
|
||
}
|
||
#define TTF_OpenFont BUGFIX_TTF_OpenFont206
|
||
|
||
|
||
/* Possible languages: */
|
||
|
||
enum {
|
||
LANG_AF, /* Afrikaans */
|
||
LANG_BE, /* Belarusian */
|
||
LANG_BG, /* Bulgarian */
|
||
LANG_BR, /* Breton */
|
||
LANG_CA, /* Catalan */
|
||
LANG_CS, /* Czech */
|
||
LANG_CY, /* Welsh */
|
||
LANG_DA, /* Danish */
|
||
LANG_DE, /* German */
|
||
LANG_EL, /* Greek */
|
||
LANG_EN, /* English (American) (DEFAULT) */
|
||
LANG_EN_GB, /* English (British) */
|
||
LANG_ES, /* Spanish */
|
||
LANG_EU, /* Basque */
|
||
LANG_FI, /* Finnish */
|
||
LANG_FR, /* French */
|
||
LANG_GL, /* Galician */
|
||
LANG_HE, /* Hebrew */
|
||
LANG_HI, /* Hindi */
|
||
LANG_HR, /* Croatian */
|
||
LANG_HU, /* Hungarian */
|
||
LANG_I_KLINGON_ROMANIZED, /* Klingon (Romanized) */
|
||
LANG_ID, /* Indonesian */
|
||
LANG_IS, /* Icelandic */
|
||
LANG_IT, /* Italian */
|
||
LANG_JA, /* Japanese */
|
||
LANG_KO, /* Korean */
|
||
LANG_LT, /* Lithuanian */
|
||
LANG_MS, /* Malay */
|
||
LANG_NB, /* Norwegian Bokmal */
|
||
LANG_NL, /* Dutch */
|
||
LANG_NN, /* Norwegian Nynorsk */
|
||
LANG_PL, /* Polish */
|
||
LANG_PT_BR, /* Portuguese (Brazilian) */
|
||
LANG_PT_PT, /* Portuguese (Portugal) */
|
||
LANG_RO, /* Romanian */
|
||
LANG_RU, /* Russian */
|
||
LANG_SK, /* Slovak */
|
||
LANG_SL, /* Slovenian */
|
||
LANG_SQ, /* Albanian */
|
||
LANG_SR, /* Serbian */
|
||
LANG_SV, /* Swedish */
|
||
LANG_TA, /* Tamil */
|
||
LANG_TR, /* Turkish */
|
||
LANG_VI, /* Vietnamese */
|
||
LANG_WA, /* Walloon */
|
||
LANG_ZH_CN, /* Chinese (Simplified) */
|
||
LANG_ZH_TW, /* Chinese (Traditional) */
|
||
NUM_LANGS
|
||
};
|
||
|
||
static const char * lang_prefixes[NUM_LANGS] = {
|
||
"af",
|
||
"be",
|
||
"bg",
|
||
"br",
|
||
"ca",
|
||
"cs",
|
||
"cy",
|
||
"da",
|
||
"de",
|
||
"el",
|
||
"en",
|
||
"en_gb",
|
||
"es",
|
||
"eu",
|
||
"fi",
|
||
"fr",
|
||
"gl",
|
||
"he",
|
||
"hi",
|
||
"hr",
|
||
"hu",
|
||
"tlh",
|
||
"id",
|
||
"is",
|
||
"it",
|
||
"ja",
|
||
"ko",
|
||
"lt",
|
||
"ms",
|
||
"nb",
|
||
"nl",
|
||
"nn",
|
||
"pl",
|
||
"pt_br",
|
||
"pt_pt",
|
||
"ro",
|
||
"ru",
|
||
"sk",
|
||
"sl",
|
||
"sq",
|
||
"sr",
|
||
"sv",
|
||
"ta",
|
||
"tr",
|
||
"vi",
|
||
"wa",
|
||
"zh_cn",
|
||
"zh_tw"
|
||
};
|
||
|
||
|
||
/* List of languages which doesn't use the default font: */
|
||
|
||
|
||
static int lang_use_own_font[] = {
|
||
LANG_EL,
|
||
LANG_HE,
|
||
LANG_HI,
|
||
LANG_JA,
|
||
LANG_KO,
|
||
LANG_TA,
|
||
LANG_ZH_CN,
|
||
LANG_ZH_TW,
|
||
-1
|
||
};
|
||
|
||
static int lang_use_right_to_left[] = {
|
||
LANG_HE,
|
||
-1
|
||
};
|
||
|
||
|
||
typedef struct info_type {
|
||
double ratio;
|
||
unsigned tinter;
|
||
int colorable;
|
||
int tintable;
|
||
int mirrorable;
|
||
int flipable;
|
||
int tintgray;
|
||
} info_type;
|
||
|
||
|
||
typedef struct state_type {
|
||
int mirrored;
|
||
int flipped;
|
||
unsigned min,size,max;
|
||
} state_type;
|
||
|
||
|
||
enum {
|
||
SAVE_OVER_PROMPT,
|
||
SAVE_OVER_ALWAYS,
|
||
SAVE_OVER_NO
|
||
};
|
||
|
||
|
||
enum {
|
||
STARTER_OUTLINE,
|
||
STARTER_SCENE
|
||
};
|
||
|
||
|
||
/* Globals: */
|
||
|
||
static int use_sound, fullscreen, disable_quit, simple_shapes, language,
|
||
disable_print, print_delay, only_uppercase, promptless_save, grab_input,
|
||
wheely, no_fancy_cursors, keymouse, mouse_x, mouse_y,
|
||
mousekey_up, mousekey_down, mousekey_left, mousekey_right,
|
||
dont_do_xor, use_print_config, dont_load_stamps, noshortcuts,
|
||
mirrorstamps, disable_stamp_controls, disable_save;
|
||
static int recording, playing;
|
||
static char * playfile;
|
||
static FILE * demofi;
|
||
static int WINDOW_WIDTH, WINDOW_HEIGHT;
|
||
static const char * printcommand;
|
||
static int prog_bar_ctr;
|
||
static SDL_Surface * screen;
|
||
|
||
static SDL_Surface * canvas;
|
||
static SDL_Surface * img_starter, * img_starter_bkgd;
|
||
static int starter_mirrored, starter_flipped;
|
||
|
||
enum {
|
||
UNDO_STARTER_NONE,
|
||
UNDO_STARTER_MIRRORED,
|
||
UNDO_STARTER_FLIPPED
|
||
};
|
||
|
||
#define NUM_UNDO_BUFS 20
|
||
static SDL_Surface * undo_bufs[NUM_UNDO_BUFS];
|
||
static int undo_starters[NUM_UNDO_BUFS];
|
||
static int cur_undo, oldest_undo, newest_undo;
|
||
|
||
static SDL_Surface * img_title, * img_progress;
|
||
static SDL_Surface * img_btn_up, * img_btn_down, * img_btn_off;
|
||
static SDL_Surface * img_yes, * img_no;
|
||
static SDL_Surface * img_open, * img_erase, * img_back;
|
||
static SDL_Surface * img_cursor_up, * img_cursor_down;
|
||
static SDL_Surface * img_cursor_starter_up, * img_cursor_starter_down;
|
||
static SDL_Surface * img_scroll_up, * img_scroll_down;
|
||
static SDL_Surface * img_scroll_up_off, * img_scroll_down_off;
|
||
static SDL_Surface * img_paintcan;
|
||
static SDL_Surface * img_grow, * img_shrink;
|
||
|
||
static SDL_Surface * img_sparkles;
|
||
|
||
static SDL_Surface * img_title_on, * img_title_off,
|
||
* img_title_large_on, * img_title_large_off;
|
||
static SDL_Surface * img_title_names[NUM_TITLES];
|
||
static SDL_Surface * img_tools[NUM_TOOLS], * img_tool_names[NUM_TOOLS];
|
||
|
||
#define MAX_STAMPS 512
|
||
#define MAX_BRUSHES 64
|
||
#define MAX_FONTS 64
|
||
|
||
static int num_brushes, num_stamps;
|
||
static SDL_Surface * img_brushes[MAX_BRUSHES];
|
||
static SDL_Surface * img_stamps[MAX_STAMPS];
|
||
static SDL_Surface * img_stamps_premirror[MAX_STAMPS];
|
||
static char * txt_stamps[MAX_STAMPS];
|
||
static info_type * inf_stamps[MAX_STAMPS];
|
||
static state_type * state_stamps[MAX_STAMPS];
|
||
#ifndef NOSOUND
|
||
static Mix_Chunk * snd_stamps[MAX_STAMPS];
|
||
#endif
|
||
static SDL_Surface * img_stamp_thumbs[MAX_STAMPS],
|
||
* img_stamp_thumbs_premirror[MAX_STAMPS];
|
||
|
||
static SDL_Surface * img_shapes[NUM_SHAPES], * img_shape_names[NUM_SHAPES];
|
||
static SDL_Surface * img_magics[NUM_MAGICS], * img_magic_names[NUM_MAGICS];
|
||
static SDL_Surface * img_openlabels_open, * img_openlabels_erase,
|
||
* img_openlabels_back;
|
||
|
||
static SDL_Surface * img_tux[NUM_TIP_TUX];
|
||
|
||
#ifndef LOW_QUALITY_COLOR_SELECTOR
|
||
static SDL_Surface * img_color_btns[NUM_COLORS];
|
||
#endif
|
||
|
||
static SDL_Surface * img_cur_brush;
|
||
static int brush_counter, rainbow_color;
|
||
|
||
static TTF_Font * font, * small_font, * large_font, * locale_font;
|
||
static TTF_Font * fonts[MAX_FONTS];
|
||
static int num_fonts;
|
||
|
||
#ifndef NOSOUND
|
||
static Mix_Chunk * sounds[NUM_SOUNDS];
|
||
#endif
|
||
|
||
|
||
#define NUM_ERASERS 6 /* How many sizes of erasers (from ERASER_MIN to _MAX) */
|
||
#define ERASER_MIN 13
|
||
#define ERASER_MAX 128
|
||
|
||
|
||
static SDL_Cursor * cursor_hand, * cursor_arrow, * cursor_watch,
|
||
* cursor_up, * cursor_down, * cursor_tiny, * cursor_crosshair,
|
||
* cursor_brush, * cursor_wand, * cursor_insertion, * cursor_rotate;
|
||
|
||
|
||
static int cur_tool, cur_color, cur_brush, cur_stamp, cur_shape, cur_magic;
|
||
static int cur_font, cur_eraser;
|
||
static int cursor_left, cursor_x, cursor_y, cursor_textwidth;
|
||
static int colors_are_selectable;
|
||
static int been_saved;
|
||
static char file_id[32];
|
||
static char starter_id[32];
|
||
static int brush_scroll, stamp_scroll, font_scroll;
|
||
static int eraser_sound;
|
||
|
||
static char texttool_str[256];
|
||
static unsigned int texttool_len;
|
||
|
||
static int tool_avail[NUM_TOOLS], tool_avail_bak[NUM_TOOLS];
|
||
|
||
typedef struct edge_type {
|
||
int y_upper;
|
||
float x_intersect, dx_per_scan;
|
||
struct edge_type * next;
|
||
} edge;
|
||
|
||
|
||
typedef struct point_type {
|
||
int x, y;
|
||
} point_type;
|
||
|
||
typedef struct fpoint_type {
|
||
float x, y;
|
||
} fpoint_type;
|
||
|
||
typedef enum { Left, Right, Bottom, Top } an_edge;
|
||
#define NUM_EDGES 4
|
||
|
||
static SDL_Event scrolltimer_event;
|
||
|
||
static char * langstr;
|
||
static char * savedir;
|
||
|
||
#ifdef USE_HQ4X
|
||
static int RGBtoYUV[65536];
|
||
#endif
|
||
|
||
typedef struct dirent2 {
|
||
struct dirent f;
|
||
int place;
|
||
} dirent2;
|
||
|
||
|
||
/* Local function prototypes: */
|
||
|
||
static void mainloop(void);
|
||
static void brush_draw(int x1, int y1, int x2, int y2, int update);
|
||
static void blit_brush(int x, int y);
|
||
static void magic_draw(int x1, int y1, int x2, int y2, int button_down);
|
||
static void blit_magic(int x, int y, int button_down);
|
||
static void stamp_draw(int x, int y);
|
||
static void rec_undo_buffer(void);
|
||
static void update_canvas(int x1, int y1, int x2, int y2);
|
||
static void show_usage(FILE * f, char * prg);
|
||
static void show_lang_usage(FILE * f, char * prg);
|
||
static void show_locale_usage(FILE * f, char * prg);
|
||
static void setup(int argc, char * argv[]);
|
||
static SDL_Cursor * get_cursor(char * bits, char * mask_bits,
|
||
int w, int h, int x, int y);
|
||
static void seticon(void);
|
||
static SDL_Surface * loadimage(const char * const fname);
|
||
static SDL_Surface * do_loadimage(const char * const fname, int abort_on_error);
|
||
static SDL_Surface * loadaltimage(const char * const fname);
|
||
static void draw_toolbar(void);
|
||
static void draw_magic(void);
|
||
static void draw_colors(int enabled);
|
||
static void draw_brushes(void);
|
||
static void draw_stamps(void);
|
||
static void draw_shapes(void);
|
||
static void draw_erasers(void);
|
||
static void draw_fonts(void);
|
||
static void draw_none(void);
|
||
#ifndef NOSOUND
|
||
static void loadarbitrary(SDL_Surface * surfs[], SDL_Surface * altsurfs[],
|
||
char * descs[], info_type * infs[],
|
||
Mix_Chunk * sounds[], int * count, int starting, int max,
|
||
const char * const dir, int fatal, int maxw, int maxh);
|
||
#else
|
||
static void loadarbitrary(SDL_Surface * surfs[], SDL_Surface * altsurfs[],
|
||
char * descs[], info_type * infs[],
|
||
int * count, int starting, int max,
|
||
const char * const dir, int fatal, int maxw, int maxh);
|
||
#endif
|
||
static SDL_Surface * thumbnail(SDL_Surface * src, int max_x, int max_y,
|
||
int keep_aspect);
|
||
|
||
static Uint32 getpixel(SDL_Surface * surface, int x, int y);
|
||
static void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel);
|
||
static void clipped_putpixel(SDL_Surface * dest, int x, int y, Uint32 c);
|
||
|
||
static void debug(const char * const str);
|
||
static void do_undo(void);
|
||
static void do_redo(void);
|
||
static void render_brush(void);
|
||
static void playsound(int chan, int s, int override);
|
||
static void line_xor(int x1, int y1, int x2, int y2);
|
||
static void rect_xor(int x1, int y1, int x2, int y2);
|
||
static void update_stamp_xor(void);
|
||
static void stamp_xor(int x1, int y1);
|
||
static void do_eraser(int x, int y);
|
||
static void disable_avail_tools(void);
|
||
static void enable_avail_tools(void);
|
||
static void reset_avail_tools(void);
|
||
static void update_screen(int x1, int y1, int x2, int y2);
|
||
static Uint8 alpha(Uint8 c1, Uint8 c2, Uint8 a);
|
||
static int compare_strings(char * * s1, char * * s2);
|
||
static int compare_dirent2s(struct dirent2 * f1, struct dirent2 * f2);
|
||
static void draw_tux_text(int which_tux, const char * const str,
|
||
int want_right_to_left);
|
||
static void wordwrap_text(const char * const str, SDL_Color color,
|
||
int left, int top, int right,
|
||
int want_right_to_left);
|
||
static char * loaddesc(const char * const fname);
|
||
static info_type * loadinfo(const char * const fname);
|
||
#ifndef NOSOUND
|
||
static Mix_Chunk * loadsound(const char * const fname);
|
||
#endif
|
||
static void do_wait(void);
|
||
static void load_current(void);
|
||
static void save_current(void);
|
||
static char * get_fname(const char * const name);
|
||
static int do_prompt(const char * const text, const char * const btn_yes, const char * const btn_no);
|
||
static void cleanup(void);
|
||
static void free_cursor(SDL_Cursor ** cursor);
|
||
static void free_surface(SDL_Surface **surface_array);
|
||
static void free_surface_array(SDL_Surface *surface_array[], int count);
|
||
//static void update_shape(int cx, int ox1, int ox2, int cy, int oy1, int oy2,
|
||
// int fixed);
|
||
static void do_shape(int cx, int cy, int ox, int oy, int rotn, int use_brush);
|
||
static int rotation(int ctr_x, int ctr_y, int ox, int oy);
|
||
static int do_save(void);
|
||
static int do_png_save(FILE * fi, const char * const fname, SDL_Surface * surf);
|
||
static void get_new_file_id(void);
|
||
static int do_quit(void);
|
||
static int do_open(int want_new_tool);
|
||
#ifdef SCAN_FILL
|
||
static void scan_fill(int cnt, point_type * pts);
|
||
#endif
|
||
#ifdef SCANLINE_POLY_FILL
|
||
static int clip_polygon(int n, fpoint_type * pin, fpoint_type * pout);
|
||
#endif
|
||
static void wait_for_sfx(void);
|
||
static int current_language(void);
|
||
static int stamp_colorable(int stamp);
|
||
static int stamp_tintable(int stamp);
|
||
static int stamp_tintgray(int stamp);
|
||
static void rgbtohsv(Uint8 r8, Uint8 g8, Uint8 b8, float *h, float *s, float *v);
|
||
static void hsvtorgb(float h, float s, float v, Uint8 *r8, Uint8 *g8, Uint8 *b8);
|
||
static void show_progress_bar(void);
|
||
static void do_print(void);
|
||
static void strip_trailing_whitespace(char * buf);
|
||
static void do_render_cur_text(int do_blit);
|
||
static void loadfonts(const char * const dir, int fatal);
|
||
static char * uppercase(char * str);
|
||
static unsigned char * textdir(const unsigned char * const str);
|
||
static SDL_Surface * do_render_button_label(const char * const label);
|
||
static void create_button_labels(void);
|
||
static int colors_close(Uint32 c1, Uint32 c2);
|
||
static void do_flood_fill(int x, int y, Uint32 cur_colr, Uint32 old_colr);
|
||
static Uint32 scrolltimer_callback(Uint32 interval, void *param);
|
||
static Uint32 drawtext_callback(Uint32 interval, void *param);
|
||
static void control_drawtext_timer(Uint32 interval, const char * const text);
|
||
static void parse_options(FILE * fi);
|
||
static void do_setcursor(SDL_Cursor * c);
|
||
static const char * great_str(void);
|
||
static void draw_image_title(int t, int x);
|
||
static int need_own_font(int l);
|
||
static int need_right_to_left(int l);
|
||
static void handle_keymouse(SDLKey key, Uint8 updown);
|
||
static void handle_active(SDL_Event * event);
|
||
static char * remove_slash(char * path);
|
||
static void anti_carriage_return(int left, int right, int cur_top, int new_top,
|
||
int cur_bot, int line_width);
|
||
static int mySDL_WaitEvent(SDL_Event *event);
|
||
static int mySDL_PollEvent(SDL_Event *event);
|
||
static void load_starter_id(char * saved_id);
|
||
static void load_starter(char * img_id);
|
||
static SDL_Surface * duplicate_surface(SDL_Surface * orig);
|
||
static TTF_Font *try_alternate_font(int language);
|
||
static void mirror_starter(void);
|
||
static void flip_starter(void);
|
||
|
||
#ifdef DEBUG
|
||
static char * debug_gettext(const char * str);
|
||
static int charsize(char c);
|
||
#endif
|
||
|
||
|
||
#define MAX_UTF8_CHAR_LENGTH 6
|
||
|
||
#define USEREVENT_TEXT_UPDATE 1
|
||
|
||
|
||
/* --- MAIN --- */
|
||
|
||
int main(int argc, char * argv[])
|
||
{
|
||
SDL_Surface * tmp_surf;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
SDL_Rect dest;
|
||
char tmp_str[128];
|
||
|
||
/* Set up locale support */
|
||
|
||
setlocale(LC_ALL, "");
|
||
|
||
|
||
/* Set up! */
|
||
|
||
setup(argc, argv);
|
||
|
||
|
||
do_setcursor(cursor_arrow);
|
||
|
||
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
|
||
dest.x = (WINDOW_WIDTH - img_title->w) / 2;
|
||
dest.y = (WINDOW_HEIGHT - img_title->h);
|
||
|
||
SDL_BlitSurface(img_title, NULL, screen, &dest);
|
||
|
||
snprintf(tmp_str, sizeof(tmp_str), "%s – %s", VER_VERSION, VER_DATE);
|
||
tmp_surf = TTF_RenderUTF8_Blended(font, tmp_str, black);
|
||
dest.x = 20 + (WINDOW_WIDTH - img_title->w) / 2;
|
||
dest.y = WINDOW_HEIGHT - 60;
|
||
SDL_BlitSurface(tmp_surf, NULL, screen, &dest);
|
||
SDL_FreeSurface(tmp_surf);
|
||
SDL_Flip(screen);
|
||
playsound(0, SND_HARP, 1);
|
||
|
||
do_wait();
|
||
SDL_FreeSurface(img_title);
|
||
|
||
|
||
/* Set defaults! */
|
||
|
||
cur_undo = 0;
|
||
oldest_undo = 0;
|
||
newest_undo = 0;
|
||
|
||
cur_tool = TOOL_BRUSH;
|
||
cur_color = COLOR_BLACK;
|
||
colors_are_selectable = 1;
|
||
cur_brush = 0;
|
||
cur_stamp = 0;
|
||
cur_shape = SHAPE_SQUARE;
|
||
cur_magic = 0;
|
||
cur_font = 0;
|
||
cur_eraser = 0;
|
||
cursor_left = -1;
|
||
cursor_x = -1;
|
||
cursor_y = -1;
|
||
cursor_textwidth = 0;
|
||
|
||
mouse_x = WINDOW_WIDTH / 2;
|
||
mouse_y = WINDOW_HEIGHT / 2;
|
||
SDL_WarpMouse(mouse_x, mouse_y);
|
||
|
||
mousekey_up = SDL_KEYUP;
|
||
mousekey_down = SDL_KEYUP;
|
||
mousekey_left = SDL_KEYUP;
|
||
mousekey_right = SDL_KEYUP;
|
||
|
||
eraser_sound = 0;
|
||
|
||
img_cur_brush = NULL;
|
||
render_brush();
|
||
|
||
brush_scroll = 0;
|
||
stamp_scroll = 0;
|
||
font_scroll = 0;
|
||
|
||
|
||
reset_avail_tools();
|
||
|
||
|
||
/* Load current image (if any): */
|
||
|
||
load_current();
|
||
been_saved = 1;
|
||
tool_avail[TOOL_SAVE] = 0;
|
||
|
||
|
||
/* Draw the screen! */
|
||
|
||
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
|
||
draw_toolbar();
|
||
draw_colors(1);
|
||
draw_brushes();
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
SDL_Flip(screen);
|
||
|
||
|
||
/* Main loop! */
|
||
|
||
mainloop();
|
||
|
||
|
||
/* Close and quit! */
|
||
|
||
save_current();
|
||
|
||
wait_for_sfx();
|
||
|
||
|
||
cleanup();
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* FIXME: Move elsewhere!!! */
|
||
|
||
#define PROMPT_QUIT_TXT gettext_noop("Do you really want to quit?")
|
||
#define PROMPT_QUIT_YES gettext_noop("Yes")
|
||
#define PROMPT_QUIT_NO gettext_noop("No")
|
||
|
||
#define PROMPT_QUIT_SAVE_TXT gettext_noop("If you quit, you’ll lose your picture! Save it?")
|
||
#define PROMPT_QUIT_SAVE_YES gettext_noop("Yes")
|
||
#define PROMPT_QUIT_SAVE_NO gettext_noop("No")
|
||
|
||
#define PROMPT_OPEN_SAVE_TXT gettext_noop("Save your picture first?")
|
||
#define PROMPT_OPEN_SAVE_YES gettext_noop("Yes")
|
||
#define PROMPT_OPEN_SAVE_NO gettext_noop("No")
|
||
|
||
#define PROMPT_OPEN_UNOPENABLE_TXT gettext_noop("Can’t open that picture!")
|
||
#define PROMPT_OPEN_UNOPENABLE_YES gettext_noop("OK")
|
||
|
||
#define PROMPT_NEW_TXT gettext_noop("Starting a new picture will erase the current one!")
|
||
#define PROMPT_NEW_YES gettext_noop("That’s OK!")
|
||
#define PROMPT_NEW_NO gettext_noop("Never mind!")
|
||
|
||
#define PROMPT_OPEN_NOFILES_TXT gettext_noop("There are no saved files!")
|
||
#define PROMPT_OPEN_NOFILES_YES gettext_noop("OK")
|
||
|
||
#define PROMPT_PRINT_NOW_TXT gettext_noop("Print your picture now?")
|
||
#define PROMPT_PRINT_NOW_YES gettext_noop("Yes")
|
||
#define PROMPT_PRINT_NOW_NO gettext_noop("No")
|
||
|
||
#define PROMPT_PRINT_TXT gettext_noop("Your picture has been printed!")
|
||
#define PROMPT_PRINT_YES gettext_noop("OK")
|
||
|
||
#define PROMPT_PRINT_TOO_SOON_TXT gettext_noop("You can’t print yet!")
|
||
#define PROMPT_PRINT_TOO_SOON_YES gettext_noop("OK")
|
||
|
||
#define PROMPT_ERASE_TXT gettext_noop("Erase this picture?")
|
||
#define PROMPT_ERASE_YES gettext_noop("Yes")
|
||
#define PROMPT_ERASE_NO gettext_noop("No")
|
||
|
||
|
||
enum {
|
||
SHAPE_TOOL_MODE_STRETCH,
|
||
SHAPE_TOOL_MODE_ROTATE,
|
||
SHAPE_TOOL_MODE_DONE
|
||
};
|
||
|
||
|
||
/* --- MAIN LOOP! --- */
|
||
|
||
static void mainloop(void)
|
||
{
|
||
int done, off_y, which, button_down, old_x, old_y, new_x, new_y,
|
||
line_start_x, line_start_y, w, h, shape_tool_mode,
|
||
shape_ctr_x, shape_ctr_y, shape_outer_x, shape_outer_y;
|
||
int num_things, thing_scroll, cur_thing, old_thing, do_draw, old_tool,
|
||
tmp_int, max;
|
||
int cur_time, last_print_time, scrolling, ignoring_motion;
|
||
SDL_TimerID scrolltimer;
|
||
SDL_Event event;
|
||
SDLKey key, key_down;
|
||
Uint16 key_unicode;
|
||
SDLMod mod;
|
||
Uint32 last_cursor_blink, cur_cursor_blink,
|
||
pre_event_time, current_event_time;
|
||
|
||
|
||
num_things = 0;
|
||
thing_scroll = 0;
|
||
cur_thing = 0;
|
||
old_thing = 0;
|
||
do_draw = 0;
|
||
old_x = 0;
|
||
old_y = 0;
|
||
new_x = 0;
|
||
new_y = 0;
|
||
line_start_x = 0;
|
||
line_start_y = 0;
|
||
shape_ctr_x = 0;
|
||
shape_ctr_y = 0;
|
||
shape_outer_x = 0;
|
||
shape_outer_y =0;
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
button_down = 0;
|
||
last_print_time = -print_delay;
|
||
last_cursor_blink = 0;
|
||
texttool_len = 0;
|
||
scrolling = 0;
|
||
scrolltimer = 0;
|
||
key_down = SDLK_LAST;
|
||
key_unicode = 0;
|
||
|
||
|
||
done = 0;
|
||
|
||
do
|
||
{
|
||
ignoring_motion = 0;
|
||
|
||
pre_event_time = SDL_GetTicks();
|
||
|
||
|
||
while (mySDL_PollEvent(&event))
|
||
{
|
||
current_event_time = SDL_GetTicks();
|
||
|
||
if (current_event_time > pre_event_time + 250)
|
||
ignoring_motion = 1;
|
||
|
||
|
||
if (event.type == SDL_QUIT)
|
||
{
|
||
done = do_quit();
|
||
}
|
||
else if (event.type == SDL_ACTIVEEVENT)
|
||
{
|
||
handle_active(&event);
|
||
}
|
||
else if (event.type == SDL_KEYUP)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
|
||
handle_keymouse(key, SDL_KEYUP);
|
||
}
|
||
else if (event.type == SDL_KEYDOWN)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
mod = event.key.keysym.mod;
|
||
|
||
handle_keymouse(key, SDL_KEYDOWN);
|
||
|
||
if (key == SDLK_ESCAPE)
|
||
{
|
||
done = do_quit();
|
||
}
|
||
#ifdef WIN32
|
||
else if (key == SDLK_F4 && (mod & KMOD_ALT))
|
||
{
|
||
done = do_quit();
|
||
}
|
||
#endif
|
||
else if (key == SDLK_z &&
|
||
(mod & KMOD_CTRL ||
|
||
mod & KMOD_LCTRL ||
|
||
mod & KMOD_RCTRL) &&
|
||
!noshortcuts)
|
||
{
|
||
/* Ctrl-Z - Undo */
|
||
|
||
if (tool_avail[TOOL_UNDO])
|
||
{
|
||
if (cur_undo == newest_undo)
|
||
{
|
||
rec_undo_buffer();
|
||
do_undo();
|
||
}
|
||
do_undo();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
}
|
||
}
|
||
else if (key == SDLK_r &&
|
||
(mod & KMOD_CTRL ||
|
||
mod & KMOD_LCTRL ||
|
||
mod & KMOD_RCTRL) &&
|
||
!noshortcuts)
|
||
{
|
||
/* Ctrl-R - Redo */
|
||
|
||
if (tool_avail[TOOL_REDO])
|
||
{
|
||
do_redo();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
}
|
||
}
|
||
else if (key == SDLK_o &&
|
||
(mod & KMOD_CTRL ||
|
||
mod & KMOD_LCTRL ||
|
||
mod & KMOD_RCTRL) &&
|
||
!noshortcuts)
|
||
{
|
||
/* Ctrl-O - Open */
|
||
|
||
tmp_int = tool_avail[TOOL_NEW];
|
||
disable_avail_tools();
|
||
draw_toolbar();
|
||
draw_colors(0);
|
||
draw_none();
|
||
|
||
tmp_int = do_open(tmp_int);
|
||
|
||
enable_avail_tools();
|
||
tool_avail[TOOL_NEW] = tmp_int;
|
||
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
|
||
if (cur_tool == TOOL_BRUSH ||
|
||
cur_tool == TOOL_LINES ||
|
||
cur_tool == TOOL_SHAPES ||
|
||
cur_tool == TOOL_TEXT)
|
||
{
|
||
draw_colors(1);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
draw_colors(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp));
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC &&
|
||
cur_magic == MAGIC_FILL)
|
||
{
|
||
draw_colors(1);
|
||
}
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
draw_brushes();
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
draw_magic();
|
||
else if (cur_tool == TOOL_STAMP)
|
||
draw_stamps();
|
||
else if (cur_tool == TOOL_TEXT)
|
||
draw_fonts();
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
draw_shapes();
|
||
else if (cur_tool == TOOL_ERASER)
|
||
draw_erasers();
|
||
|
||
draw_tux_text(TUX_GREAT, tool_tips[cur_tool], 1);
|
||
|
||
|
||
/* FIXME: Make delay configurable: */
|
||
|
||
control_drawtext_timer(1000, tool_tips[cur_tool]);
|
||
}
|
||
else if ((key == SDLK_n &&
|
||
((mod & KMOD_CTRL ||
|
||
mod & KMOD_LCTRL ||
|
||
mod & KMOD_RCTRL))) && tool_avail[TOOL_NEW] &&
|
||
!noshortcuts)
|
||
{
|
||
/* Ctrl-N - New */
|
||
|
||
if (do_prompt(PROMPT_NEW_TXT,
|
||
PROMPT_NEW_YES,
|
||
PROMPT_NEW_NO))
|
||
{
|
||
free_surface(&img_starter);
|
||
free_surface(&img_starter_bkgd);
|
||
starter_mirrored = 0;
|
||
starter_flipped = 0;
|
||
|
||
SDL_FillRect(canvas, NULL,
|
||
SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
update_canvas(0, 0,
|
||
WINDOW_WIDTH - 96,
|
||
(48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
cur_undo = 0;
|
||
oldest_undo = 0;
|
||
newest_undo = 0;
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
|
||
been_saved = 1;
|
||
reset_avail_tools();
|
||
|
||
file_id[0] = '\0';
|
||
starter_id[0] = '\0';
|
||
|
||
playsound(1, SND_HARP, 1);
|
||
}
|
||
else
|
||
{
|
||
draw_tux_text(tool_tux[TUX_DEFAULT], TIP_NEW_ABORT,
|
||
1);
|
||
}
|
||
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
else if (key == SDLK_s &&
|
||
(mod & KMOD_CTRL ||
|
||
mod & KMOD_LCTRL ||
|
||
mod & KMOD_RCTRL) &&
|
||
!noshortcuts)
|
||
{
|
||
/* Ctrl-S - Save */
|
||
|
||
if (do_save())
|
||
{
|
||
/* Only think it's been saved if it HAS been saved :^) */
|
||
|
||
been_saved = 1;
|
||
tool_avail[TOOL_SAVE] = 0;
|
||
}
|
||
|
||
/* cur_tool = old_tool; */
|
||
draw_toolbar();
|
||
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
else
|
||
{
|
||
/* Handle key in text tool: */
|
||
|
||
if (cur_tool == TOOL_TEXT &&
|
||
cursor_x != -1 && cursor_y != -1)
|
||
{
|
||
key_down = key;
|
||
key_unicode = event.key.keysym.unicode;
|
||
|
||
#ifdef DEBUG
|
||
printf("charsize(%c) = %d\n", event.key.keysym.unicode,
|
||
charsize(event.key.keysym.unicode));
|
||
#endif
|
||
|
||
if (key_down == SDLK_BACKSPACE)
|
||
{
|
||
|
||
if (texttool_len > 0)
|
||
{
|
||
texttool_len--;
|
||
texttool_str[texttool_len] = '\0';
|
||
playsound(0, SND_KEYCLICK, 1);
|
||
|
||
do_render_cur_text(0);
|
||
}
|
||
}
|
||
else if (key_down == SDLK_RETURN)
|
||
{
|
||
if (texttool_len > 0)
|
||
{
|
||
rec_undo_buffer();
|
||
do_render_cur_text(1);
|
||
texttool_len = 0;
|
||
cursor_textwidth = 0;
|
||
}
|
||
|
||
cursor_x = cursor_left;
|
||
cursor_y = cursor_y + TTF_FontHeight(fonts[cur_font]);
|
||
|
||
if (cursor_y > ((48 * 7 + 40 + HEIGHTOFFSET) -
|
||
TTF_FontHeight(fonts[cur_font])))
|
||
{
|
||
cursor_y = ((48 * 7 + 40 + HEIGHTOFFSET) -
|
||
TTF_FontHeight(fonts[cur_font]));
|
||
}
|
||
|
||
playsound(0, SND_RETURN, 1);
|
||
}
|
||
else if (isprint(key_unicode))
|
||
{
|
||
if (texttool_len < sizeof(texttool_str) - MAX_UTF8_CHAR_LENGTH)
|
||
{
|
||
#ifdef DEBUG
|
||
printf(" key = %c\n"
|
||
"unicode = %c (%d)\n\n",
|
||
key_down, key_unicode, key_unicode);
|
||
#endif
|
||
|
||
texttool_str[texttool_len++] = key_unicode;
|
||
|
||
texttool_str[texttool_len] = '\0';
|
||
playsound(0, SND_KEYCLICK, 1);
|
||
do_render_cur_text(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if ((event.type == SDL_MOUSEBUTTONDOWN &&
|
||
event.button.button >= 1 &&
|
||
event.button.button <= 3))
|
||
{
|
||
if (/* event.button.x >= 0 && */
|
||
event.button.x < 96 &&
|
||
event.button.y >= 40 &&
|
||
event.button.y < (48 * 7) + 40) /* FIXME: FIX ME? */
|
||
{
|
||
/* A tool on the left has been pressed! */
|
||
|
||
which = ((event.button.y - 40) / 48) * 2 +
|
||
(event.button.x / 48);
|
||
|
||
if (which < NUM_TOOLS && tool_avail[which])
|
||
{
|
||
/* Render any current text: */
|
||
|
||
if (cur_tool == TOOL_TEXT && which != TOOL_TEXT &&
|
||
texttool_len > 0)
|
||
{
|
||
if (cursor_x != -1 && cursor_y != -1)
|
||
{
|
||
if (texttool_len > 0)
|
||
{
|
||
rec_undo_buffer();
|
||
do_render_cur_text(1);
|
||
texttool_len = 0;
|
||
cursor_textwidth = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
old_tool = cur_tool;
|
||
cur_tool = which;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
|
||
playsound(1, SND_CLICK, 0);
|
||
|
||
draw_tux_text(tool_tux[cur_tool], tool_tips[cur_tool],
|
||
1);
|
||
|
||
|
||
/* Draw items for this tool: */
|
||
|
||
if (cur_tool == TOOL_BRUSH)
|
||
{
|
||
cur_thing = cur_brush;
|
||
draw_brushes();
|
||
draw_colors(1);
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
cur_thing = cur_eraser;
|
||
draw_erasers();
|
||
draw_colors(0);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
cur_thing = cur_stamp;
|
||
draw_stamps();
|
||
draw_colors(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp));
|
||
|
||
update_stamp_xor();
|
||
}
|
||
else if (cur_tool == TOOL_LINES)
|
||
{
|
||
cur_thing = cur_brush;
|
||
draw_brushes();
|
||
draw_colors(1);
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
cur_thing = cur_shape;
|
||
draw_shapes();
|
||
draw_colors(1);
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
cur_thing = cur_font;
|
||
draw_fonts();
|
||
draw_colors(1);
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
cur_thing = cur_eraser;
|
||
draw_erasers();
|
||
draw_colors(0);
|
||
}
|
||
else if (cur_tool == TOOL_UNDO)
|
||
{
|
||
if (cur_undo == newest_undo)
|
||
{
|
||
rec_undo_buffer();
|
||
do_undo();
|
||
}
|
||
do_undo();
|
||
|
||
been_saved = 0;
|
||
|
||
if (!disable_save)
|
||
tool_avail[TOOL_SAVE] = 1;
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
}
|
||
else if (cur_tool == TOOL_REDO)
|
||
{
|
||
do_redo();
|
||
|
||
been_saved = 0;
|
||
|
||
if (!disable_save)
|
||
tool_avail[TOOL_SAVE] = 1;
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
}
|
||
else if (cur_tool == TOOL_OPEN)
|
||
{
|
||
tmp_int = tool_avail[TOOL_NEW];
|
||
disable_avail_tools();
|
||
draw_toolbar();
|
||
draw_colors(0);
|
||
draw_none();
|
||
|
||
tmp_int = do_open(tmp_int);
|
||
|
||
enable_avail_tools();
|
||
tool_avail[TOOL_NEW] = tmp_int;
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
|
||
draw_tux_text(TUX_GREAT, tool_tips[cur_tool], 1);
|
||
|
||
if (cur_tool == TOOL_BRUSH ||
|
||
cur_tool == TOOL_LINES ||
|
||
cur_tool == TOOL_SHAPES ||
|
||
cur_tool == TOOL_TEXT)
|
||
{
|
||
draw_colors(1);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
draw_colors(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp));
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC &&
|
||
cur_magic == MAGIC_FILL)
|
||
{
|
||
draw_colors(1);
|
||
}
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
draw_brushes();
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
draw_magic();
|
||
else if (cur_tool == TOOL_STAMP)
|
||
draw_stamps();
|
||
else if (cur_tool == TOOL_TEXT)
|
||
draw_fonts();
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
draw_shapes();
|
||
else if (cur_tool == TOOL_ERASER)
|
||
draw_erasers();
|
||
}
|
||
else if (cur_tool == TOOL_SAVE)
|
||
{
|
||
if (do_save())
|
||
{
|
||
been_saved = 1;
|
||
tool_avail[TOOL_SAVE] = 0;
|
||
}
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
else if (cur_tool == TOOL_NEW)
|
||
{
|
||
if (do_prompt(PROMPT_NEW_TXT,
|
||
PROMPT_NEW_YES,
|
||
PROMPT_NEW_NO))
|
||
{
|
||
free_surface(&img_starter);
|
||
free_surface(&img_starter_bkgd);
|
||
starter_mirrored = 0;
|
||
starter_flipped = 0;
|
||
|
||
SDL_FillRect(canvas, NULL,
|
||
SDL_MapRGB(canvas->format,
|
||
255, 255, 255));
|
||
update_canvas(0, 0,
|
||
WINDOW_WIDTH - 96,
|
||
(48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
cur_undo = 0;
|
||
oldest_undo = 0;
|
||
newest_undo = 0;
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
|
||
been_saved = 1;
|
||
reset_avail_tools();
|
||
|
||
file_id[0] = '\0';
|
||
starter_id[0] = '\0';
|
||
|
||
playsound(1, SND_HARP, 1);
|
||
}
|
||
else
|
||
{
|
||
draw_tux_text(tool_tux[TUX_DEFAULT],
|
||
TIP_NEW_ABORT, 1);
|
||
}
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
else if (cur_tool == TOOL_PRINT)
|
||
{
|
||
cur_time = SDL_GetTicks() / 1000;
|
||
|
||
#ifdef DEBUG
|
||
printf("Current time = %d\n", cur_time);
|
||
#endif
|
||
|
||
if (cur_time >= last_print_time + print_delay)
|
||
{
|
||
if (do_prompt(PROMPT_PRINT_NOW_TXT,
|
||
PROMPT_PRINT_NOW_YES,
|
||
PROMPT_PRINT_NOW_NO))
|
||
{
|
||
do_print();
|
||
|
||
last_print_time = cur_time;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
do_prompt(PROMPT_PRINT_TOO_SOON_TXT,
|
||
PROMPT_PRINT_TOO_SOON_YES,
|
||
"");
|
||
}
|
||
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
cur_thing = cur_magic;
|
||
rainbow_color = 0;
|
||
draw_magic();
|
||
|
||
if (cur_magic == MAGIC_FILL)
|
||
draw_colors(1);
|
||
else
|
||
draw_colors(0);
|
||
}
|
||
else if (cur_tool == TOOL_QUIT)
|
||
{
|
||
done = do_quit();
|
||
cur_tool = old_tool;
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
}
|
||
}
|
||
else if (event.button.x >= WINDOW_WIDTH - 96 &&
|
||
event.button.x < WINDOW_WIDTH &&
|
||
event.button.y >= 40 &&
|
||
event.button.y < (48 * (7 + TOOLOFFSET / 2)) + 40)
|
||
{
|
||
/* Options on the right have been pressed! */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_STAMP ||
|
||
cur_tool == TOOL_SHAPES || cur_tool == TOOL_LINES ||
|
||
cur_tool == TOOL_MAGIC || cur_tool == TOOL_TEXT ||
|
||
cur_tool == TOOL_ERASER)
|
||
{
|
||
/* Note set of things we're dealing with */
|
||
/* (stamps, brushes, etc.) */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
{
|
||
num_things = num_brushes;
|
||
thing_scroll = brush_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
num_things = num_stamps;
|
||
thing_scroll = stamp_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
num_things = num_fonts;
|
||
thing_scroll = font_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
num_things = NUM_SHAPES;
|
||
thing_scroll = 0;
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
num_things = NUM_MAGICS;
|
||
thing_scroll = 0;
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
num_things = NUM_ERASERS;
|
||
thing_scroll = 0;
|
||
}
|
||
|
||
do_draw = 0;
|
||
|
||
|
||
/* Deal with scroll buttons: */
|
||
|
||
max = 14;
|
||
|
||
if (cur_tool == TOOL_STAMP && !disable_stamp_controls)
|
||
max = 10;
|
||
|
||
if (num_things > max + TOOLOFFSET)
|
||
{
|
||
if (event.button.y < 40 + 24)
|
||
{
|
||
if (thing_scroll > 0)
|
||
{
|
||
thing_scroll = thing_scroll - 2;
|
||
do_draw = 1;
|
||
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (scrolling == 0)
|
||
{
|
||
memcpy(&scrolltimer_event,
|
||
&event,
|
||
sizeof(SDL_Event));
|
||
|
||
|
||
/* FIXME: Make delay value changable: */
|
||
|
||
scrolltimer =
|
||
SDL_AddTimer(REPEAT_SPEED,
|
||
scrolltimer_callback,
|
||
(void*) &scrolltimer_event);
|
||
|
||
scrolling = 1;
|
||
}
|
||
else
|
||
{
|
||
SDL_RemoveTimer(scrolltimer);
|
||
|
||
scrolltimer =
|
||
SDL_AddTimer(REPEAT_SPEED / 3,
|
||
scrolltimer_callback,
|
||
(void*) &scrolltimer_event);
|
||
}
|
||
|
||
|
||
if (thing_scroll == 0)
|
||
{
|
||
do_setcursor(cursor_arrow);
|
||
|
||
if (scrolling == 1)
|
||
{
|
||
SDL_RemoveTimer(scrolltimer);
|
||
scrolling = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (event.button.y >=
|
||
(48 * ((max - 2) / 2 + TOOLOFFSET / 2)) + 40 + 24 &&
|
||
event.button.y <
|
||
(48 * ((max - 2) / 2 + TOOLOFFSET / 2)) + 40 + 24 + 24)
|
||
{
|
||
if (thing_scroll < num_things - (max - 2) - TOOLOFFSET)
|
||
{
|
||
thing_scroll = thing_scroll + 2;
|
||
do_draw = 1;
|
||
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (scrolling == 0)
|
||
{
|
||
memcpy(&scrolltimer_event,
|
||
&event,
|
||
sizeof(SDL_Event));
|
||
|
||
/* FIXME: Make delay value changable: */
|
||
|
||
scrolltimer =
|
||
SDL_AddTimer(REPEAT_SPEED,
|
||
scrolltimer_callback,
|
||
(void*) &scrolltimer_event);
|
||
|
||
scrolling = 1;
|
||
}
|
||
else
|
||
{
|
||
SDL_RemoveTimer(scrolltimer);
|
||
|
||
scrolltimer =
|
||
SDL_AddTimer(REPEAT_SPEED / 3,
|
||
scrolltimer_callback,
|
||
(void*) &scrolltimer_event);
|
||
}
|
||
|
||
if (thing_scroll == 0)
|
||
{
|
||
do_setcursor(cursor_arrow);
|
||
|
||
if (scrolling == 1)
|
||
{
|
||
SDL_RemoveTimer(scrolltimer);
|
||
scrolling = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
off_y = 24;
|
||
}
|
||
else
|
||
{
|
||
off_y = 0;
|
||
}
|
||
|
||
|
||
|
||
if (event.button.y > 40 + off_y &&
|
||
event.button.y <
|
||
(48 * ((max / 2) + TOOLOFFSET / 2)) + 40 - off_y)
|
||
{
|
||
which = ((event.button.y - 40 - off_y) / 48) * 2 +
|
||
((event.button.x - (WINDOW_WIDTH - 96)) / 48) +
|
||
thing_scroll;
|
||
|
||
if (which < num_things)
|
||
{
|
||
#ifndef NOSOUND
|
||
if (cur_tool != TOOL_STAMP ||
|
||
snd_stamps[which] == NULL)
|
||
{
|
||
playsound(1, SND_BLEEP, 0);
|
||
}
|
||
#endif
|
||
|
||
old_thing = cur_thing;
|
||
cur_thing = which;
|
||
do_draw = 1;
|
||
}
|
||
else
|
||
{
|
||
cur_thing = num_things - 1;
|
||
do_draw = 1;
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_STAMP &&
|
||
event.button.y >= (48 * ((max / 2) + TOOLOFFSET / 2)) + 40 &&
|
||
event.button.y < (48 * ((max / 2) + TOOLOFFSET / 2)) + 40 + 96 &&
|
||
!disable_stamp_controls)
|
||
{
|
||
/* Stamp controls! */
|
||
|
||
if (event.button.y >= (48 * ((max / 2) + TOOLOFFSET / 2)) + 40 &&
|
||
event.button.y < (48 * ((max / 2) + TOOLOFFSET / 2)) + 40 + 48)
|
||
{
|
||
/* One of the top buttons: */
|
||
|
||
if (event.button.x >= WINDOW_WIDTH - 96 &&
|
||
event.button.x <= WINDOW_WIDTH - 48)
|
||
{
|
||
/* Top left button: Mirror: */
|
||
|
||
if (inf_stamps[cur_stamp]->mirrorable)
|
||
{
|
||
state_stamps[cur_stamp]->mirrored =
|
||
!state_stamps[cur_stamp]->mirrored;
|
||
|
||
playsound(0, SND_MIRROR, 0);
|
||
draw_stamps();
|
||
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Top right button: Flip: */
|
||
|
||
if (inf_stamps[cur_stamp]->flipable)
|
||
{
|
||
state_stamps[cur_stamp]->flipped =
|
||
!state_stamps[cur_stamp]->flipped;
|
||
|
||
playsound(0, SND_FLIP, 0);
|
||
draw_stamps();
|
||
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* One of the bottom buttons: */
|
||
|
||
if (event.button.x >= WINDOW_WIDTH - 96 &&
|
||
event.button.x <= WINDOW_WIDTH - 48)
|
||
{
|
||
|
||
/* Bottom left button: Shrink: */
|
||
|
||
if (state_stamps[cur_stamp]->size > MIN_STAMP_SIZE)
|
||
{
|
||
state_stamps[cur_stamp]->size--;
|
||
|
||
playsound(0, SND_SHRINK, 0);
|
||
draw_stamps();
|
||
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Bottom right button: Grow: */
|
||
|
||
if (state_stamps[cur_stamp]->size < MAX_STAMP_SIZE)
|
||
{
|
||
state_stamps[cur_stamp]->size++;
|
||
|
||
playsound(0, SND_GROW, 0);
|
||
draw_stamps();
|
||
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Assign the change(s), if any / redraw, if needed: */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
{
|
||
cur_brush = cur_thing;
|
||
brush_scroll = thing_scroll;
|
||
render_brush();
|
||
|
||
if (do_draw)
|
||
draw_brushes();
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
cur_eraser = cur_thing;
|
||
|
||
if (do_draw)
|
||
draw_erasers();
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
cur_font = cur_thing;
|
||
font_scroll = thing_scroll;
|
||
|
||
if (do_draw)
|
||
draw_fonts();
|
||
|
||
do_render_cur_text(0);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
#ifndef NOSOUND
|
||
if (cur_stamp != cur_thing ||
|
||
stamp_scroll == thing_scroll)
|
||
{
|
||
/* Only play when picking a different stamp, not
|
||
simply scrolling */
|
||
|
||
if (snd_stamps[cur_thing] != NULL)
|
||
Mix_PlayChannel(2, snd_stamps[cur_thing], 0);
|
||
}
|
||
#endif
|
||
|
||
|
||
cur_stamp = cur_thing;
|
||
stamp_scroll = thing_scroll;
|
||
|
||
update_stamp_xor();
|
||
|
||
if (do_draw)
|
||
draw_stamps();
|
||
|
||
if (txt_stamps[cur_stamp] != NULL)
|
||
{
|
||
#ifdef DEBUG
|
||
printf("txt_stamps[cur_stamp] = %s\n",
|
||
txt_stamps[cur_stamp]);
|
||
#endif
|
||
|
||
draw_tux_text(TUX_GREAT,
|
||
txt_stamps[cur_stamp], 1);
|
||
}
|
||
else
|
||
draw_tux_text(TUX_GREAT, "", 0);
|
||
|
||
|
||
/* Enable or disable color selector: */
|
||
|
||
if ((stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp)) !=
|
||
(stamp_colorable(old_thing) ||
|
||
stamp_tintable(old_thing)))
|
||
{
|
||
draw_colors(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp));
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
cur_shape = cur_thing;
|
||
|
||
draw_tux_text(TUX_GREAT, shape_tips[cur_shape], 1);
|
||
|
||
if (do_draw)
|
||
draw_shapes();
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
if (cur_thing != cur_magic)
|
||
{
|
||
if (cur_thing == MAGIC_FILL)
|
||
draw_colors(1);
|
||
else
|
||
draw_colors(0);
|
||
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
}
|
||
|
||
cur_magic = cur_thing;
|
||
|
||
draw_tux_text(TUX_GREAT, magic_tips[cur_magic], 1);
|
||
|
||
if (do_draw)
|
||
draw_magic();
|
||
}
|
||
|
||
/* Update the screen: */
|
||
|
||
if (do_draw)
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
}
|
||
else if (event.button.x > 96 &&
|
||
/* FIXME: Need exact number here! */
|
||
event.button.x < WINDOW_WIDTH &&
|
||
event.button.y > (48 * (7 + TOOLOFFSET / 2)) + 40 &&
|
||
event.button.y <= (48 * (7 + TOOLOFFSET / 2)) + 48 + 48 &&
|
||
(cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES ||
|
||
cur_tool == TOOL_SHAPES || cur_tool == TOOL_TEXT ||
|
||
(cur_tool == TOOL_MAGIC && cur_magic == MAGIC_FILL) ||
|
||
(cur_tool == TOOL_STAMP &&
|
||
(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp)))))
|
||
{
|
||
/* Color! */
|
||
|
||
which = ((event.button.x - 96) /
|
||
((WINDOW_WIDTH - 96) / NUM_COLORS));
|
||
|
||
if (which < NUM_COLORS)
|
||
{
|
||
cur_color = which;
|
||
playsound(1, SND_BUBBLE, 1);
|
||
draw_colors(1);
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
render_brush();
|
||
draw_tux_text(TUX_KISS, color_names[cur_color], 1);
|
||
|
||
if (cur_tool == TOOL_TEXT)
|
||
do_render_cur_text(0);
|
||
}
|
||
}
|
||
else if (event.button.x > 96 &&
|
||
event.button.x < WINDOW_WIDTH - 96 &&
|
||
/* event.button.y >= 0 && */
|
||
event.button.y < (48 * 7) + 40 + HEIGHTOFFSET)
|
||
{
|
||
/* Draw something! */
|
||
|
||
old_x = event.button.x - 96;
|
||
old_y = event.button.y;
|
||
|
||
if (been_saved)
|
||
{
|
||
been_saved = 0;
|
||
|
||
if (!disable_save)
|
||
tool_avail[TOOL_SAVE] = 1;
|
||
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
|
||
if (cur_tool == TOOL_BRUSH)
|
||
{
|
||
/* Start painting! */
|
||
|
||
rec_undo_buffer();
|
||
|
||
/* (Arbitrarily large, so we draw once now) */
|
||
brush_counter = 999;
|
||
|
||
brush_draw(old_x, old_y, old_x, old_y, 1);
|
||
playsound(0, SND_PAINT1 + (img_cur_brush->w) / 12, 1);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
/* Draw a stamp! */
|
||
|
||
rec_undo_buffer();
|
||
|
||
stamp_draw(old_x, old_y);
|
||
#ifdef LOW_QUALITY_STAMP_OUTLINE
|
||
// the +1 is for rounding, probably needed only one side though
|
||
rect_xor(old_x - (CUR_STAMP_W+1)/2,
|
||
old_y - (CUR_STAMP_H+1)/2,
|
||
old_x + (CUR_STAMP_W+1)/2,
|
||
old_y + (CUR_STAMP_H+1)/2);
|
||
#else
|
||
stamp_xor(old_x, old_y);
|
||
#endif
|
||
playsound(1, SND_STAMP, 1);
|
||
|
||
draw_tux_text(TUX_GREAT, great_str(), 1);
|
||
|
||
/* FIXME: Make delay configurable: */
|
||
|
||
control_drawtext_timer(1000, txt_stamps[cur_stamp]);
|
||
}
|
||
else if (cur_tool == TOOL_LINES)
|
||
{
|
||
/* Start a line! */
|
||
|
||
rec_undo_buffer();
|
||
|
||
line_start_x = old_x;
|
||
line_start_y = old_y;
|
||
|
||
/* (Arbitrarily large, so we draw once now) */
|
||
brush_counter = 999;
|
||
|
||
brush_draw(old_x, old_y, old_x, old_y, 1);
|
||
|
||
playsound(1, SND_LINE_START, 1);
|
||
draw_tux_text(TUX_BORED, TIP_LINE_START, 1);
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
if (shape_tool_mode == SHAPE_TOOL_MODE_DONE)
|
||
{
|
||
/* Start drawing a shape! */
|
||
|
||
rec_undo_buffer();
|
||
|
||
shape_ctr_x = old_x;
|
||
shape_ctr_y = old_y;
|
||
|
||
shape_tool_mode = SHAPE_TOOL_MODE_STRETCH;
|
||
|
||
playsound(1, SND_LINE_START, 1);
|
||
draw_tux_text(TUX_BORED, TIP_SHAPE_START, 1);
|
||
}
|
||
else if (shape_tool_mode == SHAPE_TOOL_MODE_ROTATE)
|
||
{
|
||
/* Draw the shape with the brush! */
|
||
|
||
/* (Arbitrarily large...) */
|
||
brush_counter = 999;
|
||
|
||
playsound(1, SND_LINE_END, 1);
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y,
|
||
rotation(shape_ctr_x, shape_ctr_y,
|
||
event.button.x - 96,
|
||
event.button.y),
|
||
1);
|
||
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
draw_tux_text(TUX_GREAT, tool_tips[TOOL_SHAPES], 1);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
/* Start doing magic! */
|
||
|
||
tmp_int = cur_undo;
|
||
rec_undo_buffer();
|
||
|
||
|
||
/* Mirror or flip, make a note so we record it for
|
||
the starters, too! */
|
||
|
||
if (cur_magic == MAGIC_MIRROR)
|
||
undo_starters[tmp_int] = UNDO_STARTER_MIRRORED;
|
||
else if (cur_magic == MAGIC_FLIP)
|
||
undo_starters[tmp_int] = UNDO_STARTER_FLIPPED;
|
||
|
||
|
||
/* (Arbitrarily large, so we draw once now) */
|
||
brush_counter = 999;
|
||
|
||
if (cur_magic != MAGIC_FILL)
|
||
{
|
||
magic_draw(old_x, old_y, old_x, old_y, button_down);
|
||
}
|
||
else
|
||
{
|
||
do_flood_fill(old_x, old_y,
|
||
SDL_MapRGB(canvas->format,
|
||
color_hexes[cur_color][0],
|
||
color_hexes[cur_color][1],
|
||
color_hexes[cur_color][2]),
|
||
getpixel(canvas, old_x, old_y));
|
||
|
||
draw_tux_text(TUX_GREAT, magic_tips[MAGIC_FILL], 1);
|
||
}
|
||
|
||
if (cur_magic == MAGIC_FLIP ||
|
||
cur_magic == MAGIC_MIRROR ||
|
||
cur_magic == MAGIC_FILL)
|
||
{
|
||
update_canvas(0, 0, canvas->w, canvas->h);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
/* Erase! */
|
||
|
||
rec_undo_buffer();
|
||
|
||
do_eraser(old_x, old_y);
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
/* Text Tool! */
|
||
|
||
if (cursor_x != -1 && cursor_y != -1)
|
||
{
|
||
/*
|
||
if (texttool_len > 0)
|
||
{
|
||
rec_undo_buffer();
|
||
do_render_cur_text(1);
|
||
texttool_len = 0;
|
||
}
|
||
*/
|
||
}
|
||
|
||
cursor_x = old_x;
|
||
cursor_y = old_y;
|
||
cursor_left = old_x;
|
||
|
||
do_render_cur_text(0);
|
||
}
|
||
|
||
button_down = 1;
|
||
|
||
/* Make sure these commands are available now: */
|
||
|
||
if (tool_avail[TOOL_NEW] == 0)
|
||
{
|
||
tool_avail[TOOL_NEW] = 1;
|
||
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen,
|
||
0, 0,
|
||
96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEBUTTONDOWN &&
|
||
wheely &&
|
||
event.button.button >= 4 &&
|
||
event.button.button <= 5)
|
||
{
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_STAMP ||
|
||
cur_tool == TOOL_SHAPES || cur_tool == TOOL_LINES ||
|
||
cur_tool == TOOL_MAGIC || cur_tool == TOOL_TEXT)
|
||
{
|
||
/* Note set of things we're dealing with */
|
||
/* (stamps, brushes, etc.) */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
{
|
||
num_things = num_brushes;
|
||
thing_scroll = brush_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
num_things = num_stamps;
|
||
thing_scroll = stamp_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
num_things = num_fonts;
|
||
thing_scroll = font_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
num_things = NUM_SHAPES;
|
||
thing_scroll = 0;
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
num_things = NUM_MAGICS;
|
||
thing_scroll = 0;
|
||
}
|
||
|
||
do_draw = 0;
|
||
|
||
|
||
|
||
/* Deal with scroll wheels: */
|
||
|
||
max = 14;
|
||
|
||
if (cur_tool == TOOL_STAMP && !disable_stamp_controls)
|
||
max = 10;
|
||
|
||
if (num_things > max + TOOLOFFSET)
|
||
{
|
||
if (event.button.button == 4)
|
||
{
|
||
/* Wheelmouse - UP "button" */
|
||
|
||
if (thing_scroll > 0)
|
||
{
|
||
thing_scroll = thing_scroll - 2;
|
||
do_draw = 1;
|
||
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (thing_scroll == 0)
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
else if (event.button.button == 5)
|
||
{
|
||
/* Wheelmouse - DOWN "button" */
|
||
|
||
if (thing_scroll < num_things - (max - 2))
|
||
{
|
||
thing_scroll = thing_scroll + 2;
|
||
do_draw = 1;
|
||
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (thing_scroll == 0)
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
|
||
off_y = 24;
|
||
}
|
||
else
|
||
{
|
||
off_y = 0;
|
||
}
|
||
}
|
||
|
||
|
||
/* Assign the change(s), if any / redraw, if needed: */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
{
|
||
cur_brush = cur_thing;
|
||
brush_scroll = thing_scroll;
|
||
render_brush();
|
||
|
||
if (do_draw)
|
||
draw_brushes();
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
cur_eraser = cur_thing;
|
||
|
||
if (do_draw)
|
||
draw_erasers();
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
cur_font = cur_thing;
|
||
font_scroll = thing_scroll;
|
||
|
||
if (do_draw)
|
||
draw_fonts();
|
||
|
||
do_render_cur_text(0);
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
#ifndef NOSOUND
|
||
if (cur_stamp != cur_thing)
|
||
{
|
||
/* Only play when picking a different stamp, not
|
||
simply scrolling */
|
||
|
||
if (snd_stamps[cur_thing] != NULL)
|
||
Mix_PlayChannel(2, snd_stamps[cur_thing], 0);
|
||
}
|
||
#endif
|
||
|
||
cur_stamp = cur_thing;
|
||
stamp_scroll = thing_scroll;
|
||
|
||
update_stamp_xor();
|
||
|
||
if (do_draw)
|
||
draw_stamps();
|
||
|
||
if (txt_stamps[cur_stamp] != NULL)
|
||
{
|
||
draw_tux_text(TUX_GREAT, txt_stamps[cur_stamp], 1);
|
||
}
|
||
else
|
||
draw_tux_text(TUX_GREAT, "", 0);
|
||
|
||
|
||
/* Enable or disable color selector: */
|
||
|
||
if ((stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp)) !=
|
||
(stamp_colorable(old_thing) ||
|
||
stamp_tintable(old_thing)))
|
||
{
|
||
draw_colors(stamp_colorable(cur_stamp) ||
|
||
stamp_tintable(cur_stamp));
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
cur_shape = cur_thing;
|
||
|
||
draw_tux_text(TUX_GREAT, shape_tips[cur_shape], 1);
|
||
|
||
if (do_draw)
|
||
draw_shapes();
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
if (cur_thing != cur_magic)
|
||
{
|
||
if (cur_thing == MAGIC_FILL)
|
||
draw_colors(1);
|
||
else
|
||
draw_colors(0);
|
||
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH, 48);
|
||
}
|
||
|
||
cur_magic = cur_thing;
|
||
|
||
draw_tux_text(TUX_GREAT, magic_tips[cur_magic], 1);
|
||
|
||
if (do_draw)
|
||
draw_magic();
|
||
}
|
||
|
||
|
||
/* Update the screen: */
|
||
|
||
if (do_draw)
|
||
SDL_UpdateRect(screen,
|
||
WINDOW_WIDTH - 96, 0,
|
||
96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
else if (event.type == SDL_USEREVENT)
|
||
{
|
||
if (event.user.code == USEREVENT_TEXT_UPDATE)
|
||
{
|
||
/* Time to replace "Great!" with old tip text: */
|
||
|
||
if (event.user.data1 != NULL)
|
||
{
|
||
if (((unsigned char *) event.user.data1)[0] == '=')
|
||
{
|
||
draw_tux_text(TUX_GREAT,
|
||
(char *) event.user.data1 + 1, 1);
|
||
}
|
||
else
|
||
{
|
||
draw_tux_text(TUX_GREAT,
|
||
(char *) event.user.data1, 0);
|
||
}
|
||
}
|
||
else
|
||
draw_tux_text(TUX_GREAT, "", 1);
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEBUTTONUP)
|
||
{
|
||
if (scrolling)
|
||
{
|
||
SDL_RemoveTimer(scrolltimer);
|
||
scrolling = 0;
|
||
}
|
||
|
||
if (button_down)
|
||
{
|
||
if (cur_tool == TOOL_LINES)
|
||
{
|
||
/* (Arbitrarily large, so we draw once now) */
|
||
brush_counter = 999;
|
||
|
||
brush_draw(line_start_x, line_start_y,
|
||
event.button.x - 96, event.button.y, 1);
|
||
brush_draw(event.button.x - 96, event.button.y,
|
||
event.button.x - 96, event.button.y, 1);
|
||
|
||
playsound(1, SND_LINE_END, 1);
|
||
draw_tux_text(TUX_GREAT, tool_tips[TOOL_LINES], 1);
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
if (shape_tool_mode == SHAPE_TOOL_MODE_STRETCH)
|
||
{
|
||
/* Now we can rotate the shape... */
|
||
|
||
shape_outer_x = event.button.x - 96;
|
||
shape_outer_y = event.button.y;
|
||
|
||
if (!simple_shapes && !shape_no_rotate[cur_shape])
|
||
{
|
||
shape_tool_mode = SHAPE_TOOL_MODE_ROTATE;
|
||
|
||
SDL_WarpMouse(shape_outer_x + 96, shape_ctr_y);
|
||
do_setcursor(cursor_rotate);
|
||
|
||
|
||
/* Erase stretchy XOR: */
|
||
|
||
do_shape(shape_ctr_x, shape_ctr_y, old_x, old_y,
|
||
0, 0);
|
||
|
||
/* Make an initial rotation XOR to be erased: */
|
||
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y,
|
||
rotation(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y),
|
||
0);
|
||
|
||
playsound(1, SND_LINE_START, 1);
|
||
draw_tux_text(TUX_BORED, TIP_SHAPE_NEXT, 1);
|
||
|
||
|
||
/* FIXME: Do something less intensive! */
|
||
|
||
SDL_Flip(screen);
|
||
}
|
||
else
|
||
{
|
||
brush_counter = 999; /* arbitrarily large... */
|
||
|
||
|
||
playsound(1, SND_LINE_END, 1);
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y,
|
||
0, 1);
|
||
|
||
SDL_Flip(screen);
|
||
|
||
shape_tool_mode = SHAPE_TOOL_MODE_DONE;
|
||
draw_tux_text(TUX_GREAT,
|
||
tool_tips[TOOL_SHAPES], 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
button_down = 0;
|
||
}
|
||
else if (event.type == SDL_MOUSEMOTION && !ignoring_motion)
|
||
{
|
||
new_x = event.button.x - 96;
|
||
new_y = event.button.y;
|
||
|
||
|
||
/* FIXME: Is doing this every event too intensive? */
|
||
/* Should I check current cursor first? */
|
||
|
||
if (event.button.x < 96 && event.button.y < (48 * 7) + 40 &&
|
||
event.button.y > 40)
|
||
{
|
||
/* Tools: */
|
||
|
||
if (tool_avail[(event.button.x / 48) +
|
||
((event.button.y - 40) / 48) * 2])
|
||
{
|
||
do_setcursor(cursor_hand);
|
||
}
|
||
else
|
||
{
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
else if (event.button.x > 96 &&
|
||
event.button.y >= (48 * 7) + 40 + HEIGHTOFFSET &&
|
||
event.button.y <= (48 * 7) + 40 + 48 + HEIGHTOFFSET)
|
||
{
|
||
/* Color picker: */
|
||
|
||
if (colors_are_selectable)
|
||
do_setcursor(cursor_hand);
|
||
else
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
else if (event.button.x >= WINDOW_WIDTH - 96 &&
|
||
event.button.y > 40 &&
|
||
event.button.y <= (48 * (7 + TOOLOFFSET / 2)) + 40)
|
||
{
|
||
/* Selector: */
|
||
|
||
/* Note set of things we're dealing with */
|
||
/* (stamps, brushes, etc.) */
|
||
|
||
if (cur_tool == TOOL_BRUSH || cur_tool == TOOL_LINES)
|
||
{
|
||
num_things = num_brushes;
|
||
thing_scroll = brush_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_STAMP)
|
||
{
|
||
num_things = num_stamps;
|
||
thing_scroll = stamp_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
{
|
||
num_things = num_fonts;
|
||
thing_scroll = font_scroll;
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
num_things = NUM_SHAPES;
|
||
thing_scroll = 0;
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
num_things = NUM_MAGICS;
|
||
thing_scroll = 0;
|
||
}
|
||
|
||
|
||
max = 14;
|
||
if (cur_tool == TOOL_STAMP && !disable_stamp_controls)
|
||
max = 10;
|
||
|
||
|
||
if (num_things > max + TOOLOFFSET)
|
||
{
|
||
/* Are there scroll buttons? */
|
||
|
||
if (event.button.y < 40 + 24)
|
||
{
|
||
/* Up button; is it available? */
|
||
|
||
if (thing_scroll > 0)
|
||
do_setcursor(cursor_up);
|
||
else
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
else if (event.button.y > (48 * ((max - 2) / 2 + TOOLOFFSET / 2)) + 40 + 24 &&
|
||
event.button.y <= (48 * ((max - 2) / 2 + TOOLOFFSET / 2)) + 40 + 24 + 24)
|
||
{
|
||
/* Down button; is it available? */
|
||
|
||
if (thing_scroll < num_things - (max - 2))
|
||
do_setcursor(cursor_down);
|
||
else
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
else
|
||
{
|
||
/* One of the selectors: */
|
||
|
||
which = ((event.button.y - 40 - 24) / 48) * 2 +
|
||
(event.button.x - (WINDOW_WIDTH - 96)) / 48;
|
||
|
||
if (which < num_things)
|
||
do_setcursor(cursor_hand);
|
||
else
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* No scroll buttons - must be a selector: */
|
||
|
||
which = ((event.button.y - 40) / 48) * 2 +
|
||
(event.button.x - (WINDOW_WIDTH - 96)) / 48;
|
||
|
||
if (which < num_things)
|
||
do_setcursor(cursor_hand);
|
||
else
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
else if (event.button.x > 96 &&
|
||
event.button.x < WINDOW_WIDTH - 96 &&
|
||
event.button.y < (48 * 7) + 40 + HEIGHTOFFSET)
|
||
{
|
||
/* Canvas: */
|
||
|
||
if (cur_tool == TOOL_BRUSH)
|
||
do_setcursor(cursor_brush);
|
||
else if (cur_tool == TOOL_STAMP)
|
||
do_setcursor(cursor_tiny);
|
||
else if (cur_tool == TOOL_LINES)
|
||
do_setcursor(cursor_crosshair);
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
if (shape_tool_mode != SHAPE_TOOL_MODE_ROTATE)
|
||
do_setcursor(cursor_crosshair);
|
||
else
|
||
do_setcursor(cursor_rotate);
|
||
}
|
||
else if (cur_tool == TOOL_TEXT)
|
||
do_setcursor(cursor_insertion);
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
do_setcursor(cursor_wand);
|
||
else if (cur_tool == TOOL_ERASER)
|
||
do_setcursor(cursor_tiny);
|
||
}
|
||
else
|
||
{
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
|
||
|
||
if (button_down)
|
||
{
|
||
if (cur_tool == TOOL_BRUSH)
|
||
{
|
||
/* Pushing button and moving: Draw with the brush: */
|
||
|
||
brush_draw(old_x, old_y, new_x, new_y, 1);
|
||
|
||
playsound(0, SND_PAINT1 + (img_cur_brush->w) / 12, 0);
|
||
}
|
||
else if (cur_tool == TOOL_LINES)
|
||
{
|
||
/* Still pushing button, while moving:
|
||
Draw XOR where line will go: */
|
||
|
||
line_xor(line_start_x, line_start_y, old_x, old_y);
|
||
|
||
line_xor(line_start_x, line_start_y, new_x, new_y);
|
||
|
||
update_screen(line_start_x + 96, line_start_y,
|
||
old_x + 96, old_y);
|
||
update_screen(line_start_x + 96, line_start_y,
|
||
new_x + 96, new_y);
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES)
|
||
{
|
||
/* Still pushing button, while moving:
|
||
Draw XOR where shape will go: */
|
||
|
||
if (shape_tool_mode == SHAPE_TOOL_MODE_STRETCH)
|
||
{
|
||
do_shape(shape_ctr_x, shape_ctr_y, old_x, old_y,
|
||
0, 0);
|
||
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
new_x, new_y,
|
||
0, 0);
|
||
|
||
|
||
/* FIXME: Fix update shape function! */
|
||
|
||
/* update_shape(shape_ctr_x, old_x, new_x,
|
||
shape_ctr_y, old_y, new_y,
|
||
shape_locked[cur_shape]); */
|
||
|
||
SDL_Flip(screen);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_MAGIC)
|
||
{
|
||
/* Pushing button and moving: Do the magic: */
|
||
|
||
if (cur_magic != MAGIC_FLIP &&
|
||
cur_magic != MAGIC_MIRROR &&
|
||
cur_magic != MAGIC_FILL)
|
||
{
|
||
magic_draw(old_x, old_y, new_x, new_y, button_down);
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
/* Still pushing, and moving - Erase! */
|
||
|
||
do_eraser(new_x, new_y);
|
||
}
|
||
}
|
||
|
||
|
||
if (cur_tool == TOOL_STAMP ||
|
||
(cur_tool == TOOL_ERASER && !button_down))
|
||
{
|
||
/* Moving: Draw XOR where stamp/eraser will apply: */
|
||
|
||
if (cur_tool == TOOL_STAMP)
|
||
{
|
||
w = img_stamps[cur_stamp]->w;
|
||
h = img_stamps[cur_stamp]->h;
|
||
}
|
||
else if (cur_tool == TOOL_ERASER)
|
||
{
|
||
w = (ERASER_MIN +
|
||
((NUM_ERASERS - cur_eraser - 1) *
|
||
((ERASER_MAX - ERASER_MIN) / (NUM_ERASERS - 1))));
|
||
|
||
h = w;
|
||
}
|
||
|
||
if (old_x >= 0 && old_x < WINDOW_WIDTH - 96 - 96 &&
|
||
old_y >= 0 && old_y < (48 * 7) + 40 + HEIGHTOFFSET)
|
||
{
|
||
if (cur_tool == TOOL_STAMP)
|
||
{
|
||
#ifndef LOW_QUALITY_STAMP_OUTLINE
|
||
stamp_xor(old_x, old_y);
|
||
#else
|
||
rect_xor(old_x - (CUR_STAMP_W+1)/2,
|
||
old_y - (CUR_STAMP_H+1)/2,
|
||
old_x + (CUR_STAMP_W+1)/2,
|
||
old_y + (CUR_STAMP_H+1)/2);
|
||
#endif
|
||
|
||
update_screen(old_x - (CUR_STAMP_W+1)/2 + 96,
|
||
old_y - (CUR_STAMP_H+1)/2,
|
||
old_x + (CUR_STAMP_W+1)/2 + 96,
|
||
old_y + (CUR_STAMP_H+1)/2);
|
||
}
|
||
else
|
||
{
|
||
rect_xor(old_x - w / 2, old_y - h / 2,
|
||
old_x + w / 2, old_y + h / 2);
|
||
|
||
update_screen(old_x - w / 2 + 96, old_y - h / 2,
|
||
old_x + w / 2 + 96, old_y + h / 2);
|
||
}
|
||
}
|
||
|
||
if (new_x >= 0 && new_x < WINDOW_WIDTH - 96 - 96 &&
|
||
new_y >= 0 && new_y < (48 * 7) + 40 + HEIGHTOFFSET)
|
||
{
|
||
if (cur_tool == TOOL_STAMP)
|
||
{
|
||
#ifndef LOW_QUALITY_STAMP_OUTLINE
|
||
stamp_xor(new_x, new_y);
|
||
#else
|
||
rect_xor(old_x - (CUR_STAMP_W+1)/2,
|
||
old_y - (CUR_STAMP_H+1)/2,
|
||
old_x + (CUR_STAMP_W+1)/2,
|
||
old_y + (CUR_STAMP_H+1)/2);
|
||
#endif
|
||
|
||
update_screen(old_x - (CUR_STAMP_W+1)/2 + 96,
|
||
old_y - (CUR_STAMP_H+1)/2,
|
||
old_x + (CUR_STAMP_W+1)/2 + 96,
|
||
old_y + (CUR_STAMP_H+1)/2);
|
||
}
|
||
else
|
||
{
|
||
rect_xor(new_x - w / 2, new_y - h / 2,
|
||
new_x + w / 2, new_y + h / 2);
|
||
|
||
update_screen(new_x - w / 2 + 96, new_y - h / 2,
|
||
new_x + w / 2 + 96, new_y + h / 2);
|
||
}
|
||
}
|
||
}
|
||
else if (cur_tool == TOOL_SHAPES &&
|
||
shape_tool_mode == SHAPE_TOOL_MODE_ROTATE)
|
||
{
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y,
|
||
rotation(shape_ctr_x, shape_ctr_y,
|
||
old_x, old_y), 0);
|
||
|
||
|
||
do_shape(shape_ctr_x, shape_ctr_y,
|
||
shape_outer_x, shape_outer_y,
|
||
rotation(shape_ctr_x, shape_ctr_y,
|
||
new_x, new_y), 0);
|
||
|
||
|
||
/* FIXME: Do something less intensive! */
|
||
|
||
SDL_Flip(screen);
|
||
}
|
||
|
||
old_x = new_x;
|
||
old_y = new_y;
|
||
}
|
||
}
|
||
|
||
|
||
SDL_Delay(10);
|
||
|
||
cur_cursor_blink = SDL_GetTicks();
|
||
|
||
|
||
if (cur_tool == TOOL_TEXT && cursor_x != -1 && cursor_y != -1 &&
|
||
cur_cursor_blink > last_cursor_blink + CURSOR_BLINK_SPEED)
|
||
{
|
||
last_cursor_blink = SDL_GetTicks();
|
||
|
||
line_xor(cursor_x + cursor_textwidth, cursor_y,
|
||
cursor_x + cursor_textwidth,
|
||
cursor_y + TTF_FontHeight(fonts[cur_font]));
|
||
|
||
update_screen(cursor_x + 96 + cursor_textwidth, cursor_y,
|
||
cursor_x + 96 + cursor_textwidth,
|
||
cursor_y + TTF_FontHeight(fonts[cur_font]));
|
||
}
|
||
}
|
||
while (!done);
|
||
}
|
||
|
||
|
||
/* Draw using the current brush: */
|
||
|
||
static void brush_draw(int x1, int y1, int x2, int y2, int update)
|
||
{
|
||
int dx, dy, y;
|
||
int orig_x1, orig_y1, orig_x2, orig_y2, tmp;
|
||
float m, b;
|
||
|
||
orig_x1 = x1;
|
||
orig_y1 = y1;
|
||
|
||
orig_x2 = x2;
|
||
orig_y2 = y2;
|
||
|
||
|
||
x1 = x1 - (img_brushes[cur_brush]->w / 2);
|
||
y1 = y1 - (img_brushes[cur_brush]->h / 2);
|
||
|
||
x2 = x2 - (img_brushes[cur_brush]->w / 2);
|
||
y2 = y2 - (img_brushes[cur_brush]->h / 2);
|
||
|
||
|
||
dx = x2 - x1;
|
||
dy = y2 - y1;
|
||
|
||
if (dx != 0)
|
||
{
|
||
m = ((float) dy) / ((float) dx);
|
||
b = y1 - m * x1;
|
||
|
||
if (x2 >= x1)
|
||
dx = 1;
|
||
else
|
||
dx = -1;
|
||
|
||
|
||
while (x1 != x2)
|
||
{
|
||
y1 = m * x1 + b;
|
||
y2 = m * (x1 + dx) + b;
|
||
|
||
if (y1 > y2)
|
||
{
|
||
y = y1;
|
||
y1 = y2;
|
||
y2 = y;
|
||
}
|
||
|
||
for (y = y1; y <= y2; y++)
|
||
blit_brush(x1, y);
|
||
|
||
x1 = x1 + dx;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (y1 > y2)
|
||
{
|
||
y = y1;
|
||
y1 = y2;
|
||
y2 = y;
|
||
}
|
||
|
||
for (y = y1; y <= y2; y++)
|
||
blit_brush(x1, y);
|
||
}
|
||
|
||
if (orig_x1 > orig_x2)
|
||
{
|
||
tmp = orig_x1;
|
||
orig_x1 = orig_x2;
|
||
orig_x2 = tmp;
|
||
}
|
||
|
||
if (orig_y1 > orig_y2)
|
||
{
|
||
tmp = orig_y1;
|
||
orig_y1 = orig_y2;
|
||
orig_y2 = tmp;
|
||
}
|
||
|
||
|
||
if (update)
|
||
{
|
||
update_canvas(orig_x1 - (img_brushes[cur_brush]->w / 2),
|
||
orig_y1 - (img_brushes[cur_brush]->h / 2),
|
||
orig_x2 + (img_brushes[cur_brush]->w / 2),
|
||
orig_y2 + (img_brushes[cur_brush]->h / 2));
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw the current brush in the current color: */
|
||
|
||
static void blit_brush(int x, int y)
|
||
{
|
||
SDL_Rect dest;
|
||
|
||
brush_counter++;
|
||
|
||
if (brush_counter >= (img_cur_brush->h / 4))
|
||
{
|
||
brush_counter = 0;
|
||
|
||
dest.x = x;
|
||
dest.y = y;
|
||
|
||
SDL_BlitSurface(img_cur_brush, NULL, canvas, &dest);
|
||
}
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
// stamp tinter
|
||
|
||
#define TINTER_ANYHUE 0 // like normal, but remaps all hues in the stamp
|
||
#define TINTER_NARROW 1 // like normal, but narrow hue angle
|
||
#define TINTER_NORMAL 2 // normal
|
||
#define TINTER_VECTOR 3 // map black->white to black->destination
|
||
|
||
// This goes from 8-bit sRGB (range 0 to 255) to linear (range 0 to 1).
|
||
// The math to produce a table entry:
|
||
// tmp = oldvalue / 255.0;
|
||
// result = (tmp<=0.03928) ? tmp/12.92 : pow((tmp+0.055)/1.055,2.4);
|
||
static const float sRGB_to_linear_table[256] = {
|
||
0.000000, 0.000304, 0.000607, 0.000911, 0.001214, 0.001518, 0.001821,
|
||
0.002125, 0.002428, 0.002732, 0.003035, 0.003347, 0.003677, 0.004025,
|
||
0.004391, 0.004777, 0.005182, 0.005605, 0.006049, 0.006512, 0.006995,
|
||
0.007499, 0.008023, 0.008568, 0.009134, 0.009721, 0.010330, 0.010960,
|
||
0.011612, 0.012286, 0.012983, 0.013702, 0.014444, 0.015209, 0.015996,
|
||
0.016807, 0.017642, 0.018500, 0.019382, 0.020289, 0.021219, 0.022174,
|
||
0.023153, 0.024158, 0.025187, 0.026241, 0.027321, 0.028426, 0.029557,
|
||
0.030713, 0.031896, 0.033105, 0.034340, 0.035601, 0.036889, 0.038204,
|
||
0.039546, 0.040915, 0.042311, 0.043735, 0.045186, 0.046665, 0.048172,
|
||
0.049707, 0.051269, 0.052861, 0.054480, 0.056128, 0.057805, 0.059511,
|
||
0.061246, 0.063010, 0.064803, 0.066626, 0.068478, 0.070360, 0.072272,
|
||
0.074214, 0.076185, 0.078187, 0.080220, 0.082283, 0.084376, 0.086500,
|
||
0.088656, 0.090842, 0.093059, 0.095307, 0.097587, 0.099899, 0.102242,
|
||
0.104616, 0.107023, 0.109462, 0.111932, 0.114435, 0.116971, 0.119538,
|
||
0.122139, 0.124772, 0.127438, 0.130136, 0.132868, 0.135633, 0.138432,
|
||
0.141263, 0.144128, 0.147027, 0.149960, 0.152926, 0.155926, 0.158961,
|
||
0.162029, 0.165132, 0.168269, 0.171441, 0.174647, 0.177888, 0.181164,
|
||
0.184475, 0.187821, 0.191202, 0.194618, 0.198069, 0.201556, 0.205079,
|
||
0.208637, 0.212231, 0.215861, 0.219526, 0.223228, 0.226966, 0.230740,
|
||
0.234551, 0.238398, 0.242281, 0.246201, 0.250158, 0.254152, 0.258183,
|
||
0.262251, 0.266356, 0.270498, 0.274677, 0.278894, 0.283149, 0.287441,
|
||
0.291771, 0.296138, 0.300544, 0.304987, 0.309469, 0.313989, 0.318547,
|
||
0.323143, 0.327778, 0.332452, 0.337164, 0.341914, 0.346704, 0.351533,
|
||
0.356400, 0.361307, 0.366253, 0.371238, 0.376262, 0.381326, 0.386429,
|
||
0.391572, 0.396755, 0.401978, 0.407240, 0.412543, 0.417885, 0.423268,
|
||
0.428690, 0.434154, 0.439657, 0.445201, 0.450786, 0.456411, 0.462077,
|
||
0.467784, 0.473531, 0.479320, 0.485150, 0.491021, 0.496933, 0.502886,
|
||
0.508881, 0.514918, 0.520996, 0.527115, 0.533276, 0.539479, 0.545724,
|
||
0.552011, 0.558340, 0.564712, 0.571125, 0.577580, 0.584078, 0.590619,
|
||
0.597202, 0.603827, 0.610496, 0.617207, 0.623960, 0.630757, 0.637597,
|
||
0.644480, 0.651406, 0.658375, 0.665387, 0.672443, 0.679542, 0.686685,
|
||
0.693872, 0.701102, 0.708376, 0.715694, 0.723055, 0.730461, 0.737910,
|
||
0.745404, 0.752942, 0.760525, 0.768151, 0.775822, 0.783538, 0.791298,
|
||
0.799103, 0.806952, 0.814847, 0.822786, 0.830770, 0.838799, 0.846873,
|
||
0.854993, 0.863157, 0.871367, 0.879622, 0.887923, 0.896269, 0.904661,
|
||
0.913099, 0.921582, 0.930111, 0.938686, 0.947307, 0.955973, 0.964686,
|
||
0.973445, 0.982251, 0.991102, 1.000000,
|
||
};
|
||
|
||
// this goes the other way; range checking will be required
|
||
static const unsigned char linear_to_sRGB_table[4096] =
|
||
"\x00\x01\x02\x03\x03\x04\x05\x06\x07\x08\x08\x09\x0a\x0b\x0b\x0c\x0d\x0d"
|
||
"\x0e\x0f\x10\x10\x11\x11\x12\x12\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17"
|
||
"\x18\x18\x18\x19\x19\x1a\x1a\x1a\x1b\x1b\x1c\x1c\x1c\x1d\x1d\x1d\x1e\x1e"
|
||
"\x1e\x1f\x1f\x1f\x20\x20\x20\x21\x21\x21\x22\x22\x22\x23\x23\x23\x23\x24"
|
||
"\x24\x24\x25\x25\x25\x25\x26\x26\x26\x26\x27\x27\x27\x28\x28\x28\x28\x29"
|
||
"\x29\x29\x29\x2a\x2a\x2a\x2a\x2b\x2b\x2b\x2b\x2c\x2c\x2c\x2c\x2c\x2d\x2d"
|
||
"\x2d\x2d\x2e\x2e\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x30\x30\x30\x30\x30\x31\x31"
|
||
"\x31\x31\x31\x32\x32\x32\x32\x33\x33\x33\x33\x33\x34\x34\x34\x34\x34\x35"
|
||
"\x35\x35\x35\x35\x35\x36\x36\x36\x36\x36\x37\x37\x37\x37\x37\x38\x38\x38"
|
||
"\x38\x38\x38\x39\x39\x39\x39\x39\x39\x3a\x3a\x3a\x3a\x3a\x3a\x3b\x3b\x3b"
|
||
"\x3b\x3b\x3c\x3c\x3c\x3c\x3c\x3c\x3d\x3d\x3d\x3d\x3d\x3d\x3d\x3e\x3e\x3e"
|
||
"\x3e\x3e\x3e\x3f\x3f\x3f\x3f\x3f\x3f\x40\x40\x40\x40\x40\x40\x41\x41\x41"
|
||
"\x41\x41\x41\x41\x42\x42\x42\x42\x42\x42\x42\x43\x43\x43\x43\x43\x43\x44"
|
||
"\x44\x44\x44\x44\x44\x44\x45\x45\x45\x45\x45\x45\x45\x46\x46\x46\x46\x46"
|
||
"\x46\x46\x46\x47\x47\x47\x47\x47\x47\x47\x48\x48\x48\x48\x48\x48\x48\x48"
|
||
"\x49\x49\x49\x49\x49\x49\x49\x4a\x4a\x4a\x4a\x4a\x4a\x4a\x4a\x4b\x4b\x4b"
|
||
"\x4b\x4b\x4b\x4b\x4c\x4c\x4c\x4c\x4c\x4c\x4c\x4c\x4d\x4d\x4d\x4d\x4d\x4d"
|
||
"\x4d\x4d\x4e\x4e\x4e\x4e\x4e\x4e\x4e\x4e\x4f\x4f\x4f\x4f\x4f\x4f\x4f\x4f"
|
||
"\x50\x50\x50\x50\x50\x50\x50\x50\x50\x51\x51\x51\x51\x51\x51\x51\x51\x51"
|
||
"\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x53\x53\x53\x53\x53\x54"
|
||
"\x54\x54\x54\x54\x54\x54\x54\x54\x55\x55\x55\x55\x55\x55\x55\x55\x55\x56"
|
||
"\x56\x56\x56\x56\x56\x56\x56\x56\x57\x57\x57\x57\x57\x57\x57\x57\x57\x58"
|
||
"\x58\x58\x58\x58\x58\x58\x58\x58\x58\x59\x59\x59\x59\x59\x59\x59\x59\x59"
|
||
"\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b"
|
||
"\x5b\x5b\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x5d\x5d\x5d\x5d\x5d\x5d"
|
||
"\x5d\x5d\x5d\x5e\x5e\x5e\x5e\x5e\x5e\x5e\x5e\x5e\x5e\x5e\x5f\x5f\x5f\x5f"
|
||
"\x5f\x5f\x5f\x5f\x5f\x5f\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x60\x61"
|
||
"\x61\x61\x61\x61\x61\x61\x61\x61\x61\x62\x62\x62\x62\x62\x62\x62\x62\x62"
|
||
"\x62\x62\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x64\x64\x64\x64\x64"
|
||
"\x64\x64\x64\x64\x64\x64\x65\x65\x65\x65\x65\x65\x65\x65\x65\x65\x65\x66"
|
||
"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x67\x67\x67\x67\x67\x67\x67\x67"
|
||
"\x67\x67\x67\x67\x68\x68\x68\x68\x68\x68\x68\x68\x68\x68\x68\x69\x69\x69"
|
||
"\x69\x69\x69\x69\x69\x69\x69\x69\x6a\x6a\x6a\x6a\x6a\x6a\x6a\x6a\x6a\x6a"
|
||
"\x6a\x6a\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6b\x6c\x6c\x6c\x6c"
|
||
"\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6d\x6d\x6d\x6d\x6d\x6d\x6d\x6d\x6d"
|
||
"\x6d\x6d\x6d\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6e\x6f\x6f\x6f"
|
||
"\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x70\x70\x70\x70\x70\x70\x70\x70\x70"
|
||
"\x70\x70\x70\x70\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x72"
|
||
"\x72\x72\x72\x72\x72\x72\x72\x72\x72\x72\x72\x72\x73\x73\x73\x73\x73\x73"
|
||
"\x73\x73\x73\x73\x73\x73\x73\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74"
|
||
"\x74\x74\x75\x75\x75\x75\x75\x75\x75\x75\x75\x75\x75\x75\x75\x75\x76\x76"
|
||
"\x76\x76\x76\x76\x76\x76\x76\x76\x76\x76\x76\x77\x77\x77\x77\x77\x77\x77"
|
||
"\x77\x77\x77\x77\x77\x77\x77\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78\x78"
|
||
"\x78\x78\x78\x79\x79\x79\x79\x79\x79\x79\x79\x79\x79\x79\x79\x79\x79\x7a"
|
||
"\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7a\x7b\x7b\x7b\x7b\x7b\x7b"
|
||
"\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7c\x7c\x7c\x7c\x7c\x7c\x7c\x7c\x7c"
|
||
"\x7c\x7c\x7c\x7c\x7c\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d\x7d"
|
||
"\x7d\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7e\x7f\x7f"
|
||
"\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x80\x80\x80\x80\x80"
|
||
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x81\x81\x81\x81\x81\x81\x81\x81"
|
||
"\x81\x81\x81\x81\x81\x81\x81\x82\x82\x82\x82\x82\x82\x82\x82\x82\x82\x82"
|
||
"\x82\x82\x82\x82\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83"
|
||
"\x83\x83\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x84\x85"
|
||
"\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x86\x86\x86"
|
||
"\x86\x86\x86\x86\x86\x86\x86\x86\x86\x86\x86\x86\x86\x87\x87\x87\x87\x87"
|
||
"\x87\x87\x87\x87\x87\x87\x87\x87\x87\x87\x87\x88\x88\x88\x88\x88\x88\x88"
|
||
"\x88\x88\x88\x88\x88\x88\x88\x88\x88\x89\x89\x89\x89\x89\x89\x89\x89\x89"
|
||
"\x89\x89\x89\x89\x89\x89\x89\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a"
|
||
"\x8a\x8a\x8a\x8a\x8a\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b\x8b"
|
||
"\x8b\x8b\x8b\x8b\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c\x8c"
|
||
"\x8c\x8c\x8c\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d\x8d"
|
||
"\x8d\x8d\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e\x8e"
|
||
"\x8e\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f"
|
||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x91"
|
||
"\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x91\x92"
|
||
"\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x93"
|
||
"\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x93\x94\x94"
|
||
"\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x94\x95\x95"
|
||
"\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x96\x96"
|
||
"\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x97"
|
||
"\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98"
|
||
"\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98\x98"
|
||
"\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
|
||
"\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a"
|
||
"\x9a\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b"
|
||
"\x9b\x9b\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c\x9c"
|
||
"\x9c\x9c\x9c\x9c\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d\x9d"
|
||
"\x9d\x9d\x9d\x9d\x9d\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e"
|
||
"\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9f\x9f\x9f\x9f\x9f\x9f\x9f\x9f\x9f\x9f\x9f"
|
||
"\x9f\x9f\x9f\x9f\x9f\x9f\x9f\x9f\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0"
|
||
"\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1"
|
||
"\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa1\xa2\xa2\xa2\xa2\xa2\xa2"
|
||
"\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa2\xa3\xa3\xa3\xa3"
|
||
"\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa3\xa4"
|
||
"\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4\xa4"
|
||
"\xa4\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5"
|
||
"\xa5\xa5\xa5\xa5\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
|
||
"\xa6\xa6\xa6\xa6\xa6\xa6\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7"
|
||
"\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa7\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8"
|
||
"\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa8\xa9\xa9\xa9\xa9\xa9"
|
||
"\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xa9\xaa\xaa"
|
||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||
"\xaa\xaa\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab"
|
||
"\xab\xab\xab\xab\xab\xac\xac\xac\xac\xac\xac\xac\xac\xac\xac\xac\xac\xac"
|
||
"\xac\xac\xac\xac\xac\xac\xac\xac\xac\xad\xad\xad\xad\xad\xad\xad\xad\xad"
|
||
"\xad\xad\xad\xad\xad\xad\xad\xad\xad\xad\xad\xad\xad\xae\xae\xae\xae\xae"
|
||
"\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xae\xaf"
|
||
"\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf"
|
||
"\xaf\xaf\xaf\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0"
|
||
"\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1"
|
||
"\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb2\xb2\xb2\xb2\xb2\xb2"
|
||
"\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb3"
|
||
"\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3\xb3"
|
||
"\xb3\xb3\xb3\xb3\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4"
|
||
"\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb4\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5"
|
||
"\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xb6\xb6\xb6"
|
||
"\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6"
|
||
"\xb6\xb6\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7"
|
||
"\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8"
|
||
"\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb9\xb9\xb9\xb9"
|
||
"\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9"
|
||
"\xb9\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba\xba"
|
||
"\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb"
|
||
"\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc"
|
||
"\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc\xbc"
|
||
"\xbc\xbc\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd"
|
||
"\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe"
|
||
"\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbf\xbf"
|
||
"\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf\xbf"
|
||
"\xbf\xbf\xbf\xbf\xbf\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0"
|
||
"\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc1\xc1\xc1\xc1\xc1\xc1"
|
||
"\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
|
||
"\xc1\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2"
|
||
"\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc2\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3"
|
||
"\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc3\xc4\xc4"
|
||
"\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4"
|
||
"\xc4\xc4\xc4\xc4\xc4\xc4\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5"
|
||
"\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc5\xc6\xc6\xc6\xc6"
|
||
"\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6"
|
||
"\xc6\xc6\xc6\xc6\xc6\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7"
|
||
"\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc7\xc8\xc8\xc8\xc8\xc8"
|
||
"\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8"
|
||
"\xc8\xc8\xc8\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9"
|
||
"\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xc9\xca\xca\xca\xca\xca\xca"
|
||
"\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca\xca"
|
||
"\xca\xca\xca\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb"
|
||
"\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcb\xcc\xcc\xcc\xcc\xcc\xcc"
|
||
"\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc"
|
||
"\xcc\xcc\xcc\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
|
||
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xce\xce\xce\xce\xce"
|
||
"\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce\xce"
|
||
"\xce\xce\xce\xce\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf"
|
||
"\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xd0\xd0\xd0\xd0"
|
||
"\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0\xd0"
|
||
"\xd0\xd0\xd0\xd0\xd0\xd0\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1"
|
||
"\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd2\xd2"
|
||
"\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2"
|
||
"\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd2\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3"
|
||
"\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3\xd3"
|
||
"\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4"
|
||
"\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd4\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
|
||
"\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
|
||
"\xd5\xd5\xd5\xd5\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6"
|
||
"\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd6\xd7\xd7\xd7"
|
||
"\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7"
|
||
"\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd7\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8"
|
||
"\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8\xd8"
|
||
"\xd8\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9"
|
||
"\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xda\xda\xda\xda\xda"
|
||
"\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda"
|
||
"\xda\xda\xda\xda\xda\xda\xda\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb"
|
||
"\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb"
|
||
"\xdb\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc"
|
||
"\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdd\xdd\xdd\xdd\xdd"
|
||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
|
||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde"
|
||
"\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde\xde"
|
||
"\xde\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf"
|
||
"\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0"
|
||
"\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0"
|
||
"\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1"
|
||
"\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1\xe1"
|
||
"\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2"
|
||
"\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe2\xe3"
|
||
"\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3"
|
||
"\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe4\xe4\xe4\xe4\xe4\xe4"
|
||
"\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4"
|
||
"\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe4\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
|
||
"\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5\xe5"
|
||
"\xe5\xe5\xe5\xe5\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6"
|
||
"\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe6\xe7"
|
||
"\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7"
|
||
"\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8"
|
||
"\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8"
|
||
"\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9"
|
||
"\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9"
|
||
"\xe9\xe9\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea"
|
||
"\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea"
|
||
"\xea\xea\xea\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb"
|
||
"\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xec"
|
||
"\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec"
|
||
"\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xec\xed\xed\xed"
|
||
"\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed"
|
||
"\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xed\xee\xee\xee\xee\xee\xee"
|
||
"\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee\xee"
|
||
"\xee\xee\xee\xee\xee\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xef\xef"
|
||
"\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef\xef"
|
||
"\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0"
|
||
"\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0"
|
||
"\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1"
|
||
"\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1"
|
||
"\xf1\xf1\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2"
|
||
"\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2\xf2"
|
||
"\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3"
|
||
"\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xf4\xf4"
|
||
"\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4"
|
||
"\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf5\xf5\xf5"
|
||
"\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5"
|
||
"\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf6\xf6\xf6\xf6"
|
||
"\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6"
|
||
"\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7"
|
||
"\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7"
|
||
"\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
||
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
||
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf9\xf9\xf9\xf9\xf9\xf9\xf9"
|
||
"\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9"
|
||
"\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa"
|
||
"\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa"
|
||
"\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb"
|
||
"\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb"
|
||
"\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc"
|
||
"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc"
|
||
"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd"
|
||
"\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd"
|
||
"\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
|
||
"\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe"
|
||
"\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff"
|
||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||
;
|
||
|
||
static unsigned char linear_to_sRGB (float linear) FUNCTION;
|
||
static unsigned char linear_to_sRGB (float linear)
|
||
{
|
||
unsigned slot;
|
||
slot = linear*4096.0 + 0.5;
|
||
if(slot>4095)
|
||
{
|
||
if(linear>0.5)
|
||
slot = 4095;
|
||
else
|
||
slot = 0;
|
||
}
|
||
return linear_to_sRGB_table[slot];
|
||
}
|
||
|
||
typedef struct multichan {
|
||
double L,hue,sat; // L,a,b would be better -- 2-way formula unknown
|
||
unsigned char or,og,ob,alpha; // old 8-bit values
|
||
} multichan;
|
||
|
||
#define X0 ((double)0.9505)
|
||
#define Y0 ((double)1.0000)
|
||
#define Z0 ((double)1.0890)
|
||
#define u0_prime ( (4.0 * X0) / (X0 + 15.0*Y0 + 3.0*Z0) )
|
||
#define v0_prime ( (9.0 * Y0) / (X0 + 15.0*Y0 + 3.0*Z0) )
|
||
|
||
|
||
static void fill_multichan(multichan *mc, double *up, double *vp)
|
||
{
|
||
double X,Y,Z,u,v;
|
||
double u_prime, v_prime; /* temp, part of official formula */
|
||
double Y_norm, fract; /* severely temp */
|
||
|
||
double r = sRGB_to_linear_table[mc->or];
|
||
double g = sRGB_to_linear_table[mc->og];
|
||
double b = sRGB_to_linear_table[mc->ob];
|
||
|
||
// coordinate change, RGB --> XYZ
|
||
X = 0.4124*r + 0.3576*g + 0.1805*b;
|
||
Y = 0.2126*r + 0.7152*g + 0.0722*b;
|
||
Z = 0.0193*r + 0.1192*g + 0.9505*b;
|
||
|
||
// XYZ --> Luv
|
||
Y_norm = Y/Y0;
|
||
fract = 1.0 / (X + 15.0*Y + 3.0*Z);
|
||
u_prime = 4.0*X*fract;
|
||
v_prime = 9.0*Y*fract;
|
||
mc->L = (Y_norm>0.008856) ? 116.0*pow(Y_norm,1.0/3.0)-16.0 : 903.3*Y_norm;
|
||
u = 13.0*mc->L*(u_prime - u0_prime);
|
||
v = 13.0*mc->L*(v_prime - v0_prime);
|
||
|
||
mc->sat = sqrt(u*u + v*v);
|
||
mc->hue = atan2(u,v);
|
||
if(up) *up = u;
|
||
if(vp) *vp = v;
|
||
}
|
||
|
||
|
||
static double tint_part_1(multichan *work, SDL_Surface *in)
|
||
{
|
||
int xx,yy;
|
||
double u_total = 0;
|
||
double v_total = 0;
|
||
|
||
SDL_LockSurface(in);
|
||
for (yy = 0; yy < in->h; yy++)
|
||
{
|
||
for (xx = 0; xx < in->w; xx++)
|
||
{
|
||
multichan *mc = work+yy*in->w+xx;
|
||
// put pixels into a more tolerable form
|
||
SDL_GetRGBA(getpixel(in, xx, yy),
|
||
in->format,
|
||
&mc->or, &mc->og, &mc->ob, &mc->alpha);
|
||
double u,v;
|
||
fill_multichan(mc,&u,&v);
|
||
// average out u and v, giving more weight to opaque high-saturation pixels
|
||
// (this is to take an initial guess at the primary hue)
|
||
u_total += mc->alpha * u * mc->sat;
|
||
v_total += mc->alpha * v * mc->sat;
|
||
}
|
||
}
|
||
SDL_UnlockSurface(in);
|
||
|
||
return atan2(u_total,v_total);
|
||
}
|
||
|
||
|
||
static void change_colors(SDL_Surface *out, multichan *work, double hue_range, multichan *key_color_ptr)
|
||
{
|
||
double lower_hue_1,upper_hue_1,lower_hue_2,upper_hue_2;
|
||
int xx,yy;
|
||
|
||
// prepare source and destination color info
|
||
// should reset hue_range or not? won't bother for now
|
||
multichan key_color = *key_color_ptr; // want to work from a copy, for safety
|
||
lower_hue_1 = key_color.hue - hue_range;
|
||
upper_hue_1 = key_color.hue + hue_range;
|
||
if (lower_hue_1 < -M_PI)
|
||
{
|
||
lower_hue_2 = lower_hue_1 + 2 * M_PI;
|
||
upper_hue_2 = upper_hue_1 + 2 * M_PI;
|
||
}
|
||
else
|
||
{
|
||
lower_hue_2 = lower_hue_1 - 2 * M_PI;
|
||
upper_hue_2 = upper_hue_1 - 2 * M_PI;
|
||
}
|
||
|
||
// get the destination color set up
|
||
multichan dst;
|
||
dst.or = color_hexes[cur_color][0];
|
||
dst.og = color_hexes[cur_color][1];
|
||
dst.ob = color_hexes[cur_color][2];
|
||
fill_multichan(&dst,NULL,NULL);
|
||
double satratio = dst.sat / key_color.sat;
|
||
double slope = (dst.L-key_color.L)/dst.sat;
|
||
|
||
SDL_LockSurface(out);
|
||
for (yy = 0; yy < out->h; yy++)
|
||
{
|
||
for (xx = 0; xx < out->w; xx++)
|
||
{
|
||
multichan *mc = work+yy*out->w+xx;
|
||
|
||
double oldhue = mc->hue;
|
||
|
||
// if not in the first range, and not in the second range, skip this one
|
||
// (really should alpha-blend as a function of hue angle difference)
|
||
if( (oldhue<lower_hue_1 || oldhue>upper_hue_1) && (oldhue<lower_hue_2 || oldhue>upper_hue_2) )
|
||
{
|
||
putpixel(out, xx, yy, SDL_MapRGBA(out->format, mc->or, mc->og, mc->ob, mc->alpha));
|
||
continue;
|
||
}
|
||
|
||
// Modify the pixel
|
||
double old_sat = mc->sat;
|
||
double newsat = old_sat * satratio;
|
||
double L = mc->L;
|
||
if(dst.sat>0)
|
||
L += newsat * slope; // not greyscale destination
|
||
else
|
||
L += old_sat*(dst.L-key_color.L)/key_color.sat;
|
||
|
||
// convert from L,u,v all the way back to sRGB with 8-bit channels
|
||
double X,Y,Z;
|
||
double u_prime, v_prime; /* temp, part of official formula */
|
||
unsigned tries = 3;
|
||
trysat:;
|
||
double u = newsat * sin(dst.hue);
|
||
double v = newsat * cos(dst.hue);
|
||
|
||
// Luv to XYZ
|
||
u_prime = u/(13.0*L)+u0_prime;
|
||
v_prime = v/(13.0*L)+v0_prime;
|
||
Y = (L>7.99959199307) ? Y0*pow((L+16.0)/116.0,3.0) : Y0*L/903.3;
|
||
X = 2.25*Y*u_prime/v_prime;
|
||
Z = (3.0*Y - 0.75*Y*u_prime)/v_prime - 5.0*Y;
|
||
|
||
// coordinate change: XYZ to RGB
|
||
double r = 3.2410*X + -1.5374*Y + -0.4986*Z;
|
||
double g = -0.9692*X + 1.8760*Y + 0.0416*Z;
|
||
double b = 0.0556*X + -0.2040*Y + 1.0570*Z;
|
||
|
||
// If it is out of gamut, try to de-saturate it a few times before truncating.
|
||
// (the linear_to_sRGB function will truncate)
|
||
if((r<=-0.5 || g<=-0.5 || b<=-0.5 || r>=255.5 || g>=255.5 || b>=255.5) && tries--)
|
||
{
|
||
newsat *= 0.8;
|
||
goto trysat;
|
||
}
|
||
|
||
putpixel(out, xx, yy,
|
||
SDL_MapRGBA(out->format, linear_to_sRGB(r), linear_to_sRGB(g), linear_to_sRGB(b), mc->alpha));
|
||
}
|
||
}
|
||
SDL_UnlockSurface(out);
|
||
}
|
||
|
||
|
||
static multichan *find_most_saturated(double initial_hue, multichan *work, unsigned i, double *hue_range_ptr)
|
||
{
|
||
// find the most saturated pixel near the initial hue guess
|
||
multichan *key_color_ptr = NULL;
|
||
double hue_range;
|
||
switch (inf_stamps[cur_stamp]->tinter)
|
||
{
|
||
default:
|
||
case TINTER_NORMAL:
|
||
hue_range = 18*M_PI/180.0; // plus or minus 18 degrees search, 27 replace
|
||
break;
|
||
case TINTER_NARROW:
|
||
hue_range = 6*M_PI/180.0; // plus or minus 6 degrees search, 9 replace
|
||
break;
|
||
case TINTER_ANYHUE:
|
||
hue_range = M_PI; // plus or minus 180 degrees
|
||
break;
|
||
}
|
||
hue_range_retry:;
|
||
double max_sat = 0;
|
||
double lower_hue_1 = initial_hue - hue_range;
|
||
double upper_hue_1 = initial_hue + hue_range;
|
||
double lower_hue_2;
|
||
double upper_hue_2;
|
||
if (lower_hue_1 < -M_PI)
|
||
{
|
||
lower_hue_2 = lower_hue_1 + 2 * M_PI;
|
||
upper_hue_2 = upper_hue_1 + 2 * M_PI;
|
||
}
|
||
else
|
||
{
|
||
lower_hue_2 = lower_hue_1 - 2 * M_PI;
|
||
upper_hue_2 = upper_hue_1 - 2 * M_PI;
|
||
}
|
||
while (i--)
|
||
{
|
||
multichan *mc = work+i;
|
||
// if not in the first range, and not in the second range, skip this one
|
||
if( (mc->hue<lower_hue_1 || mc->hue>upper_hue_1) && (mc->hue<lower_hue_2 || mc->hue>upper_hue_2) )
|
||
continue;
|
||
if(mc->sat > max_sat) {
|
||
max_sat = mc->sat;
|
||
key_color_ptr = mc;
|
||
}
|
||
}
|
||
if (!key_color_ptr)
|
||
{
|
||
hue_range *= 1.5;
|
||
if (hue_range < M_PI)
|
||
goto hue_range_retry;
|
||
}
|
||
*hue_range_ptr = hue_range;
|
||
return key_color_ptr;
|
||
}
|
||
|
||
|
||
static void vector_tint_surface(SDL_Surface * out, SDL_Surface * in)
|
||
{
|
||
int xx,yy;
|
||
|
||
double r = sRGB_to_linear_table[color_hexes[cur_color][0]];
|
||
double g = sRGB_to_linear_table[color_hexes[cur_color][1]];
|
||
double b = sRGB_to_linear_table[color_hexes[cur_color][2]];
|
||
|
||
SDL_LockSurface(in);
|
||
for (yy = 0; yy < in->h; yy++)
|
||
{
|
||
for (xx = 0; xx < in->w; xx++)
|
||
{
|
||
unsigned char r8, g8, b8, a8;
|
||
SDL_GetRGBA(getpixel(in, xx, yy),
|
||
in->format,
|
||
&r8, &g8, &b8, &a8);
|
||
// get the linear greyscale value
|
||
double old = sRGB_to_linear_table[r8]*0.2126 + sRGB_to_linear_table[g8]*0.7152 + sRGB_to_linear_table[b8]*0.0722;
|
||
|
||
putpixel(out, xx, yy,
|
||
SDL_MapRGBA(out->format, linear_to_sRGB(r*old), linear_to_sRGB(g*old), linear_to_sRGB(b*old), a8));
|
||
}
|
||
}
|
||
SDL_UnlockSurface(in);
|
||
}
|
||
|
||
|
||
static void tint_surface(SDL_Surface * tmp_surf, SDL_Surface * surf_ptr)
|
||
{
|
||
unsigned width = surf_ptr->w;
|
||
unsigned height = surf_ptr->h;
|
||
|
||
multichan *work = malloc(sizeof *work * width * height);
|
||
|
||
double initial_hue = tint_part_1(work, surf_ptr);
|
||
|
||
double hue_range;
|
||
multichan *key_color_ptr = find_most_saturated(initial_hue, work, width*height, &hue_range);
|
||
|
||
if (key_color_ptr)
|
||
{
|
||
// wider for processing than for searching
|
||
hue_range *= 1.5;
|
||
|
||
change_colors(tmp_surf, work, hue_range, key_color_ptr);
|
||
}
|
||
else
|
||
{
|
||
fprintf(stderr, "fallback to tinter=vector, this should be in the *.dat file\n");
|
||
vector_tint_surface(tmp_surf, surf_ptr);
|
||
}
|
||
|
||
free(work);
|
||
}
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
/* Draw using the current stamp: */
|
||
|
||
static void stamp_draw(int x, int y)
|
||
{
|
||
SDL_Rect src, dest;
|
||
SDL_Surface * tmp_surf, * surf_ptr, * final_surf;
|
||
Uint32 amask;
|
||
Uint8 r, g, b, a;
|
||
int xx, yy, dont_free_tmp_surf, base_x, base_y;
|
||
|
||
|
||
/* Use a pre-mirrored version, if there is one? */
|
||
|
||
if (state_stamps[cur_stamp]->mirrored)
|
||
{
|
||
if (img_stamps_premirror[cur_stamp] != NULL)
|
||
{
|
||
/* Use pre-mirrored one! */
|
||
|
||
surf_ptr = img_stamps_premirror[cur_stamp];
|
||
}
|
||
else
|
||
{
|
||
/* Use normal (only) one, and mirror it ourselves: */
|
||
|
||
surf_ptr = img_stamps[cur_stamp];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Not mirrored: */
|
||
|
||
surf_ptr = img_stamps[cur_stamp];
|
||
}
|
||
|
||
|
||
/* Create a temp surface to play with: */
|
||
|
||
if (stamp_colorable(cur_stamp) || stamp_tintable(cur_stamp))
|
||
{
|
||
amask = ~(surf_ptr->format->Rmask |
|
||
surf_ptr->format->Gmask |
|
||
surf_ptr->format->Bmask);
|
||
|
||
tmp_surf =
|
||
SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||
surf_ptr->w,
|
||
surf_ptr->h,
|
||
surf_ptr->format->BitsPerPixel,
|
||
surf_ptr->format->Rmask,
|
||
surf_ptr->format->Gmask,
|
||
surf_ptr->format->Bmask,
|
||
amask);
|
||
|
||
if (tmp_surf == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't render the colored stamp!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
dont_free_tmp_surf = 0;
|
||
}
|
||
else
|
||
{
|
||
/* Not altering color; no need to create temp surf if we don't use it! */
|
||
|
||
tmp_surf = NULL;
|
||
dont_free_tmp_surf = 1;
|
||
}
|
||
|
||
|
||
/* Alter the stamp's color, if needed: */
|
||
|
||
if (stamp_colorable(cur_stamp))
|
||
{
|
||
/* Render the stamp in the chosen color: */
|
||
|
||
/* FIXME: It sucks to render this EVERY TIME. Why not just when
|
||
they pick the color, or pick the stamp, like with brushes?
|
||
(Why? Because I'm LAZY! :^) ) */
|
||
|
||
|
||
/* Render the stamp: */
|
||
|
||
SDL_LockSurface(surf_ptr);
|
||
SDL_LockSurface(tmp_surf);
|
||
|
||
for (yy = 0; yy < surf_ptr->h; yy++)
|
||
{
|
||
for (xx = 0; xx < surf_ptr->w; xx++)
|
||
{
|
||
SDL_GetRGBA(getpixel(surf_ptr, xx, yy),
|
||
surf_ptr->format,
|
||
&r, &g, &b, &a);
|
||
|
||
putpixel(tmp_surf, xx, yy,
|
||
SDL_MapRGBA(tmp_surf->format,
|
||
color_hexes[cur_color][0],
|
||
color_hexes[cur_color][1],
|
||
color_hexes[cur_color][2],
|
||
a));
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(tmp_surf);
|
||
SDL_UnlockSurface(surf_ptr);
|
||
}
|
||
else if (stamp_tintable(cur_stamp))
|
||
{
|
||
if (inf_stamps[cur_stamp]->tinter == TINTER_VECTOR)
|
||
vector_tint_surface(tmp_surf, surf_ptr);
|
||
else
|
||
tint_surface(tmp_surf, surf_ptr);
|
||
}
|
||
else
|
||
{
|
||
/* No color change, just use it! */
|
||
|
||
tmp_surf = surf_ptr;
|
||
}
|
||
|
||
|
||
/* Shrink or grow it! */
|
||
|
||
#ifdef USE_HQ4X
|
||
if (CAN_USE_HQ4X)
|
||
{
|
||
/* Use high quality 4x filter! */
|
||
|
||
|
||
/* Make the new surface for the scaled image: */
|
||
|
||
amask = ~(img_stamps[cur_stamp]->format->Rmask |
|
||
img_stamps[cur_stamp]->format->Gmask |
|
||
img_stamps[cur_stamp]->format->Bmask);
|
||
|
||
final_surf = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||
img_stamps[cur_stamp]->w * 4,
|
||
img_stamps[cur_stamp]->h * 4,
|
||
img_stamps[cur_stamp]->format->BitsPerPixel,
|
||
img_stamps[cur_stamp]->format->Rmask,
|
||
img_stamps[cur_stamp]->format->Gmask,
|
||
img_stamps[cur_stamp]->format->Bmask,
|
||
amask);
|
||
|
||
if (final_surf == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't build stamp thumbnails\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
hq4x_32(tmp_surf, final_surf, RGBtoYUV);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
final_surf = thumbnail(tmp_surf, CUR_STAMP_W, CUR_STAMP_H, 0);
|
||
}
|
||
|
||
|
||
/* Where it will go? */
|
||
|
||
base_x = x - (CUR_STAMP_W+1)/2;
|
||
base_y = y - (CUR_STAMP_H+1)/2;
|
||
|
||
|
||
/* And blit it! */
|
||
|
||
if (state_stamps[cur_stamp]->flipped)
|
||
{
|
||
/* Flipped! */
|
||
|
||
if (state_stamps[cur_stamp]->mirrored &&
|
||
img_stamps_premirror[cur_stamp] == NULL)
|
||
{
|
||
/* Mirrored, too! */
|
||
|
||
for (yy = 0; yy < final_surf->h; yy++)
|
||
{
|
||
for (xx = 0; xx < final_surf->w; xx++)
|
||
{
|
||
src.x = final_surf->w - 1 - xx;
|
||
src.y = final_surf->h - 1 - yy;
|
||
src.w = 1;
|
||
src.h = 1;
|
||
|
||
dest.x = base_x + xx;
|
||
dest.y = base_y + yy;
|
||
|
||
SDL_BlitSurface(final_surf, &src, canvas, &dest);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* (Only flipped) */
|
||
|
||
for (yy = 0; yy < final_surf->h; yy++)
|
||
{
|
||
src.x = 0;
|
||
src.y = final_surf->h - 1 - yy;
|
||
src.w = final_surf->w;
|
||
src.h = 1;
|
||
|
||
dest.x = base_x;
|
||
dest.y = base_y + yy;
|
||
|
||
SDL_BlitSurface(final_surf, &src, canvas, &dest);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (state_stamps[cur_stamp]->mirrored &&
|
||
img_stamps_premirror[cur_stamp] == NULL)
|
||
{
|
||
/* Mirrored! */
|
||
|
||
for (xx = 0; xx < final_surf->w; xx++)
|
||
{
|
||
src.x = final_surf->w - 1 - xx;
|
||
src.y = 0;
|
||
src.w = 1;
|
||
src.h = final_surf->h;
|
||
|
||
dest.x = base_x + xx;
|
||
dest.y = base_y;
|
||
|
||
SDL_BlitSurface(final_surf, &src, canvas, &dest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Not altered at all */
|
||
|
||
dest.x = base_x;
|
||
dest.y = base_y;
|
||
|
||
SDL_BlitSurface(final_surf, NULL, canvas, &dest);
|
||
}
|
||
}
|
||
|
||
update_canvas(x - (CUR_STAMP_W+1)/2,
|
||
y - (CUR_STAMP_H+1)/2,
|
||
x + (CUR_STAMP_W+1)/2,
|
||
y + (CUR_STAMP_H+1)/2);
|
||
|
||
/* Free the temporary surfaces */
|
||
|
||
if (!dont_free_tmp_surf)
|
||
SDL_FreeSurface(tmp_surf);
|
||
|
||
SDL_FreeSurface(final_surf);
|
||
}
|
||
|
||
|
||
/* Draw using the current brush: */
|
||
|
||
static void magic_draw(int x1, int y1, int x2, int y2, int button_down)
|
||
{
|
||
int dx, dy, y;
|
||
int orig_x1, orig_y1, orig_x2, orig_y2, tmp;
|
||
float m, b;
|
||
|
||
if (cur_magic == MAGIC_RAINBOW)
|
||
rainbow_color = (rainbow_color + 1) % NUM_RAINBOW_COLORS;
|
||
|
||
orig_x1 = x1;
|
||
orig_y1 = y1;
|
||
|
||
orig_x2 = x2;
|
||
orig_y2 = y2;
|
||
|
||
|
||
dx = x2 - x1;
|
||
dy = y2 - y1;
|
||
|
||
if (dx != 0)
|
||
{
|
||
m = ((float) dy) / ((float) dx);
|
||
b = y1 - m * x1;
|
||
|
||
if (x2 >= x1)
|
||
dx = 1;
|
||
else
|
||
dx = -1;
|
||
|
||
|
||
while (x1 != x2)
|
||
{
|
||
y1 = m * x1 + b;
|
||
y2 = m * (x1 + dx) + b;
|
||
|
||
if (y1 > y2)
|
||
{
|
||
for (y = y1; y >= y2; y--)
|
||
blit_magic(x1, y, button_down);
|
||
}
|
||
else
|
||
{
|
||
for (y = y1; y <= y2; y++)
|
||
blit_magic(x1, y, button_down);
|
||
}
|
||
|
||
x1 = x1 + dx;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (y1 > y2)
|
||
{
|
||
for (y = y1; y >= y2; y--)
|
||
blit_magic(x1, y, button_down);
|
||
}
|
||
else
|
||
{
|
||
for (y = y1; y <= y2; y++)
|
||
blit_magic(x1, y, button_down);
|
||
}
|
||
}
|
||
|
||
if (orig_x1 > orig_x2)
|
||
{
|
||
tmp = orig_x1;
|
||
orig_x1 = orig_x2;
|
||
orig_x2 = tmp;
|
||
}
|
||
|
||
if (orig_y1 > orig_y2)
|
||
{
|
||
tmp = orig_y1;
|
||
orig_y1 = orig_y2;
|
||
orig_y2 = tmp;
|
||
}
|
||
|
||
|
||
/* Play sound: */
|
||
|
||
if (cur_magic == MAGIC_DRIP)
|
||
playsound(0, SND_DRIP, 0);
|
||
else if (cur_magic == MAGIC_CHALK)
|
||
playsound(0, SND_CHALK, 0);
|
||
else if (cur_magic == MAGIC_SPARKLES)
|
||
playsound(0, SND_SPARKLES1 + (rand() % 2), 0);
|
||
else if (cur_magic == MAGIC_FLIP)
|
||
playsound(0, SND_FLIP, 0);
|
||
else if (cur_magic == MAGIC_MIRROR)
|
||
playsound(0, SND_MIRROR, 0);
|
||
else if (cur_magic == MAGIC_NEGATIVE)
|
||
playsound(0, SND_NEGATIVE, 0);
|
||
else if (cur_magic == MAGIC_BLUR)
|
||
playsound(0, SND_BLUR, 0);
|
||
else if (cur_magic == MAGIC_THICK)
|
||
playsound(0, SND_THICK, 0);
|
||
else if (cur_magic == MAGIC_THIN)
|
||
playsound(0, SND_THIN, 0);
|
||
else if (cur_magic == MAGIC_BLOCKS && ((rand() % 10) < 5))
|
||
playsound(0, SND_BLOCKS, 0);
|
||
else if (cur_magic == MAGIC_FADE)
|
||
playsound(0, SND_FADE, 0);
|
||
else if (cur_magic == MAGIC_RAINBOW)
|
||
playsound(0, SND_RAINBOW, 0);
|
||
|
||
|
||
/* FIXME: Arbitrary? */
|
||
|
||
update_canvas(orig_x1 - 32, orig_y1 - 32,
|
||
orig_x2 + 32, orig_y2 + 32);
|
||
}
|
||
|
||
|
||
/* Draw the current brush in the current color: */
|
||
|
||
static void blit_magic(int x, int y, int button_down)
|
||
{
|
||
int xx, yy, w, h;
|
||
Uint32 colr;
|
||
Uint8 r, g, b,
|
||
r1, g1, b1,
|
||
r2, g2, b2,
|
||
r3, g3, b3,
|
||
r4, g4, b4;
|
||
SDL_Surface * last;
|
||
SDL_Rect src, dest;
|
||
int undo_ctr;
|
||
|
||
|
||
/* In case we need to use the current canvas (just saved to undo buf)... */
|
||
|
||
if (cur_undo > 0)
|
||
undo_ctr = cur_undo - 1;
|
||
else
|
||
undo_ctr = NUM_UNDO_BUFS - 1;
|
||
|
||
last = undo_bufs[undo_ctr];
|
||
|
||
|
||
brush_counter++;
|
||
|
||
if (brush_counter >= 4) /* FIXME: Arbitrary? */
|
||
{
|
||
brush_counter = 0;
|
||
|
||
|
||
if (cur_magic == MAGIC_BLUR)
|
||
{
|
||
/* FIXME: Circular "brush?" */
|
||
|
||
SDL_LockSurface(canvas);
|
||
for (yy = y - 16; yy < y + 16; yy = yy + 2)
|
||
{
|
||
for (xx = x - 16; xx < x + 16; xx = xx + 2)
|
||
{
|
||
SDL_GetRGB(getpixel(canvas, clamp(0, xx, canvas->w - 1),
|
||
clamp(0, yy - 1, canvas->h - 1)),
|
||
canvas->format,
|
||
&r1, &g1, &b1);
|
||
|
||
SDL_GetRGB(getpixel(canvas, clamp(0, xx - 1, canvas->w - 1),
|
||
clamp(0, yy, canvas->h - 1)),
|
||
canvas->format,
|
||
&r2, &g2, &b2);
|
||
|
||
SDL_GetRGB(getpixel(canvas, clamp(0, xx + 1, canvas->w - 1),
|
||
clamp(0, yy, canvas->h - 1)),
|
||
canvas->format,
|
||
&r3, &g3, &b3);
|
||
|
||
SDL_GetRGB(getpixel(canvas, clamp(0, xx, canvas->w - 1),
|
||
clamp(0, yy + 1, canvas->h - 1)),
|
||
canvas->format,
|
||
&r4, &g4, &b4);
|
||
|
||
|
||
r = (r1 + r2 + r3 + r4) >> 2;
|
||
g = (g1 + g2 + g3 + g4) >> 2;
|
||
b = (b1 + b2 + b3 + b4) >> 2;
|
||
|
||
putpixel(canvas, xx, yy,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
}
|
||
}
|
||
SDL_UnlockSurface(canvas);
|
||
}
|
||
else if (cur_magic == MAGIC_BLOCKS)
|
||
{
|
||
/* Put x/y on exact grid points: */
|
||
|
||
x = (x / 4) * 4;
|
||
y = (y / 4) * 4;
|
||
|
||
SDL_LockSurface(last);
|
||
SDL_LockSurface(canvas);
|
||
|
||
for (yy = y - 8; yy < y + 8; yy = yy + 4)
|
||
{
|
||
for (xx = x - 8; xx < x + 8; xx = xx + 4)
|
||
{
|
||
Uint32 pix[16];
|
||
Uint32 p_or = 0;
|
||
Uint32 p_and = ~0;
|
||
unsigned i = 16;
|
||
while(i--)
|
||
{
|
||
Uint32 p_tmp;
|
||
p_tmp = getpixel(last, xx+(i>>2), yy+(i&3));
|
||
p_or |= p_tmp;
|
||
p_and &= p_tmp;
|
||
pix[i] = p_tmp;
|
||
}
|
||
if(p_or==p_and) // if all pixels the same already
|
||
{
|
||
SDL_GetRGB(p_or, last->format, &r, &g, &b);
|
||
}
|
||
else // nope, must average them
|
||
{
|
||
double r_sum = 0.0;
|
||
double g_sum = 0.0;
|
||
double b_sum = 0.0;
|
||
i = 16;
|
||
while(i--)
|
||
{
|
||
SDL_GetRGB(pix[i], last->format, &r, &g, &b);
|
||
r_sum += sRGB_to_linear_table[r];
|
||
g_sum += sRGB_to_linear_table[g];
|
||
b_sum += sRGB_to_linear_table[b];
|
||
}
|
||
r = linear_to_sRGB(r_sum/16.0);
|
||
g = linear_to_sRGB(g_sum/16.0);
|
||
b = linear_to_sRGB(b_sum/16.0);
|
||
}
|
||
|
||
/* Draw block: */
|
||
|
||
dest.x = xx;
|
||
dest.y = yy;
|
||
dest.w = 4;
|
||
dest.h = 4;
|
||
|
||
SDL_FillRect(canvas, &dest, SDL_MapRGB(canvas->format, r, g, b));
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(canvas);
|
||
SDL_UnlockSurface(last);
|
||
}
|
||
else if (cur_magic == MAGIC_SMUDGE)
|
||
{
|
||
static double state[32][32][3];
|
||
unsigned i = 32*32;
|
||
double rate = button_down ? 0.5 : 0.0;
|
||
|
||
SDL_LockSurface(canvas);
|
||
|
||
while (i--)
|
||
{
|
||
int iy = i>>5;
|
||
int ix = i&0x1f;
|
||
// is it not on the circle of radius sqrt(120) at location 16,16?
|
||
if ( (ix-16)*(ix-16) + (iy-16)*(iy-16) > 120)
|
||
continue;
|
||
// it is on the circle, so grab it
|
||
|
||
SDL_GetRGB(getpixel(canvas, x+ix-16, y+iy-16), last->format, &r, &g, &b);
|
||
state[ix][iy][0] = rate*state[ix][iy][0] + (1.0-rate)*sRGB_to_linear_table[r];
|
||
state[ix][iy][1] = rate*state[ix][iy][1] + (1.0-rate)*sRGB_to_linear_table[g];
|
||
state[ix][iy][2] = rate*state[ix][iy][2] + (1.0-rate)*sRGB_to_linear_table[b];
|
||
|
||
// opacity 100% --> new data not blended w/ existing data
|
||
putpixel(canvas, x+ix-16, y+iy-16, SDL_MapRGB(canvas->format, linear_to_sRGB(state[ix][iy][0]), linear_to_sRGB(state[ix][iy][1]), linear_to_sRGB(state[ix][iy][2])));
|
||
}
|
||
SDL_UnlockSurface(canvas);
|
||
}
|
||
else if (cur_magic == MAGIC_NEGATIVE)
|
||
{
|
||
SDL_LockSurface(last);
|
||
SDL_LockSurface(canvas);
|
||
|
||
for (yy = y - 16; yy < y + 16; yy++)
|
||
{
|
||
for (xx = x - 16; xx < x + 16; xx++)
|
||
{
|
||
SDL_GetRGB(getpixel(last, xx, yy), last->format,
|
||
&r, &g, &b);
|
||
|
||
r = 0xFF - r;
|
||
g = 0xFF - g;
|
||
b = 0xFF - b;
|
||
|
||
putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b));
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(canvas);
|
||
SDL_UnlockSurface(last);
|
||
}
|
||
else if (cur_magic == MAGIC_FADE)
|
||
{
|
||
SDL_LockSurface(last);
|
||
SDL_LockSurface(canvas);
|
||
|
||
for (yy = y - 16; yy < y + 16; yy++)
|
||
{
|
||
for (xx = x - 16; xx < x + 16; xx++)
|
||
{
|
||
/* Get average color around here: */
|
||
|
||
SDL_GetRGB(getpixel(last, xx, yy), last->format,
|
||
&r, &g, &b);
|
||
|
||
r = min(r + 48, 255);
|
||
g = min(g + 48, 255);
|
||
b = min(b + 48, 255);
|
||
|
||
putpixel(canvas, xx, yy, SDL_MapRGB(canvas->format, r, g, b));
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(canvas);
|
||
SDL_UnlockSurface(last);
|
||
}
|
||
else if (cur_magic == MAGIC_RAINBOW)
|
||
{
|
||
/* Pick next color: */
|
||
|
||
colr = SDL_MapRGB(canvas->format,
|
||
rainbow_hexes[rainbow_color][0],
|
||
rainbow_hexes[rainbow_color][1],
|
||
rainbow_hexes[rainbow_color][2]);
|
||
|
||
|
||
/* Draw the shape: */
|
||
|
||
for (yy = 0; yy <= 16; yy++)
|
||
{
|
||
w = (yy * yy) / 16;
|
||
|
||
|
||
/* Top half: */
|
||
|
||
dest.x = x - 16 + w;
|
||
dest.w = 32 - (w * 2);
|
||
dest.y = y - yy;;
|
||
dest.h = 1;
|
||
|
||
SDL_FillRect(canvas, &dest, colr);
|
||
|
||
|
||
/* Bottom half: */
|
||
|
||
dest.x = x - 16 + w;
|
||
dest.w = 32 - (w * 2);
|
||
dest.y = y + yy;
|
||
dest.h = 1;
|
||
|
||
SDL_FillRect(canvas, &dest, colr);
|
||
}
|
||
}
|
||
else if (cur_magic == MAGIC_CHALK)
|
||
{
|
||
SDL_LockSurface(last);
|
||
|
||
for (yy = y - 8; yy <= y + 8; yy = yy + 4)
|
||
{
|
||
for (xx = x - 8; xx <= x + 8; xx = xx + 4)
|
||
{
|
||
dest.x = xx + ((rand() % 5) - 2);
|
||
dest.y = yy + ((rand() % 5) - 2);
|
||
dest.w = (rand() % 4) + 2;
|
||
dest.h = (rand() % 4) + 2;
|
||
|
||
colr = getpixel(last, clamp(0, xx, canvas->w-1),
|
||
clamp(0, yy, canvas->h-1));
|
||
SDL_FillRect(canvas, &dest, colr);
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(last);
|
||
}
|
||
else if (cur_magic == MAGIC_DRIP)
|
||
{
|
||
for (xx = x - 8; xx <= x + 8; xx++)
|
||
{
|
||
h = (rand() % 8) + 8;
|
||
|
||
for (yy = y; yy <= y + h; yy++)
|
||
{
|
||
src.x = xx;
|
||
src.y = y;
|
||
src.w = 1;
|
||
src.h = 16;
|
||
|
||
dest.x = xx;
|
||
dest.y = yy;
|
||
|
||
SDL_BlitSurface(last, &src, canvas, &dest);
|
||
}
|
||
}
|
||
}
|
||
else if (cur_magic == MAGIC_SPARKLES)
|
||
{
|
||
if ((rand() % 10) < 2)
|
||
{
|
||
src.x = 0;
|
||
src.y = (rand() % 4) * 32;
|
||
src.w = 32;
|
||
src.h = 32;
|
||
|
||
dest.x = x - 16;
|
||
dest.y = y - 16;
|
||
|
||
SDL_BlitSurface(img_sparkles, &src, canvas, &dest);
|
||
}
|
||
}
|
||
else if (cur_magic == MAGIC_FLIP)
|
||
{
|
||
/* Flip the canvas: */
|
||
|
||
for (yy = 0; yy < canvas->h; yy++)
|
||
{
|
||
src.x = 0;
|
||
src.y = yy;
|
||
src.w = canvas->w;
|
||
src.h = 1;
|
||
|
||
dest.x = 0;
|
||
dest.y = canvas->h - yy - 1;
|
||
|
||
SDL_BlitSurface(last, &src, canvas, &dest);
|
||
}
|
||
|
||
|
||
/* Flip starter, too! */
|
||
|
||
starter_flipped = !starter_flipped;
|
||
|
||
if (img_starter != NULL)
|
||
flip_starter();
|
||
}
|
||
else if (cur_magic == MAGIC_MIRROR)
|
||
{
|
||
/* Mirror-image the canvas: */
|
||
|
||
for (xx = 0; xx < canvas->w; xx++)
|
||
{
|
||
src.x = xx;
|
||
src.y = 0;
|
||
src.w = 1;
|
||
src.h = canvas->h;
|
||
|
||
dest.x = canvas->w - xx - 1;
|
||
dest.y = 0;
|
||
|
||
SDL_BlitSurface(last, &src, canvas, &dest);
|
||
}
|
||
|
||
|
||
/* Mirror starter, too! */
|
||
|
||
starter_mirrored = !starter_mirrored;
|
||
|
||
if (img_starter != NULL)
|
||
mirror_starter();
|
||
}
|
||
else if (cur_magic == MAGIC_THIN || cur_magic == MAGIC_THICK)
|
||
{
|
||
SDL_LockSurface(last);
|
||
SDL_LockSurface(canvas);
|
||
|
||
for (xx = -8; xx <= 8; xx++)
|
||
{
|
||
for (yy = -8; yy <= 8; yy++)
|
||
{
|
||
SDL_GetRGB(getpixel(last, x + xx, y + yy), last->format,
|
||
&r, &g, &b);
|
||
|
||
r = min(r, (Uint8)255);
|
||
g = min(g, (Uint8)255);
|
||
b = min(b, (Uint8)255);
|
||
|
||
if ((cur_magic == MAGIC_THIN && (((r + g + b) / 3) > 128)) ||
|
||
(cur_magic == MAGIC_THICK && (((r + g + b) / 3) <= 128)))
|
||
{
|
||
putpixel(canvas, x + xx + 0, y + yy - 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx - 1, y + yy + 0,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 1, y + yy + 0,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 0, y + yy + 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
|
||
putpixel(canvas, x + xx - 1, y + yy - 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx - 1, y + yy + 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 1, y + yy - 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 1, y + yy + 1,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
|
||
putpixel(canvas, x + xx + 0, y + yy - 2,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx - 2, y + yy + 0,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 2, y + yy + 0,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
putpixel(canvas, x + xx + 0, y + yy + 2,
|
||
SDL_MapRGB(canvas->format, r, g, b));
|
||
}
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(canvas);
|
||
SDL_UnlockSurface(last);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Store canvas into undo buffer: */
|
||
|
||
static void rec_undo_buffer(void)
|
||
{
|
||
int wanna_update_toolbar;
|
||
|
||
wanna_update_toolbar = 0;
|
||
|
||
|
||
SDL_BlitSurface(canvas, NULL, undo_bufs[cur_undo], NULL);
|
||
undo_starters[cur_undo] = UNDO_STARTER_NONE;
|
||
|
||
cur_undo = (cur_undo + 1) % NUM_UNDO_BUFS;
|
||
|
||
if (cur_undo == oldest_undo)
|
||
oldest_undo = (oldest_undo + 1) % NUM_UNDO_BUFS;
|
||
|
||
newest_undo = cur_undo;
|
||
|
||
#ifdef DEBUG
|
||
printf("DRAW: Current=%d Oldest=%d Newest=%d\n",
|
||
cur_undo, oldest_undo, newest_undo);
|
||
#endif
|
||
|
||
|
||
/* Update toolbar buttons, if needed: */
|
||
|
||
if (tool_avail[TOOL_UNDO] == 0)
|
||
{
|
||
tool_avail[TOOL_UNDO] = 1;
|
||
wanna_update_toolbar = 1;
|
||
}
|
||
|
||
if (tool_avail[TOOL_REDO])
|
||
{
|
||
tool_avail[TOOL_REDO] = 0;
|
||
wanna_update_toolbar = 1;
|
||
}
|
||
|
||
if (wanna_update_toolbar)
|
||
{
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
}
|
||
|
||
|
||
/* Update the screen with the new canvas: */
|
||
|
||
static void update_canvas(int x1, int y1, int x2, int y2)
|
||
{
|
||
SDL_Rect src, dest;
|
||
|
||
if (img_starter != NULL)
|
||
{
|
||
/* If there was a starter, cover this part of the drawing with
|
||
the corresponding part of the starter's foreground! */
|
||
|
||
src.x = x1;
|
||
src.y = y1;
|
||
src.w = x2 - x1 + 1;
|
||
src.h = y2 - y1 + 1;
|
||
|
||
dest.x = x1;
|
||
dest.y = y1;
|
||
dest.w = src.w;
|
||
dest.h = src.h;
|
||
|
||
SDL_BlitSurface(img_starter, &dest, canvas, &dest);
|
||
}
|
||
|
||
dest.x = 96;
|
||
dest.y = 0;
|
||
SDL_BlitSurface(canvas, NULL, screen, &dest);
|
||
update_screen(x1 + 96, y1, x2 + 96, y2);
|
||
}
|
||
|
||
|
||
/* Show program version: */
|
||
|
||
static void show_version(void)
|
||
{
|
||
printf("\nTux Paint\n");
|
||
printf(" Version " VER_VERSION " (" VER_DATE ")\n");
|
||
|
||
#ifdef LOW_QUALITY_THUMBNAILS
|
||
printf(" Low Quality Thumbnails enabled\n");
|
||
#endif
|
||
|
||
#ifdef LOW_QUALITY_COLOR_SELECTOR
|
||
printf(" Low Quality Color Selector enabled\n");
|
||
#endif
|
||
|
||
#ifdef LOW_QUALITY_STAMP_OUTLINE
|
||
printf(" Low Quality Stamp Outline enabled\n");
|
||
#endif
|
||
|
||
#ifdef LOW_QUALITY_FLOOD_FILL
|
||
printf(" Low Quality Flood Fill enabled\n");
|
||
#endif
|
||
|
||
#ifdef NO_PROMPT_SHADOWS
|
||
printf(" Prompt Shadows disabled\n");
|
||
#endif
|
||
|
||
#ifdef NOSOUND
|
||
printf(" Sound disabled\n");
|
||
#endif
|
||
|
||
#ifdef DEBUG
|
||
printf(" Verbose debugging enabled\n");
|
||
#endif
|
||
|
||
printf("\n");
|
||
}
|
||
|
||
|
||
/* Show usage display: */
|
||
|
||
static void show_usage(FILE * f, char * prg)
|
||
{
|
||
char * blank;
|
||
unsigned i;
|
||
|
||
blank = strdup(prg);
|
||
|
||
for (i = 0; i < strlen(blank); i++)
|
||
blank[i] = ' ';
|
||
|
||
fprintf(f,
|
||
"\n"
|
||
"Usage: %s {--usage | --help | --version | --copying}\n"
|
||
"\n"
|
||
" %s [--windowed | --fullscreen]\n"
|
||
" %s [--640x480 | --800x600 | --1024x768 |\n"
|
||
" %s --1280x1024 | --1400x1050 | --1600x1200]\n"
|
||
" %s [--sound | --nosound] [--quit | --noquit]\n"
|
||
" %s [--print | --noprint] [--complexshapes | --simpleshapes]\n"
|
||
" %s [--mixedcase | --uppercase] [--fancycursors | --nofancycursors]\n"
|
||
" %s [--mouse | --keyboard] [--dontgrab | --grab]\n"
|
||
" %s [--noshortcuts | --shortcuts] [--wheelmouse | --nowheelmouse]\n"
|
||
" %s [--outlines | --nooutlines] [--stamps | --nostamps]\n"
|
||
" %s [--nostampcontrols | --stampcontrols]\n"
|
||
" %s [--mirrorstamps | --dontmirrorstamps]\n"
|
||
" %s [--saveoverask | --saveover | --saveovernew]\n"
|
||
" %s [--nosave | --save]\n"
|
||
" %s [--savedir DIRECTORY]\n"
|
||
#ifdef WIN32
|
||
" %s [--printcfg | --noprintcfg]\n"
|
||
#endif
|
||
" %s [--printdelay=SECONDS]\n"
|
||
" %s [--lang LANGUAGE | --locale LOCALE | --lang help]\n"
|
||
" %s [--nosysconfig] [--nolockfile]\n"
|
||
/* " %s [--record FILE | --playback FILE]\n" */
|
||
"\n",
|
||
prg, prg,
|
||
blank, blank, blank,
|
||
blank, blank, blank,
|
||
blank, blank, blank,
|
||
blank, blank, blank,
|
||
blank, blank, blank,
|
||
#ifdef WIN32
|
||
blank,
|
||
#endif
|
||
blank);
|
||
|
||
free(blank);
|
||
}
|
||
|
||
|
||
/* FIXME: All this should REALLY be array-based!!! */
|
||
|
||
/* Show available languages: */
|
||
|
||
static void show_lang_usage(FILE * f, char * prg)
|
||
{
|
||
fprintf(f,
|
||
"\n"
|
||
"Usage: %s [--lang LANGUAGE]\n"
|
||
"\n"
|
||
"LANGUAGE may be one of:\n"
|
||
/* C */ " english american-english\n"
|
||
/* af */ " afrikaans\n"
|
||
/* sq */ " albanian\n"
|
||
/* eu */ " basque euskara\n"
|
||
/* be */ " belarusian bielaruskaja\n"
|
||
/* nb */ " bokmal\n"
|
||
/* pt_BR */ " brazilian brazilian-portuguese portugues-brazilian\n"
|
||
/* br */ " breton brezhoneg\n"
|
||
/* en_GB */ " british british-english\n"
|
||
/* bg_BG */ " bulgarian\n"
|
||
/* ca */ " catalan catala\n"
|
||
/* zh_CN */ " chinese simplified-chinese\n"
|
||
/* zh_TW */ " traditional-chinese\n"
|
||
/* hr */ " croatian hrvatski\n"
|
||
/* cs */ " czech cesky\n"
|
||
/* da */ " danish dansk\n"
|
||
/* nl */ " dutch nederlands\n"
|
||
/* fi */ " finnish suomi\n"
|
||
/* fr */ " french francais\n"
|
||
/* gl */ " galician galego\n"
|
||
/* de */ " german deutsch\n"
|
||
/* el */ " greek\n"
|
||
/* he */ " hebrew\n"
|
||
/* hi */ " hindi\n"
|
||
/* hu */ " hungarian magyar\n"
|
||
/* is */ " icelandic islenska\n"
|
||
/* id */ " indonesian bahasa-indonesia\n"
|
||
/* it */ " italian italiano\n"
|
||
/* ja */ " japanese\n"
|
||
/* tlh */ " klingon tlhIngan\n"
|
||
/* ko */ " korean\n"
|
||
/* lt */ " lithuanian lietuviu\n"
|
||
/* ms */ " malay\n"
|
||
/* nn */ " norwegian nynorsk norsk\n"
|
||
/* pl */ " polish polski\n"
|
||
/* pt_PT */ " portuguese portugues\n"
|
||
/* ro */ " romanian\n"
|
||
/* ru */ " russian russkiy\n"
|
||
/* sr */ " serbian\n"
|
||
/* sk */ " slovak\n"
|
||
/* sl */ " slovenian slovensko\n"
|
||
/* es */ " spanish espanol\n"
|
||
/* sv */ " swedish svenska\n"
|
||
/* ta */ " tamil\n"
|
||
/* tr */ " turkish\n"
|
||
/* vi */ " vietnamese\n"
|
||
/* wa */ " walloon walon\n"
|
||
/* cy */ " welsh cymraeg\n"
|
||
"\n",
|
||
prg);
|
||
}
|
||
|
||
|
||
/* FIXME: Add accented characters to the descriptions */
|
||
|
||
/* Show available locales: */
|
||
|
||
static void show_locale_usage(FILE * f, char * prg)
|
||
{
|
||
fprintf(f,
|
||
"\n"
|
||
"Usage: %s [--locale LOCALE]\n"
|
||
"\n"
|
||
"LOCALE may be one of:\n"
|
||
" C (English American English)\n"
|
||
" af_ZA (Afrikaans)\n"
|
||
" eu_ES (Baque Euskara)\n"
|
||
" be_BY (Belarusian Bielaruskaja)\n"
|
||
" nb_NO (Bokmal)\n"
|
||
" pt_BR (Brazilian Brazilian Portuguese Portugues Brazilian)\n"
|
||
" br_FR (Breton Brezhoneg)\n"
|
||
" en_GB (British British English)\n"
|
||
" bg_BG (Bulgarian)\n"
|
||
" ca_ES (Catalan Catala)\n"
|
||
" zh_CN (Chinese-Simplified)\n"
|
||
" zh_TW (Chinese-Traditional)\n"
|
||
" cs_CZ (Czech Cesky)\n"
|
||
" da_DK (Danish Dansk)\n"
|
||
" nl_NL (Dutch)\n"
|
||
" fi_FI (Finnish Suomi)\n"
|
||
" fr_FR (French Francais)\n"
|
||
" gl_ES (Galician Galego)\n"
|
||
" de_DE (German Deutsch)\n"
|
||
" el_GR (Greek)\n"
|
||
" he_IL (Hebrew)\n"
|
||
" hi_IN (Hindi)\n"
|
||
" hr_HR (Croatian Hrvatski)\n"
|
||
" hu_HU (Hungarian Magyar)\n"
|
||
" tlh (Klingon tlhIngan)\n"
|
||
" is_IS (Icelandic Islenska)\n"
|
||
" id_ID (Indonesian Bahasa Indonesia)\n"
|
||
" it_IT (Italian Italiano)\n"
|
||
" ja_JP (Japanese)\n"
|
||
" ko_KR (Korean)\n"
|
||
" ms_MY (Malay)\n"
|
||
" lt_LT (Lithuanian Lietuviu)\n"
|
||
" nn_NO (Norwegian Nynorsk Norsk)\n"
|
||
" pl_PL (Polish Polski)\n"
|
||
" pt_PT (Portuguese Portugues)\n"
|
||
" ro_RO (Romanian)\n"
|
||
" ru_RU (Russian Russkiy)\n"
|
||
" sk_SK (Slovak)\n"
|
||
" sl_SI (Slovenian)\n"
|
||
" sq_AL (Albanian)\n"
|
||
" sr_YU (Serbian)\n"
|
||
" es_ES (Spanish Espanol)\n"
|
||
" sv_SE (Swedish Svenska)\n"
|
||
" tr_TR (Turkish)\n"
|
||
" vi_VN (Vietnamese)\n"
|
||
" wa_BE (Walloon)\n"
|
||
" cy_GB (Welsh Cymraeg)\n"
|
||
"\n",
|
||
prg);
|
||
}
|
||
|
||
|
||
static const char *getfilename(const char* path)
|
||
{
|
||
char *p;
|
||
|
||
if ( (p = strrchr( path, '\\' )) != NULL )
|
||
return p+1;
|
||
if ( (p = strrchr( path, '/' )) != NULL )
|
||
return p+1;
|
||
return path;
|
||
}
|
||
|
||
|
||
// The original Tux Paint canvas was 608x472. The canvas can be
|
||
// other sizes now, but many old stamps are sized for the small
|
||
// canvas. So, with larger canvases, we must choose a good scale
|
||
// factor to compensate. As the canvas size grows, the user will
|
||
// want a balance of "more stamps on the screen" and "stamps not
|
||
// getting tiny". This will calculate the needed scale factor.
|
||
static unsigned compute_default_scale_factor(double ratio)
|
||
{
|
||
double old_diag = sqrt(608*608+472*472);
|
||
double new_diag = sqrt(canvas->w*canvas->w+canvas->h*canvas->h);
|
||
double good_def = ratio*sqrt(new_diag/old_diag);
|
||
double good_log = log(good_def);
|
||
unsigned defsize = HARD_MAX_STAMP_SIZE;
|
||
while(defsize>0)
|
||
{
|
||
double this_err = good_log - log(scaletable[defsize].numer / (double)scaletable[defsize].denom);
|
||
double next_err = good_log - log(scaletable[defsize-1].numer / (double)scaletable[defsize-1].denom);
|
||
if( fabs(next_err) > fabs(this_err) ) break;
|
||
defsize--;
|
||
}
|
||
return defsize;
|
||
}
|
||
|
||
|
||
/* Setup: */
|
||
|
||
static void setup(int argc, char * argv[])
|
||
{
|
||
int i, ok_to_use_sysconfig, ok_to_use_lockfile;
|
||
char str[128];
|
||
char * upstr;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
char * homedirdir;
|
||
FILE * fi;
|
||
SDL_Surface * tmp_surf;
|
||
SDL_Rect dest;
|
||
int scale;
|
||
#ifndef LOW_QUALITY_COLOR_SELECTOR
|
||
int x, y;
|
||
SDL_Surface * tmp_btn;
|
||
Uint8 r, g, b, a;
|
||
#endif
|
||
SDL_Surface * tmp_imgcurup, * tmp_imgcurdown;
|
||
|
||
|
||
#ifdef __BEOS__
|
||
/* if run from gui, like OpenTracker in BeOS or Explorer in Windows,
|
||
find path from which binary was run and change dir to it
|
||
so all files will be local :) */
|
||
/* UPDATE (2004.10.06): Since SDL 1.2.7 SDL sets that path correctly,
|
||
so this code wouldn't be needed if SDL was init before anything else,
|
||
(just basic init, window shouldn't be needed). */
|
||
|
||
if (argc && argv[0])
|
||
{
|
||
char * slash = strrchr(argv[0], '/');
|
||
*(slash + 1) = '\0';
|
||
chdir(argv[0]);
|
||
*(slash + 1) = '/';
|
||
}
|
||
#endif
|
||
|
||
|
||
/* Set default options: */
|
||
|
||
use_sound = 1;
|
||
fullscreen = 0;
|
||
noshortcuts = 0;
|
||
dont_do_xor = 0;
|
||
keymouse = 0;
|
||
wheely = 1;
|
||
grab_input = 0;
|
||
no_fancy_cursors = 0;
|
||
simple_shapes = 0;
|
||
only_uppercase = 0;
|
||
promptless_save = SAVE_OVER_PROMPT;
|
||
disable_quit = 0;
|
||
disable_save = 0;
|
||
disable_print = 0;
|
||
dont_load_stamps = 0;
|
||
print_delay = 0;
|
||
printcommand = "pngtopnm | pnmtops | lpr";
|
||
langstr = NULL;
|
||
use_print_config = 0;
|
||
mirrorstamps = 0;
|
||
disable_stamp_controls = 0;
|
||
WINDOW_WIDTH = 640;
|
||
WINDOW_HEIGHT = 480;
|
||
playfile = NULL;
|
||
recording = 0;
|
||
playing = 0;
|
||
ok_to_use_lockfile = 1;
|
||
|
||
|
||
#ifdef __BEOS__
|
||
/* Fancy cursors on BeOS are buggy in SDL */
|
||
|
||
no_fancy_cursors = 1;
|
||
#endif
|
||
|
||
|
||
#ifdef WIN32
|
||
savedir = strdup("userdata");
|
||
#elif __BEOS__
|
||
savedir = strdup("./userdata");
|
||
#else
|
||
savedir = NULL;
|
||
#endif
|
||
|
||
|
||
|
||
/* Load options from global config file: */
|
||
|
||
#ifndef WIN32
|
||
|
||
/* Check to see if it's ok first: */
|
||
|
||
ok_to_use_sysconfig = 1;
|
||
|
||
for (i = 1; i < argc; i++)
|
||
{
|
||
if (strcmp(argv[i], "--nosysconfig") == 0)
|
||
{
|
||
ok_to_use_sysconfig = 0;
|
||
i = argc; /* aka break; */
|
||
}
|
||
}
|
||
|
||
|
||
if (ok_to_use_sysconfig)
|
||
{
|
||
snprintf(str, sizeof(str), "%s/tuxpaint.conf", CONFDIR);
|
||
|
||
fi = fopen(str, "r");
|
||
if (fi != NULL)
|
||
{
|
||
parse_options(fi);
|
||
fclose(fi);
|
||
}
|
||
else
|
||
debug(str);
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* Load options from user's own configuration (".rc" / ".cfg") file: */
|
||
|
||
#if defined(WIN32) || defined(__BEOS__)
|
||
/* Windows and BeOS: Use a "tuxpaint.cfg" file: */
|
||
|
||
strcpy(str, "tuxpaint.cfg");
|
||
|
||
//#elif __APPLE__
|
||
/* Mac: ??? */
|
||
/* FIXME! */
|
||
|
||
#else
|
||
/* Linux and other Unixes: Use 'rc' style (~/.tuxpaintrc) */
|
||
|
||
if (getenv("HOME") != NULL)
|
||
{
|
||
/* Should it be "~/.tuxpaint/tuxpaintrc" instead???
|
||
Comments welcome ... bill@newbreedsoftware.com */
|
||
|
||
snprintf(str, sizeof(str), "%s/.tuxpaintrc", getenv("HOME"));
|
||
}
|
||
else
|
||
{
|
||
/* WOAH! We don't know what our home directory is!? Last resort,
|
||
do it Windows/BeOS way: */
|
||
|
||
strcpy(str, "tuxpaint.cfg");
|
||
}
|
||
#endif
|
||
|
||
|
||
fi = fopen(str, "r");
|
||
if (fi != NULL)
|
||
{
|
||
parse_options(fi);
|
||
fclose(fi);
|
||
}
|
||
else
|
||
debug(str);
|
||
|
||
|
||
/* Handle command-line arguments: */
|
||
|
||
for (i = 1; i < argc; i++)
|
||
{
|
||
if (strcmp(argv[i], "--fullscreen") == 0 || strcmp(argv[i], "-f") == 0)
|
||
{
|
||
fullscreen = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--windowed") == 0 || strcmp(argv[i], "-w") == 0)
|
||
{
|
||
fullscreen = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--mirrorstamps") == 0)
|
||
{
|
||
mirrorstamps = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--dontmirrorstamps") == 0)
|
||
{
|
||
mirrorstamps = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--nostampcontrols") == 0)
|
||
{
|
||
disable_stamp_controls = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--stampcontrols") == 0)
|
||
{
|
||
disable_stamp_controls = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--noshortcuts") == 0)
|
||
{
|
||
noshortcuts = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--shortcuts") == 0)
|
||
{
|
||
noshortcuts = 0;
|
||
}
|
||
else if ( argv[i][0]=='-' && argv[i][1]=='-' && argv[i][2]>='1' && argv[i][2]<='9' )
|
||
{
|
||
char *endp1;
|
||
char *endp2;
|
||
int w,h;
|
||
w = strtoul(argv[i]+2, &endp1, 10);
|
||
h = strtoul(endp1+1, &endp2, 10);
|
||
// sanity check it
|
||
if(argv[i]+2==endp1 || endp1+1==endp2 || *endp1!='x' || *endp2 || w<500 || h<480 || h>w*3 || w>h*4)
|
||
{
|
||
show_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
WINDOW_WIDTH = w;
|
||
WINDOW_HEIGHT = h;
|
||
}
|
||
else if (strcmp(argv[i], "--nooutlines") == 0)
|
||
{
|
||
dont_do_xor = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--outlines") == 0)
|
||
{
|
||
dont_do_xor = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--keyboard") == 0)
|
||
{
|
||
keymouse = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--mouse") == 0)
|
||
{
|
||
keymouse = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--nowheelmouse") == 0)
|
||
{
|
||
wheely = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--wheelmouse") == 0)
|
||
{
|
||
wheely = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--grab") == 0)
|
||
{
|
||
grab_input = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--dontgrab") == 0)
|
||
{
|
||
grab_input = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--nofancycursors") == 0)
|
||
{
|
||
no_fancy_cursors = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--fancycursors") == 0)
|
||
{
|
||
no_fancy_cursors = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--saveover") == 0)
|
||
{
|
||
promptless_save = SAVE_OVER_ALWAYS;
|
||
}
|
||
else if (strcmp(argv[i], "--saveoverask") == 0)
|
||
{
|
||
promptless_save = SAVE_OVER_PROMPT;
|
||
}
|
||
else if (strcmp(argv[i], "--saveovernew") == 0)
|
||
{
|
||
promptless_save = SAVE_OVER_NO;
|
||
}
|
||
else if (strcmp(argv[i], "--uppercase") == 0 || strcmp(argv[i], "-u") == 0)
|
||
{
|
||
only_uppercase = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--mixedcase") == 0 || strcmp(argv[i], "-m") == 0)
|
||
{
|
||
only_uppercase = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--simpleshapes") == 0 ||
|
||
strcmp(argv[i], "-s") == 0)
|
||
{
|
||
simple_shapes = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--complexshapes") == 0)
|
||
{
|
||
simple_shapes = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--noquit") == 0 || strcmp(argv[i], "-x") == 0)
|
||
{
|
||
disable_quit = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--quit") == 0)
|
||
{
|
||
disable_quit = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--nosave") == 0)
|
||
{
|
||
disable_save = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--save") == 0)
|
||
{
|
||
disable_save = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--nostamps") == 0)
|
||
{
|
||
dont_load_stamps = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--stamps") == 0)
|
||
{
|
||
dont_load_stamps = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--noprint") == 0 || strcmp(argv[i], "-p") == 0)
|
||
{
|
||
disable_print = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--print") == 0)
|
||
{
|
||
disable_print = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--noprintcfg") == 0)
|
||
{
|
||
#ifndef WIN32
|
||
fprintf(stderr, "Note: printcfg option only applies to Windows!\n");
|
||
#endif
|
||
use_print_config = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--printcfg") == 0)
|
||
{
|
||
#ifndef WIN32
|
||
fprintf(stderr, "Note: printcfg option only applies to Windows!\n");
|
||
#endif
|
||
use_print_config = 1;
|
||
}
|
||
else if (strstr(argv[i], "--printdelay=") == argv[i])
|
||
{
|
||
sscanf(strstr(argv[i], "--printdelay=") + 13, "%d", &print_delay);
|
||
#ifdef DEBUG
|
||
printf("Print delay set to %d seconds\n", print_delay);
|
||
#endif
|
||
}
|
||
else if (strcmp(argv[i], "--nosound") == 0 || strcmp(argv[i], "-q") == 0)
|
||
{
|
||
use_sound = 0;
|
||
}
|
||
else if (strcmp(argv[i], "--sound") == 0)
|
||
{
|
||
use_sound = 1;
|
||
}
|
||
else if (strcmp(argv[i], "--locale") == 0 || strcmp(argv[i], "-L") == 0)
|
||
{
|
||
if (i < argc - 1)
|
||
{
|
||
snprintf(str, sizeof(str), "LANG=%s", argv[i + 1]);
|
||
putenv(str);
|
||
|
||
setlocale(LC_ALL, ""); /* argv[i + 1]) ? */
|
||
i++;
|
||
}
|
||
else
|
||
{
|
||
/* Forgot to specify the language (locale)! */
|
||
|
||
fprintf(stderr, "%s takes an argument\n", argv[i]);
|
||
show_locale_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
}
|
||
else if (strstr(argv[i], "--lang=") == argv[i])
|
||
{
|
||
if (langstr != NULL)
|
||
free(langstr);
|
||
|
||
langstr = strdup(argv[i] + 7);
|
||
}
|
||
else if (strcmp(argv[i], "--lang") == 0 || strcmp(argv[i], "-l") == 0)
|
||
{
|
||
if (i < argc - 1)
|
||
{
|
||
if (langstr != NULL)
|
||
free(langstr);
|
||
|
||
langstr = strdup(argv[i + 1]);
|
||
i++;
|
||
}
|
||
else
|
||
{
|
||
/* Forgot to specify the language! */
|
||
|
||
fprintf(stderr, "%s takes an argument\n", argv[i]);
|
||
show_lang_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
}
|
||
else if (strcmp(argv[i], "--savedir") == 0)
|
||
{
|
||
if (i < argc - 1)
|
||
{
|
||
if (savedir != NULL)
|
||
free(savedir);
|
||
|
||
savedir = strdup(argv[i + 1]);
|
||
remove_slash(savedir);
|
||
i++;
|
||
}
|
||
else
|
||
{
|
||
/* Forgot to specify the directory name! */
|
||
|
||
fprintf(stderr, "%s takes an argument\n", argv[i]);
|
||
show_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
}
|
||
else if (strcmp(argv[i], "--record") == 0 ||
|
||
strcmp(argv[i], "--playback") == 0)
|
||
{
|
||
if (i < argc - 1)
|
||
{
|
||
playfile = strdup(argv[i + 1]);
|
||
|
||
if (strcmp(argv[i], "--record") == 0)
|
||
recording = 1;
|
||
else if (strcmp(argv[i], "--playback") == 0)
|
||
playing = 1;
|
||
|
||
i++;
|
||
}
|
||
else
|
||
{
|
||
/* Forgot to specify the filename! */
|
||
|
||
fprintf(stderr, "%s takes an argument\n", argv[i]);
|
||
show_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
}
|
||
else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0)
|
||
{
|
||
show_version();
|
||
exit(0);
|
||
}
|
||
else if (strcmp(argv[i], "--copying") == 0 || strcmp(argv[i], "-c") == 0)
|
||
{
|
||
show_version();
|
||
printf(
|
||
"\n"
|
||
"This program is free software; you can redistribute it\n"
|
||
"and/or modify it under the terms of the GNU General Public\n"
|
||
"License as published by the Free Software Foundation;\n"
|
||
"either version 2 of the License, or (at your option) any\n"
|
||
"later version.\n"
|
||
"\n"
|
||
"This program is distributed in the hope that it will be\n"
|
||
"useful and entertaining, but WITHOUT ANY WARRANTY; without\n"
|
||
"even the implied warranty of MERCHANTABILITY or FITNESS\n"
|
||
"FOR A PARTICULAR PURPOSE. See the GNU General Public\n"
|
||
"License for more details.\n"
|
||
"\n"
|
||
"You should have received a copy of the GNU General Public\n"
|
||
"License along with this program; if not, write to the Free\n"
|
||
"Software Foundation, Inc., 59 Temple Place, Suite 330,\n"
|
||
"Boston, MA 02111-1307 USA\n"
|
||
"\n"
|
||
);
|
||
exit(0);
|
||
}
|
||
else if (strcmp(argv[i], "--help") == 0 ||
|
||
strcmp(argv[i], "-h") == 0)
|
||
{
|
||
show_version();
|
||
show_usage(stdout, (char *) getfilename(argv[0]));
|
||
|
||
printf(
|
||
"See: " DOC_PREFIX "README.txt\n"
|
||
"\n");
|
||
exit(0);
|
||
}
|
||
else if (strcmp(argv[i], "--usage") == 0 ||
|
||
strcmp(argv[i], "-u") == 0)
|
||
{
|
||
show_usage(stdout, (char *) getfilename(argv[0]));
|
||
exit(0);
|
||
}
|
||
else if (strcmp(argv[i], "--nosysconfig") == 0)
|
||
{
|
||
debug("Not using system config.");
|
||
}
|
||
else if (strcmp(argv[i], "--nolockfile") == 0)
|
||
{
|
||
debug("Not using lockfile");
|
||
ok_to_use_lockfile = 0;
|
||
}
|
||
else
|
||
{
|
||
show_usage(stderr, (char *) getfilename(argv[0]));
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
|
||
/* Set up language: */
|
||
|
||
if (langstr == NULL && getenv("LANG") != NULL &&
|
||
strncasecmp(getenv("LANG"), "lt_LT", 5) == 0)
|
||
{
|
||
langstr = strdup("lithuanian");
|
||
}
|
||
|
||
if (langstr == NULL && getenv("LANG") != NULL &&
|
||
strncasecmp(getenv("LANG"), "pl_PL", 5) == 0)
|
||
{
|
||
langstr = strdup("polish");
|
||
}
|
||
|
||
if (langstr != NULL)
|
||
{
|
||
if (strcmp(langstr, "english") == 0 ||
|
||
strcmp(langstr, "american-english") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=C");
|
||
putenv((char *) "LC_ALL=C");
|
||
}
|
||
else if (strcmp(langstr, "croatian") == 0 ||
|
||
strcmp(langstr, "hrvatski") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=hr_HR.UTF-8");
|
||
putenv((char *) "LC_ALL=hr_HR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "catalan") == 0 ||
|
||
strcmp(langstr, "catala") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ca_ES.UTF-8");
|
||
putenv((char *) "LC_ALL=ca_ES.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "belarusian") == 0 ||
|
||
strcmp(langstr, "bielaruskaja") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=be_BY.UTF-8");
|
||
putenv((char *) "LC_ALL=be_BY.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "czech") == 0 ||
|
||
strcmp(langstr, "cesky") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=cs_CZ.UTF-8");
|
||
putenv((char *) "LC_ALL=cs_CZ.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "danish") == 0 ||
|
||
strcmp(langstr, "dansk") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=da_DK.UTF-8");
|
||
putenv((char *) "LC_ALL=da_DK.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "german") == 0 ||
|
||
strcmp(langstr, "deutsch") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=de_DE.UTF-8");
|
||
putenv((char *) "LC_ALL=de_DE.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "greek") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=el_GR.UTF-8");
|
||
putenv((char *) "LC_ALL=el_GR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "british-english") == 0 ||
|
||
strcmp(langstr, "british") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=en_GB.UTF-8");
|
||
putenv((char *) "LC_ALL=en_GB.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "spanish") == 0 ||
|
||
strcmp(langstr, "espanol") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=es_ES.UTF-8");
|
||
putenv((char *) "LC_ALL=es_ES.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "finnish") == 0 ||
|
||
strcmp(langstr, "suomi") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=fi_FI.UTF-8");
|
||
putenv((char *) "LC_ALL=fi_FI.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "french") == 0 ||
|
||
strcmp(langstr, "francais") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=fr_FR.UTF-8");
|
||
putenv((char *) "LC_ALL=fr_FR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "galician") == 0 ||
|
||
strcmp(langstr, "galego") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=gl_ES.UTF-8");
|
||
putenv((char *) "LC_ALL=gl_ES.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "hebrew") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=he_IL.UTF-8");
|
||
putenv((char *) "LC_ALL=he_IL.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "hindi") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=hi_IN.UTF-8");
|
||
putenv((char *) "LC_ALL=hi_IN.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "hungarian") == 0 ||
|
||
strcmp(langstr, "magyar") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=hu_HU.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "indonesian") == 0 ||
|
||
strcmp(langstr, "bahasa-indonesia") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=id_ID.UTF-8");
|
||
putenv((char *) "LC_ALL=id_ID.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "icelandic") == 0 ||
|
||
strcmp(langstr, "islenska") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=is_IS.UTF-8");
|
||
putenv((char *) "LC_ALL=is_IS.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "italian") == 0 ||
|
||
strcmp(langstr, "italiano") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=it_IT.UTF-8");
|
||
putenv((char *) "LC_ALL=it_IT.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "japanese") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ja_JP.UTF-8");
|
||
putenv((char *) "LC_ALL=ja_JP.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "vietnamese") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=vi_VN.UTF-8");
|
||
putenv((char *) "LC_ALL=vi_VN.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "afrikaans") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=af_ZA.UTF-8");
|
||
putenv((char *) "LC_ALL=af_ZA.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "albanian") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=sq_AL.UTF-8");
|
||
putenv((char *) "LC_ALL=sq_AL.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "breton") == 0 ||
|
||
strcmp(langstr, "brezhoneg") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=br_FR.UTF-8");
|
||
putenv((char *) "LC_ALL=br_FR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "bulgarian") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=bg_BG.UTF-8");
|
||
putenv((char *) "LC_ALL=bg_BG.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "welsh") == 0 ||
|
||
strcmp(langstr, "cymraeg") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=cy_GB.UTF-8");
|
||
putenv((char *) "LC_ALL=cy_GB.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "bokmal") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=nb_NO.UTF-8");
|
||
putenv((char *) "LC_ALL=nb_NO.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "basque") == 0 ||
|
||
strcmp(langstr, "euskara") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=eu_ES.UTF-8");
|
||
putenv((char *) "LC_ALL=eu_ES.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "korean") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ko_KR.UTF-8");
|
||
putenv((char *) "LC_ALL=ko_KR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "klingon") == 0 ||
|
||
strcmp(langstr, "tlhIngan") == 0 ||
|
||
strcmp(langstr, "tlhingan") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=tlh.UTF-8");
|
||
putenv((char *) "LC_ALL=tlh.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "tamil") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ta_IN.UTF-8");
|
||
putenv((char *) "LC_ALL=ta_IN.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "lithuanian") == 0 ||
|
||
strcmp(langstr, "lietuviu") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=lt_LT.UTF-8");
|
||
putenv((char *) "LC_ALL=lt_LT.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "malay") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ms_MY.UTF-8");
|
||
putenv((char *) "LC_ALL=ms_MY.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "dutch") == 0 ||
|
||
strcmp(langstr, "nederlands") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=nl_NL.UTF-8");
|
||
putenv((char *) "LC_ALL=nl_NL.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "norwegian") == 0 ||
|
||
strcmp(langstr, "nynorsk") == 0 ||
|
||
strcmp(langstr, "norsk") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=nn_NO.UTF-8");
|
||
putenv((char *) "LC_ALL=nn_NO.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "polish") == 0 ||
|
||
strcmp(langstr, "polski") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=pl_PL.UTF-8");
|
||
putenv((char *) "LC_ALL=pl_PL.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "brazilian-portuguese") == 0 ||
|
||
strcmp(langstr, "portugues-brazilian") == 0 ||
|
||
strcmp(langstr, "brazilian") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=pt_BR.UTF-8");
|
||
putenv((char *) "LC_ALL=pt_BR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "portuguese") == 0 ||
|
||
strcmp(langstr, "portugues") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=pt_PT.UTF-8");
|
||
putenv((char *) "LC_ALL=pt_PT.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "romanian") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ro_RO.UTF-8");
|
||
putenv((char *) "LC_ALL=ro_RO.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "russian") == 0 ||
|
||
strcmp(langstr, "russkiy") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=ru_RU.UTF-8");
|
||
putenv((char *) "LC_ALL=ru_RU.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "slovak") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=sk_SK.UTF-8");
|
||
putenv((char *) "LC_ALL=sk_SK.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "slovenian") == 0 ||
|
||
strcmp(langstr, "slovensko") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=sl_SI.UTF-8");
|
||
putenv((char *) "LC_ALL=sl_SI.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "serbian") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=sr_YU.UTF-8");
|
||
putenv((char *) "LC_ALL=sr_YU.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "swedish") == 0 ||
|
||
strcmp(langstr, "svenska") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=sv_SE.UTF-8");
|
||
putenv((char *) "LC_ALL=sv_SE.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "turkish") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=tr_TR.UTF-8");
|
||
putenv((char *) "LC_ALL=tr_TR.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "walloon") == 0 ||
|
||
strcmp(langstr, "walon") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=wa_BE.UTF-8");
|
||
putenv((char *) "LC_ALL=wa_BE.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "chinese") == 0 ||
|
||
strcmp(langstr, "simplified-chinese") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=zh_CN.UTF-8");
|
||
putenv((char *) "LC_ALL=zh_CN.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "traditional-chinese") == 0)
|
||
{
|
||
putenv((char *) "LANGUAGE=zh_TW.UTF-8");
|
||
putenv((char *) "LC_ALL=zh_TW.UTF-8");
|
||
}
|
||
else if (strcmp(langstr, "help") == 0 || strcmp(langstr, "list") == 0)
|
||
{
|
||
show_lang_usage(stdout, (char *) getfilename(argv[0]));
|
||
free(langstr);
|
||
exit(0);
|
||
}
|
||
else
|
||
{
|
||
fprintf(stderr, "%s is an invalid language\n", langstr);
|
||
show_lang_usage(stderr, (char *) getfilename(argv[0]));
|
||
free(langstr);
|
||
exit(1);
|
||
}
|
||
|
||
setlocale(LC_ALL, "");
|
||
free(langstr);
|
||
}
|
||
|
||
bindtextdomain("tuxpaint", LOCALEDIR);
|
||
|
||
/* Old version of glibc does not have bind_textdomain_codeset() */
|
||
#if defined __GLIBC__ && __GLIBC__ == 2 && __GLIBC_MINOR__ >=2 || __GLIBC__ > 2
|
||
bind_textdomain_codeset("tuxpaint", "UTF-8");
|
||
#endif
|
||
|
||
textdomain("tuxpaint");
|
||
|
||
language = current_language();
|
||
|
||
|
||
#ifdef DEBUG
|
||
printf("DEBUG: Language is %s (%d)\n", lang_prefixes[language], language);
|
||
#endif
|
||
|
||
#ifndef WIN32
|
||
putenv((char *) "SDL_VIDEO_X11_WMCLASS=TuxPaint.TuxPaint");
|
||
#endif
|
||
|
||
|
||
/* Test for lockfile, if we're using one: */
|
||
|
||
if (ok_to_use_lockfile)
|
||
{
|
||
char * lock_fname;
|
||
FILE * fi;
|
||
time_t time_lock, time_now;
|
||
|
||
|
||
/* Get the current time: */
|
||
|
||
time_now = time(NULL);
|
||
|
||
|
||
/* Look for the lockfile... */
|
||
|
||
lock_fname = get_fname("lockfile.dat");
|
||
|
||
fi = fopen(lock_fname, "r");
|
||
if (fi != NULL)
|
||
{
|
||
/* If it exists, read its contents: */
|
||
|
||
if (fread(&time_lock, sizeof(time_t), 1, fi) > 0)
|
||
{
|
||
/* Has it not been 30 seconds yet? */
|
||
|
||
if (time_now < time_lock + 30)
|
||
{
|
||
/* FIXME: Wrap in gettext() */
|
||
printf("\nYou're already running a copy of Tux Paint!\n\n");
|
||
|
||
fclose(fi);
|
||
exit(0);
|
||
}
|
||
}
|
||
|
||
fclose(fi);
|
||
}
|
||
|
||
|
||
/* Okay to run; create/update the lockfile */
|
||
|
||
fi = fopen(lock_fname, "w");
|
||
if (fi != NULL)
|
||
{
|
||
/* If we can write to it, do so! */
|
||
|
||
fwrite(&time_now, sizeof(time_t), 1, fi);
|
||
fclose(fi);
|
||
}
|
||
else
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I couldn't create the lockfile (%s)\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", lock_fname, strerror(errno));
|
||
}
|
||
}
|
||
|
||
|
||
/* Init SDL Video: */
|
||
|
||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I could not initialize video!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
exit(1);
|
||
}
|
||
|
||
|
||
/* Set-up Key-Repeat: */
|
||
|
||
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
|
||
SDL_DEFAULT_REPEAT_INTERVAL);
|
||
|
||
|
||
/* Init SDL Timer: */
|
||
|
||
if (SDL_Init(SDL_INIT_TIMER) < 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I could not initialize timer!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
exit(1);
|
||
}
|
||
|
||
|
||
/* Init TTF stuff: */
|
||
|
||
if (TTF_Init() < 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I could not initialize the font (TTF) library!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
SDL_Quit();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
/* Init SDL Audio and set-up Mixer: */
|
||
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
if (SDL_Init(SDL_INIT_AUDIO) < 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I could not initialize audio!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
use_sound = 0;
|
||
}
|
||
else
|
||
{
|
||
#ifndef WIN32
|
||
if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024) < 0)
|
||
#else
|
||
if (Mix_OpenAudio(44100, AUDIO_S16, 2, 2048) < 0)
|
||
#endif
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I could not set up audio for 44100 Hz "
|
||
"16-bit stereo.\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
use_sound = 0;
|
||
}
|
||
else
|
||
{
|
||
/* Load sounds: */
|
||
|
||
for (i = 0; i < NUM_SOUNDS; i++)
|
||
{
|
||
sounds[i] = Mix_LoadWAV(sound_fnames[i]);
|
||
|
||
if (sounds[i] == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I couldn't open a sound file:\n%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", sound_fnames[i], SDL_GetError());
|
||
use_sound = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
|
||
/* Set window icon and caption: */
|
||
|
||
#ifndef __APPLE__
|
||
seticon();
|
||
#endif
|
||
SDL_WM_SetCaption("Tux Paint", "Tux Paint");
|
||
|
||
/* Open Window: */
|
||
|
||
if (fullscreen)
|
||
{
|
||
#ifdef USE_HWSURFACE
|
||
screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT,
|
||
VIDEO_BPP, SDL_FULLSCREEN | SDL_HWSURFACE);
|
||
#else
|
||
screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT,
|
||
VIDEO_BPP, SDL_FULLSCREEN | SDL_SWSURFACE);
|
||
#endif
|
||
|
||
if (screen == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I could not open the display in fullscreen mode.\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
fullscreen = 0;
|
||
}
|
||
}
|
||
|
||
|
||
if (!fullscreen)
|
||
{
|
||
#ifdef USE_HWSURFACE
|
||
screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT,
|
||
VIDEO_BPP, SDL_HWSURFACE);
|
||
#else
|
||
screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT,
|
||
VIDEO_BPP, SDL_SWSURFACE);
|
||
#endif
|
||
}
|
||
|
||
if (screen == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I could not open the display.\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
#if defined(WIN32) && defined(LARGE_CURSOR_FULLSCREEN_BUG)
|
||
if (fullscreen && no_fancy_cursors == 0)
|
||
{
|
||
fprintf(stderr, "Warning: An SDL bug causes the fancy cursors to leave\n"
|
||
"trails in fullscreen mode. Disabling fancy cursors.\n"
|
||
"(You can do this yourself with 'nofancycursors' option,\n"
|
||
"to avoid this warning in the future.)\n");
|
||
no_fancy_cursors = 1;
|
||
}
|
||
#endif
|
||
|
||
|
||
/* Create cursors: */
|
||
|
||
scale = 1;
|
||
|
||
#ifdef SMALL_CURSOR_SHAPES
|
||
scale = 2;
|
||
#endif
|
||
|
||
cursor_hand = get_cursor(hand_bits, hand_mask_bits,
|
||
hand_width, hand_height,
|
||
12 / scale, 1 / scale);
|
||
|
||
cursor_wand = get_cursor(wand_bits, wand_mask_bits,
|
||
wand_width, wand_height,
|
||
4 / scale, 4 / scale);
|
||
|
||
cursor_insertion = get_cursor(insertion_bits, insertion_mask_bits,
|
||
insertion_width, insertion_height,
|
||
7 / scale, 4 / scale);
|
||
|
||
cursor_brush = get_cursor(brush_bits, brush_mask_bits,
|
||
brush_width, brush_height,
|
||
4 / scale, 28 / scale);
|
||
|
||
cursor_crosshair = get_cursor(crosshair_bits, crosshair_mask_bits,
|
||
crosshair_width, crosshair_height,
|
||
15 / scale, 15 / scale);
|
||
|
||
cursor_rotate = get_cursor(rotate_bits, rotate_mask_bits,
|
||
rotate_width, rotate_height,
|
||
15 / scale, 15 / scale);
|
||
|
||
cursor_watch = get_cursor(watch_bits, watch_mask_bits,
|
||
watch_width, watch_height,
|
||
14 / scale, 14 / scale);
|
||
|
||
cursor_arrow = get_cursor(arrow_bits, arrow_mask_bits,
|
||
arrow_width, arrow_height,
|
||
0, 0);
|
||
|
||
cursor_up = get_cursor(up_bits, up_mask_bits,
|
||
up_width, up_height,
|
||
15 / scale, 1 / scale);
|
||
|
||
cursor_down = get_cursor(down_bits, down_mask_bits,
|
||
down_width, down_height,
|
||
15 / scale, 30 / scale);
|
||
|
||
cursor_tiny = get_cursor(tiny_bits, tiny_mask_bits,
|
||
tiny_width, tiny_height,
|
||
3 / scale, 3 / scale);
|
||
|
||
do_setcursor(cursor_watch);
|
||
|
||
|
||
|
||
/* Create drawing canvas: */
|
||
|
||
canvas = SDL_CreateRGBSurface(screen->flags,
|
||
WINDOW_WIDTH - (96 * 2),
|
||
(48 * 7) + 40 + HEIGHTOFFSET,
|
||
screen->format->BitsPerPixel,
|
||
screen->format->Rmask,
|
||
screen->format->Gmask,
|
||
screen->format->Bmask,
|
||
0);
|
||
|
||
img_starter = NULL;
|
||
img_starter_bkgd = NULL;
|
||
starter_mirrored = 0;
|
||
starter_flipped = 0;
|
||
|
||
if (canvas == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't build drawing canvas!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
SDL_FillRect(canvas, NULL, SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
|
||
|
||
/* Create undo buffer space: */
|
||
|
||
for (i = 0; i < NUM_UNDO_BUFS; i++)
|
||
{
|
||
undo_bufs[i] = SDL_CreateRGBSurface(screen->flags,
|
||
WINDOW_WIDTH - (96 * 2),
|
||
(48 * 7) + 40 + HEIGHTOFFSET,
|
||
screen->format->BitsPerPixel,
|
||
screen->format->Rmask,
|
||
screen->format->Gmask,
|
||
screen->format->Bmask,
|
||
0);
|
||
|
||
|
||
if (undo_bufs[i] == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't build undo buffer! (%d of %d)\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", i + 1, NUM_UNDO_BUFS, SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
undo_starters[i] = UNDO_STARTER_NONE;
|
||
}
|
||
|
||
|
||
/* Load and display title image: */
|
||
|
||
img_title = loadimage(DATA_PREFIX "images/title.png");
|
||
img_progress = loadimage(DATA_PREFIX "images/ui/progress.png");
|
||
|
||
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
|
||
dest.x = (WINDOW_WIDTH - img_title->w) / 2;
|
||
dest.y = (WINDOW_HEIGHT - img_title->h);
|
||
|
||
SDL_BlitSurface(img_title, NULL, screen, &dest);
|
||
|
||
prog_bar_ctr = 0;
|
||
show_progress_bar();
|
||
|
||
SDL_Flip(screen);
|
||
|
||
|
||
#ifdef USE_HQ4X
|
||
/* Init high quality scaling stuff: */
|
||
|
||
InitLUTs(RGBtoYUV);
|
||
#endif
|
||
|
||
|
||
/* Load other images: */
|
||
|
||
for (i = 0; i < NUM_TOOLS; i++)
|
||
img_tools[i] = loadimage(tool_img_fnames[i]);
|
||
|
||
img_title_on = loadimage(DATA_PREFIX "images/ui/title.png");
|
||
img_title_large_on = loadimage(DATA_PREFIX "images/ui/title_large.png");
|
||
img_title_off = loadimage(DATA_PREFIX "images/ui/no_title.png");
|
||
img_title_large_off = loadimage(DATA_PREFIX "images/ui/no_title_large.png");
|
||
|
||
img_btn_up = loadimage(DATA_PREFIX "images/ui/btn_up.png");
|
||
img_btn_down = loadimage(DATA_PREFIX "images/ui/btn_down.png");
|
||
img_btn_off = loadimage(DATA_PREFIX "images/ui/btn_off.png");
|
||
|
||
show_progress_bar();
|
||
|
||
img_yes = loadimage(DATA_PREFIX "images/ui/yes.png");
|
||
img_no = loadimage(DATA_PREFIX "images/ui/no.png");
|
||
|
||
img_open = loadimage(DATA_PREFIX "images/ui/open.png");
|
||
img_erase = loadimage(DATA_PREFIX "images/ui/erase.png");
|
||
img_back = loadimage(DATA_PREFIX "images/ui/back.png");
|
||
|
||
img_grow = loadimage(DATA_PREFIX "images/ui/grow.png");
|
||
img_shrink = loadimage(DATA_PREFIX "images/ui/shrink.png");
|
||
|
||
show_progress_bar();
|
||
|
||
tmp_imgcurup = loadimage(DATA_PREFIX "images/ui/cursor_up_large.png");
|
||
tmp_imgcurdown = loadimage(DATA_PREFIX "images/ui/cursor_down_large.png");
|
||
img_cursor_up = thumbnail(tmp_imgcurup, THUMB_W, THUMB_H, 0);
|
||
img_cursor_down = thumbnail(tmp_imgcurdown, THUMB_W, THUMB_H, 0);
|
||
|
||
tmp_imgcurup = loadimage(DATA_PREFIX "images/ui/cursor_starter_up.png");
|
||
tmp_imgcurdown = loadimage(DATA_PREFIX "images/ui/cursor_starter_down.png");
|
||
img_cursor_starter_up = thumbnail(tmp_imgcurup, THUMB_W, THUMB_H, 0);
|
||
img_cursor_starter_down = thumbnail(tmp_imgcurdown, THUMB_W, THUMB_H, 0);
|
||
SDL_FreeSurface(tmp_imgcurup);
|
||
SDL_FreeSurface(tmp_imgcurdown);
|
||
|
||
show_progress_bar();
|
||
|
||
img_scroll_up = loadimage(DATA_PREFIX "images/ui/scroll_up.png");
|
||
img_scroll_down = loadimage(DATA_PREFIX "images/ui/scroll_down.png");
|
||
|
||
img_scroll_up_off = loadimage(DATA_PREFIX "images/ui/scroll_up_off.png");
|
||
img_scroll_down_off = loadimage(DATA_PREFIX "images/ui/scroll_down_off.png");
|
||
|
||
img_paintcan = loadimage(DATA_PREFIX "images/ui/paintcan.png");
|
||
|
||
show_progress_bar();
|
||
|
||
img_sparkles = loadimage(DATA_PREFIX "images/ui/sparkles.png");
|
||
|
||
|
||
/* Load brushes: */
|
||
|
||
#ifndef NOSOUND
|
||
loadarbitrary(img_brushes, NULL, NULL, NULL, NULL, &num_brushes, 0,
|
||
MAX_BRUSHES, DATA_PREFIX "brushes", 1, 40, 40);
|
||
#else
|
||
loadarbitrary(img_brushes, NULL, NULL, NULL, &num_brushes, 0,
|
||
MAX_BRUSHES, DATA_PREFIX "brushes", 1, 40, 40);
|
||
#endif
|
||
|
||
|
||
homedirdir = get_fname("brushes");
|
||
#ifndef NOSOUND
|
||
loadarbitrary(img_brushes, NULL, NULL, NULL, NULL, &num_brushes, num_brushes,
|
||
MAX_BRUSHES, homedirdir, 0, 40, 40);
|
||
#else
|
||
loadarbitrary(img_brushes, NULL, NULL, NULL, &num_brushes, num_brushes,
|
||
MAX_BRUSHES, homedirdir, 0, 40, 40);
|
||
#endif
|
||
|
||
if (num_brushes == 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: No brushes found in " DATA_PREFIX "brushes/\n"
|
||
"or %s\n\n", homedirdir);
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
free(homedirdir);
|
||
|
||
|
||
/* Load system fonts: */
|
||
|
||
font = TTF_OpenFont(DATA_PREFIX "fonts/default_font.ttf",
|
||
18 - (only_uppercase * 3));
|
||
|
||
if (font == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't load font file: "
|
||
DATA_PREFIX "fonts/default_font.ttf\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
large_font = TTF_OpenFont(DATA_PREFIX "fonts/default_font.ttf",
|
||
36 - (only_uppercase * 3));
|
||
|
||
if (large_font == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't load font file: "
|
||
DATA_PREFIX "fonts/default_font.ttf\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
small_font = TTF_OpenFont(DATA_PREFIX "fonts/default_font.ttf",
|
||
14 - (only_uppercase * 2));
|
||
|
||
if (small_font == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't load font file: "
|
||
DATA_PREFIX "fonts/default_font.ttf\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
if (need_own_font(language))
|
||
{
|
||
snprintf(str, sizeof(str), "%sfonts/locale/%s.ttf",
|
||
DATA_PREFIX, lang_prefixes[language]);
|
||
|
||
locale_font = TTF_OpenFont(str, 18);
|
||
|
||
if (locale_font == NULL)
|
||
{
|
||
locale_font = try_alternate_font(language);
|
||
if (locale_font == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Can't load font for this locale:\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n"
|
||
"Will use default (American English) instead.\n\n",
|
||
str, SDL_GetError());
|
||
|
||
|
||
/* Revert to default: */
|
||
|
||
putenv((char *) "LANG=C");
|
||
putenv((char *) "OUTPUT_CHARSET=C");
|
||
setlocale(LC_ALL, "C");
|
||
|
||
bindtextdomain("tuxpaint", LOCALEDIR);
|
||
textdomain("tuxpaint");
|
||
language = current_language();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (locale_font == NULL)
|
||
locale_font = font;
|
||
|
||
|
||
/* Load other available fonts: */
|
||
|
||
num_fonts = 0;
|
||
|
||
loadfonts(DATA_PREFIX "fonts", 1);
|
||
|
||
homedirdir = get_fname("fonts");
|
||
loadfonts(homedirdir, 0);
|
||
free(homedirdir);
|
||
|
||
|
||
/* Load stamps: */
|
||
|
||
if (dont_load_stamps == 0)
|
||
{
|
||
homedirdir = get_fname("stamps");
|
||
#ifndef NOSOUND
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, snd_stamps,
|
||
&num_stamps, 0,
|
||
MAX_STAMPS, homedirdir, 0, -1, -1);
|
||
#else
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, &num_stamps, 0,
|
||
MAX_STAMPS, homedirdir, 0, -1, -1);
|
||
#endif
|
||
|
||
|
||
#ifndef NOSOUND
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, snd_stamps, &num_stamps,
|
||
num_stamps, MAX_STAMPS, DATA_PREFIX "stamps", 0, -1, -1);
|
||
#else
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, &num_stamps,
|
||
num_stamps, MAX_STAMPS, DATA_PREFIX "stamps", 0, -1, -1);
|
||
#endif
|
||
|
||
#ifdef __APPLE__
|
||
#ifndef NOSOUND
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, snd_stamps, &num_stamps,
|
||
num_stamps, MAX_STAMPS, "/Library/Application Support/TuxPaint/stamps", 0, -1, -1);
|
||
#else
|
||
loadarbitrary(img_stamps, img_stamps_premirror,
|
||
txt_stamps, inf_stamps, &num_stamps,
|
||
num_stamps, MAX_STAMPS, "/Library/Application Support/TuxPaint/stamps", 0, -1, -1);
|
||
#endif
|
||
#endif
|
||
|
||
if (num_stamps == 0)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: No stamps found in " DATA_PREFIX "stamps/\n"
|
||
"or %s\n\n", homedirdir);
|
||
}
|
||
|
||
free(homedirdir);
|
||
|
||
|
||
unsigned default_stamp_size = compute_default_scale_factor(1.0);
|
||
|
||
/* Create stamp thumbnails: */
|
||
|
||
for (i = 0; i < num_stamps; i++)
|
||
{
|
||
if (img_stamps[i]->w > 40 ||
|
||
img_stamps[i]->h > 40)
|
||
{
|
||
img_stamp_thumbs[i] = thumbnail(img_stamps[i], 40, 40, 1);
|
||
}
|
||
else
|
||
{
|
||
img_stamp_thumbs[i] = NULL;
|
||
}
|
||
|
||
|
||
if (img_stamps_premirror[i] != NULL && !disable_stamp_controls)
|
||
{
|
||
/* Also thumbnail the pre-drawn mirror version, if any: */
|
||
|
||
if (img_stamps_premirror[i]->w > 40 ||
|
||
img_stamps_premirror[i]->h > 40)
|
||
{
|
||
img_stamp_thumbs_premirror[i] =
|
||
thumbnail(img_stamps_premirror[i], 40, 40, 1);
|
||
}
|
||
else
|
||
{
|
||
img_stamp_thumbs_premirror[i] = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
img_stamps_premirror[i] = NULL;
|
||
}
|
||
|
||
state_stamps[i] = malloc(sizeof(state_type));
|
||
|
||
if (inf_stamps[i] == NULL)
|
||
{
|
||
/* Didn't load one for this stamp, assume defaults: */
|
||
|
||
inf_stamps[i] = malloc(sizeof(info_type));
|
||
inf_stamps[i]->tintable = 0;
|
||
inf_stamps[i]->colorable = 0;
|
||
inf_stamps[i]->mirrorable = 1;
|
||
inf_stamps[i]->tintgray = 1;
|
||
inf_stamps[i]->flipable = 1;
|
||
inf_stamps[i]->ratio = 1.0;
|
||
inf_stamps[i]->tinter = TINTER_NORMAL;
|
||
}
|
||
|
||
{
|
||
unsigned int upper = HARD_MAX_STAMP_SIZE;
|
||
unsigned int lower = 0;
|
||
|
||
do
|
||
{
|
||
scaleparams *s = &scaletable[upper];
|
||
int pw, ph; // proposed width and height
|
||
|
||
pw = (img_stamps[i]->w * s->numer + s->denom - 1) / s->denom;
|
||
ph = (img_stamps[i]->h * s->numer + s->denom - 1) / s->denom;
|
||
|
||
// OK to let a stamp stick off the sides in one direction, not two
|
||
if (pw < canvas->w * 2 && ph < canvas->h * 1)
|
||
break;
|
||
if (pw < canvas->w * 1 && ph < canvas->h * 2)
|
||
break;
|
||
}
|
||
while (--upper);
|
||
|
||
|
||
do
|
||
{
|
||
scaleparams *s = &scaletable[lower];
|
||
int pw, ph; // proposed width and height
|
||
|
||
pw = (img_stamps[i]->w * s->numer + s->denom - 1) / s->denom;
|
||
ph = (img_stamps[i]->h * s->numer + s->denom - 1) / s->denom;
|
||
|
||
if (pw*ph > 20)
|
||
break;
|
||
}
|
||
while (++lower < HARD_MAX_STAMP_SIZE);
|
||
|
||
|
||
if(upper<lower)
|
||
{
|
||
// this, if it ever happens, is very bad
|
||
upper = (upper+lower)/2;
|
||
lower = upper;
|
||
}
|
||
|
||
unsigned mid = default_stamp_size;
|
||
if(inf_stamps[i]->ratio != 1.0)
|
||
mid = compute_default_scale_factor(inf_stamps[i]->ratio);
|
||
|
||
if(mid > upper)
|
||
mid = upper;
|
||
|
||
if(mid < lower)
|
||
mid = lower;
|
||
|
||
state_stamps[i]->min = lower;
|
||
state_stamps[i]->size = mid;
|
||
state_stamps[i]->max = upper;
|
||
}
|
||
|
||
|
||
/* If Tux Paint is in mirror-image-by-default mode, mirror, if we can: */
|
||
|
||
if (mirrorstamps && inf_stamps[i]->mirrorable)
|
||
state_stamps[i]->mirrored = 1;
|
||
else
|
||
state_stamps[i]->mirrored = 0;
|
||
|
||
state_stamps[i]->flipped = 0;
|
||
|
||
show_progress_bar();
|
||
}
|
||
}
|
||
|
||
|
||
/* Load magic icons: */
|
||
|
||
for (i = 0; i < NUM_MAGICS; i++)
|
||
{
|
||
img_magics[i] = loadimage(magic_img_fnames[i]);
|
||
show_progress_bar();
|
||
}
|
||
|
||
|
||
/* Load shape icons: */
|
||
|
||
for (i = 0; i < NUM_SHAPES; i++)
|
||
{
|
||
img_shapes[i] = loadimage(shape_img_fnames[i]);
|
||
show_progress_bar();
|
||
}
|
||
|
||
|
||
/* Load tip tux images: */
|
||
|
||
for (i = 0; i < NUM_TIP_TUX; i++)
|
||
{
|
||
img_tux[i] = loadimage(tux_img_fnames[i]);
|
||
show_progress_bar();
|
||
}
|
||
|
||
|
||
/* Create toolbox and selector labels: */
|
||
|
||
for (i = 0; i < NUM_TITLES; i++)
|
||
{
|
||
if (strlen(title_names[i]) > 0)
|
||
{
|
||
if (need_own_font(language) && locale_font != NULL &&
|
||
strcmp(gettext(title_names[i]), title_names[i]) != 0)
|
||
{
|
||
tmp_surf = TTF_RenderUTF8_Blended(locale_font,
|
||
textdir(gettext(title_names[i])), black);
|
||
img_title_names[i] = thumbnail(tmp_surf,
|
||
min(84, tmp_surf->w), tmp_surf->h, 0);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
else
|
||
{
|
||
upstr = uppercase(textdir(gettext(title_names[i])));
|
||
tmp_surf = TTF_RenderUTF8_Blended(large_font, upstr, black);
|
||
img_title_names[i] = thumbnail(tmp_surf,
|
||
min(84, tmp_surf->w), tmp_surf->h, 0);
|
||
SDL_FreeSurface(tmp_surf);
|
||
free(upstr);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
img_title_names[i] = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* Generate color selection buttons: */
|
||
|
||
#ifndef LOW_QUALITY_COLOR_SELECTOR
|
||
|
||
/* Create appropriately-shaped buttons: */
|
||
|
||
tmp_btn = thumbnail(img_btn_down, (WINDOW_WIDTH - 96) / NUM_COLORS, 48, 0);
|
||
|
||
|
||
/* Create surfaces to draw them into: */
|
||
|
||
for (i = 0; i < NUM_COLORS; i++)
|
||
{
|
||
|
||
img_color_btns[i] = SDL_CreateRGBSurface(screen->flags,
|
||
/* (WINDOW_WIDTH - 96) / NUM_COLORS, 48, */
|
||
tmp_btn->w, tmp_btn->h,
|
||
screen->format->BitsPerPixel,
|
||
screen->format->Rmask,
|
||
screen->format->Gmask,
|
||
screen->format->Bmask,
|
||
0);
|
||
|
||
if (img_color_btns[i] == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't build color button! (%d of %d)\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", i + 1, NUM_COLORS, SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
SDL_LockSurface(img_color_btns[i]);
|
||
}
|
||
|
||
|
||
/* Generate the buttons based on the thumbnails: */
|
||
|
||
SDL_LockSurface(tmp_btn);
|
||
|
||
for (y = 0; y < tmp_btn->h /* 48 */; y++)
|
||
{
|
||
for (x = 0; x < tmp_btn->w /* (WINDOW_WIDTH - 96) / NUM_COLORS */; x++)
|
||
{
|
||
SDL_GetRGB(getpixel(tmp_btn, x, y), tmp_btn->format,
|
||
&r, &g, &b);
|
||
a = 255 - ((r + g + b) / 3);
|
||
|
||
for (i = 0; i < NUM_COLORS; i++)
|
||
{
|
||
putpixel(img_color_btns[i], x, y,
|
||
SDL_MapRGB(img_color_btns[i]->format,
|
||
alpha(color_hexes[i][0], 255, a),
|
||
alpha(color_hexes[i][1], 255, a),
|
||
alpha(color_hexes[i][2], 255, a)));
|
||
}
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < NUM_COLORS; i++)
|
||
SDL_UnlockSurface(img_color_btns[i]);
|
||
|
||
SDL_UnlockSurface(tmp_btn);
|
||
SDL_FreeSurface(tmp_btn);
|
||
|
||
#endif
|
||
|
||
create_button_labels();
|
||
|
||
|
||
/* Seed random-number generator: */
|
||
|
||
srand(SDL_GetTicks());
|
||
|
||
|
||
/* Enable Unicode support in SDL: */
|
||
|
||
SDL_EnableUNICODE(1);
|
||
|
||
|
||
/* Open demo recording or playback file: */
|
||
|
||
if (recording)
|
||
{
|
||
demofi = fopen(playfile, "w");
|
||
|
||
if (demofi == NULL)
|
||
{
|
||
fprintf(stderr, "Error: Cannot create recording file: %s\n"
|
||
"%s\n\n",
|
||
playfile, strerror(errno));
|
||
exit(1);
|
||
}
|
||
}
|
||
else if (playing)
|
||
{
|
||
demofi = fopen(playfile, "r");
|
||
|
||
if (demofi == NULL)
|
||
{
|
||
fprintf(stderr, "Error: Cannot open playback file: %s\n"
|
||
"%s\n\n",
|
||
playfile, strerror(errno));
|
||
exit(1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
demofi = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
/* Render a button label using the appropriate string/font: */
|
||
|
||
static SDL_Surface * do_render_button_label(const char * const label)
|
||
{
|
||
char * str;
|
||
SDL_Surface * tmp_surf, * surf;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
|
||
if (need_own_font(language) && locale_font != NULL &&
|
||
strcmp(gettext(label), label) != 0)
|
||
{
|
||
tmp_surf = TTF_RenderUTF8_Blended(locale_font, textdir(gettext(label)), black);
|
||
surf = thumbnail(tmp_surf, min(48, tmp_surf->w), tmp_surf->h, 0);
|
||
}
|
||
else
|
||
{
|
||
str = uppercase(textdir(gettext(label)));
|
||
tmp_surf = TTF_RenderUTF8_Blended(small_font, str, black);
|
||
surf = thumbnail(tmp_surf, min(48, tmp_surf->w), tmp_surf->h, 0);
|
||
free(str);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
|
||
return surf;
|
||
}
|
||
|
||
static void create_button_labels(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < NUM_TOOLS; i++)
|
||
img_tool_names[i] = do_render_button_label(tool_names[i]);
|
||
|
||
for (i = 0; i < NUM_MAGICS; i++)
|
||
img_magic_names[i] = do_render_button_label(magic_names[i]);
|
||
|
||
for (i = 0; i < NUM_SHAPES; i++)
|
||
img_shape_names[i] = do_render_button_label(shape_names[i]);
|
||
|
||
|
||
/* 'Open' label: */
|
||
|
||
img_openlabels_open = do_render_button_label(textdir(gettext_noop("Open")));
|
||
|
||
|
||
/* 'Erase' label: */
|
||
|
||
img_openlabels_erase = do_render_button_label(textdir(gettext_noop("Erase")));
|
||
|
||
|
||
/* 'Back' label: */
|
||
|
||
img_openlabels_back = do_render_button_label(textdir(gettext_noop("Back")));
|
||
}
|
||
|
||
|
||
static void seticon(void)
|
||
{
|
||
int masklen;
|
||
Uint8 * mask;
|
||
SDL_Surface * icon;
|
||
|
||
/* Load icon into a surface: */
|
||
|
||
#ifndef WIN32
|
||
icon = IMG_Load(DATA_PREFIX "images/icon.png");
|
||
#else
|
||
icon = IMG_Load(DATA_PREFIX "images/icon32x32.png");
|
||
#endif
|
||
|
||
if (icon == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I could not load the icon image: %s\n"
|
||
"The Simple DirectMedia error that occurred was:\n"
|
||
"%s\n\n", DATA_PREFIX "images/icon.png", SDL_GetError());
|
||
return;
|
||
}
|
||
|
||
|
||
#ifndef WIN32
|
||
/* Create mask: */
|
||
masklen = (((icon -> w) + 7) / 8) * (icon -> h);
|
||
mask = malloc(masklen * sizeof(Uint8));
|
||
memset(mask, 0xFF, masklen);
|
||
|
||
/* Set icon: */
|
||
SDL_WM_SetIcon(icon, mask);
|
||
|
||
/* Free icon surface & mask: */
|
||
free(mask);
|
||
#else
|
||
/* Set icon: */
|
||
SDL_WM_SetIcon(icon, NULL);
|
||
#endif
|
||
SDL_FreeSurface(icon);
|
||
|
||
|
||
/* Grab keyboard and mouse, if requested: */
|
||
|
||
if (grab_input)
|
||
{
|
||
debug("Grabbing input!");
|
||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||
}
|
||
}
|
||
|
||
|
||
/* Load a mouse pointer (cursor) shape: */
|
||
|
||
static SDL_Cursor * get_cursor(char * bits, char * mask_bits,
|
||
int width, int height, int x, int y)
|
||
{
|
||
Uint8 b;
|
||
Uint8 temp_bitmap[128], temp_bitmask[128];
|
||
int i;
|
||
|
||
|
||
if (((width + 7) / 8) * height > 128)
|
||
{
|
||
fprintf(stderr, "Error: Cursor is too large!\n");
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
for (i = 0; i < ((width + 7) / 8) * height; i++)
|
||
{
|
||
b = bits[i];
|
||
|
||
temp_bitmap[i] = (((b & 0x01) << 7) |
|
||
((b & 0x02) << 5) |
|
||
((b & 0x04) << 3) |
|
||
((b & 0x08) << 1) |
|
||
((b & 0x10) >> 1) |
|
||
((b & 0x20) >> 3) |
|
||
((b & 0x40) >> 5) |
|
||
((b & 0x80) >> 7));
|
||
|
||
b = mask_bits[i];
|
||
|
||
temp_bitmask[i] = (((b & 0x01) << 7) |
|
||
((b & 0x02) << 5) |
|
||
((b & 0x04) << 3) |
|
||
((b & 0x08) << 1) |
|
||
((b & 0x10) >> 1) |
|
||
((b & 0x20) >> 3) |
|
||
((b & 0x40) >> 5) |
|
||
((b & 0x80) >> 7));
|
||
}
|
||
|
||
return(SDL_CreateCursor(temp_bitmap, temp_bitmask, width, height, x, y));
|
||
}
|
||
|
||
|
||
/* Load an image (with errors): */
|
||
|
||
static SDL_Surface * loadimage(const char * const fname)
|
||
{
|
||
return(do_loadimage(fname, 1));
|
||
}
|
||
|
||
|
||
/* Load an image: */
|
||
|
||
static SDL_Surface * do_loadimage(const char * const fname, int abort_on_error)
|
||
{
|
||
SDL_Surface * s, * disp_fmt_s;
|
||
|
||
|
||
/* Load the image file: */
|
||
|
||
s = IMG_Load(fname);
|
||
if (s == NULL)
|
||
{
|
||
if (abort_on_error)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I couldn't load a graphics file:\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", fname, SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
else
|
||
{
|
||
return(NULL);
|
||
}
|
||
}
|
||
|
||
|
||
/* Convert to the display format: */
|
||
|
||
disp_fmt_s = SDL_DisplayFormatAlpha(s);
|
||
if (disp_fmt_s == NULL)
|
||
{
|
||
if (abort_on_error)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I couldn't convert a graphics file:\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", fname, SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
else
|
||
{
|
||
SDL_FreeSurface(s);
|
||
return(NULL);
|
||
}
|
||
}
|
||
|
||
|
||
/* Free the temp. surface & return the converted one: */
|
||
|
||
SDL_FreeSurface(s);
|
||
|
||
return(disp_fmt_s);
|
||
}
|
||
|
||
|
||
/* Draw the toolbar: */
|
||
|
||
static void draw_toolbar(void)
|
||
{
|
||
int i;
|
||
SDL_Rect dest;
|
||
|
||
|
||
/* FIXME: A hack to make 'Print' button act just like 'New' button: */
|
||
|
||
if (!disable_print)
|
||
tool_avail[TOOL_PRINT] = tool_avail[TOOL_NEW];
|
||
|
||
|
||
draw_image_title(TITLE_TOOLS, 0);
|
||
|
||
for (i = 0; i < NUM_TOOLS + TOOLOFFSET; i++)
|
||
{
|
||
dest.x = ((i % 2) * 48);
|
||
dest.y = ((i / 2) * 48) + 40;
|
||
|
||
|
||
if (i < NUM_TOOLS)
|
||
{
|
||
if (i == cur_tool)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (tool_avail[i])
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = ((i % 2) * 48) + 4;
|
||
dest.y = ((i / 2) * 48) + 40 + 4;
|
||
|
||
SDL_BlitSurface(img_tools[i], NULL, screen, &dest);
|
||
|
||
|
||
dest.x = ((i % 2) * 48) + 4 + (40 - img_tool_names[i]->w) / 2;
|
||
dest.y = ((i / 2) * 48) + 40 + 4 + (44 - img_tool_names[i]->h);
|
||
|
||
SDL_BlitSurface(img_tool_names[i], NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw magic controls: */
|
||
|
||
static void draw_magic(void)
|
||
{
|
||
int i;
|
||
SDL_Rect dest;
|
||
|
||
|
||
/* FIXME: Should we worry about more than 14 magic effects? :^/ */
|
||
|
||
|
||
draw_image_title(TITLE_MAGIC, WINDOW_WIDTH - 96);
|
||
|
||
for (i = 0; i < 14 + TOOLOFFSET; i++)
|
||
{
|
||
dest.x = WINDOW_WIDTH - 96 + ((i % 2) * 48);
|
||
dest.y = ((i / 2) * 48) + 40;
|
||
|
||
|
||
if (i < NUM_MAGICS)
|
||
{
|
||
if (i == cur_magic)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = WINDOW_WIDTH - 96 + ((i % 2) * 48) + 4;
|
||
dest.y = ((i / 2) * 48) + 40 + 4;
|
||
|
||
SDL_BlitSurface(img_magics[i], NULL, screen, &dest);
|
||
|
||
|
||
dest.x = WINDOW_WIDTH - 96 + ((i % 2) * 48) + 4 +
|
||
(40 - img_magic_names[i]->w) / 2;
|
||
dest.y = ((i / 2) * 48) + 40 + 4 + (44 - img_magic_names[i]->h);
|
||
|
||
SDL_BlitSurface(img_magic_names[i], NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw color selector: */
|
||
|
||
static void draw_colors(int enabled)
|
||
{
|
||
int i;
|
||
SDL_Rect dest;
|
||
|
||
dest.x = 0;
|
||
dest.y = 40 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET;
|
||
|
||
if (enabled)
|
||
{
|
||
SDL_BlitSurface(img_title_large_on, NULL, screen, &dest);
|
||
|
||
dest.x = 0;
|
||
dest.y = 40 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET;
|
||
SDL_BlitSurface(img_title_large_on, NULL, screen, &dest);
|
||
|
||
dest.x = (96 - img_title_names[TITLE_COLORS]->w) / 2;
|
||
dest.y = (40 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET +
|
||
(48 - img_title_names[TITLE_COLORS]->h) / 2);
|
||
SDL_BlitSurface(img_title_names[TITLE_COLORS], NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_title_large_off, NULL, screen, &dest);
|
||
}
|
||
|
||
for (i = 0; i < NUM_COLORS; i++)
|
||
{
|
||
#ifndef LOW_QUALITY_COLOR_SELECTOR
|
||
dest.x = (i * ((WINDOW_WIDTH - 96) / NUM_COLORS)) + 96;
|
||
dest.y = 40 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET;
|
||
|
||
if (enabled)
|
||
SDL_BlitSurface(img_color_btns[i], NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_color_btns[COLOR_WHITE], NULL, screen, &dest);
|
||
#else
|
||
dest.x = (i * ((WINDOW_WIDTH - 96) / NUM_COLORS)) + 96;
|
||
dest.y = 40 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET;
|
||
dest.w = ((WINDOW_WIDTH - 96) / NUM_COLORS);
|
||
dest.h = 48 + HEIGHTOFFSET;
|
||
|
||
if (enabled)
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format,
|
||
color_hexes[i][0],
|
||
color_hexes[i][1],
|
||
color_hexes[i][2]));
|
||
else
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format, 240, 240, 240));
|
||
#endif
|
||
|
||
if (i == cur_color && enabled)
|
||
{
|
||
dest.x = (i * ((WINDOW_WIDTH - 96) / NUM_COLORS)) + 96;
|
||
dest.y = 44 + ((NUM_TOOLS / 2) * 48) + HEIGHTOFFSET;
|
||
|
||
SDL_BlitSurface(img_paintcan, NULL, screen, &dest);
|
||
}
|
||
}
|
||
|
||
|
||
/* Keep track of this globally, so the cursor shape will act right */
|
||
|
||
colors_are_selectable = enabled;
|
||
}
|
||
|
||
|
||
/* Draw brushes: */
|
||
|
||
static void draw_brushes(void)
|
||
{
|
||
int i, off_y, max, brush;
|
||
SDL_Rect dest;
|
||
|
||
|
||
/* Draw the title: */
|
||
|
||
draw_image_title(TITLE_BRUSHES, WINDOW_WIDTH - 96);
|
||
|
||
|
||
/* Do we need scrollbars? */
|
||
|
||
if (num_brushes > 14 + TOOLOFFSET)
|
||
{
|
||
off_y = 24;
|
||
max = 12 + TOOLOFFSET;
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40;
|
||
|
||
if (brush_scroll > 0)
|
||
{
|
||
SDL_BlitSurface(img_scroll_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_up_off, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40 + 24 + ((6 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (brush_scroll < num_brushes - 12 - TOOLOFFSET)
|
||
{
|
||
SDL_BlitSurface(img_scroll_down, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_down_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
off_y = 0;
|
||
max = 14 + TOOLOFFSET;
|
||
}
|
||
|
||
|
||
/* Draw each of the shown brushes: */
|
||
|
||
for (brush = brush_scroll;
|
||
brush < brush_scroll + max;
|
||
brush++)
|
||
{
|
||
i = brush - brush_scroll;
|
||
|
||
|
||
dest.x = ((i % 2) * 48) + (WINDOW_WIDTH - 96);
|
||
dest.y = ((i / 2) * 48) + 40 + off_y;
|
||
|
||
if (brush == cur_brush)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (brush < num_brushes)
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
if (brush < num_brushes)
|
||
{
|
||
dest.x = ((i % 2) * 48) + (WINDOW_WIDTH - 96) +
|
||
((48 - (img_brushes[brush]->w)) / 2);
|
||
|
||
/* FIXME: Shouldn't that be ->h??? */
|
||
|
||
dest.y = ((i / 2) * 48) + 40 + ((48 - (img_brushes[brush]->w)) / 2) +
|
||
off_y;
|
||
|
||
SDL_BlitSurface(img_brushes[brush], NULL, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw fonts: */
|
||
|
||
static void draw_fonts(void)
|
||
{
|
||
int i, off_y, max, font;
|
||
SDL_Rect dest, src;
|
||
SDL_Surface * tmp_surf;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
|
||
|
||
/* Draw the title: */
|
||
|
||
draw_image_title(TITLE_LETTERS, WINDOW_WIDTH - 96);
|
||
|
||
|
||
/* Do we need scrollbars? */
|
||
|
||
if (num_fonts > 14 + TOOLOFFSET)
|
||
{
|
||
off_y = 24;
|
||
max = 12 + TOOLOFFSET;
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40;
|
||
|
||
if (font_scroll > 0)
|
||
{
|
||
SDL_BlitSurface(img_scroll_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_up_off, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40 + 24 + ((6 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (font_scroll < num_fonts - 12 - TOOLOFFSET)
|
||
{
|
||
SDL_BlitSurface(img_scroll_down, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_down_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
off_y = 0;
|
||
max = 14 + TOOLOFFSET;
|
||
}
|
||
|
||
|
||
/* Draw each of the shown fonts: */
|
||
|
||
for (font = font_scroll;
|
||
font < font_scroll + max;
|
||
font++)
|
||
{
|
||
i = font - font_scroll;
|
||
|
||
|
||
dest.x = ((i % 2) * 48) + (WINDOW_WIDTH - 96);
|
||
dest.y = ((i / 2) * 48) + 40 + off_y;
|
||
|
||
if (font == cur_font)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (font < num_fonts)
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
/* FIXME: We should render the font buttons once, at startup! */
|
||
|
||
if (font < num_fonts)
|
||
{
|
||
tmp_surf = TTF_RenderUTF8_Blended(fonts[font], "A", black);
|
||
|
||
src.x = (tmp_surf->w - 48) / 2;
|
||
src.y = (tmp_surf->h - 48) / 2;
|
||
src.w = 48;
|
||
src.h = 48;
|
||
|
||
if (src.x < 0)
|
||
src.x = 0;
|
||
if (src.y < 0)
|
||
src.y = 0;
|
||
|
||
dest.x = ((i % 2) * 48) + (WINDOW_WIDTH - 96);
|
||
if (src.w > tmp_surf->w)
|
||
{
|
||
src.w = tmp_surf->w;
|
||
dest.x = dest.x + ((48 - (tmp_surf->w)) / 2);
|
||
}
|
||
|
||
|
||
dest.y = ((i / 2) * 48) + 40 + off_y;
|
||
if (src.h > tmp_surf->h)
|
||
{
|
||
src.h = tmp_surf->h;
|
||
dest.y = dest.y + ((48 - (tmp_surf->h)) / 2);
|
||
}
|
||
|
||
SDL_BlitSurface(tmp_surf, &src, screen, &dest);
|
||
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw stamps: */
|
||
|
||
static void draw_stamps(void)
|
||
{
|
||
int i, off_y, max, stamp, most;
|
||
int base_x, base_y, xx, yy;
|
||
SDL_Rect src, dest;
|
||
SDL_Surface * img;
|
||
|
||
|
||
/* Draw the title: */
|
||
|
||
draw_image_title(TITLE_STAMPS, WINDOW_WIDTH - 96);
|
||
|
||
|
||
/* How many can we show? */
|
||
|
||
most = 10;
|
||
if (disable_stamp_controls)
|
||
most = 14;
|
||
|
||
|
||
/* Do we need scrollbars? */
|
||
|
||
if (num_stamps > most + TOOLOFFSET)
|
||
{
|
||
off_y = 24;
|
||
max = (most - 2) + TOOLOFFSET;
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40;
|
||
|
||
if (stamp_scroll > 0)
|
||
{
|
||
SDL_BlitSurface(img_scroll_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_up_off, NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40 + 24 + ((6 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (!disable_stamp_controls)
|
||
dest.y = dest.y - (48 * 2);
|
||
|
||
if (stamp_scroll < num_stamps - (most - 2) - TOOLOFFSET)
|
||
{
|
||
SDL_BlitSurface(img_scroll_down, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_scroll_down_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
off_y = 0;
|
||
max = most + TOOLOFFSET;
|
||
}
|
||
|
||
|
||
/* Draw each of the shown stamps: */
|
||
|
||
for (stamp = stamp_scroll;
|
||
stamp < stamp_scroll + max;
|
||
stamp++)
|
||
{
|
||
i = stamp - stamp_scroll;
|
||
|
||
|
||
dest.x = ((i % 2) * 48) + (WINDOW_WIDTH - 96);
|
||
dest.y = ((i / 2) * 48) + 40 + off_y;
|
||
|
||
if (stamp == cur_stamp)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (stamp < num_stamps)
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
if (stamp < num_stamps)
|
||
{
|
||
/* Draw the stamp itself: */
|
||
|
||
if (state_stamps[stamp]->mirrored &&
|
||
img_stamps_premirror[stamp] != NULL)
|
||
{
|
||
/* Use pre-drawn mirrored version! */
|
||
|
||
if (img_stamp_thumbs_premirror[stamp] != NULL)
|
||
img = img_stamp_thumbs_premirror[stamp];
|
||
else
|
||
img = img_stamps_premirror[stamp];
|
||
}
|
||
else
|
||
{
|
||
/* Use normal version: */
|
||
|
||
if (img_stamp_thumbs[stamp] != NULL)
|
||
img = img_stamp_thumbs[stamp];
|
||
else
|
||
img = img_stamps[stamp];
|
||
}
|
||
|
||
|
||
/* Where to put it? */
|
||
|
||
base_x = ((i % 2) * 48) + (WINDOW_WIDTH - 96) +
|
||
((48 - (img->w)) / 2);
|
||
|
||
base_y = ((i / 2) * 48) + 40 + ((48 - (img->h)) / 2) + off_y;
|
||
|
||
|
||
if (state_stamps[stamp]->mirrored &&
|
||
img_stamps_premirror[stamp] == NULL)
|
||
{
|
||
/* It's mirrored!: */
|
||
|
||
if (state_stamps[stamp]->flipped)
|
||
{
|
||
/* It's flipped, too! Mirror AND flip! */
|
||
|
||
for (xx = 0; xx < img->w; xx++)
|
||
{
|
||
for (yy = 0; yy < img->h; yy++)
|
||
{
|
||
src.x = xx;
|
||
src.y = yy;
|
||
src.w = 1;
|
||
src.h = 1;
|
||
|
||
dest.x = base_x + img->w - xx - 1;
|
||
dest.y = base_y + img->h - yy - 1;
|
||
|
||
SDL_BlitSurface(img, &src, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Not flipped; just simple mirror-image: */
|
||
|
||
for (xx = 0; xx < img->w; xx++)
|
||
{
|
||
src.x = xx;
|
||
src.y = 0;
|
||
src.w = 1;
|
||
src.h = img->h;
|
||
|
||
dest.x = base_x + img->w - xx - 1;
|
||
dest.y = base_y;
|
||
|
||
SDL_BlitSurface(img, &src, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* It's not mirrored: */
|
||
|
||
if (state_stamps[stamp]->flipped)
|
||
{
|
||
/* Simple flip-image: */
|
||
|
||
for (yy = 0; yy < img->h; yy++)
|
||
{
|
||
src.x = 0;
|
||
src.y = yy;
|
||
src.w = img->w;
|
||
src.h = 1;
|
||
|
||
dest.x = base_x;
|
||
dest.y = base_y + img->h - yy - 1;
|
||
|
||
SDL_BlitSurface(img, &src, screen, &dest);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* No flip or mirror: just blit! */
|
||
|
||
dest.x = base_x;
|
||
dest.y = base_y;
|
||
|
||
SDL_BlitSurface(img, NULL, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw stamp controls: */
|
||
|
||
if (!disable_stamp_controls)
|
||
{
|
||
/* Show mirror button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40 + ((5 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (inf_stamps[cur_stamp]->mirrorable)
|
||
{
|
||
if (state_stamps[cur_stamp]->mirrored)
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = WINDOW_WIDTH - 96 + (48 - img_magics[MAGIC_MIRROR]->w) / 2;
|
||
dest.y = (40 + ((5 + TOOLOFFSET / 2) * 48) +
|
||
(48 - img_magics[MAGIC_MIRROR]->h) / 2);
|
||
|
||
SDL_BlitSurface(img_magics[MAGIC_MIRROR], NULL, screen, &dest);
|
||
|
||
|
||
/* Show flip button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 48;
|
||
dest.y = 40 + ((5 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (inf_stamps[cur_stamp]->flipable)
|
||
{
|
||
if (state_stamps[cur_stamp]->flipped)
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
dest.x = WINDOW_WIDTH - 48 + (48 - img_magics[MAGIC_FLIP]->w) / 2;
|
||
dest.y = (40 + ((5 + TOOLOFFSET / 2) * 48) +
|
||
(48 - img_magics[MAGIC_FLIP]->h) / 2);
|
||
|
||
SDL_BlitSurface(img_magics[MAGIC_FLIP], NULL, screen, &dest);
|
||
|
||
|
||
/* Show shrink button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 40 + ((6 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (state_stamps[cur_stamp]->size > MIN_STAMP_SIZE)
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
|
||
dest.x = WINDOW_WIDTH - 96 + (48 - img_shrink->w) / 2;
|
||
dest.y = (40 + ((6 + TOOLOFFSET / 2) * 48) +
|
||
(48 - img_shrink->h) / 2);
|
||
|
||
SDL_BlitSurface(img_shrink, NULL, screen, &dest);
|
||
|
||
|
||
/* Show grow button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 48;
|
||
dest.y = 40 + ((6 + TOOLOFFSET / 2) * 48);
|
||
|
||
if (state_stamps[cur_stamp]->size < MAX_STAMP_SIZE)
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
|
||
dest.x = WINDOW_WIDTH - 48 + (48 - img_grow->w) / 2;
|
||
dest.y = (40 + ((6 + TOOLOFFSET / 2) * 48) +
|
||
(48 - img_grow->h) / 2);
|
||
|
||
SDL_BlitSurface(img_grow, NULL, screen, &dest);
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw the shape selector: */
|
||
|
||
static void draw_shapes(void)
|
||
{
|
||
int i;
|
||
SDL_Rect dest;
|
||
|
||
|
||
draw_image_title(TITLE_SHAPES, WINDOW_WIDTH - 96);
|
||
|
||
for (i = 0; i < 14 + TOOLOFFSET; i++)
|
||
{
|
||
dest.x = ((i % 2) * 48) + WINDOW_WIDTH - 96;
|
||
dest.y = ((i / 2) * 48) + 40;
|
||
|
||
|
||
if (i == cur_shape)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (i < NUM_SHAPES)
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
if (i < NUM_SHAPES)
|
||
{
|
||
dest.x = ((i % 2) * 48) + 4 + WINDOW_WIDTH - 96;
|
||
dest.y = ((i / 2) * 48) + 40 + 4;
|
||
|
||
SDL_BlitSurface(img_shapes[i], NULL, screen, &dest);
|
||
|
||
dest.x = ((i % 2) * 48) + 4 + WINDOW_WIDTH - 96 +
|
||
(40 - img_shape_names[i]->w) / 2;
|
||
dest.y = ((i / 2) * 48) + 40 + 4 + (44 - img_shape_names[i]->h);
|
||
|
||
SDL_BlitSurface(img_shape_names[i], NULL, screen, &dest);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw the eraser selector: */
|
||
|
||
static void draw_erasers(void)
|
||
{
|
||
int i, x, y, sz;
|
||
SDL_Rect dest;
|
||
|
||
|
||
draw_image_title(TITLE_ERASERS, WINDOW_WIDTH - 96);
|
||
|
||
for (i = 0; i < 14 + TOOLOFFSET; i++)
|
||
{
|
||
dest.x = ((i % 2) * 48) + WINDOW_WIDTH - 96;
|
||
dest.y = ((i / 2) * 48) + 40;
|
||
|
||
|
||
if (i == cur_eraser)
|
||
{
|
||
SDL_BlitSurface(img_btn_down, NULL, screen, &dest);
|
||
}
|
||
else if (i < NUM_ERASERS)
|
||
{
|
||
SDL_BlitSurface(img_btn_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
if (i < NUM_ERASERS)
|
||
{
|
||
sz = (2 + ((NUM_ERASERS - 1 - i) * (38 / (NUM_ERASERS - 1))));
|
||
|
||
x = ((i % 2) * 48) + WINDOW_WIDTH - 96 + 24 - sz / 2;
|
||
y = ((i / 2) * 48) + 40 + 24 - sz / 2;
|
||
|
||
dest.x = x;
|
||
dest.y = y;
|
||
dest.w = sz;
|
||
dest.h = 2;
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format, 0, 0, 0));
|
||
|
||
dest.x = x;
|
||
dest.y = y + sz - 2;
|
||
dest.w = sz;
|
||
dest.h = 2;
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format, 0, 0, 0));
|
||
|
||
dest.x = x;
|
||
dest.y = y;
|
||
dest.w = 2;
|
||
dest.h = sz;
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format, 0, 0, 0));
|
||
|
||
dest.x = x + sz - 2;
|
||
dest.y = y;
|
||
dest.w = 2;
|
||
dest.h = sz;
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(screen->format, 0, 0, 0));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw no selectables: */
|
||
|
||
static void draw_none(void)
|
||
{
|
||
int i;
|
||
SDL_Rect dest;
|
||
|
||
dest.x = WINDOW_WIDTH - 96;
|
||
dest.y = 0;
|
||
SDL_BlitSurface(img_title_off, NULL, screen, &dest);
|
||
|
||
for (i = 0; i < 14 + TOOLOFFSET; i++)
|
||
{
|
||
dest.x = ((i % 2) * 48) + WINDOW_WIDTH - 96;
|
||
dest.y = ((i / 2) * 48) + 40;
|
||
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
}
|
||
}
|
||
|
||
|
||
/* Load an arbitrary set of images into an array (e.g., brushes or stamps) */
|
||
|
||
#ifndef NOSOUND
|
||
static void loadarbitrary(SDL_Surface * surfs[], SDL_Surface * altsurfs[],
|
||
char * descs[], info_type * infs[],
|
||
Mix_Chunk * sounds[],
|
||
int * count, int starting, int max,
|
||
const char * const dir, int fatal, int maxw, int maxh)
|
||
#else
|
||
static void loadarbitrary(SDL_Surface * surfs[], SDL_Surface * altsurfs[],
|
||
char * descs[], info_type * infs[],
|
||
int * count, int starting, int max,
|
||
const char * const dir, int fatal, int maxw, int maxh)
|
||
#endif
|
||
{
|
||
DIR * d;
|
||
struct dirent * f;
|
||
struct stat sbuf;
|
||
char fname[512];
|
||
int d_names_alloced;
|
||
char * * d_names;
|
||
int num_files, i;
|
||
|
||
|
||
/* Make some space: */
|
||
|
||
d_names_alloced = 32;
|
||
d_names = (char * *) malloc(sizeof(char *) * d_names_alloced);
|
||
if (d_names == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't allocate memory for directory listing!\n"
|
||
"The system error that occurred was: %s\n",
|
||
strerror(errno));
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
*count = starting;
|
||
|
||
/* Open the directory: */
|
||
|
||
d = opendir(dir);
|
||
if (d == NULL)
|
||
{
|
||
if (fatal)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't find a directory of images\n"
|
||
"%s\n"
|
||
"The system error that occurred was: %s\n",
|
||
dir, strerror(errno));
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
/* Read directory for images: */
|
||
|
||
num_files = 0;
|
||
do
|
||
{
|
||
f = readdir(d);
|
||
|
||
if (f != NULL)
|
||
{
|
||
d_names[num_files] = strdup(f->d_name);
|
||
num_files++;
|
||
|
||
if (num_files >= d_names_alloced)
|
||
{
|
||
d_names_alloced = d_names_alloced + 32;
|
||
|
||
d_names = (char * *) realloc(d_names, sizeof(char *) * d_names_alloced);
|
||
if (d_names == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't reallocate memory for directory listing!\n"
|
||
"The system error that occurred was: %s\n",
|
||
strerror(errno));
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
while (f != NULL);
|
||
|
||
closedir(d);
|
||
|
||
|
||
qsort(d_names, num_files, sizeof(char *),
|
||
(int(*)(const void *, const void *))compare_strings);
|
||
|
||
|
||
/* Do something with each file (load if PNG, recurse if directory): */
|
||
|
||
for (i = 0; i < num_files && *count < max; i++)
|
||
{
|
||
/* Ignore things starting with "." (e.g., "." and ".." dirs): */
|
||
|
||
if (strstr(d_names[i], ".") != d_names[i])
|
||
{
|
||
/* If it's a directory, recurse down into it: */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s", dir, d_names[i]);
|
||
debug(fname);
|
||
|
||
stat(fname, &sbuf);
|
||
|
||
if (S_ISDIR(sbuf.st_mode))
|
||
{
|
||
debug("...is a directory");
|
||
|
||
#ifndef NOSOUND
|
||
loadarbitrary(surfs, altsurfs, descs, infs, sounds,
|
||
count, *count, max, fname,
|
||
fatal, maxw, maxh);
|
||
#else
|
||
loadarbitrary(surfs, altsurfs, descs, infs,
|
||
count, *count, max, fname,
|
||
fatal, maxw, maxh);
|
||
#endif
|
||
}
|
||
else if (strstr(d_names[i], ".png") != NULL &&
|
||
strstr(d_names[i], "_mirror.png") == NULL)
|
||
{
|
||
/* If it has ".png" in the filename, assume we can try to load it: */
|
||
|
||
surfs[*count] = loadimage(fname);
|
||
|
||
if ((surfs[*count]->w <= maxw &&
|
||
surfs[*count]->h <= maxh) ||
|
||
(maxw == -1 || maxh == -1))
|
||
{
|
||
/* Check for a companion ".txt" file! */
|
||
|
||
if (descs != NULL)
|
||
descs[*count] = loaddesc(fname);
|
||
|
||
if (infs != NULL)
|
||
infs[*count] = loadinfo(fname);
|
||
|
||
if (altsurfs != NULL)
|
||
altsurfs[*count] = loadaltimage(fname);
|
||
|
||
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
if (sounds != NULL)
|
||
sounds[*count] = loadsound(fname);
|
||
}
|
||
#endif
|
||
|
||
|
||
*count = *count + 1;
|
||
}
|
||
else
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Image too large (%d x %d - max: %d x %d)\n"
|
||
"%s\n\n",
|
||
surfs[*count]->w, surfs[*count]->h, maxw, maxh,
|
||
fname);
|
||
}
|
||
|
||
show_progress_bar();
|
||
}
|
||
}
|
||
|
||
free(d_names[i]);
|
||
}
|
||
|
||
free(d_names);
|
||
|
||
|
||
/* Give warning if too many files were found (e.g., some not loaded): */
|
||
|
||
if (*count == max)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Reached maximum images (%d) which can be stored in:\n"
|
||
"%s\n\n",
|
||
max, dir);
|
||
}
|
||
|
||
debug("loadarbitrary() ends...");
|
||
}
|
||
|
||
|
||
/* Create a thumbnail: */
|
||
|
||
static SDL_Surface * thumbnail(SDL_Surface * src, int max_x, int max_y,
|
||
int keep_aspect)
|
||
{
|
||
int x, y;
|
||
float src_x, src_y, off_x, off_y;
|
||
SDL_Surface * s;
|
||
Uint32 amask, tr, tg, tb, ta;
|
||
Uint8 r, g, b, a;
|
||
float xscale, yscale;
|
||
int tmp;
|
||
|
||
|
||
/* Determine scale and centering offsets: */
|
||
|
||
if (!keep_aspect)
|
||
{
|
||
yscale = (float) ((float) src->h / (float) max_y);
|
||
xscale = (float) ((float) src->w / (float) max_x);
|
||
|
||
off_x = 0;
|
||
off_y = 0;
|
||
}
|
||
else
|
||
{
|
||
if (src->h > src->w)
|
||
{
|
||
yscale = (float) ((float) src->h / (float) max_y);
|
||
xscale = yscale;
|
||
|
||
off_x = ((src->h - src->w) / xscale) / 2;
|
||
off_y = 0;
|
||
}
|
||
else
|
||
{
|
||
xscale = (float) ((float) src->w / (float) max_x);
|
||
yscale = xscale;
|
||
|
||
off_x = 0;
|
||
off_y = ((src->w - src->h) / xscale) / 2;
|
||
}
|
||
}
|
||
|
||
|
||
/* Create surface for thumbnail: */
|
||
|
||
amask = ~(src->format->Rmask |
|
||
src->format->Gmask |
|
||
src->format->Bmask);
|
||
|
||
s = SDL_CreateRGBSurface(src->flags, /* SDL_SWSURFACE, */
|
||
max_x, max_y,
|
||
src->format->BitsPerPixel,
|
||
src->format->Rmask,
|
||
src->format->Gmask,
|
||
src->format->Bmask,
|
||
src->format->Amask); /* amask); */
|
||
|
||
|
||
if (s == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't build stamp thumbnails\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
/* Create thumbnail itself: */
|
||
|
||
SDL_LockSurface(src);
|
||
SDL_LockSurface(s);
|
||
|
||
for (y = 0; y < max_y; y++)
|
||
{
|
||
for (x = 0; x < max_x; x++)
|
||
{
|
||
#ifndef LOW_QUALITY_THUMBNAILS
|
||
tr = 0;
|
||
tg = 0;
|
||
tb = 0;
|
||
ta = 0;
|
||
|
||
tmp = 0;
|
||
|
||
for (src_y = y * yscale; src_y < y * yscale + yscale &&
|
||
src_y < src->h; src_y++)
|
||
{
|
||
for (src_x = x * xscale; src_x < x * xscale + xscale &&
|
||
src_x < src->w; src_x++)
|
||
{
|
||
SDL_GetRGBA(getpixel(src, src_x, src_y),
|
||
src->format,
|
||
&r, &g, &b, &a);
|
||
|
||
tr = tr + r;
|
||
tb = tb + b;
|
||
tg = tg + g;
|
||
ta = ta + a;
|
||
|
||
tmp++;
|
||
}
|
||
}
|
||
|
||
if (tmp != 0)
|
||
{
|
||
tr = tr / tmp;
|
||
tb = tb / tmp;
|
||
tg = tg / tmp;
|
||
ta = ta / tmp;
|
||
|
||
putpixel(s, x + off_x, y + off_y, SDL_MapRGBA(s->format,
|
||
(Uint8) tr,
|
||
(Uint8) tg,
|
||
(Uint8) tb,
|
||
(Uint8) ta));
|
||
}
|
||
#else
|
||
src_x = x * xscale;
|
||
src_y = y * yscale;
|
||
|
||
putpixel(s, x + off_x, y + off_y, getpixel(src, src_x, src_y));
|
||
#endif
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(s);
|
||
SDL_UnlockSurface(src);
|
||
|
||
return s;
|
||
}
|
||
|
||
|
||
/* Get a pixel: */
|
||
|
||
static Uint32 getpixel(SDL_Surface * surface, int x, int y)
|
||
{
|
||
int bpp;
|
||
Uint8 * p;
|
||
Uint32 pixel;
|
||
|
||
pixel = 0;
|
||
|
||
|
||
/* get the X/Y values within the bounds of this surface */
|
||
if (x < 0)
|
||
x = 0;
|
||
if (x > surface->w - 1)
|
||
x = surface->w - 1;
|
||
if (y > surface->h - 1)
|
||
y = surface->h - 1;
|
||
if (y < 0)
|
||
y = 0;
|
||
|
||
/* SDL_LockSurface(surface); */
|
||
|
||
|
||
/* Determine bytes-per-pixel for the surface in question: */
|
||
|
||
bpp = surface->format->BytesPerPixel;
|
||
|
||
|
||
/* Set a pointer to the exact location in memory of the pixel
|
||
in question: */
|
||
|
||
p = (Uint8 *) (((Uint8 *)surface->pixels) + /* Start at top of RAM */
|
||
(y * surface->pitch) + /* Go down Y lines */
|
||
(x * bpp)); /* Go in X pixels */
|
||
|
||
|
||
/* Return the correctly-sized piece of data containing the
|
||
* pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit
|
||
* RGB value) */
|
||
|
||
if (bpp == 1) /* 8-bit display */
|
||
pixel = *p;
|
||
else if (bpp == 2) /* 16-bit display */
|
||
pixel = *(Uint16 *)p;
|
||
else if (bpp == 3) /* 24-bit display */
|
||
{
|
||
/* Depending on the byte-order, it could be stored RGB or BGR! */
|
||
|
||
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
||
pixel = p[0] << 16 | p[1] << 8 | p[2];
|
||
else
|
||
pixel = p[0] | p[1] << 8 | p[2] << 16;
|
||
}
|
||
else if (bpp == 4) /* 32-bit display */
|
||
pixel = *(Uint32 *)p;
|
||
|
||
/* SDL_UnlockSurface(surface); */
|
||
|
||
return pixel;
|
||
}
|
||
|
||
|
||
/* Draw a single pixel into the surface: */
|
||
|
||
static void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel)
|
||
{
|
||
int bpp;
|
||
Uint8 * p;
|
||
|
||
|
||
/* Assuming the X/Y values are within the bounds of this surface... */
|
||
|
||
if (x >= 0 && y >= 0 && x < surface->w && y < surface->h)
|
||
{
|
||
/* SDL_LockSurface(surface); */
|
||
|
||
|
||
/* Determine bytes-per-pixel for the surface in question: */
|
||
|
||
bpp = surface->format->BytesPerPixel;
|
||
|
||
|
||
/* Set a pointer to the exact location in memory of the pixel
|
||
* in question: */
|
||
|
||
p = (Uint8 *) (((Uint8 *)surface->pixels) + /* Start: beginning of RAM */
|
||
(y * surface->pitch) + /* Go down Y lines */
|
||
(x * bpp)); /* Go in X pixels */
|
||
|
||
|
||
/* Set the (correctly-sized) piece of data in the surface's RAM
|
||
* to the pixel value sent in: */
|
||
|
||
if (bpp == 1)
|
||
*p = pixel;
|
||
else if (bpp == 2)
|
||
*(Uint16 *)p = pixel;
|
||
else if (bpp == 3)
|
||
{
|
||
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
||
{
|
||
p[0] = (pixel >> 16) & 0xff;
|
||
p[1] = (pixel >> 8) & 0xff;
|
||
p[2] = pixel & 0xff;
|
||
}
|
||
else
|
||
{
|
||
p[0] = pixel & 0xff;
|
||
p[1] = (pixel >> 8) & 0xff;
|
||
p[2] = (pixel >> 16) & 0xff;
|
||
}
|
||
}
|
||
else if (bpp == 4)
|
||
{
|
||
*(Uint32 *)p = pixel;
|
||
}
|
||
|
||
/* SDL_UnlockSurface(surface); */
|
||
}
|
||
}
|
||
|
||
/* Should really clip at the line level, but oh well... */
|
||
|
||
static void clipped_putpixel(SDL_Surface * dest, int x, int y, Uint32 c)
|
||
{
|
||
if (x >= 96 && x < (WINDOW_WIDTH - 96) &&
|
||
y >= 0 && y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||
{
|
||
putpixel(dest, x, y, c);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* Show debugging stuff: */
|
||
|
||
static void debug(const char * const str)
|
||
{
|
||
#ifndef DEBUG
|
||
(void)str;
|
||
#else
|
||
fprintf(stderr, "DEBUG: %s\n", str);
|
||
fflush(stderr);
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Undo! */
|
||
|
||
static void do_undo(void)
|
||
{
|
||
int wanna_update_toolbar;
|
||
|
||
wanna_update_toolbar = 0;
|
||
|
||
if (cur_undo != oldest_undo)
|
||
{
|
||
cur_undo--;
|
||
|
||
if (cur_undo < 0)
|
||
cur_undo = NUM_UNDO_BUFS - 1;
|
||
|
||
#ifdef DEBUG
|
||
printf("BLITTING: %d\n", cur_undo);
|
||
#endif
|
||
SDL_BlitSurface(undo_bufs[cur_undo], NULL, canvas, NULL);
|
||
|
||
|
||
if (img_starter != NULL)
|
||
{
|
||
if (undo_starters[cur_undo] == UNDO_STARTER_MIRRORED)
|
||
{
|
||
starter_mirrored = !starter_mirrored;
|
||
mirror_starter();
|
||
}
|
||
else if (undo_starters[cur_undo] == UNDO_STARTER_FLIPPED)
|
||
{
|
||
starter_flipped = !starter_flipped;
|
||
flip_starter();
|
||
}
|
||
}
|
||
|
||
update_canvas(0, 0, (WINDOW_WIDTH - 96), (48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
|
||
if (cur_undo == oldest_undo)
|
||
{
|
||
tool_avail[TOOL_UNDO] = 0;
|
||
wanna_update_toolbar = 1;
|
||
}
|
||
|
||
if (tool_avail[TOOL_REDO] == 0)
|
||
{
|
||
tool_avail[TOOL_REDO] = 1;
|
||
wanna_update_toolbar = 1;
|
||
}
|
||
|
||
if (wanna_update_toolbar)
|
||
{
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
|
||
been_saved = 0;
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf("UNDO: Current=%d Oldest=%d Newest=%d\n",
|
||
cur_undo, oldest_undo, newest_undo);
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Redo! */
|
||
|
||
static void do_redo(void)
|
||
{
|
||
if (cur_undo != newest_undo)
|
||
{
|
||
if (img_starter != NULL)
|
||
{
|
||
if (undo_starters[cur_undo] == UNDO_STARTER_MIRRORED)
|
||
{
|
||
starter_mirrored = !starter_mirrored;
|
||
mirror_starter();
|
||
}
|
||
else if (undo_starters[cur_undo] == UNDO_STARTER_FLIPPED)
|
||
{
|
||
starter_flipped = !starter_flipped;
|
||
flip_starter();
|
||
}
|
||
}
|
||
|
||
cur_undo = (cur_undo + 1) % NUM_UNDO_BUFS;
|
||
|
||
#ifdef DEBUG
|
||
printf("BLITTING: %d\n", cur_undo);
|
||
#endif
|
||
SDL_BlitSurface(undo_bufs[cur_undo], NULL, canvas, NULL);
|
||
|
||
update_canvas(0, 0, (WINDOW_WIDTH - 96), (48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
been_saved = 0;
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf("REDO: Current=%d Oldest=%d Newest=%d\n",
|
||
cur_undo, oldest_undo, newest_undo);
|
||
#endif
|
||
|
||
|
||
if (((cur_undo + 1) % NUM_UNDO_BUFS) == newest_undo)
|
||
{
|
||
tool_avail[TOOL_REDO] = 0;
|
||
}
|
||
|
||
tool_avail[TOOL_UNDO] = 1;
|
||
|
||
draw_toolbar();
|
||
SDL_UpdateRect(screen, 0, 0, 96, (48 * (7 + TOOLOFFSET / 2)) + 40);
|
||
}
|
||
|
||
|
||
/* Create the current brush in the current color: */
|
||
|
||
static void render_brush(void)
|
||
{
|
||
Uint32 amask;
|
||
int x, y;
|
||
Uint8 r, g, b, a;
|
||
|
||
|
||
/* Kludge; not sure why cur_brush would become greater! */
|
||
|
||
if (cur_brush >= num_brushes)
|
||
cur_brush = 0;
|
||
|
||
|
||
/* Free the old rendered brush (if any): */
|
||
|
||
if (img_cur_brush != NULL)
|
||
{
|
||
SDL_FreeSurface(img_cur_brush);
|
||
}
|
||
|
||
|
||
/* Create a surface to render into: */
|
||
|
||
amask = ~(img_brushes[cur_brush]->format->Rmask |
|
||
img_brushes[cur_brush]->format->Gmask |
|
||
img_brushes[cur_brush]->format->Bmask);
|
||
|
||
img_cur_brush =
|
||
SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||
img_brushes[cur_brush]->w,
|
||
img_brushes[cur_brush]->h,
|
||
img_brushes[cur_brush]->format->BitsPerPixel,
|
||
img_brushes[cur_brush]->format->Rmask,
|
||
img_brushes[cur_brush]->format->Gmask,
|
||
img_brushes[cur_brush]->format->Bmask,
|
||
amask);
|
||
|
||
if (img_cur_brush == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Can't render a brush!\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", SDL_GetError());
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
/* Render the new brush: */
|
||
|
||
SDL_LockSurface(img_brushes[cur_brush]);
|
||
SDL_LockSurface(img_cur_brush);
|
||
|
||
for (y = 0; y < img_brushes[cur_brush]->h; y++)
|
||
{
|
||
for (x = 0; x < img_brushes[cur_brush]->w; x++)
|
||
{
|
||
SDL_GetRGBA(getpixel(img_brushes[cur_brush], x, y),
|
||
img_brushes[cur_brush]->format,
|
||
&r, &g, &b, &a);
|
||
|
||
putpixel(img_cur_brush, x, y,
|
||
SDL_MapRGBA(img_cur_brush->format,
|
||
color_hexes[cur_color][0],
|
||
color_hexes[cur_color][1],
|
||
color_hexes[cur_color][2],
|
||
a));
|
||
}
|
||
}
|
||
|
||
SDL_UnlockSurface(img_cur_brush);
|
||
SDL_UnlockSurface(img_brushes[cur_brush]);
|
||
|
||
brush_counter = 0;
|
||
}
|
||
|
||
|
||
/* Play a sound: */
|
||
|
||
static void playsound(int chan, int s, int override)
|
||
{
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
if (override || !Mix_Playing(chan))
|
||
Mix_PlayChannel(chan, sounds[s], 0);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Draw a XOR line: */
|
||
|
||
static void line_xor(int x1, int y1, int x2, int y2)
|
||
{
|
||
int dx, dy, y, num_drawn;
|
||
float m, b;
|
||
|
||
|
||
/* Kludgey, but it works: */
|
||
|
||
//SDL_LockSurface(screen);
|
||
|
||
dx = x2 - x1;
|
||
dy = y2 - y1;
|
||
|
||
num_drawn = 0;
|
||
|
||
if (dx != 0)
|
||
{
|
||
m = ((float) dy) / ((float) dx);
|
||
b = y1 - m * x1;
|
||
|
||
if (x2 >= x1)
|
||
dx = 1;
|
||
else
|
||
dx = -1;
|
||
|
||
|
||
while (x1 != x2)
|
||
{
|
||
y1 = m * x1 + b;
|
||
y2 = m * (x1 + dx) + b;
|
||
|
||
if (y1 > y2)
|
||
{
|
||
y = y1;
|
||
y1 = y2;
|
||
y2 = y;
|
||
}
|
||
|
||
for (y = y1; y <= y2; y++)
|
||
{
|
||
num_drawn++;
|
||
if (num_drawn < 10 || dont_do_xor == 0)
|
||
{
|
||
clipped_putpixel(screen, x1 + 96, y,
|
||
0xFFFFFFFF - getpixel(screen, x1 + 96, y));
|
||
}
|
||
}
|
||
|
||
x1 = x1 + dx;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (y1 > y2)
|
||
{
|
||
for (y = y1; y >= y2; y--)
|
||
{
|
||
num_drawn++;
|
||
|
||
if (num_drawn < 10 || dont_do_xor == 0)
|
||
{
|
||
clipped_putpixel(screen, x1 + 96, y,
|
||
0xFFFFFFFF - getpixel(screen, x1 + 96, y));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (y = y1; y <= y2; y++)
|
||
{
|
||
num_drawn++;
|
||
|
||
if (num_drawn < 10 || dont_do_xor == 0)
|
||
{
|
||
clipped_putpixel(screen, x1 + 96, y,
|
||
0xFFFFFFFF - getpixel(screen, x1 + 96, y));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//SDL_UnlockSurface(screen);
|
||
}
|
||
|
||
|
||
/* Draw a XOR rectangle: */
|
||
|
||
static void rect_xor(int x1, int y1, int x2, int y2)
|
||
{
|
||
if (x1 < 0)
|
||
x1 = 0;
|
||
|
||
if (x2 < 0)
|
||
x2 = 0;
|
||
|
||
if (y1 < 0)
|
||
y1 = 0;
|
||
|
||
if (y2 < 0)
|
||
y2 = 0;
|
||
|
||
if (x1 >= (WINDOW_WIDTH - 96 - 96))
|
||
x1 = (WINDOW_WIDTH - 96 - 96) - 1;
|
||
|
||
if (x2 >= (WINDOW_WIDTH - 96 - 96))
|
||
x2 = (WINDOW_WIDTH - 96 - 96) - 1;
|
||
|
||
if (y1 >= (48 * 7) + 40 + HEIGHTOFFSET)
|
||
y1 = (48 * 7) + 40 + HEIGHTOFFSET - 1;
|
||
|
||
if (y2 >= (48 * 7) + 40 + HEIGHTOFFSET)
|
||
y2 = (48 * 7) + 40 + HEIGHTOFFSET - 1;
|
||
|
||
line_xor(x1, y1, x2, y1);
|
||
line_xor(x2, y1, x2, y2);
|
||
line_xor(x2, y2, x1, y2);
|
||
line_xor(x1, y2, x1, y1);
|
||
}
|
||
|
||
|
||
/* Erase at the cursor! */
|
||
|
||
static void do_eraser(int x, int y)
|
||
{
|
||
SDL_Rect dest;
|
||
int sz;
|
||
|
||
sz = (ERASER_MIN +
|
||
((NUM_ERASERS - 1 - cur_eraser) *
|
||
((ERASER_MAX - ERASER_MIN) / (NUM_ERASERS - 1))));
|
||
|
||
dest.x = x - (sz / 2);
|
||
dest.y = y - (sz / 2);
|
||
dest.w = sz;
|
||
dest.h = sz;
|
||
|
||
if (img_starter_bkgd == NULL)
|
||
{
|
||
SDL_FillRect(canvas, &dest,
|
||
SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
}
|
||
else
|
||
{
|
||
SDL_BlitSurface(img_starter_bkgd, &dest, canvas, &dest);
|
||
}
|
||
|
||
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
if (!Mix_Playing(0))
|
||
{
|
||
eraser_sound = (eraser_sound + 1) % 2;
|
||
|
||
playsound(0, SND_ERASER1 + eraser_sound, 0);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
update_canvas(x - sz / 2, y - sz / 2, x + sz / 2, y + sz / 2);
|
||
|
||
rect_xor(x - sz / 2, y - sz / 2,
|
||
x + sz / 2, y + sz / 2);
|
||
}
|
||
|
||
|
||
/* Reset available tools (for new image / starting out): */
|
||
|
||
static void reset_avail_tools(void)
|
||
{
|
||
int i;
|
||
int disallow_print = disable_print; /* set to 1 later if printer unavail */
|
||
|
||
for (i = 0; i < NUM_TOOLS; i++)
|
||
{
|
||
tool_avail[i] = 1;
|
||
}
|
||
|
||
|
||
/* Unavailable at the beginning of a new canvas: */
|
||
|
||
tool_avail[TOOL_UNDO] = 0;
|
||
tool_avail[TOOL_REDO] = 0;
|
||
tool_avail[TOOL_NEW] = 0;
|
||
|
||
if (been_saved)
|
||
tool_avail[TOOL_SAVE] = 0;
|
||
|
||
|
||
/* Unavailable in rare circumstances: */
|
||
|
||
if (num_stamps == 0)
|
||
tool_avail[TOOL_STAMP] = 0;
|
||
|
||
|
||
/* Disable quit? */
|
||
|
||
if (disable_quit)
|
||
tool_avail[TOOL_QUIT] = 0;
|
||
|
||
|
||
/* Disable save? */
|
||
|
||
if (disable_save)
|
||
tool_avail[TOOL_SAVE] = 0;
|
||
|
||
|
||
#ifdef WIN32
|
||
if(!IsPrinterAvailable()) disallow_print = 1;
|
||
#endif
|
||
|
||
#ifdef __BEOS__
|
||
if(!IsPrinterAvailable()) disallow_print = disable_print = 1;
|
||
#endif
|
||
|
||
|
||
/* Disable print? */
|
||
|
||
if (disallow_print)
|
||
tool_avail[TOOL_PRINT] = 0;
|
||
}
|
||
|
||
|
||
/* Save and disable available tools (for Open-Dialog) */
|
||
|
||
static void disable_avail_tools(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < NUM_TOOLS; i++)
|
||
{
|
||
tool_avail_bak[i] = tool_avail[i];
|
||
tool_avail[i]=0;
|
||
}
|
||
}
|
||
|
||
/* Restore and enable available tools (for End-Of-Open-Dialog) */
|
||
|
||
static void enable_avail_tools(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < NUM_TOOLS; i++)
|
||
{
|
||
tool_avail[i] = tool_avail_bak[i];
|
||
}
|
||
}
|
||
|
||
|
||
/* Update a rect. based on two x/y coords (not necessarly in order): */
|
||
|
||
static void update_screen(int x1, int y1, int x2, int y2)
|
||
{
|
||
int tmp;
|
||
|
||
if (x1 > x2)
|
||
{
|
||
tmp = x1;
|
||
x1 = x2;
|
||
x2 = tmp;
|
||
}
|
||
|
||
if (y1 > y2)
|
||
{
|
||
tmp = y1;
|
||
y1 = y2;
|
||
y2 = tmp;
|
||
}
|
||
|
||
x1 = x1 - 1;
|
||
x2 = x2 + 1;
|
||
y1 = y1 - 1;
|
||
y2 = y2 + 1;
|
||
|
||
|
||
if (x1 < 0)
|
||
x1 = 0;
|
||
if (x2 < 0)
|
||
x2 = 0;
|
||
if (y1 < 0)
|
||
y1 = 0;
|
||
if (y2 < 0)
|
||
y2 = 0;
|
||
|
||
if (x1 >= WINDOW_WIDTH)
|
||
x1 = WINDOW_WIDTH - 1;
|
||
if (x2 >= WINDOW_WIDTH)
|
||
x2 = WINDOW_WIDTH - 1;
|
||
if (y1 >= WINDOW_HEIGHT)
|
||
y1 = WINDOW_HEIGHT - 1;
|
||
if (y2 >= WINDOW_HEIGHT)
|
||
y2 = WINDOW_HEIGHT - 1;
|
||
|
||
SDL_UpdateRect(screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||
}
|
||
|
||
|
||
/* Build a color based on two colors and an alpha... */
|
||
|
||
static Uint8 alpha(Uint8 c1, Uint8 c2, Uint8 a)
|
||
{
|
||
Uint16 c, nc1, nc2, na;
|
||
|
||
na = a;
|
||
nc1 = c1;
|
||
nc2 = c2;
|
||
|
||
if (nc1 > 200)
|
||
nc1 = 200;
|
||
|
||
c = ((nc1 * na) / 255 + (nc2 * (255 - na)) / 255);
|
||
|
||
return (Uint8) c;
|
||
}
|
||
|
||
|
||
/* For qsort() call in loadarbitrary()... */
|
||
|
||
static int compare_strings(char * * s1, char * * s2)
|
||
{
|
||
return (strcmp(*s1, *s2));
|
||
}
|
||
|
||
|
||
/* For qsort() call in do_open()... */
|
||
|
||
static int compare_dirent2s(struct dirent2 * f1, struct dirent2 * f2)
|
||
{
|
||
#ifdef DEBUG
|
||
printf("compare_dirents: %s\t%s\n", f1->f.d_name, f2->f.d_name);
|
||
#endif
|
||
|
||
if (f1->place == f2->place)
|
||
return (strcmp(f1->f.d_name, f2->f.d_name));
|
||
else
|
||
return (f1->place - f2->place);
|
||
}
|
||
|
||
|
||
/* Draw tux's text on the screen: */
|
||
|
||
static void draw_tux_text(int which_tux, const char * const str,
|
||
int want_right_to_left)
|
||
{
|
||
SDL_Rect dest;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
|
||
|
||
/* Remove any text-changing timer if one is running: */
|
||
|
||
control_drawtext_timer(0, "");
|
||
|
||
|
||
/* Clear first: */
|
||
|
||
dest.x = 0;
|
||
dest.y = (48 * 7) + 40 + 48 + HEIGHTOFFSET;
|
||
dest.w = WINDOW_WIDTH;
|
||
dest.h = WINDOW_HEIGHT - ((48 * 7) + 40 + 48 + HEIGHTOFFSET);
|
||
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
|
||
|
||
/* Draw tux: */
|
||
|
||
dest.x = 0;
|
||
dest.y = WINDOW_HEIGHT - (img_tux[which_tux] -> h);
|
||
|
||
if (dest.y < ((48 * 7) + 40 + 48 + HEIGHTOFFSET))
|
||
dest.y = ((48 * 7) + 40 + 48 + HEIGHTOFFSET);
|
||
|
||
SDL_BlitSurface(img_tux[which_tux], NULL, screen, &dest);
|
||
|
||
|
||
wordwrap_text(str, black,
|
||
img_tux[which_tux] -> w + 5,
|
||
(48 * 7) + 40 + 48 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH,
|
||
want_right_to_left);
|
||
|
||
|
||
/* Update the display: */
|
||
|
||
SDL_UpdateRect(screen,
|
||
0, (48 * 7) + 40 + 48 + HEIGHTOFFSET,
|
||
WINDOW_WIDTH,
|
||
WINDOW_HEIGHT - ((48 * 7) + 40 + 48 + HEIGHTOFFSET));
|
||
}
|
||
|
||
|
||
static void wordwrap_text(const char * const str, SDL_Color color,
|
||
int left, int top, int right,
|
||
int want_right_to_left)
|
||
{
|
||
int x, y, j;
|
||
unsigned int i;
|
||
char substr[512];
|
||
unsigned char * locale_str;
|
||
char * tstr;
|
||
unsigned char utf8_char[5];
|
||
int len;
|
||
SDL_Surface * text;
|
||
SDL_Rect dest, src;
|
||
|
||
int utf8_str_len, last_text_height;
|
||
unsigned char utf8_str[512];
|
||
|
||
|
||
/* Cursor starting position: */
|
||
|
||
x = left;
|
||
y = top;
|
||
|
||
last_text_height = 0;
|
||
|
||
debug(str);
|
||
debug(gettext(str));
|
||
debug("...");
|
||
|
||
if (strcmp(str, "") != 0)
|
||
{
|
||
if (want_right_to_left == 0)
|
||
locale_str = strdup(gettext(str));
|
||
else
|
||
locale_str = strdup(textdir(gettext(str)));
|
||
|
||
|
||
/* For each UTF8 character: */
|
||
|
||
utf8_str_len = 0;
|
||
utf8_str[0] = '\0';
|
||
|
||
for (i = 0; i <= strlen(locale_str); i++)
|
||
{
|
||
if (locale_str[i] < 128)
|
||
{
|
||
utf8_str[utf8_str_len++] = locale_str[i];
|
||
utf8_str[utf8_str_len] = '\0';
|
||
|
||
|
||
/* Space? Blit the word! (Word-wrap if necessary) */
|
||
|
||
if (locale_str[i] == ' ' || locale_str[i] == '\0')
|
||
{
|
||
text = TTF_RenderUTF8_Blended(locale_font, utf8_str, color);
|
||
|
||
if (!text) continue; /* Didn't render anything... */
|
||
|
||
/* ----------- */
|
||
if (text->w > right - left)
|
||
{
|
||
/* Move left and down (if not already at left!) */
|
||
|
||
if (x > left)
|
||
{
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
anti_carriage_return(left, right, top, top + text->h, y + text->h,
|
||
x - left);
|
||
|
||
x = left;
|
||
y = y + text->h;
|
||
}
|
||
|
||
|
||
/* Junk the blitted word; it's too long! */
|
||
|
||
last_text_height = text->h;
|
||
SDL_FreeSurface(text);
|
||
|
||
|
||
/* For each UTF8 character: */
|
||
|
||
for (j = 0; j < utf8_str_len; j++)
|
||
{
|
||
/* How many bytes does this character need? */
|
||
|
||
if (utf8_str[j] < 128) /* 0xxx xxxx - 1 byte */
|
||
{
|
||
utf8_char[0] = utf8_str[j];
|
||
utf8_char[1] = '\0';
|
||
}
|
||
else if ((utf8_str[j] & 0xE0) == 0xC0) /* 110x xxxx - 2 bytes */
|
||
{
|
||
utf8_char[0] = utf8_str[j];
|
||
utf8_char[1] = utf8_str[j + 1];
|
||
utf8_char[2] = '\0';
|
||
j = j + 1;
|
||
}
|
||
else if ((utf8_str[j] & 0xF0) == 0xE0) /* 1110 xxxx - 3 bytes */
|
||
{
|
||
utf8_char[0] = utf8_str[j];
|
||
utf8_char[1] = utf8_str[j + 1];
|
||
utf8_char[2] = utf8_str[j + 2];
|
||
utf8_char[3] = '\0';
|
||
j = j + 2;
|
||
}
|
||
else /* 1111 0xxx - 4 bytes */
|
||
{
|
||
utf8_char[0] = utf8_str[j];
|
||
utf8_char[1] = utf8_str[j + 1];
|
||
utf8_char[2] = utf8_str[j + 2];
|
||
utf8_char[3] = utf8_str[j + 3];
|
||
utf8_char[4] = '\0';
|
||
j = j + 3;
|
||
}
|
||
|
||
|
||
if (utf8_char[0] != '\0')
|
||
{
|
||
text = TTF_RenderUTF8_Blended(locale_font, utf8_char, color);
|
||
if (text != NULL)
|
||
{
|
||
if (x + text->w > right)
|
||
{
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
anti_carriage_return(left, right, top, top + text->h,
|
||
y + text->h, x - left);
|
||
|
||
x = left;
|
||
y = y + text->h;
|
||
}
|
||
|
||
dest.x = x;
|
||
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
dest.y = top;
|
||
else
|
||
dest.y = y;
|
||
|
||
SDL_BlitSurface(text, NULL, screen, &dest);
|
||
|
||
last_text_height = text->h;
|
||
|
||
x = x + text->w;
|
||
|
||
SDL_FreeSurface(text);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Not too wide for one line... */
|
||
|
||
if (x + text->w > right)
|
||
{
|
||
/* This word needs to move down? */
|
||
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
anti_carriage_return(left, right, top, top + text->h, y + text->h,
|
||
x - left);
|
||
|
||
x = left;
|
||
y = y + text->h;
|
||
}
|
||
|
||
dest.x = x;
|
||
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
dest.y = top;
|
||
else
|
||
dest.y = y;
|
||
|
||
SDL_BlitSurface(text, NULL, screen, &dest);
|
||
|
||
last_text_height = text->h;
|
||
x = x + text->w;
|
||
|
||
SDL_FreeSurface(text);
|
||
}
|
||
|
||
|
||
utf8_str_len = 0;
|
||
utf8_str[0] = '\0';
|
||
}
|
||
}
|
||
else if ((locale_str[i] & 0xE0) == 0xC0)
|
||
{
|
||
utf8_str[utf8_str_len++] = locale_str[i];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 1];
|
||
utf8_str[utf8_str_len] = '\0';
|
||
i++;
|
||
}
|
||
else if ((locale_str[i] & 0xF0) == 0xE0)
|
||
{
|
||
utf8_str[utf8_str_len++] = locale_str[i];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 1];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 2];
|
||
utf8_str[utf8_str_len] = '\0';
|
||
i = i + 2;
|
||
}
|
||
else
|
||
{
|
||
utf8_str[utf8_str_len++] = locale_str[i];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 1];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 2];
|
||
utf8_str[utf8_str_len++] = locale_str[i + 3];
|
||
utf8_str[utf8_str_len] = '\0';
|
||
i = i + 3;
|
||
}
|
||
}
|
||
|
||
free(locale_str);
|
||
}
|
||
else if (strlen(str) != 0)
|
||
{
|
||
/* Truncate if too big! (sorry!) */
|
||
|
||
if (want_right_to_left == 0)
|
||
tstr = strdup(uppercase(gettext(str)));
|
||
else
|
||
tstr = strdup(uppercase(textdir(gettext(str))));
|
||
|
||
if (strlen(tstr) > sizeof(substr) - 1)
|
||
tstr[sizeof(substr) - 1] = '\0';
|
||
|
||
|
||
/* For each word... */
|
||
|
||
for (i = 0; i < strlen(tstr); i++)
|
||
{
|
||
/* Figure out the word... */
|
||
|
||
len = 0;
|
||
|
||
for (j = i; tstr[j] != ' ' && tstr[j] != '\0'; j++)
|
||
{
|
||
substr[len++] = tstr[j];
|
||
}
|
||
|
||
substr[len++] = ' ';
|
||
substr[len] = '\0';
|
||
|
||
|
||
/* Render the word for display... */
|
||
|
||
|
||
text = TTF_RenderUTF8_Blended(locale_font, substr, color);
|
||
|
||
|
||
/* If it won't fit on this line, move to the next! */
|
||
|
||
if (x + text->w > right) /* Correct? */
|
||
{
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
anti_carriage_return(left, right, top, top + text->h, y + text->h,
|
||
x - left);
|
||
|
||
x = left;
|
||
y = y + text->h;
|
||
}
|
||
|
||
|
||
/* Draw the word: */
|
||
|
||
dest.x = x;
|
||
|
||
if (need_right_to_left(language) && want_right_to_left)
|
||
dest.y = top;
|
||
else
|
||
dest.y = y;
|
||
|
||
SDL_BlitSurface(text, NULL, screen, &dest);
|
||
|
||
|
||
/* Move the cursor one word's worth: */
|
||
|
||
x = x + text->w;
|
||
|
||
|
||
/* Free the temp. surface: */
|
||
|
||
last_text_height = text->h;
|
||
SDL_FreeSurface(text);
|
||
|
||
|
||
/* Now on to the next word... */
|
||
|
||
i = j;
|
||
}
|
||
|
||
free(tstr);
|
||
}
|
||
|
||
|
||
/* Right-justify the final line of text, in right-to-left mode: */
|
||
|
||
if (need_right_to_left(language) && want_right_to_left && last_text_height > 0)
|
||
{
|
||
src.x = left;
|
||
src.y = top;
|
||
src.w = x - left;
|
||
src.h = last_text_height;
|
||
|
||
dest.x = right - src.w;
|
||
dest.y = top;
|
||
|
||
SDL_BlitSurface(screen, &src, screen, &dest);
|
||
|
||
dest.x = left;
|
||
dest.y = top;
|
||
dest.w = (right - left - src.w);
|
||
dest.h = last_text_height;
|
||
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
}
|
||
}
|
||
|
||
|
||
/* Load a file's sound: */
|
||
|
||
#ifndef NOSOUND
|
||
|
||
static Mix_Chunk * loadsound(const char * const fname)
|
||
{
|
||
char * snd_fname;
|
||
char tmp_str[64];
|
||
Mix_Chunk * tmp_snd;
|
||
|
||
|
||
debug(fname);
|
||
|
||
|
||
/* First, check for localized version of sound: */
|
||
|
||
snd_fname = malloc(strlen(fname) + strlen(lang_prefixes[language]) + 2);
|
||
|
||
strcpy(snd_fname, fname);
|
||
snprintf(tmp_str, sizeof(tmp_str), "_%s.wav", lang_prefixes[language]);
|
||
|
||
|
||
if (strstr(snd_fname, ".png") != NULL)
|
||
{
|
||
strcpy(strstr(snd_fname, ".png"), tmp_str);
|
||
debug(snd_fname);
|
||
|
||
tmp_snd = Mix_LoadWAV(snd_fname);
|
||
|
||
if (tmp_snd == NULL)
|
||
{
|
||
debug("...No local version of sound!");
|
||
|
||
/* Now, check for default sound: */
|
||
|
||
free(snd_fname);
|
||
|
||
snd_fname = strdup(fname);
|
||
|
||
if (strstr(snd_fname, ".png") != NULL)
|
||
{
|
||
strcpy(strstr(snd_fname, ".png"), ".wav");
|
||
debug(snd_fname);
|
||
tmp_snd = Mix_LoadWAV(snd_fname);
|
||
free(snd_fname);
|
||
|
||
if (tmp_snd == NULL)
|
||
{
|
||
debug("...No default version of sound!");
|
||
return NULL;
|
||
}
|
||
|
||
return (tmp_snd);
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
return (tmp_snd);
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* Strip any trailing spaces: */
|
||
|
||
static void strip_trailing_whitespace( char *buf )
|
||
{
|
||
unsigned i = strlen(buf);
|
||
while(i--)
|
||
{
|
||
if(!isspace(buf[i])) break;
|
||
buf[i] = '\0';
|
||
}
|
||
}
|
||
|
||
|
||
/* Load a file's description: */
|
||
|
||
static char * loaddesc(const char * const fname)
|
||
{
|
||
char * txt_fname;
|
||
char buf[256], def_buf[256];
|
||
int found, got_first;
|
||
FILE * fi;
|
||
|
||
|
||
txt_fname = strdup(fname);
|
||
|
||
if (strstr(txt_fname, ".png") != NULL)
|
||
{
|
||
strcpy(strstr(txt_fname, ".png"), ".txt");
|
||
|
||
fi = fopen(txt_fname, "r");
|
||
|
||
if (fi == NULL)
|
||
{
|
||
/*
|
||
fprintf(stderr, "\nWarning: Couldn't open a description file:\n");
|
||
perror(txt_fname);
|
||
fprintf(stderr, "\n");
|
||
*/
|
||
|
||
free(txt_fname);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
free(txt_fname);
|
||
|
||
got_first = 0;
|
||
found = 0;
|
||
|
||
strcpy(def_buf, "");
|
||
|
||
do
|
||
{
|
||
fgets(buf, sizeof(buf), fi);
|
||
|
||
if (!feof(fi))
|
||
{
|
||
strip_trailing_whitespace(buf);
|
||
|
||
|
||
if (!got_first)
|
||
{
|
||
/* First one is the default: */
|
||
|
||
strcpy(def_buf, buf);
|
||
got_first = 1;
|
||
}
|
||
|
||
|
||
debug(buf);
|
||
|
||
|
||
/* See if it's the one for this locale... */
|
||
|
||
if (strstr(buf, lang_prefixes[language]) == buf)
|
||
{
|
||
|
||
debug(buf + strlen(lang_prefixes[language]));
|
||
if (strstr(buf + strlen(lang_prefixes[language]), ".utf8=") ==
|
||
buf + strlen(lang_prefixes[language]))
|
||
{
|
||
found = 1;
|
||
|
||
debug("...FOUND!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
while (!feof(fi) && !found);
|
||
|
||
fclose(fi);
|
||
|
||
|
||
/* Return the string: */
|
||
|
||
if (found)
|
||
{
|
||
return(strdup(buf + (strlen(lang_prefixes[language])) + 6));
|
||
}
|
||
else
|
||
{
|
||
/* No locale-specific translation; use the default (English) */
|
||
|
||
return(strdup(def_buf));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
|
||
/* Load a file's info: */
|
||
|
||
static info_type * loadinfo(const char * const fname)
|
||
{
|
||
char * dat_fname;
|
||
char buf[256];
|
||
info_type inf;
|
||
info_type * inf_ret;
|
||
FILE * fi;
|
||
|
||
|
||
/* Clear info struct first: */
|
||
|
||
inf.ratio = 1.0;
|
||
inf.colorable = 0;
|
||
inf.tintable = 0;
|
||
inf.mirrorable = 1;
|
||
inf.tintgray = 1;
|
||
inf.flipable = 1;
|
||
inf.tinter = TINTER_NORMAL;
|
||
|
||
/* Load info! */
|
||
|
||
dat_fname = strdup(fname);
|
||
|
||
if (strstr(dat_fname, ".png") != NULL)
|
||
{
|
||
strcpy(strstr(dat_fname, ".png"), ".dat");
|
||
|
||
fi = fopen(dat_fname, "r");
|
||
|
||
if (fi == NULL)
|
||
{
|
||
/*
|
||
fprintf(stderr, "\nWarning: Couldn't open an info file:\n");
|
||
perror(txt_fname);
|
||
fprintf(stderr, "\n");
|
||
*/
|
||
|
||
free(dat_fname);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
free(dat_fname);
|
||
|
||
|
||
do
|
||
{
|
||
fgets(buf, sizeof(buf), fi);
|
||
|
||
if (!feof(fi))
|
||
{
|
||
strip_trailing_whitespace(buf);
|
||
|
||
if (strcmp(buf, "colorable") == 0)
|
||
inf.colorable = 1;
|
||
else if (strcmp(buf, "tintable") == 0)
|
||
inf.tintable = 1;
|
||
else if (!memcmp(buf, "scale", 5) && (isspace(buf[5]) || buf[5]=='='))
|
||
{
|
||
double tmp, tmp2;
|
||
char *cp = buf+6;
|
||
while (isspace(*cp) || *cp=='=')
|
||
cp++;
|
||
if (strchr(cp,'%'))
|
||
{
|
||
tmp = strtod(cp,NULL) / 100.0;
|
||
if (tmp > 0.0001 && tmp < 10000.0)
|
||
inf.ratio = tmp;
|
||
}
|
||
else if (strchr(cp,'/'))
|
||
{
|
||
tmp = strtod(cp,&cp);
|
||
while(*cp && !isdigit(*cp))
|
||
cp++;
|
||
tmp2 = strtod(cp,NULL);
|
||
if (tmp>0.0001 && tmp<10000.0 && tmp2>0.0001 && tmp2<10000.0 && tmp/tmp2>0.0001 && tmp/tmp2<10000.0)
|
||
inf.ratio = tmp/tmp2;
|
||
}
|
||
else if (strchr(cp,':'))
|
||
{
|
||
tmp = strtod(cp,&cp);
|
||
while(*cp && !isdigit(*cp))
|
||
cp++;
|
||
tmp2 = strtod(cp,NULL);
|
||
if (tmp>0.0001 && tmp<10000.0 && tmp2>0.0001 && tmp2<10000.0 && tmp2/tmp>0.0001 && tmp2/tmp<10000.0)
|
||
inf.ratio = tmp2/tmp;
|
||
}
|
||
else
|
||
{
|
||
tmp = strtod(cp,NULL);
|
||
if (tmp > 0.0001 && tmp < 10000.0)
|
||
inf.ratio = 1.0 / tmp;
|
||
}
|
||
}
|
||
else if (!memcmp(buf, "tinter", 6) && (isspace(buf[6]) || buf[6]=='='))
|
||
{
|
||
char *cp = buf+7;
|
||
while (isspace(*cp) || *cp=='=')
|
||
cp++;
|
||
if (!strcmp(cp,"anyhue"))
|
||
{
|
||
inf.tinter = TINTER_ANYHUE;
|
||
}
|
||
else if (!strcmp(cp,"narrow"))
|
||
{
|
||
inf.tinter = TINTER_NARROW;
|
||
}
|
||
else if (!strcmp(cp,"normal"))
|
||
{
|
||
inf.tinter = TINTER_NORMAL;
|
||
}
|
||
else if (!strcmp(cp,"vector"))
|
||
{
|
||
inf.tinter = TINTER_VECTOR;
|
||
}
|
||
else
|
||
{
|
||
debug(cp);
|
||
}
|
||
}
|
||
else if (strcmp(buf, "nomirror") == 0)
|
||
inf.mirrorable = 0;
|
||
else if (strcmp(buf, "notintgray") == 0)
|
||
inf.tintgray = 0;
|
||
else if (strcmp(buf, "noflip") == 0)
|
||
inf.flipable = 0;
|
||
}
|
||
}
|
||
while (!feof(fi));
|
||
|
||
fclose(fi);
|
||
|
||
|
||
/* Return the info: */
|
||
|
||
inf_ret = malloc(sizeof(info_type));
|
||
/* FIXME: Check for errors! */
|
||
|
||
memcpy(inf_ret, &inf, sizeof(info_type));
|
||
|
||
return(inf_ret);
|
||
}
|
||
else
|
||
{
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
|
||
/* Load a file's alternative image: */
|
||
|
||
static SDL_Surface * loadaltimage(const char * const fname)
|
||
{
|
||
char * alt_fname;
|
||
SDL_Surface * s;
|
||
|
||
|
||
s = NULL;
|
||
|
||
|
||
alt_fname = (char *) malloc(sizeof(char) *
|
||
(strlen(fname) + strlen("_mirror") + 1));
|
||
if (alt_fname != NULL)
|
||
{
|
||
strcpy(alt_fname, fname);
|
||
|
||
if (strstr(alt_fname, ".png") != NULL)
|
||
{
|
||
strcpy(strstr(alt_fname, ".png"), "_mirror.png");
|
||
|
||
s = do_loadimage(alt_fname, 0);
|
||
}
|
||
|
||
|
||
free(alt_fname);
|
||
}
|
||
|
||
return s;
|
||
}
|
||
|
||
|
||
/* Wait for a keypress or mouse click */
|
||
|
||
static void do_wait(void)
|
||
{
|
||
SDL_Event event;
|
||
int done, counter;
|
||
|
||
done = 0;
|
||
|
||
counter = 50; /* About 5 seconds */
|
||
|
||
do
|
||
{
|
||
while (mySDL_PollEvent(&event))
|
||
{
|
||
if (event.type == SDL_QUIT)
|
||
{
|
||
done = 1;
|
||
|
||
/* FIXME: Handle SDL_Quit better */
|
||
}
|
||
else if (event.type == SDL_ACTIVEEVENT)
|
||
{
|
||
handle_active(&event);
|
||
}
|
||
else if (event.type == SDL_KEYDOWN)
|
||
{
|
||
done = 1;
|
||
}
|
||
else if (event.type == SDL_MOUSEBUTTONDOWN &&
|
||
event.button.button >= 1 &&
|
||
event.button.button <= 3)
|
||
{
|
||
done = 1;
|
||
}
|
||
}
|
||
|
||
counter--;
|
||
SDL_Delay(100);
|
||
}
|
||
while (!done && counter > 0);
|
||
}
|
||
|
||
|
||
/* Load current (if any) image: */
|
||
|
||
static void load_current(void)
|
||
{
|
||
SDL_Surface * tmp;
|
||
char * fname;
|
||
char ftmp[1024];
|
||
FILE * fi;
|
||
SDL_Rect dest;
|
||
|
||
|
||
/* Determine the current picture's ID: */
|
||
|
||
fname = get_fname("current_id.txt");
|
||
|
||
fi = fopen(fname, "r");
|
||
if (fi == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Couldn't determine the current image's ID\n"
|
||
"%s\n"
|
||
"The system error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
file_id[0] = '\0';
|
||
starter_id[0] = '\0';
|
||
}
|
||
else
|
||
{
|
||
fgets(file_id, sizeof(file_id), fi);
|
||
if (strlen(file_id) > 0)
|
||
{
|
||
file_id[strlen(file_id) - 1] = '\0';
|
||
}
|
||
fclose(fi);
|
||
}
|
||
|
||
free(fname);
|
||
|
||
|
||
/* Load that image: */
|
||
|
||
if (file_id[0] != '\0')
|
||
{
|
||
snprintf(ftmp, sizeof(ftmp), "saved/%s%s", file_id, FNAME_EXTENSION);
|
||
|
||
fname = get_fname(ftmp);
|
||
|
||
#ifdef SAVE_AS_BMP
|
||
tmp = SDL_LoadBMP(fname);
|
||
#else
|
||
tmp = IMG_Load(fname);
|
||
#endif
|
||
|
||
if (tmp == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Couldn't load any current image.\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", fname, SDL_GetError());
|
||
|
||
file_id[0] = '\0';
|
||
starter_id[0] = '\0';
|
||
}
|
||
else
|
||
{
|
||
SDL_FillRect(canvas, NULL, SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
|
||
dest.x = (canvas->w - tmp->w) / 2;
|
||
dest.y = (canvas->h - tmp->h) / 2;
|
||
SDL_BlitSurface(tmp, NULL, canvas, &dest);
|
||
|
||
SDL_FreeSurface(tmp);
|
||
|
||
|
||
load_starter_id(file_id);
|
||
load_starter(starter_id);
|
||
|
||
if (starter_mirrored)
|
||
mirror_starter();
|
||
|
||
if (starter_flipped)
|
||
flip_starter();
|
||
|
||
tool_avail[TOOL_NEW] = 1;
|
||
}
|
||
|
||
free(fname);
|
||
}
|
||
}
|
||
|
||
|
||
/* Save the current image to disk: */
|
||
|
||
static void save_current(void)
|
||
{
|
||
char * fname;
|
||
int res;
|
||
FILE * fi;
|
||
|
||
|
||
fname = get_fname("");
|
||
|
||
res = mkdir(fname, 0755);
|
||
|
||
if (res != 0 && errno != EEXIST)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't create user data directory:\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
}
|
||
|
||
free(fname);
|
||
|
||
|
||
fname = get_fname("current_id.txt");
|
||
|
||
fi = fopen(fname, "w");
|
||
if (fi == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't keep track of current image.\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
}
|
||
else
|
||
{
|
||
fprintf(fi, "%s\n", file_id);
|
||
fclose(fi);
|
||
}
|
||
|
||
free(fname);
|
||
}
|
||
|
||
|
||
/* The filename for the current image: */
|
||
|
||
static char * get_fname(const char * const name)
|
||
{
|
||
char f[512];
|
||
const char * tux_settings_dir;
|
||
|
||
|
||
/* Where is the user's data directory?
|
||
This is where their saved files are stored,
|
||
local fonts, brushes and stamps can be found,
|
||
and where the "current_id.txt" file is saved */
|
||
|
||
#ifdef WIN32
|
||
/* Windows predefines "savedir" as "userdata", though it may get
|
||
overridden with "--savedir" option */
|
||
|
||
snprintf(f, sizeof(f), "%s/%s", savedir, name);
|
||
|
||
#elif __BEOS__
|
||
/* BeOS similarly predefines "savedir" as "./userdata"... */
|
||
|
||
if (*name == '\0')
|
||
strcpy(f, savedir);
|
||
else
|
||
snprintf(f, sizeof(f), "%s/%s", savedir, name);
|
||
#else
|
||
/* On Mac, Linux and other Unixes, it's in a place under our home dir.: */
|
||
|
||
|
||
#ifdef __APPLE__
|
||
/* Macintosh: It's under ~/Library/Application Support/TuxPaint */
|
||
|
||
tux_settings_dir = "Library/Application Support/TuxPaint";
|
||
#else
|
||
/* Linux & Unix: It's under ~/.tuxpaint */
|
||
|
||
tux_settings_dir = ".tuxpaint";
|
||
#endif
|
||
|
||
|
||
/* Put together home directory path + settings directory + filename... */
|
||
|
||
if (savedir == NULL)
|
||
{
|
||
/* Save directory not overridden: */
|
||
|
||
if (getenv("HOME") != NULL)
|
||
{
|
||
if (*name == '\0')
|
||
{
|
||
/* (Some mkdir()'s don't like trailing slashes) */
|
||
|
||
snprintf(f, sizeof(f), "%s/%s", getenv("HOME"), tux_settings_dir);
|
||
}
|
||
else
|
||
{
|
||
snprintf(f, sizeof(f), "%s/%s/%s",
|
||
getenv("HOME"), tux_settings_dir, name);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* WOAH! Don't know where HOME directory is! Last resort, use '.'! */
|
||
|
||
strcpy(f, name);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* User had overridden save directory with "--savedir" option: */
|
||
|
||
if (*name != '\0')
|
||
{
|
||
/* (Some mkdir()'s don't like trailing slashes) */
|
||
|
||
snprintf(f, sizeof(f), "%s/%s", savedir, name);
|
||
}
|
||
else
|
||
{
|
||
snprintf(f, sizeof(f), "%s", savedir);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
return strdup(f);
|
||
}
|
||
|
||
|
||
/* Prompt the user with a yes/no question: */
|
||
|
||
static int do_prompt(const char * const text, const char * const btn_yes, const char * const btn_no)
|
||
{
|
||
SDL_Event event;
|
||
SDL_Rect dest;
|
||
int done, ans, w;
|
||
SDL_Color black = {0, 0, 0, 0};
|
||
SDLKey key;
|
||
SDLKey key_y, key_n;
|
||
char keystr[200];
|
||
#ifndef NO_PROMPT_SHADOWS
|
||
int i;
|
||
SDL_Surface * alpha_surf;
|
||
#endif
|
||
|
||
|
||
/* FIXME: Move elsewhere! Or not?! */
|
||
|
||
strcpy(keystr, textdir(gettext("Yes")));
|
||
key_y = tolower(keystr[0]);
|
||
|
||
strcpy(keystr, textdir(gettext("No")));
|
||
key_n = tolower(keystr[0]);
|
||
|
||
|
||
do_setcursor(cursor_arrow);
|
||
|
||
|
||
/* Move cursor automatically if in keymouse mode: */
|
||
|
||
if (keymouse)
|
||
{
|
||
mouse_x = WINDOW_WIDTH / 2;
|
||
mouse_y = WINDOW_HEIGHT / 2;
|
||
SDL_WarpMouse(mouse_x, mouse_y);
|
||
}
|
||
|
||
|
||
/* Draw button box: */
|
||
|
||
playsound(0, SND_PROMPT, 1);
|
||
|
||
for (w = 0; w <= 96; w = w + 4)
|
||
{
|
||
dest.x = 160 + 96 - w + PROMPTOFFSETX;
|
||
dest.y = 94 + 96 - w + PROMPTOFFSETY;
|
||
dest.w = (320 - 96 * 2) + w * 2;
|
||
dest.h = w * 2;
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 0, 0, 0));
|
||
|
||
SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
|
||
SDL_Delay(10);
|
||
}
|
||
|
||
|
||
#ifndef NO_PROMPT_SHADOWS
|
||
alpha_surf = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
|
||
(320 - 96 * 2) + (w - 4) * 2,
|
||
(w - 4) * 2,
|
||
screen->format->BitsPerPixel,
|
||
screen->format->Rmask,
|
||
screen->format->Gmask,
|
||
screen->format->Bmask,
|
||
screen->format->Amask);
|
||
|
||
if (alpha_surf != NULL)
|
||
{
|
||
SDL_FillRect(alpha_surf, NULL, SDL_MapRGB(alpha_surf->format, 0, 0, 0));
|
||
SDL_SetAlpha(alpha_surf, SDL_SRCALPHA, 64);
|
||
|
||
for (i = 8; i > 0; i = i - 2)
|
||
{
|
||
dest.x = 160 + 96 - (w - 4) + i + PROMPTOFFSETX;
|
||
dest.y = 94 + 96 - (w - 4) + i + PROMPTOFFSETY;
|
||
dest.w = (320 - 96 * 2) + (w - 4) * 2;
|
||
dest.h = (w - 4) * 2;
|
||
|
||
SDL_BlitSurface(alpha_surf, NULL, screen, &dest);
|
||
}
|
||
|
||
SDL_FreeSurface(alpha_surf);
|
||
}
|
||
#endif
|
||
|
||
|
||
w = w - 6;
|
||
|
||
dest.x = 160 + 96 - w + PROMPTOFFSETX;
|
||
dest.y = 94 + 96 - w + PROMPTOFFSETY;
|
||
dest.w = (320 - 96 * 2) + w * 2;
|
||
dest.h = w * 2;
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
|
||
|
||
/* Draw the question: */
|
||
|
||
wordwrap_text(text, black,
|
||
166 + PROMPTOFFSETX, 100 + PROMPTOFFSETY, 475 + PROMPTOFFSETX,
|
||
1);
|
||
|
||
|
||
/* Draw yes button: */
|
||
|
||
dest.x = 166 + PROMPTOFFSETX;
|
||
dest.y = 178 + PROMPTOFFSETY;
|
||
SDL_BlitSurface(img_yes, NULL, screen, &dest);
|
||
|
||
|
||
/* (Bound to UTF8 domain, so always ask for UTF8 rendering!) */
|
||
|
||
wordwrap_text(btn_yes, black, 166 + PROMPTOFFSETX + 48 + 4,
|
||
183 + PROMPTOFFSETY, 475 + PROMPTOFFSETX, 1);
|
||
|
||
|
||
/* Draw no button: */
|
||
|
||
if (strlen(btn_no) != 0)
|
||
{
|
||
dest.x = 166 + PROMPTOFFSETX;
|
||
dest.y = 230 + PROMPTOFFSETY;
|
||
SDL_BlitSurface(img_no, NULL, screen, &dest);
|
||
|
||
wordwrap_text(btn_no, black,
|
||
166 + PROMPTOFFSETX + 48 + 4, 235 + PROMPTOFFSETY,
|
||
475 + PROMPTOFFSETX, 1);
|
||
}
|
||
|
||
|
||
/* Draw Tux, waiting... */
|
||
|
||
draw_tux_text(TUX_BORED, "", 0);
|
||
|
||
SDL_Flip(screen);
|
||
|
||
done = 0;
|
||
ans = 0;
|
||
|
||
do
|
||
{
|
||
mySDL_WaitEvent(&event);
|
||
|
||
if (event.type == SDL_QUIT)
|
||
{
|
||
ans = 0;
|
||
done = 1;
|
||
}
|
||
else if (event.type == SDL_ACTIVEEVENT)
|
||
{
|
||
handle_active(&event);
|
||
}
|
||
else if (event.type == SDL_KEYUP)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
|
||
handle_keymouse(key, SDL_KEYUP);
|
||
}
|
||
else if (event.type == SDL_KEYDOWN)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
|
||
handle_keymouse(key, SDL_KEYDOWN);
|
||
|
||
|
||
/* FIXME: Should use SDLK_{c} instead of '{c}'? How? */
|
||
|
||
if (key == key_y || key == SDLK_RETURN)
|
||
{
|
||
/* Y or ENTER - Yes! */
|
||
|
||
ans = 1;
|
||
done = 1;
|
||
}
|
||
else if (key == key_n || key == SDLK_ESCAPE)
|
||
{
|
||
/* N or ESCAPE - No! */
|
||
|
||
if (strlen(btn_no) != 0)
|
||
{
|
||
ans = 0;
|
||
done = 1;
|
||
}
|
||
else
|
||
{
|
||
if (key == SDLK_ESCAPE)
|
||
{
|
||
/* ESCAPE also simply dismisses if there's no Yes/No
|
||
choice: */
|
||
|
||
ans = 1;
|
||
done = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEBUTTONDOWN &&
|
||
event.button.button >= 1 &&
|
||
event.button.button <= 3)
|
||
{
|
||
if (event.button.x >= 166 + PROMPTOFFSETX &&
|
||
event.button.x < 166 + PROMPTOFFSETX + 48)
|
||
{
|
||
if (event.button.y >= 178 + PROMPTOFFSETY &&
|
||
event.button.y < 178 + PROMPTOFFSETY + 48)
|
||
{
|
||
ans = 1;
|
||
done = 1;
|
||
}
|
||
else if (strlen(btn_no) != 0 &&
|
||
event.button.y >= 230 + PROMPTOFFSETY &&
|
||
event.button.y < 230 + PROMPTOFFSETY + 48)
|
||
{
|
||
ans = 0;
|
||
done = 1;
|
||
}
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEMOTION)
|
||
{
|
||
if (event.button.x >= 166 + PROMPTOFFSETX &&
|
||
event.button.x < 166 + 48 + PROMPTOFFSETX &&
|
||
((event.button.y >= 178 + PROMPTOFFSETY &&
|
||
event.button.y < 178 + 48 + PROMPTOFFSETY) ||
|
||
(strlen(btn_no) != 0 &&
|
||
event.button.y >= 230 && event.button.y < 230 + 48)))
|
||
{
|
||
do_setcursor(cursor_hand);
|
||
}
|
||
else
|
||
{
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
}
|
||
while (!done);
|
||
|
||
|
||
/* FIXME: Sound effect! */
|
||
/* ... */
|
||
|
||
|
||
/* Erase question prompt: */
|
||
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96 - 96, 48 * 7 + 40 + HEIGHTOFFSET);
|
||
|
||
return ans;
|
||
}
|
||
|
||
|
||
/* Free memory and prepare to quit: */
|
||
|
||
static void cleanup(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < MAX_STAMPS; i++)
|
||
{
|
||
if (txt_stamps[i])
|
||
{
|
||
free(txt_stamps[i]);
|
||
txt_stamps[i] = NULL;
|
||
}
|
||
|
||
if (inf_stamps[i])
|
||
{
|
||
free(inf_stamps[i]);
|
||
inf_stamps[i] = NULL;
|
||
}
|
||
|
||
if (state_stamps[i])
|
||
{
|
||
free(state_stamps[i]);
|
||
state_stamps[i] = NULL;
|
||
}
|
||
}
|
||
|
||
free_surface_array( img_brushes, MAX_BRUSHES );
|
||
free_surface_array( img_stamps, MAX_STAMPS );
|
||
free_surface_array( img_stamps_premirror, MAX_STAMPS );
|
||
free_surface_array( img_tools, NUM_TOOLS );
|
||
free_surface_array( img_tool_names, NUM_TOOLS );
|
||
free_surface_array( img_title_names, NUM_TITLES );
|
||
free_surface_array( img_magics, NUM_MAGICS );
|
||
free_surface_array( img_magic_names, NUM_MAGICS );
|
||
free_surface_array( img_shapes, NUM_SHAPES );
|
||
free_surface_array( img_shape_names, NUM_SHAPES );
|
||
free_surface_array( img_tux, NUM_TIP_TUX );
|
||
|
||
free_surface( &img_openlabels_open );
|
||
free_surface( &img_openlabels_erase );
|
||
free_surface( &img_openlabels_back );
|
||
|
||
free_surface( &img_progress );
|
||
|
||
free_surface( &img_yes );
|
||
free_surface( &img_no );
|
||
|
||
free_surface( &img_title_on );
|
||
free_surface( &img_title_off );
|
||
free_surface( &img_title_large_on );
|
||
free_surface( &img_title_large_off );
|
||
|
||
free_surface( &img_open );
|
||
free_surface( &img_erase );
|
||
free_surface( &img_back );
|
||
|
||
free_surface( &img_btn_up );
|
||
free_surface( &img_btn_down );
|
||
free_surface( &img_btn_off );
|
||
|
||
free_surface( &img_cursor_up );
|
||
free_surface( &img_cursor_down );
|
||
|
||
free_surface( &img_cursor_starter_up );
|
||
free_surface( &img_cursor_starter_down );
|
||
|
||
free_surface( &img_scroll_up );
|
||
free_surface( &img_scroll_down );
|
||
free_surface( &img_scroll_up_off );
|
||
free_surface( &img_scroll_down_off );
|
||
|
||
free_surface( &img_paintcan );
|
||
|
||
free_surface( &img_sparkles );
|
||
|
||
free_surface_array( undo_bufs, NUM_UNDO_BUFS );
|
||
#ifndef LOW_QUALITY_COLOR_SELECTOR
|
||
free_surface_array( img_color_btns, NUM_COLORS );
|
||
#endif
|
||
free_surface_array( img_stamp_thumbs, MAX_STAMPS );
|
||
|
||
free_surface( &screen );
|
||
free_surface( &img_starter );
|
||
free_surface( &img_starter_bkgd );
|
||
free_surface( &canvas );
|
||
free_surface( &img_cur_brush );
|
||
|
||
if (font != NULL)
|
||
{
|
||
TTF_CloseFont(font);
|
||
font = NULL;
|
||
}
|
||
|
||
if (small_font != NULL)
|
||
{
|
||
TTF_CloseFont(small_font);
|
||
small_font = NULL;
|
||
}
|
||
|
||
if (large_font != NULL)
|
||
{
|
||
TTF_CloseFont(large_font);
|
||
large_font = NULL;
|
||
}
|
||
|
||
for (i = 0; i < MAX_FONTS; i++)
|
||
{
|
||
if (fonts[i])
|
||
{
|
||
TTF_CloseFont(fonts[i]);
|
||
fonts[i] = NULL;
|
||
}
|
||
}
|
||
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
for (i = 0; i < NUM_SOUNDS; i++)
|
||
{
|
||
if (sounds[i])
|
||
{
|
||
Mix_FreeChunk(sounds[i]);
|
||
sounds[i] = NULL;
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < num_stamps; i++)
|
||
{
|
||
if (snd_stamps[i])
|
||
{
|
||
Mix_FreeChunk(snd_stamps[i]);
|
||
snd_stamps[i] = NULL;
|
||
}
|
||
}
|
||
|
||
Mix_CloseAudio();
|
||
}
|
||
#endif
|
||
|
||
|
||
free_cursor(&cursor_hand);
|
||
free_cursor(&cursor_arrow);
|
||
free_cursor(&cursor_watch);
|
||
free_cursor(&cursor_up);
|
||
free_cursor(&cursor_down);
|
||
free_cursor(&cursor_tiny);
|
||
free_cursor(&cursor_crosshair);
|
||
free_cursor(&cursor_brush);
|
||
free_cursor(&cursor_wand);
|
||
free_cursor(&cursor_insertion);
|
||
free_cursor(&cursor_rotate);
|
||
|
||
|
||
/* (Just in case...) */
|
||
|
||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||
|
||
|
||
/* Close recording or playback file: */
|
||
|
||
if (demofi != NULL)
|
||
{
|
||
fclose(demofi);
|
||
}
|
||
|
||
|
||
/* Close up! */
|
||
|
||
TTF_Quit();
|
||
SDL_Quit();
|
||
|
||
}
|
||
|
||
|
||
static void free_cursor(SDL_Cursor ** cursor)
|
||
{
|
||
if (*cursor)
|
||
{
|
||
SDL_FreeCursor(*cursor);
|
||
*cursor = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
static void free_surface(SDL_Surface **surface_array)
|
||
{
|
||
if (*surface_array)
|
||
{
|
||
SDL_FreeSurface(*surface_array);
|
||
*surface_array = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
static void free_surface_array(SDL_Surface *surface_array[], int count)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < count; ++i)
|
||
{
|
||
free_surface(&surface_array[i]);
|
||
}
|
||
}
|
||
|
||
|
||
/* Update screen where shape is/was: */
|
||
|
||
// FIXME: unused
|
||
/*
|
||
static void update_shape(int cx, int ox1, int ox2, int cy, int oy1, int oy2, int fix)
|
||
{
|
||
int rx, ry;
|
||
|
||
rx = abs(ox1 - cx);
|
||
if (abs(ox2 - cx) > rx)
|
||
rx = abs(ox2 - cx);
|
||
|
||
ry = abs(oy1 - cy);
|
||
if (abs(oy2 - cy) > ry)
|
||
ry = abs(oy2 - cy);
|
||
|
||
if (fix)
|
||
{
|
||
if (ry > rx)
|
||
rx = ry;
|
||
else
|
||
ry = rx;
|
||
}
|
||
|
||
SDL_UpdateRect(screen, max((cx - rx), 0) + 96, max(cy - ry, 0),
|
||
min((cx + rx) + 96, screen->w),
|
||
min(cy + ry, screen->h));
|
||
}
|
||
*/
|
||
|
||
|
||
/* Draw a shape! */
|
||
|
||
static void do_shape(int cx, int cy, int ox, int oy, int rotn, int use_brush)
|
||
{
|
||
int side, angle_skip, init_ang, rx, ry, rmax, x1, y1, x2, y2, xp, yp,
|
||
old_brush, step;
|
||
float a1, a2, rotn_rad;
|
||
#ifdef SCAN_FILL
|
||
point_type pts[1024]; /* Careful! */
|
||
fpoint_type fpts_orig[1024], fpts_new[1024];
|
||
int i;
|
||
int num_pts;
|
||
#else
|
||
int xx;
|
||
#endif
|
||
|
||
|
||
/* Determine radius/shape of the shape to draw: */
|
||
|
||
old_brush = 0;
|
||
rx = ox - cx;
|
||
ry = oy - cy;
|
||
|
||
|
||
/* If the shape has a 1:1 ("locked") aspect ratio, use the larger radius: */
|
||
|
||
if (shape_locked[cur_shape])
|
||
{
|
||
if (rx > ry)
|
||
ry = rx;
|
||
else
|
||
rx = ry;
|
||
}
|
||
|
||
|
||
/* Is the shape tiny? Make it SOME size, first! */
|
||
|
||
if (rx < 15 && ry < 15)
|
||
{
|
||
rx = 15;
|
||
ry = 15;
|
||
}
|
||
|
||
|
||
/* Render a default brush: */
|
||
|
||
if (use_brush)
|
||
{
|
||
old_brush = cur_brush;
|
||
cur_brush = 0; /* Kludgy! */
|
||
render_brush();
|
||
}
|
||
|
||
|
||
/* Draw the shape: */
|
||
|
||
angle_skip = 360 / shape_sides[cur_shape];
|
||
|
||
init_ang = shape_init_ang[cur_shape];
|
||
|
||
|
||
#ifdef SCAN_FILL
|
||
num_pts = 0;
|
||
#endif
|
||
|
||
|
||
step = 1;
|
||
|
||
if (dont_do_xor && !use_brush)
|
||
{
|
||
/* If we're in light outline mode & not drawing the shape with the brush,
|
||
if it has lots of sides (like a circle), reduce the number of sides: */
|
||
|
||
if (shape_sides[cur_shape] > 5)
|
||
step = (shape_sides[cur_shape] / 8);
|
||
}
|
||
|
||
|
||
for (side = 0; side < shape_sides[cur_shape]; side = side + step)
|
||
{
|
||
a1 = (angle_skip * side + init_ang) * M_PI / 180;
|
||
a2 = (angle_skip * (side + 1) + init_ang) * M_PI / 180;
|
||
|
||
x1 = (int) (cos(a1) * rx);
|
||
y1 = (int) (-sin(a1) * ry);
|
||
|
||
x2 = (int) (cos(a2) * rx);
|
||
y2 = (int) (-sin(a2) * ry);
|
||
|
||
|
||
/* Rotate the line: */
|
||
|
||
if (rotn != 0)
|
||
{
|
||
rotn_rad = rotn * M_PI / 180;
|
||
|
||
xp = x1 * cos(rotn_rad) - y1 * sin(rotn_rad);
|
||
yp = x1 * sin(rotn_rad) + y1 * cos(rotn_rad);
|
||
|
||
x1 = xp;
|
||
y1 = yp;
|
||
|
||
xp = x2 * cos(rotn_rad) - y2 * sin(rotn_rad);
|
||
yp = x2 * sin(rotn_rad) + y2 * cos(rotn_rad);
|
||
|
||
x2 = xp;
|
||
y2 = yp;
|
||
}
|
||
|
||
|
||
/* Center the line around the center of the shape: */
|
||
|
||
x1 = x1 + cx;
|
||
y1 = y1 + cy;
|
||
x2 = x2 + cx;
|
||
y2 = y2 + cy;
|
||
|
||
|
||
/* Draw: */
|
||
|
||
if (!use_brush)
|
||
{
|
||
/* (XOR) */
|
||
|
||
line_xor(x1, y1, x2, y2);
|
||
}
|
||
else
|
||
{
|
||
/* Brush */
|
||
|
||
brush_draw(x1, y1, x2, y2, 0);
|
||
}
|
||
|
||
#ifdef SCAN_FILL
|
||
fpts_orig[num_pts].x = (float) x2;
|
||
fpts_orig[num_pts].y = (float) y2;
|
||
num_pts++;
|
||
#endif
|
||
}
|
||
|
||
|
||
if (use_brush && shape_filled[cur_shape])
|
||
{
|
||
#ifdef SCAN_FILL
|
||
/* FIXME: This is all broken!!! */
|
||
|
||
num_pts = clip_polygon(num_pts, fpts_orig, fpts_new);
|
||
|
||
for (i = 0; i < num_pts; i++)
|
||
{
|
||
pts[i].x = (int) (fpts_new[i].x);
|
||
pts[i].y = (int) (fpts_new[i].y);
|
||
}
|
||
|
||
scan_fill(num_pts, pts);
|
||
#else
|
||
/* FIXME: In the meantime, we'll do this lame radius-based fill: */
|
||
|
||
for (xx = abs(rx); xx >= 0; xx--)
|
||
{
|
||
for (side = 0; side < shape_sides[cur_shape]; side++)
|
||
{
|
||
a1 = (angle_skip * side + init_ang) * M_PI / 180;
|
||
a2 = (angle_skip * (side + 1) + init_ang) * M_PI / 180;
|
||
|
||
x1 = (int) (cos(a1) * xx);
|
||
y1 = (int) (-sin(a1) * ry);
|
||
|
||
x2 = (int) (cos(a2) * xx);
|
||
y2 = (int) (-sin(a2) * ry);
|
||
|
||
|
||
/* Rotate the line: */
|
||
|
||
if (rotn != 0)
|
||
{
|
||
rotn_rad = rotn * M_PI / 180;
|
||
|
||
xp = x1 * cos(rotn_rad) - y1 * sin(rotn_rad);
|
||
yp = x1 * sin(rotn_rad) + y1 * cos(rotn_rad);
|
||
|
||
x1 = xp;
|
||
y1 = yp;
|
||
|
||
xp = x2 * cos(rotn_rad) - y2 * sin(rotn_rad);
|
||
yp = x2 * sin(rotn_rad) + y2 * cos(rotn_rad);
|
||
|
||
x2 = xp;
|
||
y2 = yp;
|
||
}
|
||
|
||
|
||
/* Center the line around the center of the shape: */
|
||
|
||
x1 = x1 + cx;
|
||
y1 = y1 + cy;
|
||
x2 = x2 + cx;
|
||
y2 = y2 + cy;
|
||
|
||
|
||
/* Draw: */
|
||
|
||
brush_draw(x1, y1, x2, y2, 0);
|
||
}
|
||
|
||
if (xx % 10 == 0)
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Update it! */
|
||
|
||
if (use_brush)
|
||
{
|
||
if (abs(rx) > abs(ry))
|
||
rmax = abs(rx) + 20;
|
||
else
|
||
rmax = abs(ry) + 20;
|
||
|
||
update_canvas(cx - rmax, cy - rmax,
|
||
cx + rmax, cy + rmax);
|
||
}
|
||
|
||
|
||
/* Return to normal brush (for paint brush and line tools): */
|
||
|
||
if (use_brush)
|
||
{
|
||
cur_brush = old_brush;
|
||
render_brush();
|
||
}
|
||
}
|
||
|
||
|
||
/* What angle is the mouse away from the center of a shape? */
|
||
|
||
static int rotation(int ctr_x, int ctr_y, int ox, int oy)
|
||
{
|
||
return(atan2(oy - ctr_y, ox - ctr_x) * 180 / M_PI);
|
||
}
|
||
|
||
|
||
/* FIXME: Move elsewhere!!! */
|
||
|
||
#define PROMPT_SAVE_OVER_TXT gettext_noop("Save over the older version of this picture?")
|
||
#define PROMPT_SAVE_OVER_YES gettext_noop("Yes")
|
||
#define PROMPT_SAVE_OVER_NO gettext_noop("No, save a new file")
|
||
|
||
|
||
/* Save the current image: */
|
||
|
||
static int do_save(void)
|
||
{
|
||
int res;
|
||
char * fname;
|
||
char tmp[1024];
|
||
SDL_Surface * thm;
|
||
#ifndef SAVE_AS_BMP
|
||
FILE * fi;
|
||
#endif
|
||
|
||
|
||
/* Was saving completely disabled? */
|
||
|
||
if (disable_save)
|
||
return 0;
|
||
|
||
|
||
if (promptless_save == SAVE_OVER_NO)
|
||
{
|
||
/* Never save over - _always_ save a new file! */
|
||
|
||
get_new_file_id();
|
||
}
|
||
else if (promptless_save == SAVE_OVER_PROMPT)
|
||
{
|
||
/* Saving the same picture? */
|
||
|
||
if (file_id[0] != '\0')
|
||
{
|
||
/* We sure we want to do that? */
|
||
|
||
if (do_prompt(PROMPT_SAVE_OVER_TXT,
|
||
PROMPT_SAVE_OVER_YES,
|
||
PROMPT_SAVE_OVER_NO) == 0)
|
||
{
|
||
/* No - Let's save a new picture! */
|
||
|
||
get_new_file_id();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Saving a new picture: */
|
||
|
||
get_new_file_id();
|
||
}
|
||
}
|
||
else if (promptless_save == SAVE_OVER_ALWAYS)
|
||
{
|
||
if (file_id[0] == '\0')
|
||
get_new_file_id();
|
||
}
|
||
|
||
|
||
/* Make sure we have a ~/.tuxpaint directory: */
|
||
|
||
show_progress_bar();
|
||
do_setcursor(cursor_watch);
|
||
|
||
fname = get_fname("");
|
||
|
||
res = mkdir(fname, 0755);
|
||
|
||
if (res != 0 && errno != EEXIST)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't create user data directory:\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
|
||
fprintf(stderr,
|
||
"Cannot save the any pictures! SORRY!\n\n");
|
||
|
||
draw_tux_text(TUX_OOPS, SDL_GetError(), 0);
|
||
|
||
free(fname);
|
||
return 0;
|
||
}
|
||
free(fname);
|
||
|
||
show_progress_bar();
|
||
|
||
|
||
/* Make sure we have a ~/.tuxpaint/saved directory: */
|
||
|
||
fname = get_fname("saved");
|
||
|
||
res = mkdir(fname, 0755);
|
||
|
||
if (res != 0 && errno != EEXIST)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't create user data directory:\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
|
||
fprintf(stderr,
|
||
"Cannot save any pictures! SORRY!\n\n");
|
||
|
||
draw_tux_text(TUX_OOPS, SDL_GetError(), 0);
|
||
|
||
free(fname);
|
||
return 0;
|
||
}
|
||
free(fname);
|
||
|
||
show_progress_bar();
|
||
|
||
|
||
/* Make sure we have a ~/.tuxpaint/saved/.thumbs/ directory: */
|
||
|
||
fname = get_fname("saved/.thumbs");
|
||
|
||
res = mkdir(fname, 0755);
|
||
|
||
if (res != 0 && errno != EEXIST)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't create user data thumbnail directory:\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", fname, strerror(errno));
|
||
|
||
fprintf(stderr,
|
||
"Cannot save any pictures! SORRY!\n\n");
|
||
|
||
draw_tux_text(TUX_OOPS, SDL_GetError(), 0);
|
||
|
||
free(fname);
|
||
return 0;
|
||
}
|
||
free(fname);
|
||
|
||
show_progress_bar();
|
||
|
||
|
||
/* Save the file: */
|
||
|
||
snprintf(tmp, sizeof(tmp), "saved/%s%s", file_id, FNAME_EXTENSION);
|
||
fname = get_fname(tmp);
|
||
debug(fname);
|
||
|
||
#ifdef SAVE_AS_BMP
|
||
if (SDL_SaveBMP(canvas, fname))
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Couldn't save the current image!\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred was:\n"
|
||
"%s\n\n", fname, SDL_GetError());
|
||
|
||
draw_tux_text(TUX_OOPS, SDL_GetError(), 0);
|
||
|
||
free(fname);
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
/* Ta-Da! */
|
||
|
||
playsound(0, SND_SAVE, 1);
|
||
draw_tux_text(TUX_DEFAULT, tool_tips[TOOL_SAVE], 1);
|
||
}
|
||
#else
|
||
fi = fopen(fname, "wb");
|
||
if (fi == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Couldn't save the current image!\n"
|
||
"%s\n"
|
||
"The system error that occurred was:\n"
|
||
"%s\n\n",
|
||
fname, strerror(errno));
|
||
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
}
|
||
else
|
||
{
|
||
if (!do_png_save(fi, fname, canvas))
|
||
{
|
||
free(fname);
|
||
return 0;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
free(fname);
|
||
|
||
show_progress_bar();
|
||
|
||
|
||
/* Save thumbnail, too: */
|
||
|
||
/* (Was thumbnail in old directory, rather than under .thumbs?) */
|
||
|
||
snprintf(tmp, sizeof(tmp), "saved/%s-t%s", file_id, FNAME_EXTENSION);
|
||
fname = get_fname(tmp);
|
||
fi = fopen(fname, "r");
|
||
if (fi != NULL)
|
||
{
|
||
fclose(fi);
|
||
}
|
||
else
|
||
{
|
||
/* No old thumbnail! Save this image's thumbnail in the new place,
|
||
under ".thumbs" */
|
||
|
||
snprintf(tmp, sizeof(tmp), "saved/.thumbs/%s-t%s", file_id, FNAME_EXTENSION);
|
||
fname = get_fname(tmp);
|
||
}
|
||
|
||
debug(fname);
|
||
|
||
thm = thumbnail(canvas, THUMB_W - 20, THUMB_H - 20, 0);
|
||
|
||
fi = fopen(fname, "wb");
|
||
if (fi == NULL)
|
||
{
|
||
fprintf(stderr, "\nError: Couldn't save thumbnail of image!\n"
|
||
"%s\n"
|
||
"The system error that occurred was:\n"
|
||
"%s\n\n",
|
||
fname, strerror(errno));
|
||
}
|
||
else
|
||
{
|
||
do_png_save(fi, fname, thm);
|
||
}
|
||
SDL_FreeSurface(thm);
|
||
|
||
free(fname);
|
||
|
||
|
||
/* Write 'starter' info, if any: */
|
||
|
||
if (starter_id[0] != '\0')
|
||
{
|
||
snprintf(tmp, sizeof(tmp), "saved/%s.dat", file_id);
|
||
fname = get_fname(tmp);
|
||
fi = fopen(fname, "w");
|
||
if (fi != NULL)
|
||
{
|
||
fprintf(fi, "%s\n", starter_id);
|
||
fprintf(fi, "%d %d\n", starter_mirrored, starter_flipped);
|
||
fclose(fi);
|
||
}
|
||
|
||
free(fname);
|
||
}
|
||
|
||
|
||
/* All happy! */
|
||
|
||
playsound(0, SND_SAVE, 1);
|
||
draw_tux_text(TUX_DEFAULT, tool_tips[TOOL_SAVE], 1);
|
||
do_setcursor(cursor_arrow);
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
/* Actually save the PNG data to the file stream: */
|
||
|
||
static int do_png_save(FILE * fi, const char * const fname, SDL_Surface * surf)
|
||
{
|
||
png_structp png_ptr;
|
||
png_infop info_ptr;
|
||
png_text text_ptr[4];
|
||
unsigned char ** png_rows;
|
||
Uint8 r, g, b;
|
||
int x, y, count;
|
||
|
||
|
||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||
if (png_ptr == NULL)
|
||
{
|
||
fclose(fi);
|
||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
||
|
||
fprintf(stderr, "\nError: Couldn't save the image!\n%s\n\n", fname);
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
}
|
||
else
|
||
{
|
||
info_ptr = png_create_info_struct(png_ptr);
|
||
if (info_ptr == NULL)
|
||
{
|
||
fclose(fi);
|
||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
||
|
||
fprintf(stderr, "\nError: Couldn't save the image!\n%s\n\n", fname);
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
}
|
||
else
|
||
{
|
||
if (setjmp(png_jmpbuf(png_ptr)))
|
||
{
|
||
fclose(fi);
|
||
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
||
|
||
fprintf(stderr, "\nError: Couldn't save the image!\n%s\n\n", fname);
|
||
draw_tux_text(TUX_OOPS, strerror(errno), 0);
|
||
|
||
return 0;
|
||
}
|
||
else
|
||
{
|
||
png_init_io(png_ptr, fi);
|
||
|
||
info_ptr->width = surf->w;
|
||
info_ptr->height = surf->h;
|
||
info_ptr->bit_depth = 8;
|
||
info_ptr->color_type = PNG_COLOR_TYPE_RGB;
|
||
info_ptr->interlace_type = 1;
|
||
info_ptr->valid = 0;
|
||
|
||
|
||
/* Set headers */
|
||
|
||
count = 0;
|
||
|
||
/*
|
||
if (title != NULL && strlen(title) > 0)
|
||
{
|
||
text_ptr[count].key = "Title";
|
||
text_ptr[count].text = title;
|
||
text_ptr[count].compression = PNG_TEXT_COMPRESSION_NONE;
|
||
count++;
|
||
}
|
||
*/
|
||
|
||
text_ptr[count].key = (png_charp) "Software";
|
||
text_ptr[count].text =
|
||
(png_charp) "Tux Paint " VER_VERSION " (" VER_DATE ")";
|
||
text_ptr[count].compression = PNG_TEXT_COMPRESSION_NONE;
|
||
count++;
|
||
|
||
|
||
png_set_text(png_ptr, info_ptr, text_ptr, count);
|
||
|
||
png_write_info(png_ptr, info_ptr);
|
||
|
||
|
||
|
||
/* Save the picture: */
|
||
|
||
png_rows = malloc(sizeof(char *) * surf->h);
|
||
|
||
for (y = 0; y < surf->h; y++)
|
||
{
|
||
png_rows[y] = malloc(sizeof(char) * 3 * surf->w);
|
||
|
||
for (x = 0; x < surf->w; x++)
|
||
{
|
||
SDL_GetRGB(getpixel(surf, x, y), surf->format, &r, &g, &b);
|
||
|
||
png_rows[y][x * 3 + 0] = r;
|
||
png_rows[y][x * 3 + 1] = g;
|
||
png_rows[y][x * 3 + 2] = b;
|
||
}
|
||
}
|
||
|
||
png_write_image(png_ptr, png_rows);
|
||
|
||
for (y = 0; y < surf->h; y++)
|
||
free(png_rows[y]);
|
||
|
||
free(png_rows);
|
||
|
||
|
||
png_write_end(png_ptr, NULL);
|
||
|
||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||
fclose(fi);
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Pick a new file ID: */
|
||
|
||
static void get_new_file_id(void)
|
||
{
|
||
time_t t;
|
||
|
||
t = time(NULL);
|
||
|
||
strftime(file_id, sizeof(file_id), "%Y%m%d%H%M%S", localtime(&t));
|
||
debug(file_id);
|
||
|
||
|
||
/* FIXME: Show thumbnail and prompt for title: */
|
||
}
|
||
|
||
|
||
/* Handle quitting (and prompting to save, if necessary!) */
|
||
|
||
static int do_quit(void)
|
||
{
|
||
int done;
|
||
|
||
done = do_prompt(PROMPT_QUIT_TXT,
|
||
PROMPT_QUIT_YES,
|
||
PROMPT_QUIT_NO);
|
||
|
||
if (done && !been_saved && !disable_save)
|
||
{
|
||
if (do_prompt(PROMPT_QUIT_SAVE_TXT,
|
||
PROMPT_QUIT_SAVE_YES,
|
||
PROMPT_QUIT_SAVE_NO))
|
||
{
|
||
if (do_save())
|
||
{
|
||
do_prompt(tool_tips[TOOL_SAVE],
|
||
"OK",
|
||
"");
|
||
}
|
||
else
|
||
{
|
||
/* Couldn't save! Abort quit! */
|
||
|
||
done = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return(done);
|
||
}
|
||
|
||
|
||
/* Open a saved image: */
|
||
|
||
#define PLACE_STARTERS_DIR 0
|
||
#define PLACE_SAVED_DIR 1
|
||
#define NUM_PLACES_TO_LOOK 2
|
||
|
||
|
||
static int do_open(int want_new_tool)
|
||
{
|
||
SDL_Surface * img, * img1, * img2;
|
||
int things_alloced;
|
||
SDL_Surface * * thumbs = NULL;
|
||
DIR * d;
|
||
struct dirent * f;
|
||
struct dirent2 * fs;
|
||
int place;
|
||
char * dirname[NUM_PLACES_TO_LOOK];
|
||
char * rfname;
|
||
char * * d_names = NULL, * * d_exts = NULL;
|
||
int * d_places;
|
||
FILE * fi;
|
||
char fname[1024];
|
||
char * tmp_fname;
|
||
int num_files, i, done, update_list, want_erase, cur, which,
|
||
num_files_in_dirs, j, res;
|
||
SDL_Rect dest;
|
||
SDL_Event event;
|
||
SDLKey key;
|
||
Uint32 last_click_time;
|
||
int last_click_which, last_click_button;
|
||
int places_to_look;
|
||
|
||
|
||
|
||
do_setcursor(cursor_watch);
|
||
|
||
|
||
/* Allocate some space: */
|
||
|
||
things_alloced = 32;
|
||
|
||
fs = (struct dirent2 *) malloc(sizeof(struct dirent2) * things_alloced);
|
||
|
||
num_files = 0;
|
||
cur = 0;
|
||
which = 0;
|
||
num_files_in_dirs = 0;
|
||
|
||
|
||
/* Open directories of images: */
|
||
|
||
for (places_to_look = 0;
|
||
places_to_look < NUM_PLACES_TO_LOOK;
|
||
places_to_look++)
|
||
{
|
||
if (places_to_look == PLACE_STARTERS_DIR)
|
||
{
|
||
/* Check for coloring-book style 'starter' images first: */
|
||
|
||
dirname[places_to_look] = strdup(DATA_PREFIX "starters");
|
||
}
|
||
else
|
||
{
|
||
/* Then check for saved-images: */
|
||
|
||
dirname[places_to_look] = get_fname("saved");
|
||
}
|
||
|
||
|
||
/* Read directory of images and build thumbnails: */
|
||
|
||
d = opendir(dirname[places_to_look]);
|
||
|
||
if (d != NULL)
|
||
{
|
||
/* Gather list of files (for sorting): */
|
||
|
||
do
|
||
{
|
||
f = readdir(d);
|
||
|
||
if (f != NULL)
|
||
{
|
||
memcpy(&(fs[num_files_in_dirs].f), f, sizeof(struct dirent));
|
||
fs[num_files_in_dirs].place = places_to_look;
|
||
|
||
num_files_in_dirs++;
|
||
|
||
if (num_files_in_dirs >= things_alloced)
|
||
{
|
||
things_alloced = things_alloced + 32;
|
||
fs = (struct dirent2 *) realloc(fs,
|
||
sizeof(struct dirent2) *
|
||
things_alloced);
|
||
}
|
||
}
|
||
}
|
||
while (f != NULL);
|
||
|
||
closedir(d);
|
||
}
|
||
}
|
||
|
||
|
||
/* (Re)allocate space for the information about these files: */
|
||
|
||
thumbs = (SDL_Surface * *) malloc(sizeof(SDL_Surface *) *
|
||
num_files_in_dirs);
|
||
d_places = (int *) malloc(sizeof(int) * num_files_in_dirs);
|
||
d_names = (char * *) malloc(sizeof(char *) * num_files_in_dirs);
|
||
d_exts = (char * *) malloc(sizeof(char *) * num_files_in_dirs);
|
||
|
||
|
||
/* Sort: */
|
||
|
||
qsort(fs, num_files_in_dirs, sizeof(struct dirent2),
|
||
(int(*)(const void *, const void *))compare_dirent2s);
|
||
|
||
|
||
/* Read directory of images and build thumbnails: */
|
||
|
||
for (j = 0; j < num_files_in_dirs; j++)
|
||
{
|
||
f = &(fs[j].f);
|
||
place = fs[j].place;
|
||
|
||
show_progress_bar();
|
||
|
||
if (f != NULL)
|
||
{
|
||
debug(f->d_name);
|
||
|
||
if (strstr(f->d_name, "-t.") == NULL &&
|
||
strstr(f->d_name, "-back.") == NULL)
|
||
{
|
||
if (strstr(f->d_name, FNAME_EXTENSION) != NULL
|
||
#ifndef SAVE_AS_BMP
|
||
/* Support legacy BMP files for load: */
|
||
|
||
|| strstr(f->d_name, ".bmp") != NULL
|
||
#endif
|
||
)
|
||
{
|
||
strcpy(fname, f->d_name);
|
||
if (strstr(fname, FNAME_EXTENSION) != NULL)
|
||
{
|
||
strcpy(strstr(fname, FNAME_EXTENSION), "");
|
||
d_exts[num_files] = strdup(FNAME_EXTENSION);
|
||
}
|
||
|
||
#ifndef SAVE_AS_BMP
|
||
if (strstr(fname, ".bmp") != NULL)
|
||
{
|
||
strcpy(strstr(fname, ".bmp"), "");
|
||
d_exts[num_files] = strdup(".bmp");
|
||
}
|
||
#endif
|
||
|
||
d_names[num_files] = strdup(fname);
|
||
d_places[num_files] = place;
|
||
|
||
|
||
/* Is it the 'current' file we just loaded?
|
||
We'll make it the current selection! */
|
||
|
||
if (strcmp(d_names[num_files], file_id) == 0)
|
||
{
|
||
which = num_files;
|
||
cur = (which / 4) * 4;
|
||
|
||
/* Center the cursor (useful for when the last item is
|
||
selected first!) */
|
||
|
||
if (cur - 8 >= 0)
|
||
cur = cur - 8;
|
||
else if (cur - 4 >= 0)
|
||
cur = cur - 4;
|
||
}
|
||
|
||
|
||
/* Try to load thumbnail first: */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/.thumbs/%s-t.png",
|
||
dirname[d_places[num_files]], d_names[num_files]);
|
||
debug(fname);
|
||
img = IMG_Load(fname);
|
||
|
||
if (img == NULL)
|
||
{
|
||
/* No thumbnail in the new location ("saved/.thumbs"),
|
||
try the old locatin ("saved/"): */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s-t.png",
|
||
dirname[d_places[num_files]],
|
||
d_names[num_files]);
|
||
debug(fname);
|
||
|
||
img = IMG_Load(fname);
|
||
}
|
||
|
||
if (img != NULL)
|
||
{
|
||
/* Loaded the thumbnail from one or the other location */
|
||
show_progress_bar();
|
||
|
||
img1 = SDL_DisplayFormat(img);
|
||
SDL_FreeSurface(img);
|
||
|
||
// if too big, or too small in both dimensions, rescale it
|
||
// ( for now: using old thumbnail as source for high speed, low quality)
|
||
if (img1->w > THUMB_W-20 || img1->h > THUMB_H-20 || (img1->w < THUMB_W-20 && img1->h < THUMB_H-20) )
|
||
{
|
||
img2 = thumbnail(img1, THUMB_W - 20, THUMB_H - 20, 0);
|
||
SDL_FreeSurface(img1);
|
||
img1 = img2;
|
||
}
|
||
|
||
thumbs[num_files] = img1;
|
||
|
||
if (thumbs[num_files] == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Couldn't create a thumbnail of "
|
||
"saved image!\n"
|
||
"%s\n", fname);
|
||
}
|
||
|
||
num_files++;
|
||
}
|
||
else
|
||
{
|
||
/* No thumbnail - load original: */
|
||
/* (Make sure we have a .../saved/.thumbs/ directory:) */
|
||
|
||
tmp_fname = get_fname("saved/.thumbs");
|
||
|
||
res = mkdir(tmp_fname, 0755);
|
||
|
||
if (res != 0 && errno != EEXIST)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Can't create user data thumbnail directory:\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n", tmp_fname, strerror(errno));
|
||
}
|
||
|
||
free(tmp_fname);
|
||
|
||
|
||
img = NULL;
|
||
|
||
if (d_places[num_files] == PLACE_STARTERS_DIR)
|
||
{
|
||
/* Try to load a starter's background image, first!
|
||
If it exists, it should give a better idea of what the
|
||
starter looks like, compared to the overlay image... */
|
||
|
||
/* (Try JPEG first) */
|
||
snprintf(fname, sizeof(fname), "%s/%s-back.jpeg",
|
||
dirname[d_places[num_files]],
|
||
d_names[num_files]);
|
||
|
||
img = IMG_Load(fname);
|
||
|
||
|
||
if (img == NULL)
|
||
{
|
||
/* (Try PNG next) */
|
||
snprintf(fname, sizeof(fname), "%s/%s-back.png",
|
||
dirname[d_places[num_files]],
|
||
d_names[num_files]);
|
||
|
||
img = IMG_Load(fname);
|
||
}
|
||
}
|
||
|
||
|
||
if (img == NULL)
|
||
{
|
||
/* Didn't load a starter background (or didn't try!),
|
||
try loading the actual image... */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s",
|
||
dirname[d_places[num_files]], f->d_name);
|
||
debug(fname);
|
||
#ifdef SAVE_AS_BMP
|
||
img = SDL_LoadBMP(fname);
|
||
#else
|
||
img = IMG_Load(fname);
|
||
#endif
|
||
}
|
||
|
||
|
||
show_progress_bar();
|
||
|
||
if (img == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: I can't open one of the saved files!\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that "
|
||
"occurred was:\n"
|
||
"%s\n\n",
|
||
fname, SDL_GetError());
|
||
|
||
free(d_names[num_files]);
|
||
free(d_exts[num_files]);
|
||
}
|
||
else
|
||
{
|
||
/* Turn it into a thumbnail: */
|
||
|
||
img1 = SDL_DisplayFormat(img);
|
||
img2 = thumbnail(img1, THUMB_W - 20, THUMB_H - 20, 0);
|
||
SDL_FreeSurface(img1);
|
||
|
||
show_progress_bar();
|
||
|
||
thumbs[num_files] = SDL_DisplayFormat(img2);
|
||
SDL_FreeSurface(img2);
|
||
if (thumbs[num_files] == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Couldn't create a thumbnail of "
|
||
"saved image!\n"
|
||
"%s\n", fname);
|
||
}
|
||
|
||
SDL_FreeSurface(img);
|
||
|
||
show_progress_bar();
|
||
|
||
|
||
/* Let's save this thumbnail, so we don't have to
|
||
create it again next time 'Open' is called: */
|
||
|
||
if (d_places[num_files] == PLACE_SAVED_DIR)
|
||
{
|
||
debug("Saving thumbnail for this one!");
|
||
|
||
snprintf(fname, sizeof(fname), "%s/.thumbs/%s-t.png",
|
||
dirname[d_places[num_files]], d_names[num_files]);
|
||
|
||
fi = fopen(fname, "wb");
|
||
if (fi == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: Couldn't save thumbnail of "
|
||
"saved image!\n"
|
||
"%s\n"
|
||
"The error that occurred was:\n"
|
||
"%s\n\n",
|
||
fname, strerror(errno));
|
||
}
|
||
else
|
||
{
|
||
do_png_save(fi, fname, thumbs[num_files]);
|
||
}
|
||
|
||
show_progress_bar();
|
||
}
|
||
|
||
|
||
num_files++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* It was a thumbnail file ("...-t.png") or immutable scene starter's
|
||
overlay layer ("...-front.png") */
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
#ifdef DEBUG
|
||
printf("%d saved files were found!\n", num_files);
|
||
#endif
|
||
|
||
|
||
|
||
if (num_files == 0)
|
||
{
|
||
do_prompt(PROMPT_OPEN_NOFILES_TXT, PROMPT_OPEN_NOFILES_YES, "");
|
||
}
|
||
else
|
||
{
|
||
/* Let user choose an image: */
|
||
|
||
draw_tux_text(TUX_BORED,
|
||
textdir(gettext_noop("Choose the picture you want, "
|
||
"then click “Open”.")), 1);
|
||
|
||
/* NOTE: cur is now set above; if file_id'th file is found, it's
|
||
set to that file's index; otherwise, we default to '0' */
|
||
|
||
update_list = 1;
|
||
want_erase = 0;
|
||
|
||
done = 0;
|
||
|
||
last_click_which = -1;
|
||
last_click_time = 0;
|
||
last_click_button = -1;
|
||
|
||
|
||
do_setcursor(cursor_arrow);
|
||
|
||
|
||
do
|
||
{
|
||
/* Update screen: */
|
||
|
||
if (update_list)
|
||
{
|
||
/* Erase: */
|
||
|
||
dest.x = 96;
|
||
dest.y = 0;
|
||
dest.w = WINDOW_WIDTH - 96 - 96;
|
||
dest.h = 48 * 7 + 40 + HEIGHTOFFSET;
|
||
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format,
|
||
255, 255, 255));
|
||
|
||
|
||
/* Draw icons: */
|
||
|
||
for (i = cur; i < cur + 16 && i < num_files; i++)
|
||
{
|
||
/* Draw cursor: */
|
||
|
||
dest.x = THUMB_W * ((i - cur) % 4) + 96;
|
||
dest.y = THUMB_H * ((i - cur) / 4) + 24;
|
||
|
||
if (d_places[i] == PLACE_SAVED_DIR)
|
||
{
|
||
if (i == which)
|
||
{
|
||
SDL_BlitSurface(img_cursor_down, NULL, screen, &dest);
|
||
debug(d_names[i]);
|
||
}
|
||
else
|
||
SDL_BlitSurface(img_cursor_up, NULL, screen, &dest);
|
||
}
|
||
else
|
||
{
|
||
if (i == which)
|
||
{
|
||
SDL_BlitSurface(img_cursor_starter_down, NULL, screen, &dest);
|
||
debug(d_names[i]);
|
||
}
|
||
else
|
||
SDL_BlitSurface(img_cursor_starter_up, NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
|
||
dest.x = THUMB_W * ((i - cur) % 4) + 96 + 10 +
|
||
(THUMB_W - 20 - thumbs[i]->w) / 2;
|
||
dest.y = THUMB_H * ((i - cur) / 4) + 24 + 10 +
|
||
(THUMB_H - 20 - thumbs[i]->h) / 2;
|
||
|
||
if (thumbs[i] != NULL)
|
||
SDL_BlitSurface(thumbs[i], NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
/* Draw arrows: */
|
||
|
||
dest.x = (WINDOW_WIDTH - img_scroll_up->w) / 2;
|
||
dest.y = 0;
|
||
|
||
if (cur > 0)
|
||
SDL_BlitSurface(img_scroll_up, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_scroll_up_off, NULL, screen, &dest);
|
||
|
||
dest.x = (WINDOW_WIDTH - img_scroll_up->w) / 2;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||
|
||
if (cur < num_files - 16)
|
||
SDL_BlitSurface(img_scroll_down, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_scroll_down_off, NULL, screen, &dest);
|
||
|
||
|
||
/* "Open" button: */
|
||
|
||
dest.x = 96;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||
SDL_BlitSurface(img_open, NULL, screen, &dest);
|
||
|
||
dest.x = 96 + (48 - img_openlabels_open->w) / 2;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - img_openlabels_open->h;
|
||
SDL_BlitSurface(img_openlabels_open, NULL, screen, &dest);
|
||
|
||
|
||
/* "Back" button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 96 - 48;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||
SDL_BlitSurface(img_back, NULL, screen, &dest);
|
||
|
||
dest.x = WINDOW_WIDTH - 96 - 48 + (48 - img_openlabels_back->w) / 2;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - img_openlabels_back->h;
|
||
SDL_BlitSurface(img_openlabels_back, NULL, screen, &dest);
|
||
|
||
|
||
/* "Erase" button: */
|
||
|
||
dest.x = WINDOW_WIDTH - 96 - 48 - 48;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - 48;
|
||
|
||
if (d_places[which] != PLACE_STARTERS_DIR)
|
||
SDL_BlitSurface(img_erase, NULL, screen, &dest);
|
||
else
|
||
SDL_BlitSurface(img_btn_off, NULL, screen, &dest);
|
||
|
||
dest.x = WINDOW_WIDTH - 96 - 48 - 48 + (48 - img_openlabels_erase->w) / 2;
|
||
dest.y = (48 * 7 + 40 + HEIGHTOFFSET) - img_openlabels_erase->h;
|
||
SDL_BlitSurface(img_openlabels_erase, NULL, screen, &dest);
|
||
|
||
|
||
SDL_Flip(screen);
|
||
|
||
update_list = 0;
|
||
}
|
||
|
||
|
||
mySDL_WaitEvent(&event);
|
||
|
||
if (event.type == SDL_QUIT)
|
||
{
|
||
done = 1;
|
||
|
||
/* FIXME: Handle SDL_Quit better */
|
||
}
|
||
else if (event.type == SDL_ACTIVEEVENT)
|
||
{
|
||
handle_active(&event);
|
||
}
|
||
else if (event.type == SDL_KEYUP)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
|
||
handle_keymouse(key, SDL_KEYUP);
|
||
}
|
||
else if (event.type == SDL_KEYDOWN)
|
||
{
|
||
key = event.key.keysym.sym;
|
||
|
||
handle_keymouse(key, SDL_KEYDOWN);
|
||
|
||
if (key == SDLK_LEFT)
|
||
{
|
||
if (which > 0)
|
||
{
|
||
which--;
|
||
|
||
if (which < cur)
|
||
cur = cur - 4;
|
||
|
||
update_list = 1;
|
||
}
|
||
}
|
||
else if (key == SDLK_RIGHT)
|
||
{
|
||
if (which < num_files - 1)
|
||
{
|
||
which++;
|
||
|
||
if (which >= cur + 16)
|
||
cur = cur + 4;
|
||
|
||
update_list = 1;
|
||
}
|
||
}
|
||
else if (key == SDLK_UP)
|
||
{
|
||
if (which >= 0)
|
||
{
|
||
which = which - 4;
|
||
|
||
if (which < 0)
|
||
which = 0;
|
||
|
||
if (which < cur)
|
||
cur = cur - 4;
|
||
|
||
update_list = 1;
|
||
}
|
||
}
|
||
else if (key == SDLK_DOWN)
|
||
{
|
||
if (which < num_files)
|
||
{
|
||
which = which + 4;
|
||
|
||
if (which >= num_files)
|
||
which = num_files - 1;
|
||
|
||
if (which >= cur + 16)
|
||
cur = cur + 4;
|
||
|
||
update_list = 1;
|
||
}
|
||
}
|
||
else if (key == SDLK_RETURN || key == SDLK_SPACE)
|
||
{
|
||
/* Open */
|
||
|
||
done = 1;
|
||
playsound(1, SND_CLICK, 1);
|
||
}
|
||
else if (key == SDLK_ESCAPE)
|
||
{
|
||
/* Go back: */
|
||
|
||
which = -1;
|
||
done = 1;
|
||
playsound(1, SND_CLICK, 1);
|
||
}
|
||
else if (key == SDLK_d &&
|
||
(event.key.keysym.mod & KMOD_CTRL ||
|
||
event.key.keysym.mod & KMOD_LCTRL ||
|
||
event.key.keysym.mod & KMOD_RCTRL) &&
|
||
d_places[which] != PLACE_STARTERS_DIR &&
|
||
!noshortcuts)
|
||
{
|
||
/* Delete! */
|
||
|
||
want_erase = 1;
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEBUTTONDOWN &&
|
||
event.button.button >= 1 &&
|
||
event.button.button <= 3)
|
||
{
|
||
if (event.button.x >= 96 && event.button.x < WINDOW_WIDTH - 96 &&
|
||
event.button.y >= 24 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET - 48))
|
||
{
|
||
/* Picked an icon! */
|
||
|
||
which = ((event.button.x - 96) / (THUMB_W) +
|
||
(((event.button.y - 24) / THUMB_H) * 4)) + cur;
|
||
|
||
if (which < num_files)
|
||
{
|
||
playsound(1, SND_BLEEP, 1);
|
||
update_list = 1;
|
||
|
||
|
||
if (which == last_click_which &&
|
||
SDL_GetTicks() < last_click_time + 1000 &&
|
||
event.button.button == last_click_button)
|
||
{
|
||
/* Double-click! */
|
||
|
||
done = 1;
|
||
}
|
||
|
||
last_click_which = which;
|
||
last_click_time = SDL_GetTicks();
|
||
last_click_button = event.button.button;
|
||
}
|
||
}
|
||
else if (event.button.x >= (WINDOW_WIDTH - img_scroll_up->w) / 2 &&
|
||
event.button.x <= (WINDOW_WIDTH + img_scroll_up->w) / 2)
|
||
{
|
||
if (event.button.y < 24)
|
||
{
|
||
/* Up scroll button: */
|
||
|
||
if (cur > 0)
|
||
{
|
||
cur = cur - 4;
|
||
update_list = 1;
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (cur == 0)
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
|
||
if (which > cur + 16)
|
||
which = which - 4;
|
||
}
|
||
else if (event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET - 48) &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET - 24))
|
||
{
|
||
/* Down scroll button: */
|
||
|
||
if (cur < num_files - 16)
|
||
{
|
||
cur = cur + 4;
|
||
update_list = 1;
|
||
playsound(1, SND_SCROLL, 1);
|
||
|
||
if (cur >= num_files - 16)
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
|
||
if (which < cur)
|
||
which = which + 4;
|
||
}
|
||
}
|
||
else if (event.button.x >= 96 && event.button.x < 96 + 48 &&
|
||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||
{
|
||
/* Open */
|
||
|
||
done = 1;
|
||
playsound(1, SND_CLICK, 1);
|
||
}
|
||
else if (event.button.x >= (WINDOW_WIDTH - 96 - 48) &&
|
||
event.button.x < (WINDOW_WIDTH - 96) &&
|
||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||
{
|
||
/* Back */
|
||
|
||
which = -1;
|
||
done = 1;
|
||
playsound(1, SND_CLICK, 1);
|
||
}
|
||
else if (event.button.x >= (WINDOW_WIDTH - 96 - 48 - 48) &&
|
||
event.button.x < (WINDOW_WIDTH - 48 - 96) &&
|
||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET) &&
|
||
d_places[which] != PLACE_STARTERS_DIR)
|
||
{
|
||
/* Erase */
|
||
|
||
want_erase = 1;
|
||
}
|
||
}
|
||
else if (event.type == SDL_MOUSEMOTION)
|
||
{
|
||
/* Deal with mouse pointer shape! */
|
||
|
||
if (event.button.y < 24 &&
|
||
event.button.x >= (WINDOW_WIDTH - img_scroll_up->w) / 2 &&
|
||
event.button.x <= (WINDOW_WIDTH + img_scroll_up->w) / 2 &&
|
||
cur > 0)
|
||
{
|
||
/* Scroll up button: */
|
||
|
||
do_setcursor(cursor_up);
|
||
}
|
||
else if (event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET - 48) &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET - 24) &&
|
||
event.button.x >= (WINDOW_WIDTH - img_scroll_up->w) / 2 &&
|
||
event.button.x <= (WINDOW_WIDTH + img_scroll_up->w) / 2 &&
|
||
cur < num_files - 16)
|
||
{
|
||
/* Scroll down button: */
|
||
|
||
do_setcursor(cursor_down);
|
||
}
|
||
else if (((event.button.x >= 96 && event.button.x < 96 + 48) ||
|
||
(event.button.x >= (WINDOW_WIDTH - 96 - 48) &&
|
||
event.button.x < (WINDOW_WIDTH - 96)) ||
|
||
(event.button.x >= (WINDOW_WIDTH - 96 - 48 - 48) &&
|
||
event.button.x < (WINDOW_WIDTH - 48 - 96) &&
|
||
d_places[which] != PLACE_STARTERS_DIR)) &&
|
||
event.button.y >= (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET))
|
||
{
|
||
/* One of the command buttons: */
|
||
|
||
do_setcursor(cursor_hand);
|
||
}
|
||
else if (event.button.x >= 96 && event.button.x < WINDOW_WIDTH - 96 &&
|
||
event.button.y > 24 &&
|
||
event.button.y < (48 * 7 + 40 + HEIGHTOFFSET) - 48 &&
|
||
((((event.button.x - 96) / (THUMB_W) +
|
||
(((event.button.y - 24) / THUMB_H) * 4)) +
|
||
cur) < num_files))
|
||
{
|
||
/* One of the thumbnails: */
|
||
|
||
do_setcursor(cursor_hand);
|
||
}
|
||
else
|
||
{
|
||
/* Unclickable... */
|
||
|
||
do_setcursor(cursor_arrow);
|
||
}
|
||
}
|
||
|
||
|
||
if (want_erase)
|
||
{
|
||
want_erase = 0;
|
||
|
||
if (do_prompt(PROMPT_ERASE_TXT,
|
||
PROMPT_ERASE_YES, PROMPT_ERASE_NO))
|
||
{
|
||
snprintf(fname, sizeof(fname), "saved/%s%s",
|
||
d_names[which], d_exts[which]);
|
||
|
||
rfname = get_fname(fname);
|
||
debug(rfname);
|
||
|
||
if (unlink(rfname) == 0)
|
||
{
|
||
thumbs[which] = NULL;
|
||
update_list = 1;
|
||
|
||
|
||
/* Delete the thumbnail, too: */
|
||
|
||
snprintf(fname, sizeof(fname),
|
||
"saved/.thumbs/%s-t.png",
|
||
d_names[which]);
|
||
|
||
free(rfname);
|
||
rfname = get_fname(fname);
|
||
debug(rfname);
|
||
|
||
unlink(rfname);
|
||
|
||
|
||
/* Try deleting old-style thumbnail, too: */
|
||
|
||
unlink(rfname);
|
||
snprintf(fname, sizeof(fname), "saved/%s-t.png",
|
||
d_names[which]);
|
||
|
||
free(rfname);
|
||
rfname = get_fname(fname);
|
||
debug(rfname);
|
||
|
||
unlink(rfname);
|
||
|
||
|
||
/* Delete .dat file, if any: */
|
||
|
||
unlink(rfname);
|
||
snprintf(fname, sizeof(fname), "saved/%s.dat",
|
||
d_names[which]);
|
||
|
||
free(rfname);
|
||
rfname = get_fname(fname);
|
||
debug(rfname);
|
||
|
||
unlink(rfname);
|
||
|
||
|
||
/* Move all other files up a notch: */
|
||
|
||
free(d_names[which]);
|
||
free(d_exts[which]);
|
||
free_surface(&thumbs[which]);
|
||
|
||
for (i = which; i < num_files - 1; i++)
|
||
{
|
||
d_names[i] = d_names[i + 1];
|
||
d_exts[i] = d_exts[i + 1];
|
||
thumbs[i] = thumbs[i + 1];
|
||
d_places[i] = d_places[i + 1];
|
||
}
|
||
|
||
num_files--;
|
||
|
||
|
||
/* Make sure the cursor doesn't go off the end! */
|
||
|
||
if (which >= num_files)
|
||
which = num_files - 1;
|
||
|
||
|
||
/* Scroll up if the cursor goes off top of screen! */
|
||
|
||
if (which < cur && cur >= 4)
|
||
{
|
||
cur = cur - 4;
|
||
update_list = 1;
|
||
}
|
||
|
||
|
||
/* No files to open now? */
|
||
|
||
if (which < 0)
|
||
{
|
||
do_prompt(PROMPT_OPEN_NOFILES_TXT,
|
||
PROMPT_OPEN_NOFILES_YES, "");
|
||
done = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
perror(rfname);
|
||
|
||
do_prompt("CAN'T", "OK", "");
|
||
update_list = 1;
|
||
}
|
||
|
||
free(rfname);
|
||
}
|
||
else
|
||
{
|
||
update_list = 1;
|
||
}
|
||
}
|
||
|
||
}
|
||
while (!done);
|
||
|
||
|
||
/* Load the chosen picture: */
|
||
|
||
if (which != -1)
|
||
{
|
||
/* Save old one first? */
|
||
|
||
if (!been_saved && !disable_save)
|
||
{
|
||
if (do_prompt(PROMPT_OPEN_SAVE_TXT,
|
||
PROMPT_OPEN_SAVE_YES,
|
||
PROMPT_OPEN_SAVE_NO))
|
||
{
|
||
do_save();
|
||
}
|
||
}
|
||
|
||
|
||
/* Figure out filename: */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s%s",
|
||
dirname[d_places[which]],
|
||
d_names[which], d_exts[which]);
|
||
|
||
#ifdef SAVE_AS_BMP
|
||
img = SDL_LoadBMP(fname);
|
||
#else
|
||
img = IMG_Load(fname);
|
||
#endif
|
||
|
||
if (img == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Couldn't load the saved image!\n"
|
||
"%s\n"
|
||
"The Simple DirectMedia Layer error that occurred "
|
||
"was:\n"
|
||
"%s\n\n", fname, SDL_GetError());
|
||
|
||
do_prompt(PROMPT_OPEN_UNOPENABLE_TXT,
|
||
PROMPT_OPEN_UNOPENABLE_YES, "");
|
||
}
|
||
else
|
||
{
|
||
free_surface(&img_starter);
|
||
free_surface(&img_starter_bkgd);
|
||
starter_mirrored = 0;
|
||
starter_flipped = 0;
|
||
|
||
SDL_FillRect(canvas, NULL,
|
||
SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
|
||
/* FIXME: What to do when in 640x480 mode, and loading an
|
||
800x600 (or larger) image!? */
|
||
|
||
dest.x = (canvas->w - img->w) / 2;
|
||
dest.y = (canvas->h - img->h) / 2;
|
||
|
||
SDL_BlitSurface(img, NULL, canvas, &dest);
|
||
SDL_FreeSurface(img);
|
||
|
||
|
||
cur_undo = 0;
|
||
oldest_undo = 0;
|
||
newest_undo = 0;
|
||
|
||
if (d_places[which] == PLACE_SAVED_DIR)
|
||
{
|
||
/* Saved image: */
|
||
|
||
been_saved = 1;
|
||
|
||
strcpy(file_id, d_names[which]);
|
||
starter_id[0] = '\0';
|
||
|
||
|
||
/* See if this saved image was based on a 'starter' */
|
||
|
||
load_starter_id(d_names[which]);
|
||
|
||
if (starter_id[0] != '\0')
|
||
{
|
||
load_starter(starter_id);
|
||
|
||
if (starter_mirrored)
|
||
mirror_starter();
|
||
|
||
if (starter_flipped)
|
||
flip_starter();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* Immutable 'starter' image;
|
||
we'll need to save a new image when saving...: */
|
||
|
||
been_saved = 1;
|
||
|
||
file_id[0] = '\0';
|
||
strcpy(starter_id, d_names[which]);
|
||
load_starter(starter_id);
|
||
|
||
SDL_BlitSurface(img_starter_bkgd, NULL, canvas, NULL);
|
||
SDL_BlitSurface(img_starter, NULL, canvas, NULL);
|
||
}
|
||
|
||
|
||
reset_avail_tools();
|
||
tool_avail[TOOL_NEW] = 1;
|
||
|
||
tool_avail_bak[TOOL_UNDO] = 0;
|
||
tool_avail_bak[TOOL_REDO] = 0;
|
||
|
||
want_new_tool = 1;
|
||
}
|
||
}
|
||
|
||
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96 - 96, 48 * 7 + 40 + HEIGHTOFFSET);
|
||
}
|
||
|
||
|
||
/* Clean up: */
|
||
|
||
free_surface_array(thumbs, num_files);
|
||
|
||
free(thumbs);
|
||
|
||
for (i = 0; i < num_files; i++)
|
||
{
|
||
free(d_names[i]);
|
||
free(d_exts[i]);
|
||
}
|
||
|
||
for (i = 0; i < NUM_PLACES_TO_LOOK; i++)
|
||
free(dirname[i]);
|
||
|
||
free(d_names);
|
||
free(d_exts);
|
||
free(d_places);
|
||
|
||
return(want_new_tool);
|
||
}
|
||
|
||
/* -------------- Poly Fill Stuff -------------- */
|
||
|
||
#ifdef SCANLINE_POLY_FILL
|
||
|
||
static void insert_edge(edge * list, edge * edg)
|
||
{
|
||
edge * p, * q;
|
||
|
||
debug("insert_edge()");
|
||
|
||
q = list;
|
||
|
||
p = q->next;
|
||
while (p != NULL)
|
||
{
|
||
if (edg->x_intersect < p->x_intersect)
|
||
{
|
||
p = NULL;
|
||
}
|
||
else
|
||
{
|
||
q = p;
|
||
p = p->next;
|
||
}
|
||
}
|
||
|
||
edg->next = q->next;
|
||
q->next = edg;
|
||
}
|
||
|
||
|
||
static int y_next(int k, int cnt, point_type * pts)
|
||
{
|
||
int j;
|
||
|
||
debug("y_next()");
|
||
|
||
if ((k + 1) > (cnt - 1))
|
||
j = 0;
|
||
else
|
||
j = k + 1;
|
||
|
||
while (pts[k].y == pts[j].y)
|
||
{
|
||
if ((j + 1) > (cnt - 1))
|
||
j = 0;
|
||
else
|
||
j++;
|
||
}
|
||
|
||
return (pts[j].y);
|
||
}
|
||
|
||
|
||
static void make_edge_rec(point_type lower, point_type upper,
|
||
int y_comp, edge * edg, edge * edges[])
|
||
{
|
||
debug("make_edge_rec()");
|
||
|
||
edg->dx_per_scan = (float)((upper.x - lower.x) / (upper.y - lower.y));
|
||
edg->x_intersect = lower.x;
|
||
|
||
if (upper.y < y_comp)
|
||
edg->y_upper = upper.y - 1;
|
||
else
|
||
edg->y_upper = upper.y;
|
||
|
||
insert_edge(edges[lower.y], edg);
|
||
}
|
||
|
||
|
||
static void build_edge_list(int cnt, point_type * pts, edge * edges[])
|
||
{
|
||
edge * edg;
|
||
point_type v1, v2;
|
||
int i, y_prev;
|
||
|
||
debug("build_edge_list()");
|
||
|
||
y_prev = pts[cnt - 2].y;
|
||
|
||
v1.x = pts[cnt - 1].x;
|
||
v1.y = pts[cnt - 1].y;
|
||
|
||
for (i = 0; i < cnt; i++)
|
||
{
|
||
v2 = pts[i];
|
||
if (v1.y != v2.y)
|
||
{
|
||
edg = (edge *) malloc(sizeof(edge));
|
||
if (v1.y < v2.y)
|
||
make_edge_rec(v1, v2, y_next(i, cnt, pts), edg, edges);
|
||
else
|
||
make_edge_rec(v2, v1, y_prev, edg, edges);
|
||
}
|
||
|
||
y_prev = v1.y;
|
||
v1 = v2;
|
||
}
|
||
}
|
||
|
||
|
||
static void build_active_list(int scan, edge * active, edge * edges[])
|
||
{
|
||
edge * p, * q;
|
||
|
||
debug("build_active_list()");
|
||
|
||
p = edges[scan]->next;
|
||
while (p != NULL)
|
||
{
|
||
q = p->next;
|
||
insert_edge(active, p);
|
||
p = q;
|
||
}
|
||
}
|
||
|
||
|
||
static void fill_scan(int scan, edge * active)
|
||
{
|
||
edge * p1, * p2;
|
||
int i;
|
||
Uint32 color;
|
||
|
||
|
||
debug("fill_scan()");
|
||
|
||
color = SDL_MapRGB(canvas->format,
|
||
color_hexes[cur_color][0] / 2,
|
||
color_hexes[cur_color][1] / 2,
|
||
color_hexes[cur_color][2] / 2);
|
||
|
||
SDL_LockSurface(canvas);
|
||
|
||
p1 = active->next;
|
||
while (p1 != NULL)
|
||
{
|
||
p2 = p1->next;
|
||
|
||
for (i = p1->x_intersect; i < p2->x_intersect; i++)
|
||
{
|
||
putpixel(canvas, i, scan, color);
|
||
}
|
||
|
||
p1 = p2->next;
|
||
}
|
||
|
||
SDL_UnlockSurface(canvas);
|
||
}
|
||
|
||
|
||
static void delete_after(edge * q)
|
||
{
|
||
edge * p;
|
||
|
||
debug("delete_after()");
|
||
|
||
p = q->next;
|
||
q->next = p->next;
|
||
free(p);
|
||
}
|
||
|
||
|
||
static void update_active_list(int scan, edge * active)
|
||
{
|
||
edge * q, * p;
|
||
|
||
debug("update_active_list()");
|
||
|
||
q = active;
|
||
p = active->next;
|
||
|
||
while (p != NULL)
|
||
{
|
||
if (scan >= p->y_upper)
|
||
{
|
||
p = p->next;
|
||
delete_after(q);
|
||
}
|
||
else
|
||
{
|
||
p->x_intersect = p->x_intersect + p->dx_per_scan;
|
||
q = p;
|
||
p = p->next;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static void resort_active_list(edge * active)
|
||
{
|
||
edge * q, * p;
|
||
|
||
debug("resort_active_list()");
|
||
|
||
p = active->next;
|
||
|
||
active->next = NULL;
|
||
|
||
while (p != NULL)
|
||
{
|
||
q = p->next;
|
||
insert_edge(active, p);
|
||
p = q;
|
||
}
|
||
}
|
||
|
||
|
||
static void scan_fill(int cnt, point_type * pts)
|
||
{
|
||
/* edge * edges[48 * 7 + 40 + HEIGHTOFFSET + 5], * active; */
|
||
edge * * edges = alloca((48 * 7 + 40 + HEIGHTOFFSET + 5) * sizeof(edge*)),
|
||
* active;
|
||
int i, scan;
|
||
|
||
debug("scan_fill()");
|
||
|
||
|
||
/* Create empty edges: */
|
||
|
||
for (i = 0; i < 48 * 7 + 40 + HEIGHTOFFSET + 5; i++)
|
||
{
|
||
edges[i] = (edge *) malloc(sizeof(edge));
|
||
edges[i]->next = NULL;
|
||
}
|
||
|
||
|
||
/* Build edge list: */
|
||
|
||
build_edge_list(cnt, pts, edges);
|
||
|
||
|
||
/* Set active edge: */
|
||
|
||
active = (edge *) malloc(sizeof(edge));
|
||
active->next = NULL;
|
||
|
||
|
||
/* Scan! */
|
||
|
||
for (scan = 0; scan < 48 * 7 + 40 + HEIGHTOFFSET; scan++)
|
||
{
|
||
build_active_list(scan, active, edges);
|
||
|
||
if (active->next)
|
||
{
|
||
fill_scan(scan, active);
|
||
|
||
update_canvas(0, scan, WINDOW_WIDTH - 96, scan);
|
||
SDL_Flip(screen);
|
||
SDL_Delay(10);
|
||
|
||
update_active_list(scan, active);
|
||
resort_active_list(active);
|
||
}
|
||
}
|
||
|
||
|
||
/* Free edge list: */
|
||
|
||
debug("Freeing...");
|
||
|
||
for (i = 0; i < 48 * 7 + 40 + HEIGHTOFFSET; i++)
|
||
{
|
||
free(edges[i]);
|
||
}
|
||
}
|
||
|
||
|
||
/* ------------- Poly clipping stuff: -------------- */
|
||
|
||
static int inside(fpoint_type p, an_edge b)
|
||
{
|
||
if (b == Left)
|
||
{
|
||
if (p.x < 0)
|
||
return 0;
|
||
}
|
||
else if (b == Right)
|
||
{
|
||
if (p.x >= WINDOW_WIDTH - 96)
|
||
return 0;
|
||
}
|
||
else if (b == Bottom)
|
||
{
|
||
if (p.y >= 48 * 7 + 40 + HEIGHTOFFSET)
|
||
return 0;
|
||
}
|
||
else if (b == Top)
|
||
{
|
||
if (p.y < 0)
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
static int cross(fpoint_type p1, fpoint_type p2, an_edge b)
|
||
{
|
||
if (inside(p1, b) == inside(p2, b))
|
||
return 0;
|
||
else
|
||
return 1;
|
||
}
|
||
|
||
|
||
static fpoint_type intersect(fpoint_type p1, fpoint_type p2, an_edge b)
|
||
{
|
||
fpoint_type ipt;
|
||
float m;
|
||
|
||
if (p1.x != p2.x)
|
||
m = (p1.y - p2.y) / (p1.x - p2.x);
|
||
else
|
||
m = 1.0;
|
||
|
||
if (b == Left)
|
||
{
|
||
ipt.x = 0;
|
||
ipt.y = p2.y + (-p2.x) * m;
|
||
}
|
||
else if (b == Right)
|
||
{
|
||
ipt.x = WINDOW_WIDTH - 96 - 1;
|
||
ipt.y = p2.y + ((WINDOW_WIDTH - 96 - 1) - p2.x) * m;
|
||
}
|
||
else if (b == Top)
|
||
{
|
||
ipt.y = 0;
|
||
if (p1.x != p2.x)
|
||
ipt.x = p2.x + (-p2.y) / m;
|
||
else
|
||
ipt.x = p2.x;
|
||
}
|
||
else if (b == Bottom)
|
||
{
|
||
ipt.y = (48 * 7 + 40 + HEIGHTOFFSET) - 1;
|
||
if (p1.x != p2.x)
|
||
ipt.x = p2.x + (((48 * 7 + 40 + HEIGHTOFFSET) - 1) - p2.y) / m;
|
||
else
|
||
ipt.x = p2.x;
|
||
}
|
||
|
||
return(ipt);
|
||
}
|
||
|
||
|
||
static void clip_point(fpoint_type p, an_edge b, fpoint_type * pout, int * cnt,
|
||
fpoint_type * first[], fpoint_type * s)
|
||
{
|
||
fpoint_type ipt;
|
||
|
||
if (first[b] == NULL)
|
||
{
|
||
first[b] = &p;
|
||
}
|
||
else
|
||
{
|
||
if (cross(p, s[b], b))
|
||
{
|
||
ipt = intersect(p, s[b], b);
|
||
|
||
if (b < Top) /* Should be NUM_EDGES? */
|
||
{
|
||
clip_point(ipt, b + 1, pout, cnt, first, s);
|
||
}
|
||
else
|
||
{
|
||
pout[*cnt] = ipt;
|
||
(*cnt)++;
|
||
}
|
||
}
|
||
}
|
||
|
||
s[b] = p;
|
||
|
||
|
||
if (inside(p, b))
|
||
{
|
||
if (b < Top) /* Should be NUM_EDGES? */
|
||
{
|
||
clip_point(p, b + 1, pout, cnt, first, s);
|
||
}
|
||
else
|
||
{
|
||
pout[*cnt] = p;
|
||
(*cnt)++;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static void close_clip(fpoint_type * pout, int * cnt, fpoint_type * first[],
|
||
fpoint_type * s)
|
||
{
|
||
fpoint_type i;
|
||
an_edge b;
|
||
|
||
for (b = Left; b <= Top; b++)
|
||
{
|
||
if (cross(s[b], *first[b], b))
|
||
{
|
||
i = intersect(s[b], *first[b], b);
|
||
if (b < Top)
|
||
{
|
||
clip_point(i, b + 1, pout, cnt, first, s);
|
||
}
|
||
else
|
||
{
|
||
pout[*cnt] = i;
|
||
(*cnt)++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static int clip_polygon(int n, fpoint_type * pin, fpoint_type * pout)
|
||
{
|
||
fpoint_type * first[NUM_EDGES] = {0, 0, 0, 0};
|
||
fpoint_type s[NUM_EDGES];
|
||
int i, cnt;
|
||
|
||
cnt = 0;
|
||
|
||
for (i = 0; i < n; i++)
|
||
{
|
||
clip_point(pin[i], Left, pout, &cnt, first, s);
|
||
}
|
||
|
||
close_clip(pout, &cnt, first, s);
|
||
|
||
return(cnt);
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* Let sound effects (e.g., "Save" sfx) play out before quitting... */
|
||
|
||
static void wait_for_sfx(void)
|
||
{
|
||
#ifndef NOSOUND
|
||
if (use_sound)
|
||
{
|
||
while (Mix_Playing(-1))
|
||
SDL_Delay(10);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Determine the current language/locale, and set the language string: */
|
||
|
||
static int current_language(void)
|
||
{
|
||
char * loc;
|
||
#ifdef WIN32
|
||
char str[128];
|
||
#endif
|
||
int lang, i, found;
|
||
|
||
|
||
/* Default... */
|
||
|
||
lang = LANG_EN;
|
||
|
||
|
||
#ifndef WIN32
|
||
loc = setlocale(LC_MESSAGES, NULL);
|
||
if (loc != NULL)
|
||
{
|
||
if (strstr(loc, "LC_MESSAGES") != NULL)
|
||
loc = getenv("LANG");
|
||
}
|
||
#else
|
||
loc = getenv("LANGUAGE");
|
||
if (!loc)
|
||
{
|
||
loc = g_win32_getlocale();
|
||
if (loc)
|
||
{
|
||
snprintf(str, sizeof(str), "LANGUAGE=%s", loc);
|
||
putenv(str);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
debug(loc);
|
||
|
||
if (loc != NULL)
|
||
{
|
||
/* Which, if any, of the locales is it? */
|
||
|
||
found = 0;
|
||
|
||
for (i = 0; i < NUM_LANGS && found == 0; i++)
|
||
{
|
||
/* Case-insensitive */
|
||
/* (so that, e.g. "pt_BR" is recognized as "pt_br") */
|
||
|
||
if (strncasecmp(loc, lang_prefixes[i], strlen(lang_prefixes[i])) == 0)
|
||
/* if (strcasecmp(loc, lang_prefixes[i]) == 0) */
|
||
{
|
||
lang = i;
|
||
found = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf("lang=%d\n\n", lang);
|
||
sleep(10);
|
||
#endif
|
||
|
||
|
||
return lang;
|
||
}
|
||
|
||
|
||
|
||
////////////////////////////////////////////////////////////
|
||
// stamp outline
|
||
|
||
/* XOR-based outline of rubber stamp shapes
|
||
(unused if LOW_QUALITY_STAMP_OUTLINE is #defined) */
|
||
|
||
#if 1
|
||
#define STIPLE_W 5
|
||
#define STIPLE_H 5
|
||
static char stiple[] =
|
||
"84210"
|
||
"10842"
|
||
"42108"
|
||
"08421"
|
||
"21084"
|
||
;
|
||
#endif
|
||
|
||
#if 0
|
||
#define STIPLE_W 4
|
||
#define STIPLE_H 4
|
||
static char stiple[] =
|
||
"8000"
|
||
"0800"
|
||
"0008"
|
||
"0080"
|
||
;
|
||
#endif
|
||
|
||
#if 0
|
||
#define STIPLE_W 12
|
||
#define STIPLE_H 12
|
||
static char stiple[] =
|
||
"808808000000"
|
||
"800000080880"
|
||
"008088080000"
|
||
"808000000808"
|
||
"000080880800"
|
||
"088080000008"
|
||
"000000808808"
|
||
"080880800000"
|
||
"080000008088"
|
||
"000808808000"
|
||
"880800000080"
|
||
"000008088080"
|
||
;
|
||
#endif
|
||
|
||
static unsigned char *stamp_outline_data;
|
||
static int stamp_outline_w, stamp_outline_h;
|
||
|
||
static void update_stamp_xor(void)
|
||
{
|
||
int xx, yy, rx, ry;
|
||
Uint8 dummy;
|
||
SDL_Surface * src;
|
||
|
||
/* Use pre-mirrored stamp image, if applicable: */
|
||
|
||
if (state_stamps[cur_stamp]->mirrored &&
|
||
img_stamps_premirror[cur_stamp] != NULL)
|
||
{
|
||
src = img_stamps_premirror[cur_stamp];
|
||
}
|
||
else
|
||
{
|
||
src = img_stamps[cur_stamp];
|
||
}
|
||
|
||
// start by scaling
|
||
src = thumbnail(src, CUR_STAMP_W, CUR_STAMP_H, 0);
|
||
|
||
unsigned char *alphabits = calloc(src->w+4, src->h+4);
|
||
|
||
SDL_LockSurface(src);
|
||
for (yy = 0; yy < src->h; yy++)
|
||
{
|
||
/* Compensate for flip! */
|
||
if (state_stamps[cur_stamp]->flipped)
|
||
ry = src->h - 1 - yy;
|
||
else
|
||
ry = yy;
|
||
for (xx = 0; xx < src->w; xx++)
|
||
{
|
||
/* Compensate for mirror! */
|
||
if (state_stamps[cur_stamp]->mirrored &&
|
||
img_stamps_premirror[cur_stamp] == NULL)
|
||
{
|
||
rx = src->w - 1 - xx;
|
||
}
|
||
else
|
||
{
|
||
rx = xx;
|
||
}
|
||
|
||
SDL_GetRGBA(getpixel(src, rx, ry),
|
||
src->format, &dummy, &dummy, &dummy, alphabits + xx+2 + (yy+2)*(src->w+4));
|
||
}
|
||
}
|
||
SDL_UnlockSurface(src);
|
||
|
||
int new_w = src->w+4;
|
||
int new_h = src->h+4;
|
||
SDL_FreeSurface(src);
|
||
unsigned char *outline = calloc(new_w, new_h);
|
||
|
||
for (yy = 1; yy < new_h-1; yy++)
|
||
{
|
||
for (xx = 1; xx < new_w-1; xx++)
|
||
{
|
||
unsigned char above = 0;
|
||
unsigned char below = 0xff;
|
||
unsigned char tmp;
|
||
|
||
tmp = alphabits[(xx-1) + (yy-1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx+1) + (yy-1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
|
||
tmp = alphabits[(xx+0) + (yy-1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx+0) + (yy+0)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx+1) + (yy+0)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx-1) + (yy+0)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx+0) + (yy+1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
|
||
tmp = alphabits[(xx-1) + (yy+1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
tmp = alphabits[(xx+1) + (yy+1)*new_w];
|
||
above |= tmp;
|
||
below &= tmp;
|
||
|
||
outline[xx + yy*new_w] = (above^below)>>7;
|
||
}
|
||
}
|
||
|
||
char *old_outline_data = stamp_outline_data;
|
||
SDL_LockSurface(screen); // abuse this lock until I determine the correct need
|
||
stamp_outline_data = outline;
|
||
stamp_outline_w = new_w;
|
||
stamp_outline_h = new_h;
|
||
SDL_UnlockSurface(screen);
|
||
if (old_outline_data)
|
||
free(old_outline_data);
|
||
free(alphabits);
|
||
}
|
||
|
||
static void stamp_xor(int x, int y)
|
||
{
|
||
int xx, yy, sx, sy;
|
||
|
||
SDL_LockSurface(screen);
|
||
for (yy = 0; yy < stamp_outline_h; yy++)
|
||
{
|
||
for (xx = 0; xx < stamp_outline_w; xx++)
|
||
{
|
||
if(!stamp_outline_data[xx + yy*stamp_outline_w])
|
||
continue;
|
||
sx = 96 + x + xx - stamp_outline_w/2;
|
||
sy = y + yy - stamp_outline_h/2;
|
||
if (stiple[sx%STIPLE_W + sy%STIPLE_H * STIPLE_W] != '8')
|
||
continue;
|
||
clipped_putpixel(screen, sx, sy, 0xFFFFFFFF - getpixel(screen, sx, sy));
|
||
}
|
||
}
|
||
SDL_UnlockSurface(screen);
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////
|
||
|
||
/* Returns whether a particular stamp can be colored: */
|
||
|
||
static int stamp_colorable(int stamp)
|
||
{
|
||
if (inf_stamps[stamp] != NULL)
|
||
{
|
||
return inf_stamps[stamp]->colorable;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
/* Returns whether a particular stamp can be tinted: */
|
||
|
||
static int stamp_tintable(int stamp)
|
||
{
|
||
if (inf_stamps[stamp] != NULL)
|
||
{
|
||
return inf_stamps[stamp]->tintable;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
/* Returns whether low-saturation ('gray') parts of stamp can be tinted: */
|
||
|
||
static int stamp_tintgray(int stamp)
|
||
{
|
||
if (inf_stamps[stamp] != NULL)
|
||
{
|
||
return inf_stamps[stamp]->tintgray;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
static void rgbtohsv(Uint8 r8, Uint8 g8, Uint8 b8, float *h, float *s, float *v)
|
||
{
|
||
float rgb_min, rgb_max, delta, r, g, b;
|
||
|
||
r = (r8 / 255.0);
|
||
g = (g8 / 255.0);
|
||
b = (b8 / 255.0);
|
||
|
||
rgb_min = min(r, min(g, b));
|
||
rgb_max = max(r, max(g, b));
|
||
*v = rgb_max;
|
||
|
||
delta = rgb_max - rgb_min;
|
||
|
||
if (rgb_max == 0)
|
||
{
|
||
/* Black */
|
||
|
||
*s = 0;
|
||
*h = -1;
|
||
}
|
||
else
|
||
{
|
||
*s = delta / rgb_max;
|
||
|
||
if (r == rgb_max)
|
||
*h = (g - b) / delta;
|
||
else if (g == rgb_max)
|
||
*h = 2 + (b - r) / delta; /* between cyan & yellow */
|
||
else
|
||
*h = 4 + (r - g) / delta; /* between magenta & cyan */
|
||
|
||
*h = (*h * 60); /* degrees */
|
||
|
||
if (*h < 0)
|
||
*h = (*h + 360);
|
||
}
|
||
}
|
||
|
||
|
||
static void hsvtorgb(float h, float s, float v, Uint8 *r8, Uint8 *g8, Uint8 *b8)
|
||
{
|
||
int i;
|
||
float f, p, q, t, r, g, b;
|
||
|
||
if (s == 0)
|
||
{
|
||
/* Achromatic (grey) */
|
||
|
||
r = v;
|
||
g = v;
|
||
b = v;
|
||
}
|
||
else
|
||
{
|
||
h = h / 60;
|
||
i = floor(h);
|
||
f = h - i;
|
||
p = v * (1 - s);
|
||
q = v * (1 - s * f);
|
||
t = v * (1 - s * (1 - f));
|
||
|
||
if (i == 0)
|
||
{
|
||
r = v;
|
||
g = t;
|
||
b = p;
|
||
}
|
||
else if (i == 1)
|
||
{
|
||
r = q;
|
||
g = v;
|
||
b = p;
|
||
}
|
||
else if (i == 2)
|
||
{
|
||
r = p;
|
||
g = v;
|
||
b = t;
|
||
}
|
||
else if (i == 3)
|
||
{
|
||
r = p;
|
||
g = q;
|
||
b = v;
|
||
}
|
||
else if (i == 4)
|
||
{
|
||
r = t;
|
||
g = p;
|
||
b = v;
|
||
}
|
||
else
|
||
{
|
||
r = v;
|
||
g = p;
|
||
b = q;
|
||
}
|
||
}
|
||
|
||
|
||
*r8 = (Uint8) (r * 255);
|
||
*g8 = (Uint8) (g * 255);
|
||
*b8 = (Uint8) (b * 255);
|
||
}
|
||
|
||
|
||
static void show_progress_bar(void)
|
||
{
|
||
SDL_Rect dest, src;
|
||
int x;
|
||
|
||
|
||
for (x = 0; x < WINDOW_WIDTH; x = x + 65)
|
||
{
|
||
src.x = 65 - (prog_bar_ctr % 65);
|
||
src.y = 0;
|
||
src.w = 65;
|
||
src.h = 24;
|
||
|
||
dest.x = x;
|
||
dest.y = WINDOW_HEIGHT - 24;
|
||
|
||
SDL_BlitSurface(img_progress, &src, screen, &dest);
|
||
}
|
||
|
||
prog_bar_ctr++;
|
||
|
||
SDL_UpdateRect(screen, 0, WINDOW_HEIGHT - 24, WINDOW_WIDTH, 24);
|
||
}
|
||
|
||
|
||
static void do_print(void)
|
||
{
|
||
#if !defined(WIN32) && !defined(__BEOS__) && !defined(__APPLE__)
|
||
/* Linux, Unix, etc. */
|
||
|
||
FILE * pi;
|
||
|
||
pi = popen(printcommand, "w");
|
||
|
||
if (pi == NULL)
|
||
{
|
||
perror(printcommand);
|
||
}
|
||
else
|
||
{
|
||
if (do_png_save(pi, printcommand, canvas))
|
||
do_prompt(PROMPT_PRINT_TXT, PROMPT_PRINT_YES, "");
|
||
}
|
||
#else
|
||
#ifdef WIN32
|
||
/* Win32 */
|
||
|
||
char f[512];
|
||
int show = (SDL_GetModState() & KMOD_ALT) && !fullscreen;
|
||
|
||
snprintf(f, sizeof(f), "%s/%s", savedir, "print.cfg");
|
||
|
||
{
|
||
const char *error = SurfacePrint(canvas, use_print_config?f:NULL, show);
|
||
|
||
if ( error ) fprintf(stderr, "%s\n", error);
|
||
}
|
||
#elif defined(__BEOS__)
|
||
/* BeOS */
|
||
|
||
SurfacePrint(canvas);
|
||
#elif defined(__APPLE__)
|
||
/* Mac OS X */
|
||
|
||
int show = (SDL_GetModState() & KMOD_ALT) && !fullscreen;
|
||
|
||
const char* error = SurfacePrint (canvas, show);
|
||
|
||
if (error)
|
||
fprintf (stderr, "Cannot print: %s\n", error);
|
||
else
|
||
do_prompt (PROMPT_PRINT_TXT, PROMPT_PRINT_YES, "");
|
||
#endif
|
||
|
||
#endif
|
||
}
|
||
|
||
|
||
static void do_render_cur_text(int do_blit)
|
||
{
|
||
int w, h;
|
||
SDL_Color color = {color_hexes[cur_color][0],
|
||
color_hexes[cur_color][1],
|
||
color_hexes[cur_color][2],
|
||
0};
|
||
SDL_Surface * tmp_surf;
|
||
SDL_Rect dest, src;
|
||
char * str;
|
||
|
||
|
||
/* Keep cursor on the screen! */
|
||
|
||
if (cursor_y > ((48 * 7 + 40 + HEIGHTOFFSET) -
|
||
TTF_FontHeight(fonts[cur_font])))
|
||
{
|
||
cursor_y = ((48 * 7 + 40 + HEIGHTOFFSET) -
|
||
TTF_FontHeight(fonts[cur_font]));
|
||
}
|
||
|
||
|
||
/* Render the text: */
|
||
|
||
if (texttool_len > 0)
|
||
{
|
||
str = uppercase(texttool_str);
|
||
|
||
tmp_surf = TTF_RenderUTF8_Blended(fonts[cur_font], str, color);
|
||
|
||
w = tmp_surf->w;
|
||
h = tmp_surf->h;
|
||
|
||
cursor_textwidth = w;
|
||
|
||
free(str);
|
||
}
|
||
else
|
||
{
|
||
/* FIXME: Do something different! */
|
||
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
cursor_textwidth = 0;
|
||
return;
|
||
}
|
||
|
||
|
||
if (!do_blit)
|
||
{
|
||
/* FIXME: Only delete what's changed! */
|
||
|
||
update_canvas(0, 0, WINDOW_WIDTH - 96, (48 * 7) + 40 + HEIGHTOFFSET);
|
||
|
||
|
||
/* Draw outline around text: */
|
||
|
||
dest.x = cursor_x - 2 + 96;
|
||
dest.y = cursor_y - 2;
|
||
dest.w = w + 4;
|
||
dest.h = h + 4;
|
||
|
||
if (dest.x + dest.w > WINDOW_WIDTH - 96)
|
||
dest.w = WINDOW_WIDTH - 96 - dest.x;
|
||
if (dest.y + dest.h > (48 * 7 + 40 + HEIGHTOFFSET))
|
||
dest.h = (48 * 7 + 40 + HEIGHTOFFSET) - dest.y;
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(canvas->format, 0, 0, 0));
|
||
|
||
|
||
/* FIXME: This would be nice if it were alpha-blended: */
|
||
|
||
dest.x = cursor_x + 96;
|
||
dest.y = cursor_y;
|
||
dest.w = w;
|
||
dest.h = h;
|
||
|
||
if (dest.x + dest.w > WINDOW_WIDTH - 96)
|
||
dest.w = WINDOW_WIDTH - 96 - dest.x;
|
||
if (dest.y + dest.h > (48 * 7 + 40 + HEIGHTOFFSET))
|
||
dest.h = (48 * 7 + 40 + HEIGHTOFFSET) - dest.y;
|
||
|
||
if ((color_hexes[cur_color][0] +
|
||
color_hexes[cur_color][1] +
|
||
color_hexes[cur_color][2]) >= 384)
|
||
{
|
||
/* Grey background if blit is white!... */
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(canvas->format, 64, 64, 64));
|
||
}
|
||
else
|
||
{
|
||
/* White background, normally... */
|
||
|
||
SDL_FillRect(screen, &dest,
|
||
SDL_MapRGB(canvas->format, 255, 255, 255));
|
||
}
|
||
}
|
||
|
||
|
||
/* Draw the text itself! */
|
||
|
||
if (tmp_surf != NULL)
|
||
{
|
||
dest.x = cursor_x;
|
||
dest.y = cursor_y;
|
||
|
||
src.x = 0;
|
||
src.y = 0;
|
||
src.w = tmp_surf->w;
|
||
src.h = tmp_surf->h;
|
||
|
||
if (dest.x + src.w > WINDOW_WIDTH - 96 - 96)
|
||
src.w = WINDOW_WIDTH - 96 - 96 - dest.x;
|
||
if (dest.y + src.h > (48 * 7 + 40 + HEIGHTOFFSET))
|
||
src.h = (48 * 7 + 40 + HEIGHTOFFSET) - dest.y;
|
||
|
||
if (do_blit)
|
||
{
|
||
SDL_BlitSurface(tmp_surf, &src, canvas, &dest);
|
||
update_canvas(dest.x, dest.y, dest.x + tmp_surf->w, dest.y + tmp_surf->h);
|
||
}
|
||
else
|
||
{
|
||
dest.x = dest.x + 96;
|
||
SDL_BlitSurface(tmp_surf, &src, screen, &dest);
|
||
}
|
||
}
|
||
|
||
|
||
/* FIXME: Only update what's changed! */
|
||
|
||
SDL_Flip(screen);
|
||
|
||
|
||
if (tmp_surf != NULL)
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
|
||
|
||
static void loadfonts(const char * const dir, int fatal)
|
||
{
|
||
DIR * d;
|
||
struct dirent * f;
|
||
struct stat sbuf;
|
||
char fname[512];
|
||
int d_names_alloced;
|
||
char * * d_names;
|
||
int num_files, i;
|
||
|
||
|
||
/* Open the directory: */
|
||
|
||
d = opendir(dir);
|
||
if (d == NULL)
|
||
{
|
||
if (fatal)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't find a directory of fonts\n"
|
||
"%s\n"
|
||
"The system error that occurred was: %s\n",
|
||
dir, strerror(errno));
|
||
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
else
|
||
return;
|
||
}
|
||
|
||
|
||
/* Make some space: */
|
||
|
||
d_names_alloced = 32;
|
||
d_names = (char * *) malloc(sizeof(char *) * d_names_alloced);
|
||
if (d_names == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't allocate memory for directory listing!\n"
|
||
"The system error that occurred was: %s\n",
|
||
strerror(errno));
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
|
||
|
||
|
||
/* Read directory for images: */
|
||
|
||
num_files = 0;
|
||
do
|
||
{
|
||
f = readdir(d);
|
||
|
||
if (f != NULL)
|
||
{
|
||
d_names[num_files] = strdup(f->d_name);
|
||
num_files++;
|
||
|
||
if (num_files >= d_names_alloced)
|
||
{
|
||
d_names_alloced = d_names_alloced + 32;
|
||
d_names = (char * *) realloc(d_names, sizeof(char *) * d_names_alloced);
|
||
|
||
if (d_names == NULL)
|
||
{
|
||
fprintf(stderr,
|
||
"\nError: I can't allocate memory for directory listing!\n"
|
||
"The system error that occurred was: %s\n",
|
||
strerror(errno));
|
||
cleanup();
|
||
exit(1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
while (f != NULL);
|
||
|
||
closedir(d);
|
||
|
||
|
||
qsort(d_names, num_files, sizeof(char *),
|
||
(int(*)(const void *, const void *))compare_strings);
|
||
|
||
|
||
/* Do something with each file (load TTFs): */
|
||
|
||
for (i = 0; i < num_files && num_fonts + 3 < MAX_FONTS; i++)
|
||
{
|
||
/* Ignore things starting with "." (e.g., "." and ".." dirs): */
|
||
|
||
if (strstr(d_names[i], ".") != d_names[i])
|
||
{
|
||
/* If it's a directory, recurse down into it: */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s", dir, d_names[i]);
|
||
debug(fname);
|
||
|
||
stat(fname, &sbuf);
|
||
|
||
if (strstr(d_names[i], ".ttf") != NULL)
|
||
{
|
||
/* If it has ".ttf" in the filename, assume we can try to load it: */
|
||
|
||
fonts[num_fonts++] = TTF_OpenFont(fname, 16);
|
||
fonts[num_fonts++] = TTF_OpenFont(fname, 24);
|
||
fonts[num_fonts++] = TTF_OpenFont(fname, 32);
|
||
fonts[num_fonts++] = TTF_OpenFont(fname, 48);
|
||
|
||
show_progress_bar();
|
||
}
|
||
}
|
||
|
||
free(d_names[i]);
|
||
}
|
||
|
||
|
||
/* Give warning if too many files were found (e.g., some not loaded): */
|
||
|
||
if (num_fonts == MAX_FONTS)
|
||
{
|
||
fprintf(stderr,
|
||
"\nWarning: Reached maximum fonts (%d) which can be loaded.\n\n",
|
||
MAX_FONTS);
|
||
}
|
||
}
|
||
|
||
|
||
/* Return string as uppercase if that option is set: */
|
||
|
||
#ifdef OLD_UPPERCASE_CODE
|
||
|
||
static char * uppercase(char * str)
|
||
{
|
||
char * ustr;
|
||
int i;
|
||
|
||
ustr = strdup(str);
|
||
|
||
if (only_uppercase)
|
||
{
|
||
for (i = 0; i < strlen(ustr); i++)
|
||
ustr[i] = toupper(ustr[i]);
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf(" ORIGINAL: %s\n"
|
||
"UPPERCASE: %s\n\n", str, ustr);
|
||
#endif
|
||
|
||
return (ustr);
|
||
}
|
||
|
||
#else
|
||
|
||
static char * uppercase(char * str)
|
||
{
|
||
unsigned int i, sz;
|
||
wchar_t * dest;
|
||
char * ustr;
|
||
|
||
if (only_uppercase)
|
||
{
|
||
sz = sizeof(wchar_t) * (strlen(str) + 1);
|
||
|
||
dest = (wchar_t *) malloc(sz);
|
||
ustr = (char *) malloc(sizeof(char) * (strlen(str) + 1));
|
||
|
||
if (dest != NULL)
|
||
{
|
||
mbstowcs(dest, str, sz);
|
||
|
||
for (i = 0; i < strlen(str); i++)
|
||
{
|
||
dest[i] = towupper(dest[i]);
|
||
}
|
||
|
||
wcstombs(ustr, dest, sizeof(char) * (strlen(str) + 1));
|
||
|
||
free(dest);
|
||
}
|
||
|
||
printf(" ORIGINAL: %s\n"
|
||
"UPPERCASE: %s\n\n", str, ustr);
|
||
}
|
||
else
|
||
{
|
||
ustr = strdup(str);
|
||
}
|
||
|
||
return(ustr);
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/* Return string in right-to-left mode, if necessary: */
|
||
|
||
static unsigned char * textdir(const unsigned char * const str)
|
||
{
|
||
unsigned char * dstr;
|
||
unsigned i, j;
|
||
|
||
#ifdef DEBUG
|
||
printf("ORIG_DIR: %s\n", str);
|
||
#endif
|
||
|
||
dstr = (unsigned char *) malloc((strlen(str) + 5) * sizeof(unsigned char));
|
||
|
||
if (need_right_to_left(language))
|
||
{
|
||
dstr[strlen(str)] = '\0';
|
||
|
||
for (i = 0; i < strlen(str); i++)
|
||
{
|
||
j = (strlen(str) - i - 1);
|
||
|
||
if (str[i] < 128) /* 0xxx xxxx - 1 byte */
|
||
{
|
||
dstr[j] = str[i];
|
||
}
|
||
else if ((str[i] & 0xE0) == 0xC0) /* 110x xxxx - 2 bytes */
|
||
{
|
||
dstr[j - 1] = str[i + 0];
|
||
dstr[j - 0] = str[i + 1];
|
||
i = i + 1;
|
||
}
|
||
else if ((str[i] & 0xF0) == 0xE0) /* 1110 xxxx - 3 bytes */
|
||
{
|
||
dstr[j - 2] = str[i + 0];
|
||
dstr[j - 1] = str[i + 1];
|
||
dstr[j - 0] = str[i + 2];
|
||
i = i + 2;
|
||
}
|
||
else /* 1111 0xxx - 4 bytes */
|
||
{
|
||
dstr[j - 3] = str[i + 0];
|
||
dstr[j - 2] = str[i + 1];
|
||
dstr[j - 1] = str[i + 2];
|
||
dstr[j - 0] = str[i + 3];
|
||
i = i + 3;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
strcpy(dstr, str);
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
printf("L2R_DIR: %s\n", dstr);
|
||
#endif
|
||
|
||
return (dstr);
|
||
}
|
||
|
||
|
||
/* For flood fill... */
|
||
|
||
static int colors_close(Uint32 c1, Uint32 c2)
|
||
{
|
||
#ifdef LOW_QUALITY_FLOOD_FILL
|
||
return (c1 == c2);
|
||
#else
|
||
Uint8 r1, g1, b1,
|
||
r2, g2, b2;
|
||
|
||
if (c1 == c2)
|
||
{
|
||
/* Get it over with quick, if possible! */
|
||
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
SDL_GetRGB(c1, canvas->format, &r1, &g1, &b1);
|
||
SDL_GetRGB(c2, canvas->format, &r2, &g2, &b2);
|
||
|
||
if (abs(r1 - r2) <= 64 &&
|
||
abs(g1 - g2) <= 64 &&
|
||
abs(b1 - b2) <= 64)
|
||
return 1;
|
||
else
|
||
return 0;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
/* Flood fill! */
|
||
|
||
static void do_flood_fill(int x, int y, Uint32 cur_colr, Uint32 old_colr)
|
||
{
|
||
int fillL, fillR, i, in_line;
|
||
static unsigned char prog_anim;
|
||
|
||
|
||
if (cur_colr == old_colr ||
|
||
colors_close(cur_colr, old_colr))
|
||
return;
|
||
|
||
|
||
fillL = x;
|
||
fillR = x;
|
||
|
||
prog_anim++;
|
||
if ((prog_anim % 4) == 0)
|
||
{
|
||
show_progress_bar();
|
||
playsound(0, SND_BUBBLE, 0);
|
||
}
|
||
|
||
|
||
/* Find left side, filling along the way */
|
||
|
||
in_line = 1;
|
||
|
||
while (in_line)
|
||
{
|
||
putpixel(canvas, fillL, y, cur_colr);
|
||
fillL--;
|
||
|
||
in_line = (fillL < 0) ? 0 : colors_close(getpixel(canvas, fillL, y),
|
||
old_colr);
|
||
}
|
||
|
||
fillL++;
|
||
|
||
|
||
/* Find right side, filling along the way */
|
||
|
||
in_line = 1;
|
||
while (in_line)
|
||
{
|
||
putpixel(canvas, fillR, y, cur_colr);
|
||
fillR++;
|
||
|
||
in_line = (fillR >= canvas->w) ? 0 : colors_close(getpixel(canvas,
|
||
fillR, y),
|
||
old_colr);
|
||
}
|
||
|
||
fillR--;
|
||
|
||
|
||
/* Search top and bottom */
|
||
|
||
for (i = fillL; i <= fillR; i++)
|
||
{
|
||
if (y > 0 && colors_close(getpixel(canvas, i, y - 1), old_colr))
|
||
do_flood_fill(i, y - 1, cur_colr, old_colr);
|
||
|
||
if (y < canvas->h && colors_close(getpixel(canvas, i, y + 1), old_colr))
|
||
do_flood_fill(i, y + 1, cur_colr, old_colr);
|
||
}
|
||
}
|
||
|
||
|
||
/* Scroll Timer */
|
||
|
||
static Uint32 scrolltimer_callback(Uint32 interval, void *param)
|
||
{
|
||
SDL_PushEvent((SDL_Event*)param);
|
||
|
||
return interval;
|
||
}
|
||
|
||
|
||
/* Controls the Text-Timer - interval == 0 removes the timer */
|
||
|
||
static void control_drawtext_timer(Uint32 interval, const char * const text)
|
||
{
|
||
static int activated = 0;
|
||
static SDL_TimerID TimerID = 0;
|
||
static SDL_Event drawtext_event;
|
||
|
||
|
||
/* Remove old timer if any is running */
|
||
|
||
if (activated)
|
||
{
|
||
SDL_RemoveTimer(TimerID);
|
||
activated = 0;
|
||
TimerID = 0;
|
||
}
|
||
|
||
if (interval == 0)
|
||
return;
|
||
|
||
drawtext_event.type = SDL_USEREVENT;
|
||
drawtext_event.user.code = USEREVENT_TEXT_UPDATE;
|
||
drawtext_event.user.data1 = (void*) text;
|
||
|
||
|
||
/* Add new timer */
|
||
|
||
TimerID = SDL_AddTimer(interval, drawtext_callback, (void*) &drawtext_event);
|
||
activated = 1;
|
||
}
|
||
|
||
|
||
/* Drawtext Timer */
|
||
|
||
static Uint32 drawtext_callback(Uint32 interval, void *param)
|
||
{
|
||
(void)interval;
|
||
SDL_PushEvent((SDL_Event*)param);
|
||
|
||
return 0; /* Remove timer */
|
||
}
|
||
|
||
|
||
static void parse_options(FILE * fi)
|
||
{
|
||
char str[256];
|
||
|
||
do
|
||
{
|
||
fgets(str, sizeof(str), fi);
|
||
|
||
strip_trailing_whitespace(str);
|
||
|
||
if (!feof(fi))
|
||
{
|
||
debug(str);
|
||
|
||
|
||
/* Should "lang=" and "locale=" be here as well???
|
||
Comments welcome ... bill@newbreedsoftware.com */
|
||
|
||
|
||
/* FIXME: This should be handled better! */
|
||
/* (e.g., complain on illegal lines, support comments, blanks, etc.) */
|
||
|
||
if (strcmp(str, "fullscreen=yes") == 0)
|
||
{
|
||
fullscreen = 1;
|
||
}
|
||
else if (strcmp(str, "fullscreen=no") == 0 ||
|
||
strcmp(str, "windowed=yes") == 0)
|
||
{
|
||
fullscreen = 0;
|
||
}
|
||
else if (strcmp(str, "nostampcontrols=yes") == 0)
|
||
{
|
||
disable_stamp_controls = 1;
|
||
}
|
||
else if (strcmp(str, "nostampcontrols=no") == 0 ||
|
||
strcmp(str, "stampcontrols=yes") == 0)
|
||
{
|
||
disable_stamp_controls = 0;
|
||
}
|
||
else if (strcmp(str, "mirrorstamps=yes") == 0)
|
||
{
|
||
mirrorstamps = 1;
|
||
}
|
||
else if (strcmp(str, "mirrorstamps=no") == 0 ||
|
||
strcmp(str, "dontmirrorstamps=yes") == 0)
|
||
{
|
||
mirrorstamps = 0;
|
||
}
|
||
else if (strcmp(str, "noshortcuts=yes") == 0)
|
||
{
|
||
noshortcuts = 1;
|
||
}
|
||
else if (strcmp(str, "noshortcuts=no") == 0 ||
|
||
strcmp(str, "shortcuts=yes") == 0)
|
||
{
|
||
noshortcuts = 0;
|
||
}
|
||
else if (!memcmp("windowsize=",str,11))
|
||
{
|
||
char *endp1;
|
||
char *endp2;
|
||
int w,h;
|
||
w = strtoul(str+11, &endp1, 10);
|
||
h = strtoul(endp1+1, &endp2, 10);
|
||
// sanity check it
|
||
if(str+11==endp1 || endp1+1==endp2 || *endp1!='x' || *endp2 || w<500 || h<480 || h>w*3 || w>h*4)
|
||
{
|
||
// Oddly, config files have no error checking.
|
||
//show_usage(stderr, (char *) getfilename(argv[0]));
|
||
//exit(1);
|
||
}
|
||
else
|
||
{
|
||
WINDOW_WIDTH = w;
|
||
WINDOW_HEIGHT = h;
|
||
}
|
||
}
|
||
// to handle old config files
|
||
else if (strcmp(str, "800x600=yes") == 0 ||
|
||
strcmp(str, "windowsize=800x600") == 0)
|
||
{
|
||
WINDOW_WIDTH = 800;
|
||
WINDOW_HEIGHT = 600;
|
||
}
|
||
// also for old config files
|
||
else if (strcmp(str, "800x600=no") == 0 ||
|
||
strcmp(str, "640x480=yes") == 0 ||
|
||
strcmp(str, "windowsize=640x480") == 0)
|
||
{
|
||
WINDOW_WIDTH = 640;
|
||
WINDOW_HEIGHT = 480;
|
||
}
|
||
else if (strcmp(str, "nooutlines=yes") == 0)
|
||
{
|
||
dont_do_xor = 1;
|
||
}
|
||
else if (strcmp(str, "nooutlines=no") == 0 ||
|
||
strcmp(str, "outlines=yes") == 0)
|
||
{
|
||
dont_do_xor = 0;
|
||
}
|
||
else if (strcmp(str, "keyboard=yes") == 0)
|
||
{
|
||
keymouse = 1;
|
||
}
|
||
else if (strcmp(str, "keyboard=no") == 0 ||
|
||
strcmp(str, "mouse=yes") == 0)
|
||
{
|
||
keymouse = 0;
|
||
}
|
||
else if (strcmp(str, "nowheelmouse=yes") == 0)
|
||
{
|
||
wheely = 0;
|
||
}
|
||
else if (strcmp(str, "nowheelmouse=no") == 0 ||
|
||
strcmp(str, "wheelmouse=yes") == 0)
|
||
{
|
||
wheely = 1;
|
||
}
|
||
else if (strcmp(str, "grab=yes") == 0)
|
||
{
|
||
grab_input = 1;
|
||
}
|
||
else if (strcmp(str, "grab=no") == 0 ||
|
||
strcmp(str, "nograb=yes") == 0)
|
||
{
|
||
grab_input = 0;
|
||
}
|
||
else if (strcmp(str, "nofancycursors=yes") == 0)
|
||
{
|
||
no_fancy_cursors = 1;
|
||
}
|
||
else if (strcmp(str, "nofancycursors=no") == 0 ||
|
||
strcmp(str, "fancycursors=yes") == 0)
|
||
{
|
||
no_fancy_cursors = 0;
|
||
}
|
||
else if (strcmp(str, "uppercase=yes") == 0)
|
||
{
|
||
only_uppercase = 1;
|
||
}
|
||
else if (strcmp(str, "uppercase=no") == 0 ||
|
||
strcmp(str, "mixedcase=yes") == 0)
|
||
{
|
||
only_uppercase = 0;
|
||
}
|
||
else if (strcmp(str, "noquit=yes") == 0)
|
||
{
|
||
disable_quit = 1;
|
||
}
|
||
else if (strcmp(str, "noquit=no") == 0 ||
|
||
strcmp(str, "quit=yes") == 0)
|
||
{
|
||
disable_quit = 0;
|
||
}
|
||
else if (strcmp(str, "nosave=yes") == 0)
|
||
{
|
||
disable_save = 1;
|
||
}
|
||
else if (strcmp(str, "nosave=no") == 0 ||
|
||
strcmp(str, "save=yes") == 0)
|
||
{
|
||
disable_save = 0;
|
||
}
|
||
else if (strcmp(str, "noprint=yes") == 0)
|
||
{
|
||
disable_print = 1;
|
||
}
|
||
else if (strcmp(str, "noprint=no") == 0 ||
|
||
strcmp(str, "print=yes") == 0)
|
||
{
|
||
disable_print = 0;
|
||
}
|
||
else if (strcmp(str, "nostamps=yes") == 0)
|
||
{
|
||
dont_load_stamps = 1;
|
||
}
|
||
else if (strcmp(str, "nostamps=no") == 0 ||
|
||
strcmp(str, "stamps=yes") == 0)
|
||
{
|
||
dont_load_stamps = 0;
|
||
}
|
||
else if (strcmp(str, "nosound=yes") == 0)
|
||
{
|
||
use_sound = 0;
|
||
}
|
||
else if (strcmp(str, "nosound=no") == 0 ||
|
||
strcmp(str, "sound=yes") == 0)
|
||
{
|
||
use_sound = 1;
|
||
}
|
||
else if (strcmp(str, "simpleshapes=yes") == 0)
|
||
{
|
||
simple_shapes = 1;
|
||
}
|
||
else if (strcmp(str, "simpleshapes=no") == 0 ||
|
||
strcmp(str, "complexshapes=yes") == 0)
|
||
{
|
||
simple_shapes = 1;
|
||
}
|
||
else if (strstr(str, "lang=") == str)
|
||
{
|
||
langstr = strdup(str + 5);
|
||
#ifdef DEBUG
|
||
printf("langstr set to: %s\n", langstr);
|
||
#endif
|
||
}
|
||
else if (strstr(str, "printdelay=") == str)
|
||
{
|
||
sscanf(str + 11, "%d", &print_delay);
|
||
#ifdef DEBUG
|
||
printf("Print delay set to %d seconds\n", print_delay);
|
||
#endif
|
||
}
|
||
else if (strcmp(str, "printcfg=yes") == 0)
|
||
{
|
||
#ifndef WIN32
|
||
fprintf(stderr, "Note: printcfg option only applies to Windows!\n");
|
||
#endif
|
||
use_print_config = 1;
|
||
}
|
||
else if (strcmp(str, "printcfg=no") == 0 ||
|
||
strcmp(str, "noprintcfg=yes") == 0)
|
||
{
|
||
#ifndef WIN32
|
||
fprintf(stderr, "Note: printcfg option only applies to Windows!\n");
|
||
#endif
|
||
use_print_config = 0;
|
||
}
|
||
else if (strstr(str, "printcommand=") == str)
|
||
{
|
||
printcommand = strdup(str + 13);
|
||
}
|
||
else if (strcmp(str, "saveover=yes") == 0)
|
||
{
|
||
promptless_save = SAVE_OVER_ALWAYS;
|
||
}
|
||
else if (strcmp(str, "saveover=ask") == 0)
|
||
{
|
||
/* (Default) */
|
||
|
||
promptless_save = SAVE_OVER_PROMPT;
|
||
}
|
||
else if (strcmp(str, "saveover=new") == 0)
|
||
{
|
||
promptless_save = SAVE_OVER_NO;
|
||
}
|
||
else if (strstr(str, "savedir=") == str)
|
||
{
|
||
savedir = strdup(str + 8);
|
||
remove_slash(savedir);
|
||
|
||
#ifdef DEBUG
|
||
printf("savedir set to: %s\n", savedir);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
while (!feof(fi));
|
||
}
|
||
|
||
|
||
#ifdef DEBUG
|
||
static char * debug_gettext(const char * str)
|
||
{
|
||
if (strcmp(str, dgettext(NULL, str)) == 0)
|
||
{
|
||
printf("NOTRANS: %s\n", str);
|
||
fflush(stdout);
|
||
}
|
||
|
||
return(dgettext(NULL, str));
|
||
}
|
||
#endif
|
||
|
||
|
||
static void do_setcursor(SDL_Cursor * c)
|
||
{
|
||
if (!no_fancy_cursors)
|
||
SDL_SetCursor(c);
|
||
}
|
||
|
||
|
||
static const char * great_str(void)
|
||
{
|
||
return(great_strs[rand() % (sizeof(great_strs) / sizeof(char *))]);
|
||
}
|
||
|
||
|
||
#ifdef DEBUG
|
||
static int charsize(char c)
|
||
{
|
||
Uint16 str[2];
|
||
int w, h;
|
||
|
||
str[0] = c;
|
||
str[1] = '\0';
|
||
|
||
TTF_SizeUNICODE(fonts[cur_font], str, &w, &h);
|
||
|
||
return w;
|
||
}
|
||
#endif
|
||
|
||
static void draw_image_title(int t, int x)
|
||
{
|
||
SDL_Rect dest;
|
||
|
||
dest.x = x;
|
||
dest.y = 0;
|
||
SDL_BlitSurface(img_title_on, NULL, screen, &dest);
|
||
|
||
dest.x = x + (96 - img_title_names[t]->w) / 2;;
|
||
dest.y = (40 - img_title_names[t]->h) / 2;
|
||
SDL_BlitSurface(img_title_names[t], NULL, screen, &dest);
|
||
}
|
||
|
||
|
||
|
||
static int need_own_font(int l)
|
||
{
|
||
int i, need;
|
||
|
||
need = 0;
|
||
|
||
for (i = 0; lang_use_own_font[i] != -1 && need == 0; i++)
|
||
{
|
||
if (lang_use_own_font[i] == l)
|
||
{
|
||
need = 1;
|
||
}
|
||
}
|
||
|
||
return need;
|
||
}
|
||
|
||
|
||
static int need_right_to_left(int l)
|
||
{
|
||
int i, need;
|
||
|
||
need = 0;
|
||
|
||
for (i = 0; lang_use_right_to_left[i] != -1 && need == 0; i++)
|
||
{
|
||
if (lang_use_right_to_left[i] == l)
|
||
{
|
||
need = 1;
|
||
}
|
||
}
|
||
|
||
return need;
|
||
}
|
||
|
||
|
||
|
||
/* Handle keyboard events to control the mouse: */
|
||
|
||
static void handle_keymouse(SDLKey key, Uint8 updown)
|
||
{
|
||
SDL_Event event;
|
||
|
||
if (keymouse)
|
||
{
|
||
if (key == SDLK_LEFT)
|
||
mousekey_left = updown;
|
||
else if (key == SDLK_RIGHT)
|
||
mousekey_right = updown;
|
||
else if (key == SDLK_UP)
|
||
mousekey_up = updown;
|
||
else if (key == SDLK_DOWN)
|
||
mousekey_down = updown;
|
||
else if (key == SDLK_SPACE)
|
||
{
|
||
if (updown == SDL_KEYDOWN)
|
||
event.type = SDL_MOUSEBUTTONDOWN;
|
||
else
|
||
event.type = SDL_MOUSEBUTTONUP;
|
||
|
||
event.button.x = mouse_x;
|
||
event.button.y = mouse_y;
|
||
event.button.button = 1;
|
||
|
||
SDL_PushEvent(&event);
|
||
}
|
||
|
||
if (mousekey_up == SDL_KEYDOWN && mouse_y > 0)
|
||
mouse_y = mouse_y - 8;
|
||
else if (mousekey_down == SDL_KEYDOWN && mouse_y < WINDOW_HEIGHT - 1)
|
||
mouse_y = mouse_y + 8;
|
||
|
||
if (mousekey_left == SDL_KEYDOWN && mouse_x > 0)
|
||
mouse_x = mouse_x - 8;
|
||
if (mousekey_right == SDL_KEYDOWN && mouse_x < WINDOW_WIDTH - 1)
|
||
mouse_x = mouse_x + 8;
|
||
|
||
SDL_WarpMouse(mouse_x, mouse_y);
|
||
}
|
||
}
|
||
|
||
|
||
/* Unblank screen in fullscreen mode, if needed: */
|
||
|
||
static void handle_active( SDL_Event *event )
|
||
{
|
||
if (event->active.state & SDL_APPACTIVE)
|
||
{
|
||
if (event->active.gain == 1 )
|
||
{
|
||
if ( fullscreen )
|
||
SDL_Flip(screen);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/* removes a single '\' or '/' from end of path */
|
||
|
||
static char *remove_slash( char *path )
|
||
{
|
||
int len = strlen(path);
|
||
|
||
if (!len)
|
||
return path;
|
||
|
||
if (path[len-1] == '/' || path[len-1] == '\\')
|
||
path[len-1] = 0;
|
||
|
||
return path;
|
||
}
|
||
|
||
|
||
/* For right-to-left languages, when word-wrapping, we need to
|
||
make sure the text doesn't end up going from bottom-to-top, too! */
|
||
|
||
static void anti_carriage_return(int left, int right, int cur_top, int new_top,
|
||
int cur_bot, int line_width)
|
||
{
|
||
SDL_Rect src, dest;
|
||
|
||
|
||
/* Move current set of text down one line (and right-justify it!): */
|
||
|
||
src.x = left;
|
||
src.y = cur_top;
|
||
src.w = line_width;
|
||
src.h = cur_bot - cur_top;
|
||
|
||
dest.x = right - line_width;
|
||
dest.y = new_top;
|
||
|
||
SDL_BlitSurface(screen, &src, screen, &dest);
|
||
|
||
|
||
/* Clear the top line for new text: */
|
||
|
||
dest.x = left;
|
||
dest.y = cur_top;
|
||
dest.w = right - left;
|
||
dest.h = new_top - cur_top;
|
||
|
||
SDL_FillRect(screen, &dest, SDL_MapRGB(screen->format, 255, 255, 255));
|
||
}
|
||
|
||
|
||
static int mySDL_WaitEvent(SDL_Event *event)
|
||
{
|
||
int ret;
|
||
|
||
|
||
if (playing)
|
||
{
|
||
if (!feof(demofi))
|
||
{
|
||
ret = 1;
|
||
fread(event, sizeof(SDL_Event), 1, demofi);
|
||
}
|
||
else
|
||
{
|
||
/* All done! Back to normal! */
|
||
|
||
printf("(Done playing playback file '%s')\n", playfile);
|
||
|
||
ret = 0;
|
||
playing = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ret = SDL_WaitEvent(event);
|
||
|
||
if (recording)
|
||
{
|
||
fwrite(event, sizeof(SDL_Event), 1, demofi);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
static int mySDL_PollEvent(SDL_Event *event)
|
||
{
|
||
int ret;
|
||
|
||
if (playing)
|
||
{
|
||
if (!feof(demofi))
|
||
{
|
||
ret = 1;
|
||
fread(event, sizeof(SDL_Event), 1, demofi);
|
||
}
|
||
else
|
||
{
|
||
/* All done! Back to normal! */
|
||
|
||
printf("(Done playing playback file '%s')\n", playfile);
|
||
|
||
ret = 0;
|
||
playing = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ret = SDL_PollEvent(event);
|
||
|
||
if (recording && ret > 0)
|
||
{
|
||
fwrite(event, sizeof(SDL_Event), 1, demofi);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
static void load_starter_id(char * saved_id)
|
||
{
|
||
char * rname;
|
||
char fname[32];
|
||
FILE * fi;
|
||
|
||
snprintf(fname, sizeof(fname), "saved/%s.dat", saved_id);
|
||
rname = get_fname(fname);
|
||
|
||
starter_id[0] = '\0';
|
||
|
||
fi = fopen(rname, "r");
|
||
if (fi != NULL)
|
||
{
|
||
fgets(starter_id, sizeof(starter_id), fi);
|
||
starter_id[strlen(starter_id) - 1] = '\0';
|
||
|
||
fscanf(fi, "%d", &starter_mirrored);
|
||
fscanf(fi, "%d", &starter_flipped);
|
||
|
||
fclose(fi);
|
||
}
|
||
|
||
free(rname);
|
||
}
|
||
|
||
static void load_starter(char * img_id)
|
||
{
|
||
char * dirname;
|
||
char fname[256];
|
||
SDL_Surface * tmp_surf;
|
||
SDL_Rect dest;
|
||
|
||
|
||
/* Determine path to starter files: */
|
||
|
||
/* FIXME: On Windows, MacOSX, BeOS, etc. -- do it their way! */
|
||
#if defined(WIN32) || defined(__BEOS__)
|
||
dirname = strdup(DATA_PREFIX "starters");
|
||
#else
|
||
dirname = strdup("/usr/local/share/tuxpaint/starters");
|
||
#endif
|
||
|
||
|
||
/* Clear them to NULL first: */
|
||
|
||
img_starter = NULL;
|
||
img_starter_bkgd = NULL;
|
||
|
||
|
||
/* Load the core image: */
|
||
|
||
snprintf(fname, sizeof(fname), "%s/%s.png", dirname, img_id);
|
||
tmp_surf = IMG_Load(fname);
|
||
|
||
if (tmp_surf != NULL)
|
||
{
|
||
img_starter = SDL_DisplayFormatAlpha(tmp_surf);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
|
||
if (img_starter != NULL &&
|
||
(img_starter->w != canvas->w || img_starter->h != canvas->h))
|
||
{
|
||
tmp_surf = img_starter;
|
||
|
||
img_starter = SDL_CreateRGBSurface(canvas->flags,
|
||
canvas->w, canvas->h,
|
||
tmp_surf->format->BitsPerPixel,
|
||
tmp_surf->format->Rmask,
|
||
tmp_surf->format->Gmask,
|
||
tmp_surf->format->Bmask,
|
||
tmp_surf->format->Amask);
|
||
|
||
SDL_SetAlpha(tmp_surf, 0, 0);
|
||
|
||
if (img_starter != NULL)
|
||
{
|
||
dest.x = (canvas->w - tmp_surf->w) / 2;
|
||
dest.y = (canvas->h - tmp_surf->h) / 2;
|
||
|
||
SDL_BlitSurface(tmp_surf, NULL, img_starter, &dest);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
}
|
||
|
||
|
||
/* Try to load the a background image: */
|
||
|
||
/* (JPEG first) */
|
||
snprintf(fname, sizeof(fname), "%s/%s-back.jpeg", dirname, img_id);
|
||
tmp_surf = IMG_Load(fname);
|
||
|
||
/* (Failed? Try PNG next) */
|
||
if (tmp_surf == NULL)
|
||
{
|
||
snprintf(fname, sizeof(fname), "%s/%s-back.png", dirname, img_id);
|
||
tmp_surf = IMG_Load(fname);
|
||
}
|
||
|
||
if (tmp_surf != NULL)
|
||
{
|
||
img_starter_bkgd = SDL_DisplayFormat(tmp_surf);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
|
||
if (img_starter_bkgd != NULL &&
|
||
(img_starter_bkgd->w != canvas->w || img_starter_bkgd->h != canvas->h))
|
||
{
|
||
tmp_surf = img_starter_bkgd;
|
||
|
||
img_starter_bkgd = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||
canvas->w, canvas->h,
|
||
canvas->format->BitsPerPixel,
|
||
canvas->format->Rmask,
|
||
canvas->format->Gmask,
|
||
canvas->format->Bmask,
|
||
0);
|
||
|
||
if (img_starter_bkgd != NULL)
|
||
{
|
||
dest.x = (canvas->w - tmp_surf->w) / 2;
|
||
dest.y = (canvas->h - tmp_surf->h) / 2;
|
||
|
||
SDL_BlitSurface(tmp_surf, NULL, img_starter_bkgd, &dest);
|
||
SDL_FreeSurface(tmp_surf);
|
||
}
|
||
}
|
||
|
||
free(dirname);
|
||
}
|
||
|
||
|
||
static TTF_Font *try_alternate_font(int language)
|
||
{
|
||
char str[128];
|
||
char prefix[64];
|
||
char *p;
|
||
|
||
strcpy(prefix, lang_prefixes[language]);
|
||
if ((p = strrchr(prefix, '_')) != NULL)
|
||
{
|
||
*p = 0;
|
||
snprintf(str, sizeof(str), "%sfonts/locale/%s.ttf",
|
||
DATA_PREFIX, prefix);
|
||
|
||
return TTF_OpenFont(str, 18);
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
static SDL_Surface * duplicate_surface(SDL_Surface * orig)
|
||
{
|
||
/*
|
||
Uint32 amask;
|
||
|
||
amask = ~(orig->format->Rmask |
|
||
orig->format->Gmask |
|
||
orig->format->Bmask);
|
||
|
||
return(SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||
orig->w, orig->h,
|
||
orig->format->BitsPerPixel,
|
||
orig->format->Rmask,
|
||
orig->format->Gmask,
|
||
orig->format->Bmask,
|
||
amask));
|
||
*/
|
||
|
||
return(SDL_DisplayFormatAlpha(orig));
|
||
}
|
||
|
||
static void mirror_starter(void)
|
||
{
|
||
SDL_Surface * orig;
|
||
int x;
|
||
SDL_Rect src, dest;
|
||
|
||
|
||
/* Mirror overlay: */
|
||
|
||
orig = img_starter;
|
||
img_starter = duplicate_surface(orig);
|
||
|
||
if (img_starter != NULL)
|
||
{
|
||
for (x = 0; x < orig->w; x++)
|
||
{
|
||
src.x = x;
|
||
src.y = 0;
|
||
src.w = 1;
|
||
src.h = orig->h;
|
||
|
||
dest.x = orig->w - x - 1;
|
||
dest.y = 0;
|
||
|
||
SDL_BlitSurface(orig, &src, img_starter, &dest);
|
||
}
|
||
|
||
SDL_FreeSurface(orig);
|
||
}
|
||
else
|
||
{
|
||
img_starter = orig;
|
||
}
|
||
|
||
|
||
/* Mirror background: */
|
||
|
||
if (img_starter_bkgd != NULL)
|
||
{
|
||
orig = img_starter_bkgd;
|
||
img_starter_bkgd = duplicate_surface(orig);
|
||
|
||
if (img_starter_bkgd != NULL)
|
||
{
|
||
for (x = 0; x < orig->w; x++)
|
||
{
|
||
src.x = x;
|
||
src.y = 0;
|
||
src.w = 1;
|
||
src.h = orig->h;
|
||
|
||
dest.x = orig->w - x - 1;
|
||
dest.y = 0;
|
||
|
||
SDL_BlitSurface(orig, &src, img_starter_bkgd, &dest);
|
||
}
|
||
|
||
SDL_FreeSurface(orig);
|
||
}
|
||
else
|
||
{
|
||
img_starter_bkgd = orig;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
static void flip_starter(void)
|
||
{
|
||
SDL_Surface * orig;
|
||
int y;
|
||
SDL_Rect src, dest;
|
||
|
||
|
||
/* Flip overlay: */
|
||
|
||
orig = img_starter;
|
||
img_starter = duplicate_surface(orig);
|
||
|
||
if (img_starter != NULL)
|
||
{
|
||
for (y = 0; y < orig->h; y++)
|
||
{
|
||
src.x = 0;
|
||
src.y = y;
|
||
src.w = orig->w;
|
||
src.h = 1;
|
||
|
||
dest.x = 0;
|
||
dest.y = orig->h - y - 1;
|
||
|
||
SDL_BlitSurface(orig, &src, img_starter, &dest);
|
||
}
|
||
|
||
SDL_FreeSurface(orig);
|
||
}
|
||
else
|
||
{
|
||
img_starter = orig;
|
||
}
|
||
|
||
|
||
/* Flip background: */
|
||
|
||
if (img_starter_bkgd != NULL)
|
||
{
|
||
orig = img_starter_bkgd;
|
||
img_starter_bkgd = duplicate_surface(orig);
|
||
|
||
if (img_starter_bkgd != NULL)
|
||
{
|
||
for (y = 0; y < orig->h; y++)
|
||
{
|
||
src.x = 0;
|
||
src.y = y;
|
||
src.w = orig->w;
|
||
src.h = 1;
|
||
|
||
dest.x = 0;
|
||
dest.y = orig->h - y - 1;
|
||
|
||
SDL_BlitSurface(orig, &src, img_starter_bkgd, &dest);
|
||
}
|
||
|
||
SDL_FreeSurface(orig);
|
||
}
|
||
else
|
||
{
|
||
img_starter_bkgd = orig;
|
||
}
|
||
}
|
||
}
|
||
|