// ---------------------------------------------------------------- // From Game Programming in C++ by Sanjay Madhav // Copyright (C) 2017 Sanjay Madhav. All rights reserved. // // Released under the BSD License // See LICENSE in root directory for full details. // ---------------------------------------------------------------- #include "UIScreen.h" #include "Texture.h" #include "Shader.h" #include "Game.h" #include "Renderer.h" #include "Font.h" UIScreen::UIScreen(Game* game) :mGame(game) ,mTitle(nullptr) ,mBackground(nullptr) ,mTitlePos(0.0f, 300.0f) ,mNextButtonPos(0.0f, 200.0f) ,mBGPos(0.0f, 250.0f) ,mState(EActive) { // Add to UI Stack mGame->PushUI(this); mFont = mGame->GetFont("Assets/Carlito-Regular.ttf"); mButtonOn = mGame->GetRenderer()->GetTexture("Assets/ButtonYellow.png"); mButtonOff = mGame->GetRenderer()->GetTexture("Assets/ButtonBlue.png"); } UIScreen::~UIScreen() { if (mTitle) { mTitle->Unload(); delete mTitle; } for (auto b : mButtons) { delete b; } mButtons.clear(); } void UIScreen::Update(float deltaTime) { } void UIScreen::Draw(Shader* shader) { // Draw background (if exists) if (mBackground) { DrawTexture(shader, mBackground, mBGPos); } // Draw title (if exists) if (mTitle) { DrawTexture(shader, mTitle, mTitlePos); } // Draw buttons for (auto b : mButtons) { // Draw background of button Texture* tex = b->GetHighlighted() ? mButtonOn : mButtonOff; DrawTexture(shader, tex, b->GetPosition()); // Draw text of button DrawTexture(shader, b->GetNameTex(), b->GetPosition()); } // Override in subclasses to draw any textures } void UIScreen::ProcessInput(const uint8_t* keys) { // Do we have buttons? if (!mButtons.empty()) { // Get position of mouse int x, y; SDL_GetMouseState(&x, &y); // Convert to (0,0) center coordinates Vector2 mousePos(static_cast(x), static_cast(y)); mousePos.x -= mGame->GetRenderer()->GetScreenWidth() * 0.5f; mousePos.y = mGame->GetRenderer()->GetScreenHeight() * 0.5f - mousePos.y; // Highlight any buttons for (auto b : mButtons) { if (b->ContainsPoint(mousePos)) { b->SetHighlighted(true); } else { b->SetHighlighted(false); } } } } void UIScreen::HandleKeyPress(int key) { switch (key) { case SDL_BUTTON_LEFT: if (!mButtons.empty()) { for (auto b : mButtons) { if (b->GetHighlighted()) { b->OnClick(); break; } } } break; default: break; } } void UIScreen::Close() { mState = EClosing; } void UIScreen::SetTitle(const std::string& text, const Vector3& color, int pointSize) { // Clear out previous title texture if it exists if (mTitle) { mTitle->Unload(); delete mTitle; mTitle = nullptr; } mTitle = mFont->RenderText(text, color, pointSize); } void UIScreen::AddButton(const std::string& name, std::function onClick) { Vector2 dims(static_cast(mButtonOn->GetWidth()), static_cast(mButtonOn->GetHeight())); Button* b = new Button(name, mFont, onClick, mNextButtonPos, dims); mButtons.emplace_back(b); // Update position of next button // Move down by height of button plus padding mNextButtonPos.y -= mButtonOff->GetHeight() + 20.0f; } void UIScreen::DrawTexture(class Shader* shader, class Texture* texture, const Vector2& offset, float scale, bool flipY) { // Scale the quad by the width/height of texture // and flip the y if we need to float yScale = static_cast(texture->GetHeight()) * scale; if (flipY) { yScale *= -1.0f; } Matrix4 scaleMat = Matrix4::CreateScale( static_cast(texture->GetWidth()) * scale, yScale, 1.0f); // Translate to position on screen Matrix4 transMat = Matrix4::CreateTranslation( Vector3(offset.x, offset.y, 0.0f)); // Set world transform Matrix4 world = scaleMat * transMat; shader->SetMatrixUniform("uWorldTransform", world); // Set current texture texture->SetActive(); // Draw quad glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } void UIScreen::SetRelativeMouseMode(bool relative) { if (relative) { SDL_SetRelativeMouseMode(SDL_TRUE); // Make an initial call to get relative to clear out SDL_GetRelativeMouseState(nullptr, nullptr); } else { SDL_SetRelativeMouseMode(SDL_FALSE); } } Button::Button(const std::string& name, Font* font, std::function onClick, const Vector2& pos, const Vector2& dims) :mOnClick(onClick) ,mNameTex(nullptr) ,mFont(font) ,mPosition(pos) ,mDimensions(dims) ,mHighlighted(false) { SetName(name); } Button::~Button() { if (mNameTex) { mNameTex->Unload(); delete mNameTex; } } void Button::SetName(const std::string& name) { mName = name; if (mNameTex) { mNameTex->Unload(); delete mNameTex; mNameTex = nullptr; } mNameTex = mFont->RenderText(mName); } bool Button::ContainsPoint(const Vector2& pt) const { bool no = pt.x < (mPosition.x - mDimensions.x / 2.0f) || pt.x > (mPosition.x + mDimensions.x / 2.0f) || pt.y < (mPosition.y - mDimensions.y / 2.0f) || pt.y > (mPosition.y + mDimensions.y / 2.0f); return !no; } void Button::OnClick() { // Call attached handler, if it exists if (mOnClick) { mOnClick(); } }