Stripped back old shader code for now.

This commit is contained in:
2024-12-24 12:27:55 -06:00
parent 2b36a12335
commit e10aea20a1
81 changed files with 325 additions and 900 deletions

16
archive/ui/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
UIAlignableElement.cpp
UISubAlignableElement.cpp
UIElement.cpp
UIMenu.cpp
)
# Subdirs
add_subdirectory(container)
add_subdirectory(elements)

View File

@ -0,0 +1,247 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIAlignableElement.hpp"
using namespace Dawn;
UIAlignableElement::UIAlignableElement() {
alignUnit[0] = UIAlignmentUnit::SCALE;
alignUnit[1] = UIAlignmentUnit::SCALE;
alignUnit[2] = UIAlignmentUnit::SCALE;
alignUnit[3] = UIAlignmentUnit::SCALE;
eventAlignmentUpdated = [&](const glm::vec2 p, const glm::vec2 s) {
};
}
void UIAlignableElement::updateSelfAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
auto valueAxis = [&](
const enum UIAlignmentUnit unit,
const float_t alignment,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize
) {
if(alignment == UI_ALIGN_SIZE_AUTO) return contentSize;
switch(unit) {
case UIAlignmentUnit::PIXEL:
return alignment;
case UIAlignmentUnit::SCALE:
return canvasScale * alignment;
case UIAlignmentUnit::PERCENT:
return parentSize * (alignment / 100.0f);
case UIAlignmentUnit::RATIO:
return (alignment / 100.0f) * ratioSize;
default:
assertUnreachable("Invalid UIAlignmentType");
return 0.0f;
}
};
auto alignAxis = [&](
const enum UIAlignmentType type,
const enum UIAlignmentUnit unit0,
const enum UIAlignmentUnit unit1,
const float_t alignment0,
const float_t alignment1,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize,
float_t &outPosition,
float_t &outSize
) {
switch(type) {
case UIAlignmentType::START:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::MIDDLE:
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
outPosition = (parentSize / 2.0f) - (contentSize / 2.0f) + valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::END:
outSize = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outPosition = parentSize - outSize - valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::STRETCH:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = parentSize - (outPosition + valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
));
break;
default:
assertUnreachable("Invalid UIAlignmentType");
}
};
bool_t heightFirst = (
alignUnit[0] == UIAlignmentUnit::RATIO ||
alignUnit[2] == UIAlignmentUnit::RATIO
);
if(heightFirst) {
// Align height first, this will define size.y which we can use as the ratio
// for the width/X axis alignment.
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
0,
this->getContentHeight(),
position.y,
size.y
);
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
size.y,
this->getContentWidth(),
position.x,
size.x
);
} else {
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
0,
this->getContentWidth(),
position.x,
size.x
);
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
size.x,
this->getContentHeight(),
position.y,
size.y
);
}
this->position += pPos;
this->eventAlignmentUpdated(position, size);
}
bool_t UIAlignableElement::hasExplicitWidth() {
if(size.x == 0.0f) return false;
if(
(alignX == UIAlignmentType::STRETCH) ||
(alignX == UIAlignmentType::END)
) {
return align[0] != UI_ALIGN_SIZE_AUTO;
}
return align[2] != UI_ALIGN_SIZE_AUTO;
}
bool_t UIAlignableElement::hasExplicitHeight() {
if(size.y == 0.0f) return false;
if(
(alignY == UIAlignmentType::STRETCH) ||
(alignY == UIAlignmentType::END)
) {
return align[1] != UI_ALIGN_SIZE_AUTO;
}
return align[3] != UI_ALIGN_SIZE_AUTO;
}
float_t UIAlignableElement::getWidth() {
if(hasExplicitWidth()) return size.x;
return getContentWidth();
}
float_t UIAlignableElement::getHeight() {
if(hasExplicitHeight()) return size.y;
return getContentHeight();
}
void UIAlignableElement::updateAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
this->updateSelfAlignment(pPos, pSize, canvasScale);
// Now update children alignment
auto children = getChildren();
for(auto &c : children) {
c->updateAlignment(this->position, this->size, canvasScale);
}
}

View File

@ -0,0 +1,83 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIElement.hpp"
namespace Dawn {
#define UI_ALIGN_SIZE_AUTO -1.0f
enum class UIAlignmentType {
START,
MIDDLE,
END,
STRETCH
};
enum class UIAlignmentUnit {
PIXEL,
SCALE,
PERCENT,
RATIO
};
class UIAlignableElement : public UIElement {
protected:
glm::vec2 position;
glm::vec2 size;
/**
* Updates the alignment of this element ONLY.
*
* @param parentPosition The position of the parent.
* @param parentSize The size of the parent.
* @param canvasScale The scale of the canvas.
*/
virtual void updateSelfAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
);
/**
* Returns true only if the width of this component is explicitly set.
*
* @return True if the width of this component is explicitly set.
*/
bool_t hasExplicitWidth();
/**
* Returns true only if the height of this component is explicitly set.
*
* @return True if the height of this component is explicitly set.
*/
bool_t hasExplicitHeight();
public:
// Primary alignment controls
glm::vec4 align = glm::vec4(0, 0, 0, 0);
enum UIAlignmentType alignX = UIAlignmentType::STRETCH;
enum UIAlignmentType alignY = UIAlignmentType::STRETCH;
enum UIAlignmentUnit alignUnit[4];
std::function<
void(const glm::vec2, const glm::vec2)
> eventAlignmentUpdated;
/**
* Constructor for the UIAlignableElement.
*/
UIAlignableElement();
float_t getWidth() override;
float_t getHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

53
archive/ui/UIElement.cpp Normal file
View File

@ -0,0 +1,53 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIElement.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
std::vector<std::shared_ptr<UIElement>> UIElement::getChildren() {
return {};
}
void UIElement::getSelfQuads(UICanvas &ctx) {
//Do nothing
}
float_t UIElement::getContentWidth() {
return 0.0f;
}
float_t UIElement::getContentHeight() {
return 0.0f;
}
float_t UIElement::getWidth() {
return this->getContentWidth();
}
float_t UIElement::getHeight() {
return this->getContentHeight();
}
void UIElement::getQuads(UICanvas &ctx) {
this->getSelfQuads(ctx);
auto children = getChildren();
for(auto &c : children) {
c->getQuads(ctx);
}
}
void UIElement::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
auto children = getChildren();
for(auto &c : children) {
c->updateAlignment(parentPosition, parentSize, canvasScale);
}
}

80
archive/ui/UIElement.hpp Normal file
View File

@ -0,0 +1,80 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/UIShader.hpp"
#include "component/ui/UICanvas.hpp"
namespace Dawn {
class UIElement {
protected:
/**
* Virtual method overridden by the UIElement to get the quads for the
* component.
*
* @param alignment The alignment of this component.
* @param ctx The canvas to add the quads to.
*/
virtual void getSelfQuads(UICanvas &ctx);
public:
/**
* Overrided method by the UI Element that requests the minimum
* width of the content.
*
* @return The minimum width of the content.
*/
virtual float_t getContentWidth();
/**
* Overrided method by the UI Element that requests the minimum
* height of the content.
*
* @return The minimum height of the content.
*/
virtual float_t getContentHeight();
/**
* Returns the width of this component.
*
* @return The width of this component.
*/
virtual float_t getWidth();
/**
* Returns the height of this component.
*
* @return The height of this component.
*/
virtual float_t getHeight();
/**
* Virtual method overridden by the UIElement to get the children of
* this component.
*/
virtual std::vector<std::shared_ptr<UIElement>> getChildren();
/**
* Method called by the UICanvas to get the quads for this component.
*
* @param ctx The canvas to add the quads to.
*/
void getQuads(UICanvas &ctx);
/**
* Updates the alignment of this component based on the parent. Typically
* left to the UIAlignableElement to implement, default implementation
* does nothing but invoke children.
*
* @param parentPosition The position of the parent.
* @param parentSize The size of the parent.
*/
virtual void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
);
};
}

50
archive/ui/UIMenu.cpp Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIMenu.hpp"
using namespace Dawn;
void UIMenu::setPosition(int32_t x, int32_t y) {
assertTrue(x >= 0, "X position must be greater than or equal to 0.");
assertTrue(y >= 0, "Y position must be greater than or equal to 0.");
assertTrue(x < columns, "X must be less than the number of columns.");
assertTrue(y < rows, "Y must be less than the number of rows.");
if(this->x == x && this->y == y) return;
this->x = x;
this->y = y;
eventPositionChanged.emit(x, y);
}
void UIMenu::setSize(int32_t columns, int32_t rows) {
assertTrue(columns > 0, "Columns must be greater than 0.");
assertTrue(rows > 0, "Rows must be greater than 0.");
assertTrue(columns > x, "Columns must be greater than current x position.");
assertTrue(rows > y, "Rows must be greater than current y position.");
if(this->columns == columns && this->rows == rows) return;
this->columns = columns;
this->rows = rows;
}
int32_t UIMenu::getX() {
return x;
}
int32_t UIMenu::getY() {
return y;
}
int32_t UIMenu::getColumns() {
return columns;
}
int32_t UIMenu::getRows() {
return rows;
}

64
archive/ui/UIMenu.hpp Normal file
View File

@ -0,0 +1,64 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIElement.hpp"
namespace Dawn {
class UIMenu final : public UIElement {
private:
int32_t x = 0;
int32_t y = 0;
int32_t columns = 1;
int32_t rows = 1;
public:
Event<int32_t, int32_t> eventPositionChanged;
/**
* Sets the position of this menu.
*
* @param x The x position of this menu.
* @param y The y position of this menu.
*/
void setPosition(int32_t x, int32_t y);
/**
* Sets the size of this menu.
*
* @param columns The number of columns in this menu.
* @param rows The number of rows in this menu.
*/
void setSize(int32_t columns, int32_t rows);
/**
* Gets the x position of this menu.
*
* @return The x position of this menu.
*/
int32_t getX();
/**
* Gets the y position of this menu.
*
* @return The y position of this menu.
*/
int32_t getY();
/**
* Gets the number of columns in this menu.
*
* @return The number of columns in this menu.
*/
int32_t getColumns();
/**
* Gets the number of rows in this menu.
*
* @return The number of rows in this menu.
*/
int32_t getRows();
};
}

View File

@ -0,0 +1,68 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UISubAlignableElement.hpp"
using namespace Dawn;
void UISubAlignableElement::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
UIAlignableElement::updateAlignment(parentPosition, parentSize, canvasScale);
switch(this->subAlignX) {
case UISubAlignment::START:
this->subAlignedPosition.x = this->position.x;
break;
case UISubAlignment::MIDDLE:
this->subAlignedPosition.x = (
this->position.x +
(this->size.x / 2.0f) -
(this->getContentWidth() / 2.0f)
);
break;
case UISubAlignment::END:
this->subAlignedPosition.x = (
this->position.x +
this->size.x -
this->getContentWidth()
);
break;
default:
assertUnreachable("Unknown UISubAlignment!");
}
switch(this->subAlignY) {
case UISubAlignment::START:
this->subAlignedPosition.y = this->position.y;
break;
case UISubAlignment::MIDDLE:
this->subAlignedPosition.y = (
this->position.y +
(this->size.y / 2.0f) -
(this->getContentHeight() / 2.0f)
);
break;
case UISubAlignment::END:
this->subAlignedPosition.y = (
this->position.y +
this->size.y -
this->getContentHeight()
);
break;
default:
assertUnreachable("Unknown UISubAlignment!");
}
this->eventSubAlignmentUpdated.emit(this->subAlignedPosition);
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
enum class UISubAlignment {
START,
MIDDLE,
END
};
class UISubAlignableElement : public UIAlignableElement {
protected:
glm::vec2 subAlignedPosition;
public:
Event<glm::vec2> eventSubAlignmentUpdated;
enum UISubAlignment subAlignX = UISubAlignment::START;
enum UISubAlignment subAlignY = UISubAlignment::START;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -0,0 +1,12 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
UIColumnContainer.cpp
UIContainer.cpp
UIPaddingContainer.cpp
UIRowContainer.cpp
)

View File

@ -0,0 +1,36 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
#include "UIColumnContainer.hpp"
using namespace Dawn;
void UIColumnContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
this->updateSelfAlignment(parentPosition, parentSize, canvasScale);
// Now we have our dimensions, divide evenly
auto children = this->getChildren();
float_t x = 0.0f;
float_t xPiece = this->size.x / (float_t)children.size();
// Update all children
for(auto &child : children) {
child->updateAlignment(
this->position + glm::vec2(x, 0),
glm::vec2(
xPiece,
this->size.y
),
canvasScale
);
x += xPiece;
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIColumnContainer final : public UIContainer {
public:
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -0,0 +1,47 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
#include "UIContainer.hpp"
using namespace Dawn;
std::vector<std::shared_ptr<UIElement>> UIContainer::getChildren() {
return this->children;
}
float_t UIContainer::getContentWidth() {
float_t width = 0;
auto children = this->getChildren();
for(auto child : children) {
width = Math::max(width, child->getWidth());
}
return width;
}
float_t UIContainer::getContentHeight() {
float_t height = 0;
auto children = this->getChildren();
for(auto child : children) {
height = Math::max(height, child->getHeight());
}
return height;
}
void UIContainer::appendChild(std::shared_ptr<UIElement> child) {
assertNotNull(child, "Cannot append a null child!");
this->children.push_back(child);
}
void UIContainer::removeChild(std::shared_ptr<UIElement> child) {
assertNotNull(child, "Cannot remove a null child!");
auto it = std::find(this->children.begin(), this->children.end(), child);
if(it == this->children.end()) return;
this->children.erase(it);
}
void UIContainer::clearChildren() {
this->children.clear();
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
class UIContainer : public UIAlignableElement {
private:
std::vector<std::shared_ptr<UIElement>> children;
public:
std::vector<std::shared_ptr<UIElement>> getChildren() override;
float_t getContentWidth() override;
float_t getContentHeight() override;
/**
* Appends a child to this container.
*
* @param child Child to append.
*/
void appendChild(std::shared_ptr<UIElement> child);
/**
* Removes a child from this container.
*
* @param child Child to remove.
*/
void removeChild(std::shared_ptr<UIElement> child);
/**
* Removes all children from this container.
*/
void clearChildren();
};
}

View File

@ -0,0 +1,38 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIPaddingContainer.hpp"
using namespace Dawn;
float_t UIPaddingContainer::getContentWidth() {
float_t width = 0.0f;
for(auto &child : getChildren()) {
width = Math::max(width, child->getWidth());
}
return width + padding.x + padding.z;
}
float_t UIPaddingContainer::getContentHeight() {
float_t height = 0.0f;
for(auto &child : getChildren()) {
height = Math::max(height, child->getHeight());
}
return height + padding.y + padding.w;
}
void UIPaddingContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
glm::vec2 childPosition = parentPosition + glm::vec2(padding.x, padding.y);
glm::vec2 childSize = parentSize - glm::vec2(padding.x + padding.z, padding.y + padding.w);
auto children = getChildren();
for(auto &child : children) {
child->updateAlignment(childPosition, childSize, canvasScale);
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIPaddingContainer final : public UIContainer {
public:
glm::vec4 padding = { 0, 0, 0, 0 };
float_t getContentWidth() override;
float_t getContentHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -0,0 +1,51 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIRowContainer.hpp"
using namespace Dawn;
float_t UIRowContainer::getContentWidth() {
float_t width = 0.0f;
for(auto &child : this->getChildren()) {
width = Math::max(width, child->getWidth());
}
return width;
}
float_t UIRowContainer::getContentHeight() {
float_t height = 0.0f;
for(auto &child : this->getChildren()) {
height += child->getHeight();
}
return height;
}
void UIRowContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
this->updateSelfAlignment(parentPosition, parentSize, canvasScale);
// Now we have our dimensions, divide evenly
auto children = this->getChildren();
float_t y = 0.0f;
float_t yPiece = this->size.y / (float_t)children.size();
// Update all children
for(auto &child : children) {
child->updateAlignment(
this->position + glm::vec2(0, y),
glm::vec2(
this->size.x,
yPiece
),
canvasScale
);
y += yPiece;
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIRowContainer final : public UIContainer {
public:
float_t getContentWidth() override;
float_t getContentHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -0,0 +1,10 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
UILabel.cpp
UIRectangle.cpp
)

View File

@ -0,0 +1,175 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UILabel.hpp"
using namespace Dawn;
void UILabel::getSelfQuads(UICanvas &ctx) {
std::vector<struct UIShaderQuad> quads;
if(this->texture == nullptr || this->text.empty()) return;
glm::vec4 quad;
glm::vec2 pos = glm::vec2(0, this->texture->fontSize);
bool_t lastCharWasSpace = false;
for(size_t i = 0; i < text.size(); i++) {
wchar_t c = text[i];
auto info = texture->getCharacterData(c);
// Newline(s)
if(c == L'\n') {
pos.x = 0;
pos.y += this->texture->fontSize;
continue;
}
// Spaces
if(c == L' ') {
pos.x += info.advance.x;
lastCharWasSpace = true;
continue;
}
// Word Wrap
if(wordWrap) {
if(lastCharWasSpace) {
// Scan ahead to next space
float_t wordWidth = pos.x;// Start at current position and scan ahead.
for(size_t j = i; j < text.size(); j++) {
wchar_t c2 = text[j];
if(c2 == L' ' || c2 == L'\n') {
break;// If we hit another space, we are OK.
}
// Will this character fit on the row? If not the whole word will wrap.
auto info2 = texture->getCharacterData(c);
wordWidth += info.advance.x;
if(wordWidth > size.x) {
pos.x = 0;
pos.y += this->texture->fontSize;
break;
}
}
lastCharWasSpace = false;
}
// } else if(pos.x + info.size.x > subAlignedPosition.x + size.x) {
// // Not word wrap, but instead just overflow characters.
// pos.x = 0;
// pos.y += this->texture->fontSize;
}
ctx.addQuad(
{
subAlignedPosition.x + pos.x + info.offset.x,
subAlignedPosition.y + pos.y + info.offset.y,
subAlignedPosition.x + pos.x + info.size.x + info.offset.x,
subAlignedPosition.y + pos.y + info.size.y + info.offset.y
},
{
info.quad.x,
info.quad.y,
info.quad.z,
info.quad.w
},
this->color,
UIShaderQuadStyle::FONT,
texture->texture
);
pos += info.advance;
}
}
float_t UILabel::getContentWidth() {
if(this->texture == nullptr || this->text.empty()) return 0.0f;
float_t lineWidth = 0.0f;
float_t width = 0.0f;
for(wchar_t c : text) {
if(c == L'\n') {
width = Math::max<float_t>(width, lineWidth);
lineWidth = 0.0f;
continue;
}
auto info = texture->getCharacterData(c);
lineWidth += info.advance.x;
if(
this->hasExplicitWidth() &&
lineWidth >= size.x
) return size.x;
}
width = Math::max<float_t>(width, lineWidth);
return width;
}
float_t UILabel::getContentHeight() {
if(this->texture == nullptr || this->text.empty()) return 0.0f;
float_t height = this->texture->fontSize;
float_t lineWidth = 0.0f;
bool_t lastCharWasSpace = false;
for(wchar_t c : text) {
if(c == L'\n') {
height += this->texture->fontSize;
continue;
}
auto info = texture->getCharacterData(c);
if(c == L' ') {
lineWidth += info.advance.x;
lastCharWasSpace = true;
continue;
}
if(wordWrap) {
if(lastCharWasSpace) {
// Scan ahead to next space
float_t wordWidth = lineWidth;// Start at current position and scan ahead.
for(size_t j = 0; j < text.size(); j++) {
wchar_t c2 = text[j];
if(c2 == L' ' || c2 == L'\n') {
break;// If we hit another space, we are OK.
}
// Will this character fit on the row? If not the whole word will wrap.
auto info2 = texture->getCharacterData(c);
wordWidth += info.advance.x;
if(wordWidth > size.x) {
height += this->texture->fontSize;
lineWidth = 0.0f;
break;
}
}
lastCharWasSpace = false;
}
// } else if(lineWidth + info.size.x > size.x) {
// height += this->texture->fontSize;
// lineWidth = 0.0f;
}
}
return height;
}
std::shared_ptr<TrueTypeTexture> UILabel::getFont() {
return this->texture;
}
std::wstring UILabel::getText() {
return this->text;
}
void UILabel::setFont(std::shared_ptr<TrueTypeTexture> texture) {
this->texture = texture;
}
void UILabel::setText(const std::wstring &text) {
this->text = text;
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UISubAlignableElement.hpp"
#include "display/font/TrueTypeTexture.hpp"
namespace Dawn {
class UILabel final : public UISubAlignableElement {
private:
std::shared_ptr<TrueTypeTexture> texture = nullptr;
std::wstring text = L"Hello World";
protected:
void getSelfQuads(UICanvas &ctx) override;
public:
bool_t wordWrap = true;
struct Color color = COLOR_WHITE;
float_t getContentWidth() override;
float_t getContentHeight() override;
/**
* Returns the font used for this label.
*
* @return The font used for this label.
*/
std::shared_ptr<TrueTypeTexture> getFont();
/**
* Returns the text used for this label.
*
* @return The text used for this label.
*/
std::wstring getText();
/**
* Sets the font to use for this label.
*
* @param texture TrueType texture to use for this label.
*/
void setFont(std::shared_ptr<TrueTypeTexture> texture);
/**
* Sets the text to use for this label.
*
* @param text The text to use for this label.
*/
void setText(const std::wstring &text);
};
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIRectangle.hpp"
using namespace Dawn;
void UIRectangle::getSelfQuads(UICanvas &ctx) {
std::vector<struct UIShaderQuad> quads;
ctx.addQuad(
glm::vec4(position, position + size),
uv,
color,
UIShaderQuadStyle::TEXTURED,
texture
);
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
class UIRectangle final : public UIAlignableElement {
protected:
void getSelfQuads(UICanvas &ctx) override;
public:
struct Color color = COLOR_WHITE;
std::shared_ptr<Texture> texture = nullptr;
glm::vec4 uv = glm::vec4(0,0,1,1);
};
}