2019-12-01 15:41:14 +00:00
|
|
|
// Fixed-point format for expressing world-space coordinates, with 4 bits of
|
|
|
|
// fractional resolution.
|
2022-07-13 16:47:31 +00:00
|
|
|
// -------------------------------------------------------------------------
|
2019-12-01 15:41:14 +00:00
|
|
|
|
2021-06-30 14:30:06 +00:00
|
|
|
#define SUBPIXEL_HPP
|
|
|
|
|
2020-08-17 18:13:54 +00:00
|
|
|
#define PIXEL_NONE (-999)
|
|
|
|
|
2022-02-26 23:36:22 +00:00
|
|
|
typedef uint8_t subpixel_length_8_t;
|
2019-12-01 15:41:14 +00:00
|
|
|
typedef int subpixel_t;
|
|
|
|
|
2022-02-12 11:33:23 +00:00
|
|
|
static const subpixel_t SUBPIXEL_FACTOR = 16;
|
|
|
|
static const char SUBPIXEL_BITS = 4;
|
|
|
|
|
2020-07-02 19:19:50 +00:00
|
|
|
#define TO_SP(v) \
|
2024-01-06 22:28:55 +00:00
|
|
|
((v) << SUBPIXEL_BITS)
|
2020-07-02 19:19:50 +00:00
|
|
|
|
2021-06-19 13:15:24 +00:00
|
|
|
#define TO_PIXEL(v) \
|
2024-01-06 22:28:55 +00:00
|
|
|
((v) >> SUBPIXEL_BITS)
|
2021-06-19 13:15:24 +00:00
|
|
|
|
|
|
|
// In-place conversion to a pixel. Ugly, and should not exist.
|
|
|
|
#define TO_PIXEL_INPLACE(v) \
|
2024-01-06 22:28:55 +00:00
|
|
|
((v) >>= SUBPIXEL_BITS)
|
2021-06-19 13:15:24 +00:00
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
inline subpixel_t to_sp(float pixel_v) {
|
2022-02-12 11:33:23 +00:00
|
|
|
return static_cast<subpixel_t>(pixel_v * SUBPIXEL_FACTOR);
|
2019-12-01 15:41:14 +00:00
|
|
|
}
|
|
|
|
|
2022-02-26 23:36:22 +00:00
|
|
|
inline subpixel_length_8_t to_sp8(float pixel_v) {
|
|
|
|
return static_cast<subpixel_length_8_t>(to_sp(pixel_v));
|
2021-06-24 17:41:56 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
template <class SubpixelType, class PixelType> class SubpixelBase {
|
2019-12-01 15:41:14 +00:00
|
|
|
public:
|
2020-08-25 12:31:22 +00:00
|
|
|
typedef SubpixelBase<SubpixelType, PixelType> SelfType;
|
|
|
|
|
2019-12-01 15:41:14 +00:00
|
|
|
// Code generation will require direct access to v, if performing
|
|
|
|
// arithmetic with a local variable...
|
2020-08-25 12:31:22 +00:00
|
|
|
SubpixelType v;
|
2019-12-01 15:41:14 +00:00
|
|
|
|
2021-07-01 15:44:18 +00:00
|
|
|
SubpixelType operator +(float pixel_v) const {
|
2020-08-25 13:56:15 +00:00
|
|
|
return (this->v + static_cast<SubpixelType>(to_sp(pixel_v)));
|
|
|
|
}
|
|
|
|
|
2021-07-01 15:44:18 +00:00
|
|
|
SubpixelType operator -(const SelfType &other) const {
|
2020-07-02 19:19:50 +00:00
|
|
|
return (this->v - other.v);
|
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
void operator +=(float pixel_v) {
|
|
|
|
this->v += static_cast<SubpixelType>(to_sp(pixel_v));
|
2019-12-01 15:41:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
void operator -=(float pixel_v) {
|
|
|
|
this->v -= static_cast<SubpixelType>(to_sp(pixel_v));
|
2019-12-01 15:41:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 09:11:59 +00:00
|
|
|
// No overloads of `operator =()`, since the class needs to be trivially
|
|
|
|
// copyable.
|
2020-08-25 12:31:22 +00:00
|
|
|
void set(float pixel_v) {
|
|
|
|
v = static_cast<SubpixelType>(to_sp(pixel_v));
|
2019-12-01 15:41:14 +00:00
|
|
|
}
|
2019-12-03 21:45:08 +00:00
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
void set(const PixelType &pixel_v) {
|
|
|
|
v = static_cast<SubpixelType>(TO_SP(pixel_v));
|
2020-06-28 13:38:55 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
PixelType to_pixel() const {
|
2021-06-19 13:15:24 +00:00
|
|
|
return static_cast<PixelType>(TO_PIXEL(v));
|
2019-12-03 21:45:08 +00:00
|
|
|
}
|
2020-08-17 18:13:54 +00:00
|
|
|
|
2020-08-25 13:56:15 +00:00
|
|
|
PixelType to_pixel_slow() const { // MODDERS: Delete
|
|
|
|
return (v / 16);
|
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
operator SubpixelType() const {
|
2020-08-17 21:44:56 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2020-08-25 12:31:22 +00:00
|
|
|
static SubpixelType None() {
|
|
|
|
return static_cast<SubpixelType>(TO_SP(PIXEL_NONE));
|
2020-08-17 18:13:54 +00:00
|
|
|
}
|
2019-12-01 15:41:14 +00:00
|
|
|
};
|
|
|
|
|
2019-12-01 16:22:06 +00:00
|
|
|
template <class T> struct SPPointBase {
|
|
|
|
T x, y;
|
2019-12-01 15:41:14 +00:00
|
|
|
|
|
|
|
void set(float screen_x, float screen_y) {
|
2020-08-19 09:11:59 +00:00
|
|
|
x.set(screen_x);
|
|
|
|
y.set(screen_y);
|
2020-06-28 13:38:55 +00:00
|
|
|
}
|
2019-12-01 15:41:14 +00:00
|
|
|
};
|
2019-12-01 16:22:06 +00:00
|
|
|
|
|
|
|
// 16-bit (Q12.4)
|
2020-08-25 12:31:22 +00:00
|
|
|
typedef SubpixelBase<subpixel_t, pixel_t> Subpixel;
|
2021-06-27 13:28:58 +00:00
|
|
|
|
|
|
|
struct SPPoint : public SPPointBase<Subpixel> {
|
|
|
|
void set_long(subpixel_t subpixel_x, subpixel_t subpixel_y) {
|
|
|
|
reinterpret_cast<uint32_t &>(x) = (
|
|
|
|
subpixel_x | (static_cast<uint32_t>(subpixel_y) << 16)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-12-01 16:22:06 +00:00
|
|
|
// 8-bit (Q4.4)
|
2023-06-03 22:01:13 +00:00
|
|
|
typedef SubpixelBase<subpixel_length_8_t, pixel_length_8_t> SubpixelLength8;
|
|
|
|
typedef SubpixelBase<char, pixel_delta_8_t> Subpixel8;
|
2019-12-01 16:22:06 +00:00
|
|
|
typedef SPPointBase<Subpixel8> SPPoint8;
|
2022-07-13 16:47:31 +00:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Subpixels with one decimal digit of fractional resolution?! Sure, if you
|
|
|
|
// absolutely want those precise multiples of 0.1 in your movement code...
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
typedef int decimal_subpixel_t;
|
|
|
|
|
|
|
|
struct DecimalSubpixel {
|
|
|
|
decimal_subpixel_t v;
|
|
|
|
|
|
|
|
pixel_t to_pixel() const {
|
|
|
|
return static_cast<pixel_t>(v / 10);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline decimal_subpixel_t to_dsp(float pixel_v) {
|
|
|
|
return static_cast<decimal_subpixel_t>(pixel_v * 10);
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|