1/* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken@libsdl.org 21*/ 22#include "SDL_config.h" 23 24/* AAlib based SDL video driver implementation. 25*/ 26 27#include <unistd.h> 28#include <sys/stat.h> 29 30 31#include "SDL_video.h" 32#include "SDL_mouse.h" 33#include "../SDL_sysvideo.h" 34#include "../SDL_pixels_c.h" 35#include "../../events/SDL_events_c.h" 36 37#include "SDL_aavideo.h" 38#include "SDL_aaevents_c.h" 39#include "SDL_aamouse_c.h" 40 41#include <aalib.h> 42 43/* Initialization/Query functions */ 44static int AA_VideoInit(_THIS, SDL_PixelFormat *vformat); 45static SDL_Rect **AA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); 46static SDL_Surface *AA_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); 47static int AA_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); 48static void AA_VideoQuit(_THIS); 49 50/* Hardware surface functions */ 51static int AA_AllocHWSurface(_THIS, SDL_Surface *surface); 52static int AA_LockHWSurface(_THIS, SDL_Surface *surface); 53static int AA_FlipHWSurface(_THIS, SDL_Surface *surface); 54static void AA_UnlockHWSurface(_THIS, SDL_Surface *surface); 55static void AA_FreeHWSurface(_THIS, SDL_Surface *surface); 56 57/* Cache the VideoDevice struct */ 58static struct SDL_VideoDevice *local_this; 59 60/* AAlib driver bootstrap functions */ 61 62static int AA_Available(void) 63{ 64 return 1; /* Always available ! */ 65} 66 67static void AA_DeleteDevice(SDL_VideoDevice *device) 68{ 69 SDL_free(device->hidden); 70 SDL_free(device); 71} 72 73static SDL_VideoDevice *AA_CreateDevice(int devindex) 74{ 75 SDL_VideoDevice *device; 76 77 /* Initialize all variables that we clean on shutdown */ 78 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); 79 if ( device ) { 80 SDL_memset(device, 0, (sizeof *device)); 81 device->hidden = (struct SDL_PrivateVideoData *) 82 SDL_malloc((sizeof *device->hidden)); 83 } 84 if ( (device == NULL) || (device->hidden == NULL) ) { 85 SDL_OutOfMemory(); 86 if ( device ) { 87 SDL_free(device); 88 } 89 return(0); 90 } 91 SDL_memset(device->hidden, 0, (sizeof *device->hidden)); 92 93 /* Set the function pointers */ 94 device->VideoInit = AA_VideoInit; 95 device->ListModes = AA_ListModes; 96 device->SetVideoMode = AA_SetVideoMode; 97 device->CreateYUVOverlay = NULL; 98 device->SetColors = AA_SetColors; 99 device->UpdateRects = NULL; 100 device->VideoQuit = AA_VideoQuit; 101 device->AllocHWSurface = AA_AllocHWSurface; 102 device->CheckHWBlit = NULL; 103 device->FillHWRect = NULL; 104 device->SetHWColorKey = NULL; 105 device->SetHWAlpha = NULL; 106 device->LockHWSurface = AA_LockHWSurface; 107 device->UnlockHWSurface = AA_UnlockHWSurface; 108 device->FlipHWSurface = NULL; 109 device->FreeHWSurface = AA_FreeHWSurface; 110 device->SetCaption = NULL; 111 device->SetIcon = NULL; 112 device->IconifyWindow = NULL; 113 device->GrabInput = NULL; 114 device->GetWMInfo = NULL; 115 device->InitOSKeymap = AA_InitOSKeymap; 116 device->PumpEvents = AA_PumpEvents; 117 118 device->free = AA_DeleteDevice; 119 120 return device; 121} 122 123VideoBootStrap AALIB_bootstrap = { 124 "aalib", "ASCII Art Library", 125 AA_Available, AA_CreateDevice 126}; 127 128static void AA_ResizeHandler(aa_context *); 129 130int AA_VideoInit(_THIS, SDL_PixelFormat *vformat) 131{ 132 int keyboard; 133 int i; 134 135 /* Initialize all variables that we clean on shutdown */ 136 for ( i=0; i<SDL_NUMMODES; ++i ) { 137 SDL_modelist[i] = SDL_malloc(sizeof(SDL_Rect)); 138 SDL_modelist[i]->x = SDL_modelist[i]->y = 0; 139 } 140 /* Modes sorted largest to smallest */ 141 SDL_modelist[0]->w = 1024; SDL_modelist[0]->h = 768; 142 SDL_modelist[1]->w = 800; SDL_modelist[1]->h = 600; 143 SDL_modelist[2]->w = 640; SDL_modelist[2]->h = 480; 144 SDL_modelist[3]->w = 320; SDL_modelist[3]->h = 400; 145 SDL_modelist[4]->w = 320; SDL_modelist[4]->h = 240; 146 SDL_modelist[5]->w = 320; SDL_modelist[5]->h = 200; 147 SDL_modelist[6] = NULL; 148 149 /* Initialize the library */ 150 151 AA_mutex = SDL_CreateMutex(); 152 153 aa_parseoptions (NULL, NULL, NULL, NULL); 154 155 AA_context = aa_autoinit(&aa_defparams); 156 if ( ! AA_context ) { 157 SDL_SetError("Unable to initialize AAlib"); 158 return(-1); 159 } 160 161 /* Enable mouse and keyboard support */ 162 163 if ( ! aa_autoinitkbd (AA_context, AA_SENDRELEASE) ) { 164 SDL_SetError("Unable to initialize AAlib keyboard"); 165 return(-1); 166 } 167 if ( ! aa_autoinitmouse (AA_context, AA_SENDRELEASE) ) { 168 fprintf(stderr,"Warning: Unable to initialize AAlib mouse"); 169 } 170 AA_rparams = aa_getrenderparams(); 171 172 local_this = this; 173 174 aa_resizehandler(AA_context, AA_ResizeHandler); 175 176 fprintf(stderr,"Using AAlib driver: %s (%s)\n", AA_context->driver->name, AA_context->driver->shortname); 177 178 AA_in_x11 = (SDL_strcmp(AA_context->driver->shortname,"X11") == 0); 179 /* Determine the screen depth (use default 8-bit depth) */ 180 vformat->BitsPerPixel = 8; 181 vformat->BytesPerPixel = 1; 182 183 /* We're done! */ 184 return(0); 185} 186 187SDL_Rect **AA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 188{ 189 if(format->BitsPerPixel != 8) 190 return NULL; 191 192 if ( flags & SDL_FULLSCREEN ) { 193 return SDL_modelist; 194 } else { 195 return (SDL_Rect **) -1; 196 } 197} 198 199/* From aavga.c 200 AAlib does not give us the choice of the actual resolution, thus we have to simulate additional 201 resolution by scaling down manually each frame 202*/ 203static void fastscale (register char *b1, register char *b2, int x1, int x2, int y1, int y2) 204{ 205 register int ex, spx = 0, ddx, ddx1; 206 int ddy1, ddy, spy = 0, ey; 207 int x; 208 char *bb1 = b1; 209 if (!x1 || !x2 || !y1 || !y2) 210 return; 211 ddx = x1 + x1; 212 ddx1 = x2 + x2; 213 if (ddx1 < ddx) 214 spx = ddx / ddx1, ddx %= ddx1; 215 ddy = y1 + y1; 216 ddy1 = y2 + y2; 217 if (ddy1 < ddy) 218 spy = (ddy / ddy1) * x1, ddy %= ddy1; 219 ey = -ddy1; 220 for (; y2; y2--) { 221 ex = -ddx1; 222 for (x = x2; x; x--) { 223 *b2 = *b1; 224 b2++; 225 b1 += spx; 226 ex += ddx; 227 if (ex > 0) { 228 b1++; 229 ex -= ddx1; 230 } 231 } 232 bb1 += spy; 233 ey += ddy; 234 if (ey > 0) { 235 bb1 += x1; 236 ey -= ddy1; 237 } 238 b1 = bb1; 239 } 240} 241 242/* Various screen update functions available */ 243static void AA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); 244 245SDL_Surface *AA_SetVideoMode(_THIS, SDL_Surface *current, 246 int width, int height, int bpp, Uint32 flags) 247{ 248 int mode; 249 250 if ( AA_buffer ) { 251 SDL_free( AA_buffer ); 252 } 253 254 AA_buffer = SDL_malloc(width * height); 255 if ( ! AA_buffer ) { 256 SDL_SetError("Couldn't allocate buffer for requested mode"); 257 return(NULL); 258 } 259 260/* printf("Setting mode %dx%d\n", width, height); */ 261 262 SDL_memset(aa_image(AA_context), 0, aa_imgwidth(AA_context) * aa_imgheight(AA_context)); 263 SDL_memset(AA_buffer, 0, width * height); 264 265 /* Allocate the new pixel format for the screen */ 266 if ( ! SDL_ReallocFormat(current, 8, 0, 0, 0, 0) ) { 267 return(NULL); 268 } 269 270 /* Set up the new mode framebuffer */ 271 current->flags = SDL_FULLSCREEN; 272 AA_w = current->w = width; 273 AA_h = current->h = height; 274 current->pitch = current->w; 275 current->pixels = AA_buffer; 276 277 AA_x_ratio = ((double)aa_imgwidth(AA_context)) / ((double)width); 278 AA_y_ratio = ((double)aa_imgheight(AA_context)) / ((double)height); 279 280 /* Set the blit function */ 281 this->UpdateRects = AA_DirectUpdate; 282 283 /* We're done */ 284 return(current); 285} 286 287static void AA_ResizeHandler(aa_context *context) 288{ 289 aa_resize(context); 290 local_this->hidden->x_ratio = ((double)aa_imgwidth(context)) / ((double)local_this->screen->w); 291 local_this->hidden->y_ratio = ((double)aa_imgheight(context)) / ((double)local_this->screen->h); 292 293 fastscale (local_this->hidden->buffer, aa_image(context), local_this->hidden->w, aa_imgwidth (context), local_this->hidden->h, aa_imgheight (context)); 294 aa_renderpalette(context, local_this->hidden->palette, local_this->hidden->rparams, 0, 0, aa_scrwidth(context), aa_scrheight(context)); 295 aa_flush(context); 296} 297 298/* We don't actually allow hardware surfaces other than the main one */ 299static int AA_AllocHWSurface(_THIS, SDL_Surface *surface) 300{ 301 return(-1); 302} 303static void AA_FreeHWSurface(_THIS, SDL_Surface *surface) 304{ 305 return; 306} 307 308/* We need to wait for vertical retrace on page flipped displays */ 309static int AA_LockHWSurface(_THIS, SDL_Surface *surface) 310{ 311 /* TODO ? */ 312 return(0); 313} 314static void AA_UnlockHWSurface(_THIS, SDL_Surface *surface) 315{ 316 return; 317} 318 319/* FIXME: How is this done with AAlib? */ 320static int AA_FlipHWSurface(_THIS, SDL_Surface *surface) 321{ 322 SDL_mutexP(AA_mutex); 323 aa_flush(AA_context); 324 SDL_mutexV(AA_mutex); 325 return(0); 326} 327 328static void AA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) 329{ 330 int i; 331 SDL_Rect *rect; 332 333 fastscale (AA_buffer, aa_image(AA_context), AA_w, aa_imgwidth (AA_context), AA_h, aa_imgheight (AA_context)); 334#if 1 335 aa_renderpalette(AA_context, AA_palette, AA_rparams, 0, 0, aa_scrwidth(AA_context), aa_scrheight(AA_context)); 336#else 337 /* Render only the rectangles in the list */ 338 printf("Update rects : "); 339 for ( i=0; i < numrects; ++i ) { 340 rect = &rects[i]; 341 printf("(%d,%d-%d,%d)", rect->x, rect->y, rect->w, rect->h); 342 aa_renderpalette(AA_context, AA_palette, AA_rparams, rect->x * AA_x_ratio, rect->y * AA_y_ratio, rect->w * AA_x_ratio, rect->h * AA_y_ratio); 343 } 344 printf("\n"); 345#endif 346 SDL_mutexP(AA_mutex); 347 aa_flush(AA_context); 348 SDL_mutexV(AA_mutex); 349 return; 350} 351 352int AA_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) 353{ 354 int i; 355 356 for ( i=0; i < ncolors; i++ ) { 357 aa_setpalette(AA_palette, firstcolor + i, 358 colors[i].r>>2, 359 colors[i].g>>2, 360 colors[i].b>>2); 361 } 362 return(1); 363} 364 365/* Note: If we are terminated, this could be called in the middle of 366 another SDL video routine -- notably UpdateRects. 367*/ 368void AA_VideoQuit(_THIS) 369{ 370 int i; 371 372 aa_uninitkbd(AA_context); 373 aa_uninitmouse(AA_context); 374 375 /* Free video mode lists */ 376 for ( i=0; i<SDL_NUMMODES; ++i ) { 377 if ( SDL_modelist[i] != NULL ) { 378 SDL_free(SDL_modelist[i]); 379 SDL_modelist[i] = NULL; 380 } 381 } 382 383 aa_close(AA_context); 384 385 SDL_DestroyMutex(AA_mutex); 386 387 this->screen->pixels = NULL; 388} 389