Fix Descent 1 laser color
Descent 1 mangles colors during `g3_init_polygon_model`, so this must
not be called on polygons not designed for mangling. Rearrange the
logic to allow Descent 1 to verify that polygon models are well-formed
without using the functions that mangle the colors.
Fixes: 42a2e3ab0b
("Avoid crash loading polymodels with invalid subcalls")
Reported-by: derhass <https://github.com/dxx-rebirth/dxx-rebirth/issues/416>
This commit is contained in:
parent
3a6bfb8dd6
commit
87125c5053
|
@ -46,6 +46,9 @@ void g3_draw_polygon_model(grs_bitmap *const *model_bitmaps, polygon_model_point
|
||||||
|
|
||||||
//init code for bitmap models
|
//init code for bitmap models
|
||||||
int16_t g3_init_polygon_model(uint8_t *model_ptr, std::size_t model_size);
|
int16_t g3_init_polygon_model(uint8_t *model_ptr, std::size_t model_size);
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
void g3_validate_polygon_model(uint8_t *model_ptr, std::size_t model_size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,10 @@ int g3d_interp_outline;
|
||||||
|
|
||||||
namespace dsx {
|
namespace dsx {
|
||||||
|
|
||||||
static int16_t init_model_sub(uint8_t *model_sub_ptr, const uint8_t *model_base_ptr, std::size_t model_size, int16_t highest_texture_num);
|
static int16_t init_model_sub(uint8_t *model_sub_ptr, const uint8_t *model_base_ptr, std::size_t model_size);
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
static void validate_model_sub(uint8_t *model_sub_ptr, const uint8_t *model_base_ptr, std::size_t model_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline int16_t *wp(uint8_t *p)
|
static inline int16_t *wp(uint8_t *p)
|
||||||
{
|
{
|
||||||
|
@ -444,7 +447,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class init_model_sub_state :
|
template <typename T>
|
||||||
|
class model_load_state :
|
||||||
public interpreter_track_model_extent,
|
public interpreter_track_model_extent,
|
||||||
public interpreter_ignore_op_defpoints,
|
public interpreter_ignore_op_defpoints,
|
||||||
public interpreter_ignore_op_defp_start,
|
public interpreter_ignore_op_defp_start,
|
||||||
|
@ -453,55 +457,94 @@ class init_model_sub_state :
|
||||||
public interpreter_base
|
public interpreter_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int16_t highest_texture_num;
|
using interpreter_track_model_extent::interpreter_track_model_extent;
|
||||||
init_model_sub_state(const uint8_t *const model_base_ptr, const std::size_t model_size, const int16_t h) :
|
int16_t init_bounded_model_sub(const unsigned line, uint8_t *const p, const std::ptrdiff_t d) const
|
||||||
interpreter_track_model_extent(model_base_ptr, model_size),
|
|
||||||
highest_texture_num(h)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void op_flatpoly(uint8_t *const p, const uint_fast32_t nv) const
|
|
||||||
{
|
|
||||||
(void)nv;
|
|
||||||
Assert(nv > 2); //must have 3 or more points
|
|
||||||
#if defined(DXX_BUILD_DESCENT_I)
|
|
||||||
*wp(p+28) = static_cast<short>(gr_find_closest_color_15bpp(w(p+28)));
|
|
||||||
#elif defined(DXX_BUILD_DESCENT_II)
|
|
||||||
(void)p;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
void op_tmappoly(uint8_t *const p, const uint_fast32_t nv)
|
|
||||||
{
|
|
||||||
(void)nv;
|
|
||||||
Assert(nv > 2); //must have 3 or more points
|
|
||||||
if (truncate_invalid_model(__LINE__, p, 28, sizeof(uint16_t)))
|
|
||||||
return;
|
|
||||||
if (w(p+28) > highest_texture_num)
|
|
||||||
highest_texture_num = w(p+28);
|
|
||||||
}
|
|
||||||
uint16_t init_bounded_model_sub(const unsigned line, uint8_t *const p, const std::ptrdiff_t d, const uint16_t highest_texture_num) const
|
|
||||||
{
|
{
|
||||||
if (truncate_invalid_model(line, p, d, sizeof(uint16_t)))
|
if (truncate_invalid_model(line, p, d, sizeof(uint16_t)))
|
||||||
return 0;
|
return 0;
|
||||||
return init_model_sub(p + d, model_base, model_length, highest_texture_num);
|
return static_cast<const T *>(this)->init_sub_model(p + d);
|
||||||
|
}
|
||||||
|
void op_tmappoly(uint8_t *const p, const uint_fast32_t nv)
|
||||||
|
{
|
||||||
|
constexpr unsigned offset_texture = 28;
|
||||||
|
(void)nv;
|
||||||
|
Assert(nv > 2); //must have 3 or more points
|
||||||
|
if (truncate_invalid_model(__LINE__, p, offset_texture, sizeof(uint16_t)))
|
||||||
|
return;
|
||||||
|
static_cast<T *>(this)->update_texture(w(p + offset_texture));
|
||||||
}
|
}
|
||||||
void op_sortnorm(uint8_t *const p)
|
void op_sortnorm(uint8_t *const p)
|
||||||
{
|
{
|
||||||
if (truncate_invalid_model(__LINE__, p, 30, sizeof(uint16_t)))
|
constexpr unsigned offset_submodel0 = 28;
|
||||||
|
constexpr unsigned offset_submodel1 = offset_submodel0 + sizeof(uint16_t);
|
||||||
|
if (truncate_invalid_model(__LINE__, p, offset_submodel1, sizeof(uint16_t)))
|
||||||
return;
|
return;
|
||||||
const auto n0 = w(p + 28);
|
const auto n0 = w(p + offset_submodel0);
|
||||||
const auto n1 = w(p + 30);
|
const auto h0 = init_bounded_model_sub(__LINE__, p, n0);
|
||||||
auto h = init_bounded_model_sub(__LINE__, p, n0, highest_texture_num);
|
const auto n1 = w(p + offset_submodel1);
|
||||||
highest_texture_num = init_bounded_model_sub(__LINE__, p, n1, h);
|
const auto h1 = init_bounded_model_sub(__LINE__, p, n1);
|
||||||
|
const auto hm = std::max(h0, h1);
|
||||||
|
static_cast<T *>(this)->update_texture(hm);
|
||||||
}
|
}
|
||||||
void op_subcall(uint8_t *const p)
|
void op_subcall(uint8_t *const p)
|
||||||
{
|
{
|
||||||
if (truncate_invalid_model(__LINE__, p, 16, sizeof(uint16_t)))
|
constexpr unsigned offset_displacement = 16;
|
||||||
|
if (truncate_invalid_model(__LINE__, p, offset_displacement, sizeof(uint16_t)))
|
||||||
return;
|
return;
|
||||||
const auto n0 = w(p + 16);
|
const auto n0 = w(p + offset_displacement);
|
||||||
highest_texture_num = init_bounded_model_sub(__LINE__, p, n0, highest_texture_num);
|
const auto h0 = init_bounded_model_sub(__LINE__, p, n0);
|
||||||
|
static_cast<T *>(this)->update_texture(h0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class init_model_sub_state :
|
||||||
|
public model_load_state<init_model_sub_state>
|
||||||
|
#if defined(DXX_BUILD_DESCENT_II)
|
||||||
|
, public interpreter_ignore_op_flatpoly
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int16_t highest_texture_num = -1;
|
||||||
|
using model_load_state::model_load_state;
|
||||||
|
int16_t init_sub_model(uint8_t *const p) const
|
||||||
|
{
|
||||||
|
return init_model_sub(p, model_base, model_length);
|
||||||
|
}
|
||||||
|
void update_texture(const int16_t t)
|
||||||
|
{
|
||||||
|
if (highest_texture_num < t)
|
||||||
|
highest_texture_num = t;
|
||||||
|
}
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
void op_flatpoly(uint8_t *const p, const uint_fast32_t nv) const
|
||||||
|
{
|
||||||
|
//must have 3 or more points
|
||||||
|
if (nv <= 2)
|
||||||
|
return;
|
||||||
|
const auto p16 = wp(p + 28);
|
||||||
|
*p16 = static_cast<short>(gr_find_closest_color_15bpp(*p16));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
class validate_model_sub_state :
|
||||||
|
public model_load_state<validate_model_sub_state>,
|
||||||
|
public interpreter_ignore_op_flatpoly
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using model_load_state::model_load_state;
|
||||||
|
unsigned init_sub_model(uint8_t *const p) const
|
||||||
|
{
|
||||||
|
validate_model_sub(p, model_base, model_length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void update_texture(int16_t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
constexpr const glow_values_t *g3_draw_morphing_model_state::glow_values;
|
constexpr const glow_values_t *g3_draw_morphing_model_state::glow_values;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -794,9 +837,9 @@ void g3_draw_morphing_model(grs_canvas &canvas, const uint8_t *const p, grs_bitm
|
||||||
iterate_polymodel(p, state);
|
iterate_polymodel(p, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t init_model_sub(uint8_t *const model_sub_ptr, const uint8_t *const model_base_ptr, const std::size_t model_size, const int16_t highest_texture_num)
|
static int16_t init_model_sub(uint8_t *const model_sub_ptr, const uint8_t *const model_base_ptr, const std::size_t model_size)
|
||||||
{
|
{
|
||||||
init_model_sub_state state(model_base_ptr, model_size, highest_texture_num);
|
init_model_sub_state state(model_base_ptr, model_size);
|
||||||
Assert(++nest_count < 1000);
|
Assert(++nest_count < 1000);
|
||||||
iterate_polymodel(model_sub_ptr, state);
|
iterate_polymodel(model_sub_ptr, state);
|
||||||
return state.highest_texture_num;
|
return state.highest_texture_num;
|
||||||
|
@ -808,7 +851,24 @@ int16_t g3_init_polygon_model(uint8_t *const model_ptr, const std::size_t model_
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
nest_count = 0;
|
nest_count = 0;
|
||||||
#endif
|
#endif
|
||||||
return init_model_sub(model_ptr, model_ptr, model_size, -1);
|
return init_model_sub(model_ptr, model_ptr, model_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
static void validate_model_sub(uint8_t *const model_sub_ptr, const uint8_t *const model_base_ptr, const std::size_t model_size)
|
||||||
|
{
|
||||||
|
validate_model_sub_state state(model_base_ptr, model_size);
|
||||||
|
assert(++nest_count < 1000);
|
||||||
|
iterate_polymodel(model_sub_ptr, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void g3_validate_polygon_model(uint8_t *const model_ptr, const std::size_t model_size)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
nest_count = 0;
|
||||||
|
#endif
|
||||||
|
return validate_model_sub(model_ptr, model_ptr, model_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -758,6 +758,10 @@ void polygon_model_data_read(polymodel *pm, PHYSFS_File *fp)
|
||||||
#endif
|
#endif
|
||||||
if (words_bigendian)
|
if (words_bigendian)
|
||||||
swap_polygon_model_data(pm->model_data.get());
|
swap_polygon_model_data(pm->model_data.get());
|
||||||
|
#if defined(DXX_BUILD_DESCENT_I)
|
||||||
|
g3_validate_polygon_model(pm->model_data.get(), model_data_size);
|
||||||
|
#elif defined(DXX_BUILD_DESCENT_II)
|
||||||
g3_init_polygon_model(pm->model_data.get(), model_data_size);
|
g3_init_polygon_model(pm->model_data.get(), model_data_size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue