<commit_before>/**
 * @file    searchWindow.cpp
 * RapidLib
 * @author  Michael Zbyszynski
 * @date    14 Sep 2017
 * @copyright Copyright © 2017 Goldsmiths. All rights reserved.
 */

#include <limits>
#include "searchWindow.h"

template<typename T>
searchWindow<T>::searchWindow(const std::size_t seriesXSize, const std::size_t seriesYSize, const warpPath &shrunkenWarpPath, const int searchRadius) : minMaxValues(seriesXSize, std::make_pair(-1, 0)), maxY(seriesYSize - 1)
{

    //Current location of higher resolution path
    std::pair<int, int> currentIndex = shrunkenWarpPath.indices[0];

    //Last evaluated part of low resolution path
    std::pair<int, int> lastWarped = std::make_pair(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());

    int blockSize = 2; //TODO: something other than 2? Different for x and y?

    //project each part of the low-res path to high res cells
    for ( auto &xyIndex : shrunkenWarpPath.indices)
    {
        if (xyIndex.first > lastWarped.first)
        {
            currentIndex.first += blockSize;
        }

        if (xyIndex.second > lastWarped.second)
        {
            currentIndex.second += blockSize;
        }

        if ((xyIndex.first > lastWarped.first) && (xyIndex.second > lastWarped.second))
        {
            markVisited(currentIndex.first - 1, currentIndex.second);
            markVisited(currentIndex.first, currentIndex.second - 1);
        }

        for (int j = 0; j < blockSize; ++j)
        {
            markVisited(currentIndex.first + j, currentIndex.second);
            markVisited(currentIndex.first + j, currentIndex.second + blockSize - 1); //TODO: These are redundant?
        }

        lastWarped = xyIndex;
    }

    if (searchRadius > 0)
    {
        expandWindow(1);
        expandWindow(searchRadius - 1);
    }
}

template<typename T>
inline void searchWindow<T>::markVisited(std::size_t col, std::size_t row)
{
    if (row <= maxY && col < minMaxValues.size())  //Don't mark beyond the edge of the window
    {
        if (minMaxValues[col].first == -1)
        {
            minMaxValues[col].first = row;
            minMaxValues[col].second = row;
        } else if (minMaxValues[col].first > row) {
            minMaxValues[col].first = row;
        } else if (minMaxValues[col].second < row) {
             minMaxValues[col].second = row;
        }
    }
}

template<typename T>
void searchWindow<T>::expandWindow(int radius)
{
    if (radius > 0) {
        //Add all cells in the current window to a vector.
        std::vector<std::pair<int, int>> windowCells;
        for (int currentX = 0; currentX < minMaxValues.size(); ++currentX) {
            for (std::size_t currentY = minMaxValues[currentX].first; currentY <= minMaxValues[currentX].second; ++currentY) {
                windowCells.push_back(std::make_pair(currentX, currentY));
            }
        }

        int maxX = int(minMaxValues.size() - 1);

        for (auto &currentCell : windowCells) {

            if (currentCell.first != 0 && currentCell.second != maxY) { //move to upper left if possible
                //expand until edges are met
                int targetX = currentCell.first - radius;
                int targetY = currentCell.second + radius;

                if (targetX >= 0 && targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(0 - targetX, targetY - int(maxY)); //FIXME: ints? size_t?
                    markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge);
                }
            }

            if (currentCell.second != maxY) { //move up if possible
                int targetX = currentCell.first;
                int targetY = currentCell.second + radius;
                if (targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = targetY - int(maxY);
                    markVisited(targetX, targetY - cellsPastEdge);
                }
            }

            if (currentCell.first != maxX && currentCell.second != maxY) { //move upper right if possible
                std::size_t targetX = currentCell.first + radius;
                std::size_t targetY = currentCell.second + radius;
                if (targetX <= maxX && targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    std::size_t cellsPastEdge = std::max(targetX - maxX, targetY - maxY);
                    markVisited(targetX - cellsPastEdge, targetY - cellsPastEdge);
                }
            }

            if (currentCell.first != 0) { //move left if possible
                int targetX = currentCell.first - radius;
                std::size_t targetY = currentCell.second;
                if (targetX != 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = (0 - targetX);
                    markVisited(targetX + cellsPastEdge, targetY);
                }
            }

            if (currentCell.first != maxX) { //move right if possible
                int targetX = currentCell.first + radius;
                int targetY = currentCell.second;
                if (targetX <= maxX) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = (targetX - maxX);
                    markVisited(targetX - cellsPastEdge, targetY);
                }
            }

            if (currentCell.first != 0 && currentCell.second != 0) { //move to lower left if possible
                int targetX = currentCell.first - radius;
                int targetY = currentCell.second - radius;

                if (targetX >= 0 && targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(0 - targetX, 0 - targetY);
                    markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge);
                }
            }

            if (currentCell.second != 0) { //move down if possible
                int targetX = currentCell.first;
                int targetY = currentCell.second - radius;
                if (targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = 0 - targetY;
                    markVisited(targetX, targetY + cellsPastEdge);
                }
            }

            if (currentCell.first != maxX && currentCell.second != 0) { //move lower right if possible
                int targetX = currentCell.first + radius;
                int targetY = currentCell.second - radius;
                if (targetX <= maxX && targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(targetX - maxX, 0 - targetY);
                    markVisited(targetX - cellsPastEdge, targetY + cellsPastEdge);
                }
            }
        }
    }
}

//explicit instantiation
template class searchWindow<double>;
template class searchWindow<float>;
<commit_msg>algorithm for windows<commit_after>/**
 * @file    searchWindow.cpp
 * RapidLib
 * @author  Michael Zbyszynski
 * @date    14 Sep 2017
 * @copyright Copyright © 2017 Goldsmiths. All rights reserved.
 */

#include <limits>
#include <algorithm>
#include "searchWindow.h"

template<typename T>
searchWindow<T>::searchWindow(const std::size_t seriesXSize, const std::size_t seriesYSize, const warpPath &shrunkenWarpPath, const int searchRadius) : minMaxValues(seriesXSize, std::make_pair(-1, 0)), maxY(seriesYSize - 1)
{

    //Current location of higher resolution path
    std::pair<int, int> currentIndex = shrunkenWarpPath.indices[0];

    //Last evaluated part of low resolution path
    std::pair<int, int> lastWarped = std::make_pair(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());

    int blockSize = 2; //TODO: something other than 2? Different for x and y?

    //project each part of the low-res path to high res cells
    for ( auto &xyIndex : shrunkenWarpPath.indices)
    {
        if (xyIndex.first > lastWarped.first)
        {
            currentIndex.first += blockSize;
        }

        if (xyIndex.second > lastWarped.second)
        {
            currentIndex.second += blockSize;
        }

        if ((xyIndex.first > lastWarped.first) && (xyIndex.second > lastWarped.second))
        {
            markVisited(currentIndex.first - 1, currentIndex.second);
            markVisited(currentIndex.first, currentIndex.second - 1);
        }

        for (int j = 0; j < blockSize; ++j)
        {
            markVisited(currentIndex.first + j, currentIndex.second);
            markVisited(currentIndex.first + j, currentIndex.second + blockSize - 1); //TODO: These are redundant?
        }

        lastWarped = xyIndex;
    }

    if (searchRadius > 0)
    {
        expandWindow(1);
        expandWindow(searchRadius - 1);
    }
}

template<typename T>
inline void searchWindow<T>::markVisited(std::size_t col, std::size_t row)
{
    if (row <= maxY && col < minMaxValues.size())  //Don't mark beyond the edge of the window
    {
        if (minMaxValues[col].first == -1)
        {
            minMaxValues[col].first = row;
            minMaxValues[col].second = row;
        } else if (minMaxValues[col].first > row) {
            minMaxValues[col].first = row;
        } else if (minMaxValues[col].second < row) {
             minMaxValues[col].second = row;
        }
    }
}

template<typename T>
void searchWindow<T>::expandWindow(int radius)
{
    if (radius > 0) {
        //Add all cells in the current window to a vector.
        std::vector<std::pair<int, int>> windowCells;
        for (int currentX = 0; currentX < minMaxValues.size(); ++currentX) {
            for (std::size_t currentY = minMaxValues[currentX].first; currentY <= minMaxValues[currentX].second; ++currentY) {
                windowCells.push_back(std::make_pair(currentX, currentY));
            }
        }

        int maxX = int(minMaxValues.size() - 1);

        for (auto &currentCell : windowCells) {

            if (currentCell.first != 0 && currentCell.second != maxY) { //move to upper left if possible
                //expand until edges are met
                int targetX = currentCell.first - radius;
                int targetY = currentCell.second + radius;

                if (targetX >= 0 && targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(0 - targetX, targetY - int(maxY)); //FIXME: ints? size_t?
                    markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge);
                }
            }

            if (currentCell.second != maxY) { //move up if possible
                int targetX = currentCell.first;
                int targetY = currentCell.second + radius;
                if (targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = targetY - int(maxY);
                    markVisited(targetX, targetY - cellsPastEdge);
                }
            }

            if (currentCell.first != maxX && currentCell.second != maxY) { //move upper right if possible
                std::size_t targetX = currentCell.first + radius;
                std::size_t targetY = currentCell.second + radius;
                if (targetX <= maxX && targetY <= maxY) {
                    markVisited(targetX, targetY);
                } else {
                    std::size_t cellsPastEdge = std::max(targetX - maxX, targetY - maxY);
                    markVisited(targetX - cellsPastEdge, targetY - cellsPastEdge);
                }
            }

            if (currentCell.first != 0) { //move left if possible
                int targetX = currentCell.first - radius;
                std::size_t targetY = currentCell.second;
                if (targetX != 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = (0 - targetX);
                    markVisited(targetX + cellsPastEdge, targetY);
                }
            }

            if (currentCell.first != maxX) { //move right if possible
                int targetX = currentCell.first + radius;
                int targetY = currentCell.second;
                if (targetX <= maxX) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = (targetX - maxX);
                    markVisited(targetX - cellsPastEdge, targetY);
                }
            }

            if (currentCell.first != 0 && currentCell.second != 0) { //move to lower left if possible
                int targetX = currentCell.first - radius;
                int targetY = currentCell.second - radius;

                if (targetX >= 0 && targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(0 - targetX, 0 - targetY);
                    markVisited(targetX + cellsPastEdge, targetY + cellsPastEdge);
                }
            }

            if (currentCell.second != 0) { //move down if possible
                int targetX = currentCell.first;
                int targetY = currentCell.second - radius;
                if (targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = 0 - targetY;
                    markVisited(targetX, targetY + cellsPastEdge);
                }
            }

            if (currentCell.first != maxX && currentCell.second != 0) { //move lower right if possible
                int targetX = currentCell.first + radius;
                int targetY = currentCell.second - radius;
                if (targetX <= maxX && targetY >= 0) {
                    markVisited(targetX, targetY);
                } else {
                    int cellsPastEdge = std::max(targetX - maxX, 0 - targetY);
                    markVisited(targetX - cellsPastEdge, targetY + cellsPastEdge);
                }
            }
        }
    }
}

//explicit instantiation
template class searchWindow<double>;
template class searchWindow<float>;
<|endoftext|>


<commit_before>// Copyright 2016 Tom Barthel-Steer
// http://www.tomsteer.net
//
// Licensed 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.

#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "consts.h"
#ifndef TARGET_WINXP
    #include <pcap.h>
#endif
#include "translations/translations.h"

#include <QTimer>
#include <QDesktopServices>
#include <QUrl>
#include <QStringList>

aboutDialog::aboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::aboutDialog)
{
    ui->setupUi(this);

    if (QString(VERSION) == QString(GIT_CURRENT_SHA1)) {
        ui->DisplayVer->setText(QString("%1").arg(VERSION));
    } else {
        ui->DisplayVer->setText(QString("%1\n%2").arg(VERSION).arg(GIT_CURRENT_SHA1));
    }
    ui->displayDate->setText(QString("%1, %2 %3 %4").arg(GIT_DATE_DAY).arg(GIT_DATE_DATE).arg(GIT_DATE_MONTH).arg(GIT_DATE_YEAR));
    ui->DisplayName->setText(AUTHOR);

    // Translators
    QStringList translators;
    for (auto translations : Translations::lTranslations)
    {
        for (auto translatorName : translations.Translators)
        {
            if (!translators.contains(translatorName))
                translators << translatorName;
        }
    }
    ui->lblTranslatorNames->setText(translators.join("\n"));

    // Libs
    ui->lblLicense->setText(
                tr("This application is provided under the Apache License, version 2.0")
    );
    ui->lblQtInfo->setText(tr("This application uses the Qt Library, version %1, licensed under the GNU LGPL")
                           .arg(qVersion()));
    #ifndef TARGET_WINXP
        const char *libpcap = pcap_lib_version();
        ui->lblLibs->setText(tr("This application uses the pcap Library, version %1, icensed under the The 3-Clause BSD License")
                .arg(libpcap));
    #else
        ui->lblLibs->setText(QString());
    #endif

    // Setup diagnostics tree
    ui->twDiag->setColumnCount(2);
    ui->twDiag->header()->hide();

    // Get listener list
    const auto listenerList = sACNManager::getInstance()->getListenerList();

    // Sort list
    struct {
            bool operator()(const QWeakPointer<sACNListener> &a, const QWeakPointer<sACNListener> &b) const
            {
                auto aStrong = a.toStrongRef();
                auto bStrong = b.toStrongRef();
                if (aStrong && bStrong)
                    return aStrong->universe() < bStrong->universe();
                else if (!aStrong)
                    return true;
                else
                    return false;
            }
        } listenerSortbyUni;
    auto listenerListSorted = listenerList.values();
    std::sort(listenerListSorted.begin(), listenerListSorted.end(), listenerSortbyUni);

    // Display Sorted!
    for (auto weakListener : listenerListSorted) {

        sACNManager::tListener listener(weakListener);
        if (listener) {
            int universe = listener->universe();

            // Save listener
            m_universeDetails.append(universeDetails());
            m_universeDetails.last().listener = listener;

            // Universe Number Text (Parent)
            {
                m_universeDetails.last().treeUniverse =  new QTreeWidgetItem(ui->twDiag);
                m_universeDetails.last().treeUniverse->setText(0, QString(tr("Universe %1")).arg(universe));
            }

            // Merges per second (Child)
            {
                m_universeDetails.last().treeMergesPerSecond = new QTreeWidgetItem(m_universeDetails.last().treeUniverse);
                m_universeDetails.last().treeMergesPerSecond->setText(0, tr("Merges per second"));
                m_universeDetails.last().treeMergesPerSecond->setText(1, "-");
            }

            // Bind status (Child)
            {
                m_universeDetails.last().treeMergesBindStatus = new QTreeWidgetItem(m_universeDetails.last().treeUniverse);
                m_universeDetails.last().treeMergesBindStatus->setText(0, tr("Bind status"));

                m_universeDetails.last().treeMergesBindStatusUnicast = new QTreeWidgetItem(m_universeDetails.last().treeMergesBindStatus);
                m_universeDetails.last().treeMergesBindStatusUnicast->setText(0, tr("Unicast"));
                bindStatus(m_universeDetails.last().treeMergesBindStatusUnicast, listener->getBindStatus().unicast);

                m_universeDetails.last().treeMergesBindStatusMulticast = new QTreeWidgetItem(m_universeDetails.last().treeMergesBindStatus);
                m_universeDetails.last().treeMergesBindStatusMulticast->setText(0, tr("Multicast"));
                bindStatus(m_universeDetails.last().treeMergesBindStatusMulticast, listener->getBindStatus().multicast);

            }
        }
    }
    resizeDiagColumn();

    m_displayTimer = new QTimer(this);
    connect(m_displayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay()));
    m_displayTimer->start(1000);

}

aboutDialog::~aboutDialog()
{
    foreach (universeDetails universeDetail, m_universeDetails) {
        delete universeDetail.treeUniverse;
    }

    m_displayTimer->deleteLater();
    delete ui;
}

void aboutDialog::updateDisplay()
{
    for (universeDetails universeDetail : m_universeDetails) {
        // Update merges per second
        auto merges = universeDetail.listener->mergesPerSecond();
        if (merges > 0)
            universeDetail.treeMergesPerSecond->setText(1, QString("%1").arg(merges));
    }
}

void aboutDialog::bindStatus(QTreeWidgetItem *treeItem, sACNListener::eBindStatus bindStatus)
{
    QString bindString;
    switch (bindStatus) {
    case sACNListener::BIND_UNKNOWN:
        bindString = QString(tr("Unknown"));
        break;
    case sACNListener::BIND_OK:
        bindString = QString(tr("OK"));
        break;
    case sACNListener::BIND_FAILED:
        bindString = QString(tr("Failed"));
        break;
    }
    treeItem->setText(1, bindString);
}

void aboutDialog::resizeDiagColumn()
{
    // Resize coloums
    for (int n = 0; n< ui->twDiag->columnCount(); n++) {
        ui->twDiag->resizeColumnToContents(n);
    }
}

void aboutDialog::on_twDiag_expanded(const QModelIndex &index)
{
    Q_UNUSED(index);

    resizeDiagColumn();
}
void aboutDialog::on_twDiag_collapsed(const QModelIndex &index)
{
    Q_UNUSED(index);

    resizeDiagColumn();
}

void aboutDialog::on_aboutDialog_finished(int result)
{
    Q_UNUSED(result);

    this->deleteLater();
}
<commit_msg>About typo<commit_after>// Copyright 2016 Tom Barthel-Steer
// http://www.tomsteer.net
//
// Licensed 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.

#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "consts.h"
#ifndef TARGET_WINXP
    #include <pcap.h>
#endif
#include "translations/translations.h"

#include <QTimer>
#include <QDesktopServices>
#include <QUrl>
#include <QStringList>

aboutDialog::aboutDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::aboutDialog)
{
    ui->setupUi(this);

    if (QString(VERSION) == QString(GIT_CURRENT_SHA1)) {
        ui->DisplayVer->setText(QString("%1").arg(VERSION));
    } else {
        ui->DisplayVer->setText(QString("%1\n%2").arg(VERSION).arg(GIT_CURRENT_SHA1));
    }
    ui->displayDate->setText(QString("%1, %2 %3 %4").arg(GIT_DATE_DAY).arg(GIT_DATE_DATE).arg(GIT_DATE_MONTH).arg(GIT_DATE_YEAR));
    ui->DisplayName->setText(AUTHOR);

    // Translators
    QStringList translators;
    for (auto translations : Translations::lTranslations)
    {
        for (auto translatorName : translations.Translators)
        {
            if (!translators.contains(translatorName))
                translators << translatorName;
        }
    }
    ui->lblTranslatorNames->setText(translators.join("\n"));

    // Libs
    ui->lblLicense->setText(
                tr("This application is provided under the Apache License, version 2.0")
    );
    ui->lblQtInfo->setText(tr("This application uses the Qt Library, version %1, licensed under the GNU LGPL")
                           .arg(qVersion()));
    #ifndef TARGET_WINXP
        const char *libpcap = pcap_lib_version();
        ui->lblLibs->setText(tr("This application uses the pcap Library, version %1, licensed under the The 3-Clause BSD License")
                .arg(libpcap));
    #else
        ui->lblLibs->setText(QString());
    #endif

    // Setup diagnostics tree
    ui->twDiag->setColumnCount(2);
    ui->twDiag->header()->hide();

    // Get listener list
    const auto listenerList = sACNManager::getInstance()->getListenerList();

    // Sort list
    struct {
            bool operator()(const QWeakPointer<sACNListener> &a, const QWeakPointer<sACNListener> &b) const
            {
                auto aStrong = a.toStrongRef();
                auto bStrong = b.toStrongRef();
                if (aStrong && bStrong)
                    return aStrong->universe() < bStrong->universe();
                else if (!aStrong)
                    return true;
                else
                    return false;
            }
        } listenerSortbyUni;
    auto listenerListSorted = listenerList.values();
    std::sort(listenerListSorted.begin(), listenerListSorted.end(), listenerSortbyUni);

    // Display Sorted!
    for (auto weakListener : listenerListSorted) {

        sACNManager::tListener listener(weakListener);
        if (listener) {
            int universe = listener->universe();

            // Save listener
            m_universeDetails.append(universeDetails());
            m_universeDetails.last().listener = listener;

            // Universe Number Text (Parent)
            {
                m_universeDetails.last().treeUniverse =  new QTreeWidgetItem(ui->twDiag);
                m_universeDetails.last().treeUniverse->setText(0, QString(tr("Universe %1")).arg(universe));
            }

            // Merges per second (Child)
            {
                m_universeDetails.last().treeMergesPerSecond = new QTreeWidgetItem(m_universeDetails.last().treeUniverse);
                m_universeDetails.last().treeMergesPerSecond->setText(0, tr("Merges per second"));
                m_universeDetails.last().treeMergesPerSecond->setText(1, "-");
            }

            // Bind status (Child)
            {
                m_universeDetails.last().treeMergesBindStatus = new QTreeWidgetItem(m_universeDetails.last().treeUniverse);
                m_universeDetails.last().treeMergesBindStatus->setText(0, tr("Bind status"));

                m_universeDetails.last().treeMergesBindStatusUnicast = new QTreeWidgetItem(m_universeDetails.last().treeMergesBindStatus);
                m_universeDetails.last().treeMergesBindStatusUnicast->setText(0, tr("Unicast"));
                bindStatus(m_universeDetails.last().treeMergesBindStatusUnicast, listener->getBindStatus().unicast);

                m_universeDetails.last().treeMergesBindStatusMulticast = new QTreeWidgetItem(m_universeDetails.last().treeMergesBindStatus);
                m_universeDetails.last().treeMergesBindStatusMulticast->setText(0, tr("Multicast"));
                bindStatus(m_universeDetails.last().treeMergesBindStatusMulticast, listener->getBindStatus().multicast);

            }
        }
    }
    resizeDiagColumn();

    m_displayTimer = new QTimer(this);
    connect(m_displayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay()));
    m_displayTimer->start(1000);

}

aboutDialog::~aboutDialog()
{
    foreach (universeDetails universeDetail, m_universeDetails) {
        delete universeDetail.treeUniverse;
    }

    m_displayTimer->deleteLater();
    delete ui;
}

void aboutDialog::updateDisplay()
{
    for (universeDetails universeDetail : m_universeDetails) {
        // Update merges per second
        auto merges = universeDetail.listener->mergesPerSecond();
        if (merges > 0)
            universeDetail.treeMergesPerSecond->setText(1, QString("%1").arg(merges));
    }
}

void aboutDialog::bindStatus(QTreeWidgetItem *treeItem, sACNListener::eBindStatus bindStatus)
{
    QString bindString;
    switch (bindStatus) {
    case sACNListener::BIND_UNKNOWN:
        bindString = QString(tr("Unknown"));
        break;
    case sACNListener::BIND_OK:
        bindString = QString(tr("OK"));
        break;
    case sACNListener::BIND_FAILED:
        bindString = QString(tr("Failed"));
        break;
    }
    treeItem->setText(1, bindString);
}

void aboutDialog::resizeDiagColumn()
{
    // Resize coloums
    for (int n = 0; n< ui->twDiag->columnCount(); n++) {
        ui->twDiag->resizeColumnToContents(n);
    }
}

void aboutDialog::on_twDiag_expanded(const QModelIndex &index)
{
    Q_UNUSED(index);

    resizeDiagColumn();
}
void aboutDialog::on_twDiag_collapsed(const QModelIndex &index)
{
    Q_UNUSED(index);

    resizeDiagColumn();
}

void aboutDialog::on_aboutDialog_finished(int result)
{
    Q_UNUSED(result);

    this->deleteLater();
}
<|endoftext|>


<commit_before>#include "factory.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#ifdef USE_COLOUR_SPACE_I420
#include "epiphansdk_video_source.h"
#endif

namespace gg {

IVideoSource * Factory::_sources[2] = { NULL, NULL };

IVideoSource * Factory::connect(enum Device type) {
#ifdef USE_COLOUR_SPACE_I420
    std::string device_id = "";
#else
    int device_id = -1; // default value makes no sense
#endif

    switch (type) {
    case DVI2PCIeDuo_DVI:
#ifdef USE_COLOUR_SPACE_I420
#ifdef EpiphanSDK_DVI
        device_id = EpiphanSDK_DVI;
#else
        throw DeviceNotFound("EpiphanSDK_DVI macro not defined");
#endif
#else
        device_id = 0; // always /dev/video0
#endif
        break;
    case DVI2PCIeDuo_SDI:
#ifdef USE_COLOUR_SPACE_I420
#ifdef EpiphanSDK_SDI
        device_id = EpiphanSDK_SDI;
#else
        throw DeviceNotFound("EpiphanSDK_SDI macro not defined");
#endif
#else
        device_id = 1; // always /dev/video1
#endif
        break;
    default:
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not recognised");
        throw DeviceNotFound(msg);
    }

    if (_sources[(int) type] == NULL)
    {
#ifdef USE_COLOUR_SPACE_I420
        IVideoSource * src = nullptr;
        try
        {
            src = new VideoSourceEpiphanSDK(device_id,
                                            V2U_GRABFRAME_FORMAT_I420);
        }
        catch (VideoSourceError & e)
        {
            throw DeviceNotFound(e.what());
        }
#else
#ifdef USE_OPENCV
        IVideoSource * src = new VideoSourceOpenCV(device_id);
#else
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not supported");
        throw VideoSourceError(msg);
#endif // USE_OPENCV
#endif

        // check querying frame dimensions
        int width = -1, height = -1;
        if (not src->get_frame_dimensions(width, height))
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" does not return frame dimensions.");
            throw DeviceOffline(error);
        }

        // check meaningful frame dimensions
        if (width <= 0 or height <= 0)
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" returns meaningless frame dimensions.");
            throw DeviceOffline(error);
        }

        // check querying frames
#ifdef USE_COLOUR_SPACE_I420
        VideoFrame_I420 frame;
#else
        VideoFrame_BGRA frame;
#endif
        if (not src->get_frame(frame))
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" does not return frames.");
            throw DeviceOffline(error);
        }

        // if no exception raised up to here, glory be to GiftGrab
        _sources[(int) type] = src;
    }

    return _sources[(int) type];
}

void Factory::disconnect(enum Device type) {
    switch (type) {
    case DVI2PCIeDuo_DVI:
    case DVI2PCIeDuo_SDI:
        break; // everything up to here is recognised
    default:
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not recognised");
        throw DeviceNotFound(msg);
    }

    if (_sources[(int) type])
    {
        delete _sources[(int) type];
        _sources[(int) type] = NULL;
    }
}

IVideoTarget * Factory::writer(Storage type)
{
    switch (type)
    {
    case File_XviD:
        return new VideoTargetOpenCV("XVID");
    case File_H265:
#ifdef USE_FFMPEG
        return new VideoTargetFFmpeg("H265");
#else
        // nop, see default below
#endif
    default:
        std::string msg;
        msg.append("Video target type ")
           .append(std::to_string(type))
           .append(" not recognised");
        throw VideoTargetError(msg);
    }
}

}
<commit_msg>Issue #65: added USE_OPENCV macro check to Factory writer method as well<commit_after>#include "factory.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#ifdef USE_COLOUR_SPACE_I420
#include "epiphansdk_video_source.h"
#endif

namespace gg {

IVideoSource * Factory::_sources[2] = { NULL, NULL };

IVideoSource * Factory::connect(enum Device type) {
#ifdef USE_COLOUR_SPACE_I420
    std::string device_id = "";
#else
    int device_id = -1; // default value makes no sense
#endif

    switch (type) {
    case DVI2PCIeDuo_DVI:
#ifdef USE_COLOUR_SPACE_I420
#ifdef EpiphanSDK_DVI
        device_id = EpiphanSDK_DVI;
#else
        throw DeviceNotFound("EpiphanSDK_DVI macro not defined");
#endif
#else
        device_id = 0; // always /dev/video0
#endif
        break;
    case DVI2PCIeDuo_SDI:
#ifdef USE_COLOUR_SPACE_I420
#ifdef EpiphanSDK_SDI
        device_id = EpiphanSDK_SDI;
#else
        throw DeviceNotFound("EpiphanSDK_SDI macro not defined");
#endif
#else
        device_id = 1; // always /dev/video1
#endif
        break;
    default:
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not recognised");
        throw DeviceNotFound(msg);
    }

    if (_sources[(int) type] == NULL)
    {
#ifdef USE_COLOUR_SPACE_I420
        IVideoSource * src = nullptr;
        try
        {
            src = new VideoSourceEpiphanSDK(device_id,
                                            V2U_GRABFRAME_FORMAT_I420);
        }
        catch (VideoSourceError & e)
        {
            throw DeviceNotFound(e.what());
        }
#else
#ifdef USE_OPENCV
        IVideoSource * src = new VideoSourceOpenCV(device_id);
#else
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not supported");
        throw VideoSourceError(msg);
#endif // USE_OPENCV
#endif

        // check querying frame dimensions
        int width = -1, height = -1;
        if (not src->get_frame_dimensions(width, height))
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" does not return frame dimensions.");
            throw DeviceOffline(error);
        }

        // check meaningful frame dimensions
        if (width <= 0 or height <= 0)
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" returns meaningless frame dimensions.");
            throw DeviceOffline(error);
        }

        // check querying frames
#ifdef USE_COLOUR_SPACE_I420
        VideoFrame_I420 frame;
#else
        VideoFrame_BGRA frame;
#endif
        if (not src->get_frame(frame))
        {
            std::string error;
            error.append("Device ")
#ifdef USE_COLOUR_SPACE_I420
                 .append(device_id)
#else
                 .append(std::to_string(device_id))
#endif
                 .append(" connected, but ")
                 .append(" does not return frames.");
            throw DeviceOffline(error);
        }

        // if no exception raised up to here, glory be to GiftGrab
        _sources[(int) type] = src;
    }

    return _sources[(int) type];
}

void Factory::disconnect(enum Device type) {
    switch (type) {
    case DVI2PCIeDuo_DVI:
    case DVI2PCIeDuo_SDI:
        break; // everything up to here is recognised
    default:
        std::string msg;
        msg.append("Device ")
           .append(std::to_string(type))
           .append(" not recognised");
        throw DeviceNotFound(msg);
    }

    if (_sources[(int) type])
    {
        delete _sources[(int) type];
        _sources[(int) type] = NULL;
    }
}

IVideoTarget * Factory::writer(Storage type)
{
    switch (type)
    {
    case File_XviD:
#ifdef USE_OPENCV
        return new VideoTargetOpenCV("XVID");
#endif // USE_OPENCV
    case File_H265:
#ifdef USE_FFMPEG
        return new VideoTargetFFmpeg("H265");
#else
        // nop, see default below
#endif
    default:
        std::string msg;
        msg.append("Video target type ")
           .append(std::to_string(type))
           .append(" not supported");
        throw VideoTargetError(msg);
    }
}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemo6sensorbase.h"

SensorManagerInterface* maemo6sensorbase::m_remoteSensorManager = 0;

const float maemo6sensorbase::GRAVITY_EARTH = 9.80665;
const float maemo6sensorbase::GRAVITY_EARTH_THOUSANDTH = 0.00980665;
const int maemo6sensorbase::KErrNotFound=-1;
const char* const maemo6sensorbase::ALWAYS_ON = "alwaysOn";
const char* const maemo6sensorbase::BUFFER_SIZE = "bufferSize";

maemo6sensorbase::maemo6sensorbase(QSensor *sensor)
    : QSensorBackend(sensor), m_sensorInterface(0), m_bufferSize(-1), m_prevOutputRange(-1)
{
    if (!m_remoteSensorManager)
        m_remoteSensorManager = &SensorManagerInterface::instance();
}

maemo6sensorbase::~maemo6sensorbase()
{
    if (m_sensorInterface) {
        stop();
        QObject::disconnect(m_sensorInterface);
        delete m_sensorInterface, m_sensorInterface = 0;
    }
}

void maemo6sensorbase::start()
{
    if (m_sensorInterface) {
        // dataRate
        int dataRate = sensor()->dataRate();
        if (dataRate > 0) {
            int interval = 1000 / dataRate;
            // for testing maximum speed
            //interval = 1;
            //dataRate = 1000;
            qDebug() << "Setting data rate" << dataRate << "Hz (interval" << interval << "ms) for" << m_sensorInterface->id();
            m_sensorInterface->setInterval(interval);
        } else {
            qDebug() << "Data rate in don't care mode (interval" << m_sensorInterface->interval() << "ms) for" << m_sensorInterface->id();
        }

        // outputRange
        int currentRange = sensor()->outputRange();

        if (currentRange != m_prevOutputRange){
            qoutputrange range = sensor()->outputRanges().at(currentRange);
            DataRange range1(range.minimum, range.maximum, range.accuracy);
            m_sensorInterface->requestDataRange(range1);
            m_prevOutputRange = currentRange;
        }

        // always on
        QVariant alwaysOn = sensor()->property(ALWAYS_ON);
        alwaysOn.isValid()?
                m_sensorInterface->setStandbyOverride(alwaysOn.toBool()):
                m_sensorInterface->setStandbyOverride(false);

        // buffering
        doConnectAfterCheck();

        int returnCode = m_sensorInterface->start().error().type();
        if (returnCode==0) return;
        qWarning()<<"m_sensorInterface did not start, error code:"<<returnCode;
    }
    sensorStopped();
}

void maemo6sensorbase::stop()
{
    if (m_sensorInterface)
        m_sensorInterface->stop();
    m_bufferSize= -1;
}

void maemo6sensorbase::setRanges(qreal correctionFactor){
    if (!m_sensorInterface) return;

    QList<DataRange> ranges = m_sensorInterface->getAvailableDataRanges();

    for (int i=0, l=ranges.size(); i<l; i++){
        DataRange range = ranges.at(i);
        qreal rangeMin = range.min * correctionFactor;
        qreal rangeMax = range.max * correctionFactor;
        qreal resolution = range.resolution * correctionFactor;
        addOutputRange(rangeMin, rangeMax, resolution);
    }
}

bool maemo6sensorbase::doConnectAfterCheck(){
    if (!m_sensorInterface) return false;

    // buffer size
    int size = bufferSize();
    if (size == m_bufferSize) return true;

    m_sensorInterface->setBufferSize(size);
    // if multiple->single or single->multiple or if uninitialized
    if ((m_bufferSize>1 && size==1) || (m_bufferSize==1 && size>1) || m_bufferSize==-1){
        m_bufferSize = size;
        return doConnect();
    }
    m_bufferSize = size;
    return true;
}

const int maemo6sensorbase::bufferSize(){
    QVariant bufferVariant = sensor()->property(BUFFER_SIZE);
    int bufferSize = bufferVariant.isValid()?bufferVariant.toInt():1;
    if (bufferSize<1) return 1;     // min
    if (bufferSize>256) return 256; // max
    return bufferSize;
}

<commit_msg>setBufferSize() waits for the next sensord release<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemo6sensorbase.h"

SensorManagerInterface* maemo6sensorbase::m_remoteSensorManager = 0;

const float maemo6sensorbase::GRAVITY_EARTH = 9.80665;
const float maemo6sensorbase::GRAVITY_EARTH_THOUSANDTH = 0.00980665;
const int maemo6sensorbase::KErrNotFound=-1;
const char* const maemo6sensorbase::ALWAYS_ON = "alwaysOn";
const char* const maemo6sensorbase::BUFFER_SIZE = "bufferSize";

maemo6sensorbase::maemo6sensorbase(QSensor *sensor)
    : QSensorBackend(sensor), m_sensorInterface(0), m_bufferSize(-1), m_prevOutputRange(-1)
{
    if (!m_remoteSensorManager)
        m_remoteSensorManager = &SensorManagerInterface::instance();
}

maemo6sensorbase::~maemo6sensorbase()
{
    if (m_sensorInterface) {
        stop();
        QObject::disconnect(m_sensorInterface);
        delete m_sensorInterface, m_sensorInterface = 0;
    }
}

void maemo6sensorbase::start()
{
    if (m_sensorInterface) {
        // dataRate
        int dataRate = sensor()->dataRate();
        if (dataRate > 0) {
            int interval = 1000 / dataRate;
            // for testing maximum speed
            //interval = 1;
            //dataRate = 1000;
            qDebug() << "Setting data rate" << dataRate << "Hz (interval" << interval << "ms) for" << m_sensorInterface->id();
            m_sensorInterface->setInterval(interval);
        } else {
            qDebug() << "Data rate in don't care mode (interval" << m_sensorInterface->interval() << "ms) for" << m_sensorInterface->id();
        }

        // outputRange
        int currentRange = sensor()->outputRange();

        if (currentRange != m_prevOutputRange){
            qoutputrange range = sensor()->outputRanges().at(currentRange);
            DataRange range1(range.minimum, range.maximum, range.accuracy);
            m_sensorInterface->requestDataRange(range1);
            m_prevOutputRange = currentRange;
        }

        // always on
        QVariant alwaysOn = sensor()->property(ALWAYS_ON);
        alwaysOn.isValid()?
                m_sensorInterface->setStandbyOverride(alwaysOn.toBool()):
                m_sensorInterface->setStandbyOverride(false);

        // buffering
        doConnectAfterCheck();

        int returnCode = m_sensorInterface->start().error().type();
        if (returnCode==0) return;
        qWarning()<<"m_sensorInterface did not start, error code:"<<returnCode;
    }
    sensorStopped();
}

void maemo6sensorbase::stop()
{
    if (m_sensorInterface)
        m_sensorInterface->stop();
    m_bufferSize= -1;
}

void maemo6sensorbase::setRanges(qreal correctionFactor){
    if (!m_sensorInterface) return;

    QList<DataRange> ranges = m_sensorInterface->getAvailableDataRanges();

    for (int i=0, l=ranges.size(); i<l; i++){
        DataRange range = ranges.at(i);
        qreal rangeMin = range.min * correctionFactor;
        qreal rangeMax = range.max * correctionFactor;
        qreal resolution = range.resolution * correctionFactor;
        addOutputRange(rangeMin, rangeMax, resolution);
    }
}

bool maemo6sensorbase::doConnectAfterCheck(){
    if (!m_sensorInterface) return false;

    // buffer size
    int size = bufferSize();
    if (size == m_bufferSize) return true;

    //TODO: waiting next sensord version
    // m_sensorInterface->setBufferSize(size);

    // if multiple->single or single->multiple or if uninitialized
    if ((m_bufferSize>1 && size==1) || (m_bufferSize==1 && size>1) || m_bufferSize==-1){
        m_bufferSize = size;
        return doConnect();
    }
    m_bufferSize = size;
    return true;
}

const int maemo6sensorbase::bufferSize(){
    QVariant bufferVariant = sensor()->property(BUFFER_SIZE);
    int bufferSize = bufferVariant.isValid()?bufferVariant.toInt():1;
    if (bufferSize<1) return 1;     // min
    if (bufferSize>256) return 256; // max
    return bufferSize;
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "csgeom/poly2d.h"
#include "csgeom/vector3.h"
#include "csutil/garray.h"
#include "isys/system.h"
#include "terrvis.h"
#include "qint.h"
#include "qsqrt.h"

//------------------------------------------------------------------------

int csTerrainQuad::global_visnr = 0;

csTerrainQuad::csTerrainQuad ()
{
  children[0] = NULL;
  children[1] = NULL;
  children[2] = NULL;
  children[3] = NULL;
  visnr = -1;
}

csTerrainQuad::~csTerrainQuad ()
{
  delete children[0];
  delete children[1];
  delete children[2];
  delete children[3];
}

void csTerrainQuad::Build (int depth)
{
  if (depth <= 0) return;
  children[0] = new csTerrainQuad ();
  children[0]->Build (depth-1);
  children[1] = new csTerrainQuad ();
  children[1]->Build (depth-1);
  children[2] = new csTerrainQuad ();
  children[2]->Build (depth-1);
  children[3] = new csTerrainQuad ();
  children[3]->Build (depth-1);
}

/// smallest value for horizon
#define MININF (-99999999.0)
#define MAXINF (-MININF)

void csTerrainQuad::InitHorizon(float *horizon, int horsize)
{
  for(int i=0; i<horsize; i++)
    horizon[i] = MININF;
}

int csTerrainQuad::GetHorIndex(const csVector3& campos, float x, float z,
  int horsize)
{
#if 0
  x -= campos.x;
  z -= campos.z;
  float len = qsqrt (x*x + z*z);
  float cosinus = x / len;
  int idx = QInt (acos (cosinus) * float (horsize-1) / (M_PI*2.));
  if (idx == 0) return idx;
  if (z < 0) idx = horsize-idx;
#else
  x -= campos.x;
  z -= campos.z;
  float len = qsqrt (x*x + z*z);
  // circle is split into horsize parts, each of size k (of 2*PI total)
  // the x-axis is right in the middle of parts 0 and horsize/2
  // thus precision around z==0 is not so important
  float k = 2.0*PI / float(horsize);
  float cosinus = x / len;
  float invcos = acos(cosinus);
  if(invcos < k*0.5) return 0;
  if(invcos > PI - k*0.5) return horsize/2;
  int idx = QInt( invcos + k*0.5 );
  if(z < 0) idx = horsize - idx;
#endif
#if 0
  /// @@@ could make a table to lookup the angle from x/z
  /// instead of atan
  float diffx = x - campos.x;
  float diffz = z - campos.z;

  double atn = M_PI_2; // pi/2
  if(diffz != 0.0) atn = atan(diffx / diffz);
  // scale from -PI/2..PI/2 to 0..horsize-1
  atn += M_PI_2;
  atn *= float(horsize-1)/PI;
  int idx = QInt(atn);
#endif
  CS_ASSERT(idx >= 0 && idx < horsize);
  return idx;
}

void csTerrainQuad::ComputeExtent(const csVector3& campos, const csBox3& bbox,
    int horsize, int& left, int& right)
{
  // only need to test four of the vertices, since the height is not important
  // for this.
  int idx[4];
  idx[0] = GetHorIndex(campos, bbox.MinX(), bbox.MinZ(), horsize);
  idx[1] = GetHorIndex(campos, bbox.MaxX(), bbox.MinZ(), horsize);
  idx[2] = GetHorIndex(campos, bbox.MaxX(), bbox.MaxZ(), horsize);
  idx[3] = GetHorIndex(campos, bbox.MinX(), bbox.MaxZ(), horsize);
  // note: from  0-1, 1-2, 2-3, 3-0 are the edge lines

  left = right = idx[0];
  for(int i=1; i<4; i++)
  {
    // already included?
    if( (right-idx[i]+horsize)%horsize <= (right-left+horsize)%horsize )
      continue;
    // extend the directions, by adding this angle to existing range.
    int ldiff = (left - idx[i] + horsize) % horsize;
    int rdiff = (idx[i] - right + horsize) % horsize;
    if(ldiff < rdiff)
      // angle is closer to left than right angle
      left = idx[i];
    else
      right = idx[i];
  }
  /// the resulting span should be less than half the horizon
printf ("idx[0]=%d idx[1]=%d idx[2]=%d idx[3]=%d\n", idx[0], idx[1], idx[2], idx[3]);
printf ("left=%d right=%d horsize=%d\n", left, right, horsize);
printf ("campos=(%g,%g,%g) bbox=(%g,%g,%g)-(%g,%g,%g)\n", campos.x, campos.y, campos.z, bbox.MinX (), bbox.MinY (), bbox.MinZ (), bbox.MaxX (), bbox.MaxY (), bbox.MaxZ ());
fflush (stdout);
  CS_ASSERT( (right - left + horsize)%horsize <= (horsize/2+1));
}

void csTerrainQuad::ComputeMinMaxDY(const csVector3& campos, const csBox3& bbox,
    float &mindy, float &maxdy)
{
  /// idea is this:
  /// dy (change of y) is the deltay / deltadistance.
  /// maximum dy, is the max_height / minimumdistance
  /// minimum dy, is the min_height / maximumdistance

  /// compute ground-distance to each of the four points.
  /// squared distance is used
  float sqdist[4];
  csVector2 d;
  d.Set(bbox.MinX() - campos.x, bbox.MinZ() - campos.z);
  sqdist[0] = d.SquaredNorm();
  d.Set(bbox.MaxX() - campos.x, bbox.MinZ() - campos.z);
  sqdist[1] = d.SquaredNorm();
  d.Set(bbox.MinX() - campos.x, bbox.MaxZ() - campos.z);
  sqdist[2] = d.SquaredNorm();
  d.Set(bbox.MaxX() - campos.x, bbox.MaxZ() - campos.z);
  sqdist[3] = d.SquaredNorm();

  /// compute min/max squared distance
  float mindist = sqdist[0];
  float maxdist = sqdist[0];
  for(int i=1; i<4; i++)
  {
    if(sqdist[i] < mindist) mindist = sqdist[i];
    else if(sqdist[i] > maxdist) maxdist = sqdist[i];
  }

  /// use difference between camera.y and min,maxheight
  /// to get min and max height change
  float minh = min_height - campos.y;
  float maxh = max_height - campos.y;

  /// divide by distance, correctly using infinite if divbyzero.
  /// like this:
  /// if divbyzero, use infinity with the same sign.
  /// see if negative values occur, distances get swapped in that case

  if(minh < 0.0)
  {
    /// below zero, smallest height at minimal distance is the steepest down
    if(mindist == 0.0) mindy = MININF;
    else mindy = minh / qsqrt(mindist);
  }
  else
  {
    /// above zero, the smallest height at maximal distance is the smallest
    /// upslope
    if(maxdist == 0.0) mindy = MAXINF;
    else mindy = minh / qsqrt(maxdist);
  }

  if(maxh < 0.0)
  {
    /// below zero, biggest height at maximal distance is the least downslope
    if(maxdist == 0.0) maxdy = MININF;
    else maxdy = maxh / qsqrt(maxdist);
  }
  else
  {
    /// above zero, the biggest height at minimum distance is steepest upslope
    if(mindist == 0.0) maxdy = MAXINF;
    else maxdy = maxh / qsqrt(mindist);
  }

//printf ("sqdist[0]=%g\n", sqdist[0]);
//printf ("sqdist[1]=%g\n", sqdist[1]);
//printf ("sqdist[2]=%g\n", sqdist[2]);
//printf ("sqdist[3]=%g\n", sqdist[3]);
//printf ("mindist=%g maxdist=%g\n", mindist, maxdist);
//printf ("min_height=%g max_height=%g\n", min_height, max_height);
//printf ("minh=%g maxh=%g\n", minh, maxh);
//fflush (stdout);
  /// we've been trying to do this all along here.
  CS_ASSERT( mindy <= maxdy );
}

bool csTerrainQuad::CheckIfAbove(float* horizon, int horsize, int left,
  int right, float dy)
{
  /// loop from left to right, but it can wrap by horsize
  int len = (right-left+horsize)%horsize;
  int idx = left;
  while(len--)
  {
    if( dy > horizon[idx] ) return true;
    idx = (idx+1)%horsize;
  }
  return false;
}

void csTerrainQuad::HeightenHorizon(float* horizon, int horsize, int left,
  int right, float dy)
{
  int len = (right-left+horsize)%horsize;
  int idx = left;
  while(len--)
  {
    if( dy > horizon[idx] ) horizon[idx] = dy;
    idx = (idx+1)%horsize;
  }
}

void csTerrainQuad::ComputeVisibility(const csVector3& campos,
  const csBox3& bbox, float* horizon, int horsize)
{
  // compute visibility for this node

  // compute min and max dy values.
  float mindy, maxdy;
  ComputeMinMaxDY(campos, bbox, mindy, maxdy);

  // start and end angles for projected bounding box on horizon
  int left = 0, right = 0;
  // visibility
  bool vis = false;
  // if camera is 'in' this node (disregarding height), vis always true
  if(  (bbox.MinX()-SMALL_EPSILON <= campos.x) &&
       (campos.x <= bbox.MaxX()+SMALL_EPSILON)
    && (bbox.MinZ()-SMALL_EPSILON <= campos.z) &&
       (campos.z <= bbox.MaxZ()+SMALL_EPSILON) )
  {
    // node spans the entire horizon
    left = 0;
    right = horsize-1;
    vis = true;
  }
  else {
    // see which piece of the horizon is spanned by the bbox
    ComputeExtent(campos, bbox, horsize, left, right);

    // check min and max dy against the horizon
    // if the max is bigger than any value -> the node could be visible
    vis = CheckIfAbove(horizon, horsize, left, right, maxdy);
  }

  if(!vis) return; // nothing to be done, nor for the children.

  // so this node is visible
  MarkVisible();
  // update horizon with minimum height
  HeightenHorizon(horizon, horsize, left, right, mindy);

  // for leaves, we are done now.
  if(IsLeaf()) return;

  // the children must be checked front-to-back...
  float midx = (bbox.MinX() + bbox.MaxX()) * 0.5;
  float midz = (bbox.MinZ() + bbox.MaxZ()) * 0.5;

  // first see where the camera lies:
  // TOP +z, BOT -z
  // LEFT -x, RIGHT +x
  // z splits top from bottom
  // x splits left from right
  int camchild = 0;
  if(campos.z < midz) camchild = CS_QUAD_TOPLEFT;
  else camchild = CS_QUAD_BOTLEFT;
  if(campos.x > midx) camchild++; // get the right quad

  // iterate front to back
  csBox3 cbox[4];
  cbox[CS_QUAD_TOPLEFT].Set (bbox.MinX(), 0, bbox.MinZ(), midx, 0, midz);
  cbox[CS_QUAD_TOPRIGHT].Set(midx, 0, bbox.MinZ(), bbox.MaxX(), 0, midz);
  cbox[CS_QUAD_BOTLEFT].Set (bbox.MinX(), 0, midz, midx, 0, bbox.MaxZ());
  cbox[CS_QUAD_BOTRIGHT].Set(midx, 0, midz, bbox.MaxX(), 0, bbox.MaxZ());

  // rect is set up as: 0 1
  //                    2 3
  // so, in bits, this is ab:  a is 0(left) 1(right), b is 0(top) 1(bot)
  // flip bits to get the other squares.
  int child = camchild;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^1;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^2;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^3;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
}

//------------------------------------------------------------------------

<commit_msg>Fix to the latest fix to terrvis.<commit_after>/*
    Copyright (C) 2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "csgeom/poly2d.h"
#include "csgeom/vector3.h"
#include "csutil/garray.h"
#include "isys/system.h"
#include "terrvis.h"
#include "qint.h"
#include "qsqrt.h"

//------------------------------------------------------------------------

int csTerrainQuad::global_visnr = 0;

csTerrainQuad::csTerrainQuad ()
{
  children[0] = NULL;
  children[1] = NULL;
  children[2] = NULL;
  children[3] = NULL;
  visnr = -1;
}

csTerrainQuad::~csTerrainQuad ()
{
  delete children[0];
  delete children[1];
  delete children[2];
  delete children[3];
}

void csTerrainQuad::Build (int depth)
{
  if (depth <= 0) return;
  children[0] = new csTerrainQuad ();
  children[0]->Build (depth-1);
  children[1] = new csTerrainQuad ();
  children[1]->Build (depth-1);
  children[2] = new csTerrainQuad ();
  children[2]->Build (depth-1);
  children[3] = new csTerrainQuad ();
  children[3]->Build (depth-1);
}

/// smallest value for horizon
#define MININF (-99999999.0)
#define MAXINF (-MININF)

void csTerrainQuad::InitHorizon(float *horizon, int horsize)
{
  for(int i=0; i<horsize; i++)
    horizon[i] = MININF;
}

int csTerrainQuad::GetHorIndex(const csVector3& campos, float x, float z,
  int horsize)
{
#if 0
  x -= campos.x;
  z -= campos.z;
  float len = qsqrt (x*x + z*z);
  float cosinus = x / len;
  int idx = QInt (acos (cosinus) * float (horsize-1) / (M_PI*2.));
  if (idx == 0) return idx;
  if (z < 0) idx = horsize-idx;
#else
  x -= campos.x;
  z -= campos.z;
  float len = qsqrt (x*x + z*z);
  // circle is split into horsize parts, each of size k (of 2*PI total)
  // the x-axis is right in the middle of parts 0 and horsize/2
  // thus precision around z==0 is not so important
  float k = 2.0*PI / float(horsize);
  float cosinus = x / len;
  float invcos = acos(cosinus);
  if(invcos < k*0.5) return 0;
  if(invcos > PI - k*0.5) return horsize/2;
  int idx = QInt( (invcos + k*0.5)/k );
  if(z < 0) idx = horsize - idx;
#endif
#if 0
  /// @@@ could make a table to lookup the angle from x/z
  /// instead of atan
  float diffx = x - campos.x;
  float diffz = z - campos.z;

  double atn = M_PI_2; // pi/2
  if(diffz != 0.0) atn = atan(diffx / diffz);
  // scale from -PI/2..PI/2 to 0..horsize-1
  atn += M_PI_2;
  atn *= float(horsize-1)/PI;
  int idx = QInt(atn);
#endif
  CS_ASSERT(idx >= 0 && idx < horsize);
  return idx;
}

void csTerrainQuad::ComputeExtent(const csVector3& campos, const csBox3& bbox,
    int horsize, int& left, int& right)
{
  // only need to test four of the vertices, since the height is not important
  // for this.
  int idx[4];
  idx[0] = GetHorIndex(campos, bbox.MinX(), bbox.MinZ(), horsize);
  idx[1] = GetHorIndex(campos, bbox.MaxX(), bbox.MinZ(), horsize);
  idx[2] = GetHorIndex(campos, bbox.MaxX(), bbox.MaxZ(), horsize);
  idx[3] = GetHorIndex(campos, bbox.MinX(), bbox.MaxZ(), horsize);
  // note: from  0-1, 1-2, 2-3, 3-0 are the edge lines

  left = right = idx[0];
  for(int i=1; i<4; i++)
  {
    // already included?
    if( (right-idx[i]+horsize)%horsize <= (right-left+horsize)%horsize )
      continue;
    // extend the directions, by adding this angle to existing range.
    int ldiff = (left - idx[i] + horsize) % horsize;
    int rdiff = (idx[i] - right + horsize) % horsize;
    if(ldiff < rdiff)
      // angle is closer to left than right angle
      left = idx[i];
    else
      right = idx[i];
  }
  /// the resulting span should be less than half the horizon
printf ("idx[0]=%d idx[1]=%d idx[2]=%d idx[3]=%d\n", idx[0], idx[1], idx[2], idx[3]);
printf ("left=%d right=%d horsize=%d\n", left, right, horsize);
printf ("campos=(%g,%g,%g) bbox=(%g,%g,%g)-(%g,%g,%g)\n", campos.x, campos.y, campos.z, bbox.MinX (), bbox.MinY (), bbox.MinZ (), bbox.MaxX (), bbox.MaxY (), bbox.MaxZ ());
fflush (stdout);
  CS_ASSERT( (right - left + horsize)%horsize <= (horsize/2+1));
}

void csTerrainQuad::ComputeMinMaxDY(const csVector3& campos, const csBox3& bbox,
    float &mindy, float &maxdy)
{
  /// idea is this:
  /// dy (change of y) is the deltay / deltadistance.
  /// maximum dy, is the max_height / minimumdistance
  /// minimum dy, is the min_height / maximumdistance

  /// compute ground-distance to each of the four points.
  /// squared distance is used
  float sqdist[4];
  csVector2 d;
  d.Set(bbox.MinX() - campos.x, bbox.MinZ() - campos.z);
  sqdist[0] = d.SquaredNorm();
  d.Set(bbox.MaxX() - campos.x, bbox.MinZ() - campos.z);
  sqdist[1] = d.SquaredNorm();
  d.Set(bbox.MinX() - campos.x, bbox.MaxZ() - campos.z);
  sqdist[2] = d.SquaredNorm();
  d.Set(bbox.MaxX() - campos.x, bbox.MaxZ() - campos.z);
  sqdist[3] = d.SquaredNorm();

  /// compute min/max squared distance
  float mindist = sqdist[0];
  float maxdist = sqdist[0];
  for(int i=1; i<4; i++)
  {
    if(sqdist[i] < mindist) mindist = sqdist[i];
    else if(sqdist[i] > maxdist) maxdist = sqdist[i];
  }

  /// use difference between camera.y and min,maxheight
  /// to get min and max height change
  float minh = min_height - campos.y;
  float maxh = max_height - campos.y;

  /// divide by distance, correctly using infinite if divbyzero.
  /// like this:
  /// if divbyzero, use infinity with the same sign.
  /// see if negative values occur, distances get swapped in that case

  if(minh < 0.0)
  {
    /// below zero, smallest height at minimal distance is the steepest down
    if(mindist == 0.0) mindy = MININF;
    else mindy = minh / qsqrt(mindist);
  }
  else
  {
    /// above zero, the smallest height at maximal distance is the smallest
    /// upslope
    if(maxdist == 0.0) mindy = MAXINF;
    else mindy = minh / qsqrt(maxdist);
  }

  if(maxh < 0.0)
  {
    /// below zero, biggest height at maximal distance is the least downslope
    if(maxdist == 0.0) maxdy = MININF;
    else maxdy = maxh / qsqrt(maxdist);
  }
  else
  {
    /// above zero, the biggest height at minimum distance is steepest upslope
    if(mindist == 0.0) maxdy = MAXINF;
    else maxdy = maxh / qsqrt(mindist);
  }

//printf ("sqdist[0]=%g\n", sqdist[0]);
//printf ("sqdist[1]=%g\n", sqdist[1]);
//printf ("sqdist[2]=%g\n", sqdist[2]);
//printf ("sqdist[3]=%g\n", sqdist[3]);
//printf ("mindist=%g maxdist=%g\n", mindist, maxdist);
//printf ("min_height=%g max_height=%g\n", min_height, max_height);
//printf ("minh=%g maxh=%g\n", minh, maxh);
//fflush (stdout);
  /// we've been trying to do this all along here.
  CS_ASSERT( mindy <= maxdy );
}

bool csTerrainQuad::CheckIfAbove(float* horizon, int horsize, int left,
  int right, float dy)
{
  /// loop from left to right, but it can wrap by horsize
  int len = (right-left+horsize)%horsize;
  int idx = left;
  while(len--)
  {
    if( dy > horizon[idx] ) return true;
    idx = (idx+1)%horsize;
  }
  return false;
}

void csTerrainQuad::HeightenHorizon(float* horizon, int horsize, int left,
  int right, float dy)
{
  int len = (right-left+horsize)%horsize;
  int idx = left;
  while(len--)
  {
    if( dy > horizon[idx] ) horizon[idx] = dy;
    idx = (idx+1)%horsize;
  }
}

void csTerrainQuad::ComputeVisibility(const csVector3& campos,
  const csBox3& bbox, float* horizon, int horsize)
{
  // compute visibility for this node

  // compute min and max dy values.
  float mindy, maxdy;
  ComputeMinMaxDY(campos, bbox, mindy, maxdy);

  // start and end angles for projected bounding box on horizon
  int left = 0, right = 0;
  // visibility
  bool vis = false;
  // if camera is 'in' this node (disregarding height), vis always true
  if(  (bbox.MinX()-SMALL_EPSILON <= campos.x) &&
       (campos.x <= bbox.MaxX()+SMALL_EPSILON)
    && (bbox.MinZ()-SMALL_EPSILON <= campos.z) &&
       (campos.z <= bbox.MaxZ()+SMALL_EPSILON) )
  {
    // node spans the entire horizon
    left = 0;
    right = horsize-1;
    vis = true;
  }
  else {
    // see which piece of the horizon is spanned by the bbox
    ComputeExtent(campos, bbox, horsize, left, right);

    // check min and max dy against the horizon
    // if the max is bigger than any value -> the node could be visible
    vis = CheckIfAbove(horizon, horsize, left, right, maxdy);
  }

  if(!vis) return; // nothing to be done, nor for the children.

  // so this node is visible
  MarkVisible();
  // update horizon with minimum height
  HeightenHorizon(horizon, horsize, left, right, mindy);

  // for leaves, we are done now.
  if(IsLeaf()) return;

  // the children must be checked front-to-back...
  float midx = (bbox.MinX() + bbox.MaxX()) * 0.5;
  float midz = (bbox.MinZ() + bbox.MaxZ()) * 0.5;

  // first see where the camera lies:
  // TOP +z, BOT -z
  // LEFT -x, RIGHT +x
  // z splits top from bottom
  // x splits left from right
  int camchild = 0;
  if(campos.z < midz) camchild = CS_QUAD_TOPLEFT;
  else camchild = CS_QUAD_BOTLEFT;
  if(campos.x > midx) camchild++; // get the right quad

  // iterate front to back
  csBox3 cbox[4];
  cbox[CS_QUAD_TOPLEFT].Set (bbox.MinX(), 0, bbox.MinZ(), midx, 0, midz);
  cbox[CS_QUAD_TOPRIGHT].Set(midx, 0, bbox.MinZ(), bbox.MaxX(), 0, midz);
  cbox[CS_QUAD_BOTLEFT].Set (bbox.MinX(), 0, midz, midx, 0, bbox.MaxZ());
  cbox[CS_QUAD_BOTRIGHT].Set(midx, 0, midz, bbox.MaxX(), 0, bbox.MaxZ());

  // rect is set up as: 0 1
  //                    2 3
  // so, in bits, this is ab:  a is 0(left) 1(right), b is 0(top) 1(bot)
  // flip bits to get the other squares.
  int child = camchild;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^1;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^2;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
  child = camchild^3;
  GetChild(child)->ComputeVisibility(campos, cbox[child], horizon, horsize);
}

//------------------------------------------------------------------------

<|endoftext|>


<commit_before>/* FasTC
 * Copyright (c) 2013 University of North Carolina at Chapel Hill.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes, without
 * fee, and without a written agreement is hereby granted, provided that the
 * above copyright notice, this paragraph, and the following four paragraphs
 * appear in all copies.
 *
 * Permission to incorporate this software into commercial products may be
 * obtained by contacting the authors or the Office of Technology Development
 * at the University of North Carolina at Chapel Hill <otd@unc.edu>.
 *
 * This software program and documentation are copyrighted by the University of
 * North Carolina at Chapel Hill. The software program and documentation are
 * supplied "as is," without any accompanying services from the University of
 * North Carolina at Chapel Hill or the authors. The University of North
 * Carolina at Chapel Hill and the authors do not warrant that the operation of
 * the program will be uninterrupted or error-free. The end-user understands
 * that the program was developed for research purposes and is advised not to
 * rely exclusively on the program for any reason.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE
 * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
 * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA
 * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY
 * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY
 * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON
 * AN "AS IS" BASIS, AND THE UNIVERSITY  OF NORTH CAROLINA AT CHAPEL HILL AND
 * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Please send all BUG REPORTS to <pavel@cs.unc.edu>.
 *
 * The authors may be contacted via:
 *
 * Pavel Krajcevski
 * Dept of Computer Science
 * 201 S Columbia St
 * Frederick P. Brooks, Jr. Computer Science Bldg
 * Chapel Hill, NC 27599-3175
 * USA
 *
 * <http://gamma.cs.unc.edu/FasTC/>
 */

#include "gtest/gtest.h"

// This is the PVR library header
#include "PVRTextureUtilities.h"

// This is our library header
#include "PVRTCCompressor.h"

#include "TestUtils.h"

// #define OUTPUT_DEBUG_IMAGE

#ifdef OUTPUT_DEBUG_IMAGE
#  include "Core/include/Image.h"
#  include "IO/include/ImageFile.h"
#endif  // OUTPUT_DEBUG_IMAGE

class ImageTester {
 public:
  explicit ImageTester(const char *filename) {
    pvrtexture::CPVRTexture pvrTex(filename);

    const uint8 *data = static_cast<const uint8 *>(pvrTex.getDataPtr());
    ASSERT_TRUE(data);

    const pvrtexture::CPVRTextureHeader &hdr = pvrTex.getHeader();
    const uint32 w = hdr.getWidth();
    const uint32 h = hdr.getHeight();

    uint32 *outPixels = new uint32[w * h];

    DecompressionJob dcj(data, reinterpret_cast<uint8 *>(outPixels), w, h);
    PVRTCC::Decompress(dcj, PVRTCC::eWrapMode_Wrap);

    bool result = pvrtexture::Transcode(pvrTex,
                                        pvrtexture::PVRStandard8PixelType,
                                        ePVRTVarTypeUnsignedByte,
                                        ePVRTCSpacelRGB);
    EXPECT_TRUE(result);

    uint32 *libPixels = static_cast<uint32 *>(pvrTex.getDataPtr());

    for(int i = 0; i < w*h; i++) {
      EXPECT_EQ(PixelPrinter(libPixels[i]), PixelPrinter(outPixels[i]));
    }

#ifdef OUTPUT_DEBUG_IMAGE
    char dbgfname[256];
    snprintf(dbgfname, sizeof(dgbfname), "Debug%s.png", filename);
    ::ImageFile imgFile(dbgfname, eFileFormat_PNG, ::Image(w, h, outPixels));
    imgFile.Write();
#endif  // OUTPUT_DEBUG_IMAGE

    delete outPixels;
  }
};

TEST(Decompressor, DecompressGradient) {
  ImageTester("gradient.pvr");
}

TEST(Decompressor, DecompressWhite) {
  ImageTester("white.pvr");
}

TEST(Decompressor, DecompressGray) {
  ImageTester("gray.pvr");
}

TEST(Decompressor, DecompressTransparent) {
  ImageTester("transparent.pvr");
}

<commit_msg>Fix typo<commit_after>/* FasTC
 * Copyright (c) 2013 University of North Carolina at Chapel Hill.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes, without
 * fee, and without a written agreement is hereby granted, provided that the
 * above copyright notice, this paragraph, and the following four paragraphs
 * appear in all copies.
 *
 * Permission to incorporate this software into commercial products may be
 * obtained by contacting the authors or the Office of Technology Development
 * at the University of North Carolina at Chapel Hill <otd@unc.edu>.
 *
 * This software program and documentation are copyrighted by the University of
 * North Carolina at Chapel Hill. The software program and documentation are
 * supplied "as is," without any accompanying services from the University of
 * North Carolina at Chapel Hill or the authors. The University of North
 * Carolina at Chapel Hill and the authors do not warrant that the operation of
 * the program will be uninterrupted or error-free. The end-user understands
 * that the program was developed for research purposes and is advised not to
 * rely exclusively on the program for any reason.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE
 * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
 * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA
 * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY
 * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY
 * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON
 * AN "AS IS" BASIS, AND THE UNIVERSITY  OF NORTH CAROLINA AT CHAPEL HILL AND
 * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Please send all BUG REPORTS to <pavel@cs.unc.edu>.
 *
 * The authors may be contacted via:
 *
 * Pavel Krajcevski
 * Dept of Computer Science
 * 201 S Columbia St
 * Frederick P. Brooks, Jr. Computer Science Bldg
 * Chapel Hill, NC 27599-3175
 * USA
 *
 * <http://gamma.cs.unc.edu/FasTC/>
 */

#include "gtest/gtest.h"

// This is the PVR library header
#include "PVRTextureUtilities.h"

// This is our library header
#include "PVRTCCompressor.h"

#include "TestUtils.h"

// #define OUTPUT_DEBUG_IMAGE

#ifdef OUTPUT_DEBUG_IMAGE
#  include "Core/include/Image.h"
#  include "IO/include/ImageFile.h"
#endif  // OUTPUT_DEBUG_IMAGE

class ImageTester {
 public:
  explicit ImageTester(const char *filename) {
    pvrtexture::CPVRTexture pvrTex(filename);

    const uint8 *data = static_cast<const uint8 *>(pvrTex.getDataPtr());
    ASSERT_TRUE(data);

    const pvrtexture::CPVRTextureHeader &hdr = pvrTex.getHeader();
    const uint32 w = hdr.getWidth();
    const uint32 h = hdr.getHeight();

    uint32 *outPixels = new uint32[w * h];

    DecompressionJob dcj(data, reinterpret_cast<uint8 *>(outPixels), w, h);
    PVRTCC::Decompress(dcj, PVRTCC::eWrapMode_Wrap);

    bool result = pvrtexture::Transcode(pvrTex,
                                        pvrtexture::PVRStandard8PixelType,
                                        ePVRTVarTypeUnsignedByte,
                                        ePVRTCSpacelRGB);
    EXPECT_TRUE(result);

    uint32 *libPixels = static_cast<uint32 *>(pvrTex.getDataPtr());

    for(int i = 0; i < w*h; i++) {
      EXPECT_EQ(PixelPrinter(libPixels[i]), PixelPrinter(outPixels[i]));
    }

#ifdef OUTPUT_DEBUG_IMAGE
    char dbgfname[256];
    snprintf(dbgfname, sizeof(dbgfname), "Debug%s.png", filename);
    ::ImageFile imgFile(dbgfname, eFileFormat_PNG, ::Image(w, h, outPixels));
    imgFile.Write();
#endif  // OUTPUT_DEBUG_IMAGE

    delete outPixels;
  }
};

TEST(Decompressor, DecompressGradient) {
  ImageTester("gradient.pvr");
}

TEST(Decompressor, DecompressWhite) {
  ImageTester("white.pvr");
}

TEST(Decompressor, DecompressGray) {
  ImageTester("gray.pvr");
}

TEST(Decompressor, DecompressTransparent) {
  ImageTester("transparent.pvr");
}

<|endoftext|>


<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Renderer.h"
#include "Engine.h"
#include "Texture.h"
#include "Node.h"
#include "Utils.h"
#include "Shader.h"
#include "Camera.h"
#include "EventHander.h"
#include "SceneManager.h"
#include "MeshBuffer.h"
#include "EventDispatcher.h"
#include "RenderTarget.h"

namespace ouzel
{
    Renderer::Renderer()
    {

    }

    Renderer::~Renderer()
    {

    }

    bool Renderer::init(const Size2& size, bool resizable, bool fullscreen, Driver driver)
    {
        _driver = driver;
        _size = size;
        _resizable = resizable;
        _fullscreen = fullscreen;

        return true;
    }

    void Renderer::clear()
    {
        _drawCallCount = 0;
    }

    void Renderer::flush()
    {
    }

    void Renderer::resize(const Size2& size)
    {
        if (_size != size)
        {
            _size = size;
            Engine::getInstance()->getSceneManager()->recalculateProjection();

            WindowEventPtr event = std::make_shared<WindowEvent>();
            event->type = Event::Type::WINDOW_SIZE_CHANGE;
            event->size = _size;
            event->title = _title;

            Engine::getInstance()->getEventDispatcher()->dispatchEvent(event, Engine::getInstance()->getRenderer());
        }
    }

    void Renderer::setTitle(const std::string& title)
    {
        if (_title != title)
        {
            _title = title;

            WindowEventPtr event = std::make_shared<WindowEvent>();
            event->type = Event::Type::WINDOW_TITLE_CHANGE;
            event->size = _size;
            event->title = _title;

            Engine::getInstance()->getEventDispatcher()->dispatchEvent(event, Engine::getInstance()->getRenderer());
        }
    }

    TexturePtr Renderer::createTexture(const Size2& size, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());
        texture->init(size, dynamic);

        return texture;
    }

    bool Renderer::activateTexture(const TexturePtr& texture, uint32_t layer)
    {
        _activeTextures[layer] = texture;

        return true;
    }

    TexturePtr Renderer::loadTextureFromFile(const std::string& filename, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());

        if (!texture->initFromFile(filename, dynamic))
        {
            texture.reset();
        }

        return texture;
    }

    TexturePtr Renderer::loadTextureFromData(const void* data, const Size2& size, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());

        if (!texture->initFromData(data, size, dynamic))
        {
            texture.reset();
        }

        return texture;
    }

    RenderTargetPtr Renderer::createRenderTarget(const Size2& size, bool depthBuffer)
    {
        RenderTargetPtr renderTarget(new RenderTarget());

        if (!renderTarget->init(size, depthBuffer))
        {
            renderTarget.reset();
        }

        return renderTarget;
    }

    bool Renderer::activateRenderTarget(const RenderTargetPtr& renderTarget)
    {
        _activeRenderTarget = renderTarget;

        return true;
    }

    ShaderPtr Renderer::loadShaderFromFiles(const std::string& fragmentShader, const std::string& vertexShader, uint32_t vertexAttributes)
    {
        ShaderPtr shader(new Shader());

        if (!shader->initFromFiles(fragmentShader, vertexShader, vertexAttributes))
        {
            shader.reset();
        }

        return shader;
    }

    ShaderPtr Renderer::loadShaderFromBuffers(const uint8_t* fragmentShader, uint32_t fragmentShaderSize, const uint8_t* vertexShader, uint32_t vertexShaderSize, uint32_t vertexAttributes)
    {
        ShaderPtr shader(new Shader());

        if (!shader->initFromBuffers(fragmentShader, fragmentShaderSize, vertexShader, vertexShaderSize, vertexAttributes))
        {
            shader.reset();
        }

        return shader;
    }

    bool Renderer::activateShader(const ShaderPtr& shader)
    {
        _activeShader = shader;

        return true;
    }

    MeshBufferPtr Renderer::createMeshBuffer(const void* indices, uint32_t indexSize, uint32_t indexCount, bool dynamicIndexBuffer, const void* vertices, uint32_t vertexSize, uint32_t vertexCount, bool dynamicVertexBuffer, uint32_t vertexAttributes)
    {
        MeshBufferPtr meshBuffer(new MeshBuffer());

        if (!meshBuffer->initFromData(indices, indexSize, indexCount, dynamicIndexBuffer, vertices, vertexSize, vertexCount, dynamicVertexBuffer, vertexAttributes))
        {
            meshBuffer.reset();
        }

        return meshBuffer;
    }

    bool Renderer::drawMeshBuffer(const MeshBufferPtr& meshBuffer, uint32_t indexCount, DrawMode drawMode)
    {
        OUZEL_UNUSED(drawMode);

        if (_activeShader)
        {
            if (meshBuffer->getVertexAttributes() != _activeShader->getVertexAttributes())
            {
                return false;
            }

            if (indexCount > meshBuffer->getIndexCount())
            {
                return false;
            }
        }
        else
        {
            return false;
        }

        _drawCallCount++;

        return true;
    }

    Vector2 Renderer::viewToScreenLocation(const Vector2& position)
    {
        float x = 2.0f * position.x / _size.width - 1.0f;
        float y = 2.0f * (_size.height - position.y) / _size.height - 1.0f;

        return Vector2(x, y);
    }

    Vector2 Renderer::screenToViewLocation(const Vector2& position)
    {
        float x = (position.x + 1.0f) / 2.0f * _size.width;
        float y = _size.height - (position.y + 1.0f) / 2.0f * _size.height;

        return Vector2(x, y);
    }

    bool Renderer::checkVisibility(const Matrix4& transform, const AABB2& boundingBox, const CameraPtr& camera)
    {
        // TODO: do calculations for different scale modes
        Rectangle visiableRect(0.0f, 0.0f, _size.width, _size.height);

        // transform center point to screen space
        Vector2 diff = boundingBox.max - boundingBox.min;

        Vector3 v3p(boundingBox.min.x + diff.x / 2.0f, boundingBox.min.y + diff.y / 2.0f, 0.0f);
        diff *= camera->getZoom();

        transform.transformPoint(v3p);

        Vector2 v2p = camera->projectPoint(v3p);

        Size2 hSize(diff.x / 2.0f, diff.y / 2.0f);

        // convert content size to world coordinates
        Size2 hWorldSize;

        hWorldSize.width = std::max(fabsf(hSize.width * transform.m[0] + hSize.height * transform.m[4]), fabsf(hSize.width * transform.m[0] - hSize.height * transform.m[4]));
        hWorldSize.height = std::max(fabsf(hSize.width * transform.m[1] + hSize.height * transform.m[5]), fabsf(hSize.width * transform.m[1] - hSize.height * transform.m[5]));

        // enlarge visible rect half size in screen coord
        visiableRect.x -= hWorldSize.width;
        visiableRect.y -= hWorldSize.height;
        visiableRect.width += hWorldSize.width * 2.0f;
        visiableRect.height += hWorldSize.height * 2.0f;

        return visiableRect.containsPoint(v2p);
    }

    bool Renderer::saveScreenshot(const std::string& filename)
    {
        OUZEL_UNUSED(filename);

        return true;
    }
}
<commit_msg>Use content scale when calculating visibility<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Renderer.h"
#include "Engine.h"
#include "Texture.h"
#include "Node.h"
#include "Utils.h"
#include "Shader.h"
#include "Camera.h"
#include "EventHander.h"
#include "SceneManager.h"
#include "MeshBuffer.h"
#include "EventDispatcher.h"
#include "RenderTarget.h"

namespace ouzel
{
    Renderer::Renderer()
    {

    }

    Renderer::~Renderer()
    {

    }

    bool Renderer::init(const Size2& size, bool resizable, bool fullscreen, Driver driver)
    {
        _driver = driver;
        _size = size;
        _resizable = resizable;
        _fullscreen = fullscreen;

        return true;
    }

    void Renderer::clear()
    {
        _drawCallCount = 0;
    }

    void Renderer::flush()
    {
    }

    void Renderer::resize(const Size2& size)
    {
        if (_size != size)
        {
            _size = size;
            Engine::getInstance()->getSceneManager()->recalculateProjection();

            WindowEventPtr event = std::make_shared<WindowEvent>();
            event->type = Event::Type::WINDOW_SIZE_CHANGE;
            event->size = _size;
            event->title = _title;

            Engine::getInstance()->getEventDispatcher()->dispatchEvent(event, Engine::getInstance()->getRenderer());
        }
    }

    void Renderer::setTitle(const std::string& title)
    {
        if (_title != title)
        {
            _title = title;

            WindowEventPtr event = std::make_shared<WindowEvent>();
            event->type = Event::Type::WINDOW_TITLE_CHANGE;
            event->size = _size;
            event->title = _title;

            Engine::getInstance()->getEventDispatcher()->dispatchEvent(event, Engine::getInstance()->getRenderer());
        }
    }

    TexturePtr Renderer::createTexture(const Size2& size, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());
        texture->init(size, dynamic);

        return texture;
    }

    bool Renderer::activateTexture(const TexturePtr& texture, uint32_t layer)
    {
        _activeTextures[layer] = texture;

        return true;
    }

    TexturePtr Renderer::loadTextureFromFile(const std::string& filename, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());

        if (!texture->initFromFile(filename, dynamic))
        {
            texture.reset();
        }

        return texture;
    }

    TexturePtr Renderer::loadTextureFromData(const void* data, const Size2& size, bool dynamic, bool mipmaps)
    {
        TexturePtr texture(new Texture());

        if (!texture->initFromData(data, size, dynamic))
        {
            texture.reset();
        }

        return texture;
    }

    RenderTargetPtr Renderer::createRenderTarget(const Size2& size, bool depthBuffer)
    {
        RenderTargetPtr renderTarget(new RenderTarget());

        if (!renderTarget->init(size, depthBuffer))
        {
            renderTarget.reset();
        }

        return renderTarget;
    }

    bool Renderer::activateRenderTarget(const RenderTargetPtr& renderTarget)
    {
        _activeRenderTarget = renderTarget;

        return true;
    }

    ShaderPtr Renderer::loadShaderFromFiles(const std::string& fragmentShader, const std::string& vertexShader, uint32_t vertexAttributes)
    {
        ShaderPtr shader(new Shader());

        if (!shader->initFromFiles(fragmentShader, vertexShader, vertexAttributes))
        {
            shader.reset();
        }

        return shader;
    }

    ShaderPtr Renderer::loadShaderFromBuffers(const uint8_t* fragmentShader, uint32_t fragmentShaderSize, const uint8_t* vertexShader, uint32_t vertexShaderSize, uint32_t vertexAttributes)
    {
        ShaderPtr shader(new Shader());

        if (!shader->initFromBuffers(fragmentShader, fragmentShaderSize, vertexShader, vertexShaderSize, vertexAttributes))
        {
            shader.reset();
        }

        return shader;
    }

    bool Renderer::activateShader(const ShaderPtr& shader)
    {
        _activeShader = shader;

        return true;
    }

    MeshBufferPtr Renderer::createMeshBuffer(const void* indices, uint32_t indexSize, uint32_t indexCount, bool dynamicIndexBuffer, const void* vertices, uint32_t vertexSize, uint32_t vertexCount, bool dynamicVertexBuffer, uint32_t vertexAttributes)
    {
        MeshBufferPtr meshBuffer(new MeshBuffer());

        if (!meshBuffer->initFromData(indices, indexSize, indexCount, dynamicIndexBuffer, vertices, vertexSize, vertexCount, dynamicVertexBuffer, vertexAttributes))
        {
            meshBuffer.reset();
        }

        return meshBuffer;
    }

    bool Renderer::drawMeshBuffer(const MeshBufferPtr& meshBuffer, uint32_t indexCount, DrawMode drawMode)
    {
        OUZEL_UNUSED(drawMode);

        if (_activeShader)
        {
            if (meshBuffer->getVertexAttributes() != _activeShader->getVertexAttributes())
            {
                return false;
            }

            if (indexCount > meshBuffer->getIndexCount())
            {
                return false;
            }
        }
        else
        {
            return false;
        }

        _drawCallCount++;

        return true;
    }

    Vector2 Renderer::viewToScreenLocation(const Vector2& position)
    {
        float x = 2.0f * position.x / _size.width - 1.0f;
        float y = 2.0f * (_size.height - position.y) / _size.height - 1.0f;

        return Vector2(x, y);
    }

    Vector2 Renderer::screenToViewLocation(const Vector2& position)
    {
        float x = (position.x + 1.0f) / 2.0f * _size.width;
        float y = _size.height - (position.y + 1.0f) / 2.0f * _size.height;

        return Vector2(x, y);
    }

    bool Renderer::checkVisibility(const Matrix4& transform, const AABB2& boundingBox, const CameraPtr& camera)
    {
        Rectangle visiableRect(0.0f, 0.0f, _size.width, _size.height);

        // transform center point to screen space
        Vector2 diff = boundingBox.max - boundingBox.min;

        Vector3 v3p(boundingBox.min.x + diff.x / 2.0f, boundingBox.min.y + diff.y / 2.0f, 0.0f);
        diff *= camera->getZoom();
        diff.x *= camera->getContentScale().x;
        diff.y *= camera->getContentScale().y;

        transform.transformPoint(v3p);

        Vector2 v2p = camera->projectPoint(v3p);

        Size2 hSize(diff.x / 2.0f, diff.y / 2.0f);

        // convert content size to world coordinates
        Size2 hWorldSize;

        hWorldSize.width = std::max(fabsf(hSize.width * transform.m[0] + hSize.height * transform.m[4]), fabsf(hSize.width * transform.m[0] - hSize.height * transform.m[4]));
        hWorldSize.height = std::max(fabsf(hSize.width * transform.m[1] + hSize.height * transform.m[5]), fabsf(hSize.width * transform.m[1] - hSize.height * transform.m[5]));

        // enlarge visible rect half size in screen coord
        visiableRect.x -= hWorldSize.width;
        visiableRect.y -= hWorldSize.height;
        visiableRect.width += hWorldSize.width * 2.0f;
        visiableRect.height += hWorldSize.height * 2.0f;

        return visiableRect.containsPoint(v2p);
    }

    bool Renderer::saveScreenshot(const std::string& filename)
    {
        OUZEL_UNUSED(filename);

        return true;
    }
}
<|endoftext|>