<commit_before>// $Id$
//
//  Copyright (C) 2001-2006 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#include "Bond.h"
#include "Atom.h"
#include "ROMol.h"
#include <RDGeneral/Invariant.h>

namespace RDKit {

Bond::Bond() {
  initBond();
};

Bond::Bond(BondType bT) {
  initBond();
  d_bondType = bT;
};

Bond::Bond(const Bond &other){
  // NOTE: we do *not* copy ownership!
  dp_mol = 0;
  d_bondType = other.d_bondType;
  d_beginAtomIdx = other.d_beginAtomIdx;
  d_endAtomIdx = other.d_endAtomIdx;
  d_dirTag = other.d_dirTag;
  d_stereo = other.d_stereo;
  d_stereoAtoms = other.d_stereoAtoms;
  df_isAromatic = other.df_isAromatic;
  df_isConjugated = other.df_isConjugated;
  d_index = other.d_index;
  if(other.dp_props){
    dp_props = new Dict(*other.dp_props);
  } else {
    dp_props = new Dict();
    //STR_VECT computed;
    //dp_props->setVal("computedProps", computed);
  }
}

Bond::~Bond()
{
  if(dp_props) delete dp_props;
}

Bond &Bond::operator=(const Bond &other){
  // FIX: should we copy molecule ownership?  I don't think so.
  // FIX: how to deal with atom indices?
  initBond();
  dp_mol = other.dp_mol;
  d_bondType = other.d_bondType;
  d_beginAtomIdx = other.d_beginAtomIdx;
  d_endAtomIdx = other.d_endAtomIdx;
  d_dirTag = other.d_dirTag;
  d_stereoAtoms = other.d_stereoAtoms;
  df_isAromatic = other.df_isAromatic;
  df_isConjugated = other.df_isConjugated;
  d_index = other.d_index;
  if(dp_props) delete dp_props;
  if(other.dp_props)
    dp_props = new Dict(*other.dp_props);
  return *this;
}

Bond *Bond::copy() const {
  Bond *res = new Bond(*this);
  return res;
}

void Bond::setOwningMol(ROMol *other)
{
  // FIX: doesn't update topology
  dp_mol = other;
}

unsigned int Bond::getOtherAtomIdx(const unsigned int thisIdx) const
{
  PRECONDITION(d_beginAtomIdx == thisIdx ||
	       d_endAtomIdx == thisIdx, "bad index");
  if( d_beginAtomIdx == thisIdx ) return d_endAtomIdx;
  else if (d_endAtomIdx == thisIdx) return d_beginAtomIdx;
  // we cannot actually get down here
  return 0;
}

void Bond::setBeginAtomIdx(unsigned int what) {
  if(dp_mol) RANGE_CHECK(0,what,getOwningMol().getNumAtoms()-1);
  d_beginAtomIdx = what;
};

void Bond::setEndAtomIdx(unsigned int what) {
  if(dp_mol) RANGE_CHECK(0,what,getOwningMol().getNumAtoms()-1);
  d_endAtomIdx = what;
};

void Bond::setBeginAtom(Atom *at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setBeginAtomIdx(at->getIdx());
}
void Bond::setBeginAtom(Atom::ATOM_SPTR at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setBeginAtomIdx(at->getIdx());
}

void Bond::setEndAtom(Atom *at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setEndAtomIdx(at->getIdx());
}
void Bond::setEndAtom(Atom::ATOM_SPTR at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setEndAtomIdx(at->getIdx());
}

  Atom *Bond::getBeginAtom() const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");
    return dp_mol->getAtomWithIdx(d_beginAtomIdx);
  };
  Atom *Bond::getEndAtom() const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");
    return dp_mol->getAtomWithIdx(d_endAtomIdx);
  };
  Atom *Bond::getOtherAtom(Atom const *what) const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");

    return dp_mol->getAtomWithIdx(getOtherAtomIdx(what->getIdx()));
  };

double Bond::getBondTypeAsDouble() const {
  switch(getBondType()){
  case UNSPECIFIED: return 0; break;
  case IONIC: return 0; break;
  case SINGLE: return 1; break;
  case DOUBLE: return 2; break;
  case TRIPLE: return 3; break;
  case QUADRUPLE: return 4; break;
  case QUINTUPLE: return 5; break;
  case HEXTUPLE: return 6; break;
  case ONEANDAHALF: return 1.5; break;
  case TWOANDAHALF: return 2.5; break;
  case THREEANDAHALF: return 3.5; break;
  case FOURANDAHALF: return 4.5; break;
  case FIVEANDAHALF: return 5.5; break;
  case AROMATIC: return 1.5; break;
  case DATIVEONE: return 1.0; break; // FIX: this should probably be different
  case DATIVE: return 1.0; break; //FIX: again probably wrong
  default:
    UNDER_CONSTRUCTION("Bad bond type");
  }
}

double Bond::getValenceContrib(Atom::ATOM_SPTR at) const {
  return getValenceContrib(at.get());
}

double Bond::getValenceContrib(const Atom *atom) const {
  switch(getBondType()){
  case UNSPECIFIED: return 0; break;
  case IONIC: return 0; break;
  case SINGLE: return 1; break;
  case DOUBLE: return 2; break;
  case TRIPLE: return 3; break;
  case QUADRUPLE: return 4; break;
  case QUINTUPLE: return 5; break;
  case HEXTUPLE: return 6; break;
  case ONEANDAHALF: return 1.5; break;
  case TWOANDAHALF: return 2.5; break;
  case THREEANDAHALF: return 3.5; break;
  case FOURANDAHALF: return 4.5; break;
  case FIVEANDAHALF: return 5.5; break;
  case AROMATIC: return 1.5; break;
  case DATIVEONE:
    if(atom->getIdx()==getEndAtomIdx())return 1.0;
    else return 0.0;
    break;
  case DATIVE:
    if(atom->getIdx()==getEndAtomIdx())return 1.0;
    else return 0.0;
    break;
  default:
    UNDER_CONSTRUCTION("Bad bond type");

  }
}

void Bond::setQuery(QUERYBOND_QUERY *what) {
  //  Bonds don't have queries at the moment because I have not
  //  yet figured out what a good base query should be.
  //  It would be nice to be able to do substructure searches
  //  using molecules alone, so it'd be nice if we got this
  //  issue resolved ASAP.
  PRECONDITION(0,"plain bonds have no Query");
}

Bond::QUERYBOND_QUERY *Bond::getQuery() const {
  PRECONDITION(0,"plain bonds have no Query");
  return NULL;
};

bool Bond::Match(Bond const *what) const{
  bool res;
  if(getBondType()==Bond::UNSPECIFIED ||
     what->getBondType()==Bond::UNSPECIFIED){
    res = true;
  } else {
    res = getBondType() == what->getBondType();
  }
  return res;
};

bool Bond::Match(const Bond::BOND_SPTR what) const {
  return Match(what.get());
};

void Bond::expandQuery(Bond::QUERYBOND_QUERY *what,
		       Queries::CompositeQueryType how,
		       bool maintainOrder) {
  PRECONDITION(0,"plain bonds have no query");
};

void Bond::initBond(){
  d_bondType = UNSPECIFIED;
  d_dirTag = NONE;
  d_stereo = STEREONONE;
  d_stereoAtoms.clear();
  dp_mol = 0;
  d_beginAtomIdx = 0;
  d_endAtomIdx = 0;
  df_isAromatic = 0;
  d_index = 0;
  df_isConjugated = 0;
  dp_props = new Dict();
  // ok every bond contains a property entry called "computedProps" which provides
  //  list of property keys that correspond to value that have been computed
  // this can used to blow out all computed properties while leaving the rest along
  // initialize this list to an empty vector of strings
  //STR_VECT computed;
  //dp_props->setVal("computedProps", computed);

};

}; // end o' namespace

std::ostream & operator<<(std::ostream& target, const RDKit::Bond &bond){
  target << bond.getIdx() << " ";
  target << bond.getBeginAtomIdx() << "->" << bond.getEndAtomIdx();
  target << " order: " << bond.getBondType();
  if(bond.getBondDir())
    target << " dir: " << bond.getBondDir();
  if(bond.getStereo())
    target << " stereo: " << bond.getStereo();
  target << " conj?: " << bond.getIsConjugated();
  target << " aromatic?: " << bond.getIsAromatic();

  return target;
}
<commit_msg>some speedups<commit_after>// $Id$
//
//  Copyright (C) 2001-2010 Greg Landrum and Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#include "Bond.h"
#include "Atom.h"
#include "ROMol.h"
#include <RDGeneral/Invariant.h>

namespace RDKit {

Bond::Bond() {
  initBond();
  dp_props = new Dict();
};

Bond::Bond(BondType bT) {
  initBond();
  d_bondType = bT;
  dp_props = new Dict();
};

Bond::Bond(const Bond &other){
  // NOTE: we do *not* copy ownership!
  dp_mol = 0;
  d_bondType = other.d_bondType;
  d_beginAtomIdx = other.d_beginAtomIdx;
  d_endAtomIdx = other.d_endAtomIdx;
  d_dirTag = other.d_dirTag;
  d_stereo = other.d_stereo;
  d_stereoAtoms = other.d_stereoAtoms;
  df_isAromatic = other.df_isAromatic;
  df_isConjugated = other.df_isConjugated;
  d_index = other.d_index;
  if(other.dp_props){
    dp_props = new Dict(*other.dp_props);
  } else {
    dp_props = new Dict();
  }
}

Bond::~Bond()
{
  if(dp_props) delete dp_props;
}

Bond &Bond::operator=(const Bond &other){
  dp_mol = other.dp_mol;
  d_bondType = other.d_bondType;
  d_beginAtomIdx = other.d_beginAtomIdx;
  d_endAtomIdx = other.d_endAtomIdx;
  d_dirTag = other.d_dirTag;
  d_stereoAtoms = other.d_stereoAtoms;
  df_isAromatic = other.df_isAromatic;
  df_isConjugated = other.df_isConjugated;
  d_index = other.d_index;
  if(other.dp_props){
    dp_props = new Dict(*other.dp_props);
  }else{
    dp_props = new Dict();
  }

  return *this;
}

Bond *Bond::copy() const {
  Bond *res = new Bond(*this);
  return res;
}

void Bond::setOwningMol(ROMol *other)
{
  // FIX: doesn't update topology
  dp_mol = other;
}

unsigned int Bond::getOtherAtomIdx(const unsigned int thisIdx) const
{
  PRECONDITION(d_beginAtomIdx == thisIdx ||
	       d_endAtomIdx == thisIdx, "bad index");
  if( d_beginAtomIdx == thisIdx ) return d_endAtomIdx;
  else if (d_endAtomIdx == thisIdx) return d_beginAtomIdx;
  // we cannot actually get down here
  return 0;
}

void Bond::setBeginAtomIdx(unsigned int what) {
  if(dp_mol) RANGE_CHECK(0,what,getOwningMol().getNumAtoms()-1);
  d_beginAtomIdx = what;
};

void Bond::setEndAtomIdx(unsigned int what) {
  if(dp_mol) RANGE_CHECK(0,what,getOwningMol().getNumAtoms()-1);
  d_endAtomIdx = what;
};

void Bond::setBeginAtom(Atom *at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setBeginAtomIdx(at->getIdx());
}
void Bond::setBeginAtom(Atom::ATOM_SPTR at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setBeginAtomIdx(at->getIdx());
}

void Bond::setEndAtom(Atom *at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setEndAtomIdx(at->getIdx());
}
void Bond::setEndAtom(Atom::ATOM_SPTR at) {
  PRECONDITION( dp_mol != 0, "no owning molecule for bond");
  setEndAtomIdx(at->getIdx());
}

  Atom *Bond::getBeginAtom() const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");
    return dp_mol->getAtomWithIdx(d_beginAtomIdx);
  };
  Atom *Bond::getEndAtom() const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");
    return dp_mol->getAtomWithIdx(d_endAtomIdx);
  };
  Atom *Bond::getOtherAtom(Atom const *what) const {
    PRECONDITION( dp_mol != 0, "no owning molecule for bond");

    return dp_mol->getAtomWithIdx(getOtherAtomIdx(what->getIdx()));
  };

double Bond::getBondTypeAsDouble() const {
  switch(getBondType()){
  case UNSPECIFIED: return 0; break;
  case IONIC: return 0; break;
  case SINGLE: return 1; break;
  case DOUBLE: return 2; break;
  case TRIPLE: return 3; break;
  case QUADRUPLE: return 4; break;
  case QUINTUPLE: return 5; break;
  case HEXTUPLE: return 6; break;
  case ONEANDAHALF: return 1.5; break;
  case TWOANDAHALF: return 2.5; break;
  case THREEANDAHALF: return 3.5; break;
  case FOURANDAHALF: return 4.5; break;
  case FIVEANDAHALF: return 5.5; break;
  case AROMATIC: return 1.5; break;
  case DATIVEONE: return 1.0; break; // FIX: this should probably be different
  case DATIVE: return 1.0; break; //FIX: again probably wrong
  default:
    UNDER_CONSTRUCTION("Bad bond type");
  }
}

double Bond::getValenceContrib(Atom::ATOM_SPTR at) const {
  return getValenceContrib(at.get());
}

double Bond::getValenceContrib(const Atom *atom) const {
  switch(getBondType()){
  case UNSPECIFIED: return 0; break;
  case IONIC: return 0; break;
  case SINGLE: return 1; break;
  case DOUBLE: return 2; break;
  case TRIPLE: return 3; break;
  case QUADRUPLE: return 4; break;
  case QUINTUPLE: return 5; break;
  case HEXTUPLE: return 6; break;
  case ONEANDAHALF: return 1.5; break;
  case TWOANDAHALF: return 2.5; break;
  case THREEANDAHALF: return 3.5; break;
  case FOURANDAHALF: return 4.5; break;
  case FIVEANDAHALF: return 5.5; break;
  case AROMATIC: return 1.5; break;
  case DATIVEONE:
    if(atom->getIdx()==getEndAtomIdx())return 1.0;
    else return 0.0;
    break;
  case DATIVE:
    if(atom->getIdx()==getEndAtomIdx())return 1.0;
    else return 0.0;
    break;
  default:
    UNDER_CONSTRUCTION("Bad bond type");

  }
}

void Bond::setQuery(QUERYBOND_QUERY *what) {
  //  Bonds don't have queries at the moment because I have not
  //  yet figured out what a good base query should be.
  //  It would be nice to be able to do substructure searches
  //  using molecules alone, so it'd be nice if we got this
  //  issue resolved ASAP.
  PRECONDITION(0,"plain bonds have no Query");
}

Bond::QUERYBOND_QUERY *Bond::getQuery() const {
  PRECONDITION(0,"plain bonds have no Query");
  return NULL;
};

bool Bond::Match(Bond const *what) const{
  bool res;
  if(getBondType()==Bond::UNSPECIFIED ||
     what->getBondType()==Bond::UNSPECIFIED){
    res = true;
  } else {
    res = getBondType() == what->getBondType();
  }
  return res;
};

bool Bond::Match(const Bond::BOND_SPTR what) const {
  return Match(what.get());
};

void Bond::expandQuery(Bond::QUERYBOND_QUERY *what,
		       Queries::CompositeQueryType how,
		       bool maintainOrder) {
  PRECONDITION(0,"plain bonds have no query");
};

void Bond::initBond(){
  d_bondType = UNSPECIFIED;
  d_dirTag = NONE;
  d_stereo = STEREONONE;
  d_stereoAtoms.clear();
  dp_mol = 0;
  d_beginAtomIdx = 0;
  d_endAtomIdx = 0;
  df_isAromatic = 0;
  d_index = 0;
  df_isConjugated = 0;
};

}; // end o' namespace

std::ostream & operator<<(std::ostream& target, const RDKit::Bond &bond){
  target << bond.getIdx() << " ";
  target << bond.getBeginAtomIdx() << "->" << bond.getEndAtomIdx();
  target << " order: " << bond.getBondType();
  if(bond.getBondDir())
    target << " dir: " << bond.getBondDir();
  if(bond.getStereo())
    target << " stereo: " << bond.getStereo();
  target << " conj?: " << bond.getIsConjugated();
  target << " aromatic?: " << bond.getIsAromatic();

  return target;
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS changefileheader (1.36.166); FILE MERGED 2008/04/01 15:36:39 thb 1.36.166.3: #i85898# Stripping all external header guards 2008/04/01 12:39:42 thb 1.36.166.2: #i85898# Stripping all external header guards 2008/03/31 13:59:14 rt 1.36.166.1: #i87441# Change license header to LPGL v3.<commit_after><|endoftext|>


<commit_before>/*
    Copyright (C) 2000 by Jorrit Tyberghein
    With additions by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/system.h"
#include "csutil/inifile.h"
#include "apps/perftest/perftest.h"
#include "apps/perftest/ptests3d.h"
#include "apps/perftest/ptests2d.h"
#include "csgfxldr/csimage.h"
#include "igraph3d.h"
#include "itxtmgr.h"
#include "iconsole.h"

//------------------------------ We need the VFS plugin -----------------------

REGISTER_STATIC_LIBRARY (vfs)

//-----------------------------------------------------------------------------

PerfTest::PerfTest ()
{
  draw_3d = true;
  draw_2d = true;
}

PerfTest::~PerfTest ()
{
}

void cleanup ()
{
  System->console_out ("Cleaning up...\n");
  delete System;
}

iMaterialHandle* PerfTest::LoadMaterial (char* file)
{
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  size_t size;
  char* buf;
  iImage* image;
  buf = VFS->ReadFile (file, size);
  if (!buf || !size)
  {
    Printf (MSG_FATAL_ERROR, "Error loading texture '%s'!\n", file);
    exit (-1);
  }
  image = csImageLoader::Load ((UByte*)buf, size,
  	txtmgr->GetTextureFormat ());
  delete [] buf;
  if (!image) exit (-1);
  iTextureHandle* texture = txtmgr->RegisterTexture (image, CS_TEXTURE_3D);
  if (!texture) exit (-1);
  image->DecRef ();
  iMaterialHandle* mat = txtmgr->RegisterMaterial (texture);
  return mat;
}

bool PerfTest::Initialize (int argc, const char* const argv[],
  const char *iConfigName)
{
  if (!superclass::Initialize (argc, argv, iConfigName))
    return false;

  // Open the main system. This will open all the previously loaded plug-ins.
  if (!Open ("Crystal Space Graphics Performance Tester"))
  {
    Printf (MSG_FATAL_ERROR, "Error opening system!\n");
    cleanup ();
    exit (1);
  }

  // Setup the texture manager
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  txtmgr->SetVerbose (true);

  // Initialize the texture manager
  txtmgr->ResetPalette ();

  // Initialize textures.
  materials[0] = LoadMaterial ("/lib/std/stone4.gif");
  materials[1] = LoadMaterial ("/lib/std/mystone2.gif");
  materials[2] = LoadMaterial ("/lib/std/andrew_marble4.gif");
  materials[3] = LoadMaterial ("/lib/std/andrew_wood.gif");
  txtmgr->PrepareTextures ();

  // Allocate a uniformly distributed in R,G,B space palette for console
  // The console will crash on some platforms if this isn't initialize properly
  int r,g,b;
  for (r = 0; r < 8; r++)
    for (g = 0; g < 8; g++)
      for (b = 0; b < 4; b++)
	txtmgr->ReserveColor (r * 32, g * 32, b * 64);
  txtmgr->SetPalette ();

  // Initialize the console
  if (Console != NULL)
    // Don't let messages before this one appear
    Console->Clear ();

  // Some commercials...
  Printf (MSG_INITIALIZATION,
    "Crystal Space 3D Performance Tester 0.1.\n");

  txtmgr->SetPalette ();

  const char *val;
  if ((val = GetOptionCL ("2d")))
  {
    current_tester = new StringTester ();
    draw_3d = false;
  }
  else
    current_tester = new SinglePolygonTester ();

  if ((val = GetOptionCL ("3d")))
    draw_2d = false;

  needs_setup = true;

  return true;
}

static time_t last_time;

void PerfTest::NextFrame ()
{
  SysSystemDriver::NextFrame ();
  time_t elapsed_time, current_time;
  GetElapsedTime (elapsed_time, current_time);

  // Tell 3D driver we're going to display 3D things.
  if (!G3D->BeginDraw (draw_3d ? CSDRAW_3DGRAPHICS : CSDRAW_2DGRAPHICS))
    return;

  // Setup if needed.
  if (needs_setup)
  {
    current_tester->Setup (G3D, this);
    last_time = current_time;
  }

  // Do the test frame.
  if (current_tester)
  {
    current_tester->Draw (G3D);
    if (current_time-last_time >= 10000)
    {
      Printf (MSG_INITIALIZATION, "%f FPS\n",
      	current_tester->GetCount ()/10.);
      Tester* next_tester = current_tester->NextTester ();
      delete current_tester;
      current_tester = next_tester;
      if (current_tester)
      {
        needs_setup = true;
	current_tester->Setup (G3D, this);
      }
      else
      {
	if (draw_3d && draw_2d)
	{
	  draw_3d = false;
	  current_tester = new LineTester2D ();
	  needs_setup = true;
	  current_tester->Setup (G3D, this);
	}
	else
	  StartShutdown ();
      }
    }
  }

  // Start drawing 2D graphics.
  if (needs_setup)
  {
    if (!G3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;
    Console->Clear ();
    last_time = current_time;
    char desc[255];
    current_tester->Description (desc);
    Printf (MSG_INITIALIZATION, desc);
    needs_setup = false;
  }

  // Drawing code ends here.
  G3D->FinishDraw ();
  // Print the final output.
  G3D->Print (NULL);
}

bool PerfTest::HandleEvent (csEvent &Event)
{
  if (superclass::HandleEvent (Event))
    return true;

  if ((Event.Type == csevKeyDown) && (Event.Key.Code == CSKEY_ESC))
  {
    StartShutdown ();
    return true;
  }
  else if ((Event.Type == csevKeyDown) && (Event.Key.Code == ' '))
  {
    last_time -= 10000;
    return true;
  }

  return false;
}

/*---------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  srand (time (NULL));

  // Create our main class.
  System = new PerfTest ();

  // We want at least the minimal set of plugins
  System->RequestPlugin ("crystalspace.kernel.vfs:VFS");
  System->RequestPlugin ("crystalspace.graphics3d.software:VideoDriver");
  System->RequestPlugin ("crystalspace.console.stdout:Console");

  // Initialize the main system. This will load all needed plug-ins
  // (3D, 2D, network, sound, ...) and initialize them.
  if (!System->Initialize (argc, argv, NULL))
  {
    System->Printf (MSG_FATAL_ERROR, "Error initializing system!\n");
    cleanup ();
    exit (1);
  }

  // Main loop.
  System->Loop ();

  // Cleanup.
  cleanup ();

  return 0;
}
<commit_msg>now works again<commit_after>/*
    Copyright (C) 2000 by Jorrit Tyberghein
    With additions by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/system.h"
#include "csutil/inifile.h"
#include "apps/perftest/perftest.h"
#include "apps/perftest/ptests3d.h"
#include "apps/perftest/ptests2d.h"
#include "csgfxldr/csimage.h"
#include "igraph3d.h"
#include "itxtmgr.h"
#include "iconsole.h"

//------------------------------ We need the VFS plugin -----------------------

REGISTER_STATIC_LIBRARY (vfs)

//-----------------------------------------------------------------------------

PerfTest::PerfTest ()
{
  draw_3d = true;
  draw_2d = true;
}

PerfTest::~PerfTest ()
{
}

void cleanup ()
{
  System->console_out ("Cleaning up...\n");
  delete System;
}

iMaterialHandle* PerfTest::LoadMaterial (char* file)
{
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  size_t size;
  char* buf;
  iImage* image;
  buf = VFS->ReadFile (file, size);
  if (!buf || !size)
  {
    Printf (MSG_FATAL_ERROR, "Error loading texture '%s'!\n", file);
    exit (-1);
  }
  image = csImageLoader::Load ((UByte*)buf, size,
  	txtmgr->GetTextureFormat ());
  delete [] buf;
  if (!image) exit (-1);
  iTextureHandle* texture = txtmgr->RegisterTexture (image, CS_TEXTURE_3D);
  if (!texture) exit (-1);
  image->DecRef ();
  iMaterialHandle* mat = txtmgr->RegisterMaterial (texture);
  return mat;
}

bool PerfTest::Initialize (int argc, const char* const argv[],
  const char *iConfigName)
{
  if (!superclass::Initialize (argc, argv, iConfigName))
    return false;

  // Open the main system. This will open all the previously loaded plug-ins.
  if (!Open ("Crystal Space Graphics Performance Tester"))
  {
    Printf (MSG_FATAL_ERROR, "Error opening system!\n");
    cleanup ();
    exit (1);
  }

  // Setup the texture manager
  iTextureManager* txtmgr = G3D->GetTextureManager ();
  txtmgr->SetVerbose (true);

  // Initialize the texture manager
  txtmgr->ResetPalette ();

  // Initialize textures.
  materials[0] = LoadMaterial ("/lib/std/stone4.gif");
  materials[1] = LoadMaterial ("/lib/std/mystone2.gif");
  materials[2] = LoadMaterial ("/lib/std/andrew_marble4.gif");
  materials[3] = LoadMaterial ("/lib/std/andrew_wood.gif");
  txtmgr->PrepareTextures ();

  // Allocate a uniformly distributed in R,G,B space palette for console
  // The console will crash on some platforms if this isn't initialize properly
  int r,g,b;
  for (r = 0; r < 8; r++)
    for (g = 0; g < 8; g++)
      for (b = 0; b < 4; b++)
	txtmgr->ReserveColor (r * 32, g * 32, b * 64);
  txtmgr->SetPalette ();

  // Initialize the console
  if (Console != NULL)
    // Don't let messages before this one appear
    Console->Clear ();

  // Some commercials...
  Printf (MSG_INITIALIZATION,
    "Crystal Space 3D Performance Tester 0.1.\n");

  txtmgr->SetPalette ();

  const char *val;
  if ((val = GetOptionCL ("2d")))
  {
    current_tester = new StringTester ();
    draw_3d = false;
  }
  else
    current_tester = new SinglePolygonTester ();

  if ((val = GetOptionCL ("3d")))
    draw_2d = false;

  needs_setup = true;

  return true;
}

static time_t last_time;

void PerfTest::NextFrame ()
{
  SysSystemDriver::NextFrame ();
  time_t elapsed_time, current_time;
  GetElapsedTime (elapsed_time, current_time);

  // Tell 3D driver we're going to display 3D things.
  if (!G3D->BeginDraw (draw_3d ? CSDRAW_3DGRAPHICS : CSDRAW_2DGRAPHICS))
    return;

  // Setup if needed.
  if (needs_setup)
  {
    current_tester->Setup (G3D, this);
    last_time = current_time;
  }

  // Do the test frame.
  if (current_tester)
  {
    current_tester->Draw (G3D);
    if (current_time-last_time >= 10000)
    {
      Printf (MSG_INITIALIZATION, "%f FPS\n",
      	current_tester->GetCount ()/10.);
      Tester* next_tester = current_tester->NextTester ();
      delete current_tester;
      current_tester = next_tester;
      if (current_tester)
      {
        needs_setup = true;
	current_tester->Setup (G3D, this);
      }
      else
      {
	if (draw_3d && draw_2d)
	{
	  draw_3d = false;
	  current_tester = new LineTester2D ();
	  needs_setup = true;
	  current_tester->Setup (G3D, this);
	}
	else
	  Shutdown = true;
      }
    }
  }

  // Start drawing 2D graphics.
  if (needs_setup)
  {
    if (!G3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;
    if (Console) Console->Clear ();
    last_time = current_time;
    char desc[255];
    current_tester->Description (desc);
    Printf (MSG_INITIALIZATION, desc);
    needs_setup = false;
  }

  // Drawing code ends here.
  G3D->FinishDraw ();
  // Print the final output.
  G3D->Print (NULL);
}

bool PerfTest::HandleEvent (csEvent &Event)
{
  if (superclass::HandleEvent (Event))
    return true;

  if ((Event.Type == csevKeyDown) && (Event.Key.Code == CSKEY_ESC))
  {
    Shutdown = true;
    return true;
  }
  else if ((Event.Type == csevKeyDown) && (Event.Key.Code == ' '))
  {
    last_time -= 10000;
    return true;
  }

  return false;
}

/*---------------------------------------------------------------------*
 * Main function
 *---------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  srand (time (NULL));

  // Create our main class.
  System = new PerfTest ();

  // We want at least the minimal set of plugins
  System->RequestPlugin ("crystalspace.kernel.vfs:VFS");
  System->RequestPlugin ("crystalspace.graphics3d.software:VideoDriver");
  System->RequestPlugin ("crystalspace.console.stdout:Console");

  // Initialize the main system. This will load all needed plug-ins
  // (3D, 2D, network, sound, ...) and initialize them.
  if (!System->Initialize (argc, argv, NULL))
  {
    System->Printf (MSG_FATAL_ERROR, "Error initializing system!\n");
    cleanup ();
    exit (1);
  }

  // Main loop.
  System->Loop ();

  // Cleanup.
  cleanup ();

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS components1 (1.57.94); FILE MERGED 2007/01/29 17:35:57 af 1.57.94.11: #i68075# New RelocateToParentWindow() method. 2007/01/29 15:27:09 af 1.57.94.10: #68075# Resolved resync problems. 2007/01/25 15:43:06 af 1.57.94.9: RESYNC: (1.61-1.64); FILE MERGED 2006/11/21 16:32:04 af 1.57.94.8: RESYNC: (1.60-1.61); FILE MERGED 2006/11/21 09:42:33 af 1.57.94.7: RESYNC: (1.59-1.60); FILE MERGED 2006/11/16 15:32:57 af 1.57.94.6: #i68075# Optimizations to increase start-up performance. 2006/09/25 17:50:57 af 1.57.94.5: RESYNC: (1.57-1.59); FILE MERGED 2006/09/21 09:16:47 af 1.57.94.4: #i68075# Not calling SfxViewShell::SetWindow() anymore. 2006/09/15 09:48:44 af 1.57.94.3: #i68075# The SfxViewShell::SetWindow() method is not called anymore.  Removed the arguments from Resize(). 2006/08/28 14:48:40 af 1.57.94.2: #i68075# Removed unused header. 2006/08/22 13:35:49 af 1.57.94.1: #i68075# Transition to new drawing framework.<commit_after><|endoftext|>


<commit_before>#ifndef SHADOWS_H
#define SHADOWS_H

extern long OptimiseOTagR(unsigned long* ot, int nOTSize);

#endif
<commit_msg>S_DrawGouraudBar extern<commit_after>#ifndef SHADOWS_H
#define SHADOWS_H

extern void S_DrawGouraudBar(int unk00, int unk01, int unk02, int time, struct GouraudBarColourSet* colour);
extern long OptimiseOTagR(unsigned long* ot, int nOTSize);

#endif
<|endoftext|>


<commit_before><commit_msg><commit_after><|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  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.
 *
 *  @file TimeCalibTools.cpp
 */

#include <boost/algorithm/string/predicate.hpp> /// for starts_with
#include <algorithm> /// for any_of()
#include <sstream>
#include "TimeCalibTools.h"
#include "JPetLoggerInclude.h"

double TimeCalibTools::getTimeCalibCorrection(const TOMBChToCorrection& timeCalibration, const unsigned int channel)
{
  if (timeCalibration.find(channel) == timeCalibration.end()) {
    WARNING("No time calibration available for this channel");
    return 0.0;
  } else {
    return timeCalibration.at(channel);
  }
}

TimeCalibTools::TOMBChToCorrection TimeCalibTools::loadTimeCalibration(const std::string& calibFile, const TimeCalibTools::TOMBChMap& tombMap)
{
  INFO("Loading time calibration from:" + calibFile);
  auto calibRecords = readCalibrationRecordsFromFile(calibFile);
  return generateTimeCalibration(calibRecords, tombMap);
}

TimeCalibTools::TOMBChToCorrection TimeCalibTools::generateTimeCalibration(const std::vector<TimeCalibRecord>& calibRecords,  const TimeCalibTools::TOMBChMap& tombMap)
{
  TOMBChToCorrection timeCalibration;
  if (areCorrectTimeCalibRecords(calibRecords)) {
    std::transform(calibRecords.begin(),
                   calibRecords.end(),
                   std::inserter(timeCalibration, timeCalibration.begin()),
    [&tombMap](const TimeCalibRecord & r) {
      auto key = std::make_tuple(r.layer, r.slot, r.side, r.threshold);
      auto correction = r.offset_value_leading;
      if (tombMap.find(key) != tombMap.end()) {
        auto tombCh = tombMap.at(key);
        return std::make_pair(tombCh, correction);
      } else {
        ERROR("No TOMB channel number in TOMB MAP for the combination: layer=" + std::to_string(r.layer) + ",slot=" + std::to_string(r.slot) + ",side=" + std::to_string(r.side) + ",threshold=" + std::to_string(r.threshold));
        return std::make_pair(-1, 0.0);
      }
    });
  } else {
    ERROR("Empty calibration will be returned");
  }
  return timeCalibration;
}

std::vector<TimeCalibRecord> TimeCalibTools::readCalibrationRecordsFromFile(const std::string& calibFile)
{
  using namespace std;
  namespace ba = boost::algorithm;

  std::vector<TimeCalibRecord> timeCalibRecords;
  string line;
  TimeCalibRecord record = { -1, -1, JPetPM::SideA, -1, 0.0, -1.0, 0.0, -1.0, -1.0 };
  ifstream inputFile(calibFile);

  while (getline(inputFile, line)) {
    /// Lines starting with # are comments and they are ignored.
    if (ba::starts_with(line, "#")) {
      continue;
    } else {
      if (fillTimeCalibRecord(line, record)) {
        timeCalibRecords.push_back(record);
      } else {
        ERROR("Line from the time calibration file seems to be incorrect:" + line);
      }
    }
  }
  return timeCalibRecords;
}

bool TimeCalibTools::areCorrectTimeCalibRecords(const std::vector<TimeCalibRecord>& records)
{
  const auto kMinSlot = 1;
  const auto kMaxSlot = 96;
  const auto kMinLayer = 1;
  const auto kMaxLayer = 3;
  const auto kMinThr = 1;
  const auto kMaxThr = 4;
  return ! std::any_of(
           records.begin(),
           records.end(),
  [](const TimeCalibRecord & r) {
    return ((r.layer < kMinLayer) ||
            (r.layer > kMaxLayer) ||
            (r.slot < kMinSlot) ||
            (r.slot > kMaxSlot) ||
            (r.threshold < kMinThr) ||
            (r.threshold > kMaxThr)
           );
  });
}

bool TimeCalibTools::fillTimeCalibRecord(const std::string& input, TimeCalibRecord& outRecord)
{
  using namespace std;
  int layer = -1;
  int slot = -1;
  char side = 'A';
  int thr = -1;
  double o_val_lead = 0;
  double o_uncert_lead = 0;
  double o_val_trail = 0;
  double o_uncert_trail = 0;
  double quality = 0;
  istringstream ss(input);
  ss >> layer >> slot >> side >> thr >> o_val_lead >> o_uncert_lead >> o_val_trail >> o_uncert_trail >> quality;
  if (ss.fail() || (side != 'A' && side != 'B')) {
    return false;
  } else {
    outRecord.layer = layer;
    outRecord.slot = slot;
    if (side == 'A') {
      outRecord.side = JPetPM::SideA;
    } else {
      outRecord.side = JPetPM::SideB;
    }
    outRecord.threshold = thr;
    outRecord.offset_value_leading = o_val_lead;
    outRecord.offset_uncertainty_leading = o_uncert_lead;
    outRecord.offset_value_trailing = o_val_trail;
    outRecord.offset_uncertainty_trailing = o_uncert_trail;
    outRecord.quality = quality;
    return true;
  }
}
<commit_msg>Change WARNING to DEBUG if no calibration given TimeCalibTools<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  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.
 *
 *  @file TimeCalibTools.cpp
 */

#include <boost/algorithm/string/predicate.hpp> /// for starts_with
#include <algorithm> /// for any_of()
#include <sstream>
#include "TimeCalibTools.h"
#include "JPetLoggerInclude.h"

double TimeCalibTools::getTimeCalibCorrection(const TOMBChToCorrection& timeCalibration, const unsigned int channel)
{
  if (timeCalibration.find(channel) == timeCalibration.end()) {
    DEBUG("No time calibration available for this channel");
    return 0.0;
  } else {
    return timeCalibration.at(channel);
  }
}

TimeCalibTools::TOMBChToCorrection TimeCalibTools::loadTimeCalibration(const std::string& calibFile, const TimeCalibTools::TOMBChMap& tombMap)
{
  INFO("Loading time calibration from:" + calibFile);
  auto calibRecords = readCalibrationRecordsFromFile(calibFile);
  return generateTimeCalibration(calibRecords, tombMap);
}

TimeCalibTools::TOMBChToCorrection TimeCalibTools::generateTimeCalibration(const std::vector<TimeCalibRecord>& calibRecords,  const TimeCalibTools::TOMBChMap& tombMap)
{
  TOMBChToCorrection timeCalibration;
  if (areCorrectTimeCalibRecords(calibRecords)) {
    std::transform(calibRecords.begin(),
                   calibRecords.end(),
                   std::inserter(timeCalibration, timeCalibration.begin()),
    [&tombMap](const TimeCalibRecord & r) {
      auto key = std::make_tuple(r.layer, r.slot, r.side, r.threshold);
      auto correction = r.offset_value_leading;
      if (tombMap.find(key) != tombMap.end()) {
        auto tombCh = tombMap.at(key);
        return std::make_pair(tombCh, correction);
      } else {
        ERROR("No TOMB channel number in TOMB MAP for the combination: layer=" + std::to_string(r.layer) + ",slot=" + std::to_string(r.slot) + ",side=" + std::to_string(r.side) + ",threshold=" + std::to_string(r.threshold));
        return std::make_pair(-1, 0.0);
      }
    });
  } else {
    ERROR("Empty calibration will be returned");
  }
  return timeCalibration;
}

std::vector<TimeCalibRecord> TimeCalibTools::readCalibrationRecordsFromFile(const std::string& calibFile)
{
  using namespace std;
  namespace ba = boost::algorithm;

  std::vector<TimeCalibRecord> timeCalibRecords;
  string line;
  TimeCalibRecord record = { -1, -1, JPetPM::SideA, -1, 0.0, -1.0, 0.0, -1.0, -1.0 };
  ifstream inputFile(calibFile);

  while (getline(inputFile, line)) {
    /// Lines starting with # are comments and they are ignored.
    if (ba::starts_with(line, "#")) {
      continue;
    } else {
      if (fillTimeCalibRecord(line, record)) {
        timeCalibRecords.push_back(record);
      } else {
        ERROR("Line from the time calibration file seems to be incorrect:" + line);
      }
    }
  }
  return timeCalibRecords;
}

bool TimeCalibTools::areCorrectTimeCalibRecords(const std::vector<TimeCalibRecord>& records)
{
  const auto kMinSlot = 1;
  const auto kMaxSlot = 96;
  const auto kMinLayer = 1;
  const auto kMaxLayer = 3;
  const auto kMinThr = 1;
  const auto kMaxThr = 4;
  return ! std::any_of(
           records.begin(),
           records.end(),
  [](const TimeCalibRecord & r) {
    return ((r.layer < kMinLayer) ||
            (r.layer > kMaxLayer) ||
            (r.slot < kMinSlot) ||
            (r.slot > kMaxSlot) ||
            (r.threshold < kMinThr) ||
            (r.threshold > kMaxThr)
           );
  });
}

bool TimeCalibTools::fillTimeCalibRecord(const std::string& input, TimeCalibRecord& outRecord)
{
  using namespace std;
  int layer = -1;
  int slot = -1;
  char side = 'A';
  int thr = -1;
  double o_val_lead = 0;
  double o_uncert_lead = 0;
  double o_val_trail = 0;
  double o_uncert_trail = 0;
  double quality = 0;
  istringstream ss(input);
  ss >> layer >> slot >> side >> thr >> o_val_lead >> o_uncert_lead >> o_val_trail >> o_uncert_trail >> quality;
  if (ss.fail() || (side != 'A' && side != 'B')) {
    return false;
  } else {
    outRecord.layer = layer;
    outRecord.slot = slot;
    if (side == 'A') {
      outRecord.side = JPetPM::SideA;
    } else {
      outRecord.side = JPetPM::SideB;
    }
    outRecord.threshold = thr;
    outRecord.offset_value_leading = o_val_lead;
    outRecord.offset_uncertainty_leading = o_uncert_lead;
    outRecord.offset_value_trailing = o_val_trail;
    outRecord.offset_uncertainty_trailing = o_uncert_trail;
    outRecord.quality = quality;
    return true;
  }
}
<|endoftext|>


<commit_before>/*
 * measurethread.cpp
 *
 *  Created on: 18.11.2008
 *      Author: kazei
 */

#include "measurethread.h"
#include "sleep.h"

#define draw_x(x) emit line(x,0,x,-127,Qt::SolidLine)
#define draw_y(y) emit line(0,y,2500,y,Qt::SolidLine)

//#define GOLDEN

QList<qreal> sm_diff(QByteArray data, int nr)//nr - Depth of smoothing in one direction
{
    QList<qreal> diff;

    for (int i=0;i<data.count();i++)
    {
        if(i<nr || i>=data.count()-nr)
        {
            diff<<0;
            continue;
        }
        double a=0;
        double b=0;
        for (int k=-nr;k<=nr;k++)
        {
            a+=k*data[i+k]-k*data[i+k]/nr;
            b+=k*k;
        }

        diff<<a/b*10;
    }
    return diff;
}

QByteArray MeasureThread::sweep()
{
    osc->setch1(volts1);

    int mini=0;
    int maxi=0;
    int starti, stopi;

    QByteArray data;

    while(!(mini>maxi))
    {
        gen->setsweep(fsf,fff);
        osc->wait("READY");
        gen->startsweep();
        osc->wait("READY");
        data = osc->readcurve();

        /*		    max
 *		     _
 *		    / \
 *		___/   |   _______
 *		        \_/
 *		        min
 *
 *         /\     _
 *		---  \   / -------
 *            \_/
 *		    diff_min/
 *
 */

        emit path(data,QPen(Qt::green));

        QList<qreal> diff = sm_diff(data,sm1);

        emit path(diff,QPen(Qt::darkYellow));

        double min_diff_val=0;
        int min_diff_index;

        //find diff_min
        for (int i=0;i<diff.count();i++)
        {
            if (diff[i]<min_diff_val)
            {
                min_diff_val = diff[i];
                min_diff_index = i;
            }
        }

        //find diff=0 right from diff_min <=> min
        for (int i=min_diff_index;i<diff.count()-1;i++)
        {
            if (diff[i]<=0 && diff[i+1]>0)
            {
                mini = i;
                break;
            }
        }

        //find diff=0 left from diff_min <=> max
        for (int i=min_diff_index;i>0;i--)
        {
            if (diff[i-1]>=0 && diff[i]<0)
            {
                maxi = i;
                break;
            }
        }

        //		starti=2*maxi-min_diff_index;//double interval
        //		stopi=2*mini-min_diff_index;
        starti=2*maxi-mini;
        draw_x(starti);
        stopi=2*mini-maxi;
        draw_x(stopi);
    }
    //calculate coefficents to convert index to frequency
    double kt = (fff-fsf)/data.count();
    sff = kt*(stopi)+fsf;
    ssf = kt*(starti)+fsf;
    k = (sff-ssf)/data.count();

    int max_data=0;
    for(int i=0;i<data.count();i++)
        if(data.at(i)>max_data)
            max_data=data.at(i);

    //	double curv=osc->getch1();
    //	double onediv=curv/25.4;
    //	double maxv=max_data*onediv;
    //	double newv=maxv/4;
    double ch1=osc->getch1();
    ch1=ch1*max_data/101.6;
    osc->setch1(ch1);
    k2=ch1/25.4;

    gen->setsweep(ssf,sff);
    osc->wait("READY");
    gen->startsweep();
    osc->wait("READY");

    QByteArray data2 = osc->readcurve();
    return data2;
}

float MeasureThread::getamplonf(float freq)
{
    gen->setfreq(freq);
    return vol->acquire();
}

float MeasureThread::golden(float a, float b, float epsilon, bool max)
{
    const double phi = 1.61803398874989484;

    float x1=b-(b-a)/phi;
    float x2=a+(b-a)/phi;

    float y1=getamplonf(x1);
    float y2=getamplonf(x2);

    while ((b-a)>=epsilon*2)
    {
        if ( (y1>y2 && max) || (y1<y2 && !max))
        {
            b=x2;
            x2=x1;
            y2=y1;
            x1=a+b-x2;
            y1=getamplonf(x1);
        }
        else
        {
            a=x1;
            x1=x2;
            y1=y2;
            x2=b-(x1-a);
            y2=getamplonf(x2);
        }
    }

    return (a+b)/2;
}

double MeasureThread::find_extremum(QByteArray dat, int start, int stop, int sm, bool max)
{
#ifdef GOLDEN
    return golden(k*start+ssf,k*stop+ssf,epsilon,true);
#else
    while(start<stop && sm > 1)
    {
        QList<qreal> diff=sm_diff(dat,sm);
        //left to right
        for(int i=start;i<stop;i++)
        {
            if((max && diff[i]<=0) || (!max && diff[i]>=0))
            {
                start=i;
                break;
            }
        }
        //right to left
        for(int i=stop;i>start;i--)
        {
            if((max && diff[i]>=0) || (!max && diff[i]<=0))
            {
                stop=i;
                break;
            }
        }
        sm--;
    }

    return k*(start+stop)/2+ssf;
#endif
}

void MeasureThread::findresonance()
{
    int xmin=0,xmax1=0,xfmax=0,xmax2=0;

    QByteArray dat;
    QList<qreal> diff;

    int cycles=0;
    while ((xfmax <= xmax1)||(xfmax >= xmin))
    {
        //draw X axis
        dat = sweep();

        emit line(0,0,dat.count(),0,Qt::SolidLine);

        int fmax=0;
        for (int i=0; i<dat.count();i++)
        {
            if (fmax<dat[i])
            {
                fmax=dat[i];
                xfmax=i;
            }
        }

        emit path(dat,QPen(Qt::blue));

        diff=sm_diff(dat,sm2);

        emit path(diff, QPen(Qt::red));

        float min=255;
        float max1=0;
        float max2=0;

        for (int i=0;i<dat.count();i++)
        {
            if (min>diff[i])
            {
                min=diff[i];
                xmin=i;
            }
        }

        for (int i=0;i<xmin;i++)
        {
            if (max1<diff[i])
            {
                max1=diff[i];
                xmax1=i;
            }
        }

        for (int i=xmin;i<dat.count();i++)
        {
            if (max2<diff[i])
            {
                max2=diff[i];
                xmax2=i;
            }
        }

        draw_x(xmin);
        draw_x(xmax1);
        draw_x(xmax2);
        cycles++;
        if(cycles>4)
            throw GPIBGenericException(trUtf8("Could not acquire resonance qurve"));
    }

    for(int i=0; i<dat.count(); i++)
    {
        curve<<QPair<double,double>(k*i+ssf, dat[i]*k2);
    }

    gen->sweepoff();

    rf=find_extremum(dat,xmax1,xmin,sm2,true);
    draw_x((rf-ssf)/k);
    ra=getamplonf(rf);
    draw_y(-ra/k2*sqrt(2));

    af=find_extremum(dat,xmin,xmax2,sm2,false);
    draw_x((af-ssf)/k);
    aa=getamplonf(af);
    draw_y(-aa/k2*sqrt(2));

    gen->sweepon();
}

void MeasureThread::run()
{
    epsilon=0.1;
    fsf=startf;
    fff=stopf;

    gen=0;
    vol=0;
    osc=0;

    curve.clear();

    try{
        //---------Main block-------------
        if (oscid.isEmpty() || genid.isEmpty() || mulid.isEmpty())
        {
            if(oscid.isEmpty())
                throw GPIBGenericException(trUtf8("Oscilloscope GPIB ID is empty"));
            if(genid.isEmpty())
                throw GPIBGenericException(trUtf8("Generator GPIB ID is empty"));
            if(mulid.isEmpty())
                throw GPIBGenericException(trUtf8("Multimeter GPIB ID is empty"));
            return;
        }

        gen = new genctrl(genid);
        vol = new volctrl(mulid);
        osc = new oscctrl(oscid);

        findresonance();

        if(!filename.isEmpty())
        {
            QFile f(filename);
            f.open(QFile::WriteOnly);
            QString buf;
            for(int i=0;i<curve.count();i++)
            {
                buf.setNum(curve.at(i).first,'f',10);
                f.write(buf.toAscii());
                f.write("\t");
                buf.setNum(curve.at(i).second,'f',10);
                f.write(buf.toAscii());
                f.write("\r\n");
            }
            f.close();
        }

        QStringList data;
        data<<QString("First run start freq, Hz:%1").arg(fsf);
        data<<QString("First run stop freq, Hz:%1").arg(fff);
        data<<QString("Second run start freq, Hz:%1").arg(ssf);
        data<<QString("Second run stop freq, Hz:%1").arg(sff);
        data<<QString("Resonance freq, Hz:%1").arg(rf);
        data<<QString("Resonance ampl, V:%1").arg(ra);
        data<<QString("Antiresonance freq, Hz:%1").arg(af);
        data<<QString("Antiresonance ampl, V:%1").arg(aa);
        emit finished(data);
        //------END main block-------------------
    } catch (GPIBGenericException e) {
        QStringList data;
        data<<QString("::ERROR::");
        data<<e.report();
        emit finished(data);
    } catch(std::exception e) {
        QStringList data;
        data<<QString("::ERROR::");
        data<<trUtf8("Caught unexpected exception %1").arg(e.what());
        emit finished(data);
    }

    delete gen;
    delete vol;
    delete osc;
}
<commit_msg>upr: adaptive lowering of direvative smoothening level should work now and yield better results, but it still could use some optimisation, since it wastes bit too much cpu cycles (maybe).<commit_after>/*
 * measurethread.cpp
 *
 *  Created on: 18.11.2008
 *      Author: kazei
 */

#include "measurethread.h"
#include "sleep.h"

#define draw_x(x) emit line(x,0,x,-127,Qt::SolidLine)
#define draw_y(y) emit line(0,y,2500,y,Qt::SolidLine)

//#define GOLDEN

QList<qreal> sm_diff(QByteArray data, int nr)//nr - Depth of smoothing in one direction
{
    QList<qreal> diff;

    for (int i=0;i<data.count();i++)
    {
        if(i<nr || i>=data.count()-nr)
        {
            diff<<0;
            continue;
        }
        double a=0;
        double b=0;
        for (int k=-nr;k<=nr;k++)
        {
            a+=k*data[i+k]-k*data[i+k]/nr;
            b+=k*k;
        }

        diff<<a/b*10;
    }
    return diff;
}

QByteArray MeasureThread::sweep()
{
    osc->setch1(volts1);

    int mini=0;
    int maxi=0;
    int starti, stopi;

    QByteArray data;

    while(!(mini>maxi))
    {
        gen->setsweep(fsf,fff);
        osc->wait("READY");
        gen->startsweep();
        osc->wait("READY");
        data = osc->readcurve();

        /*		    max
 *		     _
 *		    / \
 *		___/   |   _______
 *		        \_/
 *		        min
 *
 *         /\     _
 *		---  \   / -------
 *            \_/
 *		    diff_min/
 *
 */

        emit path(data,QPen(Qt::green));

        QList<qreal> diff = sm_diff(data,sm1);

        emit path(diff,QPen(Qt::darkYellow));

        double min_diff_val=0;
        int min_diff_index;

        //find diff_min
        for (int i=0;i<diff.count();i++)
        {
            if (diff[i]<min_diff_val)
            {
                min_diff_val = diff[i];
                min_diff_index = i;
            }
        }

        //find diff=0 right from diff_min <=> min
        for (int i=min_diff_index;i<diff.count()-1;i++)
        {
            if (diff[i]<=0 && diff[i+1]>0)
            {
                mini = i;
                break;
            }
        }

        //find diff=0 left from diff_min <=> max
        for (int i=min_diff_index;i>0;i--)
        {
            if (diff[i-1]>=0 && diff[i]<0)
            {
                maxi = i;
                break;
            }
        }

        //		starti=2*maxi-min_diff_index;//double interval
        //		stopi=2*mini-min_diff_index;
        starti=2*maxi-mini;
        draw_x(starti);
        stopi=2*mini-maxi;
        draw_x(stopi);
    }
    //calculate coefficents to convert index to frequency
    double kt = (fff-fsf)/data.count();
    sff = kt*(stopi)+fsf;
    ssf = kt*(starti)+fsf;
    k = (sff-ssf)/data.count();

    int max_data=0;
    for(int i=0;i<data.count();i++)
        if(data.at(i)>max_data)
            max_data=data.at(i);

    //	double curv=osc->getch1();
    //	double onediv=curv/25.4;
    //	double maxv=max_data*onediv;
    //	double newv=maxv/4;
    double ch1=osc->getch1();
    ch1=ch1*max_data/101.6;
    osc->setch1(ch1);
    k2=ch1/25.4;

    gen->setsweep(ssf,sff);
    osc->wait("READY");
    gen->startsweep();
    osc->wait("READY");

    QByteArray data2 = osc->readcurve();
    return data2;
}

float MeasureThread::getamplonf(float freq)
{
    gen->setfreq(freq);
    return vol->acquire();
}

float MeasureThread::golden(float a, float b, float epsilon, bool max)
{
    const double phi = 1.61803398874989484;

    float x1=b-(b-a)/phi;
    float x2=a+(b-a)/phi;

    float y1=getamplonf(x1);
    float y2=getamplonf(x2);

    while ((b-a)>=epsilon*2)
    {
        if ( (y1>y2 && max) || (y1<y2 && !max))
        {
            b=x2;
            x2=x1;
            y2=y1;
            x1=a+b-x2;
            y1=getamplonf(x1);
        }
        else
        {
            a=x1;
            x1=x2;
            y1=y2;
            x2=b-(x1-a);
            y2=getamplonf(x2);
        }
    }

    return (a+b)/2;
}

double MeasureThread::find_extremum(QByteArray dat, int start, int stop, int sm, bool max)
{
#ifdef GOLDEN
    return golden(k*start+ssf,k*stop+ssf,epsilon,true);
#else
    while(start<stop && sm >= 1)
    {
        QList<qreal> diff=sm_diff(dat,sm);
        //left to right
        for(int i=start;i<stop;i++)
        {
            if((max && diff[i]<=0) || (!max && diff[i]>=0))
            {
                start=i-1;
                break;
            }
        }
        //right to left
        for(int i=stop;i>start;i--)
        {
            if((max && diff[i]>=0) || (!max && diff[i]<=0))
            {
                stop=i+1;
                break;
            }
        }
        sm--;
    }

    return k*(start+stop)/2.0f+ssf;
#endif
}

void MeasureThread::findresonance()
{
    int xmin=0,xmax1=0,xfmax=0,xmax2=0;

    QByteArray dat;
    QList<qreal> diff;

    int cycles=0;
    while ((xfmax <= xmax1)||(xfmax >= xmin))
    {
        //draw X axis
        dat = sweep();

        emit line(0,0,dat.count(),0,Qt::SolidLine);

        int fmax=0;
        for (int i=0; i<dat.count();i++)
        {
            if (fmax<dat[i])
            {
                fmax=dat[i];
                xfmax=i;
            }
        }

        emit path(dat,QPen(Qt::blue));

        diff=sm_diff(dat,sm2);

        emit path(diff, QPen(Qt::red));

        float min=255;
        float max1=0;
        float max2=0;

        for (int i=0;i<dat.count();i++)
        {
            if (min>diff[i])
            {
                min=diff[i];
                xmin=i;
            }
        }

        for (int i=0;i<xmin;i++)
        {
            if (max1<diff[i])
            {
                max1=diff[i];
                xmax1=i;
            }
        }

        for (int i=xmin;i<dat.count();i++)
        {
            if (max2<diff[i])
            {
                max2=diff[i];
                xmax2=i;
            }
        }

        draw_x(xmin);
        draw_x(xmax1);
        draw_x(xmax2);
        cycles++;
        if(cycles>4)
            throw GPIBGenericException(trUtf8("Could not acquire resonance qurve"));
    }

    for(int i=0; i<dat.count(); i++)
    {
        curve<<QPair<double,double>(k*i+ssf, dat[i]*k2);
    }

    gen->sweepoff();

    rf=find_extremum(dat,xmax1,xmin,sm2,true);
    draw_x((rf-ssf)/k);
    ra=getamplonf(rf);
    draw_y(-ra/k2*sqrt(2));

    af=find_extremum(dat,xmin,xmax2,sm2,false);
    draw_x((af-ssf)/k);
    aa=getamplonf(af);
    draw_y(-aa/k2*sqrt(2));

    gen->sweepon();
}

void MeasureThread::run()
{
    epsilon=0.1;
    fsf=startf;
    fff=stopf;

    gen=0;
    vol=0;
    osc=0;

    curve.clear();

    try{
        //---------Main block-------------
        if (oscid.isEmpty() || genid.isEmpty() || mulid.isEmpty())
        {
            if(oscid.isEmpty())
                throw GPIBGenericException(trUtf8("Oscilloscope GPIB ID is empty"));
            if(genid.isEmpty())
                throw GPIBGenericException(trUtf8("Generator GPIB ID is empty"));
            if(mulid.isEmpty())
                throw GPIBGenericException(trUtf8("Multimeter GPIB ID is empty"));
            return;
        }

        gen = new genctrl(genid);
        vol = new volctrl(mulid);
        osc = new oscctrl(oscid);

        findresonance();

        if(!filename.isEmpty())
        {
            QFile f(filename);
            f.open(QFile::WriteOnly);
            QString buf;
            for(int i=0;i<curve.count();i++)
            {
                buf.setNum(curve.at(i).first,'f',10);
                f.write(buf.toAscii());
                f.write("\t");
                buf.setNum(curve.at(i).second,'f',10);
                f.write(buf.toAscii());
                f.write("\r\n");
            }
            f.close();
        }

        QStringList data;
        data<<QString("First run start freq, Hz:%1").arg(fsf);
        data<<QString("First run stop freq, Hz:%1").arg(fff);
        data<<QString("Second run start freq, Hz:%1").arg(ssf);
        data<<QString("Second run stop freq, Hz:%1").arg(sff);
        data<<QString("Resonance freq, Hz:%1").arg(rf);
        data<<QString("Resonance ampl, V:%1").arg(ra);
        data<<QString("Antiresonance freq, Hz:%1").arg(af);
        data<<QString("Antiresonance ampl, V:%1").arg(aa);
        emit finished(data);
        //------END main block-------------------
    } catch (GPIBGenericException e) {
        QStringList data;
        data<<QString("::ERROR::");
        data<<e.report();
        emit finished(data);
    } catch(std::exception e) {
        QStringList data;
        data<<QString("::ERROR::");
        data<<trUtf8("Caught unexpected exception %1").arg(e.what());
        emit finished(data);
    }

    delete gen;
    delete vol;
    delete osc;
}
<|endoftext|>


<commit_before>#include "GPU.H"

#include "PROFILE.H"
#include "PSXINPUT.H"
#include "SHADOWS.H"
#include "FXTRIG.H"
#include "TEXT_S.H"

#include <LIBETC.H>
#if PSXPC_TEST
#include <stdio.h>
#elif PSX_VERSION
#include <STDIO.H>
#endif
#include <EMULATOR.H>
#include <LIBGPU.H>
#include "CONTROL.H"

unsigned long GnFrameCounter = 19;
unsigned long GnLastFrameCount = 19;
struct PSXTEXTSTRUCT* psxtextinfo;
struct PSXSPRITESTRUCT* psxspriteinfo;
int rgbscaleme = 256;
int gfx_debugging_mode;
struct DB_STRUCT db;
struct MMTEXTURE* RoomTextInfo;
#if __linux__
extern unsigned long* GadwOrderingTables_V2;
#else
unsigned long GadwOrderingTables_V2[512];
#endif
static int LnFlipFrame;
#if __linux__
unsigned long* GadwOrderingTables;
unsigned long* GadwPolygonBuffers;
#else
unsigned long GadwOrderingTables[5128];
unsigned long GadwPolygonBuffers[52260];
#endif

void GPU_UseOrderingTables(unsigned long* pBuffers, int nOTSize)//5DF68(<), 5F1C8(<) (D) (ND)
{
	db.order_table[0] = (unsigned long*)((unsigned long)&pBuffers[0]);
	db.order_table[1] = (unsigned long*)((unsigned long)&pBuffers[nOTSize]);
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[0]);
	db.pickup_order_table[1] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[256]);
	return;
}

void GPU_UsePolygonBuffers(unsigned long* pBuffers, int nPBSize)//5DFB0(<),
{
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = (unsigned long*)((unsigned long)&pBuffers[0]);
	db.poly_buffer[1] = (unsigned long*)((unsigned long)&pBuffers[nPBSize]);
	return;
}

void GPU_EndScene()//5DFDC(<), 5F23C(<) (F)
{
#if DEBUG_VERSION
	int nPolys;
	static int nWorstPolys;

	nPolys = ((int) &db.polyptr[0] - (int) &db.curpolybuf[0]) * 0x4EC4EC4F / 16 - (((long) &db.polyptr[0] - (long) &db.curpolybuf[0]) >> 31);

	if (psxtextinfo->u2v2pad < nPolys)
	{
		psxtextinfo->u2v2pad = nPolys;
	}

	//loc_5E020
#endif

	OptimiseOTagR(&db.ot[0], db.nOTSize);

#if DEBUG_VERSION
	ProfileRGB(255, 255, 255);
	//do_gfx_debug_mode(&db.ot[db.nOTSize - 1]);
	ProfileRGB(0, 255, 255);
#endif

	Emulator_EndScene();
	return;
}

int GPU_FlipNoIdle()//5E078(<), 5F264(<) (F)
{
#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileRGB(255, 255, 255);
		ProfileAddOT(&db.ot[0]);
	}
#endif

	//loc_5E0B0
	DrawSync(0);

#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileAddDrawOT(&db.ot[0]);
	}
#endif

	LnFlipFrame = GnLastFrameCount;

	//loc_5E0D8
	if (LnFlipFrame < 2)
	{
		do
		{
			VSync(0);
			LnFlipFrame++;
		} while (LnFlipFrame < 2);
	}
	else
	{
		//loc_5E120
		VSync(0);
		LnFlipFrame++;
	}

	GnLastFrameCount = 0;
	PutDispEnv(&db.disp[db.current_buffer]);
	DrawOTagEnv(&db.ot[db.nOTSize-1], &db.draw[db.current_buffer]);

#if DEBUG_VERSION
	ProfileStartCount();
#endif

	db.current_buffer ^= 1;

	return LnFlipFrame;
}

void do_gfx_debug_mode(unsigned long* otstart)//5E1B4(<) ? (F)
{
	unsigned long* data;
	unsigned char code;
	int ntri;
	int nquad;
	unsigned short x0;
	unsigned short y0;
	unsigned short x1;
	unsigned short y1;
	unsigned short x2;
	unsigned short y2;
	LINE_F2* line2;
	char txbuf[64];

	if (RawEdge & IN_UNK8)
	{
		gfx_debugging_mode++;
	}

	//loc_5E1E0
	nquad = 0;

	if (gfx_debugging_mode > 2)
	{
		gfx_debugging_mode = 0;
	}

	//loc_5E1F8
	data = (unsigned long*)otstart[0];
	ntri = 0;

	if (((unsigned long)data & 0xFFFFFF) != 0xFFFFFF)
	{
		do
		{
			if ((data[0] & 0xFF000000) != 0)
			{
				code = ((char*)data)[7];//getcode

				if (gfx_debugging_mode < 2)
				{
					if ((code & 0xFC) == 0x7C)
					{
						if (gfx_debugging_mode != 0)
						{
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E27C
							((char*)data)[7] = (code & 2) | 0x3C;//setcode
						}

						nquad = 1;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E290
						if (gfx_debugging_mode != 0)
						{
							((char*)data)[7] = 0x36;
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E2B4
							((char*)data)[7] = (code & 2) | 0x34;
						}

						ntri = 1;
					}//loc_5E3C4
				}
				else if (gfx_debugging_mode == 2)
				{
					//loc_5E2C8

					if ((code & 0xFC) == 0x7C)
					{
						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						nquad++;

						((char*)data)[7] = 0x4C;
						((char*)data)[4] = 0x0;
						((char*)data)[5] = 0x50;
						((char*)data)[6] = 0x0;
						((long*)data)[6] = 0x55555555;

						((short*)data)[8] = ((unsigned short*)data)[22];

						line2 = (LINE_F2*)&data[6];

						((short*)data)[9] = ((unsigned short*)data)[23];

						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[10] = x2;
						((short*)data)[11] = y2;

						line2->code = 0x40;
						line2->x0 = x0;
						line2->y0 = y0;
						line2->x1 = x2;
						line2->y1 = y2;
						line2->r0 = 0;
						line2->g0 = 80;
						line2->b0 = 0;

						((char*)data)[3] = 9;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E368
						ntri++;

						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						((char*)data)[7] = 76;
						((char*)data)[4] = 0;
						((char*)data)[5] = 80;
						((char*)data)[6] = 0;
						((long*)data)[6] = 0x55555555;
						((char*)data)[3] = 6;
						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[8] = x2;
						((short*)data)[9] = y2;
						((short*)data)[10] = x0;
						((short*)data)[11] = y0;
					}
				}//loc_5E3C4
			}
		}while (data[0] != 0xFFFFFF);
		//loc_5E3C4
	}

	//loc_5E3D8
	if (gfx_debugging_mode == 0)
	{
		return;
	}

	sprintf(&txbuf[0], "TRI %d", ntri);
	PrintString(34, 220, 3, &txbuf[0], 0);

	sprintf(&txbuf[0], "QUAD %d", nquad);
	PrintString(34, 232, 3, &txbuf[0], 0);
}

void GPU_FlipStory(unsigned long* gfx)//5E448(<), * (F)
{
	RECT16 r;
	RECT16* fuckmyanalpassage;

	DrawSync(0);
	VSync(0);

	PutDispEnv(&db.disp[db.current_buffer]);
	fuckmyanalpassage = (RECT16*) &db.disp[db.current_buffer ^ 1].disp;
	r.x = fuckmyanalpassage->x;
	r.y = fuckmyanalpassage->y;
	r.w = fuckmyanalpassage->w;
	r.h = fuckmyanalpassage->h;
	LoadImagePSX(&r, gfx);
	DrawOTagEnv(&db.ot[db.nOTSize - 1], &db.draw[db.current_buffer]);
	db.current_buffer ^= 1;
}<commit_msg>Update GPU.C<commit_after>#include "GPU.H"

#include "PROFILE.H"
#include "PSXINPUT.H"
#include "SHADOWS.H"
#include "FXTRIG.H"
#include "TEXT_S.H"

#include <LIBETC.H>
#if PSXPC_TEST
#include <stdio.h>
#elif PSX_VERSION
#include <STDIO.H>
#endif
#include <EMULATOR.H>
#include <LIBGPU.H>
#include "CONTROL.H"

unsigned long GnFrameCounter = 19;
unsigned long GnLastFrameCount = 19;
struct PSXTEXTSTRUCT* psxtextinfo;
struct PSXSPRITESTRUCT* psxspriteinfo;
int rgbscaleme = 256;
int gfx_debugging_mode;
struct DB_STRUCT db;
struct MMTEXTURE* RoomTextInfo;
#if __linux__
unsigned long* GadwOrderingTables_V2;
#else
unsigned long GadwOrderingTables_V2[512];
#endif
static int LnFlipFrame;
#if __linux__
unsigned long* GadwOrderingTables;
unsigned long* GadwPolygonBuffers;
#else
unsigned long GadwOrderingTables[5128];
unsigned long GadwPolygonBuffers[52260];
#endif

void GPU_UseOrderingTables(unsigned long* pBuffers, int nOTSize)//5DF68(<), 5F1C8(<) (D) (ND)
{
	db.order_table[0] = (unsigned long*)((unsigned long)&pBuffers[0]);
	db.order_table[1] = (unsigned long*)((unsigned long)&pBuffers[nOTSize]);
	db.nOTSize = nOTSize;
	db.pickup_order_table[0] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[0]);
	db.pickup_order_table[1] = (unsigned long*)((unsigned long)&GadwOrderingTables_V2[256]);
	return;
}

void GPU_UsePolygonBuffers(unsigned long* pBuffers, int nPBSize)//5DFB0(<),
{
	db.nPBSize = nPBSize;
	db.poly_buffer[0] = (unsigned long*)((unsigned long)&pBuffers[0]);
	db.poly_buffer[1] = (unsigned long*)((unsigned long)&pBuffers[nPBSize]);
	return;
}

void GPU_EndScene()//5DFDC(<), 5F23C(<) (F)
{
#if DEBUG_VERSION
	int nPolys;
	static int nWorstPolys;

	nPolys = ((int) &db.polyptr[0] - (int) &db.curpolybuf[0]) * 0x4EC4EC4F / 16 - (((long) &db.polyptr[0] - (long) &db.curpolybuf[0]) >> 31);

	if (psxtextinfo->u2v2pad < nPolys)
	{
		psxtextinfo->u2v2pad = nPolys;
	}

	//loc_5E020
#endif

	OptimiseOTagR(&db.ot[0], db.nOTSize);

#if DEBUG_VERSION
	ProfileRGB(255, 255, 255);
	//do_gfx_debug_mode(&db.ot[db.nOTSize - 1]);
	ProfileRGB(0, 255, 255);
#endif

	Emulator_EndScene();
	return;
}

int GPU_FlipNoIdle()//5E078(<), 5F264(<) (F)
{
#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileRGB(255, 255, 255);
		ProfileAddOT(&db.ot[0]);
	}
#endif

	//loc_5E0B0
	DrawSync(0);

#if DEBUG_VERSION
	if (ProfileDraw)
	{
		ProfileAddDrawOT(&db.ot[0]);
	}
#endif

	LnFlipFrame = GnLastFrameCount;

	//loc_5E0D8
	if (LnFlipFrame < 2)
	{
		do
		{
			VSync(0);
			LnFlipFrame++;
		} while (LnFlipFrame < 2);
	}
	else
	{
		//loc_5E120
		VSync(0);
		LnFlipFrame++;
	}

	GnLastFrameCount = 0;
	PutDispEnv(&db.disp[db.current_buffer]);
	DrawOTagEnv(&db.ot[db.nOTSize-1], &db.draw[db.current_buffer]);

#if DEBUG_VERSION
	ProfileStartCount();
#endif

	db.current_buffer ^= 1;

	return LnFlipFrame;
}

void do_gfx_debug_mode(unsigned long* otstart)//5E1B4(<) ? (F)
{
	unsigned long* data;
	unsigned char code;
	int ntri;
	int nquad;
	unsigned short x0;
	unsigned short y0;
	unsigned short x1;
	unsigned short y1;
	unsigned short x2;
	unsigned short y2;
	LINE_F2* line2;
	char txbuf[64];

	if (RawEdge & IN_UNK8)
	{
		gfx_debugging_mode++;
	}

	//loc_5E1E0
	nquad = 0;

	if (gfx_debugging_mode > 2)
	{
		gfx_debugging_mode = 0;
	}

	//loc_5E1F8
	data = (unsigned long*)otstart[0];
	ntri = 0;

	if (((unsigned long)data & 0xFFFFFF) != 0xFFFFFF)
	{
		do
		{
			if ((data[0] & 0xFF000000) != 0)
			{
				code = ((char*)data)[7];//getcode

				if (gfx_debugging_mode < 2)
				{
					if ((code & 0xFC) == 0x7C)
					{
						if (gfx_debugging_mode != 0)
						{
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E27C
							((char*)data)[7] = (code & 2) | 0x3C;//setcode
						}

						nquad = 1;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E290
						if (gfx_debugging_mode != 0)
						{
							((char*)data)[7] = 0x36;
							((short*)data)[13] &= 0xFF9F;
						}
						else
						{
							//loc_5E2B4
							((char*)data)[7] = (code & 2) | 0x34;
						}

						ntri = 1;
					}//loc_5E3C4
				}
				else if (gfx_debugging_mode == 2)
				{
					//loc_5E2C8

					if ((code & 0xFC) == 0x7C)
					{
						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						nquad++;

						((char*)data)[7] = 0x4C;
						((char*)data)[4] = 0x0;
						((char*)data)[5] = 0x50;
						((char*)data)[6] = 0x0;
						((long*)data)[6] = 0x55555555;

						((short*)data)[8] = ((unsigned short*)data)[22];

						line2 = (LINE_F2*)&data[6];

						((short*)data)[9] = ((unsigned short*)data)[23];

						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[10] = x2;
						((short*)data)[11] = y2;

						line2->code = 0x40;
						line2->x0 = x0;
						line2->y0 = y0;
						line2->x1 = x2;
						line2->y1 = y2;
						line2->r0 = 0;
						line2->g0 = 80;
						line2->b0 = 0;

						((char*)data)[3] = 9;
					}
					else if ((code & 0xFC) == 0x74)
					{
						//loc_5E368
						ntri++;

						x0 = ((unsigned short*)data)[4];
						y0 = ((unsigned short*)data)[5];
						x1 = ((unsigned short*)data)[10];
						y1 = ((unsigned short*)data)[11];
						x2 = ((unsigned short*)data)[16];
						y2 = ((unsigned short*)data)[17];

						((char*)data)[7] = 76;
						((char*)data)[4] = 0;
						((char*)data)[5] = 80;
						((char*)data)[6] = 0;
						((long*)data)[6] = 0x55555555;
						((char*)data)[3] = 6;
						((short*)data)[4] = x0;
						((short*)data)[5] = y0;
						((short*)data)[6] = x1;
						((short*)data)[7] = y1;
						((short*)data)[8] = x2;
						((short*)data)[9] = y2;
						((short*)data)[10] = x0;
						((short*)data)[11] = y0;
					}
				}//loc_5E3C4
			}
		}while (data[0] != 0xFFFFFF);
		//loc_5E3C4
	}

	//loc_5E3D8
	if (gfx_debugging_mode == 0)
	{
		return;
	}

	sprintf(&txbuf[0], "TRI %d", ntri);
	PrintString(34, 220, 3, &txbuf[0], 0);

	sprintf(&txbuf[0], "QUAD %d", nquad);
	PrintString(34, 232, 3, &txbuf[0], 0);
}

void GPU_FlipStory(unsigned long* gfx)//5E448(<), * (F)
{
	RECT16 r;
	RECT16* fuckmyanalpassage;

	DrawSync(0);
	VSync(0);

	PutDispEnv(&db.disp[db.current_buffer]);
	fuckmyanalpassage = (RECT16*) &db.disp[db.current_buffer ^ 1].disp;
	r.x = fuckmyanalpassage->x;
	r.y = fuckmyanalpassage->y;
	r.w = fuckmyanalpassage->w;
	r.h = fuckmyanalpassage->h;
	LoadImagePSX(&r, gfx);
	DrawOTagEnv(&db.ot[db.nOTSize - 1], &db.draw[db.current_buffer]);
	db.current_buffer ^= 1;
}<|endoftext|>


<commit_before><commit_msg>Attempt at solving rare case of interdictor desync.<commit_after><|endoftext|>


<commit_before>#include "data.h"

#include <cassert>
#include <map>
#include <vector>

namespace redsea {

std::string getLCDchar(int code) {
  assert (code >= 32);
  const std::vector<std::string> char_map ({
      " ","!","\\\"","#","¤","%","&","'","(",")","*","+",",","-",".","/",
      "0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
      "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
      "P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","―","_",
      "‖","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
      "p","q","r","s","t","u","v","w","x","y","z","{","|","}","¯"," ",
      "á","à","é","è","í","ì","ó","ò","ú","ù","Ñ","Ç","Ş","β","¡","Ĳ",
      "â","ä","ê","ë","î","ï","ô","ö","û","ü","ñ","ç","ş","ǧ","ı","ĳ",
      "ª","α","©","‰","Ǧ","ě","ň","ő","π","€","£","$","←","↑","→","↓",
      "º","¹","²","³","±","İ","ń","ű","µ","¿","÷","°","¼","½","¾","§",
      "Á","À","É","È","Í","Ì","Ó","Ò","Ú","Ù","Ř","Č","Š","Ž","Ð","Ŀ",
      "Â","Ä","Ê","Ë","Î","Ï","Ô","Ö","Û","Ü","ř","č","š","ž","đ","ŀ",
      "Ã","Å","Æ","Œ","ŷ","Ý","Õ","Ø","Þ","Ŋ","Ŕ","Ć","Ś","Ź","Ŧ","ð",
      "ã","å","æ","œ","ŵ","ý","õ","ø","þ","ŋ","ŕ","ć","ś","ź","ŧ"," "});
  return char_map[code - 32];
}

std::string getPTYname(int pty) {
  assert (pty >= 0 && pty <= 32);
  const std::vector<std::string> pty_names ({
   "No PTY", "News", "Current Affairs", "Information",
   "Sport", "Education", "Drama", "Cultures",
   "Science", "Varied Speech","Pop Music", "Rock Music",
   "Easy Listening","Light Classics M","Serious Classics","Other Music",
   "Weather & Metr", "Finance", "Children's Progs", "Social Affairs",
   "Religion", "Phone In", "Travel & Touring", "Leisure & Hobby",
   "Jazz Music", "Country Music", "National Music", "Oldies Music",
   "Folk Music", "Documentary", "Alarm Test", "Alarm - Alarm !"
  });
  return pty_names[pty];

}

std::string getCountryString(uint16_t pi, uint16_t ecc) {
  const std::map<uint16_t,std::vector<std::string>> country_codes ({
    {0xA0,{"us","us","us","us","us","us","us","us","us","us","us","--","us","us","--"}},
    {0xA1,{"--","--","--","--","--","--","--","--","--","--","ca","ca","ca","ca","gl"}},
    {0xA2,{"ai","ag","ec","fk","bb","bz","ky","cr","cu","ar","br","bm","an","gp","bs"}},
    {0xA3,{"bo","co","jm","mq","gf","py","ni","--","pa","dm","do","cl","gd","tc","gy"}},
    {0xA4,{"gt","hn","aw","--","ms","tt","pe","sr","uy","kn","lc","sv","ht","ve","--"}},
    {0xA5,{"--","--","--","--","--","--","--","--","--","--","mx","vc","mx","mx","mx"}},
    {0xA6,{"--","--","--","--","--","--","--","--","--","--","--","--","--","--","pm"}},
    {0xD0,{"cm","cf","dj","mg","ml","ao","gq","ga","gn","za","bf","cg","tg","bj","mw"}},
    {0xD1,{"na","lr","gh","mr","st","cv","sn","gm","bi","--","bw","km","tz","et","bg"}},
    {0xD2,{"sl","zw","mz","ug","sz","ke","so","ne","td","gw","zr","ci","tz","zm","--"}},
    {0xD3,{"--","--","eh","--","rw","ls","--","sc","--","mu","--","sd","--","--","--"}},
    {0xE0,{"de","dz","ad","il","it","be","ru","ps","al","at","hu","mt","de","--","eg"}},
    {0xE1,{"gr","cy","sm","ch","jo","fi","lu","bg","dk","gi","iq","gb","ly","ro","fr"}},
    {0xE2,{"ma","cz","pl","va","sk","sy","tn","--","li","is","mc","lt","yu","es","no"}},
    {0xE3,{"ie","ie","tr","mk","tj","--","--","nl","lv","lb","az","hr","kz","se","by"}},
    {0xE4,{"md","ee","kg","--","--","ua","--","pt","si","am","uz","ge","--","tm","ba"}},
    {0xF0,{"au","au","au","au","au","au","au","au","sa","af","mm","cn","kp","bh","my"}},
    {0xF1,{"ki","bt","bd","pk","fj","om","nr","ir","nz","sb","bn","lk","tw","kr","hk"}},
    {0xF2,{"kw","qa","kh","ws","in","mo","vn","ph","jp","sg","mv","id","ae","np","vu"}},
    {0xF3,{"la","th","to","--","--","--","--","--","pg","--","ye","--","--","fm","mn"}}
  });

  std::string result("--");

  uint16_t pi_cc = pi >> 12;

  if (country_codes.find(ecc) != country_codes.end() && pi_cc > 0) {
    result = country_codes.at(ecc).at(pi_cc-1);
  }

  return result;

}

std::string getLanguageString(uint16_t code) {
  std::vector<std::string> languages ({
    "Unknown","Albanian","Breton","Catalan",
    "Croatian","Welsh","Czech","Danish",
    "German","English","Spanish","Esperanto",
    "Estonian","Basque","Faroese","French",
    "Frisian","Irish","Gaelic","Galician",
    "Icelandic","Italian","Lappish","Latin",
    "Latvian","Luxembourgian","Lithuanian","Hungarian",
    "Maltese","Dutch","Norwegian","Occitan",
    "Polish","Portuguese","Romanian","Romansh",
    "Serbian","Slovak","Slovene","Finnish",
    "Swedish","Turkish","Flemish","Walloon",
    "","","","",
    "","","","",
    "","","","",
    "","","","",
    "","","","",
    "Background","","","",
    "","Zulu","Vietnamese","Uzbek",
    "Urdu","Ukrainian","Thai","Telugu",
    "Tatar","Tamil","Tadzhik","Swahili",
    "SrananTongo","Somali","Sinhalese","Shona",
    "Serbo-Croat","Ruthenian","Russian","Quechua",
    "Pushtu","Punjabi","Persian","Papamiento",
    "Oriya","Nepali","Ndebele","Marathi",
    "Moldovian","Malaysian","Malagasay","Macedonian",
    "Laotian","Korean","Khmer","Kazakh",
    "Kannada","Japanese","Indonesian","Hindi",
    "Hebrew","Hausa","Gurani","Gujurati",
    "Greek","Georgian","Fulani","Dari",
    "Churash","Chinese","Burmese","Bulgarian",
    "Bengali","Belorussian","Bambora","Azerbaijan",
    "Assamese","Armenian","Arabic","Amharic"
  });

  std::string result("");
  if (code < languages.size()) {
    result = languages[code];
  }

  return result;
}

std::string getAppName(uint16_t aid) {
  std::map<uint16_t,std::string> oda_apps({
    { 0x0000, "None" },
    { 0x0093, "Cross referencing DAB within RDS" },
    { 0x0BCB, "Leisure & Practical Info for Drivers" },
    { 0x0C24, "ELECTRABEL-DSM 7" },
    { 0x0CC1, "Wireless Playground broadcast control signal" },
    { 0x0D45, "RDS-TMC: ALERT-C / EN ISO 14819-1" },
    { 0x0D8B, "ELECTRABEL-DSM 18" },
    { 0x0E2C, "ELECTRABEL-DSM 3" },
    { 0x0E31, "ELECTRABEL-DSM 13" },
    { 0x0F87, "ELECTRABEL-DSM 2" },
    { 0x125F, "I-FM-RDS for fixed and mobile devices" },
    { 0x1BDA, "ELECTRABEL-DSM 1" },
    { 0x1C5E, "ELECTRABEL-DSM 20" },
    { 0x1C68, "ITIS In-vehicle data base" },
    { 0x1CB1, "ELECTRABEL-DSM 10" },
    { 0x1D47, "ELECTRABEL-DSM 4" },
    { 0x1DC2, "CITIBUS 4" },
    { 0x1DC5, "Encrypted TTI using ALERT-Plus" },
    { 0x1E8F, "ELECTRABEL-DSM 17" },
    { 0x4AA1, "RASANT" },
    { 0x4AB7, "ELECTRABEL-DSM 9" },
    { 0x4BA2, "ELECTRABEL-DSM 5" },
    { 0x4BD7, "RadioText+ (RT+)" },
    { 0x4C59, "CITIBUS 2" },
    { 0x4D87, "Radio Commerce System (RCS)" },
    { 0x4D95, "ELECTRABEL-DSM 16" },
    { 0x4D9A, "ELECTRABEL-DSM 11" },
    { 0x5757, "Personal weather station" },
    { 0x6552, "Enhanced RadioText (eRT)" },
    { 0x7373, "Enhanced early warning system" },
    { 0xC350, "NRSC Song Title and Artist" },
    { 0xC3A1, "Personal Radio Service" },
    { 0xC3B0, "iTunes Tagging" },
    { 0xC3C3, "NAVTEQ Traffic Plus" },
    { 0xC4D4, "eEAS" },
    { 0xC549, "Smart Grid Broadcast Channel" },
    { 0xC563, "ID Logic" },
    { 0xC6A7, "Veil Enabled Interactive Device" },
    { 0xC737, "Utility Message Channel (UMC)" },
    { 0xCB73, "CITIBUS 1" },
    { 0xCB97, "ELECTRABEL-DSM 14" },
    { 0xCC21, "CITIBUS 3" },
    { 0xCD46, "RDS-TMC: ALERT-C" },
    { 0xCD47, "RDS-TMC: ALERT-C" },
    { 0xCD9E, "ELECTRABEL-DSM 8" },
    { 0xCE6B, "Encrypted TTI using ALERT-Plus" },
    { 0xE123, "APS Gateway" },
    { 0xE1C1, "Action code" },
    { 0xE319, "ELECTRABEL-DSM 12" },
    { 0xE411, "Beacon downlink" },
    { 0xE440, "ELECTRABEL-DSM 15" },
    { 0xE4A6, "ELECTRABEL-DSM 19" },
    { 0xE5D7, "ELECTRABEL-DSM 6" },
    { 0xE911, "EAS open protocol" }
  });

  std::string result("(Unknown)");
  if (oda_apps.find(aid) != oda_apps.end()) {
    result = oda_apps[aid];
  }

  return result;
}

}
<commit_msg>prevent assertion crash by returning empty char on error<commit_after>#include "data.h"

#include <cassert>
#include <map>
#include <vector>

namespace redsea {

std::string getLCDchar(int code) {
  std::string result(" ");
  const std::vector<std::string> char_map ({
      " ","!","\\\"","#","¤","%","&","'","(",")","*","+",",","-",".","/",
      "0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
      "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
      "P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","―","_",
      "‖","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
      "p","q","r","s","t","u","v","w","x","y","z","{","|","}","¯"," ",
      "á","à","é","è","í","ì","ó","ò","ú","ù","Ñ","Ç","Ş","β","¡","Ĳ",
      "â","ä","ê","ë","î","ï","ô","ö","û","ü","ñ","ç","ş","ǧ","ı","ĳ",
      "ª","α","©","‰","Ǧ","ě","ň","ő","π","€","£","$","←","↑","→","↓",
      "º","¹","²","³","±","İ","ń","ű","µ","¿","÷","°","¼","½","¾","§",
      "Á","À","É","È","Í","Ì","Ó","Ò","Ú","Ù","Ř","Č","Š","Ž","Ð","Ŀ",
      "Â","Ä","Ê","Ë","Î","Ï","Ô","Ö","Û","Ü","ř","č","š","ž","đ","ŀ",
      "Ã","Å","Æ","Œ","ŷ","Ý","Õ","Ø","Þ","Ŋ","Ŕ","Ć","Ś","Ź","Ŧ","ð",
      "ã","å","æ","œ","ŵ","ý","õ","ø","þ","ŋ","ŕ","ć","ś","ź","ŧ"," "});

  int idx = code - 32;
  if (idx >= 0 && idx < (int)char_map.size())
    result = char_map[idx];

  return result;
}

std::string getPTYname(int pty) {
  assert (pty >= 0 && pty <= 32);
  const std::vector<std::string> pty_names ({
   "No PTY", "News", "Current Affairs", "Information",
   "Sport", "Education", "Drama", "Cultures",
   "Science", "Varied Speech","Pop Music", "Rock Music",
   "Easy Listening","Light Classics M","Serious Classics","Other Music",
   "Weather & Metr", "Finance", "Children's Progs", "Social Affairs",
   "Religion", "Phone In", "Travel & Touring", "Leisure & Hobby",
   "Jazz Music", "Country Music", "National Music", "Oldies Music",
   "Folk Music", "Documentary", "Alarm Test", "Alarm - Alarm !"
  });
  return pty_names[pty];

}

std::string getCountryString(uint16_t pi, uint16_t ecc) {
  const std::map<uint16_t,std::vector<std::string>> country_codes ({
    {0xA0,{"us","us","us","us","us","us","us","us","us","us","us","--","us","us","--"}},
    {0xA1,{"--","--","--","--","--","--","--","--","--","--","ca","ca","ca","ca","gl"}},
    {0xA2,{"ai","ag","ec","fk","bb","bz","ky","cr","cu","ar","br","bm","an","gp","bs"}},
    {0xA3,{"bo","co","jm","mq","gf","py","ni","--","pa","dm","do","cl","gd","tc","gy"}},
    {0xA4,{"gt","hn","aw","--","ms","tt","pe","sr","uy","kn","lc","sv","ht","ve","--"}},
    {0xA5,{"--","--","--","--","--","--","--","--","--","--","mx","vc","mx","mx","mx"}},
    {0xA6,{"--","--","--","--","--","--","--","--","--","--","--","--","--","--","pm"}},
    {0xD0,{"cm","cf","dj","mg","ml","ao","gq","ga","gn","za","bf","cg","tg","bj","mw"}},
    {0xD1,{"na","lr","gh","mr","st","cv","sn","gm","bi","--","bw","km","tz","et","bg"}},
    {0xD2,{"sl","zw","mz","ug","sz","ke","so","ne","td","gw","zr","ci","tz","zm","--"}},
    {0xD3,{"--","--","eh","--","rw","ls","--","sc","--","mu","--","sd","--","--","--"}},
    {0xE0,{"de","dz","ad","il","it","be","ru","ps","al","at","hu","mt","de","--","eg"}},
    {0xE1,{"gr","cy","sm","ch","jo","fi","lu","bg","dk","gi","iq","gb","ly","ro","fr"}},
    {0xE2,{"ma","cz","pl","va","sk","sy","tn","--","li","is","mc","lt","yu","es","no"}},
    {0xE3,{"ie","ie","tr","mk","tj","--","--","nl","lv","lb","az","hr","kz","se","by"}},
    {0xE4,{"md","ee","kg","--","--","ua","--","pt","si","am","uz","ge","--","tm","ba"}},
    {0xF0,{"au","au","au","au","au","au","au","au","sa","af","mm","cn","kp","bh","my"}},
    {0xF1,{"ki","bt","bd","pk","fj","om","nr","ir","nz","sb","bn","lk","tw","kr","hk"}},
    {0xF2,{"kw","qa","kh","ws","in","mo","vn","ph","jp","sg","mv","id","ae","np","vu"}},
    {0xF3,{"la","th","to","--","--","--","--","--","pg","--","ye","--","--","fm","mn"}}
  });

  std::string result("--");

  uint16_t pi_cc = pi >> 12;

  if (country_codes.find(ecc) != country_codes.end() && pi_cc > 0) {
    result = country_codes.at(ecc).at(pi_cc-1);
  }

  return result;

}

std::string getLanguageString(uint16_t code) {
  std::vector<std::string> languages ({
    "Unknown","Albanian","Breton","Catalan",
    "Croatian","Welsh","Czech","Danish",
    "German","English","Spanish","Esperanto",
    "Estonian","Basque","Faroese","French",
    "Frisian","Irish","Gaelic","Galician",
    "Icelandic","Italian","Lappish","Latin",
    "Latvian","Luxembourgian","Lithuanian","Hungarian",
    "Maltese","Dutch","Norwegian","Occitan",
    "Polish","Portuguese","Romanian","Romansh",
    "Serbian","Slovak","Slovene","Finnish",
    "Swedish","Turkish","Flemish","Walloon",
    "","","","",
    "","","","",
    "","","","",
    "","","","",
    "","","","",
    "Background","","","",
    "","Zulu","Vietnamese","Uzbek",
    "Urdu","Ukrainian","Thai","Telugu",
    "Tatar","Tamil","Tadzhik","Swahili",
    "SrananTongo","Somali","Sinhalese","Shona",
    "Serbo-Croat","Ruthenian","Russian","Quechua",
    "Pushtu","Punjabi","Persian","Papamiento",
    "Oriya","Nepali","Ndebele","Marathi",
    "Moldovian","Malaysian","Malagasay","Macedonian",
    "Laotian","Korean","Khmer","Kazakh",
    "Kannada","Japanese","Indonesian","Hindi",
    "Hebrew","Hausa","Gurani","Gujurati",
    "Greek","Georgian","Fulani","Dari",
    "Churash","Chinese","Burmese","Bulgarian",
    "Bengali","Belorussian","Bambora","Azerbaijan",
    "Assamese","Armenian","Arabic","Amharic"
  });

  std::string result("");
  if (code < languages.size()) {
    result = languages[code];
  }

  return result;
}

std::string getAppName(uint16_t aid) {
  std::map<uint16_t,std::string> oda_apps({
    { 0x0000, "None" },
    { 0x0093, "Cross referencing DAB within RDS" },
    { 0x0BCB, "Leisure & Practical Info for Drivers" },
    { 0x0C24, "ELECTRABEL-DSM 7" },
    { 0x0CC1, "Wireless Playground broadcast control signal" },
    { 0x0D45, "RDS-TMC: ALERT-C / EN ISO 14819-1" },
    { 0x0D8B, "ELECTRABEL-DSM 18" },
    { 0x0E2C, "ELECTRABEL-DSM 3" },
    { 0x0E31, "ELECTRABEL-DSM 13" },
    { 0x0F87, "ELECTRABEL-DSM 2" },
    { 0x125F, "I-FM-RDS for fixed and mobile devices" },
    { 0x1BDA, "ELECTRABEL-DSM 1" },
    { 0x1C5E, "ELECTRABEL-DSM 20" },
    { 0x1C68, "ITIS In-vehicle data base" },
    { 0x1CB1, "ELECTRABEL-DSM 10" },
    { 0x1D47, "ELECTRABEL-DSM 4" },
    { 0x1DC2, "CITIBUS 4" },
    { 0x1DC5, "Encrypted TTI using ALERT-Plus" },
    { 0x1E8F, "ELECTRABEL-DSM 17" },
    { 0x4AA1, "RASANT" },
    { 0x4AB7, "ELECTRABEL-DSM 9" },
    { 0x4BA2, "ELECTRABEL-DSM 5" },
    { 0x4BD7, "RadioText+ (RT+)" },
    { 0x4C59, "CITIBUS 2" },
    { 0x4D87, "Radio Commerce System (RCS)" },
    { 0x4D95, "ELECTRABEL-DSM 16" },
    { 0x4D9A, "ELECTRABEL-DSM 11" },
    { 0x5757, "Personal weather station" },
    { 0x6552, "Enhanced RadioText (eRT)" },
    { 0x7373, "Enhanced early warning system" },
    { 0xC350, "NRSC Song Title and Artist" },
    { 0xC3A1, "Personal Radio Service" },
    { 0xC3B0, "iTunes Tagging" },
    { 0xC3C3, "NAVTEQ Traffic Plus" },
    { 0xC4D4, "eEAS" },
    { 0xC549, "Smart Grid Broadcast Channel" },
    { 0xC563, "ID Logic" },
    { 0xC6A7, "Veil Enabled Interactive Device" },
    { 0xC737, "Utility Message Channel (UMC)" },
    { 0xCB73, "CITIBUS 1" },
    { 0xCB97, "ELECTRABEL-DSM 14" },
    { 0xCC21, "CITIBUS 3" },
    { 0xCD46, "RDS-TMC: ALERT-C" },
    { 0xCD47, "RDS-TMC: ALERT-C" },
    { 0xCD9E, "ELECTRABEL-DSM 8" },
    { 0xCE6B, "Encrypted TTI using ALERT-Plus" },
    { 0xE123, "APS Gateway" },
    { 0xE1C1, "Action code" },
    { 0xE319, "ELECTRABEL-DSM 12" },
    { 0xE411, "Beacon downlink" },
    { 0xE440, "ELECTRABEL-DSM 15" },
    { 0xE4A6, "ELECTRABEL-DSM 19" },
    { 0xE5D7, "ELECTRABEL-DSM 6" },
    { 0xE911, "EAS open protocol" }
  });

  std::string result("(Unknown)");
  if (oda_apps.find(aid) != oda_apps.end()) {
    result = oda_apps[aid];
  }

  return result;
}

}
<|endoftext|>