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-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Routines to do run length encoding/decoding
|
|
|
|
* on bitmaps.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-06-30 23:56:51 +00:00
|
|
|
#include <algorithm>
|
2006-03-20 17:12:09 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "pstypes.h"
|
|
|
|
#include "u_mem.h"
|
|
|
|
#include "gr.h"
|
|
|
|
#include "grdef.h"
|
2012-07-07 18:35:06 +00:00
|
|
|
#include "dxxerror.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "rle.h"
|
2014-07-03 01:47:29 +00:00
|
|
|
#include "byteutil.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2014-11-15 03:10:09 +00:00
|
|
|
#include "compiler-range_for.h"
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-05 22:57:23 +00:00
|
|
|
|
2016-07-23 04:10:42 +00:00
|
|
|
constexpr uint8_t RLE_CODE = 0xe0;
|
|
|
|
constexpr uint8_t NOT_RLE_CODE = 0x1f;
|
2014-11-15 03:10:09 +00:00
|
|
|
static_assert((RLE_CODE | NOT_RLE_CODE) == 0xff, "RLE mask error");
|
|
|
|
static inline int IS_RLE_CODE(const uint8_t &x)
|
|
|
|
{
|
|
|
|
return (x & RLE_CODE) == RLE_CODE;
|
|
|
|
}
|
2009-11-30 22:42:55 +00:00
|
|
|
#define rle_stosb(_dest, _len, _color) memset(_dest,_color,_len)
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2017-04-08 16:48:17 +00:00
|
|
|
uint8_t *gr_rle_decode(const uint8_t *sb, uint8_t *db, const rle_position_t e)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-06-30 23:56:51 +00:00
|
|
|
using std::advance;
|
|
|
|
using std::distance;
|
2017-04-08 16:48:17 +00:00
|
|
|
for (; sb != e.src;)
|
2014-06-30 23:56:51 +00:00
|
|
|
{
|
2017-04-08 16:48:17 +00:00
|
|
|
const uint8_t *p = sb;
|
2014-06-30 23:56:51 +00:00
|
|
|
uint8_t c;
|
|
|
|
for (; c = *p, !IS_RLE_CODE(c);)
|
|
|
|
if (++p == e.src)
|
2017-04-08 16:48:17 +00:00
|
|
|
return db;
|
2014-06-30 23:56:51 +00:00
|
|
|
size_t count = (c & NOT_RLE_CODE);
|
2017-04-08 16:48:17 +00:00
|
|
|
const size_t cn = std::min<size_t>(distance(sb, p), distance(db, e.dst));
|
|
|
|
memcpy(db, sb, cn);
|
|
|
|
advance(db, cn);
|
2014-06-30 23:56:51 +00:00
|
|
|
if (!count)
|
|
|
|
break;
|
2017-04-08 16:48:17 +00:00
|
|
|
advance(sb, cn);
|
|
|
|
if (sb == e.src || db == e.dst || count > static_cast<size_t>(distance(db, e.dst)))
|
2014-06-30 23:56:51 +00:00
|
|
|
break;
|
2017-04-08 16:48:17 +00:00
|
|
|
if (++ sb == e.src)
|
|
|
|
break;
|
|
|
|
std::fill_n(db, count, *sb++);
|
|
|
|
advance(db, count);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2017-04-08 16:48:17 +00:00
|
|
|
return db;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Given pointer to start of one scanline of rle data, uncompress it to
|
|
|
|
// dest, from source pixels x1 to x2.
|
2014-11-30 22:09:22 +00:00
|
|
|
void gr_rle_expand_scanline_masked(uint8_t *dest, const uint8_t *src, int x1, int x2)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
ubyte count;
|
|
|
|
ubyte color=0;
|
|
|
|
|
|
|
|
if ( x2 < x1 ) return;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while ( i < x1 ) {
|
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
2014-11-15 03:10:09 +00:00
|
|
|
count = color & NOT_RLE_CODE;
|
2006-03-20 17:12:09 +00:00
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
i += count;
|
|
|
|
}
|
|
|
|
count = i - x1;
|
|
|
|
i = x1;
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
|
|
|
|
if ( x1+count > x2 ) {
|
|
|
|
count = x2-x1+1;
|
|
|
|
if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color );
|
|
|
|
dest += count;
|
|
|
|
i += count;
|
|
|
|
|
2007-10-18 14:44:02 +00:00
|
|
|
while( i <= x2 )
|
|
|
|
{
|
2006-03-20 17:12:09 +00:00
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
2014-11-15 03:10:09 +00:00
|
|
|
count = color & NOT_RLE_CODE;
|
2006-03-20 17:12:09 +00:00
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
if ( i+count <= x2 ) {
|
2007-10-18 14:44:02 +00:00
|
|
|
if ( color != 255 )rle_stosb( dest, count, color );
|
2006-03-20 17:12:09 +00:00
|
|
|
i += count;
|
|
|
|
dest += count;
|
|
|
|
} else {
|
|
|
|
count = x2-i+1;
|
2007-10-18 14:44:02 +00:00
|
|
|
if ( color != 255 )rle_stosb( dest, count, color );
|
2006-03-20 17:12:09 +00:00
|
|
|
i += count;
|
|
|
|
dest += count;
|
|
|
|
}
|
2007-10-18 14:44:02 +00:00
|
|
|
}
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2014-11-30 22:09:22 +00:00
|
|
|
void gr_rle_expand_scanline(uint8_t *dest, const uint8_t *src, int x1, int x2)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
ubyte count;
|
|
|
|
ubyte color=0;
|
|
|
|
|
|
|
|
if ( x2 < x1 ) return;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while ( i < x1 ) {
|
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
2014-11-15 03:10:09 +00:00
|
|
|
count = color & NOT_RLE_CODE;
|
2006-03-20 17:12:09 +00:00
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
i += count;
|
|
|
|
}
|
|
|
|
count = i - x1;
|
|
|
|
i = x1;
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
|
|
|
|
if ( x1+count > x2 ) {
|
|
|
|
count = x2-x1+1;
|
|
|
|
rle_stosb( dest, count, color );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rle_stosb( dest, count, color );
|
|
|
|
dest += count;
|
|
|
|
i += count;
|
|
|
|
|
|
|
|
while( i <= x2 ) {
|
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
|
|
|
count = color & (~RLE_CODE);
|
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
if ( i+count <= x2 ) {
|
|
|
|
rle_stosb( dest, count, color );
|
|
|
|
i += count;
|
|
|
|
dest += count;
|
|
|
|
} else {
|
|
|
|
count = x2-i+1;
|
|
|
|
rle_stosb( dest, count, color );
|
|
|
|
i += count;
|
|
|
|
dest += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-15 03:10:09 +00:00
|
|
|
static std::ptrdiff_t gr_rle_encode( int org_size, const uint8_t *src, ubyte *dest )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
ubyte c, oc;
|
|
|
|
ubyte count;
|
2016-07-14 01:59:02 +00:00
|
|
|
uint8_t *dest_start;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
dest_start = dest;
|
|
|
|
oc = *src++;
|
|
|
|
count = 1;
|
|
|
|
|
2015-02-14 22:48:27 +00:00
|
|
|
if (org_size > 0)
|
|
|
|
for (uint_fast32_t i = org_size; --i;)
|
|
|
|
{
|
2006-03-20 17:12:09 +00:00
|
|
|
c = *src++;
|
|
|
|
if ( c!=oc ) {
|
|
|
|
if ( count ) {
|
|
|
|
if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
|
|
|
|
*dest++ = oc;
|
|
|
|
Assert( oc != RLE_CODE );
|
|
|
|
} else {
|
|
|
|
count |= RLE_CODE;
|
|
|
|
*dest++ = count;
|
|
|
|
*dest++ = oc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
oc = c;
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
if ( count == NOT_RLE_CODE ) {
|
|
|
|
count |= RLE_CODE;
|
|
|
|
*dest++=count;
|
|
|
|
*dest++=oc;
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
|
|
|
|
*dest++ = oc;
|
|
|
|
Assert( oc != RLE_CODE );
|
|
|
|
} else {
|
|
|
|
count |= RLE_CODE;
|
|
|
|
*dest++ = count;
|
|
|
|
*dest++ = oc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*dest++ = RLE_CODE;
|
|
|
|
|
|
|
|
return dest-dest_start;
|
|
|
|
}
|
|
|
|
|
2014-11-30 22:09:22 +00:00
|
|
|
static unsigned gr_rle_getsize(int org_size, const uint8_t *src)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
ubyte c, oc;
|
|
|
|
ubyte count;
|
|
|
|
int dest_size=0;
|
|
|
|
|
|
|
|
oc = *src++;
|
|
|
|
count = 1;
|
|
|
|
|
2015-02-14 22:48:27 +00:00
|
|
|
if (org_size > 0)
|
|
|
|
for (uint_fast32_t i = org_size; --i;)
|
|
|
|
{
|
2006-03-20 17:12:09 +00:00
|
|
|
c = *src++;
|
|
|
|
if ( c!=oc ) {
|
|
|
|
if ( count ) {
|
|
|
|
if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
|
|
|
|
dest_size++;
|
|
|
|
} else {
|
|
|
|
dest_size++;
|
|
|
|
dest_size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
oc = c;
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
if ( count == NOT_RLE_CODE ) {
|
|
|
|
dest_size++;
|
|
|
|
dest_size++;
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
if ( (count==1) && (! IS_RLE_CODE(oc)) ) {
|
|
|
|
dest_size++;
|
|
|
|
} else {
|
|
|
|
dest_size++;
|
|
|
|
dest_size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dest_size++;
|
|
|
|
|
|
|
|
return dest_size;
|
|
|
|
}
|
|
|
|
|
2015-01-29 04:27:37 +00:00
|
|
|
int gr_bitmap_rle_compress(grs_bitmap &bmp)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
int doffset;
|
|
|
|
int large_rle = 0;
|
|
|
|
|
|
|
|
// first must check to see if this is large bitmap.
|
|
|
|
|
2015-02-14 22:48:27 +00:00
|
|
|
const uint_fast32_t bm_h = bmp.bm_h;
|
|
|
|
const uint_fast32_t bm_w = bmp.bm_w;
|
|
|
|
for (uint_fast32_t y = 0; y != bm_h; ++y)
|
|
|
|
{
|
|
|
|
auto d1 = gr_rle_getsize(bm_w, &bmp.get_bitmap_data()[bm_w * y]);
|
2006-03-20 17:12:09 +00:00
|
|
|
if (d1 > 255) {
|
2015-01-29 04:27:37 +00:00
|
|
|
large_rle = BM_FLAG_RLE_BIG;
|
2006-03-20 17:12:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-28 03:42:53 +00:00
|
|
|
RAIIdmem<uint8_t[]> rle_data;
|
2015-02-14 22:48:27 +00:00
|
|
|
MALLOC(rle_data, uint8_t[], MAX_BMP_SIZE(bm_w, bm_h));
|
2014-10-12 22:11:28 +00:00
|
|
|
if (!rle_data) return 0;
|
2006-03-20 17:12:09 +00:00
|
|
|
if (!large_rle)
|
2015-02-14 22:48:27 +00:00
|
|
|
doffset = 4 + bm_h;
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
2015-02-14 22:48:27 +00:00
|
|
|
doffset = 4 + (2 * bm_h); // each row of rle'd bitmap has short instead of byte offset now
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-02-14 22:48:27 +00:00
|
|
|
for (uint_fast32_t y = 0; y != bm_h; ++y)
|
|
|
|
{
|
|
|
|
auto d1 = gr_rle_getsize(bm_w, &bmp.get_bitmap_data()[bm_w * y]);
|
2015-01-29 04:27:37 +00:00
|
|
|
if ( ((doffset+d1) > bmp.bm_w*bmp.bm_h) || (d1 > (large_rle?32767:255) ) ) {
|
2006-03-20 17:12:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2015-01-29 04:27:37 +00:00
|
|
|
const auto d = gr_rle_encode( bmp.bm_w, &bmp.get_bitmap_data()[bmp.bm_w*y], &rle_data[doffset] );
|
2006-03-20 17:12:09 +00:00
|
|
|
Assert( d==d1 );
|
|
|
|
doffset += d;
|
|
|
|
if (large_rle)
|
2015-07-14 02:42:12 +00:00
|
|
|
PUT_INTEL_SHORT(&rle_data[(y*2)+4], static_cast<short>(d));
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
|
|
|
rle_data[y+4] = d;
|
|
|
|
}
|
2015-02-17 03:52:59 +00:00
|
|
|
memcpy(bmp.get_bitmap_data(), &doffset, 4);
|
|
|
|
memcpy(&bmp.get_bitmap_data()[4], &rle_data.get()[4], doffset - 4);
|
2017-01-15 00:03:13 +00:00
|
|
|
bmp.add_flags(BM_FLAG_RLE | large_rle);
|
2006-03-20 17:12:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-12 03:11:46 +00:00
|
|
|
namespace {
|
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct rle_cache_element
|
|
|
|
{
|
2014-11-30 22:09:17 +00:00
|
|
|
const grs_bitmap *rle_bitmap;
|
2014-07-22 02:14:56 +00:00
|
|
|
grs_bitmap_ptr expanded_bitmap;
|
2006-03-20 17:12:09 +00:00
|
|
|
int last_used;
|
2013-12-22 22:03:07 +00:00
|
|
|
};
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-08-12 03:11:46 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 04:27:37 +00:00
|
|
|
static int rle_cache_initialized;
|
|
|
|
static int rle_counter;
|
|
|
|
static int rle_next;
|
2016-07-10 04:11:34 +00:00
|
|
|
static array<rle_cache_element, 32> rle_cache;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
void rle_cache_close(void)
|
|
|
|
{
|
|
|
|
if (rle_cache_initialized) {
|
|
|
|
rle_cache_initialized = 0;
|
2014-11-15 03:10:09 +00:00
|
|
|
range_for (auto &i, rle_cache)
|
|
|
|
i.expanded_bitmap.reset();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-27 22:00:14 +00:00
|
|
|
static void rle_cache_init()
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2016-01-09 16:38:11 +00:00
|
|
|
rle_cache = {};
|
2006-03-20 17:12:09 +00:00
|
|
|
rle_cache_initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rle_cache_flush()
|
|
|
|
{
|
2014-11-15 03:10:09 +00:00
|
|
|
range_for (auto &i, rle_cache)
|
|
|
|
{
|
|
|
|
i.rle_bitmap = NULL;
|
|
|
|
i.last_used = 0;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-30 22:09:17 +00:00
|
|
|
static void rle_expand_texture_sub(const grs_bitmap &bmp, grs_bitmap &rle_temp_bitmap_1)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-12-02 03:24:38 +00:00
|
|
|
auto sbits = &bmp.get_bitmap_data()[4 + bmp.bm_h];
|
|
|
|
auto dbits = rle_temp_bitmap_1.get_bitmap_data();
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2017-01-15 00:03:13 +00:00
|
|
|
rle_temp_bitmap_1.set_flags(bmp.get_flags() & (~BM_FLAG_RLE));
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2014-11-30 22:09:17 +00:00
|
|
|
for (int i=0; i < bmp.bm_h; i++ ) {
|
2017-04-08 16:48:17 +00:00
|
|
|
gr_rle_decode(sbits, dbits, rle_end(bmp, rle_temp_bitmap_1));
|
2016-06-16 03:56:44 +00:00
|
|
|
sbits += static_cast<int>(bmp.bm_data[4+i]);
|
2014-11-30 22:09:17 +00:00
|
|
|
dbits += bmp.bm_w;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-30 22:09:18 +00:00
|
|
|
grs_bitmap *_rle_expand_texture(const grs_bitmap &bmp)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
int lowest_count, lc;
|
|
|
|
|
|
|
|
if (!rle_cache_initialized) rle_cache_init();
|
|
|
|
|
2017-01-15 00:03:13 +00:00
|
|
|
Assert(!(bmp.get_flag_mask(BM_FLAG_PAGED_OUT)));
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
lc = rle_counter;
|
|
|
|
rle_counter++;
|
2009-11-30 22:42:55 +00:00
|
|
|
|
|
|
|
if (rle_counter < 0)
|
|
|
|
rle_counter = 0;
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
if ( rle_counter < lc ) {
|
2016-07-10 04:11:34 +00:00
|
|
|
rle_cache_flush();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lowest_count = rle_cache[rle_next].last_used;
|
2016-07-10 04:11:34 +00:00
|
|
|
auto least_recently_used = &rle_cache[rle_next];
|
2006-03-20 17:12:09 +00:00
|
|
|
rle_next++;
|
2016-07-10 04:11:34 +00:00
|
|
|
if (rle_next >= rle_cache.size())
|
2006-03-20 17:12:09 +00:00
|
|
|
rle_next = 0;
|
|
|
|
|
2016-07-10 04:11:34 +00:00
|
|
|
range_for (auto &i, rle_cache)
|
|
|
|
{
|
|
|
|
if (i.rle_bitmap == &bmp)
|
|
|
|
{
|
|
|
|
i.last_used = rle_counter;
|
|
|
|
return i.expanded_bitmap.get();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2016-07-10 04:11:34 +00:00
|
|
|
if (i.last_used < lowest_count)
|
|
|
|
{
|
|
|
|
lowest_count = (least_recently_used = &i)->last_used;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-10 04:11:34 +00:00
|
|
|
least_recently_used->expanded_bitmap = gr_create_bitmap(bmp.bm_w, bmp.bm_h);
|
|
|
|
rle_expand_texture_sub(bmp, *least_recently_used->expanded_bitmap.get());
|
|
|
|
least_recently_used->rle_bitmap = &bmp;
|
|
|
|
least_recently_used->last_used = rle_counter;
|
|
|
|
return least_recently_used->expanded_bitmap.get();
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2017-01-01 00:45:45 +00:00
|
|
|
void gr_rle_expand_scanline_generic(grs_canvas &canvas, grs_bitmap &dest, int dx, const int dy, const uint8_t *src, const int x1, const int x2)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-09-26 02:42:14 +00:00
|
|
|
int i = 0;
|
2006-03-20 17:12:09 +00:00
|
|
|
int count;
|
|
|
|
ubyte color=0;
|
|
|
|
|
|
|
|
if ( x2 < x1 ) return;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
while ( i < x1 ) {
|
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
|
|
|
count = color & NOT_RLE_CODE;
|
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
i += count;
|
|
|
|
}
|
|
|
|
count = i - x1;
|
|
|
|
i = x1;
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
|
|
|
|
if ( x1+count > x2 ) {
|
|
|
|
count = x2-x1+1;
|
2014-09-26 02:42:14 +00:00
|
|
|
for ( int j=0; j<count; j++ )
|
2017-01-01 00:45:45 +00:00
|
|
|
gr_bm_pixel(canvas, dest, dx++, dy, color);
|
2006-03-20 17:12:09 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-26 02:42:14 +00:00
|
|
|
for ( int j=0; j<count; j++ )
|
2017-01-01 00:45:45 +00:00
|
|
|
gr_bm_pixel(canvas, dest, dx++, dy, color);
|
2006-03-20 17:12:09 +00:00
|
|
|
i += count;
|
|
|
|
|
|
|
|
while( i <= x2 ) {
|
|
|
|
color = *src++;
|
|
|
|
if ( color == RLE_CODE ) return;
|
|
|
|
if ( IS_RLE_CODE(color) ) {
|
|
|
|
count = color & NOT_RLE_CODE;
|
|
|
|
color = *src++;
|
|
|
|
} else {
|
|
|
|
// unique
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
// we know have '*count' pixels of 'color'.
|
|
|
|
if ( i+count <= x2 ) {
|
2014-09-26 02:42:14 +00:00
|
|
|
for ( int j=0; j<count; j++ )
|
2017-01-01 00:45:45 +00:00
|
|
|
gr_bm_pixel(canvas, dest, dx++, dy, color);
|
2006-03-20 17:12:09 +00:00
|
|
|
i += count;
|
|
|
|
} else {
|
|
|
|
count = x2-i+1;
|
2014-09-26 02:42:14 +00:00
|
|
|
for ( int j=0; j<count; j++ )
|
2017-01-01 00:45:45 +00:00
|
|
|
gr_bm_pixel(canvas, dest, dx++, dy, color);
|
2006-03-20 17:12:09 +00:00
|
|
|
i += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* swaps entries 0 and 255 in an RLE bitmap without uncompressing it
|
|
|
|
*/
|
2015-01-29 04:27:37 +00:00
|
|
|
void rle_swap_0_255(grs_bitmap &bmp)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-09-26 02:42:14 +00:00
|
|
|
int len, rle_big;
|
2014-11-19 04:14:10 +00:00
|
|
|
unsigned char *start;
|
2006-03-20 17:12:09 +00:00
|
|
|
unsigned short line_size;
|
|
|
|
|
2017-01-15 00:03:13 +00:00
|
|
|
rle_big = bmp.get_flag_mask(BM_FLAG_RLE_BIG);
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-01-28 03:42:53 +00:00
|
|
|
RAIIdmem<uint8_t[]> temp;
|
2015-01-29 04:27:37 +00:00
|
|
|
MALLOC(temp, uint8_t[], MAX_BMP_SIZE(bmp.bm_w, bmp.bm_h));
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-01-29 04:27:37 +00:00
|
|
|
const std::size_t pointer_offset = rle_big ? 4 + 2 * bmp.bm_h : 4 + bmp.bm_h;
|
|
|
|
auto ptr = &bmp.bm_data[pointer_offset];
|
2014-11-19 04:14:10 +00:00
|
|
|
auto ptr2 = &temp[pointer_offset];
|
2015-01-29 04:27:37 +00:00
|
|
|
for (int i = 0; i < bmp.bm_h; i++) {
|
2006-03-20 17:12:09 +00:00
|
|
|
start = ptr2;
|
|
|
|
if (rle_big)
|
2015-06-13 22:42:21 +00:00
|
|
|
line_size = GET_INTEL_SHORT(&bmp.bm_data[4 + 2 * i]);
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
2015-01-29 04:27:37 +00:00
|
|
|
line_size = bmp.bm_data[4 + i];
|
2014-09-26 02:42:14 +00:00
|
|
|
for (int j = 0; j < line_size; j++) {
|
2006-03-20 17:12:09 +00:00
|
|
|
if ( ! IS_RLE_CODE(ptr[j]) ) {
|
|
|
|
if (ptr[j] == 0) {
|
|
|
|
*ptr2++ = RLE_CODE | 1;
|
|
|
|
*ptr2++ = 255;
|
|
|
|
} else
|
|
|
|
*ptr2++ = ptr[j];
|
|
|
|
} else {
|
|
|
|
*ptr2++ = ptr[j];
|
|
|
|
if ((ptr[j] & NOT_RLE_CODE) == 0)
|
|
|
|
break;
|
|
|
|
j++;
|
|
|
|
if (ptr[j] == 0)
|
|
|
|
*ptr2++ = 255;
|
|
|
|
else if (ptr[j] == 255)
|
|
|
|
*ptr2++ = 0;
|
|
|
|
else
|
|
|
|
*ptr2++ = ptr[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rle_big) // set line size
|
2015-04-02 02:36:52 +00:00
|
|
|
PUT_INTEL_SHORT(&temp[4 + 2 * i], static_cast<uint16_t>(ptr2 - start));
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
|
|
|
temp[4 + i] = ptr2 - start;
|
|
|
|
ptr += line_size; // go to next line
|
|
|
|
}
|
2015-02-17 03:52:59 +00:00
|
|
|
len = ptr2 - temp.get();
|
|
|
|
memcpy(bmp.get_bitmap_data(), &len, 4);
|
|
|
|
memcpy(&bmp.get_bitmap_data()[4], &temp.get()[4], len - 4);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remaps all entries using colormap in an RLE bitmap without uncompressing it
|
|
|
|
*/
|
2015-01-29 04:27:37 +00:00
|
|
|
void rle_remap(grs_bitmap &bmp, array<color_t, 256> &colormap)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-09-26 02:42:14 +00:00
|
|
|
int len, rle_big;
|
2014-11-19 04:14:33 +00:00
|
|
|
unsigned char *start;
|
2006-03-20 17:12:09 +00:00
|
|
|
unsigned short line_size;
|
|
|
|
|
2017-01-15 00:03:13 +00:00
|
|
|
rle_big = bmp.get_flag_mask(BM_FLAG_RLE_BIG);
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-01-28 03:42:53 +00:00
|
|
|
RAIIdmem<uint8_t[]> temp;
|
2015-01-29 04:27:37 +00:00
|
|
|
MALLOC(temp, uint8_t[], MAX_BMP_SIZE(bmp.bm_w, bmp.bm_h) + 30000);
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-01-29 04:27:37 +00:00
|
|
|
const std::size_t pointer_offset = rle_big ? 4 + 2 * bmp.bm_h : 4 + bmp.bm_h;
|
|
|
|
auto ptr = &bmp.get_bitmap_data()[pointer_offset];
|
2014-11-19 04:14:33 +00:00
|
|
|
auto ptr2 = &temp[pointer_offset];
|
2015-01-29 04:27:37 +00:00
|
|
|
for (int i = 0; i < bmp.bm_h; i++) {
|
2006-03-20 17:12:09 +00:00
|
|
|
start = ptr2;
|
|
|
|
if (rle_big)
|
2015-07-14 02:42:12 +00:00
|
|
|
line_size = GET_INTEL_SHORT(&bmp.get_bitmap_data()[4 + 2 * i]);
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
2015-01-29 04:27:37 +00:00
|
|
|
line_size = bmp.get_bitmap_data()[4 + i];
|
2014-09-26 02:42:14 +00:00
|
|
|
for (int j = 0; j < line_size; j++) {
|
2006-03-20 17:12:09 +00:00
|
|
|
if ( ! IS_RLE_CODE(ptr[j])) {
|
|
|
|
if (IS_RLE_CODE(colormap[ptr[j]]))
|
|
|
|
*ptr2++ = RLE_CODE | 1; // add "escape sequence"
|
|
|
|
*ptr2++ = colormap[ptr[j]]; // translate
|
|
|
|
} else {
|
|
|
|
*ptr2++ = ptr[j]; // just copy current rle code
|
|
|
|
if ((ptr[j] & NOT_RLE_CODE) == 0)
|
|
|
|
break;
|
|
|
|
j++;
|
|
|
|
*ptr2++ = colormap[ptr[j]]; // translate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rle_big) // set line size
|
2015-04-02 02:36:52 +00:00
|
|
|
PUT_INTEL_SHORT(&temp[4 + 2 * i], static_cast<uint16_t>(ptr2 - start));
|
2006-03-20 17:12:09 +00:00
|
|
|
else
|
|
|
|
temp[4 + i] = ptr2 - start;
|
|
|
|
ptr += line_size; // go to next line
|
|
|
|
}
|
2015-02-17 03:52:59 +00:00
|
|
|
len = ptr2 - temp.get();
|
|
|
|
memcpy(bmp.get_bitmap_data(), &len, 4);
|
|
|
|
memcpy(&bmp.get_bitmap_data()[4], &temp.get()[4], len - 4);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2015-12-05 22:57:23 +00:00
|
|
|
|
2017-02-11 21:42:30 +00:00
|
|
|
void bm_rle_src_stride::advance_src_bits()
|
|
|
|
{
|
|
|
|
/* Both bytes are always legal to read since the bitmap data
|
|
|
|
* is placed after the length table. Reading both, then
|
|
|
|
* conditionally masking out the high bits (dependent on
|
|
|
|
* BM_FLAG_RLE_BIG) encourages the compiler to implement
|
|
|
|
* this line without using branches.
|
|
|
|
*/
|
|
|
|
const uintptr_t u = (ptr_src_bit_lengths[0] | (static_cast<uintptr_t>(ptr_src_bit_lengths[1]) << 8)) & src_bit_load_mask;
|
|
|
|
ptr_src_bit_lengths += src_bit_stride_size;
|
|
|
|
src_bits += u;
|
|
|
|
}
|
|
|
|
|
|
|
|
bm_rle_expand::step_result bm_rle_expand::step_internal(uint8_t *const begin_dbits, uint8_t *const end_dbits)
|
|
|
|
{
|
2017-04-08 16:48:17 +00:00
|
|
|
const auto rd = gr_rle_decode(src_bits, begin_dbits, {end_src_bm, end_dbits});
|
2017-02-11 21:42:30 +00:00
|
|
|
/* If the destination buffer is exhausted, return without
|
|
|
|
* modifying the source state. This lets the caller retry
|
|
|
|
* with a larger buffer, if desired.
|
|
|
|
*/
|
2017-04-08 16:48:17 +00:00
|
|
|
if (unlikely(begin_dbits == rd))
|
2017-02-11 21:42:30 +00:00
|
|
|
return dst_exhausted;
|
|
|
|
advance_src_bits();
|
|
|
|
return again;
|
|
|
|
}
|
|
|
|
|
2015-12-05 22:57:23 +00:00
|
|
|
}
|