lots of small rendering & batcher cleanup

This commit is contained in:
Noel Berry 2020-12-24 00:19:58 -08:00
parent 46c900756e
commit 8c0ef3e769
11 changed files with 395 additions and 88 deletions

View File

@ -151,16 +151,28 @@ Mat3x2 Batch::pop_matrix()
return was; return was;
} }
Mat3x2 Batch::peek_matrix() const
{
return m_matrix;
}
void Batch::push_scissor(const Rect& scissor) void Batch::push_scissor(const Rect& scissor)
{ {
m_scissor_stack.push_back(m_batch.scissor); m_scissor_stack.push_back(m_batch.scissor);
SET_BATCH_VAR(scissor); SET_BATCH_VAR(scissor);
} }
void Batch::pop_scissor() Rect Batch::pop_scissor()
{ {
Rect was = m_batch.scissor;
Rect scissor = m_scissor_stack.pop(); Rect scissor = m_scissor_stack.pop();
SET_BATCH_VAR(scissor); SET_BATCH_VAR(scissor);
return was;
}
Rect Batch::peek_scissor() const
{
return m_batch.scissor;
} }
void Batch::push_blend(const BlendMode& blend) void Batch::push_blend(const BlendMode& blend)
@ -169,10 +181,17 @@ void Batch::push_blend(const BlendMode& blend)
SET_BATCH_VAR(blend); SET_BATCH_VAR(blend);
} }
void Batch::pop_blend() BlendMode Batch::pop_blend()
{ {
BlendMode was = m_batch.blend;
BlendMode blend = m_blend_stack.pop(); BlendMode blend = m_blend_stack.pop();
SET_BATCH_VAR(blend); SET_BATCH_VAR(blend);
return was;
}
BlendMode Batch::peek_blend() const
{
return m_batch.blend;
} }
void Batch::push_material(const MaterialRef& material) void Batch::push_material(const MaterialRef& material)
@ -181,10 +200,17 @@ void Batch::push_material(const MaterialRef& material)
SET_BATCH_VAR(material); SET_BATCH_VAR(material);
} }
void Batch::pop_material() MaterialRef Batch::pop_material()
{ {
MaterialRef was = m_batch.material;
MaterialRef material = m_material_stack.pop(); MaterialRef material = m_material_stack.pop();
SET_BATCH_VAR(material); SET_BATCH_VAR(material);
return was;
}
MaterialRef Batch::peek_material() const
{
return m_batch.material;
} }
void Batch::push_layer(int layer) void Batch::push_layer(int layer)
@ -193,10 +219,17 @@ void Batch::push_layer(int layer)
SET_BATCH_VAR(layer); SET_BATCH_VAR(layer);
} }
void Batch::pop_layer() int Batch::pop_layer()
{ {
int was = m_batch.layer;
int layer = m_layer_stack.pop(); int layer = m_layer_stack.pop();
SET_BATCH_VAR(layer); SET_BATCH_VAR(layer);
return was;
}
int Batch::peek_layer() const
{
return m_batch.layer;
} }
void Batch::push_color_mode(ColorMode mode) void Batch::push_color_mode(ColorMode mode)
@ -208,11 +241,18 @@ void Batch::push_color_mode(ColorMode mode)
m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0); m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0);
} }
void Batch::pop_color_mode() ColorMode Batch::pop_color_mode()
{ {
ColorMode was = m_color_mode;
m_color_mode = m_color_mode_stack.pop(); m_color_mode = m_color_mode_stack.pop();
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0); m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0); m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0);
return was;
}
ColorMode Batch::peek_color_mode() const
{
return m_color_mode;
} }
void Batch::set_texture(const TextureRef& texture) void Batch::set_texture(const TextureRef& texture)
@ -764,9 +804,58 @@ void Batch::arrow_head(const Vec2& point_pos, const Vec2& from_pos, float side_l
tri(point_pos, base + perp * side_len / 2, base - perp * side_len / 2, color); tri(point_pos, base + perp * side_len / 2, base - perp * side_len / 2, color);
} }
void Batch::tex() void Batch::tex(const TextureRef& texture, const Vec2& pos, Color color)
{ {
set_texture(texture);
const auto w = texture->width();
const auto h = texture->height();
PUSH_QUAD(
pos.x, pos.y, pos.x + w, pos.y, pos.x + w, pos.y + h, pos.x, pos.y + h,
0, 0, 1, 0, 1, 1, 0, 1,
color, color, color, color,
m_tex_mult, m_tex_wash, 0);
}
void Batch::tex(const TextureRef& texture, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color)
{
push_matrix(Mat3x2::create_transform(pos, origin, scale, rotation));
set_texture(texture);
const auto w = texture->width();
const auto h = texture->height();
PUSH_QUAD(
0, 0, w, 0, w, h, 0, h,
0, 0, 1, 0, 1, 1, 0, 1,
color, color, color, color,
m_tex_mult, m_tex_wash, 0);
pop_matrix();
}
void Batch::tex(const TextureRef& texture, const Rect& clip, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color)
{
push_matrix(Mat3x2::create_transform(pos, origin, scale, rotation));
set_texture(texture);
const auto tw = texture->width();
const auto th = texture->height();
const auto tx0 = clip.x / tw;
const auto tx1 = (clip.x + clip.w) / tw;
const auto ty0 = clip.y / th;
const auto ty1 = (clip.y + clip.h) / th;
PUSH_QUAD(
0, 0, clip.w, 0, clip.w, clip.h, 0, clip.h,
tx0, ty0, tx1, ty0, tx1, ty1, tx0, ty1,
color, color, color, color,
m_tex_mult, m_tex_wash, 0);
pop_matrix();
} }
void Batch::tex(const Subtexture& sub, const Vec2& pos, Color color) void Batch::tex(const Subtexture& sub, const Vec2& pos, Color color)
@ -835,6 +924,11 @@ void Batch::tex(const Subtexture& sub, const Vec2& pos, const Vec2& origin, cons
pop_matrix(); pop_matrix();
} }
void Batch::tex(const Subtexture& sub, const Rect& clip, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color)
{
tex(sub.crop(clip), pos, origin, scale, rotation, color);
}
void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Color color) void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Color color)
{ {
str(font, text, pos, TextAlign::TopLeft, font.size, color); str(font, text, pos, TextAlign::TopLeft, font.size, color);

View File

@ -35,6 +35,7 @@ namespace Blah
inline TextAlign operator|(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) | static_cast<char>(rhs)); } inline TextAlign operator|(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) | static_cast<char>(rhs)); }
inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) & static_cast<char>(rhs)); } inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) & static_cast<char>(rhs)); }
// A simple 2D sprite batcher, used for drawing shapes and textures
class Batch class Batch
{ {
public: public:
@ -57,38 +58,56 @@ namespace Blah
// Pops the matrix from the stack // Pops the matrix from the stack
Mat3x2 pop_matrix(); Mat3x2 pop_matrix();
// Gets the current matrix from the top of the stackKO
Mat3x2 peek_matrix() const;
// Pushes a Scissor rectangle. Note this is not transformed by the matrix stack // Pushes a Scissor rectangle. Note this is not transformed by the matrix stack
// or other scissors. Each push is screen-space. // or other scissors. Each push is screen-space.
void push_scissor(const Rect& scissor); void push_scissor(const Rect& scissor);
// Pops a Scissor rectangle from the stack // Pops a Scissor rectangle from the stack
void pop_scissor(); Rect pop_scissor();
// Gets the current Scissor rectangle from the top of the stack
Rect peek_scissor() const;
// Pushes a blend mode // Pushes a blend mode
void push_blend(const BlendMode& blend); void push_blend(const BlendMode& blend);
// Pops a blend mode // Pops a blend mode
void pop_blend(); BlendMode pop_blend();
// Gets the current BlendMode from the top of the stack
BlendMode peek_blend() const;
// Pushes a Material to use for all drawing. Note that the state of the Material // Pushes a Material to use for all drawing. Note that the state of the Material
// is not copied - it will be drawn with the values of the Material at render. // is not copied - it will be drawn with the values of the Material at render.
void push_material(const MaterialRef& material); void push_material(const MaterialRef& material);
// Pops a Material // Pops a Material
void pop_material(); MaterialRef pop_material();
// Gets the current Material from the top of the stack
MaterialRef peek_material() const;
// Pushes a render layer. Lower values are rendered first. This is not super optimized // Pushes a render layer. Lower values are rendered first. This is not super optimized
// and should generally be avoided. // and should generally be avoided.
void push_layer(int layer); void push_layer(int layer);
// Pops a Layer // Pops a Layer
void pop_layer(); int pop_layer();
// Gets the current Layer from the top of the stack
int peek_layer() const;
// Pushes a Color Mode for drawing Textures // Pushes a Color Mode for drawing Textures
void push_color_mode(ColorMode mode); void push_color_mode(ColorMode mode);
// Pops a Color MOde // Pops a Color MOde
void pop_color_mode(); ColorMode pop_color_mode();
// Gets the current ColorMode from the top of the stack
ColorMode peek_color_mode() const;
// Sets the current texture used for drawing. Note that certain functions will override // Sets the current texture used for drawing. Note that certain functions will override
// this (ex the `str` and `tex` methods) // this (ex the `str` and `tex` methods)
@ -143,9 +162,13 @@ namespace Blah
void arrow_head(const Vec2& point_pos, float radians, float side_len, Color color); void arrow_head(const Vec2& point_pos, float radians, float side_len, Color color);
void arrow_head(const Vec2& point_pos, const Vec2& from_pos, float side_len, Color color); void arrow_head(const Vec2& point_pos, const Vec2& from_pos, float side_len, Color color);
void tex(); void tex(const TextureRef& texture, const Vec2& position = Vec2::zero, Color color = Color::white);
void tex(const Subtexture& subtexture, const Vec2& pos, Color color); void tex(const TextureRef& texture, const Vec2& position, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const TextureRef& texture, const Rect& clip, const Vec2& position, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const Subtexture& subtexture, const Vec2& position = Vec2::zero, Color color = Color::white);
void tex(const Subtexture& subtexture, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color); void tex(const Subtexture& subtexture, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const Subtexture& subtexture, const Rect& clip, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void str(const SpriteFont& font, const String& text, const Vec2& pos, Color color); void str(const SpriteFont& font, const String& text, const Vec2& pos, Color color);
void str(const SpriteFont& font, const String& text, const Vec2& pos, TextAlign align, float size, Color color); void str(const SpriteFont& font, const String& text, const Vec2& pos, TextAlign align, float size, Color color);
@ -161,8 +184,6 @@ namespace Blah
uint8_t mult; uint8_t mult;
uint8_t wash; uint8_t wash;
uint8_t fill; uint8_t fill;
static VertexAttribute attributes[6];
}; };
struct DrawBatch struct DrawBatch

View File

@ -1,4 +1,5 @@
#include <blah/drawing/subtexture.h> #include <blah/drawing/subtexture.h>
#include <blah/math/calc.h>
using namespace Blah; using namespace Blah;
@ -42,3 +43,22 @@ void Subtexture::update()
tex_coords[3].y = (source.y + source.h) * uvy; tex_coords[3].y = (source.y + source.h) * uvy;
} }
} }
void Subtexture::crop_info(const Rect& clip, Rect* dest_source, Rect* dest_frame) const
{
*dest_source = (clip + source.top_left() + frame.top_left()).overlap_rect(source);
dest_frame->x = Calc::min(0, frame.x + clip.x);
dest_frame->y = Calc::min(0, frame.y + clip.y);
dest_frame->w = clip.w;
dest_frame->h = clip.h;
}
Subtexture Subtexture::crop(const Rect& clip) const
{
Subtexture dst;
dst.texture = texture;
crop_info(clip, &dst.source, &dst.frame);
dst.update();
return dst;
}

View File

@ -36,5 +36,11 @@ namespace Blah
// updates the `draw_coords` and `tex_coords` // updates the `draw_coords` and `tex_coords`
void update(); void update();
// returns resulting source and frame rectangles based on the provided clip rectangle
void crop_info(const Rect& clip, Rect* dest_source, Rect* dest_frame) const;
// returns a subtexture cropped to the provided rectangle
Subtexture crop(const Rect& clip) const;
}; };
} }

View File

@ -62,7 +62,10 @@ TextureRef Graphics::create_texture(int width, int height, TextureFormat format)
BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0"); BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0");
BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format"); BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format");
return GraphicsBackend::create_texture(width, height, TextureFilter::Linear, TextureWrap::Repeat, TextureWrap::Repeat, format); if (width > 0 && height > 0)
return GraphicsBackend::create_texture(width, height, TextureFilter::Linear, TextureWrap::Repeat, TextureWrap::Repeat, format);
return TextureRef();
} }
TextureRef Graphics::create_texture(Stream& stream) TextureRef Graphics::create_texture(Stream& stream)
@ -104,10 +107,27 @@ FrameBufferRef Graphics::create_framebuffer(int width, int height, const Texture
BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0"); BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0");
BLAH_ASSERT(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count"); BLAH_ASSERT(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count");
BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided"); BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided");
int color_count = 0;
int depth_count = 0;
for (int i = 0; i < attachment_count; i++) for (int i = 0; i < attachment_count; i++)
{
BLAH_ASSERT((int)attachments[i] > (int)TextureFormat::None && (int)attachments[i] < (int)TextureFormat::Count, "Invalid texture format"); BLAH_ASSERT((int)attachments[i] > (int)TextureFormat::None && (int)attachments[i] < (int)TextureFormat::Count, "Invalid texture format");
return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count); if (attachments[i] == TextureFormat::DepthStencil)
depth_count++;
else
color_count++;
}
BLAH_ASSERT(depth_count <= 1, "FrameBuffer can only have 1 Depth/Stencil Texture");
BLAH_ASSERT(color_count <= BLAH_ATTACHMENTS - 1, "Exceeded maximum Color attachment count");
if (color_count <= BLAH_ATTACHMENTS - 1 && depth_count <= 1 && width > 0 && height > 0)
return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count);
return FrameBufferRef();
} }
ShaderRef Graphics::create_shader(const ShaderData* data) ShaderRef Graphics::create_shader(const ShaderData* data)
@ -119,9 +139,10 @@ MaterialRef Graphics::create_material(const ShaderRef& shader)
{ {
BLAH_ASSERT(shader, "The provided shader is invalid"); BLAH_ASSERT(shader, "The provided shader is invalid");
// TODO: if (shader)
// use a pool for Materials? return MaterialRef(new Material(shader));
return MaterialRef(new Material(shader));
return MaterialRef();
} }
MeshRef Graphics::create_mesh() MeshRef Graphics::create_mesh()

View File

@ -6,11 +6,11 @@
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <memory> #include <memory>
#define BLAH_ATTACHMENTS 16 #define BLAH_ATTACHMENTS 5 // 4 color attachments + 1 depth/stencil
#define BLAH_UNIFORMS 16 #define BLAH_UNIFORMS 16 // 16 shader uniforms
#define BLAH_ATTRIBUTES 16 #define BLAH_ATTRIBUTES 16 // 16 shader attributes
#define BLAH_ATTRIBUTE_NAME 32 #define BLAH_ATTRIBUTE_NAME 32 // max shader attribute name length
#define BLAH_UNIFORM_NAME 32 #define BLAH_UNIFORM_NAME 32 // max shader uniform name length
namespace Blah namespace Blah
{ {

View File

@ -6,10 +6,10 @@
using namespace Blah; using namespace Blah;
Packer::Packer() Packer::Packer()
: max_size(8192), power_of_two(true), spacing(1), padding(1), dirty(false) { } : max_size(8192), power_of_two(true), spacing(1), padding(1), m_dirty(false) { }
Packer::Packer(int max_size, int spacing, bool power_of_two) Packer::Packer(int max_size, int spacing, bool power_of_two)
: max_size(max_size), power_of_two(power_of_two), spacing(spacing), padding(1), dirty(false) { } : max_size(max_size), power_of_two(power_of_two), spacing(spacing), padding(1), m_dirty(false) { }
Packer::Packer(Packer&& src) noexcept Packer::Packer(Packer&& src) noexcept
{ {
@ -17,10 +17,10 @@ Packer::Packer(Packer&& src) noexcept
power_of_two = src.power_of_two; power_of_two = src.power_of_two;
spacing = src.spacing; spacing = src.spacing;
padding = src.padding; padding = src.padding;
dirty = src.dirty; m_dirty = src.m_dirty;
pages = std::move(src.pages); pages = std::move(src.pages);
entries = std::move(src.entries); entries = std::move(src.entries);
buffer = std::move(src.buffer); m_buffer = std::move(src.m_buffer);
} }
Packer& Packer::operator=(Packer&& src) noexcept Packer& Packer::operator=(Packer&& src) noexcept
@ -29,10 +29,10 @@ Packer& Packer::operator=(Packer&& src) noexcept
power_of_two = src.power_of_two; power_of_two = src.power_of_two;
spacing = src.spacing; spacing = src.spacing;
padding = src.padding; padding = src.padding;
dirty = src.dirty; m_dirty = src.m_dirty;
pages = std::move(src.pages); pages = std::move(src.pages);
entries = std::move(src.entries); entries = std::move(src.entries);
buffer = std::move(src.buffer); m_buffer = std::move(src.m_buffer);
return *this; return *this;
} }
@ -58,7 +58,7 @@ void Packer::add(uint64_t id, const String& path)
void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels) void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
{ {
dirty = true; m_dirty = true;
Entry entry(id, RectI(0, 0, w, h)); Entry entry(id, RectI(0, 0, w, h));
@ -111,17 +111,17 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
entry.packed.h = (bottom - top); entry.packed.h = (bottom - top);
// create pixel data // create pixel data
entry.memory_index = buffer.position(); entry.memory_index = m_buffer.position();
// copy pixels over // copy pixels over
if (entry.packed.w == w && entry.packed.h == h) if (entry.packed.w == w && entry.packed.h == h)
{ {
buffer.write((char*)pixels, sizeof(Color) * w * h); m_buffer.write((char*)pixels, sizeof(Color) * w * h);
} }
else else
{ {
for (int i = 0; i < entry.packed.h; i++) for (int i = 0; i < entry.packed.h; i++)
buffer.write((char*)(pixels + left + (top + i) * entry.frame.w), sizeof(Color) * entry.packed.w); m_buffer.write((char*)(pixels + left + (top + i) * entry.frame.w), sizeof(Color) * entry.packed.w);
} }
} }
@ -130,10 +130,10 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
void Packer::pack() void Packer::pack()
{ {
if (!dirty) if (!m_dirty)
return; return;
dirty = false; m_dirty = false;
pages.clear(); pages.clear();
// only if we have stuff to pack // only if we have stuff to pack
@ -266,7 +266,7 @@ void Packer::pack()
if (!sources[i]->empty) if (!sources[i]->empty)
{ {
RectI dst = sources[i]->packed; RectI dst = sources[i]->packed;
Color* src = (Color*)(buffer.data() + sources[i]->memory_index); Color* src = (Color*)(m_buffer.data() + sources[i]->memory_index);
// TODO: // TODO:
// Optimize this? // Optimize this?
@ -293,18 +293,18 @@ void Packer::clear()
{ {
pages.clear(); pages.clear();
entries.clear(); entries.clear();
dirty = false; m_dirty = false;
} }
void Packer::dispose() void Packer::dispose()
{ {
pages.clear(); pages.clear();
entries.clear(); entries.clear();
buffer.close(); m_buffer.close();
max_size = 0; max_size = 0;
power_of_two = 0; power_of_two = 0;
spacing = 0; spacing = 0;
dirty = false; m_dirty = false;
} }
Packer::Node::Node() Packer::Node::Node()

View File

@ -66,8 +66,8 @@ namespace Blah
Node* Reset(const RectI& rect); Node* Reset(const RectI& rect);
}; };
bool dirty; bool m_dirty;
BufferStream buffer; BufferStream m_buffer;
void add_entry(uint64_t id, int w, int h, const Color* pixels); void add_entry(uint64_t id, int w, int h, const Color* pixels);
}; };

View File

@ -162,7 +162,7 @@ Mat3x2 Mat3x2::add(const Mat3x2& a, const Mat3x2& b)
a.m21 + b.m21, a.m21 + b.m21,
a.m22 + b.m22, a.m22 + b.m22,
a.m31 + b.m31, a.m31 + b.m31,
a.m21 + b.m32); a.m32 + b.m32);
} }
Mat3x2 Mat3x2::subtract(const Mat3x2& a, const Mat3x2& b) Mat3x2 Mat3x2::subtract(const Mat3x2& a, const Mat3x2& b)
@ -173,7 +173,7 @@ Mat3x2 Mat3x2::subtract(const Mat3x2& a, const Mat3x2& b)
a.m21 - b.m21, a.m21 - b.m21,
a.m22 - b.m22, a.m22 - b.m22,
a.m31 - b.m31, a.m31 - b.m31,
a.m21 - b.m32); a.m32 - b.m32);
} }
Mat3x2 Mat3x2::multiply(const Mat3x2& a, const Mat3x2& b) Mat3x2 Mat3x2::multiply(const Mat3x2& a, const Mat3x2& b)

View File

@ -54,10 +54,169 @@ Rect Rect::scale(float sx, float sy)
return *this; return *this;
} }
Line Rect::left_line() const { return Line(left(), top(), left(), bottom()); } float Rect::left() const
Line Rect::right_line() const { return Line(right(), top(), right(), bottom()); } {
Line Rect::top_line() const { return Line(left(), top(), right(), top()); } return x;
Line Rect::bottom_line() const { return Line(left(), bottom(), right(), bottom()); } }
float Rect::right() const
{
return x + w;
}
float Rect::top() const
{
return y;
}
float Rect::bottom() const
{
return y + h;
}
Vec2 Rect::center() const
{
return Vec2(x + w / 2, y + h / 2);
}
float Rect::center_x() const
{
return x + w / 2;
}
float Rect::center_y() const
{
return y + h / 2;
}
Vec2 Rect::top_left() const
{
return Vec2(x, y);
}
Vec2 Rect::top_right() const
{
return Vec2(x + w, y);
}
Vec2 Rect::bottom_right() const
{
return Vec2(x + w, y + h);
}
Vec2 Rect::bottom_left() const
{
return Vec2(x, y + h);
}
Vec2 Rect::center_left() const
{
return Vec2(x, y + h / 2);
}
Vec2 Rect::center_right() const
{
return Vec2(x + w, y + h / 2);
}
Vec2 Rect::middle_top() const
{
return Vec2(x + w / 2, y);
}
Vec2 Rect::middle_bottom() const
{
return Vec2(x + w / 2, y + h);
}
Line Rect::left_line() const
{
return Line(left(), top(), left(), bottom());
}
Line Rect::right_line() const
{
return Line(right(), top(), right(), bottom());
}
Line Rect::top_line() const
{
return Line(left(), top(), right(), top());
}
Line Rect::bottom_line() const
{
return Line(left(), bottom(), right(), bottom());
}
bool Rect::contains(const Point& pt) const
{
return pt.x >= x && pt.x < x + w && pt.y >= y && pt.y < y + h;
}
bool Rect::contains(const Vec2& pt) const
{
return pt.x >= x && pt.x < x + w && pt.y >= y && pt.y < y + h;
}
Rect Rect::overlap_rect(const Rect& against) const
{
Rect result(0, 0, 0, 0);
if (x + w >= against.x && x < against.x + against.w)
{
result.x = Calc::max(x, against.x);
result.w = Calc::min(x + w, against.x + against.w) - result.x;
}
if (y + h >= against.y && y < against.y + against.h)
{
result.y = Calc::max(y, against.y);
result.h = Calc::min(y + h, against.y + against.h) - result.y;
}
return result;
}
bool Rect::intersects(const Line& line) const
{
return line.intersects(*this);
}
bool Rect::intersects(const Line& line, Vec2* out_intersection_point) const
{
return line.intersects(*this, out_intersection_point);
}
bool Rect::intersects(const Vec2& line_from, const Vec2& line_to) const
{
return intersects(Line(line_from, line_to));
}
bool Rect::intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const
{
return intersects(Line(line_from, line_to), out_intersection_point);
}
Vec2 Rect::intersection_point(const Line& line) const
{
Vec2 ret;
if (line.intersects(*this, &ret))
return ret;
else
return Vec2::zero;
}
Vec2 Rect::intersection_point(const Vec2& line_from, const Vec2& line_to) const
{
Vec2 ret;
if (Line(line_from, line_to).intersects(*this, &ret))
return ret;
else
return Vec2::zero;
}
Rect Rect::inflate(float amount) const
{
return Rect(x - amount, y - amount, w + amount * 2, h + amount * 2);
}
Rect Rect::operator+(const Vec2& rhs) const { return Rect(x + rhs.x, y + rhs.y, w, h); } Rect Rect::operator+(const Vec2& rhs) const { return Rect(x + rhs.x, y + rhs.y, w, h); }
Rect Rect::operator-(const Vec2& rhs) const { return Rect(x - rhs.x, y - rhs.y, w, h); } Rect Rect::operator-(const Vec2& rhs) const { return Rect(x - rhs.x, y - rhs.y, w, h); }

View File

@ -23,59 +23,45 @@ namespace Blah
Rect scale(float s); Rect scale(float s);
Rect scale(float sx, float sy); Rect scale(float sx, float sy);
float left() const { return x; } float left() const;
float right() const { return x + w; } float right() const;
float top() const { return y; } float top() const;
float bottom() const { return y + h; } float bottom() const;
Vec2 center() const { return Vec2(x + w / 2, y + h / 2); } Vec2 center() const;
float center_x() const { return x + w / 2; } float center_x() const;
float center_y() const { return y + h / 2; } float center_y() const;
Vec2 top_left() const { return Vec2(x, y); } Vec2 top_left() const;
Vec2 top_right() const { return Vec2(x + w, y); } Vec2 top_right() const;
Vec2 bottom_right() const { return Vec2(x + w, y + h); } Vec2 bottom_right() const;
Vec2 bottom_left() const { return Vec2(x, y + h); } Vec2 bottom_left() const;
Vec2 center_left() const { return Vec2(x, y + h / 2); } Vec2 center_left() const;
Vec2 center_right() const { return Vec2(x + w, y + h / 2); } Vec2 center_right() const;
Vec2 middle_top() const { return Vec2(x + w / 2, y); } Vec2 middle_top() const;
Vec2 middle_bottom() const { return Vec2(x + w / 2, y + h); } Vec2 middle_bottom() const;
Line left_line() const; Line left_line() const;
Line right_line() const; Line right_line() const;
Line top_line() const; Line top_line() const;
Line bottom_line() const; Line bottom_line() const;
bool contains(const Point& pt) const { return pt.x >= x && pt.x < x + w && pt.y >= y && pt.y < y + h; } bool contains(const Point& pt) const;
bool contains(const Vec2& pt) const { return pt.x >= x && pt.x < x + w && pt.y >= y && pt.y < y + h; } bool contains(const Vec2& pt) const;
bool overlaps(const Rect& rect) const { return x + w >= rect.x && y + h >= rect.y && x < rect.x + rect.w && y < rect.y + rect.h; } bool overlaps(const Rect& rect) const { return x + w >= rect.x && y + h >= rect.y && x < rect.x + rect.w && y < rect.y + rect.h; }
Rect overlap_rect(const Rect& other) const;
bool intersects(const Line& line) const { return line.intersects(*this); } bool intersects(const Line& line) const;
bool intersects(const Line& line, Vec2* out_intersection_point) const { return line.intersects(*this, out_intersection_point); } bool intersects(const Line& line, Vec2* out_intersection_point) const;
bool intersects(const Vec2& line_from, const Vec2& line_to) const { return intersects(Line(line_from, line_to)); } bool intersects(const Vec2& line_from, const Vec2& line_to) const;
bool intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const { return intersects(Line(line_from, line_to), out_intersection_point); } bool intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const;
Vec2 intersection_point(const Line& line) const Vec2 intersection_point(const Line& line) const;
{ Vec2 intersection_point(const Vec2& line_from, const Vec2& line_to) const;
Vec2 ret;
if (line.intersects(*this, &ret))
return ret;
else
return Vec2::zero;
}
Vec2 intersection_point(const Vec2& line_from, const Vec2& line_to) const Rect inflate(float amount) const;
{
Vec2 ret;
if (Line(line_from, line_to).intersects(*this, &ret))
return ret;
else
return Vec2::zero;
}
Rect inflate(float amount) const { return Rect(x - amount, y - amount, w + amount * 2, h + amount * 2); }
/* /*
Rect Sectors: Rect Sectors: