File: | librosprite.c |
Warning: | line 717, column 4 Value stored to 'translated_pixel' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * This file is part of librosprite. |
3 | * Licensed under the MIT License, |
4 | * http://www.opensource.org/licenses/mit-license.php |
5 | * Copyright 2008 James Shaw <js102@zepler.net> |
6 | */ |
7 | |
8 | /** |
9 | * \file |
10 | */ |
11 | |
12 | #include <assert.h> |
13 | #include <stdio.h> |
14 | #include <stdlib.h> |
15 | #include <stdint.h> |
16 | #include <stdbool.h> |
17 | #include <string.h> |
18 | |
19 | #include "librosprite.h" |
20 | |
21 | /** |
22 | * Reads four bytes, 00, 11, 22 and 33, of a byte array b to give 0x33221100. |
23 | */ |
24 | #define BTUINT(b)((unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[ 2] << 16) | ((unsigned)b[3] << 24)) \ |
25 | ((unsigned)b[0] | \ |
26 | ((unsigned)b[1] << 8) | \ |
27 | ((unsigned)b[2] << 16) | \ |
28 | ((unsigned)b[3] << 24)) |
29 | |
30 | /** |
31 | * Reverse the byte order of a word such that 0xAABBCCDD becomes 0xDDCCBBAA. |
32 | */ |
33 | #define BSWAP(word)(((word & (0x000000ff)) << 24) | ((word & 0x0000ff00 ) << 8) | ((word & 0x00ff0000) >> 8) | ((word & 0xff000000) >> 24)) (((word & (0x000000ff)) << 24) | ((word & 0x0000ff00) << 8) | ((word & 0x00ff0000) >> 8) | ((word & 0xff000000) >> 24)) |
34 | |
35 | #define ERRCHK(x)do { rosprite_error err = x; if (err != ROSPRITE_OK) return err ; } while(0) do { \ |
36 | rosprite_error err = x; \ |
37 | if (err != ROSPRITE_OK) return err; \ |
38 | } while(0) |
39 | |
40 | struct rosprite_header { |
41 | uint32_t width_words; /* width in words */ |
42 | /* height defined in sprite struct */ |
43 | uint32_t first_used_bit; /* old format only (spriteType = 0) */ |
44 | uint32_t last_used_bit; |
45 | |
46 | /** |
47 | * Image size in bytes |
48 | */ |
49 | uint32_t image_size; |
50 | |
51 | /** |
52 | * Mask size in bytes |
53 | */ |
54 | uint32_t mask_size; |
55 | }; |
56 | |
57 | struct rosprite_mask_state { |
58 | uint32_t x; |
59 | uint32_t y; |
60 | uint32_t first_used_bit; |
61 | uint32_t row_max_bit; |
62 | uint32_t height; |
63 | uint32_t current_byte_index; |
64 | uint32_t current_word; |
65 | uint32_t bpp; |
66 | }; |
67 | |
68 | struct rosprite_file_context { |
69 | FILE* f; |
70 | }; |
71 | |
72 | struct rosprite_mem_context { |
73 | uint8_t* base; |
74 | unsigned long offset; |
75 | bool_Bool known_size; |
76 | unsigned long size; |
77 | }; |
78 | |
79 | static const struct rosprite_mode oldmodes[] = { |
80 | /*0*/{ .colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
81 | /*1*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
82 | /*2*/{ .colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
83 | |
84 | /*3*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB }, |
85 | |
86 | /*4*/{ .colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
87 | /*5*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
88 | |
89 | /*6*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB }, |
90 | /*7*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB }, |
91 | |
92 | /*8*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
93 | /*9*/{ .colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
94 | /*10*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
95 | /*11*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
96 | /*12*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
97 | /*13*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
98 | /*14*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
99 | /*15*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
100 | /*16*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
101 | /*17*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
102 | /*18*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
103 | /*19*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
104 | /*20*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
105 | /*21*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
106 | /*22*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi =180, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
107 | /*23*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
108 | /*24*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
109 | /*25*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
110 | /*26*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
111 | /*27*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
112 | /*28*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
113 | /*29*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
114 | /*30*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
115 | /*31*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
116 | /*32*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
117 | /*33*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
118 | /*34*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
119 | /*35*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
120 | /*36*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
121 | /*37*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
122 | /*38*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
123 | /*39*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
124 | /*40*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
125 | /*41*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
126 | /*42*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
127 | /*43*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
128 | /*44*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
129 | /*45*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
130 | /*46*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
131 | /*47*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB }, |
132 | /*48*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 45, .ydpi = 90, .color_model = ROSPRITE_RGB }, |
133 | /*49*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 90, .color_model = ROSPRITE_RGB } |
134 | }; |
135 | |
136 | /* table for converting a 5bit channel into an 8bit channel (used for 16bpp to 32bpp conversion) */ |
137 | static const uint8_t sprite_16bpp_translate[] = { |
138 | 0x00, 0x08, 0x10, 0x18, 0x20, 0x29, 0x31, 0x39, |
139 | 0x41, 0x4a, 0x52, 0x5a, 0x62, 0x6a, 0x73, 0x7b, |
140 | 0x83, 0x8b, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbd, |
141 | 0xc5, 0xcd, 0xd5, 0xde, 0xe6, 0xee, 0xf6, 0xff |
142 | }; |
143 | |
144 | /* palettes generated with palette2c.c |
145 | * which in turn requires rosprite_load_palette(FILE* f) |
146 | * defined in this file |
147 | */ |
148 | static const uint32_t sprite_1bpp_palette[] = { 0xffffffff, 0xff }; |
149 | |
150 | static const uint32_t sprite_2bpp_palette[] = { 0xffffffff, 0xbbbbbbff, 0x777777ff, 0xff }; |
151 | |
152 | static const uint32_t sprite_4bpp_palette[] = { |
153 | 0xffffffff, 0xddddddff, 0xbbbbbbff, 0x999999ff, |
154 | 0x777777ff, 0x555555ff, 0x333333ff, 0xff, |
155 | 0x4499ff, 0xeeee00ff, 0xcc00ff, 0xdd0000ff, |
156 | 0xeeeebbff, 0x558800ff, 0xffbb00ff, 0xbbffff |
157 | }; |
158 | |
159 | static const uint32_t sprite_8bpp_palette[] = { |
160 | 0xff, 0x111111ff, 0x222222ff, 0x333333ff, |
161 | 0x440000ff, 0x551111ff, 0x662222ff, 0x773333ff, |
162 | 0x44ff, 0x111155ff, 0x222266ff, 0x333377ff, |
163 | 0x440044ff, 0x551155ff, 0x662266ff, 0x773377ff, |
164 | 0x880000ff, 0x991111ff, 0xaa2222ff, 0xbb3333ff, |
165 | 0xcc0000ff, 0xdd1111ff, 0xee2222ff, 0xff3333ff, |
166 | 0x880044ff, 0x991155ff, 0xaa2266ff, 0xbb3377ff, |
167 | 0xcc0044ff, 0xdd1155ff, 0xee2266ff, 0xff3377ff, |
168 | 0x4400ff, 0x115511ff, 0x226622ff, 0x337733ff, |
169 | 0x444400ff, 0x555511ff, 0x666622ff, 0x777733ff, |
170 | 0x4444ff, 0x115555ff, 0x226666ff, 0x337777ff, |
171 | 0x444444ff, 0x555555ff, 0x666666ff, 0x777777ff, |
172 | 0x884400ff, 0x995511ff, 0xaa6622ff, 0xbb7733ff, |
173 | 0xcc4400ff, 0xdd5511ff, 0xee6622ff, 0xff7733ff, |
174 | 0x884444ff, 0x995555ff, 0xaa6666ff, 0xbb7777ff, |
175 | 0xcc4444ff, 0xdd5555ff, 0xee6666ff, 0xff7777ff, |
176 | 0x8800ff, 0x119911ff, 0x22aa22ff, 0x33bb33ff, |
177 | 0x448800ff, 0x559911ff, 0x66aa22ff, 0x77bb33ff, |
178 | 0x8844ff, 0x119955ff, 0x22aa66ff, 0x33bb77ff, |
179 | 0x448844ff, 0x559955ff, 0x66aa66ff, 0x77bb77ff, |
180 | 0x888800ff, 0x999911ff, 0xaaaa22ff, 0xbbbb33ff, |
181 | 0xcc8800ff, 0xdd9911ff, 0xeeaa22ff, 0xffbb33ff, |
182 | 0x888844ff, 0x999955ff, 0xaaaa66ff, 0xbbbb77ff, |
183 | 0xcc8844ff, 0xdd9955ff, 0xeeaa66ff, 0xffbb77ff, |
184 | 0xcc00ff, 0x11dd11ff, 0x22ee22ff, 0x33ff33ff, |
185 | 0x44cc00ff, 0x55dd11ff, 0x66ee22ff, 0x77ff33ff, |
186 | 0xcc44ff, 0x11dd55ff, 0x22ee66ff, 0x33ff77ff, |
187 | 0x44cc44ff, 0x55dd55ff, 0x66ee66ff, 0x77ff77ff, |
188 | 0x88cc00ff, 0x99dd11ff, 0xaaee22ff, 0xbbff33ff, |
189 | 0xcccc00ff, 0xdddd11ff, 0xeeee22ff, 0xffff33ff, |
190 | 0x88cc44ff, 0x99dd55ff, 0xaaee66ff, 0xbbff77ff, |
191 | 0xcccc44ff, 0xdddd55ff, 0xeeee66ff, 0xffff77ff, |
192 | 0x88ff, 0x111199ff, 0x2222aaff, 0x3333bbff, |
193 | 0x440088ff, 0x551199ff, 0x6622aaff, 0x7733bbff, |
194 | 0xccff, 0x1111ddff, 0x2222eeff, 0x3333ffff, |
195 | 0x4400ccff, 0x5511ddff, 0x6622eeff, 0x7733ffff, |
196 | 0x880088ff, 0x991199ff, 0xaa22aaff, 0xbb33bbff, |
197 | 0xcc0088ff, 0xdd1199ff, 0xee22aaff, 0xff33bbff, |
198 | 0x8800ccff, 0x9911ddff, 0xaa22eeff, 0xbb33ffff, |
199 | 0xcc00ccff, 0xdd11ddff, 0xee22eeff, 0xff33ffff, |
200 | 0x4488ff, 0x115599ff, 0x2266aaff, 0x3377bbff, |
201 | 0x444488ff, 0x555599ff, 0x6666aaff, 0x7777bbff, |
202 | 0x44ccff, 0x1155ddff, 0x2266eeff, 0x3377ffff, |
203 | 0x4444ccff, 0x5555ddff, 0x6666eeff, 0x7777ffff, |
204 | 0x884488ff, 0x995599ff, 0xaa66aaff, 0xbb77bbff, |
205 | 0xcc4488ff, 0xdd5599ff, 0xee66aaff, 0xff77bbff, |
206 | 0x8844ccff, 0x9955ddff, 0xaa66eeff, 0xbb77ffff, |
207 | 0xcc44ccff, 0xdd55ddff, 0xee66eeff, 0xff77ffff, |
208 | 0x8888ff, 0x119999ff, 0x22aaaaff, 0x33bbbbff, |
209 | 0x448888ff, 0x559999ff, 0x66aaaaff, 0x77bbbbff, |
210 | 0x88ccff, 0x1199ddff, 0x22aaeeff, 0x33bbffff, |
211 | 0x4488ccff, 0x5599ddff, 0x66aaeeff, 0x77bbffff, |
212 | 0x888888ff, 0x999999ff, 0xaaaaaaff, 0xbbbbbbff, |
213 | 0xcc8888ff, 0xdd9999ff, 0xeeaaaaff, 0xffbbbbff, |
214 | 0x8888ccff, 0x9999ddff, 0xaaaaeeff, 0xbbbbffff, |
215 | 0xcc88ccff, 0xdd99ddff, 0xeeaaeeff, 0xffbbffff, |
216 | 0xcc88ff, 0x11dd99ff, 0x22eeaaff, 0x33ffbbff, |
217 | 0x44cc88ff, 0x55dd99ff, 0x66eeaaff, 0x77ffbbff, |
218 | 0xccccff, 0x11ddddff, 0x22eeeeff, 0x33ffffff, |
219 | 0x44ccccff, 0x55ddddff, 0x66eeeeff, 0x77ffffff, |
220 | 0x88cc88ff, 0x99dd99ff, 0xaaeeaaff, 0xbbffbbff, |
221 | 0xcccc88ff, 0xdddd99ff, 0xeeeeaaff, 0xffffbbff, |
222 | 0x88ccccff, 0x99ddddff, 0xaaeeeeff, 0xbbffffff, |
223 | 0xccccccff, 0xddddddff, 0xeeeeeeff, 0xffffffff |
224 | }; |
225 | |
226 | static inline rosprite_error rosprite_read_word(reader reader, void* ctx, uint32_t* result); |
227 | static rosprite_error rosprite_get_mode(uint32_t spriteMode, struct rosprite_mode* result); |
228 | static uint32_t rosprite_palette_lookup(struct rosprite* sprite, uint32_t pixel); |
229 | static inline uint32_t rosprite_cmyk_to_rgb(uint32_t cmyk); |
230 | static uint32_t rosprite_next_mask_pixel(uint8_t* mask, struct rosprite_mask_state* mask_state); |
231 | static rosprite_error rosprite_load_high_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header); |
232 | static rosprite_error rosprite_load_low_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header); |
233 | rosprite_error rosprite_load_sprite(reader reader, void* ctx, struct rosprite** result); |
234 | static rosprite_error rosprite_init_mask_state(struct rosprite* sprite, struct rosprite_header* header, uint8_t* mask, struct rosprite_mask_state** result); |
235 | static uint32_t rosprite_upscale_color(uint32_t pixel, struct rosprite_mode* mode, bool_Bool* has_alpha_pixel_data); |
236 | static inline void rosprite_fix_alpha(uint32_t* image, unsigned long pixels); |
237 | |
238 | rosprite_error rosprite_load(reader reader, void* ctx, struct rosprite_area** result) |
239 | { |
240 | uint32_t firstSpriteOffset, firstFreeWordOffset; |
241 | int bytes_read; |
242 | uint32_t i; |
243 | |
244 | struct rosprite_area* sprite_area = malloc(sizeof(struct rosprite_area)); |
245 | |
246 | ERRCHK(rosprite_read_word(reader, ctx, &(sprite_area->sprite_count)))do { rosprite_error err = rosprite_read_word(reader, ctx, & (sprite_area->sprite_count)); if (err != ROSPRITE_OK) return err; } while(0); |
247 | |
248 | ERRCHK(rosprite_read_word(reader, ctx, &firstSpriteOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, & firstSpriteOffset); if (err != ROSPRITE_OK) return err; } while (0); |
249 | ERRCHK(rosprite_read_word(reader, ctx, &firstFreeWordOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, & firstFreeWordOffset); if (err != ROSPRITE_OK) return err; } while (0); /* TODO: use this for some sanity checking? */ |
250 | sprite_area->extension_size = 16 - firstSpriteOffset; |
251 | |
252 | sprite_area->extension_words = NULL((void*)0); |
253 | if (sprite_area->extension_size > 0) { |
254 | sprite_area->extension_words = malloc(sprite_area->extension_size); |
255 | bytes_read = reader(sprite_area->extension_words, (size_t) (sprite_area->extension_size), ctx); |
256 | if (bytes_read < (signed long) sprite_area->extension_size) { |
257 | return ROSPRITE_EOF; |
258 | } |
259 | } |
260 | |
261 | sprite_area->sprites = malloc(sizeof(struct rosprite*) * sprite_area->sprite_count); /* allocate array of pointers */ |
262 | for (i = 0; i < sprite_area->sprite_count; i++) { |
263 | struct rosprite* sprite; |
264 | ERRCHK(rosprite_load_sprite(reader, ctx, &sprite))do { rosprite_error err = rosprite_load_sprite(reader, ctx, & sprite); if (err != ROSPRITE_OK) return err; } while(0); |
265 | sprite_area->sprites[i] = sprite; |
266 | } |
267 | |
268 | *result = sprite_area; |
269 | |
270 | return ROSPRITE_OK; |
271 | } |
272 | |
273 | void rosprite_destroy_sprite_area(struct rosprite_area* sprite_area) |
274 | { |
275 | uint32_t i; |
276 | for (i = 0; i < sprite_area->sprite_count; i++) { |
277 | struct rosprite* sprite = sprite_area->sprites[i]; |
278 | if (sprite->has_palette) free(sprite->palette); |
279 | free(sprite->image); |
280 | free(sprite); |
281 | } |
282 | |
283 | free(sprite_area->sprites); |
284 | if (sprite_area->extension_size > 0) free(sprite_area->extension_words); |
285 | free(sprite_area); |
286 | } |
287 | |
288 | rosprite_error rosprite_load_palette(reader reader, void* ctx, struct rosprite_palette** result) |
289 | { |
290 | uint32_t c; |
291 | uint8_t b[6]; |
292 | unsigned int bytesRead; |
293 | |
294 | /* TODO: currently assume palette has linear entries (2nd byte in is 00, 01, 02 etc) */ |
295 | struct rosprite_palette* palette = malloc(sizeof(struct rosprite_palette)); |
296 | |
297 | palette->palette = malloc(sizeof(uint32_t) * 256); /* allocate 256 whether we need them all or not */ |
298 | |
299 | c = 0; |
300 | |
301 | bytesRead = reader(b, 6, ctx); |
302 | assert(bytesRead % 6 == 0)((bytesRead % 6 == 0) ? (void) (0) : __assert_fail ("bytesRead % 6 == 0" , "src/librosprite.c", 302, __extension__ __PRETTY_FUNCTION__ )); |
303 | while (bytesRead == 6) { |
304 | assert(b[0] == 19)((b[0] == 19) ? (void) (0) : __assert_fail ("b[0] == 19", "src/librosprite.c" , 304, __extension__ __PRETTY_FUNCTION__)); /* VDU 19 */ |
305 | |
306 | /* only process logical colours */ |
307 | if (b[2] == 16) { |
308 | /*assert(c == b[1]);*/ |
309 | |
310 | uint32_t entry = (b[3] << 24) | (b[4] << 16) | (b[5] << 8) | 0xff; /* last byte is alpha */ |
311 | palette->palette[c] = entry; |
312 | |
313 | c++; |
314 | assert(c <= 256)((c <= 256) ? (void) (0) : __assert_fail ("c <= 256", "src/librosprite.c" , 314, __extension__ __PRETTY_FUNCTION__)); |
315 | } |
316 | |
317 | bytesRead = reader(b, 6, ctx); |
318 | assert(bytesRead % 6 == 0)((bytesRead % 6 == 0) ? (void) (0) : __assert_fail ("bytesRead % 6 == 0" , "src/librosprite.c", 318, __extension__ __PRETTY_FUNCTION__ )); |
319 | } |
320 | |
321 | palette->size = c; |
322 | |
323 | *result = palette; |
324 | |
325 | return ROSPRITE_OK; |
326 | } |
327 | |
328 | void rosprite_destroy_palette(struct rosprite_palette* palette) |
329 | { |
330 | free(palette->palette); |
331 | free(palette); |
332 | } |
333 | |
334 | rosprite_error rosprite_create_file_context(FILE* f, struct rosprite_file_context** result) |
335 | { |
336 | struct rosprite_file_context* ctx = malloc(sizeof(struct rosprite_file_context)); |
337 | if (!ctx) return ROSPRITE_NOMEM; |
338 | ctx->f = f; |
339 | *result = ctx; |
340 | |
341 | return ROSPRITE_OK; |
342 | } |
343 | |
344 | void rosprite_destroy_file_context(struct rosprite_file_context* ctx) |
345 | { |
346 | free(ctx); |
347 | } |
348 | |
349 | int rosprite_file_reader(uint8_t* buf, size_t count, void* ctx) |
350 | { |
351 | return fread(buf, 1 /*size*/, count, ((struct rosprite_file_context*) ctx)->f); |
352 | } |
353 | |
354 | rosprite_error rosprite_create_mem_context(uint8_t* p, unsigned long total_size, struct rosprite_mem_context** result) |
355 | { |
356 | struct rosprite_mem_context* ctx = malloc(sizeof(struct rosprite_mem_context)); |
357 | if (!ctx) return ROSPRITE_NOMEM; |
358 | |
359 | ctx->base = p; |
360 | ctx->offset = 0; |
361 | ctx->size = total_size; |
362 | *result = ctx; |
363 | |
364 | return ROSPRITE_OK; |
365 | } |
366 | |
367 | void rosprite_destroy_mem_context(struct rosprite_mem_context* ctx) |
368 | { |
369 | free(ctx); |
370 | } |
371 | |
372 | int rosprite_mem_reader(uint8_t* buf, size_t count, void* ctx) |
373 | { |
374 | size_t copy_size; |
375 | struct rosprite_mem_context* memctx = ctx; |
376 | |
377 | /* if we're asked for more memory than the block contains, |
378 | * only copy as much as we can |
379 | */ |
380 | if ((memctx->offset + count) > memctx->size) { |
381 | copy_size = memctx->size - memctx->offset; |
382 | } else { |
383 | copy_size = count; |
384 | } |
385 | memcpy(buf, memctx->base + memctx->offset, copy_size); |
386 | memctx->offset += copy_size; |
387 | return copy_size; |
388 | } |
389 | |
390 | /** |
391 | * Load a single sprite. |
392 | * |
393 | * \param[out] result |
394 | */ |
395 | rosprite_error rosprite_load_sprite(reader reader, void* ctx, struct rosprite** result) |
396 | { |
397 | uint32_t nextSpriteOffset; |
398 | uint32_t imageOffset; |
399 | uint32_t maskOffset, spriteModeWord; |
400 | uint32_t paletteEntries; |
401 | uint8_t* image; |
402 | uint8_t* mask = NULL((void*)0); |
403 | |
404 | struct rosprite* sprite = malloc(sizeof(struct rosprite)); |
405 | struct rosprite_header* header = malloc(sizeof(struct rosprite_header)); |
406 | |
407 | ERRCHK(rosprite_read_word(reader, ctx, &nextSpriteOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, & nextSpriteOffset); if (err != ROSPRITE_OK) return err; } while (0); |
408 | |
409 | reader(sprite->name, 12, ctx); |
410 | sprite->name[12] = '\0'; |
411 | |
412 | ERRCHK(rosprite_read_word(reader, ctx, &header->width_words))do { rosprite_error err = rosprite_read_word(reader, ctx, & header->width_words); if (err != ROSPRITE_OK) return err; } while(0); /* file has width - 1 and height - 1 */ |
413 | header->width_words += 1; |
414 | ERRCHK(rosprite_read_word(reader, ctx, &(sprite->height)))do { rosprite_error err = rosprite_read_word(reader, ctx, & (sprite->height)); if (err != ROSPRITE_OK) return err; } while (0); |
415 | sprite->height += 1; |
416 | ERRCHK(rosprite_read_word(reader, ctx, &(header->first_used_bit)))do { rosprite_error err = rosprite_read_word(reader, ctx, & (header->first_used_bit)); if (err != ROSPRITE_OK) return err ; } while(0); /* old format only (spriteType = 0) */ |
417 | ERRCHK(rosprite_read_word(reader, ctx, &(header->last_used_bit)))do { rosprite_error err = rosprite_read_word(reader, ctx, & (header->last_used_bit)); if (err != ROSPRITE_OK) return err ; } while(0); |
418 | |
419 | ERRCHK(rosprite_read_word(reader, ctx, &imageOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, & imageOffset); if (err != ROSPRITE_OK) return err; } while(0); |
420 | assert(imageOffset >= 44)((imageOffset >= 44) ? (void) (0) : __assert_fail ("imageOffset >= 44" , "src/librosprite.c", 420, __extension__ __PRETTY_FUNCTION__ )); /* should never be smaller than the size of the header) */ |
421 | |
422 | ERRCHK(rosprite_read_word(reader, ctx, &maskOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, & maskOffset); if (err != ROSPRITE_OK) return err; } while(0); |
423 | ERRCHK(rosprite_read_word(reader, ctx, &spriteModeWord))do { rosprite_error err = rosprite_read_word(reader, ctx, & spriteModeWord); if (err != ROSPRITE_OK) return err; } while( 0); |
424 | |
425 | ERRCHK(rosprite_get_mode(spriteModeWord, &(sprite->mode)))do { rosprite_error err = rosprite_get_mode(spriteModeWord, & (sprite->mode)); if (err != ROSPRITE_OK) return err; } while (0); |
426 | |
427 | /* TODO left-hand wastage */ |
428 | |
429 | assert((header->last_used_bit + 1) % sprite->mode.colorbpp == 0)(((header->last_used_bit + 1) % sprite->mode.colorbpp == 0) ? (void) (0) : __assert_fail ("(header->last_used_bit + 1) % sprite->mode.colorbpp == 0" , "src/librosprite.c", 429, __extension__ __PRETTY_FUNCTION__ )); |
430 | /*assert(header->width_words % sprite->mode->colorbpp == 0);*/ |
431 | sprite->width = (header->width_words * 32 - header->first_used_bit - (31 - header->last_used_bit)) / sprite->mode.colorbpp; |
432 | |
433 | sprite->palettesize = imageOffset - 44; |
434 | sprite->has_palette = (sprite->palettesize > 0); |
435 | |
436 | /* sprite has no mask if imageOffset == maskOffset */ |
437 | if (imageOffset == maskOffset) { |
438 | sprite->has_mask = false0; |
439 | header->image_size = nextSpriteOffset - 44 - sprite->palettesize; |
440 | header->mask_size = 0; |
441 | } else { |
442 | sprite->has_mask = true1; |
443 | header->image_size = maskOffset - imageOffset; |
444 | header->mask_size = nextSpriteOffset - 44 - sprite->palettesize - header->image_size; |
445 | } |
446 | |
447 | if (sprite->has_palette) { |
448 | uint32_t j, word1, word2, entry; |
449 | assert(sprite->palettesize % 8 == 0)((sprite->palettesize % 8 == 0) ? (void) (0) : __assert_fail ("sprite->palettesize % 8 == 0", "src/librosprite.c", 449 , __extension__ __PRETTY_FUNCTION__)); |
450 | sprite->palette = malloc(sizeof(uint32_t) * sprite->palettesize); |
451 | paletteEntries = sprite->palettesize / 8; |
452 | |
453 | /* Each palette entry is two words big |
454 | * The second word is a duplicate of the first |
455 | * I think this is in case you ever wanted flashing colours |
456 | * PRM1-730 |
457 | */ |
458 | for (j = 0; j < paletteEntries; j++) { |
459 | ERRCHK(rosprite_read_word(reader, ctx, &word1))do { rosprite_error err = rosprite_read_word(reader, ctx, & word1); if (err != ROSPRITE_OK) return err; } while(0); |
460 | ERRCHK(rosprite_read_word(reader, ctx, &word2))do { rosprite_error err = rosprite_read_word(reader, ctx, & word2); if (err != ROSPRITE_OK) return err; } while(0); |
461 | assert(word1 == word2)((word1 == word2) ? (void) (0) : __assert_fail ("word1 == word2" , "src/librosprite.c", 461, __extension__ __PRETTY_FUNCTION__ )); /* if they aren't equal, flashing colours are desired, which we don't support */ |
462 | |
463 | /* swap rr and bb parts -- PRM1-731 */ |
464 | entry = ((word1 & 0xff000000) >> 16) | (word1 & 0x00ff0000) | ((word1 & 0x0000ff00) << 16) | 0xff; |
465 | sprite->palette[j] = entry; |
466 | } |
467 | } |
468 | |
469 | image = malloc(header->image_size); |
470 | reader(image, header->image_size, ctx); |
471 | |
472 | if (sprite->has_mask) { |
473 | mask = malloc(header->mask_size); |
474 | reader(mask, header->mask_size, ctx); |
475 | } |
476 | |
477 | /* sanity check image_size */ |
478 | assert((header->width_words) * 4 * (sprite->height) == header->image_size)(((header->width_words) * 4 * (sprite->height) == header ->image_size) ? (void) (0) : __assert_fail ("(header->width_words) * 4 * (sprite->height) == header->image_size" , "src/librosprite.c", 478, __extension__ __PRETTY_FUNCTION__ )); |
479 | /* TODO: sanity check mask_size */ |
480 | if (sprite->mode.colorbpp > 8) { |
481 | ERRCHK(rosprite_load_high_color(image, mask, sprite, header))do { rosprite_error err = rosprite_load_high_color(image, mask , sprite, header); if (err != ROSPRITE_OK) return err; } while (0); |
482 | } else { |
483 | ERRCHK(rosprite_load_low_color(image, mask, sprite, header))do { rosprite_error err = rosprite_load_low_color(image, mask , sprite, header); if (err != ROSPRITE_OK) return err; } while (0); |
484 | } |
485 | |
486 | free(image); |
487 | free(mask); |
488 | free(header); |
489 | |
490 | *result = sprite; |
491 | |
492 | return ROSPRITE_OK; |
493 | } |
494 | |
495 | /** |
496 | * Determine the sprite_mode for the specified sprite_mode_word. |
497 | * |
498 | * \param[out] result |
499 | */ |
500 | static rosprite_error rosprite_get_mode(uint32_t sprite_mode_word, struct rosprite_mode* result) |
501 | { |
502 | struct rosprite_mode mode; |
503 | |
504 | uint32_t spriteType = (sprite_mode_word & (15 << 27)) >> 27; /* preserve bits 27-30 only */ |
505 | |
506 | if (spriteType != 0) { |
507 | bool_Bool hasEightBitAlpha = sprite_mode_word >> 31; /* bit 31 */ |
508 | /* new modes have 1bpp masks (PRM5a-111) |
509 | * unless bit 31 is set (http://select.riscos.com/prm/graphics/sprites/alphachannel.html) |
510 | */ |
511 | mode.maskbpp = (hasEightBitAlpha ? 8 : 1); |
512 | mode.mask_width = mode.maskbpp; |
513 | mode.xdpi = (sprite_mode_word & (8191 << 14)) >> 14; /* preserve bits 14-26 only */ |
514 | mode.ydpi = (sprite_mode_word & (8191 << 1)) >> 1; /* preserve bits 1-13 only */ |
515 | |
516 | mode.color_model = ROSPRITE_RGB; |
517 | switch (spriteType) { |
518 | case 1: |
519 | mode.colorbpp = 1; break; |
520 | case 2: |
521 | mode.colorbpp = 2; break; |
522 | case 3: |
523 | mode.colorbpp = 4; break; |
524 | case 4: |
525 | mode.colorbpp = 8; break; |
526 | case 5: |
527 | mode.colorbpp = 16; break; |
528 | case 6: |
529 | mode.colorbpp = 32; break; |
530 | case 7: |
531 | mode.colorbpp = 32; |
532 | mode.color_model = ROSPRITE_CMYK; |
533 | break; |
534 | case 8: |
535 | mode.colorbpp = 24; break; |
536 | default: |
537 | return ROSPRITE_BADMODE; |
538 | } |
539 | } else { |
540 | assert(sprite_mode_word < 256)((sprite_mode_word < 256) ? (void) (0) : __assert_fail ("sprite_mode_word < 256" , "src/librosprite.c", 540, __extension__ __PRETTY_FUNCTION__ )); /* don't think you can have modes over 255? */ |
541 | |
542 | mode = oldmodes[sprite_mode_word]; |
543 | } |
544 | |
545 | /* illegal mode check */ |
546 | if ((mode.colorbpp == 0) || (mode.xdpi == 0) || (mode.ydpi == 0)) { |
547 | return ROSPRITE_BADMODE; |
548 | } |
549 | |
550 | memcpy(result, &mode, sizeof(struct rosprite_mode)); |
551 | |
552 | return ROSPRITE_OK; |
553 | } |
554 | |
555 | /** |
556 | * Load a sprite image with 16 or more bpp. |
557 | * |
558 | * \param[out] sprite On exit, sprite.image will be populated |
559 | */ |
560 | static rosprite_error rosprite_load_high_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header) |
561 | { |
562 | struct rosprite_mask_state* mask_state = NULL((void*)0); |
563 | uint32_t currentByteIndex = 0; |
564 | uint32_t j, x, y, x_pixels, pixel; |
565 | bool_Bool has_alpha_pixel_data = false0; |
566 | uint32_t b; |
567 | bool_Bool old_has_alpha; |
568 | |
569 | if (sprite->has_mask) { |
570 | ERRCHK(rosprite_init_mask_state(sprite, header, mask, &mask_state))do { rosprite_error err = rosprite_init_mask_state(sprite, header , mask, &mask_state); if (err != ROSPRITE_OK) return err; } while(0); |
571 | } |
572 | |
573 | sprite->image = malloc(sprite->width * sprite->height * 4); /* all image data is 32bpp going out */ |
574 | |
575 | /* Spec says that there must be no left-hand wastage */ |
576 | assert(header->first_used_bit == 0)((header->first_used_bit == 0) ? (void) (0) : __assert_fail ("header->first_used_bit == 0", "src/librosprite.c", 576, __extension__ __PRETTY_FUNCTION__)); |
577 | |
578 | { |
579 | const uint32_t bpp = sprite->mode.colorbpp; |
580 | const uint32_t bytesPerPixel = bpp / 8; |
581 | const uint32_t row_max_bit = header->width_words * 32 - (31 - header->last_used_bit); /* Last used bit in row */ |
582 | |
583 | for (y = 0; y < sprite->height; y++) { |
584 | x_pixels = 0; |
585 | for (x = 0; x < row_max_bit; x += bpp) { |
586 | pixel = 0; |
587 | for (j = 0; j < bytesPerPixel; j++) { |
588 | b = image_in[currentByteIndex++]; |
589 | pixel = pixel | (b << (j * 8)); |
590 | } |
591 | |
592 | old_has_alpha = has_alpha_pixel_data; |
593 | pixel = rosprite_upscale_color(pixel, &(sprite->mode), &has_alpha_pixel_data); |
594 | if (old_has_alpha != has_alpha_pixel_data && (y > 0 || x_pixels > 0)) { |
595 | rosprite_fix_alpha(sprite->image, (y * sprite->width) + x_pixels - 1); |
596 | } |
597 | if (sprite->has_mask) { |
598 | uint8_t mask_pixel = rosprite_next_mask_pixel(mask, mask_state); |
599 | pixel = (pixel & 0xffffff00) | mask_pixel; |
600 | } |
601 | sprite->image[y*sprite->width + x_pixels] = pixel; |
602 | x_pixels++; |
603 | } |
604 | |
605 | /* Ensure byte index is pointing at start of next row */ |
606 | if (y + 1 < sprite->height) { |
607 | currentByteIndex = (currentByteIndex + 3) & ~3; /* Round up to next multiple of 4 */ |
608 | } |
609 | } |
610 | } |
611 | if (sprite->has_mask) free(mask_state); |
612 | return ROSPRITE_OK; |
613 | } |
614 | |
615 | /** |
616 | * Iterate over the specified number of pixels, starting at the image pointer, |
617 | * and set the alpha channel to 0x00. |
618 | */ |
619 | static inline void rosprite_fix_alpha(uint32_t* image, unsigned long pixels) |
620 | { |
621 | uint32_t i; |
622 | for (i = 0; i <= pixels; i++) { |
623 | image[i] = image[i] & 0xffffff00; |
624 | } |
625 | } |
626 | |
627 | /** |
628 | * Load a sprite image with 8 or fewer bpp. |
629 | * |
630 | * \param[out] sprite On exit, sprite.image will be populated |
631 | */ |
632 | static rosprite_error rosprite_load_low_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header) |
633 | { |
634 | uint32_t current_byte_index, currentword; |
635 | uint32_t x, y, x_pixels, pixel; |
636 | uint8_t mask_pixel; |
637 | |
638 | struct rosprite_mask_state* mask_state = NULL((void*)0); |
639 | if (sprite->has_mask) { |
640 | ERRCHK(rosprite_init_mask_state(sprite, header, mask, &mask_state))do { rosprite_error err = rosprite_init_mask_state(sprite, header , mask, &mask_state); if (err != ROSPRITE_OK) return err; } while(0); |
641 | } |
642 | |
643 | sprite->image = malloc(sprite->width * sprite->height * 4); /* all image data is 32bpp going out */ |
644 | |
645 | { |
646 | const uint32_t bpp = sprite->mode.colorbpp; |
647 | const uint32_t row_max_bit = header->width_words * 32 - (31 - header->last_used_bit); /* Last used bit in row */ |
648 | const uint32_t bitmask = (1 << bpp) - 1; /* creates a mask of 1s that is bpp bits wide */ |
649 | |
650 | current_byte_index = 0; |
651 | currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in + current_byte_index)[1] << 8) | ((unsigned)(image_in + current_byte_index)[2] << 16) | ((unsigned)(image_in + current_byte_index)[3] << 24)); |
652 | current_byte_index += 4; |
653 | |
654 | for (y = 0; y < sprite->height; y++) { |
655 | x_pixels = 0; |
656 | for (x = header->first_used_bit; x < row_max_bit ; x += bpp) { |
657 | const uint32_t offset_into_word = x % 32; |
658 | |
659 | pixel = (currentword & (bitmask << offset_into_word)) >> offset_into_word; |
660 | pixel = rosprite_palette_lookup(sprite, pixel); /* lookup returns 32bpp */ |
661 | if (sprite->has_mask) { |
662 | mask_pixel = rosprite_next_mask_pixel(mask, mask_state); |
663 | pixel = (pixel & 0xffffff00) | mask_pixel; |
664 | } |
665 | sprite->image[y*sprite->width + x_pixels] = pixel; |
666 | x_pixels++; |
667 | |
668 | /* If we're not at the end of the row and we've processed all of this word, fetch the next one */ |
669 | if (x + bpp < row_max_bit && offset_into_word + bpp == 32) { |
670 | currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in + current_byte_index)[1] << 8) | ((unsigned)(image_in + current_byte_index)[2] << 16) | ((unsigned)(image_in + current_byte_index)[3] << 24)); |
671 | current_byte_index += 4; |
672 | } |
673 | } |
674 | |
675 | /* Advance to first word of next row */ |
676 | if (y + 1 < sprite->height) { |
677 | currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in + current_byte_index)[1] << 8) | ((unsigned)(image_in + current_byte_index)[2] << 16) | ((unsigned)(image_in + current_byte_index)[3] << 24)); |
678 | current_byte_index += 4; |
679 | } |
680 | } |
681 | } |
682 | if (sprite->has_mask) free(mask_state); |
683 | |
684 | return ROSPRITE_OK; |
685 | } |
686 | |
687 | static uint32_t rosprite_palette_lookup(struct rosprite* sprite, uint32_t pixel) |
688 | { |
689 | uint32_t translated_pixel; |
690 | /* because we're dealing with 8bpp or less */ |
691 | if (sprite->has_palette) { |
692 | |
693 | if(pixel < (sprite->palettesize / 8)) { |
694 | translated_pixel = sprite->palette[pixel]; |
695 | } else { |
696 | translated_pixel = sprite_8bpp_palette[pixel]; |
697 | } |
698 | } else { |
699 | switch (sprite->mode.colorbpp) { |
700 | case 8: |
701 | assert(pixel < 256)((pixel < 256) ? (void) (0) : __assert_fail ("pixel < 256" , "src/librosprite.c", 701, __extension__ __PRETTY_FUNCTION__ )); |
702 | translated_pixel = sprite_8bpp_palette[pixel]; |
703 | break; |
704 | case 4: |
705 | assert(pixel < 16)((pixel < 16) ? (void) (0) : __assert_fail ("pixel < 16" , "src/librosprite.c", 705, __extension__ __PRETTY_FUNCTION__ )); |
706 | translated_pixel = sprite_4bpp_palette[pixel]; |
707 | break; |
708 | case 2: |
709 | assert(pixel < 4)((pixel < 4) ? (void) (0) : __assert_fail ("pixel < 4", "src/librosprite.c", 709, __extension__ __PRETTY_FUNCTION__) ); |
710 | translated_pixel = sprite_2bpp_palette[pixel]; |
711 | break; |
712 | case 1: |
713 | assert(pixel < 2)((pixel < 2) ? (void) (0) : __assert_fail ("pixel < 2", "src/librosprite.c", 713, __extension__ __PRETTY_FUNCTION__) ); |
714 | translated_pixel = sprite_1bpp_palette[pixel]; |
715 | break; |
716 | default: |
717 | translated_pixel = 0; |
Value stored to 'translated_pixel' is never read | |
718 | assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c" , 718, __extension__ __PRETTY_FUNCTION__)); |
719 | } |
720 | } |
721 | return translated_pixel; |
722 | } |
723 | |
724 | static rosprite_error rosprite_init_mask_state(struct rosprite* sprite, struct rosprite_header* header, uint8_t* mask, struct rosprite_mask_state** result) |
725 | { |
726 | struct rosprite_mask_state* mask_state = malloc(sizeof(struct rosprite_mask_state)); |
727 | if (!mask_state) return ROSPRITE_NOMEM; |
728 | |
729 | mask_state->x = header->first_used_bit; |
730 | mask_state->y = 0; |
731 | mask_state->first_used_bit = header->first_used_bit; |
732 | mask_state->row_max_bit = sprite->width * sprite->mode.mask_width; |
733 | mask_state->height = sprite->height; |
734 | mask_state->bpp = sprite->mode.mask_width; |
735 | mask_state->current_word = BTUINT(mask)((unsigned)mask[0] | ((unsigned)mask[1] << 8) | ((unsigned )mask[2] << 16) | ((unsigned)mask[3] << 24)); |
736 | mask_state->current_byte_index = 4; |
737 | |
738 | *result = mask_state; |
739 | |
740 | return ROSPRITE_OK; |
741 | } |
742 | |
743 | /** |
744 | * Get the next mask byte. |
745 | * A mask of 0xff denotes 100% opaque, 0x00 denotes 100% transparent. |
746 | * |
747 | * \param[in,out] mask_state |
748 | */ |
749 | static uint32_t rosprite_next_mask_pixel(uint8_t* mask, struct rosprite_mask_state* mask_state) |
750 | { |
751 | /* a 1bpp mask (for new mode sprites), each row is word aligned (therefore potential righthand wastage */ |
752 | const uint32_t bitmask = (1 << mask_state->bpp) - 1; |
753 | const uint32_t offset_into_word = mask_state->x % 32; |
754 | uint32_t pixel = (mask_state->current_word & (bitmask << offset_into_word)) >> offset_into_word; |
755 | |
756 | if (mask_state->x + mask_state->bpp < mask_state->row_max_bit && offset_into_word + mask_state->bpp == 32) { |
757 | mask_state->current_word = BTUINT((mask + mask_state->current_byte_index))((unsigned)(mask + mask_state->current_byte_index)[0] | (( unsigned)(mask + mask_state->current_byte_index)[1] << 8) | ((unsigned)(mask + mask_state->current_byte_index)[2 ] << 16) | ((unsigned)(mask + mask_state->current_byte_index )[3] << 24)); |
758 | mask_state->current_byte_index += 4; |
759 | } |
760 | |
761 | mask_state->x += mask_state->bpp; |
762 | if (mask_state->x >= mask_state->row_max_bit) { |
763 | mask_state->x = mask_state->first_used_bit; |
764 | |
765 | if (mask_state->y + 1 < mask_state->height) { |
766 | mask_state->current_word = BTUINT((mask + mask_state->current_byte_index))((unsigned)(mask + mask_state->current_byte_index)[0] | (( unsigned)(mask + mask_state->current_byte_index)[1] << 8) | ((unsigned)(mask + mask_state->current_byte_index)[2 ] << 16) | ((unsigned)(mask + mask_state->current_byte_index )[3] << 24)); |
767 | mask_state->current_byte_index += 4; |
768 | } |
769 | |
770 | mask_state->y++; |
771 | } |
772 | |
773 | /* |
774 | * if the mask is 1bpp, make sure the whole byte is 0x00 or 0xff |
775 | */ |
776 | if (mask_state->bpp < 8) { |
777 | pixel = (pixel & 1) ? 0xff : 0x00; |
778 | } |
779 | |
780 | return pixel; |
781 | } |
782 | |
783 | /** |
784 | * Upscale a 16, 24 or 32bpp sprite to the 0xRRGGBBAA representation. |
785 | * Do not call this function with a sprite with less than 16bpp, |
786 | * but use a palette lookup instead. |
787 | */ |
788 | static uint32_t rosprite_upscale_color(uint32_t pixel, struct rosprite_mode* mode, bool_Bool* has_alpha_pixel_data) |
789 | { |
790 | uint8_t alpha; |
791 | switch (mode->colorbpp) { |
792 | case 32: |
793 | if (mode->color_model == ROSPRITE_RGB) { |
794 | /* swap from 0xAABBGGRR to 0xRRGGBBAA */ |
795 | pixel = BSWAP(pixel)(((pixel & (0x000000ff)) << 24) | ((pixel & 0x0000ff00 ) << 8) | ((pixel & 0x00ff0000) >> 8) | ((pixel & 0xff000000) >> 24)); |
796 | } else { |
797 | pixel = rosprite_cmyk_to_rgb(pixel); |
798 | } |
799 | break; |
800 | case 24: |
801 | /* reverse byte order */ |
802 | pixel = BSWAP(pixel)(((pixel & (0x000000ff)) << 24) | ((pixel & 0x0000ff00 ) << 8) | ((pixel & 0x00ff0000) >> 8) | ((pixel & 0xff000000) >> 24)); |
803 | break; |
804 | case 16: |
805 | /* incoming format is b_00000000000000000bbbbbgggggrrrrr */ |
806 | { |
807 | uint8_t red = pixel & 31; |
808 | uint8_t green = (pixel & (31 << 5)) >> 5; |
809 | uint8_t blue = (pixel & (31 << 10)) >> 10; |
810 | |
811 | /* sanity check */ |
812 | assert(red < 32)((red < 32) ? (void) (0) : __assert_fail ("red < 32", "src/librosprite.c" , 812, __extension__ __PRETTY_FUNCTION__)); |
813 | assert(green < 32)((green < 32) ? (void) (0) : __assert_fail ("green < 32" , "src/librosprite.c", 813, __extension__ __PRETTY_FUNCTION__ )); |
814 | assert(blue < 32)((blue < 32) ? (void) (0) : __assert_fail ("blue < 32", "src/librosprite.c", 814, __extension__ __PRETTY_FUNCTION__) ); |
815 | |
816 | pixel = ((uint32_t)sprite_16bpp_translate[red] << 24)| |
817 | ((uint32_t)sprite_16bpp_translate[green] << 16)| |
818 | ((uint32_t)sprite_16bpp_translate[blue] << 8); |
819 | } |
820 | break; |
821 | case 8: |
822 | case 4: |
823 | case 2: |
824 | case 1: |
825 | assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c" , 825, __extension__ __PRETTY_FUNCTION__)); /* shouldn't need to call for <= 8bpp, since a palette lookup will return 32bpp */ |
826 | default: |
827 | assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c" , 827, __extension__ __PRETTY_FUNCTION__)); /* unknown bpp */ |
828 | } |
829 | |
830 | alpha = pixel & 0xff; |
831 | if (alpha == 0x00) { |
832 | if (!(*has_alpha_pixel_data)) { |
833 | pixel = pixel | 0xff; |
834 | } |
835 | } else { |
836 | *has_alpha_pixel_data = true1; |
837 | } |
838 | return pixel; |
839 | } |
840 | |
841 | static inline uint32_t rosprite_cmyk_to_rgb(uint32_t cmyk) |
842 | { |
843 | uint8_t c = cmyk & 0xff; |
844 | uint8_t m = (cmyk & 0xff00) >> 8; |
845 | uint8_t y = (cmyk & 0xff0000) >> 16; |
846 | uint8_t k = cmyk >> 24; |
847 | |
848 | /* Convert to CMY colourspace */ |
849 | uint8_t C = c + k; |
850 | uint8_t M = m + k; |
851 | uint8_t Y = y + k; |
852 | |
853 | /* And to RGB */ |
854 | uint8_t r = 255 - C; |
855 | uint8_t g = 255 - M; |
856 | uint8_t b = 255 - Y; |
857 | |
858 | return r << 24 | g << 16 | b << 8; |
859 | } |
860 | |
861 | static inline rosprite_error rosprite_read_word(reader reader, void* ctx, uint32_t* result) |
862 | { |
863 | unsigned char b[4]; |
864 | if (reader(b, 4, ctx) < 4) { |
865 | return ROSPRITE_EOF; |
866 | } |
867 | *result = BTUINT(b)((unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[ 2] << 16) | ((unsigned)b[3] << 24)); |
868 | return ROSPRITE_OK; |
869 | } |