2006-03-20 17:12:09 +00:00
|
|
|
/*
|
2014-06-01 17:55:23 +00:00
|
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
|
|
* described in COPYING.txt.
|
|
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
|
|
* according to the Parallax license below.
|
|
|
|
* See COPYING.txt for license details.
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
|
|
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Routines to cache merged textures.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "gr.h"
|
2012-07-07 18:35:06 +00:00
|
|
|
#include "dxxerror.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "game.h"
|
|
|
|
#include "textures.h"
|
|
|
|
#include "rle.h"
|
2012-05-14 17:06:28 +00:00
|
|
|
#include "timer.h"
|
2015-01-29 04:27:35 +00:00
|
|
|
#include "piggy.h"
|
2012-11-11 22:12:51 +00:00
|
|
|
#include "texmerge.h"
|
2015-01-29 04:27:35 +00:00
|
|
|
#include "piggy.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2014-11-30 22:09:18 +00:00
|
|
|
#include "compiler-range_for.h"
|
|
|
|
#include "partial_range.h"
|
|
|
|
|
2016-09-24 18:06:11 +00:00
|
|
|
#if DXX_USE_OGL
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "ogl_init.h"
|
|
|
|
#endif
|
2016-11-19 17:24:52 +00:00
|
|
|
#define MAX_NUM_CACHE_BITMAPS 10
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
//static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS];
|
|
|
|
|
2015-08-12 03:11:46 +00:00
|
|
|
namespace {
|
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct TEXTURE_CACHE {
|
2014-07-22 02:14:56 +00:00
|
|
|
grs_bitmap_ptr bitmap;
|
2006-03-20 17:12:09 +00:00
|
|
|
grs_bitmap * bottom_bmp;
|
|
|
|
grs_bitmap * top_bmp;
|
|
|
|
int orient;
|
2012-05-14 17:06:28 +00:00
|
|
|
fix64 last_time_used;
|
2013-12-22 22:03:07 +00:00
|
|
|
};
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2016-06-05 18:45:20 +00:00
|
|
|
/* Helper classes merge_texture_0 through merge_texture_3 correspond to
|
|
|
|
* the four values of `orient` used by texmerge_get_cached_bitmap.
|
|
|
|
*/
|
|
|
|
struct merge_texture_0
|
|
|
|
{
|
|
|
|
static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
|
|
|
|
{
|
|
|
|
return wh * y + x;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct merge_texture_1
|
|
|
|
{
|
|
|
|
static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
|
|
|
|
{
|
|
|
|
return wh * x + ((wh - 1) - y);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct merge_texture_2
|
|
|
|
{
|
|
|
|
static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
|
|
|
|
{
|
|
|
|
return wh * ((wh - 1) - y) + ((wh - 1) - x);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct merge_texture_3
|
|
|
|
{
|
|
|
|
static size_t get_top_data_index(const unsigned wh, const unsigned y, const unsigned x)
|
|
|
|
{
|
|
|
|
return wh * ((wh - 1) - x) + y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* For supertransparent colors, remap 254.
|
|
|
|
* For regular transparent colors, do nothing.
|
|
|
|
*
|
|
|
|
* In both cases, the caller remaps TRANSPARENCY_COLOR to the bottom
|
|
|
|
* bitmap.
|
|
|
|
*/
|
|
|
|
struct merge_transform_super_xparent
|
|
|
|
{
|
|
|
|
static uint8_t transform_color(uint8_t c)
|
|
|
|
{
|
|
|
|
return c == 254 ? TRANSPARENCY_COLOR : c;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct merge_transform_new
|
|
|
|
{
|
|
|
|
static uint8_t transform_color(uint8_t c)
|
|
|
|
{
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Run the transform for one texture merge case. Different values of
|
|
|
|
* `orient` in texmerge_get_cached_bitmap lead to different types for
|
|
|
|
* `get_index`.
|
|
|
|
*/
|
|
|
|
template <typename texture_transform, typename get_index>
|
|
|
|
static void merge_textures_case(const unsigned wh, const uint8_t *const top_data, const uint8_t *const bottom_data, uint8_t *dest_data)
|
|
|
|
{
|
|
|
|
for (unsigned y = 0; y < wh; ++y)
|
|
|
|
for (unsigned x = 0; x < wh; ++x)
|
|
|
|
{
|
|
|
|
const auto c = top_data[get_index::get_top_data_index(wh, y, x)];
|
|
|
|
/* All merged textures support TRANSPARENCY_COLOR, so handle
|
|
|
|
* it here. Supertransparency is delegated down to
|
|
|
|
* `texture_transform`, since not all textures want
|
|
|
|
* supertransparency.
|
|
|
|
*/
|
|
|
|
*dest_data++ = (c == TRANSPARENCY_COLOR)
|
|
|
|
? bottom_data[wh * y + x]
|
|
|
|
: texture_transform::transform_color(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Dispatch a texture transformation based on the value of `orient`.
|
|
|
|
* The loops are duplicated in each case so that `orient` is not reread
|
|
|
|
* for each byte processed.
|
|
|
|
*/
|
|
|
|
template <typename texture_transform>
|
|
|
|
static void merge_textures(unsigned orient, const grs_bitmap &expanded_bottom_bmp, const grs_bitmap &expanded_top_bmp, uint8_t *const dest_data)
|
|
|
|
{
|
|
|
|
const auto &top_data = expanded_top_bmp.bm_data;
|
|
|
|
const auto &bottom_data = expanded_bottom_bmp.bm_data;
|
|
|
|
const auto wh = expanded_bottom_bmp.bm_w;
|
|
|
|
switch (orient)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
merge_textures_case<texture_transform, merge_texture_0>(wh, top_data, bottom_data, dest_data);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
merge_textures_case<texture_transform, merge_texture_1>(wh, top_data, bottom_data, dest_data);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
merge_textures_case<texture_transform, merge_texture_2>(wh, top_data, bottom_data, dest_data);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
merge_textures_case<texture_transform, merge_texture_3>(wh, top_data, bottom_data, dest_data);
|
|
|
|
break;
|
|
|
|
}
|
2015-08-12 03:11:46 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 21:18:42 +00:00
|
|
|
static std::array<TEXTURE_CACHE, MAX_NUM_CACHE_BITMAPS> Cache;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
static int cache_hits = 0;
|
|
|
|
static int cache_misses = 0;
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2016-11-19 17:24:52 +00:00
|
|
|
int texmerge_init()
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2016-11-19 17:24:52 +00:00
|
|
|
range_for (auto &i, Cache)
|
2014-11-30 22:09:18 +00:00
|
|
|
{
|
|
|
|
i.bitmap = NULL;
|
|
|
|
i.last_time_used = -1;
|
|
|
|
i.top_bmp = NULL;
|
|
|
|
i.bottom_bmp = NULL;
|
|
|
|
i.orient = -1;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void texmerge_flush()
|
|
|
|
{
|
2016-11-19 17:24:52 +00:00
|
|
|
range_for (auto &i, Cache)
|
2014-11-30 22:09:18 +00:00
|
|
|
{
|
|
|
|
i.last_time_used = -1;
|
|
|
|
i.top_bmp = NULL;
|
|
|
|
i.bottom_bmp = NULL;
|
|
|
|
i.orient = -1;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
void texmerge_close()
|
|
|
|
{
|
2016-11-19 17:24:52 +00:00
|
|
|
range_for (auto &i, Cache)
|
2014-11-30 22:09:18 +00:00
|
|
|
{
|
|
|
|
i.bitmap.reset();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--unused-- int info_printed = 0;
|
|
|
|
|
2014-11-30 22:09:19 +00:00
|
|
|
grs_bitmap &texmerge_get_cached_bitmap(unsigned tmap_bottom, unsigned tmap_top)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
grs_bitmap *bitmap_top, *bitmap_bottom;
|
2014-09-26 02:42:10 +00:00
|
|
|
int orient;
|
2012-05-14 17:06:28 +00:00
|
|
|
int lowest_time_used;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
bitmap_top = &GameBitmaps[Textures[tmap_top&0x3FFF].index];
|
|
|
|
bitmap_bottom = &GameBitmaps[Textures[tmap_bottom].index];
|
|
|
|
|
|
|
|
orient = ((tmap_top&0xC000)>>14) & 3;
|
|
|
|
|
2012-05-14 17:06:28 +00:00
|
|
|
lowest_time_used = Cache[0].last_time_used;
|
2014-11-30 22:09:18 +00:00
|
|
|
auto least_recently_used = &Cache.front();
|
2016-11-19 17:24:52 +00:00
|
|
|
range_for (auto &i, Cache)
|
2014-11-30 22:09:18 +00:00
|
|
|
{
|
|
|
|
if ( (i.last_time_used > -1) && (i.top_bmp==bitmap_top) && (i.bottom_bmp==bitmap_bottom) && (i.orient==orient )) {
|
2006-03-20 17:12:09 +00:00
|
|
|
cache_hits++;
|
2014-11-30 22:09:18 +00:00
|
|
|
i.last_time_used = timer_query();
|
2014-11-30 22:09:19 +00:00
|
|
|
return *i.bitmap.get();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2014-11-30 22:09:18 +00:00
|
|
|
if ( i.last_time_used < lowest_time_used ) {
|
|
|
|
lowest_time_used = i.last_time_used;
|
|
|
|
least_recently_used = &i;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---- Page out the LRU bitmap;
|
|
|
|
cache_misses++;
|
|
|
|
|
|
|
|
// Make sure the bitmaps are paged in...
|
|
|
|
|
|
|
|
PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
|
|
|
|
PIGGY_PAGE_IN(Textures[tmap_bottom]);
|
2011-04-22 08:33:04 +00:00
|
|
|
if (bitmap_bottom->bm_w != bitmap_bottom->bm_h || bitmap_top->bm_w != bitmap_top->bm_h)
|
2016-06-05 18:45:21 +00:00
|
|
|
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);
|
2011-04-22 08:33:04 +00:00
|
|
|
if (bitmap_bottom->bm_w != bitmap_top->bm_w || bitmap_bottom->bm_h != bitmap_top->bm_h)
|
2016-06-05 18:45:21 +00:00
|
|
|
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);
|
2011-04-22 08:33:04 +00:00
|
|
|
|
2014-11-30 22:09:18 +00:00
|
|
|
least_recently_used->bitmap = gr_create_bitmap(bitmap_bottom->bm_w, bitmap_bottom->bm_h);
|
2016-09-24 18:06:11 +00:00
|
|
|
#if DXX_USE_OGL
|
2014-11-30 22:09:20 +00:00
|
|
|
ogl_freebmtexture(*least_recently_used->bitmap.get());
|
2006-03-20 17:12:09 +00:00
|
|
|
#endif
|
|
|
|
|
2016-06-05 18:45:20 +00:00
|
|
|
auto &expanded_top_bmp = *rle_expand_texture(*bitmap_top);
|
|
|
|
auto &expanded_bottom_bmp = *rle_expand_texture(*bitmap_bottom);
|
2017-01-15 00:03:13 +00:00
|
|
|
if (bitmap_top->get_flag_mask(BM_FLAG_SUPER_TRANSPARENT))
|
|
|
|
{
|
2016-06-05 18:45:20 +00:00
|
|
|
merge_textures<merge_transform_super_xparent>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
|
2014-11-30 22:09:21 +00:00
|
|
|
gr_set_bitmap_flags(*least_recently_used->bitmap.get(), BM_FLAG_TRANSPARENT);
|
2014-11-30 22:09:18 +00:00
|
|
|
least_recently_used->bitmap->avg_color = bitmap_top->avg_color;
|
2006-03-20 17:12:09 +00:00
|
|
|
} else {
|
2016-06-05 18:45:20 +00:00
|
|
|
merge_textures<merge_transform_new>(orient, expanded_bottom_bmp, expanded_top_bmp, least_recently_used->bitmap->get_bitmap_data());
|
2017-01-15 00:03:13 +00:00
|
|
|
least_recently_used->bitmap->set_flags(bitmap_bottom->get_flag_mask(~BM_FLAG_RLE));
|
2014-11-30 22:09:18 +00:00
|
|
|
least_recently_used->bitmap->avg_color = bitmap_bottom->avg_color;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2014-11-30 22:09:18 +00:00
|
|
|
least_recently_used->top_bmp = bitmap_top;
|
|
|
|
least_recently_used->bottom_bmp = bitmap_bottom;
|
|
|
|
least_recently_used->last_time_used = timer_query();
|
|
|
|
least_recently_used->orient = orient;
|
2014-11-30 22:09:19 +00:00
|
|
|
return *least_recently_used->bitmap.get();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|