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

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

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

******************************************************************************/

#include "ModuleRuler.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "Utilities.h"

#include <pqLinePropertyWidget.h>
#include <pqView.h>
#include <vtkAlgorithm.h>
#include <vtkDataArray.h>
#include <vtkDataSet.h>
#include <vtkImageData.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkRulerSourceRepresentation.h>
#include <vtkSMParaViewPipelineControllerWithRendering.h>
#include <vtkSMPropertyHelper.h>
#include <vtkSMSessionProxyManager.h>
#include <vtkSMSourceProxy.h>
#include <vtkSMViewProxy.h>

#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>

namespace tomviz {

ModuleRuler::ModuleRuler(QObject* p) : Superclass(p), m_showLine(true)
{
}

ModuleRuler::~ModuleRuler()
{
  this->finalize();
}

QIcon ModuleRuler::icon() const
{
  return QIcon(":/icons/pqRuler.png");
}

bool ModuleRuler::initialize(DataSource* data, vtkSMViewProxy* view)
{
  if (!this->Superclass::initialize(data, view)) {
    return false;
  }
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;

  vtkSMSessionProxyManager* pxm = data->producer()->GetSessionProxyManager();
  vtkAlgorithm* alg =
    vtkAlgorithm::SafeDownCast(data->producer()->GetClientSideObject());
  double bounds[6];
  vtkDataSet::SafeDownCast(alg->GetOutputDataObject(0))->GetBounds(bounds);
  double bounds_min[3] = { bounds[0], bounds[2], bounds[4] };
  double bounds_max[3] = { bounds[1], bounds[3], bounds[5] };

  m_RulerSource.TakeReference(
    vtkSMSourceProxy::SafeDownCast(pxm->NewProxy("sources", "Ruler")));
  vtkSMPropertyHelper(m_RulerSource, "Point1").Set(bounds_min, 3);
  vtkSMPropertyHelper(m_RulerSource, "Point2").Set(bounds_max, 3);
  m_RulerSource->UpdateVTKObjects();
  controller->RegisterPipelineProxy(m_RulerSource);

  m_Representation = controller->Show(m_RulerSource, 0, view);

  m_Representation->UpdateVTKObjects();

  updateUnits();

  QObject::connect(data, &DataSource::dataChanged, this,
                   &ModuleRuler::updateUnits);

  return m_Representation && m_RulerSource;
}

bool ModuleRuler::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(m_Representation);
  controller->UnRegisterProxy(m_RulerSource);
  this->m_Representation = nullptr;
  this->m_RulerSource = nullptr;
  return true;
}

void ModuleRuler::addToPanel(QWidget* panel)
{
  if (panel->layout()) {
    delete panel->layout();
  }
  QVBoxLayout* layout = new QVBoxLayout;

  m_Widget = new pqLinePropertyWidget(
    m_RulerSource, m_RulerSource->GetPropertyGroup(0), panel);
  layout->addWidget(m_Widget);
  m_Widget->setView(
    tomviz::convert<pqView*>(ActiveObjects::instance().activeView()));
  m_Widget->select();
  m_Widget->setWidgetVisible(m_showLine);
  layout->addStretch();
  QObject::connect(m_Widget.data(), &pqPropertyWidget::changeFinished, m_Widget.data(),
                   &pqPropertyWidget::apply);
  QObject::connect(m_Widget.data(), &pqPropertyWidget::changeFinished, this,
                   &ModuleRuler::endPointsUpdated);
  QObject::connect(m_Widget, SIGNAL(widgetVisibilityUpdated(bool)), this,
                   SLOT(updateShowLine(bool)));

  m_Widget->setWidgetVisible(m_showLine);

  QLabel* label0 = new QLabel("Point 0 data value: ");
  QLabel* label1 = new QLabel("Point 1 data value: ");
  QObject::connect(
    this, &ModuleRuler::newEndpointData, label0,
    [label0, label1](double val0, double val1) {
      label0->setText(QString("Point 0 data value: %1").arg(val0));
      label1->setText(QString("Point 1 data value: %1").arg(val1));
    });
  layout->addWidget(label0);
  layout->addWidget(label1);
  panel->setLayout(layout);
}

void ModuleRuler::prepareToRemoveFromPanel(QWidget* panel)
{
  // Disconnect before the panel is removed to avoid m_showLine always being set
  // to false when the signal widgetVisibilityUpdated(bool) is emitted during
  // the tear down of the pqLinePropertyWidget.
  QObject::disconnect(m_Widget, SIGNAL(widgetVisibilityUpdated(bool)),
                      this, SLOT(updateShowLine(bool)));
}

bool ModuleRuler::setVisibility(bool val)
{
  vtkSMPropertyHelper(m_Representation, "Visibility").Set(val ? 1 : 0);
  m_Representation->UpdateVTKObjects();
  if (m_Widget) {
    m_Widget->setWidgetVisible(val);
  }
  return true;
}

bool ModuleRuler::visibility() const
{
  if (m_Representation) {
    return vtkSMPropertyHelper(m_Representation, "Visibility").GetAsInt() != 0;
  } else {
    return false;
  }
}

bool ModuleRuler::serialize(pugi::xml_node& ns) const
{
  pugi::xml_node rulerNode = ns.append_child("Ruler");
  pugi::xml_node representationNode = ns.append_child("Representation");

  QStringList rulerProperties;
  rulerProperties << "Point1"
                  << "Point2";
  QStringList representationProperties;
  representationProperties << "Visibility";
  if (!tomviz::serialize(m_RulerSource, rulerNode, rulerProperties)) {
    qWarning("Failed to serialize ruler");
    return false;
  }
  if (!tomviz::serialize(m_Representation, representationNode,
                         representationProperties)) {
    qWarning("Failed to serialize ruler representation");
    return false;
  }
  return true;
}

bool ModuleRuler::deserialize(const pugi::xml_node& ns)
{
  return tomviz::deserialize(m_RulerSource, ns.child("Ruler")) &&
         tomviz::deserialize(m_Representation, ns.child("Representation"));
}

bool ModuleRuler::isProxyPartOfModule(vtkSMProxy* proxy)
{
  return proxy == m_RulerSource.GetPointer() ||
         proxy == m_Representation.GetPointer();
}

std::string ModuleRuler::getStringForProxy(vtkSMProxy* proxy)
{
  if (proxy == m_RulerSource.GetPointer()) {
    return "Ruler";
  } else if (proxy == m_Representation.GetPointer()) {
    return "Representation";
  } else {
    qWarning("Unknown proxy passed to module ruler in save animation");
    return "";
  }
}

vtkSMProxy* ModuleRuler::getProxyForString(const std::string& str)
{
  if (str == "Ruler") {
    return m_RulerSource;
  } else if (str == "Representation") {
    return m_Representation;
  } else {
    return nullptr;
  }
}

void ModuleRuler::updateUnits()
{
  DataSource* source = dataSource();
  QString units = source->getUnits(0);
  vtkRulerSourceRepresentation* rep =
    vtkRulerSourceRepresentation::SafeDownCast(
      m_Representation->GetClientSideObject());
  QString labelFormat = "%-#6.3g %1";
  rep->SetLabelFormat(labelFormat.arg(units).toLatin1().data());
}

void ModuleRuler::updateShowLine(bool show)
{
  m_showLine = show;
}

void ModuleRuler::endPointsUpdated()
{
  double point1[3];
  double point2[3];
  vtkSMPropertyHelper(m_RulerSource, "Point1").Get(point1, 3);
  vtkSMPropertyHelper(m_RulerSource, "Point2").Get(point2, 3);
  DataSource* source = dataSource();
  vtkImageData* img = vtkImageData::SafeDownCast(
    vtkAlgorithm::SafeDownCast(source->producer()->GetClientSideObject())
      ->GetOutputDataObject(0));
  vtkIdType p1 = img->FindPoint(point1);
  vtkIdType p2 = img->FindPoint(point2);
  double v1 = img->GetPointData()->GetScalars()->GetTuple1(p1);
  double v2 = img->GetPointData()->GetScalars()->GetTuple1(p2);
  emit newEndpointData(v1, v2);
  renderNeeded();
}
}
<commit_msg>Add serialization/deserialization of ModuleRuler "Show Line" setting<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

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

******************************************************************************/

#include "ModuleRuler.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "Utilities.h"

#include <pqLinePropertyWidget.h>
#include <pqView.h>
#include <vtkAlgorithm.h>
#include <vtkDataArray.h>
#include <vtkDataSet.h>
#include <vtkImageData.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkRulerSourceRepresentation.h>
#include <vtkSMParaViewPipelineControllerWithRendering.h>
#include <vtkSMPropertyHelper.h>
#include <vtkSMSessionProxyManager.h>
#include <vtkSMSourceProxy.h>
#include <vtkSMViewProxy.h>

#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>

namespace tomviz {

ModuleRuler::ModuleRuler(QObject* p) : Superclass(p), m_showLine(true)
{
}

ModuleRuler::~ModuleRuler()
{
  this->finalize();
}

QIcon ModuleRuler::icon() const
{
  return QIcon(":/icons/pqRuler.png");
}

bool ModuleRuler::initialize(DataSource* data, vtkSMViewProxy* view)
{
  if (!this->Superclass::initialize(data, view)) {
    return false;
  }
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;

  vtkSMSessionProxyManager* pxm = data->producer()->GetSessionProxyManager();
  vtkAlgorithm* alg =
    vtkAlgorithm::SafeDownCast(data->producer()->GetClientSideObject());
  double bounds[6];
  vtkDataSet::SafeDownCast(alg->GetOutputDataObject(0))->GetBounds(bounds);
  double bounds_min[3] = { bounds[0], bounds[2], bounds[4] };
  double bounds_max[3] = { bounds[1], bounds[3], bounds[5] };

  m_RulerSource.TakeReference(
    vtkSMSourceProxy::SafeDownCast(pxm->NewProxy("sources", "Ruler")));
  vtkSMPropertyHelper(m_RulerSource, "Point1").Set(bounds_min, 3);
  vtkSMPropertyHelper(m_RulerSource, "Point2").Set(bounds_max, 3);
  m_RulerSource->UpdateVTKObjects();
  controller->RegisterPipelineProxy(m_RulerSource);

  m_Representation = controller->Show(m_RulerSource, 0, view);

  m_Representation->UpdateVTKObjects();

  updateUnits();

  QObject::connect(data, &DataSource::dataChanged, this,
                   &ModuleRuler::updateUnits);

  return m_Representation && m_RulerSource;
}

bool ModuleRuler::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(m_Representation);
  controller->UnRegisterProxy(m_RulerSource);
  this->m_Representation = nullptr;
  this->m_RulerSource = nullptr;
  return true;
}

void ModuleRuler::addToPanel(QWidget* panel)
{
  if (panel->layout()) {
    delete panel->layout();
  }
  QVBoxLayout* layout = new QVBoxLayout;

  m_Widget = new pqLinePropertyWidget(
    m_RulerSource, m_RulerSource->GetPropertyGroup(0), panel);
  layout->addWidget(m_Widget);
  m_Widget->setView(
    tomviz::convert<pqView*>(ActiveObjects::instance().activeView()));
  m_Widget->select();
  m_Widget->setWidgetVisible(m_showLine);
  layout->addStretch();
  QObject::connect(m_Widget.data(), &pqPropertyWidget::changeFinished, m_Widget.data(),
                   &pqPropertyWidget::apply);
  QObject::connect(m_Widget.data(), &pqPropertyWidget::changeFinished, this,
                   &ModuleRuler::endPointsUpdated);
  QObject::connect(m_Widget, SIGNAL(widgetVisibilityUpdated(bool)), this,
                   SLOT(updateShowLine(bool)));

  m_Widget->setWidgetVisible(m_showLine);

  QLabel* label0 = new QLabel("Point 0 data value: ");
  QLabel* label1 = new QLabel("Point 1 data value: ");
  QObject::connect(
    this, &ModuleRuler::newEndpointData, label0,
    [label0, label1](double val0, double val1) {
      label0->setText(QString("Point 0 data value: %1").arg(val0));
      label1->setText(QString("Point 1 data value: %1").arg(val1));
    });
  layout->addWidget(label0);
  layout->addWidget(label1);
  panel->setLayout(layout);
}

void ModuleRuler::prepareToRemoveFromPanel(QWidget* vtkNotUsed(panel))
{
  // Disconnect before the panel is removed to avoid m_showLine always being set
  // to false when the signal widgetVisibilityUpdated(bool) is emitted during
  // the tear down of the pqLinePropertyWidget.
  QObject::disconnect(m_Widget, SIGNAL(widgetVisibilityUpdated(bool)),
                      this, SLOT(updateShowLine(bool)));
}

bool ModuleRuler::setVisibility(bool val)
{
  vtkSMPropertyHelper(m_Representation, "Visibility").Set(val ? 1 : 0);
  m_Representation->UpdateVTKObjects();
  if (m_Widget) {
    m_Widget->setWidgetVisible(val);
  }
  return true;
}

bool ModuleRuler::visibility() const
{
  if (m_Representation) {
    return vtkSMPropertyHelper(m_Representation, "Visibility").GetAsInt() != 0;
  } else {
    return false;
  }
}

bool ModuleRuler::serialize(pugi::xml_node& ns) const
{
  pugi::xml_node rulerNode = ns.append_child("Ruler");
  pugi::xml_node representationNode = ns.append_child("Representation");

  QStringList rulerProperties;
  rulerProperties << "Point1"
                  << "Point2";
  QStringList representationProperties;
  representationProperties << "Visibility";
  if (!tomviz::serialize(m_RulerSource, rulerNode, rulerProperties)) {
    qWarning("Failed to serialize ruler");
    return false;
  }

  pugi::xml_node showLine = representationNode.append_child("ShowLine");
  showLine.append_attribute("value").set_value(m_showLine);

  if (!tomviz::serialize(m_Representation, representationNode,
                         representationProperties)) {
    qWarning("Failed to serialize ruler representation");
    return false;
  }

  return true;
}

bool ModuleRuler::deserialize(const pugi::xml_node& ns)
{
  pugi::xml_node representationNode = ns.child("Representation");
  bool success = tomviz::deserialize(m_RulerSource, ns.child("Ruler")) &&
    tomviz::deserialize(m_Representation, representationNode);

  if (representationNode) {
    pugi::xml_node showLineNode = representationNode.child("ShowLine");
    if (showLineNode) {
      pugi::xml_attribute valueAttribute = showLineNode.attribute("value");
      if (valueAttribute) {
        m_showLine = valueAttribute.as_bool();
      }
    }
  }

  return success;
}

bool ModuleRuler::isProxyPartOfModule(vtkSMProxy* proxy)
{
  return proxy == m_RulerSource.GetPointer() ||
         proxy == m_Representation.GetPointer();
}

std::string ModuleRuler::getStringForProxy(vtkSMProxy* proxy)
{
  if (proxy == m_RulerSource.GetPointer()) {
    return "Ruler";
  } else if (proxy == m_Representation.GetPointer()) {
    return "Representation";
  } else {
    qWarning("Unknown proxy passed to module ruler in save animation");
    return "";
  }
}

vtkSMProxy* ModuleRuler::getProxyForString(const std::string& str)
{
  if (str == "Ruler") {
    return m_RulerSource;
  } else if (str == "Representation") {
    return m_Representation;
  } else {
    return nullptr;
  }
}

void ModuleRuler::updateUnits()
{
  DataSource* source = dataSource();
  QString units = source->getUnits(0);
  vtkRulerSourceRepresentation* rep =
    vtkRulerSourceRepresentation::SafeDownCast(
      m_Representation->GetClientSideObject());
  QString labelFormat = "%-#6.3g %1";
  rep->SetLabelFormat(labelFormat.arg(units).toLatin1().data());
}

void ModuleRuler::updateShowLine(bool show)
{
  m_showLine = show;
}

void ModuleRuler::endPointsUpdated()
{
  double point1[3];
  double point2[3];
  vtkSMPropertyHelper(m_RulerSource, "Point1").Get(point1, 3);
  vtkSMPropertyHelper(m_RulerSource, "Point2").Get(point2, 3);
  DataSource* source = dataSource();
  vtkImageData* img = vtkImageData::SafeDownCast(
    vtkAlgorithm::SafeDownCast(source->producer()->GetClientSideObject())
      ->GetOutputDataObject(0));
  vtkIdType p1 = img->FindPoint(point1);
  vtkIdType p2 = img->FindPoint(point2);
  double v1 = img->GetPointData()->GetScalars()->GetTuple1(p1);
  double v2 = img->GetPointData()->GetScalars()->GetTuple1(p2);
  emit newEndpointData(v1, v2);
  renderNeeded();
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2006, Google Inc.
// 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 Google Inc. 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.

#include <assert.h>

// Disable exception handler warnings.
#pragma warning( disable : 4530 )

#include <fstream>

#include "common/windows/string_utils-inl.h"

#include "common/windows/http_upload.h"

namespace google_breakpad {

using std::ifstream;
using std::ios;

static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";

// Helper class which closes an internet handle when it goes away
class HTTPUpload::AutoInternetHandle {
 public:
  explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}
  ~AutoInternetHandle() {
    if (handle_) {
      InternetCloseHandle(handle_);
    }
  }

  HINTERNET get() { return handle_; }

 private:
  HINTERNET handle_;
};

// static
bool HTTPUpload::SendRequest(const wstring &url,
                             const map<wstring, wstring> &parameters,
                             const wstring &upload_file,
                             const wstring &file_part_name,
                             int *timeout,
                             wstring *response_body,
                             int *response_code) {
  if (response_code) {
    *response_code = 0;
  }

  // TODO(bryner): support non-ASCII parameter names
  if (!CheckParameters(parameters)) {
    return false;
  }

  // Break up the URL and make sure we can handle it
  wchar_t scheme[16], host[256], path[256];
  URL_COMPONENTS components;
  memset(&components, 0, sizeof(components));
  components.dwStructSize = sizeof(components);
  components.lpszScheme = scheme;
  components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
  components.lpszHostName = host;
  components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
  components.lpszUrlPath = path;
  components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
  if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),
                        0, &components)) {
    return false;
  }
  bool secure = false;
  if (wcscmp(scheme, L"https") == 0) {
    secure = true;
  } else if (wcscmp(scheme, L"http") != 0) {
    return false;
  }

  AutoInternetHandle internet(InternetOpen(kUserAgent,
                                           INTERNET_OPEN_TYPE_PRECONFIG,
                                           NULL,  // proxy name
                                           NULL,  // proxy bypass
                                           0));   // flags
  if (!internet.get()) {
    return false;
  }

  AutoInternetHandle connection(InternetConnect(internet.get(),
                                                host,
                                                components.nPort,
                                                NULL,    // user name
                                                NULL,    // password
                                                INTERNET_SERVICE_HTTP,
                                                0,       // flags
                                                NULL));  // context
  if (!connection.get()) {
    return false;
  }

  DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;
  http_open_flags |= INTERNET_FLAG_NO_COOKIES;
  AutoInternetHandle request(HttpOpenRequest(connection.get(),
                                             L"POST",
                                             path,
                                             NULL,    // version
                                             NULL,    // referer
                                             NULL,    // agent type
                                             http_open_flags,
                                             NULL));  // context
  if (!request.get()) {
    return false;
  }

  wstring boundary = GenerateMultipartBoundary();
  wstring content_type_header = GenerateRequestHeader(boundary);
  HttpAddRequestHeaders(request.get(),
                        content_type_header.c_str(),
                        static_cast<DWORD>(-1),
                        HTTP_ADDREQ_FLAG_ADD);

  string request_body;
  if (!GenerateRequestBody(parameters, upload_file,
                           file_part_name, boundary, &request_body)) {
    return false;
  }

  if (timeout) {
    if (!InternetSetOption(request.get(),
                           INTERNET_OPTION_SEND_TIMEOUT,
                           timeout,
                           sizeof(timeout))) {
      fwprintf(stderr, L"Could not unset send timeout, continuing...\n");
    }

    if (!InternetSetOption(request.get(),
                           INTERNET_OPTION_RECEIVE_TIMEOUT,
                           timeout,
                           sizeof(timeout))) {
      fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");
    }
  }

  if (!HttpSendRequest(request.get(), NULL, 0,
                       const_cast<char *>(request_body.data()),
                       static_cast<DWORD>(request_body.size()))) {
    return false;
  }

  // The server indicates a successful upload with HTTP status 200.
  wchar_t http_status[4];
  DWORD http_status_size = sizeof(http_status);
  if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,
                     static_cast<LPVOID>(&http_status), &http_status_size,
                     0)) {
    return false;
  }

  int http_response = wcstol(http_status, NULL, 10);
  if (response_code) {
    *response_code = http_response;
  }

  bool result = (http_response == 200);

  if (result) {
    result = ReadResponse(request.get(), response_body);
  }

  return result;
}

// static
bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {
  bool has_content_length_header = false;
  wchar_t content_length[32];
  DWORD content_length_size = sizeof(content_length);
  DWORD claimed_size = 0;
  string response_body;

  if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,
                    static_cast<LPVOID>(&content_length),
                    &content_length_size, 0)) {
    has_content_length_header = true;
    claimed_size = wcstol(content_length, NULL, 10);
    response_body.reserve(claimed_size);
  }

  DWORD bytes_available;
  DWORD total_read = 0;
  BOOL return_code;

  while (((return_code = InternetQueryDataAvailable(request, &bytes_available,
	  0, 0)) != 0) && bytes_available > 0) {

    vector<char> response_buffer(bytes_available);
    DWORD size_read;

    return_code = InternetReadFile(request,
                                   &response_buffer[0],
                                   bytes_available, &size_read);

    if (return_code && size_read > 0) {
      total_read += size_read;
      response_body.append(&response_buffer[0], size_read);
    } else {
      break;
    }
  }

  bool succeeded = return_code && (!has_content_length_header ||
                                   (total_read == claimed_size));
  if (succeeded && response) {
    *response = UTF8ToWide(response_body);
  }

  return succeeded;
}

// static
wstring HTTPUpload::GenerateMultipartBoundary() {
  // The boundary has 27 '-' characters followed by 16 hex digits
  static const wchar_t kBoundaryPrefix[] = L"---------------------------";
  static const int kBoundaryLength = 27 + 16 + 1;

  // Generate some random numbers to fill out the boundary
  int r0 = rand();
  int r1 = rand();

  wchar_t temp[kBoundaryLength];
  swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);

  // remove when VC++7.1 is no longer supported
  temp[kBoundaryLength - 1] = L'\0';

  return wstring(temp);
}

// static
wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
  wstring header = L"Content-Type: multipart/form-data; boundary=";
  header += boundary;
  return header;
}

// static
bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,
                                     const wstring &upload_file,
                                     const wstring &file_part_name,
                                     const wstring &boundary,
                                     string *request_body) {
  vector<char> contents;
  if (!GetFileContents(upload_file, &contents)) {
    return false;
  }

  string boundary_str = WideToUTF8(boundary);
  if (boundary_str.empty()) {
    return false;
  }

  request_body->clear();

  // Append each of the parameter pairs as a form-data part
  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
       pos != parameters.end(); ++pos) {
    request_body->append("--" + boundary_str + "\r\n");
    request_body->append("Content-Disposition: form-data; name=\"" +
                         WideToUTF8(pos->first) + "\"\r\n\r\n" +
                         WideToUTF8(pos->second) + "\r\n");
  }

  // Now append the upload file as a binary (octet-stream) part
  string filename_utf8 = WideToUTF8(upload_file);
  if (filename_utf8.empty()) {
    return false;
  }

  string file_part_name_utf8 = WideToUTF8(file_part_name);
  if (file_part_name_utf8.empty()) {
    return false;
  }

  request_body->append("--" + boundary_str + "\r\n");
  request_body->append("Content-Disposition: form-data; "
                       "name=\"" + file_part_name_utf8 + "\"; "
                       "filename=\"" + filename_utf8 + "\"\r\n");
  request_body->append("Content-Type: application/octet-stream\r\n");
  request_body->append("\r\n");

  if (!contents.empty()) {
      request_body->append(&(contents[0]), contents.size());
  }
  request_body->append("\r\n");
  request_body->append("--" + boundary_str + "--\r\n");
  return true;
}

// static
bool HTTPUpload::GetFileContents(const wstring &filename,
                                 vector<char> *contents) {
  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
  // later, _wfopen has been deprecated in favor of _wfopen_s, which does
  // not exist in earlier versions, so let the ifstream open the file itself.
#if _MSC_VER >= 1400  // MSVC 2005/8
  ifstream file;
  file.open(filename.c_str(), ios::binary);
#else  // _MSC_VER >= 1400
  ifstream file(_wfopen(filename.c_str(), L"rb"));
#endif  // _MSC_VER >= 1400
  if (file.is_open()) {
    file.seekg(0, ios::end);
    std::streamoff length = file.tellg();
    contents->resize(length);
    if (length != 0) {
      file.seekg(0, ios::beg);
      file.read(&((*contents)[0]), length);
    }
    file.close();
    return true;
  }
  return false;
}

// static
wstring HTTPUpload::UTF8ToWide(const string &utf8) {
  if (utf8.length() == 0) {
    return wstring();
  }

  // compute the length of the buffer we'll need
  int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);

  if (charcount == 0) {
    return wstring();
  }

  // convert
  wchar_t* buf = new wchar_t[charcount];
  MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);
  wstring result(buf);
  delete[] buf;
  return result;
}

// static
string HTTPUpload::WideToUTF8(const wstring &wide) {
  if (wide.length() == 0) {
    return string();
  }

  // compute the length of the buffer we'll need
  int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1,
                                      NULL, 0, NULL, NULL);
  if (charcount == 0) {
    return string();
  }

  // convert
  char *buf = new char[charcount];
  WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount,
                      NULL, NULL);

  string result(buf);
  delete[] buf;
  return result;
}

// static
bool HTTPUpload::CheckParameters(const map<wstring, wstring> &parameters) {
  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
       pos != parameters.end(); ++pos) {
    const wstring &str = pos->first;
    if (str.size() == 0) {
      return false;  // disallow empty parameter names
    }
    for (unsigned int i = 0; i < str.size(); ++i) {
      wchar_t c = str[i];
      if (c < 32 || c == '"' || c > 127) {
        return false;
      }
    }
  }
  return true;
}

}  // namespace google_breakpad
<commit_msg>Fix sizeof bug in HTTPUpload::SendRequest A=Himanshu <only4coding@gmail.com> R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=710993<commit_after>// Copyright (c) 2006, Google Inc.
// 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 Google Inc. 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.

#include <assert.h>

// Disable exception handler warnings.
#pragma warning( disable : 4530 )

#include <fstream>

#include "common/windows/string_utils-inl.h"

#include "common/windows/http_upload.h"

namespace google_breakpad {

using std::ifstream;
using std::ios;

static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";

// Helper class which closes an internet handle when it goes away
class HTTPUpload::AutoInternetHandle {
 public:
  explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}
  ~AutoInternetHandle() {
    if (handle_) {
      InternetCloseHandle(handle_);
    }
  }

  HINTERNET get() { return handle_; }

 private:
  HINTERNET handle_;
};

// static
bool HTTPUpload::SendRequest(const wstring &url,
                             const map<wstring, wstring> &parameters,
                             const wstring &upload_file,
                             const wstring &file_part_name,
                             int *timeout,
                             wstring *response_body,
                             int *response_code) {
  if (response_code) {
    *response_code = 0;
  }

  // TODO(bryner): support non-ASCII parameter names
  if (!CheckParameters(parameters)) {
    return false;
  }

  // Break up the URL and make sure we can handle it
  wchar_t scheme[16], host[256], path[256];
  URL_COMPONENTS components;
  memset(&components, 0, sizeof(components));
  components.dwStructSize = sizeof(components);
  components.lpszScheme = scheme;
  components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
  components.lpszHostName = host;
  components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
  components.lpszUrlPath = path;
  components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
  if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),
                        0, &components)) {
    return false;
  }
  bool secure = false;
  if (wcscmp(scheme, L"https") == 0) {
    secure = true;
  } else if (wcscmp(scheme, L"http") != 0) {
    return false;
  }

  AutoInternetHandle internet(InternetOpen(kUserAgent,
                                           INTERNET_OPEN_TYPE_PRECONFIG,
                                           NULL,  // proxy name
                                           NULL,  // proxy bypass
                                           0));   // flags
  if (!internet.get()) {
    return false;
  }

  AutoInternetHandle connection(InternetConnect(internet.get(),
                                                host,
                                                components.nPort,
                                                NULL,    // user name
                                                NULL,    // password
                                                INTERNET_SERVICE_HTTP,
                                                0,       // flags
                                                NULL));  // context
  if (!connection.get()) {
    return false;
  }

  DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;
  http_open_flags |= INTERNET_FLAG_NO_COOKIES;
  AutoInternetHandle request(HttpOpenRequest(connection.get(),
                                             L"POST",
                                             path,
                                             NULL,    // version
                                             NULL,    // referer
                                             NULL,    // agent type
                                             http_open_flags,
                                             NULL));  // context
  if (!request.get()) {
    return false;
  }

  wstring boundary = GenerateMultipartBoundary();
  wstring content_type_header = GenerateRequestHeader(boundary);
  HttpAddRequestHeaders(request.get(),
                        content_type_header.c_str(),
                        static_cast<DWORD>(-1),
                        HTTP_ADDREQ_FLAG_ADD);

  string request_body;
  if (!GenerateRequestBody(parameters, upload_file,
                           file_part_name, boundary, &request_body)) {
    return false;
  }

  if (timeout) {
    if (!InternetSetOption(request.get(),
                           INTERNET_OPTION_SEND_TIMEOUT,
                           timeout,
                           sizeof(*timeout))) {
      fwprintf(stderr, L"Could not unset send timeout, continuing...\n");
    }

    if (!InternetSetOption(request.get(),
                           INTERNET_OPTION_RECEIVE_TIMEOUT,
                           timeout,
                           sizeof(*timeout))) {
      fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");
    }
  }

  if (!HttpSendRequest(request.get(), NULL, 0,
                       const_cast<char *>(request_body.data()),
                       static_cast<DWORD>(request_body.size()))) {
    return false;
  }

  // The server indicates a successful upload with HTTP status 200.
  wchar_t http_status[4];
  DWORD http_status_size = sizeof(http_status);
  if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,
                     static_cast<LPVOID>(&http_status), &http_status_size,
                     0)) {
    return false;
  }

  int http_response = wcstol(http_status, NULL, 10);
  if (response_code) {
    *response_code = http_response;
  }

  bool result = (http_response == 200);

  if (result) {
    result = ReadResponse(request.get(), response_body);
  }

  return result;
}

// static
bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {
  bool has_content_length_header = false;
  wchar_t content_length[32];
  DWORD content_length_size = sizeof(content_length);
  DWORD claimed_size = 0;
  string response_body;

  if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,
                    static_cast<LPVOID>(&content_length),
                    &content_length_size, 0)) {
    has_content_length_header = true;
    claimed_size = wcstol(content_length, NULL, 10);
    response_body.reserve(claimed_size);
  }

  DWORD bytes_available;
  DWORD total_read = 0;
  BOOL return_code;

  while (((return_code = InternetQueryDataAvailable(request, &bytes_available,
	  0, 0)) != 0) && bytes_available > 0) {

    vector<char> response_buffer(bytes_available);
    DWORD size_read;

    return_code = InternetReadFile(request,
                                   &response_buffer[0],
                                   bytes_available, &size_read);

    if (return_code && size_read > 0) {
      total_read += size_read;
      response_body.append(&response_buffer[0], size_read);
    } else {
      break;
    }
  }

  bool succeeded = return_code && (!has_content_length_header ||
                                   (total_read == claimed_size));
  if (succeeded && response) {
    *response = UTF8ToWide(response_body);
  }

  return succeeded;
}

// static
wstring HTTPUpload::GenerateMultipartBoundary() {
  // The boundary has 27 '-' characters followed by 16 hex digits
  static const wchar_t kBoundaryPrefix[] = L"---------------------------";
  static const int kBoundaryLength = 27 + 16 + 1;

  // Generate some random numbers to fill out the boundary
  int r0 = rand();
  int r1 = rand();

  wchar_t temp[kBoundaryLength];
  swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);

  // remove when VC++7.1 is no longer supported
  temp[kBoundaryLength - 1] = L'\0';

  return wstring(temp);
}

// static
wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
  wstring header = L"Content-Type: multipart/form-data; boundary=";
  header += boundary;
  return header;
}

// static
bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,
                                     const wstring &upload_file,
                                     const wstring &file_part_name,
                                     const wstring &boundary,
                                     string *request_body) {
  vector<char> contents;
  if (!GetFileContents(upload_file, &contents)) {
    return false;
  }

  string boundary_str = WideToUTF8(boundary);
  if (boundary_str.empty()) {
    return false;
  }

  request_body->clear();

  // Append each of the parameter pairs as a form-data part
  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
       pos != parameters.end(); ++pos) {
    request_body->append("--" + boundary_str + "\r\n");
    request_body->append("Content-Disposition: form-data; name=\"" +
                         WideToUTF8(pos->first) + "\"\r\n\r\n" +
                         WideToUTF8(pos->second) + "\r\n");
  }

  // Now append the upload file as a binary (octet-stream) part
  string filename_utf8 = WideToUTF8(upload_file);
  if (filename_utf8.empty()) {
    return false;
  }

  string file_part_name_utf8 = WideToUTF8(file_part_name);
  if (file_part_name_utf8.empty()) {
    return false;
  }

  request_body->append("--" + boundary_str + "\r\n");
  request_body->append("Content-Disposition: form-data; "
                       "name=\"" + file_part_name_utf8 + "\"; "
                       "filename=\"" + filename_utf8 + "\"\r\n");
  request_body->append("Content-Type: application/octet-stream\r\n");
  request_body->append("\r\n");

  if (!contents.empty()) {
      request_body->append(&(contents[0]), contents.size());
  }
  request_body->append("\r\n");
  request_body->append("--" + boundary_str + "--\r\n");
  return true;
}

// static
bool HTTPUpload::GetFileContents(const wstring &filename,
                                 vector<char> *contents) {
  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
  // later, _wfopen has been deprecated in favor of _wfopen_s, which does
  // not exist in earlier versions, so let the ifstream open the file itself.
#if _MSC_VER >= 1400  // MSVC 2005/8
  ifstream file;
  file.open(filename.c_str(), ios::binary);
#else  // _MSC_VER >= 1400
  ifstream file(_wfopen(filename.c_str(), L"rb"));
#endif  // _MSC_VER >= 1400
  if (file.is_open()) {
    file.seekg(0, ios::end);
    std::streamoff length = file.tellg();
    contents->resize(length);
    if (length != 0) {
      file.seekg(0, ios::beg);
      file.read(&((*contents)[0]), length);
    }
    file.close();
    return true;
  }
  return false;
}

// static
wstring HTTPUpload::UTF8ToWide(const string &utf8) {
  if (utf8.length() == 0) {
    return wstring();
  }

  // compute the length of the buffer we'll need
  int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);

  if (charcount == 0) {
    return wstring();
  }

  // convert
  wchar_t* buf = new wchar_t[charcount];
  MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);
  wstring result(buf);
  delete[] buf;
  return result;
}

// static
string HTTPUpload::WideToUTF8(const wstring &wide) {
  if (wide.length() == 0) {
    return string();
  }

  // compute the length of the buffer we'll need
  int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1,
                                      NULL, 0, NULL, NULL);
  if (charcount == 0) {
    return string();
  }

  // convert
  char *buf = new char[charcount];
  WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount,
                      NULL, NULL);

  string result(buf);
  delete[] buf;
  return result;
}

// static
bool HTTPUpload::CheckParameters(const map<wstring, wstring> &parameters) {
  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
       pos != parameters.end(); ++pos) {
    const wstring &str = pos->first;
    if (str.size() == 0) {
      return false;  // disallow empty parameter names
    }
    for (unsigned int i = 0; i < str.size(); ++i) {
      wchar_t c = str[i];
      if (c < 32 || c == '"' || c > 127) {
        return false;
      }
    }
  }
  return true;
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>

int suma(int mayor){
    int saco = 0;

    for(int numero=0; numero<=mayor; numero++)
	saco += numero;

    return saco;
}

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

    printf("%i\n", suma(7));
    printf("%i\n", suma(6));

    return EXIT_SUCCESS;
}
<commit_msg>Delete serie.cpp<commit_after><|endoftext|>


<commit_before><commit_msg>[허지훈]Point Light<commit_after><|endoftext|>


<commit_before>#include <cstring>

#include "3rdparty/lodepng/lodepng.h"
#include "augs/ensure.h"

#include "augs/image/image.h"
#include "augs/filesystem/directory.h"
#include "augs/filesystem/file.h"
#include "augs/readwrite/byte_readwrite.h"

template<class C>
static void Line(
	int x1,
	int y1,
	int x2,
	int y2,
	C callback
) {
	// Bresenham's line algorithm
	const bool steep = (std::abs(y2 - y1) > std::abs(x2 - x1));
	if (steep)
	{
		std::swap(x1, y1);
		std::swap(x2, y2);
	}

	if (x1 > x2)
	{
		std::swap(x1, x2);
		std::swap(y1, y2);
	}

	const int dx = x2 - x1;
	const int dy = std::abs(y2 - y1);

	float error = dx / 2.0f;
	const int ystep = (y1 < y2) ? 1 : -1;
	int y = (int)y1;

	const int maxX = (int)x2;

	for (int x = (int)x1; x<=maxX; x++)
	{
		if (steep)
		{
			callback(y, x);
		}
		else
		{
			callback(x, y);
		}

		error -= dy;
		if (error < 0)
		{
			y += ystep;
			error += dx;
		}
	}
}

namespace augs {
	static void throw_if_zero_size(const path_type& path, const vec2u size) {
		if (!size.x || !size.y) {
			throw image_loading_error("Failed to load image %x:\nWidth or height is zero!", path);
		}
	}

	vec2u image::get_size(const path_type& file_path) {
		try {
			return image(file_path).get_size();
		}
		catch (image_loading_error err) {
			throw image_loading_error("Failed to read image size.\n%x", err.what());
		}
	}

	image::image(const vec2u new_size) {
		resize_fill(new_size);
	}

	image::image(
		const unsigned char* const ptr,
		const unsigned channels,
		const unsigned pitch,
		const vec2u new_size
	) {
		resize_no_fill(new_size);

		if (channels == 1) {
			for (unsigned j = 0; j < new_size.y; ++j) {
				for (unsigned i = 0; i < new_size.x; ++i) {
					pixel({ i, j }) = { 255, 255, 255, ptr[pitch * j + i] };
				}
			}
		}
		else if (channels == 4 && pitch == 0) {
			std::memcpy(v.data(), ptr, new_size.area() * 4);
		}
		else {
			ensure(false);
		}
	}

	image::image(const path_type& path) {
		from_file(path);
	}

	void image::from_file(const path_type& path) {
		const auto extension = path.extension();

		if (extension == "") {
			const auto resolved_path = augs::switch_path(
				augs::path_type(path) += ".png",
				augs::path_type(path) += ".bin"
			);

			from_file(resolved_path);
		}
		else {
			if (extension == ".png") {
				from_png(path);
			}
			else if (extension == ".bin") {
				from_binary_file(path);
			}
			else {
				throw image_loading_error(
					"Failed to load image %x:\nUnknown image extension: %x!", path, extension
				);
			}
		}

		throw_if_zero_size(path, size);
	}

	void image::from_binary_file(const path_type& path) try {
		auto in = with_exceptions<std::ifstream>();
		in.open(path, std::ios::in | std::ios::binary);

		augs::read_bytes(in, size);
		augs::read_bytes(in, v);

		throw_if_zero_size(path, size);
	}
	catch (const augs::file_open_error& err) {
		throw image_loading_error(
			"Failed to load image %x:\n%x", path, err.what()
		);
	}

	void image::from_png(const path_type& path) {
		unsigned width;
		unsigned height;

		if (
			const auto lodepng_result =
			lodepng::decode(*reinterpret_cast<std::vector<unsigned char>*>(&v), width, height, path.string())
		) {
			throw image_loading_error(
				"Failed to load image %x:\nlodepng returned %x", path, lodepng_result
			);
		}

		size.x = width;
		size.y = height;

		throw_if_zero_size(path, size);
	}

	void image::execute(const paint_command_variant& in) {
		std::visit([&](const auto& resolved) {
			execute(resolved);
		}, in);
	}

	void image::execute(
		const paint_circle_midpoint_command& in
	) {
		const auto side = in.radius * 2 + 1;

		image new_surface;
		auto& surface = v.empty() ? *this : new_surface;

		surface = augs::image(vec2u { std::max(size.x, side), std::max(size.y, side) });

		ensure(size.x >= side);
		ensure(size.y >= side);

		const auto angle_start = vec2::from_degrees(in.angle_start);
		const auto angle_end = vec2::from_degrees(in.angle_end);

		const auto pp = [&](
			const unsigned x,
			const unsigned y
		) {
			const auto x_center = static_cast<signed>(x - size.x / 2);
			const auto y_center = static_cast<signed>(y - size.y / 2);

			const auto angle = vec2i(x_center, y_center);// .degrees();

			if (!in.constrain_angle || (angle_start.cross(vec2(angle)) >= 0.f && angle_end.cross(vec2(angle)) <= 0.f)) {
				const auto col = in.filling;
				//if (scale_alpha)
				//	col.a = (angle - angle_start) / (angle_end - angle_start) * 255;

				surface.pixel({ x, y } ) = col;
			}
		};

		for (unsigned i = 0; i < in.border_width; ++i) {
			int x = in.radius - i;
			int y = 0;

			int decisionOver2 = 1 - x;   // Decision criterion divided by 2 evaluated at x=r, y=0
			const auto x0 = size.x / 2;
			const auto y0 = size.y / 2;

			while (y <= x)
			{
				pp(x + x0, y + y0); // Octant 1
				pp(y + x0, x + y0); // Octant 2
				pp(-x + x0, y + y0); // Octant 4
				pp(-y + x0, x + y0); // Octant 3
				pp(-x + x0, -y + y0); // Octant 5
				pp(-y + x0, -x + y0); // Octant 6
				pp(x + x0, -y + y0); // Octant 7
				pp(y + x0, -x + y0); // Octant 8
				y++;

				if (decisionOver2 <= 0) {
					decisionOver2 += 2 * y + 1;   // Change in decision criterion for y -> y+1
				}
				else {
					decisionOver2 += 2 * (y - (--x)) + 1;   // Change for y -> y+1, x -> x-1
				}
			}
		}

		if (in.border_width > 1) {
			for (unsigned y = 0; y < surface.size.x; ++y) {
				for (unsigned x = 0; x < surface.size.x; ++x) {
					if (x > 0 && y > 0 && x < surface.size.x - 1 && y < surface.size.y - 1) {
						if (surface.pixel({ x, y }).a == 0 &&
							surface.pixel({x + 1, y}).a > 0 &&
							surface.pixel({x - 1, y}).a > 0 &&
							surface.pixel({x, y + 1}).a > 0 &&
							surface.pixel({x, y - 1}).a > 0)
							pp(x, y);
					}
				}
			}
		}

		if (&surface != this) {
			blit(
				surface,
				{ 0u, 0u },
				false,
				true
			);
		}
	}

	void image::execute(
		const paint_circle_filled_command& in
	) {
		const auto side = in.radius * 2 + 1;

		if (v.empty()) {
			resize_fill({ side, side });
		}
		else {
			ensure(size.x >= side);
			ensure(size.y >= side);
		}

		for (unsigned y = 0; y < size.y; ++y) {
			for (unsigned x = 0; x < size.x; ++x) {
				const auto x_center = static_cast<signed>(x - size.x / 2);
				const auto y_center = static_cast<signed>(y - size.y / 2);

				if (x_center*x_center + y_center*y_center <= static_cast<int>(in.radius*in.radius)) {
					pixel({ x, y }) = in.filling;
				}
			}
		}

		//pixel(side / 2, 0) = rgba(0, 0, 0, 0);
		//pixel(side / 2, side -1) = rgba(0, 0, 0, 0);
		//pixel(0, side /2) = rgba(0, 0, 0, 0);
		//pixel(side -1, side /2) = rgba(0, 0, 0, 0);
	}

	void image::execute(
		const paint_line_command& in
	) {
		Line(in.from.x, in.from.y, in.to.x, in.to.y, [&](const int x, const int y) {
			const auto pos = vec2u(x, y);

			ensure(in_bounds(pos));
			pixel(pos) = in.filling;
		});
	}

	void image::swap_red_and_blue() {
		for (auto& p : v) {
			std::swap(p.r, p.b);
		}
	}

	void image::save(const path_type& path) const {
		const auto extension = path.extension();

		if (extension == ".png") {
			save_as_png(path);
		}
		else if (extension == ".bin") {
			save_as_binary_file(path);
		}
		else {
			LOG("Warning: %x has unknown extension: %x! Saving as binary.", path, extension);
			save_as_binary_file(path);
		}
	}

	void image::save_as_png(const path_type& path) const {
		augs::create_directories_for(path);

		if (
			const auto lodepng_result =
			lodepng::encode(path.string(), *reinterpret_cast<const std::vector<unsigned char>*>(&v), size.x, size.y)
		) {
			LOG("Failed to save %x: lodepng returned %x. Ensure that the target directory exists.", path, lodepng_result);
		}
	}

	void image::save_as_binary_file(const path_type& path) const {
		augs::create_directories_for(path);

		std::ofstream out(path, std::ios::out | std::ios::binary);
		augs::write_bytes(out, size);
		augs::write_bytes(out, v);
	}

	void image::fill(const rgba col) {
		for (auto& p : v) {
			p = col;
		}
	}

	void image::blit(
		const image& source_image,
		const vec2u dst,
		const bool flip_source,
		const bool add_rgba_values
	) {
		const auto source_size = source_image.get_size();

		if (!add_rgba_values) {
			if (flip_source) {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ y, x }) = source_image.pixel(vec2u{ x, y });
					}
				}
			}
			else {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ x, y }) = source_image.pixel(vec2u{ x, y });
					}
				}
			}
		}
		else {
			if (flip_source) {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ y, x }) += source_image.pixel(vec2u{ x, y });
					}
				}
			}
			else {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ x, y }) += source_image.pixel(vec2u{ x, y });
					}
				}
			}
		}
	}

	image& image::desaturate() {
		for (unsigned y = 0; y < size.y; ++y) {
			for (unsigned x = 0; x < size.x; ++x) {
				pixel({ x, y }).desaturate();
			}
		}

		return *this;
	}
}

<commit_msg>implemented optimized function for just reading image sizes<commit_after>#include <cstring>

#include "3rdparty/lodepng/lodepng.h"
#include "augs/ensure.h"

#include "augs/image/image.h"
#include "augs/filesystem/directory.h"
#include "augs/filesystem/file.h"
#include "augs/readwrite/byte_readwrite.h"

#if PLATFORM_UNIX
#include <arpa/inet.h>
#else
#include <winsock.h>
#endif

template<class C>
static void Line(
	int x1,
	int y1,
	int x2,
	int y2,
	C callback
) {
	// Bresenham's line algorithm
	const bool steep = (std::abs(y2 - y1) > std::abs(x2 - x1));
	if (steep)
	{
		std::swap(x1, y1);
		std::swap(x2, y2);
	}

	if (x1 > x2)
	{
		std::swap(x1, x2);
		std::swap(y1, y2);
	}

	const int dx = x2 - x1;
	const int dy = std::abs(y2 - y1);

	float error = dx / 2.0f;
	const int ystep = (y1 < y2) ? 1 : -1;
	int y = (int)y1;

	const int maxX = (int)x2;

	for (int x = (int)x1; x<=maxX; x++)
	{
		if (steep)
		{
			callback(y, x);
		}
		else
		{
			callback(x, y);
		}

		error -= dy;
		if (error < 0)
		{
			y += ystep;
			error += dx;
		}
	}
}

namespace augs {
	static void throw_if_zero_size(const path_type& path, const vec2u size) {
		if (!size.x || !size.y) {
			throw image_loading_error("Failed to load image %x:\nWidth or height is zero!", path);
		}
	}

	vec2u image::get_size(const path_type& file_path) {
		try {
			const auto extension = file_path.extension();
			auto in = with_exceptions<std::ifstream>(file_path);

			if (extension == ".png") {
				unsigned int width, height;

				in.seekg(16);
				in.read((char*)&width, 4);
				in.read((char*)&height, 4);

				width = ntohl(width);
				height = ntohl(height);

				return { width, height };
			}
			else if (extension == ".bin") {
				vec2u s;
				augs::read_bytes(in, s);
				return s;
			}
			else {
				throw image_loading_error(
					"Failed to read size of %x:\nUnknown image extension: %x!", file_path, extension
				);
			}
		}
		catch (image_loading_error err) {
			throw;
		}
		catch (std::exception err) {
			throw image_loading_error("Failed to read size of %x:\n%x", file_path, err.what());
		}
	}

	image::image(const vec2u new_size) {
		resize_fill(new_size);
	}

	image::image(
		const unsigned char* const ptr,
		const unsigned channels,
		const unsigned pitch,
		const vec2u new_size
	) {
		resize_no_fill(new_size);

		if (channels == 1) {
			for (unsigned j = 0; j < new_size.y; ++j) {
				for (unsigned i = 0; i < new_size.x; ++i) {
					pixel({ i, j }) = { 255, 255, 255, ptr[pitch * j + i] };
				}
			}
		}
		else if (channels == 4 && pitch == 0) {
			std::memcpy(v.data(), ptr, new_size.area() * 4);
		}
		else {
			ensure(false);
		}
	}

	image::image(const path_type& path) {
		from_file(path);
	}

	void image::from_file(const path_type& path) {
		const auto extension = path.extension();

		if (extension == "") {
			const auto resolved_path = augs::switch_path(
				augs::path_type(path) += ".png",
				augs::path_type(path) += ".bin"
			);

			from_file(resolved_path);
		}
		else {
			if (extension == ".png") {
				from_png(path);
			}
			else if (extension == ".bin") {
				from_binary_file(path);
			}
			else {
				throw image_loading_error(
					"Failed to load image %x:\nUnknown image extension: %x!", path, extension
				);
			}
		}

		throw_if_zero_size(path, size);
	}

	void image::from_binary_file(const path_type& path) try {
		auto in = with_exceptions<std::ifstream>();
		in.open(path, std::ios::in | std::ios::binary);

		augs::read_bytes(in, size);
		augs::read_bytes(in, v);

		throw_if_zero_size(path, size);
	}
	catch (const augs::file_open_error& err) {
		throw image_loading_error(
			"Failed to load image %x:\n%x", path, err.what()
		);
	}

	void image::from_png(const path_type& path) {
		unsigned width;
		unsigned height;

		if (
			const auto lodepng_result =
			lodepng::decode(*reinterpret_cast<std::vector<unsigned char>*>(&v), width, height, path.string())
		) {
			throw image_loading_error(
				"Failed to load image %x:\nlodepng returned %x", path, lodepng_result
			);
		}

		size.x = width;
		size.y = height;

		throw_if_zero_size(path, size);
	}

	void image::execute(const paint_command_variant& in) {
		std::visit([&](const auto& resolved) {
			execute(resolved);
		}, in);
	}

	void image::execute(
		const paint_circle_midpoint_command& in
	) {
		const auto side = in.radius * 2 + 1;

		image new_surface;
		auto& surface = v.empty() ? *this : new_surface;

		surface = augs::image(vec2u { std::max(size.x, side), std::max(size.y, side) });

		ensure(size.x >= side);
		ensure(size.y >= side);

		const auto angle_start = vec2::from_degrees(in.angle_start);
		const auto angle_end = vec2::from_degrees(in.angle_end);

		const auto pp = [&](
			const unsigned x,
			const unsigned y
		) {
			const auto x_center = static_cast<signed>(x - size.x / 2);
			const auto y_center = static_cast<signed>(y - size.y / 2);

			const auto angle = vec2i(x_center, y_center);// .degrees();

			if (!in.constrain_angle || (angle_start.cross(vec2(angle)) >= 0.f && angle_end.cross(vec2(angle)) <= 0.f)) {
				const auto col = in.filling;
				//if (scale_alpha)
				//	col.a = (angle - angle_start) / (angle_end - angle_start) * 255;

				surface.pixel({ x, y } ) = col;
			}
		};

		for (unsigned i = 0; i < in.border_width; ++i) {
			int x = in.radius - i;
			int y = 0;

			int decisionOver2 = 1 - x;   // Decision criterion divided by 2 evaluated at x=r, y=0
			const auto x0 = size.x / 2;
			const auto y0 = size.y / 2;

			while (y <= x)
			{
				pp(x + x0, y + y0); // Octant 1
				pp(y + x0, x + y0); // Octant 2
				pp(-x + x0, y + y0); // Octant 4
				pp(-y + x0, x + y0); // Octant 3
				pp(-x + x0, -y + y0); // Octant 5
				pp(-y + x0, -x + y0); // Octant 6
				pp(x + x0, -y + y0); // Octant 7
				pp(y + x0, -x + y0); // Octant 8
				y++;

				if (decisionOver2 <= 0) {
					decisionOver2 += 2 * y + 1;   // Change in decision criterion for y -> y+1
				}
				else {
					decisionOver2 += 2 * (y - (--x)) + 1;   // Change for y -> y+1, x -> x-1
				}
			}
		}

		if (in.border_width > 1) {
			for (unsigned y = 0; y < surface.size.x; ++y) {
				for (unsigned x = 0; x < surface.size.x; ++x) {
					if (x > 0 && y > 0 && x < surface.size.x - 1 && y < surface.size.y - 1) {
						if (surface.pixel({ x, y }).a == 0 &&
							surface.pixel({x + 1, y}).a > 0 &&
							surface.pixel({x - 1, y}).a > 0 &&
							surface.pixel({x, y + 1}).a > 0 &&
							surface.pixel({x, y - 1}).a > 0)
							pp(x, y);
					}
				}
			}
		}

		if (&surface != this) {
			blit(
				surface,
				{ 0u, 0u },
				false,
				true
			);
		}
	}

	void image::execute(
		const paint_circle_filled_command& in
	) {
		const auto side = in.radius * 2 + 1;

		if (v.empty()) {
			resize_fill({ side, side });
		}
		else {
			ensure(size.x >= side);
			ensure(size.y >= side);
		}

		for (unsigned y = 0; y < size.y; ++y) {
			for (unsigned x = 0; x < size.x; ++x) {
				const auto x_center = static_cast<signed>(x - size.x / 2);
				const auto y_center = static_cast<signed>(y - size.y / 2);

				if (x_center*x_center + y_center*y_center <= static_cast<int>(in.radius*in.radius)) {
					pixel({ x, y }) = in.filling;
				}
			}
		}

		//pixel(side / 2, 0) = rgba(0, 0, 0, 0);
		//pixel(side / 2, side -1) = rgba(0, 0, 0, 0);
		//pixel(0, side /2) = rgba(0, 0, 0, 0);
		//pixel(side -1, side /2) = rgba(0, 0, 0, 0);
	}

	void image::execute(
		const paint_line_command& in
	) {
		Line(in.from.x, in.from.y, in.to.x, in.to.y, [&](const int x, const int y) {
			const auto pos = vec2u(x, y);

			ensure(in_bounds(pos));
			pixel(pos) = in.filling;
		});
	}

	void image::swap_red_and_blue() {
		for (auto& p : v) {
			std::swap(p.r, p.b);
		}
	}

	void image::save(const path_type& path) const {
		const auto extension = path.extension();

		if (extension == ".png") {
			save_as_png(path);
		}
		else if (extension == ".bin") {
			save_as_binary_file(path);
		}
		else {
			LOG("Warning: %x has unknown extension: %x! Saving as binary.", path, extension);
			save_as_binary_file(path);
		}
	}

	void image::save_as_png(const path_type& path) const {
		augs::create_directories_for(path);

		if (
			const auto lodepng_result =
			lodepng::encode(path.string(), *reinterpret_cast<const std::vector<unsigned char>*>(&v), size.x, size.y)
		) {
			LOG("Failed to save %x: lodepng returned %x. Ensure that the target directory exists.", path, lodepng_result);
		}
	}

	void image::save_as_binary_file(const path_type& path) const {
		augs::create_directories_for(path);

		std::ofstream out(path, std::ios::out | std::ios::binary);
		augs::write_bytes(out, size);
		augs::write_bytes(out, v);
	}

	void image::fill(const rgba col) {
		for (auto& p : v) {
			p = col;
		}
	}

	void image::blit(
		const image& source_image,
		const vec2u dst,
		const bool flip_source,
		const bool add_rgba_values
	) {
		const auto source_size = source_image.get_size();

		if (!add_rgba_values) {
			if (flip_source) {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ y, x }) = source_image.pixel(vec2u{ x, y });
					}
				}
			}
			else {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ x, y }) = source_image.pixel(vec2u{ x, y });
					}
				}
			}
		}
		else {
			if (flip_source) {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ y, x }) += source_image.pixel(vec2u{ x, y });
					}
				}
			}
			else {
				for (auto y = 0u; y < source_size.y; ++y) {
					for (auto x = 0u; x < source_size.x; ++x) {
						pixel(dst + vec2u{ x, y }) += source_image.pixel(vec2u{ x, y });
					}
				}
			}
		}
	}

	image& image::desaturate() {
		for (unsigned y = 0; y < size.y; ++y) {
			for (unsigned x = 0; x < size.x; ++x) {
				pixel({ x, y }).desaturate();
			}
		}

		return *this;
	}
}

<|endoftext|>


<commit_before>// Copyright 2015 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <bsoncxx/document/view_or_value.hpp>
#include <bsoncxx/stdx/optional.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/validation_criteria.hpp>

#include <mongocxx/config/prelude.hpp>

namespace mongocxx {
MONGOCXX_INLINE_NAMESPACE_BEGIN
namespace options {

///
/// Class representing the optional arguments to a MongoDB createCollection command
///
class MONGOCXX_API create_collection {
   public:
    ///
    /// Specify false to disable the automatic creation of an index on the _id field.
    ///
    /// @note For replica sets, all collections must have autoIndexId set to true.
    ///
    /// @param auto_index_id
    ///   Whether or not this collection will automatically generate an index on _id.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& auto_index_id(bool auto_index_id);

    ///
    /// Gets the current auto_index_id setting.
    ///
    /// @return
    ///   Whether or not this collection will automatically generate an index on _id.
    ///
    const stdx::optional<bool>& auto_index_id() const;

    ///
    /// To create a capped collection, specify true.
    ///
    /// @note If you specify true, you must also set a maximum size using the size() method.
    ///
    /// @param capped
    ///   Whether or not this collection will be capped.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see https://docs.mongodb.com/master/reference/glossary/#term-capped-collection
    ///
    create_collection& capped(bool capped);

    ///
    /// Gets the current capped setting.
    ///
    /// @return
    ///   Whether or not this collection will be capped.
    ///
    /// @see https://docs.mongodb.com/master/reference/glossary/#term-capped-collection
    ///
    const stdx::optional<bool>& capped() const;

    ///
    /// Sets the default collation for this collection.
    ///
    /// @param collation
    ///   The default collation for the collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see
    ///   https://docs.mongodb.com/master/reference/collation/
    ///
    create_collection& collation(bsoncxx::document::view_or_value collation);

    ///
    /// Gets the default collation for this collection.
    ///
    /// @return
    ///   The default collation for the collection.
    ///
    /// @see
    ///   https://docs.mongodb.com/master/reference/collation/
    ///
    const stdx::optional<bsoncxx::document::view_or_value>& collation() const;

    ///
    /// The maximum number of documents allowed in the capped collection.
    ///
    /// @note The size limit takes precedence over this limit. If a capped collection reaches
    ///   the size limit before it reaches the maximum number of documents, MongoDB removes
    ///   old documents.
    ///
    /// @param max_documents
    ///   Maximum number of documents allowed in the collection (if capped).
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& max(int max_documents);

    ///
    /// Gets the current setting for the maximum number of documents allowed in the capped
    /// collection.
    ///
    /// @return
    ///   Maximum number of documents allowed in the collection (if capped).
    ///
    const stdx::optional<int>& max() const;

    ///
    /// When true, disables the power of 2 sizes allocation for the collection.
    ///
    /// @see https://docs.mongodb.com/master/reference/command/create/
    ///
    /// @param no_padding
    ///   When true, disables power of 2 sizing for this collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& no_padding(bool no_padding);

    ///
    /// Gets the current value of the "no padding" option for the collection.
    ///
    /// @see https://docs.mongodb.com/master/reference/command/create/
    ///
    /// @return
    ///   When true, power of 2 sizing is disabled for this collection.
    ///
    const stdx::optional<bool>& no_padding() const;

    ///
    /// A maximum size, in bytes, for a capped collection.
    ///
    /// @note Once a capped collection reaches its maximum size, MongoDB removes older
    ///   documents to make space for new documents.
    ///
    /// @note Size is required for capped collections and ignored for other collections.
    ///
    /// @param max_size
    ///   Maximum size, in bytes, of this collection (if capped).
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& size(int max_size);

    ///
    /// Gets the current size setting, for a capped collection.
    ///
    /// @return
    ///   Maximum size, in bytes, of this collection (if capped).
    ///
    const stdx::optional<int>& size() const;

    ///
    /// Specify configuration to the storage on a per-collection basis.
    ///
    /// @note This option is currently only available with the WiredTiger storage engine.
    ///
    /// @param storage_engine_options
    ///   Configuration options specific to the storage engine.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& storage_engine(bsoncxx::document::view_or_value storage_engine_opts);

    ///
    /// Gets the current storage engine configuration for this collection.
    ///
    /// @return
    ///   Configuration options specific to the storage engine.
    ///
    const stdx::optional<bsoncxx::document::view_or_value>& storage_engine() const;

    ///
    /// Specify validation criteria for this collection.
    ///
    /// @param validation
    ///   Validation criteria for this collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see https://docs.mongodb.com/master/core/document-validation/
    ///
    create_collection& validation_criteria(class validation_criteria validation);

    ///
    /// Gets the current validation criteria for this collection.
    ///
    /// @return
    ///   Validation criteria for this collection.
    ///
    /// @see https://docs.mongodb.com/master/core/document-validation/
    ///
    const stdx::optional<class validation_criteria>& validation_criteria() const;

    ///
    /// Return a bson document representing the options set on this object.
    ///
    /// @deprecated
    ///   This method is deprecated. To determine which options are set on this object, use the
    ///   provided accessors instead.
    ///
    /// @return Options, as a document.
    ///
    bsoncxx::document::value to_document() const;

    ///
    /// @deprecated
    ///   This method is deprecated. To determine which options are set on this object, use the
    ///   provided accessors instead.
    ///
    MONGOCXX_INLINE operator bsoncxx::document::value() const;

   private:
    stdx::optional<bool> _auto_index_id;
    stdx::optional<bool> _capped;
    stdx::optional<bsoncxx::document::view_or_value> _collation;
    stdx::optional<int> _max_documents;
    stdx::optional<int> _max_size;
    stdx::optional<bool> _no_padding;
    stdx::optional<bsoncxx::document::view_or_value> _storage_engine_opts;
    stdx::optional<class validation_criteria> _validation;
};

MONGOCXX_INLINE create_collection::operator bsoncxx::document::value() const {
    return to_document();
}

}  // namespace options
MONGOCXX_INLINE_NAMESPACE_END
}  // namespace mongocxx

#include <mongocxx/config/postlude.hpp>
<commit_msg>CXX-1080 Document autoIndexId as deprecated<commit_after>// Copyright 2015 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <bsoncxx/document/view_or_value.hpp>
#include <bsoncxx/stdx/optional.hpp>
#include <mongocxx/stdx.hpp>
#include <mongocxx/validation_criteria.hpp>

#include <mongocxx/config/prelude.hpp>

namespace mongocxx {
MONGOCXX_INLINE_NAMESPACE_BEGIN
namespace options {

///
/// Class representing the optional arguments to a MongoDB createCollection command
///
class MONGOCXX_API create_collection {
   public:
    ///
    /// Specify false to disable the automatic creation of an index on the _id field.
    ///
    /// @deprecated
    ///   This method is deprecated. Server versions 3.4 and above no longer support the
    ///   "autoIndexId" option.
    ///
    /// @note For replica sets, all collections must have autoIndexId set to true.
    ///
    /// @param auto_index_id
    ///   Whether or not this collection will automatically generate an index on _id.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& auto_index_id(bool auto_index_id);

    ///
    /// Gets the current auto_index_id setting.
    ///
    /// @return
    ///   Whether or not this collection will automatically generate an index on _id.
    ///
    const stdx::optional<bool>& auto_index_id() const;

    ///
    /// To create a capped collection, specify true.
    ///
    /// @note If you specify true, you must also set a maximum size using the size() method.
    ///
    /// @param capped
    ///   Whether or not this collection will be capped.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see https://docs.mongodb.com/master/reference/glossary/#term-capped-collection
    ///
    create_collection& capped(bool capped);

    ///
    /// Gets the current capped setting.
    ///
    /// @return
    ///   Whether or not this collection will be capped.
    ///
    /// @see https://docs.mongodb.com/master/reference/glossary/#term-capped-collection
    ///
    const stdx::optional<bool>& capped() const;

    ///
    /// Sets the default collation for this collection.
    ///
    /// @param collation
    ///   The default collation for the collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see
    ///   https://docs.mongodb.com/master/reference/collation/
    ///
    create_collection& collation(bsoncxx::document::view_or_value collation);

    ///
    /// Gets the default collation for this collection.
    ///
    /// @return
    ///   The default collation for the collection.
    ///
    /// @see
    ///   https://docs.mongodb.com/master/reference/collation/
    ///
    const stdx::optional<bsoncxx::document::view_or_value>& collation() const;

    ///
    /// The maximum number of documents allowed in the capped collection.
    ///
    /// @note The size limit takes precedence over this limit. If a capped collection reaches
    ///   the size limit before it reaches the maximum number of documents, MongoDB removes
    ///   old documents.
    ///
    /// @param max_documents
    ///   Maximum number of documents allowed in the collection (if capped).
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& max(int max_documents);

    ///
    /// Gets the current setting for the maximum number of documents allowed in the capped
    /// collection.
    ///
    /// @return
    ///   Maximum number of documents allowed in the collection (if capped).
    ///
    const stdx::optional<int>& max() const;

    ///
    /// When true, disables the power of 2 sizes allocation for the collection.
    ///
    /// @see https://docs.mongodb.com/master/reference/command/create/
    ///
    /// @param no_padding
    ///   When true, disables power of 2 sizing for this collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& no_padding(bool no_padding);

    ///
    /// Gets the current value of the "no padding" option for the collection.
    ///
    /// @see https://docs.mongodb.com/master/reference/command/create/
    ///
    /// @return
    ///   When true, power of 2 sizing is disabled for this collection.
    ///
    const stdx::optional<bool>& no_padding() const;

    ///
    /// A maximum size, in bytes, for a capped collection.
    ///
    /// @note Once a capped collection reaches its maximum size, MongoDB removes older
    ///   documents to make space for new documents.
    ///
    /// @note Size is required for capped collections and ignored for other collections.
    ///
    /// @param max_size
    ///   Maximum size, in bytes, of this collection (if capped).
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& size(int max_size);

    ///
    /// Gets the current size setting, for a capped collection.
    ///
    /// @return
    ///   Maximum size, in bytes, of this collection (if capped).
    ///
    const stdx::optional<int>& size() const;

    ///
    /// Specify configuration to the storage on a per-collection basis.
    ///
    /// @note This option is currently only available with the WiredTiger storage engine.
    ///
    /// @param storage_engine_options
    ///   Configuration options specific to the storage engine.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    create_collection& storage_engine(bsoncxx::document::view_or_value storage_engine_opts);

    ///
    /// Gets the current storage engine configuration for this collection.
    ///
    /// @return
    ///   Configuration options specific to the storage engine.
    ///
    const stdx::optional<bsoncxx::document::view_or_value>& storage_engine() const;

    ///
    /// Specify validation criteria for this collection.
    ///
    /// @param validation
    ///   Validation criteria for this collection.
    ///
    /// @return
    ///   A reference to the object on which this member function is being called.  This facilitates
    ///   method chaining.
    ///
    /// @see https://docs.mongodb.com/master/core/document-validation/
    ///
    create_collection& validation_criteria(class validation_criteria validation);

    ///
    /// Gets the current validation criteria for this collection.
    ///
    /// @return
    ///   Validation criteria for this collection.
    ///
    /// @see https://docs.mongodb.com/master/core/document-validation/
    ///
    const stdx::optional<class validation_criteria>& validation_criteria() const;

    ///
    /// Return a bson document representing the options set on this object.
    ///
    /// @deprecated
    ///   This method is deprecated. To determine which options are set on this object, use the
    ///   provided accessors instead.
    ///
    /// @return Options, as a document.
    ///
    bsoncxx::document::value to_document() const;

    ///
    /// @deprecated
    ///   This method is deprecated. To determine which options are set on this object, use the
    ///   provided accessors instead.
    ///
    MONGOCXX_INLINE operator bsoncxx::document::value() const;

   private:
    stdx::optional<bool> _auto_index_id;
    stdx::optional<bool> _capped;
    stdx::optional<bsoncxx::document::view_or_value> _collation;
    stdx::optional<int> _max_documents;
    stdx::optional<int> _max_size;
    stdx::optional<bool> _no_padding;
    stdx::optional<bsoncxx::document::view_or_value> _storage_engine_opts;
    stdx::optional<class validation_criteria> _validation;
};

MONGOCXX_INLINE create_collection::operator bsoncxx::document::value() const {
    return to_document();
}

}  // namespace options
MONGOCXX_INLINE_NAMESPACE_END
}  // namespace mongocxx

#include <mongocxx/config/postlude.hpp>
<|endoftext|>


<commit_before>#include "stdafx.h"

#include "Ogre_glTF_materialLoader.hpp"
#include "Ogre_glTF_textureImporter.hpp"
#include "Ogre_glTF_common.hpp"
#include <OgreHlmsPbsDatablock.h>
#include <OgreHlms.h>
#include <OgreHlmsManager.h>
#include <OgreLogManager.h>
#include "Ogre_glTF_internal_utils.hpp"

using namespace Ogre_glTF;

Ogre::Vector3 materialLoader::convertColor(const tinygltf::ColorValue& color)
{
	std::array<float, 4> colorBuffer{};
	internal_utils::container_double_to_float(color, colorBuffer);
	return Ogre::Vector3 { colorBuffer.data() };
}

void materialLoader::setBaseColor(Ogre::HlmsPbsDatablock* block, Ogre::Vector3 color) const
{
	block->setDiffuse(color);
}

void materialLoader::setMetallicValue(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setMetalness(value);
}

void materialLoader::setRoughnesValue(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setRoughness(value);
}

void materialLoader::setEmissiveColor(Ogre::HlmsPbsDatablock* block, Ogre::Vector3 color) const
{
	block->setEmissive(color);
}

bool materialLoader::isTextureIndexValid(int value) const
{
	return !(value < 0);
}

void materialLoader::setBaseColorTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("diffuse texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_DIFFUSE, 0, texture);
	}
}

void materialLoader::setMetalRoughTexture(Ogre::HlmsPbsDatablock* block, int gltfTextureID) const
{
	if(!isTextureIndexValid(gltfTextureID)) return;
	//Ogre cannot use combined metal rough textures. Metal is in the R channel, and rough in the G channel. It seems that the images are loaded as BGR by the libarry
	//R channel is channel 2 (from 0), G channel is 1.

	auto metalTexure = textureImporterRef.generateGreyScaleFromChannel(gltfTextureID, 2);
	auto roughTexure = textureImporterRef.generateGreyScaleFromChannel(gltfTextureID, 1);

	if(metalTexure)
	{
		//OgreLog("metalness grey-scale texture extracted by textureImporter : " + metalTexure->getName());
		block->setTexture(Ogre::PBSM_METALLIC, 0, metalTexure);
	}

	if(roughTexure)
	{
		//OgreLog("roughness grey-scale texture extracted by textureImporter : " + roughTexure->getName());
		block->setTexture(Ogre::PBSM_ROUGHNESS, 0, roughTexure);
	}
}

void materialLoader::setNormalTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getNormalSNORM(value);
	if(texture)
	{
		//OgreLog("normal texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_NORMAL, 0, texture);
	}
}

void materialLoader::setOcclusionTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("occlusion texture from textureImporter : " + texture->getName());
		//OgreLog("Warning: Ogre doesn't support occlusion map in it's HLMS PBS implementation!");
		//block->setTexture(Ogre::PbsTextureTypes::PBSM_, 0, texture);
	}
}

void materialLoader::setEmissiveTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("emissive texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_EMISSIVE, 0, texture);
	}
}

void materialLoader::setAlphaMode(Ogre::HlmsPbsDatablock* block, const std::string& mode) const
{
	if(mode == "BLEND")
	{
		auto blendBlock = *block->getBlendblock();
		blendBlock.setBlendType(Ogre::SBT_TRANSPARENT_ALPHA);
		block->setBlendblock(blendBlock);
	}
	else if(mode =="MASK")
	{
		block->setAlphaTest( Ogre::CMPF_GREATER_EQUAL );
	}
}

void materialLoader::setAlphaCutoff(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setAlphaTestThreshold(value);
}

materialLoader::materialLoader(tinygltf::Model& input, textureImporter& textureInterface) :
	textureImporterRef(textureInterface),
	model(input)
{
}

Ogre::HlmsDatablock* materialLoader::getDatablock(size_t index) const
{
	//OgreLog("Loading material...");
	//TODO this will need some modification if we support multiple meshes by glTF file
	auto HlmsPbs			 = static_cast<Ogre::HlmsPbs*>(Ogre::Root::getSingleton().getHlmsManager()->getHlms(Ogre::HlmsTypes::HLMS_PBS));
	//const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0);
	//const auto& mesh		 = model.meshes[mainMeshIndex];
	//const auto material    = model.materials[mesh.primitives.at(index).material];
    const auto material		 = model.materials[index];

    std::string mtlName = material.name + "_" + std::to_string(index);
	auto datablock = static_cast<Ogre::HlmsPbsDatablock*>(HlmsPbs->getDatablock(Ogre::IdString(mtlName)));
	if(datablock)
	{
		//OgreLog("Found HlmsPbsDatablock " + material.name + " in Ogre::HlmsPbs");
		return datablock;
	}
    datablock = static_cast<Ogre::HlmsPbsDatablock*>(HlmsPbs->createDatablock(Ogre::IdString(mtlName),
																			  mtlName,
																			  Ogre::HlmsMacroblock(),
																			  Ogre::HlmsBlendblock(),
																			  Ogre::HlmsParamVec()));
	datablock->setWorkflow(Ogre::HlmsPbsDatablock::Workflows::MetallicWorkflow);

	//OgreLog("Create HlmsPbsDatablock " + mtlName);
	//TODO refactor these almost exact pieces of code
	for (const auto& content : material.values)
	{
		//OgreLog(content.first);
        if (content.first == "baseColorTexture")
            setBaseColorTexture(datablock, content.second.TextureIndex());

		if (content.first == "metallicRoughnessTexture")
			setMetalRoughTexture(datablock, content.second.TextureIndex());

        if (content.first == "baseColorFactor")
        {
            setBaseColor(datablock, convertColor(content.second.ColorFactor()));
            float alpha = content.second.number_array[3];
            if (alpha > 0.9999)
            {
                datablock->setTransparency(alpha, Ogre::HlmsPbsDatablock::None);
            }
            else
            {
                datablock->setTransparency(alpha, Ogre::HlmsPbsDatablock::Transparent);
            }
        }

		if (content.first == "metallicFactor")
			setMetallicValue(datablock, static_cast<float>(content.second.Factor()));

		if (content.first == "roughnessFactor")
			setRoughnesValue(datablock, static_cast<float>(content.second.Factor()));
	}

	//OgreLog("additionalValues");
	for (const auto& content : material.additionalValues)
	{
		//OgreLog(content.first);
		if(content.first == "normalTexture")
			setNormalTexture(datablock, content.second.TextureIndex());

		//if (content.first == "occlusionTexture")
		//	setOcclusionTexture(datablock, getTextureIndex(content));

		if(content.first == "emissiveTexture")
			setEmissiveTexture(datablock, content.second.TextureIndex());

		if(content.first == "emissiveFactor")
			setEmissiveColor(datablock, convertColor(content.second.ColorFactor()));

		if(content.first == "alphaMode")
			setAlphaMode(datablock, content.second.string_value);

		if(content.first == "alphaCutoff")
			setAlphaCutoff(datablock, static_cast<Ogre::Real>(content.second.number_value));
	}

	//	OgreLog("extCommonValues");
	//	for(const auto& content : material.extCommonValues)
	//		OgreLog(content.first);

	//	OgreLog("extPBRValues");
	//	for(const auto& content : material.extPBRValues)
	//		OgreLog(content.first);
    auto hlmsTextureManager = Ogre::Root::getSingleton().getHlmsManager()->getTextureManager();
    if (datablock->getTexture(Ogre::PBSM_REFLECTION).isNull())
    {
        auto envMap = hlmsTextureManager->createOrRetrieveTexture("env.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_ENV_MAP);
        datablock->setTexture(Ogre::PBSM_REFLECTION, envMap.xIdx, envMap.texture);
    }
	return datablock;
}

size_t materialLoader::getDatablockCount() const //todo this could use some refactoring. This information is actually fetched like, twice.
{
	const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0);
	const auto& mesh = model.meshes[mainMeshIndex];
	return mesh.primitives.size();
}
<commit_msg>Code cleanup<commit_after>#include "stdafx.h"

#include "Ogre_glTF_materialLoader.hpp"
#include "Ogre_glTF_textureImporter.hpp"
#include "Ogre_glTF_common.hpp"
#include <OgreHlmsPbsDatablock.h>
#include <OgreHlms.h>
#include <OgreHlmsManager.h>
#include <OgreLogManager.h>
#include "Ogre_glTF_internal_utils.hpp"

using namespace Ogre_glTF;

Ogre::Vector3 materialLoader::convertColor(const tinygltf::ColorValue& color)
{
	std::array<float, 4> colorBuffer{};
	internal_utils::container_double_to_float(color, colorBuffer);
	return Ogre::Vector3 { colorBuffer.data() };
}

void materialLoader::setBaseColor(Ogre::HlmsPbsDatablock* block, Ogre::Vector3 color) const
{
	block->setDiffuse(color);
}

void materialLoader::setMetallicValue(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setMetalness(value);
}

void materialLoader::setRoughnesValue(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setRoughness(value);
}

void materialLoader::setEmissiveColor(Ogre::HlmsPbsDatablock* block, Ogre::Vector3 color) const
{
	block->setEmissive(color);
}

bool materialLoader::isTextureIndexValid(int value) const
{
	return !(value < 0);
}

void materialLoader::setBaseColorTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("diffuse texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_DIFFUSE, 0, texture);
	}
}

void materialLoader::setMetalRoughTexture(Ogre::HlmsPbsDatablock* block, int gltfTextureID) const
{
	if(!isTextureIndexValid(gltfTextureID)) return;
	//Ogre cannot use combined metal rough textures. Metal is in the R channel, and rough in the G channel. It seems that the images are loaded as BGR by the libarry
	//R channel is channel 2 (from 0), G channel is 1.

	auto metalTexure = textureImporterRef.generateGreyScaleFromChannel(gltfTextureID, 2);
	auto roughTexure = textureImporterRef.generateGreyScaleFromChannel(gltfTextureID, 1);

	if(metalTexure)
	{
		//OgreLog("metalness grey-scale texture extracted by textureImporter : " + metalTexure->getName());
		block->setTexture(Ogre::PBSM_METALLIC, 0, metalTexure);
	}

	if(roughTexure)
	{
		//OgreLog("roughness grey-scale texture extracted by textureImporter : " + roughTexure->getName());
		block->setTexture(Ogre::PBSM_ROUGHNESS, 0, roughTexure);
	}
}

void materialLoader::setNormalTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getNormalSNORM(value);
	if(texture)
	{
		//OgreLog("normal texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_NORMAL, 0, texture);
	}
}

void materialLoader::setOcclusionTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("occlusion texture from textureImporter : " + texture->getName());
		//OgreLog("Warning: Ogre doesn't support occlusion map in it's HLMS PBS implementation!");
		//block->setTexture(Ogre::PbsTextureTypes::PBSM_, 0, texture);
	}
}

void materialLoader::setEmissiveTexture(Ogre::HlmsPbsDatablock* block, int value) const
{
	if(!isTextureIndexValid(value)) return;
	auto texture = textureImporterRef.getTexture(value);
	if(texture)
	{
		//OgreLog("emissive texture from textureImporter : " + texture->getName());
		block->setTexture(Ogre::PbsTextureTypes::PBSM_EMISSIVE, 0, texture);
	}
}

void materialLoader::setAlphaMode(Ogre::HlmsPbsDatablock* block, const std::string& mode) const
{
	if(mode == "BLEND")
	{
		auto blendBlock = *block->getBlendblock();
		blendBlock.setBlendType(Ogre::SBT_TRANSPARENT_ALPHA);
		block->setBlendblock(blendBlock);
	}
	else if(mode =="MASK")
	{
		block->setAlphaTest( Ogre::CMPF_GREATER_EQUAL );
	}
}

void materialLoader::setAlphaCutoff(Ogre::HlmsPbsDatablock* block, Ogre::Real value) const
{
	block->setAlphaTestThreshold(value);
}

materialLoader::materialLoader(tinygltf::Model& input, textureImporter& textureInterface) :
	textureImporterRef(textureInterface),
	model(input)
{
}

Ogre::HlmsDatablock* materialLoader::getDatablock(size_t index) const
{
	//OgreLog("Loading material...");
	//TODO this will need some modification if we support multiple meshes by glTF file
	auto HlmsPbs			 = static_cast<Ogre::HlmsPbs*>(Ogre::Root::getSingleton().getHlmsManager()->getHlms(Ogre::HlmsTypes::HLMS_PBS));
	//const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0);
	//const auto& mesh		 = model.meshes[mainMeshIndex];
	//const auto material    = model.materials[mesh.primitives.at(index).material];
    const auto material		 = model.materials[index];

    std::string mtlName = material.name + "_" + std::to_string(index);
	auto datablock = static_cast<Ogre::HlmsPbsDatablock*>(HlmsPbs->getDatablock(Ogre::IdString(mtlName)));
	if(datablock)
	{
		//OgreLog("Found HlmsPbsDatablock " + material.name + " in Ogre::HlmsPbs");
		return datablock;
	}
    datablock = static_cast<Ogre::HlmsPbsDatablock*>(HlmsPbs->createDatablock(Ogre::IdString(mtlName),
																			  mtlName,
																			  Ogre::HlmsMacroblock(),
																			  Ogre::HlmsBlendblock(),
																			  Ogre::HlmsParamVec()));
	datablock->setWorkflow(Ogre::HlmsPbsDatablock::Workflows::MetallicWorkflow);

	//OgreLog("Create HlmsPbsDatablock " + mtlName);
	//TODO refactor these almost exact pieces of code
	for (const auto& content : material.values)
	{
		//OgreLog(content.first);
        if (content.first == "baseColorTexture")
            setBaseColorTexture(datablock, content.second.TextureIndex());

		if (content.first == "metallicRoughnessTexture")
			setMetalRoughTexture(datablock, content.second.TextureIndex());

        if (content.first == "baseColorFactor")
        {
            setBaseColor(datablock, convertColor(content.second.ColorFactor()));

            // Need to set the alpha channel separately
            float alpha = content.second.number_array[3];
            auto transparentMode = (alpha > 0.99) ? Ogre::HlmsPbsDatablock::None : Ogre::HlmsPbsDatablock::Transparent;
            datablock->setTransparency(alpha, transparentMode);
        }

		if (content.first == "metallicFactor")
			setMetallicValue(datablock, static_cast<float>(content.second.Factor()));

		if (content.first == "roughnessFactor")
			setRoughnesValue(datablock, static_cast<float>(content.second.Factor()));
	}

	//OgreLog("additionalValues");
	for (const auto& content : material.additionalValues)
	{
		//OgreLog(content.first);
		if(content.first == "normalTexture")
			setNormalTexture(datablock, content.second.TextureIndex());

		//if (content.first == "occlusionTexture")
		//	setOcclusionTexture(datablock, getTextureIndex(content));

		if(content.first == "emissiveTexture")
			setEmissiveTexture(datablock, content.second.TextureIndex());

		if(content.first == "emissiveFactor")
			setEmissiveColor(datablock, convertColor(content.second.ColorFactor()));

		if(content.first == "alphaMode")
			setAlphaMode(datablock, content.second.string_value);

		if(content.first == "alphaCutoff")
			setAlphaCutoff(datablock, static_cast<Ogre::Real>(content.second.number_value));
	}

	//	OgreLog("extCommonValues");
	//	for(const auto& content : material.extCommonValues)
	//		OgreLog(content.first);

	//	OgreLog("extPBRValues");
	//	for(const auto& content : material.extPBRValues)
	//		OgreLog(content.first);
    auto hlmsTextureManager = Ogre::Root::getSingleton().getHlmsManager()->getTextureManager();
    if (datablock->getTexture(Ogre::PBSM_REFLECTION).isNull())
    {
        auto envMap = hlmsTextureManager->createOrRetrieveTexture("env.dds", Ogre::HlmsTextureManager::TEXTURE_TYPE_ENV_MAP);
        datablock->setTexture(Ogre::PBSM_REFLECTION, envMap.xIdx, envMap.texture);
    }
	return datablock;
}

size_t materialLoader::getDatablockCount() const //todo this could use some refactoring. This information is actually fetched like, twice.
{
	const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0);
	const auto& mesh = model.meshes[mainMeshIndex];
	return mesh.primitives.size();
}
<|endoftext|>