<commit_before>/*
 *  soundpicker.cpp  -  widget to select a sound file or a beep
 *  Program:  kalarm
 *  (C) 2002, 2004 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give permission
 *  to link the code of this program with any edition of the Qt library by
 *  Trolltech AS, Norway (or with modified versions of Qt that use the same
 *  license as Qt), and distribute linked combinations including the two.
 *  You must obey the GNU General Public License in all respects for all of
 *  the code used other than Qt.  If you modify this file, you may extend
 *  this exception to your version of the file, but you are not obligated to
 *  do so. If you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "kalarm.h"

#include <qlayout.h>
#include <qregexp.h>
#include <qtooltip.h>
#include <qwhatsthis.h>

#include <kglobal.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <arts/kplayobjectfactory.h>

#include "checkbox.h"
#include "pushbutton.h"
#include "soundpicker.moc"

// Collect these widget labels together to ensure consistent wording and
// translations across different modules.
QString SoundPicker::i18n_Sound()       { return i18n("An audio sound", "Sound"); }
QString SoundPicker::i18n_s_Sound()     { return i18n("An audio sound", "&Sound"); }
QString SoundPicker::i18n_SetVolume()   { return i18n("Set volume"); }
QString SoundPicker::i18n_v_SetVolume() { return i18n("Set &volume"); }
QString SoundPicker::i18n_Repeat()      { return i18n("Repeat"); }
QString SoundPicker::i18n_p_Repeat()    { return i18n("Re&peat"); }

SoundPicker::SoundPicker(QWidget* parent, const char* name)
	: QFrame(parent, name)
{
	// Sound checkbox
	setFrameStyle(QFrame::NoFrame);
	QHBoxLayout* soundLayout = new QHBoxLayout(this, 0, 2*KDialog::spacingHint());
	soundLayout->setAlignment(Qt::AlignVCenter);
	mCheckbox = new CheckBox(i18n_s_Sound(), this);
	mCheckbox->setFixedSize(mCheckbox->sizeHint());
	connect(mCheckbox, SIGNAL(toggled(bool)), SLOT(slotSoundToggled(bool)));
	QWhatsThis::add(mCheckbox,
	      i18n("If checked, a sound will be played when the message is displayed. Click the "
	           "button on the right to select the sound."));
	soundLayout->addWidget(mCheckbox);

	// Sound file picker button
	mFilePicker = new PushButton(this);
	mFilePicker->setPixmap(SmallIcon("playsound"));
	mFilePicker->setFixedSize(mFilePicker->sizeHint());
	mFilePicker->setToggleButton(true);
	connect(mFilePicker, SIGNAL(clicked()), SLOT(slotPickFile()));
	QWhatsThis::add(mFilePicker,
	      i18n("Select a sound file to play when the message is displayed. If no sound file is "
	           "selected, a beep will sound."));
	soundLayout->addWidget(mFilePicker);

	// Sound repetition checkbox
	mRepeatCheckbox = new CheckBox(i18n_p_Repeat(), this);
	mRepeatCheckbox->setFixedSize(mRepeatCheckbox->sizeHint());
	QWhatsThis::add(mRepeatCheckbox,
	      i18n("If checked, the sound file will be played repeatedly for as long as the message is displayed."));
	soundLayout->addWidget(mRepeatCheckbox);
#ifdef WITHOUT_ARTS
	mRepeatCheckbox->hide();
#endif

#ifdef SOUNDPICKER_VOLUME
	// Set volume checkbox
	mVolumeCheckbox = new CheckBox(i18n_v_SetVolume(), this);
	mVolumeCheckbox->setFixedSize(mVolumeCheckbox->sizeHint());
	connect(mVolumeCheckbox, SIGNAL(toggled(bool)), SLOT(slotVolumeToggled(bool)));
	QWhatsThis::add(mVolumeCheckbox,
	      i18n("Select to choose the volume for playing the sound file."));
	soundLayout->addWidget(mVolumeCheckbox);

	// Volume slider
	mVolumeSlider = new Slider(0, 100, 10, 0, Qt::Horizontal, this);
	mVolumeSlider->setFixedSize(mVolumeSlider->sizeHint());
	QWhatsThis::add(mVolumeSlider,
	      i18n("Choose the volume for playing the sound file."));
	mVolumeCheckbox->setFocusWidget(mVolumeSlider);
	soundLayout->addWidget(mVolumeSlider);
#endif
	soundLayout->addStretch();

	// Initialise the file picker button state and tooltip
	slotSoundToggled(false);
}

/******************************************************************************
 * Set the read-only status of the widget.
 */
void SoundPicker::setReadOnly(bool readOnly)
{
	mCheckbox->setReadOnly(readOnly);
	mFilePicker->setReadOnly(readOnly);
	mRepeatCheckbox->setReadOnly(readOnly);
}

/******************************************************************************
 * Return whether beep is selected.
 */
bool SoundPicker::beep() const
{
	return mCheckbox->isChecked()  &&  !mFilePicker->isOn();
}

/******************************************************************************
 * Return the selected sound file, if the main checkbox is checked.
 * Returns null string if beep is currently selected.
 */
QString SoundPicker::file() const
{
	return mCheckbox->isChecked() && mFilePicker->isOn() ? mFile : QString::null;
}

/******************************************************************************
 * Return whether sound file repetition is selected, if the main checkbox is checked.
 * Returns false if beep is currently selected.
 */
bool SoundPicker::repeat() const
{
	return mCheckbox->isChecked() && mFilePicker->isOn() && !mFile.isEmpty() && mRepeatCheckbox->isChecked();
}

/******************************************************************************
 * Return whether repetition is selected, regardless of the current beep and
 * file settings.
 */
bool SoundPicker::repeatSetting() const
{
	return mRepeatCheckbox->isChecked();
}

/******************************************************************************
 * Initialise the widget's state.
 */
void SoundPicker::set(bool beep, const QString& f, bool repeat)
{
	mCheckbox->setChecked(beep || !f.isEmpty());
	mFile = f;
	mRepeatCheckbox->setChecked(repeat);
	mFilePicker->setOn(!beep  &&  !f.isEmpty());
	setFilePicker();
}

/******************************************************************************
 * Set sound on or off.
 */
void SoundPicker::setChecked(bool on)
{
	mCheckbox->setChecked(on);
}

/******************************************************************************
 * Set the current beep status.
 */
void SoundPicker::setBeep(bool beep)
{
	mFilePicker->setOn(!beep);
	setFilePicker();
}

/******************************************************************************
 * Set the current sound file selection and repetition status.
 */
void SoundPicker::setFile(const QString& f, bool repeat)
{
	mFile = f;
	mRepeatCheckbox->setChecked(repeat);
	mFilePicker->setOn(true);
	setFilePicker();
}
/******************************************************************************
 * Called when the sound checkbox is toggled.
 */
void SoundPicker::slotSoundToggled(bool on)
{
	mFilePicker->setEnabled(on);
	setFilePicker();
}

/******************************************************************************
 * Called when the file picker button is clicked.
 */
void SoundPicker::slotPickFile()
{
	if (mFilePicker->isOn())
	{
		KURL url = browseFile(mFile, mDefaultDir);
		if (!url.isEmpty())
		{
			mFile = url.prettyURL();
			mDefaultDir = url.path();
			setFilePicker();
		}
		else if (mFile.isEmpty())
			mFilePicker->setOn(false);
	}
	setFilePicker();
}

/******************************************************************************
 * Display a dialogue to choose a sound file, initially highlighting any
 * specified file. 'initialFile' must be a full path name or URL.
 * Reply = URL selected. If none is selected, URL.isEmpty() is true.
 */
KURL SoundPicker::browseFile(const QString& initialFile, const QString& defaultDir)
{
	QString initialDir = !initialFile.isEmpty() ? QString(initialFile).remove(QRegExp("/[^/]*$"))
	                   : !defaultDir.isEmpty()  ? defaultDir
	                   : KGlobal::dirs()->findResourceDir("sound", "KDE_Notify.wav");
	KFileDialog fileDlg(initialDir, KDE::PlayObjectFactory::mimeTypes().join(" "), 0, "soundFileDlg", true);
	fileDlg.setCaption(i18n("Choose Sound File"));
	fileDlg.setMode(KFile::File | KFile::ExistingOnly);
	if (!initialFile.isEmpty())
		fileDlg.setSelection(initialFile);
	if (fileDlg.exec() == QDialog::Accepted)
		return fileDlg.selectedURL();
	return KURL();
}

/******************************************************************************
 * Set the sound picker button according to whether a sound file is selected.
 */
void SoundPicker::setFilePicker()
{
	bool repeatEnable = false;
	QToolTip::remove(mFilePicker);
	if (mFilePicker->isEnabled())
	{
		repeatEnable = mFilePicker->isOn();
		if (mFilePicker->isOn())
			QToolTip::add(mFilePicker, i18n("Play '%1'").arg(mFile));
		else
			QToolTip::add(mFilePicker, i18n("Beep"));
	}
	mRepeatCheckbox->setEnabled(repeatEnable);
}
<commit_msg>Make KAlarm build for "./configure --without-arts"<commit_after>/*
 *  soundpicker.cpp  -  widget to select a sound file or a beep
 *  Program:  kalarm
 *  (C) 2002, 2004 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give permission
 *  to link the code of this program with any edition of the Qt library by
 *  Trolltech AS, Norway (or with modified versions of Qt that use the same
 *  license as Qt), and distribute linked combinations including the two.
 *  You must obey the GNU General Public License in all respects for all of
 *  the code used other than Qt.  If you modify this file, you may extend
 *  this exception to your version of the file, but you are not obligated to
 *  do so. If you do not wish to do so, delete this exception statement from
 *  your version.
 */

#include "kalarm.h"

#include <qlayout.h>
#include <qregexp.h>
#include <qtooltip.h>
#include <qwhatsthis.h>

#include <kglobal.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#ifndef WITHOUT_ARTS
#include <arts/kplayobjectfactory.h>
#endif

#include "checkbox.h"
#include "pushbutton.h"
#include "soundpicker.moc"

// Collect these widget labels together to ensure consistent wording and
// translations across different modules.
QString SoundPicker::i18n_Sound()       { return i18n("An audio sound", "Sound"); }
QString SoundPicker::i18n_s_Sound()     { return i18n("An audio sound", "&Sound"); }
QString SoundPicker::i18n_SetVolume()   { return i18n("Set volume"); }
QString SoundPicker::i18n_v_SetVolume() { return i18n("Set &volume"); }
QString SoundPicker::i18n_Repeat()      { return i18n("Repeat"); }
QString SoundPicker::i18n_p_Repeat()    { return i18n("Re&peat"); }

SoundPicker::SoundPicker(QWidget* parent, const char* name)
	: QFrame(parent, name)
{
	// Sound checkbox
	setFrameStyle(QFrame::NoFrame);
	QHBoxLayout* soundLayout = new QHBoxLayout(this, 0, 2*KDialog::spacingHint());
	soundLayout->setAlignment(Qt::AlignVCenter);
	mCheckbox = new CheckBox(i18n_s_Sound(), this);
	mCheckbox->setFixedSize(mCheckbox->sizeHint());
	connect(mCheckbox, SIGNAL(toggled(bool)), SLOT(slotSoundToggled(bool)));
	QWhatsThis::add(mCheckbox,
	      i18n("If checked, a sound will be played when the message is displayed. Click the "
	           "button on the right to select the sound."));
	soundLayout->addWidget(mCheckbox);

	// Sound file picker button
	mFilePicker = new PushButton(this);
	mFilePicker->setPixmap(SmallIcon("playsound"));
	mFilePicker->setFixedSize(mFilePicker->sizeHint());
	mFilePicker->setToggleButton(true);
	connect(mFilePicker, SIGNAL(clicked()), SLOT(slotPickFile()));
	QWhatsThis::add(mFilePicker,
	      i18n("Select a sound file to play when the message is displayed. If no sound file is "
	           "selected, a beep will sound."));
	soundLayout->addWidget(mFilePicker);

	// Sound repetition checkbox
	mRepeatCheckbox = new CheckBox(i18n_p_Repeat(), this);
	mRepeatCheckbox->setFixedSize(mRepeatCheckbox->sizeHint());
	QWhatsThis::add(mRepeatCheckbox,
	      i18n("If checked, the sound file will be played repeatedly for as long as the message is displayed."));
	soundLayout->addWidget(mRepeatCheckbox);
#ifdef WITHOUT_ARTS
	mRepeatCheckbox->hide();
#endif

#ifdef SOUNDPICKER_VOLUME
	// Set volume checkbox
	mVolumeCheckbox = new CheckBox(i18n_v_SetVolume(), this);
	mVolumeCheckbox->setFixedSize(mVolumeCheckbox->sizeHint());
	connect(mVolumeCheckbox, SIGNAL(toggled(bool)), SLOT(slotVolumeToggled(bool)));
	QWhatsThis::add(mVolumeCheckbox,
	      i18n("Select to choose the volume for playing the sound file."));
	soundLayout->addWidget(mVolumeCheckbox);

	// Volume slider
	mVolumeSlider = new Slider(0, 100, 10, 0, Qt::Horizontal, this);
	mVolumeSlider->setFixedSize(mVolumeSlider->sizeHint());
	QWhatsThis::add(mVolumeSlider,
	      i18n("Choose the volume for playing the sound file."));
	mVolumeCheckbox->setFocusWidget(mVolumeSlider);
	soundLayout->addWidget(mVolumeSlider);
#endif
	soundLayout->addStretch();

	// Initialise the file picker button state and tooltip
	slotSoundToggled(false);
}

/******************************************************************************
 * Set the read-only status of the widget.
 */
void SoundPicker::setReadOnly(bool readOnly)
{
	mCheckbox->setReadOnly(readOnly);
	mFilePicker->setReadOnly(readOnly);
	mRepeatCheckbox->setReadOnly(readOnly);
}

/******************************************************************************
 * Return whether beep is selected.
 */
bool SoundPicker::beep() const
{
	return mCheckbox->isChecked()  &&  !mFilePicker->isOn();
}

/******************************************************************************
 * Return the selected sound file, if the main checkbox is checked.
 * Returns null string if beep is currently selected.
 */
QString SoundPicker::file() const
{
	return mCheckbox->isChecked() && mFilePicker->isOn() ? mFile : QString::null;
}

/******************************************************************************
 * Return whether sound file repetition is selected, if the main checkbox is checked.
 * Returns false if beep is currently selected.
 */
bool SoundPicker::repeat() const
{
	return mCheckbox->isChecked() && mFilePicker->isOn() && !mFile.isEmpty() && mRepeatCheckbox->isChecked();
}

/******************************************************************************
 * Return whether repetition is selected, regardless of the current beep and
 * file settings.
 */
bool SoundPicker::repeatSetting() const
{
	return mRepeatCheckbox->isChecked();
}

/******************************************************************************
 * Initialise the widget's state.
 */
void SoundPicker::set(bool beep, const QString& f, bool repeat)
{
	mCheckbox->setChecked(beep || !f.isEmpty());
	mFile = f;
	mRepeatCheckbox->setChecked(repeat);
	mFilePicker->setOn(!beep  &&  !f.isEmpty());
	setFilePicker();
}

/******************************************************************************
 * Set sound on or off.
 */
void SoundPicker::setChecked(bool on)
{
	mCheckbox->setChecked(on);
}

/******************************************************************************
 * Set the current beep status.
 */
void SoundPicker::setBeep(bool beep)
{
	mFilePicker->setOn(!beep);
	setFilePicker();
}

/******************************************************************************
 * Set the current sound file selection and repetition status.
 */
void SoundPicker::setFile(const QString& f, bool repeat)
{
	mFile = f;
	mRepeatCheckbox->setChecked(repeat);
	mFilePicker->setOn(true);
	setFilePicker();
}
/******************************************************************************
 * Called when the sound checkbox is toggled.
 */
void SoundPicker::slotSoundToggled(bool on)
{
	mFilePicker->setEnabled(on);
	setFilePicker();
}

/******************************************************************************
 * Called when the file picker button is clicked.
 */
void SoundPicker::slotPickFile()
{
	if (mFilePicker->isOn())
	{
		KURL url = browseFile(mFile, mDefaultDir);
		if (!url.isEmpty())
		{
			mFile = url.prettyURL();
			mDefaultDir = url.path();
			setFilePicker();
		}
		else if (mFile.isEmpty())
			mFilePicker->setOn(false);
	}
	setFilePicker();
}

/******************************************************************************
 * Display a dialogue to choose a sound file, initially highlighting any
 * specified file. 'initialFile' must be a full path name or URL.
 * Reply = URL selected. If none is selected, URL.isEmpty() is true.
 */
KURL SoundPicker::browseFile(const QString& initialFile, const QString& defaultDir)
{
	QString initialDir = !initialFile.isEmpty() ? QString(initialFile).remove(QRegExp("/[^/]*$"))
	                   : !defaultDir.isEmpty()  ? defaultDir
	                   : KGlobal::dirs()->findResourceDir("sound", "KDE_Notify.wav");
#ifdef WITHOUT_ARTS
	KFileDialog fileDlg(initialDir, QString::fromLatin1("*.wav *.mp3 *.ogg|%1\n*|%2").arg(i18n("Sound Files")).arg(i18n("All Files")), 0, "soundFileDlg", true);
#else
	KFileDialog fileDlg(initialDir, KDE::PlayObjectFactory::mimeTypes().join(" "), 0, "soundFileDlg", true);
#endif
	fileDlg.setCaption(i18n("Choose Sound File"));
	fileDlg.setMode(KFile::File | KFile::ExistingOnly);
	if (!initialFile.isEmpty())
		fileDlg.setSelection(initialFile);
	if (fileDlg.exec() == QDialog::Accepted)
		return fileDlg.selectedURL();
	return KURL();
}

/******************************************************************************
 * Set the sound picker button according to whether a sound file is selected.
 */
void SoundPicker::setFilePicker()
{
	bool repeatEnable = false;
	QToolTip::remove(mFilePicker);
	if (mFilePicker->isEnabled())
	{
		repeatEnable = mFilePicker->isOn();
		if (mFilePicker->isOn())
			QToolTip::add(mFilePicker, i18n("Play '%1'").arg(mFile));
		else
			QToolTip::add(mFilePicker, i18n("Beep"));
	}
	mRepeatCheckbox->setEnabled(repeatEnable);
}
<|endoftext|>


<commit_before>#include <babylon/samples/samples_index.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/core/string.h>
#include <babylon/interfaces/irenderable_scene.h>

#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>

namespace BABYLON {
namespace Samples {

SamplesIndex::SamplesIndex() = default;

void SamplesIndex::fillSamplesFailures() const
{
  static bool done = false;
  if (done)
    return;

  _samplesFailures = {
    {"BlurModeForMirrorsScene", {SampleFailureReasonKind::empty3d}},
    {"CircleCurvesFromBeziersScene", {SampleFailureReasonKind::empty3d, "Rendering empty with 50% chance"}},
    {"EnvironmentTextureScene", {SampleFailureReasonKind::empty3d}},
    {"FurMaterialScene", {SampleFailureReasonKind::segFault}},
    {"InnerMeshPointsScene", {SampleFailureReasonKind::broken3d, "Low FPS! Less than 1"}},
    {"IsPointInsideMeshScene", {SampleFailureReasonKind::processHung, "infinite loop inside Mesh::pointIsInside"}},
    {"LevelOfDetailScene", {SampleFailureReasonKind::segFault, "Low FPS / Segfault when dragging the mouse"}},
    {"LinesMeshSpiralScene", {SampleFailureReasonKind::empty3d}},
    {"LorenzAttractorScene", {SampleFailureReasonKind::empty3d, "Rendering empty with 50% chance"}},
    {"MotionBlurPostProcessScene", {SampleFailureReasonKind::empty3d}},
    {"MultiSampleRenderTargetsScene", {SampleFailureReasonKind::empty3d}},
    {"PointsCloudScene", {SampleFailureReasonKind::empty3d}},
    {"ProceduralHexPlanetGenerationScene", {SampleFailureReasonKind::broken3d, "Very small planet..."}},
    {"SimpleSkinScene", {SampleFailureReasonKind::empty3d}},
    {"ShaderMaterialWarpSpeedScene", {SampleFailureReasonKind::empty3d}},
    {"VolumetricLightScatteringScene", {SampleFailureReasonKind::segFault}}
  };

  done = true;
}

SamplesIndex& SamplesIndex::Instance()
{
  static SamplesIndex instance;
  return instance;
}

SamplesIndex::~SamplesIndex() = default;

void SamplesIndex::RegisterSample(const std::string& categoryName, const std::string& sampleName,
                                  SampleFactoryFunction fn)
{
  _samplesIndex[categoryName].addSample(sampleName, fn);
}

std::optional<BABYLON::Samples::SampleFailureReason>
SamplesIndex::doesSampleFail(const std::string& sampleName) const
{
  fillSamplesFailures();

  if (_samplesFailures.find(sampleName) == _samplesFailures.end())
    return std::nullopt;
  else
    return _samplesFailures.at(sampleName);
}

bool SamplesIndex::sampleExists(const std::string& sampleName) const
{
  for (const auto& item : _samplesIndex) {
    if (stl_util::contains(item.second.samples(), sampleName)) {
      return true;
    }
  }

  return false;
}

nlohmann::json ReadSampleInfoFile()
{
  std::ifstream is("samples_info.json");
  if (!is.good())
    is = std::ifstream("../samples_info.json");
  if (!is.good())
    is = std::ifstream("../../samples_info.json");
  if (is.good()) {
    nlohmann::json j;
    is >> j;
    return j;
  }
  else
    return nlohmann::json();
}

SampleInfo SamplesIndex::getSampleInfo(const std::string& sampleNameMixedCase) const
{
  static nlohmann::json _samplesInfo = ReadSampleInfoFile();
  static std::map<std::string, SampleInfo> cache;

  std::string sampleNameLowerCase;
  for (auto c : sampleNameMixedCase)
    sampleNameLowerCase += static_cast<char>(std::tolower(c));

  if (cache.find(sampleNameLowerCase) != cache.end())
    return cache.at(sampleNameLowerCase);

  SampleInfo result;
  for (const auto& element : _samplesInfo) {
    if (element["sample_name"] == sampleNameLowerCase) {
      result.Brief      = element["brief"];
      result.HeaderFile = element["header_file"];
      result.SourceFile = element["source_file"];
      for (const auto& link : element["links"]) {
        result.Links.push_back(link);
      }
    }
  }
  cache[sampleNameLowerCase] = result;
  return result;
}

std::vector<std::string> SamplesIndex::getSampleNames() const
{
  // Extract the enabled sample names from the map
  std::vector<std::string> sampleNames;
  for (const auto& samplesCategory : _samplesIndex) {
    for (const auto& element : samplesCategory.second.samples()) {
      sampleNames.emplace_back(element.first);
    }
  }

  // Sort the vector with sample names in ascending order
  std::sort(sampleNames.begin(), sampleNames.end());

  return sampleNames;
}

std::vector<std::string> SamplesIndex::getCategoryNames() const
{
  // Extract the category names
  auto categoryNames = stl_util::extract_keys(_samplesIndex);

  // Sort the vector with category names in ascending order
  std::sort(categoryNames.begin(), categoryNames.end());

  return categoryNames;
}

bool SamplesIndex::categoryExists(const std::string& categoryNameToSearch) const
{
  bool _categoryExists = false;

  // Extract the category names
  auto categoryNames = stl_util::extract_keys(_samplesIndex);

  // Search for sample
  for (const auto& categoryName : categoryNames) {
    if (categoryName == categoryNameToSearch) {
      _categoryExists = true;
      break;
    }
  }

  return _categoryExists;
}

std::vector<std::string>
SamplesIndex::getSampleNamesInCategory(const std::string& categoryName) const
{
  // Extract the enabled sample names for the given category from the map
  std::vector<std::string> sampleNames;
  if (stl_util::contains(_samplesIndex, categoryName)) {
    const auto& samplesCategory = _samplesIndex.at(categoryName);
    for (const auto& element : samplesCategory.samples()) {
      sampleNames.emplace_back(element.first);
    }
  }

  // Sort the vector with sample names in ascending order
  std::sort(sampleNames.begin(), sampleNames.end());

  return sampleNames;
}

IRenderableScenePtr SamplesIndex::createRenderableScene(const std::string& sampleName,
                                                        ICanvas* iCanvas) const
{
  for (const auto& item : _samplesIndex) {
    if (stl_util::contains(item.second.samples(), sampleName)) {
      return item.second.samples().at(sampleName)(iCanvas);
    }
  }

  return nullptr;
}

void SamplesIndex::listSamples()
{
  auto categories = getCategoryNames();
  for (const auto& category : categories) {
    std::cout << "********************************************"
              << "\n";
    std::cout << "Category: " << category << "\n";
    std::cout << "********************************************"
              << "\n";
    auto samples = getSampleNamesInCategory(category);
    for (const auto& sample : samples) {
      std::cout << sample << "\n";
    }
  }
}

std::string SampleFailureReason_Str(SampleFailureReasonKind s)
{
  switch (s) {
    case SampleFailureReasonKind::segFault:
      return "Segmentation fault";
    case SampleFailureReasonKind::processHung:
      return "Process hung (infinite loop?)";
    case SampleFailureReasonKind::empty3d:
      return "3D rendering is empty";
    case SampleFailureReasonKind::broken3d:
      return "Broken (bad rendering and/or bad behavior)";
    default:
      throw "Unhandled enum!";
  }
}

} // end of namespace Samples
} // end of namespace BABYLON
<commit_msg>FurMaterialScene: more detail about the failure<commit_after>#include <babylon/samples/samples_index.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/core/string.h>
#include <babylon/interfaces/irenderable_scene.h>

#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>

namespace BABYLON {
namespace Samples {

SamplesIndex::SamplesIndex() = default;

void SamplesIndex::fillSamplesFailures() const
{
  static bool done = false;
  if (done)
    return;

  _samplesFailures = {
    {"BlurModeForMirrorsScene", {SampleFailureReasonKind::empty3d}},
    {"CircleCurvesFromBeziersScene", {SampleFailureReasonKind::empty3d, "Rendering empty with 50% chance"}},
    {"EnvironmentTextureScene", {SampleFailureReasonKind::empty3d}},
    {"FurMaterialScene", {SampleFailureReasonKind::broken3d, "Black fur!"}},
    {"InnerMeshPointsScene", {SampleFailureReasonKind::broken3d, "Low FPS! Less than 1"}},
    {"IsPointInsideMeshScene", {SampleFailureReasonKind::processHung, "infinite loop inside Mesh::pointIsInside"}},
    {"LevelOfDetailScene", {SampleFailureReasonKind::segFault, "Low FPS / Segfault when dragging the mouse"}},
    {"LinesMeshSpiralScene", {SampleFailureReasonKind::empty3d}},
    {"LorenzAttractorScene", {SampleFailureReasonKind::empty3d, "Rendering empty with 50% chance"}},
    {"MotionBlurPostProcessScene", {SampleFailureReasonKind::empty3d}},
    {"MultiSampleRenderTargetsScene", {SampleFailureReasonKind::empty3d}},
    {"PointsCloudScene", {SampleFailureReasonKind::empty3d}},
    {"ProceduralHexPlanetGenerationScene", {SampleFailureReasonKind::broken3d, "Very small planet..."}},
    {"SimpleSkinScene", {SampleFailureReasonKind::empty3d}},
    {"ShaderMaterialWarpSpeedScene", {SampleFailureReasonKind::empty3d}},
    {"VolumetricLightScatteringScene", {SampleFailureReasonKind::segFault}}
  };

  done = true;
}

SamplesIndex& SamplesIndex::Instance()
{
  static SamplesIndex instance;
  return instance;
}

SamplesIndex::~SamplesIndex() = default;

void SamplesIndex::RegisterSample(const std::string& categoryName, const std::string& sampleName,
                                  SampleFactoryFunction fn)
{
  _samplesIndex[categoryName].addSample(sampleName, fn);
}

std::optional<BABYLON::Samples::SampleFailureReason>
SamplesIndex::doesSampleFail(const std::string& sampleName) const
{
  fillSamplesFailures();

  if (_samplesFailures.find(sampleName) == _samplesFailures.end())
    return std::nullopt;
  else
    return _samplesFailures.at(sampleName);
}

bool SamplesIndex::sampleExists(const std::string& sampleName) const
{
  for (const auto& item : _samplesIndex) {
    if (stl_util::contains(item.second.samples(), sampleName)) {
      return true;
    }
  }

  return false;
}

nlohmann::json ReadSampleInfoFile()
{
  std::ifstream is("samples_info.json");
  if (!is.good())
    is = std::ifstream("../samples_info.json");
  if (!is.good())
    is = std::ifstream("../../samples_info.json");
  if (is.good()) {
    nlohmann::json j;
    is >> j;
    return j;
  }
  else
    return nlohmann::json();
}

SampleInfo SamplesIndex::getSampleInfo(const std::string& sampleNameMixedCase) const
{
  static nlohmann::json _samplesInfo = ReadSampleInfoFile();
  static std::map<std::string, SampleInfo> cache;

  std::string sampleNameLowerCase;
  for (auto c : sampleNameMixedCase)
    sampleNameLowerCase += static_cast<char>(std::tolower(c));

  if (cache.find(sampleNameLowerCase) != cache.end())
    return cache.at(sampleNameLowerCase);

  SampleInfo result;
  for (const auto& element : _samplesInfo) {
    if (element["sample_name"] == sampleNameLowerCase) {
      result.Brief      = element["brief"];
      result.HeaderFile = element["header_file"];
      result.SourceFile = element["source_file"];
      for (const auto& link : element["links"]) {
        result.Links.push_back(link);
      }
    }
  }
  cache[sampleNameLowerCase] = result;
  return result;
}

std::vector<std::string> SamplesIndex::getSampleNames() const
{
  // Extract the enabled sample names from the map
  std::vector<std::string> sampleNames;
  for (const auto& samplesCategory : _samplesIndex) {
    for (const auto& element : samplesCategory.second.samples()) {
      sampleNames.emplace_back(element.first);
    }
  }

  // Sort the vector with sample names in ascending order
  std::sort(sampleNames.begin(), sampleNames.end());

  return sampleNames;
}

std::vector<std::string> SamplesIndex::getCategoryNames() const
{
  // Extract the category names
  auto categoryNames = stl_util::extract_keys(_samplesIndex);

  // Sort the vector with category names in ascending order
  std::sort(categoryNames.begin(), categoryNames.end());

  return categoryNames;
}

bool SamplesIndex::categoryExists(const std::string& categoryNameToSearch) const
{
  bool _categoryExists = false;

  // Extract the category names
  auto categoryNames = stl_util::extract_keys(_samplesIndex);

  // Search for sample
  for (const auto& categoryName : categoryNames) {
    if (categoryName == categoryNameToSearch) {
      _categoryExists = true;
      break;
    }
  }

  return _categoryExists;
}

std::vector<std::string>
SamplesIndex::getSampleNamesInCategory(const std::string& categoryName) const
{
  // Extract the enabled sample names for the given category from the map
  std::vector<std::string> sampleNames;
  if (stl_util::contains(_samplesIndex, categoryName)) {
    const auto& samplesCategory = _samplesIndex.at(categoryName);
    for (const auto& element : samplesCategory.samples()) {
      sampleNames.emplace_back(element.first);
    }
  }

  // Sort the vector with sample names in ascending order
  std::sort(sampleNames.begin(), sampleNames.end());

  return sampleNames;
}

IRenderableScenePtr SamplesIndex::createRenderableScene(const std::string& sampleName,
                                                        ICanvas* iCanvas) const
{
  for (const auto& item : _samplesIndex) {
    if (stl_util::contains(item.second.samples(), sampleName)) {
      return item.second.samples().at(sampleName)(iCanvas);
    }
  }

  return nullptr;
}

void SamplesIndex::listSamples()
{
  auto categories = getCategoryNames();
  for (const auto& category : categories) {
    std::cout << "********************************************"
              << "\n";
    std::cout << "Category: " << category << "\n";
    std::cout << "********************************************"
              << "\n";
    auto samples = getSampleNamesInCategory(category);
    for (const auto& sample : samples) {
      std::cout << sample << "\n";
    }
  }
}

std::string SampleFailureReason_Str(SampleFailureReasonKind s)
{
  switch (s) {
    case SampleFailureReasonKind::segFault:
      return "Segmentation fault";
    case SampleFailureReasonKind::processHung:
      return "Process hung (infinite loop?)";
    case SampleFailureReasonKind::empty3d:
      return "3D rendering is empty";
    case SampleFailureReasonKind::broken3d:
      return "Broken (bad rendering and/or bad behavior)";
    default:
      throw "Unhandled enum!";
  }
}

} // end of namespace Samples
} // end of namespace BABYLON
<|endoftext|>


<commit_before>#include "./window.h"
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
#include <QDebug>
#include <QCoreApplication>
#include <QKeyEvent>
#include <QStateMachine>
#include <QAbstractState>
#include <QAbstractTransition>
#include <QLoggingCategory>
#include "./graphics/gl.h"
#include "./abstract_scene.h"

QLoggingCategory openGlChan("OpenGl");

Window::Window(std::shared_ptr<AbstractScene> scene, QWindow *parent)
  : QQuickView(parent), scene(scene)
{
  setClearBeforeRendering(false);

  connect(this, SIGNAL(widthChanged(int)), this, SLOT(resizeOpenGL()));
  connect(this, SIGNAL(heightChanged(int)), this, SLOT(resizeOpenGL()));
  connect(this, &Window::sceneGraphInvalidated, this, &Window::onInvalidated,
          Qt::DirectConnection);

  connect(reinterpret_cast<QObject *>(engine()), SIGNAL(quit()), this,
          SLOT(close()));

  connect(this, SIGNAL(beforeRendering()), this, SLOT(render()),
          Qt::DirectConnection);

  auto format = createSurfaceFormat();
  setFormat(format);

  timer.start();
}

Window::~Window()
{
  disconnect(logger, &QOpenGLDebugLogger::messageLogged, this,
             &Window::onMessageLogged);
}

QSurfaceFormat Window::createSurfaceFormat()
{
  QSurfaceFormat format;
  format.setDepthBufferSize(24);
  format.setMajorVersion(4);
  format.setMinorVersion(5);
  format.setSamples(4);
  format.setOption(QSurfaceFormat::DebugContext);
  format.setSwapInterval(0);

  return format;
}

void Window::initializeOpenGL()
{
  qCInfo(openGlChan) << "initializeOpenGL";
  context = openglContext();
  context->makeCurrent(this);

  gl = new Graphics::Gl();
  gl->initialize(context, size());

  logger = new QOpenGLDebugLogger(context);
  connect(context, &QOpenGLContext::aboutToBeDestroyed, this,
          &Window::contextAboutToBeDestroyed, Qt::DirectConnection);

  connect(logger, &QOpenGLDebugLogger::messageLogged, this,
          &Window::onMessageLogged, Qt::DirectConnection);

  if (logger->initialize())
  {
    logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
    logger->enableMessages();
  }

  glAssert(gl->glDisable(GL_CULL_FACE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));
  glAssert(gl->glDisable(GL_STENCIL_TEST));
  glAssert(gl->glDisable(GL_BLEND));
  glAssert(gl->glDepthMask(GL_FALSE));
}

void Window::keyReleaseEvent(QKeyEvent *event)
{
  QQuickView::keyReleaseEvent(event);
  keysPressed -= static_cast<Qt::Key>(event->key());
}

void Window::keyPressEvent(QKeyEvent *event)
{
  QQuickView::keyPressEvent(event);
  keysPressed += static_cast<Qt::Key>(event->key());
}

void Window::onInvalidated()
{
  qCInfo(openGlChan) << "on invalidated: delete logger";
  scene->cleanup();
  delete logger;
}

void Window::handleLazyInitialization()
{
  static bool initialized = false;
  if (!initialized)
  {
    initializeOpenGL();

    scene->setContext(context, gl);
    scene->resize(size().width(), size().height());
    scene->initialize();
    initialized = true;
  }
}

void Window::render()
{
  handleLazyInitialization();

  update();
  scene->render();

  // Use to check for missing release calls
  // resetOpenGLState();

  QQuickView::update();
}

void Window::resizeOpenGL()
{
  if (!gl)
    return;

  scene->resize(width(), height());
  gl->setSize(this->size());
}

void Window::update()
{
  double frameTime = timer.restart() / 1000.0;
  updateAverageFrameTime(frameTime);

  scene->update(frameTime, keysPressed);
}

void Window::toggleFullscreen()
{
  setVisibility(visibility() == QWindow::Windowed ? QWindow::FullScreen
                                                  : QWindow::Windowed);
}

void Window::contextAboutToBeDestroyed()
{
  qCInfo(openGlChan) << "Closing rendering thread";
}

void Window::updateAverageFrameTime(double frameTime)
{
  runningTime += frameTime;
  ++framesInSecond;

  if (runningTime > 1.0)
  {
    avgFrameTime = runningTime / framesInSecond;
    emit averageFrameTimeUpdated();

    framesInSecond = 0;
    runningTime = 0;
  }
}

void Window::onMessageLogged(QOpenGLDebugMessage message)
{
  // Ignore buffer detailed info which cannot be fixed
  if (message.id() == 131185)
    return;

  // Ignore buffer performance warning
  if (message.id() == 131186)
    return;

  // Ignore generic vertex attribute array 1 uses a pointer with a small value
  if (message.id() == 131076)
    return;

  switch (message.severity())
  {
  case QOpenGLDebugMessage::Severity::NotificationSeverity:
    qCInfo(openGlChan) << message;
    break;

  case QOpenGLDebugMessage::Severity::LowSeverity:
    qCDebug(openGlChan) << message;
    break;
  case QOpenGLDebugMessage::Severity::MediumSeverity:
    qCWarning(openGlChan) << message;
    break;
  case QOpenGLDebugMessage::Severity::HighSeverity:
    qCCritical(openGlChan) << message;
    throw std::runtime_error(message.message().toStdString());
    break;
  default:
    return;
  }
}

<commit_msg>Explicitly don't support resizing and don't crash any more.<commit_after>#include "./window.h"
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
#include <QDebug>
#include <QCoreApplication>
#include <QKeyEvent>
#include <QStateMachine>
#include <QAbstractState>
#include <QAbstractTransition>
#include <QLoggingCategory>
#include "./graphics/gl.h"
#include "./abstract_scene.h"

QLoggingCategory openGlChan("OpenGl");

Window::Window(std::shared_ptr<AbstractScene> scene, QWindow *parent)
  : QQuickView(parent), scene(scene)
{
  setClearBeforeRendering(false);

  connect(this, SIGNAL(widthChanged(int)), this, SLOT(resizeOpenGL()));
  connect(this, SIGNAL(heightChanged(int)), this, SLOT(resizeOpenGL()));
  connect(this, &Window::sceneGraphInvalidated, this, &Window::onInvalidated,
          Qt::DirectConnection);

  connect(reinterpret_cast<QObject *>(engine()), SIGNAL(quit()), this,
          SLOT(close()));

  connect(this, SIGNAL(beforeRendering()), this, SLOT(render()),
          Qt::DirectConnection);

  auto format = createSurfaceFormat();
  setFormat(format);

  timer.start();
}

Window::~Window()
{
  disconnect(logger, &QOpenGLDebugLogger::messageLogged, this,
             &Window::onMessageLogged);
}

QSurfaceFormat Window::createSurfaceFormat()
{
  QSurfaceFormat format;
  format.setDepthBufferSize(24);
  format.setMajorVersion(4);
  format.setMinorVersion(5);
  format.setSamples(4);
  format.setOption(QSurfaceFormat::DebugContext);
  format.setSwapInterval(0);

  return format;
}

void Window::initializeOpenGL()
{
  qCInfo(openGlChan) << "initializeOpenGL";
  context = openglContext();
  context->makeCurrent(this);

  gl = new Graphics::Gl();
  gl->initialize(context, size());

  logger = new QOpenGLDebugLogger(context);
  connect(context, &QOpenGLContext::aboutToBeDestroyed, this,
          &Window::contextAboutToBeDestroyed, Qt::DirectConnection);

  connect(logger, &QOpenGLDebugLogger::messageLogged, this,
          &Window::onMessageLogged, Qt::DirectConnection);

  if (logger->initialize())
  {
    logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
    logger->enableMessages();
  }

  glAssert(gl->glDisable(GL_CULL_FACE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));
  glAssert(gl->glDisable(GL_STENCIL_TEST));
  glAssert(gl->glDisable(GL_BLEND));
  glAssert(gl->glDepthMask(GL_FALSE));
}

void Window::keyReleaseEvent(QKeyEvent *event)
{
  QQuickView::keyReleaseEvent(event);
  keysPressed -= static_cast<Qt::Key>(event->key());
}

void Window::keyPressEvent(QKeyEvent *event)
{
  QQuickView::keyPressEvent(event);
  keysPressed += static_cast<Qt::Key>(event->key());
}

void Window::onInvalidated()
{
  qCInfo(openGlChan) << "on invalidated: delete logger";
  scene->cleanup();
  delete logger;
}

void Window::handleLazyInitialization()
{
  static bool initialized = false;
  if (!initialized)
  {
    initializeOpenGL();

    scene->setContext(context, gl);
    scene->resize(size().width(), size().height());
    scene->initialize();
    initialized = true;
  }
}

void Window::render()
{
  handleLazyInitialization();

  update();
  scene->render();

  // Use to check for missing release calls
  // resetOpenGLState();

  QQuickView::update();
}

void Window::resizeOpenGL()
{
  if (!gl)
    return;

  qCWarning(openGlChan) << "Resize not supported for now";
  /*
  scene->resize(width(), height());
  gl->setSize(this->size());
  */
}

void Window::update()
{
  double frameTime = timer.restart() / 1000.0;
  updateAverageFrameTime(frameTime);

  scene->update(frameTime, keysPressed);
}

void Window::toggleFullscreen()
{
  setVisibility(visibility() == QWindow::Windowed ? QWindow::FullScreen
                                                  : QWindow::Windowed);
}

void Window::contextAboutToBeDestroyed()
{
  qCInfo(openGlChan) << "Closing rendering thread";
}

void Window::updateAverageFrameTime(double frameTime)
{
  runningTime += frameTime;
  ++framesInSecond;

  if (runningTime > 1.0)
  {
    avgFrameTime = runningTime / framesInSecond;
    emit averageFrameTimeUpdated();

    framesInSecond = 0;
    runningTime = 0;
  }
}

void Window::onMessageLogged(QOpenGLDebugMessage message)
{
  // Ignore buffer detailed info which cannot be fixed
  if (message.id() == 131185)
    return;

  // Ignore buffer performance warning
  if (message.id() == 131186)
    return;

  // Ignore generic vertex attribute array 1 uses a pointer with a small value
  if (message.id() == 131076)
    return;

  switch (message.severity())
  {
  case QOpenGLDebugMessage::Severity::NotificationSeverity:
    qCInfo(openGlChan) << message;
    break;

  case QOpenGLDebugMessage::Severity::LowSeverity:
    qCDebug(openGlChan) << message;
    break;
  case QOpenGLDebugMessage::Severity::MediumSeverity:
    qCWarning(openGlChan) << message;
    break;
  case QOpenGLDebugMessage::Severity::HighSeverity:
    qCCritical(openGlChan) << message;
    throw std::runtime_error(message.message().toStdString());
    break;
  default:
    return;
  }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "xapiand.h"

#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager_ptr = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager_ptr) {
		manager_ptr->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, const char *cluster_name_, const char *discovery_group, int discovery_port, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, cluster_name_, discovery_group, discovery_port, http_port, binary_port);

	manager_ptr = &manager;

	manager.run(num_servers);

	manager_ptr = NULL;
}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int discovery_port = 0;
	int http_port = 0;
	int binary_port = 0;
	const char *discovery_group = NULL;
	const char *cluster_name = "xapiand";
	const char *p;

	INFO((void *)NULL,
		"\n\n"
		"  __  __           _                 _\n"
		"  \\ \\/ /__ _ _ __ (_) __ _ _ __   __| |\n"
		"   \\  // _` | '_ \\| |/ _` | '_ \\ / _` |\n"
		"   /  \\ (_| | |_) | | (_| | | | | (_| |\n"
		"  /_/\\_\\__,_| .__/|_|\\__,_|_| |_|\\__,_|\n"
		"            |_|  v%s\n"
		"   [%s]\n"
		"          Using Xapian v%s\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT, XAPIAN_VERSION);

	INFO((void *)NULL, "Joined cluster: %s\n", cluster_name);

#ifdef XAPIAN_HAS_GLASS_BACKEND
	// Prefer glass database
	if (setenv("XAPIAN_PREFER_GLASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled glass database.\n");
	}
#elif XAPIAN_HAS_BRASS_BACKEND
	// Prefer brass database
	if (setenv("XAPIAN_PREFER_BRASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled brass database.\n");
	}
#endif

	// Enable changesets
	if (setenv("XAPIAN_MAX_CHANGESETS", "10", false) == 0) {
		INFO((void *)NULL, "Database changesets set to 10.\n");
	}

	// Flush threshold increased
	int flush_threshold = 10000;  // Default is 10000 (if no set)
	p = getenv("XAPIAN_FLUSH_THRESHOLD");
	if (p) flush_threshold = atoi(p);
	if (flush_threshold < 100000 && setenv("XAPIAN_FLUSH_THRESHOLD", "100000", false) == 0) {
		INFO((void *)NULL, "Increased flush threshold to 100000 (it was originally set to %d).\n", flush_threshold);
	}

	time(&init_time);
	struct tm *timeinfo = localtime(&init_time);
	timeinfo->tm_hour   = 0;
	timeinfo->tm_min    = 0;
	timeinfo->tm_sec    = 0;
	int diff_t = (int)(init_time - mktime(timeinfo));
	b_time.minute = diff_t / SLOT_TIME_SECOND;
	b_time.second =  diff_t % SLOT_TIME_SECOND;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	run(num_servers, cluster_name, discovery_group, discovery_port, http_port, binary_port);
	INFO((void *)NULL, "Done with all work!\n");

	return 0;
}
<commit_msg>Disabled cutting edge databases<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "xapiand.h"

#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager_ptr = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager_ptr) {
		manager_ptr->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, const char *cluster_name_, const char *discovery_group, int discovery_port, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, cluster_name_, discovery_group, discovery_port, http_port, binary_port);

	manager_ptr = &manager;

	manager.run(num_servers);

	manager_ptr = NULL;
}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int discovery_port = 0;
	int http_port = 0;
	int binary_port = 0;
	const char *discovery_group = NULL;
	const char *cluster_name = "xapiand";
	const char *p;

	INFO((void *)NULL,
		"\n\n"
		"  __  __           _                 _\n"
		"  \\ \\/ /__ _ _ __ (_) __ _ _ __   __| |\n"
		"   \\  // _` | '_ \\| |/ _` | '_ \\ / _` |\n"
		"   /  \\ (_| | |_) | | (_| | | | | (_| |\n"
		"  /_/\\_\\__,_| .__/|_|\\__,_|_| |_|\\__,_|\n"
		"            |_|  v%s\n"
		"   [%s]\n"
		"          Using Xapian v%s\n\n", PACKAGE_VERSION, PACKAGE_BUGREPORT, XAPIAN_VERSION);

	INFO((void *)NULL, "Joined cluster: %s\n", cluster_name);

/*
#ifdef XAPIAN_HAS_GLASS_BACKEND
	// Prefer glass database
	if (setenv("XAPIAN_PREFER_GLASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled glass database.\n");
	}
#elif XAPIAN_HAS_BRASS_BACKEND
	// Prefer brass database
	if (setenv("XAPIAN_PREFER_BRASS", "1", false) == 0) {
		INFO((void *)NULL, "Enabled brass database.\n");
	}
#endif
*/

	// Enable changesets
	if (setenv("XAPIAN_MAX_CHANGESETS", "10", false) == 0) {
		INFO((void *)NULL, "Database changesets set to 10.\n");
	}

	// Flush threshold increased
	int flush_threshold = 10000;  // Default is 10000 (if no set)
	p = getenv("XAPIAN_FLUSH_THRESHOLD");
	if (p) flush_threshold = atoi(p);
	if (flush_threshold < 100000 && setenv("XAPIAN_FLUSH_THRESHOLD", "100000", false) == 0) {
		INFO((void *)NULL, "Increased flush threshold to 100000 (it was originally set to %d).\n", flush_threshold);
	}

	time(&init_time);
	struct tm *timeinfo = localtime(&init_time);
	timeinfo->tm_hour   = 0;
	timeinfo->tm_min    = 0;
	timeinfo->tm_sec    = 0;
	int diff_t = (int)(init_time - mktime(timeinfo));
	b_time.minute = diff_t / SLOT_TIME_SECOND;
	b_time.second =  diff_t % SLOT_TIME_SECOND;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	run(num_servers, cluster_name, discovery_group, discovery_port, http_port, binary_port);
	INFO((void *)NULL, "Done with all work!\n");

	return 0;
}
<|endoftext|>


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

#include "xapiand.h"
#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager) {
		manager->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, http_port, binary_port);

	manager.run(num_servers);

}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int http_port = XAPIAND_HTTP_SERVERPORT;
	int binary_port = XAPIAND_BINARY_SERVERPORT;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	LOG((void *)NULL, "Starting %s (%s).\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
	run(num_servers, http_port, binary_port);
	LOG((void *)NULL, "Done with all work!\n");

	return 0;
}
<commit_msg>Set manager_ptr as a global when manager is initialized (for signals)<commit_after>/*
 * Copyright deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "xapiand.h"
#include "utils.h"
#include "manager.h"

#include <stdlib.h>

XapiandManager *manager_ptr = NULL;

static void sig_shutdown_handler(int sig)
{
	if (manager_ptr) {
		manager_ptr->sig_shutdown_handler(sig);
	}
}

void setup_signal_handlers(void) {
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);

	struct sigaction act;

	/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
	 * Otherwise, sa_handler is used. */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_shutdown_handler;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
}

void run(int num_servers, int http_port, int binary_port)
{
	ev::default_loop default_loop;

	setup_signal_handlers();

	XapiandManager manager(&default_loop, http_port, binary_port);

	manager_ptr = &manager;

	manager.run(num_servers);

	manager_ptr = NULL;
}

int main(int argc, char **argv)
{
	int num_servers = 8;
	int http_port = XAPIAND_HTTP_SERVERPORT;
	int binary_port = XAPIAND_BINARY_SERVERPORT;

	if (argc > 2) {
		http_port = atoi(argv[1]);
		binary_port = atoi(argv[2]);
	}

	LOG((void *)NULL, "Starting %s (%s).\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
	run(num_servers, http_port, binary_port);
	LOG((void *)NULL, "Done with all work!\n");

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <random>
#define SIZEF 500

struct Position{
  int x;
  int y;
};

using namespace std;

void walk(Position *p,int &board,int size){
  //https://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range
  random_device rd;
  mt19937 gen(rd());
  //http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
  uniform_int_distribution<int> uni(0,100);
  auto random = uni(gen);
  cout << random+"\n";
}

int main(int argc, char const *argv[]) {
  int board [SIZEF][SIZEF];
  int size,count;
  Position *p;
  cin >> size;
  p->x = 0;
  p->y = 0;
  board[0][0] = 1;
  count = 2;
  for (int i = 0; i < size; i++) {
    for (int j = 0;j < size; j++){
      walk(p,**board,size);
    }
  }
  return 0;
}
<commit_msg>alocado p<commit_after>#include <iostream>
#include <random>
#define SIZEF 500

struct Position{
  int x;
  int y;
};

using namespace std;

void walk(Position *p,int &board,int size){
  //https://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range
  random_device rd;
  mt19937 gen(rd());
  //http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
  uniform_int_distribution<int> uni(0,100);
  auto random = uni(gen);
  cout << random+"\n";
}

int main(int argc, char const *argv[]) {
  int board [SIZEF][SIZEF];
  int size,count;
  Position *p;
  p = (Position *) malloc(sizeof(Position));
  cin >> size;
  p->x = 0;
  p->y = 0;
  board[0][0] = 1;
  count = 2;
  for (int i = 0; i < size; i++) {
    for (int j = 0;j < size; j++){
      walk(p,**board,size);
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "Downloads.h"

/* common implementation headers */
#include "network.h"
#include "Address.h"
#include "AccessList.h"
#include "CacheManager.h"
#include "BzMaterial.h"
#include "URLManager.h"
#include "AnsiCodes.h"
#include "TextureManager.h"

/* local implementation headers */
#include "playing.h"
#include "HUDDialogStack.h"

// FIXME - someone write a better explanation
static const char DownloadContent[] =
  "#\n"
  "# This file controls the access to servers for downloads.\n"
  "# Patterns are attempted in order against both the hostname\n"
  "# and ip. The first matching pattern sets the state. If no\n"
  "# patterns are matched, then the server is authorized. There\n"
  "# are four types of matches:\n"
  "#\n"
  "#   simple globbing (* and ?)\n"
  "#     allow\n"
  "#     deny\n"
  "#\n"
  "#   regular expressions\n"
  "#     allow_regex\n"
  "#     deny_regex\n"
  "#\n"
  "\n"
  "#\n"
  "# To authorize all servers, remove the last 3 lines.\n"
  "#\n"
  "\n"
  "allow *.bzflag.bz\n"
  "allow *.bzflag.org\n"
  "deny *\n";

static AccessList DownloadAccessList("DownloadAccess.txt", DownloadContent);

/******************************************************************************/
#ifdef HAVE_CURL
/******************************************************************************/

// Function Prototypes
static void printAuthNotice();
static bool getFileTime(const std::string& url, time_t& t);
static bool getAndCacheURL(const std::string& url);
static bool authorizedServer(const std::string& url);
static void setHudMessage(const std::string& msg);

void Downloads::doDownloads()
{
  CACHEMGR.loadIndex();
  CACHEMGR.limitCacheSize();

  DownloadAccessList.reload();

  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, false /* ignore referencing */);

  bool authNotice = false;

  const bool doDownloads =	BZDB.isTrue("doDownloads");
  const bool updateDownloads =  BZDB.isTrue("updateDownloads");

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {

      // check access authorization
      if (!authorizedServer(texUrl)) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        authNotice = true;
        continue;
      }

      // use the cache?
      CacheManager::CacheRecord oldrec;
      if (CACHEMGR.findURL(texUrl, oldrec)) {
        time_t filetime = 0;
        if (doDownloads && updateDownloads) {
          getFileTime(texUrl, filetime);
        }
        if (filetime <= oldrec.date) {
          // use the cached file
          MATERIALMGR.setTextureLocal(texUrl, oldrec.name);
          continue;
        }
      }

      // bail here if we can't download
      if (!doDownloads) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        std::string msg = ColorStrings[GreyColor];
        msg += "not downloading: " + texUrl;
        addMessage(NULL, msg);
        continue;
      }

      // download and cache the URL
      if (getAndCacheURL(texUrl)) {
        const std::string localname = CACHEMGR.getLocalName(texUrl);
        MATERIALMGR.setTextureLocal(texUrl, localname);
      } else {
        MATERIALMGR.setTextureLocal(texUrl, "");
      }
    }
  }

  if (authNotice) {
    printAuthNotice();
  }

  CACHEMGR.saveIndex();

  return;
}

bool Downloads::updateDownloads(bool& rebuild)
{
  CACHEMGR.loadIndex();
  CACHEMGR.limitCacheSize();

  DownloadAccessList.reload();

  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, true /* only referenced materials */);

  TextureManager& TEXMGR = TextureManager::instance();

  rebuild = false;
  bool updated = false;
  bool authNotice = false;

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {

      // check access authorization
      if (!authorizedServer(texUrl)) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        authNotice = true;
        continue;
      }

      // use the cache or update?
      CacheManager::CacheRecord oldrec;
      if (CACHEMGR.findURL(texUrl, oldrec)) {
        time_t filetime;
        getFileTime(texUrl, filetime);
        if (filetime <= oldrec.date) {
          // keep using the cached file
          MATERIALMGR.setTextureLocal(texUrl, oldrec.name);
          if (!TEXMGR.isLoaded(oldrec.name)) {
            rebuild = true;
          }
          continue;
        }
      }

      // download the file and update the cache
      if (getAndCacheURL(texUrl)) {
        updated = true;
        const std::string localname = CACHEMGR.getLocalName(texUrl);
        if (!TEXMGR.isLoaded(localname)) {
          rebuild = true;
        } else {
          TEXMGR.reloadTextureImage(localname); // reload with the new image
        }
        MATERIALMGR.setTextureLocal(texUrl, localname); // if it wasn't cached
      }
    }
  }

  if (authNotice) {
    printAuthNotice();
  }

  CACHEMGR.saveIndex();

  return updated;
}

void Downloads::removeTextures()
{
  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, false /* ignore referencing */);

  TextureManager& TEXMGR = TextureManager::instance();

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {
      const std::string& localname = CACHEMGR.getLocalName(texUrl);
      if (TEXMGR.isLoaded(localname)) {
        TEXMGR.removeTexture(localname);
      }
    }
  }

  return;
}

static void printAuthNotice()
{
  std::string msg = ColorStrings[WhiteColor];
  msg += "NOTE: ";
  msg += ColorStrings[GreyColor];
  msg += "download access is controlled by ";
  msg += ColorStrings[YellowColor];
  msg += DownloadAccessList.getFileName();
  addMessage(NULL, msg);
  return;
}

static bool getFileTime(const std::string& url, time_t& t)
{
  setHudMessage("Download DNS check...");

  URLManager& URLMGR = URLManager::instance();
  if (URLMGR.getURLHeader(url)) {
    URLMGR.getFileTime(t);
    return true;
  } else {
    t = 0;
    return false;
  }

  setHudMessage("");
}

static bool getAndCacheURL(const std::string& url)
{
  bool result = false;

  setHudMessage("Download DNS check...");

  URLManager& URLMGR = URLManager::instance();
  URLMGR.setProgressFunc(curlProgressFunc, NULL);

  std::string msg = ColorStrings[GreyColor];
  msg += "downloading: " + url;
  addMessage(NULL, msg);

  void* urlData;
  unsigned int urlSize;

  if (URLMGR.getURL(url, &urlData, urlSize)) {
    time_t filetime;
    URLMGR.getFileTime(filetime);
    // CACHEMGR generates name, usedDate, and key
    CacheManager::CacheRecord rec;
    rec.url = url;
    rec.size = urlSize;
    rec.date = filetime;
    CACHEMGR.addFile(rec, urlData);
    free(urlData);
    result = true;
  }
  else {
    std::string msg = ColorStrings[RedColor] + "* failure *";
    addMessage(NULL, msg);
    result = false;
  }

  URLMGR.setProgressFunc(NULL, NULL);

  setHudMessage("");

  return result;
}

static bool authorizedServer(const std::string& url)
{
  // avoid the DNS lookup
  if (DownloadAccessList.alwaysAuthorized()) {
    return true;
  }

  // parse url
  std::string protocol, hostname, path, ip;
  int port = 1;
  if (BzfNetwork::parseURL(url, protocol, hostname, port, path) &&
      ((protocol == "http") || (protocol == "ftp")) &&
      (port >= 1) && (port <= 65535)) {
    setHudMessage("Access DNS check...");
    Address address(hostname); // get the address  (BLOCKING)
    ip = address.getDotNotation();
    setHudMessage("");
  }

  // make the list of strings to check
  std::vector<std::string> nameAndIp;
  if (hostname.size() > 0) {
    nameAndIp.push_back(hostname);
  }
  if (ip.size() > 0) {
    nameAndIp.push_back(ip);
  }

  // check and print error if not authorized
  if (!DownloadAccessList.authorized(nameAndIp)) {
    std::string msg = ColorStrings[RedColor];
    msg += "local server denial: ";
    msg += ColorStrings[GreyColor];
    msg += url;
    addMessage(NULL, msg);
    return false;
  }

  return true;
}

static void setHudMessage(const std::string& msg)
{
  HUDDialogStack::get()->setFailedMessage(msg.c_str());
  drawFrame(0.0f);
  return;
}

/******************************************************************************/
#else // ! HAVE_CURL
/******************************************************************************/

void Downloads::doDownloads()
{
  bool needWarning = false;
  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set);

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {
      needWarning = true;
      // one time warning
      std::string msg = ColorStrings[GreyColor];
      msg += "not downloading: " + texUrl;
      addMessage(NULL, msg);
      // avoid future warnings
      MATERIALMGR.setTextureLocal(texUrl, "");
    }
  }

  if (needWarning && BZDB.isTrue("doDownloads")) {
    std::string msg = ColorStrings[RedColor];
    msg += "Downloads are not available for clients without libcurl";
    addMessage(NULL, msg);
    msg = ColorStrings[YellowColor];
    msg += "To disable this message, disable [Automatic Downloads] in";
    addMessage(NULL, msg);
    msg = ColorStrings[YellowColor];
    msg += "Options -> Cache Options, or get a client with libcurl";
    addMessage(NULL, msg);
  }

  return;
}

bool Downloads::updateDownloads()
{
  std::string msg = ColorStrings[RedColor];
  msg += "Downloads are not available for clients without libcurl";
  addMessage(NULL, msg);
  return false;
}

/******************************************************************************/
#endif // HAVE_CURL
/******************************************************************************/

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>the declaration in dowloads.h is the same for both HAVE_CURL and no HAVE_CURL, yet the definition has two types<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "Downloads.h"

/* common implementation headers */
#include "network.h"
#include "Address.h"
#include "AccessList.h"
#include "CacheManager.h"
#include "BzMaterial.h"
#include "URLManager.h"
#include "AnsiCodes.h"
#include "TextureManager.h"

/* local implementation headers */
#include "playing.h"
#include "HUDDialogStack.h"

// FIXME - someone write a better explanation
static const char DownloadContent[] =
  "#\n"
  "# This file controls the access to servers for downloads.\n"
  "# Patterns are attempted in order against both the hostname\n"
  "# and ip. The first matching pattern sets the state. If no\n"
  "# patterns are matched, then the server is authorized. There\n"
  "# are four types of matches:\n"
  "#\n"
  "#   simple globbing (* and ?)\n"
  "#     allow\n"
  "#     deny\n"
  "#\n"
  "#   regular expressions\n"
  "#     allow_regex\n"
  "#     deny_regex\n"
  "#\n"
  "\n"
  "#\n"
  "# To authorize all servers, remove the last 3 lines.\n"
  "#\n"
  "\n"
  "allow *.bzflag.bz\n"
  "allow *.bzflag.org\n"
  "deny *\n";

static AccessList DownloadAccessList("DownloadAccess.txt", DownloadContent);

/******************************************************************************/
#ifdef HAVE_CURL
/******************************************************************************/

// Function Prototypes
static void printAuthNotice();
static bool getFileTime(const std::string& url, time_t& t);
static bool getAndCacheURL(const std::string& url);
static bool authorizedServer(const std::string& url);
static void setHudMessage(const std::string& msg);

void Downloads::doDownloads()
{
  CACHEMGR.loadIndex();
  CACHEMGR.limitCacheSize();

  DownloadAccessList.reload();

  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, false /* ignore referencing */);

  bool authNotice = false;

  const bool doDownloads =	BZDB.isTrue("doDownloads");
  const bool updateDownloads =  BZDB.isTrue("updateDownloads");

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {

      // check access authorization
      if (!authorizedServer(texUrl)) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        authNotice = true;
        continue;
      }

      // use the cache?
      CacheManager::CacheRecord oldrec;
      if (CACHEMGR.findURL(texUrl, oldrec)) {
        time_t filetime = 0;
        if (doDownloads && updateDownloads) {
          getFileTime(texUrl, filetime);
        }
        if (filetime <= oldrec.date) {
          // use the cached file
          MATERIALMGR.setTextureLocal(texUrl, oldrec.name);
          continue;
        }
      }

      // bail here if we can't download
      if (!doDownloads) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        std::string msg = ColorStrings[GreyColor];
        msg += "not downloading: " + texUrl;
        addMessage(NULL, msg);
        continue;
      }

      // download and cache the URL
      if (getAndCacheURL(texUrl)) {
        const std::string localname = CACHEMGR.getLocalName(texUrl);
        MATERIALMGR.setTextureLocal(texUrl, localname);
      } else {
        MATERIALMGR.setTextureLocal(texUrl, "");
      }
    }
  }

  if (authNotice) {
    printAuthNotice();
  }

  CACHEMGR.saveIndex();

  return;
}

bool Downloads::updateDownloads(bool& rebuild)
{
  CACHEMGR.loadIndex();
  CACHEMGR.limitCacheSize();

  DownloadAccessList.reload();

  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, true /* only referenced materials */);

  TextureManager& TEXMGR = TextureManager::instance();

  rebuild = false;
  bool updated = false;
  bool authNotice = false;

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {

      // check access authorization
      if (!authorizedServer(texUrl)) {
        MATERIALMGR.setTextureLocal(texUrl, "");
        authNotice = true;
        continue;
      }

      // use the cache or update?
      CacheManager::CacheRecord oldrec;
      if (CACHEMGR.findURL(texUrl, oldrec)) {
        time_t filetime;
        getFileTime(texUrl, filetime);
        if (filetime <= oldrec.date) {
          // keep using the cached file
          MATERIALMGR.setTextureLocal(texUrl, oldrec.name);
          if (!TEXMGR.isLoaded(oldrec.name)) {
            rebuild = true;
          }
          continue;
        }
      }

      // download the file and update the cache
      if (getAndCacheURL(texUrl)) {
        updated = true;
        const std::string localname = CACHEMGR.getLocalName(texUrl);
        if (!TEXMGR.isLoaded(localname)) {
          rebuild = true;
        } else {
          TEXMGR.reloadTextureImage(localname); // reload with the new image
        }
        MATERIALMGR.setTextureLocal(texUrl, localname); // if it wasn't cached
      }
    }
  }

  if (authNotice) {
    printAuthNotice();
  }

  CACHEMGR.saveIndex();

  return updated;
}

void Downloads::removeTextures()
{
  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, false /* ignore referencing */);

  TextureManager& TEXMGR = TextureManager::instance();

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {
      const std::string& localname = CACHEMGR.getLocalName(texUrl);
      if (TEXMGR.isLoaded(localname)) {
        TEXMGR.removeTexture(localname);
      }
    }
  }

  return;
}

static void printAuthNotice()
{
  std::string msg = ColorStrings[WhiteColor];
  msg += "NOTE: ";
  msg += ColorStrings[GreyColor];
  msg += "download access is controlled by ";
  msg += ColorStrings[YellowColor];
  msg += DownloadAccessList.getFileName();
  addMessage(NULL, msg);
  return;
}

static bool getFileTime(const std::string& url, time_t& t)
{
  setHudMessage("Download DNS check...");

  URLManager& URLMGR = URLManager::instance();
  if (URLMGR.getURLHeader(url)) {
    URLMGR.getFileTime(t);
    return true;
  } else {
    t = 0;
    return false;
  }

  setHudMessage("");
}

static bool getAndCacheURL(const std::string& url)
{
  bool result = false;

  setHudMessage("Download DNS check...");

  URLManager& URLMGR = URLManager::instance();
  URLMGR.setProgressFunc(curlProgressFunc, NULL);

  std::string msg = ColorStrings[GreyColor];
  msg += "downloading: " + url;
  addMessage(NULL, msg);

  void* urlData;
  unsigned int urlSize;

  if (URLMGR.getURL(url, &urlData, urlSize)) {
    time_t filetime;
    URLMGR.getFileTime(filetime);
    // CACHEMGR generates name, usedDate, and key
    CacheManager::CacheRecord rec;
    rec.url = url;
    rec.size = urlSize;
    rec.date = filetime;
    CACHEMGR.addFile(rec, urlData);
    free(urlData);
    result = true;
  }
  else {
    std::string msg = ColorStrings[RedColor] + "* failure *";
    addMessage(NULL, msg);
    result = false;
  }

  URLMGR.setProgressFunc(NULL, NULL);

  setHudMessage("");

  return result;
}

static bool authorizedServer(const std::string& url)
{
  // avoid the DNS lookup
  if (DownloadAccessList.alwaysAuthorized()) {
    return true;
  }

  // parse url
  std::string protocol, hostname, path, ip;
  int port = 1;
  if (BzfNetwork::parseURL(url, protocol, hostname, port, path) &&
      ((protocol == "http") || (protocol == "ftp")) &&
      (port >= 1) && (port <= 65535)) {
    setHudMessage("Access DNS check...");
    Address address(hostname); // get the address  (BLOCKING)
    ip = address.getDotNotation();
    setHudMessage("");
  }

  // make the list of strings to check
  std::vector<std::string> nameAndIp;
  if (hostname.size() > 0) {
    nameAndIp.push_back(hostname);
  }
  if (ip.size() > 0) {
    nameAndIp.push_back(ip);
  }

  // check and print error if not authorized
  if (!DownloadAccessList.authorized(nameAndIp)) {
    std::string msg = ColorStrings[RedColor];
    msg += "local server denial: ";
    msg += ColorStrings[GreyColor];
    msg += url;
    addMessage(NULL, msg);
    return false;
  }

  return true;
}

static void setHudMessage(const std::string& msg)
{
  HUDDialogStack::get()->setFailedMessage(msg.c_str());
  drawFrame(0.0f);
  return;
}

/******************************************************************************/
#else // ! HAVE_CURL
/******************************************************************************/

void Downloads::doDownloads()
{
  bool needWarning = false;
  BzMaterialManager::TextureSet set;
  BzMaterialManager::TextureSet::iterator set_it;
  MATERIALMGR.makeTextureList(set, true);

  for (set_it = set.begin(); set_it != set.end(); set_it++) {
    const std::string& texUrl = set_it->c_str();
    if (CACHEMGR.isCacheFileType(texUrl)) {
      needWarning = true;
      // one time warning
      std::string msg = ColorStrings[GreyColor];
      msg += "not downloading: " + texUrl;
      addMessage(NULL, msg);
      // avoid future warnings
      MATERIALMGR.setTextureLocal(texUrl, "");
    }
  }

  if (needWarning && BZDB.isTrue("doDownloads")) {
    std::string msg = ColorStrings[RedColor];
    msg += "Downloads are not available for clients without libcurl";
    addMessage(NULL, msg);
    msg = ColorStrings[YellowColor];
    msg += "To disable this message, disable [Automatic Downloads] in";
    addMessage(NULL, msg);
    msg = ColorStrings[YellowColor];
    msg += "Options -> Cache Options, or get a client with libcurl";
    addMessage(NULL, msg);
  }

  return;
}

bool Downloads::updateDownloads(bool& /*rebuild*/)
{
  std::string msg = ColorStrings[RedColor];
  msg += "Downloads are not available for clients without libcurl";
  addMessage(NULL, msg);
  return false;
}

/******************************************************************************/
#endif // HAVE_CURL
/******************************************************************************/

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface headers */
#include "ShotStats.h"
#include "HUDDialog.h"

/* system implementation headers */
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>

/* common implementation headers */
#include "FontManager.h"
#include "StateDatabase.h"

/* local implementation headers */
#include "ShotStatsDefaultKey.h"
#include "HUDDialog.h"
#include "HUDDialogStack.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "ShotStatistics.h"
#include "Player.h"
#include "RemotePlayer.h"
#include "LocalPlayer.h"

/* FIXME */
extern RemotePlayer** player;
extern int curMaxPlayers;

ShotStats::ShotStats() : HUDDialog()
{
  std::vector<HUDuiControl*>& list = getControls();

  // add title
  createLabel("Shot Statistics", list);

  columns = 16;
  rows = 0;

  // section headings
  createLabel("\nPlayer", list);
  createLabel("\nHit%", list);
  createLabel("Total\nFired", list);
  createLabel("Total\nHit", list);
  createLabel("Norm.\nFired", list);
  createLabel("Norm.\nHit", list);
  createLabel("GM\nFired", list);
  createLabel("GM\nHit", list);
  createLabel("Laser\nFired", list);
  createLabel("Laser\nHit", list);
  createLabel("SB\nFired", list);
  createLabel("SB\nHit", list);
  createLabel("SW\nFired", list);
  createLabel("SW\nHit", list);
  createLabel("Thief\nFired", list);
  createLabel("Thief\nHit", list);
  ++rows;

  // my statistics first
  LocalPlayer* myTank = LocalPlayer::getMyTank();
  addStats((Player*)myTank, list);

  // add statistics for each player
  for (int i = 0; i < curMaxPlayers; ++i) {
    if (player[i]) {
      addStats((Player*)player[i], list);
    }
  }

  resize(HUDDialog::getWidth(), HUDDialog::getHeight());
  initNavigation(list, 1, 1);
}

ShotStats::~ShotStats()
{
}

void ShotStats::createLabel(const char* string, std::vector<HUDuiControl*>& list)
{
  HUDuiLabel* control = new HUDuiLabel;
  control->setFontFace(getFontFace());
  control->setString(string);
  list.push_back(control);
}

void ShotStats::addStats(Player* player, std::vector<HUDuiControl*>& list)
{
  char* buffer = new char[32];

  const ShotStatistics* stats = player->getShotStatistics();
  createLabel(player->getCallSign(), list);
  sprintf(buffer, "%2d%%", stats->getTotalPerc());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTotalFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTotalHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getNormalFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getNormalHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getGMFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getGMHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getLFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getLHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSBFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSBHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSWFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSWHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTHFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTHHit());
  createLabel(buffer, list);
  ++rows;

  delete[] buffer;
}

const int		ShotStats::getFontFace()
{
  // create font
  return FontManager::instance().getFaceID(BZDB.get("sansSerifFont"));
}

HUDuiDefaultKey*	ShotStats::getDefaultKey()
{
  return ShotStatsDefaultKey::getInstance();
}

void			ShotStats::execute()
{
  HUDDialogStack::get()->pop();
}

void			ShotStats::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // Reposition everything -- that's gonna be a challenge!

  FontManager &fm = FontManager::instance();

  // set up table
  // total width / (number of columns + 3 columns extra for player name + 2 columns margin)
  const float columnWidth = width / (columns + 5.0f);
  const float fontSize = (float) columnWidth / 6;
  const float rowHeight = fm.getStrHeight(getFontFace(), fontSize, " ") * 1.2f;

  // center title
  const float titleFontSize = (float)height / 15.0f;
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(getFontFace(), titleFontSize, " ");
  const float titleY = (float)height - titleHeight;
  float x = 0.5f * ((float)width - titleWidth);
  float y = titleY;
  title->setPosition(x, y);

  for (int i = 1; i < (int)list.size(); ++i) {
    // determine row & column (i - 1 to account for title)
    int row = (int)floor((i - 1) / columns);
    int column = (i - 1) - (columns * row) + 1;
    // account for 3 extra columns in player name
    if (column > 1)
      column = column + 3;

    // find coordinates corresponding to this row & column
    x = column * columnWidth;
    y = titleY - (row + 1) * rowHeight;
    // headings take up an additional row (embedded newlines)
    if (row > 0) y -= rowHeight;

    // move label to the specified coordinates
    list[i]->setFontSize(fontSize);
    list[i]->setPosition(x, y);
  }

}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>no need for floor<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface headers */
#include "ShotStats.h"
#include "HUDDialog.h"

/* system implementation headers */
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>

/* common implementation headers */
#include "FontManager.h"
#include "StateDatabase.h"

/* local implementation headers */
#include "ShotStatsDefaultKey.h"
#include "HUDDialog.h"
#include "HUDDialogStack.h"
#include "HUDuiControl.h"
#include "HUDuiLabel.h"
#include "ShotStatistics.h"
#include "Player.h"
#include "RemotePlayer.h"
#include "LocalPlayer.h"

/* FIXME */
extern RemotePlayer** player;
extern int curMaxPlayers;

ShotStats::ShotStats() : HUDDialog()
{
  std::vector<HUDuiControl*>& list = getControls();

  // add title
  createLabel("Shot Statistics", list);

  columns = 16;
  rows = 0;

  // section headings
  createLabel("\nPlayer", list);
  createLabel("\nHit%", list);
  createLabel("Total\nFired", list);
  createLabel("Total\nHit", list);
  createLabel("Norm.\nFired", list);
  createLabel("Norm.\nHit", list);
  createLabel("GM\nFired", list);
  createLabel("GM\nHit", list);
  createLabel("Laser\nFired", list);
  createLabel("Laser\nHit", list);
  createLabel("SB\nFired", list);
  createLabel("SB\nHit", list);
  createLabel("SW\nFired", list);
  createLabel("SW\nHit", list);
  createLabel("Thief\nFired", list);
  createLabel("Thief\nHit", list);
  ++rows;

  // my statistics first
  LocalPlayer* myTank = LocalPlayer::getMyTank();
  addStats((Player*)myTank, list);

  // add statistics for each player
  for (int i = 0; i < curMaxPlayers; ++i) {
    if (player[i]) {
      addStats((Player*)player[i], list);
    }
  }

  resize(HUDDialog::getWidth(), HUDDialog::getHeight());
  initNavigation(list, 1, 1);
}

ShotStats::~ShotStats()
{
}

void ShotStats::createLabel(const char* string, std::vector<HUDuiControl*>& list)
{
  HUDuiLabel* control = new HUDuiLabel;
  control->setFontFace(getFontFace());
  control->setString(string);
  list.push_back(control);
}

void ShotStats::addStats(Player* player, std::vector<HUDuiControl*>& list)
{
  char* buffer = new char[32];

  const ShotStatistics* stats = player->getShotStatistics();
  createLabel(player->getCallSign(), list);
  sprintf(buffer, "%2d%%", stats->getTotalPerc());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTotalFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTotalHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getNormalFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getNormalHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getGMFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getGMHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getLFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getLHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSBFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSBHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSWFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getSWHit());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTHFired());
  createLabel(buffer, list);
  sprintf(buffer, "%d", stats->getTHHit());
  createLabel(buffer, list);
  ++rows;

  delete[] buffer;
}

const int		ShotStats::getFontFace()
{
  // create font
  return FontManager::instance().getFaceID(BZDB.get("sansSerifFont"));
}

HUDuiDefaultKey*	ShotStats::getDefaultKey()
{
  return ShotStatsDefaultKey::getInstance();
}

void			ShotStats::execute()
{
  HUDDialogStack::get()->pop();
}

void			ShotStats::resize(int width, int height)
{
  HUDDialog::resize(width, height);

  // Reposition everything -- that's gonna be a challenge!

  FontManager &fm = FontManager::instance();

  // set up table
  // total width / (number of columns + 3 columns extra for player name + 2 columns margin)
  const float columnWidth = width / (columns + 5.0f);
  const float fontSize = (float) columnWidth / 6;
  const float rowHeight = fm.getStrHeight(getFontFace(), fontSize, " ") * 1.2f;

  // center title
  const float titleFontSize = (float)height / 15.0f;
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(getFontFace(), titleFontSize, " ");
  const float titleY = (float)height - titleHeight;
  float x = 0.5f * ((float)width - titleWidth);
  float y = titleY;
  title->setPosition(x, y);

  for (int i = 1; i < (int)list.size(); ++i) {
    // determine row & column (i - 1 to account for title)
    int row = (i - 1) / columns;
    int column = (i - 1) - (columns * row) + 1;
    // account for 3 extra columns in player name
    if (column > 1)
      column = column + 3;

    // find coordinates corresponding to this row & column
    x = column * columnWidth;
    y = titleY - (row + 1) * rowHeight;
    // headings take up an additional row (embedded newlines)
    if (row > 0) y -= rowHeight;

    // move label to the specified coordinates
    list[i]->setFontSize(fontSize);
    list[i]->setPosition(x, y);
  }

}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>