1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 2003 Sam Hocevar 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 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 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public 16 License along with this library; if not, write to the Free 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19 Sam Hocevar 20 sam (at) zoy.org 21 */ 22 23 #ifdef SAVE_RCSID 24 static char rcsid = 25 "@(#) $Id: libsdl-1.2.11-libcaca.patch,v 1.1 2006/09/18 16:06:06 mr_bones_ Exp $"; 26 #endif 27 28 /* libcaca based SDL video driver implementation. 29 */ 30 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <sys/stat.h> 36 37 38 #include "SDL.h" 39 #include "SDL_error.h" 40 #include "SDL_video.h" 41 #include "SDL_mouse.h" 42 #include "../SDL_sysvideo.h" 43 #include "../SDL_pixels_c.h" 44 #include "../../events/SDL_events_c.h" 45 46 #include "SDL_cacavideo.h" 47 #include "SDL_cacaevents_c.h" 48 49 #include <caca.h> 50 #ifdef CACA_API_VERSION_1 51 #include <caca0.h> 52 #endif 53 54 /* Initialization/Query functions */ 55 static int Caca_VideoInit(_THIS, SDL_PixelFormat *vformat); 56 static SDL_Rect **Caca_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); 57 static SDL_Surface *Caca_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); 58 static void Caca_VideoQuit(_THIS); 59 60 /* Hardware surface functions */ 61 static int Caca_AllocHWSurface(_THIS, SDL_Surface *surface); 62 static int Caca_LockHWSurface(_THIS, SDL_Surface *surface); 63 static int Caca_FlipHWSurface(_THIS, SDL_Surface *surface); 64 static void Caca_UnlockHWSurface(_THIS, SDL_Surface *surface); 65 static void Caca_FreeHWSurface(_THIS, SDL_Surface *surface); 66 67 /* Cache the VideoDevice struct */ 68 static struct SDL_VideoDevice *local_this; 69 70 /* libcaca driver bootstrap functions */ 71 72 static int Caca_Available(void) 73 { 74 return 1; /* Always available ! */ 75 } 76 77 static void Caca_DeleteDevice(SDL_VideoDevice *device) 78 { 79 free(device->hidden); 80 free(device); 81 } 82 static SDL_VideoDevice *Caca_CreateDevice(int devindex) 83 { 84 SDL_VideoDevice *device; 85 86 /* Initialize all variables that we clean on shutdown */ 87 device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); 88 if ( device ) { 89 memset(device, 0, (sizeof *device)); 90 device->hidden = (struct SDL_PrivateVideoData *) 91 malloc((sizeof *device->hidden)); 92 } 93 if ( (device == NULL) || (device->hidden == NULL) ) { 94 SDL_OutOfMemory(); 95 if ( device ) { 96 free(device); 97 } 98 return(0); 99 } 100 memset(device->hidden, 0, (sizeof *device->hidden)); 101 102 /* Set the function pointers */ 103 device->VideoInit = Caca_VideoInit; 104 device->ListModes = Caca_ListModes; 105 device->SetVideoMode = Caca_SetVideoMode; 106 device->CreateYUVOverlay = NULL; 107 device->SetColors = NULL; 108 device->UpdateRects = NULL; 109 device->VideoQuit = Caca_VideoQuit; 110 device->AllocHWSurface = Caca_AllocHWSurface; 111 device->CheckHWBlit = NULL; 112 device->FillHWRect = NULL; 113 device->SetHWColorKey = NULL; 114 device->SetHWAlpha = NULL; 115 device->LockHWSurface = Caca_LockHWSurface; 116 device->UnlockHWSurface = Caca_UnlockHWSurface; 117 device->FlipHWSurface = NULL; 118 device->FreeHWSurface = Caca_FreeHWSurface; 119 device->SetCaption = NULL; 120 device->SetIcon = NULL; 121 device->IconifyWindow = NULL; 122 device->GrabInput = NULL; 123 device->GetWMInfo = NULL; 124 device->InitOSKeymap = Caca_InitOSKeymap; 125 device->PumpEvents = Caca_PumpEvents; 126 127 device->free = Caca_DeleteDevice; 128 129 return device; 130 } 131 132 VideoBootStrap CACA_bootstrap = { 133 "caca", "Color ASCII Art Library", 134 Caca_Available, Caca_CreateDevice 135 }; 136 137 int Caca_VideoInit(_THIS, SDL_PixelFormat *vformat) 138 { 139 int i; 140 141 /* Initialize all variables that we clean on shutdown */ 142 for ( i=0; i<SDL_NUMMODES; ++i ) { 143 SDL_modelist[i] = malloc(sizeof(SDL_Rect)); 144 SDL_modelist[i]->x = SDL_modelist[i]->y = 0; 145 } 146 /* Modes sorted largest to smallest */ 147 SDL_modelist[0]->w = 1024; SDL_modelist[0]->h = 768; 148 SDL_modelist[1]->w = 800; SDL_modelist[1]->h = 600; 149 SDL_modelist[2]->w = 640; SDL_modelist[2]->h = 480; 150 SDL_modelist[3]->w = 320; SDL_modelist[3]->h = 400; 151 SDL_modelist[4]->w = 320; SDL_modelist[4]->h = 240; 152 SDL_modelist[5]->w = 320; SDL_modelist[5]->h = 200; 153 SDL_modelist[6] = NULL; 154 155 Caca_mutex = SDL_CreateMutex(); 156 157 /* Initialize the library */ 158 if ( caca_init() != 0 ) { 159 SDL_SetError("Unable to initialize libcaca"); 160 return(-1); 161 } 162 163 /* Initialize private variables */ 164 Caca_lastkey = 0; 165 Caca_bitmap = NULL; 166 Caca_buffer = NULL; 167 168 local_this = this; 169 170 /* Determine the screen depth (use default 8-bit depth) */ 171 vformat->BitsPerPixel = 8; 172 vformat->BytesPerPixel = 1; 173 174 /* We're done! */ 175 return(0); 176 } 177 178 SDL_Rect **Caca_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 179 { 180 if(format->BitsPerPixel != 8) 181 return NULL; 182 183 if ( flags & SDL_FULLSCREEN ) { 184 return SDL_modelist; 185 } else { 186 return (SDL_Rect **) -1; 187 } 188 } 189 190 /* Various screen update functions available */ 191 static void Caca_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); 192 193 SDL_Surface *Caca_SetVideoMode(_THIS, SDL_Surface *current, 194 int width, int height, int bpp, Uint32 flags) 195 { 196 if ( Caca_buffer ) { 197 free( Caca_buffer ); 198 Caca_buffer = NULL; 199 } 200 201 if ( Caca_bitmap ) { 202 caca_free_bitmap( Caca_bitmap ); 203 Caca_bitmap = NULL; 204 } 205 206 Caca_buffer = malloc(2 * ((width + 15) & ~15) * height); 207 if ( ! Caca_buffer ) { 208 SDL_SetError("Couldn't allocate buffer for requested mode"); 209 return(NULL); 210 } 211 212 memset(Caca_buffer, 0, 2 * ((width + 15) & ~15) * height); 213 214 /* Allocate the new pixel format for the screen */ 215 if ( ! SDL_ReallocFormat(current, 16, 0xf800, 0x07e0, 0x001f, 0) ) { 216 return(NULL); 217 } 218 219 /* Set up the new mode framebuffer */ 220 current->flags = SDL_FULLSCREEN; 221 Caca_w = current->w = width; 222 Caca_h = current->h = height; 223 current->pitch = 2 * ((width + 15) & ~15); 224 current->pixels = Caca_buffer; 225 226 /* Create the libcaca bitmap */ 227 Caca_bitmap = caca_create_bitmap( 16, width, height, current->pitch, 0xf800, 0x07e0, 0x001f, 0x0000 ); 228 if ( ! Caca_bitmap ) { 229 SDL_SetError("Couldn't allocate libcaca bitmap"); 230 return(NULL); 231 } 232 233 /* Set the blit function */ 234 this->UpdateRects = Caca_DirectUpdate; 235 236 /* We're done */ 237 return(current); 238 } 239 240 /* We don't actually allow hardware surfaces other than the main one */ 241 static int Caca_AllocHWSurface(_THIS, SDL_Surface *surface) 242 { 243 return(-1); 244 } 245 static void Caca_FreeHWSurface(_THIS, SDL_Surface *surface) 246 { 247 return; 248 } 249 250 /* We need to wait for vertical retrace on page flipped displays */ 251 static int Caca_LockHWSurface(_THIS, SDL_Surface *surface) 252 { 253 /* TODO ? */ 254 return(0); 255 } 256 static void Caca_UnlockHWSurface(_THIS, SDL_Surface *surface) 257 { 258 return; 259 } 260 261 /* FIXME: How is this done with libcaca? */ 262 static int Caca_FlipHWSurface(_THIS, SDL_Surface *surface) 263 { 264 SDL_mutexP(Caca_mutex); 265 caca_refresh(); 266 SDL_mutexV(Caca_mutex); 267 return(0); 268 } 269 270 static void Caca_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) 271 { 272 SDL_mutexP(Caca_mutex); 273 caca_draw_bitmap( 0, 0, caca_get_width() - 1, caca_get_height() - 1, 274 Caca_bitmap, Caca_buffer ); 275 caca_refresh(); 276 SDL_mutexV(Caca_mutex); 277 return; 278 } 279 280 /* Note: If we are terminated, this could be called in the middle of 281 another SDL video routine -- notably UpdateRects. 282 */ 283 void Caca_VideoQuit(_THIS) 284 { 285 int i; 286 287 /* Free video mode lists */ 288 for ( i=0; i<SDL_NUMMODES; ++i ) { 289 if ( SDL_modelist[i] != NULL ) { 290 free(SDL_modelist[i]); 291 SDL_modelist[i] = NULL; 292 } 293 } 294 295 if ( Caca_bitmap ) { 296 caca_free_bitmap( Caca_bitmap ); 297 Caca_bitmap = NULL; 298 } 299 300 caca_end(); 301 302 SDL_DestroyMutex(Caca_mutex); 303 } 304 305