Merge branch 'master' of /home/Ancurio/programming/C++/mkxp
This commit is contained in:
		
						commit
						d9f13c39e9
					
				
					 38 changed files with 792 additions and 686 deletions
				
			
		| 
						 | 
				
			
			@ -20,6 +20,8 @@ Matz's Ruby Interpreter, also called CRuby, is the most widely deployed version
 | 
			
		|||
For a list of differences, see:
 | 
			
		||||
http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9
 | 
			
		||||
 | 
			
		||||
This binding supports RGSS1, RGSS2 and RGSS3.
 | 
			
		||||
 | 
			
		||||
### mruby (Lightweight Ruby)
 | 
			
		||||
Website: https://github.com/mruby/mruby
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +31,8 @@ Due to heavy differences between mruby and MRI as well as lacking modules, runni
 | 
			
		|||
 | 
			
		||||
Some extensions to the standard classes/modules are provided, taking the RPG Maker XP helpfile as a quasi "reference". These include Marshal, File, FileTest and Time.
 | 
			
		||||
 | 
			
		||||
This binding only supports RGSS1.
 | 
			
		||||
 | 
			
		||||
**Important:** If you decide to use [mattn's oniguruma regexp gem](https://github.com/mattn/mruby-onig-regexp), don't forget to add `-lonig` to the linker flags to avoid ugly symbol overlaps with libc.
 | 
			
		||||
 | 
			
		||||
### null
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ fileIntForPath(const char *path, bool rubyExc)
 | 
			
		|||
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		shState->fileSystem().openRead(*ops, path);
 | 
			
		||||
		shState->fileSystem().openReadRaw(*ops, path);
 | 
			
		||||
	}
 | 
			
		||||
	catch (const Exception &e)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,29 @@
 | 
			
		|||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
collectStrings(VALUE obj, std::vector<std::string> &out)
 | 
			
		||||
{
 | 
			
		||||
	if (RB_TYPE_P(obj, RUBY_T_STRING))
 | 
			
		||||
	{
 | 
			
		||||
		out.push_back(RSTRING_PTR(obj));
 | 
			
		||||
	}
 | 
			
		||||
	else if (RB_TYPE_P(obj, RUBY_T_ARRAY))
 | 
			
		||||
	{
 | 
			
		||||
		for (long i = 0; i < RARRAY_LEN(obj); ++i)
 | 
			
		||||
		{
 | 
			
		||||
			VALUE str = rb_ary_entry(obj, i);
 | 
			
		||||
 | 
			
		||||
			/* Non-string objects are tolerated (ignored) */
 | 
			
		||||
			if (!RB_TYPE_P(str, RUBY_T_STRING))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			out.push_back(RSTRING_PTR(str));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEF_TYPE(Font);
 | 
			
		||||
 | 
			
		||||
RB_METHOD(fontDoesExist)
 | 
			
		||||
| 
						 | 
				
			
			@ -48,12 +71,30 @@ RB_METHOD(FontSetName);
 | 
			
		|||
 | 
			
		||||
RB_METHOD(fontInitialize)
 | 
			
		||||
{
 | 
			
		||||
	VALUE name = Qnil;
 | 
			
		||||
	VALUE namesObj = Qnil;
 | 
			
		||||
	int size = 0;
 | 
			
		||||
 | 
			
		||||
	rb_get_args(argc, argv, "|oi", &name, &size RB_ARG_END);
 | 
			
		||||
	rb_get_args(argc, argv, "|oi", &namesObj, &size RB_ARG_END);
 | 
			
		||||
 | 
			
		||||
	Font *f = new Font(0, size);
 | 
			
		||||
	Font *f;
 | 
			
		||||
 | 
			
		||||
	if (NIL_P(namesObj))
 | 
			
		||||
	{
 | 
			
		||||
		namesObj = rb_iv_get(rb_obj_class(self), "default_name");
 | 
			
		||||
		f = new Font(0, size);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		std::vector<std::string> names;
 | 
			
		||||
		collectStrings(namesObj, names);
 | 
			
		||||
 | 
			
		||||
		f = new Font(&names, size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* This is semantically wrong; the new Font object should take
 | 
			
		||||
	 * a dup'ed object here in case of an array. Ditto for the setters.
 | 
			
		||||
	 * However the same bug/behavior exists in all RM versions. */
 | 
			
		||||
	rb_iv_set(self, "name", namesObj);
 | 
			
		||||
 | 
			
		||||
	setPrivateData(self, f);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,13 +106,6 @@ RB_METHOD(fontInitialize)
 | 
			
		|||
	if (rgssVer >= 3)
 | 
			
		||||
		wrapProperty(self, &f->getOutColor(), "out_color", ColorType);
 | 
			
		||||
 | 
			
		||||
	if (NIL_P(name))
 | 
			
		||||
		name = rb_iv_get(rb_obj_class(self), "default_name");
 | 
			
		||||
 | 
			
		||||
	/* Going over the 'name=' function automatically causes
 | 
			
		||||
	 * a possbile name array to be re-verified for existing fonts */
 | 
			
		||||
	FontSetName(1, &name, self);
 | 
			
		||||
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,57 +139,17 @@ RB_METHOD(FontGetName)
 | 
			
		|||
	return rb_iv_get(self, "name");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fontSetNameHelper(VALUE self, int argc, VALUE *argv,
 | 
			
		||||
                  const char *nameIv, char *outBuf, size_t outLen)
 | 
			
		||||
{
 | 
			
		||||
	rb_check_argc(argc, 1);
 | 
			
		||||
 | 
			
		||||
	VALUE arg = argv[0];
 | 
			
		||||
 | 
			
		||||
	// Fixme: in RGSS3, specifying "" (and only that) as font name results in
 | 
			
		||||
	// no text being drawn (everything else is substituted with Arial I think)
 | 
			
		||||
	strncpy(outBuf, "", outLen);
 | 
			
		||||
 | 
			
		||||
	if (RB_TYPE_P(arg, RUBY_T_STRING))
 | 
			
		||||
	{
 | 
			
		||||
		strncpy(outBuf, RSTRING_PTR(arg), outLen);
 | 
			
		||||
	}
 | 
			
		||||
	else if (RB_TYPE_P(arg, RUBY_T_ARRAY))
 | 
			
		||||
	{
 | 
			
		||||
		for (long i = 0; i < RARRAY_LEN(arg); ++i)
 | 
			
		||||
		{
 | 
			
		||||
			VALUE str = rb_ary_entry(arg, i);
 | 
			
		||||
 | 
			
		||||
			/* Non-string objects are tolerated (ignored) */
 | 
			
		||||
			if (!RB_TYPE_P(str, RUBY_T_STRING))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			const char *family = RSTRING_PTR(str);
 | 
			
		||||
 | 
			
		||||
			/* We only set the core Font object's name attribute
 | 
			
		||||
			 * to the actually existing font name */
 | 
			
		||||
			if (!shState->fontState().fontPresent(family))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			strncpy(outBuf, family, outLen);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* RMXP doesn't even care if the argument type is
 | 
			
		||||
	 * something other than string/array. Whatever... */
 | 
			
		||||
	rb_iv_set(self, nameIv, arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RB_METHOD(FontSetName)
 | 
			
		||||
{
 | 
			
		||||
	Font *f = getPrivateData<Font>(self);
 | 
			
		||||
 | 
			
		||||
	char result[256];
 | 
			
		||||
	fontSetNameHelper(self, argc, argv, "name",
 | 
			
		||||
	                  result, sizeof(result));
 | 
			
		||||
	rb_check_argc(argc, 1);
 | 
			
		||||
 | 
			
		||||
	f->setName(result);
 | 
			
		||||
	std::vector<std::string> namesObj;
 | 
			
		||||
	collectStrings(argv[0], namesObj);
 | 
			
		||||
 | 
			
		||||
	f->setName(namesObj);
 | 
			
		||||
	rb_iv_set(self, "name", argv[0]);
 | 
			
		||||
 | 
			
		||||
	return argv[0];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -223,11 +217,15 @@ RB_METHOD(FontGetDefaultName)
 | 
			
		|||
 | 
			
		||||
RB_METHOD(FontSetDefaultName)
 | 
			
		||||
{
 | 
			
		||||
	char result[256];
 | 
			
		||||
	fontSetNameHelper(self, argc, argv, "default_name",
 | 
			
		||||
	                  result, sizeof(result));
 | 
			
		||||
	RB_UNUSED_PARAM;
 | 
			
		||||
 | 
			
		||||
	Font::setDefaultName(result);
 | 
			
		||||
	rb_check_argc(argc, 1);
 | 
			
		||||
 | 
			
		||||
	std::vector<std::string> namesObj;
 | 
			
		||||
	collectStrings(argv[0], namesObj);
 | 
			
		||||
 | 
			
		||||
	Font::setDefaultName(namesObj, shState->fontState());
 | 
			
		||||
	rb_iv_set(self, "default_name", argv[0]);
 | 
			
		||||
 | 
			
		||||
	return argv[0];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -267,7 +265,24 @@ fontBindingInit()
 | 
			
		|||
 | 
			
		||||
	Font::initDefaultDynAttribs();
 | 
			
		||||
	wrapProperty(klass, &Font::getDefaultColor(), "default_color", ColorType);
 | 
			
		||||
	rb_iv_set(klass, "default_name", rb_str_new_cstr(Font::getDefaultName()));
 | 
			
		||||
 | 
			
		||||
	/* Initialize default names */
 | 
			
		||||
	const std::vector<std::string> &defNames = Font::getInitialDefaultNames();
 | 
			
		||||
	VALUE defNamesObj;
 | 
			
		||||
 | 
			
		||||
	if (defNames.size() == 1)
 | 
			
		||||
	{
 | 
			
		||||
		defNamesObj = rb_str_new_cstr(defNames[0].c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		defNamesObj = rb_ary_new2(defNames.size());
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < defNames.size(); ++i)
 | 
			
		||||
			rb_ary_push(defNamesObj, rb_str_new_cstr(defNames[i].c_str()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rb_iv_set(klass, "default_name", defNamesObj);
 | 
			
		||||
 | 
			
		||||
	if (rgssVer >= 3)
 | 
			
		||||
		wrapProperty(klass, &Font::getDefaultOutColor(), "default_out_color", ColorType);
 | 
			
		||||
| 
						 | 
				
			
			@ -310,14 +325,4 @@ fontBindingInit()
 | 
			
		|||
	INIT_PROP_BIND(Font, Outline, "outline");
 | 
			
		||||
	INIT_PROP_BIND(Font, OutColor, "out_color");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rgssVer >= 2)
 | 
			
		||||
	{
 | 
			
		||||
		VALUE defNames = rb_ary_new2(3);
 | 
			
		||||
		rb_ary_push(defNames, rb_str_new2("Verdana"));
 | 
			
		||||
		rb_ary_push(defNames, rb_str_new2("Arial"));
 | 
			
		||||
		rb_ary_push(defNames, rb_str_new2("Courier New"));
 | 
			
		||||
 | 
			
		||||
		FontSetDefaultName(1, &defNames, klass);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,6 +183,18 @@ RB_METHOD(graphicsReset)
 | 
			
		|||
	return Qnil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RB_METHOD(graphicsPlayMovie)
 | 
			
		||||
{
 | 
			
		||||
	RB_UNUSED_PARAM;
 | 
			
		||||
 | 
			
		||||
	const char *filename;
 | 
			
		||||
	rb_get_args(argc, argv, "z", &filename RB_ARG_END);
 | 
			
		||||
 | 
			
		||||
	shState->graphics().playMovie(filename);
 | 
			
		||||
 | 
			
		||||
	return Qnil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEF_GRA_PROP_I(FrameRate)
 | 
			
		||||
DEF_GRA_PROP_I(FrameCount)
 | 
			
		||||
DEF_GRA_PROP_I(Brightness)
 | 
			
		||||
| 
						 | 
				
			
			@ -223,6 +235,11 @@ void graphicsBindingInit()
 | 
			
		|||
	INIT_GRA_PROP_BIND( Brightness, "brightness" );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rgssVer >= 3)
 | 
			
		||||
	{
 | 
			
		||||
	_rb_define_module_function(module, "play_movie", graphicsPlayMovie);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INIT_GRA_PROP_BIND( Fullscreen, "fullscreen"  );
 | 
			
		||||
	INIT_GRA_PROP_BIND( ShowCursor, "show_cursor" );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,7 @@ DEF_PROP_I(Sprite, Y)
 | 
			
		|||
DEF_PROP_I(Sprite, OX)
 | 
			
		||||
DEF_PROP_I(Sprite, OY)
 | 
			
		||||
DEF_PROP_I(Sprite, BushDepth)
 | 
			
		||||
DEF_PROP_I(Sprite, BushOpacity)
 | 
			
		||||
DEF_PROP_I(Sprite, Opacity)
 | 
			
		||||
DEF_PROP_I(Sprite, BlendType)
 | 
			
		||||
DEF_PROP_I(Sprite, WaveAmp)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +127,8 @@ spriteBindingInit()
 | 
			
		|||
	_rb_define_method(klass, "width", spriteWidth);
 | 
			
		||||
	_rb_define_method(klass, "height", spriteHeight);
 | 
			
		||||
 | 
			
		||||
	INIT_PROP_BIND( Sprite, BushOpacity, "bush_opacity" );
 | 
			
		||||
 | 
			
		||||
	INIT_PROP_BIND( Sprite, WaveAmp,    "wave_amp"    );
 | 
			
		||||
	INIT_PROP_BIND( Sprite, WaveLength, "wave_length" );
 | 
			
		||||
	INIT_PROP_BIND( Sprite, WaveSpeed,  "wave_speed"  );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -266,7 +266,7 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
 | 
			
		|||
	mrb_state *scriptMrb = mrb_open();
 | 
			
		||||
	SDL_RWops ops;
 | 
			
		||||
 | 
			
		||||
	shState->fileSystem().openRead(ops, scriptPack.c_str());
 | 
			
		||||
	shState->fileSystem().openReadRaw(ops, scriptPack.c_str());
 | 
			
		||||
 | 
			
		||||
	mrb_value scriptArray = mrb_nil_value();
 | 
			
		||||
	std::string readError;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,9 +57,9 @@
 | 
			
		|||
 | 
			
		||||
# Apply linear interpolation when game screen
 | 
			
		||||
# is upscaled
 | 
			
		||||
# (default: disabled)
 | 
			
		||||
# (default: enabled)
 | 
			
		||||
#
 | 
			
		||||
# smoothScaling=false
 | 
			
		||||
# smoothScaling=true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Sync screen redraws to the monitor refresh rate
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -238,6 +238,6 @@ inline ALenum chooseALFormat(int sampleSize, int channelCount)
 | 
			
		|||
 | 
			
		||||
#define AUDIO_SLEEP 10
 | 
			
		||||
#define STREAM_BUF_SIZE 32768
 | 
			
		||||
#define GLOBAL_VOLUME 0.8
 | 
			
		||||
#define GLOBAL_VOLUME 0.8f
 | 
			
		||||
 | 
			
		||||
#endif // ALUTIL_H
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										100
									
								
								src/alstream.cpp
									
										
									
									
									
								
							
							
						
						
									
										100
									
								
								src/alstream.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -42,12 +42,12 @@ ALStream::ALStream(LoopMode loopMode,
 | 
			
		|||
	  source(0),
 | 
			
		||||
	  thread(0),
 | 
			
		||||
	  preemptPause(false),
 | 
			
		||||
      pitch(1.0)
 | 
			
		||||
      pitch(1.0f)
 | 
			
		||||
{
 | 
			
		||||
	alSrc = AL::Source::gen();
 | 
			
		||||
 | 
			
		||||
	AL::Source::setVolume(alSrc, 1.0);
 | 
			
		||||
	AL::Source::setPitch(alSrc, 1.0);
 | 
			
		||||
	AL::Source::setVolume(alSrc, 1.0f);
 | 
			
		||||
	AL::Source::setPitch(alSrc, 1.0f);
 | 
			
		||||
	AL::Source::detachBuffer(alSrc);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < STREAM_BUFS; ++i)
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +172,7 @@ void ALStream::setPitch(float value)
 | 
			
		|||
	/* If the source supports setting pitch natively,
 | 
			
		||||
	 * we don't have to do it via OpenAL */
 | 
			
		||||
	if (source && source->setPitch(value))
 | 
			
		||||
		AL::Source::setPitch(alSrc, 1.0);
 | 
			
		||||
		AL::Source::setPitch(alSrc, 1.0f);
 | 
			
		||||
	else
 | 
			
		||||
		AL::Source::setPitch(alSrc, value);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -199,43 +199,73 @@ void ALStream::closeSource()
 | 
			
		|||
	delete source;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ALStreamOpenHandler : FileSystem::OpenHandler
 | 
			
		||||
{
 | 
			
		||||
	SDL_RWops *srcOps;
 | 
			
		||||
	bool looped;
 | 
			
		||||
	ALDataSource *source;
 | 
			
		||||
	std::string errorMsg;
 | 
			
		||||
 | 
			
		||||
	ALStreamOpenHandler(SDL_RWops &srcOps, bool looped)
 | 
			
		||||
	    : srcOps(&srcOps), looped(looped), source(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool tryRead(SDL_RWops &ops, const char *ext)
 | 
			
		||||
	{
 | 
			
		||||
		/* Copy this because we need to keep it around,
 | 
			
		||||
		 * as we will continue reading data from it later */
 | 
			
		||||
		*srcOps = ops;
 | 
			
		||||
 | 
			
		||||
		/* Try to read ogg file signature */
 | 
			
		||||
		char sig[5] = { 0 };
 | 
			
		||||
		SDL_RWread(srcOps, sig, 1, 4);
 | 
			
		||||
		SDL_RWseek(srcOps, 0, RW_SEEK_SET);
 | 
			
		||||
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			if (!strcmp(sig, "OggS"))
 | 
			
		||||
			{
 | 
			
		||||
				source = createVorbisSource(*srcOps, looped);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!strcmp(sig, "MThd"))
 | 
			
		||||
			{
 | 
			
		||||
				shState->midiState().initIfNeeded(shState->config());
 | 
			
		||||
 | 
			
		||||
				if (HAVE_FLUID)
 | 
			
		||||
				{
 | 
			
		||||
					source = createMidiSource(*srcOps, looped);
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			source = createSDLSource(*srcOps, ext, STREAM_BUF_SIZE, looped);
 | 
			
		||||
		}
 | 
			
		||||
		catch (const Exception &e)
 | 
			
		||||
		{
 | 
			
		||||
			/* All source constructors will close the passed ops
 | 
			
		||||
			 * before throwing errors */
 | 
			
		||||
			errorMsg = e.msg;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ALStream::openSource(const std::string &filename)
 | 
			
		||||
{
 | 
			
		||||
	char ext[8];
 | 
			
		||||
	shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext));
 | 
			
		||||
	ALStreamOpenHandler handler(srcOps, looped);
 | 
			
		||||
	shState->fileSystem().openRead(handler, filename.c_str());
 | 
			
		||||
	source = handler.source;
 | 
			
		||||
	needsRewind.clear();
 | 
			
		||||
 | 
			
		||||
	/* Try to read ogg file signature */
 | 
			
		||||
	char sig[5] = { 0 };
 | 
			
		||||
	SDL_RWread(&srcOps, sig, 1, 4);
 | 
			
		||||
	SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
 | 
			
		||||
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		if (!strcmp(sig, "OggS"))
 | 
			
		||||
		{
 | 
			
		||||
			source = createVorbisSource(srcOps, looped);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!strcmp(sig, "MThd"))
 | 
			
		||||
		{
 | 
			
		||||
			shState->midiState().initIfNeeded(shState->config());
 | 
			
		||||
 | 
			
		||||
			if (HAVE_FLUID)
 | 
			
		||||
			{
 | 
			
		||||
				source = createMidiSource(srcOps, looped);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped);
 | 
			
		||||
	}
 | 
			
		||||
	catch (const Exception &e)
 | 
			
		||||
	if (!source)
 | 
			
		||||
	{
 | 
			
		||||
		char buf[512];
 | 
			
		||||
		snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s.%s: %s",
 | 
			
		||||
		         filename.c_str(), ext, e.msg.c_str());
 | 
			
		||||
		snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s: %s",
 | 
			
		||||
		         filename.c_str(), handler.errorMsg.c_str());
 | 
			
		||||
 | 
			
		||||
		Debug() << buf;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ struct AudioPrivate
 | 
			
		|||
					else
 | 
			
		||||
					{
 | 
			
		||||
						/* BGM is stopped. -> MeNotPlaying */
 | 
			
		||||
						bgm.setVolume(AudioStream::External, 1.0);
 | 
			
		||||
						bgm.setVolume(AudioStream::External, 1.0f);
 | 
			
		||||
 | 
			
		||||
						if (!bgm.noResumeStop)
 | 
			
		||||
							bgm.stream.play();
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +193,7 @@ struct AudioPrivate
 | 
			
		|||
				if (bgm.stream.queryState() == ALStream::Stopped)
 | 
			
		||||
				{
 | 
			
		||||
					/* BGM stopped midway fade in. -> MeNotPlaying */
 | 
			
		||||
					bgm.setVolume(AudioStream::External, 1.0);
 | 
			
		||||
					bgm.setVolume(AudioStream::External, 1.0f);
 | 
			
		||||
					meWatch.state = MeNotPlaying;
 | 
			
		||||
					bgm.unlockStream();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +219,7 @@ struct AudioPrivate
 | 
			
		|||
				if (vol >= 1)
 | 
			
		||||
				{
 | 
			
		||||
					/* BGM fully faded in. -> MeNotPlaying */
 | 
			
		||||
					vol = 1.0;
 | 
			
		||||
					vol = 1.0f;
 | 
			
		||||
					meWatch.state = MeNotPlaying;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,11 +34,11 @@ AudioStream::AudioStream(ALStream::LoopMode loopMode,
 | 
			
		|||
	  noResumeStop(false),
 | 
			
		||||
	  stream(loopMode, threadId)
 | 
			
		||||
{
 | 
			
		||||
	current.volume = 1.0;
 | 
			
		||||
	current.pitch = 1.0;
 | 
			
		||||
	current.volume = 1.0f;
 | 
			
		||||
	current.pitch = 1.0f;
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < VolumeTypeCount; ++i)
 | 
			
		||||
		volumes[i] = 1.0;
 | 
			
		||||
		volumes[i] = 1.0f;
 | 
			
		||||
 | 
			
		||||
	fade.thread = 0;
 | 
			
		||||
	fade.threadName = std::string("audio_fadeout (") + threadId + ")";
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +82,8 @@ void AudioStream::play(const std::string &filename,
 | 
			
		|||
 | 
			
		||||
	lockStream();
 | 
			
		||||
 | 
			
		||||
	float _volume = clamp<int>(volume, 0, 100) / 100.f;
 | 
			
		||||
	float _pitch  = clamp<int>(pitch, 50, 150) / 100.f;
 | 
			
		||||
	float _volume = clamp<int>(volume, 0, 100) / 100.0f;
 | 
			
		||||
	float _pitch  = clamp<int>(pitch, 50, 150) / 100.0f;
 | 
			
		||||
 | 
			
		||||
	ALStream::State sState = stream.queryState();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +211,7 @@ void AudioStream::fadeOut(int duration)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	fade.active.set();
 | 
			
		||||
	fade.msStep = (1.0) / duration;
 | 
			
		||||
	fade.msStep = 1.0f / duration;
 | 
			
		||||
	fade.reqFini.clear();
 | 
			
		||||
	fade.reqTerm.clear();
 | 
			
		||||
	fade.startTicks = SDL_GetTicks();
 | 
			
		||||
| 
						 | 
				
			
			@ -302,7 +302,7 @@ void AudioStream::fadeOutThread()
 | 
			
		|||
		lockStream();
 | 
			
		||||
 | 
			
		||||
		uint32_t curDur = SDL_GetTicks() - fade.startTicks;
 | 
			
		||||
		float resVol = 1.0 - (curDur*fade.msStep);
 | 
			
		||||
		float resVol = 1.0f - (curDur*fade.msStep);
 | 
			
		||||
 | 
			
		||||
		ALStream::State state = stream.queryState();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -313,7 +313,7 @@ void AudioStream::fadeOutThread()
 | 
			
		|||
			if (state != ALStream::Paused)
 | 
			
		||||
				stream.stop();
 | 
			
		||||
 | 
			
		||||
			setVolume(FadeOut, 1.0);
 | 
			
		||||
			setVolume(FadeOut, 1.0f);
 | 
			
		||||
			unlockStream();
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -340,15 +340,15 @@ void AudioStream::fadeInThread()
 | 
			
		|||
 | 
			
		||||
		/* Fade in duration is always 1 second */
 | 
			
		||||
		uint32_t cur = SDL_GetTicks() - fadeIn.startTicks;
 | 
			
		||||
		float prog = cur / 1000.0;
 | 
			
		||||
		float prog = cur / 1000.0f;
 | 
			
		||||
 | 
			
		||||
		ALStream::State state = stream.queryState();
 | 
			
		||||
 | 
			
		||||
		if (state != ALStream::Playing
 | 
			
		||||
		||  prog >= 1.0
 | 
			
		||||
		||  prog >= 1.0f
 | 
			
		||||
		||  fadeIn.rqFini)
 | 
			
		||||
		{
 | 
			
		||||
			setVolume(FadeIn, 1.0);
 | 
			
		||||
			setVolume(FadeIn, 1.0f);
 | 
			
		||||
			unlockStream();
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -247,13 +247,26 @@ struct BitmapPrivate
 | 
			
		|||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct BitmapOpenHandler : FileSystem::OpenHandler
 | 
			
		||||
{
 | 
			
		||||
	SDL_Surface *surf;
 | 
			
		||||
 | 
			
		||||
	BitmapOpenHandler()
 | 
			
		||||
	    : surf(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool tryRead(SDL_RWops &ops, const char *ext)
 | 
			
		||||
	{
 | 
			
		||||
		surf = IMG_LoadTyped_RW(&ops, 1, ext);
 | 
			
		||||
		return surf != 0;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Bitmap::Bitmap(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	SDL_RWops ops;
 | 
			
		||||
	char ext[8];
 | 
			
		||||
 | 
			
		||||
	shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext));
 | 
			
		||||
	SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext);
 | 
			
		||||
	BitmapOpenHandler handler;
 | 
			
		||||
	shState->fileSystem().openRead(handler, filename);
 | 
			
		||||
	SDL_Surface *imgSurf = handler.surf;
 | 
			
		||||
 | 
			
		||||
	if (!imgSurf)
 | 
			
		||||
		throw Exception(Exception::SDLError, "Error loading image '%s': %s",
 | 
			
		||||
| 
						 | 
				
			
			@ -992,9 +1005,9 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
 | 
			
		|||
	SDL_Surface *out = SDL_CreateRGBSurface
 | 
			
		||||
		(0, in->w+1, in->h+1, fm.BitsPerPixel, fm.Rmask, fm.Gmask, fm.Bmask, fm.Amask);
 | 
			
		||||
 | 
			
		||||
	float fr = c.r / 255.0;
 | 
			
		||||
	float fg = c.g / 255.0;
 | 
			
		||||
	float fb = c.b / 255.0;
 | 
			
		||||
	float fr = c.r / 255.0f;
 | 
			
		||||
	float fg = c.g / 255.0f;
 | 
			
		||||
	float fb = c.b / 255.0f;
 | 
			
		||||
 | 
			
		||||
	/* We allocate an output surface one pixel wider and higher than the input,
 | 
			
		||||
	 * (implicitly) blit a copy of the input with RGB values set to black into
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,11 +1061,11 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
 | 
			
		|||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			float fSrcA = srcA / 255.0;
 | 
			
		||||
			float fShdA = shdA / 255.0;
 | 
			
		||||
			float fSrcA = srcA / 255.0f;
 | 
			
		||||
			float fShdA = shdA / 255.0f;
 | 
			
		||||
 | 
			
		||||
			/* Because opacity == 1, co1 == fSrcA */
 | 
			
		||||
			float co2 = fShdA * (1.0 - fSrcA);
 | 
			
		||||
			float co2 = fShdA * (1.0f - fSrcA);
 | 
			
		||||
			/* Result alpha */
 | 
			
		||||
			float fa = fSrcA + co2;
 | 
			
		||||
			/* Temp value to simplify arithmetic below */
 | 
			
		||||
| 
						 | 
				
			
			@ -1061,10 +1074,10 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
 | 
			
		|||
			/* Result colors */
 | 
			
		||||
			uint8_t r, g, b, a;
 | 
			
		||||
 | 
			
		||||
			r = clamp<float>(fr * co3, 0, 1) * 255;
 | 
			
		||||
			g = clamp<float>(fg * co3, 0, 1) * 255;
 | 
			
		||||
			b = clamp<float>(fb * co3, 0, 1) * 255;
 | 
			
		||||
			a = clamp<float>(fa, 0, 1) * 255;
 | 
			
		||||
			r = clamp<float>(fr * co3, 0, 1) * 255.0f;
 | 
			
		||||
			g = clamp<float>(fg * co3, 0, 1) * 255.0f;
 | 
			
		||||
			b = clamp<float>(fb * co3, 0, 1) * 255.0f;
 | 
			
		||||
			a = clamp<float>(fa, 0, 1) * 255.0f;
 | 
			
		||||
 | 
			
		||||
			*outP = SDL_MapRGBA(&fm, r, g, b, a);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1169,11 +1182,11 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
 | 
			
		|||
	Vec2i gpTexSize;
 | 
			
		||||
	shState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize);
 | 
			
		||||
 | 
			
		||||
	bool fastBlit = !p->touchesTaintedArea(posRect) && txtAlpha == 1.0;
 | 
			
		||||
	bool fastBlit = !p->touchesTaintedArea(posRect) && txtAlpha == 1.0f;
 | 
			
		||||
 | 
			
		||||
	if (fastBlit)
 | 
			
		||||
	{
 | 
			
		||||
		if (squeeze == 1.0 && !shState->config().subImageFix)
 | 
			
		||||
		if (squeeze == 1.0f && !shState->config().subImageFix)
 | 
			
		||||
		{
 | 
			
		||||
			/* Even faster: upload directly to bitmap texture.
 | 
			
		||||
			 * We have to make sure the posRect lies within the texture
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -151,7 +151,7 @@ void Config::read(int argc, char *argv[])
 | 
			
		|||
	PO_DESC(winResizable, bool, false) \
 | 
			
		||||
	PO_DESC(fullscreen, bool, false) \
 | 
			
		||||
	PO_DESC(fixedAspectRatio, bool, true) \
 | 
			
		||||
	PO_DESC(smoothScaling, bool, false) \
 | 
			
		||||
	PO_DESC(smoothScaling, bool, true) \
 | 
			
		||||
	PO_DESC(vsync, bool, false) \
 | 
			
		||||
	PO_DESC(defScreenW, int, 0) \
 | 
			
		||||
	PO_DESC(defScreenH, int, 0) \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								src/config.h
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								src/config.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -31,49 +31,6 @@ struct CropTexture
 | 
			
		|||
	int w, h;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct TouchOverlay
 | 
			
		||||
{
 | 
			
		||||
	std::string image;
 | 
			
		||||
 | 
			
		||||
	struct Button
 | 
			
		||||
	{
 | 
			
		||||
		enum Shape
 | 
			
		||||
		{
 | 
			
		||||
			Rectangle,
 | 
			
		||||
			Circle,
 | 
			
		||||
			Triangle
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		std::string id;
 | 
			
		||||
		std::string target;
 | 
			
		||||
		Shape shape;
 | 
			
		||||
 | 
			
		||||
		int x;
 | 
			
		||||
		int y;
 | 
			
		||||
 | 
			
		||||
		union
 | 
			
		||||
		{
 | 
			
		||||
			struct
 | 
			
		||||
			{
 | 
			
		||||
				int width;
 | 
			
		||||
				int height;
 | 
			
		||||
			} r;
 | 
			
		||||
 | 
			
		||||
			struct
 | 
			
		||||
			{
 | 
			
		||||
				int radius;
 | 
			
		||||
			} c;
 | 
			
		||||
			struct
 | 
			
		||||
			{
 | 
			
		||||
				int x1, y1;
 | 
			
		||||
				int x2, y2;
 | 
			
		||||
			} t;
 | 
			
		||||
		} u;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	std::vector<Button> buttons;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Config
 | 
			
		||||
{
 | 
			
		||||
	int rgssVersion;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,9 +61,9 @@ struct Vec4
 | 
			
		|||
		return (x == other.x && y == other.y && z == other.z && w == other.w);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool xyzHasEffect() const
 | 
			
		||||
	bool xyzNotNull() const
 | 
			
		||||
	{
 | 
			
		||||
		return (x != 0.0 || y != 0.0 || z != 0.0);
 | 
			
		||||
		return (x != 0.0f || y != 0.0f || z != 0.0f);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +88,11 @@ struct Vec2i
 | 
			
		|||
		return x == other.x && y == other.y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const Vec2i &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return !(*this == other);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2i &operator+=(const Vec2i &value)
 | 
			
		||||
	{
 | 
			
		||||
		x += value.x;
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +136,11 @@ struct Vec2i
 | 
			
		|||
		return Vec2i(x % value, y % value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2i operator&(unsigned value) const
 | 
			
		||||
	{
 | 
			
		||||
		return Vec2i(x & value, y & value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2i operator-() const
 | 
			
		||||
	{
 | 
			
		||||
		return Vec2i(-x, -y);
 | 
			
		||||
| 
						 | 
				
			
			@ -176,6 +186,11 @@ struct IntRect : SDL_Rect
 | 
			
		|||
		        w == other.w && h == other.h);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const IntRect &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return !(*this == other);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2i pos() const
 | 
			
		||||
	{
 | 
			
		||||
		return Vec2i(x, y);
 | 
			
		||||
| 
						 | 
				
			
			@ -259,13 +274,13 @@ struct NormValue
 | 
			
		|||
 | 
			
		||||
	NormValue(int unNorm)
 | 
			
		||||
	    : unNorm(unNorm),
 | 
			
		||||
	      norm(unNorm / 255.0)
 | 
			
		||||
	      norm(unNorm / 255.0f)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void operator =(int value)
 | 
			
		||||
	{
 | 
			
		||||
		unNorm = clamp(value, 0, 255);
 | 
			
		||||
		norm = unNorm / 255.0;
 | 
			
		||||
		norm = unNorm / 255.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator ==(int value) const
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -111,7 +111,11 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
	UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg;
 | 
			
		||||
 | 
			
		||||
	initALCFunctions(rtData.alcDev);
 | 
			
		||||
 | 
			
		||||
	// XXX this function breaks input focus on OSX
 | 
			
		||||
#ifndef __MACOSX__
 | 
			
		||||
	SDL_SetEventFilter(eventFilter, &rtData);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	fullscreen = rtData.config.fullscreen;
 | 
			
		||||
	int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +131,9 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
	bool displayingFPS = false;
 | 
			
		||||
 | 
			
		||||
	bool cursorInWindow = false;
 | 
			
		||||
	bool windowFocused = false;
 | 
			
		||||
 | 
			
		||||
	/* SDL doesn't send an initial FOCUS_GAINED event */
 | 
			
		||||
	bool windowFocused = true;
 | 
			
		||||
 | 
			
		||||
	bool terminate = false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -490,9 +496,9 @@ int EventThread::eventFilter(void *data, SDL_Event *event)
 | 
			
		|||
		Debug() << "SDL_APP_LOWMEMORY";
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	case SDL_RENDER_TARGETS_RESET :
 | 
			
		||||
		Debug() << "****** SDL_RENDER_TARGETS_RESET";
 | 
			
		||||
		return 0;
 | 
			
		||||
//	case SDL_RENDER_TARGETS_RESET :
 | 
			
		||||
//		Debug() << "****** SDL_RENDER_TARGETS_RESET";
 | 
			
		||||
//		return 0;
 | 
			
		||||
 | 
			
		||||
//	case SDL_RENDER_DEVICE_RESET :
 | 
			
		||||
//		Debug() << "****** SDL_RENDER_DEVICE_RESET";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,7 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <stack>
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
#include <iconv.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -249,201 +250,65 @@ strcpySafe(char *dst, const char *src,
 | 
			
		|||
	return cpyMax;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Attempt to locate an extension string in a filename.
 | 
			
		||||
 * Either a pointer into the input string pointing at the
 | 
			
		||||
 * extension, or null is returned */
 | 
			
		||||
static const char *
 | 
			
		||||
findExt(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	for (len = strlen(filename); len > 0; --len)
 | 
			
		||||
	{
 | 
			
		||||
		if (filename[len] == '/')
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		if (filename[len] == '.')
 | 
			
		||||
			return &filename[len+1];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
initReadOps(PHYSFS_File *handle,
 | 
			
		||||
            SDL_RWops &ops,
 | 
			
		||||
            bool freeOnClose)
 | 
			
		||||
{
 | 
			
		||||
	ops.size  = SDL_RWopsSize;
 | 
			
		||||
	ops.seek  = SDL_RWopsSeek;
 | 
			
		||||
	ops.read  = SDL_RWopsRead;
 | 
			
		||||
	ops.write = SDL_RWopsWrite;
 | 
			
		||||
 | 
			
		||||
	if (freeOnClose)
 | 
			
		||||
		ops.close = SDL_RWopsCloseFree;
 | 
			
		||||
	else
 | 
			
		||||
		ops.close = SDL_RWopsClose;
 | 
			
		||||
 | 
			
		||||
	ops.type = SDL_RWOPS_PHYSFS;
 | 
			
		||||
	ops.hidden.unknown.data1 = handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void strTolower(std::string &str)
 | 
			
		||||
{
 | 
			
		||||
	for (size_t i = 0; i < str.size(); ++i)
 | 
			
		||||
		str[i] = tolower(str[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
 | 
			
		||||
 | 
			
		||||
struct FileSystemPrivate
 | 
			
		||||
{
 | 
			
		||||
	/* Maps: lower case filepath without extension,
 | 
			
		||||
	 * To:   mixed case full filepath
 | 
			
		||||
	 * This is for compatibility with games that take Windows'
 | 
			
		||||
	 * case insensitivity for granted */
 | 
			
		||||
	/* Maps: lower case full filepath,
 | 
			
		||||
	 * To:   mixed case full filepath */
 | 
			
		||||
	BoostHash<std::string, std::string> pathCache;
 | 
			
		||||
	/* Maps: lower case directory path,
 | 
			
		||||
	 * To:   list of lower case filenames */
 | 
			
		||||
	BoostHash<std::string, std::vector<std::string> > fileLists;
 | 
			
		||||
 | 
			
		||||
	/* This is for compatibility with games that take Windows'
 | 
			
		||||
	 * case insensitivity for granted */
 | 
			
		||||
	bool havePathCache;
 | 
			
		||||
 | 
			
		||||
	/* Attempt to locate an extension string in a filename.
 | 
			
		||||
	 * Either a pointer into the input string pointing at the
 | 
			
		||||
	 * extension, or null is returned */
 | 
			
		||||
	const char *findExt(const char *filename)
 | 
			
		||||
	{
 | 
			
		||||
		size_t len;
 | 
			
		||||
 | 
			
		||||
		for (len = strlen(filename); len > 0; --len)
 | 
			
		||||
		{
 | 
			
		||||
			if (filename[len] == '/')
 | 
			
		||||
				return 0;
 | 
			
		||||
 | 
			
		||||
			if (filename[len] == '.')
 | 
			
		||||
				return &filename[len+1];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct CompleteFilenameData
 | 
			
		||||
	{
 | 
			
		||||
		bool found;
 | 
			
		||||
		/* Contains the incomplete filename we're looking for;
 | 
			
		||||
		 * when found, we write the complete filename into this
 | 
			
		||||
		 * same buffer */
 | 
			
		||||
		char *outBuf;
 | 
			
		||||
		/* Length of incomplete file name */
 | 
			
		||||
		size_t filenameLen;
 | 
			
		||||
		/* Maximum we can write into outBuf */
 | 
			
		||||
		size_t outBufN;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static void completeFilenameRegCB(void *data, const char *,
 | 
			
		||||
	                                  const char *fname)
 | 
			
		||||
	{
 | 
			
		||||
		CompleteFilenameData &d = *static_cast<CompleteFilenameData*>(data);
 | 
			
		||||
 | 
			
		||||
		if (d.found)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (strncmp(d.outBuf, fname, d.filenameLen) != 0)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		/* If fname matches up to a following '.' (meaning the rest is part
 | 
			
		||||
		 * of the extension), or up to a following '\0' (full match), we've
 | 
			
		||||
		 * found our file */
 | 
			
		||||
		switch (fname[d.filenameLen])
 | 
			
		||||
		{
 | 
			
		||||
		case '.' :
 | 
			
		||||
			/* Overwrite the incomplete file name we looked for with
 | 
			
		||||
			 * the full version containing any extensions */
 | 
			
		||||
			strcpySafe(d.outBuf, fname, d.outBufN, -1);
 | 
			
		||||
		case '\0' :
 | 
			
		||||
			d.found = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool completeFilenameReg(const char *filepath,
 | 
			
		||||
	                         char *outBuffer,
 | 
			
		||||
	                         size_t outN)
 | 
			
		||||
	{
 | 
			
		||||
		strcpySafe(outBuffer, filepath, outN, -1);
 | 
			
		||||
 | 
			
		||||
		size_t len = strlen(outBuffer);
 | 
			
		||||
		char *delim;
 | 
			
		||||
 | 
			
		||||
		/* Find the deliminator separating directory and file name */
 | 
			
		||||
		for (delim = outBuffer + len; delim > outBuffer; --delim)
 | 
			
		||||
			if (*delim == '/')
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
		bool root = (delim == outBuffer);
 | 
			
		||||
		CompleteFilenameData d;
 | 
			
		||||
 | 
			
		||||
		if (!root)
 | 
			
		||||
		{
 | 
			
		||||
			/* If we have such a deliminator, we set it to '\0' so we
 | 
			
		||||
			 * can pass the first half to PhysFS as the directory name,
 | 
			
		||||
			 * and compare all filenames against the second half */
 | 
			
		||||
			d.outBuf = delim+1;
 | 
			
		||||
			d.filenameLen = len - (delim - outBuffer + 1);
 | 
			
		||||
 | 
			
		||||
			*delim = '\0';
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* Otherwise the file is in the root directory */
 | 
			
		||||
			d.outBuf = outBuffer;
 | 
			
		||||
			d.filenameLen = len - (delim - outBuffer);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d.found = false;
 | 
			
		||||
		d.outBufN = outN - (d.outBuf - outBuffer);
 | 
			
		||||
 | 
			
		||||
		PHYSFS_enumerateFilesCallback(root ? "" : outBuffer, completeFilenameRegCB, &d);
 | 
			
		||||
 | 
			
		||||
		if (!d.found)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		/* Now we put the deliminator back in to form the completed
 | 
			
		||||
		 * file path (if required) */
 | 
			
		||||
		if (delim != outBuffer)
 | 
			
		||||
			*delim = '/';
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool completeFilenamePC(const char *filepath,
 | 
			
		||||
	                        char *outBuffer,
 | 
			
		||||
	                        size_t outN)
 | 
			
		||||
	{
 | 
			
		||||
		std::string lowCase(filepath);
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < lowCase.size(); ++i)
 | 
			
		||||
			lowCase[i] = tolower(lowCase[i]);
 | 
			
		||||
 | 
			
		||||
		if (!pathCache.contains(lowCase))
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		const std::string &fullPath = pathCache[lowCase];
 | 
			
		||||
		strcpySafe(outBuffer, fullPath.c_str(), outN, fullPath.size());
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool completeFilename(const char *filepath,
 | 
			
		||||
	                      char *outBuffer,
 | 
			
		||||
	                      size_t outN)
 | 
			
		||||
	{
 | 
			
		||||
		if (havePathCache)
 | 
			
		||||
			return completeFilenamePC(filepath, outBuffer, outN);
 | 
			
		||||
		else
 | 
			
		||||
			return completeFilenameReg(filepath, outBuffer, outN);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PHYSFS_File *openReadHandle(const char *filename,
 | 
			
		||||
	                            char *extBuf,
 | 
			
		||||
	                            size_t extBufN)
 | 
			
		||||
	{
 | 
			
		||||
		char found[512];
 | 
			
		||||
 | 
			
		||||
		if (!completeFilename(filename, found, sizeof(found)))
 | 
			
		||||
			throw Exception(Exception::NoFileError, "%s", filename);
 | 
			
		||||
 | 
			
		||||
		PHYSFS_File *handle = PHYSFS_openRead(found);
 | 
			
		||||
 | 
			
		||||
		if (!handle)
 | 
			
		||||
			throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
 | 
			
		||||
 | 
			
		||||
		if (!extBuf)
 | 
			
		||||
			return handle;
 | 
			
		||||
 | 
			
		||||
		for (char *q = found+strlen(found); q > found; --q)
 | 
			
		||||
		{
 | 
			
		||||
			if (*q == '/')
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (*q != '.')
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			strcpySafe(extBuf, q+1, extBufN, -1);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return handle;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initReadOps(PHYSFS_File *handle,
 | 
			
		||||
	                 SDL_RWops &ops,
 | 
			
		||||
	                 bool freeOnClose)
 | 
			
		||||
	{
 | 
			
		||||
		ops.size  = SDL_RWopsSize;
 | 
			
		||||
		ops.seek  = SDL_RWopsSeek;
 | 
			
		||||
		ops.read  = SDL_RWopsRead;
 | 
			
		||||
		ops.write = SDL_RWopsWrite;
 | 
			
		||||
 | 
			
		||||
		if (freeOnClose)
 | 
			
		||||
			ops.close = SDL_RWopsCloseFree;
 | 
			
		||||
		else
 | 
			
		||||
			ops.close = SDL_RWopsClose;
 | 
			
		||||
 | 
			
		||||
		ops.type = SDL_RWOPS_PHYSFS;
 | 
			
		||||
		ops.hidden.unknown.data1 = handle;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FileSystem::FileSystem(const char *argv0,
 | 
			
		||||
| 
						 | 
				
			
			@ -484,99 +349,105 @@ void FileSystem::addPath(const char *path)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
struct CacheEnumCBData
 | 
			
		||||
struct CacheEnumData
 | 
			
		||||
{
 | 
			
		||||
	FileSystemPrivate *p;
 | 
			
		||||
	std::stack<std::vector<std::string>*> fileLists;
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
	iconv_t nfd2nfc;
 | 
			
		||||
	char buf[512];
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	CacheEnumCBData(FileSystemPrivate *fsp)
 | 
			
		||||
	CacheEnumData(FileSystemPrivate *p)
 | 
			
		||||
	    : p(p)
 | 
			
		||||
	{
 | 
			
		||||
		p = fsp;
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
		nfd2nfc = iconv_open("utf-8", "utf-8-mac");
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~CacheEnumCBData()
 | 
			
		||||
	~CacheEnumData()
 | 
			
		||||
	{
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
		iconv_close(nfd2nfc);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void nfcFromNfd(char *dst, const char *src, size_t dstSize)
 | 
			
		||||
	/* Converts in-place */
 | 
			
		||||
	void toNFC(char *inout)
 | 
			
		||||
	{
 | 
			
		||||
		size_t srcSize = strlen(src);
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
		size_t srcSize = strlen(inout);
 | 
			
		||||
		size_t bufSize = sizeof(buf);
 | 
			
		||||
		char *bufPtr = buf;
 | 
			
		||||
		char *inoutPtr = inout;
 | 
			
		||||
 | 
			
		||||
		/* Reserve room for null terminator */
 | 
			
		||||
		--dstSize;
 | 
			
		||||
		/* iconv takes a char** instead of a const char**, even though
 | 
			
		||||
		 * the string data isn't written to. */
 | 
			
		||||
		--bufSize;
 | 
			
		||||
 | 
			
		||||
		iconv(nfd2nfc,
 | 
			
		||||
			  const_cast<char**>(&src), &srcSize,
 | 
			
		||||
			  &dst, &dstSize);
 | 
			
		||||
			  &inoutPtr, &srcSize,
 | 
			
		||||
			  &bufPtr, &bufSize);
 | 
			
		||||
		/* Null-terminate */
 | 
			
		||||
		*dst = 0;
 | 
			
		||||
		*bufPtr = 0;
 | 
			
		||||
		strcpy(inout, buf);
 | 
			
		||||
#else
 | 
			
		||||
		(void) inout;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void cacheEnumCB(void *d, const char *origdir,
 | 
			
		||||
                        const char *fname)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
	CacheEnumCBData *data = static_cast<CacheEnumCBData*>(d);
 | 
			
		||||
	FileSystemPrivate *p = data->p;
 | 
			
		||||
#else
 | 
			
		||||
	FileSystemPrivate *p = static_cast<FileSystemPrivate*>(d);
 | 
			
		||||
#endif
 | 
			
		||||
	CacheEnumData &data = *static_cast<CacheEnumData*>(d);
 | 
			
		||||
	char fullPath[512];
 | 
			
		||||
 | 
			
		||||
	char buf[512];
 | 
			
		||||
 | 
			
		||||
	if (*origdir == '\0')
 | 
			
		||||
		strncpy(buf, fname, sizeof(buf));
 | 
			
		||||
	if (!*origdir)
 | 
			
		||||
		snprintf(fullPath, sizeof(fullPath), "%s", fname);
 | 
			
		||||
	else
 | 
			
		||||
		snprintf(buf, sizeof(buf), "%s/%s", origdir, fname);
 | 
			
		||||
		snprintf(fullPath, sizeof(fullPath), "%s/%s", origdir, fname);
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
	char bufNfc[sizeof(buf)];
 | 
			
		||||
	data->nfcFromNfd(bufNfc, buf, sizeof(bufNfc));
 | 
			
		||||
#else
 | 
			
		||||
	char *const bufNfc = buf;
 | 
			
		||||
#endif
 | 
			
		||||
	/* Deal with OSX' weird UTF-8 standards */
 | 
			
		||||
	data.toNFC(fullPath);
 | 
			
		||||
 | 
			
		||||
	char *ptr = bufNfc;
 | 
			
		||||
	std::string mixedCase(fullPath);
 | 
			
		||||
	std::string lowerCase = mixedCase;
 | 
			
		||||
	strTolower(lowerCase);
 | 
			
		||||
 | 
			
		||||
	/* Trim leading slash */
 | 
			
		||||
	if (*ptr == '/')
 | 
			
		||||
		++ptr;
 | 
			
		||||
	PHYSFS_Stat stat;
 | 
			
		||||
	PHYSFS_stat(fullPath, &stat);
 | 
			
		||||
 | 
			
		||||
	std::string mixedCase(ptr);
 | 
			
		||||
 | 
			
		||||
	for (char *q = bufNfc; *q; ++q)
 | 
			
		||||
		*q = tolower(*q);
 | 
			
		||||
 | 
			
		||||
	p->pathCache.insert(std::string(ptr), mixedCase);
 | 
			
		||||
 | 
			
		||||
	for (char *q = ptr+strlen(ptr); q > ptr; --q)
 | 
			
		||||
	if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY)
 | 
			
		||||
	{
 | 
			
		||||
		if (*q == '/')
 | 
			
		||||
			break;
 | 
			
		||||
		/* Create a new list for this directory */
 | 
			
		||||
		std::vector<std::string> &list = data.p->fileLists[lowerCase];
 | 
			
		||||
 | 
			
		||||
		if (*q != '.')
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		*q = '\0';
 | 
			
		||||
		p->pathCache.insert(std::string(ptr), mixedCase);
 | 
			
		||||
		/* Iterate over its contents */
 | 
			
		||||
		data.fileLists.push(&list);
 | 
			
		||||
		PHYSFS_enumerateFilesCallback(fullPath, cacheEnumCB, d);
 | 
			
		||||
		data.fileLists.pop();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* Get the file list for the directory we're currently
 | 
			
		||||
		 * traversing and append this filename to it */
 | 
			
		||||
		std::vector<std::string> &list = *data.fileLists.top();
 | 
			
		||||
		std::string lowerFilename(fname);
 | 
			
		||||
		strTolower(lowerFilename);
 | 
			
		||||
		list.push_back(lowerFilename);
 | 
			
		||||
 | 
			
		||||
	PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, d);
 | 
			
		||||
		/* Add the lower -> mixed mapping of the file's full path */
 | 
			
		||||
		data.p->pathCache.insert(lowerCase, mixedCase);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileSystem::createPathCache()
 | 
			
		||||
{
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
	CacheEnumCBData data(p);
 | 
			
		||||
	CacheEnumData data(p);
 | 
			
		||||
	data.fileLists.push(&p->fileLists[""]);
 | 
			
		||||
	PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data);
 | 
			
		||||
#else
 | 
			
		||||
	PHYSFS_enumerateFilesCallback("", cacheEnumCB, p);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	p->havePathCache = true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -591,10 +462,9 @@ static void fontSetEnumCB(void *data, const char *,
 | 
			
		|||
                          const char *fname)
 | 
			
		||||
{
 | 
			
		||||
	FontSetsCBData *d = static_cast<FontSetsCBData*>(data);
 | 
			
		||||
	FileSystemPrivate *p = d->p;
 | 
			
		||||
 | 
			
		||||
	/* Only consider filenames with font extensions */
 | 
			
		||||
	const char *ext = p->findExt(fname);
 | 
			
		||||
	const char *ext = findExt(fname);
 | 
			
		||||
 | 
			
		||||
	if (!ext)
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -618,7 +488,7 @@ static void fontSetEnumCB(void *data, const char *,
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	SDL_RWops ops;
 | 
			
		||||
	p->initReadOps(handle, ops, false);
 | 
			
		||||
	initReadOps(handle, ops, false);
 | 
			
		||||
 | 
			
		||||
	d->sfs->initFontSetCB(ops, filename);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -632,15 +502,147 @@ void FileSystem::initFontSets(SharedFontState &sfs)
 | 
			
		|||
	PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileSystem::openRead(SDL_RWops &ops,
 | 
			
		||||
                          const char *filename,
 | 
			
		||||
                          bool freeOnClose,
 | 
			
		||||
                          char *extBuf,
 | 
			
		||||
                          size_t extBufN)
 | 
			
		||||
struct OpenReadEnumData
 | 
			
		||||
{
 | 
			
		||||
 	PHYSFS_File *handle = p->openReadHandle(filename, extBuf, extBufN);
 | 
			
		||||
	FileSystem::OpenHandler &handler;
 | 
			
		||||
	SDL_RWops ops;
 | 
			
		||||
 | 
			
		||||
	p->initReadOps(handle, ops, freeOnClose);
 | 
			
		||||
	/* The filename (without directory) we're looking for */
 | 
			
		||||
	const char *filename;
 | 
			
		||||
	size_t filenameN;
 | 
			
		||||
 | 
			
		||||
	/* Optional hash to translate full filepaths
 | 
			
		||||
	 * (used with path cache) */
 | 
			
		||||
	BoostHash<std::string, std::string> *pathTrans;
 | 
			
		||||
 | 
			
		||||
	/* Number of files we've attempted to read and parse */
 | 
			
		||||
	size_t matchCount;
 | 
			
		||||
	bool stopSearching;
 | 
			
		||||
 | 
			
		||||
	/* In case of a PhysFS error, save it here so it
 | 
			
		||||
	 * doesn't get changed before we get back into our code */
 | 
			
		||||
	const char *physfsError;
 | 
			
		||||
 | 
			
		||||
	OpenReadEnumData(FileSystem::OpenHandler &handler,
 | 
			
		||||
	                 const char *filename, size_t filenameN,
 | 
			
		||||
	                 BoostHash<std::string, std::string> *pathTrans)
 | 
			
		||||
	    : handler(handler), filename(filename), filenameN(filenameN),
 | 
			
		||||
	      pathTrans(pathTrans), matchCount(0), stopSearching(false),
 | 
			
		||||
	      physfsError(0)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void openReadEnumCB(void *d, const char *dirpath,
 | 
			
		||||
                           const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	OpenReadEnumData &data = *static_cast<OpenReadEnumData*>(d);
 | 
			
		||||
	char buffer[512];
 | 
			
		||||
	const char *fullPath;
 | 
			
		||||
 | 
			
		||||
	if (data.stopSearching)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* If there's not even a partial match, continue searching */
 | 
			
		||||
	if (strncmp(filename, data.filename, data.filenameN) != 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!*dirpath)
 | 
			
		||||
	{
 | 
			
		||||
		fullPath = filename;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		snprintf(buffer, sizeof(buffer), "%s/%s", dirpath, filename);
 | 
			
		||||
		fullPath = buffer;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	char last = filename[data.filenameN];
 | 
			
		||||
 | 
			
		||||
	/* If fname matches up to a following '.' (meaning the rest is part
 | 
			
		||||
	 * of the extension), or up to a following '\0' (full match), we've
 | 
			
		||||
	 * found our file */
 | 
			
		||||
	if (last != '.' && last != '\0')
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* If the path cache is active, translate from lower case
 | 
			
		||||
	 * to mixed case path */
 | 
			
		||||
	if (data.pathTrans)
 | 
			
		||||
		fullPath = (*data.pathTrans)[fullPath].c_str();
 | 
			
		||||
 | 
			
		||||
	PHYSFS_File *phys = PHYSFS_openRead(fullPath);
 | 
			
		||||
 | 
			
		||||
	if (!phys)
 | 
			
		||||
	{
 | 
			
		||||
		/* Failing to open this file here means there must
 | 
			
		||||
		 * be a deeper rooted problem somewhere within PhysFS.
 | 
			
		||||
		 * Just abort alltogether. */
 | 
			
		||||
		data.stopSearching = true;
 | 
			
		||||
		data.physfsError = PHYSFS_getLastError();
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	initReadOps(phys, data.ops, false);
 | 
			
		||||
 | 
			
		||||
	const char *ext = findExt(filename);
 | 
			
		||||
 | 
			
		||||
	if (data.handler.tryRead(data.ops, ext))
 | 
			
		||||
		data.stopSearching = true;
 | 
			
		||||
 | 
			
		||||
	++data.matchCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileSystem::openRead(OpenHandler &handler, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[512];
 | 
			
		||||
	size_t len = strcpySafe(buffer, filename, sizeof(buffer), -1);
 | 
			
		||||
	char *delim;
 | 
			
		||||
 | 
			
		||||
	if (p->havePathCache)
 | 
			
		||||
		for (size_t i = 0; i < len; ++i)
 | 
			
		||||
			buffer[i] = tolower(buffer[i]);
 | 
			
		||||
 | 
			
		||||
	/* Find the deliminator separating directory and file name */
 | 
			
		||||
	for (delim = buffer + len; delim > buffer; --delim)
 | 
			
		||||
		if (*delim == '/')
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	const bool root = (delim == buffer);
 | 
			
		||||
 | 
			
		||||
	const char *file = buffer;
 | 
			
		||||
	const char *dir = "";
 | 
			
		||||
 | 
			
		||||
	if (!root)
 | 
			
		||||
	{
 | 
			
		||||
		/* Cut the buffer in half so we can use it
 | 
			
		||||
		 * for both filename and directory path */
 | 
			
		||||
		*delim = '\0';
 | 
			
		||||
		file = delim+1;
 | 
			
		||||
		dir = buffer;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	OpenReadEnumData data(handler, file, len + buffer - delim - !root,
 | 
			
		||||
	                      p->havePathCache ? &p->pathCache : 0);
 | 
			
		||||
 | 
			
		||||
	if (p->havePathCache)
 | 
			
		||||
	{
 | 
			
		||||
		/* Get the list of files contained in this directory
 | 
			
		||||
		 * and manually iterate over them */
 | 
			
		||||
		const std::vector<std::string> &fileList = p->fileLists[dir];
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < fileList.size(); ++i)
 | 
			
		||||
			openReadEnumCB(&data, dir, fileList[i].c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		PHYSFS_enumerateFilesCallback(dir, openReadEnumCB, &data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (data.physfsError)
 | 
			
		||||
		throw Exception(Exception::PHYSFSError, "PhysFS: %s", data.physfsError);
 | 
			
		||||
 | 
			
		||||
	if (data.matchCount == 0)
 | 
			
		||||
		throw Exception(Exception::NoFileError, "%s", filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileSystem::openReadRaw(SDL_RWops &ops,
 | 
			
		||||
| 
						 | 
				
			
			@ -650,12 +652,10 @@ void FileSystem::openReadRaw(SDL_RWops &ops,
 | 
			
		|||
	PHYSFS_File *handle = PHYSFS_openRead(filename);
 | 
			
		||||
	assert(handle);
 | 
			
		||||
 | 
			
		||||
	p->initReadOps(handle, ops, freeOnClose);
 | 
			
		||||
	initReadOps(handle, ops, freeOnClose);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileSystem::exists(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	char found[512];
 | 
			
		||||
 | 
			
		||||
	return p->completeFilename(filename, found, sizeof(found));
 | 
			
		||||
	return PHYSFS_exists(filename);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,17 +43,28 @@ public:
 | 
			
		|||
	 * available font assets */
 | 
			
		||||
	void initFontSets(SharedFontState &sfs);
 | 
			
		||||
 | 
			
		||||
	void openRead(SDL_RWops &ops,
 | 
			
		||||
	              const char *filename,
 | 
			
		||||
	              bool freeOnClose = false,
 | 
			
		||||
	              char *extBuf = 0,
 | 
			
		||||
	              size_t extBufN = 0);
 | 
			
		||||
	struct OpenHandler
 | 
			
		||||
	{
 | 
			
		||||
		/* Try to read and interpret data provided from ops.
 | 
			
		||||
		 * If data cannot be parsed, return false, otherwise true.
 | 
			
		||||
		 * Can be called multiple times until a parseable file is found.
 | 
			
		||||
		 * It's the handler's responsibility to close every passed
 | 
			
		||||
		 * ops structure, even when data could not be parsed.
 | 
			
		||||
		 * After this function returns, ops becomes invalid, so don't take
 | 
			
		||||
		 * references to it. Instead, copy the structure without closing
 | 
			
		||||
		 * if you need to further read from it later. */
 | 
			
		||||
		virtual bool tryRead(SDL_RWops &ops, const char *ext) = 0;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void openRead(OpenHandler &handler,
 | 
			
		||||
	              const char *filename);
 | 
			
		||||
 | 
			
		||||
	/* Circumvents extension supplementing */
 | 
			
		||||
	void openReadRaw(SDL_RWops &ops,
 | 
			
		||||
	                 const char *filename,
 | 
			
		||||
	                 bool freeOnClose = false);
 | 
			
		||||
 | 
			
		||||
	/* Does not perform extension supplementing */
 | 
			
		||||
	bool exists(const char *filename);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										88
									
								
								src/font.cpp
									
										
									
									
									
								
							
							
						
						
									
										88
									
								
								src/font.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -174,7 +174,7 @@ _TTF_Font *SharedFontState::getFont(std::string family,
 | 
			
		|||
	// FIXME 0.9 is guesswork at this point
 | 
			
		||||
//	float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
 | 
			
		||||
//	font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
 | 
			
		||||
	font = TTF_OpenFontRW(ops, 1, size* .90);
 | 
			
		||||
	font = TTF_OpenFontRW(ops, 1, size* 0.90f);
 | 
			
		||||
 | 
			
		||||
	if (!font)
 | 
			
		||||
		throw Exception(Exception::SDLError, "%s", SDL_GetError());
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +184,7 @@ _TTF_Font *SharedFontState::getFont(std::string family,
 | 
			
		|||
	return font;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SharedFontState::fontPresent(std::string family)
 | 
			
		||||
bool SharedFontState::fontPresent(std::string family) const
 | 
			
		||||
{
 | 
			
		||||
	/* Check for substitutions */
 | 
			
		||||
	if (p->subs.contains(family))
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +202,26 @@ _TTF_Font *SharedFontState::openBundled(int size)
 | 
			
		|||
	return TTF_OpenFontRW(ops, 1, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pickExistingFontName(const std::vector<std::string> &names,
 | 
			
		||||
                          std::string &out,
 | 
			
		||||
                          const SharedFontState &sfs)
 | 
			
		||||
{
 | 
			
		||||
	/* Note: In RMXP, a names array with no existing entry
 | 
			
		||||
	 * results in no text being drawn at all (same for "" and []);
 | 
			
		||||
	 * we can't replicate this in mkxp due to the default substitute. */
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < names.size(); ++i)
 | 
			
		||||
	{
 | 
			
		||||
		if (sfs.fontPresent(names[i]))
 | 
			
		||||
		{
 | 
			
		||||
			out = names[i];
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out = "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct FontPrivate
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -229,15 +249,15 @@ struct FontPrivate
 | 
			
		|||
	static Color defaultColorTmp;
 | 
			
		||||
	static Color defaultOutColorTmp;
 | 
			
		||||
 | 
			
		||||
	static std::vector<std::string> initialDefaultNames;
 | 
			
		||||
 | 
			
		||||
	/* The actual font is opened as late as possible
 | 
			
		||||
	 * (when it is queried by a Bitmap), prior it is
 | 
			
		||||
	 * set to null */
 | 
			
		||||
	TTF_Font *sdlFont;
 | 
			
		||||
 | 
			
		||||
	FontPrivate(const char *name = 0,
 | 
			
		||||
	            int size = 0)
 | 
			
		||||
	    : name(name ? std::string(name) : defaultName),
 | 
			
		||||
	      size(size ? size : defaultSize),
 | 
			
		||||
	FontPrivate(int size)
 | 
			
		||||
	    : size(size),
 | 
			
		||||
	      bold(defaultBold),
 | 
			
		||||
	      italic(defaultItalic),
 | 
			
		||||
	      outline(defaultOutline),
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +310,8 @@ Color      *FontPrivate::defaultOutColor = &FontPrivate::defaultOutColorTmp;
 | 
			
		|||
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
 | 
			
		||||
Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128);
 | 
			
		||||
 | 
			
		||||
std::vector<std::string> FontPrivate::initialDefaultNames;
 | 
			
		||||
 | 
			
		||||
bool Font::doesExist(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	if (!name)
 | 
			
		||||
| 
						 | 
				
			
			@ -298,10 +320,15 @@ bool Font::doesExist(const char *name)
 | 
			
		|||
	return shState->fontState().fontPresent(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Font::Font(const char *name,
 | 
			
		||||
Font::Font(const std::vector<std::string> *names,
 | 
			
		||||
           int size)
 | 
			
		||||
{
 | 
			
		||||
	p = new FontPrivate(name, size);
 | 
			
		||||
	p = new FontPrivate(size ? size : FontPrivate::defaultSize);
 | 
			
		||||
 | 
			
		||||
	if (names)
 | 
			
		||||
		setName(*names);
 | 
			
		||||
	else
 | 
			
		||||
		p->name = FontPrivate::defaultName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Font::Font(const Font &other)
 | 
			
		||||
| 
						 | 
				
			
			@ -321,17 +348,9 @@ const Font &Font::operator=(const Font &o)
 | 
			
		|||
	return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *Font::getName() const
 | 
			
		||||
void Font::setName(const std::vector<std::string> &names)
 | 
			
		||||
{
 | 
			
		||||
	return p->name.c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::setName(const char *value)
 | 
			
		||||
{
 | 
			
		||||
	if (p->name == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->name = value;
 | 
			
		||||
	pickExistingFontName(names, p->name, shState->fontState());
 | 
			
		||||
	p->sdlFont = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -367,14 +386,15 @@ DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutline,  bool,    FontPrivate::defaultOutli
 | 
			
		|||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor,    Color&, *FontPrivate::defaultColor)
 | 
			
		||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutColor, Color&, *FontPrivate::defaultOutColor)
 | 
			
		||||
 | 
			
		||||
const char *Font::getDefaultName()
 | 
			
		||||
void Font::setDefaultName(const std::vector<std::string> &names,
 | 
			
		||||
                          const SharedFontState &sfs)
 | 
			
		||||
{
 | 
			
		||||
	return FontPrivate::defaultName.c_str();
 | 
			
		||||
	pickExistingFontName(names, FontPrivate::defaultName, sfs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::setDefaultName(const char *value)
 | 
			
		||||
const std::vector<std::string> &Font::getInitialDefaultNames()
 | 
			
		||||
{
 | 
			
		||||
	FontPrivate::defaultName = value;
 | 
			
		||||
	return FontPrivate::initialDefaultNames;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::initDynAttribs()
 | 
			
		||||
| 
						 | 
				
			
			@ -393,8 +413,30 @@ void Font::initDefaultDynAttribs()
 | 
			
		|||
		FontPrivate::defaultOutColor = new Color(FontPrivate::defaultOutColorTmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::initDefaults()
 | 
			
		||||
void Font::initDefaults(const SharedFontState &sfs)
 | 
			
		||||
{
 | 
			
		||||
	std::vector<std::string> &names = FontPrivate::initialDefaultNames;
 | 
			
		||||
 | 
			
		||||
	switch (rgssVer)
 | 
			
		||||
	{
 | 
			
		||||
	case 1 :
 | 
			
		||||
		// FIXME: Japanese version has "MS PGothic" instead
 | 
			
		||||
		names.push_back("Arial");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case 2 :
 | 
			
		||||
		names.push_back("UmePlus Gothic");
 | 
			
		||||
		names.push_back("MS Gothic");
 | 
			
		||||
		names.push_back("Courier New");
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
	case 3 :
 | 
			
		||||
		names.push_back("VL Gothic");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setDefaultName(names, sfs);
 | 
			
		||||
 | 
			
		||||
	FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false);
 | 
			
		||||
	FontPrivate::defaultShadow  = (rgssVer == 2 ? true : false);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										69
									
								
								src/font.h
									
										
									
									
									
								
							
							
						
						
									
										69
									
								
								src/font.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -25,6 +25,9 @@
 | 
			
		|||
#include "etc.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
struct SDL_RWops;
 | 
			
		||||
struct _TTF_Font;
 | 
			
		||||
struct Config;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +50,7 @@ public:
 | 
			
		|||
	_TTF_Font *getFont(std::string family,
 | 
			
		||||
	                   int size);
 | 
			
		||||
 | 
			
		||||
	bool fontPresent(std::string family);
 | 
			
		||||
	bool fontPresent(std::string family) const;
 | 
			
		||||
 | 
			
		||||
	static _TTF_Font *openBundled(int size);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -55,22 +58,6 @@ private:
 | 
			
		|||
	SharedFontStatePrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Concerning Font::name/defaultName :
 | 
			
		||||
 * In RGSS, this is not actually a string; any type of
 | 
			
		||||
 * object is accepted, however anything but strings and
 | 
			
		||||
 * arrays is ignored (and text drawing turns blank).
 | 
			
		||||
 * Single strings are interpreted as font family names,
 | 
			
		||||
 * and directly passed to the underlying C++ object;
 | 
			
		||||
 * arrays however are searched for the first string
 | 
			
		||||
 * object corresponding to a valid font family name,
 | 
			
		||||
 * and rendering is done with that. In mkxp, we pass
 | 
			
		||||
 * this first valid font family as the 'name' attribute
 | 
			
		||||
 * back to the C++ object on assignment and object
 | 
			
		||||
 * creation (in case Font.default_name is also an array).
 | 
			
		||||
 * Invalid parameters (things other than strings or
 | 
			
		||||
 * arrays not containing any valid family name) are
 | 
			
		||||
 * passed back as "". */
 | 
			
		||||
 | 
			
		||||
struct FontPrivate;
 | 
			
		||||
 | 
			
		||||
class Font
 | 
			
		||||
| 
						 | 
				
			
			@ -78,31 +65,43 @@ class Font
 | 
			
		|||
public:
 | 
			
		||||
	static bool doesExist(const char *name);
 | 
			
		||||
 | 
			
		||||
	Font(const char *name = 0,
 | 
			
		||||
	Font(const std::vector<std::string> *names = 0,
 | 
			
		||||
	     int size = 0);
 | 
			
		||||
 | 
			
		||||
	/* Clone constructor */
 | 
			
		||||
	Font(const Font &other);
 | 
			
		||||
 | 
			
		||||
	~Font();
 | 
			
		||||
 | 
			
		||||
	const Font &operator=(const Font &o);
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Name,     const char * )
 | 
			
		||||
	DECL_ATTR( Size,     int          )
 | 
			
		||||
	DECL_ATTR( Bold,     bool         )
 | 
			
		||||
	DECL_ATTR( Italic,   bool         )
 | 
			
		||||
	DECL_ATTR( Color,    Color&       )
 | 
			
		||||
	DECL_ATTR( Shadow,   bool         )
 | 
			
		||||
	DECL_ATTR( Outline,  bool         )
 | 
			
		||||
	DECL_ATTR( OutColor, Color&       )
 | 
			
		||||
	DECL_ATTR( Size,     int    )
 | 
			
		||||
	DECL_ATTR( Bold,     bool   )
 | 
			
		||||
	DECL_ATTR( Italic,   bool   )
 | 
			
		||||
	DECL_ATTR( Color,    Color& )
 | 
			
		||||
	DECL_ATTR( Shadow,   bool   )
 | 
			
		||||
	DECL_ATTR( Outline,  bool   )
 | 
			
		||||
	DECL_ATTR( OutColor, Color& )
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultName,     const char* )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultSize,     int         )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultBold,     bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultItalic,   bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultColor,    Color&      )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultShadow,   bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultOutline,  bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultOutColor, Color&      )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultSize,     int    )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultBold,     bool   )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultItalic,   bool   )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultColor,    Color& )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultShadow,   bool   )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultOutline,  bool   )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultOutColor, Color& )
 | 
			
		||||
 | 
			
		||||
	/* There is no point in providing getters for these,
 | 
			
		||||
	 * as the bindings will always return the stored native
 | 
			
		||||
	 * string/array object anyway. It's impossible to mirror
 | 
			
		||||
	 * in the C++ core.
 | 
			
		||||
	 * The core object picks the first existing name from the
 | 
			
		||||
	 * passed array and stores it internally (same for default). */
 | 
			
		||||
	void setName(const std::vector<std::string> &names);
 | 
			
		||||
	static void setDefaultName(const std::vector<std::string> &names,
 | 
			
		||||
	                           const SharedFontState &sfs);
 | 
			
		||||
 | 
			
		||||
	static const std::vector<std::string> &getInitialDefaultNames();
 | 
			
		||||
 | 
			
		||||
	/* Assigns heap allocated objects to object properties;
 | 
			
		||||
	 * using this in pure C++ will cause memory leaks
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +109,7 @@ public:
 | 
			
		|||
	void initDynAttribs();
 | 
			
		||||
	static void initDefaultDynAttribs();
 | 
			
		||||
 | 
			
		||||
	static void initDefaults();
 | 
			
		||||
	static void initDefaults(const SharedFontState &sfs);
 | 
			
		||||
 | 
			
		||||
	/* internal */
 | 
			
		||||
	_TTF_Font *getSdlFont();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,15 +169,15 @@ public:
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
 | 
			
		||||
	void requestViewportRender(const Vec4 &c, const Vec4 &f, const Vec4 &t)
 | 
			
		||||
	{
 | 
			
		||||
		const IntRect &viewpRect = glState.scissorBox.get();
 | 
			
		||||
		const IntRect &screenRect = geometry.rect;
 | 
			
		||||
 | 
			
		||||
		bool toneRGBEffect  = t.xyzHasEffect();
 | 
			
		||||
		bool toneGrayEffect = t.w != 0;
 | 
			
		||||
		bool colorEffect    = c.w > 0;
 | 
			
		||||
		bool flashEffect    = f.w > 0;
 | 
			
		||||
		const bool toneRGBEffect  = t.xyzNotNull();
 | 
			
		||||
		const bool toneGrayEffect = t.w != 0;
 | 
			
		||||
		const bool colorEffect    = c.w > 0;
 | 
			
		||||
		const bool flashEffect    = f.w > 0;
 | 
			
		||||
 | 
			
		||||
		if (toneGrayEffect)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -240,7 +240,7 @@ public:
 | 
			
		|||
			/* Then apply them using hardware blending */
 | 
			
		||||
			gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
 | 
			
		||||
 | 
			
		||||
			if (add.xyzHasEffect())
 | 
			
		||||
			if (add.xyzNotNull())
 | 
			
		||||
			{
 | 
			
		||||
				gl.BlendEquation(GL_FUNC_ADD);
 | 
			
		||||
				shader.setColor(add);
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +248,7 @@ public:
 | 
			
		|||
				screenQuad.draw();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (sub.xyzHasEffect())
 | 
			
		||||
			if (sub.xyzNotNull())
 | 
			
		||||
			{
 | 
			
		||||
				gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 | 
			
		||||
				shader.setColor(sub);
 | 
			
		||||
| 
						 | 
				
			
			@ -281,9 +281,9 @@ public:
 | 
			
		|||
 | 
			
		||||
	void setBrightness(float norm)
 | 
			
		||||
	{
 | 
			
		||||
		brightnessQuad.setColor(Vec4(0, 0, 0, 1.0 - norm));
 | 
			
		||||
		brightnessQuad.setColor(Vec4(0, 0, 0, 1.0f - norm));
 | 
			
		||||
 | 
			
		||||
		brightEffect = norm < 1.0;
 | 
			
		||||
		brightEffect = norm < 1.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateReso(int width, int height)
 | 
			
		||||
| 
						 | 
				
			
			@ -742,7 +742,7 @@ void Graphics::transition(int duration,
 | 
			
		|||
		shader.setFrozenScene(p->frozenScene.tex);
 | 
			
		||||
		shader.setCurrentScene(p->currentScene.tex);
 | 
			
		||||
		shader.setTransMap(transMap->getGLTypes().tex);
 | 
			
		||||
		shader.setVague(vague / 256.0);
 | 
			
		||||
		shader.setVague(vague / 256.0f);
 | 
			
		||||
		shader.setTexSize(p->scRes);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			@ -780,7 +780,7 @@ void Graphics::transition(int duration,
 | 
			
		|||
 | 
			
		||||
		p->checkSyncLock();
 | 
			
		||||
 | 
			
		||||
		const float prog = i * (1.0 / duration);
 | 
			
		||||
		const float prog = i * (1.0f / duration);
 | 
			
		||||
 | 
			
		||||
		if (transMap)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -858,7 +858,7 @@ void Graphics::fadeout(int duration)
 | 
			
		|||
	FBO::unbind();
 | 
			
		||||
 | 
			
		||||
	float curr = p->brightness;
 | 
			
		||||
	float diff = 255.0 - curr;
 | 
			
		||||
	float diff = 255.0f - curr;
 | 
			
		||||
 | 
			
		||||
	for (int i = duration-1; i > -1; --i)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -888,7 +888,7 @@ void Graphics::fadein(int duration)
 | 
			
		|||
	FBO::unbind();
 | 
			
		||||
 | 
			
		||||
	float curr = p->brightness;
 | 
			
		||||
	float diff = 255.0 - curr;
 | 
			
		||||
	float diff = 255.0f - curr;
 | 
			
		||||
 | 
			
		||||
	for (int i = 1; i <= duration; ++i)
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -963,6 +963,11 @@ void Graphics::resizeScreen(int width, int height)
 | 
			
		|||
	shState->eThread().requestWindowResize(width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::playMovie(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	Debug() << "Graphics.playMovie(" << filename << ") not implemented";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Graphics, Brightness, int, p->brightness)
 | 
			
		||||
 | 
			
		||||
void Graphics::setBrightness(int value)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,6 +54,7 @@ public:
 | 
			
		|||
	int width() const;
 | 
			
		||||
	int height() const;
 | 
			
		||||
	void resizeScreen(int width, int height);
 | 
			
		||||
	void playMovie(const char *filename);
 | 
			
		||||
 | 
			
		||||
	void reset();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -320,7 +320,7 @@ readEvent(MidiReadHandler *handler, MemChunk &chunk,
 | 
			
		|||
			              | (data[2] << 0x00);
 | 
			
		||||
 | 
			
		||||
			e.type = Tempo;
 | 
			
		||||
			e.e.tempo.bpm = 60000000.0 / mpqn;
 | 
			
		||||
			e.e.tempo.bpm = 60000000 / mpqn;
 | 
			
		||||
		}
 | 
			
		||||
		else if (metaType == 0x2F)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -626,9 +626,20 @@ struct MidiSource : ALDataSource, MidiReadHandler
 | 
			
		|||
		std::vector<uint8_t> data(dataLen);
 | 
			
		||||
 | 
			
		||||
		if (SDL_RWread(&ops, &data[0], 1, dataLen) < dataLen)
 | 
			
		||||
		{
 | 
			
		||||
			SDL_RWclose(&ops);
 | 
			
		||||
			throw Exception(Exception::MKXPError, "Reading midi data failed");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		readMidi(this, data);
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			readMidi(this, data);
 | 
			
		||||
		}
 | 
			
		||||
		catch (const Exception &)
 | 
			
		||||
		{
 | 
			
		||||
			SDL_RWclose(&ops);
 | 
			
		||||
			throw;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		synth = shState->midiState().allocateSynth();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -688,7 +699,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
 | 
			
		|||
 | 
			
		||||
	void updatePlaybackSpeed(uint32_t bpm)
 | 
			
		||||
	{
 | 
			
		||||
		float deltaLength = 60.0 / (dpb * bpm);
 | 
			
		||||
		float deltaLength = 60.0f / (dpb * bpm);
 | 
			
		||||
		playbackSpeed = TICK_FRAMES / (deltaLength * freq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -899,7 +910,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
 | 
			
		|||
	bool setPitch(float value)
 | 
			
		||||
	{
 | 
			
		||||
		// not completely correct, but close
 | 
			
		||||
		pitchShift = round((value > 1.0 ? 14 : 24) * (value - 1.0));
 | 
			
		||||
		pitchShift = round((value > 1.0f ? 14 : 24) * (value - 1.0f));
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,8 +105,8 @@ struct PlanePrivate
 | 
			
		|||
			return;
 | 
			
		||||
 | 
			
		||||
		/* Scaled (zoomed) bitmap dimensions */
 | 
			
		||||
		double sw = bitmap->width()  * zoomX;
 | 
			
		||||
		double sh = bitmap->height() * zoomY;
 | 
			
		||||
		float sw = bitmap->width()  * zoomX;
 | 
			
		||||
		float sh = bitmap->height() * zoomY;
 | 
			
		||||
 | 
			
		||||
		/* Plane offset wrapped by scaled bitmap dims */
 | 
			
		||||
		float wox = fwrap(ox, sw);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ struct RGSS_entryData
 | 
			
		|||
 | 
			
		||||
struct RGSS_entryHandle
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryData data;
 | 
			
		||||
	const RGSS_entryData data;
 | 
			
		||||
	uint32_t currentMagic;
 | 
			
		||||
	uint64_t currentOffset;
 | 
			
		||||
	PHYSFS_Io *io;
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +229,7 @@ RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset)
 | 
			
		|||
static PHYSFS_sint64
 | 
			
		||||
RGSS_ioTell(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
	const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	return entry->currentOffset;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -237,7 +237,7 @@ RGSS_ioTell(PHYSFS_Io *self)
 | 
			
		|||
static PHYSFS_sint64
 | 
			
		||||
RGSS_ioLength(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
	const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	return entry->data.size;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -245,7 +245,7 @@ RGSS_ioLength(PHYSFS_Io *self)
 | 
			
		|||
static PHYSFS_Io*
 | 
			
		||||
RGSS_ioDuplicate(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
	const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
	RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry);
 | 
			
		||||
 | 
			
		||||
	PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io);
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +448,7 @@ RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
 | 
			
		|||
 | 
			
		||||
	if (hasFile)
 | 
			
		||||
	{
 | 
			
		||||
		RGSS_entryData &entry = data->entryHash[filename];
 | 
			
		||||
		const RGSS_entryData &entry = data->entryHash[filename];
 | 
			
		||||
 | 
			
		||||
		stat->filesize = entry.size;
 | 
			
		||||
		stat->filetype = PHYSFS_FILETYPE_REGULAR;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,9 @@ public:
 | 
			
		|||
	virtual ~Scene();
 | 
			
		||||
 | 
			
		||||
	virtual void composite();
 | 
			
		||||
	virtual void requestViewportRender(Vec4& /*color*/, Vec4& /*flash*/, Vec4& /*tone*/) {}
 | 
			
		||||
	virtual void requestViewportRender(const Vec4& /* color */,
 | 
			
		||||
	                                   const Vec4& /* flash */,
 | 
			
		||||
	                                   const Vec4& /* tone */) {}
 | 
			
		||||
 | 
			
		||||
	const Geometry &getGeometry() const { return geometry; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -764,13 +764,13 @@ void Widget::click(int x, int y, uint8_t button)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Ratio of cell area to total widget width */
 | 
			
		||||
#define BW_CELL_R 0.75
 | 
			
		||||
#define BW_CELL_R 0.75f
 | 
			
		||||
 | 
			
		||||
void BindingWidget::drawHandler(SDL_Surface *surf)
 | 
			
		||||
{
 | 
			
		||||
	const int cellW = (rect.w*BW_CELL_R) / 2;
 | 
			
		||||
	const int cellH = rect.h / 2;
 | 
			
		||||
	const int cellOffX = (1.0-BW_CELL_R) * rect.w;
 | 
			
		||||
	const int cellOffX = (1.0f-BW_CELL_R) * rect.w;
 | 
			
		||||
 | 
			
		||||
	const int cellOff[] =
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -860,7 +860,7 @@ int BindingWidget::cellIndex(int x, int y) const
 | 
			
		|||
{
 | 
			
		||||
	const int cellW = (rect.w*BW_CELL_R) / 2;
 | 
			
		||||
	const int cellH = rect.h / 2;
 | 
			
		||||
	const int cellOff = (1.0-BW_CELL_R) * rect.w;
 | 
			
		||||
	const int cellOff = (1.0f-BW_CELL_R) * rect.w;
 | 
			
		||||
 | 
			
		||||
	if (x < cellOff)
 | 
			
		||||
		return -1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,7 +80,7 @@ struct SharedMidiState
 | 
			
		|||
			return;
 | 
			
		||||
 | 
			
		||||
		flSettings = fluid.new_settings();
 | 
			
		||||
		fluid.settings_setnum(flSettings, "synth.gain", 1.0);
 | 
			
		||||
		fluid.settings_setnum(flSettings, "synth.gain", 1.0f);
 | 
			
		||||
		fluid.settings_setnum(flSettings, "synth.sample-rate", SYNTH_SAMPLERATE);
 | 
			
		||||
		fluid.settings_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no");
 | 
			
		||||
		fluid.settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -172,7 +172,6 @@ void SharedState::initInstance(RGSSThreadData *threadData)
 | 
			
		|||
	 * Font depends on SharedState existing */
 | 
			
		||||
 | 
			
		||||
	rgssVersion = threadData->config.rgssVersion;
 | 
			
		||||
	Font::initDefaults();
 | 
			
		||||
 | 
			
		||||
	_globalIBO = new GlobalIBO();
 | 
			
		||||
	_globalIBO->ensureSize(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -183,6 +182,7 @@ void SharedState::initInstance(RGSSThreadData *threadData)
 | 
			
		|||
	try
 | 
			
		||||
	{
 | 
			
		||||
		SharedState::instance = new SharedState(threadData);
 | 
			
		||||
		Font::initDefaults(instance->p->fontState);
 | 
			
		||||
		defaultFont = new Font();
 | 
			
		||||
	}
 | 
			
		||||
	catch (const Exception &exc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,8 +123,8 @@ void SoundEmitter::play(const std::string &filename,
 | 
			
		|||
                        int volume,
 | 
			
		||||
                        int pitch)
 | 
			
		||||
{
 | 
			
		||||
	float _volume = clamp<int>(volume, 0, 100) / 100.f;
 | 
			
		||||
	float _pitch  = clamp<int>(pitch, 50, 150) / 100.f;
 | 
			
		||||
	float _volume = clamp<int>(volume, 0, 100) / 100.0f;
 | 
			
		||||
	float _pitch  = clamp<int>(pitch, 50, 150) / 100.0f;
 | 
			
		||||
 | 
			
		||||
	SoundBuffer *buffer = allocateBuffer(filename);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +184,44 @@ void SoundEmitter::stop()
 | 
			
		|||
		AL::Source::stop(alSrcs[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SoundOpenHandler : FileSystem::OpenHandler
 | 
			
		||||
{
 | 
			
		||||
	SoundBuffer *buffer;
 | 
			
		||||
 | 
			
		||||
	SoundOpenHandler()
 | 
			
		||||
	    : buffer(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool tryRead(SDL_RWops &ops, const char *ext)
 | 
			
		||||
	{
 | 
			
		||||
		Sound_Sample *sample = Sound_NewSample(&ops, ext, 0, STREAM_BUF_SIZE);
 | 
			
		||||
 | 
			
		||||
		if (!sample)
 | 
			
		||||
		{
 | 
			
		||||
			SDL_RWclose(&ops);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Do all of the decoding in the handler so we don't have
 | 
			
		||||
		 * to keep the source ops around */
 | 
			
		||||
		uint32_t decBytes = Sound_DecodeAll(sample);
 | 
			
		||||
		uint8_t sampleSize = formatSampleSize(sample->actual.format);
 | 
			
		||||
		uint32_t sampleCount = decBytes / sampleSize;
 | 
			
		||||
 | 
			
		||||
		buffer = new SoundBuffer;
 | 
			
		||||
		buffer->bytes = sampleSize * sampleCount;
 | 
			
		||||
 | 
			
		||||
		ALenum alFormat = chooseALFormat(sampleSize, sample->actual.channels);
 | 
			
		||||
 | 
			
		||||
		AL::Buffer::uploadData(buffer->alBuffer, alFormat, sample->buffer,
 | 
			
		||||
							   buffer->bytes, sample->actual.rate);
 | 
			
		||||
 | 
			
		||||
		Sound_FreeSample(sample);
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
 | 
			
		||||
{
 | 
			
		||||
	SoundBuffer *buffer = bufferHash.value(filename, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -199,40 +237,22 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
 | 
			
		|||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* Buffer not in cashe, needs to be loaded */
 | 
			
		||||
		SDL_RWops dataSource;
 | 
			
		||||
		char ext[8];
 | 
			
		||||
		/* Buffer not in cache, needs to be loaded */
 | 
			
		||||
		SoundOpenHandler handler;
 | 
			
		||||
		shState->fileSystem().openRead(handler, filename.c_str());
 | 
			
		||||
		buffer = handler.buffer;
 | 
			
		||||
 | 
			
		||||
		shState->fileSystem().openRead(dataSource, filename.c_str(),
 | 
			
		||||
		                               false, ext, sizeof(ext));
 | 
			
		||||
 | 
			
		||||
		Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, ext, 0, STREAM_BUF_SIZE);
 | 
			
		||||
 | 
			
		||||
		if (!sampleHandle)
 | 
			
		||||
		if (!buffer)
 | 
			
		||||
		{
 | 
			
		||||
			char buf[512];
 | 
			
		||||
			snprintf(buf, sizeof(buf), "Unable to decode sound: %s.%s: %s",
 | 
			
		||||
			         filename.c_str(), ext, Sound_GetError());
 | 
			
		||||
			snprintf(buf, sizeof(buf), "Unable to decode sound: %s: %s",
 | 
			
		||||
			         filename.c_str(), Sound_GetError());
 | 
			
		||||
			Debug() << buf;
 | 
			
		||||
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uint32_t decBytes = Sound_DecodeAll(sampleHandle);
 | 
			
		||||
		uint8_t sampleSize = formatSampleSize(sampleHandle->actual.format);
 | 
			
		||||
		uint32_t sampleCount = decBytes / sampleSize;
 | 
			
		||||
 | 
			
		||||
		buffer = new SoundBuffer;
 | 
			
		||||
		buffer->key = filename;
 | 
			
		||||
		buffer->bytes = sampleSize * sampleCount;
 | 
			
		||||
 | 
			
		||||
		ALenum alFormat = chooseALFormat(sampleSize, sampleHandle->actual.channels);
 | 
			
		||||
 | 
			
		||||
		AL::Buffer::uploadData(buffer->alBuffer, alFormat, sampleHandle->buffer,
 | 
			
		||||
							   buffer->bytes, sampleHandle->actual.rate);
 | 
			
		||||
 | 
			
		||||
		Sound_FreeSample(sampleHandle);
 | 
			
		||||
 | 
			
		||||
		uint32_t wouldBeBytes = bufferBytes + buffer->bytes;
 | 
			
		||||
 | 
			
		||||
		/* If memory limit is reached, delete lowest priority buffer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -109,7 +109,7 @@ struct SpritePrivate
 | 
			
		|||
		wave.amp = 0;
 | 
			
		||||
		wave.length = 180;
 | 
			
		||||
		wave.speed = 360;
 | 
			
		||||
		wave.phase = 0.0;
 | 
			
		||||
		wave.phase = 0.0f;
 | 
			
		||||
		wave.dirty = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,7 @@ struct SpritePrivate
 | 
			
		|||
		                     (srcRect->y + srcRect->height) +
 | 
			
		||||
		                     bitmap->height();
 | 
			
		||||
 | 
			
		||||
		efBushDepth = 1.0 - texBushDepth / bitmap->height();
 | 
			
		||||
		efBushDepth = 1.0f - texBushDepth / bitmap->height();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void onSrcRectChange()
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +194,7 @@ struct SpritePrivate
 | 
			
		|||
	void emitWaveChunk(SVertex *&vert, float phase, int width,
 | 
			
		||||
	                   float zoomY, int chunkY, int chunkLength)
 | 
			
		||||
	{
 | 
			
		||||
		float wavePos = phase + (chunkY / (float) wave.length) * M_PI * 2;
 | 
			
		||||
		float wavePos = phase + (chunkY / (float) wave.length) * (float) (M_PI * 2);
 | 
			
		||||
		float chunkX = sin(wavePos) * wave.amp;
 | 
			
		||||
 | 
			
		||||
		FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +261,7 @@ struct SpritePrivate
 | 
			
		|||
		wave.qArray.resize(!!firstLength + chunks + !!lastLength);
 | 
			
		||||
		SVertex *vert = &wave.qArray.vertices[0];
 | 
			
		||||
 | 
			
		||||
		float phase = (wave.phase * M_PI) / 180.f;
 | 
			
		||||
		float phase = (wave.phase * (float) M_PI) / 180.0f;
 | 
			
		||||
 | 
			
		||||
		if (firstLength > 0)
 | 
			
		||||
			emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,14 +51,14 @@ extern const int autotileVXRectsBN;
 | 
			
		|||
/* Waterfall (C) autotile patterns */
 | 
			
		||||
static const StaticRect autotileVXRectsC[] =
 | 
			
		||||
{
 | 
			
		||||
	{ 32.5, 0.5, 15, 31 },
 | 
			
		||||
	{ 16.5, 0.5, 15, 31 },
 | 
			
		||||
	{  0.0, 0.5, 15, 31 },
 | 
			
		||||
	{ 16.5, 0.5, 15, 31 },
 | 
			
		||||
	{ 32.5, 0.5, 15, 31 },
 | 
			
		||||
	{ 48.5, 0.5, 15, 31 },
 | 
			
		||||
	{  0.0, 0.5, 15, 31 },
 | 
			
		||||
	{ 48.5, 0.5, 15, 31 }
 | 
			
		||||
	{ 32.5f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{ 16.5f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{  0.0f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{ 16.5f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{ 32.5f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{ 48.5f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{  0.0f, 0.5f, 15.0f, 31.0f },
 | 
			
		||||
	{ 48.5f, 0.5f, 15.0f, 31.0f }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(autotileVXRectsC);
 | 
			
		||||
| 
						 | 
				
			
			@ -500,7 +500,7 @@ onTileA4(Reader &reader, int16_t tileID,
 | 
			
		|||
	Vec2i orig = blitsA4[0].dst;
 | 
			
		||||
	tileID -= 0x1700;
 | 
			
		||||
 | 
			
		||||
	const int offY[] = { 0, 3, 5, 8, 10, 13 };
 | 
			
		||||
	static const int offY[] = { 0, 3, 5, 8, 10, 13 };
 | 
			
		||||
 | 
			
		||||
	int patternID  = tileID % 0x30;
 | 
			
		||||
	int autotileID = tileID / 0x30;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,13 @@ wrap(int value, int range)
 | 
			
		|||
	return res < 0 ? res + range : res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline Vec2i
 | 
			
		||||
wrap(const Vec2i &value, int range)
 | 
			
		||||
{
 | 
			
		||||
	return Vec2i(wrap(value.x, range),
 | 
			
		||||
	             wrap(value.y, range));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int16_t
 | 
			
		||||
tableGetWrapped(const Table &t, int x, int y, int z = 0)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +61,16 @@ tableGetWrapped(const Table &t, int x, int y, int z = 0)
 | 
			
		|||
	             z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Calculate the tile x/y on which this pixel x/y lies */
 | 
			
		||||
static inline Vec2i
 | 
			
		||||
getTilePos(const Vec2i &pixelPos)
 | 
			
		||||
{
 | 
			
		||||
	/* Round the pixel position down to the nearest top left
 | 
			
		||||
	 * tile boundary, by masking off the lower 5 bits (2^5 = 32).
 | 
			
		||||
	 * Then divide by 32 to convert into tile units. */
 | 
			
		||||
	return (pixelPos & ~(32-1)) / 32;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum AtSubPos
 | 
			
		||||
{
 | 
			
		||||
	TopLeft          = 0,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -236,7 +236,7 @@ struct TilemapPrivate
 | 
			
		|||
	Table *mapData;
 | 
			
		||||
	Table *priorities;
 | 
			
		||||
	bool visible;
 | 
			
		||||
	Vec2i offset;
 | 
			
		||||
	Vec2i origin;
 | 
			
		||||
 | 
			
		||||
	Vec2i dispPos;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +294,6 @@ struct TilemapPrivate
 | 
			
		|||
		/* Used layers out of 'zlayers' (rest is hidden) */
 | 
			
		||||
		size_t activeLayers;
 | 
			
		||||
		Scene::Geometry sceneGeo;
 | 
			
		||||
		Vec2i sceneOffset;
 | 
			
		||||
	} elem;
 | 
			
		||||
 | 
			
		||||
	/* Affected by: autotiles, tileset */
 | 
			
		||||
| 
						 | 
				
			
			@ -394,7 +393,7 @@ struct TilemapPrivate
 | 
			
		|||
 | 
			
		||||
	void updateFlashMapViewport()
 | 
			
		||||
	{
 | 
			
		||||
		flashMap.setViewport(IntRect(viewpPos.x, viewpPos.y, viewpW, viewpH));
 | 
			
		||||
		flashMap.setViewport(IntRect(viewpPos, Vec2i(viewpW, viewpH)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateAtlasInfo()
 | 
			
		||||
| 
						 | 
				
			
			@ -442,13 +441,8 @@ struct TilemapPrivate
 | 
			
		|||
 | 
			
		||||
	void updateSceneGeometry(const Scene::Geometry &geo)
 | 
			
		||||
	{
 | 
			
		||||
		elem.sceneOffset = geo.offset();
 | 
			
		||||
		elem.sceneGeo = geo;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updatePosition()
 | 
			
		||||
	{
 | 
			
		||||
		dispPos = -(offset - viewpPos * 32) + elem.sceneOffset;
 | 
			
		||||
		mapViewportDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void invalidateAtlasSize()
 | 
			
		||||
| 
						 | 
				
			
			@ -698,7 +692,7 @@ struct TilemapPrivate
 | 
			
		|||
		int tileY = tsInd / 8;
 | 
			
		||||
 | 
			
		||||
		Vec2i texPos = TileAtlas::tileToAtlasCoor(tileX, tileY, atlas.efTilesetH, atlas.size.y);
 | 
			
		||||
		FloatRect texRect((float) texPos.x+.5, (float) texPos.y+.5, 31, 31);
 | 
			
		||||
		FloatRect texRect((float) texPos.x+0.5f, (float) texPos.y+0.5f, 31, 31);
 | 
			
		||||
		FloatRect posRect(x*32, y*32, 32, 32);
 | 
			
		||||
 | 
			
		||||
		SVertex v[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -898,38 +892,17 @@ struct TilemapPrivate
 | 
			
		|||
 | 
			
		||||
	void updateMapViewport()
 | 
			
		||||
	{
 | 
			
		||||
		int tileOX, tileOY;
 | 
			
		||||
		const Vec2i combOrigin = origin + elem.sceneGeo.orig;
 | 
			
		||||
		const Vec2i mvpPos = getTilePos(combOrigin);
 | 
			
		||||
 | 
			
		||||
		if (offset.x >= 0)
 | 
			
		||||
			tileOX = offset.x / 32;
 | 
			
		||||
		else
 | 
			
		||||
			tileOX = -(-(offset.x-31) / 32);
 | 
			
		||||
 | 
			
		||||
		if (offset.y >= 0)
 | 
			
		||||
			tileOY = offset.y / 32;
 | 
			
		||||
		else
 | 
			
		||||
			tileOY = -(-(offset.y-31) / 32);
 | 
			
		||||
 | 
			
		||||
		bool dirty = false;
 | 
			
		||||
 | 
			
		||||
		if (tileOX < viewpPos.x || tileOX + 21 > viewpPos.x + viewpW)
 | 
			
		||||
		{
 | 
			
		||||
			viewpPos.x = tileOX;
 | 
			
		||||
			dirty = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tileOY < viewpPos.y || tileOY + 16 > viewpPos.y + viewpH)
 | 
			
		||||
		{
 | 
			
		||||
			viewpPos.y = tileOY;
 | 
			
		||||
			dirty = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dirty)
 | 
			
		||||
		if (mvpPos != viewpPos)
 | 
			
		||||
		{
 | 
			
		||||
			viewpPos = mvpPos;
 | 
			
		||||
			buffersDirty = true;
 | 
			
		||||
			updateFlashMapViewport();
 | 
			
		||||
			updatePosition();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dispPos = elem.sceneGeo.rect.pos() - wrap(combOrigin, 32);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void prepare()
 | 
			
		||||
| 
						 | 
				
			
			@ -1024,7 +997,6 @@ void GroundLayer::drawInt()
 | 
			
		|||
void GroundLayer::onGeometryChange(const Scene::Geometry &geo)
 | 
			
		||||
{
 | 
			
		||||
	p->updateSceneGeometry(geo);
 | 
			
		||||
	p->updatePosition();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ZLayer::ZLayer(TilemapPrivate *p, Viewport *viewport)
 | 
			
		||||
| 
						 | 
				
			
			@ -1072,7 +1044,7 @@ void ZLayer::drawInt()
 | 
			
		|||
 | 
			
		||||
int ZLayer::calculateZ(TilemapPrivate *p, int index)
 | 
			
		||||
{
 | 
			
		||||
	return 32 * (index + p->viewpPos.y + 1) - p->offset.y;
 | 
			
		||||
	return 32 * (index + p->viewpPos.y + 1) - p->origin.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZLayer::initUpdateZ()
 | 
			
		||||
| 
						 | 
				
			
			@ -1172,8 +1144,8 @@ DEF_ATTR_RD_SIMPLE(Tilemap, MapData, Table*, p->mapData)
 | 
			
		|||
DEF_ATTR_RD_SIMPLE(Tilemap, FlashData, Table*, p->flashMap.getData())
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, Priorities, Table*, p->priorities)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, Visible, bool, p->visible)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->offset.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->offset.y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->origin.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->origin.y)
 | 
			
		||||
 | 
			
		||||
void Tilemap::setTileset(Bitmap *value)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1259,11 +1231,10 @@ void Tilemap::setOX(int value)
 | 
			
		|||
{
 | 
			
		||||
	guardDisposed();
 | 
			
		||||
 | 
			
		||||
	if (p->offset.x == value)
 | 
			
		||||
	if (p->origin.x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->offset.x = value;
 | 
			
		||||
	p->updatePosition();
 | 
			
		||||
	p->origin.x = value;
 | 
			
		||||
	p->mapViewportDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1271,11 +1242,10 @@ void Tilemap::setOY(int value)
 | 
			
		|||
{
 | 
			
		||||
	guardDisposed();
 | 
			
		||||
 | 
			
		||||
	if (p->offset.y == value)
 | 
			
		||||
	if (p->origin.y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->offset.y = value;
 | 
			
		||||
	p->updatePosition();
 | 
			
		||||
	p->origin.y = value;
 | 
			
		||||
	p->zOrderDirty = true;
 | 
			
		||||
	p->mapViewportDirty = true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,12 +57,12 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
 | 
			
		|||
 | 
			
		||||
	Table *mapData;
 | 
			
		||||
	Table *flags;
 | 
			
		||||
	Vec2i offset;
 | 
			
		||||
	Vec2i origin;
 | 
			
		||||
 | 
			
		||||
	Vec2i dispPos;
 | 
			
		||||
	/* Map viewport position */
 | 
			
		||||
	/* Subregion of the map that is drawn to screen (map viewport) */
 | 
			
		||||
	IntRect mapViewp;
 | 
			
		||||
	Vec2i sceneOffset;
 | 
			
		||||
	/* Position on screen the map subregion is drawn at */
 | 
			
		||||
	Vec2i dispPos;
 | 
			
		||||
	Scene::Geometry sceneGeo;
 | 
			
		||||
 | 
			
		||||
	std::vector<SVertex> groundVert;
 | 
			
		||||
| 
						 | 
				
			
			@ -179,49 +179,31 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
 | 
			
		|||
		TileAtlasVX::build(atlas, bitmaps);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updatePosition()
 | 
			
		||||
	{
 | 
			
		||||
		dispPos.x = -(offset.x - mapViewp.x * 32) + sceneOffset.x;
 | 
			
		||||
		dispPos.y = -(offset.y - mapViewp.y * 32) + sceneOffset.y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateMapViewport()
 | 
			
		||||
	{
 | 
			
		||||
		int tileOX, tileOY;
 | 
			
		||||
		/* Note: We include one extra row at the top above
 | 
			
		||||
		 * the normal map viewport to ensure the legs of table
 | 
			
		||||
		 * tiles off screen are properly drawn */
 | 
			
		||||
 | 
			
		||||
		Vec2i offs(offset.x-sceneOffset.x, offset.y-sceneOffset.y);
 | 
			
		||||
		IntRect newMvp;
 | 
			
		||||
 | 
			
		||||
		if (offs.x >= 0)
 | 
			
		||||
			tileOX = offs.x / 32;
 | 
			
		||||
		else
 | 
			
		||||
			tileOX = -(-(offs.x-31) / 32);
 | 
			
		||||
		const Vec2i combOrigin = origin + sceneGeo.orig;
 | 
			
		||||
		const Vec2i geoSize = sceneGeo.rect.size();
 | 
			
		||||
 | 
			
		||||
		if (offs.y >= 0)
 | 
			
		||||
			tileOY = offs.y / 32;
 | 
			
		||||
		else
 | 
			
		||||
			tileOY = -(-(offs.y-31) / 32);
 | 
			
		||||
		newMvp.setPos(getTilePos(combOrigin) - Vec2i(0, 1));
 | 
			
		||||
 | 
			
		||||
		bool dirty = false;
 | 
			
		||||
		/* Ensure that the size is big enough to cover the whole viewport,
 | 
			
		||||
		 * and add one tile row/column as a buffer for scrolling */
 | 
			
		||||
		newMvp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1, 2));
 | 
			
		||||
 | 
			
		||||
		if (tileOX < mapViewp.x || tileOX > mapViewp.x)
 | 
			
		||||
		{
 | 
			
		||||
			mapViewp.x = tileOX;
 | 
			
		||||
			dirty = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tileOY < mapViewp.y || tileOY > mapViewp.y)
 | 
			
		||||
		{
 | 
			
		||||
			mapViewp.y = tileOY;
 | 
			
		||||
			dirty = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dirty)
 | 
			
		||||
		if (newMvp != mapViewp)
 | 
			
		||||
		{
 | 
			
		||||
			mapViewp = newMvp;
 | 
			
		||||
			flashMap.setViewport(newMvp);
 | 
			
		||||
			buffersDirty = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		updatePosition();
 | 
			
		||||
		flashMap.setViewport(mapViewp);
 | 
			
		||||
		dispPos = sceneGeo.rect.pos() - wrap(combOrigin, 32) - Vec2i(0, 32);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static size_t quadBytes(size_t quads)
 | 
			
		||||
| 
						 | 
				
			
			@ -366,10 +348,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
 | 
			
		|||
 | 
			
		||||
	void onGeometryChange(const Scene::Geometry &geo)
 | 
			
		||||
	{
 | 
			
		||||
		const Vec2i geoSize = geo.rect.size();
 | 
			
		||||
		mapViewp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1));
 | 
			
		||||
 | 
			
		||||
		sceneOffset = geo.offset();
 | 
			
		||||
		sceneGeo = geo;
 | 
			
		||||
 | 
			
		||||
		buffersDirty = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +358,7 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
 | 
			
		|||
 | 
			
		||||
	/* TileAtlasVX::Reader */
 | 
			
		||||
	void onQuads(const FloatRect *t, const FloatRect *p,
 | 
			
		||||
	              size_t n, bool overPlayer)
 | 
			
		||||
	             size_t n, bool overPlayer)
 | 
			
		||||
	{
 | 
			
		||||
		SVertex *vert = allocVert(overPlayer ? aboveVert : groundVert, n*4);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -467,8 +445,8 @@ TilemapVX::BitmapArray &TilemapVX::getBitmapArray()
 | 
			
		|||
DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashMap.getData())
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->offset.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->origin.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->origin.y)
 | 
			
		||||
 | 
			
		||||
Viewport *TilemapVX::getViewport() const
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -541,10 +519,10 @@ void TilemapVX::setOX(int value)
 | 
			
		|||
{
 | 
			
		||||
	guardDisposed();
 | 
			
		||||
 | 
			
		||||
	if (p->offset.x == value)
 | 
			
		||||
	if (p->origin.x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->offset.x = value;
 | 
			
		||||
	p->origin.x = value;
 | 
			
		||||
	p->mapViewportDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -552,10 +530,10 @@ void TilemapVX::setOY(int value)
 | 
			
		|||
{
 | 
			
		||||
	guardDisposed();
 | 
			
		||||
 | 
			
		||||
	if (p->offset.y == value)
 | 
			
		||||
	if (p->origin.y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->offset.y = value;
 | 
			
		||||
	p->origin.y = value;
 | 
			
		||||
	p->mapViewportDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -130,7 +130,7 @@ private:
 | 
			
		|||
		if (rotation < 0)
 | 
			
		||||
			rotation += 360;
 | 
			
		||||
 | 
			
		||||
		float angle  = rotation * 3.141592654f / 180.f;
 | 
			
		||||
		float angle  = rotation * 3.141592654f / 180.0f;
 | 
			
		||||
		float cosine = (float) cos(angle);
 | 
			
		||||
		float sine   = (float) sin(angle);
 | 
			
		||||
		float sxc    = scale.x * cosine;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -642,7 +642,7 @@ struct WindowPrivate
 | 
			
		|||
 | 
			
		||||
		if (active && cursorVert.vert)
 | 
			
		||||
		{
 | 
			
		||||
			float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0;
 | 
			
		||||
			float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0f;
 | 
			
		||||
 | 
			
		||||
			cursorVert.setAlpha(alpha);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -651,7 +651,7 @@ struct WindowPrivate
 | 
			
		|||
 | 
			
		||||
		if (pause && pauseAniVert.vert)
 | 
			
		||||
		{
 | 
			
		||||
			float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0;
 | 
			
		||||
			float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0f;
 | 
			
		||||
			FloatRect frameRect = pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]];
 | 
			
		||||
 | 
			
		||||
			pauseAniVert.setAlpha(alpha);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -482,7 +482,7 @@ struct WindowVXPrivate
 | 
			
		|||
	void updateBaseQuad()
 | 
			
		||||
	{
 | 
			
		||||
		const FloatRect tex(0, 0, geo.w, geo.h);
 | 
			
		||||
		const FloatRect pos(0, (geo.h / 2.0) * (1 - openness.norm),
 | 
			
		||||
		const FloatRect pos(0, (geo.h / 2.0f) * (1.0f - openness.norm),
 | 
			
		||||
		                    geo.w, geo.h * openness.norm);
 | 
			
		||||
 | 
			
		||||
		base.quad.setTexPosRect(tex, pos);
 | 
			
		||||
| 
						 | 
				
			
			@ -633,7 +633,7 @@ struct WindowVXPrivate
 | 
			
		|||
		Quad::setTexRect(pauseVert, pauseSrc[pauseQuad[pauseQuadIdx]]);
 | 
			
		||||
 | 
			
		||||
		/* Set opacity */
 | 
			
		||||
		Quad::setColor(pauseVert, Vec4(1, 1, 1, pauseAlpha[pauseAlphaIdx] / 255.0));
 | 
			
		||||
		Quad::setColor(pauseVert, Vec4(1, 1, 1, pauseAlpha[pauseAlphaIdx] / 255.0f));
 | 
			
		||||
 | 
			
		||||
		ctrlVertArrayDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -643,7 +643,7 @@ struct WindowVXPrivate
 | 
			
		|||
		if (cursorVert.count() == 0)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		Vec4 color(1, 1, 1, cursorAlpha[cursorAlphaIdx] / 255.0);
 | 
			
		||||
		Vec4 color(1, 1, 1, cursorAlpha[cursorAlphaIdx] / 255.0f);
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < cursorVert.count(); ++i)
 | 
			
		||||
			Quad::setColor(&cursorVert.vertices[i*4], color);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue