NXEngine v1.0.0.5
[NXEngine.git] / graphics / nxsurface.cpp
blobc52f5a5e5e48375ecfa2e1e145581edf5b87f028
2 #include <string.h>
3 #include <stdint.h>
4 #include "../settings.h"
5 #include "../config.h"
6 #include "graphics.h"
7 #include "nxsurface.h"
8 #include "nxsurface.fdh"
10 #ifdef CONFIG_MUTABLE_SCALE
11 int SCALE = 3;
12 #endif
15 NXSurface::NXSurface()
17 fSurface = NULL;
18 fFreeSurface = true;
22 NXSurface::NXSurface(int wd, int ht, NXFormat *format)
24 fSurface = NULL;
25 AllocNew(wd, ht, format);
26 fFreeSurface = true;
30 NXSurface::NXSurface(SDL_Surface *from_sfc, bool free_surface)
32 fSurface = from_sfc;
33 fFreeSurface = free_surface;
36 NXSurface::~NXSurface()
38 Free();
41 // static function, and requires a reload of all surfaces
42 void NXSurface::SetScale(int factor)
44 #ifdef CONFIG_MUTABLE_SCALE
45 SCALE = factor;
46 #else
47 staterr("NXSurface::SetScale: CONFIG_MUTABLE_SCALE not set");
48 #endif
52 void c------------------------------() {}
55 // allocate for an empty surface of the given size
56 bool NXSurface::AllocNew(int wd, int ht, NXFormat *format)
58 Free();
60 fSurface = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, wd*SCALE, ht*SCALE, \
61 format->BitsPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask);
63 if (!fSurface)
65 staterr("NXSurface::AllocNew: failed to allocate RGB surface");
66 return 1;
69 return fSurface;
73 // load the surface from a .pbm or bitmap file
74 bool NXSurface::LoadImage(const char *pbm_name, bool use_colorkey, int use_display_format)
76 SDL_Surface *image;
78 Free();
80 if (use_display_format == -1)
81 { // use value specified in settings
82 use_display_format = settings->displayformat;
85 image = SDL_LoadBMP(pbm_name);
86 if (!image)
88 staterr("NXSurface::LoadImage: load failed of '%s'!", pbm_name);
89 return 1;
92 fSurface = Scale(image, SCALE, use_colorkey, true, use_display_format);
93 return (fSurface == NULL);
97 NXSurface *NXSurface::FromFile(const char *pbm_name, bool use_colorkey, int use_display_format)
99 NXSurface *sfc = new NXSurface;
100 if (sfc->LoadImage(pbm_name, use_colorkey, use_display_format))
102 delete sfc;
103 return NULL;
106 return sfc;
111 void c------------------------------() {}
114 // draw some or all of another surface onto this surface.
115 void NXSurface::DrawSurface(NXSurface *src, \
116 int dstx, int dsty, int srcx, int srcy, int wd, int ht)
118 SDL_Rect srcrect, dstrect;
120 srcrect.x = srcx * SCALE;
121 srcrect.y = srcy * SCALE;
122 srcrect.w = wd * SCALE;
123 srcrect.h = ht * SCALE;
125 dstrect.x = dstx * SCALE;
126 dstrect.y = dsty * SCALE;
128 SDL_BlitSurface(src->fSurface, &srcrect, fSurface, &dstrect);
131 void NXSurface::DrawSurface(NXSurface *src, int dstx, int dsty)
133 DrawSurface(src, dstx, dsty, 0, 0, src->Width(), src->Height());
136 // draw the given source surface in a repeating pattern across the entire width of the surface.
137 // x_dst: an starting X with which to offset the pattern horizontally (usually negative).
138 // y_dst: the Y coordinate to copy to on the destination.
139 // y_src: the Y coordinate to copy from.
140 // height: the number of pixels tall to copy.
141 void NXSurface::BlitPatternAcross(NXSurface *src,
142 int x_dst, int y_dst, int y_src, int height)
144 SDL_Rect srcrect, dstrect;
146 srcrect.x = 0;
147 srcrect.w = src->fSurface->w;
148 srcrect.y = (y_src * SCALE);
149 srcrect.h = (height * SCALE);
151 int x = (x_dst * SCALE);
152 int y = (y_dst * SCALE);
153 int destwd = fSurface->w;
157 dstrect.x = x;
158 dstrect.y = y;
160 SDL_BlitSurface(src->fSurface, &srcrect, fSurface, &dstrect);
161 x += src->fSurface->w;
163 while(x < destwd);
168 void c------------------------------() {}
172 void NXSurface::DrawRect(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, uint8_t b)
174 SDL_Rect rect;
175 uint32_t color = MapColor(r, g, b);
177 // top and bottom
178 rect.x = x1 * SCALE;
179 rect.y = y1 * SCALE;
180 rect.w = ((x2 - x1) + 1) * SCALE;
181 rect.h = SCALE;
182 SDL_FillRect(fSurface, &rect, color);
184 rect.y = y2 * SCALE;
185 SDL_FillRect(fSurface, &rect, color);
187 // left and right
188 rect.y = y1 * SCALE;
189 rect.w = SCALE;
190 rect.h = ((y2 - y1) + 1) * SCALE;
191 SDL_FillRect(fSurface, &rect, color);
193 rect.x = x2 * SCALE;
194 SDL_FillRect(fSurface, &rect, color);
198 void NXSurface::FillRect(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, uint8_t b)
200 SDL_Rect rect;
202 rect.x = x1 * SCALE;
203 rect.y = y1 * SCALE;
204 rect.w = ((x2 - x1) + 1) * SCALE;
205 rect.h = ((y2 - y1) + 1) * SCALE;
207 SDL_FillRect(fSurface, &rect, MapColor(r, g, b));
210 void NXSurface::Clear(uint8_t r, uint8_t g, uint8_t b)
212 SDL_FillRect(fSurface, NULL, MapColor(r, g, b));
216 void NXSurface::DrawPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b)
218 DrawRect(x, y, x, y, r, g, b);
222 void c------------------------------() {}
225 int NXSurface::Width()
227 return fSurface->w / SCALE;
230 int NXSurface::Height()
232 return fSurface->h / SCALE;
235 NXFormat *NXSurface::Format()
237 return fSurface->format;
240 void NXSurface::Flip()
242 SDL_Flip(fSurface);
246 void c------------------------------() {}
249 void NXSurface::set_clip_rect(int x, int y, int w, int h)
251 NXRect rect(x * SCALE, y * SCALE, w * SCALE, h * SCALE);
252 SDL_SetClipRect(fSurface, &rect);
255 void NXSurface::set_clip_rect(NXRect *rect)
257 SDL_SetClipRect(fSurface, rect);
260 void NXSurface::clear_clip_rect()
262 SDL_SetClipRect(fSurface, NULL);
266 void c------------------------------() {}
269 // internal function which scales the given SDL surface by the given factor.
270 SDL_Surface *NXSurface::Scale(SDL_Surface *original, int factor, \
271 bool use_colorkey, bool free_original, bool use_display_format)
273 SDL_Surface *scaled;
275 if (factor == 1 && free_original)
277 scaled = original;
279 else
281 scaled = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, \
282 original->w * SCALE, \
283 original->h * SCALE, \
284 original->format->BitsPerPixel, \
285 original->format->Rmask, original->format->Gmask,
286 original->format->Bmask, original->format->Amask);
288 if (original->format->BitsPerPixel == 8)
289 { // copy the palette from the old surface to the new surface
290 SDL_Color palette[256];
291 for(int i=0;i<256;i++)
293 SDL_GetRGB(i, original->format, &palette[i].r, &palette[i].g, &palette[i].b);
296 SDL_SetColors(scaled, palette, 0, 256);
299 // all the .pbm files are 8bpp, so I haven't had a reason
300 // to write any other scalers.
301 switch(original->format->BitsPerPixel)
303 case 8:
304 Scale8(original, scaled, factor);
305 break;
307 default:
308 staterr("NXSurface::Scale: unsupported bpp %d", original->format->BitsPerPixel);
309 SDL_FreeSurface(scaled);
310 return NULL;
313 // can get rid of original now if they wanted us to
314 if (free_original)
315 SDL_FreeSurface(original);
318 // set colorkey to black if requested
319 if (use_colorkey)
320 { // don't use SDL_RLEACCEL--it seems to actually make things a lot slower,
321 // especially on maps with motion tiles.
322 SDL_SetColorKey(scaled, SDL_SRCCOLORKEY, SDL_MapRGB(scaled->format, 0, 0, 0));
325 if (use_palette)
327 scaled = palette_add(scaled);
328 if (!scaled)
329 return NULL;
332 if (use_display_format)
334 SDL_Surface *ret_sfc = SDL_DisplayFormat(scaled);
335 SDL_FreeSurface(scaled);
337 return ret_sfc;
339 else
341 return scaled;
345 void NXSurface::Scale8(SDL_Surface *src, SDL_Surface *dst, int factor)
347 int x, y, i;
349 for(y=0;y<src->h;y++)
351 uint8_t *srcline = (uint8_t *)src->pixels + (y * src->pitch);
352 uint8_t *dstline = (uint8_t *)dst->pixels + (y * factor * dst->pitch);
353 uint8_t *dstptr = dstline;
355 for(x=0;x<src->w;x++)
357 for(i=0;i<factor;i++)
358 *(dstptr++) = srcline[x];
361 dstptr = dstline;
362 for(i=1;i<factor;i++)
364 dstptr += dst->pitch;
365 memcpy(dstptr, dstline, dst->pitch);
371 void c------------------------------() {}
374 void NXSurface::EnableColorKey()
376 SDL_SetColorKey(fSurface, SDL_SRCCOLORKEY, SDL_MapRGB(fSurface->format, 0, 0, 0));
379 uint32_t NXSurface::MapColor(uint8_t r, uint8_t g, uint8_t b)
381 return SDL_MapRGB(fSurface->format, r, g, b);
385 void NXSurface::Free()
387 if (fSurface)
389 if (fFreeSurface)
390 SDL_FreeSurface(fSurface);
392 fSurface = NULL;