<commit_before>//
//
//    The Laxkit, a windowing toolkit
//    Please consult http://laxkit.sourceforge.net about where to send any
//    correspondence about this software.
//
//    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    Copyright (C) 2012 by Tom Lechner
//

#include <lax/undo.h>
#include <sys/times.h>

#include <iostream>
using namespace std;
#define DBG

namespace Laxkit {

#define REDOABLE 2
#define UNDOABLE 1

//--------------------------------------------- Undoable ------------------------------------------
/*! \class Undoable
 * \brief Subclass from this if you want an object that can act as an agent of undoing.
 */

//--------------------------------------------- UndoData ------------------------------------------
/*! \class UndoData
 * \brief Undo node for UndoManager.
 *
 * Objects classed from this will be passed to Undoable objects to either undo or redo.
 * If direction is 1, then the item is undoable, else 2 is redoable.
 *
 * Subclasses must provide enough information to either redo OR undo, otherwise modify
 * the data to reflect what must be done after Undoable::Undo() or Redo() is called.
 */

static unsigned long getUniqueUndoId()
{
    static unsigned long uniquenumber=1;
    return uniquenumber++;
}

UndoData::UndoData(int nisauto)
{
	isauto=nisauto; //whether this undo element must exist connected to the previous undo element
	if (nisauto) undogroup=getUniqueUndoId();
	else undogroup=0;

	description=NULL;
	data=NULL;
	time=0;
	context=NULL;
	direction=UNDOABLE;
	prev=next=NULL;
}

/*! If prev==NULL, then delete next, else just remove *this from chain.
 */
UndoData::~UndoData()
{
	if (prev) {
		 //is just a link in chain, remove from chain
		if (next) next->prev=prev;
		prev->next=next;
		prev=next=NULL;
	} else {
		 //is head of chain, remove whole chain
		if (next) {
			next->prev=NULL;
			delete next;
			next=NULL;
		}
	}

	delete[] description;
}

int UndoData::isUndoable()
{ return direction==UNDOABLE; }

int UndoData::isRedoable()
{ return direction==REDOABLE; }

//--------------------------------------------- UndoManager ------------------------------------------
/*! \class UndoManager
 * \brief Simple class to keep track of undoes.
 */

UndoManager::UndoManager()
{
	head=current=NULL;
}

UndoManager::~UndoManager()
{
	if (head) delete head;
}

/*! Takes possession of data, and will delete it when done.
 */
int UndoManager::AddUndo(UndoData *data)
{
	//current points to an UndoData that is ready to be undone. It must have isauto==0.
	//If there are no UndoData nodes, then
	//current is NULL. In this case, if head is not NULL, then it is a list of redoables.

	data->time=times(NULL);

     //if any after current, remove them
	if (current) {
		while (current->next && current->next->isRedoable()) {
			delete current->next;
		}
	} else if (head) { delete head; head=NULL; }

    if (current) {
		current->next=data;
		data->prev=current;
		current=current->next;
	} else {
		if (head) {
			 //head would be pointing to a redoable, but there are no undoables
			data->next=head;
			head->prev=data;
			head=data;
		} else head=current=data;
    }

	return 0;
}

//! Default is to call current->context->Undo(), and move current.
int UndoManager::Undo()
{
	if (!current) return 1;
	if (!current->context) {
		cerr <<" *** missing undo context!"<<endl;
		return 2;
	}
	if (current->context->Undo(current)==0) {
		current->direction=REDOABLE;
		current=current->prev;
		return 0;
	}
	return 3; //undo failed
}

//! Default is to call current->context->Redo(), and move current.
int UndoManager::Redo()
{
	if (!head) return 1;
	if (current && !current->next) return 2;

	if (current) current=current->next;
	else current=head;

	if (!current->context) {
		cerr <<" *** missing undo context!"<<endl;
		return 3;
	}

	if (current->context->Redo(current)==0) {
		current->direction=UNDOABLE;
		return 0;
	}
	return 4; //redo failed
}

//--------------------------------------------- UndoManager manager ------------------------------------------
static UndoManager *default_undo_manager=NULL;

UndoManager *GetUndoManager()
{
    if (!default_undo_manager) default_undo_manager=new UndoManager;
    return default_undo_manager;
}

/*! Any old manager will be deleted, and the newmanager pointer taken.
 */
UndoManager *SetUndoManager(UndoManager *newmanager)
{
	if (default_undo_manager) delete default_undo_manager;
	default_undo_manager=newmanager;
	return default_undo_manager;
}

} //namespace Laxkit

<commit_msg>laying groundwork for undo<commit_after>//
//
//    The Laxkit, a windowing toolkit
//    Please consult http://laxkit.sourceforge.net about where to send any
//    correspondence about this software.
//
//    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    Copyright (C) 2012 by Tom Lechner
//

#include <lax/undo.h>
#include <sys/times.h>

#include <iostream>
using namespace std;
#define DBG

namespace Laxkit {

#define REDOABLE 2
#define UNDOABLE 1

//--------------------------------------------- Undoable ------------------------------------------
/*! \class Undoable
 * \brief Subclass from this if you want an object that can act as an agent of undoing.
 */

//--------------------------------------------- UndoData ------------------------------------------
/*! \class UndoData
 * \brief Undo node for UndoManager.
 *
 * Objects classed from this will be passed to Undoable objects to either undo or redo.
 * If direction is 1, then the item is undoable, else 2 is redoable.
 *
 * Subclasses must provide enough information to either redo OR undo, otherwise modify
 * the data to reflect what must be done after Undoable::Undo() or Redo() is called.
 */

static unsigned long getUniqueUndoId()
{
    static unsigned long uniquenumber=1;
    return uniquenumber++;
}

UndoData::UndoData(int nisauto)
{
	isauto=nisauto; //whether this undo element must exist connected to the previous undo element
	if (nisauto) undogroup=getUniqueUndoId();
	else undogroup=0;

	description=NULL;
	data=NULL;
	time=0;
	context=NULL;
	direction=UNDOABLE;
	prev=next=NULL;
}

/*! If prev==NULL, then delete next, else just remove *this from chain.
 *
 * If context is an anObject, then dec_count it.
 */
UndoData::~UndoData()
{
	if (prev) {
		 //is just a link in chain, remove from chain
		if (next) next->prev=prev;
		prev->next=next;
		prev=next=NULL;
	} else {
		 //is head of chain, remove whole chain
		if (next) {
			next->prev=NULL;
			delete next;
			next=NULL;
		}
	}

	if (dynamic_cast<anObject*>(context)) dynamic_cast<anObject*>(context)->dec_count();
	delete[] description;
}

int UndoData::isUndoable()
{ return direction==UNDOABLE; }

int UndoData::isRedoable()
{ return direction==REDOABLE; }

//--------------------------------------------- UndoManager ------------------------------------------
/*! \class UndoManager
 * \brief Simple class to keep track of undoes.
 */

UndoManager::UndoManager()
{
	head=current=NULL;
}

UndoManager::~UndoManager()
{
	if (head) delete head;
}

/*! Takes possession of data, and will delete it when done.
 */
int UndoManager::AddUndo(UndoData *data)
{
	//current points to an UndoData that is ready to be undone. It must have isauto==0.
	//If there are no UndoData nodes, then
	//current is NULL. In this case, if head is not NULL, then it is a list of redoables.

	data->time=times(NULL);

     //if any after current, remove them
	if (current) {
		while (current->next && current->next->isRedoable()) {
			delete current->next;
		}
	} else if (head) { delete head; head=NULL; }

    if (current) {
		current->next=data;
		data->prev=current;
		current=current->next;
	} else {
		if (head) {
			 //head would be pointing to a redoable, but there are no undoables
			data->next=head;
			head->prev=data;
			head=data;
		} else head=current=data;
    }

	return 0;
}

//! Default is to call current->context->Undo(), and move current.
int UndoManager::Undo()
{
	if (!current) return 1;
	if (!current->context) {
		cerr <<" *** missing undo context!"<<endl;
		return 2;
	}
	if (current->context->Undo(current)==0) {
		current->direction=REDOABLE;
		current=current->prev;
		return 0;
	}
	return 3; //undo failed
}

//! Default is to call current->context->Redo(), and move current.
int UndoManager::Redo()
{
	if (!head) return 1;
	if (current && !current->next) return 2;

	if (current) current=current->next;
	else current=head;

	if (!current->context) {
		cerr <<" *** missing undo context!"<<endl;
		return 3;
	}

	if (current->context->Redo(current)==0) {
		current->direction=UNDOABLE;
		return 0;
	}
	return 4; //redo failed
}

//--------------------------------------------- UndoManager manager ------------------------------------------
static UndoManager *default_undo_manager=NULL;

UndoManager *GetUndoManager()
{
    if (!default_undo_manager) default_undo_manager=new UndoManager;
    return default_undo_manager;
}

/*! Any old manager will be deleted, and the newmanager pointer taken.
 */
UndoManager *SetUndoManager(UndoManager *newmanager)
{
	if (default_undo_manager) delete default_undo_manager;
	default_undo_manager=newmanager;
	return default_undo_manager;
}

} //namespace Laxkit

<|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.
*/

#include <assert.h>
#include <string>

#include "common.h"
#include "bzfgl.h"
#include "TextureManager.h"
#include "TextureFont.h"
#include "bzfio.h"

#include "OpenGLGState.h"

TextureFont::TextureFont()
{
  for (int i = 0; i < 128; i++) {
    listIDs[i] = _GL_INVALID_ID;
    fontMetrics[i].charWidth = -1;
  }

  size = -1;
  textureID = -1;

  textureXSize = -1;
  textureYSize = -1;
  textureZStep = -1;
  numberOfCharacters = -1;
}

TextureFont::~TextureFont()
{
  for (int i = 0; i < 128; i++) {
    if (listIDs[i] != _GL_INVALID_ID)
      glDeleteLists(listIDs[i], 1);
  }
}

int TextureFont::getSize()
{
  return size;
}

const char* TextureFont::getFaceName()
{
  return faceName.c_str();
}

/* read values in Key: Value form from font metrics (.fmt) files */
bool TextureFont::fmtRead(OSFile &file, std::string expectedLeft, std::string &retval)
{
  static std::string workingFile;
  static int line = 0;

  // reset line number if we've switched files
  if (workingFile != file.getFileName()) {
    workingFile = file.getFileName();
    line = 0;
  }

  std::string tmpBuf;

  // allow for blank lines with native or foreign linebreaks, comment lines
  while (tmpBuf.size() == 0 || tmpBuf[0] == '#' || tmpBuf[0] == 10 || tmpBuf[0] == 13) {
    tmpBuf = file.readLine();
    // keep a line counter
    line++;
  }

  if (tmpBuf.substr(0, tmpBuf.find(":")) == expectedLeft) {
    retval = tmpBuf.substr(tmpBuf.find(":") + 1, tmpBuf.size());
    return true;
  } else {
    DEBUG2("Unexpected line in font metrics file %s, line %d (expected %s)\n",
      file.getFileName(), line, expectedLeft.c_str());
    return false;
  }
}

bool TextureFont::load(OSFile &file)
{
  const char *extension = file.getExtension();

  if (!extension)
    return false;

  if (!file.open("rb"))
    return false;

  std::string tmpBuf;

  if (!fmtRead(file, "NumChars", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &numberOfCharacters);
  if (!fmtRead(file, "TextureWidth", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureXSize);
  if (!fmtRead(file, "TextureHeight", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureYSize);
  if (!fmtRead(file, "TextZStep", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureZStep);

  int i;
  for (i = 0; i < numberOfCharacters; i++) {
    // check character
    if (!fmtRead(file, "Char", tmpBuf)) return false;
    if ((tmpBuf.size() < 3) ||
	(tmpBuf[1] != '\"' || tmpBuf[2] != (i + 32) || tmpBuf[3] != '\"')) {
      DEBUG2("Unexpected character: %s, in font metrics file %s (expected \"%c\").\n",
	tmpBuf.c_str(), file.getFileName(), (char)(i + 32));
      return false;
    }
    // read metrics
    if (!fmtRead(file, "InitialDist", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].initialDist);
    if (!fmtRead(file, "Width", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].charWidth);
    if (!fmtRead(file, "Whitespace", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].whiteSpaceDist);
    if (!fmtRead(file, "StartX", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].startX);
    if (!fmtRead(file, "EndX", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].endX);
    if (!fmtRead(file, "StartY", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].startY);
    if (!fmtRead(file, "EndY", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].endY);
  }

  file.close();

  // now compute the names
  std::string fullName = file.getStdName();
  char *temp;

  // get just the file part
  temp = strrchr(fullName.c_str(), '/');
  if (temp)
    faceName = temp + 1;
  else
    faceName = fullName;

  // now get the texture name
  texture = faceName;

  // now wack off the extension;
  if (extension)
    faceName.erase(faceName.size() - sizeof(extension), faceName.size());

  temp = strrchr(faceName.c_str(), '_');

  if (temp) {
    size = atoi(temp+1);
    faceName.resize(temp - faceName.c_str());
  }

  // faceName.erase(faceName.size()-sizeof(temp),faceName.size());

  if (extension)
    texture.erase(texture.size() - sizeof(extension), texture.size());

  return (numberOfCharacters > 0);
}

void TextureFont::build(void)
{
  preLoadLists();
}

void TextureFont::preLoadLists(void)
{
  if (texture.size() < 1) {
    DEBUG2("Font %s does not have an associated texture name, not loading\n", texture.c_str());
    return;
  }

  // load up the texture
  TextureManager &tm = TextureManager::instance();
  std::string textureAndDir = "fonts/" + texture;
  textureID = tm.getTextureID(textureAndDir.c_str());

  DEBUG4("Font %s (face %s) has texture ID %d\n", texture.c_str(), faceName.c_str(), textureID);

  if (textureID == -1) {
    DEBUG2("Font texture %s has invalid ID\n", texture.c_str());
    return;
  }

  glPushMatrix();
  for (int i = 0; i < numberOfCharacters; i++) {
    if (listIDs[i] != _GL_INVALID_ID)
      glDeleteLists(listIDs[i], 1);
    listIDs[i] = glGenLists(1);
    glLoadIdentity();

    glNewList(listIDs[i], GL_COMPILE);

    glTranslatef((float)fontMetrics[i].initialDist, 0, 0);

    float fFontY = (float)fontMetrics[i].endY - fontMetrics[i].startY;
    float fFontX = (float)fontMetrics[i].endX - fontMetrics[i].startX;

    glBegin(GL_QUADS);
      glNormal3f(0, 0, 1);
      glTexCoord2f((float)fontMetrics[i].startX / (float)textureXSize, 1.0f - (float)fontMetrics[i].startY / (float)textureYSize);
      glVertex3f(0, fFontY, 0);

      glTexCoord2f((float)fontMetrics[i].startX / (float)textureXSize, 1.0f - (float)fontMetrics[i].endY / (float)textureYSize);
      glVertex3f(0, 0, 0);

      glTexCoord2f((float)fontMetrics[i].endX / (float)textureXSize, 1.0f - (float)fontMetrics[i].endY / (float)textureYSize);
      glVertex3f(fFontX, 0, 0);

      glTexCoord2f((float)fontMetrics[i].endX / (float)textureXSize, 1.0f - (float)fontMetrics[i].startY / (float)textureYSize);
      glVertex3f(fFontX, fFontY, 0);
    glEnd();

    glTranslatef(fFontX, 0, 0);

    glEndList();
  }
  glPopMatrix();

  // create GState
  OpenGLGStateBuilder builder(gstate);
  builder.setTexture(textureID);
  builder.setBlending();
  builder.setAlphaFunc();
  builder.enableTextureReplace(false);
  gstate = builder.getState();
}

float TextureFont::getStrLength(float scale, const char *str)
{
  int len = (int)strlen(str);
  int charToUse = 0;
  int lastCharacter = 0;

  float totalLen = 0;
  float thisPassLen = 0;

  for (int i = 0; i < len; i++) {
    if (str[i] == '\n') {	// newline, get back to the intial X and push down
      thisPassLen = 0;
    } else {
      lastCharacter = charToUse;
      if ((str[i] < 32) || (str[i] < 9))
	charToUse = 32;
      else if (str[i] > numberOfCharacters + 32)
	charToUse = 32;
      else
	charToUse = str[i];

      charToUse -= 32;

      if (charToUse == 0) {
	if (i == 0)
	  thisPassLen += fontMetrics[charToUse].initialDist + fontMetrics[charToUse].charWidth+fontMetrics[charToUse].whiteSpaceDist;
	else
	  thisPassLen += fontMetrics[lastCharacter].whiteSpaceDist + fontMetrics[charToUse].whiteSpaceDist+fontMetrics[charToUse].initialDist + fontMetrics[charToUse].charWidth;
      } else {
	float fFontX = (float)fontMetrics[charToUse].endX - fontMetrics[charToUse].startX;
	thisPassLen += fFontX + (float)fontMetrics[charToUse].initialDist;
      }
    }
    if (thisPassLen > totalLen)
      totalLen = thisPassLen;
  }

  return totalLen * scale;
}

void TextureFont::free(void)
{
  textureID = -1;
}

void TextureFont::drawString(float scale, GLfloat color[3], const char *str)
{
  if (!str)
    return;

  if (textureID == -1)
    preLoadLists();

  if (textureID == -1)
    return;

  gstate.setState();

  TextureManager &tm = TextureManager::instance();
  if (!tm.bind(textureID))
    return;

  if (color[0] >= 0)
    glColor3fv(color);

  glPushMatrix();
  glScalef(scale, scale, 1);

  glPushMatrix();
  int len = (int)strlen(str);
  int charToUse = 0;
  int lastCharacter = 0;
  for (int i = 0; i < len; i++) {
    if (str[i] == '\n') {	// newline, get back to the intial X and push down
      glPopMatrix();
      glTranslatef(0, -(float)textureZStep, 0);
      glPushMatrix();
    } else {
      lastCharacter = charToUse;
      if ((str[i] < 32) || (str[i] < 9))
	charToUse = 32;
      else if (str[i] > numberOfCharacters + 32)
	charToUse = 32;
      else
	charToUse = str[i];

      charToUse -= 32;

      if (charToUse == 0) {
	if (i == 0)
	  glTranslatef((float)fontMetrics[charToUse].initialDist + (float)fontMetrics[charToUse].charWidth + (float)fontMetrics[charToUse].whiteSpaceDist, 0, 0);
	else
	  glTranslatef((float)fontMetrics[lastCharacter].whiteSpaceDist + (float)fontMetrics[charToUse].whiteSpaceDist + fontMetrics[charToUse].initialDist + (float)fontMetrics[charToUse].charWidth, 0, 0);
      } else {
	glCallList(listIDs[charToUse]);
      }
    }
  }
  glPopMatrix();
  if (color[0] >= 0)
    glColor4f(1, 1, 1, 1);
  glPopMatrix();
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>sizeof a char pointer is not necessarily the same thing as the length of the string.  modified version of hdunkel's amd64 patch.<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.
*/

#include <assert.h>
#include <string>
#include <string.h>

#include "common.h"
#include "bzfgl.h"
#include "TextureManager.h"
#include "TextureFont.h"
#include "bzfio.h"

#include "OpenGLGState.h"

TextureFont::TextureFont()
{
  for (int i = 0; i < 128; i++) {
    listIDs[i] = _GL_INVALID_ID;
    fontMetrics[i].charWidth = -1;
  }

  size = -1;
  textureID = -1;

  textureXSize = -1;
  textureYSize = -1;
  textureZStep = -1;
  numberOfCharacters = -1;
}

TextureFont::~TextureFont()
{
  for (int i = 0; i < 128; i++) {
    if (listIDs[i] != _GL_INVALID_ID)
      glDeleteLists(listIDs[i], 1);
  }
}

int TextureFont::getSize()
{
  return size;
}

const char* TextureFont::getFaceName()
{
  return faceName.c_str();
}

/* read values in Key: Value form from font metrics (.fmt) files */
bool TextureFont::fmtRead(OSFile &file, std::string expectedLeft, std::string &retval)
{
  static std::string workingFile;
  static int line = 0;

  // reset line number if we've switched files
  if (workingFile != file.getFileName()) {
    workingFile = file.getFileName();
    line = 0;
  }

  std::string tmpBuf;

  // allow for blank lines with native or foreign linebreaks, comment lines
  while (tmpBuf.size() == 0 || tmpBuf[0] == '#' || tmpBuf[0] == 10 || tmpBuf[0] == 13) {
    tmpBuf = file.readLine();
    // keep a line counter
    line++;
  }

  if (tmpBuf.substr(0, tmpBuf.find(":")) == expectedLeft) {
    retval = tmpBuf.substr(tmpBuf.find(":") + 1, tmpBuf.size());
    return true;
  } else {
    DEBUG2("Unexpected line in font metrics file %s, line %d (expected %s)\n",
      file.getFileName(), line, expectedLeft.c_str());
    return false;
  }
}

bool TextureFont::load(OSFile &file)
{
  const char *extension = file.getExtension();

  if (!extension)
    return false;

  if (!file.open("rb"))
    return false;

  std::string tmpBuf;

  if (!fmtRead(file, "NumChars", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &numberOfCharacters);
  if (!fmtRead(file, "TextureWidth", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureXSize);
  if (!fmtRead(file, "TextureHeight", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureYSize);
  if (!fmtRead(file, "TextZStep", tmpBuf)) return false;
  sscanf(tmpBuf.c_str(), " %d", &textureZStep);

  int i;
  for (i = 0; i < numberOfCharacters; i++) {
    // check character
    if (!fmtRead(file, "Char", tmpBuf)) return false;
    if ((tmpBuf.size() < 3) ||
	(tmpBuf[1] != '\"' || tmpBuf[2] != (i + 32) || tmpBuf[3] != '\"')) {
      DEBUG2("Unexpected character: %s, in font metrics file %s (expected \"%c\").\n",
	tmpBuf.c_str(), file.getFileName(), (char)(i + 32));
      return false;
    }
    // read metrics
    if (!fmtRead(file, "InitialDist", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].initialDist);
    if (!fmtRead(file, "Width", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].charWidth);
    if (!fmtRead(file, "Whitespace", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].whiteSpaceDist);
    if (!fmtRead(file, "StartX", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].startX);
    if (!fmtRead(file, "EndX", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].endX);
    if (!fmtRead(file, "StartY", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].startY);
    if (!fmtRead(file, "EndY", tmpBuf)) return false;
    sscanf(tmpBuf.c_str(), " %d", &fontMetrics[i].endY);
  }

  file.close();

  // now compute the names
  std::string fullName = file.getStdName();
  char *temp;

  // get just the file part
  temp = strrchr(fullName.c_str(), '/');
  if (temp)
    faceName = temp + 1;
  else
    faceName = fullName;

  // now get the texture name
  texture = faceName;

  // now wack off the extension;
  if (extension)
    faceName.erase(faceName.size() - strlen(extension), faceName.size());

  temp = strrchr(faceName.c_str(), '_');

  if (temp) {
    size = atoi(temp+1);
    faceName.resize(temp - faceName.c_str());
  }

  // faceName.erase(faceName.size()-strlen(temp),faceName.size());

  if (extension)
    texture.erase(texture.size() - strlen(extension), texture.size());

  return (numberOfCharacters > 0);
}

void TextureFont::build(void)
{
  preLoadLists();
}

void TextureFont::preLoadLists(void)
{
  if (texture.size() < 1) {
    DEBUG2("Font %s does not have an associated texture name, not loading\n", texture.c_str());
    return;
  }

  // load up the texture
  TextureManager &tm = TextureManager::instance();
  std::string textureAndDir = "fonts/" + texture;
  textureID = tm.getTextureID(textureAndDir.c_str());

  DEBUG4("Font %s (face %s) has texture ID %d\n", texture.c_str(), faceName.c_str(), textureID);

  if (textureID == -1) {
    DEBUG2("Font texture %s has invalid ID\n", texture.c_str());
    return;
  }

  glPushMatrix();
  for (int i = 0; i < numberOfCharacters; i++) {
    if (listIDs[i] != _GL_INVALID_ID)
      glDeleteLists(listIDs[i], 1);
    listIDs[i] = glGenLists(1);
    glLoadIdentity();

    glNewList(listIDs[i], GL_COMPILE);

    glTranslatef((float)fontMetrics[i].initialDist, 0, 0);

    float fFontY = (float)fontMetrics[i].endY - fontMetrics[i].startY;
    float fFontX = (float)fontMetrics[i].endX - fontMetrics[i].startX;

    glBegin(GL_QUADS);
      glNormal3f(0, 0, 1);
      glTexCoord2f((float)fontMetrics[i].startX / (float)textureXSize, 1.0f - (float)fontMetrics[i].startY / (float)textureYSize);
      glVertex3f(0, fFontY, 0);

      glTexCoord2f((float)fontMetrics[i].startX / (float)textureXSize, 1.0f - (float)fontMetrics[i].endY / (float)textureYSize);
      glVertex3f(0, 0, 0);

      glTexCoord2f((float)fontMetrics[i].endX / (float)textureXSize, 1.0f - (float)fontMetrics[i].endY / (float)textureYSize);
      glVertex3f(fFontX, 0, 0);

      glTexCoord2f((float)fontMetrics[i].endX / (float)textureXSize, 1.0f - (float)fontMetrics[i].startY / (float)textureYSize);
      glVertex3f(fFontX, fFontY, 0);
    glEnd();

    glTranslatef(fFontX, 0, 0);

    glEndList();
  }
  glPopMatrix();

  // create GState
  OpenGLGStateBuilder builder(gstate);
  builder.setTexture(textureID);
  builder.setBlending();
  builder.setAlphaFunc();
  builder.enableTextureReplace(false);
  gstate = builder.getState();
}

float TextureFont::getStrLength(float scale, const char *str)
{
  int len = (int)strlen(str);
  int charToUse = 0;
  int lastCharacter = 0;

  float totalLen = 0;
  float thisPassLen = 0;

  for (int i = 0; i < len; i++) {
    if (str[i] == '\n') {	// newline, get back to the intial X and push down
      thisPassLen = 0;
    } else {
      lastCharacter = charToUse;
      if ((str[i] < 32) || (str[i] < 9))
	charToUse = 32;
      else if (str[i] > numberOfCharacters + 32)
	charToUse = 32;
      else
	charToUse = str[i];

      charToUse -= 32;

      if (charToUse == 0) {
	if (i == 0)
	  thisPassLen += fontMetrics[charToUse].initialDist + fontMetrics[charToUse].charWidth+fontMetrics[charToUse].whiteSpaceDist;
	else
	  thisPassLen += fontMetrics[lastCharacter].whiteSpaceDist + fontMetrics[charToUse].whiteSpaceDist+fontMetrics[charToUse].initialDist + fontMetrics[charToUse].charWidth;
      } else {
	float fFontX = (float)fontMetrics[charToUse].endX - fontMetrics[charToUse].startX;
	thisPassLen += fFontX + (float)fontMetrics[charToUse].initialDist;
      }
    }
    if (thisPassLen > totalLen)
      totalLen = thisPassLen;
  }

  return totalLen * scale;
}

void TextureFont::free(void)
{
  textureID = -1;
}

void TextureFont::drawString(float scale, GLfloat color[3], const char *str)
{
  if (!str)
    return;

  if (textureID == -1)
    preLoadLists();

  if (textureID == -1)
    return;

  gstate.setState();

  TextureManager &tm = TextureManager::instance();
  if (!tm.bind(textureID))
    return;

  if (color[0] >= 0)
    glColor3fv(color);

  glPushMatrix();
  glScalef(scale, scale, 1);

  glPushMatrix();
  int len = (int)strlen(str);
  int charToUse = 0;
  int lastCharacter = 0;
  for (int i = 0; i < len; i++) {
    if (str[i] == '\n') {	// newline, get back to the intial X and push down
      glPopMatrix();
      glTranslatef(0, -(float)textureZStep, 0);
      glPushMatrix();
    } else {
      lastCharacter = charToUse;
      if ((str[i] < 32) || (str[i] < 9))
	charToUse = 32;
      else if (str[i] > numberOfCharacters + 32)
	charToUse = 32;
      else
	charToUse = str[i];

      charToUse -= 32;

      if (charToUse == 0) {
	if (i == 0)
	  glTranslatef((float)fontMetrics[charToUse].initialDist + (float)fontMetrics[charToUse].charWidth + (float)fontMetrics[charToUse].whiteSpaceDist, 0, 0);
	else
	  glTranslatef((float)fontMetrics[lastCharacter].whiteSpaceDist + (float)fontMetrics[charToUse].whiteSpaceDist + fontMetrics[charToUse].initialDist + (float)fontMetrics[charToUse].charWidth, 0, 0);
      } else {
	glCallList(listIDs[charToUse]);
      }
    }
  }
  glPopMatrix();
  if (color[0] >= 0)
    glColor4f(1, 1, 1, 1);
  glPopMatrix();
}

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


<commit_before>/* Copyright (c) 2018 PaddlePaddle 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 obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

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

#include "paddle/fluid/framework/device_worker.h"
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"

namespace paddle {
namespace framework {

std::shared_ptr<PullDenseWorker> PullDenseWorker::s_instance_ = NULL;
std::mutex PullDenseWorker::mutex_for_version_;
std::map<uint64_t, uint64_t> PullDenseWorker::last_versions_;
std::map<uint64_t, uint64_t> PullDenseWorker::current_version_;
std::map<uint64_t, std::vector<uint64_t>> PullDenseWorker::training_versions_;
std::map<uint64_t, std::vector<std::string>>
    PullDenseWorker::dense_value_names_;

void PullDenseWorker::Initialize(const TrainerDesc& param) {
  running_ = false;
  param_ = param.pull_dense_param();
  dwp_param_ = param.downpour_param();
  threshold_ = param_.threshold();
  thread_num_ = param_.device_num();
  sleep_time_ms_ = param_.sleep_time_ms();
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    TableParameter table;
    for (auto i : param_.dense_table()) {
      if (i.table_id() == tid) {
        table = i;
        break;
      }
    }
    // setup dense variables for each table
    int var_num = table.dense_value_name_size();
    dense_value_names_[tid].resize(var_num);
    for (int j = 0; j < var_num; ++j) {
      dense_value_names_[tid][j] = table.dense_value_name(j);
    }
    // setup training version for each table
    training_versions_[tid].resize(thread_num_, 0);
    last_versions_[tid] = 0;
    current_version_[tid] = 0;
  }
  fleet_ptr_ = FleetWrapper::GetInstance();
#ifdef PADDLE_WITH_CUDA
  copy_streams_.clear();
#endif
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)
  places_.clear();
  thread_scopes_.clear();
#endif
}

void PullDenseWorker::CreatePinVar() {
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_PSLIB)
  // for (auto& v : dense_value_names_) {
  //  for (auto& name : v.second) {
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    for (size_t j = 0; j < dense_value_names_[tid].size(); j++) {
      auto& name = dense_value_names_[tid][j];
      Variable* var = root_scope_->FindVar(name);

      LoDTensor* tensor = var->GetMutable<LoDTensor>();
      auto* ptr = root_scope_->Var(name + "pin");
      InitializeVariable(ptr, proto::VarType::LOD_TENSOR);
      LoDTensor* pin_tensor = ptr->GetMutable<LoDTensor>();
#ifdef PADDLE_WITH_CUDA
      pin_tensor->mutable_data<float>(tensor->dims(),
                                      platform::CUDAPinnedPlace());
#endif
#ifdef PADDLE_WITH_XPU
      pin_tensor->mutable_data<float>(tensor->dims(), platform::CPUPlace());
#endif
    }
  }
#endif
}

void PullDenseWorker::Wait(std::vector<::std::future<int32_t>>* status_vec) {
  for (auto& t : *status_vec) {
    t.wait();
    auto status = t.get();
    if (status != 0) {
      LOG(WARNING) << "Current Pull Dense Thread Failed Times"
                   << ++pull_dense_fail_times_;
    }
  }

  size_t MAX_FAIL_NUM = 20;
  if (pull_dense_fail_times_ > MAX_FAIL_NUM) {
    PADDLE_THROW(platform::errors::Fatal(
        "Pull dense failed more than %d times.", MAX_FAIL_NUM));
    exit(-1);
  }
  status_vec->resize(0);
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)

  for (size_t i = 0; i < places_.size(); ++i) {
    // for (auto& v : dense_value_names_) {
    //  for (auto& name : v.second) {
    for (int x = 0; x < dwp_param_.program_config(0).pull_dense_table_id_size();
         ++x) {
      uint64_t tid = static_cast<uint64_t>(
          dwp_param_.program_config(0).pull_dense_table_id(x));
      for (size_t j = 0; j < dense_value_names_[tid].size(); j++) {
        auto& name = dense_value_names_[tid][j];

        Variable* pin_var = root_scope_->FindVar(name + "pin");
        LoDTensor* pin_tensor = pin_var->GetMutable<LoDTensor>();
        float* pin_w = pin_tensor->data<float>();
        Variable* var = thread_scopes_[i]->FindVar(name);
        LoDTensor* tensor = var->GetMutable<LoDTensor>();
        float* w = tensor->data<float>();
#ifdef PADDLE_WITH_CUDA
        memory::Copy(BOOST_GET_CONST(platform::CUDAPlace, places_[i]), w,
                     platform::CUDAPinnedPlace(), pin_w,
                     sizeof(float) * tensor->numel(), copy_streams_[i]);
#endif
#ifdef PADDLE_WITH_XPU
        memory::Copy(BOOST_GET_CONST(platform::XPUPlace, places_[i]), w,
                     platform::CPUPlace(), pin_w,
                     sizeof(float) * tensor->numel());
#endif
      }
    }
  }
#endif
}

void PullDenseWorker::Stop() {
  if (running_) {
    running_ = false;
    t_.join();
  }
}

void PullDenseWorker::PullDense(bool force_update) {
  pull_dense_status_.resize(0);
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    if (force_update || CheckUpdateParam(tid)) {
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)
      VLOG(3) << "pull dense " << force_update << " " << tid;
      fleet_ptr_->PullDenseVarsAsync(*root_scope_, tid, dense_value_names_[tid],
                                     &pull_dense_status_, false);
#else
      fleet_ptr_->PullDenseVarsAsync(*root_scope_, tid, dense_value_names_[tid],
                                     &pull_dense_status_, true);
#endif
      ResetThreadVersion(tid);
    }
  }
  if (pull_dense_status_.size() != 0) {
    Wait(&pull_dense_status_);
  }
}

int PullDenseWorker::Start() {
  running_ = true;
  // before training, we can pull dense from pserver first.
  PullDense(true);
  t_ = std::thread(&PullDenseWorker::Run, this);
  return 0;
}

void PullDenseWorker::Run() {
  while (running_) {
    PullDense(false);
#ifndef _WIN32
    usleep(sleep_time_ms_ * 1000);
#endif
  }
}

void PullDenseWorker::IncreaseThreadVersion(int thread_id, uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  training_versions_[table_id][thread_id]++;
}

bool PullDenseWorker::CheckUpdateParam(uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  auto& version = training_versions_[table_id];
  current_version_[table_id] =
      *(std::min_element(version.begin(), version.end()));
  if (current_version_[table_id] - last_versions_[table_id] <
      static_cast<size_t>(threshold_)) {
    return false;
  }
  return true;
}

void PullDenseWorker::ResetThreadVersion(uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  last_versions_[table_id] = current_version_[table_id];
}

int PullDenseWorker::GetThreadIdByScope(const Scope* scope) {
  if (scope_to_thread_id_.find(scope) != scope_to_thread_id_.end()) {
    return scope_to_thread_id_[scope];
  }
  return -1;
}

void PullDenseWorker::SetThreadIdByScope(const Scope* scope, int tid) {
  scope_to_thread_id_[scope] = tid;
}

}  // namespace framework
}  // namespace paddle
<commit_msg>solve bug in pull_dense_worker (#27918)<commit_after>/* Copyright (c) 2018 PaddlePaddle 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 obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

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

#include "paddle/fluid/framework/device_worker.h"
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"

namespace paddle {
namespace framework {

std::shared_ptr<PullDenseWorker> PullDenseWorker::s_instance_ = NULL;
std::mutex PullDenseWorker::mutex_for_version_;
std::map<uint64_t, uint64_t> PullDenseWorker::last_versions_;
std::map<uint64_t, uint64_t> PullDenseWorker::current_version_;
std::map<uint64_t, std::vector<uint64_t>> PullDenseWorker::training_versions_;
std::map<uint64_t, std::vector<std::string>>
    PullDenseWorker::dense_value_names_;

void PullDenseWorker::Initialize(const TrainerDesc& param) {
  running_ = false;
  param_ = param.pull_dense_param();
  dwp_param_ = param.downpour_param();
  threshold_ = param_.threshold();
  thread_num_ = param_.device_num();
  sleep_time_ms_ = param_.sleep_time_ms();
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    TableParameter table;
    for (auto i : param_.dense_table()) {
      if (i.table_id() == tid) {
        table = i;
        break;
      }
    }
    // setup dense variables for each table
    int var_num = table.dense_value_name_size();
    dense_value_names_[tid].resize(var_num);
    for (int j = 0; j < var_num; ++j) {
      dense_value_names_[tid][j] = table.dense_value_name(j);
    }
    // setup training version for each table
    training_versions_[tid].resize(thread_num_, 0);
    last_versions_[tid] = 0;
    current_version_[tid] = 0;
  }
  fleet_ptr_ = FleetWrapper::GetInstance();
#ifdef PADDLE_WITH_CUDA
  copy_streams_.clear();
#endif
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)
  places_.clear();
  thread_scopes_.clear();
#endif
}

void PullDenseWorker::CreatePinVar() {
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)
  // for (auto& v : dense_value_names_) {
  //  for (auto& name : v.second) {
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    for (size_t j = 0; j < dense_value_names_[tid].size(); j++) {
      auto& name = dense_value_names_[tid][j];
      Variable* var = root_scope_->FindVar(name);

      LoDTensor* tensor = var->GetMutable<LoDTensor>();
      auto* ptr = root_scope_->Var(name + "pin");
      InitializeVariable(ptr, proto::VarType::LOD_TENSOR);
      LoDTensor* pin_tensor = ptr->GetMutable<LoDTensor>();
#ifdef PADDLE_WITH_CUDA
      pin_tensor->mutable_data<float>(tensor->dims(),
                                      platform::CUDAPinnedPlace());
#endif
#ifdef PADDLE_WITH_XPU
      pin_tensor->mutable_data<float>(tensor->dims(), platform::CPUPlace());
#endif
    }
  }
#endif
}

void PullDenseWorker::Wait(std::vector<::std::future<int32_t>>* status_vec) {
  for (auto& t : *status_vec) {
    t.wait();
    auto status = t.get();
    if (status != 0) {
      LOG(WARNING) << "Current Pull Dense Thread Failed Times"
                   << ++pull_dense_fail_times_;
    }
  }

  size_t MAX_FAIL_NUM = 20;
  if (pull_dense_fail_times_ > MAX_FAIL_NUM) {
    PADDLE_THROW(platform::errors::Fatal(
        "Pull dense failed more than %d times.", MAX_FAIL_NUM));
    exit(-1);
  }
  status_vec->resize(0);
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)

  for (size_t i = 0; i < places_.size(); ++i) {
    // for (auto& v : dense_value_names_) {
    //  for (auto& name : v.second) {
    for (int x = 0; x < dwp_param_.program_config(0).pull_dense_table_id_size();
         ++x) {
      uint64_t tid = static_cast<uint64_t>(
          dwp_param_.program_config(0).pull_dense_table_id(x));
      for (size_t j = 0; j < dense_value_names_[tid].size(); j++) {
        auto& name = dense_value_names_[tid][j];

        Variable* pin_var = root_scope_->FindVar(name + "pin");
        LoDTensor* pin_tensor = pin_var->GetMutable<LoDTensor>();
        float* pin_w = pin_tensor->data<float>();
        Variable* var = thread_scopes_[i]->FindVar(name);
        LoDTensor* tensor = var->GetMutable<LoDTensor>();
        float* w = tensor->data<float>();
#ifdef PADDLE_WITH_CUDA
        memory::Copy(BOOST_GET_CONST(platform::CUDAPlace, places_[i]), w,
                     platform::CUDAPinnedPlace(), pin_w,
                     sizeof(float) * tensor->numel(), copy_streams_[i]);
#endif
#ifdef PADDLE_WITH_XPU
        memory::Copy(BOOST_GET_CONST(platform::XPUPlace, places_[i]), w,
                     platform::CPUPlace(), pin_w,
                     sizeof(float) * tensor->numel());
#endif
      }
    }
  }
#endif
}

void PullDenseWorker::Stop() {
  if (running_) {
    running_ = false;
    t_.join();
  }
}

void PullDenseWorker::PullDense(bool force_update) {
  pull_dense_status_.resize(0);
  for (int i = 0; i < dwp_param_.program_config(0).pull_dense_table_id_size();
       ++i) {
    uint64_t tid = static_cast<uint64_t>(
        dwp_param_.program_config(0).pull_dense_table_id(i));
    if (force_update || CheckUpdateParam(tid)) {
#if (defined PADDLE_WITH_CUDA) || (defined PADDLE_WITH_XPU)
      VLOG(3) << "pull dense " << force_update << " " << tid;
      fleet_ptr_->PullDenseVarsAsync(*root_scope_, tid, dense_value_names_[tid],
                                     &pull_dense_status_, false);
#else
      fleet_ptr_->PullDenseVarsAsync(*root_scope_, tid, dense_value_names_[tid],
                                     &pull_dense_status_, true);
#endif
      ResetThreadVersion(tid);
    }
  }
  if (pull_dense_status_.size() != 0) {
    Wait(&pull_dense_status_);
  }
}

int PullDenseWorker::Start() {
  running_ = true;
  // before training, we can pull dense from pserver first.
  PullDense(true);
  t_ = std::thread(&PullDenseWorker::Run, this);
  return 0;
}

void PullDenseWorker::Run() {
  while (running_) {
    PullDense(false);
#ifndef _WIN32
    usleep(sleep_time_ms_ * 1000);
#endif
  }
}

void PullDenseWorker::IncreaseThreadVersion(int thread_id, uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  training_versions_[table_id][thread_id]++;
}

bool PullDenseWorker::CheckUpdateParam(uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  auto& version = training_versions_[table_id];
  current_version_[table_id] =
      *(std::min_element(version.begin(), version.end()));
  if (current_version_[table_id] - last_versions_[table_id] <
      static_cast<size_t>(threshold_)) {
    return false;
  }
  return true;
}

void PullDenseWorker::ResetThreadVersion(uint64_t table_id) {
  std::lock_guard<std::mutex> lock(mutex_for_version_);
  last_versions_[table_id] = current_version_[table_id];
}

int PullDenseWorker::GetThreadIdByScope(const Scope* scope) {
  if (scope_to_thread_id_.find(scope) != scope_to_thread_id_.end()) {
    return scope_to_thread_id_[scope];
  }
  return -1;
}

void PullDenseWorker::SetThreadIdByScope(const Scope* scope, int tid) {
  scope_to_thread_id_[scope] = tid;
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>/*************************************************
 * Servo                                         *
 * read joystick data, normalize, write to servo *
 *                                               *
 * @author: Navid Kalaei <navidkalaie@gmail.com> *
 * @github: @navid-kalaei                        *
 * @license: MIT                                 *
 *************************************************/

#include "Arduino.h"
#include "Servo.h"

// time to wait in millis
#define DELAY_TIME 200

#define SERIAL_RATE 9600
#define JOY_PIN_X 0
#define JOY_PIN_Y 1

#define SERVO_PIN 9

// boundries of analogRead()
#define ANALOG_READ_LOW 0
#define ANALOG_READ_HIGH 1023

// boundries for normalizing analogRead() from -90 to +90
#define NORMALIZE_BOUND_LOW -90
#define NORMALIZE_BOUND_HIGH 90
// use this number to shift normalize value be between 0 to 180
#define NORMALIZE_ORIGIN 90

// the value that joystick has at first
// they're usefull in normalizing
short int joyXOrigin = 0;
short int joyYOrigin = 0;

short int joyXOriginNormalized = 0;
short int joyYOriginNormalized = 0;

short int joyValueX = 0;
short int joyValueY = 0;

short int joyValueXNormalized = 0;
short int joyValueYNormalized = 0;

Servo myServo;

int myServoPos = 0;

short int normalize(short int value){
  /*
   * a wrapper for map built-in function
   *
   * @param value: is within analogRead boundries
   * @return: normalize value within normalize boundries
   */

   // https://www.arduino.cc/en/Reference/Map
   // map(value, fromLow, fromHigh, toLow, toHigh)
   return map(value,
    ANALOG_READ_LOW, ANALOG_READ_HIGH,
    NORMALIZE_BOUND_LOW, NORMALIZE_BOUND_HIGH);
}

void checkBoundries(short int &value){
  /*
   * check if value is between normalized boudries or reset it to a boundry
   *
   * @param value: to check
   * @return: void
   */

   if(value > NORMALIZE_BOUND_HIGH){
     value = NORMALIZE_BOUND_HIGH;
   }
   else if(value < NORMALIZE_BOUND_LOW){
     value = NORMALIZE_BOUND_LOW;
   }
}

void setup(){
  myServo.attach(SERVO_PIN);

  // initialize joystick pins
  pinMode(JOY_PIN_X, INPUT);
  pinMode(JOY_PIN_Y, INPUT);

  joyXOrigin = analogRead(JOY_PIN_X);
  joyYOrigin = analogRead(JOY_PIN_Y);

  joyXOriginNormalized = normalize(joyXOrigin);

  joyYOriginNormalized = normalize(joyYOrigin);

  // wait until Serail is not available
  while(!Serial);
  Serial.begin(SERIAL_RATE);
}

void loop(){
  joyValueX = analogRead(JOY_PIN_X);
  joyValueXNormalized = normalize(joyValueX) - joyXOriginNormalized;
  checkBoundries(joyValueXNormalized);

  joyValueY =  analogRead(JOY_PIN_Y);
  joyValueYNormalized = normalize(joyValueY) - joyYOriginNormalized;
  checkBoundries(joyValueYNormalized);

  myServoPos = joyValueXNormalized + NORMALIZE_ORIGIN;
  myServo.write(myServoPos);
  //Serial.println(myServoPos);

  // delay(DELAY_TIME);

}
<commit_msg>remove Y axe from servo/src/main.cpp (because servo is 2 dimential)<commit_after>/*************************************************
 * Servo                                         *
 * read joystick data, normalize, write to servo *
 *                                               *
 * @author: Navid Kalaei <navidkalaie@gmail.com> *
 * @github: @navid-kalaei                        *
 * @license: MIT                                 *
 *************************************************/

#include "Arduino.h"
#include "Servo.h"

// time to wait in millis
#define DELAY_TIME 200

#define SERIAL_RATE 9600
#define JOY_PIN_X 0
#define JOY_PIN_Y 1

#define SERVO_PIN 9

// boundries of analogRead()
#define ANALOG_READ_LOW 0
#define ANALOG_READ_HIGH 1023

// boundries for normalizing analogRead() from -90 to +90
#define NORMALIZE_BOUND_LOW -90
#define NORMALIZE_BOUND_HIGH 90
// use this number to shift normalize value be between 0 to 180
#define NORMALIZE_ORIGIN 90

// the value that joystick has at first
// they're usefull in normalizing
short int joyXOrigin = 0;

short int joyXOriginNormalized = 0;

short int joyValueX = 0;

short int joyValueXNormalized = 0;

Servo myServo;

int myServoPos = 0;

short int normalize(short int value){
  /*
   * a wrapper for map built-in function
   *
   * @param value: is within analogRead boundries
   * @return: normalize value within normalize boundries
   */

   // https://www.arduino.cc/en/Reference/Map
   // map(value, fromLow, fromHigh, toLow, toHigh)
   return map(value,
    ANALOG_READ_LOW, ANALOG_READ_HIGH,
    NORMALIZE_BOUND_LOW, NORMALIZE_BOUND_HIGH);
}

void checkBoundries(short int &value){
  /*
   * check if value is between normalized boudries or reset it to a boundry
   *
   * @param value: to check
   * @return: void
   */

   if(value > NORMALIZE_BOUND_HIGH){
     value = NORMALIZE_BOUND_HIGH;
   }
   else if(value < NORMALIZE_BOUND_LOW){
     value = NORMALIZE_BOUND_LOW;
   }
}

void setup(){
  myServo.attach(SERVO_PIN);

  // initialize joystick pins
  pinMode(JOY_PIN_X, INPUT);

  joyXOrigin = analogRead(JOY_PIN_X);

  joyXOriginNormalized = normalize(joyXOrigin);

  // wait until Serail is not available
  while(!Serial);
  Serial.begin(SERIAL_RATE);
}

void loop(){
  joyValueX = analogRead(JOY_PIN_X);
  joyValueXNormalized = normalize(joyValueX) - joyXOriginNormalized;
  checkBoundries(joyValueXNormalized);

  myServoPos = joyValueXNormalized + NORMALIZE_ORIGIN;
  myServo.write(myServoPos);
  //Serial.println(myServoPos);

  // delay(DELAY_TIME);
}
<|endoftext|>


<commit_before>/*
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"

// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)

#include "HardwareSerial.h"

// Define constants and variables for buffering incoming serial data.  We're
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 16
#else
  #define SERIAL_BUFFER_SIZE 64
#endif

struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile int head;
  volatile int tail;
};

#if defined(UBRRH) || defined(UBRR0H)
  ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR1H)
  ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR2H)
  ring_buffer rx_buffer2  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer2  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR3H)
  ring_buffer rx_buffer3  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer3  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

#if !defined(USART_RX_vect) && !defined(SIG_USART0_RECV) && \
    !defined(SIG_UART0_RECV) && !defined(USART0_RX_vect) && \
	!defined(SIG_UART_RECV)
  #error Don't know what the Data Received vector is called for the first UART
#else
#if defined(USART_RX_vect)
  SIGNAL(USART_RX_vect)
#elif defined(SIG_USART0_RECV)
  SIGNAL(SIG_USART0_RECV)
#elif defined(SIG_UART0_RECV)
  SIGNAL(SIG_UART0_RECV)
#elif defined(USART0_RX_vect)
  SIGNAL(USART0_RX_vect)
#elif defined(SIG_UART_RECV)
  SIGNAL(SIG_UART_RECV)
#endif
  {
  #if defined(UDR0)
    unsigned char c  =  UDR0;
  #elif defined(UDR)
    unsigned char c  =  UDR;
  #else
    #error UDR not defined
  #endif
    store_char(c, &rx_buffer);
  }
#endif

//#if defined(SIG_USART1_RECV)
#if defined(USART1_RX_vect)
  //SIGNAL(SIG_USART1_RECV)
  SIGNAL(USART1_RX_vect)
  {
    unsigned char c = UDR1;
    store_char(c, &rx_buffer1);
  }
#elif defined(SIG_USART1_RECV)
  #error SIG_USART1_RECV
#endif

#if defined(USART2_RX_vect) && defined(UDR2)
  SIGNAL(USART2_RX_vect)
  {
    unsigned char c = UDR2;
    store_char(c, &rx_buffer2);
  }
#elif defined(SIG_USART2_RECV)
  #error SIG_USART2_RECV
#endif

#if defined(USART3_RX_vect) && defined(UDR3)
  SIGNAL(USART3_RX_vect)
  {
    unsigned char c = UDR3;
    store_char(c, &rx_buffer3);
  }
#elif defined(SIG_USART3_RECV)
  #error SIG_USART3_RECV
#endif

#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect)
  #error Don't know what the Data Register Empty vector is called for the first UART
#else
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#endif
{
  if (tx_buffer.head == tx_buffer.tail) {
	// Buffer empty, so disable interrupts
#if defined(UCSR0B)
    cbi(UCSR0B, UDRIE0);
#else
    cbi(UCSRB, UDRIE);
#endif
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer.buffer[tx_buffer.tail];
    tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;

  #if defined(UDR0)
    UDR0 = c;
  #elif defined(UDR)
    UDR = c;
  #else
    #error UDR not defined
  #endif
  }
}
#endif

#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect)
{
  if (tx_buffer1.head == tx_buffer1.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR1B, UDRIE1);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer1.buffer[tx_buffer1.tail];
    tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR1 = c;
  }
}
#endif

#ifdef USART2_UDRE_vect
ISR(USART2_UDRE_vect)
{
  if (tx_buffer2.head == tx_buffer2.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR2B, UDRIE2);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer2.buffer[tx_buffer2.tail];
    tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR2 = c;
  }
}
#endif

#ifdef USART3_UDRE_vect
ISR(USART3_UDRE_vect)
{
  if (tx_buffer3.head == tx_buffer3.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR3B, UDRIE3);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer3.buffer[tx_buffer3.tail];
    tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR3 = c;
  }
}
#endif

// Constructors ////////////////////////////////////////////////////////////////

HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer,
  volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
  volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
  volatile uint8_t *udr,
  uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x)
{
  _rx_buffer = rx_buffer;
  _tx_buffer = tx_buffer;
  _ubrrh = ubrrh;
  _ubrrl = ubrrl;
  _ucsra = ucsra;
  _ucsrb = ucsrb;
  _udr = udr;
  _rxen = rxen;
  _txen = txen;
  _rxcie = rxcie;
  _udrie = udrie;
  _u2x = u2x;
}

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif

  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  while (_tx_buffer->head != _tx_buffer->tail)
    ;

  cbi(*_ucsrb, _rxen);
  cbi(*_ucsrb, _txen);
  cbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);

  // clear any received data
  _rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
  return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
  } else {
    return _rx_buffer->buffer[_rx_buffer->tail];
  }
}

int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
    _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}

void HardwareSerial::flush()
{
  while (_tx_buffer->head != _tx_buffer->tail)
    ;
}

void HardwareSerial::write(uint8_t c)
{
  int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // If the output buffer is full, there's nothing for it other than to
  // wait for the interrupt handler to empty it a bit
  while (i == _tx_buffer->tail)
    ;

  _tx_buffer->buffer[_tx_buffer->head] = c;
  _tx_buffer->head = i;

  sbi(*_ucsrb, _udrie);
}

// Preinstantiate Objects //////////////////////////////////////////////////////

#if defined(UBRRH) && defined(UBRRL)
  HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X);
#elif defined(UBRR0H) && defined(UBRR0L)
  HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0);
#elif defined(USBCON)
  #warning no serial port defined  (port 0)
#else
  #error no serial port defined  (port 0)
#endif

#if defined(UBRR1H)
  HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1);
#endif
#if defined(UBRR2H)
  HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2);
#endif
#if defined(UBRR3H)
  HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3);
#endif

#endif // whole file

<commit_msg>Adding serialEvent(), serialEvent1(), etc.<commit_after>/*
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"

// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)

#include "HardwareSerial.h"

// Define constants and variables for buffering incoming serial data.  We're
// using a ring buffer (I think), in which head is the index of the location
// to which to write the next incoming character and tail is the index of the
// location from which to read.
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 16
#else
  #define SERIAL_BUFFER_SIZE 64
#endif

struct ring_buffer
{
  unsigned char buffer[SERIAL_BUFFER_SIZE];
  volatile int head;
  volatile int tail;
};

#if defined(UBRRH) || defined(UBRR0H)
  ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR1H)
  ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR2H)
  ring_buffer rx_buffer2  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer2  =  { { 0 }, 0, 0 };
#endif
#if defined(UBRR3H)
  ring_buffer rx_buffer3  =  { { 0 }, 0, 0 };
  ring_buffer tx_buffer3  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

#if !defined(USART_RX_vect) && !defined(SIG_USART0_RECV) && \
    !defined(SIG_UART0_RECV) && !defined(USART0_RX_vect) && \
	!defined(SIG_UART_RECV)
  #error Don't know what the Data Received vector is called for the first UART
#else
  void serialEvent() __attribute__((weak));
  void serialEvent() {}
#if defined(USART_RX_vect)
  SIGNAL(USART_RX_vect)
#elif defined(SIG_USART0_RECV)
  SIGNAL(SIG_USART0_RECV)
#elif defined(SIG_UART0_RECV)
  SIGNAL(SIG_UART0_RECV)
#elif defined(USART0_RX_vect)
  SIGNAL(USART0_RX_vect)
#elif defined(SIG_UART_RECV)
  SIGNAL(SIG_UART_RECV)
#endif
  {
  #if defined(UDR0)
    unsigned char c  =  UDR0;
  #elif defined(UDR)
    unsigned char c  =  UDR;
  #else
    #error UDR not defined
  #endif
    store_char(c, &rx_buffer);
	serialEvent();
  }
#endif

#if defined(USART1_RX_vect)
  void serialEvent1() __attribute__((weak));
  void serialEvent1() {}
  SIGNAL(USART1_RX_vect)
  {
    unsigned char c = UDR1;
    store_char(c, &rx_buffer1);
	serialEvent1();
  }
#elif defined(SIG_USART1_RECV)
  #error SIG_USART1_RECV
#endif

#if defined(USART2_RX_vect) && defined(UDR2)
  void serialEvent2() __attribute__((weak));
  void serialEvent2() {}
  SIGNAL(USART2_RX_vect)
  {
    unsigned char c = UDR2;
    store_char(c, &rx_buffer2);
	serialEvent2();
  }
#elif defined(SIG_USART2_RECV)
  #error SIG_USART2_RECV
#endif

#if defined(USART3_RX_vect) && defined(UDR3)
  void serialEvent3() __attribute__((weak));
  void serialEvent3() {}
  SIGNAL(USART3_RX_vect)
  {
    unsigned char c = UDR3;
    store_char(c, &rx_buffer3);
	serialEvent3();
  }
#elif defined(SIG_USART3_RECV)
  #error SIG_USART3_RECV
#endif

#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect)
  #error Don't know what the Data Register Empty vector is called for the first UART
#else
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#endif
{
  if (tx_buffer.head == tx_buffer.tail) {
	// Buffer empty, so disable interrupts
#if defined(UCSR0B)
    cbi(UCSR0B, UDRIE0);
#else
    cbi(UCSRB, UDRIE);
#endif
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer.buffer[tx_buffer.tail];
    tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;

  #if defined(UDR0)
    UDR0 = c;
  #elif defined(UDR)
    UDR = c;
  #else
    #error UDR not defined
  #endif
  }
}
#endif

#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect)
{
  if (tx_buffer1.head == tx_buffer1.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR1B, UDRIE1);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer1.buffer[tx_buffer1.tail];
    tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR1 = c;
  }
}
#endif

#ifdef USART2_UDRE_vect
ISR(USART2_UDRE_vect)
{
  if (tx_buffer2.head == tx_buffer2.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR2B, UDRIE2);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer2.buffer[tx_buffer2.tail];
    tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR2 = c;
  }
}
#endif

#ifdef USART3_UDRE_vect
ISR(USART3_UDRE_vect)
{
  if (tx_buffer3.head == tx_buffer3.tail) {
	// Buffer empty, so disable interrupts
    cbi(UCSR3B, UDRIE3);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = tx_buffer3.buffer[tx_buffer3.tail];
    tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE;

    UDR3 = c;
  }
}
#endif

// Constructors ////////////////////////////////////////////////////////////////

HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer,
  volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
  volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
  volatile uint8_t *udr,
  uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x)
{
  _rx_buffer = rx_buffer;
  _tx_buffer = tx_buffer;
  _ubrrh = ubrrh;
  _ubrrl = ubrrl;
  _ucsra = ucsra;
  _ucsrb = ucsrb;
  _udr = udr;
  _rxen = rxen;
  _txen = txen;
  _rxcie = rxcie;
  _udrie = udrie;
  _u2x = u2x;
}

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif

  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  while (_tx_buffer->head != _tx_buffer->tail)
    ;

  cbi(*_ucsrb, _rxen);
  cbi(*_ucsrb, _txen);
  cbi(*_ucsrb, _rxcie);
  cbi(*_ucsrb, _udrie);

  // clear any received data
  _rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
  return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
  } else {
    return _rx_buffer->buffer[_rx_buffer->tail];
  }
}

int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer->head == _rx_buffer->tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
    _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}

void HardwareSerial::flush()
{
  while (_tx_buffer->head != _tx_buffer->tail)
    ;
}

void HardwareSerial::write(uint8_t c)
{
  int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // If the output buffer is full, there's nothing for it other than to
  // wait for the interrupt handler to empty it a bit
  while (i == _tx_buffer->tail)
    ;

  _tx_buffer->buffer[_tx_buffer->head] = c;
  _tx_buffer->head = i;

  sbi(*_ucsrb, _udrie);
}

// Preinstantiate Objects //////////////////////////////////////////////////////

#if defined(UBRRH) && defined(UBRRL)
  HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X);
#elif defined(UBRR0H) && defined(UBRR0L)
  HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0);
#elif defined(USBCON)
  #warning no serial port defined  (port 0)
#else
  #error no serial port defined  (port 0)
#endif

#if defined(UBRR1H)
  HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1);
#endif
#if defined(UBRR2H)
  HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2);
#endif
#if defined(UBRR3H)
  HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3);
#endif

#endif // whole file

<|endoftext|>


<commit_before>// irview : simple viewer for adding false colour to IR or thermal images
//					/ video / camera feed
// usage: prog {image/video file}

// Author : Toby Breckon, toby.breckon@durham.ac.uk

// Copyright (c) 2008 School of Engineering, Cranfield University
// Copyright (c) 2017 School of Engineering and Computing Sciences, Durham University
// License : GPL - http://www.gnu.org/licenses/gpl.html

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

#include "cv.h"         // open cv general include file

#if (CV_MAJOR_VERSION > 2)

// includes for OpenCV 3.x and onward

#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

#include <iostream>		// standard C++ I/O
#include <string>		// standard C++ I/O
#include <algorithm>		// includes max()

using namespace cv; // OpenCV API is in the C++ "cv" namespace
using namespace std;

#else

// includes for older OpenCV 2.4.x

#include "highgui.h"	// open cv GUI include file

#include <stdio.h>
#include <ctype.h>

#endif

/******************************************************************************/
// setup the camera index properly based on OS platform

// 0 in linux gives first camera for v4l
//-1 in windows gives first device or user dialog selection

#ifdef linux
	#define CAMERA_INDEX 0
#else
	#define CAMERA_INDEX -1
#endif
/******************************************************************************/

#define PROG_ID_STRING "IrView v0.2- (c) Toby Breckon, 2008-2017+"
#define LICENSE_STRING "GPL - http://www.gnu.org/licenses/gpl.html"

static void print_help(char **name){
	printf("\n%s\n", PROG_ID_STRING);
	printf ("\t with OpenCV version %s (%d.%d.%d)\n",
					CV_VERSION,
					CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
	printf("%s\n\n", LICENSE_STRING);

	printf("Usage :%s [image/video file]\n", name[0]);
	printf("Camera interface: run with no file agrument for direct camera use\n");
	printf("\nKeyboard commands\n");
	printf("\t a - automatic scaling (default: on)\n");
	printf("\t b - show both false colour and original (default: off)\n");
	printf("\t c - toggle false colour (default: on)\n");
	printf("\t e - exit (as per x or ESC)\n");
	printf("\t f - toggle full screen (default: off)\n");
	printf("\t x - exit\n\n");
}

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

// concatenate 2 OpenCV Mat Objects side-by-side (in general)

Mat concatImages(Mat img1, Mat img2)
{
		Mat out = Mat(img1.rows, img1.cols + img2.cols, img1.type());
		Mat roi = out(Rect(0, 0, img1.cols, img1.rows));
		Mat roi2 = out(Rect(img1.cols, 0, img2.cols, img2.rows));

		img1.copyTo(roi);

		// depth of img1 is master, depth of img2 is slave
		// so convert if needed

		if (img1.depth() != img2.depth())
		{
				// e.g. if img2 is 8-bit and img1 32-bit - scale to range 0->1 (32-bit)
				// otherwise img2 is 32-bit and img1 is 8-bit - scale to 0->255 (8-bit)

				img2.convertTo(roi2, img1.depth(), (img2.depth() < img1.depth()) ? 1.0 / 255.0 : 255);
		} else {
				img2.copyTo(roi2);
		}
		return out;
}

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

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

	IplImage* img = NULL;			// image object
	CvCapture* capture = NULL; // capture object

	const char* windowNameHSV = PROG_ID_STRING; // window name

 	IplImage* HSV = NULL;					// HSV image
 	IplImage* singleChannelH = NULL;		// Hue plain (from input image)
 	IplImage* singleChannelPlain = NULL; 	// constant plane for S & V

	bool keepProcessing = true;		// loop control flag
	char key = '\0';				// user input
	int	EVENT_LOOP_DELAY = 40;		 // 40ms equates to 1000ms/25fps =
									// 40ms per frame

	bool useFalseColour = true;		 // process flag - false colour
	bool useNormalisation = true;	 // process flag - normalisation
	bool useConcatImage = false; 	 // process flag - show concatenated images
	bool useFullScreen = false; 	 // process flag - run full screen

	// if command line arguments are provided try to read image/video_name
	// otherwise default to capture from attached H/W camera

	if(
		( argc == 2 && (img = cvLoadImage( argv[1], 1)) != 0 ) ||
		( argc == 2 && (capture = cvCreateFileCapture( argv[1] )) != 0 ) ||
		( argc != 2 && (capture = cvCreateCameraCapture( CAMERA_INDEX )) != 0 )
		)
	{
		// print help

		print_help(argv);

		// create window object (use flag=0 to allow resize, 1 to auto fix size)

		cvNamedWindow(windowNameHSV, CV_WINDOW_NORMAL);

		// if capture object in use (i.e. video/camera)
		// get initial image from capture object

		if (capture) {

			// cvQueryFrame s just a combination of cvGrabFrame
			// and cvRetrieveFrame in one call.

			img = cvQueryFrame(capture);
			if(!img){
			if (argc == 2){
				printf("End of video file reached\n");
			} else {
				printf("ERROR: cannot get next frame from camera\n");
			}
			exit(0);
			}

		}

		cvResizeWindow(windowNameHSV, img->width, img->height);

		// setup output image in HSV

		HSV = cvCloneImage(img);
		singleChannelH =
					cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelH->origin = img->origin;
		IplImage* singleChannelV =
					cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelV->origin = img->origin;

		// set single channel up for Saturation / Variance

		singleChannelPlain = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelPlain->origin = img->origin;
		cvSet(singleChannelPlain, cvScalar(255));

		// start main loop

		while (keepProcessing)
		{

			// if capture object in use (i.e. video/camera)
			// get image from capture object

			if (capture) {

				// cvQueryFrame is just a combination of cvGrabFrame
				// and cvRetrieveFrame in one call.

				img = cvQueryFrame(capture);

				// cvQueryFrame s just a combination of cvGrabFrame
				// and cvRetrieveFrame in one call.

				if(!img){
					if (argc == 2){
						printf("End of video file reached\n");
					} else {
						printf("ERROR: cannot get next frame from camera\n");
					}
					exit(0);
				}

			}

			// extract first (or only input image channel)

			if (img->nChannels > 1) {
					cvSetImageCOI(img, 1); // select channel 1, 0 means all channels
			}

			// we will use this for the Hue and Variance channels

			cvCopy(img, singleChannelH);
			cvCopy(img, singleChannelV);
			cvSetImageCOI(img, 0);

			// do colour normalisation (makes it look more impressive)

			if (useNormalisation){
					cvNormalize(singleChannelH, singleChannelH, 0, 255, CV_MINMAX, NULL);
					cvNormalize(singleChannelV, singleChannelV, 0, 255, CV_MINMAX, NULL);
			}

			// do scaling to avoid Hue space wrap around (i.e. dark == bright!)
			// N.B. changing the scaling factor and addition will vary the colour
			// effect - OpenCV 8-bit Hue in range 0->120 => 0.5 * Hue + 90 maps
			// all values to (wrap-around) 180->60 range in Hue.

			cvConvertScale(singleChannelH, singleChannelH, 0.5, 90);

			// put it all back together in RGB

			cvMerge(singleChannelH, singleChannelPlain,	singleChannelV, NULL, HSV);
			cvCvtColor(HSV, HSV, CV_HSV2BGR);

			// display image in window

			if (useConcatImage){
					imshow(windowNameHSV, concatImages(cv::cvarrToMat(img), cv::cvarrToMat(HSV)));
			} else {
				if (useFalseColour){
						cvShowImage(windowNameHSV, HSV);
				} else {
						cvShowImage(windowNameHSV, img);
				}
			}

			// start event processing loop

			key = cvWaitKey(EVENT_LOOP_DELAY);

			// process any keyboard input

			switch (tolower(key))
			{
				case	'x':
				case	'e':
				case	char(27): // ESC key

					// if user presses "x" then exit

		 				keepProcessing = false;
					;
					break;
				case	'a':

					// toggle automatic scaling

					useNormalisation = (!useNormalisation);

					;
					break;
			 	case	'b':

					// toggle concatenated images

					useConcatImage = (!useConcatImage);

						;
						break;
				case	'c':

					// toggle false colour

					useFalseColour = (!useFalseColour);

					;
					break;
				case	'f':

						// toggle false colour

						useFullScreen = (!useFullScreen);

						// set or unset the CV_WINDOW_FULLSCREEN flag via logical AND with toggle boolean

						cvSetWindowProperty(windowNameHSV, CV_WND_PROP_FULLSCREEN, (CV_WINDOW_FULLSCREEN & useFullScreen));

						;
						break;
			}

		}

		// destroy window objects

		cvDestroyAllWindows();

		// destroy image object (if it does not originate from a capture object)

		if (!capture){
				cvReleaseImage( &img );
		}

		cvReleaseImage( &HSV );
		cvReleaseImage( &singleChannelH );
		cvReleaseImage( &singleChannelPlain );

		// all OK : main returns 0

		return 0;
	}

		// not OK : main returns -1

		print_help(argv);
		return -1;
}
/******************************************************************************/
<commit_msg>align comments<commit_after>// irview : simple viewer for adding false colour to IR or thermal images
//					/ video / camera feed
// usage: prog {image/video file}

// Author : Toby Breckon, toby.breckon@durham.ac.uk

// Copyright (c) 2008 School of Engineering, Cranfield University
// Copyright (c) 2017 School of Engineering and Computing Sciences, Durham University
// License : GPL - http://www.gnu.org/licenses/gpl.html

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

#include "cv.h"         // open cv general include file

#if (CV_MAJOR_VERSION > 2)

// includes for OpenCV 3.x and onward

#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

#include <iostream>		// standard C++ I/O
#include <string>		// standard C++ I/O
#include <algorithm>		// includes max()

using namespace cv; // OpenCV API is in the C++ "cv" namespace
using namespace std;

#else

// includes for older OpenCV 2.4.x

#include "highgui.h"	// open cv GUI include file

#include <stdio.h>
#include <ctype.h>

#endif

/******************************************************************************/
// setup the camera index properly based on OS platform

// 0 in linux gives first camera for v4l
//-1 in windows gives first device or user dialog selection

#ifdef linux
	#define CAMERA_INDEX 0
#else
	#define CAMERA_INDEX -1
#endif
/******************************************************************************/

#define PROG_ID_STRING "IrView v0.2- (c) Toby Breckon, 2008-2017+"
#define LICENSE_STRING "GPL - http://www.gnu.org/licenses/gpl.html"

static void print_help(char **name){
	printf("\n%s\n", PROG_ID_STRING);
	printf ("\t with OpenCV version %s (%d.%d.%d)\n",
					CV_VERSION,
					CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
	printf("%s\n\n", LICENSE_STRING);

	printf("Usage :%s [image/video file]\n", name[0]);
	printf("Camera interface: run with no file agrument for direct camera use\n");
	printf("\nKeyboard commands\n");
	printf("\t a - automatic scaling (default: on)\n");
	printf("\t b - show both false colour and original (default: off)\n");
	printf("\t c - toggle false colour (default: on)\n");
	printf("\t e - exit (as per x or ESC)\n");
	printf("\t f - toggle full screen (default: off)\n");
	printf("\t x - exit\n\n");
}

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

// concatenate 2 OpenCV Mat Objects side-by-side (in general)

Mat concatImages(Mat img1, Mat img2)
{
		Mat out = Mat(img1.rows, img1.cols + img2.cols, img1.type());
		Mat roi = out(Rect(0, 0, img1.cols, img1.rows));
		Mat roi2 = out(Rect(img1.cols, 0, img2.cols, img2.rows));

		img1.copyTo(roi);

		// depth of img1 is master, depth of img2 is slave
		// so convert if needed

		if (img1.depth() != img2.depth())
		{
				// e.g. if img2 is 8-bit and img1 32-bit - scale to range 0->1 (32-bit)
				// otherwise img2 is 32-bit and img1 is 8-bit - scale to 0->255 (8-bit)

				img2.convertTo(roi2, img1.depth(), (img2.depth() < img1.depth()) ? 1.0 / 255.0 : 255);
		} else {
				img2.copyTo(roi2);
		}
		return out;
}

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

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

	IplImage* img = NULL;				// image object
	CvCapture* capture = NULL; 	// capture object

	const char* windowNameHSV = PROG_ID_STRING; // window name

 	IplImage* HSV = NULL;									// HSV image
 	IplImage* singleChannelH = NULL;			// Hue plain (from input image)
 	IplImage* singleChannelPlain = NULL; 	// constant plane for S & V

	bool keepProcessing = true;		// loop control flag
	char key = '\0';							// user input
	int	EVENT_LOOP_DELAY = 40;		// 40ms equates to 1000ms/25fps =
																// 40ms per frame

	bool useFalseColour = true;		 // process flag - false colour
	bool useNormalisation = true;	 // process flag - normalisation
	bool useConcatImage = false; 	 // process flag - show concatenated images
	bool useFullScreen = false; 	 // process flag - run full screen

	// if command line arguments are provided try to read image/video_name
	// otherwise default to capture from attached H/W camera

	if(
		( argc == 2 && (img = cvLoadImage( argv[1], 1)) != 0 ) ||
		( argc == 2 && (capture = cvCreateFileCapture( argv[1] )) != 0 ) ||
		( argc != 2 && (capture = cvCreateCameraCapture( CAMERA_INDEX )) != 0 )
		)
	{
		// print help

		print_help(argv);

		// create window object (use flag=0 to allow resize, 1 to auto fix size)

		cvNamedWindow(windowNameHSV, CV_WINDOW_NORMAL);

		// if capture object in use (i.e. video/camera)
		// get initial image from capture object

		if (capture) {

			// cvQueryFrame s just a combination of cvGrabFrame
			// and cvRetrieveFrame in one call.

			img = cvQueryFrame(capture);
			if(!img){
			if (argc == 2){
				printf("End of video file reached\n");
			} else {
				printf("ERROR: cannot get next frame from camera\n");
			}
			exit(0);
			}

		}

		cvResizeWindow(windowNameHSV, img->width, img->height);

		// setup output image in HSV

		HSV = cvCloneImage(img);
		singleChannelH =
					cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelH->origin = img->origin;
		IplImage* singleChannelV =
					cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelV->origin = img->origin;

		// set single channel up for Saturation / Variance

		singleChannelPlain = cvCreateImage(cvSize(img->width,img->height), IPL_DEPTH_8U, 1);
		singleChannelPlain->origin = img->origin;
		cvSet(singleChannelPlain, cvScalar(255));

		// start main loop

		while (keepProcessing)
		{

			// if capture object in use (i.e. video/camera)
			// get image from capture object

			if (capture) {

				// cvQueryFrame is just a combination of cvGrabFrame
				// and cvRetrieveFrame in one call.

				img = cvQueryFrame(capture);

				// cvQueryFrame s just a combination of cvGrabFrame
				// and cvRetrieveFrame in one call.

				if(!img){
					if (argc == 2){
						printf("End of video file reached\n");
					} else {
						printf("ERROR: cannot get next frame from camera\n");
					}
					exit(0);
				}

			}

			// extract first (or only input image channel)

			if (img->nChannels > 1) {
					cvSetImageCOI(img, 1); // select channel 1, 0 means all channels
			}

			// we will use this for the Hue and Variance channels

			cvCopy(img, singleChannelH);
			cvCopy(img, singleChannelV);
			cvSetImageCOI(img, 0);

			// do colour normalisation (makes it look more impressive)

			if (useNormalisation){
					cvNormalize(singleChannelH, singleChannelH, 0, 255, CV_MINMAX, NULL);
					cvNormalize(singleChannelV, singleChannelV, 0, 255, CV_MINMAX, NULL);
			}

			// do scaling to avoid Hue space wrap around (i.e. dark == bright!)
			// N.B. changing the scaling factor and addition will vary the colour
			// effect - OpenCV 8-bit Hue in range 0->120 => 0.5 * Hue + 90 maps
			// all values to (wrap-around) 180->60 range in Hue.

			cvConvertScale(singleChannelH, singleChannelH, 0.5, 90);

			// put it all back together in RGB

			cvMerge(singleChannelH, singleChannelPlain,	singleChannelV, NULL, HSV);
			cvCvtColor(HSV, HSV, CV_HSV2BGR);

			// display image in window

			if (useConcatImage){
					imshow(windowNameHSV, concatImages(cv::cvarrToMat(img), cv::cvarrToMat(HSV)));
			} else {
				if (useFalseColour){
						cvShowImage(windowNameHSV, HSV);
				} else {
						cvShowImage(windowNameHSV, img);
				}
			}

			// start event processing loop

			key = cvWaitKey(EVENT_LOOP_DELAY);

			// process any keyboard input

			switch (tolower(key))
			{
				case	'x':
				case	'e':
				case	char(27): // ESC key

					// if user presses "x" then exit

		 				keepProcessing = false;
					;
					break;
				case	'a':

					// toggle automatic scaling

					useNormalisation = (!useNormalisation);

					;
					break;
			 	case	'b':

					// toggle concatenated images

					useConcatImage = (!useConcatImage);

						;
						break;
				case	'c':

					// toggle false colour

					useFalseColour = (!useFalseColour);

					;
					break;
				case	'f':

						// toggle false colour

						useFullScreen = (!useFullScreen);

						// set or unset the CV_WINDOW_FULLSCREEN flag via logical AND with toggle boolean

						cvSetWindowProperty(windowNameHSV, CV_WND_PROP_FULLSCREEN, (CV_WINDOW_FULLSCREEN & useFullScreen));

						;
						break;
			}

		}

		// destroy window objects

		cvDestroyAllWindows();

		// destroy image object (if it does not originate from a capture object)

		if (!capture){
				cvReleaseImage( &img );
		}

		cvReleaseImage( &HSV );
		cvReleaseImage( &singleChannelH );
		cvReleaseImage( &singleChannelPlain );

		// all OK : main returns 0

		return 0;
	}

		// not OK : main returns -1

		print_help(argv);
		return -1;
}
/******************************************************************************/
<|endoftext|>