Skip to content

Commit

Permalink
Add Rectangle class
Browse files Browse the repository at this point in the history
  • Loading branch information
mikke89 committed Apr 10, 2023
1 parent 1811229 commit 5267e77
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 59 deletions.
1 change: 1 addition & 0 deletions CMake/FileList.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ set(Core_PUB_HDR_FILES
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyIdSet.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyParser.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertySpecification.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Rectangle.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/RenderInterface.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ScriptInterface.h
${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ScrollTypes.h
Expand Down
2 changes: 1 addition & 1 deletion Include/RmlUi/Core/Elements/ElementProgress.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class RMLUICORE_API ElementProgress : public Element
Texture texture;

// The rectangle extracted from a sprite, 'rect_set' controls whether it is active.
Rectangle rect;
Rectanglef rect;
bool rect_set;

// The geometry used to render this element. Only applies if the 'fill-image' property is set.
Expand Down
125 changes: 125 additions & 0 deletions Include/RmlUi/Core/Rectangle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* This source file is part of RmlUi, the HTML/CSS Interface Middleware
*
* For the latest information, see http://github.com/mikke89/RmlUi
*
* Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
* Copyright (c) 2019 The RmlUi Team, and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#ifndef RMLUI_CORE_RECTANGLE_H
#define RMLUI_CORE_RECTANGLE_H

#include "Debug.h"
#include "Vector2.h"

namespace Rml {

/**
Templated class for a generic rectangle.
*/
template <typename Type>
class Rectangle {
public:
using Vector2Type = Vector2<Type>;

Rectangle() = default;

static inline Rectangle FromPosition(Vector2Type pos) { return Rectangle(pos, pos); }
static inline Rectangle FromPositionSize(Vector2Type pos, Vector2Type size) { return Rectangle(pos, pos + size); }
static inline Rectangle FromSize(Vector2Type size) { return Rectangle(Vector2Type(), size); }
static inline Rectangle FromCorners(Vector2Type top_left, Vector2Type bottom_right) { return Rectangle(top_left, bottom_right); }
static inline Rectangle MakeInvalid() { return Rectangle(Vector2Type(0), Vector2Type(-1)); }

Vector2Type Position() const { return p0; }
Vector2Type Size() const { return p1 - p0; }

Vector2Type TopLeft() const { return p0; }
Vector2Type BottomRight() const { return p1; }

Vector2Type Center() const { return (p0 + p1) / Type(2); }

Type Left() const { return p0.x; }
Type Right() const { return p1.x; }
Type Top() const { return p0.y; }
Type Bottom() const { return p1.y; }
Type Width() const { return p1.x - p0.x; }
Type Height() const { return p1.y - p0.y; }

void Extend(Type v) { Extend(Vector2Type(v)); }
void Extend(Vector2Type v)
{
p0 -= v;
p1 += v;
}
void ExtendTopLeft(Vector2Type v) { p0 -= v; }
void ExtendBottomRight(Vector2Type v) { p1 += v; }

void Join(Vector2Type p)
{
p0 = Math::Min(p0, p);
p1 = Math::Max(p1, p);
}
void Join(Rectangle other)
{
p0 = Math::Min(p0, other.p0);
p1 = Math::Max(p1, other.p1);
}

void Intersect(Rectangle other)
{
RMLUI_ASSERT(Valid() && other.Valid());
p0 = Math::Max(p0, other.p0);
p1 = Math::Max(Math::Min(p1, other.p1), p0);
}
void IntersectIfValid(Rectangle other)
{
if (!Valid())
*this = other;
else if (other.Valid())
Intersect(other);
}

bool Intersects(Rectangle other) const { return p0.x < other.p1.x && p1.x > other.p0.x && p0.y < other.p1.y && p1.y > other.p0.y; }
bool Contains(Vector2Type point) const { return point.x >= p0.x && point.x <= p1.x && point.y >= p0.y && point.y <= p1.y; }

bool Valid() const { return p0.x <= p1.x && p0.y <= p1.y; }

bool operator==(Rectangle rhs) const { return p0 == rhs.p0 && p1 == rhs.p1; }
bool operator!=(Rectangle rhs) const { return !(*this == rhs); }

template <typename U>
explicit operator Rectangle<U>() const
{
return Rectangle<U>::FromCorners(static_cast<Vector2<U>>(p0), static_cast<Vector2<U>>(p1));
}

Vector2Type p0; // Minimum coordinates for a valid rectangle.
Vector2Type p1; // Maximum coordinates for a valid rectangle.

private:
Rectangle(Vector2Type p0, Vector2Type p1) : p0(p0), p1(p1) {}
};

} // namespace Rml

#endif
10 changes: 2 additions & 8 deletions Include/RmlUi/Core/Spritesheet.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,8 @@ namespace Rml {

struct Spritesheet;


struct Rectangle {
Rectangle(float x = 0, float y = 0, float width = 0, float height = 0) : x(x), y(y), width(width), height(height) {}
float x, y, width, height;
};

struct Sprite {
Rectangle rectangle; // in 'px' units
Rectanglef rectangle; // in 'px' units
const Spritesheet* sprite_sheet;
};
using SpriteMap = UnorderedMap<String, Sprite>; // key: sprite name (as given in @spritesheet)
Expand All @@ -63,7 +57,7 @@ struct Spritesheet {
int definition_line_number, float display_scale, const Texture& texture);
};

using SpriteDefinitionList = Vector<Pair<String, Rectangle>>; // Sprite name and rectangle
using SpriteDefinitionList = Vector<Pair<String, Rectanglef>>; // Sprite name and rectangle


/**
Expand Down
4 changes: 3 additions & 1 deletion Include/RmlUi/Core/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum class Character : char32_t { Null, Replacement = 0xfffd };
#include "Vector2.h"
#include "Vector3.h"
#include "Vector4.h"
#include "Rectangle.h"
#include "Matrix4.h"
#include "ObserverPtr.h"

Expand All @@ -67,6 +68,8 @@ using Vector3i = Vector3< int >;
using Vector3f = Vector3< float >;
using Vector4i = Vector4< int >;
using Vector4f = Vector4< float >;
using Rectanglei = Rectangle< int >;
using Rectanglef = Rectangle< float >;
using ColumnMajorMatrix4f = Matrix4< float, ColumnMajorStorage< float > >;
using RowMajorMatrix4f = Matrix4< float, RowMajorStorage< float > >;
using Matrix4f = RMLUI_MATRIX4_TYPE;
Expand All @@ -87,7 +90,6 @@ struct Animation;
struct Transition;
struct TransitionList;
struct DecoratorDeclarationList;
struct Rectangle;
enum class EventId : uint16_t;
enum class PropertyId : uint8_t;
enum class MediaQueryId : uint8_t;
Expand Down
13 changes: 7 additions & 6 deletions Source/Core/DecoratorNinePatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ DecoratorNinePatch::~DecoratorNinePatch()
{
}

bool DecoratorNinePatch::Initialise(const Rectangle& _rect_outer, const Rectangle& _rect_inner, const Array<Property, 4>* _edges, const Texture& _texture, float _display_scale)
bool DecoratorNinePatch::Initialise(const Rectanglef& _rect_outer, const Rectanglef& _rect_inner, const Array<Property, 4>* _edges, const Texture& _texture, float _display_scale)
{
rect_outer = _rect_outer;
rect_inner = _rect_inner;
Expand Down Expand Up @@ -79,11 +79,12 @@ DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) co
/* In the following, we operate on the four diagonal vertices in the grid, as they define the whole grid. */

// Absolute texture coordinates 'px'
Vector2f tex_pos[4];
tex_pos[0] = { rect_outer.x, rect_outer.y };
tex_pos[1] = { rect_inner.x, rect_inner.y };
tex_pos[2] = { rect_inner.x + rect_inner.width, rect_inner.y + rect_inner.height };
tex_pos[3] = { rect_outer.x + rect_outer.width, rect_outer.y + rect_outer.height };
Vector2f tex_pos[4] = {
rect_outer.TopLeft(),
rect_inner.TopLeft(),
rect_inner.BottomRight(),
rect_outer.BottomRight(),
};

// Normalized texture coordinates [0, 1]
Vector2f tex_coords[4];
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/DecoratorNinePatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ class DecoratorNinePatch : public Decorator
DecoratorNinePatch();
virtual ~DecoratorNinePatch();

bool Initialise(const Rectangle& rect_outer, const Rectangle& rect_inner, const Array<Property, 4>* _edges, const Texture& texture, float display_scale);
bool Initialise(const Rectanglef& rect_outer, const Rectanglef& rect_inner, const Array<Property, 4>* _edges, const Texture& texture, float display_scale);

DecoratorDataHandle GenerateElementData(Element* element) const override;
void ReleaseElementData(DecoratorDataHandle element_data) const override;

void RenderElement(Element* element, DecoratorDataHandle element_data) const override;

private:
Rectangle rect_outer, rect_inner;
Rectanglef rect_outer, rect_inner;
float display_scale = 1;
UniquePtr<Array<Property,4>> edges;
};
Expand Down
6 changes: 2 additions & 4 deletions Source/Core/DecoratorTiledInstancer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,8 @@ bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Tex
// A tile is always either a sprite or an image.
if (const Sprite * sprite = instancer_interface.GetSprite(texture_name))
{
tile.position.x = sprite->rectangle.x;
tile.position.y = sprite->rectangle.y;
tile.size.x = sprite->rectangle.width;
tile.size.y = sprite->rectangle.height;
tile.position = sprite->rectangle.Position();
tile.size = sprite->rectangle.Size();
tile.display_scale = sprite->sprite_sheet->display_scale;

texture = sprite->sprite_sheet->texture;
Expand Down
27 changes: 9 additions & 18 deletions Source/Core/Elements/ElementImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,19 @@ bool ElementImage::GetIntrinsicDimensions(Vector2f& _dimensions, float& _ratio)

// Calculate the x dimension.
if (HasAttribute("width"))
dimensions.x = GetAttribute< float >("width", -1);
dimensions.x = GetAttribute<float>("width", -1);
else if (rect_source == RectSource::None)
dimensions.x = (float)texture.GetDimensions(GetRenderInterface()).x;
else
dimensions.x = rect.width;
dimensions.x = rect.Width();

// Calculate the y dimension.
if (HasAttribute("height"))
dimensions.y = GetAttribute< float >("height", -1);
else if (rect_source == RectSource::None)
dimensions.y = (float)texture.GetDimensions(GetRenderInterface()).y;
else
dimensions.y = rect.height;
dimensions.y = rect.Height();

dimensions *= dimensions_scale;

Expand Down Expand Up @@ -190,17 +190,9 @@ void ElementImage::GenerateGeometry()
Vector2f texcoords[2];
if (rect_source != RectSource::None)
{
Vector2f texture_dimensions((float) texture.GetDimensions(GetRenderInterface()).x, (float) texture.GetDimensions(GetRenderInterface()).y);
if (texture_dimensions.x == 0)
texture_dimensions.x = 1;
if (texture_dimensions.y == 0)
texture_dimensions.y = 1;

texcoords[0].x = rect.x / texture_dimensions.x;
texcoords[0].y = rect.y / texture_dimensions.y;

texcoords[1].x = (rect.x + rect.width) / texture_dimensions.x;
texcoords[1].y = (rect.y + rect.height) / texture_dimensions.y;
Vector2f texture_dimensions = Vector2f(Math::Max(texture.GetDimensions(GetRenderInterface()), Vector2i(1)));
texcoords[0] = rect.TopLeft() / texture_dimensions;
texcoords[1] = rect.BottomRight() / texture_dimensions;
}
else
{
Expand Down Expand Up @@ -305,10 +297,9 @@ void ElementImage::UpdateRect()
}
else
{
rect.x = (float)std::atof(coords_list[0].c_str());
rect.y = (float)std::atof(coords_list[1].c_str());
rect.width = (float)std::atof(coords_list[2].c_str());
rect.height = (float)std::atof(coords_list[3].c_str());
const Vector2f position = {FromString(coords_list[0], 0.f), FromString(coords_list[1], 0.f)};
const Vector2f size = {FromString(coords_list[2], 0.f), FromString(coords_list[3], 0.f)};
rect = Rectanglef::FromPositionSize(position, size);

// We have new, valid coordinates; force the geometry to be regenerated.
valid_rect = true;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Elements/ElementImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class RMLUICORE_API ElementImage : public Element

// The rectangle extracted from the sprite or 'rect' attribute. The rect_source will be None if
// these have not been specified or are invalid.
Rectangle rect;
Rectanglef rect;
enum class RectSource { None, Attribute, Sprite } rect_source;

// The geometry used to render this element.
Expand Down
14 changes: 3 additions & 11 deletions Source/Core/Elements/ElementProgress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,9 @@ void ElementProgress::GenerateGeometry()
Vector2f texcoords[2];
if (rect_set)
{
Vector2f texture_dimensions((float)texture.GetDimensions(GetRenderInterface()).x, (float)texture.GetDimensions(GetRenderInterface()).y);
if (texture_dimensions.x == 0)
texture_dimensions.x = 1;
if (texture_dimensions.y == 0)
texture_dimensions.y = 1;

texcoords[0].x = rect.x / texture_dimensions.x;
texcoords[0].y = rect.y / texture_dimensions.y;

texcoords[1].x = (rect.x + rect.width) / texture_dimensions.x;
texcoords[1].y = (rect.y + rect.height) / texture_dimensions.y;
Vector2f texture_dimensions = Vector2f(Math::Max(texture.GetDimensions(GetRenderInterface()), Vector2i(1)));
texcoords[0] = rect.TopLeft() / texture_dimensions;
texcoords[1] = rect.BottomRight() / texture_dimensions;
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Spritesheet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ bool SpritesheetList::AddSpriteSheet(const String& name, const String& image_sou
for (auto& sprite_definition : sprite_definitions)
{
const String& sprite_name = sprite_definition.first;
const Rectangle& sprite_rectangle = sprite_definition.second;
const Rectanglef& sprite_rectangle = sprite_definition.second;

Sprite& new_sprite = sprite_map[sprite_name];
if (new_sprite.sprite_sheet)
Expand Down
12 changes: 6 additions & 6 deletions Source/Core/StyleSheetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,17 @@ class SpritesheetPropertyParser final : public AbstractPropertyParser {
if (!specification.ParseShorthandDeclaration(properties, id_rectangle, value))
return false;

Rectangle rectangle;
Vector2f position, size;
if (auto property = properties.GetProperty(id_rx))
rectangle.x = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
position.x = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
if (auto property = properties.GetProperty(id_ry))
rectangle.y = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
position.y = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
if (auto property = properties.GetProperty(id_rw))
rectangle.width = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
size.x = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
if (auto property = properties.GetProperty(id_rh))
rectangle.height = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));
size.y = ComputeAbsoluteLength(*property, 1.f, Vector2f(1.f));

sprite_definitions.emplace_back(name, rectangle);
sprite_definitions.emplace_back(name, Rectanglef::FromPositionSize(position, size));
}

return true;
Expand Down

0 comments on commit 5267e77

Please sign in to comment.