<commit_before>#include <map>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient {
	RELAY_DECLARE_CLASS_VARS
private:
	const char* server_host;

	const std::function<void (int)> provide_sock;

	int sock;
	std::mutex send_mutex;
	std::thread* net_thread, *new_thread;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (int)>& provide_sock_in)
			: RELAY_DECLARE_CONSTRUCTOR_EXTENDS, server_host(serverHostIn), provide_sock(provide_sock_in),
			sock(0), net_thread(NULL), new_thread(NULL) {
		send_mutex.lock();
		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

private:
	void reconnect(std::string disconnectReason, bool alreadyLocked=false) {
		printf("Closing relay socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
		exit(-1);
	}

	static void do_connect(RelayNetworkClient* me) {
		me->send_mutex.lock();

		if (me->net_thread)
			me->net_thread->join();
		me->net_thread = me->new_thread;

		me->sock = socket(AF_INET6, SOCK_STREAM, 0);
		if (me->sock <= 0)
			return me->reconnect("unable to create socket", true);

		sockaddr_in6 addr;
		if (!lookup_address(me->server_host, &addr))
			return me->reconnect("unable to lookup host", true);

		int v6only = 0;
		setsockopt(me->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		addr.sin6_port = htons(8336);
		if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
			return me->reconnect("failed to connect()", true);

		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);

		me->net_process();
	}

	void net_process() {
		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		if (send_all(sock, (char*)&version_header, sizeof(version_header)) != sizeof(version_header))
			return reconnect("failed to write version header", true);
		if (send_all(sock, VERSION_STRING, strlen(VERSION_STRING)) != strlen(VERSION_STRING))
			return reconnect("failed to write version string", true);

		int nodelay = 1;
		setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

		if (errno)
			return reconnect("error during connect", true);

		send_mutex.unlock();

		relay_msg_header header;
		if (read_all(sock, (char*)&header, 4*3) != 4*3)
			return reconnect("failed to read message header");

		if (header.magic != RELAY_MAGIC_BYTES)
			return reconnect("invalid magic bytes");
		if (header.type != VERSION_TYPE)
			return reconnect("didnt get version first");

		uint32_t message_size = ntohl(header.length);
		if (message_size > 1000000)
			return reconnect("got message too large");

		char msg[message_size];
		if (read_all(sock, (char*)msg, message_size) < (int64_t)(message_size))
			return reconnect("failed to read message data");

		struct sockaddr_in6 addr;
		socklen_t len = sizeof(addr);
		if (getsockname(sock, (struct sockaddr*)&addr, &len) != 0)
			return reconnect("failed to get bound host/port");
		if (len != sizeof(addr))
			return reconnect("getsockname didnt return a sockaddr_in6?");

		printf("Connected to %s : %d at %lu\n", server_host, addr.sin6_port, epoch_millis_lu(std::chrono::system_clock::now()));

		provide_sock(sock);
		return reconnect("provide_sock returned");
	}

public:
	void receive_sock(int recv_sock) {
		std::lock_guard<std::mutex> lock(send_mutex);
		char buff[0xffff];
		while (true) {
			ssize_t res = recv(recv_sock, buff, sizeof(buff), 0);
			if (res <= 0) { printf("Error reading from recv_sock %d: %ld (%s)\n", recv_sock, res, strerror(errno)); return; }
			res = send_all(sock, buff, res);
			if (res <= 0) { printf("Error sending to sock %d: %ld (%s)\n", sock, res, strerror(errno)); return; }
		}
	}
};

int main(int argc, char** argv) {
	if (argc != 3) {
		printf("USAGE: %s RELAY_SERVER_A RELAY_SERVER_B\n", argv[0]);
		return -1;
	}

	RelayNetworkClient *relayClientA, *relayClientB;
	relayClientA = new RelayNetworkClient(argv[1], [&](int sock) { relayClientB->receive_sock(sock); });
	relayClientB = new RelayNetworkClient(argv[2], [&](int sock) { relayClientA->receive_sock(sock); });

	while (true) { sleep(1000); }
}
<commit_msg>Fix print statement in proxy<commit_after>#include <map>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient {
	RELAY_DECLARE_CLASS_VARS
private:
	const char* server_host;

	const std::function<void (int)> provide_sock;

	int sock;
	std::mutex send_mutex;
	std::thread* net_thread, *new_thread;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (int)>& provide_sock_in)
			: RELAY_DECLARE_CONSTRUCTOR_EXTENDS, server_host(serverHostIn), provide_sock(provide_sock_in),
			sock(0), net_thread(NULL), new_thread(NULL) {
		send_mutex.lock();
		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

private:
	void reconnect(std::string disconnectReason, bool alreadyLocked=false) {
		printf("Closing relay socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
		exit(-1);
	}

	static void do_connect(RelayNetworkClient* me) {
		me->send_mutex.lock();

		if (me->net_thread)
			me->net_thread->join();
		me->net_thread = me->new_thread;

		me->sock = socket(AF_INET6, SOCK_STREAM, 0);
		if (me->sock <= 0)
			return me->reconnect("unable to create socket", true);

		sockaddr_in6 addr;
		if (!lookup_address(me->server_host, &addr))
			return me->reconnect("unable to lookup host", true);

		int v6only = 0;
		setsockopt(me->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		addr.sin6_port = htons(8336);
		if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
			return me->reconnect("failed to connect()", true);

		fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);

		me->net_process();
	}

	void net_process() {
		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		if (send_all(sock, (char*)&version_header, sizeof(version_header)) != sizeof(version_header))
			return reconnect("failed to write version header", true);
		if (send_all(sock, VERSION_STRING, strlen(VERSION_STRING)) != strlen(VERSION_STRING))
			return reconnect("failed to write version string", true);

		int nodelay = 1;
		setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

		if (errno)
			return reconnect("error during connect", true);

		send_mutex.unlock();

		relay_msg_header header;
		if (read_all(sock, (char*)&header, 4*3) != 4*3)
			return reconnect("failed to read message header");

		if (header.magic != RELAY_MAGIC_BYTES)
			return reconnect("invalid magic bytes");
		if (header.type != VERSION_TYPE)
			return reconnect("didnt get version first");

		uint32_t message_size = ntohl(header.length);
		if (message_size > 1000000)
			return reconnect("got message too large");

		char msg[message_size];
		if (read_all(sock, (char*)msg, message_size) < (int64_t)(message_size))
			return reconnect("failed to read message data");

		struct sockaddr_in6 addr;
		socklen_t len = sizeof(addr);
		if (getsockname(sock, (struct sockaddr*)&addr, &len) != 0)
			return reconnect("failed to get bound host/port");
		if (len != sizeof(addr))
			return reconnect("getsockname didnt return a sockaddr_in6?");

		printf("Connected to %s local_port %d at %lu\n", server_host, addr.sin6_port, epoch_millis_lu(std::chrono::system_clock::now()));

		provide_sock(sock);
		return reconnect("provide_sock returned");
	}

public:
	void receive_sock(int recv_sock) {
		std::lock_guard<std::mutex> lock(send_mutex);
		char buff[0xffff];
		while (true) {
			ssize_t res = recv(recv_sock, buff, sizeof(buff), 0);
			if (res <= 0) { printf("Error reading from recv_sock %d: %ld (%s)\n", recv_sock, res, strerror(errno)); return; }
			res = send_all(sock, buff, res);
			if (res <= 0) { printf("Error sending to sock %d: %ld (%s)\n", sock, res, strerror(errno)); return; }
		}
	}
};

int main(int argc, char** argv) {
	if (argc != 3) {
		printf("USAGE: %s RELAY_SERVER_A RELAY_SERVER_B\n", argv[0]);
		return -1;
	}

	RelayNetworkClient *relayClientA, *relayClientB;
	relayClientA = new RelayNetworkClient(argv[1], [&](int sock) { relayClientB->receive_sock(sock); });
	relayClientB = new RelayNetworkClient(argv[2], [&](int sock) { relayClientA->receive_sock(sock); });

	while (true) { sleep(1000); }
}
<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright (C) 2004 Mark Bucciarelli <mark@hubcapconsulting.com>

   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; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include <kdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextstream.h>

#include "script.h"

static QString srcdir();
static int runscripts
( const QString &interpreter, const QString &extension, const QString &path );

const QString dots = "..................................................";
const QString not_a_test_filename_prefix = "__";

// Read srcdir from Makefile (for builddir != srcdir).
QString srcdir()
{
  bool found = false;
  QString dir;

  QFile file( "Makefile" );
  if ( !file.open( IO_ReadOnly  | IO_Translate ) ) return "";

  QTextStream in( &file );
  QString line;
  while ( !found && !in.atEnd() )
  {
    line = in.readLine();
    if ( line.startsWith( "srcdir = " ) )
    {
      dir = line.mid( 9 );
      found = true;
    }
  }

  if ( !found ) dir = "";

  return dir;
}

int runscripts
( const QString &interpreter, const QString &extension, const QString &path )
{
  int rval = 0;
  QStringList files;

  QDir dir( path );

  Script* s = new Script( dir );

  dir.setNameFilter( extension );
  dir.setFilter( QDir::Files );
  dir.setSorting( QDir::Name | QDir::IgnoreCase );
  const QFileInfoList *list = dir.entryInfoList();
  QFileInfoListIterator it( *list );
  QFileInfo *fi;
  while ( !rval && ( fi = it.current() ) != 0 )
  {
    // Don't run scripts that are shared routines.
    if ( ! fi->fileName().startsWith( not_a_test_filename_prefix ) )
    {
      s->addArgument( interpreter );
      s->addArgument( path + QDir::separator() + fi->fileName().latin1() );

      // Thorsten's xautomation tests run with user interaction by default.
      if ( interpreter == "sh" ) s->addArgument( "--batch" );
      if ( interpreter == "php" ) s->addArgument( "--batch" );

      rval = s->run();

      kdDebug() << "runscripts: " << fi->fileName()
        << " " << dots.left( dots.length() - fi->fileName().length() )
        << " " << ( ! rval ? "PASS" : "FAIL" ) << endl;

      // Don't abort if one test files--run them all
      if ( rval ) rval = 0;

      delete s;
      s = new Script( dir );
    }
    ++it;
  }
  delete s;
  s = 0;

  return rval;
}

int main( int, char** )
{
  int rval = 0;

  QString path = srcdir();

  if ( !rval ) rval = runscripts( "python", "*.py *.Py *.PY *.pY", path );

  if ( !rval ) rval = runscripts( "sh", "*.sh *.Sh *.SH *.sH", path );

  if ( !rval ) rval = runscripts( "perl", "*.pl *.Pl *.PL *.pL", path );

  if ( !rval ) rval = runscripts( "php", "*.php *.php3 *.php4 *.php5", path );

  return rval;
}
<commit_msg>deliver error on failed test<commit_after>/* This file is part of the KDE project
   Copyright (C) 2004 Mark Bucciarelli <mark@hubcapconsulting.com>

   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; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include <kdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextstream.h>

#include "script.h"

static QString srcdir();
static int runscripts
( const QString &interpreter, const QString &extension, const QString &path );

const QString dots = "..................................................";
const QString not_a_test_filename_prefix = "__";

// Read srcdir from Makefile (for builddir != srcdir).
QString srcdir()
{
  bool found = false;
  QString dir;

  QFile file( "Makefile" );
  if ( !file.open( IO_ReadOnly  | IO_Translate ) ) return "";

  QTextStream in( &file );
  QString line;
  while ( !found && !in.atEnd() )
  {
    line = in.readLine();
    if ( line.startsWith( "srcdir = " ) )
    {
      dir = line.mid( 9 );
      found = true;
    }
  }

  if ( !found ) dir = "";

  return dir;
}

int runscripts
( const QString &interpreter, const QString &extension, const QString &path )
{
  int rval = 0;
  int oneBadApple = 0;
  QStringList files;

  QDir dir( path );

  Script* s = new Script( dir );

  dir.setNameFilter( extension );
  dir.setFilter( QDir::Files );
  dir.setSorting( QDir::Name | QDir::IgnoreCase );
  const QFileInfoList *list = dir.entryInfoList();
  QFileInfoListIterator it( *list );
  QFileInfo *fi;
  while ( !rval && ( fi = it.current() ) != 0 )
  {
    // Don't run scripts that are shared routines.
    if ( ! fi->fileName().startsWith( not_a_test_filename_prefix ) )
    {
      s->addArgument( interpreter );
      s->addArgument( path + QDir::separator() + fi->fileName().latin1() );

      // Thorsten's xautomation tests run with user interaction by default.
      if ( interpreter == "sh" ) s->addArgument( "--batch" );
      if ( interpreter == "php" ) s->addArgument( "--batch" );

      rval = s->run();

      kdDebug() << "runscripts: " << fi->fileName()
        << " " << dots.left( dots.length() - fi->fileName().length() )
        << " " << ( ! rval ? "PASS" : "FAIL" ) << endl;

      // Don't abort if one test files--run them all
      if ( rval )
      {
        oneBadApple = 1;
        rval = 0;
      }

      delete s;
      s = new Script( dir );
    }
    ++it;
  }
  delete s;
  s = 0;

  return oneBadApple;
}

int main( int, char** )
{
  int rval = 0;

  QString path = srcdir();

  if ( !rval ) rval = runscripts( "python", "*.py *.Py *.PY *.pY", path );

  if ( !rval ) rval = runscripts( "sh", "*.sh *.Sh *.SH *.sH", path );

  if ( !rval ) rval = runscripts( "perl", "*.pl *.Pl *.PL *.pL", path );

  if ( !rval ) rval = runscripts( "php", "*.php *.php3 *.php4 *.php5", path );

  return rval;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/io/MutatorInputStream.h"

using namespace db::io;
using namespace db::rt;

MutatorInputStream::MutatorInputStream(
   InputStream* is, MutationAlgorithm* algorithm, bool cleanup) :
   FilterInputStream(is, cleanup),
   mSource(2048),
   mDestination(4096)
{
   // store mutation algorithm
   mAlgorithm = algorithm;
   mResult = MutationAlgorithm::NeedsData;
   mSourceEmpty = false;
}

MutatorInputStream::~MutatorInputStream()
{
}

int MutatorInputStream::read(char* b, int length)
{
   int rval = 0;

   // mutate while no data is available and algorithm not complete
   while(rval == 0 && mResult < MutationAlgorithm::CompleteAppend)
   {
      // try to mutate data
      mResult = mAlgorithm->mutateData(&mSource, &mDestination, mSourceEmpty);
      switch(mResult)
      {
         case MutationAlgorithm::NeedsData:
            if(mSource.isFull())
            {
               // no more data available for algorithm
               Exception* e = new Exception(
                  "Insufficient data for mutation algorithm!",
                  "db.io.MutationException");
               Exception::setLast(e);
               rval = -1;
            }
            else
            {
               // read more data from underlying stream
               mSourceEmpty = (mSource.put(mInputStream) == 0);
            }
            break;
         default:
            // set rval to available data
            rval = mDestination.length();
            break;
      }
   }

   // if the algorithm has completed, handle any excess source data
   if(mResult >= MutationAlgorithm::CompleteAppend)
   {
      if(mResult == MutationAlgorithm::CompleteAppend)
      {
         // empty source into destination
         mSource.get(&mDestination, mSource.length(), true);

         // get bytes from destination
         rval = mDestination.get(b, length);

         if(rval == 0 && !mSourceEmpty)
         {
            // read bytes directly into passed buffer
            rval = mInputStream->read(b, length);
         }
      }
      else if(mDestination.isEmpty() && !mSourceEmpty)
      {
         // clear remaining bytes in underlying input stream
         mSource.clear();
         while(mSource.put(mInputStream) > 0)
         {
            mSource.clear();
         }
      }
   }

   return rval;
}
<commit_msg>Fixed various bugs in MutatorInputStream implementation.<commit_after>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include "db/io/MutatorInputStream.h"

using namespace db::io;
using namespace db::rt;

MutatorInputStream::MutatorInputStream(
   InputStream* is, MutationAlgorithm* algorithm, bool cleanup) :
   FilterInputStream(is, cleanup),
   mSource(2048),
   mDestination(4096)
{
   // store mutation algorithm
   mAlgorithm = algorithm;
   mResult = MutationAlgorithm::NeedsData;
   mSourceEmpty = false;
}

MutatorInputStream::~MutatorInputStream()
{
}

int MutatorInputStream::read(char* b, int length)
{
   int rval = 0;

   // mutate while no data is available and algorithm not complete
   while(rval == 0 && mResult < MutationAlgorithm::CompleteAppend)
   {
      // try to mutate data
      mResult = mAlgorithm->mutateData(&mSource, &mDestination, mSourceEmpty);
      switch(mResult)
      {
         case MutationAlgorithm::NeedsData:
            if(mSource.isFull() || mSourceEmpty)
            {
               // no more data available for algorithm
               Exception* e = new Exception(
                  "Insufficient data for mutation algorithm!",
                  "db.io.MutationException");
               Exception::setLast(e);
               rval = -1;
            }
            else
            {
               // read more data from underlying stream
               mSourceEmpty = (mSource.put(mInputStream) == 0);
            }
            break;
         default:
            // set rval to available data
            rval = mDestination.length();
            break;
      }
   }

   // if the algorithm has completed, handle any excess source data
   if(mResult >= MutationAlgorithm::CompleteAppend)
   {
      if(mResult == MutationAlgorithm::CompleteAppend)
      {
         // empty source into destination
         mSource.get(&mDestination, mSource.length(), true);

         // get bytes from destination
         rval = mDestination.get(b, length);

         if(rval == 0 && !mSourceEmpty)
         {
            // read bytes directly into passed buffer
            rval = mInputStream->read(b, length);
         }
      }
      else if(mDestination.isEmpty() && !mSourceEmpty)
      {
         // clear remaining bytes in underlying input stream
         mSource.clear();
         while(mSource.put(mInputStream) > 0)
         {
            mSource.clear();
         }
      }
   }
   else
   {
      // get data from destination buffer
      rval = mDestination.get(b, length);
   }

   return rval;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../hubo-ach/hubo.h"

// for ach
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include <stdbool.h>
#include <math.h>
#include <inttypes.h>
#include "ach.h"

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

// ach message type
//typedef struct hubo h[1];

// ach channels
ach_channel_t chan_num;
ach_channel_t chan_num_console;

static char** my_completion(const char*, int ,int);
char* my_generator(const char*,int);
char * dupstr (char*);
void *xmalloc (int);
void parse(char *s);
int test(char *s , struct hubo *h);
char* getArg(string s, int argNum);
void hubo_update(struct hubo *h);
int name2mot(char*s, struct hubo *h);
double hubo_get(char*s, struct hubo *h);
void hubo_jmc_beep(struct hubo *h, struct console *c, char* buff);
void hubo_jmc_home(struct hubo *h, struct console *c, char* buff);
//char* cmd [] ={ "test","hello", "world", "hell" ,"word", "quit", " " };
char* cmd [] ={ "initialize","fet",
		"ctrl","enczero", "goto","get","test","update", "quit","beep", "home"," "}; //,
/*
		"get RHY", "get RHR", "get RHP", "get RKN", "get RAP", "get RAR",
		"get LHY", "get LHR", "get LHP", "get LKN", "get LAP", "get LAR",
		"get RSP", "get RSR", "get RSY", "get REB", "get RWY", "get RWP",
		"get LSP", "get LSR", "get LSY", "get LEB", "get LWY", "get LWP",
		"get NKY", "get NK1", "get NK2", "get WST", "get RF1", "get RF2",
		"get RF3", "get RF4", "get RF5", "get LF1", "get LF2", "get LF3",
		"get LF4", "get LF5"};
 */

int main() {
	printf("\n");
	printf(" ***************** hubo-ach **************** \n");
	printf(" Support: Daniel M. Lofaro dan@danlofaro.com \n");
	printf(" ******************************************* \n");

        // get initial values for hubo
        // open ach channel
        //int r = ach_open(&chan_num, "hubo", NULL);
        int r = ach_open(&chan_num, ch_hubo, NULL);
        assert( ACH_OK == r );

        //r = ach_open(&chan_num_console, "hubo-console", NULL);
        r = ach_open(&chan_num_console, ch_hubo_console, NULL);
        assert( ACH_OK == r );

	struct hubo H;
        struct console C;
        size_t fs;
        r = ach_get( &chan_num, &H, sizeof(H), &fs, NULL, ACH_O_LAST );
        assert( sizeof(H) == fs );
        r = ach_get( &chan_num_console, &C, sizeof(C), &fs, NULL, ACH_O_LAST );
        //if(r == ACH_OK){assert( sizeof(C) == fs );}

	char *buf;
	rl_attempted_completion_function = my_completion;
	printf("\n");
	while((buf = readline(">> hubo-ach: "))!=NULL) {
	//enable auto-complete
	rl_bind_key('\t',rl_complete);

//	printf("cmd [%s]\n",buf);
//	printf(">> ");
	printf("   ");

	/* get update after every command */
	hubo_update(&H);

	char* buf0 = getArg(buf, 0);
	//printf(buf0);

	if (strcmp(buf0,"update")==0) {
		hubo_update(&H);
		printf("--->Hubo Information Updated\n");
	}
	else if (strcmp(buf0,"get")==0) {
		double jRef = hubo_get(buf,&H);
		char* tmp = getArg(buf,1);
		printf(">> %s = %f rad \n",tmp,jRef);
	}
	else if (strcmp(buf0,"beep")==0) {
		hubo_jmc_beep(&H, &C, buf);
	}
	else if (strcmp(buf0,"home")==0) {
		hubo_jmc_home(&H, &C, buf);
		printf("%s - Initilize \n",getArg(buf,1));
	}
	else if (strcmp(buf0,"ctrl")==0) {
		int onOrOff = atof(getArg(buf,2));
                if(onOrOff == 0 | onOrOff == 1) {
                        C.cmd[0] = HUBO_CTRL_ON_OFF;
                        C.cmd[1] = name2mot(getArg(buf,1),&H);  // set motor num
                        C.cmd[2] = atof(getArg(buf,2));         // 1 = on, 0 = 0ff
                        int r = ach_put( &chan_num_console, &C, sizeof(C) );
                        if(onOrOff == 0) {
                                printf("%s - Turning Off CTRL\n",getArg(buf,1));}
                        else {
                                printf("%s - Turning On CTRL\n",getArg(buf,1));}
                }

	}
	else if (strcmp(buf0,"fet")==0) {
		int onOrOff = atof(getArg(buf,2));
		if(onOrOff == 0 | onOrOff == 1) {
			C.cmd[0] = HUBO_FET_ON_OFF;
			C.cmd[1] = name2mot(getArg(buf,1),&H);  // set motor num
			C.cmd[2] = atof(getArg(buf,2));		// 1 = on, 0 = 0ff
       			int r = ach_put( &chan_num_console, &C, sizeof(C) );
			if(onOrOff == 0) {
				printf("%s - Turning Off FET\n",getArg(buf,1));}
			else {
				printf("%s - Turning On FET\n",getArg(buf,1));}
		}
	}
	else if (strcmp(buf0,"initialize")==0) {
		C.cmd[0] = HUBO_JMC_INI;
		C.cmd[1] = name2mot(getArg(buf,1),&H);	// set motor num
		//C.val[0] = atof(getArg(buf,2));
		r =	ach_put( &chan_num_console, &C, sizeof(C));
		printf("%s - Initilize \n",getArg(buf,1));
	}
	else if (strcmp(buf0,"test")==0)
		test(buf, &H);
	/* Quit */
	else if (strcmp(buf0,"quit")==0)
		break;
	if (buf[0]!=0)
	add_history(buf);
	}

	free(buf);
 	return 0;
}

double hubo_get(char*s, struct hubo *h) {

	/* get joint number */
	int jointNo = name2mot(getArg(s,1),h);

	return h->joint[jointNo].ref;
}

void hubo_jmc_beep(struct hubo *h, struct console *c, char* buff) {
	/* make beiep */
	c->cmd[0] = HUBO_JMC_BEEP;
	c->cmd[1] = name2mot(getArg(buff, 1), h);
	c->val[2] = atof(getArg(buff,2));
       	int r = ach_put( &chan_num_console, c, sizeof(*c) );
	printf("send beep r = %i C = %i v = %f\n",r, c->cmd[0], c->val[0]);

}

void hubo_jmc_home(struct hubo *h, struct console *c, char* buff) {
	/* make beiep */
	c->cmd[0] = HUBO_GOTO_HOME;
	c->cmd[1] = name2mot(getArg(buff, 1), h);
       	int r = ach_put( &chan_num_console, c, sizeof(*c) );
//	printf(">> Home %s \n",getArg(buff,1));
}

void hubo_update(struct hubo *h) {
       	size_t fs;
       	int r = ach_get( &chan_num, h, sizeof(*h), &fs, NULL, ACH_O_LAST );
//	printf("r = %i\n",r);
//	printf("sizefo(*h) = %i, fs = %i\n",sizeof(*h), fs);
	//if((r != ACH_STALE_FRAMES) & (r != ACH_MISSED_FRAME)) {
	if((r == ACH_OK) | (r == ACH_MISSED_FRAME)) {
	       	assert( sizeof(*h) == fs );
	}

	// look into posix message que
	// posix rt signal can give signal numb er and an interger
}

char* getArg(string s, int argNum) {
//	printf("\n dan test\n");

	istringstream iss(s);

	int i = 0;
//	char* theOut[];
	do
    	{
        	string sub;
        	iss >> sub;
 //       	cout << "Substring: " << sub << endl;
		if( i == argNum ) {
			return (char*)sub.c_str(); }
		i++;
    	} while (iss);

    	return NULL;
}

int test(char* s, struct hubo *h) {
	printf("\n dan test\n");

	char* mot = getArg(s,1);

	int tmp = name2mot(mot, h);
	printf("mot = %i \n",tmp);
	return 0;
}

int name2mot(char* name, struct hubo *h) {
	/* Returns the number of the requested joint */
	int i = 0;
	int iout = -1;
	for( i = 0; i < numOfJoints; i++ ) {
			char *mot = h->joint[i].name;
			if (strcmp(name, mot) == 0) {
//				printf("i = %i\n", i);
				iout = i;}
	}
	return iout;
}

static char** my_completion( const char * text , int start,  int end) {
	char **matches;

	matches = (char **)NULL;

	if (start == 0)
		matches = rl_completion_matches ((char*)text, &my_generator);
	else
		rl_bind_key('\t',rl_abort);

	return (matches);
}

char* my_generator(const char* text, int state) {
	static int list_index, len;
	char *name;

	if (!state) {
		list_index = 0;
		len = strlen (text);
	}

	while (name = cmd[list_index]) {
		list_index++;

	if (strncmp (name, text, len) == 0)
		return (dupstr(name));
	}

	/* If no names matched, then return NULL. */
	return ((char *)NULL);
}

char * dupstr (char* s) {
	char *r;

	r = (char*) xmalloc ((strlen (s) + 1));
	strcpy (r, s);
	return (r);
}

void * xmalloc (int size) {
	void *buf;

	buf = malloc (size);
	if (!buf) {
		fprintf (stderr, "Error: Out of memory. Exiting.'n");
		exit (1);
	}
	return buf;
}
<commit_msg>converted to new hubo-ach structure - not tested<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../hubo-ach/hubo.h"

// for ach
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include <stdbool.h>
#include <math.h>
#include <inttypes.h>
#include "ach.h"

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

// ach message type
//typedef struct hubo h[1];

// ach channels
ach_channel_t chan_hubo_ref;      // hubo-ach
ach_channel_t chan_hubo_init_cmd; // hubo-ach-console
ach_channel_t chan_hubo_state;    // hubo-ach-state
ach_channel_t chan_hubo_param;    // hubo-ach-param

static char** my_completion(const char*, int ,int);
char* my_generator(const char*,int);
char * dupstr (char*);
void *xmalloc (int);
void parse(char *s);
int test(char *s , struct hubo *h);
char* getArg(string s, int argNum);
void hubo_update(struct hubo_ref *h_ref, struct hubo_state *h_state, struct hubo_param *h_param);
int name2mot(char*s, struct hubo_param *h);
double hubo_get(char*s, struct hubo_ref *h, struct hubo_param *p);
void hubo_jmc_beep(struct hubo_param *h, struct hubo_init_cmd *c, char* buff);
void hubo_jmc_home(struct hubo_param *h, struct hubo_init_cmd *c, char* buff);
//char* cmd [] ={ "test","hello", "world", "hell" ,"word", "quit", " " };
char* cmd [] ={ "initialize","fet",
		"ctrl","enczero", "goto","get","test","update", "quit","beep", "home"," "}; //,
/*
		"get RHY", "get RHR", "get RHP", "get RKN", "get RAP", "get RAR",
		"get LHY", "get LHR", "get LHP", "get LKN", "get LAP", "get LAR",
		"get RSP", "get RSR", "get RSY", "get REB", "get RWY", "get RWP",
		"get LSP", "get LSR", "get LSY", "get LEB", "get LWY", "get LWP",
		"get NKY", "get NK1", "get NK2", "get WST", "get RF1", "get RF2",
		"get RF3", "get RF4", "get RF5", "get LF1", "get LF2", "get LF3",
		"get LF4", "get LF5"};
 */

int main() {
	printf("\n");
	printf(" ***************** hubo-ach **************** \n");
	printf(" Support: Daniel M. Lofaro dan@danlofaro.com \n");
	printf(" ******************************************* \n");

        // get initial values for hubo
        // open ach channel
	int r = ach_open(&chan_hubo_ref, HUBO_CHAN_REF_NAME, NULL);
	assert( ACH_OK == r );

	// open hubo state
	r = ach_open(&chan_hubo_state, HUBO_CHAN_STATE_NAME, NULL);
	assert( ACH_OK == r );

	// initilize control channel
	r = ach_open(&chan_hubo_init_cmd, HUBO_CHAN_INIT_CMD_NAME, NULL);
	assert( ACH_OK == r );

	// paramater
	r = ach_open(&chan_hubo_param, HUBO_CHAN_PARAM_NAME, NULL);
	assert( ACH_OK == r );

	// get initial values for hubo
	struct hubo_ref H_ref;
	struct hubo_init_cmd H_init;
	struct hubo_state H_state;
	struct hubo_param H_param;
	memset( &H_ref,   0, sizeof(H_ref));
	memset( &H_init,  0, sizeof(H_init));
	memset( &H_state, 0, sizeof(H_state));
	memset( &H_param, 0, sizeof(H_param));

	size_t fs;
	r = ach_get( &chan_hubo_ref, &H_ref, sizeof(H_ref), &fs, NULL, ACH_O_LAST );
	assert( sizeof(H_ref) == fs );
	r = ach_get( &chan_hubo_init_cmd, &H_init, sizeof(H_init), &fs, NULL, ACH_O_LAST );
	assert( sizeof(H_init) == fs );
	r = ach_get( &chan_hubo_init_cmd, &H_state, sizeof(H_state), &fs, NULL, ACH_O_LAST );
	assert( sizeof(H_state) == fs );
	r = ach_get( &chan_hubo_param, &H_param, sizeof(H_param), &fs, NULL, ACH_O_LAST );
	assert( sizeof(H_param) == fs );

	char *buf;
	rl_attempted_completion_function = my_completion;
	printf("\n");
	while((buf = readline(">> hubo-ach: "))!=NULL) {
	//enable auto-complete
	rl_bind_key('\t',rl_complete);

//	printf("cmd [%s]\n",buf);
//	printf(">> ");
	printf("   ");

	/* get update after every command */
	hubo_update(&H_ref, &H_state, &H_param);

	char* buf0 = getArg(buf, 0);
	//printf(buf0);

	if (strcmp(buf0,"update")==0) {
		hubo_update(&H_ref, &H_state, &H_param);
		printf("--->Hubo Information Updated\n");
	}
	else if (strcmp(buf0,"get")==0) {
		double jRef = hubo_get(buf,&H_ref, &H_param);
		char* tmp = getArg(buf,1);
		printf(">> %s = %f rad \n",tmp,jRef);
	}
	else if (strcmp(buf0,"beep")==0) {
		hubo_jmc_beep(&H_param, &H_init, buf);
	}
	else if (strcmp(buf0,"home")==0) {
		hubo_jmc_home(&H_param, &H_init, buf);
		printf("%s - Initilize \n",getArg(buf,1));
	}
	else if (strcmp(buf0,"ctrl")==0) {
		int onOrOff = atof(getArg(buf,2));
                if(onOrOff == 0 | onOrOff == 1) {
                        H_init.cmd[0] = HUBO_CTRL_ON_OFF;
                        H_init.cmd[1] = name2mot(getArg(buf,1),&H_param);  // set motor num
                        H_init.cmd[2] = atof(getArg(buf,2));         // 1 = on, 0 = 0ff
                        r = ach_put( &chan_hubo_init_cmd, &H_init, sizeof(H_init) );
                        if(onOrOff == 0) {
                                printf("%s - Turning Off CTRL\n",getArg(buf,1));}
                        else {
                                printf("%s - Turning On CTRL\n",getArg(buf,1));}
                }

	}
	else if (strcmp(buf0,"fet")==0) {
		int onOrOff = atof(getArg(buf,2));
		if(onOrOff == 0 | onOrOff == 1) {
			H_init.cmd[0] = HUBO_FET_ON_OFF;
			H_init.cmd[1] = name2mot(getArg(buf,1),&H_param);  // set motor num
			H_init.cmd[2] = atof(getArg(buf,2));		// 1 = on, 0 = 0ff
                        int r = ach_put( &chan_hubo_init_cmd, &H_init, sizeof(H_init) );
			if(onOrOff == 0) {
				printf("%s - Turning Off FET\n",getArg(buf,1));}
			else {
				printf("%s - Turning On FET\n",getArg(buf,1));}
		}
	}
	else if (strcmp(buf0,"initialize")==0) {
		H_init.cmd[0] = HUBO_JMC_INI;
		H_init.cmd[1] = name2mot(getArg(buf,1),&H_param);	// set motor num
		//C.val[0] = atof(getArg(buf,2));
                int r = ach_put( &chan_hubo_init_cmd, &H_init, sizeof(H_init) );
		printf("%s - Initilize \n",getArg(buf,1));
	}
	/* Quit */
	else if (strcmp(buf0,"quit")==0)
		break;
	if (buf[0]!=0)
	add_history(buf);
	}

	free(buf);
 	return 0;
}

double hubo_get(char*s, struct hubo_ref *h, struct hubo_param *p) {

	/* get joint number */
	int jointNo = name2mot(getArg(s,1),p);

	return h->ref[jointNo];
}

void hubo_jmc_beep(struct hubo_param *h, struct hubo_init_cmd *c, char* buff) {
	/* make beiep */
	c->cmd[0] = HUBO_JMC_BEEP;
	c->cmd[1] = name2mot(getArg(buff, 1), h);
	c->val[2] = atof(getArg(buff,2));
       	int r = ach_put( &chan_hubo_init_cmd, c, sizeof(*c) );
	printf("send beep r = %i C = %i v = %f\n",r, c->cmd[0], c->val[0]);

}

void hubo_jmc_home(struct hubo_param *h, struct hubo_init_cmd *c, char* buff) {
	/* make beiep */
	c->cmd[0] = HUBO_GOTO_HOME;
	c->cmd[1] = name2mot(getArg(buff, 1), h);
       	int r = ach_put( &chan_hubo_init_cmd, c, sizeof(*c) );
//	printf(">> Home %s \n",getArg(buff,1));
}

void hubo_update(struct hubo_ref *h_ref, struct hubo_state *h_state, struct hubo_param *h_param) {
       	size_t fs;
       	int r = ach_get( &chan_hubo_ref, h_ref, sizeof(*h_ref), &fs, NULL, ACH_O_LAST );
	if((r == ACH_OK) | (r == ACH_MISSED_FRAME)) {
	       	assert( sizeof(*h_ref) == fs );}
       	r = ach_get( &chan_hubo_state, h_state, sizeof(*h_state), &fs, NULL, ACH_O_LAST );
	if((r == ACH_OK) | (r == ACH_MISSED_FRAME)) {
	       	assert( sizeof(*h_state) == fs );}
       	r = ach_get( &chan_hubo_param, h_param, sizeof(*h_param), &fs, NULL, ACH_O_LAST );
	if((r == ACH_OK) | (r == ACH_MISSED_FRAME)) {
	       	assert( sizeof(*h_param) == fs );}
	// look into posix message que
	// posix rt signal can give signal numb er and an interger
}

char* getArg(string s, int argNum) {
//	printf("\n dan test\n");

	istringstream iss(s);

	int i = 0;
//	char* theOut[];
	do
    	{
        	string sub;
        	iss >> sub;
 //       	cout << "Substring: " << sub << endl;
		if( i == argNum ) {
			return (char*)sub.c_str(); }
		i++;
    	} while (iss);

    	return NULL;
}

int test(char* s, struct hubo_param *h) {
	printf("\n dan test\n");

	char* mot = getArg(s,1);

	int tmp = name2mot(mot, h);
	printf("mot = %i \n",tmp);
	return 0;
}

int name2mot(char* name, struct hubo_param *h) {
	/* Returns the number of the requested joint */
	int i = 0;
	int iout = -1;
	for( i = 0; i < HUBO_JOINT_COUNT ; i++ ) {
			char *mot = h->joint[i].name;
			if (strcmp(name, mot) == 0) {
//				printf("i = %i\n", i);
				iout = i;}
	}
	return iout;
}

static char** my_completion( const char * text , int start,  int end) {
	char **matches;

	matches = (char **)NULL;

	if (start == 0)
		matches = rl_completion_matches ((char*)text, &my_generator);
	else
		rl_bind_key('\t',rl_abort);

	return (matches);
}

char* my_generator(const char* text, int state) {
	static int list_index, len;
	char *name;

	if (!state) {
		list_index = 0;
		len = strlen (text);
	}

	while (name = cmd[list_index]) {
		list_index++;

	if (strncmp (name, text, len) == 0)
		return (dupstr(name));
	}

	/* If no names matched, then return NULL. */
	return ((char *)NULL);
}

char * dupstr (char* s) {
	char *r;

	r = (char*) xmalloc ((strlen (s) + 1));
	strcpy (r, s);
	return (r);
}

void * xmalloc (int size) {
	void *buf;

	buf = malloc (size);
	if (!buf) {
		fprintf (stderr, "Error: Out of memory. Exiting.'n");
		exit (1);
	}
	return buf;
}
<|endoftext|>


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

#include "IECoreGL/ShaderStateComponent.h"

#include "IECoreGL/CachedConverter.h"
#include "IECoreGL/Shader.h"
#include "IECoreGL/ShaderLoader.h"
#include "IECoreGL/Texture.h"
#include "IECoreGL/TextureLoader.h"

#include "IECore/MessageHandler.h"
#include "IECore/SplineData.h"

#include <iostream>

using namespace std;
using namespace IECore;
using namespace IECoreGL;

//////////////////////////////////////////////////////////////////////////
// ShaderStateComponent::Implementation
//////////////////////////////////////////////////////////////////////////

class ShaderStateComponent::Implementation : public IECore::RefCounted
{

	public :

		Implementation()
			:	m_shaderLoader( ShaderLoader::defaultShaderLoader() ), m_textureLoader( TextureLoader::defaultTextureLoader() ), m_fragmentSource( "" ), m_geometrySource( "" ), m_vertexSource( "" ),
				m_parameterMap( nullptr ), m_shaderSetup( nullptr )
		{
			initHash();
		}

		Implementation( ShaderLoaderPtr shaderLoader, TextureLoaderPtr textureLoader, const std::string &vertexSource, const std::string &geometrySource, const std::string &fragmentSource, IECore::ConstCompoundObjectPtr parameterValues )
			:	m_shaderLoader( shaderLoader ), m_textureLoader( textureLoader ), m_fragmentSource( fragmentSource ), m_geometrySource( geometrySource ),
				m_vertexSource( vertexSource ), m_parameterMap( parameterValues->copy() ), m_shaderSetup( nullptr )
		{
			initHash();
		}

		ShaderLoader *shaderLoader()
		{
			return m_shaderLoader.get();
		}

		TextureLoader *textureLoader()
		{
			return m_textureLoader.get();
		}

		IECore::MurmurHash hash() const
		{
			return m_hash;
		}

		Shader::Setup *shaderSetup()
		{
			ensureShaderSetup();
			return m_shaderSetup.get();
		}

		const Shader::Setup *shaderSetup() const
		{
			ensureShaderSetup();
			return m_shaderSetup.get();
		}

		void addParametersToShaderSetup( Shader::Setup *shaderSetup ) const
		{
			if( !m_parameterMap )
			{
				return;
			}
			const IECore::CompoundObject::ObjectMap &d = m_parameterMap->members();
			for( IECore::CompoundObject::ObjectMap::const_iterator it = d.begin(), eIt = d.end(); it != eIt; it++ )
			{
				const Shader::Parameter *p = shaderSetup->shader()->uniformParameter( it->first );
				if( !p )
				{
					continue;
				}

				if( p->type == GL_SAMPLER_2D )
				{
					ConstTexturePtr texture = nullptr;
					if(
						it->second->typeId() == (IECore::TypeId)IECoreImage::ImagePrimitiveTypeId ||
						it->second->typeId() == IECore::CompoundDataTypeId ||
						it->second->typeId() == IECore::SplineffData::staticTypeId() ||
						it->second->typeId() == IECore::SplinefColor3fData::staticTypeId()
					)
					{
						texture = IECore::runTimeCast<const Texture>( CachedConverter::defaultCachedConverter()->convert( it->second.get() ) );
					}
					else if( it->second->typeId() == IECore::StringData::staticTypeId() )
					{
						const std::string &fileName = static_cast<const IECore::StringData *>( it->second.get() )->readable();
						if( fileName!="" )
						{
							texture = m_textureLoader->load( fileName );
						}
					}

					shaderSetup->addUniformParameter( it->first.value(), texture );
				}
				else if( it->second->isInstanceOf( IECore::DataTypeId ) )
				{
					shaderSetup->addUniformParameter( it->first.value(), boost::static_pointer_cast<const IECore::Data>( it->second ) );
				}
			}

		}

	private :

		ShaderLoaderPtr m_shaderLoader;
		TextureLoaderPtr m_textureLoader;
		std::string m_fragmentSource;
		std::string m_geometrySource;
		std::string m_vertexSource;
		IECore::CompoundObjectPtr m_parameterMap;
		IECore::MurmurHash m_hash;
		mutable Shader::SetupPtr m_shaderSetup;

		void initHash()
		{
			m_hash.append( m_fragmentSource );
			m_hash.append( m_geometrySource );
			m_hash.append( m_vertexSource );
			if( m_parameterMap )
			{
				m_parameterMap->hash( m_hash );
			}
		}

		void ensureShaderSetup() const
		{
			if( m_shaderSetup )
			{
				return;
			}

			if( !m_parameterMap )
			{
				// we were default constructed, so we're just a facing ratio shader.
				m_shaderSetup = new Shader::Setup( Shader::facingRatio() );
				return;
			}

			// load a shader, create a setup, and add our parameters to it.
			ShaderPtr shader = m_shaderLoader->create( m_vertexSource, m_geometrySource, m_fragmentSource );
			m_shaderSetup = new Shader::Setup( shader );

			addParametersToShaderSetup( m_shaderSetup.get() );
		}

};

//////////////////////////////////////////////////////////////////////////
// ShaderStateComponent
//////////////////////////////////////////////////////////////////////////

StateComponent::Description<ShaderStateComponent> ShaderStateComponent::g_description;

ShaderStateComponent::ShaderStateComponent()
	:	m_implementation( new Implementation() )
{
}

ShaderStateComponent::ShaderStateComponent( ShaderLoaderPtr shaderLoader, TextureLoaderPtr textureLoader, const std::string &vertexSource, const std::string &geometrySource, const std::string &fragmentSource, IECore::ConstCompoundObjectPtr parameterValues )
	:	m_implementation( new Implementation( shaderLoader, textureLoader, vertexSource, geometrySource, fragmentSource, parameterValues ) )
{
}

ShaderStateComponent::~ShaderStateComponent()
{
}

void ShaderStateComponent::bind() const
{
}

ShaderLoader *ShaderStateComponent::shaderLoader()
{
	return m_implementation->shaderLoader();
}

TextureLoader *ShaderStateComponent::textureLoader()
{
	return m_implementation->textureLoader();
}

IECore::MurmurHash ShaderStateComponent::hash() const
{
	return m_implementation->hash();
}

Shader::Setup *ShaderStateComponent::shaderSetup()
{
	return m_implementation->shaderSetup();
}

const Shader::Setup *ShaderStateComponent::shaderSetup() const
{
	return m_implementation->shaderSetup();
}

void ShaderStateComponent::addParametersToShaderSetup( Shader::Setup *shaderSetup ) const
{
	m_implementation->addParametersToShaderSetup( shaderSetup );
}
<commit_msg>ShaderStateComponent : support convention for limiting texture resolution<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2013, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreGL/ShaderStateComponent.h"

#include "IECoreGL/CachedConverter.h"
#include "IECoreGL/Shader.h"
#include "IECoreGL/ShaderLoader.h"
#include "IECoreGL/Texture.h"
#include "IECoreGL/TextureLoader.h"

#include "IECore/MessageHandler.h"
#include "IECore/SplineData.h"

#include "boost/algorithm/string.hpp"

#include <iostream>

using namespace std;
using namespace IECore;
using namespace IECoreGL;

namespace
{

const InternedString g_maxTextureResolutionParameterSuffix( ":maxResolution" );

} // namespace

//////////////////////////////////////////////////////////////////////////
// ShaderStateComponent::Implementation
//////////////////////////////////////////////////////////////////////////

class ShaderStateComponent::Implementation : public IECore::RefCounted
{

	public :

		Implementation()
			:	m_shaderLoader( ShaderLoader::defaultShaderLoader() ), m_textureLoader( TextureLoader::defaultTextureLoader() ), m_fragmentSource( "" ), m_geometrySource( "" ), m_vertexSource( "" ),
				m_parameterMap( nullptr ), m_shaderSetup( nullptr )
		{
			initHash();
		}

		Implementation( ShaderLoaderPtr shaderLoader, TextureLoaderPtr textureLoader, const std::string &vertexSource, const std::string &geometrySource, const std::string &fragmentSource, IECore::ConstCompoundObjectPtr parameterValues )
			:	m_shaderLoader( shaderLoader ), m_textureLoader( textureLoader ), m_fragmentSource( fragmentSource ), m_geometrySource( geometrySource ),
				m_vertexSource( vertexSource ), m_parameterMap( parameterValues->copy() ), m_shaderSetup( nullptr )
		{
			initHash();
		}

		ShaderLoader *shaderLoader()
		{
			return m_shaderLoader.get();
		}

		TextureLoader *textureLoader()
		{
			return m_textureLoader.get();
		}

		IECore::MurmurHash hash() const
		{
			return m_hash;
		}

		Shader::Setup *shaderSetup()
		{
			ensureShaderSetup();
			return m_shaderSetup.get();
		}

		const Shader::Setup *shaderSetup() const
		{
			ensureShaderSetup();
			return m_shaderSetup.get();
		}

		void addParametersToShaderSetup( Shader::Setup *shaderSetup ) const
		{
			if( !m_parameterMap )
			{
				return;
			}
			const IECore::CompoundObject::ObjectMap &d = m_parameterMap->members();
			for( IECore::CompoundObject::ObjectMap::const_iterator it = d.begin(), eIt = d.end(); it != eIt; it++ )
			{
				// We're skipping parameters that are intended as metadata that describes textures
				if( boost::ends_with( it->first.c_str(), g_maxTextureResolutionParameterSuffix.c_str() ) )
				{
					continue;
				}

				const Shader::Parameter *p = shaderSetup->shader()->uniformParameter( it->first );
				if( !p )
				{
					continue;
				}

				if( p->type == GL_SAMPLER_2D )
				{
					ConstTexturePtr texture = nullptr;
					if(
						it->second->typeId() == (IECore::TypeId)IECoreImage::ImagePrimitiveTypeId ||
						it->second->typeId() == IECore::CompoundDataTypeId ||
						it->second->typeId() == IECore::SplineffData::staticTypeId() ||
						it->second->typeId() == IECore::SplinefColor3fData::staticTypeId()
					)
					{
						texture = IECore::runTimeCast<const Texture>( CachedConverter::defaultCachedConverter()->convert( it->second.get() ) );
					}
					else if( it->second->typeId() == IECore::StringData::staticTypeId() )
					{
						const std::string &fileName = static_cast<const IECore::StringData *>( it->second.get() )->readable();
						if( fileName!="" )
						{
							// A parameter whose name is the texture parameter's
							// name followed by the suffix for maximum texture
							// resolution is interpreted as such and limits the
							// resolution of the respective texture.
							std::string maxResolutionParameter( it->first.string() + g_maxTextureResolutionParameterSuffix.string() );
							const IntData *maxResolutionData = m_parameterMap->member<IntData>( maxResolutionParameter );

							texture = m_textureLoader->load( fileName, maxResolutionData ? maxResolutionData->readable() : std::numeric_limits<int>::max() );
						}
					}

					shaderSetup->addUniformParameter( it->first.value(), texture );
				}
				else if( it->second->isInstanceOf( IECore::DataTypeId ) )
				{
					shaderSetup->addUniformParameter( it->first.value(), boost::static_pointer_cast<const IECore::Data>( it->second ) );
				}
			}

		}

	private :

		ShaderLoaderPtr m_shaderLoader;
		TextureLoaderPtr m_textureLoader;
		std::string m_fragmentSource;
		std::string m_geometrySource;
		std::string m_vertexSource;
		IECore::CompoundObjectPtr m_parameterMap;
		IECore::MurmurHash m_hash;
		mutable Shader::SetupPtr m_shaderSetup;

		void initHash()
		{
			m_hash.append( m_fragmentSource );
			m_hash.append( m_geometrySource );
			m_hash.append( m_vertexSource );
			if( m_parameterMap )
			{
				m_parameterMap->hash( m_hash );
			}
		}

		void ensureShaderSetup() const
		{
			if( m_shaderSetup )
			{
				return;
			}

			if( !m_parameterMap )
			{
				// we were default constructed, so we're just a facing ratio shader.
				m_shaderSetup = new Shader::Setup( Shader::facingRatio() );
				return;
			}

			// load a shader, create a setup, and add our parameters to it.
			ShaderPtr shader = m_shaderLoader->create( m_vertexSource, m_geometrySource, m_fragmentSource );
			m_shaderSetup = new Shader::Setup( shader );

			addParametersToShaderSetup( m_shaderSetup.get() );
		}

};

//////////////////////////////////////////////////////////////////////////
// ShaderStateComponent
//////////////////////////////////////////////////////////////////////////

StateComponent::Description<ShaderStateComponent> ShaderStateComponent::g_description;

ShaderStateComponent::ShaderStateComponent()
	:	m_implementation( new Implementation() )
{
}

ShaderStateComponent::ShaderStateComponent( ShaderLoaderPtr shaderLoader, TextureLoaderPtr textureLoader, const std::string &vertexSource, const std::string &geometrySource, const std::string &fragmentSource, IECore::ConstCompoundObjectPtr parameterValues )
	:	m_implementation( new Implementation( shaderLoader, textureLoader, vertexSource, geometrySource, fragmentSource, parameterValues ) )
{
}

ShaderStateComponent::~ShaderStateComponent()
{
}

void ShaderStateComponent::bind() const
{
}

ShaderLoader *ShaderStateComponent::shaderLoader()
{
	return m_implementation->shaderLoader();
}

TextureLoader *ShaderStateComponent::textureLoader()
{
	return m_implementation->textureLoader();
}

IECore::MurmurHash ShaderStateComponent::hash() const
{
	return m_implementation->hash();
}

Shader::Setup *ShaderStateComponent::shaderSetup()
{
	return m_implementation->shaderSetup();
}

const Shader::Setup *ShaderStateComponent::shaderSetup() const
{
	return m_implementation->shaderSetup();
}

void ShaderStateComponent::addParametersToShaderSetup( Shader::Setup *shaderSetup ) const
{
	m_implementation->addParametersToShaderSetup( shaderSetup );
}
<|endoftext|>


<commit_before>//
//  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

const char *binstr(int v, int n)
{
	static char buffer[16];
	char *p = buffer;

	for (int i = n-1; i >= 0; i--)
		*(p++) = ((v >> i) & 1) ? '1' : '0';
	*(p++) = 0;

	return buffer;
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options]\n", cmd);
	printf("\n");
	printf("    -i <input_freq_mhz>\n");
	printf("        PLL Input Frequency (default: 12 MHz)\n");
	printf("\n");
	printf("    -o <output_freq_mhz>\n");
	printf("        PLL Output Frequency (default: 60 MHz)\n");
	printf("\n");
	printf("    -S\n");
	printf("        Disable SIMPLE feedback path mode\n");
	printf("\n");
	printf("    -q\n");
	printf("        Do not print PLL settings to stdout\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	double f_pllin = 12;
	double f_pllout = 60;
	bool simple_feedback = true;
	bool quiet = false;

	int opt;
	while ((opt = getopt(argc, argv, "i:o:S:q")) != -1)
	{
		switch (opt)
		{
		case 'i':
			f_pllin = atof(optarg);
			break;
		case 'o':
			f_pllout = atof(optarg);
			break;
		case 'S':
			simple_feedback = false;
			break;
		case 'q':
			quiet = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (optind != argc)
		help(argv[0]);

	bool found_something = false;
	double best_fout = 0;
	int best_divr = 0;
	int best_divf = 0;
	int best_divq = 0;

	if (f_pllin < 10 || f_pllin > 133) {
		fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
		exit(1);
	}

	if (f_pllout < 16 || f_pllout > 275) {
		fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
		exit(1);
	}

	for (int divr = 0; divr <= 15; divr++)
	{
		double f_pfd = f_pllin / (divr + 1);
		if (f_pfd < 10 || f_pfd > 133) continue;

		for (int divf = 0; divf <= 63; divf++)
		{
			if (simple_feedback)
			{
				double f_vco = f_pfd * (divf + 1);
				if (f_vco < 533 || f_vco > 1066) continue;

				for (int divq = 1; divq <= 6; divq++)
				{
					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
			else
			{
				for (int divq = 1; divq <= 6; divq++)
				{
					double f_vco = f_pfd * (divf + 1) * exp2(divq);
					if (f_vco < 533 || f_vco > 1066) continue;

					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
		}
	}

	double f_pfd = f_pllin / (best_divr + 1);;
	double f_vco = f_pfd * (best_divf + 1);

	int filter_range =
			f_pfd < 17 ? 1 :
			f_pfd < 26 ? 2 :
			f_pfd < 44 ? 3 :
			f_pfd < 66 ? 4 :
			f_pfd < 101 ? 5 : 6;

	if (!simple_feedback)
		f_vco *= exp2(best_divq);

	if (!found_something) {
		fprintf(stderr, "Error: No valid configuration found!\n");
		exit(1);
	}

	if (!quiet)
	{
		printf("\n");

		printf("F_PLLIN:  %8.3f MHz (given)\n", f_pllin);
		printf("F_PLLOUT: %8.3f MHz (requested)\n", f_pllout);
		printf("F_PLLOUT: %8.3f MHz (achieved)\n", best_fout);

		printf("\n");

		printf("FEEDBACK: %s\n", simple_feedback ? "SIMPLE" : "NON_SIMPLE");
		printf("F_PFD: %8.3f MHz\n", f_pfd);
		printf("F_VCO: %8.3f MHz\n", f_vco);

		printf("\n");

		printf("DIVR: %2d (4'b%s)\n", best_divr, binstr(best_divr, 4));
		printf("DIVF: %2d (7'b%s)\n", best_divf, binstr(best_divf, 7));
		printf("DIVQ: %2d (3'b%s)\n", best_divq, binstr(best_divq, 3));

		printf("\n");

		printf("FILTER_RANGE: %d (3'b%s)\n", filter_range, binstr(filter_range, 3));

		printf("\n");
	}

	return 0;
}
<commit_msg>icepll: added -f option to export configuration as Verilog module<commit_after>//
//  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at>
//
//  Permission to use, copy, modify, and/or distribute this software for any
//  purpose with or without fee is hereby granted, provided that the above
//  copyright notice and this permission notice appear in all copies.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>

const char *binstr(int v, int n)
{
	static char buffer[16];
	char *p = buffer;

	for (int i = n-1; i >= 0; i--)
		*(p++) = ((v >> i) & 1) ? '1' : '0';
	*(p++) = 0;

	return buffer;
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options]\n", cmd);
	printf("\n");
	printf("    -i <input_freq_mhz>\n");
	printf("        PLL Input Frequency (default: 12 MHz)\n");
	printf("\n");
	printf("    -o <output_freq_mhz>\n");
	printf("        PLL Output Frequency (default: 60 MHz)\n");
	printf("\n");
	printf("    -S\n");
	printf("        Disable SIMPLE feedback path mode\n");
	printf("\n");
	printf("    -f <filename.v>\n");
	printf("        Save PLL configuration as Verilog module\n");
	printf("\n");
	printf("    -q\n");
	printf("        Do not print PLL configuration to stdout\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	double f_pllin = 12;
	double f_pllout = 60;
	bool simple_feedback = true;
	char* verilog_filename = NULL;
	bool quiet = false;

	int opt;
	while ((opt = getopt(argc, argv, "i:o:S:f:q")) != -1)
	{
		switch (opt)
		{
		case 'i':
			f_pllin = atof(optarg);
			break;
		case 'o':
			f_pllout = atof(optarg);
			break;
		case 'S':
			simple_feedback = false;
			break;
		case 'f':
			verilog_filename = optarg;
			break;
		case 'q':
			quiet = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (optind != argc)
		help(argv[0]);

	bool found_something = false;
	double best_fout = 0;
	int best_divr = 0;
	int best_divf = 0;
	int best_divq = 0;

	if (f_pllin < 10 || f_pllin > 133) {
		fprintf(stderr, "Error: PLL input frequency %.3f MHz is outside range 10 MHz - 133 MHz!\n", f_pllin);
		exit(1);
	}

	if (f_pllout < 16 || f_pllout > 275) {
		fprintf(stderr, "Error: PLL output frequency %.3f MHz is outside range 16 MHz - 275 MHz!\n", f_pllout);
		exit(1);
	}

	for (int divr = 0; divr <= 15; divr++)
	{
		double f_pfd = f_pllin / (divr + 1);
		if (f_pfd < 10 || f_pfd > 133) continue;

		for (int divf = 0; divf <= 63; divf++)
		{
			if (simple_feedback)
			{
				double f_vco = f_pfd * (divf + 1);
				if (f_vco < 533 || f_vco > 1066) continue;

				for (int divq = 1; divq <= 6; divq++)
				{
					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
			else
			{
				for (int divq = 1; divq <= 6; divq++)
				{
					double f_vco = f_pfd * (divf + 1) * exp2(divq);
					if (f_vco < 533 || f_vco > 1066) continue;

					double fout = f_vco * exp2(-divq);

					if (fabs(fout - f_pllout) < fabs(best_fout - f_pllout) || !found_something) {
						best_fout = fout;
						best_divr = divr;
						best_divf = divf;
						best_divq = divq;
						found_something = true;
					}
				}
			}
		}
	}

	double f_pfd = f_pllin / (best_divr + 1);;
	double f_vco = f_pfd * (best_divf + 1);

	int filter_range =
			f_pfd < 17 ? 1 :
			f_pfd < 26 ? 2 :
			f_pfd < 44 ? 3 :
			f_pfd < 66 ? 4 :
			f_pfd < 101 ? 5 : 6;

	if (!simple_feedback)
		f_vco *= exp2(best_divq);

	if (!found_something) {
		fprintf(stderr, "Error: No valid configuration found!\n");
		exit(1);
	}

	if (!quiet)
	{
		printf("\n");

		printf("F_PLLIN:  %8.3f MHz (given)\n", f_pllin);
		printf("F_PLLOUT: %8.3f MHz (requested)\n", f_pllout);
		printf("F_PLLOUT: %8.3f MHz (achieved)\n", best_fout);

		printf("\n");

		printf("FEEDBACK: %s\n", simple_feedback ? "SIMPLE" : "NON_SIMPLE");
		printf("F_PFD: %8.3f MHz\n", f_pfd);
		printf("F_VCO: %8.3f MHz\n", f_vco);

		printf("\n");

		printf("DIVR: %2d (4'b%s)\n", best_divr, binstr(best_divr, 4));
		printf("DIVF: %2d (7'b%s)\n", best_divf, binstr(best_divf, 7));
		printf("DIVQ: %2d (3'b%s)\n", best_divq, binstr(best_divq, 3));

		printf("\n");

		printf("FILTER_RANGE: %d (3'b%s)\n", filter_range, binstr(filter_range, 3));

		printf("\n");
	}

	if (verilog_filename != NULL)
	{
		// open file for writing
		FILE *f;
		f = fopen(verilog_filename, "w");

		// header
		fprintf(f, "/**\n * PLL configuration\n *\n"
					" * This Verilog source file was generated automatically\n"
					" * using the icepll tool from the IceStorm project.\n"
					" * Use at your own risk.\n"
					" *\n"
					" * Given input frequency:      %8.3f MHz\n"
					" * Requested output frequency: %8.3f MHz\n"
					" * Achieved output frequency:  %8.3f MHz\n"
					" */\n\n",
					f_pllin, f_pllout, best_fout);

		// generate Verilog module
		fprintf(f,  "module pll(\n"
					"\tinput  clock_in,\n"
					"\toutput clock_out,\n"
					"\toutput locked\n"
					"\t)\n\n"
				);

		// save iCE40 PLL tile configuration
		fprintf(f, "SB_PLL40_CORE #(\n");
		fprintf(f, "\t\t.FEEDBACK_PATH(\"%s\"),\n", (simple_feedback ? "SIMPLE" : "NON_SIMPLE"));
		fprintf(f, "\t\t.PLLOUT_SELECT(\"GENCLK\"),\n");
		fprintf(f, "\t\t.DIVR(4'b%s),\n", binstr(best_divr, 4));
		fprintf(f, "\t\t.DIVF(7'b%s),\n", binstr(best_divf, 7));
		fprintf(f, "\t\t.DIVQ(3'b%s),\n", binstr(best_divq, 3));
		fprintf(f, "\t\t.FILTER_RANGE(3'b%s),\n", binstr(filter_range, 3));
		fprintf(f, "\t) uut (\n"
					"\t\t.LOCK(locked),\n"
					"\t\t.RESETB(1'b1),\n"
					"\t\t.BYPASS(1'b0),\n"
					"\t\t.REFERENCECLK(clock_in),\n"
					"\t\t.PLLOUTCORE(clock_out),\n"
					"\t\t);\n\n"
				);

		fprintf(f, "endmodule\n");
		fclose(f);

		printf("PLL configuration written to: %s\n", verilog_filename);
	}

	return 0;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#endif

#include "AttachableObject.h"

#include <Base/Console.h>
#include <App/Application.h>

using namespace Part;
using namespace Attacher;

PROPERTY_SOURCE(Part::AttachableObject, Part::Feature);

AttachableObject::AttachableObject()
   :  _attacher(0)
{
    ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry");

    ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object");
    MapMode.setEnums(AttachEngine::eMapModeStrings);
    //a rough test if mode string list in Attacher.cpp is in sync with eMapMode enum.
    assert(MapMode.getEnumVector().size() == mmDummy_NumberOfModes);

    ADD_PROPERTY_TYPE(MapReversed, (false), "Attachment", App::Prop_None, "Reverse Z direction (flip sketch upside down)");

    ADD_PROPERTY_TYPE(MapPathParameter, (0.0), "Attachment", App::Prop_None, "Sets point of curve to map the sketch to. 0..1 = start..end");

    ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)");

    //setAttacher(new AttachEngine3D);//default attacher
}

AttachableObject::~AttachableObject()
{
    if(_attacher)
        delete _attacher;
}

void AttachableObject::setAttacher(AttachEngine* attacher)
{
    if (_attacher)
        delete _attacher;
    _attacher = attacher;
    updateAttacherVals();
}

bool AttachableObject::positionBySupport()
{
    if (!_attacher)
        throw Base::Exception("AttachableObject: can't positionBySupport, because no AttachEngine is set.");
    updateAttacherVals();
    try{
        this->Placement.setValue(_attacher->calculateAttachedPlacement(this->Placement.getValue()));
        return true;
    } catch (ExceptionCancel) {
        //disabled, don't do anything
        return false;
    };
}

App::DocumentObjectExecReturn *AttachableObject::execute()
{
    if(this->isTouched_Mapping()) {
        try{
            positionBySupport();
        } catch (Base::Exception &e) {
            return new App::DocumentObjectExecReturn(e.what());
        } catch (Standard_Failure &e){
            return new App::DocumentObjectExecReturn(e.GetMessageString());
        }
    }
    return Part::Feature::execute();
}

void setReadonlyness(App::Property &prop, bool on)
{
    unsigned long status = prop.getStatus();
    prop.setStatus(App::Property::ReadOnly, on);
    if (status != prop.getStatus())
        App::GetApplication().signalChangePropertyEditor(prop);
}

void AttachableObject::onChanged(const App::Property* prop)
{
    if(! this->isRestoring()){
        if ((prop == &Support
             || prop == &MapMode
             || prop == &MapPathParameter
             || prop == &MapReversed
             || prop == &superPlacement)){

            bool bAttached = false;
            try{
                bAttached = positionBySupport();
            } catch (Base::Exception &e) {
                this->setError();
                Base::Console().Error("PositionBySupport: %s",e.what());
                //set error message - how?
            } catch (Standard_Failure &e){
                this->setError();
                Base::Console().Error("PositionBySupport: %s",e.GetMessageString());
            }

            eMapMode mmode = eMapMode(this->MapMode.getValue());
            setReadonlyness(this->superPlacement, !bAttached);
            setReadonlyness(this->Placement, bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
        }

    }

    Part::Feature::onChanged(prop);
}

void AttachableObject::updateAttacherVals()
{
    if (!_attacher)
        return;
    _attacher->setUp(this->Support,
                     eMapMode(this->MapMode.getValue()),
                     this->MapReversed.getValue(),
                     this->MapPathParameter.getValue(),
                     0.0,0.0,
                     this->superPlacement.getValue());
}

<commit_msg>+ move global function to namespace<commit_after>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#endif

#include "AttachableObject.h"

#include <Base/Console.h>
#include <App/Application.h>

using namespace Part;
using namespace Attacher;

PROPERTY_SOURCE(Part::AttachableObject, Part::Feature);

AttachableObject::AttachableObject()
   :  _attacher(0)
{
    ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry");

    ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object");
    MapMode.setEnums(AttachEngine::eMapModeStrings);
    //a rough test if mode string list in Attacher.cpp is in sync with eMapMode enum.
    assert(MapMode.getEnumVector().size() == mmDummy_NumberOfModes);

    ADD_PROPERTY_TYPE(MapReversed, (false), "Attachment", App::Prop_None, "Reverse Z direction (flip sketch upside down)");

    ADD_PROPERTY_TYPE(MapPathParameter, (0.0), "Attachment", App::Prop_None, "Sets point of curve to map the sketch to. 0..1 = start..end");

    ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)");

    //setAttacher(new AttachEngine3D);//default attacher
}

AttachableObject::~AttachableObject()
{
    if(_attacher)
        delete _attacher;
}

void AttachableObject::setAttacher(AttachEngine* attacher)
{
    if (_attacher)
        delete _attacher;
    _attacher = attacher;
    updateAttacherVals();
}

bool AttachableObject::positionBySupport()
{
    if (!_attacher)
        throw Base::Exception("AttachableObject: can't positionBySupport, because no AttachEngine is set.");
    updateAttacherVals();
    try{
        this->Placement.setValue(_attacher->calculateAttachedPlacement(this->Placement.getValue()));
        return true;
    } catch (ExceptionCancel) {
        //disabled, don't do anything
        return false;
    };
}

App::DocumentObjectExecReturn *AttachableObject::execute()
{
    if(this->isTouched_Mapping()) {
        try{
            positionBySupport();
        } catch (Base::Exception &e) {
            return new App::DocumentObjectExecReturn(e.what());
        } catch (Standard_Failure &e){
            return new App::DocumentObjectExecReturn(e.GetMessageString());
        }
    }
    return Part::Feature::execute();
}

namespace Attacher {
    void setReadonlyness(App::Property &prop, bool on)
    {
        unsigned long status = prop.getStatus();
        prop.setStatus(App::Property::ReadOnly, on);
        if (status != prop.getStatus())
            App::GetApplication().signalChangePropertyEditor(prop);
    }
}

void AttachableObject::onChanged(const App::Property* prop)
{
    if(! this->isRestoring()){
        if ((prop == &Support
             || prop == &MapMode
             || prop == &MapPathParameter
             || prop == &MapReversed
             || prop == &superPlacement)){

            bool bAttached = false;
            try{
                bAttached = positionBySupport();
            } catch (Base::Exception &e) {
                this->setError();
                Base::Console().Error("PositionBySupport: %s",e.what());
                //set error message - how?
            } catch (Standard_Failure &e){
                this->setError();
                Base::Console().Error("PositionBySupport: %s",e.GetMessageString());
            }

            eMapMode mmode = eMapMode(this->MapMode.getValue());
            setReadonlyness(this->superPlacement, !bAttached);
            setReadonlyness(this->Placement, bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
        }

    }

    Part::Feature::onChanged(prop);
}

void AttachableObject::updateAttacherVals()
{
    if (!_attacher)
        return;
    _attacher->setUp(this->Support,
                     eMapMode(this->MapMode.getValue()),
                     this->MapReversed.getValue(),
                     this->MapPathParameter.getValue(),
                     0.0,0.0,
                     this->superPlacement.getValue());
}

<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "MagnumFont.h"

#include <sstream>
#include <Containers/Array.h>
#include <Utility/Directory.h>
#include <Utility/Unicode.h>
#include <Text/GlyphCache.h>
#include <Trade/ImageData.h>

#include "TgaImporter/TgaImporter.h"

namespace Magnum { namespace Text {

struct MagnumFont::Data {
    Utility::Configuration conf;
    Trade::ImageData2D image;
    std::unordered_map<char32_t, UnsignedInt> glyphId;
    std::vector<Vector2> glyphAdvance;
};

namespace {
    class MagnumFontLayouter: public AbstractLayouter {
        public:
            explicit MagnumFontLayouter(const std::unordered_map<char32_t, UnsignedInt>& glyphId, const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text);

            std::tuple<Rectangle, Rectangle, Vector2> renderGlyph(UnsignedInt i) override;

        private:
            const std::vector<Vector2>& glyphAdvance;
            const GlyphCache& cache;
            const Float fontSize, textSize;
            std::vector<UnsignedInt> glyphs;
    };
}

MagnumFont::MagnumFont(): _opened(nullptr) {}

MagnumFont::MagnumFont(PluginManager::AbstractManager* const manager, std::string plugin): AbstractFont(manager, std::move(plugin)), _opened(nullptr) {}

MagnumFont::~MagnumFont() { close(); }

auto MagnumFont::doFeatures() const -> Features { return Feature::OpenData|Feature::MultiFile|Feature::PreparedGlyphCache; }

bool MagnumFont::doIsOpened() const { return _opened; }

void MagnumFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float) {
    /* We need just the configuration file and image file */
    if(data.size() != 2) {
        Error() << "Text::MagnumFont::openData(): wanted two files, got" << data.size();
        return;
    }

    /* Open the configuration file */
    std::istringstream in({reinterpret_cast<const char*>(data[0].second.begin()), data[0].second.size()});
    Utility::Configuration conf(in, Utility::Configuration::Flag::SkipComments);
    if(!conf.isValid() || conf.isEmpty()) {
        Error() << "Text::MagnumFont::openData(): cannot open file" << data[0].first << conf.isValid();
        return;
    }

    /* Check version */
    if(conf.value<UnsignedInt>("version") != 1) {
        Error() << "Text::MagnumFont::openData(): unsupported file version, expected 1 but got"
                << conf.value<UnsignedInt>("version");
        return;
    }

    /* Check that we have also the image file */
    if(conf.value("image") != data[1].first) {
        Error() << "Text::MagnumFont::openData(): expected file"
                << conf.value("image") << "but got" << data[1].first;
        return;
    }

    /* Open and load image file */
    Trade::TgaImporter importer;
    if(!importer.openData(data[1].second)) {
        Error() << "Text::MagnumFont::openData(): cannot open image file";
        return;
    }
    Trade::ImageData2D* image = importer.image2D(0);
    if(!image) {
        Error() << "Text::MagnumFont::openData(): cannot load image file";
        return;
    }

    openInternal(std::move(conf), std::move(*image));
    delete image;
}

void MagnumFont::doOpenFile(const std::string& filename, Float) {
    /* Open the configuration file */
    Utility::Configuration conf(filename, Utility::Configuration::Flag::ReadOnly|Utility::Configuration::Flag::SkipComments);
    if(!conf.isValid() || conf.isEmpty()) {
        Error() << "Text::MagnumFont::openFile(): cannot open file" << filename << conf.isValid();
        return;
    }

    /* Check version */
    if(conf.value<UnsignedInt>("version") != 1) {
        Error() << "Text::MagnumFont::openFile(): unsupported file version, expected 1 but got"
                << conf.value<UnsignedInt>("version");
        return;
    }

    /* Open and load image file */
    const std::string imageFilename = Utility::Directory::join(Utility::Directory::path(filename), conf.value("image"));
    Trade::TgaImporter importer;
    if(!importer.openFile(imageFilename)) {
        Error() << "Text::MagnumFont::openFile(): cannot open image file" << imageFilename;
        return;
    }
    Trade::ImageData2D* image = importer.image2D(0);
    if(!image) {
        Error() << "Text::MagnumFont::openFile(): cannot load image file";
        return;
    }

    openInternal(std::move(conf), std::move(*image));
    delete image;
}

void MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image) {
    /* Everything okay, save the data internally */
    _opened = new Data{std::move(conf), std::move(image), {}, {}};
    _size = _opened->conf.value<Float>("fontSize");

    /* Glyph advances */
    const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph");
    _opened->glyphAdvance.reserve(glyphs.size());
    for(const Utility::ConfigurationGroup* const g: glyphs)
        _opened->glyphAdvance.push_back(g->value<Vector2>("advance"));

    /* Fill character->glyph map */
    const std::vector<Utility::ConfigurationGroup*> chars = _opened->conf.groups("char");
    for(const Utility::ConfigurationGroup* const c: chars) {
        const UnsignedInt glyphId = c->value<UnsignedInt>("glyph");
        CORRADE_INTERNAL_ASSERT(glyphId < _opened->glyphAdvance.size());
        _opened->glyphId.emplace(c->value<char32_t>("unicode"), glyphId);
    }
}

void MagnumFont::doClose() {
    delete _opened;
    _opened = nullptr;
}

UnsignedInt MagnumFont::doGlyphId(const char32_t character) {
    auto it = _opened->glyphId.find(character);
    return it != _opened->glyphId.end() ? it->second : 0;
}

Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) {
    return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2();
}

GlyphCache* MagnumFont::doCreateGlyphCache() {
    /* Set cache image */
    auto cache = new Text::GlyphCache(
        _opened->conf.value<Vector2i>("originalImageSize"),
        _opened->image.size(),
        _opened->conf.value<Vector2i>("padding"));
    cache->setImage({}, _opened->image);

    /* Fill glyph map */
    const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph");
    for(std::size_t i = 0; i != glyphs.size(); ++i)
        cache->insert(i, glyphs[i]->value<Vector2i>("position"), glyphs[i]->value<Rectanglei>("rectangle"));

    return cache;
}

AbstractLayouter* MagnumFont::doLayout(const GlyphCache& cache, Float size, const std::string& text) {
    return new MagnumFontLayouter(_opened->glyphId, _opened->glyphAdvance, cache, this->size(), size, text);
}

namespace {

MagnumFontLayouter::MagnumFontLayouter(const std::unordered_map<char32_t, UnsignedInt>& glyphId, const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text): glyphAdvance(glyphAdvance), cache(cache), fontSize(fontSize), textSize(textSize) {
    /* Get glyph codes from characters */
    glyphs.reserve(text.size());
    for(std::size_t i = 0; i != text.size(); ) {
        UnsignedInt codepoint;
        std::tie(codepoint, i) = Utility::Unicode::nextChar(text, i);
        const auto it = glyphId.find(codepoint);
        glyphs.push_back(it == glyphId.end() ? 0 : it->second);
    }
    _glyphCount = glyphs.size();
}

std::tuple<Rectangle, Rectangle, Vector2> MagnumFontLayouter::renderGlyph(UnsignedInt i) {
    /* Position of the texture in the resulting glyph, texture coordinates */
    Vector2i position;
    Rectanglei rectangle;
    std::tie(position, rectangle) = cache[glyphs[i]];

    const Rectangle texturePosition = Rectangle::fromSize(Vector2(position)/fontSize,
                                                          Vector2(rectangle.size())/fontSize);
    const Rectangle textureCoordinates(Vector2(rectangle.bottomLeft())/cache.textureSize(),
                                       Vector2(rectangle.topRight())/cache.textureSize());

    /* Absolute quad position, composed from cursor position, glyph offset
       and texture position, denormalized to requested text size */
    Rectangle quadPosition = Rectangle::fromSize(
        Vector2(texturePosition.left(), texturePosition.bottom())*textSize,
        texturePosition.size()*textSize);

    /* Advance for given glyph, denormalized to requested text size */
    const Vector2 advance = glyphAdvance[glyphs[i]]*textSize/fontSize;

    return std::make_tuple(quadPosition, textureCoordinates, advance);
}

}

}}
<commit_msg>Adapted to Magnum changes.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "MagnumFont.h"

#include <sstream>
#include <Containers/Array.h>
#include <Utility/Directory.h>
#include <Utility/Unicode.h>
#include <Text/GlyphCache.h>
#include <Trade/ImageData.h>

#include "TgaImporter/TgaImporter.h"

namespace Magnum { namespace Text {

struct MagnumFont::Data {
    Utility::Configuration conf;
    Trade::ImageData2D image;
    std::unordered_map<char32_t, UnsignedInt> glyphId;
    std::vector<Vector2> glyphAdvance;
};

namespace {
    class MagnumFontLayouter: public AbstractLayouter {
        public:
            explicit MagnumFontLayouter(const std::unordered_map<char32_t, UnsignedInt>& glyphId, const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text);

            std::tuple<Rectangle, Rectangle, Vector2> renderGlyph(UnsignedInt i) override;

        private:
            const std::vector<Vector2>& glyphAdvance;
            const GlyphCache& cache;
            const Float fontSize, textSize;
            std::vector<UnsignedInt> glyphs;
    };
}

MagnumFont::MagnumFont(): _opened(nullptr) {}

MagnumFont::MagnumFont(PluginManager::AbstractManager* const manager, std::string plugin): AbstractFont(manager, std::move(plugin)), _opened(nullptr) {}

MagnumFont::~MagnumFont() { close(); }

auto MagnumFont::doFeatures() const -> Features { return Feature::OpenData|Feature::MultiFile|Feature::PreparedGlyphCache; }

bool MagnumFont::doIsOpened() const { return _opened; }

void MagnumFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float) {
    /* We need just the configuration file and image file */
    if(data.size() != 2) {
        Error() << "Text::MagnumFont::openData(): wanted two files, got" << data.size();
        return;
    }

    /* Open the configuration file */
    std::istringstream in({reinterpret_cast<const char*>(data[0].second.begin()), data[0].second.size()});
    Utility::Configuration conf(in, Utility::Configuration::Flag::SkipComments);
    if(!conf.isValid() || conf.isEmpty()) {
        Error() << "Text::MagnumFont::openData(): cannot open file" << data[0].first << conf.isValid();
        return;
    }

    /* Check version */
    if(conf.value<UnsignedInt>("version") != 1) {
        Error() << "Text::MagnumFont::openData(): unsupported file version, expected 1 but got"
                << conf.value<UnsignedInt>("version");
        return;
    }

    /* Check that we have also the image file */
    if(conf.value("image") != data[1].first) {
        Error() << "Text::MagnumFont::openData(): expected file"
                << conf.value("image") << "but got" << data[1].first;
        return;
    }

    /* Open and load image file */
    Trade::TgaImporter importer;
    if(!importer.openData(data[1].second)) {
        Error() << "Text::MagnumFont::openData(): cannot open image file";
        return;
    }
    Trade::ImageData2D* image = importer.image2D(0);
    if(!image) {
        Error() << "Text::MagnumFont::openData(): cannot load image file";
        return;
    }

    openInternal(std::move(conf), std::move(*image));
    delete image;
}

void MagnumFont::doOpenFile(const std::string& filename, Float) {
    /* Open the configuration file */
    Utility::Configuration conf(filename, Utility::Configuration::Flag::ReadOnly|Utility::Configuration::Flag::SkipComments);
    if(!conf.isValid() || conf.isEmpty()) {
        Error() << "Text::MagnumFont::openFile(): cannot open file" << filename << conf.isValid();
        return;
    }

    /* Check version */
    if(conf.value<UnsignedInt>("version") != 1) {
        Error() << "Text::MagnumFont::openFile(): unsupported file version, expected 1 but got"
                << conf.value<UnsignedInt>("version");
        return;
    }

    /* Open and load image file */
    const std::string imageFilename = Utility::Directory::join(Utility::Directory::path(filename), conf.value("image"));
    Trade::TgaImporter importer;
    if(!importer.openFile(imageFilename)) {
        Error() << "Text::MagnumFont::openFile(): cannot open image file" << imageFilename;
        return;
    }
    Trade::ImageData2D* image = importer.image2D(0);
    if(!image) {
        Error() << "Text::MagnumFont::openFile(): cannot load image file";
        return;
    }

    openInternal(std::move(conf), std::move(*image));
    delete image;
}

void MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image) {
    /* Everything okay, save the data internally */
    _opened = new Data{std::move(conf), std::move(image), {}, {}};
    _size = _opened->conf.value<Float>("fontSize");

    /* Glyph advances */
    const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph");
    _opened->glyphAdvance.reserve(glyphs.size());
    for(const Utility::ConfigurationGroup* const g: glyphs)
        _opened->glyphAdvance.push_back(g->value<Vector2>("advance"));

    /* Fill character->glyph map */
    const std::vector<Utility::ConfigurationGroup*> chars = _opened->conf.groups("char");
    for(const Utility::ConfigurationGroup* const c: chars) {
        const UnsignedInt glyphId = c->value<UnsignedInt>("glyph");
        CORRADE_INTERNAL_ASSERT(glyphId < _opened->glyphAdvance.size());
        _opened->glyphId.emplace(c->value<char32_t>("unicode"), glyphId);
    }
}

void MagnumFont::doClose() {
    delete _opened;
    _opened = nullptr;
}

UnsignedInt MagnumFont::doGlyphId(const char32_t character) {
    auto it = _opened->glyphId.find(character);
    return it != _opened->glyphId.end() ? it->second : 0;
}

Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) {
    return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2();
}

GlyphCache* MagnumFont::doCreateGlyphCache() {
    /* Set cache image */
    auto cache = new Text::GlyphCache(
        _opened->conf.value<Vector2i>("originalImageSize"),
        _opened->image.size(),
        _opened->conf.value<Vector2i>("padding"));
    cache->setImage({}, _opened->image);

    /* Fill glyph map */
    const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph");
    for(std::size_t i = 0; i != glyphs.size(); ++i)
        cache->insert(i, glyphs[i]->value<Vector2i>("position"), glyphs[i]->value<Rectanglei>("rectangle"));

    return cache;
}

AbstractLayouter* MagnumFont::doLayout(const GlyphCache& cache, Float size, const std::string& text) {
    return new MagnumFontLayouter(_opened->glyphId, _opened->glyphAdvance, cache, this->size(), size, text);
}

namespace {

MagnumFontLayouter::MagnumFontLayouter(const std::unordered_map<char32_t, UnsignedInt>& glyphId, const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, const std::string& text): glyphAdvance(glyphAdvance), cache(cache), fontSize(fontSize), textSize(textSize) {
    /* Get glyph codes from characters */
    glyphs.reserve(text.size());
    for(std::size_t i = 0; i != text.size(); ) {
        UnsignedInt codepoint;
        std::tie(codepoint, i) = Utility::Unicode::nextChar(text, i);
        const auto it = glyphId.find(codepoint);
        glyphs.push_back(it == glyphId.end() ? 0 : it->second);
    }
    _glyphCount = glyphs.size();
}

std::tuple<Rectangle, Rectangle, Vector2> MagnumFontLayouter::renderGlyph(UnsignedInt i) {
    /* Position of the texture in the resulting glyph, texture coordinates */
    Vector2i position;
    Rectanglei rectangle;
    std::tie(position, rectangle) = cache[glyphs[i]];

    const Rectangle texturePosition = Rectangle::fromSize(Vector2(position)/fontSize,
                                                          Vector2(rectangle.size())/fontSize);
    const Rectangle textureCoordinates(Vector2(rectangle.bottomLeft())/Vector2(cache.textureSize()),
                                       Vector2(rectangle.topRight())/Vector2(cache.textureSize()));

    /* Absolute quad position, composed from cursor position, glyph offset
       and texture position, denormalized to requested text size */
    Rectangle quadPosition = Rectangle::fromSize(
        Vector2(texturePosition.left(), texturePosition.bottom())*textSize,
        texturePosition.size()*textSize);

    /* Advance for given glyph, denormalized to requested text size */
    const Vector2 advance = glyphAdvance[glyphs[i]]*textSize/fontSize;

    return std::make_tuple(quadPosition, textureCoordinates, advance);
}

}

}}
<|endoftext|>