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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * Routines to cache merged textures.
23
 *
24
 */
25
 
26
 
27
#include "gr.h"
28
#include "dxxerror.h"
29
#include "game.h"
30
#include "textures.h"
31
#include "rle.h"
32
#include "timer.h"
33
#include "piggy.h"
34
#include "texmerge.h"
35
#include "piggy.h"
36
 
37
#include "compiler-range_for.h"
38
#include "partial_range.h"
39
 
40
#if DXX_USE_OGL
41
#include "ogl_init.h"
42
#endif
43
#define MAX_NUM_CACHE_BITMAPS 10
44
 
45
//static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS];                     
46
 
47
namespace {
48
 
49
struct TEXTURE_CACHE {
50
        grs_bitmap_ptr bitmap;
51
        grs_bitmap * bottom_bmp;
52
        grs_bitmap * top_bmp;
53
        int             orient;
54
        fix64           last_time_used;
55
};
56
 
57
/* Helper classes merge_texture_0 through merge_texture_3 correspond to
58
 * the four values of `orient` used by texmerge_get_cached_bitmap.
59
 */
60
struct merge_texture_0
61
{
62
        static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
63
        {
64
                return wh * y + x;
65
        }
66
};
67
 
68
struct merge_texture_1
69
{
70
        static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
71
        {
72
                return wh * x + ((wh - 1) - y);
73
        }
74
};
75
 
76
struct merge_texture_2
77
{
78
        static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
79
        {
80
                return wh * ((wh - 1) - y) + ((wh - 1) - x);
81
        }
82
};
83
 
84
struct merge_texture_3
85
{
86
        static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
87
        {
88
                return wh * ((wh - 1) - x) + y;
89
        }
90
};
91
 
92
/* For supertransparent colors, remap 254.
93
 * For regular transparent colors, do nothing.
94
 *
95
 * In both cases, the caller remaps TRANSPARENCY_COLOR to the bottom
96
 * bitmap.
97
 */
98
struct merge_transform_super_xparent
99
{
100
        static uint8_t transform_color(uint8_t c)
101
        {
102
                return c == 254 ? TRANSPARENCY_COLOR : c;
103
        }
104
};
105
 
106
struct merge_transform_new
107
{
108
        static uint8_t transform_color(uint8_t c)
109
        {
110
                return c;
111
        }
112
};
113
 
114
}
115
 
116
/* Run the transform for one texture merge case.  Different values of
117
 * `orient` in texmerge_get_cached_bitmap lead to different types for
118
 * `get_index`.
119
 */
120
template <typename texture_transform, typename get_index>
121
static void merge_textures_case(const unsigned wh, const uint8_t *const top_data, const uint8_t *const bottom_data, uint8_t *dest_data)
122
{
123
        for (unsigned y = 0; y < wh; ++y)
124
                for (unsigned x = 0; x < wh; ++x)
125
                {
126
                        const auto c = top_data[get_index::get_top_data_index(wh, y, x)];
127
                        /* All merged textures support TRANSPARENCY_COLOR, so handle
128
                         * it here.  Supertransparency is delegated down to
129
                         * `texture_transform`, since not all textures want
130
                         * supertransparency.
131
                         */
132
                        *dest_data++ = (c == TRANSPARENCY_COLOR)
133
                                ? bottom_data[wh * y + x]
134
                                : texture_transform::transform_color(c);
135
                }
136
}
137
 
138
/* Dispatch a texture transformation based on the value of `orient`.
139
 * The loops are duplicated in each case so that `orient` is not reread
140
 * for each byte processed.
141
 */
142
template <typename texture_transform>
143
static void merge_textures(unsigned orient, const grs_bitmap &expanded_bottom_bmp, const grs_bitmap &expanded_top_bmp, uint8_t *const dest_data)
144
{
145
        const auto &top_data = expanded_top_bmp.bm_data;
146
        const auto &bottom_data = expanded_bottom_bmp.bm_data;
147
        const auto wh = expanded_bottom_bmp.bm_w;
148
        switch (orient)
149
        {
150
                case 0:
151
                        merge_textures_case<texture_transform, merge_texture_0>(wh, top_data, bottom_data, dest_data);
152
                        break;
153
                case 1:
154
                        merge_textures_case<texture_transform, merge_texture_1>(wh, top_data, bottom_data, dest_data);
155
                        break;
156
                case 2:
157
                        merge_textures_case<texture_transform, merge_texture_2>(wh, top_data, bottom_data, dest_data);
158
                        break;
159
                case 3:
160
                        merge_textures_case<texture_transform, merge_texture_3>(wh, top_data, bottom_data, dest_data);
161
                        break;
162
        }
163
}
164
 
165
static std::array<TEXTURE_CACHE, MAX_NUM_CACHE_BITMAPS> Cache;
166
 
167
static int cache_hits = 0;
168
static int cache_misses = 0;
169
 
170
//----------------------------------------------------------------------
171
 
172
int texmerge_init()
173
{
174
        range_for (auto &i, Cache)
175
        {
176
                i.bitmap = NULL;
177
                i.last_time_used = -1;
178
                i.top_bmp = NULL;
179
                i.bottom_bmp = NULL;
180
                i.orient = -1;
181
        }
182
 
183
        return 1;
184
}
185
 
186
void texmerge_flush()
187
{
188
        range_for (auto &i, Cache)
189
        {
190
                i.last_time_used = -1;
191
                i.top_bmp = NULL;
192
                i.bottom_bmp = NULL;
193
                i.orient = -1;
194
        }
195
}
196
 
197
 
198
//-------------------------------------------------------------------------
199
void texmerge_close()
200
{
201
        range_for (auto &i, Cache)
202
        {
203
                i.bitmap.reset();
204
        }
205
}
206
 
207
//--unused-- int info_printed = 0;
208
 
209
grs_bitmap &texmerge_get_cached_bitmap(unsigned tmap_bottom, unsigned tmap_top)
210
{
211
        grs_bitmap *bitmap_top, *bitmap_bottom;
212
        int orient;
213
        int lowest_time_used;
214
 
215
        bitmap_top = &GameBitmaps[Textures[tmap_top&0x3FFF].index];
216
        bitmap_bottom = &GameBitmaps[Textures[tmap_bottom].index];
217
 
218
        orient = ((tmap_top&0xC000)>>14) & 3;
219
 
220
        lowest_time_used = Cache[0].last_time_used;
221
        auto least_recently_used = &Cache.front();
222
        range_for (auto &i, Cache)
223
        {
224
                if ( (i.last_time_used > -1) && (i.top_bmp==bitmap_top) && (i.bottom_bmp==bitmap_bottom) && (i.orient==orient ))        {
225
                        cache_hits++;
226
                        i.last_time_used = timer_query();
227
                        return *i.bitmap.get();
228
                }      
229
                if ( i.last_time_used < lowest_time_used )      {
230
                        lowest_time_used = i.last_time_used;
231
                        least_recently_used = &i;
232
                }
233
        }
234
 
235
        //---- Page out the LRU bitmap;
236
        cache_misses++;
237
 
238
        // Make sure the bitmaps are paged in...
239
 
240
        PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
241
        PIGGY_PAGE_IN(Textures[tmap_bottom]);
242
        if (bitmap_bottom->bm_w != bitmap_bottom->bm_h || bitmap_top->bm_w != bitmap_top->bm_h)
243
                Error("Texture width != texture height!\nbottom tmap = %u; bottom bitmap = %u; bottom width = %u; bottom height = %u\ntop tmap = %u; top bitmap = %u; top width=%u; top height=%u", tmap_bottom, Textures[tmap_bottom].index, bitmap_bottom->bm_w, bitmap_bottom->bm_h, tmap_top, Textures[tmap_top & 0x3fff].index, bitmap_top->bm_w, bitmap_top->bm_h);
244
        if (bitmap_bottom->bm_w != bitmap_top->bm_w || bitmap_bottom->bm_h != bitmap_top->bm_h)
245
                Error("Top and Bottom textures have different size!\nbottom tmap = %u; bottom bitmap = %u; bottom width = %u; bottom height = %u\ntop tmap = %u; top bitmap = %u; top width=%u; top height=%u", tmap_bottom, Textures[tmap_bottom].index, bitmap_bottom->bm_w, bitmap_bottom->bm_h, tmap_top, Textures[tmap_top & 0x3fff].index, bitmap_top->bm_w, bitmap_top->bm_h);
246
 
247
        least_recently_used->bitmap = gr_create_bitmap(bitmap_bottom->bm_w,  bitmap_bottom->bm_h);
248
#if DXX_USE_OGL
249
        ogl_freebmtexture(*least_recently_used->bitmap.get());
250
#endif
251
 
252
        auto &expanded_top_bmp = *rle_expand_texture(*bitmap_top);
253
        auto &expanded_bottom_bmp = *rle_expand_texture(*bitmap_bottom);
254
        if (bitmap_top->get_flag_mask(BM_FLAG_SUPER_TRANSPARENT))
255
        {
256
                merge_textures<merge_transform_super_xparent>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
257
                gr_set_bitmap_flags(*least_recently_used->bitmap.get(), BM_FLAG_TRANSPARENT);
258
#if !DXX_USE_OGL
259
                least_recently_used->bitmap->avg_color = bitmap_top->avg_color;
260
#endif
261
        } else  {
262
                merge_textures<merge_transform_new>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
263
                least_recently_used->bitmap->set_flags(bitmap_bottom->get_flag_mask(~BM_FLAG_RLE));
264
#if !DXX_USE_OGL
265
                least_recently_used->bitmap->avg_color = bitmap_bottom->avg_color;
266
#endif
267
        }
268
 
269
        least_recently_used->top_bmp = bitmap_top;
270
        least_recently_used->bottom_bmp = bitmap_bottom;
271
        least_recently_used->last_time_used = timer_query();
272
        least_recently_used->orient = orient;
273
        return *least_recently_used->bitmap.get();
274
}