From 8c0ef3e7698f98a5c9d97aaef5c013b7f3ed761d Mon Sep 17 00:00:00 2001 From: Noel Berry Date: Thu, 24 Dec 2020 00:19:58 -0800 Subject: [PATCH] lots of small rendering & batcher cleanup --- public/blah/drawing/batch.cpp | 106 ++++++++++++++++-- public/blah/drawing/batch.h | 39 +++++-- public/blah/drawing/subtexture.cpp | 20 ++++ public/blah/drawing/subtexture.h | 6 ++ public/blah/graphics/graphics.cpp | 31 +++++- public/blah/graphics/graphics.h | 10 +- public/blah/images/packer.cpp | 32 +++--- public/blah/images/packer.h | 4 +- public/blah/math/mat3x2.cpp | 4 +- public/blah/math/rect.cpp | 167 ++++++++++++++++++++++++++++- public/blah/math/rect.h | 64 +++++------ 11 files changed, 395 insertions(+), 88 deletions(-) diff --git a/public/blah/drawing/batch.cpp b/public/blah/drawing/batch.cpp index 8932f3b..0dce22e 100644 --- a/public/blah/drawing/batch.cpp +++ b/public/blah/drawing/batch.cpp @@ -151,16 +151,28 @@ Mat3x2 Batch::pop_matrix() return was; } +Mat3x2 Batch::peek_matrix() const +{ + return m_matrix; +} + void Batch::push_scissor(const Rect& scissor) { m_scissor_stack.push_back(m_batch.scissor); SET_BATCH_VAR(scissor); } -void Batch::pop_scissor() +Rect Batch::pop_scissor() { + Rect was = m_batch.scissor; Rect scissor = m_scissor_stack.pop(); SET_BATCH_VAR(scissor); + return was; +} + +Rect Batch::peek_scissor() const +{ + return m_batch.scissor; } void Batch::push_blend(const BlendMode& blend) @@ -169,10 +181,17 @@ void Batch::push_blend(const BlendMode& blend) SET_BATCH_VAR(blend); } -void Batch::pop_blend() +BlendMode Batch::pop_blend() { + BlendMode was = m_batch.blend; BlendMode blend = m_blend_stack.pop(); SET_BATCH_VAR(blend); + return was; +} + +BlendMode Batch::peek_blend() const +{ + return m_batch.blend; } void Batch::push_material(const MaterialRef& material) @@ -181,10 +200,17 @@ void Batch::push_material(const MaterialRef& material) SET_BATCH_VAR(material); } -void Batch::pop_material() +MaterialRef Batch::pop_material() { + MaterialRef was = m_batch.material; MaterialRef material = m_material_stack.pop(); SET_BATCH_VAR(material); + return was; +} + +MaterialRef Batch::peek_material() const +{ + return m_batch.material; } void Batch::push_layer(int layer) @@ -193,10 +219,17 @@ void Batch::push_layer(int layer) SET_BATCH_VAR(layer); } -void Batch::pop_layer() +int Batch::pop_layer() { + int was = m_batch.layer; int layer = m_layer_stack.pop(); SET_BATCH_VAR(layer); + return was; +} + +int Batch::peek_layer() const +{ + return m_batch.layer; } 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); } -void Batch::pop_color_mode() +ColorMode Batch::pop_color_mode() { + ColorMode was = m_color_mode; m_color_mode = m_color_mode_stack.pop(); m_tex_mult = (m_color_mode == ColorMode::Normal ? 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) @@ -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); } -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) @@ -835,6 +924,11 @@ void Batch::tex(const Subtexture& sub, const Vec2& pos, const Vec2& origin, cons 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) { str(font, text, pos, TextAlign::TopLeft, font.size, color); diff --git a/public/blah/drawing/batch.h b/public/blah/drawing/batch.h index efd14ad..c168661 100644 --- a/public/blah/drawing/batch.h +++ b/public/blah/drawing/batch.h @@ -35,6 +35,7 @@ namespace Blah inline TextAlign operator|(TextAlign lhs, TextAlign rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } + // A simple 2D sprite batcher, used for drawing shapes and textures class Batch { public: @@ -57,38 +58,56 @@ namespace Blah // Pops the matrix from the stack 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 // or other scissors. Each push is screen-space. void push_scissor(const Rect& scissor); // 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 void push_blend(const BlendMode& blend); // 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 // is not copied - it will be drawn with the values of the Material at render. void push_material(const MaterialRef& 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 // and should generally be avoided. void push_layer(int 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 void push_color_mode(ColorMode 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 // 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, const Vec2& from_pos, float side_len, Color color); - void tex(); - void tex(const Subtexture& subtexture, const Vec2& pos, Color color); + void tex(const TextureRef& texture, const Vec2& position = Vec2::zero, Color color = Color::white); + 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 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, TextAlign align, float size, Color color); @@ -161,8 +184,6 @@ namespace Blah uint8_t mult; uint8_t wash; uint8_t fill; - - static VertexAttribute attributes[6]; }; struct DrawBatch diff --git a/public/blah/drawing/subtexture.cpp b/public/blah/drawing/subtexture.cpp index ab5ba81..74bc999 100644 --- a/public/blah/drawing/subtexture.cpp +++ b/public/blah/drawing/subtexture.cpp @@ -1,4 +1,5 @@ #include +#include using namespace Blah; @@ -42,3 +43,22 @@ void Subtexture::update() 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; +} \ No newline at end of file diff --git a/public/blah/drawing/subtexture.h b/public/blah/drawing/subtexture.h index d4d29cf..c88b88a 100644 --- a/public/blah/drawing/subtexture.h +++ b/public/blah/drawing/subtexture.h @@ -36,5 +36,11 @@ namespace Blah // updates the `draw_coords` and `tex_coords` 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; }; } \ No newline at end of file diff --git a/public/blah/graphics/graphics.cpp b/public/blah/graphics/graphics.cpp index e2c862a..909b8e1 100644 --- a/public/blah/graphics/graphics.cpp +++ b/public/blah/graphics/graphics.cpp @@ -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((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) @@ -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(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count"); 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++) + { 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) @@ -119,9 +139,10 @@ MaterialRef Graphics::create_material(const ShaderRef& shader) { BLAH_ASSERT(shader, "The provided shader is invalid"); - // TODO: - // use a pool for Materials? - return MaterialRef(new Material(shader)); + if (shader) + return MaterialRef(new Material(shader)); + + return MaterialRef(); } MeshRef Graphics::create_mesh() diff --git a/public/blah/graphics/graphics.h b/public/blah/graphics/graphics.h index c4a39e3..135c0b2 100644 --- a/public/blah/graphics/graphics.h +++ b/public/blah/graphics/graphics.h @@ -6,11 +6,11 @@ #include #include -#define BLAH_ATTACHMENTS 16 -#define BLAH_UNIFORMS 16 -#define BLAH_ATTRIBUTES 16 -#define BLAH_ATTRIBUTE_NAME 32 -#define BLAH_UNIFORM_NAME 32 +#define BLAH_ATTACHMENTS 5 // 4 color attachments + 1 depth/stencil +#define BLAH_UNIFORMS 16 // 16 shader uniforms +#define BLAH_ATTRIBUTES 16 // 16 shader attributes +#define BLAH_ATTRIBUTE_NAME 32 // max shader attribute name length +#define BLAH_UNIFORM_NAME 32 // max shader uniform name length namespace Blah { diff --git a/public/blah/images/packer.cpp b/public/blah/images/packer.cpp index 82489cb..6ed1adf 100644 --- a/public/blah/images/packer.cpp +++ b/public/blah/images/packer.cpp @@ -6,10 +6,10 @@ using namespace Blah; 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) - : 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 { @@ -17,10 +17,10 @@ Packer::Packer(Packer&& src) noexcept power_of_two = src.power_of_two; spacing = src.spacing; padding = src.padding; - dirty = src.dirty; + m_dirty = src.m_dirty; pages = std::move(src.pages); entries = std::move(src.entries); - buffer = std::move(src.buffer); + m_buffer = std::move(src.m_buffer); } Packer& Packer::operator=(Packer&& src) noexcept @@ -29,10 +29,10 @@ Packer& Packer::operator=(Packer&& src) noexcept power_of_two = src.power_of_two; spacing = src.spacing; padding = src.padding; - dirty = src.dirty; + m_dirty = src.m_dirty; pages = std::move(src.pages); entries = std::move(src.entries); - buffer = std::move(src.buffer); + m_buffer = std::move(src.m_buffer); 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) { - dirty = true; + m_dirty = true; 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); // create pixel data - entry.memory_index = buffer.position(); + entry.memory_index = m_buffer.position(); // copy pixels over 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 { 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() { - if (!dirty) + if (!m_dirty) return; - dirty = false; + m_dirty = false; pages.clear(); // only if we have stuff to pack @@ -266,7 +266,7 @@ void Packer::pack() if (!sources[i]->empty) { 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: // Optimize this? @@ -293,18 +293,18 @@ void Packer::clear() { pages.clear(); entries.clear(); - dirty = false; + m_dirty = false; } void Packer::dispose() { pages.clear(); entries.clear(); - buffer.close(); + m_buffer.close(); max_size = 0; power_of_two = 0; spacing = 0; - dirty = false; + m_dirty = false; } Packer::Node::Node() diff --git a/public/blah/images/packer.h b/public/blah/images/packer.h index e9bc3a4..745fc72 100644 --- a/public/blah/images/packer.h +++ b/public/blah/images/packer.h @@ -66,8 +66,8 @@ namespace Blah Node* Reset(const RectI& rect); }; - bool dirty; - BufferStream buffer; + bool m_dirty; + BufferStream m_buffer; void add_entry(uint64_t id, int w, int h, const Color* pixels); }; diff --git a/public/blah/math/mat3x2.cpp b/public/blah/math/mat3x2.cpp index e67016e..9bc5a95 100644 --- a/public/blah/math/mat3x2.cpp +++ b/public/blah/math/mat3x2.cpp @@ -162,7 +162,7 @@ Mat3x2 Mat3x2::add(const Mat3x2& a, const Mat3x2& b) a.m21 + b.m21, a.m22 + b.m22, a.m31 + b.m31, - a.m21 + b.m32); + a.m32 + b.m32); } 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.m22 - b.m22, a.m31 - b.m31, - a.m21 - b.m32); + a.m32 - b.m32); } Mat3x2 Mat3x2::multiply(const Mat3x2& a, const Mat3x2& b) diff --git a/public/blah/math/rect.cpp b/public/blah/math/rect.cpp index b778e95..db39da5 100644 --- a/public/blah/math/rect.cpp +++ b/public/blah/math/rect.cpp @@ -54,10 +54,169 @@ Rect Rect::scale(float sx, float sy) return *this; } -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()); } +float Rect::left() const +{ + return x; +} + +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); } diff --git a/public/blah/math/rect.h b/public/blah/math/rect.h index b316ceb..bfdbc83 100644 --- a/public/blah/math/rect.h +++ b/public/blah/math/rect.h @@ -23,59 +23,45 @@ namespace Blah Rect scale(float s); Rect scale(float sx, float sy); - float left() const { return x; } - float right() const { return x + w; } - float top() const { return y; } - float bottom() const { return y + h; } + float left() const; + float right() const; + float top() const; + float bottom() const; - Vec2 center() const { return Vec2(x + w / 2, y + h / 2); } - float center_x() const { return x + w / 2; } - float center_y() const { return y + h / 2; } + Vec2 center() const; + float center_x() const; + float center_y() const; - Vec2 top_left() const { return Vec2(x, y); } - Vec2 top_right() const { return Vec2(x + w, y); } - Vec2 bottom_right() const { return Vec2(x + w, y + h); } - Vec2 bottom_left() const { return Vec2(x, y + h); } + Vec2 top_left() const; + Vec2 top_right() const; + Vec2 bottom_right() const; + Vec2 bottom_left() const; - Vec2 center_left() const { return Vec2(x, y + h / 2); } - Vec2 center_right() const { return Vec2(x + w, y + h / 2); } - Vec2 middle_top() const { return Vec2(x + w / 2, y); } - Vec2 middle_bottom() const { return Vec2(x + w / 2, y + h); } + Vec2 center_left() const; + Vec2 center_right() const; + Vec2 middle_top() const; + Vec2 middle_bottom() const; Line left_line() const; Line right_line() const; Line top_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 Vec2& 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; 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, Vec2* out_intersection_point) const { return line.intersects(*this, out_intersection_point); } - 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, Vec2* out_intersection_point) const { return intersects(Line(line_from, line_to), out_intersection_point); } + bool intersects(const Line& line) const; + bool intersects(const Line& line, Vec2* out_intersection_point) const; + 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; - Vec2 intersection_point(const Line& line) const - { - Vec2 ret; - if (line.intersects(*this, &ret)) - return ret; - else - return Vec2::zero; - } + Vec2 intersection_point(const Line& line) const; + Vec2 intersection_point(const Vec2& line_from, const Vec2& line_to) const; - Vec2 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 inflate(float amount) const { return Rect(x - amount, y - amount, w + amount * 2, h + amount * 2); } + Rect inflate(float amount) const; /* Rect Sectors: