diff --git a/src/dawn/CMakeLists.txt b/src/dawn/CMakeLists.txt index 0ee68451..87fc9815 100644 --- a/src/dawn/CMakeLists.txt +++ b/src/dawn/CMakeLists.txt @@ -35,7 +35,6 @@ add_subdirectory(save) add_subdirectory(scene) add_subdirectory(state) add_subdirectory(time) -add_subdirectory(ui) if(DAWN_VISUAL_NOVEL) add_subdirectory(visualnovel) diff --git a/src/dawn/display/RenderPipeline.cpp b/src/dawn/display/RenderPipeline.cpp index 6d153c48..deb05880 100644 --- a/src/dawn/display/RenderPipeline.cpp +++ b/src/dawn/display/RenderPipeline.cpp @@ -153,14 +153,16 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) { assertUnreachable(); } - auto itChild = canvas->children.begin(); - while(itChild != canvas->children.end()) { - vectorAppend(&shaderPassItems, (*itChild)->getPassItems( - projection, view, model - )); - ++itChild; - } - ++itCanvas; + auto children = canvas->item.chil + + // auto itChild = canvas->children.begin(); + // while(itChild != canvas->children.end()) { + // vectorAppend(&shaderPassItems, (*itChild)->getPassItems( + // projection, view, model + // )); + // ++itChild; + // } + // ++itCanvas; } // Debug Lines diff --git a/src/dawn/display/RenderPipeline.hpp b/src/dawn/display/RenderPipeline.hpp index e8541540..bdfb3f04 100644 --- a/src/dawn/display/RenderPipeline.hpp +++ b/src/dawn/display/RenderPipeline.hpp @@ -9,8 +9,7 @@ #include "scene/components/display/MeshRenderer.hpp" #include "scene/components/display/Camera.hpp" #include "scene/components/scene/SubSceneController.hpp" -#include "ui/UIComponent.hpp" - +#include "scene/components/ui/UIComponent.hpp" namespace Dawn { class RenderManager; diff --git a/src/dawn/scene/components/ui/UICanvas.cpp b/src/dawn/scene/components/ui/UICanvas.cpp index fe591f36..ff7d066f 100644 --- a/src/dawn/scene/components/ui/UICanvas.cpp +++ b/src/dawn/scene/components/ui/UICanvas.cpp @@ -4,9 +4,7 @@ // https://opensource.org/licenses/MIT #include "UICanvas.hpp" -#include "ui/UIComponent.hpp" #include "game/DawnGame.hpp" -#include "ui/UIMenu.hpp" using namespace Dawn; @@ -15,71 +13,11 @@ UICanvas * UICanvas::create(Scene *scene) { return item->addComponent(); } -UICanvas::UICanvas(SceneItem *item) : - SceneItemComponent(item), - camera(nullptr), - currentMenu(nullptr) -{ -} - -float_t UICanvas::getWidth() { - if(this->camera == nullptr) { - return this->getGame()->renderManager.getBackBuffer()->getWidth(); - } - return this->camera->getRenderTarget()->getWidth(); -} - -float_t UICanvas::getHeight() { - if(this->camera == nullptr) { - return this->getGame()->renderManager.getBackBuffer()->getHeight(); - } - return this->camera->getRenderTarget()->getHeight(); -} - -void UICanvas::setCurrentMenu(struct UIMenu *menu) { +UICanvas::UICanvas(SceneItem *item) : SceneItemComponent(item) { } void UICanvas::onStart() { - useEffectWithTeardown([&]{ - if(this->camera == nullptr) return evtCamResize = [&]{}; - - auto it = this->children.begin(); - while(it != this->children.end()) { - (*it)->updatePositions(); - ++it; - } - - return evtCamResize = useEvent([&](float_t w, float_t h){ - auto it = this->children.begin(); - while(it != this->children.end()) { - (*it)->updatePositions(); - ++it; - } - }, camera->eventRenderTargetResized); - }, camera); - - useEffectWithTeardown([&]{ - if(currentMenu != nullptr) currentMenu->onActive(); - - return [&] { - if(currentMenu == nullptr) currentMenu->onInactive(); - }; - }, this->currentMenu); - - // Scene Update - useEvent([&](float_t delta){ - if(this->currentMenu == nullptr) return; - this->currentMenu->onTick(); - }, getScene()->eventSceneUpdate); - - // Find Camera if we need to. - if(camera == nullptr) camera = this->getScene()->findComponent(); } void UICanvas::onDispose() { - auto it = this->children.begin(); - while(it != this->children.end()) { - delete *it; - ++it; - } } \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UICanvas.hpp b/src/dawn/scene/components/ui/UICanvas.hpp index e07f26e0..ebdf4ec4 100644 --- a/src/dawn/scene/components/ui/UICanvas.hpp +++ b/src/dawn/scene/components/ui/UICanvas.hpp @@ -15,19 +15,8 @@ namespace Dawn { UI_DRAW_TYPE_CAMERA_OVERLAY }; - class UIComponent; - struct UIMenu; - class UICanvas : public SceneItemComponent { - protected: - std::function evtCamResize; - - void onRenderTargetResize(float_t w, float_t h); - public: - StateProperty currentMenu; - StateProperty camera; - /** * Creates a UI Canvas Scene Item Element, and attaches it to the provided * scene. @@ -38,8 +27,8 @@ namespace Dawn { static UICanvas * create(Scene *scene); //======================================================================// - std::vector children; - UIDrawType drawType = UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE; + + enum UIDrawType drawType = UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE; /** * Constructs the UI Canvas Scene Item Component. @@ -48,65 +37,6 @@ namespace Dawn { */ UICanvas(SceneItem *item); - /** - * Construct and append a UI item to this UI Canvas. - * - * @tparam Type of the UI Item. - * @return Pointer to the created UI Item. - */ - template - T * addElement() { - auto item = new T(this); - this->children.push_back(item); - return item; - } - - /** - * Find a UI Element attached to this canvas. - * - * @tparam Type of the UI item to find. - * @return Pointer to first matching element of type T. - */ - template - T * findElement() { - auto it = this->children.begin(); - while(it != this->children.end()) { - auto castedAs = dynamic_cast(*it); - if(castedAs != nullptr) return castedAs; - ++it; - } - return nullptr; - } - - /** - * Returns the width of the root UI Canvas size. In future I may allow - * this to be dynamic, right now it uses the render canvas however. - * - * @return Width of the UI Canvas. - */ - float_t getWidth(); - - /** - * Returns the height of this UI Canvas element. - * - * @return Height of the UI Canvas. - */ - float_t getHeight(); - - /** - * Returns the currently active menu for this UI Canvas. - * - * @return The currently active menu, or nullptr if there is none. - */ - struct UIMenu * getCurrentMenu(); - - /** - * Sets the currently active menu, and ticks it appropriately. - * - * @param menu Menu to set as the current active menu. - */ - void setCurrentMenu(struct UIMenu *menu); - void onStart() override; void onDispose() override; }; diff --git a/src/dawn/scene/components/ui/UIComponent.cpp b/src/dawn/scene/components/ui/UIComponent.cpp new file mode 100644 index 00000000..493bcf7e --- /dev/null +++ b/src/dawn/scene/components/ui/UIComponent.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "UIComponent.hpp" + +using namespace Dawn; + +UIComponent::UIComponent(SceneItem *item) : SceneItemComponent(item) { + +} \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UIComponent.hpp b/src/dawn/scene/components/ui/UIComponent.hpp new file mode 100644 index 00000000..715f4026 --- /dev/null +++ b/src/dawn/scene/components/ui/UIComponent.hpp @@ -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 "scene/SceneItemComponent.hpp" +#include "UICanvas.hpp" + +namespace Dawn { + class UIComponent : public SceneItemComponent { + private: + UICanvas *canvas = nullptr; + + public: + UIComponent(SceneItem *item); + + friend class UICanvas; + }; +} \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UILabel.cpp b/src/dawn/scene/components/ui/UILabel.cpp new file mode 100644 index 00000000..8c3a3310 --- /dev/null +++ b/src/dawn/scene/components/ui/UILabel.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "UILabel.hpp" + +using namespace Dawn; + +UILabel::UILabel(SceneItem *item) : + UIComponent(item), + text(""), + fontSize(10.0f), + font(nullptr) +{ +} + +void UILabel::updateMesh() { + if(!this->needsRebuffering || !this->hasText) return; + if(((Font*)this->font) == nullptr || !this->font->isReady()) return; + + // float_t width = this->width; + // if(width == 0) width = -1; + + // std::string text = this->getGame()->localeManager.getString(key); + this->font->buffer( + this->text, + this->fontSize, + -1, + &this->mesh, + &this->measure + ); + this->needsRebuffering = false; +} + +void UILabel::onStart() { + useEffect([&]{ + hasText = ((std::string)text).size() > 0; + needsRebuffering = true; + }, text); + + useEffect([&]{ + needsRebuffering = true; + }, fontSize); + + useEffect([&]{ + needsRebuffering = true; + }, font); +} \ No newline at end of file diff --git a/src/dawn/scene/components/ui/UILabel.hpp b/src/dawn/scene/components/ui/UILabel.hpp new file mode 100644 index 00000000..20a95d33 --- /dev/null +++ b/src/dawn/scene/components/ui/UILabel.hpp @@ -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 "UIComponent.hpp" + +namespace Dawn { + class UILabel : public UIComponent { + private: + bool_t needsRebuffering = true; + bool_t hasText = false; + + Mesh mesh; + + void updateMesh(); + + public: + StateProperty text; + StateProperty fontSize; + StateProperty font; + struct Color textColor = COLOR_MAGENTA; + struct FontMeasure measure; + int32_t startQuad = 0; + int32_t quadCount = -1; + + UILabel(SceneItem *item); + + void onStart() override; + }; +} \ No newline at end of file diff --git a/src/dawn/ui/CMakeLists.txt b/src/dawn/ui/CMakeLists.txt deleted file mode 100644 index 1c86017b..00000000 --- a/src/dawn/ui/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2022 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DAWN_TARGET_NAME} - PRIVATE - UIBorder.cpp - UIComponent.cpp - UILabel.cpp - UISprite.cpp - UIEmpty.cpp - UIGrid.cpp - UIMenu.cpp -) \ No newline at end of file diff --git a/src/dawn/ui/UIBorder.cpp b/src/dawn/ui/UIBorder.cpp deleted file mode 100644 index f1222583..00000000 --- a/src/dawn/ui/UIBorder.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UIBorder.hpp" -#include "game/DawnGame.hpp" - -using namespace Dawn; - -UIBorder::UIBorder(UICanvas *canvas) : UIComponent(canvas) { - this->mesh.createBuffers(QUAD_VERTICE_COUNT * 9, QUAD_INDICE_COUNT * 9); - - this->updatePositions(); -} - -void UIBorder::updatePositions() { - UIComponent::updatePositions(); - - glm::vec2 oneThird = this->uv1 / 3.0f; - glm::vec2 overallDimensions = glm::vec2(this->getWidth(), this->getHeight()); - glm::vec2 innerDimensions = overallDimensions - (this->edgeDimensions * 2.0f); - - - // Top Left. - QuadMesh::bufferQuadMesh(&this->mesh, - glm::vec2(0, 0), - this->uv0, - edgeDimensions, - this->uv0 + oneThird, - 0, 0 - ); - - // Top Center - QuadMesh::bufferQuadMesh(&this->mesh, - glm::vec2(edgeDimensions.x, 0), - this->uv0 + glm::vec2(oneThird.x, 0), - glm::vec2(edgeDimensions.x + innerDimensions.x, edgeDimensions.y), - this->uv0 + glm::vec2(oneThird.x * 2.0f, oneThird.y), - QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT - ); - - // Top Right - QuadMesh::bufferQuadMesh(&this->mesh, - glm::vec2(edgeDimensions.x + innerDimensions.x, 0), - this->uv0 + glm::vec2(oneThird.x * 2.0f, 0), - glm::vec2(overallDimensions.x, edgeDimensions.y), - glm::vec2(this->uv1.x, this->uv0.y + oneThird.y), - QUAD_VERTICE_COUNT * 2, QUAD_INDICE_COUNT * 2 - ); - - // Middle Left - QuadMesh::bufferQuadMesh(&this->mesh, - glm::vec2(0, edgeDimensions.y), - this->uv0 + glm::vec2(0, oneThird.y), - glm::vec2(edgeDimensions.x, edgeDimensions.y + innerDimensions.y), - this->uv0 + glm::vec2(oneThird.x, oneThird.y * 2.0f), - QUAD_VERTICE_COUNT * 3, QUAD_INDICE_COUNT * 3 - ); - - // Center - QuadMesh::bufferQuadMesh(&this->mesh, - edgeDimensions, - this->uv0 + oneThird, - edgeDimensions + innerDimensions, - this->uv0 + (oneThird * 2.0f), - QUAD_VERTICE_COUNT * 4, QUAD_INDICE_COUNT * 4 - ); - - // Middle Right - QuadMesh::bufferQuadMesh(&this->mesh, - edgeDimensions + glm::vec2(innerDimensions.x, 0), - this->uv0 + glm::vec2(oneThird.x * 2.0f, oneThird.y), - edgeDimensions + innerDimensions + glm::vec2(edgeDimensions.x, 0), - this->uv1 - glm::vec2(0.0f, oneThird.y), - QUAD_VERTICE_COUNT * 5, QUAD_INDICE_COUNT * 5 - ); - - // Bottom Left - QuadMesh::bufferQuadMesh(&this->mesh, - glm::vec2(0.0f, edgeDimensions.y + innerDimensions.y), - this->uv0 + glm::vec2(0.0f, uv1.y - oneThird.y), - glm::vec2(edgeDimensions.x, overallDimensions.y), - this->uv1 - glm::vec2(oneThird.x * 2.0f, 0.0f), - QUAD_VERTICE_COUNT * 6, QUAD_INDICE_COUNT * 6 - ); - - // Bottom Center - QuadMesh::bufferQuadMesh(&this->mesh, - edgeDimensions + glm::vec2(0.0f, innerDimensions.y), - this->uv1 - oneThird, - overallDimensions - glm::vec2(edgeDimensions.x, 0.0f), - this->uv1 - glm::vec2(oneThird.x, 0.0f), - QUAD_VERTICE_COUNT * 7, QUAD_INDICE_COUNT * 7 - ); - - // Bottom Right - QuadMesh::bufferQuadMesh(&this->mesh, - overallDimensions - edgeDimensions, - this->uv1 - oneThird, - overallDimensions, - this->uv1, - QUAD_VERTICE_COUNT * 8, QUAD_INDICE_COUNT * 8 - ); -} - -std::vector UIBorder::getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform -) { - std::vector items; - if(this->texture == nullptr) return items; - - items.push_back(this->getGame()->renderManager.uiShaderProgram.getUIPassItem( - projection, - view, - transform, - this->texture, - COLOR_WHITE, - &this->mesh, - this->z - )); - - return items; -} - -void UIBorder::setBorderSize(glm::vec2 borderSize) { - this->edgeDimensions = borderSize; - this->updatePositions(); -} - -glm::vec2 UIBorder::getInnerSize() { - return glm::vec2(this->getWidth(), this->getHeight()) - this->edgeDimensions; -} - -glm::vec2 UIBorder::getBorderSize() { - return this->edgeDimensions; -} - -UIBorder::~UIBorder() { -} \ No newline at end of file diff --git a/src/dawn/ui/UIBorder.hpp b/src/dawn/ui/UIBorder.hpp deleted file mode 100644 index f98ae7b0..00000000 --- a/src/dawn/ui/UIBorder.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "UIComponent.hpp" -#include "display/mesh/QuadMesh.hpp" -#include "display/Texture.hpp" - -namespace Dawn { - class UIBorder : public UIComponent { - private: - Mesh mesh; - glm::vec2 edgeDimensions = glm::vec2(8.0f, 8.0f); - glm::vec2 uv0 = glm::vec2(0.0f, 0.0f); - glm::vec2 uv1 = glm::vec2(1.0f, 1.0f); - - void updatePositions() override; - std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) override; - - public: - Texture *texture = nullptr; - - UIBorder(UICanvas *canvas); - - /** - * Changes the dimensions of the border. - * - * @param borderSize Size of the border. - */ - void setBorderSize(glm::vec2 borderSize); - - /** - * Returns the size of the border. - * - * @return Border size of this UI border. - */ - glm::vec2 getBorderSize(); - - /** - * Returns the size of the area within the border. - * - * @return The inner content area size. - */ - glm::vec2 getInnerSize(); - - ~UIBorder(); - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UIComponent.cpp b/src/dawn/ui/UIComponent.cpp deleted file mode 100644 index 3cd5b23b..00000000 --- a/src/dawn/ui/UIComponent.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UIComponent.hpp" - -using namespace Dawn; - -void UIComponent::calculateDimensions( - enum UIComponentAlign align, - float_t *position, - float_t *size, - float_t outerSize, - float_t innerSize, - glm::vec2 alignment -) { - assertNotNull(position); - assertNotNull(size); - - switch(align) { - case UI_COMPONENT_ALIGN_STRETCH: - *position = alignment[0]; - *size = outerSize + (alignment[0] + alignment[1]); - break; - - case UI_COMPONENT_ALIGN_START: - *position = alignment[0]; - *size = alignment[1]; - break; - - case UI_COMPONENT_ALIGN_MIDDLE: - *size = innerSize; - *position = (outerSize / 2.0f) - (innerSize / 2.0f) + alignment[0]; - break; - - case UI_COMPONENT_ALIGN_END: - *size = alignment[0]; - *position = outerSize - innerSize - alignment[1]; - break; - - default: - assertUnreachable(); - break; - } -} - -UIComponent::UIComponent(UICanvas *canvas) { - assertNotNull(canvas); - this->canvas = canvas; -} - -void UIComponent::updatePositions() { - float_t outerWidth, outerHeight; - - if(this->parent == nullptr) { - outerWidth = this->canvas->getWidth(); - outerHeight = this->canvas->getHeight(); - } else { - outerWidth = this->parent->getWidth(); - outerHeight = this->parent->getHeight(); - } - - UIComponent::calculateDimensions( - this->alignX, - &this->relativeX, - &this->width, - outerWidth, - this->getContentWidth(), - glm::vec2(this->alignment[0], this->alignment[2]) - ); - UIComponent::calculateDimensions( - this->alignY, - &this->relativeY, - &this->height, - outerHeight, - this->getContentHeight(), - glm::vec2(this->alignment[1], this->alignment[3]) - ); - -// this->relativeX = mathRound(this->relativeX); -// this->relativeY = mathRound(this->relativeY); -// this->width = mathRound(this->width); -// this->height = mathRound(this->height); - - // Update children - auto it = this->children.begin(); - while(it != this->children.end()) { - (*it)->updatePositions(); - ++it; - } - - // Fire event - eventAlignmentUpdated.invoke(this); -} - -float_t UIComponent::getWidth() { - return this->width; -} - -float_t UIComponent::getHeight() { - return this->height; -} - -float_t UIComponent::getContentWidth() { - return this->width; -} - -float_t UIComponent::getContentHeight() { - return this->height; -} - -float_t UIComponent::getRelativeX() { - return this->relativeX; -} - -float_t UIComponent::getRelativeY() { - return this->relativeY; -} - -DawnGame * UIComponent::getGame() { - return this->canvas->getGame(); -} - -Scene * UIComponent::getScene() { - return this->canvas->getScene(); -} - -void UIComponent::setTransform( - UIComponentAlign xAlign, - UIComponentAlign yAlign, - glm::vec4 alignment, - float_t z -) { - this->alignX = xAlign; - this->alignY = yAlign; - this->alignment = alignment; - this->z = z; - this->updatePositions(); -} - -std::vector UIComponent::getPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 parent -) { - - // Calculate self transform matrix - glm::mat4 selfTransform = parent * glm::translate( - glm::mat4(1.0f), - glm::vec3(this->relativeX, this->relativeY, this->z) - ); - - // Draw Self - auto items = this->getSelfPassItems(projection, view, selfTransform); - - // Render children - auto it = this->children.begin(); - while(it != this->children.end()) { - vectorAppend(&items, (*it)->getPassItems(projection, view, selfTransform)); - ++it; - } - - return items; -} - -void UIComponent::addChild(UIComponent *child) { - if(child->parent == this) return; - if(child->parent != nullptr) child->parent->removeChild(child); - this->children.push_back(child); - child->parent = this; - this->updatePositions(); -} - -void UIComponent::removeChild(UIComponent *child) { - assertTrue(child->parent == this); - auto it = this->children.begin(); - while(it != this->children.end()) { - if(*it == child) { - this->children.erase(it); - break; - } - ++it; - } - child->parent = nullptr; -} - -UIComponent::~UIComponent() { - -} \ No newline at end of file diff --git a/src/dawn/ui/UIComponent.hpp b/src/dawn/ui/UIComponent.hpp deleted file mode 100644 index 67d61ede..00000000 --- a/src/dawn/ui/UIComponent.hpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "scene/components/ui/UICanvas.hpp" -#include "display/Color.hpp" -#include "util/array.hpp" -#include "util/mathutils.hpp" -#include "display/shader/Shader.hpp" -#include "state/State.hpp" - -namespace Dawn { - enum UIComponentAlign { - UI_COMPONENT_ALIGN_START, - UI_COMPONENT_ALIGN_MIDDLE, - UI_COMPONENT_ALIGN_END, - UI_COMPONENT_ALIGN_STRETCH - }; - - class UIGrid; - - class UIComponent : public StateOwner { - protected: - // Calculated (and cached) values - float_t width = 1; - float_t height = 1; - float_t relativeX = 0; - float_t relativeY = 0; - - // Setting values - UIComponentAlign alignX = UI_COMPONENT_ALIGN_START; - UIComponentAlign alignY = UI_COMPONENT_ALIGN_START; - glm::vec4 alignment = glm::vec4(0, 0, 32, 32); - float_t z = 0; - std::vector children; - UIComponent *parent = nullptr; - - // Events - Event eventAlignmentUpdated; - - // I currently don't support rotation or scale. Not because I can't but - // because it's basically un-necessary. Unity does support rotation but - // it doesn't affect how the alignment side of things work (similar to how - // CSS would handle things) When I need to support these I will add the - // code but right now it's not necessary - - /** - * Updates the cached/stored values based on the setting internal values. - * You should watchdog this if you intend to do something when values are - * updated, e.g. if you need to resize a quad, or something. - */ - virtual void updatePositions(); - - /** - * Intended to be overwritten by subclass. Called by the draw method to - * ask this child to draw. - * - * @param projection Projection matrix of the camera. - * @param view View matrix of the camera. - * @param parent Matrix of the parent of this UI item. - * @return The list of shader pass items. - */ - virtual std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) = 0; - - public: - /** - * Method used to calculate alignment dimensions. - * - * @param align Alignment value enumator. - * @param position Output position floating point. - * @param size Output size floating point. - * @param outerSize Outer size (of the parent). - * @param innerSize Inner size (of this element's content). - * @param alignment Alignment settings. - */ - static void calculateDimensions( - enum UIComponentAlign align, - float_t *position, - float_t *size, - float_t outerSize, - float_t innerSize, - glm::vec2 alignment - ); - - UICanvas *canvas; - - UIComponent(UICanvas *canvas); - - /** - * Returns the calculated width, based on the internal alignment values. - * - * @return Width of the component. - */ - virtual float_t getWidth(); - - /** - * Returns the calculated height, based on the internal alignment values. - * - * @return Height of the component. - */ - virtual float_t getHeight(); - - /** - * Returns the internal width of the content within this element, e.g. - * the content width. - * - * @return Content width. - */ - virtual float_t getContentWidth(); - - /** - * Returns the internal height of the content within this element, e.g. - * the content height. - * - * @return Content height. - */ - virtual float_t getContentHeight(); - - /** - * Returns the X position, relative to this components' parent. - * - * @return Relative X position. - */ - float_t getRelativeX(); - - /** - * Returns the Y position, relative to this components' parent. - * - * @return Relative Y position. - */ - float_t getRelativeY(); - - /** - * Gets the game that this UI component belongs to. - * - * @return Game instance. - */ - DawnGame * getGame(); - - /** - * Gets the scene that thsi UI Component belongs to. - * - * @return Scene instance. - */ - Scene * getScene(); - - /** - * Updates the transformation for this component. - * - * @param xAlign X axis alignment method. - * @param yAlign Y axis alignment method. - * @param alignment Alignment parameters, changes depending on the align. - * @param z Z position (relative to screen). - */ - virtual void setTransform( - UIComponentAlign xAlign, - UIComponentAlign yAlign, - glm::vec4 alignment, - float_t z - ); - - /** - * Returns the list of renderable shader pass items for this UI element. - * This is basically how you get your UI item to draw, this is called by - * the RenderPipeline. - * - * @param projection Projection matrix of the camera. - * @param view View matrix of the camera. - * @param parent Matrix of the parent of this UI item. - * @return The list of shader pass items, including children. - */ - std::vector getPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 parent - ); - - /** - * Adds a child to this UI Component. - * - * @param child Child UI Component to add. - */ - virtual void addChild(UIComponent *child); - - /** - * Removes a child from this UI Component. - * - * @param child Child to remove. - */ - virtual void removeChild(UIComponent *child); - - virtual ~UIComponent(); - - friend class UICanvas; - friend class UIGrid; - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UIEmpty.cpp b/src/dawn/ui/UIEmpty.cpp deleted file mode 100644 index f59fcb40..00000000 --- a/src/dawn/ui/UIEmpty.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UIEmpty.hpp" - -using namespace Dawn; - -UIEmpty::UIEmpty(UICanvas *canvas) : UIComponent(canvas) { - -} - -std::vector UIEmpty::getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform -) { - return std::vector(); -} \ No newline at end of file diff --git a/src/dawn/ui/UIEmpty.hpp b/src/dawn/ui/UIEmpty.hpp deleted file mode 100644 index 7bb7dc32..00000000 --- a/src/dawn/ui/UIEmpty.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "UIComponent.hpp" - -namespace Dawn { - class UIEmpty : public UIComponent { - protected: - std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) override; - - public: - UIEmpty(UICanvas *canvas); - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UIGrid.cpp b/src/dawn/ui/UIGrid.cpp deleted file mode 100644 index f4b66b32..00000000 --- a/src/dawn/ui/UIGrid.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UIGrid.hpp" - -using namespace Dawn; - -UIGrid::UIGrid(UICanvas *canvas) : UIComponent(canvas) { - -} - -void UIGrid::updatePositions() { - UIComponent::updatePositions(); - - this->sizeCol = ( - this->width - (this->gutterX * (this->columns - 1)) - ) / this->columns; - this->sizeRow = ( - this->height - (this->gutterY * (this->rows - 1)) - ) / this->rows; - - auto it = this->gridChildren.begin(); - while(it != this->gridChildren.end()) { - this->alignChild(it->first, it->second); - ++it; - } -} - -std::vector UIGrid::getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform -) { - return std::vector(); -} - -void UIGrid::onChildAligned(UIComponent *child) { - if(this->alignmentListenerLocked) return; - assertNotNull(child); - assertMapHasKey(this->gridChildren, child); - this->alignmentListenerLocked = true; - this->alignChild(child, this->gridChildren[child]); - this->alignmentListenerLocked = false; -} - -void UIGrid::alignChild(UIComponent *child, struct UIGridPosition pos) { - assertNotNull(child); - - float_t gridX = (this->sizeCol * pos.x) + (this->gutterX * pos.x); - float_t gridY = (this->sizeRow * pos.y) + (this->gutterY * pos.y); - - // Hack for when content width is undefined. - child->width = this->sizeCol; - child->height = this->sizeRow; - - // Alignment - float_t x, y, sizeX, sizeY; - UIComponent::calculateDimensions( - pos.alignX, - &x, - &sizeX, - this->sizeCol, - child->getContentWidth(), - glm::vec2(0, 0) - ); - UIComponent::calculateDimensions( - pos.alignY, - &y, - &sizeY, - this->sizeRow, - child->getContentHeight(), - glm::vec2(0, 0) - ); - - child->setTransform( - UI_COMPONENT_ALIGN_START, UI_COMPONENT_ALIGN_START, - glm::vec4(gridX + x, gridY + y, sizeX, sizeY), - 0.0f - ); -} - -void UIGrid::setGridSize( - int32_t columns, int32_t rows, - float_t gutterX, float_t gutterY -) { - this->rows = rows; - this->columns = columns; - this->gutterX = gutterX; - this->gutterY = gutterY; - - // TODO: Need to fix children here. - - this->gridChildren.clear(); - this->updatePositions(); -} - -void UIGrid::addToGrid( - UIComponent *ui, - int32_t x, int32_t y, - enum UIComponentAlign alignX, enum UIComponentAlign alignY -) { - assertTrue(x >= 0 && x < this->columns); - assertTrue(y >= 0 && y < this->rows); - this->addChild(ui); - struct UIGridPosition pos; - pos.x = x; - pos.y = y; - pos.alignX = alignX; - pos.alignY = alignY; - this->gridChildren[ui] = pos; - this->alignChild(ui, pos); - - // Re-Add event listener - ui->eventAlignmentUpdated.addListener(this, &UIGrid::onChildAligned); -} - -int32_t UIGrid::getRows() { - return this->rows; -} - -int32_t UIGrid::getColumns() { - return this->columns; -} - -void UIGrid::removeChild(UIComponent *component) { - UIComponent::removeChild(component); - assertUnreachable(); -} \ No newline at end of file diff --git a/src/dawn/ui/UIGrid.hpp b/src/dawn/ui/UIGrid.hpp deleted file mode 100644 index 685678b2..00000000 --- a/src/dawn/ui/UIGrid.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "UIComponent.hpp" -#include "util/mathutils.hpp" - -namespace Dawn { - struct UIGridPosition { - int32_t x; - int32_t y; - enum UIComponentAlign alignX; - enum UIComponentAlign alignY; - }; - - - class UIGrid : public UIComponent { - private: - int32_t rows = 1; - int32_t columns = 1; - float_t gutterX = 0; - float_t gutterY = 0; - float_t sizeRow, sizeCol; - std::map gridChildren; - bool_t alignmentListenerLocked = false; - - /** - * Internal method to update the alignment of a child. - * - * @param child Child UI component. - * @param pos Positional information of the child UI item.. - */ - void alignChild(UIComponent *child, struct UIGridPosition pos); - - void onChildAligned(UIComponent *child); - - protected: - void updatePositions() override; - std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) override; - - public: - UIGrid(UICanvas *canvas); - - /** - * Sets the dimensions of the grid. - * - * @param columns Count of columns in the grid. - * @param rows Count of rows in the grid. - * @param gutterX Gutter spacing between the cells of the grid. - * @param gutterY Gutter spacing between the cells of the grid. - */ - void setGridSize( - int32_t columns, int32_t rows, - float_t gutterX, float_t gutterY - ); - - /** - * Adds a UI component to the grid. - * - * @param component Component to add to the grid. - * @param column Column Position. - * @param row Row Position. - * @param alignX X alignment of the component within the cell. - * @param alignY Y alignment of the component within the cell. - */ - void addToGrid( - UIComponent *ui, - int32_t x, int32_t y, - enum UIComponentAlign alignX, enum UIComponentAlign alignY - ); - - int32_t getRows(); - int32_t getColumns(); - - void removeChild(UIComponent *component) override; - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UILabel.cpp b/src/dawn/ui/UILabel.cpp deleted file mode 100644 index 8d5c641a..00000000 --- a/src/dawn/ui/UILabel.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UILabel.hpp" -#include "game/DawnGame.hpp" - -using namespace Dawn; - -UILabel::UILabel(UICanvas *canvas) : UIComponent(canvas) { - evtLangUpdated = useEvent([&]{ - this->needsRebuffering = true; - if(key.size() > 0 && this->getGame()->localeManager.getString(key).size() > 0) { - this->hasText = true; - } - }, getGame()->localeManager.eventLanguageUpdated); -} - -void UILabel::updatePositions() { - UIComponent::updatePositions(); - this->updateMesh(); -} - -void UILabel::updateMesh() { - if(!this->needsRebuffering || !this->hasText) return; - if(this->font == nullptr || !this->font->isReady()) return; - - float_t width = this->width; - if(width == 0) width = -1; - - std::string text = this->getGame()->localeManager.getString(key); - this->font->buffer( - text, - this->fontSize, - width, - &this->mesh, - &this->measure - ); - - this->needsRebuffering = false; -} - -void UILabel::setFont(Font *font) { - this->font = font; - this->needsRebuffering = true; -} - -void UILabel::setText(std::string key) { - this->key = key; - this->hasText = false; - if(key.size() > 0 && this->getGame()->localeManager.getString(key).size()>0){ - this->hasText = true; - } - this->needsRebuffering = true; -} - -void UILabel::setFontSize(float_t fontSize) { - this->fontSize = fontSize; - this->needsRebuffering = true; -} - -float_t UILabel::getFontSize() { - return this->fontSize; -} - -float_t UILabel::getContentWidth() { - this->updateMesh(); - return this->measure.getWidth(); -} - -float_t UILabel::getContentHeight() { - this->updateMesh(); - return this->measure.getHeight(); -} - -std::vector UILabel::getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform -) { - std::vector items; - if(this->font == nullptr) return items; - - // this has to go eventually - this->updateMesh(); - auto item = this->getGame()->renderManager.uiShaderProgram.getUIPassItem( - projection, - view, - transform, - this->font->getTexture(), - this->textColor, - &this->mesh, - this->z - ); - item.start = this->startQuad * QUAD_INDICE_COUNT; - item.count = this->quadCount == -1 ? -1 : this->quadCount * QUAD_INDICE_COUNT; - items.push_back(item); - return items; -} - -void UILabel::setTransform( - UIComponentAlign xAlign, - UIComponentAlign yAlign, - glm::vec4 alignment, - float_t z -) { - this->needsRebuffering = true; - UIComponent::setTransform(xAlign, yAlign, alignment, z); -} \ No newline at end of file diff --git a/src/dawn/ui/UILabel.hpp b/src/dawn/ui/UILabel.hpp deleted file mode 100644 index 8bb25f14..00000000 --- a/src/dawn/ui/UILabel.hpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "UIComponent.hpp" -#include "display/mesh/QuadMesh.hpp" -#include "display/font/Font.hpp" - -namespace Dawn { - class UILabel : public UIComponent { - private: - Mesh mesh; - bool_t needsRebuffering = true; - Font *font = nullptr; - std::string key = ""; - float_t fontSize = 10.0f; - bool_t hasText = false; - std::function evtLangUpdated; - - void updatePositions() override; - - std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) override; - - public: - struct FontMeasure measure; - int32_t startQuad = 0; - int32_t quadCount = -1; - - /** The colour of this label */ - struct Color textColor = COLOR_MAGENTA; - - UILabel(UICanvas *canvas); - virtual float_t getContentWidth() override; - virtual float_t getContentHeight() override; - void setTransform( - UIComponentAlign xAlign, - UIComponentAlign yAlign, - glm::vec4 alignment, - float_t z - ) override; - - /** - * Internal method to force the font mesh to be recreated. - */ - void updateMesh(); - - /** - * Set the font to use for the label. - * - * @param font Font to use. - */ - void setFont(Font *font); - - /** - * Sets the text for the label to use. - * - * @param key Localzied string key for the label to use. - */ - void setText(std::string key); - - /** - * Sets / Updates the font size for the label. - * - * @param fontSize Font size to use. - */ - void setFontSize(float_t fontSize); - - /** - * Get the labels' current font size. - * - * @return Font size of the label. - */ - float_t getFontSize(); - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UIMenu.cpp b/src/dawn/ui/UIMenu.cpp deleted file mode 100644 index 1c2babce..00000000 --- a/src/dawn/ui/UIMenu.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2023 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UIMenu.hpp" -#include "game/DawnGame.hpp" - -using namespace Dawn; - -UIMenu::UIMenu(UICanvas *canvas, int32_t columns, int32_t rows) { - assertNotNull(canvas); - assertTrue(columns > 0); - assertTrue(rows > 0); - - this->canvas = canvas; - this->rows = rows; - this->columns = columns; - this->items = (UIMenuItem**)memoryFillWithZero(sizeof(UIMenuItem*)*columns*rows); -} - -void UIMenu::setSize(int32_t cols, int32_t rows) { - assertNotNull(this->items); - assertTrue(columns > 0); - assertTrue(rows > 0); - assertTrue(columns != this->columns); - assertTrue(rows != this->rows); - - memoryFree(this->items); - this->items = (UIMenuItem**)memoryFillWithZero(sizeof(UIMenuItem*)*columns*rows); -} - -UIMenuItem * UIMenu::getItem(int32_t x, int32_t y) { - return this->items[x * this->columns + y]; -} - -void UIMenu::setPosition(int32_t x, int32_t y) { - assertTrue(x >= 0 && x < this->columns); - assertTrue(y >= 0 && y < this->rows); - UIMenuItem *item; - - if(this->x != -1) { - assertTrue(this->y != -1); - item = this->getItem(this->x, this->y); - if(item != nullptr) { - item->onItemOff(); - } - } - - this->eventCursorChange.invoke(this->x, this->y, x, y); - - this->x = x; - this->y = y; - item = this->getItem(x, y); - if(item != nullptr && item->canBeOvered()) { - item->onItemOver(); - } -} - -void UIMenu::moveRelative(int32_t x, int32_t y) { - int32_t x2 = this->x + x; - if(x2 < 0 || x2 >= this->columns) return; - int32_t y2 = this->y + y; - if(y2 < 0 || y2 >= this->rows) return; - this->setPosition(x2, y2); -} - -void UIMenu::setItem(int32_t x, int32_t y, UIMenuItem *item) { - assertTrue(x >= 0); - assertTrue(y >= 0); - assertTrue(x < this->columns); - assertTrue(y < this->rows); - assertNotNull(item); - assertNotNull(this->items); - assertNull(this->getItem(x, y)); - - this->items[x * this->columns + y] = item; -} - -void UIMenu::onInactive() { - this->eventMenuInactive.invoke(); -} - -void UIMenu::onActive() { - this->eventMenuActive.invoke(); -} - -void UIMenu::onTick() { - auto im = &this->canvas->getGame()->inputManager; - - if(im->isPressed(INPUT_BIND_ACCEPT)) { - auto item = this->getItem(this->x, this->y); - if(item != nullptr && item->canBeSelected()) { - item->onItemSelected(); - return; - } - } - - if(im->isPressed(INPUT_BIND_NEGATIVE_Y)) { - this->moveRelative(0, 1); - return; - } - - if(im->isPressed(INPUT_BIND_POSITIVE_Y)) { - this->moveRelative(0, -1); - return; - } - - if(im->isPressed(INPUT_BIND_NEGATIVE_X)) { - this->moveRelative(-1, 0); - return; - } - - if(im->isPressed(INPUT_BIND_POSITIVE_X)) { - this->moveRelative(1, 0); - return; - } - - // TODO: Support more modes and holding buttons to scroll. -} - -UIMenu::~UIMenu() { - if(this->canvas->currentMenu == this) this->canvas->currentMenu = nullptr; - memoryFree(this->items); -} \ No newline at end of file diff --git a/src/dawn/ui/UIMenu.hpp b/src/dawn/ui/UIMenu.hpp deleted file mode 100644 index e3357f76..00000000 --- a/src/dawn/ui/UIMenu.hpp +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2023 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "event/Event.hpp" -#include "ui/UIComponent.hpp" -#include "util/memory.hpp" - -namespace Dawn { - class UIMenuItem { - public: - /** - * Called when the item is selected (Accepted) on. - */ - virtual void onItemSelected() = 0; - - /** - * Called when either the mouse or the user controller input is removed - * off this item. - */ - virtual void onItemOver() = 0; - - /** - * Called when either the mouth or the user controller input is put over - * this item. - */ - virtual void onItemOff() = 0; - - /** - * Returns whether the UI item can be hovered overed or not. - * @return Whether it can be overed or not. - */ - virtual bool_t canBeOvered() = 0; - - /** - * Returns whether or not the item can be selected or not. - * @return Whether it can be selected or not. - */ - virtual bool_t canBeSelected() = 0; - }; - - struct UIMenu { - private: - UICanvas *canvas; - int32_t x = -1; - int32_t y = -1; - int32_t rows = 1; - int32_t columns = 1; - UIMenuItem **items = nullptr; - - protected: - /** Invoked by UICanvas when this menu has been made inactive. */ - void onInactive(); - /** Invoked by UICanvas when this menu has been made active. */ - void onActive(); - /** Invoked by UICanvas every tick this menu is active. */ - void onTick(); - - public: - Event<> eventMenuActive; - Event<> eventMenuInactive; - Event eventCursorChange; - Event eventItemSelected; - - /** - * Construct a new UI Menu Host. - * - * @param canvas Canvas that this menu belongs to. - * @param columns Iniitial size of the menu X axis. - * @param rows Initial size of the menu Y axis. - */ - UIMenu(UICanvas *canvas, int32_t columns, int32_t rows); - - /** - * Sets the size of the UI Menu. - * - * @param columns How many columns in the menu. - * @param rows How many rows in the menu. - */ - void setSize(int32_t columns, int32_t rows); - - /** - * Returns the UI Item at the given position. - * - * @param x X coordinate of the item to get. - * @param y Y coordinate of the item to get. - * @return The pointer to the menu item, or null if invalid. - */ - UIMenuItem * getItem(int32_t x, int32_t y); - - /** - * Sets the position of the cursor in the grid. - * - * @param x X position of the cursor. - * @param y Y position of the cursor. - */ - void setPosition(int32_t x, int32_t y); - - /** - * Move the cursor relative to the current position. - * - * @param x X position to move relative. - * @param y Y position to move relative. - */ - void moveRelative(int32_t x, int32_t y); - - /** - * Adds/Sets an item onto the menu. - * - * @param x X coordinate to set the item. - * @param y Y coordinate to set the item. - * @param item Item to set. - */ - void setItem(int32_t x, int32_t y, UIMenuItem *item); - - /** - * Cleans up the menu items, doesn't free the children themselves. - */ - ~UIMenu(); - - friend class UICanvas; - }; -} \ No newline at end of file diff --git a/src/dawn/ui/UISprite.cpp b/src/dawn/ui/UISprite.cpp deleted file mode 100644 index fe1e4119..00000000 --- a/src/dawn/ui/UISprite.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "UISprite.hpp" -#include "game/DawnGame.hpp" - -using namespace Dawn; - -UISprite::UISprite(UICanvas *canvas) : UIComponent(canvas) { - this->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT); -} - -void UISprite::updatePositions() { - UIComponent::updatePositions(); - - QuadMesh::bufferQuadMesh( - &this->mesh, - glm::vec2(0, 0), glm::vec2(0, 0), - glm::vec2(this->width, this->height), glm::vec2(1, 1), - 0, 0 - ); -} - -std::vector UISprite::getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform -) { - std::vector items; - - items.push_back(this->getGame()->renderManager.uiShaderProgram.getUIPassItem( - projection, - view, - transform, - this->texture, - this->color, - &this->mesh, - this->z - )); - return items; -} \ No newline at end of file diff --git a/src/dawn/ui/UISprite.hpp b/src/dawn/ui/UISprite.hpp deleted file mode 100644 index f08ae453..00000000 --- a/src/dawn/ui/UISprite.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "UIComponent.hpp" -#include "display/mesh/QuadMesh.hpp" -#include "display/Texture.hpp" - -namespace Dawn { - class UISprite : public UIComponent { - protected: - void updatePositions() override; - std::vector getSelfPassItems( - glm::mat4 projection, - glm::mat4 view, - glm::mat4 transform - ) override; - - public: - Mesh mesh; - struct Color color = COLOR_WHITE; - Texture *texture = nullptr; - - /** - * UI Sprite Constructor, use the UIElement / UIComponent create instead. - * - * @param canvas Canvas that this sprite belongs to. - */ - UISprite(UICanvas *canvas); - }; -} \ No newline at end of file