dxx-rebirth/similar/2d/palette.cpp

262 lines
6.5 KiB
C++
Raw Normal View History

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.
*/
/*
*
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>
#include "physfsx.h"
2006-03-20 17:12:09 +00:00
#include "pstypes.h"
#include "u_mem.h"
#include "gr.h"
#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"
2021-09-04 12:17:14 +00:00
#include "d_enumerate.h"
2013-01-06 21:11:53 +00:00
#include "dxxsconf.h"
#include "dsx-ns.h"
2013-01-06 21:11:53 +00:00
#include "compiler-range_for.h"
#include <array>
2013-01-06 21:11:53 +00:00
2015-12-13 18:00:49 +00:00
namespace dcx {
2020-12-26 21:17:29 +00:00
namespace {
unsigned get_squared_color_delta(const int r, const int g, const int b, const rgb_t &rgb)
{
const auto dr = r - rgb.r;
const auto dg = g - rgb.g;
const auto db = b - rgb.b;
return (dr * dr) + (dg * dg) + (db * db);
}
2021-09-04 12:17:14 +00:00
color_palette_index gr_find_closest_color_palette(const int r, const int g, const int b, const palette_array_t &palette)
{
// Anything is better than this.
unsigned best_value = UINT_MAX;
color_palette_index best_index{};
// only go to 255, 'cause we dont want to check the transparent color.
for (auto &&[candidate_idx, candidate_rgb] : enumerate(unchecked_partial_range(palette, palette.size() - 1)))
2021-09-04 12:17:14 +00:00
{
const auto candidate_value = get_squared_color_delta(r, g, b, candidate_rgb);
if (best_value > candidate_value)
{
best_index = candidate_idx;
if (candidate_value == 0)
/* Perfect match */
break;
best_value = candidate_value;
}
}
return best_index;
}
2014-09-20 23:47:27 +00:00
static unsigned Num_computed_colors;
2006-03-20 17:12:09 +00:00
struct color_record {
uint8_t r, g, b;
color_palette_index color_num;
};
2006-03-20 17:12:09 +00:00
2020-12-27 22:03:09 +00:00
uint8_t gr_palette_gamma_param;
2006-03-20 17:12:09 +00:00
2020-12-26 21:17:29 +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;
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) {
constexpr uint8_t 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
}
}
namespace dcx {
2020-12-26 21:17:29 +00:00
namespace {
2013-01-06 21:11:53 +00:00
static void diminish_entry(rgb_t &c)
{
c.r >>= 2;
c.g >>= 2;
c.b >>= 2;
}
2020-12-26 21:17:29 +00:00
}
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;
gr_palette_load( gr_palette );
2006-03-20 17:12:09 +00:00
}
}
int gr_palette_get_gamma()
{
return gr_palette_gamma_param;
}
}
namespace dsx {
2006-03-20 17:12:09 +00:00
#if defined(DXX_BUILD_DESCENT_II)
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;
}
#endif
2006-03-20 17:12:09 +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
auto &&[fp, physfserr] = PHYSFSX_openReadBuffered(filename);
if (!fp)
{
#if defined(DXX_BUILD_DESCENT_I)
Error("Failed to open palette file <%s>: %s", filename, PHYSFS_getErrorByCode(physfserr));
#elif defined(DXX_BUILD_DESCENT_II)
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...
auto &&[fp2, physfserr2] = PHYSFSX_openReadBuffered(DEFAULT_LEVEL_PALETTE);
if (!fp)
Error("Failed to open both palette file <%s> and default palette file <" DEFAULT_LEVEL_PALETTE ">: (\"%s\", \"%s\")", filename, PHYSFS_getErrorByCode(physfserr), PHYSFS_getErrorByCode(physfserr2));
fp = std::move(fp2);
#endif
}
2006-03-20 17:12:09 +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() );
PHYSFS_read( fp, gr_fade_table, 256*34, 1 );
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;
#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++) {
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
#endif
2006-03-20 17:12:09 +00:00
}
}
2015-12-13 18:00:49 +00:00
namespace dcx {
void reset_computed_colors()
2006-03-20 17:12:09 +00:00
{
Num_computed_colors = 0;
2006-03-20 17:12:09 +00:00
}
color_palette_index gr_find_closest_color(const int r, const int g, const int b)
2006-03-20 17:12:09 +00:00
{
static std::array<color_record, 32> Computed_colors;
const auto num_computed_colors = Num_computed_colors;
2006-03-20 17:12:09 +00:00
// If we've already computed this color, return it!
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;
if (i)
{
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
}
// Add a computed color to list of computed colors in Computed_colors.
// If list wasn't full already, increment Num_computed_colors.
// If was full, replace the last one. Rely on the bubble-up logic
// above to move popular entries away from the end.
auto &cc = (num_computed_colors < Computed_colors.size())
? Computed_colors[Num_computed_colors++]
: Computed_colors.back();
cc.r = r;
cc.g = g;
cc.b = b;
return cc.color_num = gr_find_closest_color_palette(r, g, b, gr_palette);
2006-03-20 17:12:09 +00:00
}
color_palette_index gr_find_closest_color_15bpp( int rgb )
2006-03-20 17:12:09 +00:00
{
return gr_find_closest_color( ((rgb>>10)&31)*2, ((rgb>>5)&31)*2, (rgb&31)*2 );
}
2021-09-04 12:17:14 +00:00
color_palette_index gr_find_closest_color_current(const int r, const int g, const int b)
2006-03-20 17:12:09 +00:00
{
2021-09-04 12:17:14 +00:00
return gr_find_closest_color_palette(r, g, b, gr_current_pal);
2006-03-20 17:12:09 +00:00
}
}