<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $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 "qoutlinemapper_p.h"

#include "qmath.h"

#include <stdlib.h>

QT_BEGIN_NAMESPACE

static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;

#define qreal_to_fixed_26_6(f) (int(f * 64))

static const QRectF boundingRect(const QPointF *points, int pointCount)
{
    const QPointF *e = points;
    const QPointF *last = points + pointCount;
    qreal minx, maxx, miny, maxy;
    minx = maxx = e->x();
    miny = maxy = e->y();
    while (++e < last) {
        if (e->x() < minx)
            minx = e->x();
        else if (e->x() > maxx)
            maxx = e->x();
        if (e->y() < miny)
            miny = e->y();
        else if (e->y() > maxy)
            maxy = e->y();
    }
    return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
}

QT_FT_Outline *QOutlineMapper::convertPath(const QPainterPath &path)
{
    Q_ASSERT(!path.isEmpty());
    int elmCount = path.elementCount();
#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::convertPath(), size=%d\n", elmCount);
#endif
    beginOutline(path.fillRule());

    for (int index=0; index<elmCount; ++index) {
        const QPainterPath::Element &elm = path.elementAt(index);

        switch (elm.type) {

        case QPainterPath::MoveToElement:
            if (index == elmCount - 1)
                continue;
            moveTo(elm);
            break;

        case QPainterPath::LineToElement:
            lineTo(elm);
            break;

        case QPainterPath::CurveToElement:
            curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
            index += 2;
            break;

        default:
            break; // This will never hit..
        }
    }

    endOutline();
    return outline();
}

QT_FT_Outline *QOutlineMapper::convertPath(const QVectorPath &path)
{
    int count = path.elementCount();

#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::convertPath(VP), size=%d\n", count);
#endif
    beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);

    if (path.elements()) {
        // TODO: if we do closing of subpaths in convertElements instead we
        // could avoid this loop
        const QPainterPath::ElementType *elements = path.elements();
        const QPointF *points = reinterpret_cast<const QPointF *>(path.points());

        for (int index = 0; index < count; ++index) {
            switch (elements[index]) {
                case QPainterPath::MoveToElement:
                    if (index == count - 1)
                        continue;
                    moveTo(points[index]);
                    break;

                case QPainterPath::LineToElement:
                    lineTo(points[index]);
                    break;

                case QPainterPath::CurveToElement:
                    curveTo(points[index], points[index+1], points[index+2]);
                    index += 2;
                    break;

                default:
                    break; // This will never hit..
            }
        }

    } else {
        // ### We can kill this copying and just use the buffer straight...

        m_elements.resize(count);
        memcpy(m_elements.data(), path.points(), count* sizeof(QPointF));

        m_element_types.resize(0);
    }

    endOutline();
    return outline();
}

void QOutlineMapper::endOutline()
{
    closeSubpath();

    int element_count = m_elements.size();

    if (element_count == 0) {
        memset(&m_outline, 0, sizeof(m_outline));
        return;
    }

    QPointF *elements;

    // Transform the outline
    if (m_txop == QTransform::TxNone) {
        elements = m_elements.data();
    } else {
        if (m_txop == QTransform::TxTranslate) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
            }
        } else if (m_txop == QTransform::TxScale) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
            }
        } else if (m_txop < QTransform::TxProject) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
                                          m_m22 * e.y() + m_m12 * e.x() + m_dy);
            }
        } else {
            const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.data());
            QPainterPath path = vp.convertToPainterPath();
            path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
            if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
                path.setFillRule(Qt::WindingFill);
            uint old_txop = m_txop;
            m_txop = QTransform::TxNone;
            if (path.isEmpty())
                m_valid = false;
            else
                convertPath(path);
            m_txop = old_txop;
            return;
        }
        elements = m_elements_dev.data();
    }

    if (m_round_coords) {
        // round coordinates to match outlines drawn with drawLine_midpoint_i
        for (int i = 0; i < m_elements.size(); ++i)
            elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
                                  qFloor(elements[i].y() + aliasedCoordinateDelta));
    }

    controlPointRect = boundingRect(elements, element_count);

#ifdef QT_DEBUG_CONVERT
    printf(" - control point rect (%.2f, %.2f) %.2f x %.2f\n",
           controlPointRect.x(), controlPointRect.y(),
           controlPointRect.width(), controlPointRect.height());
#endif

    // Check for out of dev bounds...
    const bool do_clip = (controlPointRect.left() < -QT_RASTER_COORD_LIMIT
                          || controlPointRect.right() > QT_RASTER_COORD_LIMIT
                          || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
                          || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT);

    if (do_clip) {
        clipElements(elements, elementTypes(), element_count);
    } else {
        convertElements(elements, elementTypes(), element_count);
    }
}

void QOutlineMapper::convertElements(const QPointF *elements,
                                       const QPainterPath::ElementType *types,
                                       int element_count)
{

    if (types) {
        // Translate into FT coords
        const QPointF *e = elements;
        for (int i=0; i<element_count; ++i) {
            switch (*types) {
            case QPainterPath::MoveToElement:
                {
                    QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                              qreal_to_fixed_26_6(e->y()) };
                    if (i != 0)
                        m_contours << m_points.size() - 1;
                    m_points << pt_fixed;
                    m_tags <<  QT_FT_CURVE_TAG_ON;
                }
                break;

            case QPainterPath::LineToElement:
                {
                    QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                              qreal_to_fixed_26_6(e->y()) };
                    m_points << pt_fixed;
                    m_tags << QT_FT_CURVE_TAG_ON;
                }
                break;

            case QPainterPath::CurveToElement:
                {
                    QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
                                               qreal_to_fixed_26_6(e->y()) };
                    ++e;
                    QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
                                               qreal_to_fixed_26_6((e)->y()) };
                    ++e;
                    QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
                                              qreal_to_fixed_26_6((e)->y()) };

                    m_points << cp1_fixed << cp2_fixed << ep_fixed;
                    m_tags << QT_FT_CURVE_TAG_CUBIC
                           << QT_FT_CURVE_TAG_CUBIC
                           << QT_FT_CURVE_TAG_ON;

                    types += 2;
                    i += 2;
                }
                break;
            default:
                break;
            }
            ++types;
            ++e;
        }
    } else {
        // Plain polygon...
        const QPointF *last = elements + element_count;
        const QPointF *e = elements;
        while (e < last) {
            QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                      qreal_to_fixed_26_6(e->y()) };
            m_points << pt_fixed;
            m_tags << QT_FT_CURVE_TAG_ON;
            ++e;
        }
    }

    // close the very last subpath
    m_contours << m_points.size() - 1;

    m_outline.n_contours = m_contours.size();
    m_outline.n_points = m_points.size();

    m_outline.points = m_points.data();
    m_outline.tags = m_tags.data();
    m_outline.contours = m_contours.data();

#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::endOutline\n");

    printf(" - contours: %d\n", m_outline.n_contours);
    for (int i=0; i<m_outline.n_contours; ++i) {
        printf("   - %d\n", m_outline.contours[i]);
    }

    printf(" - points: %d\n", m_outline.n_points);
    for (int i=0; i<m_outline.n_points; ++i) {
        printf("   - %d -- %.2f, %.2f, (%d, %d)\n", i,
               (double) (m_outline.points[i].x / 64.0),
               (double) (m_outline.points[i].y / 64.0),
               (int) m_outline.points[i].x, (int) m_outline.points[i].y);
    }
#endif
}

void QOutlineMapper::clipElements(const QPointF *elements,
                                    const QPainterPath::ElementType *types,
                                    int element_count)
{
    // We could save a bit of time by actually implementing them fully
    // instead of going through convenience functionallity, but since
    // this part of code hardly every used, it shouldn't matter.

    QPainterPath path;
    if (types) {
        for (int i=0; i<element_count; ++i) {
            switch (types[i]) {
            case QPainterPath::MoveToElement:
                path.moveTo(elements[i]);
                break;

            case QPainterPath::LineToElement:
                path.lineTo(elements[i]);
                break;

            case QPainterPath::CurveToElement:
                path.cubicTo(elements[i], elements[i+1], elements[i+2]);
                i += 2;
                break;
            default:
                break;
            }
        }
    } else {
        path.moveTo(elements[0]);
        for (int i=1; i<element_count; ++i)
            path.lineTo(elements[i]);
    }

    QPainterPath clipPath;
    clipPath.addRect(m_clip_rect);
    QPainterPath clippedPath = path.intersected(clipPath);
    uint old_txop = m_txop;
    m_txop = QTransform::TxNone;
    if (clippedPath.isEmpty())
        m_valid = false;
    else
        convertPath(clippedPath);
    m_txop = old_txop;
}

QT_END_NAMESPACE
<commit_msg>Fix compilation on OS X.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $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 "qoutlinemapper_p.h"
#include <private/qpainterpath_p.h>
#include "qmath.h"

#include <stdlib.h>

QT_BEGIN_NAMESPACE

static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;

#define qreal_to_fixed_26_6(f) (int(f * 64))

static const QRectF boundingRect(const QPointF *points, int pointCount)
{
    const QPointF *e = points;
    const QPointF *last = points + pointCount;
    qreal minx, maxx, miny, maxy;
    minx = maxx = e->x();
    miny = maxy = e->y();
    while (++e < last) {
        if (e->x() < minx)
            minx = e->x();
        else if (e->x() > maxx)
            maxx = e->x();
        if (e->y() < miny)
            miny = e->y();
        else if (e->y() > maxy)
            maxy = e->y();
    }
    return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
}

QT_FT_Outline *QOutlineMapper::convertPath(const QPainterPath &path)
{
    Q_ASSERT(!path.isEmpty());
    int elmCount = path.elementCount();
#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::convertPath(), size=%d\n", elmCount);
#endif
    beginOutline(path.fillRule());

    for (int index=0; index<elmCount; ++index) {
        const QPainterPath::Element &elm = path.elementAt(index);

        switch (elm.type) {

        case QPainterPath::MoveToElement:
            if (index == elmCount - 1)
                continue;
            moveTo(elm);
            break;

        case QPainterPath::LineToElement:
            lineTo(elm);
            break;

        case QPainterPath::CurveToElement:
            curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
            index += 2;
            break;

        default:
            break; // This will never hit..
        }
    }

    endOutline();
    return outline();
}

QT_FT_Outline *QOutlineMapper::convertPath(const QVectorPath &path)
{
    int count = path.elementCount();

#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::convertPath(VP), size=%d\n", count);
#endif
    beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);

    if (path.elements()) {
        // TODO: if we do closing of subpaths in convertElements instead we
        // could avoid this loop
        const QPainterPath::ElementType *elements = path.elements();
        const QPointF *points = reinterpret_cast<const QPointF *>(path.points());

        for (int index = 0; index < count; ++index) {
            switch (elements[index]) {
                case QPainterPath::MoveToElement:
                    if (index == count - 1)
                        continue;
                    moveTo(points[index]);
                    break;

                case QPainterPath::LineToElement:
                    lineTo(points[index]);
                    break;

                case QPainterPath::CurveToElement:
                    curveTo(points[index], points[index+1], points[index+2]);
                    index += 2;
                    break;

                default:
                    break; // This will never hit..
            }
        }

    } else {
        // ### We can kill this copying and just use the buffer straight...

        m_elements.resize(count);
        memcpy(m_elements.data(), path.points(), count* sizeof(QPointF));

        m_element_types.resize(0);
    }

    endOutline();
    return outline();
}

void QOutlineMapper::endOutline()
{
    closeSubpath();

    int element_count = m_elements.size();

    if (element_count == 0) {
        memset(&m_outline, 0, sizeof(m_outline));
        return;
    }

    QPointF *elements;

    // Transform the outline
    if (m_txop == QTransform::TxNone) {
        elements = m_elements.data();
    } else {
        if (m_txop == QTransform::TxTranslate) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
            }
        } else if (m_txop == QTransform::TxScale) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
            }
        } else if (m_txop < QTransform::TxProject) {
            for (int i=0; i<m_elements.size(); ++i) {
                const QPointF &e = m_elements.at(i);
                m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
                                          m_m22 * e.y() + m_m12 * e.x() + m_dy);
            }
        } else {
            const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.data());
            QPainterPath path = vp.convertToPainterPath();
            path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
            if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
                path.setFillRule(Qt::WindingFill);
            uint old_txop = m_txop;
            m_txop = QTransform::TxNone;
            if (path.isEmpty())
                m_valid = false;
            else
                convertPath(path);
            m_txop = old_txop;
            return;
        }
        elements = m_elements_dev.data();
    }

    if (m_round_coords) {
        // round coordinates to match outlines drawn with drawLine_midpoint_i
        for (int i = 0; i < m_elements.size(); ++i)
            elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
                                  qFloor(elements[i].y() + aliasedCoordinateDelta));
    }

    controlPointRect = boundingRect(elements, element_count);

#ifdef QT_DEBUG_CONVERT
    printf(" - control point rect (%.2f, %.2f) %.2f x %.2f\n",
           controlPointRect.x(), controlPointRect.y(),
           controlPointRect.width(), controlPointRect.height());
#endif

    // Check for out of dev bounds...
    const bool do_clip = (controlPointRect.left() < -QT_RASTER_COORD_LIMIT
                          || controlPointRect.right() > QT_RASTER_COORD_LIMIT
                          || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
                          || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT);

    if (do_clip) {
        clipElements(elements, elementTypes(), element_count);
    } else {
        convertElements(elements, elementTypes(), element_count);
    }
}

void QOutlineMapper::convertElements(const QPointF *elements,
                                       const QPainterPath::ElementType *types,
                                       int element_count)
{

    if (types) {
        // Translate into FT coords
        const QPointF *e = elements;
        for (int i=0; i<element_count; ++i) {
            switch (*types) {
            case QPainterPath::MoveToElement:
                {
                    QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                              qreal_to_fixed_26_6(e->y()) };
                    if (i != 0)
                        m_contours << m_points.size() - 1;
                    m_points << pt_fixed;
                    m_tags <<  QT_FT_CURVE_TAG_ON;
                }
                break;

            case QPainterPath::LineToElement:
                {
                    QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                              qreal_to_fixed_26_6(e->y()) };
                    m_points << pt_fixed;
                    m_tags << QT_FT_CURVE_TAG_ON;
                }
                break;

            case QPainterPath::CurveToElement:
                {
                    QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
                                               qreal_to_fixed_26_6(e->y()) };
                    ++e;
                    QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
                                               qreal_to_fixed_26_6((e)->y()) };
                    ++e;
                    QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
                                              qreal_to_fixed_26_6((e)->y()) };

                    m_points << cp1_fixed << cp2_fixed << ep_fixed;
                    m_tags << QT_FT_CURVE_TAG_CUBIC
                           << QT_FT_CURVE_TAG_CUBIC
                           << QT_FT_CURVE_TAG_ON;

                    types += 2;
                    i += 2;
                }
                break;
            default:
                break;
            }
            ++types;
            ++e;
        }
    } else {
        // Plain polygon...
        const QPointF *last = elements + element_count;
        const QPointF *e = elements;
        while (e < last) {
            QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
                                      qreal_to_fixed_26_6(e->y()) };
            m_points << pt_fixed;
            m_tags << QT_FT_CURVE_TAG_ON;
            ++e;
        }
    }

    // close the very last subpath
    m_contours << m_points.size() - 1;

    m_outline.n_contours = m_contours.size();
    m_outline.n_points = m_points.size();

    m_outline.points = m_points.data();
    m_outline.tags = m_tags.data();
    m_outline.contours = m_contours.data();

#ifdef QT_DEBUG_CONVERT
    printf("QOutlineMapper::endOutline\n");

    printf(" - contours: %d\n", m_outline.n_contours);
    for (int i=0; i<m_outline.n_contours; ++i) {
        printf("   - %d\n", m_outline.contours[i]);
    }

    printf(" - points: %d\n", m_outline.n_points);
    for (int i=0; i<m_outline.n_points; ++i) {
        printf("   - %d -- %.2f, %.2f, (%d, %d)\n", i,
               (double) (m_outline.points[i].x / 64.0),
               (double) (m_outline.points[i].y / 64.0),
               (int) m_outline.points[i].x, (int) m_outline.points[i].y);
    }
#endif
}

void QOutlineMapper::clipElements(const QPointF *elements,
                                    const QPainterPath::ElementType *types,
                                    int element_count)
{
    // We could save a bit of time by actually implementing them fully
    // instead of going through convenience functionallity, but since
    // this part of code hardly every used, it shouldn't matter.

    QPainterPath path;
    if (types) {
        for (int i=0; i<element_count; ++i) {
            switch (types[i]) {
            case QPainterPath::MoveToElement:
                path.moveTo(elements[i]);
                break;

            case QPainterPath::LineToElement:
                path.lineTo(elements[i]);
                break;

            case QPainterPath::CurveToElement:
                path.cubicTo(elements[i], elements[i+1], elements[i+2]);
                i += 2;
                break;
            default:
                break;
            }
        }
    } else {
        path.moveTo(elements[0]);
        for (int i=1; i<element_count; ++i)
            path.lineTo(elements[i]);
    }

    QPainterPath clipPath;
    clipPath.addRect(m_clip_rect);
    QPainterPath clippedPath = path.intersected(clipPath);
    uint old_txop = m_txop;
    m_txop = QTransform::TxNone;
    if (clippedPath.isEmpty())
        m_valid = false;
    else
        convertPath(clippedPath);
    m_txop = old_txop;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include "Simon.h"

Simon::Simon(){

}

void Simon::setup() {
    b = InternetButton();
    solution = new Position[0];
    solutionSize = 0;

    state = Welcome;

    difficulty = 3;
    successMax = 0;
    successCount = 0;

    RGB.control(true);
    this.b.begin();
    this.b.allLedsOff();
}

void Simon::loop() {
    switch (state) {
        case Welcome:
            welcome();
            break;
        case Ready:
            ready();
            break;
        case Showing:
            show();
            break;
        case ListeningDown:
            listenDown();
            break;
        case ListeningUp:
            listenUp();
            break;
        case CompleteSuccess:
            celebrate();
            break;
        case Failed:
            fail();
            break;
    }
}

void Simon::welcome() {
    b.playSong("C4,8,E4,8,G4,8,C5,8,G5,4");
    b.allLedsOn(0,20,20);
    delay(500);
    b.allLedsOff();

    flash(Top, true, true);
    flash(Right, true, true);
    flash(Bottom, true, true);
    flash(Left, true, true);
    state = Ready;
}

void Simon::demo() {
      b.ledOn(11, 25, 0, 0);
            b.ledOn(1, 25, 0, 0);

            b.ledOn(2, 0, 0, 25);
            b.ledOn(3, 0, 0, 25);
            b.ledOn(4, 0, 0, 25);

            b.ledOn(5, 12, 12, 0);
            b.ledOn(6, 12, 12, 0);
            b.ledOn(7, 12, 12, 0);

            b.ledOn(8, 0, 25, 0);
            b.ledOn(9, 0, 25, 0);
            b.ledOn(10, 0, 25, 0);

    delay(10000);
}

void Simon::ready() {
    Position read = anyButtonOn();

    switch (read) {
        case None:
            return;
        case Top:
            difficulty = 4;
            break;
        case Right:
            difficulty = 9;
            break;
        case Bottom:
            difficulty = 14;
            break;
        case Left:
            difficulty = 29;
            break;
    }
    celebrate();
}

void Simon::setColor() {
    if (difficulty < 10) {
        RGB.color(255, 0, 0);
        return;
    }
    if (difficulty < 15) {
        RGB.color(120, 120, 0);
        return;
    }
    if (difficulty < 30) {
        RGB.color(0, 255, 0);
        return;
    }

    RGB.color(0, 0, 255);
}

void Simon::start() {
    //b.allLedsOn(0,20,20);
    //delay(500);
    //b.allLedsOff();

    successMax = 0;

    generate(difficulty);
    setColor();

    state = Showing;
}

void Simon::generate(int size) {
    solutionSize = size;
    solution = new Position[solutionSize];

    for (int i = 0; i < size; i++) {
        while(true) {
            Position next = (Position) random(4);

            if (i-2 >= 0 && next == solution[i-1] && next == solution[i-2]) {
                continue;
            }

            solution[i] = next;
            break;
        }
    }
}

void Simon::show() {
    for (int i = 0; i < successMax + 1; i++) {
        Position next = solution[i];
        flash(next, true, true);
        delay(100);
    }

    successCount = 0;
    state = ListeningDown;
}

void Simon::listenDown() {
    Position read = anyButtonOn();
    if (read == None) {
        return;
    }

    if (solution[successCount] == read) {
        flash(read, false, true);
        state = ListeningUp;
        return;
    }

    state = Failed;
}

void Simon::listenUp() {
    Position read = anyButtonOn();

    if (read == None) {
        unflash();

        successCount++;

        if (successCount > successMax) {
                if (successCount == solutionSize) {
                    state = CompleteSuccess;
                    return;
                }

            successMax++;

            delay(1000);
            state = Showing;
            return;
        }

        state = ListeningDown;
        return;
    }

     if (solution[successCount] != read) {
         state = Failed;
         return;
     }
}

Position Simon::anyButtonOn() {
    if (b.buttonOn(1)) {
        return Top;
    }
    if (b.buttonOn(2)) {
        return Right;
    }
    if (b.buttonOn(3)) {
        return Bottom;
    }
    if (b.buttonOn(4)) {
        return Left;
    }
    return None;
}

void Simon::celebrate() {
    flash(Top, false, false);
    flash(Right, false, false);
    flash(Bottom, false, false);
    flash(Left, false, false);
    b.playSong("C4,8,E4,8,G4,8,C5,8,G5,4");

    //b.allLedsOn(0, 255, 0);
    delay(300);
    b.allLedsOff();

    delay(500);
    difficulty++;
    start();
}

void Simon::flash(Position p, bool timed, bool sound) {
    switch (p) {
        case Top:
            b.ledOn(11, 255, 0, 0);
            b.ledOn(1, 255, 0, 0);
            if (sound) { b.playNote("C4",4); }
            break;
        case Right:
            b.ledOn(2, 0, 0, 255);
            b.ledOn(3, 0, 0, 255);
            b.ledOn(4, 0, 0, 255);
            if (sound) { b.playNote("E4",4); }
            break;
        case Bottom:
            b.ledOn(5, 120, 120, 0);
            b.ledOn(6, 120, 120, 0);
            b.ledOn(7, 120, 120, 0);
            if (sound) { b.playNote("G4",4); }
            break;
        case Left:
            b.ledOn(8, 0, 255, 0);
            b.ledOn(9, 0, 255, 0);
            b.ledOn(10, 0, 255, 0);
            if (sound) { b.playNote("C5",4); }
            break;
        case None:
            delay(100);
            return;
    }
    if (timed) {
        b.allLedsOff();
    }
}

void Simon::unflash() {
    // TODO: stop sound
    b.allLedsOff();
}

void Simon::fail() {
    flash(solution[successCount], false, false);
    b.playNote("C2",1);

    for( int a = 0; a < 3; a = a + 1 )
    {

        b.allLedsOn(255,0,0);
        RGB.brightness(255);
        delay(500);
        b.allLedsOff();
        RGB.brightness(1);
        delay(500);
    }

    RGB.color(0, 0, 0);
    RGB.brightness(255);
    state = Welcome;
}

<commit_msg>Update Simon.cpp<commit_after>#include "Simon.h"

Simon::Simon(){

}

void Simon::setup() {
    b = InternetButton();
    solution = new Position[0];
    solutionSize = 0;

    state = Welcome;

    difficulty = 3;
    successMax = 0;
    successCount = 0;

    RGB.control(true);
    b.begin();
    b.allLedsOff();
}

void Simon::loop() {
    switch (state) {
        case Welcome:
            welcome();
            break;
        case Ready:
            ready();
            break;
        case Showing:
            show();
            break;
        case ListeningDown:
            listenDown();
            break;
        case ListeningUp:
            listenUp();
            break;
        case CompleteSuccess:
            celebrate();
            break;
        case Failed:
            fail();
            break;
    }
}

void Simon::welcome() {
    b.playSong("C4,8,E4,8,G4,8,C5,8,G5,4");
    b.allLedsOn(0,20,20);
    delay(500);
    b.allLedsOff();

    flash(Top, true, true);
    flash(Right, true, true);
    flash(Bottom, true, true);
    flash(Left, true, true);
    state = Ready;
}

void Simon::demo() {
      b.ledOn(11, 25, 0, 0);
            b.ledOn(1, 25, 0, 0);

            b.ledOn(2, 0, 0, 25);
            b.ledOn(3, 0, 0, 25);
            b.ledOn(4, 0, 0, 25);

            b.ledOn(5, 12, 12, 0);
            b.ledOn(6, 12, 12, 0);
            b.ledOn(7, 12, 12, 0);

            b.ledOn(8, 0, 25, 0);
            b.ledOn(9, 0, 25, 0);
            b.ledOn(10, 0, 25, 0);

    delay(10000);
}

void Simon::ready() {
    Position read = anyButtonOn();

    switch (read) {
        case None:
            return;
        case Top:
            difficulty = 4;
            break;
        case Right:
            difficulty = 9;
            break;
        case Bottom:
            difficulty = 14;
            break;
        case Left:
            difficulty = 29;
            break;
    }
    celebrate();
}

void Simon::setColor() {
    if (difficulty < 10) {
        RGB.color(255, 0, 0);
        return;
    }
    if (difficulty < 15) {
        RGB.color(120, 120, 0);
        return;
    }
    if (difficulty < 30) {
        RGB.color(0, 255, 0);
        return;
    }

    RGB.color(0, 0, 255);
}

void Simon::start() {
    //b.allLedsOn(0,20,20);
    //delay(500);
    //b.allLedsOff();

    successMax = 0;

    generate(difficulty);
    setColor();

    state = Showing;
}

void Simon::generate(int size) {
    solutionSize = size;
    solution = new Position[solutionSize];

    for (int i = 0; i < size; i++) {
        while(true) {
            Position next = (Position) random(4);

            if (i-2 >= 0 && next == solution[i-1] && next == solution[i-2]) {
                continue;
            }

            solution[i] = next;
            break;
        }
    }
}

void Simon::show() {
    for (int i = 0; i < successMax + 1; i++) {
        Position next = solution[i];
        flash(next, true, true);
        delay(100);
    }

    successCount = 0;
    state = ListeningDown;
}

void Simon::listenDown() {
    Position read = anyButtonOn();
    if (read == None) {
        return;
    }

    if (solution[successCount] == read) {
        flash(read, false, true);
        state = ListeningUp;
        return;
    }

    state = Failed;
}

void Simon::listenUp() {
    Position read = anyButtonOn();

    if (read == None) {
        unflash();

        successCount++;

        if (successCount > successMax) {
                if (successCount == solutionSize) {
                    state = CompleteSuccess;
                    return;
                }

            successMax++;

            delay(1000);
            state = Showing;
            return;
        }

        state = ListeningDown;
        return;
    }

     if (solution[successCount] != read) {
         state = Failed;
         return;
     }
}

Position Simon::anyButtonOn() {
    if (b.buttonOn(1)) {
        return Top;
    }
    if (b.buttonOn(2)) {
        return Right;
    }
    if (b.buttonOn(3)) {
        return Bottom;
    }
    if (b.buttonOn(4)) {
        return Left;
    }
    return None;
}

void Simon::celebrate() {
    flash(Top, false, false);
    flash(Right, false, false);
    flash(Bottom, false, false);
    flash(Left, false, false);
    b.playSong("C4,8,E4,8,G4,8,C5,8,G5,4");

    //b.allLedsOn(0, 255, 0);
    delay(300);
    b.allLedsOff();

    delay(500);
    difficulty++;
    start();
}

void Simon::flash(Position p, bool timed, bool sound) {
    switch (p) {
        case Top:
            b.ledOn(11, 255, 0, 0);
            b.ledOn(1, 255, 0, 0);
            if (sound) { b.playNote("C4",4); }
            break;
        case Right:
            b.ledOn(2, 0, 0, 255);
            b.ledOn(3, 0, 0, 255);
            b.ledOn(4, 0, 0, 255);
            if (sound) { b.playNote("E4",4); }
            break;
        case Bottom:
            b.ledOn(5, 120, 120, 0);
            b.ledOn(6, 120, 120, 0);
            b.ledOn(7, 120, 120, 0);
            if (sound) { b.playNote("G4",4); }
            break;
        case Left:
            b.ledOn(8, 0, 255, 0);
            b.ledOn(9, 0, 255, 0);
            b.ledOn(10, 0, 255, 0);
            if (sound) { b.playNote("C5",4); }
            break;
        case None:
            delay(100);
            return;
    }
    if (timed) {
        b.allLedsOff();
    }
}

void Simon::unflash() {
    // TODO: stop sound
    b.allLedsOff();
}

void Simon::fail() {
    flash(solution[successCount], false, false);
    b.playNote("C2",1);

    for( int a = 0; a < 3; a = a + 1 )
    {

        b.allLedsOn(255,0,0);
        RGB.brightness(255);
        delay(500);
        b.allLedsOff();
        RGB.brightness(1);
        delay(500);
    }

    RGB.color(0, 0, 0);
    RGB.brightness(255);
    state = Welcome;
}

<|endoftext|>


<commit_before>#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <gphoto2/gphoto2.h>

#include <cstring>
#include <iostream>

using emscripten::val;

template <typename T, auto Deleter>
using gpp_unique_ptr =
    std::unique_ptr<T, std::integral_constant<decltype(Deleter), Deleter>>;

using GPPWidget = gpp_unique_ptr<CameraWidget, gp_widget_unref>;

void gpp_try(int status) {
  if (status != GP_OK) {
    throw std::runtime_error(gp_result_as_string(status));
  }
}

void gpp_log_error(GPContext *context, const char *text, void *data) {
  std::cerr << text << std::endl;
}

#define GPP_CALL(RET, EXPR) \
  ({                        \
    RET OUT;                \
    RET *_ = &OUT;          \
    gpp_try(EXPR);          \
    OUT;                    \
  })

EM_JS([[noreturn]] void, throw_msg, (const char *msg),
      { throw new Error(UTF8ToString(msg)); });

template <typename Func>
auto gpp_rethrow(Func func) {
  try {
    return func();
  } catch (std::exception &e) {
    throw_msg(e.what());
  }
}

const thread_local val Uint8Array = val::global("Uint8Array");
const thread_local val Blob = val::global("Blob");
const thread_local val File = val::global("File");
const thread_local val arrayOf = val::global("Array")["of"];

class Context {
 public:
  Context() : camera(nullptr), context(nullptr) {
    gpp_rethrow([=]() {
      camera.reset(GPP_CALL(Camera *, gp_camera_new(_)));
      context.reset(gp_context_new());
      gp_context_set_error_func(context.get(), gpp_log_error, nullptr);
      gpp_try(gp_camera_init(camera.get(), context.get()));
    });
  }

  val supportedOps() {
    auto ops =
        GPP_CALL(CameraAbilities, gp_camera_get_abilities(camera.get(), _))
            .operations;

    val result = val::object();
    result.set("captureImage", (ops & GP_OPERATION_CAPTURE_IMAGE) != 0);
    result.set("captureVideo", (ops & GP_OPERATION_CAPTURE_VIDEO) != 0);
    result.set("captureAudio", (ops & GP_OPERATION_CAPTURE_AUDIO) != 0);
    result.set("capturePreview", (ops & GP_OPERATION_CAPTURE_PREVIEW) != 0);
    result.set("config", (ops & GP_OPERATION_CONFIG) != 0);
    result.set("triggerCapture", (ops & GP_OPERATION_TRIGGER_CAPTURE) != 0);
    return result;
  }

  bool hasPendingEvent() {
    return gpp_rethrow([=]() {
      CameraEventType event_type = GP_EVENT_UNKNOWN;
      gpp_unique_ptr<void, free> event_data(GPP_CALL(
          void *, gp_camera_wait_for_event(camera.get(), 0, &event_type, _,
                                           context.get())));
      return event_type != GP_EVENT_TIMEOUT;
    });
  }

  val configToJS() {
    return gpp_rethrow([=]() {
      GPPWidget config(
          GPP_CALL(CameraWidget *,
                   gp_camera_get_config(camera.get(), _, context.get())));
      return walk_config(config.get()).second;
    });
  }

  void setConfigValue(std::string name, val value) {
    gpp_rethrow([=]() {
      GPPWidget widget(GPP_CALL(
          CameraWidget *, gp_camera_get_single_config(
                              camera.get(), name.c_str(), _, context.get())));
      auto type =
          GPP_CALL(CameraWidgetType, gp_widget_get_type(widget.get(), _));
      switch (type) {
        case GP_WIDGET_RANGE: {
          float number = value.as<float>();
          gpp_try(gp_widget_set_value(widget.get(), &number));
          break;
        }
        case GP_WIDGET_MENU:
        case GP_WIDGET_RADIO:
        case GP_WIDGET_TEXT: {
          auto str = value.as<std::string>();
          gpp_try(gp_widget_set_value(widget.get(), str.c_str()));
          break;
        }
        case GP_WIDGET_TOGGLE: {
          int on = value.as<bool>() ? 1 : 0;
          gpp_try(gp_widget_set_value(widget.get(), &on));
          break;
        }
        case GP_WIDGET_DATE: {
          auto seconds = static_cast<int>(value.as<double>() / 1000);
          gpp_try(gp_widget_set_value(widget.get(), &seconds));
          break;
        }
        default: {
          throw std::logic_error("unimplemented");
        }
      }
      gpp_try(gp_camera_set_single_config(camera.get(), name.c_str(),
                                          widget.get(), context.get()));
    });
  }

  val capturePreviewAsBlob() {
    return gpp_rethrow([=]() {
      auto &file = get_file();

      gpp_try(gp_camera_capture_preview(camera.get(), &file, context.get()));

      auto params = blob_chunks_and_opts(file);
      return Blob.new_(std::move(params.first), std::move(params.second));
    });
  }

  val captureImageAsFile() {
    return gpp_rethrow([=]() {
      auto &file = get_file();

      {
        struct TempCameraFile {
          Camera &camera;
          GPContext &context;
          CameraFilePath path;

          ~TempCameraFile() {
            gp_camera_file_delete(&camera, path.folder, path.name, &context);
          }
        };

        TempCameraFile camera_file{
            .camera = *camera,
            .context = *context,
        };

        strcpy(camera_file.path.folder, "/");
        strcpy(camera_file.path.name, "web-gphoto2");

        gpp_try(gp_camera_capture(camera.get(), GP_CAPTURE_IMAGE,
                                  &camera_file.path, context.get()));

        gpp_try(gp_camera_file_get(camera.get(), camera_file.path.folder,
                                   camera_file.path.name, GP_FILE_TYPE_NORMAL,
                                   &file, context.get()));
      }

      gpp_try(gp_file_set_name(&file, "image."));
      gpp_try(gp_file_adjust_name_for_mime_type(&file));
      auto name = val(GPP_CALL(const char *, gp_file_get_name(&file, _)));

      auto params = blob_chunks_and_opts(file);
      return File.new_(std::move(params.first), std::move(name),
                       std::move(params.second));
    });
  }

 private:
  gpp_unique_ptr<Camera, gp_camera_unref> camera;
  gpp_unique_ptr<GPContext, gp_context_unref> context;
  gpp_unique_ptr<CameraFile, gp_file_unref> file;

  static std::pair<val, val> walk_config(CameraWidget *widget) {
    val result = val::object();

    val name(GPP_CALL(const char *, gp_widget_get_name(widget, _)));
    result.set("name", name);
    result.set("info", GPP_CALL(const char *, gp_widget_get_info(widget, _)));
    result.set("label", GPP_CALL(const char *, gp_widget_get_label(widget, _)));
    result.set("readonly",
               GPP_CALL(int, gp_widget_get_readonly(widget, _)) != 0);

    auto type = GPP_CALL(CameraWidgetType, gp_widget_get_type(widget, _));

    switch (type) {
      case GP_WIDGET_RANGE: {
        result.set("type", "range");
        result.set("value", GPP_CALL(float, gp_widget_get_value(widget, _)));

        float min, max, step;
        gpp_try(gp_widget_get_range(widget, &min, &max, &step));
        result.set("min", min);
        result.set("max", max);
        result.set("step", step);

        break;
      }
      case GP_WIDGET_MENU:
      case GP_WIDGET_RADIO: {
        result.set("type", type == GP_WIDGET_MENU ? "menu" : "radio");
        result.set("value",
                   GPP_CALL(const char *, gp_widget_get_value(widget, _)));

        val choices = val::array();
        for (int i = 0, n = gp_widget_count_choices(widget); i < n; i++) {
          choices.call<void>(
              "push",
              val(GPP_CALL(const char *, gp_widget_get_choice(widget, i, _))));
        }
        result.set("choices", choices);

        break;
      }
      case GP_WIDGET_TOGGLE: {
        result.set("type", "toggle");
        result.set("value", GPP_CALL(int, gp_widget_get_value(widget, _)) != 0);

        break;
      }
      case GP_WIDGET_TEXT: {
        result.set("type", "text");
        result.set("value",
                   GPP_CALL(const char *, gp_widget_get_value(widget, _)));

        break;
      }
      case GP_WIDGET_WINDOW:
      case GP_WIDGET_SECTION: {
        result.set("type", type == GP_WIDGET_WINDOW ? "window" : "section");

        val children = val::object();
        for (int i = 0, n = gp_widget_count_children(widget); i < n; i++) {
          auto child =
              GPP_CALL(CameraWidget *, gp_widget_get_child(widget, i, _));
          auto kv = walk_config(child);
          children.set(kv.first, kv.second);
        }
        result.set("children", children);

        break;
      }
      case GP_WIDGET_DATE: {
        auto seconds = GPP_CALL(int, gp_widget_get_value(widget, _));
        result.set("type", "datetime");
        result.set("value", static_cast<double>(seconds) * 1000);

        break;
      }
      default: {
        throw std::logic_error("unimplemented");
      }
    }

    return {name, result};
  }

  CameraFile &get_file() {
    if (file.get() == nullptr) {
      file.reset(GPP_CALL(CameraFile *, gp_file_new(_)));
    }
    return *file;
  }

  std::pair<val, val> blob_chunks_and_opts(CameraFile &file) {
    auto mime_type = GPP_CALL(const char *, gp_file_get_mime_type(&file, _));

    const char *data;
    unsigned long size;
    gpp_try(gp_file_get_data_and_size(&file, &data, &size));

    val blob_opts = val::object();
    blob_opts.set("type", mime_type);

    return {arrayOf(Uint8Array.new_(emscripten::typed_memory_view(size, data))),
            std::move(blob_opts)};
  }
};

EMSCRIPTEN_BINDINGS(gphoto2_js_api) {
  emscripten::enum_<CameraOperation>("SupportedOps")
      .value("None", GP_OPERATION_NONE)
      .value("CaptureImage", GP_OPERATION_CAPTURE_IMAGE)
      .value("CaptureVideo", GP_OPERATION_CAPTURE_VIDEO)
      .value("CaptureAudio", GP_OPERATION_CAPTURE_AUDIO)
      .value("CapturePreview", GP_OPERATION_CAPTURE_PREVIEW)
      .value("Config", GP_OPERATION_CONFIG)
      .value("TriggerCapture", GP_OPERATION_TRIGGER_CAPTURE);

  emscripten::class_<Context>("Context")
      .constructor<>()
      .function("configToJS", &Context::configToJS)
      .function("setConfigValue", &Context::setConfigValue)
      .function("capturePreviewAsBlob", &Context::capturePreviewAsBlob)
      .function("captureImageAsFile", &Context::captureImageAsFile)
      .function("hasPendingEvent", &Context::hasPendingEvent)
      .function("triggerCapture", &Context::triggerCapture)
      .function("supportedOps", &Context::supportedOps);
}
<commit_msg>Remove triggerCapture<commit_after>#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <gphoto2/gphoto2.h>

#include <cstring>
#include <iostream>

using emscripten::val;

template <typename T, auto Deleter>
using gpp_unique_ptr =
    std::unique_ptr<T, std::integral_constant<decltype(Deleter), Deleter>>;

using GPPWidget = gpp_unique_ptr<CameraWidget, gp_widget_unref>;

void gpp_try(int status) {
  if (status != GP_OK) {
    throw std::runtime_error(gp_result_as_string(status));
  }
}

void gpp_log_error(GPContext *context, const char *text, void *data) {
  std::cerr << text << std::endl;
}

#define GPP_CALL(RET, EXPR) \
  ({                        \
    RET OUT;                \
    RET *_ = &OUT;          \
    gpp_try(EXPR);          \
    OUT;                    \
  })

EM_JS([[noreturn]] void, throw_msg, (const char *msg),
      { throw new Error(UTF8ToString(msg)); });

template <typename Func>
auto gpp_rethrow(Func func) {
  try {
    return func();
  } catch (std::exception &e) {
    throw_msg(e.what());
  }
}

const thread_local val Uint8Array = val::global("Uint8Array");
const thread_local val Blob = val::global("Blob");
const thread_local val File = val::global("File");
const thread_local val arrayOf = val::global("Array")["of"];

class Context {
 public:
  Context() : camera(nullptr), context(nullptr) {
    gpp_rethrow([=]() {
      camera.reset(GPP_CALL(Camera *, gp_camera_new(_)));
      context.reset(gp_context_new());
      gp_context_set_error_func(context.get(), gpp_log_error, nullptr);
      gpp_try(gp_camera_init(camera.get(), context.get()));
    });
  }

  val supportedOps() {
    auto ops =
        GPP_CALL(CameraAbilities, gp_camera_get_abilities(camera.get(), _))
            .operations;

    val result = val::object();
    result.set("captureImage", (ops & GP_OPERATION_CAPTURE_IMAGE) != 0);
    result.set("captureVideo", (ops & GP_OPERATION_CAPTURE_VIDEO) != 0);
    result.set("captureAudio", (ops & GP_OPERATION_CAPTURE_AUDIO) != 0);
    result.set("capturePreview", (ops & GP_OPERATION_CAPTURE_PREVIEW) != 0);
    result.set("config", (ops & GP_OPERATION_CONFIG) != 0);
    result.set("triggerCapture", (ops & GP_OPERATION_TRIGGER_CAPTURE) != 0);
    return result;
  }

  bool hasPendingEvent() {
    return gpp_rethrow([=]() {
      CameraEventType event_type = GP_EVENT_UNKNOWN;
      gpp_unique_ptr<void, free> event_data(GPP_CALL(
          void *, gp_camera_wait_for_event(camera.get(), 0, &event_type, _,
                                           context.get())));
      return event_type != GP_EVENT_TIMEOUT;
    });
  }

  val configToJS() {
    return gpp_rethrow([=]() {
      GPPWidget config(
          GPP_CALL(CameraWidget *,
                   gp_camera_get_config(camera.get(), _, context.get())));
      return walk_config(config.get()).second;
    });
  }

  void setConfigValue(std::string name, val value) {
    gpp_rethrow([=]() {
      GPPWidget widget(GPP_CALL(
          CameraWidget *, gp_camera_get_single_config(
                              camera.get(), name.c_str(), _, context.get())));
      auto type =
          GPP_CALL(CameraWidgetType, gp_widget_get_type(widget.get(), _));
      switch (type) {
        case GP_WIDGET_RANGE: {
          float number = value.as<float>();
          gpp_try(gp_widget_set_value(widget.get(), &number));
          break;
        }
        case GP_WIDGET_MENU:
        case GP_WIDGET_RADIO:
        case GP_WIDGET_TEXT: {
          auto str = value.as<std::string>();
          gpp_try(gp_widget_set_value(widget.get(), str.c_str()));
          break;
        }
        case GP_WIDGET_TOGGLE: {
          int on = value.as<bool>() ? 1 : 0;
          gpp_try(gp_widget_set_value(widget.get(), &on));
          break;
        }
        case GP_WIDGET_DATE: {
          auto seconds = static_cast<int>(value.as<double>() / 1000);
          gpp_try(gp_widget_set_value(widget.get(), &seconds));
          break;
        }
        default: {
          throw std::logic_error("unimplemented");
        }
      }
      gpp_try(gp_camera_set_single_config(camera.get(), name.c_str(),
                                          widget.get(), context.get()));
    });
  }

  val capturePreviewAsBlob() {
    return gpp_rethrow([=]() {
      auto &file = get_file();

      gpp_try(gp_camera_capture_preview(camera.get(), &file, context.get()));

      auto params = blob_chunks_and_opts(file);
      return Blob.new_(std::move(params.first), std::move(params.second));
    });
  }

  val captureImageAsFile() {
    return gpp_rethrow([=]() {
      auto &file = get_file();

      {
        struct TempCameraFile {
          Camera &camera;
          GPContext &context;
          CameraFilePath path;

          ~TempCameraFile() {
            gp_camera_file_delete(&camera, path.folder, path.name, &context);
          }
        };

        TempCameraFile camera_file{
            .camera = *camera,
            .context = *context,
        };

        strcpy(camera_file.path.folder, "/");
        strcpy(camera_file.path.name, "web-gphoto2");

        gpp_try(gp_camera_capture(camera.get(), GP_CAPTURE_IMAGE,
                                  &camera_file.path, context.get()));

        gpp_try(gp_camera_file_get(camera.get(), camera_file.path.folder,
                                   camera_file.path.name, GP_FILE_TYPE_NORMAL,
                                   &file, context.get()));
      }

      gpp_try(gp_file_set_name(&file, "image."));
      gpp_try(gp_file_adjust_name_for_mime_type(&file));
      auto name = val(GPP_CALL(const char *, gp_file_get_name(&file, _)));

      auto params = blob_chunks_and_opts(file);
      return File.new_(std::move(params.first), std::move(name),
                       std::move(params.second));
    });
  }

 private:
  gpp_unique_ptr<Camera, gp_camera_unref> camera;
  gpp_unique_ptr<GPContext, gp_context_unref> context;
  gpp_unique_ptr<CameraFile, gp_file_unref> file;

  static std::pair<val, val> walk_config(CameraWidget *widget) {
    val result = val::object();

    val name(GPP_CALL(const char *, gp_widget_get_name(widget, _)));
    result.set("name", name);
    result.set("info", GPP_CALL(const char *, gp_widget_get_info(widget, _)));
    result.set("label", GPP_CALL(const char *, gp_widget_get_label(widget, _)));
    result.set("readonly",
               GPP_CALL(int, gp_widget_get_readonly(widget, _)) != 0);

    auto type = GPP_CALL(CameraWidgetType, gp_widget_get_type(widget, _));

    switch (type) {
      case GP_WIDGET_RANGE: {
        result.set("type", "range");
        result.set("value", GPP_CALL(float, gp_widget_get_value(widget, _)));

        float min, max, step;
        gpp_try(gp_widget_get_range(widget, &min, &max, &step));
        result.set("min", min);
        result.set("max", max);
        result.set("step", step);

        break;
      }
      case GP_WIDGET_MENU:
      case GP_WIDGET_RADIO: {
        result.set("type", type == GP_WIDGET_MENU ? "menu" : "radio");
        result.set("value",
                   GPP_CALL(const char *, gp_widget_get_value(widget, _)));

        val choices = val::array();
        for (int i = 0, n = gp_widget_count_choices(widget); i < n; i++) {
          choices.call<void>(
              "push",
              val(GPP_CALL(const char *, gp_widget_get_choice(widget, i, _))));
        }
        result.set("choices", choices);

        break;
      }
      case GP_WIDGET_TOGGLE: {
        result.set("type", "toggle");
        result.set("value", GPP_CALL(int, gp_widget_get_value(widget, _)) != 0);

        break;
      }
      case GP_WIDGET_TEXT: {
        result.set("type", "text");
        result.set("value",
                   GPP_CALL(const char *, gp_widget_get_value(widget, _)));

        break;
      }
      case GP_WIDGET_WINDOW:
      case GP_WIDGET_SECTION: {
        result.set("type", type == GP_WIDGET_WINDOW ? "window" : "section");

        val children = val::object();
        for (int i = 0, n = gp_widget_count_children(widget); i < n; i++) {
          auto child =
              GPP_CALL(CameraWidget *, gp_widget_get_child(widget, i, _));
          auto kv = walk_config(child);
          children.set(kv.first, kv.second);
        }
        result.set("children", children);

        break;
      }
      case GP_WIDGET_DATE: {
        auto seconds = GPP_CALL(int, gp_widget_get_value(widget, _));
        result.set("type", "datetime");
        result.set("value", static_cast<double>(seconds) * 1000);

        break;
      }
      default: {
        throw std::logic_error("unimplemented");
      }
    }

    return {name, result};
  }

  CameraFile &get_file() {
    if (file.get() == nullptr) {
      file.reset(GPP_CALL(CameraFile *, gp_file_new(_)));
    }
    return *file;
  }

  std::pair<val, val> blob_chunks_and_opts(CameraFile &file) {
    auto mime_type = GPP_CALL(const char *, gp_file_get_mime_type(&file, _));

    const char *data;
    unsigned long size;
    gpp_try(gp_file_get_data_and_size(&file, &data, &size));

    val blob_opts = val::object();
    blob_opts.set("type", mime_type);

    return {arrayOf(Uint8Array.new_(emscripten::typed_memory_view(size, data))),
            std::move(blob_opts)};
  }
};

EMSCRIPTEN_BINDINGS(gphoto2_js_api) {
  emscripten::enum_<CameraOperation>("SupportedOps")
      .value("None", GP_OPERATION_NONE)
      .value("CaptureImage", GP_OPERATION_CAPTURE_IMAGE)
      .value("CaptureVideo", GP_OPERATION_CAPTURE_VIDEO)
      .value("CaptureAudio", GP_OPERATION_CAPTURE_AUDIO)
      .value("CapturePreview", GP_OPERATION_CAPTURE_PREVIEW)
      .value("Config", GP_OPERATION_CONFIG)
      .value("TriggerCapture", GP_OPERATION_TRIGGER_CAPTURE);

  emscripten::class_<Context>("Context")
      .constructor<>()
      .function("configToJS", &Context::configToJS)
      .function("setConfigValue", &Context::setConfigValue)
      .function("capturePreviewAsBlob", &Context::capturePreviewAsBlob)
      .function("captureImageAsFile", &Context::captureImageAsFile)
      .function("hasPendingEvent", &Context::hasPendingEvent)
      .function("supportedOps", &Context::supportedOps);
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// simple_optimizer.cpp
//
// Identification: /peloton/src/optimizer/simple_optimizer.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/simple_optimizer.h"
#include "parser/peloton/abstract_parse.h"
#include "planner/abstract_plan.h"
#include "planner/drop_plan.h"
#include "planner/seq_scan_plan.h"

#include "common/logger.h"

#include <memory>

namespace peloton {
namespace planner {
class AbstractPlan;
}
namespace optimizer {

SimpleOptimizer::SimpleOptimizer() {
}
;

SimpleOptimizer::~SimpleOptimizer() {
}
;

std::shared_ptr<planner::AbstractPlan> SimpleOptimizer::BuildPlanTree(
    const std::unique_ptr<parser::AbstractParse>& parse_tree) {

  std::shared_ptr<planner::AbstractPlan> plan_tree;
  if (parse_tree.get() == nullptr)
    return plan_tree;

  std::unique_ptr<planner::AbstractPlan> child_plan = nullptr;

  // TODO: Transform the parse tree

  // One to one Mapping
  auto parse_item_node_type = parse_tree->GetParseNodeType();

  switch (parse_item_node_type) {
    case PARSE_NODE_TYPE_DROP:
      std::unique_ptr<planner::AbstractPlan> DropPlan(new planner::DropPlan("department-table"));
      child_plan = std::move(DropPlan);
      break;

    case PARSE_NODE_TYPE_SCAN:
      std::unique_ptr<planner::AbstractPlan> SeqScanPlan(new planner::SeqScanPlan("department-table"));
      child_plan = std::move(SeqScanPlan);
      break;

    default:
      LOG_INFO("Unsupported Parse Node Type");
  }

// Need to recurse and give base case. for every child in parse tree.

  if (child_plan != nullptr) {
    if (plan_tree != nullptr)
      plan_tree->AddChild(std::move(child_plan));
    else
      plan_tree = std::move(child_plan);
  }

  return plan_tree;
}

}  // namespace optimizer
}  // namespace peloton
<commit_msg>Simple Fixes<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// simple_optimizer.cpp
//
// Identification: /peloton/src/optimizer/simple_optimizer.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/simple_optimizer.h"
#include "parser/peloton/abstract_parse.h"
#include "planner/abstract_plan.h"
#include "planner/drop_plan.h"
#include "planner/seq_scan_plan.h"

#include "common/logger.h"

#include <memory>

namespace peloton {
namespace planner {
class AbstractPlan;
}
namespace optimizer {

SimpleOptimizer::SimpleOptimizer() {
}
;

SimpleOptimizer::~SimpleOptimizer() {
}
;

std::shared_ptr<planner::AbstractPlan> SimpleOptimizer::BuildPlanTree(
    const std::unique_ptr<parser::AbstractParse>& parse_tree) {

  std::shared_ptr<planner::AbstractPlan> plan_tree;
  if (parse_tree.get() == nullptr)
    return plan_tree;

  std::unique_ptr<planner::AbstractPlan> child_plan = nullptr;

  // TODO: Transform the parse tree

  // One to one Mapping
  auto parse_item_node_type = parse_tree->GetParseNodeType();

  switch (parse_item_node_type) {
    case PARSE_NODE_TYPE_DROP:
      std::unique_ptr<planner::AbstractPlan> DropPlan(new planner::DropPlan("department-table"));
      child_plan = std::move(DropPlan);
      break;

    case PARSE_NODE_TYPE_SCAN:
      std::unique_ptr<planner::AbstractPlan> SeqScanPlan(new planner::SeqScanPlan());
      child_plan = std::move(SeqScanPlan);
      break;

    default:
      LOG_INFO("Unsupported Parse Node Type");
  }

// Need to recurse and give base case. for every child in parse tree.

  if (child_plan != nullptr) {
    if (plan_tree != nullptr)
      plan_tree->AddChild(std::move(child_plan));
    else
      plan_tree = std::move(child_plan);
  }

  return plan_tree;
}

}  // namespace optimizer
}  // namespace peloton
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <omp.h>
#include <random>
#include <stdio.h>
#include <string>
#include <time.h>

#include "Neural_Networks.h"

using namespace std;

void Read_MNIST(string training_set_images, string training_set_labels, string test_set_images, string test_set_labels, int number_training, int number_test, float **input, float **output) {
	ifstream file(training_set_images, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 4; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = 0; h < number_training; h++) {
			unsigned char pixel;

			for (int j = 0; j < 28 * 28; j++) {
				file.read((char*)(&pixel), 1);
				input[h][j] = pixel / 255.0;
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + training_set_images + " not found" << endl;
	}

	file.open(training_set_labels, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 2; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = 0; h < number_training; h++) {
			unsigned char label;

			file.read((char*)(&label), 1);

			for (int j = 0; j < 10; j++) {
				output[h][j] = (j == label);
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + training_set_labels + " not found" << endl;
	}

	file.open(test_set_images, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 4; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = number_training; h < number_training + number_test; h++) {
			unsigned char pixel;

			for (int j = 0; j < 28 * 28; j++) {
				file.read((char*)(&pixel), 1);
				input[h][j] = pixel / 255.0;
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + test_set_images + " not found" << endl;
	}

	file.open(test_set_labels, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 2; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = number_training; h < number_training + number_test; h++) {
			unsigned char label;

			file.read((char*)(&label), 1);

			for (int j = 0; j < 10; j++) {
				output[h][j] = (j == label);
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + test_set_labels + " not found" << endl;
	}
}

int main() {
	int batch_size = 128;
	int epochs = 20;
	int number_threads = 6;
	int number_training = 60000;
	int number_test = 10000;
	int number_nodes[] = { 784, 10 };

	float **x_data = new float*[number_training + number_test];
	float **y_data = new float*[number_training + number_test];
	float **x_train = x_data;
	float **y_train = y_data;
	float **x_test = &x_data[number_training];
	float **y_test = &y_data[number_training];

	double learning_rate = 0.5;

	string path;

	Neural_Networks NN = Neural_Networks();

	cout << "path where MNIST handwritten digits dataset is : ";
	getline(cin, path);

	for (int h = 0; h < number_training + number_test; h++) {
		x_data[h] = new float[number_nodes[0]];
		y_data[h] = new float[number_nodes[1]];
	}
	Read_MNIST(path + "train-images.idx3-ubyte", path + "train-labels.idx1-ubyte", path + "t10k-images.idx3-ubyte", path + "t10k-labels.idx1-ubyte", number_training, number_test, x_data, y_data);
	omp_set_num_threads(number_threads);

	srand(9);

	NN.Add( 1, 28, 28);
	NN.Add(24, 24, 24)
		->Activation(Activation::relu)
		->Batch_Normalization();
	NN.Add(24, 12, 12);
	NN.Add(48,  8,  8)
		->Activation(Activation::relu)
		->Batch_Normalization();
	NN.Add(48,  4,  4);
	NN.Add(512)
		->Activation(Activation::relu)
		->Batch_Normalization();
	NN.Add(number_nodes[1])->Activation(Activation::softmax);

	NN.Connect(1, 0, "W")->Initializer(HeNormal());
	NN.Connect(2, 1, "P,max");
	NN.Connect(3, 2, "W")->Initializer(HeNormal());
	NN.Connect(4, 3, "P,max");
	NN.Connect(5, 4, "W")->Initializer(HeNormal());
	NN.Connect(6, 5, "W")->Initializer(HeNormal());

	NN.Compile(Loss::cross_entropy, new Optimizer(SGD(learning_rate)));

	for (int e = 0, time = clock(); e < epochs; e++) {
		int score[2] = { 0, };

		float **_input = new float*[batch_size];
		float **output = new float*[batch_size];

		double loss[2] = { NN.Fit(NN.Shuffle(x_train, number_training), NN.Shuffle(y_train, number_training), number_training, batch_size), NN.Evaluate(x_test, y_test, number_test, batch_size) };

		for (int h = 0; h < batch_size; h++) {
			output[h] = new float[number_nodes[1]];
		}
		for (int h = 0, i = 0; i < number_training + number_test; i++) {
			_input[h] = x_data[i];

			if (++h == batch_size || i == number_training + number_test - 1) {
				NN.Predict(_input, output, h);

				for (int argmax, index = i - h + 1; --h >= 0;) {
					double max = 0;

					for (int j = 0; j < number_nodes[1]; j++) {
						if (j == 0 || max < output[h][j]) {
							max = output[h][argmax = j];
						}
					}
					score[(index + h < number_training) ? (0) : (1)] += (int)y_data[index + h][argmax];
				}
				h = 0;
			}
		}
		printf("loss: %.4f / %.4f	accuracy: %.4f / %.4f	step %d  %.2f sec\n", loss[0], loss[1], 1.0 * score[0] / number_training, 1.0 * score[1] / number_test, e + 1, (double)(clock() - time) / CLOCKS_PER_SEC);

		for (int h = 0; h < batch_size; h++) {
			delete[] output[h];
		}
		delete[] _input;
		delete[] output;
	}

	for (int i = 0; i < number_training + number_test; i++) {
		delete[] x_data[i];
		delete[] y_data[i];
	}
	delete[] x_data;
	delete[] y_data;
}
<commit_msg>Update main.cpp<commit_after>#include <fstream>
#include <iostream>
#include <omp.h>
#include <random>
#include <stdio.h>
#include <string>
#include <time.h>

#include "Neural_Networks.h"

using namespace std;

void Read_MNIST(string training_set_images, string training_set_labels, string test_set_images, string test_set_labels, int number_training, int number_test, float **input, float **output) {
	ifstream file(training_set_images, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 4; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = 0; h < number_training; h++) {
			unsigned char pixel;

			for (int j = 0; j < 28 * 28; j++) {
				file.read((char*)(&pixel), 1);
				input[h][j] = pixel / 255.0;
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + training_set_images + " not found" << endl;
	}

	file.open(training_set_labels, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 2; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = 0; h < number_training; h++) {
			unsigned char label;

			file.read((char*)(&label), 1);

			for (int j = 0; j < 10; j++) {
				output[h][j] = (j == label);
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + training_set_labels + " not found" << endl;
	}

	file.open(test_set_images, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 4; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = number_training; h < number_training + number_test; h++) {
			unsigned char pixel;

			for (int j = 0; j < 28 * 28; j++) {
				file.read((char*)(&pixel), 1);
				input[h][j] = pixel / 255.0;
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + test_set_images + " not found" << endl;
	}

	file.open(test_set_labels, ifstream::binary);

	if (file.is_open()) {
		for (int h = 0, value; h < 2; h++) {
			file.read((char*)(&value), sizeof(int));
		}
		for (int h = number_training; h < number_training + number_test; h++) {
			unsigned char label;

			file.read((char*)(&label), 1);

			for (int j = 0; j < 10; j++) {
				output[h][j] = (j == label);
			}
		}
		file.close();
	}
	else {
		cerr << "[Read_MNIST], " + test_set_labels + " not found" << endl;
	}
}

int main() {
	int batch_size = 128;
	int epochs = 20;
	int number_threads = 6;
	int number_training = 60000;
	int number_test = 10000;
	int number_nodes[] = { 784, 10 };

	float **x_data = new float*[number_training + number_test];
	float **y_data = new float*[number_training + number_test];
	float **x_train = x_data;
	float **y_train = y_data;
	float **x_test = &x_data[number_training];
	float **y_test = &y_data[number_training];

	double learning_rate = 0.5;

	string path;

	Neural_Networks NN = Neural_Networks();

	cout << "path where MNIST handwritten digits dataset is : ";
	getline(cin, path);

	for (int h = 0; h < number_training + number_test; h++) {
		x_data[h] = new float[number_nodes[0]];
		y_data[h] = new float[number_nodes[1]];
	}
	Read_MNIST(path + "train-images.idx3-ubyte", path + "train-labels.idx1-ubyte", path + "t10k-images.idx3-ubyte", path + "t10k-labels.idx1-ubyte", number_training, number_test, x_data, y_data);
	omp_set_num_threads(number_threads);

	srand(9);

	NN.Add( 1, 28, 28);
	NN.Add(24, 24, 24)->Activation(Activation::relu)->Batch_Normalization();
	NN.Add(24, 12, 12);
	NN.Add(48,  8,  8)->Activation(Activation::relu)->Batch_Normalization();
	NN.Add(48,  4,  4);
	NN.Add(512)->Activation(Activation::relu)->Batch_Normalization();
	NN.Add(number_nodes[1])->Activation(Activation::softmax);

	NN.Connect(1, 0, "W")->Initializer(HeNormal());
	NN.Connect(2, 1, "P,max");
	NN.Connect(3, 2, "W")->Initializer(HeNormal());
	NN.Connect(4, 3, "P,max");
	NN.Connect(5, 4, "W")->Initializer(HeNormal());
	NN.Connect(6, 5, "W")->Initializer(HeNormal());

	NN.Compile(Loss::cross_entropy, new Optimizer(SGD(learning_rate)));

	for (int e = 0, time = clock(); e < epochs; e++) {
		int score[2] = { 0, };

		float **_input = new float*[batch_size];
		float **output = new float*[batch_size];

		double loss[2] = { NN.Fit(NN.Shuffle(x_train, number_training), NN.Shuffle(y_train, number_training), number_training, batch_size), NN.Evaluate(x_test, y_test, number_test, batch_size) };

		for (int h = 0; h < batch_size; h++) {
			output[h] = new float[number_nodes[1]];
		}
		for (int h = 0, i = 0; i < number_training + number_test; i++) {
			_input[h] = x_data[i];

			if (++h == batch_size || i == number_training + number_test - 1) {
				NN.Predict(_input, output, h);

				for (int argmax, index = i - h + 1; --h >= 0;) {
					double max = 0;

					for (int j = 0; j < number_nodes[1]; j++) {
						if (j == 0 || max < output[h][j]) {
							max = output[h][argmax = j];
						}
					}
					score[(index + h < number_training) ? (0) : (1)] += (int)y_data[index + h][argmax];
				}
				h = 0;
			}
		}
		printf("loss: %.4f / %.4f	accuracy: %.4f / %.4f	step %d  %.2f sec\n", loss[0], loss[1], 1.0 * score[0] / number_training, 1.0 * score[1] / number_test, e + 1, (double)(clock() - time) / CLOCKS_PER_SEC);

		for (int h = 0; h < batch_size; h++) {
			delete[] output[h];
		}
		delete[] _input;
		delete[] output;
	}

	for (int i = 0; i < number_training + number_test; i++) {
		delete[] x_data[i];
		delete[] y_data[i];
	}
	delete[] x_data;
	delete[] y_data;
}
<|endoftext|>


<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors:
 *
 * Roland Smeenk
 * Cedric Pinson <cedric.pinson@plopbyte.net>
 *
 */
#include <osg/Geode>
#include <osgAnimation/MorphGeometry>

#include <sstream>

using namespace osgAnimation;

MorphGeometry::MorphGeometry() :
    _dirty(false),
    _method(NORMALIZED),
    _morphNormals(true)
{
    setUseDisplayList(false);
    setUpdateCallback(new UpdateVertex);
    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(true);
}

MorphGeometry::MorphGeometry(const osg::Geometry& b) :
    osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS),
    _dirty(false),
    _method(NORMALIZED),
    _morphNormals(true)
{
    setUseDisplayList(false);
    setUpdateCallback(new UpdateVertex);
    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(true);
    if (b.getInternalOptimizedGeometry())
        computeInternalOptimizedGeometry();
}

MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) :
    osg::Geometry(b,copyop),
    _dirty(b._dirty),
    _method(b._method),
    _morphTargets(b._morphTargets),
    _positionSource(b._positionSource),
    _normalSource(b._normalSource),
    _morphNormals(b._morphNormals)
{
    setUseDisplayList(false);
    setUseVertexBufferObjects(true);
    if (b.getInternalOptimizedGeometry())
        computeInternalOptimizedGeometry();
}

void MorphGeometry::transformSoftwareMethod()
{
    if (_dirty)
    {
        // See if we have an internal optimized geometry
        osg::Geometry* morphGeometry = this;
        if (_internalOptimizedGeometry.valid())
            morphGeometry = _internalOptimizedGeometry.get();

        osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry->getVertexArray());
        if (pos && _positionSource.size() != pos->size())
        {
            _positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
            pos->setDataVariance(osg::Object::DYNAMIC);
        }

        osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry->getNormalArray());
        if (normal && _normalSource.size() != normal->size())
        {
            _normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
            normal->setDataVariance(osg::Object::DYNAMIC);
        }

        if (!_positionSource.empty())
        {
            bool initialized = false;
            if (_method == NORMALIZED)
            {
                // base * 1 - (sum of weights) + sum of (weight * target)
                float baseWeight = 0;
                for (unsigned int i=0; i < _morphTargets.size(); i++)
                {
                    baseWeight += _morphTargets[i].getWeight();
                }
                baseWeight = 1 - baseWeight;

                if (baseWeight != 0)
                {
                    initialized = true;
                    for (unsigned int i=0; i < pos->size(); i++)
                    {
                        (*pos)[i] = _positionSource[i] * baseWeight;
                    }
                    if (_morphNormals)
                    {
                        for (unsigned int i=0; i < normal->size(); i++)
                        {
                            (*normal)[i] = _normalSource[i] * baseWeight;
                        }
                    }
                }
            }
            else //if (_method == RELATIVE)
            {
                // base + sum of (weight * target)
                initialized = true;
                for (unsigned int i=0; i < pos->size(); i++)
                {
                    (*pos)[i] = _positionSource[i];
                }
                if (_morphNormals)
                {
                    for (unsigned int i=0; i < normal->size(); i++)
                    {
                        (*normal)[i] = _normalSource[i];
                    }
                }
            }

            for (unsigned int i=0; i < _morphTargets.size(); i++)
            {
                if (_morphTargets[i].getWeight() > 0)
                {
                    // See if any the targets use the internal optimized geometry
                    osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry();
                    if (!targetGeometry)
                        targetGeometry = _morphTargets[i].getGeometry();

                    osg::Vec3Array* targetPos = dynamic_cast<osg::Vec3Array*>(targetGeometry->getVertexArray());
                    osg::Vec3Array* targetNormals = dynamic_cast<osg::Vec3Array*>(targetGeometry->getNormalArray());

                    if (initialized)
                    {
                        // If vertices are initialized, add the morphtargets
                        for (unsigned int j=0; j < pos->size(); j++)
                        {
                            (*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight();
                        }

                        if (_morphNormals)
                        {
                            for (unsigned int j=0; j < normal->size(); j++)
                            {
                                (*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight();
                            }
                        }
                    }
                    else
                    {
                        // If not initialized, initialize with this morph target
                        initialized = true;
                        for (unsigned int j=0; j < pos->size(); j++)
                        {
                            (*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight();
                        }

                        if (_morphNormals)
                        {
                            for (unsigned int j=0; j < normal->size(); j++)
                            {
                                (*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight();
                            }
                        }
                    }
                }
            }

            pos->dirty();
            if (_morphNormals)
            {
                for (unsigned int j=0; j < normal->size(); j++)
                {
                    (*normal)[j].normalize();
                }
                normal->dirty();
            }
        }

        dirtyBound();
        _dirty = false;
    }
}

UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
    osg::Object(apc, copyop),
    AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
}

UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}

/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
        if (geode)
        {
            unsigned int numDrawables = geode->getNumDrawables();
            for (unsigned int i = 0; i != numDrawables; ++i)
            {
                osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(geode->getDrawable(i));
                if (morph)
                {
                    // Update morph weights
                    std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> >::iterator iter = _weightTargets.begin();
                    while (iter != _weightTargets.end())
                    {
                        if (iter->second->getValue() >= 0)
                        {
                            morph->setWeight(iter->first, iter->second->getValue());
                        }
                        ++iter;
                    }
                }
            }
        }
    }
    traverse(node,nv);
}

bool UpdateMorph::needLink() const
{
    // the idea is to return true if nothing is linked
    return (_weightTargets.size() == 0);
}

bool UpdateMorph::link(osgAnimation::Channel* channel)
{
    // Typically morph geometries only have the weights for morph targets animated

    std::istringstream iss(channel->getName());

    int weightIndex;
    iss >> weightIndex;

    if (iss.fail())
    {
        return false;
    }

    if (weightIndex >= 0)
    {
        osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
        if (!ft)
        {
            ft = new osgAnimation::FloatTarget;
            _weightTargets[weightIndex] = ft;
        }
        return channel->setTarget(ft);
    }
    else
    {
        OSG_WARN << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
    }
    return false;
}
<commit_msg>Fixed the erronous header so that it is OSGPL like the rest of the osgAnimation.<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
 */

#include <osg/Geode>
#include <osgAnimation/MorphGeometry>

#include <sstream>

using namespace osgAnimation;

MorphGeometry::MorphGeometry() :
    _dirty(false),
    _method(NORMALIZED),
    _morphNormals(true)
{
    setUseDisplayList(false);
    setUpdateCallback(new UpdateVertex);
    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(true);
}

MorphGeometry::MorphGeometry(const osg::Geometry& b) :
    osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS),
    _dirty(false),
    _method(NORMALIZED),
    _morphNormals(true)
{
    setUseDisplayList(false);
    setUpdateCallback(new UpdateVertex);
    setDataVariance(osg::Object::DYNAMIC);
    setUseVertexBufferObjects(true);
    if (b.getInternalOptimizedGeometry())
        computeInternalOptimizedGeometry();
}

MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) :
    osg::Geometry(b,copyop),
    _dirty(b._dirty),
    _method(b._method),
    _morphTargets(b._morphTargets),
    _positionSource(b._positionSource),
    _normalSource(b._normalSource),
    _morphNormals(b._morphNormals)
{
    setUseDisplayList(false);
    setUseVertexBufferObjects(true);
    if (b.getInternalOptimizedGeometry())
        computeInternalOptimizedGeometry();
}

void MorphGeometry::transformSoftwareMethod()
{
    if (_dirty)
    {
        // See if we have an internal optimized geometry
        osg::Geometry* morphGeometry = this;
        if (_internalOptimizedGeometry.valid())
            morphGeometry = _internalOptimizedGeometry.get();

        osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry->getVertexArray());
        if (pos && _positionSource.size() != pos->size())
        {
            _positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
            pos->setDataVariance(osg::Object::DYNAMIC);
        }

        osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry->getNormalArray());
        if (normal && _normalSource.size() != normal->size())
        {
            _normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
            normal->setDataVariance(osg::Object::DYNAMIC);
        }

        if (!_positionSource.empty())
        {
            bool initialized = false;
            if (_method == NORMALIZED)
            {
                // base * 1 - (sum of weights) + sum of (weight * target)
                float baseWeight = 0;
                for (unsigned int i=0; i < _morphTargets.size(); i++)
                {
                    baseWeight += _morphTargets[i].getWeight();
                }
                baseWeight = 1 - baseWeight;

                if (baseWeight != 0)
                {
                    initialized = true;
                    for (unsigned int i=0; i < pos->size(); i++)
                    {
                        (*pos)[i] = _positionSource[i] * baseWeight;
                    }
                    if (_morphNormals)
                    {
                        for (unsigned int i=0; i < normal->size(); i++)
                        {
                            (*normal)[i] = _normalSource[i] * baseWeight;
                        }
                    }
                }
            }
            else //if (_method == RELATIVE)
            {
                // base + sum of (weight * target)
                initialized = true;
                for (unsigned int i=0; i < pos->size(); i++)
                {
                    (*pos)[i] = _positionSource[i];
                }
                if (_morphNormals)
                {
                    for (unsigned int i=0; i < normal->size(); i++)
                    {
                        (*normal)[i] = _normalSource[i];
                    }
                }
            }

            for (unsigned int i=0; i < _morphTargets.size(); i++)
            {
                if (_morphTargets[i].getWeight() > 0)
                {
                    // See if any the targets use the internal optimized geometry
                    osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry();
                    if (!targetGeometry)
                        targetGeometry = _morphTargets[i].getGeometry();

                    osg::Vec3Array* targetPos = dynamic_cast<osg::Vec3Array*>(targetGeometry->getVertexArray());
                    osg::Vec3Array* targetNormals = dynamic_cast<osg::Vec3Array*>(targetGeometry->getNormalArray());

                    if (initialized)
                    {
                        // If vertices are initialized, add the morphtargets
                        for (unsigned int j=0; j < pos->size(); j++)
                        {
                            (*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight();
                        }

                        if (_morphNormals)
                        {
                            for (unsigned int j=0; j < normal->size(); j++)
                            {
                                (*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight();
                            }
                        }
                    }
                    else
                    {
                        // If not initialized, initialize with this morph target
                        initialized = true;
                        for (unsigned int j=0; j < pos->size(); j++)
                        {
                            (*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight();
                        }

                        if (_morphNormals)
                        {
                            for (unsigned int j=0; j < normal->size(); j++)
                            {
                                (*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight();
                            }
                        }
                    }
                }
            }

            pos->dirty();
            if (_morphNormals)
            {
                for (unsigned int j=0; j < normal->size(); j++)
                {
                    (*normal)[j].normalize();
                }
                normal->dirty();
            }
        }

        dirtyBound();
        _dirty = false;
    }
}

UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
    osg::Object(apc, copyop),
    AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
}

UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}

/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
        if (geode)
        {
            unsigned int numDrawables = geode->getNumDrawables();
            for (unsigned int i = 0; i != numDrawables; ++i)
            {
                osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(geode->getDrawable(i));
                if (morph)
                {
                    // Update morph weights
                    std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> >::iterator iter = _weightTargets.begin();
                    while (iter != _weightTargets.end())
                    {
                        if (iter->second->getValue() >= 0)
                        {
                            morph->setWeight(iter->first, iter->second->getValue());
                        }
                        ++iter;
                    }
                }
            }
        }
    }
    traverse(node,nv);
}

bool UpdateMorph::needLink() const
{
    // the idea is to return true if nothing is linked
    return (_weightTargets.size() == 0);
}

bool UpdateMorph::link(osgAnimation::Channel* channel)
{
    // Typically morph geometries only have the weights for morph targets animated

    std::istringstream iss(channel->getName());

    int weightIndex;
    iss >> weightIndex;

    if (iss.fail())
    {
        return false;
    }

    if (weightIndex >= 0)
    {
        osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
        if (!ft)
        {
            ft = new osgAnimation::FloatTarget;
            _weightTargets[weightIndex] = ft;
        }
        return channel->setTarget(ft);
    }
    else
    {
        OSG_WARN << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
    }
    return false;
}
<|endoftext|>