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

  Program:   Visualization Toolkit
  Module:    vtkInteractorStyleRubberBandZoom.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkInteractorStyleRubberBandZoom.h"

#include "vtkCamera.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkUnsignedCharArray.h"

vtkStandardNewMacro(vtkInteractorStyleRubberBandZoom);

vtkInteractorStyleRubberBandZoom::vtkInteractorStyleRubberBandZoom()
{
  this->StartPosition[0] = this->StartPosition[1] = 0;
  this->EndPosition[0] = this->EndPosition[1] = 0;
  this->Moving = 0;
  this->PixelArray = vtkUnsignedCharArray::New();
}

vtkInteractorStyleRubberBandZoom::~vtkInteractorStyleRubberBandZoom()
{
  this->PixelArray->Delete();
}

void vtkInteractorStyleRubberBandZoom::OnMouseMove()
{
  if (!this->Interactor || !this->Moving)
    {
    return;
    }

  this->EndPosition[0] = this->Interactor->GetEventPosition()[0];
  this->EndPosition[1] = this->Interactor->GetEventPosition()[1];
  int *size = this->Interactor->GetRenderWindow()->GetSize();
  if (this->EndPosition[0] > (size[0]-1))
    {
    this->EndPosition[0] = size[0]-1;
    }
  if (this->EndPosition[0] < 0)
    {
    this->EndPosition[0] = 0;
    }
  if (this->EndPosition[1] > (size[1]-1))
    {
    this->EndPosition[1] = size[1]-1;
    }
  if (this->EndPosition[1] < 0)
    {
    this->EndPosition[1] = 0;
    }

  vtkUnsignedCharArray *tmpPixelArray = vtkUnsignedCharArray::New();
  tmpPixelArray->DeepCopy(this->PixelArray);

  unsigned char *pixels = tmpPixelArray->GetPointer(0);

  int min[2], max[2];
  min[0] = this->StartPosition[0] <= this->EndPosition[0] ?
    this->StartPosition[0] : this->EndPosition[0];
  min[1] = this->StartPosition[1] <= this->EndPosition[1] ?
    this->StartPosition[1] : this->EndPosition[1];
  max[0] = this->EndPosition[0] > this->StartPosition[0] ?
    this->EndPosition[0] : this->StartPosition[0];
  max[1] = this->EndPosition[1] > this->StartPosition[1] ?
    this->EndPosition[1] : this->StartPosition[1];

  int i;
  for (i = min[0]; i <= max[0]; i++)
    {
    pixels[3*(min[1]*size[0]+i)] = 255 ^ pixels[3*(min[1]*size[0]+i)];
    pixels[3*(min[1]*size[0]+i)+1] = 255 ^ pixels[3*(min[1]*size[0]+i)+1];
    pixels[3*(min[1]*size[0]+i)+2] = 255 ^ pixels[3*(min[1]*size[0]+i)+2];
    pixels[3*(max[1]*size[0]+i)] = 255 ^ pixels[3*(max[1]*size[0]+i)];
    pixels[3*(max[1]*size[0]+i)+1] = 255 ^ pixels[3*(max[1]*size[0]+i)+1];
    pixels[3*(max[1]*size[0]+i)+2] = 255 ^ pixels[3*(max[1]*size[0]+i)+2];
    }
  for (i = min[1]+1; i < max[1]; i++)
    {
    pixels[3*(i*size[0]+min[0])] = 255 ^ pixels[3*(i*size[0]+min[0])];
    pixels[3*(i*size[0]+min[0])+1] = 255 ^ pixels[3*(i*size[0]+min[0])+1];
    pixels[3*(i*size[0]+min[0])+2] = 255 ^ pixels[3*(i*size[0]+min[0])+2];
    pixels[3*(i*size[0]+max[0])] = 255 ^ pixels[3*(i*size[0]+max[0])];
    pixels[3*(i*size[0]+max[0])+1] = 255 ^ pixels[3*(i*size[0]+max[0])+1];
    pixels[3*(i*size[0]+max[0])+2] = 255 ^ pixels[3*(i*size[0]+max[0])+2];
    }

  this->Interactor->GetRenderWindow()->SetPixelData(0, 0, size[0]-1, size[1]-1, pixels, 1);

  tmpPixelArray->Delete();
}

void vtkInteractorStyleRubberBandZoom::OnLeftButtonDown()
{
  if (!this->Interactor)
    {
    return;
    }
  this->Moving = 1;

  vtkRenderWindow *renWin = this->Interactor->GetRenderWindow();

  this->StartPosition[0] = this->Interactor->GetEventPosition()[0];
  this->StartPosition[1] = this->Interactor->GetEventPosition()[1];
  this->EndPosition[0] = this->StartPosition[0];
  this->EndPosition[1] = this->StartPosition[1];

  this->PixelArray->Initialize();
  this->PixelArray->SetNumberOfComponents(3);
  int *size = renWin->GetSize();
  this->PixelArray->SetNumberOfTuples(size[0]*size[1]);

  renWin->GetPixelData(0, 0, size[0]-1, size[1]-1, 1, this->PixelArray);

  this->FindPokedRenderer(this->StartPosition[0], this->StartPosition[1]);
}

void vtkInteractorStyleRubberBandZoom::OnLeftButtonUp()
{
  if (!this->Interactor || !this->Moving)
    {
    return;
    }

  if (   (this->StartPosition[0] != this->EndPosition[0])
      || (this->StartPosition[1] != this->EndPosition[1]) )
    {
    this->Zoom();
    }
  this->Moving = 0;
}

void vtkInteractorStyleRubberBandZoom::Zoom()
{
  int width, height;
  width = abs(this->EndPosition[0] - this->StartPosition[0]);
  height = abs(this->EndPosition[1] - this->StartPosition[1]);
  int *size = this->CurrentRenderer->GetSize();
  int *origin = this->CurrentRenderer->GetOrigin();
  vtkCamera *cam = this->CurrentRenderer->GetActiveCamera();

  int min[2];
  double rbcenter[3];
  min[0] = this->StartPosition[0] < this->EndPosition[0] ?
    this->StartPosition[0] : this->EndPosition[0];
  min[1] = this->StartPosition[1] < this->EndPosition[1] ?
    this->StartPosition[1] : this->EndPosition[1];

  rbcenter[0] = min[0] + 0.5*width;
  rbcenter[1] = min[1] + 0.5*height;
  rbcenter[2] = 0;

  this->CurrentRenderer->SetDisplayPoint(rbcenter);
  this->CurrentRenderer->DisplayToView();
  this->CurrentRenderer->ViewToWorld();

  double invw;
  double worldRBCenter[4];
  this->CurrentRenderer->GetWorldPoint(worldRBCenter);
  invw = 1.0/worldRBCenter[3];
  worldRBCenter[0] *= invw;
  worldRBCenter[1] *= invw;
  worldRBCenter[2] *= invw;

  double winCenter[3];
  winCenter[0] = origin[0] + 0.5*size[0];
  winCenter[1] = origin[1] + 0.5*size[1];
  winCenter[2] = 0;

  this->CurrentRenderer->SetDisplayPoint(winCenter);
  this->CurrentRenderer->DisplayToView();
  this->CurrentRenderer->ViewToWorld();

  double worldWinCenter[4];
  this->CurrentRenderer->GetWorldPoint(worldWinCenter);
  invw = 1.0/worldWinCenter[3];
  worldWinCenter[0] *= invw;
  worldWinCenter[1] *= invw;
  worldWinCenter[2] *= invw;

  double translation[3];
  translation[0] = worldRBCenter[0] - worldWinCenter[0];
  translation[1] = worldRBCenter[1] - worldWinCenter[1];
  translation[2] = worldRBCenter[2] - worldWinCenter[2];

  double pos[3], fp[3];
  cam->GetPosition(pos);
  cam->GetFocalPoint(fp);

  pos[0] += translation[0]; pos[1] += translation[1]; pos[2] += translation[2];
  fp[0] += translation[0];  fp[1] += translation[1];  fp[2] += translation[2];

  cam->SetPosition(pos);
  cam->SetFocalPoint(fp);

  double zoomFactor;
  if (width > height)
    {
    zoomFactor = size[0] / static_cast<double>(width);
    }
  else
    {
    zoomFactor = size[1] / static_cast<double>(height);
    }
  if (cam->GetParallelProjection())
    {
    cam->Zoom(zoomFactor);
    }
  else
    {
    // In perspective mode, zoom in by moving the camera closer.  Because we are
    // moving the camera closer, we have to be careful to try to adjust the
    // clipping planes to best match the actual position they were in before.
    double initialDistance = cam->GetDistance();
    cam->Dolly(zoomFactor);
    double finalDistance = cam->GetDistance();
    double deltaDistance = initialDistance - finalDistance;
    double clippingRange[2];
    cam->GetClippingRange(clippingRange);
    clippingRange[0] -= deltaDistance;
    clippingRange[1] -= deltaDistance;
    // Correct bringing clipping planes too close or behind camera.
    if (clippingRange[1] <= 0.0)
      {
      clippingRange[1] = 0.001;
      }
    // This near plane check comes from vtkRenderer::ResetCameraClippingRange()
    if (clippingRange[0] < 0.001*clippingRange[1])
      {
      clippingRange[0] = 0.001*clippingRange[1];
      }
    cam->SetClippingRange(clippingRange);
    }

  this->Interactor->Render();
}

void vtkInteractorStyleRubberBandZoom::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>Add missing Frame() call on the renderWindow<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkInteractorStyleRubberBandZoom.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkInteractorStyleRubberBandZoom.h"

#include "vtkCamera.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkUnsignedCharArray.h"

vtkStandardNewMacro(vtkInteractorStyleRubberBandZoom);

vtkInteractorStyleRubberBandZoom::vtkInteractorStyleRubberBandZoom()
{
  this->StartPosition[0] = this->StartPosition[1] = 0;
  this->EndPosition[0] = this->EndPosition[1] = 0;
  this->Moving = 0;
  this->PixelArray = vtkUnsignedCharArray::New();
}

vtkInteractorStyleRubberBandZoom::~vtkInteractorStyleRubberBandZoom()
{
  this->PixelArray->Delete();
}

void vtkInteractorStyleRubberBandZoom::OnMouseMove()
{
  if (!this->Interactor || !this->Moving)
    {
    return;
    }

  this->EndPosition[0] = this->Interactor->GetEventPosition()[0];
  this->EndPosition[1] = this->Interactor->GetEventPosition()[1];
  int *size = this->Interactor->GetRenderWindow()->GetSize();
  if (this->EndPosition[0] > (size[0]-1))
    {
    this->EndPosition[0] = size[0]-1;
    }
  if (this->EndPosition[0] < 0)
    {
    this->EndPosition[0] = 0;
    }
  if (this->EndPosition[1] > (size[1]-1))
    {
    this->EndPosition[1] = size[1]-1;
    }
  if (this->EndPosition[1] < 0)
    {
    this->EndPosition[1] = 0;
    }

  vtkUnsignedCharArray *tmpPixelArray = vtkUnsignedCharArray::New();
  tmpPixelArray->DeepCopy(this->PixelArray);

  unsigned char *pixels = tmpPixelArray->GetPointer(0);

  int min[2], max[2];
  min[0] = this->StartPosition[0] <= this->EndPosition[0] ?
    this->StartPosition[0] : this->EndPosition[0];
  min[1] = this->StartPosition[1] <= this->EndPosition[1] ?
    this->StartPosition[1] : this->EndPosition[1];
  max[0] = this->EndPosition[0] > this->StartPosition[0] ?
    this->EndPosition[0] : this->StartPosition[0];
  max[1] = this->EndPosition[1] > this->StartPosition[1] ?
    this->EndPosition[1] : this->StartPosition[1];

  int i;
  for (i = min[0]; i <= max[0]; i++)
    {
    pixels[3*(min[1]*size[0]+i)] = 255 ^ pixels[3*(min[1]*size[0]+i)];
    pixels[3*(min[1]*size[0]+i)+1] = 255 ^ pixels[3*(min[1]*size[0]+i)+1];
    pixels[3*(min[1]*size[0]+i)+2] = 255 ^ pixels[3*(min[1]*size[0]+i)+2];
    pixels[3*(max[1]*size[0]+i)] = 255 ^ pixels[3*(max[1]*size[0]+i)];
    pixels[3*(max[1]*size[0]+i)+1] = 255 ^ pixels[3*(max[1]*size[0]+i)+1];
    pixels[3*(max[1]*size[0]+i)+2] = 255 ^ pixels[3*(max[1]*size[0]+i)+2];
    }
  for (i = min[1]+1; i < max[1]; i++)
    {
    pixels[3*(i*size[0]+min[0])] = 255 ^ pixels[3*(i*size[0]+min[0])];
    pixels[3*(i*size[0]+min[0])+1] = 255 ^ pixels[3*(i*size[0]+min[0])+1];
    pixels[3*(i*size[0]+min[0])+2] = 255 ^ pixels[3*(i*size[0]+min[0])+2];
    pixels[3*(i*size[0]+max[0])] = 255 ^ pixels[3*(i*size[0]+max[0])];
    pixels[3*(i*size[0]+max[0])+1] = 255 ^ pixels[3*(i*size[0]+max[0])+1];
    pixels[3*(i*size[0]+max[0])+2] = 255 ^ pixels[3*(i*size[0]+max[0])+2];
    }

  this->Interactor->GetRenderWindow()->SetPixelData(0, 0, size[0]-1, size[1]-1, pixels, 1);
  this->Interactor->GetRenderWindow()->Frame();

  tmpPixelArray->Delete();
}

void vtkInteractorStyleRubberBandZoom::OnLeftButtonDown()
{
  if (!this->Interactor)
    {
    return;
    }
  this->Moving = 1;

  vtkRenderWindow *renWin = this->Interactor->GetRenderWindow();

  this->StartPosition[0] = this->Interactor->GetEventPosition()[0];
  this->StartPosition[1] = this->Interactor->GetEventPosition()[1];
  this->EndPosition[0] = this->StartPosition[0];
  this->EndPosition[1] = this->StartPosition[1];

  this->PixelArray->Initialize();
  this->PixelArray->SetNumberOfComponents(3);
  int *size = renWin->GetSize();
  this->PixelArray->SetNumberOfTuples(size[0]*size[1]);

  renWin->GetPixelData(0, 0, size[0]-1, size[1]-1, 1, this->PixelArray);

  this->FindPokedRenderer(this->StartPosition[0], this->StartPosition[1]);
}

void vtkInteractorStyleRubberBandZoom::OnLeftButtonUp()
{
  if (!this->Interactor || !this->Moving)
    {
    return;
    }

  if (   (this->StartPosition[0] != this->EndPosition[0])
      || (this->StartPosition[1] != this->EndPosition[1]) )
    {
    this->Zoom();
    }
  this->Moving = 0;
}

void vtkInteractorStyleRubberBandZoom::Zoom()
{
  int width, height;
  width = abs(this->EndPosition[0] - this->StartPosition[0]);
  height = abs(this->EndPosition[1] - this->StartPosition[1]);
  int *size = this->CurrentRenderer->GetSize();
  int *origin = this->CurrentRenderer->GetOrigin();
  vtkCamera *cam = this->CurrentRenderer->GetActiveCamera();

  int min[2];
  double rbcenter[3];
  min[0] = this->StartPosition[0] < this->EndPosition[0] ?
    this->StartPosition[0] : this->EndPosition[0];
  min[1] = this->StartPosition[1] < this->EndPosition[1] ?
    this->StartPosition[1] : this->EndPosition[1];

  rbcenter[0] = min[0] + 0.5*width;
  rbcenter[1] = min[1] + 0.5*height;
  rbcenter[2] = 0;

  this->CurrentRenderer->SetDisplayPoint(rbcenter);
  this->CurrentRenderer->DisplayToView();
  this->CurrentRenderer->ViewToWorld();

  double invw;
  double worldRBCenter[4];
  this->CurrentRenderer->GetWorldPoint(worldRBCenter);
  invw = 1.0/worldRBCenter[3];
  worldRBCenter[0] *= invw;
  worldRBCenter[1] *= invw;
  worldRBCenter[2] *= invw;

  double winCenter[3];
  winCenter[0] = origin[0] + 0.5*size[0];
  winCenter[1] = origin[1] + 0.5*size[1];
  winCenter[2] = 0;

  this->CurrentRenderer->SetDisplayPoint(winCenter);
  this->CurrentRenderer->DisplayToView();
  this->CurrentRenderer->ViewToWorld();

  double worldWinCenter[4];
  this->CurrentRenderer->GetWorldPoint(worldWinCenter);
  invw = 1.0/worldWinCenter[3];
  worldWinCenter[0] *= invw;
  worldWinCenter[1] *= invw;
  worldWinCenter[2] *= invw;

  double translation[3];
  translation[0] = worldRBCenter[0] - worldWinCenter[0];
  translation[1] = worldRBCenter[1] - worldWinCenter[1];
  translation[2] = worldRBCenter[2] - worldWinCenter[2];

  double pos[3], fp[3];
  cam->GetPosition(pos);
  cam->GetFocalPoint(fp);

  pos[0] += translation[0]; pos[1] += translation[1]; pos[2] += translation[2];
  fp[0] += translation[0];  fp[1] += translation[1];  fp[2] += translation[2];

  cam->SetPosition(pos);
  cam->SetFocalPoint(fp);

  double zoomFactor;
  if (width > height)
    {
    zoomFactor = size[0] / static_cast<double>(width);
    }
  else
    {
    zoomFactor = size[1] / static_cast<double>(height);
    }
  if (cam->GetParallelProjection())
    {
    cam->Zoom(zoomFactor);
    }
  else
    {
    // In perspective mode, zoom in by moving the camera closer.  Because we are
    // moving the camera closer, we have to be careful to try to adjust the
    // clipping planes to best match the actual position they were in before.
    double initialDistance = cam->GetDistance();
    cam->Dolly(zoomFactor);
    double finalDistance = cam->GetDistance();
    double deltaDistance = initialDistance - finalDistance;
    double clippingRange[2];
    cam->GetClippingRange(clippingRange);
    clippingRange[0] -= deltaDistance;
    clippingRange[1] -= deltaDistance;
    // Correct bringing clipping planes too close or behind camera.
    if (clippingRange[1] <= 0.0)
      {
      clippingRange[1] = 0.001;
      }
    // This near plane check comes from vtkRenderer::ResetCameraClippingRange()
    if (clippingRange[0] < 0.001*clippingRange[1])
      {
      clippingRange[0] = 0.001*clippingRange[1];
      }
    cam->SetClippingRange(clippingRange);
    }

  this->Interactor->Render();
}

void vtkInteractorStyleRubberBandZoom::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>#include <Fqd.hpp>

using namespace flink;
using namespace eeros::hal;

Fqd::Fqd(std::string id,
					 void* libHandle,
					 std::string device,
					 uint32_t subDeviceNumber,
					 uint32_t channel,
					 double scale,
					 double offset,
					 double rangeMin,
					 double rangeMax,
					 std::string unit,
					 bool getDelta) :
	ScalableInput<double>(id, libHandle, scale, offset, rangeMin, rangeMax, unit), channel(channel), prevPos(0), getDelta(getDelta)
{
	FlinkDevice *dev = FlinkDevice::getDevice(device);
	this->subdeviceHandle = flink_get_subdevice_by_id(dev->getDeviceHandle(), subDeviceNumber);
	reset();
}

double Fqd::get() {
	uint32_t data = 0;
	flink_counter_get_count(subdeviceHandle, channel, &data);
	int16_t newPos = static_cast<uint16_t>(data);
	int16_t deltaPos = newPos - prevPos;
	prevPos = newPos;
	double delta = deltaPos / scale + offset;
	pos += delta;

	if (getDelta)
		return delta;
	else
		return pos;
}

void Fqd::reset() {
	flink_subdevice_reset(subdeviceHandle); // TODO only reset counter, not the subdevice!
	pos = 0;
}

extern "C"{
	eeros::hal::ScalableInput<double> *createFqd(std::string id, void* libHandle, std::string device, uint32_t subDeviceNumber, uint32_t channel, double scale, double offset, double rangeMin, double rangeMax, std::string unit){
		return new flink::Fqd(id, libHandle, device, subDeviceNumber, channel, scale, offset, rangeMin, rangeMax, unit);
	}

	void resetFqd(flink::Fqd *obj){
		obj->reset();
	}
}
<commit_msg>fix reset fqd<commit_after>#include <Fqd.hpp>

using namespace flink;
using namespace eeros::hal;

Fqd::Fqd(std::string id,
					 void* libHandle,
					 std::string device,
					 uint32_t subDeviceNumber,
					 uint32_t channel,
					 double scale,
					 double offset,
					 double rangeMin,
					 double rangeMax,
					 std::string unit,
					 bool getDelta) :
	ScalableInput<double>(id, libHandle, scale, offset, rangeMin, rangeMax, unit), channel(channel), prevPos(0), getDelta(getDelta)
{
	FlinkDevice *dev = FlinkDevice::getDevice(device);
	this->subdeviceHandle = flink_get_subdevice_by_id(dev->getDeviceHandle(), subDeviceNumber);
	reset();
}

double Fqd::get() {
	uint32_t data = 0;
	flink_counter_get_count(subdeviceHandle, channel, &data);
	int16_t newPos = static_cast<uint16_t>(data);
	int16_t deltaPos = newPos - prevPos;
	prevPos = newPos;
	double delta = deltaPos / scale + offset;
	pos += delta;

	if (getDelta)
		return delta;
	else
		return pos;
}

void Fqd::reset() {
	flink_subdevice_reset(subdeviceHandle); // TODO only reset counter, not the subdevice!
	pos = 0;
	prevPos = 0;
}

extern "C"{
	eeros::hal::ScalableInput<double> *createFqd(std::string id, void* libHandle, std::string device, uint32_t subDeviceNumber, uint32_t channel, double scale, double offset, double rangeMin, double rangeMax, std::string unit){
		return new flink::Fqd(id, libHandle, device, subDeviceNumber, channel, scale, offset, rangeMin, rangeMax, unit);
	}

	void resetFqd(flink::Fqd *obj){
		obj->reset();
	}
}
<|endoftext|>


<commit_before>#include "text_shape.hpp"

#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
#include "../drape/glstate.hpp"
#include "../drape/batcher.hpp"
#include "../drape/texture_set_holder.hpp"

#include "../base/math.hpp"
#include "../base/logging.hpp"
#include "../base/stl_add.hpp"
#include "../base/string_utils.hpp"

#include "../std/algorithm.hpp"
#include "../std/vector.hpp"

using m2::PointF;

namespace df
{

namespace
{
  static uint32_t const ListStride = 24;
  static float const realFontSize = 20.0f;

  void SetColor(vector<float> &dst, float const * ar, int index)
  {
    uint32_t const colorArraySize = 4;
    uint32_t const baseListIndex = ListStride * index;
    for (uint32_t i = 0; i < 6; ++i)
      memcpy(&dst[baseListIndex + colorArraySize * i], ar, colorArraySize * sizeof(float));
  }

  template <typename T>
  void QuadStripToList(vector<T> & dst, vector<T> & src, int32_t index)
  {
    static const int32_t dstStride = 6;
    static const int32_t srcStride = 4;
    const int32_t baseDstIndex = index * dstStride;
    const int32_t baseSrcIndex = index * srcStride;

    dst[baseDstIndex] = src[baseSrcIndex];
    dst[baseDstIndex + 1] = src[baseSrcIndex + 1];
    dst[baseDstIndex + 2] = src[baseSrcIndex + 2];
    dst[baseDstIndex + 3] = src[baseSrcIndex + 1];
    dst[baseDstIndex + 4] = src[baseSrcIndex + 3];
    dst[baseDstIndex + 5] = src[baseSrcIndex + 2];
  }

  PointF GetShift(dp::Anchor anchor, float width, float height)
  {
    switch(anchor)
    {
    case dp::Center:      return PointF(-width / 2.0f, -height / 2.0f);
    case dp::Left:        return PointF(0.0f, -height / 2.0f);
    case dp::Right:       return PointF(-width, -height / 2.0f);
    case dp::Top:         return PointF(-width / 2.0f, -height);
    case dp::Bottom:      return PointF(-width / 2.0f, 0);
    case dp::LeftTop:     return PointF(0.0f, -height);
    case dp::RightTop:    return PointF(-width, -height);
    case dp::LeftBottom:  return PointF(0.0f, 0.0f);
    case dp::RightBottom: return PointF(-width, 0.0f);
    default:              return PointF(0.0f, 0.0f);
    }
  }

  struct Vertex
  {
    Vertex() {}
    Vertex(m2::PointF const & pos, m2::PointF const & dir)
      : m_position(pos), m_direction(dir) {}

    Vertex(float posX, float posY, float dirX = 0.0f, float dirY = 0.0f)
      : m_position(posX, posY), m_direction(dirX, dirY) {}

    m2::PointF m_position;
    m2::PointF m_direction;
  };

  struct TexCoord
  {
    TexCoord() {}
    TexCoord(m2::PointF const & tex, float index = 0.0f, float depth = 0.0f)
      : m_texCoord(tex), m_index(index), m_depth(depth) {}

    TexCoord(float texX, float texY, float index = 0.0f, float depth = 0.0f)
      : m_texCoord(texX, texY), m_index(index), m_depth(depth) {}

    m2::PointF m_texCoord;
    float m_index;
    float m_depth;
  };
}

TextShape::TextShape(m2::PointF const & basePoint, TextViewParams const & params)
    : m_basePoint(basePoint),
      m_params(params)
{
}

void TextShape::AddGeometryWithTheSameTextureSet(int setNum, int letterCount, bool auxText,
                          float maxTextLength, PointF const & anchorDelta,
                          RefPointer<Batcher> batcher, RefPointer<TextureSetHolder> textures) const
{
  strings::UniString text;
  float fontSize;
  Color base, outline;
  float needOutline;
  if(auxText)
  {
    text = strings::MakeUniString(m_params.m_secondaryText);
    fontSize = m_params.m_secondaryTextFont.m_size;
    base = m_params.m_secondaryTextFont.m_color;
    outline = m_params.m_secondaryTextFont.m_outlineColor;
    needOutline = m_params.m_secondaryTextFont.m_needOutline;
  }
  else
  {
    text = strings::MakeUniString(m_params.m_primaryText);
    fontSize = m_params.m_primaryTextFont.m_size;
    base = m_params.m_primaryTextFont.m_color;
    outline = m_params.m_primaryTextFont.m_outlineColor;
    needOutline = m_params.m_primaryTextFont.m_needOutline;
  }

  int const numVert = letterCount * 4;
  vector<Vertex> vertex(numVert);
  vector<TexCoord> texture(numVert);

  float stride = 0.0f;
  int textureSet;

  TextureSetHolder::GlyphRegion region;
  for(int i = 0, j = 0 ; i < text.size() ; i++)
  {
    textures->GetGlyphRegion(text[i], region);
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    float const aspect = fontSize / realFontSize;
    advance *= aspect;
    if (region.GetTextureNode().m_textureSet != setNum)
    {
      stride += advance;
      continue;
    }

    textureSet = region.GetTextureNode().m_textureSet;
    m2::RectF const rect = region.GetTexRect();
    float const textureNum = (region.GetTextureNode().m_textureOffset << 1) + needOutline;
    m2::PointU pixelSize;
    region.GetPixelSize(pixelSize);
    float const h = pixelSize.y * aspect;
    float const w = pixelSize.x * aspect;
    yOffset *= aspect;
    xOffset *= aspect;

    PointF const leftBottom(stride - xOffset + anchorDelta.x, yOffset + anchorDelta.y);
    PointF const rightBottom(stride + w - xOffset + anchorDelta.x, yOffset + anchorDelta.y);
    PointF const leftTop(stride - xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);
    PointF const rightTop(stride + w - xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);

    int index = j * 4;
    vertex[index++] = Vertex(m_basePoint, leftTop);
    vertex[index++] = Vertex(m_basePoint, leftBottom);
    vertex[index++] = Vertex(m_basePoint, rightTop);
    vertex[index++] = Vertex(m_basePoint, rightBottom);

    index = j * 4;
    texture[index++] = TexCoord(rect.minX(), rect.maxY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.minX(), rect.minY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.maxX(), rect.maxY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.maxX(), rect.minY(), textureNum, m_params.m_depth);

    j++;
    stride += advance;
  }

  vector<Vertex> vertex2(numVert * 3 / 2);
  vector<TexCoord> texture2(numVert * 3 / 2);
  vector<float> color(numVert * 6);
  vector<float> color2(numVert * 6);

  float clr1[4], clr2[4];
  Convert(base, clr1[0], clr1[1], clr1[2], clr1[3]);
  Convert(outline, clr2[0], clr2[1], clr2[2], clr2[3]);

  for(int i = 0; i < letterCount ; i++)
  {
    QuadStripToList(vertex2, vertex, i);
    QuadStripToList(texture2, texture, i);
    SetColor(color, clr1, i);
    SetColor(color2, clr2, i);
  }

  GLState state(gpu::FONT_PROGRAM, GLState::OverlayLayer);
  state.SetTextureSet(textureSet);
  state.SetBlending(Blending(true));

  AttributeProvider provider(4, 6*letterCount);
  {
    BindingInfo position(1);
    BindingDecl & decl = position.GetBindingDecl(0);
    decl.m_attributeName = "a_position";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(0, position, MakeStackRefPointer((void*)&vertex2[0]));
  }
  {
    BindingInfo texcoord(1);
    BindingDecl & decl = texcoord.GetBindingDecl(0);
    decl.m_attributeName = "a_texcoord";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(1, texcoord, MakeStackRefPointer((void*)&texture2[0]));
  }
  {
    BindingInfo base_color(1);
    BindingDecl & decl = base_color.GetBindingDecl(0);
    decl.m_attributeName = "a_color";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(2, base_color, MakeStackRefPointer((void*)&color[0]));
  }
  {
    BindingInfo outline_color(1);
    BindingDecl & decl = outline_color.GetBindingDecl(0);
    decl.m_attributeName = "a_outline_color";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(3, outline_color, MakeStackRefPointer((void*)&color2[0]));
  }

  float const bbY = m_params.m_primaryTextFont.m_size + m_params.m_secondaryTextFont.m_size;
  OverlayHandle * handle = new SquareHandle(m_params.m_featureID,
                                           m_params.m_anchor,
                                           m_basePoint,
                                           m2::PointD(maxTextLength, bbY),
                                           m_params.m_depth);

  //handle->SetIsVisible(true);

  batcher->InsertTriangleList(state, MakeStackRefPointer(&provider), MovePointer(handle));
}

void TextShape::Draw(RefPointer<Batcher> batcher, RefPointer<TextureSetHolder> textures) const
{
  strings::UniString const text = strings::MakeUniString(m_params.m_primaryText);
  int const size = text.size();
  float const fontSize = m_params.m_primaryTextFont.m_size;
  float textLength = 0.0f;
  int const maxTextureSetCount = textures->GetMaxTextureSet();
  buffer_vector<int, 16> sizes(maxTextureSetCount);

  for (int i = 0 ; i < size ; i++)
  {
    TextureSetHolder::GlyphRegion region;
    textures->GetGlyphRegion(text[i], region);
    ++sizes[region.GetTextureNode().m_textureSet];
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    textLength += advance * fontSize / realFontSize;
  }

  if (m_params.m_secondaryText.empty())
  {
    PointF const anchorDelta = GetShift(m_params.m_anchor, textLength, fontSize) + m_params.m_primaryOffset;
    for(int i = 0; i < maxTextureSetCount ; ++i)
    {
      if (sizes[i])
        AddGeometryWithTheSameTextureSet(i, sizes[i], false, textLength, anchorDelta, batcher, textures);
    }
    return;
  }

  strings::UniString const auxText = strings::MakeUniString(m_params.m_secondaryText);
  int const auxSize = auxText.size();
  float const auxFontSize = m_params.m_secondaryTextFont.m_size;
  float auxTextLength = 0.0f;
  buffer_vector<int, 16> auxSizes(maxTextureSetCount);

  for (int i = 0 ; i < auxSize ; i++)
  {
    TextureSetHolder::GlyphRegion region;
    textures->GetGlyphRegion(auxText[i], region);
    ++auxSizes[region.GetTextureNode().m_textureSet];
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    auxTextLength += advance * auxFontSize / realFontSize;
  }

  float const length = max(textLength, auxTextLength);
  PointF const anchorDelta = GetShift(m_params.m_anchor, length, fontSize + auxFontSize);
  float dx = textLength > auxTextLength ? 0.0f : (auxTextLength - textLength) / 2.0f;
  PointF const textDelta = PointF(dx, auxFontSize) + anchorDelta + m_params.m_primaryOffset;
  dx = textLength > auxTextLength ? (textLength - auxTextLength) / 2.0f : 0.0f;
  PointF const auxTextDelta = PointF(dx, 0.0f) + anchorDelta + m_params.m_primaryOffset;

  for (int i = 0; i < maxTextureSetCount ; ++i)
  {
    if (sizes[i])
      AddGeometryWithTheSameTextureSet(i, sizes[i], false, length, textDelta, batcher, textures);
    if (auxSizes[i])
      AddGeometryWithTheSameTextureSet(i, auxSizes[i], true, length, auxTextDelta, batcher, textures);
  }
}

} //end of df namespace
<commit_msg>fixed xOffset<commit_after>#include "text_shape.hpp"

#include "../drape/shader_def.hpp"
#include "../drape/attribute_provider.hpp"
#include "../drape/glstate.hpp"
#include "../drape/batcher.hpp"
#include "../drape/texture_set_holder.hpp"

#include "../base/math.hpp"
#include "../base/logging.hpp"
#include "../base/stl_add.hpp"
#include "../base/string_utils.hpp"

#include "../std/algorithm.hpp"
#include "../std/vector.hpp"

using m2::PointF;

namespace df
{

namespace
{
  static uint32_t const ListStride = 24;
  static float const realFontSize = 20.0f;

  void SetColor(vector<float> &dst, float const * ar, int index)
  {
    uint32_t const colorArraySize = 4;
    uint32_t const baseListIndex = ListStride * index;
    for (uint32_t i = 0; i < 6; ++i)
      memcpy(&dst[baseListIndex + colorArraySize * i], ar, colorArraySize * sizeof(float));
  }

  template <typename T>
  void QuadStripToList(vector<T> & dst, vector<T> & src, int32_t index)
  {
    static const int32_t dstStride = 6;
    static const int32_t srcStride = 4;
    const int32_t baseDstIndex = index * dstStride;
    const int32_t baseSrcIndex = index * srcStride;

    dst[baseDstIndex] = src[baseSrcIndex];
    dst[baseDstIndex + 1] = src[baseSrcIndex + 1];
    dst[baseDstIndex + 2] = src[baseSrcIndex + 2];
    dst[baseDstIndex + 3] = src[baseSrcIndex + 1];
    dst[baseDstIndex + 4] = src[baseSrcIndex + 3];
    dst[baseDstIndex + 5] = src[baseSrcIndex + 2];
  }

  PointF GetShift(dp::Anchor anchor, float width, float height)
  {
    switch(anchor)
    {
    case dp::Center:      return PointF(-width / 2.0f, -height / 2.0f);
    case dp::Left:        return PointF(0.0f, -height / 2.0f);
    case dp::Right:       return PointF(-width, -height / 2.0f);
    case dp::Top:         return PointF(-width / 2.0f, -height);
    case dp::Bottom:      return PointF(-width / 2.0f, 0);
    case dp::LeftTop:     return PointF(0.0f, -height);
    case dp::RightTop:    return PointF(-width, -height);
    case dp::LeftBottom:  return PointF(0.0f, 0.0f);
    case dp::RightBottom: return PointF(-width, 0.0f);
    default:              return PointF(0.0f, 0.0f);
    }
  }

  struct Vertex
  {
    Vertex() {}
    Vertex(m2::PointF const & pos, m2::PointF const & dir)
      : m_position(pos), m_direction(dir) {}

    Vertex(float posX, float posY, float dirX = 0.0f, float dirY = 0.0f)
      : m_position(posX, posY), m_direction(dirX, dirY) {}

    m2::PointF m_position;
    m2::PointF m_direction;
  };

  struct TexCoord
  {
    TexCoord() {}
    TexCoord(m2::PointF const & tex, float index = 0.0f, float depth = 0.0f)
      : m_texCoord(tex), m_index(index), m_depth(depth) {}

    TexCoord(float texX, float texY, float index = 0.0f, float depth = 0.0f)
      : m_texCoord(texX, texY), m_index(index), m_depth(depth) {}

    m2::PointF m_texCoord;
    float m_index;
    float m_depth;
  };
}

TextShape::TextShape(m2::PointF const & basePoint, TextViewParams const & params)
    : m_basePoint(basePoint),
      m_params(params)
{
}

void TextShape::AddGeometryWithTheSameTextureSet(int setNum, int letterCount, bool auxText,
                          float maxTextLength, PointF const & anchorDelta,
                          RefPointer<Batcher> batcher, RefPointer<TextureSetHolder> textures) const
{
  strings::UniString text;
  float fontSize;
  Color base, outline;
  float needOutline;
  if(auxText)
  {
    text = strings::MakeUniString(m_params.m_secondaryText);
    fontSize = m_params.m_secondaryTextFont.m_size;
    base = m_params.m_secondaryTextFont.m_color;
    outline = m_params.m_secondaryTextFont.m_outlineColor;
    needOutline = m_params.m_secondaryTextFont.m_needOutline;
  }
  else
  {
    text = strings::MakeUniString(m_params.m_primaryText);
    fontSize = m_params.m_primaryTextFont.m_size;
    base = m_params.m_primaryTextFont.m_color;
    outline = m_params.m_primaryTextFont.m_outlineColor;
    needOutline = m_params.m_primaryTextFont.m_needOutline;
  }

  int const numVert = letterCount * 4;
  vector<Vertex> vertex(numVert);
  vector<TexCoord> texture(numVert);

  float stride = 0.0f;
  int textureSet;

  TextureSetHolder::GlyphRegion region;
  for(int i = 0, j = 0 ; i < text.size() ; i++)
  {
    textures->GetGlyphRegion(text[i], region);
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    float const aspect = fontSize / realFontSize;
    advance *= aspect;
    if (region.GetTextureNode().m_textureSet != setNum)
    {
      stride += advance;
      continue;
    }

    textureSet = region.GetTextureNode().m_textureSet;
    m2::RectF const rect = region.GetTexRect();
    float const textureNum = (region.GetTextureNode().m_textureOffset << 1) + needOutline;
    m2::PointU pixelSize;
    region.GetPixelSize(pixelSize);
    float const h = pixelSize.y * aspect;
    float const w = pixelSize.x * aspect;
    yOffset *= aspect;
    xOffset *= aspect;

    PointF const leftBottom(stride + xOffset + anchorDelta.x, yOffset + anchorDelta.y);
    PointF const rightBottom(stride + w + xOffset + anchorDelta.x, yOffset + anchorDelta.y);
    PointF const leftTop(stride + xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);
    PointF const rightTop(stride + w + xOffset + anchorDelta.x, yOffset + h + anchorDelta.y);

    int index = j * 4;
    vertex[index++] = Vertex(m_basePoint, leftTop);
    vertex[index++] = Vertex(m_basePoint, leftBottom);
    vertex[index++] = Vertex(m_basePoint, rightTop);
    vertex[index++] = Vertex(m_basePoint, rightBottom);

    index = j * 4;
    texture[index++] = TexCoord(rect.minX(), rect.maxY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.minX(), rect.minY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.maxX(), rect.maxY(), textureNum, m_params.m_depth);
    texture[index++] = TexCoord(rect.maxX(), rect.minY(), textureNum, m_params.m_depth);

    j++;
    stride += advance;
  }

  vector<Vertex> vertex2(numVert * 3 / 2);
  vector<TexCoord> texture2(numVert * 3 / 2);
  vector<float> color(numVert * 6);
  vector<float> color2(numVert * 6);

  float clr1[4], clr2[4];
  Convert(base, clr1[0], clr1[1], clr1[2], clr1[3]);
  Convert(outline, clr2[0], clr2[1], clr2[2], clr2[3]);

  for(int i = 0; i < letterCount ; i++)
  {
    QuadStripToList(vertex2, vertex, i);
    QuadStripToList(texture2, texture, i);
    SetColor(color, clr1, i);
    SetColor(color2, clr2, i);
  }

  GLState state(gpu::FONT_PROGRAM, GLState::OverlayLayer);
  state.SetTextureSet(textureSet);
  state.SetBlending(Blending(true));

  AttributeProvider provider(4, 6*letterCount);
  {
    BindingInfo position(1);
    BindingDecl & decl = position.GetBindingDecl(0);
    decl.m_attributeName = "a_position";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(0, position, MakeStackRefPointer((void*)&vertex2[0]));
  }
  {
    BindingInfo texcoord(1);
    BindingDecl & decl = texcoord.GetBindingDecl(0);
    decl.m_attributeName = "a_texcoord";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(1, texcoord, MakeStackRefPointer((void*)&texture2[0]));
  }
  {
    BindingInfo base_color(1);
    BindingDecl & decl = base_color.GetBindingDecl(0);
    decl.m_attributeName = "a_color";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(2, base_color, MakeStackRefPointer((void*)&color[0]));
  }
  {
    BindingInfo outline_color(1);
    BindingDecl & decl = outline_color.GetBindingDecl(0);
    decl.m_attributeName = "a_outline_color";
    decl.m_componentCount = 4;
    decl.m_componentType = gl_const::GLFloatType;
    decl.m_offset = 0;
    decl.m_stride = 0;
    provider.InitStream(3, outline_color, MakeStackRefPointer((void*)&color2[0]));
  }

  float const bbY = m_params.m_primaryTextFont.m_size + m_params.m_secondaryTextFont.m_size;
  OverlayHandle * handle = new SquareHandle(m_params.m_featureID,
                                           m_params.m_anchor,
                                           m_basePoint,
                                           m2::PointD(maxTextLength, bbY),
                                           m_params.m_depth);

  //handle->SetIsVisible(true);

  batcher->InsertTriangleList(state, MakeStackRefPointer(&provider), MovePointer(handle));
}

void TextShape::Draw(RefPointer<Batcher> batcher, RefPointer<TextureSetHolder> textures) const
{
  strings::UniString const text = strings::MakeUniString(m_params.m_primaryText);
  int const size = text.size();
  float const fontSize = m_params.m_primaryTextFont.m_size;
  float textLength = 0.0f;
  int const maxTextureSetCount = textures->GetMaxTextureSet();
  buffer_vector<int, 16> sizes(maxTextureSetCount);

  for (int i = 0 ; i < size ; i++)
  {
    TextureSetHolder::GlyphRegion region;
    textures->GetGlyphRegion(text[i], region);
    ++sizes[region.GetTextureNode().m_textureSet];
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    textLength += advance * fontSize / realFontSize;
  }

  if (m_params.m_secondaryText.empty())
  {
    PointF const anchorDelta = GetShift(m_params.m_anchor, textLength, fontSize) + m_params.m_primaryOffset;
    for(int i = 0; i < maxTextureSetCount ; ++i)
    {
      if (sizes[i])
        AddGeometryWithTheSameTextureSet(i, sizes[i], false, textLength, anchorDelta, batcher, textures);
    }
    return;
  }

  strings::UniString const auxText = strings::MakeUniString(m_params.m_secondaryText);
  int const auxSize = auxText.size();
  float const auxFontSize = m_params.m_secondaryTextFont.m_size;
  float auxTextLength = 0.0f;
  buffer_vector<int, 16> auxSizes(maxTextureSetCount);

  for (int i = 0 ; i < auxSize ; i++)
  {
    TextureSetHolder::GlyphRegion region;
    textures->GetGlyphRegion(auxText[i], region);
    ++auxSizes[region.GetTextureNode().m_textureSet];
    float xOffset, yOffset, advance;
    region.GetMetrics(xOffset, yOffset, advance);
    auxTextLength += advance * auxFontSize / realFontSize;
  }

  float const length = max(textLength, auxTextLength);
  PointF const anchorDelta = GetShift(m_params.m_anchor, length, fontSize + auxFontSize);
  float dx = textLength > auxTextLength ? 0.0f : (auxTextLength - textLength) / 2.0f;
  PointF const textDelta = PointF(dx, auxFontSize) + anchorDelta + m_params.m_primaryOffset;
  dx = textLength > auxTextLength ? (textLength - auxTextLength) / 2.0f : 0.0f;
  PointF const auxTextDelta = PointF(dx, 0.0f) + anchorDelta + m_params.m_primaryOffset;

  for (int i = 0; i < maxTextureSetCount ; ++i)
  {
    if (sizes[i])
      AddGeometryWithTheSameTextureSet(i, sizes[i], false, length, textDelta, batcher, textures);
    if (auxSizes[i])
      AddGeometryWithTheSameTextureSet(i, auxSizes[i], true, length, auxTextDelta, batcher, textures);
  }
}

} //end of df namespace
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file implements the ViewGLContext and PbufferGLContext classes.

#include <dlfcn.h>
#include <GL/glew.h>
#include <GL/glxew.h>
#include <GL/glx.h>
#include <GL/osmew.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "app/x11_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "app/gfx/gl/gl_context.h"
#include "app/gfx/gl/gl_context_osmesa.h"

namespace gfx {

typedef GLXContext GLContextHandle;
typedef GLXPbuffer PbufferHandle;

// This class is a wrapper around a GL context that renders directly to a
// window.
class ViewGLContext : public GLContext {
 public:
  explicit ViewGLContext(gfx::PluginWindowHandle window)
      : window_(window),
        context_(NULL) {
    DCHECK(window);
  }

  // Initializes the GL context.
  bool Initialize(bool multisampled);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  gfx::PluginWindowHandle window_;
  GLContextHandle context_;

  DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
};

// This class is a wrapper around a GL context used for offscreen rendering.
// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
// rendering.
class PbufferGLContext : public GLContext {
 public:
  explicit PbufferGLContext()
      : context_(NULL),
        pbuffer_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  PbufferHandle pbuffer_;

  DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
};

// Backup context if Pbuffers (GLX 1.3) aren't supported. May run slower...
class PixmapGLContext : public GLContext {
 public:
  explicit PixmapGLContext()
      : context_(NULL),
        pixmap_(0),
        glx_pixmap_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  Pixmap pixmap_;
  GLXPixmap glx_pixmap_;

  DISALLOW_COPY_AND_ASSIGN(PixmapGLContext);
};

// scoped_ptr functor for XFree(). Use as follows:
//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
class ScopedPtrXFree {
 public:
  void operator()(void* x) const {
    ::XFree(x);
  }
};

// Some versions of NVIDIA's GL libGL.so include a broken version of
// dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
// load it, and use glew to dynamically resolve symbols.
// See http://code.google.com/p/chromium/issues/detail?id=16800

static bool InitializeOneOff() {
  static bool initialized = false;
  if (initialized)
    return true;

  osmewInit();
  if (!OSMesaCreateContext) {
    void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle) {
      LOG(ERROR) << "Could not find libGL.so.1";
      return false;
    }

    // Initializes context-independent parts of GLEW
    if (glxewInit() != GLEW_OK) {
      LOG(ERROR) << "glxewInit failed";
      return false;
    }
    // glxewContextInit really only needs a display connection to
    // complete, and we don't want to have to create an OpenGL context
    // just to get access to GLX 1.3 entry points to create pbuffers.
    // We therefore added a glxewContextInitWithDisplay entry point.
    Display* display = x11_util::GetXDisplay();
    if (glxewContextInitWithDisplay(display) != GLEW_OK) {
      LOG(ERROR) << "glxewContextInit failed";
      return false;
    }
  }

  initialized = true;
  return true;
}

bool ViewGLContext::Initialize(bool multisampled) {
  if (multisampled) {
    LOG(WARNING) << "Multisampling not implemented.";
  }

  Display* display = x11_util::GetXDisplay();
  XWindowAttributes attributes;
  XGetWindowAttributes(display, window_, &attributes);
  XVisualInfo visual_info_template;
  visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
  int visual_info_count = 0;
  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
      XGetVisualInfo(display, VisualIDMask,
                     &visual_info_template,
                     &visual_info_count));
  DCHECK(visual_info_list.get());
  DCHECK_GT(visual_info_count, 0);
  context_ = NULL;
  for (int i = 0; i < visual_info_count; ++i) {
    context_ = glXCreateContext(display, visual_info_list.get() + i, 0, True);
    if (context_)
      break;
  }
  if (!context_) {
    LOG(ERROR) << "Couldn't create GL context.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void ViewGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);

  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }
}

bool ViewGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }

  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, window_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = 0;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool ViewGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == window_ &&
      glXGetCurrentContext() == context_;
}

bool ViewGLContext::IsOffscreen() {
  return false;
}

void ViewGLContext::SwapBuffers() {
  Display* display = x11_util::GetXDisplay();
  glXSwapBuffers(display, window_);
}

gfx::Size ViewGLContext::GetSize() {
  XWindowAttributes attributes;
  Display* display = x11_util::GetXDisplay();
  XGetWindowAttributes(display, window_, &attributes);
  return gfx::Size(attributes.width, attributes.height);
}

void* ViewGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
                                          bool multisampled) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    // TODO(apatrick): Support OSMesa rendering to a window on Linux.
    NOTREACHED() << "OSMesa rendering to a window is not yet implemented.";
    return NULL;
  } else {
    scoped_ptr<ViewGLContext> context(new ViewGLContext(window));

    if (!context->Initialize(multisampled))
      return NULL;

    return context.release();
  }
}

bool PbufferGLContext::Initialize(void* shared_handle) {
  if (!glXChooseFBConfig ||
      !glXCreateNewContext ||
      !glXCreatePbuffer ||
      !glXDestroyPbuffer) {
    LOG(ERROR) << "Pbuffer support not available.";
    return false;
  }

  static const int config_attributes[] = {
    GLX_DRAWABLE_TYPE,
    GLX_PBUFFER_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,
    0,
    0
  };

  Display* display = x11_util::GetXDisplay();

  int nelements = 0;
  // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
      glXChooseFBConfig(display, 0, config_attributes, &nelements));
  if (!config.get()) {
    LOG(ERROR) << "glXChooseFBConfig failed.";
    return false;
  }
  if (!nelements) {
    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
    return false;
  }
  context_ = glXCreateNewContext(display,
                                 config.get()[0],
                                 GLX_RGBA_TYPE,
                                 static_cast<GLContextHandle>(shared_handle),
                                 True);
  if (!context_) {
    LOG(ERROR) << "glXCreateNewContext failed.";
    return false;
  }
  static const int pbuffer_attributes[] = {
    GLX_PBUFFER_WIDTH,
    1,
    GLX_PBUFFER_HEIGHT,
    1,
    0
  };
  pbuffer_ = glXCreatePbuffer(display,
                              config.get()[0], pbuffer_attributes);
  if (!pbuffer_) {
    Destroy();
    LOG(ERROR) << "glXCreatePbuffer failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PbufferGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (pbuffer_) {
    glXDestroyPbuffer(display, pbuffer_);
    pbuffer_ = 0;
  }
}

bool PbufferGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, pbuffer_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PbufferGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == pbuffer_ &&
      glXGetCurrentContext() == context_;
}

bool PbufferGLContext::IsOffscreen() {
  return true;
}

void PbufferGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
}

gfx::Size PbufferGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pbuffer.";
  return gfx::Size(1, 1);
}

void* PbufferGLContext::GetHandle() {
  return context_;
}

bool PixmapGLContext::Initialize(void* shared_handle) {
  LOG(INFO) << "GL context: using pixmaps.";
  if (!glXChooseVisual ||
      !glXCreateGLXPixmap ||
      !glXDestroyGLXPixmap) {
    LOG(ERROR) << "Pixmap support not available.";
    return false;
  }

  static int attributes[] = {
    GLX_RGBA,
    0
  };

  Display* display = x11_util::GetXDisplay();
  int screen = DefaultScreen(display);

  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info(
      glXChooseVisual(display, screen, attributes));

  if (!visual_info.get()) {
    LOG(ERROR) << "glXChooseVisual failed.";
    return false;
  }
  context_ = glXCreateContext(display, visual_info.get(),
                              static_cast<GLContextHandle>(shared_handle),
                              True);
  if (!context_) {
    LOG(ERROR) << "glXCreateContext failed.";
    return false;
  }

  pixmap_ = XCreatePixmap(display, RootWindow(display, screen), 1, 1,
                          visual_info->depth);
  if (!pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  glx_pixmap_ = glXCreateGLXPixmap(display, visual_info.get(), pixmap_);
  if (!glx_pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PixmapGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (glx_pixmap_) {
    glXDestroyGLXPixmap(display, glx_pixmap_);
    glx_pixmap_ = 0;
  }

  if (pixmap_) {
    XFreePixmap(display, pixmap_);
    pixmap_ = 0;
  }
}

bool PixmapGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, glx_pixmap_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PixmapGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == glx_pixmap_ &&
      glXGetCurrentContext() == context_;
}

bool PixmapGLContext::IsOffscreen() {
  return true;
}

void PixmapGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pixmap.";
}

gfx::Size PixmapGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pixmap.";
  return gfx::Size(1, 1);
}

void* PixmapGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);

    if (!context->Initialize(shared_handle))
      return NULL;

    return context.release();
  } else {
    scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
    if (context->Initialize(shared_handle))
      return context.release();

    scoped_ptr<PixmapGLContext> context_pixmap(new PixmapGLContext);
    if (context_pixmap->Initialize(shared_handle))
      return context_pixmap.release();

    return NULL;
  }
}

}  // namespace gfx
<commit_msg>Added warning if GLX version is less than 1.3. Pbuffers need GLX 1.3 and the pixmap fallback for 1.2 does not work on all systems. TEST=try BUG=none<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file implements the ViewGLContext and PbufferGLContext classes.

#include <dlfcn.h>
#include <GL/glew.h>
#include <GL/glxew.h>
#include <GL/glx.h>
#include <GL/osmew.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "app/x11_util.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "app/gfx/gl/gl_context.h"
#include "app/gfx/gl/gl_context_osmesa.h"

namespace gfx {

typedef GLXContext GLContextHandle;
typedef GLXPbuffer PbufferHandle;

// This class is a wrapper around a GL context that renders directly to a
// window.
class ViewGLContext : public GLContext {
 public:
  explicit ViewGLContext(gfx::PluginWindowHandle window)
      : window_(window),
        context_(NULL) {
    DCHECK(window);
  }

  // Initializes the GL context.
  bool Initialize(bool multisampled);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  gfx::PluginWindowHandle window_;
  GLContextHandle context_;

  DISALLOW_COPY_AND_ASSIGN(ViewGLContext);
};

// This class is a wrapper around a GL context used for offscreen rendering.
// It is initially backed by a 1x1 pbuffer. Use it to create an FBO to do useful
// rendering.
class PbufferGLContext : public GLContext {
 public:
  explicit PbufferGLContext()
      : context_(NULL),
        pbuffer_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  PbufferHandle pbuffer_;

  DISALLOW_COPY_AND_ASSIGN(PbufferGLContext);
};

// Backup context if Pbuffers (GLX 1.3) aren't supported. May run slower...
class PixmapGLContext : public GLContext {
 public:
  explicit PixmapGLContext()
      : context_(NULL),
        pixmap_(0),
        glx_pixmap_(0) {
  }

  // Initializes the GL context.
  bool Initialize(void* shared_handle);

  virtual void Destroy();
  virtual bool MakeCurrent();
  virtual bool IsCurrent();
  virtual bool IsOffscreen();
  virtual void SwapBuffers();
  virtual gfx::Size GetSize();
  virtual void* GetHandle();

 private:
  GLContextHandle context_;
  Pixmap pixmap_;
  GLXPixmap glx_pixmap_;

  DISALLOW_COPY_AND_ASSIGN(PixmapGLContext);
};

// scoped_ptr functor for XFree(). Use as follows:
//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
// where "XVisualInfo" is any X type that is freed with XFree.
class ScopedPtrXFree {
 public:
  void operator()(void* x) const {
    ::XFree(x);
  }
};

// Some versions of NVIDIA's GL libGL.so include a broken version of
// dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
// load it, and use glew to dynamically resolve symbols.
// See http://code.google.com/p/chromium/issues/detail?id=16800

static bool InitializeOneOff() {
  static bool initialized = false;
  if (initialized)
    return true;

  osmewInit();
  if (!OSMesaCreateContext) {
    void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle) {
      LOG(ERROR) << "Could not find libGL.so.1";
      return false;
    }

    // Initializes context-independent parts of GLEW
    if (glxewInit() != GLEW_OK) {
      LOG(ERROR) << "glxewInit failed";
      return false;
    }
    // glxewContextInit really only needs a display connection to
    // complete, and we don't want to have to create an OpenGL context
    // just to get access to GLX 1.3 entry points to create pbuffers.
    // We therefore added a glxewContextInitWithDisplay entry point.
    Display* display = x11_util::GetXDisplay();
    if (glxewContextInitWithDisplay(display) != GLEW_OK) {
      LOG(ERROR) << "glxewContextInit failed";
      return false;
    }

    int major, minor;
    if (!glXQueryVersion(display, &major, &minor)) {
      LOG(ERROR) << "glxQueryVersion failed";
      return false;
    }

    if (major == 1 && minor < 3) {
      LOG(WARNING) << "GLX 1.3 or later is recommended.";
    }
  }

  initialized = true;
  return true;
}

bool ViewGLContext::Initialize(bool multisampled) {
  if (multisampled) {
    LOG(WARNING) << "Multisampling not implemented.";
  }

  Display* display = x11_util::GetXDisplay();
  XWindowAttributes attributes;
  XGetWindowAttributes(display, window_, &attributes);
  XVisualInfo visual_info_template;
  visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
  int visual_info_count = 0;
  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
      XGetVisualInfo(display, VisualIDMask,
                     &visual_info_template,
                     &visual_info_count));
  DCHECK(visual_info_list.get());
  DCHECK_GT(visual_info_count, 0);
  context_ = NULL;
  for (int i = 0; i < visual_info_count; ++i) {
    context_ = glXCreateContext(display, visual_info_list.get() + i, 0, True);
    if (context_)
      break;
  }
  if (!context_) {
    LOG(ERROR) << "Couldn't create GL context.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void ViewGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);

  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }
}

bool ViewGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }

  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, window_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = 0;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool ViewGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == window_ &&
      glXGetCurrentContext() == context_;
}

bool ViewGLContext::IsOffscreen() {
  return false;
}

void ViewGLContext::SwapBuffers() {
  Display* display = x11_util::GetXDisplay();
  glXSwapBuffers(display, window_);
}

gfx::Size ViewGLContext::GetSize() {
  XWindowAttributes attributes;
  Display* display = x11_util::GetXDisplay();
  XGetWindowAttributes(display, window_, &attributes);
  return gfx::Size(attributes.width, attributes.height);
}

void* ViewGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateViewGLContext(gfx::PluginWindowHandle window,
                                          bool multisampled) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    // TODO(apatrick): Support OSMesa rendering to a window on Linux.
    NOTREACHED() << "OSMesa rendering to a window is not yet implemented.";
    return NULL;
  } else {
    scoped_ptr<ViewGLContext> context(new ViewGLContext(window));

    if (!context->Initialize(multisampled))
      return NULL;

    return context.release();
  }
}

bool PbufferGLContext::Initialize(void* shared_handle) {
  if (!glXChooseFBConfig ||
      !glXCreateNewContext ||
      !glXCreatePbuffer ||
      !glXDestroyPbuffer) {
    LOG(ERROR) << "Pbuffer support not available.";
    return false;
  }

  static const int config_attributes[] = {
    GLX_DRAWABLE_TYPE,
    GLX_PBUFFER_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,
    0,
    0
  };

  Display* display = x11_util::GetXDisplay();

  int nelements = 0;
  // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient.
  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config(
      glXChooseFBConfig(display, 0, config_attributes, &nelements));
  if (!config.get()) {
    LOG(ERROR) << "glXChooseFBConfig failed.";
    return false;
  }
  if (!nelements) {
    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
    return false;
  }
  context_ = glXCreateNewContext(display,
                                 config.get()[0],
                                 GLX_RGBA_TYPE,
                                 static_cast<GLContextHandle>(shared_handle),
                                 True);
  if (!context_) {
    LOG(ERROR) << "glXCreateNewContext failed.";
    return false;
  }
  static const int pbuffer_attributes[] = {
    GLX_PBUFFER_WIDTH,
    1,
    GLX_PBUFFER_HEIGHT,
    1,
    0
  };
  pbuffer_ = glXCreatePbuffer(display,
                              config.get()[0], pbuffer_attributes);
  if (!pbuffer_) {
    Destroy();
    LOG(ERROR) << "glXCreatePbuffer failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PbufferGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (pbuffer_) {
    glXDestroyPbuffer(display, pbuffer_);
    pbuffer_ = 0;
  }
}

bool PbufferGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, pbuffer_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PbufferGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == pbuffer_ &&
      glXGetCurrentContext() == context_;
}

bool PbufferGLContext::IsOffscreen() {
  return true;
}

void PbufferGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
}

gfx::Size PbufferGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pbuffer.";
  return gfx::Size(1, 1);
}

void* PbufferGLContext::GetHandle() {
  return context_;
}

bool PixmapGLContext::Initialize(void* shared_handle) {
  LOG(INFO) << "GL context: using pixmaps.";
  if (!glXChooseVisual ||
      !glXCreateGLXPixmap ||
      !glXDestroyGLXPixmap) {
    LOG(ERROR) << "Pixmap support not available.";
    return false;
  }

  static int attributes[] = {
    GLX_RGBA,
    0
  };

  Display* display = x11_util::GetXDisplay();
  int screen = DefaultScreen(display);

  scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info(
      glXChooseVisual(display, screen, attributes));

  if (!visual_info.get()) {
    LOG(ERROR) << "glXChooseVisual failed.";
    return false;
  }
  context_ = glXCreateContext(display, visual_info.get(),
                              static_cast<GLContextHandle>(shared_handle),
                              True);
  if (!context_) {
    LOG(ERROR) << "glXCreateContext failed.";
    return false;
  }

  pixmap_ = XCreatePixmap(display, RootWindow(display, screen), 1, 1,
                          visual_info->depth);
  if (!pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  glx_pixmap_ = glXCreateGLXPixmap(display, visual_info.get(), pixmap_);
  if (!glx_pixmap_) {
    LOG(ERROR) << "XCreatePixmap failed.";
    return false;
  }

  if (!MakeCurrent()) {
    Destroy();
    LOG(ERROR) << "Couldn't make context current for initialization.";
    return false;
  }

  if (!InitializeGLEW()) {
    Destroy();
    return false;
  }

  if (!InitializeCommon()) {
    Destroy();
    return false;
  }

  return true;
}

void PixmapGLContext::Destroy() {
  Display* display = x11_util::GetXDisplay();
  Bool result = glXMakeCurrent(display, 0, 0);
  // glXMakeCurrent isn't supposed to fail when unsetting the context, unless
  // we have pending draws on an invalid window - which shouldn't be the case
  // here.
  DCHECK(result);
  if (context_) {
    glXDestroyContext(display, context_);
    context_ = NULL;
  }

  if (glx_pixmap_) {
    glXDestroyGLXPixmap(display, glx_pixmap_);
    glx_pixmap_ = 0;
  }

  if (pixmap_) {
    XFreePixmap(display, pixmap_);
    pixmap_ = 0;
  }
}

bool PixmapGLContext::MakeCurrent() {
  if (IsCurrent()) {
    return true;
  }
  Display* display = x11_util::GetXDisplay();
  if (glXMakeCurrent(display, glx_pixmap_, context_) != True) {
    glXDestroyContext(display, context_);
    context_ = NULL;
    LOG(ERROR) << "Couldn't make context current.";
    return false;
  }

  return true;
}

bool PixmapGLContext::IsCurrent() {
  return glXGetCurrentDrawable() == glx_pixmap_ &&
      glXGetCurrentContext() == context_;
}

bool PixmapGLContext::IsOffscreen() {
  return true;
}

void PixmapGLContext::SwapBuffers() {
  NOTREACHED() << "Attempted to call SwapBuffers on a pixmap.";
}

gfx::Size PixmapGLContext::GetSize() {
  NOTREACHED() << "Should not be requesting size of this pixmap.";
  return gfx::Size(1, 1);
}

void* PixmapGLContext::GetHandle() {
  return context_;
}

GLContext* GLContext::CreateOffscreenGLContext(void* shared_handle) {
  if (!InitializeOneOff())
    return NULL;

  if (OSMesaCreateContext) {
    scoped_ptr<OSMesaGLContext> context(new OSMesaGLContext);

    if (!context->Initialize(shared_handle))
      return NULL;

    return context.release();
  } else {
    scoped_ptr<PbufferGLContext> context(new PbufferGLContext);
    if (context->Initialize(shared_handle))
      return context.release();

    scoped_ptr<PixmapGLContext> context_pixmap(new PixmapGLContext);
    if (context_pixmap->Initialize(shared_handle))
      return context_pixmap.release();

    return NULL;
  }
}

}  // namespace gfx
<|endoftext|>


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

  Copyright (c) Kapteyn Astronomical Institute
  University of Groningen, Groningen, Netherlands. All Rights Reserved.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  This file was originally developed by Davide Punzo, Kapteyn Astronomical Institute,
  and was supported through the European Research Council grant nr. 291531.

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

// MRMLDisplayableManager includes
#include "vtkMRMLAstroBeamDisplayableManager.h"

// MRML includes
#include <vtkMRMLAbstractViewNode.h>
#include <vtkMRMLAstroVolumeDisplayNode.h>
#include <vtkMRMLAstroVolumeNode.h>
#include <vtkMRMLLogic.h>
#include <vtkMRMLSliceLayerLogic.h>
#include <vtkMRMLSliceLogic.h>
#include <vtkMRMLSliceNode.h>
#include <vtkMRMLViewNode.h>

// VTK includes
#include <vtkActor2D.h>
#include <vtkActor2DCollection.h>
#include <vtkAxisActor2D.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkGeneralTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty2D.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkLine.h>
#include <vtksys/SystemTools.hxx>
#include <vtkTransform.h>

// STD includes
#include <sstream>

// SlicerQt includes
#include <qSlicerApplication.h>

// vtkSlicer includes
#include <vtkSlicerApplicationLogic.h>

// Constants
static const int RENDERER_LAYER = 1; // layer ID where the orientation marker will be displayed
const double PI_2  = PI * 0.5;

//---------------------------------------------------------------------------
class vtkAstroBeamRendererUpdateObserver : public vtkCommand
{
public:
  static vtkAstroBeamRendererUpdateObserver *New()
    {
    return new vtkAstroBeamRendererUpdateObserver;
    }
  vtkAstroBeamRendererUpdateObserver()
    {
    this->DisplayableManager = 0;
    }
  virtual void Execute(vtkObject* vtkNotUsed(wdg), unsigned long vtkNotUsed(event), void* vtkNotUsed(calldata))
    {
    if (this->DisplayableManager)
      {
      this->DisplayableManager->UpdateFromRenderer();
      }
  }
  vtkWeakPointer<vtkMRMLAstroBeamDisplayableManager> DisplayableManager;
};

namespace
{
//----------------------------------------------------------------------------
template <typename T> T StringToNumber(const char* num)
{
  std::stringstream ss;
  ss << num;
  T result;
  return ss >> result ? result : 0;
}

//----------------------------------------------------------------------------
double StringToDouble(const char* str)
{
  return StringToNumber<double>(str);
}

}// end namespace

//---------------------------------------------------------------------------
vtkStandardNewMacro(vtkMRMLAstroBeamDisplayableManager);

//---------------------------------------------------------------------------
class vtkMRMLAstroBeamDisplayableManager::vtkInternal
{
public:
  vtkInternal(vtkMRMLAstroBeamDisplayableManager * external);
  ~vtkInternal();

  void SetupMarkerRenderer();
  void AddRendererUpdateObserver(vtkRenderer* renderer);
  void RemoveRendererUpdateObserver();

  void SetupBeam();
  void UpdateBeam();
  void ShowActors(bool show);

  vtkSmartPointer<vtkRenderer> MarkerRenderer;
  vtkSmartPointer<vtkAstroBeamRendererUpdateObserver> RendererUpdateObserver;
  vtkSmartPointer<vtkPoints> beamPoints;
  vtkSmartPointer<vtkCellArray> beamCellArray;
  vtkSmartPointer<vtkPolyData> beamPolyData;
  vtkSmartPointer<vtkActor2D> beamActor;
  vtkSmartPointer<vtkPolyDataMapper2D> beamMapper;
  vtkSmartPointer<vtkCollection> col;

  int RendererUpdateObservationId;
  vtkWeakPointer<vtkRenderer> ObservedRenderer;

  bool ActorsAddedToRenderer;
  vtkMRMLAstroBeamDisplayableManager* External;

  qSlicerApplication* app;
};

//---------------------------------------------------------------------------
// vtkInternal methods

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkInternal::vtkInternal(vtkMRMLAstroBeamDisplayableManager * external)
{
  this->External = external;
  this->RendererUpdateObserver = vtkSmartPointer<vtkAstroBeamRendererUpdateObserver>::New();
  this->RendererUpdateObserver->DisplayableManager = this->External;
  this->RendererUpdateObservationId = 0;
  this->ActorsAddedToRenderer = false;
  this->MarkerRenderer = vtkSmartPointer<vtkRenderer>::New();
  this->beamPoints = vtkSmartPointer<vtkPoints>::New();
  this->beamCellArray = vtkSmartPointer<vtkCellArray>::New();
  this->beamPolyData = vtkSmartPointer<vtkPolyData>::New();
  this->beamActor = vtkSmartPointer<vtkActor2D>::New();
  this->beamMapper = vtkSmartPointer<vtkPolyDataMapper2D>::New();
  this->col = vtkSmartPointer<vtkCollection>::New();
  this->app = 0;
}

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkInternal::~vtkInternal()
{
  RemoveRendererUpdateObserver();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::ShowActors(bool show)
{
  if (this->ActorsAddedToRenderer == show)
    {
    // no change
    return;
    }
  if (show)
    {
    this->MarkerRenderer->AddViewProp(this->beamActor);
    }
  else
    {
    this->MarkerRenderer->RemoveViewProp(this->beamActor);
    }
  this->ActorsAddedToRenderer = show;
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::AddRendererUpdateObserver(vtkRenderer* renderer)
{
  RemoveRendererUpdateObserver();
  if (renderer)
    {
    this->ObservedRenderer = renderer;
    this->RendererUpdateObservationId = renderer->AddObserver(vtkCommand::StartEvent, this->RendererUpdateObserver);
    }
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::RemoveRendererUpdateObserver()
{
  if (this->ObservedRenderer)
    {
    this->ObservedRenderer->RemoveObserver(this->RendererUpdateObservationId);
    this->RendererUpdateObservationId = 0;
    this->ObservedRenderer = NULL;
    }
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::SetupMarkerRenderer()
{
  vtkRenderer* renderer = this->External->GetRenderer();
  if (renderer==NULL)
    {
    vtkErrorWithObjectMacro(this->External, "vtkMRMLAstroBeamDisplayableManager"
                                            "::vtkInternal::SetupMarkerRenderer() failed: renderer is invalid");
    return;
    }

  this->MarkerRenderer->InteractiveOff();

  vtkRenderWindow* renderWindow = renderer->GetRenderWindow();
  if (renderWindow->GetNumberOfLayers() < RENDERER_LAYER+1)
    {
    renderWindow->SetNumberOfLayers( RENDERER_LAYER+1 );
    }
  this->MarkerRenderer->SetLayer(RENDERER_LAYER);
  renderWindow->AddRenderer(this->MarkerRenderer);

}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::SetupBeam()
{
  this->beamActor->PickableOff();
  this->beamActor->DragableOff();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::UpdateBeam()
{
  // clean the attributes before updating
  this->beamPoints->Initialize();
  this->beamPoints->Squeeze();
  this->beamCellArray->Initialize();
  this->beamCellArray->Squeeze();

  vtkMRMLAbstractViewNode* viewNode =
      vtkMRMLAbstractViewNode::SafeDownCast
      (this->External->GetMRMLDisplayableNode());
  if (!viewNode)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroBeamDisplayableManager::UpdateBeam()"
                            " failed: view node is invalid.");
    this->ShowActors(false);
    return;
    }

  vtkMRMLSliceNode* sliceNode = vtkMRMLSliceNode::SafeDownCast(viewNode);
  if (!sliceNode)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroBeamDisplayableManager::UpdateBeam()"
                            " failed: displayable node is invalid.");
    this->ShowActors(false);
    return;
    }

  if (!sliceNode->GetAttribute("SlicerAstro.Beam"))
    {
    return;
    }

  if (sliceNode->GetOrientation().compare("XY") ||
      !strcmp(sliceNode->GetAttribute("SlicerAstro.Beam"), "off"))
    {
    this->ShowActors(false);
    return;
    }

  // get the Logics
  this->app = qSlicerApplication::application();

  vtkMRMLSliceLogic* sliceLogic =
    this->app->applicationLogic()->GetSliceLogic(sliceNode);

  if (!sliceLogic)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroTwoDAxesDisplayableManager::UpdateAxes()"
                            " failed: sliceLogic node is invalid.");
    this->ShowActors(false);
    return;
    }

  this->col->AddItem(sliceLogic->GetBackgroundLayer());
  this->col->AddItem(sliceLogic->GetForegroundLayer());
  this->col->AddItem(sliceLogic->GetLabelLayer());

  bool hasVolume = false;

  for (int layer = 0; layer < this->col->GetNumberOfItems(); layer++)
    {
    vtkMRMLSliceLayerLogic* sliceLayerLogic =
      vtkMRMLSliceLayerLogic::SafeDownCast
        (this->col->GetItemAsObject(layer));

    if(!sliceLayerLogic)
      {
      return;
      }

    vtkMRMLAstroVolumeNode* volumeNode =
      vtkMRMLAstroVolumeNode::SafeDownCast
        (sliceLayerLogic->GetVolumeNode());

    if (!volumeNode)
      {
      continue;
      }

    if (!strcmp(volumeNode->GetAttribute("SlicerAstro.BMAJ"), "UNDEFINED") ||
        !strcmp(volumeNode->GetAttribute("SlicerAstro.BMIN"), "UNDEFINED") ||
        !strcmp(volumeNode->GetAttribute("SlicerAstro.BPA"), "UNDEFINED"))
      {
      continue;
      }

    hasVolume = true;

    sliceNode->UpdateMatrices();
    sliceLayerLogic->UpdateTransforms();

    vtkNew<vtkTransform> transform;
    double BPA = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BPA"));
    transform->RotateZ(BPA);
    const double degtorad = atan(1.) / 45.;
    vtkGeneralTransform* ijkToXY =
        sliceLayerLogic->GetXYToIJKTransform();
    ijkToXY->Inverse();

    double BMAJ = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BMAJ"));
    double BMIN = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BMIN"));
    double CDELT1 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.CDELT1"));
    double CDELT2 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.CDELT2"));
    double NAXIS1 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.NAXIS1"));

    double aCosPixel = BMAJ * cos(BPA * degtorad) / CDELT1;
    double aSinPixel = BMAJ * sin(BPA * degtorad) / CDELT2;
    double a = sqrt(aCosPixel * aCosPixel + aSinPixel * aSinPixel);

    double bCosPixel = BMIN * cos((BPA + 90) * degtorad) / CDELT1;
    double bSinPixel = BMIN * sin((BPA + 90) * degtorad) / CDELT2;
    double b = sqrt(bCosPixel * bCosPixel + bSinPixel * bSinPixel);

    double centerX = NAXIS1 - a * 3;
    double centerY = b * 3;

    double ijk[3], xy[3];
    // add points
    for (int ii = 0; ii <= 60; ii++)
      {
      double rot = ii * (2 * PI / 60.);
      ijk[0] = a * cos(rot);
      ijk[1] = b * sin(rot);
      ijk[2] = 0.;

      transform->TransformPoint(ijk, ijk);

      ijk[0] += centerX;
      ijk[1] += centerY;

      ijkToXY->TransformPoint(ijk, xy);

      this->beamPoints->InsertPoint(ii, xy[0], xy[1], 0);
      }

    int n = this->beamPoints->GetNumberOfPoints();
    // unify the points with lines
    std::vector<vtkSmartPointer<vtkLine> > lines;
    for (int ii = 0; ii < n - 1; ii++)
      {
      vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
      lines.push_back(line);
      }

    for (int ii = 0; ii < n - 1; ii++)
      {
      lines[ii]->GetPointIds()->SetId(0, ii);
      lines[ii]->GetPointIds()->SetId(1, ii + 1);
      }

    // create the cellArray
    for (int ii = 0; ii < n - 1; ii++)
      {
      this->beamCellArray->InsertNextCell(lines[ii]);
      }

    // setup the mapper and actor
    this->beamPolyData->SetPoints(this->beamPoints);
    this->beamPolyData->SetLines(this->beamCellArray);
    this->beamMapper->SetInputData(this->beamPolyData);
    this->beamActor->SetMapper(this->beamMapper);
    this->beamActor->GetProperty()->SetLineWidth(1.5);
    this->MarkerRenderer->AddActor2D(this->beamActor);

    this->ShowActors(true);
    break;
    }

  if (!hasVolume)
    {
    this->ShowActors(false);
    }
}

//---------------------------------------------------------------------------
// vtkMRMLRulerDisplayableManager methods

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkMRMLAstroBeamDisplayableManager()
{
  this->Internal = new vtkInternal(this);
}

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::~vtkMRMLAstroBeamDisplayableManager()
{
  delete this->Internal;
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::Create()
{
  this->Internal->SetupMarkerRenderer();
  this->Internal->SetupBeam();
  this->Superclass::Create();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::UpdateFromViewNode()
{
  // View node is changed, which may mean that either the marker type (visibility), size, or orientation is changed
  this->Internal->UpdateBeam();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::OnMRMLDisplayableNodeModifiedEvent(vtkObject* vtkNotUsed(caller))
{
  // view node is changed
  this->UpdateFromViewNode();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::UpdateFromRenderer()
{
  // Rendering is performed, so let's re-render the marker with up-to-date orientation
  this->Internal->UpdateBeam();
}
<commit_msg>BUG: fix transform copy in Beam display manager<commit_after>/*==============================================================================

  Copyright (c) Kapteyn Astronomical Institute
  University of Groningen, Groningen, Netherlands. All Rights Reserved.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  This file was originally developed by Davide Punzo, Kapteyn Astronomical Institute,
  and was supported through the European Research Council grant nr. 291531.

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

// MRMLDisplayableManager includes
#include "vtkMRMLAstroBeamDisplayableManager.h"

// MRML includes
#include <vtkMRMLAbstractViewNode.h>
#include <vtkMRMLAstroVolumeDisplayNode.h>
#include <vtkMRMLAstroVolumeNode.h>
#include <vtkMRMLLogic.h>
#include <vtkMRMLSliceLayerLogic.h>
#include <vtkMRMLSliceLogic.h>
#include <vtkMRMLSliceNode.h>
#include <vtkMRMLViewNode.h>

// VTK includes
#include <vtkActor2D.h>
#include <vtkActor2DCollection.h>
#include <vtkAxisActor2D.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkGeneralTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty2D.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkLine.h>
#include <vtksys/SystemTools.hxx>
#include <vtkTransform.h>

// STD includes
#include <sstream>

// SlicerQt includes
#include <qSlicerApplication.h>

// vtkSlicer includes
#include <vtkSlicerApplicationLogic.h>

// Constants
static const int RENDERER_LAYER = 1; // layer ID where the orientation marker will be displayed
const double PI_2  = PI * 0.5;

//---------------------------------------------------------------------------
class vtkAstroBeamRendererUpdateObserver : public vtkCommand
{
public:
  static vtkAstroBeamRendererUpdateObserver *New()
    {
    return new vtkAstroBeamRendererUpdateObserver;
    }
  vtkAstroBeamRendererUpdateObserver()
    {
    this->DisplayableManager = 0;
    }
  virtual void Execute(vtkObject* vtkNotUsed(wdg), unsigned long vtkNotUsed(event), void* vtkNotUsed(calldata))
    {
    if (this->DisplayableManager)
      {
      this->DisplayableManager->UpdateFromRenderer();
      }
  }
  vtkWeakPointer<vtkMRMLAstroBeamDisplayableManager> DisplayableManager;
};

namespace
{
//----------------------------------------------------------------------------
template <typename T> T StringToNumber(const char* num)
{
  std::stringstream ss;
  ss << num;
  T result;
  return ss >> result ? result : 0;
}

//----------------------------------------------------------------------------
double StringToDouble(const char* str)
{
  return StringToNumber<double>(str);
}

}// end namespace

//---------------------------------------------------------------------------
vtkStandardNewMacro(vtkMRMLAstroBeamDisplayableManager);

//---------------------------------------------------------------------------
class vtkMRMLAstroBeamDisplayableManager::vtkInternal
{
public:
  vtkInternal(vtkMRMLAstroBeamDisplayableManager * external);
  ~vtkInternal();

  void SetupMarkerRenderer();
  void AddRendererUpdateObserver(vtkRenderer* renderer);
  void RemoveRendererUpdateObserver();

  void SetupBeam();
  void UpdateBeam();
  void ShowActors(bool show);

  vtkSmartPointer<vtkRenderer> MarkerRenderer;
  vtkSmartPointer<vtkAstroBeamRendererUpdateObserver> RendererUpdateObserver;
  vtkSmartPointer<vtkPoints> beamPoints;
  vtkSmartPointer<vtkCellArray> beamCellArray;
  vtkSmartPointer<vtkPolyData> beamPolyData;
  vtkSmartPointer<vtkActor2D> beamActor;
  vtkSmartPointer<vtkPolyDataMapper2D> beamMapper;
  vtkSmartPointer<vtkCollection> col;

  int RendererUpdateObservationId;
  vtkWeakPointer<vtkRenderer> ObservedRenderer;

  bool ActorsAddedToRenderer;
  vtkMRMLAstroBeamDisplayableManager* External;

  qSlicerApplication* app;
};

//---------------------------------------------------------------------------
// vtkInternal methods

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkInternal::vtkInternal(vtkMRMLAstroBeamDisplayableManager * external)
{
  this->External = external;
  this->RendererUpdateObserver = vtkSmartPointer<vtkAstroBeamRendererUpdateObserver>::New();
  this->RendererUpdateObserver->DisplayableManager = this->External;
  this->RendererUpdateObservationId = 0;
  this->ActorsAddedToRenderer = false;
  this->MarkerRenderer = vtkSmartPointer<vtkRenderer>::New();
  this->beamPoints = vtkSmartPointer<vtkPoints>::New();
  this->beamCellArray = vtkSmartPointer<vtkCellArray>::New();
  this->beamPolyData = vtkSmartPointer<vtkPolyData>::New();
  this->beamActor = vtkSmartPointer<vtkActor2D>::New();
  this->beamMapper = vtkSmartPointer<vtkPolyDataMapper2D>::New();
  this->col = vtkSmartPointer<vtkCollection>::New();
  this->app = 0;
}

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkInternal::~vtkInternal()
{
  RemoveRendererUpdateObserver();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::ShowActors(bool show)
{
  if (this->ActorsAddedToRenderer == show)
    {
    // no change
    return;
    }
  if (show)
    {
    this->MarkerRenderer->AddViewProp(this->beamActor);
    }
  else
    {
    this->MarkerRenderer->RemoveViewProp(this->beamActor);
    }
  this->ActorsAddedToRenderer = show;
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::AddRendererUpdateObserver(vtkRenderer* renderer)
{
  RemoveRendererUpdateObserver();
  if (renderer)
    {
    this->ObservedRenderer = renderer;
    this->RendererUpdateObservationId = renderer->AddObserver(vtkCommand::StartEvent, this->RendererUpdateObserver);
    }
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::RemoveRendererUpdateObserver()
{
  if (this->ObservedRenderer)
    {
    this->ObservedRenderer->RemoveObserver(this->RendererUpdateObservationId);
    this->RendererUpdateObservationId = 0;
    this->ObservedRenderer = NULL;
    }
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::SetupMarkerRenderer()
{
  vtkRenderer* renderer = this->External->GetRenderer();
  if (renderer==NULL)
    {
    vtkErrorWithObjectMacro(this->External, "vtkMRMLAstroBeamDisplayableManager"
                                            "::vtkInternal::SetupMarkerRenderer() failed: renderer is invalid");
    return;
    }

  this->MarkerRenderer->InteractiveOff();

  vtkRenderWindow* renderWindow = renderer->GetRenderWindow();
  if (renderWindow->GetNumberOfLayers() < RENDERER_LAYER+1)
    {
    renderWindow->SetNumberOfLayers( RENDERER_LAYER+1 );
    }
  this->MarkerRenderer->SetLayer(RENDERER_LAYER);
  renderWindow->AddRenderer(this->MarkerRenderer);

}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::SetupBeam()
{
  this->beamActor->PickableOff();
  this->beamActor->DragableOff();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::vtkInternal::UpdateBeam()
{
  // clean the attributes before updating
  this->beamPoints->Initialize();
  this->beamPoints->Squeeze();
  this->beamCellArray->Initialize();
  this->beamCellArray->Squeeze();

  vtkMRMLAbstractViewNode* viewNode =
      vtkMRMLAbstractViewNode::SafeDownCast
      (this->External->GetMRMLDisplayableNode());
  if (!viewNode)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroBeamDisplayableManager::UpdateBeam()"
                            " failed: view node is invalid.");
    this->ShowActors(false);
    return;
    }

  vtkMRMLSliceNode* sliceNode = vtkMRMLSliceNode::SafeDownCast(viewNode);
  if (!sliceNode)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroBeamDisplayableManager::UpdateBeam()"
                            " failed: displayable node is invalid.");
    this->ShowActors(false);
    return;
    }

  if (!sliceNode->GetAttribute("SlicerAstro.Beam"))
    {
    return;
    }

  if (sliceNode->GetOrientation().compare("XY") ||
      !strcmp(sliceNode->GetAttribute("SlicerAstro.Beam"), "off"))
    {
    this->ShowActors(false);
    return;
    }

  // get the Logics
  this->app = qSlicerApplication::application();

  vtkMRMLSliceLogic* sliceLogic =
    this->app->applicationLogic()->GetSliceLogic(sliceNode);

  if (!sliceLogic)
    {
    vtkErrorWithObjectMacro(this->External,
                            "vtkMRMLAstroTwoDAxesDisplayableManager::UpdateAxes()"
                            " failed: sliceLogic node is invalid.");
    this->ShowActors(false);
    return;
    }

  this->col->AddItem(sliceLogic->GetBackgroundLayer());
  this->col->AddItem(sliceLogic->GetForegroundLayer());
  this->col->AddItem(sliceLogic->GetLabelLayer());

  bool hasVolume = false;

  for (int layer = 0; layer < this->col->GetNumberOfItems(); layer++)
    {
    vtkMRMLSliceLayerLogic* sliceLayerLogic =
      vtkMRMLSliceLayerLogic::SafeDownCast
        (this->col->GetItemAsObject(layer));

    if(!sliceLayerLogic)
      {
      return;
      }

    vtkMRMLAstroVolumeNode* volumeNode =
      vtkMRMLAstroVolumeNode::SafeDownCast
        (sliceLayerLogic->GetVolumeNode());

    if (!volumeNode)
      {
      continue;
      }

    if (!strcmp(volumeNode->GetAttribute("SlicerAstro.BMAJ"), "UNDEFINED") ||
        !strcmp(volumeNode->GetAttribute("SlicerAstro.BMIN"), "UNDEFINED") ||
        !strcmp(volumeNode->GetAttribute("SlicerAstro.BPA"), "UNDEFINED"))
      {
      continue;
      }

    hasVolume = true;

    sliceNode->UpdateMatrices();
    sliceLayerLogic->UpdateTransforms();

    vtkNew<vtkTransform> transform;
    double BPA = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BPA"));
    transform->RotateZ(BPA);
    const double degtorad = atan(1.) / 45.;
    vtkNew<vtkGeneralTransform> ijkToXY;
    ijkToXY->DeepCopy(sliceLayerLogic->GetXYToIJKTransform());
    ijkToXY->Inverse();

    double BMAJ = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BMAJ"));
    double BMIN = StringToDouble(volumeNode->GetAttribute("SlicerAstro.BMIN"));
    double CDELT1 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.CDELT1"));
    double CDELT2 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.CDELT2"));
    double NAXIS1 = StringToDouble(volumeNode->GetAttribute("SlicerAstro.NAXIS1"));

    double aCosPixel = BMAJ * cos(BPA * degtorad) / CDELT1;
    double aSinPixel = BMAJ * sin(BPA * degtorad) / CDELT2;
    double a = sqrt(aCosPixel * aCosPixel + aSinPixel * aSinPixel);

    double bCosPixel = BMIN * cos((BPA + 90) * degtorad) / CDELT1;
    double bSinPixel = BMIN * sin((BPA + 90) * degtorad) / CDELT2;
    double b = sqrt(bCosPixel * bCosPixel + bSinPixel * bSinPixel);

    double centerX = NAXIS1 - a * 3;
    double centerY = b * 3;

    double ijk[3], xy[3];
    // add points
    for (int ii = 0; ii <= 60; ii++)
      {
      double rot = ii * (2 * PI / 60.);
      ijk[0] = a * cos(rot);
      ijk[1] = b * sin(rot);
      ijk[2] = 0.;

      transform->TransformPoint(ijk, ijk);

      ijk[0] += centerX;
      ijk[1] += centerY;

      ijkToXY->TransformPoint(ijk, xy);

      this->beamPoints->InsertPoint(ii, xy[0], xy[1], 0);
      }

    int n = this->beamPoints->GetNumberOfPoints();
    // unify the points with lines
    std::vector<vtkSmartPointer<vtkLine> > lines;
    for (int ii = 0; ii < n - 1; ii++)
      {
      vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
      lines.push_back(line);
      }

    for (int ii = 0; ii < n - 1; ii++)
      {
      lines[ii]->GetPointIds()->SetId(0, ii);
      lines[ii]->GetPointIds()->SetId(1, ii + 1);
      }

    // create the cellArray
    for (int ii = 0; ii < n - 1; ii++)
      {
      this->beamCellArray->InsertNextCell(lines[ii]);
      }

    // setup the mapper and actor
    this->beamPolyData->SetPoints(this->beamPoints);
    this->beamPolyData->SetLines(this->beamCellArray);
    this->beamMapper->SetInputData(this->beamPolyData);
    this->beamActor->SetMapper(this->beamMapper);
    this->beamActor->GetProperty()->SetLineWidth(1.5);
    this->MarkerRenderer->AddActor2D(this->beamActor);

    this->ShowActors(true);
    break;
    }

  if (!hasVolume)
    {
    this->ShowActors(false);
    }
}

//---------------------------------------------------------------------------
// vtkMRMLRulerDisplayableManager methods

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::vtkMRMLAstroBeamDisplayableManager()
{
  this->Internal = new vtkInternal(this);
}

//---------------------------------------------------------------------------
vtkMRMLAstroBeamDisplayableManager::~vtkMRMLAstroBeamDisplayableManager()
{
  delete this->Internal;
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::Create()
{
  this->Internal->SetupMarkerRenderer();
  this->Internal->SetupBeam();
  this->Superclass::Create();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::UpdateFromViewNode()
{
  // View node is changed, which may mean that either the marker type (visibility), size, or orientation is changed
  this->Internal->UpdateBeam();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::OnMRMLDisplayableNodeModifiedEvent(vtkObject* vtkNotUsed(caller))
{
  // view node is changed
  this->UpdateFromViewNode();
}

//---------------------------------------------------------------------------
void vtkMRMLAstroBeamDisplayableManager::UpdateFromRenderer()
{
  // Rendering is performed, so let's re-render the marker with up-to-date orientation
  this->Internal->UpdateBeam();
}
<|endoftext|>