//-----------------------------------------------------------------------------
// AScript sdl module
//-----------------------------------------------------------------------------
#include "Module_sdl.h"

AScript_BeginModule(sdl)

// symbols in SDL_Event
AScript_DeclarePrivSymbol(type);
AScript_DeclarePrivSymbol(gain);
AScript_DeclarePrivSymbol(state);
AScript_DeclarePrivSymbol(scancode);
AScript_DeclarePrivSymbol(sym);
AScript_DeclarePrivSymbol(mod);
AScript_DeclarePrivSymbol(unicode);
AScript_DeclarePrivSymbol(x);
AScript_DeclarePrivSymbol(y);
AScript_DeclarePrivSymbol(xrel);
AScript_DeclarePrivSymbol(yrel);
AScript_DeclarePrivSymbol(axis);
AScript_DeclarePrivSymbol(value);
AScript_DeclarePrivSymbol(button);
AScript_DeclarePrivSymbol(which);
AScript_DeclarePrivSymbol(hat);
AScript_DeclarePrivSymbol(ball);
AScript_DeclarePrivSymbol(w);
AScript_DeclarePrivSymbol(h);
// symbols in SDL_Color
AScript_DeclarePrivSymbol(r)
AScript_DeclarePrivSymbol(g)
AScript_DeclarePrivSymbol(b)
// symbols in SDL_PixelFormat
AScript_DeclarePrivSymbol(palette);
AScript_DeclarePrivSymbol(BitsPerPixel);
AScript_DeclarePrivSymbol(BytesPerPixel);
AScript_DeclarePrivSymbol(Rloss);
AScript_DeclarePrivSymbol(Gloss);
AScript_DeclarePrivSymbol(Bloss);
AScript_DeclarePrivSymbol(Aloss);
AScript_DeclarePrivSymbol(Rshift);
AScript_DeclarePrivSymbol(Gshift);
AScript_DeclarePrivSymbol(Bshift);
AScript_DeclarePrivSymbol(Ashift);
AScript_DeclarePrivSymbol(Rmask);
AScript_DeclarePrivSymbol(Gmask);
AScript_DeclarePrivSymbol(Bmask);
AScript_DeclarePrivSymbol(Amask);
AScript_DeclarePrivSymbol(colorkey);
AScript_DeclarePrivSymbol(alpha);
// symbols in SDL_Surface
AScript_DeclarePrivSymbol(flags)
AScript_DeclarePrivSymbol(format)
AScript_DeclarePrivSymbol(pitch)
AScript_DeclarePrivSymbol(pixels)
AScript_DeclarePrivSymbol(clip_rect)
AScript_DeclarePrivSymbol(refcount)
// symbols in SDL_VideoInfo
AScript_DeclarePrivSymbol(hw_available);
AScript_DeclarePrivSymbol(wm_available);
AScript_DeclarePrivSymbol(blit_hw);
AScript_DeclarePrivSymbol(blit_hw_CC);
AScript_DeclarePrivSymbol(blit_hw_A);
AScript_DeclarePrivSymbol(blit_sw);
AScript_DeclarePrivSymbol(blit_sw_CC);
AScript_DeclarePrivSymbol(blit_sw_A);
AScript_DeclarePrivSymbol(blit_fill);
AScript_DeclarePrivSymbol(video_mem);
AScript_DeclarePrivSymbol(vfmt);
// symbols in SDL_CDtrack
AScript_DeclarePrivSymbol(id)
AScript_DeclarePrivSymbol(length)
AScript_DeclarePrivSymbol(offset)
// symbols in SDL_CD
AScript_DeclarePrivSymbol(status)
AScript_DeclarePrivSymbol(numtracks)
AScript_DeclarePrivSymbol(cur_track)
AScript_DeclarePrivSymbol(cur_frame)
// symbols for other purposes
AScript_DeclarePrivSymbol(thread_);

//-----------------------------------------------------------------------------
// Object_Cursor implementation
//-----------------------------------------------------------------------------
Object_Cursor::~Object_Cursor()
{
	//::SDL_FreeCursor(_pCursor);
}

Object *Object_Cursor::Clone() const
{
	return NULL;
}

void Object_Cursor::FreeCursor()
{
	if (_pCursor != NULL) ::SDL_FreeCursor(_pCursor);
	_pCursor = NULL;
}

String Object_Cursor::ToString(Signal sig, bool exprFlag)
{
	return String("<Cursor>");
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Cursor
//-----------------------------------------------------------------------------
// sdl.Cursor#FreeCursor():void
AScript_DeclareMethod(Cursor, FreeCursor)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementMethod(Cursor, FreeCursor)
{
	Object_Cursor *pObj = Object_Cursor::GetSelfObj(args);
	pObj->FreeCursor();
	return Value::Null;
}

// implementation of class Cursor
AScript_ImplementPrivClass(Cursor)
{
	AScript_AssignMethod(Cursor, FreeCursor);
}

//-----------------------------------------------------------------------------
// Object_Timer implementation
//-----------------------------------------------------------------------------
Object_Timer::~Object_Timer()
{
	::SDL_RemoveTimer(_timerID);
	Object::Delete(_pObjFunc);
}

Object *Object_Timer::Clone() const
{
	return NULL;
}

String Object_Timer::ToString(Signal sig, bool exprFlag)
{
	return String("<sdl.timer>");
}

bool Object_Timer::AddTimer(Uint32 interval)
{
	_contFlag = true;
	_timerID = ::SDL_AddTimer(interval, CallbackStub, this);
	return _timerID != NULL;
}

bool Object_Timer::RemoveTimer()
{
	_contFlag = false;
	SDL_bool rtn = ::SDL_RemoveTimer(_timerID);
	_timerID = NULL;
	return rtn? true : false;
}

bool Object_Timer::DoHandle()
{
	if (!_contFlag) return false;
	Function *pFunc = _pObjFunc->GetFunction();
	Environment &env = pFunc->GetEnvScope();
	ValueList valListArg;
	valListArg.reserve(1);
	valListArg.push_back(Value(this, false));
	Value result = _pObjFunc->Eval(env, _sig, valListArg);
	if (_sig.IsSignalled()) {
		SDL_QuitEvent event;
		event.type = SDL_QUIT;
		::SDL_PushEvent(reinterpret_cast<SDL_Event *>(&event));
		return false;
	}
	_contFlag = result.GetBoolean();
	return _contFlag;
}

Uint32 Object_Timer::CallbackStub(Uint32 interval, void *param)
{
	Object_Timer *pSelf = reinterpret_cast<Object_Timer *>(param);
	if (pSelf->IsThread()) {
		return pSelf->DoHandle()? interval : 0;
	} else {
		SDL_UserEvent event;
		event.type = SDL_USEREVENT_Timer;
		event.code = 0;
		event.data1 = Object::Reference(pSelf); // decremented in PollEvent or WaitEvent
		event.data2 = NULL;
		::SDL_PushEvent(reinterpret_cast<SDL_Event *>(&event));
		return interval;
	}
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Timer
//-----------------------------------------------------------------------------
// sdl.Timer#RemoveTimer()
AScript_DeclareMethod(Timer, RemoveTimer)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Timer, RemoveTimer)
{
	Object_Timer *pObj = Object_Timer::GetSelfObj(args);
	return Value(pObj->RemoveTimer());
}

// implementation of class Timer
AScript_ImplementPrivClass(Timer)
{
	AScript_AssignMethod(Timer, RemoveTimer);
}

//-----------------------------------------------------------------------------
// Object_Event implementation
//-----------------------------------------------------------------------------
Object_Event::~Object_Event()
{
}

Object *Object_Event::Clone() const
{
	return NULL;
}

String Object_Event::ToString(Signal sig, bool exprFlag)
{
	String str;
	str += "<Event:";
	str += GetEventTypeName(_event.type);
	char buff[80];
	if (_event.type == SDL_ACTIVEEVENT) {
		const SDL_ActiveEvent &event = _event.active;
		::sprintf(buff, "(gain=%d, state=%d)", event.gain, event.state);
		str += buff;
	} else if (_event.type == SDL_KEYDOWN || _event.type == SDL_KEYUP) {
		const SDL_KeyboardEvent &event = _event.key;
		::sprintf(buff, "(state=%d, scancode=%d, sym=%d, mod=0x%04x, unicode=%d)",
				event.state, event.keysym.scancode, event.keysym.sym,
				event.keysym.mod, event.keysym.unicode);
		str += buff;
	} else if (_event.type == SDL_MOUSEMOTION) {
		const SDL_MouseMotionEvent &event = _event.motion;
		::sprintf(buff, "(state=%d, x=%d, y=%d, xrel=%d, yrel=%d)",
			event.state, event.x, event.y, event.xrel, event.yrel);
		str += buff;
	} else if (_event.type == SDL_MOUSEBUTTONDOWN || _event.type == SDL_MOUSEBUTTONUP) {
		const SDL_MouseButtonEvent &event = _event.button;
		::sprintf(buff, "(button=%d, state=%d, x=%d, y=%d)",
			event.button, event.state, event.x, event.y);
		str += buff;
	} else if (_event.type == SDL_JOYAXISMOTION) {
		const SDL_JoyAxisEvent &event = _event.jaxis;
		::sprintf(buff, "(which=%d, axis=%d, value=%d)",
			event.which, event.axis, event.value);
		str += buff;
	} else if (_event.type == SDL_JOYBUTTONDOWN || _event.type == SDL_JOYBUTTONUP) {
		const SDL_JoyButtonEvent &event = _event.jbutton;
		::sprintf(buff, "(which=%d, button=%d, state=%d)",
			event.which, event.button, event.state);
		str += buff;
	} else if (_event.type == SDL_JOYHATMOTION) {
		const SDL_JoyHatEvent &event = _event.jhat;
		::sprintf(buff, "(which=%d, hat=%d, value=%d)",
			event.which, event.hat, event.value);
		str += buff;
	} else if (_event.type == SDL_JOYBALLMOTION) {
		const SDL_JoyBallEvent &event = _event.jball;
		::sprintf(buff, "(which=%d, ball=%d, xrel=%d, yrel=%d)",
			event.which, event.ball, event.xrel, event.yrel);
		str += buff;
	} else if (_event.type == SDL_VIDEORESIZE) {
		const SDL_ResizeEvent &event = _event.resize;
		::sprintf(buff, "(w=%d, h=%d)", event.w, event.h);
		str += buff;
	} else if (_event.type == SDL_VIDEOEXPOSE) {
		//const SDL_ExposeEvent &event = _event.expose;
		// nothing to do
	} else if (_event.type == SDL_QUIT) {
		//const SDL_QuitEvent &event = _event.quit;
		// nothing to do
	} else if (_event.type == SDL_USEREVENT) {
		//const SDL_UserEvent &event = _event.user;
		// nothing to do
	} else if (_event.type == SDL_SYSWMEVENT) {
		//const SDL_SysWMEvent &event = _event.syswm;
		// nothing to do
	}
	str += ">";
	return str;
}

Value Object_Event::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(type))) {
		return Value(_event.type);
	}
	if (_event.type == SDL_ACTIVEEVENT) {
		const SDL_ActiveEvent &event = _event.active;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(gain))) {
			return Value(event.gain);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(state))) {
			return Value(event.state);
		}
	} else if (_event.type == SDL_KEYDOWN || _event.type == SDL_KEYUP) {
		const SDL_KeyboardEvent &event = _event.key;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(state))) {
			return Value(event.state);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(scancode))) {
			return Value(event.keysym.scancode);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(sym))) {
			return Value(static_cast<int>(event.keysym.sym));
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(mod))) {
			return Value(static_cast<int>(event.keysym.mod));
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(unicode))) {
			return Value(event.keysym.unicode);
		}
	} else if (_event.type == SDL_MOUSEMOTION) {
		const SDL_MouseMotionEvent &event = _event.motion;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(state))) {
			return Value(event.state);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(x))) {
			return Value(event.x);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(y))) {
			return Value(event.y);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(xrel))) {
			return Value(event.xrel);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(yrel))) {
			return Value(event.yrel);
		}
	} else if (_event.type == SDL_MOUSEBUTTONDOWN || _event.type == SDL_MOUSEBUTTONUP) {
		const SDL_MouseButtonEvent &event = _event.button;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(button))) {
			return Value(event.button);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(state))) {
			return Value(event.state);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(x))) {
			return Value(event.x);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(y))) {
			return Value(event.y);
		}
	} else if (_event.type == SDL_JOYAXISMOTION) {
		const SDL_JoyAxisEvent &event = _event.jaxis;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(which))) {
			return Value(event.which);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(axis))) {
			return Value(event.axis);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(value))) {
			return Value(event.value);
		}
	} else if (_event.type == SDL_JOYBUTTONDOWN || _event.type == SDL_JOYBUTTONUP) {
		const SDL_JoyButtonEvent &event = _event.jbutton;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(which))) {
			return Value(event.which);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(button))) {
			return Value(event.button);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(state))) {
			return Value(event.state);
		}
	} else if (_event.type == SDL_JOYHATMOTION) {
		const SDL_JoyHatEvent &event = _event.jhat;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(which))) {
			return Value(event.which);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(hat))) {
			return Value(event.hat);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(value))) {
			return Value(event.value);
		}
	} else if (_event.type == SDL_JOYBALLMOTION) {
		const SDL_JoyBallEvent &event = _event.jball;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(which))) {
			return Value(event.which);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(ball))) {
			return Value(event.ball);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(xrel))) {
			return Value(event.xrel);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(yrel))) {
			return Value(event.yrel);
		}
	} else if (_event.type == SDL_VIDEORESIZE) {
		const SDL_ResizeEvent &event = _event.resize;
		if (pSymbol->IsIdentical(AScript_PrivSymbol(w))) {
			return Value(event.w);
		} else if (pSymbol->IsIdentical(AScript_PrivSymbol(h))) {
			return Value(event.h);
		}
	} else if (_event.type == SDL_VIDEOEXPOSE) {
		//const SDL_ExposeEvent &event = _event.expose;
		// nothing to do
	} else if (_event.type == SDL_QUIT) {
		//const SDL_QuitEvent &event = _event.quit;
		// nothing to do
	} else if (_event.type == SDL_USEREVENT) {
		//const SDL_UserEvent &event = _event.user;
		// nothing to do
	} else if (_event.type == SDL_SYSWMEVENT) {
		//const SDL_SysWMEvent &event = _event.syswm;
		// nothing to do
	}
	evaluatedFlag = false;
	return Value::Null;
}

// implementation of class Event
AScript_ImplementPrivClass(Event)
{
	//AScript_AssignMethod(Match, group);
}

//-----------------------------------------------------------------------------
// Object_Rect implementation
//-----------------------------------------------------------------------------
Object_Rect::~Object_Rect()
{
}

Object *Object_Rect::Clone() const
{
	return NULL;
}

String Object_Rect::ToString(Signal sig, bool exprFlag)
{
	char buff[80];
	::sprintf(buff, "<Rect:x=%d,y=%d,w=%d,h=%d>", _rect.x, _rect.y, _rect.w, _rect.h);
	return String(buff);
}

Value Object_Rect::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(x))) {
		return Value(_rect.x);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(y))) {
		return Value(_rect.y);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(w))) {
		return Value(_rect.w);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(h))) {
		return Value(_rect.h);
	}
	evaluatedFlag = false;
	return Value::Null;
}

// implementation of class Rect
AScript_ImplementPrivClass(Rect)
{
}

//-----------------------------------------------------------------------------
// Object_Color implementation
//-----------------------------------------------------------------------------
Object_Color::~Object_Color()
{
}

Object *Object_Color::Clone() const
{
	return NULL;
}

String Object_Color::ToString(Signal sig, bool exprFlag)
{
	char buff[80];
	::sprintf(buff, "<Color:r=%d,g=%d,b=%d>", _color.r, _color.g, _color.b);
	return String(buff);
}

Value Object_Color::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(r))) {
		return Value(_color.r);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(g))) {
		return Value(_color.g);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(b))) {
		return Value(_color.b);
	}
	evaluatedFlag = false;
	return Value::Null;
}

// implementation of class Color
AScript_ImplementPrivClassWithCast(Color)
{
}

AScript_ImplementCastFrom(Color)
{
	if (value.GetType() == VTYPE_Color) {
		AScript::Object_Color *pObjColor = value.GetColorObj();
		SDL_Color color;
		color.r = pObjColor->GetRed();
		color.g = pObjColor->GetGreen();
		color.b = pObjColor->GetBlue();
		color.unused = 0;
		value = Value(new Object_Color(color));
		return true;
	}
	return false;
}

AScript_ImplementCastTo(Color)
{
	if (valType == VTYPE_Color) {
		SDL_Color &color = dynamic_cast<Object_Color *>(value.GetObject())->GetColor();
		value = Value(new AScript::Object_Color(env, color.r, color.g, color.b, 255));
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
// Object_Palette implementation
//-----------------------------------------------------------------------------
Object_Palette::~Object_Palette()
{
}

Object *Object_Palette::Clone() const
{
	return NULL;
}

String Object_Palette::ToString(Signal sig, bool exprFlag)
{
	return String("<Palette>");
}

Value Object_Palette::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = false;
	return Value::Null;
}

// implementation of class Palette
AScript_ImplementPrivClass(Palette)
{
}

//-----------------------------------------------------------------------------
// Object_PixelFormat implementation
//-----------------------------------------------------------------------------
Object_PixelFormat::Object_PixelFormat(const SDL_PixelFormat &pixelFormat) :
			Object(AScript_PrivClass(PixelFormat)), _pixelFormat(pixelFormat)
{
	if (pixelFormat.palette != NULL) {
		_pixelFormat.palette = new SDL_Palette;
		int ncolors = pixelFormat.palette->ncolors;
		_pixelFormat.palette->ncolors = ncolors;
		_pixelFormat.palette->colors = new SDL_Color[ncolors];
		for (int i = 0; i < ncolors; i++) {
			_pixelFormat.palette->colors[i] = pixelFormat.palette->colors[i];
		}
	}
}

Object_PixelFormat::~Object_PixelFormat()
{
	if (_pixelFormat.palette != NULL) {
		delete[] _pixelFormat.palette->colors;
		delete _pixelFormat.palette;
	}
}

Object *Object_PixelFormat::Clone() const
{
	return NULL;
}

String Object_PixelFormat::ToString(Signal sig, bool exprFlag)
{
	return String("<PixelFormat>");
}

Value Object_PixelFormat::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(palette))) {
		return Object_Palette::CreateValue(_pixelFormat.palette);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(BitsPerPixel))) {
		return Value(_pixelFormat.BitsPerPixel);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(BytesPerPixel))) {
		return Value(_pixelFormat.BytesPerPixel);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Rloss))) {
		return Value(_pixelFormat.Rloss);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Gloss))) {
		return Value(_pixelFormat.Gloss);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Bloss))) {
		return Value(_pixelFormat.Bloss);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Aloss))) {
		return Value(_pixelFormat.Aloss);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Rshift))) {
		return Value(_pixelFormat.Rshift);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Gshift))) {
		return Value(_pixelFormat.Gshift);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Bshift))) {
		return Value(_pixelFormat.Bshift);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Ashift))) {
		return Value(_pixelFormat.Ashift);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Rmask))) {
		return Value(_pixelFormat.Rmask);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Gmask))) {
		return Value(_pixelFormat.Gmask);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Bmask))) {
		return Value(_pixelFormat.Bmask);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(Amask))) {
		return Value(_pixelFormat.Amask);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(colorkey))) {
		return Value(_pixelFormat.colorkey);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(alpha))) {
		return Value(_pixelFormat.alpha);
	}
	evaluatedFlag = false;
	return Value::Null;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_PixelFormat
//-----------------------------------------------------------------------------
// sdl.PixelFormat#MapRGB(r:number, g:number, b:number)
AScript_DeclareMethod(PixelFormat, MapRGB)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "r", VTYPE_Number);
	DeclareArg(env, "g", VTYPE_Number);
	DeclareArg(env, "b", VTYPE_Number);
}

AScript_ImplementMethod(PixelFormat, MapRGB)
{
	SDL_PixelFormat *fmt = Object_PixelFormat::GetSelfObj(args)->GetPixelFormat();
	return Value(::SDL_MapRGB(fmt,
				args.GetUChar(0), args.GetUChar(1), args.GetUChar(2)));
}

// sdl.PixelFormat#MapRGBA(r:number, g:number, b:number, a:number)
AScript_DeclareMethod(PixelFormat, MapRGBA)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "r", VTYPE_Number);
	DeclareArg(env, "g", VTYPE_Number);
	DeclareArg(env, "b", VTYPE_Number);
	DeclareArg(env, "a", VTYPE_Number);
}

AScript_ImplementMethod(PixelFormat, MapRGBA)
{
	SDL_PixelFormat *fmt = Object_PixelFormat::GetSelfObj(args)->GetPixelFormat();
	return Value(::SDL_MapRGBA(fmt,
				args.GetUChar(0), args.GetUChar(1),
				args.GetUChar(2), args.GetUChar(3)));
}

// sdl.PixelFormat#GetRGB(pixel:number)
AScript_DeclareMethod(PixelFormat, GetRGB)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "pixel", VTYPE_Number);
}

AScript_ImplementMethod(PixelFormat, GetRGB)
{
	SDL_PixelFormat *fmt = Object_PixelFormat::GetSelfObj(args)->GetPixelFormat();
	Uint8 r, g, b;
	::SDL_GetRGB(args.GetULong(0), fmt, &r, &g, &b);
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(r));
	valList.push_back(Value(g));
	valList.push_back(Value(b));
	return result;
}

// sdl.PixelFormat#GetRGBA(pixel:number):void
AScript_DeclareMethod(PixelFormat, GetRGBA)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "pixel", VTYPE_Number);
}

AScript_ImplementMethod(PixelFormat, GetRGBA)
{
	SDL_PixelFormat *fmt = Object_PixelFormat::GetSelfObj(args)->GetPixelFormat();
	Uint8 r, g, b, a;
	::SDL_GetRGBA(args.GetULong(0), fmt, &r, &g, &b, &a);
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(r));
	valList.push_back(Value(g));
	valList.push_back(Value(b));
	valList.push_back(Value(a));
	return result;
}

// implementation of class PixelFormat
AScript_ImplementPrivClass(PixelFormat)
{
	AScript_AssignMethod(PixelFormat, MapRGB);
	AScript_AssignMethod(PixelFormat, MapRGBA);
	AScript_AssignMethod(PixelFormat, GetRGB);
	AScript_AssignMethod(PixelFormat, GetRGBA);
}

//-----------------------------------------------------------------------------
// Object_PixelFormat implementation
//-----------------------------------------------------------------------------
Object_Surface::~Object_Surface()
{
	::SDL_FreeSurface(_pSurface);
	Object::Delete(_pObjRef);
}

Object *Object_Surface::Clone() const
{
	return NULL;
}

Value Object_Surface::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(flags))) {
		return Value(_pSurface->flags);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(format))) {
		return Object_PixelFormat::CreateValue(*_pSurface->format);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(w))) {
		return Value(_pSurface->w);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(h))) {
		return Value(_pSurface->h);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(pitch))) {
		return Value(_pSurface->pitch);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(pixels))) {
		return Value::Null;
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(clip_rect))) {
		return Object_Rect::CreateValue(_pSurface->clip_rect);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(refcount))) {
		return Value(_pSurface->refcount);
	}
	evaluatedFlag = false;
	return Value::Null;
}

String Object_Surface::ToString(Signal sig, bool exprFlag)
{
	return String("<Surface>");
}

Object_Surface *Object_Surface::CreateSurfaceFromImage(Signal sig, Object_Image *pObjImg)
{
	void *pixels = pObjImg->GetBuffer();
	int width = static_cast<int>(pObjImg->GetWidth());
	int height = static_cast<int>(pObjImg->GetHeight());
	int depth = static_cast<int>(pObjImg->GetBitsPerPixel());
	int pitch = static_cast<int>(pObjImg->GetBytesPerLine());
	Uint32 Rmask, Gmask, Bmask, Amask;
	Object_Image::Format fmt = pObjImg->GetFormat();
	if (fmt == Object_Image::FORMAT_RGB) {
		Rmask = 0x00ff0000;
		Gmask = 0x0000ff00;
		Bmask = 0x000000ff;
		Amask = 0x00000000;
	} else if (fmt == Object_Image::FORMAT_RGBA) {
		Rmask = 0x00ff0000;
		Gmask = 0x0000ff00;
		Bmask = 0x000000ff;
		Amask = 0xff000000;
	} else {
		sig.SetError(ERR_ValueError, "unsupported image type");
		return NULL;
	}
	SDL_Surface *pSurface = ::SDL_CreateRGBSurfaceFrom(
				pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
	Object_Surface *pObj = new Object_Surface(pSurface);
	pObj->SetReferenceObject(Object::Reference(pObjImg));
	return pObj;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Surface
//-----------------------------------------------------------------------------
// sdl.Surface#UpdateRect(x:number => 0, y:number => 0, w:number => 0, h:number => 0):void
AScript_DeclareMethod(Surface, UpdateRect)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "x", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
	DeclareArg(env, "y", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
	DeclareArg(env, "w", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
	DeclareArg(env, "h", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
}

AScript_ImplementMethod(Surface, UpdateRect)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	::SDL_UpdateRect(pSurface,
		args.GetInt(0), args.GetInt(1), args.GetInt(2), args.GetInt(3));
	return Value::Null;
}

// sdl.Surface#UpdateRects(rects[]:Rect):void
AScript_DeclareMethod(Surface, UpdateRects)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "rects", AScript_PrivVTYPE(Rect), OCCUR_Once, true);
}

AScript_ImplementMethod(Surface, UpdateRects)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	const ValueList &valList = args.GetList(0);
	int numrects = static_cast<int>(valList.size());
	SDL_Rect *rects = new SDL_Rect[numrects];
	SDL_Rect *pRect = rects;
	foreach_const (ValueList, pValue, valList) {
		const Object_Rect *pObj =
					dynamic_cast<const Object_Rect *>(pValue->GetObject());
		*pRect = pObj->GetRect();
		pRect++;
	}
	::SDL_UpdateRects(pSurface, numrects, rects);
	delete[] rects;
	return Value::Null;
}

// sdl.Surface#Flip()
AScript_DeclareMethod(Surface, Flip)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Surface, Flip)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	return Value(::SDL_Flip(pSurface));
}

// sdl.Surface#SetColors(colors[]:Color, firstcolor:number => 0)
AScript_DeclareMethod(Surface, SetColors)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "colors", AScript_PrivVTYPE(Color), OCCUR_Once, true);
	DeclareArg(env, "firstcolor", VTYPE_Number, OCCUR_Once, false, false,
															new Expr_Value(0));
}

AScript_ImplementMethod(Surface, SetColors)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	const ValueList &valList = args.GetList(0);
	int firstcolor = args.GetInt(1);
	int ncolors = static_cast<int>(valList.size());
	SDL_Color *colors = new SDL_Color[ncolors];
	SDL_Color *pColor = colors;
	foreach_const (ValueList, pValue, valList) {
		const Object_Color *pObj =
					dynamic_cast<const Object_Color *>(pValue->GetObject());
		*pColor = pObj->GetColor();
		pColor++;
	}
	int rtn = ::SDL_SetColors(pSurface, colors, firstcolor, ncolors);
	delete[] colors;
	return Value(rtn);
}

// sdl.Surface#SetPalette(flags:number, colors[]:Color, firstcolor:number => 0)
AScript_DeclareMethod(Surface, SetPalette)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
	DeclareArg(env, "colors", AScript_PrivVTYPE(Color), OCCUR_Once, true);
	DeclareArg(env, "firstcolor", VTYPE_Number, OCCUR_Once, false, false,
															new Expr_Value(0));
}

AScript_ImplementMethod(Surface, SetPalette)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	int flags = args.GetInt(0);
	const ValueList &valList = args.GetList(1);
	int firstcolor = args.GetInt(2);
	int ncolors = static_cast<int>(valList.size());
	SDL_Color *colors = new SDL_Color[ncolors];
	SDL_Color *pColor = colors;
	foreach_const (ValueList, pValue, valList) {
		const Object_Color *pObj =
					dynamic_cast<const Object_Color *>(pValue->GetObject());
		*pColor = pObj->GetColor();
		pColor++;
	}
	int rtn = ::SDL_SetPalette(pSurface, flags, colors, firstcolor, ncolors);
	delete[] colors;
	return Value(rtn);
}

// sdl.Surface#LockSurface()
AScript_DeclareMethod(Surface, LockSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Surface, LockSurface)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	return Value(::SDL_LockSurface(pSurface));
}

// sdl.Surface#UnlockSurface():void
AScript_DeclareMethod(Surface, UnlockSurface)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementMethod(Surface, UnlockSurface)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	::SDL_UnlockSurface(pSurface);
	return Value::Null;
}

// sdl.Surface#SaveBMP(file:string):void
AScript_DeclareMethod(Surface, SaveBMP)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "file", VTYPE_String);
}

AScript_ImplementMethod(Surface, SaveBMP)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	return Value(::SDL_SaveBMP(pSurface, args.GetString(0)));
}

// sdl.Surface#SetColorKey(flag:number, key:number)
AScript_DeclareMethod(Surface, SetColorKey)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flag", VTYPE_Number);
	DeclareArg(env, "key", VTYPE_Number);
}

AScript_ImplementMethod(Surface, SetColorKey)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	return Value(::SDL_SetColorKey(pSurface, args.GetULong(0), args.GetULong(1)));
}

// sdl.Surface#SetAlpha(flag:number, alpha:number)
AScript_DeclareMethod(Surface, SetAlpha)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flag", VTYPE_Number);
	DeclareArg(env, "alpha", VTYPE_Number);
}

AScript_ImplementMethod(Surface, SetAlpha)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	return Value(::SDL_SetAlpha(pSurface, args.GetULong(0), args.GetUChar(1)));
}

// sdl.Surface#SetClipRect(rect:Rect):map:void
AScript_DeclareMethod(Surface, SetClipRect)
{
	SetMode(RSLTMODE_Void, FLAG_Map);
	DeclareArg(env, "rect", AScript_PrivVTYPE(Rect));
}

AScript_ImplementMethod(Surface, SetClipRect)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Rect &rect = dynamic_cast<Object_Rect *>(args.GetObject(0))->GetRect();
	::SDL_SetClipRect(pSurface, &rect);
	return Value::Null;
}

// sdl.Surface#GetClipRect()
AScript_DeclareMethod(Surface, GetClipRect)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Surface, GetClipRect)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Rect rect;
	::SDL_GetClipRect(pSurface, &rect);
	return Object_Rect::CreateValue(rect);
}

// sdl.Surface#ConvertSurface(fmt:PixelFormat, flags:number) {block?}
AScript_DeclareMethod(Surface, ConvertSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "fmt", AScript_PrivVTYPE(PixelFormat));
	DeclareArg(env, "flag", VTYPE_Number);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Surface, ConvertSurface)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	const SDL_PixelFormat *fmt =
		dynamic_cast<const Object_PixelFormat *>(args.GetObject(0))->GetPixelFormat();
	int flags = args.GetInt(1);
	SDL_Surface *pSurfaceConv = ::SDL_ConvertSurface(pSurface,
								const_cast<SDL_PixelFormat *>(fmt), flags);
	if (pSurfaceConv == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurfaceConv));
}

// sdl.Surface#FillRect(dstrect:Rect, color:Color):map:void
AScript_DeclareMethod(Surface, FillRect)
{
	SetMode(RSLTMODE_Void, FLAG_Map);
	DeclareArg(env, "rect", AScript_PrivVTYPE(Rect));
	DeclareArg(env, "color", AScript_PrivVTYPE(Color));
}

AScript_ImplementMethod(Surface, FillRect)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Rect &dstrect = dynamic_cast<Object_Rect *>(args.GetObject(0))->GetRect();
	SDL_Color &color = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	Uint32 colorIdx = ::SDL_MapRGB(pSurface->format, color.r, color.g, color.b);
	return Value(::SDL_FillRect(pSurface, &dstrect, colorIdx));
}

// sdl.Surface#DisplayFormat() {block?}
AScript_DeclareMethod(Surface, DisplayFormat)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Surface, DisplayFormat)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Surface *pSurfaceConv = ::SDL_DisplayFormat(pSurface);
	if (pSurfaceConv == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurfaceConv));
}

// sdl.Surface#DisplayFormatAlpha() {block?}
AScript_DeclareMethod(Surface, DisplayFormatAlpha)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Surface, DisplayFormatAlpha)
{
	SDL_Surface *pSurface = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Surface *pSurfaceConv = ::SDL_DisplayFormatAlpha(pSurface);
	if (pSurfaceConv == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurfaceConv));
}

// sdl.Surface#PutSurface(src:Surface, x:number => 0, y:number => 0):map
AScript_DeclareMethod(Surface, PutSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "src", AScript_PrivVTYPE(Surface));
	DeclareArg(env, "x", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
	DeclareArg(env, "y", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
}

AScript_ImplementMethod(Surface, PutSurface)
{
	SDL_Surface *dst = Object_Surface::GetSelfObj(args)->GetSurface();
	SDL_Surface *src =
		dynamic_cast<Object_Surface *>(args.GetObject(0))->GetSurface();
	int x = args.GetInt(1), y = args.GetInt(2);
	SDL_Rect *srcrect = NULL;
	SDL_Rect dstrect;
	dstrect.x = x, dstrect.y = y, dstrect.w = 0, dstrect.h = 0;
	return Value(::SDL_BlitSurface(src, srcrect, dst, &dstrect));
}

// implementation of class Surface
AScript_ImplementPrivClassWithCast(Surface)
{
	AScript_AssignMethod(Surface, UpdateRect);
	AScript_AssignMethod(Surface, UpdateRects);
	AScript_AssignMethod(Surface, Flip);
	AScript_AssignMethod(Surface, SetColors);
	AScript_AssignMethod(Surface, SetPalette);
	AScript_AssignMethod(Surface, LockSurface);
	AScript_AssignMethod(Surface, UnlockSurface);
	AScript_AssignMethod(Surface, SaveBMP);
	AScript_AssignMethod(Surface, SetColorKey);
	AScript_AssignMethod(Surface, SetAlpha);
	AScript_AssignMethod(Surface, SetClipRect);
	AScript_AssignMethod(Surface, GetClipRect);
	AScript_AssignMethod(Surface, ConvertSurface);
	AScript_AssignMethod(Surface, FillRect);
	AScript_AssignMethod(Surface, DisplayFormat);
	AScript_AssignMethod(Surface, DisplayFormatAlpha);
	AScript_AssignMethod(Surface, PutSurface);
}

AScript_ImplementCastFrom(Surface)
{
	if (value.IsImage()) {
		Object_Image *pObjImage = value.GetImageObj();
		Object_Surface *pObjSurface =
					Object_Surface::CreateSurfaceFromImage(sig, pObjImage);
		if (sig.IsSignalled()) return false;
		value = Value(pObjSurface);
		return true;
	}
	return false;
}

AScript_ImplementCastTo(Surface)
{
	return false;
}

//-----------------------------------------------------------------------------
// Object_Overlay implementation
//-----------------------------------------------------------------------------
Object_Overlay::~Object_Overlay()
{
	::SDL_FreeYUVOverlay(_pOverlay);
}

Object *Object_Overlay::Clone() const
{
	return NULL;
}

String Object_Overlay::ToString(Signal sig, bool exprFlag)
{
	return String("<Overlay>");
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Overlay
//-----------------------------------------------------------------------------
// sdl.Overlay#LockYUVOverlay()
AScript_DeclareMethod(Overlay, LockYUVOverlay)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Overlay, LockYUVOverlay)
{
	SDL_Overlay *pOverlay = Object_Overlay::GetSelfObj(args)->GetOverlay();
	return Value(::SDL_LockYUVOverlay(pOverlay));
}

// sdl.Overlay#UnlockYUVOverlay():void
AScript_DeclareMethod(Overlay, UnlockYUVOverlay)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementMethod(Overlay, UnlockYUVOverlay)
{
	SDL_Overlay *pOverlay = Object_Overlay::GetSelfObj(args)->GetOverlay();
	::SDL_UnlockYUVOverlay(pOverlay);
	return Value::Null;
}

// sdl.Overlay#DisplayYUVOverlay(dstrect:Rect)
AScript_DeclareMethod(Overlay, DisplayYUVOverlay)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "dstrect", AScript_PrivVTYPE(Rect));
}

AScript_ImplementMethod(Overlay, DisplayYUVOverlay)
{
	SDL_Overlay *pOverlay = Object_Overlay::GetSelfObj(args)->GetOverlay();
	SDL_Rect &dstrect = dynamic_cast<Object_Rect *>(args.GetObject(0))->GetRect();
	return Value(::SDL_DisplayYUVOverlay(pOverlay, &dstrect));
}

// implementation of class Overlay
AScript_ImplementPrivClass(Overlay)
{
	AScript_AssignMethod(Overlay, LockYUVOverlay);
	AScript_AssignMethod(Overlay, UnlockYUVOverlay);
	AScript_AssignMethod(Overlay, DisplayYUVOverlay);
}

//-----------------------------------------------------------------------------
// Object_VideoInfo implementation
//-----------------------------------------------------------------------------
Object_VideoInfo::~Object_VideoInfo()
{
}

Object *Object_VideoInfo::Clone() const
{
	return NULL;
}

String Object_VideoInfo::ToString(Signal sig, bool exprFlag)
{
	return String("<VideoInfo>");
}

Value Object_VideoInfo::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(hw_available))) {
		return Value(_pVideoInfo->hw_available? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(wm_available))) {
		return Value(_pVideoInfo->wm_available? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_hw))) {
		return Value(_pVideoInfo->blit_hw? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_hw_CC))) {
		return Value(_pVideoInfo->blit_hw_CC? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_hw_A))) {
		return Value(_pVideoInfo->blit_hw_A? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_sw))) {
		return Value(_pVideoInfo->blit_sw? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_sw_CC))) {
		return Value(_pVideoInfo->blit_sw_CC? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_sw_A))) {
		return Value(_pVideoInfo->blit_sw_A? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(blit_fill))) {
		return Value(_pVideoInfo->blit_fill? true : false);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(video_mem))) {
		return Value(_pVideoInfo->video_mem);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(vfmt))) {
		if (_pVideoInfo->vfmt == NULL) return Value::Null;
		return Object_PixelFormat::CreateValue(*_pVideoInfo->vfmt);
	}
	evaluatedFlag = false;
	return Value::Null;
}

// implementation of class VideoInfo
AScript_ImplementPrivClass(VideoInfo)
{
}

#if 0
//-----------------------------------------------------------------------------
// Object_Font implementation
//-----------------------------------------------------------------------------
Object_Font::~Object_Font()
{
	::TTF_CloseFont(_pFont);
}

Object *Object_Font::Clone() const
{
	return NULL;
}

String Object_Font::ToString(Signal sig, bool exprFlag)
{
	String str;
	str = "<Font";
	do {
		char *familyName = ::TTF_FontFaceFamilyName(_pFont);
		if (familyName != NULL) {
			str += ":";
			str += familyName;
		}
	} while (0);
	str += ">";
	return str;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Font
//-----------------------------------------------------------------------------
// sdl.Font#GetFontStyle()
AScript_DeclareMethod(Font, GetFontStyle)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, GetFontStyle)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_GetFontStyle(pFont));
}

// sdl.Font#SetFontStyle(style:number):void
AScript_DeclareMethod(Font, SetFontStyle)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "style", VTYPE_Number);
}

AScript_ImplementMethod(Font, SetFontStyle)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	::TTF_SetFontStyle(pFont, args.GetInt(0));
	return Value::Null;
}

// sdl.Font#GetFontOutline()
// symbol is not found in SDL_ttf.lib for VC
AScript_DeclareMethod(Font, GetFontOutline)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, GetFontOutline)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	//return Value(::TTF_GetFontOutline(pFont));
	sig.SetError(ERR_SystemError, "not implemented");
	return Value::Null;
}

// sdl.Font#SetFontOutline(outline:number):void
// symbol is not found in SDL_ttf.lib for VC
AScript_DeclareMethod(Font, SetFontOutline)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "style", VTYPE_Number);
}

AScript_ImplementMethod(Font, SetFontOutline)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	//::TTF_SetFontOutline(pFont, args.GetInt(0));
	sig.SetError(ERR_SystemError, "not implemented");
	return Value::Null;
}

// sdl.Font#GetFontHinting()
AScript_DeclareMethod(Font, GetFontHinting)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, GetFontHinting)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_GetFontHinting(pFont));
}

// sdl.Font#SetFontHinting(hinting:number):void
AScript_DeclareMethod(Font, SetFontHinting)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "hinting", VTYPE_Number);
}

AScript_ImplementMethod(Font, SetFontHinting)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	::TTF_SetFontHinting(pFont, args.GetInt(0));
	return Value::Null;
}

// sdl.Font#GetFontKerning()
AScript_DeclareMethod(Font, GetFontKerning)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, GetFontKerning)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_GetFontKerning(pFont));
}

// sdl.Font#SetFontKerning(allowed:number)
AScript_DeclareMethod(Font, SetFontKerning)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "allowed", VTYPE_Number);
}

AScript_ImplementMethod(Font, SetFontKerning)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	::TTF_SetFontKerning(pFont, args.GetInt(0));
	return Value::Null;
}

// sdl.Font#FontHeight()
AScript_DeclareMethod(Font, FontHeight)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontHeight)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontHeight(pFont));
}

// sdl.Font#FontAscent()
AScript_DeclareMethod(Font, FontAscent)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontAscent)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontAscent(pFont));
}

// sdl.Font#FontDescent()
AScript_DeclareMethod(Font, FontDescent)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontDescent)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontDescent(pFont));
}

// sdl.Font#FontLineSkip()
AScript_DeclareMethod(Font, FontLineSkip)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontLineSkip)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontLineSkip(pFont));
}

// sdl.Font#FontFaces()
AScript_DeclareMethod(Font, FontFaces)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontFaces)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontFaces(pFont));
}

// sdl.Font#FontFaceIsFixedWidth()
AScript_DeclareMethod(Font, FontFaceIsFixedWidth)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontFaceIsFixedWidth)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_FontFaceIsFixedWidth(pFont));
}

// sdl.Font#FontFaceFamilyName()
AScript_DeclareMethod(Font, FontFaceFamilyName)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontFaceFamilyName)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	char *familyName = ::TTF_FontFaceFamilyName(pFont);
	if (familyName == NULL) return Value::Null;
	return Value(env, familyName);
}

// sdl.Font#FontFaceStyleName()
AScript_DeclareMethod(Font, FontFaceStyleName)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Font, FontFaceStyleName)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	char *styleName = ::TTF_FontFaceStyleName(pFont);
	if (styleName == NULL) return Value::Null;
	return Value(env, styleName);
}

// sdl.Font#GlyphIsProvided(ch:number)
AScript_DeclareMethod(Font, GlyphIsProvided)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ch", VTYPE_Number);
}

AScript_ImplementMethod(Font, GlyphIsProvided)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	return Value(::TTF_GlyphIsProvided(pFont, args.GetUShort(0)));
}

// sdl.Font#GlyphMetrics(ch:number)
AScript_DeclareMethod(Font, GlyphMetrics)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ch", VTYPE_Number);
}

AScript_ImplementMethod(Font, GlyphMetrics)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	int minx, maxx, miny, maxy, advance;
	int rtn = ::TTF_GlyphMetrics(pFont, args.GetUShort(0),
								&minx, &maxx, &miny, &maxy, &advance);
	if (rtn < 0) return Value::Null;
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(minx));
	valList.push_back(Value(maxx));
	valList.push_back(Value(miny));
	valList.push_back(Value(maxy));
	valList.push_back(Value(advance));
	return result;
}

// sdl.Font#SizeText(text:string)
AScript_DeclareMethod(Font, SizeText)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "text", VTYPE_String);
}

AScript_ImplementMethod(Font, SizeText)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	int w, h;
	int rtn = ::TTF_SizeUTF8(pFont, args.GetString(0), &w, &h);
	if (rtn < 0) return Value::Null;
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(w));
	valList.push_back(Value(h));
	return result;
}

// sdl.Font#RenderText_Solid(text:string, fg:Color) {block?}
AScript_DeclareMethod(Font, RenderText_Solid)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "text", VTYPE_String);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderText_Solid)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	const char *text = args.GetString(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderUTF8_Solid(pFont, text, fg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.Font#RenderText_Shaded(text:string, fg:Color, bg:Color) {block?}
AScript_DeclareMethod(Font, RenderText_Shaded)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "text", VTYPE_String);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareArg(env, "bg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderText_Shaded)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	const char *text = args.GetString(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Color &bg = dynamic_cast<Object_Color *>(args.GetObject(2))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderUTF8_Shaded(pFont, text, fg, bg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.Font#RenderText_Blended(text:string, fg:Color) {block?}
AScript_DeclareMethod(Font, RenderText_Blended)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "text", VTYPE_String);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderText_Blended)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	const char *text = args.GetString(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderUTF8_Blended(pFont, text, fg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.Font#RenderGlyph_Solid(ch:number, fg:Color) {block?}
AScript_DeclareMethod(Font, RenderGlyph_Solid)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ch", VTYPE_Number);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderGlyph_Solid)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	Uint16 ch = args.GetUShort(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderGlyph_Solid(pFont, ch, fg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.Font#RenderGlyph_Shaded(ch:number, fg:Color, bg:Color) {block?}
AScript_DeclareMethod(Font, RenderGlyph_Shaded)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ch", VTYPE_Number);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareArg(env, "bg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderGlyph_Shaded)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	Uint16 ch = args.GetUShort(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Color &bg = dynamic_cast<Object_Color *>(args.GetObject(2))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderGlyph_Shaded(pFont, ch, fg, bg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.Font#RenderGlyph_Blended(ch:number, fg:Color) {block?}
AScript_DeclareMethod(Font, RenderGlyph_Blended)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ch", VTYPE_Number);
	DeclareArg(env, "fg", AScript_PrivVTYPE(Color));
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(Font, RenderGlyph_Blended)
{
	TTF_Font *pFont = Object_Font::GetSelfObj(args)->GetFont();
	Uint16 ch = args.GetUShort(0);
	SDL_Color &fg = dynamic_cast<Object_Color *>(args.GetObject(1))->GetColor();
	SDL_Surface *pSurface = ::TTF_RenderGlyph_Blended(pFont, ch, fg);
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// implementation of class Font
AScript_ImplementPrivClass(Font)
{
	AScript_AssignMethod(Font, GetFontStyle);
	AScript_AssignMethod(Font, SetFontStyle);
	AScript_AssignMethod(Font, GetFontOutline);
	AScript_AssignMethod(Font, SetFontOutline);
	AScript_AssignMethod(Font, GetFontHinting);
	AScript_AssignMethod(Font, SetFontHinting);
	AScript_AssignMethod(Font, GetFontKerning);
	AScript_AssignMethod(Font, SetFontKerning);
	AScript_AssignMethod(Font, FontHeight);
	AScript_AssignMethod(Font, FontAscent);
	AScript_AssignMethod(Font, FontDescent);
	AScript_AssignMethod(Font, FontLineSkip);
	AScript_AssignMethod(Font, FontFaces);
	AScript_AssignMethod(Font, FontFaceIsFixedWidth);
	AScript_AssignMethod(Font, FontFaceFamilyName);
	AScript_AssignMethod(Font, FontFaceStyleName);
	AScript_AssignMethod(Font, GlyphIsProvided);
	AScript_AssignMethod(Font, GlyphMetrics);
	AScript_AssignMethod(Font, SizeText);
	AScript_AssignMethod(Font, RenderText_Solid);
	AScript_AssignMethod(Font, RenderText_Shaded);
	AScript_AssignMethod(Font, RenderText_Blended);
	AScript_AssignMethod(Font, RenderGlyph_Solid);
	AScript_AssignMethod(Font, RenderGlyph_Shaded);
	AScript_AssignMethod(Font, RenderGlyph_Blended);
}
#endif

//-----------------------------------------------------------------------------
// Object_Joystick implementation
//-----------------------------------------------------------------------------
Object_Joystick::~Object_Joystick()
{
	::SDL_JoystickClose(_pJoystick);
}

Object *Object_Joystick::Clone() const
{
	return NULL;
}

String Object_Joystick::ToString(Signal sig, bool exprFlag)
{
	return String("<Joystick>");
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Joystick
//-----------------------------------------------------------------------------
// sdl.Joystick#JoystickIndex()
AScript_DeclareMethod(Joystick, JoystickIndex)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickIndex)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickIndex(pJoystick));
}

// sdl.Joystick#JoystickNumAxes()
AScript_DeclareMethod(Joystick, JoystickNumAxes)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickNumAxes)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickNumAxes(pJoystick));
}

// sdl.Joystick#JoystickNumBalls()
AScript_DeclareMethod(Joystick, JoystickNumBalls)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickNumBalls)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickNumBalls(pJoystick));
}

// sdl.Joystick#JoystickNumHats()
AScript_DeclareMethod(Joystick, JoystickNumHats)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickNumHats)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickNumHats(pJoystick));
}

// sdl.Joystick#JoystickNumButtons()
AScript_DeclareMethod(Joystick, JoystickNumButtons)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickNumButtons)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickNumButtons(pJoystick));
}

// sdl.Joystick#JoystickGetAxis(axis:number)
AScript_DeclareMethod(Joystick, JoystickGetAxis)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "axis", VTYPE_Number);
}

AScript_ImplementMethod(Joystick, JoystickGetAxis)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickGetAxis(pJoystick, args.GetInt(0)));
}

// sdl.Joystick#JoystickGetHat(hat:number)
AScript_DeclareMethod(Joystick, JoystickGetHat)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "hat", VTYPE_Number);
}

AScript_ImplementMethod(Joystick, JoystickGetHat)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickGetHat(pJoystick, args.GetInt(0)));
}

// sdl.Joystick#JoystickGetButton(button:number)
AScript_DeclareMethod(Joystick, JoystickGetButton)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "button", VTYPE_Number);
}

AScript_ImplementMethod(Joystick, JoystickGetButton)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	return Value(::SDL_JoystickGetButton(pJoystick, args.GetInt(0)));
}

// sdl.Joystick#JoystickGetBall(ball:number)
AScript_DeclareMethod(Joystick, JoystickGetBall)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "ball", VTYPE_Number);
}

AScript_ImplementMethod(Joystick, JoystickGetBall)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	int dx, dy;
	if (::SDL_JoystickGetBall(pJoystick, args.GetInt(0), &dx, &dy) < 0) {
		return Value::Null;
	}
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(dx));
	valList.push_back(Value(dy));
	return result;
}

// sdl.Joystick#JoystickClose():void
AScript_DeclareMethod(Joystick, JoystickClose)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementMethod(Joystick, JoystickClose)
{
	SDL_Joystick *pJoystick = Object_Joystick::GetSelfObj(args)->GetJoystick();
	::SDL_JoystickClose(pJoystick);
	return Value::Null;
}

// implementation of class Joystick
AScript_ImplementPrivClass(Joystick)
{
	AScript_AssignMethod(Joystick, JoystickIndex);
	AScript_AssignMethod(Joystick, JoystickNumAxes);
	AScript_AssignMethod(Joystick, JoystickNumBalls);
	AScript_AssignMethod(Joystick, JoystickNumHats);
	AScript_AssignMethod(Joystick, JoystickNumButtons);
	AScript_AssignMethod(Joystick, JoystickGetAxis);
	AScript_AssignMethod(Joystick, JoystickGetHat);
	AScript_AssignMethod(Joystick, JoystickGetButton);
	AScript_AssignMethod(Joystick, JoystickGetBall);
	AScript_AssignMethod(Joystick, JoystickClose);
}

//-----------------------------------------------------------------------------
// Object_AudioSpec implementation
//-----------------------------------------------------------------------------
Object_AudioSpec::~Object_AudioSpec()
{
	if (_audio_buf != NULL) ::SDL_FreeWAV(_audio_buf);
	::free(_pAudioSpec);
	Function::Delete(_pFuncCallback);
}

Object *Object_AudioSpec::Clone() const
{
	return NULL;
}

void Object_AudioSpec::Callback(Uint8 *stream, int len)
{
	if (_pFuncCallback == NULL) return;
	Environment &env = *this;
	Signal &sig = *_pSig;
	Object_Audio::Format fmt;
	if (_pAudioSpec->format == AUDIO_U16SYS) {
		fmt = IsBigEndian()? Object_Audio::FORMAT_U16BE : Object_Audio::FORMAT_U16LE;
	} else if (_pAudioSpec->format == AUDIO_S16SYS) {
		fmt = IsBigEndian()? Object_Audio::FORMAT_S16BE : Object_Audio::FORMAT_S16LE;
	} else {
		fmt =
			(_pAudioSpec->format == AUDIO_U8)? Object_Audio::FORMAT_U8 :
			(_pAudioSpec->format == AUDIO_S8)? Object_Audio::FORMAT_S8 :
			(_pAudioSpec->format == AUDIO_U16LSB)? Object_Audio::FORMAT_U16LE :
			(_pAudioSpec->format == AUDIO_S16LSB)? Object_Audio::FORMAT_S16LE :
			(_pAudioSpec->format == AUDIO_U16MSB)? Object_Audio::FORMAT_U16BE :
			(_pAudioSpec->format == AUDIO_S16MSB)? Object_Audio::FORMAT_S16BE :
			Object_Audio::FORMAT_U8;
	}
	Object_Audio *pObjAudio = new Object_Audio(env, fmt, _pAudioSpec->channels);
	::SDL_LockAudio();
	pObjAudio->ReferenceBuffer(NULL, stream, len);
	Value value(pObjAudio);
	ValueList valList(value);
	Args args(valList);
	_pFuncCallback->Eval(env, sig, args);
	::SDL_UnlockAudio();
}

void Object_AudioSpec::CallbackStub(void *userdata, Uint8 *stream, int len)
{
	if (userdata == NULL) return;
	Object_AudioSpec *pSelf = reinterpret_cast<Object_AudioSpec *>(userdata);
	pSelf->Callback(stream, len);
}

String Object_AudioSpec::ToString(Signal sig, bool exprFlag)
{
	char buff[64];
	String rtn;
	rtn += "<AudioSpec";
	do {
		rtn += ":";
		::sprintf(buff, "%dHz", _pAudioSpec->freq);
		rtn += buff;
	} while (0);
	do {
		rtn += ":";
		rtn +=
			(_pAudioSpec->format == AUDIO_U8)? "u8" :
			(_pAudioSpec->format == AUDIO_S8)? "s8" :
			(_pAudioSpec->format == AUDIO_U16LSB)? "u16lsb" :
			(_pAudioSpec->format == AUDIO_S16LSB)? "s16lsb" :
			(_pAudioSpec->format == AUDIO_U16MSB)? "u16msb" :
			(_pAudioSpec->format == AUDIO_S16MSB)? "s16msb" :
			(_pAudioSpec->format == AUDIO_U16SYS)? "u16sys" :
			(_pAudioSpec->format == AUDIO_S16SYS)? "s16sys" : "?";
	} while (0);
	do {
		rtn += ":";
		::sprintf(buff, "%dch", _pAudioSpec->channels);
		rtn += buff;
	} while (0);
	do {
		rtn += ":";
		::sprintf(buff, "%dsamples", _pAudioSpec->samples);
		rtn += buff;
	} while (0);
	rtn += ">";
	return rtn;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_AudioSpec
//-----------------------------------------------------------------------------
// sdl.AudioSpec#MixAudio(src:AudioSpec, volume:number)
AScript_DeclareMethod(AudioSpec, MixAudio)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "src", AScript_PrivVTYPE(AudioSpec));
	DeclareArg(env, "volume", VTYPE_Number);
}

AScript_ImplementMethod(AudioSpec, MixAudio)
{
	Object_AudioSpec *pDst = Object_AudioSpec::GetSelfObj(args);
	Object_AudioSpec *pSrc =dynamic_cast<Object_AudioSpec *>(args.GetObject(0));
	int volume = args.GetInt(1);
	if (pDst->GetAudioBuf() == NULL || pSrc->GetAudioBuf() == NULL) {
		sig.SetError(ERR_ValueError, "audio buffer is not prepared");
		return Value::Null;
	}
	if (pDst->GetAudioLen() != pSrc->GetAudioLen()) {
		sig.SetError(ERR_ValueError, "lengths of audio buffer are different");
		return Value::Null;
	}
	::SDL_MixAudio(pDst->GetAudioBuf(), pSrc->GetAudioBuf(),
											pDst->GetAudioLen(), volume);
	return Value::Null;
}

// implementation of class AudioSpec
AScript_ImplementPrivClass(AudioSpec)
{
	AScript_AssignMethod(AudioSpec, MixAudio);
}

//-----------------------------------------------------------------------------
// Object_AudioCVT implementation
//-----------------------------------------------------------------------------
Object_AudioCVT::~Object_AudioCVT()
{
	::free(_pAudioCVT);
}

Object *Object_AudioCVT::Clone() const
{
	return NULL;
}

String Object_AudioCVT::ToString(Signal sig, bool exprFlag)
{
	return String("<AudioCVT>");
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_AudioCVT
//-----------------------------------------------------------------------------
// sdl.AudioCVT#ConvertAudio()
AScript_DeclareMethod(AudioCVT, ConvertAudio)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(AudioCVT, ConvertAudio)
{
	SDL_AudioCVT *pAudioCVT = Object_AudioCVT::GetSelfObj(args)->GetAudioCVT();
	return Value(::SDL_ConvertAudio(pAudioCVT));
}

// implementation of class AudioCVT
AScript_ImplementPrivClass(AudioCVT)
{
	AScript_AssignMethod(AudioCVT, ConvertAudio);
}

//-----------------------------------------------------------------------------
// Object_CDtrack implementation
//-----------------------------------------------------------------------------
Object_CDtrack::~Object_CDtrack()
{
}

Object *Object_CDtrack::Clone() const
{
	return NULL;
}

Value Object_CDtrack::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(id))) {
		return Value(static_cast<int>(_CDtrack.id));
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(type))) {
		return Value(static_cast<int>(_CDtrack.type));
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(length))) {
		return Value(static_cast<int>(_CDtrack.length));
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(offset))) {
		return Value(static_cast<int>(_CDtrack.offset));
	}
	evaluatedFlag = false;
	return Value::Null;
}

String Object_CDtrack::ToString(Signal sig, bool exprFlag)
{
	return String("<CDtrack>");
}

// implementation of class CDtrack
AScript_ImplementPrivClass(CDtrack)
{
}

//-----------------------------------------------------------------------------
// Object_CD implementation
//-----------------------------------------------------------------------------
Object_CD::~Object_CD()
{
	::SDL_CDClose(_pCD);
}

Object *Object_CD::Clone() const
{
	return NULL;
}

Value Object_CD::DoPropGet(Signal sig, const Symbol *pSymbol, bool &evaluatedFlag)
{
	evaluatedFlag = true;
	if (pSymbol->IsIdentical(AScript_PrivSymbol(status))) {
		return Value(static_cast<int>(_pCD->status));
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(numtracks))) {
		return Value(_pCD->numtracks);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(cur_track))) {
		return Value(_pCD->cur_track);
	} else if (pSymbol->IsIdentical(AScript_PrivSymbol(cur_frame))) {
		return Value(_pCD->cur_frame);
	}
	evaluatedFlag = false;
	return Value::Null;
}

String Object_CD::ToString(Signal sig, bool exprFlag)
{
	return String("<CD>");
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_CD
//-----------------------------------------------------------------------------
// sdl.CD#CDStatus()
AScript_DeclareMethod(CD, CDStatus)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(CD, CDStatus)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDStatus(pCD));
}

// sdl.CD#CDPlay(start:number, length:number)
AScript_DeclareMethod(CD, CDPlay)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "start", VTYPE_Number);
	DeclareArg(env, "length", VTYPE_Number);
}

AScript_ImplementMethod(CD, CDPlay)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDPlay(pCD, args.GetInt(0), args.GetInt(1)));
}

// sdl.CD#CDPlayTracks(start_track:number, start_frame:number,
//                     ntracks:number, nframes:number)
AScript_DeclareMethod(CD, CDPlayTracks)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "start_track", VTYPE_Number);
	DeclareArg(env, "start_frame", VTYPE_Number);
	DeclareArg(env, "ntracks", VTYPE_Number);
	DeclareArg(env, "nframes", VTYPE_Number);
}

AScript_ImplementMethod(CD, CDPlayTracks)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDPlayTracks(pCD, args.GetInt(0), args.GetInt(1),
										args.GetInt(2), args.GetInt(3)));
}

// sdl.CD#CDPause()
AScript_DeclareMethod(CD, CDPause)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(CD, CDPause)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDPause(pCD));
}

// sdl.CD#CDResume()
AScript_DeclareMethod(CD, CDResume)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(CD, CDResume)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDResume(pCD));
}

// sdl.CD#CDStop()
AScript_DeclareMethod(CD, CDStop)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(CD, CDStop)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDStop(pCD));
}

// sdl.CD#CDEject()
AScript_DeclareMethod(CD, CDEject)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(CD, CDEject)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	return Value(::SDL_CDEject(pCD));
}

// sdl.CD#CDClose():void
AScript_DeclareMethod(CD, CDClose)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementMethod(CD, CDClose)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	::SDL_CDClose(pCD);
	return Value::Null;
}

// sdl.CD#GetTrack(n:number):map
AScript_DeclareMethod(CD, GetTrack)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "n", VTYPE_Number);
}

AScript_ImplementMethod(CD, GetTrack)
{
	SDL_CD *pCD = Object_CD::GetSelfObj(args)->GetCD();
	int n = args.GetInt(0);
	if (n < 0 || n > pCD->numtracks) {
		sig.SetError(ERR_ValueError, "track index is out of range");
		return Value::Null;
	}
	return Object_CDtrack::CreateValue(pCD->track[n]);
}

// implementation of class CD
AScript_ImplementPrivClass(CD)
{
	AScript_AssignMethod(CD, CDStatus);
	AScript_AssignMethod(CD, CDPlay);
	AScript_AssignMethod(CD, CDPlayTracks);
	AScript_AssignMethod(CD, CDPause);
	AScript_AssignMethod(CD, CDResume);
	AScript_AssignMethod(CD, CDStop);
	AScript_AssignMethod(CD, CDEject);
	AScript_AssignMethod(CD, CDClose);
	AScript_AssignMethod(CD, GetTrack);
}

//-----------------------------------------------------------------------------
// SDL functions: General
//-----------------------------------------------------------------------------
// sdl.Init(flags:number)
AScript_DeclareFunction(Init)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
}

AScript_ImplementFunction(Init)
{
	int rtn = ::SDL_Init(args.GetULong(0));
	if (rtn < 0) return Value(rtn);
#if 0
	do {
		int flags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF;
		::IMG_Init(flags);
	} while (0);
	//::TTF_Init();
	do {
		int flags = MIX_INIT_FLAC | MIX_INIT_MOD | MIX_INIT_MP3 | MIX_INIT_OGG;
		::Mix_Init(flags);
	} while (0);
#endif
	return Value(rtn);
}

// sdl.InitSubSystem(flags:number)
AScript_DeclareFunction(InitSubSystem)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
}

AScript_ImplementFunction(InitSubSystem)
{
	return Value(::SDL_InitSubSystem(args.GetULong(0)));
}

// sdl.QuitSubSystem(flags:number):void
AScript_DeclareFunction(QuitSubSystem)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
}

AScript_ImplementFunction(QuitSubSystem)
{
	::SDL_QuitSubSystem(args.GetULong(0));
	return Value::Null;
}

// sdl.Quit():void
AScript_DeclareFunction(Quit)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(Quit)
{
	::SDL_Quit();
	//::IMG_Quit();
	//::TTF_Quit();
	return Value::Null;
}

// sdl.WasInit(flags:number)
AScript_DeclareFunction(WasInit)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
}

AScript_ImplementFunction(WasInit)
{
	return Value(::SDL_WasInit(args.GetULong(0)));
}

// sdl.GetError()
AScript_DeclareFunction(GetError)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetError)
{
	//return Value(env, ::SDL_GetError());
	return Value(env, "");
}

//-----------------------------------------------------------------------------
// SDL functions: Video
//-----------------------------------------------------------------------------
// sdl.GetVideoSurface() {block?}
AScript_DeclareFunction(GetVideoSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(GetVideoSurface)
{
	SDL_Surface *pSurface = ::SDL_GetVideoSurface();
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.GetVideoInfo()
AScript_DeclareFunction(GetVideoInfo)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetVideoInfo)
{
	const SDL_VideoInfo *pVideoInfo = ::SDL_GetVideoInfo();
	if (pVideoInfo == NULL) return Value::Null;
	return Object_VideoInfo::CreateValue(pVideoInfo);
}

// sdl.VideoDriverName()
AScript_DeclareFunction(VideoDriverName)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(VideoDriverName)
{
	char buff[64];
	char *p = ::SDL_VideoDriverName(buff, sizeof(buff));
	if (p == NULL) return Value::Null;
	return Value(env, p);
}

// sdl.ListModes()
AScript_DeclareFunction(ListModes)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(ListModes)
{
	return Value::Null;
}

// sdl.VideoModeOK(width:number, height:number, bpp:number, flags:number)
AScript_DeclareFunction(VideoModeOK)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "width", VTYPE_Number);
	DeclareArg(env, "height", VTYPE_Number);
	DeclareArg(env, "bpp", VTYPE_Number);
	DeclareArg(env, "flags", VTYPE_Number);
}

AScript_ImplementFunction(VideoModeOK)
{
	return Value(::SDL_VideoModeOK(
		args.GetInt(0), args.GetInt(1), args.GetInt(2), args.GetULong(3)));
}

// sdl.SetVideoMode(width:number, height:number, bpp:number, flags:number) {block?}
AScript_DeclareFunction(SetVideoMode)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "width", VTYPE_Number);
	DeclareArg(env, "height", VTYPE_Number);
	DeclareArg(env, "bpp", VTYPE_Number);
	DeclareArg(env, "flags", VTYPE_Number);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(SetVideoMode)
{
	SDL_Surface *pSurface = ::SDL_SetVideoMode(
		args.GetInt(0), args.GetInt(1), args.GetInt(2), args.GetULong(3));
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.SetGamma(redgamma:number, greengamma:number, bluegamma:number)
AScript_DeclareFunction(SetGamma)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "redgamma", VTYPE_Number);
	DeclareArg(env, "greengamma", VTYPE_Number);
	DeclareArg(env, "bluegamma", VTYPE_Number);
}

AScript_ImplementFunction(SetGamma)
{
	return Value(::SDL_SetGamma(static_cast<float>(args.GetNumber(0)),
		static_cast<float>(args.GetNumber(1)), static_cast<float>(args.GetNumber(2))));
}

// sdl.GetGammaRamp()
AScript_DeclareFunction(GetGammaRamp)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetGammaRamp)
{
	Uint16 redtable[256], greentable[256], bluetable[256];
	int rtn = ::SDL_GetGammaRamp(redtable, greentable, bluetable);
	if (rtn < 0) return Value::Null;
	Value result;
	ValueList &valList = result.InitAsList(env);
	do {
		Value valElem;
		ValueList &valElemList = valElem.InitAsList(env);
		valList.push_back(valElem);
		for (int i = 0; i < 256; i++) {
			valElemList.push_back(Value(redtable[i]));
		}
	} while (0);
	do {
		Value valElem;
		ValueList &valElemList = valElem.InitAsList(env);
		valList.push_back(valElem);
		for (int i = 0; i < 256; i++) {
			valElemList.push_back(Value(greentable[i]));
		}
	} while (0);
	do {
		Value valElem;
		ValueList &valElemList = valElem.InitAsList(env);
		valList.push_back(valElem);
		for (int i = 0; i < 256; i++) {
			valElemList.push_back(Value(bluetable[i]));
		}
	} while (0);
	return Value::Null;
}

// sdl.SetGammaRamp(redtable[]:number, greentable[]:number, bluetable[]:number)
AScript_DeclareFunction(SetGammaRamp)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "redtable", VTYPE_Number, OCCUR_Once, true);
	DeclareArg(env, "greentable", VTYPE_Number, OCCUR_Once, true);
	DeclareArg(env, "bluetable", VTYPE_Number, OCCUR_Once, true);
}

AScript_ImplementFunction(SetGammaRamp)
{
	Uint16 redtable[256], greentable[256], bluetable[256];
	::memset(redtable, 0, sizeof(redtable));
	::memset(redtable, 0, sizeof(greentable));
	::memset(redtable, 0, sizeof(bluetable));
	do {
		int i = 0;
		foreach_const (ValueList, pValue, args.GetList(0)) {
			if (i > 255) break;
			redtable[i++] = pValue->GetUShort();
		}
	} while (0);
	do {
		int i = 0;
		foreach_const (ValueList, pValue, args.GetList(1)) {
			if (i > 255) break;
			greentable[i++] = pValue->GetUShort();
		}
	} while (0);
	do {
		int i = 0;
		foreach_const (ValueList, pValue, args.GetList(2)) {
			if (i > 255) break;
			bluetable[i++] = pValue->GetUShort();
		}
	} while (0);
	int rtn = ::SDL_SetGammaRamp(redtable, greentable, bluetable);
	return Value(rtn);
}

// sdl.CreateRGBSurface(flags:number, width:number, height:number, depth:number,
//              Rmask:number, Gmask:number, Bmask:number, Amask:number) {block?}
AScript_DeclareFunction(CreateRGBSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "flags", VTYPE_Number);
	DeclareArg(env, "width", VTYPE_Number);
	DeclareArg(env, "height", VTYPE_Number);
	DeclareArg(env, "depth", VTYPE_Number);
	DeclareArg(env, "Rmask", VTYPE_Number);
	DeclareArg(env, "Gmask", VTYPE_Number);
	DeclareArg(env, "Bmask", VTYPE_Number);
	DeclareArg(env, "Amask", VTYPE_Number);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(CreateRGBSurface)
{
	SDL_Surface *pSurface = ::SDL_CreateRGBSurface(
		args.GetULong(0), args.GetInt(1), args.GetInt(2), args.GetInt(3),
		args.GetULong(4), args.GetULong(5), args.GetULong(6), args.GetULong(7));
	if (pSurface == NULL) return Value::Null;
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.CreateRGBSurfaceFrom(image:image) {block?}
AScript_DeclareFunction(CreateRGBSurfaceFrom)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "image", VTYPE_Image);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(CreateRGBSurfaceFrom)
{
	Object_Image *pObjImg = args.GetImageObj(0);
	Object_Surface *pObj = Object_Surface::CreateSurfaceFromImage(sig, pObjImg);
	if (sig.IsSignalled()) return Value::Null;
	return ReturnValue(env, sig, args, Value(pObj));
}

// sdl.LoadBMP(file:string) {block?}
AScript_DeclareFunction(LoadBMP)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "file", VTYPE_String);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(LoadBMP)
{
	const char *file = args.GetString(0);
	SDL_Surface *pSurface = ::SDL_LoadBMP(file);
	if (pSurface == NULL) {
		sig.SetError(ERR_RuntimeError, "failed to load an image %s", file);
		return Value::Null;
	}
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.LoadImage(file:string) {block?}
AScript_DeclareFunction(LoadImage)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "file", VTYPE_String);
	DeclareBlock(OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(LoadImage)
{
	const char *file = args.GetString(0);
	SDL_Surface *pSurface = ::IMG_Load(file);
	if (pSurface == NULL) {
		sig.SetError(ERR_RuntimeError, "failed to load an image %s", file);
		return Value::Null;
	}
	return ReturnValue(env, sig, args, Object_Surface::CreateValue(pSurface));
}

// sdl.BlitSurface(src:Surface, srcrect, dst:Surface, dstrect)
AScript_DeclareFunction(BlitSurface)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "src",		AScript_PrivVTYPE(Surface));
	DeclareArg(env, "srcrect",	VTYPE_Any);
	DeclareArg(env, "dst",		AScript_PrivVTYPE(Surface));
	DeclareArg(env, "dstrect",	VTYPE_Any);
}

AScript_ImplementFunction(BlitSurface)
{
	SDL_Surface *src =
		dynamic_cast<Object_Surface *>(args.GetObject(0))->GetSurface();
	SDL_Surface *dst =
		dynamic_cast<Object_Surface *>(args.GetObject(2))->GetSurface();
	SDL_Rect *srcrect = NULL, *dstrect = NULL;
	if (args.IsType(1, AScript_PrivVTYPE(Rect))) {
		srcrect = &dynamic_cast<Object_Rect *>(args.GetObject(1))->GetRect();
	}
	if (args.IsType(3, AScript_PrivVTYPE(Rect))) {
		dstrect = &dynamic_cast<Object_Rect *>(args.GetObject(3))->GetRect();
	}
	return Value(::SDL_BlitSurface(src, srcrect, dst, dstrect));
}

// sdl.WarpMouse(x:number, y:number):void
AScript_DeclareFunction(WarpMouse)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "x", VTYPE_Number);
	DeclareArg(env, "y", VTYPE_Number);
}

AScript_ImplementFunction(WarpMouse)
{
	::SDL_WarpMouse(args.GetUShort(0), args.GetUShort(1));
	return Value::Null;
}

// sdl.CreateCursor(data:binary, mask:binary,
//                  w:number, h:number, hot_x:number, hot_y:number)
AScript_DeclareFunction(CreateCursor)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "data", VTYPE_Binary);
	DeclareArg(env, "mask", VTYPE_Binary);
	DeclareArg(env, "w", VTYPE_Number);
	DeclareArg(env, "h", VTYPE_Number);
	DeclareArg(env, "hot_x", VTYPE_Number);
	DeclareArg(env, "hot_y", VTYPE_Number);
}

AScript_ImplementFunction(CreateCursor)
{
	Uint8 *data = const_cast<Uint8 *>(
				reinterpret_cast<const Uint8 *>(args.GetBinary(0).data()));
	Uint8 *mask = const_cast<Uint8 *>(
				reinterpret_cast<const Uint8 *>(args.GetBinary(1).data()));
	int w = args.GetInt(2), h = args.GetInt(3);
	int hot_x = args.GetInt(4), hot_y = args.GetInt(5);
	SDL_Cursor *pCursor = ::SDL_CreateCursor(data, mask, w, h, hot_x, hot_y);
	return Object_Cursor::CreateValue(pCursor);
}

// sdl.SetCursor(cursor:Cursor):void
AScript_DeclareFunction(SetCursor)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "cursor", AScript_PrivVTYPE(Cursor));
}

AScript_ImplementFunction(SetCursor)
{
	SDL_Cursor *pCursor =
			dynamic_cast<Object_Cursor *>(args.GetObject(0))->GetCursor();
	if (pCursor == NULL) {
		sig.SetError(ERR_ValueError, "invalid cursor instance");
		return Value::Null;
	}
	::SDL_SetCursor(pCursor);
	return Value::Null;
}

// sdl.GetCursor()
AScript_DeclareFunction(GetCursor)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetCursor)
{
	SDL_Cursor *pCursor = ::SDL_GetCursor();
	return Object_Cursor::CreateValue(pCursor);
}

// sdl.ShowCursor(toggle:number)
AScript_DeclareFunction(ShowCursor)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "toggle", VTYPE_Number);
}

AScript_ImplementFunction(ShowCursor)
{
	return Value(::SDL_ShowCursor(args.GetInt(0)));
}

// sdl.GL_GetAttribute(attr:number)
AScript_DeclareFunction(GL_GetAttribute)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "attr", VTYPE_Number);
}

AScript_ImplementFunction(GL_GetAttribute)
{
	int value;
	int rtn = ::SDL_GL_GetAttribute(
				static_cast<SDL_GLattr>(args.GetInt(0)), &value);
	if (rtn < 0) return Value::Null;
	return Value(value);
}

// sdl.GL_SetAttribute(attr:number, value:number)
AScript_DeclareFunction(GL_SetAttribute)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "attr", VTYPE_Number);
	DeclareArg(env, "value", VTYPE_Number);
}

AScript_ImplementFunction(GL_SetAttribute)
{
	int rtn = ::SDL_GL_SetAttribute(
				static_cast<SDL_GLattr>(args.GetInt(0)), args.GetInt(1));
	return Value(rtn);
}

// sdl.GL_SwapBuffers():void
AScript_DeclareFunction(GL_SwapBuffers)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(GL_SwapBuffers)
{
	::SDL_GL_SwapBuffers();
	return Value::Null;
}

// sdl.CreateYUVOverlay()
AScript_DeclareFunction(CreateYUVOverlay)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "width", VTYPE_Number);
	DeclareArg(env, "height", VTYPE_Number);
	DeclareArg(env, "format", VTYPE_Number);
	DeclareArg(env, "display", AScript_PrivVTYPE(Surface));
}

AScript_ImplementFunction(CreateYUVOverlay)
{
	SDL_Surface *pSurface =
		dynamic_cast<Object_Surface *>(args.GetObject(3))->GetSurface();
	SDL_Overlay *pOverlay = ::SDL_CreateYUVOverlay(
			args.GetInt(0), args.GetInt(1), args.GetULong(2), pSurface);
	if (pOverlay == NULL) return Value::Null;
	return Object_Overlay::CreateValue(pOverlay);
}

//-----------------------------------------------------------------------------
// SDL functions: Window Management
//-----------------------------------------------------------------------------
// sdl.WM_SetCaption(title:string, icon:string):void
AScript_DeclareFunction(WM_SetCaption)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "title", VTYPE_String);
	DeclareArg(env, "icon", VTYPE_String);
}

AScript_ImplementFunction(WM_SetCaption)
{
	::SDL_WM_SetCaption(args.GetString(0), args.GetString(1));
	return Value::Null;
}

// sdl.WM_GetCaption()
AScript_DeclareFunction(WM_GetCaption)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(WM_GetCaption)
{
	char *title = NULL, *icon = NULL;
	::SDL_WM_GetCaption(&title, &icon);
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(env, (title == NULL)? "" : title));
	valList.push_back(Value(env, (icon == NULL)? "" : icon));
	return result;
}

// sdl.WM_SetIcon(icon:Surface, mask?:binary)
AScript_DeclareFunction(WM_SetIcon)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "surface", AScript_PrivVTYPE(Surface));
	DeclareArg(env, "mask", VTYPE_Binary, OCCUR_ZeroOrOnce);
}

AScript_ImplementFunction(WM_SetIcon)
{
	SDL_Surface *pSurface = dynamic_cast<Object_Surface *>(args.GetObject(0))->GetSurface();
	const char *mask = args.IsBinary(1)? args.GetBinary(1).data() : NULL;
	::SDL_WM_SetIcon(pSurface,
				const_cast<Uint8 *>(reinterpret_cast<const Uint8 *>(mask)));
	return Value::Null;
}

// sdl.WM_IconifyWindow()
AScript_DeclareFunction(WM_IconifyWindow)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(WM_IconifyWindow)
{
	return Value(::SDL_WM_IconifyWindow());
}

// sdl.WM_ToggleFullScreen(surface:Surface)
AScript_DeclareFunction(WM_ToggleFullScreen)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "surface", AScript_PrivVTYPE(Surface));
}

AScript_ImplementFunction(WM_ToggleFullScreen)
{
	SDL_Surface *pSurface = dynamic_cast<Object_Surface *>(args.GetObject(0))->GetSurface();
	return Value(::SDL_WM_ToggleFullScreen(pSurface));
}

// sdl.WM_GrabInput(mode:number)
AScript_DeclareFunction(WM_GrabInput)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "mode", VTYPE_Number);
}

AScript_ImplementFunction(WM_GrabInput)
{
	SDL_GrabMode mode = static_cast<SDL_GrabMode>(args.GetInt(0));
	return Value(static_cast<int>(::SDL_WM_GrabInput(mode)));
}

//-----------------------------------------------------------------------------
// SDL functions: Events
//-----------------------------------------------------------------------------
// sdl.PumpEvents():void
AScript_DeclareFunction(PumpEvents)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(PumpEvents)
{
	::SDL_PumpEvents();
	return Value::Null;
}

// sdl.AddEvents(events[]:Event, mask:number)
AScript_DeclareFunction(AddEvents)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "events", AScript_PrivVTYPE(Event), OCCUR_Once, true);
	DeclareArg(env, "mask", VTYPE_Number);
}

AScript_ImplementFunction(AddEvents)
{
	int numevents = static_cast<int>(args.GetList(0).size());
	Uint32 mask = args.GetULong(1);
	int i = 0;
	SDL_Event *events = new SDL_Event[numevents];
	foreach_const (ValueList, pValue, args.GetList(0)) {
		events[i++] =
				dynamic_cast<const Object_Event *>(pValue->GetObject())->GetEvent();
	}
	int rtn = ::SDL_PeepEvents(events, numevents, SDL_ADDEVENT, mask);
	delete[] events;
	return Value(rtn);
}

// sdl.PeekEvents(numevents:number, mask:number)
AScript_DeclareFunction(PeekEvents)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "numevents", VTYPE_Number);
	DeclareArg(env, "mask", VTYPE_Number);
}

AScript_ImplementFunction(PeekEvents)
{
	int numevents = args.GetInt(0);
	Uint32 mask = args.GetULong(1);
	SDL_Event *events = new SDL_Event[numevents];
	int rtn = ::SDL_PeepEvents(events, numevents, SDL_PEEKEVENT, mask);
	if (rtn < 0) {
		delete[] events;
		return Value::Null;
	}
	Value result;
	ValueList &valList = result.InitAsList(env);
	for (int i = 0; i < numevents; i++) {
		valList.push_back(Object_Event::CreateValue(events[i]));
	}
	delete[] events;
	return result;
}

// sdl.GetEvents(numevents:number, mask:number)
AScript_DeclareFunction(GetEvents)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "numevents", VTYPE_Number);
	DeclareArg(env, "mask", VTYPE_Number);
}

AScript_ImplementFunction(GetEvents)
{
	int numevents = args.GetInt(0);
	Uint32 mask = args.GetULong(1);
	SDL_Event *events = new SDL_Event[numevents];
	int rtn = ::SDL_PeepEvents(events, numevents, SDL_GETEVENT, mask);
	if (rtn < 0) {
		delete[] events;
		return Value::Null;
	}
	Value result;
	ValueList &valList = result.InitAsList(env);
	for (int i = 0; i < numevents; i++) {
		valList.push_back(Object_Event::CreateValue(events[i]));
	}
	delete[] events;
	return result;
}

// sdl.PollEvent()
AScript_DeclareFunction(PollEvent)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(PollEvent)
{
	SDL_Event event;
	if (::SDL_PollEvent(&event) == 0) return Value::Null;
	if (event.type == SDL_USEREVENT_Timer) {
		Object_Timer *pObjTimer = reinterpret_cast<Object_Timer *>(event.user.data1);
		pObjTimer->DoHandle();
		Object::Delete(pObjTimer);
		return Value::Null;
	}
	return Object_Event::CreateValue(event);
}

// sdl.WaitEvent()
AScript_DeclareFunction(WaitEvent)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(WaitEvent)
{
	SDL_Event event;
	for (;;) {
		if (::SDL_WaitEvent(&event) == 0) return Value::Null;
		if (event.type == SDL_USEREVENT_Timer) {
			Object_Timer *pObjTimer = reinterpret_cast<Object_Timer *>(event.user.data1);
			pObjTimer->DoHandle();
			Object::Delete(pObjTimer);
		} else {
			break;
		}
	}
	return Object_Event::CreateValue(event);
}

// sdl.PushEvent(event:Event)
AScript_DeclareFunction(PushEvent)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "event", AScript_PrivVTYPE(Event));
}

AScript_ImplementFunction(PushEvent)
{
	SDL_Event *event = &dynamic_cast<Object_Event *>(args.GetObject(0))->GetEvent();
	return Value(::SDL_PushEvent(event));
}

// sdl.SetEventFilter(filter:function)
static Function *_pFuncEventFilter = NULL;
static int EventFilter(const SDL_Event *event)
{
	if (_pFuncEventFilter == NULL) return 1;
	Signal sig;
	Environment &env = _pFuncEventFilter->GetEnvScope();
	ValueList valList;
	valList.push_back(Object_Event::CreateValue(*event));
	Args args(valList);
	Value result = _pFuncEventFilter->Eval(env, sig, args);
	if (sig.IsSignalled()) return 0;
	return result.GetBoolean()? 1 : 0;
}

AScript_DeclareFunction(SetEventFilter)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "filter", VTYPE_Function);
}

AScript_ImplementFunction(SetEventFilter)
{
	Function::Delete(_pFuncEventFilter);
	_pFuncEventFilter = Function::Reference(args.GetFunction(0));
	::SDL_SetEventFilter(EventFilter);
	return Value::Null;
}

// sdl.GetEventFilter()
AScript_DeclareFunction(GetEventFilter)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetEventFilter)
{
	if (_pFuncEventFilter == NULL) return Value::Null;
	return Value(env, _pFuncEventFilter, Value::Null);
}

// sdl.EventState(type:number, state:number)
AScript_DeclareFunction(EventState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "type", VTYPE_Number);
	DeclareArg(env, "state", VTYPE_Number);
}

AScript_ImplementFunction(EventState)
{
	return Value(::SDL_EventState(args.GetUChar(0), args.GetInt(1)));
}

// sdl.CheckKeyState(key:number):map
AScript_DeclareFunction(CheckKeyState)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "key", VTYPE_Number);
}

AScript_ImplementFunction(CheckKeyState)
{
	int key = args.GetInt(0);
	int numkeys = 0;
	Uint8 *keystate = ::SDL_GetKeyState(&numkeys);
	return Value(0 <= key && key < numkeys && keystate[key] != 0);
}

// sdl.GetModState()
AScript_DeclareFunction(GetModState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetModState)
{
	return Value(static_cast<int>(::SDL_GetModState()));
}

// sdl.SetModState(modstate:number):void
AScript_DeclareFunction(SetModState)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "modstate", VTYPE_Number);
}

AScript_ImplementFunction(SetModState)
{
	::SDL_SetModState(static_cast<SDLMod>(args.GetInt(0)));
	return Value::Null;
}

// sdl.GetKeyName(key:number)
AScript_DeclareFunction(GetKeyName)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "key", VTYPE_Number);
}

AScript_ImplementFunction(GetKeyName)
{
	return Value(env, ::SDL_GetKeyName(static_cast<SDLKey>(args.GetInt(0))));
}

// sdl.EnableUNICODE(enable:number)
AScript_DeclareFunction(EnableUNICODE)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "enable", VTYPE_Number);
}

AScript_ImplementFunction(EnableUNICODE)
{
	return Value(::SDL_EnableUNICODE(args.GetInt(0)));
}

// sdl.EnableKeyRepeat(delay:number, interval:number)
AScript_DeclareFunction(EnableKeyRepeat)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "delay", VTYPE_Number);
	DeclareArg(env, "interval", VTYPE_Number);
}

AScript_ImplementFunction(EnableKeyRepeat)
{
	return Value(::SDL_EnableKeyRepeat(args.GetInt(0), args.GetInt(1)));
}

// sdl.GetMouseState()
AScript_DeclareFunction(GetMouseState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetMouseState)
{
	int x, y;
	Uint8 state = ::SDL_GetMouseState(&x, &y);
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(state));
	valList.push_back(Value(x));
	valList.push_back(Value(y));
	return result;
}

// sdl.GetRelativeMouseState()
AScript_DeclareFunction(GetRelativeMouseState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetRelativeMouseState)
{
	int x, y;
	Uint8 state = ::SDL_GetRelativeMouseState(&x, &y);
	Value result;
	ValueList &valList = result.InitAsList(env);
	valList.push_back(Value(state));
	valList.push_back(Value(x));
	valList.push_back(Value(y));
	return result;
}

// sdl.GetAppState()
AScript_DeclareFunction(GetAppState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetAppState)
{
	return Value(::SDL_GetAppState());
}

// sdl.JoystickEventState(state:number)
AScript_DeclareFunction(JoystickEventState)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "state", VTYPE_Number);
}

AScript_ImplementFunction(JoystickEventState)
{
	return Value(::SDL_JoystickEventState(args.GetInt(0)));
}

//-----------------------------------------------------------------------------
// SDL functions: Joystick
//-----------------------------------------------------------------------------
// sdl.NumJoysticks()
AScript_DeclareFunction(NumJoysticks)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(NumJoysticks)
{
	return Value(::SDL_NumJoysticks());
}

// sdl.JoystickName(index:number):map
AScript_DeclareFunction(JoystickName)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "index", VTYPE_Number);
}

AScript_ImplementFunction(JoystickName)
{
	return Value(env, ::SDL_JoystickName(args.GetInt(0)));
}

// sdl.JoystickOpen(index:number):map
AScript_DeclareFunction(JoystickOpen)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "index", VTYPE_Number);
}

AScript_ImplementFunction(JoystickOpen)
{
	SDL_Joystick *pJoystick = ::SDL_JoystickOpen(args.GetInt(0));
	if (pJoystick == NULL) return Value::Null;
	return Object_Joystick::CreateValue(pJoystick);
}

// sdl.JoystickOpened(index:number):map
AScript_DeclareFunction(JoystickOpened)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "index", VTYPE_Number);
}

AScript_ImplementFunction(JoystickOpened)
{
	return Value(::SDL_JoystickOpened(args.GetInt(0))? true : false);
}

// sdl.JoystickUpdate():void
AScript_DeclareFunction(JoystickUpdate)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(JoystickUpdate)
{
	::SDL_JoystickUpdate();
	return Value::Null;
}

//-----------------------------------------------------------------------------
// SDL functions: Audio
//-----------------------------------------------------------------------------
// sdl.OpenAudio(desired:AudioSpec)
AScript_DeclareFunction(OpenAudio)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "desired", AScript_PrivVTYPE(AudioSpec));
}

AScript_ImplementFunction(OpenAudio)
{
	SDL_AudioSpec *desired =
		dynamic_cast<Object_AudioSpec *>(args.GetObject(0))->GetAudioSpec();
	SDL_AudioSpec *obtained =
		reinterpret_cast<SDL_AudioSpec *>(::malloc(sizeof(SDL_AudioSpec)));
	if (::SDL_OpenAudio(desired, obtained) < 0) {
		sig.SetError(ERR_RuntimeError, "failed to open audio device");
		::free(obtained);
		return Value::Null;
	}
	return Object_AudioSpec::CreateValue(obtained, NULL, NULL, NULL, 0);
}

// sdl.PauseAudio(pause_on:number):void
AScript_DeclareFunction(PauseAudio)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "pause_on", VTYPE_Number);
}

AScript_ImplementFunction(PauseAudio)
{
	::SDL_PauseAudio(args.GetInt(0));
	return Value::Null;
}

// sdl.GetAudioStatus()
AScript_DeclareFunction(GetAudioStatus)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetAudioStatus)
{
	return Value(static_cast<int>(::SDL_GetAudioStatus()));
}

// sdl.LoadWAV(file:string)
AScript_DeclareFunction(LoadWAV)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "file", VTYPE_String);
}

AScript_ImplementFunction(LoadWAV)
{
	SDL_AudioSpec *pAudioSpec =
		reinterpret_cast<SDL_AudioSpec *>(::malloc(sizeof(SDL_AudioSpec)));
	Uint8 *audio_buf = NULL;
	Uint32 audio_len = 0;
	if (::SDL_LoadWAV(args.GetString(0), pAudioSpec, &audio_buf, &audio_len) == NULL) {
		sig.SetError(ERR_RuntimeError, "failed to load WAV data");
		return Value::Null;
	}
	pAudioSpec->callback = Object_AudioSpec::CallbackStub;
	pAudioSpec->userdata = NULL;
	return Object_AudioSpec::CreateValue(pAudioSpec, NULL, NULL, audio_buf, audio_len);
}

// sdl.BuildAudioCVT(src_format:number, src_channels:number, src_rate:number,
//                   dst_format:number, dst_channels:number, dst_rate:number)
AScript_DeclareFunction(BuildAudioCVT)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "src_format", VTYPE_Number);
	DeclareArg(env, "src_channels", VTYPE_Number);
	DeclareArg(env, "src_rate", VTYPE_Number);
	DeclareArg(env, "dst_format", VTYPE_Number);
	DeclareArg(env, "dst_channels", VTYPE_Number);
	DeclareArg(env, "dst_rate", VTYPE_Number);
}

AScript_ImplementFunction(BuildAudioCVT)
{
	SDL_AudioCVT *cvt =
			reinterpret_cast<SDL_AudioCVT *>(::malloc(sizeof(SDL_AudioCVT)));
	Uint16 src_format = args.GetUShort(0);
	Uint8 src_channels = args.GetUChar(1);
	int src_rate = args.GetInt(2);
	Uint16 dst_format = args.GetUShort(3);
	Uint8 dst_channels = args.GetUChar(4);
	int dst_rate = args.GetInt(5);
	int rtn = ::SDL_BuildAudioCVT(cvt, src_format, src_channels, src_rate,
									dst_format, dst_channels, dst_rate);
	if (rtn < 0) return Value::Null;
	return Object_AudioCVT::CreateValue(cvt);
}

// sdl.LockAudio():void
AScript_DeclareFunction(LockAudio)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(LockAudio)
{
	::SDL_LockAudio();
	return Value::Null;
}

// sdl.UnlockAudio():void
AScript_DeclareFunction(UnlockAudio)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(UnlockAudio)
{
	::SDL_LockAudio();
	return Value::Null;
}

// sdl.CloseAudio():void
AScript_DeclareFunction(CloseAudio)
{
	SetMode(RSLTMODE_Void, FLAG_None);
}

AScript_ImplementFunction(CloseAudio)
{
	::SDL_LockAudio();
	return Value::Null;
}

//-----------------------------------------------------------------------------
// SDL functions: CD-ROM
//-----------------------------------------------------------------------------
// sdl.CDNumDrives()
AScript_DeclareFunction(CDNumDrives)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(CDNumDrives)
{
	return Value(::SDL_CDNumDrives());
}

// sdl.CDName(drive:number):map
AScript_DeclareFunction(CDName)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "drive", VTYPE_Number);
}

AScript_ImplementFunction(CDName)
{
	return Value(env, ::SDL_CDName(args.GetInt(0)));
}

// sdl.CDOpen(drive:number)
AScript_DeclareFunction(CDOpen)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "drive", VTYPE_Number);
}

AScript_ImplementFunction(CDOpen)
{
	SDL_CD *pCD = ::SDL_CDOpen(args.GetInt(0));
	if (pCD == NULL) {
		sig.SetError(ERR_IOError, "can't open CD drive #%d", args.GetInt(0));
		return Value::Null;
	}
	return Object_CD::CreateValue(pCD);
}

//-----------------------------------------------------------------------------
// SDL functions: Multi-threaded Programming
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// SDL functions: Time
//-----------------------------------------------------------------------------
// sdl.GetTicks()
AScript_DeclareFunction(GetTicks)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(GetTicks)
{
	return Value(::SDL_GetTicks());
}

// sdl.Delay(ms:number):void
AScript_DeclareFunction(Delay)
{
	SetMode(RSLTMODE_Void, FLAG_None);
	DeclareArg(env, "ms", VTYPE_Number);
}

AScript_ImplementFunction(Delay)
{
	::SDL_Delay(args.GetULong(0));
	return Value::Null;
}

// sdl.AddTimer(interval:number, callback?:function):[thread] {block?}
AScript_DeclareFunction(AddTimer)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "interval", VTYPE_Number);
	DeclareArg(env, "callback", VTYPE_Function, OCCUR_ZeroOrOnce);
	DeclareBlock(OCCUR_ZeroOrOnce);
	DeclareAttr(AScript_PrivSymbol(thread_));
}

AScript_ImplementFunction(AddTimer)
{
	Object_Function *pObjFunc;
	if (args.IsFunction(1)) {
		pObjFunc = Object_Function::Reference(args.GetFunctionObj(1));
	} else if (args.IsBlockSpecified()) {
		const Function *pFunc = args.GetBlockFunc(env, sig, GetSymbolForBlock());
		if (sig.IsSignalled()) return Value::Null;
		pObjFunc = new Object_Function(env, Function::Reference(pFunc), Value::Null);
	} else {
		sig.SetError(ERR_ValueError, "function or block must be specified");
		return Value::Null;
	}
	bool threadFlag = args.IsSet(AScript_PrivSymbol(thread_));
	Object_Timer *pObj = new Object_Timer(sig, pObjFunc, threadFlag);
	pObj->AddTimer(args.GetULong(0));
	return Value(pObj);
}

//-----------------------------------------------------------------------------
// Object constructors
//-----------------------------------------------------------------------------
// sdl.Rect(x:number, y:number, w:number, h:number):map
AScript_DeclareFunction(Rect)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "x", VTYPE_Number);
	DeclareArg(env, "y", VTYPE_Number);
	DeclareArg(env, "w", VTYPE_Number);
	DeclareArg(env, "h", VTYPE_Number);
}

AScript_ImplementFunction(Rect)
{
	SDL_Rect rect;
	rect.x = args.GetInt(0);
	rect.y = args.GetInt(1);
	rect.w = args.GetInt(2);
	rect.h = args.GetInt(3);
	return Object_Rect::CreateValue(rect);
}

// sdl.Color(r:number, g:number, b:number):map
AScript_DeclareFunction(Color)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "r", VTYPE_Number);
	DeclareArg(env, "g", VTYPE_Number);
	DeclareArg(env, "b", VTYPE_Number);
}

AScript_ImplementFunction(Color)
{
	SDL_Color color;
	color.r = args.GetUChar(0);
	color.g = args.GetUChar(1);
	color.b = args.GetUChar(2);
	color.unused = 0;
	return Object_Color::CreateValue(color);
}

// sdl.AudioSpec(freq:number, format:number,
//               channels:number, samples:number, callback?:function)
AScript_DeclareFunction(AudioSpec)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "freq",		VTYPE_Number, OCCUR_Once, false, false,
												new Expr_Value(22050));
	DeclareArg(env, "format",	VTYPE_Number, OCCUR_Once, false, false,
												new Expr_Value(AUDIO_S16));
	DeclareArg(env, "channels",	VTYPE_Number, OCCUR_Once, false, false,
												new Expr_Value(1));
	DeclareArg(env, "samples",	VTYPE_Number, OCCUR_Once, false, false,
												new Expr_Value(8192));
	DeclareArg(env, "callback",	VTYPE_Function, OCCUR_ZeroOrOnce);
	SetHelp(
	"It passes an audio object to the callback that is supposed to fill it\n"
	"with audio data.");
}

AScript_ImplementFunction(AudioSpec)
{
	SDL_AudioSpec *pAudioSpec =
			reinterpret_cast<SDL_AudioSpec *>(::malloc(sizeof(SDL_AudioSpec)));
	::memset(pAudioSpec, 0, sizeof(SDL_AudioSpec));
	pAudioSpec->freq		= args.GetInt(0);
	pAudioSpec->format		= args.GetUShort(1);
	pAudioSpec->channels	= args.GetUChar(2);
	pAudioSpec->samples		= args.GetUShort(3);
	pAudioSpec->callback	= Object_AudioSpec::CallbackStub;
	pAudioSpec->userdata	= NULL;
	Function *pFuncCallback = NULL;
	if (args.IsFunction(4)) {
		pFuncCallback = Function::Reference(args.GetFunction(4));
	}
	Object_AudioSpec *pObj =
			new Object_AudioSpec(pAudioSpec, &sig, pFuncCallback, NULL, 0);
	pAudioSpec->userdata = pObj;
	return Value(pObj);
}

//-----------------------------------------------------------------------------
// SDL functions: TTF
//-----------------------------------------------------------------------------
#if 0
// sdl.OpenFont(file:string, ptsize:number, index:number => 0)
AScript_DeclareFunction(OpenFont)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "file", VTYPE_String);
	DeclareArg(env, "ptsize", VTYPE_Number);
	DeclareArg(env, "index", VTYPE_Number, OCCUR_Once, false, false, new Expr_Value(0));
}

AScript_ImplementFunction(OpenFont)
{
	const char *file = args.GetString(0);
	TTF_Font *pFont = ::TTF_OpenFontIndex(file, args.GetInt(1), args.GetLong(2));
	if (pFont == NULL) {
		sig.SetError(ERR_IOError, "failed to open a font file %s", file);
		return Value::Null;
	}
	return Object_Font::CreateValue(pFont);
}
#endif

// sdl.test()
void callback(void *userdata, Uint8 *stream, int len)
{
	SDL_AudioSpec &specObtained = *reinterpret_cast<SDL_AudioSpec *>(userdata);
	Uint8 *p = stream;
	for (int i = 0; i < len / 2; i++, p += 2) {
		unsigned short num = static_cast<unsigned short>(
							::sin(6.28 * i * 400 / specObtained.freq) * 3000);
		*(p + 0) = static_cast<unsigned char>(num);
		*(p + 1) = static_cast<unsigned char>(num >> 8);
	}
}

AScript_DeclareFunction(test)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementFunction(test)
{
	SDL_AudioSpec specDesired;
	SDL_AudioSpec specObtained;
	specDesired.freq		= 22050;
	specDesired.format		= AUDIO_S16LSB;
	specDesired.channels	= 0;
	specDesired.samples		= 8192;
	specDesired.callback	= callback;
	specDesired.userdata	= &specObtained;
	::SDL_Init(SDL_INIT_AUDIO);
	::SDL_OpenAudio(&specDesired, &specObtained);
	::SDL_PauseAudio(0);
	//::SDL_Delay(1000);
	OAL::Sleep(1);
	::SDL_Quit();
	return Value::Null;
}

// Module entry
AScript_ModuleEntry()
{
	// symbols in SDL_Event
	AScript_RealizePrivSymbol(type);
	AScript_RealizePrivSymbol(gain);
	AScript_RealizePrivSymbol(state);
	AScript_RealizePrivSymbol(scancode);
	AScript_RealizePrivSymbol(sym);
	AScript_RealizePrivSymbol(mod);
	AScript_RealizePrivSymbol(unicode);
	AScript_RealizePrivSymbol(x);
	AScript_RealizePrivSymbol(y);
	AScript_RealizePrivSymbol(xrel);
	AScript_RealizePrivSymbol(yrel);
	AScript_RealizePrivSymbol(axis);
	AScript_RealizePrivSymbol(value);
	AScript_RealizePrivSymbol(button);
	AScript_RealizePrivSymbol(which);
	AScript_RealizePrivSymbol(hat);
	AScript_RealizePrivSymbol(ball);
	AScript_RealizePrivSymbol(w);
	AScript_RealizePrivSymbol(h);
	// symbols in SDL_Color
	AScript_RealizePrivSymbol(r)
	AScript_RealizePrivSymbol(g)
	AScript_RealizePrivSymbol(b)
	// symbols in SDL_PixelFormat
	AScript_RealizePrivSymbol(palette);
	AScript_RealizePrivSymbol(BitsPerPixel);
	AScript_RealizePrivSymbol(BytesPerPixel);
	AScript_RealizePrivSymbol(Rloss);
	AScript_RealizePrivSymbol(Gloss);
	AScript_RealizePrivSymbol(Bloss);
	AScript_RealizePrivSymbol(Aloss);
	AScript_RealizePrivSymbol(Rshift);
	AScript_RealizePrivSymbol(Gshift);
	AScript_RealizePrivSymbol(Bshift);
	AScript_RealizePrivSymbol(Ashift);
	AScript_RealizePrivSymbol(Rmask);
	AScript_RealizePrivSymbol(Gmask);
	AScript_RealizePrivSymbol(Bmask);
	AScript_RealizePrivSymbol(Amask);
	AScript_RealizePrivSymbol(colorkey);
	AScript_RealizePrivSymbol(alpha);
	// symbols in SDL_Surface
	AScript_RealizePrivSymbol(flags)
	AScript_RealizePrivSymbol(format)
	AScript_RealizePrivSymbol(pitch)
	AScript_RealizePrivSymbol(pixels)
	AScript_RealizePrivSymbol(clip_rect)
	AScript_RealizePrivSymbol(refcount)
	// symbols in SDL_VideoInfo
	AScript_RealizePrivSymbol(hw_available);
	AScript_RealizePrivSymbol(wm_available);
	AScript_RealizePrivSymbol(blit_hw);
	AScript_RealizePrivSymbol(blit_hw_CC);
	AScript_RealizePrivSymbol(blit_hw_A);
	AScript_RealizePrivSymbol(blit_sw);
	AScript_RealizePrivSymbol(blit_sw_CC);
	AScript_RealizePrivSymbol(blit_sw_A);
	AScript_RealizePrivSymbol(blit_fill);
	AScript_RealizePrivSymbol(video_mem);
	AScript_RealizePrivSymbol(vfmt);
	// symbols in SDL_CDtrack
	AScript_RealizePrivSymbol(id)
	AScript_RealizePrivSymbol(length)
	AScript_RealizePrivSymbol(offset)
	// symbols in SDL_CD
	AScript_RealizePrivSymbol(status)
	AScript_RealizePrivSymbol(numtracks)
	AScript_RealizePrivSymbol(cur_track)
	AScript_RealizePrivSymbol(cur_frame)
	// symbols for other purposes
	AScript_RealizePrivSymbolEx(thread_, "thread")
	// class realization
	AScript_RealizePrivClass(Cursor,		"Cursor", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Timer,			"Timer", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Event,			"Event", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Rect,			"Rect", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Color,			"Color", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Palette,		"Palette", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(PixelFormat,	"PixelFormat", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Surface,		"Surface", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Overlay,		"Overlay", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(VideoInfo,		"VideoInfo", env.LookupClass(VTYPE_Object));
	//AScript_RealizePrivClass(Font,			"Font", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(Joystick,		"Joystick", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(AudioSpec,		"AudioSpec", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(AudioCVT,		"AudioCVT", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(CDtrack,		"CDtrack", env.LookupClass(VTYPE_Object));
	AScript_RealizePrivClass(CD,			"CD", env.LookupClass(VTYPE_Object));
	// value assignment
	AScript_AssignValue(ACTIVEEVENT,		Value(SDL_ACTIVEEVENT));
	AScript_AssignValue(KEYDOWN,			Value(SDL_KEYDOWN));
	AScript_AssignValue(KEYUP,				Value(SDL_KEYUP));
	AScript_AssignValue(MOUSEMOTION,		Value(SDL_MOUSEMOTION));
	AScript_AssignValue(MOUSEBUTTONDOWN,	Value(SDL_MOUSEBUTTONDOWN));
	AScript_AssignValue(MOUSEBUTTONUP,		Value(SDL_MOUSEBUTTONUP));
	AScript_AssignValue(JOYAXISMOTION,		Value(SDL_JOYAXISMOTION));
	AScript_AssignValue(JOYBALLMOTION,		Value(SDL_JOYBALLMOTION));
	AScript_AssignValue(JOYHATMOTION,		Value(SDL_JOYHATMOTION));
	AScript_AssignValue(JOYBUTTONDOWN,		Value(SDL_JOYBUTTONDOWN));
	AScript_AssignValue(JOYBUTTONUP,		Value(SDL_JOYBUTTONUP));
	AScript_AssignValue(QUIT,				Value(SDL_QUIT));
	AScript_AssignValue(SYSWMEVENT,			Value(SDL_SYSWMEVENT));
	AScript_AssignValue(VIDEORESIZE,		Value(SDL_VIDEORESIZE));
	AScript_AssignValue(VIDEOEXPOSE,		Value(SDL_VIDEOEXPOSE));
	AScript_AssignValue(USEREVENT,			Value(SDL_USEREVENT));
	AScript_AssignValue(INIT_TIMER,			Value(SDL_INIT_TIMER));
	AScript_AssignValue(INIT_AUDIO,			Value(SDL_INIT_AUDIO));
	AScript_AssignValue(INIT_VIDEO,			Value(SDL_INIT_VIDEO));
	AScript_AssignValue(INIT_CDROM,			Value(SDL_INIT_CDROM));
	AScript_AssignValue(INIT_JOYSTICK,		Value(SDL_INIT_JOYSTICK));
	AScript_AssignValue(INIT_EVERYTHING,	Value(SDL_INIT_EVERYTHING));
	AScript_AssignValue(INIT_NOPARACHUTE,	Value(SDL_INIT_NOPARACHUTE));
	AScript_AssignValue(INIT_EVENTTHREAD,	Value(SDL_INIT_EVENTTHREAD));
	AScript_AssignValue(SWSURFACE,			Value(SDL_SWSURFACE));
	AScript_AssignValue(HWSURFACE,			Value(SDL_HWSURFACE));
	AScript_AssignValue(ASYNCBLIT,			Value(SDL_ASYNCBLIT));
	AScript_AssignValue(ANYFORMAT,			Value(SDL_ANYFORMAT));
	AScript_AssignValue(HWPALETTE,			Value(SDL_HWPALETTE));
	AScript_AssignValue(DOUBLEBUF,			Value(SDL_DOUBLEBUF));
	AScript_AssignValue(FULLSCREEN,			Value(SDL_FULLSCREEN));
	AScript_AssignValue(OPENGL,				Value(SDL_OPENGL));
	AScript_AssignValue(OPENGLBLIT,			Value(SDL_OPENGLBLIT));
	AScript_AssignValue(RESIZABLE,			Value(SDL_RESIZABLE));
	AScript_AssignValue(NOFRAME,			Value(SDL_NOFRAME));
	AScript_AssignValue(SRCCOLORKEY,		Value(SDL_SRCCOLORKEY));
	AScript_AssignValue(SRCALPHA,			Value(SDL_SRCALPHA));
	AScript_AssignValue(RLEACCEL,			Value(SDL_RLEACCEL));
	AScript_AssignValue(GRAB_QUERY,			Value(SDL_GRAB_QUERY));
	AScript_AssignValue(GRAB_OFF,			Value(SDL_GRAB_OFF));
	AScript_AssignValue(GRAB_ON,			Value(SDL_GRAB_ON));
	AScript_AssignValue(K_BACKSPACE,		Value(SDLK_BACKSPACE));
	AScript_AssignValue(K_TAB,				Value(SDLK_TAB));
	AScript_AssignValue(K_CLEAR,			Value(SDLK_CLEAR));
	AScript_AssignValue(K_RETURN,			Value(SDLK_RETURN));
	AScript_AssignValue(K_PAUSE,			Value(SDLK_PAUSE));
	AScript_AssignValue(K_ESCAPE,			Value(SDLK_ESCAPE));
	AScript_AssignValue(K_SPACE,			Value(SDLK_SPACE));
	AScript_AssignValue(K_EXCLAIM,			Value(SDLK_EXCLAIM));
	AScript_AssignValue(K_QUOTEDBL,			Value(SDLK_QUOTEDBL));
	AScript_AssignValue(K_HASH,				Value(SDLK_HASH));
	AScript_AssignValue(K_DOLLAR,			Value(SDLK_DOLLAR));
	AScript_AssignValue(K_AMPERSAND,		Value(SDLK_AMPERSAND));
	AScript_AssignValue(K_QUOTE,			Value(SDLK_QUOTE));
	AScript_AssignValue(K_LEFTPAREN,		Value(SDLK_LEFTPAREN));
	AScript_AssignValue(K_RIGHTPAREN,		Value(SDLK_RIGHTPAREN));
	AScript_AssignValue(K_ASTERISK,			Value(SDLK_ASTERISK));
	AScript_AssignValue(K_PLUS,				Value(SDLK_PLUS));
	AScript_AssignValue(K_COMMA,			Value(SDLK_COMMA));
	AScript_AssignValue(K_MINUS,			Value(SDLK_MINUS));
	AScript_AssignValue(K_PERIOD,			Value(SDLK_PERIOD));
	AScript_AssignValue(K_SLASH,			Value(SDLK_SLASH));
	AScript_AssignValue(K_0,				Value(SDLK_0));
	AScript_AssignValue(K_1,				Value(SDLK_1));
	AScript_AssignValue(K_2,				Value(SDLK_2));
	AScript_AssignValue(K_3,				Value(SDLK_3));
	AScript_AssignValue(K_4,				Value(SDLK_4));
	AScript_AssignValue(K_5,				Value(SDLK_5));
	AScript_AssignValue(K_6,				Value(SDLK_6));
	AScript_AssignValue(K_7,				Value(SDLK_7));
	AScript_AssignValue(K_8,				Value(SDLK_8));
	AScript_AssignValue(K_9,				Value(SDLK_9));
	AScript_AssignValue(K_COLON,			Value(SDLK_COLON));
	AScript_AssignValue(K_SEMICOLON,		Value(SDLK_SEMICOLON));
	AScript_AssignValue(K_LESS,				Value(SDLK_LESS));
	AScript_AssignValue(K_EQUALS,			Value(SDLK_EQUALS));
	AScript_AssignValue(K_GREATER,			Value(SDLK_GREATER));
	AScript_AssignValue(K_QUESTION,			Value(SDLK_QUESTION));
	AScript_AssignValue(K_AT,				Value(SDLK_AT));
	AScript_AssignValue(K_LEFTBRACKET,		Value(SDLK_LEFTBRACKET));
	AScript_AssignValue(K_BACKSLASH,		Value(SDLK_BACKSLASH));
	AScript_AssignValue(K_RIGHTBRACKET,		Value(SDLK_RIGHTBRACKET));
	AScript_AssignValue(K_CARET,			Value(SDLK_CARET));
	AScript_AssignValue(K_UNDERSCORE,		Value(SDLK_UNDERSCORE));
	AScript_AssignValue(K_BACKQUOTE,		Value(SDLK_BACKQUOTE));
	AScript_AssignValue(K_a,				Value(SDLK_a));
	AScript_AssignValue(K_b,				Value(SDLK_b));
	AScript_AssignValue(K_c,				Value(SDLK_c));
	AScript_AssignValue(K_d,				Value(SDLK_d));
	AScript_AssignValue(K_e,				Value(SDLK_e));
	AScript_AssignValue(K_f,				Value(SDLK_f));
	AScript_AssignValue(K_g,				Value(SDLK_g));
	AScript_AssignValue(K_h,				Value(SDLK_h));
	AScript_AssignValue(K_i,				Value(SDLK_i));
	AScript_AssignValue(K_j,				Value(SDLK_j));
	AScript_AssignValue(K_k,				Value(SDLK_k));
	AScript_AssignValue(K_l,				Value(SDLK_l));
	AScript_AssignValue(K_m,				Value(SDLK_m));
	AScript_AssignValue(K_n,				Value(SDLK_n));
	AScript_AssignValue(K_o,				Value(SDLK_o));
	AScript_AssignValue(K_p,				Value(SDLK_p));
	AScript_AssignValue(K_q,				Value(SDLK_q));
	AScript_AssignValue(K_r,				Value(SDLK_r));
	AScript_AssignValue(K_s,				Value(SDLK_s));
	AScript_AssignValue(K_t,				Value(SDLK_t));
	AScript_AssignValue(K_u,				Value(SDLK_u));
	AScript_AssignValue(K_v,				Value(SDLK_v));
	AScript_AssignValue(K_w,				Value(SDLK_w));
	AScript_AssignValue(K_x,				Value(SDLK_x));
	AScript_AssignValue(K_y,				Value(SDLK_y));
	AScript_AssignValue(K_z,				Value(SDLK_z));
	AScript_AssignValue(K_DELETE,				Value(SDLK_DELETE));
	AScript_AssignValue(K_KP0,				Value(SDLK_KP0));
	AScript_AssignValue(K_KP1,				Value(SDLK_KP1));
	AScript_AssignValue(K_KP2,				Value(SDLK_KP2));
	AScript_AssignValue(K_KP3,				Value(SDLK_KP3));
	AScript_AssignValue(K_KP4,				Value(SDLK_KP4));
	AScript_AssignValue(K_KP5,				Value(SDLK_KP5));
	AScript_AssignValue(K_KP6,				Value(SDLK_KP6));
	AScript_AssignValue(K_KP7,				Value(SDLK_KP7));
	AScript_AssignValue(K_KP8,				Value(SDLK_KP8));
	AScript_AssignValue(K_KP9,				Value(SDLK_KP9));
	AScript_AssignValue(K_KP_PERIOD,		Value(SDLK_KP_PERIOD));
	AScript_AssignValue(K_KP_DIVIDE,		Value(SDLK_KP_DIVIDE));
	AScript_AssignValue(K_KP_MULTIPLY,		Value(SDLK_KP_MULTIPLY));
	AScript_AssignValue(K_KP_MINUS,			Value(SDLK_KP_MINUS));
	AScript_AssignValue(K_KP_PLUS,			Value(SDLK_KP_PLUS));
	AScript_AssignValue(K_KP_ENTER,			Value(SDLK_KP_ENTER));
	AScript_AssignValue(K_KP_EQUALS,		Value(SDLK_KP_EQUALS));
	AScript_AssignValue(K_UP,				Value(SDLK_UP));
	AScript_AssignValue(K_DOWN,				Value(SDLK_DOWN));
	AScript_AssignValue(K_RIGHT,			Value(SDLK_RIGHT));
	AScript_AssignValue(K_LEFT,				Value(SDLK_LEFT));
	AScript_AssignValue(K_INSERT,			Value(SDLK_INSERT));
	AScript_AssignValue(K_HOME,				Value(SDLK_HOME));
	AScript_AssignValue(K_END,				Value(SDLK_END));
	AScript_AssignValue(K_PAGEUP,			Value(SDLK_PAGEUP));
	AScript_AssignValue(K_PAGEDOWN,			Value(SDLK_PAGEDOWN));
	AScript_AssignValue(K_F1,				Value(SDLK_F1));
	AScript_AssignValue(K_F2,				Value(SDLK_F2));
	AScript_AssignValue(K_F3,				Value(SDLK_F3));
	AScript_AssignValue(K_F4,				Value(SDLK_F4));
	AScript_AssignValue(K_F5,				Value(SDLK_F5));
	AScript_AssignValue(K_F6,				Value(SDLK_F6));
	AScript_AssignValue(K_F7,				Value(SDLK_F7));
	AScript_AssignValue(K_F8,				Value(SDLK_F8));
	AScript_AssignValue(K_F9,				Value(SDLK_F9));
	AScript_AssignValue(K_F10,				Value(SDLK_F10));
	AScript_AssignValue(K_F11,				Value(SDLK_F11));
	AScript_AssignValue(K_F12,				Value(SDLK_F12));
	AScript_AssignValue(K_F13,				Value(SDLK_F13));
	AScript_AssignValue(K_F14,				Value(SDLK_F14));
	AScript_AssignValue(K_F15,				Value(SDLK_F15));
	AScript_AssignValue(K_NUMLOCK,			Value(SDLK_NUMLOCK));
	AScript_AssignValue(K_CAPSLOCK,			Value(SDLK_CAPSLOCK));
	AScript_AssignValue(K_SCROLLOCK,		Value(SDLK_SCROLLOCK));
	AScript_AssignValue(K_RSHIFT,			Value(SDLK_RSHIFT));
	AScript_AssignValue(K_LSHIFT,			Value(SDLK_LSHIFT));
	AScript_AssignValue(K_RCTRL,			Value(SDLK_RCTRL));
	AScript_AssignValue(K_LCTRL,			Value(SDLK_LCTRL));
	AScript_AssignValue(K_RALT,				Value(SDLK_RALT));
	AScript_AssignValue(K_LALT,				Value(SDLK_LALT));
	AScript_AssignValue(K_RMETA,			Value(SDLK_RMETA));
	AScript_AssignValue(K_LMETA,			Value(SDLK_LMETA));
	AScript_AssignValue(K_LSUPER,			Value(SDLK_LSUPER));
	AScript_AssignValue(K_RSUPER,			Value(SDLK_RSUPER));
	AScript_AssignValue(K_MODE,				Value(SDLK_MODE));
	AScript_AssignValue(K_HELP,				Value(SDLK_HELP));
	AScript_AssignValue(K_PRINT,			Value(SDLK_PRINT));
	AScript_AssignValue(K_SYSREQ,			Value(SDLK_SYSREQ));
	AScript_AssignValue(K_BREAK,			Value(SDLK_BREAK));
	AScript_AssignValue(K_MENU,				Value(SDLK_MENU));
	AScript_AssignValue(K_POWER,			Value(SDLK_POWER));
	AScript_AssignValue(K_EURO,				Value(SDLK_EURO));
	AScript_AssignValue(KMOD_NONE,			Value(KMOD_NONE));
	AScript_AssignValue(KMOD_NUM,			Value(KMOD_NUM));
	AScript_AssignValue(KMOD_CAPS,			Value(KMOD_CAPS));
	AScript_AssignValue(KMOD_LCTRL,			Value(KMOD_LCTRL));
	AScript_AssignValue(KMOD_RCTRL,			Value(KMOD_RCTRL));
	AScript_AssignValue(KMOD_RSHIFT,		Value(KMOD_RSHIFT));
	AScript_AssignValue(KMOD_LSHIFT,		Value(KMOD_LSHIFT));
	AScript_AssignValue(KMOD_RALT,			Value(KMOD_RALT));
	AScript_AssignValue(KMOD_LALT,			Value(KMOD_LALT));
	AScript_AssignValue(KMOD_CTRL,			Value(KMOD_CTRL));
	AScript_AssignValue(KMOD_SHIFT,			Value(KMOD_SHIFT));
	AScript_AssignValue(KMOD_ALT,			Value(KMOD_ALT));
	AScript_AssignValue(APPMOUSEFOCUS,		Value(SDL_APPMOUSEFOCUS));
	AScript_AssignValue(APPINPUTFOCUS,		Value(SDL_APPINPUTFOCUS));
	AScript_AssignValue(APPACTIVE,			Value(SDL_APPACTIVE));
	AScript_AssignValue(QUERY,				Value(SDL_QUERY));
	AScript_AssignValue(ENABLE,				Value(SDL_ENABLE));
	AScript_AssignValue(IGNORE,				Value(SDL_IGNORE));
	AScript_AssignValue(AUDIO_STOPPED,		Value(SDL_AUDIO_STOPPED));
	AScript_AssignValue(AUDIO_PAUSED,		Value(SDL_AUDIO_PAUSED));
	AScript_AssignValue(AUDIO_PLAYING,		Value(SDL_AUDIO_PLAYING));
	AScript_AssignValue(AUDIO_U8,			Value(AUDIO_U8));
	AScript_AssignValue(AUDIO_S8,			Value(AUDIO_S8));
	AScript_AssignValue(AUDIO_U16,			Value(AUDIO_U16));
	AScript_AssignValue(AUDIO_U16LSB,		Value(AUDIO_U16LSB));
	AScript_AssignValue(AUDIO_S16,			Value(AUDIO_S16));
	AScript_AssignValue(AUDIO_S16LSB,		Value(AUDIO_S16LSB));
	AScript_AssignValue(AUDIO_U16MSB,		Value(AUDIO_U16MSB));
	AScript_AssignValue(AUDIO_S16MSB,		Value(AUDIO_S16MSB));
	AScript_AssignValue(AUDIO_U16SYS,		Value(AUDIO_U16SYS));
	AScript_AssignValue(AUDIO_S16SYS,		Value(AUDIO_S16SYS));
	AScript_AssignValue(CD_TRAYEMPTY,		Value(CD_TRAYEMPTY));
	AScript_AssignValue(CD_STOPPED,			Value(CD_STOPPED));
	AScript_AssignValue(CD_PLAYING,			Value(CD_PLAYING));
	AScript_AssignValue(CD_PAUSED,			Value(CD_PAUSED));
	AScript_AssignValue(CD_ERROR,			Value(CD_ERROR));
	// SDL GL Attributes
	AScript_AssignValue(GL_RED_SIZE,		Value(SDL_GL_RED_SIZE));
	AScript_AssignValue(GL_GREEN_SIZE,		Value(SDL_GL_GREEN_SIZE));
	AScript_AssignValue(GL_BLUE_SIZE,		Value(SDL_GL_BLUE_SIZE));
	AScript_AssignValue(GL_ALPHA_SIZE,		Value(SDL_GL_ALPHA_SIZE));
	AScript_AssignValue(GL_DOUBLEBUFFER,	Value(SDL_GL_DOUBLEBUFFER));
	AScript_AssignValue(GL_BUFFER_SIZE,		Value(SDL_GL_BUFFER_SIZE));
	AScript_AssignValue(GL_DEPTH_SIZE,		Value(SDL_GL_DEPTH_SIZE));
	AScript_AssignValue(GL_STENCIL_SIZE,	Value(SDL_GL_STENCIL_SIZE));
	AScript_AssignValue(GL_ACCUM_RED_SIZE,	Value(SDL_GL_ACCUM_RED_SIZE));
	AScript_AssignValue(GL_ACCUM_GREEN_SIZE,Value(SDL_GL_ACCUM_GREEN_SIZE));
	AScript_AssignValue(GL_ACCUM_BLUE_SIZE,	Value(SDL_GL_ACCUM_BLUE_SIZE));
	AScript_AssignValue(GL_ACCUM_ALPHA_SIZE,Value(SDL_GL_ACCUM_ALPHA_SIZE));
	// SDL functions: General
	AScript_AssignFunction(Init);
	AScript_AssignFunction(InitSubSystem);
	AScript_AssignFunction(QuitSubSystem);
	AScript_AssignFunction(Quit);
	AScript_AssignFunction(WasInit);
	AScript_AssignFunction(GetError);
	// SDL functions: Video
	AScript_AssignFunction(GetVideoSurface);
	AScript_AssignFunction(GetVideoInfo);
	AScript_AssignFunction(VideoDriverName);
	AScript_AssignFunction(ListModes);
	AScript_AssignFunction(VideoModeOK);
	AScript_AssignFunction(SetVideoMode);
	AScript_AssignFunction(SetGamma);
	AScript_AssignFunction(GetGammaRamp);
	AScript_AssignFunction(SetGammaRamp);
	AScript_AssignFunction(CreateRGBSurface);
	AScript_AssignFunction(CreateRGBSurfaceFrom);
	AScript_AssignFunction(LoadBMP);
	AScript_AssignFunction(LoadImage);
	AScript_AssignFunction(BlitSurface);
	AScript_AssignFunction(WarpMouse);
	AScript_AssignFunction(CreateCursor);
	AScript_AssignFunction(SetCursor);
	AScript_AssignFunction(GetCursor);
	AScript_AssignFunction(ShowCursor);
	AScript_AssignFunction(GL_GetAttribute);
	AScript_AssignFunction(GL_SetAttribute);
	AScript_AssignFunction(GL_SwapBuffers);
	AScript_AssignFunction(CreateYUVOverlay);
	// SDL functions: Window Management
	AScript_AssignFunction(WM_SetCaption);
	AScript_AssignFunction(WM_GetCaption);
	AScript_AssignFunction(WM_SetIcon);
	AScript_AssignFunction(WM_IconifyWindow);
	AScript_AssignFunction(WM_ToggleFullScreen);
	AScript_AssignFunction(WM_GrabInput);
	// SDL functions: Events
	AScript_AssignFunction(PumpEvents);
	AScript_AssignFunction(AddEvents);		// SDL_PeepEvents(SDL_ADDEVENT)
	AScript_AssignFunction(PeekEvents);		// SDL_PeepEvents(SDL_PEEKEVENT)
	AScript_AssignFunction(GetEvents);		// SDL_PeepEvents(SDL_GETEVENT)
	AScript_AssignFunction(PollEvent);
	AScript_AssignFunction(WaitEvent);
	AScript_AssignFunction(PushEvent);
	AScript_AssignFunction(SetEventFilter);
	AScript_AssignFunction(GetEventFilter);
	AScript_AssignFunction(EventState);
	AScript_AssignFunction(CheckKeyState);	// SDL_GetKeyState()
	AScript_AssignFunction(GetModState);
	AScript_AssignFunction(SetModState);
	AScript_AssignFunction(GetKeyName);
	AScript_AssignFunction(EnableUNICODE);
	AScript_AssignFunction(EnableKeyRepeat);
	AScript_AssignFunction(GetMouseState);
	AScript_AssignFunction(GetRelativeMouseState);
	AScript_AssignFunction(GetAppState);
	AScript_AssignFunction(JoystickEventState);
	// SDL functions: Joystick
	AScript_AssignFunction(NumJoysticks);
	AScript_AssignFunction(JoystickName);
	AScript_AssignFunction(JoystickOpen);
	AScript_AssignFunction(JoystickOpened);
	AScript_AssignFunction(JoystickUpdate);
	// SDL functions: Audio
	AScript_AssignFunction(OpenAudio);
	AScript_AssignFunction(PauseAudio);
	AScript_AssignFunction(GetAudioStatus);
	AScript_AssignFunction(LoadWAV);
	AScript_AssignFunction(BuildAudioCVT);
	AScript_AssignFunction(LockAudio);
	AScript_AssignFunction(UnlockAudio);
	AScript_AssignFunction(CloseAudio);
	// SDL functions: CD-ROM
	AScript_AssignFunction(CDNumDrives);
	AScript_AssignFunction(CDName);
	AScript_AssignFunction(CDOpen);
	// SDL functions: Multi-threaded Programming
	// SDL functions: Time
	AScript_AssignFunction(GetTicks);
	AScript_AssignFunction(Delay);
	AScript_AssignFunction(AddTimer);
	// SDL functions: TTF
	//AScript_AssignFunction(OpenFont);
	// Object constructors
	AScript_AssignFunction(Color);
	AScript_AssignFunction(Rect);
	AScript_AssignFunction(AudioSpec);
	AScript_AssignFunctionEx(BuildAudioCVT, "AudioCVT");
	// test function
	AScript_AssignFunction(test);
}

AScript_ModuleTerminate()
{
}

const char *GetEventTypeName(Uint8 type)
{
	static const struct {
		Uint8 type;
		const char *name;
	} tbl[] = {
		{ SDL_ACTIVEEVENT,		"ActiveEvent",		},
		{ SDL_KEYDOWN,			"KeyDown",			},
		{ SDL_KEYUP,			"KeyUp",			},
		{ SDL_MOUSEMOTION,		"MouseMotion",		},
		{ SDL_MOUSEBUTTONDOWN,	"MouseButtonDown",	},
		{ SDL_MOUSEBUTTONUP,	"MouseButtonUp",	},
		{ SDL_JOYAXISMOTION,	"JoyAxisMotion",	},
		{ SDL_JOYBALLMOTION,	"JoyBallMotion",	},
		{ SDL_JOYHATMOTION,		"JoyHatMotion",		},
		{ SDL_JOYBUTTONDOWN,	"JoyButtonDown",	},
		{ SDL_JOYBUTTONUP,		"JoyButtonUp",		},
		{ SDL_QUIT,				"Quit",				},
		{ SDL_SYSWMEVENT,		"SysWMEvent",		},
		{ SDL_VIDEORESIZE,		"VideoResize",		},
		{ SDL_VIDEOEXPOSE,		"VideoExpose",		},
		{ SDL_USEREVENT,		"UserEvent",		},
	};
	for (int i = 0; i < NUMBEROF(tbl); i++) {
		if (tbl[i].type == type) return tbl[i].name;
	}
	return "(unknown)";
}

AScript_EndModule(sdl, sdl)

AScript_RegisterModule(sdl)
