<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTileGrid.h"

SkTileGrid::SkTileGrid(int tileWidth, int tileHeight, int xTileCount, int yTileCount, SkTileGridNextDatumFunctionPtr nextDatumFunction)
{
    fTileWidth = tileWidth;
    fTileHeight = tileHeight;
    fXTileCount = xTileCount;
    fYTileCount = yTileCount;
    fTileCount = fXTileCount * fYTileCount;
    fInsertionCount = 0;
    fGridBounds = SkIRect::MakeXYWH(0, 0, fTileWidth * fXTileCount, fTileHeight * fYTileCount);
    fNextDatumFunction = nextDatumFunction;
    fTileData = SkNEW_ARRAY(SkTDArray<void *>, fTileCount);
}

SkTileGrid::~SkTileGrid() {
    SkDELETE_ARRAY(fTileData);
}

SkTDArray<void *>& SkTileGrid::tile(int x, int y) {
    return fTileData[y * fXTileCount + x];
}

void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) {
    SkASSERT(!bounds.isEmpty());
    SkIRect dilatedBounds = bounds;
    dilatedBounds.outset(1,1); // Consideration for filtering and AA

    if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) {
        return;
    }

    int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fTileWidth, fXTileCount - 1), 0);
    int maxTileX = SkMax32(SkMin32(dilatedBounds.right() / fTileWidth, fXTileCount - 1), 0);
    int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fTileHeight, fYTileCount -1), 0);
    int maxTileY = SkMax32(SkMin32(dilatedBounds.bottom() / fTileHeight, fYTileCount -1), 0);

    for (int x = minTileX; x <= maxTileX; x++) {
        for (int y = minTileY; y <= maxTileY; y++) {
            this->tile(x, y).push(data);
        }
    }
    fInsertionCount++;
}

void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) {
    // The +1/-1 is to compensate for the outset in applied SkCanvas::getClipBounds
    int tileStartX = (query.left() + 1) / fTileWidth;
    int tileEndX = (query.right() + fTileWidth - 1) / fTileWidth;
    int tileStartY = (query.top() + 1) / fTileHeight;
    int tileEndY = (query.bottom() + fTileHeight - 1) / fTileHeight;
    if (tileStartX >= fXTileCount || tileStartY >= fYTileCount || tileEndX <= 0 || tileEndY <= 0) {
        return; // query does not intersect the grid
    }
    // clamp to grid
    if (tileStartX < 0) tileStartX = 0;
    if (tileStartY < 0) tileStartY = 0;
    if (tileEndX > fXTileCount) tileEndX = fXTileCount;
    if (tileEndY > fYTileCount) tileEndY = fYTileCount;

    int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY);
    if (queryTileCount == 1) {
        *results = this->tile(tileStartX, tileStartY);
    } else {
        results->reset();
        SkTDArray<int> curPositions;
        curPositions.setCount(queryTileCount);
        // Note: Reserving space for 1024 tile pointers on the stack. If the malloc
        // becomes a bottleneck, we may consider increasing that number.
        SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount);
        SkTDArray<void *>** tileRange = storage.get();
        int tile = 0;
        for (int x = tileStartX; x < tileEndX; ++x) {
            for (int y = tileStartY; y < tileEndY; ++y) {
                tileRange[tile] = &this->tile(x, y);
                curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished;
                ++tile;
            }
        }
        void *nextElement;
        while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) {
            results->push(nextElement);
        }
    }
}

void SkTileGrid::clear() {
    for (int i = 0; i < fTileCount; i++) {
        fTileData[i].reset();
    }
}

int SkTileGrid::getCount() const {
    return fInsertionCount;
}
<commit_msg>Improving comment in SkTileGrid::search<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTileGrid.h"

SkTileGrid::SkTileGrid(int tileWidth, int tileHeight, int xTileCount, int yTileCount, SkTileGridNextDatumFunctionPtr nextDatumFunction)
{
    fTileWidth = tileWidth;
    fTileHeight = tileHeight;
    fXTileCount = xTileCount;
    fYTileCount = yTileCount;
    fTileCount = fXTileCount * fYTileCount;
    fInsertionCount = 0;
    fGridBounds = SkIRect::MakeXYWH(0, 0, fTileWidth * fXTileCount, fTileHeight * fYTileCount);
    fNextDatumFunction = nextDatumFunction;
    fTileData = SkNEW_ARRAY(SkTDArray<void *>, fTileCount);
}

SkTileGrid::~SkTileGrid() {
    SkDELETE_ARRAY(fTileData);
}

SkTDArray<void *>& SkTileGrid::tile(int x, int y) {
    return fTileData[y * fXTileCount + x];
}

void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) {
    SkASSERT(!bounds.isEmpty());
    SkIRect dilatedBounds = bounds;
    dilatedBounds.outset(1,1); // Consideration for filtering and AA

    if (!SkIRect::Intersects(dilatedBounds, fGridBounds)) {
        return;
    }

    int minTileX = SkMax32(SkMin32(dilatedBounds.left() / fTileWidth, fXTileCount - 1), 0);
    int maxTileX = SkMax32(SkMin32(dilatedBounds.right() / fTileWidth, fXTileCount - 1), 0);
    int minTileY = SkMax32(SkMin32(dilatedBounds.top() / fTileHeight, fYTileCount -1), 0);
    int maxTileY = SkMax32(SkMin32(dilatedBounds.bottom() / fTileHeight, fYTileCount -1), 0);

    for (int x = minTileX; x <= maxTileX; x++) {
        for (int y = minTileY; y <= maxTileY; y++) {
            this->tile(x, y).push(data);
        }
    }
    fInsertionCount++;
}

void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) {
    // The +1/-1 is to compensate for the outset in applied SkCanvas::getClipBounds
    int tileStartX = (query.left() + 1) / fTileWidth;
    int tileEndX = (query.right() + fTileWidth - 1) / fTileWidth;
    int tileStartY = (query.top() + 1) / fTileHeight;
    int tileEndY = (query.bottom() + fTileHeight - 1) / fTileHeight;
    if (tileStartX >= fXTileCount || tileStartY >= fYTileCount || tileEndX <= 0 || tileEndY <= 0) {
        return; // query does not intersect the grid
    }
    // clamp to grid
    if (tileStartX < 0) tileStartX = 0;
    if (tileStartY < 0) tileStartY = 0;
    if (tileEndX > fXTileCount) tileEndX = fXTileCount;
    if (tileEndY > fYTileCount) tileEndY = fYTileCount;

    int queryTileCount = (tileEndX - tileStartX) * (tileEndY - tileStartY);
    if (queryTileCount == 1) {
        *results = this->tile(tileStartX, tileStartY);
    } else {
        results->reset();
        SkTDArray<int> curPositions;
        curPositions.setCount(queryTileCount);
        // Note: Reserving space for 1024 tile pointers on the stack. If the
        // malloc becomes a bottleneck, we may consider increasing that number.
        // Typical large web page, say 2k x 16k, would require 512 tiles of
        // size 256 x 256 pixels.
        SkAutoSTArray<1024, SkTDArray<void *>*> storage(queryTileCount);
        SkTDArray<void *>** tileRange = storage.get();
        int tile = 0;
        for (int x = tileStartX; x < tileEndX; ++x) {
            for (int y = tileStartY; y < tileEndY; ++y) {
                tileRange[tile] = &this->tile(x, y);
                curPositions[tile] = tileRange[tile]->count() ? 0 : kTileFinished;
                ++tile;
            }
        }
        void *nextElement;
        while(NULL != (nextElement = fNextDatumFunction(tileRange, curPositions))) {
            results->push(nextElement);
        }
    }
}

void SkTileGrid::clear() {
    for (int i = 0; i < fTileCount; i++) {
        fTileData[i].reset();
    }
}

int SkTileGrid::getCount() const {
    return fInsertionCount;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAdvancedTypefaceMetrics.h"
#include "SkFontDescriptor.h"
#include "SkFontHost.h"
#include "SkFontStream.h"
#include "SkStream.h"
#include "SkTypeface.h"

SK_DEFINE_INST_COUNT(SkTypeface)

//#define TRACE_LIFECYCLE

#ifdef TRACE_LIFECYCLE
    static int32_t gTypefaceCounter;
#endif

SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
    : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: create  %p fontID %d total %d\n",
             this, fontID, ++gTypefaceCounter);
#endif
}

SkTypeface::~SkTypeface() {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
             this, fUniqueID, --gTypefaceCounter);
#endif
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::GetDefaultTypeface() {
    // we keep a reference to this guy for all time, since if we return its
    // fontID, the font cache may later on ask to resolve that back into a
    // typeface object.
    static SkTypeface* gDefaultTypeface;

    if (NULL == gDefaultTypeface) {
        gDefaultTypeface =
        SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
    }
    return gDefaultTypeface;
}

SkTypeface* SkTypeface::RefDefault() {
    return SkRef(GetDefaultTypeface());
}

uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
    if (NULL == face) {
        face = GetDefaultTypeface();
    }
    return face->uniqueID();
}

bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
    return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb);
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) {
    return SkFontHost::CreateTypeface(NULL, name, style);
}

SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
    if (family && family->style() == s) {
        family->ref();
        return const_cast<SkTypeface*>(family);
    }
    return SkFontHost::CreateTypeface(family, NULL, s);
}

SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
    return SkFontHost::CreateTypefaceFromStream(stream);
}

SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
    return SkFontHost::CreateTypefaceFromFile(path);
}

///////////////////////////////////////////////////////////////////////////////

void SkTypeface::serialize(SkWStream* wstream) const {
    bool isLocal = false;
    SkFontDescriptor desc(this->style());
    this->onGetFontDescriptor(&desc, &isLocal);

    desc.serialize(wstream);
    if (isLocal) {
        int ttcIndex;   // TODO: write this to the stream?
        SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
        if (rstream.get()) {
            size_t length = rstream->getLength();
            wstream->writePackedUInt(length);
            wstream->writeStream(rstream, length);
        } else {
            wstream->writePackedUInt(0);
        }
    } else {
        wstream->writePackedUInt(0);
    }
}

SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
    SkFontDescriptor desc(stream);
    size_t length = stream->readPackedUInt();
    if (length > 0) {
        void* addr = sk_malloc_flags(length, 0);
        if (addr) {
            SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream,
                                                        (addr, length, false)));
            return SkTypeface::CreateFromStream(localStream.get());
        }
        // failed to allocate, so just skip and create-from-name
        stream->skip(length);
    }

    return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
}

///////////////////////////////////////////////////////////////////////////////

int SkTypeface::countTables() const {
    return this->onGetTableTags(NULL);
}

int SkTypeface::getTableTags(SkFontTableTag tags[]) const {
    return this->onGetTableTags(tags);
}

size_t SkTypeface::getTableSize(SkFontTableTag tag) const {
    return this->onGetTableData(tag, 0, ~0U, NULL);
}

size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length,
                                void* data) const {
    return this->onGetTableData(tag, offset, length, data);
}

SkStream* SkTypeface::openStream(int* ttcIndex) const {
    int ttcIndexStorage;
    if (NULL == ttcIndex) {
        // So our subclasses don't need to check for null param
        ttcIndex = &ttcIndexStorage;
    }
    return this->onOpenStream(ttcIndex);
}

int SkTypeface::getUnitsPerEm() const {
    // should we try to cache this in the base-class?
    return this->onGetUPEM();
}

SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
                                SkAdvancedTypefaceMetrics::PerGlyphInfo info,
                                const uint32_t* glyphIDs,
                                uint32_t glyphIDsCount) const {
    return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int SkTypeface::onGetUPEM() const {
    int upem = 0;

    SkAdvancedTypefaceMetrics* metrics;
    metrics = this->getAdvancedTypefaceMetrics(
                             SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
                             NULL, 0);
    if (metrics) {
        upem = metrics->fEmSize;
        metrics->unref();
    }
    return upem;
}

int SkTypeface::onGetTableTags(SkFontTableTag tags[]) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
}

size_t SkTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
                                  size_t length, void* data) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get()
        ? SkFontStream::GetTableData(stream, ttcIndex, tag, offset, length, data)
        : 0;
}
<commit_msg>Partial fix for skp reading failure on fonts<commit_after>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAdvancedTypefaceMetrics.h"
#include "SkFontDescriptor.h"
#include "SkFontHost.h"
#include "SkFontStream.h"
#include "SkStream.h"
#include "SkTypeface.h"

SK_DEFINE_INST_COUNT(SkTypeface)

//#define TRACE_LIFECYCLE

#ifdef TRACE_LIFECYCLE
    static int32_t gTypefaceCounter;
#endif

SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
    : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: create  %p fontID %d total %d\n",
             this, fontID, ++gTypefaceCounter);
#endif
}

SkTypeface::~SkTypeface() {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
             this, fUniqueID, --gTypefaceCounter);
#endif
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::GetDefaultTypeface() {
    // we keep a reference to this guy for all time, since if we return its
    // fontID, the font cache may later on ask to resolve that back into a
    // typeface object.
    static SkTypeface* gDefaultTypeface;

    if (NULL == gDefaultTypeface) {
        gDefaultTypeface =
        SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
    }
    return gDefaultTypeface;
}

SkTypeface* SkTypeface::RefDefault() {
    return SkRef(GetDefaultTypeface());
}

uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
    if (NULL == face) {
        face = GetDefaultTypeface();
    }
    return face->uniqueID();
}

bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
    return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb);
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) {
    return SkFontHost::CreateTypeface(NULL, name, style);
}

SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
    if (family && family->style() == s) {
        family->ref();
        return const_cast<SkTypeface*>(family);
    }
    return SkFontHost::CreateTypeface(family, NULL, s);
}

SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
    return SkFontHost::CreateTypefaceFromStream(stream);
}

SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
    return SkFontHost::CreateTypefaceFromFile(path);
}

///////////////////////////////////////////////////////////////////////////////

void SkTypeface::serialize(SkWStream* wstream) const {
    bool isLocal = false;
    SkFontDescriptor desc(this->style());
    this->onGetFontDescriptor(&desc, &isLocal);

    desc.serialize(wstream);
    if (isLocal) {
        int ttcIndex;   // TODO: write this to the stream?
        SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
        if (rstream.get()) {
            size_t length = rstream->getLength();
            wstream->writePackedUInt(length);
            wstream->writeStream(rstream, length);
        } else {
            wstream->writePackedUInt(0);
        }
    } else {
        wstream->writePackedUInt(0);
    }
}

SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
    SkFontDescriptor desc(stream);
    size_t length = stream->readPackedUInt();
    if (length > 0) {
        void* addr = sk_malloc_flags(length, 0);
        if (addr) {
            SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream,
                                                        (addr, length, false)));
            stream->skip(length);
            return SkTypeface::CreateFromStream(localStream.get());
        }
        // failed to allocate, so just skip and create-from-name
        stream->skip(length);
    }

    return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
}

///////////////////////////////////////////////////////////////////////////////

int SkTypeface::countTables() const {
    return this->onGetTableTags(NULL);
}

int SkTypeface::getTableTags(SkFontTableTag tags[]) const {
    return this->onGetTableTags(tags);
}

size_t SkTypeface::getTableSize(SkFontTableTag tag) const {
    return this->onGetTableData(tag, 0, ~0U, NULL);
}

size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length,
                                void* data) const {
    return this->onGetTableData(tag, offset, length, data);
}

SkStream* SkTypeface::openStream(int* ttcIndex) const {
    int ttcIndexStorage;
    if (NULL == ttcIndex) {
        // So our subclasses don't need to check for null param
        ttcIndex = &ttcIndexStorage;
    }
    return this->onOpenStream(ttcIndex);
}

int SkTypeface::getUnitsPerEm() const {
    // should we try to cache this in the base-class?
    return this->onGetUPEM();
}

SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
                                SkAdvancedTypefaceMetrics::PerGlyphInfo info,
                                const uint32_t* glyphIDs,
                                uint32_t glyphIDsCount) const {
    return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int SkTypeface::onGetUPEM() const {
    int upem = 0;

    SkAdvancedTypefaceMetrics* metrics;
    metrics = this->getAdvancedTypefaceMetrics(
                             SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
                             NULL, 0);
    if (metrics) {
        upem = metrics->fEmSize;
        metrics->unref();
    }
    return upem;
}

int SkTypeface::onGetTableTags(SkFontTableTag tags[]) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
}

size_t SkTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
                                  size_t length, void* data) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get()
        ? SkFontStream::GetTableData(stream, ttcIndex, tag, offset, length, data)
        : 0;
}
<|endoftext|>


<commit_before>#ifndef REMAP_HPP
#define REMAP_HPP

#include "KeyCode.hpp"
#include "CallBackWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  // ----------------------------------------------------------------------
  struct RemapParams {
    RemapParams(const Params_KeyboardEventCallBack& p) :
      params(p), isremapped(false) {}

    const Params_KeyboardEventCallBack& params;
    bool isremapped;
  };

  // --------------------
  struct RemapConsumerParams {
    RemapConsumerParams(const Params_KeyboardSpecialEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_KeyboardSpecialEventCallback& params;
    bool isremapped;
  };

  // --------------------
  struct RemapPointingParams_relative {
    RemapPointingParams_relative(const Params_RelativePointerEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_RelativePointerEventCallback& params;
    bool isremapped;
  };

  // --------------------
  struct RemapPointingParams_scroll {
    RemapPointingParams_scroll(const Params_ScrollWheelEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_ScrollWheelEventCallback& params;
    bool isremapped;
  };
}

#endif
<commit_msg>sort #include<commit_after>#ifndef REMAP_HPP
#define REMAP_HPP

#include "CallBackWrapper.hpp"
#include "KeyCode.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  // ----------------------------------------------------------------------
  struct RemapParams {
    RemapParams(const Params_KeyboardEventCallBack& p) :
      params(p), isremapped(false) {}

    const Params_KeyboardEventCallBack& params;
    bool isremapped;
  };

  // --------------------
  struct RemapConsumerParams {
    RemapConsumerParams(const Params_KeyboardSpecialEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_KeyboardSpecialEventCallback& params;
    bool isremapped;
  };

  // --------------------
  struct RemapPointingParams_relative {
    RemapPointingParams_relative(const Params_RelativePointerEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_RelativePointerEventCallback& params;
    bool isremapped;
  };

  // --------------------
  struct RemapPointingParams_scroll {
    RemapPointingParams_scroll(const Params_ScrollWheelEventCallback& p) :
      params(p), isremapped(false) {}

    const Params_ScrollWheelEventCallback& params;
    bool isremapped;
  };
}

#endif
<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "pipe_grammar.h"

#include "load_pipe_exception.h"

#include "pipe_declaration_types.h"

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <string>
#include <sstream>

/**
 * \file pipe_grammar.cxx
 *
 * \brief The implementation of parsing pipeline blocks from a string.
 */

using namespace boost::spirit;

#ifndef DOXYGEN_IGNORE

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_key_options_t,
  (boost::optional<vistk::config_flags_t>, flags)
  (boost::optional<vistk::config_provider_t>, provider)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_key_t,
  (vistk::config::keys_t, key_path)
  (vistk::config_key_options_t, options)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_value_t,
  (vistk::config_key_t, key)
  (vistk::config::value_t, value)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_pipe_block,
  (vistk::config::keys_t, key)
  (vistk::config_values_t, values)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::process_pipe_block,
  (vistk::process::name_t, name)
  (vistk::process_registry::type_t, type)
  (vistk::config_values_t, config_values)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::connect_pipe_block,
  (vistk::process::port_addr_t, from)
  (vistk::process::port_addr_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::map_options_t,
  (boost::optional<vistk::process::port_flags_t>, flags)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::input_map_t,
  (vistk::map_options_t, options)
  (vistk::process::port_t, from)
  (vistk::process::port_addr_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::output_map_t,
  (vistk::map_options_t, options)
  (vistk::process::port_addr_t, from)
  (vistk::process::port_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::group_pipe_block,
  (vistk::process::name_t, name)
  (vistk::config_values_t, config_values)
  (vistk::input_maps_t, input_mappings)
  (vistk::output_maps_t, output_mappings)
)

#endif

namespace vistk
{

namespace
{

static token_t const config_block_name = token_t("config");
static token_t const process_block_name = token_t("process");
static token_t const connect_block_name = token_t("connect");
static token_t const group_block_name = token_t("group");
static token_t const map_block_name = token_t("map");

static token_t const from_name = token_t("from");
static token_t const to_name = token_t("to");
static token_t const type_token = token_t("::");

static token_t const config_path_separator = token_t(config::block_sep);
static token_t const port_separator = token_t(".");
static token_t const flag_separator = token_t(",");
static token_t const flag_decl_open = token_t("[");
static token_t const flag_decl_close = token_t("]");
static token_t const provider_open = token_t("{");
static token_t const provider_close = token_t("}");

}

template<typename Iterator>
class VISTK_PIPELINE_UTIL_NO_EXPORT pipe_grammar
  : public qi::grammar<Iterator, pipe_blocks()>
{
  public:
    pipe_grammar();
    ~pipe_grammar();

    qi::rule<Iterator> opt_whitespace;
    qi::rule<Iterator> whitespace;
    qi::rule<Iterator> eol;
    qi::rule<Iterator> line_end;

    qi::rule<Iterator, config_flag_t()> config_flag;
    qi::rule<Iterator, config_flags_t()> config_flags;
    qi::rule<Iterator, config_flags_t()> config_flags_decl;

    qi::rule<Iterator, config_provider_t()> config_provider;
    qi::rule<Iterator, config_provider_t()> config_provider_decl;

    qi::rule<Iterator, config_key_options_t()> config_key_options;

    qi::rule<Iterator, config::key_t()> config_key;
    qi::rule<Iterator, config::keys_t()> config_key_path;
    qi::rule<Iterator, config::value_t()> config_value;

    qi::rule<Iterator, config_key_t()> config_key_full;

    qi::rule<Iterator, config_value_t()> partial_config_value_decl;

    qi::rule<Iterator, config_pipe_block()> config_block;

    qi::rule<Iterator, process_registry::type_t()> type_name;
    qi::rule<Iterator, process_registry::type_t()> type_decl;

    qi::rule<Iterator, process::name_t()> process_name;

    qi::rule<Iterator, process_pipe_block()> process_block;

    qi::rule<Iterator, process::port_t()> port_name;
    qi::rule<Iterator, process::port_addr_t()> port_addr;

    qi::rule<Iterator, connect_pipe_block()> connect_block;

    qi::rule<Iterator, process::port_flag_t()> map_flag;
    qi::rule<Iterator, process::port_flags_t(), qi::locals<process::port_flags_t> > map_flags;
    qi::rule<Iterator, process::port_flags_t()> map_flags_decl;

    qi::rule<Iterator, map_options_t()> map_options;

    qi::rule<Iterator, input_map_t()> input_map_block;
    qi::rule<Iterator, output_map_t()> output_map_block;

    qi::rule<Iterator, group_pipe_block(), qi::locals<config_values_t, input_maps_t, output_maps_t> > group_block;

    qi::rule<Iterator, pipe_blocks()> block_set;
};

pipe_blocks
parse_pipe_blocks_from_string(std::string const& str)
{
  static pipe_grammar<std::string::const_iterator> grammar;

  std::string::const_iterator i = str.begin();
  std::string::const_iterator const i_end = str.end();

  pipe_blocks blocks;

  try
  {
    qi::parse(i, i_end, grammar, blocks);
  }
  catch (qi::expectation_failure<std::string::const_iterator>& e)
  {
    std::stringstream sstr;

    sstr << e.what_;

    throw failed_to_parse(sstr.str(), std::string(e.first, e.last));
  }

  if (i != i_end)
  {
    /// \todo Throw an exception.
  }

  return blocks;
}

template<typename Iterator>
pipe_grammar<Iterator>
::pipe_grammar()
  : pipe_grammar::base_type(block_set, "pipeline-declaration")
{
  opt_whitespace.name("opt-namespace");
  opt_whitespace %=
    *(  qi::blank
     );

  whitespace.name("whitespace");
  whitespace %=
    +(  qi::blank
     );

  eol.name("eol");
  eol %=
     (  qi::lit("\r\n")
     |  qi::lit("\n")
     );

  line_end.name("line-end");
  line_end %=
    +(  eol
     );

  config_flag.name("key-flag");
  config_flag %=
    +(  qi::alpha
     );

  config_flags.name("key-flags");
  config_flags %=
     (  config_flag
     %  qi::lit(flag_separator)
     );

  config_flags_decl.name("key-flags-decl");
  config_flags_decl %=
     (  qi::lit(flag_decl_open)
     >  config_flags
     >  qi::lit(flag_decl_close)
     );

  config_provider.name("key-provider");
  config_provider %=
    +(  qi::upper
     );

  config_provider_decl.name("key-provider-spec");
  config_provider_decl %=
     (  qi::lit(provider_open)
     >  config_provider
     >  qi::lit(provider_close)
     );

  config_key_options.name("key-options");
  config_key_options %=
     ( -config_flags_decl
     > -config_provider_decl
     );

  config_key.name("key-component");
  config_key %=
    +(  qi::alnum
     |  qi::lit('-')
     |  qi::lit('_')
     );

  config_key_path.name("key-path");
  config_key_path %=
     (  config_key
     %  qi::lit(config_path_separator)
     );

  config_value.name("key-value");
  config_value %=
    +(  qi::graph
     |  qi::lit(' ')
     |  qi::lit('\t')
     );

  config_key_full.name("full-key-path");
  config_key_full %=
     (  config_key_path
     >  config_key_options
     );

  partial_config_value_decl.name("partial-config-spec");
  partial_config_value_decl %=
     (  opt_whitespace
     >  qi::lit(config_path_separator)
     >  config_key_full
     >  whitespace
     >  config_value
     >  line_end
     );

  config_block.name("config-block-spec");
  config_block %=
     (  opt_whitespace
     >  qi::lit(config_block_name)
     >  whitespace
     >  config_key_path
     >  line_end
     > *partial_config_value_decl
     );

  type_name.name("type-name");
  type_name %=
     (  config_key
     );

  type_decl.name("type-decl");
  type_decl %=
     (  qi::lit(type_token)
     >  whitespace
     >  type_name
     );

  process_name.name("port-process");
  process_name %=
     (  config_key
     );

  process_block.name("process-block-spec");
  process_block %=
     (  opt_whitespace
     >  qi::lit(process_block_name)
     >  whitespace
     >  process_name
     >  line_end
     >  opt_whitespace
     >  type_decl
     >  line_end
     > *partial_config_value_decl
     );

  port_name.name("port-name");
  port_name %=
     (  config_key
     );

  port_addr.name("port-addr");
  port_addr %=
     (  process_name
     >  qi::lit(port_separator)
     >  port_name
     );

  connect_block.name("connect-block-spec");
  connect_block %=
     (  opt_whitespace
     >  qi::lit(connect_block_name)
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_addr
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_addr
     >  line_end
     );

  map_flag.name("map-flag");
  map_flag %=
    +(  qi::alpha
     );

  map_flags.name("map-flags");
  map_flags %=
     (  map_flag[boost::phoenix::insert(_a, _1)]
     %  qi::lit(flag_separator)
     );

  map_flags_decl.name("map-flag-decl");
  map_flags_decl %=
     (  qi::lit(flag_decl_open)
     >  map_flags
     >  qi::lit(flag_decl_close)
     );

  map_options.name("map-options");
  map_options %=
     ( -map_flags_decl
     );

  input_map_block.name("input-mapping-spec");
  input_map_block %=
     (  opt_whitespace
     >  qi::lit(map_block_name)
     >  map_options
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_name
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_addr
     >  line_end
     );

  output_map_block.name("output-mapping-spec");
  output_map_block %=
     (  opt_whitespace
     >  qi::lit(map_block_name)
     >  map_options
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_addr
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_name
     >  line_end
     );

  group_block.name("group-block-spec");
  group_block %=
     (  opt_whitespace
     >  qi::lit(group_block_name)
     >  whitespace
     >  process_name
     >  line_end
     > *(  partial_config_value_decl[boost::phoenix::push_back(_a, _1)]
        |  input_map_block[boost::phoenix::push_back(_b, _1)]
        |  output_map_block[boost::phoenix::push_back(_c, _1)]
        )
     );

  block_set.name("block-spec");
  block_set %=
    *(  config_block
     |  process_block
     |  connect_block
     |  group_block
     );
}

template<typename Iterator>
pipe_grammar<Iterator>
::~pipe_grammar()
{
}

}
<commit_msg>Extract partial config decls parser<commit_after>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include "pipe_grammar.h"

#include "load_pipe_exception.h"

#include "pipe_declaration_types.h"

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <string>
#include <sstream>

/**
 * \file pipe_grammar.cxx
 *
 * \brief The implementation of parsing pipeline blocks from a string.
 */

using namespace boost::spirit;

#ifndef DOXYGEN_IGNORE

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_key_options_t,
  (boost::optional<vistk::config_flags_t>, flags)
  (boost::optional<vistk::config_provider_t>, provider)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_key_t,
  (vistk::config::keys_t, key_path)
  (vistk::config_key_options_t, options)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_value_t,
  (vistk::config_key_t, key)
  (vistk::config::value_t, value)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::config_pipe_block,
  (vistk::config::keys_t, key)
  (vistk::config_values_t, values)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::process_pipe_block,
  (vistk::process::name_t, name)
  (vistk::process_registry::type_t, type)
  (vistk::config_values_t, config_values)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::connect_pipe_block,
  (vistk::process::port_addr_t, from)
  (vistk::process::port_addr_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::map_options_t,
  (boost::optional<vistk::process::port_flags_t>, flags)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::input_map_t,
  (vistk::map_options_t, options)
  (vistk::process::port_t, from)
  (vistk::process::port_addr_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::output_map_t,
  (vistk::map_options_t, options)
  (vistk::process::port_addr_t, from)
  (vistk::process::port_t, to)
)

BOOST_FUSION_ADAPT_STRUCT(
  vistk::group_pipe_block,
  (vistk::process::name_t, name)
  (vistk::config_values_t, config_values)
  (vistk::input_maps_t, input_mappings)
  (vistk::output_maps_t, output_mappings)
)

#endif

namespace vistk
{

namespace
{

static token_t const config_block_name = token_t("config");
static token_t const process_block_name = token_t("process");
static token_t const connect_block_name = token_t("connect");
static token_t const group_block_name = token_t("group");
static token_t const map_block_name = token_t("map");

static token_t const from_name = token_t("from");
static token_t const to_name = token_t("to");
static token_t const type_token = token_t("::");

static token_t const config_path_separator = token_t(config::block_sep);
static token_t const port_separator = token_t(".");
static token_t const flag_separator = token_t(",");
static token_t const flag_decl_open = token_t("[");
static token_t const flag_decl_close = token_t("]");
static token_t const provider_open = token_t("{");
static token_t const provider_close = token_t("}");

}

template<typename Iterator>
class VISTK_PIPELINE_UTIL_NO_EXPORT pipe_grammar
  : public qi::grammar<Iterator, pipe_blocks()>
{
  public:
    pipe_grammar();
    ~pipe_grammar();

    qi::rule<Iterator> opt_whitespace;
    qi::rule<Iterator> whitespace;
    qi::rule<Iterator> eol;
    qi::rule<Iterator> line_end;

    qi::rule<Iterator, config_flag_t()> config_flag;
    qi::rule<Iterator, config_flags_t()> config_flags;
    qi::rule<Iterator, config_flags_t()> config_flags_decl;

    qi::rule<Iterator, config_provider_t()> config_provider;
    qi::rule<Iterator, config_provider_t()> config_provider_decl;

    qi::rule<Iterator, config_key_options_t()> config_key_options;

    qi::rule<Iterator, config::key_t()> config_key;
    qi::rule<Iterator, config::keys_t()> config_key_path;
    qi::rule<Iterator, config::value_t()> config_value;

    qi::rule<Iterator, config_key_t()> config_key_full;

    qi::rule<Iterator, config_value_t()> partial_config_value_decl;
    qi::rule<Iterator, config_values_t()> partial_config_value_decls;

    qi::rule<Iterator, config_pipe_block()> config_block;

    qi::rule<Iterator, process_registry::type_t()> type_name;
    qi::rule<Iterator, process_registry::type_t()> type_decl;

    qi::rule<Iterator, process::name_t()> process_name;

    qi::rule<Iterator, process_pipe_block()> process_block;

    qi::rule<Iterator, process::port_t()> port_name;
    qi::rule<Iterator, process::port_addr_t()> port_addr;

    qi::rule<Iterator, connect_pipe_block()> connect_block;

    qi::rule<Iterator, process::port_flag_t()> map_flag;
    qi::rule<Iterator, process::port_flags_t(), qi::locals<process::port_flags_t> > map_flags;
    qi::rule<Iterator, process::port_flags_t()> map_flags_decl;

    qi::rule<Iterator, map_options_t()> map_options;

    qi::rule<Iterator, input_map_t()> input_map_block;
    qi::rule<Iterator, output_map_t()> output_map_block;

    qi::rule<Iterator, group_pipe_block(), qi::locals<config_values_t, input_maps_t, output_maps_t> > group_block;

    qi::rule<Iterator, pipe_blocks()> block_set;
};

pipe_blocks
parse_pipe_blocks_from_string(std::string const& str)
{
  static pipe_grammar<std::string::const_iterator> grammar;

  std::string::const_iterator i = str.begin();
  std::string::const_iterator const i_end = str.end();

  pipe_blocks blocks;

  try
  {
    qi::parse(i, i_end, grammar, blocks);
  }
  catch (qi::expectation_failure<std::string::const_iterator>& e)
  {
    std::stringstream sstr;

    sstr << e.what_;

    throw failed_to_parse(sstr.str(), std::string(e.first, e.last));
  }

  if (i != i_end)
  {
    /// \todo Throw an exception.
  }

  return blocks;
}

template<typename Iterator>
pipe_grammar<Iterator>
::pipe_grammar()
  : pipe_grammar::base_type(block_set, "pipeline-declaration")
{
  opt_whitespace.name("opt-namespace");
  opt_whitespace %=
    *(  qi::blank
     );

  whitespace.name("whitespace");
  whitespace %=
    +(  qi::blank
     );

  eol.name("eol");
  eol %=
     (  qi::lit("\r\n")
     |  qi::lit("\n")
     );

  line_end.name("line-end");
  line_end %=
    +(  eol
     );

  config_flag.name("key-flag");
  config_flag %=
    +(  qi::alpha
     );

  config_flags.name("key-flags");
  config_flags %=
     (  config_flag
     %  qi::lit(flag_separator)
     );

  config_flags_decl.name("key-flags-decl");
  config_flags_decl %=
     (  qi::lit(flag_decl_open)
     >  config_flags
     >  qi::lit(flag_decl_close)
     );

  config_provider.name("key-provider");
  config_provider %=
    +(  qi::upper
     );

  config_provider_decl.name("key-provider-spec");
  config_provider_decl %=
     (  qi::lit(provider_open)
     >  config_provider
     >  qi::lit(provider_close)
     );

  config_key_options.name("key-options");
  config_key_options %=
     ( -config_flags_decl
     > -config_provider_decl
     );

  config_key.name("key-component");
  config_key %=
    +(  qi::alnum
     |  qi::lit('-')
     |  qi::lit('_')
     );

  config_key_path.name("key-path");
  config_key_path %=
     (  config_key
     %  qi::lit(config_path_separator)
     );

  config_value.name("key-value");
  config_value %=
    +(  qi::graph
     |  qi::lit(' ')
     |  qi::lit('\t')
     );

  config_key_full.name("full-key-path");
  config_key_full %=
     (  config_key_path
     >  config_key_options
     );

  partial_config_value_decl.name("partial-config-spec");
  partial_config_value_decl %=
     (  opt_whitespace
     >  qi::lit(config_path_separator)
     >  config_key_full
     >  whitespace
     >  config_value
     >  line_end
     );

  partial_config_value_decls.name("partial-configs-spec");
  partial_config_value_decls %=
    *(  partial_config_value_decl
     );

  config_block.name("config-block-spec");
  config_block %=
     (  opt_whitespace
     >  qi::lit(config_block_name)
     >  whitespace
     >  config_key_path
     >  line_end
     >  partial_config_value_decls
     );

  type_name.name("type-name");
  type_name %=
     (  config_key
     );

  type_decl.name("type-decl");
  type_decl %=
     (  qi::lit(type_token)
     >  whitespace
     >  type_name
     );

  process_name.name("port-process");
  process_name %=
     (  config_key
     );

  process_block.name("process-block-spec");
  process_block %=
     (  opt_whitespace
     >  qi::lit(process_block_name)
     >  whitespace
     >  process_name
     >  line_end
     >  opt_whitespace
     >  type_decl
     >  line_end
     >  partial_config_value_decls
     );

  port_name.name("port-name");
  port_name %=
     (  config_key
     );

  port_addr.name("port-addr");
  port_addr %=
     (  process_name
     >  qi::lit(port_separator)
     >  port_name
     );

  connect_block.name("connect-block-spec");
  connect_block %=
     (  opt_whitespace
     >  qi::lit(connect_block_name)
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_addr
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_addr
     >  line_end
     );

  map_flag.name("map-flag");
  map_flag %=
    +(  qi::alpha
     );

  map_flags.name("map-flags");
  map_flags %=
     (  map_flag[boost::phoenix::insert(_a, _1)]
     %  qi::lit(flag_separator)
     );

  map_flags_decl.name("map-flag-decl");
  map_flags_decl %=
     (  qi::lit(flag_decl_open)
     >  map_flags
     >  qi::lit(flag_decl_close)
     );

  map_options.name("map-options");
  map_options %=
     ( -map_flags_decl
     );

  input_map_block.name("input-mapping-spec");
  input_map_block %=
     (  opt_whitespace
     >  qi::lit(map_block_name)
     >  map_options
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_name
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_addr
     >  line_end
     );

  output_map_block.name("output-mapping-spec");
  output_map_block %=
     (  opt_whitespace
     >  qi::lit(map_block_name)
     >  map_options
     >  whitespace
     >  qi::lit(from_name)
     >  whitespace
     >  port_addr
     >  line_end
     >  opt_whitespace
     >  qi::lit(to_name)
     >  whitespace
     >  port_name
     >  line_end
     );

  group_block.name("group-block-spec");
  group_block %=
     (  opt_whitespace
     >  qi::lit(group_block_name)
     >  whitespace
     >  process_name
     >  line_end
     > *(  partial_config_value_decl[boost::phoenix::push_back(_a, _1)]
        |  input_map_block[boost::phoenix::push_back(_b, _1)]
        |  output_map_block[boost::phoenix::push_back(_c, _1)]
        )
     );

  block_set.name("block-spec");
  block_set %=
    *(  config_block
     |  process_block
     |  connect_block
     |  group_block
     );
}

template<typename Iterator>
pipe_grammar<Iterator>
::~pipe_grammar()
{
}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing 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 THE AUTHOR ``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 THE AUTHOR 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 "catch.hpp"

#include <rpc/object.h>
#include "../src/internal.h"

SCENARIO("RPC_NULL_OBJECT", "Create a NULL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t copy;
		object = rpc_null_create();

		THEN("Type is NULL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_NULL);
		}

		AND_THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}
	}
}

SCENARIO("RPC_BOOL_OBJECT", "Create a BOOL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		bool value = true;
		bool different_value = false;
		object = rpc_bool_create(value);
		different_object = rpc_bool_create(different_value);

		THEN("Type is BOOL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_BOOL);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_bool_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_b == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_UINT64_OBJECT", "Create a UINT64 RPC object and perform basic operations on it") {
	GIVEN("UINT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		uint64_t value = 1234;
		uint64_t different_value = 5678;
		object = rpc_uint64_create(value);
		different_object = rpc_uint64_create(different_value);

		THEN("Type is UINT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_UINT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_uint64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_ui == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_INT64_OBJECT", "Create a INT64 RPC object and perform basic operations on it") {
	GIVEN("INT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		int64_t value = 1234;
		int64_t different_value = -1234;
		object = rpc_int64_create(value);
		different_object = rpc_int64_create(different_value);

		THEN("Type is INT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_INT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_int64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_i == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DOUBLE_OBJECT", "Create a DOUBLE RPC object and perform basic operations on it") {
	GIVEN("DOUBLE object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		double value = 12.34;
		double different_value = -12.34;
		object = rpc_double_create(value);
		different_object = rpc_double_create(different_value);

		THEN("Type is DOUBLE") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_DOUBLE);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_double_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_d == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DESCRIPTION_TEST", "Create a tree of RPC objects and print their description") {
	GIVEN("RPC objects tree") {
		int data = 0xff00ff00;
		static const char *referene = "<dictionary> {\n"
		    "    null_val: <null> ,\n"
		    "    array: <array> [\n"
		    "        0: <null> ,\n"
		    "        1: <bool> true,\n"
		    "        2: <uint64> 1234,\n"
		    "        3: <int64> -1234,\n"
		    "        4: <double> 12.340000,\n"
		    "        5: <date> 1970-01-01 00:00:00,\n"
		    "        6: <string> \"test string\",\n"
		    "        7: <binary> 00ff00ff,\n"
		    "        8: <fd> 10,\n"
		    "    ],\n"
		    "    test_string2: <string> \"test_test_test\",\n"
		    "}\n";

		rpc_object_t null = rpc_null_create();
		rpc_object_t boolean = rpc_bool_create(true);
		rpc_object_t u_integer = rpc_uint64_create(1234);
		rpc_object_t integer = rpc_int64_create(-1234);
		rpc_object_t dbl = rpc_double_create(12.34);
		rpc_object_t date = rpc_date_create(0);
		rpc_object_t string = rpc_string_create("test string");
		rpc_object_t binary = rpc_data_create(&data, sizeof(data), false);
		rpc_object_t fd = rpc_fd_create(10);
		rpc_object_t dict = rpc_dictionary_create();
		rpc_object_t array = rpc_array_create();

		rpc_array_append_stolen_value(array, null);
		rpc_array_append_stolen_value(array, boolean);
		rpc_array_append_stolen_value(array, u_integer);
		rpc_array_append_stolen_value(array, integer);
		rpc_array_append_stolen_value(array, dbl);
		rpc_array_append_stolen_value(array, date);
		rpc_array_append_stolen_value(array, string);
		rpc_array_append_stolen_value(array, binary);
		rpc_array_append_stolen_value(array, fd);

		rpc_dictionary_set_value(dict, "null_val", null);
		rpc_dictionary_set_value(dict, "array", array);

		rpc_dictionary_set_string(dict, "test_string2", "test_test_test");

		THEN("Parent RPC object's description is equal to refrence description") {
			REQUIRE(g_strcmp0(referene, rpc_copy_description(dict)) == 0);
		}

		rpc_release(dict);
	}
}
<commit_msg>ADDED: date object test<commit_after>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing 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 THE AUTHOR ``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 THE AUTHOR 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 "catch.hpp"

#include <rpc/object.h>
#include "../src/internal.h"

SCENARIO("RPC_NULL_OBJECT", "Create a NULL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t copy;
		object = rpc_null_create();

		THEN("Type is NULL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_NULL);
		}

		AND_THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}
	}
}

SCENARIO("RPC_BOOL_OBJECT", "Create a BOOL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		bool value = true;
		bool different_value = false;
		object = rpc_bool_create(value);
		different_object = rpc_bool_create(different_value);

		THEN("Type is BOOL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_BOOL);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_bool_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_b == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_UINT64_OBJECT", "Create a UINT64 RPC object and perform basic operations on it") {
	GIVEN("UINT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		uint64_t value = 1234;
		uint64_t different_value = 5678;
		object = rpc_uint64_create(value);
		different_object = rpc_uint64_create(different_value);

		THEN("Type is UINT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_UINT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_uint64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_ui == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_INT64_OBJECT", "Create a INT64 RPC object and perform basic operations on it") {
	GIVEN("INT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		int64_t value = 1234;
		int64_t different_value = -1234;
		object = rpc_int64_create(value);
		different_object = rpc_int64_create(different_value);

		THEN("Type is INT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_INT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_int64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_i == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DOUBLE_OBJECT", "Create a DOUBLE RPC object and perform basic operations on it") {
	GIVEN("DOUBLE object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		double value = 12.34;
		double different_value = -12.34;
		object = rpc_double_create(value);
		different_object = rpc_double_create(different_value);

		THEN("Type is DOUBLE") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_DOUBLE);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_double_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_d == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DATE_OBJECT", "Create a DATE RPC object and perform basic operations on it") {
	GIVEN("DATE object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		int value = 0;
		object = rpc_date_create(value);
		different_object = rpc_date_create_from_current();

		THEN("Type is DATE") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_DATE);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_date_get_value(object) == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DESCRIPTION_TEST", "Create a tree of RPC objects and print their description") {
	GIVEN("RPC objects tree") {
		int data = 0xff00ff00;
		static const char *referene = "<dictionary> {\n"
		    "    null_val: <null> ,\n"
		    "    array: <array> [\n"
		    "        0: <null> ,\n"
		    "        1: <bool> true,\n"
		    "        2: <uint64> 1234,\n"
		    "        3: <int64> -1234,\n"
		    "        4: <double> 12.340000,\n"
		    "        5: <date> 1970-01-01 00:00:00,\n"
		    "        6: <string> \"test string\",\n"
		    "        7: <binary> 00ff00ff,\n"
		    "        8: <fd> 10,\n"
		    "    ],\n"
		    "    test_string2: <string> \"test_test_test\",\n"
		    "}\n";

		rpc_object_t null = rpc_null_create();
		rpc_object_t boolean = rpc_bool_create(true);
		rpc_object_t u_integer = rpc_uint64_create(1234);
		rpc_object_t integer = rpc_int64_create(-1234);
		rpc_object_t dbl = rpc_double_create(12.34);
		rpc_object_t date = rpc_date_create(0);
		rpc_object_t string = rpc_string_create("test string");
		rpc_object_t binary = rpc_data_create(&data, sizeof(data), false);
		rpc_object_t fd = rpc_fd_create(10);
		rpc_object_t dict = rpc_dictionary_create();
		rpc_object_t array = rpc_array_create();

		rpc_array_append_stolen_value(array, null);
		rpc_array_append_stolen_value(array, boolean);
		rpc_array_append_stolen_value(array, u_integer);
		rpc_array_append_stolen_value(array, integer);
		rpc_array_append_stolen_value(array, dbl);
		rpc_array_append_stolen_value(array, date);
		rpc_array_append_stolen_value(array, string);
		rpc_array_append_stolen_value(array, binary);
		rpc_array_append_stolen_value(array, fd);

		rpc_dictionary_set_value(dict, "null_val", null);
		rpc_dictionary_set_value(dict, "array", array);

		rpc_dictionary_set_string(dict, "test_string2", "test_test_test");

		THEN("Parent RPC object's description is equal to refrence description") {
			REQUIRE(g_strcmp0(referene, rpc_copy_description(dict)) == 0);
		}

		rpc_release(dict);
	}
}
<|endoftext|>


<commit_before>#include "GlDevice.hpp"
#include "GlSystem.hpp"
#include "GlPresenter.hpp"
#include "GlRenderBuffer.hpp"
#include "GlContext.hpp"
#include "GlTexture.hpp"
#include "GlVertexShader.hpp"
#include "GlPixelShader.hpp"
#include "GlInternalTexture.hpp"
#include "Win32Output.hpp"
#include "../File.hpp"
#include "../Exception.hpp"
#ifdef ___INANITY_WINDOWS
#include "../Strings.hpp"
#endif

#ifdef ___INANITY_WINDOWS
GlDevice::GlDevice(ptr<GlSystem> system, const String& deviceName, ptr<GlContext> context)
: system(system), deviceName(deviceName), context(context), hglrc(0)
{
}

GlDevice::~GlDevice()
{
	if(hglrc)
		wglDeleteContext(hglrc);
}
#endif

ptr<System> GlDevice::GetSystem() const
{
	return system;
}

ptr<Presenter> GlDevice::CreatePresenter(ptr<Output> abstractOutput, const PresentMode& mode)
{
	try
	{
#ifdef ___INANITY_WINDOWS
		// область вывода - только Win32
		ptr<Win32Output> output = abstractOutput.DynamicCast<Win32Output>();
		if(!output)
			THROW_PRIMARY_EXCEPTION("Only Win32 output allowed");

		// если режим полноэкранный, переключить его
		if(mode.fullscreen)
		{
			// заполнить структуру режима экрана
			DEVMODE devMode;
			ZeroMemory(&devMode, sizeof(devMode));
			devMode.dmSize = sizeof(devMode);
			devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
			devMode.dmBitsPerPel = 32;
			devMode.dmPelsWidth = mode.width;
			devMode.dmPelsHeight = mode.height;
			// сменить режим экрана
			if(ChangeDisplaySettingsEx(Strings::UTF82Unicode(deviceName).c_str(), &devMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
				THROW_PRIMARY_EXCEPTION("Can't change display settings");
		}

		// получить дескриптор окна
		HDC hdc = GetDC(output->GetHWND());
		if(!hdc)
			THROW_PRIMARY_EXCEPTION("Can't get hdc");

		// подобрать формат пикселов
		PIXELFORMATDESCRIPTOR pfd;
		ZeroMemory(&pfd, sizeof(pfd));
		pfd.nSize = sizeof(pfd);
		pfd.nVersion = 1;
		pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
		pfd.iPixelType = PFD_TYPE_RGBA;
		pfd.cColorBits = 24;
		pfd.cDepthBits = 0; // не используем глубину для первичного буфера
		pfd.iLayerType = PFD_MAIN_PLANE;
		int pixelFormat = ChoosePixelFormat(hdc, &pfd);
		if(!pixelFormat)
			THROW_PRIMARY_EXCEPTION("Can't choose pixel format");
		// и установить этот формат
		if(!SetPixelFormat(hdc, pixelFormat, &pfd))
			THROW_PRIMARY_EXCEPTION("Can't set pixel format");

		// создать контекст
		hglrc = wglCreateContext(hdc);
		if(!hglrc)
			THROW_PRIMARY_EXCEPTION("Can't create OpenGL window context");

		// сделать его текущим
		if(!wglMakeCurrent(hdc, hglrc))
			THROW_SECONDARY_EXCEPTION("Can't make OpenGL context current", Exception::SystemError());

		// время для инициализации GLEW
		GlSystem::InitGLEW();

		// создать и вернуть Presenter
		return NEW(GlPresenter(this, hdc, NEW(GlRenderBuffer(0, 0))));

#endif
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create presenter for GL device", exception);
	}
}

ptr<Context> GlDevice::GetContext()
{
	return context;
}

ptr<RenderBuffer> GlDevice::CreateRenderBuffer(int width, int height, PixelFormat pixelFormat)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen texture");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

		GLint internalFormat;
		GLenum format;
		GLenum type;
		if(!GlSystem::GetTextureFormat(pixelFormat, internalFormat, format, type))
			THROW_PRIMARY_EXCEPTION("Invalid pixel format");
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, (GLsizei)width, (GLsizei)height, 0, format, type, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");

		return NEW(GlRenderBuffer(internalTexture, NEW(GlTexture(internalTexture))));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create render buffer", exception);
	}
}

ptr<DepthStencilBuffer> GlDevice::CreateDepthStencilBuffer(int width, int height, bool canBeResource)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen textures");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

		GLint internalFormat;
		GLenum format;
		GLenum type;
		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, (GLsizei)width, (GLsizei)height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");

		return NEW(GlDepthStencilBuffer(internalTexture, NEW(GlTexture(internalTexture))));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create depth stencil buffer", exception);
	}
}

void GlDevice::CompileShader(GLuint shaderName, ptr<File> file)
{
	// указать текст шейдера
	const GLchar* string = (const GLchar*)file->GetData();
	const GLint length = (GLint)file->GetSize();
	glShaderSource(shaderName, 1, &string, &length);
	GlSystem::CheckErrors("Can't set shader source");

	// скомпилировать шейдер
	glCompileShader(shaderName);
	{
		GLint status;
		glGetShaderiv(shaderName, GL_COMPILE_STATUS, &status);
		if(status != GL_TRUE)
		{
			// получить лог ошибок
			GLint logLength;
			glGetShaderiv(shaderName, GL_INFO_LOG_LENGTH, &logLength);
			String log(logLength, ' ');
			glGetShaderInfoLog(shaderName, logLength, &logLength, &*log.begin());
			log.resize(logLength);

			// очистить ошибки, на всякий случай
			GlSystem::ClearErrors();

			// выбросить ошибку
			THROW_PRIMARY_EXCEPTION("Can't compile shader:\n" + log);
		}
	}
}

ptr<VertexShader> GlDevice::CreateVertexShader(ptr<File> file)
{
	try
	{
		GLuint shaderName = glCreateShader(GL_VERTEX_SHADER);
		GlSystem::CheckErrors("Can't create shader");

		CompileShader(shaderName, file);

		return NEW(GlVertexShader(shaderName));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create vertex shader", exception);
	}
}

ptr<PixelShader> GlDevice::CreatePixelShader(ptr<File> file)
{
	try
	{
		GLuint shaderName = glCreateShader(GL_FRAGMENT_SHADER);
		GlSystem::CheckErrors("Can't create shader");

		CompileShader(shaderName, file);

		return NEW(GlPixelShader(shaderName));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create pixel shader", exception);
	}
}

ptr<UniformBuffer> GlDevice::CreateUniformBuffer(int size)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlUniformBuffer> uniformBuffer = NEW(GlUniformBuffer(bufferName, size));

		glBindBuffer(GL_UNIFORM_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_DYNAMIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return uniformBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create uniform buffer", exception);
	}
}

ptr<VertexBuffer> GlDevice::CreateVertexBuffer(ptr<File> file, ptr<Layout> layout)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlVertexBuffer> vertexBuffer = NEW(GlVertexBuffer(bufferName, file->GetSize() / layout->GetStride(), layout));

		glBindBuffer(GL_ARRAY_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_ARRAY_BUFFER, file->GetSize(), file->GetData(), GL_STATIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return vertexBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create vertex buffer", exception);
	}
}

ptr<IndexBuffer> GlDevice::CreateIndexBuffer(ptr<File> file, int indexSize)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlIndexBuffer> indexBuffer = NEW(GlIndexBuffer(bufferName, file->GetSize() / indexSize, indexSize));

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_ELEMENT_ARRAY_BUFFER, file->GetSize(), file->GetData(), GL_STATIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return indexBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create index buffer", exception);
	}
}

ptr<Texture> GlDevice::CreateStaticTexture(ptr<File> file)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen texture");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

#error Work is not finished...
		GLint internalFormat;
		GLenum format;
		GLenum type;
		if(!GlSystem::GetTextureFormat(pixelFormat, internalFormat, format, type))
			THROW_PRIMARY_EXCEPTION("Invalid pixel format");
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, (GLsizei)width, (GLsizei)height, 0, format, type, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create static texture", exception);
	}
}
<commit_msg>some more work on GL<commit_after>#include "GlDevice.hpp"
#include "GlSystem.hpp"
#include "GlPresenter.hpp"
#include "GlRenderBuffer.hpp"
#include "GlDepthStencilBuffer.hpp"
#include "GlContext.hpp"
#include "GlTexture.hpp"
#include "GlVertexShader.hpp"
#include "GlPixelShader.hpp"
#include "GlUniformBuffer.hpp"
#include "GlVertexBuffer.hpp"
#include "GlIndexBuffer.hpp"
#include "Layout.hpp"
#include "GlInternalTexture.hpp"
#include "Win32Output.hpp"
#include "../File.hpp"
#include "../Exception.hpp"
#ifdef ___INANITY_WINDOWS
#include "../Strings.hpp"
#endif

#ifdef ___INANITY_WINDOWS
GlDevice::GlDevice(ptr<GlSystem> system, const String& deviceName, ptr<GlContext> context)
: system(system), deviceName(deviceName), context(context), hglrc(0)
{
}

GlDevice::~GlDevice()
{
	if(hglrc)
		wglDeleteContext(hglrc);
}
#endif

ptr<System> GlDevice::GetSystem() const
{
	return system;
}

ptr<Presenter> GlDevice::CreatePresenter(ptr<Output> abstractOutput, const PresentMode& mode)
{
	try
	{
#ifdef ___INANITY_WINDOWS
		// область вывода - только Win32
		ptr<Win32Output> output = abstractOutput.DynamicCast<Win32Output>();
		if(!output)
			THROW_PRIMARY_EXCEPTION("Only Win32 output allowed");

		// если режим полноэкранный, переключить его
		if(mode.fullscreen)
		{
			// заполнить структуру режима экрана
			DEVMODE devMode;
			ZeroMemory(&devMode, sizeof(devMode));
			devMode.dmSize = sizeof(devMode);
			devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
			devMode.dmBitsPerPel = 32;
			devMode.dmPelsWidth = mode.width;
			devMode.dmPelsHeight = mode.height;
			// сменить режим экрана
			if(ChangeDisplaySettingsEx(Strings::UTF82Unicode(deviceName).c_str(), &devMode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
				THROW_PRIMARY_EXCEPTION("Can't change display settings");
		}

		// получить дескриптор окна
		HDC hdc = GetDC(output->GetHWND());
		if(!hdc)
			THROW_PRIMARY_EXCEPTION("Can't get hdc");

		// подобрать формат пикселов
		PIXELFORMATDESCRIPTOR pfd;
		ZeroMemory(&pfd, sizeof(pfd));
		pfd.nSize = sizeof(pfd);
		pfd.nVersion = 1;
		pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
		pfd.iPixelType = PFD_TYPE_RGBA;
		pfd.cColorBits = 24;
		pfd.cDepthBits = 0; // не используем глубину для первичного буфера
		pfd.iLayerType = PFD_MAIN_PLANE;
		int pixelFormat = ChoosePixelFormat(hdc, &pfd);
		if(!pixelFormat)
			THROW_PRIMARY_EXCEPTION("Can't choose pixel format");
		// и установить этот формат
		if(!SetPixelFormat(hdc, pixelFormat, &pfd))
			THROW_PRIMARY_EXCEPTION("Can't set pixel format");

		// создать контекст
		hglrc = wglCreateContext(hdc);
		if(!hglrc)
			THROW_PRIMARY_EXCEPTION("Can't create OpenGL window context");

		// сделать его текущим
		if(!wglMakeCurrent(hdc, hglrc))
			THROW_SECONDARY_EXCEPTION("Can't make OpenGL context current", Exception::SystemError());

		// время для инициализации GLEW
		GlSystem::InitGLEW();

		// создать и вернуть Presenter
		return NEW(GlPresenter(this, hdc, NEW(GlRenderBuffer(0, 0))));

#endif
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create presenter for GL device", exception);
	}
}

ptr<Context> GlDevice::GetContext()
{
	return context;
}

ptr<RenderBuffer> GlDevice::CreateRenderBuffer(int width, int height, PixelFormat pixelFormat)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen texture");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

		GLint internalFormat;
		GLenum format;
		GLenum type;
		if(!GlSystem::GetTextureFormat(pixelFormat, internalFormat, format, type))
			THROW_PRIMARY_EXCEPTION("Invalid pixel format");
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, (GLsizei)width, (GLsizei)height, 0, format, type, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");

		return NEW(GlRenderBuffer(internalTexture, NEW(GlTexture(internalTexture))));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create render buffer", exception);
	}
}

ptr<DepthStencilBuffer> GlDevice::CreateDepthStencilBuffer(int width, int height, bool canBeResource)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen textures");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, (GLsizei)width, (GLsizei)height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");

		return NEW(GlDepthStencilBuffer(internalTexture, NEW(GlTexture(internalTexture))));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create depth stencil buffer", exception);
	}
}

void GlDevice::CompileShader(GLuint shaderName, ptr<File> file)
{
	// указать текст шейдера
	const GLchar* string = (const GLchar*)file->GetData();
	const GLint length = (GLint)file->GetSize();
	glShaderSource(shaderName, 1, &string, &length);
	GlSystem::CheckErrors("Can't set shader source");

	// скомпилировать шейдер
	glCompileShader(shaderName);
	{
		GLint status;
		glGetShaderiv(shaderName, GL_COMPILE_STATUS, &status);
		if(status != GL_TRUE)
		{
			// получить лог ошибок
			GLint logLength;
			glGetShaderiv(shaderName, GL_INFO_LOG_LENGTH, &logLength);
			String log(logLength, ' ');
			glGetShaderInfoLog(shaderName, logLength, &logLength, &*log.begin());
			log.resize(logLength);

			// очистить ошибки, на всякий случай
			GlSystem::ClearErrors();

			// выбросить ошибку
			THROW_PRIMARY_EXCEPTION("Can't compile shader:\n" + log);
		}
	}
}

ptr<VertexShader> GlDevice::CreateVertexShader(ptr<File> file)
{
	try
	{
		GLuint shaderName = glCreateShader(GL_VERTEX_SHADER);
		GlSystem::CheckErrors("Can't create shader");

		CompileShader(shaderName, file);

		return NEW(GlVertexShader(shaderName));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create vertex shader", exception);
	}
}

ptr<PixelShader> GlDevice::CreatePixelShader(ptr<File> file)
{
	try
	{
		GLuint shaderName = glCreateShader(GL_FRAGMENT_SHADER);
		GlSystem::CheckErrors("Can't create shader");

		CompileShader(shaderName, file);

		return NEW(GlPixelShader(shaderName));
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create pixel shader", exception);
	}
}

ptr<UniformBuffer> GlDevice::CreateUniformBuffer(int size)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlUniformBuffer> uniformBuffer = NEW(GlUniformBuffer(bufferName, size));

		glBindBuffer(GL_UNIFORM_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_DYNAMIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return uniformBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create uniform buffer", exception);
	}
}

ptr<VertexBuffer> GlDevice::CreateVertexBuffer(ptr<File> file, ptr<Layout> layout)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlVertexBuffer> vertexBuffer = NEW(GlVertexBuffer(bufferName, file->GetSize() / layout->GetStride(), layout));

		glBindBuffer(GL_ARRAY_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_ARRAY_BUFFER, file->GetSize(), file->GetData(), GL_STATIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return vertexBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create vertex buffer", exception);
	}
}

ptr<IndexBuffer> GlDevice::CreateIndexBuffer(ptr<File> file, int indexSize)
{
	try
	{
		GLuint bufferName;
		glGenBuffers(1, &bufferName);
		GlSystem::CheckErrors("Can't gen buffer");
		ptr<GlIndexBuffer> indexBuffer = NEW(GlIndexBuffer(bufferName, file->GetSize() / indexSize, indexSize));

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName);
		GlSystem::CheckErrors("Can't bind buffer");

		glBufferData(GL_ELEMENT_ARRAY_BUFFER, file->GetSize(), file->GetData(), GL_STATIC_DRAW);
		GlSystem::CheckErrors("Can't setup buffer data");

		return indexBuffer;
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create index buffer", exception);
	}
}

ptr<Texture> GlDevice::CreateStaticTexture(ptr<File> file)
{
	try
	{
		GLuint textureName;
		glGenTextures(1, &textureName);
		GlSystem::CheckErrors("Can't gen texture");
		ptr<GlInternalTexture> internalTexture = NEW(GlInternalTexture(textureName));
		glBindTexture(GL_TEXTURE_2D, textureName);
		GlSystem::CheckErrors("Can't bind texture");

#error Work is not finished...
		GLint internalFormat;
		GLenum format;
		GLenum type;
		if(!GlSystem::GetTextureFormat(pixelFormat, internalFormat, format, type))
			THROW_PRIMARY_EXCEPTION("Invalid pixel format");
		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, (GLsizei)width, (GLsizei)height, 0, format, type, 0);
		GlSystem::CheckErrors("Can't initialize texture");

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		GlSystem::CheckErrors("Can't set texture parameters");
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY_EXCEPTION("Can't create static texture", exception);
	}
}
<|endoftext|>


<commit_before>#include "gridmap.hpp"
#include <cstdio>
#include <cmath>
#include <cstdlib>

class GridPath {
public:

	enum { UnitCost = false };

	typedef float Cost;
	static const float InfCost = -1.0;

	typedef int Oper;	// Index into the ops arrays.
	enum { Nop = -1 };

	GridPath(GridMap*, unsigned int, unsigned int,
		unsigned int, unsigned int);

	class State {
		friend class GridPath;
		unsigned int loc;
		int nops;
		Oper ops[8];
	public:
		State(void) : nops(-1) { }
	};

	class PackedState {
		friend class GridPath;
		unsigned int loc;
	public:
		unsigned long hash(void) { return loc; }

		bool eq(const PackedState &other) const {
			return other.loc == loc;
		}
	};

	struct Undo {
		Undo(State &, Oper) { }
	};

	State initialstate(void);

	Cost h(State &s) {
		return octiledist(s.loc, finish);
	}

	bool isgoal(State &s) {
		return s.loc == finish;
	}

	unsigned int nops(State &s) {
		if (s.nops < 0) {
			s.nops = 0;

			bool up = map->terrainok(s.loc, map->up(s.loc));
			bool down = map->terrainok(s.loc, map->down(s.loc));
			bool left = map->terrainok(s.loc, map->left(s.loc));
			bool right = map->terrainok(s.loc, map->right(s.loc));

			if (up)
				s.ops[s.nops++] = map->up(s.loc);
			if (down)
				s.ops[s.nops++] = map->down(s.loc);
			if (left)
				s.ops[s.nops++] = map->left(s.loc);
			if (right)
				s.ops[s.nops++] = map->right(s.loc);
			if (up && left && map->terrainok(s.loc, map->up(map->left(s.loc))))
				s.ops[s.nops++] = map->up(map->left(s.loc));
			if (down && left && map->terrainok(s.loc, map->down(map->left(s.loc))))
				s.ops[s.nops++] = map->down(map->left(s.loc));
			if (up && right && map->terrainok(s.loc, map->up(map->right(s.loc))))
				s.ops[s.nops++] = map->up(map->right(s.loc));
			if (down && right && map->terrainok(s.loc, map->down(map->right(s.loc))))
				s.ops[s.nops++] = map->down(map->right(s.loc));
		}
		return s.nops;
	}

	Oper nthop(State &s, unsigned int n) {
		return s.ops[n];
	}

	Oper revop(State &s, Oper op) {
		return s.loc;
	}

	Cost opcost(State &s, Oper op) {
		if (map->x(s.loc) == map->x(op) || map->y(s.loc) == map->y(op))
			return 1;
		return sqrtf(2.0);
	}

	void undo(State &s, Undo &u) { }

	State &apply(State &buf, State &s, Oper op) {
		buf.loc = op;
		return buf;
	}

	void pack(PackedState &dst, State &src) {
		dst.loc = src.loc;
	}

	State &unpack(State &buf, PackedState &pkd) {
		buf.loc = pkd.loc;
		return buf;
	}

	void dumpstate(FILE *out, State &s) {
		fprintf(out, "%u, %u\n", map->x(s.loc), map->y(s.loc));
	}

	unsigned int width(void) { return map->width(); }

	unsigned int height(void) { return map->height(); }

private:

	float octiledist(unsigned int l0, unsigned int l1) {
		unsigned int dx = abs(map->x(l0) - map->x(l1));
		unsigned int dy = abs(map->y(l0) - map->y(l1));
		unsigned int diag = dx < dy ? dx : dy;
		unsigned int straight = dx < dy ? dy : dx;
		return (straight - diag) + sqrtf(2.0) * diag;
	}

	unsigned int start, finish;
	GridMap *map;
};<commit_msg>Cleanup 8-way operator testing in grids.<commit_after>#include "gridmap.hpp"
#include <cstdio>
#include <cmath>
#include <cstdlib>

class GridPath {
public:

	enum { UnitCost = false };

	typedef float Cost;
	static const float InfCost = -1.0;

	typedef int Oper;	// Index into the ops arrays.
	enum { Nop = -1 };

	GridPath(GridMap*, unsigned int, unsigned int,
		unsigned int, unsigned int);

	class State {
		friend class GridPath;
		unsigned int loc;
		int nops;
		Oper ops[8];
	public:
		State(void) : nops(-1) { }
	};

	class PackedState {
		friend class GridPath;
		unsigned int loc;
	public:
		unsigned long hash(void) { return loc; }

		bool eq(const PackedState &other) const {
			return other.loc == loc;
		}
	};

	struct Undo {
		Undo(State &, Oper) { }
	};

	State initialstate(void);

	Cost h(State &s) {
		return octiledist(s.loc, finish);
	}

	bool isgoal(State &s) {
		return s.loc == finish;
	}

	unsigned int nops(State &s) {
		if (s.nops < 0) {
			s.nops = 0;

			bool upok = map->terrainok(s.loc, map->up(s.loc));
			if (upok)
				s.ops[s.nops++] = map->up(s.loc);

			bool downok = map->terrainok(s.loc, map->down(s.loc));
			if (downok)
				s.ops[s.nops++] = map->down(s.loc);

			bool leftok = map->terrainok(s.loc, map->left(s.loc));
			if (leftok)
				s.ops[s.nops++] = map->left(s.loc);

			bool rightok= map->terrainok(s.loc, map->right(s.loc));
			if (rightok)
				s.ops[s.nops++] = map->right(s.loc);

			const unsigned int upleft = map->up(map->left(s.loc));
			if (upok && leftok && map->terrainok(s.loc, upleft))
				s.ops[s.nops++] = upleft;

			const unsigned int downleft = map->down(map->left(s.loc));
			if (downok && leftok && map->terrainok(s.loc, downleft))
				s.ops[s.nops++] = downleft;

			const unsigned int upright = map->up(map->right(s.loc));
			if (upok && rightok && map->terrainok(s.loc, upright))
				s.ops[s.nops++] = upright;

			const unsigned int downright = map->down(map->right(s.loc));
			if (downok && rightok && map->terrainok(s.loc, downright))
				s.ops[s.nops++] = downright;
		}
		return s.nops;
	}

	Oper nthop(State &s, unsigned int n) {
		return s.ops[n];
	}

	Oper revop(State &s, Oper op) {
		return s.loc;
	}

	Cost opcost(State &s, Oper op) {
		if (map->x(s.loc) == map->x(op) || map->y(s.loc) == map->y(op))
			return 1;
		return sqrtf(2.0);
	}

	void undo(State &s, Undo &u) { }

	State &apply(State &buf, State &s, Oper op) {
		buf.loc = op;
		return buf;
	}

	void pack(PackedState &dst, State &src) {
		dst.loc = src.loc;
	}

	State &unpack(State &buf, PackedState &pkd) {
		buf.loc = pkd.loc;
		return buf;
	}

	void dumpstate(FILE *out, State &s) {
		fprintf(out, "%u, %u\n", map->x(s.loc), map->y(s.loc));
	}

	unsigned int width(void) { return map->width(); }

	unsigned int height(void) { return map->height(); }

private:

	float octiledist(unsigned int l0, unsigned int l1) {
		unsigned int dx = abs(map->x(l0) - map->x(l1));
		unsigned int dy = abs(map->y(l0) - map->y(l1));
		unsigned int diag = dx < dy ? dx : dy;
		unsigned int straight = dx < dy ? dy : dx;
		return (straight - diag) + sqrtf(2.0) * diag;
	}

	unsigned int start, finish;
	GridMap *map;
};<|endoftext|>