Subversion Repositories Games.Descent

Rev

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
}