#include <console.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#ifndef NO_UNICODE
#include <wchar.h>
#include <wctype.h>
#endif
#include <noise.h>
#include <mersenne.h>
#include <libtcod_int.h>
#include <libtcod_utility.h>
#include <libtcod_version.h>
#ifdef TCOD_CONSOLE_SUPPORT
#if defined( TCOD_VISUAL_STUDIO )
static const char *version_string ="libtcod "TCOD_STRVERSION;
#else
static const char *version_string __attribute__((unused)) ="libtcod "TCOD_STRVERSION;
#endif
TCOD_internal_context_t TCOD_ctx={
16,16,
false,false,false,
8,8,
"terminal.png","",
NULL,NULL,NULL,0,false,0,0,0,0,0,0,
#ifdef TCOD_SDL2
TCOD_RENDERER_GLSL,
NULL,
#endif
{0,0,0},255,
{0},
false,
false,
true,
};
static TCOD_color_t color_control_fore[TCOD_COLCTRL_NUMBER];
static TCOD_color_t color_control_back[TCOD_COLCTRL_NUMBER];
void TCOD_console_set_color_control(TCOD_colctrl_t con, TCOD_color_t fore, TCOD_color_t back) {
TCOD_IFNOT(con >= TCOD_COLCTRL_1 && con <= TCOD_COLCTRL_NUMBER ) return;
color_control_fore[con-1]=fore;
color_control_back[con-1]=back;
}
TCOD_console_t TCOD_console_new(int w, int h) {
TCOD_IFNOT(w > 0 && h > 0 ) {
return NULL;
} else {
TCOD_console_data_t *con=(TCOD_console_data_t *)calloc(sizeof(TCOD_console_data_t),1);
con->w=w;
con->h=h;
TCOD_console_init(con,NULL,false);
if(TCOD_ctx.root) {
con->alignment=TCOD_ctx.root->alignment;
con->bkgnd_flag=TCOD_ctx.root->bkgnd_flag;
}
return (TCOD_console_t)con;
}
}
TCOD_key_t TCOD_console_check_for_keypress(int flags) {
return TCOD_sys_check_for_keypress(flags);
}
TCOD_key_t TCOD_console_wait_for_keypress(bool flush) {
return TCOD_sys_wait_for_keypress(flush);
}
bool TCOD_console_is_window_closed(void) {
return TCOD_ctx.is_window_closed;
}
bool TCOD_console_has_mouse_focus(void) {
return TCOD_ctx.app_has_mouse_focus;
}
#ifdef TCOD_SDL2
bool TCOD_console_is_active(void) {
return TCOD_ctx.app_is_active;
}
#endif
void TCOD_console_set_window_title(const char *title) {
TCOD_sys_set_window_title(title);
}
void TCOD_console_set_fullscreen(bool fullscreen) {
TCOD_IFNOT(TCOD_ctx.root != NULL) return;
TCOD_sys_set_fullscreen(fullscreen);
TCOD_ctx.fullscreen=fullscreen;
}
bool TCOD_console_is_fullscreen(void) {
return TCOD_ctx.fullscreen;
}
void TCOD_console_set_background_flag(TCOD_console_t con,TCOD_bkgnd_flag_t flag) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
dat->bkgnd_flag=flag;
}
TCOD_bkgnd_flag_t TCOD_console_get_background_flag(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return TCOD_BKGND_NONE;
return dat->bkgnd_flag;
}
void TCOD_console_set_alignment(TCOD_console_t con,TCOD_alignment_t alignment) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
dat->alignment=alignment;
}
TCOD_alignment_t TCOD_console_get_alignment(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return TCOD_LEFT;
return dat->alignment;
}
static void TCOD_console_data_free(TCOD_console_data_t *dat) {
if (dat->fg_colors) TCOD_image_delete(dat->fg_colors);
if (dat->bg_colors) TCOD_image_delete(dat->bg_colors);
free(dat->ch_array);
}
void TCOD_console_delete(TCOD_console_t con) {
TCOD_console_data_t *dat=(TCOD_console_data_t *)(con);
if (! dat ) {
dat=TCOD_ctx.root;
TCOD_sys_uninit();
TCOD_ctx.root=NULL;
}
TCOD_console_data_free(dat);
free(dat);
}
void TCOD_console_blit(TCOD_console_t srcCon, int xSrc, int ySrc, int wSrc, int hSrc,
TCOD_console_t dstCon, int xDst, int yDst, float foreground_alpha, float background_alpha) {
TCOD_console_data_t *src = srcCon ? (TCOD_console_data_t *)srcCon : TCOD_ctx.root;
TCOD_console_data_t *dst = dstCon ? (TCOD_console_data_t *)dstCon : TCOD_ctx.root;
TCOD_color_t *srcFgColors, *srcBgColors, *dstFgColors, *dstBgColors;
bool srcHasKeyColor;
TCOD_color_t srcKeyColor;
int cx, cy;
if (wSrc == 0) wSrc = src->w;
if (hSrc == 0) hSrc = src->h;
TCOD_IFNOT(wSrc > 0 && hSrc > 0) return;
TCOD_IFNOT(xDst + wSrc >= 0 && yDst + hSrc >= 0 && xDst < dst->w && yDst < dst->h) return;
TCOD_image_get_key_data(src->bg_colors, &srcHasKeyColor, &srcKeyColor);
srcFgColors = TCOD_image_get_colors(src->fg_colors);
srcBgColors = TCOD_image_get_colors(src->bg_colors);
dstFgColors = TCOD_image_get_colors(dst->fg_colors);
dstBgColors = TCOD_image_get_colors(dst->bg_colors);
for (cx = xSrc; cx < xSrc + wSrc; cx++) {
for (cy = ySrc; cy < ySrc + hSrc; cy++) {
int dx = cx - xSrc + xDst;
int dy = cy - ySrc + yDst;
int dst_idx = dy * dst->w + dx;
int src_idx = cy * src->w + cx;
int srcChar, dstChar;
TCOD_color_t srcFgColor, srcBgColor, dstFgColor, dstBgColor;
if ((unsigned)cx >= (unsigned)src->w || (unsigned)cy >= (unsigned)src->h) continue;
if ((unsigned)dx >= (unsigned)dst->w || (unsigned)dy >= (unsigned)dst->h) continue;
srcChar = src->ch_array[src_idx];
srcFgColor = srcFgColors[src_idx];
srcBgColor = srcBgColors[src_idx];
if (srcHasKeyColor &&
srcBgColor.r == srcKeyColor.r && srcBgColor.g == srcKeyColor.g && srcBgColor.b == srcKeyColor.b)
continue;
if (foreground_alpha == 1.0f && background_alpha == 1.0f) {
dstChar = srcChar;
dstFgColor = srcFgColor;
dstBgColor = srcBgColor;
}
else {
dstChar = dst->ch_array[dst_idx];
dstFgColor = dstFgColors[dst_idx];
dstBgColor = dstBgColors[dst_idx];
dstBgColor = TCOD_color_lerp(dstBgColor, srcBgColor, background_alpha);
if (srcChar == ' ') {
dstFgColor = TCOD_color_lerp(dstFgColor, srcBgColor, background_alpha);
}
else if (dstChar == ' ') {
dstChar = srcChar;
dstFgColor = TCOD_color_lerp(dstBgColor, srcFgColor, foreground_alpha);
}
else if (dstChar == srcChar) {
dstFgColor = TCOD_color_lerp(dstFgColor, srcFgColor, foreground_alpha);
}
else {
if (foreground_alpha < 0.5f) {
dstFgColor = TCOD_color_lerp(dstFgColor, dstBgColor,
foreground_alpha * 2);
}
else {
dstChar = srcChar;
dstFgColor = TCOD_color_lerp(dstBgColor, srcFgColor,
(foreground_alpha - 0.5f) * 2);
}
}
}
dstFgColors[dst_idx] = dstFgColor;
dstBgColors[dst_idx] = dstBgColor;
dst->ch_array[dst_idx] = dstChar;
}
}
TCOD_image_invalidate_mipmaps(dst->fg_colors);
TCOD_image_invalidate_mipmaps(dst->bg_colors);
}
void TCOD_console_flush(void) {
TCOD_IFNOT(TCOD_ctx.root != NULL) return;
TCOD_sys_flush(true);
}
void TCOD_console_set_fade(uint8_t val, TCOD_color_t fadecol) {
TCOD_ctx.fade=val;
TCOD_ctx.fading_color=fadecol;
}
uint8_t TCOD_console_get_fade(void) {
return TCOD_ctx.fade;
}
TCOD_color_t TCOD_console_get_fading_color(void) {
return TCOD_ctx.fading_color;
}
void TCOD_console_put_char(TCOD_console_t con, int x, int y, int c, TCOD_bkgnd_flag_t flag) {
int offset;
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL && (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h) return;
TCOD_IFNOT(c >= 0 && c < TCOD_ctx.max_font_chars) return;
offset = y * dat->w + x;
dat->ch_array[offset] = c;
TCOD_image_put_pixel(dat->fg_colors, x, y, dat->fore);
TCOD_console_set_char_background(con, x, y, dat->back, (TCOD_bkgnd_flag_t)flag);
}
void TCOD_console_put_char_ex(TCOD_console_t con, int x, int y, int c, TCOD_color_t fore, TCOD_color_t back) {
int offset;
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL && (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h) return;
TCOD_IFNOT(c >= 0 && c < TCOD_ctx.max_font_chars) return;
offset = y * dat->w + x;
dat->ch_array[offset] = c;
TCOD_image_put_pixel(dat->fg_colors, x, y, fore);
TCOD_image_put_pixel(dat->bg_colors, x, y, back);
}
void TCOD_console_set_dirty(int dx, int dy, int dw, int dh) {
TCOD_sys_set_dirty(dx, dy, dw, dh);
}
void TCOD_console_clear(TCOD_console_t con) {
int i;
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
for (i = 0; i < dat->w * dat->h; i++) {
dat->ch_array[i] = ' ';
}
TCOD_image_clear(dat->fg_colors, dat->fore);
TCOD_image_clear(dat->bg_colors, dat->back);
TCOD_sys_set_dirty(0, 0, dat->w, dat->h);
}
TCOD_color_t TCOD_console_get_char_background(TCOD_console_t con, int x, int y) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h)
return TCOD_black;
return TCOD_image_get_pixel(dat->bg_colors, x, y);
}
void TCOD_console_set_char_foreground(TCOD_console_t con, int x, int y, TCOD_color_t col) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
if ((unsigned)(x) >= (unsigned)dat->w || (unsigned)(y) >= (unsigned)dat->h) return;
TCOD_IFNOT(dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h)
return;
TCOD_image_put_pixel(dat->fg_colors, x, y, col);
}
TCOD_color_t TCOD_console_get_char_foreground(TCOD_console_t con, int x, int y) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h)
return TCOD_white;
return TCOD_image_get_pixel(dat->fg_colors, x, y);
}
int TCOD_console_get_char(TCOD_console_t con, int x, int y) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h)
return 0;
return dat->ch_array[y * dat->w + x];
}
void TCOD_console_set_char_background(TCOD_console_t con, int x, int y, TCOD_color_t col, TCOD_bkgnd_flag_t flag) {
TCOD_color_t *back;
int newr, newg, newb;
int alpha;
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h)
return;
back = &(TCOD_image_get_colors(dat->bg_colors)[y*dat->w + x]);
if (flag == TCOD_BKGND_DEFAULT) flag = dat->bkgnd_flag;
switch (flag & 0xff) {
case TCOD_BKGND_SET: *back = col; break;
case TCOD_BKGND_MULTIPLY: *back = TCOD_color_multiply(*back, col); break;
case TCOD_BKGND_LIGHTEN:
back->r = MAX(back->r, col.r);
back->g = MAX(back->g, col.g);
back->b = MAX(back->b, col.b);
break;
case TCOD_BKGND_DARKEN:
back->r = MIN(back->r, col.r);
back->g = MIN(back->g, col.g);
back->b = MIN(back->b, col.b);
break;
case TCOD_BKGND_SCREEN:
back->r = (uint8_t)(255 - (int)(255 - back->r)*(255 - col.r) / 255);
back->g = (uint8_t)(255 - (int)(255 - back->g)*(255 - col.g) / 255);
back->b = (uint8_t)(255 - (int)(255 - back->b)*(255 - col.b) / 255);
break;
case TCOD_BKGND_COLOR_DODGE:
if (back->r != 255) newr = (int)(255 * col.r) / (255 - back->r);
else newr = 255;
if (back->g != 255) newg = (int)(255 * col.g) / (255 - back->g);
else newg = 255;
if (back->b != 255) newb = (int)(255 * col.b) / (255 - back->b);
else newb = 255;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_COLOR_BURN:
if (col.r > 0) newr = 255 - (int)(255 * (255 - back->r)) / col.r;
else newr = 0;
if (col.g > 0) newg = 255 - (int)(255 * (255 - back->g)) / col.g;
else newg = 0;
if (col.b > 0) newb = 255 - (int)(255 * (255 - back->b)) / col.b;
else newb = 0;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_ADD:
newr = (int)(back->r) + col.r;
newg = (int)(back->g) + col.g;
newb = (int)(back->b) + col.b;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_ADDA:
alpha = (flag >> 8);
newr = (int)(back->r) + alpha * col.r / 255;
newg = (int)(back->g) + alpha * col.g / 255;
newb = (int)(back->b) + alpha * col.b / 255;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_BURN:
newr = (int)(back->r) + col.r - 255;
newg = (int)(back->g) + col.g - 255;
newb = (int)(back->b) + col.b - 255;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_OVERLAY:
newr = col.r <= 128 ? 2 * (int)(col.r) * back->r / 255 : 255 - 2 * (int)(255 - col.r)*(255 - back->r) / 255;
newg = col.g <= 128 ? 2 * (int)(col.g) * back->g / 255 : 255 - 2 * (int)(255 - col.g)*(255 - back->g) / 255;
newb = col.b <= 128 ? 2 * (int)(col.b) * back->b / 255 : 255 - 2 * (int)(255 - col.b)*(255 - back->b) / 255;
back->r = (uint8_t)CLAMP(0, 255, newr);
back->g = (uint8_t)CLAMP(0, 255, newg);
back->b = (uint8_t)CLAMP(0, 255, newb);
break;
case TCOD_BKGND_ALPH:
alpha = (flag >> 8);
*back = TCOD_color_lerp(*back, col, (float)(alpha / 255.0f));
break;
default: break;
}
}
void TCOD_console_set_char(TCOD_console_t con, int x, int y, int c) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
if ((unsigned)(x) >= (unsigned)dat->w || (unsigned)(y) >= (unsigned)dat->h) return;
dat->ch_array[y * dat->w + x] = c;
}
static void TCOD_console_clamp(int cx, int cy, int cw, int ch, int *x, int *y, int *w, int *h) {
if (*x + *w > cw) *w = cw - *x;
if (*y + *h > ch) *h = ch - *y;
if (*x < cx) {
*w -= cx - *x;
*x = cx;
}
if (*y < cy) {
*h -= cy - *y;
*y = cy;
}
}
void TCOD_console_rect(TCOD_console_t con, int x, int y, int rw, int rh, bool clear, TCOD_bkgnd_flag_t flag) {
int cx, cy;
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
TCOD_ASSERT((unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h);
TCOD_ASSERT(x + rw <= dat->w && y + rh <= dat->h);
TCOD_console_clamp(0, 0, dat->w, dat->h, &x, &y, &rw, &rh);
TCOD_IFNOT(rw > 0 && rh > 0) return;
for (cx = x; cx < x + rw; cx++) {
for (cy = y; cy<y + rh; cy++) {
TCOD_console_set_char_background(con, cx, cy, dat->back, flag);
if (clear) {
dat->ch_array[cx + cy*dat->w] = ' ';
}
}
}
}
void TCOD_console_hline(TCOD_console_t con,int x,int y, int l, TCOD_bkgnd_flag_t flag) {
int i;
for (i=x; i< x+l; i++) TCOD_console_put_char(con,i,y,TCOD_CHAR_HLINE,flag);
}
void TCOD_console_vline(TCOD_console_t con,int x,int y, int l, TCOD_bkgnd_flag_t flag) {
int i;
for (i=y; i< y+l; i++) TCOD_console_put_char(con,x,i,TCOD_CHAR_VLINE,flag);
}
char *TCOD_console_vsprint(const char *fmt, va_list ap) {
#define NB_BUFFERS 10
#define INITIAL_SIZE 512
static char *msg[NB_BUFFERS]={NULL};
static int buflen[NB_BUFFERS]={0};
static int curbuf=0;
char *ret;
bool ok=false;
if (!msg[0]) {
int i;
for (i=0; i < NB_BUFFERS; i++) {
buflen[i]=INITIAL_SIZE;
msg[i]=(char *)calloc(sizeof(char),INITIAL_SIZE);
}
}
do {
int len = vsnprintf(msg[curbuf],buflen[curbuf],fmt,ap);
ok=true;
if (len < 0 || len >= buflen[curbuf]) {
if ( len > 0 ) {
while ( buflen[curbuf] < len+1 ) buflen[curbuf]*=2;
} else {
buflen[curbuf]*=2;
}
free( msg[curbuf] );
msg[curbuf]=(char *)calloc(sizeof(char),buflen[curbuf]);
ok=false;
}
} while (! ok);
ret=msg[curbuf];
curbuf = (curbuf+1)%NB_BUFFERS;
return ret;
}
void TCOD_console_print_frame(TCOD_console_t con,int x,int y,int w,int h, bool empty, TCOD_bkgnd_flag_t flag, const char *fmt, ...) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_console_put_char(con,x,y,TCOD_CHAR_NW,flag);
TCOD_console_put_char(con,x+w-1,y,TCOD_CHAR_NE,flag);
TCOD_console_put_char(con,x,y+h-1,TCOD_CHAR_SW,flag);
TCOD_console_put_char(con,x+w-1,y+h-1,TCOD_CHAR_SE,flag);
TCOD_console_hline(con,x+1,y,w-2,flag);
TCOD_console_hline(con,x+1,y+h-1,w-2,flag);
if ( h > 2 ) {
TCOD_console_vline(con,x,y+1,h-2,flag);
TCOD_console_vline(con,x+w-1,y+1,h-2,flag);
if ( empty ) {
TCOD_console_rect(con,x+1,y+1,w-2,h-2,true,flag);
}
}
if (fmt) {
va_list ap;
int xs;
TCOD_color_t tmp;
char *title;
va_start(ap,fmt);
title = TCOD_console_vsprint(fmt,ap);
va_end(ap);
title[w-3]=0;
xs = x + (w-(int)strlen(title)-2)/2;
tmp=dat->back;
dat->back=dat->fore;
dat->fore=tmp;
TCOD_console_print_ex(con,xs,y,TCOD_BKGND_SET,TCOD_LEFT," %s ",title);
tmp=dat->back;
dat->back=dat->fore;
dat->fore=tmp;
}
}
void TCOD_console_print(TCOD_console_t con,int x, int y, const char *fmt, ...) {
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
va_start(ap,fmt);
TCOD_console_print_internal(con,x,y,0,0,dat->bkgnd_flag,
dat->alignment,TCOD_console_vsprint(fmt,ap), false, false);
va_end(ap);
}
void TCOD_console_print_ex(TCOD_console_t con,int x, int y,
TCOD_bkgnd_flag_t flag, TCOD_alignment_t alignment, const char *fmt, ...) {
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
va_start(ap,fmt);
TCOD_console_print_internal(con,x,y,0,0,flag,alignment,
TCOD_console_vsprint(fmt,ap), false, false);
va_end(ap);
}
int TCOD_console_print_rect(TCOD_console_t con,int x, int y, int w, int h, const char *fmt, ...) {
int ret;
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return 0;
va_start(ap,fmt);
ret = TCOD_console_print_internal(con,x,y,w,h,dat->bkgnd_flag,dat->alignment,
TCOD_console_vsprint(fmt,ap), true, false);
va_end(ap);
return ret;
}
int TCOD_console_print_rect_ex(TCOD_console_t con,int x, int y, int w, int h,
TCOD_bkgnd_flag_t flag, TCOD_alignment_t alignment,const char *fmt, ...) {
int ret;
va_list ap;
va_start(ap,fmt);
ret = TCOD_console_print_internal(con,x,y,w,h,flag,alignment,TCOD_console_vsprint(fmt,ap), true, false);
va_end(ap);
return ret;
}
int TCOD_console_get_height_rect(TCOD_console_t con,int x, int y, int w, int h, const char *fmt, ...) {
int ret;
va_list ap;
va_start(ap,fmt);
ret = TCOD_console_print_internal(con,x,y,w,h,TCOD_BKGND_NONE,TCOD_LEFT,TCOD_console_vsprint(fmt,ap), true, true);
va_end(ap);
return ret;
}
int TCOD_console_stringLength(const unsigned char *s) {
int l=0;
while (*s) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
else if ( (unsigned)(*s) > (unsigned)TCOD_COLCTRL_STOP ) l++;
s++;
}
return l;
}
unsigned char * TCOD_console_forward(unsigned char *s,int l) {
while ( *s && l > 0 ) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
else if ( *s > (int)TCOD_COLCTRL_STOP ) l--;
s++;
}
return s;
}
unsigned char *TCOD_console_strchr(unsigned char *s, unsigned char c) {
while ( *s && *s != c ) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
s++;
}
return (*s ? s : NULL);
}
int TCOD_console_print_internal(TCOD_console_t con,int x,int y, int rw, int rh, TCOD_bkgnd_flag_t flag,
TCOD_alignment_t align, char *msg, bool can_split, bool count_only) {
unsigned char *c=(unsigned char *)msg;
int cx=0,cy=y;
int minx,maxx,miny,maxy;
TCOD_color_t oldFore;
TCOD_color_t oldBack;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h )
return 0;
TCOD_IFNOT(msg != NULL) return 0;
if ( rh == 0 ) rh = dat->h-y;
if ( rw == 0 ) switch(align) {
case TCOD_LEFT : rw = dat->w-x; break;
case TCOD_RIGHT : rw=x+1; break;
case TCOD_CENTER : default : rw=dat->w; break;
}
oldFore=dat->fore;
oldBack=dat->back;
miny=y;
maxy=dat->h-1;
if (rh > 0) maxy=MIN(maxy,y+rh-1);
switch (align) {
case TCOD_LEFT : minx=MAX(0,x); maxx=MIN(dat->w-1,x+rw-1); break;
case TCOD_RIGHT : minx=MAX(0,x-rw+1); maxx=MIN(dat->w-1,x); break;
case TCOD_CENTER : default : minx=MAX(0,x-rw/2); maxx=MIN(dat->w-1,x+rw/2); break;
}
do {
unsigned char *end=TCOD_console_strchr(c,'\n');
char bak=0;
int cl;
unsigned char *split=NULL;
if ( end ) *end=0;
cl= TCOD_console_stringLength(c);
switch (align) {
case TCOD_LEFT : cx=x; break;
case TCOD_RIGHT : cx=x-cl+1; break;
case TCOD_CENTER : cx= x-cl/2;break;
}
if ( cy >= miny && cy <= maxy && cx <= maxx && cx+cl -1 >= minx ) {
if ( can_split && cy <= maxy ) {
if ( cx < minx ) split = TCOD_console_forward(c, align == TCOD_CENTER ? cl-2*(minx-cx) : cl-(minx-cx));
else if ( align == TCOD_CENTER ) {
if ( cx + cl/2 > maxx+1 ) split = TCOD_console_forward(c, maxx+1 - cx);
} else {
if ( cx + cl > maxx+1 ) split = TCOD_console_forward(c, maxx+1 - cx);
}
}
if ( split ) {
unsigned char *oldsplit=split;
while ( ! isspace(*split) && split > c ) split --;
if (end) *end='\n';
if (!isspace(*split) ) {
split=oldsplit;
}
end=split;
bak=*split;
*split=0;
cl=TCOD_console_stringLength(c);
switch (align) {
case TCOD_LEFT : cx=x; break;
case TCOD_RIGHT : cx=x-cl+1; break;
case TCOD_CENTER : cx= x-cl/2;break;
}
}
if ( cx < minx ) {
c += minx-cx;
cl -= minx-cx;
cx=minx;
}
if ( cx + cl > maxx+1 ) {
split = TCOD_console_forward(c, maxx+1 - cx);
*split=0;
}
if ( cy >= 0 && cy < dat->h )
while (*c) {
if ( *c >= TCOD_COLCTRL_1 && *c <= TCOD_COLCTRL_NUMBER ) {
dat->fore=color_control_fore[(int)(*c)-1];
dat->back=color_control_back[(int)(*c)-1];
} else if ( *c == TCOD_COLCTRL_FORE_RGB ) {
c++;
dat->fore.r=*c++;
dat->fore.g=*c++;
dat->fore.b=*c;
} else if ( *c == TCOD_COLCTRL_BACK_RGB ) {
c++;
dat->back.r=*c++;
dat->back.g=*c++;
dat->back.b=*c;
} else if ( *c == TCOD_COLCTRL_STOP ) {
dat->fore=oldFore;
dat->back=oldBack;
} else {
if (! count_only) TCOD_console_put_char(con,cx,cy,(int)(*c),flag);
cx++;
}
c++;
}
}
if ( end ) {
if ( split && ! isspace(bak) ) {
*end=bak;
c=end;
} else {
c=end+1;
}
cy++;
} else c=NULL;
} while ( c && cy < dat->h && (rh == 0 || cy < y+rh) );
return cy-y+1;
}
#ifndef NO_UNICODE
wchar_t *TCOD_console_strchr_utf(wchar_t *s, char c) {
while ( *s && *s != c ) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
s++;
}
return (*s ? s : NULL);
}
void TCOD_console_map_string_to_font_utf(const wchar_t *s, int fontCharX, int fontCharY) {
TCOD_IFNOT(s != NULL) return;
while (*s) {
TCOD_sys_map_ascii_to_font(*s, fontCharX, fontCharY);
fontCharX++;
if ( fontCharX == TCOD_ctx.fontNbCharHoriz ) {
fontCharX=0;
fontCharY++;
}
s++;
}
}
wchar_t *TCOD_console_vsprint_utf(const wchar_t *fmt, va_list ap) {
#define NB_BUFFERS 10
#define INITIAL_SIZE 512
static wchar_t *msg[NB_BUFFERS]={NULL};
static int buflen[NB_BUFFERS]={0};
static int curbuf=0;
wchar_t *ret;
bool ok=false;
if (!msg[0]) {
int i;
for (i=0; i < NB_BUFFERS; i++) {
buflen[i]=INITIAL_SIZE;
msg[i]=(wchar_t *)calloc(sizeof(wchar_t),INITIAL_SIZE);
}
}
do {
int len = vsnwprintf(msg[curbuf],buflen[curbuf],fmt,ap);
ok=true;
if (len < 0 || len >= buflen[curbuf]) {
if ( len > 0 ) {
while ( buflen[curbuf] < len+1 ) buflen[curbuf]*=2;
} else {
buflen[curbuf]*=2;
}
free( msg[curbuf] );
msg[curbuf]=(wchar_t *)calloc(sizeof(wchar_t),buflen[curbuf]);
ok=false;
}
} while (! ok);
ret=msg[curbuf];
curbuf = (curbuf+1)%NB_BUFFERS;
return ret;
}
int TCOD_console_stringLength_utf(const wchar_t *s) {
int l=0;
while (*s) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
else if ( *s > (int)TCOD_COLCTRL_STOP ) l++;
s++;
}
return l;
}
wchar_t * TCOD_console_forward_utf(wchar_t *s,int l) {
while ( *s && l > 0 ) {
if ( *s == (int)TCOD_COLCTRL_FORE_RGB || *s == (int)TCOD_COLCTRL_BACK_RGB ) s+=3;
else if ( *s > (int)TCOD_COLCTRL_STOP ) l--;
s++;
}
return s;
}
int TCOD_console_print_internal_utf(TCOD_console_t con,int x,int y, int rw, int rh, TCOD_bkgnd_flag_t flag,
TCOD_alignment_t align, wchar_t *msg, bool can_split, bool count_only) {
wchar_t *c=msg;
int cx=0,cy=y;
int minx,maxx,miny,maxy;
TCOD_color_t oldFore;
TCOD_color_t oldBack;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL
&& (unsigned)(x) < (unsigned)dat->w && (unsigned)(y) < (unsigned)dat->h )
return 0;
TCOD_IFNOT(msg != NULL) return 0;
if ( rh == 0 ) rh = dat->h-y;
if ( rw == 0 ) switch(align) {
case TCOD_LEFT : rw = dat->w-x; break;
case TCOD_RIGHT : rw=x+1; break;
case TCOD_CENTER : default : rw=dat->w; break;
}
oldFore=dat->fore;
oldBack=dat->back;
miny=y;
maxy=dat->h-1;
if (rh > 0) maxy=MIN(maxy,y+rh-1);
switch (align) {
case TCOD_LEFT : minx=MAX(0,x); maxx=MIN(dat->w-1,x+rw-1); break;
case TCOD_RIGHT : minx=MAX(0,x-rw+1); maxx=MIN(dat->w-1,x); break;
case TCOD_CENTER : default : minx=MAX(0,x-rw/2); maxx=MIN(dat->w-1,x+rw/2); break;
}
do {
wchar_t *end=TCOD_console_strchr_utf(c,'\n');
wchar_t bak=0;
int cl;
wchar_t *split=NULL;
if ( end ) *end=0;
cl= TCOD_console_stringLength_utf(c);
switch (align) {
case TCOD_LEFT : cx=x; break;
case TCOD_RIGHT : cx=x-cl+1; break;
case TCOD_CENTER : cx= x-cl/2;break;
}
if ( cy >= miny && cy <= maxy && cx <= maxx && cx+cl -1 >= minx ) {
if ( can_split && cy < maxy ) {
if ( cx < minx ) split = TCOD_console_forward_utf(c, align == TCOD_CENTER ? cl-2*(minx-cx) : cl-(minx-cx));
else if ( align==TCOD_CENTER ) {
if ( cx + cl/2 > maxx+1 ) split = TCOD_console_forward_utf(c, maxx+1 - cx);
} else {
if ( cx + cl > maxx+1 ) split = TCOD_console_forward_utf(c, maxx+1 - cx);
}
}
if ( split ) {
wchar_t *oldsplit=split;
while ( ! iswspace(*split) && split > c ) split --;
if (end) *end='\n';
if (!iswspace(*split) ) {
split=oldsplit;
}
end=split;
bak=*split;
*split=0;
cl=TCOD_console_stringLength_utf(c);
switch (align) {
case TCOD_LEFT : cx=x; break;
case TCOD_RIGHT : cx=x-cl+1; break;
case TCOD_CENTER : cx= x-cl/2;break;
}
}
if ( cx < minx ) {
c += minx-cx;
cl -= minx-cx;
cx=minx;
}
if ( cx + cl > maxx+1 ) {
split = TCOD_console_forward_utf(c, maxx+1 - cx);
*split=0;
}
if ( cy >= 0 && cy < dat->h )
while (*c) {
if ( *c >= TCOD_COLCTRL_1 && *c <= TCOD_COLCTRL_NUMBER ) {
dat->fore=color_control_fore[(int)(*c)-1];
dat->back=color_control_back[(int)(*c)-1];
} else if ( *c == TCOD_COLCTRL_FORE_RGB ) {
c++;
dat->fore.r=(uint8_t)(*c++);
dat->fore.g=(uint8_t)(*c++);
dat->fore.b=(uint8_t)(*c);
} else if ( *c == TCOD_COLCTRL_BACK_RGB ) {
c++;
dat->back.r=(uint8_t)(*c++);
dat->back.g=(uint8_t)(*c++);
dat->back.b=(uint8_t)(*c);
} else if ( *c == TCOD_COLCTRL_STOP ) {
dat->fore=oldFore;
dat->back=oldBack;
} else {
if (! count_only) TCOD_console_put_char(con,cx,cy,(int)(*c),flag);
cx++;
}
c++;
}
}
if ( end ) {
if ( split && ! iswspace(bak) ) {
*end=bak;
c=end;
} else {
c=end+1;
}
cy++;
} else c=NULL;
} while ( c && cy < dat->h && (rh == 0 || cy < y+rh) );
return cy-y+1;
}
void TCOD_console_print_utf(TCOD_console_t con,int x, int y, const wchar_t *fmt, ...) {
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
va_start(ap,fmt);
TCOD_console_print_internal_utf(con,x,y,0,0,dat->bkgnd_flag,dat->alignment,
TCOD_console_vsprint_utf(fmt,ap), false, false);
va_end(ap);
}
void TCOD_console_print_ex_utf(TCOD_console_t con,int x, int y,
TCOD_bkgnd_flag_t flag, TCOD_alignment_t alignment, const wchar_t *fmt, ...) {
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return;
va_start(ap,fmt);
TCOD_console_print_internal_utf(con,x,y,0,0,flag,alignment,TCOD_console_vsprint_utf(fmt,ap), false, false);
va_end(ap);
}
int TCOD_console_print_rect_utf(TCOD_console_t con,int x, int y, int w, int h,
const wchar_t *fmt, ...) {
int ret;
va_list ap;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT ( dat != NULL ) return 0;
va_start(ap,fmt);
ret = TCOD_console_print_internal_utf(con,x,y,w,h,dat->bkgnd_flag,dat->alignment,
TCOD_console_vsprint_utf(fmt,ap), true, false);
va_end(ap);
return ret;
}
int TCOD_console_print_rect_ex_utf(TCOD_console_t con,int x, int y, int w, int h,
TCOD_bkgnd_flag_t flag, TCOD_alignment_t alignment, const wchar_t *fmt, ...) {
int ret;
va_list ap;
va_start(ap,fmt);
ret=TCOD_console_print_internal_utf(con,x,y,w,h,flag,alignment,TCOD_console_vsprint_utf(fmt,ap), true, false);
va_end(ap);
return ret;
}
int TCOD_console_get_height_rect_utf(TCOD_console_t con,int x, int y, int w, int h, const wchar_t *fmt, ...) {
int ret;
va_list ap;
va_start(ap,fmt);
ret = TCOD_console_print_internal_utf(con,x,y,w,h,TCOD_BKGND_NONE,TCOD_LEFT,TCOD_console_vsprint_utf(fmt,ap), true, true);
va_end(ap);
return ret;
}
#endif
void TCOD_console_init_root(int w, int h, const char*title, bool fullscreen, TCOD_renderer_t renderer) {
TCOD_IF(w > 0 && h > 0) {
TCOD_console_data_t *con=(TCOD_console_data_t *)calloc(sizeof(TCOD_console_data_t),1);
int i;
con->w=w;
con->h=h;
TCOD_ctx.root=con;
#ifdef TCOD_SDL2
TCOD_ctx.renderer=renderer;
#endif
for (i=0; i < TCOD_COLCTRL_NUMBER; i++) {
color_control_fore[i]=TCOD_white;
color_control_back[i]=TCOD_black;
}
TCOD_console_init((TCOD_console_t)con,title,fullscreen);
}
}
static void TCOD_console_data_alloc(TCOD_console_data_t *dat) {
dat->ch_array = (int *)calloc(sizeof(int), dat->w*dat->h);
dat->fg_colors = TCOD_image_new(dat->w, dat->h);
dat->bg_colors = TCOD_image_new(dat->w, dat->h);
}
bool TCOD_console_init(TCOD_console_t con,const char *title, bool fullscreen) {
int i;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return false;
dat->fore=TCOD_white;
dat->back=TCOD_black;
TCOD_console_data_alloc(dat);
dat->bkgnd_flag=TCOD_BKGND_NONE;
dat->alignment=TCOD_LEFT;
for (i=0; i< dat->w*dat->h; i++) {
dat->ch_array[i] = ' ';
}
if ( title ) {
if (! TCOD_sys_init(dat, fullscreen) ) return false;
TCOD_sys_set_window_title(title);
}
return true;
}
void TCOD_console_set_default_foreground(TCOD_console_t con,TCOD_color_t col) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
dat->fore=col;
}
void TCOD_console_set_default_background(TCOD_console_t con,TCOD_color_t col) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
dat->back=col;
}
TCOD_color_t TCOD_console_get_default_foreground(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return TCOD_white;
return dat->fore;
}
TCOD_color_t TCOD_console_get_default_background(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return TCOD_black;
return dat->back;
}
int TCOD_console_get_width(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return 0;
return dat->w;
}
int TCOD_console_get_height(TCOD_console_t con) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return 0;
return dat->h;
}
TCOD_image_t TCOD_console_get_foreground_color_image(TCOD_console_t con) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return NULL;
return dat->fg_colors;
}
TCOD_image_t TCOD_console_get_background_color_image(TCOD_console_t con) {
TCOD_console_data_t *dat = con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return NULL;
return dat->bg_colors;
}
void TCOD_console_set_custom_font(const char *fontFile, int flags,int nb_char_horiz, int nb_char_vertic) {
TCOD_sys_set_custom_font(fontFile, nb_char_horiz, nb_char_vertic, flags);
}
void TCOD_console_map_ascii_code_to_font(int asciiCode, int fontCharX, int fontCharY) {
TCOD_IFNOT(TCOD_ctx.root != NULL) return;
TCOD_sys_map_ascii_to_font(asciiCode, fontCharX, fontCharY);
}
void TCOD_console_map_ascii_codes_to_font(int asciiCode, int nbCodes, int fontCharX, int fontCharY) {
int c;
TCOD_IFNOT(TCOD_ctx.root != NULL) return;
TCOD_IFNOT(asciiCode >= 0 && asciiCode+nbCodes <= TCOD_ctx.max_font_chars) return;
for (c=asciiCode; c < asciiCode+nbCodes; c++ ) {
TCOD_sys_map_ascii_to_font(c, fontCharX, fontCharY);
fontCharX++;
if ( fontCharX == TCOD_ctx.fontNbCharHoriz ) {
fontCharX=0;
fontCharY++;
}
}
}
void TCOD_console_map_string_to_font(const char *s, int fontCharX, int fontCharY) {
TCOD_IFNOT(s != NULL) return;
TCOD_IFNOT(TCOD_ctx.root != NULL) return;
while (*s) {
TCOD_console_map_ascii_code_to_font(*s, fontCharX, fontCharY);
fontCharX++;
if ( fontCharX == TCOD_ctx.fontNbCharHoriz ) {
fontCharX=0;
fontCharY++;
}
s++;
}
}
bool TCOD_console_is_key_pressed(TCOD_keycode_t key) {
return TCOD_sys_is_key_pressed(key);
}
void TCOD_console_set_key_color(TCOD_console_t con,TCOD_color_t col) {
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
TCOD_image_set_key_color(dat->bg_colors, col);
}
void TCOD_console_credits(void) {
bool end=false;
int x=TCOD_console_get_width(NULL)/2-6;
int y=TCOD_console_get_height(NULL)/2;
int fade=260;
TCOD_sys_save_fps();
TCOD_sys_set_fps(25);
while (!end ) {
TCOD_key_t k;
end=TCOD_console_credits_render(x,y,false);
TCOD_sys_check_for_event(TCOD_EVENT_KEY_PRESS,&k,NULL);
if ( fade == 260 && k.vk != TCODK_NONE ) {
fade -= 10;
}
TCOD_console_flush();
if ( fade < 260 ) {
fade -= 10;
TCOD_console_set_fade(fade,TCOD_black);
if ( fade == 0 ) end=true;
}
}
TCOD_console_set_fade(255,TCOD_black);
TCOD_sys_restore_fps();
}
static bool init2=false;
void TCOD_console_credits_reset(void) {
init2=false;
}
bool TCOD_console_credits_render(int x, int y, bool alpha) {
static char poweredby[128];
static float char_heat[128];
static int char_x[128];
static int char_y[128];
static bool init1=false;
static int len,len1,cw=-1,ch=-1;
static float xstr;
static TCOD_color_t colmap[64];
static TCOD_color_t colmap_light[64];
static TCOD_noise_t noise;
static TCOD_color_t colkeys[4] = {
{255,255,204},
{255,204,0},
{255,102,0},
{102,153,255},
};
static TCOD_color_t colkeys_light[4] = {
{255,255,204},
{128,128,77},
{51,51,31},
{0,0,0},
};
static int colpos[4]={
0,21,42,63
};
static TCOD_image_t img=NULL;
int i,xc,yc,xi,yi,j;
static int left,right,top,bottom;
float sparklex,sparkley,sparklerad,sparklerad2,noisex;
#define MAX_PARTICULES 50
static float pheat[MAX_PARTICULES];
static float px[MAX_PARTICULES],py[MAX_PARTICULES], pvx[MAX_PARTICULES],pvy[MAX_PARTICULES];
static int nbpart=0, firstpart=0;
static float partDelay=0.1f;
float elapsed=TCOD_sys_get_last_frame_length();
TCOD_color_t fbackup;
if (!init1) {
TCOD_color_t col;
TCOD_color_gen_map(colmap,4,colkeys,colpos);
TCOD_color_gen_map(colmap_light,4,colkeys_light,colpos);
sprintf(poweredby,"Powered by\n%s",version_string);
noise=TCOD_noise_new(1,TCOD_NOISE_DEFAULT_HURST,TCOD_NOISE_DEFAULT_LACUNARITY,NULL);
len=(int)strlen(poweredby);
len1=11;
left=MAX(x-4,0);
top=MAX(y-4,0);
col= TCOD_console_get_default_background(NULL);
TCOD_console_set_default_background(NULL,TCOD_black);
TCOD_console_set_default_background(NULL,col);
init1=true;
}
if (!init2) {
int curx,cury;
xstr=-4.0f;
curx=x;
cury=y;
for (i=0; i < len ;i++) {
char_heat[i]=-1;
char_x[i]=curx;
char_y[i]=cury;
curx++;
if ( poweredby[i] == '\n' ) {
curx=x;
cury++;
}
}
nbpart=firstpart=0;
init2=true;
}
if (TCOD_console_get_width(NULL) != cw || TCOD_console_get_height(NULL)!=ch) {
int width,height;
cw=TCOD_console_get_width(NULL);
ch=TCOD_console_get_height(NULL);
right=MIN(x+len,cw-1);
bottom=MIN(y+6,ch-1);
width=right - left + 1;
height=bottom - top + 1;
if ( img ) TCOD_image_delete(img);
img = TCOD_image_new(width*2,height*2);
}
fbackup=TCOD_console_get_default_foreground(NULL);
if ( xstr < (float)len1 ) {
sparklex=x+xstr;
sparkley=(float)y;
} else {
sparklex=x-len1+xstr;
sparkley=(float)y+1;
}
noisex=xstr*6;
sparklerad=3.0f+2*TCOD_noise_get(noise,&noisex);
if ( xstr >= len-1 ) sparklerad -= (xstr-len+1)*4.0f;
else if ( xstr < 0.0f ) sparklerad += xstr*4.0f;
else if ( poweredby[ (int)(xstr+0.5f) ] == ' ' || poweredby[ (int)(xstr+0.5f) ] == '\n' ) sparklerad/=2;
sparklerad2=sparklerad*sparklerad*4;
for (xc=left*2,xi=0; xc < (right+1)*2; xc++,xi++) {
for (yc=top*2,yi=0; yc < (bottom+1)*2; yc++,yi++) {
float dist=((xc-2*sparklex)*(xc-2*sparklex)+(yc-2*sparkley)*(yc-2*sparkley));
TCOD_color_t pixcol;
if ( sparklerad >= 0.0f && dist < sparklerad2 ) {
int colidx=63-(int)(63*(sparklerad2-dist)/sparklerad2) + TCOD_random_get_int(NULL,-10,10);
colidx=CLAMP(0,63,colidx);
pixcol=colmap_light[colidx];
} else {
pixcol=TCOD_black;
}
if ( alpha ) {
static int asciiToFlag[] = {
1,
2,
3,
8,
9,
10,
4,
};
int conc= TCOD_console_get_char(NULL,xc/2,yc/2);
TCOD_color_t bk=TCOD_console_get_char_background(NULL,xc/2,yc/2);
if ( conc >= TCOD_CHAR_SUBP_NW && conc <= TCOD_CHAR_SUBP_SW ) {
int bkflag=asciiToFlag[conc - TCOD_CHAR_SUBP_NW ];
int xflag = (xc & 1);
int yflag = (yc & 1);
int credflag = (1+3*yflag) * (xflag+1);
if ( (credflag & bkflag) != 0 ) {
bk = TCOD_console_get_char_foreground(NULL,xc/2,yc/2);
}
}
pixcol.r = MIN(255,(int)(bk.r)+pixcol.r);
pixcol.g = MIN(255,(int)(bk.g)+pixcol.g);
pixcol.b = MIN(255,(int)(bk.b)+pixcol.b);
}
TCOD_image_put_pixel(img,xi,yi,pixcol);
}
}
j=nbpart;i=firstpart;
while (j > 0) {
int colidx=(int)(64*(1.0f-pheat[i]));
TCOD_color_t col;
colidx=MIN(63,colidx);
col=colmap[colidx];
if ( (int)py[i]< (bottom-top+1)*2 ) {
int ipx = (int)px[i];
int ipy = (int)py[i];
float fpx = px[i]-ipx;
float fpy = py[i]-ipy;
TCOD_color_t col2=TCOD_image_get_pixel(img,ipx,ipy);
col2=TCOD_color_lerp(col,col2,0.5f*(fpx+fpy));
TCOD_image_put_pixel(img,ipx,ipy,col2);
col2=TCOD_image_get_pixel(img,ipx+1,ipy);
col2=TCOD_color_lerp(col2,col,fpx);
TCOD_image_put_pixel(img,ipx+1,ipy,col2);
col2=TCOD_image_get_pixel(img,ipx,ipy+1);
col2=TCOD_color_lerp(col2,col,fpy);
TCOD_image_put_pixel(img,ipx,ipy+1,col2);
} else pvy[i]=-pvy[i] * 0.5f;
pvx[i] *= (1.0f-elapsed);
pvy[i] += (1.0f-pheat[i])*elapsed*300.0f;
px[i] += pvx[i]*elapsed;
py[i] += pvy[i]*elapsed;
pheat[i] -= elapsed*0.3f;
if ( pheat[i] < 0.0f ) {
firstpart = (firstpart+1)%MAX_PARTICULES;
nbpart--;
}
i = (i+1)%MAX_PARTICULES;
j--;
}
partDelay -= elapsed;
if ( partDelay < 0.0f && nbpart < MAX_PARTICULES && sparklerad > 2.0f ) {
int lastpart = firstpart;
int nb=nbpart;
while (nb > 0 ) {
lastpart = ( lastpart + 1 )%MAX_PARTICULES;
nb--;
}
nbpart++;
px[lastpart] = 2*(sparklex-left);
py[lastpart] = 2*(sparkley-top)+2;
pvx[lastpart] = TCOD_random_get_float(NULL,-5.0f,5.0f);
pvy[lastpart] = TCOD_random_get_float(NULL,-0.5f, -15.0f);
pheat[lastpart] = 1.0f;
partDelay += 0.1f;
}
TCOD_image_blit_2x(img,NULL,left,top,0,0,-1,-1);
for (i=0; i < len ;i++) {
if ( char_heat[i] >= 0.0f && poweredby[i]!='\n') {
int colidx=(int)(64*char_heat[i]);
TCOD_color_t col;
colidx=MIN(63,colidx);
col=colmap[colidx];
if ( xstr >= len ) {
float coef=(xstr-len)/len;
if ( alpha ) {
TCOD_color_t fore=TCOD_console_get_char_background(NULL,char_x[i],char_y[i]);
int r=(int)(coef*fore.r + (1.0f-coef)*col.r);
int g=(int)(coef*fore.g + (1.0f-coef)*col.g);
int b=(int)(coef*fore.b + (1.0f-coef)*col.b);
col.r = CLAMP(0,255,r);
col.g = CLAMP(0,255,g);
col.b = CLAMP(0,255,b);
TCOD_console_set_char_foreground(NULL,char_x[i],char_y[i],col);
} else {
col=TCOD_color_lerp(col,TCOD_black,coef);
}
}
TCOD_console_set_char(NULL,char_x[i],char_y[i],poweredby[i]);
TCOD_console_set_char_foreground(NULL,char_x[i],char_y[i],col);
}
}
xstr += elapsed * 4;
for (i=0; i < (int)(xstr+0.5f); i++) {
char_heat[i]=(xstr-i)/(len/2);
}
TCOD_console_set_default_foreground(NULL,fbackup);
if ( xstr <= 2*len ) return false;
init2=false;
return true;
}
static void TCOD_console_read_asc(TCOD_console_t con,FILE *f,int width, int height, float version) {
int x,y;
TCOD_console_data_t *dat=con ? (TCOD_console_data_t *)con : TCOD_ctx.root;
TCOD_IFNOT(dat != NULL) return;
while(fgetc(f) != '#');
for(x = 0; x < width; x++) {
for(y = 0; y < height; y++) {
TCOD_color_t fore,back;
int c = fgetc(f);
fore.r = fgetc(f);
fore.g = fgetc(f);
fore.b = fgetc(f);
back.r = fgetc(f);
back.g = fgetc(f);
back.b = fgetc(f);
if ( version >= 0.3f ) {
fgetc(f);
fgetc(f);
}
TCOD_console_put_char_ex(con,x,y,c,fore,back);
}
}
fclose(f);
}
static void TCOD_console_read_apf(TCOD_console_t con,FILE *f,int width, int height, float version) {
}
static int string_ends_with(const char *str, const char *suffix) {
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
return
(str_len >= suffix_len) &&
(0 == strcmp(str + (str_len-suffix_len), suffix));
}
TCOD_console_t TCOD_console_from_file(const char *filename) {
float version;
int width,height;
TCOD_console_t con;
FILE *f;
TCOD_IFNOT( filename != NULL ) {
return NULL;
}
if (string_ends_with(filename, ".xp")) {
return TCOD_console_from_xp(filename);
}
f=fopen(filename,"rb");
TCOD_IFNOT( f!=NULL ) {
return NULL;
}
if (fscanf(f, "ASCII-Paint v%g", &version) != 1 ) {
fclose(f);
return NULL;
}
if (fscanf(f, "%i %i", &width, &height) != 2 ) {
fclose(f);
return NULL;
}
TCOD_IFNOT ( width > 0 && height > 0) {
fclose(f);
return NULL;
}
con=TCOD_console_new(width,height);
if (string_ends_with(filename, ".asc")) {
TCOD_console_read_asc(con,f,width,height,version);
} else {
TCOD_console_read_apf(con,f,width,height,version);
}
return con;
}
bool TCOD_console_load_asc(TCOD_console_t pcon, const char *filename) {
float version;
int width,height;
FILE *f;
TCOD_console_data_t *con=pcon ? (TCOD_console_data_t *)pcon : TCOD_ctx.root;
TCOD_IFNOT(con != NULL) return false;
TCOD_IFNOT( filename != NULL ) {
return false;
}
f=fopen(filename,"rb");
TCOD_IFNOT( f!=NULL ) {
return false;
}
if (fscanf(f, "ASCII-Paint v%g", &version) != 1 ) {
fclose(f);
return false;
}
if (fscanf(f, "%i %i", &width, &height) != 2 ) {
fclose(f);
return false;
}
TCOD_IFNOT ( width > 0 && height > 0) {
fclose(f);
return false;
}
if ( con->w != width || con->h != height ) {
TCOD_console_data_free(con);
con->w = width;
con->h = height;
TCOD_console_data_alloc(con);
}
TCOD_console_read_asc(con,f,width,height,version);
return true;
}
bool TCOD_console_save_asc(TCOD_console_t pcon, const char *filename) {
static float version = 0.3f;
FILE *f;
int x,y;
TCOD_console_data_t *con=pcon ? (TCOD_console_data_t *)pcon : TCOD_ctx.root;
TCOD_IFNOT(con != NULL) return false;
TCOD_IFNOT( filename != NULL ) {
return false;
}
TCOD_IFNOT(con->w > 0 && con->h > 0) return false;
f=fopen(filename,"wb");
TCOD_IFNOT( f != NULL ) return false;
fprintf(f, "ASCII-Paint v%g\n", version);
fprintf(f, "%i %i\n", con->w, con->h);
fputc('#', f);
for(x = 0; x < con->w; x++) {
for(y = 0; y < con->h; y++) {
TCOD_color_t fore,back;
int c=TCOD_console_get_char(con,x,y);
fore=TCOD_console_get_char_foreground(con,x,y);
back=TCOD_console_get_char_background(con,x,y);
fputc(c, f);
fputc(fore.r,f);
fputc(fore.g,f);
fputc(fore.b,f);
fputc(back.r,f);
fputc(back.g,f);
fputc(back.b,f);
fputc(0,f);
fputc(1,f);
}
}
fclose(f);
return true;
}
static bool hasDetectedBigEndianness = false;
static bool isBigEndian;
void detectBigEndianness(void) {
if (!hasDetectedBigEndianness){
uint32_t Value32;
uint8_t *VPtr = (uint8_t *)&Value32;
VPtr[0] = VPtr[1] = VPtr[2] = 0; VPtr[3] = 1;
if(Value32 == 1) isBigEndian = true;
else isBigEndian = false;
hasDetectedBigEndianness = true;
}
}
uint16_t bswap16(uint16_t s){
uint8_t* ps = (uint8_t*)&s;
uint16_t res;
uint8_t* pres = (uint8_t*)&res;
pres[0] = ps[1];
pres[1] = ps[0];
return res;
}
uint32_t bswap32(uint32_t s){
uint8_t *ps=(uint8_t *)(&s);
uint32_t res;
uint8_t *pres=(uint8_t *)&res;
pres[0]=ps[3];
pres[1]=ps[2];
pres[2]=ps[1];
pres[3]=ps[0];
return res;
}
uint16_t l16(uint16_t s){
if (isBigEndian) return bswap16(s); else return s;
}
uint32_t l32(uint32_t s){
if (isBigEndian) return bswap32(s); else return s;
}
void fix16(uint16_t* u){
*u = l16(*u);
}
void fix32(uint32_t* u){
*u = l32(*u);
}
uint32_t fourCC(const char* c){
return (*(uint32_t*)c);
}
bool fourCCequals(uint32_t u, const char* str){
return fourCC(str)==u;
}
void fromFourCC(uint32_t u, char*s){
const char* c = (const char*)(&u);
s[0]=c[0];
s[1]=c[1];
s[2]=c[2];
s[3]=c[3];
s[4]=0;
}
void put8(uint8_t d, FILE* fp){
fwrite(&d,1,1,fp);
}
void put16(uint16_t d, FILE* fp){
fwrite(&d,2,1,fp);
}
void put32(uint32_t d, FILE* fp){
fwrite(&d,4,1,fp);
}
void putFourCC(const char* c, FILE* fp){
put32(fourCC(c),fp);
}
void putData(void* what, int length, FILE* fp){
fwrite(what,length,1,fp);
}
bool get8(uint8_t* u, FILE* fp){
return 1==fread((void*)u, sizeof(uint8_t),1,fp);
}
bool get16(uint16_t* u, FILE* fp){
return 1==fread((void*)u, sizeof(uint16_t),1,fp);
}
bool get32(uint32_t* u, FILE* fp){
return 1==fread((void*)u, sizeof(uint32_t),1,fp);
}
bool getData(void* u, size_t sz, FILE* fp){
return 1==fread(u, sz,1,fp);
}
typedef struct {
uint32_t show_grid;
uint32_t grid_width;
uint32_t grid_height;
} SettingsDataV1;
#define FILTER_TYPE_UNCOMPRESSED 0
#define FORMAT_TYPE_CRGBRGB 0
typedef struct {
uint32_t width;
uint32_t height;
uint32_t filter;
uint32_t format;
} ImageDetailsV1;
typedef struct {
uint32_t name;
uint32_t mode;
uint32_t index;
uint32_t dataSize;
} LayerV1 ;
typedef struct {
uint32_t name;
uint32_t mode;
uint32_t fgalpha;
uint32_t bgalpha;
uint32_t visible;
uint32_t index;
uint32_t dataSize;
} LayerV2;
void fixSettings(SettingsDataV1* s){
fix32(&s->show_grid);
fix32(&s->grid_width);
fix32(&s->grid_height);
}
void fixImage(ImageDetailsV1* v){
fix32(&v->width);
fix32(&v->height);
fix32(&v->filter);
fix32(&v->format);
}
void fixLayerv1(LayerV1* l){
fix32(&l->mode);
fix32(&l->index);
fix32(&l->dataSize);
}
void fixLayerv2(LayerV2* l){
fix32(&l->mode);
fix32(&l->fgalpha);
fix32(&l->bgalpha);
fix32(&l->visible);
fix32(&l->index);
fix32(&l->dataSize);
}
bool TCOD_console_save_apf(TCOD_console_t pcon, const char *filename) {
TCOD_console_data_t *con=pcon ? (TCOD_console_data_t *)pcon : TCOD_ctx.root;
FILE* fp ;
TCOD_IFNOT(con != NULL) return false;
detectBigEndianness();
fp = fopen(filename, "wb");
if(fp == NULL) {
return false;
}
else {
int x,y;
uint32_t riffSize = 0;
uint32_t imgDetailsSize ;
SettingsDataV1 settingsData;
ImageDetailsV1 imgData;
fpos_t posRiffSize;
uint32_t settingsSz ;
uint32_t layerImageSize ;
uint32_t layerChunkSize ;
putFourCC("RIFF",fp);
fgetpos(fp,&posRiffSize);
put32(0,fp);
putFourCC("apf ",fp);
riffSize += 4;
settingsData.show_grid = 0;
settingsData.grid_width = 8;
settingsData.grid_height = 8;
settingsSz = sizeof(uint32_t) + sizeof settingsData;
putFourCC("sett",fp);
put32(l32(settingsSz),fp);
put32(l32(1),fp);
putData((void*)&settingsData,sizeof settingsData,fp);
if (settingsSz&1){
put8(0,fp);
riffSize++;
}
riffSize += 4+4+settingsSz;
imgData.width = con->w;
imgData.height = con->h;
imgData.filter = 0;
imgData.format = 0;
imgDetailsSize = sizeof(uint32_t) + sizeof imgData;
putFourCC("imgd",fp);
put32(l32(imgDetailsSize),fp);
put32(l32(1),fp);
putData((void*)&imgData,sizeof imgData,fp);
if (imgDetailsSize&1){
put8(0,fp);
riffSize++;
}
riffSize += 4+4+imgDetailsSize;
layerImageSize = imgData.width*imgData.height*7;
layerChunkSize = sizeof(uint32_t)
+ sizeof(LayerV2)
+ layerImageSize;
putFourCC("layr",fp);
put32(l32(layerChunkSize),fp);
put32(l32(2),fp);
putFourCC("LAY0",fp);
put32(l32(0),fp);
put32(l32(255),fp);
put32(l32(255),fp);
put32(l32(1),fp);
put32(l32(0),fp);
put32(l32(layerImageSize),fp);
for(x = 0; x < con->w; x++) {
for(y = 0; y < con->h; y++) {
TCOD_color_t fore,back;
int c=TCOD_console_get_char(con,x,y);
fore=TCOD_console_get_char_foreground(con,x,y);
back=TCOD_console_get_char_background(con,x,y);
put8(c, fp);
put8(fore.r,fp);
put8(fore.g,fp);
put8(fore.b,fp);
put8(back.r,fp);
put8(back.g,fp);
put8(back.b,fp);
}
}
if (layerChunkSize&1){
put8(0,fp);
riffSize++;
}
riffSize += 2*sizeof(uint32_t)+layerChunkSize;
fsetpos(fp,&posRiffSize);
put32(l32(riffSize),fp);
}
fclose(fp);
return true;
}
typedef struct {
LayerV1 headerv1;
LayerV2 headerv2;
uint8_t* data;
} LayerData;
typedef struct {
ImageDetailsV1 details;
SettingsDataV1 settings;
LayerData layer;
} Data;
bool TCOD_console_load_apf(TCOD_console_t pcon, const char *filename) {
uint32_t sett = fourCC("sett");
uint32_t imgd = fourCC("imgd");
uint32_t layr = fourCC("layr");
FILE* fp ;
Data data;
TCOD_console_data_t *con=pcon ? (TCOD_console_data_t *)pcon : TCOD_ctx.root;
TCOD_IFNOT(con != NULL) return false;
detectBigEndianness();
data.details.width = 1;
data.details.height = 1;
data.details.filter = 0;
data.details.format = 0;
data.settings.show_grid = true;
data.settings.grid_width = 10;
data.settings.grid_height = 10;
#define ERR(x) {printf("Error: %s\n. Aborting operation.",x); return false;}
#define ERR_NEWER(x) {printf("Error: It looks like this file was made with a newer version of Ascii-Paint\n. In particular the %s field. Aborting operation.",x); return false;}
fp = fopen(filename, "rb");
if(fp == NULL) {
printf("The file %s could not be loaded.\n", filename);
return false;
}
else {
uint32_t riff;
uint32_t riffSize;
int index = 0;
int x,y;
uint8_t *imgData;
bool keepGoing = true;
if (! get32(&riff,fp) || ! fourCCequals(riff,"RIFF")){
ERR("File doesn't have a RIFF header");
}
if (!get32(&riffSize,fp)) ERR("No RIFF size field!");
fix32(&riffSize);
while(keepGoing && fp){
uint32_t apf;
if (! get32(&apf,fp)) break;
if (fourCCequals(apf,"apf ") || fourCCequals(apf,"APF ")){
while(keepGoing && fp){
uint32_t seg;
if (! get32(&seg,fp)){
keepGoing = false;
break;
}
else {
if (seg==sett){
uint32_t sz;
uint32_t ver;
SettingsDataV1 settingsData;
get32(&sz,fp);
fix32(&sz);
get32(&ver,fp);
fix32(&ver);
if (ver!=1) ERR_NEWER("settings");
if (! getData((void*)&settingsData,sizeof settingsData,fp)) ERR("Can't read settings.");
data.settings = settingsData;
fixSettings(&data.settings);
}
else if (seg==imgd){
uint32_t sz;
uint32_t ver;
ImageDetailsV1 dets;
get32(&sz,fp);
fix32(&sz);
get32(&ver,fp);
fix32(&ver);
if (ver!=1) ERR_NEWER("image details");
if (! getData((void*)&dets, sizeof dets, fp)) ERR("Can't read image details.");
data.details = dets;
fixImage(&data.details);
TCOD_IFNOT ( data.details.width > 0 && data.details.height > 0) {
fclose(fp);
return false;
}
if ( con->w != data.details.width || con->h != data.details.height ) {
TCOD_console_data_free(con);
con->w = data.details.width;
con->h = data.details.height;
TCOD_console_data_alloc(con);
}
}
else if (seg==layr){
uint32_t sz;
uint32_t ver;
get32(&sz,fp);
fix32(&sz);
get32(&ver,fp);
fix32(&ver);
if (ver>2) ERR_NEWER("layer spec");
if (ver==1){
if (! getData((void*)&data.layer.headerv1, sizeof( LayerV1 ), fp)) ERR("Can't read layer header.");
fixLayerv1(&data.layer.headerv1);
data.layer.data = (uint8_t*)malloc(sizeof(uint8_t)*data.layer.headerv1.dataSize);
getData((void*) data.layer.data, data.layer.headerv1.dataSize, fp);
}
else if (ver==2){
if (! getData((void*)&data.layer.headerv2, sizeof( LayerV2 ), fp)) ERR("Can't read layer header.");
fixLayerv2(&data.layer.headerv2);
data.layer.data = (uint8_t*)malloc(sizeof(uint8_t)*data.layer.headerv2.dataSize);
getData((void*) data.layer.data, data.layer.headerv2.dataSize, fp);
}
}
else {
uint32_t sz;
get32(&sz,fp);
fix32(&sz);
fseek(fp,sz,SEEK_CUR);
}
}
}
keepGoing = false;
}
else {
uint32_t sz;
get32(&sz,fp);
fseek(fp,sz,SEEK_CUR);
}
}
imgData = data.layer.data;
for(x = 0; x < con->w; x++) {
for(y = 0; y < con->h; y++) {
TCOD_color_t fore,back;
int c = (unsigned char)(imgData[index++]);
fore.r = (uint8_t)(imgData[index++]);
fore.g = (uint8_t)(imgData[index++]);
fore.b = (uint8_t)(imgData[index++]);
back.r = (uint8_t)(imgData[index++]);
back.g = (uint8_t)(imgData[index++]);
back.b = (uint8_t)(imgData[index++]);
TCOD_console_put_char_ex(con,x,y,c,fore,back);
}
}
free (data.layer.data);
}
fclose(fp);
return true;
}
#endif