- Reestructuración de ficheros y directorios general

- merge v0.01 --> Añadido fileselector
- Añadidas fuentes de Gem y Pure Data
- pix2jpg incluído en Gem. Archivos de construcción de Gem modificados.
- Añadido fichero ompiling.txt con instrucciones de compilación
This commit is contained in:
Santi Noreña 2013-02-04 18:00:17 +01:00
parent c9adfd020b
commit e85d191b46
3100 changed files with 775434 additions and 3073 deletions

229
Gem/src/Base/CPPExtern.cpp Normal file
View file

@ -0,0 +1,229 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mark@danks.org
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "CPPExtern.h"
#include "RTE/RTE.h"
#ifdef _WIN32
# include <io.h>
#else
# include <unistd.h>
#endif
#ifdef _MSC_VER /* This is only for Microsoft's compiler, not cygwin, e.g. */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# define close _close
#endif
#include <stdio.h>
#include <stdarg.h>
void *Obj_header::operator new(size_t, void *location, void *) {
return(location);
}
t_object * CPPExtern::m_holder=NULL;
char* CPPExtern::m_holdname=NULL;
/////////////////////////////////////////////////////////
//
// CPPExtern
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
CPPExtern :: CPPExtern()
: x_obj(m_holder),
m_objectname(NULL),
m_canvas(NULL),
m_endpost(true)
{
m_canvas = canvas_getcurrent();
if(m_holdname) {
m_objectname=gensym(m_holdname);
} else {
m_objectname=gensym("unknown Gem object");
}
}
CPPExtern :: CPPExtern(const CPPExtern&org) :
x_obj(org.x_obj),
m_objectname(org.m_objectname),
m_canvas(org.m_canvas),
m_endpost(true)
{
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
CPPExtern :: ~CPPExtern()
{ }
void CPPExtern :: post(const char*fmt,...) const
{
char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
va_end(ap);
if(m_endpost && NULL!=m_objectname && NULL!=m_objectname->s_name && &s_ != m_objectname){
::post("[%s]: %s", m_objectname->s_name, buf);
} else {
::post("%s", buf);
}
m_endpost=true;
}
void CPPExtern :: startpost(const char*fmt,...) const
{
char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
va_end(ap);
if(m_endpost && NULL!=m_objectname && NULL!=m_objectname->s_name && &s_ != m_objectname){
::startpost("[%s]: %s", m_objectname->s_name, buf);
} else {
::startpost("%s", buf);
}
m_endpost=false;
}
void CPPExtern :: endpost(void) const
{
::endpost();
m_endpost=true;
}
typedef void (*verbose_t)(int level, const char *fmt, ...);
void CPPExtern :: verbose(const int level, const char*fmt,...) const
{
char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
va_end(ap);
static verbose_t rte_verbose=NULL;
static bool rte_verbose_checked=false;
if(false==rte_verbose_checked) {
gem::RTE::RTE*rte=gem::RTE::RTE::getRuntimeEnvironment();
if(rte) {
rte_verbose=(verbose_t)rte->getFunction("verbose");
}
}
rte_verbose_checked=true;
/* only pd>=0.39(?) supports ::verbose() */
if(rte_verbose) {
if(NULL!=m_objectname && NULL!=m_objectname->s_name && &s_ != m_objectname){
rte_verbose(level, "[%s]: %s", m_objectname->s_name, buf);
} else {
rte_verbose(level, "%s", buf);
}
} else {
if(NULL!=m_objectname && NULL!=m_objectname->s_name && &s_ != m_objectname){
::post("[%s]: %s", m_objectname->s_name, buf);
} else {
::post("%s", buf);
}
}
}
void CPPExtern :: error(const char*fmt,...) const
{
char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
va_end(ap);
if(NULL!=m_objectname && NULL!=m_objectname->s_name && &s_ != m_objectname){
char*objname=m_objectname->s_name;
if(x_obj)
pd_error(x_obj, "[%s]: %s", objname, buf);
else if (m_holder)
pd_error(m_holder, "[%s]: %s", objname, buf);
else
::error("[%s]: %s", objname, buf);
} else {
if(x_obj)
pd_error(x_obj, "%s", buf);
else if (m_holder)
pd_error(m_holder, "%s", buf);
else
::error("%s", buf);
}
}
typedef int (*close_t)(int fd);
std::string CPPExtern::findFile(const std::string f, const std::string e) const {
char buf[MAXPDSTRING], buf2[MAXPDSTRING];
char*bufptr=0;
std::string result="";
int fd=-1;
t_canvas*canvas=const_cast<t_canvas*>(getCanvas());
char*filename=const_cast<char*>(f.c_str());
char*ext=const_cast<char*>(e.c_str());
if ((fd=open_via_path(canvas_getdir(canvas)->s_name, filename, ext,
buf2, &bufptr, MAXPDSTRING, 1))>=0){
static close_t rte_close=NULL;
if(NULL==rte_close) {
gem::RTE::RTE*rte=gem::RTE::RTE::getRuntimeEnvironment();
if(rte) {
rte_close=(close_t)rte->getFunction("sys_close");
}
if(NULL==rte_close) {
rte_close=close;
}
}
rte_close(fd);
result=buf2;
result+="/";
result+=bufptr;
} else {
canvas_makefilename(canvas, filename, buf, MAXPDSTRING);
result=buf;
}
return result;
}
std::string CPPExtern::findFile(const std::string file) const {
return findFile(file, "");
}
bool CPPExtern :: checkGemVersion(const int major, const int minor) {
if(!GemVersion::versionCheck(major, minor)) {
::error("GEM version mismatch: compiled for %d.%d but we are running %s",
major, minor,
GemVersion::versionString());
return false;
}
return true;
}
CPPExtern&CPPExtern::operator=(const CPPExtern&org) {
x_obj=org.x_obj;
m_objectname=org.m_objectname;
m_canvas=org.m_canvas;
m_endpost=true;
return *this;
}

371
Gem/src/Base/CPPExtern.h Normal file
View file

@ -0,0 +1,371 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The base class for all externs written in C++
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_CPPEXTERN_H_
#define _INCLUDE__GEM_BASE_CPPEXTERN_H_
#include "Gem/ExportDef.h"
#include "Gem/RTE.h"
#include "Gem/Version.h"
#include <new>
#include <string>
class CPPExtern;
/* forward declaration of a generic exception handler for GemExceptions */
namespace gem {
GEM_EXTERN void catchGemException(const char*objname, const t_object*obj);
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
Obj_header
The obligatory object header
DESCRIPTION
This is in a separate struct to assure that when PD uses the
class, the t_object is the very first thing. If it were the
first thing in CPPExtern, then there could be problems with
the vtable.
-----------------------------------------------------------------*/
struct GEM_EXTERN Obj_header
{
//////////
// The obligatory object header
t_object pd_obj;
//////////
// Our data structure
CPPExtern *data;
// This has a dummy arg so that NT won't complain
void *operator new(size_t, void *location, void *dummy);
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
CPPExtern
The base class for all externs written in C++
DESCRIPTION
Each extern which is written in C++ needs to use the #defines at the
end of this header file. Currently, the operator new(size_t) and
operator delete(void *) are not overridden. This will be a problem
when PD expects everything to fit in its memory space and control
all memory allocation.
The define
CPPEXTERN_HEADER(NEW_CLASS, PARENT_CLASS);
should be somewhere in your header file.
One of the defines like
CPPEXTERN_NEW(NEW_CLASS);
CPPEXTERN_NEW_WITH_TWO_ARGS(NEW_CLASS, t_floatarg, A_FLOAT, t_floatarg, A_FLOAT);
should be the first thing in your implementation file.
NEW_CLASS is the name of your class and PARENT_CLASS is the
parent of your class.
-----------------------------------------------------------------*/
class GEM_EXTERN CPPExtern
{
public:
//////////
// Constructor
CPPExtern(void);
//////////
// The Pd header
t_object *x_obj;
//////////
// Destructor
virtual ~CPPExtern(void) = 0;
//////////
// Get the object's canvas
const t_canvas *getCanvas(void) const { return(m_canvas); }
//////////
// This is a holder - don't touch it
static t_object *m_holder;
//////////
// my name
static char *m_holdname;
t_symbol *m_objectname;
protected:
//////////
// Creation callback
static void real_obj_setupCallback(t_class *) {}
private:
//////////
// The canvas that the object is in
t_canvas *m_canvas;
public:
// these call pd's print-functions, and eventually prepend the object's name
void startpost(const char*format, ...) const;
void post(const char*format, ...) const;
void endpost(void) const;
void verbose(const int level, const char*format, ...) const;
void error(const char*format, ...) const; /* internally uses pd_error() */
// searches for a file based on the parent abstraction's path
// wraps open_via_path() and canvas_makefilename()
// the full filename is returned
// if the file does not exist, it is constructed
std::string findFile(const std::string filename, const std::string ext) const;
std::string findFile(const std::string filename) const;
private:
mutable bool m_endpost; /* internal state for startpost/post/endpost */
static bool checkGemVersion(const int major, const int minor);
CPPExtern(const CPPExtern&);
virtual CPPExtern&operator=(const CPPExtern&);
};
////////////////////////////////////////
// This should be used in the header
////////////////////////////////////////
#define CPPEXTERN_HEADER(NEW_CLASS, PARENT_CLASS) \
public: \
static void obj_freeCallback(void *data) \
{ CPPExtern *mydata = ((Obj_header *)data)->data; delete mydata; \
((Obj_header *)data)->Obj_header::~Obj_header(); } \
static void real_obj_setupCallback(t_class *classPtr) \
{ PARENT_CLASS::real_obj_setupCallback(classPtr); \
NEW_CLASS::obj_setupCallback(classPtr); } \
private: \
static inline NEW_CLASS *GetMyClass(void *data) {return((NEW_CLASS *)((Obj_header *)data)->data);} \
static void obj_setupCallback(t_class *classPtr);
////////////////////////////////////////
// This should be the first thing in the implementation file
////////////////////////////////////////
//
// NO ARGUMENTS
/////////////////////////////////////////////////
#define CPPEXTERN_NEW(NEW_CLASS) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (void) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
REAL_NEW__SETUP2(NEW_CLASS)
//
// ONE ARGUMENT
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_ONE_ARG(NEW_CLASS, TYPE, PD_TYPE) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (TYPE arg) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(arg); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
PD_TYPE, \
REAL_NEW__SETUP2(NEW_CLASS)
//
// GIMME ARGUMENT
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_GIMME(NEW_CLASS) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (t_symbol*s, int argc, t_atom*argv) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(argc,argv); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
A_GIMME, \
REAL_NEW__SETUP2(NEW_CLASS)
//
// TWO ARGUMENTS
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_TWO_ARGS(NEW_CLASS, TYPE, PD_TYPE, TTWO, PD_TWO) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (TYPE arg, TTWO arg2) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(arg, arg2); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
PD_TYPE, PD_TWO, \
REAL_NEW__SETUP2(NEW_CLASS)
//
// THREE ARGUMENTS
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_THREE_ARGS(NEW_CLASS, TYPE, PD_TYPE, TTWO, PD_TWO, TTHREE, PD_THREE) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (TYPE arg, TTWO arg2, TTHREE arg3) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(arg, arg2, arg3); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
PD_TYPE, PD_TWO, PD_THREE, \
REAL_NEW__SETUP2(NEW_CLASS)
//
// FOUR ARGUMENTS
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_FOUR_ARGS(NEW_CLASS, TYPE, PD_TYPE, TTWO, PD_TWO, TTHREE, PD_THREE, TFOUR, PD_FOUR) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (TYPE arg, TTWO arg2, TTHREE arg3, TFOUR arg4) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(arg, arg2, arg3, arg4); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
PD_TYPE, PD_TWO, PD_THREE, PD_FOUR, \
REAL_NEW__SETUP2(NEW_CLASS)
//
// FIVE ARGUMENTS
/////////////////////////////////////////////////
#define CPPEXTERN_NEW_WITH_FIVE_ARGS(NEW_CLASS, TYPE, PD_TYPE, TTWO, PD_TWO, TTHREE, PD_THREE, TFOUR, PD_FOUR, TFIVE, PD_FIVE) \
REAL_NEW__CLASS(NEW_CLASS); \
static void* create_ ## NEW_CLASS (TYPE arg, TTWO arg2, TTHREE arg3, TFOUR arg4, TFIVE arg5) \
REAL_NEW__CREATE1(NEW_CLASS) \
obj->data = new NEW_CLASS(arg, arg2, arg3, arg4, arg5); \
REAL_NEW__CREATE2(NEW_CLASS) \
REAL_NEW__SETUP1(NEW_CLASS) \
PD_TYPE, PD_TWO, PD_THREE, PD_FOUR, PD_FIVE \
REAL_NEW__SETUP2(NEW_CLASS)
//////////////////////////////////////////////////////////////////////////////
// These should never be called or used directly!!!
//
//
///////////////////////////////////////////////////////////////////////////////
#define REAL_NEW__CLASS(NEW_CLASS) STATIC_CLASS t_class * NEW_CLASS ## _class
#define REAL_NEW__CREATE1(NEW_CLASS) { \
try{ \
Obj_header *obj = new (pd_new(NEW_CLASS ## _class),(void *)NULL) Obj_header; \
CPPExtern::m_holder = &obj->pd_obj; \
CPPExtern::m_holdname=(char*)#NEW_CLASS;
#define REAL_NEW__CREATE2(NEW_CLASS) \
CPPExtern::m_holder = NULL; \
CPPExtern::m_holdname=NULL; \
return(obj); \
} catch (...) {gem::catchGemException(CPPExtern::m_holdname, CPPExtern::m_holder); return NULL;} \
}
#define REAL_NEW__SETUP1(NEW_CLASS) \
extern "C" { \
GEM_EXPORT void NEW_CLASS ## _setup(void) \
{ \
static int recalled=0; if(recalled)return; recalled=1; \
NEW_CLASS ## _class = class_new( \
gensym(#NEW_CLASS), \
(t_newmethod)create_ ## NEW_CLASS, \
(t_method)&NEW_CLASS::obj_freeCallback, \
sizeof(Obj_header), GEM_CLASSFLAGS,
#define REAL_NEW__SETUP2(NEW_CLASS) \
A_NULL); \
SET_HELPSYMBOL(NEW_CLASS); \
NEW_CLASS::real_obj_setupCallback(NEW_CLASS ## _class); \
} \
} \
AUTO_REGISTER_CLASS(NEW_CLASS);
///////////////////////////////////////////////////////////////////////////////
// static class:
// by default classes are declared static
// however, sometimes we need classes not-static, so we can refer to them
// from other classes
///////////////////////////////////////////////////////////////////////////////
#ifdef NO_STATIC_CLASS
# define STATIC_CLASS
#else
# define STATIC_CLASS static
#endif
///////////////////////////////////////////////////////////////////////////////
// auto registering a class
// this creates a dummy class, whose constructor calls the setup-function
// (registering the class with pd)
// a static copy of this class is created at runtime, to actually do the setup-call
///////////////////////////////////////////////////////////////////////////////
#ifdef NO_AUTO_REGISTER_CLASS
// if NO_AUTO_REGISTER_CLASS is defined, we will not register the class
# define AUTO_REGISTER_CLASS(NEW_CLASS) \
static int NEW_CLASS ## _dummyinstance
#else
// for debugging we can show the which classes are auto-registering
# if 0
# define POST_AUTOREGISTER(NEW_CLASS) post("auto-registering: "#NEW_CLASS)
# else
# define POST_AUTOREGISTER(NEW_CLASS)
# endif
# define AUTO_REGISTER_CLASS(NEW_CLASS) \
class NEW_CLASS ## _cppclass { \
public: \
NEW_CLASS ## _cppclass(void) {POST_AUTOREGISTER(NEW_CLASS); NEW_CLASS ## _setup(); } \
}; \
static NEW_CLASS ## _cppclass NEW_CLASS ## _instance
#endif
///////////////////////////////////////////////////////////////////////////////
// setting the help-symbol
///////////////////////////////////////////////////////////////////////////////
#if defined HELPSYMBOL_BASE || defined HELPSYMBOL
# ifndef HELPSYMBOL_BASE
# define HELPSYMBOL_BASE ""
# endif
# ifndef HELPSYMBOL
# define SET_HELPSYMBOL(NEW_CLASS) \
class_sethelpsymbol(NEW_CLASS ## _class, gensym(HELPSYMBOL_BASE #NEW_CLASS))
# else
# define SET_HELPSYMBOL(NEW_CLASS) \
class_sethelpsymbol(NEW_CLASS ## _class, gensym(HELPSYMBOL_BASE HELPSYMBOL))
# endif
#else
# define SET_HELPSYMBOL(NEW_CLASS)
#endif /* HELPSYMBOL */
///////////////////////////////////////////////////////////////////////////////
// setting the class-flags
///////////////////////////////////////////////////////////////////////////////
#ifndef GEM_CLASSFLAGS
# define GEM_CLASSFLAGS 0
#endif
// macros for boilerplate code to object messages
#include "RTE/MessageCallbacks.h"
#endif // for header file

242
Gem/src/Base/GemBase.cpp Normal file
View file

@ -0,0 +1,242 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
/*
* m_state: context dependent initialization state
*
* states:
*
* INIT: a context has just been created; initialize the object for this context
* DISABLED: the object is not useable in this context
* ENABLED: the object can run in this context; however, no context-ressources have been allocated yet (needs startRendering())
* RENDERING: startRendering() has been called and we can render this object just fine...
* MODIFIED: the object has been modified, and need to free it's context-ressources (stopRendering()) and request new ones (startRendering())
*
* state-change triggers:
* reset(): -> INIT
* setModified(): -> MODIFIED
*
* state-changers:
* isRunnable(); INIT -> ENABLED|DISABLED
* startRendering(): ENABLED->RENDERING
* stopRendering(): MODIFIED->ENABLED
*
* 0..INIT ( => isRunnable() -> (startRendering() -> RENDERING) (-> DISABLED))
* 1..RENDERING ( stopRendering() -> STOPPED)
* 2..STOPPED ( -> INIT) (startRendering() -> RENDERING)
* 3..DISABLED ( -> INIT)
*
*---
* INIT -> isRunnable() -> (DISABLED) (ENABLED)
* reset(): DISABLED -> INIT
* ENABLED -> startRendering() -> RENDERING
* setModified(): ENABLED
* STOPPING -> stopRendering() -> ENABLED
* RENDERING: render()
* isRunnable() has to be called once for each (new) context
* startRendering() has to be called for each context when new IDs are to be generated
* stopRendering() has to be called for each context to free IDs
* we need a mechanism to reset a context (e.g. because a context is destroyed and it's ID might be reused)
*/
#include "GemBase.h"
#include "Gem/Cache.h"
/////////////////////////////////////////////////////////
//
// GemBase
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemBase :: GemBase(void)
: gem_amRendering(false), m_cache(NULL), m_modified(true),
m_out1(NULL),
m_enabled(true), m_state(INIT)
{
m_out1 = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemBase :: ~GemBase(void)
{
if (gem_amRendering){
stopRendering();
gem_amRendering=false;
}
if (m_out1)
outlet_free(m_out1);
}
/////////////////////////////////////////////////////////
// gem_cacheMess
//
/////////////////////////////////////////////////////////
void GemBase :: gem_startstopMess(int state)
{
// for now, this is important, as it is the only way to call the stopRendering
#if 1
if (state && !gem_amRendering){
m_enabled = isRunnable();
if(m_enabled) {
startRendering();
m_state=RENDERING;
}
}
else if (!state && gem_amRendering){
if(m_enabled) {
stopRendering();
m_state=ENABLED;
}
}
gem_amRendering=(state!=0);
// continue sending out the cache message
t_atom ap[1];
SETFLOAT(ap, state);
outlet_anything(this->m_out1, gensym("gem_state"), 1, ap);
#else
post("gem_startstopMess(%d) called...please report this to the upstream developers", state);
#endif
}
/////////////////////////////////////////////////////////
// renderMess
//
/////////////////////////////////////////////////////////
void GemBase :: gem_renderMess(GemCache* cache, GemState*state)
{
m_cache=cache;
if(m_cache && m_cache->m_magic!=GEMCACHE_MAGIC)
m_cache=NULL;
if(INIT==m_state) {
if(isRunnable()) {
m_state=ENABLED;
} else {
m_state=DISABLED;
}
}
if(MODIFIED==m_state) {
stopRendering();
m_state=ENABLED;
}
if(ENABLED==m_state) {
startRendering();
m_state=RENDERING;
}
if(RENDERING==m_state) {
gem_amRendering=true;
if(state)render(state);
continueRender(state);
if(state)postrender(state);
}
m_modified=false;
}
void GemBase :: continueRender(GemState*state){
t_atom ap[2];
ap->a_type=A_POINTER;
ap->a_w.w_gpointer=(t_gpointer *)m_cache; // the cache ?
(ap+1)->a_type=A_POINTER;
(ap+1)->a_w.w_gpointer=(t_gpointer *)state;
outlet_anything(this->m_out1, gensym("gem_state"), 2, ap);
}
/////////////////////////////////////////////////////////
// setModified
//
/////////////////////////////////////////////////////////
void GemBase :: setModified(void)
{
if (m_cache&& (m_cache->m_magic!=GEMCACHE_MAGIC))
m_cache=NULL;
if (m_cache) m_cache->dirty = true;
m_modified=true;
switch(m_state) {
case DISABLED:
case INIT:
break;
default:
m_state=MODIFIED;
}
}
/////////////////////////////////////////////////////////
// realStopRendering
//
/////////////////////////////////////////////////////////
void GemBase :: realStopRendering(void)
{
/* no idea what this function is for; ask the user when it appears */
post("realStopRendering() called...please report this to the upstream developers");
stopRendering();
m_cache = NULL;
m_state=ENABLED;
}
/////////////////////////////////////////////////////////
// disabling the rendering of this object
//
/////////////////////////////////////////////////////////
bool GemBase :: isRunnable(void)
{
return true;
}
enum GemBase::RenderState GemBase::getState(void) {
return m_state;
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void GemBase :: obj_setupCallback(t_class *classPtr)
{
class_addmethod(classPtr, reinterpret_cast<t_method>(&GemBase::gem_MessCallback),
gensym("gem_state"), A_GIMME, A_NULL);
}
void GemBase :: gem_MessCallback(void *data, t_symbol *s, int argc, t_atom *argv)
{
if (argc==2 && argv->a_type==A_POINTER && (argv+1)->a_type==A_POINTER){
GetMyClass(data)->gem_renderMess((GemCache *)argv->a_w.w_gpointer, (GemState *)(argv+1)->a_w.w_gpointer);
#if 1
} else if (argc==1 && argv->a_type==A_FLOAT){
GetMyClass(data)->gem_startstopMess(atom_getint(argv)); // start rendering (forget this !?)
#endif
} else {
GetMyClass(data)->error("wrong arguments in GemTrigger...");
}
}

134
Gem/src/Base/GemBase.h Normal file
View file

@ -0,0 +1,134 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The base class for all of the gem objects
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger.
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMBASE_H_
#define _INCLUDE__GEM_BASE_GEMBASE_H_
#include "Gem/GemGL.h"
#include "Gem/ContextData.h"
#include "Base/CPPExtern.h"
class GemCache;
class GemState;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemBase
Base class for gem objects
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN GemBase : public CPPExtern
{
protected:
//////////
// Constructor
GemBase();
//////////
// Destructor
virtual ~GemBase();
//////////
virtual void render(GemState *state) = 0;
//////////
void continueRender(GemState *state);
//////////
// After objects below you in the chain have finished.
// You should reset all GEM/OpenGL states here.
virtual void postrender(GemState *) { ; }
//////////
// Called when rendering stops
#if 1/*(jmz) this seems to be for gem2pdp*/
virtual void stoprender() { realStopRendering(); }
#endif
//////////
// If you care about the start of rendering
virtual void startRendering() { ; }
//////////
// If you care about the stop of rendering
virtual void stopRendering() { ; }
//////////
// has rendering started ?
// deprecated, use 'getState()==RENDERING' instead
bool gem_amRendering;
//////////
// If anything in the object has changed
virtual void setModified();
//////////
// Don't mess with this unless you know what you are doing.
GemCache *m_cache;
//////////
// check whether this object has changed
bool m_modified;
//////////
// The outlet
t_outlet *m_out1;
//////////
// this gets called in the before the startRendering() routine
// if it returns TRUE, the object's startRendering(), render() and stopRendering() functions will be called
// it it returns FALSE, the object will be disabled
// when rendering is restarted, this function get's called again
// the default is to enable rendering
// this function is important if you want to disable an object because it cannot be used (e.g. missing driver support)
virtual bool isRunnable(void);
//////////
// creation callback
static void real_obj_setupCallback(t_class *classPtr)
{ CPPExtern::real_obj_setupCallback(classPtr); GemBase::obj_setupCallback(classPtr); }
private:
void realStopRendering();
void gem_startstopMess(int state);
void gem_renderMess(GemCache* state, GemState* state2);
static inline GemBase *GetMyClass(void *data) {return((GemBase *)((Obj_header *)data)->data);}
friend class gemhead;
static void obj_setupCallback(t_class *classPtr);
static void gem_MessCallback(void *, t_symbol *,int, t_atom*);
/* whether the object is internally disabled or not
* objects are to be disabled, if the system cannot make use of them, e.g. because of unsupported openGL features
*/
gem::ContextData<bool>m_enabled;
enum RenderState {INIT, ENABLED, DISABLED, RENDERING, MODIFIED};
gem::ContextData<enum RenderState>m_state;
protected:
enum RenderState getState(void);
};
#endif // for header file

205
Gem/src/Base/GemContext.cpp Normal file
View file

@ -0,0 +1,205 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemContext.h"
#include "Gem/Manager.h"
#include "Gem/Exception.h"
#include "Gem/RTE.h"
#include <stack>
#include <set>
#ifdef GEM_MULTICONTEXT
# warning multicontext rendering currently under development
#endif /* GEM_MULTICONTEXT */
static GLEWContext*s_glewcontext=NULL;
static GemGlewXContext*s_glewxcontext=NULL;
using namespace gem;
class Context::PIMPL {
public:
PIMPL(void) :
#ifdef GEM_MULTICONTEXT
context(new GLEWContext), xcontext(new GemGlewXContext),
#else
context(NULL), xcontext(NULL),
#endif
contextid(makeID())
{
/* check the stack-sizes */
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, maxStackDepth+GemMan::STACKMODELVIEW);
glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, maxStackDepth+GemMan::STACKTEXTURE);
glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, maxStackDepth+GemMan::STACKPROJECTION);
if(GLEW_ARB_imaging)
glGetIntegerv(GL_MAX_COLOR_MATRIX_STACK_DEPTH, maxStackDepth+GemMan::STACKCOLOR);
else
maxStackDepth[GemMan::STACKCOLOR]=0;
}
PIMPL(const PIMPL&p) :
#ifdef GEM_MULTICONTEXT
context(new GLEWContext(*p.context)), xcontext(new GemGlewXContext(*p.xcontext)),
#else
context(NULL), xcontext(NULL),
#endif
contextid(makeID())
{
/* check the stack-sizes */
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, maxStackDepth+GemMan::STACKMODELVIEW);
glGetIntegerv(GL_MAX_COLOR_MATRIX_STACK_DEPTH, maxStackDepth+GemMan::STACKCOLOR);
glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, maxStackDepth+GemMan::STACKTEXTURE);
glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, maxStackDepth+GemMan::STACKPROJECTION);
}
~PIMPL(void) {
freeID(contextid);
#ifdef GEM_MULTICONTEXT
if(context )delete context; context=NULL;
if(xcontext)delete xcontext; xcontext=0;
#endif
}
GLint maxStackDepth[4];
GLEWContext *context;
GemGlewXContext*xcontext;
unsigned int contextid;
// LATER: reusing IDs prevents a memleak in gem::ContextData
// LATER: reusing IDs might make us re-use invalid gem::ContextData!
static std::set<unsigned int>s_takenIDs;
static unsigned int makeID(void) // GemContext_newid
{
unsigned int id=0;
#ifdef GEM_MULTICONTEXT
while(s_takenIDs.find(id) != s_takenIDs.end())
id++;
#endif /* GEM_MULTICONTEXT */
s_takenIDs.insert(id);
return id;
}
static void freeID(unsigned int id)
{
/* LATER reuse freed ids */
/* LATER remove this ID from the s_contextid stack and related (x)context */
s_takenIDs.erase(id);
}
static unsigned int s_contextid;
static GLEWContext*s_context;
static GemGlewXContext*s_xcontext;
};
unsigned int Context::PIMPL::s_contextid=0;
GLEWContext* Context::PIMPL::s_context=NULL;
GemGlewXContext*Context::PIMPL::s_xcontext=NULL;
std::set<unsigned int> Context::PIMPL::s_takenIDs;
Context::Context(void)
: m_pimpl(new PIMPL())
{
push();
std::string errstring="";
GLenum err = glewInit();
if (GLEW_OK != err) {
if(GLEW_ERROR_GLX_VERSION_11_ONLY == err) {
errstring="failed to init GLEW (glx): continuing anyhow - please report any problems to the gem-dev mailinglist!";
} else if (GLEW_ERROR_GL_VERSION_10_ONLY) {
errstring="failed to init GLEW: your system only supports openGL-1.0";
} else {
errstring="failed to init GLEW";
}
}
post("GLEW version %s",glewGetString(GLEW_VERSION));
if(!m_pimpl) {
errstring="failed to init GemContext";
}
pop();
if(!errstring.empty()) {
if(m_pimpl)delete m_pimpl; m_pimpl=NULL;
throw(GemException(errstring));
}
GemMan::m_windowState++;
}
Context::Context(const Context&c)
: m_pimpl(new PIMPL(*(c.m_pimpl)))
{
push();
post("foo GLEW version %s",glewGetString(GLEW_VERSION));
pop();
}
Context&Context::operator=(const Context&c) {
if(&c == this || c.m_pimpl == m_pimpl)
return (*this);
if(m_pimpl)delete m_pimpl;
m_pimpl=new PIMPL(*c.m_pimpl);
push();
pop();
return(*this);
}
Context::~Context(void) {
if(m_pimpl)delete m_pimpl; m_pimpl=NULL;
GemMan::m_windowState--;
}
bool Context::push(void) {
GemMan::maxStackDepth[GemMan::STACKMODELVIEW]= m_pimpl->maxStackDepth[GemMan::STACKMODELVIEW];
GemMan::maxStackDepth[GemMan::STACKCOLOR]= m_pimpl->maxStackDepth[GemMan::STACKCOLOR];
GemMan::maxStackDepth[GemMan::STACKTEXTURE]= m_pimpl->maxStackDepth[GemMan::STACKTEXTURE];
GemMan::maxStackDepth[GemMan::STACKPROJECTION]=m_pimpl->maxStackDepth[GemMan::STACKPROJECTION];
m_pimpl->s_context=m_pimpl->context;
m_pimpl->s_xcontext=m_pimpl->xcontext;
m_pimpl->s_contextid=m_pimpl->contextid;
return true;
}
bool Context::pop(void) {
return true;
}
unsigned int Context::getContextId(void) {
return PIMPL::s_contextid;
}
/* returns the last GemWindow that called makeCurrent()
* LATER: what to do if this has been invalidated (e.g. because the context was destroyed) ?
*/
GLEWContext*Context::getGlewContext(void) {
return PIMPL::s_context;
}
GemGlewXContext*Context::getGlewXContext(void) {
return PIMPL::s_xcontext;
}
GLEWContext*glewGetContext(void) {return gem::Context::getGlewContext();}
GemGlewXContext*wglewGetContext(void){return gem::Context::getGlewXContext();}
GemGlewXContext*glxewGetContext(void){return gem::Context::getGlewXContext();}

57
Gem/src/Base/GemContext.h Normal file
View file

@ -0,0 +1,57 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
a rendering context
Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMCONTEXT_H_
#define _INCLUDE__GEM_BASE_GEMCONTEXT_H_
#include "Gem/ExportDef.h"
#include "Gem/GemGL.h"
# if defined _WIN32
typedef struct WGLEWContextStruct WGLEWContext;
# define GemGlewXContext WGLEWContext
# elif defined __linux__ || defined HAVE_GL_GLX_H
typedef struct GLXEWContextStruct GLXEWContext;
# define GemGlewXContext GLXEWContext
# else
# define GemGlewXContext void
# endif
typedef struct GLEWContextStruct GLEWContext;
namespace gem {
class GEM_EXTERN Context {
private:
class PIMPL;
PIMPL*m_pimpl;
public:
Context(void);
Context(const Context&);
virtual ~Context(void);
Context&operator=(const Context&);
// make context current
bool push(void);
// make context uncurrent
bool pop(void);
public:
static unsigned int getContextId(void);
static GLEWContext*getGlewContext(void);
static GemGlewXContext*getGlewXContext(void);
};
}; // namespace
#endif // for header file

23
Gem/src/Base/GemGLBase.h Normal file
View file

@ -0,0 +1,23 @@
/* ------------------------------------------------------------------
* GEM - Graphics Environment for Multimedia
*
* Copyright (c) 2008 zmoelnig@iem.at
* For information on usage and redistribution, and for a DISCLAIMER
* OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS"
*
* this file has been generated...
* ------------------------------------------------------------------
*/
#ifndef _INCLUDE__GEM_BASE_GEMGLBASE_H_
#define _INCLUDE__GEM_BASE_GEMGLBASE_H_
#include "Utils/GLUtil.h"
#include "Base/GemBase.h"
class GEM_EXTERN GemGLBase : public GemBase
{
};
#endif /* for header file */

View file

@ -0,0 +1,96 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemGluObj.h"
/////////////////////////////////////////////////////////
//
// GemGluObj
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemGluObj :: GemGluObj(t_floatarg size, t_floatarg slices, t_floatarg stacks)
: GemShape(size),
m_numSlices((int)slices),m_numStacks((int)stacks),
m_sliceInlet(NULL)
{
m_drawTypes.clear();
m_drawTypes["default"]=GL_DEFAULT_GEM;
m_drawTypes["line"]=GL_LINE;
m_drawTypes["fill"]=GL_FILL;
m_drawTypes["point"]=GL_POINT;
m_drawTypes["points"]=GL_POINT;
m_drawType = (GLenum) GL_FILL;
if(m_numSlices<=0)m_numSlices=10;
if(m_numStacks<=0)m_numStacks=m_numSlices;
// the number of slices
m_sliceInlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("numslices"));
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemGluObj :: ~GemGluObj()
{
// in case we are deleted while still running
inlet_free(m_sliceInlet);
}
/////////////////////////////////////////////////////////
// numSlicesMess
//
/////////////////////////////////////////////////////////
void GemGluObj :: numSlicesMess(int numSlices)
{
m_numSlices = (numSlices < 2) ? 2 : numSlices;
m_numStacks = m_numSlices;
setModified();
}
void GemGluObj :: numSlicesMess(int numSlices, int numStacks)
{
m_numSlices = (numSlices < 2) ? 2 : numSlices;
m_numStacks = (numStacks < 2) ? 2 : numStacks;
setModified();
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void GemGluObj :: obj_setupCallback(t_class *classPtr)
{
class_addmethod(classPtr, reinterpret_cast<t_method>(&GemGluObj::numSlicesMessCallback),
gensym("numslices"), A_GIMME, A_NULL);
}
void GemGluObj :: numSlicesMessCallback(void *data, t_symbol*, int argc, t_atom*argv)
{
switch(argc){
case 1:
GetMyClass(data)->numSlicesMess(atom_getint(argv));
break;
case 2:
GetMyClass(data)->numSlicesMess(atom_getint(argv), atom_getint(argv+1));
break;
default:
GetMyClass(data)->error("only 1 or 2 arguments for \"slices [stacks]\" allowed!");
}
}

92
Gem/src/Base/GemGluObj.h Normal file
View file

@ -0,0 +1,92 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
A Glu object
Copyright (c) 1997-2000 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMGLUOBJ_H_
#define _INCLUDE__GEM_BASE_GEMGLUOBJ_H_
// I hate Microsoft...I shouldn't have to do this!
#ifdef _WIN32
#include <windows.h>
#endif
#include <string.h>
#include <math.h>
#ifndef M_PI
# define M_PI (3.1415926)
#endif
#include "Base/GemShape.h"
#ifndef GLU_SILHOUETTE
# define GLU_SILHOUETTE 0
#endif
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemGluObj
A Glu object
DESCRIPTION
Inlet for an int - "in2"
"in2" - the number of slices in the object
-----------------------------------------------------------------*/
class GEM_EXTERN GemGluObj : public GemShape
{
public:
//////////
// Constructor
GemGluObj(t_floatarg size, t_floatarg slices=10.f, t_floatarg stacks=0.f);
protected:
//////////
// Destructor
virtual ~GemGluObj();
//////////
// The number of slices in the quadric
void numSlicesMess(int numSlices);
void numSlicesMess(int numSlices, int numStacks);
//////////
// The number of slices
int m_numSlices, m_numStacks;
//////////
t_inlet *m_sliceInlet;
//////////
// creation callback
static void real_obj_setupCallback(t_class *classPtr)
{ GemShape::real_obj_setupCallback(classPtr); GemGluObj::obj_setupCallback(classPtr); }
private:
static inline GemGluObj *GetMyClass(void *data) {return((GemGluObj *)((Obj_header *)data)->data);}
//////////
// Static member functions
static void obj_setupCallback(t_class *classPtr);
static void numSlicesMessCallback(void *data, t_symbol*, int, t_atom*);
};
#endif // for header file

View file

@ -0,0 +1,78 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemPathBase.h"
#include "Utils/Functions.h"
// CPPEXTERN_NEW_WITH_GIMME(GemPathBase);
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemPathBase :: GemPathBase(int argc, t_atom *argv)
: m_numDimens(1), m_array(NULL),
m_out1(NULL)
{
m_out1 = outlet_new(this->x_obj, 0);
if (argc >= 2)
openMess(atom_getsymbol(&argv[1]));
if (argc >= 1)
{
m_numDimens = (int)atom_getfloat(&argv[0]);
if (m_numDimens < 1) m_numDimens = 1;
if (m_numDimens > 64)
{
error("too many dimensions, must be below 64");
m_numDimens = 64;
}
}
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemPathBase :: ~GemPathBase()
{
outlet_free(m_out1);
}
/////////////////////////////////////////////////////////
// openMess
//
/////////////////////////////////////////////////////////
void GemPathBase :: openMess(t_symbol *arrayname)
{
m_array = (t_garray *)pd_findbyclass(arrayname, garray_class);
if (!m_array)
{
error("unable to find array %s", arrayname->s_name);
return;
}
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void GemPathBase :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG1(classPtr, "open", openMess, t_symbol*);
CPPEXTERN_MSG1(classPtr, "float", floatMess, t_float);
}

View file

@ -0,0 +1,67 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Base class for paths
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMPATHBASE_H_
#define _INCLUDE__GEM_BASE_GEMPATHBASE_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemPathBase
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN GemPathBase : public CPPExtern
{
CPPEXTERN_HEADER(GemPathBase, CPPExtern);
public:
//////////
// Constructor
GemPathBase(int argc, t_atom *argv);
protected:
//////////
// Destructor
virtual ~GemPathBase();
//////////
// When an open is received
virtual void openMess(t_symbol *arrayname);
//////////
// When a float val is received
virtual void floatMess(t_float val) = 0;
//////////
// The number of dimensions
int m_numDimens;
//////////
// The array
t_garray *m_array;
//////////
// The outlet
t_outlet *m_out1;
};
#endif // for header file

View file

@ -0,0 +1,232 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2002 James Tittle & Chris Clepper
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemPixDualObj.h"
#include "Gem/Cache.h"
#include "Gem/State.h"
#include <string.h>
#include <stdio.h>
/////////////////////////////////////////////////////////
//
// GemPixDualObj
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemPixDualObj :: GemPixDualObj()
: m_cacheRight(NULL),
m_pixRight(NULL),// was dsiabled by DH 8/5/02
m_pixRightValid(-1),
org_pixRightValid(-1),
m_inlet(NULL)
{
m_inlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("gem_state"), gensym("gem_right"));
memset(&m_pixRight, 0, sizeof(m_pixRight));
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemPixDualObj :: ~GemPixDualObj()
{
inlet_free(m_inlet);
}
/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: render(GemState *state)
{
GemPixObj::render(state);
}
/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
#define PROCESS_DUALIMAGE_SIMD(CS) \
switch(m_simd){ \
case (GEM_SIMD_MMX): \
process##CS ##_MMX(image, m_pixRight->image); \
break; \
case(GEM_SIMD_SSE2): \
process##CS ##_SSE2(image, m_pixRight->image); \
break; \
case(GEM_SIMD_ALTIVEC): \
process##CS ##_Altivec(image, m_pixRight->image); \
break; \
default: \
process##CS ##_##CS(image, m_pixRight->image); \
}
#define PROCESS_DUALIMAGE(CS1, CS2) \
process##CS1 ##_##CS2 (image, m_pixRight->image);
#define PROCESS_COLORSPACE(FUN_RGBA, FUN_YUV, FUN_GRAY) \
switch (m_pixRight->image.format) { \
case GL_RGBA: case GL_BGRA_EXT: \
found=true; FUN_RGBA; break; \
case GL_LUMINANCE: \
found=true; FUN_GRAY; break; \
case GL_YCBCR_422_GEM: \
found=true; FUN_YUV ; break; \
default:break;}
void GemPixDualObj :: processImage(imageStruct &image)
{
if (!m_cacheRight || m_cacheRight->m_magic!=GEMCACHE_MAGIC){
m_cacheRight=NULL;
return;
}
//if (!m_cacheRight || !&image || !&m_pixRight || !&m_pixRight->image) return;
if (!m_pixRightValid || !&image || !&m_pixRight || !&m_pixRight->image) return;
if (image.xsize != m_pixRight->image.xsize ||
image.ysize != m_pixRight->image.ysize) {
error("two images do not have equal dimensions (%dx%d != %dx%d)",
image.xsize, image.ysize,
m_pixRight->image.xsize, m_pixRight->image.ysize);
m_pixRightValid = 0;
return;
}
if(image.upsidedown != m_pixRight->image.upsidedown) {
image.fixUpDown();
m_pixRight->image.fixUpDown();
}
bool found = false;
switch (image.format) {
case GL_RGBA:
case GL_BGRA_EXT:
PROCESS_COLORSPACE(PROCESS_DUALIMAGE_SIMD(RGBA),
PROCESS_DUALIMAGE(RGBA, YUV),
PROCESS_DUALIMAGE(RGBA, Gray));
break;
case GL_LUMINANCE:
PROCESS_COLORSPACE(PROCESS_DUALIMAGE(Gray, RGBA),
PROCESS_DUALIMAGE(Gray, YUV),
PROCESS_DUALIMAGE_SIMD(Gray));
break;
case GL_YCBCR_422_GEM:
PROCESS_COLORSPACE(PROCESS_DUALIMAGE(YUV, RGBA),
PROCESS_DUALIMAGE_SIMD(YUV),
PROCESS_DUALIMAGE(YUV, Gray));
break;
default: break;
}
if (!found)processDualImage(image, m_pixRight->image);
}
/////////////////////////////////////////////////////////
// process
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: processDualImage(imageStruct &left, imageStruct &right){
char *lformat, *rformat;
switch (left.format) {
case GL_RGBA:
case GL_BGRA_EXT:
lformat =(char*)"RGBA";break;
case GL_LUMINANCE:
lformat =(char*)"Gray";break;
case GL_YCBCR_422_GEM:
lformat =(char*)"YUV";break;
default:
lformat = new char[6];
sprintf(lformat,"0x%04X", (unsigned int)left.format);
}
switch (right.format) {
case GL_RGBA:
case GL_BGRA_EXT:
rformat =(char*)"RGBA";break;
case GL_LUMINANCE:
rformat =(char*)"Gray";break;
case GL_YCBCR_422_GEM:
rformat =(char*)"YUV";break;
default:
rformat = new char[6];
sprintf(rformat, "0x%04X", (unsigned int)left.format);
}
error("no method to combine (%s) and (%s)", lformat, rformat);
}
/////////////////////////////////////////////////////////
// postrender
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: postrender(GemState *state)
{
if (org_pixRightValid != m_pixRightValid)setPixModified();
org_pixRightValid = m_pixRightValid;
m_pixRightValid = 0;
}
/////////////////////////////////////////////////////////
// stopRendering
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: stopRendering()
{
m_pixRightValid = 0;
}
/////////////////////////////////////////////////////////
// rightRender
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: rightRender(GemState *statePtr)
{
if (!statePtr || !statePtr->get(GemState::_PIX, m_pixRight) || !m_pixRight) {
m_pixRightValid = 0;
m_pixRight = 0;
return;
}
m_pixRightValid = 1;
if (m_pixRight->newimage)setPixModified(); // force the left arm to create a new image
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void GemPixDualObj :: obj_setupCallback(t_class *classPtr)
{
class_addmethod(classPtr, reinterpret_cast<t_method>(&GemPixDualObj::gem_rightMessCallback),
gensym("gem_right"), A_GIMME, A_NULL);
}
void GemPixDualObj :: gem_rightMessCallback(void *data, t_symbol *s, int argc, t_atom *argv)
{
if (argc==1 && argv->a_type==A_FLOAT){
} else if (argc==2 && argv->a_type==A_POINTER && (argv+1)->a_type==A_POINTER){
GetMyClass(data)->m_cacheRight = (GemCache*)argv->a_w.w_gpointer;
GetMyClass(data)->rightRender((GemState *)(argv+1)->a_w.w_gpointer);
} else GetMyClass(data)->error("wrong righthand arguments....");
}

View file

@ -0,0 +1,190 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
An object which accepts two pixes.
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
Copyright (c) 2002 James Tittle & Chris Clepper
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMPIXDUALOBJ_H_
#define _INCLUDE__GEM_BASE_GEMPIXDUALOBJ_H_
#define NEW_DUAL_PIX
#include "Base/GemPixObj.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemPixDualObj
An object which accepts two pixes.
DESCRIPTION
Inlet for a gem - "gem_right"
"gem_right" - The second gem list
-----------------------------------------------------------------*/
class GEM_EXTERN GemPixDualObj : public GemPixObj
{
public:
//////////
// Constructor
GemPixDualObj();
protected:
//////////
// Destructor
virtual ~GemPixDualObj();
void render(GemState *state);
//////////
// Derived classes should NOT override this!
// This makes sure that the images are the same size.
// This calls the other process functions based on the input images.
virtual void processImage(imageStruct &image);
#ifndef NEW_DUAL_PIX
//////////
// The derived class HAS override this.
// This is called whenever a new image comes through and
// both of the image structs are RGBA
virtual void processDualImage(imageStruct &image, imageStruct &right) = 0;
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and both
// of the image structs are gray8.
// The default behavior is to output an error.
virtual void processDualGray(imageStruct &image, imageStruct &right);
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and
// the left image is an RGBA while the right is a gray8.
// The default behavior is to output an error.
virtual void processRightGray(imageStruct &image, imageStruct &right);
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and
// the left image is a gray8, the right is an RGBA
// The default behavior is to output an error.
virtual void processLeftGray(imageStruct &image, imageStruct &right);
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and both
// of the image structs are YUV.
// The default behavior is to output an error.
virtual void processDualYUV(imageStruct &image, imageStruct &right);
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and
// the left image is an RGBA while the right is a YUV.
// The default behavior is to output an error.
virtual void processRightYUV(imageStruct &image, imageStruct &right);
//////////
// The derived class CAN override this.
// This is called whenever a new image comes through and
// the left image is a YUV, the right is an RGBA
// The default behavior is to output an error.
virtual void processLeftYUV(imageStruct &image, imageStruct &right);
#else
//////////
// The derived class SHOULD override this, if it provides a method for "all" formats
virtual void processDualImage(imageStruct &left, imageStruct &right);
// Here come the more specific dual-processors
// The derived class SHOULD override these as needed
/* for simplicity this is done via preprocessor defines:
* the functions defined are like :
** processRGBA_RGBA(left, right);
*/
#define PROCESS_DUALIMAGE(CS1, CS2) \
virtual void process##CS1 ##_##CS2 (imageStruct &left, imageStruct &right){processDualImage(left, right);}
PROCESS_DUALIMAGE(RGBA, RGBA);
PROCESS_DUALIMAGE(RGBA, Gray);
PROCESS_DUALIMAGE(RGBA, YUV );
PROCESS_DUALIMAGE(Gray, RGBA);
PROCESS_DUALIMAGE(Gray, Gray);
PROCESS_DUALIMAGE(Gray, YUV );
PROCESS_DUALIMAGE(YUV, RGBA);
PROCESS_DUALIMAGE(YUV, Gray);
PROCESS_DUALIMAGE(YUV, YUV );
#undef PROCESS_DUALIMAGE
/* for simplicity this is done via preprocessor defines:
* the functions defined are like :
** processRGBA_Altivec(left, right);
*/
#define PROCESS_DUALIMAGE_SIMD(CS1, CS2,_SIMD_EXT) \
virtual void process##CS1 ##_##_SIMD_EXT (imageStruct &left, imageStruct &right){ \
process##CS1 ##_##CS2 (left, right);}
PROCESS_DUALIMAGE_SIMD(RGBA, RGBA, MMX);
PROCESS_DUALIMAGE_SIMD(RGBA, MMX , SSE2);
PROCESS_DUALIMAGE_SIMD(RGBA, RGBA, Altivec);
PROCESS_DUALIMAGE_SIMD(YUV , YUV , MMX);
PROCESS_DUALIMAGE_SIMD(YUV , MMX , SSE2);
PROCESS_DUALIMAGE_SIMD(YUV , YUV , Altivec);
PROCESS_DUALIMAGE_SIMD(Gray, Gray, MMX);
PROCESS_DUALIMAGE_SIMD(Gray, MMX , SSE2);
PROCESS_DUALIMAGE_SIMD(Gray, Gray, Altivec);
#undef PROCESS_DUALIMAGE_SIMD
#endif
//////////
virtual void postrender(GemState *);
virtual void stopRendering();
virtual void rightstopRendering() { ; }
virtual void rightRender(GemState *state);
virtual void rightPostrender(GemState *) { ; }
virtual void rightStoprender() { ; }
//////////
GemCache *m_cacheRight;
//////////
pixBlock *m_pixRight;
int m_pixRightValid;
int org_pixRightValid;
//////////
t_inlet *m_inlet;
//////////
// creation callback
static void real_obj_setupCallback(t_class *classPtr)
{ GemPixObj::real_obj_setupCallback(classPtr); GemPixDualObj::obj_setupCallback(classPtr); }
private:
static inline GemPixDualObj *GetMyClass(void *data) {return((GemPixDualObj *)((Obj_header *)data)->data);}
//////////
// Static member functions
static void obj_setupCallback(t_class *classPtr);
static void gem_rightMessCallback(void *x, t_symbol *s, int argc, t_atom *argv);
};
#endif // for header file

220
Gem/src/Base/GemPixObj.cpp Normal file
View file

@ -0,0 +1,220 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemPixObj.h"
#include "Gem/Cache.h"
#include "Gem/State.h"
/////////////////////////////////////////////////////////
//
// GemPixObj
//
/////////////////////////////////////////////////////////
GemPixObj :: GemPixObj() :
cachedPixBlock(pixBlock()),
orgPixBlock(NULL), m_processOnOff(1),
m_simd(GemSIMD::getCPU())
{
cachedPixBlock.newimage=0;
cachedPixBlock.newfilm =0;
}
/////////////////////////////////////////////////////////
// setPixModified
//
/////////////////////////////////////////////////////////
void GemPixObj :: setPixModified()
{
if(m_cache && m_cache->m_magic!=GEMCACHE_MAGIC)m_cache=NULL;
if(m_cache)m_cache->resendImage = 1;
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void GemPixObj :: render(GemState *state){
// We save all information of our image, so the pix-processors can do what they want:
// change formats, sizes, databuffer, whatever
// the data is restored in the <postrender> call,
// so that the objects can rely on their (buffered) images
pixBlock*image=NULL;
if (!state || !state->get(GemState::_PIX, image))return;
if(!image ||
!&image->image) return;
cachedPixBlock.newimage=image->newimage;
if (!image->newimage) {
image = &cachedPixBlock;
} else {
orgPixBlock = image;
cachedPixBlock.newimage = image->newimage;
cachedPixBlock.newfilm = image->newfilm; //added for newfilm copy from cache cgc 6-21-03
image->image.copy2ImageStruct(&cachedPixBlock.image);
image = &cachedPixBlock;
if (m_processOnOff){
switch(image->image.format){
case GL_RGBA:
case GL_BGRA_EXT:
switch(m_simd){
case(GEM_SIMD_MMX):
processRGBAMMX(image->image);
break;
case(GEM_SIMD_SSE2):
processRGBASSE2(image->image);
break;
case(GEM_SIMD_ALTIVEC):
processRGBAAltivec(image->image);
break;
default:
processRGBAImage(image->image);
}
break;
case GL_RGB:
case GL_BGR_EXT:
processRGBImage(image->image);
break;
case GL_LUMINANCE:
switch(m_simd){
case(GEM_SIMD_MMX):
processGrayMMX(image->image);
break;
case(GEM_SIMD_SSE2):
processGraySSE2(image->image);
break;
case(GEM_SIMD_ALTIVEC):
processGrayAltivec(image->image);
break;
default:
processGrayImage(image->image);
}
break;
case GL_YCBCR_422_GEM:
switch(m_simd){
case(GEM_SIMD_MMX):
processYUVMMX(image->image);
break;
case(GEM_SIMD_SSE2):
processYUVSSE2(image->image);
break;
case(GEM_SIMD_ALTIVEC):
processYUVAltivec(image->image);
break;
default:
processYUVImage(image->image);
}
break;
default:
processImage(image->image);
}
}
}
state->set(GemState::_PIX, image);
}
//////////
// get the original state back
void GemPixObj :: postrender(GemState *state){
state->set(GemState::_PIX, orgPixBlock);
}
/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
void GemPixObj :: processImage(imageStruct &image)
{
switch (image.format) {
case GL_RGBA:
case GL_BGRA_EXT:
error("cannot handle RGBA image");
break;
case GL_RGB:
case GL_BGR_EXT:
error("cannot handle RGB image");
break;
case GL_LUMINANCE:
error("cannot handle Grey image");
break;
case GL_YCBCR_422_GEM:
error("cannot handle YUV image");
break;
default:
error("cannot handle this format (%x) !", image.format);
}
}
/////////////////////////////////////////////////////////
// processImage (typed)
//
/////////////////////////////////////////////////////////
void GemPixObj :: processRGBAImage(imageStruct &image)
{ processImage(image); }
void GemPixObj :: processRGBImage(imageStruct &image)
{ processImage(image); }
void GemPixObj :: processGrayImage(imageStruct &image)
{ processImage(image); }
void GemPixObj :: processYUVImage(imageStruct &image)
{ processImage(image); }
/////////////////////////////////////////////////////////
// processImage - SIMD (typed)
//
/////////////////////////////////////////////////////////
void GemPixObj :: processRGBAMMX (imageStruct &image)
{ processRGBAImage(image); }
void GemPixObj :: processGrayMMX (imageStruct &image)
{ processGrayImage(image); }
void GemPixObj :: processYUVMMX (imageStruct &image)
{ processYUVImage(image); }
void GemPixObj :: processRGBASSE2 (imageStruct &image)
{ processRGBAMMX(image); }
void GemPixObj :: processGraySSE2 (imageStruct &image)
{ processGrayMMX(image); }
void GemPixObj :: processYUVSSE2 (imageStruct &image)
{ processYUVMMX(image); }
void GemPixObj :: processRGBAAltivec(imageStruct &image)
{ processRGBAImage(image); }
void GemPixObj :: processGrayAltivec(imageStruct &image)
{ processGrayImage(image); }
void GemPixObj :: processYUVAltivec (imageStruct &image)
{ processYUVImage(image); }
/////////////////////////////////////////////////////////
// processOnOff
//
/////////////////////////////////////////////////////////
void GemPixObj :: processOnOff(int on)
{
m_processOnOff = on;
setPixModified();
}
/////////////////////////////////////////////////////////
// static member functions
//
/////////////////////////////////////////////////////////
void GemPixObj :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG1(classPtr, "float", processOnOff, int);
CPPEXTERN_MSG1(classPtr, "simd" , SIMD , int);
}
void GemPixObj :: SIMD(int n)
{
m_simd=GemSIMD::requestCPU(n);
}

143
Gem/src/Base/GemPixObj.h Normal file
View file

@ -0,0 +1,143 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Base class for pix class gem objects
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMPIXOBJ_H_
#define _INCLUDE__GEM_BASE_GEMPIXOBJ_H_
#include "Base/GemBase.h"
#include "Gem/Image.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemPixObj
Base class for pix class gem objects
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN GemPixObj : public GemBase
{
public:
//////////
// Constructor
GemPixObj();
protected:
//////////
// Destructor
virtual ~GemPixObj() { }
//////////
// The derived class should override this if it provides
// processing independent of the image.format
// This is called whenever a new image comes through.
// The default is to output an error
virtual void processImage(imageStruct &image);
//////////
// The derived class should override this.
// This is called whenever a new RGB image comes through.
// The default is to call processImage().
virtual void processRGBImage(imageStruct &image);
//////////
// The derived class should override this.
// This is called whenever a new RGBA image comes through.
// The default is to call processImage().
virtual void processRGBAImage(imageStruct &image);
// SIMD-optimized functions: by default the non-optimized function is called
virtual void processRGBAMMX(imageStruct &image);
virtual void processRGBASSE2(imageStruct &image);
virtual void processRGBAAltivec(imageStruct &image);
//////////
// The derived class should override this.
// This is called whenever a new gray8 image comes through.
// The default is to call processImage().
virtual void processGrayImage(imageStruct &image);
// SIMD-optimized functions: by default the non-optimized function is called
virtual void processGrayMMX(imageStruct &image);
virtual void processGraySSE2(imageStruct &image);
virtual void processGrayAltivec(imageStruct &image);
//////////
// The derived class should override this.
// This is called whenever a new YUV422 image comes through.
// The default is to call processImage().
virtual void processYUVImage(imageStruct &image);
// SIMD-optimized functions: by default the non-optimized function is called
virtual void processYUVMMX(imageStruct &image);
virtual void processYUVSSE2(imageStruct &image);
virtual void processYUVAltivec(imageStruct &image);
//////////
// If the derived class needs the image resent.
// This sets the dirty bit on the pixBlock.
void setPixModified();
//////////
// Turn on/off processing
void processOnOff(int on);
//////////
// the pixBlock-cache
pixBlock cachedPixBlock;
pixBlock *orgPixBlock;
//////////
int m_processOnOff;
int m_simd;
//////////
// creation callback
static void real_obj_setupCallback(t_class *classPtr) {
GemBase::real_obj_setupCallback(classPtr);
GemPixObj::obj_setupCallback(classPtr);
}
//////////
// The derived class should NOT override this unless they have some
// very special behavior.
// Do the rendering, which calls processImage or processGrayImage, etc...
// save the image-information
virtual void render(GemState *state);
// turn the pointer back to the old data after rendering
virtual void postrender(GemState *state);
void startRendering(void) {
//post("start rendering");
setPixModified();
}
private:
static inline GemPixObj *GetMyClass(void *data) {return((GemPixObj *)((Obj_header *)data)->data);}
//////////
// static member functions
static void obj_setupCallback(t_class *classPtr);
protected:
virtual void SIMD(int);
};
#endif // for header file

261
Gem/src/Base/GemShape.cpp Normal file
View file

@ -0,0 +1,261 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemShape.h"
#include "Gem/State.h"
#include <algorithm>
/////////////////////////////////////////////////////////
//
// a generic GemShape
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
namespace {
static char mytolower(char in){
if(in<='Z' && in>='A')
return in-('Z'-'z');
return in;
}
static void initialize_drawtypes(std::map<std::string, GLenum>&drawtypes) {
drawtypes["default"]=GL_DEFAULT_GEM;
drawtypes["point"]=GL_POINTS;
drawtypes["points"]=GL_POINTS;
/* how about GL_LINE ?? */
drawtypes["line"]=GL_LINE_LOOP;
drawtypes["lineloop"]=GL_LINE_LOOP;
drawtypes["lines"]=GL_LINES;
drawtypes["linestrip"]=GL_LINE_STRIP;
drawtypes["tri"]=GL_TRIANGLES;
drawtypes["triangle"]=GL_TRIANGLES;
drawtypes["tristrip"]=GL_TRIANGLE_STRIP;
drawtypes["trifan"]=GL_TRIANGLE_FAN;
drawtypes["quad"]=GL_QUADS;
drawtypes["quads"]=GL_QUADS;
drawtypes["quadstrip"]=GL_QUAD_STRIP;
drawtypes["strip"]=GL_TRIANGLE_STRIP;
drawtypes["fill"]=GL_POLYGON;
}
}
GemShape :: GemShape(t_floatarg size)
: m_linewidth(1.0f), m_size((float)size), m_drawType(GL_DEFAULT_GEM), m_blend(0),
m_inlet(NULL),
m_texType(0), m_texNum(0),
m_texCoords(NULL),
m_lighting(false)
{
if (m_size == 0.f)m_size = 1.f;
// the size inlet
m_inlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_float, gensym("ft1"));
initialize_drawtypes(m_drawTypes);
}
GemShape :: GemShape()
: m_linewidth(1.0f), m_size(1.0f), m_drawType(GL_DEFAULT_GEM), m_blend(0),
m_inlet(NULL),
m_texType(0), m_texNum(0),
m_texCoords(NULL),
m_lighting(false)
{
// no size inlet
initialize_drawtypes(m_drawTypes);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemShape :: ~GemShape()
{
if(m_inlet)inlet_free(m_inlet);
}
/////////////////////////////////////////////////////////
// SetVertex
// set up the texture-coordinates
/////////////////////////////////////////////////////////
void GemShape :: SetVertex(GemState* state,float x, float y, float z, float tx, float ty,int curCoord)
{
int i;
TexCoord*texcoords=NULL;
int numCoords = 0;
int numUnits = 0;
state->get(GemState::_GL_TEX_NUMCOORDS, numCoords);
state->get(GemState::_GL_TEX_UNITS, numUnits);
if (numCoords) {
tx=state->texCoordX(curCoord);
ty=state->texCoordY(curCoord);
}
if (numUnits) {
for( i=0; i<numUnits; i++) {
glMultiTexCoord2fARB(GL_TEXTURE0+i, tx, ty);
}
} else { // no multitexturing!
glTexCoord2f(tx, ty);
}
glVertex3f( x, y, z );
}
void GemShape :: SetVertex(GemState* state,float x, float y, float z,
float s, float t, float r, float q,
int curCoord)
{
int i;
int numCoords = 0;
int numUnits = 0;
state->get(GemState::_GL_TEX_NUMCOORDS, numCoords);
state->get(GemState::_GL_TEX_UNITS, numUnits);
if (numCoords) {
s*=state->texCoordX(curCoord);
t*=state->texCoordY(curCoord);
}
if (numUnits) {
for( i=0; i<numUnits; i++)
glMultiTexCoord4fARB(GL_TEXTURE0+i, s, t, r, q);
} else { // no multitexturing!
glTexCoord4f(s, t, r, q);
}
glVertex3f( x, y, z );
}
/////////////////////////////////////////////////////////
// linewidthMess
//
/////////////////////////////////////////////////////////
void GemShape :: linewidthMess(float linewidth)
{
m_linewidth = (linewidth < 0.0f) ? 0.0f : linewidth;
setModified();
}
/////////////////////////////////////////////////////////
// sizeMess
//
/////////////////////////////////////////////////////////
void GemShape :: sizeMess(float size)
{
m_size = size;
setModified();
}
/////////////////////////////////////////////////////////
// typeMess
//
/////////////////////////////////////////////////////////
void GemShape :: typeMess(t_symbol *type)
{
if(0==m_drawTypes.size()) {
error("unable to change drawstyle");
}
std::string name=type->s_name;
std::transform(name.begin(), name.end(), name.begin(), mytolower);
std::map<std::string, GLenum>::iterator it=m_drawTypes.find(name);
if(m_drawTypes.end() == it) {
error ("unknown draw style '%s'... possible values are:", name.c_str());
it=m_drawTypes.begin();
while(m_drawTypes.end() != it) {
error("\t %s", it->first.c_str());
it++;
}
return;
}
m_drawType=it->second;
setModified();
}
/////////////////////////////////////////////////////////
// blendMess
//
/////////////////////////////////////////////////////////
void GemShape :: blendMess(float blend)
{
m_blend = (blend>0);
setModified();
}
void GemShape :: render(GemState *state)
{
if (m_drawType == GL_LINE_LOOP || m_drawType == GL_LINE_STRIP || m_drawType == GL_LINES)
glLineWidth(m_linewidth);
if (m_blend) {
glEnable(GL_POLYGON_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glHint(GL_POLYGON_SMOOTH_HINT,GL_DONT_CARE);
}
m_texType=0;
m_texNum =0;
m_texCoords=NULL;
m_lighting=false;
state->get(GemState::_GL_TEX_COORDS, m_texCoords);
state->get(GemState::_GL_TEX_TYPE, m_texType);
state->get(GemState::_GL_TEX_NUMCOORDS, m_texNum);
state->get(GemState::_GL_LIGHTING, m_lighting);
renderShape(state);
// LATER try to restore the original state
if (m_blend) {
glDisable(GL_POLYGON_SMOOTH);
glDisable(GL_BLEND);
}
if (m_drawType == GL_LINE_LOOP || m_drawType == GL_LINE_STRIP || m_drawType == GL_LINES)
glLineWidth(1.0);
}
/////////////////////////////////////////////////////////
// static member functions
//
/////////////////////////////////////////////////////////
void GemShape :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG1(classPtr, "width", linewidthMess, float);
CPPEXTERN_MSG1(classPtr, "draw", typeMess, t_symbol*);
CPPEXTERN_MSG1(classPtr, "blend", blendMess, float);
CPPEXTERN_MSG1(classPtr, "ft1", sizeMess, float);
}

141
Gem/src/Base/GemShape.h Normal file
View file

@ -0,0 +1,141 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Base class for shapes
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMSHAPE_H_
#define _INCLUDE__GEM_BASE_GEMSHAPE_H_
#include "Base/GemBase.h"
#include <map>
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemShape
Base class for shapes
DESCRIPTION
Inlet for a float - "ft1"
"ft1" - the size of the shape
"draw" - the drawing style
"width" - the line width when drawing with lines
-----------------------------------------------------------------*/
class TexCoord;
class GEM_EXTERN GemShape : public GemBase
{
public:
//////////
// Constructor
// [in] size - A size of 0. means to just use the default (ie, 1.)
GemShape(t_floatarg size);
GemShape();
protected:
//////////
// Destructor
virtual ~GemShape();
//-----------------------------------
// GROUP: Access functions
//-----------------------------------
//////////
// The width of the lines in line draw mode
void linewidthMess(float linewidth);
//////////
// The size of the object
void sizeMess(float size);
//////////
// How the object should be drawn
virtual void typeMess(t_symbol *type);
//-----------------------------------
// GROUP: Utility functions
//-----------------------------------
void SetVertex(GemState* state,float x, float y, float z,
float tx, float ty,
int curCoord);
void SetVertex(GemState* state,float x, float y, float z,
float s, float t, float r, float q,
int curCoord);
//-----------------------------------
// GROUP: Member variables
//-----------------------------------
//////////
// The line width for GL_LINE mode
GLfloat m_linewidth;
//////////
// The size of the object
GLfloat m_size;
//////////
// The drawing style (GL_LINE, GL_POLYGON, etc)
GLenum m_drawType;
//////////
// do we want blending?
GLboolean m_blend;
void blendMess(float blend);
////////
// override this memberfunction to automatically enable softblended rendering,...
virtual void renderShape(GemState *state) {;}
// OR
// override this memberfunction if you don't want softblending
virtual void render(GemState *state);
//////////
// The size inlet
t_inlet *m_inlet;
//-----------------------------------
// GROUP: Setup functions
//-----------------------------------
//////////
// creation callback
static void real_obj_setupCallback(t_class *classPtr)
{ GemBase::real_obj_setupCallback(classPtr); GemShape::obj_setupCallback(classPtr); }
private:
static inline GemShape *GetMyClass(void *data) {return((GemShape *)((Obj_header *)data)->data);}
//////////
// static member functions
static void obj_setupCallback(t_class *classPtr);
protected:
int m_texType, m_texNum;
TexCoord*m_texCoords;
bool m_lighting;
std::map<std::string, GLenum>m_drawTypes;
};
#endif // for header file

View file

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemVertex.h"
#include "Gem/Cache.h"
/////////////////////////////////////////////////////////
//
// GemVertex
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemVertex :: GemVertex()
{}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemVertex :: ~GemVertex()
{
}
/////////////////////////////////////////////////////////
// setModified
//
/////////////////////////////////////////////////////////
void GemVertex :: setModified()
{
GemBase::setModified();
if(m_cache)m_cache->vertexDirty = 1;
}

37
Gem/src/Base/GemVertex.h Normal file
View file

@ -0,0 +1,37 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
include file for VertexArrays
Copyright (c) 2004-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMVERTEX_H_
#define _INCLUDE__GEM_BASE_GEMVERTEX_H_
#include "Base/GemBase.h"
class GEM_EXTERN GemVertex : public GemBase {
protected:
//////////
// Constructor
GemVertex();
~GemVertex();
//////////
// If anything in the object has changed
// especially, if the vertex-array has changed
virtual void setModified();
};
#endif /* _INCLUDE__GEM_BASE_GEMVERTEX_H_ */

228
Gem/src/Base/GemWinCreate.h Normal file
View file

@ -0,0 +1,228 @@
/*-----------------------------------------------------------------
GEM - Graphics Environment for Multimedia
create a window
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMWINCREATE_H_
#define _INCLUDE__GEM_BASE_GEMWINCREATE_H_
#include "Gem/GemConfig.h"
#include "Gem/GemGL.h"
#if defined _WIN32
# include <windows.h>
#elif defined __APPLE__
# import <AGL/agl.h>
#elif defined __linux__ || defined HAVE_GL_GLX_H
# ifdef HAVE_LIBXXF86VM
# include <X11/extensions/xf86vmode.h>
# endif
#else
# error Define OS specific window creation
#endif
#include "Gem/ExportDef.h"
// I hate Microsoft...I shouldn't have to do this!
#ifdef _WIN32
# pragma warning( disable : 4244 )
# pragma warning( disable : 4305 )
# pragma warning( disable : 4091 )
#endif
#include <string.h>
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
WindowInfo
All of the relavent information about an OpenGL window
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN WindowInfo
{
public:
// Constructor
WindowInfo() :
fs(0),
#if defined _WIN32
win(NULL), dc(NULL), context(NULL),
#elif defined __APPLE__
pWind(NULL), context(NULL), offscreen(NULL), pixelSize(32),
pixMap(NULL), rowBytes(0), baseAddr(NULL),
#elif defined __linux__ || defined HAVE_GL_GLX_H
dpy(NULL), win(0), screen(0), cmap(0), context(NULL), delete_atom(0), have_border(false),
#else
#endif
have_constContext(0)
{}
int fs; // FullScreen
#if defined _WIN32
HWND win; // Window handle
HDC dc; // Device context handle
HGLRC context; // OpenGL context
#elif defined __APPLE__
WindowPtr pWind; // GEM window reference for gemwin
AGLContext context; // OpenGL context
GWorldPtr offscreen; // Macintosh offscreen buffer
long pixelSize; //
Rect r; //
PixMapHandle pixMap; // PixMap Handle
long rowBytes; //
void *baseAddr; //
short fontList; // Font
#elif defined __linux__ || defined HAVE_GL_GLX_H
Display *dpy; // X Display
Window win; // X Window
int screen; // X Screen
Colormap cmap; // X color map
GLXContext context; // OpenGL context
Atom delete_atom;
bool have_border;
# ifdef HAVE_LIBXXF86VM
XF86VidModeModeInfo deskMode; // originale ModeLine of the Desktop
# endif
#else
# error Define OS specific window data
#endif
int have_constContext; // 1 if we have a constant context
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
WindowHints
Hints for window creation
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN WindowHints
{
public:
//////////
// Should the window be realized
int actuallyDisplay;
//////////
// Single or double buffered
int buffer;
//////////
// The width/x of the window
int width;
//////////
// The height/y of the window
int height;
//////////
// the real width/height of the window (set by createGemWindow())
int real_w, real_h;
//////////
// The offset/x of the window (likely tobe overridden by the window-manager)
int x_offset;
//////////
// The offset/y of the window (likely tobe overridden by the window-manager)
int y_offset;
//////////
// Should we do fullscreen ?
int fullscreen;
//////////
// Is there a second screen ?
int secondscreen;
//////////
// Should there be a window border?
int border;
//////////
// mode for full-screen antialiasing
int fsaa;
///// if we can use a different display , this has its meaning under X
char* display;
//////////////
// display some title....
char* title;
//////////
// The GLXcontext to share rendering with
#if defined _WIN32
HGLRC shared;
#elif defined __APPLE__
AGLContext shared;
#elif defined __linux__ || defined HAVE_GL_GLX_H
GLXContext shared;
#else
#error Define OS specific OpenGL context
#endif
};
//////////
// Create a new window
GEM_EXTERN extern int createGemWindow(WindowInfo &info, WindowHints &hints);
//////////
// Destroy a window
GEM_EXTERN extern void destroyGemWindow(WindowInfo &info);
//////////
// Set the cursor
GEM_EXTERN extern int cursorGemWindow(WindowInfo &info, int state);
//////////
// Set the topmost position
GEM_EXTERN extern int topmostGemWindow(WindowInfo &info, int state);
//////////
// swap the buffers (get's called in double-buffered mode)
GEM_EXTERN extern void gemWinSwapBuffers(WindowInfo &nfo);
/////////
// reestablish a context
GEM_EXTERN extern void gemWinMakeCurrent(WindowInfo &nfo);
/////////
// init OS-specific stuff
GEM_EXTERN extern bool initGemWin(void);
/////////
// prepare a WindowInfo for context-sharing
GEM_EXTERN void initWin_sharedContext(WindowInfo &info, WindowHints &hints);
/////////
//
GEM_EXTERN extern void dispatchGemWindowMessages(WindowInfo &nfo);
#endif // for header file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,423 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "Gem/GemConfig.h"
#ifdef _WIN32
# include "GemWinCreate.h"
# include <stdlib.h>
# include "Gem/Event.h"
# include "Gem/GemGL.h"
#include "Gem/RTE.h"
GEM_EXTERN void gemAbortRendering();
/////////////////////////////////////////////////////////
// bSetupPixelFormat
//
/////////////////////////////////////////////////////////
BOOL bSetupPixelFormat(HDC hdc, const WindowHints &hints)
{
PIXELFORMATDESCRIPTOR pfd;
// clean out the descriptor
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
if (hints.buffer == 2)
pfd.dwFlags = pfd.dwFlags | PFD_DOUBLEBUFFER;
pfd.dwLayerMask = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cRedBits = 8;
pfd.cBlueBits = 8;
pfd.cGreenBits = 8;
pfd.cDepthBits = 16;
pfd.cAccumBits = 0;
pfd.cStencilBits = 8;
int pixelformat;
if ( (pixelformat = ChoosePixelFormat(hdc, &pfd)) == 0 )
{
post("GEM: ChoosePixelFormat failed");
return(FALSE);
}
if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE)
{
post("GEM: SetPixelFormat failed");
return(FALSE);
}
return(TRUE);
}
/////////////////////////////////////////////////////////
// MainWndProc
//
/////////////////////////////////////////////////////////
LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static RECT rcClient;
static int ctrlKeyDown = 0;
// assume that we handle the message
long lRet = 0;
switch (uMsg)
{
// mouse motion
case WM_MOUSEMOVE:
triggerMotionEvent(LOWORD(lParam), HIWORD(lParam));
break;
// left button up
case WM_LBUTTONUP:
triggerButtonEvent(0, 0, LOWORD(lParam), HIWORD(lParam));
break;
// left button down
case WM_LBUTTONDOWN:
triggerButtonEvent(0, 1, LOWORD(lParam), HIWORD(lParam));
break;
// middle button up
case WM_MBUTTONUP:
triggerButtonEvent(1, 0, LOWORD(lParam), HIWORD(lParam));
break;
// middle button down
case WM_MBUTTONDOWN:
triggerButtonEvent(1, 1, LOWORD(lParam), HIWORD(lParam));
break;
// right button up
case WM_RBUTTONUP:
triggerButtonEvent(2, 0, LOWORD(lParam), HIWORD(lParam));
break;
// right button down
case WM_RBUTTONDOWN:
triggerButtonEvent(2, 1, LOWORD(lParam), HIWORD(lParam));
break;
// keyboard action
case WM_KEYUP:
if ((int)wParam == VK_CONTROL)
ctrlKeyDown = 0;
triggerKeyboardEvent((char*)&wParam, (int)wParam, 1);
break;
// keyboard action
case WM_KEYDOWN:
if ((int)wParam == VK_CONTROL)
ctrlKeyDown = 1;
else if (ctrlKeyDown && (int)wParam == 'R')
gemAbortRendering();
else
triggerKeyboardEvent((char*)&wParam, (int)wParam, 0);
break;
// resize event
case WM_SIZE:
triggerResizeEvent(LOWORD(lParam), HIWORD(lParam));
GetClientRect(hWnd, &rcClient);
break;
// we want to override these messages
// and not do anything
case WM_DESTROY:
case WM_CLOSE:
break;
case WM_CREATE:
{
}
break;
// pass all unhandled messages to DefWindowProc
default:
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
return(lRet);
}
/////////////////////////////////////////////////////////
// createGemWindow
//
/////////////////////////////////////////////////////////
GEM_EXTERN int createGemWindow(WindowInfo &info, WindowHints &hints)
{
static int firstTime = 1;
// Register the frame class
HINSTANCE hInstance = GetModuleHandle(NULL);
if (!hInstance)
{
error("GEM: Unable to get module instance");
return(0);
}
if (firstTime)
{
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hCursor = LoadCursor(NULL, IDC_CROSS);
wndclass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "GEM";
if (!RegisterClass(&wndclass) )
{
error("GEM: Unable to register window class");
return(0);
}
firstTime = 0;
}
DWORD dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
hints.real_w = hints.width;
hints.real_h = hints.height;
int x = hints.x_offset;
int y = hints.y_offset;
bool fullscreen=(hints.fullscreen!=0);
if (fullscreen){
DEVMODE dmScreenSettings; // Device Mode
if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dmScreenSettings)){
error("GEM: couldn't get screen capabilities!");
}
int w = dmScreenSettings.dmPelsWidth;
int h = dmScreenSettings.dmPelsHeight;
x=y=0;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = hints.width; // Selected Screen Width
dmScreenSettings.dmPelsHeight = hints.height; // Selected Screen Height
dmScreenSettings.dmBitsPerPel = 32; // Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) {
dmScreenSettings.dmPelsWidth = w;
dmScreenSettings.dmPelsHeight = h;
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) {
error("GEM: couldn't switch to fullscreen");
fullscreen=false;
} else {
hints.real_h=h;
hints.real_w=w;
}
}
}
if (fullscreen){
dwExStyle = WS_EX_APPWINDOW;
style |= WS_POPUP;
} else {
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
if (hints.border)
style |= WS_OVERLAPPEDWINDOW;
else
style |= WS_POPUP;
}
info.fs = fullscreen;//hints.fullscreen;
// Since Windows uses some of the window for the border, etc,
// we have to ask how big the window should really be
RECT newSize;
newSize.left = x;
newSize.top = y;
newSize.right = hints.real_w+x;
newSize.bottom = hints.real_h+y;
AdjustWindowRectEx(&newSize, style, FALSE, dwExStyle); // no menu
if (newSize.left<0 && x>=0){
newSize.right-=newSize.left;
newSize.left=0;
}
if (newSize.top<0 && y>=0){
newSize.bottom-=newSize.top;
newSize.top=0;
}
// Create the window
info.win = CreateWindowEx (
dwExStyle,
"GEM",
hints.title,
style,
newSize.left,
newSize.top,
newSize.right - newSize.left,
newSize.bottom - newSize.top,
NULL,
NULL,
hInstance,
NULL);
if (!info.win) {
error("GEM: Unable to create window");
return(0);
}
// create the device context
info.dc = GetDC(info.win);
if (!info.dc) {
error("GEM: Unable to create device context");
destroyGemWindow(info);
return(0);
}
// set the pixel format for the window
if (!bSetupPixelFormat(info.dc, hints)) {
error("GEM: Unable to set window pixel format");
destroyGemWindow(info);
return(0);
}
// create the OpenGL context
info.context = wglCreateContext(info.dc);
if (!info.context) {
error("GEM: Unable to create OpenGL context");
destroyGemWindow(info);
return(0);
}
// do we share display lists?
if (hints.shared) wglShareLists(hints.shared, info.context);
// make the context the current rendering context
if (!wglMakeCurrent(info.dc, info.context)) {
error("GEM: Unable to make OpenGL context current");
destroyGemWindow(info);
return(0);
}
if (!hints.actuallyDisplay) return(1);
// show and update main window
if (fullscreen){
ShowWindow(info.win,SW_SHOW); // Show The Window
SetForegroundWindow(info.win); // Slightly Higher Priority
SetFocus(info.win);
} else ShowWindow(info.win, SW_SHOWNORMAL);
UpdateWindow(info.win);
return(1);
}
/////////////////////////////////////////////////////////
// destroyGemWindow
//
/////////////////////////////////////////////////////////
GEM_EXTERN void destroyGemWindow(WindowInfo &info)
{
if (info.fs) ChangeDisplaySettings(NULL,0); // Switch Back To The Desktop
if (info.win) {
if (info.dc) {
if (info.context) {
wglDeleteContext(info.context);
}
ReleaseDC(info.win, info.dc);
}
DestroyWindow(info.win);
}
info.dc = NULL;
info.win = NULL;
info.dc = NULL;
}
/////////////////////////////////////////////////////////
// switch cursor on/off
//
/////////////////////////////////////////////////////////
int cursorGemWindow(WindowInfo &info, int state)
{
static int cursor_state = 1;
state=!(!state);
if (cursor_state != state){
cursor_state=ShowCursor(state)+1;
}
return cursor_state;
}
/////////////////////////////////////////////////////////
// set topmost position on/off
//
/////////////////////////////////////////////////////////
int topmostGemWindow(WindowInfo &info, int state)
{
static int topmost_state = 0;
state=!(!state);
if (state)
SetWindowPos(info.win, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
else
SetWindowPos(info.win, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
topmost_state = state;
return topmost_state;
}
void gemWinSwapBuffers(WindowInfo&nfo)
{
SwapBuffers(nfo.dc);
}
void gemWinMakeCurrent(WindowInfo&nfo)
{
if (!nfo.dc && !nfo.context)return; // do not crash ??
wglMakeCurrent(nfo.dc, nfo.context);
}
bool initGemWin(void) {
return 1;
}
GEM_EXTERN void initWin_sharedContext(WindowInfo &info, WindowHints &hints)
{
// myHints.shared = constInfo.context;
hints.shared = NULL;
}
GEM_EXTERN void dispatchGemWindowMessages(WindowInfo &win)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif /* WIN32 */

View file

@ -0,0 +1,511 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "Gem/GemConfig.h"
#if defined __linux__ || defined HAVE_GL_GLX_H
#include "Gem/Event.h"
#include "Gem/Manager.h"
#include "GemWinCreate.h"
#include <m_pd.h>
#include <X11/cursorfont.h>
#include <stdio.h>
#include <stdlib.h>
#define EVENT_MASK \
ExposureMask|StructureNotifyMask|PointerMotionMask|ButtonMotionMask | \
ButtonReleaseMask | ButtonPressMask | KeyPressMask | KeyReleaseMask | ResizeRedirectMask | DestroyNotify
// window creation variables
static int snglBuf24[] = {GLX_RGBA,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 16,
GLX_STENCIL_SIZE, 8,
GLX_ACCUM_RED_SIZE, 8,
GLX_ACCUM_GREEN_SIZE, 8,
GLX_ACCUM_BLUE_SIZE, 8,
None};
static int snglBuf24Stereo[] = {GLX_RGBA,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 16,
GLX_STENCIL_SIZE, 8,
GLX_ACCUM_RED_SIZE, 8,
GLX_ACCUM_GREEN_SIZE, 8,
GLX_ACCUM_BLUE_SIZE, 8,
GLX_STEREO,
None};
static int dblBuf24[] = {GLX_RGBA,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
GLX_STENCIL_SIZE, 8,
GLX_ACCUM_RED_SIZE, 8,
GLX_ACCUM_GREEN_SIZE, 8,
GLX_ACCUM_BLUE_SIZE, 8,
GLX_DOUBLEBUFFER,
None};
static int dblBuf24Stereo[] = {GLX_RGBA,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
GLX_STENCIL_SIZE, 8,
GLX_ACCUM_RED_SIZE, 8,
GLX_ACCUM_GREEN_SIZE, 8,
GLX_ACCUM_BLUE_SIZE, 8,
GLX_DOUBLEBUFFER,
GLX_STEREO,
None};
static int snglBuf8[] = {GLX_RGBA,
GLX_RED_SIZE, 3,
GLX_GREEN_SIZE, 3,
GLX_BLUE_SIZE, 2,
GLX_DEPTH_SIZE, 16,
None};
static int snglBuf8Stereo[] = {GLX_RGBA,
GLX_RED_SIZE, 3,
GLX_GREEN_SIZE, 3,
GLX_BLUE_SIZE, 2,
GLX_DEPTH_SIZE, 16,
GLX_STEREO,
None};
static int dblBuf8[] = {GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 2,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 16,
GLX_DOUBLEBUFFER,
None};
static int dblBuf8Stereo[] = {GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 2,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 16,
GLX_DOUBLEBUFFER,
GLX_STEREO,
None};
static int xerr=0;
int ErrorHandler (Display *dpy, XErrorEvent *event)
{
// we don't really care about the error
// let's hope for the best
if(event)
xerr=event->error_code;
if ( event->error_code != BadWindow ) {
char buf[256];
XGetErrorText (dpy, event->error_code, buf, sizeof(buf));
error("GEM-Xwin: %s\n", buf);
} else
error("GEM-Xwin: BadWindow (%d)\n", xerr);
return (0);
}
Bool WaitForNotify(Display *, XEvent *e, char *arg)
{
return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}
int createGemWindow(WindowInfo &info, WindowHints &hints)
{
#ifdef HAVE_LIBXXF86VM
XF86VidModeModeInfo **modes;
#endif
int modeNum=4;
int bestMode=0;
int fullscreen=hints.fullscreen;
char svalue[3];
int fsaa=(int)hints.fsaa;
sprintf(svalue, "%d", fsaa);
if (fsaa!=0) setenv("__GL_FSAA_MODE", svalue, 1); // this works only for NVIDIA-cards
XSetErrorHandler (ErrorHandler);
if ( (info.dpy = XOpenDisplay(hints.display)) == NULL)
{
error("GEM: Could not open display %s",hints.display);
return(0);
}
info.screen = DefaultScreen(info.dpy);
/* this used to be in GemMan::createContext()
* and produced a number of XDisplays that were not closed
* i really think that it fits better in here;
* however, i have currently no way to test what really happens
* if the X-server has no glx extension
*/
if ( !glXQueryExtension(info.dpy, NULL, NULL) )
{
error("GEM: X server has no OpenGL GLX extension");
destroyGemWindow(info);
return 0;
}
if (fullscreen){
if (hints.display){
error("GEM: fullscreen not available on remote display");
fullscreen=0;
} else {
#ifdef HAVE_LIBXXF86VM
XF86VidModeGetAllModeLines(info.dpy, info.screen, &modeNum, &modes);
info.deskMode = *modes[0];
#else
error("GEM: no xxf86vm-support: cannot switch to fullscreen");
#endif
}
}
XVisualInfo *vi;
// the user wants double buffer
if (hints.buffer == 2) {
// try for a double-buffered on 24bit machine (try stereo first)
vi = glXChooseVisual(info.dpy, info.screen, dblBuf24Stereo);
if (vi == NULL)
vi = glXChooseVisual(info.dpy, info.screen, dblBuf24);
if (vi == NULL) {
// try for a double buffered on a 8bit machine (try stereo first)
vi = glXChooseVisual(info.dpy, info.screen, dblBuf8Stereo);
if(vi == NULL)
vi = glXChooseVisual(info.dpy, info.screen, dblBuf8);
if (vi == NULL) {
error("GEM: Unable to create double buffer window");
destroyGemWindow(info);
return(0);
}
post("GEM: Only using 8 color bits");
}
}
// the user wants single buffer
else {
// try for a single buffered on a 24bit machine (try stereo first)
vi = glXChooseVisual(info.dpy, info.screen, snglBuf24Stereo);
if (vi == NULL)
vi = glXChooseVisual(info.dpy, info.screen, snglBuf24);
if (vi == NULL) {
// try for a single buffered on a 8bit machine (try stereo first)
vi = glXChooseVisual(info.dpy, info.screen, snglBuf8Stereo);
if (vi == NULL)
vi = glXChooseVisual(info.dpy, info.screen, snglBuf8);
if (vi == NULL) {
error("GEM: Unable to create single buffer window");
destroyGemWindow(info);
return(0);
}
post("GEM: Only using 8 color bits");
}
hints.buffer = 1;
}
if (vi->c_class != TrueColor && vi->c_class != DirectColor) {
error("GEM: TrueColor visual required for this program (got %d)", vi->c_class);
destroyGemWindow(info);
return(0);
}
// create the rendering context
try {
info.context = glXCreateContext(info.dpy, vi, hints.shared, GL_TRUE);
} catch(void*e){
info.context=NULL;
}
if (info.context == NULL) {
error("GEM: Could not create rendering context");
destroyGemWindow(info);
return(0);
}
// create the X color map
info.cmap = XCreateColormap(info.dpy, RootWindow(info.dpy, vi->screen),
vi->visual, AllocNone);
if (!info.cmap) {
error("GEM: Could not create X colormap");
destroyGemWindow(info);
return(0);
}
XSetWindowAttributes swa;
swa.colormap = info.cmap;
swa.border_pixel = 0;
// event_mask creates signal that window has been created
swa.event_mask = EVENT_MASK;
hints.real_w = hints.width;
hints.real_h = hints.height;
int flags;
int x = hints.x_offset;
int y = hints.y_offset;
#ifdef HAVE_LIBXXF86VM
if (fullscreen){
/* look for mode with requested resolution */
for (int i = 0; i < modeNum; i++) {
if ((modes[i]->hdisplay == hints.width) && (modes[i]->vdisplay == hints.height)) {
bestMode = i;
}
}
XF86VidModeSwitchToMode(info.dpy, info.screen, modes[bestMode]);
XF86VidModeSetViewPort(info.dpy, info.screen, 0, 0);
hints.real_w = modes[bestMode]->hdisplay;
hints.real_h = modes[bestMode]->vdisplay;
XFree(modes);
swa.override_redirect = True;
flags=CWBorderPixel|CWColormap|CWEventMask|CWOverrideRedirect;
x=y=0;
} else
#endif
{ // !fullscren
info.have_border = hints.border;
if (hints.border){
swa.override_redirect = False;
flags=CWBorderPixel|CWColormap|CWEventMask|CWOverrideRedirect;
} else {
swa.override_redirect = True;
flags=CWBorderPixel|CWColormap|CWEventMask|CWOverrideRedirect;
}
}
info.fs = fullscreen;
info.win = XCreateWindow(info.dpy, RootWindow(info.dpy, vi->screen),
x, y, hints.real_w, hints.real_h,
0, vi->depth, InputOutput,
vi->visual, flags, &swa);
if (!info.win)
{
error("GEM: Could not create X window");
destroyGemWindow(info);
return(0);
}
XSelectInput(info.dpy, info.win, EVENT_MASK);
/* found a bit at
* http://biology.ncsa.uiuc.edu/library/SGI_bookshelves/SGI_Developer/books/OpenGL_Porting/sgi_html/apf.html
* LATER think about reacting on this event...
*/
info.delete_atom = XInternAtom(info.dpy, "WM_DELETE_WINDOW", True);
if (info.delete_atom != None)
XSetWMProtocols(info.dpy, info.win, &info.delete_atom,1);
XSetStandardProperties(info.dpy, info.win,
hints.title, "gem",
None, 0, 0, NULL);
try{
xerr=0;
glXMakeCurrent(info.dpy, info.win, info.context);
/* seems like the error-handler was called; so something did not work the way it should
* should we really prevent window-creation in this case?
* LATER re-think the entire dual-context thing
*/
if(xerr!=0) {
error("GEM: problems making glX-context current: refusing to continue");
error("GEM: try setting the environment variable GEM_SINGLE_CONTEXT=1");
destroyGemWindow(info);
return(0);
}
}catch(void*e){
error("GEM: Could not make glX-context current");
destroyGemWindow(info);
return(0);
}
if (!hints.actuallyDisplay) return(1);
XMapRaised(info.dpy, info.win);
// XMapWindow(info.dpy, info.win);
XEvent report;
XIfEvent(info.dpy, &report, WaitForNotify, (char*)info.win);
if (glXIsDirect(info.dpy, info.context))post("GEM: Direct Rendering enabled!");
return(1);
}
int cursorGemWindow(WindowInfo &info, int state)
{
if (!state) {
static char data[1] = {0};
Cursor cursor;
Pixmap blank;
XColor dummy;
blank = XCreateBitmapFromData(info.dpy, info.win,
data, 1, 1);
cursor = XCreatePixmapCursor(info.dpy, blank, blank,
&dummy, &dummy, 0, 0);
XFreePixmap(info.dpy, blank);
XDefineCursor(info.dpy, info.win,cursor);
}
else
XUndefineCursor(info.dpy, info.win);
return 0; //?
}
int topmostGemWindow(WindowInfo &info, int state){
/* we don't give a warning to not be annoying */
return 1;
}
void destroyGemWindow(WindowInfo &info)
{
/* both glXMakeCurrent() and XCloseDisplay() will crash the application
* if the handler of the display (info.dpy) is invalid, e.g. because
* somebody closed the Gem-window with xkill or by clicking on the "x" of the window
*/
if (info.dpy)
{
int err=0;
/* patch by cesare marilungo to prevent the crash "on my laptop" */
glXMakeCurrent(info.dpy, None, NULL); /* this crashes if no window is there! */
if (info.win)
err=XDestroyWindow(info.dpy, info.win);
if (info.have_constContext && info.context) {
// this crashes sometimes on my laptop:
glXDestroyContext(info.dpy, info.context);
}
if (info.cmap)
err=XFreeColormap(info.dpy, info.cmap);
#ifdef HAVE_LIBXXF86VM
if (info.fs){
XF86VidModeSwitchToMode(info.dpy, info.screen, &info.deskMode);
XF86VidModeSetViewPort(info.dpy, info.screen, 0, 0);
info.fs=0;
}
#endif
err=XCloseDisplay(info.dpy); /* this crashes if no window is there */
}
info.dpy = NULL;
info.win = 0;
info.cmap = 0;
info.context = NULL;
if(info.delete_atom)info.delete_atom=0; /* not very sophisticated destruction...*/
}
void gemWinSwapBuffers(WindowInfo&nfo)
{
glXSwapBuffers(nfo.dpy, nfo.win);
}
void gemWinMakeCurrent(WindowInfo&nfo)
{
if (!nfo.dpy && !nfo.win && !nfo.context)return; // do not crash
glXMakeCurrent(nfo.dpy, nfo.win, nfo.context);
}
bool initGemWin(void) {
/* nothing to be done here... */
return 1;
}
GEM_EXTERN void initWin_sharedContext(WindowInfo &info, WindowHints &hints)
{
// myHints.shared = constInfo.context;
hints.shared = NULL;
}
GEM_EXTERN void dispatchGemWindowMessages(WindowInfo &win)
{
XEvent event;
XButtonEvent* eb = (XButtonEvent*)&event;
XKeyEvent* kb = (XKeyEvent*)&event;
XResizeRequestEvent *res = (XResizeRequestEvent*)&event;
char keystring[2];
KeySym keysym_return;
while (XCheckWindowEvent(win.dpy,win.win,
ResizeRedirectMask |
KeyPressMask | KeyReleaseMask |
PointerMotionMask |
ButtonMotionMask |
ButtonPressMask |
ButtonReleaseMask,
&event))
{
switch (event.type)
{
case ButtonPress:
triggerButtonEvent(eb->button-1, 1, eb->x, eb->y);
break;
case ButtonRelease:
triggerButtonEvent(eb->button-1, 0, eb->x, eb->y);
break;
case MotionNotify:
triggerMotionEvent(eb->x, eb->y);
if(!win.have_border) {
int err=XSetInputFocus(win.dpy, win.win, RevertToParent, CurrentTime);
err=0;
}
break;
case KeyPress:
if (XLookupString(kb,keystring,2,&keysym_return,NULL)==0) {
//modifier key:use keysym
//triggerKeyboardEvent(XKeysymToString(keysym_return), kb->keycode, 1);
}
if ( (keysym_return & 0xff00)== 0xff00 ) {
//non alphanumeric key: use keysym
triggerKeyboardEvent(XKeysymToString(keysym_return), kb->keycode, 1);
} else {
triggerKeyboardEvent(keystring, kb->keycode, 1);
}
break;
case KeyRelease:
if (XLookupString(kb,keystring,2,&keysym_return,NULL)==0) {
//modifier key:use keysym
triggerKeyboardEvent(XKeysymToString(keysym_return), kb->keycode, 0);
}
if ( (keysym_return & 0xff00)== 0xff00 ) {
//non alphanumeric key: use keysym
triggerKeyboardEvent(XKeysymToString(keysym_return), kb->keycode, 0);
} else {
triggerKeyboardEvent(keystring, kb->keycode, 0);
}
break;
case ResizeRequest:
triggerResizeEvent(res->width, res->height);
XResizeWindow(win.dpy, win.win, res->width, res->height);
break;
default:
break;
}
}
if (XCheckTypedEvent(win.dpy, ClientMessage, &event)) {
GemMan::destroyWindowSoon();
}
}
#endif // unix

376
Gem/src/Base/GemWindow.cpp Normal file
View file

@ -0,0 +1,376 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "GemWindow.h"
#include "Gem/Manager.h"
#include "RTE/MessageCallbacks.h"
#include "Gem/Settings.h"
#include "GemContext.h"
#include "Gem/Exception.h"
class GemWindow::PIMPL {
public:
PIMPL(GemWindow*gc) : parent(gc),
mycontext(NULL),
infoOut(NULL),
dispatchClock(NULL),
dispatchTime(10.),
qClock(NULL)
{
qClock=clock_new(this, reinterpret_cast<t_method>(qCallBack));
dispatchClock=clock_new(this, reinterpret_cast<t_method>(dispatchCallBack));
}
~PIMPL(void) {
if(qClock) clock_free (qClock); qClock=NULL;
if(dispatchClock) clock_free (dispatchClock); dispatchClock=NULL;
if(infoOut)outlet_free(infoOut); infoOut=NULL;
}
GemWindow*parent;
gem::Context*mycontext;
t_outlet*infoOut;
t_clock*dispatchClock;
double dispatchTime;
void dispatch(void) {
parent->dispatch();
clock_delay(dispatchClock, dispatchTime);
}
static void dispatchCallBack(PIMPL*x) {
x->dispatch();
}
void undispatch(void) {
clock_unset(dispatchClock);
}
std::vector<std::vector<t_atom> >qQueue;
t_clock*qClock;
void queue(std::vector<t_atom>alist) {
if(alist.size()>0)
qQueue.push_back(alist);
requeue();
}
void queue(t_symbol*s,int argc, t_atom*argv) {
std::vector<t_atom>alist;
t_atom at[1];
SETSYMBOL(at, s);
alist.push_back(at[0]);
while(argc-->0) {
alist.push_back(*argv++);
}
queue(alist);
}
void sendInfo(std::vector<t_atom>alist) {
int argc=alist.size();
t_atom*ap=NULL;
t_atom*argv=NULL;
#if 0
argv=alist.data();
#else
int i=0;
ap=new t_atom[argc];
argv=ap;
for(i=0; i<argc; i++) {
argv[i]=alist[i];
}
#endif
outlet_anything(infoOut, atom_getsymbol(argv), argc-1, argv+1);
if(ap)
delete[]ap;
}
void dequeue(void) {
unsigned int i=0;
for(i=0; i<qQueue.size(); i++) {
sendInfo(qQueue[i]);
}
qQueue.clear();
}
/* qClock callback for dequeueing */
static void qCallBack(PIMPL*x) {
x->dequeue();
}
/* start the clock again */
void requeue(void) {
clock_delay(qClock, 0);
}
};
/////////////////////////////////////////////////////////
//
// GemWindow
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemWindow :: GemWindow()
: m_pimpl(new PIMPL(this)),
m_width(500), m_height(500),
m_xoffset(0), m_yoffset(0),
m_border(true), m_fullscreen(false),
m_buffer(2),
m_title("Gem"),
m_cursor(true),
m_fsaa(0),
m_context(NULL)
{
int i;
i=m_width; gem::Settings::get("window.width" , i), m_width =i;
i=m_height; gem::Settings::get("window.height", i), m_height=i;
m_pimpl->infoOut = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemWindow :: ~GemWindow()
{
if(m_pimpl) {
m_pimpl->mycontext=destroyContext(m_pimpl->mycontext);
delete m_pimpl; m_pimpl=NULL;
}
}
void GemWindow::info(std::vector<t_atom>l) {
m_pimpl->queue(l);
}
void GemWindow::info(t_symbol*s, int argc, t_atom*argv) {
m_pimpl->queue(s, argc, argv);
}
void GemWindow::info(std::string s) {
info(gensym(s.c_str()), 0, NULL);
}
void GemWindow::info(std::string s, int i) {
info(s, (t_float)i);
}
void GemWindow :: info(std::string s, t_float value)
{
t_atom atom;
SETFLOAT(&atom, value);
info(gensym(s.c_str()), 1, &atom);
}
void GemWindow :: info(std::string s, std::string value)
{
t_atom atom;
SETSYMBOL(&atom, gensym(value.c_str()));
info(gensym(s.c_str()), 1, &atom);
}
void GemWindow :: bang(void)
{
outlet_bang(m_pimpl->infoOut);
}
/* mouse movement */
void GemWindow::motion(int x, int y)
{
t_atom ap[3];
SETSYMBOL(ap+0, gensym("motion"));
SETFLOAT (ap+1, x);
SETFLOAT (ap+2, y);
info(gensym("mouse"), 3, ap);
}
/* mouse buttons */
void GemWindow::button(int id, int state)
{
t_atom ap[3];
SETSYMBOL(ap+0, gensym("button"));
SETFLOAT (ap+1, id);
SETFLOAT (ap+2, state);
info(gensym("mouse"), 3, ap);
}
/* keyboard buttons */
void GemWindow::key(std::string sid, int iid, int state) {
t_atom ap[3];
SETSYMBOL(ap+0, gensym("key"));
SETFLOAT (ap+1, iid);
SETFLOAT (ap+2, state);
info(gensym("keyboard"), 3, ap);
SETSYMBOL(ap+0, gensym("keyname"));
SETSYMBOL(ap+1, gensym(sid.c_str()));
// SETFLOAT (ap+2, state);
info(gensym("keyboard"), 3, ap);
}
void GemWindow::dimension(unsigned int w, unsigned int h) {
t_atom ap[2];
SETFLOAT (ap+0, w);
SETFLOAT (ap+1, h);
info(gensym("dimen"), 2, ap);
}
void GemWindow::position(int x, int y) {
t_atom ap[2];
SETFLOAT (ap+0, x);
SETFLOAT (ap+1, y);
info(gensym("offset"), 2, ap);
}
void GemWindow::dispatch() {
// LATER setup a clock that calls dispatch() every so often
}
gem::Context*GemWindow::createContext(void){
return new gem::Context();
}
gem::Context*GemWindow::destroyContext(gem::Context*ctx){
if(ctx)delete ctx;
ctx=NULL;
return ctx;
}
bool GemWindow::createGemWindow(void){
if(!m_context) {
try {
m_pimpl->mycontext = new gem::Context();
} catch (GemException&x) {
m_context=NULL;
error("%s", x.what());
return false;
}
m_context=m_pimpl->mycontext;
} else {
m_pimpl->mycontext = NULL;
}
m_pimpl->dispatch();
return true;
}
void GemWindow::destroyGemWindow(void){
m_pimpl->mycontext=destroyContext(m_pimpl->mycontext);
m_pimpl->undispatch();
}
bool GemWindow::pushContext(void){
if(!m_context) {
return false;
}
if(!m_context->push())
return false;
dispatch();
return true;
}
bool GemWindow::popContext(void){
return (m_context && m_context->pop());
}
void GemWindow::render(void){
if(!makeCurrent()) {
error("unable to switch to current window (do you have one?), cannot render!");
return;
}
if(!pushContext()) {
error("unable to switch to current context, cannot render!");
return;
}
bang();
if(m_buffer==2)
swapBuffers();
popContext();
}
void GemWindow:: bufferMess(int buf) {
switch(buf) {
case 1: case 2:
m_buffer=buf;
break;
default:
error("buffer can only be '1' (single) or '2' (double) buffered");
break;
}
}
void GemWindow:: fsaaMess(int value) {
m_fsaa=value;
}
void GemWindow::titleMess(std::string s) {
m_title=s;
}
void GemWindow::borderMess(bool on) {
m_border=on;
}
void GemWindow:: fullscreenMess(int on) {
m_fullscreen=on;
}
void GemWindow:: offsetMess(int x, int y) {
m_xoffset=x;
m_yoffset=y;
}
void GemWindow:: createMess(std::string) {
create();
}
void GemWindow:: destroyMess(void) {
destroy();
}
void GemWindow:: cursorMess(bool on) {
m_cursor=on;
}
void GemWindow:: printMess(void) {
// nada
}
void GemWindow :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG0(classPtr, "bang", render);
CPPEXTERN_MSG1(classPtr, "create", createMess, std::string);
CPPEXTERN_MSG0(classPtr, "destroy", destroyMess);
CPPEXTERN_MSG1(classPtr, "buffer", bufferMess, int);
CPPEXTERN_MSG1(classPtr, "FSAA", fsaaMess, int);
CPPEXTERN_MSG1(classPtr, "title", titleMess, std::string);
CPPEXTERN_MSG2(classPtr, "dimen", dimensionsMess, unsigned int, unsigned int);
CPPEXTERN_MSG2(classPtr, "offset", offsetMess, int, int);
CPPEXTERN_MSG1(classPtr, "fullscreen", fullscreenMess, int);
CPPEXTERN_MSG1(classPtr, "border", borderMess, bool);
CPPEXTERN_MSG1(classPtr, "cursor", cursorMess, bool);
// CPPEXTERN_MSG0(classPtr, "print", printMess);
}

208
Gem/src/Base/GemWindow.h Normal file
View file

@ -0,0 +1,208 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
a window class to render to
Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_GEMWINDOW_H_
#define _INCLUDE__GEM_BASE_GEMWINDOW_H_
#include "Gem/GemGL.h"
#include "Base/CPPExtern.h"
#include <vector>
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemWindow
a window
DESCRIPTION
-----------------------------------------------------------------*/
namespace gem {
class Context;
};
class GEM_EXTERN GemWindow : public CPPExtern
{
CPPEXTERN_HEADER(GemWindow, CPPExtern);
private:
class PIMPL;
PIMPL*m_pimpl;
public:
//////////
// Constructor
GemWindow(void);
//////////
// Destructor
virtual ~GemWindow(void);
public:
/* OUTPUT */
/* an outlet to propagate information to the patch... mainly callbacks from the context */
/* LATER think about detaching the output from the stack, so we can e.g. destroy a window from a mouse-callback */
void info(std::vector<t_atom>);
void info(t_symbol*s, int, t_atom*);
void info(std::string);
void info(std::string, t_float);
void info(std::string, int i);
void info(std::string, std::string);
/* tell downstream objects to render */
void bang(void);
/* mouse movement */
void motion(int x, int y);
/* mouse buttons */
void button(int id, int state);
/* keyboard buttons */
// void key(std::string id, int state);
//void key(int id, int state);
void key(std::string, int, int state);
/* window resize/move */
void dimension(unsigned int, unsigned int);
void position (int, int);
/* INPUT */
/* create a new context */
static gem::Context*createContext(void);
/* destroy a given context;
* @returns NULL
*/
static gem::Context*destroyContext(gem::Context*);
/* this MUST be called from the derived classes
* as it will eventually establish a new GemContext (if m_context is non-NULL)
* if you want to share GemContext's you MUST call
* GemWindow::createContext() yourself and set m_context to the result
*
* if <tt>false</tt> is returned, you should not continue
*/
bool createGemWindow(void);
/* create a new window
* make sure that this calls the parent's createContext() method
*/
virtual bool create(void) = 0;
/* destroy an established context+infrastructuure *
* make sure that this get's called from your destroy() implementation
*/
void destroyGemWindow();
/* create the current window
* make sure to call GemWindow::destroyGemWindow()
*/
virtual void destroy(void) = 0;
/* make the object's context (window,...) the current context
* this is virtual, so objects can add their own code
* note however, that they should also call this (parent's) function within
* typically implementations look like this:
* bool <mywindow>::makeCurrent(void) {
* // do your own stuff
*
* is <tt>false</tt> is returned, do not attempt to use it (e.g. draw into it)
*/
virtual bool makeCurrent(void) = 0;
/*
* make the GemWindow current (reset stacks), switch multiContext
*/
bool pushContext(void);
/*
* make uncurrent
*/
bool popContext (void);
/* swap back/front buffer
*/
virtual void swapBuffers(void) = 0;
/* dispatch messages from the window
* this might get called more often than the render-cycle
* it might also be called automatically as soon as the window
* is create()ed (and until the window is destroy()ed)
*/
virtual void dispatch(void);
/* render to this window
* the default implementation calls:
* if(!makeCurrent())return;
* if(!pushContext())return;
* bang();
* if(m_buffer==2)swap();
* popContext();
* but you can override this, if you want to
*/
virtual void render(void);
/* set/get the dimension of the context
* setting is done by supplying arguments to the method;
* querying is done by supplying NO arguments
* this should be kept throughout
*/
virtual void dimensionsMess(unsigned int width, unsigned int height) = 0;
// common property setters
// by default they will simply set the corresponding values (below in the protected section)
// to whatever argument is given them
// so you can use these values when creating the window
// however, if you need to take immediate action (e.g. because you can), you ought to override these functions
/* render context (pre creation) */
virtual void bufferMess(int buf);
virtual void fsaaMess(int value);
/* window decoration (pre creation) */
virtual void titleMess(std::string);
virtual void borderMess(bool on);
virtual void fullscreenMess(int on);
virtual void offsetMess(int x, int y);
/* creation/destruction */
virtual void createMess(std::string);
virtual void destroyMess(void);
/* post creation */
virtual void cursorMess(bool on);
/* print some info */
virtual void printMess(void);
protected:
unsigned int m_width, m_height;
// common properties of GemWindow's
// you can safely ignore these, if they mean nothing to you
// however, if they do mean something to you, it would be good if you used these
int m_xoffset, m_yoffset;
bool m_border;
int m_fullscreen;
unsigned int m_buffer;
std::string m_title;
bool m_cursor;
int m_fsaa;
gem::Context* m_context;
};
#endif // for header file

80
Gem/src/Base/Makefile.am Normal file
View file

@ -0,0 +1,80 @@
#####################################################################
# Gem/Base Base-classes for Pd-objectclasses
#####################################################################
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)/src @GEM_CPPFLAGS@
include ../check-sources.mk
noinst_LTLIBRARIES = libBase.la
libBase_la_CXXFLAGS =
libBase_la_LIBADD =
libBase_la_LDFLAGS =
# RTE flags
libBase_la_CXXFLAGS += @GEM_RTE_CFLAGS@ @GEM_ARCH_CXXFLAGS@
libBase_la_LIBADD += @GEM_RTE_LIBS@
libBase_la_LDFLAGS += @GEM_ARCH_LDFLAGS@
# X
libBase_la_CXXFLAGS += $(X_CFLAGS)
libBase_la_LIBADD += $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIBS)
# openGL
libBase_la_CXXFLAGS += @GLX_CFLAGS@
libBase_la_LIBADD += @GLX_LIBS@
# GLEW
libBase_la_CXXFLAGS += @GEM_LIB_GLEW_CFLAGS@
libBase_la_LIBADD += @GEM_LIB_GLEW_LIBS@
# FTGL
libBase_la_CXXFLAGS += @GEM_LIB_FTGL_CFLAGS@
libBase_la_LIBADD += @GEM_LIB_FTGL_LIBS@
libBase_la_includedir = $(includedir)/Gem/Base
libBase_la_include_HEADERS= \
CPPExtern.h \
GemBase.h \
GemGLBase.h \
GemGluObj.h \
GemPathBase.h \
GemPixObj.h \
GemPixDualObj.h \
GemShape.h \
TextBase.h
libBase_la_include_HEADERS+= \
GemWindow.h \
GemContext.h
libBase_la_SOURCES= \
CPPExtern.cpp \
CPPExtern.h \
GemBase.cpp \
GemBase.h \
GemGLBase.h \
GemContext.cpp \
GemContext.h \
GemGluObj.cpp \
GemGluObj.h \
GemPathBase.cpp \
GemPathBase.h \
GemPixDualObj.cpp \
GemPixDualObj.h \
GemPixObj.cpp \
GemPixObj.h \
GemShape.cpp \
GemShape.h \
GemVertex.cpp \
GemVertex.h \
GemWinCreate.h \
GemWinCreateMac.cpp \
GemWinCreateNT.cpp \
GemWinCreateXWin.cpp \
GemWindow.cpp \
GemWindow.h \
TextBase.cpp \
TextBase.h

View file

@ -0,0 +1,21 @@
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)
noinst_LTLIBRARIES = libBase.la
libBase_la_CXXFLAGS =
libBase_la_LIBADD =
# RTE flags
libBase_la_CXXFLAGS += @GEM_RTE_CFLAGS@
libBase_la_LIBADD += @GEM_RTE_LIBS@
# GLEW
libBase_la_CXXFLAGS += @GEM_LIB_GLEW_CFLAGS@
libBase_la_LIBADD += @GEM_LIB_GLEW_LIBS@
# FTGL
libBase_la_CXXFLAGS += @GEM_LIB_FTGL_CFLAGS@
libBase_la_LIBADD += @GEM_LIB_FTGL_LIBS@
libBase_la_SOURCES= @SOURCES@

536
Gem/src/Base/TextBase.cpp Normal file
View file

@ -0,0 +1,536 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-2000 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2005 Georg Holzmann <grh@mur.at>
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
/*
* FIXXME: check how font handling behaves with multiple contexts
*/
#include "TextBase.h"
#include "Gem/Settings.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
# include <io.h>
# define close _close
typedef unsigned __int8 uint8_t;
#else
# include <unistd.h>
#endif
#include "Utils/GemString.h"
std::string TextBase::DEFAULT_FONT = "vera.ttf";
/////////////////////////////////////////////////////////
//
// TextBase
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
#ifdef FTGL
TextBase :: TextBase(int argc, t_atom *argv)
:
m_dist(1), m_valid(0), m_fontSize(20), m_fontDepth(20), m_precision(1.f),
m_widthJus(CENTER), m_heightJus(MIDDLE), m_depthJus(HALFWAY),
m_inlet(NULL),
m_font(NULL), m_fontname(NULL)
{
// initial text
gem::Settings::get("font.face", DEFAULT_FONT);
gem::Settings::get("font.size", m_fontSize);
m_theText.push_back(L"gem");
makeLineDist();
if(argc)textMess(argc, argv);
m_inlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("ft1"));
}
void TextBase :: startRendering(void) {
if(NULL==m_font) {
if(m_fontname)
fontNameMess(m_fontname->s_name);
}
}
////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void TextBase :: renderLine(const char*line, float dist) {
float x1=0, y1=0, z1=0, x2=0, y2=0, z2=0;
#if 0
startpost("renderline: "); {
const char*c=line;
while(c) {
startpost("%c (%x)", c, c);
c++;
}
}
#endif
m_font->BBox(line, x1, y1, z1, x2, y2, z2); // FTGL
glPushMatrix();
glNormal3f(0.0, 0.0, 1.0);
justifyFont(x1, y1, z1, x2, y2, z2, dist);
m_font->Render(line);
glPopMatrix();
}
void TextBase :: renderLine(const wchar_t*line, float dist) {
float x1=0, y1=0, z1=0, x2=0, y2=0, z2=0;
m_font->BBox(line, x1, y1, z1, x2, y2, z2); // FTGL
glPushMatrix();
glNormal3f(0.0, 0.0, 1.0);
justifyFont(x1, y1, z1, x2, y2, z2, dist);
m_font->Render(line);
glPopMatrix();
}
void TextBase :: render(GemState *)
{
unsigned int i=0;
if (m_theText.empty() || !m_font)return;
// step through the lines
for(i=0; i<m_theText.size(); i++)
{
renderLine(m_theText[i].c_str(), m_lineDist[i]*m_fontSize);
}
}
////////////////////////////////////////////////////////
// setFontSize
//
////////////////////////////////////////////////////////
void TextBase :: setFontSize(float size){
m_fontSize = size;
if (!m_font)return;
if (! m_font->FaceSize(static_cast<int>(m_fontSize)) ) {
error("unable to set fontsize !");
}
setModified();
}
////////////////////////////////////////////////////////
// setPrecision
//
////////////////////////////////////////////////////////
void TextBase :: setPrecision(float prec)
{
m_precision = prec;
error("no settable precision for FTGL !");
}
////////////////////////////////////////////////////////
// fontNameMess
//
////////////////////////////////////////////////////////
void TextBase :: fontNameMess(const std::string filename){
m_valid = 0;
const char *bufptr=NULL;
int fd=-1;
if(filename.empty()){
error("no font-file specified");
return;
}
std::string fn = findFile(filename);
bufptr=fn.c_str();
/* try to open the file */
FILE*file = fopen(bufptr, "r");
if (!file) {
error("cannot find font-file '%s'", bufptr);
return;
}
fclose(file);
/* now read font */
if(m_font)delete m_font; m_font=NULL;
if (makeFont(bufptr)==NULL){
error("unable to open font '%s'", bufptr);
return;
}
m_fontname=gensym(filename.c_str());
setFontSize(m_fontSize);
m_font->Depth(m_fontDepth);
m_font->CharMap(ft_encoding_unicode);
setModified();
}
#else /* !FTGL */
TextBase :: TextBase(int argc, t_atom *argv){
static bool first_time=true;
if (first_time){
post("Gem has been compiled without FONT-support !");
first_time=false;
}
m_inlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("float"), gensym("ft1"));
}
/////////////////////////////////////////////////////////
// setFontSize
//
/////////////////////////////////////////////////////////
void TextBase :: setFontSize(float size)
{}
/////////////////////////////////////////////////////////
// setPrecision
//
/////////////////////////////////////////////////////////
void TextBase :: setPrecision(float prec)
{}
/////////////////////////////////////////////////////////
// fontNameMess
//
/////////////////////////////////////////////////////////
void TextBase :: fontNameMess(const std::string s)
{}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void TextBase :: render(GemState*)
{/* a no-op */ }
#endif /* FTGL */
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
TextBase :: ~TextBase(){
/* textbase deletion */
if(m_inlet)inlet_free(m_inlet);
}
/////////////////////////////////////////////////////////
// setJustification
//
/////////////////////////////////////////////////////////
void TextBase :: setFontSize(){
setFontSize(m_fontSize);
}
/////////////////////////////////////////////////////////
// setJustification
//
/////////////////////////////////////////////////////////
void TextBase :: setJustification(JustifyWidth wType, JustifyHeight hType, JustifyDepth dType){
m_widthJus = wType;
m_heightJus = hType;
m_depthJus = dType;
makeLineDist();
}
void TextBase :: setJustification(JustifyWidth wType, JustifyHeight hType)
{
m_widthJus = wType;
m_heightJus = hType;
makeLineDist();
}
void TextBase :: setJustification(JustifyWidth wType)
{
m_widthJus = wType;
}
void TextBase :: justifyFont(float x1, float y1, float z1,
float x2, float y2, float z2, float y_offset)
{
float width = 0.f;
float height = 0.f;
float depth = 0.f;
// Get ascender height (= height of the text)
#ifdef FTGL
float ascender = m_font->Ascender();
#else
// we don't have any ascender when not using FTGL
float ascender = m_fontSize;
#endif
if (m_widthJus == LEFT) width = x1;
else if (m_widthJus == RIGHT) width = x2-x1;
else if (m_widthJus == CENTER)width = x2 / 2.f;
else if (m_widthJus == BASEW) width = 0;
// if (m_heightJus == BOTTOM) height = y1;
// else if (m_heightJus == TOP) height = y2-y1;
// else if (m_heightJus == MIDDLE)height = y2 / 2.f;
// else if (m_heightJus == BASEH) height = 0;
if (m_heightJus == BOTTOM || m_heightJus == BASEH)
height = y_offset;
else if (m_heightJus == TOP) height = ascender + y_offset;
else if (m_heightJus == MIDDLE)height = (ascender/2.f) + y_offset;
if (m_depthJus == FRONT) depth = z1;
else if (m_depthJus == BACK) depth = z2-z1;
else if (m_depthJus == HALFWAY)depth = z2 / 2.f;
else if (m_depthJus == BASED) depth = 0;
glScalef(FONT_SCALE, FONT_SCALE, FONT_SCALE);
glTranslatef(-width, -height, -depth);
}
/////////////////////////////////////////////////////////
// textMess
//
/////////////////////////////////////////////////////////
void TextBase :: breakLine(wstring line)
{
// split the string wherever there is a '\n'
while(line.length()>0){
size_t pos=line.find('\n');
// if not found, we're done
if(wstring::npos == pos)break;
wstring lin=line.substr(0,pos);
m_theText.push_back(gem::string::getVisualLine(lin));
line=line.erase(0,pos+1);
}
// if there is still a text append it
if(line.length()) {
//m_theText.push_back(line);
m_theText.push_back(gem::string::getVisualLine(line));
}
makeLineDist();
setModified();
}
void TextBase :: textMess(int argc, t_atom *argv)
{
m_theText.clear();
if ( argc < 1 ) {return; }
wstring line = L"";
int i=0;
// convert the atom-list into 1 string
for (i = 0; i < argc; ++i)
{
string newtext;
if (A_FLOAT == argv[i].a_type) {
char str[MAXPDSTRING];
char*sp=str;
atom_string(&argv[i], str, MAXPDSTRING);
while(*sp) {
unsigned char c=*sp++;
line+=c;
}
} else {
char*sp=atom_getsymbol(&argv[i])->s_name;
try {
std::wstring ws=gem::string::toWstring(sp);
line+=ws;
} catch (int i) {
i=0;
while(*sp) {
unsigned char c=*sp++;
line+=c;
}
}
}
if(argc-1>i)line += L' ';
}
breakLine(line);
}
/////////////////////////////////////////////////////////
// line distance, the offset
// of the individual lines
/////////////////////////////////////////////////////////
void TextBase :: makeLineDist()
{
unsigned int i=0;
m_lineDist.clear();
if (m_heightJus == BOTTOM || m_heightJus == BASEH)
{
// so the offset will be a simple
// [0 1 2 3 ... n] sequence
for(i=0; i<m_theText.size(); i++)
m_lineDist.push_back(i);
return;
}
if (m_heightJus == TOP)
{
// now in the other direction:
// [-n ... -2 -1 0]
signed long j;
for(j=m_theText.size()-1; j>=0; j--){
m_lineDist.push_back(-j);
}
return;
}
// else:
// calculate the y offset of each line, so
// that the text will be centered:
/*lines y-offset calculation
1: 0 = 0- 0
2: -0.5 0.5 = [0 1] - 0.5
3: -1 0 1 = [0 1 2] - 1
4: -1.5 -0.5 0.5 1.5 = [0 1 2 3] - 1.5
5: -2 -1 0 1 2 = [0 1 2 3 4] - 2
...
*/
float diff = (m_theText.size()-1)*0.5;
for(i=0; i<m_theText.size(); i++)
m_lineDist.push_back((i-diff)*m_dist);
}
//-- moocow: modified version of "textMess" for float lists
// this can be used with moocow's pd-string external
// available at http://www.ling.uni-potsdam.de/~moocow/projects/pd/#externs
// it works like this: a string is represented as a list of ASCII-values
/////////////////////////////////////////////////////////
// stringMess
//
/////////////////////////////////////////////////////////
void TextBase :: stringMess(int argc, t_atom *argv)
{
m_theText.clear();
if ( argc < 1 ) { return; }
int i;
wstring line = L"";
for (i = 0; i < argc; i++) {
int v=atom_getint(argv+i);
/*
* i experienced crashes in FTGL with indices>65535;
* since TrueType fonts cannot hold more than 65536 entries
* we just clamp it...
* note: at least wikipedia claims that TTF can only hold 2^16 glyphs
* i have seen ttf-fonts with (seemingly) more
*/
if(v<0||v>65535) {
verbose(1, "invalid character %d: using ' ' instead", v);
v=32;
}
line += static_cast<wchar_t>(v);
}
//line += L'\0';
breakLine(line);
}
//-- /moocow
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void TextBase :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG(classPtr, "list", textMess);
CPPEXTERN_MSG(classPtr, "text", textMess);
//-- moocow
CPPEXTERN_MSG(classPtr, "string", stringMess);
//-- /moocow
CPPEXTERN_MSG1(classPtr, "font", fontNameMess, std::string);
CPPEXTERN_MSG1(classPtr, "ft1", setFontSize, float);
CPPEXTERN_MSG1(classPtr, "precision", setPrecision, float);
CPPEXTERN_MSG1(classPtr, "linedist", linedistMess, float);
class_addmethod(classPtr, reinterpret_cast<t_method>(&TextBase::justifyMessCallback),
gensym("justify"), A_GIMME, A_NULL);
}
void TextBase :: justifyMessCallback(void *data, t_symbol *s, int argc, t_atom*argv)
{
JustifyWidth wType=CENTER;
JustifyHeight hType=MIDDLE;
JustifyDepth dType=HALFWAY;
char c;
switch(argc){
case 3:
c=atom_getsymbol(argv+2)->s_name[2];
switch (c){
case 'o': case 'O': dType = FRONT; break;
case 'c': case 'C': dType = BACK; break;
case 's': case 'S': dType = BASED; break;
case 'l': case 'L': case 'n': case 'N': dType = HALFWAY; break;
default:
GetMyClass(data)->error("invalid depth justification: %s (must be: front|back|halfway|base)",
atom_getsymbol(argv+2)->s_name);
return;
}
case 2:
c=atom_getsymbol(argv+1)->s_name[2];
switch (c){
case 't': case 'T': hType = BOTTOM; break;
case 'p': case 'P': hType = TOP; break;
case 'd': case 'D': case 'n': case 'N': hType = MIDDLE; break;
case 's': case 'S': hType = BASEH; break;
default:
GetMyClass(data)->error("invalid height justification: %s (must be bottom|top|middle|base)",
atom_getsymbol(argv+1)->s_name);
return;
}
case 1:
c=atom_getsymbol(argv)->s_name[2];
switch (c){
case 'f': case 'F': wType = LEFT; break;
case 'g': case 'G': wType = RIGHT; break;
case 'n': case 'N': wType = CENTER; break;
case 's': case 'S': wType = BASEW; break;
default:
GetMyClass(data)->error("invalid width justification: %s (must be left|right|center|base)",
atom_getsymbol(argv+0)->s_name);
return;
}
break;
default:
GetMyClass(data)->error("justification most be \"width [height [depth]]\"");
return;
}
switch(argc){
case 1: GetMyClass(data)->setJustification(wType); break;
case 2: GetMyClass(data)->setJustification(wType, hType); break;
case 3: GetMyClass(data)->setJustification(wType, hType, dType); break;
}
}
void TextBase :: linedistMess(float dist)
{
m_dist = dist;
makeLineDist();
}

227
Gem/src/Base/TextBase.h Normal file
View file

@ -0,0 +1,227 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
A text
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
Copyright (c) 2005 Georg Holzmann <grh@mur.at>
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_BASE_TEXTBASE_H_
#define _INCLUDE__GEM_BASE_TEXTBASE_H_
#ifdef _WIN32
# pragma warning( disable : 4786 )
# pragma warning( disable : 4788 )
#endif
#include "Gem/GemConfig.h"
#include "Base/GemBase.h"
#include <vector>
#include <string>
#ifdef FTGL
# define FONT_SCALE 0.2/3.0
# ifdef HAVE_FTGL_FTGL_H
# include "FTGL/ftgl.h"
# else
# include "FTFont.h"
# endif
#else
# define FONT_SCALE 1.0
#endif
using std::vector;
using std::string;
using std::wstring;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
TextBase
Base class for text objects
DESCRIPTION
"ft1" - The font size
"text" - The text to draw
-----------------------------------------------------------------*/
class GEM_EXTERN TextBase : public GemBase
{
CPPEXTERN_HEADER(TextBase, GemBase);
public:
//////////
// Constructor with args
TextBase(int argc, t_atom *argv);
protected:
//////////
// Destructor
virtual ~TextBase();
//////////
// Do the rendering
virtual void render(GemState*);
//////////
// break a string according to '\n'
virtual void breakLine(wstring line);
//-- moocow
//////////
// Set the text string from an ASCII list
virtual void stringMess(int argc, t_atom *argv);
void stringMess(t_symbol*, int argc, t_atom*argv) { stringMess(argc, argv); }
//-- /moocow
//////////
// Set the text string
virtual void textMess(int argc, t_atom *argv);
void textMess(t_symbol*, int argc, t_atom*argv) { textMess(argc, argv); }
//////////
// The font to use
virtual void fontNameMess(const std::string filename);
//////////
// set line distance
virtual void linedistMess(float dist);
//////////
// Set the font size
virtual void setFontSize(float size);
virtual void setFontSize();
//////////
// Set the precision for rendering
virtual void setPrecision(float prec);
//////////
// The different types of justification
enum JustifyWidth { LEFT, RIGHT, CENTER, BASEW };
enum JustifyHeight { BOTTOM, TOP, MIDDLE, BASEH };
enum JustifyDepth { FRONT, BACK, HALFWAY, BASED };
//////////
// Set the justification
virtual void setJustification(JustifyWidth wType);
virtual void setJustification(JustifyWidth wType, JustifyHeight hType);
virtual void setJustification(JustifyWidth wType, JustifyHeight hType, JustifyDepth dType);
//////////
// do the justification
// x1,...,z2 just defines the bounding box of the rendered string.
// y_offset is the offset of the current line
virtual void justifyFont(float x1, float y1, float z1,
float x2, float y2, float z2, float y_offset=0);
//-----------------------------------
// GROUP: Member variables
//-----------------------------------
//////////
// The text to display
// (one entry for each line)
vector<wstring> m_theText;
//////////
// distance between the lines
// (1 = 1 line, 0.5 = 0.5 lines, ...)
float m_dist;
///////////
// vector with the offset
// of the individual lines
vector<float> m_lineDist;
//////////
// Do we have a valid font?
int m_valid;
//////////
// The font fize
float m_fontSize;
//////////
// The font depth (only for extruded fonts)
float m_fontDepth;
//////////
// The rendering precision
float m_precision;
//////////
// The width justification
JustifyWidth m_widthJus;
//////////
// The height justification
JustifyHeight m_heightJus;
//////////
// The depth justification
JustifyDepth m_depthJus;
//////////
// The inlet
t_inlet *m_inlet;
//////////
// The default font name
static std::string DEFAULT_FONT;
//////////
// The font structure
#ifdef FTGL
FTFont *m_font;
/* this should delete (m_font) if it is notnull and recreate it.
* a pointer to the new structure is returned (and is set to m_font).
* if creation fails, the font is cleaned-up and NULL is returned
*/
virtual FTFont* makeFont(const char*fontname)=0;
/* this is just handy to reload a font */
t_symbol* m_fontname;
/* on starting to render, we reload the font, to make sure it is there
* this rids us of having to reload the font by hand every time the rendering is restarted
*/
virtual void startRendering(void);
/* render one line of the text */
virtual void renderLine(const char*line,float dist);
virtual void renderLine(const wchar_t*line,float dist);
#endif
private:
///////////
// helpers:
///////////
// helper to make the
// line distance vector
void makeLineDist();
//////////
// Static member functions
static void justifyMessCallback(void *data, t_symbol *, int, t_atom*);
};
#endif // for header file

View file

@ -0,0 +1,43 @@
#####################################################################
# Gem/Controls: objectclasses that control rendering
#####################################################################
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)/src @GEM_CPPFLAGS@
include ../check-sources.mk
noinst_LTLIBRARIES = libControls.la
libControls_la_CXXFLAGS =
libControls_la_LIBADD =
libControls_la_LDFLAGS =
# RTE flags
libControls_la_CXXFLAGS += @GEM_RTE_CFLAGS@ @GEM_ARCH_CXXFLAGS@
libControls_la_LIBADD += @GEM_RTE_LIBS@
libControls_la_LDFLAGS += @GEM_ARCH_LDFLAGS@
libControls_la_SOURCES= \
gemframebuffer.cpp \
gemframebuffer.h \
gemhead.cpp \
gemhead.h \
gemkeyboard.cpp \
gemkeyboard.h \
gemkeyname.cpp \
gemkeyname.h \
gemlist.cpp \
gemlist.h \
gemlist_info.cpp \
gemlist_info.h \
gemlist_matrix.cpp \
gemlist_matrix.h \
gemmouse.cpp \
gemmouse.h \
gemreceive.cpp \
gemreceive.h \
gemwin.cpp \
gemwin.h \
render_trigger.cpp \
render_trigger.h

View file

@ -0,0 +1,15 @@
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)
noinst_LTLIBRARIES = libControls.la
libControls_la_CXXFLAGS =
libControls_la_LIBADD =
# RTE flags
libControls_la_CXXFLAGS += @GEM_RTE_CFLAGS@
libControls_la_LIBADD += @GEM_RTE_LIBS@
libControls_la_SOURCES= @SOURCES@

View file

@ -0,0 +1,548 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// tigital AT mac DOT com
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2005-2006 James Tittle II, tigital At mac DoT com
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemframebuffer.h"
#include <string.h>
#include "Gem/State.h"
#include "Gem/GLStack.h"
CPPEXTERN_NEW_WITH_TWO_ARGS(gemframebuffer, t_symbol *, A_DEFSYMBOL, t_symbol *, A_DEFSYMBOL);
/////////////////////////////////////////////////////////
//
// gemframebuffer
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemframebuffer :: gemframebuffer(t_symbol *format, t_symbol *type)
: m_haveinit(false), m_wantinit(false), m_frameBufferIndex(0), m_depthBufferIndex(0),
m_offScreenID(0), m_texTarget(GL_TEXTURE_2D), m_texunit(0),
m_width(256), m_height(256),
m_rectangle(false),
m_internalformat(GL_RGB8), m_format(GL_RGB), m_wantFormat(GL_RGB),
m_type(GL_UNSIGNED_BYTE),
m_outTexInfo(NULL)
{
// create an outlet to send out texture info:
// - ID
// - width & height
// - format/type (ie. GL_TEXTURE_RECTANGLE or GL_TEXTURE_2D)
// - anything else?
if(!m_outTexInfo)
m_outTexInfo = outlet_new(this->x_obj, 0);
m_FBOcolor[0] = 0.f;
m_FBOcolor[1] = 0.f;
m_FBOcolor[2] = 0.f;
m_FBOcolor[3] = 0.f;
m_perspect[0] = -1.f;
m_perspect[1] = 1.f;
m_perspect[2] = -1.f;
m_perspect[3] = 1.f;
m_perspect[4] = 1.f;
m_perspect[5] = 20.f;
if(format && format->s_name && format!=gensym(""))
formatMess(format->s_name);
if(type && type->s_name && type !=gensym(""))
typeMess(type->s_name);
}
////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemframebuffer :: ~gemframebuffer()
{
destroyFBO();
outlet_free(m_outTexInfo);
}
////////////////////////////////////////////////////////
// extension check
//
/////////////////////////////////////////////////////////
bool gemframebuffer :: isRunnable() {
if(!GLEW_VERSION_1_3) {
error("openGL version 1.3 needed");
return false;
}
if(GLEW_EXT_framebuffer_object) {
m_wantinit=true;
/* check rectangle possibilities */
m_canRectangle=GL_TEXTURE_2D;
if(GLEW_ARB_texture_rectangle)
m_canRectangle=GL_TEXTURE_RECTANGLE_ARB;
else if (GLEW_EXT_texture_rectangle)
m_canRectangle=GL_TEXTURE_RECTANGLE_EXT;
return true;
}
error("openGL framebuffer extension is not supported by this system");
return false;
}
////////////////////////////////////////////////////////
// renderGL
//
/////////////////////////////////////////////////////////
void gemframebuffer :: render(GemState *state)
{
gem::GLStack*stacks=NULL;
if(state) {
state->get(GemState::_GL_STACKS, stacks);
}
if(!m_width || !m_height) {
error("width and height must be present!");
}
glActiveTexture(GL_TEXTURE0_ARB + m_texunit);
if (m_wantinit)
initFBO();
// store the window viewport dimensions so we can reset them,
// and set the viewport to the dimensions of our texture
glGetIntegerv(GL_VIEWPORT, m_vp);
glGetFloatv( GL_COLOR_CLEAR_VALUE, m_color );
glBindTexture( m_texTarget, 0 );
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_frameBufferIndex);
// Bind the texture to the frame buffer.
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
m_texTarget, m_offScreenID, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, m_depthBufferIndex);
// debug yellow color
// glClearColor( 1,1,0,0);
glClearColor( m_FBOcolor[0], m_FBOcolor[1], m_FBOcolor[2], m_FBOcolor[3] );
// Clear the buffers and reset the model view matrix.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// We need a one-to-one mapping of pixels to texels in order to
// ensure every element of our texture is processed. By setting our
// viewport to the dimensions of our destination texture and drawing
// a screen-sized quad (see below), we ensure that every pixel of our
// texel is generated and processed in the fragment program.
glViewport(0,0, m_width, m_height);
if(stacks) stacks->push(gem::GLStack::PROJECTION);
glLoadIdentity();
glFrustum( m_perspect[0], m_perspect[1], m_perspect[2], m_perspect[3], m_perspect[4], m_perspect[5]);
if(stacks) stacks->push(gem::GLStack::MODELVIEW);
glLoadIdentity();
}
////////////////////////////////////////////////////////
// postRender
//
/////////////////////////////////////////////////////////
void gemframebuffer :: postrender(GemState *state)
{
t_float w, h;
gem::GLStack*stacks=NULL;
if(state) {
state->get(GemState::_GL_STACKS, stacks);
}
glActiveTexture(GL_TEXTURE0_ARB + m_texunit);
if(m_texTarget== GL_TEXTURE_2D) {
w=1.f;
h=1.f;
} else {
w=static_cast<t_float>(m_width);
h=static_cast<t_float>(m_height);
}
// GPGPU CONCEPT 4: Viewport-Sized Quad = Data Stream Generator.
// In order to execute fragment programs, we need to generate pixels.
// Drawing a quad the size of our viewport (see above) generates a
// fragment for every pixel of our destination texture. Each fragment
// is processed identically by the fragment program. Notice that in
// the reshape() function, below, we have set the frustum to
// orthographic, and the frustum dimensions to [-1,1]. Thus, our
// viewport-sized quad vertices are at [-1,-1], [1,-1], [1,1], and
// [-1,1]: the corners of the viewport.
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
glBindTexture( m_texTarget, m_offScreenID );
if(stacks) stacks->pop(gem::GLStack::PROJECTION);
if(stacks) stacks->pop(gem::GLStack::MODELVIEW);
// reset to visible window's clear color
glClearColor( m_color[0], m_color[1], m_color[2], m_color[3] );
// reset to original viewport dimensions
glViewport( m_vp[0], m_vp[1], m_vp[2], m_vp[3] );
// now that the render is done,
// send textureID, w, h, textureTarget to outlet
t_atom ap[5];
SETFLOAT(ap+0, static_cast<t_float>(m_offScreenID));
SETFLOAT(ap+1, w);
SETFLOAT(ap+2, h);
SETFLOAT(ap+3, m_texTarget);
SETFLOAT(ap+4, static_cast<t_float>(0.));
outlet_list(m_outTexInfo, 0, 5, ap);
}
void gemframebuffer :: printInfo()
{
std::string format, internalformat;
switch(m_format) {
case GL_YUV422_GEM: format="YUV"; break;
case GL_RGB: format="RGB"; break;
case GL_RGBA: format="RGBA"; break;
case GL_BGRA: format="BGRA"; break;
case GL_RGB_FLOAT32_ATI: format="RGB32"; break;
default: format="<unknown>";
}
switch(m_internalformat) {
case GL_YUV422_GEM: internalformat="YUV"; break;
case GL_RGB: internalformat="RGB"; break;
case GL_RGBA: internalformat="RGBA"; break;
case GL_BGRA: internalformat="BGRA"; break;
case GL_RGB_FLOAT32_ATI: internalformat="RGB32"; break;
default: internalformat="<unknown>";
}
std::string rectangle;
int rect=(m_rectangle?m_canRectangle:GL_TEXTURE_2D);
if(GL_TEXTURE_2D==rect) rectangle="2D";
else if(GL_TEXTURE_RECTANGLE_ARB==rect)rectangle="RECTANGLE(ARB)";
else if(GL_TEXTURE_RECTANGLE_EXT==rect)rectangle="RECTANGLE(EXT)";
std::string type;
switch(m_type) {
case GL_UNSIGNED_BYTE: type="BYTE"; break;
case GL_FLOAT : type="FLOAT"; break;
default : type="unknown";
}
verbose(0, "size: %dx%d", m_width, m_height);
verbose(0, "rectangle: %d -> %s", m_rectangle, rectangle.c_str());
verbose(0, "format: %s/%s [%d/%d]", format.c_str(), internalformat.c_str(), m_format, m_internalformat);
verbose(0, "type: %s [%d]", type.c_str(), m_type);
verbose(0, "texunit: %d", m_texunit);
}
/////////////////////////////////////////////////////////
// initFBO
//
/////////////////////////////////////////////////////////
void gemframebuffer :: initFBO()
{
// clean up any existing FBO before creating a new one
if(m_haveinit)
destroyFBO();
m_texTarget = (m_rectangle?m_canRectangle:GL_TEXTURE_2D);
/* check supported formats */
fixFormat(m_wantFormat);
// Generate frame buffer object then bind it.
glGenFramebuffersEXT(1, &m_frameBufferIndex);
glGenRenderbuffersEXT(1, &m_depthBufferIndex);
// Create the texture we will be using to render to.
glGenTextures(1, &m_offScreenID);
glBindTexture(m_texTarget, m_offScreenID);
glTexImage2D( m_texTarget, 0, m_internalformat, m_width, m_height, 0, m_format, m_type, NULL );
// 2.13.2006
// GL_LINEAR causes fallback to software shader
// so switching back to GL_NEAREST
glTexParameteri(m_texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(m_texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLuint wrapmode = (GLEW_EXT_texture_edge_clamp)?GL_CLAMP_TO_EDGE:GL_CLAMP;
glTexParameterf(m_texTarget, GL_TEXTURE_WRAP_S, wrapmode);
glTexParameterf(m_texTarget, GL_TEXTURE_WRAP_T, wrapmode);
// Initialize the render buffer.
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBufferIndex);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, m_width, m_height);
// Make sure we have not errors.
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT) ;
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
switch(status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
error("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
error("GL_FRAMEBUFFER_UNSUPPORTED_EXT");
break;
case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
error("GL_INVALID_FRAMEBUFFER_OPERATION_EXT");
break;
default:
error("Unknown ERROR %d", status);
}
return;
}
// Return out of the frame buffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
m_haveinit = true;
m_wantinit = false;
printInfo();
}
////////////////////////////////////////////////////////
// destroyFBO
//
/////////////////////////////////////////////////////////
void gemframebuffer :: destroyFBO()
{
if(!GLEW_EXT_framebuffer_object)
return;
// Release all resources.
if(m_depthBufferIndex) glDeleteRenderbuffersEXT(1, &m_depthBufferIndex);
if(m_frameBufferIndex) glDeleteFramebuffersEXT(1, &m_frameBufferIndex);
if(m_offScreenID) glDeleteTextures(1, &m_offScreenID);
m_haveinit = false;
}
////////////////////////////////////////////////////////
// bangMess
//
/////////////////////////////////////////////////////////
void gemframebuffer :: bangMess()
{
error("'bang' message not implemented");
}
////////////////////////////////////////////////////////
// startRendering
//
/////////////////////////////////////////////////////////
void gemframebuffer :: startRendering()
{
m_wantinit = true;
}
////////////////////////////////////////////////////////
// stopRendering
//
/////////////////////////////////////////////////////////
void gemframebuffer :: stopRendering()
{
destroyFBO();
}
////////////////////////////////////////////////////////
// dimMess
//
/////////////////////////////////////////////////////////
void gemframebuffer :: dimMess(int width, int height)
{
if (width != m_width || height != m_height)
{
m_width = width;
m_height = height;
setModified();
}
}
void gemframebuffer :: colorMess(t_symbol*s,int argc, t_atom*argv)
{
float red=1., green=1., blue=1., alpha=1.;
switch(argc) {
case (4):
alpha=atom_getfloat(argv+3);
case (3):
red =atom_getfloat(argv+0);
green=atom_getfloat(argv+1);
blue =atom_getfloat(argv+2);
break;
default:
error("'color' message takes 3 (RGB) or 4 (RGBA) values");
return;
}
m_FBOcolor[0] = red;
m_FBOcolor[1] = green;
m_FBOcolor[2] = blue;
m_FBOcolor[3] = alpha;
// setModified();
}
void gemframebuffer :: perspectiveMess(t_symbol*s,int argc, t_atom*argv)
{
switch(argc){
case 6:
m_perspect[0]=atom_getfloat(argv);
m_perspect[1]=atom_getfloat(argv+1);
m_perspect[2]=atom_getfloat(argv+2);
m_perspect[3]=atom_getfloat(argv+3);
m_perspect[4]=atom_getfloat(argv+4);
m_perspect[5]=atom_getfloat(argv+5);
// setModified();
break;
default:
error("\"perspec\" expects 6 values for frustum - left, right, bottom, top, near, far");
}
}
/* needs to be called with a valid context */
void gemframebuffer :: fixFormat(GLenum wantFormat)
{
m_type = GL_UNSIGNED_BYTE;
if(wantFormat == GL_RGB_FLOAT32_ATI && !GLEW_ATI_texture_float) {
wantFormat = GL_RGB;
}
switch(wantFormat) {
default:
verbose(1,"using default format");
case GL_RGB:
m_internalformat=m_format=GL_RGB;
break;
case GL_RGB_FLOAT32_ATI:
m_internalformat = GL_RGB_FLOAT32_ATI;
m_format = GL_RGB;
break;
case GL_RGBA:
m_internalformat = GL_RGBA;
m_format = GL_RGBA;
break;
case GL_YUV422_GEM:
m_format=GL_YUV422_GEM;
m_internalformat=GL_RGB8;
break;
}
#ifdef __APPLE__
switch(wantFormat) {
case GL_RGB_FLOAT32_ATI:
m_format = GL_BGR;
break;
case GL_RGBA:
m_format = GL_BGRA;
break;
case GL_YUV422_GEM:
m_type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
break;
default:
break;
}
#endif
}
void gemframebuffer :: formatMess(std::string format)
{
GLenum tmp_format=0;
if("YUV"==format) {
tmp_format = GL_YUV422_GEM;
} else if ("RGB"==format) {
tmp_format = GL_RGB;
} else if ("RGBA"==format) {
tmp_format = GL_RGBA;
} else if ("RGB32"==format) {
tmp_format = GL_RGB_FLOAT32_ATI;
}
if(tmp_format)
m_wantFormat=tmp_format;
setModified();
}
void gemframebuffer :: typeMess(std::string type)
{
if("FLOAT"==type) {
m_type = GL_FLOAT;
} else {
type="BYTE";
m_type=GL_UNSIGNED_BYTE;
}
// changed type, so we need to rebuild the FBO
setModified();
}
void gemframebuffer :: rectangleMess(bool rectangle)
{
m_rectangle=rectangle;
setModified();
}
void gemframebuffer :: texunitMess(int unit) {
m_texunit=static_cast<GLuint>(unit);
}
////////////////////////////////////////////////////////
// static member function
//
////////////////////////////////////////////////////////
void gemframebuffer :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG0(classPtr, "bang", bangMess);
CPPEXTERN_MSG (classPtr, "color", colorMess);
CPPEXTERN_MSG (classPtr, "perspec", perspectiveMess);
CPPEXTERN_MSG2(classPtr, "dimen", dimMess, int, int);
CPPEXTERN_MSG1(classPtr, "format", formatMess, std::string);
CPPEXTERN_MSG1(classPtr, "type", typeMess, std::string);
CPPEXTERN_MSG1(classPtr, "rectangle", rectangleMess, bool);
CPPEXTERN_MSG1(classPtr, "texunit", texunitMess, int);
/* legacy */
CPPEXTERN_MSG2(classPtr, "dim", dimMess, int, int);
CPPEXTERN_MSG1(classPtr, "mode", rectangleMess, bool);
}

View file

@ -0,0 +1,107 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
render to offscreen buffer and make texture
created 11/27/2005
Copyright (c) 2005-2006 James Tittle II, tigital AT mac DOT com
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMFRAMEBUFFER_H_
#define _INCLUDE__GEM_CONTROLS_GEMFRAMEBUFFER_H_
#include "Base/GemBase.h"
#include <iostream>
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemframebuffer
render to offscreen buffer and make texture
DESCRIPTION
"bang" - sends out a state list
-----------------------------------------------------------------*/
class GEM_EXTERN gemframebuffer : public GemBase
{
CPPEXTERN_HEADER(gemframebuffer, GemBase);
public:
//////////
// Constructor
gemframebuffer(t_symbol *format, t_symbol *type);
protected:
//////////
// Destructor
~gemframebuffer(void);
//////////
// A render message
void render(GemState *state);
void postrender(GemState *state);
void initFBO(void);
void destroyFBO(void);
//////////
// Set up the modifying flags
void startRendering(void);
//////////
// Clean up the modifying flags
void stopRendering(void);
// extension checks
virtual bool isRunnable(void);
//////////
// change the size dimensions
void dimMess(int width, int height);
//////////
// format-message
virtual void formatMess(std::string);
virtual void typeMess(std::string);
virtual void colorMess(t_symbol*,int argc, t_atom*argv);
virtual void perspectiveMess(t_symbol*,int argc, t_atom*argv);
virtual void rectangleMess(bool mode);
virtual void texunitMess(int mode);
virtual void fixFormat(GLenum wantedFormat);
virtual void printInfo(void);
private:
GLboolean m_haveinit, m_wantinit;
GLuint m_frameBufferIndex;
GLuint m_depthBufferIndex;
GLuint m_offScreenID;
GLuint m_texTarget;
GLuint m_texunit;
int m_width, m_height;
bool m_rectangle; // 1=TEXTURE_RECTANGLE_EXT, 0=TEXTURE_2D
GLenum m_canRectangle; // whichever rectangle formats are supported
int m_internalformat;
int m_format;
GLenum m_wantFormat;
int m_type;
GLint m_vp[4];
GLfloat m_color[4];
GLfloat m_FBOcolor[4];
t_outlet *m_outTexInfo;
GLfloat m_perspect[6];
void bangMess(void);
};
#endif // for header file

View file

@ -0,0 +1,284 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemhead.h"
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
#include "Gem/Manager.h"
#include "Gem/State.h"
#include "Gem/Cache.h"
#include "Base/GemBase.h"
#include "Gem/GLStack.h"
#include "Gem/Exception.h"
#include <stdio.h>
#ifdef _MSC_VER /* This is only for Microsoft's compiler, not cygwin, e.g. */
# define snprintf _snprintf
#endif
CPPEXTERN_NEW_WITH_GIMME(gemhead);
static std::string float2str(t_float v) {
std::string s;
char buf[1000];
snprintf(buf, 1000, "%g", v);
s=buf;
return s;
}
/////////////////////////////////////////////////////////
//
// gemhead
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemhead :: gemhead(int argc, t_atom*argv) :
gemreceive(gensym("__gem_render")),
m_cache(new GemCache(this)), m_renderOn(1)
{
if(m_fltin)inlet_free(m_fltin); m_fltin=NULL;
m_basename=m_name->s_name;
float priority=50.;
#if 1
switch(argc) {
case 2:
if(argv[0].a_type == A_FLOAT && argv[1].a_type == A_SYMBOL) {
priority=atom_getfloat(argv+0);
m_basename+=atom_getsymbol(argv+1)->s_name;
} else if(argv[1].a_type == A_FLOAT && argv[0].a_type == A_SYMBOL) {
priority=atom_getfloat(argv+1);
m_basename+=atom_getsymbol(argv+0)->s_name;
} else if(argv[1].a_type == A_FLOAT && argv[0].a_type == A_FLOAT) {
priority=atom_getfloat(argv+0);
m_basename+=::float2str(atom_getfloat (argv+1));
}
break;
case 1:
if(argv[0].a_type == A_FLOAT) {
priority=atom_getfloat(argv+0);
} else if(argv[0].a_type == A_SYMBOL) {
m_basename+=atom_getsymbol(argv+0)->s_name;
}
break;
case 0:
priority=50.f;
break;
default:
throw(GemException("invalid arguments: 'gemhead [<priority> [<basereceivename>]]'"));
}
#else
if(argc==0)
priority=50.;
else if(argv[0].a_type == A_FLOAT) {
priority=atom_getfloat(argv);
} else
throw(GemException("invalid arguments: 'gemhead [<priority>]'"));
#endif
m_priority=priority+1;
setMess(priority);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemhead :: ~gemhead()
{
if (m_cache)
stopRendering();
if(m_cache)delete m_cache;
m_cache=NULL;
}
/////////////////////////////////////////////////////////
// renderGL
//
/////////////////////////////////////////////////////////
void gemhead :: renderGL(GemState *state)
{
static const GLfloat a_color[]={0.2,0.2,0.2,1};
static const GLfloat d_color[]={0.8,0.8,0.8,1};
static const GLfloat e_color[]={0.0,0.0,0.0,1};
static const GLfloat s_color[]={0.0,0.0,0.0,1};
static const GLfloat shininess[]={0.0};
if (!m_cache || !m_renderOn) return;
// set the default color and transformation matrix
glColor4f(1.f, 1.f, 1.f, 1.f);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a_color);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, d_color);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e_color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s_color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
gem::GLStack*stacks=NULL;
if(state)
{
state->reset();
// set the state dirty flag
state->set(GemState::_DIRTY, m_cache->dirty);
state->VertexDirty=m_cache->vertexDirty;
state->get(GemState::_GL_STACKS, stacks);
if(stacks)stacks->push();
}
// are we profiling and need to send new images?
if (GemMan::getProfileLevel() >= 2)
m_cache->resendImage = 1;
t_atom ap[2];
ap->a_type=A_POINTER;
ap->a_w.w_gpointer=reinterpret_cast<t_gpointer*>(m_cache); // the cache ?
(ap+1)->a_type=A_POINTER;
(ap+1)->a_w.w_gpointer=reinterpret_cast<t_gpointer*>(state);
outlet_anything(this->m_outlet, gensym("gem_state"), 2, ap);
m_cache->dirty = false;
m_cache->vertexDirty=false;
state->get(GemState::_GL_STACKS, stacks);
if(stacks)stacks->pop();
}
/////////////////////////////////////////////////////////
// bangMess
//
/////////////////////////////////////////////////////////
void gemhead :: bangMess()
{
int renderon = m_renderOn;
// make sure that the window and the cache exist
if ( !GemMan::windowExists() || !m_cache )
return;
// make a dummy GemState
GemState tempState;
GemMan::fillGemState(tempState);
m_renderOn = 1;
renderGL(&tempState);
m_renderOn = renderon;
glFlush();
}
/////////////////////////////////////////////////////////
// renderOnOff
//
/////////////////////////////////////////////////////////
void gemhead :: renderOnOff(int state)
{
m_renderOn = state;
}
/////////////////////////////////////////////////////////
// setPriority
//
/////////////////////////////////////////////////////////
void gemhead :: setMess(t_float priority)
{
if (0.==priority)priority=50.;
if(priority==m_priority)
return;
m_priority=priority;
std::string rcv=m_basename;
if(priority<0.f)
rcv=m_basename+"_osd";
gemreceive::priorityMess(priority);
gemreceive::nameMess(rcv);
}
void gemhead :: receive(t_symbol*s, int argc, t_atom*argv) {
if(m_renderOn && gensym("gem_state")==s) {
if(1==argc && A_FLOAT==argv->a_type) {
int i=atom_getint(argv);
switch(i) {
case 0:
stopRendering();
break;
default:
startRendering();
}
} else if (2==argc && A_POINTER==argv[0].a_type && A_POINTER==argv[1].a_type) {
GemCache*cache=reinterpret_cast<GemCache*>(argv[0].a_w.w_gpointer);
GemState*state=reinterpret_cast<GemState*>(argv[1].a_w.w_gpointer);
renderGL(state);
}
} else {
// not for us...
}
}
/////////////////////////////////////////////////////////
// outputRenderOnOff
//
/////////////////////////////////////////////////////////
void gemhead :: outputRenderOnOff(int state)
{
// continue sending out the cache message
t_atom ap[1];
SETFLOAT(ap, state);
outlet_anything(this->m_outlet, gensym("gem_state"), 1, ap);
}
/////////////////////////////////////////////////////////
// startRendering
//
/////////////////////////////////////////////////////////
void gemhead :: startRendering()
{
if (m_cache) m_cache->reset(this);
else m_cache = new GemCache(this);
outputRenderOnOff(1);
}
/////////////////////////////////////////////////////////
// stopRendering
//
/////////////////////////////////////////////////////////
void gemhead :: stopRendering()
{
outputRenderOnOff(0);
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemhead :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG0(classPtr, "bang", bangMess);
CPPEXTERN_MSG1(classPtr, "float", renderOnOff, int);
CPPEXTERN_MSG1(classPtr, "set", setMess, int);
}

View file

@ -0,0 +1,87 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The starting point for all graphics trees
Copyright (c) 1997-1998 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMHEAD_H_
#define _INCLUDE__GEM_CONTROLS_GEMHEAD_H_
#include "Base/CPPExtern.h"
#include "gemreceive.h"
class GemState;
class GemCache;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemhead
The starting point for all graphics trees
DESCRIPTION
"bang" - sends out a state list
-----------------------------------------------------------------*/
class GEM_EXTERN gemhead : public gemreceive
{
CPPEXTERN_HEADER(gemhead, CPPExtern);
public:
//////////
// Constructor
gemhead(int, t_atom*);
//////////
// A render message
void renderGL(GemState *state);
//////////
// Set up the modifying flags
virtual void startRendering();
//////////
// Clean up the modifying flags
virtual void stopRendering();
//////////
// change the priority
void setMess(t_float priority);
virtual void receive(t_symbol*s, int argc, t_atom*argv);
protected:
//////////
// Destructor
virtual ~gemhead();
std::string m_basename;
private:
t_outlet *m_out1;
GemCache *m_cache; // The cache information
void outputRenderOnOff(int state);
void renderOnOff(int state); // Turn rendering on and off
int m_renderOn;
void bangMess();
};
#endif // for header file

View file

@ -0,0 +1,71 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemkeyboard.h"
#include "Gem/Event.h"
CPPEXTERN_NEW(gemkeyboard);
/////////////////////////////////////////////////////////
//
// gemkeyboard
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemkeyboard :: gemkeyboard()
{
m_outKeyVal = outlet_new(this->x_obj, 0);
// register event callback
setKeyboardCallback(&gemkeyboard::keyboardCallback, this);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemkeyboard :: ~gemkeyboard()
{
// remove event callback
removeKeyboardCallback(&gemkeyboard::keyboardCallback, this);
outlet_free(m_outKeyVal);
}
/////////////////////////////////////////////////////////
// KeyBoardPressed
//
/////////////////////////////////////////////////////////
void gemkeyboard :: KeyBoardPressed(int val, int state)
{
if (state==0)return;
outlet_float(m_outKeyVal, static_cast<t_float>(val));
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemkeyboard :: obj_setupCallback(t_class *)
{ }
void gemkeyboard :: keyboardCallback(char* w, int x, int y, void *data)
{
(reinterpret_cast<gemkeyboard*>(data))->KeyBoardPressed(x, y);
}

View file

@ -0,0 +1,61 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Respond to mouse events
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMKEYBOARD_H_
#define _INCLUDE__GEM_CONTROLS_GEMKEYBOARD_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemkeyboard
Respond to keyboard events
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN gemkeyboard : public CPPExtern
{
CPPEXTERN_HEADER(gemkeyboard, CPPExtern);
public:
//////////
// Constructor
gemkeyboard();
protected:
//////////
// Destructor
virtual ~gemkeyboard();
//////////
// keyboard-button
void KeyBoardPressed(int val, int state);
//////////
// The key-val outlet
t_outlet *m_outKeyVal;
private:
//////////
// Static member functions
static void keyboardCallback(char *w, int x, int y, void *data);
};
#endif // for header file

View file

@ -0,0 +1,73 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemkeyname.h"
#include "Gem/Event.h"
CPPEXTERN_NEW(gemkeyname);
/////////////////////////////////////////////////////////
//
// gemkeyname
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemkeyname :: gemkeyname()
{
m_outKeyState = outlet_new(this->x_obj, 0);
m_outKeyVal = outlet_new(this->x_obj, 0);
// register event callback
setKeyboardCallback(&gemkeyname::keynameCallback, this);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemkeyname :: ~gemkeyname()
{
// remove event callback
removeKeyboardCallback(&gemkeyname::keynameCallback, this);
outlet_free(m_outKeyState);
outlet_free(m_outKeyVal);
}
/////////////////////////////////////////////////////////
// mouseMotion
//
/////////////////////////////////////////////////////////
void gemkeyname :: KeyNamePressed(char *string, int val, int state)
{
outlet_symbol(m_outKeyVal, gensym(string));
outlet_float(m_outKeyState, static_cast<t_float>(state));
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemkeyname :: obj_setupCallback(t_class *)
{ }
void gemkeyname :: keynameCallback(char *x, int y, int z, void *data)
{
(reinterpret_cast<gemkeyname*>(data))->KeyNamePressed(x,y, z);
}

View file

@ -0,0 +1,66 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Respond to mouse events
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMKEYNAME_H_
#define _INCLUDE__GEM_CONTROLS_GEMKEYNAME_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemkeyname
Respond to keyboard events
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN gemkeyname : public CPPExtern
{
CPPEXTERN_HEADER(gemkeyname, CPPExtern);
public:
//////////
// Constructor
gemkeyname();
protected:
//////////
// Destructor
virtual ~gemkeyname();
//////////
// keyname-button
void KeyNamePressed(char* string, int val, int state);
//////////
// The key-val outlet
t_outlet *m_outKeyVal;
//////////
// The key-state outlet
t_outlet *m_outKeyState;
private:
//////////
// Static member functions
static void keynameCallback(char* x, int y, int z, void *data);
};
#endif // for header file

View file

@ -0,0 +1,199 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// ch@chdh.net
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemlist.h"
#include "Gem/Cache.h"
#include "Gem/Manager.h"
CPPEXTERN_NEW(gemlist);
/////////////////////////////////////////////////////////
//
// gemlist
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemlist :: gemlist(void)
: m_validState(false),
m_tickTime(-1.f),
m_lightState(false),
m_drawType(0),
m_mycache(new GemCache(NULL)),
m_inlet(NULL)
{
// create the cold inlet
m_inlet = inlet_new(this->x_obj, &this->x_obj->ob_pd, gensym("gem_state"), gensym("gem_right"));
}
////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemlist :: ~gemlist()
{
if(m_mycache)delete m_mycache; m_mycache=NULL;
if(m_inlet)inlet_free(m_inlet); m_inlet=NULL;
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void gemlist :: render(GemState *state)
{
m_state=*state; //copy current state for later use
m_validState=true;
}
/////////////////////////////////////////////////////////
// postrender
//
/////////////////////////////////////////////////////////
void gemlist :: postrender(GemState *)
{
// m_validState=false;
// this is to early to reset the m_validState
// when should we call this???
// TODO : fix this.
}
void gemlist :: sendCacheState(GemCache *cache, GemState*state)
{
if ( !GemMan::windowExists() ) {
// LATER: shouldn't this test for a valid context rather than an existing window??
// error("you should not bang the gemlist now");
return;
}
if(state) {
t_atom ap[2];
if(!cache)
cache=m_mycache;
ap->a_type=A_POINTER;
ap->a_w.w_gpointer=reinterpret_cast<t_gpointer*>(cache);
(ap+1)->a_type=A_POINTER;
(ap+1)->a_w.w_gpointer=reinterpret_cast<t_gpointer*>(state);
outlet_anything(m_out1, gensym("gem_state"), 2, ap);
}
}
/////////////////////////////////////////////////////////
// bang
//
/////////////////////////////////////////////////////////
void gemlist :: trigger()
{
if(m_validState) {
// outlet the current state when banged
sendCacheState(m_cache, &m_state);
} else {
// GemMan::fillGemState(state);
sendCacheState(NULL, &m_mystate);
}
}
///////////////////
// here come some messages for setting up a manual GemState
void gemlist :: ticktimeMess(t_float ticktime)
{
m_tickTime=ticktime;
m_mystate.set(GemState::_TIMING_TICK, m_tickTime);
}
void gemlist :: lightingMess(bool light)
{
m_lightState=light;
m_mystate.set(GemState::_GL_LIGHTING, m_lightState);
m_mystate.set(GemState::_GL_SMOOTH, m_lightState);
}
void gemlist :: drawMess(t_atom&arg)
{
if(A_SYMBOL==arg.a_type) {
t_symbol*type=atom_getsymbol(&arg);
char c=*type->s_name;
switch (c){
case 'D': case 'd': // default
m_drawType = GL_DEFAULT_GEM;
break;
case 'L': case 'l': // line
m_drawType = GL_LINE;
break;
case 'F': case 'f': // fill
m_drawType = GL_FILL;
break;
case 'P': case 'p': // point
m_drawType = GL_POINT;
break;
default:
m_drawType = static_cast<GLenum>(getGLdefine(&arg));
}
}
else m_drawType=atom_getint(&arg);
m_mystate.set(GemState::_GL_DRAWTYPE, m_drawType);
}
/////////////////////////////////////////////////////////
// rightRender
//
/////////////////////////////////////////////////////////
void gemlist :: rightRender(GemCache*cache, GemState *state)
{
if(state) {
m_state=*state;
m_validState=true;
// get the current state on the right inlet
} else {
m_validState=false;
}
m_cache=cache;
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemlist :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG0(classPtr, "bang", trigger);
CPPEXTERN_MSG (classPtr, "gem_right", rightMess);
CPPEXTERN_MSG1(classPtr, "ticktime", ticktimeMess, float);
CPPEXTERN_MSG1(classPtr, "lighting", lightingMess, bool);
CPPEXTERN_MSG (classPtr, "draw", drawMess);
}
void gemlist :: drawMess(t_symbol*s, int argc, t_atom*argv)
{
if(argc==1)
drawMess(argv[0]);
}
void gemlist::rightMess(t_symbol *s, int argc, t_atom *argv)
{
GemCache*cache=NULL;
GemState*state=NULL;
if (argc==1 && argv->a_type==A_FLOAT){
rightRender(cache, state);
} else if (argc==2 && argv->a_type==A_POINTER && (argv+1)->a_type==A_POINTER){
cache=reinterpret_cast<GemCache*>(argv->a_w.w_gpointer);
state=reinterpret_cast<GemState*>((argv+1)->a_w.w_gpointer);
rightRender( cache, state );
} else error("wrong righthand arguments....");
}

View file

@ -0,0 +1,89 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
this object work with gemlist exactly like pd [float] work with float
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMLIST_H_
#define _INCLUDE__GEM_CONTROLS_GEMLIST_H_
#include "Base/GemBase.h"
#include "Gem/State.h"
class GemCache;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemlist
DESCRIPTION
"gemlist" - send the curent gemlist when banged.
The curent gemlist can be set via the hot or cold inlet
-----------------------------------------------------------------*/
class GEM_EXTERN gemlist : public GemBase
{
CPPEXTERN_HEADER(gemlist, GemBase);
public:
//////////
// Constructor
gemlist(void);
protected:
//////////
// Destructor
virtual ~gemlist(void);
//////////
// Push the current state
virtual void render(GemState *state);
//////////
virtual void postrender(GemState *state);
//////////
// send a valid state to the outlet
void sendCacheState(GemCache*cache, GemState*state);
//////////
void trigger(void);
virtual void rightRender(GemCache*cache, GemState *state);
void rightMess(t_symbol *s, int argc, t_atom *argv);
virtual void ticktimeMess(t_float ticktime);
virtual void lightingMess(bool state);
virtual void drawMess(t_atom&arg);
virtual void drawMess(t_symbol*s, int argc, t_atom*argv);
//////////
// curent state
GemState m_state;
bool m_validState;
float m_tickTime;
bool m_lightState;
GLenum m_drawType;
GemState m_mystate;
GemCache* m_mycache;
t_inlet *m_inlet;
};
#endif // for header file

View file

@ -0,0 +1,163 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// Implementation file
//
// Copyright (c) 2002-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// zmoelnig@iem.kug.ac.at
// For information on usage and redistribution, and for a DISCLAIMER
// * OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS"
//
//
////////////////////////////////////////////////////////
#include "gemlist_info.h"
#include "math.h"
#ifdef __ppc__
#include "Utils/Functions.h"
#undef sqrt
#define sqrt fast_sqrtf
#endif
#define rad2deg -57.2957795132
CPPEXTERN_NEW_WITH_ONE_ARG ( gemlist_info , t_floatarg, A_DEFFLOAT );
/////////////////////////////////////////////////////////
//
// gemlist_info
//
/////////////////////////////////////////////////////////
// Constructor
//
gemlist_info :: gemlist_info (t_floatarg arg0=0) {
m_outletRotation = outlet_new(this->x_obj, 0);
m_outletShear = outlet_new(this->x_obj, 0);
m_outletScale = outlet_new(this->x_obj, 0);
m_outletPosition = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
gemlist_info :: ~gemlist_info () {
outlet_free(m_outletScale);
outlet_free(m_outletPosition);
outlet_free(m_outletRotation);
outlet_free(m_outletShear);
}
/////////////////////////////////////////////////////////
// extension check
//
bool gemlist_info :: isRunnable() {
if(GLEW_VERSION_1_1)
return true;
error("your system does not support openGL-1.0 needed for operation");
return false;
}
/////////////////////////////////////////////////////////
// Render
//
void gemlist_info :: render(GemState *state) {
float mi[16]={0};
t_atom alist[12];
float X, Y, Z, ScaleX, ScaleY, ScaleZ, shearYX, shearZX, shearZY;
glGetFloatv(GL_MODELVIEW_MATRIX,mi);
// test de syngularité a effectuer
// normalisation
// for (i=0; i<16; i++) mi[i] /= mi[15];
// not usefull because I never saw mi[15]!=1; if this change, un-comment this normalisation procedure
ScaleX = sqrt (mi[0] * mi[0] + mi[4] * mi[4] + mi[8] * mi[8]);
mi[0] /= ScaleX; // Normalise X
mi[4] /= ScaleX;
mi[8] /= ScaleX;
shearYX = mi[0]*mi[1] + mi[4]*mi[5] + mi[8]*mi[9];
mi[1] -= shearYX * mi[0]; //make X and Y orthogonal
mi[5] -= shearYX * mi[4];
mi[9] -= shearYX * mi[8];
ScaleY = sqrt (mi[1] * mi[1] + mi[5] * mi[5] + mi[9] * mi[9]);
mi[1] /= ScaleY; // Normalise Y
mi[5] /= ScaleY;
mi[9] /= ScaleY;
shearYX /= ScaleY;
shearZX = mi[0]*mi[2] + mi[4]*mi[6] + mi[8]*mi[10];
mi[2] -= shearZX * mi[0]; //make X and Z orthogonal
mi[6] -= shearZX * mi[4];
mi[10] -= shearZX * mi[8];
shearZY = mi[1]*mi[2] + mi[5]*mi[6] + mi[9]*mi[10];
mi[2] -= shearZY * mi[1]; //make X and Z orthogonal
mi[6] -= shearZY * mi[5];
mi[10] -= shearZY * mi[9];
ScaleZ = sqrt (mi[2] * mi[2] + mi[6] * mi[6] + mi[10] * mi[10]);
mi[2] /= ScaleZ; // Normalise Y
mi[6] /= ScaleZ;
mi[10] /= ScaleZ;
shearZX /= ScaleZ;
shearZY /= ScaleZ;
// maybee some test could be inserted here.
// The matrix can only be decomposed if it's determinent is not 0.
Y = asin(-mi[8]);
if ( cos(Y) != 0 ) {
X = atan2(mi[9], mi[10]);
Z = atan2(mi[4], mi[0]);
} else {
X = atan2(mi[1], mi[5]);
Z = 0;
}
X *= rad2deg;
Y *= rad2deg;
Z *= rad2deg;
SETFLOAT(alist+0, ScaleX);
SETFLOAT(alist+1, ScaleY);
SETFLOAT(alist+2, ScaleZ);
SETFLOAT(alist+3, X);
SETFLOAT(alist+4, Y);
SETFLOAT(alist+5, Z);
SETFLOAT(alist+6, mi[12]);
SETFLOAT(alist+7, mi[13]);
SETFLOAT(alist+8, mi[14]);
SETFLOAT(alist+9, shearYX);
SETFLOAT(alist+10, shearZX);
SETFLOAT(alist+11, shearZY);
outlet_list (m_outletPosition, &s_list, 3, alist+6);
outlet_list (m_outletScale, &s_list, 3, alist+0);
outlet_list (m_outletShear, &s_list, 3, alist+9);
outlet_list (m_outletRotation, &s_list, 3, alist+3);
}
/////////////////////////////////////////////////////////
// static member functions
//
void gemlist_info :: obj_setupCallback(t_class *classPtr) {
}

View file

@ -0,0 +1,49 @@
/* ------------------------------------------------------------------
* GEM - Graphics Environment for Multimedia
*
* Copyright (c) 2002-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
* zmoelnig@iem.kug.ac.at
* For information on usage and redistribution, and for a DISCLAIMER
* OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS"
*
* ------------------------------------------------------------------
*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMLIST_INFO_H_
#define _INCLUDE__GEM_CONTROLS_GEMLIST_INFO_H_
#include "Base/GemBase.h"
/*
CLASS
gemlist_info
KEYWORDS
openGL 0
DESCRIPTION
get information (scale, shear, rotation, translation) about a gemlist
*/
class GEM_EXTERN gemlist_info : public GemBase
{
CPPEXTERN_HEADER(gemlist_info, GemBase);
public:
// Constructor
gemlist_info (t_floatarg); // CON
protected:
// Destructor
virtual ~gemlist_info ();
// Do the rendering
virtual void render (GemState *state);
// extension checks
virtual bool isRunnable();
private:
// The outlets
t_outlet *m_outletScale;
t_outlet *m_outletRotation;
t_outlet *m_outletPosition;
t_outlet *m_outletShear;
};
#endif // for header file

View file

@ -0,0 +1,81 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// Implementation file
//
// Copyright (c) 2002-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// zmoelnig@iem.kug.ac.at
// For information on usage and redistribution, and for a DISCLAIMER
// * OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS"
//
//
////////////////////////////////////////////////////////
#include "gemlist_matrix.h"
#include "math.h"
#ifdef __ppc__
#include "Utils/Functions.h"
#undef sqrt
#define sqrt fast_sqrtf
#endif
#define rad2deg -57.2957795132
CPPEXTERN_NEW_WITH_ONE_ARG ( gemlist_matrix , t_floatarg, A_DEFFLOAT );
/////////////////////////////////////////////////////////
//
// gemlist_matrix
//
/////////////////////////////////////////////////////////
// Constructor
//
gemlist_matrix :: gemlist_matrix (t_floatarg arg0=0) {
m_outletMatrice = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
gemlist_matrix :: ~gemlist_matrix () {
outlet_free(m_outletMatrice);
}
/////////////////////////////////////////////////////////
// extension check
//
bool gemlist_matrix :: isRunnable() {
if(GLEW_VERSION_1_1)
return true;
error("your system does not support openGL-1.0 needed for operation");
return false;
}
/////////////////////////////////////////////////////////
// Render
//
void gemlist_matrix :: render(GemState *state) {
float mi[16]={0};
int i;
t_atom alist[16];
glGetFloatv(GL_MODELVIEW_MATRIX,mi);
for (i=0;i<16;i++)
{
SETFLOAT(alist+i, mi[i]);
}
outlet_list (m_outletMatrice, &s_list, 16, alist);
}
/////////////////////////////////////////////////////////
// static member functions
//
void gemlist_matrix :: obj_setupCallback(t_class *classPtr) {
}

View file

@ -0,0 +1,45 @@
/* ------------------------------------------------------------------
* GEM - Graphics Environment for Multimedia
*
* Copyright (c) 2002-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
* zmoelnig@iem.kug.ac.at
* For information on usage and redistribution, and for a DISCLAIMER
* OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS"
*
* ------------------------------------------------------------------
*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMLIST_MATRIX_H_
#define _INCLUDE__GEM_CONTROLS_GEMLIST_MATRIX_H_
#include "Base/GemBase.h"
/*
CLASS
gemlist_matrix
KEYWORDS
openGL 0
DESCRIPTION
get information (scale, shear, rotation, translation) about a gemlist
*/
class GEM_EXTERN gemlist_matrix : public GemBase
{
CPPEXTERN_HEADER(gemlist_matrix, GemBase);
public:
// Constructor
gemlist_matrix (t_floatarg); // CON
protected:
// Destructor
virtual ~gemlist_matrix ();
// Do the rendering
virtual void render (GemState *state);
// extension checks
virtual bool isRunnable();
private:
// The outlets
t_outlet *m_outletMatrice;
};
#endif // for header file

View file

@ -0,0 +1,152 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#define GEM_CLASSFLAGS CLASS_NOINLET
#include "gemmouse.h"
#include "Gem/Event.h"
#include "Gem/Manager.h"
CPPEXTERN_NEW_WITH_GIMME(gemmouse);
/////////////////////////////////////////////////////////
//
// gemmouse
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemmouse :: gemmouse(int argc, t_atom*argv) :
m_scaleX(1.0), m_scaleY(1.0), m_scaleMode(NONE)
{
m_outXPos = outlet_new(this->x_obj, 0);
m_outYPos = outlet_new(this->x_obj, 0);
m_outLBut = outlet_new(this->x_obj, 0);
m_outMBut = outlet_new(this->x_obj, 0);
m_outRBut = outlet_new(this->x_obj, 0);
switch(argc){
case 0:
m_scaleX = m_scaleY = 0.f;
break;
case 1:
m_scaleX = m_scaleY = atom_getfloat(argv);
m_scaleMode =HEIGHT;
break;
default:
m_scaleX=atom_getfloat(argv);
m_scaleY=atom_getfloat(argv+1);
m_scaleMode =BOTH;
}
// register event callback
setMotionCallback(&gemmouse::mouseMotionCallback, this);
setButtonCallback(&gemmouse::mouseButtonCallback, this);
setWheelCallback(&gemmouse::mouseWheelCallback, this);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemmouse :: ~gemmouse()
{
// remove event callback
removeMotionCallback(&gemmouse::mouseMotionCallback, this);
removeButtonCallback(&gemmouse::mouseButtonCallback, this);
removeWheelCallback(&gemmouse::mouseWheelCallback, this);
outlet_free(m_outXPos);
outlet_free(m_outYPos);
outlet_free(m_outLBut);
outlet_free(m_outMBut);
outlet_free(m_outRBut);
}
/////////////////////////////////////////////////////////
// mouseMotion
//
/////////////////////////////////////////////////////////
void gemmouse :: mouseMotion(int x, int y)
{
t_float scalex = 1., scaley=1.;
int width, height;
GemMan::getRealDimen(&width, &height);
switch(m_scaleMode) {
case NONE:
break;
case BOTH:
scalex=m_scaleX/width;
scaley=m_scaleY/height;
break;
case WIDTH:
scalex=m_scaleX/width;
scaley=scalex;
break;
case HEIGHT:
scaley=m_scaleY/height;
scalex=scaley;
break;
}
outlet_float(m_outYPos, static_cast<t_float>(y*scaley));
outlet_float(m_outXPos, static_cast<t_float>(x*scalex));
}
/////////////////////////////////////////////////////////
// mouseButton
//
/////////////////////////////////////////////////////////
void gemmouse :: mouseButton(int which, int state, int x, int y)
{
switch (which){
case 0: outlet_float(m_outLBut, static_cast<t_float>(state)); break;
case 1: outlet_float(m_outMBut, static_cast<t_float>(state)); break;
case 2: outlet_float(m_outRBut, static_cast<t_float>(state)); break;
}
}
/////////////////////////////////////////////////////////
// mouseButton
//
/////////////////////////////////////////////////////////
void gemmouse :: mouseWheel(int axis, int value)
{
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemmouse :: obj_setupCallback(t_class *)
{ }
void gemmouse :: mouseMotionCallback(int x, int y, void *data)
{
(reinterpret_cast<gemmouse*>(data))->mouseMotion(x, y);
}
void gemmouse :: mouseButtonCallback(int which, int state, int x, int y, void *data)
{
(reinterpret_cast<gemmouse*>(data))->mouseButton(which, state, x, y);
}
void gemmouse :: mouseWheelCallback(int axis, int value, void *data)
{
(reinterpret_cast<gemmouse*>(data))->mouseWheel(axis, value);
}

101
Gem/src/Controls/gemmouse.h Normal file
View file

@ -0,0 +1,101 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Respond to mouse events
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMMOUSE_H_
#define _INCLUDE__GEM_CONTROLS_GEMMOUSE_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemmouse
Respond to mouse events
DESCRIPTION
-----------------------------------------------------------------*/
enum t_mousescale { NONE, WIDTH, HEIGHT, BOTH };
class GEM_EXTERN gemmouse : public CPPExtern
{
CPPEXTERN_HEADER(gemmouse, CPPExtern);
public:
//////////
// Constructor
gemmouse(int,t_atom*);
protected:
//////////
// Destructor
virtual ~gemmouse();
//////////
// mouse motion
void mouseMotion(int x, int y);
//////////
// mouse button
void mouseButton(int which, int state, int x, int y);
//////////
// mouse button
void mouseWheel(int axis, int value);
//////////
// The xpos outlet
t_outlet *m_outXPos;
//////////
// The ypos outlet
t_outlet *m_outYPos;
//////////
// The left button outlet
t_outlet *m_outLBut;
//////////
// The middle outlet
t_outlet *m_outMBut;
//////////
// The right outlet
t_outlet *m_outRBut;
//////////
// coordinate-scales
// if !=0, the mouse-coordinate is scaled to 0..m_scale
// if ==0, the mouse-coordinate is scaled to 0..windowsize
t_float m_scaleX, m_scaleY;
//////////
// should Y we scaled separately or like X ?
t_mousescale m_scaleMode;
private:
//////////
// Static member functions
static void mouseMotionCallback(int x, int y, void *data);
static void mouseButtonCallback(int which, int state, int x, int y, void *data);
static void mouseWheelCallback(int axis, int value, void *data);
};
#endif // for header file

View file

@ -0,0 +1,287 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 2008-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "gemreceive.h"
#if 0
# define debug_post ::post
#else
# define debug_post
#endif
static t_class *gemreceive_proxy_class;
struct _bind_element {
gemreceive *object;
t_float priority;
struct _bind_element*next;
};
struct _gemreceive_proxy {
t_object p_obj;
t_symbol*key;
t_bind_element*elements;
struct _gemreceive_proxy*next;
};
t_gemreceive_proxy*gemreceive :: proxy_list = NULL;
t_gemreceive_proxy* gemreceive::find_key(t_symbol*key)
{
t_gemreceive_proxy*binding=0;
for(binding=proxy_list; binding; binding=binding->next) {
if(binding->key == key)
return binding;
}
/* not found */
return 0;
}
t_gemreceive_proxy*gemreceive::add_key(t_symbol*key)
{
t_gemreceive_proxy*bind_list=0;
bind_list=reinterpret_cast<t_gemreceive_proxy*>(pd_new(gemreceive_proxy_class));
bind_list->key=key;
bind_list->elements=0;
bind_list->next=0;
debug_post("binding %x to %s", bind_list, key->s_name);
pd_bind(&bind_list->p_obj.ob_pd, key);
t_gemreceive_proxy*last=proxy_list;
if(last) {
while(last->next) {
last=last->next;
}
last->next = bind_list;
} else {
proxy_list = bind_list;
}
return bind_list;
}
void gemreceive::add_element(t_gemreceive_proxy*bind_list, t_bind_element*element)
{
/* insert the object according to it's priority
* this is already the right queue
*/
t_float priority=element->priority;
t_bind_element*elements=bind_list->elements, *last=0;
debug_post("priority insert of %x:%g", element, priority);
if(!elements || elements->priority >= priority) {
bind_list->elements = element;
element->next = elements;
debug_post("inserting in the beginngin");
return;
}
debug_post("trying %x:%g", elements, elements->priority);
while(elements && elements->priority < priority) {
debug_post("skipping %x:%g to %x", elements, elements->priority, elements->next);
last=elements;
elements=elements->next;
}
debug_post("inserting after %x:%g", last, (last ? (last->priority):0));
debug_post("inserting befor %x:%g", elements, (elements?(elements->priority):0));
element->next=elements;
if(last) {
last->next = element;
} else {
bug("\nlast object invalid when inserting prioritized receiver\n");
}
}
void gemreceive::bind(gemreceive*x, t_symbol*key, t_float priority) {
t_gemreceive_proxy*bind_list=0;
t_bind_element*element=0;
debug_post("trying to bind 0x%X:: '%s':%g via %x", x, key->s_name, priority, proxy_list);
bind_list=find_key(key);
if(!bind_list)
bind_list=add_key(key);
if(!bind_list)return;
element=(t_bind_element*)getbytes(sizeof(t_bind_element));
element->object=x;
element->priority=priority;
element->next=0;
add_element(bind_list, element);
}
void gemreceive::unbind(gemreceive*x, t_symbol*key) {
t_gemreceive_proxy*list=0, *last=0;
t_bind_element*elements=0, *lastlmn=0;
debug_post("trying to unbind 0x%X:: '%s' from %x", x, key->s_name, proxy_list);
for(list=proxy_list; list && list->key!=key; list=list->next){
last=list;
}
if(!list)return;
for(elements=list->elements; elements && elements->object != x; elements=elements->next) {
lastlmn=elements;
}
if(elements) {
/* found it, now remove it */
if(lastlmn) {
lastlmn->next=elements->next;
} else {
list->elements=elements->next;
}
elements->object=0;
elements->priority=0;
elements->next=0;
freebytes(elements, sizeof(elements));
} else {
// not here...
}
if(0==list->elements) {
// should we unbind ??
if(last) {
last->next=list->next;
} else {
proxy_list=list->next;
}
pd_unbind(&list->p_obj.ob_pd, list->key);
list->next=0;
list->key=0;
pd_free(&list->p_obj.ob_pd);
}
}
CPPEXTERN_NEW_WITH_TWO_ARGS(gemreceive, t_symbol*, A_DEFSYMBOL, t_floatarg, A_DEFFLOAT);
/////////////////////////////////////////////////////////
//
// gemreceive
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemreceive :: gemreceive(t_symbol*s,t_floatarg f) :
m_name(s), m_priority(f),
m_outlet(NULL), m_fltin(NULL)
{
debug_post("hi, i am gemreceive 0x%X", this);
m_fltin = inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_float, gensym(""));
m_outlet = outlet_new(this->x_obj, 0);
bind(this, m_name, m_priority);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemreceive :: ~gemreceive()
{
unbind(this, m_name);
if(m_fltin)inlet_free(m_fltin);m_fltin=NULL;
if(m_outlet)outlet_free(m_outlet);m_outlet=NULL;
}
/////////////////////////////////////////////////////////
// receiving
//
/////////////////////////////////////////////////////////
void gemreceive :: receive(t_symbol*s, int argc, t_atom*argv)
{
debug_post("receiveing....%x", m_outlet);
outlet_anything(m_outlet, s, argc, argv);
}
void gemreceive :: nameMess(std::string s) {
if(m_name) {
unbind(this, m_name);
}
m_name=gensym(s.c_str());
bind(this, m_name, m_priority);
}
void gemreceive :: priorityMess(t_float f) {
m_priority=f;
if(m_name) {
unbind(this, m_name);
bind(this, m_name, m_priority);
}
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemreceive :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG1(classPtr, "symbol", nameMess, std::string);
CPPEXTERN_MSG1(classPtr, "", priorityMess, t_float);
gemreceive_proxy_class = class_new(0, 0, 0,
sizeof(t_gemreceive_proxy),
CLASS_NOINLET | CLASS_PD,
A_NULL);
class_addanything(gemreceive_proxy_class, reinterpret_cast<t_method>(gemreceive::proxyCallback));
}
void gemreceive :: proxyCallback(t_gemreceive_proxy*p, t_symbol*s, int argc, t_atom*argv)
{
t_bind_element*elements=p->elements;
debug_post("proxy anything: %x", p);
while(elements) {
gemreceive*o=elements->object;
elements=elements->next;
debug_post("proxy for 0x%X", o);
if(o) {
o->receive(s, argc, argv);
}
}
}

View file

@ -0,0 +1,102 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
ordered receive
Copyright (c) 2008-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMRECEIVE_H_
#define _INCLUDE__GEM_CONTROLS_GEMRECEIVE_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemreceive
[receive] with explicit order
DESCRIPTION
this object is really totally unrelated to Gem.
however, it is included here, in order to replace the current
(integrated) implementation of [gemhead] with an abstraction that makes use
of an ordered [receive]
the original object was [oreceive] in the iemguts library
-----------------------------------------------------------------*/
EXTERN_STRUCT _bind_element;
EXTERN_STRUCT _gemreceive_proxy;
typedef struct _bind_element t_bind_element;
typedef struct _gemreceive_proxy t_gemreceive_proxy;
class GEM_EXTERN gemreceive : public CPPExtern
{
CPPEXTERN_HEADER(gemreceive, CPPExtern);
public:
//////////
// Constructor
gemreceive(t_symbol*s, t_floatarg f=50.f);
protected:
//////////
// Destructor
virtual ~gemreceive();
//////////
// keyboard-button
virtual void receive(t_symbol*s, int argc, t_atom*argv);
//////////
// the symbol we are bound to
void nameMess(std::string);
t_symbol*m_name;
//////////
// the receive priority
void priorityMess(t_float f);
t_float m_priority;
//////////
// The receive outlet
t_outlet *m_outlet;
//////////
// inlet for priority
t_inlet*m_fltin;
private:
//////////
// Static member functions
static void proxyCallback(t_gemreceive_proxy*, t_symbol*s, int argc, t_atom*argv);
static t_gemreceive_proxy*find_key(t_symbol*);
static t_gemreceive_proxy*add_key(t_symbol*);
static void add_element(t_gemreceive_proxy*, t_bind_element*);
static t_gemreceive_proxy*proxy_list;
public:
static void bind(gemreceive*x, t_symbol*name, t_float priority);
static void unbind(gemreceive*x, t_symbol*name);
};
#endif // for header file

728
Gem/src/Controls/gemwin.cpp Normal file
View file

@ -0,0 +1,728 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-2000 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#ifdef __APPLE__
# ifdef __x86_64
# define NO_AUTO_REGISTER_CLASS
# endif
#endif
#include "gemwin.h"
#include "Gem/GemGL.h"
#ifdef __APPLE__
# include <Carbon/Carbon.h>
# include <AvailabilityMacros.h>
#endif // __APPLE__
#include "Utils/GemMath.h"
#include "Gem/Manager.h"
CPPEXTERN_NEW_WITH_ONE_ARG(gemwin, t_floatarg, A_DEFFLOAT);
static bool StillHaveGemWin(bool up) {
static int ref_counter = 0;
if (up){
ref_counter++;
if (ref_counter==1)return false;
} else {
ref_counter--;
if (ref_counter<0)ref_counter=0;
return (ref_counter!=0);
}
return true;
}
/////////////////////////////////////////////////////////
//
// gemwin
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemwin :: gemwin(t_floatarg framespersecond)
: m_FrameRate(NULL)
{
if(!StillHaveGemWin(true)) {
/* this is the only [gemwin] */
GemMan::resetState();
if (framespersecond > 0.)
GemMan::frameRate(framespersecond);
} else {
if(framespersecond>0.)
GemMan::frameRate(framespersecond);
}
m_FrameRate = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
gemwin :: ~gemwin()
{
if(!StillHaveGemWin(false))
GemMan::destroyWindow();
}
/////////////////////////////////////////////////////////
// bangMess
//
/////////////////////////////////////////////////////////
void gemwin :: bangMess()
{
if ( GemMan::windowExists() )
{
if(1==GemMan::m_buffer)
GemMan::swapBuffers();
else /* double buffered mode */
GemMan::render(NULL);
}
else
error("no window");
}
/////////////////////////////////////////////////////////
// intMess
//
/////////////////////////////////////////////////////////
void gemwin :: intMess(int state)
{
if (state)
GemMan::startRendering();
else
GemMan::stopRendering();
}
/////////////////////////////////////////////////////////
// renderMess
//
/////////////////////////////////////////////////////////
void gemwin :: renderMess()
{
if (GemMan::getRenderState())
GemMan::render(NULL);
else
error("not in render mode");
}
/////////////////////////////////////////////////////////
// titleMess
//
/////////////////////////////////////////////////////////
void gemwin :: titleMess(t_symbol* s)
{
GemMan::m_title = s->s_name;
}
/////////////////////////////////////////////////////////
// createMess
//
/////////////////////////////////////////////////////////
void gemwin :: createMess(t_symbol* s)
{
char* disp = NULL;
/* just in case a "pleaseDestroy" is still pending... */
GemMan::pleaseDestroy=false;
if (s != &s_)
disp = s->s_name;
if ( !GemMan::windowExists() ) {
GemMan::createContext(disp);
if ( !GemMan::createWindow(disp) ) {
error("no window made");
return;
}
GemMan::swapBuffers();
GemMan::swapBuffers();
} else
error("window already made");
}
/////////////////////////////////////////////////////////
// bufferMess
//
/////////////////////////////////////////////////////////
void gemwin :: bufferMess(int buf)
{
if (buf == 1)
GemMan::m_buffer = 1;
else
GemMan::m_buffer = 2;
}
/////////////////////////////////////////////////////////
// stereoMess
//
/////////////////////////////////////////////////////////
void gemwin :: stereoMess(int mode)
{
if (mode<0){
error("stereo-mode must not be %d", mode);
return;
}
if (mode>1) {
error("only stereo-modes 1/0 are allowed!!!");
return;
}
GemMan::m_stereo = mode;
}
/////////////////////////////////////////////////////////
// fullscreenMess
//
/////////////////////////////////////////////////////////
void gemwin :: fullscreenMess(int on)
{
GemMan::m_fullscreen = on;
}
/////////////////////////////////////////////////////////
// menuBarMess 1 = show -1 = hide, but autoshow
// 0 = hide, but neverShow
/////////////////////////////////////////////////////////
void gemwin :: menuBarMess(int on)
{
GemMan::m_menuBar = on;
#ifdef __APPLE__
if (on == 0) {
SetSystemUIMode( kUIModeAllHidden, kUIOptionDisableAppleMenu |
kUIOptionDisableProcessSwitch |
kUIOptionDisableSessionTerminate |
kUIOptionDisableForceQuit );
}else if (on > 0) {
SetSystemUIMode( kUIModeNormal, 0 );
}else if (on < 0) {
SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar );
}
#endif
}
/////////////////////////////////////////////////////////
// secondScreen
//
/////////////////////////////////////////////////////////
void gemwin :: secondscreenMess(int on)
{
GemMan::m_secondscreen = on;
}
/////////////////////////////////////////////////////////
// dimensionsMess
//
/////////////////////////////////////////////////////////
void gemwin :: dimensionsMess(int width, int height)
{
if (width <= 0) {
error("width must be greater than 0");
return;
}
if (height <= 0 ) {
error ("height must be greater than 0");
return;
}
GemMan::m_width = width;
GemMan::m_height = height;
}
/////////////////////////////////////////////////////////
// offsetMess
//
/////////////////////////////////////////////////////////
void gemwin :: offsetMess(int x, int y)
{
GemMan::m_xoffset = x;
GemMan::m_yoffset = y;
}
/////////////////////////////////////////////////////////
// colorMess
//
/////////////////////////////////////////////////////////
void gemwin :: colorMess(float red, float green, float blue, float alpha)
{
GemMan::m_clear_color[0] = red;
GemMan::m_clear_color[1] = green;
GemMan::m_clear_color[2] = blue;
GemMan::m_clear_color[3] = alpha;
if ( GemMan::windowExists() ) {
glClearColor(red, green, blue, alpha);
}
}
/////////////////////////////////////////////////////////
// clearmaskMess
//
/////////////////////////////////////////////////////////
void gemwin :: clearmaskMess(float bitmask)
{
GemMan::m_clear_mask = static_cast<GLbitfield>(bitmask);
}
/////////////////////////////////////////////////////////
// ambientMess
//
/////////////////////////////////////////////////////////
void gemwin :: ambientMess(float red, float green, float blue, float alpha)
{
GemMan::m_mat_ambient[0] = red;
GemMan::m_mat_ambient[1] = green;
GemMan::m_mat_ambient[2] = blue;
GemMan::m_mat_ambient[3] = blue;
}
/////////////////////////////////////////////////////////
// specularMess
//
/////////////////////////////////////////////////////////
void gemwin :: specularMess(float red, float green, float blue, float alpha)
{
GemMan::m_mat_specular[0] = red;
GemMan::m_mat_specular[1] = green;
GemMan::m_mat_specular[2] = blue;
GemMan::m_mat_specular[2] = alpha;
}
/////////////////////////////////////////////////////////
// shininessMess
//
/////////////////////////////////////////////////////////
void gemwin :: shininessMess(float val)
{
GemMan::m_mat_shininess = val;
}
/////////////////////////////////////////////////////////
// fogDensityMess
//
/////////////////////////////////////////////////////////
void gemwin :: fogDensityMess(float val)
{
if (val < 0.f)
val = 0.f;
GemMan::m_fog = val;
}
/////////////////////////////////////////////////////////
// fogRangeMess
//
/////////////////////////////////////////////////////////
void gemwin :: fogRangeMess(float start, float end)
{
if (start < 0.f)
start= 0.f;
if (end < 0.f)
end = 0.f;
GemMan::m_fogStart = start;
GemMan::m_fogEnd = end;
}
/////////////////////////////////////////////////////////
// fogColorMess
//
/////////////////////////////////////////////////////////
void gemwin :: fogColorMess(float red, float green, float blue, float alpha)
{
GemMan::m_fogColor[0] = red;
GemMan::m_fogColor[1] = green;
GemMan::m_fogColor[2] = blue;
GemMan::m_fogColor[3] = alpha;
}
/////////////////////////////////////////////////////////
// fogModeMess
//
/////////////////////////////////////////////////////////
void gemwin :: fogModeMess(int mode)
{
switch (mode)
{
case 0 :
GemMan::m_fogMode = GemMan::FOG_OFF;
break;
case 1 :
GemMan::m_fogMode = GemMan::FOG_LINEAR;
break;
case 2 :
GemMan::m_fogMode = GemMan::FOG_EXP;
break;
case 3 :
GemMan::m_fogMode = GemMan::FOG_EXP2;
break;
default :
error("fogmode must be 0, 1, 2 or 3");
break;
}
}
/////////////////////////////////////////////////////////
// cursorMess
//
/////////////////////////////////////////////////////////
void gemwin :: cursorMess(float setting)
{
GemMan :: cursorOnOff(static_cast<int>(setting));
}
/////////////////////////////////////////////////////////
// topmostMess
//
/////////////////////////////////////////////////////////
void gemwin :: topmostMess(float topmost)
{
GemMan::topmostOnOff(static_cast<int>(topmost));
}
/////////////////////////////////////////////////////////
// cursorMess
//
/////////////////////////////////////////////////////////
void gemwin :: blurMess(float setting)
{
if (setting>=0.f && setting <= 1.f)
GemMan :: m_motionBlur = setting;
}
/////////////////////////////////////////////////////////
// fpsMess
//
/////////////////////////////////////////////////////////
void gemwin :: fpsMess()
{
outlet_float(m_FrameRate,GemMan :: fps);
}
/////////////////////////////////////////////////////////
// fsaaMess
//
/////////////////////////////////////////////////////////
void gemwin :: fsaaMess(int value)
{
if (value == 2 || value == 4 || value == 8){
GemMan :: fsaa = value;
}
else{
GemMan :: fsaa = value;
}
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void gemwin :: obj_setupCallback(t_class *classPtr)
{
CPPEXTERN_MSG0(classPtr, "bang", bangMess);
CPPEXTERN_MSG1(classPtr, "float", intMess, int);
CPPEXTERN_MSG0(classPtr, "render", renderMess);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::titleMessCallback),
gensym("title"), A_DEFSYM ,A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::createMessCallback),
gensym("create"), A_DEFSYM ,A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::createStereoMessCallback),
gensym("createStereo"), A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::createStereoMessCallback),
gensym("createstereo"), A_NULL);
CPPEXTERN_MSG1(classPtr, "buffer", bufferMess, int);
CPPEXTERN_MSG1(classPtr, "fullscreen", fullscreenMess, int);
CPPEXTERN_MSG1(classPtr, "menubar", menuBarMess, int);
CPPEXTERN_MSG1(classPtr, "secondscreen", secondscreenMess, int);
CPPEXTERN_MSG1(classPtr, "topmost", topmostMess, int);
CPPEXTERN_MSG2(classPtr, "dimen", dimensionsMess, int, int);
CPPEXTERN_MSG2(classPtr, "offset", offsetMess, int, int);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::colorMessCallback),
gensym("color"), A_GIMME, A_NULL);
CPPEXTERN_MSG1(classPtr, "clearmask", clearmaskMess, float);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::perspectiveMessCallback),
gensym("perspec"), A_GIMME, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::viewMessCallback),
gensym("view"), A_GIMME, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::fogMessCallback),
gensym("fog"), A_GIMME, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::fogColorMessCallback),
gensym("fogcolor"), A_GIMME, A_NULL);
CPPEXTERN_MSG1(classPtr, "fogmode", fogModeMess, int);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::ambientMessCallback),
gensym("ambient"), A_GIMME, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::specularMessCallback),
gensym("specular"), A_GIMME, A_NULL);
CPPEXTERN_MSG1(classPtr, "shininess", shininessMess, float);
CPPEXTERN_MSG1(classPtr, "cursor", cursorMess, float);
CPPEXTERN_MSG1(classPtr, "blur", blurMess, float);
// just call GemMan directly
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::resetMessCallback),
gensym("reset"), A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::destroyMessCallback),
gensym("destroy"), A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::printMessCallback),
gensym("print"), A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::profileMessCallback),
gensym("profile"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::lightingMessCallback),
gensym("lighting"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoMessCallback),
gensym("stereo"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoSepMessCallback),
gensym("stereoSep"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoFocMessCallback),
gensym("stereoFoc"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoSepMessCallback),
gensym("stereosep"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoFocMessCallback),
gensym("stereofoc"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoLineMessCallback),
gensym("stereoLine"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::stereoLineMessCallback),
gensym("stereoline"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::borderMessCallback),
gensym("border"), A_FLOAT, A_NULL);
class_addmethod(classPtr, reinterpret_cast<t_method>(&gemwin::frameMessCallback),
gensym("frame"), A_FLOAT, A_NULL);
CPPEXTERN_MSG0(classPtr, "fps", fpsMess);
CPPEXTERN_MSG1(classPtr, "FSAA", fsaaMess, int);
}
void gemwin :: printMessCallback(void *)
{
GemMan::printInfo();
}
void gemwin :: profileMessCallback(void *, t_float state)
{
GemMan::m_profile = static_cast<int>(state);
}
void gemwin :: lightingMessCallback(void *, t_float state)
{
GemMan::lightingOnOff(static_cast<int>(state));
}
void gemwin :: fogMessCallback(void *data, t_symbol *, int argc, t_atom *argv)
{
switch (argc)
{
case (1):
GetMyClass(data)->fogDensityMess(atom_getfloat(&argv[0]));
break;
case (2):
GetMyClass(data)->fogRangeMess(atom_getfloat(&argv[0]),atom_getfloat(&argv[1]));
break;
default:
GetMyClass(data)->error("fog message needs 1 or 2 arguments");
}
}
void gemwin :: fogColorMessCallback(void *data, t_symbol*s,int argc, t_atom*argv)
{
float red, green, blue, alpha=1.f;
switch(argc){
case 4:
alpha=atom_getfloat(argv+3);
case 3:
red= atom_getfloat(argv);
green=atom_getfloat(argv+1);
blue= atom_getfloat(argv+2);
GetMyClass(data)->fogColorMess(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha));
break;
default:
GetMyClass(data)->error("\"fogcolor\" expects 3 or 4 values");
}
}
void gemwin :: stereoMessCallback(void *data, t_float state)
{
int mode = static_cast<int>(state);
if (mode<0 || mode>3){
GetMyClass(data)->error("possible stereo-modes are: 0, 1, 2, 3");
return;
}
GemMan::m_stereo = mode;
}
void gemwin :: stereoSepMessCallback(void *, t_float state)
{
GemMan::m_stereoSep = state;
}
void gemwin :: stereoFocMessCallback(void *, t_float state)
{
GemMan::m_stereoFocal = state;
}
void gemwin :: stereoLineMessCallback(void *, t_float state)
{
GemMan::m_stereoLine = (state!=0.0);
}
void gemwin :: borderMessCallback(void *, t_float state)
{
GemMan::m_border = static_cast<int>(state);
}
void gemwin :: destroyMessCallback(void *)
{
GemMan::destroyWindow();
}
void gemwin :: resetMessCallback(void *)
{
GemMan::resetState();
}
void gemwin :: frameMessCallback(void *, t_float rate)
{
GemMan::frameRate(static_cast<float>(rate));
}
void gemwin :: perspectiveMessCallback(void *data, t_symbol *, int argc, t_atom *argv)
{
if (argc != 6)
{
GetMyClass(data)->error("perspec message needs 6 arguments");
return;
}
GemMan::m_perspect[0] = atom_getfloat(&argv[0]); // left
GemMan::m_perspect[1] = atom_getfloat(&argv[1]); // right
GemMan::m_perspect[2] = atom_getfloat(&argv[2]); // bottom
GemMan::m_perspect[3] = atom_getfloat(&argv[3]); // top
GemMan::m_perspect[4] = atom_getfloat(&argv[4]); // front
GemMan::m_perspect[5] = atom_getfloat(&argv[5]); // back
}
void gemwin :: viewMessCallback(void *data, t_symbol *, int argc, t_atom *argv)
{
const float DEG2RAD = 0.01745329251994f;
float azimuth = 0.f;
float theta = 0.f;
float distance = 1.f;
if (GemMan::m_stereoFocal > 0)
{
distance = GemMan::m_stereoFocal;
}
switch (argc)
{
// setting all lookat values directly
case 9 :
GemMan::m_lookat[0] = atom_getfloat(&argv[0]); // eyex
GemMan::m_lookat[1] = atom_getfloat(&argv[1]); // eyey
GemMan::m_lookat[2] = atom_getfloat(&argv[2]); // eyez
GemMan::m_lookat[3] = atom_getfloat(&argv[3]); // centerx
GemMan::m_lookat[4] = atom_getfloat(&argv[4]); // centery
GemMan::m_lookat[5] = atom_getfloat(&argv[5]); // centerz
GemMan::m_lookat[6] = atom_getfloat(&argv[6]); // upx
GemMan::m_lookat[7] = atom_getfloat(&argv[7]); // upy
GemMan::m_lookat[8] = atom_getfloat(&argv[8]); // upz
break;
case 5 :
theta = static_cast<float>(DEG2RAD) * atom_getfloat(&argv[4]);
case 4 :
azimuth = static_cast<float>(DEG2RAD) * atom_getfloat(&argv[3]);
// just have position
case 3 :
{
const float dx = static_cast<float>(cos(theta) * sinf(azimuth));
const float dy = static_cast<float>(sin(theta));
const float dz = -static_cast<float>(cos(theta) * cosf(azimuth));
GemMan::m_lookat[0] = atom_getfloat(&argv[0]); // eyex
GemMan::m_lookat[1] = atom_getfloat(&argv[1]); // eyey
GemMan::m_lookat[2] = atom_getfloat(&argv[2]); // eyez
GemMan::m_lookat[3] = GemMan::m_lookat[0] + dx * distance; // centerx
GemMan::m_lookat[4] = GemMan::m_lookat[1] + dy * distance; // centery
GemMan::m_lookat[5] = GemMan::m_lookat[2] + dz * distance; // centery
GemMan::m_lookat[6] = -dx*dy; // upx
GemMan::m_lookat[7] = dx*dx+dz*dz; // upy
GemMan::m_lookat[8] = -dy*dz; // upz
}
break;
default:
GetMyClass(data)->error("view message needs 3, 4, 5 or 9 arguments");
// note :: LATER set the StereoView ...
}
}
void gemwin :: titleMessCallback(void *data, t_symbol* disp)
{
GetMyClass(data)->titleMess(disp);
}
void gemwin :: createMessCallback(void *data, t_symbol* disp)
{
GetMyClass(data)->createMess(disp);
}
void gemwin :: createStereoMessCallback(void *data)
{
GetMyClass(data)->error("'createStereo' is deprecated and does not work any more");
GetMyClass(data)->error("use 'stereo 1' + 'create' instead");
}
void gemwin :: colorMessCallback(void *data, t_symbol*s, int argc, t_atom*argv)
{
float red, green, blue, alpha=0.f;
switch(argc){
case 4:
alpha=atom_getfloat(argv+3);
case 3:
red= atom_getfloat(argv);
green=atom_getfloat(argv+1);
blue= atom_getfloat(argv+2);
GetMyClass(data)->colorMess(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha));
break;
default:
GetMyClass(data)->error("\"color\" expects 3 or 4 values");
}
}
void gemwin :: ambientMessCallback(void *data, t_symbol*s,int argc, t_atom*argv)
{
float red, green, blue, alpha=1.f;
switch(argc){
case 4:
alpha=atom_getfloat(argv+3);
case 3:
red= atom_getfloat(argv);
green=atom_getfloat(argv+1);
blue= atom_getfloat(argv+2);
GetMyClass(data)->ambientMess(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha));
break;
default:
GetMyClass(data)->error("\"ambient\" expects 3 or 4 values");
}
}
void gemwin :: specularMessCallback(void *data, t_symbol*s,int argc, t_atom*argv)
{
float red, green, blue, alpha=1.f;
switch(argc){
case 4:
alpha=atom_getfloat(argv+3);
case 3:
red= atom_getfloat(argv);
green=atom_getfloat(argv+1);
blue= atom_getfloat(argv+2);
GetMyClass(data)->specularMess(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha));
break;
default:
GetMyClass(data)->error("\"specular\" expects 3 or 4 values");
}
}

144
Gem/src/Controls/gemwin.h Normal file
View file

@ -0,0 +1,144 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Interface for the window manager
Copyright (c) 1997-200 Mark Danks.
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_GEMWIN_H_
#define _INCLUDE__GEM_CONTROLS_GEMWIN_H_
#include "Base/CPPExtern.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
gemwin
The window manager
DESCRIPTION
Access to GemMan.
"int" - turn on/off the rendering (in double buffered mode)
"bang" - swap the buffers
"render" - render a frame now
"title" - set a title for the graphics window
"create" - create a graphics window
"destroy" - destroy the graphics window
"buffer" - single or double buffering
"fullscreen" - fullscreen mode
"topmost" - set the window to stay on top
"dimen" - the window dimensions
"offset" - the window offset
"frame" - the frame rate
"lighting" - turn lighting on/off
"ambient" - the ambient light color
"specular" - the specular light color
"shininess" - the shininess value
"stereo" - select stereo-mode (0=off; 1=normal)
"stereoSep" - the stereo separation
"stereoFoc" - the distance to the focal point
"stereoLine" - draw a line between two stereo screens...
"perspective" - set the perspective viewing
"reset" - reset the graphics manager to the initial state
"color" - rgb color for clearing
"profile #" - turn on/off profiling (time per frame)
- # == 0 : turn off
- # == 1 : turn on
- # == 2 : turn on without image caching
"view" - set the viewpoint
"fogmode" - set the fog mode
- 0 : FOG_OFF
- 1 : FOG_LINEAR (from begin to end)
- 2 : FOG_EXP (density) (default)
- 3 : FOG_EXP2 (density)
"fog" - set the fog density or begin/end of the fog
"fogcolor" - the fog color
-----------------------------------------------------------------*/
class GEM_EXTERN gemwin : public CPPExtern
{
CPPEXTERN_HEADER(gemwin, CPPExtern);
public:
//////////
// Constructor
gemwin(t_floatarg framespersecond);
private:
//////////
// Destructor
virtual ~gemwin();
void bangMess();
void intMess(int state);
void renderMess();
void titleMess(t_symbol* s);
void createMess(t_symbol* s);
void stereoMess(int mode);
void bufferMess(int buf);
void dimensionsMess(int width, int height);
void fullscreenMess(int on);
void menuBarMess(int on);
void secondscreenMess(int on);
void offsetMess(int x, int y);
void colorMess(float red, float green, float blue, float alpha);
void clearmaskMess(float bitmask);
void ambientMess(float red, float green, float blue, float alpha);
void specularMess(float red, float green, float blue, float alpha);
void shininessMess(float val);
void fogModeMess(int mode);
void fogDensityMess(float val);
void fogRangeMess(float start, float end);
void fogColorMess(float red, float green, float blue, float alpha);
void cursorMess(float setting);
void topmostMess(float settting);
void blurMess(float setting);
void fpsMess();
void fsaaMess(int value);
t_outlet *m_FrameRate;
private:
//////////
// Static member functions
static void titleMessCallback(void *data, t_symbol* s);
static void createMessCallback(void *data, t_symbol* s);
static void createStereoMessCallback(void *data);
static void colorMessCallback(void *data, t_symbol*,int,t_atom*);
static void ambientMessCallback(void *data, t_symbol*,int,t_atom*);
static void specularMessCallback(void *data, t_symbol*,int,t_atom*);
static void fogMessCallback(void *, t_symbol *, int argc, t_atom *argv);
static void fogColorMessCallback(void *, t_symbol*,int,t_atom*);
// just call GemMan directly
static void destroyMessCallback(void *);
static void printMessCallback(void *);
static void profileMessCallback(void *, t_float state);
static void resetMessCallback(void *);
static void lightingMessCallback(void *, t_float state);
static void borderMessCallback(void *, t_float state);
static void frameMessCallback(void *, t_float framesPerSecond);
static void perspectiveMessCallback(void *, t_symbol *, int argc, t_atom *argv);
static void viewMessCallback(void *, t_symbol *, int argc, t_atom *argv);
static void stereoMessCallback(void *data, t_float state);
static void stereoFocMessCallback(void *, t_float state);
static void stereoSepMessCallback(void *, t_float state);
static void stereoLineMessCallback(void *, t_float state);
};
#endif // for header file

View file

@ -0,0 +1,68 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "render_trigger.h"
CPPEXTERN_NEW(render_trigger);
/////////////////////////////////////////////////////////
//
// render_trigger
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
render_trigger :: render_trigger()
{
m_preOut = outlet_new(this->x_obj, 0);
m_postOut = outlet_new(this->x_obj, 0);
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
render_trigger :: ~render_trigger()
{
outlet_free(m_preOut);
outlet_free(m_postOut);
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void render_trigger :: render(GemState *)
{
outlet_bang(m_preOut);
}
/////////////////////////////////////////////////////////
// postrender
//
/////////////////////////////////////////////////////////
void render_trigger :: postrender(GemState *)
{
outlet_bang(m_postOut);
}
/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void render_trigger :: obj_setupCallback(t_class *)
{ }

View file

@ -0,0 +1,63 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Send out a bang on pre and post render
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_CONTROLS_RENDER_TRIGGER_H_
#define _INCLUDE__GEM_CONTROLS_RENDER_TRIGGER_H_
#include "Base/GemBase.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
render_trigger
Send out a bang on pre and post render
DESCRIPTION
"render_triggerstate" - whether to use render_trigger blending
-----------------------------------------------------------------*/
class GEM_EXTERN render_trigger : public GemBase
{
CPPEXTERN_HEADER(render_trigger, GemBase);
public:
//////////
// Constructor
render_trigger();
protected:
//////////
// Destructor
virtual ~render_trigger();
//////////
// Push the current state
virtual void render(GemState *state);
//////////
// Pop the state
virtual void postrender(GemState *state);
//////////
t_outlet *m_preOut; // bang for the pre render
//////////
t_outlet *m_postOut; // bang for the post render
};
#endif // for header file

64
Gem/src/Gem/Cache.cpp Normal file
View file

@ -0,0 +1,64 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "Cache.h"
#include "Controls/gemhead.h"
/////////////////////////////////////////////////////////
//
// GemCache
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemCache :: GemCache(gemhead *parent)
: dirty(true), resendImage(false), vertexDirty(false),
m_parent(parent), m_magic(GEMCACHE_MAGIC)
{
}
GemCache :: GemCache(const GemCache&org)
: dirty(org.dirty), resendImage(org.resendImage), vertexDirty(org.vertexDirty),
m_parent(org.m_parent), m_magic(GEMCACHE_MAGIC)
{
}
void GemCache :: reset(gemhead *parent)
{
dirty =true;
resendImage=false;
vertexDirty=false;
m_parent =parent;
m_magic =GEMCACHE_MAGIC;
}
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
GemCache :: ~GemCache(void)
{
m_magic=0xFFFFFFF;
m_parent=NULL;
}
GemCache&GemCache::operator=(const GemCache&org) {
dirty=org.dirty;
resendImage=org.resendImage;
vertexDirty=org.vertexDirty;
m_parent=org.m_parent;
m_magic=GEMCACHE_MAGIC;
return *this;
}

74
Gem/src/Gem/Cache.h Normal file
View file

@ -0,0 +1,74 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The state to pass among GEM objects
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_CACHE_H_
#define _INCLUDE__GEM_GEM_CACHE_H_
#include "Gem/ExportDef.h"
class gemhead;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemCache
The cache to pass among GEM objects
DESCRIPTION
-----------------------------------------------------------------*/
#define GEMCACHE_MAGIC 0x1234567
class GEM_EXTERN GemCache
{
public:
//////////
// Constructor
GemCache(gemhead *parent);
GemCache(const GemCache&);
//////////
// Destructor
virtual ~GemCache(void);
virtual GemCache& operator=(const GemCache&);
//////////
// Was a modification made which will void a display list?
bool dirty;
//////////
// Should the image be resent?
bool resendImage;
//////////
// has the Vertex-Array changed?
bool vertexDirty;
//////////
// re-set (like creation, but without instantiating
void reset(gemhead*parent);
//////////
gemhead *m_parent;
//////////
// indicates a valid cache
int m_magic;
};
#endif // for header file

View file

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
#include "ContextData.h"
#include "Base/GemContext.h"
using namespace gem;
/* LATER, when we have multiple contexts, this should really be "-1" or such
*/
const int ContextDataBase::INVALID_CONTEXT=0;
int ContextDataBase::getCurContext(void) {
/* this should get an integer-index of the current context from GemContext */
int id=0;
id=gem::Context::getContextId();
return id;
}
ContextDataBase::~ContextDataBase(void) {
}

149
Gem/src/Gem/ContextData.h Normal file
View file

@ -0,0 +1,149 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
data specific to a rendering context
Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_CONTEXTDATA_H_
#define _INCLUDE__GEM_GEM_CONTEXTDATA_H_
#include "Gem/ExportDef.h"
#include <vector>
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
ContextData
rendering context specific data
this is heavily inspired by VrJuggler
DESCRIPTION
several things in openGL like display-lists are context dependent
if we have multiple contexts, such values most be generated for each context
ContextData provides a generic (templated) datatype for this
LATER (SOONER) think about splitting the render() into a context-specific section that
set's up display-lists,... and a draw() function that just calls the pre-generated values
-----------------------------------------------------------------*/
namespace gem {
class GEM_EXTERN ContextDataBase {
protected:
static const int INVALID_CONTEXT;
virtual int getCurContext(void);
virtual ~ContextDataBase(void);
};
template<class ContextDataType = int>
class GEM_EXTERN ContextData : ContextDataBase
{
private:
public:
//////////
// Constructor
ContextData(void) : m_haveDefaultValue(false) {;}
ContextData(ContextDataType v) : m_haveDefaultValue(true), m_defaultValue(v) {;}
virtual ~ContextData() {
m_ContextDataVector.clear();
}
/**
* returns the context-specific value
*
* @usage ContextData<GLenum>m_fun; m_fun=GL_FUNC_ADD;
*
* @pre We are in a draw process.
* @note Should only be called from the draw function.
* Results are un-defined for other functions.
*/
virtual operator ContextDataType()
{
return (*getPtrToCur());
}
/**
* assigns a value to the correct context
*
* @pre We are in a draw process.
* @note Should only be called from the draw function.
* Results are un-defined for other functions.
*/
virtual ContextDataType&operator = (ContextDataType value)
{
/* simplistic approach to handle out-of-context assignments:
* assign the value to all context instances
*/
if(INVALID_CONTEXT==getCurContext()) {
doSetAll(value);
}
return (*getPtrToCur()=value);
}
private:
bool m_haveDefaultValue;
ContextDataType m_defaultValue;
std::vector<ContextDataType*> m_ContextDataVector;
/* Makes sure that the vector is at least requiredSize large */
void checkSize(unsigned int requiredSize)
{
if(requiredSize > m_ContextDataVector.size())
{
m_ContextDataVector.reserve(requiredSize); // Resize smartly
while(m_ContextDataVector.size() < requiredSize) // Add any new items needed
{
if(m_haveDefaultValue) {
m_ContextDataVector.push_back(new ContextDataType(m_defaultValue));
} else {
m_ContextDataVector.push_back(new ContextDataType);
}
}
}
}
/**
* Returns a pointer to the correct data element in the current context.
*
* @pre We are in the draw function.
* @post Synchronized.
* @note ASSERT: Same context is rendered by same thread each time.
*/
ContextDataType* getPtrToCur(void)
{
// Get current context
int context_id = getCurContext();
// Cache ref for better performance
checkSize(context_id+1); // Make sure we are large enough (+1 since we have index)
return m_ContextDataVector[context_id];
}
void doSetAll(ContextDataType v)
{
unsigned int i=0;
for(i=0; i< m_ContextDataVector.size(); i++) {
*m_ContextDataVector[i]=v;
}
}
};
};
#endif // for header file

327
Gem/src/Gem/Dylib.cpp Normal file
View file

@ -0,0 +1,327 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 1997-2000 Mark Danks.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2002 James Tittle & Chris Clepper
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
// a wrapper for calling Pd's sys_register_loader()
//
/////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma warning( disable: 4091)
# define snprintf _snprintf
#endif /* _MSC_VER */
#include "Dylib.h"
#include "Files.h"
#include "Base/CPPExtern.h"
#include <string>
#include <stdio.h>
#if defined __linux__ || defined __APPLE__ || defined __FreeBSD_kernel__
#include <unistd.h>
# define DL_OPEN
#endif
#ifdef DL_OPEN
# include <dlfcn.h>
#endif
#if defined _WIN32
# include <io.h>
# include <windows.h>
#endif
#include <iostream>
class GemDylibHandle {
public:
std::string fullname;
#ifdef DL_OPEN
void * dlhandle;
#endif
#ifdef _WIN32
HINSTANCE w32handle;
#endif
int dummy2;
GemDylibHandle(void) :
fullname(std::string()),
#ifdef DL_OPEN
dlhandle(NULL),
#endif
#ifdef _WIN32
w32handle(NULL),
#endif
dummy2(0)
{;}
~GemDylibHandle(void) {
close();
}
static std::string getFullfilename(const t_canvas*canvas, const char*filename, const char*ext) {
std::string fullname_;
char buf[MAXPDSTRING];
char*bufptr;
int fd=0;
if ((fd=canvas_open(const_cast<t_canvas*>(canvas), filename, ext, buf, &bufptr, MAXPDSTRING, 1))>=0){
gem::files::close(fd);
fullname_=buf;
fullname_+="/";
fullname_+=bufptr;
} else {
if(canvas) {
canvas_makefilename(const_cast<t_canvas*>(canvas), const_cast<char*>(filename), buf, MAXPDSTRING);
fullname_=buf;
} else {
return std::string("");
}
}
return fullname_;
}
static GemDylibHandle*open(const std::string filename) {
GemDylibHandle*handle=new GemDylibHandle();
char buf[MAXPDSTRING];
if(filename.empty()) {
throw(GemException(std::string("No DyLib name given!")));
}
sys_bashfilename(filename.c_str(), buf);
#ifdef DL_OPEN
handle->dlhandle=dlopen(filename.c_str(), RTLD_NOW);
if(handle->dlhandle) {
handle->fullname=filename;
return handle;
}
#endif
#ifdef _WIN32
UINT errorboxflags=SetErrorMode(SEM_FAILCRITICALERRORS);
SetLastError(0);
handle->w32handle=LoadLibrary(buf);
DWORD errorNumber = GetLastError();
errorboxflags=SetErrorMode(errorboxflags);
if(handle->w32handle) {
handle->fullname=filename;
return handle;
}
#endif
delete handle;
handle=NULL;
std::string errormsg;
#ifdef DL_OPEN
errormsg=dlerror();
if(!errormsg.empty()) {
std::string error="dlerror '";
error+=errormsg;
error+="'";
throw(GemException(error));
}
#endif
#ifdef _WIN32
LPVOID lpErrorMessage=NULL;
if(errorNumber) {
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errorNumber,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpErrorMessage,
0, NULL );
}
std::cerr << "GemDylib failed: #"<<errorNumber<<": ";
if(lpErrorMessage) {
std::cerr<<(const char*)lpErrorMessage;
}else {
std::cerr<<"(unknown)";
}
std::cerr<<std::endl;
std::string error = "DLLerror(";
char errbuf[10];
snprintf(errbuf, 10, "0x%x", errorNumber);
errbuf[10-1]=0;
error+=errbuf;
error+=")";
if(lpErrorMessage) {
error+=(const char*)lpErrorMessage;
}
std::cerr << "GemDylib throwing: "<< error << std::endl;
throw(GemException(std::string(error)));
#endif
return NULL;
}
static GemDylibHandle*open(const CPPExtern*obj, const std::string filename, const std::string extension) {
const t_canvas*canvas=(obj)?(canvas=const_cast<CPPExtern*>(obj)->getCanvas()):0;
const char*ext=extension.c_str();
//std::string fullname=getFullfilename(canvas, filename.c_str(), ext);
std::string fullname=gem::files::getFullpath(filename+ext, obj);
if(fullname.empty()) {
//fullname=getFullfilename(canvas, filename.c_str(), GemDylibHandle::defaultExtension.c_str());
fullname=gem::files::getFullpath(filename+GemDylibHandle::defaultExtension, obj);
}
if(fullname.empty()) {
std::string error="couldn't find '";
error+=filename;
error+="'.'";
error+=ext;
error+="'";
throw(GemException(error));
}
return open(fullname);
}
static const std::string defaultExtension;
void close(void) {
#ifdef DL_OPEN
if(dlhandle)
dlclose(dlhandle);
dlhandle=NULL;
#endif
#ifdef _WIN32
if(w32handle)
FreeLibrary(w32handle);
w32handle=NULL;
#endif
}
};
const std::string GemDylibHandle::defaultExtension =
#ifdef _WIN32
std::string(".dll")
#elif defined DL_OPEN
std::string(".so")
#else
std::string("")
#endif
;
GemDylib::GemDylib(const CPPExtern*obj, const std::string filename, const std::string extension)
throw (GemException) :
m_handle(0) {
m_handle=GemDylibHandle::open(obj, filename, extension);
if(NULL==m_handle) {
std::string err="unable to open '";
err+=filename;
if(!extension.empty()) {
err+=".";
err+=extension;
}
err+="'";
throw GemException(err);
}
}
GemDylib::GemDylib(const std::string filename, const std::string extension) throw (GemException) : m_handle(0) {
m_handle=GemDylibHandle::open(0, filename, extension);
if(NULL==m_handle) {
std::string err="unable to open '";
err+=filename;
if(!extension.empty()) {
err+=".";
err+=extension;
}
err+="'";
throw GemException(err);
}
}
GemDylib::GemDylib(const GemDylib&org) : m_handle(NULL) {
std::string filename=org.m_handle->fullname;
m_handle=GemDylibHandle::open(filename);
if(NULL==m_handle) {
std::string err="unable to open '";
err+=filename;
err+="'";
throw GemException(err);
}
}
GemDylib::~GemDylib(void) {
if(m_handle)
delete m_handle;
m_handle=NULL;
}
GemDylib& GemDylib::operator=(const GemDylib&org) {
if(m_handle)
delete m_handle;
m_handle=NULL;
if(org.m_handle) {
m_handle=GemDylibHandle::open(org.m_handle->fullname);
}
return *this;
}
GemDylib::function_t GemDylib::proc(const std::string procname) {
function_t result=NULL;
// if(NULL==procname)return NULL;
#ifdef DL_OPEN
dlerror();
if(m_handle->dlhandle)
result=(function_t)(dlsym(m_handle->dlhandle, procname.c_str()));
if(NULL!=result)return result;
#endif
#ifdef _WIN32
if(m_handle->w32handle)
result=(function_t)(GetProcAddress(m_handle->w32handle, procname.c_str()));
if(NULL!=result)return result;
#endif
return result;
}
bool GemDylib::run(const std::string procname) {
function_t runproc=proc(procname);
if(runproc) {
(runproc)();
return true;
}
return false;
}
bool GemDylib::LoadLib(const std::string basefilename, const std::string extension, const std::string procname) {
try {
GemDylib*dylib=new GemDylib(basefilename, extension);
if(NULL!=dylib) {
dylib->run(procname);
return true;
}
} catch (GemException&x) {
std::cerr << "GemDylib::LoadLib: "<<x.what()<<std::endl;
}
return false;
}
const std::string GemDylib::getDefaultExtension(void) {
return GemDylibHandle::defaultExtension;
}

68
Gem/src/Gem/Dylib.h Normal file
View file

@ -0,0 +1,68 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
- registers a loader with Pd
Copyright (c) 2010-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_DYLIB_H_
#define _INCLUDE__GEM_GEM_DYLIB_H_
#include "Gem/Exception.h"
/* an opaque handle to the platform specific library handle */
class GemDylibHandle;
class CPPExtern;
class GEM_EXTERN GemDylib {
private:
GemDylibHandle*m_handle;
public:
GemDylib(const CPPExtern*obj,
const std::string libname,
const std::string extension=std::string("")
) throw(GemException);
GemDylib(const std::string libname,
const std::string extension=std::string("")
) throw(GemException);
GemDylib(const GemDylib&);
virtual ~GemDylib(void);
typedef void (*function_t)(void);
virtual GemDylib& operator=(const GemDylib&);
// if void<procname>(void) exists in dylib, run it and return "true"
// else return false;
bool run(const std::string procname);
// if <procname> exists in dylib, return it, else return NULL
function_t proc(const std::string procname);
public:
/**
* LoadLib(): convenience function that searches a library named <baselibname> and then runs <procname>()
* if "extension" is NULL, a platform-specific default is used
* on success "true" is returned, else "false
*/
static bool LoadLib(const std::string procname,
const std::string baselibname,
const std::string fileext=std::string(""));
static const std::string getDefaultExtension(void);
};
#endif

466
Gem/src/Gem/Event.cpp Normal file
View file

@ -0,0 +1,466 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "Event.h"
#include <stdlib.h>
#include "m_pd.h"
/////////////////////////////////////////////////////////
// The callbacks
//
/////////////////////////////////////////////////////////
struct CallbackList{
CallbackList() : data(NULL), func(NULL), next(NULL) {}
void *data;
void *func;
CallbackList *next;
};
static CallbackList *s_motionList = NULL;
static CallbackList *s_buttonList = NULL;
static CallbackList *s_wheelList = NULL;
static CallbackList *s_keyboardList = NULL;
static CallbackList *s_resizeList = NULL;
/////////////////////////////////////////////////////////
// Motion callbacks
//
/////////////////////////////////////////////////////////
GEM_EXTERN void setMotionCallback(MOTION_CB callback, void *data)
{
CallbackList *newCallback = new CallbackList;
newCallback->data = data;
newCallback->func = (void *)callback;
if (!s_motionList)
s_motionList = newCallback;
else
{
CallbackList *theList = s_motionList;
while(theList->next)
theList = theList->next;
theList->next = newCallback;
}
}
GEM_EXTERN void removeMotionCallback(MOTION_CB callback, void *data)
{
CallbackList *theList = s_motionList;
if (!theList)
return;
else if (theList->func == (void *)callback &&
theList->data == data)
{
s_motionList = theList->next;
delete theList;
}
else
{
while(theList->next)
{
if (theList->next->func == (void *)callback &&
theList->next->data == data)
{
CallbackList *holder = theList->next;
theList->next = holder->next;
delete holder;
return;
}
theList = theList->next;
}
}
}
/////////////////////////////////////////////////////////
// Button callbacks
//
/////////////////////////////////////////////////////////
GEM_EXTERN void setButtonCallback(BUTTON_CB callback, void *data)
{
CallbackList *newCallback = new CallbackList;
newCallback->data = data;
newCallback->func = (void *)callback;
if (!s_buttonList)
s_buttonList = newCallback;
else
{
CallbackList *theList = s_buttonList;
while(theList->next)
theList = theList->next;
theList->next = newCallback;
}
}
GEM_EXTERN void removeButtonCallback(BUTTON_CB callback, void *data)
{
CallbackList *theList = s_buttonList;
if (!theList)
return;
else if (theList->func == (void *)callback &&
theList->data == data)
{
s_buttonList = theList->next;
delete theList;
}
else
{
while(theList->next)
{
if (theList->next->func == (void *)callback &&
theList->next->data == data)
{
CallbackList *holder = theList->next;
theList->next = holder->next;
delete holder;
return;
}
theList = theList->next;
}
}
}
/////////////////////////////////////////////////////////
// Wheel callbacks
//
/////////////////////////////////////////////////////////
GEM_EXTERN void setWheelCallback(WHEEL_CB callback, void *data)
{
CallbackList *newCallback = new CallbackList;
newCallback->data = data;
newCallback->func = (void *)callback;
if (!s_wheelList)
s_wheelList = newCallback;
else
{
CallbackList *theList = s_wheelList;
while(theList->next)
theList = theList->next;
theList->next = newCallback;
}
}
GEM_EXTERN void removeWheelCallback(WHEEL_CB callback, void *data)
{
CallbackList *theList = s_wheelList;
if (!theList)
return;
else if (theList->func == (void *)callback &&
theList->data == data)
{
s_wheelList = theList->next;
delete theList;
}
else
{
while(theList->next)
{
if (theList->next->func == (void *)callback &&
theList->next->data == data)
{
CallbackList *holder = theList->next;
theList->next = holder->next;
delete holder;
return;
}
theList = theList->next;
}
}
}
/////////////////////////////////////////////////////////
// Keyboard callbacks
//
/////////////////////////////////////////////////////////
GEM_EXTERN void setKeyboardCallback(KEYBOARD_CB callback, void *data)
{
CallbackList *newCallback = new CallbackList;
newCallback->data = data;
newCallback->func = (void *)callback;
if (!s_keyboardList)
s_keyboardList = newCallback;
else
{
CallbackList *theList = s_keyboardList;
while(theList->next)
theList = theList->next;
theList->next = newCallback;
}
}
GEM_EXTERN void removeKeyboardCallback(KEYBOARD_CB callback, void *data)
{
CallbackList *theList = s_keyboardList;
if (!theList)
return;
else if (theList->func == (void *)callback &&
theList->data == data)
{
s_keyboardList = theList->next;
delete theList;
}
else
{
while(theList->next)
{
if (theList->next->func == (void *)callback &&
theList->next->data == data)
{
CallbackList *holder = theList->next;
theList->next = holder->next;
delete holder;
return;
}
theList = theList->next;
}
}
}
/////////////////////////////////////////////////////////
// Resize callbacks
//
/////////////////////////////////////////////////////////
GEM_EXTERN void setResizeCallback(RESIZE_CB callback, void *data)
{
CallbackList *newCallback = new CallbackList;
newCallback->data = data;
newCallback->func = (void *)callback;
if (!s_resizeList)
s_resizeList = newCallback;
else
{
CallbackList *theList = s_resizeList;
while(theList->next)
theList = theList->next;
theList->next = newCallback;
}
}
GEM_EXTERN void removeResizeCallback(RESIZE_CB callback, void *data)
{
CallbackList *theList = s_resizeList;
if (!theList)
return;
else if (theList->func == (void *)callback &&
theList->data == data)
{
s_resizeList = theList->next;
delete theList;
}
else
{
while(theList->next)
{
if (theList->next->func == (void *)callback &&
theList->next->data == data)
{
CallbackList *holder = theList->next;
theList->next = holder->next;
delete holder;
return;
}
theList = theList->next;
}
}
}
/////////////////////////////////////////////////////////
// Trigger queue
//
/////////////////////////////////////////////////////////
typedef enum {
NONE,
MOTION,
BUTTON,
WHEEL,
KEYBOARD,
RESIZE
} gem_event_t;
typedef struct _event_queue_item {
gem_event_t type;
struct _event_queue_item*next;
char*string;
int x;
int y;
int state;
int axis;
int value;
int which;
} gem_event_queue_item_t;
typedef struct _gem_event_queue_t{
gem_event_queue_item_t*first;
gem_event_queue_item_t*last;
t_clock *clock;
} gem_event_queue_t;
gem_event_queue_t*event_queue = NULL;
static gem_event_queue_item_t* createEvent(gem_event_t type, char*string, int x, int y, int state, int axis, int value, int which)
{
gem_event_queue_item_t*ret=new gem_event_queue_item_t;
ret->type=type;
ret->next=NULL;
ret->string=string;
ret->x=x;
ret->y=y;
ret->state=state;
ret->axis=axis;
ret->value=value;
ret->which=which;
return ret;
}
static void deleteEvent( gem_event_queue_item_t* event) {
if(event == event_queue->first) {
event_queue->first=event->next;
}
if(event == event_queue->last) {
event_queue->last=NULL;
}
event->type=NONE;
event->next=NULL;
event->string=0;
event->x=0;
event->y=0;
event->state=0;
event->axis=0;
event->value=0;
event->which=0;
delete event;
}
static void eventClock(void *x);
static void addEvent(gem_event_t type, char*string, int x, int y, int state, int axis, int value, int which) {
if (NULL==event_queue) {
event_queue=new gem_event_queue_t;
event_queue->first=NULL;
event_queue->last =NULL;
event_queue->clock=clock_new(NULL, reinterpret_cast<t_method>(eventClock));
}
gem_event_queue_item_t*item=createEvent(type, string, x, y, state, axis, value, which);
if(NULL==event_queue->first) {
event_queue->first=item;
}
if(event_queue->last) {
event_queue->last->next=item;
}
event_queue->last=item;
clock_delay(event_queue->clock, 0);
}
static void dequeueEvents(void) {
CallbackList *theList=NULL;
if (NULL==event_queue) {
error("dequeue NULL queue");
return;
}
gem_event_queue_item_t*events = event_queue->first;
if(NULL==events) {
error("dequeue empty queue");
return;
}
while(events) {
switch(events->type) {
case( MOTION):
theList = s_motionList;
while(theList)
{
MOTION_CB callback = (MOTION_CB)theList->func;
(*callback)(events->x, events->y, theList->data);
theList = theList->next;
}
break;
case( BUTTON):
theList = s_buttonList;
while(theList)
{
BUTTON_CB callback = (BUTTON_CB)theList->func;
(*callback)(events->which, events->state, events->x, events->y, theList->data);
theList = theList->next;
}
break;
case( WHEEL):
theList = s_wheelList;
while(theList)
{
WHEEL_CB callback = (WHEEL_CB)theList->func;
(*callback)(events->axis, events->value, theList->data);
theList = theList->next;
}
break;
case( KEYBOARD):
theList = s_keyboardList;
while(theList)
{
KEYBOARD_CB callback = (KEYBOARD_CB)theList->func;
(*callback)(events->string, events->value, events->state, theList->data);
theList = theList->next;
}
break;
case( RESIZE):
theList = s_resizeList;
while(theList)
{
RESIZE_CB callback = (RESIZE_CB)theList->func;
(*callback)(events->x, events->y, theList->data);
theList = theList->next;
}
break;
default: break;
}
gem_event_queue_item_t*old = events;
events=events->next;
deleteEvent(old);
}
}
static void eventClock(void *x)
{
dequeueEvents();
}
/////////////////////////////////////////////////////////
// Trigger events
//
/////////////////////////////////////////////////////////
GEM_EXTERN void triggerMotionEvent(int x, int y)
{
addEvent(MOTION, NULL, x, y, 0, 0, 0, 0);
}
GEM_EXTERN void triggerButtonEvent(int which, int state, int x, int y)
{
addEvent(BUTTON, NULL, x, y, state, 0, 0, which);
}
GEM_EXTERN void triggerWheelEvent(int axis, int value)
{
addEvent(WHEEL, NULL, 0, 0, 0, axis, value, 0);
}
GEM_EXTERN void triggerKeyboardEvent(char *string, int value, int state)
{
addEvent(KEYBOARD, gensym(string)->s_name, 0, 0, state, 0, value, 0);
}
GEM_EXTERN void triggerResizeEvent(int xSize, int ySize)
{
addEvent(RESIZE, NULL, xSize, ySize, 0, 0, 0, 0);
}

104
Gem/src/Gem/Event.h Normal file
View file

@ -0,0 +1,104 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
get keyboard/mouse callbacks
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_EVENT_H_
#define _INCLUDE__GEM_GEM_EVENT_H_
#include "Gem/ExportDef.h"
//////////////////////////////////////////////////////////////////
//
// Mouse motion callback
//
//////////////////////////////////////////////////////////////////
typedef void (*MOTION_CB)(int, int, void *);
//////////
// Set a mouse motion callback
GEM_EXTERN extern void setMotionCallback(MOTION_CB callback, void *data);
//////////
// Remove a mouse motion callback
GEM_EXTERN extern void removeMotionCallback(MOTION_CB callback, void *data);
//////////////////////////////////////////////////////////////////
//
// Mouse button callback
//
//////////////////////////////////////////////////////////////////
typedef void (*BUTTON_CB)(int, int, int, int, void *);
//////////
// Set a button callback
// which == 0 == left
// which == 1 == middle
// which == 2 == right
GEM_EXTERN extern void setButtonCallback(BUTTON_CB callback, void *data);
//////////
// Remove a button callback
GEM_EXTERN extern void removeButtonCallback(BUTTON_CB callback, void *data);
//////////////////////////////////////////////////////////////////
//
// Mouse wheel callback
//
//////////////////////////////////////////////////////////////////
typedef void (*WHEEL_CB)(int, int, void *);
//////////
// Set a wheel callback
GEM_EXTERN extern void setWheelCallback(WHEEL_CB callback, void *data);
//////////
// Remove a wheel callback
GEM_EXTERN extern void removeWheelCallback(WHEEL_CB callback, void *data);
//////////////////////////////////////////////////////////////////
//
// Keyboard callback
//
//////////////////////////////////////////////////////////////////
typedef void (*KEYBOARD_CB)(char *,int, int, void *);
//////////
// Set a keyboard callback
GEM_EXTERN extern void setKeyboardCallback(KEYBOARD_CB callback, void *data);
//////////
// Remove a keyboard callback
GEM_EXTERN extern void removeKeyboardCallback(KEYBOARD_CB callback, void *data);
//////////////////////////////////////////////////////////////////
//
// Resize callback
//
//////////////////////////////////////////////////////////////////
typedef void (*RESIZE_CB)(int, int, void *);
//////////
// Set a resize callback
GEM_EXTERN extern void setResizeCallback(RESIZE_CB callback, void *data);
//////////
// Remove a resize callback
GEM_EXTERN extern void removeResizeCallback(RESIZE_CB callback, void *data);
//////////
// Trigger an event
GEM_EXTERN extern void triggerMotionEvent(int x, int y);
GEM_EXTERN extern void triggerButtonEvent(int which, int state, int x, int y);
GEM_EXTERN extern void triggerWheelEvent(int axis, int value);
GEM_EXTERN extern void triggerKeyboardEvent(char *string, int value, int state);
GEM_EXTERN extern void triggerResizeEvent(int xSize, int ySize);
#endif // for header file

67
Gem/src/Gem/Exception.cpp Normal file
View file

@ -0,0 +1,67 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
// for NULL
#include <new>
#include "Exception.h"
// for error()
#include "m_pd.h"
GemException::GemException(const char *error) throw()
: ErrorString(error)
{}
GemException::GemException(const std::string error) throw()
: ErrorString(error)
{}
GemException::GemException() throw()
: ErrorString(std::string(""))
{}
GemException::~GemException() throw()
{}
const char *GemException::what() const throw() {
return ErrorString.c_str();
}
void GemException::report(const char*origin) const throw() {
if(!(ErrorString.empty())) {
if (NULL==origin)
error("GemException: %s", ErrorString.c_str());
else
error("[%s]: %s", origin, ErrorString.c_str());
}
}
void gem::catchGemException(const char*name, const t_object*obj) {
try {
throw;
} catch (GemException&ex) {
if(NULL==obj) {
ex.report(name);
} else {
t_object*o=(t_object*)obj;
char*str=(char*)ex.what();
if(NULL!=str) {
if (NULL==name)
pd_error(o, "GemException: %s", str);
else
pd_error(o, "[%s]: %s", name, str);
}
}
}
}

58
Gem/src/Gem/Exception.h Normal file
View file

@ -0,0 +1,58 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The base class for exceptions thrown by Gem
Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemException
an exception class...
DESCRIPTION
this is a class, we can throw on creation,
to make sure that the pd-object can not be created
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_EXCEPTION_H_
#define _INCLUDE__GEM_GEM_EXCEPTION_H_
#include "Gem/ExportDef.h"
#include <string>
typedef struct _text t_object;
class GEM_EXTERN GemException
{
public:
GemException(void) throw();
GemException(const char*error) throw();
GemException(const std::string error) throw();
virtual ~GemException(void) throw();
virtual const char *what(void) const throw();
virtual void report(const char*origin=0) const throw();
private:
const std::string ErrorString;
};
namespace gem {
GEM_EXTERN void catchGemException(const char*name=NULL, const t_object*obj=NULL);
};
#endif /* _INCLUDE__GEM_GEM_EXCEPTION_H_ */

71
Gem/src/Gem/ExportDef.h Normal file
View file

@ -0,0 +1,71 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
Export crap
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_EXPORTDEF_H_
#define _INCLUDE__GEM_GEM_EXPORTDEF_H_
#if defined _MSC_VER
/* turn of some warnings on vc-compilers */
/* data conversion with possible loss of data */
# pragma warning( disable : 4244 )
/* identifier conversion with possible loss of data */
# pragma warning( disable : 4305 )
/* declspec without variable declaration */
# pragma warning( disable : 4091 )
/* M$DN classes exporting STL members... */
# pragma warning( disable : 4251 )
/* "switch" without "case" (just "default") */
# pragma warning( disable : 4065 )
/* Exception Specifications! */
# pragma warning (disable : 4290)
/* CRT deprecation warnings */
# define _CRT_SECURE_NO_WARNINGS 1
/* MSVC always uses dllimport/dllexport */
#define DLL_EXPORT
#endif /* _MSC_VER */
#ifdef DLL_EXPORT
// Windows requires explicit import and exporting of functions and classes.
// While this is a pain to do sometimes, in large software development
// projects, it is very useful.
# define GEM_EXPORT __declspec(dllexport)
# define GEM_IMPORT __declspec(dllimport)
# define GEM_DEPRECATED __declspec(deprecated)
#elif defined __GNUC__
# define GEM_EXPORT
# define GEM_IMPORT
# define GEM_DEPRECATED __attribute__ ((deprecated))
#else
/* unknown compiler */
# warning set up compiler specific defines
#endif
#ifdef GEM_INTERNAL
# define GEM_EXTERN GEM_EXPORT
#else
# define GEM_EXTERN GEM_IMPORT
#endif
#endif // for header file

178
Gem/src/Gem/Files.cpp Normal file
View file

@ -0,0 +1,178 @@
#include "Gem/GemConfig.h"
#ifdef _WIN32
#define _WIN32_WINNT 0x0400
# include <io.h>
# include <windows.h>
#else
# include <glob.h>
# include <unistd.h>
#endif
#include "Files.h"
#ifdef HAVE_WORDEXP_H
# include <wordexp.h>
#endif
#include "Gem/RTE.h"
#include "Base/CPPExtern.h"
namespace gem {
namespace files {
std::vector<std::string>getFilenameListing(const std::string&pattern) {
std::vector<std::string>result;
#ifdef _WIN32
WIN32_FIND_DATA findData;
DWORD errorNumber;
HANDLE hFind;
LPVOID lpErrorMessage;
hFind = FindFirstFile(pattern.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
{
errorNumber = GetLastError();
switch (errorNumber)
{
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
break;
default:
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
errorNumber,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpErrorMessage,
0, NULL );
//pd_error(x,"[folder_list] %s", (char *)lpErrorMessage);
}
return result;
}
do {
result.push_back(findData.cFileName);
} while (FindNextFile(hFind, &findData) != 0);
FindClose(hFind);
#else
/* use glob */
glob_t glob_buffer;
int i=0;
switch( glob( pattern.c_str(), GLOB_TILDE, NULL, &glob_buffer ) ) {
case GLOB_NOSPACE:
// error("out of memory for \"%s\"",pattern.c_str());
return result;
# ifdef GLOB_ABORTED
case GLOB_ABORTED:
//error("aborted \"%s\"",pattern.c_str());
return result;
# endif
# ifdef GLOB_NOMATCH
case GLOB_NOMATCH:
//error("nothing found for \"%s\"",pattern.c_str());
return result;
# endif
}
for(i=0; i<glob_buffer.gl_pathc; i++) {
result.push_back(glob_buffer.gl_pathv[i]);
}
globfree( &(glob_buffer) );
#endif
return result;
}
std::string expandEnv(const std::string&value, bool bashfilename) {
std::string ret;
/* FIXXME:
* ouch, on linux value has to include "$VARIABLENAME", check whether we need "%VARIABLENAME%" on w32
*/
if(value.empty())
return value;
if(bashfilename) {
char bashBuffer[MAXPDSTRING];
sys_bashfilename(value.c_str(), bashBuffer);
ret=bashBuffer;
} else {
ret=value;
}
#ifdef HAVE_WORDEXP_H
wordexp_t pwordexp;
if(0==wordexp(ret.c_str(), &pwordexp, 0)) {
pwordexp.we_offs=0;
if(pwordexp.we_wordc) {
// we only take the first match into account
ret=pwordexp.we_wordv[0];
}
# ifdef __APPLE__
/* wordfree() broken on apple: keeps deallocating non-aligned memory */
# warning wordfree() not called
# else
wordfree(&pwordexp);
# endif
}
#endif
#ifdef _WIN32
char envVarBuffer[MAXPDSTRING];
ExpandEnvironmentStrings(ret.c_str(), envVarBuffer, MAX_PATH - 2);
ret=envVarBuffer;
#endif
return ret;
}
std::string getExtension(const std::string&fileName, const bool lower) {
using namespace std;
std::string Ext;
std::string::size_type idx;
idx = fileName.rfind('.');
if(idx != std::string::npos)
Ext=fileName.substr(idx + 1);
if(lower) {
// lower-case: http://www.cplusplus.com/forum/general/837/
#if 0
std::transform(Ext.begin(), Ext.end(), Ext.begin(), std::tolower);
#else
const int length = Ext.length();
for(int i=0; i < length; ++i) {
Ext[i] = tolower(Ext[i]);
}
#endif
}
return Ext;
}
std::string getFullpath(const std::string&path, const CPPExtern*obj) {
std::string result=expandEnv(path);
if(obj!=NULL) {
char buf[MAXPDSTRING];
t_canvas*canvas=const_cast<t_canvas*>(obj->getCanvas());
if(canvas) {
canvas_makefilename(canvas, const_cast<char*>(result.c_str()), buf, MAXPDSTRING);
result=buf;
}
}
return result;
}
void close(int fd) {
#ifdef _WIN32
::_close(fd);
#else
::close(fd);
#endif
}
};
};

39
Gem/src/Gem/Files.h Normal file
View file

@ -0,0 +1,39 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
- file handling with Gem
Copyright (c) 2010-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_FILES_H_
#define _INCLUDE__GEM_GEM_FILES_H_
#include <string>
#include <vector>
#include "Gem/ExportDef.h"
class CPPExtern;
namespace gem {
namespace files {
GEM_EXTERN std::vector<std::string>getFilenameListing(const std::string&pattern);
GEM_EXTERN std::string expandEnv(const std::string&, bool bashfilename=false);
GEM_EXTERN std::string getExtension(const std::string&filename, bool make_lowercase=false);
GEM_EXTERN std::string getFullpath(const std::string&, const CPPExtern*obj=NULL);
GEM_EXTERN void close(int fd);
};
};
#endif /* _INCLUDE__GEM_GEM_FILES_H_ */

200
Gem/src/Gem/GLStack.cpp Normal file
View file

@ -0,0 +1,200 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2002 tigital
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma NOTE("memory(484): warning C4150: Löschen eines Zeigers auf den nicht definierten Typ 'gem::GLStack::Data'. Destruktor wurde nicht aufgerufen.")
#endif
#include "Gem/GLStack.h"
#include "Gem/RTE.h"
/* need GLUtil for glReportError */
#include "Gem/GemGL.h"
#include "Utils/GLUtil.h"
#include <map>
#define GLDEBUG if(glReportError())::startpost("glError @ %s:%d[%s] ", __FILE__, __LINE__, __FUNCTION__), ::post
using namespace gem;
namespace gem {
class GLStack::Data {
public:
Data(void) {
int i=0;
for(i=0; i<4; i++) {
stackDepth[i]=0;
maxDepth[i]=0;
orgDepth[i]=0;
}
}
int stackDepth[4];
int maxDepth[4];
int orgDepth[4];
};
};
namespace {
static std::map<enum GLStack::GemStackId, GLenum>s_id2mode;
static std::map<enum GLStack::GemStackId, GLenum>s_id2depth;
static std::map<enum GLStack::GemStackId, GLenum>s_id2maxdepth;
static std::map<enum GLStack::GemStackId, bool>s_id2init;
}
GLStack:: GLStack(bool haveValidContext) : data(new Data()) {
static bool firsttime=true;
if(firsttime) {
s_id2mode[MODELVIEW] =GL_MODELVIEW;
s_id2mode[PROJECTION]=GL_PROJECTION;
s_id2mode[TEXTURE] =GL_TEXTURE;
s_id2mode[COLOR] =GL_COLOR;
s_id2depth[MODELVIEW] =GL_MODELVIEW_STACK_DEPTH;
s_id2depth[PROJECTION]=GL_PROJECTION_STACK_DEPTH;
s_id2depth[TEXTURE] =GL_TEXTURE_STACK_DEPTH;
s_id2depth[COLOR] =GL_COLOR_MATRIX_STACK_DEPTH;
s_id2maxdepth[MODELVIEW] =GL_MAX_MODELVIEW_STACK_DEPTH;
s_id2maxdepth[PROJECTION]=GL_MAX_PROJECTION_STACK_DEPTH;
s_id2maxdepth[TEXTURE] =GL_MAX_TEXTURE_STACK_DEPTH;
s_id2maxdepth[COLOR] =GL_MAX_COLOR_MATRIX_STACK_DEPTH;
s_id2init[MODELVIEW] =false;
s_id2init[PROJECTION]=false;
s_id2init[TEXTURE] =false;
s_id2init[COLOR] =false;
}
firsttime=false;
if(haveValidContext) {
reset();
}
}
GLStack::~GLStack() {
}
#ifdef __GNUC__
# warning push/pop texture matrix has to be done per texunit
// each texunit has it's own matrix to be pushed/popped
// changing the texunit (e.g. in [pix_texture]) makes the
// local depthcounter a useless, and we get a lot of
// stack under/overflows
#endif
/** push the given matrix to the stack if the maximum has not been reached
* returns true on success and false otherwise (stack overflow)
* NOTE: needs valid openGL context
*/
bool GLStack::push(enum GemStackId id) {
GLenum mode=s_id2mode[id];
if(!mode)return false;
if(data->stackDepth[id]<data->maxDepth[id]) {
glMatrixMode(mode);
glPushMatrix();
data->stackDepth[id]++;
return true;
}
data->stackDepth[id]++;
return false;
}
void GLStack::push() {
push(COLOR);
push(TEXTURE);
push(PROJECTION);
push(MODELVIEW);
}
/** pop the given matrix from the stack if the maximum has not been reached
* returns true on success and false otherwise (stack underlow)
* NOTE: needs valid openGL context
*/
bool GLStack::pop(enum GemStackId id) {
GLenum mode=s_id2mode[id];
if(!mode)return false;
data->stackDepth[id]--;
if(data->stackDepth[id]<data->maxDepth[id]) {
glMatrixMode(mode);
glPopMatrix();
return true;
}
return false;
}
void GLStack::pop() {
pop(COLOR);
pop(TEXTURE);
pop(PROJECTION);
pop(MODELVIEW);
}
/**
* reset the maximum stack depth of the given stack
* NOTE: needs valid openGL context
*/
void GLStack::reset() {
reset(MODELVIEW);
reset(PROJECTION);
reset(TEXTURE);
reset(COLOR);
}
/**
* reset the maximum stack depth of all stacks
* NOTE: needs valid openGL context
*/
int GLStack::reset(enum GemStackId id) {
bool firsttime=!(s_id2init[id]);
if(firsttime) {
s_id2init[id]=true;
if(COLOR == id && !GLEW_ARB_imaging) {
s_id2maxdepth[id]=0;
s_id2depth[id]=0;
}
glReportError(); // clear any errors so far
}
GLenum maxdepth=s_id2maxdepth[id];
GLenum depth=s_id2depth[id];
if(maxdepth && depth) {
/* hmm, some ati-cards (with fglrx) report GLEW_ARB_imaging support but fail the 'depth' test for COLOR */
glGetIntegerv(maxdepth, data->maxDepth+id);
if(firsttime && glReportError())s_id2maxdepth[id]=0;
glGetIntegerv(depth, data->stackDepth+id);
if(firsttime && glReportError())s_id2depth[id]=0;
data->orgDepth[id]=data->stackDepth[id];
return data->stackDepth[id];
}
return -1;
}
void GLStack::print() {
post("MODELVIEW: %02d/%02d", data->stackDepth[MODELVIEW], data->maxDepth[MODELVIEW]);
post("PROJECTION: %02d/%02d", data->stackDepth[PROJECTION], data->maxDepth[PROJECTION]);
post("TEXTURE: %02d/%02d", data->stackDepth[TEXTURE], data->maxDepth[TEXTURE]);
post("COLOR: %02d/%02d", data->stackDepth[COLOR], data->maxDepth[COLOR]);
}

74
Gem/src/Gem/GLStack.h Normal file
View file

@ -0,0 +1,74 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
handling of diverse openGL stacks
Copyright (c) 1997-2000 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_GLSTACK_H_
#define _INCLUDE__GEM_GEM_GLSTACK_H_
#include "Gem/ExportDef.h"
#include <memory>
namespace gem {
class GEM_EXTERN GLStack {
public:
GLStack(bool haveValidContext=false);
virtual ~GLStack(void);
enum GemStackId { MODELVIEW, COLOR, TEXTURE, PROJECTION };
/** push the given matrix to the stack if the maximum has not been reached
* returns true on success and false otherwise (stack overflow)
* NOTE: needs valid openGL context
* NOTE: might change the current matrix mode; you have to manually reset it
*/
bool push(enum GemStackId);
/** pushes all matrices possible
* NOTE: finishes in MODELVIEW matrix mode
*/
void push(void);
/** pop the given matrix from the stack if the maximum has not been reached
* returns true on success and false otherwise (stack underflow)
* NOTE: needs valid openGL context
* NOTE: might change the current matrix mode; you have to manually reset it
*/
bool pop(enum GemStackId);
/** pops all matrices possible
* NOTE: finishes in MODELVIEW matrix mode
*/
void pop(void);
/**
* reset the maximum stack depth of the given stack
* NOTE: needs valid openGL context
*/
void reset(void);
/**
* reset the maximum stack depth of all stacks
* returns the current stack depth (-1 on failure)
* NOTE: needs valid openGL context
*/
int reset(enum GemStackId);
void print(void);
private:
class Data;
std::auto_ptr<Data>data;
};
} /* namespace gem */
#endif /* _INCLUDE__GEM_GEM_GLSTACK_H_ */

64
Gem/src/Gem/GemConfig.h Normal file
View file

@ -0,0 +1,64 @@
/* configuration-file */
#ifndef HAVE_BASE_GEMCONFIG_H_
#define HAVE_BASE_GEMCONFIG_H_
#ifdef _MSC_VER
# ifndef _WIN32
# define _WIN32
# endif
#endif
#ifdef _WIN32
# ifndef NT
# define NT
# endif
# ifndef MSW
# define MSW
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
#endif
#define GEM_FILMBACKEND_undefined 0
#define GEM_FILMBACKEND_Darwin 1
#define GEM_VIDEOBACKEND_undefined 0
#define GEM_VIDEOBACKEND_Darwin 1
#define GEM_VIDEOBACKEND_DS 2
#define GEM_VIDEOBACKEND_NT 3
#define GEM_VIDEOBACKEND_SGI 4
#ifdef HAVE_CONFIG_H
# include "config.h"
/* stupid hack to avoid duplicate inclusion of config.h e.g. in avifile.h */
# undef HAVE_CONFIG_H
#else /* includes system-specific files */
# ifdef __linux__
# include "Gem/configLinux.h"
# elif defined __APPLE__
# include "Gem/configDarwin.h"
# elif defined _WIN32
# include "Gem/configNT.h"
# endif
#endif
#if defined GEM_VIDEOBACKEND && GEM_VIDEOBACKEND == GEM_VIDEOBACKEND_undefined
# warning ignoring unknown video backend
# undef GEM_VIDEOBACKEND
#endif
#if defined GEM_FILMBACKEND && GEM_FILMBACKEND == GEM_FILMBACKEND_undefined
# warning ignoring unknown film backend
# undef GEM_FILMBACKEND
#endif
#ifdef HAVE_LIBFTGL
# define FTGL
#endif
#endif /* HAVE_BASE_GEMCONFIG_H_ */

87
Gem/src/Gem/GemGL.h Normal file
View file

@ -0,0 +1,87 @@
/*
* GemGL: openGL includes for GEM
*
* include this file if you want to include the
* openGL-headers installed on your system
*
* tasks:
*
* + this file hides the peculiarities of the various platforms
* (like "OpenGL/gl.h" vs "GL/gl.h")
*
* + define some pre-processor defines that are missing in the GL-headers
*
* + try to exclude parts of the GL-headers based on GemConfig.h
*
*/
#ifndef _INCLUDE__GEM_GEM_GEMGL_H_
#define _INCLUDE__GEM_GEM_GEMGL_H_
#include "Gem/ExportDef.h"
// I hate Microsoft...I shouldn't have to do this!
#ifdef _WIN32
# include <windows.h>
#endif
#ifdef GLEW_MX
# define GEM_MULTICONTEXT
#endif
#include "Gem/glew.h"
#ifdef __APPLE__
# include <OpenGL/OpenGL.h>
#elif defined _WIN32
# include "Gem/wglew.h"
#elif defined(__linux__) || defined(__FreeBSD_kernel__)
# include "Gem/glxew.h"
#endif /* OS */
#ifdef GEM_MULTICONTEXT
GEM_EXTERN GLEWContext*glewGetContext(void);
# ifdef __APPLE__
# elif defined _WIN32
GEM_EXTERN WGLEWContext*wglewGetContext(void);
# elif defined __linux__ || defined HAVE_GL_GLX_H
GEM_EXTERN GLXEWContext*glxewGetContext(void);
# endif
#endif /* GEM_MULTICONTEXT */
#ifndef GL_YUV422_GEM
# define GL_YCBCR_422_GEM GL_YCBCR_422_APPLE
# define GL_YUV422_GEM GL_YCBCR_422_GEM
#endif /* GL_YUV422_GEM */
#ifndef GL_RGBA_GEM
# ifdef __APPLE__
# define GL_RGBA_GEM GL_BGRA_EXT
# else
# define GL_RGBA_GEM GL_RGBA
# endif
#endif /* GL_RGBA_GEM */
/* default draw-style */
#ifndef GL_DEFAULT_GEM
# define GL_DEFAULT_GEM 0xFFFF
#endif
/* uäh: in OSX10.3 we only have CGL-1.1 and
* all the functions are using "long*" rather than "GLint*")
* only CGL-1.2 got it right
*/
#ifdef CGL_VERSION_1_0
# ifdef CGL_VERSION_1_2
# define GemCGLint GLint
# else
# define GemCGLint long
# endif
#endif
#endif /* _INCLUDE__GEM_GEM_GEMGL_H_ */

1954
Gem/src/Gem/Image.cpp Normal file

File diff suppressed because it is too large Load diff

288
Gem/src/Gem/Image.h Normal file
View file

@ -0,0 +1,288 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
GemPixUtil.h
- contains image functions for pix objects
- part of GEM
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_IMAGE_H_
#define _INCLUDE__GEM_GEM_IMAGE_H_
#include "Gem/GemGL.h"
#include <string.h>
#include <stdlib.h>
// basic helper functions, like CLAMP and powerOfTwo
#include "Utils/Functions.h"
///////////////////////////////////////////////////////////////////////////////
// Color component defines
//
// These should be used to reference the various color channels
///////////////////////////////////////////////////////////////////////////////
/* RGBA */
#if GL_RGBA_GEM == GL_RGBA
const int chRed = 0;
const int chGreen = 1;
const int chBlue = 2;
const int chAlpha = 3;
#else
const int chAlpha = 0;
const int chRed = 1;
const int chGreen = 2;
const int chBlue = 3;
#endif
/* Gray */
const int chGray = 0;
/* YUV422 */
const int chU = 0;
const int chY0 = 1;
const int chV = 2;
const int chY1 = 3;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
imageStruct
The basic image structure
-----------------------------------------------------------------*/
// we now have a class "imageStruct";
// since i need to compile some of the sources with an older version of Gem
// there is a new define here:
#define IMAGE_CLASS
struct GEM_EXTERN imageStruct
{
imageStruct(void);
imageStruct(const imageStruct&);
virtual ~imageStruct(void);
virtual void info(void);
//////////
// columns
virtual unsigned char* allocate(size_t size);
virtual unsigned char* allocate(void);
// if we have allocated some space already, only re-allocate when needed.
virtual unsigned char* reallocate(size_t size);
virtual unsigned char* reallocate(void);
// delete the buffer (if it is ours)
virtual void clear(void);
//////////
// dimensions of the image
GLint xsize;
GLint ysize;
//////////
// (average) width of 1 pixel (LUMINANCE = 1, RGBA = 4, YUV = 2)
GLint csize;
//////////
// data type - always GL_UNSIGNED_BYTE (except for OS X)
GLenum type;
//////////
// the format - either GL_RGBA, GL_LUMINANCE
// or GL_YCBCR_422_GEM (which is on mac-computers GL_YCBCR_422_APPLE)
GLenum format;
//////////
// is this owned by us (? what about underscores ?)
int notowned;
//////////
// gets a pixel
/* X,Y are the coordinates
* C is the offset in the interleaved data (like chRed==0 for red)
* you should use chRed instead of 0 (because it might not be 0)
*
* you must make sure that (0<=X<xsize) and (0<=Y<ysize)
*/
// heck, why are X&Y swapped ?? (JMZ)
inline unsigned char GetPixel(int Y, int X, int C) const
{
return(data[Y * xsize * csize + X * csize + C]); }
//////////
// sets a pixel
/* while X and Y should be clear (coordinates),
* C is the offset (like chRed==0 for red).
* VAL is the value to set.
*
* you must make sure that (0<=X<xsize) and (0<=Y<ysize)
*/
inline void SetPixel(int Y, int X, int C, unsigned char VAL)
{ data[Y * xsize * csize + X * csize + C] = VAL; }
/////////
// gets the color of a pixel
virtual void getRGB(int X, int Y, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a=NULL) const;
virtual void getGrey(int X, int Y, unsigned char*g) const;
virtual void getYUV(int X, int Y, unsigned char*y, unsigned char*u, unsigned char*v) const;
/* following will set the whole image-data to either black or white
* the size of the image-data is NOT xsize*ysize*csize but datasize
* this is mostly slower
* i have put the datasize into private (like pdata) (bad idea?)
*/
virtual void setBlack(void);
virtual void setWhite(void);
/* certain formats are bound to certain csizes,
* it's quite annoying to have to think again and again (ok, not much thinking)
* so we just give the format (like GL_LUMINANCE)
* and it will set the image format to this format
* and set and return the correct csize (like 1)
* if no format is given the current format is used
*/
virtual int setCsizeByFormat(int format);
virtual int setCsizeByFormat(void);
/* various copy functions
* sometimes we want to copy the whole image (including pixel-data),
* but often it is enough to just copy the meta-data (without pixel-data)
* into a new imageStruct
*/
virtual void copy2Image(imageStruct *to) const;
virtual void copy2ImageStruct(imageStruct *to) const; // copy the imageStruct (but not the actual data)
/* this is a sort of better copy2Image,
* which only copies the imageStruct-data if it is needed
*/
virtual void refreshImage(imageStruct *to) const;
/* inplace swapping Red and Blue channel */
virtual void swapRedBlue(void);
///////////////////////////////////////////////////////////////////////////////
// acquiring data including colour-transformations
// should be accelerated if possible
/* i wonder whether this is the right place to put these routines
* they should be stored somewhere centrally
* (because maybe a lot of objects would like them) (like [pix_rgba]...)
* but it might be better to put them (the actual conversion routines) into
* separate files (a separate library?)
* orgdata points to the actual data in the given format
* the datasize will be read from image.xsize, image.ysize
* the dest-format will be given by image.format
* this is maybe not really clean (the meta-data is stored in the destination,
* while the source has no meta-data of its own)
*/
virtual void convertTo (imageStruct*to, GLenum dest_format=0) const;
virtual void convertFrom(const imageStruct*from, GLenum dest_format=0);
virtual void fromRGB (const unsigned char* orgdata);
virtual void fromRGBA (const unsigned char* orgdata);
virtual void fromBGR (const unsigned char* orgdata);
virtual void fromBGRA (const unsigned char* orgdata);
virtual void fromRGB16 (const unsigned char* orgdata);
virtual void fromABGR (const unsigned char* orgdata);
virtual void fromARGB (const unsigned char* orgdata);
virtual void fromGray (const unsigned char* orgdata);
virtual void fromGray (short* orgdata);
virtual void fromUYVY (const unsigned char* orgdata);
virtual void fromYUY2 (const unsigned char* orgdata); // YUYV
virtual void fromYVYU (const unsigned char* orgdata);
/* planar YUV420: this is rather generic and not really YV12 only */
virtual void fromYV12 (const unsigned char* Y, const unsigned char*U, const unsigned char*V);
/* assume that the planes are near each other: YVU */
virtual void fromYV12 (const unsigned char* orgdata);
/* assume that the planes are near each other: YVU */
virtual void fromYU12 (const unsigned char* orgdata);
/* overloading the above two in order to accept pdp YV12 packets */
virtual void fromYV12 (const short* Y, const short*U, const short*V);
virtual void fromYV12 (const short* orgdata);
/* aliases */
virtual void fromYUV422 (const unsigned char* orgdata){fromUYVY(orgdata);}
virtual void fromYUV420P(const unsigned char* orgdata){fromYV12(orgdata);}
virtual void fromYUV420P(const unsigned char*Y,const unsigned char*U,const unsigned char*V){fromYV12(Y,U,V);}
// "data" points to the image.
// the memory could(!) be reserved by this class or someone else
// "notowned" should be set to "1", if "data" points to foreign memory
// "data" is not freed directly, when the destructor is called
unsigned char *data; // the pointer to the data
private:
// "pdata" is the private data, and is the memory reserved by this class
// this data is freed when the destructor is called
unsigned char *pdata;
// "datasize" is the size of data reserved at "pdata"
size_t datasize;
public:
//////////
// true if the image is flipped horizontally (origin is upper-left)
// false if the image is openGL-conformant (origin is lower-left)
GLboolean upsidedown;
/* make the image orientation openGL-conformant */
virtual void fixUpDown(void);
imageStruct& operator=(const imageStruct&);
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
pixBlock
The pix block structure
-----------------------------------------------------------------*/
struct GEM_EXTERN pixBlock
{
pixBlock();
//////////
// the block's image
imageStruct image;
//////////
// is this a newimage since last time?
// ie, has it been refreshed
bool newimage;
//////////
// keeps track of when new films are loaded
// useful for rectangle_textures on OSX
bool newfilm;
};
///////////////////////////////////////////////////////////////////////////////
// imageStruct utility functions
//
///////////////////////////////////////////////////////////////////////////////
//////////
// copies all of the data over and mallocs memory
GEM_EXTERN extern void copy2Image(imageStruct *to, imageStruct *from);
//////////
// assumes that it only has to refresh the data
GEM_EXTERN extern void refreshImage(imageStruct *to, imageStruct *from);
GEM_EXTERN extern int getPixFormat(char*);
#endif // GEMPIXUTIL_H_

153
Gem/src/Gem/ImageIO.h Normal file
View file

@ -0,0 +1,153 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
GemPixImageLoad.h
- code to load in and resize an image
- part of GEM
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_IMAGEIO_H_
#define _INCLUDE__GEM_GEM_IMAGEIO_H_
#include "Gem/ExportDef.h"
struct imageStruct;
#include <string>
// image2mem() reads an image file into memory
// and a pointer to an imageStruct
// NULL = failure
//
// format:
// returns either GL_LUMINANCE or GL_RGBA
//
// automatically allocates the memory for the user
//
// This can read TIFF, SGI, and JPG images
//
namespace gem {
class Properties;
namespace image {
class GEM_EXTERN load {
public:
/**
* loads an image (given as 'filename') synchronously
* the function blocks until the image is loaded (in which case it returns TRUE)
* of the image-loading completely failed (in which case it returns FALSE)
*
* the loaded image is stored in 'img'
* 'props' holds a list of additional image properties discovered during loading
*/
static bool sync(const std::string filename,
imageStruct&img,
Properties&props);
typedef unsigned int id_t;
static const id_t IMMEDIATE;
static const id_t INVALID;
/* the callback used for asynchronous image loading
* userdata is is the pointer supplied when calling async();
* id is the ID returned by async()
* img holds a reference to the newly loaded image
* the image is allocated by the loder, but
* the callback (you!) is responsible for freeing the image
* once it is no more needed
* if image loading failed, img is set to NULL
* props holds a list of additional image properties discovered during loading
*
* currently (with Pd being the only RTE),
* the callback will always be called from within the main thread
*
* the callback might be called directly from within async(),
* in which case the ID given in the callback and returned by async()
* is IMMEDIATE
*/
typedef void (*callback)(void *userdata,
id_t ID,
imageStruct*img,
const Properties&props);
/* loads an image (given as 'filename') asynchronously
* image loading is done in a separate thread (if possible);
* when the image is loaded, the callback 'cb' is called with the new image
*
* this function returns an ID which is also passed to the callback function,
* so the caller can identify a certain request (e.g. if several images have been
* queued for loading before the 1st one was successfully returned;
*
* the image might get loaded (and the cb called) before the call to loadAsync()
* has finished, in which case IMMEDIATE is returned (and used in the CB)
*
* if the image cannot be loaded at all, INVALID is returned
* (and no callback will ever be called)
*
*/
static bool async(callback cb,
void*userdata,
const std::string filename,
id_t&ID
);
/* cancels asynchronous loading of an image
* removes the given ID (as returned by loadAsync()) from the loader queue
* returns TRUE if item could be removed, or FALSE if no item ID is in the queue
*
* there is no point in cancel()ing an IMMEDIATE or ILLEGAL id
*/
static bool cancel(id_t ID);
/* load an image in a synchronous way (that is argument compatible with async())
*/
static bool sync(callback cb,
void*userdata,
const std::string filename,
id_t&ID);
/*
* deliver all loaded images not delivered yet
*/
static void poll(void);
/*
* set asynch loading to "polling" mode
* in "polling" mode, the caller has to call 'poll()' manually in order to get any loaded images delivered
* in "pushing" mode this is done automatically (but might hang with current Pd)
*/
static bool setPolling(bool);
};};};
/* legacy */
GEM_EXTERN extern imageStruct *image2mem(const char *filename);
// image2mem() reads an image file into memory
// and a pointer to an imageStruct
// NULL = failure
//
// format:
// returns either GL_LUMINANCE or GL_RGBA
//
// automatically allocates the memory for the user
//
// This can write TIFF, JPG and other images (depending on which backends are available
// legacy: type=0 -> TIFF; type>0 -> JPEG and (quality:=type)
//
GEM_EXTERN extern int mem2image(imageStruct *image, const char *filename, const int type);
#endif

233
Gem/src/Gem/ImageLoad.cpp Normal file
View file

@ -0,0 +1,233 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2002-2003 james tittle/tigital
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "ImageIO.h"
#include "Gem/RTE.h"
#include "Utils/SynchedWorkerThread.h"
#include "plugins/imageloader.h"
namespace gem { namespace image {
struct PixImageThreadLoader : public gem::thread::SynchedWorkerThread {
struct InData {
load::callback cb;
void*userdata;
std::string filename;
InData(load::callback cb_, void*data_, std::string fname) :
cb(cb_),
userdata(data_),
filename(fname) {
};
};
struct OutData {
load::callback cb;
void*userdata;
imageStruct*img;
gem::Properties props;
OutData(const InData&in) :
cb(in.cb),
userdata(in.userdata),
img(NULL) {
};
};
static gem::plugins::imageloader*s_imageloader;
PixImageThreadLoader(void) :
SynchedWorkerThread(false)
{
if(NULL==s_imageloader) {
s_imageloader=gem::plugins::imageloader::getInstance();
}
if(!s_imageloader)
throw(40);
if(!s_imageloader->isThreadable())
throw(42);
start();
}
virtual ~PixImageThreadLoader(void) {
}
virtual void* process(id_t ID, void*data) {
if(!data){
// post("========================================= oops: %d", ID);
return NULL;
}
InData*in=reinterpret_cast<InData*>(data);
OutData*out=new OutData(*in);
if(!out) {
return NULL;
}
// DOIT
out->img=new imageStruct;
if(!s_imageloader->load(in->filename, *out->img, out->props)) {
delete out->img;
out->img=0;
}
void*result=reinterpret_cast<void*>(out);
//post("processing[%d] %p -> %p", ID, data, result);
return result;
};
virtual void done(id_t ID, void*data) {
OutData*out=reinterpret_cast<OutData*>(data);
if(out) {
(*(out->cb))(out->userdata, ID, out->img, out->props);
delete out;
} else {
error("loaded image:%d with no data!", ID);
}
};
virtual bool queue(id_t&ID, load::callback cb, void*userdata, std::string filename) {
InData *in = new InData(cb, userdata, filename);
return SynchedWorkerThread::queue(ID, reinterpret_cast<void*>(in));
};
static PixImageThreadLoader*getInstance(bool retry=true) {
static bool didit=false;
if(!retry && didit)
return s_instance;
didit=true;
if(NULL==s_instance) {
try {
s_instance=new PixImageThreadLoader();
} catch(int i) {
i=0;
static bool dunnit=false;
if(!dunnit) {
verbose(1, "threaded ImageLoading not supported!");
}
dunnit=true;
}
if(s_instance)
s_instance->setPolling(true);
}
return s_instance;
};
private:
static PixImageThreadLoader*s_instance;
};
PixImageThreadLoader*PixImageThreadLoader::s_instance=NULL;
gem::plugins::imageloader*PixImageThreadLoader::s_imageloader=NULL;
const load::id_t load::IMMEDIATE= 0;
const load::id_t load::INVALID =~0;
bool load::sync(const std::string filename,
imageStruct&result,
gem::Properties&props) {
if(!PixImageThreadLoader::s_imageloader)
PixImageThreadLoader::s_imageloader=gem::plugins::imageloader::getInstance();
if((PixImageThreadLoader::s_imageloader) &&
(PixImageThreadLoader::s_imageloader->load(filename, result, props)))
{
return true;
}
return false;
}
bool load::async(load::callback cb,
void*userdata,
const std::string filename,
id_t&ID) {
if(NULL==cb) {
ID=INVALID;
return false;
}
PixImageThreadLoader*threadloader=PixImageThreadLoader::getInstance();
//post("threadloader %p", threadloader);
if(threadloader) {
return threadloader->queue(ID, cb, userdata, filename);
}
return sync(cb, userdata, filename, ID);
}
bool load::sync(load::callback cb,
void*userdata,
const std::string filename,
id_t&ID) {
if(NULL==cb) {
ID=INVALID;
return false;
}
imageStruct*result=new imageStruct;
gem::Properties props;
if(sync(filename, *result, props)) {
ID=IMMEDIATE;
(*cb)(userdata, ID, result, props);
return true;
}
ID=INVALID;
return false;
}
bool load::cancel(id_t ID) {
PixImageThreadLoader*threadloader=PixImageThreadLoader::getInstance(false);
if(threadloader) {
bool success=threadloader->cancel(ID);
if(!success)
poll();
return success;
}
return false;
}
bool load::setPolling(bool value) {
PixImageThreadLoader*threadloader=PixImageThreadLoader::getInstance();
if(threadloader) {
return threadloader->setPolling(value);
}
return true;
}
void load::poll(void) {
PixImageThreadLoader*threadloader=PixImageThreadLoader::getInstance(false);
if(threadloader) {
threadloader->dequeue();
}
}
}; // image
}; // gem
/***************************************************************************
*
* image2mem - Read in an image in various file formats
*
***************************************************************************/
GEM_EXTERN imageStruct *image2mem(const char *filename)
{
gem::Properties props;
imageStruct *img = new imageStruct();
if(gem::image::load::sync(filename, *img, props))
return img;
delete img;
return NULL;
}

57
Gem/src/Gem/ImageSave.cpp Normal file
View file

@ -0,0 +1,57 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "ImageIO.h"
#include "Gem/RTE.h"
#include "Gem/Files.h"
#include "plugins/imagesaver.h"
#include "plugins/PluginFactory.h"
namespace gem { namespace PixImageSaver {
static gem::plugins::imagesaver*s_instance=NULL;
static gem::plugins::imagesaver*getInstance(void) {
if(NULL==s_instance) {
s_instance=gem::plugins::imagesaver::getInstance();
}
return s_instance;
}
}; };
/***************************************************************************
*
* mem2image - Save an image to a file
*
***************************************************************************/
GEM_EXTERN int mem2image(imageStruct* image, const char *filename, const int type)
{
gem::plugins::imagesaver*piximagesaver=gem::PixImageSaver::getInstance();
if(piximagesaver) {
std::string fname=filename;
std::string mimetype;
gem::Properties props;
if(type>0) {
props.set("quality", (float)type);
}
if(piximagesaver->save(*image, filename, mimetype, props)) {
return (1);
}
}
error("GEM: Unable to save image to '%s'", filename);
return (0);
}

56
Gem/src/Gem/Loaders.cpp Normal file
View file

@ -0,0 +1,56 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 1997-2000 Mark Danks.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// Copyright (c) 2002 James Tittle & Chris Clepper
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
// a wrapper for calling Pd's sys_register_loader()
//
/////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma warning( disable: 4091)
#endif /* _MSC_VER */
#include "Loaders.h"
#include "RTE/RTE.h"
#if defined __linux__ || defined __APPLE__
# define DL_OPEN
#endif
#ifdef DL_OPEN
# include <dlfcn.h>
#endif
#if defined _WIN32
# include <io.h>
# include <windows.h>
#endif
extern "C" {
typedef void (*loader_registrar_t)(gem_loader_t loader);
}
static loader_registrar_t rte_register_loader = NULL;
static int find_rte_loader(void) {
if(rte_register_loader)return 1;
gem::RTE::RTE*rte=gem::RTE::RTE::getRuntimeEnvironment();
if(rte)
rte_register_loader=(loader_registrar_t)rte->getFunction("sys_register_loader");
return(NULL!=rte_register_loader);
}
void gem_register_loader(gem_loader_t loader) {
if(find_rte_loader()) {
rte_register_loader(loader);
}
}

25
Gem/src/Gem/Loaders.h Normal file
View file

@ -0,0 +1,25 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
- registers a loader with Pd
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_LOADERS_H_
#define _INCLUDE__GEM_GEM_LOADERS_H_
#include "Gem/RTE.h"
extern "C" {
typedef int (*gem_loader_t)(t_canvas *canvas, char *classname);
void gem_register_loader(gem_loader_t loader);
}
#endif

113
Gem/src/Gem/Makefile.am Normal file
View file

@ -0,0 +1,113 @@
#####################################################################
# Gem/Gem: core infrastructure of Gem
#####################################################################
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)/src @GEM_CPPFLAGS@
include ../check-sources.mk
noinst_LTLIBRARIES = libGem.la
libGem_la_CXXFLAGS =
libGem_la_LIBADD =
libGem_la_LDFLAGS =
# RTE flags
libGem_la_CXXFLAGS += @GEM_RTE_CFLAGS@ @GEM_ARCH_CXXFLAGS@
libGem_la_LIBADD += @GEM_RTE_LIBS@
libGem_la_LDFLAGS += @GEM_ARCH_LDFLAGS@
# GLEW
libGem_la_CXXFLAGS += @GEM_LIB_GLEW_CFLAGS@
libGem_la_LIBADD += @GEM_LIB_GLEW_LIBS@
libGem_la_includedir = $(includedir)/Gem/Gem
libGem_la_include_HEADERS = \
ExportDef.h \
Version.h \
RTE.h \
State.h \
Cache.h \
Rectangle.h \
Exception.h \
Dylib.h \
Files.h \
ContextData.h \
Properties.h \
Settings.h \
Loaders.h \
Manager.h \
PBuffer.h \
Event.h
libGem_la_include_HEADERS += \
GemGL.h \
glew.h \
glxew.h \
wglew.h \
GLStack.h
libGem_la_include_HEADERS += \
Image.h \
ImageIO.h \
PixConvert.h
libGem_la_SOURCES =
if !HAVE_LIB_GLEW
libGem_la_SOURCES += glew.cpp
endif !HAVE_LIB_GLEW
libGem_la_SOURCES += \
configDarwin.h \
configLinux.h \
configNT.h \
GemConfig.h \
GemGL.h \
glew.h \
glxew.h \
wglew.h \
Cache.cpp \
Cache.h \
ContextData.cpp \
ContextData.h \
Dylib.cpp \
Dylib.h \
Event.cpp \
Event.h \
Exception.cpp \
Exception.h \
ExportDef.h \
Files.cpp \
Files.h \
GLStack.cpp \
GLStack.h \
Image.cpp \
Image.h \
ImageLoad.cpp \
ImageSave.cpp \
ImageIO.h \
PixConvert.h \
PixConvertAltivec.cpp \
PixConvertSSE2.cpp \
Loaders.cpp \
Loaders.h \
Manager.cpp \
Manager.h \
PBuffer.cpp \
PBuffer.h \
Properties.cpp \
Properties.h \
Rectangle.cpp \
Rectangle.h \
RTE.h \
Settings.cpp \
Settings.h \
Setup.cpp \
State.cpp \
State.h \
Version.h

View file

@ -0,0 +1,15 @@
AUTOMAKE_OPTIONS = foreign
AM_CPPFLAGS = -I$(top_srcdir)
noinst_LTLIBRARIES = libGem.la
libGem_la_CXXFLAGS =
libGem_la_LIBADD =
# RTE flags
libGem_la_CXXFLAGS += @GEM_RTE_CFLAGS@
libGem_la_LIBADD += @GEM_RTE_LIBS@
libGem_la_SOURCES= @SOURCES@

1447
Gem/src/Gem/Manager.cpp Normal file

File diff suppressed because it is too large Load diff

250
Gem/src/Gem/Manager.h Normal file
View file

@ -0,0 +1,250 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The base functions and structures
Also includes gemwin header file
Copyright (c) 1997-2000 Mark Danks.mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_MANAGER_H_
#define _INCLUDE__GEM_GEM_MANAGER_H_
#include "Gem/GemGL.h"
#include "Utils/GLUtil.h"
#include "Gem/ExportDef.h"
#include <string>
class gemhead;
class GemState;
class WindowInfo;
namespace gem {
class Context;
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemMan
A static class to create windows, etc.
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN GemMan
{
public:
//////////
// Should only be called once (usually by GemSetup)
static void initGem(void);
//////////
static void addObj(gemhead *obj, float priority);
//////////
static void removeObj(gemhead *obj, float priority);
//////////
// Is there a window.
static int windowExists(void);
//////////
// Are we rendering.
static int getRenderState(void);
//////////
// is there a context (has its meaning under X)
static void createContext(char* disp);
static int contextExists(void);
//////////
// If an object needs to know if the window changed.
// This is important for display lists.
static int windowNumber(void);
//////////
// reset to the initial state
static void resetState(void);
//////////
// Just send out one frame (if double buffered, will swap buffers)
static void render(void *);
static void renderChain(t_symbol *head, bool start);
static void renderChain(t_symbol *head, GemState *state);
//////////
// Start a clock to do rendering.
static void startRendering(void);
//////////
// Stop the clock to do rendering.
static void stopRendering(void);
//////////
// Create the window with the current parameters
static int createWindow(char* disp = 0);
//////////
// Destroy the window
static void destroyWindow(void);
// Destroy the window after a minimal delay
static void destroyWindowSoon(void);
//////////
// Swap the buffers.
// If single buffered, just clears the window
static void swapBuffers(void);
//////////
// Set the frame rate
static void frameRate(float framespersecond);
//////////
// Get the frame rate
static float getFramerate(void);
static int getProfileLevel(void);
static void getDimen(int*width, int*height);
static void getRealDimen(int*width, int*height);
static void getOffset(int*x, int*y);
//////////
// Turn on/off lighting
static void lightingOnOff(int state);
//////////
// Turn on/off cursor
static void cursorOnOff(int state);
//////////
// Turn on/off topmost position
static void topmostOnOff(int state);
//////////
// Request a lighting value - it is yours until you free it.
// The return can be 0, in which there are too many lights
// [in] specific - If you want a specific light. == 0 means that you don't care.
static GLenum requestLight(int specific = 0);
//////////
// Free a lighting value
static void freeLight(GLenum lightNum);
//////////
// Print out information
static void printInfo(void);
//////////
static void fillGemState(GemState &);
static int texture_rectangle_supported;
enum GemStackId { STACKMODELVIEW, STACKCOLOR, STACKTEXTURE, STACKPROJECTION };
static GLint maxStackDepth[4]; // for push/pop of matrix-stacks
static float m_perspect[6]; // values for the perspective matrix
static float m_lookat[9]; // values for the lookat matrix
// LATER make this private (right now it is needed in gem2pdp)
static int m_buffer; // single(1) or double(2)
private:
//////////
// computer and window information
static std::string m_title; // title to be displayed
static int m_fullscreen; // fullscreen (1) or not (0!)
static int m_menuBar; // hide (0), show(1), hide but autoshow(-1)
static int m_secondscreen; // set the second screen
static int m_height; // window height
static int m_width; // window width
static int m_w; // the real window width (reported by gemCreateWindow())
static int m_h; // the real window height
static int m_xoffset; // window offset (x)
static int m_yoffset; // window offset (y)
static int m_border; // window border
static int m_stereo; // stereoscopic
static int m_profile; // off(0), on(1), w/o image caching(2)
static int m_rendering;
static float m_fog; // fog density
enum FOG_TYPE
{ FOG_OFF = 0, FOG_LINEAR, FOG_EXP, FOG_EXP2 };
static FOG_TYPE m_fogMode; // what kind of fog we have
static GLfloat m_fogColor[4]; // colour of the fog
static float m_fogStart; // start of the linear fog
static float m_fogEnd; // start of the linear fog
static float m_motionBlur; // motion-blur factor in double-buffer mode
static float fps;
static int fsaa;
static bool pleaseDestroy;
//////////
// Changing these variables is likely to crash GEM
// This is current rendering window information
// The window is created and destroyed by the user, so
// if there is no window, this will contain NULL pointers.
static WindowInfo &getWindowInfo(void);
//////////
// Changing these variables is likely to crash GEM
// This is constant rendering window information
// This window is always available (although not visible)
static WindowInfo &getConstWindowInfo(void);
static int createConstWindow(char* disp = 0);
// gemwin is allowed to modifying "global" window attributes
friend class gemwin;
friend class gem::Context;
static GLfloat m_clear_color[4]; // the frame buffer clear
static GLbitfield m_clear_mask; // the clear bitmask
static GLfloat m_mat_ambient[4]; // default ambient material
static GLfloat m_mat_specular[4]; // default specular material
static GLfloat m_mat_shininess; // default shininess material
static GLfloat m_stereoSep; // stereo separation
static GLfloat m_stereoFocal; // distance to focal point
static bool m_stereoLine; // draw a line between 2 stereo-screens
static double m_lastRenderTime; // the time of the last rendered frame
// gemwin should not touch the following member variables and member functions
static int m_windowState;
static int m_windowNumber;
static int m_windowContext;
static int m_cursor;
static int m_topmost;
static void windowInit(void);
static void windowCleanup(void);
static void resetValues(void);
static void resizeCallback(int xsize, int ysize, void*);
static void dispatchWinmessCallback(void);
//////////
// check for supported openGL extensions we might need
static void checkOpenGLExtensions(void);
};
#endif

474
Gem/src/Gem/PBuffer.cpp Normal file
View file

@ -0,0 +1,474 @@
/* OpenGL pixel buffer
*
* Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if 0
# define debug error
#else
# define debug
#endif
#include "Gem/GemGL.h"
#ifdef __APPLE__
# include <iostream>
# include <Carbon/Carbon.h>
#else
# include <vector>
#endif
#include "PBuffer.h"
#include "Gem/RTE.h"
#ifdef GLX_VERSION_1_3
struct PBuffer_data {
Display *display;
GLXPbuffer pbuffer;
GLXContext context;
GLXPbuffer old_pbuffer;
GLXContext old_context;
};
/*
* constructor (linux specific)
*/
PBuffer::PBuffer(int width,int height,int flags) : width(width), height(height), data(NULL)
{
Display *display = glXGetCurrentDisplay();
int screen = DefaultScreen(display);
GLXContext old_context = glXGetCurrentContext();
std::vector<int> attrib;
attrib.push_back(GLX_RENDER_TYPE);
attrib.push_back(GLX_RGBA_BIT);
attrib.push_back(GLX_DRAWABLE_TYPE);
attrib.push_back(GLX_PBUFFER_BIT);
if(flags & GEM_PBUFLAG_RGB || flags & GEM_PBUFLAG_RGBA) {
attrib.push_back(GLX_RED_SIZE);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
attrib.push_back(GLX_GREEN_SIZE);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
attrib.push_back(GLX_BLUE_SIZE);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
if(flags & GEM_PBUFLAG_RGBA) {
attrib.push_back(GLX_ALPHA_SIZE);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
}
}
if(flags & GEM_PBUFLAG_DEPTH) {
attrib.push_back(GLX_DEPTH_SIZE);
attrib.push_back(24);
}
if(flags & GEM_PBUFLAG_STENCIL) {
attrib.push_back(GLX_STENCIL_SIZE);
attrib.push_back(8);
}
if(flags & GEM_PBUFLAG_FLOAT) {
attrib.push_back(GLX_FLOAT_COMPONENTS_NV);
attrib.push_back(true);
}
if(flags & GEM_PBUFLAG_MULTISAMPLE_2 || flags & GEM_PBUFLAG_MULTISAMPLE_4) {
attrib.push_back(GLX_SAMPLE_BUFFERS_ARB);
attrib.push_back(true);
attrib.push_back(GLX_SAMPLES_ARB);
attrib.push_back(flags & GEM_PBUFLAG_MULTISAMPLE_2 ? 2 : 4);
}
attrib.push_back(0);
std::vector<int> pattrib;
pattrib.push_back(GLX_LARGEST_PBUFFER);
pattrib.push_back(true);
pattrib.push_back(GLX_PRESERVED_CONTENTS);
pattrib.push_back(true);
GLXPbuffer pbuffer;
GLXContext context;
try {
int count;
GLXFBConfig *config;
if(GLXEW_SGIX_fbconfig && GLXEW_SGIX_pbuffer) {
debug("using SGIX pbuffers\n");
pattrib.push_back(0);
config = glXChooseFBConfigSGIX(display,screen,&attrib[0],&count);
if(!config) throw("glXChooseFBConfigSGIX() failed");
pbuffer = glXCreateGLXPbufferSGIX(display,config[0],width,height,&pattrib[0]);
if(!pbuffer) throw("glXCreateGLXPbufferSGIX() failed");
context = glXCreateContextWithConfigSGIX(display,config[0],GLX_RGBA_TYPE,old_context,true);
if(!context) throw("glXCreateContextWithConfigSGIX() failed");
} else if (NULL!=glXChooseFBConfig) { /* LATER make a better check! */
debug("using GLX pbuffers");
pattrib.push_back(GLX_PBUFFER_WIDTH);
pattrib.push_back(width);
pattrib.push_back(GLX_PBUFFER_HEIGHT);
pattrib.push_back(height);
pattrib.push_back(0);
config = glXChooseFBConfig(display,screen,&attrib[0],&count);
if(!config) throw("glXChooseFBConfig() failed");
pbuffer = glXCreatePbuffer(display,config[0],&pattrib[0]);
if(!pbuffer) throw("glXCreatePbuffer() failed");
XVisualInfo *visual = glXGetVisualFromFBConfig(display,config[0]);
if(!visual) throw("glXGetVisualFromFBConfig() failed");
context = glXCreateContext(display,visual,old_context,true);
if(!context) throw("glXCreateContext() failed");
} else {
throw("your system lacks PBuffer support!");
}
}
catch(const char *err) {
error("PBuffer::PBuffer(): %s",err);
pbuffer = glXGetCurrentDrawable();
context = old_context;
}
data = new PBuffer_data;
data->display = display;
data->pbuffer = pbuffer;
data->context = context;
data->old_pbuffer = glXGetCurrentDrawable();
data->old_context = old_context;
}
/*
*/
PBuffer::~PBuffer() {
if(data->context) glXDestroyContext(data->display,data->context);
if(data->pbuffer) glXDestroyPbuffer(data->display,data->pbuffer);
delete data;
}
/*
*/
void PBuffer::enable() {
data->old_pbuffer = glXGetCurrentDrawable();
data->old_context = glXGetCurrentContext();
if(!glXMakeCurrent(data->display,data->pbuffer,data->context)) {
error("PBuffer::enable(): glXMakeCurrent() failed");
}
}
/*
*/
void PBuffer::disable() {
if(!glXMakeCurrent(data->display,data->old_pbuffer,data->old_context)) {
error("PBuffer::disable(): glXMakeCurrent() failed");
}
}
#elif defined __APPLE__
#pragma mark ------AppleCode------
/*
Apple OSX pBuffer Setup
*/
struct PBuffer_data {
CGLPBufferObj pbuffer;
CGLContextObj context;
CGLContextObj old_context;
CGLPixelFormatObj pixfmt;
};
#pragma mark ---- Error Reporting ----
// ---------------------------------
float gErrorTime = 0.0;
extern AbsoluteTime gStartTime;
char gErrorMessage[256] = "";
// error reporting as both window message and debugger string
void reportError (char * strError)
{
//gErrorTime = getElapsedTime ();
//sprintf (gErrorMessage, "Error: %s (at time: %0.1f secs)", strError, gErrorTime);
error ("Error: %s", strError);
}
// ---------------------------------
// if error dump cgl errors to debugger string, return error
OSStatus cglReportError (CGLError err)
{
if (0 != err)
reportError ((char *) CGLErrorString(err));
return err;
}
/*
* constructor (APPLE specific)
*/
PBuffer::PBuffer(int width, int height, int flag) : width(width), height(height)
{
OSStatus err = noErr;
CGLPixelFormatAttribute *att,attrib[64];
GemCGLint vs, npf;
// setup offscreen context
att=attrib;
*att++=kCGLPFANoRecovery;
*att++=kCGLPFAAccelerated;
*att++=kCGLPFAWindow;
// *att++=kCGLPFAPBuffer;
*att++=kCGLPFAColorSize;
*att++=(CGLPixelFormatAttribute)32;
if (flag & GEM_PBUFLAG_DEPTH){
*att++=kCGLPFADepthSize;
//*att++=(CGLPixelFormatAttribute)24;
*att++=(CGLPixelFormatAttribute)16;
}
if (flag & GEM_PBUFLAG_STENCIL){
*att++=kCGLPFADepthSize;
*att++=(CGLPixelFormatAttribute)8;
}
if (flag & GEM_PBUFLAG_FLOAT){
// *att++=kCGLPFADepthSize;
// *att++=(CGLPixelFormatAttribute)8;
}
//*att++=kCGLPFADoubleBuffer;
// *att++=kCGLPFADisplayMask;
// *att++=kCGLPFAAllRenderers;
*att=(CGLPixelFormatAttribute)0;
data = new PBuffer_data;
data->old_context = CGLGetCurrentContext();
err = CGLGetVirtualScreen(data->old_context, &vs);
verbose (2, "Target Context (0x%X) Renderer: %s\n",data->old_context, glGetString (GL_RENDERER));
cglReportError(CGLChoosePixelFormat (attrib, &data->pixfmt, &npf));
cglReportError(CGLCreateContext (data->pixfmt, data->old_context, &(data->context)));
verbose (2, "pBuffer Context (0x%X) Renderer: %s\n",data->context, glGetString (GL_RENDERER));
/* if (float_buffer)
cglReportError( CGLCreatePBuffer ( width, height, GL_TEXTURE_2D, GL_FLOAT, 0, &(data->pbuffer) ) );
else
*/
cglReportError( CGLCreatePBuffer ( width, height, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA, 0, &(data->pbuffer) ));
cglReportError( CGLSetCurrentContext( data->context ) );
cglReportError( CGLGetVirtualScreen(data->old_context, &vs) );
cglReportError( CGLSetPBuffer(data->context, data->pbuffer, 0, 0, vs) );
verbose (2, "pbuffer (0x%X) Renderer: %s\n",data->pbuffer, glGetString (GL_RENDERER));
}
/*
*/
PBuffer::~PBuffer()
{
if(data->context) CGLDestroyContext( data->context );
if(data->pbuffer) CGLDestroyPBuffer( data->pbuffer );
if(data->pixfmt) CGLDestroyPixelFormat( data->pixfmt );
CGLSetCurrentContext(NULL);
delete data;
}
/*
*/
void PBuffer::enable()
{
GemCGLint vs;
cglReportError (CGLSetCurrentContext (data->context));
cglReportError (CGLGetVirtualScreen ( data->old_context, &vs ));
cglReportError( CGLSetPBuffer( data->context, data->pbuffer, 0, 0, vs) );
debug ("enable Context (0x%X) Renderer: %s\n",CGLGetCurrentContext(), glGetString (GL_RENDERER));
debug ("pBuffer Context (0x%X) Renderer: %s\n",data->context, glGetString (GL_RENDERER));
return;
}
/*
*/
void PBuffer::disable() {
cglReportError ( CGLSetCurrentContext( data->old_context) );
return;
}
#elif defined _WIN32
struct PBuffer_data {
HDC hdc;
HPBUFFERARB pbuffer;
HGLRC context;
HDC old_hdc;
HGLRC old_context;
};
#ifndef wglChoosePixelFormatARB
static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
#endif
#ifndef wglCreatePbufferARB
static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = NULL;
#endif
#ifndef wglGetPbufferDCARB
static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB = NULL;
#endif
#ifndef wglReleasePbufferDCARB
static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB = NULL;
#endif
#ifndef wglDestroyPbufferARB
static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = NULL;
#endif
/*
* constructor (w32 specific)
*/
PBuffer::PBuffer(int width,int height,int flags) : width(width), height(height) {
HDC old_hdc = wglGetCurrentDC();
HGLRC old_context = wglGetCurrentContext();
std::vector<int> attrib;
attrib.push_back(WGL_PIXEL_TYPE_ARB);
attrib.push_back(WGL_TYPE_RGBA_ARB);
attrib.push_back(WGL_DRAW_TO_PBUFFER_ARB);
attrib.push_back(true);
attrib.push_back(WGL_SUPPORT_OPENGL_ARB);
attrib.push_back(true);
if(flags & GEM_PBUFLAG_RGB || flags & GEM_PBUFLAG_RGBA) {
attrib.push_back(WGL_RED_BITS_ARB);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
attrib.push_back(WGL_GREEN_BITS_ARB);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
attrib.push_back(WGL_BLUE_BITS_ARB);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
if(flags & GEM_PBUFLAG_RGBA) {
attrib.push_back(WGL_ALPHA_BITS_ARB);
attrib.push_back(flags & GEM_PBUFLAG_FLOAT ? 32 : 8);
}
}
if(flags & GEM_PBUFLAG_DEPTH) {
attrib.push_back(WGL_DEPTH_BITS_ARB);
attrib.push_back(24);
}
if(flags & GEM_PBUFLAG_STENCIL) {
attrib.push_back(WGL_STENCIL_BITS_ARB);
attrib.push_back(8);
}
if(flags & GEM_PBUFLAG_FLOAT) {
attrib.push_back(WGL_FLOAT_COMPONENTS_NV);
attrib.push_back(true);
}
if(flags & GEM_PBUFLAG_MULTISAMPLE_2 || flags & GEM_PBUFLAG_MULTISAMPLE_4) {
attrib.push_back(WGL_SAMPLE_BUFFERS_ARB);
attrib.push_back(true);
attrib.push_back(WGL_SAMPLES_ARB);
attrib.push_back(flags & GEM_PBUFLAG_MULTISAMPLE_2 ? 2 : 4);
}
attrib.push_back(0);
HDC hdc;
HPBUFFERARB pbuffer;
HGLRC context;
try {
if(!wglChoosePixelFormatARB) wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
if(!wglChoosePixelFormatARB) throw("wglGetProcAddress(\"wglChoosePixelFormatARB\") failed");
if(!wglCreatePbufferARB) wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
if(!wglCreatePbufferARB) throw("wglGetProcAddress(\"wglCreatePbufferARB\") failed");
if(!wglGetPbufferDCARB) wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
if(!wglGetPbufferDCARB) throw("wglGetProcAddress(\"wglGetPbufferDCARB\") failed");
if(!wglReleasePbufferDCARB) wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
if(!wglReleasePbufferDCARB) throw("wglGetProcAddress(\"wglReleasePbufferDCARB\") failed\n");
if(!wglDestroyPbufferARB) wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
if(!wglDestroyPbufferARB) throw("wglGetProcAddress(\"wglDestroyPbufferARB\") failed\n");
int pixelformat;
unsigned int count;
wglChoosePixelFormatARB(old_hdc,&attrib[0],NULL,1,&pixelformat,&count);
if(count == 0) throw("wglChoosePixelFormatARB() failed");
int pattrib[] = { 0 };
pbuffer = wglCreatePbufferARB(old_hdc,pixelformat,width,height,pattrib);
if(!pbuffer) throw("wglCreatePbufferARB() failed");
hdc = wglGetPbufferDCARB(pbuffer);
if(!hdc) throw("wglGetPbufferDCARB() failed");
context = wglCreateContext(hdc);
if(!context) throw("wglCreateContext() failed");
if(!wglShareLists(old_context,context)) throw("wglShareLists() failed");
}
catch(const char *err) {
error("GemPBuffer: %s",err);
hdc = old_hdc;
context = old_context;
}
data = new PBuffer_data;
data->hdc = hdc;
data->pbuffer = pbuffer;
data->context = context;
data->old_hdc = old_hdc;
data->old_context = old_context;
}
/*
*/
PBuffer::~PBuffer() {
wglDeleteContext(data->context);
wglReleasePbufferDCARB(data->pbuffer,data->hdc);
wglDestroyPbufferARB(data->pbuffer);
wglMakeCurrent(data->hdc,data->context);
}
/*
*/
void PBuffer::enable() {
data->old_hdc = wglGetCurrentDC();
data->old_context = wglGetCurrentContext();
if(!wglMakeCurrent(data->hdc,data->context)) {
error("PBuffer::disable(): wglMakeCurrent() failed");
}
}
/*
*/
void PBuffer::disable() {
if(!wglMakeCurrent(data->old_hdc,data->old_context)) {
error("PBuffer::disable(): wglMakeCurrent() failed");
}
}
#else
# error do Pbuffers on your OS !
#endif /* OS */
/* dummy implementations */
PBuffer::PBuffer(const PBuffer&org) : width(org.width), height(org.height), data(NULL) {}
PBuffer&PBuffer::operator=(const PBuffer&org) { return (*this);}

54
Gem/src/Gem/PBuffer.h Normal file
View file

@ -0,0 +1,54 @@
/* OpenGL pixel buffer
*
* Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PBUFFER_H__
#define __PBUFFER_H__
struct PBuffer_data;
class PBuffer {
public:
enum {
GEM_PBUFLAG_RGB = 1 << 0,
GEM_PBUFLAG_RGBA = 1 << 1,
GEM_PBUFLAG_DEPTH = 1 << 2,
GEM_PBUFLAG_STENCIL = 1 << 3,
GEM_PBUFLAG_FLOAT = 1 << 4,
GEM_PBUFLAG_MULTISAMPLE_2 = 1 << 5,
GEM_PBUFLAG_MULTISAMPLE_4 = 1 << 6
};
PBuffer(int width,int height,int flags = GEM_PBUFLAG_RGBA | GEM_PBUFLAG_DEPTH | GEM_PBUFLAG_STENCIL);
~PBuffer(void);
void enable(void);
void disable(void);
int width;
int height;
private:
struct PBuffer_data *data;
PBuffer(const PBuffer&);
PBuffer&operator=(const PBuffer&);
};
#endif /* __PBUFFER_H__ */

173
Gem/src/Gem/PixConvert.h Normal file
View file

@ -0,0 +1,173 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
GemPixConvertSIMD.h
- header-file for color conversion
- this is mainly for (SIMD-)optimized routines
- part of GEM
Copyright (c) 2006-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_PIXCONVERT_H_
#define _INCLUDE__GEM_GEM_PIXCONVERT_H_
#include "Gem/Image.h"
#include "Utils/SIMD.h"
// use formulae from http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
/*
* [Y] 1 [ 65.738 129.075 25.064 ] [R] [ 16]
* [U] = --- * [ -37.945 -74.494 112.439 ] * [G]+[128]
* [V] = 256 [ 112.439 -94.154 -18.285 ] [B] [128]
*
* [R] 1 [ 298.082 0.0 408.583 ] [Y] [ 16]
* [G] = --- * [ 298.082 -100.291 -208.120 ] * ([U]-[128])
* [B] = 256 [ 298.082 516.411 0.0 ] [V] [128]
*/
#define YUV_POYNTON
// here comes something to be afraid of:
// (probably it would be better to define the matrices as real constant-value matrices)
// (instead of element-wise)
#ifdef YUV_POYNTON
# define Y_OFFSET 16
# define UV_OFFSET 128
// RGB2YUV
// poynton-values rounded
# define RGB2YUV_11 66
# define RGB2YUV_12 129
# define RGB2YUV_13 25
# define RGB2YUV_21 -38
# define RGB2YUV_22 -74
# define RGB2YUV_23 112
# define RGB2YUV_31 112
# define RGB2YUV_32 -94
# define RGB2YUV_33 -18
// YUV2RGB
// (we skip _21 and _31 as they are equal to _11)
#if 0
// poynton-values rounded
# define YUV2RGB_11 298
# define YUV2RGB_12 0
# define YUV2RGB_13 409
# define YUV2RGB_22 -100
# define YUV2RGB_23 -208
# define YUV2RGB_32 516
# define YUV2RGB_33 0
#else
// this is round(256*inv(rgb2yuv/256))
// so the general error should be smaller
# define YUV2RGB_11 298
# define YUV2RGB_12 -1
# define YUV2RGB_13 409
# define YUV2RGB_22 -100
# define YUV2RGB_23 -210
# define YUV2RGB_32 519
# define YUV2RGB_33 0
#endif
#else
/* the old ones: */
# define Y_OFFSET 0
# define UV_OFFSET 128
// RGB2YUV
# define RGB2YUV_11 77
# define RGB2YUV_12 150
# define RGB2YUV_13 29
# define RGB2YUV_21 -43
# define RGB2YUV_22 -85
# define RGB2YUV_23 128
# define RGB2YUV_31 128
# define RGB2YUV_32 -107
# define RGB2YUV_33 -21
// YUV2RGB
# define YUV2RGB_11 256
# define YUV2RGB_12 0
# define YUV2RGB_13 359
# define YUV2RGB_22 -88
# define YUV2RGB_23 -183
# define YUV2RGB_32 454
# define YUV2RGB_33 0
#endif /* POYNTON */
#if 0
/* yuv-coefficients would also need an offset! */
# define RGB2GRAY_RED RGB2YUV_11
# define RGB2GRAY_GREEN RGB2YUV_12
# define RGB2GRAY_BLUE RGB2YUV_13
# define RGB2GRAY_OFFSET Y_OFFSET
#else
# define RGB2GRAY_RED 77
# define RGB2GRAY_GREEN 150
# define RGB2GRAY_BLUE 29
# define RGB2GRAY_OFFSET 0
#endif
/* AltiVec */
#ifdef __VEC__
/* there are problems on OSX10.3 with older versions of gcc, since the intrinsic code
* below freely changes between signed and unsigned short vectors
* newer versions of gcc accept this...
* LATER: fix the code (GemPixConvertAltivec:750..800)
*/
# ifdef __GNUC__
/* according to hcs it does NOT work with gcc-3.3
* for simplicity, i disable everything below gcc4
* JMZ: 20061114
*/
# if __GNUC__ < 4
# warning disabling AltiVec for older gcc: please fix me
# define NO_VECTORINT_TO_VECTORUNSIGNEDINT
# endif
# endif /* GNUC */
void RGB_to_YCbCr_altivec(const unsigned char *rgbdata, size_t RGB_size,
unsigned char *pixels);
void RGBA_to_YCbCr_altivec(const unsigned char *rgbadata, size_t RGBA_size,
unsigned char *pixels);
void BGR_to_YCbCr_altivec(const unsigned char *bgrdata, size_t BGR_size,
unsigned char *pixels);
void BGRA_to_YCbCr_altivec(const unsigned char *bgradata, size_t BGRA_size,
unsigned char *pixels);
void YUV422_to_BGRA_altivec(const unsigned char *yuvdata, size_t pixelnum,
unsigned char *pixels);
void YV12_to_YUV422_altivec(const short*Y, const short*U, const short*V,
unsigned char *data, int xsize, int ysize);
# ifndef NO_VECTORINT_TO_VECTORUNSIGNEDINT
void YUV422_to_YV12_altivec(short*pY, short*pY2, short*pU, short*pV,
const unsigned char *gem_image, int xsize, int ysize);
# endif
#endif /* AltiVec */
/* SSE2 */
#ifdef __SSE2__
void RGBA_to_UYVY_SSE2(const unsigned char *rgbadata,
size_t size,
unsigned char *yuvdata);
void UYVY_to_RGBA_SSE2(const unsigned char *yuvdata,
size_t size,
unsigned char *rgbadata);
void UYVY_to_RGB_SSE2(const unsigned char *yuvdata,
size_t size,
unsigned char *rgbadata);
#endif /* SSE2 */
/* in case somebody has an old machine... */
#ifdef __MMX__
#endif /* MMX */
#endif /* _INCLUDE__GEM_GEM_PIXCONVERT_H_ */

View file

@ -0,0 +1,827 @@
#include "Utils/SIMD.h"
#ifdef __VEC__
/////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file for AltiVec-optimized color-conversion routines
//
// Copyright (c) 2005-2006 James Tittle
// Copyright (c) 2005-2006 Chris Clepper
// Copyright (c) 2006-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "PixConvert.h"
void RGB_to_YCbCr_altivec(const unsigned char *rgbdata, size_t RGB_size,
unsigned char *pixels)
{
vector signed short r0, r1, r2, g0, g1, g2, b0, b1, b2, c0, c16, c128;
vector unsigned char z0, tc0, tc1, tc2, tc3;
vector signed short tr0, tr1, tg0, tg1, tb0, tb1;
vector signed short t0, t1, t2, t3, t4, t5;
unsigned int i;
const vector unsigned char *RGB_ptr = reinterpret_cast<const vector unsigned char*>( rgbdata);
vector unsigned char *YCC_ptr = reinterpret_cast<vector unsigned char*>( pixels);
/* Permutation vector is used to extract the interleaved RGB. */
vector unsigned char vPerm1 =
static_cast<vector unsigned char>( 0, 3, 6, 9, 12, 15, 18, 21, /* R0..R7 */
1, 4, 7, 10, 13, 16, 19, 22 /* G0..G7 */);
vector unsigned char vPerm2 =
static_cast<vector unsigned char>( 2, 5, 8, 11, 14, 17, 20, 23, /* B0..B7 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
vector unsigned char vPerm3 =
static_cast<vector unsigned char>( 8, 11, 14, 17, 20, 23, 26, 29, /* R8..R15 */
9, 12, 15, 18, 21, 24, 27, 30 /* G8..G15 */);
vector unsigned char vPerm4 =
static_cast<vector unsigned char>(10, 13, 16, 19, 22, 25, 28, 31, /* B8..B15 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
/* Load the equation constants. */
vector signed short vConst1 =
static_cast<vector signed short>( 8432, 16425, 3176,
-4818, -9527, 14345,
0, 0 );
vector signed short vConst2 =
static_cast<vector signed short>( 14345, -12045, -2300,
16, 128, 0, 0, 0 );
r0 = vec_splat( vConst1, 0 ); /* 8432 */
g0 = vec_splat( vConst1, 1 ); /* 16425 */
b0 = vec_splat( vConst1, 2 ); /* 3176 */
r1 = vec_splat( vConst1, 3 ); /* -4818 */
g1 = vec_splat( vConst1, 4 ); /* -9527 */
b1 = vec_splat( vConst1, 5 ); /* 14345 */
r2 = vec_splat( vConst2, 0 ); /* 14345 */
g2 = vec_splat( vConst2, 1 ); /*-12045 */
b2 = vec_splat( vConst2, 2 ); /* -2300 */
c16 = vec_splat( vConst2, 3 ); /* 16 */
c128 = vec_splat( vConst2, 4 ); /* 128 */
c0 = static_cast<vector signed short> (0); /* 0 */
z0 = static_cast<vector unsigned char> (0); /* 0 */
for ( i = 0; i < (RGB_size/sizeof(vector unsigned char)); i+=3 ) {
/* Load the 3 RGB input vectors and seperate into red,
green and blue from the interleaved format. */
tc0 = vec_perm( RGB_ptr[i], RGB_ptr[i+1], vPerm1 ); /* R0..R7 G0..G7 */
tc1 = vec_perm( RGB_ptr[i], RGB_ptr[i+1], vPerm2 ); /* B0..B7 */
tc2 = vec_perm( RGB_ptr[i+1], RGB_ptr[i+2], vPerm3 ); /* R8..R15 G8..G15 */
tc3 = vec_perm( RGB_ptr[i+1], RGB_ptr[i+2], vPerm4 ); /* B8..B15 */
/* Unpack to 16 bit arithmatic for converstion. */
tr0 = static_cast<vector signed short>(vec_mergeh( z0, tc0 )); // tr0 = R0 .. R7
tg0 = static_cast<vector signed short>(vec_mergel( z0, tc0 )); // tg0 = G0 .. G7
tb0 = static_cast<vector signed short>(vec_mergeh( z0, tc1 )); // tb0 = B0 .. B7
tr1 = static_cast<vector signed short>(vec_mergeh( z0, tc2 )); // tr0 = R8 .. R15
tg1 = static_cast<vector signed short>(vec_mergel( z0, tc2 )); // tg0 = G8 .. G15
tb1 = static_cast<vector signed short>(vec_mergeh( z0, tc3 )); // tb0 = B8 .. B15
/* Convert the first three input vectors. Note that
only the top 17 bits of the 32 bit product are
stored. This is the same as doing the divide by 32768. */
t0 = vec_mradds( tr0, r0, c0 ); /* (R0 .. R7) * 8432 */
t1 = vec_mradds( tr0, r1, c0 ); /* (R0 .. R7) * -4818 */
t2 = vec_mradds( tr0, r2, c0 ); /* (R0 .. R7) * 14345 */
t0 = vec_mradds( tg0, g0, t0 ); /* += (G0 .. G7) * 16425 */
t1 = vec_mradds( tg0, g1, t1 ); /* += (G0 .. G7) * -9527 */
t2 = vec_mradds( tg0, g2, t2 ); /* += (G0 .. G7) * -12045 */
t0 = vec_mradds( tb0, b0, t0 ); /* += (B0 .. B7) * 3176 */
t1 = vec_mradds( tb0, b1, t1 ); /* += (B0 .. B7) * 14345 */
t2 = vec_mradds( tb0, b2, t2 ); /* += (B0 .. B7) * -2300 */
/* Convert the next three input vectors. */
t3 = vec_mradds( tr1, r0, c0 ); /* (R8 .. R15) * 8432 */
t4 = vec_mradds( tr1, r1, c0 ); /* (R8 .. R15) * -4818 */
t5 = vec_mradds( tr1, r2, c0 ); /* (R8 .. R15) * 14345 */
t3 = vec_mradds( tg1, g0, t3 ); /* += (G8 .. G15) * 16425 */
t4 = vec_mradds( tg1, g1, t4 ); /* += (G8 .. G15) * -9527 */
t5 = vec_mradds( tg1, g2, t5 ); /* += (G8 .. G15) * -12045 */
t3 = vec_mradds( tb1, b0, t3 ); /* += (B8 .. B15) * 3176 */
t4 = vec_mradds( tb1, b1, t4 ); /* += (B8 .. B15) * 14345 */
t5 = vec_mradds( tb1, b2, t5 ); /* += (B8 .. B15) * -2300 */
/* Add the constants. */
t0 = vec_adds( t0, c16 );
t3 = vec_adds( t3, c16 );
t1 = vec_adds( t1, c128 );
t4 = vec_adds( t4, c128 );
t2 = vec_adds( t2, c128 );
t5 = vec_adds( t5, c128 );
/* Pack the results, and store them. */
YCC_ptr[i] = vec_packsu( t0, t3 ); /* Y0 .. Y15 */
YCC_ptr[i+1] = vec_packsu( t1, t4 ); /* Cb0 .. Cb15 */
YCC_ptr[i+2] = vec_packsu( t2, t5 ); /* Cr0 .. Cr15 */
}
}
void RGBA_to_YCbCr_altivec(const unsigned char *rgbadata, size_t RGBA_size,
unsigned char *pixels)
{
vector signed short r0, r1, r2, g0, g1, g2, b0, b1, b2, c0, c16, c128;
vector unsigned char z0, tc0, tc1, tc2, tc3;
vector signed short tr0, tr1, tg0, tg1, tb0, tb1;
vector signed short t0, t1, t2, t3, t4, t5;
unsigned int i;
const vector unsigned char *RGBA_ptr = reinterpret_cast<const vector unsigned char*>( rgbadata);
vector unsigned char *YCC_ptr = reinterpret_cast<vector unsigned char*>( pixels);
/* Permutation vector is used to extract the interleaved RGBA. */
vector unsigned char vPerm1 =
static_cast<vector unsigned char>( 0, 4, 8, 12, 16, 20, 24, 28, /* R0..R7 */
1, 5, 9, 13, 17, 21, 25, 29 /* G0..G7 */);
vector unsigned char vPerm2 =
static_cast<vector unsigned char>( 2, 6, 10, 14, 18, 22, 26, 30, /* B0..B7 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
vector unsigned char vPerm3 =
static_cast<vector unsigned char>( 8, 12, 16, 20, 24, 28, 32, 36, /* R8..R15 */
9, 13, 17, 21, 25, 29, 33, 37 /* G8..G15 */);
vector unsigned char vPerm4 =
static_cast<vector unsigned char>(10, 14, 18, 22, 26, 30, 34, 38, /* B8..B15 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
/* Load the equation constants. */
vector signed short vConst1 =
static_cast<vector signed short>( 8432, 16425, 3176,
-4818, -9527, 14345,
0, 0 );
vector signed short vConst2 =
static_cast<vector signed short>( 14345, -12045, -2300,
16, 128, 0, 0, 0 );
r0 = vec_splat( vConst1, 0 ); /* 8432 */
g0 = vec_splat( vConst1, 1 ); /* 16425 */
b0 = vec_splat( vConst1, 2 ); /* 3176 */
r1 = vec_splat( vConst1, 3 ); /* -4818 */
g1 = vec_splat( vConst1, 4 ); /* -9527 */
b1 = vec_splat( vConst1, 5 ); /* 14345 */
r2 = vec_splat( vConst2, 0 ); /* 14345 */
g2 = vec_splat( vConst2, 1 ); /*-12045 */
b2 = vec_splat( vConst2, 2 ); /* -2300 */
c16 = vec_splat( vConst2, 3 ); /* 16 */
c128 = vec_splat( vConst2, 4 ); /* 128 */
c0 = static_cast<vector signed short> (0); /* 0 */
z0 = static_cast<vector unsigned char> (0); /* 0 */
for ( i = 0; i < (RGBA_size/sizeof(vector unsigned char)); i+=3 ) {
/* Load the 3 RGB input vectors and seperate into red,
green and blue from the interleaved format. */
tc0 = vec_perm( RGBA_ptr[i], RGBA_ptr[i+1], vPerm1 ); /* R0..R7 G0..G7 */
tc1 = vec_perm( RGBA_ptr[i], RGBA_ptr[i+1], vPerm2 ); /* B0..B7 */
tc2 = vec_perm( RGBA_ptr[i+1], RGBA_ptr[i+2], vPerm3 ); /* R8..R15 G8..G15 */
tc3 = vec_perm( RGBA_ptr[i+1], RGBA_ptr[i+2], vPerm4 ); /* B8..B15 */
/* Unpack to 16 bit arithmatic for converstion. */
tr0 = static_cast<vector signed short>(vec_mergeh( z0, tc0 )); /* tr0 = R0 .. R7 */
tg0 = static_cast<vector signed short>(vec_mergel( z0, tc0 )); /* tg0 = G0 .. G7 */
tb0 = static_cast<vector signed short>(vec_mergeh( z0, tc1 )); /* tb0 = B0 .. B7 */
tr1 = static_cast<vector signed short>(vec_mergeh( z0, tc2 )); /* tr0 = R8 .. R15 */
tg1 = static_cast<vector signed short>(vec_mergel( z0, tc2 )); /* tg0 = G8 .. G15 */
tb1 = static_cast<vector signed short>(vec_mergeh( z0, tc3 )); /* tb0 = B8 .. B15 */
/* Convert the first three input vectors. Note that
only the top 17 bits of the 32 bit product are
stored. This is the same as doing the divide by 32768. */
t0 = vec_mradds( tr0, r0, c0 ); /* (R0 .. R7) * 8432 */
t1 = vec_mradds( tr0, r1, c0 ); /* (R0 .. R7) * -4818 */
t2 = vec_mradds( tr0, r2, c0 ); /* (R0 .. R7) * 14345 */
t0 = vec_mradds( tg0, g0, t0 ); /* += (G0 .. G7) * 16425 */
t1 = vec_mradds( tg0, g1, t1 ); /* += (G0 .. G7) * -9527 */
t2 = vec_mradds( tg0, g2, t2 ); /* += (G0 .. G7) * -12045 */
t0 = vec_mradds( tb0, b0, t0 ); /* += (B0 .. B7) * 3176 */
t1 = vec_mradds( tb0, b1, t1 ); /* += (B0 .. B7) * 14345 */
t2 = vec_mradds( tb0, b2, t2 ); /* += (B0 .. B7) * -2300 */
/* Convert the next three input vectors. */
t3 = vec_mradds( tr1, r0, c0 ); /* (R8 .. R15) * 8432 */
t4 = vec_mradds( tr1, r1, c0 ); /* (R8 .. R15) * -4818 */
t5 = vec_mradds( tr1, r2, c0 ); /* (R8 .. R15) * 14345 */
t3 = vec_mradds( tg1, g0, t3 ); /* += (G8 .. G15) * 16425 */
t4 = vec_mradds( tg1, g1, t4 ); /* += (G8 .. G15) * -9527 */
t5 = vec_mradds( tg1, g2, t5 ); /* += (G8 .. G15) * -12045 */
t3 = vec_mradds( tb1, b0, t3 ); /* += (B8 .. B15) * 3176 */
t4 = vec_mradds( tb1, b1, t4 ); /* += (B8 .. B15) * 14345 */
t5 = vec_mradds( tb1, b2, t5 ); /* += (B8 .. B15) * -2300 */
/* Add the constants. */
t0 = vec_adds( t0, c16 );
t3 = vec_adds( t3, c16 );
t1 = vec_adds( t1, c128 );
t4 = vec_adds( t4, c128 );
t2 = vec_adds( t2, c128 );
t5 = vec_adds( t5, c128 );
/* Pack the results, and store them. */
YCC_ptr[i] = vec_packsu( t0, t3 ); /* Y0 .. Y15 */
YCC_ptr[i+1] = vec_packsu( t1, t4 ); /* Cb0 .. Cb15 */
YCC_ptr[i+2] = vec_packsu( t2, t5 ); /* Cr0 .. Cr15 */
}
}
void BGR_to_YCbCr_altivec(const unsigned char *bgrdata, size_t BGR_size,
unsigned char *pixels)
{
vector signed short r0, r1, r2, g0, g1, g2, b0, b1, b2, c0, c16, c128;
vector unsigned char z0, tc0, tc1, tc2, tc3;
vector signed short tr0, tr1, tg0, tg1, tb0, tb1;
vector signed short t0, t1, t2, t3, t4, t5;
unsigned int i;
const vector unsigned char *BGR_ptr = reinterpret_cast<const vector unsigned char*>( bgrdata);
vector unsigned char *YCC_ptr = reinterpret_cast<vector unsigned char*>( pixels);
/* Permutation vector is used to extract the interleaved RGB. */
vector unsigned char vPerm1 =
static_cast<vector unsigned char>( 0, 3, 6, 9, 12, 15, 18, 21, /* R0..R7 */
1, 4, 7, 10, 13, 16, 19, 22 /* G0..G7 */);
vector unsigned char vPerm2 =
static_cast<vector unsigned char>( 2, 5, 8, 11, 14, 17, 20, 23, /* B0..B7 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
vector unsigned char vPerm3 =
static_cast<vector unsigned char>( 8, 11, 14, 17, 20, 23, 26, 29, /* R8..R15 */
9, 12, 15, 18, 21, 24, 27, 30 /* G8..G15 */);
vector unsigned char vPerm4 =
static_cast<vector unsigned char>(10, 13, 16, 19, 22, 25, 28, 31, /* B8..B15 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
/* Load the equation constants. */
vector signed short vConst1 =
static_cast<vector signed short>( 8432, 16425, 3176,
-4818, -9527, 14345,
0, 0 );
vector signed short vConst2 =
static_cast<vector signed short>( 14345, -12045, -2300,
16, 128, 0, 0, 0 );
r0 = vec_splat( vConst1, 0 ); /* 8432 */
g0 = vec_splat( vConst1, 1 ); /* 16425 */
b0 = vec_splat( vConst1, 2 ); /* 3176 */
r1 = vec_splat( vConst1, 3 ); /* -4818 */
g1 = vec_splat( vConst1, 4 ); /* -9527 */
b1 = vec_splat( vConst1, 5 ); /* 14345 */
r2 = vec_splat( vConst2, 0 ); /* 14345 */
g2 = vec_splat( vConst2, 1 ); /*-12045 */
b2 = vec_splat( vConst2, 2 ); /* -2300 */
c16 = vec_splat( vConst2, 3 ); /* 16 */
c128 = vec_splat( vConst2, 4 ); /* 128 */
c0 = static_cast<vector signed short> (0); /* 0 */
z0 = static_cast<vector unsigned char> (0); /* 0 */
for ( i = 0; i < (BGR_size/sizeof(vector unsigned char)); i+=3 ) {
/* Load the 3 RGB input vectors and seperate into red,
green and blue from the interleaved format. */
tc0 = vec_perm( BGR_ptr[i], BGR_ptr[i+1], vPerm1 ); /* R0..R7 G0..G7 */
tc1 = vec_perm( BGR_ptr[i], BGR_ptr[i+1], vPerm2 ); /* B0..B7 */
tc2 = vec_perm( BGR_ptr[i+1], BGR_ptr[i+2], vPerm3 ); /* R8..R15 G8..G15 */
tc3 = vec_perm( BGR_ptr[i+1], BGR_ptr[i+2], vPerm4 ); /* B8..B15 */
/* Unpack to 16 bit arithmatic for converstion. */
tr0 = static_cast<vector signed short>(vec_mergeh( z0, tc0 )); /* tr0 = R0 .. R7 */
tg0 = static_cast<vector signed short>(vec_mergel( z0, tc0 )); /* tg0 = G0 .. G7 */
tb0 = static_cast<vector signed short>(vec_mergeh( z0, tc1 )); /* tb0 = B0 .. B7 */
tr1 = static_cast<vector signed short>(vec_mergeh( z0, tc2 )); /* tr0 = R8 .. R15 */
tg1 = static_cast<vector signed short>(vec_mergel( z0, tc2 )); /* tg0 = G8 .. G15 */
tb1 = static_cast<vector signed short>(vec_mergeh( z0, tc3 )); /* tb0 = B8 .. B15 */
/* Convert the first three input vectors. Note that
only the top 17 bits of the 32 bit product are
stored. This is the same as doing the divide by 32768. */
t0 = vec_mradds( tr0, r0, c0 ); /* (R0 .. R7) * 8432 */
t1 = vec_mradds( tr0, r1, c0 ); /* (R0 .. R7) * -4818 */
t2 = vec_mradds( tr0, r2, c0 ); /* (R0 .. R7) * 14345 */
t0 = vec_mradds( tg0, g0, t0 ); /* += (G0 .. G7) * 16425 */
t1 = vec_mradds( tg0, g1, t1 ); /* += (G0 .. G7) * -9527 */
t2 = vec_mradds( tg0, g2, t2 ); /* += (G0 .. G7) * -12045 */
t0 = vec_mradds( tb0, b0, t0 ); /* += (B0 .. B7) * 3176 */
t1 = vec_mradds( tb0, b1, t1 ); /* += (B0 .. B7) * 14345 */
t2 = vec_mradds( tb0, b2, t2 ); /* += (B0 .. B7) * -2300 */
/* Convert the next three input vectors. */
t3 = vec_mradds( tr1, r0, c0 ); /* (R8 .. R15) * 8432 */
t4 = vec_mradds( tr1, r1, c0 ); /* (R8 .. R15) * -4818 */
t5 = vec_mradds( tr1, r2, c0 ); /* (R8 .. R15) * 14345 */
t3 = vec_mradds( tg1, g0, t3 ); /* += (G8 .. G15) * 16425 */
t4 = vec_mradds( tg1, g1, t4 ); /* += (G8 .. G15) * -9527 */
t5 = vec_mradds( tg1, g2, t5 ); /* += (G8 .. G15) * -12045 */
t3 = vec_mradds( tb1, b0, t3 ); /* += (B8 .. B15) * 3176 */
t4 = vec_mradds( tb1, b1, t4 ); /* += (B8 .. B15) * 14345 */
t5 = vec_mradds( tb1, b2, t5 ); /* += (B8 .. B15) * -2300 */
/* Add the constants. */
t0 = vec_adds( t0, c16 );
t3 = vec_adds( t3, c16 );
t1 = vec_adds( t1, c128 );
t4 = vec_adds( t4, c128 );
t2 = vec_adds( t2, c128 );
t5 = vec_adds( t5, c128 );
/* Pack the results, and store them. */
YCC_ptr[i] = vec_packsu( t0, t3 ); /* Y0 .. Y15 */
YCC_ptr[i+1] = vec_packsu( t1, t4 ); /* Cb0 .. Cb15 */
YCC_ptr[i+2] = vec_packsu( t2, t5 ); /* Cr0 .. Cr15 */
}
}
void BGRA_to_YCbCr_altivec(const unsigned char *bgradata, size_t BGRA_size,
unsigned char *pixels)
{
vector signed short r0, r1, r2, g0, g1, g2, b0, b1, b2, c0, c16, c128;
vector unsigned char z0, tc0, tc1, tc2, tc3;
vector signed short tr0, tr1, tg0, tg1, tb0, tb1;
vector signed short t0, t1, t2, t3, t4, t5;
vector signed short u1, u2, uAvg, v1, v2, vAvg, out1, out2, out3, out4, uv1, uv2;
unsigned int i;
const vector unsigned char *BGRA_ptr = reinterpret_cast<const vector unsigned char*>( bgradata);
vector unsigned char *UYVY_ptr = reinterpret_cast<vector unsigned char*>( pixels);
/* Permutation vector is used to extract the interleaved BGRA. */
vector unsigned char vPerm1 =
static_cast<vector unsigned char>( 3, 7, 11, 15, 19, 23, 27, 31, // B0..B7
2, 6, 10, 14, 18, 22, 26, 30 /* G0..G7 */);
vector unsigned char vPerm2 =
static_cast<vector unsigned char>( 1, 5, 9, 13, 17, 21, 25, 29, /* R0..R7 */
0, 0, 0, 0, 0, 0, 0, 0 /* dont care */);
/* Load the equation constants. */
vector signed short vConst1 =
static_cast<vector signed short>( 8432, 16425, 3176,
-4818, -9527, 14345,
0, 0 );
vector signed short vConst2 =
static_cast<vector signed short>( 14345, -12045, -2300,
16, 128, 0, 0, 0 );
vector unsigned char avgPerm1 =
static_cast<vector unsigned char>( 0, 1, 4, 5, 8, 9, 12, 13,
16, 17, 20, 21, 24, 25, 28, 29 );
vector unsigned char avgPerm2 =
static_cast<vector unsigned char>( 2, 3, 6, 7, 10, 11, 14, 15,
18, 19, 22, 23, 26, 27, 30, 31 );
vector unsigned char Perm1 =
static_cast<vector unsigned char>( 0, 1, 16, 17, 2, 3, 18, 19,
4, 5, 20, 21, 6, 7, 22, 23 );
vector unsigned char Perm2 =
static_cast<vector unsigned char>( 8, 9, 24, 25, 10, 11, 26, 27,
12, 13, 28, 29, 14, 15, 30, 31 );
r0 = vec_splat( vConst1, 2 ); /* 8432 */
g0 = vec_splat( vConst1, 1 ); /* 16425 */
b0 = vec_splat( vConst1, 0 ); /* 3176 */
r1 = vec_splat( vConst1, 5 ); /* -4818 */
g1 = vec_splat( vConst1, 4 ); /* -9527 */
b1 = vec_splat( vConst1, 3 ); /* 14345 */
r2 = vec_splat( vConst2, 2 ); /* 14345 */
g2 = vec_splat( vConst2, 1 ); /*-12045 */
b2 = vec_splat( vConst2, 0 ); /* -2300 */
c16 = vec_splat( vConst2, 3 ); /* 16 */
c128 = vec_splat( vConst2, 4 ); /* 128 */
c0 = static_cast<vector signed short> (0); /* 0 */
z0 = static_cast<vector unsigned char> (0); /* 0 */
for ( i = 0; i < (BGRA_size/sizeof(vector unsigned char)); i++ ) {
/* Load the 4 BGRA input vectors and seperate into red,
green and blue from the interleaved format. */
const vector unsigned char *vec1 = BGRA_ptr++;
const vector unsigned char *vec2 = BGRA_ptr++;
const vector unsigned char *vec3 = BGRA_ptr++;
const vector unsigned char *vec4 = BGRA_ptr++;
tc0 = vec_perm( *vec1, *vec2, vPerm1 ); // B0..B7 G0..G7
tc1 = vec_perm( *vec1, *vec2, vPerm2 ); // R0..R7
tc2 = vec_perm( *vec3, *vec4, vPerm1 ); // B8..B15 G8..G15
tc3 = vec_perm( *vec3, *vec4, vPerm2 ); // R8..R15
/* Unpack to 16 bit arithmatic for conversion. */
tr0 = static_cast<vector signed short>(vec_mergeh( z0, tc0 )); /* tr0 = R0 .. R7 */
tg0 = static_cast<vector signed short>(vec_mergel( z0, tc0 )); /* tg0 = G0 .. G7 */
tb0 = static_cast<vector signed short>(vec_mergeh( z0, tc1 )); /* tb0 = B0 .. B7 */
tr1 = static_cast<vector signed short>(vec_mergeh( z0, tc2 )); /* tr0 = R8 .. R15 */
tg1 = static_cast<vector signed short>(vec_mergel( z0, tc2 )); /* tg0 = G8 .. G15 */
tb1 = static_cast<vector signed short>(vec_mergeh( z0, tc3 )); /* tb0 = B8 .. B15 */
/* Convert the first three input vectors. Note that
only the top 17 bits of the 32 bit product are
stored. This is the same as doing the divide by 32768. */
t0 = vec_mradds( tr0, r0, c0 ); /* (R0 .. R7) * 8432 */
t1 = vec_mradds( tr0, r1, c0 ); /* (R0 .. R7) * -4818 */
t2 = vec_mradds( tr0, r2, c0 ); /* (R0 .. R7) * 14345 */
t0 = vec_mradds( tg0, g0, t0 ); /* += (G0 .. G7) * 16425 */
t1 = vec_mradds( tg0, g1, t1 ); /* += (G0 .. G7) * -9527 */
t2 = vec_mradds( tg0, g2, t2 ); /* += (G0 .. G7) * -12045 */
t0 = vec_mradds( tb0, b0, t0 ); /* += (B0 .. B7) * 3176 */
t1 = vec_mradds( tb0, b1, t1 ); /* += (B0 .. B7) * 14345 */
t2 = vec_mradds( tb0, b2, t2 ); /* += (B0 .. B7) * -2300 */
/* Convert the next three input vectors. */
t3 = vec_mradds( tr1, r0, c0 ); /* (R8 .. R15) * 8432 */
t4 = vec_mradds( tr1, r1, c0 ); /* (R8 .. R15) * -4818 */
t5 = vec_mradds( tr1, r2, c0 ); /* (R8 .. R15) * 14345 */
t3 = vec_mradds( tg1, g0, t3 ); /* += (G8 .. G15) * 16425 */
t4 = vec_mradds( tg1, g1, t4 ); /* += (G8 .. G15) * -9527 */
t5 = vec_mradds( tg1, g2, t5 ); /* += (G8 .. G15) * -12045 */
t3 = vec_mradds( tb1, b0, t3 ); /* += (B8 .. B15) * 3176 */
t4 = vec_mradds( tb1, b1, t4 ); /* += (B8 .. B15) * 14345 */
t5 = vec_mradds( tb1, b2, t5 ); /* += (B8 .. B15) * -2300 */
/* Add the constants. */
t0 = vec_adds( t0, c16 );
t3 = vec_adds( t3, c16 );
t1 = vec_adds( t1, c128 );
t4 = vec_adds( t4, c128 );
t2 = vec_adds( t2, c128 );
t5 = vec_adds( t5, c128 );
u1 = vec_perm( t1, t4, avgPerm1 ); // rearrange U's for averaging
u2 = vec_perm( t1, t4, avgPerm2 );
uAvg = vec_avg( u1, u2 );
v1 = vec_perm( t2, t5, avgPerm1 ); // rearrange V's for averaging
v2 = vec_perm( t2, t5, avgPerm2 );
vAvg = vec_avg( v1, v2 );
uv1 = vec_perm( uAvg, vAvg, Perm1 );
uv2 = vec_perm( uAvg, vAvg, Perm2 );
out1 = vec_perm( uv1, t0, Perm1 );
out2 = vec_perm( uv1, t0, Perm2 );
out3 = vec_perm( uv2, t3, Perm1 );
out4 = vec_perm( uv2, t3, Perm2 );
*UYVY_ptr = vec_packsu( out1, out2 ); // pack down to char's
UYVY_ptr++;
*UYVY_ptr = vec_packsu( out3, out4 );
UYVY_ptr++;
}
}
void YV12_to_YUV422_altivec(const short*Y, const short*U, const short*V,
unsigned char *data, int xsize, int ysize)
{
// from geowar@apple.com, 3/15/2005
// #1. Don't use the pointers. Use vec_ld with an index that you increment (by 16) instead.
vector unsigned char *pixels1=reinterpret_cast<vector unsigned char *>(data);
vector unsigned char *pixels2=reinterpret_cast<vector unsigned char *>(data+(xsize*2));
const vector unsigned short *py1 = reinterpret_cast<const vector unsigned short *>(Y);
const vector unsigned short *py2 = reinterpret_cast<const vector unsigned short *>(Y + xsize );
const vector unsigned short *pu = reinterpret_cast<const vector unsigned short *>(U);
const vector unsigned short *pv = reinterpret_cast<const vector unsigned short *>(V);
vector unsigned short uvAdd = static_cast<vector unsigned short>( 128, 128, 128, 128,
128, 128, 128, 128 );
vector unsigned short yShift = static_cast<vector unsigned short>( 7, 7, 7, 7, 7, 7, 7, 7 );
vector unsigned short uvShift = static_cast<vector unsigned short>( 8, 8, 8, 8, 8, 8, 8, 8 );
vector unsigned short tempU, tempV, doneU, doneV, tempY1, tempY2, tempY3, tempY4,
uv1, uv2, out1, out2, out3, out4, out5, out6, out7, out8;
vector unsigned char Perm1 =
static_cast<vector unsigned char>( 0, 1, 16, 17, 2, 3, 18, 19,
4, 5, 20, 21, 6, 7, 22, 23 );
vector unsigned char Perm2 =
static_cast<vector unsigned char>( 8, 9, 24, 25, 10, 11, 26, 27,
12, 13, 28, 29, 14, 15, 30, 31 );
int row=ysize>>1;
int cols=xsize>>4;
#if 0
# ifndef PPC970
UInt32 prefetchSize = GetPrefetchConstant( 16, 1, 256 );
vec_dst( pu, prefetchSize, 0 );
vec_dst( pv, prefetchSize, 0 );
vec_dst( py1, prefetchSize, 0 );
vec_dst( py2, prefetchSize, 0 );
# endif
#endif
while(row--){
int col=cols;
while(col--){
#if 0
# ifndef PPC970
vec_dst( );
# endif
#endif
tempU = vec_sra( (*pu++), uvShift );
tempV = vec_sra( (*pv++), uvShift );
doneU = vec_add( tempU, uvAdd );
doneV = vec_add( tempV, uvAdd );
uv1 = vec_perm( doneU, doneV, Perm1 ); // uvuvuvuv uvuvuvuv
uv2 = vec_perm( doneU, doneV, Perm2 );
tempY1 = vec_sra( (*py1++), yShift );
tempY2 = vec_sra( (*py2++), yShift );
out1 = vec_perm( uv1, tempY1, Perm1 ); //fill Y's, U's & V's
out2 = vec_perm( uv1, tempY1, Perm2 );
out3 = vec_perm( uv1, tempY2, Perm1 ); //fill 2nd Y's, U's & V's
out4 = vec_perm( uv1, tempY2, Perm2 );
*pixels1 = vec_packsu( out1, out2 );
*pixels2 = vec_packsu( out3, out4 );
pixels1++; pixels2++;
tempY3 = vec_sra( (*py1++), yShift ); // load second set of Y's
tempY4 = vec_sra( (*py2++), yShift );
out5 = vec_perm( uv2, tempY3, Perm1 );
out6 = vec_perm( uv2, tempY3, Perm2 );
out7 = vec_perm( uv2, tempY4, Perm1 );
out8 = vec_perm( uv2, tempY4, Perm2 );
*pixels1 = vec_packsu( out5, out6 );
*pixels2 = vec_packsu( out7, out8 );
pixels1++; pixels2++;
}
pixels1+=(xsize*2)>>4; pixels2+=(xsize*2)>>4;
py1+=xsize>>3; py2+=xsize>>3;
}
}
void YUV422_to_YV12_altivec(short*pY, short*pY2, short*pU, short*pV,
const unsigned char *gem_image, int xsize, int ysize)
{
// UYVY UYVY UYVY UYVY
const vector unsigned char *pixels1=reinterpret_cast<const vector unsigned char *>(gem_image);
const vector unsigned char *pixels2=reinterpret_cast<const vector unsigned char *>(gem_image+(xsize*2));
// PDP packet to be filled:
// first Y plane
vector signed short *py1 = reinterpret_cast<vector signed short *>(pY);
// 2nd Y pixel
vector signed short *py2 = reinterpret_cast<vector signed short *>(pY2);
// U plane
vector signed short *pCr = reinterpret_cast<vector signed short *>(pU);
// V plane
vector signed short *pCb = reinterpret_cast<vector signed short *>(pV);
vector signed short uvSub = static_cast<vector signed short>( 128, 128, 128, 128,
128, 128, 128, 128 );
vector unsigned short yShift = static_cast<vector unsigned short>( 7, 7, 7, 7, 7, 7, 7, 7 );
vector unsigned short uvShift = static_cast<vector unsigned short>( 8, 8, 8, 8, 8, 8, 8, 8 );
vector signed short tempY1, tempY2, tempY3, tempY4,
tempUV1, tempUV2, tempUV3, tempUV4, tempUV5, tempUV6;
vector unsigned char uvPerm = static_cast<vector unsigned char>( 16, 0, 17, 4, 18, 8, 19, 12, // u0..u3
20, 2, 21, 6, 22, 10, 23, 14 ); // v0..v3
vector unsigned char uPerm = static_cast<vector unsigned char>( 0, 1, 2, 3, 4, 5, 6, 7,
16,17,18,19,20,21,22,23);
vector unsigned char vPerm = static_cast<vector unsigned char>( 8, 9, 10,11,12,13,14,15,
24,25,26,27,28,29,30,31);
vector unsigned char yPerm = static_cast<vector unsigned char>( 16, 1, 17, 3, 18, 5, 19, 7, // y0..y3
20, 9, 21, 11, 23, 13, 25, 15);// y4..y7
vector unsigned char zeroVec = static_cast<vector unsigned char>(0);
int row=ysize>>1;
int cols=xsize>>4;
#if 0
# ifndef PPC970
UInt32 prefetchSize = GetPrefetchConstant( 16, 1, 256 );
vec_dst( pu, prefetchSize, 0 );
vec_dst( pv, prefetchSize, 0 );
vec_dst( py1, prefetchSize, 0 );
vec_dst( py2, prefetchSize, 0 );
# endif
#endif
while(row--){
int col=cols;
while(col--){
#if 0
# ifndef PPC970
vec_dst( );
# endif
#endif
tempUV1 = static_cast<vector signed short>(vec_perm( *pixels1, zeroVec, uvPerm));
tempY1 = static_cast<vector signed short>(vec_perm( *pixels1, zeroVec, yPerm));
tempY2 = static_cast<vector signed short>(vec_perm( *pixels2, zeroVec, yPerm));
pixels1++;pixels2++;
tempUV2 = static_cast<vector signed short>(vec_perm( *pixels1, zeroVec, uvPerm));
tempY3 = static_cast<vector signed short>(vec_perm( *pixels1, zeroVec, yPerm));
tempY4 = static_cast<vector signed short>(vec_perm( *pixels2, zeroVec, yPerm));
pixels1++;pixels2++;
tempUV3 = vec_sub( tempUV1, uvSub );
tempUV4 = vec_sub( tempUV2, uvSub );
tempUV5 = vec_sl( tempUV3, uvShift );
tempUV6 = vec_sl( tempUV4, uvShift );
*pCb = vec_perm( tempUV5, tempUV6, uPerm );
*pCr = vec_perm( tempUV5, tempUV6, vPerm );
pCr++; pCb++;
*py1++ = vec_sl( tempY1, yShift);
*py2++ = vec_sl( tempY2, yShift);
*py1++ = vec_sl( tempY3, yShift);
*py2++ = vec_sl( tempY4, yShift);
}
py1+=(xsize>>3); py2+=(xsize>>3);
pixels1+=(xsize*2)>>4; pixels2+=(xsize*2)>>4;
}
}
#ifdef NO_VECTORINT_TO_VECTORUNSIGNEDINT
# warning disabling AltiVec for older gcc: please fix me
#else
void YUV422_to_BGRA_altivec(const unsigned char *yuvdata,
size_t pixelnum, unsigned char *output)
{
const vector unsigned char *UYVY_ptr=reinterpret_cast<const vector unsigned char *>(yuvdata);
vector unsigned char *BGRA_ptr=reinterpret_cast<vector unsigned char *>(output);
vector unsigned int vShift;
vector signed short tempU, tempV, tempY, tempUV, out1, out2, out3, out4;
vector signed short v16, v128, a255, szero, one;
vector unsigned char zero;
vector signed short t0, t1, t2, tempGB1, tempGB2, tempRA1, tempRA2;
vector signed short vU_G, vV_G, vU_B, vU_R, y0, hiImage, loImage;
vector unsigned int uv_rEven, uv_rOdd, uv_rHi, uv_rLo,
uv_gUEven, uv_gVEven, uv_gUOdd, uv_gVOdd, uv_gHi, uv_gLo,
uv_bEven, uv_bOdd;
vector signed int tempUhi, tempUlo, tempVhi, tempVlo;
vector signed int yEven, yOdd;
vector unsigned int t0Even, t0Odd, t1Even, t1Odd, t2Even, t2Odd;
/* Load the equation constants. */
vector signed short vConst =
static_cast<vector signed short>(298, 519, 409, 16, 128, 255, -100, -210 );
vector unsigned char vPerm1 =
static_cast<vector unsigned char>( 0, 1, 16, 17, 8, 9, 24, 25,
2, 3, 18, 19, 10, 11, 26, 27 );
vector unsigned char vPerm2 =
static_cast<vector unsigned char>( 4, 5, 20, 21, 12, 13, 28, 29,
6, 7, 22, 23, 14, 15, 30, 31 );
vector unsigned char vPermY =
static_cast<vector unsigned char>( 2, 3, 6, 7, 10, 11, 14, 15,
18, 19, 22, 23, 26, 27, 30, 31 );
vector unsigned char vPermU =
static_cast<vector unsigned char>( 0, 1, 16, 17, 4, 5, 20, 21,
8, 9, 24, 25, 12, 13, 28, 29 );
vector unsigned char vPermV =
static_cast<vector unsigned char>( 2, 3, 18, 19, 6, 7, 22, 23,
10, 11, 26, 27, 14, 15, 30, 31 );
vector unsigned char vOutPerm1 =
static_cast<vector unsigned char>( 0, 1, 2, 3, 16, 17, 18, 19,
4, 5, 6, 7, 20, 21, 22, 23 );
vector unsigned char vOutPerm2 =
static_cast<vector unsigned char>( 8, 9, 10, 11, 24, 25, 26, 27,
12, 13, 14, 15, 28, 29, 30, 31 );
vector unsigned char uvPerm =
static_cast<vector unsigned char>( 0, 1, 4, 5, 8, 9, 12, 13,
16, 17, 20, 21, 24, 25, 28, 29 );
zero = vec_splat_u8(0);
szero = vec_splat_s16(0);
one = vec_splat_s16(1);
vShift = vec_splat_u32(8);
a255 = vec_splat( vConst, 5 ); // alpha channel = 255
vU_G = vec_splat( vConst, 6 ); // -100
vV_G = vec_splat( vConst, 7 ); // -210
vU_B = vec_splat( vConst, 1 ); // 519
vU_R = vec_splat( vConst, 2 ); // 409
y0 = vec_splat( vConst, 0 ); // 298
v16 = vec_splat( vConst, 3 ); // 16
v128 = vec_splat( vConst, 4 ); // 128
for ( unsigned int i = 0; i < (pixelnum/sizeof(vector unsigned char)); i++ ) {
// Load UYUV input vector
const vector unsigned char *vec1 = UYVY_ptr++;
//expand the UInt8's to short's
hiImage = static_cast<vector signed short>(vec_mergeh( zero, *vec1 ));
loImage = static_cast<vector signed short>(vec_mergel( zero, *vec1 ));
tempUV = static_cast<vector signed short>(vec_perm( hiImage, loImage, uvPerm ));
tempY = static_cast<vector signed short>(vec_perm( hiImage, loImage, vPermY ));
// subtract UV_OFFSET from UV's (should this be saturated?)
tempUV = static_cast<vector signed short>(vec_sub( tempUV, v128 ));
// subtract Y-OFFSET from Y's (should this be saturated?)
tempY = static_cast<vector signed short>(vec_sub( tempY, v16 ));
// expand to UUUU UUUU and VVVV VVVV
tempU = vec_perm(tempUV, tempUV, vPermU);
tempV = vec_perm(tempUV, tempUV, vPermV);
//below:
//
//error: cannot convert `vector int' to `vector unsigned int' in assignment
tempUhi = vec_mule( tempU, one );
// unsigned int = vec_mule( signed short, signed short )
// should be
// signed int = vec_mule( signed short, signed short )
tempUlo = vec_mulo( tempU, one );
tempVhi = vec_mule( tempV, one );
tempVlo = vec_mulo( tempV, one );
// uv_r = YUV2RGB_12*u + YUV2RGB_13*v
// uv_r = (-1)*u + 409*v (or "409*V - U")
uv_rEven = vec_mule( tempV, vU_R );
uv_rOdd = vec_mulo( tempV, vU_R );
uv_rHi = vec_sub( uv_rEven, tempUhi );
uv_rLo = vec_sub( uv_rOdd, tempUlo );
// uv_g = YUV2RGB_22*u + YUV2RGB_23*v
// uv_g = -100*u + (-210)*v
// multiply U by -100
uv_gUEven = vec_mule( tempU, vU_G );
uv_gUOdd = vec_mulo( tempU, vU_G );
// multiply V by -210
uv_gVEven = vec_mule( tempV, vV_G );
uv_gVOdd = vec_mulo( tempV, vV_G );
// add U & V products
uv_gHi = vec_add( uv_gUEven, uv_gVEven );
uv_gLo = vec_add( uv_gUOdd, uv_gVOdd );
// uv_b = YUV2RGB_32*u + YUV2RGB_33*v
// uv_b = 519*u + 0*v
uv_bEven = vec_mule( tempU, vU_B );
uv_bOdd = vec_mulo( tempU, vU_B );
// y = YUV2RGB_11 * tempY
// y = 298* (tempY - 16)
yEven = vec_mule( tempY, y0 );
yOdd = vec_mulo( tempY, y0 );
// add while int's
t0Even = vec_add( yEven, uv_bEven );
t0Odd = vec_add( yOdd, uv_bOdd );
t1Even = vec_add( yEven, uv_gHi );
t1Odd = vec_add( yOdd, uv_gLo );
t2Even = vec_add( yEven, uv_rHi );
t2Odd = vec_add( yOdd, uv_rLo );
// shift while int's
t0Even = vec_sra( t0Even, vShift );
t0Odd = vec_sra( t0Odd, vShift );
t1Even = vec_sra( t1Even, vShift );
t1Odd = vec_sra( t1Odd, vShift );
t2Even = vec_sra( t2Even, vShift );
t2Odd = vec_sra( t2Odd, vShift );
// pack down to shorts
t0 = vec_packs( t0Even, t0Odd );
t1 = vec_packs( t1Even, t1Odd );
t2 = vec_packs( t2Even, t2Odd );
// Permute to GBGBGBGB GBGBGBGB + re-interleave even & odd
tempGB1 = vec_perm( t1, t0, vPerm1 );
tempGB2 = vec_perm( t1, t0, vPerm2 );
// Permute to ARARARAR ARARARAR + re-interleave even & odd
tempRA1 = vec_perm( a255, t2, vPerm1 );
tempRA2 = vec_perm( a255, t2, vPerm2 );
// Permute to ARGB's
out1 = vec_perm( tempRA1, tempGB1, vOutPerm1 );
out2 = vec_perm( tempRA1, tempGB1, vOutPerm2 );
out3 = vec_perm( tempRA2, tempGB2, vOutPerm1 );
out4 = vec_perm( tempRA2, tempGB2, vOutPerm2 );
// pack down to char's
*BGRA_ptr = vec_packsu( out1, out2 );
BGRA_ptr++;
*BGRA_ptr = vec_packsu( out3, out4 );
BGRA_ptr++;
}
}
#endif /* NO_VECTORINT_TO_VECTORUNSIGNEDINT */
#endif /* __VEC__ */

View file

@ -0,0 +1,423 @@
#ifdef __SSE2__
/////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file for SSE2-optimized color-conversion routines
//
// Copyright (c) 2006-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
/* darned: it seems like i just cannot get SIMD-code right!
* to my eye, there appear to me WAY too much shuffle's down there
* if somebody would want to have a look i'd be grateful
*/
#if defined _MSC_VER
/* data conversion with possible loss of data */
# pragma warning( disable : 4309 )
#endif
#include "PixConvert.h"
#include "Gem/Image.h"
#define RGB2YUV_14 0
#define RGB2YUV_24 0
#define RGB2YUV_34 0
/* for post() */
#include "m_pd.h"
/* just some debugging stuff ... */
#define PRINT_MASK "%03d "
static void print_char(__m128i m){
_mm_pause();
unsigned char*s=(unsigned char*)&m;
int i=0;
for(i=0; i<(sizeof(__m128i)/sizeof(unsigned char)); i++){
startpost(PRINT_MASK, *s);s++;
}
endpost();
}
static void print_short(__m128i m){
_mm_pause();
signed short*s=(signed short*)&m;
int i=0;
for(i=0; i<(sizeof(__m128i)/sizeof(signed short)); i++){
startpost(PRINT_MASK, *s);s++;
}
endpost();
}
static void print_int(__m128i m){
_mm_pause();
signed int*s=(signed int*)&m;
int i=0;
for(i=0; i<(sizeof(__m128i)/sizeof(signed int)); i++){
startpost(PRINT_MASK, *s);s++;
}
endpost();
}
/* convert RGBA to YUV422 */
void RGBA_to_UYVY_SSE2(const unsigned char *rgbadata,
size_t size,
unsigned char *yuvdata)
{
const __m128i *rgba_p = (const __m128i*)rgbadata; /* 4 RGBA pixels */
__m128i *yuv_p = (__m128i*)yuvdata; /* 4*2 YUV pixels */
const __m128i zero = _mm_setzero_si128();
const __m128i RG2Y=_mm_set_epi16(RGB2YUV_12, RGB2YUV_11, RGB2YUV_12, RGB2YUV_11,
RGB2YUV_12, RGB2YUV_11, RGB2YUV_12, RGB2YUV_11);
const __m128i BA2Y=_mm_set_epi16(RGB2YUV_14, RGB2YUV_13, RGB2YUV_14, RGB2YUV_13,
RGB2YUV_14, RGB2YUV_13, RGB2YUV_14, RGB2YUV_13);
const __m128i RG2U=_mm_set_epi16(RGB2YUV_22, RGB2YUV_21, RGB2YUV_22, RGB2YUV_21,
RGB2YUV_22, RGB2YUV_21, RGB2YUV_22, RGB2YUV_21);
const __m128i BA2U=_mm_set_epi16(RGB2YUV_24, RGB2YUV_23, RGB2YUV_24, RGB2YUV_23,
RGB2YUV_24, RGB2YUV_23, RGB2YUV_24, RGB2YUV_23);
const __m128i RG2V=_mm_set_epi16(RGB2YUV_32, RGB2YUV_31, RGB2YUV_32, RGB2YUV_31,
RGB2YUV_32, RGB2YUV_31, RGB2YUV_32, RGB2YUV_31);
const __m128i BA2V=_mm_set_epi16(RGB2YUV_34, RGB2YUV_33, RGB2YUV_34, RGB2YUV_33,
RGB2YUV_34, RGB2YUV_33, RGB2YUV_34, RGB2YUV_33);
const __m128i OFFSET=_mm_set_epi16(Y_OFFSET, UV_OFFSET,
Y_OFFSET, UV_OFFSET,
Y_OFFSET, UV_OFFSET,
Y_OFFSET, UV_OFFSET);
/* nomenclatura:
* lower-case letters denote 8bit values (like "r" is red, 8bit)
* upper-case letters denote 16bit (or 32bit) values (like "G" is green, 16bit)
*
*/
__m128i rgba0, rgba1, RGBA0, RGBA1;
__m128i RGRG, BABA, RGRG0, BABA0, RGRG1, BABA1;
__m128i RGRG_BABA0, RGRG_BABA1;
__m128i Y0, Y1, U, V, UY, VY, UV, YY;
const int shuffle = _MM_SHUFFLE(3, 1, 2, 0);
int i=size>>3; /* we do 2*128bit per cycle: this is 2*4*32bit == 8 pixels */
while(i-->0){
rgba0=*rgba_p++; /* r0 g0 b0 a0 r1 g1 ... b3 a3 */
rgba1=*rgba_p++; /* r4 g4 b4 a4 r5 g5 ... b7 a7 */
/* 1st 4 pixels */
RGBA0 = _mm_unpacklo_epi8(rgba0, zero); /* R0 G0 B0 A0 ... B1 A1 */
RGBA1 = _mm_unpackhi_epi8(rgba0, zero); /* R2 G2 B2 A2 ... B3 A3 */
RGRG_BABA0 = _mm_unpacklo_epi32(RGBA0, RGBA1); /* R0 G0 R2 G2 B0 A0 B2 A2 */
RGRG_BABA1 = _mm_unpackhi_epi32(RGBA0, RGBA1); /* R1 G1 R3 G3 B1 A1 B3 A3 */
RGRG0 = _mm_unpacklo_epi64(RGRG_BABA0, RGRG_BABA1); /* R0 G0 R2 G2 R1 G1 R3 G3 */
BABA0 = _mm_unpackhi_epi64(RGRG_BABA0, RGRG_BABA1); /* B0 A0 B2 A2 B1 A1 B3 A3 */
// get Y for the 1st 4 pixels (thats 32bit)
// Y_RG32 = _mm_madd_epi16(RGRG0, RG2Y); /* R0*a+G0*b R2*a+G2*b R1*a+G1*b R3*a+G3*b */
// Y_BA32 = _mm_madd_epi16(BABA0, BA2Y); /* B0*c+A0*d B2*c+A2*d B1*c+A1*d B3*c+A3*d */
Y0 = _mm_add_epi32(_mm_madd_epi16(RGRG0, RG2Y), _mm_madd_epi16(BABA0, BA2Y));
Y0 = _mm_shuffle_epi32(Y0, shuffle);
//startpost("Y0: "); print_int(Y0); /* Y0, Y1, Y2, Y3 */
/* 2nd 4 pixels */
RGBA0 = _mm_unpacklo_epi8(rgba1, zero); /* R4 G4 B4 A4 R5 G5 B5 A5 */
RGBA1 = _mm_unpackhi_epi8(rgba1, zero); /* R6 G6 B6 A6 R7 G7 B7 A7 */
RGRG_BABA0 = _mm_unpacklo_epi32(RGBA0, RGBA1); /* R4 G4 R6 G6 B4 A4 B6 A6 */
RGRG_BABA1 = _mm_unpackhi_epi32(RGBA0, RGBA1); /* R5 G5 R7 G7 B5 A5 B7 A7 */
RGRG1 = _mm_unpacklo_epi64(RGRG_BABA0, RGRG_BABA1); /* R4 G4 R6 G6 R5 G5 R7 G7 */
BABA1 = _mm_unpackhi_epi64(RGRG_BABA0, RGRG_BABA1); /* B4 A4 B6 A6 B5 A5 B7 A7 */
// get Y for the 2nd 4 pixels (thats 32bit)
// Y_RG32 = _mm_madd_epi16(RGRG1, RG2Y); /* R4*a+G4*b R6*a+G6*b R5*a+G5*b R7*a+G7*b */
// Y_BA32 = _mm_madd_epi16(BABA1, BA2Y); /* B4*c+A4*d B6*c+A6*d B5*c+A5*d B7*c+A7*d */
Y1 = _mm_add_epi32(_mm_madd_epi16(RGRG1, RG2Y), _mm_madd_epi16(BABA1, BA2Y));
Y1 = _mm_shuffle_epi32(Y1, shuffle);
//startpost("Y1: "); print_int(Y1);
// now get UV
/* (R01 G01 R23 G23 R45 G45 R67 G67) / 2 */
RGRG = _mm_avg_epu16(_mm_unpackhi_epi64(RGRG0, RGRG1), _mm_unpacklo_epi64(RGRG0, RGRG1));
/* (B01 A01 B23 A23 B45 A45 B67 A67) / 2 */
BABA = _mm_avg_epu16(_mm_unpackhi_epi64(BABA0, BABA1), _mm_unpacklo_epi64(BABA0, BABA1));
// get 4 U for 8 pixels (32bit each)
//U_RG32 = _mm_madd_epi16(RGRG, RG2U); /* R4*a+G4*b R6*a+G6*b R5*a+G5*b R7*a+G7*b */
//U_BA32 = _mm_madd_epi16(BABA, AB2U); /* B4*c+A4*d B6*c+A6*d B5*c+A5*d B7*c+A7*d */
U = _mm_add_epi32 (_mm_madd_epi16(RGRG, RG2U), _mm_madd_epi16(BABA, BA2U));
// get 4 V for 8 pixels (32bit each)
//V_RG32 = _mm_madd_epi16(RGRG, RG2V); /* R4*a+G4*b R6*a+G6*b R5*a+G5*b R7*a+G7*b */
//V_BA32 = _mm_madd_epi16(BABA, AB2V); /* B4*c+A4*d B6*c+A6*d B5*c+A5*d B7*c+A7*d */
V = _mm_add_epi32 (_mm_madd_epi16(RGRG, RG2V), _mm_madd_epi16(BABA, BA2V));
// 32 instructions so far
// so now we have (all values in 32bit)
/*
* U U U U
* Y1 Y1 Y1 Y1
* V V V V
* Y2 Y2 Y2 Y2
*/
// we still need to right-shift everything by 8
// and press it into 8bit values, so we have one vector with UYVYUYVYUYVYUYVY
// (or just take the 3rd 8bit-tuple)
Y0 = _mm_srai_epi32(Y0, 8);
U = _mm_srai_epi32(U , 8);
Y1 = _mm_srai_epi32(Y1, 8);
V = _mm_srai_epi32(V , 8);
UV = _mm_packs_epi32(U, V);
YY = _mm_packs_epi32(Y0, Y1);
UV = _mm_shuffle_epi32(UV, shuffle);
UV = _mm_shufflehi_epi16(UV, shuffle);
UV = _mm_shufflelo_epi16(UV, shuffle);
UY = _mm_unpacklo_epi16(UV, YY);
VY = _mm_unpackhi_epi16(UV, YY);
UY = _mm_adds_epi16(UY, OFFSET);
VY = _mm_adds_epi16(VY, OFFSET);
_mm_stream_si128(yuv_p++, _mm_packus_epi16(UY, VY));
// 32+15 instructions
}
}
/* convert RGBA to YUV422 */
void UYVY_to_RGBA_SSE2(const unsigned char *yuvdata,
size_t size,
unsigned char *rgbadata)
{
__m128i *rgba_p = (__m128i*)rgbadata; /* 4 RGBA pixels */
const __m128i *yuv_p = (const __m128i*)yuvdata; /* 4*2 YUV pixels */
const __m128i Y2RGB = _mm_set_epi16(YUV2RGB_11,0,YUV2RGB_11,0,YUV2RGB_11,0,YUV2RGB_11,0);
const __m128i UV2R = _mm_set_epi16(YUV2RGB_13, YUV2RGB_12, YUV2RGB_13, YUV2RGB_12,
YUV2RGB_13, YUV2RGB_12, YUV2RGB_13, YUV2RGB_12);
const __m128i UV2G = _mm_set_epi16(YUV2RGB_23, YUV2RGB_22, YUV2RGB_23, YUV2RGB_22,
YUV2RGB_23, YUV2RGB_22, YUV2RGB_23, YUV2RGB_22);
const __m128i UV2B = _mm_set_epi16(YUV2RGB_33, YUV2RGB_32, YUV2RGB_33, YUV2RGB_32,
YUV2RGB_33, YUV2RGB_32, YUV2RGB_33, YUV2RGB_32);
const __m128i offset= _mm_set_epi16(Y_OFFSET, UV_OFFSET, Y_OFFSET, UV_OFFSET,
Y_OFFSET, UV_OFFSET, Y_OFFSET, UV_OFFSET);
const __m128i A32 = _mm_set_epi32(255, 255, 255, 255);
/* nomenclatura:
* lower-case letters denote 8bit values (like "r" is red, 8bit)
* upper-case letters denote 16bit (or 32bit) values (like "G" is green, 16bit)
*/
__m128i uyvy, UYVY0, UYVY1;
__m128i UV, YZ, Y, Z;
__m128i UV_R, UV_G, UV_B;
__m128i R, G, B, A;
__m128i RB0, RB1, GA0, GA1;
const int shuffle = _MM_SHUFFLE(3, 1, 2, 0);
int i=size>>3; /* we do 2*128bit per cycle: this is 2*4*32bit == 8 pixels */
while(i-->0){
uyvy=*yuv_p++; /* u0 y0 v0 z0 u1 y1 v1 z1 u2 y2 v2 z2 u3 y3 v3 z3 */
UYVY0 = _mm_unpacklo_epi8(uyvy, _mm_setzero_si128()); /* U0 Y0 V0 Z0 U1 Y1 V1 Z1 */
UYVY1 = _mm_unpackhi_epi8(uyvy, _mm_setzero_si128()); /* U2 Y2 V2 Z2 U3 Y3 V3 Z3 */
UYVY0 = _mm_sub_epi16(UYVY0, offset);
UYVY1 = _mm_sub_epi16(UYVY1, offset);
UYVY0 = _mm_shufflelo_epi16(UYVY0, shuffle);
UYVY0 = _mm_shufflehi_epi16(UYVY0, shuffle);
UYVY0 = _mm_shuffle_epi32 (UYVY0, shuffle); /* U0 V0 U1 V1 Y0 Z0 Y1 Z1 */
UYVY1 = _mm_shufflelo_epi16(UYVY1, shuffle);
UYVY1 = _mm_shufflehi_epi16(UYVY1, shuffle);
UYVY1 = _mm_shuffle_epi32 (UYVY1, shuffle); /* U2 V2 U3 V3 Y2 Z2 Y3 Z3 */
UV = _mm_unpacklo_epi32(UYVY0, UYVY1); /* U0 V0 U2 V2 U1 V1 U3 V3 */
YZ = _mm_unpackhi_epi32(UYVY0, UYVY1); /* Y0 Z0 Y2 Z2 Y1 Z1 Y3 Z3 */
Z = _mm_madd_epi16(YZ, Y2RGB); /* Z0' Z2' Z1' Z3' */
Y = _mm_madd_epi16(YZ, _mm_srli_si128(Y2RGB, 2)); /* Y0' Y2' Y1' Y3' */
UV_R = _mm_madd_epi16(UV, UV2R);
UV_G = _mm_madd_epi16(UV, UV2G);
UV_B = _mm_madd_epi16(UV, UV2B);
R = _mm_srai_epi32(_mm_add_epi32(Y, UV_R), 8);
G = _mm_srai_epi32(_mm_add_epi32(Y, UV_G), 8);
B = _mm_srai_epi32(_mm_add_epi32(Y, UV_B), 8);
RB0 = _mm_packs_epi32(R, B);
GA0 = _mm_packs_epi32(G, A32);
R = _mm_srai_epi32(_mm_add_epi32(Z, UV_R), 8);
G = _mm_srai_epi32(_mm_add_epi32(Z, UV_G), 8);
B = _mm_srai_epi32(_mm_add_epi32(Z, UV_B), 8);
RB1 = _mm_packs_epi32(R, B);
GA1 = _mm_packs_epi32(G, A32);
R = _mm_unpacklo_epi16(RB0, RB1); /* R0 R1 R4 R5 R2 R3 R6 R7 */
R = _mm_shuffle_epi32 (R, shuffle);/* R0 R1 R2 R3 R4 R5 R6 R7 */
B = _mm_unpackhi_epi16(RB0, RB1);
B = _mm_shuffle_epi32 (B, shuffle);
G = _mm_unpacklo_epi16(GA0, GA1);
G = _mm_shuffle_epi32 (G, shuffle);
A = _mm_unpackhi_epi16(GA0, GA1); /* no need to shuffle, since A0=A1=...=255 */
RB0= _mm_unpacklo_epi16(R, B);
RB1= _mm_unpackhi_epi16(R, B);
RB0= _mm_packus_epi16 (RB0, RB1); /* R0 B0 R1 B1 R2 B2 R3 B3 R4 B4 R5 B5 R6 B6 R7 B7 */
GA0= _mm_unpacklo_epi16(G, A);
GA1= _mm_unpackhi_epi16(G, A);
GA0= _mm_packus_epi16 (GA0, GA1);
_mm_stream_si128(rgba_p++, _mm_unpacklo_epi8(RB0, GA0));
_mm_stream_si128(rgba_p++, _mm_unpackhi_epi8(RB0, GA0));
}
}
/* convert RGB24 to YUV422 */
void UYVY_to_RGB_SSE2(const unsigned char *yuvdata,
size_t size,
unsigned char *rgbdata)
{
const __m128i *yuv_p = (const __m128i*)yuvdata; /* 4*2 YUV pixels */
const __m128i Y2RGB = _mm_set_epi16(YUV2RGB_11,0,YUV2RGB_11,0,YUV2RGB_11,0,YUV2RGB_11,0);
const __m128i UV2R = _mm_set_epi16(YUV2RGB_13, YUV2RGB_12, YUV2RGB_13, YUV2RGB_12,
YUV2RGB_13, YUV2RGB_12, YUV2RGB_13, YUV2RGB_12);
const __m128i UV2G = _mm_set_epi16(YUV2RGB_23, YUV2RGB_22, YUV2RGB_23, YUV2RGB_22,
YUV2RGB_23, YUV2RGB_22, YUV2RGB_23, YUV2RGB_22);
const __m128i UV2B = _mm_set_epi16(YUV2RGB_33, YUV2RGB_32, YUV2RGB_33, YUV2RGB_32,
YUV2RGB_33, YUV2RGB_32, YUV2RGB_33, YUV2RGB_32);
const __m128i offset= _mm_set_epi16(Y_OFFSET, UV_OFFSET, Y_OFFSET, UV_OFFSET,
Y_OFFSET, UV_OFFSET, Y_OFFSET, UV_OFFSET);
const __m128i A32 = _mm_set_epi32(255, 255, 255, 255);
const __m128i all = _mm_set_epi8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
/* nomenclatura:
* lower-case letters denote 8bit values (like "r" is red, 8bit)
* upper-case letters denote 16bit (or 32bit) values (like "G" is green, 16bit)
*/
__m128i uyvy, UYVY0, UYVY1;
__m128i UV, YZ, Y, Z;
__m128i UV_R, UV_G, UV_B;
__m128i R, G, B, A;
__m128i RB0, RB1, GA0, GA1;
vector_128 v0, v1;
const int shuffle = _MM_SHUFFLE(3, 1, 2, 0);
int i=size>>3; /* we do 2*128bit per cycle: this is 2*4*32bit == 8 pixels */
while(i-->0){
uyvy=*yuv_p++; /* u0 y0 v0 z0 u1 y1 v1 z1 u2 y2 v2 z2 u3 y3 v3 z3 */
UYVY0 = _mm_unpacklo_epi8(uyvy, _mm_setzero_si128()); /* U0 Y0 V0 Z0 U1 Y1 V1 Z1 */
UYVY1 = _mm_unpackhi_epi8(uyvy, _mm_setzero_si128()); /* U2 Y2 V2 Z2 U3 Y3 V3 Z3 */
UYVY0 = _mm_sub_epi16(UYVY0, offset);
UYVY1 = _mm_sub_epi16(UYVY1, offset);
UYVY0 = _mm_shufflelo_epi16(UYVY0, shuffle);
UYVY0 = _mm_shufflehi_epi16(UYVY0, shuffle);
UYVY0 = _mm_shuffle_epi32 (UYVY0, shuffle); /* U0 V0 U1 V1 Y0 Z0 Y1 Z1 */
UYVY1 = _mm_shufflelo_epi16(UYVY1, shuffle);
UYVY1 = _mm_shufflehi_epi16(UYVY1, shuffle);
UYVY1 = _mm_shuffle_epi32 (UYVY1, shuffle); /* U2 V2 U3 V3 Y2 Z2 Y3 Z3 */
UV = _mm_unpacklo_epi32(UYVY0, UYVY1); /* U0 V0 U2 V2 U1 V1 U3 V3 */
YZ = _mm_unpackhi_epi32(UYVY0, UYVY1); /* Y0 Z0 Y2 Z2 Y1 Z1 Y3 Z3 */
Z = _mm_madd_epi16(YZ, Y2RGB); /* Z0' Z2' Z1' Z3' */
Y = _mm_madd_epi16(YZ, _mm_srli_si128(Y2RGB, 2)); /* Y0' Y2' Y1' Y3' */
UV_R = _mm_madd_epi16(UV, UV2R);
UV_G = _mm_madd_epi16(UV, UV2G);
UV_B = _mm_madd_epi16(UV, UV2B);
R = _mm_srai_epi32(_mm_add_epi32(Y, UV_R), 8);
G = _mm_srai_epi32(_mm_add_epi32(Y, UV_G), 8);
B = _mm_srai_epi32(_mm_add_epi32(Y, UV_B), 8);
RB0 = _mm_packs_epi32(R, G);
GA0 = _mm_packs_epi32(B, _mm_setzero_si128());
R = _mm_srai_epi32(_mm_add_epi32(Z, UV_R), 8);
G = _mm_srai_epi32(_mm_add_epi32(Z, UV_G), 8);
B = _mm_srai_epi32(_mm_add_epi32(Z, UV_B), 8);
RB1 = _mm_packs_epi32(R, G);
GA1 = _mm_packs_epi32(B, _mm_setzero_si128());
v0.v= _mm_packus_epi16 (RB0, GA0);
v1.v= _mm_packus_epi16 (RB1, GA1);
rgbdata[chRed ]=v0.c[ 0];
rgbdata[chGreen ]=v0.c[ 4];
rgbdata[chBlue ]=v0.c[ 8];
rgbdata+=3;
rgbdata[chRed ]=v1.c[ 0];
rgbdata[chGreen ]=v1.c[ 4];
rgbdata[chBlue ]=v1.c[ 8];
rgbdata+=3;
rgbdata[chRed ]=v0.c[ 2];
rgbdata[chGreen ]=v0.c[ 6];
rgbdata[chBlue ]=v0.c[10];
rgbdata+=3;
rgbdata[chRed ]=v1.c[ 2];
rgbdata[chGreen ]=v1.c[ 6];
rgbdata[chBlue ]=v1.c[10];
rgbdata+=3;
rgbdata[chRed ]=v0.c[ 1];
rgbdata[chGreen ]=v0.c[ 5];
rgbdata[chBlue ]=v0.c[ 9];
rgbdata+=3;
rgbdata[chRed ]=v1.c[ 1];
rgbdata[chGreen ]=v1.c[ 5];
rgbdata[chBlue ]=v1.c[ 9];
rgbdata+=3;
rgbdata[chRed ]=v0.c[ 3];
rgbdata[chGreen ]=v0.c[ 7];
rgbdata[chBlue ]=v0.c[11];
rgbdata+=3;
rgbdata[chRed ]=v1.c[ 3];
rgbdata[chGreen ]=v1.c[ 7];
rgbdata[chBlue ]=v1.c[11];
rgbdata+=3;
}
}
#endif

154
Gem/src/Gem/Properties.cpp Normal file
View file

@ -0,0 +1,154 @@
#include <map>
#include "Properties.h"
#include <iostream>
namespace gem {
class Properties::PIMPL {
public:
std::map<std::string, any> valuemap;
std::map<std::string, enum Properties::PropertyType> typemap;
PIMPL(void) {;}
};
Properties::Properties() :
pimpl(new PIMPL())
{ }
Properties::Properties(const gem::Properties&org) :
pimpl(new PIMPL())
{
assign(org);
}
Properties::~Properties() {
delete pimpl;
}
#if 0
any&Properties::operator[](const std::string&key) {
return pimpl->valuemap[key];
}
#endif
any Properties::get(const std::string&key) const {
return pimpl->valuemap[key];
}
void Properties::set(const std::string&key, gem::any value) {
const std::type_info*typ=&value.get_type();
PropertyType pt = UNKNOWN;
double d=0;
std::string s;
#define ISTYPE(type) (*typ == typeid(type))
if (value.empty()) {
pt = NONE;
} else if(ISTYPE(char)) {
pt = DOUBLE;
d=any_cast<char>(value);
} else if(ISTYPE(unsigned char)) {
pt = DOUBLE;
d=any_cast<unsigned char>(value);
} else if(ISTYPE(short)) {
pt = DOUBLE;
d=any_cast<short>(value);
} else if(ISTYPE(unsigned short)) {
pt = DOUBLE;
d=any_cast<unsigned short>(value);
} else if(ISTYPE(int)) {
pt = DOUBLE;
d=any_cast<int>(value);
} else if(ISTYPE(unsigned int)) {
pt = DOUBLE;
d=any_cast<unsigned int>(value);
#if 0
/* "long"s cannot be stored in "double"s without loosing precision... */
} else if(ISTYPE(long)) {
pt = DOUBLE;
d=any_cast<long>(value);
} else if(ISTYPE(unsigned long)) {
pt = DOUBLE;
d=any_cast<unsigned long>(value);
#endif
} else if(ISTYPE(float)) {
pt = DOUBLE;
d=any_cast<float>(value);
} else if(ISTYPE(double)) {
pt = DOUBLE;
d=any_cast<double>(value);
} else if(ISTYPE(char*)) {
pt = STRING;
s=std::string(any_cast<char*>(value));
#ifdef SETSYMBOL
/* only use this, if compiled with Pd... */
} else if(ISTYPE(t_symbol*)) {
pt = STRING;
s=std::string((any_cast<t_symbol*>(value))->s_name);
#endif
} else if(ISTYPE(std::string)) {
pt = STRING;
s=any_cast<std::string>(value);
}
switch(pt) {
case NONE:
pimpl->valuemap[key]=value;
pimpl->typemap[key]=NONE;
break;
case DOUBLE:
pimpl->valuemap[key]=d;
pimpl->typemap[key]=DOUBLE;
break;
case STRING:
pimpl->valuemap[key]=s;
pimpl->typemap[key]=STRING;
break;
default:
pimpl->valuemap[key]=value;
pimpl->typemap[key]=UNKNOWN;
break;
}
}
std::vector<std::string>Properties::keys() const {
std::vector<std::string>result;
std::map<std::string,gem::any>::iterator it;
for(it = pimpl->valuemap.begin(); it != pimpl->valuemap.end(); ++it)
result.push_back(it->first);
return result;
}
enum Properties::PropertyType Properties::type(std::string key) const {
std::map<std::string, enum Properties::PropertyType>::iterator it=pimpl->typemap.find(key);
if(pimpl->typemap.end() == it)
return UNSET;
return it->second;
}
void Properties::erase(std::string key) {
pimpl->typemap.erase(key);
pimpl->valuemap.erase(key);
}
void Properties::clear() {
pimpl->typemap.clear();
pimpl->valuemap.clear();
}
Properties& Properties::assign(const Properties&org) {
pimpl->valuemap=org.pimpl->valuemap;
pimpl->typemap =org.pimpl->typemap;
return(*this);
}
};

110
Gem/src/Gem/Properties.h Normal file
View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2010-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
*
* map that stores "any"thing
*
* USAGE:
*
* Properties am; // create a new Properties
* am["a"] = 42; // assign value "42" to key "a"
* int i=0;
* try { i=any_cast<int>am["a"]; } catch(bad_any_cast ex) { ; } // retrieve value from key "a"; might throw a bad_any_cast exception
* am.get("a", i); // retrieve value at key "a"; if there was an error (e.g. typeof(i) does not match, then i is left untouched and "false" is returned
*
* NOTE:
* this simplilstic approach has some problems with type-conversion
* e.g. this will fail:
* am["a"]=12.0f; any_cast<int>am["a"];
*/
#ifndef GEM_PROPERTIES_H
#define GEM_PROPERTIES_H
#include "Gem/ExportDef.h"
#include "Utils/any.h"
#include <vector>
#include <string>
namespace gem
{
class GEM_EXTERN Properties {
private:
class PIMPL;
PIMPL*pimpl;
public:
enum PropertyType {
UNSET=-1, /* not set, in-existent */
NONE, /* "bang" */
DOUBLE, /* double */
STRING, /* std::string */
UNKNOWN /* all the rest */
};
Properties(void);
Properties(const gem::Properties&); /* copy constructor */
virtual ~Properties(void);
#if 0
/* array/hashmap like access:
* e.g.: prop["width"]=640;
*/
virtual gem::any&operator[](const std::string&key);
#endif
/* get the value of a property
* e.g.: double w=any_cast<double>prop.at("width")
*/
virtual gem::any get(const std::string&key) const;
/* check whether the given key exists
* if the key was in the property-map, return the type of the property
* if no key of the given value exists, return <code>PropertyType::UNSET</code>
*/
virtual enum PropertyType type(const std::string) const;
/* set a property
* e.g.: double w=640; prop.set("width", w);
*/
virtual void set(const std::string&key, gem::any value);
/* get a property
* e.g.: double w=320; prop.get("width", w);
* NOTE: if no property of the given name exists or the existing property
* is of a different (incompatible) type, "value" will not be changed
*/
template<class Class>
bool get(const std::string&key, Class&value) const {
try {
value=gem::any_cast<Class>(get(key));
} catch (gem::bad_any_cast e) {
return false;
}
return true;
};
/* get all keys
*/
virtual std::vector<std::string>keys(void) const;
/*
* delete a given key from the Properties
*/
virtual void erase(const std::string);
/*
* delete all keys from the Properties
*/
virtual void clear(void);
/*
* assign Properties from another set
*/
virtual gem::Properties& assign(const gem::Properties&);
gem::Properties& operator= (const gem::Properties&org) { return assign(org); }
};
};
#endif /* GEM_PROPERTIES_H */

29
Gem/src/Gem/RTE.h Normal file
View file

@ -0,0 +1,29 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
include Realtime-Environments headers
Copyright (c) 2010-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_RTE_H_
#define _INCLUDE__GEM_GEM_RTE_H_
#if defined _MSC_VER
/* data conversion with possible loss of data */
# pragma warning( push )
# pragma warning( disable : 4091 )
#endif
#include "m_pd.h"
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#endif /* _INCLUDE__GEM_GEM_RTE_H_ */

48
Gem/src/Gem/Rectangle.cpp Normal file
View file

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 2012 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "Rectangle.h"
/////////////////////////////////////////////////////////
//
// Rectangle
//
namespace gem {
Rectangle :: Rectangle(void) :
x1(0.f), y1(0.f), x2(1.f), y2(1.f)
{
}
#define CLAMP01(x) if(x<0.)x=0.;else if(x>1.)x=1.;
Rectangle Rectangle :: createNormalized(float x1, float y1, float x2, float y2) {
Rectangle result;
float minX=(x1<x2)?x1:x2;
float maxX=(x1>x2)?x1:x2;
float minY=(y1<y2)?y1:y2;
float maxY=(y1>y2)?y1:y2;
CLAMP01(minX);
CLAMP01(maxX);
CLAMP01(minY);
CLAMP01(maxY);
result.x1=minX;
result.x2=maxX;
result.y1=minY;
result.y2=maxY;
return result;
}
};

44
Gem/src/Gem/Rectangle.h Normal file
View file

@ -0,0 +1,44 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
an abstract rectangle representation
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_RECTANGLE_H_
#define _INCLUDE__GEM_GEM_RECTANGLE_H_
#include "Gem/ExportDef.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
Rectangle
abstract rectangle class (to be used e.g. as ROI)
DESCRIPTION
-----------------------------------------------------------------*/
namespace gem {
class GEM_EXTERN Rectangle
{
public:
//////////
// Constructor
Rectangle(void);
float x1, y1, x2, y2;
static Rectangle createNormalized(float x1, float y1, float x2, float y2);
};
};
#endif // for header file

315
Gem/src/Gem/Settings.cpp Normal file
View file

@ -0,0 +1,315 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
// Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
// load settings from a file (or get them via env-variables)
//
/////////////////////////////////////////////////////////
#include "Gem/GemConfig.h"
#include "Gem/RTE.h"
#include "Settings.h"
#include "Files.h"
#include <map>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define GEM_SETTINGS_FILE "gem.conf"
static const char*s_configdir[] = {
#ifdef __linux__
"/etc/pd",
"~/.config/pure-data",
#elif defined __APPLE__
"/Library/Pd",
"~/Library/Pd",
#elif defined _WIN32
"%CommonProgramFiles%\\Pd",
"%AppData%\\Pd",
#endif
0 /* $(pwd)/gem.conf */
};
/* this is ripped from m_imp.h */
struct _gemclass
{
t_symbol *c_name; /* name (mostly for error reporting) */
t_symbol *c_helpname; /* name of help file */
t_symbol *c_externdir; /* directory extern was loaded from */
/* ... */ /* the real t_class continues here... */
};
# define t_gemclass struct _gemclass
namespace {
struct PIMPL {
// dictionary for setting values
std::map <std::string, t_atom> data;
virtual t_atom*get(std::string name) {
std::map<std::string, t_atom>::iterator it=data.find(name);
if(it==data.end())
return NULL;
return &it->second;
}
virtual void set(std::string name, t_atom*value) {
// LATER: we should expand envvariables
if(value) {
data[name]= *value;
} else {
data.erase(name);
}
}
void set(std::string name, int i) {
t_atom a;
SETFLOAT(&a, i);
set(name, &a);
}
void set(std::string name, float f) {
t_atom a;
SETFLOAT(&a, f);
set(name, &a);
}
void set(std::string name, double f) {
t_atom a;
SETFLOAT(&a, f);
set(name, &a);
}
void set(std::string name, std::string s) {
t_atom a;
SETSYMBOL(&a, gensym(s.c_str()));
set(name, &a);
}
// std::string expandEnv(std::string , bool bashfilename=false);
bool open(const char*filename, const char*dirname=NULL) {
t_binbuf*bb=binbuf_new();
int r=0;
if(NULL==filename)
return false;
if(dirname) {
r=binbuf_read(bb, (char*)filename, const_cast<char*>(gem::files::expandEnv(dirname, true).c_str()), 1);
if(0==r)verbose(1, "found Gem-settings '%s' in '%s'", filename, dirname);
} else {
r=binbuf_read_via_path(bb, (char*)filename, (char*)".", 1);
if(0==r)verbose(1, "found Gem-settings '%s'", filename);
}
if(r){
binbuf_free(bb);
return false;
}
int ac=binbuf_getnatom(bb);
t_atom*av=binbuf_getvec(bb);
std::string s;
t_atom*a=NULL;
int state=0; /* 0=(next is ID); 1=(next is value); 2=(next is ignored) */
while(ac--) {
if (av->a_type == A_SEMI) {
// done
if(!s.empty()) {
set(s, a);
}
state=0;
s.clear();
} else {
switch (state) {
case 0:
s=atom_getsymbol(av)->s_name;
state=1;
break;
case 1:
a=av;
state=2;
break;
default:
break;
}
}
av++;
}
binbuf_free(bb);
return true;
}
void print(void) {
std::map <std::string , t_atom>::iterator it;
for(it = data.begin();
it != data.end();
it++)
{
if(!it->first.empty()) {
startpost("key ['%s']: '", it->first.c_str());
postatom(1, &it->second);
post("'");
}
}
}
PIMPL(void)
{
int i=0;
#ifdef GEM_DEFAULT_FONT
set("font.face", GEM_DEFAULT_FONT);
#endif
setEnv("settings.file", "GEM_SETTINGS");
t_atom*a=NULL;
a=get("settings.file");
if(a) {
std::string s=atom_getsymbol(a)->s_name;
open(gem::files::expandEnv(s.c_str(), true).c_str(), ".");
} else {
while(s_configdir[i]) {
open(GEM_SETTINGS_FILE, s_configdir[i]);
i++;
}
open(GEM_SETTINGS_FILE, ".");
}
/* legacy settings via environmental variables */
setEnv("texture.rectangle", "GEM_RECTANGLE_TEXTURE");
setEnv("singlecontext", "GEM_SINGLE_CONTEXT"); // hmm, what's a better new name for this?
setEnv("font.face", "GEM_DEFAULT_FONT");
t_gemclass *c = (t_gemclass*)class_new(gensym("Gem"), 0, 0, 0, 0, A_NULL);
set("gem.path", c->c_externdir->s_name);
// print();
}
~PIMPL(void) {
}
void setEnv(std::string key, const std::string env) {
if(env.empty())return;
if(key.empty())return;
char*result=getenv(env.c_str());
if(NULL==result) {
return;
}
t_atom a;
errno=0;
/* try integer */
long l=strtol(result, NULL, 0);
if(0==errno) {
SETFLOAT(&a, l);
set(key, &a);
}
/* try float */
double d=strtod(result, NULL);
if(0==errno) {
SETFLOAT(&a, d);
set(key, &a);
}
/* try symbol */
SETSYMBOL(&a, gensym(result));
set(key, &a);
// we ignore lists and other complex things for now
}
};
static PIMPL*settings=NULL;
};
/* gem::Settings: the public API */
/* public static functions */
void gem::Settings::init() {
if(settings)return;
settings=new PIMPL();
}
void gem::Settings::print() {
if(!settings)return;
settings->print();
}
void gem::Settings::save() {
if(!settings)return;
post("gem::Settings: save not yet implemented!");
}
t_atom*gem::Settings::get(const std::string s) {
if(NULL==settings) init();
return settings->get(s.c_str());
}
void gem::Settings::set(const std::string s, t_atom*v) {
settings->set(s.c_str(), v);
}
void gem::Settings::get(const std::string key, int&value) {
t_atom*a=get(key);
if(a && A_FLOAT==a->a_type) {
value=atom_getint(a);
}
}
void gem::Settings::get(const std::string key, float&value) {
t_atom*a=get(key);
if(a && A_FLOAT==a->a_type) {
value=atom_getfloat(a);
}
}
void gem::Settings::get(const std::string key, double&value) {
t_atom*a=get(key);
if(a && A_FLOAT==a->a_type) {
value=atom_getfloat(a);
}
}
void gem::Settings::get(const std::string key, std::string&value) {
t_atom*a=get(key);
if(a) {
value=atom_getsymbol(a)->s_name;
}
}
std::vector<std::string>gem::Settings::keys(void) {
std::vector<std::string>result;
if(NULL==settings) init();
if(NULL!=settings) {
std::map<std::string, t_atom>::iterator it=settings->data.begin();
while(settings->data.end() != it) {
result.push_back(it->first);
}
}
return result;
}

35
Gem/src/Gem/Settings.h Normal file
View file

@ -0,0 +1,35 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
- Runtime Configuration of Gem
Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_SETTINGS_H_
#define _INCLUDE__GEM_GEM_SETTINGS_H_
#include <string>
#include <vector>
typedef struct _atom t_atom;
namespace gem { namespace Settings {
void init(void);
void print(void);
void save(void);
t_atom*get(const std::string key);
void set(const std::string key, t_atom*value=NULL);
void get(const std::string key, int&value);
void get(const std::string key, float&value);
void get(const std::string key, double&value);
void get(const std::string key, std::string&value);
std::vector<std::string> keys();
}; };
#endif

245
Gem/src/Gem/Setup.cpp Normal file
View file

@ -0,0 +1,245 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-2000 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
/* OLDNAMES.lib pd.lib opengl32.lib glu32.lib freetype235mt.lib FTGL_static.lib libcpmt.lib msvcrt.lib msvcprt.lib ws2_32.lib pthreadVC.lib
* pd.lib freetype235mt.lib FTGL_static.lib opengl32.lib glu32.lib ws2_32.lib pthreadVC.lib (?)
* OLDNAMES.lib: _close, _open, _strdup
* pd.lib
* opengl32.lib
* glu32.lib: gluFunctions (sphere, cylinder, lookat,...)
* freetype235mt.lib FTGL_static.lib
* libcpmt.lib: std::cerr,...
* msvcrt.lib: typeinfo,...
* ws2_32.lib
* pthreadVC.lib
*/
#include "Gem/GemConfig.h"
/* -------------------------- setup function ------------------------------ */
#include "Gem/Manager.h"
#include "Gem/Version.h"
#include "Gem/Files.h"
#include <stdio.h>
#ifdef _WIN32
# include <io.h>
# include <windows.h>
# define snprintf _snprintf
#else
# include <unistd.h>
#endif
#include <fcntl.h>
#ifndef _MSC_VER
# define _open open
# define _close close
#endif
static const char GEM_MAINTAINER[] = "IOhannes m zmoelnig";
static const char *GEM_AUTHORS[] = {
"Chris Clepper",
"Cyrille Henry",
"IOhannes m zmoelnig"
};
static const char GEM_OTHERAUTHORS[] =
"Guenter Geiger, Daniel Heckenberg, James Tittle, Hans-Christoph Steiner, et al.";
extern "C" {
#if defined HAVE_S_STUFF_H
# include "s_stuff.h"
# ifndef _WIN32
/* MSVC/MinGW cannot really handle these exported symbols */
# define GEM_ADDPATH
# endif
#endif /* HAVE_S_STUFF_H */
/* this is ripped from m_imp.h */
struct _gemclass
{
t_symbol *c_name; /* name (mostly for error reporting) */
t_symbol *c_helpname; /* name of help file */
t_symbol *c_externdir; /* directory extern was loaded from */
/* ... */ /* the real t_class continues here... */
};
# define t_gemclass struct _gemclass
} // for extern "C"
namespace Gem {
static bool checkVersion(const char*dirname, const char*filename, int flags) {
t_binbuf*bb=binbuf_new();
if(binbuf_read(bb, const_cast<char*>(filename), const_cast<char*>(dirname), flags)) {
/* couldn't find the file */
return true;
}
int argc = binbuf_getnatom(bb);
t_atom*argv=binbuf_getvec(bb);
const t_symbol* _X=gensym("#X");
const t_symbol* _text=gensym("text");
const t_symbol* _version=gensym("VERSION");
std::string gotversion;
int i;
/* search for: "#X text <num> <num> VERSION <string>;" */
// #X text 10 30 VERSION 0.93 \;
for(i=0; i<argc; i++) {
if(A_SYMBOL!=argv[i].a_type)continue;
if((_X==atom_getsymbol(argv+i)) && (i+6<argc)) {
t_atom*ap=argv+i+1;
if(_text ==atom_getsymbol(ap+0) &&
_version==atom_getsymbol(ap+3) &&
A_FLOAT == ap[1].a_type &&
A_FLOAT == ap[2].a_type
) {
char buf[MAXPDSTRING];
if(A_SYMBOL==ap[4].a_type) {
gotversion=std::string(atom_getsymbol(ap+4)->s_name);
} else {
snprintf(buf, MAXPDSTRING-1, "%g", atom_getfloat(ap+4));
gotversion=std::string(buf);
}
break;
}
}
}
binbuf_free(bb);
int major, minor;
sscanf(gotversion.c_str(), "%d.%d", &major, &minor);
bool result=gem::Version::versionCheck(major,minor);
if(!result) {
error("Gem binary/abstractions version mismatch!");
verbose(0, "Gem binary is %d.%d, but Gem abstractions are %s", GEM_VERSION_MAJOR, GEM_VERSION_MINOR, gotversion.c_str());
verbose(0, "This usually means that you have a path to another version of Gem stored in your startup preferences");
verbose(0, "Consider removing the wrong path!");
}
return result;
}
static void addownpath(const char*filename) {
char buf[MAXPDSTRING];
char*bufptr=NULL;
int fd=-1;
int flags=O_RDONLY;
#ifdef _WIN32
flags |= _O_BINARY;
#endif
/* check whether we can find the abstractions (because they are already in Pd's path) */
if ((fd=canvas_open(NULL, filename, "", buf, &bufptr, MAXPDSTRING, 1))>=0){
gem::files::close(fd);
checkVersion(buf, filename, flags);
return;
}
char*mypath=0;
t_gemclass *c = (t_gemclass*)class_new(gensym("Gem"), 0, 0, 0, 0, A_NULL);
mypath=c->c_externdir->s_name;
/* check whether we can find the abstractions in Gem's own path */
snprintf(buf, MAXPDSTRING-1, "%s/%s", mypath, filename);
buf[MAXPDSTRING-1]=0;
if ((fd=_open(buf, flags))>=0){
_close(fd);
} else {
// can't find this abstraction...giving up
verbose(0, "please add path to '%s' to your search-path!", filename);
return;
}
#ifdef GEM_ADDPATH
verbose(1, "eventually adding Gem path '%s' to search-paths", mypath);
sys_searchpath = namelist_append(sys_searchpath, mypath, 0);
#else
verbose(0, "please manually add '%s' to your search-path!", mypath);
#endif
checkVersion(mypath, filename, flags);
}
}; // namespace
namespace gem {
namespace plugins { void init(void); };
namespace Settings{ void init(void); };
};
namespace Gem {
void setup()
{
// startup GEM
post("GEM: Graphics Environment for Multimedia");
verbose(-1, "GEM: ver: %s", GemVersion::versionString());
verbose(-1, "GEM: compiled: " __DATE__);
verbose(-1, "GEM: maintained by %s", GEM_MAINTAINER);
verbose(-1, "GEM: Authors :\tMark Danks (original version)");
for(unsigned int i=0; i<sizeof(GEM_AUTHORS)/sizeof(*GEM_AUTHORS); i++) {
verbose(-1, "GEM:\t\t%s", GEM_AUTHORS[i]);
}
verbose(-1, "GEM: with help by %s", GEM_OTHERAUTHORS);
verbose(-1, "GEM: found a bug? miss a feature? please report it:");
verbose(-1, "GEM: \thomepage http://gem.iem.at/");
verbose(-1, "GEM: \tbug-tracker http://sourceforge.net/projects/pd-gem/");
verbose(-1, "GEM: \tmailing-list http://lists.puredata.info/listinfo/gem-dev/");
gem::Settings::init();
addownpath("Gem-meta.pd");
GemMan::initGem();
// initialize some plugins
gem::plugins::init();
}
}; // namespace
extern "C" {
GEM_EXTERN void Gem_setup()
{
Gem::setup();
}
GEM_EXTERN void gem_setup()
{
Gem_setup();
}
GEM_EXTERN void GEM_setup()
{
Gem_setup();
}
} // for extern"C"

336
Gem/src/Gem/State.cpp Normal file
View file

@ -0,0 +1,336 @@
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
//
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "State.h"
#include "Gem/GemGL.h"
/* for GemMan::StackIDs */
#include "Gem/Manager.h"
#include "Gem/GLStack.h"
#include <map>
#include <memory>
#include <iostream>
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#if defined _MSC_VER
/* disable deprecated warnings */
# pragma warning( disable : 4996 )
#endif
#define CATCH_ANY(y) catch(gem::bad_any_cast&x) { ::verbose(3, "%s:%d [%s] %d:: %s", __FILE__, __LINE__, __FUNCTION__, (y), x.what().c_str()); }
using namespace gem;
class GemStateData {
friend class GemState;
public:
GemStateData(void) : stacks(new GLStack()){}
~GemStateData(void) {
if (NULL==stacks.get()){
post("ouch");
// const GLStack*dummy=new GLStack();
//stacks=dummy;
stacks.reset();
post("yaroooo!");
}
}
GemStateData& copyFrom(const GemStateData*org) {
data=org->data;
stacks->reset();
return (*this);
}
protected:
// dictionary for setting values
std::map <GemState::key_t, any> data;
std::auto_ptr<GLStack>stacks;
static std::map <std::string, int> keys;
};
std::map <std::string, int> GemStateData::keys;
/////////////////////////////////////////////////////////
//
// GemState
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
GemState :: GemState()
: dirty(0), inDisplayList(0), lighting(0), smooth(0), texture(0),
image(0), texCoords(0), numTexCoords(0), multiTexUnits(0),
tickTime(50.f), drawType(0),
VertexDirty(0),
VertexArray(0), VertexArraySize(0), VertexArrayStride(0),
ColorArray(0), HaveColorArray(0),
NormalArray(0), HaveNormalArray(0),
TexCoordArray(0), HaveTexCoordArray(0),
data(new GemStateData())
{
// std::cout << "GemState" << std::endl;
stackDepth[GemMan::STACKMODELVIEW]=
stackDepth[GemMan::STACKCOLOR]=
stackDepth[GemMan::STACKTEXTURE]=
stackDepth[GemMan::STACKPROJECTION]=
1; // 1 is the current matrix
set(_DIRTY, (dirty=false));
set(_GL_DISPLAYLIST, (inDisplayList=false));
set(_GL_LIGHTING, (lighting=false));
set(_GL_SMOOTH, (smooth=false));
set(_GL_TEX_TYPE, (texture=0));
// set(_PIX, (image=0));
set(_GL_TEX_NUMCOORDS, (numTexCoords=0)); // LATER get rid of this
set(_GL_TEX_COORDS, (texCoords=0)); // LATER make this a std::vector
set(_GL_TEX_UNITS, (multiTexUnits=0));
set(_TIMING_TICK, (tickTime=50.f));
set(_GL_DRAWTYPE, (drawType=0));
set(_GL_STACKS, data->stacks.get());
/*
set("vertex.array.vertex", 0);
set("vertex.array.color", 0);
set("vertex.array.normal", 0);
set("vertex.array.texcoord", 0);
*/
}
GemState& GemState::operator=(const GemState&org) {
dirty=org.dirty;
inDisplayList=org.inDisplayList;
lighting=org.lighting;
smooth=org.smooth;
texture=org.texture;
image=org.image;
texCoords=org.texCoords;
numTexCoords=org.numTexCoords;
multiTexUnits=org.multiTexUnits;
tickTime=org.tickTime;
drawType=org.drawType;
VertexArray=org.VertexArray;
VertexArraySize=org.VertexArraySize;
VertexArrayStride=org.VertexArrayStride;
ColorArray=org.ColorArray;
HaveColorArray=org.HaveColorArray;
NormalArray=org.NormalArray;
HaveNormalArray=org.HaveNormalArray;
TexCoordArray=org.TexCoordArray;
HaveTexCoordArray=org.HaveTexCoordArray;
data->copyFrom(org.data);
return (*this);
}
GemState::GemState(const GemState&org) :
dirty(org.dirty),
inDisplayList(org.inDisplayList),
lighting(org.lighting),
smooth(org.smooth),
texture(org.texture),
image(org.image),
texCoords(org.texCoords),
numTexCoords(org.numTexCoords),
multiTexUnits(org.multiTexUnits),
tickTime(org.tickTime),
drawType(org.drawType),
VertexArray(org.VertexArray),
VertexArraySize(org.VertexArraySize),
VertexArrayStride(org.VertexArrayStride),
ColorArray(org.ColorArray),
HaveColorArray(org.HaveColorArray),
NormalArray(org.NormalArray),
HaveNormalArray(org.HaveNormalArray),
TexCoordArray(org.TexCoordArray),
HaveTexCoordArray(org.HaveTexCoordArray),
data(NULL)
{
data->copyFrom(org.data);
}
void GemState :: reset() {
VertexArray = 0;
VertexArraySize = 0;
ColorArray = 0;
NormalArray = 0;
TexCoordArray = 0;
HaveColorArray = 0;
HaveNormalArray = 0;
HaveTexCoordArray = 0;
drawType = 0;
if(GemMan::windowExists()) {
GLStack *stacks;
get(GemState::_GL_STACKS, stacks);
stacks->reset();
}
set(GemState::_PIX, (image=0));
set(GemState::_GL_TEX_NUMCOORDS, (numTexCoords=0));
}
GemState :: ~GemState() {
if(data)delete data;data=NULL;
}
// --------------------------------------------------------------
/* legacy functions */
float GemState::texCoordX(int num) const {
if (texture && numTexCoords > num)
return texCoords[num].s;
else return 0.;
}
float GemState::texCoordY(int num) const {
if (texture && numTexCoords > num)
return texCoords[num].t;
else return 0.;
}
/* real properties */
/* get a named property */
bool GemState::get(const GemState::key_t key, any&value) {
std::map<GemState::key_t,any>::iterator it =
data->data.find(key);
if(it==data->data.end()) {
if(key==_PIX) { value=image; return true; }
if(key==_GL_TEX_NUMCOORDS) { value=numTexCoords; return true; }
return false; // FIXXME
if(key==_DIRTY) { value=dirty; return true; }
if(key==_GL_DISPLAYLIST) { value=inDisplayList; return true; }
if(key==_GL_LIGHTING) { value=lighting; return true; }
if(key==_GL_SMOOTH) { value=smooth; return true; }
if(key==_GL_TEX_TYPE) { value=texture; return true; }
if(key==_GL_TEX_COORDS) { if(!texCoords)return false; value=texCoords; return true; }
if(key==_GL_TEX_UNITS) { value=multiTexUnits; return true; }
if(key==_TIMING_TICK) { value=tickTime; return true; }
if(key==_GL_DRAWTYPE) { value=drawType; return true; }
#if 0
//if(key==GemState::_GL_STACKS) { value=stackDepth[4]; return true; }
if(key=="vertex.dirty") { value=VertexDirty; return true; }
if(key=="*VertexArray") { value=*VertexArray; return true; }
if(key=="VertexArraySize") { value=VertexArraySize; return true; }
if(key=="VertexArrayStride") { value=VertexArrayStride; return true; }
if(key=="*ColorArray") { value=*ColorArray; return true; }
if(key=="HaveColorArray") { value=HaveColorArray; return true; }
if(key=="*NormalArray") { value=*NormalArray; return true; }
if(key=="HaveNormalArray") { value=HaveNormalArray; return true; }
if(key=="*TexCoordArray") { value=*TexCoordArray; return true; }
if(key=="HaveTexCoordArray") { value=HaveTexCoordArray; return true; }
#endif
return false;
}
value=it->second;
return true;
}
/* set a named property */
bool GemState::set(const GemState::key_t key, any value) {
if(value.empty()) {
data->data.erase(key);
return false;
}
/* wrapper for DEPRECATED access to member variables */
if(1) {
try {
switch(key) {
case(_DIRTY): dirty=gem::any_cast<bool>(value); break;
case(_PIX): image=gem::any_cast<pixBlock*>(value); break;
case(_GL_TEX_NUMCOORDS): numTexCoords=gem::any_cast<int>(value); break;
case(_GL_TEX_COORDS): texCoords=gem::any_cast<TexCoord*>(value); break;
case(_GL_LIGHTING): lighting=gem::any_cast<bool>(value); break;
case(_GL_SMOOTH): smooth=gem::any_cast<bool>(value); break;
case(_GL_TEX_TYPE): texture=gem::any_cast<int>(value); break;
case(_GL_TEX_UNITS): multiTexUnits=gem::any_cast<int>(value); break;
case(_TIMING_TICK): tickTime=gem::any_cast<float>(value); break;
case(_GL_DRAWTYPE): drawType=gem::any_cast<GLenum>(value); break;
case(_GL_DISPLAYLIST): inDisplayList=gem::any_cast<bool>(value); break;
default: break;
}
} CATCH_ANY(key);
}
data->data[key]=value;
return true;
}
/* remove a named property */
bool GemState::remove(const GemState::key_t key) {
return (0!=data->data.erase(key));
}
const GemState::key_t GemState::getKey(const std::string&s) {
if(GemStateData::keys.empty()) {
GemStateData::keys["dirty"]=_DIRTY;
GemStateData::keys["timing.tick"]=_TIMING_TICK;
GemStateData::keys["pix"]=_PIX;
GemStateData::keys["gl.stacks"]=_GL_STACKS;
GemStateData::keys["gl.displaylist"]=_GL_DISPLAYLIST;
GemStateData::keys["gl.lighting"]=_GL_LIGHTING;
GemStateData::keys["gl.smooth"]=_GL_SMOOTH;
GemStateData::keys["gl.drawtype"]=_GL_DRAWTYPE;
GemStateData::keys["gl.tex.type"]=_GL_TEX_TYPE;
GemStateData::keys["gl.tex.coords"]=_GL_TEX_COORDS;
GemStateData::keys["gl.tex.numcoords"]=_GL_TEX_NUMCOORDS;
GemStateData::keys["gl.tex.units"]=_GL_TEX_UNITS;
GemStateData::keys["gl.tex.orientation"]=_GL_TEX_ORIENTATION;
GemStateData::keys["gl.tex.basecoord"]=_GL_TEX_BASECOORD;
}
key_t result=_ILLEGAL;
std::map<std::string, int>::iterator it = GemStateData::keys.find(s);
if(it == GemStateData::keys.end()) {
result=(key_t)it->second;
} else {
result=(key_t)GemStateData::keys.size();
GemStateData::keys[s]=result;
}
return result;
}

231
Gem/src/Gem/State.h Normal file
View file

@ -0,0 +1,231 @@
/*-----------------------------------------------------------------
LOG
GEM - Graphics Environment for Multimedia
The state to pass among GEM objects
Copyright (c) 1997-2000 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
-----------------------------------------------------------------*/
#ifndef _INCLUDE__GEM_GEM_STATE_H_
#define _INCLUDE__GEM_GEM_STATE_H_
#include "Gem/ExportDef.h"
#include "Gem/GemGL.h"
#include "Gem/RTE.h"
#include "Utils/any.h"
struct pixBlock;
class TexCoord;
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
TexCoord
DESCRIPTION
-----------------------------------------------------------------*/
class GEM_EXTERN TexCoord
{
public:
TexCoord() : s(0.f), t(0.f) { }
TexCoord(float s_, float t_) : s(s_), t(t_) { }
float s;
float t;
};
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
GemState
The state to pass among GEM objects
DESCRIPTION
-----------------------------------------------------------------*/
class GemStateData;
class GEM_EXTERN GemState
{
public:
typedef enum {
_ILLEGAL=-1,
_DIRTY, /* "dirty" */
_TIMING_TICK, /* "timing.tick" */
_PIX, /* "pix" */
_GL_STACKS, /* "stacks" */
_GL_DISPLAYLIST, /* */
_GL_LIGHTING, /* */
_GL_SMOOTH, /* */
_GL_DRAWTYPE, /* */
_GL_TEX_TYPE, /* "tex.type" */
_GL_TEX_COORDS, /* "tex.coords" */
_GL_TEX_NUMCOORDS, /* "tex.numcoords" */
_GL_TEX_UNITS, /* "tex.units" <int> # of texUnits */
_GL_TEX_ORIENTATION, /* "tex.orientation" <bool> false=bottomleft; true=topleft */
_GL_TEX_BASECOORD, /* "tex.basecoords" <TexCoord> width/height of texture */
_LAST
} key_t;
//////////
// Has something changed since the last time?
// deprecated: use property 'dirty' instead
GEM_DEPRECATED bool dirty;
//////////
// Are we in a display list creation?
// deprecated: use property 'gl.displaylist' instead
GEM_DEPRECATED bool inDisplayList;
//////////
// Lighting on?
// deprecated: use property 'gl.lighting' instead
GEM_DEPRECATED bool lighting;
//////////
// Smooth shading (flat is other type)
// deprecated: use property 'gl.smooth' instead
GEM_DEPRECATED bool smooth;
//////////
// Texture mapping on?
// 0..off
// 1..normalized texture
// 2..rectangle texture
// deprecated: use property 'gl.tex.type' instead
GEM_DEPRECATED int texture;
//////////
// The image to texture map
// deprecated: use property 'pix' instead
GEM_DEPRECATED pixBlock *image;
//////////
// Texture coordinates.
// This can be NULL if there aren't any coordinates
// deprecated: use property 'gl.tex.coords' instead
GEM_DEPRECATED TexCoord *texCoords;
//////////
// The number of TexCoords
// deprecated: use property 'gl.tex.numcoords' instead
GEM_DEPRECATED int numTexCoords;
//////////
// The number of multiTexUnits
// default = 0, max = 7
// deprecated: use property 'gl.tex.units' instead
GEM_DEPRECATED int multiTexUnits;
//////////
// Milliseconds since last frame
// If in Stereoscopic mode, then it is the same number for both left
// and right renderings
// deprecated: use property 'timing.tick' instead
GEM_DEPRECATED float tickTime;
//////////////////
// the default draw-type (might be overridden within a Geo)
// deprecated: use property 'gl.drawtype' instead
GEM_DEPRECATED GLenum drawType;
//////////
// how deep is the current stack /* 4 fields for the 4 stacks */
// deprecated: use property 'gl.stacks' instead
GEM_DEPRECATED int stackDepth[4];
////////////
//vertex-array data
// deprecated: use property 'vertex.dirty' instead
GEM_DEPRECATED int VertexDirty; // the vertex-arrays has changed
// deprecated: use property 'vertex.array.vertex' instead
GEM_DEPRECATED GLfloat *VertexArray;
// deprecated: use property 'vertex.array.vertex' instead
GEM_DEPRECATED int VertexArraySize;
// deprecated: use property 'vertex.array.vertex' instead
GEM_DEPRECATED int VertexArrayStride;
// deprecated: use property 'vertex.array.color' instead
GEM_DEPRECATED GLfloat *ColorArray;
// deprecated: use property 'vertex.array.color' instead
GEM_DEPRECATED bool HaveColorArray;
// deprecated: use property 'vertex.array.normal' instead
GEM_DEPRECATED GLfloat *NormalArray;
// deprecated: use property 'vertex.array.normal' instead
GEM_DEPRECATED bool HaveNormalArray;
// deprecated: use property 'vertex.array.texcoord' instead
GEM_DEPRECATED GLfloat *TexCoordArray;
// deprecated: use property 'vertex.array.texcoord' instead
GEM_DEPRECATED bool HaveTexCoordArray;
//////////
// Constructor
GemState(void);
GemState(const GemState&);
//////////
// Destructor
virtual ~GemState(void);
float texCoordX(int num) const;
float texCoordY(int num) const;
/* reset (parts of?) the GemState: to be called from [gemhead] */
void reset(void);
/* get a named property */
/* if the property exists (as the given type),
* the value of the 2nd argument is set accordingly and <code>true</code> is returned
* if the key does not exist (or the type is wrong) the value is not touched and <code>false</code> is returned instead
*/
virtual bool get(const key_t key, gem::any&value);
template<class T>
bool get(const key_t key, T&value) {
try {
gem::any val;
if(!get(key,val)) {
// key not found
return false;
}
value=gem::any_cast<T>(val);
return true;
} catch (gem::bad_any_cast&x) {
::verbose(3, "%s:%d [%s] %d :: %s", __FILE__, __LINE__, __FUNCTION__, key, x.what().c_str());
// type problem
}
return false;
};
/* set a named property */
virtual bool set(const key_t key, gem::any value);
/* remove a named property */
virtual bool remove(const key_t key);
// Copy assignment
GemState& operator=(const GemState&);
static const key_t getKey(const std::string&);
protected:
GemStateData*data;
};
#endif // for header file

19
Gem/src/Gem/Version.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef GEM_VERSION_H
#define GEM_VERSION_H
#include "Gem/ExportDef.h"
#define GEM_VERSION_MAJOR 0
#define GEM_VERSION_MINOR 93
namespace gem {
class GEM_EXTERN Version {
public:
const static char* versionString(void);
static bool versionCheck(int major, int minor);
}; };
#define GemVersion gem::Version
#endif

View file

@ -0,0 +1,12 @@
/* Gem/configDarwin.h. Generated by configure. */
/* font rendering */
#define HAVE_LIBFTGL 1
/* image loading / saving */
/* #undef HAVE_LIBMAGICKPLUSPLUS */
/* types, structures, compiler characteristics, ... */
#define SIZEOF_VOID_P 4
#define SIZEOF_UNSIGNED_INT 4

View file

@ -0,0 +1,2 @@
/* configLinux.h : dummy file to be included if there is no autoconf-generated config.h file */

9
Gem/src/Gem/configNT.h Normal file
View file

@ -0,0 +1,9 @@
/* configuration for Windows M$VC
*
* this file should get included if _MSC_VER is defined
* for default-defines on _MSC_VER see
* see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_predir_predefined_macros.asp for available macros
*
*
* this file is empty as all the settings are done via property pages
*/

Some files were not shown because too many files have changed in this diff Show more