
#include "main.h"

//${CONFIG_BEGIN}
#define CFG_BINARY_FILES *.bin|*.dat
#define CFG_BRL_DATABUFFER_IMPLEMENTED 1
#define CFG_BRL_FILESTREAM_IMPLEMENTED 1
#define CFG_BRL_GAMETARGET_IMPLEMENTED 1
#define CFG_BRL_STREAM_IMPLEMENTED 1
#define CFG_BRL_THREAD_IMPLEMENTED 1
#define CFG_CD 
#define CFG_CONFIG release
#define CFG_CPP_GC_MODE 1
#define CFG_GLFW_COPY_LIBS openal32;libcurl;libcrypto-1_1-x64;libssl-1_1-x64
#define CFG_GLFW_GCC_LIB_OPTS -lopenal32
#define CFG_GLFW_GCC_MSIZE_WINNT 64
#define CFG_GLFW_SWAP_INTERVAL -1
#define CFG_GLFW_USE_HTTPS 0
#define CFG_GLFW_USE_MINGW 1
#define CFG_GLFW_VERSION 3
#define CFG_GLFW_WINDOW_DECORATED 1
#define CFG_GLFW_WINDOW_FLOATING 0
#define CFG_GLFW_WINDOW_FULLSCREEN 0
#define CFG_GLFW_WINDOW_HEIGHT 475
#define CFG_GLFW_WINDOW_RESIZABLE 0
#define CFG_GLFW_WINDOW_SAMPLES 0
#define CFG_GLFW_WINDOW_TITLE PPSG Tracker v1.302f - by R.Katsenos Silok/sng
#define CFG_GLFW_WINDOW_WIDTH 640
#define CFG_HOST winnt
#define CFG_IMAGE_FILES *.png|*.jpg
#define CFG_LANG cpp
#define CFG_MODPATH 
#define CFG_MOJO_AUTO_SUSPEND_ENABLED 0
#define CFG_MOJO_DRIVER_IMPLEMENTED 1
#define CFG_MOJO_IMAGE_FILTERING_ENABLED 0
#define CFG_MUSIC_FILES *.wav|*.ogg
#define CFG_OPENGL_DEPTH_BUFFER_ENABLED 0
#define CFG_OPENGL_GLES20_ENABLED 0
#define CFG_SAFEMODE 0
#define CFG_SOUND_FILES *.wav|*.ogg
#define CFG_TARGET glfw
#define CFG_TEXT_FILES *.txt|*.xml|*.json
//${CONFIG_END}

//${TRANSCODE_BEGIN}

#include <wctype.h>
#include <locale.h>

// C++ Cerberus runtime.
//
// Placed into the public domain 24/02/2011.
// No warranty implied; use at your own risk.

//***** Cerberus Types *****

typedef wchar_t Char;
template<class T> class Array;
class String;
class Object;

#if CFG_CPP_DOUBLE_PRECISION_FLOATS
typedef double Float;
#define FLOAT(X) X
#else
typedef float Float;
#define FLOAT(X) X##f
#endif

void dbg_error( const char *p );

#if !_MSC_VER
#define sprintf_s sprintf
#define sscanf_s sscanf
#endif

//***** GC Config *****

#if CFG_CPP_GC_DEBUG
#define DEBUG_GC 1
#else
#define DEBUG_GC 0
#endif

// GC mode:
//
// 0 = disabled
// 1 = Incremental GC every OnWhatever
// 2 = Incremental GC every allocation
//
#ifndef CFG_CPP_GC_MODE
#define CFG_CPP_GC_MODE 1
#endif

//How many bytes alloced to trigger GC
//
#ifndef CFG_CPP_GC_TRIGGER
#define CFG_CPP_GC_TRIGGER 8*1024*1024
#endif

//GC_MODE 2 needs to track locals on a stack - this may need to be bumped if your app uses a LOT of locals, eg: is heavily recursive...
//
#ifndef CFG_CPP_GC_MAX_LOCALS
#define CFG_CPP_GC_MAX_LOCALS 8192
#endif

// ***** GC *****

#if _WIN32

int gc_micros(){
	static int f;
	static LARGE_INTEGER pcf;
	if( !f ){
		if( QueryPerformanceFrequency( &pcf ) && pcf.QuadPart>=1000000L ){
			pcf.QuadPart/=1000000L;
			f=1;
		}else{
			f=-1;
		}
	}
	if( f>0 ){
		LARGE_INTEGER pc;
		if( QueryPerformanceCounter( &pc ) ) return pc.QuadPart/pcf.QuadPart;
		f=-1;
	}
	return 0;// timeGetTime()*1000;
}

#elif __APPLE__

#include <mach/mach_time.h>

int gc_micros(){
	static int f;
	static mach_timebase_info_data_t timeInfo;
	if( !f ){
		mach_timebase_info( &timeInfo );
		timeInfo.denom*=1000L;
		f=1;
	}
	return mach_absolute_time()*timeInfo.numer/timeInfo.denom;
}

#else

int gc_micros(){
	return 0;
}

#endif

#define gc_mark_roots gc_mark

void gc_mark_roots();

struct gc_object;

gc_object *gc_object_alloc( int size );
void gc_object_free( gc_object *p );

struct gc_object{
	gc_object *succ;
	gc_object *pred;
	int flags;
	
	virtual ~gc_object(){
	}
	
	virtual void mark(){
	}
	
	void *operator new( size_t size ){
		return gc_object_alloc( size );
	}
	
	void operator delete( void *p ){
		gc_object_free( (gc_object*)p );
	}
};

gc_object gc_free_list;
gc_object gc_marked_list;
gc_object gc_unmarked_list;
gc_object gc_queued_list;	//doesn't really need to be doubly linked...

int gc_free_bytes;
int gc_marked_bytes;
int gc_alloced_bytes;
int gc_max_alloced_bytes;
int gc_new_bytes;
int gc_markbit=1;

gc_object *gc_cache[8];

void gc_collect_all();
void gc_mark_queued( int n );

#define GC_CLEAR_LIST( LIST ) ((LIST).succ=(LIST).pred=&(LIST))

#define GC_LIST_IS_EMPTY( LIST ) ((LIST).succ==&(LIST))

#define GC_REMOVE_NODE( NODE ){\
(NODE)->pred->succ=(NODE)->succ;\
(NODE)->succ->pred=(NODE)->pred;}

#define GC_INSERT_NODE( NODE,SUCC ){\
(NODE)->pred=(SUCC)->pred;\
(NODE)->succ=(SUCC);\
(SUCC)->pred->succ=(NODE);\
(SUCC)->pred=(NODE);}

void gc_init1(){
	GC_CLEAR_LIST( gc_free_list );
	GC_CLEAR_LIST( gc_marked_list );
	GC_CLEAR_LIST( gc_unmarked_list);
	GC_CLEAR_LIST( gc_queued_list );
}

void gc_init2(){
	gc_mark_roots();
}

#if CFG_CPP_GC_MODE==2

int gc_ctor_nest;
gc_object *gc_locals[CFG_CPP_GC_MAX_LOCALS],**gc_locals_sp=gc_locals;

struct gc_ctor{
	gc_ctor(){ ++gc_ctor_nest; }
	~gc_ctor(){ --gc_ctor_nest; }
};

struct gc_enter{
	gc_object **sp;
	gc_enter():sp(gc_locals_sp){
	}
	~gc_enter(){
#if DEBUG_GC
		static int max_locals;
		int n=gc_locals_sp-gc_locals;
		if( n>max_locals ){
			max_locals=n;
			printf( "max_locals=%i\n",n );
		}
#endif		
		gc_locals_sp=sp;
	}
};

#define GC_CTOR gc_ctor _c;
#define GC_ENTER gc_enter _e;

#else

struct gc_ctor{
};
struct gc_enter{
};

#define GC_CTOR
#define GC_ENTER

#endif

//Can be modified off thread!
static volatile int gc_ext_new_bytes;

#if _MSC_VER
#define atomic_add(P,V) InterlockedExchangeAdd((volatile unsigned int*)P,V)			//(*(P)+=(V))
#define atomic_sub(P,V) InterlockedExchangeSubtract((volatile unsigned int*)P,V)	//(*(P)-=(V))
#else
#define atomic_add(P,V) __sync_fetch_and_add(P,V)
#define atomic_sub(P,V) __sync_fetch_and_sub(P,V)
#endif

//Careful! May be called off thread!
//
void gc_ext_malloced( int size ){
	atomic_add( &gc_ext_new_bytes,size );
}

void gc_object_free( gc_object *p ){

	int size=p->flags & ~7;
	gc_free_bytes-=size;
	
	if( size<64 ){
		p->succ=gc_cache[size>>3];
		gc_cache[size>>3]=p;
	}else{
		free( p );
	}
}

void gc_flush_free( int size ){

	int t=gc_free_bytes-size;
	if( t<0 ) t=0;
	
	//ignore bytes freed by released strings
	int new_bytes=gc_new_bytes;
	
	while( gc_free_bytes>t ){
	
		gc_object *p=gc_free_list.succ;

		GC_REMOVE_NODE( p );

#if DEBUG_GC
//		printf( "deleting @%p\n",p );fflush( stdout );
//		p->flags|=4;
//		continue;
#endif
		delete p;
	}
	
	gc_new_bytes=new_bytes;
}

gc_object *gc_object_alloc( int size ){

	size=(size+7)&~7;
	
	gc_new_bytes+=size;
	
#if CFG_CPP_GC_MODE==2

	if( !gc_ctor_nest ){

#if DEBUG_GC
		int ms=gc_micros();
#endif
		if( gc_new_bytes+gc_ext_new_bytes>(CFG_CPP_GC_TRIGGER) ){
			atomic_sub( &gc_ext_new_bytes,gc_ext_new_bytes );
			gc_collect_all();
			gc_new_bytes=0;
		}else{
			gc_mark_queued( (long long)(gc_new_bytes)*(gc_alloced_bytes-gc_new_bytes)/(CFG_CPP_GC_TRIGGER)+gc_new_bytes );
		}

#if DEBUG_GC
		ms=gc_micros()-ms;
		if( ms>=100 ) {printf( "gc time:%i\n",ms );fflush( stdout );}
#endif
	}
	
#endif

	gc_flush_free( size );

	gc_object *p;
	if( size<64 && (p=gc_cache[size>>3]) ){
		gc_cache[size>>3]=p->succ;
	}else{
		p=(gc_object*)malloc( size );
	}
	
	p->flags=size|gc_markbit;
	GC_INSERT_NODE( p,&gc_unmarked_list );

	gc_alloced_bytes+=size;
	if( gc_alloced_bytes>gc_max_alloced_bytes ) gc_max_alloced_bytes=gc_alloced_bytes;
	
#if CFG_CPP_GC_MODE==2
	*gc_locals_sp++=p;
#endif

	return p;
}

#if DEBUG_GC

template<class T> gc_object *to_gc_object( T *t ){
	gc_object *p=dynamic_cast<gc_object*>(t);
	if( p && (p->flags & 4) ){
		printf( "gc error : object already deleted @%p\n",p );fflush( stdout );
		exit(-1);
	}
	return p;
}

#else

#define to_gc_object(t) dynamic_cast<gc_object*>(t)

#endif

template<class T> T *gc_retain( T *t ){
#if CFG_CPP_GC_MODE==2
	*gc_locals_sp++=to_gc_object( t );
#endif
	return t;
}

template<class T> void gc_mark( T *t ){

	gc_object *p=to_gc_object( t );
	
	if( p && (p->flags & 3)==gc_markbit ){
		p->flags^=1;
		GC_REMOVE_NODE( p );
		GC_INSERT_NODE( p,&gc_marked_list );
		gc_marked_bytes+=(p->flags & ~7);
		p->mark();
	}
}

template<class T> void gc_mark_q( T *t ){

	gc_object *p=to_gc_object( t );
	
	if( p && (p->flags & 3)==gc_markbit ){
		p->flags^=1;
		GC_REMOVE_NODE( p );
		GC_INSERT_NODE( p,&gc_queued_list );
	}
}

template<class T,class V> void gc_assign( T *&lhs,V *rhs ){

	gc_object *p=to_gc_object( rhs );
	
	if( p && (p->flags & 3)==gc_markbit ){
		p->flags^=1;
		GC_REMOVE_NODE( p );
		GC_INSERT_NODE( p,&gc_queued_list );
	}
	lhs=rhs;
}

void gc_mark_locals(){

#if CFG_CPP_GC_MODE==2
	for( gc_object **pp=gc_locals;pp!=gc_locals_sp;++pp ){
		gc_object *p=*pp;
		if( p && (p->flags & 3)==gc_markbit ){
			p->flags^=1;
			GC_REMOVE_NODE( p );
			GC_INSERT_NODE( p,&gc_marked_list );
			gc_marked_bytes+=(p->flags & ~7);
			p->mark();
		}
	}
#endif	
}

void gc_mark_queued( int n ){
	while( gc_marked_bytes<n && !GC_LIST_IS_EMPTY( gc_queued_list ) ){
		gc_object *p=gc_queued_list.succ;
		GC_REMOVE_NODE( p );
		GC_INSERT_NODE( p,&gc_marked_list );
		gc_marked_bytes+=(p->flags & ~7);
		p->mark();
	}
}

void gc_validate_list( gc_object &list,const char *msg ){
	gc_object *node=list.succ;
	while( node ){
		if( node==&list ) return;
		if( !node->pred ) break;
		if( node->pred->succ!=node ) break;
		node=node->succ;
	}
	if( msg ){
		puts( msg );fflush( stdout );
	}
	puts( "LIST ERROR!" );
	exit(-1);
}

//returns reclaimed bytes
void gc_sweep(){

	int reclaimed_bytes=gc_alloced_bytes-gc_marked_bytes;
	
	if( reclaimed_bytes ){
	
		//append unmarked list to end of free list
		gc_object *head=gc_unmarked_list.succ;
		gc_object *tail=gc_unmarked_list.pred;
		gc_object *succ=&gc_free_list;
		gc_object *pred=succ->pred;
		
		head->pred=pred;
		tail->succ=succ;
		pred->succ=head;
		succ->pred=tail;
		
		gc_free_bytes+=reclaimed_bytes;
	}

	//move marked to unmarked.
	if( GC_LIST_IS_EMPTY( gc_marked_list ) ){
		GC_CLEAR_LIST( gc_unmarked_list );
	}else{
		gc_unmarked_list.succ=gc_marked_list.succ;
		gc_unmarked_list.pred=gc_marked_list.pred;
		gc_unmarked_list.succ->pred=gc_unmarked_list.pred->succ=&gc_unmarked_list;
		GC_CLEAR_LIST( gc_marked_list );
	}
	
	//adjust sizes
	gc_alloced_bytes=gc_marked_bytes;
	gc_marked_bytes=0;
	gc_markbit^=1;
}

void gc_collect_all(){

//	puts( "Mark locals" );
	gc_mark_locals();

//	puts( "Marked queued" );
	gc_mark_queued( 0x7fffffff );

//	puts( "Sweep" );
	gc_sweep();

//	puts( "Mark roots" );
	gc_mark_roots();

#if DEBUG_GC
	gc_validate_list( gc_marked_list,"Validating gc_marked_list"  );
	gc_validate_list( gc_unmarked_list,"Validating gc_unmarked_list"  );
	gc_validate_list( gc_free_list,"Validating gc_free_list" );
#endif

}

void gc_collect(){
	
#if CFG_CPP_GC_MODE==1

#if DEBUG_GC
	int ms=gc_micros();
#endif

	if( gc_new_bytes+gc_ext_new_bytes>(CFG_CPP_GC_TRIGGER) ){
		atomic_sub( &gc_ext_new_bytes,gc_ext_new_bytes );
		gc_collect_all();
		gc_new_bytes=0;
	}else{
		gc_mark_queued( (long long)(gc_new_bytes)*(gc_alloced_bytes-gc_new_bytes)/(CFG_CPP_GC_TRIGGER)+gc_new_bytes );
	}

#if DEBUG_GC
	ms=gc_micros()-ms;
//	if( ms>=100 ) {printf( "gc time:%i\n",ms );fflush( stdout );}
	if( ms>10 ) {printf( "gc time:%i\n",ms );fflush( stdout );}
#endif

#endif
}

// ***** Array *****

template<class T> T *t_memcpy( T *dst,const T *src,int n ){
	memcpy( dst,src,n*sizeof(T) );
	return dst+n;
}

template<class T> T *t_memset( T *dst,int val,int n ){
	memset( dst,val,n*sizeof(T) );
	return dst+n;
}

template<class T> int t_memcmp( const T *x,const T *y,int n ){
	return memcmp( x,y,n*sizeof(T) );
}

template<class T> int t_strlen( const T *p ){
	const T *q=p++;
	while( *q++ ){}
	return q-p;
}

template<class T> T *t_create( int n,T *p ){
	t_memset( p,0,n );
	return p+n;
}

template<class T> T *t_create( int n,T *p,const T *q ){
	t_memcpy( p,q,n );
	return p+n;
}

template<class T> void t_destroy( int n,T *p ){
}

template<class T> void gc_mark_elements( int n,T *p ){
}

template<class T> void gc_mark_elements( int n,T **p ){
	for( int i=0;i<n;++i ) gc_mark( p[i] );
}

template<class T> class Array{
public:
	Array():rep( &nullRep ){
	}

	//Uses default...
//	Array( const Array<T> &t )...
	
	Array( int length ):rep( Rep::alloc( length ) ){
		t_create( rep->length,rep->data );
	}
	
	Array( const T *p,int length ):rep( Rep::alloc(length) ){
		t_create( rep->length,rep->data,p );
	}
	
	~Array(){
	}

	//Uses default...
//	Array &operator=( const Array &t )...
	
	int Length()const{ 
		return rep->length; 
	}
	
	T &At( int index ){
		if( index<0 || index>=rep->length ) dbg_error( "Array index out of range" );
		return rep->data[index]; 
	}
	
	const T &At( int index )const{
		if( index<0 || index>=rep->length ) dbg_error( "Array index out of range" );
		return rep->data[index]; 
	}
	
	T &operator[]( int index ){
		return rep->data[index]; 
	}

	const T &operator[]( int index )const{
		return rep->data[index]; 
	}
	
	Array Slice( int from,int term )const{
		int len=rep->length;
		if( from<0 ){ 
			from+=len;
			if( from<0 ) from=0;
		}else if( from>len ){
			from=len;
		}
		if( term<0 ){
			term+=len;
		}else if( term>len ){
			term=len;
		}
		if( term<=from ) return Array();
		return Array( rep->data+from,term-from );
	}

	Array Slice( int from )const{
		return Slice( from,rep->length );
	}
	
	Array Resize( int newlen )const{
		if( newlen<=0 ) return Array();
		int n=rep->length;
		if( newlen<n ) n=newlen;
		Rep *p=Rep::alloc( newlen );
		T *q=p->data;
		q=t_create( n,q,rep->data );
		q=t_create( (newlen-n),q );
		return Array( p );
	}
	
private:
	struct Rep : public gc_object{
		int length;
		T data[0];
		
		Rep():length(0){
			flags=3;
		}
		
		Rep( int length ):length(length){
		}
		
		~Rep(){
			t_destroy( length,data );
		}
		
		void mark(){
			gc_mark_elements( length,data );
		}
		
		static Rep *alloc( int length ){
			if( !length ) return &nullRep;
			void *p=gc_object_alloc( sizeof(Rep)+length*sizeof(T) );
			return ::new(p) Rep( length );
		}
		
	};
	Rep *rep;
	
	static Rep nullRep;
	
	template<class C> friend void gc_mark( Array<C> t );
	template<class C> friend void gc_mark_q( Array<C> t );
	template<class C> friend Array<C> gc_retain( Array<C> t );
	template<class C> friend void gc_assign( Array<C> &lhs,Array<C> rhs );
	template<class C> friend void gc_mark_elements( int n,Array<C> *p );
	
	Array( Rep *rep ):rep(rep){
	}
};

template<class T> typename Array<T>::Rep Array<T>::nullRep;

template<class T> Array<T> *t_create( int n,Array<T> *p ){
	for( int i=0;i<n;++i ) *p++=Array<T>();
	return p;
}

template<class T> Array<T> *t_create( int n,Array<T> *p,const Array<T> *q ){
	for( int i=0;i<n;++i ) *p++=*q++;
	return p;
}

template<class T> void gc_mark( Array<T> t ){
	gc_mark( t.rep );
}

template<class T> void gc_mark_q( Array<T> t ){
	gc_mark_q( t.rep );
}

template<class T> Array<T> gc_retain( Array<T> t ){
#if CFG_CPP_GC_MODE==2
	gc_retain( t.rep );
#endif
	return t;
}

template<class T> void gc_assign( Array<T> &lhs,Array<T> rhs ){
	gc_mark( rhs.rep );
	lhs=rhs;
}

template<class T> void gc_mark_elements( int n,Array<T> *p ){
	for( int i=0;i<n;++i ) gc_mark( p[i].rep );
}
		
// ***** String *****

static const char *_str_load_err;

class String{
public:
	String():rep( &nullRep ){
	}
	
	String( const String &t ):rep( t.rep ){
		rep->retain();
	}

	String( int n ){
		char buf[256];
		sprintf_s( buf,"%i",n );
		rep=Rep::alloc( t_strlen(buf) );
		for( int i=0;i<rep->length;++i ) rep->data[i]=buf[i];
	}
	
	String( Float n ){
		char buf[256];
		
		//would rather use snprintf, but it's doing weird things in MingW.
		//
		sprintf_s( buf,"%.17lg",n );
		//
		char *p;
		for( p=buf;*p;++p ){
			if( *p=='.' || *p=='e' ) break;
		}
		if( !*p ){
			*p++='.';
			*p++='0';
			*p=0;
		}

		rep=Rep::alloc( t_strlen(buf) );
		for( int i=0;i<rep->length;++i ) rep->data[i]=buf[i];
	}

	String( Char ch,int length ):rep( Rep::alloc(length) ){
		for( int i=0;i<length;++i ) rep->data[i]=ch;
	}

	String( const Char *p ):rep( Rep::alloc(t_strlen(p)) ){
		t_memcpy( rep->data,p,rep->length );
	}

	String( const Char *p,int length ):rep( Rep::alloc(length) ){
		t_memcpy( rep->data,p,rep->length );
	}
	
#if __OBJC__	
	String( NSString *nsstr ):rep( Rep::alloc([nsstr length]) ){
		unichar *buf=(unichar*)malloc( rep->length * sizeof(unichar) );
		[nsstr getCharacters:buf range:NSMakeRange(0,rep->length)];
		for( int i=0;i<rep->length;++i ) rep->data[i]=buf[i];
		free( buf );
	}
#endif

#if __cplusplus_winrt
	String( Platform::String ^str ):rep( Rep::alloc(str->Length()) ){
		for( int i=0;i<rep->length;++i ) rep->data[i]=str->Data()[i];
	}
#endif

	~String(){
		rep->release();
	}
	
	template<class C> String( const C *p ):rep( Rep::alloc(t_strlen(p)) ){
		for( int i=0;i<rep->length;++i ) rep->data[i]=p[i];
	}
	
	template<class C> String( const C *p,int length ):rep( Rep::alloc(length) ){
		for( int i=0;i<rep->length;++i ) rep->data[i]=p[i];
	}
	
	String Copy()const{
		Rep *crep=Rep::alloc( rep->length );
		t_memcpy( crep->data,rep->data,rep->length );
		return String( crep );
	}
	
	int Length()const{
		return rep->length;
	}
	
	const Char *Data()const{
		return rep->data;
	}
	
	Char At( int index )const{
		if( index<0 || index>=rep->length ) dbg_error( "Character index out of range" );
		return rep->data[index]; 
	}
	
	Char operator[]( int index )const{
		return rep->data[index];
	}
	
	String &operator=( const String &t ){
		t.rep->retain();
		rep->release();
		rep=t.rep;
		return *this;
	}
	
	String &operator+=( const String &t ){
		return operator=( *this+t );
	}
	
	int Compare( const String &t )const{
		int n=rep->length<t.rep->length ? rep->length : t.rep->length;
		for( int i=0;i<n;++i ){
			if( int q=(int)(rep->data[i])-(int)(t.rep->data[i]) ) return q;
		}
		return rep->length-t.rep->length;
	}
	
	bool operator==( const String &t )const{
		return rep->length==t.rep->length && t_memcmp( rep->data,t.rep->data,rep->length )==0;
	}
	
	bool operator!=( const String &t )const{
		return rep->length!=t.rep->length || t_memcmp( rep->data,t.rep->data,rep->length )!=0;
	}
	
	bool operator<( const String &t )const{
		return Compare( t )<0;
	}
	
	bool operator<=( const String &t )const{
		return Compare( t )<=0;
	}
	
	bool operator>( const String &t )const{
		return Compare( t )>0;
	}
	
	bool operator>=( const String &t )const{
		return Compare( t )>=0;
	}
	
	String operator+( const String &t )const{
		if( !rep->length ) return t;
		if( !t.rep->length ) return *this;
		Rep *p=Rep::alloc( rep->length+t.rep->length );
		Char *q=p->data;
		q=t_memcpy( q,rep->data,rep->length );
		q=t_memcpy( q,t.rep->data,t.rep->length );
		return String( p );
	}
	
	int Find( String find,int start=0 )const{
		if( start<0 ) start=0;
		while( start+find.rep->length<=rep->length ){
			if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start;
			++start;
		}
		return -1;
	}
	
	int FindLast( String find )const{
		int start=rep->length-find.rep->length;
		while( start>=0 ){
			if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start;
			--start;
		}
		return -1;
	}
	
	int FindLast( String find,int start )const{
		if( start>rep->length-find.rep->length ) start=rep->length-find.rep->length;
		while( start>=0 ){
			if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start;
			--start;
		}
		return -1;
	}
	
	String Trim()const{
		int i=0,i2=rep->length;
		while( i<i2 && rep->data[i]<=32 ) ++i;
		while( i2>i && rep->data[i2-1]<=32 ) --i2;
		if( i==0 && i2==rep->length ) return *this;
		return String( rep->data+i,i2-i );
	}

	Array<String> Split( String sep )const{
	
		if( !sep.rep->length ){
			Array<String> bits( rep->length );
			for( int i=0;i<rep->length;++i ){
				bits[i]=String( (Char)(*this)[i],1 );
			}
			return bits;
		}
		
		int i=0,i2,n=1;
		while( (i2=Find( sep,i ))!=-1 ){
			++n;
			i=i2+sep.rep->length;
		}
		Array<String> bits( n );
		if( n==1 ){
			bits[0]=*this;
			return bits;
		}
		i=0;n=0;
		while( (i2=Find( sep,i ))!=-1 ){
			bits[n++]=Slice( i,i2 );
			i=i2+sep.rep->length;
		}
		bits[n]=Slice( i );
		return bits;
	}

	String Join( Array<String> bits )const{
		if( bits.Length()==0 ) return String();
		if( bits.Length()==1 ) return bits[0];
		int newlen=rep->length * (bits.Length()-1);
		for( int i=0;i<bits.Length();++i ){
			newlen+=bits[i].rep->length;
		}
		Rep *p=Rep::alloc( newlen );
		Char *q=p->data;
		q=t_memcpy( q,bits[0].rep->data,bits[0].rep->length );
		for( int i=1;i<bits.Length();++i ){
			q=t_memcpy( q,rep->data,rep->length );
			q=t_memcpy( q,bits[i].rep->data,bits[i].rep->length );
		}
		return String( p );
	}

	String Replace( String find,String repl )const{
		int i=0,i2,newlen=0;
		while( (i2=Find( find,i ))!=-1 ){
			newlen+=(i2-i)+repl.rep->length;
			i=i2+find.rep->length;
		}
		if( !i ) return *this;
		newlen+=rep->length-i;
		Rep *p=Rep::alloc( newlen );
		Char *q=p->data;
		i=0;
		while( (i2=Find( find,i ))!=-1 ){
			q=t_memcpy( q,rep->data+i,i2-i );
			q=t_memcpy( q,repl.rep->data,repl.rep->length );
			i=i2+find.rep->length;
		}
		q=t_memcpy( q,rep->data+i,rep->length-i );
		return String( p );
	}

	String ToLower()const{
		for( int i=0;i<rep->length;++i ){
			Char t=towlower( rep->data[i] );
			if( t==rep->data[i] ) continue;
			Rep *p=Rep::alloc( rep->length );
			Char *q=p->data;
			t_memcpy( q,rep->data,i );
			for( q[i++]=t;i<rep->length;++i ){
				q[i]=towlower( rep->data[i] );
			}
			return String( p );
		}
		return *this;
	}

	String ToUpper()const{
		for( int i=0;i<rep->length;++i ){
			Char t=towupper( rep->data[i] );
			if( t==rep->data[i] ) continue;
			Rep *p=Rep::alloc( rep->length );
			Char *q=p->data;
			t_memcpy( q,rep->data,i );
			for( q[i++]=t;i<rep->length;++i ){
				q[i]=towupper( rep->data[i] );
			}
			return String( p );
		}
		return *this;
	}
	
	bool Contains( String sub )const{
		return Find( sub )!=-1;
	}

	bool StartsWith( String sub )const{
		return sub.rep->length<=rep->length && !t_memcmp( rep->data,sub.rep->data,sub.rep->length );
	}

	bool EndsWith( String sub )const{
		return sub.rep->length<=rep->length && !t_memcmp( rep->data+rep->length-sub.rep->length,sub.rep->data,sub.rep->length );
	}
	
	String Slice( int from,int term )const{
		int len=rep->length;
		if( from<0 ){
			from+=len;
			if( from<0 ) from=0;
		}else if( from>len ){
			from=len;
		}
		if( term<0 ){
			term+=len;
		}else if( term>len ){
			term=len;
		}
		if( term<from ) return String();
		if( from==0 && term==len ) return *this;
		return String( rep->data+from,term-from );
	}

	String Slice( int from )const{
		return Slice( from,rep->length );
	}
	
	Array<int> ToChars()const{
		Array<int> chars( rep->length );
		for( int i=0;i<rep->length;++i ) chars[i]=rep->data[i];
		return chars;
	}
	
	int ToInt()const{
		char buf[64];
		return atoi( ToCString<char>( buf,sizeof(buf) ) );
	}
	
	Float ToFloat()const{
		char buf[256];
		return atof( ToCString<char>( buf,sizeof(buf) ) );
	}

	template<class C> class CString{
		struct Rep{
			int refs;
			C data[1];
		};
		Rep *_rep;
		static Rep _nul;
	public:
		template<class T> CString( const T *data,int length ){
			_rep=(Rep*)malloc( length*sizeof(C)+sizeof(Rep) );
			_rep->refs=1;
			_rep->data[length]=0;
			for( int i=0;i<length;++i ){
				_rep->data[i]=(C)data[i];
			}
		}
		CString():_rep( new Rep ){
			_rep->refs=1;
		}
		CString( const CString &c ):_rep(c._rep){
			++_rep->refs;
		}
		~CString(){
			if( !--_rep->refs ) free( _rep );
		}
		CString &operator=( const CString &c ){
			++c._rep->refs;
			if( !--_rep->refs ) free( _rep );
			_rep=c._rep;
			return *this;
		}
		operator const C*()const{ 
			return _rep->data;
		}
	};
	
	template<class C> CString<C> ToCString()const{
		return CString<C>( rep->data,rep->length );
	}

	template<class C> C *ToCString( C *p,int length )const{
		if( --length>rep->length ) length=rep->length;
		for( int i=0;i<length;++i ) p[i]=rep->data[i];
		p[length]=0;
		return p;
	}
	
#if __OBJC__	
	NSString *ToNSString()const{
		return [NSString stringWithCharacters:ToCString<unichar>() length:rep->length];
	}
#endif

#if __cplusplus_winrt
	Platform::String ^ToWinRTString()const{
		return ref new Platform::String( rep->data,rep->length );
	}
#endif
	CString<char> ToUtf8()const{
		std::vector<unsigned char> buf;
		Save( buf );
		return CString<char>( &buf[0],buf.size() );
	}

	bool Save( FILE *fp )const{
		std::vector<unsigned char> buf;
		Save( buf );
		return buf.size() ? fwrite( &buf[0],1,buf.size(),fp )==buf.size() : true;
	}
	
	void Save( std::vector<unsigned char> &buf )const{
	
		Char *p=rep->data;
		Char *e=p+rep->length;
		
		while( p<e ){
			Char c=*p++;
			if( c<0x80 ){
				buf.push_back( c );
			}else if( c<0x800 ){
				buf.push_back( 0xc0 | (c>>6) );
				buf.push_back( 0x80 | (c & 0x3f) );
			}else{
				buf.push_back( 0xe0 | (c>>12) );
				buf.push_back( 0x80 | ((c>>6) & 0x3f) );
				buf.push_back( 0x80 | (c & 0x3f) );
			}
		}
	}
	
	static String FromChars( Array<int> chars ){
		int n=chars.Length();
		Rep *p=Rep::alloc( n );
		for( int i=0;i<n;++i ){
			p->data[i]=chars[i];
		}
		return String( p );
	}

	static String Load( FILE *fp ){
		unsigned char tmp[4096];
		std::vector<unsigned char> buf;
		for(;;){
			int n=fread( tmp,1,4096,fp );
			if( n>0 ) buf.insert( buf.end(),tmp,tmp+n );
			if( n!=4096 ) break;
		}
		return buf.size() ? String::Load( &buf[0],buf.size() ) : String();
	}
	
	static String Load( unsigned char *p,int n ){
	
		_str_load_err=0;
		
		unsigned char *e=p+n;
		std::vector<Char> chars;
		
		int t0=n>0 ? p[0] : -1;
		int t1=n>1 ? p[1] : -1;

		if( t0==0xfe && t1==0xff ){
			p+=2;
			while( p<e-1 ){
				int c=*p++;
				chars.push_back( (c<<8)|*p++ );
			}
		}else if( t0==0xff && t1==0xfe ){
			p+=2;
			while( p<e-1 ){
				int c=*p++;
				chars.push_back( (*p++<<8)|c );
			}
		}else{
			int t2=n>2 ? p[2] : -1;
			if( t0==0xef && t1==0xbb && t2==0xbf ) p+=3;
			unsigned char *q=p;
			bool fail=false;
			while( p<e ){
				unsigned int c=*p++;
				if( c & 0x80 ){
					if( (c & 0xe0)==0xc0 ){
						if( p>=e || (p[0] & 0xc0)!=0x80 ){
							fail=true;
							break;
						}
						c=((c & 0x1f)<<6) | (p[0] & 0x3f);
						p+=1;
					}else if( (c & 0xf0)==0xe0 ){
						if( p+1>=e || (p[0] & 0xc0)!=0x80 || (p[1] & 0xc0)!=0x80 ){
							fail=true;
							break;
						}
						c=((c & 0x0f)<<12) | ((p[0] & 0x3f)<<6) | (p[1] & 0x3f);
						p+=2;
					}else{
						fail=true;
						break;
					}
				}
				chars.push_back( c );
			}
			if( fail ){
				_str_load_err="Invalid UTF-8";
				return String( q,n );
			}
		}
		return chars.size() ? String( &chars[0],chars.size() ) : String();
	}

private:
	
	struct Rep{
		int refs;
		int length;
		Char data[0];
		
		Rep():refs(1),length(0){
		}
		
		Rep( int length ):refs(1),length(length){
		}
		
		void retain(){
			++refs;
		}
		
		void release(){
			if( --refs || this==&nullRep ) return;
			gc_new_bytes-=sizeof(Rep)+length*sizeof(Char);
			free( this );
		}

		static Rep *alloc( int length ){
			if( !length ) return &nullRep;
			void *p=malloc( sizeof(Rep)+length*sizeof(Char) );
			gc_new_bytes+=sizeof(Rep)+length*sizeof(Char);
			return new(p) Rep( length );
		}
	};
	Rep *rep;
	
	static Rep nullRep;
	
	String( Rep *rep ):rep(rep){
	}
};

String::Rep String::nullRep;

String *t_create( int n,String *p ){
	for( int i=0;i<n;++i ) new( &p[i] ) String();
	return p+n;
}

String *t_create( int n,String *p,const String *q ){
	for( int i=0;i<n;++i ) new( &p[i] ) String( q[i] );
	return p+n;
}

void t_destroy( int n,String *p ){
	for( int i=0;i<n;++i ) p[i].~String();
}

// ***** Object *****

String dbg_stacktrace();

class Object : public gc_object{
public:
	virtual bool Equals( Object *obj ){
		return this==obj;
	}
	
	virtual int Compare( Object *obj ){
		return (char*)this-(char*)obj;
	}
	
	virtual String debug(){
		return "+Object\n";
	}
};

class ThrowableObject : public Object{
#ifndef NDEBUG
public:
	String stackTrace;
	ThrowableObject():stackTrace( dbg_stacktrace() ){}
#endif
};

struct gc_interface{
	virtual ~gc_interface(){}
};

//***** Debugger *****

//#define Error bbError
//#define Print bbPrint

int bbPrint( String t );

#define dbg_stream stderr

#if _MSC_VER
#define dbg_typeof decltype
#else
#define dbg_typeof __typeof__
#endif 

struct dbg_func;
struct dbg_var_type;

static int dbg_suspend;
static int dbg_stepmode;

const char *dbg_info;
String dbg_exstack;

static void *dbg_var_buf[65536*3];
static void **dbg_var_ptr=dbg_var_buf;

static dbg_func *dbg_func_buf[1024];
static dbg_func **dbg_func_ptr=dbg_func_buf;

String dbg_type( bool *p ){
	return "Bool";
}

String dbg_type( int *p ){
	return "Int";
}

String dbg_type( Float *p ){
	return "Float";
}

String dbg_type( String *p ){
	return "String";
}

template<class T> String dbg_type( T **p ){
	return "Object";
}

template<class T> String dbg_type( Array<T> *p ){
	return dbg_type( &(*p)[0] )+"[]";
}

String dbg_value( bool *p ){
	return *p ? "True" : "False";
}

String dbg_value( int *p ){
	return String( *p );
}

String dbg_value( Float *p ){
	return String( *p );
}

String dbg_value( String *p ){
	String t=*p;
	if( t.Length()>100 ) t=t.Slice( 0,100 )+"...";
	t=t.Replace( "\"","~q" );
	t=t.Replace( "\t","~t" );
	t=t.Replace( "\n","~n" );
	t=t.Replace( "\r","~r" );
	return String("\"")+t+"\"";
}

template<class T> String dbg_value( T **t ){
	Object *p=dynamic_cast<Object*>( *t );
	char buf[64];
	sprintf_s( buf,"%p",p );
	return String("@") + (buf[0]=='0' && buf[1]=='x' ? buf+2 : buf );
}

template<class T> String dbg_value( Array<T> *p ){
	String t="[";
	int n=(*p).Length();
	if( n>100 ) n=100;
	for( int i=0;i<n;++i ){
		if( i ) t+=",";
		t+=dbg_value( &(*p)[i] );
	}
	return t+"]";
}

String dbg_ptr_value( void *p ){
	char buf[64];
	sprintf_s( buf,"%p",p );
	return (buf[0]=='0' && buf[1]=='x' ? buf+2 : buf );
}

template<class T> String dbg_decl( const char *id,T *ptr ){
	return String( id )+":"+dbg_type(ptr)+"="+dbg_value(ptr)+"\n";
}

struct dbg_var_type{
	virtual String type( void *p )=0;
	virtual String value( void *p )=0;
};

template<class T> struct dbg_var_type_t : public dbg_var_type{

	String type( void *p ){
		return dbg_type( (T*)p );
	}
	
	String value( void *p ){
		return dbg_value( (T*)p );
	}
	
	static dbg_var_type_t<T> info;
};
template<class T> dbg_var_type_t<T> dbg_var_type_t<T>::info;

struct dbg_blk{
	void **var_ptr;
	
	dbg_blk():var_ptr(dbg_var_ptr){
		if( dbg_stepmode=='l' ) --dbg_suspend;
	}
	
	~dbg_blk(){
		if( dbg_stepmode=='l' ) ++dbg_suspend;
		dbg_var_ptr=var_ptr;
	}
};

struct dbg_func : public dbg_blk{
	const char *id;
	const char *info;

	dbg_func( const char *p ):id(p),info(dbg_info){
		*dbg_func_ptr++=this;
		if( dbg_stepmode=='s' ) --dbg_suspend;
	}
	
	~dbg_func(){
		if( dbg_stepmode=='s' ) ++dbg_suspend;
		--dbg_func_ptr;
		dbg_info=info;
	}
};

int dbg_print( String t ){
	static char *buf;
	static int len;
	int n=t.Length();
	if( n+100>len ){
		len=n+100;
		free( buf );
		buf=(char*)malloc( len );
	}
	buf[n]='\n';
	for( int i=0;i<n;++i ) buf[i]=t[i];
	fwrite( buf,n+1,1,dbg_stream );
	fflush( dbg_stream );
	return 0;
}

void dbg_callstack(){

	void **var_ptr=dbg_var_buf;
	dbg_func **func_ptr=dbg_func_buf;
	
	while( var_ptr!=dbg_var_ptr ){
		while( func_ptr!=dbg_func_ptr && var_ptr==(*func_ptr)->var_ptr ){
			const char *id=(*func_ptr++)->id;
			const char *info=func_ptr!=dbg_func_ptr ? (*func_ptr)->info : dbg_info;
			fprintf( dbg_stream,"+%s;%s\n",id,info );
		}
		void *vp=*var_ptr++;
		const char *nm=(const char*)*var_ptr++;
		dbg_var_type *ty=(dbg_var_type*)*var_ptr++;
		dbg_print( String(nm)+":"+ty->type(vp)+"="+ty->value(vp) );
	}
	while( func_ptr!=dbg_func_ptr ){
		const char *id=(*func_ptr++)->id;
		const char *info=func_ptr!=dbg_func_ptr ? (*func_ptr)->info : dbg_info;
		fprintf( dbg_stream,"+%s;%s\n",id,info );
	}
}

String dbg_stacktrace(){
	if( !dbg_info || !dbg_info[0] ) return "";
	String str=String( dbg_info )+"\n";
	dbg_func **func_ptr=dbg_func_ptr;
	if( func_ptr==dbg_func_buf ) return str;
	while( --func_ptr!=dbg_func_buf ){
		str+=String( (*func_ptr)->info )+"\n";
	}
	return str;
}

void dbg_throw( const char *err ){
	dbg_exstack=dbg_stacktrace();
	throw err;
}

void dbg_stop(){

#if TARGET_OS_IPHONE
	dbg_throw( "STOP" );
#endif

	fprintf( dbg_stream,"{{~~%s~~}}\n",dbg_info );
	dbg_callstack();
	dbg_print( "" );
	
	for(;;){

		char buf[256];
		char *e=fgets( buf,256,stdin );
		if( !e ) exit( -1 );
		
		e=strchr( buf,'\n' );
		if( !e ) exit( -1 );
		
		*e=0;
		
		Object *p;
		
		switch( buf[0] ){
		case '?':
			break;
		case 'r':	//run
			dbg_suspend=0;		
			dbg_stepmode=0;
			return;
		case 's':	//step
			dbg_suspend=1;
			dbg_stepmode='s';
			return;
		case 'e':	//enter func
			dbg_suspend=1;
			dbg_stepmode='e';
			return;
		case 'l':	//leave block
			dbg_suspend=0;
			dbg_stepmode='l';
			return;
		case '@':	//dump object
			p=0;
			sscanf_s( buf+1,"%p",&p );
			if( p ){
				dbg_print( p->debug() );
			}else{
				dbg_print( "" );
			}
			break;
		case 'q':	//quit!
			exit( 0 );
			break;			
		default:
			printf( "????? %s ?????",buf );fflush( stdout );
			exit( -1 );
		}
	}
}

void dbg_error( const char *err ){

#if TARGET_OS_IPHONE
	dbg_throw( err );
#endif

	for(;;){
		bbPrint( String("Cerberus Runtime Error : ")+err );
		bbPrint( dbg_stacktrace() );
		dbg_stop();
	}
}

#define DBG_INFO(X) dbg_info=(X);if( dbg_suspend>0 ) dbg_stop();

#define DBG_ENTER(P) dbg_func _dbg_func(P);

#define DBG_BLOCK() dbg_blk _dbg_blk;

#define DBG_GLOBAL( ID,NAME )	//TODO!

#define DBG_LOCAL( ID,NAME )\
*dbg_var_ptr++=&ID;\
*dbg_var_ptr++=(void*)NAME;\
*dbg_var_ptr++=&dbg_var_type_t<dbg_typeof(ID)>::info;

//**** main ****

int argc;
const char **argv;

Float D2R=0.017453292519943295f;
Float R2D=57.29577951308232f;

int bbPrint( String t ){

	static std::vector<unsigned char> buf;
	buf.clear();
	t.Save( buf );
	buf.push_back( '\n' );
	buf.push_back( 0 );
	
#if __cplusplus_winrt	//winrt?

#if CFG_WINRT_PRINT_ENABLED
	OutputDebugStringA( (const char*)&buf[0] );
#endif

#elif _WIN32			//windows?

	fputs( (const char*)&buf[0],stdout );
	fflush( stdout );

#elif __APPLE__			//macos/ios?

	fputs( (const char*)&buf[0],stdout );
	fflush( stdout );
	
#elif __linux			//linux?

#if CFG_ANDROID_NDK_PRINT_ENABLED
	LOGI( (const char*)&buf[0] );
#else
	fputs( (const char*)&buf[0],stdout );
	fflush( stdout );
#endif

#endif

	return 0;
}

class BBExitApp{
};

int bbError( String err ){
	if( !err.Length() ){
#if __cplusplus_winrt
		throw BBExitApp();
#else
		exit( 0 );
#endif
	}
	dbg_error( err.ToCString<char>() );
	return 0;
}

int bbDebugLog( String t ){
	bbPrint( t );
	return 0;
}

int bbDebugStop(){
	dbg_stop();
	return 0;
}

int bbInit();
int bbMain();

#if _MSC_VER

static void _cdecl seTranslator( unsigned int ex,EXCEPTION_POINTERS *p ){

	switch( ex ){
	case EXCEPTION_ACCESS_VIOLATION:dbg_error( "Memory access violation" );
	case EXCEPTION_ILLEGAL_INSTRUCTION:dbg_error( "Illegal instruction" );
	case EXCEPTION_INT_DIVIDE_BY_ZERO:dbg_error( "Integer divide by zero" );
	case EXCEPTION_STACK_OVERFLOW:dbg_error( "Stack overflow" );
	}
	dbg_error( "Unknown exception" );
}

#else

void sighandler( int sig  ){
	switch( sig ){
	case SIGSEGV:dbg_error( "Memory access violation" );
	case SIGILL:dbg_error( "Illegal instruction" );
	case SIGFPE:dbg_error( "Floating point exception" );
#if !_WIN32
	case SIGBUS:dbg_error( "Bus error" );
#endif	
	}
	dbg_error( "Unknown signal" );
}

#endif

//entry point call by target main()...
//
int bb_std_main( int argc,const char **argv ){

	::argc=argc;
	::argv=argv;
	
#if _MSC_VER

	_set_se_translator( seTranslator );

#else
	
	signal( SIGSEGV,sighandler );
	signal( SIGILL,sighandler );
	signal( SIGFPE,sighandler );
#if !_WIN32
	signal( SIGBUS,sighandler );
#endif

#endif

	if( !setlocale( LC_CTYPE,"en_US.UTF-8" ) ){
		setlocale( LC_CTYPE,"" );
	}

	gc_init1();

	bbInit();
	
	gc_init2();

	bbMain();

	return 0;
}


//***** game.h *****

struct BBGameEvent{
	enum{
		None=0,
		KeyDown=1,KeyUp=2,KeyChar=3,
		MouseDown=4,MouseUp=5,MouseMove=6,
		TouchDown=7,TouchUp=8,TouchMove=9,
		MotionAccel=10
	};
};

class BBGameDelegate : public Object{
public:
	virtual void StartGame(){}
	virtual void SuspendGame(){}
	virtual void ResumeGame(){}
	virtual void UpdateGame(){}
	virtual void RenderGame(){}
	virtual void KeyEvent( int event,int data ){}
	virtual void MouseEvent( int event,int data,Float x,Float y, Float z ){}
	virtual void TouchEvent( int event,int data,Float x,Float y ){}
	virtual void MotionEvent( int event,int data,Float x,Float y,Float z ){}
	virtual void DiscardGraphics(){}
};

struct BBDisplayMode : public Object{
	int width;
	int height;
	int depth;
	int hertz;
	int flags;
	BBDisplayMode( int width=0,int height=0,int depth=0,int hertz=0,int flags=0 ):width(width),height(height),depth(depth),hertz(hertz),flags(flags){}
};

class BBGame{
public:
	BBGame();
	virtual ~BBGame(){}
	
	// ***** Extern *****
	static BBGame *Game(){ return _game; }
	
	virtual void SetDelegate( BBGameDelegate *delegate );
	virtual BBGameDelegate *Delegate(){ return _delegate; }
	
	virtual void SetKeyboardEnabled( bool enabled );
	virtual bool KeyboardEnabled();
	
	virtual void SetUpdateRate( int updateRate );
	virtual int UpdateRate();
	
	virtual bool Started(){ return _started; }
	virtual bool Suspended(){ return _suspended; }
	
	virtual int Millisecs();
	virtual void GetDate( Array<int> date );
	virtual int SaveState( String state );
	virtual String LoadState();
	virtual String LoadString( String path );
	virtual int CountJoysticks( bool update );
	virtual bool PollJoystick( int port,Array<Float> joyx,Array<Float> joyy,Array<Float> joyz,Array<bool> buttons );
	virtual void OpenUrl( String url );
	virtual void SetMouseVisible( bool visible );
	
	virtual int GetDeviceWidth(){ return 0; }
	virtual int GetDeviceHeight(){ return 0; }
	virtual void SetDeviceWindow( int width,int height,int flags ){}
	virtual Array<BBDisplayMode*> GetDisplayModes(){ return Array<BBDisplayMode*>(); }
	virtual BBDisplayMode *GetDesktopMode(){ return 0; }
	virtual void SetSwapInterval( int interval ){}

	// ***** Native *****
	virtual String PathToFilePath( String path );
	virtual FILE *OpenFile( String path,String mode );
	virtual unsigned char *LoadData( String path,int *plength );
	virtual unsigned char *LoadImageData( String path,int *width,int *height,int *depth ){ return 0; }
	virtual unsigned char *LoadAudioData( String path,int *length,int *channels,int *format,int *hertz ){ return 0; }
	
	//***** Internal *****
	virtual void Die( ThrowableObject *ex );
	virtual void gc_collect();
	virtual void StartGame();
	virtual void SuspendGame();
	virtual void ResumeGame();
	virtual void UpdateGame();
	virtual void RenderGame();
	virtual void KeyEvent( int ev,int data );
	virtual void MouseEvent( int ev,int data,float x,float y, float z );
	virtual void TouchEvent( int ev,int data,float x,float y );
	virtual void MotionEvent( int ev,int data,float x,float y,float z );
	virtual void DiscardGraphics();
	
protected:

	static BBGame *_game;

	BBGameDelegate *_delegate;
	bool _keyboardEnabled;
	int _updateRate;
	bool _started;
	bool _suspended;
};

//***** game.cpp *****

BBGame *BBGame::_game;

BBGame::BBGame():
_delegate( 0 ),
_keyboardEnabled( false ),
_updateRate( 0 ),
_started( false ),
_suspended( false ){
	_game=this;
}

void BBGame::SetDelegate( BBGameDelegate *delegate ){
	_delegate=delegate;
}

void BBGame::SetKeyboardEnabled( bool enabled ){
	_keyboardEnabled=enabled;
}

bool BBGame::KeyboardEnabled(){
	return _keyboardEnabled;
}

void BBGame::SetUpdateRate( int updateRate ){
	_updateRate=updateRate;
}

int BBGame::UpdateRate(){
	return _updateRate;
}

int BBGame::Millisecs(){
	return 0;
}

void BBGame::GetDate( Array<int> date ){
	int n=date.Length();
	if( n>0 ){
		time_t t=time( 0 );
		
#if _MSC_VER
		struct tm tii;
		struct tm *ti=&tii;
		localtime_s( ti,&t );
#else
		struct tm *ti=localtime( &t );
#endif

		date[0]=ti->tm_year+1900;
		if( n>1 ){ 
			date[1]=ti->tm_mon+1;
			if( n>2 ){
				date[2]=ti->tm_mday;
				if( n>3 ){
					date[3]=ti->tm_hour;
					if( n>4 ){
						date[4]=ti->tm_min;
						if( n>5 ){
							date[5]=ti->tm_sec;
							if( n>6 ){
								date[6]=0;
							}
						}
					}
				}
			}
		}
	}
}

int BBGame::SaveState( String state ){
	if( FILE *f=OpenFile( "./.cerberusstate","wb" ) ){
		bool ok=state.Save( f );
		fclose( f );
		return ok ? 0 : -2;
	}
	return -1;
}

String BBGame::LoadState(){
	if( FILE *f=OpenFile( "./.cerberusstate","rb" ) ){
		String str=String::Load( f );
		fclose( f );
		return str;
	}
	return "";
}

String BBGame::LoadString( String path ){
	if( FILE *fp=OpenFile( path,"rb" ) ){
		String str=String::Load( fp );
		fclose( fp );
		return str;
	}
	return "";
}

int BBGame::CountJoysticks( bool update ){
	return 0;
}

bool BBGame::PollJoystick( int port,Array<Float> joyx,Array<Float> joyy,Array<Float> joyz,Array<bool> buttons ){
	return false;
}

void BBGame::OpenUrl( String url ){
}

void BBGame::SetMouseVisible( bool visible ){
}

//***** C++ Game *****

String BBGame::PathToFilePath( String path ){
	return path;
}

FILE *BBGame::OpenFile( String path,String mode ){
	path=PathToFilePath( path );
	if( path=="" ) return 0;
	
#if __cplusplus_winrt
	path=path.Replace( "/","\\" );
	FILE *f;
	if( _wfopen_s( &f,path.ToCString<wchar_t>(),mode.ToCString<wchar_t>() ) ) return 0;
	return f;
#elif _WIN32
	return _wfopen( path.ToCString<wchar_t>(),mode.ToCString<wchar_t>() );
#else
	return fopen( path.ToCString<char>(),mode.ToCString<char>() );
#endif
}

unsigned char *BBGame::LoadData( String path,int *plength ){

	FILE *f=OpenFile( path,"rb" );
	if( !f ) return 0;

	const int BUF_SZ=4096;
	std::vector<void*> tmps;
	int length=0;
	
	for(;;){
		void *p=malloc( BUF_SZ );
		int n=fread( p,1,BUF_SZ,f );
		tmps.push_back( p );
		length+=n;
		if( n!=BUF_SZ ) break;
	}
	fclose( f );
	
	unsigned char *data=(unsigned char*)malloc( length );
	unsigned char *p=data;
	
	int sz=length;
	for( int i=0;i<tmps.size();++i ){
		int n=sz>BUF_SZ ? BUF_SZ : sz;
		memcpy( p,tmps[i],n );
		free( tmps[i] );
		sz-=n;
		p+=n;
	}
	
	*plength=length;
	
	gc_ext_malloced( length );
	
	return data;
}

//***** INTERNAL *****

void BBGame::Die( ThrowableObject *ex ){
	bbPrint( "Cerberus Runtime Error : Uncaught Cerberus Exception" );
#ifndef NDEBUG
	bbPrint( ex->stackTrace );
#endif
	exit( -1 );
}

void BBGame::gc_collect(){
	gc_mark( _delegate );
	::gc_collect();
}

void BBGame::StartGame(){

	if( _started ) return;
	_started=true;
	
	try{
		_delegate->StartGame();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::SuspendGame(){

	if( !_started || _suspended ) return;
	_suspended=true;
	
	try{
		_delegate->SuspendGame();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::ResumeGame(){

	if( !_started || !_suspended ) return;
	_suspended=false;
	
	try{
		_delegate->ResumeGame();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::UpdateGame(){

	if( !_started || _suspended ) return;
	
	try{
		_delegate->UpdateGame();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::RenderGame(){

	if( !_started ) return;
	
	try{
		_delegate->RenderGame();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::KeyEvent( int ev,int data ){

	if( !_started ) return;
	
	try{
		_delegate->KeyEvent( ev,data );
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::MouseEvent( int ev,int data,float x,float y, float z ){

	if( !_started ) return;
	
	try{
		_delegate->MouseEvent( ev,data,x,y,z );
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::TouchEvent( int ev,int data,float x,float y ){

	if( !_started ) return;
	
	try{
		_delegate->TouchEvent( ev,data,x,y );
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::MotionEvent( int ev,int data,float x,float y,float z ){

	if( !_started ) return;
	
	try{
		_delegate->MotionEvent( ev,data,x,y,z );
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}

void BBGame::DiscardGraphics(){

	if( !_started ) return;
	
	try{
		_delegate->DiscardGraphics();
	}catch( ThrowableObject *ex ){
		Die( ex );
	}
	gc_collect();
}


//***** wavloader.h *****
//
unsigned char *LoadWAV( FILE *f,int *length,int *channels,int *format,int *hertz );

//***** wavloader.cpp *****
//
static const char *readTag( FILE *f ){
	static char buf[8];
	if( fread( buf,4,1,f )!=1 ) return "";
	buf[4]=0;
	return buf;
}

static int readInt( FILE *f ){
	unsigned char buf[4];
	if( fread( buf,4,1,f )!=1 ) return -1;
	return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
}

static int readShort( FILE *f ){
	unsigned char buf[2];
	if( fread( buf,2,1,f )!=1 ) return -1;
	return (buf[1]<<8) | buf[0];
}

static void skipBytes( int n,FILE *f ){
	char *p=(char*)malloc( n );
	fread( p,n,1,f );
	free(p);
}

unsigned char *LoadWAV( FILE *f,int *plength,int *pchannels,int *pformat,int *phertz ){
	if( !strcmp( readTag( f ),"RIFF" ) ){
		int len=readInt( f )-8;len=len;
		if( !strcmp( readTag( f ),"WAVE" ) ){
			if( !strcmp( readTag( f ),"fmt " ) ){
				int len2=readInt( f );
				int comp=readShort( f );
				if( comp==1 ){
					int chans=readShort( f );
					int hertz=readInt( f );
					int bytespersec=readInt( f );bytespersec=bytespersec;
					int pad=readShort( f );pad=pad;
					int bits=readShort( f );
					int format=bits/8;
					if( len2>16 ) skipBytes( len2-16,f );
					for(;;){
						const char *p=readTag( f );
						if( feof( f ) ) break;
						int size=readInt( f );
						if( strcmp( p,"data" ) ){
							skipBytes( size,f );
							continue;
						}
						unsigned char *data=(unsigned char*)malloc( size );
						if( fread( data,size,1,f )==1 ){
							*plength=size/(chans*format);
							*pchannels=chans;
							*pformat=format;
							*phertz=hertz;
							return data;
						}
						free( data );
					}
				}
			}
		}
	}
	return 0;
}



//***** oggloader.h *****
unsigned char *LoadOGG( FILE *f,int *length,int *channels,int *format,int *hertz );

//***** oggloader.cpp *****
unsigned char *LoadOGG( FILE *f,int *length,int *channels,int *format,int *hertz ){

	int error;
	stb_vorbis *v=stb_vorbis_open_file( f,0,&error,0 );
	if( !v ) return 0;
	
	stb_vorbis_info info=stb_vorbis_get_info( v );
	
	int limit=info.channels*4096;
	int offset=0,data_len=0,total=limit;

	short *data=(short*)malloc( total*sizeof(short) );
	
	for(;;){
		int n=stb_vorbis_get_frame_short_interleaved( v,info.channels,data+offset,total-offset );
		if( !n ) break;
	
		data_len+=n;
		offset+=n*info.channels;
		
		if( offset+limit>total ){
			total*=2;
			data=(short*)realloc( data,total*sizeof(short) );
		}
	}
	
	*length=data_len;
	*channels=info.channels;
	*format=2;
	*hertz=info.sample_rate;
	
	stb_vorbis_close(v);

	return (unsigned char*)data;
}



//***** glfwgame.h *****

class BBGlfwGame : public BBGame{
public:
	BBGlfwGame();
	
	static BBGlfwGame *GlfwGame(){ return _glfwGame; }
	
	virtual void SetUpdateRate( int hertz );
	virtual int Millisecs();
	virtual int CountJoysticks( bool update );
	virtual bool PollJoystick( int port,Array<Float> joyx,Array<Float> joyy,Array<Float> joyz,Array<bool> buttons );
	virtual void OpenUrl( String url );
	virtual void SetMouseVisible( bool visible );
		
	virtual int GetDeviceWidth(){ return _width; }
	virtual int GetDeviceHeight(){ return _height; }
	virtual void SetDeviceWindow( int width,int height,int flags );
	virtual void SetSwapInterval( int interval );
	virtual Array<BBDisplayMode*> GetDisplayModes();
	virtual BBDisplayMode *GetDesktopMode();

	virtual String PathToFilePath( String path );
	virtual unsigned char *LoadImageData( String path,int *width,int *height,int *format );
	virtual unsigned char *LoadAudioData( String path,int *length,int *channels,int *format,int *hertz );
	
	void Run();
	
	GLFWwindow *GetGLFWwindow(){ return _window; }
		
private:
	static BBGlfwGame *_glfwGame;
	
	GLFWvidmode _desktopMode;
	
	GLFWwindow *_window;
	int _width;
	int _height;
	int _swapInterval;
	bool _focus;

	double _updatePeriod;
	double _nextUpdate;
	
	String _baseDir;
	String _internalDir;
	
	int _joys[4];
	int _numJoys;
	bool _joysCounted;
	
	double GetTime();
	void Sleep( double time );
	void UpdateEvents();

//	void SetGlfwWindow( int width,int height,int red,int green,int blue,int alpha,int depth,int stencil,bool fullscreen );
		
	static int TransKey( int key );
	static int KeyToChar( int key );
	
	static void OnKey( GLFWwindow *window,int key,int scancode,int action,int mods );
	static void OnChar( GLFWwindow *window,unsigned int chr );
	static void OnMouseButton( GLFWwindow *window,int button,int action,int mods );
  static void OnMouseWheel( GLFWwindow *window, double x, double y );
	static void OnCursorPos( GLFWwindow *window,double x,double y );
	static void OnWindowClose( GLFWwindow *window );
	static void OnWindowSize( GLFWwindow *window,int width,int height );
};

//***** glfwgame.cpp *****

#include <errno.h>

#define _QUOTE(X) #X
#define _STRINGIZE( X ) _QUOTE(X)

enum{
	VKEY_BACKSPACE=8,VKEY_TAB,
	VKEY_ENTER=13,
	VKEY_SHIFT=16,
	VKEY_CONTROL=17,
	VKEY_ESCAPE=27,
	VKEY_SPACE=32,
	VKEY_PAGE_UP=33,VKEY_PAGE_DOWN,VKEY_END,VKEY_HOME,
	VKEY_LEFT=37,VKEY_UP,VKEY_RIGHT,VKEY_DOWN,
	VKEY_INSERT=45,VKEY_DELETE,
	VKEY_0=48,VKEY_1,VKEY_2,VKEY_3,VKEY_4,VKEY_5,VKEY_6,VKEY_7,VKEY_8,VKEY_9,
	VKEY_A=65,VKEY_B,VKEY_C,VKEY_D,VKEY_E,VKEY_F,VKEY_G,VKEY_H,VKEY_I,VKEY_J,
	VKEY_K,VKEY_L,VKEY_M,VKEY_N,VKEY_O,VKEY_P,VKEY_Q,VKEY_R,VKEY_S,VKEY_T,
	VKEY_U,VKEY_V,VKEY_W,VKEY_X,VKEY_Y,VKEY_Z,
	
	VKEY_LSYS=91,VKEY_RSYS,
	
	VKEY_NUM0=96,VKEY_NUM1,VKEY_NUM2,VKEY_NUM3,VKEY_NUM4,
	VKEY_NUM5,VKEY_NUM6,VKEY_NUM7,VKEY_NUM8,VKEY_NUM9,
	VKEY_NUMMULTIPLY=106,VKEY_NUMADD,VKEY_NUMSLASH,
	VKEY_NUMSUBTRACT,VKEY_NUMDECIMAL,VKEY_NUMDIVIDE,

	VKEY_F1=112,VKEY_F2,VKEY_F3,VKEY_F4,VKEY_F5,VKEY_F6,
	VKEY_F7,VKEY_F8,VKEY_F9,VKEY_F10,VKEY_F11,VKEY_F12,

	VKEY_LEFT_SHIFT=160,VKEY_RIGHT_SHIFT,
	VKEY_LEFT_CONTROL=162,VKEY_RIGHT_CONTROL,
	VKEY_LEFT_ALT=164,VKEY_RIGHT_ALT,

	VKEY_TILDE=192,VKEY_MINUS=189,VKEY_EQUALS=187,
	VKEY_OPENBRACKET=219,VKEY_BACKSLASH=220,VKEY_CLOSEBRACKET=221,
	VKEY_SEMICOLON=186,VKEY_QUOTES=222,
	VKEY_COMMA=188,VKEY_PERIOD=190,VKEY_SLASH=191
};

void Init_GL_Exts();

int glfwGraphicsSeq=0;

BBGlfwGame *BBGlfwGame::_glfwGame;

BBGlfwGame::BBGlfwGame():_window(0),_width(0),_height(0),_swapInterval(1),_focus(true),_updatePeriod(0),_nextUpdate(0),_numJoys(0),_joysCounted(false){
	_glfwGame=this;

	memset( &_desktopMode,0,sizeof(_desktopMode) );	
	const GLFWvidmode *vmode=glfwGetVideoMode( glfwGetPrimaryMonitor() );
	if( vmode ) _desktopMode=*vmode;
}

void BBGlfwGame::SetUpdateRate( int updateRate ){
	BBGame::SetUpdateRate( updateRate );
	if( _updateRate ) _updatePeriod=1.0/_updateRate;
	_nextUpdate=0;
}

int BBGlfwGame::Millisecs(){
	return int( GetTime()*1000.0 );
}

int BBGlfwGame::CountJoysticks( bool update ){

	if( !update && _joysCounted ) return _numJoys;

	_joysCounted=true;

	_numJoys=0;

	for( int joy=0;joy<16 && _numJoys<4;++joy ){
		if( glfwJoystickPresent( joy ) ) _joys[_numJoys++]=joy;
	}
	
	return _numJoys;
}

bool BBGlfwGame::PollJoystick( int port,Array<Float> joyx,Array<Float> joyy,Array<Float> joyz,Array<bool> buttons ){

	CountJoysticks( false );
	
	if( port<0 || port>=_numJoys ) return false;
	
	port=_joys[port];
	
	//read axes
	int n_axes=0;
	const float *axes=glfwGetJoystickAxes( port,&n_axes );
	if( !axes ) return false;
	
	//read buttons
	int n_buts=0;
	const unsigned char *buts=glfwGetJoystickButtons( port,&n_buts );
	if( !buts ) return false;

	//Ugh...
	const int *dev_axes;
	const int *dev_buttons;
	
#if _WIN32
	
	//xbox 360 controller
	const int xbox360_axes[]={0,0x41,2,4,0x43,0x42,999};
	const int xbox360_buttons[]={0,1,2,3,4,5,6,7,13,10,11,12,8,9,999};
	
	//logitech dual action
	const int logitech_axes[]={0,1,0x86,2,0x43,0x87,999};
	const int logitech_buttons[]={1,2,0,3,4,5,8,9,15,12,13,14,10,11,999};
	
	if( n_axes==5 && n_buts==14 ){
		dev_axes=xbox360_axes;
		dev_buttons=xbox360_buttons;
	}else{
		dev_axes=logitech_axes;
		dev_buttons=logitech_buttons;
	}
	
#else

	//xbox 360 controller
	const int xbox360_axes[]={0,0x41,0x14,2,0x43,0x15,999};
	const int xbox360_buttons[]={11,12,13,14,8,9,5,4,2,0,3,1,6,7,10,999};

	//ps3 controller
	const int ps3_axes[]={0,0x41,0x88,2,0x43,0x89,999};
	const int ps3_buttons[]={14,13,15,12,10,11,0,3,7,4,5,6,1,2,16,999};

	//logitech dual action
	const int logitech_axes[]={0,0x41,0x86,2,0x43,0x87,999};
	const int logitech_buttons[]={1,2,0,3,4,5,8,9,15,12,13,14,10,11,999};

	if( n_axes==6 && n_buts==15 ){
		dev_axes=xbox360_axes;
		dev_buttons=xbox360_buttons;
	}else if( n_axes==4 && n_buts==19 ){
		dev_axes=ps3_axes;
		dev_buttons=ps3_buttons;
	}else{
		dev_axes=logitech_axes;
		dev_buttons=logitech_buttons;
	}

#endif

	const int *p=dev_axes;
	
	float joys[6]={0,0,0,0,0,0};
	
	for( int i=0;i<6 && p[i]!=999;++i ){
		int j=p[i]&0xf,k=p[i]&~0xf;
		if( k==0x10 ){
			joys[i]=(axes[j]+1)/2;
		}else if( k==0x20 ){
			joys[i]=(1-axes[j])/2;
		}else if( k==0x40 ){
			joys[i]=-axes[j];
		}else if( k==0x80 ){
			joys[i]=(buts[j]==GLFW_PRESS);
		}else{
			joys[i]=axes[j];
		}
	}
	
	joyx[0]=joys[0];joyy[0]=joys[1];joyz[0]=joys[2];
	joyx[1]=joys[3];joyy[1]=joys[4];joyz[1]=joys[5];
	
	p=dev_buttons;
	
	for( int i=0;i<32;++i ) buttons[i]=false;
	
	for( int i=0;i<32 && p[i]!=999;++i ){
		int j=p[i];
		if( j<0 ) j+=n_buts;
		buttons[i]=(buts[j]==GLFW_PRESS);
	}

	return true;
}

void BBGlfwGame::OpenUrl( String url ){
#if _WIN32
	ShellExecute( HWND_DESKTOP,"open",url.ToCString<char>(),0,0,SW_SHOWNORMAL );
#elif __APPLE__
	if( CFURLRef cfurl=CFURLCreateWithBytes( 0,url.ToCString<UInt8>(),url.Length(),kCFStringEncodingASCII,0 ) ){
		LSOpenCFURLRef( cfurl,0 );
		CFRelease( cfurl );
	}
#elif __linux
	system( ( String( "xdg-open \"" )+url+"\"" ).ToCString<char>() );
#endif
}

void BBGlfwGame::SetMouseVisible( bool visible ){
	if( visible ){
		glfwSetInputMode( _window,GLFW_CURSOR,GLFW_CURSOR_NORMAL );
	}else{
		glfwSetInputMode( _window,GLFW_CURSOR,GLFW_CURSOR_HIDDEN );
	}
}

String BBGlfwGame::PathToFilePath( String path ){

	if( !_baseDir.Length() ){
	
		String appPath;

#if _WIN32
		WCHAR buf[MAX_PATH+1];
		GetModuleFileNameW( GetModuleHandleW(0),buf,MAX_PATH );
		buf[MAX_PATH]=0;appPath=String( buf ).Replace( "\\","/" );

#elif __APPLE__

		char buf[PATH_MAX+1];
		uint32_t size=sizeof( buf );
		_NSGetExecutablePath( buf,&size );
		buf[PATH_MAX]=0;appPath=String( buf ).Replace( "/./","/" );
	
#elif __linux
		char lnk[PATH_MAX+1],buf[PATH_MAX];
		sprintf( lnk,"/proc/%i/exe",getpid() );
		int n=readlink( lnk,buf,PATH_MAX );
		if( n<0 || n>=PATH_MAX ) abort();
		appPath=String( buf,n );

#endif
		int i=appPath.FindLast( "/" );if( i==-1 ) abort();
		_baseDir=appPath.Slice( 0,i );
		
#if __APPLE__
		if( _baseDir.EndsWith( ".app/Contents/MacOS" ) ) _baseDir=_baseDir.Slice( 0,-5 )+"Resources";
#endif
//		bbPrint( String( "_baseDir=" )+_baseDir );
	}
	
	if( !path.StartsWith( "cerberus:" ) ){
		return path;
	}else if( path.StartsWith( "cerberus://data/" ) ){
		return _baseDir+"/data/"+path.Slice( 16 );
	}else if( path.StartsWith( "cerberus://internal/" ) ){
		if( !_internalDir.Length() ){
#ifdef CFG_GLFW_APP_LABEL

#if _WIN32
			_internalDir=String( getenv( "APPDATA" ) );
#elif __APPLE__
			_internalDir=String( getenv( "HOME" ) )+"/Library/Application Support";
#elif __linux
			_internalDir=String( getenv( "HOME" ) )+"/.config";
			mkdir( _internalDir.ToCString<char>(),0777 );
#endif

#ifdef CFG_GLFW_APP_PUBLISHER
			_internalDir=_internalDir+"/"+_STRINGIZE( CFG_GLFW_APP_PUBLISHER );
#if _WIN32
			_wmkdir( _internalDir.ToCString<wchar_t>() );
#else
			mkdir( _internalDir.ToCString<char>(),0777 );
#endif
#endif

			_internalDir=_internalDir+"/"+_STRINGIZE( CFG_GLFW_APP_LABEL );
#if _WIN32
			_wmkdir( _internalDir.ToCString<wchar_t>() );
#else
			mkdir( _internalDir.ToCString<char>(),0777 );
#endif

#else
			_internalDir=_baseDir+"/internal";
#endif			
//			bbPrint( String( "_internalDir=" )+_internalDir );
		}
		return _internalDir+"/"+path.Slice( 20 );
	}else if( path.StartsWith( "cerberus://external/" ) ){
		return _baseDir+"/external/"+path.Slice( 20 );
	}
	return "";
}

unsigned char *BBGlfwGame::LoadImageData( String path,int *width,int *height,int *depth ){

	FILE *f=OpenFile( path,"rb" );
	if( !f ) return 0;
	
	unsigned char *data=stbi_load_from_file( f,width,height,depth,0 );
	fclose( f );
	
	if( data ) gc_ext_malloced( (*width)*(*height)*(*depth) );
	
	return data;
}

unsigned char *BBGlfwGame::LoadAudioData( String path,int *length,int *channels,int *format,int *hertz ){

	FILE *f=OpenFile( path,"rb" );
	if( !f ) return 0;
	
	unsigned char *data=0;
	
	if( path.ToLower().EndsWith( ".wav" ) ){
		data=LoadWAV( f,length,channels,format,hertz );
	}else if( path.ToLower().EndsWith( ".ogg" ) ){
		data=LoadOGG( f,length,channels,format,hertz );
	}
	fclose( f );
	
	if( data ) gc_ext_malloced( (*length)*(*channels)*(*format) );
	
	return data;
}

//glfw key to cerberus key!
int BBGlfwGame::TransKey( int key ){

	if( key>='0' && key<='9' ) return key;
	if( key>='A' && key<='Z' ) return key;

	switch( key ){
	case ' ':return VKEY_SPACE;
	case ';':return VKEY_SEMICOLON;
	case '=':return VKEY_EQUALS;
	case ',':return VKEY_COMMA;
	case '-':return VKEY_MINUS;
	case '.':return VKEY_PERIOD;
	case '/':return VKEY_SLASH;
	case '~':return VKEY_TILDE;
	case '[':return VKEY_OPENBRACKET;
	case ']':return VKEY_CLOSEBRACKET;
	case '\"':return VKEY_QUOTES;
	case '\\':return VKEY_BACKSLASH;
	
	case '`':return VKEY_TILDE;
	case '\'':return VKEY_QUOTES;

	case GLFW_KEY_LEFT_SHIFT:
	case GLFW_KEY_RIGHT_SHIFT:return VKEY_SHIFT;
	case GLFW_KEY_LEFT_CONTROL:
	case GLFW_KEY_RIGHT_CONTROL:return VKEY_CONTROL;
	
//	case GLFW_KEY_LEFT_SHIFT:return VKEY_LEFT_SHIFT;
//	case GLFW_KEY_RIGHT_SHIFT:return VKEY_RIGHT_SHIFT;
//	case GLFW_KEY_LCTRL:return VKEY_LCONTROL;
//	case GLFW_KEY_RCTRL:return VKEY_RCONTROL;
	
	case GLFW_KEY_BACKSPACE:return VKEY_BACKSPACE;
	case GLFW_KEY_TAB:return VKEY_TAB;
	case GLFW_KEY_ENTER:return VKEY_ENTER;
	case GLFW_KEY_ESCAPE:return VKEY_ESCAPE;
	case GLFW_KEY_INSERT:return VKEY_INSERT;
	case GLFW_KEY_DELETE:return VKEY_DELETE;
	case GLFW_KEY_PAGE_UP:return VKEY_PAGE_UP;
	case GLFW_KEY_PAGE_DOWN:return VKEY_PAGE_DOWN;
	case GLFW_KEY_HOME:return VKEY_HOME;
	case GLFW_KEY_END:return VKEY_END;
	case GLFW_KEY_UP:return VKEY_UP;
	case GLFW_KEY_DOWN:return VKEY_DOWN;
	case GLFW_KEY_LEFT:return VKEY_LEFT;
	case GLFW_KEY_RIGHT:return VKEY_RIGHT;
	
	case GLFW_KEY_KP_0:return VKEY_NUM0;
	case GLFW_KEY_KP_1:return VKEY_NUM1;
	case GLFW_KEY_KP_2:return VKEY_NUM2;
	case GLFW_KEY_KP_3:return VKEY_NUM3;
	case GLFW_KEY_KP_4:return VKEY_NUM4;
	case GLFW_KEY_KP_5:return VKEY_NUM5;
	case GLFW_KEY_KP_6:return VKEY_NUM6;
	case GLFW_KEY_KP_7:return VKEY_NUM7;
	case GLFW_KEY_KP_8:return VKEY_NUM8;
	case GLFW_KEY_KP_9:return VKEY_NUM9;
	case GLFW_KEY_KP_DIVIDE:return VKEY_NUMDIVIDE;
	case GLFW_KEY_KP_MULTIPLY:return VKEY_NUMMULTIPLY;
	case GLFW_KEY_KP_SUBTRACT:return VKEY_NUMSUBTRACT;
	case GLFW_KEY_KP_ADD:return VKEY_NUMADD;
	case GLFW_KEY_KP_DECIMAL:return VKEY_NUMDECIMAL;
	
	case GLFW_KEY_F1:return VKEY_F1;
	case GLFW_KEY_F2:return VKEY_F2;
	case GLFW_KEY_F3:return VKEY_F3;
	case GLFW_KEY_F4:return VKEY_F4;
	case GLFW_KEY_F5:return VKEY_F5;
	case GLFW_KEY_F6:return VKEY_F6;
	case GLFW_KEY_F7:return VKEY_F7;
	case GLFW_KEY_F8:return VKEY_F8;
	case GLFW_KEY_F9:return VKEY_F9;
	case GLFW_KEY_F10:return VKEY_F10;
	case GLFW_KEY_F11:return VKEY_F11;
	case GLFW_KEY_F12:return VKEY_F12;
	}
	return 0;
}

//cerberus key to special cerberus char
int BBGlfwGame::KeyToChar( int key ){
	switch( key ){
	case VKEY_BACKSPACE:
	case VKEY_TAB:
	case VKEY_ENTER:
	case VKEY_ESCAPE:
		return key;
	case VKEY_PAGE_UP:
	case VKEY_PAGE_DOWN:
	case VKEY_END:
	case VKEY_HOME:
	case VKEY_LEFT:
	case VKEY_UP:
	case VKEY_RIGHT:
	case VKEY_DOWN:
	case VKEY_INSERT:
		return key | 0x10000;
	case VKEY_DELETE:
		return 127;
	}
	return 0;
}

void BBGlfwGame::OnKey( GLFWwindow *window,int key,int scancode,int action,int mods ){

	key=TransKey( key );
	if( !key ) return;
	
	switch( action ){
	case GLFW_PRESS:
	case GLFW_REPEAT:
		_glfwGame->KeyEvent( BBGameEvent::KeyDown,key );
		if( int chr=KeyToChar( key ) ) _glfwGame->KeyEvent( BBGameEvent::KeyChar,chr );
		break;
	case GLFW_RELEASE:
		_glfwGame->KeyEvent( BBGameEvent::KeyUp,key );
		break;
	}
}

void BBGlfwGame::OnChar( GLFWwindow *window,unsigned int chr ){

	_glfwGame->KeyEvent( BBGameEvent::KeyChar,chr );
}

void BBGlfwGame::OnMouseButton( GLFWwindow *window,int button,int action,int mods ){
	switch( button ){
	case GLFW_MOUSE_BUTTON_LEFT:button=0;break;
	case GLFW_MOUSE_BUTTON_RIGHT:button=1;break;
	case GLFW_MOUSE_BUTTON_MIDDLE:button=2;break;
	default:return;
	}
	double x=0,y=0;
	glfwGetCursorPos( window,&x,&y );
	switch( action ){
	case GLFW_PRESS:
		_glfwGame->MouseEvent( BBGameEvent::MouseDown,button,x,y,0.0 );
		break;
	case GLFW_RELEASE:
		_glfwGame->MouseEvent( BBGameEvent::MouseUp,button,x,y,0.0 );
		break;
	}
}

void BBGlfwGame::OnMouseWheel( GLFWwindow *window, double x, double z )
{
  _glfwGame->MouseEvent( BBGameEvent::MouseMove,-1,0.0,0.0,z );
}

void BBGlfwGame::OnCursorPos( GLFWwindow *window,double x,double y ){
	_glfwGame->MouseEvent( BBGameEvent::MouseMove,-1,x,y,0.0 );
}

void BBGlfwGame::OnWindowClose( GLFWwindow *window ){
	glfwSetWindowShouldClose( _glfwGame->_window,0 );
	_glfwGame->KeyEvent( BBGameEvent::KeyDown,0x1b0 );
	_glfwGame->KeyEvent( BBGameEvent::KeyUp,0x1b0 );
}

void BBGlfwGame::OnWindowSize( GLFWwindow *window,int width,int height ){

	_glfwGame->_width=width;
	_glfwGame->_height=height;
	
#if CFG_GLFW_WINDOW_RENDER_WHILE_RESIZING && !__linux
	_glfwGame->RenderGame();
	glfwSwapBuffers( _glfwGame->_window );
	_glfwGame->_nextUpdate=0;
#endif
}

void BBGlfwGame::SetDeviceWindow( int width,int height,int flags ){

	_focus=false;

	if( _window ){
		for( int i=0;i<=GLFW_KEY_LAST;++i ){
			int key=TransKey( i );
			if( key && glfwGetKey( _window,i )==GLFW_PRESS ) KeyEvent( BBGameEvent::KeyUp,key );
		}
		glfwDestroyWindow( _window );
		_window=0;
	}

	bool fullscreen=(flags & 1);
	bool resizable=(flags & 2);
	bool decorated=(flags & 4);
	bool floating=(flags & 8);
	bool depthbuffer=(flags & 16);
	bool doublebuffer=!(flags & 32);
	bool secondmonitor=(flags & 64);
	bool usestencil=(flags & 128);

	glfwWindowHint( GLFW_RED_BITS,8 );
	glfwWindowHint( GLFW_GREEN_BITS,8 );
	glfwWindowHint( GLFW_BLUE_BITS,8 );
	glfwWindowHint( GLFW_ALPHA_BITS,8 );
	glfwWindowHint( GLFW_DEPTH_BITS,depthbuffer ? 32 : 0 );
	glfwWindowHint( GLFW_STENCIL_BITS,usestencil ? 8 : 0 );
	glfwWindowHint( GLFW_RESIZABLE,resizable );
	glfwWindowHint( GLFW_DECORATED,decorated );
	glfwWindowHint( GLFW_FLOATING,floating );
	glfwWindowHint( GLFW_VISIBLE,fullscreen );
	glfwWindowHint( GLFW_DOUBLEBUFFER,doublebuffer );
	glfwWindowHint( GLFW_SAMPLES,CFG_GLFW_WINDOW_SAMPLES );
	glfwWindowHint( GLFW_REFRESH_RATE,60 );
	
	GLFWmonitor *monitor=0;
	if( fullscreen ){
		int monitorid=secondmonitor ? 1 : 0;
		int count=0;
		GLFWmonitor **monitors=glfwGetMonitors( &count );
		if( monitorid>=count ) monitorid=count-1;
		monitor=monitors[monitorid];
	}
	
	_window=glfwCreateWindow( width,height,_STRINGIZE(CFG_GLFW_WINDOW_TITLE),monitor,0 );
	if( !_window ){
		bbPrint( "glfwCreateWindow FAILED!" );
		abort();
	}
	
	_width=width;
	_height=height;
	
	++glfwGraphicsSeq;

	if( !fullscreen ){	
		glfwSetWindowPos( _window,(_desktopMode.width-width)/2,(_desktopMode.height-height)/2 );
		glfwShowWindow( _window );
	}
	
	glfwMakeContextCurrent( _window );
	
	if( _swapInterval>=0 ) glfwSwapInterval( _swapInterval );

#if CFG_OPENGL_INIT_EXTENSIONS
	Init_GL_Exts();
#endif

	glfwSetKeyCallback( _window,OnKey );
	glfwSetCharCallback( _window,OnChar );
	glfwSetMouseButtonCallback( _window,OnMouseButton );
  glfwSetScrollCallback( _window, OnMouseWheel ); 
	glfwSetCursorPosCallback( _window,OnCursorPos );
	glfwSetWindowCloseCallback(	_window,OnWindowClose );
	glfwSetWindowSizeCallback(_window,OnWindowSize );
}

void BBGlfwGame::SetSwapInterval( int interval ){

	_swapInterval=interval;
	
	if( _swapInterval>=0 && _window ) glfwSwapInterval( _swapInterval );
}

Array<BBDisplayMode*> BBGlfwGame::GetDisplayModes(){
	int count=0;
	const GLFWvidmode *vmodes=glfwGetVideoModes( glfwGetPrimaryMonitor(),&count );
	Array<BBDisplayMode*> modes( count );
	int n=0;
	for( int i=0;i<count;++i ){
		const GLFWvidmode *vmode=&vmodes[i];
		if( vmode->refreshRate && vmode->refreshRate!=60 ) continue;
		modes[n++]=new BBDisplayMode( vmode->width,vmode->height );
	}
	return modes.Slice(0,n);
}

BBDisplayMode *BBGlfwGame::GetDesktopMode(){ 
	return new BBDisplayMode( _desktopMode.width,_desktopMode.height ); 
}

double BBGlfwGame::GetTime(){
	return glfwGetTime();
}

void BBGlfwGame::Sleep( double time ){
#if _WIN32
	WaitForSingleObject( GetCurrentThread(),(DWORD)( time*1000.0 ) );
#else
	timespec ts,rem;
	ts.tv_sec=floor(time);
	ts.tv_nsec=(time-floor(time))*1000000000.0;
	while( nanosleep( &ts,&rem )==EINTR ){
		ts=rem;
	}
#endif
}

void BBGlfwGame::UpdateEvents(){

	if( _suspended ){
		glfwWaitEvents();
	}else{
		glfwPollEvents();
	}
	if( glfwGetWindowAttrib( _window,GLFW_FOCUSED ) ){
		_focus=true;
		if( _suspended ){
			ResumeGame();
			_nextUpdate=0;
		}
	}else if( !glfwGetWindowAttrib( _window,GLFW_FOCUSED ) && CFG_MOJO_AUTO_SUSPEND_ENABLED ){
		if( _focus && !_suspended ){
			SuspendGame();
			_nextUpdate=0;
		}
	}
}

void BBGlfwGame::Run(){

#if	CFG_GLFW_WINDOW_WIDTH && CFG_GLFW_WINDOW_HEIGHT

	int flags=0;
#if CFG_GLFW_WINDOW_FULLSCREEN
	flags|=1;
#endif
#if CFG_GLFW_WINDOW_RESIZABLE
	flags|=2;
#endif
#if CFG_GLFW_WINDOW_DECORATED
	flags|=4;
#endif
#if CFG_GLFW_WINDOW_FLOATING
	flags|=8;
#endif
#if CFG_OPENGL_DEPTH_BUFFER_ENABLED
	flags|=16;
#endif

	SetDeviceWindow( CFG_GLFW_WINDOW_WIDTH,CFG_GLFW_WINDOW_HEIGHT,flags );

#endif

	StartGame();
	
	while( !glfwWindowShouldClose( _window ) ){
	
		RenderGame();
		
		glfwSwapBuffers( _window );
		
		//Wait for next update
		if( _nextUpdate ){
			double delay=_nextUpdate-GetTime();
			if( delay>0 ) Sleep( delay );
		}
		
		//Update user events
		UpdateEvents();

		//App suspended?		
		if( _suspended ){
			continue;
		}

		//'Go nuts' mode!
		if( !_updateRate ){
			UpdateGame();
			continue;
		}
		
		//Reset update timer?
		if( !_nextUpdate ){
			_nextUpdate=GetTime();
		}
		
		//Catch up updates...
		int i=0;
		for( ;i<4;++i ){
		
			UpdateGame();
			if( !_nextUpdate ) break;
			
			_nextUpdate+=_updatePeriod;
			
			if( _nextUpdate>GetTime() ) break;
		}
		
		if( i==4 ) _nextUpdate=0;
	}
}



//***** cerberusgame.h *****

class BBCerberusGame : public BBGlfwGame{
public:
	static void Main( int args,const char *argv[] );
};

//***** cerberusgame.cpp *****

#define _QUOTE(X) #X
#define _STRINGIZE(X) _QUOTE(X)

static void onGlfwError( int err,const char *msg ){
	printf( "GLFW Error: err=%i, msg=%s\n",err,msg );
	fflush( stdout );
}

void BBCerberusGame::Main( int argc,const char *argv[] ){

	glfwSetErrorCallback( onGlfwError );
	
	if( !glfwInit() ){
		puts( "glfwInit failed" );
		exit( -1 );
	}

	BBCerberusGame *game=new BBCerberusGame();
	
	try{
	
		bb_std_main( argc,argv );
		
	}catch( ThrowableObject *ex ){
	
		glfwTerminate();
		
		game->Die( ex );
		
		return;
	}

	if( game->Delegate() ) game->Run();
	
	glfwTerminate();
}


// ***** thread.h *****

#if __cplusplus_winrt

using namespace Windows::System::Threading;

#endif

class BBThread : public Object{
public:
	Object *result;
	
	BBThread();
	
	virtual void Start();
	virtual bool IsRunning();
	
	virtual Object *Result();
	virtual void SetResult( Object *result );
	
	static  String Strdup( const String &str );
	
	virtual void Run__UNSAFE__();
	
	
private:

	enum{
		INIT=0,
		RUNNING=1,
		FINISHED=2
	};

	
	int _state;
	Object *_result;
	
#if __cplusplus_winrt

	friend class Launcher;

	class Launcher{
	
		friend class BBThread;
		BBThread *_thread;
		
		Launcher( BBThread *thread ):_thread(thread){
		}
		
		public:
		
		void operator()( IAsyncAction ^operation ){
			_thread->Run__UNSAFE__();
			_thread->_state=FINISHED;
		} 
	};
	
#elif _WIN32

	static DWORD WINAPI run( void *p );
	
#else

	static void *run( void *p );
	
#endif

};

// ***** thread.cpp *****

BBThread::BBThread():_state( INIT ),_result( 0 ){
}

bool BBThread::IsRunning(){
	return _state==RUNNING;
}

Object *BBThread::Result(){
	return _result;
}

void BBThread::SetResult( Object *result ){
	_result=result;
}

String BBThread::Strdup( const String &str ){
	return str.Copy();
}

void BBThread::Run__UNSAFE__(){
}

#if __cplusplus_winrt

void BBThread::Start(){
	if( _state==RUNNING ) return;
	
	_result=0;
	_state=RUNNING;
	
	Launcher launcher( this );
	
	auto handler=ref new WorkItemHandler( launcher );
	
	ThreadPool::RunAsync( handler );
}

#elif _WIN32

void BBThread::Start(){
	if( _state==RUNNING ) return;
	
	_result=0;
	_state=RUNNING;
	
	DWORD _id;
	HANDLE _handle;

	if( _handle=CreateThread( 0,0,run,this,0,&_id ) ){
		CloseHandle( _handle );
		return;
	}
	
	puts( "CreateThread failed!" );
	exit( -1 );
}

DWORD WINAPI BBThread::run( void *p ){
	BBThread *thread=(BBThread*)p;

	thread->Run__UNSAFE__();
	
	thread->_state=FINISHED;
	return 0;
}

#else

void BBThread::Start(){
	if( _state==RUNNING ) return;
	
	_result=0;
	_state=RUNNING;
	
	pthread_t _handle;
	
	if( !pthread_create( &_handle,0,run,this ) ){
		pthread_detach( _handle );
		return;
	}
	
	puts( "pthread_create failed!" );
	exit( -1 );
}

void *BBThread::run( void *p ){
	BBThread *thread=(BBThread*)p;

	thread->Run__UNSAFE__();

	thread->_state=FINISHED;
	return 0;
}

#endif


// ***** databuffer.h *****

class BBDataBuffer : public Object{
public:
	
	BBDataBuffer();
	
	~BBDataBuffer();
	
	bool _New( int length,void *data=0 );
	
	bool _Load( String path );
	
	void _LoadAsync( const String &path,BBThread *thread );

	void Discard();
	
	const void *ReadPointer( int offset=0 ){
		return _data+offset;
	}
	
	void *WritePointer( int offset=0 ){
		return _data+offset;
	}
	
	int Length(){
		return _length;
	}
	
	void PokeByte( int addr,int value ){
		*(_data+addr)=value;
	}

	void PokeShort( int addr,int value ){
		*(short*)(_data+addr)=value;
	}
	
	void PokeInt( int addr,int value ){
		*(int*)(_data+addr)=value;
	}
	
	void PokeFloat( int addr,float value ){
		*(float*)(_data+addr)=value;
	}

	int PeekByte( int addr ){
		return *(_data+addr);
	}
	
	int PeekShort( int addr ){
		return *(short*)(_data+addr);
	}
	
	int PeekInt( int addr ){
		return *(int*)(_data+addr);
	}
	
	float PeekFloat( int addr ){
		return *(float*)(_data+addr);
	}
	
private:
	signed char *_data;
	int _length;
};

// ***** databuffer.cpp *****

BBDataBuffer::BBDataBuffer():_data(0),_length(0){
}

BBDataBuffer::~BBDataBuffer(){
	if( _data ) free( _data );
}

bool BBDataBuffer::_New( int length,void *data ){
	if( _data ) return false;
	if( !data ) data=malloc( length );
	_data=(signed char*)data;
	_length=length;
	return true;
}

bool BBDataBuffer::_Load( String path ){
	if( _data ) return false;
	
	_data=(signed char*)BBGame::Game()->LoadData( path,&_length );
	if( !_data ) return false;
	
	return true;
}

void BBDataBuffer::_LoadAsync( const String &cpath,BBThread *thread ){

	String path=cpath.Copy();
	
	if( _Load( path ) ) thread->SetResult( this );
}

void BBDataBuffer::Discard(){
	if( !_data ) return;
	free( _data );
	_data=0;
	_length=0;
}


// ***** stream.h *****

class BBStream : public Object{
public:

	virtual int Eof(){
		return 0;
	}

	virtual void Close(){
	}

	virtual int Length(){
		return 0;
	}
	
	virtual int Position(){
		return 0;
	}
	
	virtual int Seek( int position ){
		return 0;
	}
	
	virtual int Read( BBDataBuffer *buffer,int offset,int count ){
		return 0;
	}

	virtual int Write( BBDataBuffer *buffer,int offset,int count ){
		return 0;
	}
};

// ***** stream.cpp *****


// ***** filestream.h *****

class BBFileStream : public BBStream{
public:

	BBFileStream();
	~BBFileStream();

	void Close();
	int Eof();
	int Length();
	int Position();
	int Seek( int position );
	int Read( BBDataBuffer *buffer,int offset,int count );
	int Write( BBDataBuffer *buffer,int offset,int count );

	bool Open( String path,String mode );
	
private:
	FILE *_file;
	int _position;
	int _length;
};

// ***** filestream.cpp *****

BBFileStream::BBFileStream():_file(0),_position(0),_length(0){
}

BBFileStream::~BBFileStream(){
	if( _file ) fclose( _file );
}

bool BBFileStream::Open( String path,String mode ){
	if( _file ) return false;

	String fmode;	
	if( mode=="r" ){
		fmode="rb";
	}else if( mode=="w" ){
		fmode="wb";
	}else if( mode=="u" ){
		fmode="rb+";
	}else{
		return false;
	}

	_file=BBGame::Game()->OpenFile( path,fmode );
	if( !_file && mode=="u" ) _file=BBGame::Game()->OpenFile( path,"wb+" );
	if( !_file ) return false;
	
	fseek( _file,0,SEEK_END );
	_length=ftell( _file );
	fseek( _file,0,SEEK_SET );
	_position=0;
	
	return true;
}

void BBFileStream::Close(){
	if( !_file ) return;
	
	fclose( _file );
	_file=0;
	_position=0;
	_length=0;
}

int BBFileStream::Eof(){
	if( !_file ) return -1;
	
	return _position==_length;
}

int BBFileStream::Length(){
	return _length;
}

int BBFileStream::Position(){
	return _position;
}

int BBFileStream::Seek( int position ){
	if( !_file ) return 0;
	
	fseek( _file,position,SEEK_SET );
	_position=ftell( _file );
	return _position;
}

int BBFileStream::Read( BBDataBuffer *buffer,int offset,int count ){
	if( !_file ) return 0;
	
	int n=fread( buffer->WritePointer(offset),1,count,_file );
	_position+=n;
	return n;
}

int BBFileStream::Write( BBDataBuffer *buffer,int offset,int count ){
	if( !_file ) return 0;
	
	int n=fwrite( buffer->ReadPointer(offset),1,count,_file );
	_position+=n;
	if( _position>_length ) _length=_position;
	return n;
}


#if _WIN32

#define _usew 1

static HWND focHwnd;

static void beginPanel(){
	focHwnd=GetFocus();
}

static void endPanel(){
	SetFocus( focHwnd );
}

static int panel( String title,String text,int flags ){
	beginPanel();
	int n=MessageBoxW( GetActiveWindow(),text.ToCString<WCHAR>(),title.ToCString<WCHAR>(),flags );
	endPanel();
	return n;
}

static WCHAR *tmpWString( String str ){
	WCHAR *p=(WCHAR*)malloc( str.Length()*2+2 );
	memcpy( p,str.Data(),str.Length()*2 );
	p[str.Length()]=0;
	return p;
}

void bbNotify( String title,String text,int serious ){
	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_OK|MB_APPLMODAL|MB_TOPMOST;
	panel( title,text,flags );
}

int bbConfirm( String title,String text,int serious ){
	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_OKCANCEL|MB_APPLMODAL|MB_TOPMOST;
	int n=panel( title,text,flags );
	if( n==IDOK ) return 1;
	return 0;
}

int bbProceed( String title,String text,int serious ){
	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_YESNOCANCEL|MB_APPLMODAL|MB_TOPMOST;
	int n=panel( title,text,flags );
	if( n==IDYES ) return 1;
	if( n==IDNO ) return 0;
	return -1;
}

int bbRequestColor( void ){
	CHOOSECOLOR cc; // common dialog box structure
	static COLORREF acrCustClr[16]; // array of custom colors
	HWND hwnd; // owner window
	HBRUSH hbrush; // brush handle
	static DWORD rgbCurrent; // initial color selection
	// Initialize CHOOSECOLOR
	ZeroMemory(&cc, sizeof(CHOOSECOLOR));
	cc.lStructSize = sizeof(CHOOSECOLOR);
	cc.hwndOwner = GetActiveWindow();
	cc.lpCustColors = (LPDWORD) acrCustClr;
	cc.rgbResult = rgbCurrent;
	cc.Flags = CC_FULLOPEN | CC_RGBINIT;
	if (ChooseColor(&cc)==TRUE) {
		//hbrush = CreateSolidBrush(cc.rgbResult);
		rgbCurrent = cc.rgbResult;
		return rgbCurrent;
	}
	return -1;
}

String bbRequestFile( String title,String exts,int save,String path ){

	String file,dir;
	path=path.Replace( "/","\\" );
		
	int i=path.FindLast( "\\" );
	if( i!=-1 ){
		dir=path.Slice( 0,i );
		file=path.Slice( i+1 );
	}else{
		file=path;
	}

	if( file.Length()>MAX_PATH ) return "";
	
	if( exts.Length() ){
		if( exts.Find( ":" )==-1 ){
			exts=String( "Files\0*." )+exts;
		}else{
			exts=exts.Replace( ":",String( "\0*.",3 ) );
		}
		exts=exts.Replace( ";",String( "\0",1 ) );
		exts=exts.Replace( ",",";*." )+String( "\0",1 );
	}

	WCHAR buf[MAX_PATH+1],*p;
	memcpy( buf,file.Data(),file.Length()*2 );
	buf[file.Length()]=0;

	OPENFILENAMEW of={sizeof(of)};
	
	of.hwndOwner=GetActiveWindow();
	of.lpstrTitle=tmpWString( title );
	of.lpstrFilter=tmpWString( exts );
	of.lpstrFile=buf;
	of.lpstrInitialDir=dir.Length() ? tmpWString( dir ) : 0;
	of.nMaxFile=MAX_PATH;
	of.Flags=OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
		
	beginPanel();
	
	String str;
	
	if( save ){
		of.lpstrDefExt=L"";
		of.Flags|=OFN_OVERWRITEPROMPT;
		if( GetSaveFileNameW( &of ) ){
			str=String( buf );
		}
	}else{
		of.Flags|=OFN_FILEMUSTEXIST;
		if( GetOpenFileNameW( &of ) ){
			str=String( buf );
		}
	}
	
	endPanel();
	
	free( (void*)of.lpstrTitle );
	free( (void*)of.lpstrFilter );
	free( (void*)of.lpstrInitialDir );
	
	return str;
}

static int CALLBACK BrowseForFolderCallbackW( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
	wchar_t szPath[MAX_PATH];
	switch( uMsg ){
	case BFFM_INITIALIZED:
		SendMessageW( hwnd,BFFM_SETSELECTIONW,TRUE,pData );
		break;
	case BFFM_SELCHANGED: 
		if( SHGetPathFromIDListW( (LPITEMIDLIST)lp,szPath ) ){
			SendMessageW( hwnd,BFFM_SETSTATUSTEXTW,0,(LPARAM)szPath );
		}
		break;
	}
	return 0;
}

static int CALLBACK BrowseForFolderCallbackA( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
	char szPath[MAX_PATH];
	switch( uMsg ){
	case BFFM_INITIALIZED:
		SendMessageA( hwnd,BFFM_SETSELECTIONA,TRUE,pData );
		break;
	case BFFM_SELCHANGED: 
		if( SHGetPathFromIDListA( (LPITEMIDLIST)lp,szPath ) ){
			SendMessageA( hwnd,BFFM_SETSTATUSTEXTA,0,(LPARAM)szPath );
		}
		break;
	}
	return 0;
}

String bbRequestDir( String title,String dir ){

	dir=dir.Replace( "/","\\" );

	LPMALLOC shm;
	BROWSEINFOW bi={0};
	
	WCHAR buf[MAX_PATH],*p;
	GetFullPathNameW( dir.ToCString<WCHAR>(),MAX_PATH,buf,&p );
	
	bi.hwndOwner=GetActiveWindow();
	bi.lpszTitle=tmpWString( title );
	bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE;
	bi.lpfn=BrowseForFolderCallbackW;
	bi.lParam=(LPARAM)buf;
	
	beginPanel();

	String str;	
	if( ITEMIDLIST *idlist=SHBrowseForFolderW( &bi ) ){
		SHGetPathFromIDListW( idlist,buf );
		str=String( buf );
		//SHFree( idlist );	//?!?
	}
	
	endPanel();
	
	free( (void*)bi.lpszTitle );

	return str;
}

#elif __APPLE__ && __OBJC__

typedef int (*AlertPanel)( 
	NSString *title,
	NSString *msg,
	NSString *defaultButton,
	NSString *alternateButton,
	NSString *otherButton );

static NSWindow *keyWin;

static void beginPanel(){
	keyWin=[NSApp keyWindow];
	if( !keyWin ) [NSApp activateIgnoringOtherApps:YES];
}

static void endPanel(){
	if( keyWin ) [keyWin makeKeyWindow];
}

void bbNotify( String title,String text,int serious ){

	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
	
	beginPanel();
	
	panel( title.ToNSString(),text.ToNSString(),@"OK",0,0 );
	
	endPanel();
}

int bbConfirm( String title,String text,int serious ){

	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
	
	beginPanel();
	
	int n=panel( title.ToNSString(),text.ToNSString(),@"OK",@"Cancel",0 );

	endPanel();
	
	switch( n ){
	case NSAlertDefaultReturn:return 1;
	}
	return 0;
}

int bbProceed( String title,String text,int serious ){

	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
	
	beginPanel();
	
	int n=panel( title.ToNSString(),text.ToNSString(),@"Yes",@"No",@"Cancel" );
	
	endPanel();
	
	switch( n ){
	case NSAlertDefaultReturn:return 1;
	case NSAlertAlternateReturn:return 0;
	}
	return -1;
}

String bbRequestFile( String title,String filter,int save,String path ){

	String file,dir;
	int i=path.FindLast( "\\" );
	if( i!=-1 ){
		dir=path.Slice( 0,i );
		file=path.Slice( 1+1 );
	}else{
		file=path;
	}
	
	NSMutableArray *nsfilter=0;
	bool allowOthers=true;

	if( filter.Length() ){
	
		allowOthers=false;
	
		nsfilter=[NSMutableArray arrayWithCapacity:10];
		
		int i0=0;
		while( i0<filter.Length() ){
		
			int i1=filter.Find( ":",i0 )+1;
			if( !i1 ) break;
			
			int i2=filter.Find( ";",i1 );
			if( i2==-1 ) i2=filter.Length();
			
			while( i1<i2 ){
			
				int i3=filter.Find( ",",i1 );
				if( i3==-1 ) i3=i2;
				
				String ext=filter.Slice( i1,i3 );
				if( ext=="*" ){
					allowOthers=true;
				}else{
					[nsfilter addObject:ext.ToNSString()];
				}
				i1=i3+1;
			}
			i0=i2+1;
		}
	}

	NSString *nsdir=0;
	NSString *nsfile=0;
	NSString *nstitle=0;
	NSMutableArray *nsexts=0;

	if( dir.Length() ) nsdir=dir.ToNSString();
	if( file.Length() ) nsfile=file.ToNSString();
	if( title.Length() ) nstitle=title.ToNSString();

	beginPanel();
	
	String str;

	if( save ){
		NSSavePanel *panel=[NSSavePanel savePanel];
		
		if( nstitle ) [panel setTitle:nstitle];
		
		if( nsfilter ){
			[panel setAllowedFileTypes:nsfilter];
			[panel setAllowsOtherFileTypes:allowOthers];
		}
		
		if( [panel runModalForDirectory:nsdir file:nsfile]==NSFileHandlingPanelOKButton ){
			str=String( [panel filename] );
		}

	}else{
		NSOpenPanel *panel=[NSOpenPanel openPanel];

		if( nstitle ) [panel setTitle:nstitle];
		
		if( allowOthers ) nsfilter=0;
		
		if( [panel runModalForDirectory:nsdir file:nsfile types:nsfilter]==NSFileHandlingPanelOKButton ){
			str=String( [panel filename] );
		}
	}
	endPanel();

	return str;
}

String bbRequestDir( String title,String dir ){

	NSString *nsdir=0;
	NSString *nstitle=0;
	NSOpenPanel *panel;
	
	if( dir.Length() ) nsdir=dir.ToNSString();
	
	if( title.Length() ) nstitle=title.ToNSString();

	panel=[NSOpenPanel openPanel];
	
	[panel setCanChooseFiles:NO];
	[panel setCanChooseDirectories:YES];
	[panel setCanCreateDirectories:YES];
	
	if( nstitle ) [panel setTitle:nstitle];

	beginPanel();
	
	String str;
	
	if( [panel runModalForDirectory:nsdir file:0 types:0]==NSFileHandlingPanelOKButton ){
	
		str=String( [panel filename] );
	}

	endPanel();
	
	return str;
}

#endif


// GLFW mojo runtime.
//
// Copyright 2011 Mark Sibly, all rights reserved.
// No warranty implied; use at your own risk.

//***** gxtkGraphics.h *****

class gxtkSurface;

class gxtkGraphics : public Object{
public:

	enum{
		MAX_VERTS=1024,
		MAX_QUADS=(MAX_VERTS/4)
	};

	int width;
	int height;

	int colorARGB;
	float r,g,b,alpha;
	float ix,iy,jx,jy,tx,ty;
	bool tformed;

	float vertices[MAX_VERTS*5];
	unsigned short quadIndices[MAX_QUADS*6];

	int primType;
	int vertCount;
	gxtkSurface *primSurf;
	
	gxtkGraphics();
	
	void Flush();
	float *Begin( int type,int count,gxtkSurface *surf );
	
	//***** GXTK API *****
	virtual int Width();
	virtual int Height();
	
	virtual int  BeginRender();
	virtual void EndRender();
	virtual void DiscardGraphics();

	virtual gxtkSurface *LoadSurface( String path );
	virtual gxtkSurface *CreateSurface( int width,int height );
	virtual bool LoadSurface__UNSAFE__( gxtkSurface *surface,String path );
	
	virtual int Cls( float r,float g,float b );
	virtual int SetAlpha( float alpha );
	virtual int SetColor( float r,float g,float b );
	virtual int SetBlend( int blend );
	virtual int SetScissor( int x,int y,int w,int h );
	virtual int SetMatrix( float ix,float iy,float jx,float jy,float tx,float ty );
	
	virtual int DrawPoint( float x,float y );
	virtual int DrawRect( float x,float y,float w,float h );
	virtual int DrawLine( float x1,float y1,float x2,float y2 );
	virtual int DrawOval( float x1,float y1,float x2,float y2 );
	virtual int DrawPoly( Array<Float> verts );
	virtual int DrawPoly2( Array<Float> verts,gxtkSurface *surface,int srcx,int srcy );
	virtual int DrawSurface( gxtkSurface *surface,float x,float y );
	virtual int DrawSurface2( gxtkSurface *surface,float x,float y,int srcx,int srcy,int srcw,int srch );
	
	virtual int ReadPixels( Array<int> pixels,int x,int y,int width,int height,int offset,int pitch );
	virtual int WritePixels2( gxtkSurface *surface,Array<int> pixels,int x,int y,int width,int height,int offset,int pitch );
};

class gxtkSurface : public Object{
public:
	unsigned char *data;
	int width;
	int height;
	int depth;
	int format;
	int seq;
	
	GLuint texture;
	float uscale;
	float vscale;
	
	gxtkSurface();
	
	void SetData( unsigned char *data,int width,int height,int depth );
	void SetSubData( int x,int y,int w,int h,unsigned *src,int pitch );
	void Bind();
	
	~gxtkSurface();
	
	//***** GXTK API *****
	virtual int Discard();
	virtual int Width();
	virtual int Height();
	virtual int Loaded();
	virtual void OnUnsafeLoadComplete();
};

//***** gxtkGraphics.cpp *****

#ifndef GL_BGRA
#define GL_BGRA  0x80e1
#endif

#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812f
#endif

#ifndef GL_GENERATE_MIPMAP
#define GL_GENERATE_MIPMAP 0x8191
#endif

static int Pow2Size( int n ){
	int i=1;
	while( i<n ) i+=i;
	return i;
}

gxtkGraphics::gxtkGraphics(){

	width=height=0;
	vertCount=0;
	
#ifdef _glfw3_h_
	GLFWwindow *window=BBGlfwGame::GlfwGame()->GetGLFWwindow();
	if( window ) glfwGetWindowSize( BBGlfwGame::GlfwGame()->GetGLFWwindow(),&width,&height );
#else
	glfwGetWindowSize( &width,&height );
#endif
	
	if( CFG_OPENGL_GLES20_ENABLED ) return;
	
	for( int i=0;i<MAX_QUADS;++i ){
		quadIndices[i*6  ]=(short)(i*4);
		quadIndices[i*6+1]=(short)(i*4+1);
		quadIndices[i*6+2]=(short)(i*4+2);
		quadIndices[i*6+3]=(short)(i*4);
		quadIndices[i*6+4]=(short)(i*4+2);
		quadIndices[i*6+5]=(short)(i*4+3);
	}
}

void gxtkGraphics::Flush(){
	if( !vertCount ) return;

	if( primSurf ){
		glEnable( GL_TEXTURE_2D );
		primSurf->Bind();
	}
		
	switch( primType ){
	case 1:
		glDrawArrays( GL_POINTS,0,vertCount );
		break;
	case 2:
		glDrawArrays( GL_LINES,0,vertCount );
		break;
	case 3:
		glDrawArrays( GL_TRIANGLES,0,vertCount );
		break;
	case 4:
		glDrawElements( GL_TRIANGLES,vertCount/4*6,GL_UNSIGNED_SHORT,quadIndices );
		break;
	default:
		for( int j=0;j<vertCount;j+=primType ){
			glDrawArrays( GL_TRIANGLE_FAN,j,primType );
		}
		break;
	}

	if( primSurf ){
		glDisable( GL_TEXTURE_2D );
	}

	vertCount=0;
}

float *gxtkGraphics::Begin( int type,int count,gxtkSurface *surf ){
	if( primType!=type || primSurf!=surf || vertCount+count>MAX_VERTS ){
		Flush();
		primType=type;
		primSurf=surf;
	}
	float *vp=vertices+vertCount*5;
	vertCount+=count;
	return vp;
}

//***** GXTK API *****

int gxtkGraphics::Width(){
	return width;
}

int gxtkGraphics::Height(){
	return height;
}

int gxtkGraphics::BeginRender(){
	int newWidth = 0;
	int newHeight = 0;
	
	width=height=0;
#ifdef _glfw3_h_
	glfwGetWindowSize( BBGlfwGame::GlfwGame()->GetGLFWwindow(),&width,&height );
	glfwGetFramebufferSize( BBGlfwGame::GlfwGame()->GetGLFWwindow(),&newWidth, &newHeight );
#else
	glfwGetWindowSize( &width,&height );
#endif

#if CFG_OPENGL_GLES20_ENABLED
	return 0;
#else

	//glViewport( 0,0,width,height );
	glViewport( 0,0,newWidth,newHeight );

	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	glOrtho( 0,width,height,0,-1,1 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	
	glEnableClientState( GL_VERTEX_ARRAY );
	glVertexPointer( 2,GL_FLOAT,20,&vertices[0] );	
	
	glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	glTexCoordPointer( 2,GL_FLOAT,20,&vertices[2] );
	
	glEnableClientState( GL_COLOR_ARRAY );
	glColorPointer( 4,GL_UNSIGNED_BYTE,20,&vertices[4] );
	
	glEnable( GL_BLEND );
	glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA );
	
	glDisable( GL_TEXTURE_2D );
	
	vertCount=0;
	
	return 1;
	
#endif
}

void gxtkGraphics::EndRender(){
	if( !CFG_OPENGL_GLES20_ENABLED ) Flush();
}

void gxtkGraphics::DiscardGraphics(){
}

int gxtkGraphics::Cls( float r,float g,float b ){
	vertCount=0;

	glClearColor( r/255.0f,g/255.0f,b/255.0f,1 );
	glClear( GL_COLOR_BUFFER_BIT );

	return 0;
}

int gxtkGraphics::SetAlpha( float alpha ){
	this->alpha=alpha;
	
	int a=int(alpha*255);
	
	colorARGB=(a<<24) | (int(b*alpha)<<16) | (int(g*alpha)<<8) | int(r*alpha);
	
	return 0;
}

int gxtkGraphics::SetColor( float r,float g,float b ){
	this->r=r;
	this->g=g;
	this->b=b;

	int a=int(alpha*255);
	
	colorARGB=(a<<24) | (int(b*alpha)<<16) | (int(g*alpha)<<8) | int(r*alpha);
	
	return 0;
}

int gxtkGraphics::SetBlend( int blend ){

	Flush();
	
	switch( blend ){
	case 1:
		glBlendFunc( GL_ONE,GL_ONE );
		break;
	default:
		glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA );
	}

	return 0;
}

int gxtkGraphics::SetScissor( int x,int y,int w,int h ){

	Flush();
	
	if( x!=0 || y!=0 || w!=Width() || h!=Height() ){
		glEnable( GL_SCISSOR_TEST );
		y=Height()-y-h;
		glScissor( x,y,w,h );
	}else{
		glDisable( GL_SCISSOR_TEST );
	}
	return 0;
}

int gxtkGraphics::SetMatrix( float ix,float iy,float jx,float jy,float tx,float ty ){

	tformed=(ix!=1 || iy!=0 || jx!=0 || jy!=1 || tx!=0 || ty!=0);

	this->ix=ix;this->iy=iy;this->jx=jx;this->jy=jy;this->tx=tx;this->ty=ty;

	return 0;
}

int gxtkGraphics::DrawPoint( float x,float y ){

	if( tformed ){
		float px=x;
		x=px * ix + y * jx + tx;
		y=px * iy + y * jy + ty;
	}
	
	float *vp=Begin( 1,1,0 );
	
	vp[0]=x+.5f;vp[1]=y+.5f;(int&)vp[4]=colorARGB;

	return 0;	
}
	
int gxtkGraphics::DrawLine( float x0,float y0,float x1,float y1 ){

	if( tformed ){
		float tx0=x0,tx1=x1;
		x0=tx0 * ix + y0 * jx + tx;y0=tx0 * iy + y0 * jy + ty;
		x1=tx1 * ix + y1 * jx + tx;y1=tx1 * iy + y1 * jy + ty;
	}
	
	float *vp=Begin( 2,2,0 );

	vp[0]=x0+.5f;vp[1]=y0+.5f;(int&)vp[4]=colorARGB;
	vp[5]=x1+.5f;vp[6]=y1+.5f;(int&)vp[9]=colorARGB;
	
	return 0;
}

int gxtkGraphics::DrawRect( float x,float y,float w,float h ){

	float x0=x,x1=x+w,x2=x+w,x3=x;
	float y0=y,y1=y,y2=y+h,y3=y+h;

	if( tformed ){
		float tx0=x0,tx1=x1,tx2=x2,tx3=x3;
		x0=tx0 * ix + y0 * jx + tx;y0=tx0 * iy + y0 * jy + ty;
		x1=tx1 * ix + y1 * jx + tx;y1=tx1 * iy + y1 * jy + ty;
		x2=tx2 * ix + y2 * jx + tx;y2=tx2 * iy + y2 * jy + ty;
		x3=tx3 * ix + y3 * jx + tx;y3=tx3 * iy + y3 * jy + ty;
	}
	
	float *vp=Begin( 4,4,0 );

	vp[0 ]=x0;vp[1 ]=y0;(int&)vp[4 ]=colorARGB;
	vp[5 ]=x1;vp[6 ]=y1;(int&)vp[9 ]=colorARGB;
	vp[10]=x2;vp[11]=y2;(int&)vp[14]=colorARGB;
	vp[15]=x3;vp[16]=y3;(int&)vp[19]=colorARGB;

	return 0;
}

int gxtkGraphics::DrawOval( float x,float y,float w,float h ){
	
	float xr=w/2.0f;
	float yr=h/2.0f;

	int n;
	if( tformed ){
		float dx_x=xr * ix;
		float dx_y=xr * iy;
		float dx=sqrtf( dx_x*dx_x+dx_y*dx_y );
		float dy_x=yr * jx;
		float dy_y=yr * jy;
		float dy=sqrtf( dy_x*dy_x+dy_y*dy_y );
		n=(int)( dx+dy );
	}else{
		n=(int)( fabs( xr )+fabs( yr ) );
	}
	
	if( n<12 ){
		n=12;
	}else if( n>MAX_VERTS ){
		n=MAX_VERTS;
	}else{
		n&=~3;
	}

	float x0=x+xr,y0=y+yr;
	
	float *vp=Begin( n,n,0 );

	for( int i=0;i<n;++i ){
	
		float th=i * 6.28318531f / n;

		float px=x0+cosf( th ) * xr;
		float py=y0-sinf( th ) * yr;
		
		if( tformed ){
			float ppx=px;
			px=ppx * ix + py * jx + tx;
			py=ppx * iy + py * jy + ty;
		}
		
		vp[0]=px;vp[1]=py;(int&)vp[4]=colorARGB;
		vp+=5;
	}
	
	return 0;
}

int gxtkGraphics::DrawPoly( Array<Float> verts ){

	int n=verts.Length()/2;
	if( n<1 || n>MAX_VERTS ) return 0;
	
	float *vp=Begin( n,n,0 );
	
	for( int i=0;i<n;++i ){
		int j=i*2;
		if( tformed ){
			vp[0]=verts[j] * ix + verts[j+1] * jx + tx;
			vp[1]=verts[j] * iy + verts[j+1] * jy + ty;
		}else{
			vp[0]=verts[j];
			vp[1]=verts[j+1];
		}
		(int&)vp[4]=colorARGB;
		vp+=5;
	}

	return 0;
}

int gxtkGraphics::DrawPoly2( Array<Float> verts,gxtkSurface *surface,int srcx,int srcy ){

	int n=verts.Length()/4;
	if( n<1 || n>MAX_VERTS ) return 0;
		
	float *vp=Begin( n,n,surface );
	
	for( int i=0;i<n;++i ){
		int j=i*4;
		if( tformed ){
			vp[0]=verts[j] * ix + verts[j+1] * jx + tx;
			vp[1]=verts[j] * iy + verts[j+1] * jy + ty;
		}else{
			vp[0]=verts[j];
			vp[1]=verts[j+1];
		}
		vp[2]=(srcx+verts[j+2])*surface->uscale;
		vp[3]=(srcy+verts[j+3])*surface->vscale;
		(int&)vp[4]=colorARGB;
		vp+=5;
	}
	
	return 0;
}

int gxtkGraphics::DrawSurface( gxtkSurface *surf,float x,float y ){
	
	float w=surf->Width();
	float h=surf->Height();
	float x0=x,x1=x+w,x2=x+w,x3=x;
	float y0=y,y1=y,y2=y+h,y3=y+h;
	float u0=0,u1=w*surf->uscale;
	float v0=0,v1=h*surf->vscale;

	if( tformed ){
		float tx0=x0,tx1=x1,tx2=x2,tx3=x3;
		x0=tx0 * ix + y0 * jx + tx;y0=tx0 * iy + y0 * jy + ty;
		x1=tx1 * ix + y1 * jx + tx;y1=tx1 * iy + y1 * jy + ty;
		x2=tx2 * ix + y2 * jx + tx;y2=tx2 * iy + y2 * jy + ty;
		x3=tx3 * ix + y3 * jx + tx;y3=tx3 * iy + y3 * jy + ty;
	}
	
	float *vp=Begin( 4,4,surf );
	
	vp[0 ]=x0;vp[1 ]=y0;vp[2 ]=u0;vp[3 ]=v0;(int&)vp[4 ]=colorARGB;
	vp[5 ]=x1;vp[6 ]=y1;vp[7 ]=u1;vp[8 ]=v0;(int&)vp[9 ]=colorARGB;
	vp[10]=x2;vp[11]=y2;vp[12]=u1;vp[13]=v1;(int&)vp[14]=colorARGB;
	vp[15]=x3;vp[16]=y3;vp[17]=u0;vp[18]=v1;(int&)vp[19]=colorARGB;
	
	return 0;
}

int gxtkGraphics::DrawSurface2( gxtkSurface *surf,float x,float y,int srcx,int srcy,int srcw,int srch ){
	
	float w=srcw;
	float h=srch;
	float x0=x,x1=x+w,x2=x+w,x3=x;
	float y0=y,y1=y,y2=y+h,y3=y+h;
	float u0=srcx*surf->uscale,u1=(srcx+srcw)*surf->uscale;
	float v0=srcy*surf->vscale,v1=(srcy+srch)*surf->vscale;

	if( tformed ){
		float tx0=x0,tx1=x1,tx2=x2,tx3=x3;
		x0=tx0 * ix + y0 * jx + tx;y0=tx0 * iy + y0 * jy + ty;
		x1=tx1 * ix + y1 * jx + tx;y1=tx1 * iy + y1 * jy + ty;
		x2=tx2 * ix + y2 * jx + tx;y2=tx2 * iy + y2 * jy + ty;
		x3=tx3 * ix + y3 * jx + tx;y3=tx3 * iy + y3 * jy + ty;
	}
	
	float *vp=Begin( 4,4,surf );
	
	vp[0 ]=x0;vp[1 ]=y0;vp[2 ]=u0;vp[3 ]=v0;(int&)vp[4 ]=colorARGB;
	vp[5 ]=x1;vp[6 ]=y1;vp[7 ]=u1;vp[8 ]=v0;(int&)vp[9 ]=colorARGB;
	vp[10]=x2;vp[11]=y2;vp[12]=u1;vp[13]=v1;(int&)vp[14]=colorARGB;
	vp[15]=x3;vp[16]=y3;vp[17]=u0;vp[18]=v1;(int&)vp[19]=colorARGB;
	
	return 0;
}
	
int gxtkGraphics::ReadPixels( Array<int> pixels,int x,int y,int width,int height,int offset,int pitch ){

	Flush();

	unsigned *p=(unsigned*)malloc(width*height*4);

	glReadPixels( x,this->height-y-height,width,height,GL_BGRA,GL_UNSIGNED_BYTE,p );
	
	for( int py=0;py<height;++py ){
		memcpy( &pixels[offset+py*pitch],&p[(height-py-1)*width],width*4 );
	}
	
	free( p );
	
	return 0;
}

int gxtkGraphics::WritePixels2( gxtkSurface *surface,Array<int> pixels,int x,int y,int width,int height,int offset,int pitch ){

	surface->SetSubData( x,y,width,height,(unsigned*)&pixels[offset],pitch );
	
	return 0;
}

//***** gxtkSurface *****

gxtkSurface::gxtkSurface():data(0),width(0),height(0),depth(0),format(0),seq(-1),texture(0),uscale(0),vscale(0){
}

gxtkSurface::~gxtkSurface(){
	Discard();
}

int gxtkSurface::Discard(){
	if( seq==glfwGraphicsSeq ){
		glDeleteTextures( 1,&texture );
		seq=-1;
	}
	if( data ){
		free( data );
		data=0;
	}
	return 0;
}

int gxtkSurface::Width(){
	return width;
}

int gxtkSurface::Height(){
	return height;
}

int gxtkSurface::Loaded(){
	return 1;
}

//Careful! Can't call any GL here as it may be executing off-thread.
//
void gxtkSurface::SetData( unsigned char *data,int width,int height,int depth ){

	this->data=data;
	this->width=width;
	this->height=height;
	this->depth=depth;
	
	unsigned char *p=data;
	int n=width*height;
	
	switch( depth ){
	case 1:
#if _WIN32
		format=GL_LUMINANCE;
#elif __APPLE__
		format=GL_RED;
#elif __linux
		format=GL_LUMINANCE;
#endif
		break;
	case 2:
#if _WIN32
		format=GL_LUMINANCE_ALPHA;
#elif __APPLE__
		format=GL_RG;
#elif __linux
		format=GL_LUMINANCE_ALPHA;
#endif
		if( data ){
			while( n-- ){	//premultiply alpha
				p[0]=p[0]*p[1]/255;
				p+=2;
			}
		}
		break;
	case 3:
		format=GL_RGB;
		break;
	case 4:
		format=GL_RGBA;
		if( data ){
			while( n-- ){	//premultiply alpha
				p[0]=p[0]*p[3]/255;
				p[1]=p[1]*p[3]/255;
				p[2]=p[2]*p[3]/255;
				p+=4;
			}
		}
		break;
	}
}

void gxtkSurface::SetSubData( int x,int y,int w,int h,unsigned *src,int pitch ){
	if( format!=GL_RGBA ) return;
	
	if( !data ) data=(unsigned char*)malloc( width*height*4 );
	
	unsigned *dst=(unsigned*)data+y*width+x;
	
	for( int py=0;py<h;++py ){
		unsigned *d=dst+py*width;
		unsigned *s=src+py*pitch;
		for( int px=0;px<w;++px ){
			unsigned p=*s++;
			unsigned a=p>>24;
			*d++=(a<<24) | ((p>>0&0xff)*a/255<<16) | ((p>>8&0xff)*a/255<<8) | ((p>>16&0xff)*a/255);
		}
	}
	
	if( seq==glfwGraphicsSeq ){
		glBindTexture( GL_TEXTURE_2D,texture );
		glPixelStorei( GL_UNPACK_ALIGNMENT,1 );
		if( width==pitch ){
			glTexSubImage2D( GL_TEXTURE_2D,0,x,y,w,h,format,GL_UNSIGNED_BYTE,dst );
		}else{
			for( int py=0;py<h;++py ){
				glTexSubImage2D( GL_TEXTURE_2D,0,x,y+py,w,1,format,GL_UNSIGNED_BYTE,dst+py*width );
			}
		}
	}
}

void gxtkSurface::Bind(){

	if( !glfwGraphicsSeq ) return;
	
	if( seq==glfwGraphicsSeq ){
		glBindTexture( GL_TEXTURE_2D,texture );
		return;
	}
	
	seq=glfwGraphicsSeq;
	
	glGenTextures( 1,&texture );
	glBindTexture( GL_TEXTURE_2D,texture );
	
	if( CFG_MOJO_IMAGE_FILTERING_ENABLED ){
		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR );
		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR );
	}else{
		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST );
		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST );
	}

	glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE );
	glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE );

	int texwidth=width;
	int texheight=height;
	
	glTexImage2D( GL_TEXTURE_2D,0,format,texwidth,texheight,0,format,GL_UNSIGNED_BYTE,0 );
	if( glGetError()!=GL_NO_ERROR ){
		texwidth=Pow2Size( width );
		texheight=Pow2Size( height );
		glTexImage2D( GL_TEXTURE_2D,0,format,texwidth,texheight,0,format,GL_UNSIGNED_BYTE,0 );
	}
	
	uscale=1.0/texwidth;
	vscale=1.0/texheight;
	
	if( data ){
		glPixelStorei( GL_UNPACK_ALIGNMENT,1 );
		glTexSubImage2D( GL_TEXTURE_2D,0,0,0,width,height,format,GL_UNSIGNED_BYTE,data );
	}
}

void gxtkSurface::OnUnsafeLoadComplete(){
	Bind();
}

bool gxtkGraphics::LoadSurface__UNSAFE__( gxtkSurface *surface,String path ){

	int width,height,depth;
	unsigned char *data=BBGlfwGame::GlfwGame()->LoadImageData( path,&width,&height,&depth );
	if( !data ) return false;
	
	surface->SetData( data,width,height,depth );
	return true;
}

gxtkSurface *gxtkGraphics::LoadSurface( String path ){
	gxtkSurface *surf=new gxtkSurface();
	if( !LoadSurface__UNSAFE__( surf,path ) ) return 0;
	surf->Bind();
	return surf;
}

gxtkSurface *gxtkGraphics::CreateSurface( int width,int height ){
	gxtkSurface *surf=new gxtkSurface();
	surf->SetData( 0,width,height,4 );
	surf->Bind();
	return surf;
}

//***** gxtkAudio.h *****

class gxtkSample;

class gxtkChannel{
public:
	ALuint source;
	gxtkSample *sample;
	int flags;
	int state;
	
	int AL_Source();
};

class gxtkAudio : public Object{
public:
	static gxtkAudio *audio;
	
	ALCdevice *alcDevice;
	ALCcontext *alcContext;
	gxtkChannel channels[33];

	gxtkAudio();

	virtual void mark();

	//***** GXTK API *****
	virtual int Suspend();
	virtual int Resume();

	virtual gxtkSample *LoadSample( String path );
	virtual bool LoadSample__UNSAFE__( gxtkSample *sample,String path );
	
	virtual int PlaySample( gxtkSample *sample,int channel,int flags );

	virtual int StopChannel( int channel );
	virtual int PauseChannel( int channel );
	virtual int ResumeChannel( int channel );
	virtual int ChannelState( int channel );
	virtual int SetVolume( int channel,float volume );
	virtual int SetPan( int channel,float pan );
	virtual int SetRate( int channel,float rate );
	
	virtual int PlayMusic( String path,int flags );
	virtual int StopMusic();
	virtual int PauseMusic();
	virtual int ResumeMusic();
	virtual int MusicState();
	virtual int SetMusicVolume( float volume );
};

class gxtkSample : public Object{
public:
	ALuint al_buffer;

	gxtkSample();
	gxtkSample( ALuint buf );
	~gxtkSample();
	
	void SetBuffer( ALuint buf );
	
	//***** GXTK API *****
	virtual int Discard();
};

//***** gxtkAudio.cpp *****

gxtkAudio *gxtkAudio::audio;

static std::vector<ALuint> discarded;

static void FlushDiscarded(){

	if( !discarded.size() ) return;
	
	for( int i=0;i<33;++i ){
		gxtkChannel *chan=&gxtkAudio::audio->channels[i];
		if( chan->state ){
			int state=0;
			alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
			if( state==AL_STOPPED ) alSourcei( chan->source,AL_BUFFER,0 );
		}
	}
	
	std::vector<ALuint> out;
	
	for( int i=0;i<discarded.size();++i ){
		ALuint buf=discarded[i];
		alDeleteBuffers( 1,&buf );
		ALenum err=alGetError();
		if( err==AL_NO_ERROR ){
//			printf( "alDeleteBuffers OK!\n" );fflush( stdout );
		}else{
//			printf( "alDeleteBuffers failed...\n" );fflush( stdout );
			out.push_back( buf );
		}
	}
	discarded=out;
}

int gxtkChannel::AL_Source(){
	if( source ) return source;

	alGetError();
	alGenSources( 1,&source );
	if( alGetError()==AL_NO_ERROR ) return source;
	
	//couldn't create source...steal a free source...?
	//
	source=0;
	for( int i=0;i<32;++i ){
		gxtkChannel *chan=&gxtkAudio::audio->channels[i];
		if( !chan->source || gxtkAudio::audio->ChannelState( i ) ) continue;
//		puts( "Stealing source!" );
		source=chan->source;
		chan->source=0;
		break;
	}
	return source;
}

gxtkAudio::gxtkAudio(){

	audio=this;
	
	alcDevice=alcOpenDevice( 0 );
	if( !alcDevice ){
		alcDevice=alcOpenDevice( "Generic Hardware" );
		if( !alcDevice ) alcDevice=alcOpenDevice( "Generic Software" );
	}

//	bbPrint( "opening openal device" );
	if( alcDevice ){
		if( (alcContext=alcCreateContext( alcDevice,0 )) ){
			if( (alcMakeContextCurrent( alcContext )) ){
				//alc all go!
			}else{
				bbPrint( "OpenAl error: alcMakeContextCurrent failed" );
			}
		}else{
			bbPrint( "OpenAl error: alcCreateContext failed" );
		}
	}else{
		bbPrint( "OpenAl error: alcOpenDevice failed" );
	}

	alDistanceModel( AL_NONE );
	
	memset( channels,0,sizeof(channels) );

	channels[32].AL_Source();
}

void gxtkAudio::mark(){
	for( int i=0;i<33;++i ){
		gxtkChannel *chan=&channels[i];
		if( chan->state!=0 ){
			int state=0;
			alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
			if( state!=AL_STOPPED ) gc_mark( chan->sample );
		}
	}
}

int gxtkAudio::Suspend(){
	for( int i=0;i<33;++i ){
		gxtkChannel *chan=&channels[i];
		if( chan->state==1 ){
			int state=0;
			alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
			if( state==AL_PLAYING ) alSourcePause( chan->source );
		}
	}
	return 0;
}

int gxtkAudio::Resume(){
	for( int i=0;i<33;++i ){
		gxtkChannel *chan=&channels[i];
		if( chan->state==1 ){
			int state=0;
			alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
			if( state==AL_PAUSED ) alSourcePlay( chan->source );
		}
	}
	return 0;
}

bool gxtkAudio::LoadSample__UNSAFE__( gxtkSample *sample,String path ){

	int length=0;
	int channels=0;
	int format=0;
	int hertz=0;
	unsigned char *data=BBGlfwGame::GlfwGame()->LoadAudioData( path,&length,&channels,&format,&hertz );
	if( !data ) return false;
	
	int al_format=0;
	if( format==1 && channels==1 ){
		al_format=AL_FORMAT_MONO8;
	}else if( format==1 && channels==2 ){
		al_format=AL_FORMAT_STEREO8;
	}else if( format==2 && channels==1 ){
		al_format=AL_FORMAT_MONO16;
	}else if( format==2 && channels==2 ){
		al_format=AL_FORMAT_STEREO16;
	}
	
	int size=length*channels*format;
	
	ALuint al_buffer;
	alGenBuffers( 1,&al_buffer );
	alBufferData( al_buffer,al_format,data,size,hertz );
	free( data );
	
	sample->SetBuffer( al_buffer );
	return true;
}

gxtkSample *gxtkAudio::LoadSample( String path ){
	FlushDiscarded();
	gxtkSample *sample=new gxtkSample();
	if( !LoadSample__UNSAFE__( sample,path ) ) return 0;
	return sample;
}

int gxtkAudio::PlaySample( gxtkSample *sample,int channel,int flags ){

	FlushDiscarded();
	
	gxtkChannel *chan=&channels[channel];
	
	if( !chan->AL_Source() ) return -1;
	
	alSourceStop( chan->source );
	alSourcei( chan->source,AL_BUFFER,sample->al_buffer );
	alSourcei( chan->source,AL_LOOPING,flags ? 1 : 0 );
	alSourcePlay( chan->source );
	
	gc_assign( chan->sample,sample );

	chan->flags=flags;
	chan->state=1;

	return 0;
}

int gxtkAudio::StopChannel( int channel ){
	gxtkChannel *chan=&channels[channel];

	if( chan->state!=0 ){
		alSourceStop( chan->source );
		chan->state=0;
	}
	return 0;
}

int gxtkAudio::PauseChannel( int channel ){
	gxtkChannel *chan=&channels[channel];

	if( chan->state==1 ){
		int state=0;
		alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
		if( state==AL_STOPPED ){
			chan->state=0;
		}else{
			alSourcePause( chan->source );
			chan->state=2;
		}
	}
	return 0;
}

int gxtkAudio::ResumeChannel( int channel ){
	gxtkChannel *chan=&channels[channel];

	if( chan->state==2 ){
		alSourcePlay( chan->source );
		chan->state=1;
	}
	return 0;
}

int gxtkAudio::ChannelState( int channel ){
	gxtkChannel *chan=&channels[channel];
	
	if( chan->state==1 ){
		int state=0;
		alGetSourcei( chan->source,AL_SOURCE_STATE,&state );
		if( state==AL_STOPPED ) chan->state=0;
	}
	return chan->state;
}

int gxtkAudio::SetVolume( int channel,float volume ){
	gxtkChannel *chan=&channels[channel];

	alSourcef( chan->AL_Source(),AL_GAIN,volume );
	return 0;
}

int gxtkAudio::SetPan( int channel,float pan ){
	gxtkChannel *chan=&channels[channel];
	
	float x=sinf( pan ),y=0,z=-cosf( pan );
	alSource3f( chan->AL_Source(),AL_POSITION,x,y,z );
	return 0;
}

int gxtkAudio::SetRate( int channel,float rate ){
	gxtkChannel *chan=&channels[channel];

	alSourcef( chan->AL_Source(),AL_PITCH,rate );
	return 0;
}

int gxtkAudio::PlayMusic( String path,int flags ){
	StopMusic();
	
	gxtkSample *music=LoadSample( path );
	if( !music ) return -1;
	
	PlaySample( music,32,flags );
	return 0;
}

int gxtkAudio::StopMusic(){
	StopChannel( 32 );
	return 0;
}

int gxtkAudio::PauseMusic(){
	PauseChannel( 32 );
	return 0;
}

int gxtkAudio::ResumeMusic(){
	ResumeChannel( 32 );
	return 0;
}

int gxtkAudio::MusicState(){
	return ChannelState( 32 );
}

int gxtkAudio::SetMusicVolume( float volume ){
	SetVolume( 32,volume );
	return 0;
}

gxtkSample::gxtkSample():
al_buffer(0){
}

gxtkSample::gxtkSample( ALuint buf ):
al_buffer(buf){
}

gxtkSample::~gxtkSample(){
	Discard();
}

void gxtkSample::SetBuffer( ALuint buf ){
	al_buffer=buf;
}

int gxtkSample::Discard(){
	if( al_buffer ){
		discarded.push_back( al_buffer );
		al_buffer=0;
	}
	return 0;
}

class c_App;
class c_SoundEngine;
class c_GameDelegate;
class c_Font;
class c_GraphicsContext;
class c_Image;
class c_Frame;
class c_Glyph;
class c_Map;
class c_IntMap;
class c_Node;
class c_InputDevice;
class c_JoyState;
class c_DisplayMode;
class c_Map2;
class c_IntMap2;
class c_Stack;
class c_Node2;
class c_BBGameEvent;
class c_Sound;
class c_Stream;
class c_FileStream;
class c_DataBuffer;
class c_StreamError;
class c_StreamWriteError;
class c_App : public Object{
	public:
	c_App();
	c_App* m_new();
	int p_OnResize();
	virtual int p_OnCreate();
	int p_OnSuspend();
	int p_OnResume();
	virtual int p_OnUpdate();
	int p_OnLoading();
	virtual int p_OnRender();
	int p_OnClose();
	int p_OnBack();
	void mark();
};
class c_SoundEngine : public c_App{
	public:
	int m_Frame;
	c_SoundEngine();
	c_SoundEngine* m_new();
	static c_Font* m_FONT;
	static c_Image* m_Button1;
	static c_Sound* m_Square;
	static c_Sound* m_Ramp;
	static c_Sound* m_Ramp2;
	static c_Sound* m_Saw;
	static c_Sound* m_Noise;
	static c_Sound* m_Bass;
	static c_Sound* m_HNoise;
	static c_Sound* m_Zero;
	static String m_Track1;
	static String m_Track2;
	static String m_Track3;
	static String m_Track4;
	static String m_VolumeTrack1;
	static String m_VolumeTrack2;
	static String m_VolumeTrack3;
	static String m_VolumeTrack4;
	static String m_InstTrack1;
	static String m_InstTrack2;
	static String m_InstTrack3;
	static String m_InstTrack4;
	static String m_OctaveTrack1;
	static String m_OctaveTrack2;
	static String m_OctaveTrack3;
	static String m_OctaveTrack4;
	static Array<String > m_UndoTrack1;
	static Array<String > m_UndoTrack2;
	static Array<String > m_UndoTrack3;
	static Array<String > m_UndoTrack4;
	static Array<String > m_UndoVolumeTrack1;
	static Array<String > m_UndoVolumeTrack2;
	static Array<String > m_UndoVolumeTrack3;
	static Array<String > m_UndoVolumeTrack4;
	static Array<String > m_UndoInstTrack1;
	static Array<String > m_UndoInstTrack2;
	static Array<String > m_UndoInstTrack3;
	static Array<String > m_UndoInstTrack4;
	static Array<String > m_UndoOctaveTrack1;
	static Array<String > m_UndoOctaveTrack2;
	static Array<String > m_UndoOctaveTrack3;
	static Array<String > m_UndoOctaveTrack4;
	static int m_EDIT_CHANNEL;
	static int m_Cursorpos;
	static String m_Patternorder;
	static Array<int > m_Patterns;
	static String m_StatusInfo;
	int p_OnCreate();
	static int m_FrameTime;
	static Float m_CHOn1;
	static Float m_CHOn2;
	static Float m_CHOn3;
	static Float m_CHOn4;
	static int m_flw;
	static String m_Follow;
	static int m_USA;
	static String m_DEon;
	static int m_i;
	static int m_STATUS;
	static Float m_Scroller;
	static int m_UndoCount;
	static int m_pcount;
	static int m_FilenameInputOn;
	static String m_Filename;
	static Array<String > m_Descriptions;
	static int m_WavInit;
	static int m_InstDescriptionOn;
	static int m_Songlength;
	static int m_spd;
	static Array<int > m_InsArrayData;
	String p_SaveFile(String);
	String p_LoadFile();
	static c_Sound* m_CurrentWav;
	static c_Sound* m_CurrentWav2;
	static Float m_PWM;
	static int m_ppos;
	static int m_Press1;
	static int m_Press2;
	static String m_CopyTrack;
	static String m_CopyVolumeTrack;
	static String m_CopyInstTrack;
	static String m_CopyOctaveTrack;
	static String m_Lastgch;
	static int m_oct;
	static int m_Arpcounter;
	static int m_PWCount;
	static Float m_Decay;
	int p_Undo();
	static Float m_Dec2Pitch;
	static int m_ArpSpd;
	static Float m_fxval;
	static int m_PWDepth;
	static int m_PWVal;
	Float p_OnEdit();
	static Float m_p1;
	static Float m_last_p1;
	static Float m_fine_p1;
	static Float m_fxval1;
	static Float m_Vib1;
	static int m_Arpcounter1;
	static int m_PWCount1;
	static Float m_Decay1;
	static Float m_p2;
	static Float m_last_p2;
	static Float m_fine_p2;
	static Float m_fxval2;
	static Float m_Vib2;
	static int m_Arpcounter2;
	static int m_PWCount2;
	static Float m_Decay2;
	static Float m_p3;
	static Float m_last_p3;
	static Float m_fine_p3;
	static Float m_fxval3;
	static Float m_Vib3;
	static int m_Arpcounter3;
	static int m_PWCount3;
	static Float m_Decay3;
	static Float m_p4;
	static Float m_last_p4;
	static Float m_fine_p4;
	static Float m_fxval4;
	static Float m_Vib4;
	static int m_Arpcounter4;
	static int m_PWCount4;
	static Float m_Decay4;
	static int m_InstNo1;
	static int m_InstNo2;
	static int m_InstNo3;
	static int m_InstNo4;
	static Float m_volval1;
	static Float m_volval2;
	static Float m_volval3;
	static Float m_volval4;
	static int m_oct1;
	static int m_oct2;
	static int m_oct3;
	static int m_oct4;
	static c_Sound* m_Chan1wav;
	static c_Sound* m_Chan5wav;
	static c_Sound* m_Chan2wav;
	static c_Sound* m_Chan6wav;
	static c_Sound* m_Chan3wav;
	static c_Sound* m_Chan7wav;
	static c_Sound* m_Chan4wav;
	static c_Sound* m_Chan8wav;
	static Float m_PWM1;
	static Float m_PWM2;
	static Float m_PWM3;
	static Float m_PWM4;
	static int m_LastInstNo1;
	static int m_LastInstNo2;
	static int m_LastInstNo3;
	static int m_LastInstNo4;
	static int m_LastOct1;
	static int m_LastOct2;
	static int m_LastOct3;
	static int m_LastOct4;
	static Float m_Dec2Pitch1;
	static Float m_Dec2Pitch2;
	static Float m_Dec2Pitch3;
	static Float m_Dec2Pitch4;
	static int m_ArpSpd1;
	static int m_ArpSpd2;
	static int m_ArpSpd3;
	static int m_ArpSpd4;
	static int m_PWDepth1;
	static int m_PWVal1;
	static int m_PWDepth2;
	static int m_PWVal2;
	static int m_PWDepth3;
	static int m_PWVal3;
	static int m_PWDepth4;
	static int m_PWVal4;
	Float p_Play();
	int p_OnUpdate();
	int p_DrawGui();
	static String m_CHOff1;
	static String m_CHOff2;
	static String m_CHOff3;
	static String m_CHOff4;
	static int m_meter_H1;
	static int m_meter_H2;
	static int m_meter_H3;
	static int m_meter_H4;
	int p_OnRender();
	void mark();
};
extern c_App* bb_app__app;
class c_GameDelegate : public BBGameDelegate{
	public:
	gxtkGraphics* m__graphics;
	gxtkAudio* m__audio;
	c_InputDevice* m__input;
	c_GameDelegate();
	c_GameDelegate* m_new();
	void StartGame();
	void SuspendGame();
	void ResumeGame();
	void UpdateGame();
	void RenderGame();
	void KeyEvent(int,int);
	void MouseEvent(int,int,Float,Float,Float);
	void TouchEvent(int,int,Float,Float);
	void MotionEvent(int,int,Float,Float,Float);
	void DiscardGraphics();
	void mark();
};
extern c_GameDelegate* bb_app__delegate;
extern BBGame* bb_app__game;
int bbMain();
extern gxtkGraphics* bb_graphics_device;
int bb_graphics_SetGraphicsDevice(gxtkGraphics*);
class c_Font : public Object{
	public:
	Array<c_Image* > m__pages;
	int m__pageCount;
	int m__firstChar;
	Float m__height;
	c_IntMap* m__charMap;
	c_Font();
	c_Font* m_new(Array<c_Image* >,int,c_IntMap*,int,Float);
	c_Font* m_new2();
	static c_Font* m_Load(String,int,int,bool);
	static c_Font* m_Load2(String,int,int,int,int,int,int,int,int);
	static c_Font* m_Load3(String);
	c_Glyph* p_GetGlyph(int);
	Float p_TextWidth(String);
	Float p_TextHeight(String);
	void mark();
};
class c_GraphicsContext : public Object{
	public:
	c_Font* m_defaultFont;
	c_Font* m_font;
	int m_matrixSp;
	Float m_ix;
	Float m_iy;
	Float m_jx;
	Float m_jy;
	Float m_tx;
	Float m_ty;
	int m_tformed;
	int m_matDirty;
	Float m_color_r;
	Float m_color_g;
	Float m_color_b;
	Float m_alpha;
	int m_blend;
	Float m_scissor_x;
	Float m_scissor_y;
	Float m_scissor_width;
	Float m_scissor_height;
	Array<Float > m_matrixStack;
	c_GraphicsContext();
	c_GraphicsContext* m_new();
	int p_Validate();
	void mark();
};
extern c_GraphicsContext* bb_graphics_context;
class c_Image : public Object{
	public:
	gxtkSurface* m_surface;
	int m_width;
	int m_height;
	Array<c_Frame* > m_frames;
	int m_flags;
	Float m_tx;
	Float m_ty;
	c_Image* m_source;
	c_Image();
	static int m_DefaultFlags;
	c_Image* m_new();
	int p_SetHandle(Float,Float);
	int p_ApplyFlags(int);
	c_Image* p_Init(gxtkSurface*,int,int);
	c_Image* p_Init2(gxtkSurface*,int,int,int,int,int,int,c_Image*,int,int,int,int);
	int p_Width();
	int p_Height();
	void mark();
};
String bb_data_FixDataPath(String);
class c_Frame : public Object{
	public:
	int m_x;
	int m_y;
	c_Frame();
	c_Frame* m_new(int,int);
	c_Frame* m_new2();
	void mark();
};
int bb_lang_DebugLog(String);
c_Image* bb_graphics_LoadImage(String,int,int);
c_Image* bb_graphics_LoadImage2(String,int,int,int,int);
class c_Glyph : public Object{
	public:
	int m_page;
	int m_id;
	int m_x;
	int m_y;
	int m_width;
	int m_height;
	int m_advance;
	int m_xoff;
	int m_yoff;
	c_Glyph();
	c_Glyph* m_new(int,int,int,int,int,int,int);
	c_Glyph* m_new2();
	void mark();
};
class c_Map : public Object{
	public:
	c_Node* m_root;
	c_Map();
	c_Map* m_new();
	virtual int p_Compare(int,int)=0;
	int p_RotateLeft(c_Node*);
	int p_RotateRight(c_Node*);
	int p_InsertFixup(c_Node*);
	bool p_Add(int,c_Glyph*);
	c_Node* p_FindNode(int);
	c_Glyph* p_Get(int);
	void mark();
};
class c_IntMap : public c_Map{
	public:
	c_IntMap();
	c_IntMap* m_new();
	int p_Compare(int,int);
	void mark();
};
class c_Node : public Object{
	public:
	int m_key;
	c_Node* m_right;
	c_Node* m_left;
	c_Glyph* m_value;
	int m_color;
	c_Node* m_parent;
	c_Node();
	c_Node* m_new(int,c_Glyph*,int,c_Node*);
	c_Node* m_new2();
	void mark();
};
String bb_app_LoadString(String);
void bb_graphics_SetFont(c_Font*);
extern gxtkAudio* bb_audio_device;
int bb_audio_SetAudioDevice(gxtkAudio*);
class c_InputDevice : public Object{
	public:
	Array<c_JoyState* > m__joyStates;
	Array<bool > m__keyDown;
	int m__keyHitPut;
	Array<int > m__keyHitQueue;
	Array<int > m__keyHit;
	int m__charGet;
	int m__charPut;
	Array<int > m__charQueue;
	Float m__mouseX;
	Float m__mouseY;
	Float m__mouseZ;
	Array<Float > m__touchX;
	Array<Float > m__touchY;
	Float m__accelX;
	Float m__accelY;
	Float m__accelZ;
	c_InputDevice();
	c_InputDevice* m_new();
	void p_PutKeyHit(int);
	void p_BeginUpdate();
	void p_EndUpdate();
	void p_KeyEvent(int,int);
	void p_MouseEvent(int,int,Float,Float,Float);
	void p_TouchEvent(int,int,Float,Float);
	void p_MotionEvent(int,int,Float,Float,Float);
	int p_KeyHit(int);
	Float p_MouseX();
	Float p_MouseY();
	int p_GetChar();
	bool p_KeyDown(int);
	void mark();
};
class c_JoyState : public Object{
	public:
	Array<Float > m_joyx;
	Array<Float > m_joyy;
	Array<Float > m_joyz;
	Array<bool > m_buttons;
	c_JoyState();
	c_JoyState* m_new();
	void mark();
};
extern c_InputDevice* bb_input_device;
int bb_input_SetInputDevice(c_InputDevice*);
extern int bb_app__devWidth;
extern int bb_app__devHeight;
void bb_app_ValidateDeviceWindow(bool);
class c_DisplayMode : public Object{
	public:
	int m__width;
	int m__height;
	c_DisplayMode();
	c_DisplayMode* m_new(int,int);
	c_DisplayMode* m_new2();
	void mark();
};
class c_Map2 : public Object{
	public:
	c_Node2* m_root;
	c_Map2();
	c_Map2* m_new();
	virtual int p_Compare(int,int)=0;
	c_Node2* p_FindNode(int);
	bool p_Contains(int);
	int p_RotateLeft2(c_Node2*);
	int p_RotateRight2(c_Node2*);
	int p_InsertFixup2(c_Node2*);
	bool p_Set(int,c_DisplayMode*);
	bool p_Insert(int,c_DisplayMode*);
	void mark();
};
class c_IntMap2 : public c_Map2{
	public:
	c_IntMap2();
	c_IntMap2* m_new();
	int p_Compare(int,int);
	void mark();
};
class c_Stack : public Object{
	public:
	Array<c_DisplayMode* > m_data;
	int m_length;
	c_Stack();
	c_Stack* m_new();
	c_Stack* m_new2(Array<c_DisplayMode* >);
	void p_Push(c_DisplayMode*);
	void p_Push2(Array<c_DisplayMode* >,int,int);
	void p_Push3(Array<c_DisplayMode* >,int);
	Array<c_DisplayMode* > p_ToArray();
	void mark();
};
class c_Node2 : public Object{
	public:
	int m_key;
	c_Node2* m_right;
	c_Node2* m_left;
	c_DisplayMode* m_value;
	int m_color;
	c_Node2* m_parent;
	c_Node2();
	c_Node2* m_new(int,c_DisplayMode*,int,c_Node2*);
	c_Node2* m_new2();
	void mark();
};
extern Array<c_DisplayMode* > bb_app__displayModes;
extern c_DisplayMode* bb_app__desktopMode;
int bb_app_DeviceWidth();
int bb_app_DeviceHeight();
void bb_app_EnumDisplayModes();
extern gxtkGraphics* bb_graphics_renderDevice;
int bb_graphics_SetMatrix(Float,Float,Float,Float,Float,Float);
int bb_graphics_SetMatrix2(Array<Float >);
int bb_graphics_SetColor(Float,Float,Float);
int bb_graphics_SetColor2(Float);
int bb_graphics_SetAlpha(Float);
int bb_graphics_SetBlend(int);
int bb_graphics_SetScissor(Float,Float,Float,Float);
int bb_graphics_BeginRender();
int bb_graphics_EndRender();
class c_BBGameEvent : public Object{
	public:
	c_BBGameEvent();
	void mark();
};
void bb_app_EndApp();
extern int bb_app__updateRate;
void bb_app_SetUpdateRate(int);
class c_Sound : public Object{
	public:
	gxtkSample* m_sample;
	c_Sound();
	c_Sound* m_new(gxtkSample*);
	c_Sound* m_new2();
	void mark();
};
c_Sound* bb_audio_LoadSound(String);
int bb_input_KeyHit(int);
Float bb_input_MouseX();
Float bb_input_MouseY();
int bb_input_MouseHit(int);
int bb_slksound_BigButtonZone(int,int,int);
int bb_audio_StopChannel(int);
int bb_slksound_PauseAll();
int bb_slksound_ToInputField(int,int);
int bb_input_GetChar();
String bb_slksound_FString(String);
class c_Stream : public Object{
	public:
	c_Stream();
	c_Stream* m_new();
	virtual int p_Write(c_DataBuffer*,int,int)=0;
	void p_WriteError();
	void p_WriteAll(c_DataBuffer*,int,int);
	void p_WriteString(String,String);
	virtual void p_Close()=0;
	void mark();
};
class c_FileStream : public c_Stream{
	public:
	BBFileStream* m__stream;
	c_FileStream();
	static BBFileStream* m_OpenStream(String,String);
	c_FileStream* m_new(String,String);
	c_FileStream* m_new2(BBFileStream*);
	c_FileStream* m_new3();
	static c_FileStream* m_Open(String,String);
	void p_Close();
	int p_Write(c_DataBuffer*,int,int);
	void mark();
};
class c_DataBuffer : public BBDataBuffer{
	public:
	c_DataBuffer();
	c_DataBuffer* m_new(int,bool);
	c_DataBuffer* m_new2();
	void p_PokeBytes(int,Array<int >,int,int);
	int p_PokeString(int,String,String);
	void mark();
};
class c_StreamError : public ThrowableObject{
	public:
	c_Stream* m__stream;
	c_StreamError();
	c_StreamError* m_new(c_Stream*);
	c_StreamError* m_new2();
	void mark();
};
class c_StreamWriteError : public c_StreamError{
	public:
	c_StreamWriteError();
	c_StreamWriteError* m_new(c_Stream*);
	c_StreamWriteError* m_new2();
	void mark();
};
int bb_input_KeyDown(int);
String bb_slksound_ChangeTrack(String,int,String);
String bb_slksound_Int2Char(int);
int bb_slksound_PlayTrack(String,int);
int bb_audio_SetChannelRate(int,Float);
int bb_audio_PlaySound(c_Sound*,int,int);
Float bb_slksound_PlayInst(c_Sound*,int,int,int,c_Sound*,Float,int,Float,int);
int bb_audio_SetChannelVolume(int,Float);
int bb_slksound_ButtonZone(int,int,int,int,int);
int bb_slksound_Char2Int(String);
int bb_graphics_Cls(Float,Float,Float);
int bb_graphics_DrawRect(Float,Float,Float,Float);
int bb_graphics_DrawImageRect(c_Image*,Float,Float,int,int,int,int,int);
int bb_graphics_PushMatrix();
int bb_graphics_Transform(Float,Float,Float,Float,Float,Float);
int bb_graphics_Transform2(Array<Float >);
int bb_graphics_Translate(Float,Float);
int bb_graphics_Rotate(Float);
int bb_graphics_Scale(Float,Float);
int bb_graphics_PopMatrix();
int bb_graphics_DrawImageRect2(c_Image*,Float,Float,int,int,int,int,Float,Float,Float,int);
void bb_graphics_DrawText(String,int,int,Float,Float);
void bb_graphics_DrawText2(Array<String >,int,int,Float,Float);
String bb_slksound_Hex8(int);
String bb_slksound_Translate2Note(String,int,String);
int bb_graphics_DrawImage(c_Image*,Float,Float,int);
int bb_graphics_DrawImage2(c_Image*,Float,Float,Float,Float,Float,int);
void gc_mark( BBGame *p ){}
c_App::c_App(){
}
c_App* c_App::m_new(){
	if((bb_app__app)!=0){
		bbError(String(L"App has already been created",28));
	}
	gc_assign(bb_app__app,this);
	gc_assign(bb_app__delegate,(new c_GameDelegate)->m_new());
	bb_app__game->SetDelegate(bb_app__delegate);
	return this;
}
int c_App::p_OnResize(){
	return 0;
}
int c_App::p_OnCreate(){
	return 0;
}
int c_App::p_OnSuspend(){
	return 0;
}
int c_App::p_OnResume(){
	return 0;
}
int c_App::p_OnUpdate(){
	return 0;
}
int c_App::p_OnLoading(){
	return 0;
}
int c_App::p_OnRender(){
	return 0;
}
int c_App::p_OnClose(){
	bb_app_EndApp();
	return 0;
}
int c_App::p_OnBack(){
	p_OnClose();
	return 0;
}
void c_App::mark(){
	Object::mark();
}
c_SoundEngine::c_SoundEngine(){
	m_Frame=0;
}
c_SoundEngine* c_SoundEngine::m_new(){
	c_App::m_new();
	return this;
}
c_Font* c_SoundEngine::m_FONT;
c_Image* c_SoundEngine::m_Button1;
c_Sound* c_SoundEngine::m_Square;
c_Sound* c_SoundEngine::m_Ramp;
c_Sound* c_SoundEngine::m_Ramp2;
c_Sound* c_SoundEngine::m_Saw;
c_Sound* c_SoundEngine::m_Noise;
c_Sound* c_SoundEngine::m_Bass;
c_Sound* c_SoundEngine::m_HNoise;
c_Sound* c_SoundEngine::m_Zero;
String c_SoundEngine::m_Track1;
String c_SoundEngine::m_Track2;
String c_SoundEngine::m_Track3;
String c_SoundEngine::m_Track4;
String c_SoundEngine::m_VolumeTrack1;
String c_SoundEngine::m_VolumeTrack2;
String c_SoundEngine::m_VolumeTrack3;
String c_SoundEngine::m_VolumeTrack4;
String c_SoundEngine::m_InstTrack1;
String c_SoundEngine::m_InstTrack2;
String c_SoundEngine::m_InstTrack3;
String c_SoundEngine::m_InstTrack4;
String c_SoundEngine::m_OctaveTrack1;
String c_SoundEngine::m_OctaveTrack2;
String c_SoundEngine::m_OctaveTrack3;
String c_SoundEngine::m_OctaveTrack4;
Array<String > c_SoundEngine::m_UndoTrack1;
Array<String > c_SoundEngine::m_UndoTrack2;
Array<String > c_SoundEngine::m_UndoTrack3;
Array<String > c_SoundEngine::m_UndoTrack4;
Array<String > c_SoundEngine::m_UndoVolumeTrack1;
Array<String > c_SoundEngine::m_UndoVolumeTrack2;
Array<String > c_SoundEngine::m_UndoVolumeTrack3;
Array<String > c_SoundEngine::m_UndoVolumeTrack4;
Array<String > c_SoundEngine::m_UndoInstTrack1;
Array<String > c_SoundEngine::m_UndoInstTrack2;
Array<String > c_SoundEngine::m_UndoInstTrack3;
Array<String > c_SoundEngine::m_UndoInstTrack4;
Array<String > c_SoundEngine::m_UndoOctaveTrack1;
Array<String > c_SoundEngine::m_UndoOctaveTrack2;
Array<String > c_SoundEngine::m_UndoOctaveTrack3;
Array<String > c_SoundEngine::m_UndoOctaveTrack4;
int c_SoundEngine::m_EDIT_CHANNEL;
int c_SoundEngine::m_Cursorpos;
String c_SoundEngine::m_Patternorder;
Array<int > c_SoundEngine::m_Patterns;
String c_SoundEngine::m_StatusInfo;
int c_SoundEngine::p_OnCreate(){
	bb_app_SetUpdateRate(51);
	gc_assign(m_FONT,c_Font::m_Load(String(L"mojofont.png",12),32,96,false));
	bb_graphics_SetFont(m_FONT);
	gc_assign(m_Button1,bb_graphics_LoadImage(String(L"button1.png",11),1,c_Image::m_DefaultFlags));
	gc_assign(m_Square,bb_audio_LoadSound(String(L"ramp_64.wav",11)));
	gc_assign(m_Ramp,bb_audio_LoadSound(String(L"ramp_b_64.wav",13)));
	gc_assign(m_Ramp2,bb_audio_LoadSound(String(L"ramp_c_64.wav",13)));
	gc_assign(m_Saw,bb_audio_LoadSound(String(L"saw_64.wav",10)));
	gc_assign(m_Noise,bb_audio_LoadSound(String(L"fx2b.wav",8)));
	gc_assign(m_Bass,bb_audio_LoadSound(String(L"tri_64.wav",10)));
	gc_assign(m_HNoise,bb_audio_LoadSound(String(L"hnoise.wav",10)));
	gc_assign(m_Zero,bb_audio_LoadSound(String(L"zero_64.wav",11)));
	for(int t_j=0;t_j<=255;t_j=t_j+1){
		for(int t_p=0;t_p<=31;t_p=t_p+1){
			m_Track1=m_Track1+String(L".",1);
			m_Track2=m_Track2+String(L".",1);
			m_Track3=m_Track3+String(L".",1);
			m_Track4=m_Track4+String(L".",1);
			m_VolumeTrack1=m_VolumeTrack1+String(L"0",1);
			m_VolumeTrack2=m_VolumeTrack2+String(L"0",1);
			m_VolumeTrack3=m_VolumeTrack3+String(L"0",1);
			m_VolumeTrack4=m_VolumeTrack4+String(L"0",1);
			m_InstTrack1=m_InstTrack1+String(L"0",1);
			m_InstTrack2=m_InstTrack2+String(L"0",1);
			m_InstTrack3=m_InstTrack3+String(L"0",1);
			m_InstTrack4=m_InstTrack4+String(L"0",1);
			m_OctaveTrack1=m_OctaveTrack1+String(L"0",1);
			m_OctaveTrack2=m_OctaveTrack2+String(L"0",1);
			m_OctaveTrack3=m_OctaveTrack3+String(L"0",1);
			m_OctaveTrack4=m_OctaveTrack4+String(L"0",1);
		}
	}
	for(int t_uc=0;t_uc<=15;t_uc=t_uc+1){
		for(int t_j2=0;t_j2<=255;t_j2=t_j2+1){
			for(int t_p2=0;t_p2<=31;t_p2=t_p2+1){
				m_UndoTrack1[t_uc]=m_UndoTrack1[t_uc]+String(L".",1);
				m_UndoTrack2[t_uc]=m_UndoTrack2[t_uc]+String(L".",1);
				m_UndoTrack3[t_uc]=m_UndoTrack3[t_uc]+String(L".",1);
				m_UndoTrack4[t_uc]=m_UndoTrack4[t_uc]+String(L".",1);
				m_UndoVolumeTrack1[t_uc]=m_UndoVolumeTrack1[t_uc]+String(L"0",1);
				m_UndoVolumeTrack2[t_uc]=m_UndoVolumeTrack2[t_uc]+String(L"0",1);
				m_UndoVolumeTrack3[t_uc]=m_UndoVolumeTrack3[t_uc]+String(L"0",1);
				m_UndoVolumeTrack4[t_uc]=m_UndoVolumeTrack4[t_uc]+String(L"0",1);
				m_UndoInstTrack1[t_uc]=m_UndoInstTrack1[t_uc]+String(L"0",1);
				m_UndoInstTrack2[t_uc]=m_UndoInstTrack2[t_uc]+String(L"0",1);
				m_UndoInstTrack3[t_uc]=m_UndoInstTrack3[t_uc]+String(L"0",1);
				m_UndoInstTrack4[t_uc]=m_UndoInstTrack4[t_uc]+String(L"0",1);
				m_UndoOctaveTrack1[t_uc]=m_UndoOctaveTrack1[t_uc]+String(L"0",1);
				m_UndoOctaveTrack2[t_uc]=m_UndoOctaveTrack2[t_uc]+String(L"0",1);
				m_UndoOctaveTrack3[t_uc]=m_UndoOctaveTrack3[t_uc]+String(L"0",1);
				m_UndoOctaveTrack4[t_uc]=m_UndoOctaveTrack4[t_uc]+String(L"0",1);
			}
		}
	}
	m_EDIT_CHANNEL=1;
	m_Cursorpos=1;
	for(int t_u=0;t_u<=255;t_u=t_u+1){
		m_Patterns[t_u]=(m_Patternorder.Slice(t_u*2,t_u*2+2)).ToInt();
	}
	m_StatusInfo=String(L"Standby...",10);
	return 0;
}
int c_SoundEngine::m_FrameTime;
Float c_SoundEngine::m_CHOn1;
Float c_SoundEngine::m_CHOn2;
Float c_SoundEngine::m_CHOn3;
Float c_SoundEngine::m_CHOn4;
int c_SoundEngine::m_flw;
String c_SoundEngine::m_Follow;
int c_SoundEngine::m_USA;
String c_SoundEngine::m_DEon;
int c_SoundEngine::m_i;
int c_SoundEngine::m_STATUS;
Float c_SoundEngine::m_Scroller;
int c_SoundEngine::m_UndoCount;
int c_SoundEngine::m_pcount;
int c_SoundEngine::m_FilenameInputOn;
String c_SoundEngine::m_Filename;
Array<String > c_SoundEngine::m_Descriptions;
int c_SoundEngine::m_WavInit;
int c_SoundEngine::m_InstDescriptionOn;
int c_SoundEngine::m_Songlength;
int c_SoundEngine::m_spd;
Array<int > c_SoundEngine::m_InsArrayData;
String c_SoundEngine::p_SaveFile(String t_Filename){
	if(!((t_Filename).Length()!=0)){
		return String(L"Enter a Name...",15);
	}
	if(bbConfirm(String(L"File Operation",14),String(L"There might be an existing File ! Do you really want to continue ?",66),false)){
	}else{
		return String(L"Save Failed...",14);
	}
	int t_PatternsLen=0;
	String t_FileData=String();
	c_FileStream* t_file=c_FileStream::m_Open(String(L"cerberus://data/songs/",22)+t_Filename,String(L"w",1));
	int t_plength=0;
	int t_lastp=0;
	for(int t_i=0;t_i<=255;t_i=t_i+1){
		if(t_lastp<m_Patterns[t_i] && m_Patterns[t_i]>t_plength){
			t_plength=m_Patterns[t_i];
		}
		t_lastp=m_Patterns[t_i];
	}
	t_plength+=1;
	t_FileData=String(L"PSG1",4);
	t_FileData=t_FileData+String((Char)(m_Songlength/32),1);
	t_FileData=t_FileData+String((Char)(m_spd),1);
	t_FileData=t_FileData+String((Char)(t_plength),1);
	t_FileData=t_FileData+(m_Track1.Slice(0,t_plength*32)+m_Track2.Slice(0,t_plength*32)+m_Track3.Slice(0,t_plength*32)+m_Track4.Slice(0,t_plength*32));
	t_FileData=t_FileData+(m_VolumeTrack1.Slice(0,t_plength*32)+m_VolumeTrack2.Slice(0,t_plength*32)+m_VolumeTrack3.Slice(0,t_plength*32)+m_VolumeTrack4.Slice(0,t_plength*32));
	t_FileData=t_FileData+(m_InstTrack1.Slice(0,t_plength*32)+m_InstTrack2.Slice(0,t_plength*32)+m_InstTrack3.Slice(0,t_plength*32)+m_InstTrack4.Slice(0,t_plength*32));
	t_FileData=t_FileData+(m_OctaveTrack1.Slice(0,t_plength*32)+m_OctaveTrack2.Slice(0,t_plength*32)+m_OctaveTrack3.Slice(0,t_plength*32)+m_OctaveTrack4.Slice(0,t_plength*32));
	for(int t_i2=0;t_i2<=255;t_i2=t_i2+1){
		t_FileData=t_FileData+String((Char)(m_Patterns[t_i2]),1);
	}
	for(int t_i3=0;t_i3<=248;t_i3=t_i3+1){
		t_FileData=t_FileData+String((Char)(m_InsArrayData[t_i3]),1);
	}
	for(int t_i4=1;t_i4<=31;t_i4=t_i4+1){
		t_FileData=t_FileData+m_Descriptions[t_i4];
	}
	t_file->p_WriteString(t_FileData,String(L"utf8",4));
	t_file->p_Close();
	if((t_FileData).Length()!=0){
		return String(L"File Saved...",13);
	}else{
		return String(L"Saving Failed!",14);
	}
}
String c_SoundEngine::p_LoadFile(){
	String t_LoadFileName=String();
	int t_StopSlashPos=0;
	String t_FileData=String();
	t_LoadFileName=bbRequestFile(String(L"Select a File from DATA/SONGS/ to Load!",39),String(L"SongData:dat",12),false,String(L"data/songs/",11));
	for(int t_vb=0;t_vb<=t_LoadFileName.Length();t_vb=t_vb+1){
		if((int)t_LoadFileName[t_LoadFileName.Length()-t_vb]==92 && t_StopSlashPos<t_LoadFileName.Length()-t_vb && t_LoadFileName.Slice(t_LoadFileName.Length()-t_vb-5,t_LoadFileName.Length()-t_vb)==String(L"songs",5)){
			t_StopSlashPos=t_LoadFileName.Length()-t_vb;
		}
	}
	if((t_LoadFileName).Length()!=0){
		m_Filename=t_LoadFileName.Slice(t_StopSlashPos+1);
		t_FileData=bb_app_LoadString(String(L"cerberus://data/songs/",22)+m_Filename);
	}
	if(!((t_FileData).Length()!=0)){
		return String(L"Loading Failed!",15);
	}
	m_Track1=String();
	m_Track2=String();
	m_Track3=String();
	m_Track4=String();
	m_VolumeTrack1=String();
	m_VolumeTrack2=String();
	m_VolumeTrack3=String();
	m_VolumeTrack4=String();
	m_InstTrack1=String();
	m_InstTrack2=String();
	m_InstTrack3=String();
	m_InstTrack4=String();
	m_OctaveTrack1=String();
	m_OctaveTrack2=String();
	m_OctaveTrack3=String();
	m_OctaveTrack4=String();
	m_Songlength=(int)t_FileData[4]*32;
	m_spd=(int)t_FileData[5];
	if(!((m_spd)!=0)){
		m_spd=5;
	}
	int t_plength=(int)t_FileData[6];
	m_Track1=t_FileData.Slice(7,t_plength*32+7);
	m_Track2=t_FileData.Slice(t_plength*32+7,t_plength*32*2+7);
	m_Track3=t_FileData.Slice(t_plength*32*2+7,t_plength*32*3+7);
	m_Track4=t_FileData.Slice(t_plength*32*3+7,t_plength*32*4+7);
	m_VolumeTrack1=t_FileData.Slice(t_plength*32*4+7,t_plength*32*5+7);
	m_VolumeTrack2=t_FileData.Slice(t_plength*32*5+7,t_plength*32*6+7);
	m_VolumeTrack3=t_FileData.Slice(t_plength*32*6+7,t_plength*32*7+7);
	m_VolumeTrack4=t_FileData.Slice(t_plength*32*7+7,t_plength*32*8+7);
	m_InstTrack1=t_FileData.Slice(t_plength*32*8+7,t_plength*32*9+7);
	m_InstTrack2=t_FileData.Slice(t_plength*32*9+7,t_plength*32*10+7);
	m_InstTrack3=t_FileData.Slice(t_plength*32*10+7,t_plength*32*11+7);
	m_InstTrack4=t_FileData.Slice(t_plength*32*11+7,t_plength*32*12+7);
	m_OctaveTrack1=t_FileData.Slice(t_plength*32*12+7,t_plength*32*13+7);
	m_OctaveTrack2=t_FileData.Slice(t_plength*32*13+7,t_plength*32*14+7);
	m_OctaveTrack3=t_FileData.Slice(t_plength*32*14+7,t_plength*32*15+7);
	m_OctaveTrack4=t_FileData.Slice(t_plength*32*15+7,t_plength*32*16+7);
	for(int t_j=0;t_j<=255-t_plength;t_j=t_j+1){
		for(int t_p=0;t_p<=31;t_p=t_p+1){
			m_Track1=m_Track1+String(L".",1);
			m_Track2=m_Track2+String(L".",1);
			m_Track3=m_Track3+String(L".",1);
			m_Track4=m_Track4+String(L".",1);
			m_VolumeTrack1=m_VolumeTrack1+String(L"0",1);
			m_VolumeTrack2=m_VolumeTrack2+String(L"0",1);
			m_VolumeTrack3=m_VolumeTrack3+String(L"0",1);
			m_VolumeTrack4=m_VolumeTrack4+String(L"0",1);
			m_InstTrack1=m_InstTrack1+String(L"0",1);
			m_InstTrack2=m_InstTrack2+String(L"0",1);
			m_InstTrack3=m_InstTrack3+String(L"0",1);
			m_InstTrack4=m_InstTrack4+String(L"0",1);
			m_OctaveTrack1=m_OctaveTrack1+String(L"0",1);
			m_OctaveTrack2=m_OctaveTrack2+String(L"0",1);
			m_OctaveTrack3=m_OctaveTrack3+String(L"0",1);
			m_OctaveTrack4=m_OctaveTrack4+String(L"0",1);
		}
	}
	for(int t_i=0;t_i<=255;t_i=t_i+1){
		m_Patterns[t_i]=(int)t_FileData[t_plength*32*16+7+t_i];
	}
	for(int t_i2=0;t_i2<=248;t_i2=t_i2+1){
		m_InsArrayData[t_i2]=(int)t_FileData[t_plength*32*16+7+256+t_i2];
	}
	for(int t_i3=1;t_i3<=31;t_i3=t_i3+1){
		m_Descriptions[t_i3]=t_FileData.Slice(t_plength*32*16+7+256+248+(t_i3-1)*21+1,t_plength*32*16+7+256+248+t_i3*21+1);
	}
	if((t_FileData).Length()!=0){
		return String(L"File Loaded...",14);
	}
	return String();
}
c_Sound* c_SoundEngine::m_CurrentWav;
c_Sound* c_SoundEngine::m_CurrentWav2;
Float c_SoundEngine::m_PWM;
int c_SoundEngine::m_ppos;
int c_SoundEngine::m_Press1;
int c_SoundEngine::m_Press2;
String c_SoundEngine::m_CopyTrack;
String c_SoundEngine::m_CopyVolumeTrack;
String c_SoundEngine::m_CopyInstTrack;
String c_SoundEngine::m_CopyOctaveTrack;
String c_SoundEngine::m_Lastgch;
int c_SoundEngine::m_oct;
int c_SoundEngine::m_Arpcounter;
int c_SoundEngine::m_PWCount;
Float c_SoundEngine::m_Decay;
int c_SoundEngine::p_Undo(){
	m_UndoCount+=1;
	if(m_UndoCount>31){
		m_UndoCount=0;
	}
	m_UndoInstTrack1[m_UndoCount]=m_InstTrack1;
	m_UndoInstTrack2[m_UndoCount]=m_InstTrack2;
	m_UndoInstTrack3[m_UndoCount]=m_InstTrack3;
	m_UndoInstTrack4[m_UndoCount]=m_InstTrack4;
	m_UndoOctaveTrack1[m_UndoCount]=m_OctaveTrack1;
	m_UndoOctaveTrack2[m_UndoCount]=m_OctaveTrack2;
	m_UndoOctaveTrack3[m_UndoCount]=m_OctaveTrack3;
	m_UndoOctaveTrack4[m_UndoCount]=m_OctaveTrack4;
	m_UndoTrack1[m_UndoCount]=m_Track1;
	m_UndoTrack2[m_UndoCount]=m_Track2;
	m_UndoTrack3[m_UndoCount]=m_Track3;
	m_UndoTrack4[m_UndoCount]=m_Track4;
	m_UndoVolumeTrack1[m_UndoCount]=m_VolumeTrack1;
	m_UndoVolumeTrack2[m_UndoCount]=m_VolumeTrack2;
	m_UndoVolumeTrack3[m_UndoCount]=m_VolumeTrack3;
	m_UndoVolumeTrack4[m_UndoCount]=m_VolumeTrack4;
	return 0;
}
Float c_SoundEngine::m_Dec2Pitch;
int c_SoundEngine::m_ArpSpd;
Float c_SoundEngine::m_fxval;
int c_SoundEngine::m_PWDepth;
int c_SoundEngine::m_PWVal;
Float c_SoundEngine::p_OnEdit(){
	if((bb_slksound_ToInputField(0,441))!=0){
		m_FilenameInputOn=1;
	}
	if(m_FilenameInputOn==1){
		m_STATUS=2;
		bb_slksound_PauseAll();
		String t_gch=String();
		int t_g=0;
		t_g=bb_input_GetChar();
		t_gch=String((Char)(t_g),1);
		if(m_Filename.Length()<32 && t_g>31 && ((bb_slksound_FString(String(t_g))).Length()!=0)){
			m_Filename=m_Filename+t_gch;
		}
		if((bb_input_KeyHit(13))!=0){
			m_FilenameInputOn=0;
		}
		if(((bb_input_KeyHit(8))!=0) || ((bb_input_KeyHit(46))!=0)){
			m_Filename=m_Filename.Slice(0,m_Filename.Length()-1);
		}
	}
	if((bb_slksound_ToInputField(396,120))!=0){
		m_Descriptions[m_WavInit]=String();
		m_InstDescriptionOn=1;
	}
	if(m_InstDescriptionOn==1){
		m_STATUS=2;
		bb_slksound_PauseAll();
		String t_gch2=String();
		int t_g2=0;
		t_g2=bb_input_GetChar();
		t_gch2=String((Char)(t_g2),1);
		if(m_Descriptions[m_WavInit].Length()<21 && t_g2>31 && ((bb_slksound_FString(String(t_g2))).Length()!=0)){
			m_Descriptions[m_WavInit]=m_Descriptions[m_WavInit]+t_gch2;
		}
		if((bb_input_KeyHit(13))!=0){
			for(int t_n=m_Descriptions[m_WavInit].Length();t_n<=20;t_n=t_n+1){
				m_Descriptions[m_WavInit]=m_Descriptions[m_WavInit]+String(L" ",1);
			}
			m_InstDescriptionOn=0;
		}
		if(((bb_input_KeyHit(8))!=0) || ((bb_input_KeyHit(46))!=0)){
			m_Descriptions[m_WavInit]=String();
		}
	}
	if(bb_slksound_BigButtonZone(570,318,5)==5){
		m_i=0;
		m_pcount=0;
	}
	if(((bb_input_KeyHit(122))!=0) || bb_slksound_BigButtonZone(441,440,6)==6){
		m_StatusInfo=p_SaveFile(m_Filename);
	}
	if(((bb_input_KeyHit(123))!=0) || bb_slksound_BigButtonZone(387,440,7)==7){
		m_StatusInfo=p_LoadFile();
		m_i=0;
		m_pcount=0;
	}
	if(m_InsArrayData[m_WavInit*8]==1){
		gc_assign(m_CurrentWav,m_Ramp);
	}
	if(m_InsArrayData[m_WavInit*8]==2){
		gc_assign(m_CurrentWav,m_Ramp2);
	}
	if(m_InsArrayData[m_WavInit*8]==3){
		gc_assign(m_CurrentWav,m_Square);
	}
	if(m_InsArrayData[m_WavInit*8]==4){
		gc_assign(m_CurrentWav,m_Bass);
	}
	if(m_InsArrayData[m_WavInit*8]==5){
		gc_assign(m_CurrentWav,m_Ramp);
	}
	if(m_InsArrayData[m_WavInit*8]==6){
		gc_assign(m_CurrentWav,m_Noise);
	}
	if(m_InsArrayData[m_WavInit*8]==7){
		gc_assign(m_CurrentWav,m_HNoise);
	}
	if(m_InsArrayData[m_WavInit*8]==1){
		gc_assign(m_CurrentWav2,m_Saw);
	}
	if(m_InsArrayData[m_WavInit*8]==2){
		gc_assign(m_CurrentWav2,m_Saw);
	}
	if(m_InsArrayData[m_WavInit*8]==3){
		gc_assign(m_CurrentWav2,m_Saw);
	}
	if(m_InsArrayData[m_WavInit*8]==4){
		gc_assign(m_CurrentWav2,m_Zero);
	}
	if(m_InsArrayData[m_WavInit*8]==5){
		gc_assign(m_CurrentWav2,m_Zero);
	}
	if(m_InsArrayData[m_WavInit*8]==6){
		gc_assign(m_CurrentWav2,m_Zero);
	}
	if(m_InsArrayData[m_WavInit*8]==7){
		gc_assign(m_CurrentWav2,m_Zero);
	}
	m_PWM=Float(m_InsArrayData[m_WavInit*8+1]);
	if(!((m_FilenameInputOn)!=0) && !((m_InstDescriptionOn)!=0)){
		if((bb_input_KeyHit(45))!=0){
			Array<int > t_NewPatterns=Array<int >(255);
			for(int t_pcc=0;t_pcc<=m_pcount;t_pcc=t_pcc+1){
				t_NewPatterns[t_pcc]=m_Patterns[t_pcc];
			}
			t_NewPatterns[m_pcount]=0;
			for(int t_pcc2=m_pcount+1;t_pcc2<=255;t_pcc2=t_pcc2+1){
				t_NewPatterns[t_pcc2]=m_Patterns[t_pcc2-1];
			}
			gc_assign(m_Patterns,t_NewPatterns);
		}
		if((bb_input_KeyHit(8))!=0){
			Array<int > t_NewPatterns2=m_Patterns;
			for(int t_pcc3=m_pcount;t_pcc3<=255;t_pcc3=t_pcc3+1){
				t_NewPatterns2[t_pcc3]=m_Patterns[t_pcc3+1];
			}
			gc_assign(m_Patterns,t_NewPatterns2);
		}
	}
	if((bb_input_KeyHit(9))!=0){
		m_EDIT_CHANNEL+=2;
		bb_slksound_PauseAll();
	}
	if((bb_input_KeyHit(39))!=0){
		m_EDIT_CHANNEL+=1;
		bb_slksound_PauseAll();
	}
	if((bb_input_KeyHit(37))!=0){
		m_EDIT_CHANNEL-=1;
		bb_slksound_PauseAll();
	}
	if(m_EDIT_CHANNEL<1){
		m_EDIT_CHANNEL=8;
	}
	if(m_EDIT_CHANNEL>8){
		m_EDIT_CHANNEL=1;
	}
	if(((bb_input_KeyHit(33))!=0) && m_pcount>0){
		m_pcount-=1;
		m_ppos=m_Patterns[m_pcount]*32;
	}
	if((bb_input_KeyHit(34))!=0){
		m_pcount+=1;
		m_ppos=m_Patterns[m_pcount]*32;
	}
	if((bb_input_KeyDown(38))!=0){
		m_Press1+=1;
		if(m_Press1>12){
			m_Cursorpos-=1;
		}
	}else{
		m_Press1=0;
	}
	if((bb_input_KeyDown(40))!=0){
		m_Press2+=1;
		if(m_Press2>12){
			m_Cursorpos+=1;
		}
	}else{
		m_Press2=0;
	}
	if((bb_input_KeyHit(38))!=0){
		m_Cursorpos-=1;
	}
	if((bb_input_KeyHit(40))!=0){
		m_Cursorpos+=1;
	}
	if(m_Cursorpos>32){
		m_Cursorpos=1;
	}
	if(m_Cursorpos<1){
		m_Cursorpos=32;
	}
	String t_gch3=String();
	int t_g3=0;
	t_g3=bb_input_GetChar();
	if((m_USA)!=0){
		int t_g22=0;
		if(t_g3==121 || t_g3==89){
			t_g22=122;
		}
		if(t_g3==122 || t_g3==90){
			t_g22=121;
		}
		if((t_g22)!=0){
			t_g3=t_g22;
		}
	}
	t_gch3=String((Char)(t_g3),1);
	if(m_STATUS==0 && m_FilenameInputOn==0 && m_InstDescriptionOn==0){
		if(m_EDIT_CHANNEL==2 || m_EDIT_CHANNEL==4 || m_EDIT_CHANNEL==6 || m_EDIT_CHANNEL==8){
			if(m_EDIT_CHANNEL==2 && t_g3>47 && t_g3<58 || m_EDIT_CHANNEL==2 && t_g3>96 && t_g3<103){
				m_VolumeTrack1=bb_slksound_ChangeTrack(m_VolumeTrack1,m_i+m_ppos/32*32+m_Cursorpos,t_gch3.ToUpper());
				m_Cursorpos+=1;
			}
			if(m_EDIT_CHANNEL==4 && t_g3>47 && t_g3<58 || m_EDIT_CHANNEL==4 && t_g3>96 && t_g3<103){
				m_VolumeTrack2=bb_slksound_ChangeTrack(m_VolumeTrack2,m_i+m_ppos/32*32+m_Cursorpos,t_gch3.ToUpper());
				m_Cursorpos+=1;
			}
			if(m_EDIT_CHANNEL==6 && t_g3>47 && t_g3<58 || m_EDIT_CHANNEL==6 && t_g3>96 && t_g3<103){
				m_VolumeTrack3=bb_slksound_ChangeTrack(m_VolumeTrack3,m_i+m_ppos/32*32+m_Cursorpos,t_gch3.ToUpper());
				m_Cursorpos+=1;
			}
			if(m_EDIT_CHANNEL==8 && t_g3>47 && t_g3<58 || m_EDIT_CHANNEL==8 && t_g3>96 && t_g3<103){
				m_VolumeTrack4=bb_slksound_ChangeTrack(m_VolumeTrack4,m_i+m_ppos/32*32+m_Cursorpos,t_gch3.ToUpper());
				m_Cursorpos+=1;
			}
		}
	}
	if(((bb_input_KeyHit(120))!=0) || bb_slksound_BigButtonZone(516,359,3)==3 || bb_slksound_BigButtonZone(570,359,3)==3){
		if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
			m_CopyTrack=m_Track1.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
			m_CopyTrack=m_Track2.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
			m_CopyTrack=m_Track3.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
			m_CopyTrack=m_Track4.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
			m_CopyVolumeTrack=m_VolumeTrack1.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
			m_CopyVolumeTrack=m_VolumeTrack2.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
			m_CopyVolumeTrack=m_VolumeTrack3.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
			m_CopyVolumeTrack=m_VolumeTrack4.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
			m_CopyInstTrack=m_InstTrack1.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
			m_CopyInstTrack=m_InstTrack2.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
			m_CopyInstTrack=m_InstTrack3.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
			m_CopyInstTrack=m_InstTrack4.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
			m_CopyOctaveTrack=m_OctaveTrack1.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
			m_CopyOctaveTrack=m_OctaveTrack2.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
			m_CopyOctaveTrack=m_OctaveTrack3.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
		if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
			m_CopyOctaveTrack=m_OctaveTrack4.Slice(m_i+m_ppos/32*32,m_i+m_ppos/32*32+33);
		}
	}
	if(((bb_input_KeyHit(121))!=0) || bb_slksound_BigButtonZone(516,379,4)==4 || bb_slksound_BigButtonZone(570,379,4)==4){
		for(int t_g4=0;t_g4<=31;t_g4=t_g4+1){
			if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
				m_Track1=bb_slksound_ChangeTrack(m_Track1,m_i+m_ppos/32*32+t_g4+1,m_CopyTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
				m_Track2=bb_slksound_ChangeTrack(m_Track2,m_i+m_ppos/32*32+t_g4+1,m_CopyTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
				m_Track3=bb_slksound_ChangeTrack(m_Track3,m_i+m_ppos/32*32+t_g4+1,m_CopyTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
				m_Track4=bb_slksound_ChangeTrack(m_Track4,m_i+m_ppos/32*32+t_g4+1,m_CopyTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
				m_VolumeTrack1=bb_slksound_ChangeTrack(m_VolumeTrack1,m_i+m_ppos/32*32+t_g4+1,m_CopyVolumeTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
				m_VolumeTrack2=bb_slksound_ChangeTrack(m_VolumeTrack2,m_i+m_ppos/32*32+t_g4+1,m_CopyVolumeTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
				m_VolumeTrack3=bb_slksound_ChangeTrack(m_VolumeTrack3,m_i+m_ppos/32*32+t_g4+1,m_CopyVolumeTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
				m_VolumeTrack4=bb_slksound_ChangeTrack(m_VolumeTrack4,m_i+m_ppos/32*32+t_g4+1,m_CopyVolumeTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
				m_InstTrack1=bb_slksound_ChangeTrack(m_InstTrack1,m_i+m_ppos/32*32+t_g4+1,m_CopyInstTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
				m_InstTrack2=bb_slksound_ChangeTrack(m_InstTrack2,m_i+m_ppos/32*32+t_g4+1,m_CopyInstTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
				m_InstTrack3=bb_slksound_ChangeTrack(m_InstTrack3,m_i+m_ppos/32*32+t_g4+1,m_CopyInstTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
				m_InstTrack4=bb_slksound_ChangeTrack(m_InstTrack4,m_i+m_ppos/32*32+t_g4+1,m_CopyInstTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==2){
				m_OctaveTrack1=bb_slksound_ChangeTrack(m_OctaveTrack1,m_i+m_ppos/32*32+t_g4+1,m_CopyOctaveTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==4){
				m_OctaveTrack2=bb_slksound_ChangeTrack(m_OctaveTrack2,m_i+m_ppos/32*32+t_g4+1,m_CopyOctaveTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==6){
				m_OctaveTrack3=bb_slksound_ChangeTrack(m_OctaveTrack3,m_i+m_ppos/32*32+t_g4+1,m_CopyOctaveTrack.Slice(t_g4,1+t_g4));
			}
			if(m_EDIT_CHANNEL==7 || m_EDIT_CHANNEL==8){
				m_OctaveTrack4=bb_slksound_ChangeTrack(m_OctaveTrack4,m_i+m_ppos/32*32+t_g4+1,m_CopyOctaveTrack.Slice(t_g4,1+t_g4));
			}
		}
	}
	if(m_EDIT_CHANNEL==1 || m_EDIT_CHANNEL==3 || m_EDIT_CHANNEL==5 || m_EDIT_CHANNEL==7){
		if(m_EDIT_CHANNEL==1 && t_g3>96 && t_g3<128 || m_EDIT_CHANNEL==1 && t_g3>45 && t_g3<61 || m_EDIT_CHANNEL==1 && t_g3==43 || m_EDIT_CHANNEL==1 && t_g3==35 || m_EDIT_CHANNEL==1 && t_g3==45){
			if(t_g3!=43 && t_g3!=35 && t_g3!=46 && t_g3!=45){
				m_Lastgch=t_gch3;
			}
			if(m_STATUS==0){
				m_Track1=bb_slksound_ChangeTrack(m_Track1,m_i+m_ppos/32*32+m_Cursorpos,t_gch3);
				m_InstTrack1=bb_slksound_ChangeTrack(m_InstTrack1,m_i+m_ppos/32*32+m_Cursorpos,bb_slksound_Int2Char(m_WavInit));
				m_OctaveTrack1=bb_slksound_ChangeTrack(m_OctaveTrack1,m_i+m_ppos/32*32+m_Cursorpos,String(m_oct));
				if(t_gch3==String(L".",1) || t_gch3==String(L"+",1) || t_gch3==String(L"#",1) || t_gch3==String(L"-",1)){
					m_InstTrack1=bb_slksound_ChangeTrack(m_InstTrack1,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
					m_OctaveTrack1=bb_slksound_ChangeTrack(m_OctaveTrack1,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
				}else{
					if(m_VolumeTrack1.Slice(m_i+m_ppos/32*32+m_Cursorpos-1,m_i+m_ppos/32*32+m_Cursorpos)==String(L"0",1)){
						m_VolumeTrack1=bb_slksound_ChangeTrack(m_VolumeTrack1,m_i+m_ppos/32*32+m_Cursorpos,String(L"8",1));
					}
					m_Arpcounter=0;
					m_PWCount=0;
					m_Decay=FLOAT(0.0);
					p_Undo();
				}
				m_Cursorpos+=1;
			}
			if(m_STATUS==2){
				m_Arpcounter=0;
				m_PWCount=0;
				m_Decay=FLOAT(0.0);
			}
			String t_gch22=t_gch3;
			bb_slksound_PlayInst(m_CurrentWav,bb_slksound_PlayTrack(t_gch22,0)-24+m_oct*12,1,1,m_CurrentWav2,m_PWM,1,FLOAT(0.0),m_oct);
		}
		if(m_EDIT_CHANNEL==3 && t_g3>96 && t_g3<128 || m_EDIT_CHANNEL==3 && t_g3>45 && t_g3<61 || m_EDIT_CHANNEL==3 && t_g3==43 || m_EDIT_CHANNEL==3 && t_g3==35 || m_EDIT_CHANNEL==3 && t_g3==45){
			if(t_g3!=43 && t_g3!=35 && t_g3!=46 && t_g3!=45){
				m_Lastgch=t_gch3;
			}
			if(m_STATUS==0){
				m_Track2=bb_slksound_ChangeTrack(m_Track2,m_i+m_ppos/32*32+m_Cursorpos,t_gch3);
				m_InstTrack2=bb_slksound_ChangeTrack(m_InstTrack2,m_i+m_ppos/32*32+m_Cursorpos,bb_slksound_Int2Char(m_WavInit));
				m_OctaveTrack2=bb_slksound_ChangeTrack(m_OctaveTrack2,m_i+m_ppos/32*32+m_Cursorpos,String(m_oct));
				if(t_gch3==String(L".",1) || t_gch3==String(L"+",1) || t_gch3==String(L"#",1) || t_gch3==String(L"-",1)){
					m_InstTrack2=bb_slksound_ChangeTrack(m_InstTrack2,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
					m_OctaveTrack2=bb_slksound_ChangeTrack(m_OctaveTrack2,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
				}else{
					if(m_VolumeTrack2.Slice(m_i+m_ppos/32*32+m_Cursorpos-1,m_i+m_ppos/32*32+m_Cursorpos)==String(L"0",1)){
						m_VolumeTrack2=bb_slksound_ChangeTrack(m_VolumeTrack2,m_i+m_ppos/32*32+m_Cursorpos,String(L"8",1));
					}
					m_Arpcounter=0;
					m_PWCount=0;
					m_Decay=FLOAT(0.0);
					p_Undo();
				}
				m_Cursorpos+=1;
			}
			if(m_STATUS==2){
				m_Arpcounter=0;
				m_PWCount=0;
				m_Decay=FLOAT(0.0);
			}
			String t_gch23=t_gch3;
			bb_slksound_PlayInst(m_CurrentWav,bb_slksound_PlayTrack(t_gch23,0)-24+m_oct*12,2,1,m_CurrentWav2,m_PWM,1,FLOAT(0.0),m_oct);
		}
		if(m_EDIT_CHANNEL==5 && t_g3>96 && t_g3<128 || m_EDIT_CHANNEL==5 && t_g3>45 && t_g3<61 || m_EDIT_CHANNEL==5 && t_g3==43 || m_EDIT_CHANNEL==5 && t_g3==35 || m_EDIT_CHANNEL==5 && t_g3==45){
			if(t_g3!=43 && t_g3!=35 && t_g3!=46 && t_g3!=45){
				m_Lastgch=t_gch3;
			}
			if(m_STATUS==0){
				m_Track3=bb_slksound_ChangeTrack(m_Track3,m_i+m_ppos/32*32+m_Cursorpos,t_gch3);
				m_InstTrack3=bb_slksound_ChangeTrack(m_InstTrack3,m_i+m_ppos/32*32+m_Cursorpos,bb_slksound_Int2Char(m_WavInit));
				m_OctaveTrack3=bb_slksound_ChangeTrack(m_OctaveTrack3,m_i+m_ppos/32*32+m_Cursorpos,String(m_oct));
				if(t_gch3==String(L".",1) || t_gch3==String(L"+",1) || t_gch3==String(L"#",1) || t_gch3==String(L"-",1)){
					m_InstTrack3=bb_slksound_ChangeTrack(m_InstTrack3,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
					m_OctaveTrack3=bb_slksound_ChangeTrack(m_OctaveTrack3,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
				}else{
					if(m_VolumeTrack3.Slice(m_i+m_ppos/32*32+m_Cursorpos-1,m_i+m_ppos/32*32+m_Cursorpos)==String(L"0",1)){
						m_VolumeTrack3=bb_slksound_ChangeTrack(m_VolumeTrack3,m_i+m_ppos/32*32+m_Cursorpos,String(L"8",1));
					}
					m_Arpcounter=0;
					m_PWCount=0;
					m_Decay=FLOAT(0.0);
					p_Undo();
				}
				m_Cursorpos+=1;
			}
			if(m_STATUS==2){
				m_Arpcounter=0;
				m_PWCount=0;
				m_Decay=FLOAT(0.0);
			}
			String t_gch24=t_gch3;
			bb_slksound_PlayInst(m_CurrentWav,bb_slksound_PlayTrack(t_gch24,0)-24+m_oct*12,3,1,m_CurrentWav2,m_PWM,1,FLOAT(0.0),m_oct);
		}
		if(m_EDIT_CHANNEL==7 && t_g3>96 && t_g3<128 || m_EDIT_CHANNEL==7 && t_g3>45 && t_g3<61 || m_EDIT_CHANNEL==7 && t_g3==43 || m_EDIT_CHANNEL==7 && t_g3==35 || m_EDIT_CHANNEL==7 && t_g3==45){
			if(t_g3!=43 && t_g3!=35 && t_g3!=46 && t_g3!=45){
				m_Lastgch=t_gch3;
			}
			if(m_STATUS==0){
				m_Track4=bb_slksound_ChangeTrack(m_Track4,m_i+m_ppos/32*32+m_Cursorpos,t_gch3);
				m_InstTrack4=bb_slksound_ChangeTrack(m_InstTrack4,m_i+m_ppos/32*32+m_Cursorpos,bb_slksound_Int2Char(m_WavInit));
				m_OctaveTrack4=bb_slksound_ChangeTrack(m_OctaveTrack4,m_i+m_ppos/32*32+m_Cursorpos,String(m_oct));
				if(t_gch3==String(L".",1) || t_gch3==String(L"+",1) || t_gch3==String(L"#",1) || t_gch3==String(L"-",1)){
					m_InstTrack4=bb_slksound_ChangeTrack(m_InstTrack4,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
					m_OctaveTrack4=bb_slksound_ChangeTrack(m_OctaveTrack4,m_i+m_ppos/32*32+m_Cursorpos,String(L"0",1));
				}else{
					if(m_VolumeTrack4.Slice(m_i+m_ppos/32*32+m_Cursorpos-1,m_i+m_ppos/32*32+m_Cursorpos)==String(L"0",1)){
						m_VolumeTrack4=bb_slksound_ChangeTrack(m_VolumeTrack4,m_i+m_ppos/32*32+m_Cursorpos,String(L"8",1));
					}
					m_Arpcounter=0;
					m_PWCount=0;
					m_Decay=FLOAT(0.0);
					p_Undo();
				}
				m_Cursorpos+=1;
			}
			if(m_STATUS==2){
				m_Arpcounter=0;
				m_PWCount=0;
				m_Decay=FLOAT(0.0);
			}
			String t_gch25=t_gch3;
			bb_slksound_PlayInst(m_CurrentWav,bb_slksound_PlayTrack(t_gch25,0)-24+m_oct*12,4,1,m_CurrentWav2,m_PWM,1,FLOAT(0.0),m_oct);
		}
	}
	m_Decay+=FLOAT(0.10000000000000001)/Float(m_InsArrayData[m_WavInit*8+4]);
	if(m_Decay>FLOAT(1.0)){
		m_Decay=FLOAT(1.0);
	}
	bb_audio_SetChannelVolume(1,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(2,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(3,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(4,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(5,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(6,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(7,FLOAT(1.0)-m_Decay);
	bb_audio_SetChannelVolume(8,FLOAT(1.0)-m_Decay);
	if((m_InsArrayData[m_WavInit*8+2])!=0){
		m_Dec2Pitch=m_Decay;
	}
	m_ArpSpd=m_InsArrayData[m_WavInit*8+5];
	if(m_Arpcounter==0){
		m_fxval=FLOAT(0.0);
	}
	if(m_Arpcounter==1*m_ArpSpd){
		m_fxval=Float(m_InsArrayData[m_WavInit*8+6])/FLOAT(15.0)*Float(m_InsArrayData[m_WavInit*8+3]-m_InsArrayData[m_WavInit*8+3]/16*16);
	}
	if(m_Arpcounter==2*m_ArpSpd){
		m_fxval=Float(m_InsArrayData[m_WavInit*8+7])/FLOAT(15.0)*Float(m_InsArrayData[m_WavInit*8+3]-m_InsArrayData[m_WavInit*8+3]/16*16);
	}
	m_Arpcounter+=1;
	if(m_Arpcounter==3*m_ArpSpd){
		m_Arpcounter=0;
	}
	m_PWDepth=m_InsArrayData[m_WavInit*8+3]/16*2;
	m_PWCount+=1;
	if(m_PWCount<m_PWDepth/2){
		m_PWVal=1;
	}
	if(m_PWCount>m_PWDepth/2){
		m_PWVal=-1;
	}
	if(m_PWCount==m_PWDepth){
		m_PWCount=0;
	}
	if(m_PWDepth==0){
		m_PWVal=1;
	}
	bb_audio_SetChannelRate(1,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(5,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)+m_PWM/FLOAT(800.0)*Float(m_PWVal)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(2,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(6,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)+m_PWM/FLOAT(800.0)*Float(m_PWVal)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(3,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(7,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)+m_PWM/FLOAT(800.0)*Float(m_PWVal)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(4,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	bb_audio_SetChannelRate(8,(Float)pow(FLOAT(1.059463094),Float(bb_slksound_PlayTrack(m_Lastgch,0)-24+m_oct*12)+m_fxval)+m_PWM/FLOAT(800.0)*Float(m_PWVal)-m_Dec2Pitch*Float(m_InsArrayData[m_WavInit*8+2]));
	return 0;
}
Float c_SoundEngine::m_p1;
Float c_SoundEngine::m_last_p1;
Float c_SoundEngine::m_fine_p1;
Float c_SoundEngine::m_fxval1;
Float c_SoundEngine::m_Vib1;
int c_SoundEngine::m_Arpcounter1;
int c_SoundEngine::m_PWCount1;
Float c_SoundEngine::m_Decay1;
Float c_SoundEngine::m_p2;
Float c_SoundEngine::m_last_p2;
Float c_SoundEngine::m_fine_p2;
Float c_SoundEngine::m_fxval2;
Float c_SoundEngine::m_Vib2;
int c_SoundEngine::m_Arpcounter2;
int c_SoundEngine::m_PWCount2;
Float c_SoundEngine::m_Decay2;
Float c_SoundEngine::m_p3;
Float c_SoundEngine::m_last_p3;
Float c_SoundEngine::m_fine_p3;
Float c_SoundEngine::m_fxval3;
Float c_SoundEngine::m_Vib3;
int c_SoundEngine::m_Arpcounter3;
int c_SoundEngine::m_PWCount3;
Float c_SoundEngine::m_Decay3;
Float c_SoundEngine::m_p4;
Float c_SoundEngine::m_last_p4;
Float c_SoundEngine::m_fine_p4;
Float c_SoundEngine::m_fxval4;
Float c_SoundEngine::m_Vib4;
int c_SoundEngine::m_Arpcounter4;
int c_SoundEngine::m_PWCount4;
Float c_SoundEngine::m_Decay4;
int c_SoundEngine::m_InstNo1;
int c_SoundEngine::m_InstNo2;
int c_SoundEngine::m_InstNo3;
int c_SoundEngine::m_InstNo4;
Float c_SoundEngine::m_volval1;
Float c_SoundEngine::m_volval2;
Float c_SoundEngine::m_volval3;
Float c_SoundEngine::m_volval4;
int c_SoundEngine::m_oct1;
int c_SoundEngine::m_oct2;
int c_SoundEngine::m_oct3;
int c_SoundEngine::m_oct4;
c_Sound* c_SoundEngine::m_Chan1wav;
c_Sound* c_SoundEngine::m_Chan5wav;
c_Sound* c_SoundEngine::m_Chan2wav;
c_Sound* c_SoundEngine::m_Chan6wav;
c_Sound* c_SoundEngine::m_Chan3wav;
c_Sound* c_SoundEngine::m_Chan7wav;
c_Sound* c_SoundEngine::m_Chan4wav;
c_Sound* c_SoundEngine::m_Chan8wav;
Float c_SoundEngine::m_PWM1;
Float c_SoundEngine::m_PWM2;
Float c_SoundEngine::m_PWM3;
Float c_SoundEngine::m_PWM4;
int c_SoundEngine::m_LastInstNo1;
int c_SoundEngine::m_LastInstNo2;
int c_SoundEngine::m_LastInstNo3;
int c_SoundEngine::m_LastInstNo4;
int c_SoundEngine::m_LastOct1;
int c_SoundEngine::m_LastOct2;
int c_SoundEngine::m_LastOct3;
int c_SoundEngine::m_LastOct4;
Float c_SoundEngine::m_Dec2Pitch1;
Float c_SoundEngine::m_Dec2Pitch2;
Float c_SoundEngine::m_Dec2Pitch3;
Float c_SoundEngine::m_Dec2Pitch4;
int c_SoundEngine::m_ArpSpd1;
int c_SoundEngine::m_ArpSpd2;
int c_SoundEngine::m_ArpSpd3;
int c_SoundEngine::m_ArpSpd4;
int c_SoundEngine::m_PWDepth1;
int c_SoundEngine::m_PWVal1;
int c_SoundEngine::m_PWDepth2;
int c_SoundEngine::m_PWVal2;
int c_SoundEngine::m_PWDepth3;
int c_SoundEngine::m_PWVal3;
int c_SoundEngine::m_PWDepth4;
int c_SoundEngine::m_PWVal4;
Float c_SoundEngine::p_Play(){
	if(m_Frame==m_spd){
		m_p1=Float(bb_slksound_PlayTrack(m_Track1,m_i+m_ppos));
		if(m_p1>FLOAT(47.0) && m_p1<FLOAT(127.0)){
			m_p1=m_last_p1;
		}
		if(m_p1<FLOAT(127.0)){
			m_fine_p1=m_p1;
		}
		if(m_p1<FLOAT(127.0)){
			m_fxval1=FLOAT(0.00);
		}
		if(m_p1<FLOAT(127.0)){
			m_Vib1=FLOAT(0.00);
		}
		if(m_p1<FLOAT(127.0)){
			m_Arpcounter1=0;
		}
		if(m_p1<FLOAT(127.0)){
			m_PWCount1=0;
		}
		if(m_p1<FLOAT(127.0)){
			m_Decay1=FLOAT(0.00);
		}
		m_p2=Float(bb_slksound_PlayTrack(m_Track2,m_i+m_ppos));
		if(m_p2>FLOAT(47.0) && m_p2<FLOAT(127.0)){
			m_p2=m_last_p2;
		}
		if(m_p2<FLOAT(127.0)){
			m_fine_p2=m_p2;
		}
		if(m_p2<FLOAT(127.0)){
			m_fxval2=FLOAT(0.00);
		}
		if(m_p2<FLOAT(127.0)){
			m_Vib2=FLOAT(0.00);
		}
		if(m_p2<FLOAT(127.0)){
			m_Arpcounter2=0;
		}
		if(m_p2<FLOAT(127.0)){
			m_PWCount2=0;
		}
		if(m_p2<FLOAT(127.0)){
			m_Decay2=FLOAT(0.00);
		}
		m_p3=Float(bb_slksound_PlayTrack(m_Track3,m_i+m_ppos));
		if(m_p3>FLOAT(47.0) && m_p3<FLOAT(127.0)){
			m_p3=m_last_p3;
		}
		if(m_p3<FLOAT(127.0)){
			m_fine_p3=m_p3;
		}
		if(m_p3<FLOAT(127.0)){
			m_fxval3=FLOAT(0.00);
		}
		if(m_p3<FLOAT(127.0)){
			m_Vib3=FLOAT(0.00);
		}
		if(m_p3<FLOAT(127.0)){
			m_Arpcounter3=0;
		}
		if(m_p3<FLOAT(127.0)){
			m_PWCount3=0;
		}
		if(m_p3<FLOAT(127.0)){
			m_Decay3=FLOAT(0.00);
		}
		m_p4=Float(bb_slksound_PlayTrack(m_Track4,m_i+m_ppos));
		if(m_p4>FLOAT(47.0) && m_p4<FLOAT(127.0)){
			m_p4=m_last_p4;
		}
		if(m_p4<FLOAT(127.0)){
			m_fine_p4=m_p4;
		}
		if(m_p4<FLOAT(127.0)){
			m_fxval4=FLOAT(0.00);
		}
		if(m_p4<FLOAT(127.0)){
			m_Vib4=FLOAT(0.00);
		}
		if(m_p4<FLOAT(127.0)){
			m_Arpcounter4=0;
		}
		if(m_p4<FLOAT(127.0)){
			m_PWCount4=0;
		}
		if(m_p4<FLOAT(127.0)){
			m_Decay4=FLOAT(0.00);
		}
		m_InstNo1=bb_slksound_Char2Int(m_InstTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1));
		m_InstNo2=bb_slksound_Char2Int(m_InstTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1));
		m_InstNo3=bb_slksound_Char2Int(m_InstTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1));
		m_InstNo4=bb_slksound_Char2Int(m_InstTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1));
		if((bb_slksound_Char2Int(m_VolumeTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)))!=0){
			m_volval1=FLOAT(0.125)*Float(bb_slksound_Char2Int(m_VolumeTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)))*m_CHOn1;
		}
		if((bb_slksound_Char2Int(m_VolumeTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)))!=0){
			m_volval2=FLOAT(0.125)*Float(bb_slksound_Char2Int(m_VolumeTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)))*m_CHOn2;
		}
		if((bb_slksound_Char2Int(m_VolumeTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)))!=0){
			m_volval3=FLOAT(0.125)*Float(bb_slksound_Char2Int(m_VolumeTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)))*m_CHOn3;
		}
		if((bb_slksound_Char2Int(m_VolumeTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)))!=0){
			m_volval4=FLOAT(0.125)*Float(bb_slksound_Char2Int(m_VolumeTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)))*m_CHOn4;
		}
		m_oct1=(m_OctaveTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt();
		m_oct2=(m_OctaveTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt();
		m_oct3=(m_OctaveTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt();
		m_oct4=(m_OctaveTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt();
		if(m_InsArrayData[m_InstNo1*8]==1){
			gc_assign(m_Chan1wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo1*8]==2){
			gc_assign(m_Chan1wav,m_Ramp2);
		}
		if(m_InsArrayData[m_InstNo1*8]==3){
			gc_assign(m_Chan1wav,m_Square);
		}
		if(m_InsArrayData[m_InstNo1*8]==4){
			gc_assign(m_Chan1wav,m_Bass);
		}
		if(m_InsArrayData[m_InstNo1*8]==5){
			gc_assign(m_Chan1wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo1*8]==6){
			gc_assign(m_Chan1wav,m_Noise);
		}
		if(m_InsArrayData[m_InstNo1*8]==7){
			gc_assign(m_Chan1wav,m_HNoise);
		}
		if(m_InsArrayData[m_InstNo1*8]==1){
			gc_assign(m_Chan5wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo1*8]==2){
			gc_assign(m_Chan5wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo1*8]==3){
			gc_assign(m_Chan5wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo1*8]==4){
			gc_assign(m_Chan5wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo1*8]==5){
			gc_assign(m_Chan5wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo1*8]==6){
			gc_assign(m_Chan5wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo1*8]==7){
			gc_assign(m_Chan5wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo2*8]==1){
			gc_assign(m_Chan2wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo2*8]==2){
			gc_assign(m_Chan2wav,m_Ramp2);
		}
		if(m_InsArrayData[m_InstNo2*8]==3){
			gc_assign(m_Chan2wav,m_Square);
		}
		if(m_InsArrayData[m_InstNo2*8]==4){
			gc_assign(m_Chan2wav,m_Bass);
		}
		if(m_InsArrayData[m_InstNo2*8]==5){
			gc_assign(m_Chan2wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo2*8]==6){
			gc_assign(m_Chan2wav,m_Noise);
		}
		if(m_InsArrayData[m_InstNo2*8]==7){
			gc_assign(m_Chan2wav,m_HNoise);
		}
		if(m_InsArrayData[m_InstNo2*8]==1){
			gc_assign(m_Chan6wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo2*8]==2){
			gc_assign(m_Chan6wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo2*8]==3){
			gc_assign(m_Chan6wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo2*8]==4){
			gc_assign(m_Chan6wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo2*8]==5){
			gc_assign(m_Chan6wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo2*8]==6){
			gc_assign(m_Chan6wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo2*8]==7){
			gc_assign(m_Chan6wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo3*8]==1){
			gc_assign(m_Chan3wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo3*8]==2){
			gc_assign(m_Chan3wav,m_Ramp2);
		}
		if(m_InsArrayData[m_InstNo3*8]==3){
			gc_assign(m_Chan3wav,m_Square);
		}
		if(m_InsArrayData[m_InstNo3*8]==4){
			gc_assign(m_Chan3wav,m_Bass);
		}
		if(m_InsArrayData[m_InstNo3*8]==5){
			gc_assign(m_Chan3wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo3*8]==6){
			gc_assign(m_Chan3wav,m_Noise);
		}
		if(m_InsArrayData[m_InstNo3*8]==7){
			gc_assign(m_Chan3wav,m_HNoise);
		}
		if(m_InsArrayData[m_InstNo3*8]==1){
			gc_assign(m_Chan7wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo3*8]==2){
			gc_assign(m_Chan7wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo3*8]==3){
			gc_assign(m_Chan7wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo3*8]==4){
			gc_assign(m_Chan7wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo3*8]==5){
			gc_assign(m_Chan7wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo3*8]==6){
			gc_assign(m_Chan7wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo3*8]==7){
			gc_assign(m_Chan7wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo4*8]==1){
			gc_assign(m_Chan4wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo4*8]==2){
			gc_assign(m_Chan4wav,m_Ramp2);
		}
		if(m_InsArrayData[m_InstNo4*8]==3){
			gc_assign(m_Chan4wav,m_Square);
		}
		if(m_InsArrayData[m_InstNo4*8]==4){
			gc_assign(m_Chan4wav,m_Bass);
		}
		if(m_InsArrayData[m_InstNo4*8]==5){
			gc_assign(m_Chan4wav,m_Ramp);
		}
		if(m_InsArrayData[m_InstNo4*8]==6){
			gc_assign(m_Chan4wav,m_Noise);
		}
		if(m_InsArrayData[m_InstNo4*8]==7){
			gc_assign(m_Chan4wav,m_HNoise);
		}
		if(m_InsArrayData[m_InstNo4*8]==1){
			gc_assign(m_Chan8wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo4*8]==2){
			gc_assign(m_Chan8wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo4*8]==3){
			gc_assign(m_Chan8wav,m_Saw);
		}
		if(m_InsArrayData[m_InstNo4*8]==4){
			gc_assign(m_Chan8wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo4*8]==5){
			gc_assign(m_Chan8wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo4*8]==6){
			gc_assign(m_Chan8wav,m_Zero);
		}
		if(m_InsArrayData[m_InstNo4*8]==7){
			gc_assign(m_Chan8wav,m_Zero);
		}
		if((m_InstNo1)!=0){
			m_PWM1=Float(m_InsArrayData[m_InstNo1*8+1]);
		}
		if((m_InstNo2)!=0){
			m_PWM2=Float(m_InsArrayData[m_InstNo2*8+1]);
		}
		if((m_InstNo3)!=0){
			m_PWM3=Float(m_InsArrayData[m_InstNo3*8+1]);
		}
		if((m_InstNo4)!=0){
			m_PWM4=Float(m_InsArrayData[m_InstNo4*8+1]);
		}
		bb_slksound_PlayInst(m_Chan1wav,int(m_p1-FLOAT(24.0)+Float((m_OctaveTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*12)),1,1,m_Chan5wav,m_PWM1,int(Float(bb_slksound_Char2Int(m_VolumeTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)))),FLOAT(0.0),m_oct1);
		bb_slksound_PlayInst(m_Chan2wav,int(m_p2-FLOAT(24.0)+Float((m_OctaveTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*12)),2,1,m_Chan6wav,m_PWM2,int(Float(bb_slksound_Char2Int(m_VolumeTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)))),FLOAT(0.0),m_oct2);
		bb_slksound_PlayInst(m_Chan3wav,int(m_p3-FLOAT(24.0)+Float((m_OctaveTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*12)),3,1,m_Chan7wav,m_PWM3,int(Float(bb_slksound_Char2Int(m_VolumeTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)))),FLOAT(0.0),m_oct3);
		bb_slksound_PlayInst(m_Chan4wav,int(m_p4-FLOAT(24.0)+Float((m_OctaveTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*12)),4,1,m_Chan8wav,m_PWM4,int(Float(bb_slksound_Char2Int(m_VolumeTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)))),FLOAT(0.0),m_oct4);
		if((m_InstNo1)!=0){
			m_LastInstNo1=m_InstNo1;
		}
		if((m_InstNo2)!=0){
			m_LastInstNo2=m_InstNo2;
		}
		if((m_InstNo3)!=0){
			m_LastInstNo3=m_InstNo3;
		}
		if((m_InstNo4)!=0){
			m_LastInstNo4=m_InstNo4;
		}
		if((m_InstNo1)!=0){
			m_LastOct1=m_oct1;
		}
		if((m_InstNo2)!=0){
			m_LastOct2=m_oct2;
		}
		if((m_InstNo3)!=0){
			m_LastOct3=m_oct3;
		}
		if((m_InstNo4)!=0){
			m_LastOct4=m_oct4;
		}
		m_last_p1=m_p1;
		m_last_p2=m_p2;
		m_last_p3=m_p3;
		m_last_p4=m_p4;
		if(m_last_p1==FLOAT(130.0)){
			m_i=31;
		}
		if(m_last_p2==FLOAT(130.0)){
			m_i=31;
		}
		if(m_last_p3==FLOAT(130.0)){
			m_i=31;
		}
		if(m_last_p4==FLOAT(130.0)){
			m_i=31;
		}
		m_i+=1;
		if(m_i==32){
			m_pcount+=1;
			if(m_pcount==m_Songlength/32){
				m_pcount=0;
			}
			m_i=0;
		}
		m_Frame=0;
	}
	if(m_Decay1<FLOAT(1.0)){
		m_Decay1+=FLOAT(0.10000000000000001)/Float(m_InsArrayData[m_LastInstNo1*8+4]);
	}
	if(m_volval1-m_Decay1<FLOAT(0.0)){
		m_volval1=FLOAT(0.0);
		m_Decay1=FLOAT(0.0);
	}
	if(m_Decay2<FLOAT(1.0)){
		m_Decay2+=FLOAT(0.10000000000000001)/Float(m_InsArrayData[m_LastInstNo2*8+4]);
	}
	if(m_volval2-m_Decay2<FLOAT(0.0)){
		m_volval2=FLOAT(0.0);
		m_Decay2=FLOAT(0.0);
	}
	if(m_Decay3<FLOAT(1.0)){
		m_Decay3+=FLOAT(0.10000000000000001)/Float(m_InsArrayData[m_LastInstNo3*8+4]);
	}
	if(m_volval3-m_Decay3<FLOAT(0.0)){
		m_volval3=FLOAT(0.0);
		m_Decay3=FLOAT(0.0);
	}
	if(m_Decay4<FLOAT(1.0)){
		m_Decay4+=FLOAT(0.10000000000000001)/Float(m_InsArrayData[m_LastInstNo4*8+4]);
	}
	if(m_volval4-m_Decay4<FLOAT(0.0)){
		m_volval4=FLOAT(0.0);
		m_Decay4=FLOAT(0.0);
	}
	bb_audio_SetChannelVolume(1,m_volval1-m_Decay1);
	bb_audio_SetChannelVolume(5,m_volval1-m_Decay1);
	bb_audio_SetChannelVolume(2,m_volval2-m_Decay2);
	bb_audio_SetChannelVolume(6,m_volval2-m_Decay2);
	bb_audio_SetChannelVolume(3,m_volval3-m_Decay3);
	bb_audio_SetChannelVolume(7,m_volval3-m_Decay3);
	bb_audio_SetChannelVolume(4,m_volval4-m_Decay4);
	bb_audio_SetChannelVolume(8,m_volval4-m_Decay4);
	if((m_InsArrayData[m_LastInstNo1*8+2])!=0){
		m_Dec2Pitch1=m_Decay1;
	}
	if((m_InsArrayData[m_LastInstNo2*8+2])!=0){
		m_Dec2Pitch2=m_Decay2;
	}
	if((m_InsArrayData[m_LastInstNo3*8+2])!=0){
		m_Dec2Pitch3=m_Decay3;
	}
	if((m_InsArrayData[m_LastInstNo4*8+2])!=0){
		m_Dec2Pitch4=m_Decay4;
	}
	m_ArpSpd1=m_InsArrayData[m_LastInstNo1*8+5];
	m_ArpSpd2=m_InsArrayData[m_LastInstNo2*8+5];
	m_ArpSpd3=m_InsArrayData[m_LastInstNo3*8+5];
	m_ArpSpd4=m_InsArrayData[m_LastInstNo4*8+5];
	if(m_Arpcounter1==0){
		m_fxval1=FLOAT(0.0);
	}
	if(m_Arpcounter1==1*m_ArpSpd1){
		m_fxval1=Float(m_InsArrayData[m_LastInstNo1*8+6])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo1*8+3]-m_InsArrayData[m_LastInstNo1*8+3]/16*16);
	}
	if(m_Arpcounter1==2*m_ArpSpd1){
		m_fxval1=Float(m_InsArrayData[m_LastInstNo1*8+7])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo1*8+3]-m_InsArrayData[m_LastInstNo1*8+3]/16*16);
	}
	if(m_Arpcounter2==0){
		m_fxval2=FLOAT(0.0);
	}
	if(m_Arpcounter2==1*m_ArpSpd2){
		m_fxval2=Float(m_InsArrayData[m_LastInstNo2*8+6])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo2*8+3]-m_InsArrayData[m_LastInstNo2*8+3]/16*16);
	}
	if(m_Arpcounter2==2*m_ArpSpd2){
		m_fxval2=Float(m_InsArrayData[m_LastInstNo2*8+7])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo2*8+3]-m_InsArrayData[m_LastInstNo2*8+3]/16*16);
	}
	if(m_Arpcounter3==0){
		m_fxval3=FLOAT(0.0);
	}
	if(m_Arpcounter3==1*m_ArpSpd3){
		m_fxval3=Float(m_InsArrayData[m_LastInstNo3*8+6])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo3*8+3]-m_InsArrayData[m_LastInstNo3*8+3]/16*16);
	}
	if(m_Arpcounter3==2*m_ArpSpd3){
		m_fxval3=Float(m_InsArrayData[m_LastInstNo3*8+7])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo3*8+3]-m_InsArrayData[m_LastInstNo3*8+3]/16*16);
	}
	if(m_Arpcounter4==0){
		m_fxval4=FLOAT(0.0);
	}
	if(m_Arpcounter4==1*m_ArpSpd4){
		m_fxval4=Float(m_InsArrayData[m_LastInstNo4*8+6])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo4*8+3]-m_InsArrayData[m_LastInstNo4*8+3]/16*16);
	}
	if(m_Arpcounter4==2*m_ArpSpd4){
		m_fxval4=Float(m_InsArrayData[m_LastInstNo4*8+7])/FLOAT(15.0)*Float(m_InsArrayData[m_LastInstNo4*8+3]-m_InsArrayData[m_LastInstNo4*8+3]/16*16);
	}
	m_Arpcounter1+=1;
	if(m_Arpcounter1==3*m_ArpSpd1){
		m_Arpcounter1=0;
	}
	m_Arpcounter2+=1;
	if(m_Arpcounter2==3*m_ArpSpd2){
		m_Arpcounter2=0;
	}
	m_Arpcounter3+=1;
	if(m_Arpcounter3==3*m_ArpSpd3){
		m_Arpcounter3=0;
	}
	m_Arpcounter4+=1;
	if(m_Arpcounter4==3*m_ArpSpd4){
		m_Arpcounter4=0;
	}
	m_PWDepth1=m_InsArrayData[m_LastInstNo1*8+3]/16*2;
	m_PWCount1+=1;
	if(m_PWCount1<m_PWDepth1/2){
		m_PWVal1=1;
	}
	if(m_PWCount1>m_PWDepth1/2){
		m_PWVal1=-1;
	}
	if(m_PWCount1==m_PWDepth1){
		m_PWCount1=0;
	}
	if(m_PWDepth1==0){
		m_PWVal1=1;
	}
	m_PWDepth2=m_InsArrayData[m_LastInstNo2*8+3]/16*2;
	m_PWCount2+=1;
	if(m_PWCount2<m_PWDepth2/2){
		m_PWVal2=1;
	}
	if(m_PWCount2>m_PWDepth2/2){
		m_PWVal2=-1;
	}
	if(m_PWCount2==m_PWDepth2){
		m_PWCount2=0;
	}
	if(m_PWDepth2==0){
		m_PWVal2=1;
	}
	m_PWDepth3=m_InsArrayData[m_LastInstNo3*8+3]/16*2;
	m_PWCount3+=1;
	if(m_PWCount3<m_PWDepth3/2){
		m_PWVal3=1;
	}
	if(m_PWCount3>m_PWDepth3/2){
		m_PWVal3=-1;
	}
	if(m_PWCount3==m_PWDepth3){
		m_PWCount3=0;
	}
	if(m_PWDepth3==0){
		m_PWVal3=1;
	}
	m_PWDepth4=m_InsArrayData[m_LastInstNo4*8+3]/16*2;
	m_PWCount4+=1;
	if(m_PWCount4<m_PWDepth4/2){
		m_PWVal4=1;
	}
	if(m_PWCount4>m_PWDepth4/2){
		m_PWVal4=-1;
	}
	if(m_PWCount4==m_PWDepth4){
		m_PWCount4=0;
	}
	if(m_PWDepth4==0){
		m_PWVal4=1;
	}
	if(m_last_p1==FLOAT(127.0)){
		m_Vib1-=FLOAT(0.005)*(m_volval1*FLOAT(8.0));
	}
	if(m_last_p1==FLOAT(129.0)){
		m_Vib1+=FLOAT(0.005)*(m_volval1*FLOAT(8.0));
	}
	if(m_last_p2==FLOAT(127.0)){
		m_Vib2-=FLOAT(0.005)*(m_volval2*FLOAT(8.0));
	}
	if(m_last_p2==FLOAT(129.0)){
		m_Vib2+=FLOAT(0.005)*(m_volval2*FLOAT(8.0));
	}
	if(m_last_p3==FLOAT(127.0)){
		m_Vib3-=FLOAT(0.005)*(m_volval3*FLOAT(8.0));
	}
	if(m_last_p3==FLOAT(129.0)){
		m_Vib3+=FLOAT(0.005)*(m_volval3*FLOAT(8.0));
	}
	if(m_last_p4==FLOAT(127.0)){
		m_Vib4-=FLOAT(0.005)*(m_volval4*FLOAT(8.0));
	}
	if(m_last_p4==FLOAT(129.0)){
		m_Vib4+=FLOAT(0.005)*(m_volval4*FLOAT(8.0));
	}
	bb_audio_SetChannelRate(1,(Float)pow(FLOAT(1.059463094),m_fine_p1-FLOAT(24.0)+Float(m_LastOct1*12)+m_fxval1)+m_Vib1-m_Dec2Pitch1*Float(m_InsArrayData[m_LastInstNo1*8+2]));
	bb_audio_SetChannelRate(5,(Float)pow(FLOAT(1.059463094),m_fine_p1-FLOAT(24.0)+Float(m_LastOct1*12)+m_fxval1)+m_Vib1+m_PWM1/FLOAT(800.0)*Float(m_PWVal1)-m_Dec2Pitch1*Float(m_InsArrayData[m_LastInstNo1*8+2]));
	bb_audio_SetChannelRate(2,(Float)pow(FLOAT(1.059463094),m_fine_p2-FLOAT(24.0)+Float(m_LastOct2*12)+m_fxval2)+m_Vib2-m_Dec2Pitch2*Float(m_InsArrayData[m_LastInstNo2*8+2]));
	bb_audio_SetChannelRate(6,(Float)pow(FLOAT(1.059463094),m_fine_p2-FLOAT(24.0)+Float(m_LastOct2*12)+m_fxval2)+m_Vib2+m_PWM2/FLOAT(800.0)*Float(m_PWVal2)-m_Dec2Pitch2*Float(m_InsArrayData[m_LastInstNo2*8+2]));
	bb_audio_SetChannelRate(3,(Float)pow(FLOAT(1.059463094),m_fine_p3-FLOAT(24.0)+Float(m_LastOct3*12)+m_fxval3)+m_Vib3-m_Dec2Pitch3*Float(m_InsArrayData[m_LastInstNo3*8+2]));
	bb_audio_SetChannelRate(7,(Float)pow(FLOAT(1.059463094),m_fine_p3-FLOAT(24.0)+Float(m_LastOct3*12)+m_fxval3)+m_Vib3+m_PWM3/FLOAT(800.0)*Float(m_PWVal3)-m_Dec2Pitch3*Float(m_InsArrayData[m_LastInstNo3*8+2]));
	bb_audio_SetChannelRate(4,(Float)pow(FLOAT(1.059463094),m_fine_p4-FLOAT(24.0)+Float(m_LastOct4*12)+m_fxval4)+m_Vib4-m_Dec2Pitch4*Float(m_InsArrayData[m_LastInstNo4*8+2]));
	bb_audio_SetChannelRate(8,(Float)pow(FLOAT(1.059463094),m_fine_p4-FLOAT(24.0)+Float(m_LastOct4*12)+m_fxval4)+m_Vib4+m_PWM4/FLOAT(800.0)*Float(m_PWVal4)-m_Dec2Pitch4*Float(m_InsArrayData[m_LastInstNo4*8+2]));
	m_Frame+=1;
	return 0;
}
int c_SoundEngine::p_OnUpdate(){
	m_FrameTime+=1;
	if(((bb_input_KeyHit(116))!=0) || bb_slksound_BigButtonZone(44,408,7)==7){
		m_CHOn1=m_CHOn1-FLOAT(1.0);
		if(m_CHOn1==FLOAT(-1.0)){
			m_CHOn1=FLOAT(1.0);
		}
	}
	if(((bb_input_KeyHit(117))!=0) || bb_slksound_BigButtonZone(110,408,8)==8){
		m_CHOn2=m_CHOn2-FLOAT(1.0);
		if(m_CHOn2==FLOAT(-1.0)){
			m_CHOn2=FLOAT(1.0);
		}
	}
	if(((bb_input_KeyHit(118))!=0) || bb_slksound_BigButtonZone(176,408,9)==9){
		m_CHOn3=m_CHOn3-FLOAT(1.0);
		if(m_CHOn3==FLOAT(-1.0)){
			m_CHOn3=FLOAT(1.0);
		}
	}
	if(((bb_input_KeyHit(119))!=0) || bb_slksound_BigButtonZone(242,408,10)==10){
		m_CHOn4=m_CHOn4-FLOAT(1.0);
		if(m_CHOn4==FLOAT(-1.0)){
			m_CHOn4=FLOAT(1.0);
		}
	}
	if(((bb_input_KeyHit(120))!=0) || bb_slksound_BigButtonZone(308,408,11)==11){
		m_flw-=1;
		m_Follow=String(L"Off",3);
		if(m_flw==-1){
			m_flw=1;
			m_Follow=String(L"On",2);
		}
	}
	if(bb_slksound_BigButtonZone(516,440,32)==32 || bb_slksound_BigButtonZone(570,440,32)==32){
		m_USA+=1;
		if(m_USA>1){
			m_USA=0;
		}
		if(m_USA==1){
			m_DEon=String(L"US",2);
		}else{
			m_DEon=String(L"DE",2);
		}
	}
	if(((bb_input_KeyHit(32))!=0) || bb_slksound_BigButtonZone(516,336,2)==2){
		m_i=0;
		m_STATUS-=2;
		m_Scroller=FLOAT(0.0);
		bb_slksound_PauseAll();
		if(m_STATUS==0){
			m_StatusInfo=String(L"Editing...",10);
		}
	}
	if(m_STATUS<0){
		m_STATUS=2;
		m_StatusInfo=String(L"Standby...",10);
	}
	if(bb_slksound_BigButtonZone(570,336,11)==11){
		m_UndoCount-=1;
		if(m_UndoCount<0){
			m_UndoCount=0;
		}
		m_InstTrack1=m_UndoInstTrack1[m_UndoCount];
		m_InstTrack2=m_UndoInstTrack2[m_UndoCount];
		m_InstTrack3=m_UndoInstTrack3[m_UndoCount];
		m_InstTrack4=m_UndoInstTrack4[m_UndoCount];
		m_OctaveTrack1=m_UndoOctaveTrack1[m_UndoCount];
		m_OctaveTrack2=m_UndoOctaveTrack2[m_UndoCount];
		m_OctaveTrack3=m_UndoOctaveTrack3[m_UndoCount];
		m_OctaveTrack4=m_UndoOctaveTrack4[m_UndoCount];
		m_Track1=m_UndoTrack1[m_UndoCount];
		m_Track2=m_UndoTrack2[m_UndoCount];
		m_Track3=m_UndoTrack3[m_UndoCount];
		m_Track4=m_UndoTrack4[m_UndoCount];
		m_VolumeTrack1=m_UndoVolumeTrack1[m_UndoCount];
		m_VolumeTrack2=m_UndoVolumeTrack2[m_UndoCount];
		m_VolumeTrack3=m_UndoVolumeTrack3[m_UndoCount];
		m_VolumeTrack4=m_UndoVolumeTrack4[m_UndoCount];
	}
	if(((bb_input_KeyHit(113))!=0) || ((bb_input_KeyHit(112))!=0) || bb_slksound_BigButtonZone(516,318,1)==1){
		bb_slksound_PauseAll();
		m_Frame=0;
		m_Scroller=FLOAT(0.0);
		if((bb_input_KeyHit(112))!=0){
			m_i=0;
			m_pcount=0;
		}
		m_Cursorpos=1;
		m_STATUS+=1;
		m_i=0;
		if(m_STATUS>2){
			m_STATUS=1;
		}
		if(m_STATUS==2){
			m_StatusInfo=String(L"Standby...",10);
		}
	}
	if(m_STATUS==0 || m_STATUS==2){
		m_Frame=0;
		p_OnEdit();
		if(m_i>m_Songlength-1){
			m_i=0;
		}
		if(m_i<0){
			m_i=m_Songlength-32;
		}
		m_oct=bb_slksound_ButtonZone(473,360,m_oct+1,1,4)-1;
		m_spd=bb_slksound_ButtonZone(473,372,m_spd,1,16);
		m_Songlength=bb_slksound_ButtonZone(473,384,m_Songlength/32,1,99)*32;
		m_WavInit=bb_slksound_ButtonZone(561,144,m_WavInit,1,15);
		m_InsArrayData[m_WavInit*8]=bb_slksound_ButtonZone(561,168,m_InsArrayData[m_WavInit*8],1,7);
		m_InsArrayData[m_WavInit*8+1]=bb_slksound_ButtonZone(561,180,m_InsArrayData[m_WavInit*8+1],0,15);
		m_InsArrayData[m_WavInit*8+2]=bb_slksound_ButtonZone(561,216,m_InsArrayData[m_WavInit*8+2],0,15);
		m_InsArrayData[m_WavInit*8+4]=bb_slksound_ButtonZone(561,204,m_InsArrayData[m_WavInit*8+4],1,255);
		m_InsArrayData[m_WavInit*8+6]=bb_slksound_ButtonZone(561,228,m_InsArrayData[m_WavInit*8+6],0,12);
		m_InsArrayData[m_WavInit*8+7]=bb_slksound_ButtonZone(593,228,m_InsArrayData[m_WavInit*8+7],0,12);
		m_InsArrayData[m_WavInit*8+5]=bb_slksound_ButtonZone(561,240,m_InsArrayData[m_WavInit*8+5],0,15);
		m_InsArrayData[m_WavInit*8+3]=bb_slksound_ButtonZone(561,192,m_InsArrayData[m_WavInit*8+3]/16,0,15)*16+bb_slksound_ButtonZone(561,252,m_InsArrayData[m_WavInit*8+3]-m_InsArrayData[m_WavInit*8+3]/16*16,0,15);
		m_Patterns[m_pcount]=bb_slksound_ButtonZone(385,12,m_Patterns[m_pcount],0,255);
	}
	if(m_STATUS==1){
		m_StatusInfo=String(L"Playing...",10);
		p_Play();
	}
	m_ppos=m_Patterns[m_pcount]*32;
	return 0;
}
int c_SoundEngine::p_DrawGui(){
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(0.0),FLOAT(0.0),FLOAT(640.0),FLOAT(475.0));
	bb_graphics_SetColor(FLOAT(0.0),FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawRect(FLOAT(2.0),FLOAT(14.0),FLOAT(380.0),FLOAT(385.0));
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(303.0),FLOAT(14.0),FLOAT(2.0),FLOAT(387.0));
	bb_graphics_SetColor(FLOAT(71.0),FLOAT(53.0),FLOAT(85.0));
	bb_graphics_DrawRect(FLOAT(305.0),FLOAT(14.0),FLOAT(77.0),FLOAT(12.0));
	bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
	bb_graphics_DrawText(String(L"load save",9),391,441,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"edit undo",9),520,343,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"copytrack",9),520,363,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"pastetrck",9),520,383,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"[[[ [[[ [[[ [[[",15),425,40,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"[ [ [ [ [   [  ",15),425,52,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"[[[ [[[ [[[ [ [",15),425,64,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"[   [     [ [ [",15),425,76,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"[   [   [[[ [[[",15),425,88,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"Description:",12),442,106,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_SetColor(FLOAT(0.0),FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawRect(FLOAT(394.0),FLOAT(122.0),FLOAT(236.0),FLOAT(18.0));
	bb_graphics_DrawRect(FLOAT(4.0),FLOAT(440.0),FLOAT(385.0),FLOAT(18.0));
	bb_graphics_SetColor(FLOAT(128.0),FLOAT(128.0),FLOAT(128.0));
	bb_graphics_DrawText(m_Descriptions[m_WavInit],396,123,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
	bb_graphics_DrawText(String(L"  INSTRUMENT:",13)+bb_slksound_Hex8(m_WavInit),385,144,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L" OCT:",5)+bb_slksound_Hex8(m_oct),385,360,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         WAV:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8]),385,168,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         PWM:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+1]),385,180,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         SWP:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+3]/16),385,192,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         ENV:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+4]),385,204,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         E2P:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+2]),385,216,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         ARP:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+6]*16+m_InsArrayData[m_WavInit*8+7]),385,228,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         SPD:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+5]),385,240,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"         AMT:",13)+bb_slksound_Hex8(m_InsArrayData[m_WavInit*8+3]-m_InsArrayData[m_WavInit*8+3]/16*16),385,252,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L" SPD:",5)+bb_slksound_Hex8(m_spd),385,372,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L" Len:",5)+bb_slksound_Hex8(m_Songlength/32),385,384,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L"Layout ",7)+m_DEon,520,440,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_DrawText(String(L" ",1)+m_Filename,0,441,FLOAT(0.0),FLOAT(0.0));
	String t_ptpos=String();
	bb_graphics_SetColor(FLOAT(82.0),FLOAT(72.0),FLOAT(74.0));
	if(m_STATUS==0){
		bb_graphics_DrawRect(FLOAT(0.0),Float(2+12*m_Cursorpos),FLOAT(303.0),FLOAT(12.0));
	}
	bb_graphics_SetColor(FLOAT(143.0),FLOAT(31.0),FLOAT(87.0));
	if(((m_FilenameInputOn)!=0) || ((m_InstDescriptionOn)!=0)){
		if((m_FilenameInputOn)!=0){
			bb_graphics_DrawText(String(L" [",2),11*m_Filename.Length(),441,FLOAT(0.0),FLOAT(0.0));
		}
		if((m_InstDescriptionOn)!=0){
			bb_graphics_DrawText(String(L" [",2),385+11*m_Descriptions[m_WavInit].Length(),123,FLOAT(0.0),FLOAT(0.0));
		}
	}else{
		bb_graphics_DrawText(String(L" [",2),33*m_EDIT_CHANNEL,12*m_Cursorpos,FLOAT(0.0),FLOAT(0.0));
	}
	for(int t_g=0;t_g<=31;t_g=t_g+1){
		if(m_i+m_ppos+t_g-(m_i+m_ppos+t_g)/32*32!=(m_i+m_ppos+t_g-(m_i+m_ppos+t_g)/32*32)/4*4){
			bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
		}else{
			bb_graphics_SetColor(FLOAT(113.84615384615384),FLOAT(110.76923076923076),FLOAT(126.15384615384615));
		}
		bb_graphics_DrawText(bb_slksound_Hex8(+m_i+m_ppos+t_g-(+m_i+m_ppos+t_g)/32*32)+String(L": ",2)+bb_slksound_Translate2Note(m_Track1,+m_i+m_ppos+t_g,m_OctaveTrack1)+m_VolumeTrack1.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+m_InstTrack1.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+String(L" ",1)+bb_slksound_Translate2Note(m_Track2,+m_i+m_ppos+t_g,m_OctaveTrack2)+m_VolumeTrack2.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+m_InstTrack2.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+String(L" ",1)+bb_slksound_Translate2Note(m_Track3,+m_i+m_ppos+t_g,m_OctaveTrack3)+m_VolumeTrack3.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+m_InstTrack3.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+String(L" ",1)+bb_slksound_Translate2Note(m_Track4,+m_i+m_ppos+t_g,m_OctaveTrack4)+m_VolumeTrack4.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g)+m_InstTrack4.Slice(+m_i+m_ppos+t_g,+m_i+m_ppos+1+t_g),0,12+t_g*12,FLOAT(0.0),FLOAT(0.0));
		bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
		bb_graphics_DrawText(String(L" ",1)+bb_slksound_Hex8(m_pcount+t_g)+String(L": ",2)+bb_slksound_Hex8(m_Patterns[m_pcount+t_g]),297,12+12*t_g,FLOAT(0.0),FLOAT(0.0));
	}
	bb_graphics_SetColor(FLOAT(255.0),FLOAT(255.0),FLOAT(255.0));
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(144.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(473.0),FLOAT(360.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(168.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(180.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(192.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(204.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(228.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(593.0),FLOAT(228.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(240.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(252.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(561.0),FLOAT(216.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(473.0),FLOAT(372.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(473.0),FLOAT(384.0),0);
	bb_graphics_DrawImage(m_Button1,FLOAT(385.0),FLOAT(12.0),0);
	return 0;
}
String c_SoundEngine::m_CHOff1;
String c_SoundEngine::m_CHOff2;
String c_SoundEngine::m_CHOff3;
String c_SoundEngine::m_CHOff4;
int c_SoundEngine::m_meter_H1;
int c_SoundEngine::m_meter_H2;
int c_SoundEngine::m_meter_H3;
int c_SoundEngine::m_meter_H4;
int c_SoundEngine::p_OnRender(){
	if(m_STATUS!=1 && m_FrameTime>2){
		bb_graphics_Cls(FLOAT(0.0),FLOAT(0.0),FLOAT(0.0));
		p_DrawGui();
		m_FrameTime=0;
	}
	if(m_STATUS==1 && m_Follow==String(L"On",2) && m_i==0){
		bb_graphics_Cls(FLOAT(0.0),FLOAT(0.0),FLOAT(0.0));
		p_DrawGui();
	}
	if(m_STATUS==1 && m_Follow==String(L"On",2)){
		bb_graphics_SetColor(FLOAT(0.0),FLOAT(0.0),FLOAT(0.0));
		bb_graphics_DrawRect(FLOAT(0.0),Float(2+(12*m_i-12)),FLOAT(303.0),FLOAT(1.0));
		bb_graphics_SetColor(FLOAT(171.59999999999999),FLOAT(37.199999999999996),FLOAT(104.39999999999999));
		bb_graphics_DrawRect(FLOAT(0.0),Float(2+12*m_i),FLOAT(303.0),FLOAT(1.0));
		m_FrameTime=0;
	}
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(520.0),FLOAT(323.0),FLOAT(570.0),FLOAT(16.0));
	bb_graphics_DrawRect(FLOAT(4.0),FLOAT(408.0),FLOAT(380.0),FLOAT(16.0));
	bb_graphics_SetColor(FLOAT(38.0),FLOAT(38.0),FLOAT(38.0));
	bb_graphics_DrawRect(FLOAT(2.0),FLOAT(0.0),FLOAT(640.0),FLOAT(14.0));
	bb_graphics_SetColor(FLOAT(171.59999999999999),FLOAT(37.199999999999996),FLOAT(104.39999999999999));
	bb_graphics_DrawText(String(L"                                           ",43)+m_StatusInfo,0,-1,FLOAT(0.0),FLOAT(0.0));
	bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
	bb_graphics_DrawText(String(L"POS CHN1  CHN2  CHN3  CHN4  POS ## Status: ",43),0,-1,FLOAT(0.0),FLOAT(0.0));
	if(m_CHOn1==FLOAT(1.0)){
		m_CHOff1=String(L"on  ",4);
	}else{
		m_CHOff1=String(L"off ",4);
	}
	if(m_CHOn2==FLOAT(1.0)){
		m_CHOff2=String(L"on  ",4);
	}else{
		m_CHOff2=String(L"off ",4);
	}
	if(m_CHOn3==FLOAT(1.0)){
		m_CHOff3=String(L"on  ",4);
	}else{
		m_CHOff3=String(L"off ",4);
	}
	if(m_CHOn4==FLOAT(1.0)){
		m_CHOff4=String(L"on  ",4);
	}else{
		m_CHOff4=String(L"off ",4);
	}
	bb_graphics_SetColor(FLOAT(148.0),FLOAT(144.0),FLOAT(164.0));
	bb_graphics_DrawText(String(L"    ",4)+m_CHOff1+String(L"  ",2)+m_CHOff2+String(L"  ",2)+m_CHOff3+String(L"  ",2)+m_CHOff4+String(L" FLW:",5)+m_Follow,0,408,FLOAT(0.0),FLOAT(0.0));
	if(m_STATUS==1){
		bb_graphics_DrawText(String(L"stop home",9),520,323,FLOAT(0.0),FLOAT(0.0));
	}else{
		bb_graphics_DrawText(String(L"play home",9),520,323,FLOAT(0.0),FLOAT(0.0));
	}
	if(m_Track1.Slice(m_i+m_ppos,m_i+m_ppos+1)!=String(L".",1) && m_STATUS==1 && ((m_CHOn1)!=0)){
		m_meter_H1=(m_VolumeTrack1.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*8;
	}
	m_meter_H1-=2;
	if(m_meter_H1<2){
		m_meter_H1=2;
	}
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(407.0),FLOAT(348.0),FLOAT(16.0),FLOAT(-64.0));
	bb_graphics_SetColor(Float(79+m_meter_H1),Float(95-m_meter_H1),Float(151-m_meter_H1));
	bb_graphics_DrawRect(FLOAT(407.0),FLOAT(348.0),FLOAT(16.0),Float(-m_meter_H1));
	if(m_Track2.Slice(m_i+m_ppos,m_i+m_ppos+1)!=String(L".",1) && m_STATUS==1 && ((m_CHOn2)!=0)){
		m_meter_H2=(m_VolumeTrack2.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*8;
	}
	m_meter_H2-=2;
	if(m_meter_H2<2){
		m_meter_H2=2;
	}
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(429.0),FLOAT(348.0),FLOAT(16.0),FLOAT(-64.0));
	bb_graphics_SetColor(Float(79+m_meter_H2),Float(95-m_meter_H2),Float(151-m_meter_H2));
	bb_graphics_DrawRect(FLOAT(429.0),FLOAT(348.0),FLOAT(16.0),Float(-m_meter_H2));
	if(m_Track3.Slice(m_i+m_ppos,m_i+m_ppos+1)!=String(L".",1) && m_STATUS==1 && ((m_CHOn3)!=0)){
		m_meter_H3=(m_VolumeTrack3.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*8;
	}
	m_meter_H3-=2;
	if(m_meter_H3<2){
		m_meter_H3=2;
	}
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(451.0),FLOAT(348.0),FLOAT(16.0),FLOAT(-64.0));
	bb_graphics_SetColor(Float(79+m_meter_H3),Float(95-m_meter_H3),Float(151-m_meter_H3));
	bb_graphics_DrawRect(FLOAT(451.0),FLOAT(348.0),FLOAT(16.0),Float(-m_meter_H3));
	if(m_Track4.Slice(m_i+m_ppos,m_i+m_ppos+1)!=String(L".",1) && m_STATUS==1 && ((m_CHOn4)!=0)){
		m_meter_H4=(m_VolumeTrack4.Slice(m_i+m_ppos,m_i+m_ppos+1)).ToInt()*8;
	}
	m_meter_H4-=2;
	if(m_meter_H4<2){
		m_meter_H4=2;
	}
	bb_graphics_SetColor(FLOAT(86.0),FLOAT(60.0),FLOAT(106.0));
	bb_graphics_DrawRect(FLOAT(473.0),FLOAT(348.0),FLOAT(16.0),FLOAT(-64.0));
	bb_graphics_SetColor(Float(79+m_meter_H4),Float(95-m_meter_H4),Float(151-m_meter_H4));
	bb_graphics_DrawRect(FLOAT(473.0),FLOAT(348.0),FLOAT(16.0),Float(-m_meter_H4));
	return 0;
}
void c_SoundEngine::mark(){
	c_App::mark();
}
c_App* bb_app__app;
c_GameDelegate::c_GameDelegate(){
	m__graphics=0;
	m__audio=0;
	m__input=0;
}
c_GameDelegate* c_GameDelegate::m_new(){
	return this;
}
void c_GameDelegate::StartGame(){
	gc_assign(m__graphics,(new gxtkGraphics));
	bb_graphics_SetGraphicsDevice(m__graphics);
	bb_graphics_SetFont(0);
	gc_assign(m__audio,(new gxtkAudio));
	bb_audio_SetAudioDevice(m__audio);
	gc_assign(m__input,(new c_InputDevice)->m_new());
	bb_input_SetInputDevice(m__input);
	bb_app_ValidateDeviceWindow(false);
	bb_app_EnumDisplayModes();
	bb_app__app->p_OnCreate();
}
void c_GameDelegate::SuspendGame(){
	bb_app__app->p_OnSuspend();
	m__audio->Suspend();
}
void c_GameDelegate::ResumeGame(){
	m__audio->Resume();
	bb_app__app->p_OnResume();
}
void c_GameDelegate::UpdateGame(){
	bb_app_ValidateDeviceWindow(true);
	m__input->p_BeginUpdate();
	bb_app__app->p_OnUpdate();
	m__input->p_EndUpdate();
}
void c_GameDelegate::RenderGame(){
	bb_app_ValidateDeviceWindow(true);
	int t_mode=m__graphics->BeginRender();
	if((t_mode)!=0){
		bb_graphics_BeginRender();
	}
	if(t_mode==2){
		bb_app__app->p_OnLoading();
	}else{
		bb_app__app->p_OnRender();
	}
	if((t_mode)!=0){
		bb_graphics_EndRender();
	}
	m__graphics->EndRender();
}
void c_GameDelegate::KeyEvent(int t_event,int t_data){
	m__input->p_KeyEvent(t_event,t_data);
	if(t_event!=1){
		return;
	}
	int t_1=t_data;
	if(t_1==432){
		bb_app__app->p_OnClose();
	}else{
		if(t_1==416){
			bb_app__app->p_OnBack();
		}
	}
}
void c_GameDelegate::MouseEvent(int t_event,int t_data,Float t_x,Float t_y,Float t_z){
	m__input->p_MouseEvent(t_event,t_data,t_x,t_y,t_z);
}
void c_GameDelegate::TouchEvent(int t_event,int t_data,Float t_x,Float t_y){
	m__input->p_TouchEvent(t_event,t_data,t_x,t_y);
}
void c_GameDelegate::MotionEvent(int t_event,int t_data,Float t_x,Float t_y,Float t_z){
	m__input->p_MotionEvent(t_event,t_data,t_x,t_y,t_z);
}
void c_GameDelegate::DiscardGraphics(){
	m__graphics->DiscardGraphics();
}
void c_GameDelegate::mark(){
	BBGameDelegate::mark();
	gc_mark_q(m__graphics);
	gc_mark_q(m__audio);
	gc_mark_q(m__input);
}
c_GameDelegate* bb_app__delegate;
BBGame* bb_app__game;
int bbMain(){
	(new c_SoundEngine)->m_new();
	return 0;
}
gxtkGraphics* bb_graphics_device;
int bb_graphics_SetGraphicsDevice(gxtkGraphics* t_dev){
	gc_assign(bb_graphics_device,t_dev);
	return 0;
}
c_Font::c_Font(){
	m__pages=Array<c_Image* >();
	m__pageCount=0;
	m__firstChar=0;
	m__height=FLOAT(.0);
	m__charMap=(new c_IntMap)->m_new();
}
c_Font* c_Font::m_new(Array<c_Image* > t_pages,int t_pageCount,c_IntMap* t_chars,int t_firstChar,Float t_height){
	gc_assign(this->m__pages,t_pages);
	this->m__pageCount=t_pageCount;
	this->m__firstChar=t_firstChar;
	this->m__height=t_height;
	gc_assign(this->m__charMap,t_chars);
	return this;
}
c_Font* c_Font::m_new2(){
	return this;
}
c_Font* c_Font::m_Load(String t_path,int t_firstChar,int t_numChars,bool t_padded){
	c_Image* t_image=bb_graphics_LoadImage(t_path,1,c_Image::m_DefaultFlags);
	Array<c_Image* > t__pages=Array<c_Image* >(1);
	gc_assign(t__pages[0],t_image);
	c_IntMap* t__charMap=(new c_IntMap)->m_new();
	int t__pageCount=1;
	if(!((t_image)!=0)){
		return 0;
	}
	int t_cellWidth=t_image->p_Width()/t_numChars;
	int t_cellHeight=t_image->p_Height();
	int t_glyphX=0;
	int t_glyphY=0;
	int t_glyphWidth=t_cellWidth;
	int t_glyphHeight=t_cellHeight;
	if(t_padded==true){
		t_glyphX+=1;
		t_glyphY+=1;
		t_glyphWidth-=2;
		t_glyphHeight-=2;
	}
	int t_w=t_image->p_Width()/t_cellWidth;
	int t_h=t_image->p_Height()/t_cellHeight;
	for(int t_i=0;t_i<t_numChars;t_i=t_i+1){
		int t_y=t_i/t_w;
		int t_x=t_i % t_w;
		c_Glyph* t_glyph=(new c_Glyph)->m_new(0,t_firstChar+t_i,t_x*t_cellWidth+t_glyphX,t_y*t_cellHeight+t_glyphY,t_glyphWidth,t_glyphHeight,t_glyphWidth);
		t__charMap->p_Add(t_firstChar+t_i,t_glyph);
	}
	return (new c_Font)->m_new(t__pages,t__pageCount,t__charMap,t_firstChar,Float(t_glyphHeight));
}
c_Font* c_Font::m_Load2(String t_path,int t_cellWidth,int t_cellHeight,int t_glyphX,int t_glyphY,int t_glyphWidth,int t_glyphHeight,int t_firstChar,int t_numChars){
	c_Image* t_image=bb_graphics_LoadImage(t_path,1,c_Image::m_DefaultFlags);
	Array<c_Image* > t__pages=Array<c_Image* >(1);
	gc_assign(t__pages[0],t_image);
	c_IntMap* t__charMap=(new c_IntMap)->m_new();
	int t__pageCount=1;
	if(!((t_image)!=0)){
		return 0;
	}
	int t_w=t_image->p_Width()/t_cellWidth;
	int t_h=t_image->p_Height()/t_cellHeight;
	for(int t_i=0;t_i<t_numChars;t_i=t_i+1){
		int t_y=t_i/t_w;
		int t_x=t_i % t_w;
		c_Glyph* t_glyph=(new c_Glyph)->m_new(0,t_firstChar+t_i,t_x*t_cellWidth+t_glyphX,t_y*t_cellHeight+t_glyphY,t_glyphWidth,t_glyphHeight,t_glyphWidth);
		t__charMap->p_Add(t_firstChar+t_i,t_glyph);
	}
	return (new c_Font)->m_new(t__pages,t__pageCount,t__charMap,t_firstChar,Float(t_glyphHeight));
}
c_Font* c_Font::m_Load3(String t_url){
	String t_iniText=String();
	int t_pageNum=0;
	int t_idnum=0;
	c_Glyph* t_tmpChar=0;
	int t_plLen=0;
	Array<String > t_lines=Array<String >();
	String t_filename=String();
	int t_lineHeight=0;
	Array<c_Image* > t__pages=Array<c_Image* >();
	c_IntMap* t__charMap=(new c_IntMap)->m_new();
	int t__pageCount=0;
	String t_path=String();
	if(t_url.Find(String(L"/",1),0)>-1){
		Array<String > t_pl=t_url.Split(String(L"/",1));
		t_plLen=t_pl.Length();
		for(int t_pi=0;t_pi<=t_plLen-2;t_pi=t_pi+1){
			t_path=t_path+t_pl[t_pi]+String(L"/",1);
		}
	}
	String t_ts=t_url.ToLower();
	if(t_ts.Find(String(L".txt",4),0)>0){
		t_iniText=bb_app_LoadString(t_url);
	}else{
		t_iniText=bb_app_LoadString(t_url+String(L".txt",4));
	}
	t_lines=t_iniText.Split(String((Char)(13),1)+String((Char)(10),1));
	if(t_lines.Length()<2){
		t_lines=t_iniText.Split(String((Char)(10),1));
	}
	Array<String > t_=t_lines;
	int t_2=0;
	while(t_2<t_.Length()){
		String t_line=t_[t_2];
		t_2=t_2+1;
		t_line=t_line.Trim();
		if(t_line.StartsWith(String(L"info",4)) || t_line==String()){
			continue;
		}
		if(t_line.StartsWith(String(L"padding",7))){
			continue;
		}
		if(t_line.StartsWith(String(L"common",6))){
			Array<String > t_commondata=t_line.Split(String((Char)(32),1));
			Array<String > t_3=t_commondata;
			int t_4=0;
			while(t_4<t_3.Length()){
				String t_common=t_3[t_4];
				t_4=t_4+1;
				if(t_common.StartsWith(String(L"lineHeight=",11))){
					Array<String > t_lnh=t_common.Split(String(L"=",1));
					t_lnh[1]=t_lnh[1].Trim();
					t_lineHeight=(t_lnh[1]).ToInt();
				}
				if(t_common.StartsWith(String(L"pages=",6))){
					Array<String > t_lnh2=t_common.Split(String(L"=",1));
					t_lnh2[1]=t_lnh2[1].Trim();
					t__pageCount=(t_lnh2[1]).ToInt();
					t__pages=Array<c_Image* >(t__pageCount);
				}
			}
		}
		if(t_line.StartsWith(String(L"page",4))){
			Array<String > t_pagedata=t_line.Split(String((Char)(32),1));
			Array<String > t_5=t_pagedata;
			int t_6=0;
			while(t_6<t_5.Length()){
				String t_data=t_5[t_6];
				t_6=t_6+1;
				if(t_data.StartsWith(String(L"file=",5))){
					Array<String > t_fn=t_data.Split(String(L"=",1));
					t_fn[1]=t_fn[1].Trim();
					t_filename=t_fn[1];
					if((int)t_filename[0]==34){
						t_filename=t_filename.Slice(1,t_filename.Length()-1);
					}
					t_filename=t_path+t_filename.Trim();
					gc_assign(t__pages[t_pageNum],bb_graphics_LoadImage(t_filename,1,c_Image::m_DefaultFlags));
					t_pageNum=t_pageNum+1;
				}
			}
		}
		if(t_line.StartsWith(String(L"chars",5))){
			continue;
		}
		if(t_line.StartsWith(String(L"char",4))){
			t_tmpChar=(new c_Glyph)->m_new2();
			Array<String > t_linedata=t_line.Split(String((Char)(32),1));
			Array<String > t_7=t_linedata;
			int t_8=0;
			while(t_8<t_7.Length()){
				String t_data2=t_7[t_8];
				t_8=t_8+1;
				if(t_data2.StartsWith(String(L"id=",3))){
					Array<String > t_idc=t_data2.Split(String(L"=",1));
					t_idc[1]=t_idc[1].Trim();
					t_tmpChar->m_id=(t_idc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"x=",2))){
					Array<String > t_xc=t_data2.Split(String(L"=",1));
					t_xc[1]=t_xc[1].Trim();
					t_tmpChar->m_x=(t_xc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"y=",2))){
					Array<String > t_yc=t_data2.Split(String(L"=",1));
					t_yc[1]=t_yc[1].Trim();
					t_tmpChar->m_y=(t_yc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"width=",6))){
					Array<String > t_wc=t_data2.Split(String(L"=",1));
					t_wc[1]=t_wc[1].Trim();
					t_tmpChar->m_width=(t_wc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"height=",7))){
					Array<String > t_hc=t_data2.Split(String(L"=",1));
					t_hc[1]=t_hc[1].Trim();
					t_tmpChar->m_height=(t_hc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"xoffset=",8))){
					Array<String > t_xoc=t_data2.Split(String(L"=",1));
					t_xoc[1]=t_xoc[1].Trim();
					t_tmpChar->m_xoff=(t_xoc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"yoffset=",8))){
					Array<String > t_yoc=t_data2.Split(String(L"=",1));
					t_yoc[1]=t_yoc[1].Trim();
					t_tmpChar->m_yoff=(t_yoc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"xadvance=",9))){
					Array<String > t_advc=t_data2.Split(String(L"=",1));
					t_advc[1]=t_advc[1].Trim();
					t_tmpChar->m_advance=(t_advc[1]).ToInt();
				}
				if(t_data2.StartsWith(String(L"page=",5))){
					Array<String > t_advc2=t_data2.Split(String(L"=",1));
					t_advc2[1]=t_advc2[1].Trim();
					t_tmpChar->m_page=(t_advc2[1]).ToInt();
				}
			}
			t__charMap->p_Add(t_tmpChar->m_id,t_tmpChar);
		}
		continue;
	}
	return (new c_Font)->m_new(t__pages,t__pageCount,t__charMap,-1,Float(t_lineHeight));
}
c_Glyph* c_Font::p_GetGlyph(int t_char){
	return this->m__charMap->p_Get(t_char);
}
Float c_Font::p_TextWidth(String t_text){
	Float t_w=FLOAT(0.0);
	int t_char=0;
	String t_=t_text;
	int t_2=0;
	while(t_2<t_.Length()){
		t_char=(int)t_[t_2];
		t_2=t_2+1;
		c_Glyph* t_glyph=p_GetGlyph(t_char);
		if(!((t_glyph)!=0)){
			continue;
		}
		t_w=t_w+Float(t_glyph->m_advance);
	}
	return t_w;
}
Float c_Font::p_TextHeight(String t_text){
	return m__height;
}
void c_Font::mark(){
	Object::mark();
	gc_mark_q(m__pages);
	gc_mark_q(m__charMap);
}
c_GraphicsContext::c_GraphicsContext(){
	m_defaultFont=0;
	m_font=0;
	m_matrixSp=0;
	m_ix=FLOAT(1.0);
	m_iy=FLOAT(.0);
	m_jx=FLOAT(.0);
	m_jy=FLOAT(1.0);
	m_tx=FLOAT(.0);
	m_ty=FLOAT(.0);
	m_tformed=0;
	m_matDirty=0;
	m_color_r=FLOAT(.0);
	m_color_g=FLOAT(.0);
	m_color_b=FLOAT(.0);
	m_alpha=FLOAT(.0);
	m_blend=0;
	m_scissor_x=FLOAT(.0);
	m_scissor_y=FLOAT(.0);
	m_scissor_width=FLOAT(.0);
	m_scissor_height=FLOAT(.0);
	m_matrixStack=Array<Float >(192);
}
c_GraphicsContext* c_GraphicsContext::m_new(){
	return this;
}
int c_GraphicsContext::p_Validate(){
	if((m_matDirty)!=0){
		bb_graphics_renderDevice->SetMatrix(bb_graphics_context->m_ix,bb_graphics_context->m_iy,bb_graphics_context->m_jx,bb_graphics_context->m_jy,bb_graphics_context->m_tx,bb_graphics_context->m_ty);
		m_matDirty=0;
	}
	return 0;
}
void c_GraphicsContext::mark(){
	Object::mark();
	gc_mark_q(m_defaultFont);
	gc_mark_q(m_font);
	gc_mark_q(m_matrixStack);
}
c_GraphicsContext* bb_graphics_context;
c_Image::c_Image(){
	m_surface=0;
	m_width=0;
	m_height=0;
	m_frames=Array<c_Frame* >();
	m_flags=0;
	m_tx=FLOAT(.0);
	m_ty=FLOAT(.0);
	m_source=0;
}
int c_Image::m_DefaultFlags;
c_Image* c_Image::m_new(){
	return this;
}
int c_Image::p_SetHandle(Float t_tx,Float t_ty){
	this->m_tx=t_tx;
	this->m_ty=t_ty;
	this->m_flags=this->m_flags&-2;
	return 0;
}
int c_Image::p_ApplyFlags(int t_iflags){
	m_flags=t_iflags;
	if((m_flags&2)!=0){
		Array<c_Frame* > t_=m_frames;
		int t_2=0;
		while(t_2<t_.Length()){
			c_Frame* t_f=t_[t_2];
			t_2=t_2+1;
			t_f->m_x+=1;
		}
		m_width-=2;
	}
	if((m_flags&4)!=0){
		Array<c_Frame* > t_3=m_frames;
		int t_4=0;
		while(t_4<t_3.Length()){
			c_Frame* t_f2=t_3[t_4];
			t_4=t_4+1;
			t_f2->m_y+=1;
		}
		m_height-=2;
	}
	if((m_flags&1)!=0){
		p_SetHandle(Float(m_width)/FLOAT(2.0),Float(m_height)/FLOAT(2.0));
	}
	if(m_frames.Length()==1 && m_frames[0]->m_x==0 && m_frames[0]->m_y==0 && m_width==m_surface->Width() && m_height==m_surface->Height()){
		m_flags|=65536;
	}
	return 0;
}
c_Image* c_Image::p_Init(gxtkSurface* t_surf,int t_nframes,int t_iflags){
	if((m_surface)!=0){
		bbError(String(L"Image already initialized",25));
	}
	gc_assign(m_surface,t_surf);
	m_width=m_surface->Width()/t_nframes;
	m_height=m_surface->Height();
	gc_assign(m_frames,Array<c_Frame* >(t_nframes));
	for(int t_i=0;t_i<t_nframes;t_i=t_i+1){
		gc_assign(m_frames[t_i],(new c_Frame)->m_new(t_i*m_width,0));
	}
	p_ApplyFlags(t_iflags);
	return this;
}
c_Image* c_Image::p_Init2(gxtkSurface* t_surf,int t_x,int t_y,int t_iwidth,int t_iheight,int t_nframes,int t_iflags,c_Image* t_src,int t_srcx,int t_srcy,int t_srcw,int t_srch){
	if((m_surface)!=0){
		bbError(String(L"Image already initialized",25));
	}
	gc_assign(m_surface,t_surf);
	gc_assign(m_source,t_src);
	m_width=t_iwidth;
	m_height=t_iheight;
	gc_assign(m_frames,Array<c_Frame* >(t_nframes));
	int t_ix=t_x;
	int t_iy=t_y;
	for(int t_i=0;t_i<t_nframes;t_i=t_i+1){
		if(t_ix+m_width>t_srcw){
			t_ix=0;
			t_iy+=m_height;
		}
		if(t_ix+m_width>t_srcw || t_iy+m_height>t_srch){
			bbError(String(L"Image frame outside surface",27));
		}
		gc_assign(m_frames[t_i],(new c_Frame)->m_new(t_ix+t_srcx,t_iy+t_srcy));
		t_ix+=m_width;
	}
	p_ApplyFlags(t_iflags);
	return this;
}
int c_Image::p_Width(){
	return m_width;
}
int c_Image::p_Height(){
	return m_height;
}
void c_Image::mark(){
	Object::mark();
	gc_mark_q(m_surface);
	gc_mark_q(m_frames);
	gc_mark_q(m_source);
}
String bb_data_FixDataPath(String t_path){
	int t_i=t_path.Find(String(L":/",2),0);
	if(t_i!=-1 && t_path.Find(String(L"/",1),0)==t_i+1){
		return t_path;
	}
	if(t_path.StartsWith(String(L"./",2)) || t_path.StartsWith(String(L"/",1))){
		return t_path;
	}
	return String(L"cerberus://data/",16)+t_path;
}
c_Frame::c_Frame(){
	m_x=0;
	m_y=0;
}
c_Frame* c_Frame::m_new(int t_x,int t_y){
	this->m_x=t_x;
	this->m_y=t_y;
	return this;
}
c_Frame* c_Frame::m_new2(){
	return this;
}
void c_Frame::mark(){
	Object::mark();
}
int bb_lang_DebugLog(String t_message){
	int t_b=0;
	return 0;
}
c_Image* bb_graphics_LoadImage(String t_path,int t_frameCount,int t_flags){
	gxtkSurface* t_surf=bb_graphics_device->LoadSurface(bb_data_FixDataPath(t_path));
	if((t_surf)!=0){
		return ((new c_Image)->m_new())->p_Init(t_surf,t_frameCount,t_flags);
	}else{
		bb_lang_DebugLog(String(L"Error - Unable to load image: ",30)+t_path);
	}
	return 0;
}
c_Image* bb_graphics_LoadImage2(String t_path,int t_frameWidth,int t_frameHeight,int t_frameCount,int t_flags){
	gxtkSurface* t_surf=bb_graphics_device->LoadSurface(bb_data_FixDataPath(t_path));
	if((t_surf)!=0){
		return ((new c_Image)->m_new())->p_Init2(t_surf,0,0,t_frameWidth,t_frameHeight,t_frameCount,t_flags,0,0,0,t_surf->Width(),t_surf->Height());
	}else{
		bb_lang_DebugLog(String(L"Error - Unable to load image: ",30)+t_path);
	}
	return 0;
}
c_Glyph::c_Glyph(){
	m_page=0;
	m_id=0;
	m_x=0;
	m_y=0;
	m_width=0;
	m_height=0;
	m_advance=0;
	m_xoff=0;
	m_yoff=0;
}
c_Glyph* c_Glyph::m_new(int t_page,int t_id,int t_x,int t_y,int t_width,int t_height,int t_advance){
	this->m_page=t_page;
	this->m_id=t_id;
	this->m_x=t_x;
	this->m_y=t_y;
	this->m_width=t_width;
	this->m_height=t_height;
	this->m_advance=t_advance;
	this->m_xoff=0;
	this->m_yoff=0;
	return this;
}
c_Glyph* c_Glyph::m_new2(){
	return this;
}
void c_Glyph::mark(){
	Object::mark();
}
c_Map::c_Map(){
	m_root=0;
}
c_Map* c_Map::m_new(){
	return this;
}
int c_Map::p_RotateLeft(c_Node* t_node){
	c_Node* t_child=t_node->m_right;
	gc_assign(t_node->m_right,t_child->m_left);
	if((t_child->m_left)!=0){
		gc_assign(t_child->m_left->m_parent,t_node);
	}
	gc_assign(t_child->m_parent,t_node->m_parent);
	if((t_node->m_parent)!=0){
		if(t_node==t_node->m_parent->m_left){
			gc_assign(t_node->m_parent->m_left,t_child);
		}else{
			gc_assign(t_node->m_parent->m_right,t_child);
		}
	}else{
		gc_assign(m_root,t_child);
	}
	gc_assign(t_child->m_left,t_node);
	gc_assign(t_node->m_parent,t_child);
	return 0;
}
int c_Map::p_RotateRight(c_Node* t_node){
	c_Node* t_child=t_node->m_left;
	gc_assign(t_node->m_left,t_child->m_right);
	if((t_child->m_right)!=0){
		gc_assign(t_child->m_right->m_parent,t_node);
	}
	gc_assign(t_child->m_parent,t_node->m_parent);
	if((t_node->m_parent)!=0){
		if(t_node==t_node->m_parent->m_right){
			gc_assign(t_node->m_parent->m_right,t_child);
		}else{
			gc_assign(t_node->m_parent->m_left,t_child);
		}
	}else{
		gc_assign(m_root,t_child);
	}
	gc_assign(t_child->m_right,t_node);
	gc_assign(t_node->m_parent,t_child);
	return 0;
}
int c_Map::p_InsertFixup(c_Node* t_node){
	while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){
		if(t_node->m_parent==t_node->m_parent->m_parent->m_left){
			c_Node* t_uncle=t_node->m_parent->m_parent->m_right;
			if(((t_uncle)!=0) && t_uncle->m_color==-1){
				t_node->m_parent->m_color=1;
				t_uncle->m_color=1;
				t_uncle->m_parent->m_color=-1;
				t_node=t_uncle->m_parent;
			}else{
				if(t_node==t_node->m_parent->m_right){
					t_node=t_node->m_parent;
					p_RotateLeft(t_node);
				}
				t_node->m_parent->m_color=1;
				t_node->m_parent->m_parent->m_color=-1;
				p_RotateRight(t_node->m_parent->m_parent);
			}
		}else{
			c_Node* t_uncle2=t_node->m_parent->m_parent->m_left;
			if(((t_uncle2)!=0) && t_uncle2->m_color==-1){
				t_node->m_parent->m_color=1;
				t_uncle2->m_color=1;
				t_uncle2->m_parent->m_color=-1;
				t_node=t_uncle2->m_parent;
			}else{
				if(t_node==t_node->m_parent->m_left){
					t_node=t_node->m_parent;
					p_RotateRight(t_node);
				}
				t_node->m_parent->m_color=1;
				t_node->m_parent->m_parent->m_color=-1;
				p_RotateLeft(t_node->m_parent->m_parent);
			}
		}
	}
	m_root->m_color=1;
	return 0;
}
bool c_Map::p_Add(int t_key,c_Glyph* t_value){
	c_Node* t_node=m_root;
	c_Node* t_parent=0;
	int t_cmp=0;
	while((t_node)!=0){
		t_parent=t_node;
		t_cmp=p_Compare(t_key,t_node->m_key);
		if(t_cmp>0){
			t_node=t_node->m_right;
		}else{
			if(t_cmp<0){
				t_node=t_node->m_left;
			}else{
				return false;
			}
		}
	}
	t_node=(new c_Node)->m_new(t_key,t_value,-1,t_parent);
	if((t_parent)!=0){
		if(t_cmp>0){
			gc_assign(t_parent->m_right,t_node);
		}else{
			gc_assign(t_parent->m_left,t_node);
		}
		p_InsertFixup(t_node);
	}else{
		gc_assign(m_root,t_node);
	}
	return true;
}
c_Node* c_Map::p_FindNode(int t_key){
	c_Node* t_node=m_root;
	while((t_node)!=0){
		int t_cmp=p_Compare(t_key,t_node->m_key);
		if(t_cmp>0){
			t_node=t_node->m_right;
		}else{
			if(t_cmp<0){
				t_node=t_node->m_left;
			}else{
				return t_node;
			}
		}
	}
	return t_node;
}
c_Glyph* c_Map::p_Get(int t_key){
	c_Node* t_node=p_FindNode(t_key);
	if((t_node)!=0){
		return t_node->m_value;
	}
	return 0;
}
void c_Map::mark(){
	Object::mark();
	gc_mark_q(m_root);
}
c_IntMap::c_IntMap(){
}
c_IntMap* c_IntMap::m_new(){
	c_Map::m_new();
	return this;
}
int c_IntMap::p_Compare(int t_lhs,int t_rhs){
	return t_lhs-t_rhs;
}
void c_IntMap::mark(){
	c_Map::mark();
}
c_Node::c_Node(){
	m_key=0;
	m_right=0;
	m_left=0;
	m_value=0;
	m_color=0;
	m_parent=0;
}
c_Node* c_Node::m_new(int t_key,c_Glyph* t_value,int t_color,c_Node* t_parent){
	this->m_key=t_key;
	gc_assign(this->m_value,t_value);
	this->m_color=t_color;
	gc_assign(this->m_parent,t_parent);
	return this;
}
c_Node* c_Node::m_new2(){
	return this;
}
void c_Node::mark(){
	Object::mark();
	gc_mark_q(m_right);
	gc_mark_q(m_left);
	gc_mark_q(m_value);
	gc_mark_q(m_parent);
}
String bb_app_LoadString(String t_path){
	return bb_app__game->LoadString(bb_data_FixDataPath(t_path));
}
void bb_graphics_SetFont(c_Font* t_font){
	if(!((t_font)!=0)){
		if(!((bb_graphics_context->m_defaultFont)!=0)){
			gc_assign(bb_graphics_context->m_defaultFont,c_Font::m_Load(String(L"mojo_font.png",13),32,96,true));
		}
		t_font=bb_graphics_context->m_defaultFont;
	}
	gc_assign(bb_graphics_context->m_font,t_font);
}
gxtkAudio* bb_audio_device;
int bb_audio_SetAudioDevice(gxtkAudio* t_dev){
	gc_assign(bb_audio_device,t_dev);
	return 0;
}
c_InputDevice::c_InputDevice(){
	m__joyStates=Array<c_JoyState* >(4);
	m__keyDown=Array<bool >(512);
	m__keyHitPut=0;
	m__keyHitQueue=Array<int >(33);
	m__keyHit=Array<int >(512);
	m__charGet=0;
	m__charPut=0;
	m__charQueue=Array<int >(32);
	m__mouseX=FLOAT(.0);
	m__mouseY=FLOAT(.0);
	m__mouseZ=FLOAT(.0);
	m__touchX=Array<Float >(32);
	m__touchY=Array<Float >(32);
	m__accelX=FLOAT(.0);
	m__accelY=FLOAT(.0);
	m__accelZ=FLOAT(.0);
}
c_InputDevice* c_InputDevice::m_new(){
	for(int t_i=0;t_i<4;t_i=t_i+1){
		gc_assign(m__joyStates[t_i],(new c_JoyState)->m_new());
	}
	return this;
}
void c_InputDevice::p_PutKeyHit(int t_key){
	if(m__keyHitPut==m__keyHitQueue.Length()){
		return;
	}
	m__keyHit[t_key]+=1;
	m__keyHitQueue[m__keyHitPut]=t_key;
	m__keyHitPut+=1;
}
void c_InputDevice::p_BeginUpdate(){
	for(int t_i=0;t_i<4;t_i=t_i+1){
		c_JoyState* t_state=m__joyStates[t_i];
		if(!BBGame::Game()->PollJoystick(t_i,t_state->m_joyx,t_state->m_joyy,t_state->m_joyz,t_state->m_buttons)){
			break;
		}
		for(int t_j=0;t_j<32;t_j=t_j+1){
			int t_key=256+t_i*32+t_j;
			if(t_state->m_buttons[t_j]){
				if(!m__keyDown[t_key]){
					m__keyDown[t_key]=true;
					p_PutKeyHit(t_key);
				}
			}else{
				m__keyDown[t_key]=false;
			}
		}
	}
}
void c_InputDevice::p_EndUpdate(){
	for(int t_i=0;t_i<m__keyHitPut;t_i=t_i+1){
		m__keyHit[m__keyHitQueue[t_i]]=0;
	}
	m__keyHitPut=0;
	m__charGet=0;
	m__charPut=0;
}
void c_InputDevice::p_KeyEvent(int t_event,int t_data){
	int t_1=t_event;
	if(t_1==1){
		if(!m__keyDown[t_data]){
			m__keyDown[t_data]=true;
			p_PutKeyHit(t_data);
			if(t_data==1){
				m__keyDown[384]=true;
				p_PutKeyHit(384);
			}else{
				if(t_data==384){
					m__keyDown[1]=true;
					p_PutKeyHit(1);
				}
			}
		}
	}else{
		if(t_1==2){
			if(m__keyDown[t_data]){
				m__keyDown[t_data]=false;
				if(t_data==1){
					m__keyDown[384]=false;
				}else{
					if(t_data==384){
						m__keyDown[1]=false;
					}
				}
			}
		}else{
			if(t_1==3){
				if(m__charPut<m__charQueue.Length()){
					m__charQueue[m__charPut]=t_data;
					m__charPut+=1;
				}
			}
		}
	}
}
void c_InputDevice::p_MouseEvent(int t_event,int t_data,Float t_x,Float t_y,Float t_z){
	int t_2=t_event;
	if(t_2==4){
		p_KeyEvent(1,1+t_data);
	}else{
		if(t_2==5){
			p_KeyEvent(2,1+t_data);
			return;
		}else{
			if(t_2==6){
			}else{
				return;
			}
		}
	}
	m__mouseX=t_x;
	m__mouseY=t_y;
	m__mouseZ=t_z;
	m__touchX[0]=t_x;
	m__touchY[0]=t_y;
}
void c_InputDevice::p_TouchEvent(int t_event,int t_data,Float t_x,Float t_y){
	int t_3=t_event;
	if(t_3==7){
		p_KeyEvent(1,384+t_data);
	}else{
		if(t_3==8){
			p_KeyEvent(2,384+t_data);
			return;
		}else{
			if(t_3==9){
			}else{
				return;
			}
		}
	}
	m__touchX[t_data]=t_x;
	m__touchY[t_data]=t_y;
	if(t_data==0){
		m__mouseX=t_x;
		m__mouseY=t_y;
	}
}
void c_InputDevice::p_MotionEvent(int t_event,int t_data,Float t_x,Float t_y,Float t_z){
	int t_4=t_event;
	if(t_4==10){
	}else{
		return;
	}
	m__accelX=t_x;
	m__accelY=t_y;
	m__accelZ=t_z;
}
int c_InputDevice::p_KeyHit(int t_key){
	if(t_key>0 && t_key<512){
		return m__keyHit[t_key];
	}
	return 0;
}
Float c_InputDevice::p_MouseX(){
	return m__mouseX;
}
Float c_InputDevice::p_MouseY(){
	return m__mouseY;
}
int c_InputDevice::p_GetChar(){
	if(m__charGet==m__charPut){
		return 0;
	}
	int t_chr=m__charQueue[m__charGet];
	m__charGet+=1;
	return t_chr;
}
bool c_InputDevice::p_KeyDown(int t_key){
	if(t_key>0 && t_key<512){
		return m__keyDown[t_key];
	}
	return false;
}
void c_InputDevice::mark(){
	Object::mark();
	gc_mark_q(m__joyStates);
	gc_mark_q(m__keyDown);
	gc_mark_q(m__keyHitQueue);
	gc_mark_q(m__keyHit);
	gc_mark_q(m__charQueue);
	gc_mark_q(m__touchX);
	gc_mark_q(m__touchY);
}
c_JoyState::c_JoyState(){
	m_joyx=Array<Float >(2);
	m_joyy=Array<Float >(2);
	m_joyz=Array<Float >(2);
	m_buttons=Array<bool >(32);
}
c_JoyState* c_JoyState::m_new(){
	return this;
}
void c_JoyState::mark(){
	Object::mark();
	gc_mark_q(m_joyx);
	gc_mark_q(m_joyy);
	gc_mark_q(m_joyz);
	gc_mark_q(m_buttons);
}
c_InputDevice* bb_input_device;
int bb_input_SetInputDevice(c_InputDevice* t_dev){
	gc_assign(bb_input_device,t_dev);
	return 0;
}
int bb_app__devWidth;
int bb_app__devHeight;
void bb_app_ValidateDeviceWindow(bool t_notifyApp){
	int t_w=bb_app__game->GetDeviceWidth();
	int t_h=bb_app__game->GetDeviceHeight();
	if(t_w==bb_app__devWidth && t_h==bb_app__devHeight){
		return;
	}
	bb_app__devWidth=t_w;
	bb_app__devHeight=t_h;
	if(t_notifyApp){
		bb_app__app->p_OnResize();
	}
}
c_DisplayMode::c_DisplayMode(){
	m__width=0;
	m__height=0;
}
c_DisplayMode* c_DisplayMode::m_new(int t_width,int t_height){
	m__width=t_width;
	m__height=t_height;
	return this;
}
c_DisplayMode* c_DisplayMode::m_new2(){
	return this;
}
void c_DisplayMode::mark(){
	Object::mark();
}
c_Map2::c_Map2(){
	m_root=0;
}
c_Map2* c_Map2::m_new(){
	return this;
}
c_Node2* c_Map2::p_FindNode(int t_key){
	c_Node2* t_node=m_root;
	while((t_node)!=0){
		int t_cmp=p_Compare(t_key,t_node->m_key);
		if(t_cmp>0){
			t_node=t_node->m_right;
		}else{
			if(t_cmp<0){
				t_node=t_node->m_left;
			}else{
				return t_node;
			}
		}
	}
	return t_node;
}
bool c_Map2::p_Contains(int t_key){
	return p_FindNode(t_key)!=0;
}
int c_Map2::p_RotateLeft2(c_Node2* t_node){
	c_Node2* t_child=t_node->m_right;
	gc_assign(t_node->m_right,t_child->m_left);
	if((t_child->m_left)!=0){
		gc_assign(t_child->m_left->m_parent,t_node);
	}
	gc_assign(t_child->m_parent,t_node->m_parent);
	if((t_node->m_parent)!=0){
		if(t_node==t_node->m_parent->m_left){
			gc_assign(t_node->m_parent->m_left,t_child);
		}else{
			gc_assign(t_node->m_parent->m_right,t_child);
		}
	}else{
		gc_assign(m_root,t_child);
	}
	gc_assign(t_child->m_left,t_node);
	gc_assign(t_node->m_parent,t_child);
	return 0;
}
int c_Map2::p_RotateRight2(c_Node2* t_node){
	c_Node2* t_child=t_node->m_left;
	gc_assign(t_node->m_left,t_child->m_right);
	if((t_child->m_right)!=0){
		gc_assign(t_child->m_right->m_parent,t_node);
	}
	gc_assign(t_child->m_parent,t_node->m_parent);
	if((t_node->m_parent)!=0){
		if(t_node==t_node->m_parent->m_right){
			gc_assign(t_node->m_parent->m_right,t_child);
		}else{
			gc_assign(t_node->m_parent->m_left,t_child);
		}
	}else{
		gc_assign(m_root,t_child);
	}
	gc_assign(t_child->m_right,t_node);
	gc_assign(t_node->m_parent,t_child);
	return 0;
}
int c_Map2::p_InsertFixup2(c_Node2* t_node){
	while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){
		if(t_node->m_parent==t_node->m_parent->m_parent->m_left){
			c_Node2* t_uncle=t_node->m_parent->m_parent->m_right;
			if(((t_uncle)!=0) && t_uncle->m_color==-1){
				t_node->m_parent->m_color=1;
				t_uncle->m_color=1;
				t_uncle->m_parent->m_color=-1;
				t_node=t_uncle->m_parent;
			}else{
				if(t_node==t_node->m_parent->m_right){
					t_node=t_node->m_parent;
					p_RotateLeft2(t_node);
				}
				t_node->m_parent->m_color=1;
				t_node->m_parent->m_parent->m_color=-1;
				p_RotateRight2(t_node->m_parent->m_parent);
			}
		}else{
			c_Node2* t_uncle2=t_node->m_parent->m_parent->m_left;
			if(((t_uncle2)!=0) && t_uncle2->m_color==-1){
				t_node->m_parent->m_color=1;
				t_uncle2->m_color=1;
				t_uncle2->m_parent->m_color=-1;
				t_node=t_uncle2->m_parent;
			}else{
				if(t_node==t_node->m_parent->m_left){
					t_node=t_node->m_parent;
					p_RotateRight2(t_node);
				}
				t_node->m_parent->m_color=1;
				t_node->m_parent->m_parent->m_color=-1;
				p_RotateLeft2(t_node->m_parent->m_parent);
			}
		}
	}
	m_root->m_color=1;
	return 0;
}
bool c_Map2::p_Set(int t_key,c_DisplayMode* t_value){
	c_Node2* t_node=m_root;
	c_Node2* t_parent=0;
	int t_cmp=0;
	while((t_node)!=0){
		t_parent=t_node;
		t_cmp=p_Compare(t_key,t_node->m_key);
		if(t_cmp>0){
			t_node=t_node->m_right;
		}else{
			if(t_cmp<0){
				t_node=t_node->m_left;
			}else{
				gc_assign(t_node->m_value,t_value);
				return false;
			}
		}
	}
	t_node=(new c_Node2)->m_new(t_key,t_value,-1,t_parent);
	if((t_parent)!=0){
		if(t_cmp>0){
			gc_assign(t_parent->m_right,t_node);
		}else{
			gc_assign(t_parent->m_left,t_node);
		}
		p_InsertFixup2(t_node);
	}else{
		gc_assign(m_root,t_node);
	}
	return true;
}
bool c_Map2::p_Insert(int t_key,c_DisplayMode* t_value){
	return p_Set(t_key,t_value);
}
void c_Map2::mark(){
	Object::mark();
	gc_mark_q(m_root);
}
c_IntMap2::c_IntMap2(){
}
c_IntMap2* c_IntMap2::m_new(){
	c_Map2::m_new();
	return this;
}
int c_IntMap2::p_Compare(int t_lhs,int t_rhs){
	return t_lhs-t_rhs;
}
void c_IntMap2::mark(){
	c_Map2::mark();
}
c_Stack::c_Stack(){
	m_data=Array<c_DisplayMode* >();
	m_length=0;
}
c_Stack* c_Stack::m_new(){
	return this;
}
c_Stack* c_Stack::m_new2(Array<c_DisplayMode* > t_data){
	gc_assign(this->m_data,t_data.Slice(0));
	this->m_length=t_data.Length();
	return this;
}
void c_Stack::p_Push(c_DisplayMode* t_value){
	if(m_length==m_data.Length()){
		gc_assign(m_data,m_data.Resize(m_length*2+10));
	}
	gc_assign(m_data[m_length],t_value);
	m_length+=1;
}
void c_Stack::p_Push2(Array<c_DisplayMode* > t_values,int t_offset,int t_count){
	for(int t_i=0;t_i<t_count;t_i=t_i+1){
		p_Push(t_values[t_offset+t_i]);
	}
}
void c_Stack::p_Push3(Array<c_DisplayMode* > t_values,int t_offset){
	p_Push2(t_values,t_offset,t_values.Length()-t_offset);
}
Array<c_DisplayMode* > c_Stack::p_ToArray(){
	Array<c_DisplayMode* > t_t=Array<c_DisplayMode* >(m_length);
	for(int t_i=0;t_i<m_length;t_i=t_i+1){
		gc_assign(t_t[t_i],m_data[t_i]);
	}
	return t_t;
}
void c_Stack::mark(){
	Object::mark();
	gc_mark_q(m_data);
}
c_Node2::c_Node2(){
	m_key=0;
	m_right=0;
	m_left=0;
	m_value=0;
	m_color=0;
	m_parent=0;
}
c_Node2* c_Node2::m_new(int t_key,c_DisplayMode* t_value,int t_color,c_Node2* t_parent){
	this->m_key=t_key;
	gc_assign(this->m_value,t_value);
	this->m_color=t_color;
	gc_assign(this->m_parent,t_parent);
	return this;
}
c_Node2* c_Node2::m_new2(){
	return this;
}
void c_Node2::mark(){
	Object::mark();
	gc_mark_q(m_right);
	gc_mark_q(m_left);
	gc_mark_q(m_value);
	gc_mark_q(m_parent);
}
Array<c_DisplayMode* > bb_app__displayModes;
c_DisplayMode* bb_app__desktopMode;
int bb_app_DeviceWidth(){
	return bb_app__devWidth;
}
int bb_app_DeviceHeight(){
	return bb_app__devHeight;
}
void bb_app_EnumDisplayModes(){
	Array<BBDisplayMode* > t_modes=bb_app__game->GetDisplayModes();
	c_IntMap2* t_mmap=(new c_IntMap2)->m_new();
	c_Stack* t_mstack=(new c_Stack)->m_new();
	for(int t_i=0;t_i<t_modes.Length();t_i=t_i+1){
		int t_w=t_modes[t_i]->width;
		int t_h=t_modes[t_i]->height;
		int t_size=t_w<<16|t_h;
		if(t_mmap->p_Contains(t_size)){
		}else{
			c_DisplayMode* t_mode=(new c_DisplayMode)->m_new(t_modes[t_i]->width,t_modes[t_i]->height);
			t_mmap->p_Insert(t_size,t_mode);
			t_mstack->p_Push(t_mode);
		}
	}
	gc_assign(bb_app__displayModes,t_mstack->p_ToArray());
	BBDisplayMode* t_mode2=bb_app__game->GetDesktopMode();
	if((t_mode2)!=0){
		gc_assign(bb_app__desktopMode,(new c_DisplayMode)->m_new(t_mode2->width,t_mode2->height));
	}else{
		gc_assign(bb_app__desktopMode,(new c_DisplayMode)->m_new(bb_app_DeviceWidth(),bb_app_DeviceHeight()));
	}
}
gxtkGraphics* bb_graphics_renderDevice;
int bb_graphics_SetMatrix(Float t_ix,Float t_iy,Float t_jx,Float t_jy,Float t_tx,Float t_ty){
	bb_graphics_context->m_ix=t_ix;
	bb_graphics_context->m_iy=t_iy;
	bb_graphics_context->m_jx=t_jx;
	bb_graphics_context->m_jy=t_jy;
	bb_graphics_context->m_tx=t_tx;
	bb_graphics_context->m_ty=t_ty;
	bb_graphics_context->m_tformed=((t_ix!=FLOAT(1.0) || t_iy!=FLOAT(0.0) || t_jx!=FLOAT(0.0) || t_jy!=FLOAT(1.0) || t_tx!=FLOAT(0.0) || t_ty!=FLOAT(0.0))?1:0);
	bb_graphics_context->m_matDirty=1;
	return 0;
}
int bb_graphics_SetMatrix2(Array<Float > t_m){
	bb_graphics_SetMatrix(t_m[0],t_m[1],t_m[2],t_m[3],t_m[4],t_m[5]);
	return 0;
}
int bb_graphics_SetColor(Float t_r,Float t_g,Float t_b){
	bb_graphics_context->m_color_r=t_r;
	bb_graphics_context->m_color_g=t_g;
	bb_graphics_context->m_color_b=t_b;
	bb_graphics_renderDevice->SetColor(t_r,t_g,t_b);
	return 0;
}
int bb_graphics_SetColor2(Float t_rgb){
	bb_graphics_context->m_color_r=Float(int(t_rgb)>>16&255);
	bb_graphics_context->m_color_g=Float(int(t_rgb)>>8&255);
	bb_graphics_context->m_color_b=Float(int(t_rgb)&255);
	bb_graphics_renderDevice->SetColor(bb_graphics_context->m_color_r,bb_graphics_context->m_color_g,bb_graphics_context->m_color_b);
	return 0;
}
int bb_graphics_SetAlpha(Float t_alpha){
	bb_graphics_context->m_alpha=t_alpha;
	bb_graphics_renderDevice->SetAlpha(t_alpha);
	return 0;
}
int bb_graphics_SetBlend(int t_blend){
	bb_graphics_context->m_blend=t_blend;
	bb_graphics_renderDevice->SetBlend(t_blend);
	return 0;
}
int bb_graphics_SetScissor(Float t_x,Float t_y,Float t_width,Float t_height){
	bb_graphics_context->m_scissor_x=t_x;
	bb_graphics_context->m_scissor_y=t_y;
	bb_graphics_context->m_scissor_width=t_width;
	bb_graphics_context->m_scissor_height=t_height;
	bb_graphics_renderDevice->SetScissor(int(t_x),int(t_y),int(t_width),int(t_height));
	return 0;
}
int bb_graphics_BeginRender(){
	gc_assign(bb_graphics_renderDevice,bb_graphics_device);
	bb_graphics_context->m_matrixSp=0;
	bb_graphics_SetMatrix(FLOAT(1.0),FLOAT(0.0),FLOAT(0.0),FLOAT(1.0),FLOAT(0.0),FLOAT(0.0));
	bb_graphics_SetColor(FLOAT(255.0),FLOAT(255.0),FLOAT(255.0));
	bb_graphics_SetAlpha(FLOAT(1.0));
	bb_graphics_SetBlend(0);
	bb_graphics_SetScissor(FLOAT(0.0),FLOAT(0.0),Float(bb_app_DeviceWidth()),Float(bb_app_DeviceHeight()));
	return 0;
}
int bb_graphics_EndRender(){
	bb_graphics_renderDevice=0;
	return 0;
}
c_BBGameEvent::c_BBGameEvent(){
}
void c_BBGameEvent::mark(){
	Object::mark();
}
void bb_app_EndApp(){
	bbError(String());
}
int bb_app__updateRate;
void bb_app_SetUpdateRate(int t_hertz){
	bb_app__updateRate=t_hertz;
	bb_app__game->SetUpdateRate(t_hertz);
}
c_Sound::c_Sound(){
	m_sample=0;
}
c_Sound* c_Sound::m_new(gxtkSample* t_sample){
	gc_assign(this->m_sample,t_sample);
	return this;
}
c_Sound* c_Sound::m_new2(){
	return this;
}
void c_Sound::mark(){
	Object::mark();
	gc_mark_q(m_sample);
}
c_Sound* bb_audio_LoadSound(String t_path){
	gxtkSample* t_sample=bb_audio_device->LoadSample(bb_data_FixDataPath(t_path));
	if((t_sample)!=0){
		return (new c_Sound)->m_new(t_sample);
	}
	return 0;
}
int bb_input_KeyHit(int t_key){
	return bb_input_device->p_KeyHit(t_key);
}
Float bb_input_MouseX(){
	return bb_input_device->p_MouseX();
}
Float bb_input_MouseY(){
	return bb_input_device->p_MouseY();
}
int bb_input_MouseHit(int t_button){
	return bb_input_device->p_KeyHit(1+t_button);
}
int bb_slksound_BigButtonZone(int t_x,int t_y,int t_id){
	int t_MButton=0;
	if(bb_input_MouseX()>Float(t_x) && bb_input_MouseX()<Float(t_x+54) && bb_input_MouseY()>Float(t_y+2) && bb_input_MouseY()<Float(t_y+18) && ((bb_input_MouseHit(0))!=0)){
		t_MButton=t_id;
	}
	return t_MButton;
}
int bb_audio_StopChannel(int t_channel){
	bb_audio_device->StopChannel(t_channel);
	return 0;
}
int bb_slksound_PauseAll(){
	bb_audio_StopChannel(1);
	bb_audio_StopChannel(2);
	bb_audio_StopChannel(3);
	bb_audio_StopChannel(4);
	bb_audio_StopChannel(6);
	bb_audio_StopChannel(5);
	bb_audio_StopChannel(8);
	bb_audio_StopChannel(7);
	return 0;
}
int bb_slksound_ToInputField(int t_x,int t_y){
	int t_MButton=0;
	if(bb_input_MouseX()>Float(t_x) && bb_input_MouseX()<Float(t_x+380) && bb_input_MouseY()>Float(t_y+2) && bb_input_MouseY()<Float(t_y+16) && ((bb_input_MouseHit(0))!=0)){
		t_MButton=1;
	}
	return t_MButton;
}
int bb_input_GetChar(){
	return bb_input_device->p_GetChar();
}
String bb_slksound_FString(String t_fnd){
	String t_fstr=String(L"" L"\xfc" L"" L"\xe4" L"" L"\xf6" L" abcdefghijklmnopqrstuvwxyz!-._()&+[]/1234567890",51);
	for(int t_j=0;t_j<=t_fstr.Length();t_j=t_j+1){
		if(String((int)t_fstr[t_j])==t_fnd){
			return String(L"1",1);
		}
	}
	return String();
}
c_Stream::c_Stream(){
}
c_Stream* c_Stream::m_new(){
	return this;
}
void c_Stream::p_WriteError(){
	throw (new c_StreamWriteError)->m_new(this);
}
void c_Stream::p_WriteAll(c_DataBuffer* t_buffer,int t_offset,int t_count){
	while(t_count>0){
		int t_n=p_Write(t_buffer,t_offset,t_count);
		if(t_n<=0){
			p_WriteError();
		}
		t_offset+=t_n;
		t_count-=t_n;
	}
}
void c_Stream::p_WriteString(String t_value,String t_encoding){
	c_DataBuffer* t_buf=(new c_DataBuffer)->m_new(t_value.Length()*3,false);
	int t_len=t_buf->p_PokeString(0,t_value,String(L"utf8",4));
	p_WriteAll(t_buf,0,t_len);
}
void c_Stream::mark(){
	Object::mark();
}
c_FileStream::c_FileStream(){
	m__stream=0;
}
BBFileStream* c_FileStream::m_OpenStream(String t_path,String t_mode){
	BBFileStream* t_stream=(new BBFileStream);
	String t_fmode=t_mode;
	if(t_fmode==String(L"a",1)){
		t_fmode=String(L"u",1);
	}
	if(!t_stream->Open(t_path,t_fmode)){
		return 0;
	}
	if(t_mode==String(L"a",1)){
		t_stream->Seek(t_stream->Length());
	}
	return t_stream;
}
c_FileStream* c_FileStream::m_new(String t_path,String t_mode){
	c_Stream::m_new();
	gc_assign(m__stream,m_OpenStream(t_path,t_mode));
	if(!((m__stream)!=0)){
		bbError(String(L"Failed to open stream",21));
	}
	return this;
}
c_FileStream* c_FileStream::m_new2(BBFileStream* t_stream){
	c_Stream::m_new();
	gc_assign(m__stream,t_stream);
	return this;
}
c_FileStream* c_FileStream::m_new3(){
	c_Stream::m_new();
	return this;
}
c_FileStream* c_FileStream::m_Open(String t_path,String t_mode){
	BBFileStream* t_stream=m_OpenStream(t_path,t_mode);
	if((t_stream)!=0){
		return (new c_FileStream)->m_new2(t_stream);
	}
	return 0;
}
void c_FileStream::p_Close(){
	if(!((m__stream)!=0)){
		return;
	}
	m__stream->Close();
	m__stream=0;
}
int c_FileStream::p_Write(c_DataBuffer* t_buffer,int t_offset,int t_count){
	return m__stream->Write(t_buffer,t_offset,t_count);
}
void c_FileStream::mark(){
	c_Stream::mark();
	gc_mark_q(m__stream);
}
c_DataBuffer::c_DataBuffer(){
}
c_DataBuffer* c_DataBuffer::m_new(int t_length,bool t_direct){
	if(!_New(t_length)){
		bbError(String(L"Allocate DataBuffer failed",26));
	}
	return this;
}
c_DataBuffer* c_DataBuffer::m_new2(){
	return this;
}
void c_DataBuffer::p_PokeBytes(int t_address,Array<int > t_bytes,int t_offset,int t_count){
	if(t_address+t_count>Length()){
		t_count=Length()-t_address;
	}
	if(t_offset+t_count>t_bytes.Length()){
		t_count=t_bytes.Length()-t_offset;
	}
	for(int t_i=0;t_i<t_count;t_i=t_i+1){
		PokeByte(t_address+t_i,t_bytes[t_offset+t_i]);
	}
}
int c_DataBuffer::p_PokeString(int t_address,String t_str,String t_encoding){
	String t_2=t_encoding;
	if(t_2==String(L"utf8",4)){
		Array<int > t_p=t_str.ToChars();
		int t_i=0;
		int t_e=t_p.Length();
		Array<int > t_q=Array<int >(t_e*3);
		int t_j=0;
		while(t_i<t_e){
			int t_c=t_p[t_i]&65535;
			t_i+=1;
			if(t_c<128){
				t_q[t_j]=t_c;
				t_j+=1;
			}else{
				if(t_c<2048){
					t_q[t_j]=192|t_c>>6;
					t_q[t_j+1]=128|t_c&63;
					t_j+=2;
				}else{
					t_q[t_j]=224|t_c>>12;
					t_q[t_j+1]=128|t_c>>6&63;
					t_q[t_j+2]=128|t_c&63;
					t_j+=3;
				}
			}
		}
		p_PokeBytes(t_address,t_q,0,t_j);
		return t_j;
	}else{
		if(t_2==String(L"ascii",5)){
			p_PokeBytes(t_address,t_str.ToChars(),0,t_str.Length());
			return t_str.Length();
		}
	}
	bbError(String(L"Invalid string encoding:",24)+t_encoding);
	return 0;
}
void c_DataBuffer::mark(){
	BBDataBuffer::mark();
}
c_StreamError::c_StreamError(){
	m__stream=0;
}
c_StreamError* c_StreamError::m_new(c_Stream* t_stream){
	gc_assign(m__stream,t_stream);
	return this;
}
c_StreamError* c_StreamError::m_new2(){
	return this;
}
void c_StreamError::mark(){
	ThrowableObject::mark();
	gc_mark_q(m__stream);
}
c_StreamWriteError::c_StreamWriteError(){
}
c_StreamWriteError* c_StreamWriteError::m_new(c_Stream* t_stream){
	c_StreamError::m_new(t_stream);
	return this;
}
c_StreamWriteError* c_StreamWriteError::m_new2(){
	c_StreamError::m_new2();
	return this;
}
void c_StreamWriteError::mark(){
	c_StreamError::mark();
}
int bb_input_KeyDown(int t_key){
	return ((bb_input_device->p_KeyDown(t_key))?1:0);
}
String bb_slksound_ChangeTrack(String t_Track,int t_Pos,String t_Val){
	String t_Changed=String();
	t_Changed=t_Track;
	t_Changed=t_Track.Slice(0,t_Pos-1)+t_Val;
	t_Changed=t_Changed+t_Track.Slice(t_Pos);
	return t_Changed;
}
String bb_slksound_Int2Char(int t_i){
	String t_n=String();
	t_n=String(t_i);
	if(t_i==10){
		t_n=String(L"A",1);
	}
	if(t_i==11){
		t_n=String(L"B",1);
	}
	if(t_i==12){
		t_n=String(L"C",1);
	}
	if(t_i==13){
		t_n=String(L"D",1);
	}
	if(t_i==14){
		t_n=String(L"E",1);
	}
	if(t_i==15){
		t_n=String(L"F",1);
	}
	return t_n;
}
int bb_slksound_PlayTrack(String t_Track,int t_i){
	int t_p1=0;
	if(t_Track.Slice(t_i,t_i+1)==String(L"<",1)){
		t_p1=128;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L".",1)){
		t_p1=255;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"y",1)){
		t_p1=0;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"s",1)){
		t_p1=1;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"x",1)){
		t_p1=2;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"d",1)){
		t_p1=3;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"c",1)){
		t_p1=4;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"v",1)){
		t_p1=5;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"g",1)){
		t_p1=6;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"b",1)){
		t_p1=7;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"h",1)){
		t_p1=8;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"n",1)){
		t_p1=9;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"j",1)){
		t_p1=10;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"m",1)){
		t_p1=11;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"q",1)){
		t_p1=12;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"2",1)){
		t_p1=13;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"w",1)){
		t_p1=14;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"3",1)){
		t_p1=15;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"e",1)){
		t_p1=16;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"r",1)){
		t_p1=17;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"5",1)){
		t_p1=18;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"t",1)){
		t_p1=19;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"6",1)){
		t_p1=20;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"z",1)){
		t_p1=21;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"7",1)){
		t_p1=22;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"u",1)){
		t_p1=23;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"i",1)){
		t_p1=24;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"9",1)){
		t_p1=25;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"o",1)){
		t_p1=26;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"0",1)){
		t_p1=27;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"p",1)){
		t_p1=28;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"+",1)){
		t_p1=127;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"#",1)){
		t_p1=129;
	}
	if(t_Track.Slice(t_i,t_i+1)==String(L"-",1)){
		t_p1=130;
	}
	return t_p1;
}
int bb_audio_SetChannelRate(int t_channel,Float t_rate){
	bb_audio_device->SetRate(t_channel,t_rate);
	return 0;
}
int bb_audio_PlaySound(c_Sound* t_sound,int t_channel,int t_flags){
	if(((t_sound)!=0) && ((t_sound->m_sample)!=0)){
		bb_audio_device->PlaySample(t_sound->m_sample,t_channel,t_flags);
	}
	return 0;
}
Float bb_slksound_PlayInst(c_Sound* t_wave,int t_note,int t_channel,int t_loop,c_Sound* t_Ramp,Float t_PWM,int t_pwmfix,Float t_fine,int t_oct){
	if(t_note==104+12*t_oct){
		bb_audio_StopChannel(t_channel);
	}
	if(t_note==104+12*t_oct){
		bb_audio_StopChannel(t_channel+4);
	}
	if(t_note<44){
		bb_audio_SetChannelRate(t_channel,(Float)pow(FLOAT(1.059463094),Float(t_note))+t_fine);
		bb_audio_SetChannelRate(t_channel+4,(Float)pow(FLOAT(1.059463094),Float(t_note))+t_fine+t_PWM/FLOAT(800.0));
		if(t_pwmfix>0){
			bb_audio_PlaySound(t_wave,t_channel,t_loop);
			bb_audio_PlaySound(t_Ramp,t_channel+4,t_loop);
		}
	}
	return FLOAT(0.0);
}
int bb_audio_SetChannelVolume(int t_channel,Float t_volume){
	bb_audio_device->SetVolume(t_channel,t_volume);
	return 0;
}
int bb_slksound_ButtonZone(int t_x,int t_y,int t_val,int t_min,int t_max){
	int t_MButton=0;
	t_MButton=t_val;
	if(bb_input_MouseX()>Float(t_x) && bb_input_MouseX()<Float(t_x+16) && bb_input_MouseY()>Float(t_y+2) && bb_input_MouseY()<Float(t_y+14) && ((bb_input_MouseHit(0))!=0) && t_val>t_min){
		t_MButton=t_val-1;
	}
	if(bb_input_MouseX()>Float(t_x+16) && bb_input_MouseX()<Float(t_x+32) && bb_input_MouseY()>Float(t_y+2) && bb_input_MouseY()<Float(t_y+14) && ((bb_input_MouseHit(0))!=0) && t_val<t_max){
		t_MButton=t_val+1;
	}
	if(t_MButton<t_min){
		t_MButton=t_min;
	}
	if(t_MButton>t_max){
		t_MButton=t_max;
	}
	return t_MButton;
}
int bb_slksound_Char2Int(String t_i){
	int t_n=0;
	t_n=(t_i).ToInt();
	if(t_i==String(L"a",1) || t_i==String(L"A",1)){
		t_n=10;
	}
	if(t_i==String(L"b",1) || t_i==String(L"B",1)){
		t_n=11;
	}
	if(t_i==String(L"c",1) || t_i==String(L"C",1)){
		t_n=12;
	}
	if(t_i==String(L"d",1) || t_i==String(L"D",1)){
		t_n=13;
	}
	if(t_i==String(L"e",1) || t_i==String(L"E",1)){
		t_n=14;
	}
	if(t_i==String(L"f",1) || t_i==String(L"F",1)){
		t_n=15;
	}
	return t_n;
}
int bb_graphics_Cls(Float t_r,Float t_g,Float t_b){
	bb_graphics_renderDevice->Cls(t_r,t_g,t_b);
	return 0;
}
int bb_graphics_DrawRect(Float t_x,Float t_y,Float t_w,Float t_h){
	bb_graphics_context->p_Validate();
	bb_graphics_renderDevice->DrawRect(t_x,t_y,t_w,t_h);
	return 0;
}
int bb_graphics_DrawImageRect(c_Image* t_image,Float t_x,Float t_y,int t_srcX,int t_srcY,int t_srcWidth,int t_srcHeight,int t_frame){
	c_Frame* t_f=t_image->m_frames[t_frame];
	bb_graphics_context->p_Validate();
	bb_graphics_renderDevice->DrawSurface2(t_image->m_surface,-t_image->m_tx+t_x,-t_image->m_ty+t_y,t_srcX+t_f->m_x,t_srcY+t_f->m_y,t_srcWidth,t_srcHeight);
	return 0;
}
int bb_graphics_PushMatrix(){
	int t_sp=bb_graphics_context->m_matrixSp;
	if(t_sp==bb_graphics_context->m_matrixStack.Length()){
		gc_assign(bb_graphics_context->m_matrixStack,bb_graphics_context->m_matrixStack.Resize(t_sp*2));
	}
	bb_graphics_context->m_matrixStack[t_sp+0]=bb_graphics_context->m_ix;
	bb_graphics_context->m_matrixStack[t_sp+1]=bb_graphics_context->m_iy;
	bb_graphics_context->m_matrixStack[t_sp+2]=bb_graphics_context->m_jx;
	bb_graphics_context->m_matrixStack[t_sp+3]=bb_graphics_context->m_jy;
	bb_graphics_context->m_matrixStack[t_sp+4]=bb_graphics_context->m_tx;
	bb_graphics_context->m_matrixStack[t_sp+5]=bb_graphics_context->m_ty;
	bb_graphics_context->m_matrixSp=t_sp+6;
	return 0;
}
int bb_graphics_Transform(Float t_ix,Float t_iy,Float t_jx,Float t_jy,Float t_tx,Float t_ty){
	Float t_ix2=t_ix*bb_graphics_context->m_ix+t_iy*bb_graphics_context->m_jx;
	Float t_iy2=t_ix*bb_graphics_context->m_iy+t_iy*bb_graphics_context->m_jy;
	Float t_jx2=t_jx*bb_graphics_context->m_ix+t_jy*bb_graphics_context->m_jx;
	Float t_jy2=t_jx*bb_graphics_context->m_iy+t_jy*bb_graphics_context->m_jy;
	Float t_tx2=t_tx*bb_graphics_context->m_ix+t_ty*bb_graphics_context->m_jx+bb_graphics_context->m_tx;
	Float t_ty2=t_tx*bb_graphics_context->m_iy+t_ty*bb_graphics_context->m_jy+bb_graphics_context->m_ty;
	bb_graphics_SetMatrix(t_ix2,t_iy2,t_jx2,t_jy2,t_tx2,t_ty2);
	return 0;
}
int bb_graphics_Transform2(Array<Float > t_m){
	bb_graphics_Transform(t_m[0],t_m[1],t_m[2],t_m[3],t_m[4],t_m[5]);
	return 0;
}
int bb_graphics_Translate(Float t_x,Float t_y){
	bb_graphics_Transform(FLOAT(1.0),FLOAT(0.0),FLOAT(0.0),FLOAT(1.0),t_x,t_y);
	return 0;
}
int bb_graphics_Rotate(Float t_angle){
	bb_graphics_Transform((Float)cos((t_angle)*D2R),-(Float)sin((t_angle)*D2R),(Float)sin((t_angle)*D2R),(Float)cos((t_angle)*D2R),FLOAT(0.0),FLOAT(0.0));
	return 0;
}
int bb_graphics_Scale(Float t_x,Float t_y){
	bb_graphics_Transform(t_x,FLOAT(0.0),FLOAT(0.0),t_y,FLOAT(0.0),FLOAT(0.0));
	return 0;
}
int bb_graphics_PopMatrix(){
	int t_sp=bb_graphics_context->m_matrixSp-6;
	bb_graphics_SetMatrix(bb_graphics_context->m_matrixStack[t_sp+0],bb_graphics_context->m_matrixStack[t_sp+1],bb_graphics_context->m_matrixStack[t_sp+2],bb_graphics_context->m_matrixStack[t_sp+3],bb_graphics_context->m_matrixStack[t_sp+4],bb_graphics_context->m_matrixStack[t_sp+5]);
	bb_graphics_context->m_matrixSp=t_sp;
	return 0;
}
int bb_graphics_DrawImageRect2(c_Image* t_image,Float t_x,Float t_y,int t_srcX,int t_srcY,int t_srcWidth,int t_srcHeight,Float t_rotation,Float t_scaleX,Float t_scaleY,int t_frame){
	c_Frame* t_f=t_image->m_frames[t_frame];
	bb_graphics_PushMatrix();
	bb_graphics_Translate(t_x,t_y);
	bb_graphics_Rotate(t_rotation);
	bb_graphics_Scale(t_scaleX,t_scaleY);
	bb_graphics_Translate(-t_image->m_tx,-t_image->m_ty);
	bb_graphics_context->p_Validate();
	bb_graphics_renderDevice->DrawSurface2(t_image->m_surface,FLOAT(0.0),FLOAT(0.0),t_srcX+t_f->m_x,t_srcY+t_f->m_y,t_srcWidth,t_srcHeight);
	bb_graphics_PopMatrix();
	return 0;
}
void bb_graphics_DrawText(String t_text,int t_x,int t_y,Float t_xhandle,Float t_yhandle){
	int t_char=0;
	c_Glyph* t_tmpChar=0;
	if(!((bb_graphics_context->m_font)!=0)){
		return;
	}
	t_x=int(Float(t_x)-bb_graphics_context->m_font->p_TextWidth(t_text)*t_xhandle);
	t_y=int(Float(t_y)-bb_graphics_context->m_font->p_TextHeight(t_text)*t_yhandle);
	String t_=t_text;
	int t_2=0;
	while(t_2<t_.Length()){
		t_char=(int)t_[t_2];
		t_2=t_2+1;
		c_Glyph* t_tmpChar2=bb_graphics_context->m_font->m__charMap->p_Get(t_char);
		if(!((t_tmpChar2)!=0)){
			continue;
		}
		bb_graphics_DrawImageRect(bb_graphics_context->m_font->m__pages[t_tmpChar2->m_page],Float(t_x+t_tmpChar2->m_xoff),Float(t_y+t_tmpChar2->m_yoff),t_tmpChar2->m_x,t_tmpChar2->m_y,t_tmpChar2->m_width,t_tmpChar2->m_height,0);
		t_x+=t_tmpChar2->m_advance;
	}
}
void bb_graphics_DrawText2(Array<String > t_textLines,int t_x,int t_y,Float t_xhandle,Float t_yhandle){
	int t_char=0;
	c_Glyph* t_tmpChar=0;
	Float t_currX=FLOAT(.0);
	String t_text=String();
	int t_linesCount=t_textLines.Length();
	t_y=int(Float(t_y)-bb_graphics_context->m_font->p_TextHeight(String())*t_yhandle*Float(t_linesCount));
	t_currX=Float(t_x);
	for(int t__y=1;t__y<=t_linesCount;t__y=t__y+1){
		t_text=t_textLines[t__y-1];
		t_x=int(Float(t_x)-bb_graphics_context->m_font->p_TextWidth(t_text)*t_xhandle);
		String t_=t_text;
		int t_2=0;
		while(t_2<t_.Length()){
			t_char=(int)t_[t_2];
			t_2=t_2+1;
			c_Glyph* t_tmpChar2=bb_graphics_context->m_font->m__charMap->p_Get(t_char);
			if(!((t_tmpChar2)!=0)){
				continue;
			}
			bb_graphics_DrawImageRect(bb_graphics_context->m_font->m__pages[t_tmpChar2->m_page],Float(t_x+t_tmpChar2->m_xoff),Float(t_y+t_tmpChar2->m_yoff),t_tmpChar2->m_x,t_tmpChar2->m_y,t_tmpChar2->m_width,t_tmpChar2->m_height,0);
			t_x+=t_tmpChar2->m_advance;
		}
		t_y=int(Float(t_y)+bb_graphics_context->m_font->p_TextHeight(t_text));
		t_x=int(t_currX);
	}
}
String bb_slksound_Hex8(int t_i){
	String t_short=String();
	int t_r=t_i;
	int t_s=0;
	int t_p=32;
	Array<int > t_n=Array<int >(t_p/4+1);
	while(t_p>0){
		t_s=(t_r&15)+48;
		if(t_s>57){
			t_s+=7;
		}
		t_p-=4;
		t_n[t_p>>2]=t_s;
		t_r=t_r>>4;
	}
	t_short=String::FromChars(t_n);
	return t_short.Slice(6,8);
}
String bb_slksound_Translate2Note(String t_Track,int t_i,String t_oct){
	String t_p1=String();
	if(t_oct.Slice(t_i,t_i+1)==String(L"0",1)){
		if(t_i<t_Track.Length()){
			t_p1=String(L"???",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"<",1)){
			t_p1=String(L"{|}",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L".",1)){
			t_p1=String(L"---",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"y",1)){
			t_p1=String(L"C-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"s",1)){
			t_p1=String(L"C#0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"x",1)){
			t_p1=String(L"D-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"d",1)){
			t_p1=String(L"D#0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"c",1)){
			t_p1=String(L"E-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"v",1)){
			t_p1=String(L"F-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"g",1)){
			t_p1=String(L"F#0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"b",1)){
			t_p1=String(L"G-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"h",1)){
			t_p1=String(L"G#0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"n",1)){
			t_p1=String(L"A-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"j",1)){
			t_p1=String(L"A#0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"m",1)){
			t_p1=String(L"B-0",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"q",1)){
			t_p1=String(L"C-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"2",1)){
			t_p1=String(L"C#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"w",1)){
			t_p1=String(L"D-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"3",1)){
			t_p1=String(L"D#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"e",1)){
			t_p1=String(L"E-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"r",1)){
			t_p1=String(L"F-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"5",1)){
			t_p1=String(L"F#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"t",1)){
			t_p1=String(L"G-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"6",1)){
			t_p1=String(L"G#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"z",1)){
			t_p1=String(L"A-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"7",1)){
			t_p1=String(L"A#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"u",1)){
			t_p1=String(L"B-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"i",1)){
			t_p1=String(L"C-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"9",1)){
			t_p1=String(L"C#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"o",1)){
			t_p1=String(L"D-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"0",1)){
			t_p1=String(L"D#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"p",1)){
			t_p1=String(L"E-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"+",1)){
			t_p1=String(L"-dn",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"#",1)){
			t_p1=String(L"-up",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"-",1)){
			t_p1=String(L"End",3);
		}
	}
	if(t_oct.Slice(t_i,t_i+1)==String(L"1",1)){
		if(t_i<t_Track.Length()){
			t_p1=String(L"???",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"<",1)){
			t_p1=String(L"{|}",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L".",1)){
			t_p1=String(L"---",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"y",1)){
			t_p1=String(L"C-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"s",1)){
			t_p1=String(L"C#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"x",1)){
			t_p1=String(L"D-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"d",1)){
			t_p1=String(L"D#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"c",1)){
			t_p1=String(L"E-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"v",1)){
			t_p1=String(L"F-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"g",1)){
			t_p1=String(L"F#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"b",1)){
			t_p1=String(L"G-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"h",1)){
			t_p1=String(L"G#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"n",1)){
			t_p1=String(L"A-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"j",1)){
			t_p1=String(L"A#1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"m",1)){
			t_p1=String(L"B-1",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"q",1)){
			t_p1=String(L"C-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"2",1)){
			t_p1=String(L"C#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"w",1)){
			t_p1=String(L"D-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"3",1)){
			t_p1=String(L"D#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"e",1)){
			t_p1=String(L"E-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"r",1)){
			t_p1=String(L"F-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"5",1)){
			t_p1=String(L"F#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"t",1)){
			t_p1=String(L"G-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"6",1)){
			t_p1=String(L"G#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"z",1)){
			t_p1=String(L"A-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"7",1)){
			t_p1=String(L"A#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"u",1)){
			t_p1=String(L"B-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"i",1)){
			t_p1=String(L"C-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"9",1)){
			t_p1=String(L"C#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"o",1)){
			t_p1=String(L"D-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"0",1)){
			t_p1=String(L"D#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"p",1)){
			t_p1=String(L"E-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"+",1)){
			t_p1=String(L"-dn",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"#",1)){
			t_p1=String(L"-up",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"-",1)){
			t_p1=String(L"End",3);
		}
	}
	if(t_oct.Slice(t_i,t_i+1)==String(L"2",1)){
		if(t_i<t_Track.Length()){
			t_p1=String(L"???",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"<",1)){
			t_p1=String(L"{|}",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L".",1)){
			t_p1=String(L"---",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"y",1)){
			t_p1=String(L"C-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"s",1)){
			t_p1=String(L"C#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"x",1)){
			t_p1=String(L"D-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"d",1)){
			t_p1=String(L"D#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"c",1)){
			t_p1=String(L"E-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"v",1)){
			t_p1=String(L"F-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"g",1)){
			t_p1=String(L"F#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"b",1)){
			t_p1=String(L"G-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"h",1)){
			t_p1=String(L"G#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"n",1)){
			t_p1=String(L"A-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"j",1)){
			t_p1=String(L"A#2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"m",1)){
			t_p1=String(L"B-2",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"q",1)){
			t_p1=String(L"C-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"2",1)){
			t_p1=String(L"C#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"w",1)){
			t_p1=String(L"D-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"3",1)){
			t_p1=String(L"D#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"e",1)){
			t_p1=String(L"E-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"r",1)){
			t_p1=String(L"F-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"5",1)){
			t_p1=String(L"F#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"t",1)){
			t_p1=String(L"G-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"6",1)){
			t_p1=String(L"G#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"z",1)){
			t_p1=String(L"A-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"7",1)){
			t_p1=String(L"A#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"u",1)){
			t_p1=String(L"B-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"i",1)){
			t_p1=String(L"C-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"9",1)){
			t_p1=String(L"C#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"o",1)){
			t_p1=String(L"D-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"0",1)){
			t_p1=String(L"D#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"p",1)){
			t_p1=String(L"E-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"+",1)){
			t_p1=String(L"-dn",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"#",1)){
			t_p1=String(L"-up",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"-",1)){
			t_p1=String(L"End",3);
		}
	}
	if(t_oct.Slice(t_i,t_i+1)==String(L"3",1)){
		if(t_i<t_Track.Length()){
			t_p1=String(L"???",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"<",1)){
			t_p1=String(L"{|}",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L".",1)){
			t_p1=String(L"---",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"y",1)){
			t_p1=String(L"C-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"s",1)){
			t_p1=String(L"C#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"x",1)){
			t_p1=String(L"D-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"d",1)){
			t_p1=String(L"D#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"c",1)){
			t_p1=String(L"E-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"v",1)){
			t_p1=String(L"F-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"g",1)){
			t_p1=String(L"F#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"b",1)){
			t_p1=String(L"G-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"h",1)){
			t_p1=String(L"G#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"n",1)){
			t_p1=String(L"A-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"j",1)){
			t_p1=String(L"A#3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"m",1)){
			t_p1=String(L"B-3",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"q",1)){
			t_p1=String(L"C-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"2",1)){
			t_p1=String(L"C#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"w",1)){
			t_p1=String(L"D-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"3",1)){
			t_p1=String(L"D#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"e",1)){
			t_p1=String(L"E-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"r",1)){
			t_p1=String(L"F-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"5",1)){
			t_p1=String(L"F#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"t",1)){
			t_p1=String(L"G-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"6",1)){
			t_p1=String(L"G#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"z",1)){
			t_p1=String(L"A-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"7",1)){
			t_p1=String(L"A#4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"u",1)){
			t_p1=String(L"B-4",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"i",1)){
			t_p1=String(L"C-5",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"9",1)){
			t_p1=String(L"C#5",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"o",1)){
			t_p1=String(L"D-5",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"0",1)){
			t_p1=String(L"D#5",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"p",1)){
			t_p1=String(L"E-5",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"+",1)){
			t_p1=String(L"-dn",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"#",1)){
			t_p1=String(L"-up",3);
		}
		if(t_Track.Slice(t_i,t_i+1)==String(L"-",1)){
			t_p1=String(L"End",3);
		}
	}
	return t_p1;
}
int bb_graphics_DrawImage(c_Image* t_image,Float t_x,Float t_y,int t_frame){
	c_Frame* t_f=t_image->m_frames[t_frame];
	bb_graphics_context->p_Validate();
	if((t_image->m_flags&65536)!=0){
		bb_graphics_renderDevice->DrawSurface(t_image->m_surface,t_x-t_image->m_tx,t_y-t_image->m_ty);
	}else{
		bb_graphics_renderDevice->DrawSurface2(t_image->m_surface,t_x-t_image->m_tx,t_y-t_image->m_ty,t_f->m_x,t_f->m_y,t_image->m_width,t_image->m_height);
	}
	return 0;
}
int bb_graphics_DrawImage2(c_Image* t_image,Float t_x,Float t_y,Float t_rotation,Float t_scaleX,Float t_scaleY,int t_frame){
	c_Frame* t_f=t_image->m_frames[t_frame];
	bb_graphics_PushMatrix();
	bb_graphics_Translate(t_x,t_y);
	bb_graphics_Rotate(t_rotation);
	bb_graphics_Scale(t_scaleX,t_scaleY);
	bb_graphics_Translate(-t_image->m_tx,-t_image->m_ty);
	bb_graphics_context->p_Validate();
	if((t_image->m_flags&65536)!=0){
		bb_graphics_renderDevice->DrawSurface(t_image->m_surface,FLOAT(0.0),FLOAT(0.0));
	}else{
		bb_graphics_renderDevice->DrawSurface2(t_image->m_surface,FLOAT(0.0),FLOAT(0.0),t_f->m_x,t_f->m_y,t_image->m_width,t_image->m_height);
	}
	bb_graphics_PopMatrix();
	return 0;
}
int bbInit(){
	GC_CTOR
	bb_app__app=0;
	bb_app__delegate=0;
	bb_app__game=BBGame::Game();
	bb_graphics_device=0;
	bb_graphics_context=(new c_GraphicsContext)->m_new();
	c_Image::m_DefaultFlags=0;
	bb_audio_device=0;
	bb_input_device=0;
	bb_app__devWidth=0;
	bb_app__devHeight=0;
	bb_app__displayModes=Array<c_DisplayMode* >();
	bb_app__desktopMode=0;
	bb_graphics_renderDevice=0;
	bb_app__updateRate=0;
	c_SoundEngine::m_FONT=0;
	c_SoundEngine::m_Button1=0;
	c_SoundEngine::m_Square=0;
	c_SoundEngine::m_Ramp=0;
	c_SoundEngine::m_Ramp2=0;
	c_SoundEngine::m_Saw=0;
	c_SoundEngine::m_Noise=0;
	c_SoundEngine::m_Bass=0;
	c_SoundEngine::m_HNoise=0;
	c_SoundEngine::m_Zero=0;
	c_SoundEngine::m_Track1=String();
	c_SoundEngine::m_Track2=String();
	c_SoundEngine::m_Track3=String();
	c_SoundEngine::m_Track4=String();
	c_SoundEngine::m_VolumeTrack1=String();
	c_SoundEngine::m_VolumeTrack2=String();
	c_SoundEngine::m_VolumeTrack3=String();
	c_SoundEngine::m_VolumeTrack4=String();
	c_SoundEngine::m_InstTrack1=String();
	c_SoundEngine::m_InstTrack2=String();
	c_SoundEngine::m_InstTrack3=String();
	c_SoundEngine::m_InstTrack4=String();
	c_SoundEngine::m_OctaveTrack1=String();
	c_SoundEngine::m_OctaveTrack2=String();
	c_SoundEngine::m_OctaveTrack3=String();
	c_SoundEngine::m_OctaveTrack4=String();
	c_SoundEngine::m_UndoTrack1=Array<String >(32);
	c_SoundEngine::m_UndoTrack2=Array<String >(32);
	c_SoundEngine::m_UndoTrack3=Array<String >(32);
	c_SoundEngine::m_UndoTrack4=Array<String >(32);
	c_SoundEngine::m_UndoVolumeTrack1=Array<String >(32);
	c_SoundEngine::m_UndoVolumeTrack2=Array<String >(32);
	c_SoundEngine::m_UndoVolumeTrack3=Array<String >(32);
	c_SoundEngine::m_UndoVolumeTrack4=Array<String >(32);
	c_SoundEngine::m_UndoInstTrack1=Array<String >(32);
	c_SoundEngine::m_UndoInstTrack2=Array<String >(32);
	c_SoundEngine::m_UndoInstTrack3=Array<String >(32);
	c_SoundEngine::m_UndoInstTrack4=Array<String >(32);
	c_SoundEngine::m_UndoOctaveTrack1=Array<String >(32);
	c_SoundEngine::m_UndoOctaveTrack2=Array<String >(32);
	c_SoundEngine::m_UndoOctaveTrack3=Array<String >(32);
	c_SoundEngine::m_UndoOctaveTrack4=Array<String >(32);
	c_SoundEngine::m_EDIT_CHANNEL=0;
	c_SoundEngine::m_Cursorpos=0;
	c_SoundEngine::m_Patternorder=String();
	c_SoundEngine::m_Patterns=Array<int >(255);
	c_SoundEngine::m_StatusInfo=String();
	c_SoundEngine::m_FrameTime=0;
	c_SoundEngine::m_CHOn1=FLOAT(1.0);
	c_SoundEngine::m_CHOn2=FLOAT(1.0);
	c_SoundEngine::m_CHOn3=FLOAT(1.0);
	c_SoundEngine::m_CHOn4=FLOAT(1.0);
	c_SoundEngine::m_flw=0;
	c_SoundEngine::m_Follow=String(L"On",2);
	c_SoundEngine::m_USA=0;
	c_SoundEngine::m_DEon=String(L"DE",2);
	c_SoundEngine::m_i=0;
	c_SoundEngine::m_STATUS=2;
	c_SoundEngine::m_Scroller=FLOAT(.0);
	c_SoundEngine::m_UndoCount=0;
	c_SoundEngine::m_pcount=0;
	c_SoundEngine::m_FilenameInputOn=0;
	c_SoundEngine::m_Filename=String();
	c_SoundEngine::m_Descriptions=Array<String >(32);
	c_SoundEngine::m_WavInit=1;
	c_SoundEngine::m_InstDescriptionOn=0;
	c_SoundEngine::m_Songlength=32;
	c_SoundEngine::m_spd=4;
	c_SoundEngine::m_InsArrayData=Array<int >(255);
	c_SoundEngine::m_CurrentWav=0;
	c_SoundEngine::m_CurrentWav2=0;
	c_SoundEngine::m_PWM=FLOAT(.0);
	c_SoundEngine::m_ppos=0;
	c_SoundEngine::m_Press1=0;
	c_SoundEngine::m_Press2=0;
	c_SoundEngine::m_CopyTrack=String();
	c_SoundEngine::m_CopyVolumeTrack=String();
	c_SoundEngine::m_CopyInstTrack=String();
	c_SoundEngine::m_CopyOctaveTrack=String();
	c_SoundEngine::m_Lastgch=String();
	c_SoundEngine::m_oct=2;
	c_SoundEngine::m_Arpcounter=0;
	c_SoundEngine::m_PWCount=0;
	c_SoundEngine::m_Decay=FLOAT(.0);
	c_SoundEngine::m_Dec2Pitch=FLOAT(.0);
	c_SoundEngine::m_ArpSpd=0;
	c_SoundEngine::m_fxval=FLOAT(.0);
	c_SoundEngine::m_PWDepth=8;
	c_SoundEngine::m_PWVal=0;
	c_SoundEngine::m_p1=FLOAT(.0);
	c_SoundEngine::m_last_p1=FLOAT(.0);
	c_SoundEngine::m_fine_p1=FLOAT(.0);
	c_SoundEngine::m_fxval1=FLOAT(.0);
	c_SoundEngine::m_Vib1=FLOAT(.0);
	c_SoundEngine::m_Arpcounter1=0;
	c_SoundEngine::m_PWCount1=0;
	c_SoundEngine::m_Decay1=FLOAT(.0);
	c_SoundEngine::m_p2=FLOAT(.0);
	c_SoundEngine::m_last_p2=FLOAT(.0);
	c_SoundEngine::m_fine_p2=FLOAT(.0);
	c_SoundEngine::m_fxval2=FLOAT(.0);
	c_SoundEngine::m_Vib2=FLOAT(.0);
	c_SoundEngine::m_Arpcounter2=0;
	c_SoundEngine::m_PWCount2=0;
	c_SoundEngine::m_Decay2=FLOAT(.0);
	c_SoundEngine::m_p3=FLOAT(.0);
	c_SoundEngine::m_last_p3=FLOAT(.0);
	c_SoundEngine::m_fine_p3=FLOAT(.0);
	c_SoundEngine::m_fxval3=FLOAT(.0);
	c_SoundEngine::m_Vib3=FLOAT(.0);
	c_SoundEngine::m_Arpcounter3=0;
	c_SoundEngine::m_PWCount3=0;
	c_SoundEngine::m_Decay3=FLOAT(.0);
	c_SoundEngine::m_p4=FLOAT(.0);
	c_SoundEngine::m_last_p4=FLOAT(.0);
	c_SoundEngine::m_fine_p4=FLOAT(.0);
	c_SoundEngine::m_fxval4=FLOAT(.0);
	c_SoundEngine::m_Vib4=FLOAT(.0);
	c_SoundEngine::m_Arpcounter4=0;
	c_SoundEngine::m_PWCount4=0;
	c_SoundEngine::m_Decay4=FLOAT(.0);
	c_SoundEngine::m_InstNo1=0;
	c_SoundEngine::m_InstNo2=0;
	c_SoundEngine::m_InstNo3=0;
	c_SoundEngine::m_InstNo4=0;
	c_SoundEngine::m_volval1=FLOAT(.0);
	c_SoundEngine::m_volval2=FLOAT(.0);
	c_SoundEngine::m_volval3=FLOAT(.0);
	c_SoundEngine::m_volval4=FLOAT(.0);
	c_SoundEngine::m_oct1=0;
	c_SoundEngine::m_oct2=0;
	c_SoundEngine::m_oct3=0;
	c_SoundEngine::m_oct4=0;
	c_SoundEngine::m_Chan1wav=0;
	c_SoundEngine::m_Chan5wav=0;
	c_SoundEngine::m_Chan2wav=0;
	c_SoundEngine::m_Chan6wav=0;
	c_SoundEngine::m_Chan3wav=0;
	c_SoundEngine::m_Chan7wav=0;
	c_SoundEngine::m_Chan4wav=0;
	c_SoundEngine::m_Chan8wav=0;
	c_SoundEngine::m_PWM1=FLOAT(.0);
	c_SoundEngine::m_PWM2=FLOAT(.0);
	c_SoundEngine::m_PWM3=FLOAT(.0);
	c_SoundEngine::m_PWM4=FLOAT(.0);
	c_SoundEngine::m_LastInstNo1=0;
	c_SoundEngine::m_LastInstNo2=0;
	c_SoundEngine::m_LastInstNo3=0;
	c_SoundEngine::m_LastInstNo4=0;
	c_SoundEngine::m_LastOct1=0;
	c_SoundEngine::m_LastOct2=0;
	c_SoundEngine::m_LastOct3=0;
	c_SoundEngine::m_LastOct4=0;
	c_SoundEngine::m_Dec2Pitch1=FLOAT(.0);
	c_SoundEngine::m_Dec2Pitch2=FLOAT(.0);
	c_SoundEngine::m_Dec2Pitch3=FLOAT(.0);
	c_SoundEngine::m_Dec2Pitch4=FLOAT(.0);
	c_SoundEngine::m_ArpSpd1=0;
	c_SoundEngine::m_ArpSpd2=0;
	c_SoundEngine::m_ArpSpd3=0;
	c_SoundEngine::m_ArpSpd4=0;
	c_SoundEngine::m_PWDepth1=8;
	c_SoundEngine::m_PWVal1=0;
	c_SoundEngine::m_PWDepth2=8;
	c_SoundEngine::m_PWVal2=0;
	c_SoundEngine::m_PWDepth3=8;
	c_SoundEngine::m_PWVal3=0;
	c_SoundEngine::m_PWDepth4=8;
	c_SoundEngine::m_PWVal4=0;
	c_SoundEngine::m_CHOff1=String();
	c_SoundEngine::m_CHOff2=String();
	c_SoundEngine::m_CHOff3=String();
	c_SoundEngine::m_CHOff4=String();
	c_SoundEngine::m_meter_H1=0;
	c_SoundEngine::m_meter_H2=0;
	c_SoundEngine::m_meter_H3=0;
	c_SoundEngine::m_meter_H4=0;
	return 0;
}
void gc_mark(){
	gc_mark_q(bb_app__app);
	gc_mark_q(bb_app__delegate);
	gc_mark_q(bb_graphics_device);
	gc_mark_q(bb_graphics_context);
	gc_mark_q(bb_audio_device);
	gc_mark_q(bb_input_device);
	gc_mark_q(bb_app__displayModes);
	gc_mark_q(bb_app__desktopMode);
	gc_mark_q(bb_graphics_renderDevice);
	gc_mark_q(c_SoundEngine::m_FONT);
	gc_mark_q(c_SoundEngine::m_Button1);
	gc_mark_q(c_SoundEngine::m_Square);
	gc_mark_q(c_SoundEngine::m_Ramp);
	gc_mark_q(c_SoundEngine::m_Ramp2);
	gc_mark_q(c_SoundEngine::m_Saw);
	gc_mark_q(c_SoundEngine::m_Noise);
	gc_mark_q(c_SoundEngine::m_Bass);
	gc_mark_q(c_SoundEngine::m_HNoise);
	gc_mark_q(c_SoundEngine::m_Zero);
	gc_mark_q(c_SoundEngine::m_UndoTrack1);
	gc_mark_q(c_SoundEngine::m_UndoTrack2);
	gc_mark_q(c_SoundEngine::m_UndoTrack3);
	gc_mark_q(c_SoundEngine::m_UndoTrack4);
	gc_mark_q(c_SoundEngine::m_UndoVolumeTrack1);
	gc_mark_q(c_SoundEngine::m_UndoVolumeTrack2);
	gc_mark_q(c_SoundEngine::m_UndoVolumeTrack3);
	gc_mark_q(c_SoundEngine::m_UndoVolumeTrack4);
	gc_mark_q(c_SoundEngine::m_UndoInstTrack1);
	gc_mark_q(c_SoundEngine::m_UndoInstTrack2);
	gc_mark_q(c_SoundEngine::m_UndoInstTrack3);
	gc_mark_q(c_SoundEngine::m_UndoInstTrack4);
	gc_mark_q(c_SoundEngine::m_UndoOctaveTrack1);
	gc_mark_q(c_SoundEngine::m_UndoOctaveTrack2);
	gc_mark_q(c_SoundEngine::m_UndoOctaveTrack3);
	gc_mark_q(c_SoundEngine::m_UndoOctaveTrack4);
	gc_mark_q(c_SoundEngine::m_Patterns);
	gc_mark_q(c_SoundEngine::m_Descriptions);
	gc_mark_q(c_SoundEngine::m_InsArrayData);
	gc_mark_q(c_SoundEngine::m_CurrentWav);
	gc_mark_q(c_SoundEngine::m_CurrentWav2);
	gc_mark_q(c_SoundEngine::m_Chan1wav);
	gc_mark_q(c_SoundEngine::m_Chan5wav);
	gc_mark_q(c_SoundEngine::m_Chan2wav);
	gc_mark_q(c_SoundEngine::m_Chan6wav);
	gc_mark_q(c_SoundEngine::m_Chan3wav);
	gc_mark_q(c_SoundEngine::m_Chan7wav);
	gc_mark_q(c_SoundEngine::m_Chan4wav);
	gc_mark_q(c_SoundEngine::m_Chan8wav);
}
//${TRANSCODE_END}

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

	BBCerberusGame::Main( argc,argv );
}
