Added a background to the help menu. Made textboxes support CTRL-<key>.
[xuni.git] / src / graphics.c
blob0e07af6681cf7f1e4bc9df31fd1588ff680474bb
1 /*! \file graphics.c
3 */
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8 #include <time.h> /* for save_screenshot()'s calls */
10 #include "SDL_image.h"
12 #include "error.h"
13 #include "graphics.h"
14 #include "gui.h"
15 #include "memory.h"
16 #include "resource/resource.h"
18 static void load_icon(const char *file);
19 static Uint32 get_flags(const struct smode_t *smode);
20 static SDL_Surface *set_graphics_mode(const struct smode_t *smode);
21 static int try_resizing_screen(struct smode_t *smode);
22 static void call_blit_surface(SDL_Surface *from, SDL_Rect *fromrect,
23 SDL_Surface *to, SDL_Rect *torect);
24 static void fill_area_no_alpha(SDL_Surface *screen,
25 int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b);
26 static Uint32 get_pixel(SDL_Surface *surface, int x, int y);
28 void restrict_int(int *value, int max) {
29 if(*value < 0) *value = 0;
30 else if(*value > max) *value = max;
33 void restrict_pos(double *pos) {
34 if(*pos < 0.0) *pos = 0.0;
35 else if(*pos > 100.0) *pos = 100.0;
38 void wrap_int(int *value, int max) {
39 if(*value < 0) *value = max - (-*value % max);
40 else *value %= max;
43 void init_smode(struct smode_t *smode, struct resource_t *settings) {
44 smode->screen = 0;
45 smode->width = (int)lookup_resource_number(settings, 640,
46 "xuni-resource", "screenmode", "width", 0);
47 smode->height = (int)lookup_resource_number(settings, 480,
48 "xuni-resource", "screenmode", "height", 0);
49 smode->depth = (int)lookup_resource_number(settings, 0,
50 "xuni-resource", "screenmode", "depth", 0);
51 smode->fullscreen = (int)lookup_resource_number(settings, 0,
52 "xuni-resource", "screenmode", "fullscreen", 0);
54 smode->focus = -1;
56 smode->restrictfocus = (int)lookup_resource_number(settings, 0,
57 "xuni-resource", "screenmode", "restrict", 0);
60 /*! Initializes the SDL and SDL_ttf. Also sets the screen mode, sets the
61 caption to "Loading", disables SDL UNICODE translation, sets the focus,
62 enables key repeating, loads the icon for the window, etc.
63 \param smode The screen mode structure to read the screen mode from.
64 \param icon The icon to use for the xuni application window.
66 void init_sdl_libraries(struct smode_t *smode, const char *icon) {
67 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
68 log_message(ERROR_TYPE_FATAL, ERROR_FLAG_SDL, __FILE__, __LINE__,
69 "Can't init SDL");
72 load_icon(icon);
74 smode->screen = set_graphics_mode(smode);
75 if(!smode->screen) {
76 /* try default screen mode? */
77 log_message(ERROR_TYPE_FATAL, ERROR_FLAG_SDL, __FILE__, __LINE__,
78 "Can't set graphics mode %ix%ix%i (%s)",
79 smode->width, smode->height, smode->depth,
80 smode->fullscreen ? "fullscreen" : "windowed");
83 set_caption("Loading . . .");
85 smode->restrictfocus = set_focus(smode->restrictfocus);
87 focus_changed(smode, SDL_APPACTIVE);
89 SDL_EnableUNICODE(0);
91 if(TTF_Init() < 0) {
92 /* !!! this doesn't have to be a fatal error */
93 log_message(ERROR_TYPE_FATAL, 0, __FILE__, __LINE__,
94 "Can't init SDL_ttf: %s", TTF_GetError());
97 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
98 SDL_DEFAULT_REPEAT_INTERVAL);
101 /*! Tries to set the input grab mode ("focus") to \a mode, but only if the
102 current grab mode differs from the requested grab mode. If the modes are
103 the same, it does nothing. Regardless, it returns the new grab mode.
104 \param mode The mode to set the grab mode ("focus") to.
105 \return The new grab mode. This could differ from \a mode if the function
106 failed to set the grab mode.
108 SDL_GrabMode set_focus(SDL_GrabMode mode) {
109 if(SDL_WM_GrabInput(SDL_GRAB_QUERY) != mode) {
110 return SDL_WM_GrabInput(mode);
113 return mode;
116 /*! Determines whether the xuni windows has a specific type of focus or not.
117 \param focus The OR'd focus flags to check for, SDL_APP*.
118 \return True if the window has the focus specified in \a focus.
120 int focus_in(Uint8 focus) {
121 return (SDL_GetAppState() & focus) == focus;
124 /*! Sets \a smode->focus, based on the flags in \a focus.
125 \param smode The structure which contains the \c focus member to set.
126 \param focus The focus which, if true, to consider the xuni window active.
127 \return Nonzero if the focus has changed.
129 int focus_changed(struct smode_t *smode, Uint8 focus) {
130 /*printf("focus_changed(): mouse=%i input=%i active=%i\n",
131 SDL_GetAppState() & SDL_APPMOUSEFOCUS,
132 SDL_GetAppState() & SDL_APPINPUTFOCUS,
133 SDL_GetAppState() & SDL_APPACTIVE);*/
135 if(focus_in(focus)) {
136 if(!smode->focus) {
137 smode->focus = 1;
138 return 1;
141 else if(smode->focus) {
142 smode->focus = 0;
143 return 1;
146 return 0;
149 /*! Uninitializes the SDL and SDL_ttf libraries; the other SDL libraries
150 require no such de-initialization.
152 void quit_sdl_libraries(void) {
153 TTF_Quit();
154 SDL_Quit();
157 void free_smode(struct smode_t *smode) {
161 /*! Frees the memory allocated for a theme_t structure.
162 \param theme The theme_t structure to free the contents of.
164 void free_theme(struct theme_t *theme) {
165 SDL_FreeCursor(theme->cursors.text);
168 /*! Loads and sets an icon for the SDL window. If the icon could not be
169 opened, prints a warning instead.
171 \param file The file to use as an icon, in any format supported by
172 SDL_image. Note that Windows icons must be 32x32 to work correctly.
174 static void load_icon(const char *file) {
175 SDL_Surface *icon;
177 if(!file) return;
179 icon = IMG_Load(file);
181 if(icon) {
182 SDL_WM_SetIcon(icon, NULL);
183 SDL_FreeSurface(icon);
185 else {
186 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__, __LINE__,
187 "Can't open application icon \"%s\"", file);
191 /*! Save screenshots to shot_<time>[_<number>].bmp, where number is the Nth
192 screenshot this second. A number is only appended if a screenshot has
193 already been taken this second.
195 time is of the format mm-dd-yy_at_hh-mm-ss; hours are in 24-hour time.
197 This function is not thread-safe, because it calls localtime().
199 \param screen The surface to save to the file (usually the main screen).
201 void save_screenshot(SDL_Surface *screen) {
202 char filename[BUFSIZ];
203 static time_t prevt = (time_t)-1; /* error return value of mktime() */
204 static int count = 0;
205 time_t t = time(NULL);
206 struct tm *local = localtime(&t);
207 int pos;
209 pos = sprintf(filename, "shot_%02i-%02i-%02i_at_%02i-%02i-%02i",
210 local->tm_mday, local->tm_mon + 1, local->tm_year % 100,
211 local->tm_hour, local->tm_min, local->tm_sec);
213 if(t == prevt) {
214 /* +1 to start at _2 */
215 pos += sprintf(filename + pos, "_%i", ++count + 1);
217 else count = 0;
219 prevt = t; /* hopefully time_ts can be assigned */
221 strcpy(filename + pos, ".bmp");
223 if(SDL_SaveBMP(screen, filename)) {
224 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__, __LINE__,
225 "Can't save screenshot \"%s\"", filename);
227 else {
228 log_message(ERROR_TYPE_LOG, 0, __FILE__, __LINE__,
229 "Screenshot saved as \"%s\"", filename);
231 /* perhaps compress the screenshot here? */
235 void paint_cursor(struct xuni_t *xuni, struct widget_t *cursor) {
236 int xp, yp;
238 if(!cursor || !focus_in(SDL_APPMOUSEFOCUS)) return;
240 SDL_GetMouseState(&xp, &yp);
242 prepare_paint_image(xuni, cursor);
244 blit_surface(xuni->smode->screen,
245 cursor->p.image->image,
246 xp - cursor->p.image->image->w / 2,
247 yp - cursor->p.image->image->h / 2);
250 void show_cursor(int enable) {
251 int prev = SDL_ShowCursor(enable ? SDL_ENABLE : SDL_DISABLE);
253 /* Handles a bug in the X11 video driver: when the cursor is disabled,
254 moved, and then re-enabled, it is painted in the original position,
255 but otherwise the SDL thinks it is in the new position. Calling
256 SDL_GetMouseState() returns the new position. It takes a mouse motion
257 event (generated here by SDL_WarpMouse()) for everything to work
258 properly.
260 (This is with SDL 1.2.12.)
262 if(prev == SDL_DISABLE && enable) {
263 int x, y;
264 SDL_GetMouseState(&x, &y);
265 SDL_WarpMouse(x, y);
269 /*! Opens the image \a filename as an SDL_Surface. Logs a warning if the file
270 could not be opened.
271 \param filename The image to open (in any format supported by SDL_image).
272 \return The opened image (as an SDL_Surface) or NULL on error.
274 SDL_Surface *load_image(const char *filename) {
275 SDL_Surface *intermediate, *image;
277 if(!filename || !*filename) return 0;
279 intermediate = IMG_Load(filename);
281 if(!intermediate) {
282 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__, __LINE__,
283 "Can't open image \"%s\"", filename);
284 return 0;
287 image = SDL_DisplayFormatAlpha(intermediate);
288 SDL_FreeSurface(intermediate);
290 increment_allocated(allocated_sdl_surface(image));
292 return image;
295 int resize_screen(struct smode_t *smode, const SDL_ResizeEvent *resize) {
296 int x = smode->width;
297 int y = smode->height;
299 smode->width = resize->w;
300 smode->height = resize->h;
302 if(try_resizing_screen(smode)) {
303 smode->width = x;
304 smode->height = y;
306 return 1;
309 return 0;
312 /*! Toggles fullscreen mode for the xuni window.
314 First tries SDL_WM_ToggleFullScreen(); if that fails, it then tries
315 try_resizing_screen().
317 \param smode The current screen mode that the xuni window is in.
318 \return Zero on success, nonzero on failure.
320 int toggle_fullscreen(struct smode_t *smode) {
321 smode->fullscreen = !smode->fullscreen;
323 /*return 0;*/
325 if(SDL_WM_ToggleFullScreen(smode->screen)) return 0;
327 if(!try_resizing_screen(smode)) return 0;
329 smode->fullscreen = !smode->fullscreen; /* undo previous toggling */
330 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__, __LINE__,
331 "Can't toggle fullscreen to \"%s\"",
332 smode->fullscreen ? "fullscreen" : "windowed");
334 return 1;
337 void use_screen_mode(struct xuni_t *xuni, int width, int height) {
338 SDL_Event event;
340 event.resize.w = width;
341 event.resize.h = height;
343 if(!resize_screen(xuni->smode, &event.resize)) {
344 widget_event(xuni, xuni->gui->widget, WIDGET_EVENT_RESCALE);
348 /*! Changes the title of the xuni window to the printf-compatible arguments
349 passed.
350 \param format The format string to change the title of the xuni window to.
351 \param ... The printf-compatible arguments matching format specifiers in
352 \a format.
354 void set_caption(const char *format, ...) {
355 va_list arg;
356 char *wt;
358 va_start(arg, format);
359 wt = malloc(BUFSIZ + 1);
361 vsprintf(wt, format, arg);
363 SDL_WM_SetCaption(wt, NULL);
365 free(wt);
366 va_end(arg);
369 static Uint32 get_flags(const struct smode_t *smode) {
370 Uint32 flags = SDL_SWSURFACE | SDL_RESIZABLE | SDL_ANYFORMAT;
371 if(smode->fullscreen) flags |= SDL_FULLSCREEN;
373 return flags;
376 static SDL_Surface *set_graphics_mode(const struct smode_t *smode) {
377 return SDL_SetVideoMode(smode->width, smode->height, smode->depth,
378 get_flags(smode));
381 SDL_Rect **list_graphics_modes(struct smode_t *smode) {
382 return SDL_ListModes(NULL, get_flags(smode));
385 static int try_resizing_screen(struct smode_t *smode) {
386 SDL_Surface *nscreen = set_graphics_mode(smode);
388 if(nscreen) smode->screen = nscreen;
390 return nscreen == 0;
393 /*! Locks the video surface so that data can be written directly to, pixel by
394 pixel.
396 \param screen The surface to lock (should be the screen, the main video
397 surface).
399 void lock_screen(SDL_Surface *screen) {
400 if(SDL_MUSTLOCK(screen)) {
401 if(SDL_LockSurface(screen) < 0) {
402 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL,
403 __FILE__, __LINE__, "Can't lock screen (%p)", (void *)screen);
408 /*! Reverts the effects of lock_screen(). That is, unlocks the video surface
409 so that it can be written to normally, with surface blitting and so on.
411 \param screen The surface to unlock (should be the screen, the main video
412 surface).
414 void unlock_screen(SDL_Surface *screen) {
415 if(SDL_MUSTLOCK(screen)) {
416 SDL_UnlockSurface(screen);
420 void clear_screen(SDL_Surface *screen) {
421 SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
424 SDL_Surface *new_surface(int w, int h, int d, int alpha) {
425 SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, d,
426 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
427 0xff000000, /* red */
428 0x00ff0000, /* green */
429 0x0000ff00, /* blue */
430 alpha && 0x000000ff
431 #else
432 0x000000ff, /* red */
433 0x0000ff00, /* green */
434 0x00ff0000, /* blue */
435 alpha && 0xff000000
436 #endif
439 if(!surface) {
440 log_message(ERROR_TYPE_FATAL, ERROR_FLAG_SDL, __FILE__, __LINE__,
441 "Can't create new %ix%ix%i surface in %s edian", w, h, d,
442 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
443 "big"
444 #else
445 "little"
446 #endif
450 return surface;
453 void free_surface(SDL_Surface *surface) {
454 decrement_allocated(allocated_sdl_surface(surface));
456 if(/*xuni_memory_decrement*/(surface)) SDL_FreeSurface(surface);
459 static void call_blit_surface(SDL_Surface *from, SDL_Rect *fromrect,
460 SDL_Surface *to, SDL_Rect *torect) {
462 if(!from || !to) {
463 log_message(ERROR_TYPE_WARNING, 0, __FILE__, __LINE__,
464 "Can't blit NULL surface: blitting %p to %p",
465 (void *)from, (void *)to);
466 return;
469 if(SDL_BlitSurface(from, fromrect, to, torect) < 0) {
470 if(fromrect) {
471 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__,
472 __LINE__,
473 "Can't blit %lux%lu from (%lu,%lu) of surface %p (%lux%lu)",
474 (unsigned long)fromrect->w, (unsigned long)fromrect->h,
475 (unsigned long)fromrect->x, (unsigned long)fromrect->y,
476 (void *)from, (unsigned long)from->w, (unsigned long)from->h);
478 else {
479 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_SDL, __FILE__,
480 __LINE__,
481 "Can't blit all (NULL rect) of surface %p (%lux%lu)",
482 (void *)from, (unsigned long)from->w, (unsigned long)from->h);
485 if(torect) {
486 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_CONTINUED, __FILE__,
487 __LINE__,
488 "to surface %p (%lux%lu) at (%lu,%lu)",
489 (void *)to, (unsigned long)to->w, (unsigned long)to->h,
490 (unsigned long)torect->x, (unsigned long)torect->y);
492 else {
493 log_message(ERROR_TYPE_WARNING, ERROR_FLAG_CONTINUED, __FILE__,
494 __LINE__,
495 "to surface %p (%lux%lu) at (0,0) (NULL rect)",
496 (void *)to, (unsigned long)to->w, (unsigned long)to->h);
501 void blit_surface(SDL_Surface *screen, SDL_Surface *image, int xp, int yp) {
502 SDL_Rect rect;
504 if(!image) return;
506 rect.x = xp;
507 rect.y = yp;
509 call_blit_surface(image, NULL, screen, &rect);
512 void blit_surface_area(SDL_Surface *screen, SDL_Surface *image,
513 int tx, int ty, int fx, int fy, int fw, int fh) {
515 SDL_Rect from, to;
517 from.x = fx;
518 from.y = fy;
519 from.w = fw;
520 from.h = fh;
521 to.x = tx;
522 to.y = ty;
524 call_blit_surface(image, &from, screen, &to);
527 void blit_surface_repeat(SDL_Surface *screen, SDL_Surface *image,
528 int xp, int yp, int w, int h) {
530 int x, y;
531 SDL_Rect srect, drect;
533 srect.x = 0;
534 srect.y = 0;
536 for(x = 0; x < w; x += image->w) {
537 for(y = 0; y < h; y += image->h) {
538 drect.x = xp + x;
539 drect.y = yp + y;
541 if(x + image->w > w) srect.w = w - x;
542 else srect.w = image->w;
543 if(y + image->h > h) srect.h = h - y;
544 else srect.h = image->h;
546 call_blit_surface(image, &srect, screen, &drect);
551 #if !1
552 /* !!! this function accounts for nearly 100% of xuni's execution time */
553 void blit_surface_repeat_area(SDL_Surface *screen, SDL_Surface *image,
554 int tx, int ty, int tw, int th, int fx, int fy, int fw, int fh) {
556 int x, y;
557 SDL_Rect srect, drect;
559 srect.x = fx;
560 srect.y = fy;
562 for(x = 0; x < tw; x += fw) {
563 for(y = 0; y < th; y += fh) {
564 drect.x = tx + x;
565 drect.y = ty + y;
567 if(x + fw > tw) srect.w = tw - x;
568 else srect.w = fw;
569 if(y + fh > th) srect.h = th - y;
570 else srect.h = fh;
572 call_blit_surface(image, &srect, screen, &drect);
576 #else
577 void blit_surface_repeat_area(SDL_Surface *screen, SDL_Surface *image,
578 int tx, int ty, int tw, int th, int fx, int fy, int fw, int fh) {
580 int x, y;
581 SDL_Rect srect, drect;
583 srect.x = fx;
584 srect.y = fy;
586 srect.w = fw;
588 for(x = 0; x < tw; x += fw) {
589 drect.x = tx + x;
591 if(x + fw > tw) srect.w = tw - x;
593 srect.h = fh;
595 for(y = 0; y < th; y += fh) {
596 drect.y = ty + y;
598 if(y + fh > th) srect.h = th - y;
600 call_blit_surface(image, &srect, screen, &drect);
604 #endif
606 void blit_surface_fill_from(SDL_Surface *screen, SDL_Surface *image,
607 int tx, int ty, int tw, int th, int fx1, int fy1) {
609 int x, y;
610 SDL_Rect srect, drect;
612 /*x = image->w - fx1 < tw ? image->w - fx1 : tw;
613 y = image->h - fy1 < th ? image->h - fy1 : th;
614 blit_surface_area(screen, image,
615 tx, ty, fx1, fy1, x, y);*/
617 for(x = fx1 - image->w; x < tw; x += image->w) {
618 for(y = fy1 - image->h; y < th; y += image->h) {
619 if(x < 0) {
620 drect.x = tx;
621 srect.x = -x;
622 srect.w = image->w - -x;
624 else {
625 drect.x = tx + x;
627 srect.x = 0;
628 if(x + image->w > tw) srect.w = tw - x;
629 else srect.w = image->w;
632 if(y < 0) {
633 drect.y = ty;
634 srect.y = -y;
635 srect.h = image->h - -y;
637 else {
638 drect.y = ty + y;
640 srect.y = 0;
641 if(y + image->h > th) srect.h = th - y;
642 else srect.h = image->h;
645 call_blit_surface(image, &srect, screen, &drect);
650 void update_screen(struct xuni_t *xuni) {
651 SDL_UpdateRect(xuni->smode->screen, 0, 0, 0, 0);
654 /*! Returns true if the position (\a xp, \a yp) is inside the rectangle
655 between (\a x, \a y) and (\c x+w, \c y+h).
656 \param xp The x coordinate of the position to check.
657 \param yp The y coordinate as the position to check.
658 \param x The x coordinate of the upper-left corner of the rectangle.
659 \param y The y coordinate of the upper-left corner of the rectangle.
660 \param w The width of the rectangle.
661 \param h The height of the rectangle.
662 \return True if the position is inside the rectangle.
664 int in_rect(int xp, int yp, int x, int y, int w, int h) {
665 return xp >= x && xp < x + w && yp >= y && yp < y + h;
668 /*! Returns true if the position (\a xp, \a yp) is inside the rectangle
669 delimited by the SDL_Rect \a r.
670 \param xp The x-coordinate of the position to check.
671 \param yp The y-coordinate of the position to check.
672 \param r The rectangle to look for a position inside.
673 \return True if the position is inside the rectangle.
675 int in_sdl_rect(int xp, int yp, const SDL_Rect *r) {
676 return xp >= r->x && xp < r->x + r->w && yp >= r->y && yp < r->y + r->h;
679 int pos_in_rect(int xp, int yp, const struct pos_t *pos) {
680 /*if(!pos->clip)*/ return in_sdl_rect(xp, yp, &pos->real);
682 #if 0
683 xp -= pos->real.x;
684 yp -= pos->real.y;
686 #if !1
687 printf("(%i,%i) in (%i+%i=%i,%i+%i=%i) by (%i,%i)\n",
688 xp, yp,
689 pos->real.x, pos->clip->xoff, /*pos->clip->xclip,*/
690 pos->real.x + pos->clip->xoff /*+ pos->clip->xclip*/,
691 pos->real.y, pos->clip->yoff, /*pos->clip->yclip,*/
692 pos->real.y + pos->clip->yoff /*+ pos->clip->yclip*/,
693 pos->clip->wclip, pos->clip->hclip);
695 printf("origin values: (%i,%i) is in (%i,%i)\n",
696 xp - pos->real.x - pos->clip->xoff,
697 yp - pos->real.y - pos->clip->yoff,
698 pos->clip->wclip, pos->clip->hclip);
699 #else
700 printf("(%i,%i) in (%i,%i) by (%i,%i)\n", xp, yp,
701 pos->clip->xoff /*+ pos->clip->xclip*/,
702 pos->clip->yoff /*+ pos->clip->yclip*/,
703 pos->clip->wclip, pos->clip->hclip);
704 #endif
706 printf(" is %i\n", in_rect(xp, yp,
707 pos->clip->xoff /*+ pos->clip->xclip*/,
708 pos->clip->yoff /*+ pos->clip->yclip*/,
709 pos->clip->wclip, pos->clip->hclip));
711 return in_rect(xp, yp,
712 pos->clip->xoff /*+ pos->clip->xclip*/,
713 pos->clip->yoff /*+ pos->clip->yclip*/,
714 pos->clip->wclip, pos->clip->hclip);
715 #endif
718 #if 0
719 static struct widget_t *widget_selable(struct widget_t *widget) {
720 if(!widget) return 0;
722 /*printf("widget_selable(): \"%s\"\n", widget->name);*/
724 while(widget->selable && widget->base) {
725 widget = widget->base;
726 /*printf(" -> \"%s\"\n", widget->name);*/
729 return widget;
731 #endif
733 static void fill_area_no_alpha(SDL_Surface *screen,
734 int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b) {
736 SDL_Rect rect;
738 rect.x = x;
739 rect.y = y;
740 rect.w = w;
741 rect.h = h;
743 SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b));
746 void fill_area(SDL_Surface *screen, int x, int y, int w, int h,
747 SDL_Surface *image, int ix, int iy) {
749 Uint8 r, g, b, a;
751 SDL_GetRGBA(get_pixel(image, ix, iy), image->format, &r, &g, &b, &a);
753 if(a == 255) { /* opaque, can use fast filling */
754 fill_area_no_alpha(screen, x, y, w, h, r, g, b);
756 else {
757 blit_surface_repeat_area(screen, image, x, y, w, h, ix, iy, 1, 1);
761 static Uint32 get_pixel(SDL_Surface *surface, int x, int y) {
762 Uint8 *p;
764 if(!surface->pixels) return 0;
766 p = (Uint8 *)surface->pixels
767 + y * surface->pitch
768 + x * surface->format->BytesPerPixel;
770 if(x < 0 || y < 0 || x >= surface->w || y >= surface->h) return 0;
772 switch(surface->format->BytesPerPixel) {
773 case 1:
774 return *p;
775 case 2:
776 return *(Uint16 *)p;
777 case 3:
778 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
779 return p[0] << 16 | p[1] << 8 | p[2];
781 else return p[0] | p[1] << 8 | p[2] << 16;
782 case 4:
783 return *(Uint32 *)p;
784 default:
785 return 0;