File: | librosprite.c |
Warning: | line 612, column 9 Potential leak of memory pointed to by 'mask_state' |
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; | |||
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 | } |