Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOPNGTextureLoader.m
Go to the documentation of this file.
1/*
2
3OOPNGTextureLoader.m
4
5
6Copyright (C) 2007-2013 Jens Ayton
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25
26*/
27
30#import "OOLogging.h"
31#import "OOCPUInfo.h"
33
34//void png_error(png_structp, png_const_charp) NO_RETURN_FUNC;
35
36
37static void PNGError(png_structp png, png_const_charp message);
38static void PNGWarning(png_structp png, png_const_charp message);
39static void PNGRead(png_structp png, png_bytep bytes, png_size_t size);
40
41
42@interface OOPNGTextureLoader (OOPrivate)
43
44- (void)doLoadTexture;
45- (void)readBytes:(png_bytep)bytes count:(png_size_t)count;
46
47@end
48
49
50@implementation OOPNGTextureLoader
51
52- (void)loadTexture
53{
54 // Get data from file
55 fileData = [[NSData oo_dataWithOXZFile:_path] retain];
56 if (fileData == nil) return;
57 length = [fileData length];
58
59 [self doLoadTexture];
60
61 [fileData release];
62 fileData = nil;
63}
64
65
66- (void)dealloc
67{
68 [fileData release];
69 if (png != NULL)
70 {
71 png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
72 }
73
74 [super dealloc];
75}
76
77@end
78
79
80@implementation OOPNGTextureLoader (OOPrivate)
81
82- (void)doLoadTexture
83{
84 png_bytepp rows = NULL;
85 png_uint_32 pngWidth,
86 pngHeight;
87 int depth,
88 colorType;
89 uint32_t i;
90
91 // Set up PNG decoding
92 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, self, PNGError, PNGWarning);
93 if (png != NULL) pngInfo = png_create_info_struct(png);
94 if (pngInfo != NULL) pngEndInfo = png_create_info_struct(png);
95 if (pngEndInfo == NULL)
96 {
97 OOLog(@"texture.load.png.setup.failed", @"***** Error preparing to read %@.", _path);
98 goto FAIL;
99 }
100
101 if (EXPECT_NOT(setjmp(png_jmpbuf(png))))
102 {
103 // libpng will jump here on error.
104 if (_data)
105 {
106 free(_data);
107 _data = NULL;
108 }
109 goto FAIL;
110 }
111
112 png_set_read_fn(png, self, PNGRead);
113
114 png_read_info(png, pngInfo);
115 // Read header, get format info and check that it meets our expectations.
116 if (EXPECT_NOT(!png_get_IHDR(png, pngInfo, &pngWidth, &pngHeight, &depth, &colorType, NULL, NULL, NULL)))
117 {
118 OOLog(@"texture.load.png.failed", @"Failed to get metadata from PNG %@", _path);
119 goto FAIL;
120 }
121 png_set_strip_16(png); // 16 bits per channel -> 8 bpc
122 if (depth < 8 || colorType == PNG_COLOR_TYPE_PALETTE)
123 {
124 png_set_expand(png); // Paletted -> RGB, greyscale -> 8 bpc
125 }
126
127 if (colorType == PNG_COLOR_TYPE_GRAY)
128 {
129 _format = kOOTextureDataGrayscale;
130 }
131 else if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
132 {
134 }
135 else
136 {
137 _format = kOOTextureDataRGBA;
138
139#if OOLITE_BIG_ENDIAN
140 png_set_bgr(png);
141 png_set_swap_alpha(png); // RGBA->ARGB
142 png_set_filler(png, 0xFF, PNG_FILLER_BEFORE);
143#elif OOLITE_LITTLE_ENDIAN
144 png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
145#else
146#error Unknown handle byte order.
147#endif
148 }
149
150 png_read_update_info(png, pngInfo);
151 png_set_interlace_handling(png);
152
153 // Metadata is acceptable; load data.
154 _width = pngWidth;
155 _height = pngHeight;
156 _rowBytes = png_get_rowbytes(png, pngInfo);
157
158 // png_read_png
159 rows = malloc(sizeof *rows * _height);
160 _data = malloc(_rowBytes * _height);
161 if (EXPECT_NOT(rows == NULL || _data == NULL))
162 {
163 if (rows != NULL)
164 {
165 free(rows);
166 rows = NULL;
167 }
168 if (_data != NULL)
169 {
170 free(_data);
171 _data = NULL;
172 }
173 OOLog(kOOLogAllocationFailure, @"Failed to allocate space (%zu bytes) for texture %@", _rowBytes * _height, _path);
174 goto FAIL;
175 }
176
177 for (i = 0; i != _height; ++i)
178 {
179 rows[i] = ((png_bytep)_data) + i * _rowBytes;
180 }
181 png_read_image(png, rows);
182 png_read_end(png, pngEndInfo);
183
184FAIL:
185 free(rows);
186 png_destroy_read_struct(&png, &pngInfo, &pngEndInfo);
187}
188
189
190- (void)readBytes:(png_bytep)bytes count:(png_size_t)count
191{
192 // Check that we're within the file's bounds
193 if (EXPECT_NOT(length - offset < count))
194 {
195 NSString *message = [NSString stringWithFormat:@"attempt to read beyond end of file (%@), file may be truncated.", _path];
196 png_error(png, [message UTF8String]); // Will not return
197 }
198
199 assert(bytes != NULL);
200
201 // Copy bytes
202 memcpy(bytes, [fileData bytes] + offset, count);
203 offset += count;
204}
205
206@end
207
208
209/* Minor detail: libpng 1.4.0 removed trailing .s from error and warning
210 messages. It's also binary-incompatible with 1.2 and earlier, so it's
211 reasonable to make this test at build time.
212*/
213#if PNG_LIBPNG_VER >= 10400
214#define MSG_TERMINATOR "."
215#else
216#define MSG_TERMINATOR ""
217#endif
218
219
220static void PNGError(png_structp png, png_const_charp message)
221{
222 OOPNGTextureLoader *loader = png_get_io_ptr(png);
223 OOLog(@"texture.load.png.error", @"***** A PNG loading error occurred for %@: %s" MSG_TERMINATOR, [loader path], message);
224
225#if PNG_LIBPNG_VER >= 10500
226 png_longjmp(png, 1);
227#else
228 longjmp(png_jmpbuf(png), 1);
229#endif
230}
231
232
233static void PNGWarning(png_structp png, png_const_charp message)
234{
235 OOPNGTextureLoader *loader = png_get_io_ptr(png);
236 OOLog(@"texture.load.png.warning", @"----- A PNG loading warning occurred for %@: %s" MSG_TERMINATOR, [loader path], message);
237}
238
239
240static void PNGRead(png_structp png, png_bytep bytes, png_size_t size)
241{
242 OOPNGTextureLoader *loader = png_get_io_ptr(png);
243 [loader readBytes:bytes count:size];
244}
#define EXPECT_NOT(x)
#define FAIL(s)
#define OOLog(class, format,...)
Definition OOLogging.h:88
NSString *const kOOLogAllocationFailure
Definition OOLogging.m:649
#define MSG_TERMINATOR
static void PNGRead(png_structp png, png_bytep bytes, png_size_t size)
static void PNGError(png_structp png, png_const_charp message)
static void PNGWarning(png_structp png, png_const_charp message)
unsigned count
return nil
@ kOOTextureDataGrayscaleAlpha
Definition OOTexture.h:111
@ kOOTextureDataGrayscale
Definition OOTexture.h:110
@ kOOTextureDataRGBA
Definition OOTexture.h:109
void readBytes:count:(png_bytep bytes,[count] png_size_t count)
voidpf void uLong size
Definition ioapi.h:134
voidpf uLong offset
Definition ioapi.h:140