mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-23 22:11:01 +00:00
v_draw.cpp, v_draw.hpp: add srb2::Draw, 2D drawing abstraction
This commit is contained in:
parent
0e87a77e54
commit
d2ca5d6506
4 changed files with 491 additions and 0 deletions
|
|
@ -85,6 +85,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
r_portal.c
|
||||
screen.c
|
||||
taglist.c
|
||||
v_draw.cpp
|
||||
v_video.cpp
|
||||
s_sound.c
|
||||
sounds.c
|
||||
|
|
|
|||
138
src/v_draw.cpp
Normal file
138
src/v_draw.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "doomdef.h" // skincolornum_t
|
||||
#include "doomtype.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "k_hud.h"
|
||||
#include "m_fixed.h"
|
||||
#include "r_draw.h"
|
||||
#include "v_draw.hpp"
|
||||
#include "v_video.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
using srb2::Draw;
|
||||
using Chain = Draw::Chain;
|
||||
|
||||
int Draw::TextElement::width() const
|
||||
{
|
||||
return font_ ? font_width(*font_, default_font_flags(*font_) | flags_.value_or(0), string_.c_str()) / FRACUNIT : 0;
|
||||
}
|
||||
|
||||
void Chain::patch(patch_t* patch) const
|
||||
{
|
||||
const auto _ = Clipper(*this);
|
||||
|
||||
const bool stretchH = stretch_ == Stretch::kWidth || stretch_ == Stretch::kBoth;
|
||||
const bool stretchV = stretch_ == Stretch::kHeight || stretch_ == Stretch::kBoth;
|
||||
|
||||
const fixed_t h = stretchH ? FloatToFixed(width_ / patch->width) : FRACUNIT;
|
||||
const fixed_t v = stretchV ? FloatToFixed(height_ / patch->height) : FRACUNIT;
|
||||
|
||||
V_DrawStretchyFixedPatch(FloatToFixed(x_), FloatToFixed(y_), h * scale_, v * scale_, flags_, patch, colormap_);
|
||||
}
|
||||
|
||||
void Chain::patch(const char* name) const
|
||||
{
|
||||
patch(static_cast<patch_t*>(W_CachePatchName(name, PU_CACHE)));
|
||||
}
|
||||
|
||||
void Chain::thumbnail(UINT16 mapnum) const
|
||||
{
|
||||
const auto _ = Clipper(*this);
|
||||
|
||||
K_DrawMapThumbnail(FloatToFixed(x_), FloatToFixed(y_), FloatToFixed(width_), flags_, mapnum, colormap_);
|
||||
}
|
||||
|
||||
void Chain::fill(UINT8 color) const
|
||||
{
|
||||
const auto _ = Clipper(*this);
|
||||
|
||||
V_DrawFill(x_, y_, width_, height_, color);
|
||||
}
|
||||
|
||||
void Chain::string(const char* str, INT32 flags, Font font) const
|
||||
{
|
||||
const auto _ = Clipper(*this);
|
||||
|
||||
flags |= default_font_flags(font);
|
||||
|
||||
fixed_t x = FloatToFixed(x_);
|
||||
fixed_t y = FloatToFixed(y_);
|
||||
|
||||
switch (align_)
|
||||
{
|
||||
case Align::kLeft:
|
||||
break;
|
||||
|
||||
case Align::kCenter:
|
||||
x -= (font_width(font, flags, str) / 2) * scale_;
|
||||
break;
|
||||
|
||||
case Align::kRight:
|
||||
x -= font_width(font, flags, str) * scale_;
|
||||
break;
|
||||
}
|
||||
|
||||
V_DrawStringScaled(x, y, FloatToFixed(scale_), FRACUNIT, FRACUNIT, flags, colormap_, font_to_fontno(font), str);
|
||||
}
|
||||
|
||||
Chain::Clipper::Clipper(const Chain& chain)
|
||||
{
|
||||
V_SetClipRect(
|
||||
FloatToFixed(chain.clipx1_),
|
||||
FloatToFixed(chain.clipy1_),
|
||||
FloatToFixed(chain.clipx2_ - chain.clipx1_),
|
||||
FloatToFixed(chain.clipy2_ - chain.clipy1_),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
Chain::Clipper::~Clipper()
|
||||
{
|
||||
V_ClearClipRect();
|
||||
}
|
||||
|
||||
int Draw::font_to_fontno(Font font)
|
||||
{
|
||||
switch (font)
|
||||
{
|
||||
case Font::kThin:
|
||||
return TINY_FONT;
|
||||
|
||||
case Font::kGamemode:
|
||||
return GM_FONT;
|
||||
|
||||
case Font::kConsole:
|
||||
return HU_FONT;
|
||||
|
||||
case Font::kFreeplay:
|
||||
return KART_FONT;
|
||||
}
|
||||
|
||||
return TINY_FONT;
|
||||
};
|
||||
|
||||
INT32 Draw::default_font_flags(Font font)
|
||||
{
|
||||
INT32 flags = V_ALLOWLOWERCASE;
|
||||
|
||||
if (font == Font::kThin)
|
||||
{
|
||||
flags |= V_6WIDTHSPACE;
|
||||
}
|
||||
|
||||
return flags;
|
||||
};
|
||||
|
||||
fixed_t Draw::font_width(Font font, INT32 flags, const char* string)
|
||||
{
|
||||
return V_StringScaledWidth(FRACUNIT, FRACUNIT, FRACUNIT, flags, font_to_fontno(font), string);
|
||||
}
|
||||
234
src/v_draw.hpp
Normal file
234
src/v_draw.hpp
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __V_DRAW_HPP__
|
||||
#define __V_DRAW_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "doomdef.h" // skincolornum_t
|
||||
#include "doomtype.h"
|
||||
#include "screen.h" // BASEVIDWIDTH
|
||||
#include "typedef.h"
|
||||
#include "v_video.h"
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
class Draw
|
||||
{
|
||||
public:
|
||||
enum class Font
|
||||
{
|
||||
kThin,
|
||||
kGamemode,
|
||||
kConsole,
|
||||
kFreeplay,
|
||||
};
|
||||
|
||||
enum class Align
|
||||
{
|
||||
kLeft,
|
||||
kCenter,
|
||||
kRight,
|
||||
};
|
||||
|
||||
enum class Stretch
|
||||
{
|
||||
kNone,
|
||||
kWidth,
|
||||
kHeight,
|
||||
kBoth,
|
||||
};
|
||||
|
||||
class TextElement
|
||||
{
|
||||
public:
|
||||
explicit TextElement(std::string string) : string_(string) {}
|
||||
|
||||
template <class... Args>
|
||||
explicit TextElement(fmt::format_string<Args...> format, Args&&... args) :
|
||||
TextElement(fmt::format(format, args...))
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& string() const { return string_; }
|
||||
std::optional<Font> font() const { return font_; }
|
||||
std::optional<INT32> flags() const { return flags_; }
|
||||
|
||||
int width() const;
|
||||
|
||||
TextElement& string(std::string string)
|
||||
{
|
||||
string_ = string;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextElement& font(Font font)
|
||||
{
|
||||
font_ = font;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextElement& flags(INT32 flags)
|
||||
{
|
||||
flags_ = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string string_;
|
||||
std::optional<Font> font_;
|
||||
std::optional<INT32> flags_;
|
||||
};
|
||||
|
||||
class Chain
|
||||
{
|
||||
public:
|
||||
float x() const { return x_; }
|
||||
float y() const { return y_; }
|
||||
|
||||
// Methods add relative to the current state
|
||||
Chain& x(float x);
|
||||
Chain& y(float y);
|
||||
Chain& xy(float x, float y);
|
||||
Chain& flags(INT32 flags);
|
||||
|
||||
// Methods overwrite the current state
|
||||
Chain& width(float width);
|
||||
Chain& height(float height);
|
||||
Chain& size(float width, float height);
|
||||
Chain& scale(float scale);
|
||||
Chain& font(Font font);
|
||||
Chain& align(Align align);
|
||||
Chain& stretch(Stretch stretch);
|
||||
|
||||
// Absolute screen coordinates
|
||||
Chain& clipx(float left, float right); // 0 to BASEVIDWIDTH
|
||||
Chain& clipy(float top, float bottom); // 0 to BASEVIDHEIGHT
|
||||
|
||||
Chain& clipx() { return clipx(x_, x_ + width_); }
|
||||
Chain& clipy() { return clipy(y_, y_ + height_); }
|
||||
|
||||
Chain& colormap(const UINT8* colormap);
|
||||
Chain& colormap(skincolornum_t color);
|
||||
Chain& colormap(INT32 skin, skincolornum_t color);
|
||||
Chain& colorize(skincolornum_t color);
|
||||
|
||||
void text(const char* str) const { string(str, flags_, font_); }
|
||||
void text(const std::string& str) const { text(str.c_str()); }
|
||||
void text(const TextElement& elm) const
|
||||
{
|
||||
string(elm.string().c_str(), elm.flags().value_or(flags_), elm.font().value_or(font_));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void text(fmt::format_string<Args...> format, Args&&... args) const { text(fmt::format(format, args...)); }
|
||||
|
||||
void patch(patch_t* patch) const;
|
||||
void patch(const char* name) const;
|
||||
|
||||
void thumbnail(UINT16 mapnum) const;
|
||||
|
||||
void fill(UINT8 color) const;
|
||||
|
||||
private:
|
||||
constexpr Chain() {}
|
||||
explicit Chain(float x, float y) : x_(x), y_(y) {}
|
||||
Chain(const Chain&) = default;
|
||||
|
||||
struct Clipper
|
||||
{
|
||||
explicit Clipper(const Chain& chain);
|
||||
~Clipper();
|
||||
};
|
||||
|
||||
float x_ = 0.f;
|
||||
float y_ = 0.f;
|
||||
float width_ = 0.f;
|
||||
float height_ = 0.f;
|
||||
float scale_ = 1.f;
|
||||
|
||||
float clipx1_ = 0.f;
|
||||
float clipx2_ = BASEVIDWIDTH;
|
||||
float clipy1_ = 0.f;
|
||||
float clipy2_ = BASEVIDHEIGHT;
|
||||
|
||||
INT32 flags_ = 0;
|
||||
|
||||
Font font_ = Font::kThin;
|
||||
Align align_ = Align::kLeft;
|
||||
Stretch stretch_ = Stretch::kNone;
|
||||
|
||||
const UINT8* colormap_ = nullptr;
|
||||
|
||||
void string(const char* str, INT32 flags, Font font) const;
|
||||
|
||||
friend Draw;
|
||||
};
|
||||
|
||||
constexpr Draw() {}
|
||||
explicit Draw(float x, float y) : chain_(x, y) {}
|
||||
Draw(const Chain& chain) : chain_(chain) {}
|
||||
|
||||
// See class Chain for documentation
|
||||
|
||||
float x() const { return chain_.x(); }
|
||||
float y() const { return chain_.y(); }
|
||||
|
||||
#define METHOD(Name) \
|
||||
template <typename... Args>\
|
||||
Chain Name (Args&&... args) const { return Chain(chain_).Name(std::forward<Args>(args)...); }
|
||||
|
||||
METHOD(x);
|
||||
METHOD(y);
|
||||
METHOD(xy);
|
||||
METHOD(flags);
|
||||
METHOD(width);
|
||||
METHOD(height);
|
||||
METHOD(size);
|
||||
METHOD(scale);
|
||||
METHOD(font);
|
||||
METHOD(align);
|
||||
METHOD(stretch);
|
||||
METHOD(clipx);
|
||||
METHOD(clipy);
|
||||
METHOD(colormap);
|
||||
METHOD(colorize);
|
||||
|
||||
#undef METHOD
|
||||
|
||||
#define VOID_METHOD(Name) \
|
||||
template <typename... Args>\
|
||||
void Name (Args&&... args) const { return chain_.Name(std::forward<Args>(args)...); }
|
||||
|
||||
VOID_METHOD(text);
|
||||
VOID_METHOD(patch);
|
||||
VOID_METHOD(thumbnail);
|
||||
VOID_METHOD(fill);
|
||||
|
||||
#undef VOID_METHOD
|
||||
|
||||
private:
|
||||
Chain chain_;
|
||||
|
||||
static int font_to_fontno(Font font);
|
||||
static INT32 default_font_flags(Font font);
|
||||
static fixed_t font_width(Font font, INT32 flags, const char* string);
|
||||
};
|
||||
|
||||
#include "v_draw_setter.hpp"
|
||||
|
||||
}; // namespace srb2
|
||||
|
||||
#endif // __V_DRAW_HPP__
|
||||
118
src/v_draw_setter.hpp
Normal file
118
src/v_draw_setter.hpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __V_DRAW_SETTER_HPP__
|
||||
#define __V_DRAW_SETTER_HPP__
|
||||
|
||||
#include "r_draw.h" // R_GetTranslationColormap
|
||||
|
||||
inline Draw::Chain& Draw::Chain::x(float x)
|
||||
{
|
||||
x_ += x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::y(float y)
|
||||
{
|
||||
y_ += y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::xy(float x, float y)
|
||||
{
|
||||
x_ += x;
|
||||
y_ += y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::flags(INT32 flags)
|
||||
{
|
||||
flags_ |= flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::width(float width)
|
||||
{
|
||||
width_ = width;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::height(float height)
|
||||
{
|
||||
height_ = height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::size(float width, float height)
|
||||
{
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::scale(float scale)
|
||||
{
|
||||
scale_ = scale;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::font(Font font)
|
||||
{
|
||||
font_ = font;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::align(Align align)
|
||||
{
|
||||
align_ = align;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::stretch(Stretch stretch)
|
||||
{
|
||||
stretch_ = stretch;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::clipx(float left, float right)
|
||||
{
|
||||
clipx1_ = left;
|
||||
clipx2_ = right;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::clipy(float top, float bottom)
|
||||
{
|
||||
clipy1_ = top;
|
||||
clipy2_ = bottom;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::colormap(const UINT8* colormap)
|
||||
{
|
||||
colormap_ = colormap;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::colormap(skincolornum_t color)
|
||||
{
|
||||
return colormap(R_GetTranslationColormap(TC_DEFAULT, color, GTC_CACHE));
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::colormap(INT32 skin, skincolornum_t color)
|
||||
{
|
||||
return colormap(R_GetTranslationColormap(skin, color, GTC_CACHE));
|
||||
}
|
||||
|
||||
inline Draw::Chain& Draw::Chain::colorize(skincolornum_t color)
|
||||
{
|
||||
return colormap(R_GetTranslationColormap(TC_RAINBOW, color, GTC_CACHE));
|
||||
}
|
||||
|
||||
#endif // __V_DRAW_SETTER_HPP__
|
||||
Loading…
Add table
Reference in a new issue