<commit_before>#ifndef SDL_TIMER_HH
#define SDL_TIMER_HH

#include "Functor.hh"
#include <utility>
#include <map>

#include <iostream>

typedef struct _SDL_TimerID *SDL_TimerID;

namespace RAGE
{
    namespace SDL
    {
	//Simple overloaded implementations
	    void Delay(long millisec);
	    long GetTicks();

	    //these should be used through the timer class, not directly
	    //NB : AddGlobalTimer should not be called from an other thread thant the main one. Timers will behave strangely in multithreaded applications...
	    SDL_TimerID AddGlobalTimer(unsigned int interval, unsigned int callback (unsigned int, void*) , void *param);
	    bool RemoveGlobalTimer(SDL_TimerID t);

    		template <class TClass>
		class Timer
		{

			//Functor for Timer Callback
	    		//the only constraint about the callback function is that it should return int (next interval to apply)
	    		//and the arguments should be void* to be able to pass anything...

			class Callback : public TSpecificFunctor2<TClass,unsigned int,unsigned int>
			{
				public:
					Callback(TClass* ptobj, unsigned int (TClass::*ptfunc) (unsigned int interval,void * args))
					: TSpecificFunctor2<TClass,unsigned int,unsigned int>(ptobj,ptfunc)
					{
					}

			};

			//structure for arguments
	    		typedef struct { int lookupindex; void* args;} cbargs;

		    	//index of this functor instance in the static lookuptable
			unsigned int _index;

			cbargs* _cbargs;

			//static table lookup that stores pointer to callback
			static std::map<unsigned int, Callback* > _cbtable;
			static std::map<unsigned int, SDL_TimerID* > _timertable;

			public:

		    	//static callback function who calls the right functor from the table
			static unsigned int callback(unsigned int, void* args);

			SDL_TimerID _timerid; //set after timer is started
			//_timerid != 0  means the timer has been launched.

			Timer();
			~Timer();

			void setCallback(TClass* instance, unsigned int (TClass::*func) (unsigned int, void*) , void* args);

			bool launch(unsigned int interval);
			bool abort();
		};

		template <class TClass>
				std::map<unsigned int,typename Timer<TClass>::Callback* > Timer<TClass>::_cbtable;
		template <class TClass>
				std::map<unsigned int,SDL_TimerID* > Timer<TClass>::_timertable;

		template <class TClass>
				unsigned int Timer<TClass>::callback(unsigned int interval, void* args)
		{
			cbargs* callargs= static_cast<cbargs*>(args);
			typename std::map<unsigned int,Callback* >::iterator itcb=_cbtable.find(callargs->lookupindex);
			if ( itcb == _cbtable.end() ) return 0; //stop callback : function to call doesnt exists

			//Do the actual client callback
			int res = itcb->second->call(interval,callargs->args);

			if ( res == 0 ) // to set timer to 0 and erase it from the list, to flag termination of timer, so it can be launched again.
			{
				std::map<unsigned int,SDL_TimerID* >::iterator ittimer=_timertable.find(callargs->lookupindex);
				if ( ittimer != _timertable.end() )
				{
					*(ittimer->second) = 0;
					_timertable.erase(ittimer);
				}
				//else doesnt exists anymore ? should not happen, but it s fine...
			}
			return res;
		}

		template<class TClass>
				void Timer<TClass>::setCallback(TClass* instance,unsigned int (TClass::*func) (unsigned int, void*), void* args)
		{
			typename std::map<unsigned int, Callback*>::iterator it=_cbtable.find(_index);
			if ( it != _cbtable.end() ) delete it->second;
			it->second = new Callback(instance,func);

			//reinit _cbargs when needed
			if (_cbargs != NULL)
			{
				delete _cbargs, _cbargs = NULL;
			}
			_cbargs = new cbargs();
			_cbargs->lookupindex = _index;
			_cbargs->args = args;
		}

		template<class TClass>
		Timer<TClass>::Timer() : _cbargs(NULL), _timerid()
		{

			//setting the index for the current instance
			static unsigned int index=0;
			_index = index;
			index++;
			//preparing callback
			//_cbtable.push_back(NULL);
			//useful ? really ??
		}

		template<class TClass>
		Timer<TClass>::~Timer()
		{
			abort();// destructor abort a running timer if needed
			if (_cbargs != NULL)
				delete _cbargs, _cbargs = NULL;
			typename std::map<unsigned int, Callback*>::iterator it=_cbtable.find(_index);
			if (it != _cbtable.end())
			{
				delete it->second;
				_cbtable.erase(it);
			}
		}

		//returns true if the timer has been successfully launched. A timer can be launched only once. If this timer has already been launched this will return false.
		//returns false if the timer could not be launched.
		//NB : a timer cannot be launched from another timer's callback. Timer may behave strangely in multithreaded applications
		template<class TClass>
		bool Timer<TClass>::launch(unsigned int interval)
		{
			if ( interval > 0 && _timerid == 0 && _timertable.count(_index) == 0)
			{
				_timerid = AddGlobalTimer(interval,callback,_cbargs);
				std::pair<std::map<unsigned int,SDL_TimerID* >::iterator, bool > result = _timertable.insert(std::make_pair(_index,&_timerid));
				return result.second;
			}
			return false;
		}

		//return true if abort successful. return false if abortion failed ( the timer may already have stopped for example )
		template<class TClass>
		bool Timer<TClass>::abort()
		{
			if (_timerid != 0 && _timertable.count(_index) != 0 && RemoveGlobalTimer(_timerid) )
			{
				_timerid = 0;
				_timertable.erase(_index);
			}
			return (_timerid == 0 );
		}

	}
}

#endif
<commit_msg>fix in timer when setting callback<commit_after>#ifndef SDL_TIMER_HH
#define SDL_TIMER_HH

#include "Functor.hh"
#include <utility>
#include <map>

#include <iostream>

typedef struct _SDL_TimerID *SDL_TimerID;

namespace RAGE
{
    namespace SDL
    {
	//Simple overloaded implementations
	    void Delay(long millisec);
	    long GetTicks();

	    //these should be used through the timer class, not directly
	    //NB : AddGlobalTimer should not be called from an other thread thant the main one. Timers will behave strangely in multithreaded applications...
	    SDL_TimerID AddGlobalTimer(unsigned int interval, unsigned int callback (unsigned int, void*) , void *param);
	    bool RemoveGlobalTimer(SDL_TimerID t);

    		template <class TClass>
		class Timer
		{

			//Functor for Timer Callback
	    		//the only constraint about the callback function is that it should return int (next interval to apply)
	    		//and the arguments should be void* to be able to pass anything...

			class Callback : public TSpecificFunctor2<TClass,unsigned int,unsigned int>
			{
				public:
					Callback(TClass* ptobj, unsigned int (TClass::*ptfunc) (unsigned int interval,void * args))
					: TSpecificFunctor2<TClass,unsigned int,unsigned int>(ptobj,ptfunc)
					{
					}

			};

			//structure for arguments
	    		typedef struct { int lookupindex; void* args;} cbargs;

		    	//index of this functor instance in the static lookuptable
			unsigned int _index;

			cbargs* _cbargs;

			//static table lookup that stores pointer to callback
			static std::map<unsigned int, Callback* > _cbtable;
			static std::map<unsigned int, SDL_TimerID* > _timertable;

			public:

		    	//static callback function who calls the right functor from the table
			static unsigned int callback(unsigned int, void* args);

			SDL_TimerID _timerid; //set after timer is started
			//_timerid != 0  means the timer has been launched.

			Timer();
			~Timer();

			void setCallback(TClass* instance, unsigned int (TClass::*func) (unsigned int, void*) , void* args);

			bool launch(unsigned int interval);
			bool abort();
		};

		template <class TClass>
				std::map<unsigned int,typename Timer<TClass>::Callback* > Timer<TClass>::_cbtable;
		template <class TClass>
				std::map<unsigned int,SDL_TimerID* > Timer<TClass>::_timertable;

		template <class TClass>
				unsigned int Timer<TClass>::callback(unsigned int interval, void* args)
		{
			cbargs* callargs= static_cast<cbargs*>(args);
			typename std::map<unsigned int,Callback* >::iterator itcb=_cbtable.find(callargs->lookupindex);
			if ( itcb == _cbtable.end() ) return 0; //stop callback : function to call doesnt exists

			//Do the actual client callback
			int res = itcb->second->call(interval,callargs->args);

			if ( res == 0 ) // to set timer to 0 and erase it from the list, to flag termination of timer, so it can be launched again.
			{
				std::map<unsigned int,SDL_TimerID* >::iterator ittimer=_timertable.find(callargs->lookupindex);
				if ( ittimer != _timertable.end() )
				{
					*(ittimer->second) = 0;
					_timertable.erase(ittimer);
				}
				//else doesnt exists anymore ? should not happen, but it s fine...
			}
			return res;
		}

		template<class TClass>
				void Timer<TClass>::setCallback(TClass* instance,unsigned int (TClass::*func) (unsigned int, void*), void* args)
		{
			typename std::map<unsigned int, Callback*>::iterator it=_cbtable.find(_index);
			if ( it != _cbtable.end() )
			{
				delete it->second;
			}
			_cbtable[_index] = new Callback(instance,func);

			//reinit _cbargs when needed
			if (_cbargs != NULL)
			{
				delete _cbargs, _cbargs = NULL;
			}
			_cbargs = new cbargs();
			_cbargs->lookupindex = _index;
			_cbargs->args = args;
		}

		template<class TClass>
		Timer<TClass>::Timer() : _cbargs(NULL), _timerid()
		{

			//setting the index for the current instance
			static unsigned int index=0;
			_index = index;
			index++;
			//preparing callback
			//_cbtable.push_back(NULL);
			//useful ? really ??
		}

		template<class TClass>
		Timer<TClass>::~Timer()
		{
			abort();// destructor abort a running timer if needed
			if (_cbargs != NULL)
				delete _cbargs, _cbargs = NULL;
			typename std::map<unsigned int, Callback*>::iterator it=_cbtable.find(_index);
			if (it != _cbtable.end())
			{
				delete it->second;
				_cbtable.erase(it);
			}
		}

		//returns true if the timer has been successfully launched. A timer can be launched only once. If this timer has already been launched this will return false.
		//returns false if the timer could not be launched.
		//NB : a timer cannot be launched from another timer's callback. Timer may behave strangely in multithreaded applications
		template<class TClass>
		bool Timer<TClass>::launch(unsigned int interval)
		{
			if ( interval > 0 && _timerid == 0 && _timertable.count(_index) == 0)
			{
				_timerid = AddGlobalTimer(interval,callback,_cbargs);
				std::pair<std::map<unsigned int,SDL_TimerID* >::iterator, bool > result = _timertable.insert(std::make_pair(_index,&_timerid));
				return result.second;
			}
			return false;
		}

		//return true if abort successful. return false if abortion failed ( the timer may already have stopped for example )
		template<class TClass>
		bool Timer<TClass>::abort()
		{
			if (_timerid != 0 && _timertable.count(_index) != 0 && RemoveGlobalTimer(_timerid) )
			{
				_timerid = 0;
				_timertable.erase(_index);
			}
			return (_timerid == 0 );
		}

	}
}

#endif
<|endoftext|>


<commit_before>#ifndef Pipeline_HPP
#define Pipeline_HPP

#include <vector>
#include "PerPixelMesh.hpp"
#include "Renderable.hpp"
#include "Filters.hpp"
#include "BeatDetect.hpp"
#include "PipelineContext.hpp"
#include "Shader.hpp"

//This class is the input to projectM's renderer
//
//Most implemenatations should implement PerPixel in order to get multi-threaded
//dynamic PerPixel equations.  If you MUST (ie Milkdrop compatability), you can use the
//setStaticPerPixel function and fill in x_mesh and y_mesh yourself.
class Pipeline
{
public:

	 //static per pixel stuff
	 bool staticPerPixel;
	 int gx;
	 int gy;

	 float** x_mesh;
	 float** y_mesh;
	 //end static per pixel

	 bool  textureWrap;
	 float screenDecay;

	 //variables passed to pixel shaders
	 float q[NUM_Q_VARIABLES];

	 //blur settings n=bias x=scale
	 float blur1n;
	 float blur2n;
	 float blur3n;
	 float blur1x;
	 float blur2x;
	 float blur3x;
	 float blur1ed;

	 Shader warpShader;
	 Shader compositeShader;

	 std::vector<RenderItem*> drawables;
	 std::vector<RenderItem*> compositeDrawables;

	 Pipeline();
	 void setStaticPerPixel(int gx, int gy);
	 virtual ~Pipeline();
	 virtual Point PerPixel(Point p, const PerPixelContext context);
};

#endif
<commit_msg>forgot to include common header<commit_after>#ifndef Pipeline_HPP
#define Pipeline_HPP

#include <vector>
#include "PerPixelMesh.hpp"
#include "Renderable.hpp"
#include "Filters.hpp"
#include "BeatDetect.hpp"
#include "PipelineContext.hpp"
#include "Shader.hpp"
#include "Common.hpp"
//This class is the input to projectM's renderer
//
//Most implemenatations should implement PerPixel in order to get multi-threaded
//dynamic PerPixel equations.  If you MUST (ie Milkdrop compatability), you can use the
//setStaticPerPixel function and fill in x_mesh and y_mesh yourself.
class Pipeline
{
public:

	 //static per pixel stuff
	 bool staticPerPixel;
	 int gx;
	 int gy;

	 float** x_mesh;
	 float** y_mesh;
	 //end static per pixel

	 bool  textureWrap;
	 float screenDecay;

	 //variables passed to pixel shaders
	 float q[NUM_Q_VARIABLES];

	 //blur settings n=bias x=scale
	 float blur1n;
	 float blur2n;
	 float blur3n;
	 float blur1x;
	 float blur2x;
	 float blur3x;
	 float blur1ed;

	 Shader warpShader;
	 Shader compositeShader;

	 std::vector<RenderItem*> drawables;
	 std::vector<RenderItem*> compositeDrawables;

	 Pipeline();
	 void setStaticPerPixel(int gx, int gy);
	 virtual ~Pipeline();
	 virtual Point PerPixel(Point p, const PerPixelContext context);
};

#endif
<|endoftext|>


<commit_before>/* Rapicorn-Python Bindings
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "rope.hh" // must be included first to configure std headers
#include <deque>

// --- conventional Python module initializers ---
#define MODULE_NAME             pyRapicorn
#define MODULE_NAME_STRING      STRINGIFY (MODULE_NAME)
#define MODULE_INIT_FUNCTION    RAPICORN_CPP_PASTE2 (init, MODULE_NAME)

static int cpu_affinity (int cpu); // FIXME

// --- rope2cxx stubs (generated) ---
#include "rope2cxx.cc"

// --- Anonymous namespacing
namespace {

// --- cpy2rope stubs (generated) ---
#define HAVE_PLIC_CALL_REMOTE   1
static Rapicorn::Plic::FieldBuffer* plic_call_remote    (Rapicorn::Plic::FieldBuffer*);
static PyObject*                    plic_cpy_trampoline (PyObject *pyself, PyObject *pyargs); // generated
#include "cpy2rope.cc"
typedef Rapicorn::Plic::FieldBuffer FieldBuffer;
typedef Rapicorn::Plic::FieldBuffer8 FieldBuffer8;

// --- globals ---
static PyObject *rapicorn_exception = NULL;

// --- rapicorn thread ---
static int  max_call_stack_size = 0;
static void print_max_call_stack_size()
{
  printerr ("DEBUG:atexit: max_call_stack_size: %u\n", max_call_stack_size);
}

class UIThread : public Thread {
  EventLoop * volatile m_loop;
  virtual void
  run ()
  {
    cpu_affinity (m_cpu);
    // rapicorn_init_core() already called
    Rapicorn::StringList slist;
    slist.strings = this->cmdline_args;
    App.init_with_x11 (this->application_name, slist);
    m_loop = ref_sink (EventLoop::create());
    EventLoop::Source *esource = new ProcSource (*this);
    (*m_loop).add_source (esource, MAXINT);
    esource->exitable (false);
    {
      FieldBuffer *fb = FieldBuffer::_new (2);
      fb->add_int64 (0x02000000); // proc_id
      Deletable *dapp = &App;
      fb->add_string (dapp->object_url());
      push_return (fb);
    }
    App.execute_loops();
  }
  bool
  dispatch ()
  {
    const FieldBuffer *call = pop_proc();
    if (call)
      {
        if (0)
          {
#if 0
            std::string string;
            if (!google::protobuf::TextFormat::PrintToString (*proc, &string))
              string = "{*protobuf::TextFormat ERROR*}";
            printerr ("Rapicorn::UIThread::call:\n%s\n", string.c_str());
#endif
          }
        FieldBuffer *fr;
        FieldBuffer8 fdummy (2);
        if (call->first_id() >= 0x02000000)
          fr = FieldBuffer::_new (2);
        else
          fr = &fdummy;
        bool success = plic_call_wrapper_switch (*call, *fr);
        if (!success)
          {
            printerr ("UIThread::call error (see logs)\n"); // FIXME
            if (call->first_id() >= 0x02000000)
              {
                FieldBuffer *fb = FieldBuffer::_new (2);
                fb->add_int64 (0x02000000); // proc_id
                fb->add_string ("*ERROR*"); // FIXME
                push_return (fb);
              }
            if (call->first_id() >= 0x02000000)
              delete fr;
          }
        else if (call->first_id() >= 0x02000000)
            push_return (fr);
        delete call;
      }
    return true;
  }
protected:
  class ProcSource : public virtual EventLoop::Source {
    UIThread &m_thread;
    RAPICORN_PRIVATE_CLASS_COPY (ProcSource);
  protected:
    /*Des*/     ~ProcSource() {}
    virtual bool prepare  (uint64 current_time_usecs,
                           int64 *timeout_usecs_p)      { return m_thread.check_dispatch(); }
    virtual bool check    (uint64 current_time_usecs)   { return m_thread.check_dispatch(); }
    virtual bool dispatch ()                            { return m_thread.dispatch(); }
  public:
    explicit     ProcSource (UIThread &thread) : m_thread (thread) {}
  };
public:
  int            m_cpu;
  String         application_name;
  vector<String> cmdline_args;
  UIThread (const String &name) :
    Thread (name),
    m_loop (NULL),
    m_cpu (-1),
    rrx (0),
    rpx (0)
  {
    rrv.reserve (1);
    atexit (print_max_call_stack_size);
  }
  ~UIThread()
  {
    unref (m_loop);
    m_loop = NULL;
  }
private:
  Mutex                         rrm;
  Cond                          rrc;
  vector<FieldBuffer*>          rrv, rro;
  size_t                        rrx;
public:
  void
  push_return (FieldBuffer *rret)
  {
    rrm.lock();
    rrv.push_back (rret);
    rrc.signal();
    rrm.unlock();
    Thread::Self::yield(); // allow fast return value handling on single core
  }
  FieldBuffer*
  fetch_return (void)
  {
    if (rrx >= rro.size())
      {
        if (rrx)
          rro.resize (0);
        rrm.lock();
        while (rrv.size() == 0)
          rrc.wait (rrm);
        rrv.swap (rro); // fetch result
        rrm.unlock();
        rrx = 0;
      }
    // rrx < rro.size()
    return rro[rrx++];
  }
private:
  Mutex                rps;
  vector<FieldBuffer*> rpv, rpo;
  size_t               rpx;
public:
  void
  push_proc (FieldBuffer *proc)
  {
    int64 call_id = proc->first_id();
    size_t sz;
    rps.lock();
    rpv.push_back (proc);
    sz = rpv.size();
    rps.unlock();
    m_loop->wakeup();
    if (call_id >= 0x02000000 || // minimize turn-around times for two-way calls
        sz >= 1009)              // allow batch processing of one-way call queue
      Thread::Self::yield();     // useless if threads have different CPU affinity
  }
  FieldBuffer*
  pop_proc (bool advance = true)
  {
    if (rpx >= rpo.size())
      {
        if (rpx)
          rpo.resize (0);
        rps.lock();
        rpv.swap (rpo);
        rps.unlock();
        rpx = 0;
        max_call_stack_size = MAX (max_call_stack_size, rpo.size());
      }
    if (rpx < rpo.size())
      {
        size_t indx = rpx;
        if (advance)
          rpx++;
        return rpo[indx];
      }
    return NULL;
  }
  bool
  check_dispatch ()
  {
    return pop_proc (false) != NULL;
  }
private:
  static UIThread *ui_thread;
public:
  static String
  ui_thread_create (const String              &application_name,
                    const std::vector<String> &cmdline_args)
  {
    return_val_if_fail (ui_thread == NULL, "");
    /* initialize core */
    RapicornInitValue ivalues[] = {
      { NULL }
    };
    int argc = 0;
    char **argv = NULL;
    rapicorn_init_core (&argc, &argv, NULL, ivalues);
    /* start parallel thread */
    ui_thread = new UIThread ("RapicornUI");
    ref_sink (ui_thread);
    ui_thread->application_name = application_name;
    ui_thread->cmdline_args = cmdline_args;
    ui_thread->m_cpu = cpu_affinity (1);
    ui_thread->start();
    FieldBuffer *rpret = ui_thread->fetch_return();
    String appurl;
    if (rpret && rpret->first_id() == 0x02000000)
      {
        Rapicorn::Plic::FieldBufferReader rpr (*rpret);
        rpr.skip(); // proc_id
        if (rpr.remaining() > 0 && rpr.get_type() == Rapicorn::Plic::STRING)
          appurl = rpr.pop_string();
      }
    delete rpret;
    return appurl;
  }
  static FieldBuffer*
  ui_thread_call_remote (FieldBuffer *call)
  {
    if (!ui_thread)
      return false;
    int64 call_id = call->first_id();
    ui_thread->push_proc (call); // deletes call
    if (0) // debug
      printf ("Remote Procedure Call, id=0x%08llx (%s-way)\n",
              call_id, call_id >= 0x02000000 ? "two" : "one");
    if (call_id >= 0x02000000)
      {
        FieldBuffer *rpret = ui_thread->fetch_return();
        if (0)
          printerr ("Remote Procedure Return: 0x%08llx\n", rpret->first_id());
        return rpret;
      }
    return NULL;
  }
};
UIThread *UIThread::ui_thread = NULL;

static Rapicorn::Plic::FieldBuffer*
plic_call_remote (Rapicorn::Plic::FieldBuffer *call)
{
  return UIThread::ui_thread_call_remote (call);
}

// --- PyC functions ---
static PyObject*
rope_printout (PyObject *self,
                 PyObject *args)
{
  const char *ns = NULL;
  unsigned int nl = 0;
  if (!PyArg_ParseTuple (args, "s#", &ns, &nl))
    return NULL;
  String str = String (ns, nl);
  printout ("%s", str.c_str());
  return None_INCREF();
}

static PyObject*
rope_init_dispatcher (PyObject *self,
                        PyObject *args)
{
  const char *ns = NULL;
  unsigned int nl = 0;
  PyObject *list;
  if (!PyArg_ParseTuple (args, "s#O", &ns, &nl, &list))
    return NULL;
  const ssize_t len = PyList_Size (list);
  if (len < 0)
    return NULL;
  std::vector<String> strv;
  for (ssize_t k = 0; k < len; k++)
    {
      PyObject *item = PyList_GET_ITEM (list, k);
      char *as = NULL;
      Py_ssize_t al = 0;
      if (PyString_AsStringAndSize (item, &as, &al) < 0)
        return NULL;
      strv.push_back (String (as, al));
    }
  if (PyErr_Occurred())
    return NULL;
  String appurl = UIThread::ui_thread_create (String (ns, nl), strv);
  if (appurl.size() == 0)
    ; // FIXME: throw exception
  return PyString_FromStringAndSize (appurl.data(), appurl.size());
}

} // Anon

// --- Python module definitions (global namespace) ---
static PyMethodDef rope_vtable[] = {
  { "_init_dispatcher",         rope_init_dispatcher,         METH_VARARGS,
    "Rapicorn::_init_dispatcher() - initial setup." },
  { "__rope_pytrampoline__",    plic_cpy_trampoline,          METH_VARARGS,
    "Rapicorn function invokation trampoline." },
  { "printout",                 rope_printout,                METH_VARARGS,
    "Rapicorn::printout() - print to stdout." },
  { NULL, } // sentinel
};
static const char rapicorn_doc[] = "Rapicorn Python Language Binding Module.";

PyMODINIT_FUNC
MODULE_INIT_FUNCTION (void) // conventional dlmodule initializer
{
  // register module
  PyObject *m = Py_InitModule3 (MODULE_NAME_STRING, rope_vtable, (char*) rapicorn_doc);
  if (!m)
    return;

  // register Rypicorn exception
  if (!rapicorn_exception)
    rapicorn_exception = PyErr_NewException ((char*) MODULE_NAME_STRING ".exception", NULL, NULL);
  if (!rapicorn_exception)
    return;
  Py_INCREF (rapicorn_exception);
  PyModule_AddObject (m, "exception", rapicorn_exception);

  // retrieve argv[0]
  char *argv0;
  {
    PyObject *sysmod = PyImport_ImportModule ("sys");
    PyObject *astr   = sysmod ? PyObject_GetAttrString (sysmod, "argv") : NULL;
    PyObject *arg0   = astr ? PySequence_GetItem (astr, 0) : NULL;
    argv0            = arg0 ? strdup (PyString_AsString (arg0)) : NULL;
    Py_XDECREF (arg0);
    Py_XDECREF (astr);
    Py_XDECREF (sysmod);
    if (!argv0)
      return; // exception set
  }

  // initialize Rapicorn with dummy argv, hardcode X11 temporarily
  {
    // int dummyargc = 1;
    char *dummyargs[] = { NULL, NULL };
    dummyargs[0] = argv0[0] ? argv0 : (char*) "Python>>>";
    // char **dummyargv = dummyargs;
    // FIXME: // App.init_with_x11 (&dummyargc, &dummyargv, dummyargs[0]);
  }
  free (argv0);
}
// using global namespace for Python module initialization

// FIXME: move...
//#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

static int
cpu_affinity (int cpu)
{
  pthread_t thread = pthread_self();
  cpu_set_t cpuset;

  if (cpu >= 0 && cpu < CPU_SETSIZE)
    {
      CPU_ZERO (&cpuset);
      CPU_SET (cpu, &cpuset);
      if (pthread_setaffinity_np (thread, sizeof (cpu_set_t), &cpuset) != 0)
        perror ("pthread_setaffinity_np");
    }

  if (pthread_getaffinity_np (thread, sizeof (cpu_set_t), &cpuset) != 0)
    perror ("pthread_getaffinity_np");
  printf ("Affinity(%ld/%d cpus): thread=%p", sysconf (_SC_NPROCESSORS_ONLN), CPU_SETSIZE, (void*)thread);
  for (int j = 0; j < CPU_SETSIZE; j++)
    if (CPU_ISSET (j, &cpuset))
      {
        printf ("    CPU %d\n", j);
        return j;
      }
  return -1;
}
<commit_msg>ROPE: fixed signedness warning<commit_after>/* Rapicorn-Python Bindings
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "rope.hh" // must be included first to configure std headers
#include <deque>

// --- conventional Python module initializers ---
#define MODULE_NAME             pyRapicorn
#define MODULE_NAME_STRING      STRINGIFY (MODULE_NAME)
#define MODULE_INIT_FUNCTION    RAPICORN_CPP_PASTE2 (init, MODULE_NAME)

static int cpu_affinity (int cpu); // FIXME

// --- rope2cxx stubs (generated) ---
#include "rope2cxx.cc"

// --- Anonymous namespacing
namespace {

// --- cpy2rope stubs (generated) ---
#define HAVE_PLIC_CALL_REMOTE   1
static Rapicorn::Plic::FieldBuffer* plic_call_remote    (Rapicorn::Plic::FieldBuffer*);
static PyObject*                    plic_cpy_trampoline (PyObject *pyself, PyObject *pyargs); // generated
#include "cpy2rope.cc"
typedef Rapicorn::Plic::FieldBuffer FieldBuffer;
typedef Rapicorn::Plic::FieldBuffer8 FieldBuffer8;

// --- globals ---
static PyObject *rapicorn_exception = NULL;

// --- rapicorn thread ---
static uint  max_call_stack_size = 0;
static void print_max_call_stack_size()
{
  printerr ("DEBUG:atexit: max_call_stack_size: %u\n", max_call_stack_size);
}

class UIThread : public Thread {
  EventLoop * volatile m_loop;
  virtual void
  run ()
  {
    cpu_affinity (m_cpu);
    // rapicorn_init_core() already called
    Rapicorn::StringList slist;
    slist.strings = this->cmdline_args;
    App.init_with_x11 (this->application_name, slist);
    m_loop = ref_sink (EventLoop::create());
    EventLoop::Source *esource = new ProcSource (*this);
    (*m_loop).add_source (esource, MAXINT);
    esource->exitable (false);
    {
      FieldBuffer *fb = FieldBuffer::_new (2);
      fb->add_int64 (0x02000000); // proc_id
      Deletable *dapp = &App;
      fb->add_string (dapp->object_url());
      push_return (fb);
    }
    App.execute_loops();
  }
  bool
  dispatch ()
  {
    const FieldBuffer *call = pop_proc();
    if (call)
      {
        if (0)
          {
#if 0
            std::string string;
            if (!google::protobuf::TextFormat::PrintToString (*proc, &string))
              string = "{*protobuf::TextFormat ERROR*}";
            printerr ("Rapicorn::UIThread::call:\n%s\n", string.c_str());
#endif
          }
        FieldBuffer *fr;
        FieldBuffer8 fdummy (2);
        if (call->first_id() >= 0x02000000)
          fr = FieldBuffer::_new (2);
        else
          fr = &fdummy;
        bool success = plic_call_wrapper_switch (*call, *fr);
        if (!success)
          {
            printerr ("UIThread::call error (see logs)\n"); // FIXME
            if (call->first_id() >= 0x02000000)
              {
                FieldBuffer *fb = FieldBuffer::_new (2);
                fb->add_int64 (0x02000000); // proc_id
                fb->add_string ("*ERROR*"); // FIXME
                push_return (fb);
              }
            if (call->first_id() >= 0x02000000)
              delete fr;
          }
        else if (call->first_id() >= 0x02000000)
            push_return (fr);
        delete call;
      }
    return true;
  }
protected:
  class ProcSource : public virtual EventLoop::Source {
    UIThread &m_thread;
    RAPICORN_PRIVATE_CLASS_COPY (ProcSource);
  protected:
    /*Des*/     ~ProcSource() {}
    virtual bool prepare  (uint64 current_time_usecs,
                           int64 *timeout_usecs_p)      { return m_thread.check_dispatch(); }
    virtual bool check    (uint64 current_time_usecs)   { return m_thread.check_dispatch(); }
    virtual bool dispatch ()                            { return m_thread.dispatch(); }
  public:
    explicit     ProcSource (UIThread &thread) : m_thread (thread) {}
  };
public:
  int            m_cpu;
  String         application_name;
  vector<String> cmdline_args;
  UIThread (const String &name) :
    Thread (name),
    m_loop (NULL),
    m_cpu (-1),
    rrx (0),
    rpx (0)
  {
    rrv.reserve (1);
    atexit (print_max_call_stack_size);
  }
  ~UIThread()
  {
    unref (m_loop);
    m_loop = NULL;
  }
private:
  Mutex                         rrm;
  Cond                          rrc;
  vector<FieldBuffer*>          rrv, rro;
  size_t                        rrx;
public:
  void
  push_return (FieldBuffer *rret)
  {
    rrm.lock();
    rrv.push_back (rret);
    rrc.signal();
    rrm.unlock();
    Thread::Self::yield(); // allow fast return value handling on single core
  }
  FieldBuffer*
  fetch_return (void)
  {
    if (rrx >= rro.size())
      {
        if (rrx)
          rro.resize (0);
        rrm.lock();
        while (rrv.size() == 0)
          rrc.wait (rrm);
        rrv.swap (rro); // fetch result
        rrm.unlock();
        rrx = 0;
      }
    // rrx < rro.size()
    return rro[rrx++];
  }
private:
  Mutex                rps;
  vector<FieldBuffer*> rpv, rpo;
  size_t               rpx;
public:
  void
  push_proc (FieldBuffer *proc)
  {
    int64 call_id = proc->first_id();
    size_t sz;
    rps.lock();
    rpv.push_back (proc);
    sz = rpv.size();
    rps.unlock();
    m_loop->wakeup();
    if (call_id >= 0x02000000 || // minimize turn-around times for two-way calls
        sz >= 1009)              // allow batch processing of one-way call queue
      Thread::Self::yield();     // useless if threads have different CPU affinity
  }
  FieldBuffer*
  pop_proc (bool advance = true)
  {
    if (rpx >= rpo.size())
      {
        if (rpx)
          rpo.resize (0);
        rps.lock();
        rpv.swap (rpo);
        rps.unlock();
        rpx = 0;
        max_call_stack_size = MAX (max_call_stack_size, rpo.size());
      }
    if (rpx < rpo.size())
      {
        size_t indx = rpx;
        if (advance)
          rpx++;
        return rpo[indx];
      }
    return NULL;
  }
  bool
  check_dispatch ()
  {
    return pop_proc (false) != NULL;
  }
private:
  static UIThread *ui_thread;
public:
  static String
  ui_thread_create (const String              &application_name,
                    const std::vector<String> &cmdline_args)
  {
    return_val_if_fail (ui_thread == NULL, "");
    /* initialize core */
    RapicornInitValue ivalues[] = {
      { NULL }
    };
    int argc = 0;
    char **argv = NULL;
    rapicorn_init_core (&argc, &argv, NULL, ivalues);
    /* start parallel thread */
    ui_thread = new UIThread ("RapicornUI");
    ref_sink (ui_thread);
    ui_thread->application_name = application_name;
    ui_thread->cmdline_args = cmdline_args;
    ui_thread->m_cpu = cpu_affinity (1);
    ui_thread->start();
    FieldBuffer *rpret = ui_thread->fetch_return();
    String appurl;
    if (rpret && rpret->first_id() == 0x02000000)
      {
        Rapicorn::Plic::FieldBufferReader rpr (*rpret);
        rpr.skip(); // proc_id
        if (rpr.remaining() > 0 && rpr.get_type() == Rapicorn::Plic::STRING)
          appurl = rpr.pop_string();
      }
    delete rpret;
    return appurl;
  }
  static FieldBuffer*
  ui_thread_call_remote (FieldBuffer *call)
  {
    if (!ui_thread)
      return false;
    int64 call_id = call->first_id();
    ui_thread->push_proc (call); // deletes call
    if (0) // debug
      printf ("Remote Procedure Call, id=0x%08llx (%s-way)\n",
              call_id, call_id >= 0x02000000 ? "two" : "one");
    if (call_id >= 0x02000000)
      {
        FieldBuffer *rpret = ui_thread->fetch_return();
        if (0)
          printerr ("Remote Procedure Return: 0x%08llx\n", rpret->first_id());
        return rpret;
      }
    return NULL;
  }
};
UIThread *UIThread::ui_thread = NULL;

static Rapicorn::Plic::FieldBuffer*
plic_call_remote (Rapicorn::Plic::FieldBuffer *call)
{
  return UIThread::ui_thread_call_remote (call);
}

// --- PyC functions ---
static PyObject*
rope_printout (PyObject *self,
                 PyObject *args)
{
  const char *ns = NULL;
  unsigned int nl = 0;
  if (!PyArg_ParseTuple (args, "s#", &ns, &nl))
    return NULL;
  String str = String (ns, nl);
  printout ("%s", str.c_str());
  return None_INCREF();
}

static PyObject*
rope_init_dispatcher (PyObject *self,
                        PyObject *args)
{
  const char *ns = NULL;
  unsigned int nl = 0;
  PyObject *list;
  if (!PyArg_ParseTuple (args, "s#O", &ns, &nl, &list))
    return NULL;
  const ssize_t len = PyList_Size (list);
  if (len < 0)
    return NULL;
  std::vector<String> strv;
  for (ssize_t k = 0; k < len; k++)
    {
      PyObject *item = PyList_GET_ITEM (list, k);
      char *as = NULL;
      Py_ssize_t al = 0;
      if (PyString_AsStringAndSize (item, &as, &al) < 0)
        return NULL;
      strv.push_back (String (as, al));
    }
  if (PyErr_Occurred())
    return NULL;
  String appurl = UIThread::ui_thread_create (String (ns, nl), strv);
  if (appurl.size() == 0)
    ; // FIXME: throw exception
  return PyString_FromStringAndSize (appurl.data(), appurl.size());
}

} // Anon

// --- Python module definitions (global namespace) ---
static PyMethodDef rope_vtable[] = {
  { "_init_dispatcher",         rope_init_dispatcher,         METH_VARARGS,
    "Rapicorn::_init_dispatcher() - initial setup." },
  { "__rope_pytrampoline__",    plic_cpy_trampoline,          METH_VARARGS,
    "Rapicorn function invokation trampoline." },
  { "printout",                 rope_printout,                METH_VARARGS,
    "Rapicorn::printout() - print to stdout." },
  { NULL, } // sentinel
};
static const char rapicorn_doc[] = "Rapicorn Python Language Binding Module.";

PyMODINIT_FUNC
MODULE_INIT_FUNCTION (void) // conventional dlmodule initializer
{
  // register module
  PyObject *m = Py_InitModule3 (MODULE_NAME_STRING, rope_vtable, (char*) rapicorn_doc);
  if (!m)
    return;

  // register Rypicorn exception
  if (!rapicorn_exception)
    rapicorn_exception = PyErr_NewException ((char*) MODULE_NAME_STRING ".exception", NULL, NULL);
  if (!rapicorn_exception)
    return;
  Py_INCREF (rapicorn_exception);
  PyModule_AddObject (m, "exception", rapicorn_exception);

  // retrieve argv[0]
  char *argv0;
  {
    PyObject *sysmod = PyImport_ImportModule ("sys");
    PyObject *astr   = sysmod ? PyObject_GetAttrString (sysmod, "argv") : NULL;
    PyObject *arg0   = astr ? PySequence_GetItem (astr, 0) : NULL;
    argv0            = arg0 ? strdup (PyString_AsString (arg0)) : NULL;
    Py_XDECREF (arg0);
    Py_XDECREF (astr);
    Py_XDECREF (sysmod);
    if (!argv0)
      return; // exception set
  }

  // initialize Rapicorn with dummy argv, hardcode X11 temporarily
  {
    // int dummyargc = 1;
    char *dummyargs[] = { NULL, NULL };
    dummyargs[0] = argv0[0] ? argv0 : (char*) "Python>>>";
    // char **dummyargv = dummyargs;
    // FIXME: // App.init_with_x11 (&dummyargc, &dummyargv, dummyargs[0]);
  }
  free (argv0);
}
// using global namespace for Python module initialization

// FIXME: move...
//#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

static int
cpu_affinity (int cpu)
{
  pthread_t thread = pthread_self();
  cpu_set_t cpuset;

  if (cpu >= 0 && cpu < CPU_SETSIZE)
    {
      CPU_ZERO (&cpuset);
      CPU_SET (cpu, &cpuset);
      if (pthread_setaffinity_np (thread, sizeof (cpu_set_t), &cpuset) != 0)
        perror ("pthread_setaffinity_np");
    }

  if (pthread_getaffinity_np (thread, sizeof (cpu_set_t), &cpuset) != 0)
    perror ("pthread_getaffinity_np");
  printf ("Affinity(%ld/%d cpus): thread=%p", sysconf (_SC_NPROCESSORS_ONLN), CPU_SETSIZE, (void*)thread);
  for (int j = 0; j < CPU_SETSIZE; j++)
    if (CPU_ISSET (j, &cpuset))
      {
        printf ("    CPU %d\n", j);
        return j;
      }
  return -1;
}
<|endoftext|>


<commit_before>#include "DELTAPAK_S.H"

#include "DELTAPAK.H"
#include "DRAW.H"
#include "MATHS.H"
#include "SETUP.H"
#include "SPECIFIC.H"

void DrawCutSeqActors()//90DCC(<),
{
	struct NEW_CUTSCENE* cut;//$s3

	cut = &GLOBAL_cutme[0];
	//a0 = meshes
	//v0 = cut->numactors
	//s6 = 1

	if (1 < cut->numactors)
	{
		mPushMatrix();

		//loc_90E1C
		mPushMatrix();

		//v1 = 1 << 2
		//s7 = cutseq_meshbits[1];//$v1 shft
		//fp = cutseq_meshswapbits[1];//$v1 shft
		//v0 = 0x80000000 & cutseq_meshbits[1];

		if (0x80000000 & cutseq_meshbits[1])
		{
			//v0 = &actor_pnodes[1];//$v1 shft

			//v1 = 1 << 3
			//v1 = &cut[2];
			sizeof(struct NEW_CUTSCENE);
		}//loc_90FDC
	}//loc_91000

#if 0
addu    $v1, $s3, $v1
lh      $a1, 0x1E($v1)
lw      $a0, 0($v0)
li      $a2, 0xA60FC
jal     sub_91030
addiu   $a1, 1
sll     $v1, $s6, 3
addu    $v1, $s3, $v1
lh      $v1, 0x1C($v1)
lw      $a0, 4($s3)
lw      $a1, 8($s3)
lw      $a2, 0xC($s3)
li      $v0, 0x1F2480
sll     $v1, 6
jal     sub_76568
addu    $s4, $v1, $v0
jal     sub_91110
nop
lh      $v0, 2($s4)
lw      $v1, 4($s4)
sll     $v0, 2
addu    $s1, $s0, $v0
lw      $v0, 0x2030($gp)
sll     $v1, 2
li      $a2, 0xA60FC
lh      $a0, 0xC($a2)
lh      $a1, 0xE($a2)
lh      $a2, 0x10($a2)
jal     sub_7658C
addu    $s2, $v0, $v1
addiu   $a0, $sp, 0x48+var_38
move    $a1, $zero
li      $v0, 0xA610E
jal     sub_768BC
sw      $v0, 0x48+var_38($sp)
andi    $v0, $s7, 1
beqz    $v0, loc_90F3C
andi    $v0, $fp, 1
beqz    $v0, loc_90F1C
lw      $a0, 0($s1)
lw      $a0, 4($s1)

loc_90F1C:
addiu   $at, $s6, -1
bnez    $at, loc_90F34
nop
lw      $a1, 0x410($gp)
jal     sub_7FAD4
addiu   $ra, 8

loc_90F34:
jal     sub_7EEC4
li      $a1, 0xFFFFFFFF

loc_90F3C:
lh      $s4, 0($s4)
li      $s5, 1
addiu   $s4, -1
blez    $s4, loc_90FDC
addiu   $s1, 8

loc_90F50:
lw      $a1, 0($s2)
addiu   $s4, -1
andi    $v0, $a1, 1
beqz    $v0, loc_90F6C
andi    $a1, 2
jal     sub_76520
nop

loc_90F6C:
beqz    $a1, loc_90F7C
sll     $s5, 1
jal     sub_764D0
nop

loc_90F7C:
lw      $a0, 4($s2)
lw      $a1, 8($s2)
jal     sub_7658C
lw      $a2, 0xC($s2)
addiu   $a0, $sp, 0x48+var_38
jal     sub_768BC
move    $a1, $zero
and     $v0, $s5, $s7
beqz    $v0, loc_90FD0
and     $v0, $s5, $fp
beqz    $v0, loc_90FB0
lw      $a0, 0($s1)
lw      $a0, 4($s1)

loc_90FB0:
addiu   $at, $s6, -1
bnez    $at, loc_90FC8
nop
lw      $a1, 0x410($gp)
jal     sub_7FAD4
addiu   $ra, 8

loc_90FC8:
jal     sub_7EEC4
li      $a1, 0xFFFFFFFF

loc_90FD0:
addiu   $s2, 0x10
bnez    $s4, loc_90F50
addiu   $s1, 8

loc_90FDC:
jal     sub_76520
nop
lh      $v1, 0($s3)
addiu   $s6, 1
slt     $v1, $s6, $v1
bnez    $v1, loc_90E1C
nop
jal     sub_76520
nop

loc_91000:
lw      $ra, 0x48+var_4($sp)
lw      $fp, 0x48+var_8($sp)
lw      $s7, 0x48+var_C($sp)
lw      $s6, 0x48+var_10($sp)
lw      $s5, 0x48+var_14($sp)
lw      $s4, 0x48+var_18($sp)
lw      $s3, 0x48+var_1C($sp)
lw      $s2, 0x48+var_20($sp)
lw      $s1, 0x48+var_24($sp)
lw      $s0, 0x48+var_28($sp)
jr      $ra
addiu   $sp, 0x48
#endif
}

void updateAnimFrame(struct PACKNODE* node, int flags, short* frame)// (F)
{
	frame[7] = 3 * node->yrot_run;

	short x = 3 * node->xrot_run;
	short z = 3 * node->zrot_run;

	switch (cutrot)
	{
	case 0:
		frame[6] = x;
		frame[8] = z;
		break;
	case 1:
		frame[6] = z;
		frame[8] = -x;
		break;
	case 2:
		frame[6] = -x;
		frame[8] = -z;
		break;
	case 3:
		frame[6] = -z;
		frame[8] = x;
		break;
	}

	short* next = frame + 9;

	for (int i = 1; i < flags; i++, next += 2)
	{
		short x = node[i].yrot_run;
		short y = node[i].zrot_run;
		short z = node[i].xrot_run;

		if (cutrot && i == 1)
		{
			x = (x + ((short)cutrot << 8)) & 0x3FF;
		}

		next[0] = (y | ((x | (z << 10)) << 10)) >> 16;
		next[1] = y | ((x | (z << 10)) << 10);
	}
}

int GetTrackWord(unsigned long off, char* packed, unsigned char packmethod)
{
	int a0 = off * packmethod;
	int v0 = a0 >> 3;
	packed = &packed[v0];
	a0 &= 7;
	unsigned int at = ((unsigned char*)packed)[0] | (((unsigned char*)packed)[1] << 8) | (((unsigned char*)packed)[2] << 16) | (((unsigned char*)packed)[3] << 24);
	at = at >> a0;
	unsigned int v1 = (1 << packmethod) - 1;
	at &= v1;
	packmethod -= 1;
	v0 = (1 << packmethod);
	v0 = at & v0;

	if (v0 != 0)
	{
		v0 = v1 ^ -1;///@CHECKME nor     $v0, $zero, $v1
		at |= v0;
	}
	else
	{
		v0 = v1 ^ -1;///@CHECKME nor     $v0, $zero, $v1
	}
	//loc_90DC0
	v0 = at << 16;
	v0 >>= 16;

	return v0;
}

int DecodeTrack(char* packed, struct RTDECODE* decode)//90BD8(<), ?
{
	int t0 = 0;
	int v0 = 0;

	if (decode->decodetype == 0)
	{
		t0 = GetTrackWord(decode->off, packed, decode->packmethod);

		if (!(t0 & 0x20))
		{
			decode->decodetype = 2;

			if ((t0 & 0x10))
			{
				GetTrackWord(decode->off + 1, packed, decode->packmethod);
				decode->counter = ((t0 & 7) << 5) | (GetTrackWord(decode->off + 1, packed, decode->packmethod) & 0x1F);
				decode->data = GetTrackWord(decode->off + 2, packed, decode->packmethod);
				decode->off += 3;
				decode->length -= 3;
			}
			else
			{
				//loc_90C70
				decode->data = GetTrackWord(decode->off + 1, packed, decode->packmethod);
				decode->counter = t0 & 0x7;
				decode->off += 2;
				decode->length -= 2;
			}
		}
		else
		{
			//loc_90CA0
			if (!(t0 & 0xF))
			{
				decode->counter = 16;
			}
			else
			{
				decode->counter = (t0 & 0xF);
			}

			//loc_90CAC
			decode->decodetype = 1;
			decode->off += 1;
			decode->length -= 1;
		}
	}
	//loc_90CD0
	if (decode->decodetype == 2)
	{
		if (--decode->counter == 0)
		{
			decode->decodetype = 0;
		}

		//loc_90CFC
		return decode->data;
	}

	//loc_90D08
	v0 = GetTrackWord(decode->off, packed, decode->packmethod);

	decode->counter -= 1;
	decode->off += 1;
	decode->length -= 1;

	if (!(decode->counter & 0xFFFF))
	{
		decode->decodetype = 0;
	}
	//loc_90D48
	v0 <<= 16;
	v0 >>= 16;

	return v0;
}

void DecodeAnim(struct PACKNODE* node, int a1, int frame, short a3)//90A88(<), ?
{
	int t4;
	//t7 = a3
	//t3 = node
	//t5 = a1
	struct PACKNODE* pn = NULL;//$t0

	if (frame == 0)
	{
		t4 = 0;
		if (a1 > 0)
		{
			pn = node;
			//loc_90AA8
			do
			{
				t4++;

				pn->decode_x.off = 0;
				pn->decode_x.counter = 0;
				pn->decode_x.data = 0;
				pn->decode_x.decodetype = 0;

				pn->decode_y.off = 0;
				pn->decode_y.counter = 0;
				pn->decode_y.data = 0;
				pn->decode_y.decodetype = 0;

				pn->decode_z.off = 0;
				pn->decode_z.counter = 0;
				pn->decode_z.data = 0;
				pn->decode_z.decodetype = 0;

				pn->xrot_run = (unsigned short)pn->xkey;
				pn->yrot_run = (unsigned short)pn->ykey;
				pn->zrot_run = (unsigned short)pn->zkey;

				pn->decode_x.length = pn->xlength;
				pn->decode_y.length = pn->ylength;
				pn->decode_z.length = pn->zlength;
				pn++;
			} while (t4 < a1);
		}//loc_90BD0
	}
	else
	{
		//loc_90B14
		DecodeTrack(node->xpacked, &node->decode_x);
	}
#if 0
loc_90B14:
lw      $a0, 0x48($t3)
jal     sub_90BD8
addiu   $a1, $t3, 0xC

addiu   $a1, $t3, 0x1C
lhu     $v1, 0($t3)
lw      $a0, 0x4C($t3)
addu    $v1, $v0
jal     sub_90BD8
sh      $v1, 0($t3)

addiu   $a1, $t3, 0x2C
lhu     $v1, 2($t3)
lw      $a0, 0x50($t3)
addu    $v1, $v0
jal     sub_90BD8
sh      $v1, 2($t3)

lhu     $v1, 4($t3)
li      $t4, 1
addu    $v1, $v0
slt     $v0, $t4, $t5
beqz    $v0, loc_90BD0
sh      $v1, 4($t3)
addiu   $t3, 0x54

loc_90B6C:
lw      $a0, 0x48($t3)
jal     sub_90BD8
addiu   $a1, $t3, 0xC

addiu   $a1, $t3, 0x1C
lhu     $v1, 0($t3)
lw      $a0, 0x4C($t3)
addu    $v1, $v0
and     $v1, $t7
jal     sub_90BD8
sh      $v1, 0($t3)

addiu   $a1, $t3, 0x2C
lhu     $v1, 2($t3)
lw      $a0, 0x50($t3)
addu    $v1, $v0
and     $v1, $t7
jal     sub_90BD8
sh      $v1, 2($t3)

lhu     $v1, 4($t3)
addiu   $t4, 1
addu    $v1, $v0
and     $v1, $t7
sh      $v1, 4($t3)
slt     $v0, $t4, $t5
bnez    $v0, loc_90B6C
addiu   $t3, 0x54

loc_90BD0:
jr      $t6
nop
#endif
}
<commit_msg>[Specific-PSXPC_N] Implement DecodeAnim.<commit_after>#include "DELTAPAK_S.H"

#include "DELTAPAK.H"
#include "DRAW.H"
#include "MATHS.H"
#include "SETUP.H"
#include "SPECIFIC.H"

void DrawCutSeqActors()//90DCC(<),
{
	struct NEW_CUTSCENE* cut;//$s3

	cut = &GLOBAL_cutme[0];
	//a0 = meshes
	//v0 = cut->numactors
	//s6 = 1

	if (1 < cut->numactors)
	{
		mPushMatrix();

		//loc_90E1C
		mPushMatrix();

		//v1 = 1 << 2
		//s7 = cutseq_meshbits[1];//$v1 shft
		//fp = cutseq_meshswapbits[1];//$v1 shft
		//v0 = 0x80000000 & cutseq_meshbits[1];

		if (0x80000000 & cutseq_meshbits[1])
		{
			//v0 = &actor_pnodes[1];//$v1 shft

			//v1 = 1 << 3
			//v1 = &cut[2];
			sizeof(struct NEW_CUTSCENE);
		}//loc_90FDC
	}//loc_91000

#if 0
addu    $v1, $s3, $v1
lh      $a1, 0x1E($v1)
lw      $a0, 0($v0)
li      $a2, 0xA60FC
jal     sub_91030
addiu   $a1, 1
sll     $v1, $s6, 3
addu    $v1, $s3, $v1
lh      $v1, 0x1C($v1)
lw      $a0, 4($s3)
lw      $a1, 8($s3)
lw      $a2, 0xC($s3)
li      $v0, 0x1F2480
sll     $v1, 6
jal     sub_76568
addu    $s4, $v1, $v0
jal     sub_91110
nop
lh      $v0, 2($s4)
lw      $v1, 4($s4)
sll     $v0, 2
addu    $s1, $s0, $v0
lw      $v0, 0x2030($gp)
sll     $v1, 2
li      $a2, 0xA60FC
lh      $a0, 0xC($a2)
lh      $a1, 0xE($a2)
lh      $a2, 0x10($a2)
jal     sub_7658C
addu    $s2, $v0, $v1
addiu   $a0, $sp, 0x48+var_38
move    $a1, $zero
li      $v0, 0xA610E
jal     sub_768BC
sw      $v0, 0x48+var_38($sp)
andi    $v0, $s7, 1
beqz    $v0, loc_90F3C
andi    $v0, $fp, 1
beqz    $v0, loc_90F1C
lw      $a0, 0($s1)
lw      $a0, 4($s1)

loc_90F1C:
addiu   $at, $s6, -1
bnez    $at, loc_90F34
nop
lw      $a1, 0x410($gp)
jal     sub_7FAD4
addiu   $ra, 8

loc_90F34:
jal     sub_7EEC4
li      $a1, 0xFFFFFFFF

loc_90F3C:
lh      $s4, 0($s4)
li      $s5, 1
addiu   $s4, -1
blez    $s4, loc_90FDC
addiu   $s1, 8

loc_90F50:
lw      $a1, 0($s2)
addiu   $s4, -1
andi    $v0, $a1, 1
beqz    $v0, loc_90F6C
andi    $a1, 2
jal     sub_76520
nop

loc_90F6C:
beqz    $a1, loc_90F7C
sll     $s5, 1
jal     sub_764D0
nop

loc_90F7C:
lw      $a0, 4($s2)
lw      $a1, 8($s2)
jal     sub_7658C
lw      $a2, 0xC($s2)
addiu   $a0, $sp, 0x48+var_38
jal     sub_768BC
move    $a1, $zero
and     $v0, $s5, $s7
beqz    $v0, loc_90FD0
and     $v0, $s5, $fp
beqz    $v0, loc_90FB0
lw      $a0, 0($s1)
lw      $a0, 4($s1)

loc_90FB0:
addiu   $at, $s6, -1
bnez    $at, loc_90FC8
nop
lw      $a1, 0x410($gp)
jal     sub_7FAD4
addiu   $ra, 8

loc_90FC8:
jal     sub_7EEC4
li      $a1, 0xFFFFFFFF

loc_90FD0:
addiu   $s2, 0x10
bnez    $s4, loc_90F50
addiu   $s1, 8

loc_90FDC:
jal     sub_76520
nop
lh      $v1, 0($s3)
addiu   $s6, 1
slt     $v1, $s6, $v1
bnez    $v1, loc_90E1C
nop
jal     sub_76520
nop

loc_91000:
lw      $ra, 0x48+var_4($sp)
lw      $fp, 0x48+var_8($sp)
lw      $s7, 0x48+var_C($sp)
lw      $s6, 0x48+var_10($sp)
lw      $s5, 0x48+var_14($sp)
lw      $s4, 0x48+var_18($sp)
lw      $s3, 0x48+var_1C($sp)
lw      $s2, 0x48+var_20($sp)
lw      $s1, 0x48+var_24($sp)
lw      $s0, 0x48+var_28($sp)
jr      $ra
addiu   $sp, 0x48
#endif
}

void updateAnimFrame(struct PACKNODE* node, int flags, short* frame)// (F)
{
	frame[7] = 3 * node->yrot_run;

	short x = 3 * node->xrot_run;
	short z = 3 * node->zrot_run;

	switch (cutrot)
	{
	case 0:
		frame[6] = x;
		frame[8] = z;
		break;
	case 1:
		frame[6] = z;
		frame[8] = -x;
		break;
	case 2:
		frame[6] = -x;
		frame[8] = -z;
		break;
	case 3:
		frame[6] = -z;
		frame[8] = x;
		break;
	}

	short* next = frame + 9;

	for (int i = 1; i < flags; i++, next += 2)
	{
		short x = node[i].yrot_run;
		short y = node[i].zrot_run;
		short z = node[i].xrot_run;

		if (cutrot && i == 1)
		{
			x = (x + ((short)cutrot << 8)) & 0x3FF;
		}

		next[0] = (y | ((x | (z << 10)) << 10)) >> 16;
		next[1] = y | ((x | (z << 10)) << 10);
	}
}

int GetTrackWord(unsigned long off, char* packed, unsigned char packmethod)
{
	int a0 = off * packmethod;
	int v0 = a0 >> 3;
	packed = &packed[v0];
	a0 &= 7;
	unsigned int at = ((unsigned char*)packed)[0] | (((unsigned char*)packed)[1] << 8) | (((unsigned char*)packed)[2] << 16) | (((unsigned char*)packed)[3] << 24);
	at = at >> a0;
	unsigned int v1 = (1 << packmethod) - 1;
	at &= v1;
	packmethod -= 1;
	v0 = (1 << packmethod);
	v0 = at & v0;

	if (v0 != 0)
	{
		v0 = v1 ^ -1;///@CHECKME nor     $v0, $zero, $v1
		at |= v0;
	}
	else
	{
		v0 = v1 ^ -1;///@CHECKME nor     $v0, $zero, $v1
	}
	//loc_90DC0
	v0 = at << 16;
	v0 >>= 16;

	return v0;
}

int DecodeTrack(char* packed, struct RTDECODE* decode)//90BD8(<), ?
{
	int t0 = 0;
	int v0 = 0;

	if (decode->decodetype == 0)
	{
		t0 = GetTrackWord(decode->off, packed, decode->packmethod);

		if (!(t0 & 0x20))
		{
			decode->decodetype = 2;

			if ((t0 & 0x10))
			{
				GetTrackWord(decode->off + 1, packed, decode->packmethod);
				decode->counter = ((t0 & 7) << 5) | (GetTrackWord(decode->off + 1, packed, decode->packmethod) & 0x1F);
				decode->data = GetTrackWord(decode->off + 2, packed, decode->packmethod);
				decode->off += 3;
				decode->length -= 3;
			}
			else
			{
				//loc_90C70
				decode->data = GetTrackWord(decode->off + 1, packed, decode->packmethod);
				decode->counter = t0 & 0x7;
				decode->off += 2;
				decode->length -= 2;
			}
		}
		else
		{
			//loc_90CA0
			if (!(t0 & 0xF))
			{
				decode->counter = 16;
			}
			else
			{
				decode->counter = (t0 & 0xF);
			}

			//loc_90CAC
			decode->decodetype = 1;
			decode->off += 1;
			decode->length -= 1;
		}
	}
	//loc_90CD0
	if (decode->decodetype == 2)
	{
		if (--decode->counter == 0)
		{
			decode->decodetype = 0;
		}

		//loc_90CFC
		return decode->data;
	}

	//loc_90D08
	v0 = GetTrackWord(decode->off, packed, decode->packmethod);

	decode->counter -= 1;
	decode->off += 1;
	decode->length -= 1;

	if (!(decode->counter & 0xFFFF))
	{
		decode->decodetype = 0;
	}
	//loc_90D48
	v0 <<= 16;
	v0 >>= 16;

	return v0;
}

void DecodeAnim(struct PACKNODE* node, int a1, int frame, short a3)//90A88(<), ?
{
	int t4 = 0;

	if (frame == 0)
	{
		t4 = 0;
		if (a1 > 0)
		{
			//loc_90AA8
			do
			{
				t4++;

				node->decode_x.off = 0;
				node->decode_x.counter = 0;
				node->decode_x.data = 0;
				node->decode_x.decodetype = 0;

				node->decode_y.off = 0;
				node->decode_y.counter = 0;
				node->decode_y.data = 0;
				node->decode_y.decodetype = 0;

				node->decode_z.off = 0;
				node->decode_z.counter = 0;
				node->decode_z.data = 0;
				node->decode_z.decodetype = 0;

				node->xrot_run = (unsigned short)node->xkey;
				node->yrot_run = (unsigned short)node->ykey;
				node->zrot_run = (unsigned short)node->zkey;

				node->decode_x.length = node->xlength;
				node->decode_y.length = node->ylength;
				node->decode_z.length = node->zlength;
				node++;
			} while (t4 < a1);
		}
		//loc_90BD0
		return;
	}
	else
	{
		//loc_90B14
		node->xrot_run += DecodeTrack(node->xpacked, &node->decode_x);
		node->yrot_run += DecodeTrack(node->ypacked, &node->decode_y);
		node->zrot_run += DecodeTrack(node->zpacked, &node->decode_z);
		t4 = 1;
		node++;
		if (t4 >= a1)
		{
			return;
		}
	}

	//loc_90B6C
	do
	{
		node->xrot_run += DecodeTrack(node->xpacked, &node->decode_x) & a3;
		node->yrot_run += DecodeTrack(node->ypacked, &node->decode_y) & a3;
		node->zrot_run += DecodeTrack(node->zpacked, &node->decode_z) & a3;
		t4++;
		node++;
	} while (t4 < a1);
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2007 Till Adam <adam@kde.org>

    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 "maildir.h"

#include <QDir>
#include <QFileInfo>
#include <QUuid>

#include <klocale.h>

using namespace KPIM;

struct Maildir::Private
{
    Private( const QString& p )
    :path(p)
    {
    }

    Private( const Private& rhs )
    {
      path = rhs.path;
    }

    bool operator==( const Private& rhs ) const
    {
      return path == rhs.path;
    }
    bool accessIsPossible( QString& error ) const;
    bool canAccess( const QString& path ) const;

    QStringList subPaths() const
    {
      QStringList paths;
      paths << path + QString::fromLatin1("/cur");
      paths << path + QString::fromLatin1("/new");
      paths << path + QString::fromLatin1("/tmp");
      return paths;
    }

    QStringList listNew() const
    {
      QDir d( path + QString::fromLatin1("/new") );
      return d.entryList(QDir::Files);
    }

    QStringList listCurrent() const
    {
      QDir d( path + QString::fromLatin1("/cur") );
      return d.entryList(QDir::Files);
    }

    QString findRealKey( const QString& key ) const
    {
      QString realKey = path + QString::fromLatin1("/new/") + key;
      QFile f( realKey );
      if ( !f.exists() )
        realKey = path + QString::fromLatin1("/cur/") + key;
      QFile f2( realKey );
      if ( !f2.exists() )
        realKey = QString();
      return realKey;
    }

    QString path;
};

Maildir::Maildir( const QString& path )
:d( new Private(path) )
{
}

void Maildir::swap( const Maildir &rhs )
{
    Private *p = d;
    d = new Private( *rhs.d );
    delete p;
}

Maildir::Maildir(const Maildir & rhs)
  :d( new Private(*rhs.d) )

{
}

Maildir& Maildir::operator= (const Maildir & rhs)
{
    // copy and swap, exception safe, and handles assignment to self
    Maildir temp(rhs);
    swap( temp );
    return *this;
}

bool Maildir::operator== (const Maildir & rhs) const
{
  return *d == *rhs.d;
}

Maildir::~Maildir()
{
    delete d;
}

bool Maildir::Private::canAccess( const QString& path ) const
{
  //return access(QFile::encodeName( path ), R_OK | W_OK | X_OK ) != 0;
  // FIXME X_OK?
  QFileInfo d(path);
  return d.isReadable() && d.isWritable();
}

bool Maildir::Private::accessIsPossible( QString& error ) const
{
  QStringList paths = subPaths();
  paths.prepend( path );

  Q_FOREACH( QString p, paths )
  {
    if ( !QFile::exists(p) ) {
      error = i18n("Error opening %1; this folder is missing.",p);
      return false;
    }
    if ( !canAccess( p ) ) {
      error = i18n("Error opening %1; either this is not a valid "
                "maildir folder, or you do not have sufficient access permissions." ,p);
      return false;
    }
  }
  return true;
}

bool Maildir::isValid() const
{
  QString error;
  return isValid( error );
}

bool Maildir::isValid( QString &error ) const
{
  if ( d->accessIsPossible( error ) ) {
    return true;
  }
  return false;
}

bool Maildir::create()
{
  Q_FOREACH( QString p, d->subPaths() ) {
    QDir dir( p );
    if ( !dir.exists( p ) ) {
      if ( !dir.mkpath( p ) )
        return false;
    }
  }
  return true;
}

QStringList Maildir::entryList() const
{
  QStringList result;
  if ( isValid() ) {
    result += d->listNew();
    result += d->listCurrent();
  }
//  kDebug() << "Maildir::entryList()" << result;
  return result;
}

QStringList Maildir::subFolderList() const
{
  QDir dir( d->path );
  QString subDirPath = QString::fromLatin1(".%1.directory").arg( dir.dirName() );
  dir.cdUp();
  if (!dir.exists( subDirPath ) ) return QStringList();
  dir.cd( subDirPath );
  dir.setFilter( QDir::Dirs | QDir::NoDotAndDotDot );
  return dir.entryList();
}

QByteArray Maildir::readEntry( const QString& key ) const
{
  QByteArray result;

  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::readEntry unable to find: " << key;
      return result;
  }

  QFile f( realKey );
  f.open( QIODevice::ReadOnly );

  // FIXME be safer than this
  result = f.readAll();

  return result;
}

static QString createUniqueFileName()
{
  return QUuid::createUuid().toString();
}

void Maildir::writeEntry( const QString& key, const QByteArray& data )
{
  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::writeEntry unable to find: " << key;
      return;
  }
  QFile f( realKey );
  f.open( QIODevice::WriteOnly );
  f.write( data );
  f.close();
}

QString Maildir::addEntry( const QByteArray& data )
{
  QString uniqueKey( createUniqueFileName() );
  QString key( d->path + "/tmp/" + uniqueKey );
  QString finalKey( d->path + "/new/" + uniqueKey );
  QFile f( key );
  f.open( QIODevice::WriteOnly );
  f.write( data );
  f.close();
  if (!f.rename( finalKey )) {
    qWarning() << "Maildir: Failed to add entry: " << finalKey  << "!";
  }
  return uniqueKey;
}

bool Maildir::removeEntry( const QString& key )
{
  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::removeEntry unable to find: " << key;
      return false;
  }
  return QFile::remove(realKey);
}

<commit_msg>Add a fixme.<commit_after>/*
    Copyright (c) 2007 Till Adam <adam@kde.org>

    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 "maildir.h"

#include <QDir>
#include <QFileInfo>
#include <QUuid>

#include <klocale.h>

using namespace KPIM;

struct Maildir::Private
{
    Private( const QString& p )
    :path(p)
    {
    }

    Private( const Private& rhs )
    {
      path = rhs.path;
    }

    bool operator==( const Private& rhs ) const
    {
      return path == rhs.path;
    }
    bool accessIsPossible( QString& error ) const;
    bool canAccess( const QString& path ) const;

    QStringList subPaths() const
    {
      QStringList paths;
      paths << path + QString::fromLatin1("/cur");
      paths << path + QString::fromLatin1("/new");
      paths << path + QString::fromLatin1("/tmp");
      return paths;
    }

    QStringList listNew() const
    {
      QDir d( path + QString::fromLatin1("/new") );
      return d.entryList(QDir::Files);
    }

    QStringList listCurrent() const
    {
      QDir d( path + QString::fromLatin1("/cur") );
      return d.entryList(QDir::Files);
    }

    QString findRealKey( const QString& key ) const
    {
      QString realKey = path + QString::fromLatin1("/new/") + key;
      QFile f( realKey );
      if ( !f.exists() )
        realKey = path + QString::fromLatin1("/cur/") + key;
      QFile f2( realKey );
      if ( !f2.exists() )
        realKey = QString();
      return realKey;
    }

    QString path;
};

Maildir::Maildir( const QString& path )
:d( new Private(path) )
{
}

void Maildir::swap( const Maildir &rhs )
{
    Private *p = d;
    d = new Private( *rhs.d );
    delete p;
}

Maildir::Maildir(const Maildir & rhs)
  :d( new Private(*rhs.d) )

{
}

Maildir& Maildir::operator= (const Maildir & rhs)
{
    // copy and swap, exception safe, and handles assignment to self
    Maildir temp(rhs);
    swap( temp );
    return *this;
}

bool Maildir::operator== (const Maildir & rhs) const
{
  return *d == *rhs.d;
}

Maildir::~Maildir()
{
    delete d;
}

bool Maildir::Private::canAccess( const QString& path ) const
{
  //return access(QFile::encodeName( path ), R_OK | W_OK | X_OK ) != 0;
  // FIXME X_OK?
  QFileInfo d(path);
  return d.isReadable() && d.isWritable();
}

bool Maildir::Private::accessIsPossible( QString& error ) const
{
  QStringList paths = subPaths();
  paths.prepend( path );

  Q_FOREACH( QString p, paths )
  {
    if ( !QFile::exists(p) ) {
      error = i18n("Error opening %1; this folder is missing.",p);
      return false;
    }
    if ( !canAccess( p ) ) {
      error = i18n("Error opening %1; either this is not a valid "
                "maildir folder, or you do not have sufficient access permissions." ,p);
      return false;
    }
  }
  return true;
}

bool Maildir::isValid() const
{
  QString error;
  return isValid( error );
}

bool Maildir::isValid( QString &error ) const
{
  if ( d->accessIsPossible( error ) ) {
    return true;
  }
  return false;
}

bool Maildir::create()
{
  Q_FOREACH( QString p, d->subPaths() ) {
    QDir dir( p );
    if ( !dir.exists( p ) ) {
      if ( !dir.mkpath( p ) )
        return false;
    }
  }
  return true;
}

QStringList Maildir::entryList() const
{
  QStringList result;
  if ( isValid() ) {
    result += d->listNew();
    result += d->listCurrent();
  }
//  kDebug() << "Maildir::entryList()" << result;
  return result;
}

QStringList Maildir::subFolderList() const
{
  QDir dir( d->path );
  QString subDirPath = QString::fromLatin1(".%1.directory").arg( dir.dirName() );
  dir.cdUp();
  if (!dir.exists( subDirPath ) ) return QStringList();
  dir.cd( subDirPath );
  dir.setFilter( QDir::Dirs | QDir::NoDotAndDotDot );
  return dir.entryList();
}

QByteArray Maildir::readEntry( const QString& key ) const
{
  QByteArray result;

  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::readEntry unable to find: " << key;
      return result;
  }

  QFile f( realKey );
  f.open( QIODevice::ReadOnly );

  // FIXME be safer than this
  result = f.readAll();

  return result;
}

static QString createUniqueFileName()
{
  return QUuid::createUuid().toString();
}

void Maildir::writeEntry( const QString& key, const QByteArray& data )
{
  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::writeEntry unable to find: " << key;
      return;
  }
  QFile f( realKey );
  f.open( QIODevice::WriteOnly );
  f.write( data );
  f.close();
}

QString Maildir::addEntry( const QByteArray& data )
{
  QString uniqueKey( createUniqueFileName() );
  QString key( d->path + "/tmp/" + uniqueKey );
  QString finalKey( d->path + "/new/" + uniqueKey );
  QFile f( key );
  f.open( QIODevice::WriteOnly );
  f.write( data );
  f.close();
  /*
   * FIXME:
   *
   * THe whole point of the locking free maildir idea is that the moves between
   * the internal directories are atomic. Afaik QFile::rename does not guarantee
   * that, so this will need to be done properly. - ta
   */
  if (!f.rename( finalKey )) {
    qWarning() << "Maildir: Failed to add entry: " << finalKey  << "!";
  }
  return uniqueKey;
}

bool Maildir::removeEntry( const QString& key )
{
  QString realKey( d->findRealKey( key ) );
  if ( realKey.isEmpty() ) {
      // FIXME error handling?
      qWarning() << "Maildir::removeEntry unable to find: " << key;
      return false;
  }
  return QFile::remove(realKey);
}

<|endoftext|>


<commit_before>/*
  Copyright 2009 Larry Gritz and the other authors and contributors.
  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 the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <iostream>
#include <cstdio>

#include "OpenImageIO/thread.h"
#include "OpenImageIO/ustring.h"
#include "OpenImageIO/strutil.h"

#include "OpenImageIO/unittest.h"

OIIO_NAMESPACE_USING;

// Test ustring's internal locks by creating a bunch of strings in many
// threads simultaneously.  Hopefully something will crash if the
// internal table is not being locked properly.

static void
create_lotso_ustrings ()
{
    std::cout << "thread " << boost::this_thread::get_id() << "\n";
    char buf[20];
    const int iterations = 1000000;
    for (int i = 0;  i < iterations;  ++i) {
        sprintf (buf, "%d", i);
        ustring s (buf);
    }
}

void test_ustring_lock ()
{
    std::cout << "hw threads = " << boost::thread::hardware_concurrency() << "\n";

    const int numthreads = 16;
    boost::thread_group threads;
    for (int i = 0;  i < numthreads;  ++i) {
        threads.create_thread (&create_lotso_ustrings);
    }
    std::cout << "Created " << threads.size() << " threads\n";
    threads.join_all ();
    std::cout << "\n" << ustring::getstats() << "\n";
    OIIO_CHECK_ASSERT (true);  // If we make it here without crashing, pass
}

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

    return unit_test_failures;
}
<commit_msg>Modify ustring_test to give it thread wedging benchmark abilities (modeled after spinlock_test)<commit_after>/*
  Copyright 2009 Larry Gritz and the other authors and contributors.
  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 the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <iostream>
#include <cstdio>

#include "OpenImageIO/thread.h"
#include "OpenImageIO/ustring.h"
#include "OpenImageIO/strutil.h"
#include "OpenImageIO/timer.h"
#include "OpenImageIO/argparse.h"

#include "OpenImageIO/unittest.h"

OIIO_NAMESPACE_USING;

// Test ustring's internal locks by creating a bunch of strings in many
// threads simultaneously.  Hopefully something will crash if the
// internal table is not being locked properly.

static int iterations = 1000000;
static int numthreads = 16;
static int ntrials = 1;
static bool verbose = false;
static bool wedge = false;
static spin_mutex print_mutex;  // make the prints not clobber each other

static void
create_lotso_ustrings (int iterations)
{
    if (verbose) {
        spin_lock lock(print_mutex);
        std::cout << "thread " << boost::this_thread::get_id() << "\n";
    }
    for (int i = 0;  i < iterations;  ++i) {
        char buf[20];
        sprintf (buf, "%d", i);
        ustring s (buf);
    }
}

void test_ustring_lock (int numthreads, int iterations)
{
    boost::thread_group threads;
    for (int i = 0;  i < numthreads;  ++i) {
        threads.create_thread (boost::bind (create_lotso_ustrings, iterations));
    }
    threads.join_all ();
    OIIO_CHECK_ASSERT (true);  // If we make it here without crashing, pass
}

static void
getargs (int argc, char *argv[])
{
    bool help = false;
    ArgParse ap;
    ap.options ("ustring_test\n"
                OIIO_INTRO_STRING "\n"
                "Usage:  ustring_test [options]",
                // "%*", parse_files, "",
                "--help", &help, "Print help message",
                "-v", &verbose, "Verbose mode",
                "--threads %d", &numthreads,
                    ustring::format("Number of threads (default: %d)", numthreads).c_str(),
                "--iters %d", &iterations,
                    ustring::format("Number of iterations (default: %d)", iterations).c_str(),
                "--trials %d", &ntrials, "Number of trials",
                "--wedge", &wedge, "Do a wedge test",
                NULL);
    if (ap.parse (argc, (const char**)argv) < 0) {
        std::cerr << ap.geterror() << std::endl;
        ap.usage ();
        exit (EXIT_FAILURE);
    }
    if (help) {
        ap.usage ();
        exit (EXIT_FAILURE);
    }
}

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

    std::cout << "hw threads = " << boost::thread::hardware_concurrency() << "\n";
    std::cout << "threads\ttime (best of " << ntrials << ")\n";
    std::cout << "-------\t----------\n";

    static int threadcounts[] = { 1, 2, 4, 8, 12, 16, 20, 24, 28, 32, 64, 128, 1024, 1<<30 };
    for (int i = 0; threadcounts[i] <= numthreads; ++i) {
        int nt = wedge ? threadcounts[i] : numthreads;
        int its = iterations/nt;

        double range;
        double t = time_trial (boost::bind(test_ustring_lock,nt,its),
                               ntrials, &range);

        std::cout << Strutil::format ("%2d\t%5.1f   range %.2f\t(%d iters/thread)\n",
                                      nt, t, range, its);
        if (! wedge)
            break;    // don't loop if we're not wedging
    }

    if (verbose)
        std::cout << "\n" << ustring::getstats() << "\n";

    return unit_test_failures;
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QApplication>
#include <QPoint>
#include <QRect>

#include "screenshotservice.h"
#include "taslogger.h"

/*!
  \class FixtureService
  \brief FixtureService closes the application

*/

static QString NO_UI_ERROR = "Application has not ui, cannot take screenshot!";

ScreenshotService::ScreenshotService()
{
}

ScreenshotService::~ScreenshotService()
{
}

bool ScreenshotService::executeService(TasCommandModel& model, TasResponse& response)
{
    if(model.service() == serviceName() ){
        TasLogger::logger()->debug("ScreenshotService::executeService in");
        if(qApp->type() != QApplication::Tty){
            getScreenshot(model, response);
        }
        else{
            TasLogger::logger()->debug("ScreenshotService::executeService application has no ui!");
            response.setErrorMessage(NO_UI_ERROR);
        }
        return true;
    }
    else{
        return false;
    }
}

void ScreenshotService::getScreenshot(TasCommandModel& model, TasResponse& response)
{
    QListIterator<TasTarget*> i(model.targetList());
    QString errorMsg = PARSE_ERROR;
    QImage screenshot;
    QString pictureFormat = "PNG";
    while (i.hasNext()){
        TasTarget* commandTarget = i.next();
        QString targetId = commandTarget->id();
        QString targetType = commandTarget->type();
        TasCommand* command = commandTarget->findCommand("Screenshot");
        //are required for command completion
        if(targetId.isEmpty() || targetType.isEmpty() || !command){
            continue;
        }

        if(!command->parameter("format").isEmpty()){
            pictureFormat = command->parameter("format");
        }

        if(!isFormatSupported(pictureFormat)){
            errorMsg = "Given format " + pictureFormat + "is not supported. Supported formats are: PNG, JPEG and BMP.";
            break;
        }

        bool draw = false;
        if(command->parameter("draw") == "true"){
            draw = true;
        }

        QWidget* target = 0;
        errorMsg = "Taking screenshot failed!";
        if(targetType == TYPE_GRAPHICS_VIEW){
            //TasLogger::logger()->debug("TYPE_GRAPHICS_VIEW Target id:" + targetId);
            QGraphicsItem* item = findGraphicsItem(targetId);
            if(item){
                QGraphicsView* view = getViewForItem(item);
                if(view){
                    QPoint point = view->mapFromScene(item->scenePos());
                    QPoint windowPoint = view->mapTo(view->window(), point);
                    QRectF itemRect = item->boundingRect();
                    ItemLocationDetails locationDetails = TestabilityUtils::getItemLocationDetails(item);

                    if(draw){
                        screenshot = QPixmap::grabWidget(view->window(), locationDetails.windowPoint.x(), locationDetails.windowPoint.y(),
                                                         locationDetails.width, locationDetails.height).toImage();
                    }
                    else{
                        screenshot = QPixmap::grabWindow(view->window()->winId(), locationDetails.windowPoint.x(), locationDetails.windowPoint.y(),
                                                         locationDetails.width, locationDetails.height).toImage();
                    }

                    if (!screenshot.isNull()) {
                        screenshot.setText("tas_id", objectId(view->window()));
                    }
                }
                else{
                    errorMsg = "Could not find a GraphicsView for the GraphicsItem!";
                }
            }
            else{
                errorMsg = "Could not find the GraphicsItem!";
            }
        }
        else{
            if(targetType == TYPE_STANDARD_VIEW){
                //TasLogger::logger()->debug("TYPE_STANDARD_VIEW about to find widget Target id:" + targetId);
                target = findWidget(targetId);
            }
            else{
                //TasLogger::logger()->debug("TYPE_APPLICATION_VIEW about to find application window Target id:" + targetId);
                target = getApplicationWindow();
                //in case no window false, return the desktop
                if(!target){
                    draw = false;
                    target = qApp->desktop();
                }
            }

            if(target){

                if ( (target->isWindow() && !draw) || target->inherits("QDesktopWidget")){
                    screenshot = QPixmap::grabWindow(target->winId()).toImage();
                }

                else{
                    if(draw){
                        screenshot = QPixmap::grabWidget(target).toImage();
                    }

                    else{
                        QPoint point = target->mapToGlobal(QPoint(0,0));
                        QPoint windowPoint = target->window()->mapFromGlobal(point);
                        screenshot = QPixmap::grabWindow(target->window()->winId(), windowPoint.x(), windowPoint.y(),
                                                         target->rect().width(), target->rect().height()).toImage();
                    }
                }

                if (!screenshot.isNull()) {
                    screenshot.setText("tas_id", objectId(target));
                }
            }
            else{
                TasLogger::logger()->debug("ScreenshotService::executeService application has no visible ui!");
                errorMsg = "Application has no visible ui!";
            }
        }
        break;
    }

    if (!screenshot.isNull()){
        QByteArray bytes;
        QBuffer buffer(&bytes);
        buffer.open(QIODevice::WriteOnly);
        screenshot.save(&buffer, pictureFormat.toAscii());
        response.setData(bytes);
    }
    else{
        response.setErrorMessage(errorMsg);
    }

}

bool ScreenshotService::isFormatSupported(QString format)
{
    if( QString::compare(format, "PNG", Qt::CaseInsensitive) == 0 ||
        QString::compare(format, "JPEG", Qt::CaseInsensitive) == 0 ||
        QString::compare(format, "BMP", Qt::CaseInsensitive) == 0){
        return true;
    }
    else{
        return false;
    }
}
<commit_msg>Cosmetic<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QApplication>
#include <QPoint>
#include <QRect>

#include "screenshotservice.h"
#include "taslogger.h"

/*!
  \class ScreenshotService
  \brief ScreenshotService closes the application

*/

static QString NO_UI_ERROR = "Application has not ui, cannot take screenshot!";

ScreenshotService::ScreenshotService()
{
}

ScreenshotService::~ScreenshotService()
{
}

bool ScreenshotService::executeService(TasCommandModel& model, TasResponse& response)
{
    if(model.service() == serviceName() ){
        TasLogger::logger()->debug("ScreenshotService::executeService in");
        if(qApp->type() != QApplication::Tty){
            getScreenshot(model, response);
        }
        else{
            TasLogger::logger()->debug("ScreenshotService::executeService application has no ui!");
            response.setErrorMessage(NO_UI_ERROR);
        }
        return true;
    }
    else{
        return false;
    }
}

void ScreenshotService::getScreenshot(TasCommandModel& model, TasResponse& response)
{
    QListIterator<TasTarget*> i(model.targetList());
    QString errorMsg = PARSE_ERROR;
    QImage screenshot;
    QString pictureFormat = "PNG";
    while (i.hasNext()){
        TasTarget* commandTarget = i.next();
        QString targetId = commandTarget->id();
        QString targetType = commandTarget->type();
        TasCommand* command = commandTarget->findCommand("Screenshot");
        //are required for command completion
        if(targetId.isEmpty() || targetType.isEmpty() || !command){
            continue;
        }

        if(!command->parameter("format").isEmpty()){
            pictureFormat = command->parameter("format");
        }

        if(!isFormatSupported(pictureFormat)){
            errorMsg = "Given format " + pictureFormat + "is not supported. Supported formats are: PNG, JPEG and BMP.";
            break;
        }

        bool draw = false;
        if(command->parameter("draw") == "true"){
            draw = true;
        }

        QWidget* target = 0;
        errorMsg = "Taking screenshot failed!";
        if(targetType == TYPE_GRAPHICS_VIEW){
            //TasLogger::logger()->debug("TYPE_GRAPHICS_VIEW Target id:" + targetId);
            QGraphicsItem* item = findGraphicsItem(targetId);
            if(item){
                QGraphicsView* view = getViewForItem(item);
                if(view){
                    QPoint point = view->mapFromScene(item->scenePos());
                    QPoint windowPoint = view->mapTo(view->window(), point);
                    QRectF itemRect = item->boundingRect();
                    ItemLocationDetails locationDetails = TestabilityUtils::getItemLocationDetails(item);

                    if(draw){
                        screenshot = QPixmap::grabWidget(view->window(), locationDetails.windowPoint.x(), locationDetails.windowPoint.y(),
                                                         locationDetails.width, locationDetails.height).toImage();
                    }
                    else{
                        screenshot = QPixmap::grabWindow(view->window()->winId(), locationDetails.windowPoint.x(), locationDetails.windowPoint.y(),
                                                         locationDetails.width, locationDetails.height).toImage();
                    }

                    if (!screenshot.isNull()) {
                        screenshot.setText("tas_id", objectId(view->window()));
                    }
                }
                else{
                    errorMsg = "Could not find a GraphicsView for the GraphicsItem!";
                }
            }
            else{
                errorMsg = "Could not find the GraphicsItem!";
            }
        }
        else{
            if(targetType == TYPE_STANDARD_VIEW){
                //TasLogger::logger()->debug("TYPE_STANDARD_VIEW about to find widget Target id:" + targetId);
                target = findWidget(targetId);
            }
            else{
                //TasLogger::logger()->debug("TYPE_APPLICATION_VIEW about to find application window Target id:" + targetId);
                target = getApplicationWindow();
                //in case no window false, return the desktop
                if(!target){
                    draw = false;
                    target = qApp->desktop();
                }
            }

            if(target){

                if ( (target->isWindow() && !draw) || target->inherits("QDesktopWidget")){
                    screenshot = QPixmap::grabWindow(target->winId()).toImage();
                }

                else{
                    if(draw){
                        screenshot = QPixmap::grabWidget(target).toImage();
                    }

                    else{
                        QPoint point = target->mapToGlobal(QPoint(0,0));
                        QPoint windowPoint = target->window()->mapFromGlobal(point);
                        screenshot = QPixmap::grabWindow(target->window()->winId(), windowPoint.x(), windowPoint.y(),
                                                         target->rect().width(), target->rect().height()).toImage();
                    }
                }

                if (!screenshot.isNull()) {
                    screenshot.setText("tas_id", objectId(target));
                }
            }
            else{
                TasLogger::logger()->debug("ScreenshotService::executeService application has no visible ui!");
                errorMsg = "Application has no visible ui!";
            }
        }
        break;
    }

    if (!screenshot.isNull()){
        QByteArray bytes;
        QBuffer buffer(&bytes);
        buffer.open(QIODevice::WriteOnly);
        screenshot.save(&buffer, pictureFormat.toAscii());
        response.setData(bytes);
    }
    else{
        response.setErrorMessage(errorMsg);
    }

}

bool ScreenshotService::isFormatSupported(QString format)
{
    if( QString::compare(format, "PNG", Qt::CaseInsensitive) == 0 ||
        QString::compare(format, "JPEG", Qt::CaseInsensitive) == 0 ||
        QString::compare(format, "BMP", Qt::CaseInsensitive) == 0){
        return true;
    }
    else{
        return false;
    }
}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

// Parts of this code sourced from SnopyDogy
// https://gist.github.com/SnopyDogy/a9a22497a893ec86aa3e

#if defined (WITH_GRAPHICS)

#include <Array.hpp>
#include <image.hpp>
#include <err_cpu.hpp>
#include <cstdio>
#include <stdexcept>
#include <graphics_common.hpp>

using af::dim4;

namespace cpu
{
    template<typename T>
    void copy_image(const Array<T> &in, const fg_image_handle image)
    {
        CheckGL("Before CopyArrayToPBO");
        const T *d_X = in.get();

        glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, image->src_width * image->src_height * image->window->mode * sizeof(T),
                     d_X, GL_STREAM_COPY);

        // Unlock array
        // Not implemented yet
        // X.unlock();
        CheckGL("In CopyArrayToPBO");
    }

    #define INSTANTIATE(T)  \
        template void copy_image<T>(const Array<T> &in, const fg_image_handle image);

    INSTANTIATE(float)
    INSTANTIATE(double)
    INSTANTIATE(int)
    INSTANTIATE(uint)
    INSTANTIATE(uchar)
    INSTANTIATE(char)
}

#endif  // WITH_GRAPHICS
<commit_msg>BUGFIX: Corrected PBO binding for image cpu<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

// Parts of this code sourced from SnopyDogy
// https://gist.github.com/SnopyDogy/a9a22497a893ec86aa3e

#if defined (WITH_GRAPHICS)

#include <Array.hpp>
#include <image.hpp>
#include <err_cpu.hpp>
#include <cstdio>
#include <stdexcept>
#include <graphics_common.hpp>

using af::dim4;

namespace cpu
{
    template<typename T>
    void copy_image(const Array<T> &in, const fg_image_handle image)
    {
        CheckGL("Before CopyArrayToPBO");
        const T *d_X = in.get();
        size_t data_size = image->src_width * image->src_height * image->window->mode * sizeof(T);

        glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, image->gl_PBO);
        glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, data_size, d_X);

        CheckGL("In CopyArrayToPBO");
    }

    #define INSTANTIATE(T)  \
        template void copy_image<T>(const Array<T> &in, const fg_image_handle image);

    INSTANTIATE(float)
    INSTANTIATE(double)
    INSTANTIATE(int)
    INSTANTIATE(uint)
    INSTANTIATE(uchar)
    INSTANTIATE(char)
}

#endif  // WITH_GRAPHICS
<|endoftext|>