<commit_before>// Virvo - Virtual Reality Volume Rendering
// Contact: Stefan Zellmann, zellmans@uni-koeln.de
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

#include "vvglew.h"
#include "vvgltools.h"
#include "vvoffscreenbuffer.h"

vvOffscreenBuffer::vvOffscreenBuffer(const float scale = 1.0f, const BufferPrecision precision = VV_BYTE)
  : vvRenderTarget()
{
  const vvGLTools::Viewport v = vvGLTools::getViewport();
  init(v[2], v[3], scale, precision);
}

vvOffscreenBuffer::vvOffscreenBuffer(const int w, const int h, const float scale, const BufferPrecision precision)
  : vvRenderTarget()
{
  init(w, h, scale, precision);
}

vvOffscreenBuffer::~vvOffscreenBuffer()
{
  delete[] _pixels;
  delete _scaledDepthBuffer;
  delete[] _depthPixelsF;
  delete[] _depthPixelsNV;
  freeGLResources();
}

void vvOffscreenBuffer::initForRender()
{
  const vvGLTools::Viewport v = vvGLTools::getViewport();

  if (_preserveDepthBuffer)
  {
    storeDepthBuffer(getScaled(v[2]), getScaled(v[3]));
  }

  resize(v[2], v[3]);

  glPushAttrib(GL_VIEWPORT_BIT);

  // If width and height haven't changed, resize will return immediatly.
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
  glViewport(0, 0, _bufferWidth, _bufferHeight);
  glBindTexture(GL_TEXTURE_2D, 0);
}

void vvOffscreenBuffer::writeBack(const int w, const int h)
{
  if (_preserveDepthBuffer)
  {
    storeColorBuffer();
  }

  vvGLTools::Viewport viewport;
  if ((w == -1) || (h == -1))
  {
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    glPopAttrib();

    glGetIntegerv(GL_VIEWPORT, viewport.values);
  }
  else
  {
    viewport.values[2] = w;
    viewport.values[3] = h;
  }

  if (_preserveDepthBuffer)
  {
    renderToViewAlignedQuad();
  }
  else
  {
    glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, _frameBufferObject);
    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
    glBlitFramebufferEXT(0, 0, _bufferWidth, _bufferHeight,
                         0, 0, viewport[2], viewport[3],
                         GL_COLOR_BUFFER_BIT, GL_LINEAR);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  }
}

void vvOffscreenBuffer::resize(const int w, const int h)
{
  if ((_viewportWidth == w) && (_viewportHeight == h) && (!_updatePosted))
  {
    return;
  }

  _viewportWidth = w;
  _viewportHeight = h;

  doScale();

  if (!_initialized)
  {
    initFbo();
  }
  else
  {
    genColorAndDepthTextures();
  }

  _updatePosted = false;
}

void vvOffscreenBuffer::clearBuffer()
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  if (_preserveDepthBuffer)
  {
    writeBackDepthBuffer();
  }
}

void vvOffscreenBuffer::bindFramebuffer() const
{
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
}

void vvOffscreenBuffer::unbindFramebuffer() const
{
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void vvOffscreenBuffer::bindTexture() const
{
  glBindTexture(GL_TEXTURE_2D, _textureId);
}

void vvOffscreenBuffer::setScale(const float scale)
{
  _scale = scale;
  update();
}

void vvOffscreenBuffer::setPreserveDepthBuffer(const bool preserveDepthBuffer)
{
  _preserveDepthBuffer = preserveDepthBuffer;
}

void vvOffscreenBuffer::setUseNVDepthStencil(const bool useNVDepthStencil)
{
  _useNVDepthStencil = useNVDepthStencil;
}

void vvOffscreenBuffer::setPrecision(const BufferPrecision& precision)
{
  _precision = precision;
  update();
}

void vvOffscreenBuffer::setInterpolation(const bool interpolation)
{
  _interpolation = interpolation;
  update();
}

int vvOffscreenBuffer::getBufferWidth() const
{
  return _bufferWidth;
}

int vvOffscreenBuffer::getBufferHeight() const
{
  return _bufferHeight;
}

float vvOffscreenBuffer::getScale() const
{
  return _scale;
}

bool vvOffscreenBuffer::getPreserveFramebuffer() const
{
  return _preserveDepthBuffer;
}

bool vvOffscreenBuffer::getUseNVDepthStencil() const
{
  return _useNVDepthStencil;
}

BufferPrecision vvOffscreenBuffer::getPrecision() const
{
  return _precision;
}

bool vvOffscreenBuffer::getInterpolation() const
{
  return _interpolation;
}

void vvOffscreenBuffer::init(const int w, const int h,
                             const float scale, const BufferPrecision precision)
{
  glewInit();
  _type = VV_OFFSCREEN_BUFFER;
  _viewportWidth = w;
  _viewportHeight = h;
  _scale = scale;
  _preserveDepthBuffer = false;
  _useNVDepthStencil = false;
  _precision = precision;
  _interpolation = true;
  glGenTextures(1, &_textureId);
  glGenTextures(1, &_depthTextureId);
  _initialized = false;
  _updatePosted = true;
  _pixels = NULL;
  _scaledDepthBuffer = NULL;
  _depthPixelsF = NULL;
  _depthPixelsNV = NULL;
  resize(_viewportWidth, _viewportHeight);
}

void vvOffscreenBuffer::initFbo()
{
  freeGLResources();

  glGenFramebuffersEXT(1, &_frameBufferObject);
  genColorAndDepthTextures();

  _initialized = true;
}

void vvOffscreenBuffer::genColorAndDepthTextures()
{
  glDeleteRenderbuffersEXT(1, &_depthBuffer);
  glDeleteTextures(1, &_colorBuffer);

  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
  glGenRenderbuffersEXT(1, &_depthBuffer);
  glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _depthBuffer);
  glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT32, _bufferWidth, _bufferHeight);
  glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
                               GL_RENDERBUFFER_EXT, _depthBuffer);

  glGenTextures(1, &_colorBuffer);
  glBindTexture(GL_TEXTURE_2D, _colorBuffer);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  switch (_precision)
  {
  case VV_BYTE:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    break;
  case VV_SHORT:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_SHORT, NULL);
    break;
  case VV_FLOAT:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_FLOAT, NULL);
    break;
  }
  glViewport(0, 0, _bufferWidth, _bufferHeight);

  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
                            _colorBuffer, 0);

  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void vvOffscreenBuffer::freeGLResources() const
{
  glDeleteTextures(1, &_colorBuffer);
  glDeleteRenderbuffersEXT(1, &_depthBuffer);
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  glDeleteFramebuffersEXT(1, &_frameBufferObject);
}

int vvOffscreenBuffer::getScaled(const int v) const
{
  return (int)((float)v * _scale);
}

void vvOffscreenBuffer::doScale()
{
  _bufferWidth = getScaled(_viewportWidth);
  _bufferHeight = getScaled(_viewportHeight);
}

void vvOffscreenBuffer::update()
{
  // After the next render step, the resize() method won't return although size didn't change.
  _updatePosted = true;
}

void vvOffscreenBuffer::storeColorBuffer()
{
  delete[] _pixels;
  _pixels = new unsigned char[_bufferWidth * _bufferHeight * 4];
  glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
}

void vvOffscreenBuffer::storeDepthBuffer(const int scaledWidth, const int scaledHeight)
{
  glFinish();

  delete _scaledDepthBuffer;
  _scaledDepthBuffer = new vvOffscreenBuffer(scaledWidth, scaledHeight, 1.0f, _precision);

  glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
  glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _scaledDepthBuffer->_frameBufferObject);
  glBlitFramebufferEXT(0, 0, _viewportWidth, _viewportHeight,
                       0, 0, _scaledDepthBuffer->_bufferWidth, _scaledDepthBuffer->_bufferHeight,
                       GL_DEPTH_BUFFER_BIT, GL_NEAREST);
  _scaledDepthBuffer->bindFramebuffer();

  delete[] _depthPixelsNV;
  delete[] _depthPixelsF;

  if (_useNVDepthStencil)
  {
    _depthPixelsNV = new GLuint[_bufferWidth * _bufferHeight];
    glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_DEPTH_STENCIL_NV, GL_UNSIGNED_INT_24_8_NV, _depthPixelsNV);
  }
  else
  {
    _depthPixelsF = new float[_bufferWidth * _bufferHeight];
    glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_DEPTH_COMPONENT, GL_FLOAT, _depthPixelsF);
  }
}

void vvOffscreenBuffer::renderToViewAlignedQuad() const
{
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();

  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT
               | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_TRANSFORM_BIT);

  glDisable(GL_CULL_FACE);
  glDisable(GL_LIGHTING);
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_COLOR_MATERIAL);
  glEnable(GL_BLEND);
  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

  glEnable(GL_TEXTURE_2D);
  bindTexture();
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (_interpolation) ? GL_LINEAR : GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (_interpolation) ? GL_LINEAR : GL_NEAREST);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _bufferWidth, _bufferHeight,
               0, GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
  vvGLTools::drawViewAlignedQuad();
  glDeleteTextures(1, &_textureId);

  glPopAttrib();

  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
}

void vvOffscreenBuffer::writeBackDepthBuffer() const
{
  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);

  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  glDepthMask(GL_TRUE);
  glDepthFunc(GL_ALWAYS);
  glEnable(GL_DEPTH_TEST);

  if (_useNVDepthStencil)
  {
    glDrawPixels(_bufferWidth, _bufferHeight, GL_DEPTH_STENCIL_NV, GL_UNSIGNED_INT_24_8_NV, _depthPixelsNV);
  }
  else
  {
    glDrawPixels(_bufferWidth, _bufferHeight, GL_DEPTH_COMPONENT, GL_FLOAT, _depthPixelsF);
  }

  glPopClientAttrib();
  glPopAttrib();
}
<commit_msg>Only bind depth texture to fbo if depth buffer has to be preserved<commit_after>// Virvo - Virtual Reality Volume Rendering
// Contact: Stefan Zellmann, zellmans@uni-koeln.de
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

#include "vvglew.h"
#include "vvgltools.h"
#include "vvoffscreenbuffer.h"

vvOffscreenBuffer::vvOffscreenBuffer(const float scale = 1.0f, const BufferPrecision precision = VV_BYTE)
  : vvRenderTarget()
{
  const vvGLTools::Viewport v = vvGLTools::getViewport();
  init(v[2], v[3], scale, precision);
}

vvOffscreenBuffer::vvOffscreenBuffer(const int w, const int h, const float scale, const BufferPrecision precision)
  : vvRenderTarget()
{
  init(w, h, scale, precision);
}

vvOffscreenBuffer::~vvOffscreenBuffer()
{
  delete[] _pixels;
  delete _scaledDepthBuffer;
  delete[] _depthPixelsF;
  delete[] _depthPixelsNV;
  freeGLResources();
}

void vvOffscreenBuffer::initForRender()
{
  const vvGLTools::Viewport v = vvGLTools::getViewport();

  if (_preserveDepthBuffer)
  {
    storeDepthBuffer(getScaled(v[2]), getScaled(v[3]));
  }

  resize(v[2], v[3]);

  glPushAttrib(GL_VIEWPORT_BIT);

  // If width and height haven't changed, resize will return immediatly.
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
  glViewport(0, 0, _bufferWidth, _bufferHeight);
  glBindTexture(GL_TEXTURE_2D, 0);
}

void vvOffscreenBuffer::writeBack(const int w, const int h)
{
  if (_preserveDepthBuffer)
  {
    storeColorBuffer();
  }

  vvGLTools::Viewport viewport;
  if ((w == -1) || (h == -1))
  {
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    glPopAttrib();

    glGetIntegerv(GL_VIEWPORT, viewport.values);
  }
  else
  {
    viewport.values[2] = w;
    viewport.values[3] = h;
  }

  if (_preserveDepthBuffer)
  {
    renderToViewAlignedQuad();
  }
  else
  {
    glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, _frameBufferObject);
    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
    glBlitFramebufferEXT(0, 0, _bufferWidth, _bufferHeight,
                         0, 0, viewport[2], viewport[3],
                         GL_COLOR_BUFFER_BIT, GL_LINEAR);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  }
}

void vvOffscreenBuffer::resize(const int w, const int h)
{
  if ((_viewportWidth == w) && (_viewportHeight == h) && (!_updatePosted))
  {
    return;
  }

  _viewportWidth = w;
  _viewportHeight = h;

  doScale();

  if (!_initialized)
  {
    initFbo();
  }
  else
  {
    genColorAndDepthTextures();
  }

  _updatePosted = false;
}

void vvOffscreenBuffer::clearBuffer()
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  if (_preserveDepthBuffer)
  {
    writeBackDepthBuffer();
  }
}

void vvOffscreenBuffer::bindFramebuffer() const
{
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
}

void vvOffscreenBuffer::unbindFramebuffer() const
{
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void vvOffscreenBuffer::bindTexture() const
{
  glBindTexture(GL_TEXTURE_2D, _textureId);
}

void vvOffscreenBuffer::setScale(const float scale)
{
  _scale = scale;
  update();
}

void vvOffscreenBuffer::setPreserveDepthBuffer(const bool preserveDepthBuffer)
{
  _preserveDepthBuffer = preserveDepthBuffer;
}

void vvOffscreenBuffer::setUseNVDepthStencil(const bool useNVDepthStencil)
{
  _useNVDepthStencil = useNVDepthStencil;
}

void vvOffscreenBuffer::setPrecision(const BufferPrecision& precision)
{
  _precision = precision;
  update();
}

void vvOffscreenBuffer::setInterpolation(const bool interpolation)
{
  _interpolation = interpolation;
  update();
}

int vvOffscreenBuffer::getBufferWidth() const
{
  return _bufferWidth;
}

int vvOffscreenBuffer::getBufferHeight() const
{
  return _bufferHeight;
}

float vvOffscreenBuffer::getScale() const
{
  return _scale;
}

bool vvOffscreenBuffer::getPreserveFramebuffer() const
{
  return _preserveDepthBuffer;
}

bool vvOffscreenBuffer::getUseNVDepthStencil() const
{
  return _useNVDepthStencil;
}

BufferPrecision vvOffscreenBuffer::getPrecision() const
{
  return _precision;
}

bool vvOffscreenBuffer::getInterpolation() const
{
  return _interpolation;
}

void vvOffscreenBuffer::init(const int w, const int h,
                             const float scale, const BufferPrecision precision)
{
  glewInit();
  _type = VV_OFFSCREEN_BUFFER;
  _viewportWidth = w;
  _viewportHeight = h;
  _scale = scale;
  _preserveDepthBuffer = false;
  _useNVDepthStencil = false;
  _precision = precision;
  _interpolation = true;
  glGenTextures(1, &_textureId);
  glGenTextures(1, &_depthTextureId);
  _initialized = false;
  _updatePosted = true;
  _pixels = NULL;
  _scaledDepthBuffer = NULL;
  _depthPixelsF = NULL;
  _depthPixelsNV = NULL;
  resize(_viewportWidth, _viewportHeight);
}

void vvOffscreenBuffer::initFbo()
{
  freeGLResources();

  glGenFramebuffersEXT(1, &_frameBufferObject);
  genColorAndDepthTextures();

  _initialized = true;
}

void vvOffscreenBuffer::genColorAndDepthTextures()
{
  glDeleteTextures(1, &_colorBuffer);

  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _frameBufferObject);
  if (_preserveDepthBuffer)
  {
    glDeleteRenderbuffersEXT(1, &_depthBuffer);
    glGenRenderbuffersEXT(1, &_depthBuffer);
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _depthBuffer);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT32, _bufferWidth, _bufferHeight);
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
                                 GL_RENDERBUFFER_EXT, _depthBuffer);
  }

  glGenTextures(1, &_colorBuffer);
  glBindTexture(GL_TEXTURE_2D, _colorBuffer);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  switch (_precision)
  {
  case VV_BYTE:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    break;
  case VV_SHORT:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_SHORT, NULL);
    break;
  case VV_FLOAT:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, _bufferWidth, _bufferHeight, 0, GL_RGBA, GL_FLOAT, NULL);
    break;
  }
  glViewport(0, 0, _bufferWidth, _bufferHeight);

  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
                            _colorBuffer, 0);

  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

void vvOffscreenBuffer::freeGLResources() const
{
  glDeleteTextures(1, &_colorBuffer);
  if (_preserveDepthBuffer)
  {
    glDeleteRenderbuffersEXT(1, &_depthBuffer);
  }
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  glDeleteFramebuffersEXT(1, &_frameBufferObject);
}

int vvOffscreenBuffer::getScaled(const int v) const
{
  return (int)((float)v * _scale);
}

void vvOffscreenBuffer::doScale()
{
  _bufferWidth = getScaled(_viewportWidth);
  _bufferHeight = getScaled(_viewportHeight);
}

void vvOffscreenBuffer::update()
{
  // After the next render step, the resize() method won't return although size didn't change.
  _updatePosted = true;
}

void vvOffscreenBuffer::storeColorBuffer()
{
  delete[] _pixels;
  _pixels = new unsigned char[_bufferWidth * _bufferHeight * 4];
  glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
}

void vvOffscreenBuffer::storeDepthBuffer(const int scaledWidth, const int scaledHeight)
{
  glFinish();

  delete _scaledDepthBuffer;
  _scaledDepthBuffer = new vvOffscreenBuffer(scaledWidth, scaledHeight, 1.0f, _precision);

  glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
  glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _scaledDepthBuffer->_frameBufferObject);
  glBlitFramebufferEXT(0, 0, _viewportWidth, _viewportHeight,
                       0, 0, _scaledDepthBuffer->_bufferWidth, _scaledDepthBuffer->_bufferHeight,
                       GL_DEPTH_BUFFER_BIT, GL_NEAREST);
  _scaledDepthBuffer->bindFramebuffer();

  delete[] _depthPixelsNV;
  delete[] _depthPixelsF;

  if (_useNVDepthStencil)
  {
    _depthPixelsNV = new GLuint[_bufferWidth * _bufferHeight];
    glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_DEPTH_STENCIL_NV, GL_UNSIGNED_INT_24_8_NV, _depthPixelsNV);
  }
  else
  {
    _depthPixelsF = new float[_bufferWidth * _bufferHeight];
    glReadPixels(0, 0, _bufferWidth, _bufferHeight, GL_DEPTH_COMPONENT, GL_FLOAT, _depthPixelsF);
  }
}

void vvOffscreenBuffer::renderToViewAlignedQuad() const
{
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();

  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT
               | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_TRANSFORM_BIT);

  glDisable(GL_CULL_FACE);
  glDisable(GL_LIGHTING);
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_COLOR_MATERIAL);
  glEnable(GL_BLEND);
  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

  glEnable(GL_TEXTURE_2D);
  bindTexture();
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (_interpolation) ? GL_LINEAR : GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (_interpolation) ? GL_LINEAR : GL_NEAREST);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _bufferWidth, _bufferHeight,
               0, GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
  vvGLTools::drawViewAlignedQuad();
  glDeleteTextures(1, &_textureId);

  glPopAttrib();

  glPopMatrix();
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
}

void vvOffscreenBuffer::writeBackDepthBuffer() const
{
  glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);

  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  glDepthMask(GL_TRUE);
  glDepthFunc(GL_ALWAYS);
  glEnable(GL_DEPTH_TEST);

  if (_useNVDepthStencil)
  {
    glDrawPixels(_bufferWidth, _bufferHeight, GL_DEPTH_STENCIL_NV, GL_UNSIGNED_INT_24_8_NV, _depthPixelsNV);
  }
  else
  {
    glDrawPixels(_bufferWidth, _bufferHeight, GL_DEPTH_COMPONENT, GL_FLOAT, _depthPixelsF);
  }

  glPopClientAttrib();
  glPopAttrib();
}
<|endoftext|>


<commit_before><commit_msg>Updating the command-line help string<commit_after><|endoftext|>


<commit_before>#include <poddlthread.h>
#include <curl/curl.h>
#include <iostream>
#include <logger.h>
#include <config.h>
#include <utils.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <libgen.h>

using namespace newsbeuter;

namespace podbeuter {

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp);
static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);

poddlthread::poddlthread(download * dl_, newsbeuter::configcontainer * c) : dl(dl_), cfg(c) {
}

poddlthread::~poddlthread() {
}

void poddlthread::run() {
	gettimeofday(&tv1, NULL);
	++bytecount;

	CURL * easyhandle = curl_easy_init();
	utils::set_common_curl_options(easyhandle, cfg);

	curl_easy_setopt(easyhandle, CURLOPT_URL, dl->url());
	// set up write functions:
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, this);

	// set up progress notification:
	curl_easy_setopt(easyhandle, CURLOPT_NOPROGRESS, 0);
	curl_easy_setopt(easyhandle, CURLOPT_PROGRESSFUNCTION, progress_callback);
	curl_easy_setopt(easyhandle, CURLOPT_PROGRESSDATA, this);

	struct stat sb;

	if (stat(dl->filename(), &sb) == -1) {
		LOG(LOG_INFO, "poddlthread::run: stat failed: starting normal download");
		mkdir_p(dl->filename());
		f.open(dl->filename(), std::fstream::out);
		dl->set_offset(0);
	} else {
		LOG(LOG_INFO, "poddlthread::run: stat ok: starting download from %u", sb.st_size);
		curl_easy_setopt(easyhandle, CURLOPT_RESUME_FROM, sb.st_size);
		dl->set_offset(sb.st_size);
		f.open(dl->filename(), std::fstream::out | std::fstream::app);
	}

	if (f.is_open()) {

		dl->set_status(DL_DOWNLOADING);

		CURLcode success = curl_easy_perform(easyhandle);

		f.close();

		LOG(LOG_INFO,"poddlthread::run: curl_easy_perform rc = %u", success);

		if (0 == success)
			dl->set_status(DL_FINISHED);
		else if (dl->status() != DL_CANCELLED) {
			dl->set_status(DL_FAILED);
			::unlink(dl->filename());
		}
	} else {
		dl->set_status(DL_FAILED);
	}

	curl_easy_cleanup(easyhandle);
}

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	poddlthread * thread = (poddlthread *)userp;
	return thread->write_data(buffer, size, nmemb);
}

static int progress_callback(void *clientp, double dltotal, double dlnow, double /* ultotal */, double /*ulnow*/) {
	poddlthread * thread = (poddlthread *)clientp;
	return thread->progress(dlnow, dltotal);
}

size_t poddlthread::write_data(void * buffer, size_t size, size_t nmemb) {
	if (dl->status() == DL_CANCELLED)
		return 0;
	f.write(static_cast<char *>(buffer), size * nmemb);
	bytecount += (size * nmemb);
	return f.bad() ? 0 : size * nmemb;
}

int poddlthread::progress(double dlnow, double dltotal) {
	if (dl->status() == DL_CANCELLED)
		return -1;
	gettimeofday(&tv2, NULL);
	double kbps = compute_kbps();
	if (kbps > 9999.99) {
		kbps = 0.0;
		gettimeofday(&tv1, NULL);
		bytecount = 0;
	}
	dl->set_kbps(kbps);
	dl->set_progress(dlnow, dltotal);
	return 0;
}

double poddlthread::compute_kbps() {
	double result = 0.0;

	double t1 = tv1.tv_sec + (tv1.tv_usec/(double)1000000);
	double t2 = tv2.tv_sec + (tv2.tv_usec/(double)1000000);

	result = (bytecount / (t2 - t1))/1024;

	return result;
}

void poddlthread::mkdir_p(const char * file) {
	char path[2048];
	snprintf(path, sizeof(path), "%s", file);
	for (char * x = path;*x != '\0';x++) {
		if (*x == '/') {
			*x = '\0';
			mkdir(path, 0755);
			*x = '/';
		}
	}
}

}
<commit_msg>don't set timeout when downloading podcasts.<commit_after>#include <poddlthread.h>
#include <curl/curl.h>
#include <iostream>
#include <logger.h>
#include <config.h>
#include <utils.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <libgen.h>

using namespace newsbeuter;

namespace podbeuter {

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp);
static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);

poddlthread::poddlthread(download * dl_, newsbeuter::configcontainer * c) : dl(dl_), cfg(c) {
}

poddlthread::~poddlthread() {
}

void poddlthread::run() {
	gettimeofday(&tv1, NULL);
	++bytecount;

	CURL * easyhandle = curl_easy_init();
	utils::set_common_curl_options(easyhandle, cfg);

	curl_easy_setopt(easyhandle, CURLOPT_URL, dl->url());
	curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, 0);
	// set up write functions:
	curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, my_write_data);
	curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, this);

	// set up progress notification:
	curl_easy_setopt(easyhandle, CURLOPT_NOPROGRESS, 0);
	curl_easy_setopt(easyhandle, CURLOPT_PROGRESSFUNCTION, progress_callback);
	curl_easy_setopt(easyhandle, CURLOPT_PROGRESSDATA, this);

	struct stat sb;

	if (stat(dl->filename(), &sb) == -1) {
		LOG(LOG_INFO, "poddlthread::run: stat failed: starting normal download");
		mkdir_p(dl->filename());
		f.open(dl->filename(), std::fstream::out);
		dl->set_offset(0);
	} else {
		LOG(LOG_INFO, "poddlthread::run: stat ok: starting download from %u", sb.st_size);
		curl_easy_setopt(easyhandle, CURLOPT_RESUME_FROM, sb.st_size);
		dl->set_offset(sb.st_size);
		f.open(dl->filename(), std::fstream::out | std::fstream::app);
	}

	if (f.is_open()) {

		dl->set_status(DL_DOWNLOADING);

		CURLcode success = curl_easy_perform(easyhandle);

		f.close();

		LOG(LOG_INFO,"poddlthread::run: curl_easy_perform rc = %u (%s)", success, curl_easy_strerror(success));

		if (0 == success)
			dl->set_status(DL_FINISHED);
		else if (dl->status() != DL_CANCELLED) {
			dl->set_status(DL_FAILED);
			::unlink(dl->filename());
		}
	} else {
		dl->set_status(DL_FAILED);
	}

	curl_easy_cleanup(easyhandle);
}

static size_t my_write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
	poddlthread * thread = (poddlthread *)userp;
	return thread->write_data(buffer, size, nmemb);
}

static int progress_callback(void *clientp, double dltotal, double dlnow, double /* ultotal */, double /*ulnow*/) {
	poddlthread * thread = (poddlthread *)clientp;
	return thread->progress(dlnow, dltotal);
}

size_t poddlthread::write_data(void * buffer, size_t size, size_t nmemb) {
	if (dl->status() == DL_CANCELLED)
		return 0;
	f.write(static_cast<char *>(buffer), size * nmemb);
	bytecount += (size * nmemb);
	LOG(LOG_DEBUG, "poddlthread::write_data: bad = %u size = %u", f.bad(), size * nmemb);
	return f.bad() ? 0 : size * nmemb;
}

int poddlthread::progress(double dlnow, double dltotal) {
	if (dl->status() == DL_CANCELLED)
		return -1;
	gettimeofday(&tv2, NULL);
	double kbps = compute_kbps();
	if (kbps > 9999.99) {
		kbps = 0.0;
		gettimeofday(&tv1, NULL);
		bytecount = 0;
	}
	dl->set_kbps(kbps);
	dl->set_progress(dlnow, dltotal);
	return 0;
}

double poddlthread::compute_kbps() {
	double result = 0.0;

	double t1 = tv1.tv_sec + (tv1.tv_usec/(double)1000000);
	double t2 = tv2.tv_sec + (tv2.tv_usec/(double)1000000);

	result = (bytecount / (t2 - t1))/1024;

	return result;
}

void poddlthread::mkdir_p(const char * file) {
	char path[2048];
	snprintf(path, sizeof(path), "%s", file);
	for (char * x = path;*x != '\0';x++) {
		if (*x == '/') {
			*x = '\0';
			mkdir(path, 0755);
			*x = '/';
		}
	}
}

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_CORE_GAME_WINDOW_HPP
#define RJ_CORE_GAME_WINDOW_HPP

#include "game_updater.hpp"
#include <rectojump/shared/input.hpp>

#include <mlk/log/log.h>
#include <mlk/signals_slots/slot.h>
#include <mlk/time/time.h>
#include <mlk/types/types.h>

#include <SFML/Graphics.hpp>

namespace rj
{
	class game_window
	{
		mlk::uint m_width{1280}, m_height{720};
		std::string m_title{"Recto Jump"};
		sf::RenderWindow m_window;
		bool m_running{false};
		bool m_fullscreen{false};
		bool m_need_recreate{false};

		input& m_input{input::get()};

		game_updater m_game_updater;

	public:
		mlk::slot<> on_stop;

		game_window() :
			m_window{{m_width, m_height}, m_title}
		{ }

		// interface
		void start()
		{
			if(m_running) return;

			this->prepare_start();
			while(m_running)
			{
				if(m_need_recreate)
					this->recreate();

				m_game_updater.start_pt();

				// update
				this->update_events();
				m_input.update(m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window)));
				m_game_updater.update();

				// render
				m_window.clear();
				m_game_updater.render();
				m_window.display();

				m_game_updater.end_pt();
			}
		}

		void stop() noexcept
		{on_stop(); m_running = false;}

		void draw(const sf::Drawable& object)
		{m_window.draw(object);}

		void toggle_fullscreen() noexcept
		{
			m_fullscreen = !m_fullscreen;
			m_need_recreate = true;
		}

		// setters
		void set_framereate_limit(mlk::uint limit) noexcept
		{m_window.setFramerateLimit(limit);}

		void set_size(const vec2u& size) noexcept
		{m_window.setSize(size);}

		void set_position(const vec2i& position) noexcept
		{m_window.setPosition(position);}

		void set_fullscreen(bool b) noexcept
		{
			if(b == m_fullscreen)
				return;
			m_fullscreen = b;
			m_need_recreate = true;
		}

		// getters
		game_updater& get_updater() noexcept
		{return m_game_updater;}

		vec2u get_size() const noexcept
		{return m_window.getSize();}

		vec2i get_position() const noexcept
		{return m_window.getPosition();}

		bool get_fullscreen() const noexcept
		{return m_fullscreen;}

	private:
		void prepare_start() noexcept
		{
			m_running = true;
			mlk::lout("rj::game_window", true) << "starting gamewindow";
		}

		void update_events() noexcept
		{
			sf::Event ev;
			while(m_window.pollEvent(ev))
			{
				switch(ev.type)
				{
				case sf::Event::EventType::Closed:
					this->stop();
					break;
				case sf::Event::EventType::KeyPressed:
					m_input.key_pressed(ev.key.code);
					break;
				case sf::Event::EventType::KeyReleased:
					m_input.key_released(ev.key.code);
					break;
				case sf::Event::EventType::MouseButtonPressed:
					m_input.btn_pressed(ev.mouseButton.button);
					break;
				case sf::Event::EventType::MouseButtonReleased:
					m_input.btn_released(ev.mouseButton.button);
				default: break;
				}
			}
		}

		void recreate()
		{
			m_window.close();
			m_window.create({m_width, m_height}, m_title, m_fullscreen ? sf::Style::Fullscreen : sf::Style::Default);
			m_need_recreate = false;
		}
	};
}

#endif // RJ_CORE_GAME_WINDOW_HPP
<commit_msg>added game_window::set_view()<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_CORE_GAME_WINDOW_HPP
#define RJ_CORE_GAME_WINDOW_HPP

#include "game_updater.hpp"
#include <rectojump/shared/input.hpp>

#include <mlk/log/log.h>
#include <mlk/signals_slots/slot.h>
#include <mlk/time/time.h>
#include <mlk/types/types.h>

#include <SFML/Graphics.hpp>

namespace rj
{
	class game_window
	{
		mlk::uint m_width{1280}, m_height{720};
		std::string m_title{"Recto Jump"};
		sf::RenderWindow m_window;
		bool m_running{false};
		bool m_fullscreen{false};
		bool m_need_recreate{false};

		input& m_input{input::get()};

		game_updater m_game_updater;

	public:
		mlk::slot<> on_stop;

		game_window() :
			m_window{{m_width, m_height}, m_title}
		{ }

		// interface
		void start()
		{
			if(m_running) return;

			this->prepare_start();
			while(m_running)
			{
				if(m_need_recreate)
					this->recreate();

				m_game_updater.start_pt();

				// update
				this->update_events();
				m_input.update(m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window)));
				m_game_updater.update();

				// render
				m_window.clear();
				m_game_updater.render();
				m_window.display();

				m_game_updater.end_pt();
			}
		}

		void stop() noexcept
		{on_stop(); m_running = false;}

		void draw(const sf::Drawable& object)
		{m_window.draw(object);}

		void toggle_fullscreen() noexcept
		{
			m_fullscreen = !m_fullscreen;
			m_need_recreate = true;
		}

		// setters
		void set_framereate_limit(mlk::uint limit) noexcept
		{m_window.setFramerateLimit(limit);}

		void set_size(const vec2u& size) noexcept
		{m_window.setSize(size);}

		void set_position(const vec2i& position) noexcept
		{m_window.setPosition(position);}

		void set_fullscreen(bool b) noexcept
		{
			if(b == m_fullscreen)
				return;
			m_fullscreen = b;
			m_need_recreate = true;
		}

		void set_view(const sf::View& v) noexcept
		{m_window.setView(v);}

		// getters
		game_updater& get_updater() noexcept
		{return m_game_updater;}

		vec2u get_size() const noexcept
		{return m_window.getSize();}

		vec2i get_position() const noexcept
		{return m_window.getPosition();}

		bool get_fullscreen() const noexcept
		{return m_fullscreen;}

	private:
		void prepare_start() noexcept
		{
			m_running = true;
			mlk::lout("rj::game_window", true) << "starting gamewindow";
		}

		void update_events() noexcept
		{
			sf::Event ev;
			while(m_window.pollEvent(ev))
			{
				switch(ev.type)
				{
				case sf::Event::EventType::Closed:
					this->stop();
					break;
				case sf::Event::EventType::KeyPressed:
					m_input.key_pressed(ev.key.code);
					break;
				case sf::Event::EventType::KeyReleased:
					m_input.key_released(ev.key.code);
					break;
				case sf::Event::EventType::MouseButtonPressed:
					m_input.btn_pressed(ev.mouseButton.button);
					break;
				case sf::Event::EventType::MouseButtonReleased:
					m_input.btn_released(ev.mouseButton.button);
				default: break;
				}
			}
		}

		void recreate()
		{
			m_window.close();
			m_window.create({m_width, m_height}, m_title, m_fullscreen ? sf::Style::Fullscreen : sf::Style::Default);
			m_need_recreate = false;
		}
	};
}

#endif // RJ_CORE_GAME_WINDOW_HPP
<|endoftext|>


<commit_before>/***********************************************************************/
/**                                                                    */
/** teresa_robot.hpp                                                   */
/**                                                                    */
/** Copyright (c) 2016, Service Robotics Lab.                          */
/**                     http://robotics.upo.es                         */
/**                                                                    */
/** All rights reserved.                                               */
/**                                                                    */
/** Authors:                                                           */
/** Ignacio Perez-Hurtado (maintainer)                                 */
/** Noe Perez                                                          */
/** Rafael Ramon                                                       */
/** David Alejo Teissière                                              */
/** Fernando Caballero                                                 */
/** Jesus Capitan                                                      */
/** Luis Merino                                                        */
/**                                                                    */
/** This software may be modified and distributed under the terms      */
/** of the BSD license. See the LICENSE file for details.              */
/**                                                                    */
/** http://www.opensource.org/licenses/BSD-3-Clause                    */
/**                                                                    */
/***********************************************************************/

#ifndef _TERESA_ROBOT_HPP_
#define _TERESA_ROBOT_HPP_

#include <cmath>

namespace Teresa
{

#define MIN_HEIGHT_MM                         1260
#define MAX_HEIGHT_MM                         1425

#define MIN_TILT_ANGLE_DEGREES                 -37
#define MAX_TILT_ANGLE_DEGREES                  37

#define ROBOT_DIAMETER_M                      0.47
#define ROBOT_RADIUS_M                       0.235

#define MAX_LINEAR_VELOCITY                    0.6
#define MAX_ANGULAR_VELOCITY             1.5707963

#define LINEAR_VELOCITY_ZERO_THRESHOLD       0.001
#define ANGULAR_VELOCITY_ZERO_THRESHOLD       0.01

struct PowerDiagnostics
{
	double elec_bat_voltage;     // V
	double PC1_bat_voltage;      // V
	double cable_bat_voltage;    // V
	double motor_voltage;        // V
	double motor_h_voltage;      // V
	double motor_l_voltage;      // V

	int elec_instant_current;     // mA
	int motor_instant_current;    // mA
	int elec_integrated_current;  // mA
	int motor_integrated_current; // mA
};

/**
 * An interface for the Teresa Robot
 */
class Robot
{
public:
	Robot() {}
	virtual ~Robot() {}
        /**
	 * Set the velocity reference
	 *
	 * @param[in] linear the linear velocity reference in m/s
	 * @param[in] angular the angular velocity reference in rad/s
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocity(double linear, double angular) = 0;

 		/**
	 * Set the velocity reference
	 * Transforming to motor unit by using the upo calibration
	 * @param[in] linear the linear velocity reference in m/s
	 * @param[in] angular the angular velocity reference in rad/s
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocity2(double linear, double angular) = 0;

	/**
	 * Set the raw velocity
	 *
	 * @param[in] leftWheelRef the left wheel velocity reference
	 * @param[in] rightWheelRef the right wheel velocity reference
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocityRaw(int16_t leftWheelRef, int16_t rightWheelRef) = 0;
	/**
	 * Check if the robot is stopped
	 *
	 * @return true if robot is stopped, false otherwise
	 */
	virtual bool isStopped() = 0;
	/**
	 * Get the distance traveled by each wheel since the last call to this function
	 *
	 * @param[out] imdl the distance traveled by the left wheel in meters
	 * @param[out] imdr the distance traveled by the right wheel in meters
	 * @return true if success, false otherwise
	 */
	virtual bool getIMD(double& imdl, double& imdr) = 0;
	/**
	 * Set the height velocity
	 *
	 * @param[in] velocity in [0,40] range
	 * @return true if success, false otherwise
	 */
	virtual bool setHeightVelocity(int velocity) = 0;
	/**
	 * Set the tilt velocity
	 *
	 * @param[in] velocity in [2,8] range
	 * @return true if success, false otherwise
	 */
	virtual bool setTiltVelocity(int velocity) = 0;
	/**
	 * Set the height
	 *
	 * @param[in] height in millimeters [1260 to 1425]
         * @return true if success, false otherwise
	 */
	virtual bool setHeight(int height) = 0;
	/**
	 * Set the tilt angle
	 *
	 * @param[in] tilt angle in degrees [-37 to 37]
         * @return true if success, false otherwise
	 */
	virtual bool setTilt(int tilt) = 0;
	/**
	 * Get the height
	 *
	 * height[out] the height in millimeters
	 * @return true if success, false otherwise
	 */
	virtual bool getHeight(int& height) = 0;
	/**
	 * Get the tilt angle
	 *
	 * @param[out] tilt angle in degrees
	 * @return true if success, false otherwise
	 */
	virtual bool getTilt(int& tilt) = 0;
	/**
	 * Check if some button has been pressed
	 *
	 * @param[out] button1 true if button1 has been pressed since the last read, false otherwise
	 * @param[out] button2 true if button2 has been pressed since the last read, false otherwise
         * @return true if success, false otherwise
	 */
	virtual bool getButtons(bool& button1, bool& button2) = 0;
	/**
	 * Get the encoder steps positive or negative counted since the last reading
	 *
	 * @param[out] rotaryEncoder the encoder steps since the last reading
	 * @return true if success, false otherwise
	 */
	virtual bool getRotaryEncoder(int& rotaryEncoder) = 0;

	/**
	 * Get temperature information
	 *
	 * @param[out] leftMotor temperature of the left motor in celsius degrees
	 * @param[out] rightMotor temperature of the right motor in celsius degrees
	 * @param[out] leftDriver temperature of the left driver in celsius degrees
	 * @param[out] rightDriver temperature of the right driver in celsius degrees
	 * @param[out] tiltDriverOverheat true if tilt driver is overheat, false otherwise
	 * @param[out] heightDriverOverheat true if height driver is overheat, false otherwise
	 * @return true if success, false otherwise
	 */
	virtual bool getTemperature(int& leftMotor,
					int& rightMotor,
					int& leftDriver,
					int& rightDriver,
					bool& tiltDriverOverheat,
					bool& heightDriverOverheat) = 0;

	/**
	 * enable/disable DCDC outputs
	 *
	 * @param[in] mask binary mask [HGFEDCBA] where:
	 *             A = 1 Enable RD0 5V output
         *             A = 0 Disable RD0 5V output
         *             B = 1 Enable RD1 5V output
         *             B = 0 Disable RD1 5V output
         *             C = 1 Enable RD2 12V output
         *             C = 0 Disable RD2 12V output
         *             D = 1 Enable RD3 12V output
         *             D = 0 Disable RD3 12V output
         *             E = 1 Enable RD4 12V output
         *             E = 0 Disable RD4 12V output
         *             F = 1 Enable RD5 12V output
         *             F = 0 Disable RD5 12V output
         *             G = 1 Enable RD6 12V output
         *             G = 0 Disable RD6 12V output
         *             H = 1 Enable RD7 12V output
         *             H = 0 Disable RD7 12V output
	 * @return true if success, false otherwise
	 */
	virtual bool enableDCDC(unsigned char mask) = 0;

	/**
	 * get DCDC status
	 *
	 * @param[out] mask get the current binary mask [HGFEDCBA]
	 * @return true if success, false otherwise
	 */
	virtual bool getDCDC(unsigned char& mask) = 0;
	/**
	 * set RGB leds
	 *
	 * @param[in] leds array of desired RGB values R0,G0,B0,R1,G1,B1,...,Rn,Gn,Bn
	 * @return true if success, false otherwise
	 */
	virtual bool setLeds(const std::vector<unsigned char>& leds) = 0;
	/**
	 * get Battery status
	 *
	 * @param[out] elec_level percentage of power available in electronic battery [0,100]%
	 * @param[out] PC1_level percentage of power available in PC1 battery [0,100]%
	 * @param[out] motorH_level percentage of power available in motorH battery [0,100]%
	 * @param[out] motorL_level percentage of power available in motorL battery [0,100]%
	 * @param[out] charger_status [XXXXDCBA]
	 * 		A = 1 Charger 1 charge ended
	 *		A = 0 Charger 1 charge ongoing
	 *		B = 1 Charger 2 charge ended
	 *		B = 0 Charger 2 charge ongoing
	 *		C = 1 Charger 3 charge ended
	 *		C = 0 Charger 3 charge ongoing
	 *		D = 1 Charger 4 charge ended
	 *		D = 0 Charger 4 charge ongoing
	 * @return true if success, false otherwise
	 */
	virtual bool getBatteryStatus(unsigned char& elec_level,
					unsigned char& PC1_level,
					unsigned char& motorH_level,
					unsigned char& motorL_level,
					unsigned char& charger_status) = 0;

	/**
	 * get Power diagnostics
	 *
	 * @param[out] diagnostics struct of PowerDiagnostics with information
	 * @return true if success, false otherwise
	 */
	virtual bool getPowerDiagnostics(PowerDiagnostics& diagnostics) = 0;
protected:
	/**
	 * Saturate a linear velocity value
	 *
	 * Note: See function double saturate(double v, double max, double zero) below
	 * @param[in] v the linear velocity to saturate in m/s
	 * @return the saturated linear velocity in m/s
	 */
	static double saturateLinearVelocity(double v);
	/**
	 * Saturate an angular velocity value
	 *
	 * Note: See function double saturate(double v, double max, double zero) below
	 * @param[in] v the angular velocity to saturate in rad/s
	 * @return the saturated angular velocity in rad/s
	 */
	static double saturateAngularVelocity(double v);

private:
	/**
	 * Saturate a velocity value
	 *
	 * The returned value will be 0.0 if std::abs(v)<=zero_threshold
	 * The returned value will be max_value if v>max_value
	 * The returned value will be -max_value if v<-max_value
	 * @param[in] v the velocity to saturate
	 * @param[in] max_value the maximum velocity value
	 * @param[in] zero_threshold the zero threshold
	 * @return The saturated velocity
	 */
	static double saturate(double v, double max_value, double zero_threshold);
};

inline
double Robot::saturateLinearVelocity(double v)
{
	return saturate(v,MAX_LINEAR_VELOCITY,LINEAR_VELOCITY_ZERO_THRESHOLD);
}

inline
double Robot::saturateAngularVelocity(double v)
{
	return saturate(v,MAX_ANGULAR_VELOCITY,ANGULAR_VELOCITY_ZERO_THRESHOLD);
}

inline
double Robot::saturate(double v, double max_value, double zero_threshold)
{
	if (v<=zero_threshold && v>=-zero_threshold) {
		v = 0.0;
	}
	else if (v>max_value) {
		v = max_value;
	}
	else if (v < -max_value) {
		v = -max_value;
	}
	return v;
}

}

#endif
<commit_msg>tilt ranges changed<commit_after>/***********************************************************************/
/**                                                                    */
/** teresa_robot.hpp                                                   */
/**                                                                    */
/** Copyright (c) 2016, Service Robotics Lab.                          */
/**                     http://robotics.upo.es                         */
/**                                                                    */
/** All rights reserved.                                               */
/**                                                                    */
/** Authors:                                                           */
/** Ignacio Perez-Hurtado (maintainer)                                 */
/** Noe Perez                                                          */
/** Rafael Ramon                                                       */
/** David Alejo Teissière                                              */
/** Fernando Caballero                                                 */
/** Jesus Capitan                                                      */
/** Luis Merino                                                        */
/**                                                                    */
/** This software may be modified and distributed under the terms      */
/** of the BSD license. See the LICENSE file for details.              */
/**                                                                    */
/** http://www.opensource.org/licenses/BSD-3-Clause                    */
/**                                                                    */
/***********************************************************************/

#ifndef _TERESA_ROBOT_HPP_
#define _TERESA_ROBOT_HPP_

#include <cmath>

namespace Teresa
{

#define MIN_HEIGHT_MM                         1260
#define MAX_HEIGHT_MM                         1425

#define MIN_TILT_ANGLE_DEGREES                 -30
#define MAX_TILT_ANGLE_DEGREES                  30

#define ROBOT_DIAMETER_M                      0.47
#define ROBOT_RADIUS_M                       0.235

#define MAX_LINEAR_VELOCITY                    0.6
#define MAX_ANGULAR_VELOCITY             1.5707963

#define LINEAR_VELOCITY_ZERO_THRESHOLD       0.001
#define ANGULAR_VELOCITY_ZERO_THRESHOLD       0.01

struct PowerDiagnostics
{
	double elec_bat_voltage;     // V
	double PC1_bat_voltage;      // V
	double cable_bat_voltage;    // V
	double motor_voltage;        // V
	double motor_h_voltage;      // V
	double motor_l_voltage;      // V

	int elec_instant_current;     // mA
	int motor_instant_current;    // mA
	int elec_integrated_current;  // mA
	int motor_integrated_current; // mA
};

/**
 * An interface for the Teresa Robot
 */
class Robot
{
public:
	Robot() {}
	virtual ~Robot() {}
        /**
	 * Set the velocity reference
	 *
	 * @param[in] linear the linear velocity reference in m/s
	 * @param[in] angular the angular velocity reference in rad/s
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocity(double linear, double angular) = 0;

 		/**
	 * Set the velocity reference
	 * Transforming to motor unit by using the upo calibration
	 * @param[in] linear the linear velocity reference in m/s
	 * @param[in] angular the angular velocity reference in rad/s
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocity2(double linear, double angular) = 0;

	/**
	 * Set the raw velocity
	 *
	 * @param[in] leftWheelRef the left wheel velocity reference
	 * @param[in] rightWheelRef the right wheel velocity reference
	 * @return true if success, false otherwise
	 */
	virtual bool setVelocityRaw(int16_t leftWheelRef, int16_t rightWheelRef) = 0;
	/**
	 * Check if the robot is stopped
	 *
	 * @return true if robot is stopped, false otherwise
	 */
	virtual bool isStopped() = 0;
	/**
	 * Get the distance traveled by each wheel since the last call to this function
	 *
	 * @param[out] imdl the distance traveled by the left wheel in meters
	 * @param[out] imdr the distance traveled by the right wheel in meters
	 * @return true if success, false otherwise
	 */
	virtual bool getIMD(double& imdl, double& imdr) = 0;
	/**
	 * Set the height velocity
	 *
	 * @param[in] velocity in [0,40] range
	 * @return true if success, false otherwise
	 */
	virtual bool setHeightVelocity(int velocity) = 0;
	/**
	 * Set the tilt velocity
	 *
	 * @param[in] velocity in [2,8] range
	 * @return true if success, false otherwise
	 */
	virtual bool setTiltVelocity(int velocity) = 0;
	/**
	 * Set the height
	 *
	 * @param[in] height in millimeters [1260 to 1425]
         * @return true if success, false otherwise
	 */
	virtual bool setHeight(int height) = 0;
	/**
	 * Set the tilt angle
	 *
	 * @param[in] tilt angle in degrees [-37 to 37]
         * @return true if success, false otherwise
	 */
	virtual bool setTilt(int tilt) = 0;
	/**
	 * Get the height
	 *
	 * height[out] the height in millimeters
	 * @return true if success, false otherwise
	 */
	virtual bool getHeight(int& height) = 0;
	/**
	 * Get the tilt angle
	 *
	 * @param[out] tilt angle in degrees
	 * @return true if success, false otherwise
	 */
	virtual bool getTilt(int& tilt) = 0;
	/**
	 * Check if some button has been pressed
	 *
	 * @param[out] button1 true if button1 has been pressed since the last read, false otherwise
	 * @param[out] button2 true if button2 has been pressed since the last read, false otherwise
         * @return true if success, false otherwise
	 */
	virtual bool getButtons(bool& button1, bool& button2) = 0;
	/**
	 * Get the encoder steps positive or negative counted since the last reading
	 *
	 * @param[out] rotaryEncoder the encoder steps since the last reading
	 * @return true if success, false otherwise
	 */
	virtual bool getRotaryEncoder(int& rotaryEncoder) = 0;

	/**
	 * Get temperature information
	 *
	 * @param[out] leftMotor temperature of the left motor in celsius degrees
	 * @param[out] rightMotor temperature of the right motor in celsius degrees
	 * @param[out] leftDriver temperature of the left driver in celsius degrees
	 * @param[out] rightDriver temperature of the right driver in celsius degrees
	 * @param[out] tiltDriverOverheat true if tilt driver is overheat, false otherwise
	 * @param[out] heightDriverOverheat true if height driver is overheat, false otherwise
	 * @return true if success, false otherwise
	 */
	virtual bool getTemperature(int& leftMotor,
					int& rightMotor,
					int& leftDriver,
					int& rightDriver,
					bool& tiltDriverOverheat,
					bool& heightDriverOverheat) = 0;

	/**
	 * enable/disable DCDC outputs
	 *
	 * @param[in] mask binary mask [HGFEDCBA] where:
	 *             A = 1 Enable RD0 5V output
         *             A = 0 Disable RD0 5V output
         *             B = 1 Enable RD1 5V output
         *             B = 0 Disable RD1 5V output
         *             C = 1 Enable RD2 12V output
         *             C = 0 Disable RD2 12V output
         *             D = 1 Enable RD3 12V output
         *             D = 0 Disable RD3 12V output
         *             E = 1 Enable RD4 12V output
         *             E = 0 Disable RD4 12V output
         *             F = 1 Enable RD5 12V output
         *             F = 0 Disable RD5 12V output
         *             G = 1 Enable RD6 12V output
         *             G = 0 Disable RD6 12V output
         *             H = 1 Enable RD7 12V output
         *             H = 0 Disable RD7 12V output
	 * @return true if success, false otherwise
	 */
	virtual bool enableDCDC(unsigned char mask) = 0;

	/**
	 * get DCDC status
	 *
	 * @param[out] mask get the current binary mask [HGFEDCBA]
	 * @return true if success, false otherwise
	 */
	virtual bool getDCDC(unsigned char& mask) = 0;
	/**
	 * set RGB leds
	 *
	 * @param[in] leds array of desired RGB values R0,G0,B0,R1,G1,B1,...,Rn,Gn,Bn
	 * @return true if success, false otherwise
	 */
	virtual bool setLeds(const std::vector<unsigned char>& leds) = 0;
	/**
	 * get Battery status
	 *
	 * @param[out] elec_level percentage of power available in electronic battery [0,100]%
	 * @param[out] PC1_level percentage of power available in PC1 battery [0,100]%
	 * @param[out] motorH_level percentage of power available in motorH battery [0,100]%
	 * @param[out] motorL_level percentage of power available in motorL battery [0,100]%
	 * @param[out] charger_status [XXXXDCBA]
	 * 		A = 1 Charger 1 charge ended
	 *		A = 0 Charger 1 charge ongoing
	 *		B = 1 Charger 2 charge ended
	 *		B = 0 Charger 2 charge ongoing
	 *		C = 1 Charger 3 charge ended
	 *		C = 0 Charger 3 charge ongoing
	 *		D = 1 Charger 4 charge ended
	 *		D = 0 Charger 4 charge ongoing
	 * @return true if success, false otherwise
	 */
	virtual bool getBatteryStatus(unsigned char& elec_level,
					unsigned char& PC1_level,
					unsigned char& motorH_level,
					unsigned char& motorL_level,
					unsigned char& charger_status) = 0;

	/**
	 * get Power diagnostics
	 *
	 * @param[out] diagnostics struct of PowerDiagnostics with information
	 * @return true if success, false otherwise
	 */
	virtual bool getPowerDiagnostics(PowerDiagnostics& diagnostics) = 0;
protected:
	/**
	 * Saturate a linear velocity value
	 *
	 * Note: See function double saturate(double v, double max, double zero) below
	 * @param[in] v the linear velocity to saturate in m/s
	 * @return the saturated linear velocity in m/s
	 */
	static double saturateLinearVelocity(double v);
	/**
	 * Saturate an angular velocity value
	 *
	 * Note: See function double saturate(double v, double max, double zero) below
	 * @param[in] v the angular velocity to saturate in rad/s
	 * @return the saturated angular velocity in rad/s
	 */
	static double saturateAngularVelocity(double v);

private:
	/**
	 * Saturate a velocity value
	 *
	 * The returned value will be 0.0 if std::abs(v)<=zero_threshold
	 * The returned value will be max_value if v>max_value
	 * The returned value will be -max_value if v<-max_value
	 * @param[in] v the velocity to saturate
	 * @param[in] max_value the maximum velocity value
	 * @param[in] zero_threshold the zero threshold
	 * @return The saturated velocity
	 */
	static double saturate(double v, double max_value, double zero_threshold);
};

inline
double Robot::saturateLinearVelocity(double v)
{
	return saturate(v,MAX_LINEAR_VELOCITY,LINEAR_VELOCITY_ZERO_THRESHOLD);
}

inline
double Robot::saturateAngularVelocity(double v)
{
	return saturate(v,MAX_ANGULAR_VELOCITY,ANGULAR_VELOCITY_ZERO_THRESHOLD);
}

inline
double Robot::saturate(double v, double max_value, double zero_threshold)
{
	if (v<=zero_threshold && v>=-zero_threshold) {
		v = 0.0;
	}
	else if (v>max_value) {
		v = max_value;
	}
	else if (v < -max_value) {
		v = -max_value;
	}
	return v;
}

}

#endif
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file   concurrent_spsc_queue.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief Producer/consumer queue.
///
/// Based on code from:
/// https://github.com/facebook/folly/blob/master/folly/concurrent_spsc_queue.h
/// Original public domain version authored by Facebook
/// Modifications by Serge Aleynikov
//----------------------------------------------------------------------------
// Created: 2014-06-10
//----------------------------------------------------------------------------
/*
 ***** BEGIN LICENSE BLOCK *****

 This file is part of the utxx open-source project.

 Copyright (C) 2014 Serge Aleynikov <saleyn@gmail.com>

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

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

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 ***** END LICENSE BLOCK *****
 */
#ifndef _UTXX_CONCURRENT_SPSC_QUEUE_HPP_
#define _UTXX_CONCURRENT_SPSC_QUEUE_HPP_

#include <atomic>
#include <cassert>
#include <cstdlib>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <boost/noncopyable.hpp>
#include <boost/type_traits.hpp>
#include <utxx/math.hpp>

namespace utxx {

/**
 * \brief A lock-free single producer and single consumer queue
 * based on a ring-buffer.
 *
 * Implementation allows to use either internally allocated heap
 * memory or externally allocated shared memory.
 */
template<class T>
class concurrent_spsc_queue : private boost::noncopyable {
    struct header {
        std::atomic<int>  head;
        std::atomic<int>  tail;
        uint32_t const    size;
        uint32_t          total_memory;

        static size_t normalize_count(size_t a_mem_size) {
            size_t i = a_mem_size / sizeof(T);
            size_t n = math::upper_power(i, 2);
            return n == i ? n : n /= 2;
        }

        header() {}
        header(size_t a_mem_size)
            : head(0)
            , tail(0)
            , size(normalize_count(a_mem_size))
            , total_memory(a_mem_size)
        {
            assert((size * sizeof(T)) <= a_mem_size);
            assert((size & (size-1)) == 0); // Power of 2.
            if (size < 2)
                throw std::runtime_error
                    ("utxx::concurrent_spsc_queue: size must be greater or equal to 2");
        }
    };

    concurrent_spsc_queue(header* a_header, T* a_storage, size_t a_mem_size, bool a_own)
        : m_header_data(a_mem_size)
        , m_header(a_header)
        , m_records(a_own
            ? reinterpret_cast<T*>(::malloc(sizeof(T)*m_header_data.size))
            : static_cast<T*>(a_storage))
        , m_own_data(a_own)
        , m_mask(m_header_data.size - 1)
    {
        new (m_header) header(a_mem_size);
    }

    // Round size to the nearest power of 2 greater than the total size needed to
    // hold a_count elements.
    static size_t round_size(size_t a_count, size_t a_addon = 0) {
        return math::upper_power(a_count, 2) * sizeof(T) + a_addon;
    }

public:
    typedef T value_type;

    /// @return memory size needed for allocating internal queue data
    static size_t memory_size(size_t a_item_count) {
        return round_size(a_item_count, sizeof(header));
    }

    /// \brief Ctor for using external memory (e.g. shared memory).
    ///
    /// When the desired capacity of the queue is known in the number of items,
    /// \a a_size can be obtained by the call to memory_size().
    concurrent_spsc_queue(void* a_storage, uint32_t a_size)
        : concurrent_spsc_queue(
            static_cast<header*>(a_storage),
            reinterpret_cast<T*>(static_cast<char*>(a_storage) + sizeof(m_header)),
            a_size - sizeof(header),
            false
          )
    {}

    // size will be rounded to the nearest power of two up to or below \a a_size.
    //
    // Also, note that the number of usable slots in the queue at any
    // given time is actually (\a a_size-1), so if you start with an empty queue,
    // full() will return true after \a a_size-1 insertions.
    explicit concurrent_spsc_queue(uint32_t a_item_count)
        : concurrent_spsc_queue(&m_header_data, nullptr, round_size(a_item_count), true)
    {}

    ~concurrent_spsc_queue() {
        if (m_own_data) {
            // We need to destruct anything that may still exist in our queue.
            // (No real synchronization needed at destructor time: only one
            // thread can be doing this.)
            if (!boost::has_trivial_destructor<T>::value)
                for (int read = head(), end = tail(); read != end; read = (read + 1) & m_mask)
                    m_records[read].~T();

            if (m_records)
                ::free(m_records);
        }
    }

    /// Write aruments to the queue.
    /// @return true on success, false when the queue is full
    template<class ...Args>
    bool push(Args&&... recordArgs) {
        const int t = tail().load(std::memory_order_relaxed);
        const int next = (t + 1) & m_mask;
        if (next != head().load(std::memory_order_acquire)) {
            new (&m_records[t]) T(std::forward<Args>(recordArgs)...);
            tail().store(next, std::memory_order_release);
            return true;
        }

        // queue is full
        return false;
    }

    /// Move (or copy) the value at the front of the queue to given variable
    bool pop(T& record) {
        const int h = head().load(std::memory_order_relaxed);
        if (h == tail().load(std::memory_order_acquire)) {
            // queue is empty
            return false;
        }

        const int next = (h + 1) & m_mask;
        record = std::move(m_records[h]);
        m_records[h].~T();
        head().store(next, std::memory_order_release);
        return true;
    }

    // Pointer to the value at the front of the queue (for use in-place) or
    // nullptr if empty.
    T* peek() {
        const int h = head().load(std::memory_order_relaxed);
        return    h == tail().load(std::memory_order_acquire)
            ? nullptr /* queue is empty */
            : &m_records[h];
    }

    // Pointer to the value at the front of the queue (for use in-place) or
    // nullptr if empty.
    T* peek() const {
        const int h = head().load(std::memory_order_relaxed);
        return    h == tail().load(std::memory_order_acquire)
            ? nullptr /* queue is empty */
            : &m_records[h];
    }

    /// Pop an element from the front of the queue.
    ///
    /// Queue must not be empty!
    void pop() {
        const int h = head().load(std::memory_order_relaxed);
        assert(h != tail().load(std::memory_order_acquire));

        size_t next = (h + 1) & m_mask;
        m_records[h].~T();
        head().store(next, std::memory_order_release);
    }

    bool empty() const {
        return head().load(std::memory_order_consume)
            == tail().load(std::memory_order_consume);
    }

    bool full() const {
        const int next = (tail().load(std::memory_order_consume) + 1) & m_mask;
        return    next == head().load(std::memory_order_consume);
    }

    // * If called by consumer, then true size may be more (because producer may
    //   be adding items concurrently).
    // * If called by producer, then true size may be less (because consumer may
    //   be removing items concurrently).
    // * It is undefined to call this from any other thread.
    size_t unsafe_size() const {
        int ret = tail().load(std::memory_order_consume)
                - head().load(std::memory_order_consume);
        return ret < 0 ? ret + size() : ret;
    }

    /// @return maximum capacity of items the queue can hold.
    size_t capacity()       const { return m_header->size; }
    /// @return total memory size used internally by the queue.
    size_t total_memory()   const { return m_header->total_memory; }

private:
    header       m_header_data;
    header*      m_header;
    T* const     m_records;
    bool         m_own_data;
    size_t const m_mask;

    size_t                  size() const { return m_header->size; }
    std::atomic<int>&       head()       { return m_header->head; }
    std::atomic<int>&       tail()       { return m_header->tail; }
    const std::atomic<int>& head() const { return m_header->head; }
    const std::atomic<int>& tail() const { return m_header->tail; }
};

} // namespace utxx

#endif //_UTXX_CONCURRENT_SPSC_QUEUE_HPP_
<commit_msg>UTXX: extended functionality for concurrent_spsc_queue (iterators etc)<commit_after>// vim:ts=4:et:sw=4
//----------------------------------------------------------------------------
/// \file   concurrent_spsc_queue.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief Producer/consumer queue.
///
/// Based on code from:
/// https://github.com/facebook/folly/blob/master/folly/concurrent_spsc_queue.h
/// Original public domain version authored by Facebook
/// Modifications by Serge Aleynikov
//----------------------------------------------------------------------------
// Created: 2014-06-10
//----------------------------------------------------------------------------
/*
 ***** BEGIN LICENSE BLOCK *****

 This file is part of the utxx open-source project.

 Copyright (C) 2014 Serge Aleynikov <saleyn@gmail.com>

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

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

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 ***** END LICENSE BLOCK *****
 */
#ifndef _UTXX_CONCURRENT_SPSC_QUEUE_HPP_
#define _UTXX_CONCURRENT_SPSC_QUEUE_HPP_

#include <utxx/math.hpp>
#include <utxx/compiler_hints.hpp>
#include <boost/noncopyable.hpp>
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <type_traits>

namespace utxx {

//===========================================================================//
// concurrent_spsc_queue is a one producer and one consumer queue            //
// without locks.                                                            //
//===========================================================================//
template<class T, uint32_t StaticCapacity=0>
class concurrent_spsc_queue : private boost::noncopyable
{
    //=======================================================================//
    // Implementation:                                                       //
    //=======================================================================//
    // header (can also be located in ShMemalong with the data):
    //
    struct header
    {
        std::atomic<uint32_t>  m_head;
        std::atomic<uint32_t>  m_tail;
        uint32_t    const      m_capacity;
        T                      __padding[0];

        static uint32_t adjust_capacity(uint32_t a_capacity)
        {
            uint32_t n = math::upper_power(a_capacity, 2);
            // If the result was not equal to the original "a_capacity", it
            // was rounded UP, and we need to round it DOWN:
            if (n != a_capacity)
            {
                assert(n > a_capacity);
                n /= 2;
            }
            return n;
        }

        header()
            : m_head    (0)
            , m_tail    (0)
            , m_capacity(0)
        {}

        header(uint32_t a_capacity)
            : m_head(0)
            , m_tail(0)
            , m_capacity(adjust_capacity(a_capacity))
        {
            assert((m_capacity & (m_capacity-1)) == 0);  // Power of 2 indeed
            if (m_capacity < 2)
                throw std::runtime_error
                    ("utxx::concurrent_spsc_queue: capacity must be a positive "
                     "power of 2");
        }
    };

    uint32_t increment(uint32_t h) const { return (h + 1) & m_mask; }

public:
    //=======================================================================//
    // External API: Synchronous Operations:                                 //
    //=======================================================================//
    typedef T value_type;

    /// @return memory size needed for allocating internal queue data.
    /// XXX: this does not tale into account that the actual capacity may be
    /// lower (a rounded-down power of 2):
    ///
    static uint32_t memory_size(uint32_t a_capacity)
      { return sizeof(header) + a_capacity * sizeof(T); }

    /// Non-Default Ctor for using external memory (e.g. shared memory)
    /// Size must be obtained by the call to memory_size(). Only enabled if the
    /// StaticCapacity is 0.
    /// NB: In this case, Arg2 is really a memory size in bytes, NOT the capac-
    /// ity which is the items count!
    concurrent_spsc_queue
    (
        void*    a_storage,
        uint32_t a_size,
        bool     a_is_producer
    )
        : m_header     ((a_size - sizeof(header)) / sizeof(T))
        , m_header_ptr (static_cast<header*>(a_storage))
        , m_rec_ptr    (reinterpret_cast<T*>(static_cast<char*>(a_storage) +
                                             sizeof(header)))
        , m_shared_data(true)
        , m_is_producer(a_is_producer)
        , m_mask       (m_header.m_capacity-1)
    {
        // Verify that the sizes are correct (as would indeed be the case if
        // "a_size" was computed by "memory_size" above):
        if (a_size <= sizeof(header) ||
           (a_size  - sizeof(header)) % sizeof(T) != 0)
            throw std::invalid_argument
                  ("utxx::concurrent_spsc_queue::Ctor: Invalid storage size");

        if (unlikely(StaticCapacity != 0))
            throw std::logic_error
                  ("utxx::concurrent_spsc_queue::Ctor: both static and dynamic "
                   "capacity are specified");
    }

    /// Non-Default Ctor with automatic memory allocation on the heap;
    /// capacity will be rounded to the nearest power of two up to or below
    /// the value specified in the arg. Enabled if the StaticCapacity is 0.
    /// Also, note that the number of usable slots in the queue at any given
    /// time is actually (\a capacity-1), so if you start with an empty queue,
    /// full() will return true after \a capacity-1 insertions.
    ///
    explicit concurrent_spsc_queue(uint32_t a_capacity)
        : m_header     (a_capacity)
        , m_header_ptr (&m_header)
        , m_rec_ptr    (reinterpret_cast<T*>
                       (::malloc(sizeof(T)*m_header.m_count)))
        , m_shared_data(false)
        , m_is_producer(false)   // irrelevant in this case
        , m_mask       (m_header.m_capacity-1)
    {
        if (unlikely(StaticCapacity != 0))
            throw std::logic_error
                  ("utxx::concurrent_spsc_queue::Ctor: both static and dynamic "
                   "capacity are specified");
    }

    /// Default Ctor:
    /// Uses the StaticCapacity template parameter. Always enabled (as there
    /// are no typed arguments), but if StaticCapacity is 0, using this Ctor
    /// will result in a run-time error:
    ///
    concurrent_spsc_queue()
        : m_header     (StaticCapacity)
        , m_header_ptr (&m_header)
        , m_rec_ptr    (&m_records)
        , m_shared_data(false)
        , m_is_producer(false)  // irrelevant in this case
        , m_mask       (m_header.m_capacity-1)
    {}

    /// Dtor:
    /// We need to destruct anything that may still exist in our queue,   XXX
    /// even if the queue space is shared, but only if our role is "consumer"
    /// XXX: no synchronisation is performed at Dtor time, so it is a rerspon-
    /// sibility of the caller to ensure that the Producer is not trying to
    /// write into the queue at the same time:
    ///
    ~concurrent_spsc_queue()
    {
      if (!std::is_trivially_destructible<T>::value &&
          !(m_shared_data && m_is_producer))
          for (uint32_t read = head(), end  = tail();
               read != end;    read = increment(read))
              m_rec_ptr[read].~T();

      // If the memory allocation is dynamic (ie non-shared, non-static), then
      // de-allocate the storage space:
      if (StaticCapacity == 0 && !m_shared_data)
      {
        assert(m_rec_ptr != NULL && m_rec_ptr != &m_records);
        ::free(m_rec_ptr);
      }
    }

    /// Write a T object constructed with the "recordArgs" to the queue.
    /// @return true on success, false when the queue is full:
    /// NB: In particular, this allows us to write a pre-constructed object
    /// into the queue using a Copy or Move ctor:
    ///
    template<class ...Args>
    bool push(Args&&... recordArgs)
    {
        // NB: the side check is for ShM only, and in the debug mode only:
        // must be on the Producer side:
        assert(!m_shared_data || m_is_producer);

        uint32_t t    = tail().load(std::memory_order_relaxed);
        uint32_t next = increment(t);

        if (next != head().load(std::memory_order_acquire))
        {
            new (m_rec_ptr + t) T(std::forward<Args>(recordArgs)...);
            tail().store(next, std::memory_order_release);
            return true;
        }
        // Otherwise: queue is full:
        return false;
    }

    /// Move (or copy) the value at the front of the queue to given variable
    bool pop(T* record)
    {
        // NB: the side check is for ShM only, and in the debug mode only:
        // must be on the Consumer side:
        assert(record != NULL && (!m_shared_data || !m_is_producer));

        uint32_t h = head().load(std::memory_order_relaxed);
        if (h == tail().load(std::memory_order_acquire))
            // queue is empty:
            return false;

        uint32_t next = increment(h);
        *record = std::move(m_rec_ptr[h]);
        m_rec_ptr[h].~T();
        head().store(next, std::memory_order_release);
        return true;
    }

    /// Pointer to the value at the front of the queue (for use in-place) or
    /// nullptr if empty.
    T* peek()
    {
        // NB: the side check is for ShM only, and in the debug mode only:
        // must be on the Consumer side:
        assert(!m_shared_data || !m_is_producer);

        uint32_t h = head().load(std::memory_order_relaxed);
        return
            (h == tail().load(std::memory_order_acquire))
            ? nullptr /* queue is empty */
            : (m_rec_ptr + h);
    }

    /// Pointer to the value at the front of the queue (for use in-place) or
    /// nullptr if empty.
    T const* peek() const
    {
        // NB: the side check is for ShM only, and in the debug mode only:
        // must be on the Consumer side:
        assert(!m_shared_data || !m_is_producer);

        uint32_t h = head().load(std::memory_order_relaxed);
        return
            (h == tail().load(std::memory_order_acquire))
            ? nullptr /* queue is empty */
            : (m_rec_ptr + h);
    }

    /// Pop an element from the front of the queue.
    /// Queue must not be empty!
    void pop()
    {
        // NB: the side check is for ShM only, and in the debug mode only:
        // must be on the Consumer side:
        assert(!m_shared_data || !m_is_producer);

        uint32_t h = head().load(std::memory_order_relaxed);
        assert(h  != tail().load(std::memory_order_acquire));

        uint32_t next = increment(h);
        m_rec_ptr[h].~T();
        head().store(next, std::memory_order_release);
    }

    /// UNSAFE test for the queue being empty (because == is not synchronised):
    bool empty() const
    {
        return head().load(std::memory_order_consume)
            == tail().load(std::memory_order_consume);
    }

    /// UNSAFE test for the queue begin full (because == is not synchronised):
    bool full() const
    {
        uint32_t next =
             increment(tail().load(std::memory_order_consume));
        return next == head().load(std::memory_order_consume);
    }

    /// UNSAFE current count of T objects stored in the queue:
    /// If called by consumer, then true count may be more (because producer may
    ///   be adding items concurrently).
    /// If called by producer, then true count may be less (because consumer may
    ///   be removing items concurrently).
    /// It is undefined to call this from any other thread:
    ///
    uint32_t count() const
    {
        int ret = int(tail().load(std::memory_order_consume))
                - int(head().load(std::memory_order_consume));
        if (ret < 0)
            ret += m_header_ptr->m_capacity;
        assert(ret >= 0);
        return uint32_t(ret);
    }

    //=======================================================================//
    // UNSAFE iterators over the queue:                                      //
    //=======================================================================//
    // No locking is performed by this class, it is a responsibility of the
    // caller!
    //-----------------------------------------------------------------------//
    // The "iterator" class:                                                 //
    //-----------------------------------------------------------------------//
    class iterator
    {
    private:
        uint32_t                  m_ind;
        concurrent_spsc_queue<T>* m_queue;

        // Non-default Ctor is available for use from the outer class only:
        friend class concurrent_spsc_queue<T>;

        iterator(uint32_t ind, concurrent_spsc_queue<T>* queue)
            : m_ind  (ind),
            m_queue(queue)
        {}

    public:
        // Default Ctor: creates an invalid "iterator":
        iterator()
            : m_ind  (0),
            m_queue(nullptr)
        {};
        // Dtor, copy ctor, assignemnt and equality are auto-generated

        // Increment: XXX: no checks are performed on whether the iterator is
        // valid:
        iterator& operator++() { m_ind = m_queue->increment(m_ind); }

        // De-referencing:
        T* operator->() const { return m_queue->m_rec_ptr + m_ind;  }
        T& operator*()  const { return m_queue->m_rec_ptr  [m_ind]; }
    };

    //-----------------------------------------------------------------------//
    // The "const_iterator" class:                                           //
    //-----------------------------------------------------------------------//
    struct const_iterator
    {
    private:
        uint32_t                        m_ind;
        concurrent_spsc_queue<T> const* m_queue;

        // Non-default Ctor is available for use from the outer class only:
        friend class concurrent_spsc_queue<T>;

        const_iterator(uint32_t ind, concurrent_spsc_queue<T> const* queue)
            : m_ind  (ind),
            m_queue(queue)
        {}

    public:
        // Default Ctor: creates an invalid "const_iterator":
        const_iterator()
            : m_ind  (0),
            m_queue(nullptr)
        {};

        // Dtor, copy ctor, assignemnt and equality are auto-generated

        // Increment: XXX: no checks are performed on whether this
        // const_iterator is valid:
        const_iterator& operator++() { m_ind = m_queue->increment(m_ind); }

        // De-referencing:
        T const* operator->() const { return m_queue->m_rec_ptr + m_ind;  }
        T const& operator*()  const { return m_queue->m_rec_ptr  [m_ind]; }
    };

    //-----------------------------------------------------------------------//
    // "*begin" and "*end" iterators:                                        //
    //-----------------------------------------------------------------------//
    // Iterating goes from the oldest to the most recent items, ie from front
    // to back, ie from head (where the items are popped from) to tail (where
    // the items are pushed into):
    //
    // "begin" is non-const because the queue can be modified via the iterator
    // returned:
    iterator begin()
        { return iterator(head().load(), this); }

    // "cbegin":
    const_iterator cbegin() const
        { return iterator(head().load(), this); }

    // "end" is non-const for same reason as "begin":
    iterator end()
        { return iterator(tail().load(), this); }

    // "cend":
    const_iterator cend() const
        { return iterator(tail().load(), this); }

private:
    //=======================================================================//
    // Data Flds:                                                            //
    //=======================================================================//
    header          m_header;
    header*  const  m_header_ptr;   // Ptr to the actual hdr  (mb to m_header)
    T*       const  m_rec_ptr;      // Ptr to the actual data (mb to m_records)
    bool     const  m_shared_data;
    bool     const  m_is_producer;  // Only relevant if "m_shared_data" is set
    uint32_t const  m_mask;
    T               m_records[StaticCapacity];

    //-----------------------------------------------------------------------//
    // Accessors (for internal use only):                                    //
    //-----------------------------------------------------------------------//
    std::atomic<uint32_t>&       head()       { return m_header_ptr->m_head; }
    std::atomic<uint32_t>&       tail()       { return m_header_ptr->m_tail; }
    std::atomic<uint32_t> const& head() const { return m_header_ptr->m_head; }
    std::atomic<uint32_t> const& tail() const { return m_header_ptr->m_tail; }
};

} // namespace utxx

#endif //_UTXX_CONCURRENT_SPSC_QUEUE_HPP_
<|endoftext|>


<commit_before>#include "tablemodelvariablesoptions.h"

#include <boost/foreach.hpp>
#include <sstream>

#include <QSize>

#include "options/optionlist.h"
#include "options/optionterms.h"

#include "utils.h"

using namespace std;

TableModelVariablesOptions::TableModelVariablesOptions(QObject *parent) :
	QAbstractTableModel(parent)
{
	_boundTo = NULL;
}

int TableModelVariablesOptions::rowCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _rows.size();
}

int TableModelVariablesOptions::columnCount(const QModelIndex &parent) const
{
	if (_boundTo == NULL)
		return 0;

	return _boundTo->rowTemplate()->size();
}

QVariant TableModelVariablesOptions::data(const QModelIndex &index, int role) const
{
	if (_boundTo == NULL)
		return QVariant();

	if (index.column() == 0)
	{
		if (role == Qt::DisplayRole)
		{
			OptionTerms *option = static_cast<OptionTerms *>(_rows.at(index.row())->get(0));
			return Term(option->value().front()).asQString();
		}
		else
		{
			return QVariant();
		}
	}
	else
	{
		if (role != Qt::DisplayRole && role != Qt::EditRole)
			return QVariant();

		Option* option = _rows.at(index.row())->get(index.column());
		OptionList *list = dynamic_cast<OptionList *>(option);
		if (list == NULL)
			return QVariant("WTF");

		QString selected = tq(list->value());

		if (role == Qt::DisplayRole)
			return selected;

		QStringList items = tql(list->options());

		QList<QVariant> value;
		value.append(selected);
		value.append(items);

		return value;
	}

}

bool TableModelVariablesOptions::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (_boundTo == NULL)
		return false;

	Options *row = _rows.at(index.row());
	Option  *cell = row->get(index.column());
	OptionList *list = dynamic_cast<OptionList *>(cell);

	if (list == NULL)
		return false;

	string oldValue = list->value();
	string newValue = fq(value.toString());

	if (oldValue != newValue)
	{
		list->setValue(newValue);
		emit dataChanged(index, index);
		_boundTo->setValue(_rows);
	}

	return true;
}

Qt::ItemFlags TableModelVariablesOptions::flags(const QModelIndex &index) const
{
	if (_boundTo == NULL)
		return 0;

	if (index.column() == 0)
		return Qt::ItemIsEnabled;

	return Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

QVariant TableModelVariablesOptions::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (_boundTo == NULL)
		return QVariant();

	if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
	{
		string name;
		Option *option;
		_boundTo->rowTemplate()->get(section, name, option);
		return tq(name);
	}

	if (role == Qt::SizeHintRole && orientation == Qt::Horizontal)
	{
		if (section == 0)
			return QSize(200, -1);
		else
			return QSize(80, -1);
	}

	return QVariant();
}

void TableModelVariablesOptions::setVariables(const Terms &variables)
{
	if (_variables == variables)
		return;

	_variables = variables;

	if (_boundTo == NULL)
		return;

	beginResetModel();

	_rows.clear();

	BOOST_FOREACH(const Term &term, variables)
	{
		Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
		OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
		termCell->setValue(term.scomponents());

		_rows.push_back(row);
	}

	endResetModel();

	_boundTo->setValue(_rows);
}

const Terms &TableModelVariablesOptions::variables() const
{
	return _variables;
}

void TableModelVariablesOptions::bindTo(Option *option)
{
	_boundTo = dynamic_cast<OptionsTable *>(option);

	if (_boundTo != NULL)
	{
		beginResetModel();
		_rows = _boundTo->value();
		endResetModel();
	}
}
<commit_msg>C ANOVAs: Tweaks to default column widths<commit_after>#include "tablemodelvariablesoptions.h"

#include <boost/foreach.hpp>
#include <sstream>

#include <QSize>

#include "options/optionlist.h"
#include "options/optionterms.h"

#include "utils.h"

using namespace std;

TableModelVariablesOptions::TableModelVariablesOptions(QObject *parent) :
	QAbstractTableModel(parent)
{
	_boundTo = NULL;
}

int TableModelVariablesOptions::rowCount(const QModelIndex &) const
{
	if (_boundTo == NULL)
		return 0;

	return _rows.size();
}

int TableModelVariablesOptions::columnCount(const QModelIndex &parent) const
{
	if (_boundTo == NULL)
		return 0;

	return _boundTo->rowTemplate()->size();
}

QVariant TableModelVariablesOptions::data(const QModelIndex &index, int role) const
{
	if (_boundTo == NULL)
		return QVariant();

	if (index.column() == 0)
	{
		if (role == Qt::DisplayRole)
		{
			OptionTerms *option = static_cast<OptionTerms *>(_rows.at(index.row())->get(0));
			return Term(option->value().front()).asQString();
		}
		else
		{
			return QVariant();
		}
	}
	else
	{
		if (role != Qt::DisplayRole && role != Qt::EditRole)
			return QVariant();

		Option* option = _rows.at(index.row())->get(index.column());
		OptionList *list = dynamic_cast<OptionList *>(option);
		if (list == NULL)
			return QVariant("WTF");

		QString selected = tq(list->value());

		if (role == Qt::DisplayRole)
			return selected;

		QStringList items = tql(list->options());

		QList<QVariant> value;
		value.append(selected);
		value.append(items);

		return value;
	}

}

bool TableModelVariablesOptions::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (_boundTo == NULL)
		return false;

	Options *row = _rows.at(index.row());
	Option  *cell = row->get(index.column());
	OptionList *list = dynamic_cast<OptionList *>(cell);

	if (list == NULL)
		return false;

	string oldValue = list->value();
	string newValue = fq(value.toString());

	if (oldValue != newValue)
	{
		list->setValue(newValue);
		emit dataChanged(index, index);
		_boundTo->setValue(_rows);
	}

	return true;
}

Qt::ItemFlags TableModelVariablesOptions::flags(const QModelIndex &index) const
{
	if (_boundTo == NULL)
		return 0;

	if (index.column() == 0)
		return Qt::ItemIsEnabled;

	return Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

QVariant TableModelVariablesOptions::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (_boundTo == NULL)
		return QVariant();

	if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
	{
		string name;
		Option *option;
		_boundTo->rowTemplate()->get(section, name, option);
		return tq(name);
	}

	return QVariant();
}

void TableModelVariablesOptions::setVariables(const Terms &variables)
{
	if (_variables == variables)
		return;

	_variables = variables;

	if (_boundTo == NULL)
		return;

	beginResetModel();

	_rows.clear();

	BOOST_FOREACH(const Term &term, variables)
	{
		Options *row = static_cast<Options *>(_boundTo->rowTemplate()->clone());
		OptionTerms *termCell = static_cast<OptionTerms *>(row->get(0));
		termCell->setValue(term.scomponents());

		_rows.push_back(row);
	}

	endResetModel();

	_boundTo->setValue(_rows);
}

const Terms &TableModelVariablesOptions::variables() const
{
	return _variables;
}

void TableModelVariablesOptions::bindTo(Option *option)
{
	_boundTo = dynamic_cast<OptionsTable *>(option);

	if (_boundTo != NULL)
	{
		beginResetModel();
		_rows = _boundTo->value();
		endResetModel();
	}
}
<|endoftext|>