<commit_before>//Contains hooks that control attack range and seek range (AKA target acquisition range).

#include "weapon_range.h"
#include "../SCBW/scbwdata.h"
#include "../SCBW/enumerations.h"
#include "../SCBW/api.h"

namespace hooks {

/// Returns the modified seek range (AKA target acquisition range) for the unit.
/// Note: Seek ranges are measured in matrices (1 matrix = 32 pixels).
/// This hook affects the behavior of CUnit::getSeekRange().
u8 getSeekRangeHook(const CUnit *unit) {
  using UnitStatus::Cloaked;
  using UnitStatus::RequiresDetection;
  using scbw::getUpgradeLevel;

  const u16 unitId = unit->id;

  //Cloaked ghosts do not voluntarily attack enemy units
  if ((unitId == UnitId::ghost
       || unitId == UnitId::sarah_kerrigan
       || unitId == UnitId::Hero_AlexeiStukov
       || unitId == UnitId::Hero_SamirDuran
       || unitId == UnitId::Hero_InfestedDuran)
      && unit->status & (Cloaked | RequiresDetection)
      && unit->mainOrderId != OrderId::HoldPosition2)
    return 0;

  u8 bonusAmount = 0;
  switch (unitId) {
    case UnitId::marine:
    case UNIT_FIEND:
      if (getUpgradeLevel(unit->playerId, UpgradeId::U_238Shells))
        bonusAmount = 1;
      break;
    case UnitId::hydralisk:
      if (getUpgradeLevel(unit->playerId, UpgradeId::GroovedSpines))
        bonusAmount = 1;
      break;
    case UnitId::dragoon:
      if (getUpgradeLevel(unit->playerId, UpgradeId::SingularityCharge))
        bonusAmount = 2;
      break;
    case UnitId::fenix_dragoon:
      if (scbw::isBroodWarMode())
        bonusAmount = 2;
      break;
    case UnitId::goliath:
    case UnitId::goliath_turret:
      if (getUpgradeLevel(unit->playerId, UpgradeId::CharonBooster))
        bonusAmount = 3;
      break;
    case UnitId::alan_schezar:
    case UnitId::alan_schezar_turret:
      if (scbw::isBroodWarMode())
        bonusAmount = 3;
      break;

    //Added
    case UnitId::spider_mine:
      if (getUpgradeLevel(unit->playerId, UPGRADE_THERMAL_SENSORS))
        bonusAmount = 1;
      break;
  }

  //Added: Ocular Implants adds a flat +1 seek range
  if (unit->isBlind)
    bonusAmount += 1;

  return Unit::SeekRange[unitId] + bonusAmount;
}

/// Returns the modified max range for the weapon, which is assumed to be
/// attached to the given unit.
/// This hook affects the behavior of CUnit::getMaxWeaponRange().
/// Note: Weapon ranges are measured in pixels.
///
/// @param  weapon    The weapons.dat ID of the weapon.
/// @param  unit      The unit that owns the weapon. Use this to check upgrades.
u32 getMaxWeaponRangeHook(const CUnit *unit, u8 weaponId) {
  using scbw::getUpgradeLevel;

  u32 bonusAmount = 0;

  //Give bonus range to units inside Bunkers
  if (unit->status & UnitStatus::InBuilding)
    bonusAmount = 64;

  switch (unit->id) {
    case UnitId::marine:
    case UNIT_FIEND:
      if (getUpgradeLevel(unit->playerId, UpgradeId::U_238Shells))
        bonusAmount += 32;
      break;
    case UnitId::hydralisk:
      if (getUpgradeLevel(unit->playerId, UpgradeId::GroovedSpines))
        bonusAmount += 32;
      break;
    case UnitId::dragoon:
      if (getUpgradeLevel(unit->playerId, UpgradeId::SingularityCharge))
        bonusAmount += 64;
      break;
    case UnitId::fenix_dragoon:
      if (scbw::isBroodWarMode())
        bonusAmount += 64;
      break;
    case UnitId::goliath:
    case UnitId::goliath_turret:
      if (weaponId == WeaponId::HellfireMissilePack
          && getUpgradeLevel(unit->playerId, UpgradeId::CharonBooster))
        bonusAmount += 96;
      break;
    case UnitId::alan_schezar:
    case UnitId::alan_schezar_turret:
      if (weaponId == WeaponId::HellfireMissilePack_AlanSchezar
          && scbw::isBroodWarMode())
        bonusAmount += 96;
      break;
  }

  //Added: Ocular Implants adds a flat +32 weapon range (to ranged units only)
  if (unit->isBlind && Weapon::MaxRange[weaponId] >= 64)
    bonusAmount += 32;

  return Weapon::MaxRange[weaponId] + bonusAmount;
}

} //hooks
<commit_msg>SCT Plugin: Fix bug that prevented Ocular Implants from working on Siege Tanks<commit_after>//Contains hooks that control attack range and seek range (AKA target acquisition range).

#include "weapon_range.h"
#include "../SCBW/scbwdata.h"
#include "../SCBW/enumerations.h"
#include "../SCBW/api.h"

namespace hooks {

/// Returns the modified seek range (AKA target acquisition range) for the unit.
/// Note: Seek ranges are measured in matrices (1 matrix = 32 pixels).
/// This hook affects the behavior of CUnit::getSeekRange().
u8 getSeekRangeHook(const CUnit *unit) {
  using UnitStatus::Cloaked;
  using UnitStatus::RequiresDetection;
  using scbw::getUpgradeLevel;

  const u16 unitId = unit->id;

  //Cloaked ghosts do not voluntarily attack enemy units
  if ((unitId == UnitId::ghost
       || unitId == UnitId::sarah_kerrigan
       || unitId == UnitId::Hero_AlexeiStukov
       || unitId == UnitId::Hero_SamirDuran
       || unitId == UnitId::Hero_InfestedDuran)
      && unit->status & (Cloaked | RequiresDetection)
      && unit->mainOrderId != OrderId::HoldPosition2)
    return 0;

  u8 bonusAmount = 0;
  switch (unitId) {
    case UnitId::marine:
    case UNIT_FIEND:
      if (getUpgradeLevel(unit->playerId, UpgradeId::U_238Shells))
        bonusAmount = 1;
      break;
    case UnitId::hydralisk:
      if (getUpgradeLevel(unit->playerId, UpgradeId::GroovedSpines))
        bonusAmount = 1;
      break;
    case UnitId::dragoon:
      if (getUpgradeLevel(unit->playerId, UpgradeId::SingularityCharge))
        bonusAmount = 2;
      break;
    case UnitId::fenix_dragoon:
      if (scbw::isBroodWarMode())
        bonusAmount = 2;
      break;
    case UnitId::goliath:
    case UnitId::goliath_turret:
      if (getUpgradeLevel(unit->playerId, UpgradeId::CharonBooster))
        bonusAmount = 3;
      break;
    case UnitId::alan_schezar:
    case UnitId::alan_schezar_turret:
      if (scbw::isBroodWarMode())
        bonusAmount = 3;
      break;

    //Added
    case UnitId::spider_mine:
      if (getUpgradeLevel(unit->playerId, UPGRADE_THERMAL_SENSORS))
        bonusAmount = 1;
      break;
  }

  //Added: Ocular Implants adds a flat +1 seek range
  if (unit->isBlind || unit->subunit && unit->subunit->isBlind)
    bonusAmount += 1;

  return Unit::SeekRange[unitId] + bonusAmount;
}

/// Returns the modified max range for the weapon, which is assumed to be
/// attached to the given unit.
/// This hook affects the behavior of CUnit::getMaxWeaponRange().
/// Note: Weapon ranges are measured in pixels.
///
/// @param  weapon    The weapons.dat ID of the weapon.
/// @param  unit      The unit that owns the weapon. Use this to check upgrades.
u32 getMaxWeaponRangeHook(const CUnit *unit, u8 weaponId) {
  using scbw::getUpgradeLevel;

  u32 bonusAmount = 0;

  //Give bonus range to units inside Bunkers
  if (unit->status & UnitStatus::InBuilding)
    bonusAmount = 64;

  switch (unit->id) {
    case UnitId::marine:
    case UNIT_FIEND:
      if (getUpgradeLevel(unit->playerId, UpgradeId::U_238Shells))
        bonusAmount += 32;
      break;
    case UnitId::hydralisk:
      if (getUpgradeLevel(unit->playerId, UpgradeId::GroovedSpines))
        bonusAmount += 32;
      break;
    case UnitId::dragoon:
      if (getUpgradeLevel(unit->playerId, UpgradeId::SingularityCharge))
        bonusAmount += 64;
      break;
    case UnitId::fenix_dragoon:
      if (scbw::isBroodWarMode())
        bonusAmount += 64;
      break;
    case UnitId::goliath:
    case UnitId::goliath_turret:
      if (weaponId == WeaponId::HellfireMissilePack
          && getUpgradeLevel(unit->playerId, UpgradeId::CharonBooster))
        bonusAmount += 96;
      break;
    case UnitId::alan_schezar:
    case UnitId::alan_schezar_turret:
      if (weaponId == WeaponId::HellfireMissilePack_AlanSchezar
          && scbw::isBroodWarMode())
        bonusAmount += 96;
      break;
  }

  //Added: Ocular Implants adds a flat +32 weapon range (to ranged units only)
  if ((unit->isBlind || unit->subunit && unit->subunit->isBlind)
      && Weapon::MaxRange[weaponId] >= 64)
    bonusAmount += 32;

  return Weapon::MaxRange[weaponId] + bonusAmount;
}

} //hooks
<|endoftext|>


<commit_before>#include "vvaabb.h"
#include "vvdebugmsg.h"
#include "vvpthread.h"
#include "vvsoftrayrend.h"
#include "vvtoolshed.h"
#include "vvvoldesc.h"

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef HAVE_GL
#include <GL/glew.h>
#include "vvgltools.h"
#endif

#include <queue>

struct Ray
{
  vvVector3 o;
  vvVector3 d;
};

bool intersectBox(const Ray& ray, const vvAABB& aabb,
                  float* tnear, float* tfar)
{
  // compute intersection of ray with all six bbox planes
  vvVector3 invR(1.0f / ray.d[0], 1.0f / ray.d[1], 1.0f / ray.d[2]);
  float t1 = (aabb.getMin()[0] - ray.o[0]) * invR[0];
  float t2 = (aabb.getMax()[0] - ray.o[0]) * invR[0];
  float tmin = fminf(t1, t2);
  float tmax = fmaxf(t1, t2);

  t1 = (aabb.getMin()[1] - ray.o[1]) * invR[1];
  t2 = (aabb.getMax()[1] - ray.o[1]) * invR[1];
  tmin = fmaxf(fminf(t1, t2), tmin);
  tmax = fminf(fmaxf(t1, t2), tmax);

  t1 = (aabb.getMin()[2] - ray.o[2]) * invR[2];
  t2 = (aabb.getMax()[2] - ray.o[2]) * invR[2];
  tmin = fmaxf(fminf(t1, t2), tmin);
  tmax = fminf(fmaxf(t1, t2), tmax);

  *tnear = tmin;
  *tfar = tmax;

  return ((tmax >= tmin) && (tmax >= 0.0f));
}

struct vvSoftRayRend::Thread
{
  int id;
  pthread_t threadHandle;

  vvSoftRayRend* renderer;
  vvMatrix invViewMatrix;
  std::vector<float>* colors;

  pthread_barrier_t* barrier;
  pthread_mutex_t* mutex;
  std::vector<Tile>* tiles;

  enum Event
  {
    VV_RENDER = 0,
    VV_EXIT
  };

  std::queue<Event> events;
};

vvSoftRayRend::vvSoftRayRend(vvVolDesc* vd, vvRenderState renderState)
  : vvRenderer(vd, renderState)
  , _width(512)
  , _height(512)
  , _firstThread(NULL)
  , _rgbaTF(NULL)
  , _earlyRayTermination(true)
  , _opacityCorrection(true)
{
  vvDebugMsg::msg(1, "vvSoftRayRend::vvSoftRayRend()");

#ifdef HAVE_GL
  glewInit();
#endif

  updateTransferFunction();

  int numThreads = vvToolshed::getNumProcessors();
  pthread_barrier_t* barrier = numThreads > 0 ? new pthread_barrier_t : NULL;
  pthread_mutex_t* mutex = numThreads > 0 ? new pthread_mutex_t : NULL;

  pthread_barrier_init(barrier, NULL, numThreads + 1);
  pthread_mutex_init(mutex, NULL);

  for (int i = 0; i < numThreads; ++i)
  {
    Thread* thread = new Thread;
    thread->id = i;

    thread->renderer = this;

    thread->barrier = barrier;
    thread->mutex = mutex;

    pthread_create(&thread->threadHandle, NULL, renderFunc, thread);
    _threads.push_back(thread);

    if (i == 0)
    {
      _firstThread = thread;
    }
  }
}

vvSoftRayRend::~vvSoftRayRend()
{
  vvDebugMsg::msg(1, "vvSoftRayRend::~vvSoftRayRend()");

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    pthread_mutex_lock((*it)->mutex);
    (*it)->events.push(Thread::VV_EXIT);
    pthread_mutex_unlock((*it)->mutex);

    if (pthread_join((*it)->threadHandle, NULL) != 0)
    {
      vvDebugMsg::msg(0, "vvSoftRayRend::~vvSoftRayRend(): Error joining thread");
    }
  }

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    if (it == _threads.begin())
    {
      pthread_barrier_destroy((*it)->barrier);
      pthread_mutex_destroy((*it)->mutex);
      delete (*it)->barrier;
      delete (*it)->mutex;
    }

    delete *it;
  }
}

void vvSoftRayRend::renderVolumeGL()
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderVolumeGL()");

  vvMatrix mv;
  vvMatrix pr;

#ifdef HAVE_GL
  vvGLTools::getModelviewMatrix(&mv);
  vvGLTools::getProjectionMatrix(&pr);
  const vvGLTools::Viewport viewport = vvGLTools::getViewport();
  _width = viewport[2];
  _height = viewport[3];
#endif

  vvMatrix invViewMatrix = mv;
  invViewMatrix.multiplyLeft(pr);
  invViewMatrix.invert();

  std::vector<Tile> tiles = makeTiles(_width, _height);

  std::vector<float> colors;
  colors.resize(_width * _height * 4);

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    (*it)->invViewMatrix = invViewMatrix;
    (*it)->colors = &colors;
    (*it)->tiles = &tiles;
    (*it)->events.push(Thread::VV_RENDER);
  }
  pthread_barrier_wait(_firstThread->barrier);

  // threads render

  pthread_barrier_wait(_firstThread->barrier);
#ifdef HAVE_GL
  glWindowPos2i(0, 0);
  glDrawPixels(_width, _height, GL_RGBA, GL_FLOAT, &colors[0]);
#endif
}

void vvSoftRayRend::updateTransferFunction()
{
  vvDebugMsg::msg(3, "vvSoftRayRend::updateTransferFunction()");

  if (_firstThread != NULL && _firstThread->mutex != NULL)
  {
    pthread_mutex_lock(_firstThread->mutex);
  }

  int lutEntries = getLUTSize();
  delete[] _rgbaTF;
  _rgbaTF = new float[4 * lutEntries];

  vd->computeTFTexture(lutEntries, 1, 1, _rgbaTF);

  if (_firstThread != NULL && _firstThread->mutex != NULL)
  {
    pthread_mutex_unlock(_firstThread->mutex);
  }
}

int vvSoftRayRend::getLUTSize() const
{
  vvDebugMsg::msg(3, "vvSoftRayRend::getLUTSize()");
  return (vd->getBPV()==2) ? 4096 : 256;
}

void vvSoftRayRend::setParameter(ParameterType param, const vvParam& newValue)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::setParameter()");

  switch (param)
  {
  case vvRenderer::VV_OPCORR:
    _opacityCorrection = newValue;
    break;
  case vvRenderer::VV_TERMINATEEARLY:
    _earlyRayTermination = newValue;
    break;
  default:
    vvRenderer::setParameter(param, newValue);
    break;
  }
}

vvParam vvSoftRayRend::getParameter(ParameterType param) const
{
  vvDebugMsg::msg(3, "vvSoftRayRend::getParameter()");

  switch (param)
  {
  case vvRenderer::VV_OPCORR:
    return _opacityCorrection;
  case vvRenderer::VV_TERMINATEEARLY:
    return _earlyRayTermination;
  default:
    return vvRenderer::getParameter(param);
  }
}

std::vector<vvSoftRayRend::Tile> vvSoftRayRend::makeTiles(const int w, const int h)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::makeTiles()");

  const int tilew = 16;
  const int tileh = 16;

  int numtilesx = vvToolshed::iDivUp(w, tilew);
  int numtilesy = vvToolshed::iDivUp(h, tileh);

  std::vector<Tile> result;
  for (int y = 0; y < numtilesy; ++y)
  {
    for (int x = 0; x < numtilesx; ++x)
    {
      Tile t;
      t.left = tilew * x;
      t.bottom = tileh * y;
      t.right = t.left + tilew;
      t.top = t.bottom + tileh;
      result.push_back(t);
    }
  }
  return result;
}

void vvSoftRayRend::renderTile(const vvSoftRayRend::Tile& tile, const vvMatrix& invViewMatrix, std::vector<float>* colors)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderTile()");

  const float opacityThreshold = 0.95f;

  vvVector3i minVox = _visibleRegion.getMin();
  vvVector3i maxVox = _visibleRegion.getMax();
  for (int i = 0; i < 3; ++i)
  {
    minVox[i] = std::max(minVox[i], 0);
    maxVox[i] = std::min(maxVox[i], vd->vox[i]);
  }
  const vvVector3 minCorner = vd->objectCoords(minVox);
  const vvVector3 maxCorner = vd->objectCoords(maxVox);
  const vvAABB aabb = vvAABB(minCorner, maxCorner);

  vvVector3 size2 = vd->getSize() * 0.5f;
  const float diagonalVoxels = sqrtf(float(vd->vox[0] * vd->vox[0] +
                                           vd->vox[1] * vd->vox[1] +
                                           vd->vox[2] * vd->vox[2]));
  int numSlices = std::max(1, static_cast<int>(_quality * diagonalVoxels));

  uchar* raw = vd->getRaw(vd->getCurrentFrame());

  for (int y = tile.bottom; y < tile.top; ++y)
  {
    for (int x = tile.left; x < tile.right; ++x)
    {
      const float u = (x / static_cast<float>(_width)) * 2.0f - 1.0f;
      const float v = (y / static_cast<float>(_height)) * 2.0f - 1.0f;

      vvVector4 o(u, v, -1.0f, 1.0f);
      o.multiply(invViewMatrix);
      vvVector4 d(u, v, 1.0f, 1.0f);
      d.multiply(invViewMatrix);

      Ray ray;
      ray.o = vvVector3(o[0] / o[3], o[1] / o[3], o[2] / o[3]);
      ray.d = vvVector3(d[0] / d[3], d[1] / d[3], d[2] / d[3]);
      ray.d = ray.d - ray.o;
      ray.d.normalize();

      float tbnear = 0.0f;
      float tbfar = 0.0f;

      const bool hit = intersectBox(ray, aabb, &tbnear, &tbfar);
      if (hit)
      {
        float dist = diagonalVoxels / float(numSlices);
        float t = tbnear;
        vvVector3 pos = ray.o + ray.d * tbnear;
        const vvVector3 step = ray.d * dist;
        vvVector4 dst(0.0f);

        while (true)
        {
          vvVector3 texcoord = vvVector3((pos[0] - vd->pos[0] + size2[0]) / (size2[0] * 2.0f),
                     (-pos[1] - vd->pos[1] + size2[1]) / (size2[1] * 2.0f),
                     (-pos[2] - vd->pos[2] + size2[2]) / (size2[2] * 2.0f));
          // calc voxel coordinates
          vvVector3i texcoordi = vvVector3i(int(texcoord[0] * float(vd->vox[0] - 1)),
                                            int(texcoord[1] * float(vd->vox[1] - 1)),
                                            int(texcoord[2] * float(vd->vox[2] - 1)));
          int idx = texcoordi[2] * vd->vox[0] * vd->vox[1] + texcoordi[1] * vd->vox[0] + texcoordi[0];
          float sample = float(raw[idx]) / 256.0f;
          vvVector4 src(_rgbaTF[int(sample * 4 * getLUTSize())],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 1],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 2],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 3]);

          if (_opacityCorrection)
          {
            src[3] = 1 - powf(1 - src[3], dist);
          }

          // pre-multiply alpha
          src[0] *= src[3];
          src[1] *= src[3];
          src[2] *= src[3];

          dst = dst + src * (1.0f - dst[3]);

          if (_earlyRayTermination && (dst[3] > opacityThreshold))
          {
            break;
          }

          t += dist;
          if (t > tbfar)
          {
            break;
          }
          pos += step;
        }

        for (int c = 0; c < 4; ++c)
        {
          (*colors)[y * _width * 4 + x * 4 + c] = dst[c];
        }
      }
    }
  }
}

void* vvSoftRayRend::renderFunc(void* args)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderFunc()");

  Thread* thread = static_cast<Thread*>(args);

  while (true)
  {
    pthread_mutex_lock(thread->mutex);
    bool haveEvent = !thread->events.empty();
    pthread_mutex_unlock(thread->mutex);

    if (haveEvent)
    {
      pthread_mutex_lock(thread->mutex);
      Thread::Event e = thread->events.front();
      pthread_mutex_unlock(thread->mutex);

      switch (e)
      {
      case Thread::VV_EXIT:
        goto cleanup;
      case Thread::VV_RENDER:
        render(thread);
        break;
      }

      pthread_mutex_lock(thread->mutex);
      thread->events.pop();
      pthread_mutex_unlock(thread->mutex);
    }
  }

cleanup:
  pthread_exit(NULL);
  return NULL;
}

void vvSoftRayRend::render(vvSoftRayRend::Thread* thread)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::render()");

  pthread_barrier_wait(thread->barrier);
  while (true)
  {
    pthread_mutex_lock(thread->mutex);
    if (thread->tiles->empty())
    {
      pthread_mutex_unlock(thread->mutex);
      break;
    }
    Tile tile = thread->tiles->back();
    thread->tiles->pop_back();
    pthread_mutex_unlock(thread->mutex);
    thread->renderer->renderTile(tile, thread->invViewMatrix, thread->colors);
  }
  pthread_barrier_wait(thread->barrier);
}

<commit_msg>Use std::min/max instead of fminf/fmaxf (VC doesn't fully support C99)<commit_after>#include "vvaabb.h"
#include "vvdebugmsg.h"
#include "vvpthread.h"
#include "vvsoftrayrend.h"
#include "vvtoolshed.h"
#include "vvvoldesc.h"

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef HAVE_GL
#include <GL/glew.h>
#include "vvgltools.h"
#endif

#include <queue>

struct Ray
{
  vvVector3 o;
  vvVector3 d;
};

bool intersectBox(const Ray& ray, const vvAABB& aabb,
                  float* tnear, float* tfar)
{
  using std::min;
  using std::max;

  // compute intersection of ray with all six bbox planes
  vvVector3 invR(1.0f / ray.d[0], 1.0f / ray.d[1], 1.0f / ray.d[2]);
  float t1 = (aabb.getMin()[0] - ray.o[0]) * invR[0];
  float t2 = (aabb.getMax()[0] - ray.o[0]) * invR[0];
  float tmin = min(t1, t2);
  float tmax = max(t1, t2);

  t1 = (aabb.getMin()[1] - ray.o[1]) * invR[1];
  t2 = (aabb.getMax()[1] - ray.o[1]) * invR[1];
  tmin = max(min(t1, t2), tmin);
  tmax = min(max(t1, t2), tmax);

  t1 = (aabb.getMin()[2] - ray.o[2]) * invR[2];
  t2 = (aabb.getMax()[2] - ray.o[2]) * invR[2];
  tmin = max(min(t1, t2), tmin);
  tmax = min(max(t1, t2), tmax);

  *tnear = tmin;
  *tfar = tmax;

  return ((tmax >= tmin) && (tmax >= 0.0f));
}

struct vvSoftRayRend::Thread
{
  int id;
  pthread_t threadHandle;

  vvSoftRayRend* renderer;
  vvMatrix invViewMatrix;
  std::vector<float>* colors;

  pthread_barrier_t* barrier;
  pthread_mutex_t* mutex;
  std::vector<Tile>* tiles;

  enum Event
  {
    VV_RENDER = 0,
    VV_EXIT
  };

  std::queue<Event> events;
};

vvSoftRayRend::vvSoftRayRend(vvVolDesc* vd, vvRenderState renderState)
  : vvRenderer(vd, renderState)
  , _width(512)
  , _height(512)
  , _firstThread(NULL)
  , _rgbaTF(NULL)
  , _earlyRayTermination(true)
  , _opacityCorrection(true)
{
  vvDebugMsg::msg(1, "vvSoftRayRend::vvSoftRayRend()");

#ifdef HAVE_GL
  glewInit();
#endif

  updateTransferFunction();

  int numThreads = vvToolshed::getNumProcessors();
  pthread_barrier_t* barrier = numThreads > 0 ? new pthread_barrier_t : NULL;
  pthread_mutex_t* mutex = numThreads > 0 ? new pthread_mutex_t : NULL;

  pthread_barrier_init(barrier, NULL, numThreads + 1);
  pthread_mutex_init(mutex, NULL);

  for (int i = 0; i < numThreads; ++i)
  {
    Thread* thread = new Thread;
    thread->id = i;

    thread->renderer = this;

    thread->barrier = barrier;
    thread->mutex = mutex;

    pthread_create(&thread->threadHandle, NULL, renderFunc, thread);
    _threads.push_back(thread);

    if (i == 0)
    {
      _firstThread = thread;
    }
  }
}

vvSoftRayRend::~vvSoftRayRend()
{
  vvDebugMsg::msg(1, "vvSoftRayRend::~vvSoftRayRend()");

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    pthread_mutex_lock((*it)->mutex);
    (*it)->events.push(Thread::VV_EXIT);
    pthread_mutex_unlock((*it)->mutex);

    if (pthread_join((*it)->threadHandle, NULL) != 0)
    {
      vvDebugMsg::msg(0, "vvSoftRayRend::~vvSoftRayRend(): Error joining thread");
    }
  }

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    if (it == _threads.begin())
    {
      pthread_barrier_destroy((*it)->barrier);
      pthread_mutex_destroy((*it)->mutex);
      delete (*it)->barrier;
      delete (*it)->mutex;
    }

    delete *it;
  }
}

void vvSoftRayRend::renderVolumeGL()
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderVolumeGL()");

  vvMatrix mv;
  vvMatrix pr;

#ifdef HAVE_GL
  vvGLTools::getModelviewMatrix(&mv);
  vvGLTools::getProjectionMatrix(&pr);
  const vvGLTools::Viewport viewport = vvGLTools::getViewport();
  _width = viewport[2];
  _height = viewport[3];
#endif

  vvMatrix invViewMatrix = mv;
  invViewMatrix.multiplyLeft(pr);
  invViewMatrix.invert();

  std::vector<Tile> tiles = makeTiles(_width, _height);

  std::vector<float> colors;
  colors.resize(_width * _height * 4);

  for (std::vector<Thread*>::const_iterator it = _threads.begin();
       it != _threads.end(); ++it)
  {
    (*it)->invViewMatrix = invViewMatrix;
    (*it)->colors = &colors;
    (*it)->tiles = &tiles;
    (*it)->events.push(Thread::VV_RENDER);
  }
  pthread_barrier_wait(_firstThread->barrier);

  // threads render

  pthread_barrier_wait(_firstThread->barrier);
#ifdef HAVE_GL
  glWindowPos2i(0, 0);
  glDrawPixels(_width, _height, GL_RGBA, GL_FLOAT, &colors[0]);
#endif
}

void vvSoftRayRend::updateTransferFunction()
{
  vvDebugMsg::msg(3, "vvSoftRayRend::updateTransferFunction()");

  if (_firstThread != NULL && _firstThread->mutex != NULL)
  {
    pthread_mutex_lock(_firstThread->mutex);
  }

  int lutEntries = getLUTSize();
  delete[] _rgbaTF;
  _rgbaTF = new float[4 * lutEntries];

  vd->computeTFTexture(lutEntries, 1, 1, _rgbaTF);

  if (_firstThread != NULL && _firstThread->mutex != NULL)
  {
    pthread_mutex_unlock(_firstThread->mutex);
  }
}

int vvSoftRayRend::getLUTSize() const
{
  vvDebugMsg::msg(3, "vvSoftRayRend::getLUTSize()");
  return (vd->getBPV()==2) ? 4096 : 256;
}

void vvSoftRayRend::setParameter(ParameterType param, const vvParam& newValue)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::setParameter()");

  switch (param)
  {
  case vvRenderer::VV_OPCORR:
    _opacityCorrection = newValue;
    break;
  case vvRenderer::VV_TERMINATEEARLY:
    _earlyRayTermination = newValue;
    break;
  default:
    vvRenderer::setParameter(param, newValue);
    break;
  }
}

vvParam vvSoftRayRend::getParameter(ParameterType param) const
{
  vvDebugMsg::msg(3, "vvSoftRayRend::getParameter()");

  switch (param)
  {
  case vvRenderer::VV_OPCORR:
    return _opacityCorrection;
  case vvRenderer::VV_TERMINATEEARLY:
    return _earlyRayTermination;
  default:
    return vvRenderer::getParameter(param);
  }
}

std::vector<vvSoftRayRend::Tile> vvSoftRayRend::makeTiles(const int w, const int h)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::makeTiles()");

  const int tilew = 16;
  const int tileh = 16;

  int numtilesx = vvToolshed::iDivUp(w, tilew);
  int numtilesy = vvToolshed::iDivUp(h, tileh);

  std::vector<Tile> result;
  for (int y = 0; y < numtilesy; ++y)
  {
    for (int x = 0; x < numtilesx; ++x)
    {
      Tile t;
      t.left = tilew * x;
      t.bottom = tileh * y;
      t.right = t.left + tilew;
      t.top = t.bottom + tileh;
      result.push_back(t);
    }
  }
  return result;
}

void vvSoftRayRend::renderTile(const vvSoftRayRend::Tile& tile, const vvMatrix& invViewMatrix, std::vector<float>* colors)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderTile()");

  const float opacityThreshold = 0.95f;

  vvVector3i minVox = _visibleRegion.getMin();
  vvVector3i maxVox = _visibleRegion.getMax();
  for (int i = 0; i < 3; ++i)
  {
    minVox[i] = std::max(minVox[i], 0);
    maxVox[i] = std::min(maxVox[i], vd->vox[i]);
  }
  const vvVector3 minCorner = vd->objectCoords(minVox);
  const vvVector3 maxCorner = vd->objectCoords(maxVox);
  const vvAABB aabb = vvAABB(minCorner, maxCorner);

  vvVector3 size2 = vd->getSize() * 0.5f;
  const float diagonalVoxels = sqrtf(float(vd->vox[0] * vd->vox[0] +
                                           vd->vox[1] * vd->vox[1] +
                                           vd->vox[2] * vd->vox[2]));
  int numSlices = std::max(1, static_cast<int>(_quality * diagonalVoxels));

  uchar* raw = vd->getRaw(vd->getCurrentFrame());

  for (int y = tile.bottom; y < tile.top; ++y)
  {
    for (int x = tile.left; x < tile.right; ++x)
    {
      const float u = (x / static_cast<float>(_width)) * 2.0f - 1.0f;
      const float v = (y / static_cast<float>(_height)) * 2.0f - 1.0f;

      vvVector4 o(u, v, -1.0f, 1.0f);
      o.multiply(invViewMatrix);
      vvVector4 d(u, v, 1.0f, 1.0f);
      d.multiply(invViewMatrix);

      Ray ray;
      ray.o = vvVector3(o[0] / o[3], o[1] / o[3], o[2] / o[3]);
      ray.d = vvVector3(d[0] / d[3], d[1] / d[3], d[2] / d[3]);
      ray.d = ray.d - ray.o;
      ray.d.normalize();

      float tbnear = 0.0f;
      float tbfar = 0.0f;

      const bool hit = intersectBox(ray, aabb, &tbnear, &tbfar);
      if (hit)
      {
        float dist = diagonalVoxels / float(numSlices);
        float t = tbnear;
        vvVector3 pos = ray.o + ray.d * tbnear;
        const vvVector3 step = ray.d * dist;
        vvVector4 dst(0.0f);

        while (true)
        {
          vvVector3 texcoord = vvVector3((pos[0] - vd->pos[0] + size2[0]) / (size2[0] * 2.0f),
                     (-pos[1] - vd->pos[1] + size2[1]) / (size2[1] * 2.0f),
                     (-pos[2] - vd->pos[2] + size2[2]) / (size2[2] * 2.0f));
          // calc voxel coordinates
          vvVector3i texcoordi = vvVector3i(int(texcoord[0] * float(vd->vox[0] - 1)),
                                            int(texcoord[1] * float(vd->vox[1] - 1)),
                                            int(texcoord[2] * float(vd->vox[2] - 1)));
          int idx = texcoordi[2] * vd->vox[0] * vd->vox[1] + texcoordi[1] * vd->vox[0] + texcoordi[0];
          float sample = float(raw[idx]) / 256.0f;
          vvVector4 src(_rgbaTF[int(sample * 4 * getLUTSize())],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 1],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 2],
                        _rgbaTF[int(sample * 4 * getLUTSize()) + 3]);

          if (_opacityCorrection)
          {
            src[3] = 1 - powf(1 - src[3], dist);
          }

          // pre-multiply alpha
          src[0] *= src[3];
          src[1] *= src[3];
          src[2] *= src[3];

          dst = dst + src * (1.0f - dst[3]);

          if (_earlyRayTermination && (dst[3] > opacityThreshold))
          {
            break;
          }

          t += dist;
          if (t > tbfar)
          {
            break;
          }
          pos += step;
        }

        for (int c = 0; c < 4; ++c)
        {
          (*colors)[y * _width * 4 + x * 4 + c] = dst[c];
        }
      }
    }
  }
}

void* vvSoftRayRend::renderFunc(void* args)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::renderFunc()");

  Thread* thread = static_cast<Thread*>(args);

  while (true)
  {
    pthread_mutex_lock(thread->mutex);
    bool haveEvent = !thread->events.empty();
    pthread_mutex_unlock(thread->mutex);

    if (haveEvent)
    {
      pthread_mutex_lock(thread->mutex);
      Thread::Event e = thread->events.front();
      pthread_mutex_unlock(thread->mutex);

      switch (e)
      {
      case Thread::VV_EXIT:
        goto cleanup;
      case Thread::VV_RENDER:
        render(thread);
        break;
      }

      pthread_mutex_lock(thread->mutex);
      thread->events.pop();
      pthread_mutex_unlock(thread->mutex);
    }
  }

cleanup:
  pthread_exit(NULL);
  return NULL;
}

void vvSoftRayRend::render(vvSoftRayRend::Thread* thread)
{
  vvDebugMsg::msg(3, "vvSoftRayRend::render()");

  pthread_barrier_wait(thread->barrier);
  while (true)
  {
    pthread_mutex_lock(thread->mutex);
    if (thread->tiles->empty())
    {
      pthread_mutex_unlock(thread->mutex);
      break;
    }
    Tile tile = thread->tiles->back();
    thread->tiles->pop_back();
    pthread_mutex_unlock(thread->mutex);
    thread->renderer->renderTile(tile, thread->invViewMatrix, thread->colors);
  }
  pthread_barrier_wait(thread->barrier);
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_parceldesc.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 09:44:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"
#include "dp_parceldesc.hxx"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

using ::rtl::OUString;

namespace css = ::com::sun::star;
namespace dp_registry
{
namespace backend
{
namespace sfwk
{

// XDocumentHandler
void SAL_CALL
ParcelDescDocHandler::startDocument()
throw ( xml::sax::SAXException, RuntimeException )
{
    m_bIsParsed = false;
}

void SAL_CALL
ParcelDescDocHandler::endDocument()
throw ( xml::sax::SAXException, RuntimeException )
{
    m_bIsParsed = true;
}

void SAL_CALL
ParcelDescDocHandler::characters( const OUString & aChars )
    throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::ignorableWhitespace( const OUString & aWhitespaces )
    throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::processingInstruction(
    const OUString & aTarget, const OUString & aData )
        throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::setDocumentLocator(
    const Reference< xml::sax::XLocator >& xLocator )
        throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::startElement( const OUString& aName,
    const Reference< xml::sax::XAttributeList > & xAttribs )
        throw ( xml::sax::SAXException,
            RuntimeException )
{
    OSL_TRACE("ParcelDescDocHandler::startElement() for %s",
        rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    if ( !skipIndex )
    {
        if ( aName.equals( OUString::createFromAscii( "parcel" ) ) )
        {
            m_sLang = xAttribs->getValueByName( OUString::createFromAscii( "language" ) );
        }
        ++skipIndex;
    }
    else
    {
        OSL_TRACE("ParcelDescDocHandler::startElement() skipping for %s",
            rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    }

}

void SAL_CALL ParcelDescDocHandler::endElement( const OUString & aName )
   throw ( xml::sax::SAXException, RuntimeException )
{
    if ( skipIndex )
    {
        --skipIndex;
        OSL_TRACE("ParcelDescDocHandler::endElement() skipping for %s",
            rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    }
}

}
}
}

<commit_msg>INTEGRATION: CWS sb59 (1.4.202); FILE MERGED 2006/07/20 07:55:31 sb 1.4.202.1: #i67537# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_parceldesc.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 14:12:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"
#include "dp_parceldesc.hxx"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

using ::rtl::OUString;

namespace css = ::com::sun::star;
namespace dp_registry
{
namespace backend
{
namespace sfwk
{

// XDocumentHandler
void SAL_CALL
ParcelDescDocHandler::startDocument()
throw ( xml::sax::SAXException, RuntimeException )
{
    m_bIsParsed = false;
}

void SAL_CALL
ParcelDescDocHandler::endDocument()
throw ( xml::sax::SAXException, RuntimeException )
{
    m_bIsParsed = true;
}

void SAL_CALL
ParcelDescDocHandler::characters( const OUString & )
    throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::ignorableWhitespace( const OUString & )
    throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::processingInstruction(
    const OUString &, const OUString & )
        throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::setDocumentLocator(
    const Reference< xml::sax::XLocator >& )
        throw ( xml::sax::SAXException, RuntimeException )
{
}

void SAL_CALL
ParcelDescDocHandler::startElement( const OUString& aName,
    const Reference< xml::sax::XAttributeList > & xAttribs )
        throw ( xml::sax::SAXException,
            RuntimeException )
{
    OSL_TRACE("ParcelDescDocHandler::startElement() for %s",
        rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    if ( !skipIndex )
    {
        if ( aName.equals( OUString::createFromAscii( "parcel" ) ) )
        {
            m_sLang = xAttribs->getValueByName( OUString::createFromAscii( "language" ) );
        }
        ++skipIndex;
    }
    else
    {
        OSL_TRACE("ParcelDescDocHandler::startElement() skipping for %s",
            rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    }

}

void SAL_CALL ParcelDescDocHandler::endElement( const OUString & aName )
   throw ( xml::sax::SAXException, RuntimeException )
{
    if ( skipIndex )
    {
        --skipIndex;
        OSL_TRACE("ParcelDescDocHandler::endElement() skipping for %s",
            rtl::OUStringToOString( aName, RTL_TEXTENCODING_ASCII_US ).getStr() );
    }
}

}
}
}

<|endoftext|>


<commit_before>#include "gc/gc.hpp"

#include "builtin/compiledmethod.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/iseq.hpp"
#include "builtin/staticscope.hpp"
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
#include "builtin/string.hpp"
#include "builtin/lookuptable.hpp"
#include "builtin/call_unit.hpp"

#include "ffi.hpp"
#include "marshal.hpp"
#include "primitives.hpp"
#include "objectmemory.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"
#include "object_utils.hpp"
#include "vm/object_utils.hpp"
#include "configuration.hpp"

#include "inline_cache.hpp"
#include "bytecode_verification.hpp"
#include "instruments/timing.hpp"

#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
#include "llvm/jit_runtime.hpp"
#endif

namespace rubinius {

  void CompiledMethod::init(STATE) {
    GO(cmethod).set(state->new_class("CompiledMethod", G(executable), G(rubinius)));
    G(cmethod)->set_object_type(state, CompiledMethodType);
    G(cmethod)->name(state, state->symbol("Rubinius::CompiledMethod"));
  }

  CompiledMethod* CompiledMethod::create(STATE) {
    CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod));
    cm->local_count(state, Fixnum::from(0));
    cm->set_executor(CompiledMethod::default_executor);
    cm->backend_method_ = NULL;
    cm->inliners_ = NULL;
    cm->prim_index_ = -1;

#ifdef ENABLE_LLVM
    cm->jit_data_ = NULL;
#endif

    return cm;
  }

  CompiledMethod* CompiledMethod::dup_cm(STATE) {
    CompiledMethod* cm = CompiledMethod::create(state);
    cm->copy_object(state, this);

    cm->set_executor(CompiledMethod::default_executor);
    cm->jit_data_ = NULL;
    cm->backend_method_ = NULL;

    return cm;
  }

  int CompiledMethod::start_line(STATE) {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(state, 1))->to_native();
  }

  int CompiledMethod::start_line() {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(1))->to_native();
  }

  int CompiledMethod::line(STATE, int ip) {
    if(lines_->nil_p()) return -3;

    size_t fin = lines_->num_fields() - 2;
    for(size_t i = 0; i < fin; i += 2) {
      Fixnum* start_ip = as<Fixnum>(lines_->at(state, i));
      Fixnum* end_ip   = as<Fixnum>(lines_->at(state, i+2));

      if(start_ip->to_native() <= ip && end_ip->to_native() > ip) {
        return as<Fixnum>(lines_->at(state, i+1))->to_native();
      }
    }

    return as<Fixnum>(lines_->at(state, fin+1))->to_native();
  }

  VMMethod* CompiledMethod::internalize(STATE, const char** reason, int* ip) {
    atomic::memory_barrier();
    if(!backend_method_) {
      if(lock(state) != eLocked) rubinius::abort();
      if(!backend_method_) {
        {
          timer::Running<double, timer::milliseconds> tr(
              state->shared.stats.verification_time);

          BytecodeVerification bv(this);
          if(!bv.verify(state)) {
            if(reason) *reason = bv.failure_reason();
            if(ip) *ip = bv.failure_ip();
            std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n";
            return 0;
          }
        }

        VMMethod* vmm = NULL;
        vmm = new VMMethod(state, this);

        if(!resolve_primitive(state)) {
          vmm->setup_argument_handler(this);
        }

        backend_method_ = vmm;
        atomic::memory_barrier();
      }

      unlock(state);
    }
    return backend_method_;
  }

  Object* CompiledMethod::primitive_failed(STATE, CallFrame* call_frame,
              Executable* exec, Module* mod, Arguments& args)
  {
    if(try_as<CompiledMethod>(exec)) {
      return VMMethod::execute(state, call_frame, exec, mod, args);
    }

    // TODO fix me to raise an exception
    assert(0);
    return Qnil;
  }

  void CompiledMethod::specialize(STATE, TypeInfo* ti) {
    backend_method_->specialize(state, this, ti);
  }

  Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame,
                          Executable* exec, Module* mod, Arguments& args)
  {
    LockableScopedLock lg(state, &state->shared, __FILE__, __LINE__);

    CompiledMethod* cm = as<CompiledMethod>(exec);
    if(cm->execute == default_executor) {
      const char* reason = 0;
      int ip = -1;

      if(!cm->internalize(state, &reason, &ip)) {
        Exception::bytecode_error(state, call_frame, cm, ip, reason);
        return 0;
      }
    }

    lg.unlock();

    return cm->execute(state, call_frame, exec, mod, args);
  }

  void CompiledMethod::post_marshal(STATE) {
  }

  size_t CompiledMethod::number_of_locals() {
    return local_count_->to_native();
  }

  String* CompiledMethod::full_name(STATE) {
    return name_->to_str(state);
  }

  Object* CompiledMethod::jit_now(STATE) {
    return Qfalse;
#ifdef ENABLE_LLVM
    if(backend_method_ == NULL) {
      internalize(state);
    }

    if(state->shared.config.jit_show_compiling) {
      std::cout << "[[[ JIT compiling " << full_name(state)->c_str() << " ]]]\n";
    }

    LLVMState* ls = LLVMState::get(state);

    jit::Compiler jit;
    jit.compile_method(ls, this, backend_method_);

    if(jit.generate_function(ls)) {
      backend_method_->set_jitted(jit.llvm_function(),
                                  jit.code_bytes(), jit.function_pointer());
      return Qtrue;
    }
#endif

    return Qfalse;
  }

  Object* CompiledMethod::jit_soon(STATE) {
    return Qfalse;
#ifdef ENABLE_LLVM
    if(backend_method_ == NULL) {
      internalize(state);
    }

    if(state->shared.config.jit_show_compiling) {
      std::cout << "[[[ JIT queueing " << full_name(state)->c_str() << " ]]]\n";
    }

    LLVMState::get(state)->compile_soon(state, this);
    return Qtrue;
#else
    return Qfalse;
#endif
  }

  Object* CompiledMethod::set_breakpoint(STATE, Fixnum* ip, Object* bp) {
    int i = ip->to_native();
    if(backend_method_ == NULL) {
      if(!internalize(state)) return Primitives::failure();
    }
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    if(breakpoints_->nil_p()) {
      breakpoints(state, LookupTable::create(state));
    }

    breakpoints_->store(state, ip, bp);
    backend_method_->debugging = 1;
    backend_method_->run = VMMethod::debugger_interpreter;
    return ip;
  }

  Object* CompiledMethod::clear_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return ip;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    bool removed = false;
    if(!breakpoints_->nil_p()) {
      breakpoints_->remove(state, ip, &removed);

      // No more breakpoints, switch back to the normal interpreter
      if(breakpoints_->entries()->to_native() == 0) {
        backend_method_->debugging = 0;
        backend_method_->run = VMMethod::interpreter;
      }
    }

    return removed ? Qtrue : Qfalse;
  }

  Object* CompiledMethod::is_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return Qfalse;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();
    if(breakpoints_->nil_p()) return Qfalse;

    bool found = false;
    breakpoints_->fetch(state, ip, &found);

    if(found) return Qtrue;
    return Qfalse;
  }

  CompiledMethod* CompiledMethod::of_sender(STATE, CallFrame* calling_environment) {
    CallFrame* caller = static_cast<CallFrame*>(calling_environment->previous);
    if(caller) {
      if(caller->cm) {
        return caller->cm;
      }
    }

    return nil<CompiledMethod>();
  }

  void CompiledMethod::Info::mark(Object* obj, ObjectMark& mark) {
    auto_mark(obj, mark);

    mark_inliners(obj, mark);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;
    vmm->set_mark();

    Object* tmp;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->set_mark();
      cm->jit_data()->mark_all(cm, mark);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        tmp = mark.call(cache->module);
        if(tmp) {
          cache->module = (Module*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->method) {
        tmp = mark.call(cache->method);
        if(tmp) {
          cache->method = (Executable*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->klass_) {
        tmp = mark.call(cache->klass_);
        if(tmp) {
          cache->klass_ = (Class*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->call_unit_) {
        tmp = mark.call(cache->call_unit_);
        if(tmp) {
          cache->call_unit_ = (CallUnit*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) {
          tmp = mark.call(mod);
          if(tmp) {
            cache->seen_classes_[i].set_klass(force_as<Class>(tmp));
            mark.just_set(obj, tmp);
          }
        }
      }
    }

    for(IndirectLiterals::iterator i = vmm->indirect_literals().begin();
        i != vmm->indirect_literals().end();
        i++) {
      Object** ptr = (*i);
      if((tmp = mark.call(*ptr)) != NULL) {
        *ptr = tmp;
        mark.just_set(obj, tmp);
      }
    }
  }

  void CompiledMethod::Info::visit(Object* obj, ObjectVisitor& visit) {
    auto_visit(obj, visit);

    visit_inliners(obj, visit);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->visit_all(visit);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        visit.call(cache->module);
      }

      if(cache->method) {
        visit.call(cache->method);
      }

      if(cache->klass_) {
        visit.call(cache->klass_);
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) visit.call(mod);
      }
    }
  }

  void CompiledMethod::Info::show(STATE, Object* self, int level) {
    CompiledMethod* cm = as<CompiledMethod>(self);

    class_header(state, self);
    indent_attribute(++level, "file"); cm->file()->show(state, level);
    indent_attribute(level, "iseq"); cm->iseq()->show(state, level);
    indent_attribute(level, "lines"); cm->lines()->show_simple(state, level);
    indent_attribute(level, "literals"); cm->literals()->show_simple(state, level);
    indent_attribute(level, "local_count"); cm->local_count()->show(state, level);
    indent_attribute(level, "local_names"); cm->local_names()->show_simple(state, level);
    indent_attribute(level, "name"); cm->name()->show(state, level);
    indent_attribute(level, "required_args"); cm->required_args()->show(state, level);
    indent_attribute(level, "scope"); cm->scope()->show(state, level);
    indent_attribute(level, "splat"); cm->splat()->show(state, level);
    indent_attribute(level, "stack_size"); cm->stack_size()->show(state, level);
    indent_attribute(level, "total_args"); cm->total_args()->show(state, level);

#ifdef ENABLE_LLVM
    if(cm->backend_method_ && cm->backend_method_->jitted()) {
      llvm::outs() << "<LLVM>\n"
                   << *cm->backend_method_->llvm_function()
                   << "</LLVM>\n<MachineCode>\n";
      LLVMState::show_machine_code(
          cm->backend_method_->jitted_impl(),
          cm->backend_method_->jitted_bytes());
      llvm::outs() << "</MachineCode>\n";
    }
#endif

    close_body(level);
  }
}
<commit_msg>Move the barriers to the right places<commit_after>#include "gc/gc.hpp"

#include "builtin/compiledmethod.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/iseq.hpp"
#include "builtin/staticscope.hpp"
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
#include "builtin/string.hpp"
#include "builtin/lookuptable.hpp"
#include "builtin/call_unit.hpp"

#include "ffi.hpp"
#include "marshal.hpp"
#include "primitives.hpp"
#include "objectmemory.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"
#include "object_utils.hpp"
#include "vm/object_utils.hpp"
#include "configuration.hpp"

#include "inline_cache.hpp"
#include "bytecode_verification.hpp"
#include "instruments/timing.hpp"

#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
#include "llvm/jit_runtime.hpp"
#endif

namespace rubinius {

  void CompiledMethod::init(STATE) {
    GO(cmethod).set(state->new_class("CompiledMethod", G(executable), G(rubinius)));
    G(cmethod)->set_object_type(state, CompiledMethodType);
    G(cmethod)->name(state, state->symbol("Rubinius::CompiledMethod"));
  }

  CompiledMethod* CompiledMethod::create(STATE) {
    CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod));
    cm->local_count(state, Fixnum::from(0));
    cm->set_executor(CompiledMethod::default_executor);
    cm->backend_method_ = NULL;
    cm->inliners_ = NULL;
    cm->prim_index_ = -1;

#ifdef ENABLE_LLVM
    cm->jit_data_ = NULL;
#endif

    return cm;
  }

  CompiledMethod* CompiledMethod::dup_cm(STATE) {
    CompiledMethod* cm = CompiledMethod::create(state);
    cm->copy_object(state, this);

    cm->set_executor(CompiledMethod::default_executor);
    cm->jit_data_ = NULL;
    cm->backend_method_ = NULL;

    return cm;
  }

  int CompiledMethod::start_line(STATE) {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(state, 1))->to_native();
  }

  int CompiledMethod::start_line() {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(1))->to_native();
  }

  int CompiledMethod::line(STATE, int ip) {
    if(lines_->nil_p()) return -3;

    size_t fin = lines_->num_fields() - 2;
    for(size_t i = 0; i < fin; i += 2) {
      Fixnum* start_ip = as<Fixnum>(lines_->at(state, i));
      Fixnum* end_ip   = as<Fixnum>(lines_->at(state, i+2));

      if(start_ip->to_native() <= ip && end_ip->to_native() > ip) {
        return as<Fixnum>(lines_->at(state, i+1))->to_native();
      }
    }

    return as<Fixnum>(lines_->at(state, fin+1))->to_native();
  }

  VMMethod* CompiledMethod::internalize(STATE, const char** reason, int* ip) {
    if(!backend_method_) {
      if(lock(state) != eLocked) rubinius::abort();
      if(!backend_method_) {
        {
          timer::Running<double, timer::milliseconds> tr(
              state->shared.stats.verification_time);

          BytecodeVerification bv(this);
          if(!bv.verify(state)) {
            if(reason) *reason = bv.failure_reason();
            if(ip) *ip = bv.failure_ip();
            std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n";
            return 0;
          }
        }

        VMMethod* vmm = NULL;
        vmm = new VMMethod(state, this);

        if(!resolve_primitive(state)) {
          vmm->setup_argument_handler(this);
        }

        atomic::memory_barrier();
        backend_method_ = vmm;
      }

      unlock(state);
    }
    atomic::memory_barrier();
    return backend_method_;
  }

  Object* CompiledMethod::primitive_failed(STATE, CallFrame* call_frame,
              Executable* exec, Module* mod, Arguments& args)
  {
    if(try_as<CompiledMethod>(exec)) {
      return VMMethod::execute(state, call_frame, exec, mod, args);
    }

    // TODO fix me to raise an exception
    assert(0);
    return Qnil;
  }

  void CompiledMethod::specialize(STATE, TypeInfo* ti) {
    backend_method_->specialize(state, this, ti);
  }

  Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame,
                          Executable* exec, Module* mod, Arguments& args)
  {
    LockableScopedLock lg(state, &state->shared, __FILE__, __LINE__);

    CompiledMethod* cm = as<CompiledMethod>(exec);
    if(cm->execute == default_executor) {
      const char* reason = 0;
      int ip = -1;

      if(!cm->internalize(state, &reason, &ip)) {
        Exception::bytecode_error(state, call_frame, cm, ip, reason);
        return 0;
      }
    }

    lg.unlock();

    return cm->execute(state, call_frame, exec, mod, args);
  }

  void CompiledMethod::post_marshal(STATE) {
  }

  size_t CompiledMethod::number_of_locals() {
    return local_count_->to_native();
  }

  String* CompiledMethod::full_name(STATE) {
    return name_->to_str(state);
  }

  Object* CompiledMethod::jit_now(STATE) {
    return Qfalse;
#ifdef ENABLE_LLVM
    if(backend_method_ == NULL) {
      internalize(state);
    }

    if(state->shared.config.jit_show_compiling) {
      std::cout << "[[[ JIT compiling " << full_name(state)->c_str() << " ]]]\n";
    }

    LLVMState* ls = LLVMState::get(state);

    jit::Compiler jit;
    jit.compile_method(ls, this, backend_method_);

    if(jit.generate_function(ls)) {
      backend_method_->set_jitted(jit.llvm_function(),
                                  jit.code_bytes(), jit.function_pointer());
      return Qtrue;
    }
#endif

    return Qfalse;
  }

  Object* CompiledMethod::jit_soon(STATE) {
    return Qfalse;
#ifdef ENABLE_LLVM
    if(backend_method_ == NULL) {
      internalize(state);
    }

    if(state->shared.config.jit_show_compiling) {
      std::cout << "[[[ JIT queueing " << full_name(state)->c_str() << " ]]]\n";
    }

    LLVMState::get(state)->compile_soon(state, this);
    return Qtrue;
#else
    return Qfalse;
#endif
  }

  Object* CompiledMethod::set_breakpoint(STATE, Fixnum* ip, Object* bp) {
    int i = ip->to_native();
    if(backend_method_ == NULL) {
      if(!internalize(state)) return Primitives::failure();
    }
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    if(breakpoints_->nil_p()) {
      breakpoints(state, LookupTable::create(state));
    }

    breakpoints_->store(state, ip, bp);
    backend_method_->debugging = 1;
    backend_method_->run = VMMethod::debugger_interpreter;
    return ip;
  }

  Object* CompiledMethod::clear_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return ip;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    bool removed = false;
    if(!breakpoints_->nil_p()) {
      breakpoints_->remove(state, ip, &removed);

      // No more breakpoints, switch back to the normal interpreter
      if(breakpoints_->entries()->to_native() == 0) {
        backend_method_->debugging = 0;
        backend_method_->run = VMMethod::interpreter;
      }
    }

    return removed ? Qtrue : Qfalse;
  }

  Object* CompiledMethod::is_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return Qfalse;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();
    if(breakpoints_->nil_p()) return Qfalse;

    bool found = false;
    breakpoints_->fetch(state, ip, &found);

    if(found) return Qtrue;
    return Qfalse;
  }

  CompiledMethod* CompiledMethod::of_sender(STATE, CallFrame* calling_environment) {
    CallFrame* caller = static_cast<CallFrame*>(calling_environment->previous);
    if(caller) {
      if(caller->cm) {
        return caller->cm;
      }
    }

    return nil<CompiledMethod>();
  }

  void CompiledMethod::Info::mark(Object* obj, ObjectMark& mark) {
    auto_mark(obj, mark);

    mark_inliners(obj, mark);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;
    vmm->set_mark();

    Object* tmp;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->set_mark();
      cm->jit_data()->mark_all(cm, mark);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        tmp = mark.call(cache->module);
        if(tmp) {
          cache->module = (Module*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->method) {
        tmp = mark.call(cache->method);
        if(tmp) {
          cache->method = (Executable*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->klass_) {
        tmp = mark.call(cache->klass_);
        if(tmp) {
          cache->klass_ = (Class*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->call_unit_) {
        tmp = mark.call(cache->call_unit_);
        if(tmp) {
          cache->call_unit_ = (CallUnit*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) {
          tmp = mark.call(mod);
          if(tmp) {
            cache->seen_classes_[i].set_klass(force_as<Class>(tmp));
            mark.just_set(obj, tmp);
          }
        }
      }
    }

    for(IndirectLiterals::iterator i = vmm->indirect_literals().begin();
        i != vmm->indirect_literals().end();
        i++) {
      Object** ptr = (*i);
      if((tmp = mark.call(*ptr)) != NULL) {
        *ptr = tmp;
        mark.just_set(obj, tmp);
      }
    }
  }

  void CompiledMethod::Info::visit(Object* obj, ObjectVisitor& visit) {
    auto_visit(obj, visit);

    visit_inliners(obj, visit);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->visit_all(visit);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        visit.call(cache->module);
      }

      if(cache->method) {
        visit.call(cache->method);
      }

      if(cache->klass_) {
        visit.call(cache->klass_);
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) visit.call(mod);
      }
    }
  }

  void CompiledMethod::Info::show(STATE, Object* self, int level) {
    CompiledMethod* cm = as<CompiledMethod>(self);

    class_header(state, self);
    indent_attribute(++level, "file"); cm->file()->show(state, level);
    indent_attribute(level, "iseq"); cm->iseq()->show(state, level);
    indent_attribute(level, "lines"); cm->lines()->show_simple(state, level);
    indent_attribute(level, "literals"); cm->literals()->show_simple(state, level);
    indent_attribute(level, "local_count"); cm->local_count()->show(state, level);
    indent_attribute(level, "local_names"); cm->local_names()->show_simple(state, level);
    indent_attribute(level, "name"); cm->name()->show(state, level);
    indent_attribute(level, "required_args"); cm->required_args()->show(state, level);
    indent_attribute(level, "scope"); cm->scope()->show(state, level);
    indent_attribute(level, "splat"); cm->splat()->show(state, level);
    indent_attribute(level, "stack_size"); cm->stack_size()->show(state, level);
    indent_attribute(level, "total_args"); cm->total_args()->show(state, level);

#ifdef ENABLE_LLVM
    if(cm->backend_method_ && cm->backend_method_->jitted()) {
      llvm::outs() << "<LLVM>\n"
                   << *cm->backend_method_->llvm_function()
                   << "</LLVM>\n<MachineCode>\n";
      LLVMState::show_machine_code(
          cm->backend_method_->jitted_impl(),
          cm->backend_method_->jitted_bytes());
      llvm::outs() << "</MachineCode>\n";
    }
#endif

    close_body(level);
  }
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "entityeditorwindow.h"

// UI definition header.
#include "ui_entityeditorwindow.h"

// appleseed.studio headers.
#include "mainwindow/project/entitybrowserwindow.h"
#include "utility/interop.h"
#include "utility/tweaks.h"

// appleseed.foundation headers.
#include "foundation/utility/foreach.h"
#include "foundation/utility/string.h"

// Qt headers.
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QShortcut>
#include <QSignalMapper>
#include <Qt>

// Standard headers.
#include <cassert>

using namespace foundation;
using namespace std;

namespace appleseed {
namespace studio {

EntityEditorWindow::EntityEditorWindow(
    QWidget*                    parent,
    const string&               window_title,
    auto_ptr<IFormFactory>      form_factory,
    auto_ptr<IEntityBrowser>    entity_browser,
    const Dictionary&           values)
  : QWidget(parent)
  , m_ui(new Ui::EntityEditorWindow())
  , m_form_factory(form_factory)
  , m_entity_browser(entity_browser)
  , m_form_layout(0)
  , m_signal_mapper(new QSignalMapper(this))
{
    m_ui->setupUi(this);

    setAttribute(Qt::WA_DeleteOnClose);
    setWindowFlags(Qt::Tool);
    setWindowTitle(QString::fromStdString(window_title));

    resize(400, 300);

    create_form_layout();
    rebuild_form(values);

    connect(
        m_signal_mapper, SIGNAL(mapped(const QString&)),
        this, SLOT(slot_open_entity_browser(const QString&)));

    connect(
        m_ui->buttonbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
        this, SLOT(slot_accept()));

    connect(
        m_ui->buttonbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
        this, SLOT(close()));

    connect(
        create_window_local_shortcut(this, Qt::Key_Return), SIGNAL(activated()),
        this, SLOT(slot_accept()));

    connect(
        create_window_local_shortcut(this, Qt::Key_Escape), SIGNAL(activated()),
        this, SLOT(close()));
}

EntityEditorWindow::~EntityEditorWindow()
{
    for (const_each<WidgetProxyCollection> i = m_widget_proxies; i; ++i)
        delete i->second;

    delete m_ui;
}

namespace
{
    void delete_layout_items(QLayout* layout)
    {
        while (!layout->isEmpty())
        {
            QLayoutItem* item = layout->takeAt(0);

            if (item->layout())
                delete_layout_items(item->layout());
            else item->widget()->deleteLater();

            delete item;
        }
    }
}

void EntityEditorWindow::rebuild_form(const Dictionary& values)
{
    delete_layout_items(m_form_layout);

    m_form_factory->update(values, m_widget_definitions);

    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
        create_input_widget(*i);
}

void EntityEditorWindow::create_form_layout()
{
    m_form_layout = new QFormLayout(m_ui->scrollarea_contents);

    int left, top, right, bottom;
    m_form_layout->getContentsMargins(&left, &top, &right, &bottom);
    m_form_layout->setContentsMargins(0, top, 0, bottom);
}

Dictionary EntityEditorWindow::get_widget_definition(const string& name) const
{
    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
    {
        const Dictionary& definition = *i;

        if (definition.get<string>("name") == name)
            return definition;
    }

    return Dictionary();
}

void EntityEditorWindow::create_input_widget(const Dictionary& definition)
{
    const string widget_type = definition.get<string>("widget");

    if (widget_type == "text_box")
    {
        create_text_box_input_widget(definition);
    }
    else if (widget_type == "entity_picker")
    {
        create_entity_picker_input_widget(definition);
    }
    else if (widget_type == "dropdown_list")
    {
        create_dropdown_list_input_widget(definition);
    }
    else
    {
        assert(!"Unknown widget type.");
    }
}

namespace
{
    QString get_label_text(const Dictionary& definition)
    {
        return definition.get<QString>("label") + ":";
    }

    bool should_be_focused(const Dictionary& definition)
    {
        return
            definition.strings().exist("focus") &&
            definition.strings().get<bool>("focus");
    }
}

void EntityEditorWindow::create_text_box_input_widget(const Dictionary& definition)
{
    QLineEdit* line_edit = new QLineEdit(m_ui->scrollarea_contents);

    if (definition.strings().exist("default"))
        line_edit->setText(definition.strings().get<QString>("default"));

    if (should_be_focused(definition))
    {
        line_edit->selectAll();
        line_edit->setFocus();
    }

    m_form_layout->addRow(get_label_text(definition), line_edit);

    const string name = definition.get<string>("name");
    m_widget_proxies[name] = new LineEditProxy(line_edit);
}

void EntityEditorWindow::create_entity_picker_input_widget(const Dictionary& definition)
{
    QLineEdit* line_edit = new QLineEdit(m_ui->scrollarea_contents);

    if (definition.strings().exist("default"))
        line_edit->setText(definition.strings().get<QString>("default"));

    if (should_be_focused(definition))
    {
        line_edit->selectAll();
        line_edit->setFocus();
    }

    QWidget* button = new QPushButton("Browse", m_ui->scrollarea_contents);
    button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    connect(button, SIGNAL(clicked()), m_signal_mapper, SLOT(map()));

    const string name = definition.get<string>("name");
    m_signal_mapper->setMapping(button, QString::fromStdString(name));

    QHBoxLayout* layout = new QHBoxLayout();
    layout->addWidget(line_edit);
    layout->addWidget(button);

    m_form_layout->addRow(get_label_text(definition), layout);

    m_widget_proxies[name] = new LineEditProxy(line_edit);
}

void EntityEditorWindow::create_dropdown_list_input_widget(const Dictionary& definition)
{
    QComboBox* combo_box = new QComboBox(m_ui->scrollarea_contents);
    combo_box->setEditable(false);

    const StringDictionary& items = definition.dictionaries().get("dropdown_items").strings();
    for (const_each<StringDictionary> i = items; i; ++i)
        combo_box->addItem(i->name(), i->value<QString>());

    if (definition.strings().exist("default"))
    {
        const QString default_value = definition.strings().get<QString>("default");
        combo_box->setCurrentIndex(combo_box->findData(QVariant::fromValue(default_value)));
    }

    if (definition.strings().exist("on_change"))
    {
        const string on_change_value = definition.strings().get<string>("on_change");
        if (on_change_value == "rebuild_form")
            connect(combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slot_rebuild_form()));
    }

    if (should_be_focused(definition))
        combo_box->setFocus();

    m_form_layout->addRow(get_label_text(definition), combo_box);

    const string name = definition.get<string>("name");
    m_widget_proxies[name] = new ComboBoxProxy(combo_box);
}

Dictionary EntityEditorWindow::get_values() const
{
    Dictionary values;

    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
    {
        const Dictionary& definition = *i;

        const string name = definition.get<string>("name");
        const string value = m_widget_proxies.find(name)->second->get();

        values.insert(name, value);
    }

    return values;
}

void EntityEditorWindow::slot_rebuild_form()
{
    rebuild_form(get_values());
}

namespace
{
    class ForwardAcceptedSignal
      : public QObject
    {
        Q_OBJECT

      public:
        ForwardAcceptedSignal(QObject* parent, const QString& widget_name)
          : QObject(parent)
          , m_widget_name(widget_name)
        {
        }

      public slots:
        void slot_accept(QString page_name, QString entity_name)
        {
            emit signal_accepted(m_widget_name, page_name, entity_name);
        }

      signals:
        void signal_accepted(QString widget_name, QString page_name, QString entity_name);

      private:
        const QString m_widget_name;
    };
}

void EntityEditorWindow::slot_open_entity_browser(const QString& widget_name)
{
    const Dictionary widget_definition = get_widget_definition(widget_name.toStdString());

    EntityBrowserWindow* browser_window =
        new EntityBrowserWindow(
            this,
            widget_definition.get<string>("label"));

    const Dictionary& entity_types = widget_definition.dictionaries().get("entity_types");

    for (const_each<StringDictionary> i = entity_types.strings(); i; ++i)
    {
        const string entity_type = i->name();
        const string entity_label = i->value<string>();
        const StringDictionary entities = m_entity_browser->get_entities(entity_type);
        browser_window->add_items_page(entity_type, entity_label, entities);
    }

    ForwardAcceptedSignal* forward_signal =
        new ForwardAcceptedSignal(browser_window, widget_name);

    QObject::connect(
        browser_window, SIGNAL(signal_accepted(QString, QString)),
        forward_signal, SLOT(slot_accept(QString, QString)));

    QObject::connect(
        forward_signal, SIGNAL(signal_accepted(QString, QString, QString)),
        this, SLOT(slot_entity_browser_accept(QString, QString, QString)));

    browser_window->showNormal();
    browser_window->activateWindow();
}

void EntityEditorWindow::slot_entity_browser_accept(QString widget_name, QString page_name, QString entity_name)
{
    m_widget_proxies[widget_name.toStdString()]->set(entity_name.toStdString());

    // Close the entity browser.
    qobject_cast<QWidget*>(sender()->parent())->close();
}

void EntityEditorWindow::slot_accept()
{
    emit signal_accepted(get_values());
}

}   // namespace studio
}   // namespace appleseed

#include "mainwindow/project/moc_cpp_entityeditorwindow.cxx"
<commit_msg>fixed the layout of the widgets inside the entity editor window.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "entityeditorwindow.h"

// UI definition header.
#include "ui_entityeditorwindow.h"

// appleseed.studio headers.
#include "mainwindow/project/entitybrowserwindow.h"
#include "utility/interop.h"
#include "utility/tweaks.h"

// appleseed.foundation headers.
#include "foundation/utility/foreach.h"
#include "foundation/utility/string.h"

// Qt headers.
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QShortcut>
#include <QSignalMapper>
#include <Qt>

// Standard headers.
#include <cassert>

using namespace foundation;
using namespace std;

namespace appleseed {
namespace studio {

EntityEditorWindow::EntityEditorWindow(
    QWidget*                    parent,
    const string&               window_title,
    auto_ptr<IFormFactory>      form_factory,
    auto_ptr<IEntityBrowser>    entity_browser,
    const Dictionary&           values)
  : QWidget(parent)
  , m_ui(new Ui::EntityEditorWindow())
  , m_form_factory(form_factory)
  , m_entity_browser(entity_browser)
  , m_form_layout(0)
  , m_signal_mapper(new QSignalMapper(this))
{
    m_ui->setupUi(this);

    setAttribute(Qt::WA_DeleteOnClose);
    setWindowFlags(Qt::Tool);
    setWindowTitle(QString::fromStdString(window_title));

    resize(400, 300);

    create_form_layout();
    rebuild_form(values);

    connect(
        m_signal_mapper, SIGNAL(mapped(const QString&)),
        this, SLOT(slot_open_entity_browser(const QString&)));

    connect(
        m_ui->buttonbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
        this, SLOT(slot_accept()));

    connect(
        m_ui->buttonbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
        this, SLOT(close()));

    connect(
        create_window_local_shortcut(this, Qt::Key_Return), SIGNAL(activated()),
        this, SLOT(slot_accept()));

    connect(
        create_window_local_shortcut(this, Qt::Key_Escape), SIGNAL(activated()),
        this, SLOT(close()));
}

EntityEditorWindow::~EntityEditorWindow()
{
    for (const_each<WidgetProxyCollection> i = m_widget_proxies; i; ++i)
        delete i->second;

    delete m_ui;
}

namespace
{
    void delete_layout_items(QLayout* layout)
    {
        while (!layout->isEmpty())
        {
            QLayoutItem* item = layout->takeAt(0);

            if (item->layout())
                delete_layout_items(item->layout());
            else item->widget()->deleteLater();

            delete item;
        }
    }
}

void EntityEditorWindow::rebuild_form(const Dictionary& values)
{
    delete_layout_items(m_form_layout);

    m_form_factory->update(values, m_widget_definitions);

    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
        create_input_widget(*i);
}

void EntityEditorWindow::create_form_layout()
{
    m_form_layout = new QFormLayout(m_ui->scrollarea_contents);
    m_form_layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);

    int left, top, right, bottom;
    m_form_layout->getContentsMargins(&left, &top, &right, &bottom);
    m_form_layout->setContentsMargins(0, top, 0, bottom);
}

Dictionary EntityEditorWindow::get_widget_definition(const string& name) const
{
    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
    {
        const Dictionary& definition = *i;

        if (definition.get<string>("name") == name)
            return definition;
    }

    return Dictionary();
}

void EntityEditorWindow::create_input_widget(const Dictionary& definition)
{
    const string widget_type = definition.get<string>("widget");

    if (widget_type == "text_box")
    {
        create_text_box_input_widget(definition);
    }
    else if (widget_type == "entity_picker")
    {
        create_entity_picker_input_widget(definition);
    }
    else if (widget_type == "dropdown_list")
    {
        create_dropdown_list_input_widget(definition);
    }
    else
    {
        assert(!"Unknown widget type.");
    }
}

namespace
{
    QString get_label_text(const Dictionary& definition)
    {
        return definition.get<QString>("label") + ":";
    }

    bool should_be_focused(const Dictionary& definition)
    {
        return
            definition.strings().exist("focus") &&
            definition.strings().get<bool>("focus");
    }
}

void EntityEditorWindow::create_text_box_input_widget(const Dictionary& definition)
{
    QLineEdit* line_edit = new QLineEdit(m_ui->scrollarea_contents);

    if (definition.strings().exist("default"))
        line_edit->setText(definition.strings().get<QString>("default"));

    if (should_be_focused(definition))
    {
        line_edit->selectAll();
        line_edit->setFocus();
    }

    m_form_layout->addRow(get_label_text(definition), line_edit);

    const string name = definition.get<string>("name");
    m_widget_proxies[name] = new LineEditProxy(line_edit);
}

void EntityEditorWindow::create_entity_picker_input_widget(const Dictionary& definition)
{
    QLineEdit* line_edit = new QLineEdit(m_ui->scrollarea_contents);

    if (definition.strings().exist("default"))
        line_edit->setText(definition.strings().get<QString>("default"));

    if (should_be_focused(definition))
    {
        line_edit->selectAll();
        line_edit->setFocus();
    }

    QWidget* button = new QPushButton("Browse", m_ui->scrollarea_contents);
    button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    connect(button, SIGNAL(clicked()), m_signal_mapper, SLOT(map()));

    const string name = definition.get<string>("name");
    m_signal_mapper->setMapping(button, QString::fromStdString(name));

    QHBoxLayout* layout = new QHBoxLayout();
    layout->addWidget(line_edit);
    layout->addWidget(button);

    m_form_layout->addRow(get_label_text(definition), layout);

    m_widget_proxies[name] = new LineEditProxy(line_edit);
}

void EntityEditorWindow::create_dropdown_list_input_widget(const Dictionary& definition)
{
    QComboBox* combo_box = new QComboBox(m_ui->scrollarea_contents);
    combo_box->setEditable(false);

    const StringDictionary& items = definition.dictionaries().get("dropdown_items").strings();
    for (const_each<StringDictionary> i = items; i; ++i)
        combo_box->addItem(i->name(), i->value<QString>());

    if (definition.strings().exist("default"))
    {
        const QString default_value = definition.strings().get<QString>("default");
        combo_box->setCurrentIndex(combo_box->findData(QVariant::fromValue(default_value)));
    }

    if (definition.strings().exist("on_change"))
    {
        const string on_change_value = definition.strings().get<string>("on_change");
        if (on_change_value == "rebuild_form")
            connect(combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(slot_rebuild_form()));
    }

    if (should_be_focused(definition))
        combo_box->setFocus();

    m_form_layout->addRow(get_label_text(definition), combo_box);

    const string name = definition.get<string>("name");
    m_widget_proxies[name] = new ComboBoxProxy(combo_box);
}

Dictionary EntityEditorWindow::get_values() const
{
    Dictionary values;

    for (const_each<WidgetDefinitionCollection> i = m_widget_definitions; i; ++i)
    {
        const Dictionary& definition = *i;

        const string name = definition.get<string>("name");
        const string value = m_widget_proxies.find(name)->second->get();

        values.insert(name, value);
    }

    return values;
}

void EntityEditorWindow::slot_rebuild_form()
{
    rebuild_form(get_values());
}

namespace
{
    class ForwardAcceptedSignal
      : public QObject
    {
        Q_OBJECT

      public:
        ForwardAcceptedSignal(QObject* parent, const QString& widget_name)
          : QObject(parent)
          , m_widget_name(widget_name)
        {
        }

      public slots:
        void slot_accept(QString page_name, QString entity_name)
        {
            emit signal_accepted(m_widget_name, page_name, entity_name);
        }

      signals:
        void signal_accepted(QString widget_name, QString page_name, QString entity_name);

      private:
        const QString m_widget_name;
    };
}

void EntityEditorWindow::slot_open_entity_browser(const QString& widget_name)
{
    const Dictionary widget_definition = get_widget_definition(widget_name.toStdString());

    EntityBrowserWindow* browser_window =
        new EntityBrowserWindow(
            this,
            widget_definition.get<string>("label"));

    const Dictionary& entity_types = widget_definition.dictionaries().get("entity_types");

    for (const_each<StringDictionary> i = entity_types.strings(); i; ++i)
    {
        const string entity_type = i->name();
        const string entity_label = i->value<string>();
        const StringDictionary entities = m_entity_browser->get_entities(entity_type);
        browser_window->add_items_page(entity_type, entity_label, entities);
    }

    ForwardAcceptedSignal* forward_signal =
        new ForwardAcceptedSignal(browser_window, widget_name);

    QObject::connect(
        browser_window, SIGNAL(signal_accepted(QString, QString)),
        forward_signal, SLOT(slot_accept(QString, QString)));

    QObject::connect(
        forward_signal, SIGNAL(signal_accepted(QString, QString, QString)),
        this, SLOT(slot_entity_browser_accept(QString, QString, QString)));

    browser_window->showNormal();
    browser_window->activateWindow();
}

void EntityEditorWindow::slot_entity_browser_accept(QString widget_name, QString page_name, QString entity_name)
{
    m_widget_proxies[widget_name.toStdString()]->set(entity_name.toStdString());

    // Close the entity browser.
    qobject_cast<QWidget*>(sender()->parent())->close();
}

void EntityEditorWindow::slot_accept()
{
    emit signal_accepted(get_values());
}

}   // namespace studio
}   // namespace appleseed

#include "mainwindow/project/moc_cpp_entityeditorwindow.cxx"
<|endoftext|>