<commit_before>#include "Tetris/States/GameState.hpp"

#include <iostream>
#include <sstream>
#include <iomanip>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>

#include "Tetris/App.hpp"
#include "Tetris/Utils.hpp"
#include "Tetris/Game/Tetris.hpp"
#include "Tetris/GameObjects/Tetromino.hpp"
#include "Tetris/GameObjects/GameArea.hpp"
#include "Tetris/GameObjects/GameMenu.hpp"

using namespace tetris::game;

namespace tetris {
namespace states {

struct GameState::Impl {
    tetris::game::Tetris world{};
    tetris::gameobjects::Tetromino tetrominoObject{};
    tetris::gameobjects::Tetromino nextTetrominoObject{};
    tetris::gameobjects::GameArea gameAreaObject{};
    tetris::gameobjects::GameMenu gameMenu{};

    sf::Sprite gridSprite{};
    sf::RectangleShape gameAreaShape{};
    sf::RectangleShape backgroundShape{};
    sf::RectangleShape nextShape{};

    sf::Text highScoreText{};
    sf::Text highScoreValueText{};
    sf::Text scoreText{};
    sf::Text scoreValueText{};
    sf::Text nextText{};
    std::array<sf::Text, 3> infoText{};

    sf::Color defaultFontColor{255, 255, 255};
    sf::Color backgroundShapeColor{254,127,45};
    sf::Color gameAreaShapeColor{253,226,154};
    sf::Color nextShapeColor{252,202,70};
    int defaultFontSize{28};
    int uiCenterPosition{448};
    sf::Vector2f aux{};

    sf::Clock clock{};
    float deltaTime{0.0f};
    bool paused{false};
    bool restart{false};
};

GameState::GameState(App& app)
    : DefaultState(app) {}
GameState::~GameState() = default;

void GameState::create() {
    using namespace tetris::utils;

    impl_ = std::make_unique<Impl>();

    auto& app = getApp();
    auto& assets = app.getAssets();

    auto& defaultFont = assets.getDefaultFont();

    impl_->gridSprite.setTexture(assets.getGrid());

    impl_->gameAreaShape.setSize({
        App::TILE_SIZE * Tetris::WORLD_WIDTH,
        App::TILE_SIZE * Tetris::WORLD_HEIGHT
    });
    impl_->gameAreaShape.setPosition(0, 0);
    impl_->gameAreaShape.setFillColor(impl_->gameAreaShapeColor);

    impl_->backgroundShape.setSize({
        App::WINDOW_WIDTH, App::WINDOW_HEIGHT
    });
    impl_->backgroundShape.setPosition(0, 0);
    impl_->backgroundShape.setFillColor(impl_->backgroundShapeColor);

    impl_->nextShape.setSize({128, 128});
    impl_->nextShape.setPosition(384, App::TILE_SIZE*13);
    impl_->nextShape.setFillColor(impl_->nextShapeColor);

    setupGameMenu();
    setupScores();

    int infoTextSize = static_cast<int>(impl_->infoText.size());
    int infoTextBaseY = 240;
    for (int i = 0; i < infoTextSize; ++i) {
        auto& text = impl_->infoText[i];
        text.setFont(defaultFont);
        text.setCharacterSize(impl_->defaultFontSize);
        text.setFillColor(impl_->defaultFontColor);
        switch (i) {
            case 0:
                text.setString("Press");
                break;
            case 1:
                text.setString("Enter to");
                break;
            case 2:
                text.setString("menu");
                break;
        }
        impl_->aux = tetris::utils::calculateCenterOfRect(
                text.getLocalBounds());
        text.setOrigin(impl_->aux);
        text.setPosition(impl_->uiCenterPosition, infoTextBaseY + 32 * i);
    }

    impl_->nextText.setFont(defaultFont);
    impl_->nextText.setCharacterSize(impl_->defaultFontSize);
    impl_->nextText.setFillColor(impl_->defaultFontColor);
    impl_->nextText.setString("NEXT");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->nextText.getLocalBounds());
    impl_->nextText.setOrigin(impl_->aux);
    impl_->nextText.setPosition(impl_->uiCenterPosition, 400);

    auto& eraseLinesSound = assets.getEraseLinesSound();
    impl_->world.linesErasedCallback = [&] () {
        eraseLinesSound.play();
    };
    auto& fitTetrominoSound = assets.getFitTetrominoSound();
    impl_->world.placedTetrominoCallback = [&] () {
        fitTetrominoSound.play();
    };

    setupBlockRenderers();
    impl_->world.create();
}

void GameState::destroy() {
    impl_->world.destroy();
}

void GameState::restart() {
    destroy();
    create();
}

void GameState::beginTick() {
    impl_->deltaTime = impl_->clock.restart().asSeconds();
}

void GameState::processEvent(const sf::Event& event) {
    DefaultState::processEvent(event);

    if (event.type == sf::Event::KeyPressed) {
        if (event.key.code == sf::Keyboard::Left) {
            impl_->world.setInputMovement(Tetris::InputDirection::LEFT);
        } else if (event.key.code == sf::Keyboard::Right) {
            impl_->world.setInputMovement(Tetris::InputDirection::RIGHT);
        }
        if (event.key.code == sf::Keyboard::Z) {
            impl_->world.setInputRotation(Tetris::InputDirection::LEFT);
        } else if (event.key.code == sf::Keyboard::X) {
            impl_->world.setInputRotation(Tetris::InputDirection::RIGHT);
        }
        if (event.key.code == sf::Keyboard::Return) {
            if (impl_->paused) {
                enum { RESUME, RETRY, QUIT };
                int selected = impl_->gameMenu.getSelected();
                switch (selected) {
                    case RETRY:
                        impl_->restart = true;
                        break;
                    case QUIT:
                        getApp().exit();
                        break;
                }
            }

            impl_->paused = !impl_->paused;
            impl_->gameMenu.setActive(impl_->paused);
        }
        if (impl_->paused) {
            if (event.key.code == sf::Keyboard::Up) {
                impl_->gameMenu.previous();
            } else if (event.key.code == sf::Keyboard::Down) {
                impl_->gameMenu.next();
            }
        }
    }
}

void GameState::update() {
    if (!impl_->paused) {
        impl_->world.setFastFall(sf::Keyboard::isKeyPressed(sf::Keyboard::Down));
        impl_->world.update(impl_->deltaTime);
    }
}

void GameState::render(sf::RenderTarget& renderTarget) {
    renderTarget.draw(impl_->backgroundShape);
    renderTarget.draw(impl_->gameAreaShape);
    renderTarget.draw(impl_->gridSprite);
    renderTarget.draw(impl_->nextShape);
    renderTarget.draw(impl_->highScoreText);
    renderTarget.draw(impl_->highScoreValueText);
    renderTarget.draw(impl_->scoreText);
    renderTarget.draw(impl_->scoreValueText);
    for (auto& info : impl_->infoText) {
        renderTarget.draw(info);
    }
    renderTarget.draw(impl_->nextText);

    renderTarget.draw(impl_->tetrominoObject);
    renderTarget.draw(impl_->nextTetrominoObject);
    renderTarget.draw(impl_->gameAreaObject);
    renderTarget.draw(impl_->gameMenu);
}

void GameState::endTick() {
    if (impl_->restart) {
        restart();
    }
}

void GameState::setupGameMenu() {
    auto& defaultFont = getApp().getAssets().getDefaultFont();

    impl_->gameMenu.setOptions({"RESUME", "RETRY", "QUIT"});
    impl_->gameMenu.setFont(defaultFont);
    impl_->gameMenu.setCharacterSize(impl_->defaultFontSize);
    impl_->gameMenu.setWidth(App::TILE_SIZE*5);
    impl_->gameMenu.setPadding(App::TILE_SIZE / 2.0f, App::TILE_SIZE / 2.0f,
                               App::TILE_SIZE / 2.0f, App::TILE_SIZE / 2.0f);
    impl_->gameMenu.setLineSpacing(impl_->defaultFontSize/2);
    impl_->gameMenu.setBackgroundColor(impl_->backgroundShapeColor);
    impl_->gameMenu.setForegroundColor(impl_->defaultFontColor);
    impl_->gameMenu.setSelectColor(impl_->nextShapeColor);
    impl_->gameMenu.setPosition({5*App::TILE_SIZE, 9*App::TILE_SIZE});
    impl_->gameMenu.create();
    impl_->gameMenu.setActive(false);
}

void GameState::setupScores() {
    auto& assets = getApp().getAssets();
    auto& defaultFont = assets.getDefaultFont();

    impl_->highScoreText.setFont(defaultFont);
    impl_->highScoreText.setCharacterSize(impl_->defaultFontSize);
    impl_->highScoreText.setFillColor(impl_->defaultFontColor);
    impl_->highScoreText.setString("HI-SCORE");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->highScoreText.getLocalBounds());
    impl_->highScoreText.setOrigin(impl_->aux);
    impl_->highScoreText.setPosition(impl_->uiCenterPosition, 49);

    impl_->highScoreValueText.setFont(defaultFont);
    impl_->highScoreValueText.setCharacterSize(impl_->defaultFontSize);
    impl_->highScoreValueText.setFillColor(impl_->defaultFontColor);
    impl_->highScoreValueText.setString("00000000");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->highScoreValueText.getLocalBounds());
    impl_->highScoreValueText.setOrigin(impl_->aux);
    impl_->highScoreValueText.setPosition(impl_->uiCenterPosition, 80);

    impl_->scoreText.setFont(defaultFont);
    impl_->scoreText.setCharacterSize(impl_->defaultFontSize);
    impl_->scoreText.setFillColor(impl_->defaultFontColor);
    impl_->scoreText.setString("SCORE");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->scoreText.getLocalBounds());
    impl_->scoreText.setOrigin(impl_->aux);
    impl_->scoreText.setPosition(impl_->uiCenterPosition, 112);

    impl_->scoreValueText.setFont(defaultFont);
    impl_->scoreValueText.setCharacterSize(impl_->defaultFontSize);
    impl_->scoreValueText.setFillColor(impl_->defaultFontColor);
    impl_->scoreValueText.setString("00000000");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->scoreValueText.getLocalBounds());
    impl_->scoreValueText.setOrigin(impl_->aux);
    impl_->scoreValueText.setPosition(impl_->uiCenterPosition, 144);

    impl_->world.scoreUpdatedCallback = [&] (const int score) {
        std::ostringstream buf;
        buf << std::setfill('0') << std::setw(8);
        buf << score;
        impl_->scoreValueText.setString(buf.str());
    };
    impl_->world.highScoreUpdatedCallback = [&] (const int highScore) {
        std::ostringstream buf;
        buf << std::setfill('0') << std::setw(8);
        buf << highScore;
        impl_->highScoreValueText.setString(buf.str());
    };
}

void GameState::setupBlockRenderers() {
    auto& blockTexture = getApp().getAssets().getBlock();

    impl_->tetrominoObject.create(blockTexture);
    impl_->world.tetrominoUpdatedCallback = [&] (const Tetromino& tetromino) {
        impl_->tetrominoObject.updateTetromino(tetromino);
    };

    impl_->nextTetrominoObject.create(blockTexture);
    impl_->nextTetrominoObject.setPosition(416, 480);
    impl_->world.nextTetrominoCallback = [&] (const Tetromino& tetromino) {
        impl_->nextTetrominoObject.updateTetromino(tetromino);
    };

    impl_->gameAreaObject.create(blockTexture);
    impl_->world.worldUpdatedCallback = [&] (const Tetris::WorldBlockArray& blocks) {
        impl_->gameAreaObject.updateWorld(blocks);
    };
}

} /* namespace states */
} /* namespace tetris */
<commit_msg>Add menu open sound<commit_after>#include "Tetris/States/GameState.hpp"

#include <iostream>
#include <sstream>
#include <iomanip>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>

#include "Tetris/App.hpp"
#include "Tetris/Utils.hpp"
#include "Tetris/Game/Tetris.hpp"
#include "Tetris/GameObjects/Tetromino.hpp"
#include "Tetris/GameObjects/GameArea.hpp"
#include "Tetris/GameObjects/GameMenu.hpp"

using namespace tetris::game;

namespace tetris {
namespace states {

struct GameState::Impl {
    tetris::game::Tetris world{};
    tetris::gameobjects::Tetromino tetrominoObject{};
    tetris::gameobjects::Tetromino nextTetrominoObject{};
    tetris::gameobjects::GameArea gameAreaObject{};
    tetris::gameobjects::GameMenu gameMenu{};

    sf::Sprite gridSprite{};
    sf::RectangleShape gameAreaShape{};
    sf::RectangleShape backgroundShape{};
    sf::RectangleShape nextShape{};

    sf::Text highScoreText{};
    sf::Text highScoreValueText{};
    sf::Text scoreText{};
    sf::Text scoreValueText{};
    sf::Text nextText{};
    std::array<sf::Text, 3> infoText{};

    sf::Color defaultFontColor{255, 255, 255};
    sf::Color backgroundShapeColor{254,127,45};
    sf::Color gameAreaShapeColor{253,226,154};
    sf::Color nextShapeColor{252,202,70};
    int defaultFontSize{28};
    int uiCenterPosition{448};
    sf::Vector2f aux{};

    sf::Clock clock{};
    float deltaTime{0.0f};
    bool paused{false};
    bool restart{false};
};

GameState::GameState(App& app)
    : DefaultState(app) {}
GameState::~GameState() = default;

void GameState::create() {
    using namespace tetris::utils;

    impl_ = std::make_unique<Impl>();

    auto& app = getApp();
    auto& assets = app.getAssets();

    auto& defaultFont = assets.getDefaultFont();

    impl_->gridSprite.setTexture(assets.getGrid());

    impl_->gameAreaShape.setSize({
        App::TILE_SIZE * Tetris::WORLD_WIDTH,
        App::TILE_SIZE * Tetris::WORLD_HEIGHT
    });
    impl_->gameAreaShape.setPosition(0, 0);
    impl_->gameAreaShape.setFillColor(impl_->gameAreaShapeColor);

    impl_->backgroundShape.setSize({
        App::WINDOW_WIDTH, App::WINDOW_HEIGHT
    });
    impl_->backgroundShape.setPosition(0, 0);
    impl_->backgroundShape.setFillColor(impl_->backgroundShapeColor);

    impl_->nextShape.setSize({128, 128});
    impl_->nextShape.setPosition(384, App::TILE_SIZE*13);
    impl_->nextShape.setFillColor(impl_->nextShapeColor);

    setupGameMenu();
    setupScores();

    int infoTextSize = static_cast<int>(impl_->infoText.size());
    int infoTextBaseY = 240;
    for (int i = 0; i < infoTextSize; ++i) {
        auto& text = impl_->infoText[i];
        text.setFont(defaultFont);
        text.setCharacterSize(impl_->defaultFontSize);
        text.setFillColor(impl_->defaultFontColor);
        switch (i) {
            case 0:
                text.setString("Press");
                break;
            case 1:
                text.setString("Enter to");
                break;
            case 2:
                text.setString("menu");
                break;
        }
        impl_->aux = tetris::utils::calculateCenterOfRect(
                text.getLocalBounds());
        text.setOrigin(impl_->aux);
        text.setPosition(impl_->uiCenterPosition, infoTextBaseY + 32 * i);
    }

    impl_->nextText.setFont(defaultFont);
    impl_->nextText.setCharacterSize(impl_->defaultFontSize);
    impl_->nextText.setFillColor(impl_->defaultFontColor);
    impl_->nextText.setString("NEXT");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->nextText.getLocalBounds());
    impl_->nextText.setOrigin(impl_->aux);
    impl_->nextText.setPosition(impl_->uiCenterPosition, 400);

    auto& eraseLinesSound = assets.getEraseLinesSound();
    impl_->world.linesErasedCallback = [&] () {
        eraseLinesSound.play();
    };
    auto& fitTetrominoSound = assets.getFitTetrominoSound();
    impl_->world.placedTetrominoCallback = [&] () {
        fitTetrominoSound.play();
    };

    setupBlockRenderers();
    impl_->world.create();
}

void GameState::destroy() {
    impl_->world.destroy();
}

void GameState::restart() {
    destroy();
    create();
}

void GameState::beginTick() {
    impl_->deltaTime = impl_->clock.restart().asSeconds();
}

void GameState::processEvent(const sf::Event& event) {
    DefaultState::processEvent(event);

    if (event.type == sf::Event::KeyPressed) {
        if (event.key.code == sf::Keyboard::Left) {
            impl_->world.setInputMovement(Tetris::InputDirection::LEFT);
        } else if (event.key.code == sf::Keyboard::Right) {
            impl_->world.setInputMovement(Tetris::InputDirection::RIGHT);
        }
        if (event.key.code == sf::Keyboard::Z) {
            impl_->world.setInputRotation(Tetris::InputDirection::LEFT);
        } else if (event.key.code == sf::Keyboard::X) {
            impl_->world.setInputRotation(Tetris::InputDirection::RIGHT);
        }
        if (event.key.code == sf::Keyboard::Return) {
            if (impl_->paused) {
                enum { RESUME, RETRY, QUIT };
                int selected = impl_->gameMenu.getSelected();
                switch (selected) {
                    case RETRY:
                        impl_->restart = true;
                        break;
                    case QUIT:
                        getApp().exit();
                        break;
                }
            } else {
                auto& menuOpenSound = getApp().getAssets().getMenuOpenSound();
                menuOpenSound.play();
            }

            impl_->paused = !impl_->paused;
            impl_->gameMenu.setActive(impl_->paused);
        }
        if (impl_->paused) {
            if (event.key.code == sf::Keyboard::Up) {
                impl_->gameMenu.previous();
            } else if (event.key.code == sf::Keyboard::Down) {
                impl_->gameMenu.next();
            }
        }
    }
}

void GameState::update() {
    if (!impl_->paused) {
        impl_->world.setFastFall(sf::Keyboard::isKeyPressed(sf::Keyboard::Down));
        impl_->world.update(impl_->deltaTime);
    }
}

void GameState::render(sf::RenderTarget& renderTarget) {
    renderTarget.draw(impl_->backgroundShape);
    renderTarget.draw(impl_->gameAreaShape);
    renderTarget.draw(impl_->gridSprite);
    renderTarget.draw(impl_->nextShape);
    renderTarget.draw(impl_->highScoreText);
    renderTarget.draw(impl_->highScoreValueText);
    renderTarget.draw(impl_->scoreText);
    renderTarget.draw(impl_->scoreValueText);
    for (auto& info : impl_->infoText) {
        renderTarget.draw(info);
    }
    renderTarget.draw(impl_->nextText);

    renderTarget.draw(impl_->tetrominoObject);
    renderTarget.draw(impl_->nextTetrominoObject);
    renderTarget.draw(impl_->gameAreaObject);
    renderTarget.draw(impl_->gameMenu);
}

void GameState::endTick() {
    if (impl_->restart) {
        restart();
    }
}

void GameState::setupGameMenu() {
    auto& defaultFont = getApp().getAssets().getDefaultFont();

    impl_->gameMenu.setOptions({"RESUME", "RETRY", "QUIT"});
    impl_->gameMenu.setFont(defaultFont);
    impl_->gameMenu.setCharacterSize(impl_->defaultFontSize);
    impl_->gameMenu.setWidth(App::TILE_SIZE*5);
    impl_->gameMenu.setPadding(App::TILE_SIZE / 2.0f, App::TILE_SIZE / 2.0f,
                               App::TILE_SIZE / 2.0f, App::TILE_SIZE / 2.0f);
    impl_->gameMenu.setLineSpacing(impl_->defaultFontSize/2);
    impl_->gameMenu.setBackgroundColor(impl_->backgroundShapeColor);
    impl_->gameMenu.setForegroundColor(impl_->defaultFontColor);
    impl_->gameMenu.setSelectColor(impl_->nextShapeColor);
    impl_->gameMenu.setPosition({5*App::TILE_SIZE, 9*App::TILE_SIZE});
    impl_->gameMenu.create();
    impl_->gameMenu.setActive(false);
}

void GameState::setupScores() {
    auto& assets = getApp().getAssets();
    auto& defaultFont = assets.getDefaultFont();

    impl_->highScoreText.setFont(defaultFont);
    impl_->highScoreText.setCharacterSize(impl_->defaultFontSize);
    impl_->highScoreText.setFillColor(impl_->defaultFontColor);
    impl_->highScoreText.setString("HI-SCORE");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->highScoreText.getLocalBounds());
    impl_->highScoreText.setOrigin(impl_->aux);
    impl_->highScoreText.setPosition(impl_->uiCenterPosition, 49);

    impl_->highScoreValueText.setFont(defaultFont);
    impl_->highScoreValueText.setCharacterSize(impl_->defaultFontSize);
    impl_->highScoreValueText.setFillColor(impl_->defaultFontColor);
    impl_->highScoreValueText.setString("00000000");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->highScoreValueText.getLocalBounds());
    impl_->highScoreValueText.setOrigin(impl_->aux);
    impl_->highScoreValueText.setPosition(impl_->uiCenterPosition, 80);

    impl_->scoreText.setFont(defaultFont);
    impl_->scoreText.setCharacterSize(impl_->defaultFontSize);
    impl_->scoreText.setFillColor(impl_->defaultFontColor);
    impl_->scoreText.setString("SCORE");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->scoreText.getLocalBounds());
    impl_->scoreText.setOrigin(impl_->aux);
    impl_->scoreText.setPosition(impl_->uiCenterPosition, 112);

    impl_->scoreValueText.setFont(defaultFont);
    impl_->scoreValueText.setCharacterSize(impl_->defaultFontSize);
    impl_->scoreValueText.setFillColor(impl_->defaultFontColor);
    impl_->scoreValueText.setString("00000000");
    impl_->aux = tetris::utils::calculateCenterOfRect(
            impl_->scoreValueText.getLocalBounds());
    impl_->scoreValueText.setOrigin(impl_->aux);
    impl_->scoreValueText.setPosition(impl_->uiCenterPosition, 144);

    impl_->world.scoreUpdatedCallback = [&] (const int score) {
        std::ostringstream buf;
        buf << std::setfill('0') << std::setw(8);
        buf << score;
        impl_->scoreValueText.setString(buf.str());
    };
    impl_->world.highScoreUpdatedCallback = [&] (const int highScore) {
        std::ostringstream buf;
        buf << std::setfill('0') << std::setw(8);
        buf << highScore;
        impl_->highScoreValueText.setString(buf.str());
    };
}

void GameState::setupBlockRenderers() {
    auto& blockTexture = getApp().getAssets().getBlock();

    impl_->tetrominoObject.create(blockTexture);
    impl_->world.tetrominoUpdatedCallback = [&] (const Tetromino& tetromino) {
        impl_->tetrominoObject.updateTetromino(tetromino);
    };

    impl_->nextTetrominoObject.create(blockTexture);
    impl_->nextTetrominoObject.setPosition(416, 480);
    impl_->world.nextTetrominoCallback = [&] (const Tetromino& tetromino) {
        impl_->nextTetrominoObject.updateTetromino(tetromino);
    };

    impl_->gameAreaObject.create(blockTexture);
    impl_->world.worldUpdatedCallback = [&] (const Tetris::WorldBlockArray& blocks) {
        impl_->gameAreaObject.updateWorld(blocks);
    };
}

} /* namespace states */
} /* namespace tetris */
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Collapsible widget
//==============================================================================

#include "collapsiblewidget.h"
#include "coreguiutils.h"

//==============================================================================

#include <Qt>

//==============================================================================

#include <QLayout>
#include <QSettings>
#include <QToolButton>
#include <QVariant>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

CollapsibleHeaderTitleWidget::CollapsibleHeaderTitleWidget(QWidget *pParent) :
    QLabel(pParent)
{
}

//==============================================================================

void CollapsibleHeaderTitleWidget::mouseDoubleClickEvent(QMouseEvent *pEvent)
{
    // Default handling of the event

    QLabel::mouseDoubleClickEvent(pEvent);

    // Let people know that the widget has been double clicked

    emit doubleClicked();
}

//==============================================================================

CollapsibleHeaderWidget::CollapsibleHeaderWidget(const QColor &pSeparatorColor,
                                                 const bool &pCollapsible,
                                                 QWidget *pParent) :
    QWidget(pParent),
    mCollapsed(false),
    mLastHeader(false)
{
    // Create our main (vertical) layout

    QVBoxLayout *layout = new QVBoxLayout(this);

    layout->setMargin(0);
    layout->setSpacing(0);

    setLayout(layout);

    // Create a sub-widget with a horizontal layout

    QWidget *subWidget = new QWidget(this);
    QHBoxLayout *subLayout = new QHBoxLayout(subWidget);

    subLayout->setMargin(0);
    subLayout->setSpacing(0);

    subWidget->setLayout(subLayout);

    QColor windowColor = Core::windowColor();

    setStyleSheet(QString("QWidget {"
                          "    background: rgb(%1, %2, %3);"
                          "}").arg(QString::number(windowColor.red()),
                                   QString::number(windowColor.green()),
                                   QString::number(windowColor.blue())));

    // Create and customise our button and title

    mButton = new QToolButton(subWidget);
    mTitle  = new CollapsibleHeaderTitleWidget(subWidget);

    int iconSize = 0.4*mTitle->height();

    mButton->setIcon(pCollapsible?QIcon(":/oxygen/actions/arrow-down.png"):QIcon());
    mButton->setIconSize(QSize(iconSize, iconSize));
    mButton->setStyleSheet("QToolButton {"
                           "    border: 0px;"
                           "}"
                           ""
                           "QToolButton:pressed {"
                           "    margin: 0px;"
                           "}");

    mTitle->setAlignment(Qt::AlignCenter);

    // Add our button and title to our sub-layout

    subLayout->addWidget(mButton);
    subLayout->addWidget(mTitle);

    // Add a top separator, our sub-widget and a bottom separator to our main
    // layout
    // Note: we keep track of our top and bottom separators since we may need
    //       to hide them in some cases/circumstances...

    mTopSeparator    = Core::newLineWidget(pSeparatorColor, this);
    mBottomSeparator = Core::newLineWidget(pSeparatorColor, this);

    layout->addWidget(mTopSeparator);
    layout->addWidget(subWidget);
    layout->addWidget(mBottomSeparator);

    // Connections to toggle our collapsed state

    if (pCollapsible) {
        connect(mButton, SIGNAL(clicked(bool)),
                this, SLOT(toggleCollapsedState()));
        connect(mTitle, SIGNAL(doubleClicked()),
                this, SLOT(toggleCollapsedState()));
    }
}

//==============================================================================

void CollapsibleHeaderWidget::setFirstHeader(const bool &pFirstHeader)
{
    // Show/hide our top separator depending on whether we are the first header

    mTopSeparator->setVisible(!pFirstHeader);
}

//==============================================================================

void CollapsibleHeaderWidget::setLastHeader(const bool &pLastHeader)
{
    // Keep track of our last header status and update our bottom separator
    // visible status, if needed

    if (pLastHeader != mLastHeader) {
        mLastHeader = pLastHeader;

        updateBottomSeparatorVisibleStatus();
    }
}

//==============================================================================

bool CollapsibleHeaderWidget::isCollapsable() const
{
    // Return wheter we are collapsable

    return !mButton->icon().isNull();
}

//==============================================================================

bool CollapsibleHeaderWidget::isCollapsed() const
{
    // Return wheter we are collapsed

    return mCollapsed;
}

//==============================================================================

void CollapsibleHeaderWidget::setCollapsed(const bool &pCollapsed)
{
    // Collapse or uncollapse ourselves, if needed

    if (pCollapsed != mCollapsed)
        toggleCollapsedState();
}

//==============================================================================

QString CollapsibleHeaderWidget::title() const
{
    // Return our title

    return mTitle->text();
}

//==============================================================================

void CollapsibleHeaderWidget::setTitle(const QString &pTitle)
{
    // Set our title

    mTitle->setText(pTitle);
}

//==============================================================================

void CollapsibleHeaderWidget::updateBottomSeparatorVisibleStatus()
{
    // Show/hide our bottom separator depending on whether we are collapsed or
    // whether we are the last header

    mBottomSeparator->setVisible(!mCollapsed || mLastHeader);
}

//==============================================================================

void CollapsibleHeaderWidget::toggleCollapsedState()
{
    // Toggle our collapsed state

    mCollapsed = !mCollapsed;

    // Update our button's icon to reflect our new collapsed state

    if (mCollapsed)
        mButton->setIcon(QIcon(":/oxygen/actions/arrow-right.png"));
    else
        mButton->setIcon(QIcon(":/oxygen/actions/arrow-down.png"));

    // Update our bottom separator visible status

    updateBottomSeparatorVisibleStatus();

    // Let people know about our new new collapsed state

    emit widgetVisible(!mCollapsed);
}

//==============================================================================

void CollapsibleWidget::constructor(const QColor &pSeparatorColor)
{
    // Some initialisations

    mSeparatorColor = pSeparatorColor;
    mHeaders = QList<CollapsibleHeaderWidget *>();

    // Create a vertical layout that will contain our headers and widgets

    mLayout = new QVBoxLayout(this);

    mLayout->setMargin(0);
    mLayout->setSpacing(0);

    setLayout(mLayout);

    // Add a stretch to our layout so that its contents will take as little
    // space as possible

    mLayout->addStretch(1);
}

//==============================================================================

CollapsibleWidget::CollapsibleWidget(const QColor &pSeparatorColor,
                                     QWidget *pParent) :
    Widget(QSize(), pParent)
{
    // Construct our object

    constructor(pSeparatorColor);
}

//==============================================================================

CollapsibleWidget::CollapsibleWidget(QWidget *pParent) :
    Widget(QSize(), pParent)
{
    // Construct our object

    constructor();
}

//==============================================================================

static const auto SettingsCollapsed = QStringLiteral("Collapsed%1");

//==============================================================================

void CollapsibleWidget::loadSettings(QSettings *pSettings)
{
    // Retrieve our collapsable state

    for (int i = 0, iMax = mHeaders.count(); i < iMax; ++i)
        if (mHeaders[i]->isCollapsable())
            setCollapsed(i, pSettings->value(SettingsCollapsed.arg(i), false).toBool());
}

//==============================================================================

void CollapsibleWidget::saveSettings(QSettings *pSettings) const
{
    // Keep track of our collapsable state

    for (int i = 0, iMax = mHeaders.count(); i < iMax; ++i)
        pSettings->setValue(SettingsCollapsed.arg(i), isCollapsed(i));
}

//==============================================================================

bool CollapsibleWidget::isCollapsed(const int &pIndex) const
{
    // Return wheter our requested header is collapsed

    return mHeaders.value(pIndex)?mHeaders[pIndex]->isCollapsed():false;
}

//==============================================================================

void CollapsibleWidget::setCollapsed(const int &pIndex, const bool &pCollapsed)
{
    // Collapse or uncollapse our requested header

    if (mHeaders.value(pIndex))
        mHeaders[pIndex]->setCollapsed(pCollapsed);
}

//==============================================================================

QString CollapsibleWidget::headerTitle(const int &pIndex) const
{
    // Return the title of our requested header

    return mHeaders.value(pIndex)?mHeaders[pIndex]->title():QString();
}

//==============================================================================

void CollapsibleWidget::setHeaderTitle(const int &pIndex, const QString &pTitle)
{
    // Set the title of our requested header

    if (mHeaders.value(pIndex))
        mHeaders[pIndex]->setTitle(pTitle);
}

//==============================================================================

void CollapsibleWidget::addWidget(QWidget *pWidget, const bool &pCollapsible)
{
    // Make sure that there is a widget to add

    if (!pWidget)
        return;

    // We want to add a widget, so we first need to add a header to our layout

    CollapsibleHeaderWidget *header = new CollapsibleHeaderWidget(mSeparatorColor, pCollapsible, this);

    // Let our header know whether it is the first header

    header->setFirstHeader(mHeaders.isEmpty());

    // Let our header know that, if anything, it is our new last header, meaning
    // that our previous last header is not the last one anymore

    if (!mHeaders.isEmpty())
        mHeaders.last()->setLastHeader(false);

    header->setLastHeader(true);

    // Now, we can actually add the header to our layout, as well as keep track
    // of it

    mLayout->addWidget(header);

    mHeaders.append(header);

    // Add the widget itself

    mLayout->addWidget(pWidget);

    // Create a connection to show/hide our widget depending on the collapsed
    // state of our header

    if (pCollapsible) {
        connect(header, SIGNAL(widgetVisible(const bool &)),
                pWidget, SLOT(setVisible(bool)));
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Single Cell view: fixed an issue with the Parameters pane looking blank at startup on OS X (closes #621).<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Collapsible widget
//==============================================================================

#include "collapsiblewidget.h"
#include "coreguiutils.h"

//==============================================================================

#include <Qt>

//==============================================================================

#include <QLayout>
#include <QSettings>
#include <QToolButton>
#include <QVariant>

//==============================================================================

namespace OpenCOR {
namespace Core {

//==============================================================================

CollapsibleHeaderTitleWidget::CollapsibleHeaderTitleWidget(QWidget *pParent) :
    QLabel(pParent)
{
}

//==============================================================================

void CollapsibleHeaderTitleWidget::mouseDoubleClickEvent(QMouseEvent *pEvent)
{
    // Default handling of the event

    QLabel::mouseDoubleClickEvent(pEvent);

    // Let people know that the widget has been double clicked

    emit doubleClicked();
}

//==============================================================================

CollapsibleHeaderWidget::CollapsibleHeaderWidget(const QColor &pSeparatorColor,
                                                 const bool &pCollapsible,
                                                 QWidget *pParent) :
    QWidget(pParent),
    mCollapsed(false),
    mLastHeader(false)
{
    // Create our main (vertical) layout

    QVBoxLayout *layout = new QVBoxLayout(this);

    layout->setMargin(0);
    layout->setSpacing(0);

    setLayout(layout);

    // Create a sub-widget with a horizontal layout

    QWidget *subWidget = new QWidget(this);
    QHBoxLayout *subLayout = new QHBoxLayout(subWidget);

    subLayout->setMargin(0);
    subLayout->setSpacing(0);

    subWidget->setLayout(subLayout);

    QColor windowColor = Core::windowColor();

    setStyleSheet(QString("QWidget {"
                          "    background: rgb(%1, %2, %3);"
                          "}").arg(QString::number(windowColor.red()),
                                   QString::number(windowColor.green()),
                                   QString::number(windowColor.blue())));

    // Create and customise our button and title

    mButton = new QToolButton(subWidget);
    mTitle  = new CollapsibleHeaderTitleWidget(subWidget);

    int iconSize = 0.4*mTitle->height();

    mButton->setIcon(pCollapsible?QIcon(":/oxygen/actions/arrow-down.png"):QIcon());
    mButton->setIconSize(QSize(iconSize, iconSize));
    mButton->setStyleSheet("QToolButton {"
                           "    border: 0px;"
                           "}"
                           ""
                           "QToolButton:pressed {"
                           "    margin: 0px;"
                           "}");

    mTitle->setAlignment(Qt::AlignCenter);

    // Add our button and title to our sub-layout

    subLayout->addWidget(mButton);
    subLayout->addWidget(mTitle);

    // Add a top separator, our sub-widget and a bottom separator to our main
    // layout
    // Note: we keep track of our top and bottom separators since we may need
    //       to hide them in some cases/circumstances...

    mTopSeparator    = Core::newLineWidget(pSeparatorColor, this);
    mBottomSeparator = Core::newLineWidget(pSeparatorColor, this);

    layout->addWidget(mTopSeparator);
    layout->addWidget(subWidget);
    layout->addWidget(mBottomSeparator);

    // Connections to toggle our collapsed state

    if (pCollapsible) {
        connect(mButton, SIGNAL(clicked(bool)),
                this, SLOT(toggleCollapsedState()));
        connect(mTitle, SIGNAL(doubleClicked()),
                this, SLOT(toggleCollapsedState()));
    }
}

//==============================================================================

void CollapsibleHeaderWidget::setFirstHeader(const bool &pFirstHeader)
{
    // Show/hide our top separator depending on whether we are the first header

    mTopSeparator->setVisible(!pFirstHeader);
}

//==============================================================================

void CollapsibleHeaderWidget::setLastHeader(const bool &pLastHeader)
{
    // Keep track of our last header status and update our bottom separator
    // visible status, if needed

    if (pLastHeader != mLastHeader) {
        mLastHeader = pLastHeader;

        updateBottomSeparatorVisibleStatus();
    }
}

//==============================================================================

bool CollapsibleHeaderWidget::isCollapsable() const
{
    // Return wheter we are collapsable

    return !mButton->icon().isNull();
}

//==============================================================================

bool CollapsibleHeaderWidget::isCollapsed() const
{
    // Return wheter we are collapsed

    return mCollapsed;
}

//==============================================================================

void CollapsibleHeaderWidget::setCollapsed(const bool &pCollapsed)
{
    // Collapse or uncollapse ourselves, if needed

    if (pCollapsed != mCollapsed)
        toggleCollapsedState();
}

//==============================================================================

QString CollapsibleHeaderWidget::title() const
{
    // Return our title

    return mTitle->text();
}

//==============================================================================

void CollapsibleHeaderWidget::setTitle(const QString &pTitle)
{
    // Set our title

    mTitle->setText(pTitle);
}

//==============================================================================

void CollapsibleHeaderWidget::updateBottomSeparatorVisibleStatus()
{
    // Show/hide our bottom separator depending on whether we are collapsed or
    // whether we are the last header

    mBottomSeparator->setVisible(!mCollapsed || mLastHeader);
}

//==============================================================================

void CollapsibleHeaderWidget::toggleCollapsedState()
{
    // Toggle our collapsed state

    mCollapsed = !mCollapsed;

    // Update our button's icon to reflect our new collapsed state

    if (mCollapsed)
        mButton->setIcon(QIcon(":/oxygen/actions/arrow-right.png"));
    else
        mButton->setIcon(QIcon(":/oxygen/actions/arrow-down.png"));

    // Update our bottom separator visible status

    updateBottomSeparatorVisibleStatus();

    // Let people know about our new new collapsed state

    emit widgetVisible(!mCollapsed);
}

//==============================================================================

void CollapsibleWidget::constructor(const QColor &pSeparatorColor)
{
    // Some initialisations

    mSeparatorColor = pSeparatorColor;
    mHeaders = QList<CollapsibleHeaderWidget *>();

    // Create a vertical layout that will contain our headers and widgets

    mLayout = new QVBoxLayout(this);

    mLayout->setMargin(0);
    mLayout->setSpacing(0);

    setLayout(mLayout);
}

//==============================================================================

CollapsibleWidget::CollapsibleWidget(const QColor &pSeparatorColor,
                                     QWidget *pParent) :
    Widget(QSize(), pParent)
{
    // Construct our object

    constructor(pSeparatorColor);
}

//==============================================================================

CollapsibleWidget::CollapsibleWidget(QWidget *pParent) :
    Widget(QSize(), pParent)
{
    // Construct our object

    constructor();
}

//==============================================================================

static const auto SettingsCollapsed = QStringLiteral("Collapsed%1");

//==============================================================================

void CollapsibleWidget::loadSettings(QSettings *pSettings)
{
    // Retrieve our collapsable state

    for (int i = 0, iMax = mHeaders.count(); i < iMax; ++i)
        if (mHeaders[i]->isCollapsable())
            setCollapsed(i, pSettings->value(SettingsCollapsed.arg(i), false).toBool());
}

//==============================================================================

void CollapsibleWidget::saveSettings(QSettings *pSettings) const
{
    // Keep track of our collapsable state

    for (int i = 0, iMax = mHeaders.count(); i < iMax; ++i)
        pSettings->setValue(SettingsCollapsed.arg(i), isCollapsed(i));
}

//==============================================================================

bool CollapsibleWidget::isCollapsed(const int &pIndex) const
{
    // Return wheter our requested header is collapsed

    return mHeaders.value(pIndex)?mHeaders[pIndex]->isCollapsed():false;
}

//==============================================================================

void CollapsibleWidget::setCollapsed(const int &pIndex, const bool &pCollapsed)
{
    // Collapse or uncollapse our requested header

    if (mHeaders.value(pIndex))
        mHeaders[pIndex]->setCollapsed(pCollapsed);
}

//==============================================================================

QString CollapsibleWidget::headerTitle(const int &pIndex) const
{
    // Return the title of our requested header

    return mHeaders.value(pIndex)?mHeaders[pIndex]->title():QString();
}

//==============================================================================

void CollapsibleWidget::setHeaderTitle(const int &pIndex, const QString &pTitle)
{
    // Set the title of our requested header

    if (mHeaders.value(pIndex))
        mHeaders[pIndex]->setTitle(pTitle);
}

//==============================================================================

void CollapsibleWidget::addWidget(QWidget *pWidget, const bool &pCollapsible)
{
    // Make sure that there is a widget to add

    if (!pWidget)
        return;

    // We want to add a widget, so we first need to add a header to our layout

    CollapsibleHeaderWidget *header = new CollapsibleHeaderWidget(mSeparatorColor, pCollapsible, this);

    // Let our header know whether it is the first header

    header->setFirstHeader(mHeaders.isEmpty());

    // Let our header know that, if anything, it is our new last header, meaning
    // that our previous last header is not the last one anymore

    if (!mHeaders.isEmpty())
        mHeaders.last()->setLastHeader(false);

    header->setLastHeader(true);

    // Now, we can actually add the header to our layout, as well as keep track
    // of it

    mLayout->addWidget(header);

    mHeaders.append(header);

    // Add the widget itself

    mLayout->addWidget(pWidget);

    // Create a connection to show/hide our widget depending on the collapsed
    // state of our header

    if (pCollapsible) {
        connect(header, SIGNAL(widgetVisible(const bool &)),
                pWidget, SLOT(setVisible(bool)));
    }
}

//==============================================================================

}   // namespace Core
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>//FRAGMENT(includes)
#include <iostream>

#include <seqan/sequence.h>
#include <seqan/file.h>

using namespace seqan;

// FRAGMENT(print-strings-rec)
// Helper function for printPermutations().
void printStringsRec(String<char> &current, unsigned int pos) {
  if (pos < length(current)) {
    for (char c = 'a'; c <= 'z'; ++c) {
      current[pos] = c;
      printStringsRec(current, pos + 1);
    }
  } else {
    std::cout << current << std::endl;
  }

  //current[pos] = 'a';
}

// FRAGMENT(print-strings)
// Print all strings of the alphabet {a, ..., z} of length len.
void printStrings(int len) {
  String<char> current;
  // Build first value;
  for (int i = 0; i < len; ++i)
    current += "a";
  // Now, current == "a" * len.

  // To iterate: human -- to recurse: DIVINE.
  printStringsRec(current, 0);
}

//FRAGMENT(main)
int main() {
  printStrings(3);
  return 0;
}
<commit_msg>removed line<commit_after>//FRAGMENT(includes)
#include <iostream>

#include <seqan/sequence.h>
#include <seqan/file.h>

using namespace seqan;

// FRAGMENT(print-strings-rec)
// Helper function for printPermutations().
void printStringsRec(String<char> &current, unsigned int pos) {
  if (pos < length(current)) {
    for (char c = 'a'; c <= 'z'; ++c) {
      current[pos] = c;
      printStringsRec(current, pos + 1);
    }
  } else {
    std::cout << current << std::endl;
  }
}

// FRAGMENT(print-strings)
// Print all strings of the alphabet {a, ..., z} of length len.
void printStrings(int len) {
  String<char> current;
  // Build first value;
  for (int i = 0; i < len; ++i)
    current += "a";
  // Now, current == "a" * len.

  // To iterate: human -- to recurse: DIVINE.
  printStringsRec(current, 0);
}

//FRAGMENT(main)
int main() {
  printStrings(3);
  return 0;
}
<|endoftext|>


<commit_before>#include "AnalysisSolver.h"

#include <sofa/core/ObjectFactory.h>

#include <Eigen/SVD>
#include <Eigen/Eigenvalues>

namespace sofa {
namespace component {
namespace linearsolver {

SOFA_DECL_CLASS(AnalysisSolver)
int AnalysisSolverClass = core::RegisterObject("Analysis solver: runs other KKTSolvers successively on a given problem and performs extra analysis on KKT system").add< AnalysisSolver >();

AnalysisSolver::AnalysisSolver()
    : condest(initData(&condest, false, "condest", "compute condition number with svd"))
    , eigenvaluesign(initData(&eigenvaluesign, false, "eigenvaluesign", "computing the sign of the eigenvalues (of the implicit matrix H)"))
    , dump_qp(initData(&dump_qp, "dump_qp", "dump qp to file if non-empty"))

{}

void AnalysisSolver::init() {

	solvers.clear();
	this->getContext()->get<KKTSolver>( &solvers, core::objectmodel::BaseContext::Local );

	if( solvers.size() < 2 ) {
		std::cerr << "warning: no other kkt solvers found" << std::endl;
	} else {
		std::cout << "AnalysisSolver: dynamics/correction will use "
				  << solvers.back()->getName()
				  << std::endl;
	}
}

void AnalysisSolver::factor(const system_type& system) {

	// start at 1 since 0 is current solver
    for( unsigned i = 1, n = solvers.size() ; i < n; ++i ) {
		solvers[i]->factor(system);
	}

    typedef system_type::dmat dmat;

    if( condest.getValue() ) {

        dmat kkt;

        kkt.setZero(system.size(), system.size());

        kkt <<
            dmat(system.H), dmat(-system.J.transpose()),
            dmat(-system.J), dmat(-system.C);

        system_type::vec eigen = kkt.jacobiSvd().singularValues();

        real min = eigen.tail<1>()(0);
        real max = eigen(0);

        if( min < std::numeric_limits<real>::epsilon() ) std::cout << "AnalysisSolver: singular system"<<std::endl;
        else
        {
            const real cond = max/min;
            std::cout << "condition number: " << cond << "("<<max<<"/"<<min<<")"<<std::endl;
            std::cout << "required precision:  "<<log(cond)<<" bits"<<std::endl;
        }

        eigen = dmat(system.H).jacobiSvd().singularValues();

        min = eigen.tail<1>()(0);
        max = eigen(0);

        if( min < std::numeric_limits<real>::epsilon() ) std::cout << "AnalysisSolver: singular implicit system"<<std::endl;
        else
        {
            const real cond = max/min;
            std::cout << "condition number implicit system: " << cond << "("<<max<<"/"<<min<<")"<<std::endl;
            std::cout << "required precision implicit system:  "<<log(cond)<<" bits"<<std::endl;
        }
    }

     if( eigenvaluesign.getValue() ) {

        Eigen::EigenSolver<dmat> es( dmat(system.H) );
//        Eigen::MatrixXcd D = es.eigenvalues().asDiagonal();
        unsigned positive = 0, negative = 0;
        for( dmat::Index i =0 ; i< es.eigenvalues().rows() ; ++i )
            if( es.eigenvalues()[i].real() < 0 ) negative++;
            else positive++;

        std::cout << "eigenvalues H: neg="<<negative<<" pos="<<positive<<std::endl;
        if( negative )
        {
            getContext()->getRootContext()->setAnimate(false);

            std::cerr<<es.eigenvalues().array().abs().minCoeff()<<std::endl;
            std::cerr<<" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n";
        }

    }

    // TODO add more as needed
}

static void write_qp(std::ofstream& out,
                     const AssembledSystem& sys,
                     const AssembledSystem::vec& rhs) {

    const char endl = '\n';

    out << sys.m << ' ' << sys.n << endl;

    out << sys.H << endl;
    out << -rhs.head(sys.m).transpose() << endl;
    out << sys.P << endl;

    if( sys.n ) {
        out << sys.J << endl;
        out << rhs.tail(sys.n).transpose() << endl;

        // TODO unilateral mask !
    }

}

// solution is that of the first solver
void AnalysisSolver::correct(vec& res,
                             const system_type& sys,
                             const vec& rhs,
                             real damping) const {
	assert( solvers.size() > 1 );
	solvers.back()->correct(res, sys, rhs, damping);

    if(!dump_qp.getValue().empty() ) {
        const std::string filename = dump_qp.getValue() + ".correction";
        std::ofstream out(filename.c_str());

        write_qp(out, sys, rhs);
    }
}

// solution is that of the last solver
void AnalysisSolver::solve(vec& res,
							const system_type& sys,
							const vec& rhs) const {

    vec backup = res; // backup initial solution

	// start at 1 since 0 is current solver
    for( unsigned i = 1, n = solvers.size(); i < n; ++i ) {
		res = backup;
		solvers[i]->solve(res, sys, rhs);
	}

    if(!dump_qp.getValue().empty() ) {
        const std::string filename = dump_qp.getValue() + ".correction";
        std::ofstream out(filename.c_str());

        write_qp(out, sys, rhs);
    }

}

}
}
}
<commit_msg>Compliant: improving AnalysisSolver output<commit_after>#include "AnalysisSolver.h"

#include <sofa/core/ObjectFactory.h>

#include <Eigen/SVD>
#include <Eigen/Eigenvalues>

namespace sofa {
namespace component {
namespace linearsolver {

SOFA_DECL_CLASS(AnalysisSolver)
int AnalysisSolverClass = core::RegisterObject("Analysis solver: runs other KKTSolvers successively on a given problem and performs extra analysis on KKT system").add< AnalysisSolver >();

AnalysisSolver::AnalysisSolver()
    : condest(initData(&condest, false, "condest", "compute condition number with svd"))
    , eigenvaluesign(initData(&eigenvaluesign, false, "eigenvaluesign", "computing the sign of the eigenvalues (of the implicit matrix H)"))
    , dump_qp(initData(&dump_qp, "dump_qp", "dump qp to file if non-empty"))

{}

void AnalysisSolver::init() {

	solvers.clear();
	this->getContext()->get<KKTSolver>( &solvers, core::objectmodel::BaseContext::Local );

	if( solvers.size() < 2 ) {
		std::cerr << "warning: no other kkt solvers found" << std::endl;
	} else {
		std::cout << "AnalysisSolver: dynamics/correction will use "
				  << solvers.back()->getName()
				  << std::endl;
	}
}

void AnalysisSolver::factor(const system_type& system) {

	// start at 1 since 0 is current solver
    for( unsigned i = 1, n = solvers.size() ; i < n; ++i ) {
		solvers[i]->factor(system);
	}

    typedef system_type::dmat dmat;

    if( condest.getValue() ) {

        dmat kkt;

        kkt.setZero(system.size(), system.size());

        kkt <<
            dmat(system.H), dmat(-system.J.transpose()),
            dmat(-system.J), dmat(-system.C);

        system_type::vec eigen = kkt.jacobiSvd().singularValues();

        real min = eigen.tail<1>()(0);
        real max = eigen(0);

        if( min < std::numeric_limits<real>::epsilon() ) std::cout << "AnalysisSolver: singular KKT system"<<std::endl;
        else
        {
            const real cond = max/min;
            std::cout << "condition number (KKT system): " << cond << " ("<<max<<"/"<<min<<")"<<std::endl;
            std::cout << "required precision (KKT system):  "<<ceil(log(cond))<<" bits"<<std::endl;
        }

        eigen = dmat(system.H).jacobiSvd().singularValues();

        min = eigen.tail<1>()(0);
        max = eigen(0);

        if( min < std::numeric_limits<real>::epsilon() ) std::cout << "AnalysisSolver: singular implicit system"<<std::endl;
        else
        {
            const real cond = max/min;
            std::cout << "condition number (implicit system): " << cond << " ("<<max<<"/"<<min<<")"<<std::endl;
            std::cout << "required precision (implicit system):  "<<ceil(log(cond))<<" bits"<<std::endl;
        }
    }

     if( eigenvaluesign.getValue() ) {

        Eigen::EigenSolver<dmat> es( dmat(system.H) );
//        Eigen::MatrixXcd D = es.eigenvalues().asDiagonal();
        unsigned positive = 0, negative = 0;
        for( dmat::Index i =0 ; i< es.eigenvalues().rows() ; ++i )
            if( es.eigenvalues()[i].real() < 0 ) negative++;
            else positive++;

        std::cout << "eigenvalues H: neg="<<negative<<" pos="<<positive<<std::endl;
        if( negative )
        {
            getContext()->getRootContext()->setAnimate(false);

            std::cerr<<es.eigenvalues().array().abs().minCoeff()<<std::endl;
            std::cerr<<" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n";
        }

    }

    // TODO add more as needed
}

static void write_qp(std::ofstream& out,
                     const AssembledSystem& sys,
                     const AssembledSystem::vec& rhs) {

    const char endl = '\n';

    out << sys.m << ' ' << sys.n << endl;

    out << sys.H << endl;
    out << -rhs.head(sys.m).transpose() << endl;
    out << sys.P << endl;

    if( sys.n ) {
        out << sys.J << endl;
        out << rhs.tail(sys.n).transpose() << endl;

        // TODO unilateral mask !
    }

}

// solution is that of the first solver
void AnalysisSolver::correct(vec& res,
                             const system_type& sys,
                             const vec& rhs,
                             real damping) const {
	assert( solvers.size() > 1 );
	solvers.back()->correct(res, sys, rhs, damping);

    if(!dump_qp.getValue().empty() ) {
        const std::string filename = dump_qp.getValue() + ".correction";
        std::ofstream out(filename.c_str());

        write_qp(out, sys, rhs);
    }
}

// solution is that of the last solver
void AnalysisSolver::solve(vec& res,
							const system_type& sys,
							const vec& rhs) const {

    vec backup = res; // backup initial solution

	// start at 1 since 0 is current solver
    for( unsigned i = 1, n = solvers.size(); i < n; ++i ) {
		res = backup;
		solvers[i]->solve(res, sys, rhs);
	}

    if(!dump_qp.getValue().empty() ) {
        const std::string filename = dump_qp.getValue() + ".correction";
        std::ofstream out(filename.c_str());

        write_qp(out, sys, rhs);
    }

}

}
}
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
**
**************************************************************************/

#include "qt4projectconfigwidget.h"

#include "makestep.h"
#include "qmakestep.h"
#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "ui_qt4projectconfigwidget.h"

#include <coreplugin/icore.h>
#include <coreplugin/mainwindow.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <extensionsystem/pluginmanager.h>

#include <QtGui/QFileDialog>

namespace {
bool debug = false;
}

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;

Qt4ProjectConfigWidget::Qt4ProjectConfigWidget(Qt4Project *project)
    : BuildStepConfigWidget(),
      m_pro(project)
{
    m_ui = new Ui::Qt4ProjectConfigWidget();
    m_ui->setupUi(this);

    // fix the layout
    m_browseButton = m_ui->shadowBuildDirEdit->buttonAtIndex(0);
#ifdef Q_OS_WIN
    browseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
#endif
    m_ui->gridLayout->addWidget(m_browseButton, 4, 2);
    int minimumHeight = qMax(m_ui->qtVersionComboBox->sizeHint().height(), m_ui->manageQtVersionPushButtons->sizeHint().height());
    Qt::Alignment labelAlignment = Qt::Alignment(style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
    for (int i = 0; i < m_ui->gridLayout->rowCount(); ++i) {
        m_ui->gridLayout->setRowMinimumHeight(i, minimumHeight);
        QLayoutItem *item = m_ui->gridLayout->itemAtPosition(i, 0);
        if (item)
            item->setAlignment(labelAlignment);
    }

    m_ui->shadowBuildDirEdit->setPromptDialogTitle(tr("Shadow Build Directory"));
    m_ui->shadowBuildDirEdit->setExpectedKind(Core::Utils::PathChooser::Directory);
    m_ui->invalidQtWarningLabel->setVisible(false);

    connect(m_ui->nameLineEdit, SIGNAL(textEdited(QString)),
            this, SLOT(changeConfigName(QString)));

    connect(m_ui->shadowBuildCheckBox, SIGNAL(clicked(bool)),
            this, SLOT(shadowBuildCheckBoxClicked(bool)));

    connect(m_ui->shadowBuildDirEdit, SIGNAL(beforeBrowsing()),
            this, SLOT(onBeforeBeforeShadowBuildDirBrowsed()));

    connect(m_ui->shadowBuildDirEdit, SIGNAL(changed(QString)),
            this, SLOT(shadowBuildLineEditTextChanged()));

    connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
            this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));

    connect(m_ui->toolChainComboBox, SIGNAL(activated(int)),
            this, SLOT(selectToolChain(int)));

    connect(m_ui->importLabel, SIGNAL(linkActivated(QString)),
            this, SLOT(importLabelClicked()));

    connect(m_ui->manageQtVersionPushButtons, SIGNAL(clicked()),
            this, SLOT(manageQtVersions()));

    QtVersionManager *vm = QtVersionManager::instance();

    connect(vm, SIGNAL(qtVersionsChanged()),
            this, SLOT(setupQtVersionsComboBox()));
}

Qt4ProjectConfigWidget::~Qt4ProjectConfigWidget()
{
    delete m_ui;
}

void Qt4ProjectConfigWidget::manageQtVersions()
{
    Core::ICore *core = Core::ICore::instance();
    core->showOptionsDialog(Constants::QT_CATEGORY, Constants::QTVERSION_PAGE);
}

QString Qt4ProjectConfigWidget::displayName() const
{
    return tr("General");
}

void Qt4ProjectConfigWidget::init(const QString &buildConfiguration)
{
    if (debug)
        qDebug() << "Qt4ProjectConfigWidget::init()";

    m_buildConfiguration = buildConfiguration;

    m_ui->nameLineEdit->setText(m_pro->displayNameFor(m_buildConfiguration));

    setupQtVersionsComboBox();

    bool shadowBuild = m_pro->value(buildConfiguration, "useShadowBuild").toBool();
    m_ui->shadowBuildCheckBox->setChecked(shadowBuild);
    m_ui->shadowBuildDirEdit->setEnabled(shadowBuild);
    m_browseButton->setEnabled(shadowBuild);
    m_ui->shadowBuildDirEdit->setPath(m_pro->buildDirectory(buildConfiguration));
    updateImportLabel();
    updateToolChainCombo();
}

void Qt4ProjectConfigWidget::changeConfigName(const QString &newName)
{
    m_pro->setDisplayNameFor(m_buildConfiguration, newName);
}

void Qt4ProjectConfigWidget::setupQtVersionsComboBox()
{
    if (m_buildConfiguration.isEmpty()) // not yet initialized
        return;

    disconnect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
        this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));

    m_ui->qtVersionComboBox->clear();
    m_ui->qtVersionComboBox->addItem(tr("Default Qt Version"), 0);

    if (m_pro->qtVersionId(m_buildConfiguration) == 0) {
        m_ui->qtVersionComboBox->setCurrentIndex(0);
        m_ui->invalidQtWarningLabel->setVisible(false);
    }
    // Add Qt Versions to the combo box
    QtVersionManager *vm = QtVersionManager::instance();
    const QList<QtVersion *> &versions = vm->versions();
    for (int i = 0; i < versions.size(); ++i) {
        m_ui->qtVersionComboBox->addItem(versions.at(i)->name(), versions.at(i)->uniqueId());

        if (versions.at(i)->uniqueId() == m_pro->qtVersionId(m_buildConfiguration)) {
            m_ui->qtVersionComboBox->setCurrentIndex(i + 1);
            m_ui->invalidQtWarningLabel->setVisible(!versions.at(i)->isValid());
        }
    }

    // And connect again
    connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
        this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));
}

void Qt4ProjectConfigWidget::onBeforeBeforeShadowBuildDirBrowsed()
{
    QString initialDirectory = QFileInfo(m_pro->file()->fileName()).absolutePath();
    if (!initialDirectory.isEmpty())
        m_ui->shadowBuildDirEdit->setInitialBrowsePathBackup(initialDirectory);
}

void Qt4ProjectConfigWidget::shadowBuildCheckBoxClicked(bool checked)
{
    m_ui->shadowBuildDirEdit->setEnabled(checked);
    m_browseButton->setEnabled(checked);
    bool b = m_ui->shadowBuildCheckBox->isChecked();
    m_pro->setValue(m_buildConfiguration, "useShadowBuild", b);
    if (b)
        m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildDirEdit->path());
    else
        m_pro->setValue(m_buildConfiguration, "buildDirectory", QVariant(QString::null));
}

void Qt4ProjectConfigWidget::updateImportLabel()
{
    bool visible = false;

    // we only show if we actually have a qmake and makestep
    if (m_pro->qmakeStep() && m_pro->makeStep()) {
        QString qtPath = QtVersionManager::findQtVersionFromMakefile(m_pro->buildDirectory(m_buildConfiguration));
        QtVersion *version = m_pro->qtVersion(m_buildConfiguration);
        // check that there's a makefile
        if (!qtPath.isEmpty()) {
            // and that the makefile path is different from the current version
            if (qtPath != (version ? version->path() : QString())) {
                // import enable
                visible = true;
            } else {
                // check that the qmake flags, arguments match
                visible = !m_pro->compareBuildConfigurationToImportFrom(m_buildConfiguration, m_pro->buildDirectory(m_buildConfiguration));
            }
        } else {
            visible = false;
        }
    }

    m_ui->importLabel->setVisible(visible);
}

void Qt4ProjectConfigWidget::shadowBuildLineEditTextChanged()
{
    if (m_pro->value(m_buildConfiguration, "buildDirectory").toString() == m_ui->shadowBuildDirEdit->path())
        return;
    m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildDirEdit->path());
    // if the directory already exists
    // check if we have a build in there and
    // offer to import it
    updateImportLabel();

    m_pro->invalidateCachedTargetInformation();
}

void Qt4ProjectConfigWidget::importLabelClicked()
{
    if (!m_pro->qmakeStep() || !m_pro->makeStep())
        return;
    QString directory = m_pro->buildDirectory(m_buildConfiguration);
    if (!directory.isEmpty()) {
        QString qtPath = QtVersionManager::findQtVersionFromMakefile(directory);
        if (!qtPath.isEmpty()) {
            QtVersionManager *vm = QtVersionManager::instance();
            QtVersion *version = vm->qtVersionForDirectory(qtPath);
            if (!version) {
                version = new QtVersion(QFileInfo(qtPath).baseName(), qtPath);
                vm->addVersion(version);
            }

            QPair<QtVersion::QmakeBuildConfig, QStringList> result =
                    QtVersionManager::scanMakeFile(directory, version->defaultBuildConfig());
            QtVersion::QmakeBuildConfig qmakeBuildConfig = result.first;
            QStringList additionalArguments = result.second;

            QString versionSpec = version->sourcePath() + "/mkspecs/" + version->mkspec();
            QString parsedSpec = Qt4Project::extractSpecFromArgumentList(additionalArguments);
            QString parsedSpecOrginal = parsedSpec;
            if (QFileInfo(parsedSpec).isRelative())
                parsedSpec = QDir::cleanPath(directory + "/" + parsedSpec);
            additionalArguments = Qt4Project::removeSpecFromArgumentList(additionalArguments);
            if (parsedSpec != versionSpec) {
                additionalArguments.prepend(parsedSpecOrginal);
                additionalArguments.prepend("-spec");
            }

            // So we got all the information now apply it...
            m_pro->setQtVersion(m_buildConfiguration, version->uniqueId());
            // Combo box will be updated at the end

            QMakeStep *qmakeStep = m_pro->qmakeStep();
            qmakeStep->setQMakeArguments(m_buildConfiguration, additionalArguments);
            MakeStep *makeStep = m_pro->makeStep();

            m_pro->setValue(m_buildConfiguration, "buildConfiguration", int(qmakeBuildConfig));
            // Adjust command line arguments, this is ugly as hell
            // If we are switching to BuildAll we want "release" in there and no "debug"
            // or "debug" in there and no "release"
            // If we are switching to not BuildAl we want neither "release" nor "debug" in there
            QStringList makeCmdArguments = makeStep->value(m_buildConfiguration, "makeargs").toStringList();
            bool debug = qmakeBuildConfig & QtVersion::DebugBuild;
            if (qmakeBuildConfig & QtVersion::BuildAll) {
                makeCmdArguments.removeAll(debug ? "release" : "debug");
                if (!makeCmdArguments.contains(debug ? "debug" : "release"))
                    makeCmdArguments.append(debug ? "debug" : "release");
            } else {
                makeCmdArguments.removeAll("debug");
                makeCmdArguments.removeAll("release");
            }
            makeStep->setMakeArguments(m_buildConfiguration, makeCmdArguments);
        }
    }
    setupQtVersionsComboBox();
}

void Qt4ProjectConfigWidget::qtVersionComboBoxCurrentIndexChanged(const QString &)
{
    //Qt Version
    int newQtVersion;
    if (m_ui->qtVersionComboBox->currentIndex() == 0) {
        newQtVersion = 0;
    } else {
        newQtVersion = m_ui->qtVersionComboBox->itemData(m_ui->qtVersionComboBox->currentIndex()).toInt();
    }
    QtVersionManager *vm = QtVersionManager::instance();
    bool isValid = vm->version(newQtVersion)->isValid();
    m_ui->invalidQtWarningLabel->setVisible(!isValid);
    if (newQtVersion != m_pro->qtVersionId(m_buildConfiguration)) {
        m_pro->setQtVersion(m_buildConfiguration, newQtVersion);
        updateToolChainCombo();
        m_pro->update();
    }
}

void Qt4ProjectConfigWidget::updateToolChainCombo()
{
    m_ui->toolChainComboBox->clear();
    QList<ProjectExplorer::ToolChain::ToolChainType> toolchains = m_pro->qtVersion(m_buildConfiguration)->possibleToolChainTypes();
    foreach (ProjectExplorer::ToolChain::ToolChainType toolchain, toolchains) {
        switch (toolchain) {
        case ProjectExplorer::ToolChain::GCC:
            m_ui->toolChainComboBox->addItem(tr("gcc"), qVariantFromValue(ProjectExplorer::ToolChain::GCC));
            break;
        case ProjectExplorer::ToolChain::LinuxICC:
            m_ui->toolChainComboBox->addItem(tr("icc"), qVariantFromValue(ProjectExplorer::ToolChain::LinuxICC));
            break;
        case ProjectExplorer::ToolChain::MinGW:
            m_ui->toolChainComboBox->addItem(tr("mingw"), qVariantFromValue(ProjectExplorer::ToolChain::MinGW));
            break;
        case ProjectExplorer::ToolChain::MSVC:
            m_ui->toolChainComboBox->addItem(tr("msvc"), qVariantFromValue(ProjectExplorer::ToolChain::MSVC));
            break;
        case ProjectExplorer::ToolChain::WINCE:
            m_ui->toolChainComboBox->addItem(tr("wince"), qVariantFromValue(ProjectExplorer::ToolChain::WINCE));
            break;
#ifdef QTCREATOR_WITH_S60
        case ProjectExplorer::ToolChain::WINSCW:
            m_ui->toolChainComboBox->addItem(tr("winscw"), qVariantFromValue(ProjectExplorer::ToolChain::WINSCW));
            break;
        case ProjectExplorer::ToolChain::GCCE:
            m_ui->toolChainComboBox->addItem(tr("gcce"), qVariantFromValue(ProjectExplorer::ToolChain::GCCE));
            break;
#endif
        case ProjectExplorer::ToolChain::OTHER:
        case ProjectExplorer::ToolChain::INVALID:
        case ProjectExplorer::ToolChain::UNKNOWN:
            break;
        }
    }
    m_ui->toolChainComboBox->setEnabled(toolchains.size() > 1);
    setToolChain(toolchains.indexOf(m_pro->toolChainType(m_buildConfiguration)));
}

void Qt4ProjectConfigWidget::selectToolChain(int index)
{
    setToolChain(index);
    m_pro->update();
}

void Qt4ProjectConfigWidget::setToolChain(int index)
{
    ProjectExplorer::ToolChain::ToolChainType selectedToolChainType =
        m_ui->toolChainComboBox->itemData(index,
            Qt::UserRole).value<ProjectExplorer::ToolChain::ToolChainType>();
    m_pro->setToolChainType(m_buildConfiguration, selectedToolChainType);
    if (m_ui->toolChainComboBox->currentIndex() != index)
        m_ui->toolChainComboBox->setCurrentIndex(index);
}
<commit_msg>Fixes:    Compile on Windows<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
**
**************************************************************************/

#include "qt4projectconfigwidget.h"

#include "makestep.h"
#include "qmakestep.h"
#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "ui_qt4projectconfigwidget.h"

#include <coreplugin/icore.h>
#include <coreplugin/mainwindow.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <extensionsystem/pluginmanager.h>

#include <QtGui/QFileDialog>

namespace {
bool debug = false;
}

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;

Qt4ProjectConfigWidget::Qt4ProjectConfigWidget(Qt4Project *project)
    : BuildStepConfigWidget(),
      m_pro(project)
{
    m_ui = new Ui::Qt4ProjectConfigWidget();
    m_ui->setupUi(this);

    // fix the layout
    m_browseButton = m_ui->shadowBuildDirEdit->buttonAtIndex(0);
#ifdef Q_OS_WIN
    m_browseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
#endif
    m_ui->gridLayout->addWidget(m_browseButton, 4, 2);
    int minimumHeight = qMax(m_ui->qtVersionComboBox->sizeHint().height(), m_ui->manageQtVersionPushButtons->sizeHint().height());
    Qt::Alignment labelAlignment = Qt::Alignment(style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
    for (int i = 0; i < m_ui->gridLayout->rowCount(); ++i) {
        m_ui->gridLayout->setRowMinimumHeight(i, minimumHeight);
        QLayoutItem *item = m_ui->gridLayout->itemAtPosition(i, 0);
        if (item)
            item->setAlignment(labelAlignment);
    }

    m_ui->shadowBuildDirEdit->setPromptDialogTitle(tr("Shadow Build Directory"));
    m_ui->shadowBuildDirEdit->setExpectedKind(Core::Utils::PathChooser::Directory);
    m_ui->invalidQtWarningLabel->setVisible(false);

    connect(m_ui->nameLineEdit, SIGNAL(textEdited(QString)),
            this, SLOT(changeConfigName(QString)));

    connect(m_ui->shadowBuildCheckBox, SIGNAL(clicked(bool)),
            this, SLOT(shadowBuildCheckBoxClicked(bool)));

    connect(m_ui->shadowBuildDirEdit, SIGNAL(beforeBrowsing()),
            this, SLOT(onBeforeBeforeShadowBuildDirBrowsed()));

    connect(m_ui->shadowBuildDirEdit, SIGNAL(changed(QString)),
            this, SLOT(shadowBuildLineEditTextChanged()));

    connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
            this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));

    connect(m_ui->toolChainComboBox, SIGNAL(activated(int)),
            this, SLOT(selectToolChain(int)));

    connect(m_ui->importLabel, SIGNAL(linkActivated(QString)),
            this, SLOT(importLabelClicked()));

    connect(m_ui->manageQtVersionPushButtons, SIGNAL(clicked()),
            this, SLOT(manageQtVersions()));

    QtVersionManager *vm = QtVersionManager::instance();

    connect(vm, SIGNAL(qtVersionsChanged()),
            this, SLOT(setupQtVersionsComboBox()));
}

Qt4ProjectConfigWidget::~Qt4ProjectConfigWidget()
{
    delete m_ui;
}

void Qt4ProjectConfigWidget::manageQtVersions()
{
    Core::ICore *core = Core::ICore::instance();
    core->showOptionsDialog(Constants::QT_CATEGORY, Constants::QTVERSION_PAGE);
}

QString Qt4ProjectConfigWidget::displayName() const
{
    return tr("General");
}

void Qt4ProjectConfigWidget::init(const QString &buildConfiguration)
{
    if (debug)
        qDebug() << "Qt4ProjectConfigWidget::init()";

    m_buildConfiguration = buildConfiguration;

    m_ui->nameLineEdit->setText(m_pro->displayNameFor(m_buildConfiguration));

    setupQtVersionsComboBox();

    bool shadowBuild = m_pro->value(buildConfiguration, "useShadowBuild").toBool();
    m_ui->shadowBuildCheckBox->setChecked(shadowBuild);
    m_ui->shadowBuildDirEdit->setEnabled(shadowBuild);
    m_browseButton->setEnabled(shadowBuild);
    m_ui->shadowBuildDirEdit->setPath(m_pro->buildDirectory(buildConfiguration));
    updateImportLabel();
    updateToolChainCombo();
}

void Qt4ProjectConfigWidget::changeConfigName(const QString &newName)
{
    m_pro->setDisplayNameFor(m_buildConfiguration, newName);
}

void Qt4ProjectConfigWidget::setupQtVersionsComboBox()
{
    if (m_buildConfiguration.isEmpty()) // not yet initialized
        return;

    disconnect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
        this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));

    m_ui->qtVersionComboBox->clear();
    m_ui->qtVersionComboBox->addItem(tr("Default Qt Version"), 0);

    if (m_pro->qtVersionId(m_buildConfiguration) == 0) {
        m_ui->qtVersionComboBox->setCurrentIndex(0);
        m_ui->invalidQtWarningLabel->setVisible(false);
    }
    // Add Qt Versions to the combo box
    QtVersionManager *vm = QtVersionManager::instance();
    const QList<QtVersion *> &versions = vm->versions();
    for (int i = 0; i < versions.size(); ++i) {
        m_ui->qtVersionComboBox->addItem(versions.at(i)->name(), versions.at(i)->uniqueId());

        if (versions.at(i)->uniqueId() == m_pro->qtVersionId(m_buildConfiguration)) {
            m_ui->qtVersionComboBox->setCurrentIndex(i + 1);
            m_ui->invalidQtWarningLabel->setVisible(!versions.at(i)->isValid());
        }
    }

    // And connect again
    connect(m_ui->qtVersionComboBox, SIGNAL(currentIndexChanged(QString)),
        this, SLOT(qtVersionComboBoxCurrentIndexChanged(QString)));
}

void Qt4ProjectConfigWidget::onBeforeBeforeShadowBuildDirBrowsed()
{
    QString initialDirectory = QFileInfo(m_pro->file()->fileName()).absolutePath();
    if (!initialDirectory.isEmpty())
        m_ui->shadowBuildDirEdit->setInitialBrowsePathBackup(initialDirectory);
}

void Qt4ProjectConfigWidget::shadowBuildCheckBoxClicked(bool checked)
{
    m_ui->shadowBuildDirEdit->setEnabled(checked);
    m_browseButton->setEnabled(checked);
    bool b = m_ui->shadowBuildCheckBox->isChecked();
    m_pro->setValue(m_buildConfiguration, "useShadowBuild", b);
    if (b)
        m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildDirEdit->path());
    else
        m_pro->setValue(m_buildConfiguration, "buildDirectory", QVariant(QString::null));
}

void Qt4ProjectConfigWidget::updateImportLabel()
{
    bool visible = false;

    // we only show if we actually have a qmake and makestep
    if (m_pro->qmakeStep() && m_pro->makeStep()) {
        QString qtPath = QtVersionManager::findQtVersionFromMakefile(m_pro->buildDirectory(m_buildConfiguration));
        QtVersion *version = m_pro->qtVersion(m_buildConfiguration);
        // check that there's a makefile
        if (!qtPath.isEmpty()) {
            // and that the makefile path is different from the current version
            if (qtPath != (version ? version->path() : QString())) {
                // import enable
                visible = true;
            } else {
                // check that the qmake flags, arguments match
                visible = !m_pro->compareBuildConfigurationToImportFrom(m_buildConfiguration, m_pro->buildDirectory(m_buildConfiguration));
            }
        } else {
            visible = false;
        }
    }

    m_ui->importLabel->setVisible(visible);
}

void Qt4ProjectConfigWidget::shadowBuildLineEditTextChanged()
{
    if (m_pro->value(m_buildConfiguration, "buildDirectory").toString() == m_ui->shadowBuildDirEdit->path())
        return;
    m_pro->setValue(m_buildConfiguration, "buildDirectory", m_ui->shadowBuildDirEdit->path());
    // if the directory already exists
    // check if we have a build in there and
    // offer to import it
    updateImportLabel();

    m_pro->invalidateCachedTargetInformation();
}

void Qt4ProjectConfigWidget::importLabelClicked()
{
    if (!m_pro->qmakeStep() || !m_pro->makeStep())
        return;
    QString directory = m_pro->buildDirectory(m_buildConfiguration);
    if (!directory.isEmpty()) {
        QString qtPath = QtVersionManager::findQtVersionFromMakefile(directory);
        if (!qtPath.isEmpty()) {
            QtVersionManager *vm = QtVersionManager::instance();
            QtVersion *version = vm->qtVersionForDirectory(qtPath);
            if (!version) {
                version = new QtVersion(QFileInfo(qtPath).baseName(), qtPath);
                vm->addVersion(version);
            }

            QPair<QtVersion::QmakeBuildConfig, QStringList> result =
                    QtVersionManager::scanMakeFile(directory, version->defaultBuildConfig());
            QtVersion::QmakeBuildConfig qmakeBuildConfig = result.first;
            QStringList additionalArguments = result.second;

            QString versionSpec = version->sourcePath() + "/mkspecs/" + version->mkspec();
            QString parsedSpec = Qt4Project::extractSpecFromArgumentList(additionalArguments);
            QString parsedSpecOrginal = parsedSpec;
            if (QFileInfo(parsedSpec).isRelative())
                parsedSpec = QDir::cleanPath(directory + "/" + parsedSpec);
            additionalArguments = Qt4Project::removeSpecFromArgumentList(additionalArguments);
            if (parsedSpec != versionSpec) {
                additionalArguments.prepend(parsedSpecOrginal);
                additionalArguments.prepend("-spec");
            }

            // So we got all the information now apply it...
            m_pro->setQtVersion(m_buildConfiguration, version->uniqueId());
            // Combo box will be updated at the end

            QMakeStep *qmakeStep = m_pro->qmakeStep();
            qmakeStep->setQMakeArguments(m_buildConfiguration, additionalArguments);
            MakeStep *makeStep = m_pro->makeStep();

            m_pro->setValue(m_buildConfiguration, "buildConfiguration", int(qmakeBuildConfig));
            // Adjust command line arguments, this is ugly as hell
            // If we are switching to BuildAll we want "release" in there and no "debug"
            // or "debug" in there and no "release"
            // If we are switching to not BuildAl we want neither "release" nor "debug" in there
            QStringList makeCmdArguments = makeStep->value(m_buildConfiguration, "makeargs").toStringList();
            bool debug = qmakeBuildConfig & QtVersion::DebugBuild;
            if (qmakeBuildConfig & QtVersion::BuildAll) {
                makeCmdArguments.removeAll(debug ? "release" : "debug");
                if (!makeCmdArguments.contains(debug ? "debug" : "release"))
                    makeCmdArguments.append(debug ? "debug" : "release");
            } else {
                makeCmdArguments.removeAll("debug");
                makeCmdArguments.removeAll("release");
            }
            makeStep->setMakeArguments(m_buildConfiguration, makeCmdArguments);
        }
    }
    setupQtVersionsComboBox();
}

void Qt4ProjectConfigWidget::qtVersionComboBoxCurrentIndexChanged(const QString &)
{
    //Qt Version
    int newQtVersion;
    if (m_ui->qtVersionComboBox->currentIndex() == 0) {
        newQtVersion = 0;
    } else {
        newQtVersion = m_ui->qtVersionComboBox->itemData(m_ui->qtVersionComboBox->currentIndex()).toInt();
    }
    QtVersionManager *vm = QtVersionManager::instance();
    bool isValid = vm->version(newQtVersion)->isValid();
    m_ui->invalidQtWarningLabel->setVisible(!isValid);
    if (newQtVersion != m_pro->qtVersionId(m_buildConfiguration)) {
        m_pro->setQtVersion(m_buildConfiguration, newQtVersion);
        updateToolChainCombo();
        m_pro->update();
    }
}

void Qt4ProjectConfigWidget::updateToolChainCombo()
{
    m_ui->toolChainComboBox->clear();
    QList<ProjectExplorer::ToolChain::ToolChainType> toolchains = m_pro->qtVersion(m_buildConfiguration)->possibleToolChainTypes();
    foreach (ProjectExplorer::ToolChain::ToolChainType toolchain, toolchains) {
        switch (toolchain) {
        case ProjectExplorer::ToolChain::GCC:
            m_ui->toolChainComboBox->addItem(tr("gcc"), qVariantFromValue(ProjectExplorer::ToolChain::GCC));
            break;
        case ProjectExplorer::ToolChain::LinuxICC:
            m_ui->toolChainComboBox->addItem(tr("icc"), qVariantFromValue(ProjectExplorer::ToolChain::LinuxICC));
            break;
        case ProjectExplorer::ToolChain::MinGW:
            m_ui->toolChainComboBox->addItem(tr("mingw"), qVariantFromValue(ProjectExplorer::ToolChain::MinGW));
            break;
        case ProjectExplorer::ToolChain::MSVC:
            m_ui->toolChainComboBox->addItem(tr("msvc"), qVariantFromValue(ProjectExplorer::ToolChain::MSVC));
            break;
        case ProjectExplorer::ToolChain::WINCE:
            m_ui->toolChainComboBox->addItem(tr("wince"), qVariantFromValue(ProjectExplorer::ToolChain::WINCE));
            break;
#ifdef QTCREATOR_WITH_S60
        case ProjectExplorer::ToolChain::WINSCW:
            m_ui->toolChainComboBox->addItem(tr("winscw"), qVariantFromValue(ProjectExplorer::ToolChain::WINSCW));
            break;
        case ProjectExplorer::ToolChain::GCCE:
            m_ui->toolChainComboBox->addItem(tr("gcce"), qVariantFromValue(ProjectExplorer::ToolChain::GCCE));
            break;
#endif
        case ProjectExplorer::ToolChain::OTHER:
        case ProjectExplorer::ToolChain::INVALID:
        case ProjectExplorer::ToolChain::UNKNOWN:
            break;
        }
    }
    m_ui->toolChainComboBox->setEnabled(toolchains.size() > 1);
    setToolChain(toolchains.indexOf(m_pro->toolChainType(m_buildConfiguration)));
}

void Qt4ProjectConfigWidget::selectToolChain(int index)
{
    setToolChain(index);
    m_pro->update();
}

void Qt4ProjectConfigWidget::setToolChain(int index)
{
    ProjectExplorer::ToolChain::ToolChainType selectedToolChainType =
        m_ui->toolChainComboBox->itemData(index,
            Qt::UserRole).value<ProjectExplorer::ToolChain::ToolChainType>();
    m_pro->setToolChainType(m_buildConfiguration, selectedToolChainType);
    if (m_ui->toolChainComboBox->currentIndex() != index)
        m_ui->toolChainComboBox->setCurrentIndex(index);
}
<|endoftext|>


<commit_before>#include "Lighting.hpp"

#include <Utility/Log.hpp>
#include "../Geometry/Rectangle.hpp"
#include "../Shader/Shader.hpp"
#include "../Shader/ShaderProgram.hpp"
#include "Post.vert.hpp"
#include "Deferred.frag.hpp"
#include "FrameBuffer.hpp"
#include "ReadWriteTexture.hpp"
#include "RenderSurface.hpp"
#include "Engine/Util/Profiling.hpp"

using namespace Video;

Lighting::Lighting(const Geometry::Rectangle* rectangle) {
    // Compile shader program.
    Shader* vertexShader = new Shader(POST_VERT, POST_VERT_LENGTH, GL_VERTEX_SHADER);
    Shader* fragmentShader = new Shader(DEFERRED_FRAG, DEFERRED_FRAG_LENGTH, GL_FRAGMENT_SHADER);
    shaderProgram = new ShaderProgram({ vertexShader, fragmentShader });
    delete vertexShader;
    delete fragmentShader;

    this->rectangle = rectangle;

    // Check if framebuffer created correctly
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        Log() << "Frame buffer creation failed\n";

    // Default framebuffer
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    // Store light uniform locations.
    for (unsigned int lightIndex = 0; lightIndex < lightCount; ++lightIndex) {
        lightUniforms[lightIndex].position = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].position").c_str());
        lightUniforms[lightIndex].intensities = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].intensities").c_str());
        lightUniforms[lightIndex].attenuation = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].attenuation").c_str());
        lightUniforms[lightIndex].ambientCoefficient = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].ambientCoefficient").c_str());
        lightUniforms[lightIndex].coneAngle = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].coneAngle").c_str());
        lightUniforms[lightIndex].direction = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].direction").c_str());
    }
}

Lighting::~Lighting() {
    delete shaderProgram;
}

void Lighting::ClearLights() {
    lights.clear();
}

void Lighting::AddLight(const Light& light) {
    lights.push_back(light);
}

void Lighting::Render(const glm::mat4& inverseProjectionMatrix, RenderSurface* renderSurface) {
    // Disable depth testing
    GLboolean depthTest = glIsEnabled(GL_DEPTH_TEST);
    glEnable(GL_DEPTH_TEST);

    GLint oldDepthFunctionMode;
    glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunctionMode);
    glDepthFunc(GL_ALWAYS);

    // Blending enabled for handling multiple light sources
    GLboolean blend = glIsEnabledi(GL_BLEND, 0);
    glEnablei(GL_BLEND, 0);
    glBlendEquationi(0, GL_FUNC_ADD);
    glBlendFunci(0, GL_ONE, GL_ONE);

    shaderProgram->Use();

    renderSurface->GetPostProcessingFrameBuffer()->SetTarget();

    renderSurface->GetAlbedoTexture()->BindForReading(GL_TEXTURE0);
    renderSurface->GetNormalTexture()->BindForReading(GL_TEXTURE1);
    renderSurface->GetSpecularTexture()->BindForReading(GL_TEXTURE2);
    renderSurface->GetGlowTexture()->BindForReading(GL_TEXTURE3);
    renderSurface->GetDepthTexture()->BindForReading(GL_TEXTURE4);

    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(rectangle->GetVertexArray());

    // Set uniforms.
    glUniform1i(shaderProgram->GetUniformLocation("textureAlbedo"), 0);
    glUniform1i(shaderProgram->GetUniformLocation("textureNormal"), 1);
    glUniform1i(shaderProgram->GetUniformLocation("textureMetallic"), 2);
    glUniform1i(shaderProgram->GetUniformLocation("textureRougness"), 3);
    glUniform1i(shaderProgram->GetUniformLocation("tDepth"), 4);

    glUniform1i(shaderProgram->GetUniformLocation("lightCount"), lightCount);
    glUniformMatrix4fv(shaderProgram->GetUniformLocation("inverseProjectionMatrix"), 1, GL_FALSE, &inverseProjectionMatrix[0][0]);

    {
        PROFILE("Render lights");
        // Render lights.
        unsigned int lightIndex = 0U;

        {
            PROFILE("Update light buffer");

            for (const Light& light : lights) {
                glUniform4fv(lightUniforms[lightIndex].position, 1, &light.position[0]);
                glUniform3fv(lightUniforms[lightIndex].intensities, 1, &light.intensities[0]);
                glUniform1f(lightUniforms[lightIndex].attenuation, light.attenuation);
                glUniform1f(lightUniforms[lightIndex].ambientCoefficient, light.ambientCoefficient);
                glUniform1f(lightUniforms[lightIndex].coneAngle, light.coneAngle);
                glUniform3fv(lightUniforms[lightIndex].direction, 1, &light.direction[0]);

                if (++lightIndex >= lightCount) {
                    lightIndex = 0U;
                    glDrawElements(GL_TRIANGLES, rectangle->GetIndexCount(), GL_UNSIGNED_INT, (void*)0);
                }
            }
        }

        {
            PROFILE("Render light");
            if (lightIndex != 0U) {
                glUniform1i(shaderProgram->GetUniformLocation("lightCount"), lightIndex);
                glDrawElements(GL_TRIANGLES, rectangle->GetIndexCount(), GL_UNSIGNED_INT, (void*)0);
            }
        }
    }

    if (!depthTest)
        glDisable(GL_DEPTH_TEST);
    if (!blend)
        glDisablei(GL_BLEND, 0);

    glDepthFunc(oldDepthFunctionMode);
}
<commit_msg>First working query<commit_after>#include "Lighting.hpp"

#include <Utility/Log.hpp>
#include "../Geometry/Rectangle.hpp"
#include "../Shader/Shader.hpp"
#include "../Shader/ShaderProgram.hpp"
#include "Post.vert.hpp"
#include "Deferred.frag.hpp"
#include "FrameBuffer.hpp"
#include "ReadWriteTexture.hpp"
#include "RenderSurface.hpp"
#include "Engine/Util/Profiling.hpp"
#include <vector> //TMP TODO

using namespace Video;

Lighting::Lighting(const Geometry::Rectangle* rectangle) {
    // Compile shader program.
    Shader* vertexShader = new Shader(POST_VERT, POST_VERT_LENGTH, GL_VERTEX_SHADER);
    Shader* fragmentShader = new Shader(DEFERRED_FRAG, DEFERRED_FRAG_LENGTH, GL_FRAGMENT_SHADER);
    shaderProgram = new ShaderProgram({ vertexShader, fragmentShader });
    delete vertexShader;
    delete fragmentShader;

    this->rectangle = rectangle;

    // Check if framebuffer created correctly
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        Log() << "Frame buffer creation failed\n";

    // Default framebuffer
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    // Store light uniform locations.
    for (unsigned int lightIndex = 0; lightIndex < lightCount; ++lightIndex) {
        lightUniforms[lightIndex].position = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].position").c_str());
        lightUniforms[lightIndex].intensities = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].intensities").c_str());
        lightUniforms[lightIndex].attenuation = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].attenuation").c_str());
        lightUniforms[lightIndex].ambientCoefficient = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].ambientCoefficient").c_str());
        lightUniforms[lightIndex].coneAngle = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].coneAngle").c_str());
        lightUniforms[lightIndex].direction = shaderProgram->GetUniformLocation(("lights[" + std::to_string(lightIndex) + "].direction").c_str());
    }
}

Lighting::~Lighting() {
    delete shaderProgram;
}

void Lighting::ClearLights() {
    lights.clear();
}

void Lighting::AddLight(const Light& light) {
    lights.push_back(light);
}

void Lighting::Render(const glm::mat4& inverseProjectionMatrix, RenderSurface* renderSurface) {
    // Disable depth testing
    GLboolean depthTest = glIsEnabled(GL_DEPTH_TEST);
    glEnable(GL_DEPTH_TEST);

    GLint oldDepthFunctionMode;
    glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunctionMode);
    glDepthFunc(GL_ALWAYS);

    // Blending enabled for handling multiple light sources
    GLboolean blend = glIsEnabledi(GL_BLEND, 0);
    glEnablei(GL_BLEND, 0);
    glBlendEquationi(0, GL_FUNC_ADD);
    glBlendFunci(0, GL_ONE, GL_ONE);

    shaderProgram->Use();

    renderSurface->GetPostProcessingFrameBuffer()->SetTarget();

    renderSurface->GetAlbedoTexture()->BindForReading(GL_TEXTURE0);
    renderSurface->GetNormalTexture()->BindForReading(GL_TEXTURE1);
    renderSurface->GetSpecularTexture()->BindForReading(GL_TEXTURE2);
    renderSurface->GetGlowTexture()->BindForReading(GL_TEXTURE3);
    renderSurface->GetDepthTexture()->BindForReading(GL_TEXTURE4);

    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(rectangle->GetVertexArray());

    // Set uniforms.
    glUniform1i(shaderProgram->GetUniformLocation("textureAlbedo"), 0);
    glUniform1i(shaderProgram->GetUniformLocation("textureNormal"), 1);
    glUniform1i(shaderProgram->GetUniformLocation("textureMetallic"), 2);
    glUniform1i(shaderProgram->GetUniformLocation("textureRougness"), 3);
    glUniform1i(shaderProgram->GetUniformLocation("tDepth"), 4);

    glUniform1i(shaderProgram->GetUniformLocation("lightCount"), lightCount);
    glUniformMatrix4fv(shaderProgram->GetUniformLocation("inverseProjectionMatrix"), 1, GL_FALSE, &inverseProjectionMatrix[0][0]);

    {
        PROFILE("Render light");

        // TMP TODO
        std::vector<GLuint> queryPool(2);
        glGenQueries(queryPool.size(), queryPool.data());

        glQueryCounter(queryPool[0], GL_TIMESTAMP);

        // Render lights.
        unsigned int lightIndex = 0U;

        for (const Light& light : lights) {
            glUniform4fv(lightUniforms[lightIndex].position, 1, &light.position[0]);
            glUniform3fv(lightUniforms[lightIndex].intensities, 1, &light.intensities[0]);
            glUniform1f(lightUniforms[lightIndex].attenuation, light.attenuation);
            glUniform1f(lightUniforms[lightIndex].ambientCoefficient, light.ambientCoefficient);
            glUniform1f(lightUniforms[lightIndex].coneAngle, light.coneAngle);
            glUniform3fv(lightUniforms[lightIndex].direction, 1, &light.direction[0]);

            if (++lightIndex >= lightCount) {
                lightIndex = 0U;
                glDrawElements(GL_TRIANGLES, rectangle->GetIndexCount(), GL_UNSIGNED_INT, (void*)0);
            }
        }

        if (lightIndex != 0U) {
            glUniform1i(shaderProgram->GetUniformLocation("lightCount"), lightIndex);
            glDrawElements(GL_TRIANGLES, rectangle->GetIndexCount(), GL_UNSIGNED_INT, (void*)0);
        }

        // TMP TODO
        glQueryCounter(queryPool[1], GL_TIMESTAMP);

        GLuint64 a = GL_FALSE;
        GLuint64 b = GL_FALSE;

        while (a == GL_FALSE)
            glGetQueryObjectui64v(queryPool[0], GL_QUERY_RESULT_AVAILABLE, &a);
        glGetQueryObjectui64v(queryPool[0], GL_QUERY_RESULT, &a);
        while (b == GL_FALSE)
            glGetQueryObjectui64v(queryPool[1], GL_QUERY_RESULT_AVAILABLE, &b);
        glGetQueryObjectui64v(queryPool[1], GL_QUERY_RESULT, &b);

        GLuint64 result = b - a;

        Log() << "B: " << result / 1000000.0 << " ms\n";

        glDeleteQueries(queryPool.size(), queryPool.data());
    }

    if (!depthTest)
        glDisable(GL_DEPTH_TEST);
    if (!blend)
        glDisablei(GL_BLEND, 0);

    glDepthFunc(oldDepthFunctionMode);
}
<|endoftext|>