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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2008-03-20 23:23:46 +00:00
|
|
|
*
|
2006-03-20 17:12:09 +00:00
|
|
|
* Graphical routines for setting the palette
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2013-12-17 22:14:43 +00:00
|
|
|
#include <algorithm>
|
2006-03-20 17:12:09 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2011-06-01 07:59:55 +00:00
|
|
|
#include "physfsx.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "pstypes.h"
|
|
|
|
#include "u_mem.h"
|
|
|
|
#include "gr.h"
|
|
|
|
#include "grdef.h"
|
2012-07-07 18:35:06 +00:00
|
|
|
#include "dxxerror.h"
|
2012-07-01 02:54:33 +00:00
|
|
|
#include "maths.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "palette.h"
|
|
|
|
|
2013-01-06 21:11:53 +00:00
|
|
|
#include "dxxsconf.h"
|
2015-04-26 20:15:57 +00:00
|
|
|
#include "compiler-array.h"
|
2013-01-06 21:11:53 +00:00
|
|
|
#include "compiler-range_for.h"
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-13 18:00:48 +00:00
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
#define SQUARE(x) ((x)*(x))
|
|
|
|
|
|
|
|
#define MAX_COMPUTED_COLORS 32
|
|
|
|
|
2014-09-20 23:47:27 +00:00
|
|
|
static unsigned Num_computed_colors;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-12-22 22:03:07 +00:00
|
|
|
struct color_record {
|
2014-08-08 02:07:47 +00:00
|
|
|
ubyte r,g,b;
|
|
|
|
color_t color_num;
|
2013-12-22 22:03:07 +00:00
|
|
|
};
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-04-26 20:15:57 +00:00
|
|
|
static array<color_record, MAX_COMPUTED_COLORS> Computed_colors;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-01-06 21:03:57 +00:00
|
|
|
palette_array_t gr_palette;
|
|
|
|
palette_array_t gr_current_pal;
|
2014-08-08 02:44:27 +00:00
|
|
|
gft_array1 gr_fade_table;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
ubyte gr_palette_gamma = 0;
|
|
|
|
int gr_palette_gamma_param = 0;
|
|
|
|
|
2015-12-13 18:00:48 +00:00
|
|
|
}
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dsx {
|
2015-12-13 18:00:48 +00:00
|
|
|
|
2013-12-17 22:14:43 +00:00
|
|
|
void copy_bound_palette(palette_array_t &d, const palette_array_t &s)
|
|
|
|
{
|
2013-01-06 21:11:53 +00:00
|
|
|
auto a = [](rgb_t c) {
|
2013-12-17 22:14:43 +00:00
|
|
|
const ubyte bound = 63;
|
2013-01-06 21:11:53 +00:00
|
|
|
c.r = std::min(c.r, bound);
|
|
|
|
c.g = std::min(c.g, bound);
|
|
|
|
c.b = std::min(c.b, bound);
|
|
|
|
return c;
|
|
|
|
};
|
|
|
|
std::transform(s.begin(), s.end(), d.begin(), a);
|
2013-12-17 22:14:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void copy_diminish_palette(palette_array_t &palette, const ubyte *p)
|
|
|
|
{
|
2013-01-06 21:11:53 +00:00
|
|
|
for (unsigned i = 0; i < palette.size(); i++) {
|
|
|
|
palette[i].r = *p++ >> 2;
|
|
|
|
palette[i].g = *p++ >> 2;
|
|
|
|
palette[i].b = *p++ >> 2;
|
2013-12-17 22:14:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-06 21:11:53 +00:00
|
|
|
static void diminish_entry(rgb_t &c)
|
|
|
|
{
|
|
|
|
c.r >>= 2;
|
|
|
|
c.g >>= 2;
|
|
|
|
c.b >>= 2;
|
|
|
|
}
|
|
|
|
|
2013-12-17 22:14:43 +00:00
|
|
|
void diminish_palette(palette_array_t &palette)
|
|
|
|
{
|
2013-01-06 21:11:53 +00:00
|
|
|
range_for (rgb_t &c, palette)
|
|
|
|
diminish_entry(c);
|
2013-12-17 22:14:43 +00:00
|
|
|
}
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
void gr_palette_set_gamma( int gamma )
|
|
|
|
{
|
|
|
|
if ( gamma < 0 ) gamma = 0;
|
|
|
|
if ( gamma > 16 ) gamma = 16; //was 8
|
|
|
|
|
|
|
|
if (gr_palette_gamma_param != gamma ) {
|
|
|
|
gr_palette_gamma_param = gamma;
|
|
|
|
gr_palette_gamma = gamma;
|
2008-03-20 23:23:46 +00:00
|
|
|
gr_palette_load( gr_palette );
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int gr_palette_get_gamma()
|
|
|
|
{
|
|
|
|
return gr_palette_gamma_param;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2013-01-06 21:03:57 +00:00
|
|
|
void gr_copy_palette(palette_array_t &gr_palette, const palette_array_t &pal)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2013-01-06 21:11:53 +00:00
|
|
|
gr_palette = pal;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
Num_computed_colors = 0;
|
|
|
|
}
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2013-06-08 22:24:17 +00:00
|
|
|
void gr_use_palette_table(const char * filename )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-08-08 02:44:27 +00:00
|
|
|
int fsize;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-01-17 18:31:42 +00:00
|
|
|
auto fp = PHYSFSX_openReadBuffered(filename);
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
|
|
#define FAILURE_FORMAT "Can't open palette file <%s>"
|
|
|
|
#elif defined(DXX_BUILD_DESCENT_II)
|
|
|
|
#define FAILURE_FORMAT "Can open neither palette file <%s> nor default palette file <" DEFAULT_LEVEL_PALETTE ">"
|
2006-03-20 17:12:09 +00:00
|
|
|
// the following is a hack to enable the loading of d2 levels
|
|
|
|
// even if only the d2 mac shareware datafiles are present.
|
|
|
|
// However, if the pig file is present but the palette file isn't,
|
|
|
|
// the textures in the level will look wierd...
|
2015-01-17 18:31:42 +00:00
|
|
|
if (!fp)
|
2011-06-01 07:59:55 +00:00
|
|
|
fp = PHYSFSX_openReadBuffered( DEFAULT_LEVEL_PALETTE );
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2015-01-17 18:31:42 +00:00
|
|
|
if (!fp)
|
2013-03-03 01:03:33 +00:00
|
|
|
Error(FAILURE_FORMAT,
|
2006-03-20 17:12:09 +00:00
|
|
|
filename);
|
|
|
|
|
2011-06-01 07:59:55 +00:00
|
|
|
fsize = PHYSFS_fileLength( fp );
|
2006-03-20 17:12:09 +00:00
|
|
|
Assert( fsize == 9472 );
|
2011-09-26 23:31:19 +00:00
|
|
|
(void)fsize;
|
2013-01-06 21:11:53 +00:00
|
|
|
PHYSFS_read( fp, &gr_palette[0], sizeof(gr_palette[0]), gr_palette.size() );
|
2011-06-01 07:59:55 +00:00
|
|
|
PHYSFS_read( fp, gr_fade_table, 256*34, 1 );
|
2015-01-17 18:31:42 +00:00
|
|
|
fp.reset();
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
// This is the TRANSPARENCY COLOR
|
2014-08-08 02:44:27 +00:00
|
|
|
range_for (auto &i, gr_fade_table)
|
|
|
|
i[255] = 255;
|
2013-03-03 01:03:33 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_II)
|
2006-03-20 17:12:09 +00:00
|
|
|
Num_computed_colors = 0; // Flush palette cache.
|
|
|
|
// swap colors 0 and 255 of the palette along with fade table entries
|
|
|
|
|
|
|
|
#ifdef SWAP_0_255
|
|
|
|
for (i = 0; i < 3; i++) {
|
2013-03-03 01:03:33 +00:00
|
|
|
ubyte c;
|
2006-03-20 17:12:09 +00:00
|
|
|
c = gr_palette[i];
|
|
|
|
gr_palette[i] = gr_palette[765+i];
|
|
|
|
gr_palette[765+i] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < GR_FADE_LEVELS * 256; i++) {
|
|
|
|
if (gr_fade_table[i] == 0)
|
|
|
|
gr_fade_table[i] = 255;
|
|
|
|
}
|
|
|
|
for (i=0; i<GR_FADE_LEVELS; i++)
|
|
|
|
gr_fade_table[i*256] = TRANSPARENCY_COLOR;
|
|
|
|
#endif
|
2013-03-03 01:03:33 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2015-12-13 18:00:48 +00:00
|
|
|
}
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-13 18:00:48 +00:00
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
// Add a computed color (by gr_find_closest_color) to list of computed colors in Computed_colors.
|
|
|
|
// If list wasn't full already, increment Num_computed_colors.
|
|
|
|
// If was full, replace a random one.
|
2014-08-08 02:07:47 +00:00
|
|
|
static void add_computed_color(int r, int g, int b, color_t color_num)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
|
|
|
int add_index;
|
|
|
|
|
|
|
|
if (Num_computed_colors < MAX_COMPUTED_COLORS) {
|
|
|
|
add_index = Num_computed_colors;
|
|
|
|
Num_computed_colors++;
|
|
|
|
} else
|
|
|
|
add_index = (d_rand() * MAX_COMPUTED_COLORS) >> 15;
|
|
|
|
|
|
|
|
Computed_colors[add_index].r = r;
|
|
|
|
Computed_colors[add_index].g = g;
|
|
|
|
Computed_colors[add_index].b = b;
|
|
|
|
Computed_colors[add_index].color_num = color_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
void init_computed_colors(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<MAX_COMPUTED_COLORS; i++)
|
|
|
|
Computed_colors[i].r = 255; // Make impossible to match.
|
|
|
|
}
|
|
|
|
|
2014-08-08 02:07:47 +00:00
|
|
|
color_t gr_find_closest_color( int r, int g, int b )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-08-08 02:07:47 +00:00
|
|
|
int j;
|
|
|
|
int best_value, value;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
if (Num_computed_colors == 0)
|
|
|
|
init_computed_colors();
|
|
|
|
|
|
|
|
// If we've already computed this color, return it!
|
2014-08-08 02:07:47 +00:00
|
|
|
for (unsigned i=0; i<Num_computed_colors; i++)
|
2015-04-26 20:15:57 +00:00
|
|
|
{
|
|
|
|
auto &c = Computed_colors[i];
|
|
|
|
if (r == c.r && g == c.g && b == c.b)
|
|
|
|
{
|
|
|
|
const auto color_num = c.color_num;
|
2006-03-20 17:12:09 +00:00
|
|
|
if (i > 4) {
|
2015-04-26 20:15:57 +00:00
|
|
|
std::swap(Computed_colors[i-1], c);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2015-04-26 20:15:56 +00:00
|
|
|
return color_num;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2015-04-26 20:15:57 +00:00
|
|
|
}
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
// r &= 63;
|
|
|
|
// g &= 63;
|
|
|
|
// b &= 63;
|
|
|
|
|
2013-01-06 21:11:53 +00:00
|
|
|
best_value = SQUARE(r-gr_palette[0].r)+SQUARE(g-gr_palette[0].g)+SQUARE(b-gr_palette[0].b);
|
2014-08-08 02:07:47 +00:00
|
|
|
color_t best_index = 0;
|
2006-03-20 17:12:09 +00:00
|
|
|
if (best_value==0) {
|
|
|
|
add_computed_color(r, g, b, best_index);
|
|
|
|
return best_index;
|
|
|
|
}
|
|
|
|
j=0;
|
|
|
|
// only go to 255, 'cause we dont want to check the transparent color.
|
2014-08-08 02:07:47 +00:00
|
|
|
for (color_t i=1; i < 254; i++ ) {
|
2013-01-06 21:11:53 +00:00
|
|
|
++j;
|
|
|
|
value = SQUARE(r-gr_palette[j].r)+SQUARE(g-gr_palette[j].g)+SQUARE(b-gr_palette[j].b);
|
2006-03-20 17:12:09 +00:00
|
|
|
if ( value < best_value ) {
|
|
|
|
if (value==0) {
|
|
|
|
add_computed_color(r, g, b, i);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
best_value = value;
|
|
|
|
best_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_computed_color(r, g, b, best_index);
|
|
|
|
return best_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gr_find_closest_color_15bpp( int rgb )
|
|
|
|
{
|
|
|
|
return gr_find_closest_color( ((rgb>>10)&31)*2, ((rgb>>5)&31)*2, (rgb&31)*2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-08 02:07:47 +00:00
|
|
|
color_t gr_find_closest_color_current( int r, int g, int b )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-08-08 02:07:47 +00:00
|
|
|
int j;
|
|
|
|
int best_value, value;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
// r &= 63;
|
|
|
|
// g &= 63;
|
|
|
|
// b &= 63;
|
|
|
|
|
2013-01-06 21:11:53 +00:00
|
|
|
best_value = SQUARE(r-gr_current_pal[0].r)+SQUARE(g-gr_current_pal[0].g)+SQUARE(b-gr_current_pal[0].b);
|
2014-08-08 02:07:47 +00:00
|
|
|
color_t best_index = 0;
|
2006-03-20 17:12:09 +00:00
|
|
|
if (best_value==0)
|
|
|
|
return best_index;
|
|
|
|
|
|
|
|
j=0;
|
|
|
|
// only go to 255, 'cause we dont want to check the transparent color.
|
2014-08-08 02:07:47 +00:00
|
|
|
for (color_t i=1; i < 254; i++ ) {
|
2013-01-06 21:11:53 +00:00
|
|
|
++j;
|
|
|
|
value = SQUARE(r-gr_current_pal[j].r)+SQUARE(g-gr_current_pal[j].g)+SQUARE(b-gr_current_pal[j].b);
|
2006-03-20 17:12:09 +00:00
|
|
|
if ( value < best_value ) {
|
|
|
|
if (value==0)
|
|
|
|
return i;
|
|
|
|
best_value = value;
|
|
|
|
best_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return best_index;
|
|
|
|
}
|
2015-12-13 18:00:48 +00:00
|
|
|
|
|
|
|
}
|