<commit_before>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/platform/graphics/chromium/Canvas2DLayerBridge.h"

#include "GrContext.h"
#include "SkDevice.h"
#include "SkSurface.h"
#include "core/platform/chromium/TraceEvent.h"
#include "core/platform/graphics/GraphicsContext3D.h"
#include "core/platform/graphics/GraphicsLayer.h"
#include "core/platform/graphics/chromium/Canvas2DLayerManager.h"
#include "core/platform/graphics/gpu/SharedGraphicsContext3D.h"
#include "public/platform/Platform.h"
#include "public/platform/WebCompositorSupport.h"
#include "public/platform/WebGraphicsContext3D.h"

using WebKit::WebExternalTextureLayer;
using WebKit::WebGraphicsContext3D;

namespace WebCore {

static SkSurface* createSurface(GraphicsContext3D* context3D, const IntSize& size)
{
    ASSERT(!context3D->webContext()->isContextLost());
    GrContext* gr = context3D->grContext();
    if (!gr)
        return 0;
    gr->resetContext();
    SkImage::Info info;
    info.fWidth = size.width();
    info.fHeight = size.height();
    info.fColorType = SkImage::kPMColor_ColorType;
    info.fAlphaType = SkImage::kPremul_AlphaType;
    return SkSurface::NewRenderTarget(gr, info);
}

PassOwnPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(PassRefPtr<GraphicsContext3D> context, const IntSize& size, OpacityMode opacityMode)
{
    TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
    SkAutoTUnref<SkSurface> surface(createSurface(context.get(), size));
    if (!surface.get())
        return PassOwnPtr<Canvas2DLayerBridge>();
    SkDeferredCanvas* canvas = new SkDeferredCanvas(surface);
    OwnPtr<Canvas2DLayerBridge> layerBridge = adoptPtr(new Canvas2DLayerBridge(context, canvas, opacityMode));
    return layerBridge.release();
}

Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, SkDeferredCanvas* canvas, OpacityMode opacityMode)
    : m_canvas(canvas)
    , m_context(context)
    , m_bytesAllocated(0)
    , m_didRecordDrawCommand(false)
    , m_surfaceIsValid(true)
    , m_framesPending(0)
    , m_rateLimitingEnabled(false)
    , m_next(0)
    , m_prev(0)
    , m_lastImageId(0)
{
    ASSERT(m_canvas);
    // Used by browser tests to detect the use of a Canvas2DLayerBridge.
    TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
    m_layer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createExternalTextureLayer(this));
    m_layer->setOpaque(opacityMode == Opaque);
    m_layer->setBlendBackgroundColor(opacityMode != Opaque);
    GraphicsLayer::registerContentsLayer(m_layer->layer());
    m_layer->setRateLimitContext(m_rateLimitingEnabled);
    m_canvas->setNotificationClient(this);
}

Canvas2DLayerBridge::~Canvas2DLayerBridge()
{
    GraphicsLayer::unregisterContentsLayer(m_layer->layer());
    Canvas2DLayerManager::get().layerToBeDestroyed(this);
    m_canvas->setNotificationClient(0);
    m_mailboxes.clear();
    m_layer->clearTexture();
    m_layer.clear();
}

void Canvas2DLayerBridge::limitPendingFrames()
{
    if (m_didRecordDrawCommand) {
        m_framesPending++;
        m_didRecordDrawCommand = false;
        if (m_framesPending > 1) {
            // Turn on the rate limiter if this layer tends to accumulate a
            // non-discardable multi-frame backlog of draw commands.
            setRateLimitingEnabled(true);
        }
        if (m_rateLimitingEnabled) {
            flush();
        }
    }
}

void Canvas2DLayerBridge::prepareForDraw()
{
    ASSERT(m_layer);
    if (!isValid()) {
        if (m_canvas) {
            // drop pending commands because there is no surface to draw to
            m_canvas->silentFlush();
        }
        return;
    }
    m_context->makeContextCurrent();
}

void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAllocated)
{
    intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated;
    m_bytesAllocated = bytesAllocated;
    Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, delta);
}

size_t Canvas2DLayerBridge::storageAllocatedForRecording()
{
    return m_canvas->storageAllocatedForRecording();
}

void Canvas2DLayerBridge::flushedDrawCommands()
{
    storageAllocatedForRecordingChanged(storageAllocatedForRecording());
    m_framesPending = 0;
}

void Canvas2DLayerBridge::skippedPendingDrawCommands()
{
    // Stop triggering the rate limiter if SkDeferredCanvas is detecting
    // and optimizing overdraw.
    setRateLimitingEnabled(false);
    flushedDrawCommands();
}

void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled)
{
    if (m_rateLimitingEnabled != enabled) {
        m_rateLimitingEnabled = enabled;
        m_layer->setRateLimitContext(m_rateLimitingEnabled);
    }
}

size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree)
{
    size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree);
    if (bytesFreed)
        Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr_t)bytesFreed));
    m_bytesAllocated -= bytesFreed;
    return bytesFreed;
}

void Canvas2DLayerBridge::flush()
{
    if (m_canvas->hasPendingCommands()) {
        TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush");
        m_canvas->flush();
    }
}

WebGraphicsContext3D* Canvas2DLayerBridge::context()
{
    isValid(); // To ensure rate limiter is disabled if context is lost.
    return m_context->webContext();
}

bool Canvas2DLayerBridge::isValid()
{
    ASSERT(m_layer);
    if (m_context->webContext()->isContextLost() || !m_surfaceIsValid) {
        // Attempt to recover.
        m_layer->clearTexture();
        m_mailboxes.clear();
        RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get();
        if (!sharedContext || sharedContext->webContext()->isContextLost()) {
            m_surfaceIsValid = false;
        } else {
            m_context = sharedContext;
            IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height());
            SkAutoTUnref<SkSurface> surface(createSurface(m_context.get(), size));
            if (surface.get()) {
                m_canvas->setSurface(surface.get());
                m_surfaceIsValid = true;
                // FIXME: draw sad canvas picture into new buffer crbug.com/243842
            } else {
                // Surface allocation failed. Set m_surfaceIsValid to false to
                // trigger subsequent retry.
                m_surfaceIsValid = false;
            }
        }
    }
    if (!m_surfaceIsValid)
        setRateLimitingEnabled(false);
    return m_surfaceIsValid;

}

bool Canvas2DLayerBridge::prepareMailbox(WebKit::WebExternalTextureMailbox* outMailbox, WebKit::WebExternalBitmap* bitmap)
{
    ASSERT(!bitmap);
    if (!isValid())
        return false;
    // Release to skia textures that were previouosly released by the
    // compositor. We do this before acquiring the next snapshot in
    // order to cap maximum gpu memory consumption.
    m_context->makeContextCurrent();
    flush();
    Vector<MailboxInfo>::iterator mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (mailboxInfo->m_status == MailboxReleased) {
            if (mailboxInfo->m_mailbox.syncPoint) {
                context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint);
                mailboxInfo->m_mailbox.syncPoint = 0;
            }
            // Invalidate texture state in case the compositor altered it since the copy-on-write.
            mailboxInfo->m_image->getTexture()->invalidateCachedState();
            mailboxInfo->m_image.reset(0);
            mailboxInfo->m_status = MailboxAvailable;
        }
    }
    SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot());
    // Early exit if canvas was not drawn to since last prepareMailbox
    if (image->uniqueID() == m_lastImageId)
        return false;
    m_lastImageId = image->uniqueID();

    mailboxInfo = createMailboxInfo();
    mailboxInfo->m_status = MailboxInUse;
    mailboxInfo->m_image.swap(&image);
    // Because of texture sharing with the compositor, we must invalidate
    // the state cached in skia so that the deferred copy on write
    // in SkSurface_Gpu does not make any false assumptions.
    mailboxInfo->m_image->getTexture()->invalidateCachedState();

    ASSERT(mailboxInfo->m_mailbox.syncPoint == 0);
    ASSERT(mailboxInfo->m_image.get());
    ASSERT(mailboxInfo->m_image->getTexture());

    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_image->getTexture()->getTextureHandle());
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
    context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_mailbox.name);
    context()->flush();
    mailboxInfo->m_mailbox.syncPoint = context()->insertSyncPoint();
    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
    // Because we are changing the texture binding without going through skia,
    // we must dirty the context.
    m_context->grContext()->resetContext(kTextureBinding_GrGLBackendState);

    *outMailbox = mailboxInfo->m_mailbox;
    return true;
}

Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() {
    MailboxInfo* mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (mailboxInfo->m_status == MailboxAvailable) {
            return mailboxInfo;
        }
    }

    // No available mailbox: create one.
    m_mailboxes.grow(m_mailboxes.size() + 1);
    mailboxInfo = &m_mailboxes.last();
    context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name);
    // Worst case, canvas is triple buffered.  More than 3 active mailboxes
    // means there is a problem.
    // For the single-threaded case, this value needs to be at least
    // kMaxSwapBuffersPending+1 (in render_widget.h).
    // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2.
    // TODO(piman): fix this.
    ASSERT(m_mailboxes.size() <= 4);
    ASSERT(mailboxInfo < m_mailboxes.end());
    return mailboxInfo;
}

void Canvas2DLayerBridge::mailboxReleased(const WebKit::WebExternalTextureMailbox& mailbox)
{
    Vector<MailboxInfo>::iterator mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.name))) {
            mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint;
            ASSERT(mailboxInfo->m_status == MailboxInUse);
            mailboxInfo->m_status = MailboxReleased;
            return;
        }
    }
}

WebKit::WebLayer* Canvas2DLayerBridge::layer()
{
    ASSERT(m_layer);
    return m_layer->layer();
}

void Canvas2DLayerBridge::contextAcquired()
{
    Canvas2DLayerManager::get().layerDidDraw(this);
    m_didRecordDrawCommand = true;
}

unsigned Canvas2DLayerBridge::backBufferTexture()
{
    if (!isValid())
        return 0;
    contextAcquired();
    m_canvas->flush();
    m_context->flush();
    GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget());
    if (renderTarget) {
        return renderTarget->asTexture()->getTextureHandle();
    }
    return 0;
}

Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) {
    // This copy constructor should only be used for Vector reallocation
    // Assuming 'other' is to be destroyed, we swap m_image ownership
    // rather than do a refcount dance.
    memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox));
    m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image));
    m_status = other.m_status;
}

}
<commit_msg>Fixing flaky crash in Canvas2DLayerBridge tear-down.<commit_after>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/platform/graphics/chromium/Canvas2DLayerBridge.h"

#include "GrContext.h"
#include "SkDevice.h"
#include "SkSurface.h"
#include "core/platform/chromium/TraceEvent.h"
#include "core/platform/graphics/GraphicsContext3D.h"
#include "core/platform/graphics/GraphicsLayer.h"
#include "core/platform/graphics/chromium/Canvas2DLayerManager.h"
#include "core/platform/graphics/gpu/SharedGraphicsContext3D.h"
#include "public/platform/Platform.h"
#include "public/platform/WebCompositorSupport.h"
#include "public/platform/WebGraphicsContext3D.h"

using WebKit::WebExternalTextureLayer;
using WebKit::WebGraphicsContext3D;

namespace WebCore {

static SkSurface* createSurface(GraphicsContext3D* context3D, const IntSize& size)
{
    ASSERT(!context3D->webContext()->isContextLost());
    GrContext* gr = context3D->grContext();
    if (!gr)
        return 0;
    gr->resetContext();
    SkImage::Info info;
    info.fWidth = size.width();
    info.fHeight = size.height();
    info.fColorType = SkImage::kPMColor_ColorType;
    info.fAlphaType = SkImage::kPremul_AlphaType;
    return SkSurface::NewRenderTarget(gr, info);
}

PassOwnPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(PassRefPtr<GraphicsContext3D> context, const IntSize& size, OpacityMode opacityMode)
{
    TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
    SkAutoTUnref<SkSurface> surface(createSurface(context.get(), size));
    if (!surface.get())
        return PassOwnPtr<Canvas2DLayerBridge>();
    SkDeferredCanvas* canvas = new SkDeferredCanvas(surface);
    OwnPtr<Canvas2DLayerBridge> layerBridge = adoptPtr(new Canvas2DLayerBridge(context, canvas, opacityMode));
    return layerBridge.release();
}

Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, SkDeferredCanvas* canvas, OpacityMode opacityMode)
    : m_canvas(canvas)
    , m_context(context)
    , m_bytesAllocated(0)
    , m_didRecordDrawCommand(false)
    , m_surfaceIsValid(true)
    , m_framesPending(0)
    , m_rateLimitingEnabled(false)
    , m_next(0)
    , m_prev(0)
    , m_lastImageId(0)
{
    ASSERT(m_canvas);
    // Used by browser tests to detect the use of a Canvas2DLayerBridge.
    TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
    m_layer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createExternalTextureLayer(this));
    m_layer->setOpaque(opacityMode == Opaque);
    m_layer->setBlendBackgroundColor(opacityMode != Opaque);
    GraphicsLayer::registerContentsLayer(m_layer->layer());
    m_layer->setRateLimitContext(m_rateLimitingEnabled);
    m_canvas->setNotificationClient(this);
}

Canvas2DLayerBridge::~Canvas2DLayerBridge()
{
    GraphicsLayer::unregisterContentsLayer(m_layer->layer());
    Canvas2DLayerManager::get().layerToBeDestroyed(this);
    m_canvas->setNotificationClient(0);
    m_mailboxes.clear();
    m_layer->clearTexture();
    m_layer.clear();
}

void Canvas2DLayerBridge::limitPendingFrames()
{
    if (m_didRecordDrawCommand) {
        m_framesPending++;
        m_didRecordDrawCommand = false;
        if (m_framesPending > 1) {
            // Turn on the rate limiter if this layer tends to accumulate a
            // non-discardable multi-frame backlog of draw commands.
            setRateLimitingEnabled(true);
        }
        if (m_rateLimitingEnabled) {
            flush();
        }
    }
}

void Canvas2DLayerBridge::prepareForDraw()
{
    ASSERT(m_layer);
    if (!isValid()) {
        if (m_canvas) {
            // drop pending commands because there is no surface to draw to
            m_canvas->silentFlush();
        }
        return;
    }
    m_context->makeContextCurrent();
}

void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAllocated)
{
    intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated;
    m_bytesAllocated = bytesAllocated;
    Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, delta);
}

size_t Canvas2DLayerBridge::storageAllocatedForRecording()
{
    return m_canvas->storageAllocatedForRecording();
}

void Canvas2DLayerBridge::flushedDrawCommands()
{
    storageAllocatedForRecordingChanged(storageAllocatedForRecording());
    m_framesPending = 0;
}

void Canvas2DLayerBridge::skippedPendingDrawCommands()
{
    // Stop triggering the rate limiter if SkDeferredCanvas is detecting
    // and optimizing overdraw.
    setRateLimitingEnabled(false);
    flushedDrawCommands();
}

void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled)
{
    if (m_rateLimitingEnabled != enabled) {
        m_rateLimitingEnabled = enabled;
        m_layer->setRateLimitContext(m_rateLimitingEnabled);
    }
}

size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree)
{
    size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree);
    if (bytesFreed)
        Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr_t)bytesFreed));
    m_bytesAllocated -= bytesFreed;
    return bytesFreed;
}

void Canvas2DLayerBridge::flush()
{
    if (m_canvas->hasPendingCommands()) {
        TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush");
        m_canvas->flush();
    }
}

WebGraphicsContext3D* Canvas2DLayerBridge::context()
{
    // Check on m_layer is necessary because context() may be called during
    // the destruction of m_layer
    if (m_layer) {
        isValid(); // To ensure rate limiter is disabled if context is lost.
    }
    return m_context->webContext();
}

bool Canvas2DLayerBridge::isValid()
{
    ASSERT(m_layer);
    if (m_context->webContext()->isContextLost() || !m_surfaceIsValid) {
        // Attempt to recover.
        m_layer->clearTexture();
        m_mailboxes.clear();
        RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get();
        if (!sharedContext || sharedContext->webContext()->isContextLost()) {
            m_surfaceIsValid = false;
        } else {
            m_context = sharedContext;
            IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevice()->height());
            SkAutoTUnref<SkSurface> surface(createSurface(m_context.get(), size));
            if (surface.get()) {
                m_canvas->setSurface(surface.get());
                m_surfaceIsValid = true;
                // FIXME: draw sad canvas picture into new buffer crbug.com/243842
            } else {
                // Surface allocation failed. Set m_surfaceIsValid to false to
                // trigger subsequent retry.
                m_surfaceIsValid = false;
            }
        }
    }
    if (!m_surfaceIsValid)
        setRateLimitingEnabled(false);
    return m_surfaceIsValid;

}

bool Canvas2DLayerBridge::prepareMailbox(WebKit::WebExternalTextureMailbox* outMailbox, WebKit::WebExternalBitmap* bitmap)
{
    ASSERT(!bitmap);
    if (!isValid())
        return false;
    // Release to skia textures that were previouosly released by the
    // compositor. We do this before acquiring the next snapshot in
    // order to cap maximum gpu memory consumption.
    m_context->makeContextCurrent();
    flush();
    Vector<MailboxInfo>::iterator mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (mailboxInfo->m_status == MailboxReleased) {
            if (mailboxInfo->m_mailbox.syncPoint) {
                context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint);
                mailboxInfo->m_mailbox.syncPoint = 0;
            }
            // Invalidate texture state in case the compositor altered it since the copy-on-write.
            mailboxInfo->m_image->getTexture()->invalidateCachedState();
            mailboxInfo->m_image.reset(0);
            mailboxInfo->m_status = MailboxAvailable;
        }
    }
    SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot());
    // Early exit if canvas was not drawn to since last prepareMailbox
    if (image->uniqueID() == m_lastImageId)
        return false;
    m_lastImageId = image->uniqueID();

    mailboxInfo = createMailboxInfo();
    mailboxInfo->m_status = MailboxInUse;
    mailboxInfo->m_image.swap(&image);
    // Because of texture sharing with the compositor, we must invalidate
    // the state cached in skia so that the deferred copy on write
    // in SkSurface_Gpu does not make any false assumptions.
    mailboxInfo->m_image->getTexture()->invalidateCachedState();

    ASSERT(mailboxInfo->m_mailbox.syncPoint == 0);
    ASSERT(mailboxInfo->m_image.get());
    ASSERT(mailboxInfo->m_image->getTexture());

    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_image->getTexture()->getTextureHandle());
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
    m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
    context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_mailbox.name);
    context()->flush();
    mailboxInfo->m_mailbox.syncPoint = context()->insertSyncPoint();
    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
    // Because we are changing the texture binding without going through skia,
    // we must dirty the context.
    m_context->grContext()->resetContext(kTextureBinding_GrGLBackendState);

    *outMailbox = mailboxInfo->m_mailbox;
    return true;
}

Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() {
    MailboxInfo* mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (mailboxInfo->m_status == MailboxAvailable) {
            return mailboxInfo;
        }
    }

    // No available mailbox: create one.
    m_mailboxes.grow(m_mailboxes.size() + 1);
    mailboxInfo = &m_mailboxes.last();
    context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name);
    // Worst case, canvas is triple buffered.  More than 3 active mailboxes
    // means there is a problem.
    // For the single-threaded case, this value needs to be at least
    // kMaxSwapBuffersPending+1 (in render_widget.h).
    // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2.
    // TODO(piman): fix this.
    ASSERT(m_mailboxes.size() <= 4);
    ASSERT(mailboxInfo < m_mailboxes.end());
    return mailboxInfo;
}

void Canvas2DLayerBridge::mailboxReleased(const WebKit::WebExternalTextureMailbox& mailbox)
{
    Vector<MailboxInfo>::iterator mailboxInfo;
    for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mailboxInfo++) {
        if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.name))) {
            mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint;
            ASSERT(mailboxInfo->m_status == MailboxInUse);
            mailboxInfo->m_status = MailboxReleased;
            return;
        }
    }
}

WebKit::WebLayer* Canvas2DLayerBridge::layer()
{
    ASSERT(m_layer);
    return m_layer->layer();
}

void Canvas2DLayerBridge::contextAcquired()
{
    Canvas2DLayerManager::get().layerDidDraw(this);
    m_didRecordDrawCommand = true;
}

unsigned Canvas2DLayerBridge::backBufferTexture()
{
    if (!isValid())
        return 0;
    contextAcquired();
    m_canvas->flush();
    m_context->flush();
    GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget());
    if (renderTarget) {
        return renderTarget->asTexture()->getTextureHandle();
    }
    return 0;
}

Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) {
    // This copy constructor should only be used for Vector reallocation
    // Assuming 'other' is to be destroyed, we swap m_image ownership
    // rather than do a refcount dance.
    memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox));
    m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image));
    m_status = other.m_status;
}

}
<|endoftext|>


<commit_before>#include "Arena.hpp"
using namespace HIC;

// Global Engine
I3DEngine* gEngine = nullptr;

// Global Camera
ICamera* gCamera = nullptr;

// The game arena
Arena* gArena = nullptr;

///////////////////////////
// Front End Data

IFont* gMainMenuFont = nullptr;

ISprite* gContinueButtonSprite			= nullptr;
ISprite* gNewGameButtonSprite			= nullptr;
ISprite* gViewHiScoreButtonSprite		= nullptr;
ISprite* gQuitGameButtonSprite			= nullptr;

const float MENU_BUTTON_WIDTH = 256U;
const float MENU_BUTTON_HEIGHT = 64U;

// One off setup for the entire program.
// Returns true on success, false on failure
bool ProgramSetup()
{
	// Initialise the TL-Engine
	gEngine = New3DEngine(kTLX);
	gEngine->StartWindowed();
	gEngine->SetWindowCaption("Hyper Infinity Carnage");

	// Add default folder for meshes and other media
	gEngine->AddMediaFolder(".\\Media");

	// Initialise the camera
	gCamera = gEngine->CreateCamera(kFPS, 0.0f, 500.0f, -700.0f);

	return true;
}

// One off shutdown of the entire program
// Returns true on success, false on failure
bool ProgramShutdown()
{
	// Shutdown the TL-Engine
	gEngine->Delete();
	gEngine = nullptr;

	// Cleanup pointers
	gCamera = nullptr;

	return true;
}

// Setups the front end menu
// Returns true on success, false on failure
bool FrontEndSetup()
{
	// Load the main menu font
	gMainMenuFont = gEngine->LoadFont("Ubuntu Mono", 72);

	// Load the menu button sprites
	uint32_t halfScreenWidth = gEngine->GetWidth() / 2;

	// TODO: Check if save file exists

	gContinueButtonSprite = gEngine->CreateSprite("Continue_Button.png", halfScreenWidth - (MENU_BUTTON_WIDTH / 2), 250);

	return true;
}

// Updates the front end menu
// Returns true on success, false on failure
bool FrontEndUpdate(float frameTime)
{
	// Calculate the position to draw the title text
	uint32_t screenWidth = gEngine->GetWidth();
	uint32_t textWidth = gMainMenuFont->MeasureTextWidth("Hyper Infinity Carnage");

	// Draw the title
	gMainMenuFont->Draw("Hyper Infinity Carnage", (screenWidth / 2) - (textWidth / 2), 100, kRed);

	return true;
}

// Shutdowns the front end menu
// Returns true on success, false on failure
bool FrontEndShutdown()
{
	// Cleanup the main menu font
	gEngine->RemoveFont(gMainMenuFont);
	gMainMenuFont = nullptr;

	// Cleanup the menu button sprites
	gEngine->RemoveSprite(gContinueButtonSprite);
	gContinueButtonSprite = nullptr;

	return true;
}

// Setups the main game
// Returns true on success, false on failure
bool GameSetup()
{
	// Load the player mesh
	Player::MESH = gEngine->LoadMesh("Player.x");
	Arena::ARENA_MESH = gEngine->LoadMesh("Arena.x");
#ifdef _DEBUG
	CollisionObject::MARKER_MESH = gEngine->LoadMesh("dummy.x");
#endif
	// Load the arena
	gArena = new Arena(gEngine);

	return true;
}

// Updates the main game
// Returns true on success, false on failure
void GameUpdate(float frameTime)
{
	gArena->Update(frameTime);
	//gArena->TargetCamera(gCamera);
}

// Updates the main game
// Returns true on success, false on failure
bool GameShutdown()
{
	// Delete the arena
	delete(gArena);
	gArena = nullptr;

	// Delete the player mesh
	gEngine->RemoveMesh(Player::MESH);
	Player::MESH = nullptr;
	//Delete the arena mesh
	gEngine->RemoveMesh(Arena::ARENA_MESH);
	Arena::ARENA_MESH = nullptr;

#ifdef _DEBUG
	//Delete the collision object mesh
	gEngine->RemoveMesh(CollisionObject::MARKER_MESH);
	CollisionObject::MARKER_MESH = nullptr;
#endif

	return true;
}

// Main entry to the program
int main(int argc, char* argv[])
{
	// Initialise program (TL-Engine, OpenAL etc...). Quit Program on Failure
	if (!ProgramSetup())
	{
		return EXIT_FAILURE;
	}

	// Loop to return to the front-end
	while (true)
	{
		///////////////////////////////////
		// Front End Enter

		// Setup the front end
		if (!FrontEndSetup())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Update the front-end until the exit key is pressed
		while (!gEngine->KeyHit(Key_P))
		{
			// Update the front end
			float frameTime = gEngine->Timer();
			FrontEndUpdate(frameTime);

			// Exit the program if the exit key is pressed
			if (gEngine->KeyHit(Key_Q) || !gEngine->IsRunning())
			{
				FrontEndShutdown();
				ProgramShutdown();
				return EXIT_SUCCESS;
			}

			// Draw the scene
			gEngine->DrawScene();
		}

		if (!FrontEndShutdown())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Front End Exit
		///////////////////////////////////

		// TODO: Loading Screen

		///////////////////////////////////
		// Game Enter

		// Setup the game
		if (!GameSetup())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Continue in game loop until exited
		while (!gEngine->KeyHit(Key_Escape))
		{

			// Update the game
			float frameTime = gEngine->Timer();
			GameUpdate(frameTime);

			// Immediate program exit required (User closed window or pressed Alt-F4)
			if (!gEngine->IsRunning())
			{
				ProgramShutdown();
				return EXIT_SUCCESS;
			}

			// Draw the scene
			gEngine->DrawScene();
		}

		if (!GameShutdown())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Game Exit
		///////////////////////////////////
	}

	// Shutdown the program
	ProgramShutdown();

	return EXIT_SUCCESS;
}
<commit_msg>Added debug camera functionality<commit_after>#include "Arena.hpp"
using namespace HIC;

// Global Engine
I3DEngine* gEngine = nullptr;

// Global Camera
ICamera* gCamera = nullptr;
ICamera* gGameCamera = nullptr;
#ifdef _DEBUG
ICamera* gDebugCamera = nullptr;
#endif

// The game arena
Arena* gArena = nullptr;

///////////////////////////
// Front End Data

IFont* gMainMenuFont = nullptr;

ISprite* gContinueButtonSprite			= nullptr;
ISprite* gNewGameButtonSprite			= nullptr;
ISprite* gViewHiScoreButtonSprite		= nullptr;
ISprite* gQuitGameButtonSprite			= nullptr;

const float MENU_BUTTON_WIDTH = 256U;
const float MENU_BUTTON_HEIGHT = 64U;

// One off setup for the entire program.
// Returns true on success, false on failure
bool ProgramSetup()
{
	// Initialise the TL-Engine
	gEngine = New3DEngine(kTLX);
	gEngine->StartWindowed();
	gEngine->SetWindowCaption("Hyper Infinity Carnage");

	// Add default folder for meshes and other media
	gEngine->AddMediaFolder(".\\Media");

	// Initialise the camera
	gGameCamera = gEngine->CreateCamera(kManual, 0.0f, 500.0f, -700.0f);
#ifdef _DEBUG
	gDebugCamera = gEngine->CreateCamera(kFPS, 0.0f, 500.0f, -700.0f);
#endif
	gCamera = gGameCamera;

	return true;
}

// One off shutdown of the entire program
// Returns true on success, false on failure
bool ProgramShutdown()
{
	// Shutdown the TL-Engine
	gEngine->Delete();
	gEngine = nullptr;

	// Cleanup pointers
	gCamera = nullptr;
	gGameCamera = nullptr;
#ifdef _DEBUG
	gDebugCamera = nullptr;
#endif

	return true;
}

// Setups the front end menu
// Returns true on success, false on failure
bool FrontEndSetup()
{
	// Load the main menu font
	gMainMenuFont = gEngine->LoadFont("Ubuntu Mono", 72);

	// Load the menu button sprites
	uint32_t halfScreenWidth = gEngine->GetWidth() / 2;

	// TODO: Check if save file exists

	gContinueButtonSprite = gEngine->CreateSprite("Continue_Button.png", halfScreenWidth - (MENU_BUTTON_WIDTH / 2), 250);

	return true;
}

// Updates the front end menu
// Returns true on success, false on failure
bool FrontEndUpdate(float frameTime)
{
	// Calculate the position to draw the title text
	uint32_t screenWidth = gEngine->GetWidth();
	uint32_t textWidth = gMainMenuFont->MeasureTextWidth("Hyper Infinity Carnage");

	// Draw the title
	gMainMenuFont->Draw("Hyper Infinity Carnage", (screenWidth / 2) - (textWidth / 2), 100, kRed);

	return true;
}

// Shutdowns the front end menu
// Returns true on success, false on failure
bool FrontEndShutdown()
{
	// Cleanup the main menu font
	gEngine->RemoveFont(gMainMenuFont);
	gMainMenuFont = nullptr;

	// Cleanup the menu button sprites
	gEngine->RemoveSprite(gContinueButtonSprite);
	gContinueButtonSprite = nullptr;

	return true;
}

// Setups the main game
// Returns true on success, false on failure
bool GameSetup()
{
	// Load the player mesh
	Player::MESH = gEngine->LoadMesh("Player.x");
	Arena::ARENA_MESH = gEngine->LoadMesh("Arena.x");
#ifdef _DEBUG
	CollisionObject::MARKER_MESH = gEngine->LoadMesh("dummy.x");
#endif
	// Load the arena
	gArena = new Arena(gEngine);

	return true;
}

// Updates the main game
// Returns true on success, false on failure
void GameUpdate(float frameTime)
{
	gArena->Update(frameTime);
	gArena->TargetCamera(gGameCamera);
#ifdef _DEBUG
	if (gEngine->KeyHit(Key_Tab))
	{
		//Swap which camera is the gCamera
		if (gGameCamera == gCamera)
		{
			gCamera = gDebugCamera;
		}
		else
		{
			gCamera = gGameCamera;
		}
	}

#endif
}

// Updates the main game
// Returns true on success, false on failure
bool GameShutdown()
{
	// Delete the arena
	delete(gArena);
	gArena = nullptr;

	// Delete the player mesh
	gEngine->RemoveMesh(Player::MESH);
	Player::MESH = nullptr;
	//Delete the arena mesh
	gEngine->RemoveMesh(Arena::ARENA_MESH);
	Arena::ARENA_MESH = nullptr;

#ifdef _DEBUG
	//Delete the collision object mesh
	gEngine->RemoveMesh(CollisionObject::MARKER_MESH);
	CollisionObject::MARKER_MESH = nullptr;
#endif

	return true;
}

// Main entry to the program
int main(int argc, char* argv[])
{
	// Initialise program (TL-Engine, OpenAL etc...). Quit Program on Failure
	if (!ProgramSetup())
	{
		return EXIT_FAILURE;
	}

	// Loop to return to the front-end
	while (true)
	{
		///////////////////////////////////
		// Front End Enter

		// Setup the front end
		if (!FrontEndSetup())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Update the front-end until the exit key is pressed
		while (!gEngine->KeyHit(Key_P))
		{
			// Update the front end
			float frameTime = gEngine->Timer();
			FrontEndUpdate(frameTime);

			// Exit the program if the exit key is pressed
			if (gEngine->KeyHit(Key_Q) || !gEngine->IsRunning())
			{
				FrontEndShutdown();
				ProgramShutdown();
				return EXIT_SUCCESS;
			}

			// Draw the scene
			gEngine->DrawScene(gCamera);
		}

		if (!FrontEndShutdown())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Front End Exit
		///////////////////////////////////

		// TODO: Loading Screen

		///////////////////////////////////
		// Game Enter

		// Setup the game
		if (!GameSetup())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Continue in game loop until exited
		while (!gEngine->KeyHit(Key_Escape))
		{

			// Update the game
			float frameTime = gEngine->Timer();
			GameUpdate(frameTime);

			// Immediate program exit required (User closed window or pressed Alt-F4)
			if (!gEngine->IsRunning())
			{
				ProgramShutdown();
				return EXIT_SUCCESS;
			}

			// Draw the scene
			gEngine->DrawScene(gCamera);
		}

		if (!GameShutdown())
		{
			ProgramShutdown();
			return EXIT_FAILURE;
		}

		// Game Exit
		///////////////////////////////////
	}

	// Shutdown the program
	ProgramShutdown();

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "nodes.hpp"

namespace lang {
  Variable* resolveNameFrom(ASTNode* localNode, std::string identifier) {
    if (localNode == nullptr) return nullptr; // Reached tree root and didn't find anything.
    try {
      return localNode->getScope()->at(identifier);
    } catch(std::out_of_range& oor) {
      return resolveNameFrom(localNode->getParent(), identifier);
    }
  }

  void printIndent(int level) {
    for (int i = 0; i < level; ++i) print("  ");
  }

  ASTNode::ASTNode() {}
  ASTNode::~ASTNode() {}

  void ASTNode::addChild(ASTNode* child) {
    child->setParent(this);
    children.push_back(child);
  }

  std::vector<ASTNode*>& ASTNode::getChildren() {
    return children;
  }

  void ASTNode::setParent(ASTNode* parent) {
    this->parent = parent;
  }
  ASTNode* ASTNode::getParent() {
    return parent;
  }

  Scope* ASTNode::getScope() {
    return &local;
  }

  Scope* ASTNode::getParentScope() {
    return &this->parent->local;
  }

  void ASTNode::setLineNumber(int lines) {
    this->lines = lines;
  }
  int ASTNode::getLineNumber() {
    return this->lines;
  }

  std::string ASTNode::getNodeType() {
    return "ASTNode";
  }

  void ASTNode::printTree(int level) {
    printIndent(level);
    print("Plain ASTNode");
    for (auto child : children) {
      child->printTree(level + 1);
    }
  }

  SingleChildNode::SingleChildNode() {};
  void SingleChildNode::addChild(ASTNode* child) {
    if (this->getChildren().size() >= 1) throw std::runtime_error("Trying to add more than one child to SingleChildNode.");
    else {
      this->ASTNode::addChild(child);
    }
  }

  ASTNode* SingleChildNode::getChild() {
    return children[0];
  }

  std::string SingleChildNode::getNodeType() {
    return "SingleChildNode";
  }

  void SingleChildNode::printTree(int level) {
    printIndent(level);
    auto child = dynamic_cast<SingleChildNode*>(this->getChild());
    if (child == nullptr) {
      print("SingleChildNode, empty", "\n");
      return;
    }
    print("SingleChildNode with: ", child, "\n");
    child->printTree(level + 1);
  }

  DeclarationNode::DeclarationNode(std::vector<std::string> typeNames, Token identifier) {
    this->typeNames = typeNames;
    this->identifier = identifier;
  }

  void DeclarationNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<ExpressionNode*>(child);
    if (node == nullptr) throw std::invalid_argument("DeclarationNode only accepts an ExpressionNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string DeclarationNode::getNodeType() {
    return "DeclarationNode";
  }

  void DeclarationNode::printTree(int level) {
    printIndent(level);
    print("Declared ", this->typeNames, " as ", this->identifier, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<ExpressionNode*>(this->getChild())->printTree(level + 1);
  }

  FunctionNode::FunctionNode(std::string name, Arguments* arguments, std::vector<std::string> returnTypes):
    name(name),
    defaultArguments(arguments),
    returnTypes(returnTypes) {}

  void FunctionNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<BlockNode*>(child);
    if (node == nullptr) throw std::invalid_argument("FunctionNode only accepts a BlockNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string FunctionNode::getNodeType() {return "FunctionNode";}

  void FunctionNode::printTree(int level) {
    printIndent(level);
    print("Function " + name, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<BlockNode*>(this->getChild())->printTree(level + 1);
  }

  std::string FunctionNode::getName() {
    return name;
  }

  Arguments* FunctionNode::getArguments() {
    return defaultArguments;
  }

  TypeList FunctionNode::getReturnTypes() {
    return returnTypes;
  }

  std::vector<TokenType> ExpressionNode::validOperandTypes {
    INTEGER, FLOAT, STRING, BOOLEAN, ARRAY, TYPE, VARIABLE, FUNCTION, MEMBER
  };

  ExpressionNode::ExpressionNode(std::vector<Token>& tokens) {
    for (uint64 i = 0; i < tokens.size(); ++i) {
      if (EXPRESSION_STEPS) {
        for (auto tok : outStack) print(tok.data, " ");
        print("\n-------\n");
        for (auto tok : opStack) print(tok.data, " ");
        print("\n=======\n");
      }
      if (contains(tokens[i].type, validOperandTypes)) {
        outStack.push_back(tokens[i]);
      } else if (tokens[i].type == OPERATOR) {
        /*
        * This prevents crash when there's no operators.
        * Or when it found a parenthesis, because they're not really operators.
        */
        if (opStack.size() == 0 || opStack.back().data == "(") {
          opStack.push_back(tokens[i]);
          continue;
        }
        Operator current = *static_cast<Operator*>(tokens[i].typeData);
        Operator topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        while (opStack.size() != 0) {
          if ((current.getAssociativity() == ASSOCIATE_FROM_LEFT && current.getPrecedence() <= topOfStack.getPrecedence()) ||
          (current.getAssociativity() == ASSOCIATE_FROM_RIGHT && current.getPrecedence() < topOfStack.getPrecedence())) {
            popToOut();
          } else break;
          // Non-operators (eg parenthesis) will crash on next line, and must break to properly evaluate expression
          if (opStack.back().type != OPERATOR) break;
          // Get new top of stack
          if (opStack.size() != 0) topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        }
        opStack.push_back(tokens[i]);
      } else if (tokens[i].type == CONSTRUCT) {
        if (isNewLine(tokens[i])) break;
        if (tokens[i].data != "(" && tokens[i].data != ")") {
          throw Error("Illegal construct in expression: \"" + tokens[i].data + "\"", "SyntaxError", tokens[i].line);
        } else if (tokens[i].data == "(") {
          opStack.push_back(tokens[i]);
        } else if (tokens[i].data == ")") {
          while (opStack.size() != 0 && opStack.back().data != "(") popToOut();
          if (opStack.back().data != "(") throw Error("Mismatched parenthesis in expression", "SyntaxError", outStack.back().line);
          opStack.pop_back(); // Get rid of "("
          if (opStack.back().type == FUNCTION) popToOut();
        }
      }
    }
    while (opStack.size() > 0) popToOut();
  }

  std::vector<Token> ExpressionNode::getRPNOutput() {
    return outStack;
  }

  void ExpressionNode::buildSubtree(void) {
    std::vector<Token> stackCopy(outStack);
    ExpressionChildNode* node;
    if (stackCopy.size() >= 1) {
      auto tok = stackCopy.back();
      stackCopy.pop_back();
      node = new ExpressionChildNode(tok, stackCopy);
      node->setLineNumber(this->lines);
    } else {
      throw std::runtime_error("Empty expression.\n");
    }
    this->children.clear();
    this->addChild(node);
  }

  std::string ExpressionNode::getNodeType() {
    return "ExpressionNode";
  }

  void ExpressionNode::printTree(int level) {
    auto top = static_cast<ExpressionChildNode*>(this->getChildren()[0]);
    top->printTree(level);
  }

  ExpressionChildNode::ExpressionChildNode(Token operand): t(operand) {};
  ExpressionChildNode::ExpressionChildNode(Token op, std::vector<Token>& operands): t(op) {
    if (operands.size() == 0) return;
    auto arity = static_cast<Operator*>(op.typeData)->getArity();
    for (int i = 0; i < arity; ++i) {
      auto next = operands[operands.size() - 1];
      if (next.type == OPERATOR) {
        operands.pop_back();
        auto branch = new ExpressionChildNode(next, operands);
        branch->setLineNumber(op.line);
        this->addChild(branch);
      } else {
        operands.pop_back();
        auto leaf = new ExpressionChildNode(next);
        leaf->setLineNumber(op.line);
        this->addChild(leaf);
      }
    }
  };

  std::string ExpressionChildNode::getNodeType() {
    return "ExpressionChildNode";
  }

  void ExpressionChildNode::printTree(int level) {
    printIndent(level);
    print(this->t, "\n");
    for (auto child : this->getChildren()) {
      static_cast<ExpressionChildNode*>(child)->printTree(level + 1);
    }
  }

  BlockNode::BlockNode() {}

  std::string BlockNode::getNodeType() {
    return "BlockNode";
  }

  void BlockNode::printTree(int level) {
    printIndent(level);
    print("BlockNode\n");
    for (auto node : children) {
      node->printTree(level + 1);
    }
  }

  ConditionalNode::ConditionalNode(ExpressionNode* condition, BlockNode* trueBlock, BlockNode* falseBlock) {
    this->children.push_back(condition);
    this->children.push_back(trueBlock);
    this->children.push_back(falseBlock);
    condition->setParent(this);
    trueBlock->setParent(this);
    falseBlock->setParent(this);
  }

  ExpressionNode* ConditionalNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* ConditionalNode::getTrueBlock() {return dynamic_cast<BlockNode*>(children[1]);}
  BlockNode* ConditionalNode::getFalseBlock() {return dynamic_cast<BlockNode*>(children[2]);}

  void ConditionalNode::addChild(ASTNode* child) {
    children[this->block]->addChild(child);
  }

  void ConditionalNode::nextBlock() {
    static bool wasCalled = false;
    if (!wasCalled) {
      wasCalled = true;
      this->block++;
    } else throw Error("Multiple else statements", "SyntaxError", children[2]->getLineNumber());
  }

  std::string ConditionalNode::getNodeType() {
    return "ConditionalNode";
  }

  void ConditionalNode::printTree(int level) {
    printIndent(level);
    print("Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  WhileNode::WhileNode(ExpressionNode* condition, BlockNode* loop) {
    this->children.push_back(condition);
    this->children.push_back(loop);
    condition->setParent(this);
    loop->setParent(this);
  }

  ExpressionNode* WhileNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* WhileNode::getLoopNode() {return dynamic_cast<BlockNode*>(children[1]);}

  void WhileNode::addChild(ASTNode* child) {
    children[1]->addChild(child);
  }

  std::string WhileNode::getNodeType() {
    return "WhileNode";
  }

  void WhileNode::printTree(int level) {
    printIndent(level);
    print("While Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  AST::AbstractSyntaxTree() {
    Type* integerType = new Type(std::string("Integer"), {
      // Static members
      {"MAX_VALUE", new Member(new Variable(new Integer(LLONG_MAX), {}), PUBLIC)},
      {"MIN_VALUE", new Member(new Variable(new Integer(LLONG_MIN), {}), PUBLIC)}
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Integer")] = new Variable(integerType, {}); // Do not allow assignment by not specifying any allowed types for the Variable
    Type* floatType = new Type(std::string("Float"), {
      // Static members
      {"MAX_VALUE", new Member(new Variable(new Float(FLT_MAX), {}), PUBLIC)},
      {"MIN_VALUE", new Member(new Variable(new Float(FLT_MIN), {}), PUBLIC)}
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Float")] = new Variable(floatType, {});
    Type* stringType = new Type(std::string("String"), {
      // Static members
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("String")] = new Variable(stringType, {});
    Type* booleanType = new Type(std::string("Boolean"), {
      // Static members
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Boolean")] = new Variable(booleanType, {});
  }

  void AST::addRootChild(ASTNode* node) {
    root.addChild(node);
  }

  ChildrenNodes AST::getRootChildren() {
    return root.getChildren();
  }

} /* namespace lang */
<commit_msg>Added Function type<commit_after>#include "nodes.hpp"

namespace lang {
  Variable* resolveNameFrom(ASTNode* localNode, std::string identifier) {
    if (localNode == nullptr) return nullptr; // Reached tree root and didn't find anything.
    try {
      return localNode->getScope()->at(identifier);
    } catch(std::out_of_range& oor) {
      return resolveNameFrom(localNode->getParent(), identifier);
    }
  }

  void printIndent(int level) {
    for (int i = 0; i < level; ++i) print("  ");
  }

  ASTNode::ASTNode() {}
  ASTNode::~ASTNode() {}

  void ASTNode::addChild(ASTNode* child) {
    child->setParent(this);
    children.push_back(child);
  }

  std::vector<ASTNode*>& ASTNode::getChildren() {
    return children;
  }

  void ASTNode::setParent(ASTNode* parent) {
    this->parent = parent;
  }
  ASTNode* ASTNode::getParent() {
    return parent;
  }

  Scope* ASTNode::getScope() {
    return &local;
  }

  Scope* ASTNode::getParentScope() {
    return &this->parent->local;
  }

  void ASTNode::setLineNumber(int lines) {
    this->lines = lines;
  }
  int ASTNode::getLineNumber() {
    return this->lines;
  }

  std::string ASTNode::getNodeType() {
    return "ASTNode";
  }

  void ASTNode::printTree(int level) {
    printIndent(level);
    print("Plain ASTNode");
    for (auto child : children) {
      child->printTree(level + 1);
    }
  }

  SingleChildNode::SingleChildNode() {};
  void SingleChildNode::addChild(ASTNode* child) {
    if (this->getChildren().size() >= 1) throw std::runtime_error("Trying to add more than one child to SingleChildNode.");
    else {
      this->ASTNode::addChild(child);
    }
  }

  ASTNode* SingleChildNode::getChild() {
    return children[0];
  }

  std::string SingleChildNode::getNodeType() {
    return "SingleChildNode";
  }

  void SingleChildNode::printTree(int level) {
    printIndent(level);
    auto child = dynamic_cast<SingleChildNode*>(this->getChild());
    if (child == nullptr) {
      print("SingleChildNode, empty", "\n");
      return;
    }
    print("SingleChildNode with: ", child, "\n");
    child->printTree(level + 1);
  }

  DeclarationNode::DeclarationNode(std::vector<std::string> typeNames, Token identifier) {
    this->typeNames = typeNames;
    this->identifier = identifier;
  }

  void DeclarationNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<ExpressionNode*>(child);
    if (node == nullptr) throw std::invalid_argument("DeclarationNode only accepts an ExpressionNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string DeclarationNode::getNodeType() {
    return "DeclarationNode";
  }

  void DeclarationNode::printTree(int level) {
    printIndent(level);
    print("Declared ", this->typeNames, " as ", this->identifier, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<ExpressionNode*>(this->getChild())->printTree(level + 1);
  }

  FunctionNode::FunctionNode(std::string name, Arguments* arguments, std::vector<std::string> returnTypes):
    name(name),
    defaultArguments(arguments),
    returnTypes(returnTypes) {}

  void FunctionNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<BlockNode*>(child);
    if (node == nullptr) throw std::invalid_argument("FunctionNode only accepts a BlockNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string FunctionNode::getNodeType() {return "FunctionNode";}

  void FunctionNode::printTree(int level) {
    printIndent(level);
    print("Function " + name, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<BlockNode*>(this->getChild())->printTree(level + 1);
  }

  std::string FunctionNode::getName() {
    return name;
  }

  Arguments* FunctionNode::getArguments() {
    return defaultArguments;
  }

  TypeList FunctionNode::getReturnTypes() {
    return returnTypes;
  }

  std::vector<TokenType> ExpressionNode::validOperandTypes {
    INTEGER, FLOAT, STRING, BOOLEAN, ARRAY, TYPE, VARIABLE, FUNCTION, MEMBER
  };

  ExpressionNode::ExpressionNode(std::vector<Token>& tokens) {
    for (uint64 i = 0; i < tokens.size(); ++i) {
      if (EXPRESSION_STEPS) {
        for (auto tok : outStack) print(tok.data, " ");
        print("\n-------\n");
        for (auto tok : opStack) print(tok.data, " ");
        print("\n=======\n");
      }
      if (contains(tokens[i].type, validOperandTypes)) {
        outStack.push_back(tokens[i]);
      } else if (tokens[i].type == OPERATOR) {
        /*
        * This prevents crash when there's no operators.
        * Or when it found a parenthesis, because they're not really operators.
        */
        if (opStack.size() == 0 || opStack.back().data == "(") {
          opStack.push_back(tokens[i]);
          continue;
        }
        Operator current = *static_cast<Operator*>(tokens[i].typeData);
        Operator topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        while (opStack.size() != 0) {
          if ((current.getAssociativity() == ASSOCIATE_FROM_LEFT && current.getPrecedence() <= topOfStack.getPrecedence()) ||
          (current.getAssociativity() == ASSOCIATE_FROM_RIGHT && current.getPrecedence() < topOfStack.getPrecedence())) {
            popToOut();
          } else break;
          // Non-operators (eg parenthesis) will crash on next line, and must break to properly evaluate expression
          if (opStack.back().type != OPERATOR) break;
          // Get new top of stack
          if (opStack.size() != 0) topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        }
        opStack.push_back(tokens[i]);
      } else if (tokens[i].type == CONSTRUCT) {
        if (isNewLine(tokens[i])) break;
        if (tokens[i].data != "(" && tokens[i].data != ")") {
          throw Error("Illegal construct in expression: \"" + tokens[i].data + "\"", "SyntaxError", tokens[i].line);
        } else if (tokens[i].data == "(") {
          opStack.push_back(tokens[i]);
        } else if (tokens[i].data == ")") {
          while (opStack.size() != 0 && opStack.back().data != "(") popToOut();
          if (opStack.back().data != "(") throw Error("Mismatched parenthesis in expression", "SyntaxError", outStack.back().line);
          opStack.pop_back(); // Get rid of "("
          if (opStack.back().type == FUNCTION) popToOut();
        }
      }
    }
    while (opStack.size() > 0) popToOut();
  }

  std::vector<Token> ExpressionNode::getRPNOutput() {
    return outStack;
  }

  void ExpressionNode::buildSubtree(void) {
    std::vector<Token> stackCopy(outStack);
    ExpressionChildNode* node;
    if (stackCopy.size() >= 1) {
      auto tok = stackCopy.back();
      stackCopy.pop_back();
      node = new ExpressionChildNode(tok, stackCopy);
      node->setLineNumber(this->lines);
    } else {
      throw std::runtime_error("Empty expression.\n");
    }
    this->children.clear();
    this->addChild(node);
  }

  std::string ExpressionNode::getNodeType() {
    return "ExpressionNode";
  }

  void ExpressionNode::printTree(int level) {
    auto top = static_cast<ExpressionChildNode*>(this->getChildren()[0]);
    top->printTree(level);
  }

  ExpressionChildNode::ExpressionChildNode(Token operand): t(operand) {};
  ExpressionChildNode::ExpressionChildNode(Token op, std::vector<Token>& operands): t(op) {
    if (operands.size() == 0) return;
    auto arity = static_cast<Operator*>(op.typeData)->getArity();
    for (int i = 0; i < arity; ++i) {
      auto next = operands[operands.size() - 1];
      if (next.type == OPERATOR) {
        operands.pop_back();
        auto branch = new ExpressionChildNode(next, operands);
        branch->setLineNumber(op.line);
        this->addChild(branch);
      } else {
        operands.pop_back();
        auto leaf = new ExpressionChildNode(next);
        leaf->setLineNumber(op.line);
        this->addChild(leaf);
      }
    }
  };

  std::string ExpressionChildNode::getNodeType() {
    return "ExpressionChildNode";
  }

  void ExpressionChildNode::printTree(int level) {
    printIndent(level);
    print(this->t, "\n");
    for (auto child : this->getChildren()) {
      static_cast<ExpressionChildNode*>(child)->printTree(level + 1);
    }
  }

  BlockNode::BlockNode() {}

  std::string BlockNode::getNodeType() {
    return "BlockNode";
  }

  void BlockNode::printTree(int level) {
    printIndent(level);
    print("BlockNode\n");
    for (auto node : children) {
      node->printTree(level + 1);
    }
  }

  ConditionalNode::ConditionalNode(ExpressionNode* condition, BlockNode* trueBlock, BlockNode* falseBlock) {
    this->children.push_back(condition);
    this->children.push_back(trueBlock);
    this->children.push_back(falseBlock);
    condition->setParent(this);
    trueBlock->setParent(this);
    falseBlock->setParent(this);
  }

  ExpressionNode* ConditionalNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* ConditionalNode::getTrueBlock() {return dynamic_cast<BlockNode*>(children[1]);}
  BlockNode* ConditionalNode::getFalseBlock() {return dynamic_cast<BlockNode*>(children[2]);}

  void ConditionalNode::addChild(ASTNode* child) {
    children[this->block]->addChild(child);
  }

  void ConditionalNode::nextBlock() {
    static bool wasCalled = false;
    if (!wasCalled) {
      wasCalled = true;
      this->block++;
    } else throw Error("Multiple else statements", "SyntaxError", children[2]->getLineNumber());
  }

  std::string ConditionalNode::getNodeType() {
    return "ConditionalNode";
  }

  void ConditionalNode::printTree(int level) {
    printIndent(level);
    print("Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  WhileNode::WhileNode(ExpressionNode* condition, BlockNode* loop) {
    this->children.push_back(condition);
    this->children.push_back(loop);
    condition->setParent(this);
    loop->setParent(this);
  }

  ExpressionNode* WhileNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* WhileNode::getLoopNode() {return dynamic_cast<BlockNode*>(children[1]);}

  void WhileNode::addChild(ASTNode* child) {
    children[1]->addChild(child);
  }

  std::string WhileNode::getNodeType() {
    return "WhileNode";
  }

  void WhileNode::printTree(int level) {
    printIndent(level);
    print("While Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  AST::AbstractSyntaxTree() {
    Type* integerType = new Type(std::string("Integer"), {
      // Static members
      {"MAX_VALUE", new Member(new Variable(new Integer(LLONG_MAX), {}), PUBLIC)},
      {"MIN_VALUE", new Member(new Variable(new Integer(LLONG_MIN), {}), PUBLIC)}
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Integer")] = new Variable(integerType, {}); // Do not allow assignment by not specifying any allowed types for the Variable
    Type* floatType = new Type(std::string("Float"), {
      // Static members
      {"MAX_VALUE", new Member(new Variable(new Float(FLT_MAX), {}), PUBLIC)},
      {"MIN_VALUE", new Member(new Variable(new Float(FLT_MIN), {}), PUBLIC)}
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Float")] = new Variable(floatType, {});
    Type* stringType = new Type(std::string("String"), {
      // Static members
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("String")] = new Variable(stringType, {});
    Type* booleanType = new Type(std::string("Boolean"), {
      // Static members
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Boolean")] = new Variable(booleanType, {});
    Type* functionType = new Type(std::string("Function"), {
      // Static members
    }, {
      // Instance members
      // TODO add members
    });
    (*root.getScope())[std::string("Function")] = new Variable(functionType, {});
  }

  void AST::addRootChild(ASTNode* node) {
    root.addChild(node);
  }

  ChildrenNodes AST::getRootChildren() {
    return root.getChildren();
  }

} /* namespace lang */
<|endoftext|>


<commit_before>/*
Copyright 2016 Christian Parritt

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.

Description: This file contains the logic for an artificial
go fish player. It is made to interface with peripheral devices and
programs sunch as OpenCV and a camera to acquire information on cards in its
hand and to be asked for cards.
*/

#include "logic.h"
#include <iostream>
#include <iomanip>

int main()
{
	int loop_end = 0;
	char input = '';
	int init_card[5] = {0};
	int scan_card = 0;
	int ai_level = 0;
	bool man_switch = false;

	start:
	while (loop_end == 0)
	{
		choice:
		cout << "Do you want to play in manual mode or camera mode?\n";
		cout << "Please input M or m for manual and C or c for camera\n"; //TODO: Add period.
		cin >> input;
		if(input == 77 || input == 109)//Manual
		{
			for(int i = 1; i < 6; ++i)
			{
				cout << "Input card "<< i << " rank\n"; // asuming we put in only right inputs TODO: add period
				cin >> input;
				init_card[i-1] = atoi(input);
			}
			cout << "Input AI level (1-3)\n" //TODO: remove AI query here. It is duplicated in game_init
			cin >> input;
			ai_level = atoi(input);
			man_switch = true;
			goto play;
		}
		else if(input == 67 || input == 99)//Camera
		{
			//TODO: Need to add cam stuff

		}
		else
		{
				cout << "invalid input\n";
				goto choice;
		}
		play://Need to add functions
		game_init(init_card[0],init_card[1],init_card[2],init_card[3],init_card[4],ai_level);

	}
	again:
	cout << "Do you want to play again?\n"; //TODO: Add Y or N query
	cin >> input;//Y or y yes n or N no
	if(input == 89 || input == 121)
	{
		loop_end = 0;
		input = '';
		init_card = {0,0,0,0,0};
		scan_card = 0;
		ai_level = 0;
		man_switch = false;
		goto start;
	}
	else if(input == 78 || input == 110)
	{
		cout << "Goodbye" << endl;
		return 0;
	}
	else
		{
			cout << "invalid input\n";
			goto again;
		}
}<commit_msg>Fixed Various TODO Items<commit_after>/*
Copyright 2016 Christian Parritt

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.

Description: This file contains the logic for an artificial
go fish player. It is made to interface with peripheral devices and
programs sunch as OpenCV and a camera to acquire information on cards in its
hand and to be asked for cards.
*/

#include "logic.h"
#include <iostream>
#include <iomanip>

int main()
{
	int loop_end = 0;
	char input = '';
	int init_card[5] = {0};
	int scan_card = 0;
	bool man_switch = false;

	start:
	while (loop_end == 0)
	{
		choice:
		cout << "Do you want to play in manual mode or camera mode?\n";
		cout << "Please input M or m for manual and C or c for camera.\n";
		cin >> input;
		if(input == 77 || input == 109)//Manual
		{
			for(int i = 1; i < 6; ++i)
			{
				cout << "Input card "<< i << " rank.\n"; // asuming we put in only right inputs
				cin >> input;
				init_card[i-1] = atoi(input);
			}
			man_switch = true;
			goto play;
		}
		else if(input == 67 || input == 99)//Camera
		{
			//TODO: Need to add cam stuff
		}
		else
		{
				cout << "Invalid input!\n";
				goto choice;
		}
		play://TODO: Need to add functions
		game_init(init_card[0],init_card[1],init_card[2],init_card[3],init_card[4]);

	}
	again:
	cout << "Do you want to play again?\n"; //TODO: Add Y or N query
	cin >> input;//Y or y yes n or N no
	if(input == 89 || input == 121)
	{
		loop_end = 0;
		input = '';
		init_card = {0,0,0,0,0};
		scan_card = 0;
		ai_level = 0;
		man_switch = false;
		goto start;
	}
	else if(input == 78 || input == 110)
	{
		cout << "Goodbye" << endl;
		return 0;
	}
	else
		{
			cout << "invalid input\n";
			goto again;
		}
}<|endoftext|>


<commit_before>ec9b5338-ad58-11e7-8ca5-ac87a332f658<commit_msg>Long commit messages are not required<commit_after>ed0cec5c-ad58-11e7-ae1d-ac87a332f658<|endoftext|>


<commit_before>b1b82138-ad5a-11e7-ad57-ac87a332f658<commit_msg>new flies<commit_after>b21c9942-ad5a-11e7-89cf-ac87a332f658<|endoftext|>


<commit_before>/* To-Do:

- write rules for cells living/dying
- add checks for input size during setInitialState()
- add check for correct character values when initializing grid
- add function to randomly generate an initial state, given grid dimensions
- implement exceptions where marked
- learn ncurses to implement graphics
*/

#define ALIVE '#'
#define DEAD '.'

#include <iostream>
using std::cin; using std::cout; using std::endl;
#include <fstream>
using std::ifstream;
#include <string>
using std::string; using std::getline;

// create 2D array to use as the grid
bool** createGridArray(unsigned int grid_width, unsigned int grid_depth)
{
    bool** grid_array_pointer = new bool*[grid_depth];
    for (unsigned int i = 0; i < grid_depth; ++i) {
        grid_array_pointer[i] = new bool[grid_width];
    }
    return grid_array_pointer;
}

// set initial state of the grid
// ADD AN EXCEPTION HERE
void setInitialState(bool** grid, ifstream& init_file, unsigned int grid_width, unsigned int grid_depth)
{
    // get a line to represent each row and copy it into the grid
    string row;
    for (unsigned int y = 0; y < grid_depth; ++y) {
        getline(init_file,row);
        for (unsigned int x = 0; x < grid_width; ++x) {
            if (row[x] == ALIVE) {
                grid[y][x] = true;
            }
            else if (row[x] == DEAD) {
                grid[y][x] = false;
            }
            else {
                // raise not_implemented_error;
            }
        }
    }
}

void findNeighbors(bool* neighbors, bool** grid, unsigned int grid_width, unsigned int grid_depth, int target_y; int target_x)
{
    unsigned int count = 0;
    for (int y = target_y - 1; y <= target_y + 1; ++y) {
        for (int x = target_x - 1; x <= target_x + 1; ++x) {
            if (y == target_y && x == target_x) // ignore target itself
                continue
            // add length of row/column to offset effect of negative int in mod calculation
            neighbors[count] = grid[(y + grid_depth) % grid_depth][(x + grid_width) % grid_width];
            ++count;
        }
    }
}

void writeNextFrame(bool** grid, unsigned int grid_width, unsigned int grid_depth)
{
    // call findNeighbors on each element in grid and change value based on Conway's rules
    // create a second grid object to read from so calculations aren't affected by new frame being drawn
}

void runGame(unsigned int turns, bool** grid)
{
    // main game loop
}

void displayGrid(bool** grid, unsigned int grid_width, unsigned int grid_depth)
{
    for (unsigned int i = 0; i < grid_depth; ++i) {
        for (unsigned int j = 0; j < grid_width; ++j) {
            if (grid[i][j]) {
                cout << ALIVE << " ";
            }
            else if (!grid[i][j]) {
                cout << DEAD << " ";
            }
        }
        cout << endl;
    }
}

int main()
{
    unsigned int grid_width, grid_depth, turns;
    string file_name;
    ifstream init_file;

    cout << "Enter name of initialization file:" << endl;
    cin >> file_name;
    init_file.open(file_name);

    // get dimensions of grid
    init_file >> grid_width >> grid_depth >> turns;

    // move buffer position to next line in file
    init_file.seekg(1, init_file.cur);

    // create grid and set initial state
    bool** life_grid = createGridArray(grid_width,grid_depth);
    setInitialState(life_grid, init_file, grid_width, grid_depth);
    displayGrid(life_grid, grid_width, grid_depth);

    init_file.close();

    return 0;
}
<commit_msg>change findNeighbors to countNeighbors; now returns an int and doesn't require an extra array for neighboring cells<commit_after>/* To-Do:

- write rules for cells living/dying
- add checks for input size during setInitialState()
- add check for correct character values when initializing grid
- add function to randomly generate an initial state, given grid dimensions
- implement exceptions where marked
- learn ncurses to implement graphics
*/

#define ALIVE '#'
#define DEAD '.'

#include <iostream>
using std::cin; using std::cout; using std::endl;
#include <fstream>
using std::ifstream;
#include <string>
using std::string; using std::getline;

// create 2D array to use as the grid
bool** createGridArray(unsigned int grid_width, unsigned int grid_depth)
{
    bool** grid_array_pointer = new bool*[grid_depth];
    for (unsigned int i = 0; i < grid_depth; ++i) {
        grid_array_pointer[i] = new bool[grid_width];
    }
    return grid_array_pointer;
}

// set initial state of the grid
// ADD AN EXCEPTION HERE
void setInitialState(bool** grid, ifstream& init_file, unsigned int grid_width, unsigned int grid_depth)
{
    // get a line to represent each row and copy it into the grid
    string row;
    for (unsigned int y = 0; y < grid_depth; ++y) {
        getline(init_file,row);
        for (unsigned int x = 0; x < grid_width; ++x) {
            if (row[x] == ALIVE) {
                grid[y][x] = true;
            }
            else if (row[x] == DEAD) {
                grid[y][x] = false;
            }
            else {
                // raise not_implemented_error;
            }
        }
    }
}

// Sum the values of each neighboring cell in the grid and return it
// Since the grid is a bool array, should be equal to number of live cells
int countNeighbors(bool** grid, unsigned int grid_width, unsigned int grid_depth, int target_y; int target_x)
{
    unsigned int live_neighbors = 0;
    for (int y = target_y - 1; y <= target_y + 1; ++y) {
        for (int x = target_x - 1; x <= target_x + 1; ++x) {
            if (y == target_y && x == target_x) // ignore target itself
                continue
            // add length of row/column to offset effect of negative int in mod calculation
            live_neighbors += grid[(y + grid_depth) % grid_depth][(x + grid_width) % grid_width];
        }
    }
    return live_neighbors;
}

void writeNextFrame(bool** grid, unsigned int grid_width, unsigned int grid_depth)
{
    // call findNeighbors on each element in grid and change value based on Conway's rules
    // create a second grid object to read from so calculations aren't affected by new frame being drawn

}

void runGame(unsigned int turns, bool** grid)
{
    // main game loop
}

void displayGrid(bool** grid, unsigned int grid_width, unsigned int grid_depth)
{
    for (unsigned int i = 0; i < grid_depth; ++i) {
        for (unsigned int j = 0; j < grid_width; ++j) {
            if (grid[i][j]) {
                cout << ALIVE << " ";
            }
            else if (!grid[i][j]) {
                cout << DEAD << " ";
            }
        }
        cout << endl;
    }
}

int main()
{
    unsigned int grid_width, grid_depth, turns;
    string file_name;
    ifstream init_file;

    cout << "Enter name of initialization file:" << endl;
    cin >> file_name;
    init_file.open(file_name);

    // get dimensions of grid
    init_file >> grid_width >> grid_depth >> turns;

    // move buffer position to next line in file
    init_file.seekg(1, init_file.cur);

    // create grid and set initial state
    bool** life_grid = createGridArray(grid_width,grid_depth);
    setInitialState(life_grid, init_file, grid_width, grid_depth);
    displayGrid(life_grid, grid_width, grid_depth);

    init_file.close();

    return 0;
}
<|endoftext|>


<commit_before>2d8dad0c-2748-11e6-b271-e0f84713e7b8<commit_msg>Initial commit.2<commit_after>2d977f30-2748-11e6-a708-e0f84713e7b8<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageToListAdaptorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "itkImageToListAdaptor.h"
#include "itkRandomImageSource.h"
#include "itkImageRegionIterator.h"

int itkImageToListAdaptorTest(int, char**)
{
  std::cout << "ImageToListAdaptor Test \n \n";
  bool pass = true;
  std::string whereFail = "" ;

  typedef itk::Image< float, 3 > FloatImage ;

  // Now generate a random image
  typedef itk::RandomImageSource<FloatImage> SourceType;
  SourceType::Pointer source = SourceType::New();
  unsigned long size[3] = {17, 8, 20} ;
  unsigned long totalSize = size[0] * size[1] * size[2] ;

  source->SetSize(size);
  float minValue = -100.0;
  float maxValue = 1000.0;

  source->SetMin( static_cast< FloatImage::PixelType >( minValue ) );
  source->SetMax( static_cast< FloatImage::PixelType >( maxValue ) );
  source->Update() ;

  typedef  itk::Statistics::ImageToListAdaptor< FloatImage,
    itk::Statistics::ScalarImageAccessor< FloatImage > >
    ImageToListAdaptorType ;

  ImageToListAdaptorType::Pointer sample = ImageToListAdaptorType::New() ;
  sample->SetImage(source->GetOutput()) ;

  // tests begin

  if (totalSize != sample->Size())
    {
      pass = false ;
      whereFail = "Size()" ;
    }

  if (totalSize != sample->Size(0))
    {
      pass = false ;
      whereFail = "Size(0)" ;
    }

  if (totalSize != sample->GetNumberOfInstances())
    {
      pass = false ;
      whereFail = "GetNumberOfInstances()" ;
    }

  FloatImage::IndexType index ;
  index.Fill(2) ;// index {2, 2, 2} = instance identifier (offset from image)
  FloatImage::PixelType pixel = sample->GetImage()->GetPixel(index) ;
  ImageToListAdaptorType::InstanceIdentifier id =
    static_cast< FloatImage::OffsetValueType >(sample->GetImage()
                                               ->ComputeOffset(index)) ;

  if (pixel != sample->GetMeasurementVector(id)[0])
    {
      pass = false ;
      whereFail = "GetMeasurementVector()" ;
    }

  // iterator test
  typedef itk::ImageRegionIterator< FloatImage > ImageIterator ;
  ImageIterator i_iter(sample->GetImage(),
                       sample->GetImage()->GetLargestPossibleRegion()) ;

  ImageToListAdaptorType::Iterator s_iter = sample->Begin() ;

  while (!i_iter.IsAtEnd())
    {
      if (i_iter.Get() != s_iter.GetMeasurementVector()[0])
        {
          pass = false ;
          whereFail = "Iterator: GetMeasurementVecto()" ;
        }
      ++i_iter ;
      ++s_iter ;
    }

  if (s_iter != sample->End())
    {
      pass = false ;
      whereFail = "Iterator: End()" ;
    }

  if( !pass )
    {
      std::cout << "Test failed in " << whereFail << "." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}

<commit_msg>ENH: Now the pixel type of the source image is converted to one dimensional FixedArray using ScalarToArrayCastImageFilter<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageToListAdaptorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "itkImageToListAdaptor.h"
#include "itkRandomImageSource.h"
#include "itkImageRegionIterator.h"
#include "itkScalarToArrayCastImageFilter.h"
#include "itkFixedArray.h"

int itkImageToListAdaptorTest(int, char**)
{
  std::cout << "ImageToListAdaptor Test \n \n";
  bool pass = true;
  std::string whereFail = "" ;

  typedef itk::Image< float, 3 > FloatImage ;

  // Now generate a random image
  typedef itk::RandomImageSource<FloatImage> SourceType;
  SourceType::Pointer source = SourceType::New();
  unsigned long size[3] = {17, 8, 20} ;
  unsigned long totalSize = size[0] * size[1] * size[2] ;

  source->SetSize(size);
  float minValue = -100.0;
  float maxValue = 1000.0;

  source->SetMin( static_cast< FloatImage::PixelType >( minValue ) );
  source->SetMax( static_cast< FloatImage::PixelType >( maxValue ) );
  source->Update() ;

  // creat a new image with array pixel type from the source
  typedef itk::FixedArray< FloatImage::PixelType, 1 > ArrayPixelType ;
  typedef itk::Image< ArrayPixelType, 3 > ArrayPixelImageType ;
  typedef itk::ScalarToArrayCastImageFilter< FloatImage, ArrayPixelImageType >
    ImageCastFilterType ;
  ImageCastFilterType::Pointer castFilter = ImageCastFilterType::New() ;
  castFilter->SetInput(source->GetOutput()) ;
  castFilter->Update() ;

  // creates a sample
  typedef  itk::Statistics::ImageToListAdaptor< ArrayPixelImageType>
    ImageToListAdaptorType ;

  ImageToListAdaptorType::Pointer sample = ImageToListAdaptorType::New() ;
  sample->SetImage(castFilter->GetOutput()) ;

  // tests begin

  if (totalSize != sample->Size())
    {
      pass = false ;
      whereFail = "Size()" ;
    }

  if (totalSize != sample->Size(0))
    {
      pass = false ;
      whereFail = "Size(0)" ;
    }

  if (totalSize != sample->GetNumberOfInstances())
    {
      pass = false ;
      whereFail = "GetNumberOfInstances()" ;
    }

  ArrayPixelImageType::IndexType index ;
  index.Fill(2) ;// index {2, 2, 2} = instance identifier (offset from image)
  ArrayPixelImageType::PixelType pixel = sample->GetImage()->GetPixel(index) ;
  ImageToListAdaptorType::InstanceIdentifier id =
    static_cast< FloatImage::OffsetValueType >(sample->GetImage()
                                               ->ComputeOffset(index)) ;

  if (pixel[0] != sample->GetMeasurementVector(id)[0])
    {
      pass = false ;
      whereFail = "GetMeasurementVector()" ;
    }

  // iterator test
  typedef itk::ImageRegionIterator< ArrayPixelImageType > ImageIterator ;
  ImageIterator i_iter(sample->GetImage(),
                       sample->GetImage()->GetLargestPossibleRegion()) ;

  ImageToListAdaptorType::Iterator s_iter = sample->Begin() ;

  while (!i_iter.IsAtEnd())
    {
      if (i_iter.Get()[0] != s_iter.GetMeasurementVector()[0])
        {
          pass = false ;
          whereFail = "Iterator: GetMeasurementVecto()" ;
        }
      ++i_iter ;
      ++s_iter ;
    }

  if (s_iter != sample->End())
    {
      pass = false ;
      whereFail = "Iterator: End()" ;
    }

  if( !pass )
    {
      std::cout << "Test failed in " << whereFail << "." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}

<|endoftext|>


<commit_before>// Danny Dutton
// ECE 3574
// Project 1: Qt Markup
//
// This is the main file for the Qt application

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

// #include <QApplication>
// #include <QLabel>
// #include <QPlainTextEdit>
// #include <QWebView>
// #include <QWidget>

using namespace std;

// I should redo these to actually see if the length of the symbols
// are at least as long as the line above, not a huge priority right now
// is_h1 will detect if a line contains only "=", the symbol for an h1
bool is_h1(const string &str)
{
	if (!str.empty())
	{
		return str.find_first_not_of("=") == string::npos;
	}
	else
	{
		return false;
	}

}

// is_h2 will detect if a line contains only "-", the symbol for an h2
bool is_h2(const string &str)
{
	if (!str.empty())
	{
		return str.find_first_not_of("-") == string::npos;
	}
	else
	{
		return false;
	}
}

// Find any italics in a string an return a properly formated HTML line
string italics(const string &str)
{
	//string
	//size_t found =

	return str;
}

// Find any bolds in a string an return a properly formated HTML line
string bold(const string &str)
{
	string newstr = str;
	size_t first = newstr.find("**");
	size_t second = newstr.find("**",first+1);

	if (first != string::npos && second != string::npos)
	{
		newstr.replace(first, 2, "");
		newstr.replace(second+1, 2, "");

		return bold(newstr);
	}
	else
	{
		return newstr;
	}
}

int main(int argc, char **argv)
{
	// QApplication app(argc, argv);
	// QLabel qtmarkup("hello");
	// qtmarkup.setWindowTitle("Qt Markup");
	// qtmarkup.resize(800, 600);
	// qtmarkup.show();

	// QWebView *view = new QWebView(app);
	// view->load(QUrl("file://index.html"));
	// view->show();

	// return app.exec();

	string row;					// Row to be read from text file
	string temp;				// Temporary string to be manipulated
	vector<string> markdown;	// Vector containing all lines in the MD file
	vector<string> html;		// Vector containing all lines in HTML file
	int i;						// Iterator for loops

	ifstream inFile;			// Input file stream

	// Check if file was opened correctly. If not: display error, free memory and exit main.
	try
	{
		inFile.open(argv[1]);

		if (!inFile.good())
		{
			throw "File failed to open (file not found).";
		}
	}
	catch (const char* msg) {
		cerr << msg << endl;
		return 0;
	}

	// Read all the lines in the file and add them to the markdown vector
	while(getline(inFile, row))
	{
		markdown.push_back(row);
	}

	inFile.close();

	// Setup html file
	html.push_back("");
	html.push_back("");

	// Look for formating
	for (i = 0; i < markdown.size(); i++)
	{
		// Check for h1
		if(i != markdown.size()-1 && is_h1(markdown[i+1]))
		{
			html.push_back("
" + markdown[i] + "
");
		}

		// Check for h2
		else if(i != markdown.size()-1 && is_h2(markdown[i+1]))
		{
			html.push_back("
" + markdown[i] + "
");
		}

		// Not an h1 or h2
		else if (!markdown[i].empty())
		{
			// We dont want to include any ====== or -----
			if(!is_h1(markdown[i]) && !is_h2(markdown[i]))
			{
				temp = bold(markdown[i]);
				html.push_back("
" + temp + "
");
			}
		}
	}

	// End html file
	html.push_back("");
	html.push_back("");

	for (i = 0; i < html.size(); i++)
	{
		cout << html[i] << endl;
	}

	return 0;
}
<commit_msg>Added italics handling.<commit_after>// Danny Dutton
// ECE 3574
// Project 1: Qt Markup
//
// This is the main file for the Qt application

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

// #include <QApplication>
// #include <QLabel>
// #include <QPlainTextEdit>
// #include <QWebView>
// #include <QWidget>

using namespace std;

// I should redo these to actually see if the length of the symbols
// are at least as long as the line above, not a huge priority right now
// is_h1 will detect if a line contains only "=", the symbol for an h1
bool is_h1(const string &str)
{
	if (!str.empty())
	{
		return str.find_first_not_of("=") == string::npos;
	}
	else
	{
		return false;
	}

}

// is_h2 will detect if a line contains only "-", the symbol for an h2
bool is_h2(const string &str)
{
	if (!str.empty())
	{
		return str.find_first_not_of("-") == string::npos;
	}
	else
	{
		return false;
	}
}

// Find any italics in a string an return a properly formated HTML line
string italics(const string &str)
{
	string newstr = str;
	size_t first = newstr.find("*");
	size_t second = newstr.find("*",first+1);

	if (first != string::npos && second != string::npos && first != second-1)
	{
		newstr.replace(first, 1, "");
		newstr.replace(second+2, 1, "");

		return italics(newstr);
	}
	else
	{
		return newstr;
	}
}

// Find any bolds in a string an return a properly formated HTML line
string bold(const string &str)
{
	string newstr = str;
	size_t first = newstr.find("**");
	size_t second = newstr.find("**",first+1);

	if (first != string::npos && second != string::npos)
	{
		newstr.replace(first, 2, "");
		newstr.replace(second+1, 2, "");

		return bold(newstr);
	}
	else
	{
		return newstr;
	}
}

int main(int argc, char **argv)
{
	// QApplication app(argc, argv);
	// QLabel qtmarkup("hello");
	// qtmarkup.setWindowTitle("Qt Markup");
	// qtmarkup.resize(800, 600);
	// qtmarkup.show();

	// QWebView *view = new QWebView(app);
	// view->load(QUrl("file://index.html"));
	// view->show();

	// return app.exec();

	string row;					// Row to be read from text file
	string temp;				// Temporary string to be manipulated
	vector<string> markdown;	// Vector containing all lines in the MD file
	vector<string> html;		// Vector containing all lines in HTML file
	int i;						// Iterator for loops

	ifstream inFile;			// Input file stream

	// Check if file was opened correctly. If not: display error, free memory and exit main.
	try
	{
		inFile.open(argv[1]);

		if (!inFile.good())
		{
			throw "File failed to open (file not found).";
		}
	}
	catch (const char* msg) {
		cerr << msg << endl;
		return 0;
	}

	// Read all the lines in the file and add them to the markdown vector
	while(getline(inFile, row))
	{
		markdown.push_back(row);
	}

	inFile.close();

	// Setup html file
	html.push_back("");
	html.push_back("");

	// Look for formating
	for (i = 0; i < markdown.size(); i++)
	{
		// Check for h1
		if(i != markdown.size()-1 && is_h1(markdown[i+1]))
		{
			html.push_back("
" + markdown[i] + "
");
		}

		// Check for h2
		else if(i != markdown.size()-1 && is_h2(markdown[i+1]))
		{
			html.push_back("
" + markdown[i] + "
");
		}

		// Not an h1 or h2
		else if (!markdown[i].empty())
		{
			// We dont want to include any ====== or -----
			if(!is_h1(markdown[i]) && !is_h2(markdown[i]))
			{
				temp = bold(markdown[i]);
				temp = italics(temp);
				html.push_back("
" + temp + "
");
			}
		}
	}

	// End html file
	html.push_back("");
	html.push_back("");

	for (i = 0; i < html.size(); i++)
	{
		cout << html[i] << endl;
	}

	return 0;
}
<|endoftext|>


<commit_before>aaa342f3-4b02-11e5-ab37-28cfe9171a43<commit_msg>Typical lynda<commit_after>aab1e9e3-4b02-11e5-aaf9-28cfe9171a43<|endoftext|>


<commit_before>#include "ofApp.h"

void ofApp::setup(){
	ofLog() << "Running setup()";
	oscReceiver.setup(7172);
	embed = pnEmbed();
	embed.setup(ofGetWindowWidth(), argc, argv);
}

void ofApp::update(){
	while(oscReceiver.hasWaitingMessages()){
		// get the next message
		ofxOscMessage m;
		oscReceiver.getNextMessage(m);

		if(m.getAddress() == "/code"){
			string code = m.getArgAsString(0);
			ofLog() << "OSC mesage:\n" << "/code" << "\n" << code << "\n";
			embed.update(code);
		}
	}
}

void ofApp::draw(){
	embed.draw();

	ofFbo fbo = embed.getBuffer();

	int w = ofGetWindowWidth();
	int h = ofGetWindowHeight();
	fbo.draw(0, -(w - h) / 2, w, w);

	string fps = "FPS: " + ofToString(ofGetFrameRate());
	ofSetColor(255);
	ofDrawBitmapString(fps, 10, 20);

}

void ofApp::keyPressed(int key){}
void ofApp::keyReleased(int key){}
void ofApp::mouseMoved(int x, int y){}
void ofApp::mouseDragged(int x, int y, int button){}
void ofApp::mousePressed(int x, int y, int button){}
void ofApp::mouseReleased(int x, int y, int button){}
void ofApp::mouseEntered(int x, int y){}
void ofApp::mouseExited(int x, int y){}
void ofApp::windowResized(int w, int h){}
void ofApp::gotMessage(ofMessage msg){}
void ofApp::dragEvent(ofDragInfo dragInfo){}
<commit_msg>Do not close with Esc<commit_after>#include "ofApp.h"

void ofApp::setup(){
	ofLog() << "Running setup()";
	ofSetEscapeQuitsApp(false);
	oscReceiver.setup(7172);
	embed = pnEmbed();
	embed.setup(ofGetWindowWidth(), argc, argv);
}

void ofApp::update(){
	while(oscReceiver.hasWaitingMessages()){
		// get the next message
		ofxOscMessage m;
		oscReceiver.getNextMessage(m);

		if(m.getAddress() == "/code"){
			string code = m.getArgAsString(0);
			ofLog() << "OSC mesage:\n" << "/code" << "\n" << code << "\n";
			embed.update(code);
		}
	}
}

void ofApp::draw(){
	embed.draw();

	ofFbo fbo = embed.getBuffer();

	int w = ofGetWindowWidth();
	int h = ofGetWindowHeight();
	fbo.draw(0, -(w - h) / 2, w, w);

	string fps = "FPS: " + ofToString(ofGetFrameRate());
	ofSetColor(255);
	ofDrawBitmapString(fps, 10, 20);

}

void ofApp::keyPressed(int key){}
void ofApp::keyReleased(int key){}
void ofApp::mouseMoved(int x, int y){}
void ofApp::mouseDragged(int x, int y, int button){}
void ofApp::mousePressed(int x, int y, int button){}
void ofApp::mouseReleased(int x, int y, int button){}
void ofApp::mouseEntered(int x, int y){}
void ofApp::mouseExited(int x, int y){}
void ofApp::windowResized(int w, int h){}
void ofApp::gotMessage(ofMessage msg){}
void ofApp::dragEvent(ofDragInfo dragInfo){}
<|endoftext|>