00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifdef HAVE_CONFIG_H
00030 # include <config.h>
00031 #endif
00032
00033 #ifndef ALPHA_LINUX_CXX
00034 # include <cstdlib>
00035 #endif
00036
00037 #include "SDL_video.h"
00038 #include "SDL_endian.h"
00039 #include <iostream>
00040
00041 #ifndef UNDER_CE
00042 using std::cout;
00043 using std::endl;
00044 using std::free;
00045 using std::malloc;
00046 #endif
00047
00048 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00049 #define qtohl(x) (x)
00050 #define qtohs(x) (x)
00051 #else
00052 #define qtohl(x) \
00053 ((Uint32)((((Uint32)(x) & 0x000000ffU) << 24) | \
00054 (((Uint32)(x) & 0x0000ff00U) << 8) | \
00055 (((Uint32)(x) & 0x00ff0000U) >> 8) | \
00056 (((Uint32)(x) & 0xff000000U) >> 24)))
00057 #define qtohs(x) \
00058 ((Uint16)((((Uint16)(x) & 0x00ff) << 8) | \
00059 (((Uint16)(x) & 0xff00) >> 8)))
00060 #endif
00061 #define htoql(x) qtohl(x)
00062 #define htoqs(x) qtohs(x)
00063
00064 typedef struct PCX_Header {
00065 Uint8 manufacturer;
00066 Uint8 version;
00067 Uint8 compression;
00068 Uint8 bpp;
00069 Sint16 x1, y1;
00070 Sint16 x2, y2;
00071 Sint16 hdpi;
00072 Sint16 vdpi;
00073 Uint8 colormap[48];
00074 Uint8 reserved;
00075 Uint8 planes;
00076 Sint16 bytesperline;
00077 Sint16 color;
00078 Uint8 filler[58];
00079 } PCX_Header;
00080
00081 static void writeline (SDL_RWops *dst, Uint8* buffer, int bytes) {
00082 Uint8 value, count, tmp;
00083 Uint8 *finish = buffer + bytes;
00084
00085 while (buffer < finish) {
00086
00087 value = *(buffer++);
00088 count = 1;
00089
00090 while (buffer < finish && count < 63 && *buffer == value) {
00091 count++; buffer++;
00092 }
00093
00094 if (value < 0xc0 && count == 1) {
00095 SDL_RWwrite(dst, &value, 1, 1);
00096 } else {
00097 tmp = count + 0xc0;
00098 SDL_RWwrite(dst, &tmp, 1, 1);
00099 SDL_RWwrite(dst, &value, 1, 1);
00100 }
00101 }
00102 }
00103
00104
00105 static void save_8 (SDL_RWops *dst, int width, int height,
00106 int pitch, Uint8* buffer)
00107 {
00108 int row;
00109
00110 for (row = 0; row < height; ++row)
00111 {
00112 writeline (dst, buffer, width);
00113 buffer += pitch;
00114 }
00115 }
00116
00117
00118 static void save_24 (SDL_RWops *dst, int width, int height,
00119 int pitch, Uint8* buffer)
00120 {
00121 int x, y, c;
00122 Uint8 *line;
00123
00124 line = (Uint8 *) malloc (width);
00125
00126 for (y = 0; y < height; ++y) {
00127 for (c = 2; c >= 0; --c) {
00128 for (x = 0; x < width; ++x) {
00129 line[x] = buffer[(3*x) + c];
00130 }
00131 writeline (dst, line, width);
00132 }
00133 buffer += pitch;
00134 }
00135 free (line);
00136 }
00137
00138 static bool save_image(SDL_Surface *surface, SDL_RWops *dst)
00139 {
00140 Uint8 *cmap = 0;
00141 Uint8 *pixels;
00142 Uint8 tmp;
00143 int width, height, pitch;
00144 int colors = 0, i;
00145 PCX_Header header;
00146
00147 width = surface->w;
00148 height = surface->h;
00149 pixels = (Uint8*)surface->pixels;
00150 pitch = surface->pitch;
00151
00152 header.manufacturer = 0x0a;
00153 header.version = 5;
00154 header.compression = 1;
00155
00156 if (surface->format->palette && surface->format->BitsPerPixel == 8) {
00157 colors = surface->format->palette->ncolors;
00158 cmap = (Uint8*)malloc(3*colors);
00159 for (i = 0; i < colors; i++) {
00160 cmap[3*i] = surface->format->palette->colors[i].r;
00161 cmap[3*i+1] = surface->format->palette->colors[i].g;
00162 cmap[3*i+2] = surface->format->palette->colors[i].b;
00163 }
00164 header.bpp = 8;
00165 header.bytesperline = htoqs (width);
00166 header.planes = 1;
00167 header.color = htoqs (1);
00168 } else if (surface->format->BitsPerPixel == 24) {
00169 header.bpp = 8;
00170 header.bytesperline = htoqs (width);
00171 header.planes = 3;
00172 header.color = htoqs(1);
00173 } else {
00174 return false;
00175 }
00176
00177 header.x1 = 0;
00178 header.y1 = 0;
00179 header.x2 = htoqs (width - 1);
00180 header.y2 = htoqs (height - 1);
00181
00182 header.hdpi = htoqs (300);
00183 header.vdpi = htoqs (300);
00184 header.reserved = 0;
00185
00186
00187
00188 SDL_RWwrite(dst, &header, sizeof(PCX_Header), 1);
00189
00190 if (cmap) {
00191 save_8 (dst, width, height, pitch, pixels);
00192
00193
00194 tmp = 0x0c;
00195 SDL_RWwrite(dst, &tmp, 1, 1);
00196 SDL_RWwrite(dst, cmap, 3, colors);
00197
00198
00199 tmp = 0;
00200 for (i = colors; i < 256; i++) {
00201 SDL_RWwrite(dst, &tmp, 1, 1);
00202 SDL_RWwrite(dst, &tmp, 1, 1);
00203 SDL_RWwrite(dst, &tmp, 1, 1);
00204 }
00205
00206 free(cmap);
00207 } else {
00208 save_24 (dst, width, height, pitch, pixels);
00209 }
00210
00211 return true;
00212 }
00213
00214 bool SavePCX_RW (SDL_Surface *saveme, SDL_RWops *dst, bool freedst)
00215 {
00216 SDL_Surface *surface;
00217 bool found_error = false;
00218
00219 cout << "Taking screenshot...";
00220
00221 surface = NULL;
00222 if ( dst ) {
00223 if ( saveme->format->palette ) {
00224 if ( saveme->format->BitsPerPixel == 8 ) {
00225 surface = saveme;
00226 } else {
00227 found_error = true;
00228 cout << saveme->format->BitsPerPixel
00229 << "bpp PCX files not supported" << endl;
00230 }
00231 }
00232 else if ( (saveme->format->BitsPerPixel == 24) &&
00233 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00234 (saveme->format->Rmask == 0x00FF0000) &&
00235 (saveme->format->Gmask == 0x0000FF00) &&
00236 (saveme->format->Bmask == 0x000000FF)
00237 #else
00238 (saveme->format->Rmask == 0x000000FF) &&
00239 (saveme->format->Gmask == 0x0000FF00) &&
00240 (saveme->format->Bmask == 0x00FF0000)
00241 #endif
00242 ) {
00243 surface = saveme;
00244 } else {
00245 SDL_Rect bounds;
00246
00247
00248 surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
00249 saveme->w, saveme->h, 24,
00250 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00251 0x00FF0000, 0x0000FF00, 0x000000FF,
00252 #else
00253 0x000000FF, 0x0000FF00, 0x00FF0000,
00254 #endif
00255 0);
00256
00257 if ( surface != NULL ) {
00258 bounds.x = 0;
00259 bounds.y = 0;
00260 bounds.w = saveme->w;
00261 bounds.h = saveme->h;
00262 if ( SDL_LowerBlit(saveme, &bounds, surface,
00263 &bounds) < 0 ) {
00264 SDL_FreeSurface(surface);
00265 cout << "Couldn't convert image to 24 bpp for screenshot";
00266 found_error = true;
00267 surface = NULL;
00268 }
00269 }
00270 }
00271 } else {
00272
00273 }
00274
00275 if ( surface && (SDL_LockSurface(surface) == 0) ) {
00276
00277 found_error |= !save_image(surface, dst);
00278
00279
00280 SDL_UnlockSurface(surface);
00281 if ( surface != saveme ) {
00282 SDL_FreeSurface(surface);
00283 }
00284 }
00285
00286
00287 if ( freedst && dst ) {
00288 SDL_RWclose(dst);
00289 }
00290
00291 if (!found_error) {
00292 cout << "Done!" << endl;
00293 return true;
00294 }
00295
00296 return false;
00297 }