Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | /* |
||
| 20 | * |
||
| 21 | * Protypes for rle functions. |
||
| 22 | * |
||
| 23 | */ |
||
| 24 | |||
| 25 | #pragma once |
||
| 26 | |||
| 27 | #include "pstypes.h" |
||
| 28 | #include "gr.h" |
||
| 29 | |||
| 30 | #include <cstdint> |
||
| 31 | #include "dxxsconf.h" |
||
| 32 | #include "dsx-ns.h" |
||
| 33 | #include "compiler-poison.h" |
||
| 34 | #include <iterator> |
||
| 35 | |||
| 36 | struct rle_position_t |
||
| 37 | { |
||
| 38 | const uint8_t *src; |
||
| 39 | uint8_t *dst; |
||
| 40 | }; |
||
| 41 | |||
| 42 | static inline const uint8_t *end(const grs_bitmap &b) |
||
| 43 | { |
||
| 44 | return &b.bm_data[b.bm_h * b.bm_w]; |
||
| 45 | } |
||
| 46 | |||
| 47 | static inline uint8_t *end(grs_bitmap &b) |
||
| 48 | { |
||
| 49 | return &b.get_bitmap_data()[b.bm_h * b.bm_w]; |
||
| 50 | } |
||
| 51 | |||
| 52 | template <typename T1, typename T2> |
||
| 53 | static inline rle_position_t rle_end(const T1 &src, T2 &dst) |
||
| 54 | { |
||
| 55 | return {end(src), end(dst)}; |
||
| 56 | } |
||
| 57 | |||
| 58 | namespace dcx { |
||
| 59 | uint8_t *gr_rle_decode(const uint8_t *sb, uint8_t *db, rle_position_t e); |
||
| 60 | int gr_bitmap_rle_compress(grs_bitmap &bmp); |
||
| 61 | #if !DXX_USE_OGL |
||
| 62 | void gr_rle_expand_scanline_masked(uint8_t *dest, const uint8_t *src, int x1, int x2); |
||
| 63 | #endif |
||
| 64 | void gr_rle_expand_scanline(uint8_t *dest, const uint8_t *src, int x1, int x2); |
||
| 65 | grs_bitmap *_rle_expand_texture(const grs_bitmap &bmp); |
||
| 66 | static inline const grs_bitmap *rle_expand_texture(const grs_bitmap &bmp) __attribute_warn_unused_result; |
||
| 67 | static inline const grs_bitmap *rle_expand_texture(const grs_bitmap &bmp) |
||
| 68 | { |
||
| 69 | if (bmp.get_flag_mask(BM_FLAG_RLE)) |
||
| 70 | return _rle_expand_texture(bmp); |
||
| 71 | return &bmp; |
||
| 72 | } |
||
| 73 | void rle_cache_close(); |
||
| 74 | void rle_cache_flush(); |
||
| 75 | void rle_swap_0_255(grs_bitmap &bmp); |
||
| 76 | void rle_remap(grs_bitmap &bmp, std::array<color_palette_index, 256> &colormap); |
||
| 77 | #if !DXX_USE_OGL |
||
| 78 | #define gr_rle_expand_scanline_generic(C,D,DX,DY,S,X1,X2) gr_rle_expand_scanline_generic(D,DX,DY,S,X1,X2) |
||
| 79 | void gr_rle_expand_scanline_generic(grs_canvas &, grs_bitmap &dest, int dx, int dy, const ubyte *src, int x1, int x2 ); |
||
| 80 | #endif |
||
| 81 | |||
| 82 | class bm_rle_expand_range |
||
| 83 | { |
||
| 84 | uint8_t *iter_dbits; |
||
| 85 | uint8_t *const end_dbits; |
||
| 86 | public: |
||
| 87 | bm_rle_expand_range(uint8_t *const i, uint8_t *const e) : |
||
| 88 | iter_dbits(i), end_dbits(e) |
||
| 89 | { |
||
| 90 | } |
||
| 91 | template <std::size_t N> |
||
| 92 | bm_rle_expand_range(std::array<uint8_t, N> &a) : |
||
| 93 | iter_dbits(a.data()), end_dbits(std::next(iter_dbits, N)) |
||
| 94 | { |
||
| 95 | } |
||
| 96 | uint8_t *get_begin_dbits() const |
||
| 97 | { |
||
| 98 | return iter_dbits; |
||
| 99 | } |
||
| 100 | uint8_t *get_end_dbits() const |
||
| 101 | { |
||
| 102 | return end_dbits; |
||
| 103 | } |
||
| 104 | void consume_dbits(const unsigned w) |
||
| 105 | { |
||
| 106 | iter_dbits += w; |
||
| 107 | } |
||
| 108 | }; |
||
| 109 | |||
| 110 | class bm_rle_src_stride |
||
| 111 | { |
||
| 112 | /* Width of an individual element of the table of row lengths. This |
||
| 113 | * is sizeof(uint8_t) if the bitmap is not RLE_BIG, or is |
||
| 114 | * sizeof(uint16_t) otherwise. |
||
| 115 | */ |
||
| 116 | const unsigned src_bit_stride_size; |
||
| 117 | /* Bitmask used for filtering the table load. To minimize |
||
| 118 | * branching, the code always loads two bytes from the table of row |
||
| 119 | * lengths. If the bitmap is not RLE_BIG, then `src_bit_load_mask` |
||
| 120 | * will be 0xff and will be used to mask out the high byte from the |
||
| 121 | * load. Otherwise, `src_bit_load_mask` will be 0xffff and the mask |
||
| 122 | * operation will leave the loaded value unchanged. |
||
| 123 | */ |
||
| 124 | const unsigned src_bit_load_mask; |
||
| 125 | protected: |
||
| 126 | /* Pointer to the table of row lengths. The table is uint8_t[] if |
||
| 127 | * the bitmap is not RLE_BIG, or is uint16_t[] otherwise. The table |
||
| 128 | * is not required to be aligned. |
||
| 129 | */ |
||
| 130 | const uint8_t *ptr_src_bit_lengths; |
||
| 131 | /* Pointer to the table of RLE-encoded bitmap elements. |
||
| 132 | */ |
||
| 133 | const uint8_t *src_bits; |
||
| 134 | public: |
||
| 135 | bm_rle_src_stride(const grs_bitmap &src, const unsigned rle_big) : |
||
| 136 | /* Jump threading should collapse the separate ?: uses */ |
||
| 137 | src_bit_stride_size(rle_big ? sizeof(uint16_t) : sizeof(uint8_t)), |
||
| 138 | src_bit_load_mask(rle_big ? 0xffff : 0xff), |
||
| 139 | ptr_src_bit_lengths(&src.bm_data[4]), |
||
| 140 | src_bits(&ptr_src_bit_lengths[rle_big ? src.bm_h * 2 : src.bm_h]) |
||
| 141 | { |
||
| 142 | } |
||
| 143 | void advance_src_bits(); |
||
| 144 | }; |
||
| 145 | |||
| 146 | class bm_rle_expand : bm_rle_src_stride |
||
| 147 | { |
||
| 148 | /* Pointer to the first byte that is not part of the table of row |
||
| 149 | * lengths. When `ptr_src_bit_lengths` == `end_src_bit_lengths`, no |
||
| 150 | * further rows are available. |
||
| 151 | */ |
||
| 152 | const uint8_t *const end_src_bit_lengths; |
||
| 153 | /* Pointer to the first byte that is not part of the bitmap data. |
||
| 154 | * When `end_src_bm` == `src_bits`, no further bitmap elements are |
||
| 155 | * available. |
||
| 156 | */ |
||
| 157 | const uint8_t *const end_src_bm; |
||
| 158 | public: |
||
| 159 | enum step_result |
||
| 160 | { |
||
| 161 | /* A row decoded successfully. Act on the decoded buffer as |
||
| 162 | * necessary, then call this class again. |
||
| 163 | * |
||
| 164 | * This result is returned even if the returned row is the last |
||
| 165 | * row. The first call after the last row will return |
||
| 166 | * src_exhausted, which is the trigger to stop calling the |
||
| 167 | * class. |
||
| 168 | */ |
||
| 169 | again, |
||
| 170 | /* The source was exhausted before any work was done. No data |
||
| 171 | * is available. No further calls should be made with this |
||
| 172 | * source. |
||
| 173 | */ |
||
| 174 | src_exhausted, |
||
| 175 | /* The destination was exhausted before decoding completed. The |
||
| 176 | * source is left at the beginning of the row which failed to |
||
| 177 | * decode. The caller may try again with a larger destination |
||
| 178 | * buffer or may abandon the attempt. Further calls with the |
||
| 179 | * same source and destination will continue to return |
||
| 180 | * `dst_exhausted`. |
||
| 181 | */ |
||
| 182 | dst_exhausted, |
||
| 183 | }; |
||
| 184 | bm_rle_expand(const grs_bitmap &src) : |
||
| 185 | bm_rle_src_stride(src, src.get_flag_mask(BM_FLAG_RLE_BIG)), |
||
| 186 | end_src_bit_lengths(src_bits), |
||
| 187 | end_src_bm(end(src)) |
||
| 188 | { |
||
| 189 | } |
||
| 190 | template <typename T> |
||
| 191 | /* Decode one row of the bitmap, then return control to the |
||
| 192 | * caller. If the return value is `again`, then the caller |
||
| 193 | * should perform any per-row processing, then call step() |
||
| 194 | * again. If the return value is not `again`, then the |
||
| 195 | * destination buffer is undefined and the caller should not |
||
| 196 | * access it or call step(). |
||
| 197 | * |
||
| 198 | * `const T &` to ensure that t is only modified by the caller |
||
| 199 | * and that the caller does not accidentally provide an |
||
| 200 | * implementation of `get_begin_dbits` that moves the |
||
| 201 | * destination pointer. |
||
| 202 | */ |
||
| 203 | step_result step(const T &t) |
||
| 204 | { |
||
| 205 | /* Poison the memory first, so that it is undefined even if |
||
| 206 | * the source is exhausted. |
||
| 207 | */ |
||
| 208 | const auto b = t.get_begin_dbits(); |
||
| 209 | const auto e = t.get_end_dbits(); |
||
| 210 | DXX_MAKE_MEM_UNDEFINED(b, e); |
||
| 211 | /* Check for source exhaustion, so that empty bitmaps are |
||
| 212 | * not read at all. This allows callers to treat |
||
| 213 | * src_exhausted as a definitive end-of-record with no data |
||
| 214 | * available. |
||
| 215 | */ |
||
| 216 | if (ptr_src_bit_lengths == end_src_bit_lengths) |
||
| 217 | return src_exhausted; |
||
| 218 | return step_internal(b, e); |
||
| 219 | } |
||
| 220 | template <typename T> |
||
| 221 | /* Decode until source or destination is exhausted. The |
||
| 222 | * destination position is updated automatically as each row is |
||
| 223 | * decoded. There is no opportunity for callers to perform |
||
| 224 | * per-row processing. Callers should call step() directly if |
||
| 225 | * per-row processing is required. |
||
| 226 | * |
||
| 227 | * `T &&` since some callers may not care about the state of `t` |
||
| 228 | * afterward; `T &&` lets them pass an anonymous temporary. |
||
| 229 | */ |
||
| 230 | bool loop(const unsigned bm_w, T &&t) |
||
| 231 | { |
||
| 232 | for (;;) |
||
| 233 | { |
||
| 234 | switch (step(t)) |
||
| 235 | { |
||
| 236 | case again: |
||
| 237 | /* Step succeeded. Notify `t` to update its |
||
| 238 | * dbits position, then loop around. |
||
| 239 | */ |
||
| 240 | t.consume_dbits(bm_w); |
||
| 241 | break; |
||
| 242 | case src_exhausted: |
||
| 243 | /* Success: source buffer exhausted and no error |
||
| 244 | * conditions detected. |
||
| 245 | */ |
||
| 246 | return true; |
||
| 247 | case dst_exhausted: |
||
| 248 | /* Failure: destination buffer too small to hold |
||
| 249 | * expanded source. |
||
| 250 | */ |
||
| 251 | return false; |
||
| 252 | } |
||
| 253 | } |
||
| 254 | } |
||
| 255 | private: |
||
| 256 | step_result step_internal(uint8_t *begin_dbits, uint8_t *end_dbits); |
||
| 257 | }; |
||
| 258 | |||
| 259 | } |