<commit_before>//
//  CompositeTileImageProvider.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/23/14.
//
//

#include "CompositeTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "Tile.hpp"
#include "CompositeTileImageContribution.hpp"
#include "IFactory.hpp"
#include "ICanvas.hpp"
#include "IImage.hpp"
#include "FrameTasksExecutor.hpp"

CompositeTileImageProvider::~CompositeTileImageProvider() {
  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    child->_release();
  }
#ifdef JAVA_CODE
  super.dispose();
#endif
}

const TileImageContribution* CompositeTileImageProvider::contribution(const Tile* tile) {
  std::vector<const CompositeTileImageContribution::ChildContribution*> childrenContributions;

  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    const TileImageContribution* childContribution = child->contribution(tile);
    if (childContribution != NULL) {
      // ignore previous contributions, they are covered by the current fullCoverage & Opaque contribution.
      const int childrenContributionsSize = childrenContributions.size();
      if ((childrenContributionsSize > 0) &&
          childContribution->isFullCoverageAndOpaque()) {
        for (int j = 0; j < childrenContributionsSize; j++) {
          const CompositeTileImageContribution::ChildContribution* previousContribution = childrenContributions[j];
#ifdef C_CODE
          delete previousContribution;
#endif
#ifdef JAVA_CODE
          previousContribution.dispose();
#endif
        }
        childrenContributions.clear();
      }

      childrenContributions.push_back( new CompositeTileImageContribution::ChildContribution(i, childContribution) );
    }
  }

  return CompositeTileImageContribution::create(childrenContributions);
}

CompositeTileImageProvider::ChildResult::ChildResult(const bool                   isError,
                                                     const bool                   isCanceled,
                                                     const IImage*                image,
                                                     const std::string&           imageId,
                                                     const TileImageContribution* contribution,
                                                     const std::string&           error) :
_isError(isError),
_isCanceled(isCanceled),
_image(image),
_imageId(imageId),
_contribution(contribution),
_error(error)
{
  //  TileImageContribution::retainContribution(_contribution);
}

CompositeTileImageProvider::ChildResult::~ChildResult() {
  delete _image;

#warning DEBUG MEMORY
  TileImageContribution::releaseContribution(_contribution);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::image(const IImage*                image,
                                                                                const std::string&           imageId,
                                                                                const TileImageContribution* contribution) {
  return new CompositeTileImageProvider::ChildResult(false ,       // isError
                                                     false,        // isCanceled
                                                     image,
                                                     imageId,
                                                     contribution,
                                                     ""            // error
                                                     );
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::error(const std::string& error) {
  return new CompositeTileImageProvider::ChildResult(true,  // isError
                                                     false, // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     error);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::cancelation() {
  return new CompositeTileImageProvider::ChildResult(false, // isError
                                                     true,  // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     ""     // error
                                                     );
}

CompositeTileImageProvider::Composer::Composer(int width,
                                               int height,
                                               CompositeTileImageProvider* compositeTileImageProvider,
                                               const std::string& tileId,
                                               const Sector& tileSector,
                                               TileImageListener* listener,
                                               bool deleteListener,
                                               const CompositeTileImageContribution* compositeContribution,
                                               FrameTasksExecutor* frameTasksExecutor) :
_width(width),
_height(height),
_compositeTileImageProvider(compositeTileImageProvider),
_tileId(tileId),
_listener(listener),
_deleteListener(deleteListener),
_compositeContribution(compositeContribution),
_contributionsSize( compositeContribution->size() ),
_frameTasksExecutor(frameTasksExecutor),
_stepsDone(0),
_anyError(false),
_anyCancelation(false),
_canceled(false),
_tileSector(tileSector)
{
#warning DEBUG MEMORY
  //  TileImageContribution::retainContribution(_compositeContribution);
  for (int i = 0; i < _contributionsSize; i++) {
    _results.push_back( NULL );
  }
}

CompositeTileImageProvider::Composer::~Composer() {
  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    delete result;
  }

  TileImageContribution::releaseContribution(_compositeContribution);

#ifdef JAVA_CODE
  super.dispose();
#endif
}

void CompositeTileImageProvider::Composer::cleanUp() {
  if (_deleteListener) {
    delete _listener;
    _listener = NULL;
  }

  _compositeTileImageProvider->composerDone(this);
}

void CompositeTileImageProvider::Composer::done() {
  if (_canceled) {
    cleanUp();
    return;
  }

  if (_contributionsSize == 1) {
    const ChildResult* singleResult = _results[0];

    if (singleResult->_isError) {
      _listener->imageCreationError(_tileId,
                                    singleResult->_error);
    }
    else if (singleResult->_isCanceled) {
      _listener->imageCreationCanceled(_tileId);
    }
    else {
#warning MEMORY
//      singleResult->_contribution->_retain();
      _listener->imageCreated(singleResult->_imageId,
                              singleResult->_image->shallowCopy(),
                              singleResult->_imageId,
                              singleResult->_contribution);
    }

    cleanUp();
  }
  else {
    if (_anyError) {
      std::string composedError = "";
      for (int i = 0; i < _contributionsSize; i++) {
        const ChildResult* childResult = _results[i];
        if (childResult->_isError) {
          composedError += childResult->_error + " ";
        }
      }

      _listener->imageCreationError(_tileId,
                                    composedError);

      cleanUp();
    }
    else if (_anyCancelation) {
      _listener->imageCreationCanceled(_tileId);
      cleanUp();
    }
    else {
      _frameTasksExecutor->addPreRenderTask(new ComposerFrameTask(this));
    }
  }
}

RectangleF* CompositeTileImageProvider::Composer::getInnerRectangle(int wholeSectorWidth,
                                                                    int wholeSectorHeight,
                                                                    const Sector& wholeSector,
                                                                    const Sector& innerSector) const {
  if (wholeSector.isEquals(innerSector)){
    return new RectangleF(0, 0, wholeSectorWidth, wholeSectorHeight);
  }

  const double widthFactor  = innerSector._deltaLongitude.div(wholeSector._deltaLongitude);
  const double heightFactor = innerSector._deltaLatitude.div(wholeSector._deltaLatitude);

  const Vector2D lowerUV = wholeSector.getUVCoordinates(innerSector.getNW());

  return new RectangleF((float) (lowerUV._x   * wholeSectorWidth),
                        (float) (lowerUV._y   * wholeSectorHeight),
                        (float) (widthFactor  * wholeSectorWidth),
                        (float) (heightFactor * wholeSectorHeight));
}

void CompositeTileImageProvider::Composer::mixResult() {
  if (_canceled) {
    cleanUp();
    return;
  }

  ICanvas* canvas = IFactory::instance()->createCanvas();

  canvas->initialize(_width, _height);

  std::string imageId = "";

  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    imageId += result->_imageId + "|";

#warning //For now, we consider the whole image will appear on the tile (no source rect needed)
    const IImage* image = result->_image;
    const float   alpha = result->_contribution->_alpha;

    if (result->_contribution->isFullCoverageAndOpaque()) {
      canvas->drawImage(image, 0, 0);
    }
    else {
      if (result->_contribution->isFullCoverage()) {
        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          0, 0,
                          _width, _height,
                          alpha);
      }
      else {
        const Sector* imageSector = result->_contribution->getSector();

        const RectangleF* destRect = getInnerRectangle(_width, _height,
                                                       _tileSector,
                                                       *imageSector);

        //TEST MADRID
        //      if (_tileSector.contains(Angle::fromDegrees(40.41677540051771), Angle::fromDegrees(-3.7037901976145804))){
        //      printf("TS: %s\nIS: %s\nR: %s\n",_tileSector.description().c_str(),
        //             imageSector->description().c_str(),
        //             rect->description().c_str());
        //      }

        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          destRect->_x, destRect->_y,
                          destRect->_width, destRect->_height,
                          alpha);

        delete destRect;
      }
    }
#warning MEMORY
//    result->_contribution->_release();
  }
  _imageId = imageId;

  canvas->createImage(new ComposerImageListener(this), true);

  delete canvas;
}

bool CompositeTileImageProvider::ComposerFrameTask::isCanceled(const G3MRenderContext* rc) {
  return false;
}

void CompositeTileImageProvider::ComposerFrameTask::execute(const G3MRenderContext* rc) {
  _composer->mixResult();
}

void CompositeTileImageProvider::Composer::imageCreated(const IImage* image) {
  const CompositeTileImageContribution* compositeContribution = _compositeContribution;
  _compositeContribution = NULL; // the _compositeContribution ownership moved to the listener
  _listener->imageCreated(_tileId,
                          image,
                          _imageId,
                          compositeContribution);
  cleanUp();
}

void CompositeTileImageProvider::Composer::stepDone() {
  _stepsDone++;
  if (_stepsDone == _contributionsSize) {
    done();
  }
}

void CompositeTileImageProvider::Composer::imageCreated(const std::string&           tileId,
                                                        const IImage*                image,
                                                        const std::string&           imageId,
                                                        const TileImageContribution* contribution,
                                                        const int                    index) {
#warning DEBUG MEMORY - DIEGO AT WORK -> moves to ChildResult::image()
  TileImageContribution::retainContribution(contribution);

  _results[index] = ChildResult::image(image, imageId, contribution);
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationError(const std::string& error,
                                                              const int          index) {
  _results[index] = ChildResult::error(error);
  _anyError = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationCanceled(const int index) {
  _results[index] = ChildResult::cancelation();
  _anyCancelation = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::cancel(const std::string& tileId) {
  _canceled = true;
  _compositeTileImageProvider->cancelChildren(tileId, _compositeContribution);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreated(const std::string&           tileId,
                                                                      const IImage*                image,
                                                                      const std::string&           imageId,
                                                                      const TileImageContribution* contribution) {
  _composer->imageCreated(tileId, image, imageId, contribution, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationError(const std::string& tileId,
                                                                            const std::string& error) {
  _composer->imageCreationError(error, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationCanceled(const std::string& tileId) {
  _composer->imageCreationCanceled(_index);
}

void CompositeTileImageProvider::create(const Tile* tile,
                                        const TileImageContribution* contribution,
                                        const Vector2I& resolution,
                                        long long tileDownloadPriority,
                                        bool logDownloadActivity,
                                        TileImageListener* listener,
                                        bool deleteListener,
                                        FrameTasksExecutor* frameTasksExecutor) {

  const CompositeTileImageContribution* compositeContribution = (const CompositeTileImageContribution*) contribution;

  const std::string tileId = tile->_id;

  Composer* composer = new Composer(resolution._x,
                                    resolution._y,
                                    this,
                                    tileId,
                                    tile->_sector,
                                    listener,
                                    deleteListener,
                                    compositeContribution,
                                    frameTasksExecutor);

  _composers[ tileId ] = composer;

  const int contributionsSize = compositeContribution->size();
  for (int i = 0; i < contributionsSize; i++) {
    const CompositeTileImageContribution::ChildContribution* childContribution = compositeContribution->get(i);

    TileImageProvider* child = _children[ childContribution->_childIndex ];

#warning DEBUG MEMORY
    childContribution->_contribution->_retain();

    child->create(tile,
                  childContribution->_contribution,
                  resolution,
                  tileDownloadPriority,
                  logDownloadActivity,
                  new ChildTileImageListener(composer, i),
                  true,
                  frameTasksExecutor);
  }
}

void CompositeTileImageProvider::cancel(const std::string& tileId) {
#ifdef C_CODE
  if (_composers.find(tileId) != _composers.end()) {
    Composer* composer = _composers[tileId];
    composer->cancel(tileId);
    _composers.erase(tileId);
  }
#endif
#ifdef JAVA_CODE
  final Composer composer = _composers.remove(tileId);
  if (composer != null) {
    composer.cancel(tileId);
  }
#endif
}

void CompositeTileImageProvider::composerDone(Composer* composer) {
  _composers.erase( composer->_tileId );
  composer->_release();
}

void CompositeTileImageProvider::cancelChildren(const std::string& tileId,
                                                const CompositeTileImageContribution* compositeContribution) {
  const int contributionsSize = compositeContribution->size();

  // store all the indexes before calling child->cancel().
  // child->cancel() can force the deletion of the builder (and in order the deletion of compositeContribution)
  int* indexes = new int[contributionsSize];
  for (int i = 0; i < contributionsSize; i++) {
    indexes[i] = compositeContribution->get(i)->_childIndex;
  }

  for (int i = 0; i < contributionsSize; i++) {
    TileImageProvider* child = _children[ indexes[i] ];
    child->cancel(tileId);
  }

  delete [] indexes;
}
<commit_msg>Tile's image creation refactoring - NOT YET USABLE<commit_after>//
//  CompositeTileImageProvider.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/23/14.
//
//

#include "CompositeTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "Tile.hpp"
#include "CompositeTileImageContribution.hpp"
#include "IFactory.hpp"
#include "ICanvas.hpp"
#include "IImage.hpp"
#include "FrameTasksExecutor.hpp"

CompositeTileImageProvider::~CompositeTileImageProvider() {
  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    child->_release();
  }
#ifdef JAVA_CODE
  super.dispose();
#endif
}

const TileImageContribution* CompositeTileImageProvider::contribution(const Tile* tile) {
  std::vector<const CompositeTileImageContribution::ChildContribution*> childrenContributions;

  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    const TileImageContribution* childContribution = child->contribution(tile);
    if (childContribution != NULL) {
      // ignore previous contributions, they are covered by the current fullCoverage & Opaque contribution.
      const int childrenContributionsSize = childrenContributions.size();
      if ((childrenContributionsSize > 0) &&
          childContribution->isFullCoverageAndOpaque()) {
        for (int j = 0; j < childrenContributionsSize; j++) {
          const CompositeTileImageContribution::ChildContribution* previousContribution = childrenContributions[j];
#ifdef C_CODE
          delete previousContribution;
#endif
#ifdef JAVA_CODE
          previousContribution.dispose();
#endif
        }
        childrenContributions.clear();
      }

      childrenContributions.push_back( new CompositeTileImageContribution::ChildContribution(i, childContribution) );
    }
  }

  return CompositeTileImageContribution::create(childrenContributions);
}

CompositeTileImageProvider::ChildResult::ChildResult(const bool                   isError,
                                                     const bool                   isCanceled,
                                                     const IImage*                image,
                                                     const std::string&           imageId,
                                                     const TileImageContribution* contribution,
                                                     const std::string&           error) :
_isError(isError),
_isCanceled(isCanceled),
_image(image),
_imageId(imageId),
_contribution(contribution),
_error(error)
{
  //  TileImageContribution::retainContribution(_contribution);
}

CompositeTileImageProvider::ChildResult::~ChildResult() {
  delete _image;

#warning DEBUG MEMORY
  TileImageContribution::releaseContribution(_contribution);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::image(const IImage*                image,
                                                                                const std::string&           imageId,
                                                                                const TileImageContribution* contribution) {
  return new CompositeTileImageProvider::ChildResult(false ,       // isError
                                                     false,        // isCanceled
                                                     image,
                                                     imageId,
                                                     contribution,
                                                     ""            // error
                                                     );
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::error(const std::string& error) {
  return new CompositeTileImageProvider::ChildResult(true,  // isError
                                                     false, // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     error);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::cancelation() {
  return new CompositeTileImageProvider::ChildResult(false, // isError
                                                     true,  // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     ""     // error
                                                     );
}

CompositeTileImageProvider::Composer::Composer(int width,
                                               int height,
                                               CompositeTileImageProvider* compositeTileImageProvider,
                                               const std::string& tileId,
                                               const Sector& tileSector,
                                               TileImageListener* listener,
                                               bool deleteListener,
                                               const CompositeTileImageContribution* compositeContribution,
                                               FrameTasksExecutor* frameTasksExecutor) :
_width(width),
_height(height),
_compositeTileImageProvider(compositeTileImageProvider),
_tileId(tileId),
_listener(listener),
_deleteListener(deleteListener),
_compositeContribution(compositeContribution),
_contributionsSize( compositeContribution->size() ),
_frameTasksExecutor(frameTasksExecutor),
_stepsDone(0),
_anyError(false),
_anyCancelation(false),
_canceled(false),
_tileSector(tileSector)
{
#warning DEBUG MEMORY
  //  TileImageContribution::retainContribution(_compositeContribution);
  for (int i = 0; i < _contributionsSize; i++) {
    _results.push_back( NULL );
  }
}

CompositeTileImageProvider::Composer::~Composer() {
  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    delete result;
  }

  TileImageContribution::releaseContribution(_compositeContribution);

#ifdef JAVA_CODE
  super.dispose();
#endif
}

void CompositeTileImageProvider::Composer::cleanUp() {
  if (_deleteListener) {
    delete _listener;
    _listener = NULL;
  }

  _compositeTileImageProvider->composerDone(this);
}

void CompositeTileImageProvider::Composer::done() {
  if (_canceled) {
    cleanUp();
    return;
  }

  if (_contributionsSize == 1) {
    const ChildResult* singleResult = _results[0];

    if (singleResult->_isError) {
      _listener->imageCreationError(_tileId,
                                    singleResult->_error);
    }
    else if (singleResult->_isCanceled) {
      _listener->imageCreationCanceled(_tileId);
    }
    else {
#warning MEMORY
//      singleResult->_contribution->_retain();
      _listener->imageCreated(singleResult->_imageId,
                              singleResult->_image->shallowCopy(),
                              singleResult->_imageId,
                              singleResult->_contribution);
    }

    cleanUp();
  }
  else {
    if (_anyError) {
      std::string composedError = "";
      for (int i = 0; i < _contributionsSize; i++) {
        const ChildResult* childResult = _results[i];
        if (childResult->_isError) {
          composedError += childResult->_error + " ";
        }
      }

      _listener->imageCreationError(_tileId,
                                    composedError);

      cleanUp();
    }
    else if (_anyCancelation) {
      _listener->imageCreationCanceled(_tileId);
      cleanUp();
    }
    else {
      _frameTasksExecutor->addPreRenderTask(new ComposerFrameTask(this));
    }
  }
}

RectangleF* CompositeTileImageProvider::Composer::getInnerRectangle(int wholeSectorWidth,
                                                                    int wholeSectorHeight,
                                                                    const Sector& wholeSector,
                                                                    const Sector& innerSector) const {
  if (wholeSector.isEquals(innerSector)){
    return new RectangleF(0, 0, wholeSectorWidth, wholeSectorHeight);
  }

  const double widthFactor  = innerSector._deltaLongitude.div(wholeSector._deltaLongitude);
  const double heightFactor = innerSector._deltaLatitude.div(wholeSector._deltaLatitude);

  const Vector2D lowerUV = wholeSector.getUVCoordinates(innerSector.getNW());

  return new RectangleF((float) (lowerUV._x   * wholeSectorWidth),
                        (float) (lowerUV._y   * wholeSectorHeight),
                        (float) (widthFactor  * wholeSectorWidth),
                        (float) (heightFactor * wholeSectorHeight));
}

void CompositeTileImageProvider::Composer::mixResult() {
  if (_canceled) {
    cleanUp();
    return;
  }

  ICanvas* canvas = IFactory::instance()->createCanvas();

  canvas->initialize(_width, _height);

  std::string imageId = "";

  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    imageId += result->_imageId + "|";

#warning //For now, we consider the whole image will appear on the tile (no source rect needed)
    const IImage* image = result->_image;
    const float   alpha = result->_contribution->_alpha;

    if (result->_contribution->isFullCoverageAndOpaque()) {
      canvas->drawImage(image, 0, 0);
    }
    else {
      if (result->_contribution->isFullCoverage()) {
        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          0, 0,
                          _width, _height,
                          alpha);
      }
      else {
        const Sector* imageSector = result->_contribution->getSector();

        const RectangleF* destRect = getInnerRectangle(_width, _height,
                                                       _tileSector,
                                                       *imageSector);

        //TEST MADRID
        //      if (_tileSector.contains(Angle::fromDegrees(40.41677540051771), Angle::fromDegrees(-3.7037901976145804))){
        //      printf("TS: %s\nIS: %s\nR: %s\n",_tileSector.description().c_str(),
        //             imageSector->description().c_str(),
        //             rect->description().c_str());
        //      }

        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          destRect->_x, destRect->_y,
                          destRect->_width, destRect->_height,
                          alpha);

        delete destRect;
      }
    }
#warning MEMORY
//    result->_contribution->_release();
  }
  _imageId = imageId;

  canvas->createImage(new ComposerImageListener(this), true);

  delete canvas;
}

bool CompositeTileImageProvider::ComposerFrameTask::isCanceled(const G3MRenderContext* rc) {
  return false;
}

void CompositeTileImageProvider::ComposerFrameTask::execute(const G3MRenderContext* rc) {
  _composer->mixResult();
}

void CompositeTileImageProvider::Composer::imageCreated(const IImage* image) {
  const CompositeTileImageContribution* compositeContribution = _compositeContribution;
  _compositeContribution = NULL; // the _compositeContribution ownership moved to the listener
  _listener->imageCreated(_tileId,
                          image,
                          _imageId,
                          compositeContribution);
  cleanUp();
}

void CompositeTileImageProvider::Composer::stepDone() {
  _stepsDone++;
  if (_stepsDone == _contributionsSize) {
    done();
  }
}

void CompositeTileImageProvider::Composer::imageCreated(const std::string&           tileId,
                                                        const IImage*                image,
                                                        const std::string&           imageId,
                                                        const TileImageContribution* contribution,
                                                        const int                    index) {
#warning DEBUG MEMORY - DIEGO AT WORK -> moves to ChildResult::image()
//  TileImageContribution::retainContribution(contribution);

  _results[index] = ChildResult::image(image, imageId, contribution);
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationError(const std::string& error,
                                                              const int          index) {
  _results[index] = ChildResult::error(error);
  _anyError = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationCanceled(const int index) {
  _results[index] = ChildResult::cancelation();
  _anyCancelation = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::cancel(const std::string& tileId) {
  _canceled = true;
  _compositeTileImageProvider->cancelChildren(tileId, _compositeContribution);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreated(const std::string&           tileId,
                                                                      const IImage*                image,
                                                                      const std::string&           imageId,
                                                                      const TileImageContribution* contribution) {
  _composer->imageCreated(tileId, image, imageId, contribution, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationError(const std::string& tileId,
                                                                            const std::string& error) {
  _composer->imageCreationError(error, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationCanceled(const std::string& tileId) {
  _composer->imageCreationCanceled(_index);
}

void CompositeTileImageProvider::create(const Tile* tile,
                                        const TileImageContribution* contribution,
                                        const Vector2I& resolution,
                                        long long tileDownloadPriority,
                                        bool logDownloadActivity,
                                        TileImageListener* listener,
                                        bool deleteListener,
                                        FrameTasksExecutor* frameTasksExecutor) {

  const CompositeTileImageContribution* compositeContribution = (const CompositeTileImageContribution*) contribution;

  const std::string tileId = tile->_id;

  Composer* composer = new Composer(resolution._x,
                                    resolution._y,
                                    this,
                                    tileId,
                                    tile->_sector,
                                    listener,
                                    deleteListener,
                                    compositeContribution,
                                    frameTasksExecutor);

  _composers[ tileId ] = composer;

  const int contributionsSize = compositeContribution->size();
  for (int i = 0; i < contributionsSize; i++) {
    const CompositeTileImageContribution::ChildContribution* childContribution = compositeContribution->get(i);

    TileImageProvider* child = _children[ childContribution->_childIndex ];

#warning DEBUG MEMORY
    childContribution->_contribution->_retain();

    child->create(tile,
                  childContribution->_contribution,
                  resolution,
                  tileDownloadPriority,
                  logDownloadActivity,
                  new ChildTileImageListener(composer, i),
                  true,
                  frameTasksExecutor);
  }
}

void CompositeTileImageProvider::cancel(const std::string& tileId) {
#ifdef C_CODE
  if (_composers.find(tileId) != _composers.end()) {
    Composer* composer = _composers[tileId];
    composer->cancel(tileId);
    _composers.erase(tileId);
  }
#endif
#ifdef JAVA_CODE
  final Composer composer = _composers.remove(tileId);
  if (composer != null) {
    composer.cancel(tileId);
  }
#endif
}

void CompositeTileImageProvider::composerDone(Composer* composer) {
  _composers.erase( composer->_tileId );
  composer->_release();
}

void CompositeTileImageProvider::cancelChildren(const std::string& tileId,
                                                const CompositeTileImageContribution* compositeContribution) {
  const int contributionsSize = compositeContribution->size();

  // store all the indexes before calling child->cancel().
  // child->cancel() can force the deletion of the builder (and in order the deletion of compositeContribution)
  int* indexes = new int[contributionsSize];
  for (int i = 0; i < contributionsSize; i++) {
    indexes[i] = compositeContribution->get(i)->_childIndex;
  }

  for (int i = 0; i < contributionsSize; i++) {
    TileImageProvider* child = _children[ indexes[i] ];
    child->cancel(tileId);
  }

  delete [] indexes;
}
<|endoftext|>


<commit_before>#include "xchainer/backprop_mode.h"

#include <algorithm>
#include <memory>
#include <utility>
#include <vector>

#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/constant.h"
#include "xchainer/context.h"
#include "xchainer/graph.h"

namespace xchainer {
namespace backprop_mode_detail {

thread_local BackpropModeStack* t_backprop_mode_stack{nullptr};

template <bool kModeFlag>
void BackpropModeScope<kModeFlag>::BackpropModeScopeImpl(nonstd::optional<std::vector<GraphId>> graph_ids, Context& context) {
    // The outer-most scope creates an instance of BackpropModeStack.
    if (t_backprop_mode_stack == nullptr) {
        t_backprop_mode_stack = new BackpropModeStack{};
        is_outermost_ = true;
    }

    if (graph_ids.has_value()) {
        n_ = graph_ids->size();
        for (GraphId& graph_id : *graph_ids) {
            t_backprop_mode_stack->emplace_back(context, std::move(graph_id), kModeFlag);
        }
    } else {
        n_ = 1;
        t_backprop_mode_stack->emplace_back(context, nonstd::nullopt, kModeFlag);
    }
}

template <bool kModeFlag>
BackpropModeScope<kModeFlag>::~BackpropModeScope() {
    assert(t_backprop_mode_stack != nullptr);
    assert(t_backprop_mode_stack->size() >= n_);

    // Recover thread local variable to nullptr on exiting from the outer-most scope.
    if (is_outermost_) {
        assert(t_backprop_mode_stack->size() == n_);
        delete t_backprop_mode_stack;
        t_backprop_mode_stack = nullptr;
    } else {
        t_backprop_mode_stack->erase(t_backprop_mode_stack->end() - n_, t_backprop_mode_stack->end());
    }
}

}  // namespace backprop_mode_detail

bool IsBackpropRequired(const GraphId& graph_id, Context& context) {
    backprop_mode_detail::BackpropModeStack* bms = backprop_mode_detail::t_backprop_mode_stack;
    if (bms == nullptr) {
        // No backprop scopes have been created and backprop is thus always required, per default.
        return true;
    }
    auto it = std::find_if(bms->rbegin(), bms->rend(), [&graph_id, &context](const internal::BackpropMode& bm) {
        return &context == &bm.context() && (!bm.graph_id().has_value() || graph_id == *bm.graph_id());
    });
    if (it != bms->rend()) {
        return it->backprop();
    }
    return true;  // Per default.
}

bool IsBackpropRequired(const Array& array, const GraphId& graph_id) {
    if (graph_id == kAnyGraphId) {
        const std::vector<std::shared_ptr<ArrayNode>>& array_nodes = array.nodes();
        return std::any_of(array_nodes.begin(), array_nodes.end(), [&array](const std::shared_ptr<const ArrayNode>& array_node) {
            return IsBackpropRequired(array_node->graph_id(), array.device().context());
        });
    } else if (internal::HasArrayNode(array, graph_id)) {
        return IsBackpropRequired(graph_id, array.device().context());
    }
    return false;
}

}  // namespace xchainer
<commit_msg>Only lambda-capture what is necessary<commit_after>#include "xchainer/backprop_mode.h"

#include <algorithm>
#include <memory>
#include <utility>
#include <vector>

#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/constant.h"
#include "xchainer/context.h"
#include "xchainer/graph.h"

namespace xchainer {
namespace backprop_mode_detail {

thread_local BackpropModeStack* t_backprop_mode_stack{nullptr};

template <bool kModeFlag>
void BackpropModeScope<kModeFlag>::BackpropModeScopeImpl(nonstd::optional<std::vector<GraphId>> graph_ids, Context& context) {
    // The outer-most scope creates an instance of BackpropModeStack.
    if (t_backprop_mode_stack == nullptr) {
        t_backprop_mode_stack = new BackpropModeStack{};
        is_outermost_ = true;
    }

    if (graph_ids.has_value()) {
        n_ = graph_ids->size();
        for (GraphId& graph_id : *graph_ids) {
            t_backprop_mode_stack->emplace_back(context, std::move(graph_id), kModeFlag);
        }
    } else {
        n_ = 1;
        t_backprop_mode_stack->emplace_back(context, nonstd::nullopt, kModeFlag);
    }
}

template <bool kModeFlag>
BackpropModeScope<kModeFlag>::~BackpropModeScope() {
    assert(t_backprop_mode_stack != nullptr);
    assert(t_backprop_mode_stack->size() >= n_);

    // Recover thread local variable to nullptr on exiting from the outer-most scope.
    if (is_outermost_) {
        assert(t_backprop_mode_stack->size() == n_);
        delete t_backprop_mode_stack;
        t_backprop_mode_stack = nullptr;
    } else {
        t_backprop_mode_stack->erase(t_backprop_mode_stack->end() - n_, t_backprop_mode_stack->end());
    }
}

}  // namespace backprop_mode_detail

bool IsBackpropRequired(const GraphId& graph_id, Context& context) {
    backprop_mode_detail::BackpropModeStack* bms = backprop_mode_detail::t_backprop_mode_stack;
    if (bms == nullptr) {
        // No backprop scopes have been created and backprop is thus always required, per default.
        return true;
    }
    auto it = std::find_if(bms->rbegin(), bms->rend(), [&graph_id, &context](const internal::BackpropMode& bm) {
        return &context == &bm.context() && (!bm.graph_id().has_value() || graph_id == *bm.graph_id());
    });
    if (it != bms->rend()) {
        return it->backprop();
    }
    return true;  // Per default.
}

bool IsBackpropRequired(const Array& array, const GraphId& graph_id) {
    if (graph_id == kAnyGraphId) {
        Context& context = array.device().context();
        const std::vector<std::shared_ptr<ArrayNode>>& array_nodes = array.nodes();
        return std::any_of(array_nodes.begin(), array_nodes.end(), [&context](const std::shared_ptr<const ArrayNode>& array_node) {
            return IsBackpropRequired(array_node->graph_id(), context);
        });
    } else if (internal::HasArrayNode(array, graph_id)) {
        return IsBackpropRequired(graph_id, array.device().context());
    }
    return false;
}

}  // namespace xchainer
<|endoftext|>


<commit_before>// Copyright (c) 2009 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.

#include "chrome/browser/language_order_table_model.h"

#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"

LanguageOrderTableModel::LanguageOrderTableModel()
    : observer_(NULL) {
}

void LanguageOrderTableModel::SetAcceptLanguagesString(
    const std::string& language_list) {
  std::vector<std::string> languages_vector;
  ListToVector(language_list, &languages_vector);
  for (int i = 0; i < static_cast<int>(languages_vector.size()); i++) {
    Add(languages_vector.at(i));
  }
}

void LanguageOrderTableModel::SetObserver(TableModelObserver* observer) {
  observer_ = observer;
}

std::wstring LanguageOrderTableModel::GetText(int row, int column_id) {
  DCHECK(row >= 0 && row < RowCount());
  const std::string app_locale = g_browser_process->GetApplicationLocale();
  return UTF16ToWide(l10n_util::GetDisplayNameForLocale(languages_.at(row),
                                                        app_locale,
                                                        true));
}

bool LanguageOrderTableModel::Add(const std::string& language) {
  if (language.empty())
    return false;
  // Check for selecting duplicated language.
  for (std::vector<std::string>::const_iterator cit = languages_.begin();
       cit != languages_.end(); ++cit)
    if (*cit == language)
      return false;
  languages_.push_back(language);
  if (observer_)
    observer_->OnItemsAdded(RowCount() - 1, 1);
  return true;
}

void LanguageOrderTableModel::Remove(int index) {
  DCHECK(index >= 0 && index < RowCount());
  languages_.erase(languages_.begin() + index);
  if (observer_)
    observer_->OnItemsRemoved(index, 1);
}

int LanguageOrderTableModel::GetIndex(const std::string& language) {
  if (language.empty())
    return -1;

  int index = 0;
  for (std::vector<std::string>::const_iterator cit = languages_.begin();
      cit != languages_.end(); ++cit) {
    if (*cit == language)
      return index;

    index++;
  }

  return -1;
}

void LanguageOrderTableModel::MoveDown(int index) {
  if (index < 0 || index >= RowCount() - 1)
    return;
  std::string item = languages_.at(index);
  languages_.erase(languages_.begin() + index);
  if (index == RowCount() - 1)
    languages_.push_back(item);
  else
    languages_.insert(languages_.begin() + index + 1, item);
  if (observer_)
    observer_->OnItemsChanged(0, RowCount());
}

void LanguageOrderTableModel::MoveUp(int index) {
  if (index <= 0 || index >= static_cast<int>(languages_.size()))
    return;
  std::string item = languages_.at(index);
  languages_.erase(languages_.begin() + index);
  languages_.insert(languages_.begin() + index - 1, item);
  if (observer_)
    observer_->OnItemsChanged(0, RowCount());
}

int LanguageOrderTableModel::RowCount() {
  return static_cast<int>(languages_.size());
}

void LanguageOrderTableModel::ListToVector(const std::string& list,
                                           std::vector<std::string>* vector) {
  SplitString(list, ',', vector);
}

std::string LanguageOrderTableModel::VectorToList(
    const std::vector<std::string>& vector)  {
  std::string list;
  for (int i = 0 ; i < static_cast<int>(vector.size()) ; i++) {
    list += vector.at(i);
    if (i != static_cast<int>(vector.size()) - 1)
      list += ',';
  }
  return list;
}
<commit_msg>Enable live update of language list The old way this was written was trying to re-use the Add() method to "merge" the new langauge string with the existing list.  But in the case when a syncd browser sends a re-ordering or delete change, this would not detect the change and never fire the observer.  I changed this to simply make SetAcceptLanguagesString replace the current langages_ list.<commit_after>// Copyright (c) 2009 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.

#include "chrome/browser/language_order_table_model.h"

#include <set>

#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"

LanguageOrderTableModel::LanguageOrderTableModel()
    : observer_(NULL) {
}

void LanguageOrderTableModel::SetAcceptLanguagesString(
    const std::string& language_list) {
  std::vector<std::string> languages_vector;
  ListToVector(language_list, &languages_vector);
  languages_.clear();
  std::set<std::string> added;
  for (int i = 0; i < static_cast<int>(languages_vector.size()); i++) {
    const std::string& language(languages_vector.at(i));
    if (!language.empty() && added.count(language) == 0) {
      languages_.push_back(language);
      added.insert(language);
    }
  }
  if (observer_)
    observer_->OnModelChanged();
}

void LanguageOrderTableModel::SetObserver(TableModelObserver* observer) {
  observer_ = observer;
}

std::wstring LanguageOrderTableModel::GetText(int row, int column_id) {
  DCHECK(row >= 0 && row < RowCount());
  const std::string app_locale = g_browser_process->GetApplicationLocale();
  return UTF16ToWide(l10n_util::GetDisplayNameForLocale(languages_.at(row),
                                                        app_locale,
                                                        true));
}

bool LanguageOrderTableModel::Add(const std::string& language) {
  if (language.empty())
    return false;
  // Check for selecting duplicated language.
  for (std::vector<std::string>::const_iterator cit = languages_.begin();
       cit != languages_.end(); ++cit)
    if (*cit == language)
      return false;
  languages_.push_back(language);
  if (observer_)
    observer_->OnItemsAdded(RowCount() - 1, 1);
  return true;
}

void LanguageOrderTableModel::Remove(int index) {
  DCHECK(index >= 0 && index < RowCount());
  languages_.erase(languages_.begin() + index);
  if (observer_)
    observer_->OnItemsRemoved(index, 1);
}

int LanguageOrderTableModel::GetIndex(const std::string& language) {
  if (language.empty())
    return -1;

  int index = 0;
  for (std::vector<std::string>::const_iterator cit = languages_.begin();
      cit != languages_.end(); ++cit) {
    if (*cit == language)
      return index;

    index++;
  }

  return -1;
}

void LanguageOrderTableModel::MoveDown(int index) {
  if (index < 0 || index >= RowCount() - 1)
    return;
  std::string item = languages_.at(index);
  languages_.erase(languages_.begin() + index);
  if (index == RowCount() - 1)
    languages_.push_back(item);
  else
    languages_.insert(languages_.begin() + index + 1, item);
  if (observer_)
    observer_->OnItemsChanged(0, RowCount());
}

void LanguageOrderTableModel::MoveUp(int index) {
  if (index <= 0 || index >= static_cast<int>(languages_.size()))
    return;
  std::string item = languages_.at(index);
  languages_.erase(languages_.begin() + index);
  languages_.insert(languages_.begin() + index - 1, item);
  if (observer_)
    observer_->OnItemsChanged(0, RowCount());
}

int LanguageOrderTableModel::RowCount() {
  return static_cast<int>(languages_.size());
}

void LanguageOrderTableModel::ListToVector(const std::string& list,
                                           std::vector<std::string>* vector) {
  SplitString(list, ',', vector);
}

std::string LanguageOrderTableModel::VectorToList(
    const std::vector<std::string>& vector)  {
  std::string list;
  for (int i = 0 ; i < static_cast<int>(vector.size()) ; i++) {
    list += vector.at(i);
    if (i != static_cast<int>(vector.size()) - 1)
      list += ',';
  }
  return list;
}
<|endoftext|>


<commit_before><commit_msg>"flip_over_serum_line"<commit_after><|endoftext|>


<commit_before>// Material.cpp
#include "Material.h"

#include "CycException.h"
#include "Timer.h"
#include "Logger.h"

#include <cmath>
#include <vector>

using namespace std;

std::vector<mat_rsrc_ptr> Material::materials_;

bool Material::decay_wanted_ = false;

int Material::decay_interval_ = 1;

Table *Material::material_table = new Table("MaterialHistory");

bool Material::type_is_logged_ = false;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material() {
  last_update_time_ = TI->time();

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material(IsoVector comp) {
  last_update_time_ = TI->time();
  iso_vector_ = comp;

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material(const Material& other) {
  iso_vector_ = other.iso_vector_;
  last_update_time_ = other.last_update_time_;

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::absorb(mat_rsrc_ptr matToAdd) {
  // @gidden figure out how to handle this with the database - mjg
  // Get the given Material's composition.
  IsoVector vec_to_add = matToAdd->isoVector();
  iso_vector_ = iso_vector_ + vec_to_add;
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " absorbed material ID="
                   << matToAdd->ID() << ".";
  CLOG(LEV_DEBUG3) << "New Material state:";
  print();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(double mass) {

  IsoVector new_comp = iso_vector_;
  new_comp.setMass(mass);
  iso_vector_ = iso_vector_ - new_comp;

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had " << mass
                   << " kg extracted from it. New mass=" << quantity() << " kg.";

  mat_rsrc_ptr new_mat = new Material(new_comp);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  return mat_rsrc_ptr(new_mat);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(IsoVector rem_comp) {
  iso_vector_ = iso_vector_ - rem_comp;

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had vector extracted.";
  CLOG(LEV_DEBUG3) << "New Material state:";
  print();

  mat_rsrc_ptr new_mat = new Material(rem_comp);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  return mat_rsrc_ptr(new_mat);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::print() {
  CLOG(LEV_INFO4) << "Material ID=" << ID_
                   << ", quantity=" << quantity() << ", units=" << units();

  CLOG(LEV_INFO5) << "Composition {";
  std::vector<std::string>::iterator entry;
  std::vector<std::string> entries = iso_vector_.compStrings();
  for (entry = entries.begin(); entry != entries.end(); entry++) {
    CLOG(LEV_INFO5) << "   " << *entry;
  }
  CLOG(LEV_INFO5) << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setQuantity(double quantity) {
  iso_vector_.setMass(quantity);
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had mass set to"
                   << quantity << " kg";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
rsrc_ptr Material::clone() {
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " was cloned.";
  print();
  rsrc_ptr mat(new Material(*this));
  return mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuality(rsrc_ptr other){
  // This will be false until proven true
  bool toRet = false;
  IsoVector lhs_vec = iso_vector_;

  try {
    // Make sure the other is a material
    mat_rsrc_ptr mat = boost::dynamic_pointer_cast<Material>(other);
    if (mat) {
      toRet = true;
    }
  } catch (...) { }

  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuantityEqual(rsrc_ptr other) {
  // This will be false until proven true
  bool toRet = false;

  // Make sure the other is a material
  try{
    // check mass values
    double second_qty = boost::dynamic_pointer_cast<Material>(other)->quantity();
    toRet=( abs(quantity() - second_qty) < EPS_KG);
  } catch (std::exception e) { }
  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuantityGT(rsrc_ptr other){
  // true if the total atoms in the other is greater than in the base.
  // This will be true until proven false
  bool toRet = false;

  // Make sure the other is a material
  try{
    // check mass values
    double second_qty = boost::dynamic_pointer_cast<Material>(other)->quantity();
    toRet = second_qty - quantity() > EPS_KG;
  } catch (std::exception& e){ }

  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::decay() {
  int curr_time = TI->time();
  int delta_time = curr_time - last_update_time_;

  iso_vector_.executeDecay(delta_time);

  last_update_time_ = curr_time;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::decayMaterials(int time) {
  // if decay is on
  if (decay_wanted_) {
    // and if (time(mod interval)==0)
    if (time % decay_interval_ == 0) {
      // acquire a list of all materials
      for (vector<mat_rsrc_ptr>::iterator mat = materials_.begin();
          mat != materials_.end();
          mat++){
         // and decay each of them
         (*mat)->decay();
      }
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setDecay(int dec) {
  if ( dec <= 0 ) {
    decay_wanted_ = false;
  } else if ( dec > 0 ) {
    decay_wanted_ = true;
    decay_interval_ = dec;
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::define_table() {
  // declare the table columns
  column id("ID","INTEGER");
  column state_id("StateID","INTEGER");
  column time("Time","INTEGER");
  // declare the table's primary key
  primary_key pk;
  pk.push_back("ID"), pk.push_back("StateID");
  material_table->setPrimaryKey(pk);
  // add columns to the table
  material_table->addColumn(id);
  material_table->addColumn(state_id);
  material_table->addColumn(time);
  // add foreign keys
  foreign_key_ref *fkref;
  foreign_key *fk;
  key myk, theirk;
  //    IsotopicStates table foreign keys
  theirk.push_back("ID");
  fkref = new foreign_key_ref("IsotopicStates",theirk);
  //      the state id
  myk.push_back("StateID");
  fk = new foreign_key(myk, (*fkref) );
  material_table->addForeignKey( (*fk) ); // stated id references isotopicstates' id
  // we've now defined the table
  material_table->tableDefined();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::addToTable(){
  // if we haven't logged an material yet, define the table
  if ( !material_table->defined() )
    Material::define_table();

  // make a row
  // declare data
  data an_id( this->ID() ), a_state( 1 ), // @MJG FLAG need to do state recording
    a_time( TI->time() );
  // declare entries
  entry id("ID",an_id), state("StateID",a_state), time("Time",a_time);
  // declare row
  row aRow;
  aRow.push_back(id), aRow.push_back(state), aRow.push_back(time);
  // add the row
  material_table->addRow(aRow);
  // record this primary key
  pkref_.push_back(id);
  pkref_.push_back(state);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setOriginatorID(int id){
  originatorID_ = id;
  this->Resource::addToTable();
  this->Material::addToTable();
}
<commit_msg>added foreign key designation to material history table<commit_after>// Material.cpp
#include "Material.h"

#include "CycException.h"
#include "Timer.h"
#include "Logger.h"

#include <cmath>
#include <vector>

using namespace std;

std::vector<mat_rsrc_ptr> Material::materials_;

bool Material::decay_wanted_ = false;

int Material::decay_interval_ = 1;

Table *Material::material_table = new Table("MaterialHistory");

bool Material::type_is_logged_ = false;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material() {
  last_update_time_ = TI->time();

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material(IsoVector comp) {
  last_update_time_ = TI->time();
  iso_vector_ = comp;

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Material::Material(const Material& other) {
  iso_vector_ = other.iso_vector_;
  last_update_time_ = other.last_update_time_;

  CLOG(LEV_INFO4) << "Material created {";
  print();
  CLOG(LEV_INFO4) << "}";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::absorb(mat_rsrc_ptr matToAdd) {
  // @gidden figure out how to handle this with the database - mjg
  // Get the given Material's composition.
  IsoVector vec_to_add = matToAdd->isoVector();
  iso_vector_ = iso_vector_ + vec_to_add;
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " absorbed material ID="
                   << matToAdd->ID() << ".";
  CLOG(LEV_DEBUG3) << "New Material state:";
  print();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(double mass) {

  IsoVector new_comp = iso_vector_;
  new_comp.setMass(mass);
  iso_vector_ = iso_vector_ - new_comp;

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had " << mass
                   << " kg extracted from it. New mass=" << quantity() << " kg.";

  mat_rsrc_ptr new_mat = new Material(new_comp);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  return mat_rsrc_ptr(new_mat);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mat_rsrc_ptr Material::extract(IsoVector rem_comp) {
  iso_vector_ = iso_vector_ - rem_comp;

  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had vector extracted.";
  CLOG(LEV_DEBUG3) << "New Material state:";
  print();

  mat_rsrc_ptr new_mat = new Material(rem_comp);
  // we just split a resource, so keep track of the original for book keeping
  new_mat->setOriginalID( this->originalID() );

  return mat_rsrc_ptr(new_mat);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::print() {
  CLOG(LEV_INFO4) << "Material ID=" << ID_
                   << ", quantity=" << quantity() << ", units=" << units();

  CLOG(LEV_INFO5) << "Composition {";
  std::vector<std::string>::iterator entry;
  std::vector<std::string> entries = iso_vector_.compStrings();
  for (entry = entries.begin(); entry != entries.end(); entry++) {
    CLOG(LEV_INFO5) << "   " << *entry;
  }
  CLOG(LEV_INFO5) << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setQuantity(double quantity) {
  iso_vector_.setMass(quantity);
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " had mass set to"
                   << quantity << " kg";
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
rsrc_ptr Material::clone() {
  CLOG(LEV_DEBUG2) << "Material ID=" << ID_ << " was cloned.";
  print();
  rsrc_ptr mat(new Material(*this));
  return mat;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuality(rsrc_ptr other){
  // This will be false until proven true
  bool toRet = false;
  IsoVector lhs_vec = iso_vector_;

  try {
    // Make sure the other is a material
    mat_rsrc_ptr mat = boost::dynamic_pointer_cast<Material>(other);
    if (mat) {
      toRet = true;
    }
  } catch (...) { }

  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuantityEqual(rsrc_ptr other) {
  // This will be false until proven true
  bool toRet = false;

  // Make sure the other is a material
  try{
    // check mass values
    double second_qty = boost::dynamic_pointer_cast<Material>(other)->quantity();
    toRet=( abs(quantity() - second_qty) < EPS_KG);
  } catch (std::exception e) { }
  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Material::checkQuantityGT(rsrc_ptr other){
  // true if the total atoms in the other is greater than in the base.
  // This will be true until proven false
  bool toRet = false;

  // Make sure the other is a material
  try{
    // check mass values
    double second_qty = boost::dynamic_pointer_cast<Material>(other)->quantity();
    toRet = second_qty - quantity() > EPS_KG;
  } catch (std::exception& e){ }

  return toRet;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::decay() {
  int curr_time = TI->time();
  int delta_time = curr_time - last_update_time_;

  iso_vector_.executeDecay(delta_time);

  last_update_time_ = curr_time;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::decayMaterials(int time) {
  // if decay is on
  if (decay_wanted_) {
    // and if (time(mod interval)==0)
    if (time % decay_interval_ == 0) {
      // acquire a list of all materials
      for (vector<mat_rsrc_ptr>::iterator mat = materials_.begin();
          mat != materials_.end();
          mat++){
         // and decay each of them
         (*mat)->decay();
      }
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setDecay(int dec) {
  if ( dec <= 0 ) {
    decay_wanted_ = false;
  } else if ( dec > 0 ) {
    decay_wanted_ = true;
    decay_interval_ = dec;
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::define_table() {
  // declare the table columns
  column id("ID","INTEGER");
  column state_id("StateID","INTEGER");
  column time("Time","INTEGER");
  // declare the table's primary key
  primary_key pk;
  pk.push_back("ID"), pk.push_back("StateID");
  material_table->setPrimaryKey(pk);
  // add columns to the table
  material_table->addColumn(id);
  material_table->addColumn(state_id);
  material_table->addColumn(time);
  // add foreign keys
  foreign_key_ref *fkref;
  foreign_key *fk;
  key myk, theirk;
  //    Resources table foreign keys
  theirk.push_back("ID");
  fkref = new foreign_key_ref("Resources",theirk);
  //      the resource id
  myk.push_back("ID");
  fk = new foreign_key(myk, (*fkref) );
  material_table->addForeignKey( (*fk) ); // id references resources' id
  myk.clear(), theirk.clear();
  //    IsotopicStates table foreign keys
  theirk.push_back("ID");
  fkref = new foreign_key_ref("IsotopicStates",theirk);
  //      the state id
  myk.push_back("StateID");
  fk = new foreign_key(myk, (*fkref) );
  material_table->addForeignKey( (*fk) ); // stateid references isotopicstates' id
  myk.clear(), theirk.clear();
  // we've now defined the table
  material_table->tableDefined();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::addToTable(){
  // if we haven't logged an material yet, define the table
  if ( !material_table->defined() )
    Material::define_table();

  // make a row
  // declare data
  data an_id( this->originalID() ), a_state( 1 ), // @MJG FLAG need to do state recording
    a_time( TI->time() );
  // declare entries
  entry id("ID",an_id), state("StateID",a_state), time("Time",a_time);
  // declare row
  row aRow;
  aRow.push_back(id), aRow.push_back(state), aRow.push_back(time);
  // add the row
  material_table->addRow(aRow);
  // record this primary key
  pkref_.push_back(id);
  pkref_.push_back(state);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Material::setOriginatorID(int id){
  originatorID_ = id;
  this->Resource::addToTable();
  this->Material::addToTable();
}
<|endoftext|>


<commit_before>/*
  Copyright 2008 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

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

  (This is the Modified BSD License)
*/

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <iterator>

#include <OpenEXR/ImathMatrix.h>
#include <OpenEXR/ImathVec.h>

#include "argparse.h"
#include "imageio.h"
using namespace OpenImageIO;
#include "ustring.h"
#include "imagebuf.h"
#include "texture.h"
#include "fmath.h"
#include "sysutil.h"

static std::vector<std::string> filenames;
static std::string output_filename = "out.exr";
static bool verbose = false;
static int output_xres = 512, output_yres = 512;
static float blur = 0;
static float width = 1;
static int iters = 1;
static int autotile = 0;
static bool automip = false;
static TextureSystem *texsys = NULL;
static std::string searchpath;
static int blocksize = 1;
static bool nowarp = false;
static float cachesize = -1;
static float missing[4] = {-1, 0, 0, 1};

static int
parse_files (int argc, const char *argv[])
{
    for (int i = 0;  i < argc;  i++)
        filenames.push_back (argv[i]);
    return 0;
}

static void
getargs (int argc, const char *argv[])
{
    bool help = false;
    ArgParse ap;
    ap.options ("Usage:  testtex [options] inputfile",
                  "%*", parse_files, "",
                  "--help", &help, "Print help message",
                  "-v", &verbose, "Verbose status messages",
                  "-o %s", &output_filename, "Output test image",
                  "-res %d %d", &output_xres, &output_yres,
                      "Resolution of output test image",
                  "-iters %d", &iters,
                      "Iterations for time trials",
                  "--blur %f", &blur, "Add blur to texture lookup",
                  "--width %f", &width, "Multiply filter width of texture lookup",
                  "--missing %f %f %f", &missing[0], &missing[1], &missing[2],
                        "Specify missing texture color",
                  "--autotile %d", &autotile, "Set auto-tile size for the image cache",
                  "--automip", &automip, "Set auto-MIPmap for the image cache",
                  "--blocksize %d", &blocksize, "Set blocksize (n x n) for batches",
                  "--searchpath %s", &searchpath, "Search path for files",
                  "--nowarp", &nowarp, "Do not warp the image->texture mapping",
                  "--cachesize %g", &cachesize, "Set cache size, in MB",
                  NULL);
    if (ap.parse (argc, argv) < 0) {
        std::cerr << ap.geterror() << std::endl;
        ap.usage ();
        exit (EXIT_FAILURE);
    }
    if (help) {
        ap.usage ();
        exit (EXIT_FAILURE);
    }

    if (filenames.size() < 1) {
        std::cerr << "testtex: Must have at least one input file\n";
        ap.usage();
        exit (EXIT_FAILURE);
    }
}

static void
test_gettextureinfo (ustring filename)
{
    bool ok;

    int res[2];
    ok = texsys->get_texture_info (filename, ustring("resolution"),
                                   TypeDesc(TypeDesc::INT,2), res);
    std::cerr << "Result of get_texture_info resolution = " << ok << ' ' << res[0] << 'x' << res[1] << "\n";

    int chan;
    ok = texsys->get_texture_info (filename, ustring("channels"),
                                   TypeDesc::INT, &chan);
    std::cerr << "Result of get_texture_info channels = " << ok << ' ' << chan << "\n";

    float fchan;
    ok = texsys->get_texture_info (filename, ustring("channels"),
                                   TypeDesc::FLOAT, &fchan);
    std::cerr << "Result of get_texture_info channels = " << ok << ' ' << fchan << "\n";

    int dataformat;
    ok = texsys->get_texture_info (filename, ustring("format"),
                                   TypeDesc::INT, &dataformat);
    std::cerr << "Result of get_texture_info data format = " << ok << ' '
              << TypeDesc((TypeDesc::BASETYPE)dataformat).c_str() << "\n";

    const char *datetime = NULL;
    ok = texsys->get_texture_info (filename, ustring("DateTime"),
                                   TypeDesc::STRING, &datetime);
    std::cerr << "Result of get_texture_info datetime = " << ok << ' '
              << (datetime ? datetime : "") << "\n";

    const char *texturetype = NULL;
    ok = texsys->get_texture_info (filename, ustring("textureformat"),
                                   TypeDesc::STRING, &texturetype);
    std::cerr << "Texture type is " << ok << ' '
              << (texturetype ? texturetype : "") << "\n";
    std::cerr << "\n";
}

inline Imath::V3f
warp (float x, float y, Imath::M33f &xform)
{
    Imath::V3f coord (x, y, 1.0f);
    coord *= xform;
    coord[0] *= 1/(1+2*std::max (-0.5f, coord[1]));
    return coord;
}

static void
test_plain_texture (ustring filename)
{
    std::cerr << "Testing 2d texture " << filename << ", output = "
              << output_filename << "\n";
    const int nchannels = 4;
    ImageSpec outspec (output_xres, output_yres, nchannels, TypeDesc::HALF);
    ImageBuf image (output_filename, outspec);
    image.zero ();

    Imath::M33f scale;  scale.scale (Imath::V2f (0.5, 0.5));
    Imath::M33f rot;    rot.rotate (radians(30.0f));
    Imath::M33f trans;  trans.translate (Imath::V2f (0.35f, 0.15f));
    Imath::M33f xform = scale * rot * trans;
    xform.invert();

    TextureOptions opt;
    opt.sblur = blur;
    opt.tblur = blur;
    opt.swidth = width;
    opt.twidth = width;
    opt.nchannels = nchannels;
    float fill = 1;
    opt.fill = fill;
    if (missing[0] >= 0)
        opt.missingcolor.init ((float *)&missing, 0);

//    opt.interpmode = TextureOptions::InterpSmartBicubic;
//    opt.mipmode = TextureOptions::MipModeAniso;
    opt.swrap = opt.twrap = TextureOptions::WrapPeriodic;
//    opt.twrap = TextureOptions::WrapBlack;
    int shadepoints = blocksize*blocksize;
    float *s = ALLOCA (float, shadepoints);
    float *t = ALLOCA (float, shadepoints);
    Runflag *runflags = ALLOCA (Runflag, shadepoints);
    float *dsdx = ALLOCA (float, shadepoints);
    float *dtdx = ALLOCA (float, shadepoints);
    float *dsdy = ALLOCA (float, shadepoints);
    float *dtdy = ALLOCA (float, shadepoints);
    float *result = ALLOCA (float, shadepoints*nchannels);

    for (int iter = 0;  iter < iters;  ++iter) {
        // Iterate over blocks

        // Trick: switch to second texture, if given, for second iteration
        if (iter && filenames.size() > 1)
            filename = ustring (filenames[1]);

        for (int by = 0;  by < output_yres;  by+=blocksize) {
            for (int bx = 0;  bx < output_xres;  bx+=blocksize) {
                // Process pixels within a block.  First save the texture warp
                // (s,t) and derivatives into SIMD vectors.
                int idx = 0;
                for (int y = by; y < by+blocksize; ++y) {
                    for (int x = bx; x < bx+blocksize; ++x) {
                        if (x < output_xres && y < output_yres) {
                            if (nowarp) {
                                s[idx] = (float)x/output_xres;
                                t[idx] = (float)y/output_yres;
                                dsdx[idx] = 1.0f/output_xres;
                                dtdx[idx] = 0;
                                dsdy[idx] = 0;
                                dtdy[idx] = 1.0f/output_yres;
                            } else {
                                Imath::V3f coord = warp ((float)x/output_xres,
                                                         (float)y/output_yres,
                                                         xform);
                                Imath::V3f coordx = warp ((float)(x+1)/output_xres,
                                                          (float)y/output_yres,
                                                          xform);
                                Imath::V3f coordy = warp ((float)x/output_xres,
                                                          (float)(y+1)/output_yres,
                                                          xform);
                                s[idx] = coord[0];
                                t[idx] = coord[1];
                                dsdx[idx] = coordx[0] - coord[0];
                                dtdx[idx] = coordx[1] - coord[1];
                                dsdy[idx] = coordy[0] - coord[0];
                                dtdy[idx] = coordy[1] - coord[1];
                            }
                            runflags[idx] = RunFlagOn;
                        } else {
                            runflags[idx] = RunFlagOff;
                        }
                        ++idx;
                    }
                }
                // Call the texture system to do the filtering.
                bool ok = texsys->texture (filename, opt, runflags, 0, shadepoints,
                                           Varying(s), Varying(t),
                                           Varying(dsdx), Varying(dtdx),
                                           Varying(dsdy), Varying(dtdy), result);
                if (! ok) {
                    std::string e = texsys->geterror ();
                    if (! e.empty())
                        std::cerr << "ERROR: " << e << "\n";
                }

                // Save filtered pixels back to the image.
                idx = 0;
                for (int y = by; y < by+blocksize; ++y) {
                    for (int x = bx; x < bx+blocksize; ++x) {
                        if (runflags[idx]) {
                            image.setpixel (x, y, result + idx*nchannels);
                        }
                        ++idx;
                    }
                }
            }
        }
    }

    if (! image.save ())
        std::cerr << "Error writing " << output_filename
                  << " : " << image.geterror() << "\n";
}

static void
test_shadow (ustring filename)
{
}

static void
test_environment (ustring filename)
{
}

static void
test_getimagespec_gettexels (ustring filename)
{
    ImageSpec spec;
    if (! texsys->get_imagespec (filename, spec)) {
        std::cerr << "Could not get spec for " << filename << "\n";
        std::string e = texsys->geterror ();
        if (! e.empty())
            std::cerr << "ERROR: " << e << "\n";
        return;
    }
    int w = spec.width/2, h = spec.height/2;
    ImageSpec postagespec (w, h, spec.nchannels, TypeDesc::FLOAT);
    ImageBuf buf ("postage.exr", postagespec);
    TextureOptions opt;
    opt.nchannels = spec.nchannels;
    if (missing[0] >= 0)
        opt.missingcolor.init ((float *)&missing, 0);
    std::vector<float> tmp (w*h*spec.nchannels);
    texsys->get_texels (filename, opt, 0, w/2, w/2+w, h/2, h/2+h, 0, 1,
                        postagespec.format, &tmp[0]);
    for (int y = 0;  y < h;  ++y)
        for (int x = 0;  x < w;  ++x) {
            imagesize_t offset = (y*w + x) * spec.nchannels;
            buf.setpixel (x, y, &tmp[offset]);
        }
    buf.save ();
}

int
main (int argc, const char *argv[])
{
    getargs (argc, argv);

    texsys = TextureSystem::create ();
    std::cerr << "Created texture system\n";
    texsys->attribute ("statistics:level", 2);
    texsys->attribute ("autotile", autotile);
    texsys->attribute ("automip", (int)automip);
    if (cachesize >= 0)
        texsys->attribute ("max_memory_MB", cachesize);
    if (searchpath.length())
        texsys->attribute ("searchpath", searchpath);

    if (iters > 0) {
        ustring filename (filenames[0]);
        test_gettextureinfo (filename);
        const char *texturetype = "Plain Texture";
        texsys->get_texture_info (filename, ustring("texturetype"),
                                  TypeDesc::STRING, &texturetype);
        if (! strcmp (texturetype, "Plain Texture")) {
            test_plain_texture (filename);
        }
        if (! strcmp (texturetype, "Shadow")) {
            test_shadow (filename);
        }
        if (! strcmp (texturetype, "Environment")) {
            test_environment (filename);
        }
        test_getimagespec_gettexels (filename);
    }

    TextureSystem::destroy (texsys);
    return 0;
}
<commit_msg>fixed testtex: it was crashing when performing texture-missing.<commit_after>/*
  Copyright 2008 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

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

  (This is the Modified BSD License)
*/

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <iterator>

#include <OpenEXR/ImathMatrix.h>
#include <OpenEXR/ImathVec.h>

#include "argparse.h"
#include "imageio.h"
using namespace OpenImageIO;
#include "ustring.h"
#include "imagebuf.h"
#include "texture.h"
#include "fmath.h"
#include "sysutil.h"

static std::vector<std::string> filenames;
static std::string output_filename = "out.exr";
static bool verbose = false;
static int output_xres = 512, output_yres = 512;
static float blur = 0;
static float width = 1;
static int iters = 1;
static int autotile = 0;
static bool automip = false;
static TextureSystem *texsys = NULL;
static std::string searchpath;
static int blocksize = 1;
static bool nowarp = false;
static float cachesize = -1;
static float missing[4] = {-1, 0, 0, 1};

static int
parse_files (int argc, const char *argv[])
{
    for (int i = 0;  i < argc;  i++)
        filenames.push_back (argv[i]);
    return 0;
}

static void
getargs (int argc, const char *argv[])
{
    bool help = false;
    ArgParse ap;
    ap.options ("Usage:  testtex [options] inputfile",
                  "%*", parse_files, "",
                  "--help", &help, "Print help message",
                  "-v", &verbose, "Verbose status messages",
                  "-o %s", &output_filename, "Output test image",
                  "-res %d %d", &output_xres, &output_yres,
                      "Resolution of output test image",
                  "-iters %d", &iters,
                      "Iterations for time trials",
                  "--blur %f", &blur, "Add blur to texture lookup",
                  "--width %f", &width, "Multiply filter width of texture lookup",
                  "--missing %f %f %f", &missing[0], &missing[1], &missing[2],
                        "Specify missing texture color",
                  "--autotile %d", &autotile, "Set auto-tile size for the image cache",
                  "--automip", &automip, "Set auto-MIPmap for the image cache",
                  "--blocksize %d", &blocksize, "Set blocksize (n x n) for batches",
                  "--searchpath %s", &searchpath, "Search path for files",
                  "--nowarp", &nowarp, "Do not warp the image->texture mapping",
                  "--cachesize %g", &cachesize, "Set cache size, in MB",
                  NULL);
    if (ap.parse (argc, argv) < 0) {
        std::cerr << ap.geterror() << std::endl;
        ap.usage ();
        exit (EXIT_FAILURE);
    }
    if (help) {
        ap.usage ();
        exit (EXIT_FAILURE);
    }

    if (filenames.size() < 1) {
        std::cerr << "testtex: Must have at least one input file\n";
        ap.usage();
        exit (EXIT_FAILURE);
    }
}

static void
test_gettextureinfo (ustring filename)
{
    bool ok;

    int res[2] = {0};
    ok = texsys->get_texture_info (filename, ustring("resolution"),
                                   TypeDesc(TypeDesc::INT,2), res);
    std::cerr << "Result of get_texture_info resolution = " << ok << ' ' << res[0] << 'x' << res[1] << "\n";

    int chan = 0;
    ok = texsys->get_texture_info (filename, ustring("channels"),
                                   TypeDesc::INT, &chan);
    std::cerr << "Result of get_texture_info channels = " << ok << ' ' << chan << "\n";

    float fchan = 0;
    ok = texsys->get_texture_info (filename, ustring("channels"),
                                   TypeDesc::FLOAT, &fchan);
    std::cerr << "Result of get_texture_info channels = " << ok << ' ' << fchan << "\n";

    int dataformat = 0;
    ok = texsys->get_texture_info (filename, ustring("format"),
                                   TypeDesc::INT, &dataformat);
    std::cerr << "Result of get_texture_info data format = " << ok << ' '
              << TypeDesc((TypeDesc::BASETYPE)dataformat).c_str() << "\n";

    const char *datetime = NULL;
    ok = texsys->get_texture_info (filename, ustring("DateTime"),
                                   TypeDesc::STRING, &datetime);
    std::cerr << "Result of get_texture_info datetime = " << ok << ' '
              << (datetime ? datetime : "") << "\n";

    const char *texturetype = NULL;
    ok = texsys->get_texture_info (filename, ustring("textureformat"),
                                   TypeDesc::STRING, &texturetype);
    std::cerr << "Texture type is " << ok << ' '
              << (texturetype ? texturetype : "") << "\n";
    std::cerr << "\n";
}

inline Imath::V3f
warp (float x, float y, Imath::M33f &xform)
{
    Imath::V3f coord (x, y, 1.0f);
    coord *= xform;
    coord[0] *= 1/(1+2*std::max (-0.5f, coord[1]));
    return coord;
}

static void
test_plain_texture (ustring filename)
{
    std::cerr << "Testing 2d texture " << filename << ", output = "
              << output_filename << "\n";
    const int nchannels = 4;
    ImageSpec outspec (output_xres, output_yres, nchannels, TypeDesc::HALF);
    ImageBuf image (output_filename, outspec);
    image.zero ();

    Imath::M33f scale;  scale.scale (Imath::V2f (0.5, 0.5));
    Imath::M33f rot;    rot.rotate (radians(30.0f));
    Imath::M33f trans;  trans.translate (Imath::V2f (0.35f, 0.15f));
    Imath::M33f xform = scale * rot * trans;
    xform.invert();

    TextureOptions opt;
    opt.sblur = blur;
    opt.tblur = blur;
    opt.swidth = width;
    opt.twidth = width;
    opt.nchannels = nchannels;
    float fill = 1;
    opt.fill = fill;
    if (missing[0] >= 0)
        opt.missingcolor.init ((float *)&missing, 0);

//    opt.interpmode = TextureOptions::InterpSmartBicubic;
//    opt.mipmode = TextureOptions::MipModeAniso;
    opt.swrap = opt.twrap = TextureOptions::WrapPeriodic;
//    opt.twrap = TextureOptions::WrapBlack;
    int shadepoints = blocksize*blocksize;
    float *s = ALLOCA (float, shadepoints);
    float *t = ALLOCA (float, shadepoints);
    Runflag *runflags = ALLOCA (Runflag, shadepoints);
    float *dsdx = ALLOCA (float, shadepoints);
    float *dtdx = ALLOCA (float, shadepoints);
    float *dsdy = ALLOCA (float, shadepoints);
    float *dtdy = ALLOCA (float, shadepoints);
    float *result = ALLOCA (float, shadepoints*nchannels);

    for (int iter = 0;  iter < iters;  ++iter) {
        // Iterate over blocks

        // Trick: switch to second texture, if given, for second iteration
        if (iter && filenames.size() > 1)
            filename = ustring (filenames[1]);

        for (int by = 0;  by < output_yres;  by+=blocksize) {
            for (int bx = 0;  bx < output_xres;  bx+=blocksize) {
                // Process pixels within a block.  First save the texture warp
                // (s,t) and derivatives into SIMD vectors.
                int idx = 0;
                for (int y = by; y < by+blocksize; ++y) {
                    for (int x = bx; x < bx+blocksize; ++x) {
                        if (x < output_xres && y < output_yres) {
                            if (nowarp) {
                                s[idx] = (float)x/output_xres;
                                t[idx] = (float)y/output_yres;
                                dsdx[idx] = 1.0f/output_xres;
                                dtdx[idx] = 0;
                                dsdy[idx] = 0;
                                dtdy[idx] = 1.0f/output_yres;
                            } else {
                                Imath::V3f coord = warp ((float)x/output_xres,
                                                         (float)y/output_yres,
                                                         xform);
                                Imath::V3f coordx = warp ((float)(x+1)/output_xres,
                                                          (float)y/output_yres,
                                                          xform);
                                Imath::V3f coordy = warp ((float)x/output_xres,
                                                          (float)(y+1)/output_yres,
                                                          xform);
                                s[idx] = coord[0];
                                t[idx] = coord[1];
                                dsdx[idx] = coordx[0] - coord[0];
                                dtdx[idx] = coordx[1] - coord[1];
                                dsdy[idx] = coordy[0] - coord[0];
                                dtdy[idx] = coordy[1] - coord[1];
                            }
                            runflags[idx] = RunFlagOn;
                        } else {
                            runflags[idx] = RunFlagOff;
                        }
                        ++idx;
                    }
                }
                // Call the texture system to do the filtering.
                bool ok = texsys->texture (filename, opt, runflags, 0, shadepoints,
                                           Varying(s), Varying(t),
                                           Varying(dsdx), Varying(dtdx),
                                           Varying(dsdy), Varying(dtdy), result);
                if (! ok) {
                    std::string e = texsys->geterror ();
                    if (! e.empty())
                        std::cerr << "ERROR: " << e << "\n";
                }

                // Save filtered pixels back to the image.
                idx = 0;
                for (int y = by; y < by+blocksize; ++y) {
                    for (int x = bx; x < bx+blocksize; ++x) {
                        if (runflags[idx]) {
                            image.setpixel (x, y, result + idx*nchannels);
                        }
                        ++idx;
                    }
                }
            }
        }
    }

    if (! image.save ())
        std::cerr << "Error writing " << output_filename
                  << " : " << image.geterror() << "\n";
}

static void
test_shadow (ustring filename)
{
}

static void
test_environment (ustring filename)
{
}

static void
test_getimagespec_gettexels (ustring filename)
{
    ImageSpec spec;
    if (! texsys->get_imagespec (filename, spec)) {
        std::cerr << "Could not get spec for " << filename << "\n";
        std::string e = texsys->geterror ();
        if (! e.empty())
            std::cerr << "ERROR: " << e << "\n";
        return;
    }
    int w = spec.width/2, h = spec.height/2;
    ImageSpec postagespec (w, h, spec.nchannels, TypeDesc::FLOAT);
    ImageBuf buf ("postage.exr", postagespec);
    TextureOptions opt;
    opt.nchannels = spec.nchannels;
    if (missing[0] >= 0)
        opt.missingcolor.init ((float *)&missing, 0);
    std::vector<float> tmp (w*h*spec.nchannels);
    texsys->get_texels (filename, opt, 0, w/2, w/2+w, h/2, h/2+h, 0, 1,
                        postagespec.format, &tmp[0]);
    for (int y = 0;  y < h;  ++y)
        for (int x = 0;  x < w;  ++x) {
            imagesize_t offset = (y*w + x) * spec.nchannels;
            buf.setpixel (x, y, &tmp[offset]);
        }
    buf.save ();
}

int
main (int argc, const char *argv[])
{
    getargs (argc, argv);

    texsys = TextureSystem::create ();
    std::cerr << "Created texture system\n";
    texsys->attribute ("statistics:level", 2);
    texsys->attribute ("autotile", autotile);
    texsys->attribute ("automip", (int)automip);
    if (cachesize >= 0)
        texsys->attribute ("max_memory_MB", cachesize);
    if (searchpath.length())
        texsys->attribute ("searchpath", searchpath);

    if (iters > 0) {
        ustring filename (filenames[0]);
        test_gettextureinfo (filename);
        const char *texturetype = "Plain Texture";
        texsys->get_texture_info (filename, ustring("texturetype"),
                                  TypeDesc::STRING, &texturetype);
        if (! strcmp (texturetype, "Plain Texture")) {
            test_plain_texture (filename);
        }
        if (! strcmp (texturetype, "Shadow")) {
            test_shadow (filename);
        }
        if (! strcmp (texturetype, "Environment")) {
            test_environment (filename);
        }
        test_getimagespec_gettexels (filename);
    }

    TextureSystem::destroy (texsys);
    return 0;
}
<|endoftext|>