diff --git a/CMakeLists.txt b/CMakeLists.txt index d471265b5..64a542eb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextListComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.h ${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiBox.h @@ -167,6 +168,7 @@ set(ES_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ThemeComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiDetectDevice.cpp diff --git a/src/Renderer.h b/src/Renderer.h index f73f2939a..f70b8c83b 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -35,9 +35,9 @@ namespace Renderer void translatef(float x, float y); void translate(Vector2i offset); - void setClipRect(int x, int y, unsigned int w, unsigned int h); - void setClipRect(Vector2i offset, Vector2u size); - void clearClipRect(); + void pushClipRect(int x, int y, unsigned int w, unsigned int h); + void pushClipRect(Vector2i offset, Vector2u size); + void popClipRect(); void drawRect(int x, int y, int w, int h, unsigned int color); void drawText(std::string text, int x, int y, unsigned int color, Font* font); diff --git a/src/Renderer_draw_gl.cpp b/src/Renderer_draw_gl.cpp index d583bf2e4..22dcf4c1e 100644 --- a/src/Renderer_draw_gl.cpp +++ b/src/Renderer_draw_gl.cpp @@ -5,10 +5,13 @@ #include "Font.h" #include #include "Log.h" +#include namespace Renderer { bool loadedFonts = false; + std::stack clipStack; + void setColor4bArray(GLubyte* array, unsigned int color) { array[0] = (color & 0xff000000) / 0x1000000; @@ -36,20 +39,44 @@ namespace Renderer { translatef((float)offset.x, (float)offset.y); } - void setClipRect(int x, int y, unsigned int w, unsigned int h) + void pushClipRect(int x, int y, unsigned int w, unsigned int h) { - glScissor(x, y, w, h); + Rect rect(x, y, w, h); + if(rect.size.x == 0) + rect.size.x = Renderer::getScreenWidth() - rect.pos.x; + if(rect.size.y == 0) + rect.size.y = Renderer::getScreenHeight() - rect.pos.y; + + //glScissor starts at the bottom left of the window + //so (0, 0, 1, 1) is the bottom left pixel + //everything else uses y+ = down, so flip it to be consistent + rect.pos.y = Renderer::getScreenHeight() - rect.pos.y - rect.size.y; + + clipStack.push(rect); + glScissor(rect.pos.x, rect.pos.y, rect.size.x, rect.size.y); glEnable(GL_SCISSOR_TEST); } - void setClipRect(Vector2i offset, Vector2u size) + void pushClipRect(Vector2i pos, Vector2u size) { - setClipRect(offset.x, offset.y, size.x, size.y); + pushClipRect(pos.x, pos.y, size.x, size.y); } - void clearClipRect() + void popClipRect() { - glDisable(GL_SCISSOR_TEST); + if(clipStack.empty()) + { + LOG(LogError) << "Tried to popClipRect while the stack was empty!"; + return; + } + clipStack.pop(); + if(clipStack.empty()) + { + glDisable(GL_SCISSOR_TEST); + }else{ + Rect top = clipStack.top(); + glScissor(top.pos.x, top.pos.y, top.size.x, top.size.y); + } } void drawRect(int x, int y, int w, int h, unsigned int color) diff --git a/src/Vector2.h b/src/Vector2.h index 08e8b85b6..672c8ab3e 100644 --- a/src/Vector2.h +++ b/src/Vector2.h @@ -27,7 +27,6 @@ public: T y; }; - template Vector2 operator -(const Vector2& right) { @@ -95,4 +94,14 @@ typedef Vector2 Vector2i; typedef Vector2 Vector2u; typedef Vector2 Vector2f; +class Rect +{ +public: + Vector2i pos; + Vector2u size; + + Rect() {}; + Rect(int x, int y, unsigned int w, unsigned int h) : pos(x, y), size(w, h) {}; +}; + #endif diff --git a/src/components/AnimationComponent.cpp b/src/components/AnimationComponent.cpp index 3e071f6c1..31c4c327e 100644 --- a/src/components/AnimationComponent.cpp +++ b/src/components/AnimationComponent.cpp @@ -6,6 +6,8 @@ AnimationComponent::AnimationComponent() mMoveY = 0; mMoveSpeed = 0; mFadeRate = 0; + mOpacity = 0; + mAccumulator = 0; } void AnimationComponent::move(int x, int y, int speed) @@ -31,41 +33,46 @@ void AnimationComponent::fadeOut(int time) mFadeRate = -time; } +//this should really be fixed at the system loop level... void AnimationComponent::update(int deltaTime) { - float mult = deltaTime * 0.05f; - - if(mMoveX != 0 || mMoveY != 0) + mAccumulator += deltaTime; + while(mAccumulator >= ANIMATION_TICK_SPEED) { - int offsetx = (mMoveX > mMoveSpeed) ? mMoveSpeed : mMoveX; - int offsety = (mMoveY > mMoveSpeed) ? mMoveSpeed : mMoveY; + mAccumulator -= ANIMATION_TICK_SPEED; - offsetx = (int)(offsetx * mult); - offsety = (int)(offsety * mult); - - moveChildren(offsetx, offsety); - - mMoveX -= offsetx; - mMoveY -= offsety; - } - - if(mFadeRate != 0) - { - int opacity = (int)mOpacity + mFadeRate; - if(opacity > 255) + if(mMoveX != 0 || mMoveY != 0) { - mFadeRate = 0; - opacity = 255; + Vector2i offset(mMoveX, mMoveY); + if(abs(offset.x) > mMoveSpeed) + offset.x = mMoveSpeed * (offset.x > 0 ? 1 : -1); + if(abs(offset.y) > mMoveSpeed) + offset.y = mMoveSpeed * (offset.y > 0 ? 1 : -1); + + moveChildren(offset.x, offset.y); + + mMoveX -= offset.x; + mMoveY -= offset.y; } - if(opacity < 0) + if(mFadeRate != 0) { - mFadeRate = 0; - opacity = 0; - } + int opacity = (int)mOpacity + mFadeRate; + if(opacity > 255) + { + mFadeRate = 0; + opacity = 255; + } - mOpacity = (unsigned char)opacity; - setChildrenOpacity((unsigned char)opacity); + if(opacity < 0) + { + mFadeRate = 0; + opacity = 0; + } + + mOpacity = (unsigned char)opacity; + setChildrenOpacity((unsigned char)opacity); + } } } diff --git a/src/components/AnimationComponent.h b/src/components/AnimationComponent.h index f25c578e0..99cbd35b7 100644 --- a/src/components/AnimationComponent.h +++ b/src/components/AnimationComponent.h @@ -5,6 +5,8 @@ #include "ImageComponent.h" #include +#define ANIMATION_TICK_SPEED 16 + class AnimationComponent { public: @@ -28,6 +30,8 @@ private: int mFadeRate; int mMoveX, mMoveY, mMoveSpeed; + + int mAccumulator; }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 4b605f73e..9765a2cde 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -6,7 +6,12 @@ #include #include "../Log.h" -GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window) +Vector2i GuiGameList::getImagePos() +{ + return Vector2i((int)(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX")), (int)(Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"))); +} + +GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window), mDescription(window) { mDetailed = useDetail; @@ -19,7 +24,7 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window) { mList = new TextListComponent(mWindow, (int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")), Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, Renderer::getDefaultFont(Renderer::MEDIUM)); - mScreenshot = new ImageComponent(mWindow, (int)(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX")), (int)(Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY")), "", (unsigned int)mTheme->getFloat("gameImageWidth"), (unsigned int)mTheme->getFloat("gameImageHeight"), false); + mScreenshot = new ImageComponent(mWindow, getImagePos().x, getImagePos().y, "", (unsigned int)mTheme->getFloat("gameImageWidth"), (unsigned int)mTheme->getFloat("gameImageHeight"), false); mScreenshot->setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY")); mImageAnimation = new AnimationComponent(); @@ -30,6 +35,9 @@ GuiGameList::GuiGameList(Window* window, bool useDetail) : GuiComponent(window) mImageAnimation = NULL; } + mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12)); + mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), 0)); + setSystemId(0); } @@ -41,8 +49,9 @@ GuiGameList::~GuiGameList() { delete mImageAnimation; delete mScreenshot; - delete mTheme; } + + delete mTheme; } void GuiGameList::setSystemId(int id) @@ -86,18 +95,14 @@ void GuiGameList::render() //divider if(!mTheme->getBool("hideDividers")) Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF); - - //if we're not scrolling and we have selected a non-folder - if(!mList->isScrolling() && mList->getSelectedObject() && !mList->getSelectedObject()->isFolder()) - { - GameData* game = (GameData*)mList->getSelectedObject(); - - std::string desc = game->getDescription(); - if(!desc.empty()) - Renderer::drawWrappedText(desc, (int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12, (int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), mTheme->getColor("description"), mTheme->getDescriptionFont()); - } - + mScreenshot->render(); + + //if we're not scrolling and we have selected a non-folder + if(!mList->isScrolling() && !mList->getSelectedObject()->isFolder()) + { + mDescription.render(); + } } mList->render(); @@ -118,6 +123,7 @@ bool GuiGameList::input(InputConfig* config, Input input) mFolderStack.push(mFolder); mFolder = (FolderData*)file; updateList(); + updateDetailData(); return true; }else{ mList->stopScrolling(); @@ -251,6 +257,9 @@ void GuiGameList::updateTheme() mScreenshot->setOffset((int)(mTheme->getFloat("gameImageOffsetX") * Renderer::getScreenWidth()), (int)(mTheme->getFloat("gameImageOffsetY") * Renderer::getScreenHeight())); mScreenshot->setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY")); mScreenshot->setResize((int)mTheme->getFloat("gameImageWidth"), (int)mTheme->getFloat("gameImageHeight"), false); + + mDescription.setColor(mTheme->getColor("description")); + mDescription.setFont(mTheme->getDescriptionFont()); } } @@ -261,15 +270,19 @@ void GuiGameList::updateDetailData() if(mList->getSelectedObject() && !mList->getSelectedObject()->isFolder()) { - mScreenshot->setOffset((int)((mTheme->getFloat("gameImageOffsetX") - 0.05) * Renderer::getScreenWidth()), (int)(mTheme->getFloat("gameImageOffsetY") * Renderer::getScreenHeight())); - if(((GameData*)mList->getSelectedObject())->getImagePath().empty()) mScreenshot->setImage(mTheme->getString("imageNotFoundPath")); else mScreenshot->setImage(((GameData*)mList->getSelectedObject())->getImagePath()); - mImageAnimation->fadeIn(15); - mImageAnimation->move((int)(0.05 * Renderer::getScreenWidth()), 0, 5); + Vector2i imgOffset = Vector2i((int)(Renderer::getScreenWidth() * 0.10f), 0); + mScreenshot->setOffset(getImagePos() - imgOffset); + + mImageAnimation->fadeIn(35); + mImageAnimation->move(imgOffset.x, imgOffset.y, 20); + + mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), mScreenshot->getOffset().y + mScreenshot->getSize().y + 12)); + mDescription.setText(((GameData*)mList->getSelectedObject())->getDescription()); }else{ mScreenshot->setImage(""); } diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index 7a083b607..29e16a713 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -6,6 +6,7 @@ #include "ImageComponent.h" #include "ThemeComponent.h" #include "AnimationComponent.h" +#include "TextComponent.h" #include #include #include "../SystemData.h" @@ -13,7 +14,7 @@ #include "../FolderData.h" //This is where the magic happens - GuiGameList is the parent of almost every graphical element in ES at the moment. -//It has a GuiList child that handles the game list, a GuiTheme that handles the theming system, and a GuiImage for game images. +//It has a TextListComponent child that handles the game list, a ThemeComponent that handles the theming system, and an ImageComponent for game images. class GuiGameList : public GuiComponent { public: @@ -48,8 +49,11 @@ private: TextListComponent* mList; ImageComponent* mScreenshot; + TextComponent mDescription; AnimationComponent* mImageAnimation; ThemeComponent* mTheme; + + Vector2i getImagePos(); }; #endif diff --git a/src/components/TextComponent.cpp b/src/components/TextComponent.cpp new file mode 100644 index 000000000..af707ec21 --- /dev/null +++ b/src/components/TextComponent.cpp @@ -0,0 +1,59 @@ +#include "TextComponent.h" +#include "../Renderer.h" +#include "../Log.h" + +TextComponent::TextComponent(Window* window) : GuiComponent(window), mFont(NULL), mColor(0x000000FF) +{ +} + +TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window), + mFont(NULL), mColor(0x000000FF) +{ + setText(text); + setFont(font); + setBox(pos, size); +} + +void TextComponent::setBox(Vector2i pos, Vector2u size) +{ + setOffset(pos); + setExtent(size); +} + +void TextComponent::setExtent(Vector2u size) +{ + mSize = size; +} + +void TextComponent::setFont(Font* font) +{ + mFont = font; +} + +void TextComponent::setColor(unsigned int color) +{ + mColor = color; +} + +void TextComponent::setText(const std::string& text) +{ + mText = text; +} + +void TextComponent::onRender() +{ + Font* font = (mFont ? mFont : Renderer::getDefaultFont(Renderer::MEDIUM)); + if(font == NULL) + { + LOG(LogError) << "TextComponent can't get a valid font!"; + return; + } + + Renderer::pushClipRect(getOffset(), getSize()); + + Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor, font); + + Renderer::popClipRect(); + + GuiComponent::onRender(); +} diff --git a/src/components/TextComponent.h b/src/components/TextComponent.h new file mode 100644 index 000000000..c66e59ac0 --- /dev/null +++ b/src/components/TextComponent.h @@ -0,0 +1,27 @@ +#ifndef _TEXTCOMPONENT_H_ +#define _TEXTCOMPONENT_H_ + +#include "../GuiComponent.h" +#include "../Font.h" + +class TextComponent : public GuiComponent +{ +public: + TextComponent(Window* window); + TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size); + + void setFont(Font* font); + void setBox(Vector2i pos, Vector2u size); + void setExtent(Vector2u size); + void setText(const std::string& text); + void setColor(unsigned int color); + + void onRender(); + +private: + unsigned int mColor; + Font* mFont; + std::string mText; +}; + +#endif diff --git a/src/components/TextListComponent.h b/src/components/TextListComponent.h index a60b008e9..b3bdbb057 100644 --- a/src/components/TextListComponent.h +++ b/src/components/TextListComponent.h @@ -141,6 +141,8 @@ void TextListComponent::onRender() if(listCutoff > (int)mRowVector.size()) listCutoff = mRowVector.size(); + Renderer::pushClipRect(getOffset(), getSize()); + for(int i = startEntry; i < listCutoff; i++) { //draw selector bar @@ -154,18 +156,16 @@ void TextListComponent::onRender() int x = mTextOffsetX - (mSelection == i ? mMarqueeOffset : 0); unsigned int color = (mSelection == i && mSelectedTextColorOverride != 0) ? mSelectedTextColorOverride : row.color; - Renderer::setClipRect(getOffset(), getSize()); - if(mDrawCentered) Renderer::drawCenteredText(row.name, x, y, color, mFont); else Renderer::drawText(row.name, x, y, color, mFont); - Renderer::clearClipRect(); - y += entrySize; } + Renderer::popClipRect(); + GuiComponent::onRender(); }