<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __STORE_H
#define __STORE_H

#include "core-forward-decl.hh"
#include "memword.hh"
#include "storage.hh"
#include "type.hh"

/**
 * A value node in the store.
 * The store is entirely made of nodes. A node is basically a typed value.
 * Non-atomic values, such as records, contain references to other nodes in the
 * store, hence forming a graph, and the name "node".
 * There are two kinds of node: stable and unstable node. A stable node is
 * guaranteed never to change, whereas unstable node can change. In order to
 * maintain consistency in the store, non-atomic values are only allowed to
 * reference stable nodes. Unstable nodes are used for working data, and
 * inherently mutable data (such as the contents of a cell).
 */
class Node {
public:
  template<class T, class... Args>
  void make(VM vm, Args... args) {
    typedef Accessor<T, typename Storage<T>::Type> Access;
    Access::init(type, value, vm, args...);
  }

  inline void reset(VM vm);

  union {
    // Regular structure of a node
    struct {
      const Type* type;
      MemWord value;
    };

    // Garbage collector hack
    struct {
      Node* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Stable node, which is guaranteed never to change
 */
class StableNode {
public:
  inline void init(VM vm, UnstableNode& from);
private:
  friend class UnstableNode;
public: // TODO make it private once the development has been bootstrapped
  Node node;
};

/**
 * Unstable node, which is allowed to change over time
 */
class UnstableNode {
public:
  UnstableNode() {}

  UnstableNode(VM vm, StableNode& from) {
    copy(vm, from);
  }

  UnstableNode(VM vm, UnstableNode& from) {
    copy(vm, from);
  }

  inline void copy(VM vm, StableNode& from);
  inline void copy(VM vm, UnstableNode& from);
  inline void swap(UnstableNode& from);
  inline void reset(VM vm);

  template<class T, class... Args>
  void make(VM vm, Args... args) {
    node.make<T>(vm, args...);
  }
private:
  friend class StableNode;
public: // TODO make it private once the development has been bootstrapped
  Node node;
};

/**
 * Base class for Self types
 */
template <class T>
class BaseSelf {
protected:
  typedef typename Storage<T>::Type StorageType;
  typedef Accessor<T, StorageType> Access;
public:
  BaseSelf(Node* node) : _node(node) {}

  template<class U, class... Args>
  void make(VM vm, Args... args) {
    _node->make<U>(vm, args...);
  }

  operator Node*() {
    return _node;
  }

  Node& operator*() {
    return *_node;
  }
protected:
  auto getBase() -> decltype(Access::get(MemWord())) {
    return Access::get(_node->value);
  }

  Node* _node;
};

/**
 * Self type for custom storage-based types
 */
template <class T>
class CustomStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  CustomStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl get() {
    return this->getBase();
  }
};

/**
 * Self type for default storage-based types
 */
template <class T>
class DefaultStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  DefaultStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return &this->getBase();
  }
};

/**
 * Extractor function for the template parameters of ImplWithArray
 * Given
 *   typedef ImplWithArray<I, E> T;
 * this provides
 *   ExtractImplWithArray<T>::Impl === I
 *   ExtractImplWithArray<T>::Elem === E
 */
template <class S>
struct ExtractImplWithArray {};

template <class I, class E>
struct ExtractImplWithArray<ImplWithArray<I, E>> {
  typedef I Impl;
  typedef E Elem;
};

/**
 * Self type for ImplWithArray-based types
 */
template <class T>
class ImplWithArraySelf: public BaseSelf<T> {
private:
  typedef typename BaseSelf<T>::StorageType StorageType;
  typedef typename ExtractImplWithArray<StorageType>::Impl Impl;
  typedef typename ExtractImplWithArray<StorageType>::Elem Elem;
public:
  ImplWithArraySelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return get().operator->();
  }

  Elem& operator[](size_t i) {
    return get().operator[](i);
  }

  StaticArray<Elem> getArray(size_t size) {
    return get().getArray(size);
  }
private:
  ImplWithArray<Impl, Elem> get() {
    return ImplWithArray<Impl, Elem>(&this->getBase());
  }
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class S>
struct SelfTypeInner {
  typedef CustomStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T>
struct SelfTypeInner<T, DefaultStorage<T>> {
  typedef DefaultStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class I, class E>
struct SelfTypeInner<T, ImplWithArray<I, E>> {
  typedef ImplWithArraySelf<T> Self;
};

/**
 * Metafunction from type to its Self type
 * Use as SelfType<T>::Self
 */
template <class T>
struct SelfType {
  typedef typename SelfTypeInner<T, typename Storage<T>::Type>::Self Self;
};

/**
 * Result of the call to a builtin.
 * It always represents a node that must be waited upon. The value 'nullptr' is
 * valid, and denotes that no value must be waited upon, i.e., the execution can
 * continue.
 * Throwing an exception is achieved by pointing to a failed value.
 */
typedef Node* BuiltinResult;

const BuiltinResult BuiltinResultContinue = nullptr;

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class Impl {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(typename SelfType<T>::Self(it), args...);
  }
};

#define IMPL(ResType, Type, method, args...) \
  (Impl<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class ImplNoSelf {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(args...);
  }
};

#define IMPLNOSELF(ResType, Type, method, args...) \
  (ImplNoSelf<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

///////////////
// Reference //
///////////////

class Reference;

template <>
class Storage<Reference> {
public:
  typedef StableNode* Type;
};

template <>
class Implementation<Reference> {
public:
  Implementation<Reference>(StableNode* dest) : _dest(dest) {}
  static StableNode* build(VM, StableNode* dest) { return dest; }

  StableNode* dest() const { return _dest; }
private:
  StableNode* _dest;
};

/**
 * Type of a reference
 */
class Reference: public Type {
public:
  Reference() : Type("Reference", true) {}

  typedef Node* Self;

  static const Reference* const type() {
    static const Reference rawType;
    return &rawType;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally it would have been only a while loop
  static Node& dereference(Node& node) {
    if (node.type != type())
      return node;
    else {
      Node* result = &IMPLNOSELF(StableNode*, Reference, dest, &node)->node;
      if (result->type != type())
        return *result;
      else
        return dereferenceLoop(result);
    }
  }

  static void makeFor(VM vm, UnstableNode& node) {
    StableNode* stable = new (vm) StableNode;
    stable->init(vm, node);
  }

  static void makeFor(VM vm, Node& node) {
    UnstableNode temp;
    temp.node = node;
    makeFor(vm, temp);
    node = temp.node;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally the else case would have been only a while loop
  static StableNode* getStableRefFor(VM vm, Node& node) {
    if (node.type != type()) {
      makeFor(vm, node);
      return IMPLNOSELF(StableNode*, Reference, dest, &node);
    } else {
      StableNode* result = IMPLNOSELF(StableNode*, Reference, dest, &node);
      if (result->node.type != type())
        return result;
      else
        return getStableRefForLoop(result);
    }
  }

  static StableNode* getStableRefFor(VM vm, UnstableNode& node) {
    return getStableRefFor(vm, node.node);
  }

  static StableNode* getStableRefFor(VM vm, StableNode& node) {
    if (node.node.type != type())
      return &node;
    else
      return getStableRefFor(vm, node.node);
  }
private:
  static Node& dereferenceLoop(Node* node) {
    while (node->type == type())
      node = &(IMPLNOSELF(StableNode*, Reference, dest, node)->node);
    return *node;
  }

  static StableNode* getStableRefForLoop(StableNode* node) {
    do {
      node = IMPLNOSELF(StableNode*, Reference, dest, &node->node);
    } while (node->node.type == type());

    return node;
  }

};

/////////////////////////
// Node implementation //
/////////////////////////

void Node::reset(VM vm) {
  type = nullptr;
  value.init<void*>(vm, nullptr);
}

void StableNode::init(VM vm, UnstableNode& from) {
  node = from.node;
  if (!node.type->isCopiable())
    from.make<Reference>(vm, this);
}

void UnstableNode::copy(VM vm, StableNode& from) {
  if (from.node.type->isCopiable())
    node = from.node;
  else
    make<Reference>(vm, &from);
}

void UnstableNode::copy(VM vm, UnstableNode& from) {
  if (!from.node.type->isCopiable())
    Reference::makeFor(vm, from);
  node = from.node;
}

void UnstableNode::reset(VM vm) {
  node.reset(vm);
}

void UnstableNode::swap(UnstableNode& from) {
  Node temp = node;
  node = from.node;
  from.node = temp;
}

#include "vm.hh"

#endif // __STORE_H
<commit_msg>In Nodes, GC-related fields exported in Stable- and UnstableNode instead of Node.<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __STORE_H
#define __STORE_H

#include "core-forward-decl.hh"
#include "memword.hh"
#include "storage.hh"
#include "type.hh"

/**
 * A value node in the store.
 * The store is entirely made of nodes. A node is basically a typed value.
 * Non-atomic values, such as records, contain references to other nodes in the
 * store, hence forming a graph, and the name "node".
 * There are two kinds of node: stable and unstable node. A stable node is
 * guaranteed never to change, whereas unstable node can change. In order to
 * maintain consistency in the store, non-atomic values are only allowed to
 * reference stable nodes. Unstable nodes are used for working data, and
 * inherently mutable data (such as the contents of a cell).
 */
class Node {
public:
  template<class T, class... Args>
  void make(VM vm, Args... args) {
    typedef Accessor<T, typename Storage<T>::Type> Access;
    Access::init(type, value, vm, args...);
  }

  inline void reset(VM vm);

  const Type* type;
  MemWord value;
};

/**
 * Stable node, which is guaranteed never to change
 */
class StableNode {
public:
  inline void init(VM vm, UnstableNode& from);
private:
  friend class UnstableNode;
public: // TODO make it private once the development has been bootstrapped
  union {
    Node node;

    // Garbage collector hack
    struct {
      StableNode* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Unstable node, which is allowed to change over time
 */
class UnstableNode {
public:
  UnstableNode() {}

  UnstableNode(VM vm, StableNode& from) {
    copy(vm, from);
  }

  UnstableNode(VM vm, UnstableNode& from) {
    copy(vm, from);
  }

  inline void copy(VM vm, StableNode& from);
  inline void copy(VM vm, UnstableNode& from);
  inline void swap(UnstableNode& from);
  inline void reset(VM vm);

  template<class T, class... Args>
  void make(VM vm, Args... args) {
    node.make<T>(vm, args...);
  }
private:
  friend class StableNode;
public: // TODO make it private once the development has been bootstrapped
  union {
    Node node;

    // Garbage collector hack
    struct {
      UnstableNode* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Base class for Self types
 */
template <class T>
class BaseSelf {
protected:
  typedef typename Storage<T>::Type StorageType;
  typedef Accessor<T, StorageType> Access;
public:
  BaseSelf(Node* node) : _node(node) {}

  template<class U, class... Args>
  void make(VM vm, Args... args) {
    _node->make<U>(vm, args...);
  }

  operator Node*() {
    return _node;
  }

  Node& operator*() {
    return *_node;
  }
protected:
  auto getBase() -> decltype(Access::get(MemWord())) {
    return Access::get(_node->value);
  }

  Node* _node;
};

/**
 * Self type for custom storage-based types
 */
template <class T>
class CustomStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  CustomStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl get() {
    return this->getBase();
  }
};

/**
 * Self type for default storage-based types
 */
template <class T>
class DefaultStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  DefaultStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return &this->getBase();
  }
};

/**
 * Extractor function for the template parameters of ImplWithArray
 * Given
 *   typedef ImplWithArray<I, E> T;
 * this provides
 *   ExtractImplWithArray<T>::Impl === I
 *   ExtractImplWithArray<T>::Elem === E
 */
template <class S>
struct ExtractImplWithArray {};

template <class I, class E>
struct ExtractImplWithArray<ImplWithArray<I, E>> {
  typedef I Impl;
  typedef E Elem;
};

/**
 * Self type for ImplWithArray-based types
 */
template <class T>
class ImplWithArraySelf: public BaseSelf<T> {
private:
  typedef typename BaseSelf<T>::StorageType StorageType;
  typedef typename ExtractImplWithArray<StorageType>::Impl Impl;
  typedef typename ExtractImplWithArray<StorageType>::Elem Elem;
public:
  ImplWithArraySelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return get().operator->();
  }

  Elem& operator[](size_t i) {
    return get().operator[](i);
  }

  StaticArray<Elem> getArray(size_t size) {
    return get().getArray(size);
  }
private:
  ImplWithArray<Impl, Elem> get() {
    return ImplWithArray<Impl, Elem>(&this->getBase());
  }
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class S>
struct SelfTypeInner {
  typedef CustomStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T>
struct SelfTypeInner<T, DefaultStorage<T>> {
  typedef DefaultStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class I, class E>
struct SelfTypeInner<T, ImplWithArray<I, E>> {
  typedef ImplWithArraySelf<T> Self;
};

/**
 * Metafunction from type to its Self type
 * Use as SelfType<T>::Self
 */
template <class T>
struct SelfType {
  typedef typename SelfTypeInner<T, typename Storage<T>::Type>::Self Self;
};

/**
 * Result of the call to a builtin.
 * It always represents a node that must be waited upon. The value 'nullptr' is
 * valid, and denotes that no value must be waited upon, i.e., the execution can
 * continue.
 * Throwing an exception is achieved by pointing to a failed value.
 */
typedef Node* BuiltinResult;

const BuiltinResult BuiltinResultContinue = nullptr;

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class Impl {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(typename SelfType<T>::Self(it), args...);
  }
};

#define IMPL(ResType, Type, method, args...) \
  (Impl<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class ImplNoSelf {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(args...);
  }
};

#define IMPLNOSELF(ResType, Type, method, args...) \
  (ImplNoSelf<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

///////////////
// Reference //
///////////////

class Reference;

template <>
class Storage<Reference> {
public:
  typedef StableNode* Type;
};

template <>
class Implementation<Reference> {
public:
  Implementation<Reference>(StableNode* dest) : _dest(dest) {}
  static StableNode* build(VM, StableNode* dest) { return dest; }

  StableNode* dest() const { return _dest; }
private:
  StableNode* _dest;
};

/**
 * Type of a reference
 */
class Reference: public Type {
public:
  Reference() : Type("Reference", true) {}

  typedef Node* Self;

  static const Reference* const type() {
    static const Reference rawType;
    return &rawType;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally it would have been only a while loop
  static Node& dereference(Node& node) {
    if (node.type != type())
      return node;
    else {
      Node* result = &IMPLNOSELF(StableNode*, Reference, dest, &node)->node;
      if (result->type != type())
        return *result;
      else
        return dereferenceLoop(result);
    }
  }

  static void makeFor(VM vm, UnstableNode& node) {
    StableNode* stable = new (vm) StableNode;
    stable->init(vm, node);
  }

  static void makeFor(VM vm, Node& node) {
    UnstableNode temp;
    temp.node = node;
    makeFor(vm, temp);
    node = temp.node;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally the else case would have been only a while loop
  static StableNode* getStableRefFor(VM vm, Node& node) {
    if (node.type != type()) {
      makeFor(vm, node);
      return IMPLNOSELF(StableNode*, Reference, dest, &node);
    } else {
      StableNode* result = IMPLNOSELF(StableNode*, Reference, dest, &node);
      if (result->node.type != type())
        return result;
      else
        return getStableRefForLoop(result);
    }
  }

  static StableNode* getStableRefFor(VM vm, UnstableNode& node) {
    return getStableRefFor(vm, node.node);
  }

  static StableNode* getStableRefFor(VM vm, StableNode& node) {
    if (node.node.type != type())
      return &node;
    else
      return getStableRefFor(vm, node.node);
  }
private:
  static Node& dereferenceLoop(Node* node) {
    while (node->type == type())
      node = &(IMPLNOSELF(StableNode*, Reference, dest, node)->node);
    return *node;
  }

  static StableNode* getStableRefForLoop(StableNode* node) {
    do {
      node = IMPLNOSELF(StableNode*, Reference, dest, &node->node);
    } while (node->node.type == type());

    return node;
  }

};

/////////////////////////
// Node implementation //
/////////////////////////

void Node::reset(VM vm) {
  type = nullptr;
  value.init<void*>(vm, nullptr);
}

void StableNode::init(VM vm, UnstableNode& from) {
  node = from.node;
  if (!node.type->isCopiable())
    from.make<Reference>(vm, this);
}

void UnstableNode::copy(VM vm, StableNode& from) {
  if (from.node.type->isCopiable())
    node = from.node;
  else
    make<Reference>(vm, &from);
}

void UnstableNode::copy(VM vm, UnstableNode& from) {
  if (!from.node.type->isCopiable())
    Reference::makeFor(vm, from);
  node = from.node;
}

void UnstableNode::reset(VM vm) {
  node.reset(vm);
}

void UnstableNode::swap(UnstableNode& from) {
  Node temp = node;
  node = from.node;
  from.node = temp;
}

#include "vm.hh"

#endif // __STORE_H
<|endoftext|>


<commit_before>#include "voxel_buffer.h"
#include <string.h>

//#define VOXEL_AT(_data, x, y, z) data[z][x][y]
#define VOXEL_AT(_data, _x, _y, _z) _data[index(_x,_y,_z)]

VoxelBuffer::VoxelBuffer() {

}

VoxelBuffer::~VoxelBuffer() {
    clear();
}

void VoxelBuffer::create(int sx, int sy, int sz) {
    if (sx <= 0 || sy <= 0 || sz <= 0) {
        return;
    }
    Vector3i new_size(sx, sy, sz);
    if (new_size != _size) {
        for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
            Channel & channel = _channels[i];
            if (channel.data) {
                // TODO Optimize with realloc
                delete_channel(i, _size);
                create_channel(i, new_size);
            }
        }
        _size = new_size;
    }
}

void VoxelBuffer::clear() {
    for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
        Channel & channel = _channels[i];
        if (channel.data) {
            delete_channel(i, _size);
        }
    }
}

void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
    delete_channel(channel_index, _size);
    _channels[channel_index].defval = clear_value;
}

int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) const {
    ERR_FAIL_INDEX_V(channel_index,  MAX_CHANNELS, 0);

    const Channel & channel = _channels[channel_index];

    if (validate_pos(x, y, z) && channel.data) {
        return VOXEL_AT(channel.data, x,y,z);
    }
    else {
        return channel.defval;
    }
}

void VoxelBuffer::set_voxel(int value, int x, int y, int z, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index,  MAX_CHANNELS);
    ERR_FAIL_COND(!validate_pos(x, y, z));

    Channel & channel = _channels[channel_index];

    if (channel.defval != value) {
        if (channel.data == NULL) {
            create_channel(channel_index, _size);
        }
        VOXEL_AT(channel.data, x, y, z) = value;
    }
}

void VoxelBuffer::set_voxel_v(int value, Vector3 pos, unsigned int channel_index) {
    set_voxel(value, pos.x, pos.y, pos.z, channel_index);
}

void VoxelBuffer::fill(int defval, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL && channel.defval == defval)
        return;
    else
        create_channel_noinit(channel_index, _size);

    unsigned int volume = get_volume();
    memset(channel.data, defval, volume);
}

void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Vector3i::sort_min_max(min, max);

    min.clamp_to(Vector3i(0, 0, 0), _size);
    max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1,1,1));
    Vector3i area_size = max - min;

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL) {
        if (channel.defval == defval)
            return;
        else
            create_channel(channel_index, _size);
    }

    Vector3i pos;
    for (pos.z = min.z; pos.z < max.z; ++pos.z) {
        for (pos.x = min.x; pos.x < max.x; ++pos.x) {
            unsigned int dst_ri = index(pos.x, pos.y + min.y, pos.z);
            memset(&channel.data[dst_ri], defval, area_size.y * sizeof(uint8_t));
        }
    }
}

bool VoxelBuffer::is_uniform(unsigned int channel_index) {
    ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, true);

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL)
        return true;

    uint8_t voxel = channel.data[0];
    unsigned int volume = get_volume();
    for (unsigned int i = 0; i < volume; ++i) {
        if (channel.data[i] != voxel) {
            return false;
        }
    }

    return true;
}

void VoxelBuffer::optimize() {
    for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
        if (_channels[i].data && is_uniform(i)) {
            clear_channel(i, _channels[i].data[0]);
        }
    }
}

void VoxelBuffer::copy_from(const VoxelBuffer & other, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
    ERR_FAIL_COND(other._size == _size);

    Channel & channel = _channels[channel_index];
    const Channel & other_channel = other._channels[channel_index];

    if (other_channel.data) {
        if (channel.data == NULL) {
            create_channel_noinit(channel_index, _size);
        }
        memcpy(channel.data, other_channel.data, get_volume() * sizeof(uint8_t));
    }
    else if(channel.data) {
        delete_channel(channel_index, _size);
    }

    channel.defval = other_channel.defval;
}

void VoxelBuffer::copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Channel & channel = _channels[channel_index];
    const Channel & other_channel = other._channels[channel_index];

    Vector3i::sort_min_max(src_min, src_max);

    src_min.clamp_to(Vector3i(0, 0, 0), other._size);
    src_max.clamp_to(Vector3i(0, 0, 0), other._size + Vector3i(1,1,1));

    dst_min.clamp_to(Vector3i(0, 0, 0), _size);
    Vector3i area_size = src_max - src_min;
    //Vector3i dst_max = dst_min + area_size;

    if (area_size == _size) {
        copy_from(other, channel_index);
    }
    else {
        if (other_channel.data) {
            if (channel.data == NULL) {
                create_channel(channel_index, _size);
            }
            // Copy row by row
            Vector3i pos;
            for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
                for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
                    // Row direction is Y
                    unsigned int src_ri = other.index(pos.x + src_min.x, pos.y + src_min.y, pos.z + src_min.z);
                    unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
                    memcpy(&channel.data[dst_ri], &other_channel.data[src_ri], area_size.y * sizeof(uint8_t));
                }
            }
        }
        else if (channel.defval != other_channel.defval) {
            if (channel.data == NULL) {
                create_channel(channel_index, _size);
            }
            // Set row by row
            Vector3i pos;
            for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
                for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
                    unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
                    memset(&channel.data[dst_ri], other_channel.defval, area_size.y * sizeof(uint8_t));
                }
            }
        }
    }
}

void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) {
    create_channel_noinit(i, size);
    memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t));
}

void VoxelBuffer::create_channel_noinit(int i, Vector3i size) {
    Channel & channel = _channels[i];
    unsigned int volume = size.x * size.y * size.z;
    channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t));
}

void VoxelBuffer::delete_channel(int i, Vector3i size) {
    Channel & channel = _channels[i];
    memfree(channel.data);
    channel.data = NULL;
}

void VoxelBuffer::_bind_methods() {

    ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create);
    ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear);

    ObjectTypeDB::bind_method(_MD("get_size_x"), &VoxelBuffer::get_size_x);
    ObjectTypeDB::bind_method(_MD("get_size_y"), &VoxelBuffer::get_size_y);
    ObjectTypeDB::bind_method(_MD("get_size_z"), &VoxelBuffer::get_size_z);

    ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "channel"), &VoxelBuffer::_set_voxel_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("set_voxel_v", "value", "pos", "channel"), &VoxelBuffer::set_voxel_v, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "channel"), &VoxelBuffer::_get_voxel_binding, DEFVAL(0));

    ObjectTypeDB::bind_method(_MD("fill", "value", "channel"), &VoxelBuffer::fill, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("fill_area", "value", "min", "max", "channel"), &VoxelBuffer::_fill_area_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("copy_from", "other:VoxelBuffer", "channel"), &VoxelBuffer::_copy_from_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("copy_from_area", "other:VoxelBuffer", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_copy_from_area_binding, DEFVAL(0));

    ObjectTypeDB::bind_method(_MD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize);

}

void VoxelBuffer::_copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel) {
    ERR_FAIL_COND(other.is_null());
    copy_from(**other, channel);
}

void VoxelBuffer::_copy_from_area_binding(Ref<VoxelBuffer> other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, unsigned int channel) {
    ERR_FAIL_COND(other.is_null());
    copy_from(**other, Vector3i(src_min), Vector3i(src_max), Vector3i(dst_min), channel);
}
<commit_msg>Fixed change voxel type in VoxelBuffer<commit_after>#include "voxel_buffer.h"
#include <string.h>

//#define VOXEL_AT(_data, x, y, z) data[z][x][y]
#define VOXEL_AT(_data, _x, _y, _z) _data[index(_x,_y,_z)]

VoxelBuffer::VoxelBuffer() {

}

VoxelBuffer::~VoxelBuffer() {
    clear();
}

void VoxelBuffer::create(int sx, int sy, int sz) {
    if (sx <= 0 || sy <= 0 || sz <= 0) {
        return;
    }
    Vector3i new_size(sx, sy, sz);
    if (new_size != _size) {
        for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
            Channel & channel = _channels[i];
            if (channel.data) {
                // TODO Optimize with realloc
                delete_channel(i, _size);
                create_channel(i, new_size);
            }
        }
        _size = new_size;
    }
}

void VoxelBuffer::clear() {
    for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
        Channel & channel = _channels[i];
        if (channel.data) {
            delete_channel(i, _size);
        }
    }
}

void VoxelBuffer::clear_channel(unsigned int channel_index, int clear_value) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
    delete_channel(channel_index, _size);
    _channels[channel_index].defval = clear_value;
}

int VoxelBuffer::get_voxel(int x, int y, int z, unsigned int channel_index) const {
    ERR_FAIL_INDEX_V(channel_index,  MAX_CHANNELS, 0);

    const Channel & channel = _channels[channel_index];

    if (validate_pos(x, y, z) && channel.data) {
        return VOXEL_AT(channel.data, x,y,z);
    }
    else {
        return channel.defval;
    }
}

void VoxelBuffer::set_voxel(int value, int x, int y, int z, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index,  MAX_CHANNELS);
    ERR_FAIL_COND(!validate_pos(x, y, z));

    Channel & channel = _channels[channel_index];

    //FIX: if VOXEL_AT(channel.data, x, y, z) is not channel.defval we have to set that voxel nethertheless
    //if (channel.defval != value) {
        if (channel.data == NULL) {
            create_channel(channel_index, _size);
        }
        VOXEL_AT(channel.data, x, y, z) = value;
    //}
}

void VoxelBuffer::set_voxel_v(int value, Vector3 pos, unsigned int channel_index) {
    set_voxel(value, pos.x, pos.y, pos.z, channel_index);
}

void VoxelBuffer::fill(int defval, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL && channel.defval == defval)
        return;
    else
        create_channel_noinit(channel_index, _size);

    unsigned int volume = get_volume();
    memset(channel.data, defval, volume);
}

void VoxelBuffer::fill_area(int defval, Vector3i min, Vector3i max, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Vector3i::sort_min_max(min, max);

    min.clamp_to(Vector3i(0, 0, 0), _size);
    max.clamp_to(Vector3i(0, 0, 0), _size + Vector3i(1,1,1));
    Vector3i area_size = max - min;

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL) {
        if (channel.defval == defval)
            return;
        else
            create_channel(channel_index, _size);
    }

    Vector3i pos;
    for (pos.z = min.z; pos.z < max.z; ++pos.z) {
        for (pos.x = min.x; pos.x < max.x; ++pos.x) {
            unsigned int dst_ri = index(pos.x, pos.y + min.y, pos.z);
            memset(&channel.data[dst_ri], defval, area_size.y * sizeof(uint8_t));
        }
    }
}

bool VoxelBuffer::is_uniform(unsigned int channel_index) {
    ERR_FAIL_INDEX_V(channel_index, MAX_CHANNELS, true);

    Channel & channel = _channels[channel_index];
    if (channel.data == NULL)
        return true;

    uint8_t voxel = channel.data[0];
    unsigned int volume = get_volume();
    for (unsigned int i = 0; i < volume; ++i) {
        if (channel.data[i] != voxel) {
            return false;
        }
    }

    return true;
}

void VoxelBuffer::optimize() {
    for (unsigned int i = 0; i < MAX_CHANNELS; ++i) {
        if (_channels[i].data && is_uniform(i)) {
            clear_channel(i, _channels[i].data[0]);
        }
    }
}

void VoxelBuffer::copy_from(const VoxelBuffer & other, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);
    ERR_FAIL_COND(other._size == _size);

    Channel & channel = _channels[channel_index];
    const Channel & other_channel = other._channels[channel_index];

    if (other_channel.data) {
        if (channel.data == NULL) {
            create_channel_noinit(channel_index, _size);
        }
        memcpy(channel.data, other_channel.data, get_volume() * sizeof(uint8_t));
    }
    else if(channel.data) {
        delete_channel(channel_index, _size);
    }

    channel.defval = other_channel.defval;
}

void VoxelBuffer::copy_from(const VoxelBuffer & other, Vector3i src_min, Vector3i src_max, Vector3i dst_min, unsigned int channel_index) {
    ERR_FAIL_INDEX(channel_index, MAX_CHANNELS);

    Channel & channel = _channels[channel_index];
    const Channel & other_channel = other._channels[channel_index];

    Vector3i::sort_min_max(src_min, src_max);

    src_min.clamp_to(Vector3i(0, 0, 0), other._size);
    src_max.clamp_to(Vector3i(0, 0, 0), other._size + Vector3i(1,1,1));

    dst_min.clamp_to(Vector3i(0, 0, 0), _size);
    Vector3i area_size = src_max - src_min;
    //Vector3i dst_max = dst_min + area_size;

    if (area_size == _size) {
        copy_from(other, channel_index);
    }
    else {
        if (other_channel.data) {
            if (channel.data == NULL) {
                create_channel(channel_index, _size);
            }
            // Copy row by row
            Vector3i pos;
            for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
                for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
                    // Row direction is Y
                    unsigned int src_ri = other.index(pos.x + src_min.x, pos.y + src_min.y, pos.z + src_min.z);
                    unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
                    memcpy(&channel.data[dst_ri], &other_channel.data[src_ri], area_size.y * sizeof(uint8_t));
                }
            }
        }
        else if (channel.defval != other_channel.defval) {
            if (channel.data == NULL) {
                create_channel(channel_index, _size);
            }
            // Set row by row
            Vector3i pos;
            for (pos.z = 0; pos.z < area_size.z; ++pos.z) {
                for (pos.x = 0; pos.x < area_size.x; ++pos.x) {
                    unsigned int dst_ri = index(pos.x + dst_min.x, pos.y + dst_min.y, pos.z + dst_min.z);
                    memset(&channel.data[dst_ri], other_channel.defval, area_size.y * sizeof(uint8_t));
                }
            }
        }
    }
}

void VoxelBuffer::create_channel(int i, Vector3i size, uint8_t defval) {
    create_channel_noinit(i, size);
    memset(_channels[i].data, defval, get_volume() * sizeof(uint8_t));
}

void VoxelBuffer::create_channel_noinit(int i, Vector3i size) {
    Channel & channel = _channels[i];
    unsigned int volume = size.x * size.y * size.z;
    channel.data = (uint8_t*)memalloc(volume * sizeof(uint8_t));
}

void VoxelBuffer::delete_channel(int i, Vector3i size) {
    Channel & channel = _channels[i];
    memfree(channel.data);
    channel.data = NULL;
}

void VoxelBuffer::_bind_methods() {

    ObjectTypeDB::bind_method(_MD("create", "sx", "sy", "sz"), &VoxelBuffer::create);
    ObjectTypeDB::bind_method(_MD("clear"), &VoxelBuffer::clear);

    ObjectTypeDB::bind_method(_MD("get_size_x"), &VoxelBuffer::get_size_x);
    ObjectTypeDB::bind_method(_MD("get_size_y"), &VoxelBuffer::get_size_y);
    ObjectTypeDB::bind_method(_MD("get_size_z"), &VoxelBuffer::get_size_z);

    ObjectTypeDB::bind_method(_MD("set_voxel", "value", "x", "y", "z", "channel"), &VoxelBuffer::_set_voxel_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("set_voxel_v", "value", "pos", "channel"), &VoxelBuffer::set_voxel_v, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("get_voxel", "x", "y", "z", "channel"), &VoxelBuffer::_get_voxel_binding, DEFVAL(0));

    ObjectTypeDB::bind_method(_MD("fill", "value", "channel"), &VoxelBuffer::fill, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("fill_area", "value", "min", "max", "channel"), &VoxelBuffer::_fill_area_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("copy_from", "other:VoxelBuffer", "channel"), &VoxelBuffer::_copy_from_binding, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("copy_from_area", "other:VoxelBuffer", "src_min", "src_max", "dst_min", "channel"), &VoxelBuffer::_copy_from_area_binding, DEFVAL(0));

    ObjectTypeDB::bind_method(_MD("is_uniform", "channel"), &VoxelBuffer::is_uniform, DEFVAL(0));
    ObjectTypeDB::bind_method(_MD("optimize"), &VoxelBuffer::optimize);

}

void VoxelBuffer::_copy_from_binding(Ref<VoxelBuffer> other, unsigned int channel) {
    ERR_FAIL_COND(other.is_null());
    copy_from(**other, channel);
}

void VoxelBuffer::_copy_from_area_binding(Ref<VoxelBuffer> other, Vector3 src_min, Vector3 src_max, Vector3 dst_min, unsigned int channel) {
    ERR_FAIL_COND(other.is_null());
    copy_from(**other, Vector3i(src_min), Vector3i(src_max), Vector3i(dst_min), channel);
}
<|endoftext|>


<commit_before>#include "audio_filter_resample.h"
#include "halley/support/debug.h"

using namespace Halley;

AudioFilterResample::AudioFilterResample(std::shared_ptr<AudioSource> source, int fromHz, int toHz, AudioBufferPool& pool)
	: pool(pool)
	, source(std::move(source))
	, fromHz(fromHz)
	, toHz(toHz)
{
}

uint8_t AudioFilterResample::getNumberOfChannels() const
{
	return source->getNumberOfChannels();
}

bool AudioFilterResample::isReady() const
{
	return source->isReady();
}

bool AudioFilterResample::getAudioData(size_t numSamples, AudioMultiChannelSamples dstBuffers)
{
	const size_t nChannels = source->getNumberOfChannels();
	const size_t additionalPaddingSamples = 2;
	const size_t nLeftOver = leftoverSamples[0].n;
	const size_t samplesToGenerate = numSamples - nLeftOver;
	const size_t numSamplesSrc = samplesToGenerate * fromHz / toHz + additionalPaddingSamples;

	if (resamplers.empty()) {
		for (size_t i = 0; i < nChannels; ++i) {
			resamplers.push_back(std::make_unique<AudioResampler>(fromHz, toHz, 1, Debug::isDebug() ? 0.0f : 0.3f));
		}
	}

	// Read upstream data
	auto srcBuffers = pool.getBuffers(nChannels, numSamplesSrc);
	auto srcs = srcBuffers.getSampleSpans();
	bool playing = source->getAudioData(numSamplesSrc, srcs);

	// Prepare temporary destination data
	auto tmpBuffer = pool.getBuffer(numSamples + 32); // Is this +32 needed?
	auto tmp = tmpBuffer.getSpan();

	// Resample
	for (size_t channel = 0; channel < nChannels; ++channel) {
		// First copy any leftovers
		Expects(leftoverSamples[channel].n == nLeftOver);
		for (size_t i = 0; i < nLeftOver; ++i) {
			tmp[i] = leftoverSamples[channel].samples[i];
		}

		auto result = resamplers[channel]->resample(srcs[channel].subspan(0, numSamplesSrc), tmp.subspan(nLeftOver), 0);
		Expects(result.nRead == numSamplesSrc);
		Expects(result.nWritten >= samplesToGenerate);

		// Store left overs
		size_t leftOver = result.nWritten + nLeftOver - numSamples;
		for (size_t i = 0; i < leftOver; ++i) {
			leftoverSamples[channel].samples[i] = tmp[i + numSamples];
		}
		leftoverSamples[channel].n = leftOver;

		// Copy to destination
		memcpy(dstBuffers[channel].data(), tmp.data(), numSamples * sizeof(AudioSample));
	}

	return playing;
}

size_t AudioFilterResample::getSamplesLeft() const
{
	return source->getSamplesLeft() * toHz / fromHz;
}

void AudioFilterResample::setFromHz(int fromHz)
{
	for (auto& r: resamplers) {
		r->setFromHz(fromHz);
	}
}
<commit_msg>Lower audio resample quality<commit_after>#include "audio_filter_resample.h"
#include "halley/support/debug.h"

using namespace Halley;

AudioFilterResample::AudioFilterResample(std::shared_ptr<AudioSource> source, int fromHz, int toHz, AudioBufferPool& pool)
	: pool(pool)
	, source(std::move(source))
	, fromHz(fromHz)
	, toHz(toHz)
{
}

uint8_t AudioFilterResample::getNumberOfChannels() const
{
	return source->getNumberOfChannels();
}

bool AudioFilterResample::isReady() const
{
	return source->isReady();
}

bool AudioFilterResample::getAudioData(size_t numSamples, AudioMultiChannelSamples dstBuffers)
{
	const size_t nChannels = source->getNumberOfChannels();
	const size_t additionalPaddingSamples = 2;
	const size_t nLeftOver = leftoverSamples[0].n;
	const size_t samplesToGenerate = numSamples - nLeftOver;
	const size_t numSamplesSrc = samplesToGenerate * fromHz / toHz + additionalPaddingSamples;

	if (resamplers.empty()) {
		for (size_t i = 0; i < nChannels; ++i) {
			resamplers.push_back(std::make_unique<AudioResampler>(fromHz, toHz, 1, 0.0f));
		}
	}

	// Read upstream data
	auto srcBuffers = pool.getBuffers(nChannels, numSamplesSrc);
	auto srcs = srcBuffers.getSampleSpans();
	bool playing = source->getAudioData(numSamplesSrc, srcs);

	// Prepare temporary destination data
	auto tmpBuffer = pool.getBuffer(numSamples + 32); // Is this +32 needed?
	auto tmp = tmpBuffer.getSpan();

	// Resample
	for (size_t channel = 0; channel < nChannels; ++channel) {
		// First copy any leftovers
		Expects(leftoverSamples[channel].n == nLeftOver);
		for (size_t i = 0; i < nLeftOver; ++i) {
			tmp[i] = leftoverSamples[channel].samples[i];
		}

		auto result = resamplers[channel]->resample(srcs[channel].subspan(0, numSamplesSrc), tmp.subspan(nLeftOver), 0);
		Expects(result.nRead == numSamplesSrc);
		Expects(result.nWritten >= samplesToGenerate);

		// Store left overs
		size_t leftOver = result.nWritten + nLeftOver - numSamples;
		for (size_t i = 0; i < leftOver; ++i) {
			leftoverSamples[channel].samples[i] = tmp[i + numSamples];
		}
		leftoverSamples[channel].n = leftOver;

		// Copy to destination
		memcpy(dstBuffers[channel].data(), tmp.data(), numSamples * sizeof(AudioSample));
	}

	return playing;
}

size_t AudioFilterResample::getSamplesLeft() const
{
	return source->getSamplesLeft() * toHz / fromHz;
}

void AudioFilterResample::setFromHz(int fromHz)
{
	for (auto& r: resamplers) {
		r->setFromHz(fromHz);
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gl/GrGLInterface.h"
#include "gl/GrGLAssembleInterface.h"
#include "gl/GrGLUtil.h"

#include <EGL/egl.h>
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2.h>

static GrGLFuncPtr egl_get_gl_proc(void* ctx, const char name[]) {
    SkASSERT(nullptr == ctx);
    // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_get_all_proc_addresses.txt
    // eglGetProcAddress() is not guaranteed to support the querying of non-extension EGL functions.
    #define M(X) if (0 == strcmp(#X, name)) { return (GrGLFuncPtr) X; }
    M(eglGetCurrentDisplay);
    M(eglQueryString);
    M(glActiveTexture);
    M(glAttachShader);
    M(glBindAttribLocation);
    M(glBindBuffer);
    M(glBindFramebuffer);
    M(glBindRenderbuffer);
    M(glBindTexture);
    M(glBlendColor);
    M(glBlendEquation);
    M(glBlendFunc);
    M(glBufferData);
    M(glBufferSubData);
    M(glCheckFramebufferStatus);
    M(glClear);
    M(glClearColor);
    M(glClearStencil);
    M(glColorMask);
    M(glCompileShader);
    M(glCompressedTexImage2D);
    M(glCompressedTexSubImage2D);
    M(glCopyTexSubImage2D);
    M(glCreateProgram);
    M(glCreateShader);
    M(glCullFace);
    M(glDeleteBuffers);
    M(glDeleteFramebuffers);
    M(glDeleteProgram);
    M(glDeleteRenderbuffers);
    M(glDeleteShader);
    M(glDeleteTextures);
    M(glDepthMask);
    M(glDisable);
    M(glDisableVertexAttribArray);
    M(glDrawArrays);
    M(glDrawElements);
    M(glEnable);
    M(glEnableVertexAttribArray);
    M(glFinish);
    M(glFlush);
    M(glFramebufferRenderbuffer);
    M(glFramebufferTexture2D);
    M(glFrontFace);
    M(glGenBuffers);
    M(glGenFramebuffers);
    M(glGenRenderbuffers);
    M(glGenTextures);
    M(glGenerateMipmap);
    M(glGetBufferParameteriv);
    M(glGetError);
    M(glGetFramebufferAttachmentParameteriv);
    M(glGetIntegerv);
    M(glGetProgramInfoLog);
    M(glGetProgramiv);
    M(glGetRenderbufferParameteriv);
    M(glGetShaderInfoLog);
    M(glGetShaderPrecisionFormat);
    M(glGetShaderiv);
    M(glGetString);
    M(glGetUniformLocation);
    M(glIsTexture);
    M(glLineWidth);
    M(glLinkProgram);
    M(glPixelStorei);
    M(glReadPixels);
    M(glRenderbufferStorage);
    M(glScissor);
    M(glShaderSource);
    M(glStencilFunc);
    M(glStencilFuncSeparate);
    M(glStencilMask);
    M(glStencilMaskSeparate);
    M(glStencilOp);
    M(glStencilOpSeparate);
    M(glTexImage2D);
    M(glTexParameterf);
    M(glTexParameterfv);
    M(glTexParameteri);
    M(glTexParameteriv);
    M(glTexSubImage2D);
    M(glUniform1f);
    M(glUniform1fv);
    M(glUniform1i);
    M(glUniform1iv);
    M(glUniform2f);
    M(glUniform2fv);
    M(glUniform2i);
    M(glUniform2iv);
    M(glUniform3f);
    M(glUniform3fv);
    M(glUniform3i);
    M(glUniform3iv);
    M(glUniform4f);
    M(glUniform4fv);
    M(glUniform4i);
    M(glUniform4iv);
    M(glUniformMatrix2fv);
    M(glUniformMatrix3fv);
    M(glUniformMatrix4fv);
    M(glUseProgram);
    M(glVertexAttrib1f);
    M(glVertexAttrib2fv);
    M(glVertexAttrib3fv);
    M(glVertexAttrib4fv);
    M(glVertexAttribPointer);
    M(glViewport);
    #undef M
    return eglGetProcAddress(name);
}

sk_sp<const GrGLInterface> GrGLMakeNativeInterface() {
    return GrGLMakeAssembledInterface(nullptr, egl_get_gl_proc);
}

const GrGLInterface* GrGLCreateNativeInterface() { return GrGLMakeNativeInterface().release(); }
<commit_msg>Remove extra semi-colons<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gl/GrGLInterface.h"
#include "gl/GrGLAssembleInterface.h"
#include "gl/GrGLUtil.h"

#include <EGL/egl.h>
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2.h>

static GrGLFuncPtr egl_get_gl_proc(void* ctx, const char name[]) {
    SkASSERT(nullptr == ctx);
    // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_get_all_proc_addresses.txt
    // eglGetProcAddress() is not guaranteed to support the querying of non-extension EGL functions.
    #define M(X) if (0 == strcmp(#X, name)) { return (GrGLFuncPtr) X; }
    M(eglGetCurrentDisplay)
    M(eglQueryString)
    M(glActiveTexture)
    M(glAttachShader)
    M(glBindAttribLocation)
    M(glBindBuffer)
    M(glBindFramebuffer)
    M(glBindRenderbuffer)
    M(glBindTexture)
    M(glBlendColor)
    M(glBlendEquation)
    M(glBlendFunc)
    M(glBufferData)
    M(glBufferSubData)
    M(glCheckFramebufferStatus)
    M(glClear)
    M(glClearColor)
    M(glClearStencil)
    M(glColorMask)
    M(glCompileShader)
    M(glCompressedTexImage2D)
    M(glCompressedTexSubImage2D)
    M(glCopyTexSubImage2D)
    M(glCreateProgram)
    M(glCreateShader)
    M(glCullFace)
    M(glDeleteBuffers)
    M(glDeleteFramebuffers)
    M(glDeleteProgram)
    M(glDeleteRenderbuffers)
    M(glDeleteShader)
    M(glDeleteTextures)
    M(glDepthMask)
    M(glDisable)
    M(glDisableVertexAttribArray)
    M(glDrawArrays)
    M(glDrawElements)
    M(glEnable)
    M(glEnableVertexAttribArray)
    M(glFinish)
    M(glFlush)
    M(glFramebufferRenderbuffer)
    M(glFramebufferTexture2D)
    M(glFrontFace)
    M(glGenBuffers)
    M(glGenFramebuffers)
    M(glGenRenderbuffers)
    M(glGenTextures)
    M(glGenerateMipmap)
    M(glGetBufferParameteriv)
    M(glGetError)
    M(glGetFramebufferAttachmentParameteriv)
    M(glGetIntegerv)
    M(glGetProgramInfoLog)
    M(glGetProgramiv)
    M(glGetRenderbufferParameteriv)
    M(glGetShaderInfoLog)
    M(glGetShaderPrecisionFormat)
    M(glGetShaderiv)
    M(glGetString)
    M(glGetUniformLocation)
    M(glIsTexture)
    M(glLineWidth)
    M(glLinkProgram)
    M(glPixelStorei)
    M(glReadPixels)
    M(glRenderbufferStorage)
    M(glScissor)
    M(glShaderSource)
    M(glStencilFunc)
    M(glStencilFuncSeparate)
    M(glStencilMask)
    M(glStencilMaskSeparate)
    M(glStencilOp)
    M(glStencilOpSeparate)
    M(glTexImage2D)
    M(glTexParameterf)
    M(glTexParameterfv)
    M(glTexParameteri)
    M(glTexParameteriv)
    M(glTexSubImage2D)
    M(glUniform1f)
    M(glUniform1fv)
    M(glUniform1i)
    M(glUniform1iv)
    M(glUniform2f)
    M(glUniform2fv)
    M(glUniform2i)
    M(glUniform2iv)
    M(glUniform3f)
    M(glUniform3fv)
    M(glUniform3i)
    M(glUniform3iv)
    M(glUniform4f)
    M(glUniform4fv)
    M(glUniform4i)
    M(glUniform4iv)
    M(glUniformMatrix2fv)
    M(glUniformMatrix3fv)
    M(glUniformMatrix4fv)
    M(glUseProgram)
    M(glVertexAttrib1f)
    M(glVertexAttrib2fv)
    M(glVertexAttrib3fv)
    M(glVertexAttrib4fv)
    M(glVertexAttribPointer)
    M(glViewport)
    #undef M
    return eglGetProcAddress(name);
}

sk_sp<const GrGLInterface> GrGLMakeNativeInterface() {
    return GrGLMakeAssembledInterface(nullptr, egl_get_gl_proc);
}

const GrGLInterface* GrGLCreateNativeInterface() { return GrGLMakeNativeInterface().release(); }
<|endoftext|>


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

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>
#include <nuttx/arch.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include <debug.h>

#include <drivers/drv_pwm_output.h>
#include <drivers/drv_hrt.h>

#include <systemlib/mixer/mixer.h>

extern "C" {
//#define DEBUG
#include "px4io.h"
}

/*
 * Maximum interval in us before FMU signal is considered lost
 */
#define FMU_INPUT_DROP_LIMIT_US		200000

/* current servo arm/disarm state */
bool mixer_servos_armed = false;

/* selected control values and count for mixing */
static uint16_t *control_values;
static int control_count;

static int	mixer_callback(uintptr_t handle,
			       uint8_t control_group,
			       uint8_t control_index,
			       float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	bool should_arm;

	/* check that we are receiving fresh data from the FMU */
	if ((hrt_absolute_time() - system_state.fmu_data_received_time) > FMU_INPUT_DROP_LIMIT_US) {
		/* too many frames without FMU input, time to go to failsafe */
		system_state.mixer_manual_override = true;
		system_state.mixer_fmu_available = false;
		lib_lowprintf("RX timeout\n");
	}

	/*
	 * Decide which set of inputs we're using.
	 */

	/* this is for planes, where manual override makes sense */
	if(system_state.manual_override_ok) {
		/* if everything is ok */
		if (!system_state.mixer_manual_override && system_state.mixer_fmu_available) {
			/* we have recent control data from the FMU */
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];

		} else if (system_state.rc_channels > 0) {
			/* when override is on or the fmu is not available, but RC is present */
			control_count = system_state.rc_channels;
			control_values = &system_state.rc_channel_data[0];
		} else {
			/* we have no control input (no FMU, no RC) */

			// XXX builtin failsafe would activate here
			control_count = 0;
		}

	/* this is for multicopters, etc. where manual override does not make sense */
	} else {
		/* if the fmu is available whe are good */
		if(system_state.mixer_fmu_available) {
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];
		/* we better shut everything off */
		} else {
			control_count = 0;
		}
	}

	/*
	 * Run the mixers if we have any control data at all.
	 */
	if (control_count > 0) {
		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++) {
			if (i < mixed) {
				/* scale to servo output */
				system_state.servos[i] = (outputs[i] * 500.0f) + 1500;

			} else {
				/* set to zero to inhibit PWM pulse output */
				system_state.servos[i] = 0;
			}

			/*
			 * If we are armed, update the servo output.
			 */
			if (system_state.armed && system_state.arm_ok)
				up_pwm_servo_set(i, system_state.servos[i]);
		}
	}

	/*
	 * Decide whether the servos should be armed right now.
	 * A sufficient reason is armed state and either FMU or RC control inputs
	 */

	should_arm = system_state.armed && system_state.arm_ok && (control_count > 0);

	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	/* if the control index refers to an input that's not valid, we can't return it */
	if (control_index >= control_count)
		return -1;

	/* scale from current PWM units (1000-2000) to mixer input values */
	control = ((float)control_values[control_index] - 1500.0f) / 500.0f;

	return 0;
}

static char mixer_text[256];
static unsigned mixer_text_length = 0;

void
mixer_handle_text(const void *buffer, size_t length)
{

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;

	debug("mixer text %u", length);

	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		debug("reset");
		mixer_group.reset();
		mixer_text_length = 0;

		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		debug("append %d", length);

		/* check for overflow - this is really fatal */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text))
			return;

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';
		debug("buflen %u", mixer_text_length);

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		unsigned resid = mixer_text_length;
		mixer_group.load_from_buf(&mixer_text[0], resid);

		/* if anything was parsed */
		if (resid != mixer_text_length) {
			debug("used %u", mixer_text_length - resid);

			/* copy any leftover text to the base of the buffer for re-use */
			if (resid > 0)
				memcpy(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);

			mixer_text_length = resid;
		}

		break;
	}
}
<commit_msg>Code style fix<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2012 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>
#include <nuttx/arch.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include <debug.h>

#include <drivers/drv_pwm_output.h>
#include <drivers/drv_hrt.h>

#include <systemlib/mixer/mixer.h>

extern "C" {
//#define DEBUG
#include "px4io.h"
}

/*
 * Maximum interval in us before FMU signal is considered lost
 */
#define FMU_INPUT_DROP_LIMIT_US		200000

/* current servo arm/disarm state */
bool mixer_servos_armed = false;

/* selected control values and count for mixing */
static uint16_t *control_values;
static int control_count;

static int	mixer_callback(uintptr_t handle,
			       uint8_t control_group,
			       uint8_t control_index,
			       float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	bool should_arm;

	/* check that we are receiving fresh data from the FMU */
	if ((hrt_absolute_time() - system_state.fmu_data_received_time) > FMU_INPUT_DROP_LIMIT_US) {
		/* too many frames without FMU input, time to go to failsafe */
		system_state.mixer_manual_override = true;
		system_state.mixer_fmu_available = false;
		lib_lowprintf("RX timeout\n");
	}

	/*
	 * Decide which set of inputs we're using.
	 */

	/* this is for planes, where manual override makes sense */
	if (system_state.manual_override_ok) {
		/* if everything is ok */
		if (!system_state.mixer_manual_override && system_state.mixer_fmu_available) {
			/* we have recent control data from the FMU */
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];

		} else if (system_state.rc_channels > 0) {
			/* when override is on or the fmu is not available, but RC is present */
			control_count = system_state.rc_channels;
			control_values = &system_state.rc_channel_data[0];
		} else {
			/* we have no control input (no FMU, no RC) */

			// XXX builtin failsafe would activate here
			control_count = 0;
		}

	/* this is for multicopters, etc. where manual override does not make sense */
	} else {
		/* if the fmu is available whe are good */
		if (system_state.mixer_fmu_available) {
			control_count = PX4IO_CONTROL_CHANNELS;
			control_values = &system_state.fmu_channel_data[0];
		/* we better shut everything off */
		} else {
			control_count = 0;
		}
	}

	/*
	 * Run the mixers if we have any control data at all.
	 */
	if (control_count > 0) {
		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++) {
			if (i < mixed) {
				/* scale to servo output */
				system_state.servos[i] = (outputs[i] * 500.0f) + 1500;

			} else {
				/* set to zero to inhibit PWM pulse output */
				system_state.servos[i] = 0;
			}

			/*
			 * If we are armed, update the servo output.
			 */
			if (system_state.armed && system_state.arm_ok)
				up_pwm_servo_set(i, system_state.servos[i]);
		}
	}

	/*
	 * Decide whether the servos should be armed right now.
	 * A sufficient reason is armed state and either FMU or RC control inputs
	 */

	should_arm = system_state.armed && system_state.arm_ok && (control_count > 0);

	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	/* if the control index refers to an input that's not valid, we can't return it */
	if (control_index >= control_count)
		return -1;

	/* scale from current PWM units (1000-2000) to mixer input values */
	control = ((float)control_values[control_index] - 1500.0f) / 500.0f;

	return 0;
}

static char mixer_text[256];
static unsigned mixer_text_length = 0;

void
mixer_handle_text(const void *buffer, size_t length)
{

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;

	debug("mixer text %u", length);

	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		debug("reset");
		mixer_group.reset();
		mixer_text_length = 0;

		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		debug("append %d", length);

		/* check for overflow - this is really fatal */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text))
			return;

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';
		debug("buflen %u", mixer_text_length);

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		unsigned resid = mixer_text_length;
		mixer_group.load_from_buf(&mixer_text[0], resid);

		/* if anything was parsed */
		if (resid != mixer_text_length) {
			debug("used %u", mixer_text_length - resid);

			/* copy any leftover text to the base of the buffer for re-use */
			if (resid > 0)
				memcpy(&mixer_text[0], &mixer_text[mixer_text_length - resid], resid);

			mixer_text_length = resid;
		}

		break;
	}
}
<|endoftext|>


<commit_before>// $Id: reissCavFreeEnergyProcessor.C,v 1.8 2001/06/05 15:53:29 anker Exp $

#include <BALL/SOLVATION/reissCavFreeEnergyProcessor.h>
#include <BALL/STRUCTURE/numericalSAS.h>

using namespace std;

namespace BALL
{

	const char* ReissCavFreeEnergyProcessor::Option::VERBOSITY = "verbosity";
	const char* ReissCavFreeEnergyProcessor::Option::SOLVENT_NUMBER_DENSITY
		= "solvent_number_density";
	const char* ReissCavFreeEnergyProcessor::Option::PRESSURE = "pressure";
	const char* ReissCavFreeEnergyProcessor::Option::ABSOLUTE_TEMPERATURE
		= "absolute_temperature";
	const char* ReissCavFreeEnergyProcessor::Option::PROBE_RADIUS
		= "probe_radius";

	const int ReissCavFreeEnergyProcessor::Default::VERBOSITY = 0;
	const float ReissCavFreeEnergyProcessor::Default::SOLVENT_NUMBER_DENSITY
		= 3.33253e-2;
	const float ReissCavFreeEnergyProcessor::Default::PRESSURE = 1.01325e5;
	const float ReissCavFreeEnergyProcessor::Default::ABSOLUTE_TEMPERATURE
		= 298.0;
	const float ReissCavFreeEnergyProcessor::Default::PROBE_RADIUS = 1.385;

	ReissCavFreeEnergyProcessor::ReissCavFreeEnergyProcessor() throw()
		: EnergyProcessor()
	{
		setDefaultOptions();

		valid_ = true;
	}

	ReissCavFreeEnergyProcessor::ReissCavFreeEnergyProcessor
		(const ReissCavFreeEnergyProcessor& proc) throw()
		: EnergyProcessor(proc)
	{
	}

	ReissCavFreeEnergyProcessor::~ReissCavFreeEnergyProcessor() throw()
	{
		clear();

		valid_ = false;
	}

	void ReissCavFreeEnergyProcessor::clear() throw()
	{
		EnergyProcessor::clear();
		setDefaultOptions();

		valid_ = true;
	}

	bool ReissCavFreeEnergyProcessor::finish() throw()
	{

		// first check for user settings

		int verbosity = (int) options.getInteger(Option::VERBOSITY);
		// rho is the number density of the solvent (i. e. water) [1/m^3]
		double rho = options.getReal(Option::SOLVENT_NUMBER_DENSITY) * 1e30;
		// the pressure [ Pa ]
		double P = options.getReal(Option::PRESSURE);
		// the temperature [ K ]
		double T = options.getReal(Option::ABSOLUTE_TEMPERATURE);
		// the solvent radius [ A ]
		double solvent_radius = options.getReal(Option::PROBE_RADIUS);
		if (verbosity > 0)
		{
			Log.info() << "Using a probe radius of " << solvent_radius << " A" <<
				endl;
		}

		// now compute some constant terms (names as in Pierotti, Chem. Rev.
		// 76(6):717--726, 1976)

		double sigma1 = 2 * solvent_radius * 1e-10; // [ m ]
		double sigma1_2 = sigma1 * sigma1; // [ m^2 ]
		double sigma1_3 = sigma1 * sigma1 * sigma1; // [ m^3 ]
		double y = Constants::PI * sigma1_3 * (rho/6);	// [ 1 ]
		double y_frac = y/(1-y); // [ 1 ]
		double y_frac_2 = y_frac * y_frac; // [ 1 ]
		double NkT = Constants::AVOGADRO * Constants::BOLTZMANN * T; // [ J/mol ]
		double NpiP = Constants::AVOGADRO * Constants::PI * P; // [ ? ]

		if (verbosity > 0)
		{
			Log.info() << "y = " << y << endl;
			Log.info() << "y_frac = " << y_frac << endl;
		}

		HashMap<const Atom*,float> atom_areas;
		calculateSASAtomAreas(*fragment_, atom_areas, solvent_radius);

		// R is the sum of atom radius and probe radius [ m ]
		double R;
		// deltaGspher is the cavitatonal energy of a spherical solute [ J/mol ]
		double deltaGspher;
		// deltaGcav is the cavitatonal energy of the molecule [ J/mol ]
		double deltaGcav = 0;

		// now iterate over the atoms.

		HashMap<const Atom*,float>::Iterator it = atom_areas.begin();
		for (; +it; ++it)
		{
			R = it->first->getRadius() * 1e-10 + sigma1 / 2.0;
			deltaGspher =
				  NkT * (-log(1.0 - y) + 4.5 * y_frac_2) - (NpiP * sigma1_3 / 6.0)
				- (NkT * ((6.0 * y_frac + 18 * y_frac_2) / sigma1)
						+ (NpiP * sigma1_2)) * R
				+ (NkT * ((12.0 * y_frac + 18 * y_frac_2) / sigma1_2)
						- (2.0 * NpiP * sigma1)) * (R * R)
				+ 4.0 / 3.0 * NpiP * (R * R * R);
			deltaGcav += it->second * 1e-20 /
				( 4 * Constants::PI * R * R ) * deltaGspher;
		}
		// return energy in units of kJ/mol
		energy_ = deltaGcav/1000;
		return 1;
	}

	void ReissCavFreeEnergyProcessor::setDefaultOptions() throw()
	{
		options.setDefaultInteger(Option::VERBOSITY, Default::VERBOSITY);
		options.setDefaultReal(Option::SOLVENT_NUMBER_DENSITY,
				Default::SOLVENT_NUMBER_DENSITY);
		options.setDefaultReal(Option::PRESSURE, Default::PRESSURE);
		options.setDefaultReal(Option::ABSOLUTE_TEMPERATURE,
				Default::ABSOLUTE_TEMPERATURE);
		options.setDefaultReal(Option::PROBE_RADIUS, Default::PROBE_RADIUS);
	}

} // namespace BALL
<commit_msg>added operators = and ==<commit_after>// $Id: reissCavFreeEnergyProcessor.C,v 1.9 2001/09/11 10:00:05 aubertin Exp $

#include <BALL/SOLVATION/reissCavFreeEnergyProcessor.h>
#include <BALL/STRUCTURE/numericalSAS.h>

using namespace std;

namespace BALL
{

	const char* ReissCavFreeEnergyProcessor::Option::VERBOSITY = "verbosity";
	const char* ReissCavFreeEnergyProcessor::Option::SOLVENT_NUMBER_DENSITY
		= "solvent_number_density";
	const char* ReissCavFreeEnergyProcessor::Option::PRESSURE = "pressure";
	const char* ReissCavFreeEnergyProcessor::Option::ABSOLUTE_TEMPERATURE
		= "absolute_temperature";
	const char* ReissCavFreeEnergyProcessor::Option::PROBE_RADIUS
		= "probe_radius";

	const int ReissCavFreeEnergyProcessor::Default::VERBOSITY = 0;
	const float ReissCavFreeEnergyProcessor::Default::SOLVENT_NUMBER_DENSITY
		= 3.33253e-2;
	const float ReissCavFreeEnergyProcessor::Default::PRESSURE = 1.01325e5;
	const float ReissCavFreeEnergyProcessor::Default::ABSOLUTE_TEMPERATURE
		= 298.0;
	const float ReissCavFreeEnergyProcessor::Default::PROBE_RADIUS = 1.385;

	ReissCavFreeEnergyProcessor::ReissCavFreeEnergyProcessor() throw()
		: EnergyProcessor()
	{
		setDefaultOptions();

		valid_ = true;
	}

	ReissCavFreeEnergyProcessor::ReissCavFreeEnergyProcessor
		(const ReissCavFreeEnergyProcessor& proc) throw()
		: EnergyProcessor(proc)
	{
	}

	ReissCavFreeEnergyProcessor::~ReissCavFreeEnergyProcessor() throw()
	{
		clear();

		valid_ = false;
	}

	void ReissCavFreeEnergyProcessor::clear() throw()
	{
		EnergyProcessor::clear();
		setDefaultOptions();

		valid_ = true;
	}

        const ReissCavFreeEnergyProcessor& ReissCavFreeEnergyProcessor::operator = (const ReissCavFreeEnergyProcessor& proc) throw()
        {
	         valid_=proc.valid_;
                 energy_=proc.energy_;
                 fragment_=proc.fragment_;
                 return *this;
        }

        bool ReissCavFreeEnergyProcessor::operator == (const ReissCavFreeEnergyProcessor& proc) const throw()
        {
          bool result;
		if ((fragment_ == 0) && (proc.fragment_ == 0))
		{
			result = ((energy_ == proc.energy_) && (valid_ == proc.valid_));
		}
		else
		{
			if ((fragment_ == 0) || (proc.fragment_ == 0))
			{
				result = false;
			}
			else
			{
				result = ((*fragment_ == *proc.fragment_)
						&& (energy_ 	 == proc.energy_)
						&& (valid_ 	 == proc.valid_));
			}
		}
		return result;
	}

	bool ReissCavFreeEnergyProcessor::finish() throw()
	{

		// first check for user settings

		int verbosity = (int) options.getInteger(Option::VERBOSITY);
		// rho is the number density of the solvent (i. e. water) [1/m^3]
		double rho = options.getReal(Option::SOLVENT_NUMBER_DENSITY) * 1e30;
		// the pressure [ Pa ]
		double P = options.getReal(Option::PRESSURE);
		// the temperature [ K ]
		double T = options.getReal(Option::ABSOLUTE_TEMPERATURE);
		// the solvent radius [ A ]
		double solvent_radius = options.getReal(Option::PROBE_RADIUS);
		if (verbosity > 0)
		{
			Log.info() << "Using a probe radius of " << solvent_radius << " A" <<
				endl;
		}

		// now compute some constant terms (names as in Pierotti, Chem. Rev.
		// 76(6):717--726, 1976)

		double sigma1 = 2 * solvent_radius * 1e-10; // [ m ]
		double sigma1_2 = sigma1 * sigma1; // [ m^2 ]
		double sigma1_3 = sigma1 * sigma1 * sigma1; // [ m^3 ]
		double y = Constants::PI * sigma1_3 * (rho/6);	// [ 1 ]
		double y_frac = y/(1-y); // [ 1 ]
		double y_frac_2 = y_frac * y_frac; // [ 1 ]
		double NkT = Constants::AVOGADRO * Constants::BOLTZMANN * T; // [ J/mol ]
		double NpiP = Constants::AVOGADRO * Constants::PI * P; // [ ? ]

		if (verbosity > 0)
		{
			Log.info() << "y = " << y << endl;
			Log.info() << "y_frac = " << y_frac << endl;
		}

		HashMap<const Atom*,float> atom_areas;
		calculateSASAtomAreas(*fragment_, atom_areas, solvent_radius);

		// R is the sum of atom radius and probe radius [ m ]
		double R;
		// deltaGspher is the cavitatonal energy of a spherical solute [ J/mol ]
		double deltaGspher;
		// deltaGcav is the cavitatonal energy of the molecule [ J/mol ]
		double deltaGcav = 0;

		// now iterate over the atoms.

		HashMap<const Atom*,float>::Iterator it = atom_areas.begin();
		for (; +it; ++it)
		{
			R = it->first->getRadius() * 1e-10 + sigma1 / 2.0;
			deltaGspher =
				  NkT * (-log(1.0 - y) + 4.5 * y_frac_2) - (NpiP * sigma1_3 / 6.0)
				- (NkT * ((6.0 * y_frac + 18 * y_frac_2) / sigma1)
						+ (NpiP * sigma1_2)) * R
				+ (NkT * ((12.0 * y_frac + 18 * y_frac_2) / sigma1_2)
						- (2.0 * NpiP * sigma1)) * (R * R)
				+ 4.0 / 3.0 * NpiP * (R * R * R);
			deltaGcav += it->second * 1e-20 /
				( 4 * Constants::PI * R * R ) * deltaGspher;
		}
		// return energy in units of kJ/mol
		energy_ = deltaGcav/1000;
		return 1;
	}

	void ReissCavFreeEnergyProcessor::setDefaultOptions() throw()
	{
		options.setDefaultInteger(Option::VERBOSITY, Default::VERBOSITY);
		options.setDefaultReal(Option::SOLVENT_NUMBER_DENSITY,
				Default::SOLVENT_NUMBER_DENSITY);
		options.setDefaultReal(Option::PRESSURE, Default::PRESSURE);
		options.setDefaultReal(Option::ABSOLUTE_TEMPERATURE,
				Default::ABSOLUTE_TEMPERATURE);
		options.setDefaultReal(Option::PROBE_RADIUS, Default::PROBE_RADIUS);
	}

} // namespace BALL
<|endoftext|>


<commit_before>#include "core/global.h"

#include "DBStateServer.h"
#include "LoadingObject.h"

// RoleConfig
static ConfigVariable<channel_t> database_channel("database", INVALID_CHANNEL);

// RangesConfig
static ConfigVariable<uint32_t> range_min("min", INVALID_DO_ID);
static ConfigVariable<uint32_t> range_max("max", UINT32_MAX);

DBStateServer::DBStateServer(RoleConfig roleconfig) : StateServer(roleconfig),
	m_db_channel(database_channel.get_rval(m_roleconfig)), m_next_context(0)
{
	RangesConfig ranges = roleconfig["ranges"];
	for(auto it = ranges.begin(); it != ranges.end(); ++it)
	{
		channel_t min = range_min.get_rval(*it);
		channel_t max = range_max.get_rval(*it);
		MessageDirector::singleton.subscribe_range(this, min, max);
	}

	std::stringstream name;
	name << "DBSS(Database: " << m_db_channel << ")";
	m_log = new LogCategory("dbss", name.str());
}

DBStateServer::~DBStateServer()
{
	delete m_log;
}

void DBStateServer::handle_activate(DatagramIterator &dgi, bool has_other)
{
	uint32_t do_id = dgi.read_uint32();
	uint32_t parent_id = dgi.read_uint32();
	uint32_t zone_id = dgi.read_uint32();

	// Check object is not already active
	if(m_objs.find(do_id) != m_objs.end() || m_loading.find(do_id) != m_loading.end())
	{
		m_log->warning() << "Received activate for already-active object"
		                 << " - id:" << do_id << std::endl;
		return;
	}

	if(!has_other)
	{
		m_loading[do_id] = new LoadingObject(this, do_id, parent_id, zone_id);
	}
	else
	{
		uint16_t dc_id = dgi.read_uint16();

		// Check dclass is valid
		if(dc_id >= g_dcf->get_num_classes())
		{
			m_log->error() << "Received activate_other with unknown dclass"
		                 << " - id:" << dc_id << std::endl;
			return;
		}

		DCClass *dclass = g_dcf->get_class(dc_id);
		m_loading[do_id] = new LoadingObject(this, do_id, parent_id, zone_id, dclass, dgi);
	}
}

void DBStateServer::handle_datagram(Datagram &in_dg, DatagramIterator &dgi)
{
	channel_t sender = dgi.read_uint64();
	uint16_t msgtype = dgi.read_uint16();
	switch(msgtype)
	{
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS:
		{
			handle_activate(dgi, false);
			break;
		}
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS_OTHER:
		{
			handle_activate(dgi, true);
			break;
		}
		case DBSS_OBJECT_DELETE_DISK:
		{
			uint32_t do_id = dgi.read_uint32();
			auto obj_keyval = m_objs.find(do_id);
			if(obj_keyval != m_objs.end())
			{
				// TODO: Handle broadcast behavior
			}

			Datagram dg(m_db_channel, do_id, DBSERVER_OBJECT_DELETE);
			dg.add_uint32(do_id);
			send(dg);

			break;
		}
		case STATESERVER_OBJECT_GET_ALL:
		{
			uint32_t r_context = dgi.read_uint32();
			uint32_t r_do_id = dgi.read_uint32();

			// If object is active or loading, the Object or Loader will handle it
			if(m_objs.find(r_do_id) != m_objs.end() ||
			   m_loading.find(r_do_id) != m_loading.end())
			{
				break;
			}

			m_log->spam() << "Received GetAll for inactive object with id " << r_do_id
			              << ", sending query to database." << std::endl;

			// Get context for db query, and remember reply with it
			uint32_t db_context = m_next_context++;
			m_resp_context[db_context] = GetRecord(sender, r_context, r_do_id);

			// Send query to database
			Datagram dg(m_db_channel, r_do_id, DBSERVER_OBJECT_GET_ALL);
			dg.add_uint32(db_context);
			dg.add_uint32(r_do_id);
			send(dg);

			break;
		}
		case DBSERVER_OBJECT_GET_ALL_RESP:
		{
			uint32_t db_context = dgi.read_uint32();

			// Check context
			auto caller_keyval = m_resp_context.find(db_context);
			if(caller_keyval == m_resp_context.end())
			{
				break; // Not meant for me, handled by LoadingObject
			}
			GetRecord caller = caller_keyval->second;

			m_log->spam() << "Received GetAllResp from database"
			              " for object with id " << caller.do_id << std::endl;

			// Cleanup the context first, so it is removed if any exceptions occur
			m_resp_context.erase(db_context);

			// If object not found, just cleanup the context map
			if(dgi.read_uint8() != true)
			{
				break; // Object not found
			}

			// Read object class
			uint16_t dc_id = dgi.read_uint16();
			if(!dc_id)
			{
				m_log->error() << "Received object from database with unknown dclass"
				               << " - id:" << dc_id << std::endl;
				break;
			}
			DCClass* r_dclass = g_dcf->get_class(dc_id);

			// Get fields from database
			std::unordered_map<DCField*, std::vector<uint8_t>> required_fields;
			std::unordered_map<DCField*, std::vector<uint8_t>> ram_fields;
			if(!unpack_db_fields(dgi, r_dclass, required_fields, ram_fields))
			{
				m_log->error() << "Error while unpacking fields from database." << std::endl;
				break;
			}

			// Prepare SSGetAllResp
			Datagram dg(caller.sender, caller.do_id, STATESERVER_OBJECT_GET_ALL_RESP);
			dg.add_uint32(caller.do_id);
			dg.add_uint32(INVALID_DO_ID);
			dg.add_uint32(INVALID_ZONE);
			dg.add_uint16(r_dclass->get_number());

			// Add required fields to datagram
			int dcc_field_count = r_dclass->get_num_inherited_fields();
			for(int i = 0; i < dcc_field_count; ++i)
			{
				DCField *field = r_dclass->get_inherited_field(i);
				if(!field->as_molecular_field() && field->is_required())
				{
					auto req_it = required_fields.find(field);
					if(req_it != required_fields.end())
					{
						dg.add_data(req_it->second);
					}
					else
					{
						dg.add_data(field->get_default_value());
					}
				}
			}

			// Add ram fields to datagram
			dg.add_uint16(ram_fields.size());
			for(auto it = ram_fields.begin(); it != ram_fields.end(); ++it)
			{
				dg.add_uint16(it->first->get_number());
				dg.add_data(it->second);
			}

			// Send response back to caller
			send(dg);
		}
		default:
		{
			if(msgtype < STATESERVER_MSGTYPE_MIN || msgtype > DBSERVER_MSGTYPE_MAX)
			{
				m_log->warning() << "Received unknown message of type " << msgtype << std::endl;
			}
			else
			{
				m_log->spam() << "Ignoring stateserver or database message"
				              << " of type " << msgtype << std::endl;
			}
		}
	}
}

void DBStateServer::receive_object(DistributedObject* obj)
{
	m_objs[obj->get_id()] = obj;
}
void DBStateServer::discard_loader(uint32_t do_id)
{
	m_loading.erase(do_id);
}

bool unpack_db_fields(DatagramIterator &dgi, DCClass* dclass,
                      std::unordered_map<DCField*, std::vector<uint8_t>> &required,
                      std::unordered_map<DCField*, std::vector<uint8_t>> &ram)
{
	// Unload ram and required fields from database resp
	uint16_t db_field_count = dgi.read_uint16();
	for(uint16_t i = 0; i < db_field_count; ++i)
	{
		uint16_t field_id = dgi.read_uint16();
		DCField *field = dclass->get_field_by_index(field_id);
		if(!field)
		{
			return false;
		}
		if(field->is_ram())
		{
			dgi.unpack_field(field, ram[field]);
		}
		else if(field->is_required())
		{
			dgi.unpack_field(field, required[field]);
		}
		else
		{
			dgi.skip_field(field);
		}
	}

	return true;
}

RoleFactoryItem<DBStateServer> dbss_fact("dbss");
<commit_msg>Stateserver: Fix get_all for non-loaded objects (needs to have context)<commit_after>#include "core/global.h"

#include "DBStateServer.h"
#include "LoadingObject.h"

// RoleConfig
static ConfigVariable<channel_t> database_channel("database", INVALID_CHANNEL);

// RangesConfig
static ConfigVariable<uint32_t> range_min("min", INVALID_DO_ID);
static ConfigVariable<uint32_t> range_max("max", UINT32_MAX);

DBStateServer::DBStateServer(RoleConfig roleconfig) : StateServer(roleconfig),
	m_db_channel(database_channel.get_rval(m_roleconfig)), m_next_context(0)
{
	RangesConfig ranges = roleconfig["ranges"];
	for(auto it = ranges.begin(); it != ranges.end(); ++it)
	{
		channel_t min = range_min.get_rval(*it);
		channel_t max = range_max.get_rval(*it);
		MessageDirector::singleton.subscribe_range(this, min, max);
	}

	std::stringstream name;
	name << "DBSS(Database: " << m_db_channel << ")";
	m_log = new LogCategory("dbss", name.str());
}

DBStateServer::~DBStateServer()
{
	delete m_log;
}

void DBStateServer::handle_activate(DatagramIterator &dgi, bool has_other)
{
	uint32_t do_id = dgi.read_uint32();
	uint32_t parent_id = dgi.read_uint32();
	uint32_t zone_id = dgi.read_uint32();

	// Check object is not already active
	if(m_objs.find(do_id) != m_objs.end() || m_loading.find(do_id) != m_loading.end())
	{
		m_log->warning() << "Received activate for already-active object"
		                 << " - id:" << do_id << std::endl;
		return;
	}

	if(!has_other)
	{
		m_loading[do_id] = new LoadingObject(this, do_id, parent_id, zone_id);
	}
	else
	{
		uint16_t dc_id = dgi.read_uint16();

		// Check dclass is valid
		if(dc_id >= g_dcf->get_num_classes())
		{
			m_log->error() << "Received activate_other with unknown dclass"
		                 << " - id:" << dc_id << std::endl;
			return;
		}

		DCClass *dclass = g_dcf->get_class(dc_id);
		m_loading[do_id] = new LoadingObject(this, do_id, parent_id, zone_id, dclass, dgi);
	}
}

void DBStateServer::handle_datagram(Datagram &in_dg, DatagramIterator &dgi)
{
	channel_t sender = dgi.read_uint64();
	uint16_t msgtype = dgi.read_uint16();
	switch(msgtype)
	{
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS:
		{
			handle_activate(dgi, false);
			break;
		}
		case DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS_OTHER:
		{
			handle_activate(dgi, true);
			break;
		}
		case DBSS_OBJECT_DELETE_DISK:
		{
			uint32_t do_id = dgi.read_uint32();
			auto obj_keyval = m_objs.find(do_id);
			if(obj_keyval != m_objs.end())
			{
				// TODO: Handle broadcast behavior
			}

			Datagram dg(m_db_channel, do_id, DBSERVER_OBJECT_DELETE);
			dg.add_uint32(do_id);
			send(dg);

			break;
		}
		case STATESERVER_OBJECT_GET_ALL:
		{
			uint32_t r_context = dgi.read_uint32();
			uint32_t r_do_id = dgi.read_uint32();

			// If object is active or loading, the Object or Loader will handle it
			if(m_objs.find(r_do_id) != m_objs.end() ||
			   m_loading.find(r_do_id) != m_loading.end())
			{
				break;
			}

			m_log->spam() << "Received GetAll for inactive object with id " << r_do_id
			              << ", sending query to database." << std::endl;

			// Get context for db query, and remember reply with it
			uint32_t db_context = m_next_context++;
			m_resp_context[db_context] = GetRecord(sender, r_context, r_do_id);

			// Send query to database
			Datagram dg(m_db_channel, r_do_id, DBSERVER_OBJECT_GET_ALL);
			dg.add_uint32(db_context);
			dg.add_uint32(r_do_id);
			send(dg);

			break;
		}
		case DBSERVER_OBJECT_GET_ALL_RESP:
		{
			uint32_t db_context = dgi.read_uint32();

			// Check context
			auto caller_keyval = m_resp_context.find(db_context);
			if(caller_keyval == m_resp_context.end())
			{
				break; // Not meant for me, handled by LoadingObject
			}
			GetRecord caller = caller_keyval->second;

			m_log->spam() << "Received GetAllResp from database"
			              " for object with id " << caller.do_id << std::endl;

			// Cleanup the context first, so it is removed if any exceptions occur
			m_resp_context.erase(db_context);

			// If object not found, just cleanup the context map
			if(dgi.read_uint8() != true)
			{
				break; // Object not found
			}

			// Read object class
			uint16_t dc_id = dgi.read_uint16();
			if(!dc_id)
			{
				m_log->error() << "Received object from database with unknown dclass"
				               << " - id:" << dc_id << std::endl;
				break;
			}
			DCClass* r_dclass = g_dcf->get_class(dc_id);

			// Get fields from database
			std::unordered_map<DCField*, std::vector<uint8_t>> required_fields;
			std::unordered_map<DCField*, std::vector<uint8_t>> ram_fields;
			if(!unpack_db_fields(dgi, r_dclass, required_fields, ram_fields))
			{
				m_log->error() << "Error while unpacking fields from database." << std::endl;
				break;
			}

			// Prepare SSGetAllResp
			Datagram dg(caller.sender, caller.do_id, STATESERVER_OBJECT_GET_ALL_RESP);
			dg.add_uint32(caller.context);
			dg.add_uint32(caller.do_id);
			dg.add_uint32(INVALID_DO_ID);
			dg.add_uint32(INVALID_ZONE);
			dg.add_uint16(r_dclass->get_number());

			// Add required fields to datagram
			int dcc_field_count = r_dclass->get_num_inherited_fields();
			for(int i = 0; i < dcc_field_count; ++i)
			{
				DCField *field = r_dclass->get_inherited_field(i);
				if(!field->as_molecular_field() && field->is_required())
				{
					auto req_it = required_fields.find(field);
					if(req_it != required_fields.end())
					{
						dg.add_data(req_it->second);
					}
					else
					{
						dg.add_data(field->get_default_value());
					}
				}
			}

			// Add ram fields to datagram
			dg.add_uint16(ram_fields.size());
			for(auto it = ram_fields.begin(); it != ram_fields.end(); ++it)
			{
				dg.add_uint16(it->first->get_number());
				dg.add_data(it->second);
			}

			// Send response back to caller
			send(dg);
		}
		default:
		{
			if(msgtype < STATESERVER_MSGTYPE_MIN || msgtype > DBSERVER_MSGTYPE_MAX)
			{
				m_log->warning() << "Received unknown message of type " << msgtype << std::endl;
			}
			else
			{
				m_log->spam() << "Ignoring stateserver or database message"
				              << " of type " << msgtype << std::endl;
			}
		}
	}
}

void DBStateServer::receive_object(DistributedObject* obj)
{
	m_objs[obj->get_id()] = obj;
}
void DBStateServer::discard_loader(uint32_t do_id)
{
	m_loading.erase(do_id);
}

bool unpack_db_fields(DatagramIterator &dgi, DCClass* dclass,
                      std::unordered_map<DCField*, std::vector<uint8_t>> &required,
                      std::unordered_map<DCField*, std::vector<uint8_t>> &ram)
{
	// Unload ram and required fields from database resp
	uint16_t db_field_count = dgi.read_uint16();
	for(uint16_t i = 0; i < db_field_count; ++i)
	{
		uint16_t field_id = dgi.read_uint16();
		DCField *field = dclass->get_field_by_index(field_id);
		if(!field)
		{
			return false;
		}
		if(field->is_ram())
		{
			dgi.unpack_field(field, ram[field]);
		}
		else if(field->is_required())
		{
			dgi.unpack_field(field, required[field]);
		}
		else
		{
			dgi.skip_field(field);
		}
	}

	return true;
}

RoleFactoryItem<DBStateServer> dbss_fact("dbss");
<|endoftext|>


<commit_before>#include "GUI_TFT.h"

Guitft::~Guitft(){

}

void Guitft::fillRectangle(uint16_t poX, uint16_t poY, uint16_t length, uint16_t width, uint16_t color)
{
	this->fillRect(poX,poY,length,width,color);
}

/*
 * Implement a drawRectangle function
 */
void Guitft::drawRectangle(uint16_t poX, uint16_t poY, uint16_t length, uint16_t width,uint16_t color)
{
	drawFastHLine(poX,poY,length,color);
	drawFastHLine(poX, poY+width, length, color);
	drawFastVLine(poX, poY, width,color);
	drawFastVLine(poX+length,poY,width,color);
}

/*
 * Wrapper for drawing strings on the canvas
 */
void Guitft::drawString(char* string,uint16_t poX, uint16_t poY,uint16_t size,uint16_t fgcolor){
	setCursor(poX,poY);
	setTextSize(size);
	setTextColor(fgcolor);
	print(string);
}

/*
 * Wrapper method for drawing vertical lines
 */
void Guitft::drawVerticalLine(uint16_t poX, uint16_t poY,uint16_t length,uint16_t color){
	drawFastVLine(poX,poY,length,color);
}

/*
 * Wrapper method for drawing horizontal lines
 */
void Guitft::drawHorizontalLine(uint16_t poX, uint16_t poY,uint16_t length,uint16_t color){
	drawFastHLine(poX,poY,length,color);
}

/*
 * Wrapper method for drawing numbers
 */
uint8_t Guitft::drawNumber(long long_num,uint16_t poX, uint16_t poY,uint16_t size,uint16_t fgcolor){
	setCursor(poX,poY);
	setTextSize(size);
	setTextColor(fgcolor);
	print(long_num);
}

// Needed to declare in GUI_TFT.h as extern
// and instance it here
// to avoid compiler issues with redeclarations
Guitft Tft = Guitft(5, 6, -1); // Use hardware SPI
<commit_msg>Fixed a fundamental bug in the GUI_TFT.cpp drawRectangle routine, by using the inherited method.<commit_after>#include "GUI_TFT.h"

Guitft::~Guitft(){

}

void Guitft::fillRectangle(uint16_t poX, uint16_t poY, uint16_t length, uint16_t width, uint16_t color)
{
	this->fillRect(poX,poY,length,width,color);
}

/*
 * Implement a drawRectangle function
 */
void Guitft::drawRectangle(uint16_t poX, uint16_t poY, uint16_t length, uint16_t width,uint16_t color)
{
	this->drawRect(poX,poY,length,width,color);

	//drawFastHLine(poX,poY,length,color);
	//drawFastHLine(poX, poY+width, length, color);
	//drawFastVLine(poX, poY, width,color);
	//drawFastVLine(poX+length,poY,width,color);
}

/*
 * Wrapper for drawing strings on the canvas
 */
void Guitft::drawString(char* string,uint16_t poX, uint16_t poY,uint16_t size,uint16_t fgcolor){
	setCursor(poX,poY);
	setTextSize(size);
	setTextColor(fgcolor);
	print(string);
}

/*
 * Wrapper method for drawing vertical lines
 */
void Guitft::drawVerticalLine(uint16_t poX, uint16_t poY,uint16_t length,uint16_t color){
	drawFastVLine(poX,poY,length,color);
}

/*
 * Wrapper method for drawing horizontal lines
 */
void Guitft::drawHorizontalLine(uint16_t poX, uint16_t poY,uint16_t length,uint16_t color){
	drawFastHLine(poX,poY,length,color);
}

/*
 * Wrapper method for drawing numbers
 */
uint8_t Guitft::drawNumber(long long_num,uint16_t poX, uint16_t poY,uint16_t size,uint16_t fgcolor){
	setCursor(poX,poY);
	setTextSize(size);
	setTextColor(fgcolor);
	print(long_num);
}

// Needed to declare in GUI_TFT.h as extern
// and instance it here
// to avoid compiler issues with redeclarations
Guitft Tft = Guitft(5, 6, -1); // Use hardware SPI
<|endoftext|>