Merge branch 'master' of /home/Ancurio/programming/C++/mkxp
This commit is contained in:
commit
d9f13c39e9
|
@ -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…
Reference in New Issue