@@ -135,176 +135,8 @@ auto graphite::spriteworld::rleX::surface_offset(std::int32_t frame, std::int32_
135135
136136// MARK: - Decoding
137137
138- static inline auto rleX_calculate_sprite_geometry (
139- graphite::spriteworld::rleX *sprite,
140- graphite::quickdraw::surface& surface,
141- graphite::quickdraw::rect<std::int16_t >& rect,
142- std::uint32_t & offset,
143- std::uint32_t & right_offset_bound,
144- std::uint32_t & pitch,
145- std::uint32_t & frame
146- ) -> void {
147- rect = sprite->frame_rect (frame);
148- offset = (rect.origin .y * surface.size ().width ) + rect.origin .x ;
149- right_offset_bound = offset + rect.size .width ;
150- pitch = surface.size ().width - rect.size .width ;
151- }
152-
153- static inline auto rleX_draw_color (
154- graphite::quickdraw::surface& surface,
155- union graphite::quickdraw::ycbcr& color,
156- graphite::quickdraw::rect<std::int16_t >& rect,
157- std::uint32_t & offset,
158- std::uint32_t & right_offset_bound,
159- std::uint32_t & pitch,
160- std::uint32_t count
161- ) -> void {
162- auto rgb = graphite::quickdraw::rgb (color);
163- for (auto i = 0 ; i < count; ++i) {
164- surface.set (offset, rgb);
165- if (++offset >= right_offset_bound) {
166- offset += pitch;
167- right_offset_bound = offset + rect.size .width ;
168- }
169- }
170- }
171-
172- static auto rleX_opcode_handler_eof (
173- graphite::spriteworld::rleX *sprite,
174- graphite::quickdraw::surface& surface,
175- graphite::data::reader& reader,
176- graphite::quickdraw::rect<std::int16_t >& rect,
177- std::uint32_t & offset,
178- std::uint32_t & right_offset_bound,
179- std::uint32_t & pitch,
180- std::uint32_t & frame,
181- std::uint16_t frame_count,
182- bool & completed,
183- union graphite::quickdraw::ycbcr& color
184- ) -> void {
185- if (++frame >= frame_count) {
186- completed = true ;
187- return ;
188- }
189- rleX_calculate_sprite_geometry (sprite, surface, rect, offset, right_offset_bound, pitch, frame);
190- }
191-
192- static auto rleX_opcode_handler_set_luma (
193- graphite::spriteworld::rleX *sprite,
194- graphite::quickdraw::surface& surface,
195- graphite::data::reader& reader,
196- graphite::quickdraw::rect<std::int16_t >& rect,
197- std::uint32_t & offset,
198- std::uint32_t & right_offset_bound,
199- std::uint32_t & pitch,
200- std::uint32_t & frame,
201- std::uint16_t frame_count,
202- bool & completed,
203- union graphite::quickdraw::ycbcr& color
204- ) -> void {
205- color.components .y = reader.read_byte ();
206- }
207-
208- static auto rleX_opcode_handler_set_cr (
209- graphite::spriteworld::rleX *sprite,
210- graphite::quickdraw::surface& surface,
211- graphite::data::reader& reader,
212- graphite::quickdraw::rect<std::int16_t >& rect,
213- std::uint32_t & offset,
214- std::uint32_t & right_offset_bound,
215- std::uint32_t & pitch,
216- std::uint32_t & frame,
217- std::uint16_t frame_count,
218- bool & completed,
219- union graphite::quickdraw::ycbcr& color
220- ) -> void {
221- color.components .cr = reader.read_byte ();
222- }
223-
224- static auto rleX_opcode_handler_set_cb (
225- graphite::spriteworld::rleX *sprite,
226- graphite::quickdraw::surface& surface,
227- graphite::data::reader& reader,
228- graphite::quickdraw::rect<std::int16_t >& rect,
229- std::uint32_t & offset,
230- std::uint32_t & right_offset_bound,
231- std::uint32_t & pitch,
232- std::uint32_t & frame,
233- std::uint16_t frame_count,
234- bool & completed,
235- union graphite::quickdraw::ycbcr& color
236- ) -> void {
237- color.components .cb = reader.read_byte ();
238- }
239-
240- static auto rleX_opcode_handler_set_alpha (
241- graphite::spriteworld::rleX *sprite,
242- graphite::quickdraw::surface& surface,
243- graphite::data::reader& reader,
244- graphite::quickdraw::rect<std::int16_t >& rect,
245- std::uint32_t & offset,
246- std::uint32_t & right_offset_bound,
247- std::uint32_t & pitch,
248- std::uint32_t & frame,
249- std::uint16_t frame_count,
250- bool & completed,
251- union graphite::quickdraw::ycbcr& color
252- ) -> void {
253- color.components .alpha = reader.read_byte ();
254- }
255-
256- static auto rleX_opcode_handler_advance (
257- graphite::spriteworld::rleX *sprite,
258- graphite::quickdraw::surface& surface,
259- graphite::data::reader& reader,
260- graphite::quickdraw::rect<std::int16_t >& rect,
261- std::uint32_t & offset,
262- std::uint32_t & right_offset_bound,
263- std::uint32_t & pitch,
264- std::uint32_t & frame,
265- std::uint16_t frame_count,
266- bool & completed,
267- union graphite::quickdraw::ycbcr& color
268- ) -> void {
269- auto count = reader.read_long ();
270- rleX_draw_color (surface, color, rect, offset, right_offset_bound, pitch, count);
271- }
272-
273- static auto rleX_opcode_handler_short_advance (
274- graphite::spriteworld::rleX *sprite,
275- graphite::quickdraw::surface& surface,
276- graphite::data::reader& reader,
277- graphite::quickdraw::rect<std::int16_t >& rect,
278- std::uint32_t & offset,
279- std::uint32_t & right_offset_bound,
280- std::uint32_t & pitch,
281- std::uint32_t & frame,
282- std::uint16_t frame_count,
283- bool & completed,
284- union graphite::quickdraw::ycbcr& color
285- ) -> void {
286- auto count = reader.read_byte ();
287- rleX_draw_color (surface, color, rect, offset, right_offset_bound, pitch, static_cast <std::uint32_t >(count));
288- }
289-
290- typedef void (*rleX_opcode_handler)(
291- graphite::spriteworld::rleX*,
292- graphite::quickdraw::surface&,
293- graphite::data::reader&,
294- graphite::quickdraw::rect<std::int16_t >&,
295- std::uint32_t &,
296- std::uint32_t &,
297- std::uint32_t &,
298- std::uint32_t &,
299- std::uint16_t ,
300- bool &,
301- union graphite::quickdraw::ycbcr&
302- );
303-
304138auto graphite::spriteworld::rleX::decode (data::reader &reader) -> void
305139{
306- reader.change_byte_order (data::byte_order::lsb);
307-
308140 // Read the header of the RLE information. This will tell us what we need to do in order to actually
309141 // decode the frame.
310142 m_frame_size = quickdraw::size<std::int16_t >::read (reader, quickdraw::coding_type::macintosh);
@@ -328,51 +160,65 @@ auto graphite::spriteworld::rleX::decode(data::reader &reader) -> void
328160 // decode the RLE data correctly.
329161 m_surface = quickdraw::surface (dim * m_frame_size.width , dim * m_frame_size.height , quickdraw::colors::clear ());
330162
331- std::uint32_t current_frame = 0 ;
332- std::uint32_t count = 0 ;
333- std::uint32_t current_offset = 0 ;
163+ std::uint32_t offset = 0 ;
334164 std::uint32_t right_bound = 0 ;
335- std::uint32_t pitch = 0 ;
336-
337- bool completed_last_frame = false ;
338- auto frame = frame_rect (0 );
339-
340- union quickdraw::ycbcr yuv {
341- .components .y = 0 ,
342- .components .cb = 128 ,
343- .components .cr = 128 ,
344- .components .alpha = 255
345- };
346-
347- // NOTE: This is a very _hot_ code path and thus we need to squeeze out as much performance as possible.
348- // Build a lookup table of opcodes, in order to reduce the number of comparisons.
349- /* quickdraw::surface&, data::reader&, union quickdraw::ycbcr&, std::int32_t&, std::uint32_t&, quickdraw::rect<std::int16_t>& */
350- rleX_opcode_handler opcode_lut[] = {
351- rleX_opcode_handler_eof,
352- rleX_opcode_handler_set_luma,
353- rleX_opcode_handler_set_cr,
354- rleX_opcode_handler_set_cb,
355- rleX_opcode_handler_set_alpha,
356- rleX_opcode_handler_advance,
357- rleX_opcode_handler_short_advance
358- };
359-
360- rleX_calculate_sprite_geometry (this , m_surface, frame, current_offset, right_bound, pitch, current_frame);
361-
362- while (!completed_last_frame) {
363- opcode_lut[reader.read_byte ()](
364- this ,
365- m_surface,
366- reader,
367- frame,
368- current_offset,
369- right_bound,
370- pitch,
371- current_frame,
372- m_frame_count,
373- completed_last_frame,
374- yuv
375- );
165+ std::uint32_t pitch = m_surface.size ().width - m_frame_size.width ;
166+
167+ auto rect = frame_rect (0 );
168+ auto raw = surface ().raw ().get <std::uint8_t *>();
169+
170+
171+ for (auto frame = 0 ; frame < m_frame_count; ++frame) {
172+ rect = this ->frame_rect (frame);
173+ for (auto ch = 0 ; ch < 4 ; ++ch) {
174+ offset = (rect.origin .y * m_surface.size ().width ) + rect.origin .x ;
175+ right_bound = offset + m_frame_size.width ;
176+ auto pack_size = reader.read_long ();
177+ auto pack = reader.read_data (pack_size).get <std::uint8_t *>();
178+ auto pack_offset = 0 ;
179+
180+ while (pack_offset < pack_size) {
181+ auto run = static_cast <std::uint32_t >(pack[pack_offset++]);
182+ if (run < 0x80 ) {
183+ // Copy bytes
184+ run++;
185+ if (pack_offset + run > pack_size) {
186+ throw std::runtime_error (" Insufficient data for rlëX resource: " + std::to_string (m_id) + " , " + m_name);
187+ }
188+ for (auto i = 0 ; i < run; ++i) {
189+ raw[offset*4 + ch] = pack[pack_offset++];
190+ if (++offset >= right_bound) {
191+ offset += pitch;
192+ right_bound = offset + m_frame_size.width ;
193+ }
194+ }
195+ }
196+ else {
197+ // Repeat single byte
198+ run ^= 0x80 ;
199+ if (run >= 0x70 ) {
200+ // 2 byte count
201+ if (pack_offset == pack_size) {
202+ throw std::runtime_error (" Insufficient data for rlëX resource: " + std::to_string (m_id) + " , " + m_name);
203+ }
204+ // Combine 4 low bits with next byte
205+ run = (run & 0x0F ) << 8 | pack[pack_offset++];
206+ }
207+ run++;
208+ if (pack_offset == pack_size) {
209+ throw std::runtime_error (" Insufficient data for rlëX resource: " + std::to_string (m_id) + " , " + m_name);
210+ }
211+ auto value = pack[pack_offset++];
212+ for (auto i = 0 ; i < run; ++i) {
213+ raw[offset*4 + ch] = value;
214+ if (++offset >= right_bound) {
215+ offset += pitch;
216+ right_bound = offset + m_frame_size.width ;
217+ }
218+ }
219+ }
220+ }
221+ }
376222 }
377223}
378224
@@ -458,4 +304,4 @@ auto graphite::spriteworld::rleX::encode(data::writer &writer) -> void
458304
459305 writer.write_enum (opcode::eof);
460306 }
461- }
307+ }
0 commit comments