#ifdef TCOD_SDL2
#include <mouse.h>
#include <sys.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <console.h>
#include <libtcod_int.h>
#include <parser.h>
static TCOD_SDL_driver_t *sdl=NULL;
#ifdef TCOD_WINDOWS
#include <windows.h>
BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD reason, LPVOID reserved) {
switch (reason ) {
case DLL_PROCESS_ATTACH : sdl = SDL_implementation_factory(); break;
default : break;
}
return TRUE;
}
#else
void __attribute__ ((constructor)) DllMain(void) {
sdl = SDL_implementation_factory();
}
#endif
#if defined(__ANDROID__)
#define TCOD_TOUCH_INPUT
#define MAX_TOUCH_FINGERS 5
typedef struct {
int nupdates;
uint32_t ticks0;
SDL_FingerID finger_id;
int coords[MAX_TOUCH_FINGERS][2];
int coords_delta[MAX_TOUCH_FINGERS][2];
int consolecoords[MAX_TOUCH_FINGERS][2];
int consolecoords_delta[MAX_TOUCH_FINGERS][2];
int nfingers;
int nfingerspressed;
SDL_FingerID finger_ids[MAX_TOUCH_FINGERS];
char fingerspressed[MAX_TOUCH_FINGERS];
} TCOD_touch_t;
#endif
bool TCOD_sys_check_bmp(const char *filename);
SDL_Surface *TCOD_sys_read_bmp(const char *filename);
void TCOD_sys_write_bmp(const SDL_Surface *surf, const char *filename);
bool TCOD_sys_check_png(const char *filename);
SDL_Surface *TCOD_sys_read_png(const char *filename);
void TCOD_sys_write_png(const SDL_Surface *surf, const char *filename);
typedef struct {
char *extension;
bool (*check_type)(const char *filename);
SDL_Surface *(*read)(const char *filename);
void (*write)(const SDL_Surface *surf, const char *filename);
} image_support_t;
static image_support_t image_type[] = {
{ "BMP", TCOD_sys_check_bmp, TCOD_sys_read_bmp, TCOD_sys_write_bmp },
{ "PNG", TCOD_sys_check_png, TCOD_sys_read_png, TCOD_sys_write_png },
{ NULL, NULL, NULL, NULL },
};
scale_data_t scale_data={0};
SDL_Window* window=NULL;
SDL_Renderer* renderer=NULL;
float scale_factor=1.0f;
SDL_Surface* charmap=NULL;
char *last_clipboard_text = NULL;
static bool has_startup=false;
#define MAX_SCALE_FACTOR 5.0f
static TCOD_color_t fontKeyCol={0,0,0};
static uint32_t sdl_key=0, rgb_mask=0, nrgb_mask=0;
static bool mousebl=false;
static bool mousebm=false;
static bool mousebr=false;
static bool mouse_force_bl=false;
static bool mouse_force_bm=false;
static bool mouse_force_br=false;
#ifdef TCOD_TOUCH_INPUT
static bool mouse_touch=true;
#endif
static int min_frame_length=0;
static int min_frame_length_backup=0;
static int fps=0;
static int cur_fps=0;
static float last_frame_length=0.0f;
static TCOD_color_t *charcols=NULL;
static bool *first_draw=NULL;
static bool key_status[TCODK_CHAR+1];
int oldFade=-1;
typedef struct {
SDL_Keycode sdl_key;
int tcod_key;
} vk_to_c_entry;
#define NUM_VK_TO_C_ENTRIES 10
static vk_to_c_entry vk_to_c[NUM_VK_TO_C_ENTRIES];
static int init_ascii_to_tcod[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 77, 0, 0, 0, 0, 0,
71, 70, 72, 0, 0, 0, 0, 0, 64, 65, 67, 66, 0, 73, 68, 69,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,
111,112,113,114,115,116,117,118,119,120,121, 33, 34, 35, 36, 37,
38,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,
143,144,145,146,147,148,149,150,151,152,153, 39, 40, 41, 42, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43, 44, 45, 46, 49, 0, 0, 0, 0, 81, 78, 87, 88, 0, 0, 55,
53, 50, 52, 51, 47, 48, 0, 0, 85, 86, 82, 84, 83, 79, 80, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 54, 0, 0, 0, 0, 0,
74, 75, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static void alloc_ascii_tables(void) {
if ( TCOD_ctx.ascii_to_tcod ) free(TCOD_ctx.ascii_to_tcod);
if ( charcols ) {
free(charcols);
free(first_draw);
}
TCOD_ctx.ascii_to_tcod = (int *)calloc(sizeof(int),TCOD_ctx.max_font_chars);
charcols = (TCOD_color_t *)calloc(sizeof(TCOD_color_t),TCOD_ctx.max_font_chars);
first_draw =(bool *)calloc(sizeof(bool),TCOD_ctx.max_font_chars);
memcpy(TCOD_ctx.ascii_to_tcod,init_ascii_to_tcod,sizeof(int)*256);
}
static void check_ascii_to_tcod(void) {
if ( TCOD_ctx.fontNbCharHoriz * TCOD_ctx.fontNbCharVertic != TCOD_ctx.max_font_chars ) {
TCOD_ctx.max_font_chars=TCOD_ctx.fontNbCharHoriz * TCOD_ctx.fontNbCharVertic;
alloc_ascii_tables();
}
}
void TCOD_sys_register_SDL_renderer(SDL_renderer_t renderer) {
TCOD_ctx.sdl_cbk=renderer;
}
void TCOD_sys_map_ascii_to_font(int asciiCode, int fontCharX, int fontCharY) {
if ( asciiCode > 0 && asciiCode < TCOD_ctx.max_font_chars )
TCOD_ctx.ascii_to_tcod[asciiCode] = fontCharX + fontCharY * TCOD_ctx.fontNbCharHoriz;
}
void TCOD_sys_load_font(void) {
int i;
bool hasTransparent=false;
int x,y;
if ( charmap ) SDL_FreeSurface(charmap);
charmap=TCOD_sys_load_image(TCOD_ctx.font_file);
if (charmap == NULL ) TCOD_fatal("SDL : cannot load %s",TCOD_ctx.font_file);
if ( (float)(charmap->w / TCOD_ctx.fontNbCharHoriz) != charmap->w / TCOD_ctx.fontNbCharHoriz
|| (float)(charmap->h / TCOD_ctx.fontNbCharVertic) != charmap->h / TCOD_ctx.fontNbCharVertic ) TCOD_fatal(" %s size is not a multiple of font layout (%dx%d)\n",
TCOD_ctx.font_file,TCOD_ctx.fontNbCharHoriz,TCOD_ctx.fontNbCharVertic);
TCOD_ctx.font_width=charmap->w/TCOD_ctx.fontNbCharHoriz;
TCOD_ctx.font_height=charmap->h/TCOD_ctx.fontNbCharVertic;
if ( TCOD_ctx.colored ) free(TCOD_ctx.colored);
TCOD_ctx.colored=(bool *)calloc(sizeof(bool), TCOD_ctx.fontNbCharHoriz*TCOD_ctx.fontNbCharVertic);
check_ascii_to_tcod();
if ( charmap->format->BytesPerPixel == 4 ) {
printf ("32bits font... checking for alpha layer... ");
for (x=0; !hasTransparent && x < charmap->w; x ++ ) {
for (y=0;!hasTransparent && y < charmap->h; y++ ) {
uint8_t*pixel=(uint8_t*)(charmap->pixels) + y * charmap->pitch + x * charmap->format->BytesPerPixel;
uint8_t alpha=*((pixel)+charmap->format->Ashift/8);
if ( alpha < 255 ) {
hasTransparent=true;
}
}
}
printf (hasTransparent ? "present\n" : "not present\n");
} else if ( charmap->format->BytesPerPixel != 3 ) {
SDL_Surface *temp;
printf ("font bpp < 24. converting to 24bits\n");
temp=(SDL_Surface *)TCOD_sys_get_surface(charmap->w,charmap->h,false);
SDL_BlitSurface(charmap,NULL,temp,NULL);
SDL_FreeSurface(charmap);
charmap=temp;
} else {
printf ("24 bits font.\n");
}
if (! hasTransparent ) {
int keyx,keyy;
uint8_t*pixel;
if ( TCOD_ctx.font_tcod_layout ) {
keyx = TCOD_ctx.font_width/2;
keyy = TCOD_ctx.font_height/2;
} else if (TCOD_ctx.font_in_row) {
keyx = ((int)(' ') % TCOD_ctx.fontNbCharHoriz ) * TCOD_ctx.font_width + TCOD_ctx.font_width/2;
keyy = ((int)(' ') / TCOD_ctx.fontNbCharHoriz ) * TCOD_ctx.font_height + TCOD_ctx.font_height/2;
} else {
keyx = ((int)(' ') / TCOD_ctx.fontNbCharVertic ) * TCOD_ctx.font_width + TCOD_ctx.font_width/2;
keyy = ((int)(' ') % TCOD_ctx.fontNbCharVertic ) * TCOD_ctx.font_height + TCOD_ctx.font_height/2;
}
pixel=(uint8_t*)(charmap->pixels) + keyy * charmap->pitch + keyx * charmap->format->BytesPerPixel;
fontKeyCol.r=*((pixel)+charmap->format->Rshift/8);
fontKeyCol.g=*((pixel)+charmap->format->Gshift/8);
fontKeyCol.b=*((pixel)+charmap->format->Bshift/8);
printf ("key color : %d %d %d\n",fontKeyCol.r,fontKeyCol.g,fontKeyCol.b);
if ( ! TCOD_ctx.font_greyscale && charmap->format->BytesPerPixel == 4 ) {
SDL_Surface *temp;
printf ("32bits font with no alpha => converting to faster 24 bits\n");
temp=(SDL_Surface *)TCOD_sys_get_surface(charmap->w,charmap->h,false);
SDL_BlitSurface(charmap,NULL,temp,NULL);
SDL_FreeSurface(charmap);
charmap=temp;
}
}
for (i=0; i < TCOD_ctx.fontNbCharHoriz*TCOD_ctx.fontNbCharVertic; i++ ) {
int px,py,cx,cy;
bool end=false;
cx=(i%TCOD_ctx.fontNbCharHoriz);
cy=(i/TCOD_ctx.fontNbCharHoriz);
for( px=0; !end && px < TCOD_ctx.font_width; px++ ) {
for (py=0; !end && py < TCOD_ctx.font_height; py++ ) {
uint8_t*pixel=(uint8_t*)(charmap->pixels) + (cy*TCOD_ctx.font_height+py) * charmap->pitch
+ (cx*TCOD_ctx.font_width+px) * charmap->format->BytesPerPixel;
uint8_t r=*((pixel)+charmap->format->Rshift/8);
uint8_t g=*((pixel)+charmap->format->Gshift/8);
uint8_t b=*((pixel)+charmap->format->Bshift/8);
if ( charmap->format->BytesPerPixel == 3 ) {
if ( r == fontKeyCol.r && g == fontKeyCol.g && b == fontKeyCol.b ) continue;
}
if ( r != g || g !=b || b != r ) {
TCOD_ctx.colored[i]=true;
printf ("character for ascii code %d is colored\n",i);
end=true;
}
}
}
}
if ( ! hasTransparent && TCOD_ctx.font_greyscale ) {
bool invert=( fontKeyCol.r > 128 );
if ( charmap->format->BytesPerPixel != 4 ) {
SDL_Surface *temp;
printf("24bits greyscale font. converting to 32bits\n");
temp=(SDL_Surface *)TCOD_sys_get_surface(charmap->w,charmap->h,true);
SDL_BlitSurface(charmap,NULL,temp,NULL);
SDL_FreeSurface(charmap);
charmap=temp;
}
for (i=0; i < TCOD_ctx.fontNbCharHoriz*TCOD_ctx.fontNbCharVertic; i++ ) {
int cx,cy;
cx=(i%TCOD_ctx.fontNbCharHoriz);
cy=(i/TCOD_ctx.fontNbCharHoriz);
for (x=cx*TCOD_ctx.font_width; x < (cx+1)*TCOD_ctx.font_width; x ++ ) {
for (y=cy*TCOD_ctx.font_height;y < (cy+1)*TCOD_ctx.font_height; y++ ) {
if ( ! TCOD_ctx.colored[i]) {
uint8_t*pixel=(uint8_t*)(charmap->pixels) + y * charmap->pitch + x * charmap->format->BytesPerPixel;
uint8_t r=*((pixel)+charmap->format->Rshift/8);
*((pixel)+charmap->format->Ashift/8) = (invert ? 255-r : r);
*((pixel)+charmap->format->Rshift/8)=255;
*((pixel)+charmap->format->Gshift/8)=255;
*((pixel)+charmap->format->Bshift/8)=255;
} else {
uint8_t*pixel=(uint8_t*)(charmap->pixels) + y * charmap->pitch + x * charmap->format->BytesPerPixel;
uint8_t r=*((pixel)+charmap->format->Rshift/8);
uint8_t g=*((pixel)+charmap->format->Gshift/8);
uint8_t b=*((pixel)+charmap->format->Bshift/8);
if ( r == fontKeyCol.r && g == fontKeyCol.g && b == fontKeyCol.b ) {
*((pixel)+charmap->format->Ashift/8) = 0;
} else {
*((pixel)+charmap->format->Ashift/8) = 255;
}
}
}
}
}
}
sdl_key=SDL_MapRGB(charmap->format,fontKeyCol.r,fontKeyCol.g,fontKeyCol.b);
rgb_mask=charmap->format->Rmask|charmap->format->Gmask|charmap->format->Bmask;
nrgb_mask = ~ rgb_mask;
sdl_key &= rgb_mask;
if ( charmap->format->BytesPerPixel == 3 ) SDL_SetColorKey(charmap,SDL_TRUE|SDL_RLEACCEL,sdl_key);
for (i=0; i < TCOD_ctx.fontNbCharHoriz*TCOD_ctx.fontNbCharVertic; i++ ) {
charcols[i]=fontKeyCol;
first_draw[i]=true;
}
check_ascii_to_tcod();
if (!TCOD_ctx.font_tcod_layout) {
if ( TCOD_ctx.font_in_row ) {
for (i=0; i < TCOD_ctx.max_font_chars; i++ ) TCOD_ctx.ascii_to_tcod[i]=i;
} else {
for (i=0; i < TCOD_ctx.max_font_chars; i++ ) {
int fy = i % TCOD_ctx.fontNbCharVertic;
int fx = i / TCOD_ctx.fontNbCharVertic;
TCOD_ctx.ascii_to_tcod[i]=fx + fy * TCOD_ctx.fontNbCharHoriz;
}
}
}
}
void TCOD_sys_set_custom_font(const char *fontFile,int nb_ch, int nb_cv, int flags) {
strcpy(TCOD_ctx.font_file,fontFile);
if (flags == 0 || flags == TCOD_FONT_TYPE_GREYSCALE) flags |= TCOD_FONT_LAYOUT_ASCII_INCOL;
TCOD_ctx.font_in_row=((flags & TCOD_FONT_LAYOUT_ASCII_INROW) != 0);
TCOD_ctx.font_greyscale = ((flags & TCOD_FONT_TYPE_GREYSCALE) != 0 );
TCOD_ctx.font_tcod_layout = ((flags & TCOD_FONT_LAYOUT_TCOD) != 0 );
if ( nb_ch> 0 ) {
TCOD_ctx.fontNbCharHoriz=nb_ch;
TCOD_ctx.fontNbCharVertic=nb_cv;
} else {
if ( ( flags & TCOD_FONT_LAYOUT_ASCII_INROW ) || ( flags & TCOD_FONT_LAYOUT_ASCII_INCOL ) ) {
TCOD_ctx.fontNbCharHoriz=16;
TCOD_ctx.fontNbCharVertic=16;
} else {
TCOD_ctx.fontNbCharHoriz=32;
TCOD_ctx.fontNbCharVertic=8;
}
}
if ( TCOD_ctx.font_tcod_layout ) TCOD_ctx.font_in_row=true;
check_ascii_to_tcod();
}
void find_resolution(void) {
TCOD_ctx.actual_fullscreen_width=TCOD_ctx.fullscreen_width>TCOD_ctx.root->w*TCOD_ctx.font_width?TCOD_ctx.fullscreen_width:TCOD_ctx.root->w*TCOD_ctx.font_width;
TCOD_ctx.actual_fullscreen_height=TCOD_ctx.fullscreen_height>TCOD_ctx.root->h*TCOD_ctx.font_height?TCOD_ctx.fullscreen_height:TCOD_ctx.root->h*TCOD_ctx.font_height;
sdl->get_closest_mode(&TCOD_ctx.actual_fullscreen_width,&TCOD_ctx.actual_fullscreen_height);
}
void *TCOD_sys_create_bitmap_for_console(TCOD_console_t console) {
int w,h;
w = TCOD_console_get_width(console) * TCOD_ctx.font_width;
h = TCOD_console_get_height(console) * TCOD_ctx.font_height;
return TCOD_sys_get_surface(w,h,false);
}
static void TCOD_sys_render(void *vbitmap, TCOD_console_data_t* console) {
sdl->render(sdl, vbitmap, console);
}
void TCOD_sys_console_to_bitmap(void *vbitmap,
TCOD_console_data_t* console, TCOD_console_data_t* cache) {
static SDL_Surface *charmap_backup=NULL;
SDL_Surface *bitmap = (SDL_Surface *)vbitmap;
int x,y;
uint32_t sdl_back=0, sdl_fore=0;
TCOD_color_t fading_color = TCOD_console_get_fading_color();
int fade = (int)TCOD_console_get_fade();
bool track_changes = (cache && oldFade == fade);
uint8_t bpp = charmap->format->BytesPerPixel;
int *c = console->ch_array;
int *oc;
TCOD_color_t *ofg, *obg, *nfg, *nbg;
int hdelta;
if ( bpp == 4 ) {
hdelta=(charmap->pitch - TCOD_ctx.font_width*bpp)/4;
} else {
hdelta=(charmap->pitch - TCOD_ctx.font_width*bpp);
}
nfg = TCOD_image_get_colors(console->fg_colors);
nbg = TCOD_image_get_colors(console->bg_colors);
if (track_changes) {
oc = cache->ch_array;
ofg = TCOD_image_get_colors(cache->fg_colors);
obg = TCOD_image_get_colors(cache->bg_colors);
}
if ( charmap_backup == NULL ) {
charmap_backup=(SDL_Surface *)TCOD_sys_get_surface(charmap->w,charmap->h,true);
SDL_BlitSurface(charmap,NULL,charmap_backup,NULL);
}
#ifdef USE_SDL_LOCKS
if ( SDL_MUSTLOCK( bitmap ) && SDL_LockSurface( bitmap ) < 0 ) return;
#endif
for (y = 0; y < console->h; y++) {
for (x = 0; x < console->w; x++) {
SDL_Rect srcRect,dstRect;
bool changed=true;
if ( track_changes ) {
changed=false;
if (
nbg->r != obg->r || nbg->g != obg->g || nbg->b != obg->b ||
nfg->r != ofg->r || nfg->g != ofg->g || nfg->b != ofg->b ||
*c != *oc) {
changed=true;
}
}
if ( changed ) {
TCOD_color_t b=*nbg;
dstRect.x=x*TCOD_ctx.font_width;
dstRect.y=y*TCOD_ctx.font_height;
dstRect.w=TCOD_ctx.font_width;
dstRect.h=TCOD_ctx.font_height;
if ( fade != 255 ) {
b.r = ((int)b.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255;
b.g = ((int)b.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255;
b.b = ((int)b.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255;
}
sdl_back=SDL_MapRGB(bitmap->format,b.r,b.g,b.b);
SDL_FillRect(bitmap,&dstRect,sdl_back);
if ( *c != ' ' ) {
int ascii = TCOD_ctx.ascii_to_tcod[*c];
TCOD_color_t *curtext = &charcols[ascii];
bool first = first_draw[ascii];
TCOD_color_t f=*nfg;
if ( fade != 255 ) {
f.r = ((int)f.r) * fade / 255 + ((int)fading_color.r) * (255-fade)/255;
f.g = ((int)f.g) * fade / 255 + ((int)fading_color.g) * (255-fade)/255;
f.b = ((int)f.b) * fade / 255 + ((int)fading_color.b) * (255-fade)/255;
}
if ( f.r != b.r || f.g != b.g || f.b != b.b ) {
if ( charmap->format->Amask == 0
&& f.r == fontKeyCol.r && f.g == fontKeyCol.g && f.b == fontKeyCol.b ) {
if ( f.r < 255 ) f.r++; else f.r--;
}
srcRect.x = (ascii%TCOD_ctx.fontNbCharHoriz)*TCOD_ctx.font_width;
srcRect.y = (ascii/TCOD_ctx.fontNbCharHoriz)*TCOD_ctx.font_height;
srcRect.w=TCOD_ctx.font_width;
srcRect.h=TCOD_ctx.font_height;
if ( charmap && (first || curtext->r != f.r || curtext->g != f.g || curtext->b!=f.b) ) {
first_draw[ascii]=false;
sdl_fore=SDL_MapRGB(charmap->format,f.r,f.g,f.b) & rgb_mask;
*curtext=f;
#ifdef USE_SDL_LOCKS
if ( SDL_MUSTLOCK(charmap) ) {
if ( SDL_LockSurface(charmap) < 0 ) return;
}
#endif
if ( bpp == 4 ) {
uint32_t *pix = (uint32_t *)(((uint8_t*)charmap->pixels)+srcRect.x*bpp + srcRect.y*charmap->pitch);
int h=TCOD_ctx.font_height;
if ( ! TCOD_ctx.colored[ascii] ) {
while ( h-- ) {
int w=TCOD_ctx.font_width;
while ( w-- ) {
(*pix) &= nrgb_mask;
(*pix) |= sdl_fore;
pix++;
}
pix += hdelta;
}
} else {
uint32_t *pixorig = (uint32_t *)(((uint8_t*)charmap_backup->pixels)+srcRect.x*bpp + srcRect.y*charmap_backup->pitch);
int hdelta_backup=(charmap_backup->pitch - TCOD_ctx.font_width*4)/4;
while (h> 0) {
int w=TCOD_ctx.font_width;
while ( w > 0 ) {
int r=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Rshift/8));
int g=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Gshift/8));
int b=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Bshift/8));
(*pix) &= nrgb_mask;
r = r * f.r / 255;
g = g * f.g / 255;
b = b * f.b / 255;
(*pix) |= (r<<charmap->format->Rshift)|(g<<charmap->format->Gshift)|(b<<charmap->format->Bshift);
w--;
pix++;
pixorig++;
}
h--;
pix += hdelta;
pixorig += hdelta_backup;
}
}
} else {
uint32_t *pix = (uint32_t *)(((uint8_t*)charmap->pixels)+srcRect.x*bpp + srcRect.y*charmap->pitch);
int h=TCOD_ctx.font_height;
if ( ! TCOD_ctx.colored[ascii] ) {
while ( h-- ) {
int w=TCOD_ctx.font_width;
while ( w-- ) {
if (((*pix) & rgb_mask) != sdl_key ) {
(*pix) &= nrgb_mask;
(*pix) |= sdl_fore;
}
pix = (uint32_t *) (((uint8_t*)pix)+3);
}
pix = (uint32_t *) (((uint8_t*)pix)+hdelta);
}
} else {
uint32_t *pixorig = (uint32_t *)(((uint8_t*)charmap_backup->pixels)+srcRect.x*4 + srcRect.y*charmap_backup->pitch);
int hdelta_backup=(charmap_backup->pitch - TCOD_ctx.font_width*4)/4;
while (h> 0) {
int w=TCOD_ctx.font_width;
while ( w > 0 ) {
if (((*pixorig) & rgb_mask) != sdl_key ) {
int r=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Rshift/8));
int g=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Gshift/8));
int b=(int)(*((uint8_t*)(pixorig)+charmap_backup->format->Bshift/8));
(*pix) &= nrgb_mask;
r = r * f.r / 255;
g = g * f.g / 255;
b = b * f.b / 255;
(*pix) |= (r<<charmap->format->Rshift)|(g<<charmap->format->Gshift)|(b<<charmap->format->Bshift);
}
w--;
pix = (uint32_t *) (((uint8_t*)pix)+3);
pixorig ++;
}
h--;
pix = (uint32_t *) (((uint8_t*)pix)+hdelta);
pixorig += hdelta_backup;
}
}
}
#ifdef USE_SDL_LOCKS
if ( SDL_MUSTLOCK(charmap) ) {
SDL_UnlockSurface(charmap);
}
#endif
}
SDL_BlitSurface(charmap,&srcRect,bitmap,&dstRect);
}
}
}
c++;
nfg++;
nbg++;
if (track_changes) {
oc++;
ofg++;
obg++;
}
}
}
#ifdef USE_SDL_LOCKS
if ( SDL_MUSTLOCK( bitmap ) ) SDL_UnlockSurface( bitmap );
#endif
if (cache) {
memcpy(cache->ch_array, console->ch_array,
sizeof(console->ch_array[0]) * console->w * console->h);
TCOD_image_mipmap_copy_internal(console->fg_colors, cache->fg_colors);
TCOD_image_mipmap_copy_internal(console->bg_colors, cache->bg_colors);
}
}
void *TCOD_sys_get_surface(int width, int height, bool alpha) {
return sdl->create_surface(width,height,alpha);
}
void TCOD_sys_update_char(int asciiCode, int fontx, int fonty, TCOD_image_t img, int x, int y) {
int px,py;
int iw,ih;
static TCOD_color_t pink={255,0,255};
TCOD_sys_map_ascii_to_font(asciiCode,fontx,fonty);
TCOD_image_get_size(img,&iw,&ih);
for (px=0; px < TCOD_ctx.font_width; px ++ ) {
for (py=0;py < TCOD_ctx.font_height; py++ ) {
TCOD_color_t col=TCOD_white;
uint8_t*pixel;
uint8_t bpp;
if ( (unsigned)(x+px) < (unsigned)iw && (unsigned)(y+py) < (unsigned)ih ) {
col=TCOD_image_get_pixel(img,x+px,y+py);
}
pixel=(uint8_t*)(charmap->pixels) + (fonty*TCOD_ctx.font_height+py) * charmap->pitch + (fontx*TCOD_ctx.font_width+px) * charmap->format->BytesPerPixel;
bpp = charmap->format->BytesPerPixel;
if (bpp == 4 ) {
*((pixel)+charmap->format->Ashift/8) = col.r;
*((pixel)+charmap->format->Rshift/8)=255;
*((pixel)+charmap->format->Gshift/8)=255;
*((pixel)+charmap->format->Bshift/8)=255;
} else {
*((pixel)+charmap->format->Rshift/8)=col.r;
*((pixel)+charmap->format->Gshift/8)=col.g;
*((pixel)+charmap->format->Bshift/8)=col.b;
}
}
}
charcols[asciiCode]=pink;
TCOD_sys_set_dirty_character_code(asciiCode);
}
void TCOD_sys_startup(void) {
if (has_startup) return;
#ifndef NDEBUG
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
#endif
TCOD_IFNOT(SDL_Init(SDL_INIT_VIDEO) >= 0 ) return;
memset(&TCOD_ctx.key_state,0,sizeof(TCOD_key_t));
TCOD_ctx.max_font_chars=256;
alloc_ascii_tables();
#ifndef NO_OPENGL
TCOD_opengl_init_attributes();
#endif
has_startup=true;
}
void TCOD_sys_shutdown(void) {
if (!has_startup) return;
TCOD_sys_uninit();
sdl->shutdown();
SDL_Quit();
memset(&scale_data, 0, sizeof(scale_data_t));
has_startup = false;
}
static void TCOD_sys_load_player_config(void) {
const char *renderer;
const char *font;
int fullscreenWidth,fullscreenHeight;
TCOD_parser_t parser=TCOD_parser_new();
TCOD_parser_struct_t libtcod = TCOD_parser_new_struct(parser, "libtcod");
TCOD_struct_add_property(libtcod, "renderer", TCOD_TYPE_STRING, false);
TCOD_struct_add_property(libtcod, "font", TCOD_TYPE_STRING, false);
TCOD_struct_add_property(libtcod, "fontInRow", TCOD_TYPE_BOOL, false);
TCOD_struct_add_property(libtcod, "fontGreyscale", TCOD_TYPE_BOOL, false);
TCOD_struct_add_property(libtcod, "fontTcodLayout", TCOD_TYPE_BOOL, false);
TCOD_struct_add_property(libtcod, "fontNbCharHoriz", TCOD_TYPE_INT, false);
TCOD_struct_add_property(libtcod, "fontNbCharVertic", TCOD_TYPE_INT, false);
TCOD_struct_add_property(libtcod, "fullscreen", TCOD_TYPE_BOOL, false);
TCOD_struct_add_property(libtcod, "fullscreenWidth", TCOD_TYPE_INT, false);
TCOD_struct_add_property(libtcod, "fullscreenHeight", TCOD_TYPE_INT, false);
TCOD_struct_add_property(libtcod, "fullscreenScaling", TCOD_TYPE_BOOL, false);
TCOD_parser_run(parser,"./libtcod.cfg",NULL);
renderer=TCOD_parser_get_string_property(parser, "libtcod.renderer");
if ( renderer != NULL ) {
if ( TCOD_strcasecmp(renderer,"GLSL") == 0 ) TCOD_ctx.renderer=TCOD_RENDERER_GLSL;
else if ( TCOD_strcasecmp(renderer,"OPENGL") == 0 ) TCOD_ctx.renderer=TCOD_RENDERER_OPENGL;
else if ( TCOD_strcasecmp(renderer,"SDL") == 0 ) TCOD_ctx.renderer=TCOD_RENDERER_SDL;
else printf ("Warning : unknown renderer '%s' in libtcod.cfg\n", renderer);
}
font=TCOD_parser_get_string_property(parser, "libtcod.font");
if ( font != NULL ) {
if ( TCOD_sys_file_exists(font)) {
int fontNbCharHoriz,fontNbCharVertic;
strcpy(TCOD_ctx.font_file,font);
TCOD_ctx.font_in_row=TCOD_parser_get_bool_property(parser,"libtcod.fontInRow");
TCOD_ctx.font_greyscale=TCOD_parser_get_bool_property(parser,"libtcod.fontGreyscale");
TCOD_ctx.font_tcod_layout=TCOD_parser_get_bool_property(parser,"libtcod.fontTcodLayout");
fontNbCharHoriz=TCOD_parser_get_int_property(parser,"libtcod.fontNbCharHoriz");
fontNbCharVertic=TCOD_parser_get_int_property(parser,"libtcod.fontNbCharVertic");
if ( fontNbCharHoriz > 0 ) TCOD_ctx.fontNbCharHoriz=fontNbCharHoriz;
if ( fontNbCharVertic > 0 ) TCOD_ctx.fontNbCharVertic=fontNbCharVertic;
if ( charmap ) {
SDL_FreeSurface(charmap);
charmap=NULL;
}
} else {
printf ("Warning : font file '%s' does not exist\n",font);
}
}
TCOD_ctx.fullscreen=TCOD_parser_get_bool_property(parser,"libtcod.fullscreen");
fullscreenWidth=TCOD_parser_get_int_property(parser,"libtcod.fullscreenWidth");
fullscreenHeight=TCOD_parser_get_int_property(parser,"libtcod.fullscreenHeight");
if ( fullscreenWidth > 0 ) TCOD_ctx.fullscreen_width=fullscreenWidth;
if ( fullscreenHeight > 0 ) TCOD_ctx.fullscreen_height=fullscreenHeight;
}
TCOD_renderer_t TCOD_sys_get_renderer(void) {
return TCOD_ctx.renderer;
}
void TCOD_sys_set_renderer(TCOD_renderer_t renderer) {
if ( renderer == TCOD_ctx.renderer ) return;
TCOD_ctx.renderer=renderer;
TCOD_sys_uninit();
TCOD_sys_init(TCOD_ctx.root, TCOD_ctx.fullscreen);
TCOD_console_set_window_title(TCOD_ctx.window_title);
TCOD_console_set_dirty(0,0,TCOD_ctx.root->w,TCOD_ctx.root->h);
}
void TCOD_sys_init_screen_offset(void) {
TCOD_ctx.fullscreen_offsetx=(TCOD_ctx.actual_fullscreen_width-TCOD_ctx.root->w*TCOD_ctx.font_width)/2;
TCOD_ctx.fullscreen_offsety=(TCOD_ctx.actual_fullscreen_height-TCOD_ctx.root->h*TCOD_ctx.font_height)/2;
}
bool TCOD_sys_init(TCOD_console_data_t *console, bool fullscreen) {
static TCOD_renderer_t last_renderer=TCOD_RENDERER_SDL;
static char last_font[512]="";
TCOD_sys_startup();
if ( TCOD_sys_file_exists("./libtcod.cfg")) {
TCOD_sys_load_player_config();
if (TCOD_ctx.fullscreen) fullscreen=true;
}
if (last_renderer != TCOD_ctx.renderer || ! charmap || strcmp(last_font,TCOD_ctx.font_file) != 0) {
TCOD_sys_load_font();
}
sdl->create_window(console->w, console->h, fullscreen);
memset(key_status,0,sizeof(bool)*(TCODK_CHAR+1));
return true;
}
void TCOD_sys_uninit(void) {
if (!has_startup) return;
sdl->destroy_window();
}
void TCOD_sys_save_bitmap(void *bitmap, const char *filename) {
image_support_t *img=image_type;
while ( img->extension != NULL && strcasestr(filename,img->extension) == NULL ) img++;
if ( img->extension == NULL || img->write == NULL ) img=image_type;
img->write((SDL_Surface *)bitmap,filename);
}
void TCOD_sys_save_screenshot(const char *filename) {
char buf[128];
if ( filename == NULL ) {
int idx=0;
do {
FILE *f=NULL;
sprintf(buf,"./screenshot%03d.png",idx);
f=fopen(buf,"rb");
if ( ! f ) filename=buf;
else {
idx++;
fclose(f);
}
} while(!filename);
}
sdl->save_screenshot(filename);
}
void TCOD_sys_set_fullscreen(bool fullscreen) {
TCOD_ctx.fullscreen=fullscreen;
sdl->set_fullscreen(fullscreen);
}
void TCOD_sys_set_scale_factor(float value) {
float old_scale_factor = scale_factor;
scale_factor = value;
if (scale_factor + 1e-3 < scale_data.min_scale_factor)
scale_factor = scale_data.min_scale_factor;
else if (scale_factor - 1e-3 > MAX_SCALE_FACTOR)
scale_factor = MAX_SCALE_FACTOR;
}
void TCOD_sys_set_window_title(const char *title) {
strcpy(TCOD_ctx.window_title,title);
sdl->set_window_title(title);
}
void TCOD_sys_flush(bool render) {
static uint32_t old_time,new_time=0, elapsed=0;
int32_t frame_time,time_to_wait;
if ( render ) {
TCOD_sys_render(NULL, TCOD_ctx.root);
}
old_time=new_time;
new_time=TCOD_sys_elapsed_milli();
if (old_time > new_time)
old_time = elapsed = 0;
if ( new_time / 1000 != elapsed ) {
fps=cur_fps;
cur_fps=0;
elapsed=new_time/1000;
}
frame_time=(new_time - old_time);
last_frame_length = frame_time * 0.001f;
cur_fps++;
time_to_wait=min_frame_length-frame_time;
if (old_time > 0 && time_to_wait > 0) {
TCOD_sys_sleep_milli(time_to_wait);
new_time = TCOD_sys_elapsed_milli();
frame_time=(new_time - old_time);
}
last_frame_length = frame_time * 0.001f;
}
static char TCOD_sys_get_vk(SDL_Keycode sdl_key) {
int i;
for (i = 0; i < NUM_VK_TO_C_ENTRIES; i++) {
if (vk_to_c[i].sdl_key == sdl_key) {
vk_to_c[i].sdl_key = 0;
return vk_to_c[i].tcod_key;
}
}
return 0;
}
static void TCOD_sys_set_vk(SDL_Keycode sdl_key, char tcod_key) {
int i;
for (i = 0; i < NUM_VK_TO_C_ENTRIES; i++) {
if (vk_to_c[i].sdl_key == 0) {
vk_to_c[i].sdl_key = sdl_key;
vk_to_c[i].tcod_key = tcod_key;
break;
}
}
}
static void TCOD_sys_convert_event(SDL_Event *ev, TCOD_key_t *ret) {
SDL_KeyboardEvent *kev=&ev->key;
if (SDLK_SCANCODE_MASK == (kev->keysym.sym & SDLK_SCANCODE_MASK))
ret->c = 0;
else
ret->c = kev->keysym.sym;
if ( ( kev->keysym.mod & (KMOD_LCTRL|KMOD_RCTRL) ) != 0 ) {
if ( kev->keysym.sym >= SDLK_a && kev->keysym.sym <= SDLK_z ) {
ret->c = 'a'+(kev->keysym.sym - SDLK_a);
}
}
if ( ev->type == SDL_KEYDOWN ) TCOD_sys_set_vk(kev->keysym.sym, ret->c);
else if (ev->type == SDL_KEYUP ) ret->c = TCOD_sys_get_vk(kev->keysym.sym);
switch(kev->keysym.sym) {
case SDLK_ESCAPE : ret->vk=TCODK_ESCAPE;break;
case SDLK_SPACE : ret->vk=TCODK_SPACE; break;
case SDLK_BACKSPACE : ret->vk=TCODK_BACKSPACE;break;
case SDLK_TAB : ret->vk=TCODK_TAB;break;
case SDLK_RETURN : ret->vk=TCODK_ENTER;break;
case SDLK_PAUSE : ret->vk=TCODK_PAUSE;break;
case SDLK_PAGEUP : ret->vk=TCODK_PAGEUP;break;
case SDLK_PAGEDOWN : ret->vk=TCODK_PAGEDOWN;break;
case SDLK_HOME : ret->vk=TCODK_HOME;break;
case SDLK_END : ret->vk=TCODK_END;break;
case SDLK_DELETE : ret->vk=TCODK_DELETE;break;
case SDLK_INSERT : ret->vk=TCODK_INSERT; break;
case SDLK_LALT : case SDLK_RALT : ret->vk=TCODK_ALT;break;
case SDLK_LCTRL : case SDLK_RCTRL : ret->vk=TCODK_CONTROL;break;
case SDLK_LSHIFT : case SDLK_RSHIFT : ret->vk=TCODK_SHIFT;break;
case SDLK_PRINTSCREEN : ret->vk=TCODK_PRINTSCREEN;break;
case SDLK_LEFT : ret->vk=TCODK_LEFT;break;
case SDLK_UP : ret->vk=TCODK_UP;break;
case SDLK_RIGHT : ret->vk=TCODK_RIGHT;break;
case SDLK_DOWN : ret->vk=TCODK_DOWN;break;
case SDLK_F1 : ret->vk=TCODK_F1;break;
case SDLK_F2 : ret->vk=TCODK_F2;break;
case SDLK_F3 : ret->vk=TCODK_F3;break;
case SDLK_F4 : ret->vk=TCODK_F4;break;
case SDLK_F5 : ret->vk=TCODK_F5;break;
case SDLK_F6 : ret->vk=TCODK_F6;break;
case SDLK_F7 : ret->vk=TCODK_F7;break;
case SDLK_F8 : ret->vk=TCODK_F8;break;
case SDLK_F9 : ret->vk=TCODK_F9;break;
case SDLK_F10 : ret->vk=TCODK_F10;break;
case SDLK_F11 : ret->vk=TCODK_F11;break;
case SDLK_F12 : ret->vk=TCODK_F12;break;
case SDLK_0 : ret->vk=TCODK_0;break;
case SDLK_1 : ret->vk=TCODK_1;break;
case SDLK_2 : ret->vk=TCODK_2;break;
case SDLK_3 : ret->vk=TCODK_3;break;
case SDLK_4 : ret->vk=TCODK_4;break;
case SDLK_5 : ret->vk=TCODK_5;break;
case SDLK_6 : ret->vk=TCODK_6;break;
case SDLK_7 : ret->vk=TCODK_7;break;
case SDLK_8 : ret->vk=TCODK_8;break;
case SDLK_9 : ret->vk=TCODK_9;break;
case SDLK_RGUI : ret->vk=TCODK_RWIN;break;
case SDLK_LGUI : ret->vk=TCODK_LWIN;break;
case SDLK_NUMLOCKCLEAR : ret->vk=TCODK_NUMLOCK;break;
case SDLK_KP_0 : ret->vk=TCODK_KP0;break;
case SDLK_KP_1 : ret->vk=TCODK_KP1;break;
case SDLK_KP_2 : ret->vk=TCODK_KP2;break;
case SDLK_KP_3 : ret->vk=TCODK_KP3;break;
case SDLK_KP_4 : ret->vk=TCODK_KP4;break;
case SDLK_KP_5 : ret->vk=TCODK_KP5;break;
case SDLK_KP_6 : ret->vk=TCODK_KP6;break;
case SDLK_KP_7 : ret->vk=TCODK_KP7;break;
case SDLK_KP_8 : ret->vk=TCODK_KP8;break;
case SDLK_KP_9 : ret->vk=TCODK_KP9;break;
case SDLK_KP_DIVIDE : ret->vk=TCODK_KPDIV;break;
case SDLK_KP_MULTIPLY : ret->vk=TCODK_KPMUL;break;
case SDLK_KP_PLUS : ret->vk=TCODK_KPADD;break;
case SDLK_KP_MINUS : ret->vk=TCODK_KPSUB;break;
case SDLK_KP_ENTER : ret->vk=TCODK_KPENTER;break;
case SDLK_KP_PERIOD : ret->vk=TCODK_KPDEC;break;
default : ret->vk=TCODK_CHAR; break;
}
}
static TCOD_key_t TCOD_sys_SDLtoTCOD(SDL_Event *ev, int flags) {
TCOD_key_t *ret = &TCOD_ctx.key_state;
ret->vk=TCODK_NONE;
ret->c=0;
ret->pressed=0;
switch (ev->type) {
case SDL_KEYUP : {
SDL_KeyboardEvent *kev=&ev->key;
TCOD_key_t tmpkey;
switch(kev->keysym.sym) {
case SDLK_LALT : ret->lalt=0; break;
case SDLK_RALT : ret->ralt=0; break;
case SDLK_LCTRL : ret->lctrl=0; break;
case SDLK_RCTRL : ret->rctrl=0; break;
case SDLK_LSHIFT : ret->shift=0; break;
case SDLK_RSHIFT : ret->shift=0; break;
case SDLK_LGUI : ret->lmeta=0; break;
case SDLK_RGUI : ret->rmeta=0; break;
default:break;
}
TCOD_sys_convert_event(ev,&tmpkey);
key_status[tmpkey.vk]=false;
if ( flags & TCOD_KEY_RELEASED ) {
ret->vk=tmpkey.vk;
ret->c=tmpkey.c;
ret->pressed=0;
}
}
break;
case SDL_KEYDOWN : {
SDL_KeyboardEvent *kev=&ev->key;
TCOD_key_t tmpkey;
switch(kev->keysym.sym) {
case SDLK_LALT : ret->lalt=1; break;
case SDLK_RALT : ret->ralt=1; break;
case SDLK_LCTRL : ret->lctrl=1; break;
case SDLK_RCTRL : ret->rctrl=1; break;
case SDLK_LSHIFT : ret->shift=1; break;
case SDLK_RSHIFT : ret->shift=1; break;
case SDLK_LGUI : ret->lmeta=1; break;
case SDLK_RGUI : ret->rmeta=1; break;
default : break;
}
TCOD_sys_convert_event(ev,&tmpkey);
key_status[tmpkey.vk]=true;
if ( flags & TCOD_KEY_PRESSED ) {
ret->vk=tmpkey.vk;
ret->c=tmpkey.c;
ret->pressed=1;
}
}
break;
}
return *ret;
}
bool TCOD_sys_is_key_pressed(TCOD_keycode_t key) {
return key_status[key];
}
#ifdef TCOD_TOUCH_INPUT
static TCOD_touch_t tcod_touch={0};
static int TCOD_sys_get_touch_finger_index(SDL_FingerID fingerId) {
int i;
for (i = 0; i < tcod_touch.nfingers; i++)
if (tcod_touch.finger_ids[i] == fingerId)
return i;
if (i == tcod_touch.nfingers && i+1 <= MAX_TOUCH_FINGERS) {
tcod_touch.nfingers += 1;
tcod_touch.finger_ids[i] = fingerId;
return i;
}
return -1;
}
#endif
void TCOD_sys_unproject_screen_coords(int sx, int sy, int *ssx, int *ssy) {
if (scale_data.dst_display_width != 0 ) {
*ssx = (scale_data.src_x0 + ((sx - scale_data.dst_offset_x) * scale_data.src_copy_width) / scale_data.dst_display_width);
*ssy = (scale_data.src_y0 + ((sy - scale_data.dst_offset_y) * scale_data.src_copy_width) / scale_data.dst_display_width);
} else {
*ssx=sx - TCOD_ctx.fullscreen_offsetx;
*ssy=sy - TCOD_ctx.fullscreen_offsety;
}
}
void TCOD_sys_convert_console_to_screen_coords(int cx, int cy, int *sx, int *sy) {
*sx = scale_data.dst_offset_x + ((cx * TCOD_ctx.font_width - scale_data.src_x0) * scale_data.dst_display_width) / scale_data.src_copy_width;
*sy = scale_data.dst_offset_y + ((cy * TCOD_ctx.font_height - scale_data.src_y0) * scale_data.dst_display_height) / scale_data.src_copy_height;
}
void TCOD_sys_convert_screen_to_console_coords(int sx, int sy, int *cx, int *cy) {
int ssx, ssy;
TCOD_sys_unproject_screen_coords(sx, sy, &ssx, &ssy);
*cx = ssx / TCOD_ctx.font_width;
*cy = ssy / TCOD_ctx.font_height;
}
static TCOD_mouse_t tcod_mouse={0,0,0,0,0,0,0,0,false,false,false,false,false,false,false,false};
static TCOD_event_t TCOD_sys_handle_event(SDL_Event *ev,TCOD_event_t eventMask, TCOD_key_t *key, TCOD_mouse_t *mouse) {
TCOD_event_t retMask=0;
key->text[0] = '\0';
switch(ev->type) {
case SDL_KEYDOWN : {
TCOD_key_t tmpKey=TCOD_sys_SDLtoTCOD(ev,TCOD_KEY_PRESSED);
if ( (TCOD_EVENT_KEY_PRESS & eventMask) != 0) {
retMask|=TCOD_EVENT_KEY_PRESS;
if ( key ) *key = tmpKey;
return retMask;
}
}
break;
case SDL_KEYUP : {
TCOD_key_t tmpKey=TCOD_sys_SDLtoTCOD(ev,TCOD_KEY_RELEASED);
if ( (TCOD_EVENT_KEY_RELEASE & eventMask) != 0) {
retMask|=TCOD_EVENT_KEY_RELEASE;
if ( key ) *key = tmpKey;
return retMask;
}
}
break;
case SDL_TEXTINPUT: {
SDL_TextInputEvent *iev=&ev->text;
*key = TCOD_ctx.key_state;
key->vk = TCODK_TEXT;
key->pressed = 1;
strncpy(key->text, iev->text, TCOD_KEY_TEXT_SIZE);
return retMask | TCOD_EVENT_KEY_PRESS;
}
break;
#ifdef TCOD_TOUCH_INPUT
case SDL_FINGERDOWN :
case SDL_FINGERUP :
case SDL_FINGERMOTION :
{
int idx, mouse_touch_valid;
float xf, yf, screen_x, screen_y;
uint32_t ticks_taken = 0;
if (tcod_touch.nfingerspressed == 0) {
tcod_touch.nupdates = 0;
tcod_touch.nfingers = 0;
tcod_touch.ticks0 = SDL_GetTicks();
} else
ticks_taken = SDL_GetTicks() - tcod_touch.ticks0;
idx = TCOD_sys_get_touch_finger_index(ev->tfinger.fingerId);
if (idx == -1) {
TCOD_LOG(("ERROR: failed to allocate extra finger"));
break;
}
tcod_touch.finger_id = ev->tfinger.fingerId;
tcod_touch.nupdates += 1;
if (SDL_FINGERDOWN == ev->type) {
tcod_touch.nfingerspressed += 1;
tcod_touch.fingerspressed[idx] = 1;
mouse_touch_valid = mouse_touch && tcod_touch.nfingerspressed == 1 && tcod_touch.fingerspressed[0];
} else if (SDL_FINGERUP == ev->type) {
mouse_touch_valid = mouse_touch && tcod_touch.nfingerspressed == 1 && tcod_touch.fingerspressed[0];
tcod_touch.nfingerspressed -= 1;
tcod_touch.fingerspressed[idx] = 0;
} else
mouse_touch_valid = mouse_touch && tcod_touch.nfingerspressed == 1 && tcod_touch.fingerspressed[0];
screen_x = ev->tfinger.x * scale_data.surface_width;
screen_y = ev->tfinger.y * scale_data.surface_height;
xf = (float)(screen_x - scale_data.dst_offset_x) / scale_data.dst_display_width;
yf = (float)(screen_y - scale_data.dst_offset_y) / scale_data.dst_display_height;
tcod_touch.coords[idx][0] = scale_data.src_x0 + scale_data.src_copy_width * xf;
tcod_touch.coords[idx][1] = scale_data.src_y0 + scale_data.src_copy_height * yf;
tcod_touch.coords_delta[idx][0] = ev->tfinger.dx * scale_data.src_proportionate_width;
tcod_touch.coords_delta[idx][1] = ev->tfinger.dy * scale_data.src_proportionate_height;
tcod_touch.consolecoords[idx][0] = tcod_touch.coords[idx][0] / TCOD_ctx.font_width;
tcod_touch.consolecoords[idx][1] = tcod_touch.coords[idx][1] / TCOD_ctx.font_height;
tcod_touch.consolecoords_delta[idx][0] = tcod_touch.coords_delta[idx][0] / TCOD_ctx.font_width;
tcod_touch.consolecoords_delta[idx][1] = tcod_touch.coords_delta[idx][1] / TCOD_ctx.font_height;
if (SDL_FINGERDOWN == ev->type) {
if ((TCOD_EVENT_FINGER_PRESS & eventMask) != 0)
retMask |= TCOD_EVENT_FINGER_PRESS;
if (mouse_touch_valid && (TCOD_EVENT_MOUSE_PRESS & eventMask) != 0) {
mouse->lbutton=mousebl=true;
retMask |= TCOD_EVENT_MOUSE_PRESS;
}
} else if (SDL_FINGERUP == ev->type) {
if ((TCOD_EVENT_FINGER_RELEASE & eventMask) != 0)
retMask |= TCOD_EVENT_FINGER_RELEASE;
if (mouse_touch_valid && (TCOD_EVENT_MOUSE_RELEASE & eventMask) != 0) {
if (mousebl)
mouse->lbutton_pressed = mouse_force_bl=true;
mouse->lbutton = mousebl=false;
retMask |= TCOD_EVENT_MOUSE_RELEASE;
}
} else if (SDL_FINGERMOTION == ev->type) {
float scale_adjust = 1.0f, xc_shift = 0.0f, yc_shift = 0.0f;
if ((TCOD_EVENT_FINGER_MOVE & eventMask) != 0)
retMask |= TCOD_EVENT_FINGER_MOVE;
if (mouse_touch_valid && (TCOD_EVENT_MOUSE_MOVE & eventMask) != 0)
retMask |= TCOD_EVENT_MOUSE_MOVE;
if (tcod_touch.nfingerspressed == 1) {
if (tcod_touch.fingerspressed[0] && (tcod_touch.coords_delta[0][0] || tcod_touch.coords_delta[0][1]) && ticks_taken > 10) {
xc_shift = (float)tcod_touch.coords_delta[idx][0] / scale_data.surface_width;
yc_shift = (float)tcod_touch.coords_delta[idx][1] / scale_data.surface_height;
}
} else if (tcod_touch.nfingerspressed == 2) {
if (tcod_touch.fingerspressed[0] && tcod_touch.fingerspressed[1]) {
int f0x0 = tcod_touch.coords[0][0]-tcod_touch.coords_delta[0][0], f0y0 = tcod_touch.coords[0][1]-tcod_touch.coords_delta[0][1];
int f1x0 = tcod_touch.coords[1][0]-tcod_touch.coords_delta[1][0], f1y0 = tcod_touch.coords[1][1]-tcod_touch.coords_delta[1][1];
int f0x1 = tcod_touch.coords[0][0], f0y1 = tcod_touch.coords[0][1];
int f1x1 = tcod_touch.coords[1][0], f1y1 = tcod_touch.coords[1][1];
float p0x = (f1x0 + f0x0)/2.0f, p0y = (f1y0 + f0y0)/2.0f;
float p1x = (f1x1 + f0x1)/2.0f, p1y = (f1y1 + f0y1)/2.0f;
float len_previous = sqrtf((float)(pow(f0x0-f1x0,2) + pow(f0y0-f1y0,2)));
float len_current = sqrt((float)(pow(f0x1-f1x1, 2) + pow(f0y1-f1y1,2)));
scale_adjust = len_current/len_previous;
xc_shift = ((p1x - p0x) / scale_data.surface_width);
yc_shift = ((p1y - p0y) / scale_data.surface_height);
}
}
if (fabs(xc_shift) > 1e-3f) {
sdl->scale_xc -= xc_shift;
if (sdl->scale_xc + 1e-3f < 0.0f)
sdl->scale_xc = 0.0f;
if (sdl->scale_xc - 1e-3f > 1.0f)
sdl->scale_xc = 1.0f;
}
if (fabs(yc_shift) > 1e-3f) {
sdl->scale_yc -= yc_shift;
if (sdl->scale_yc + 1e-3f < 0.0f)
sdl->scale_yc = 0.0f;
if (sdl->scale_yc - 1e-3f > 1.0f)
sdl->scale_yc = 1.0f;
}
if (fabs(scale_adjust - 1.0f) > 1e-3f)
TCOD_sys_set_scale_factor(scale_factor * scale_adjust);
}
if (ticks_taken > 400 || tcod_touch.nfingers > 1) {
mouse->cx = 0;
mouse->cy = 0;
mouse->dcx = 0;
mouse->dcy = 0;
} else if (mouse_touch_valid && (retMask & (TCOD_EVENT_MOUSE_PRESS|TCOD_EVENT_MOUSE_RELEASE|TCOD_EVENT_MOUSE_MOVE)) != 0) {
mouse->x = tcod_touch.coords[idx][0];
mouse->y = tcod_touch.coords[idx][1];
mouse->dx += tcod_touch.coords_delta[idx][0];
mouse->dy += tcod_touch.coords_delta[idx][1];
mouse->cx = tcod_touch.consolecoords[idx][0];
mouse->cy = tcod_touch.consolecoords[idx][1];
mouse->dcx = tcod_touch.consolecoords_delta[idx][0];
mouse->dcy = tcod_touch.consolecoords_delta[idx][1];
}
break;
}
#endif
case SDL_MOUSEMOTION :
if ( (TCOD_EVENT_MOUSE_MOVE & eventMask) != 0) {
SDL_MouseMotionEvent *mev=&ev->motion;
TCOD_sys_unproject_screen_coords(mev->x, mev->y, &mouse->x, &mouse->y);
if (scale_data.surface_width != 0) {
mouse->dx += (mev->xrel * scale_data.src_proportionate_width) / scale_data.surface_width;
mouse->dy += (mev->yrel * scale_data.src_proportionate_height) / scale_data.surface_height;
}
mouse->cx = mouse->x / TCOD_ctx.font_width;
mouse->cy = mouse->y / TCOD_ctx.font_height;
mouse->dcx = mouse->dx / TCOD_ctx.font_width;
mouse->dcy = mouse->dy / TCOD_ctx.font_height;
return retMask | TCOD_EVENT_MOUSE_MOVE;
}
break;
case SDL_MOUSEWHEEL :
if (ev->wheel.y < 0)
mouse->wheel_down=true;
else
mouse->wheel_up=true;
return retMask | TCOD_EVENT_MOUSE_PRESS;
break;
case SDL_MOUSEBUTTONDOWN :
if ( (TCOD_EVENT_MOUSE_PRESS & eventMask) != 0) {
SDL_MouseButtonEvent *mev=&ev->button;
retMask|=TCOD_EVENT_MOUSE_PRESS;
switch (mev->button) {
case SDL_BUTTON_LEFT : mouse->lbutton=mousebl=true; break;
case SDL_BUTTON_MIDDLE : mouse->mbutton=mousebm=true; break;
case SDL_BUTTON_RIGHT : mouse->rbutton=mousebr=true; break;
}
if ( (TCOD_EVENT_MOUSE_MOVE & eventMask) == 0) {
mouse->x=mev->x;
mouse->y=mev->y;
mouse->cx = (mouse->x - TCOD_ctx.fullscreen_offsetx) / TCOD_ctx.font_width;
mouse->cy = (mouse->y - TCOD_ctx.fullscreen_offsety) / TCOD_ctx.font_height;
}
return retMask;
}
break;
case SDL_MOUSEBUTTONUP :
if ( (TCOD_EVENT_MOUSE_RELEASE & eventMask) != 0) {
SDL_MouseButtonEvent *mev=&ev->button;
retMask|=TCOD_EVENT_MOUSE_RELEASE;
switch (mev->button) {
case SDL_BUTTON_LEFT : if (mousebl) mouse->lbutton_pressed = mouse_force_bl=true; mouse->lbutton = mousebl=false; break;
case SDL_BUTTON_MIDDLE : if (mousebm) mouse->mbutton_pressed = mouse_force_bm=true; mouse->mbutton = mousebm=false; break;
case SDL_BUTTON_RIGHT : if (mousebr) mouse->rbutton_pressed = mouse_force_br=true; mouse->rbutton = mousebr=false; break;
}
if ( (TCOD_EVENT_MOUSE_MOVE & eventMask) == 0) {
mouse->x=mev->x;
mouse->y=mev->y;
mouse->cx = (mouse->x - TCOD_ctx.fullscreen_offsetx) / TCOD_ctx.font_width;
mouse->cy = (mouse->y - TCOD_ctx.fullscreen_offsety) / TCOD_ctx.font_height;
}
return retMask;
}
break;
case SDL_QUIT :
TCOD_ctx.is_window_closed=true;
break;
case SDL_WINDOWEVENT :
switch (ev->window.event) {
#ifdef TCOD_ANDROID
case SDL_WINDOWEVENT_SIZE_CHANGED:
{
if (scale_data.surface_width != ev->window.data1 || scale_data.surface_height != ev->window.data1)
scale_data.force_recalc = 1;
break;
}
#endif
case SDL_WINDOWEVENT_ENTER:
TCOD_ctx.app_has_mouse_focus=true; break;
case SDL_WINDOWEVENT_LEAVE:
TCOD_ctx.app_has_mouse_focus=false; break;
case SDL_WINDOWEVENT_MAXIMIZED:
TCOD_ctx.app_is_active=true; break;
case SDL_WINDOWEVENT_MINIMIZED:
TCOD_ctx.app_is_active=false; break;
case SDL_WINDOWEVENT_EXPOSED:
TCOD_sys_render(NULL, TCOD_ctx.root);
break;
#ifdef NDEBUG_HMM
default:
TCOD_LOG(("SDL2 WINDOWEVENT (unknown): 0x%04x\n", ev->window.event));
break;
#endif
}
break;
default : break;
}
return retMask;
}
TCOD_event_t TCOD_sys_wait_for_event(int eventMask, TCOD_key_t *key, TCOD_mouse_t *mouse, bool flush) {
SDL_Event ev;
TCOD_event_t retMask=0;
if ( eventMask == 0 ) return 0;
if ( flush ) {
while ( SDL_PollEvent(&ev) ) {
TCOD_sys_SDLtoTCOD(&ev,0);
}
}
tcod_mouse.lbutton_pressed =false;
tcod_mouse.rbutton_pressed =false;
tcod_mouse.mbutton_pressed =false;
tcod_mouse.wheel_up=false;
tcod_mouse.wheel_down=false;
tcod_mouse.dx=0;
tcod_mouse.dy=0;
if ( key ) {
key->vk=TCODK_NONE;
key->c=0;
}
do {
SDL_WaitEvent(&ev);
retMask=TCOD_sys_handle_event(&ev,eventMask,key,&tcod_mouse);
} while ( ev.type != SDL_QUIT && (retMask & eventMask) == 0 );
if (mouse) { *mouse=tcod_mouse; }
return retMask;
}
TCOD_event_t TCOD_sys_check_for_event(int eventMask, TCOD_key_t *key, TCOD_mouse_t *mouse) {
SDL_Event ev;
TCOD_event_t retMask=0;
if ( eventMask == 0 ) return 0;
tcod_mouse.lbutton_pressed =false;
tcod_mouse.rbutton_pressed =false;
tcod_mouse.mbutton_pressed =false;
tcod_mouse.wheel_up=false;
tcod_mouse.wheel_down=false;
tcod_mouse.dx=0;
tcod_mouse.dy=0;
if ( key ) {
key->vk=TCODK_NONE;
key->c=0;
}
while ( SDL_PollEvent(&ev) ) {
retMask=TCOD_sys_handle_event(&ev,eventMask,key,&tcod_mouse);
if ((retMask & TCOD_EVENT_KEY) != 0)
break;
}
if (mouse) { *mouse=tcod_mouse; }
return retMask;
}
TCOD_mouse_t TCOD_mouse_get_status(void) {
return tcod_mouse;
}
TCOD_key_t TCOD_sys_check_for_keypress(int flags) {
static TCOD_key_t noret={TCODK_NONE,0};
TCOD_key_t key;
TCOD_event_t ev = TCOD_sys_check_for_event(flags & TCOD_EVENT_KEY, &key, NULL);
if ((ev & TCOD_EVENT_KEY) == 0) return noret;
return key;
}
TCOD_key_t TCOD_sys_wait_for_keypress(bool flush) {
static TCOD_key_t noret={TCODK_NONE,0};
TCOD_key_t key;
TCOD_event_t ev = TCOD_sys_wait_for_event(TCOD_EVENT_KEY_PRESS, &key, NULL, flush);
if ((ev & TCOD_EVENT_KEY_PRESS) == 0) return noret;
return key;
}
void TCOD_sys_sleep_milli(uint32_t milliseconds) {
SDL_Delay(milliseconds);
}
void *TCOD_sys_load_image(const char *filename) {
image_support_t *img=image_type;
while ( img->extension != NULL && !img->check_type(filename) ) img++;
if ( img->extension == NULL || img->read == NULL ) return NULL;
return img->read(filename);
}
void TCOD_sys_get_image_size(const void *image, int *w, int *h) {
SDL_Surface *surf=(SDL_Surface *)image;
*w = surf->w;
*h = surf->h;
}
TCOD_color_t TCOD_sys_get_image_pixel(const void *image,int x, int y) {
TCOD_color_t ret;
SDL_Surface *surf=(SDL_Surface *)image;
uint8_t bpp;
uint8_t*bits;
if ( x < 0 || y < 0 || x >= surf->w || y >= surf->h ) return TCOD_black;
bpp = surf->format->BytesPerPixel;
bits = ((uint8_t*)surf->pixels)+y*surf->pitch+x*bpp;
switch (bpp) {
case 1 :
{
if (surf->format->palette) {
SDL_Color col = surf->format->palette->colors[(*bits)];
ret.r=col.r;
ret.g=col.g;
ret.b=col.b;
} else return TCOD_black;
}
break;
default :
ret.r = *((bits)+surf->format->Rshift/8);
ret.g = *((bits)+surf->format->Gshift/8);
ret.b = *((bits)+surf->format->Bshift/8);
break;
}
return ret;
}
int TCOD_sys_get_image_alpha(const void *image,int x, int y) {
SDL_Surface *surf=(SDL_Surface *)image;
uint8_t bpp;
uint8_t*bits;
if ( x < 0 || y < 0 || x >= surf->w || y >= surf->h ) return 255;
bpp = surf->format->BytesPerPixel;
if ( bpp != 4 ) return 255;
bits = ((uint8_t*)surf->pixels)+y*surf->pitch+x*bpp;
return *((bits)+surf->format->Ashift/8);
}
uint32_t TCOD_sys_elapsed_milli(void) {
return (uint32_t)SDL_GetTicks();
}
float TCOD_sys_elapsed_seconds(void) {
static float div=1.0f/1000.0f;
return SDL_GetTicks()*div;
}
void TCOD_sys_force_fullscreen_resolution(int width, int height) {
TCOD_ctx.fullscreen_width=width;
TCOD_ctx.fullscreen_height=height;
}
void * TCOD_sys_create_bitmap(int width, int height, TCOD_color_t *buf) {
int x,y;
SDL_PixelFormat fmt;
SDL_Surface *bitmap;
memset(&fmt,0,sizeof(SDL_PixelFormat));
if ( charmap != NULL ) {
fmt = *charmap->format;
} else {
fmt.BitsPerPixel=24;
fmt.Amask=0;
if ( SDL_BYTEORDER == SDL_LIL_ENDIAN ) {
fmt.Rmask=0x0000FF;
fmt.Gmask=0x00FF00;
fmt.Bmask=0xFF0000;
} else {
fmt.Rmask=0xFF0000;
fmt.Gmask=0x00FF00;
fmt.Bmask=0x0000FF;
}
}
bitmap=SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,fmt.BitsPerPixel,fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask);
for (x=0; x < width; x++) {
for (y=0; y < height; y++) {
SDL_Rect rect;
uint32_t col=SDL_MapRGB(&fmt,buf[x+y*width].r,buf[x+y*width].g,buf[x+y*width].b);
rect.x=x;
rect.y=y;
rect.w=1;
rect.h=1;
SDL_FillRect(bitmap,&rect,col);
}
}
return (void *)bitmap;
}
void TCOD_sys_delete_bitmap(void *bitmap) {
SDL_FreeSurface((SDL_Surface *)bitmap);
}
void TCOD_sys_set_fps(int val) {
if( val == 0 ) min_frame_length=0;
else min_frame_length=1000/val;
}
void TCOD_sys_save_fps(void) {
min_frame_length_backup=min_frame_length;
}
void TCOD_sys_restore_fps(void) {
min_frame_length=min_frame_length_backup;
}
int TCOD_sys_get_fps(void) {
return fps;
}
float TCOD_sys_get_last_frame_length(void) {
return last_frame_length;
}
void TCOD_sys_get_char_size(int *w, int *h) {
*w = TCOD_ctx.font_width;
*h = TCOD_ctx.font_height;
}
void TCOD_sys_get_current_resolution(int *w, int *h) {
TCOD_sys_startup();
sdl->get_current_resolution(w,h);
}
bool TCOD_sys_check_magic_number(const char *filename, size_t size, uint8_t*data) {
uint8_t tmp[128];
size_t i;
SDL_RWops *rwops = SDL_RWFromFile(filename, "rb");
if (! rwops) return false;
if ( (i = rwops->read(rwops,tmp,size,1)) != 1 ) {
rwops->close(rwops);
return false;
}
rwops->close(rwops);
for (i=0; i< size; i++) if (tmp[i]!=data[i]) return false;
return true;
}
void *TCOD_sys_get_SDL_window(void) {
return (void *)window;
}
void *TCOD_sys_get_SDL_renderer(void) {
return (void *)renderer;
}
void TCOD_mouse_show_cursor(bool visible) {
SDL_ShowCursor(visible ? 1 : 0);
}
bool TCOD_mouse_is_cursor_visible(void) {
return SDL_ShowCursor(-1) ? true : false;
}
void TCOD_mouse_move(int x, int y) {
sdl->set_mouse_position(x,y);
}
void TCOD_mouse_includes_touch(bool enable) {
#ifdef TCOD_TOUCH_INPUT
mouse_touch = enable;
#endif
}
bool TCOD_sys_clipboard_set(const char *value) {
if (!has_startup) { return false; }
return sdl->set_clipboard_text(value);
}
char *TCOD_sys_clipboard_get() {
if (!has_startup) { return ""; }
return sdl->get_clipboard_text();
}
bool TCOD_sys_read_file(const char *filename, unsigned char **buf, size_t *size) {
return sdl->file_read(filename,buf,size);
}
bool TCOD_sys_file_exists(const char * filename, ...) {
char f[1024];
va_list ap;
va_start(ap,filename);
vsprintf(f,filename,ap);
va_end(ap);
return sdl->file_exists(f);
}
bool TCOD_sys_write_file(const char *filename, unsigned char *buf, uint32_t size) {
return sdl->file_write(filename,buf,size);
}
void TCOD_sys_set_dirty(int dx, int dy, int dw, int dh) {
int x, y;
TCOD_console_data_t *dat = sdl->get_root_console_cache();
if (!dat) return;
TCOD_IFNOT(dx < dat->w && dy < dat->h && dx + dw >= 0 && dy + dh >= 0) return;
TCOD_IFNOT(dx >= 0) {
dw += dx;
dx = 0;
}
TCOD_IFNOT(dy >= 0) {
dh += dy;
dy = 0;
}
TCOD_IFNOT(dx + dw <= dat->w) dw = dat->w - dx;
TCOD_IFNOT(dy + dh <= dat->h) dh = dat->h - dy;
for (x = dx; x < dx + dw; ++x) {
for (y = dy; y < dy + dh; ++y) {
dat->ch_array[dat->w * y + x] = -1;
}
}
}
void TCOD_sys_set_dirty_character_code(int ch) {
int i;
TCOD_console_data_t *dat = sdl->get_root_console_cache();
if (!dat) return;
for (i = 0; i < dat->w * dat->h; ++i) {
if (dat->ch_array[i] == ch) {
dat->ch_array[i] = -1;
}
}
}
#endif