diff --git a/CMakeLists.txt b/CMakeLists.txt index aadf06dc..02cd0ee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ SET(SOURCES src/teststate.cpp # framework sources + src/framework/borderedimage.cpp src/framework/dispatcher.cpp src/framework/framebuffer.cpp src/framework/font.cpp diff --git a/src/framework/engine.cpp b/src/framework/engine.cpp index 8b4f0355..4b54b9df 100644 --- a/src/framework/engine.cpp +++ b/src/framework/engine.cpp @@ -68,8 +68,6 @@ void Engine::run() update(ticks, 0); lastUpdateTicks = ticks; - Point fpsPos(10,10); - while(!m_stopping) { // poll platform events Platform::poll(); @@ -105,7 +103,9 @@ void Engine::run() // render fps if(m_calculateFps) { - g_defaultFont->renderText(format("FPS: %d", fps), fpsPos); + std::string fpsText = format("FPS: %d", fps); + Size textSize = g_defaultFont->calculateTextRectSize(fpsText); + g_defaultFont->renderText(fpsText, Point(g_graphics.getScreenSize().width() - textSize.width() - 10, 10)); } // swap buffers @@ -136,7 +136,7 @@ void Engine::render() g_graphics.beginRender(); if(m_currentState) m_currentState->render(); - g_gui.render(); + g_gui->render(); g_graphics.endRender(); } @@ -144,7 +144,7 @@ void Engine::update(int ticks, int elapsedTicks) { if(m_currentState) m_currentState->update(ticks, elapsedTicks); - g_gui.update(ticks, elapsedTicks); + g_gui->update(ticks, elapsedTicks); } void Engine::onClose() @@ -156,13 +156,16 @@ void Engine::onClose() void Engine::onResize(const Size& size) { g_graphics.resize(size); - g_gui.resize(size); + g_gui->resize(size); + + if(m_currentState) + m_currentState->onResize(size); } void Engine::onInputEvent(InputEvent *event) { // inputs goest to gui first - if(!g_gui.onInputEvent(event)) { + if(!g_gui->onInputEvent(event)) { // if gui didnt capture the input then goes to the state if(m_currentState) m_currentState->onInputEvent(event); diff --git a/src/framework/gamestate.h b/src/framework/gamestate.h index a0278003..ba0ff028 100644 --- a/src/framework/gamestate.h +++ b/src/framework/gamestate.h @@ -25,6 +25,8 @@ #ifndef GAMESTATE_H #define GAMESTATE_H +#include "size.h" + struct InputEvent; class GameState @@ -38,6 +40,7 @@ public: virtual void onClose() = 0; virtual void onInputEvent(InputEvent *event) = 0; + virtual void onResize(const Size& size) = 0; virtual void render() = 0; virtual void update(int ticks, int elapsedTicks) = 0; diff --git a/src/framework/graphics.cpp b/src/framework/graphics.cpp index 34d3f546..327eb00a 100644 --- a/src/framework/graphics.cpp +++ b/src/framework/graphics.cpp @@ -180,6 +180,40 @@ void Graphics::_drawTexturedRect(const Rect& screenCoords, const Rect& textureCo glTexCoord2f(textureRight, textureTop); glVertex2i(right, top); } +void Graphics::drawRepeatedTexturedRect(const Rect& screenCoords, const Texture* texture, const Rect& texCoords) +{ + glBindTexture(GL_TEXTURE_2D, texture->getTextureId()); + glBegin(GL_QUADS); + _drawRepeatedTexturedRect(screenCoords, texCoords, texture->getSize()); + glEnd(); +} + +void Graphics::_drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize) +{ + // render many repeated texture rects + Rect virtualScreenCoords(0,0,screenCoords.size()); + for(int y = 0; y <= virtualScreenCoords.height(); y += textureCoords.height()) { + for(int x = 0; x <= virtualScreenCoords.width(); x += textureCoords.width()) { + Rect partialCoords(x, y, textureCoords.size()); + Rect partialTextureCoords = textureCoords; + + // partialCoords to screenCoords bottomRight + if(partialCoords.bottom() > virtualScreenCoords.bottom()) { + partialTextureCoords.setBottom(partialTextureCoords.bottom() + (virtualScreenCoords.bottom() - partialCoords.bottom())); + partialCoords.setBottom(virtualScreenCoords.bottom()); + } + if(partialCoords.right() > virtualScreenCoords.right()) { + partialTextureCoords.setRight(partialTextureCoords.right() + (virtualScreenCoords.right() - partialCoords.right())); + partialCoords.setRight(virtualScreenCoords.right()); + } + + partialCoords.translate(screenCoords.topLeft()); + _drawTexturedRect(partialCoords, partialTextureCoords, textureSize); + } + } +} + + void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color) { glDisable(GL_TEXTURE_2D); @@ -250,3 +284,10 @@ void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, in resetColor(); } + +void Graphics::_drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth) +{ + glEnd(); + drawBoundingRect(screenCoords, color, innerLineWidth); + glBegin(GL_QUADS); +} diff --git a/src/framework/graphics.h b/src/framework/graphics.h index a61ab3e6..92fa133f 100644 --- a/src/framework/graphics.h +++ b/src/framework/graphics.h @@ -62,12 +62,15 @@ public: // high level rendering void drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords = Rect()); + void drawRepeatedTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords); void drawColoredRect(const Rect& screenCoords, const Color& color); void drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth = 1); // lower level rendering void _beginTextureRender(const Texture *texture); void _drawTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize); + void _drawRepeatedTexturedRect(const Rect& screenCoords, const Rect& textureCoords, const Size& textureSize); + void _drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth = 1); void _endTextureRender(); private: diff --git a/src/framework/textures.cpp b/src/framework/textures.cpp index f6b94f80..3fc3db3b 100644 --- a/src/framework/textures.cpp +++ b/src/framework/textures.cpp @@ -44,18 +44,20 @@ TexturePtr Textures::get(const std::string& textureFile) if(!texture) { // load texture // currently only png textures are supported if(!boost::ends_with(textureFile, ".png")) { - logError("Unable to load texture %s, file format no supported.", textureFile.c_str()); + logFatal("Unable to load texture %s, file format no supported.", textureFile.c_str()); return texture; } uint fileSize; uchar *textureFileData = g_resources.loadFile(textureFile, &fileSize); - if(!textureFileData) + if(!textureFileData) { + logFatal("Unable to load texture %s, file could not be read.", textureFile.c_str()); return texture; + } texture = TexturePtr(TextureLoader::loadPNG(textureFileData)); if(!texture) - logError("Unable to load texture %s, loading error.", textureFile.c_str()); + logFatal("Unable to load texture %s, loading error.", textureFile.c_str()); delete[] textureFileData; } diff --git a/src/framework/ui/uibutton.cpp b/src/framework/ui/uibutton.cpp index 3c858aea..cf84a620 100644 --- a/src/framework/ui/uibutton.cpp +++ b/src/framework/ui/uibutton.cpp @@ -23,4 +23,27 @@ #include "uibutton.h" +#include "../fonts.h" +#include "../font.h" +UIButton::UIButton(const std::string& text) : + m_text(text) +{ + m_boderedImage = BorderedImagePtr(new BorderedImage("ui.png")); + m_boderedImage->setTexCoords(Rect(45,139,1,18), + Rect(130,139,1,18), + Rect(46,138,84,1), + Rect(46,157,84,1), + Rect(45,138,1,1), + Rect(130,138,1,1), + Rect(45,157,1,1), + Rect(130,157,1,1), + Rect(46,139,84,18)); +} + +void UIButton::render() +{ + m_boderedImage->draw(m_rect); + + g_fonts.get("tibia-8px-antialised")->renderText(m_text, m_rect, ALIGN_CENTER); +} diff --git a/src/framework/ui/uibutton.h b/src/framework/ui/uibutton.h index ed57cddb..758340e9 100644 --- a/src/framework/ui/uibutton.h +++ b/src/framework/ui/uibutton.h @@ -27,13 +27,22 @@ #include "../prerequisites.h" #include "uielement.h" +#include "../borderedimage.h" class UIButton : public UIElement { public: - UIButton(UIContainerPtr parent) : UIElement(parent) { } + UIButton(const std::string& text); + + void render(); virtual UI::ControlType getControlType() const { return UI::Button; } + +private: + std::string m_text; + BorderedImagePtr m_boderedImage; }; +typedef std::shared_ptr UIButtonPtr; + #endif // UIBUTTON_H diff --git a/src/framework/ui/uicontainer.cpp b/src/framework/ui/uicontainer.cpp index f2e8f5de..92fba7c6 100644 --- a/src/framework/ui/uicontainer.cpp +++ b/src/framework/ui/uicontainer.cpp @@ -24,7 +24,7 @@ #include "uicontainer.h" -UIContainer g_gui; +UIContainerPtr g_gui(new UIContainer); void UIContainer::addChild(UIElementPtr child) { @@ -60,7 +60,7 @@ void UIContainer::setRect(const Rect& rect) { // update children rect for(auto it = m_children.begin(); it != m_children.end(); ++it) { - UIElementPtr child = (*it)->asUIElement(); + const UIElementPtr& child = (*it); // transforme child rect Rect childRect = child->getRect(); @@ -94,6 +94,24 @@ void UIContainer::moveTo(const Point& pos) } +void UIContainer::render() +{ + for(auto it = m_children.begin(); it != m_children.end(); ++it) { + const UIElementPtr& child = (*it); + child->render(); + } +} + +void UIContainer::update(int ticks, int elapsedTicks) +{ + +} + +bool UIContainer::onInputEvent(InputEvent* event) +{ + return false; +} + void UIContainer::setActiveElement(UIElementPtr activeElement) { diff --git a/src/framework/ui/uicontainer.h b/src/framework/ui/uicontainer.h index 2d332988..01c191bd 100644 --- a/src/framework/ui/uicontainer.h +++ b/src/framework/ui/uicontainer.h @@ -33,7 +33,7 @@ class UIContainer : public UIElement { public: - UIContainer(UIContainerPtr parent = UIContainerPtr()) : UIElement(parent) { } + UIContainer() : UIElement() { } virtual ~UIContainer() { } virtual void addChild(UIElementPtr child); @@ -45,15 +45,16 @@ public: virtual void move(const Point& trans); virtual void moveTo(const Point& pos); - virtual void render() { } - virtual void update(int ticks, int elapsedTicks) { } - virtual bool onInputEvent(InputEvent *event) { return false; } + virtual void render(); + virtual void update(int ticks, int elapsedTicks); + virtual bool onInputEvent(InputEvent *event); virtual void setActiveElement(UIElementPtr activeElement); UIElementPtr getActiveElement() const { return m_activeElement; } virtual UI::ControlType getControlType() const { return UI::Container; } - UIContainerPtr asUIContainer() { return UIContainerPtr(this); } + + UIContainerPtr asUIContainer() { return std::static_pointer_cast(shared_from_this()); } protected: std::list m_children; @@ -63,6 +64,6 @@ private: void onMove(const Point& pos); }; -extern UIContainer g_gui; +extern UIContainerPtr g_gui; #endif // UICONTAINER_H diff --git a/src/framework/ui/uielement.cpp b/src/framework/ui/uielement.cpp index af19f49c..506c860d 100644 --- a/src/framework/ui/uielement.cpp +++ b/src/framework/ui/uielement.cpp @@ -23,14 +23,3 @@ #include "uielement.h" -#include "uicontainer.h" - -UIElement::UIElement(UIContainerPtr parent) : - m_visible(true), - m_active(true) -{ - if(parent) - parent->addChild(asUIElement()); -} - - diff --git a/src/framework/ui/uielement.h b/src/framework/ui/uielement.h index 3ccc3426..cae845ff 100644 --- a/src/framework/ui/uielement.h +++ b/src/framework/ui/uielement.h @@ -36,10 +36,10 @@ typedef std::shared_ptr UIContainerPtr; class UIElement; typedef std::shared_ptr UIElementPtr; -class UIElement +class UIElement : public std::enable_shared_from_this { public: - UIElement(UIContainerPtr parent); + UIElement() { } virtual ~UIElement() { } virtual void render() { } @@ -63,7 +63,7 @@ public: virtual UI::ControlType getControlType() const { return UI::Element; } - UIElementPtr asUIElement() { return UIElementPtr(this); } + UIElementPtr asUIElement() { return shared_from_this(); } protected: UI::ControlType m_type; diff --git a/src/framework/ui/uilabel.h b/src/framework/ui/uilabel.h index 214766b4..c193d01f 100644 --- a/src/framework/ui/uilabel.h +++ b/src/framework/ui/uilabel.h @@ -31,7 +31,7 @@ class UILabel : public UIElement { public: - UILabel(UIContainerPtr parent) : UIElement(parent) { } + UILabel() { } virtual UI::ControlType getControlType() const { return UI::Label; } }; diff --git a/src/framework/ui/uipanel.cpp b/src/framework/ui/uipanel.cpp index f21ef43d..7339c517 100644 --- a/src/framework/ui/uipanel.cpp +++ b/src/framework/ui/uipanel.cpp @@ -24,3 +24,23 @@ #include "uipanel.h" + +UIPanel::UIPanel() +{ + m_boderedImage = BorderedImagePtr(new BorderedImage("ui.png")); + m_boderedImage->setTexCoords(Rect(0,214,5,32), + Rect(6,214,5,32), + Rect(43,214,32,5), + Rect(43,220,32,5), + Rect(43,225,5,5), + Rect(49,225,5,5), + Rect(43,230,5,5), + Rect(48,231,5,5), + Rect(11,214,32,32)); +} + +void UIPanel::render() +{ + m_boderedImage->draw(m_rect); + UIContainer::render(); +} diff --git a/src/framework/ui/uipanel.h b/src/framework/ui/uipanel.h index d70be61a..1535b14b 100644 --- a/src/framework/ui/uipanel.h +++ b/src/framework/ui/uipanel.h @@ -27,13 +27,21 @@ #include "../prerequisites.h" #include "uicontainer.h" +#include "../borderedimage.h" class UIPanel : public UIContainer { public: - UIPanel(UIContainerPtr parent) : UIContainer(parent) { } + UIPanel(); + + void render(); virtual UI::ControlType getControlType() const { return UI::Panel; } + +private: + BorderedImagePtr m_boderedImage; }; +typedef std::shared_ptr UIPanelPtr; + #endif // UIPANEL_H diff --git a/src/framework/x11platform.cpp b/src/framework/x11platform.cpp index 9455b685..6887249f 100644 --- a/src/framework/x11platform.cpp +++ b/src/framework/x11platform.cpp @@ -569,6 +569,10 @@ bool Platform::createWindow(int x, int y, int width, int height, int minWidth, i x11.width = width; x11.height = height; x11.maximizeOnFirstShow = maximized; + + // call first onResize + g_engine.onResize(Size(width, height)); + return true; } diff --git a/src/main.cpp b/src/main.cpp index e94ece8a..76106ff5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ #include "framework/platform.h" #include "menustate.h" #include "teststate.h" +#include "framework/dispatcher.h" /// Catches signals so we can exit nicely void signal_handler(int sig) @@ -111,7 +112,9 @@ int main(int argc, const char *argv[]) { std::shared_ptr initialState(new MenuState); //std::shared_ptr initialState(new TestState); - g_engine.changeState(initialState.get()); + g_dispatcher.addTask([&initialState]{ + g_engine.changeState(initialState.get()); + }); Platform::showWindow(); //Platform::hideMouseCursor(); diff --git a/src/menustate.cpp b/src/menustate.cpp index eea94691..0a10510e 100644 --- a/src/menustate.cpp +++ b/src/menustate.cpp @@ -34,25 +34,15 @@ #include "framework/dispatcher.h" #include "framework/ui/ui.h" #include "framework/net/connections.h" +#include "framework/borderedimage.h" + void MenuState::onEnter() { m_background = g_textures.get("background.png"); m_background->enableBilinearFilter(); - /* - UIPanelPtr panel(new UIPanel); - panel.setAnchorsLeft(g_gui.left()); - panel.setAnchorsBottom(g_gui.right()); - panel.setMarginBottom(10); - panel.setMarginLeft(10); - panel.setSize(Size(100, 100)); - - UIButtonPtr button(new UIButton); - button.setAnchorsHorizontalCenter(panel.horizontalCenter()); - button.setTop - g_gui.addChild(panel); - */ + createMainMenu(); } void MenuState::onLeave() @@ -70,6 +60,11 @@ void MenuState::onInputEvent(InputEvent* event) } +void MenuState::onResize(const Size& size) +{ + recalculateMenuPanelPosition(); +} + void MenuState::render() { // render background @@ -89,3 +84,50 @@ void MenuState::update(int ticks, int elapsedTicks) { } + +void MenuState::createMainMenu() +{ + UIButtonPtr button; + int y = 16; + + m_menuPanel = UIPanelPtr(new UIPanel); + recalculateMenuPanelPosition(); + + button = UIButtonPtr(new UIButton("Enter Game")); + button->setRect(Rect(16, y, 86, 20)); + m_menuPanel->addChild(button); + y += 30; + + button = UIButtonPtr(new UIButton("Access Account")); + button->setRect(Rect(16, y, 86, 20)); + m_menuPanel->addChild(button); + y += 30; + + button = UIButtonPtr(new UIButton("Options")); + button->setRect(Rect(16, y, 86, 20)); + m_menuPanel->addChild(button); + y += 30; + + button = UIButtonPtr(new UIButton("Info")); + button->setRect(Rect(16, y, 86, 20)); + m_menuPanel->addChild(button); + y += 30; + + button = UIButtonPtr(new UIButton("Exit Game")); + button->setRect(Rect(16, y, 86, 20)); + m_menuPanel->addChild(button); + y += 30; + + g_gui->addChild(m_menuPanel); +} + +void MenuState::recalculateMenuPanelPosition() +{ + if(m_menuPanel) { + // calculate panel rect + Size panelSize = Size(117, 171); + Rect panelRect = Rect(0, 0, panelSize); + panelRect.moveBottomLeft(Point(60, g_graphics.getScreenSize().height() - 70)); + m_menuPanel->setRect(panelRect); + } +} \ No newline at end of file diff --git a/src/menustate.h b/src/menustate.h index 6c310c00..74b1ddec 100644 --- a/src/menustate.h +++ b/src/menustate.h @@ -28,6 +28,7 @@ #include "framework/gamestate.h" #include "framework/texture.h" #include "framework/net/connection.h" +#include "framework/ui/uipanel.h" class MenuState : public GameState { @@ -35,16 +36,21 @@ class MenuState : public GameState public: MenuState() { } - virtual void onEnter(); - virtual void onLeave(); + void onEnter(); + void onLeave(); - virtual void onClose(); - virtual void onInputEvent(InputEvent *event); + void onClose(); + void onInputEvent(InputEvent *event); + void onResize(const Size& size); - virtual void render(); - virtual void update(int ticks, int elapsedTicks); + void render(); + void update(int ticks, int elapsedTicks); private: + void createMainMenu(); + void recalculateMenuPanelPosition(); + + UIPanelPtr m_menuPanel; TexturePtr m_background; }; diff --git a/src/teststate.cpp b/src/teststate.cpp index 4d160dc6..bb8555b2 100644 --- a/src/teststate.cpp +++ b/src/teststate.cpp @@ -48,6 +48,11 @@ void TestState::onInputEvent(InputEvent* event) } +void TestState::onResize(const Size& size) +{ + +} + void TestState::render() { diff --git a/src/teststate.h b/src/teststate.h index ac294069..7bab44c0 100644 --- a/src/teststate.h +++ b/src/teststate.h @@ -32,14 +32,15 @@ class TestState : public GameState public: TestState() { } - virtual void onEnter(); - virtual void onLeave(); + void onEnter(); + void onLeave(); - virtual void onClose(); - virtual void onInputEvent(InputEvent *event); + void onClose(); + void onInputEvent(InputEvent *event); + void onResize(const Size& size); - virtual void render(); - virtual void update(int ticks, int elapsedTicks); + void render(); + void update(int ticks, int elapsedTicks); }; #endif // TESTSTATE_H