14 #include "fonts/testfont.h"
17 #define SDL_mutex_lock(X) SDL_mutexP(X)
18 #define SDL_mutex_unlock(X) SDL_mutexV(X)
20 #pragma RcB2 DEP "sdlconsole_chartab.c"
22 void console_resize(Console
*c
, int w
, int h
);
24 static SDL_mutex
*screens_lock
;
26 void console_init(struct Console
*self
) {
27 memset(self
, 0, sizeof(struct Console
));
28 self
->backendtype
= cb_sdl
;
30 void console_settitle(Console
*self
, const char *title
) {
31 #if SDL_MAJOR_VERSION == 2
32 struct SDLConsole
*c
= &self
->backend
.sdl
;
33 SDL_SetWindowTitle(c
->window
, title
);
36 SDL_WM_SetCaption(title
, NULL
);
40 #if SDL_MAJOR_VERSION == 1
41 #define update_rect(C, X, Y, W, H) SDL_UpdateRect((C)->surface, X, Y, W, H)
43 static void update_rect(struct SDLConsole
*c
, int x
, int y
, int w
, int h
) {
44 SDL_Surface
*s
= c
->surface
;
45 const SDL_Rect
* area
= w
? &(SDL_Rect
){.x
= x
, .y
= y
, .w
= w
, .h
= h
} : 0;
46 SDL_UpdateTexture(c
->texture
, area
, s
->pixels
, s
->pitch
);
47 SDL_RenderClear(c
->renderer
);
48 SDL_RenderCopy(c
->renderer
, c
->texture
, NULL
, NULL
);
49 SDL_RenderPresent(c
->renderer
);
53 void console_init_graphics(Console
* self
, point resolution
, font
* fnt
) {
54 struct SDLConsole
*c
= &self
->backend
.sdl
;
63 if(!fnt
) fnt
= &testfont
;
65 if (SDL_Init(SDL_INIT_VIDEO
) < 0) {
66 printf("Could not initialize SDL: %s\n", SDL_GetError());
69 screens_lock
= SDL_CreateMutex();
72 #if SDL_MAJOR_VERSION == 2
73 c
->window
= SDL_CreateWindow("sdl-console",
74 SDL_WINDOWPOS_UNDEFINED
,
75 SDL_WINDOWPOS_UNDEFINED
,
76 resolution
.x
, resolution
.y
,
77 0 | SDL_WINDOW_RESIZABLE
/* | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL*/);
78 c
->renderer
= SDL_CreateRenderer(c
->window
, -1, 0);
79 SDL_EnableScreenSaver();
80 SDL_SetHint(SDL_HINT_TIMER_RESOLUTION
, "5");
82 console_resize(self
, resolution
.x
, resolution
.y
);
83 //c->fnt = bitfont_to_font(&int10_font_16);
84 #if SDL_MAJOR_VERSION == 1
85 console_settitle(self
, "sdl-console");
86 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY
, SDL_DEFAULT_REPEAT_INTERVAL
);
90 void console_cleanup(Console
* self
) {
91 struct SDLConsole
*c
= &self
->backend
.sdl
;
92 if(c
->fullscreen
) console_toggle_fullscreen(self
);
93 SDL_DestroyMutex(screens_lock
);
97 int console_getcolorcount(Console
*self
) { (void) self
; return 256; }
99 void console_initoutput(Console
* self
) {(void) self
;}
101 void console_clear(Console
* self
) {
103 fs
.bottomright
.x
= self
->dim
.x
-1;
104 fs
.bottomright
.y
= self
->dim
.y
-1;
105 console_fill(self
, &fs
, ' ');
107 #undef _POSIX_C_SOURCE
108 #define _POSIX_C_SOURCE 200809L
112 static int msleep(long millisecs
) {
113 struct timespec req
, rem
;
114 req
.tv_sec
= millisecs
/ 1000;
115 req
.tv_nsec
= (millisecs
% 1000) * 1000 * 1000;
117 while((ret
= nanosleep(&req
, &rem
)) == -1 && errno
== EINTR
) req
= rem
;
121 void console_sleep(struct Console
* self
, int ms
) {
126 #define INCLUDED_FROM_SDLCONSOLE
127 #include "sdlconsole_keyboard.c"
129 static void handle_event_action(Console
*c
, SDL_Event
*event
, int action
) {
132 #if SDL_MAJOR_VERSION == 1
133 console_resize(c
, event
->resize
.w
, event
->resize
.h
);
135 console_resize(c
, event
->window
.data1
, event
->window
.data2
);
141 case ea_toggle_fullscreen
:
142 console_toggle_fullscreen(c
);
147 int console_getkey_nb(Console
* c
) {
149 /* Loop through waiting messages and process them */
150 while (SDL_PollEvent(&event
)) {
152 k
= sdlconsole_translate_event(c
, &event
, &action
);
153 handle_event_action(c
, &event
, action
);
159 int console_getkey(Console
* c
) {
161 /* Loop through waiting messages and process them */
164 if (SDL_WaitEvent(&event
)) {
165 ret
= sdlconsole_translate_event(c
, &event
, &action
);
166 handle_event_action(c
, &event
, action
);
167 if(ret
!= CK_UNDEF
) return ret
;
168 } else { // error happened, prevent 100% cpu loop
169 console_sleep(c
, 10);
177 /* prints a char and NOT advances cursor */
178 void console_addchar(struct Console
* self
, int c
, unsigned int attributes
) {
180 int save
= self
->automove
;
182 console_putchar(self
, c
, 0);
183 self
->automove
= save
;
185 /* prints a char and advances cursor */
186 void console_printchar(struct Console
* self
, int c
, unsigned int attributes
) {
188 int save
= self
->automove
;
190 console_putchar(self
, c
, 0);
191 self
->automove
= save
;
194 void console_goto(Console
* c
, int x
, int y
) {
200 void console_lock(void) {
201 while(SDL_mutex_lock(screens_lock
) == -1) {
202 printf("warning: couldn't aquire screens_lock\n");
207 void console_unlock(void) {
208 SDL_mutex_unlock(screens_lock
);
211 static void alloc_cache(SDLConsole
*c
) {
212 if(c
->cache
) free(c
->cache
);
213 c
->cache
=calloc(c
->res
.x
*c
->res
.y
, sizeof(sdl_rgb_tuple
));
216 void console_resize(Console
*self
, int w
, int h
) {
217 SDLConsole
*c
= &self
->backend
.sdl
;
221 self
->dim
.x
= w
/ c
->fnt
->dim
.x
;
222 self
->dim
.y
= h
/ c
->fnt
->dim
.y
;
224 SDL_FreeSurface(c
->surface
);
225 #if SDL_MAJOR_VERSION == 2
226 c
->surface
= SDL_CreateRGBSurface(0, w
, h
, 32,
232 if(c
->texture
) SDL_DestroyTexture(c
->texture
);
233 c
->texture
= SDL_CreateTexture(c
->renderer
,
234 SDL_PIXELFORMAT_ARGB8888
,
235 SDL_TEXTUREACCESS_STREAMING
,
238 c
->surface
= SDL_SetVideoMode(w
, h
, 32, SDL_RESIZABLE
| SDL_HWPALETTE
);
241 printf("Couldn't set screen mode to %d x %d : %s\n", w
, h
, SDL_GetError());
248 void console_toggle_fullscreen(Console
* self
) {
249 SDLConsole
*c
= &self
->backend
.sdl
;
251 #if SDL_MAJOR_VERSION == 2
252 SDL_SetWindowFullscreen(c
->window
, c
->fullscreen
? 0 : SDL_WINDOW_FULLSCREEN
);
253 #elif SDL_MAJOR_VERSION == 1
254 SDL_WM_ToggleFullScreen(c
->surface
);
256 c
->fullscreen
= ~ c
->fullscreen
;
260 void console_getbounds(Console
* c
, int* x
, int* y
) {
265 static inline sdl_rgb_t
rgb_to_srgb(rgb_t col
) {
267 ret
.colors
.a
= col
.a
;
268 ret
.colors
.r
= col
.r
;
269 ret
.colors
.g
= col
.g
;
270 ret
.colors
.b
= col
.b
;
274 static inline rgb_t
srgb_to_rgb(sdl_rgb_t col
) {
276 ret
.a
= col
.colors
.a
;
277 ret
.r
= col
.colors
.r
;
278 ret
.g
= col
.colors
.g
;
279 ret
.b
= col
.colors
.b
;
283 rgb_tuple
console_getcolors(Console
* self
) {
284 struct SDLConsole
*c
= &self
->backend
.sdl
;
286 ret
.fgcolor
= srgb_to_rgb(c
->color
.fgcolor
);
287 ret
.bgcolor
= srgb_to_rgb(c
->color
.bgcolor
);
291 int console_setcolor(struct Console
* self
, int is_fg
, rgb_t color
) {
292 struct SDLConsole
*c
= &self
->backend
.sdl
;
293 sdl_rgb_t
* dest
= is_fg
? &c
->color
.fgcolor
: &c
->color
.bgcolor
;
294 *dest
= rgb_to_srgb(color
);
298 void console_refresh(Console
* self
) {
299 struct SDLConsole
*c
= &self
->backend
.sdl
;
301 update_rect(c
, 0, 0, 0, 0);
305 void console_blink_cursor(Console
* self
) {
306 struct SDLConsole
*c
= &self
->backend
.sdl
;
307 sdl_rgb_t
*ptr
= (sdl_rgb_t
*) ((SDL_Surface
*) c
->surface
)->pixels
;
308 int x
, y
, rx
, ry
, lineoffset
;
310 if(c
->cursorblink
|| self
->isblinking
) {
311 for (y
= 0, ry
= self
->cursor
.y
* c
->fnt
->dim
.y
; y
< c
->fnt
->dim
.y
; y
++, ry
+= 1) {
312 for (x
= 0, rx
= self
->cursor
.x
* c
->fnt
->dim
.x
; x
< c
->fnt
->dim
.x
; x
++, rx
++) {
313 lineoffset
= ry
* (((SDL_Surface
*) c
->surface
)->pitch
/ 4);
314 ptr
[lineoffset
+ rx
].val
= ~ptr
[lineoffset
+ rx
].val
;
317 update_rect(c
, self
->cursor
.x
* c
->fnt
->dim
.x
,self
->cursor
.y
* c
->fnt
->dim
.y
, c
->fnt
->dim
.x
, c
->fnt
->dim
.y
);
318 self
->isblinking
= ~self
->isblinking
;
325 #define BA_TARGET_BYTE(X, Y) ((X) + ((Y) / CHAR_BIT))
326 #define BA_BIT_DISTANCE(X, Y) ((Y) % CHAR_BIT)
327 #define BA_GET(X, Y) (!!( *BA_TARGET_BYTE(X, Y) & (1 << BA_BIT_DISTANCE(X, Y)) ))
328 static char* bitfont_get_char(font
* f
, unsigned int ch
) {
329 static unsigned int lastchr
= (unsigned) -1;
330 static unsigned char char_data
[16*16];
332 unsigned char* p
= char_data
;
333 size_t i
, start
= f
->pointsperchar
* ch
;
334 assert(f
->pointsperchar
<= sizeof(char_data
));
335 for(i
= 0; i
< f
->pointsperchar
; i
++)
336 *(p
++) = BA_GET(f
->characters
, start
+ i
);
339 return (char*) char_data
;
342 void console_putchar(Console
* self
, int ch
, int doupdate
) {
343 struct SDLConsole
*c
= &self
->backend
.sdl
;
344 console_unblink(self
);
346 if(self
->cursor
.y
>= self
->dim
.y
|| self
->cursor
.x
>= self
->dim
.x
)
348 sdl_rgb_tuple cache_test
= c
->color
;
349 cache_test
.bgcolor
.colors
.a
= (unsigned char) ch
;
350 if(!memcmp(&c
->cache
[self
->cursor
.y
* self
->dim
.x
+ self
->cursor
.x
], &cache_test
, 8)) goto skip
;
351 else c
->cache
[self
->cursor
.y
* self
->dim
.x
+ self
->cursor
.x
] = cache_test
;
352 unsigned char* font
= (void*)bitfont_get_char(c
->fnt
, ch
& 0xff);
353 int pitch_div_4
= (((SDL_Surface
*) c
->surface
)->pitch
/ 4);
354 sdl_rgb_t
*ptr
= (sdl_rgb_t
*) ((SDL_Surface
*) c
->surface
)->pixels
;
355 ptr
+= self
->cursor
.y
* c
->fnt
->dim
.y
* pitch_div_4
;
356 ptr
+= self
->cursor
.x
* c
->fnt
->dim
.x
;
357 size_t advance
= (pitch_div_4
- c
->fnt
->dim
.x
);
358 sdl_rgb_t color
[2] = {[0] = c
->color
.bgcolor
, [1] = c
->color
.fgcolor
};
360 for (y
= 0; y
< c
->fnt
->dim
.y
; y
++, ptr
+= advance
) {
361 for (x
= 0; x
< c
->fnt
->dim
.x
; x
++, font
++, ptr
++) {
365 if(doupdate
) update_rect(c
, self
->cursor
.x
* c
->fnt
->dim
.x
,self
->cursor
.y
* c
->fnt
->dim
.y
, c
->fnt
->dim
.x
, c
->fnt
->dim
.y
);
368 if(self
->automove
) console_advance_cursor(self
, 1);