gi_sdl.c (8657B)
1 /* See LICENSE file for copyright and license details. */ 2 #define _BSD_SOURCE // strdup 3 #include <SDL/SDL.h> 4 #include <SDL/SDL_image.h> 5 #include <SDL/SDL_ttf.h> 6 #include "swk.h" 7 #define SWK 8 #include "config.h" 9 10 #define FONTNAME "Inconsolata.otf" 11 #define FONTFACTOR 2.1 /* XXX */ 12 #define BPP 32 13 #define SDLFLAGS SDL_DOUBLEBUF|SDL_RESIZABLE 14 15 static int first = 1; 16 static int fs = FONTSIZE; 17 static Uint32 pal[ColorLast]; 18 static SDL_Color fontcolor = { TFCOLOR }; 19 static SDL_Color bgcolor = { BGCOLOR }; 20 static SDL_Color tfcolor = { TFCOLOR }; 21 static SDL_Color cccolor = { CCCOLOR }; 22 static SDL_Surface *screen = NULL; 23 static TTF_Font *font = NULL; 24 /* FIXME: put ugly statics into void *aux of SwkWindow ? */ 25 static int has_event = 0; 26 static SDL_Event lastev = { .type=-1 }; 27 28 static inline Uint8 * 29 getscrpoint(SDL_Surface *scr, int x, int y) { 30 Uint8 *p = (Uint8 *)scr->pixels + (y*scr->pitch+x*(BPP/8)); 31 Uint8 *pend = (Uint8 *)scr->pixels + (scr->h*scr->w*(BPP/8)); 32 if((p<((Uint8 *)scr->pixels)) || (p>=pend)) 33 return NULL; 34 return p; 35 } 36 37 static void 38 putpixel(SDL_Surface *scr, int x, int y, Uint32 pixel) { 39 Uint8 *p = getscrpoint(scr, x, y); 40 if(!p) return; 41 #if BPP == 8 42 *p = pixel; 43 #elif BPP == 16 44 *(Uint16 *)p = pixel; 45 #elif BPP == 24 46 # if SDL_BYTEORDER == SDL_BIG_ENDIAN 47 p[0] = (pixel >> 16) & 0xff; 48 p[1] = (pixel >> 8) & 0xff; 49 p[2] = pixel & 0xff; 50 # else 51 p[0] = pixel & 0xff; 52 p[1] = (pixel >> 8) & 0xff; 53 p[2] = (pixel >> 16) & 0xff; 54 # endif 55 #elif BPP == 32 56 *(Uint32 *)p = pixel; 57 #endif 58 } 59 60 int 61 swk_gi_fontsize(int sz) { 62 fs += sz*2; 63 font = TTF_OpenFont(FONTNAME, fs); 64 if(font == NULL) { 65 fprintf(stderr, "Cannot open font '%s'\n", FONTNAME); 66 return 0; 67 } else 68 if(FONTBOLD) 69 TTF_SetFontStyle(font, TTF_STYLE_BOLD); 70 return 1; 71 } 72 73 int 74 swk_gi_init(SwkWindow *w) { 75 if(first) { 76 if(SDL_Init(SDL_INIT_VIDEO)) { 77 fprintf(stderr, "Cannot initialize SDL\n"); 78 return 0; 79 } 80 if(TTF_Init()==-1) { 81 fprintf(stderr, "Cannot initialize TTF: %s\n", TTF_GetError()); 82 return 0; 83 } 84 first = 0; 85 } 86 SDL_SetVideoMode(w->r.w, w->r.h, BPP, SDLFLAGS); 87 // double init is necesary to get window size 88 SDL_SetVideoMode(w->r.w, w->r.h, BPP, SDLFLAGS); 89 SDL_WM_SetCaption(w->title, NULL); 90 screen = SDL_GetVideoSurface(); 91 SDL_EnableUNICODE(1); 92 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); 93 pal[ColorFG] = SDL_MapRGB(screen->format, FGCOLOR); 94 pal[ColorBG] = SDL_MapRGB(screen->format, BGCOLOR); 95 pal[ColorHI] = SDL_MapRGB(screen->format, HICOLOR); 96 pal[ColorTF] = SDL_MapRGB(screen->format, TFCOLOR); 97 pal[ColorCC] = SDL_MapRGB(screen->format, CCCOLOR); 98 return swk_gi_fontsize(0); 99 } 100 101 int 102 swk_gi_update(SwkWindow *w) { 103 screen = SDL_GetVideoSurface(); 104 if(screen == NULL) 105 return 0; 106 w->r.w = (screen->w / fs)-1; 107 w->r.h = (screen->h / fs)-1; 108 return 1; 109 } 110 111 void 112 swk_gi_exit() { 113 SDL_Quit(); 114 } 115 116 SwkEvent * 117 swk_gi_event(SwkWindow *w, int dowait) { 118 static int mousedowny, mousedownx, mousedown = 0; 119 static int mousemoved = 0; 120 SDL_Event event; 121 SwkEvent *ret = &w->_e; 122 123 if(has_event) event = lastev; 124 else has_event = SDL_WaitEvent(&event); 125 126 if(has_event); 127 switch(event.type) { 128 default: ret = NULL; break; 129 case SDL_VIDEORESIZE: 130 //fprintf(stderr, "resize %d %d\n", event.resize.w, event.resize.h); 131 SDL_SetVideoMode(event.resize.w, event.resize.h, BPP, SDLFLAGS); 132 case SDL_ACTIVEEVENT: 133 case SDL_VIDEOEXPOSE: 134 ret->type = EExpose; 135 ret->data.expose.x = ret->data.expose.y = \ 136 ret->data.expose.w = ret->data.expose.h = 0; 137 break; 138 case SDL_MOUSEMOTION: 139 // TODO: move this stuff into swk.c.. shoudlnt be backend dependent 140 //fprintf(stderr, "event: motion (%d,%d)\n", event.motion.x,event.motion.y); 141 if(mousedown) { 142 // touchscreen spaguetti trick 143 if(mousedowny==-1) mousedowny = event.motion.y; else mousemoved = 1; 144 if(mousedownx==-1) mousedownx = event.motion.x; else mousemoved = 1; 145 if(event.motion.y>mousedowny+fs) { 146 mousedowny = event.motion.y; 147 swk_scroll_up(w); 148 } else 149 if(event.motion.y<mousedowny-fs) { 150 mousedowny = event.motion.y; 151 swk_scroll_down(w); 152 } 153 if(event.motion.x>mousedownx+fs) { 154 mousedownx = event.motion.x; 155 swk_column_move_right(); 156 swk_column_move_right(); 157 } else 158 if(event.motion.x<mousedownx-fs) { 159 mousedownx = event.motion.x; 160 swk_column_move_left(); 161 swk_column_move_left(); 162 } 163 ret->type = EExpose; 164 ret->data.expose.x = ret->data.expose.y = \ 165 ret->data.expose.w = ret->data.expose.h = 0; 166 } else { 167 ret->type = EMotion; 168 ret->data.motion.x = event.motion.x / fs; 169 ret->data.motion.y = event.motion.y / fs; 170 } 171 break; 172 case SDL_MOUSEBUTTONUP: 173 //fprintf(stderr, "event: up %d (%d,%d)\n", event.button.button,event.button.x,event.button.y); 174 mousedown = 0; 175 if(!mousemoved) { 176 ret->type = EClick; 177 ret->data.click.button = event.button.button; 178 ret->data.click.point.x = event.button.x / fs; 179 ret->data.click.point.y = event.button.y / fs; 180 } 181 break; 182 case SDL_MOUSEBUTTONDOWN: 183 //fprintf(stderr, "event: down %d (%d,%d)\n", event.button.button,event.button.x,event.button.y); 184 mousemoved = 0; 185 mousedown = 1; 186 mousedowny = TOUCHSCREEN?-1:event.button.y; 187 break; 188 case SDL_KEYDOWN: 189 ret->type = EKey; 190 ret->data.key.modmask = 0; 191 if(event.key.keysym.mod & KMOD_CTRL) 192 ret->data.key.modmask |= Ctrl; 193 if(event.key.keysym.mod & KMOD_SHIFT) 194 ret->data.key.modmask |= Shift; 195 if(event.key.keysym.mod & KMOD_ALT) 196 ret->data.key.modmask |= Alt; 197 if(event.key.keysym.mod & KMOD_META) 198 ret->data.key.modmask |= Meta; 199 if(ret->data.key.keycode != 0 && event.key.keysym.unicode != 0) { 200 ret->data.key.keycode = event.key.keysym.unicode; 201 } 202 switch((int)event.key.keysym.sym) { 203 case 13: 204 ret->data.key.keycode = '\n'; 205 break; 206 case 275: 207 ret->data.key.keycode = KRight; 208 break; 209 case 276: 210 ret->data.key.keycode = KLeft; 211 break; 212 case 1073741906: // n900 up key 213 case 273: 214 ret->data.key.keycode = KUp; 215 break; 216 case 1073741912: // n900 down key 217 case 274: 218 ret->data.key.keycode = KDown; 219 break; 220 default: 221 ret->data.key.keycode = event.key.keysym.sym; 222 break; 223 } 224 fprintf(stderr, "event: key %d %d\n", 225 ret->data.key.modmask, ret->data.key.keycode); 226 break; 227 case SDL_QUIT: 228 ret->type = EQuit; 229 break; 230 } 231 has_event = 0; 232 return ret; 233 } 234 235 void 236 swk_gi_clear() { 237 SDL_Rect rect = { 0, 0, screen->w, screen->h }; 238 SDL_FillRect(screen, &rect, pal[ColorBG]); 239 } 240 241 void 242 swk_gi_flip() { 243 SDL_LockSurface(screen); 244 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); 245 SDL_UnlockSurface(screen); 246 } 247 248 /* -- drawing primitives -- */ 249 void 250 swk_gi_line(int x1, int y1, int x2, int y2, int color) { 251 Rect r = { x1, y1, x2, y2 }; 252 if(!x2 || !y2) 253 swk_gi_fill(r, color, 0); 254 // TODO: add support for diagonal lines? 255 } 256 257 void 258 swk_gi_fill(Rect r, int color, int lil) { 259 SDL_Rect area = { r.x*fs, r.y*fs, r.w*fs, r.h*fs }; 260 if(lil==1) { 261 const int s = fs/4; 262 area.x += s; 263 area.y += s; 264 area.w -= (s*2); 265 area.h -= (s*2); 266 } else if (lil==2) { 267 area.x/=4; 268 area.y+=4; 269 area.w/=4; 270 area.h-=4; 271 } else if (lil==3) { 272 const int s = fs/4; 273 area.w -= (s*2); 274 area.h -= (s*4); 275 } 276 if(!area.w) area.w = 1; 277 if(!area.h) area.h = 1; 278 SDL_FillRect(screen, &area, pal[color]); 279 } 280 281 void 282 swk_gi_rect(Rect r, int color) { 283 swk_gi_line(r.x, r.y, r.w, 0, color); 284 swk_gi_line(r.x, r.y+r.h, r.w, 0, color); 285 swk_gi_line(r.x, r.y, 0, r.h, color); 286 swk_gi_line(r.x+r.w, r.y, 0, r.h, color); 287 } 288 289 void 290 swk_gi_text(Rect r, const char *text) { 291 const char *tptr = text; 292 char *ptr = NULL; 293 int w = (int)((double)r.w * FONTFACTOR); 294 if(text && *text) { 295 int len = text?strlen(text):0; 296 if(len>w) { 297 tptr = ptr = strdup(text); 298 ptr[w]='\0'; 299 } 300 SDL_Surface *ts = TTF_RenderText_Shaded(font, tptr, fontcolor, bgcolor); 301 if(ts) { 302 SDL_Rect from = { 0, 4, ts->w, ts->h-2 }; 303 SDL_Rect to = { (r.x)*fs, 2+r.y*fs, ts->w, ts->h-4 }; 304 SDL_BlitSurface(ts, &from, screen, &to); 305 SDL_FreeSurface(ts); 306 } else fprintf(stderr, "Cannot render string (%s)\n", text); 307 } 308 free(ptr); 309 } 310 311 void 312 swk_gi_img(Rect r, void *img) { 313 if(img) { 314 SDL_Rect area = { r.x*fs, r.y*fs, r.w*fs, r.h*fs }; 315 area.x++; area.y++; 316 SDL_BlitSurface((SDL_Surface*)img, NULL, screen, &area); 317 } 318 } 319 320 /* image api */ 321 void* 322 swk_gi_img_new(int w, int h, int color) { 323 return (void *)SDL_CreateRGBSurface(0, (w*fs)-2, (h*fs)-2, BPP, 0, 0, 0, 0); 324 } 325 326 void* 327 swk_gi_img_load(const char *str) { 328 return IMG_Load(str); 329 } 330 331 void 332 swk_gi_img_free(void *s) { 333 SDL_FreeSurface(s); 334 } 335 336 void 337 swk_gi_img_set(void *img, int x, int y, int color) { 338 if(img) putpixel((SDL_Surface*)img, x, y, pal[color]); 339 } 340 341 int 342 swk_gi_img_get(void *img, int x, int y) { 343 Uint8 *p = getscrpoint(img, x, y); 344 return p?*p:0; 345 }