initial commit
This commit is contained in:
		
							
								
								
									
										275
									
								
								corona/src/Convert.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								corona/src/Convert.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| /** | ||||
|  * @file | ||||
|  * @todo  allow conversions from direct color images to | ||||
|  *        palettized images | ||||
|  */ | ||||
| #include <map> | ||||
| #include <utility> | ||||
| #include "corona.h" | ||||
| #include "Debug.h" | ||||
| #include "SimpleImage.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   Image* ExpandPalette(Image* image) { | ||||
|     COR_GUARD("ExpandPalette()"); | ||||
|  | ||||
|     // assert isPalettized(image->getFormat()) | ||||
|  | ||||
|     const int width                  = image->getWidth(); | ||||
|     const int height                 = image->getHeight(); | ||||
|     const byte* in                   = (byte*)image->getPixels(); | ||||
|     const PixelFormat palette_format = image->getPaletteFormat(); | ||||
|     const int pixel_size             = GetPixelSize(palette_format); | ||||
|     const byte* palette              = (byte*)image->getPalette(); | ||||
|  | ||||
|     byte* pixels = new byte[width * height * pixel_size]; | ||||
|     byte* out = pixels; | ||||
|     for (int i = 0; i < width * height; ++i) { | ||||
|       memcpy(out, palette + (*in) * pixel_size, pixel_size); | ||||
|       out += pixel_size; | ||||
|       ++in; | ||||
|     } | ||||
|     delete image; | ||||
|     return new SimpleImage(width, height, palette_format, pixels); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   struct FormatDesc { | ||||
|     FormatDesc(int r, int g, int b, int a, bool ha) { | ||||
|       r_shift = r; | ||||
|       g_shift = g; | ||||
|       b_shift = b; | ||||
|       a_shift = a; | ||||
|       has_alpha = ha; | ||||
|     } | ||||
|  | ||||
|     // shifts are in bytes from the right | ||||
|     // In the case of RGBA, r_shift is 0, g_shift is 1, ... | ||||
|     int r_shift; | ||||
|     int g_shift; | ||||
|     int b_shift; | ||||
|     int a_shift; | ||||
|     bool has_alpha; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   #define DEFINE_DESC(format, desc)          \ | ||||
|     case format: {                           \ | ||||
|       COR_LOG(#format);                      \ | ||||
|       static FormatDesc format##_desc desc;  \ | ||||
|       return &format##_desc;                 \ | ||||
|     } | ||||
|  | ||||
|   FormatDesc* GetDescription(PixelFormat format) { | ||||
|     // assert isDirect(image->getFormat()) | ||||
|  | ||||
|     switch (format) { | ||||
|       DEFINE_DESC(PF_R8G8B8A8, (0, 1, 2, 3, true)); | ||||
|       DEFINE_DESC(PF_R8G8B8,   (0, 1, 2, 0, false)); | ||||
|       DEFINE_DESC(PF_B8G8R8A8, (2, 1, 0, 3, true)); | ||||
|       DEFINE_DESC(PF_B8G8R8,   (2, 1, 0, 0, false)); | ||||
|       default: return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   bool ConvertPixels(byte* out, PixelFormat out_format, | ||||
|                      const byte* in,  PixelFormat in_format, | ||||
|                      int pixel_count) | ||||
|   { | ||||
|     const FormatDesc* out_desc = GetDescription(out_format); | ||||
|     const FormatDesc* in_desc  = GetDescription(in_format); | ||||
|     if (!out_desc || !in_desc) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     const int out_size = GetPixelSize(out_format); | ||||
|     const int in_size  = GetPixelSize(in_format); | ||||
|  | ||||
|     for (int i = 0; i < pixel_count; ++i) { | ||||
|       out[out_desc->r_shift] = in[in_desc->r_shift]; | ||||
|       out[out_desc->g_shift] = in[in_desc->g_shift]; | ||||
|       out[out_desc->b_shift] = in[in_desc->b_shift]; | ||||
|  | ||||
|       if (out_desc->has_alpha) { | ||||
|         if (in_desc->has_alpha) { | ||||
|           out[out_desc->a_shift] = in[in_desc->a_shift]; | ||||
|         } else { | ||||
|           out[out_desc->a_shift] = 255; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       in  += in_size; | ||||
|       out += out_size; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   Image* DirectConversion(Image* image, PixelFormat target_format) { | ||||
|     COR_GUARD("DirectConversion()"); | ||||
|  | ||||
|     // assert isDirect(image->getFormat()) | ||||
|  | ||||
|     const int width                 = image->getWidth(); | ||||
|     const int height                = image->getHeight(); | ||||
|     const PixelFormat source_format = image->getFormat(); | ||||
|     const byte* in                  = (byte*)image->getPixels(); | ||||
|  | ||||
|     if (source_format == target_format) { | ||||
|         return image; | ||||
|     } | ||||
|  | ||||
|     const int target_size = GetPixelSize(target_format); | ||||
|     byte* out_pixels = new byte[width * height * target_size]; | ||||
|     if (!ConvertPixels(out_pixels, target_format, | ||||
|                        in, source_format, | ||||
|                        width * height)) | ||||
|     { | ||||
|       delete[] out_pixels; | ||||
|       delete image; | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     delete image; | ||||
|     return new SimpleImage(width, height, target_format, out_pixels); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   namespace hidden { | ||||
|  | ||||
|     COR_EXPORT(Image*) CorConvertImage( | ||||
|       Image* image, | ||||
|       PixelFormat target_format) | ||||
|     { | ||||
|       COR_GUARD("CorConvertImage"); | ||||
|  | ||||
|       // if we don't have an image, user doesn't care about format, or | ||||
|       // the formats match, don't do any conversion. | ||||
|       if (!image || | ||||
|           target_format == PF_DONTCARE || | ||||
|           target_format == image->getFormat()) | ||||
|       { | ||||
|         return image; | ||||
|       } | ||||
|  | ||||
|       COR_LOG("Doing the conversion..."); | ||||
|  | ||||
|       // if we have a palettized image, convert it to a direct color | ||||
|       // image and then convert that | ||||
|       if (IsPalettized(image->getFormat())) { | ||||
|         image = ExpandPalette(image); | ||||
|       } | ||||
|  | ||||
|       return DirectConversion(image, target_format); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     COR_EXPORT(Image*) CorConvertPalette( | ||||
|       Image* image, | ||||
|       PixelFormat palette_format) | ||||
|     { | ||||
|       // do we need to convert? | ||||
|       if (!image || | ||||
|           palette_format == PF_DONTCARE || | ||||
|           image->getPaletteFormat() == palette_format) | ||||
|       { | ||||
|         return image; | ||||
|       } | ||||
|  | ||||
|       // do we have invalid data? | ||||
|       if (!IsPalettized(image->getFormat()) || | ||||
|           !IsDirect(palette_format)) | ||||
|       { | ||||
|         delete image; | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       const int width  = image->getWidth(); | ||||
|       const int height = image->getHeight(); | ||||
|       const PixelFormat format = image->getFormat(); | ||||
|       const int palette_size = image->getPaletteSize(); | ||||
|  | ||||
|       // the palette indices don't change, so just make a copy | ||||
|       const int image_size = width * height * GetPixelSize(format); | ||||
|       byte* pixels = new byte[image_size]; | ||||
|       memcpy(pixels, image->getPixels(), image_size); | ||||
|  | ||||
|       byte* new_palette = new byte[ | ||||
|         palette_size * GetPixelSize(palette_format)]; | ||||
|  | ||||
|       if (!ConvertPixels(new_palette, palette_format, | ||||
|                          (byte*)image->getPalette(), image->getPaletteFormat(), | ||||
|                          palette_size)) | ||||
|       { | ||||
|         delete image; | ||||
|         delete[] pixels; | ||||
|         delete[] new_palette; | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       delete image; | ||||
|       return new SimpleImage( | ||||
|         width, height, format, pixels, | ||||
|         new_palette, palette_size, palette_format); | ||||
|     } | ||||
|  | ||||
|     COR_EXPORT(Image*) CorFlipImage( | ||||
|       Image* image, | ||||
|       int coordinate_axis) | ||||
|     { | ||||
|       COR_GUARD("CorFlipImage"); | ||||
|  | ||||
|       // if we don't have an image, don't flip. | ||||
|       if (!image) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       COR_LOG("Doing the flip..."); | ||||
|  | ||||
|       const int width                = image->getWidth(); | ||||
|       const int height               = image->getHeight(); | ||||
|       byte* pixels                   = (byte*)image->getPixels(); | ||||
|       const PixelFormat pixel_format = image->getFormat(); | ||||
|       const int pixel_size           = GetPixelSize(pixel_format); | ||||
|  | ||||
|       // flip about the X axis | ||||
|       if (coordinate_axis & CA_X) { | ||||
|  | ||||
|         byte* row = new byte[width * pixel_size]; | ||||
|         for (int h = 0; h < height / 2; ++h) { | ||||
|           byte* top = pixels + h                * width * pixel_size; | ||||
|           byte* bot = pixels + (height - h - 1) * width * pixel_size; | ||||
|           memcpy(row, top, width * pixel_size); | ||||
|           memcpy(top, bot, width * pixel_size); | ||||
|           memcpy(bot, row, width * pixel_size); | ||||
|         } | ||||
|         delete[] row; | ||||
|  | ||||
|       } | ||||
|  | ||||
|       // flip about the Y axis | ||||
|       if (coordinate_axis & CA_Y) { | ||||
|  | ||||
|         for (int h = 0; h < height; ++h) { | ||||
|           byte* row = pixels + h * width * pixel_size; | ||||
|           for (int w = 0; w < width / 2; ++w) { | ||||
|             byte* left  = row + w               * pixel_size; | ||||
|             byte* right = row + (width - w - 1) * pixel_size; | ||||
|             for (int b = 0; b < pixel_size; ++b) { | ||||
|               std::swap(left[b], right[b]); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } | ||||
|  | ||||
|       return image; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										321
									
								
								corona/src/Corona.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								corona/src/Corona.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include "corona.h" | ||||
| #include "MemoryFile.h" | ||||
| #include "Open.h" | ||||
| #include "Save.h" | ||||
| #include "SimpleImage.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|   namespace hidden { | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(const char*) CorGetVersion() { | ||||
|       return "1.0.2"; | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     class FFDImpl : public FileFormatDesc { | ||||
|     public: | ||||
|       FFDImpl(FileFormat format, const char* description, const char* exts) { | ||||
|         m_format = format; | ||||
|         m_description = description; | ||||
|  | ||||
|         const char* ext = exts; | ||||
|         while (*ext) { | ||||
|           m_extensions.push_back(ext); | ||||
|           ext += strlen(ext) + 1; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       FileFormat getFormat()             { return m_format;                } | ||||
|       const char* getDescription()       { return m_description.c_str();   } | ||||
|       size_t getExtensionCount()         { return m_extensions.size();     } | ||||
|       const char* getExtension(size_t i) { return m_extensions[i].c_str(); } | ||||
|  | ||||
|     private: | ||||
|       FileFormat m_format; | ||||
|       std::string m_description; | ||||
|       std::vector<std::string> m_extensions; | ||||
|     }; | ||||
|  | ||||
|     FFDImpl ffPNG (FF_PNG,  "PNG Files",  "png\0"); | ||||
|     FFDImpl ffJPEG(FF_JPEG, "JPEG Files", "jpeg\0jpg\0"); | ||||
|     FFDImpl ffPCX (FF_PCX,  "PCX Files",  "pcx\0"); | ||||
|     FFDImpl ffBMP (FF_BMP,  "BMP Files",  "bmp\0"); | ||||
|     FFDImpl ffTGA (FF_TGA,  "TGA Files",  "tga\0"); | ||||
|     FFDImpl ffGIF (FF_GIF,  "GIF Files",  "gif\0"); | ||||
|  | ||||
|     const int MAX_FORMAT_COUNT = 64; | ||||
|     FileFormatDesc** g_read_formats  = 0; | ||||
|     FileFormatDesc** g_write_formats = 0; | ||||
|     FileFormatDesc* g_read_array[MAX_FORMAT_COUNT + 1]  = {0}; | ||||
|     FileFormatDesc* g_write_array[MAX_FORMAT_COUNT + 1] = {0}; | ||||
|  | ||||
|  | ||||
|     COR_EXPORT(FileFormatDesc**) CorGetSupportedReadFormats() { | ||||
|       if (!g_read_formats) { | ||||
|         g_read_formats = g_read_array; | ||||
|         FileFormatDesc** f = g_read_formats; | ||||
|         *f++ = &ffPNG; | ||||
|         *f++ = &ffPCX; | ||||
|         *f++ = &ffBMP; | ||||
|         *f++ = &ffTGA; | ||||
|       } | ||||
|       return g_read_formats; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     COR_EXPORT(FileFormatDesc**) CorGetSupportedWriteFormats() { | ||||
|       if (!g_write_formats) { | ||||
|         g_write_formats = g_write_array; | ||||
|         FileFormatDesc** f = g_write_formats; | ||||
| 		*f++ = &ffPNG; | ||||
|         *f++ = &ffTGA; | ||||
|       } | ||||
|       return g_write_formats; | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorCreateImage( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format) | ||||
|     { | ||||
|       return CreateImage(width, height, format, 0); | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorCreateImageWithPixels( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format, | ||||
|       void* pixels) | ||||
|     { | ||||
|       // this function only supports creation of non-palettized images | ||||
|       if (!IsDirect(format)) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       int size = width * height * GetPixelSize(format); | ||||
|       byte* p = new byte[size]; | ||||
|       if (pixels) { | ||||
|         memcpy(p, pixels, size); | ||||
|       } else { | ||||
|         memset(p, 0, size); | ||||
|       } | ||||
|       return new SimpleImage(width, height, format, p); | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorCreatePalettizedImage( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format, | ||||
|       int palette_size, | ||||
|       PixelFormat palette_format) | ||||
|     { | ||||
|       // only support creation of palettized images | ||||
|       if (!IsPalettized(format) || !IsDirect(palette_format)) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       // make sure the palette is the right size | ||||
|       if (palette_size != GetPaletteSize(format)) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       int size = width * height * GetPixelSize(format); | ||||
|       byte* pixels = new byte[size]; | ||||
|       memset(pixels, 0, size); | ||||
|  | ||||
|       int palette_bytes = palette_size * GetPixelSize(palette_format); | ||||
|       byte* palette = new byte[palette_bytes]; | ||||
|       memset(palette, 0, palette_bytes); | ||||
|  | ||||
|       return new SimpleImage(width, height, format, pixels, | ||||
|                              palette, palette_size, palette_format);       | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorCloneImage( | ||||
|       Image* source, | ||||
|       PixelFormat format) | ||||
|     { | ||||
|       if (!source) { | ||||
|         // we need an image to clone :) | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       const int width = source->getWidth(); | ||||
|       const int height = source->getHeight(); | ||||
|       const PixelFormat source_format = source->getFormat(); | ||||
|  | ||||
|       const int source_pixel_size = GetPixelSize(source_format); | ||||
|       if (source_pixel_size == 0) { | ||||
|         // unknown pixel size? | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       // duplicate the image | ||||
|       int image_size = width * height * source_pixel_size; | ||||
|       byte* pixels = new byte[image_size]; | ||||
|       memcpy(pixels, source->getPixels(), image_size); | ||||
|        | ||||
|       if (IsPalettized(source_format)) { | ||||
|         // clone palette | ||||
|         int palette_size = source->getPaletteSize(); | ||||
|         PixelFormat palette_format = source->getPaletteFormat(); | ||||
|         int palette_bytes = palette_size * GetPixelSize(palette_format); | ||||
|         byte* palette = new byte[palette_bytes]; | ||||
|         memcpy(palette, source->getPalette(), palette_bytes); | ||||
|         Image* image = new SimpleImage(width, height, source_format, pixels, | ||||
|                                        palette, palette_size, palette_format); | ||||
|         return ConvertImage(image, format); | ||||
|       } | ||||
|  | ||||
|       Image* image = new SimpleImage(width, height, source_format, pixels); | ||||
|       return ConvertImage(image, format); | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorOpenImage( | ||||
|       const char* filename, | ||||
|       FileFormat file_format) | ||||
|     { | ||||
|       if (!filename) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       std::auto_ptr<File> file(OpenFile(filename, false)); | ||||
|       return CorOpenImageFromFile(file.get(), file_format); | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(Image*) CorOpenImageFromFile( | ||||
|       File* file, | ||||
|       FileFormat file_format) | ||||
|     { | ||||
|       if (!file) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
| #define TRY_TYPE(type)                                 \ | ||||
|   {                                                    \ | ||||
|     Image* image = CorOpenImageFromFile(file, (type)); \ | ||||
|     if (image) { return image; }                       \ | ||||
|   } | ||||
|  | ||||
|       file->seek(0, File::BEGIN); | ||||
|       switch (file_format) { | ||||
|         case FF_AUTODETECT: { | ||||
|           TRY_TYPE(FF_PNG); | ||||
|           TRY_TYPE(FF_PCX); | ||||
|           TRY_TYPE(FF_BMP); | ||||
|           TRY_TYPE(FF_TGA); | ||||
|           return 0; | ||||
|         } | ||||
|          | ||||
|         case FF_PNG:  return OpenPNG(file); | ||||
|         case FF_PCX:  return OpenPCX(file); | ||||
|         case FF_BMP:  return OpenBMP(file); | ||||
|         case FF_TGA:  return OpenTGA(file); | ||||
|         default:      return 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     int strcmp_ci(const char* a, const char* b) { | ||||
|       while (*a && *b) { | ||||
|         const int diff = tolower(*a) - tolower(*b); | ||||
|         if (diff != 0) { | ||||
|           return diff; | ||||
|         } | ||||
|         ++a; | ||||
|         ++b; | ||||
|       } | ||||
|       return tolower(*a) - tolower(*b); | ||||
|     } | ||||
|  | ||||
|     bool ends_with(const char* str, const char* ext) { | ||||
|       const int str_len = strlen(str); | ||||
|       const int ext_len = strlen(ext); | ||||
|       return (str_len >= ext_len && | ||||
|               strcmp_ci(str + str_len - ext_len, ext) == 0); | ||||
|     } | ||||
|  | ||||
|     COR_EXPORT(bool) CorSaveImage( | ||||
|       const char* filename, | ||||
|       FileFormat file_format, | ||||
|       Image* image) | ||||
|     { | ||||
|       if (!filename) { | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       if (file_format == FF_AUTODETECT) { | ||||
|         if (ends_with(filename, ".png")) { | ||||
|           file_format = FF_PNG; | ||||
|         } else if (ends_with(filename, ".tga")) { | ||||
|           file_format = FF_TGA; | ||||
|         } else { | ||||
|           return false; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       std::auto_ptr<File> file(OpenFile(filename, true)); | ||||
|       return CorSaveImageToFile(file.get(), file_format, image); | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(bool) CorSaveImageToFile( | ||||
|       File* file, | ||||
|       FileFormat file_format, | ||||
|       Image* image) | ||||
|     { | ||||
|       if (!file || !image) { | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       switch (file_format) { | ||||
|         case FF_PNG:  return SavePNG(file, image); | ||||
|         case FF_JPEG: return false; | ||||
|         case FF_PCX:  return false; | ||||
|         case FF_BMP:  return false; | ||||
|         case FF_TGA:  return SaveTGA(file, image); | ||||
|         case FF_GIF:  return false; | ||||
|         default:      return false; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     COR_EXPORT(int) CorGetPixelSize(PixelFormat format) { | ||||
|       switch (format) { | ||||
|         case PF_R8G8B8A8: return 4; | ||||
|         case PF_R8G8B8:   return 3; | ||||
|         case PF_B8G8R8A8: return 4; | ||||
|         case PF_B8G8R8:   return 3; | ||||
|         case PF_I8:       return 1; | ||||
|         default:          return 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   } | ||||
| } | ||||
							
								
								
									
										52
									
								
								corona/src/Debug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								corona/src/Debug.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #include "Debug.h" | ||||
|  | ||||
| #ifdef CORONA_DEBUG | ||||
|  | ||||
|  | ||||
| FILE* Log::handle; | ||||
| int Log::indent_count; | ||||
|  | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| void | ||||
| Log::Write(const char* str) | ||||
| { | ||||
|   EnsureOpen(); | ||||
|   if (handle) { | ||||
|     std::string s(std::string(indent_count * 2, ' ') + str + "\n"); | ||||
|     fputs(s.c_str(), handle); | ||||
|     fflush(handle); | ||||
|   } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| void | ||||
| Log::EnsureOpen() | ||||
| { | ||||
|   if (!handle) { | ||||
| #ifdef WIN32 | ||||
|     handle = 0; //fopen("C:/corona_debug.log", "w"); | ||||
| #else | ||||
|     //std::string home(getenv("HOME")); | ||||
| 	handle = 0; //fopen((home + "/corona_debug.log").c_str(), "w"); | ||||
| #endif | ||||
|     atexit(Close); | ||||
|   } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| void | ||||
| Log::Close() | ||||
| { | ||||
|   if (handle) { | ||||
| 	  fclose(handle); | ||||
|   } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										70
									
								
								corona/src/Debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								corona/src/Debug.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #ifndef DEBUG_HPP | ||||
| #define DEBUG_HPP | ||||
|  | ||||
|  | ||||
| #ifdef _DEBUG | ||||
| # ifndef CORONA_DEBUG | ||||
| #  define CORONA_DEBUG | ||||
| # endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef CORONA_DEBUG | ||||
|  | ||||
|   #include <stdio.h> | ||||
|   #include <string> | ||||
|  | ||||
|   class Log { | ||||
|   public: | ||||
|     static void Write(const char* str); | ||||
|     static void IncrementIndent() { ++indent_count; } | ||||
|     static void DecrementIndent() { --indent_count; } | ||||
|  | ||||
|   private: | ||||
|     static void EnsureOpen(); | ||||
|     static void Close(); | ||||
|  | ||||
|   private: | ||||
|     static FILE* handle; | ||||
|     static int indent_count; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   class Guard { | ||||
|   public: | ||||
|     Guard(const char* label) | ||||
|     : m_label(label) { | ||||
|       Write("+"); | ||||
|       Log::IncrementIndent(); | ||||
|     } | ||||
|  | ||||
|     ~Guard() { | ||||
|       Log::DecrementIndent(); | ||||
|       Write("-"); | ||||
|     } | ||||
|  | ||||
|     void Write(const char* prefix) { | ||||
|       Log::Write((prefix + m_label).c_str()); | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|     std::string m_label; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   #define COR_GUARD(label) Guard guard_obj__(label) | ||||
|   #define COR_LOG(label)   (Log::Write(label)) | ||||
|   #define COR_IF_DEBUG     if (true) | ||||
|   #define COR_ASSERT(condition, label) if (!(condition)) { __asm int 3 } | ||||
|  | ||||
| #else | ||||
|  | ||||
|   #define COR_GUARD(label)  | ||||
|   #define COR_LOG(label) | ||||
|   #define COR_IF_DEBUG     if (false) | ||||
|   #define COR_ASSERT(condition, label) | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										55
									
								
								corona/src/DefaultFileSystem.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								corona/src/DefaultFileSystem.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| //#include <stdio.h> | ||||
| #include <physfs.h> | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   class CFile : public DLLImplementation<File> { | ||||
|   public: | ||||
|     CFile(PHYSFS_File* file) { | ||||
|       m_file = file; | ||||
|     } | ||||
|  | ||||
|     ~CFile() { | ||||
|       PHYSFS_close(m_file); | ||||
|     } | ||||
|  | ||||
|     int COR_CALL read(void* buffer, int size) { | ||||
|       return (int)PHYSFS_read(m_file, buffer, 1, size ); | ||||
|     } | ||||
|  | ||||
|     int COR_CALL write(const void* buffer, int size) { | ||||
|       return (int)PHYSFS_write(m_file, buffer, 1, size ); | ||||
|     } | ||||
|  | ||||
|     bool COR_CALL seek(int position, SeekMode mode) { | ||||
|       PHYSFS_uint64 pos; | ||||
|       switch (mode) { | ||||
|         case BEGIN:   pos = position; break; | ||||
|         case CURRENT: pos = PHYSFS_tell(m_file) + position; break; | ||||
|         case END:     pos = PHYSFS_fileLength( m_file ) + position; break; | ||||
|         default: return false; | ||||
|       } | ||||
|       return PHYSFS_seek(m_file, pos) != 0; | ||||
|     } | ||||
|  | ||||
|     int COR_CALL tell() { | ||||
|       return (int)PHYSFS_tell(m_file); | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|     PHYSFS_File* m_file; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   COR_EXPORT(File*) CorOpenFile(const char* filename, bool writeable) { | ||||
|   	PHYSFS_File* file; | ||||
|   	if( writeable ) | ||||
|     	file = PHYSFS_openWrite(filename); | ||||
|     else | ||||
|     	file = PHYSFS_openRead(filename); | ||||
|     return (file ? new CFile(file) : 0); | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										93
									
								
								corona/src/MemoryFile.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								corona/src/MemoryFile.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| #include <string.h> | ||||
| #include "MemoryFile.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   COR_EXPORT(File*) CorCreateMemoryFile(const void* buffer, int size) { | ||||
|     if (size && !buffer) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (size < 0) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     return new MemoryFile(buffer, size); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   int getNextPowerOfTwo(int value) { | ||||
|     int i = 1; | ||||
|     while (i < value) { | ||||
|       i *= 2; | ||||
|     } | ||||
|     return i; | ||||
|   } | ||||
|  | ||||
|   MemoryFile::MemoryFile(const void* buffer, int size) { | ||||
|     m_capacity = getNextPowerOfTwo(size); | ||||
|     m_size = size; | ||||
|     m_buffer = new byte[m_capacity]; | ||||
|     memcpy(m_buffer, buffer, size); | ||||
|  | ||||
|     m_position = 0; | ||||
|   } | ||||
|  | ||||
|   MemoryFile::~MemoryFile() { | ||||
|     delete[] m_buffer; | ||||
|   } | ||||
|  | ||||
|   int COR_CALL MemoryFile::read(void* buffer, int size) { | ||||
|     int real_read = std::min((m_size - m_position), size); | ||||
|     memcpy(buffer, m_buffer + m_position, real_read); | ||||
|     m_position += real_read; | ||||
|     return real_read; | ||||
|   } | ||||
|  | ||||
|   int COR_CALL MemoryFile::write(const void* buffer, int size) { | ||||
|     ensureSize(m_position + size); | ||||
|     memcpy(m_buffer + m_position, buffer, size); | ||||
|     m_position += size; | ||||
|     return size; | ||||
|   } | ||||
|  | ||||
|   bool COR_CALL MemoryFile::seek(int position, SeekMode mode) { | ||||
|     int real_pos; | ||||
|     switch (mode) { | ||||
|       case BEGIN:   real_pos = position;              break; | ||||
|       case CURRENT: real_pos = m_position + position; break; | ||||
|       case END:     real_pos = m_size + position;     break; | ||||
|       default:      return false; | ||||
|     } | ||||
|  | ||||
|     if (real_pos < 0 || real_pos > m_size) { | ||||
|       m_position = 0; | ||||
|       return false; | ||||
|     } else { | ||||
|       m_position = real_pos; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int COR_CALL MemoryFile::tell() { | ||||
|     return m_position; | ||||
|   } | ||||
|  | ||||
|   void MemoryFile::ensureSize(int min_size) { | ||||
|     bool realloc_needed = false; | ||||
|     while (m_capacity < min_size) { | ||||
|       m_capacity *= 2; | ||||
|       realloc_needed = true; | ||||
|     } | ||||
|  | ||||
|     if (realloc_needed) { | ||||
|       byte* new_buffer = new byte[m_capacity]; | ||||
|       memcpy(new_buffer, m_buffer, m_size); | ||||
|       delete[] m_buffer; | ||||
|       m_buffer = new_buffer; | ||||
|     } | ||||
|  | ||||
|     m_size = min_size; | ||||
|   } | ||||
|  | ||||
| }; | ||||
							
								
								
									
										36
									
								
								corona/src/MemoryFile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								corona/src/MemoryFile.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #ifndef MEMORY_FILE_H | ||||
| #define MEMORY_FILE_H | ||||
|  | ||||
|  | ||||
| #include "corona.h" | ||||
| #include "Types.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   class MemoryFile : public DLLImplementation<File> { | ||||
|   public: | ||||
|     MemoryFile(const void* buffer, int size); | ||||
|     ~MemoryFile(); | ||||
|  | ||||
|     int  COR_CALL read(void* buffer, int size); | ||||
|     int  COR_CALL write(const void* buffer, int size); | ||||
|     bool COR_CALL seek(int position, SeekMode mode); | ||||
|     int  COR_CALL tell(); | ||||
|  | ||||
|   private: | ||||
|     void ensureSize(int min_size); | ||||
|  | ||||
|     byte* m_buffer; | ||||
|     int m_position; | ||||
|     int m_size; | ||||
|  | ||||
|     /// The actual size of m_buffer.  Always a power of two. | ||||
|     int m_capacity; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										16
									
								
								corona/src/Open.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								corona/src/Open.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #ifndef CORONA_OPEN_H | ||||
| #define CORONA_OPEN_H | ||||
|  | ||||
|  | ||||
| #include "corona.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|   Image* OpenBMP (File* file); // OpenBMP.cpp | ||||
|   Image* OpenPCX (File* file); // OpenPCX.cpp | ||||
|   Image* OpenPNG (File* file); // OpenPNG.cpp | ||||
|   Image* OpenTGA (File* file); // OpenTGA.cpp | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										678
									
								
								corona/src/OpenBMP.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										678
									
								
								corona/src/OpenBMP.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,678 @@ | ||||
| // format information gleaned from | ||||
| //   http://www.daubnet.com/formats/BMP.html | ||||
| // and | ||||
| //   http://www.edm2.com/0107/os2bmp.html | ||||
| // | ||||
| // If you have Visual Studio.NET: | ||||
| //   ms-help://MS.VSCC/MS.MSDNVS/gdi/bitmaps_7c36.htm | ||||
|  | ||||
| #include <string.h> | ||||
| #include "corona.h" | ||||
| #include "SimpleImage.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   struct Header { | ||||
|     bool os2; | ||||
|  | ||||
|     int file_size; | ||||
|     int data_offset; | ||||
|     int width; | ||||
|     int height; | ||||
|     int bpp; | ||||
|     int compression; | ||||
|  | ||||
|     int pitch;  // number of bytes in each scanline | ||||
|     int image_size; | ||||
|  | ||||
|     auto_array<BGR> palette; | ||||
|     int palette_size; | ||||
|  | ||||
|     // for bitfield specification... | ||||
|     //                               /*- 16-bit only -*/ | ||||
|     u32 bf_red_mask,   bf_red_shift,   bf_red_rshift; | ||||
|     u32 bf_green_mask, bf_green_shift, bf_green_rshift; | ||||
|     u32 bf_blue_mask,  bf_blue_shift,  bf_blue_rshift; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   bool   ReadHeader(File* file, Header& h); | ||||
|   bool   ReadInfoHeader(File* file, Header& h); | ||||
|   bool   ReadPalette(File* file, Header& h); | ||||
|   Image* DecodeBitmap(File* file, const Header& h); | ||||
|  | ||||
|    | ||||
|   Image* OpenBMP(File* file) { | ||||
|     Header h; | ||||
|     if (ReadHeader(file, h) && | ||||
|         ReadInfoHeader(file, h) && | ||||
|         ReadPalette(file, h)) { | ||||
|  | ||||
|       return DecodeBitmap(file, h); | ||||
|  | ||||
|     } else { | ||||
|  | ||||
|       return 0; | ||||
|  | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   bool ReadHeader(File* file, Header& h) { | ||||
|     byte header[14]; | ||||
|     if (file->read(header, 14) != 14) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // check signature | ||||
|     if (header[0] != 'B' || header[1] != 'M') { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     h.file_size   = read32_le(header + 2); | ||||
|     h.data_offset = read32_le(header + 10); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   bool ReadInfoHeader(File* file, Header& h) { | ||||
|  | ||||
|     const int HEADER_READ_SIZE = 24; | ||||
|  | ||||
|     // read the only part of the header we need | ||||
|     byte header[HEADER_READ_SIZE]; | ||||
|     if (file->read(header, HEADER_READ_SIZE) != HEADER_READ_SIZE) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     int size = read32_le(header + 0); | ||||
|     int width; | ||||
|     int height; | ||||
|     int planes; | ||||
|     int bpp; | ||||
|     int compression; | ||||
|     int image_size; | ||||
|  | ||||
|     if (size < 40) {  // assume OS/2 bitmap | ||||
|       if (size < 12) { | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       h.os2 = true; | ||||
|       width  = read16_le(header + 4); | ||||
|       height = read16_le(header + 6); | ||||
|       planes = read16_le(header + 8); | ||||
|       bpp    = read16_le(header + 10); | ||||
|       compression = 0; | ||||
|       image_size = 0; | ||||
|        | ||||
|     } else { | ||||
|  | ||||
|       h.os2 = false; | ||||
|       width       = read32_le(header + 4); | ||||
|       height      = read32_le(header + 8); | ||||
|       planes      = read16_le(header + 12); | ||||
|       bpp         = read16_le(header + 14); | ||||
|       compression = read32_le(header + 16); | ||||
|       image_size  = read32_le(header + 20); | ||||
|  | ||||
|     } | ||||
|      | ||||
|     // sanity check the info header | ||||
|     if (planes != 1) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // adjust image_size | ||||
|     // (if compression == 0 or 3, manually calculate image size) | ||||
|     int line_size = 0; | ||||
|     if (compression == 0 || compression == 3) { | ||||
|       line_size = (width * bpp + 7) / 8; | ||||
|       line_size = (line_size + 3) / 4 * 4;  // 32-bit-aligned | ||||
|       image_size = line_size * height; | ||||
|     } | ||||
|  | ||||
|     h.width       = width; | ||||
|     h.height      = height; | ||||
|     h.bpp         = bpp; | ||||
|     h.compression = compression; | ||||
|     h.pitch       = line_size; | ||||
|     h.image_size  = image_size; | ||||
|  | ||||
|     // jump forward (backward in the OS/2 case :) to the palette data | ||||
|     file->seek(size - HEADER_READ_SIZE, File::CURRENT); | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // count the number of consecutive zeroes on the right side of a | ||||
|   // binary number | ||||
|   // 0x00F0 will return 4 | ||||
|   int count_right_zeroes(u32 n) { | ||||
|     int total = 0; | ||||
|     u32 c = 1; | ||||
|     while ((total < 32) && ((n & c) == 0)) { | ||||
|       c <<= 1; | ||||
|       ++total; | ||||
|     } | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|   // count the number of ones in a binary number | ||||
|   // 0x00F1 will return 5 | ||||
|   int count_ones(u32 n) { | ||||
|     int total = 0; | ||||
|     u32 c = 1; | ||||
|     for (int i = 0; i < 32; ++i) { | ||||
|       if (n & c) { | ||||
|         ++total; | ||||
|       } | ||||
|       c <<= 1; | ||||
|     } | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|   bool ReadPalette(File* file, Header& h) { | ||||
|  | ||||
|     // initialize bit masks/shifts...  just in case | ||||
|     h.bf_red_mask   = h.bf_red_shift   = h.bf_red_rshift   = 0; | ||||
|     h.bf_green_mask = h.bf_green_shift = h.bf_green_rshift = 0; | ||||
|     h.bf_blue_mask  = h.bf_blue_shift  = h.bf_blue_rshift  = 0; | ||||
|  | ||||
|     // if we're not a palettized image, don't even read a palette | ||||
|     if (h.bpp > 8) { | ||||
|       h.palette_size = 0; | ||||
|  | ||||
|       // do we have bitfields? | ||||
|       if (h.compression == 3) { | ||||
|  | ||||
|         auto_array<byte> bitfields(new byte[12]); | ||||
|         if (file->read(bitfields, 12) != 12) { | ||||
|           return false; | ||||
|         } | ||||
|  | ||||
|         h.bf_red_mask   = read32_le((byte*)bitfields); | ||||
|         h.bf_green_mask = read32_le((byte*)bitfields + 4); | ||||
|         h.bf_blue_mask  = read32_le((byte*)bitfields + 8); | ||||
|  | ||||
|         // calculate shifts | ||||
|         h.bf_red_shift    = count_right_zeroes(h.bf_red_mask); | ||||
|         h.bf_green_shift  = count_right_zeroes(h.bf_green_mask); | ||||
|         h.bf_blue_shift   = count_right_zeroes(h.bf_blue_mask); | ||||
|         h.bf_red_rshift   = 8 - count_ones(h.bf_red_mask); | ||||
|         h.bf_green_rshift = 8 - count_ones(h.bf_green_mask); | ||||
|         h.bf_blue_rshift  = 8 - count_ones(h.bf_blue_mask); | ||||
|  | ||||
|       // otherwise, set default bitfield entries | ||||
|       } else { | ||||
|  | ||||
|         if (h.bpp == 16) { | ||||
|  | ||||
|           h.bf_red_mask     = 0x7C00; | ||||
|           h.bf_red_shift    = 10; | ||||
|           h.bf_red_rshift   = 3; | ||||
|  | ||||
|           h.bf_green_mask   = 0x03E0; | ||||
|           h.bf_green_shift  = 5; | ||||
|           h.bf_green_rshift = 3; | ||||
|  | ||||
|           h.bf_blue_mask    = 0x001F; | ||||
|           h.bf_blue_shift   = 0; | ||||
|           h.bf_blue_rshift  = 3; | ||||
|  | ||||
|         } else if (h.bpp == 32) { | ||||
|  | ||||
|           // these don't need any rshift | ||||
|           h.bf_red_mask   = 0x00FF0000; h.bf_red_shift   = 16; | ||||
|           h.bf_green_mask = 0x0000FF00; h.bf_green_shift = 8; | ||||
|           h.bf_blue_mask  = 0x000000FF; h.bf_blue_shift  = 0; | ||||
|  | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     if (h.bpp <= 8) { | ||||
|       h.palette_size = 1 << h.bpp; | ||||
|     } else { | ||||
|       h.palette_size = 0; | ||||
|       return true; | ||||
|     } | ||||
|     h.palette = new BGR[h.palette_size]; | ||||
|  | ||||
|     // read the BMP color table | ||||
|     const int buffer_size = h.palette_size * (h.os2 ? 3 : 4); | ||||
|     auto_array<byte> buffer(new byte[buffer_size]); | ||||
|     if (file->read(buffer, buffer_size) != buffer_size) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     byte* in = buffer; | ||||
|     BGR* out = h.palette; | ||||
|     for (int i = 0; i < h.palette_size; ++i) { | ||||
|       out->blue  = *in++; | ||||
|       out->green = *in++; | ||||
|       out->red   = *in++; | ||||
|       if (!h.os2) { | ||||
|         ++in;  // skip alpha | ||||
|       } | ||||
|       ++out; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   bool advance(int& x, int& y, const Header& h) { | ||||
|     if (++x >= h.width) { | ||||
|       x = 0; | ||||
|       if (++y >= h.height) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmap1(const byte* raster_data, const Header& h) { | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height]); | ||||
|      | ||||
|     auto_array<BGR> palette(new BGR[256]); | ||||
|     memset(palette, 0, 256 * sizeof(BGR)); | ||||
|     memcpy(palette, h.palette, h.palette_size * sizeof(BGR)); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       byte* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       int mask = 128; | ||||
|       for (int j = 0; j < h.width; ++j) { | ||||
|         *out++ = (*in & mask) > 0; | ||||
|  | ||||
|         mask >>= 1; | ||||
|         if (mask == 0) { | ||||
|           ++in; | ||||
|           mask = 128; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_I8, pixels.release(), | ||||
|                            (byte*)palette.release(), 256, PF_B8G8R8); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmap4(const byte* raster_data, const Header& h) { | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height]); | ||||
|      | ||||
|     auto_array<BGR> palette(new BGR[256]); | ||||
|     memset(palette, 0, 256 * sizeof(BGR)); | ||||
|     memcpy(palette, h.palette, h.palette_size * sizeof(BGR)); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       byte* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       for (int j = 0; j < h.width / 2; ++j) { | ||||
|         *out++ = (*in >> 4); | ||||
|         *out++ = (*in & 0x0F); | ||||
|  | ||||
|         ++in; | ||||
|       } | ||||
|  | ||||
|       if (h.width % 2) { | ||||
|         *out++ = (*in >> 4); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_I8, pixels.release(), | ||||
|                            (byte*)palette.release(), 256, PF_B8G8R8); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmapRLE4(const byte* raster_data, const Header& h) { | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height]); | ||||
|      | ||||
|     auto_array<BGR> palette(new BGR[256]); | ||||
|     memset(palette, 0, 256 * sizeof(BGR)); | ||||
|     memcpy(palette, h.palette, h.palette_size * sizeof(BGR)); | ||||
|  | ||||
|     // by default, we have an empty bitmap | ||||
|     memset(pixels, 0, h.width * h.height); | ||||
|  | ||||
|     // we read the image from the bottom down, and then flip it when | ||||
|     // we're done | ||||
|     int x = 0; | ||||
|     int y = 0; | ||||
|  | ||||
|     const byte* in = raster_data; | ||||
|     while (in - raster_data < h.image_size - 1) { | ||||
|       byte n = *in++; | ||||
|       byte c = *in++; | ||||
|  | ||||
|       if (n == 0) {  // escape code | ||||
|  | ||||
|         if (c == 0) {         // end of line | ||||
|           x = 0; | ||||
|  | ||||
|           //++y;  // XXXaegis uhhh...  uhhh...  :)  it works this way... | ||||
|  | ||||
|           if (y >= h.height) { | ||||
|             // did we go too far? | ||||
|             break; | ||||
|           } | ||||
|         } else if (c == 1) {  // end of bitmap | ||||
|           break; | ||||
|         } else if (c == 2) {  // delta | ||||
|  | ||||
|           // do we have enough space? | ||||
|           if (in - raster_data >= h.image_size - 1) { | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|           // I have no idea how I'm supposed to do this... | ||||
|           // Let's take a guess! | ||||
|           int dx = *in++; | ||||
|           int dy = *in++; | ||||
|           x = (x + dx) % h.width; | ||||
|           y += dy + (x + dx) / h.width; | ||||
|           if (y >= h.height) { | ||||
|             // if we went too far, stop now | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|         } else {              // read uncompressed | ||||
|  | ||||
|           // the input raster data is padded on DWORD boundaries | ||||
|           // c == num_pixels | ||||
|           int num_bytes = (c + 3) / 4 * 2; | ||||
|            | ||||
|           // make sure we have enough space | ||||
|           if (in - raster_data > h.image_size - num_bytes) { | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|           // nasty decoding loop... | ||||
|           int i = 0; | ||||
|           int j = 0; | ||||
|           while (true) { | ||||
|             byte l = (in[j] & 0xF0) >> 4; | ||||
|             byte r = (in[j] & 0x0F); | ||||
|             ++j; | ||||
|  | ||||
|             pixels[y * h.width + x] = l; | ||||
|             if (!advance(x, y, h) || ++i >= c) { | ||||
|               break; | ||||
|             } | ||||
|  | ||||
|             pixels[y * h.width + x] = r; | ||||
|             if (!advance(x, y, h) || ++i >= c) { | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
|           // make SURE we move forward the right number of bytes | ||||
|           in += num_bytes; | ||||
|         } | ||||
|  | ||||
|       } else { | ||||
|  | ||||
|         // a less nasty decoding loop... | ||||
|         byte lc = (c & 0xF0) >> 4; | ||||
|         byte rc = c & 0x0F; | ||||
|  | ||||
|         int i = 0; | ||||
|         while (true) { | ||||
|           pixels[y * h.width + x] = lc; | ||||
|           if (!advance(x, y, h) || ++i >= n) { | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|           pixels[y * h.width + x] = rc; | ||||
|           if (!advance(x, y, h) || ++i >= n) { | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } // end if | ||||
|     } // end while | ||||
|  | ||||
|     // flippy flippy! | ||||
|     int pitch = h.width; | ||||
|     auto_array<byte> row(new byte[pitch]); | ||||
|     for (int i = 0; i < h.height / 2; ++i) { | ||||
|       int j = h.height - i - 1; | ||||
|       memcpy((byte*)row,         pixels + i * pitch, pitch); | ||||
|       memcpy(pixels + i * pitch, pixels + j * pitch, pitch); | ||||
|       memcpy(pixels + j * pitch, (byte*)row,         pitch); | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_I8, pixels.release(), | ||||
|                            (byte*)palette.release(), 256, PF_B8G8R8); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmap8(const byte* raster_data, const Header& h) { | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height]); | ||||
|      | ||||
|     auto_array<BGR> palette(new BGR[256]); | ||||
|     memset(palette, 0, 256 * sizeof(BGR)); | ||||
|     memcpy(palette, h.palette, h.palette_size * sizeof(BGR)); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       byte* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       for (int j = 0; j < h.width; ++j) { | ||||
|         *out++ = *in++; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_I8, pixels.release(), | ||||
|                            (byte*)palette.release(), 256, PF_B8G8R8); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmapRLE8(const byte* raster_data, const Header& h) { | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height]); | ||||
|      | ||||
|     auto_array<BGR> palette(new BGR[256]); | ||||
|     memset(palette, 0, 256 * sizeof(BGR)); | ||||
|     memcpy(palette, h.palette, h.palette_size * sizeof(BGR)); | ||||
|  | ||||
|     // by default, we have an empty bitmap | ||||
|     memset(pixels, 0, h.width * h.height); | ||||
|  | ||||
|     // we read the image from the bottom down, and then flip it when | ||||
|     // we're done | ||||
|     int x = 0; | ||||
|     int y = 0; | ||||
|  | ||||
|     const byte* in = raster_data; | ||||
|     while (in - raster_data < h.image_size - 1) { | ||||
|       byte n = *in++; | ||||
|       byte c = *in++; | ||||
|  | ||||
|       if (n == 0) {  // escape code | ||||
|  | ||||
|         if (c == 0) {         // end of line | ||||
|           x = 0; | ||||
|  | ||||
|           //++y;  // XXXaegis uhhh...  uhhh...  :)  it works this way... | ||||
|  | ||||
|           if (y >= h.height) { | ||||
|             // did we go too far? | ||||
|             break; | ||||
|           } | ||||
|         } else if (c == 1) {  // end of bitmap | ||||
|           break; | ||||
|         } else if (c == 2) {  // delta | ||||
|  | ||||
|           // do we have enough space? | ||||
|           if (in - raster_data >= h.image_size - 1) { | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|           // I have no idea how I'm supposed to do this... | ||||
|           // Let's take a guess! | ||||
|           int dx = *in++; | ||||
|           int dy = *in++; | ||||
|           x = (x + dx) % h.width; | ||||
|           y += dy + (x + dx) / h.width; | ||||
|           if (y >= h.height) { | ||||
|             // if we went too far, stop now | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|         } else {              // read uncompressed | ||||
|  | ||||
|           // c == num_pixels | ||||
|           int num_bytes = (c + 1) / 2 * 2; | ||||
|            | ||||
|           // make sure we have enough space | ||||
|           if (in - raster_data > h.image_size - num_bytes) { | ||||
|             break; | ||||
|           } | ||||
|  | ||||
|           // decoding loop... | ||||
|           int i = 0; | ||||
|           int j = 0; | ||||
|           while (true) { | ||||
|             pixels[y * h.width + x] = in[j++]; | ||||
|             if (!advance(x, y, h) || ++i >= c) { | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
|           // make SURE we move forward the right number of bytes | ||||
|           in += num_bytes; | ||||
|         } | ||||
|  | ||||
|       } else { | ||||
|  | ||||
|         int i = 0; | ||||
|         while (true) { | ||||
|           pixels[y * h.width + x] = c; | ||||
|           if (!advance(x, y, h) || ++i >= n) { | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } // end if | ||||
|     } // end while | ||||
|  | ||||
|     // flippy flippy! | ||||
|     int pitch = h.width; | ||||
|     auto_array<byte> row(new byte[pitch]); | ||||
|     for (int i = 0; i < h.height / 2; ++i) { | ||||
|       int j = h.height - i - 1; | ||||
|       memcpy((byte*)row,         pixels + i * pitch, pitch); | ||||
|       memcpy(pixels + i * pitch, pixels + j * pitch, pitch); | ||||
|       memcpy(pixels + j * pitch, (byte*)row,         pitch); | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_I8, pixels.release(), | ||||
|                            (byte*)palette.release(), 256, PF_B8G8R8); | ||||
|   } | ||||
|    | ||||
|   Image* ReadBitmap16(const byte* raster_data, const Header& h) { | ||||
|     auto_array<RGB> pixels(new RGB[h.width * h.height]); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       RGB* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       for (int j = 0; j < h.width; ++j) { | ||||
|         int clr = read16_le(in); | ||||
|         in += 2; | ||||
|  | ||||
| #define C16(C) \ | ||||
|   (byte)( ((clr & h.bf_##C##_mask) >> h.bf_##C##_shift) << h.bf_##C##_rshift); | ||||
|  | ||||
|         out->red   = C16(red); | ||||
|         out->green = C16(green); | ||||
|         out->blue  = C16(blue); | ||||
|         ++out; | ||||
|  | ||||
| #undef C16 | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_R8G8B8, | ||||
|                            (byte*)pixels.release()); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmap24(const byte* raster_data, const Header& h) { | ||||
|     auto_array<BGR> pixels(new BGR[h.width * h.height]); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       BGR* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       for (int j = 0; j < h.width; ++j) { | ||||
|         out->blue  = *in++; | ||||
|         out->green = *in++; | ||||
|         out->red   = *in++; | ||||
|         ++out; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_B8G8R8, | ||||
|                            (byte*)pixels.release()); | ||||
|   } | ||||
|  | ||||
|   Image* ReadBitmap32(const byte* raster_data, const Header& h) { | ||||
|     auto_array<RGB> pixels(new RGB[h.width * h.height]); | ||||
|  | ||||
|     for (int i = 0; i < h.height; ++i) { | ||||
|       const byte* in = raster_data + i * h.pitch; | ||||
|       RGB* out = pixels + (h.height - i - 1) * h.width; | ||||
|  | ||||
|       for (int j = 0; j < h.width; ++j) { | ||||
|         u32 pixel = read32_le(in); | ||||
|         in += 4; | ||||
|         out->red   = (byte)((pixel & h.bf_red_mask)   >> h.bf_red_shift); | ||||
|         out->green = (byte)((pixel & h.bf_green_mask) >> h.bf_green_shift); | ||||
|         out->blue  = (byte)((pixel & h.bf_blue_mask)  >> h.bf_blue_shift); | ||||
|         ++out; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(h.width, h.height, PF_R8G8B8, | ||||
|                            (byte*)pixels.release()); | ||||
|   } | ||||
|  | ||||
|   Image* DecodeBitmap(File* file, const Header& h) { | ||||
|  | ||||
|     if (!file->seek(h.data_offset, File::BEGIN)) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // the raster data stored in the file | ||||
|     auto_array<byte> raster_data(new byte[h.image_size]); | ||||
|     if (file->read(raster_data, h.image_size) != h.image_size) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // the output pixel buffer (parameter to new SimpleImage) | ||||
|     auto_array<byte> pixels(new byte[h.width * h.height * 3]); | ||||
|  | ||||
|     typedef Image* (*Decoder)(const byte* raster_data, const Header& h); | ||||
|  | ||||
|     Decoder decoder = 0; | ||||
|  | ||||
|     if      (h.bpp == 1  &&  h.compression == 0)  { decoder = ReadBitmap1;    } | ||||
|     else if (h.bpp == 4  &&  h.compression == 0)  { decoder = ReadBitmap4;    } | ||||
|     else if (h.bpp == 4  &&  h.compression == 2)  { decoder = ReadBitmapRLE4; } | ||||
|     else if (h.bpp == 8  &&  h.compression == 0)  { decoder = ReadBitmap8;    } | ||||
|     else if (h.bpp == 8  &&  h.compression == 1)  { decoder = ReadBitmapRLE8; } | ||||
|     else if (h.bpp == 16 && (h.compression == 0 || | ||||
|                              h.compression == 3)) { decoder = ReadBitmap16;   } | ||||
|     else if (h.bpp == 24 &&  h.compression == 0)  { decoder = ReadBitmap24;   } | ||||
|     else if (h.bpp == 32 && (h.compression == 0 || | ||||
|                              h.compression == 3)) { decoder = ReadBitmap32;   } | ||||
|  | ||||
|     if (decoder) { | ||||
|       return decoder(raster_data.get(), h); | ||||
|     } else { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										190
									
								
								corona/src/OpenPCX.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								corona/src/OpenPCX.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "Debug.h" | ||||
| #include "Open.h" | ||||
| #include "SimpleImage.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   /* | ||||
|   struct PCX_HEADER { | ||||
|     byte manufacturer; | ||||
|     byte version; | ||||
|     byte encoding; | ||||
|     byte bits_per_pixel; | ||||
|     word xmin; | ||||
|     word ymin; | ||||
|     word xmax; | ||||
|     word ymax; | ||||
|     word hdpi; | ||||
|     word vdpi; | ||||
|     byte colormap[48]; | ||||
|     byte reserved; | ||||
|     byte num_planes; | ||||
|     word bytes_per_line; | ||||
|     word palette_info; | ||||
|     word h_screen_size; | ||||
|     word v_screen_size; | ||||
|     byte filler[54]; | ||||
|   }; | ||||
|   */ | ||||
|  | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   bool ReadScanline(File* file, int scansize, byte* scanline) { | ||||
|     byte* out = scanline; | ||||
|     while (out - scanline < scansize) { | ||||
|  | ||||
|       // read a byte! | ||||
|       byte data; | ||||
|       if (file->read(&data, 1) != 1) { | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       if ((data & 0xC0) != 0xC0) {  // non RLE | ||||
|         *out++ = data; | ||||
|       } else {                      // RLE | ||||
|  | ||||
|         // read the repeated byte | ||||
|         int numbytes = data & 0x3F; | ||||
|         if (file->read(&data, 1) != 1) { | ||||
|           return false; | ||||
|         } | ||||
|  | ||||
|         while (numbytes-- && out - scanline < scansize) { | ||||
|           *out++ = data; | ||||
|         } | ||||
|  | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   Image* OpenPCX(File* file) { | ||||
|     COR_GUARD("OpenPCX"); | ||||
|  | ||||
|     // read the header block | ||||
|     byte pcx_header[128]; | ||||
|     int read = file->read(pcx_header, 128); | ||||
|     if (read != 128) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // parse the header... | ||||
|     //int manufacturer   = pcx_header[0]; | ||||
|     //int version        = pcx_header[1]; | ||||
|     int encoding       = pcx_header[2]; | ||||
|     int bpp            = pcx_header[3]; | ||||
|     int xmin           = read16_le(pcx_header + 4); | ||||
|     int ymin           = read16_le(pcx_header + 6); | ||||
|     int xmax           = read16_le(pcx_header + 8); | ||||
|     int ymax           = read16_le(pcx_header + 10); | ||||
|     int num_planes     = pcx_header[65]; | ||||
|     int bytes_per_line = read16_le(pcx_header + 66); | ||||
|  | ||||
|  | ||||
|     // verify the header | ||||
|  | ||||
|     // we only support RLE encoding | ||||
|     if (encoding != 1) { | ||||
|       COR_LOG("Unsupported encoding"); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     COR_IF_DEBUG { | ||||
|       char str[100]; | ||||
|       sprintf(str, "bits per pixel - %d", bpp); | ||||
|       COR_LOG(str); | ||||
|       sprintf(str, "bytes per line - %d", bytes_per_line); | ||||
|       COR_LOG(str); | ||||
|     } | ||||
|  | ||||
|     // we only support 8 bits per pixel | ||||
|     if (bpp != 8) { | ||||
|       COR_LOG("Unsupported bpp"); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // create the image structure | ||||
|     int width  = xmax - xmin + 1; | ||||
|     int height = ymax - ymin + 1; | ||||
|  | ||||
|     auto_array<byte> scanline(new byte[bytes_per_line]); | ||||
|     auto_array<byte> pixels(new byte[width * height * 3]); | ||||
|  | ||||
|     // decode the pixel data | ||||
|  | ||||
|     if (num_planes == 1) {               // 256 colors | ||||
|  | ||||
|       auto_array<RGB> palette(new RGB[256]); | ||||
|       auto_array<byte> image(new byte[width * height]); | ||||
|  | ||||
|       // read all of the scanlines | ||||
|       for (int iy = 0; iy < height; ++iy) { | ||||
|         if (!ReadScanline(file, bytes_per_line, scanline)) { | ||||
|           COR_LOG("Failure reading scanline"); | ||||
|           return 0; | ||||
|         } | ||||
|         memcpy((byte*)image + iy * width, scanline, width); | ||||
|       } | ||||
|  | ||||
|       // seek back from the end 769 bytes | ||||
|       if (!file->seek(-769, File::END)) { | ||||
|         COR_LOG("Failure seeking to palette"); | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       // do we have a palette? | ||||
|       byte has_palette; | ||||
|       if (file->read(&has_palette, 1) != 1 || has_palette != 12) { | ||||
|         COR_LOG("Failure testing for existence of palette"); | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       // read palette | ||||
|       if (file->read(palette, 3 * 256) != 3 * 256) { | ||||
|         COR_LOG("Failure reading palette"); | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       return new SimpleImage(width, height, PF_I8, image.release(), | ||||
|                              (byte*)palette.release(), 256, PF_R8G8B8); | ||||
|  | ||||
|     } else if (num_planes == 3) { // 24-bit color | ||||
|  | ||||
|       auto_array<byte> scanline(new byte[3 * bytes_per_line]); | ||||
|  | ||||
|       byte* out = pixels; | ||||
|       for (int iy = 0; iy < height; ++iy) { | ||||
|         if (!ReadScanline(file, 3 * bytes_per_line, scanline)) { | ||||
|           COR_LOG("Failure reading scanline"); | ||||
|           return 0; | ||||
|         } | ||||
|  | ||||
|         byte* r = scanline; | ||||
|         byte* g = scanline + bytes_per_line; | ||||
|         byte* b = scanline + bytes_per_line * 2; | ||||
|         for (int ix = 0; ix < width; ++ix) { | ||||
|           *out++ = *r++; | ||||
|           *out++ = *g++; | ||||
|           *out++ = *b++; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       return new SimpleImage(width, height, PF_R8G8B8, pixels.release()); | ||||
|  | ||||
|     } else { | ||||
|       COR_LOG("Unknown number of planes"); | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| } | ||||
							
								
								
									
										255
									
								
								corona/src/OpenPNG.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								corona/src/OpenPNG.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | ||||
| /** | ||||
|  *  @todo  use our own longjmp instead of libpng's.  this way we don't need | ||||
|  *         to use PNG_SETJMP_SUPPORTED in Windows, and don't depend on | ||||
|  *         png_ptr->jmpbuf in older versions of libpng. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #include <png.h> | ||||
| #include "Debug.h" | ||||
| #include "Open.h" | ||||
| #include "SimpleImage.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   typedef unsigned char byte; | ||||
|  | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   void PNG_read_function(png_structp png_ptr, | ||||
|                          png_bytep data, | ||||
|                          png_size_t length) { | ||||
|     File* file = (File*)png_get_io_ptr(png_ptr); | ||||
|     if (file->read(data, length) != int(length)) { | ||||
|       png_error(png_ptr, "Read error"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   void PNG_warning_function(png_structp png_ptr, png_const_charp error) { | ||||
|     // no warnings | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   void PNG_error_function(png_structp png_ptr, png_const_charp warning) { | ||||
|     // copied from libpng's pngerror.cpp, but without the fprintf | ||||
|     jmp_buf jmpbuf; | ||||
|     memcpy(jmpbuf, png_ptr->jmpbuf, sizeof(jmp_buf)); | ||||
|     longjmp(jmpbuf, 1); | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   void fill_palette(png_structp png, png_infop info, png_color palette[256]) { | ||||
|  | ||||
|    COR_GUARD("fill_palette"); | ||||
|  | ||||
|     // by default, the palette is greyscale | ||||
|     for (int i = 0; i < 256; ++i) { | ||||
|       palette[i].red   = i; | ||||
|       palette[i].green = i; | ||||
|       palette[i].blue  = i; | ||||
|     } | ||||
|  | ||||
|     // do we have a palette and is it big enough? | ||||
|     png_colorp png_palette; | ||||
|     int num_palette = 0; | ||||
|     png_get_PLTE(png, info, &png_palette, &num_palette); | ||||
|  | ||||
|     COR_IF_DEBUG { | ||||
|       char str[80]; | ||||
|       sprintf(str, "palette size: %d", num_palette); | ||||
|       COR_LOG(str); | ||||
|     } | ||||
|  | ||||
|     if (num_palette >= 256) { | ||||
|  | ||||
| #if 0 | ||||
|       COR_IF_DEBUG { | ||||
|         for (int i = 0; i < 256; ++i) { | ||||
|           char str[80]; | ||||
|           sprintf(str, "r(%d) g(%d) b(%d)", | ||||
|             int(palette[i].red), | ||||
|             int(palette[i].green), | ||||
|             int(palette[i].blue)); | ||||
|           COR_LOG(str); | ||||
|         } | ||||
|       } | ||||
| #endif | ||||
|  | ||||
|       memcpy(palette, png_palette, 256 * sizeof(png_color)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   Image* OpenPNG(File* file) { | ||||
|  | ||||
|     COR_GUARD("OpenPNG"); | ||||
|  | ||||
|     // verify PNG signature | ||||
|     byte sig[8]; | ||||
|     file->read(sig, 8); | ||||
|     if (png_sig_cmp(sig, 0, 8)) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     COR_LOG("Signature verified"); | ||||
|  | ||||
|     // read struct | ||||
|     png_structp png_ptr = png_create_read_struct( | ||||
|       PNG_LIBPNG_VER_STRING, | ||||
|       NULL, NULL, NULL); | ||||
|     if (!png_ptr) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     COR_LOG("png struct created"); | ||||
|  | ||||
|     // info struct | ||||
|     png_infop info_ptr = png_create_info_struct(png_ptr); | ||||
|     if (!info_ptr) { | ||||
|       png_destroy_read_struct(&png_ptr, NULL, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     COR_LOG("info struct created"); | ||||
|  | ||||
|     // the PNG error function calls longjmp(png_ptr->jmpbuf) | ||||
|     if (setjmp(png_jmpbuf(png_ptr))) { | ||||
|       COR_LOG("Error loading PNG"); | ||||
|       png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     COR_LOG("setjmp() succeeded"); | ||||
|  | ||||
|     // set the error function | ||||
|     png_set_error_fn(png_ptr, 0, PNG_error_function, PNG_warning_function); | ||||
|  | ||||
|     // read the image | ||||
|     png_set_read_fn(png_ptr, file, PNG_read_function); | ||||
|     png_set_sig_bytes(png_ptr, 8);  // we already read 8 bytes for the sig | ||||
|     // always give us 8-bit samples (strip 16-bit and expand <8-bit) | ||||
|     int png_transform = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND; | ||||
|     png_read_png(png_ptr, info_ptr, png_transform, NULL); | ||||
|  | ||||
|     COR_LOG("PNG read"); | ||||
|  | ||||
|     if (!png_get_rows(png_ptr, info_ptr)) { | ||||
|       png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     int width  = png_get_image_width(png_ptr, info_ptr); | ||||
|     int height = png_get_image_height(png_ptr, info_ptr); | ||||
|     byte* pixels = 0;  // allocate when we know the format | ||||
|     PixelFormat format; | ||||
|     byte* palette = 0; | ||||
|     PixelFormat palette_format; | ||||
|  | ||||
|     // decode based on pixel format | ||||
|     int bit_depth = png_get_bit_depth(png_ptr, info_ptr); | ||||
|     int num_channels = png_get_channels(png_ptr, info_ptr); | ||||
|     png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); | ||||
|  | ||||
|     // 32-bit RGBA | ||||
|     if (bit_depth == 8 && num_channels == 4) { | ||||
|       COR_LOG("32-bit RGBA: bit_depth = 8 && num_channels = 4"); | ||||
|  | ||||
|       format = PF_R8G8B8A8; | ||||
|       pixels = new byte[width * height * 4]; | ||||
|       for (int i = 0; i < height; ++i) { | ||||
|         memcpy(pixels + i * width * 4, row_pointers[i], width * 4); | ||||
|       } | ||||
|  | ||||
|     // 24-bit RGB | ||||
|     } else if (bit_depth == 8 && num_channels == 3) { | ||||
|       COR_LOG("24-bit RGB: bit_depth = 8 && num_channels = 3"); | ||||
|  | ||||
|       format = PF_R8G8B8; | ||||
|       pixels = new byte[width * height * 3]; | ||||
|       for (int i = 0; i < height; ++i) { | ||||
|         memcpy(pixels + i * width * 3, row_pointers[i], width * 3); | ||||
|       } | ||||
|  | ||||
|     // palettized or greyscale with alpha | ||||
|     } else if (bit_depth == 8 && (num_channels == 2 || num_channels == 1)) { | ||||
|       png_color png_palette[256]; | ||||
|       fill_palette(png_ptr, info_ptr, png_palette); | ||||
|  | ||||
|       if (num_channels == 2) { | ||||
|         COR_LOG("bit_depth = 8 && num_channels = 2"); | ||||
|  | ||||
| 	format = PF_R8G8B8A8; | ||||
| 	pixels = new byte[width * height * 4]; | ||||
| 	byte* out = pixels; | ||||
|  | ||||
|         for (int i = 0; i < height; ++i) { | ||||
|           byte* in = row_pointers[i]; | ||||
|           for (int j = 0; j < width; ++j) { | ||||
|             byte c = *in++; | ||||
|             *out++ = png_palette[c].red; | ||||
|             *out++ = png_palette[c].green; | ||||
|             *out++ = png_palette[c].blue; | ||||
|             *out++ = *in++;  // alpha | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } else { // (num_channels == 1) | ||||
|         COR_LOG("bit_depth = 8 && num_channels = 1"); | ||||
|  | ||||
|         pixels = new byte[width * height]; | ||||
|         format = PF_I8; | ||||
|         palette = new byte[256 * 4]; | ||||
|         palette_format = PF_R8G8B8A8; | ||||
|  | ||||
|  | ||||
|         // get the transparent palette flags | ||||
|         png_bytep trans; | ||||
|         int num_trans = 0; | ||||
|         png_color_16p trans_values; // XXX not used - should be? | ||||
|         png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); | ||||
|  | ||||
|         // copy the palette from the PNG | ||||
|         for (int i = 0; i < 256; ++i) { | ||||
|           palette[i * 4 + 0] = png_palette[i].red; | ||||
|           palette[i * 4 + 1] = png_palette[i].green; | ||||
|           palette[i * 4 + 2] = png_palette[i].blue; | ||||
|           palette[i * 4 + 3] = 255; | ||||
|         } | ||||
|         // apply transparency to palette entries | ||||
|         for (int i = 0; i < num_trans; ++i) { | ||||
|           palette[trans[i] * 4 + 3] = 0; | ||||
|         } | ||||
|  | ||||
|         byte* out = pixels; | ||||
|         for (int i = 0; i < height; ++i) { | ||||
|           memcpy(out, row_pointers[i], width); | ||||
|           out += width; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|     } else {  // unknown format | ||||
|       png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | ||||
|  | ||||
|     if (palette) { | ||||
|       return new SimpleImage(width, height, format, pixels, | ||||
| 			     palette, 256, palette_format); | ||||
|     } else { | ||||
|       return new SimpleImage(width, height, format, pixels); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| } | ||||
							
								
								
									
										147
									
								
								corona/src/OpenTGA.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								corona/src/OpenTGA.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| #include <algorithm> | ||||
| #include "Debug.h" | ||||
| #include "Open.h" | ||||
| #include "SimpleImage.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   Image* OpenTGA(File* file) { | ||||
|     COR_GUARD("OpenTGA"); | ||||
|  | ||||
|     // read header | ||||
|     byte header[18]; | ||||
|     if (file->read(header, 18) != 18) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // decode header | ||||
|     int id_length        = header[0]; | ||||
|     int cm_type          = header[1]; | ||||
|     int image_type       = header[2]; | ||||
|     //int cm_first         = read16_le(header + 3); | ||||
|     int cm_length        = read16_le(header + 5); | ||||
|     int cm_entry_size    = header[7];  // in bits | ||||
|     //int x_origin         = read16_le(header + 8); | ||||
|     //int y_origin         = read16_le(header + 10); | ||||
|     int width            = read16_le(header + 12); | ||||
|     int height           = read16_le(header + 14); | ||||
|     int pixel_depth      = header[16]; | ||||
|     int image_descriptor = header[17]; | ||||
|      | ||||
|     bool mirrored = (image_descriptor & (1 << 4)) != 0;  // left-to-right? | ||||
|     bool flipped  = (image_descriptor & (1 << 5)) == 0;  // bottom-to-top? | ||||
|  | ||||
|     /* | ||||
|      * image types | ||||
|      * 0  = no image data | ||||
|      * 1  = uncompressed, color-mapped | ||||
|      * 2  = uncompressed, true-color | ||||
|      * 3  = uncompressed, black and white | ||||
|      * 9  = RLE, color-mapped | ||||
|      * 10 = RLE, true-color | ||||
|      * 11 = RLE, black and white | ||||
|      */ | ||||
|  | ||||
|     // make sure we support the image | ||||
|     if (image_type != 2 || (pixel_depth != 24 && pixel_depth != 32)) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // skip image id | ||||
|     byte unused[255]; | ||||
|     if (file->read(unused, id_length) != id_length) { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // skip color map | ||||
|     if (cm_type != 0) { | ||||
|       // allocate color map | ||||
|       int cm_entry_bytes = (cm_entry_size + 7) / 8; | ||||
|       int cm_size = cm_entry_bytes * cm_length; | ||||
|       auto_array<byte> color_map(new byte[cm_size]); | ||||
|       if (file->read(color_map, cm_size) != cm_size) { | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // read image data | ||||
|     PixelFormat format; | ||||
|     auto_array<byte> pixels; | ||||
|     if (pixel_depth == 24) { | ||||
|  | ||||
|       COR_LOG("24-bit image"); | ||||
|  | ||||
|       format = PF_B8G8R8; | ||||
|       int image_size = width * height * 3; | ||||
|       pixels = new byte[image_size]; | ||||
|       if (file->read(pixels, image_size) != image_size) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|     } else if (pixel_depth == 32) { | ||||
|  | ||||
|       COR_LOG("32-bit image"); | ||||
|  | ||||
|       format = PF_B8G8R8A8; | ||||
|       int image_size = width * height * 4; | ||||
|       pixels = new byte[image_size]; | ||||
|       if (file->read(pixels, image_size) != image_size) { | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|     } else { | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     // reverse each row | ||||
|     if (mirrored) { | ||||
|       COR_LOG("Image is mirrored"); | ||||
|  | ||||
|       const int bpp = pixel_depth / 8;  // bytes per pixel | ||||
|       for (int y = 0; y < height; ++y) { | ||||
|  | ||||
| 	// points to the first pixel of the row | ||||
| 	byte* start = pixels.get() + y * width * bpp; | ||||
| 	// points to the last pixel of the row | ||||
| 	byte* end   = start + (width - 1) * bpp; | ||||
|  | ||||
| 	while (start < end) { | ||||
| 	  for (int b = 0; b < bpp; ++b) { | ||||
| 	    std::swap(start[b], end[b]); | ||||
| 	  } | ||||
| 	  start += bpp; | ||||
| 	  end   -= bpp; | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // reverse rows as a whole | ||||
|     if (flipped) { | ||||
|       COR_LOG("Image is flipped"); | ||||
|  | ||||
|       const int bpp = pixel_depth / 8;  // bytes per pixel | ||||
|       const int row_size = width * bpp; | ||||
|       auto_array<byte> temp(new byte[row_size]);  // for the swap | ||||
|  | ||||
|       // points to the beginning of the first row | ||||
|       byte* start = pixels.get(); | ||||
|  | ||||
|       // points to the beginning of the last row | ||||
|       byte* end   = start + (height - 1) * width * bpp; | ||||
|  | ||||
|       while (start < end) { | ||||
| 	memcpy(temp.get(), start,      row_size); | ||||
| 	memcpy(start,      end,        row_size); | ||||
| 	memcpy(end,        temp.get(), row_size); | ||||
|  | ||||
| 	start += row_size; | ||||
| 	end   -= row_size; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new SimpleImage(width, height, format, pixels.release()); | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										16
									
								
								corona/src/Save.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								corona/src/Save.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #ifndef CORONA_SAVE_H | ||||
| #define CORONA_SAVE_H | ||||
|  | ||||
|  | ||||
| #include "corona.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
| #ifndef NO_PNG | ||||
|   bool SavePNG(File* file, Image* image); // SavePNG.cpp | ||||
| #endif | ||||
|   bool SaveTGA(File* file, Image* image); // SaveTGA.cpp | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										168
									
								
								corona/src/SavePNG.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								corona/src/SavePNG.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| #include <memory> | ||||
| #include <png.h> | ||||
| #include "Debug.h" | ||||
| #include "Save.h" | ||||
| #include "Types.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   void PNG_write(png_structp png_ptr, png_bytep data, png_size_t length) { | ||||
|     File* file = (File*)png_get_io_ptr(png_ptr); | ||||
|     if (file->write(data, length) != int(length)) { | ||||
|       png_error(png_ptr, "Write error"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void PNG_flush(png_structp png_ptr) { | ||||
|     // assume that files always flush | ||||
|   } | ||||
|  | ||||
|   bool SavePNG(File* file, Image* image) { | ||||
|     COR_GUARD("SavePNG"); | ||||
|  | ||||
|     if (!image) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // If the image format isn't supported directly by this function, | ||||
|     // clone to a supported format and try to save with that. | ||||
|     switch (image->getFormat()) { | ||||
|       case PF_R8G8B8A8: | ||||
|       case PF_R8G8B8: | ||||
|       case PF_I8: | ||||
| 	break; | ||||
|       default: { | ||||
| 	COR_LOG("Unsupported pixel format... cloning"); | ||||
| 	std::auto_ptr<Image> cloned(CloneImage(image, PF_R8G8B8A8)); | ||||
| 	return SavePNG(file, cloned.get()); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // create write struct | ||||
|     png_structp png_ptr = png_create_write_struct( | ||||
|       PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | ||||
|     if (!png_ptr) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // error handling! | ||||
|     if (setjmp(png_jmpbuf(png_ptr))) { | ||||
|       png_destroy_write_struct(&png_ptr, NULL); | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // create info struct | ||||
|     png_infop info_ptr = png_create_info_struct(png_ptr); | ||||
|     if (!info_ptr) { | ||||
|       png_destroy_write_struct(&png_ptr, NULL); | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     int width  = image->getWidth(); | ||||
|     int height = image->getHeight(); | ||||
|  | ||||
|     // set image characteristics | ||||
|     png_set_write_fn(png_ptr, file, PNG_write, PNG_flush); | ||||
|  | ||||
|     int color_format = 0; // png output format | ||||
|     int color_format_bpp = 0; // png bytes per pixel | ||||
|     bool color_format_paletted = false; // png palette needed flag | ||||
|  | ||||
|     // figure out output format | ||||
|     switch (image->getFormat()) { | ||||
|       case PF_R8G8B8A8: | ||||
|         color_format = PNG_COLOR_TYPE_RGB_ALPHA; | ||||
|         color_format_bpp = 4; | ||||
|         break; | ||||
|       case PF_R8G8B8: | ||||
|         color_format = PNG_COLOR_TYPE_RGB; | ||||
|         color_format_bpp = 3; | ||||
|         break; | ||||
|       case PF_I8: | ||||
|         color_format = PNG_COLOR_TYPE_PALETTE; | ||||
|         color_format_bpp = 1; | ||||
|         color_format_paletted = true; | ||||
|         break; | ||||
|       default: | ||||
|         // Unsupported format.  This should already be taken care of | ||||
|         // by the test at the beginning of this function. | ||||
|         png_destroy_write_struct(&png_ptr, &info_ptr); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     png_set_IHDR( | ||||
|       png_ptr, info_ptr, | ||||
|       width, height, | ||||
|       8, | ||||
|       color_format, | ||||
|       PNG_INTERLACE_NONE, | ||||
|       PNG_COMPRESSION_TYPE_DEFAULT, | ||||
|       PNG_FILTER_TYPE_DEFAULT); | ||||
|  | ||||
|     png_color* png_palette = 0; | ||||
|     if (color_format_paletted) { | ||||
|       COR_LOG("Saving palettized image..."); | ||||
|  | ||||
|       int image_palette_format = image->getPaletteFormat(); // palette format | ||||
|       int image_palette_size = image->getPaletteSize(); // palette size | ||||
|  | ||||
|       // allocate png palette and get pointer to image palette | ||||
|       png_palette = (png_color*)png_malloc( | ||||
|         png_ptr, sizeof(png_color) * image_palette_size); | ||||
|       byte* image_palette = (byte*)image->getPalette(); | ||||
|  | ||||
|  | ||||
|       if (image_palette_format == PF_R8G8B8) { | ||||
| 	// 24 bit source palette | ||||
| 	for (int i = 0; i < image_palette_size; i++) { | ||||
| 	  // copy entry directly | ||||
| 	  png_palette[i].red   = *image_palette++; | ||||
| 	  png_palette[i].green = *image_palette++; | ||||
| 	  png_palette[i].blue  = *image_palette++; | ||||
| 	} | ||||
|       } else if (image_palette_format == PF_R8G8B8A8) { | ||||
| 	// 32 bit source palette | ||||
| 	for (int i = 0; i < image_palette_size; i++) { | ||||
| 	  // copy entry, skip alpha | ||||
| 	  png_palette[i].red   = *image_palette++; | ||||
| 	  png_palette[i].green = *image_palette++; | ||||
| 	  png_palette[i].blue  = *image_palette++; | ||||
| 	  image_palette++; | ||||
| 	} | ||||
|       } | ||||
|       // write palette | ||||
|       png_set_PLTE(png_ptr, info_ptr, png_palette, image_palette_size); | ||||
|     } | ||||
|  | ||||
|     byte* pixels = (byte*)image->getPixels(); | ||||
|  | ||||
|     // build rows | ||||
|     void** rows = (void**)png_malloc(png_ptr, sizeof(void*) * height); | ||||
|     for (int i = 0; i < height; ++i) { | ||||
|       rows[i] = png_malloc(png_ptr, color_format_bpp * width); | ||||
|       memcpy(rows[i], pixels, color_format_bpp * width); | ||||
|       pixels += width * color_format_bpp;       | ||||
|     } | ||||
|     png_set_rows(png_ptr, info_ptr, (png_bytepp)rows); | ||||
|     info_ptr->valid |= PNG_INFO_IDAT; | ||||
|  | ||||
|     // actually write the image | ||||
|     png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); | ||||
|  | ||||
|     // clean up memory | ||||
|     for (int i = 0; i < height; ++i) { | ||||
|       png_free(png_ptr, rows[i]); | ||||
|     } | ||||
|     png_free(png_ptr, rows); | ||||
|  | ||||
|     if (png_palette) { | ||||
|       png_free(png_ptr, png_palette); | ||||
|     } | ||||
|  | ||||
|     png_destroy_write_struct(&png_ptr, &info_ptr); | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										49
									
								
								corona/src/SaveTGA.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								corona/src/SaveTGA.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #include <memory> | ||||
| #include <png.h> | ||||
| #include "Debug.h" | ||||
| #include "Save.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   bool SaveTGA(File* file, Image* source) { | ||||
|     COR_GUARD("SaveTGA"); | ||||
|  | ||||
|     std::auto_ptr<Image> image(CloneImage(source, PF_B8G8R8A8)); | ||||
|     if (!image.get()) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     const int width  = image->getWidth(); | ||||
|     const int height = image->getHeight(); | ||||
|  | ||||
|     // generate the header | ||||
|     byte header[18]; | ||||
|     header[0] = 0;               // id_length | ||||
|     header[1] = 0;               // cm_type | ||||
|     header[2] = 2;               // image_type (uncompressed true color) | ||||
|     write16_le(header + 3,  0);  // cm_first | ||||
|     write16_le(header + 5,  0);  // cm_length | ||||
|     header[7] = 0;               // cm_entry_size | ||||
|     write16_le(header + 8,  0);  // x_origin | ||||
|     write16_le(header + 10, 0);  // y_origin | ||||
|     write16_le(header + 12, width); | ||||
|     write16_le(header + 14, height); | ||||
|     header[16] = 32;             // pixel_depth | ||||
|     header[17] = (1 << 5) | 7;   // origin at upper/left, 8 bits of alpha data | ||||
|  | ||||
|     if (file->write(header, 18) != 18) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // write pixels | ||||
|     const int data_size = width * height * 4; | ||||
|     if (file->write(image->getPixels(), data_size) != data_size) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										101
									
								
								corona/src/SimpleImage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								corona/src/SimpleImage.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #ifndef CORONA_SIMPLE_IMAGE_H | ||||
| #define CORONA_SIMPLE_IMAGE_H | ||||
|  | ||||
|  | ||||
| #include "corona.h" | ||||
| #include "Types.h" | ||||
| #include "Utility.h" | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   /** | ||||
|    * Basic, flat, simple image.  Has a width, a height, a pixel | ||||
|    * format, and a 2D array of pixels (one-byte packing). | ||||
|    * | ||||
|    * The constructor takes a pixel buffer (and optionally a palette) | ||||
|    * which it then owns and delete[]'s when the image is destroyed. | ||||
|    */ | ||||
|   class SimpleImage : public DLLImplementation<Image> { | ||||
|   public: | ||||
|  | ||||
|     /** | ||||
|      * Creates a new image, setting all properties. | ||||
|      * | ||||
|      * @param width           width of the new image | ||||
|      * @param height          height of the new image | ||||
|      * @param format          format that the pixels are stored in | ||||
|      * @param pixels          pixel buffer that the SimpleImage takes | ||||
|                               ownership of.  it should be | ||||
|                               width*height*sizeof(pixel) bytes. | ||||
|      * @param palette         palette color buffer | ||||
|      * @param palette_size    number of entries in palette | ||||
|      * @param palette_format  color format palette is stored as | ||||
|      */ | ||||
|     SimpleImage(int width, | ||||
|                 int height, | ||||
|                 PixelFormat format, | ||||
|                 byte* pixels, | ||||
|                 byte* palette = 0, | ||||
|                 int palette_size = 0, | ||||
|                 PixelFormat palette_format = PF_DONTCARE) { | ||||
|  | ||||
|       m_width          = width; | ||||
|       m_height         = height; | ||||
|       m_format         = format; | ||||
|       m_pixels         = pixels; | ||||
|       m_palette        = palette; | ||||
|       m_palette_size   = palette_size; | ||||
|       m_palette_format = palette_format; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Destroys the image, freeing the owned pixel buffer and palette. | ||||
|      */ | ||||
|     ~SimpleImage() { | ||||
|       delete[] m_pixels; | ||||
|       delete[] m_palette; | ||||
|     } | ||||
|  | ||||
|     int COR_CALL getWidth() { | ||||
|       return m_width; | ||||
|     } | ||||
|  | ||||
|     int COR_CALL getHeight() { | ||||
|       return m_height; | ||||
|     } | ||||
|  | ||||
|     PixelFormat COR_CALL getFormat() { | ||||
|       return m_format; | ||||
|     } | ||||
|  | ||||
|     void* COR_CALL getPixels() { | ||||
|       return m_pixels; | ||||
|     } | ||||
|  | ||||
|     void* COR_CALL getPalette() { | ||||
|       return m_palette; | ||||
|     } | ||||
|  | ||||
|     int COR_CALL getPaletteSize() { | ||||
|       return m_palette_size; | ||||
|     } | ||||
|  | ||||
|     PixelFormat COR_CALL getPaletteFormat() { | ||||
|       return m_palette_format; | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|     int         m_width; | ||||
|     int         m_height; | ||||
|     PixelFormat m_format; | ||||
|     byte*       m_pixels; | ||||
|     byte*       m_palette; | ||||
|     int         m_palette_size; | ||||
|     PixelFormat m_palette_format; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										27
									
								
								corona/src/Types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								corona/src/Types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #ifndef CORONA_TYPES_H | ||||
| #define CORONA_TYPES_H | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   // VC++-specific types | ||||
|   #ifdef _MSC_VER | ||||
|  | ||||
|     typedef unsigned char    byte; | ||||
|     typedef unsigned __int16 u16; | ||||
|     typedef unsigned __int32 u32; | ||||
|  | ||||
|   // reasonable defaults | ||||
|   // should work on any 32-bit platform | ||||
|   #else | ||||
|  | ||||
|     typedef unsigned char  byte; | ||||
|     typedef unsigned short u16; | ||||
|     typedef unsigned long  u32; | ||||
|  | ||||
|   #endif | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										127
									
								
								corona/src/Utility.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								corona/src/Utility.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| #ifndef CORONA_UTILITY_H | ||||
| #define CORONA_UTILITY_H | ||||
|  | ||||
|  | ||||
| #include <algorithm> | ||||
| #include "corona.h" | ||||
| #include "Types.h" | ||||
|  | ||||
|  | ||||
| #define COR_EXPORT(ret)  COR_FUNCTION(ret) | ||||
|  | ||||
|  | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1200 | ||||
|  | ||||
| // define our own std::min and std::max in VC6 | ||||
| namespace std { | ||||
|   template<typename T> | ||||
|   T min(T a, T b) { | ||||
|     return a < b ? a : b; | ||||
|   } | ||||
|   template<typename T> | ||||
|   T max(T a, T b) { | ||||
|     return a > b ? a : b; | ||||
|   } | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|  | ||||
|   template<typename T> | ||||
|   class auto_array { | ||||
|   public: | ||||
|     explicit auto_array(T* initial = 0) { | ||||
|       array = initial; | ||||
|     } | ||||
|      | ||||
|     ~auto_array() { | ||||
|       delete[] array; | ||||
|     } | ||||
|  | ||||
|     operator T*() const { | ||||
|       return array; | ||||
|     } | ||||
|  | ||||
|     T* get() const { | ||||
|       return array; | ||||
|     } | ||||
|  | ||||
|     T* release() { | ||||
|       T* old = array; | ||||
|       array = 0; | ||||
|       return old; | ||||
|     } | ||||
|  | ||||
|     auto_array<T>& operator=(T* a) { | ||||
|       if (array != a) { | ||||
| 	delete array; | ||||
| 	array = a; | ||||
|       } | ||||
|       return *this; | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|     T* array; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   inline u16 read16_le(const byte* b) { | ||||
|     return b[0] + (b[1] << 8); | ||||
|   } | ||||
|  | ||||
|   inline void write16_le(byte* b, u16 value) { | ||||
|     b[0] = value & 0xFF; | ||||
|     b[1] = value >> 8; | ||||
|   } | ||||
|  | ||||
|   inline u16 read16_be(const byte* b) { | ||||
|     return (b[0] << 8) + b[1]; | ||||
|   } | ||||
|  | ||||
|   inline void write16_be(byte* b, u16 value) { | ||||
|     b[0] = value >> 8; | ||||
|     b[1] = value & 0xFF; | ||||
|   } | ||||
|  | ||||
|   inline u32 read32_le(const byte* b) { | ||||
|     return read16_le(b) + (read16_le(b + 2) << 16); | ||||
|   } | ||||
|  | ||||
|   inline u32 read32_be(const byte* b) { | ||||
|     return (read16_be(b) << 16) + read16_be(b + 2); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   struct RGB { | ||||
|     byte red; | ||||
|     byte green; | ||||
|     byte blue; | ||||
|   }; | ||||
|  | ||||
|   struct RGBA { | ||||
|     byte red; | ||||
|     byte green; | ||||
|     byte blue; | ||||
|     byte alpha; | ||||
|   }; | ||||
|  | ||||
|   struct BGR { | ||||
|     byte blue; | ||||
|     byte green; | ||||
|     byte red; | ||||
|   }; | ||||
|  | ||||
|   struct BGRA { | ||||
|     byte blue; | ||||
|     byte green; | ||||
|     byte red; | ||||
|     byte alpha; | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										728
									
								
								corona/src/corona.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										728
									
								
								corona/src/corona.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,728 @@ | ||||
| /** | ||||
|  * Corona Image I/O Library | ||||
|  * Version 1.0.2 | ||||
|  * (c) 2003 Chad Austin | ||||
|  * | ||||
|  * This API uses principles explained at | ||||
|  * http://aegisknight.org/cppinterface.html | ||||
|  * | ||||
|  * This code licensed under the terms of the zlib license.  See | ||||
|  * license.txt. | ||||
|  * | ||||
|  * | ||||
|  * Note: When compiling this header in gcc, you may want to use the | ||||
|  * -Wno-non-virtual-dtor flag to get rid of those annoying "class has | ||||
|  * virtual functions but no virtual destructor" warnings. | ||||
|  */ | ||||
|  | ||||
|  | ||||
| #ifndef CORONA_H | ||||
| #define CORONA_H | ||||
|  | ||||
|  | ||||
| #ifndef __cplusplus | ||||
| #error Corona requires C++ | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #include <stddef.h> | ||||
|  | ||||
|  | ||||
| // DLLs in Windows should use the standard calling convention | ||||
| #ifndef COR_CALL | ||||
| #  if defined(WIN32) || defined(_WIN32) | ||||
| #    define COR_CALL __stdcall | ||||
| #  else | ||||
| #    define COR_CALL | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| // Export functions from the DLL | ||||
| #ifndef COR_DECL | ||||
| #  if defined(WIN32) || defined(_WIN32) | ||||
| #    ifdef CORONA_EXPORTS | ||||
| #      define COR_DECL __declspec(dllexport) | ||||
| #    else | ||||
| #      define COR_DECL | ||||
| #    endif | ||||
| #  else | ||||
| #    define COR_DECL | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // evil "identifier is too long in debug information" warning | ||||
| #ifdef _MSC_VER | ||||
| #pragma warning(disable : 4786) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #define COR_FUNCTION(ret) extern "C" COR_DECL ret COR_CALL | ||||
|  | ||||
|  | ||||
| namespace corona { | ||||
|  | ||||
|   /** | ||||
|    * File formats supported for reading or writing. | ||||
|    */ | ||||
|   enum FileFormat { | ||||
|     FF_AUTODETECT = 0x0100, | ||||
|     FF_PNG        = 0x0101, | ||||
|     FF_JPEG       = 0x0102, | ||||
|     FF_PCX        = 0x0103, | ||||
|     FF_BMP        = 0x0104, | ||||
|     FF_TGA        = 0x0105, | ||||
|     FF_GIF        = 0x0106, | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Pixel format specifications.  Pixel data can be packed in one of | ||||
|    * the following ways. | ||||
|    */ | ||||
|   enum PixelFormat { | ||||
|     PF_DONTCARE = 0x0200,  /**< special format used when specifying a | ||||
|                                 desired pixel format */ | ||||
|     PF_R8G8B8A8 = 0x0201,  /**< RGBA, channels have eight bits of precision */ | ||||
|     PF_R8G8B8   = 0x0202,  /**< RGB, channels have eight bits of precision  */ | ||||
|     PF_I8       = 0x0203,  /**< Palettized, 8-bit indices into palette      */ | ||||
|     PF_B8G8R8A8 = 0x0204,  /**< BGRA, channels have eight bits of precision */ | ||||
|     PF_B8G8R8   = 0x0205,  /**< BGR, channels have eight bits of precision  */ | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * Axis specifications.  The image can be flipped along the following | ||||
|    * axes. | ||||
|    */ | ||||
|   enum CoordinateAxis { | ||||
|     CA_X     = 0x0001, | ||||
|     CA_Y     = 0x0002, | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * A helper class for DLL-compatible interfaces.  Derive your cross-DLL | ||||
|    * interfaces from this class. | ||||
|    * | ||||
|    * When deriving from this class, do not declare a virtual destructor | ||||
|    * on your interface. | ||||
|    */ | ||||
|   class DLLInterface { | ||||
|   private: | ||||
|     /** | ||||
|      * Destroy the object, freeing all associated memory.  This is | ||||
|      * the same as a destructor. | ||||
|      */ | ||||
|     virtual void COR_CALL destroy() = 0; | ||||
|  | ||||
|   public: | ||||
|     /** | ||||
|      * "delete image" should actually call image->destroy(), thus putting the | ||||
|      * burden of calling the destructor and freeing the memory on the image | ||||
|      * object, and thus on Corona's side of the DLL boundary. | ||||
|      */ | ||||
|     void operator delete(void* p) { | ||||
|       if (p) { | ||||
|         DLLInterface* i = static_cast<DLLInterface*>(p); | ||||
|         i->destroy(); | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * A helper class for DLL-compatible interface implementations.  Derive | ||||
|    * your implementations from DLLImplementation<YourInterface>. | ||||
|    */ | ||||
|   template<class Interface> | ||||
|   class DLLImplementation : public Interface { | ||||
|   public: | ||||
|     /** | ||||
|      * So the implementation can put its destruction logic in the destructor, | ||||
|      * as natural C++ code does. | ||||
|      */ | ||||
|     virtual ~DLLImplementation() { } | ||||
|  | ||||
|     /** | ||||
|      * Call the destructor in a Win32 ABI-compatible way. | ||||
|      */ | ||||
|     virtual void COR_CALL destroy() { | ||||
|       delete this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * So destroy()'s "delete this" doesn't go into an infinite loop, | ||||
|      * calling the interface's operator delete, which calls destroy()... | ||||
|      */ | ||||
|     void operator delete(void* p) { | ||||
|       ::operator delete(p); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|    | ||||
|   /** | ||||
|    * An image object represents a rectangular collections of pixels. | ||||
|    * They have a width, a height, and a pixel format.  Images cannot | ||||
|    * be resized. | ||||
|    */ | ||||
|   class Image : public DLLInterface { | ||||
|   public: | ||||
|     /** | ||||
|      * Get image width. | ||||
|      * @return  image width | ||||
|      */ | ||||
|     virtual int COR_CALL getWidth() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get image height. | ||||
|      * @return  image height | ||||
|      */ | ||||
|     virtual int COR_CALL getHeight() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get pixel format. | ||||
|      * @return  pixel format | ||||
|      */ | ||||
|     virtual PixelFormat COR_CALL getFormat() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get pixel buffer.  The pixels are packed in the format defined | ||||
|      * by the image's pixel format. | ||||
|      * | ||||
|      * @return  pointer to first element in pixel buffer | ||||
|      */ | ||||
|     virtual void* COR_CALL getPixels() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get the palette.  Pixels are packed in the format defined by | ||||
|      * getPaletteFormat(). | ||||
|      * | ||||
|      * @return  pointer to first palette entry | ||||
|      */ | ||||
|     virtual void* COR_CALL getPalette() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get the number of entries in the palette. | ||||
|      * | ||||
|      * @return  number of palette entries | ||||
|      */ | ||||
|     virtual int COR_CALL getPaletteSize() = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get the format of the colors in the palette. | ||||
|      * | ||||
|      * @return  pixel format of palette entries | ||||
|      */ | ||||
|     virtual PixelFormat COR_CALL getPaletteFormat() = 0; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * Represents a random-access file, usually stored on a disk.  Files | ||||
|    * are always binary: that is, they do no end-of-line | ||||
|    * transformations.  File objects are roughly analogous to ANSI C | ||||
|    * FILE* objects. | ||||
|    */ | ||||
|   class File : public DLLInterface { | ||||
|   public: | ||||
|  | ||||
|     /** | ||||
|      * The different ways you can seek within a file. | ||||
|      */ | ||||
|     enum SeekMode { | ||||
|       BEGIN,    /**< relative to the beginning of the file */ | ||||
|       CURRENT,  /**< relative to the current position in the file */ | ||||
|       END       /**< relative to the end of the file: position should | ||||
|                      be negative*/ | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Read size bytes from the file, storing them in buffer. | ||||
|      * | ||||
|      * @param buffer  buffer to read into | ||||
|      * @param size    number of bytes to read | ||||
|      * | ||||
|      * @return  number of bytes successfully read | ||||
|      */ | ||||
|     virtual int COR_CALL read(void* buffer, int size) = 0; | ||||
|  | ||||
|     /** | ||||
|      * Write size bytes from buffer to the file. | ||||
|      * | ||||
|      * @param buffer  buffer that contains the data to write | ||||
|      * @param size    number of bytes to write | ||||
|      * | ||||
|      * @return  number of bytes successfully written | ||||
|      */ | ||||
|     virtual int COR_CALL write(const void* buffer, int size) = 0; | ||||
|  | ||||
|     /** | ||||
|      * Jump to a new position in the file, using the specified seek | ||||
|      * mode.  Remember: if mode is END, the position must be negative, | ||||
|      * to seek backwards from the end of the file into its contents. | ||||
|      * If the seek fails, the current position is undefined. | ||||
|      * | ||||
|      * @param position  position relative to the mode | ||||
|      * @param mode      where to seek from in the file | ||||
|      * | ||||
|      * @return  true on success, false otherwise | ||||
|      */ | ||||
|     virtual bool COR_CALL seek(int position, SeekMode mode) = 0; | ||||
|  | ||||
|     /** | ||||
|      * Get current position within the file. | ||||
|      * | ||||
|      * @return  current position | ||||
|      */ | ||||
|     virtual int COR_CALL tell() = 0; | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /// Describes a file format that Corona supports. | ||||
|   class FileFormatDesc { | ||||
|   protected: | ||||
|     virtual ~FileFormatDesc() { } | ||||
|  | ||||
|   public: | ||||
|     /// Actual FileFormat being described. | ||||
|     virtual FileFormat getFormat() = 0; | ||||
|  | ||||
|     /// Short description of format, such as "PNG Files" or "JPEG Files" | ||||
|     virtual const char* getDescription() = 0; | ||||
|  | ||||
|     /// @{ | ||||
|     /// List of supported extensions, such as {"bmp", "rle", "dib"} | ||||
|     virtual size_t getExtensionCount() = 0; | ||||
|     virtual const char* getExtension(size_t i) = 0; | ||||
|     /// @} | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   /// PRIVATE API - for internal use only | ||||
|   namespace hidden { | ||||
|  | ||||
|     // these are extern "C" so we don't mangle the names | ||||
|  | ||||
|  | ||||
|     // API information | ||||
|  | ||||
|     COR_FUNCTION(const char*) CorGetVersion(); | ||||
|  | ||||
|     COR_FUNCTION(FileFormatDesc**) CorGetSupportedReadFormats(); | ||||
|     COR_FUNCTION(FileFormatDesc**) CorGetSupportedWriteFormats(); | ||||
|  | ||||
|     // creation | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorCreateImage( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorCreateImageWithPixels( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format, | ||||
|       void* pixels); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorCreatePalettizedImage( | ||||
|       int width, | ||||
|       int height, | ||||
|       PixelFormat format, // must be a palettized format | ||||
|       int palette_size, | ||||
|       PixelFormat palette_format); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorCloneImage( | ||||
|       Image* source, | ||||
|       PixelFormat format); | ||||
|  | ||||
|     // loading | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorOpenImage( | ||||
|       const char* filename, | ||||
|       FileFormat file_format); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorOpenImageFromFile( | ||||
|       File* file, | ||||
|       FileFormat file_format); | ||||
|  | ||||
|     // saving | ||||
|  | ||||
|     COR_FUNCTION(bool) CorSaveImage( | ||||
|       const char* filename, | ||||
|       FileFormat file_format, | ||||
|       Image* image); | ||||
|  | ||||
|     COR_FUNCTION(bool) CorSaveImageToFile( | ||||
|       File* file, | ||||
|       FileFormat file_format, | ||||
|       Image* image); | ||||
|  | ||||
|     // conversion | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorConvertImage( | ||||
|       Image* image, | ||||
|       PixelFormat format); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorConvertPalette( | ||||
|       Image* image, | ||||
|       PixelFormat palette_format); | ||||
|  | ||||
|     COR_FUNCTION(Image*) CorFlipImage( | ||||
|       Image* image, | ||||
|       int coordinate_axis); | ||||
|  | ||||
|     // files | ||||
|  | ||||
|     COR_FUNCTION(File*) CorOpenFile(const char* name, bool writeable); | ||||
|     COR_FUNCTION(File*) CorCreateMemoryFile(const void* buffer, int size); | ||||
|  | ||||
|     // utility | ||||
|  | ||||
|     COR_FUNCTION(int) CorGetPixelSize(PixelFormat format); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* PUBLIC API */ | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * Return the Corona version string. | ||||
|    * | ||||
|    * @return  Corona version information | ||||
|    */ | ||||
|   inline const char* GetVersion() { | ||||
|     return hidden::CorGetVersion(); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * Returns a null-terminated array of FileFormatDesc* pointers that | ||||
|    * describe the file formats Corona can read.  The array is owned by | ||||
|    * Corona, so do not delete it when you are done using it. | ||||
|    */ | ||||
|   inline FileFormatDesc** GetSupportedReadFormats() { | ||||
|     return hidden::CorGetSupportedReadFormats(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns a null-terminated array of FileFormatDesc* pointers that | ||||
|    * describe the file formats Corona can write.  The array is owned | ||||
|    * by Corona, so do not delete it when you are done using it. | ||||
|    */ | ||||
|   inline FileFormatDesc** GetSupportedWriteFormats() { | ||||
|     return hidden::CorGetSupportedWriteFormats(); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * Create a new, blank image with a specified width, height, and | ||||
|    * format.  If pixels is specified, Corona uses them to initialize | ||||
|    * the contents of the image.  Corona does *not* take ownership of | ||||
|    * the pixel memory, so the caller is responsible for cleaning up | ||||
|    * after itself.  If pixels is not specified, the new image is | ||||
|    * filled with zeroes. | ||||
|    * | ||||
|    * @param width   width of the new image | ||||
|    * @param height  height of the new image | ||||
|    * @param format  format the pixels are stored in, cannot be PF_DONTCARE | ||||
|    * @param pixels  pixel buffer used to initialize the new image | ||||
|    * | ||||
|    * @return  newly created blank image | ||||
|    */ | ||||
|   inline Image* CreateImage( | ||||
|     int width, | ||||
|     int height, | ||||
|     PixelFormat format, | ||||
|     void* pixels = 0) | ||||
|   { | ||||
|     return hidden::CorCreateImageWithPixels(width, height, format, pixels); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create a new, blank image with a specified width, height, format, | ||||
|    * and palette. | ||||
|    * | ||||
|    * @param width           width of image | ||||
|    * @param height          height of image | ||||
|    * @param format          format of palette indices, should be PF_I8 | ||||
|    * @param palette_size    number of colors in palette | ||||
|    * @param palette_format  pixel format of palette entries | ||||
|    */ | ||||
|   inline Image* CreateImage( | ||||
|     int width, | ||||
|     int height, | ||||
|     PixelFormat format, | ||||
|     int palette_size, | ||||
|     PixelFormat palette_format) | ||||
|   { | ||||
|     return hidden::CorCreatePalettizedImage( | ||||
|       width, height, format, | ||||
|       palette_size, palette_format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create a new image from an old one.  If format is specified, the | ||||
|    * new image is converted to that pixel format.  If format is not | ||||
|    * specified, the new image simply uses the same format as the | ||||
|    * source.  If the image could not be cloned or the pixel format is | ||||
|    * invalid, CloneImage returns 0. | ||||
|    * | ||||
|    * @param source  image to clone | ||||
|    * @param format  format the new image is stored in, defaults to PF_DONTCARE | ||||
|    * | ||||
|    * @return  new image cloned from the source, 0 if failure | ||||
|    */ | ||||
|   inline Image* CloneImage( | ||||
|     Image* source, | ||||
|     PixelFormat format = PF_DONTCARE) | ||||
|   { | ||||
|     return hidden::CorCloneImage(source, format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Opens an image from the default filesystem.  This function simply | ||||
|    * forwards the call to OpenImage(file, file_format, pixel_format) | ||||
|    * with a standard C library file. | ||||
|    * | ||||
|    * See OpenImage(fs, filename, file_format, pixel_format) for more | ||||
|    * information. | ||||
|    * | ||||
|    * @param filename      image filename to open | ||||
|    * @param file_format   file format the image is stored in, or FF_AUTODETECT | ||||
|    *                      to try all loaders | ||||
|    * @param pixel_format  desired pixel format, or PF_DONTCARE to use image's | ||||
|    *                      native format | ||||
|    * | ||||
|    * @return  the image loaded from the disk, or 0 if it cannot be opened | ||||
|    */ | ||||
|   inline Image* OpenImage( | ||||
|     const char* filename, | ||||
|     PixelFormat pixel_format = PF_DONTCARE, | ||||
|     FileFormat file_format = FF_AUTODETECT) | ||||
|   { | ||||
|     return hidden::CorConvertImage( | ||||
|       hidden::CorOpenImage(filename, file_format), | ||||
|       pixel_format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Opens an image from the specified file. | ||||
|    * | ||||
|    * If file_format is FF_AUTODETECT, the loader tries | ||||
|    * to load each format until it finds one that succeeds.  Otherwise, | ||||
|    * it tries the specific loader specified. | ||||
|    * | ||||
|    * If pixel_format is PF_DONTCARE, the new image object has the | ||||
|    * pixel format closest to the image's format on disk.  Otherwise, | ||||
|    * the pixels are converted to the specified format before the image | ||||
|    * is returned. | ||||
|    * | ||||
|    * @param file          name of the file that contains the image | ||||
|    * @param file_format   file format the image is stored in, or FF_AUTODETECT | ||||
|    *                      to try all loaders | ||||
|    * @param pixel_format  desired pixel format, or PF_DONTCARE to use image's | ||||
|    *                      native format | ||||
|    * | ||||
|    * @return  the image loaded from the file, or 0 if it cannot be opened | ||||
|    */ | ||||
|   inline Image* OpenImage( | ||||
|     File* file, | ||||
|     PixelFormat pixel_format = PF_DONTCARE, | ||||
|     FileFormat file_format = FF_AUTODETECT) | ||||
|   { | ||||
|     return hidden::CorConvertImage( | ||||
|       hidden::CorOpenImageFromFile(file, file_format), | ||||
|       pixel_format); | ||||
|   } | ||||
|  | ||||
|   /// For compatibility.  This function may be deprecated. | ||||
|   inline Image* OpenImage( | ||||
|     const char* filename, | ||||
|     FileFormat file_format, | ||||
|     PixelFormat pixel_format = PF_DONTCARE) | ||||
|   { | ||||
|     return OpenImage(filename, pixel_format, file_format); | ||||
|   } | ||||
|  | ||||
|   /// For compatibility.  This function may be deprecated. | ||||
|   inline Image* OpenImage( | ||||
|     File* file, | ||||
|     FileFormat file_format, | ||||
|     PixelFormat pixel_format = PF_DONTCARE) | ||||
|   { | ||||
|     return OpenImage(file, pixel_format, file_format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Saves an image to a file in the default filesystem.  This | ||||
|    * function simply calls SaveImage(file, file_format, image) | ||||
|    * with a standard C library file. | ||||
|    * | ||||
|    * See SaveImage(fs, filename, file_format, image) for more information. | ||||
|    * | ||||
|    * @param filename     name of the file to save the image to | ||||
|    * @param file_format  file format in which to save image.  if FF_AUTODETECT, | ||||
|    *                     SaveImage guesses the type from the file extension | ||||
|    * @param image        image to save | ||||
|    * | ||||
|    * @return  true if save succeeds, false otherwise | ||||
|    */ | ||||
|   inline bool SaveImage( | ||||
|     const char* filename, | ||||
|     FileFormat file_format, | ||||
|     Image* image) | ||||
|   { | ||||
|     return hidden::CorSaveImage(filename, file_format, image); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Saves an image to the specified file.  This function saves image | ||||
|    * to a file of type file_format.  If file_format is not a supported | ||||
|    * output type, the function fails.  As of now, Corona only supports | ||||
|    * saving images of type FF_PNG and FF_TGA. | ||||
|    * | ||||
|    * @note This function may create the file even if the save does not | ||||
|    *       succeed, so users of this library should remove the file after | ||||
|    *       the call to SaveImage(). | ||||
|    * | ||||
|    * @param file         file in which to save the image | ||||
|    * @param file_format  file format in which to save image -- must not be | ||||
|    *                     FF_AUTODETECT | ||||
|    * @param image        image to save | ||||
|    * | ||||
|    * @return  true if the save succeeds, false otherwise | ||||
|    */ | ||||
|   inline bool SaveImage( | ||||
|     File* file, | ||||
|     FileFormat file_format, | ||||
|     Image* image) | ||||
|   { | ||||
|     return hidden::CorSaveImageToFile(file, file_format, image); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Converts an image from one format to another, destroying the old | ||||
|    * image.  If source is 0, the function returns 0.  If format is | ||||
|    * PF_DONTCARE or the source and target formats match, returns the | ||||
|    * unmodified source image.  If a valid conversion is not found, | ||||
|    * ConvertImage destroys the old image and returns 0.  For example, | ||||
|    * ConvertImage does not support creating a palettized image from a | ||||
|    * direct color image yet. | ||||
|    * | ||||
|    * @param source  image to convert | ||||
|    * @param format  desired format -- can be PF_DONTCARE | ||||
|    * | ||||
|    * @return  valid image object if conversion succeeds, 0 otherwise | ||||
|    */ | ||||
|   inline Image* ConvertImage(Image* source, PixelFormat format) { | ||||
|     return hidden::CorConvertImage(source, format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Converts the palette of a palettized image from one format to | ||||
|    * another, destroying the old image.  If the source is 0, the | ||||
|    * palette_format is PF_DONTCARE, or the source and target formats | ||||
|    * match, the function returns the unmodified source image.  If a | ||||
|    * valid conversion is not found or invalid inputs are given (such | ||||
|    * as a direct-color source image), this function destroys the old | ||||
|    * image and returns 0. | ||||
|    * | ||||
|    * @param source          palettized image to convert | ||||
|    * @param palette_format  desired pixel format of palette | ||||
|    * | ||||
|    * @return  valid image object if conversion succeeds, 0 otherwise | ||||
|    */ | ||||
|   inline Image* ConvertPalette(Image* source, PixelFormat palette_format) { | ||||
|     return hidden::CorConvertPalette(source, palette_format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Flips the pixels in the image around the given axis. | ||||
|    * | ||||
|    * @param source           image to flip | ||||
|    * @param coordinate_axis  Axis around which to flip.  Both CA_X and CA_Y | ||||
|    *                         can be specified by ORing them together. | ||||
|    * | ||||
|    * @return  the image passed in | ||||
|    */ | ||||
|   inline Image* FlipImage(Image* source, int coordinate_axis) { | ||||
|     return hidden::CorFlipImage(source, coordinate_axis); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns a default File implementation. | ||||
|    * | ||||
|    * @param  filename   name of the file on local filesystem | ||||
|    * @param  writeable  whether the file can be written to | ||||
|    */ | ||||
|   inline File* OpenFile(const char* filename, bool writeable) { | ||||
|     return hidden::CorOpenFile(filename, writeable); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Creates a File implementation that reads from a buffer in memory. | ||||
|    * It stores a copy of the buffer that is passed in. | ||||
|    * | ||||
|    * The File object does <i>not</i> take ownership of the memory buffer. | ||||
|    * When the file is destroyed, it will not free the memory. | ||||
|    * | ||||
|    * @param buffer  Pointer to the beginning of the data. | ||||
|    * @param size    Size of the buffer in bytes. | ||||
|    * | ||||
|    * @return  0 if size is non-zero and buffer is null. Otherwise, | ||||
|    *          returns a valid File object. | ||||
|    */ | ||||
|   inline File* CreateMemoryFile(const void* buffer, int size) { | ||||
|     return hidden::CorCreateMemoryFile(buffer, size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the number of bytes needed to store a pixel of a gixen format. | ||||
|    * | ||||
|    * @param format  The format to query. | ||||
|    * | ||||
|    * @return  Number of bytes each pixel takes, or 0 if the format is invalid. | ||||
|    */ | ||||
|   inline int GetPixelSize(PixelFormat format) { | ||||
|     return hidden::CorGetPixelSize(format); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns true if the pixel format does not require a palette; that | ||||
|    * is, if each pixel itself contains color data. | ||||
|    * | ||||
|    * @param format  The format to query. | ||||
|    * | ||||
|    * @return  True if format is direct color, false otherwise. | ||||
|    */ | ||||
|   inline bool IsDirect(PixelFormat format) { | ||||
|     return (format == PF_R8G8B8A8 || format == PF_R8G8B8 || | ||||
|             format == PF_B8G8R8A8 || format == PF_B8G8R8); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns true if the pixel format requires a palette; that | ||||
|    * is, if each pixel is an index into a separate palette. | ||||
|    * | ||||
|    * @param format  The format to query. | ||||
|    * | ||||
|    * @return  True if format is palettized, false otherwise. | ||||
|    */ | ||||
|   inline bool IsPalettized(PixelFormat format) { | ||||
|     return format == PF_I8; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Returns the number of color entries in a palette for an image | ||||
|    * of the given format. | ||||
|    * | ||||
|    * @param format  The format to query. | ||||
|    * | ||||
|    * @return  Number of color entries, or 0 if the format is not palettized. | ||||
|    */ | ||||
|   inline int GetPaletteSize(PixelFormat format) { | ||||
|     return (format == PF_I8 ? 256 : 0); | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user
	 cirdan
					cirdan