Merge branch 'master' of /home/Ancurio/programming/C++/mkxp

Conflicts:
	src/config.h
This commit is contained in:
Jonas Kulla 2015-02-21 02:13:40 +01:00
commit d07309c8f9
85 changed files with 4901 additions and 3428 deletions

View file

@ -238,5 +238,6 @@ inline ALenum chooseALFormat(int sampleSize, int channelCount)
#define AUDIO_SLEEP 10
#define STREAM_BUF_SIZE 32768
#define GLOBAL_VOLUME 0.8
#endif // ALUTIL_H

View file

@ -23,10 +23,13 @@
#include "sharedstate.h"
#include "sharedmidistate.h"
#include "eventthread.h"
#include "filesystem.h"
#include "exception.h"
#include "aldatasource.h"
#include "fluid-fun.h"
#include "sdl-util.h"
#include "debugwriter.h"
#include <SDL_mutex.h>
#include <SDL_thread.h>
@ -122,6 +125,9 @@ void ALStream::stop()
void ALStream::play(float offset)
{
if (!source)
return;
checkStopped();
switch (state)
@ -195,8 +201,8 @@ void ALStream::closeSource()
void ALStream::openSource(const std::string &filename)
{
const char *ext;
shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext);
char ext[8];
shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext));
needsRewind.clear();
/* Try to read ogg file signature */
@ -204,24 +210,36 @@ void ALStream::openSource(const std::string &filename)
SDL_RWread(&srcOps, sig, 1, 4);
SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
if (!strcmp(sig, "OggS"))
try
{
source = createVorbisSource(srcOps, looped);
return;
}
if (!strcmp(sig, "MThd"))
{
shState->midiState().initIfNeeded(shState->config());
if (HAVE_FLUID)
if (!strcmp(sig, "OggS"))
{
source = createMidiSource(srcOps, looped);
source = createVorbisSource(srcOps, looped);
return;
}
}
source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped);
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)
{
char buf[512];
snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s.%s: %s",
filename.c_str(), ext, e.msg.c_str());
buf[sizeof(buf)-1] = '\0';
Debug() << buf;
}
}
void ALStream::stopStream()
@ -361,6 +379,8 @@ void ALStream::streamData()
* refill and queue them up again */
while (true)
{
shState->rtData().syncPoint.passSecondarySync();
ALint procBufs = AL::Source::getProcBufferCount(alSrc);
while (procBufs--)

View file

@ -25,6 +25,7 @@
#include "soundemitter.h"
#include "sharedstate.h"
#include "sharedmidistate.h"
#include "eventthread.h"
#include "sdl-util.h"
#include <string>
@ -40,6 +41,8 @@ struct AudioPrivate
SoundEmitter se;
SyncPoint &syncPoint;
/* The 'MeWatch' is responsible for detecting
* a playing ME, quickly fading out the BGM and
* keeping it paused/stopped while the ME plays,
@ -60,11 +63,12 @@ struct AudioPrivate
MeWatchState state;
} meWatch;
AudioPrivate(const Config &conf)
AudioPrivate(RGSSThreadData &rtData)
: bgm(ALStream::Looped, "bgm"),
bgs(ALStream::Looped, "bgs"),
me(ALStream::NotLooped, "me"),
se(conf)
se(rtData.config),
syncPoint(rtData.syncPoint)
{
meWatch.state = MeNotPlaying;
meWatch.thread = createSDLThread
@ -84,6 +88,8 @@ struct AudioPrivate
while (true)
{
syncPoint.passSecondarySync();
if (meWatch.termReq)
return;
@ -231,8 +237,8 @@ struct AudioPrivate
}
};
Audio::Audio(const Config &conf)
: p(new AudioPrivate(conf))
Audio::Audio(RGSSThreadData &rtData)
: p(new AudioPrivate(rtData))
{}

View file

@ -33,7 +33,7 @@
* quite make out their meaning yet) */
struct AudioPrivate;
struct Config;
struct RGSSThreadData;
class Audio
{
@ -70,7 +70,7 @@ public:
void reset();
private:
Audio(const Config &conf);
Audio(RGSSThreadData &rtData);
~Audio();
friend struct SharedStatePrivate;

View file

@ -252,7 +252,7 @@ float AudioStream::playingOffset()
void AudioStream::updateVolume()
{
float vol = 1.0;
float vol = GLOBAL_VOLUME;
for (size_t i = 0; i < VolumeTypeCount; ++i)
vol *= volumes[i];

View file

@ -4,196 +4,196 @@ extern const StaticRect autotileRects[] =
{
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 16.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 16.5, 96.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 0.5, 15, 15 },
{ 16.5, 0.5, 15, 15 },
{ 16.5, 16.5, 15, 15 },
{ 0.5, 16.5, 15, 15 }
{ 0.5, 16.5, 15, 15 },
{ 16.5, 16.5, 15, 15 }
};
extern const int autotileRectsN = sizeof(autotileRects) / sizeof(autotileRects[0]);

View file

@ -52,6 +52,8 @@
"Operation not supported for mega surfaces"); \
}
#define OUTLINE_SIZE 1
/* Normalize (= ensure width and
* height are positive) */
static IntRect normalizedRect(const IntRect &rect)
@ -248,9 +250,10 @@ struct BitmapPrivate
Bitmap::Bitmap(const char *filename)
{
SDL_RWops ops;
const char *extension;
shState->fileSystem().openRead(ops, filename, FileSystem::Image, false, &extension);
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, extension);
char ext[8];
shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext));
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext);
if (!imgSurf)
throw Exception(Exception::SDLError, "Error loading image '%s': %s",
@ -317,6 +320,7 @@ Bitmap::Bitmap(const char *filename)
/* Mega surface */
p = new BitmapPrivate(this);
p->megaSurface = imgSurf;
SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE);
}
else if (isCrop)
{
@ -487,14 +491,46 @@ void Bitmap::stretchBlt(const IntRect &destRect,
if (opacity == 0)
return;
if (source.megaSurface())
SDL_Surface *srcSurf = source.megaSurface();
if (srcSurf && shState->config().subImageFix)
{
/* Blit from software surface, for broken GL drivers */
Vec2i gpTexSize;
shState->ensureTexSize(sourceRect.w, sourceRect.h, gpTexSize);
shState->bindTex();
GLMeta::subRectImageUpload(srcSurf->w, sourceRect.x, sourceRect.y, 0, 0,
sourceRect.w, sourceRect.h, srcSurf, GL_RGBA);
GLMeta::subRectImageEnd();
SimpleShader &shader = shState->shaders().simple;
shader.bind();
shader.setTranslation(Vec2i());
shader.setTexSize(gpTexSize);
p->pushSetViewport(shader);
p->bindFBO();
Quad &quad = shState->gpQuad();
quad.setTexRect(FloatRect(0, 0, sourceRect.w, sourceRect.h));
quad.setPosRect(destRect);
p->blitQuad(quad);
p->popViewport();
p->addTaintedArea(destRect);
p->onModified();
return;
}
else if (srcSurf)
{
/* Blit from software surface */
/* Don't do transparent blits for now */
if (opacity < 255)
source.ensureNonMega();
SDL_Surface *srcSurf = source.megaSurface();
SDL_Rect srcRect = sourceRect;
SDL_Rect dstRect = destRect;
SDL_Rect btmRect = { 0, 0, width(), height() };
@ -510,26 +546,25 @@ void Bitmap::stretchBlt(const IntRect &destRect,
SDL_Surface *blitTemp =
SDL_CreateRGBSurface(0, destRect.w, destRect.h, bpp, rMask, gMask, bMask, aMask);
// FXIME: This is supposed to be a scaled blit, put SDL2 for some reason
// makes the source surface unusable after BlitScaled() is called. Investigate!
SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0);
SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0);
TEX::bind(p->gl.tex);
if (bltRect.w == dstRect.w && bltRect.h == dstRect.h)
{
/* Dest rectangle lies within bounding box */
TEX::uploadSubImage(destRect.x, destRect.y,
destRect.w, destRect.h,
blitTemp->pixels, GL_RGBA);
}
else
{
/* Clipped blit */
GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y,
bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA);
GLMeta::subRectImageEnd();
}
SDL_FreeSurface(blitTemp);
p->onModified();
@ -581,7 +616,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
}
p->addTaintedArea(destRect);
p->onModified();
}
@ -1057,6 +1091,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
TTF_Font *font = p->font->getSdlFont();
const Color &fontColor = p->font->getColor();
const Color &outColor = p->font->getOutColor();
SDL_Color c = fontColor.toSDLColor();
c.a = 255;
@ -1072,11 +1107,34 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888);
// While real outlining is not yet here, use shadow
// as a replacement to at least make text legible
if (p->font->getShadow() || p->font->getOutline())
if (p->font->getShadow())
applyShadow(txtSurf, *p->format, c);
/* outline using TTF_Outline and blending it together with SDL_BlitSurface
* FIXME: outline is forced to have the same opacity as the font color */
if (p->font->getOutline())
{
SDL_Color co = outColor.toSDLColor();
co.a = 255;
SDL_Surface *outline;
/* set the next font render to render the outline */
TTF_SetFontOutline(font, OUTLINE_SIZE);
if (shState->rtData().config.solidFonts)
outline = TTF_RenderUTF8_Solid(font, str, co);
else
outline = TTF_RenderUTF8_Blended(font, str, co);
p->ensureFormat(outline, SDL_PIXELFORMAT_ABGR8888);
SDL_Rect outRect = {OUTLINE_SIZE, OUTLINE_SIZE, txtSurf->w, txtSurf->h};
SDL_SetSurfaceBlendMode(txtSurf, SDL_BLENDMODE_BLEND);
SDL_BlitSurface(txtSurf, NULL, outline, &outRect);
SDL_FreeSurface(txtSurf);
txtSurf = outline;
/* reset outline to 0 */
TTF_SetFontOutline(font, 0);
}
int alignX = rect.x;
switch (align)
@ -1113,7 +1171,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
if (fastBlit)
{
if (squeeze == 1.0)
if (squeeze == 1.0 && !shState->config().subImageFix)
{
/* Even faster: upload directly to bitmap texture.
* We have to make sure the posRect lies within the texture

View file

@ -1 +1 @@
#include "../liberation.ttf.xxd"
#include "liberation.ttf.xxd"

View file

@ -32,6 +32,7 @@
#include "debugwriter.h"
#include "util.h"
#include "sdl-util.h"
#ifdef INI_ENCODING
extern "C" {
@ -123,6 +124,10 @@ static bool validUtf8(const char *string)
static std::string prefPath(const char *org, const char *app)
{
char *path = SDL_GetPrefPath(org, app);
if (!path)
return std::string();
std::string str(path);
SDL_free(path);
@ -135,65 +140,47 @@ namespace po = boost::program_options;
#define CONF_FILE "mkxp.conf"
Config::Config()
: rgssVersion(0),
debugMode(false),
winResizable(false),
fullscreen(false),
fixedAspectRatio(true),
smoothScaling(false),
vsync(false),
defScreenW(0),
defScreenH(0),
fixedFramerate(0),
frameSkip(true),
solidFonts(false),
gameFolder("."),
anyAltToggleFS(false),
enableReset(true),
allowSymlinks(false),
pathCache(true),
useScriptNames(false)
{
midi.chorus = false;
midi.reverb = false;
SE.sourceCount = 6;
}
{}
void Config::read(int argc, char *argv[])
{
#define PO_DESC_ALL \
PO_DESC(rgssVersion, int) \
PO_DESC(debugMode, bool) \
PO_DESC(winResizable, bool) \
PO_DESC(fullscreen, bool) \
PO_DESC(fixedAspectRatio, bool) \
PO_DESC(smoothScaling, bool) \
PO_DESC(vsync, bool) \
PO_DESC(defScreenW, int) \
PO_DESC(defScreenH, int) \
PO_DESC(fixedFramerate, int) \
PO_DESC(frameSkip, bool) \
PO_DESC(solidFonts, bool) \
PO_DESC(gameFolder, std::string) \
PO_DESC(anyAltToggleFS, bool) \
PO_DESC(enableReset, bool) \
PO_DESC(allowSymlinks, bool) \
PO_DESC(dataPathOrg, std::string) \
PO_DESC(dataPathApp, std::string) \
PO_DESC(iconPath, std::string) \
PO_DESC(titleLanguage, std::string) \
PO_DESC(midi.soundFont, std::string) \
PO_DESC(midi.chorus, bool) \
PO_DESC(midi.reverb, bool) \
PO_DESC(SE.sourceCount, int) \
PO_DESC(customScript, std::string) \
PO_DESC(pathCache, bool) \
PO_DESC(useScriptNames, bool)
PO_DESC(rgssVersion, int, 0) \
PO_DESC(debugMode, bool, false) \
PO_DESC(printFPS, bool, false) \
PO_DESC(winResizable, bool, false) \
PO_DESC(fullscreen, bool, false) \
PO_DESC(fixedAspectRatio, bool, true) \
PO_DESC(smoothScaling, bool, false) \
PO_DESC(vsync, bool, false) \
PO_DESC(defScreenW, int, 0) \
PO_DESC(defScreenH, int, 0) \
PO_DESC(fixedFramerate, int, 0) \
PO_DESC(frameSkip, bool, true) \
PO_DESC(syncToRefreshrate, bool, false) \
PO_DESC(solidFonts, bool, false) \
PO_DESC(subImageFix, bool, false) \
PO_DESC(gameFolder, std::string, ".") \
PO_DESC(anyAltToggleFS, bool, false) \
PO_DESC(enableReset, bool, true) \
PO_DESC(allowSymlinks, bool, false) \
PO_DESC(dataPathOrg, std::string, "") \
PO_DESC(dataPathApp, std::string, "") \
PO_DESC(iconPath, std::string, "") \
PO_DESC(execName, std::string, "Game") \
PO_DESC(titleLanguage, std::string, "") \
PO_DESC(midi.soundFont, std::string, "") \
PO_DESC(midi.chorus, bool, false) \
PO_DESC(midi.reverb, bool, false) \
PO_DESC(SE.sourceCount, int, 6) \
PO_DESC(customScript, std::string, "") \
PO_DESC(pathCache, bool, true) \
PO_DESC(useScriptNames, bool, false)
// Not gonna take your shit boost
#define GUARD_ALL( exp ) try { exp } catch(...) {}
#define PO_DESC(key, type) (#key, po::value< type >()->default_value(key))
#define PO_DESC(key, type, def) (#key, po::value< type >()->default_value(def))
po::options_description podesc;
podesc.add_options()
@ -219,26 +206,23 @@ void Config::read(int argc, char *argv[])
}
/* Parse configuration file */
std::ifstream confFile;
confFile.open(CONF_FILE);
SDLRWStream confFile(CONF_FILE, "r");
if (confFile)
{
try
{
po::store(po::parse_config_file(confFile, podesc, true), vm);
po::store(po::parse_config_file(confFile.stream(), podesc, true), vm);
po::notify(vm);
}
catch (po::error &error)
{
Debug() << CONF_FILE":" << error.what();
}
confFile.close();
}
#undef PO_DESC
#define PO_DESC(key, type) GUARD_ALL( key = vm[#key].as< type >(); )
#define PO_DESC(key, type, def) GUARD_ALL( key = vm[#key].as< type >(); )
PO_DESC_ALL;
@ -349,16 +333,26 @@ void Config::readGameINI()
("Game.Scripts", po::value<std::string>())
;
std::string iniPath = gameFolder + "/Game.ini";
std::ifstream iniFile;
iniFile.open((iniPath).c_str());
po::variables_map vm;
po::store(po::parse_config_file(iniFile, podesc, true), vm);
po::notify(vm);
std::string iniFilename = execName + ".ini";
SDLRWStream iniFile(iniFilename.c_str(), "r");
iniFile.close();
if (iniFile)
{
try
{
po::store(po::parse_config_file(iniFile.stream(), podesc, true), vm);
po::notify(vm);
}
catch (po::error &error)
{
Debug() << iniFilename + ":" << error.what();
}
}
else
{
Debug() << "FAILED to open" << iniFilename;
}
GUARD_ALL( game.title = vm["Game.Title"].as<std::string>(); );
GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); );

View file

@ -29,6 +29,49 @@ struct CropTexture
{
std::string filename;
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
@ -36,6 +79,7 @@ struct Config
int rgssVersion;
bool debugMode;
bool printFPS;
bool winResizable;
bool fullscreen;
@ -48,9 +92,12 @@ struct Config
int fixedFramerate;
bool frameSkip;
bool syncToRefreshrate;
bool solidFonts;
bool subImageFix;
std::string gameFolder;
bool anyAltToggleFS;
bool enableReset;
@ -61,6 +108,7 @@ struct Config
std::string dataPathApp;
std::string iconPath;
std::string execName;
std::string titleLanguage;
struct

View file

@ -26,6 +26,11 @@
#include <sstream>
#include <vector>
#ifdef __ANDROID__
#include <android/log.h>
#endif
/* A cheap replacement for qDebug() */
class Debug
@ -56,7 +61,11 @@ public:
~Debug()
{
std::clog << buf.str() << std::endl;
#ifdef __ANDROID__
__android_log_write(ANDROID_LOG_DEBUG, "mkxp", buf.str().c_str());
#else
std::cerr << buf.str() << std::endl;
#endif
}
private:

View file

@ -60,6 +60,11 @@ struct Vec4
{
return (x == other.x && y == other.y && z == other.z && w == other.w);
}
bool xyzHasEffect() const
{
return (x != 0.0 || y != 0.0 || z != 0.0);
}
};
struct Vec2i
@ -74,19 +79,68 @@ struct Vec2i
: x(x), y(y)
{}
explicit Vec2i(int xy)
: x(xy), y(xy)
{}
bool operator==(const Vec2i &other) const
{
return x == other.x && y == other.y;
}
Vec2i &operator+=(const Vec2i &other)
Vec2i &operator+=(const Vec2i &value)
{
x += other.x;
y += other.y;
x += value.x;
y += value.y;
return *this;
}
Vec2i &operator-=(const Vec2i &value)
{
x -= value.x;
y -= value.y;
return *this;
}
Vec2i operator+(const Vec2i &value) const
{
return Vec2i(x + value.x, y + value.y);
}
Vec2i operator-(const Vec2i &value) const
{
return Vec2i(x - value.x, y - value.y);
}
template<typename T>
Vec2i operator*(T value) const
{
return Vec2i(x * value, y * value);
}
template<typename T>
Vec2i operator/(T value) const
{
return Vec2i(x / value, y / value);
}
Vec2i operator%(int value) const
{
return Vec2i(x % value, y % value);
}
Vec2i operator-() const
{
return Vec2i(-x, -y);
}
Vec2i operator!() const
{
return Vec2i(!x, !y);
}
operator Vec2() const
{
return Vec2(x, y);
@ -108,6 +162,14 @@ struct IntRect : SDL_Rect
this->h = h;
}
IntRect(const Vec2i &pos, const Vec2i &size)
{
x = pos.x;
y = pos.y;
w = size.x;
h = size.y;
}
bool operator==(const IntRect &other) const
{
return (x == other.x && y == other.y &&
@ -124,10 +186,24 @@ struct IntRect : SDL_Rect
return Vec2i(w, h);
}
operator SDL_Rect() const
void setPos(const Vec2i &value)
{
SDL_Rect r = { x, y, w, h };
return r;
x = value.x;
y = value.y;
}
void setSize(const Vec2i &value)
{
w = value.x;
h = value.y;
}
bool encloses(const IntRect &o) const
{
return (x <= o.x &&
y <= o.y &&
x+w >= o.x+o.w &&
y+h >= o.y+o.h);
}
};
@ -163,35 +239,10 @@ struct FloatRect
Vec2 topRight() const { return Vec2(x+w, y); }
Vec2 bottomRight() const { return Vec2(x+w, y+h); }
void shrinkHalf()
{
x += 0.5;
y += 0.5;
w -= 1.0;
h -= 1.0;
}
FloatRect vFlipped() const
{
return FloatRect(x, y+h, w, -h);
}
FloatRect hFlipped() const
{
return FloatRect(x+w, y, -w, h);
}
Vec2 corner(int i) const
{
switch (i)
{
case 0 : return topLeft();
case 1 : return topRight();
case 2 : return bottomRight();
case 3 : return bottomLeft();
default : return Vec2();
}
}
};
/* Value between 0 and 255 with internal

View file

@ -105,12 +105,10 @@ int Color::serialSize() const
void Color::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, alpha);
writeDouble(&buffer, red);
writeDouble(&buffer, green);
writeDouble(&buffer, blue);
writeDouble(&buffer, alpha);
}
Color *Color::deserialize(const char *data, int len)
@ -119,12 +117,11 @@ Color *Color::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Color: Serialized data invalid");
Color *c = new Color();
uint i = 0;
c->red = read_double(data, i);
c->green = read_double(data, i);
c->blue = read_double(data, i);
c->alpha = read_double(data, i);
c->red = readDouble(&data);
c->green = readDouble(&data);
c->blue = readDouble(&data);
c->alpha = readDouble(&data);
c->updateInternal();
return c;
@ -241,12 +238,10 @@ int Tone::serialSize() const
void Tone::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, gray);
writeDouble(&buffer, red);
writeDouble(&buffer, green);
writeDouble(&buffer, blue);
writeDouble(&buffer, gray);
}
Tone *Tone::deserialize(const char *data, int len)
@ -255,12 +250,11 @@ Tone *Tone::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Tone: Serialized data invalid");
Tone *t = new Tone();
uint i = 0;
t->red = read_double(data, i);
t->green = read_double(data, i);
t->blue = read_double(data, i);
t->gray = read_double(data, i);
t->red = readDouble(&data);
t->green = readDouble(&data);
t->blue = readDouble(&data);
t->gray = readDouble(&data);
t->updateInternal();
return t;
@ -390,12 +384,10 @@ int Rect::serialSize() const
void Rect::serialize(char *buffer) const
{
char *buf = buffer;
write_int32(&buf, x);
write_int32(&buf, y);
write_int32(&buf, width);
write_int32(&buf, height);
writeInt32(&buffer, x);
writeInt32(&buffer, y);
writeInt32(&buffer, width);
writeInt32(&buffer, height);
}
Rect *Rect::deserialize(const char *data, int len)
@ -404,12 +396,11 @@ Rect *Rect::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Rect: Serialized data invalid");
Rect *r = new Rect();
uint i = 0;
r->x = read_int32(data, i);
r->y = read_int32(data, i);
r->width = read_int32(data, i);
r->height = read_int32(data, i);
r->x = readInt32(&data);
r->y = readInt32(&data);
r->width = readInt32(&data);
r->height = readInt32(&data);
return r;
}

View file

@ -26,25 +26,51 @@
#include <SDL_messagebox.h>
#include <SDL_timer.h>
#include <SDL_thread.h>
#include <SDL_touch.h>
#include <alext.h>
#include "sharedstate.h"
#include "graphics.h"
#include "settingsmenu.h"
#include "al-util.h"
#include "debugwriter.h"
#include <string.h>
uint8_t EventThread::keyStates[] = { false };
typedef void (ALC_APIENTRY *LPALCDEVICEPAUSESOFT) (ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCDEVICERESUMESOFT) (ALCdevice *device);
EventThread::JoyState EventThread::joyState =
{
{ 0 }, { false }
};
#define AL_DEVICE_PAUSE_FUN \
AL_FUN(DevicePause, LPALCDEVICEPAUSESOFT) \
AL_FUN(DeviceResume, LPALCDEVICERESUMESOFT)
EventThread::MouseState EventThread::mouseState =
struct ALCFunctions
{
0, 0, false, { false }
};
#define AL_FUN(name, type) type name;
AL_DEVICE_PAUSE_FUN
#undef AL_FUN
} static alc;
static void
initALCFunctions(ALCdevice *alcDev)
{
if (!strstr(alcGetString(alcDev, ALC_EXTENSIONS), "ALC_SOFT_pause_device"))
return;
Debug() << "ALC_SOFT_pause_device present";
#define AL_FUN(name, type) alc. name = (type) alcGetProcAddress(alcDev, "alc" #name "SOFT");
AL_DEVICE_PAUSE_FUN;
#undef AL_FUN
}
#define HAVE_ALC_DEVICE_PAUSE alc.DevicePause
uint8_t EventThread::keyStates[];
EventThread::JoyState EventThread::joyState;
EventThread::MouseState EventThread::mouseState;
EventThread::TouchState EventThread::touchState;
/* User event codes */
enum
@ -80,19 +106,24 @@ void EventThread::process(RGSSThreadData &rtData)
{
SDL_Event event;
SDL_Window *win = rtData.window;
WindowSizeNotify &windowSizeMsg = rtData.windowSizeMsg;
UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg;
initALCFunctions(rtData.alcDev);
SDL_SetEventFilter(eventFilter, &rtData);
fullscreen = rtData.config.fullscreen;
int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
fps.lastFrame = SDL_GetPerformanceCounter();
fps.displayCounter = 0;
fps.displaying = false;
fps.immInitFlag = false;
fps.immFiniFlag = false;
fps.acc = 0;
fps.accDiv = 0;
if (rtData.config.printFPS)
fps.sendUpdates.set();
bool displayingFPS = false;
bool cursorInWindow = false;
bool windowFocused = false;
@ -109,6 +140,11 @@ void EventThread::process(RGSSThreadData &rtData)
bool resetting = false;
int winW, winH;
int i;
SDL_GetWindowSize(win, &winW, &winH);
SettingsMenu *sMenu = 0;
while (true)
@ -132,14 +168,36 @@ void EventThread::process(RGSSThreadData &rtData)
continue;
}
/* Preselect and discard unwanted events here */
switch (event.type)
{
case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
case SDL_MOUSEMOTION :
if (event.button.which == SDL_TOUCH_MOUSEID)
continue;
break;
case SDL_FINGERDOWN :
case SDL_FINGERUP :
case SDL_FINGERMOTION :
if (event.tfinger.fingerId >= MAX_FINGERS)
continue;
break;
}
/* Now process the rest */
switch (event.type)
{
case SDL_WINDOWEVENT :
switch (event.window.event)
{
case SDL_WINDOWEVENT_SIZE_CHANGED :
windowSizeMsg.notifyChange(event.window.data1,
event.window.data2);
winW = event.window.data1;
winH = event.window.data2;
windowSizeMsg.post(Vec2i(winW, winH));
resetInputStates();
break;
case SDL_WINDOWEVENT_ENTER :
@ -210,14 +268,18 @@ void EventThread::process(RGSSThreadData &rtData)
if (event.key.keysym.scancode == SDL_SCANCODE_F2)
{
if (!fps.displaying)
if (!displayingFPS)
{
fps.immInitFlag = true;
fps.displaying = true;
fps.immInitFlag.set();
fps.sendUpdates.set();
displayingFPS = true;
}
else
{
fps.displaying = false;
displayingFPS = false;
if (!rtData.config.printFPS)
fps.sendUpdates.clear();
if (fullscreen)
{
@ -274,8 +336,12 @@ void EventThread::process(RGSSThreadData &rtData)
joyState.buttons[event.jbutton.button] = false;
break;
case SDL_JOYHATMOTION :
joyState.hats[event.jhat.hat] = event.jhat.value;
break;
case SDL_JOYAXISMOTION :
joyState.axis[event.jaxis.axis] = event.jaxis.value;
joyState.axes[event.jaxis.axis] = event.jaxis.value;
break;
case SDL_JOYDEVICEADDED :
@ -300,7 +366,21 @@ void EventThread::process(RGSSThreadData &rtData)
case SDL_MOUSEMOTION :
mouseState.x = event.motion.x;
mouseState.y = event.motion.y;
break;
case SDL_FINGERDOWN :
i = event.tfinger.fingerId;
touchState.fingers[i].down = true;
case SDL_FINGERMOTION :
i = event.tfinger.fingerId;
touchState.fingers[i].x = event.tfinger.x * winW;
touchState.fingers[i].y = event.tfinger.y * winH;
break;
case SDL_FINGERUP :
i = event.tfinger.fingerId;
memset(&touchState.fingers[i], 0, sizeof(touchState.fingers[0]));
break;
default :
@ -329,7 +409,10 @@ void EventThread::process(RGSSThreadData &rtData)
break;
case UPDATE_FPS :
if (!fps.displaying)
if (rtData.config.printFPS)
Debug() << "FPS:" << event.user.code;
if (!fps.sendUpdates)
break;
snprintf(buffer, sizeof(buffer), "%s - %d FPS",
@ -354,12 +437,69 @@ void EventThread::process(RGSSThreadData &rtData)
break;
}
/* Just in case */
rtData.syncPoint.resumeThreads();
if (SDL_JoystickGetAttached(js))
SDL_JoystickClose(js);
delete sMenu;
}
int EventThread::eventFilter(void *data, SDL_Event *event)
{
RGSSThreadData &rtData = *static_cast<RGSSThreadData*>(data);
switch (event->type)
{
case SDL_APP_WILLENTERBACKGROUND :
Debug() << "SDL_APP_WILLENTERBACKGROUND";
if (HAVE_ALC_DEVICE_PAUSE)
alc.DevicePause(rtData.alcDev);
rtData.syncPoint.haltThreads();
return 0;
case SDL_APP_DIDENTERBACKGROUND :
Debug() << "SDL_APP_DIDENTERBACKGROUND";
return 0;
case SDL_APP_WILLENTERFOREGROUND :
Debug() << "SDL_APP_WILLENTERFOREGROUND";
return 0;
case SDL_APP_DIDENTERFOREGROUND :
Debug() << "SDL_APP_DIDENTERFOREGROUND";
if (HAVE_ALC_DEVICE_PAUSE)
alc.DeviceResume(rtData.alcDev);
rtData.syncPoint.resumeThreads();
return 0;
case SDL_APP_TERMINATING :
Debug() << "SDL_APP_TERMINATING";
return 0;
case SDL_APP_LOWMEMORY :
Debug() << "SDL_APP_LOWMEMORY";
return 0;
case SDL_RENDER_TARGETS_RESET :
Debug() << "****** SDL_RENDER_TARGETS_RESET";
return 0;
case SDL_RENDER_DEVICE_RESET :
Debug() << "****** SDL_RENDER_DEVICE_RESET";
return 0;
}
return 1;
}
void EventThread::cleanup()
{
SDL_Event event;
@ -374,6 +514,7 @@ void EventThread::resetInputStates()
memset(&keyStates, 0, sizeof(keyStates));
memset(&joyState, 0, sizeof(joyState));
memset(&mouseState.buttons, 0, sizeof(mouseState.buttons));
memset(&touchState, 0, sizeof(touchState));
}
void EventThread::setFullscreen(SDL_Window *win, bool mode)
@ -454,7 +595,7 @@ bool EventThread::getShowCursor() const
void EventThread::notifyFrame()
{
if (!fps.displaying)
if (!fps.sendUpdates)
return;
uint64_t current = SDL_GetPerformanceCounter();
@ -463,8 +604,8 @@ void EventThread::notifyFrame()
if (fps.immInitFlag)
{
fps.immInitFlag = false;
fps.immFiniFlag = true;
fps.immInitFlag.clear();
fps.immFiniFlag.set();
return;
}
@ -480,7 +621,7 @@ void EventThread::notifyFrame()
return;
fps.displayCounter = 0;
fps.immFiniFlag = false;
fps.immFiniFlag.clear();
int32_t avgFPS = fps.acc / fps.accDiv;
fps.acc = fps.accDiv = 0;
@ -490,3 +631,87 @@ void EventThread::notifyFrame()
event.user.type = usrIdStart + UPDATE_FPS;
SDL_PushEvent(&event);
}
void SyncPoint::haltThreads()
{
if (mainSync.locked)
return;
/* Lock the reply sync first to avoid races */
reply.lock();
/* Lock main sync and sleep until RGSS thread
* reports back */
mainSync.lock();
reply.waitForUnlock();
/* Now that the RGSS thread is asleep, we can
* safely put the other threads to sleep as well
* without causing deadlocks */
secondSync.lock();
}
void SyncPoint::resumeThreads()
{
if (!mainSync.locked)
return;
mainSync.unlock(false);
secondSync.unlock(true);
}
bool SyncPoint::mainSyncLocked()
{
return mainSync.locked;
}
void SyncPoint::waitMainSync()
{
reply.unlock(false);
mainSync.waitForUnlock();
}
void SyncPoint::passSecondarySync()
{
if (!secondSync.locked)
return;
secondSync.waitForUnlock();
}
SyncPoint::Util::Util()
{
mut = SDL_CreateMutex();
cond = SDL_CreateCond();
}
SyncPoint::Util::~Util()
{
SDL_DestroyCond(cond);
SDL_DestroyMutex(mut);
}
void SyncPoint::Util::lock()
{
locked.set();
}
void SyncPoint::Util::unlock(bool multi)
{
locked.clear();
if (multi)
SDL_CondBroadcast(cond);
else
SDL_CondSignal(cond);
}
void SyncPoint::Util::waitForUnlock()
{
SDL_LockMutex(mut);
while (locked)
SDL_CondWait(cond, mut);
SDL_UnlockMutex(mut);
}

View file

@ -37,21 +37,22 @@
#include <stdint.h>
struct RGSSThreadData;
typedef struct ALCdevice_struct ALCdevice;
struct SDL_Window;
union SDL_Event;
#define MAX_FINGERS 4
class EventThread
{
public:
static uint8_t keyStates[SDL_NUM_SCANCODES];
struct JoyState
{
int axis[256];
int axes[256];
uint8_t hats[256];
bool buttons[256];
};
static JoyState joyState;
struct MouseState
{
int x, y;
@ -59,7 +60,21 @@ public:
bool buttons[32];
};
struct FingerState
{
bool down;
int x, y;
};
struct TouchState
{
FingerState fingers[MAX_FINGERS];
};
static uint8_t keyStates[SDL_NUM_SCANCODES];
static JoyState joyState;
static MouseState mouseState;
static TouchState touchState;
static bool allocUserEvents();
@ -84,6 +99,8 @@ public:
void notifyFrame();
private:
static int eventFilter(void *, SDL_Event*);
void resetInputStates();
void setFullscreen(SDL_Window *, bool mode);
void updateCursorState(bool inWindow);
@ -96,111 +113,101 @@ private:
{
uint64_t lastFrame;
uint64_t displayCounter;
bool displaying;
bool immInitFlag;
bool immFiniFlag;
AtomicFlag sendUpdates;
AtomicFlag immInitFlag;
AtomicFlag immFiniFlag;
double acc;
uint32_t accDiv;
} fps;
};
/* Used to asynchronously inform the RGSS thread
* about window size changes */
struct WindowSizeNotify
* about certain value changes */
template<typename T>
struct UnidirMessage
{
SDL_mutex *mutex;
UnidirMessage()
: mutex(SDL_CreateMutex()),
current(T())
{}
AtomicFlag changed;
int w, h;
WindowSizeNotify()
{
mutex = SDL_CreateMutex();
w = h = 0;
}
~WindowSizeNotify()
~UnidirMessage()
{
SDL_DestroyMutex(mutex);
}
/* Done from the sending side */
void notifyChange(int w, int h)
void post(const T &value)
{
SDL_LockMutex(mutex);
this->w = w;
this->h = h;
changed.set();
current = value;
SDL_UnlockMutex(mutex);
}
/* Done from the receiving side */
bool pollChange(int *w, int *h)
bool poll(T &out) const
{
if (!changed)
return false;
SDL_LockMutex(mutex);
*w = this->w;
*h = this->h;
out = current;
changed.clear();
SDL_UnlockMutex(mutex);
return true;
}
};
struct BindingNotify
{
BindingNotify()
/* Done from either */
void get(T &out) const
{
mut = SDL_CreateMutex();
}
~BindingNotify()
{
SDL_DestroyMutex(mut);
}
bool poll(BDescVec &out) const
{
if (!changed)
return false;
SDL_LockMutex(mut);
out = data;
changed.clear();
SDL_UnlockMutex(mut);
return true;
}
void get(BDescVec &out) const
{
SDL_LockMutex(mut);
out = data;
SDL_UnlockMutex(mut);
}
void post(const BDescVec &d)
{
SDL_LockMutex(mut);
changed.set();
data = d;
SDL_UnlockMutex(mut);
SDL_LockMutex(mutex);
out = current;
SDL_UnlockMutex(mutex);
}
private:
SDL_mutex *mut;
BDescVec data;
SDL_mutex *mutex;
mutable AtomicFlag changed;
T current;
};
struct SyncPoint
{
/* Used by eventFilter to control sleep/wakeup */
void haltThreads();
void resumeThreads();
/* Used by RGSS thread */
bool mainSyncLocked();
void waitMainSync();
/* Used by secondary (audio) threads */
void passSecondarySync();
private:
struct Util
{
Util();
~Util();
void lock();
void unlock(bool multi);
void waitForUnlock();
AtomicFlag locked;
SDL_mutex *mut;
SDL_cond *cond;
};
Util mainSync;
Util reply;
Util secondSync;
};
struct RGSSThreadData
@ -218,15 +225,18 @@ struct RGSSThreadData
AtomicFlag rqResetFinish;
EventThread *ethread;
WindowSizeNotify windowSizeMsg;
BindingNotify bindingUpdateMsg;
UnidirMessage<Vec2i> windowSizeMsg;
UnidirMessage<BDescVec> bindingUpdateMsg;
SyncPoint syncPoint;
const char *argv0;
SDL_Window *window;
ALCdevice *alcDev;
Vec2 sizeResoRatio;
Vec2i screenOffset;
const int refreshRate;
Config config;
@ -235,11 +245,15 @@ struct RGSSThreadData
RGSSThreadData(EventThread *ethread,
const char *argv0,
SDL_Window *window,
ALCdevice *alcDev,
int refreshRate,
const Config& newconf)
: ethread(ethread),
argv0(argv0),
window(window),
alcDev(alcDev),
sizeResoRatio(1, 1),
refreshRate(refreshRate),
config(newconf)
{}
};

View file

@ -42,6 +42,105 @@
#include <iconv.h>
#endif
struct SDLRWIoContext
{
SDL_RWops *ops;
std::string filename;
SDLRWIoContext(const char *filename)
: ops(SDL_RWFromFile(filename, "r")),
filename(filename)
{
if (!ops)
throw Exception(Exception::SDLError,
"Failed to open file: %s", SDL_GetError());
}
~SDLRWIoContext()
{
SDL_RWclose(ops);
}
};
static PHYSFS_Io *createSDLRWIo(const char *filename);
static SDL_RWops *getSDLRWops(PHYSFS_Io *io)
{
return static_cast<SDLRWIoContext*>(io->opaque)->ops;
}
static PHYSFS_sint64 SDLRWIoRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
{
return SDL_RWread(getSDLRWops(io), buf, 1, len);
}
static int SDLRWIoSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset)
{
return (SDL_RWseek(getSDLRWops(io), offset, RW_SEEK_SET) != -1);
}
static PHYSFS_sint64 SDLRWIoTell(struct PHYSFS_Io *io)
{
return SDL_RWseek(getSDLRWops(io), 0, RW_SEEK_CUR);
}
static PHYSFS_sint64 SDLRWIoLength(struct PHYSFS_Io *io)
{
return SDL_RWsize(getSDLRWops(io));
}
static struct PHYSFS_Io *SDLRWIoDuplicate(struct PHYSFS_Io *io)
{
SDLRWIoContext *ctx = static_cast<SDLRWIoContext*>(io->opaque);
int64_t offset = io->tell(io);
PHYSFS_Io *dup = createSDLRWIo(ctx->filename.c_str());
if (dup)
SDLRWIoSeek(dup, offset);
return dup;
}
static void SDLRWIoDestroy(struct PHYSFS_Io *io)
{
delete static_cast<SDLRWIoContext*>(io->opaque);
delete io;
}
static PHYSFS_Io SDLRWIoTemplate =
{
0, 0, /* version, opaque */
SDLRWIoRead,
0, /* write */
SDLRWIoSeek,
SDLRWIoTell,
SDLRWIoLength,
SDLRWIoDuplicate,
0, /* flush */
SDLRWIoDestroy
};
static PHYSFS_Io *createSDLRWIo(const char *filename)
{
SDLRWIoContext *ctx;
try
{
ctx = new SDLRWIoContext(filename);
}
catch (const Exception &e)
{
Debug() << "Failed mounting" << filename;
return 0;
}
PHYSFS_Io *io = new PHYSFS_Io;
*io = SDLRWIoTemplate;
io->opaque = ctx;
return io;
}
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
{
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
@ -131,18 +230,36 @@ static int SDL_RWopsCloseFree(SDL_RWops *ops)
return result;
}
/* Copies the first srcN characters from src into dst,
* or the full string if srcN == -1. Never writes more
* than dstMax, and guarantees dst to be null terminated.
* Returns copied bytes (minus terminating null) */
static size_t
strcpySafe(char *dst, const char *src,
size_t dstMax, int srcN)
{
if (srcN < 0)
srcN = strlen(src);
size_t cpyMax = std::min<size_t>(dstMax-1, srcN);
memcpy(dst, src, cpyMax);
dst[cpyMax] = '\0';
return cpyMax;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
struct FileSystemPrivate
{
/* Maps: lower case filename, To: actual (mixed case) filename.
/* Maps: lower case filepath without extension,
* To: mixed case full filepath
* This is for compatibility with games that take Windows'
* case insensitivity for granted */
BoostHash<std::string, std::string> pathCache;
bool havePathCache;
std::vector<std::string> extensions[FileSystem::Undefined+1];
/* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the
* extension, or null is returned */
@ -162,120 +279,129 @@ struct FileSystemPrivate
return 0;
}
/* Complete filename via regular physfs lookup */
bool completeFilenameReg(const char *filename,
FileSystem::FileType type,
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,
const char **foundExt)
size_t outN)
{
/* Try supplementing extensions to find an existing path */
const std::vector<std::string> &extList = extensions[type];
strcpySafe(outBuffer, filepath, outN, -1);
for (size_t i = 0; i < extList.size(); ++i)
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)
{
const char *ext = extList[i].c_str();
/* 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);
snprintf(outBuffer, outN, "%s.%s", filename, ext);
if (PHYSFS_exists(outBuffer))
{
if (foundExt)
*foundExt = ext;
return true;
}
*delim = '\0';
}
else
{
/* Otherwise the file is in the root directory */
d.outBuf = outBuffer;
d.filenameLen = len - (delim - outBuffer);
}
/* Doing the check without supplemented extension
* fits the usage pattern of RMXP games */
if (PHYSFS_exists(filename))
{
strncpy(outBuffer, filename, outN);
d.found = false;
d.outBufN = outN - (d.outBuf - outBuffer);
if (foundExt)
*foundExt = findExt(filename);
PHYSFS_enumerateFilesCallback(root ? "" : outBuffer, completeFilenameRegCB, &d);
return true;
}
if (!d.found)
return false;
return false;
/* Now we put the deliminator back in to form the completed
* file path (if required) */
if (delim != outBuffer)
*delim = '/';
return true;
}
/* Complete filename via path cache */
bool completeFilenamePC(const char *filename,
FileSystem::FileType type,
bool completeFilenamePC(const char *filepath,
char *outBuffer,
size_t outN,
const char **foundExt)
size_t outN)
{
size_t i;
char lowCase[512];
std::string lowCase(filepath);
for (i = 0; i < sizeof(lowCase)-1 && filename[i]; ++i)
lowCase[i] = tolower(filename[i]);
for (size_t i = 0; i < lowCase.size(); ++i)
lowCase[i] = tolower(lowCase[i]);
lowCase[i] = '\0';
if (!pathCache.contains(lowCase))
return false;
std::string key;
const std::string &fullPath = pathCache[lowCase];
strcpySafe(outBuffer, fullPath.c_str(), outN, fullPath.size());
const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i)
{
const char *ext = extList[i].c_str();
snprintf(outBuffer, outN, "%s.%s", lowCase, ext);
key = outBuffer;
if (pathCache.contains(key))
{
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt)
*foundExt = ext;
return true;
}
}
key = lowCase;
if (pathCache.contains(key))
{
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt)
*foundExt = findExt(filename);
return true;
}
return false;
return true;
}
/* Try to complete 'filename' with file extensions
* based on 'type'. If no combination could be found,
* returns false, and 'foundExt' is untouched */
bool completeFileName(const char *filename,
FileSystem::FileType type,
bool completeFilename(const char *filepath,
char *outBuffer,
size_t outN,
const char **foundExt)
size_t outN)
{
if (havePathCache)
return completeFilenamePC(filename, type, outBuffer, outN, foundExt);
return completeFilenamePC(filepath, outBuffer, outN);
else
return completeFilenameReg(filename, type, outBuffer, outN, foundExt);
return completeFilenameReg(filepath, outBuffer, outN);
}
PHYSFS_File *openReadHandle(const char *filename,
FileSystem::FileType type,
const char **foundExt)
char *extBuf,
size_t extBufN)
{
char found[512];
if (!completeFileName(filename, type, found, sizeof(found), foundExt))
if (!completeFilename(filename, found, sizeof(found)))
throw Exception(Exception::NoFileError, "%s", filename);
PHYSFS_File *handle = PHYSFS_openRead(found);
@ -283,6 +409,21 @@ struct FileSystemPrivate
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;
}
@ -309,45 +450,8 @@ FileSystem::FileSystem(const char *argv0,
bool allowSymlinks)
{
p = new FileSystemPrivate;
p->havePathCache = false;
/* Image extensions */
p->extensions[Image].push_back("jpg");
p->extensions[Image].push_back("png");
/* Audio extensions */
const Sound_DecoderInfo **di;
for (di = Sound_AvailableDecoders(); *di; ++di)
{
const char **ext;
for (ext = (*di)->extensions; *ext; ++ext)
{
/* All reported extensions are uppercase,
* so we need to hammer them down first */
char buf[16];
for (size_t i = 0; i < sizeof(buf); ++i)
{
buf[i] = tolower((*ext)[i]);
if (!buf[i])
break;
}
p->extensions[Audio].push_back(buf);
}
}
if (rgssVer >= 2 && !contains(p->extensions[Audio], std::string("ogg")))
p->extensions[Audio].push_back("ogg");
p->extensions[Audio].push_back("mid");
p->extensions[Audio].push_back("midi");
/* Font extensions */
p->extensions[Font].push_back("ttf");
p->extensions[Font].push_back("otf");
PHYSFS_init(argv0);
PHYSFS_registerArchiver(&RGSS1_Archiver);
@ -368,7 +472,16 @@ FileSystem::~FileSystem()
void FileSystem::addPath(const char *path)
{
PHYSFS_mount(path, 0, 1);
/* Try the normal mount first */
if (!PHYSFS_mount(path, 0, 1))
{
/* If it didn't work, try mounting via a wrapped
* SDL_RWops */
PHYSFS_Io *io = createSDLRWIo(path);
if (io)
PHYSFS_mountIo(io, path, 0, 1);
}
}
#ifdef __APPLE__
@ -436,12 +549,22 @@ static void cacheEnumCB(void *d, const char *origdir,
std::string mixedCase(ptr);
for (char *p = bufNfc; *p; ++p)
*p = tolower(*p);
for (char *q = bufNfc; *q; ++q)
*q = tolower(*q);
std::string lowerCase(ptr);
p->pathCache.insert(std::string(ptr), mixedCase);
p->pathCache.insert(lowerCase, mixedCase);
for (char *q = ptr+strlen(ptr); q > ptr; --q)
{
if (*q == '/')
break;
if (*q != '.')
continue;
*q = '\0';
p->pathCache.insert(std::string(ptr), mixedCase);
}
PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, d);
}
@ -450,7 +573,7 @@ void FileSystem::createPathCache()
{
#ifdef __APPLE__
CacheEnumCBData data(p);
PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data);
PHYSFS_enumerateFilesCallback("", cacheEnumCB2, &data);
#else
PHYSFS_enumerateFilesCallback("", cacheEnumCB, p);
#endif
@ -458,12 +581,6 @@ void FileSystem::createPathCache()
p->havePathCache = true;
}
static void strToLower(std::string &str)
{
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
struct FontSetsCBData
{
FileSystemPrivate *p;
@ -482,16 +599,21 @@ static void fontSetEnumCB(void *data, const char *,
if (!ext)
return;
std::string lower(ext);
strToLower(lower);
char lowExt[8];
size_t i;
if (!contains(p->extensions[FileSystem::Font], lower))
for (i = 0; i < sizeof(lowExt)-1 && ext[i]; ++i)
lowExt[i] = tolower(ext[i]);
lowExt[i] = '\0';
if (strcmp(lowExt, "ttf") && strcmp(lowExt, "otf"))
return;
std::string filename("Fonts/");
filename += fname;
char filename[512];
snprintf(filename, sizeof(filename), "Fonts/%s", fname);
filename[sizeof(filename)-1] = '\0';
PHYSFS_File *handle = PHYSFS_openRead(filename.c_str());
PHYSFS_File *handle = PHYSFS_openRead(filename);
if (!handle)
return;
@ -513,11 +635,11 @@ void FileSystem::initFontSets(SharedFontState &sfs)
void FileSystem::openRead(SDL_RWops &ops,
const char *filename,
FileType type,
bool freeOnClose,
const char **foundExt)
char *extBuf,
size_t extBufN)
{
PHYSFS_File *handle = p->openReadHandle(filename, type, foundExt);
PHYSFS_File *handle = p->openReadHandle(filename, extBuf, extBufN);
p->initReadOps(handle, ops, freeOnClose);
}
@ -532,9 +654,9 @@ void FileSystem::openReadRaw(SDL_RWops &ops,
p->initReadOps(handle, ops, freeOnClose);
}
bool FileSystem::exists(const char *filename, FileType type)
bool FileSystem::exists(const char *filename)
{
char found[512];
return p->completeFileName(filename, type, found, sizeof(found), 0);
return p->completeFilename(filename, found, sizeof(found));
}

View file

@ -43,28 +43,18 @@ public:
* available font assets */
void initFontSets(SharedFontState &sfs);
/* For extension supplementing */
enum FileType
{
Image = 0,
Audio,
Font,
Undefined
};
void openRead(SDL_RWops &ops,
const char *filename,
FileType type = Undefined,
bool freeOnClose = false,
const char **foundExt = 0);
char *extBuf = 0,
size_t extBufN = 0);
/* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops,
const char *filename,
bool freeOnClose = false);
bool exists(const char *filename,
FileType type = Undefined);
bool exists(const char *filename);
private:
FileSystemPrivate *p;

View file

@ -10,7 +10,7 @@
#include <fluidsynth.h>
#endif
#ifdef __LINUX__
#if __LINUX__ || __ANDROID__
#define FLUID_LIB "libfluidsynth.so.1"
#elif __MACOSX__
#define FLUID_LIB "libfluidsynth.1.dylib"

View file

@ -86,16 +86,14 @@ public:
const Font &operator=(const Font &o);
const char *getName() const;
void setName(const char *value);
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( 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_STATIC( DefaultName, const char* )
DECL_ATTR_STATIC( DefaultSize, int )
@ -108,7 +106,7 @@ public:
/* Assigns heap allocated objects to object properties;
* using this in pure C++ will cause memory leaks
* (ie. only to be used in GCed language bindings */
* (ie. only to be used in GCed language bindings) */
void initDynAttribs();
static void initDefaultDynAttribs();

View file

@ -1,5 +1,5 @@
/*
** debuglogger.cpp
** gl-debug.cpp
**
** This file is part of mkxp.
**
@ -19,25 +19,25 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "debuglogger.h"
#include "gl-debug.h"
#include "debugwriter.h"
#include <iostream>
#include "gl-fun.h"
struct DebugLoggerPrivate
struct GLDebugLoggerPrivate
{
std::ostream *stream;
DebugLoggerPrivate(const char *logFilename)
GLDebugLoggerPrivate(const char *logFilename)
{
(void) logFilename;
stream = &std::clog;
}
~DebugLoggerPrivate()
~GLDebugLoggerPrivate()
{
}
@ -62,8 +62,8 @@ static void APIENTRY arbDebugFunc(GLenum source,
const GLchar* message,
const void* userParam)
{
DebugLoggerPrivate *p =
static_cast<DebugLoggerPrivate*>(const_cast<void*>(userParam));
GLDebugLoggerPrivate *p =
static_cast<GLDebugLoggerPrivate*>(const_cast<void*>(userParam));
(void) source;
(void) type;
@ -75,9 +75,9 @@ static void APIENTRY arbDebugFunc(GLenum source,
p->writeLine(message);
}
DebugLogger::DebugLogger(const char *filename)
GLDebugLogger::GLDebugLogger(const char *filename)
{
p = new DebugLoggerPrivate(filename);
p = new GLDebugLoggerPrivate(filename);
if (gl.DebugMessageCallback)
gl.DebugMessageCallback(arbDebugFunc, p);
@ -85,7 +85,7 @@ DebugLogger::DebugLogger(const char *filename)
Debug() << "DebugLogger: no debug extensions found";
}
DebugLogger::~DebugLogger()
GLDebugLogger::~GLDebugLogger()
{
delete p;
}

View file

@ -1,5 +1,5 @@
/*
** debuglogger.h
** gl-debug.h
**
** This file is part of mkxp.
**
@ -22,16 +22,30 @@
#ifndef DEBUGLOGGER_H
#define DEBUGLOGGER_H
struct DebugLoggerPrivate;
#include "gl-fun.h"
class DebugLogger
#include <stdio.h>
#include <algorithm>
struct GLDebugLoggerPrivate;
class GLDebugLogger
{
public:
DebugLogger(const char *filename = 0);
~DebugLogger();
GLDebugLogger(const char *filename = 0);
~GLDebugLogger();
private:
DebugLoggerPrivate *p;
GLDebugLoggerPrivate *p;
};
#define GL_MARKER(format, ...) \
if (gl.StringMarker) \
{ \
char buf[128]; \
int len = snprintf(buf, sizeof(buf), format, ##__VA_ARGS__); \
gl.StringMarker(std::min<size_t>(len, sizeof(buf)), buf); \
}
#endif // DEBUGLOGGER_H

View file

@ -29,12 +29,12 @@
GLFunctions gl;
typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum, GLuint);
typedef const GLubyte* (APIENTRYP _PFNGLGETSTRINGIPROC) (GLenum, GLuint);
static void parseExtensionsCore(PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::string> &out)
static void parseExtensionsCore(_PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::string> &out)
{
PFNGLGETSTRINGIPROC GetStringi =
(PFNGLGETSTRINGIPROC) SDL_GL_GetProcAddress("glGetStringi");
_PFNGLGETSTRINGIPROC GetStringi =
(_PFNGLGETSTRINGIPROC) SDL_GL_GetProcAddress("glGetStringi");
GLint extCount = 0;
GetIntegerv(GL_NUM_EXTENSIONS, &extCount);
@ -43,7 +43,7 @@ static void parseExtensionsCore(PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::
out.insert((const char*) GetStringi(GL_EXTENSIONS, i));
}
static void parseExtensionsCompat(PFNGLGETSTRINGPROC GetString, BoostSet<std::string> &out)
static void parseExtensionsCompat(_PFNGLGETSTRINGPROC GetString, BoostSet<std::string> &out)
{
const char *ext = (const char*) GetString(GL_EXTENSIONS);
@ -82,8 +82,8 @@ void initGLFunctions()
/* Determine GL version */
const char *ver = (const char*) gl.GetString(GL_VERSION);
const char *glesPrefix = "OpenGL ES ";
size_t glesPrefixN = strlen(glesPrefix);
const char glesPrefix[] = "OpenGL ES ";
const size_t glesPrefixN = sizeof(glesPrefix)-1;
bool gles = false;
@ -101,6 +101,11 @@ void initGLFunctions()
if (glMajor < 2)
throw EXC("At least OpenGL (ES) 2.0 is required");
if (gles)
{
GL_ES_FUN;
}
BoostSet<std::string> ext;
if (glMajor >= 3)
@ -172,6 +177,13 @@ void initGLFunctions()
GL_DEBUG_KHR_FUN;
}
if (HAVE_EXT(GREMEDY_string_marker))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "GREMEDY"
GL_GREMEMDY_FUN;
}
/* Misc caps */
if (!gles || glMajor >= 3 || HAVE_EXT(EXT_unpack_subimage))
gl.unpack_subimage = true;

View file

@ -30,179 +30,194 @@
#endif
/* Etc */
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor);
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
typedef GLenum (APIENTRYP _PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP _PFNGLCLEARCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
typedef void (APIENTRYP _PFNGLCLEARPROC) (GLbitfield mask);
typedef const GLubyte * (APIENTRYP _PFNGLGETSTRINGPROC) (GLenum name);
typedef void (APIENTRYP _PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef void (APIENTRYP _PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP _PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
typedef void (APIENTRYP _PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP _PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP _PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP _PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP _PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor);
typedef void (APIENTRYP _PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP _PFNGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (APIENTRYP _PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
/* Texture */
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP _PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
typedef void (APIENTRYP _PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP _PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP _PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP _PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP _PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP _PFNGLACTIVETEXTUREPROC) (GLenum texture);
/* Debug callback */
/* Debugging */
typedef void (APIENTRY * _GLDEBUGPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void *userParam);
typedef void (APIENTRYP _PFNGLDEBUGMESSAGECALLBACKPROC) (_GLDEBUGPROC callback, const void *userParam);
typedef void (APIENTRYP _PFNGLSTRINGMARKERPROC) (GLsizei len, const GLvoid *string);
/* Buffer object */
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
typedef void (APIENTRYP _PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (APIENTRYP _PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (APIENTRYP _PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP _PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
typedef void (APIENTRYP _PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
/* Shader */
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths);
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param);
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
typedef GLuint (APIENTRYP _PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP _PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP _PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths);
typedef void (APIENTRYP _PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef void (APIENTRYP _PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP _PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param);
typedef void (APIENTRYP _PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
/* Program */
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param);
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
typedef GLuint (APIENTRYP _PFNGLCREATEPROGRAMPROC) (void);
typedef void (APIENTRYP _PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP _PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP _PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP _PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param);
typedef void (APIENTRYP _PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
/* Uniform */
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar* name);
typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
typedef GLint (APIENTRYP _PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar* name);
typedef void (APIENTRYP _PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP _PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP _PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP _PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP _PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
/* Vertex attribute */
typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
typedef void (APIENTRYP _PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
typedef void (APIENTRYP _PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP _PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP _PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
/* Framebuffer object */
typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers);
typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers);
typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
typedef void (APIENTRYP _PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers);
typedef void (APIENTRYP _PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers);
typedef void (APIENTRYP _PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP _PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP _PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
/* Vertex array object */
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
typedef void (APIENTRYP _PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
typedef void (APIENTRYP _PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
typedef void (APIENTRYP _PFNGLBINDVERTEXARRAYPROC) (GLuint array);
/* GLES only */
typedef void (APIENTRYP _PFNGLRELEASESHADERCOMPILERPROC) (void);
#ifdef GLES2_HEADER
#define GL_NUM_EXTENSIONS 0x821D
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
#define GL_UNPACK_SKIP_ROWS 0x0CF3
#endif
#define GL_20_FUN \
/* Etc */ \
GL_FUN(GetError, PFNGLGETERRORPROC) \
GL_FUN(ClearColor, PFNGLCLEARCOLORPROC) \
GL_FUN(Clear, PFNGLCLEARPROC) \
GL_FUN(GetString, PFNGLGETSTRINGPROC) \
GL_FUN(GetIntegerv, PFNGLGETINTEGERVPROC) \
GL_FUN(PixelStorei, PFNGLPIXELSTOREIPROC) \
GL_FUN(ReadPixels, PFNGLREADPIXELSPROC) \
GL_FUN(Enable, PFNGLENABLEPROC) \
GL_FUN(Disable, PFNGLDISABLEPROC) \
GL_FUN(Scissor, PFNGLSCISSORPROC) \
GL_FUN(Viewport, PFNGLVIEWPORTPROC) \
GL_FUN(BlendFunc, PFNGLBLENDFUNCPROC) \
GL_FUN(BlendFuncSeparate, PFNGLBLENDFUNCSEPARATEPROC) \
GL_FUN(BlendEquation, PFNGLBLENDEQUATIONPROC) \
GL_FUN(DrawElements, PFNGLDRAWELEMENTSPROC) \
GL_FUN(GetError, _PFNGLGETERRORPROC) \
GL_FUN(ClearColor, _PFNGLCLEARCOLORPROC) \
GL_FUN(Clear, _PFNGLCLEARPROC) \
GL_FUN(GetString, _PFNGLGETSTRINGPROC) \
GL_FUN(GetIntegerv, _PFNGLGETINTEGERVPROC) \
GL_FUN(PixelStorei, _PFNGLPIXELSTOREIPROC) \
GL_FUN(ReadPixels, _PFNGLREADPIXELSPROC) \
GL_FUN(Enable, _PFNGLENABLEPROC) \
GL_FUN(Disable, _PFNGLDISABLEPROC) \
GL_FUN(Scissor, _PFNGLSCISSORPROC) \
GL_FUN(Viewport, _PFNGLVIEWPORTPROC) \
GL_FUN(BlendFunc, _PFNGLBLENDFUNCPROC) \
GL_FUN(BlendFuncSeparate, _PFNGLBLENDFUNCSEPARATEPROC) \
GL_FUN(BlendEquation, _PFNGLBLENDEQUATIONPROC) \
GL_FUN(DrawElements, _PFNGLDRAWELEMENTSPROC) \
/* Texture */ \
GL_FUN(GenTextures, PFNGLGENTEXTURESPROC) \
GL_FUN(DeleteTextures, PFNGLDELETETEXTURESPROC) \
GL_FUN(BindTexture, PFNGLBINDTEXTUREPROC) \
GL_FUN(TexImage2D, PFNGLTEXIMAGE2DPROC) \
GL_FUN(TexSubImage2D, PFNGLTEXSUBIMAGE2DPROC) \
GL_FUN(TexParameteri, PFNGLTEXPARAMETERIPROC) \
GL_FUN(ActiveTexture, PFNGLACTIVETEXTUREPROC) \
GL_FUN(GenTextures, _PFNGLGENTEXTURESPROC) \
GL_FUN(DeleteTextures, _PFNGLDELETETEXTURESPROC) \
GL_FUN(BindTexture, _PFNGLBINDTEXTUREPROC) \
GL_FUN(TexImage2D, _PFNGLTEXIMAGE2DPROC) \
GL_FUN(TexSubImage2D, _PFNGLTEXSUBIMAGE2DPROC) \
GL_FUN(TexParameteri, _PFNGLTEXPARAMETERIPROC) \
GL_FUN(ActiveTexture, _PFNGLACTIVETEXTUREPROC) \
/* Buffer object */ \
GL_FUN(GenBuffers, PFNGLGENBUFFERSPROC) \
GL_FUN(DeleteBuffers, PFNGLDELETEBUFFERSPROC) \
GL_FUN(BindBuffer, PFNGLBINDBUFFERPROC) \
GL_FUN(BufferData, PFNGLBUFFERDATAPROC) \
GL_FUN(BufferSubData, PFNGLBUFFERSUBDATAPROC) \
GL_FUN(GenBuffers, _PFNGLGENBUFFERSPROC) \
GL_FUN(DeleteBuffers, _PFNGLDELETEBUFFERSPROC) \
GL_FUN(BindBuffer, _PFNGLBINDBUFFERPROC) \
GL_FUN(BufferData, _PFNGLBUFFERDATAPROC) \
GL_FUN(BufferSubData, _PFNGLBUFFERSUBDATAPROC) \
/* Shader */ \
GL_FUN(CreateShader, PFNGLCREATESHADERPROC) \
GL_FUN(DeleteShader, PFNGLDELETESHADERPROC) \
GL_FUN(ShaderSource, PFNGLSHADERSOURCEPROC) \
GL_FUN(CompileShader, PFNGLCOMPILESHADERPROC) \
GL_FUN(AttachShader, PFNGLATTACHSHADERPROC) \
GL_FUN(GetShaderiv, PFNGLGETSHADERIVPROC) \
GL_FUN(GetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \
GL_FUN(CreateShader, _PFNGLCREATESHADERPROC) \
GL_FUN(DeleteShader, _PFNGLDELETESHADERPROC) \
GL_FUN(ShaderSource, _PFNGLSHADERSOURCEPROC) \
GL_FUN(CompileShader, _PFNGLCOMPILESHADERPROC) \
GL_FUN(AttachShader, _PFNGLATTACHSHADERPROC) \
GL_FUN(GetShaderiv, _PFNGLGETSHADERIVPROC) \
GL_FUN(GetShaderInfoLog, _PFNGLGETSHADERINFOLOGPROC) \
/* Program */ \
GL_FUN(CreateProgram, PFNGLCREATEPROGRAMPROC) \
GL_FUN(DeleteProgram, PFNGLDELETEPROGRAMPROC) \
GL_FUN(UseProgram, PFNGLUSEPROGRAMPROC) \
GL_FUN(LinkProgram, PFNGLLINKPROGRAMPROC) \
GL_FUN(GetProgramiv, PFNGLGETPROGRAMIVPROC) \
GL_FUN(GetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \
GL_FUN(CreateProgram, _PFNGLCREATEPROGRAMPROC) \
GL_FUN(DeleteProgram, _PFNGLDELETEPROGRAMPROC) \
GL_FUN(UseProgram, _PFNGLUSEPROGRAMPROC) \
GL_FUN(LinkProgram, _PFNGLLINKPROGRAMPROC) \
GL_FUN(GetProgramiv, _PFNGLGETPROGRAMIVPROC) \
GL_FUN(GetProgramInfoLog, _PFNGLGETPROGRAMINFOLOGPROC) \
/* Uniform */ \
GL_FUN(GetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC) \
GL_FUN(Uniform1f, PFNGLUNIFORM1FPROC) \
GL_FUN(Uniform2f, PFNGLUNIFORM2FPROC) \
GL_FUN(Uniform4f, PFNGLUNIFORM4FPROC) \
GL_FUN(Uniform1i, PFNGLUNIFORM1IPROC) \
GL_FUN(UniformMatrix4fv, PFNGLUNIFORMMATRIX4FVPROC) \
GL_FUN(GetUniformLocation, _PFNGLGETUNIFORMLOCATIONPROC) \
GL_FUN(Uniform1f, _PFNGLUNIFORM1FPROC) \
GL_FUN(Uniform2f, _PFNGLUNIFORM2FPROC) \
GL_FUN(Uniform4f, _PFNGLUNIFORM4FPROC) \
GL_FUN(Uniform1i, _PFNGLUNIFORM1IPROC) \
GL_FUN(UniformMatrix4fv, _PFNGLUNIFORMMATRIX4FVPROC) \
/* Vertex attribute */ \
GL_FUN(BindAttribLocation, PFNGLBINDATTRIBLOCATIONPROC) \
GL_FUN(EnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(DisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(VertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC)
GL_FUN(BindAttribLocation, _PFNGLBINDATTRIBLOCATIONPROC) \
GL_FUN(EnableVertexAttribArray, _PFNGLENABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(DisableVertexAttribArray, _PFNGLDISABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(VertexAttribPointer, _PFNGLVERTEXATTRIBPOINTERPROC)
#define GL_ES_FUN \
GL_FUN(ReleaseShaderCompiler, _PFNGLRELEASESHADERCOMPILERPROC)
#define GL_FBO_FUN \
/* Framebuffer object */ \
GL_FUN(GenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \
GL_FUN(DeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC) \
GL_FUN(BindFramebuffer, PFNGLBINDFRAMEBUFFERPROC) \
GL_FUN(FramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC)
GL_FUN(GenFramebuffers, _PFNGLGENFRAMEBUFFERSPROC) \
GL_FUN(DeleteFramebuffers, _PFNGLDELETEFRAMEBUFFERSPROC) \
GL_FUN(BindFramebuffer, _PFNGLBINDFRAMEBUFFERPROC) \
GL_FUN(FramebufferTexture2D, _PFNGLFRAMEBUFFERTEXTURE2DPROC)
#define GL_FBO_BLIT_FUN \
GL_FUN(BlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC)
GL_FUN(BlitFramebuffer, _PFNGLBLITFRAMEBUFFERPROC)
#define GL_VAO_FUN \
/* Vertex array object */ \
GL_FUN(GenVertexArrays, PFNGLGENVERTEXARRAYSPROC) \
GL_FUN(DeleteVertexArrays, PFNGLDELETEVERTEXARRAYSPROC) \
GL_FUN(BindVertexArray, PFNGLBINDVERTEXARRAYPROC)
GL_FUN(GenVertexArrays, _PFNGLGENVERTEXARRAYSPROC) \
GL_FUN(DeleteVertexArrays, _PFNGLDELETEVERTEXARRAYSPROC) \
GL_FUN(BindVertexArray, _PFNGLBINDVERTEXARRAYPROC)
#define GL_DEBUG_KHR_FUN \
GL_FUN(DebugMessageCallback, _PFNGLDEBUGMESSAGECALLBACKPROC)
#define GL_GREMEMDY_FUN \
GL_FUN(StringMarker, _PFNGLSTRINGMARKERPROC)
struct GLFunctions
{
#define GL_FUN(name, type) type name;
GL_20_FUN
GL_ES_FUN
GL_FBO_FUN
GL_FBO_BLIT_FUN
GL_VAO_FUN
GL_DEBUG_KHR_FUN
GL_GREMEMDY_FUN
bool glsles;
bool unpack_subimage;

View file

@ -61,43 +61,43 @@ namespace TEX
return id;
}
inline void del(ID id)
static inline void del(ID id)
{
gl.DeleteTextures(1, &id.gl);
}
inline void bind(ID id)
static inline void bind(ID id)
{
gl.BindTexture(GL_TEXTURE_2D, id.gl);
}
inline void unbind()
static inline void unbind()
{
bind(ID(0));
}
inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
static inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
{
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, data);
}
inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
static inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
{
gl.TexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data);
}
inline void allocEmpty(GLsizei width, GLsizei height)
static inline void allocEmpty(GLsizei width, GLsizei height)
{
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
inline void setRepeat(bool mode)
static inline void setRepeat(bool mode)
{
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
}
inline void setSmooth(bool mode)
static inline void setSmooth(bool mode)
{
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
@ -117,27 +117,27 @@ namespace FBO
return id;
}
inline void del(ID id)
static inline void del(ID id)
{
gl.DeleteFramebuffers(1, &id.gl);
}
inline void bind(ID id)
static inline void bind(ID id)
{
gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl);
}
inline void unbind()
static inline void unbind()
{
bind(ID(0));
}
inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
static inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
{
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0);
}
inline void clear()
static inline void clear()
{
gl.Clear(GL_COLOR_BUFFER_BIT);
}
@ -148,7 +148,7 @@ struct GenericBO
{
DEF_GL_ID
inline static ID gen()
static inline ID gen()
{
ID id;
gl.GenBuffers(1, &id.gl);
@ -156,32 +156,32 @@ struct GenericBO
return id;
}
inline static void del(ID id)
static inline void del(ID id)
{
gl.DeleteBuffers(1, &id.gl);
}
inline static void bind(ID id)
static inline void bind(ID id)
{
gl.BindBuffer(target, id.gl);
}
inline static void unbind()
static inline void unbind()
{
bind(ID(0));
}
inline static void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
static inline void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
{
gl.BufferData(target, size, data, usage);
}
inline static void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
static inline void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
{
gl.BufferSubData(target, offset, size, data);
}
inline static void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
static inline void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
{
uploadData(size, 0, usage);
}

View file

@ -43,7 +43,7 @@ void GLScissorBox::apply(const IntRect &value)
void GLScissorBox::setIntersect(const IntRect &value)
{
IntRect &current = get();
const IntRect &current = get();
SDL_Rect r1 = { current.x, current.y, current.w, current.h };
SDL_Rect r2 = { value.x, value.y, value.w, value.h };

View file

@ -43,7 +43,7 @@ struct GLProperty
void push() { stack.push(current); }
void pop() { set(stack.top()); stack.pop(); }
T &get() { return current; }
const T &get() { return current; }
void set(const T &value)
{
if (value == current)

View file

@ -171,36 +171,112 @@ public:
void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
{
pp.swapRender();
const IntRect &viewpRect = glState.scissorBox.get();
const IntRect &screenRect = geometry.rect;
/* Scissor test _does_ affect FBO blit operations,
* and since we're inside the draw cycle, it will
* be turned on, so turn it off temporarily */
glState.scissorTest.pushSet(false);
if (t.w != 0.0)
{
pp.swapRender();
GLMeta::blitBegin(pp.frontBuffer());
GLMeta::blitSource(pp.backBuffer());
GLMeta::blitRectangle(geometry.rect, Vec2i());
GLMeta::blitEnd();
if (!viewpRect.encloses(screenRect))
{
/* Scissor test _does_ affect FBO blit operations,
* and since we're inside the draw cycle, it will
* be turned on, so turn it off temporarily */
glState.scissorTest.pushSet(false);
glState.scissorTest.pop();
GLMeta::blitBegin(pp.frontBuffer());
GLMeta::blitSource(pp.backBuffer());
GLMeta::blitRectangle(geometry.rect, Vec2i());
GLMeta::blitEnd();
PlaneShader &shader = shState->shaders().plane;
glState.scissorTest.pop();
}
GrayShader &shader = shState->shaders().gray;
shader.bind();
shader.setGray(t.w);
shader.applyViewportProj();
shader.setTexSize(screenRect.size());
TEX::bind(pp.backBuffer().tex);
glState.blend.pushSet(false);
screenQuad.draw();
glState.blend.pop();
}
bool toneEffect = t.xyzHasEffect();
bool colorEffect = c.xyzHasEffect();
bool flashEffect = f.xyzHasEffect();
if (!toneEffect && !colorEffect && !flashEffect)
return;
FlatColorShader &shader = shState->shaders().flatColor;
shader.bind();
shader.setColor(c);
shader.setFlash(f);
shader.setTone(t);
shader.setOpacity(1.0);
shader.applyViewportProj();
shader.setTexSize(geometry.rect.size());
TEX::bind(pp.backBuffer().tex);
/* Apply tone */
if (toneEffect)
{
/* First split up additive / substractive components */
Vec4 add, sub;
glState.blend.pushSet(false);
if (t.x > 0)
add.x = t.x;
if (t.y > 0)
add.y = t.y;
if (t.z > 0)
add.z = t.z;
screenQuad.draw();
if (t.x < 0)
sub.x = -t.x;
if (t.y < 0)
sub.y = -t.y;
if (t.z < 0)
sub.z = -t.z;
glState.blend.pop();
/* Then apply them using hardware blending */
gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
if (add.xyzHasEffect())
{
gl.BlendEquation(GL_FUNC_ADD);
shader.setColor(add);
screenQuad.draw();
}
if (sub.xyzHasEffect())
{
gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
shader.setColor(sub);
screenQuad.draw();
}
}
if (colorEffect || flashEffect)
{
gl.BlendEquation(GL_FUNC_ADD);
gl.BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ZERO, GL_ONE);
}
if (colorEffect)
{
shader.setColor(c);
screenQuad.draw();
}
if (flashEffect)
{
shader.setColor(f);
screenQuad.draw();
}
glState.blendMode.refresh();
}
void setBrightness(float norm)
@ -390,6 +466,7 @@ struct GraphicsPrivate
ScreenScene screen;
RGSSThreadData *threadData;
SDL_GLContext glCtx;
int frameRate;
int frameCount;
@ -413,6 +490,7 @@ struct GraphicsPrivate
winSize(rtData->config.defScreenW, rtData->config.defScreenH),
screen(scRes.x, scRes.y),
threadData(rtData),
glCtx(SDL_GL_GetCurrentContext()),
frameRate(DEF_FRAMERATE),
frameCount(0),
brightness(255),
@ -482,7 +560,7 @@ struct GraphicsPrivate
void checkResize()
{
if (threadData->windowSizeMsg.pollChange(&winSize.x, &winSize.y))
if (threadData->windowSizeMsg.poll(winSize))
{
/* some GL drivers change the viewport on window resize */
glState.viewport.refresh();
@ -552,16 +630,40 @@ struct GraphicsPrivate
swapGLBuffer();
}
void checkSyncLock()
{
if (!threadData->syncPoint.mainSyncLocked())
return;
/* Releasing the GL context before sleeping and making it
* current again on wakeup seems to avoid the context loss
* when the app moves into the background on Android */
SDL_GL_MakeCurrent(threadData->window, 0);
threadData->syncPoint.waitMainSync();
SDL_GL_MakeCurrent(threadData->window, glCtx);
fpsLimiter.resetFrameAdjust();
}
};
Graphics::Graphics(RGSSThreadData *data)
{
p = new GraphicsPrivate(data);
if (data->config.fixedFramerate > 0)
p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
else if (data->config.fixedFramerate < 0)
if (data->config.syncToRefreshrate)
{
p->frameRate = data->refreshRate;
p->fpsLimiter.disabled = true;
}
else if (data->config.fixedFramerate > 0)
{
p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
}
else if (data->config.fixedFramerate < 0)
{
p->fpsLimiter.disabled = true;
}
}
Graphics::~Graphics()
@ -572,6 +674,7 @@ Graphics::~Graphics()
void Graphics::update()
{
p->checkShutDownReset();
p->checkSyncLock();
if (p->frozen)
return;
@ -613,10 +716,12 @@ void Graphics::transition(int duration,
const char *filename,
int vague)
{
p->checkSyncLock();
if (!p->frozen)
return;
vague = clamp(vague, 0, 512);
vague = clamp(vague, 1, 256);
Bitmap *transMap = filename ? new Bitmap(filename) : 0;
setBrightness(255);
@ -637,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 / 512.0f);
shader.setVague(vague / 256.0);
shader.setTexSize(p->scRes);
}
else
@ -673,6 +778,8 @@ void Graphics::transition(int duration,
return;
}
p->checkSyncLock();
const float prog = i * (1.0 / duration);
if (transMap)
@ -728,6 +835,9 @@ void Graphics::setFrameRate(int value)
{
p->frameRate = clamp(value, 10, 120);
if (p->threadData->config.syncToRefreshrate)
return;
if (p->threadData->config.fixedFramerate > 0)
return;

View file

@ -133,7 +133,7 @@ struct JsAxisBinding : public Binding
bool sourceActive() const
{
int val = EventThread::joyState.axis[source];
int val = EventThread::joyState.axes[source];
if (dir == Negative)
return val < -JAXIS_THRESHOLD;
@ -150,6 +150,34 @@ struct JsAxisBinding : public Binding
AxisDir dir;
};
/* Joystick hat binding */
struct JsHatBinding : public Binding
{
JsHatBinding() {}
JsHatBinding(uint8_t source,
uint8_t pos,
Input::ButtonCode target)
: Binding(target),
source(source),
pos(pos)
{}
bool sourceActive() const
{
/* For a diagonal input accept it as an input for both the axes */
return (pos & EventThread::joyState.hats[source]) != 0;
}
bool sourceRepeatable() const
{
return true;
}
uint8_t source;
uint8_t pos;
};
/* Mouse button binding */
struct MsBinding : public Binding
{
@ -241,6 +269,7 @@ struct InputPrivate
std::vector<KbBinding> kbStatBindings;
std::vector<KbBinding> kbBindings;
std::vector<JsAxisBinding> jsABindings;
std::vector<JsHatBinding> jsHBindings;
std::vector<JsButtonBinding> jsBBindings;
std::vector<MsBinding> msBindings;
@ -348,6 +377,7 @@ struct InputPrivate
{
kbBindings.clear();
jsABindings.clear();
jsHBindings.clear();
jsBBindings.clear();
for (size_t i = 0; i < d.size(); ++i)
@ -381,6 +411,16 @@ struct InputPrivate
break;
}
case JHat :
{
JsHatBinding bind;
bind.source = src.d.jh.hat;
bind.pos = src.d.jh.pos;
bind.target = desc.target;
jsHBindings.push_back(bind);
break;
}
case JButton :
{
JsButtonBinding bind;
@ -402,6 +442,7 @@ struct InputPrivate
appendBindings(kbBindings);
appendBindings(jsABindings);
appendBindings(jsHBindings);
appendBindings(jsBBindings);
}

View file

@ -129,6 +129,20 @@ static void addAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::Button
d.push_back(desc);
}
static void addHatBinding(BDescVec &d, uint8_t hat, uint8_t pos, Input::ButtonCode target)
{
SourceDesc src;
src.type = JHat;
src.d.jh.hat = hat;
src.d.jh.pos = pos;
BindingDesc desc;
desc.src = src;
desc.target = target;
d.push_back(desc);
}
BDescVec genDefaultBindings(const Config &conf)
{
BDescVec d;
@ -150,11 +164,16 @@ BDescVec genDefaultBindings(const Config &conf)
addAxisBinding(d, 0, Positive, Input::Right);
addAxisBinding(d, 1, Negative, Input::Up );
addAxisBinding(d, 1, Positive, Input::Down );
addHatBinding(d, 0, SDL_HAT_LEFT, Input::Left );
addHatBinding(d, 0, SDL_HAT_RIGHT, Input::Right);
addHatBinding(d, 0, SDL_HAT_UP, Input::Up );
addHatBinding(d, 0, SDL_HAT_DOWN, Input::Down );
return d;
}
#define FORMAT_VER 1
#define FORMAT_VER 2
struct Header
{
@ -166,7 +185,7 @@ struct Header
static void buildPath(const std::string &dir, uint32_t rgssVersion,
char *out, size_t outSize)
{
snprintf(out, outSize, "%s/keybindings.mkxp%u", dir.c_str(), rgssVersion);
snprintf(out, outSize, "%skeybindings.mkxp%u", dir.c_str(), rgssVersion);
}
static bool writeBindings(const BDescVec &d, const std::string &dir,
@ -178,7 +197,7 @@ static bool writeBindings(const BDescVec &d, const std::string &dir,
char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "w");
FILE *f = fopen(path, "wb");
if (!f)
return false;
@ -247,6 +266,10 @@ static bool verifyDesc(const BindingDesc &desc)
return src.d.scan < SDL_NUM_SCANCODES;
case JButton:
return true;
case JHat:
/* Only accept single directional binds */
return src.d.jh.pos == SDL_HAT_LEFT || src.d.jh.pos == SDL_HAT_RIGHT ||
src.d.jh.pos == SDL_HAT_UP || src.d.jh.pos == SDL_HAT_DOWN;
case JAxis:
return src.d.ja.dir == Negative || src.d.ja.dir == Positive;
default:
@ -263,7 +286,7 @@ static bool readBindings(BDescVec &out, const std::string &dir,
char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "r");
FILE *f = fopen(path, "rb");
if (!f)
return false;

View file

@ -25,6 +25,7 @@
#include "input.h"
#include <SDL_scancode.h>
#include <SDL_joystick.h>
#include <stdint.h>
#include <assert.h>
#include <vector>
@ -40,7 +41,8 @@ enum SourceType
Invalid,
Key,
JButton,
JAxis
JAxis,
JHat
};
struct SourceDesc
@ -60,6 +62,13 @@ struct SourceDesc
/* Joystick axis direction */
AxisDir dir;
} ja;
struct
{
/* Joystick axis index */
uint8_t hat;
/* Joystick axis direction */
uint8_t pos;
} jh;
} d;
bool operator==(const SourceDesc &o) const
@ -77,6 +86,8 @@ struct SourceDesc
return d.jb == o.d.jb;
case JAxis:
return (d.ja.axis == o.d.ja.axis) && (d.ja.dir == o.d.ja.dir);
case JHat:
return (d.jh.hat == o.d.jh.hat) && (d.jh.pos == o.d.jh.pos);
default:
assert(!"unreachable");
return false;

View file

@ -26,20 +26,21 @@
#include <SDL_ttf.h>
#include <SDL_sound.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <string>
#include "sharedstate.h"
#include "eventthread.h"
#include "debuglogger.h"
#include "gl-debug.h"
#include "debugwriter.h"
#include "exception.h"
#include "gl-fun.h"
#include "binding.h"
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "icon.png.xxd"
static void
rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
@ -67,13 +68,14 @@ printGLInfo()
int rgssThreadFun(void *userdata)
{
RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
const Config &conf = threadData->config;
SDL_Window *win = threadData->window;
SDL_GLContext glCtx;
/* Setup GL context */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (threadData->config.debugMode)
if (conf.debugMode)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
glCtx = SDL_GL_CreateContext(win);
@ -102,27 +104,17 @@ int rgssThreadFun(void *userdata)
printGLInfo();
SDL_GL_SetSwapInterval(threadData->config.vsync ? 1 : 0);
bool vsync = conf.vsync || conf.syncToRefreshrate;
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
DebugLogger dLogger;
GLDebugLogger dLogger;
/* Setup AL context */
ALCdevice *alcDev = alcOpenDevice(0);
if (!alcDev)
{
rgssThreadError(threadData, "Error opening OpenAL device");
SDL_GL_DeleteContext(glCtx);
return 0;
}
ALCcontext *alcCtx = alcCreateContext(alcDev, 0);
ALCcontext *alcCtx = alcCreateContext(threadData->alcDev, 0);
if (!alcCtx)
{
rgssThreadError(threadData, "Error creating OpenAL context");
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -138,7 +130,6 @@ int rgssThreadFun(void *userdata)
{
rgssThreadError(threadData, exc.msg);
alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -153,8 +144,6 @@ int rgssThreadFun(void *userdata)
SharedState::finiInstance();
alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -171,20 +160,27 @@ static void printRgssVersion(int ver)
Debug() << buf;
}
static void showInitError(const std::string &msg)
{
Debug() << msg;
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "mkxp", msg.c_str(), 0);
}
int main(int argc, char *argv[])
{
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
/* initialize SDL first */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
{
Debug() << "Error initializing SDL:" << SDL_GetError();
showInitError(std::string("Error initializing SDL: ") + SDL_GetError());
return 0;
}
if (!EventThread::allocUserEvents())
{
Debug() << "Error allocating SDL user events";
showInitError("Error allocating SDL user events");
return 0;
}
@ -201,8 +197,15 @@ int main(int argc, char *argv[])
/* now we load the config */
Config conf;
conf.read(argc, argv);
if (!conf.gameFolder.empty())
if (chdir(conf.gameFolder.c_str()) != 0)
{
showInitError(std::string("Unable to switch into gameFolder ") + conf.gameFolder);
return 0;
}
conf.readGameINI();
assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3);
@ -211,7 +214,7 @@ int main(int argc, char *argv[])
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if (IMG_Init(imgFlags) != imgFlags)
{
Debug() << "Error initializing SDL_image:" << SDL_GetError();
showInitError(std::string("Error initializing SDL_image: ") + SDL_GetError());
SDL_Quit();
return 0;
@ -219,7 +222,7 @@ int main(int argc, char *argv[])
if (TTF_Init() < 0)
{
Debug() << "Error initializing SDL_ttf:" << SDL_GetError();
showInitError(std::string("Error initializing SDL_ttf: ") + SDL_GetError());
IMG_Quit();
SDL_Quit();
@ -228,7 +231,7 @@ int main(int argc, char *argv[])
if (Sound_Init() == 0)
{
Debug() << "Error initializing SDL_sound:" << Sound_GetError();
showInitError(std::string("Error initializing SDL_sound: ") + Sound_GetError());
TTF_Quit();
IMG_Quit();
SDL_Quit();
@ -236,7 +239,15 @@ int main(int argc, char *argv[])
return 0;
}
SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
/* Setup application icon */
SDL_RWops *iconSrc;
if (conf.iconPath.empty())
iconSrc = SDL_RWFromConstMem(assets_icon_png, assets_icon_png_len);
else
iconSrc = SDL_RWFromFile(conf.iconPath.c_str(), "rb");
SDL_Surface *iconImg = IMG_Load_RW(iconSrc, SDL_TRUE);
SDL_Window *win;
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS;
@ -252,22 +263,43 @@ int main(int argc, char *argv[])
if (!win)
{
Debug() << "Error creating window:" << SDL_GetError();
showInitError(std::string("Error creating window: ") + SDL_GetError());
return 0;
}
if (!conf.iconPath.empty())
if (iconImg)
{
SDL_Surface *iconImg = IMG_Load(conf.iconPath.c_str());
if (iconImg)
{
SDL_SetWindowIcon(win, iconImg);
SDL_FreeSurface(iconImg);
}
SDL_SetWindowIcon(win, iconImg);
SDL_FreeSurface(iconImg);
}
ALCdevice *alcDev = alcOpenDevice(0);
if (!alcDev)
{
showInitError("Error opening OpenAL device");
SDL_DestroyWindow(win);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}
SDL_DisplayMode mode;
SDL_GetDisplayMode(0, 0, &mode);
/* Can't sync to display refresh rate if its value is unknown */
if (!mode.refresh_rate)
conf.syncToRefreshrate = false;
EventThread eventThread;
RGSSThreadData rtData(&eventThread, argv[0], win, conf);
RGSSThreadData rtData(&eventThread, argv[0], win,
alcDev, mode.refresh_rate, conf);
int winW, winH;
SDL_GetWindowSize(win, &winW, &winH);
rtData.windowSizeMsg.post(Vec2i(winW, winH));
/* Load and post key bindings */
rtData.bindingUpdateMsg.post(loadBindings(conf));
@ -314,13 +346,9 @@ int main(int argc, char *argv[])
/* Clean up any remainin events */
eventThread.cleanup();
/* Store key bindings */
BDescVec keyBinds;
rtData.bindingUpdateMsg.get(keyBinds);
storeBindings(keyBinds, rtData.config);
Debug() << "Shutting down.";
alcCloseDevice(alcDev);
SDL_DestroyWindow(win);
Sound_Quit();

View file

@ -55,7 +55,13 @@
#define TICK_FRAMES 32
#define BUF_TICKS (STREAM_BUF_SIZE / TICK_FRAMES)
#define DEFAULT_BPM 120
#define LOOP_MARKER 111
#define MAX_CHANNELS 16
#define CC_CTRL_VOLUME 7
#define CC_CTRL_EXPRESSION 11
#define CC_CTRL_LOOP 111
#define CC_VAL_DEFAULT 127
enum MidiEventType
{
@ -522,6 +528,59 @@ struct Track
}
};
/* Some songs use CC events for effects like fade-out,
* slowly decreasing a channel's volume to 0. The problem is that
* for looped songs, events are continuously fed into the synth
* without restoring those controls back to their default value.
* We can't reset them at the very beginning of tracks because it
* might cause audible interactions with notes which are still decaying
* past the end of the song. Therefore, we insert a fake CC event right
* after the first NoteOn event for each channel which resets the
* control to its default state while avoiding audible glitches.
* If there is already a CC event for this control before the first
* NoteOn event, we don't clobber it by not inserting our fake event. */
template<uint8_t ctrl>
struct CCResetter
{
bool chanHandled[MAX_CHANNELS];
CCResetter()
{
memset(&chanHandled, 0, sizeof(chanHandled));
}
void handleEvent(const MidiEvent &e, Track &track)
{
if (e.type != NoteOn && e.type != CC)
return;
uint8_t chan = e.e.chan.chan;
if (chanHandled[chan])
return;
if (e.type == CC && e.e.cc.ctrl == ctrl)
{
/* Don't clobber the existing CC value */
chanHandled[chan] = true;
return;
}
else if (e.type == NoteOn)
{
chanHandled[chan] = true;
MidiEvent re;
re.delta = 0;
re.type = CC;
re.e.cc.chan = chan;
re.e.cc.ctrl = ctrl;
re.e.cc.val = CC_VAL_DEFAULT;
track.appendEvent(re);
}
}
};
struct MidiSource : ALDataSource, MidiReadHandler
{
const uint16_t freq;
@ -530,6 +589,8 @@ struct MidiSource : ALDataSource, MidiReadHandler
int16_t synthBuf[BUF_TICKS*TICK_FRAMES*2];
std::vector<Track> tracks;
CCResetter<CC_CTRL_VOLUME> volReset;
CCResetter<CC_CTRL_EXPRESSION> expReset;
/* Index of longest track */
uint8_t longestI;
@ -631,7 +692,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
playbackSpeed = TICK_FRAMES / (deltaLength * freq);
}
void activateEvent(MidiEvent &e)
void activateEvent(const MidiEvent &e)
{
int16_t key = e.e.note.key;
@ -705,9 +766,14 @@ struct MidiSource : ALDataSource, MidiReadHandler
void onMidiEvent(const MidiEvent &e, uint32_t absDelta)
{
assert(curTrack >= 0 && curTrack < (int16_t) tracks.size());
tracks[curTrack].appendEvent(e);
if (e.type == CC && e.e.cc.ctrl == LOOP_MARKER)
Track &track = tracks[curTrack];
track.appendEvent(e);
volReset.handleEvent(e, track);
expReset.handleEvent(e, track);
if (e.type == CC && e.e.cc.ctrl == CC_CTRL_LOOP)
loopDelta = absDelta;
}

View file

@ -90,8 +90,8 @@ struct PlanePrivate
if (gl.npot_repeat)
{
FloatRect srcRect;
srcRect.x = (sceneGeo.xOrigin + ox) / zoomX;
srcRect.y = (sceneGeo.yOrigin + oy) / zoomY;
srcRect.x = (sceneGeo.orig.x + ox) / zoomX;
srcRect.y = (sceneGeo.orig.y + oy) / zoomY;
srcRect.w = sceneGeo.rect.w / zoomX;
srcRect.h = sceneGeo.rect.h / zoomY;

View file

@ -23,10 +23,7 @@
#include "sharedstate.h"
Scene::Scene()
{
geometry.xOrigin = geometry.yOrigin = 0;
geometry.rect = IntRect();
}
{}
Scene::~Scene()
{

View file

@ -39,8 +39,16 @@ class Scene
public:
struct Geometry
{
int xOrigin, yOrigin;
/* Position and size relative to parent */
IntRect rect;
/* Origin of contents */
Vec2i orig;
Vec2i offset() const
{
return rect.pos() - orig;
}
};
Scene();

View file

@ -3,8 +3,10 @@
#include <SDL_atomic.h>
#include <SDL_thread.h>
#include <SDL_rwops.h>
#include <string>
#include <iostream>
struct AtomicFlag
{
@ -45,4 +47,115 @@ SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string())
return SDL_CreateThread(__sdlThreadFun<C, func>, name.c_str(), obj);
}
/* On Android, SDL_RWFromFile always opens files from inside
* the apk asset folder even when a file with same name exists
* on the physical filesystem. This wrapper attempts to open a
* real file first before falling back to the assets folder */
static inline
SDL_RWops *RWFromFile(const char *filename,
const char *mode)
{
FILE *f = fopen(filename, mode);
if (!f)
return SDL_RWFromFile(filename, mode);
return SDL_RWFromFP(f, SDL_TRUE);
}
inline bool readFileSDL(const char *path,
std::string &out)
{
SDL_RWops *f = RWFromFile(path, "rb");
if (!f)
return false;
long size = SDL_RWsize(f);
size_t back = out.size();
out.resize(back+size);
size_t read = SDL_RWread(f, &out[back], 1, size);
SDL_RWclose(f);
if (read != (size_t) size)
out.resize(back+read);
return true;
}
template<size_t bufSize = 248, size_t pbSize = 8>
class SDLRWBuf : public std::streambuf
{
public:
SDLRWBuf(SDL_RWops *ops)
: ops(ops)
{
char *end = buf + bufSize + pbSize;
setg(end, end, end);
}
private:
int_type underflow()
{
if (!ops)
return traits_type::eof();
if (gptr() < egptr())
return traits_type::to_int_type(*gptr());
char *base = buf;
char *start = base;
if (eback() == base)
{
memmove(base, egptr() - pbSize, pbSize);
start += pbSize;
}
size_t n = SDL_RWread(ops, start, 1, bufSize - (start - base));
if (n == 0)
return traits_type::eof();
setg(base, start, start + n);
return underflow();
}
SDL_RWops *ops;
char buf[bufSize+pbSize];
};
class SDLRWStream
{
public:
SDLRWStream(const char *filename,
const char *mode)
: ops(RWFromFile(filename, mode)),
buf(ops),
s(&buf)
{}
~SDLRWStream()
{
if (ops)
SDL_RWclose(ops);
}
operator bool() const
{
return ops != 0;
}
std::istream &stream()
{
return s;
}
private:
SDL_RWops *ops;
SDLRWBuf<> buf;
std::istream s;
};
#endif // SDLUTIL_H

View file

@ -27,67 +27,44 @@
#include <SDL_endian.h>
typedef unsigned uint;
#if SDL_BYTEORDER != SDL_LIL_ENDIAN
#error "Non little endian systems not supported"
#endif
static inline int16_t
read_int16(const char *data, uint &i)
{
int16_t result;
memcpy(&result, &data[i], 2);
i += 2;
return result;
}
static inline int32_t
read_int32(const char *data, uint &i)
readInt32(const char **dataP)
{
int32_t result;
memcpy(&result, &data[i], 4);
i += 4;
memcpy(&result, *dataP, 4);
*dataP += 4;
return result;
}
static inline double
read_double(const char *data, uint &i)
readDouble(const char **dataP)
{
double result;
memcpy(&result, &data[i], 8);
i += 8;
memcpy(&result, *dataP, 8);
*dataP += 8;
return result;
}
static inline void
write_int16(char **data, int16_t value)
writeInt32(char **dataP, int32_t value)
{
memcpy(*data, &value, 2);
*data += 2;
memcpy(*dataP, &value, 4);
*dataP += 4;
}
static inline void
write_int32(char **data, int32_t value)
writeDouble(char **dataP, double value)
{
memcpy(*data, &value, 4);
*data += 4;
}
static inline void
write_double(char **data, double value)
{
memcpy(*data, &value, 8);
*data += 8;
memcpy(*dataP, &value, 8);
*dataP += 8;
}
#endif // SERIALUTIL_H

View file

@ -81,6 +81,7 @@ static elementsN(vButtons);
std::string sourceDescString(const SourceDesc &src)
{
char buf[128];
char pos;
switch (src.type)
{
@ -104,6 +105,32 @@ std::string sourceDescString(const SourceDesc &src)
snprintf(buf, sizeof(buf), "JS %d", src.d.jb);
return buf;
case JHat:
switch(src.d.jh.pos)
{
case SDL_HAT_UP:
pos = 'U';
break;
case SDL_HAT_DOWN:
pos = 'D';
break;
case SDL_HAT_LEFT:
pos = 'L';
break;
case SDL_HAT_RIGHT:
pos = 'R';
break;
default:
pos = '-';
}
snprintf(buf, sizeof(buf), "Hat %d:%c",
src.d.jh.hat, pos);
return buf;
case JAxis:
snprintf(buf, sizeof(buf), "Axis %d%c",
src.d.ja.axis, src.d.ja.dir == Negative ? '-' : '+');
@ -204,7 +231,8 @@ struct Label : Widget
Label(SMP *p, const IntRect &rect,
const char *str, uint8_t r, uint8_t g, uint8_t b)
: Widget(p, rect),
str(str)
str(str),
visible(true)
{
c.r = r;
c.g = g;
@ -615,6 +643,21 @@ struct SettingsMenuPrivate
desc.d.jb = event.jbutton.button;
break;
case SDL_JOYHATMOTION:
{
int v = event.jhat.value;
/* Only register if single directional input */
if (v != SDL_HAT_LEFT && v != SDL_HAT_RIGHT &&
v != SDL_HAT_UP && v != SDL_HAT_DOWN)
return true;
desc.type = JHat;
desc.d.jh.hat = event.jhat.hat;
desc.d.jh.pos = v;
break;
}
case SDL_JOYAXISMOTION:
{
int v = event.jaxis.value;
@ -677,6 +720,9 @@ struct SettingsMenuPrivate
rtData.bindingUpdateMsg.post(binds);
/* Store the key bindings to disk as well to prevent config loss */
storeBindings(binds, rtData.config);
destroyReq = true;
}
@ -1007,6 +1053,7 @@ bool SettingsMenu::onEvent(const SDL_Event &event)
case SDL_JOYBUTTONDOWN :
case SDL_JOYBUTTONUP :
case SDL_JOYHATMOTION :
case SDL_JOYAXISMOTION :
if (!p->hasFocus)
return false;
@ -1083,6 +1130,7 @@ bool SettingsMenu::onEvent(const SDL_Event &event)
}
case SDL_JOYBUTTONDOWN:
case SDL_JOYHATMOTION:
case SDL_JOYAXISMOTION:
if (p->state != AwaitingInput)
return true;

View file

@ -28,25 +28,30 @@
#include <string.h>
#include <iostream>
#include "../sprite.frag.xxd"
#include "../hue.frag.xxd"
#include "../trans.frag.xxd"
#include "../transSimple.frag.xxd"
#include "../bitmapBlit.frag.xxd"
#include "../plane.frag.xxd"
#include "../simple.frag.xxd"
#include "../simpleColor.frag.xxd"
#include "../simpleAlpha.frag.xxd"
#include "../flashMap.frag.xxd"
#include "../simple.vert.xxd"
#include "../simpleColor.vert.xxd"
#include "../sprite.vert.xxd"
#include "../tilemap.vert.xxd"
#include "../blur.frag.xxd"
#include "../simpleMatrix.vert.xxd"
#include "../blurH.vert.xxd"
#include "../blurV.vert.xxd"
#include "../tilemapvx.vert.xxd"
#include "common.h.xxd"
#include "sprite.frag.xxd"
#include "hue.frag.xxd"
#include "trans.frag.xxd"
#include "transSimple.frag.xxd"
#include "bitmapBlit.frag.xxd"
#include "plane.frag.xxd"
#include "gray.frag.xxd"
#include "flatColor.frag.xxd"
#include "simple.frag.xxd"
#include "simpleColor.frag.xxd"
#include "simpleAlpha.frag.xxd"
#include "simpleAlphaUni.frag.xxd"
#include "flashMap.frag.xxd"
#include "minimal.vert.xxd"
#include "simple.vert.xxd"
#include "simpleColor.vert.xxd"
#include "sprite.vert.xxd"
#include "tilemap.vert.xxd"
#include "blur.frag.xxd"
#include "simpleMatrix.vert.xxd"
#include "blurH.vert.xxd"
#include "blurV.vert.xxd"
#include "tilemapvx.vert.xxd"
#define INIT_SHADER(vert, frag, name) \
@ -106,32 +111,39 @@ void Shader::unbind()
glState.program.set(0);
}
static const char *glesHeader = "precision mediump float;\n";
static const size_t glesHeaderSize = strlen(glesHeader);
static void setupShaderSource(GLuint shader,
const unsigned char *src, int srcSize)
static void setupShaderSource(GLuint shader, GLenum type,
const unsigned char *body, int bodySize)
{
GLuint shaderSrcN;
const GLchar *shaderSrc[2];
GLint shaderSrcSize[2];
static const char glesDefine[] = "#define GLSLES\n";
static const char fragDefine[] = "#define FRAGMENT_SHADER\n";
const GLchar *shaderSrc[4];
GLint shaderSrcSize[4];
size_t i = 0;
if (gl.glsles)
{
shaderSrcN = 2;
shaderSrc[0] = glesHeader;
shaderSrc[1] = (const GLchar*) src;
shaderSrcSize[0] = glesHeaderSize;
shaderSrcSize[1] = srcSize;
}
else
{
shaderSrcN = 1;
shaderSrc[0] = (const GLchar*) src;
shaderSrcSize[0] = srcSize;
shaderSrc[i] = glesDefine;
shaderSrcSize[i] = sizeof(glesDefine)-1;
++i;
}
gl.ShaderSource(shader, shaderSrcN, shaderSrc, shaderSrcSize);
if (type == GL_FRAGMENT_SHADER)
{
shaderSrc[i] = fragDefine;
shaderSrcSize[i] = sizeof(fragDefine)-1;
++i;
}
shaderSrc[i] = (const GLchar*) shader_common_h;
shaderSrcSize[i] = shader_common_h_len;
++i;
shaderSrc[i] = (const GLchar*) body;
shaderSrcSize[i] = bodySize;
++i;
gl.ShaderSource(shader, i, shaderSrc, shaderSrcSize);
}
void Shader::init(const unsigned char *vert, int vertSize,
@ -142,7 +154,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
GLint success;
/* Compile vertex shader */
setupShaderSource(vertShader, vert, vertSize);
setupShaderSource(vertShader, GL_VERTEX_SHADER, vert, vertSize);
gl.CompileShader(vertShader);
gl.GetShaderiv(vertShader, GL_COMPILE_STATUS, &success);
@ -156,7 +168,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
}
/* Compile fragment shader */
setupShaderSource(fragShader, frag, fragSize);
setupShaderSource(fragShader, GL_FRAGMENT_SHADER, frag, fragSize);
gl.CompileShader(fragShader);
gl.GetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
@ -260,6 +272,21 @@ void ShaderBase::setTranslation(const Vec2i &value)
}
FlatColorShader::FlatColorShader()
{
INIT_SHADER(minimal, flatColor, FlatColorShader);
ShaderBase::init();
GET_U(color);
}
void FlatColorShader::setColor(const Vec4 &value)
{
setVec4Uniform(u_color, value);
}
SimpleShader::SimpleShader()
{
INIT_SHADER(simple, simple, SimpleShader);
@ -306,6 +333,27 @@ void SimpleSpriteShader::setSpriteMat(const float value[16])
}
AlphaSpriteShader::AlphaSpriteShader()
{
INIT_SHADER(sprite, simpleAlphaUni, AlphaSpriteShader);
ShaderBase::init();
GET_U(spriteMat);
GET_U(alpha);
}
void AlphaSpriteShader::setSpriteMat(const float value[16])
{
gl.UniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value);
}
void AlphaSpriteShader::setAlpha(float value)
{
gl.Uniform1f(u_alpha, value);
}
TransShader::TransShader()
{
INIT_SHADER(simple, trans, TransShader);
@ -450,6 +498,21 @@ void PlaneShader::setOpacity(float value)
}
GrayShader::GrayShader()
{
INIT_SHADER(simple, gray, GrayShader);
ShaderBase::init();
GET_U(gray);
}
void GrayShader::setGray(float value)
{
gl.Uniform1f(u_gray, value);
}
TilemapShader::TilemapShader()
{
INIT_SHADER(tilemap, simple, TilemapShader);

View file

@ -87,6 +87,17 @@ protected:
GLint u_texSizeInv, u_translation;
};
class FlatColorShader : public ShaderBase
{
public:
FlatColorShader();
void setColor(const Vec4 &value);
private:
GLint u_color;
};
class SimpleShader : public ShaderBase
{
public:
@ -121,6 +132,18 @@ private:
GLint u_spriteMat;
};
class AlphaSpriteShader : public ShaderBase
{
public:
AlphaSpriteShader();
void setSpriteMat(const float value[16]);
void setAlpha(float value);
private:
GLint u_spriteMat, u_alpha;
};
class TransShader : public ShaderBase
{
public:
@ -179,6 +202,17 @@ private:
GLint u_tone, u_color, u_flash, u_opacity;
};
class GrayShader : public ShaderBase
{
public:
GrayShader();
void setGray(float value);
private:
GLint u_gray;
};
class TilemapShader : public ShaderBase
{
public:
@ -273,12 +307,15 @@ private:
/* Global object containing all available shaders */
struct ShaderSet
{
FlatColorShader flatColor;
SimpleShader simple;
SimpleColorShader simpleColor;
SimpleAlphaShader simpleAlpha;
SimpleSpriteShader simpleSprite;
AlphaSpriteShader alphaSprite;
SpriteShader sprite;
PlaneShader plane;
GrayShader gray;
TilemapShader tilemap;
FlashMapShader flashMap;
TransShader trans;

View file

@ -46,14 +46,14 @@ SharedState *SharedState::instance = 0;
int SharedState::rgssVersion = 0;
static GlobalIBO *_globalIBO = 0;
static const char *defGameArchive()
static const char *gameArchExt()
{
if (rgssVer == 1)
return "Game.rgssad";
return ".rgssad";
else if (rgssVer == 2)
return "Game.rgss2a";
return ".rgss2a";
else if (rgssVer == 3)
return "Game.rgss3a";
return ".rgss3a";
assert(!"unreachable");
return 0;
@ -88,6 +88,7 @@ struct SharedStatePrivate
TEX::ID globalTex;
int globalTexW, globalTexH;
bool globalTexDirty;
TEXFBO gpTexFBO;
@ -107,25 +108,18 @@ struct SharedStatePrivate
midiState(threadData->config),
graphics(threadData),
input(*threadData),
audio(threadData->config),
audio(*threadData),
fontState(threadData->config),
stampCounter(0)
{
if (!config.gameFolder.empty())
{
int result = chdir(config.gameFolder.c_str());
/* Shaders have been compiled in ShaderSet's constructor */
if (gl.ReleaseShaderCompiler)
gl.ReleaseShaderCompiler();
if (result != 0)
throw Exception(Exception::MKXPError,
"Unable to switch into gameFolder '%s'",
config.gameFolder.c_str());
}
// FIXME find out correct archive filename
std::string archPath = defGameArchive();
std::string archPath = config.execName + gameArchExt();
/* Check if a game archive exists */
FILE *tmp = fopen(archPath.c_str(), "r");
FILE *tmp = fopen(archPath.c_str(), "rb");
if (tmp)
{
fileSystem.addPath(archPath.c_str());
@ -150,6 +144,7 @@ struct SharedStatePrivate
TEX::setRepeat(false);
TEX::setSmooth(false);
TEX::allocEmpty(globalTexW, globalTexH);
globalTexDirty = false;
TEXFBO::init(gpTexFBO);
/* Reuse starting values */
@ -257,16 +252,27 @@ GlobalIBO &SharedState::globalIBO()
void SharedState::bindTex()
{
TEX::bind(p->globalTex);
TEX::allocEmpty(p->globalTexW, p->globalTexH);
if (p->globalTexDirty)
{
TEX::allocEmpty(p->globalTexW, p->globalTexH);
p->globalTexDirty = false;
}
}
void SharedState::ensureTexSize(int minW, int minH, Vec2i &currentSizeOut)
{
if (minW > p->globalTexW)
{
p->globalTexDirty = true;
p->globalTexW = findNextPow2(minW);
}
if (minH > p->globalTexH)
{
p->globalTexDirty = true;
p->globalTexH = findNextPow2(minH);
}
currentSizeOut = Vec2i(p->globalTexW, p->globalTexH);
}

View file

@ -26,6 +26,7 @@
#include "exception.h"
#include "config.h"
#include "util.h"
#include "debugwriter.h"
#include <SDL_sound.h>
@ -120,13 +121,16 @@ SoundEmitter::~SoundEmitter()
void SoundEmitter::play(const std::string &filename,
int volume,
int pitch)
int pitch)
{
float _volume = clamp<int>(volume, 0, 100) / 100.f;
float _pitch = clamp<int>(pitch, 50, 150) / 100.f;
SoundBuffer *buffer = allocateBuffer(filename);
if (!buffer)
return;
/* Try to find first free source */
size_t i;
for (i = 0; i < srcCount; ++i)
@ -168,7 +172,7 @@ void SoundEmitter::play(const std::string &filename,
if (switchBuffer)
AL::Source::attachBuffer(src, buffer->alBuffer);
AL::Source::setVolume(src, _volume);
AL::Source::setVolume(src, _volume * GLOBAL_VOLUME);
AL::Source::setPitch(src, _pitch);
AL::Source::play(src);
@ -197,18 +201,22 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
{
/* Buffer not in cashe, needs to be loaded */
SDL_RWops dataSource;
const char *extension;
char ext[8];
shState->fileSystem().openRead(dataSource, filename.c_str(),
FileSystem::Audio, false, &extension);
false, ext, sizeof(ext));
Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, extension, 0, STREAM_BUF_SIZE);
Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, ext, 0, STREAM_BUF_SIZE);
if (!sampleHandle)
{
SDL_RWclose(&dataSource);
throw Exception(Exception::SDLError, "%s.%s: %s",
filename.c_str(), extension, Sound_GetError());
char buf[512];
snprintf(buf, sizeof(buf), "Unable to decode sound: %s.%s: %s",
filename.c_str(), ext, Sound_GetError());
buf[sizeof(buf)-1] = '\0';
Debug() << buf;
return 0;
}
uint32_t decBytes = Sound_DecodeAll(sampleHandle);

View file

@ -57,7 +57,8 @@ struct SpritePrivate
NormValue opacity;
BlendType blendType;
SDL_Rect sceneRect;
IntRect sceneRect;
Vec2i sceneOrig;
/* Would this sprite be visible on
* the screen if drawn? */
@ -182,9 +183,8 @@ struct SpritePrivate
return;
}
SDL_Rect self;
self.x = trans.getPosition().x - trans.getOrigin().x;
self.y = trans.getPosition().y - trans.getOrigin().y;
IntRect self;
self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
self.w = bitmap->width();
self.h = bitmap->height();
@ -332,7 +332,7 @@ void Sprite::setBitmap(Bitmap *bitmap)
p->bitmap = bitmap;
if (!bitmap)
if (nullOrDisposed(bitmap))
return;
bitmap->ensureNonMega();
@ -515,7 +515,6 @@ void Sprite::draw()
bool renderEffect = p->color->hasEffect() ||
p->tone->hasEffect() ||
p->opacity != 255 ||
flashing ||
p->bushDepth != 0;
@ -541,6 +540,16 @@ void Sprite::draw()
base = &shader;
}
else if (p->opacity != 255)
{
AlphaSpriteShader &shader = shState->shaders().alphaSprite;
shader.bind();
shader.setSpriteMat(p->trans.getMatrix());
shader.setAlpha(p->opacity.norm);
shader.applyViewportProj();
base = &shader;
}
else
{
SimpleSpriteShader &shader = shState->shaders().simpleSprite;
@ -567,13 +576,10 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo)
{
/* Offset at which the sprite will be drawn
* relative to screen origin */
int xOffset = geo.rect.x - geo.xOrigin;
int yOffset = geo.rect.y - geo.yOrigin;
p->trans.setGlobalOffset(geo.offset());
p->trans.setGlobalOffset(xOffset, yOffset);
p->sceneRect.w = geo.rect.w;
p->sceneRect.h = geo.rect.h;
p->sceneRect.setSize(geo.rect.size());
p->sceneOrig = geo.orig;
}
void Sprite::releaseResources()

View file

@ -30,94 +30,92 @@
/* Init normally */
Table::Table(int x, int y /*= 1*/, int z /*= 1*/)
: m_x(x), m_y(y), m_z(z),
: xs(x), ys(y), zs(z),
data(x*y*z)
{}
Table::Table(const Table &other)
: m_x(other.m_x), m_y(other.m_y), m_z(other.m_z),
: xs(other.xs), ys(other.ys), zs(other.zs),
data(other.data)
{}
int16_t Table::get(int x, int y, int z) const
{
return data[m_x*m_y*z + m_x*y + x];
return data[xs*ys*z + xs*y + x];
}
void Table::set(int16_t value, int x, int y, int z)
{
if (x < 0 || x >= m_x
|| y < 0 || y >= m_y
|| z < 0 || z >= m_z)
if (x < 0 || x >= xs
|| y < 0 || y >= ys
|| z < 0 || z >= zs)
{
return;
}
data[m_x*m_y*z + m_x*y + x] = value;
data[xs*ys*z + xs*y + x] = value;
modified();
}
void Table::resize(int x, int y, int z)
{
if (x == m_x && y == m_y && z == m_z)
if (x == xs && y == ys && z == zs)
return;
std::vector<int16_t> newData(x*y*z);
for (int k = 0; k < std::min(z, m_z); ++k)
for (int j = 0; j < std::min(y, m_y); ++j)
for (int i = 0; i < std::min(x, m_x); ++i)
for (int k = 0; k < std::min(z, zs); ++k)
for (int j = 0; j < std::min(y, ys); ++j)
for (int i = 0; i < std::min(x, xs); ++i)
newData[x*y*k + x*j + i] = at(i, j, k);
data.swap(newData);
m_x = x;
m_y = y;
m_z = z;
xs = x;
ys = y;
zs = z;
return;
}
void Table::resize(int x, int y)
{
resize(x, y, m_z);
resize(x, y, zs);
}
void Table::resize(int x)
{
resize(x, m_y, m_z);
resize(x, ys, zs);
}
/* Serializable */
int Table::serialSize() const
{
/* header + data */
return 20 + (m_x * m_y * m_z) * 2;
return 20 + (xs * ys * zs) * 2;
}
void Table::serialize(char *buffer) const
{
char *buff_p = buffer;
/* Table dimensions: we don't care
* about them but RMXP needs them */
int dim = 1;
int size = m_x * m_y * m_z;
int size = xs * ys * zs;
if (m_y > 1)
if (ys > 1)
dim = 2;
if (m_z > 1)
if (zs > 1)
dim = 3;
write_int32(&buff_p, dim);
write_int32(&buff_p, m_x);
write_int32(&buff_p, m_y);
write_int32(&buff_p, m_z);
write_int32(&buff_p, size);
writeInt32(&buffer, dim);
writeInt32(&buffer, xs);
writeInt32(&buffer, ys);
writeInt32(&buffer, zs);
writeInt32(&buffer, size);
memcpy(buff_p, dataPtr(data), sizeof(int16_t)*size);
memcpy(buffer, dataPtr(data), sizeof(int16_t)*size);
}
@ -126,13 +124,11 @@ Table *Table::deserialize(const char *data, int len)
if (len < 20)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
uint idx = 0;
read_int32(data, idx);
int x = read_int32(data, idx);
int y = read_int32(data, idx);
int z = read_int32(data, idx);
int size = read_int32(data, idx);
readInt32(&data);
int x = readInt32(&data);
int y = readInt32(&data);
int z = readInt32(&data);
int size = readInt32(&data);
if (size != x*y*z)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
@ -141,7 +137,7 @@ Table *Table::deserialize(const char *data, int len)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
Table *t = new Table(x, y, z);
memcpy(dataPtr(t->data), &data[idx], sizeof(int16_t)*size);
memcpy(dataPtr(t->data), data, sizeof(int16_t)*size);
return t;
}

View file

@ -36,9 +36,9 @@ public:
Table(const Table &other);
virtual ~Table() {}
int xSize() const { return m_x; }
int ySize() const { return m_y; }
int zSize() const { return m_z; }
int xSize() const { return xs; }
int ySize() const { return ys; }
int zSize() const { return zs; }
int16_t get(int x, int y = 0, int z = 0) const;
void set(int16_t value, int x, int y = 0, int z = 0);
@ -54,18 +54,18 @@ public:
/* <internal */
inline int16_t &at(int x, int y = 0, int z = 0)
{
return data[m_x*m_y*z + m_x*y + x];
return data[xs*ys*z + xs*y + x];
}
inline const int16_t &at(int x, int y = 0, int z = 0) const
{
return data[m_x*m_y*z + m_x*y + x];
return data[xs*ys*z + xs*y + x];
}
sigc::signal<void> modified;
private:
int m_x, m_y, m_z;
int xs, ys, zs;
std::vector<int16_t> data;
};

View file

@ -21,6 +21,7 @@
#include "tileatlasvx.h"
#include "tilemap-common.h"
#include "bitmap.h"
#include "table.h"
#include "etc-internal.h"
@ -65,21 +66,6 @@ static elementsN(autotileVXRectsC);
namespace TileAtlasVX
{
static int
wrap(int value, int range)
{
int res = value % range;
return res < 0 ? res + range : res;
}
static int16_t
tableGetWrapped(const Table &t, int x, int y, int z = 0)
{
return t.at(wrap(x, t.xSize()),
wrap(y, t.ySize()),
z);
}
static int16_t
tableGetSafe(const Table *t, int x)
{
@ -333,35 +319,6 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT])
#define OVER_PLAYER_FLAG (1 << 4)
#define TABLE_FLAG (1 << 7)
static void
atSelectSubPos(FloatRect &pos, int i)
{
switch (i)
{
case 0:
return;
case 1:
pos.x += 16;
return;
case 2:
pos.y += 16;
return;
case 3:
pos.x += 16;
pos.y += 16;
return;
case 4:
pos.y += 24;
return;
case 5:
pos.x += 16;
pos.y += 24;
return;
default:
assert(!"Unreachable");
}
}
/* Reference: http://www.tktkgame.com/tkool/memo/vx/tile_id.html */
static void

View file

@ -1,5 +1,5 @@
/*
** flashmap.h
** tilemap-common.h
**
** This file is part of mkxp.
**
@ -19,8 +19,8 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FLASHMAP_H
#define FLASHMAP_H
#ifndef TILEMAPCOMMON_H
#define TILEMAPCOMMON_H
#include "table.h"
#include "gl-util.h"
@ -30,8 +30,11 @@
#include "glstate.h"
#include "shader.h"
#include "vertex.h"
#include "quad.h"
#include "etc-internal.h"
#include <stdint.h>
#include <assert.h>
#include <vector>
#include <sigc++/connection.h>
@ -44,11 +47,50 @@ wrap(int value, int range)
}
static inline int16_t
tableGetWrapped(const Table *t, int x, int y, int z = 0)
tableGetWrapped(const Table &t, int x, int y, int z = 0)
{
return t->get(wrap(x, t->xSize()),
wrap(y, t->ySize()),
z);
return t.get(wrap(x, t.xSize()),
wrap(y, t.ySize()),
z);
}
enum AtSubPos
{
TopLeft = 0,
TopRight = 1,
BottomLeft = 2,
BottomRight = 3,
BottomLeftTable = 4,
BottomRightTable = 5
};
static inline void
atSelectSubPos(FloatRect &pos, int i)
{
switch (i)
{
case TopLeft:
return;
case TopRight:
pos.x += 16;
return;
case BottomLeft:
pos.y += 16;
return;
case BottomRight:
pos.x += 16;
pos.y += 16;
return;
case BottomLeftTable:
pos.y += 24;
return;
case BottomRightTable:
pos.x += 16;
pos.y += 24;
return;
default:
assert(!"Unreachable");
}
}
struct FlashMap
@ -144,7 +186,7 @@ private:
bool sampleFlashColor(Vec4 &out, int x, int y) const
{
int16_t packed = tableGetWrapped(data, x, y);
int16_t packed = tableGetWrapped(*data, x, y);
if (packed == 0)
return false;
@ -216,4 +258,4 @@ private:
std::vector<CVertex> vertices;
};
#endif // FLASHMAP_H
#endif // TILEMAPCOMMON_H

View file

@ -26,6 +26,7 @@
#include "table.h"
#include "sharedstate.h"
#include "config.h"
#include "glstate.h"
#include "gl-util.h"
#include "gl-meta.h"
@ -36,7 +37,7 @@
#include "quad.h"
#include "vertex.h"
#include "tileatlas.h"
#include "flashmap.h"
#include "tilemap-common.h"
#include <sigc++/connection.h>
@ -441,15 +442,13 @@ struct TilemapPrivate
void updateSceneGeometry(const Scene::Geometry &geo)
{
elem.sceneOffset.x = geo.rect.x - geo.xOrigin;
elem.sceneOffset.y = geo.rect.y - geo.yOrigin;
elem.sceneOffset = geo.offset();
elem.sceneGeo = geo;
}
void updatePosition()
{
dispPos.x = -(offset.x - viewpPos.x * 32) + elem.sceneOffset.x;
dispPos.y = -(offset.y - viewpPos.y * 32) + elem.sceneOffset.y;
dispPos = -(offset - viewpPos * 32) + elem.sceneOffset;
}
void invalidateAtlasSize()
@ -542,19 +541,59 @@ struct TilemapPrivate
if (tileset->megaSurface())
{
/* Mega surface tileset */
TEX::bind(atlas.gl.tex);
SDL_Surface *tsSurf = tileset->megaSurface();
for (size_t i = 0; i < blits.size(); ++i)
if (shState->config().subImageFix)
{
const TileAtlas::Blit &blitOp = blits[i];
/* Implementation for broken GL drivers */
FBO::bind(atlas.gl.fbo);
glState.blend.pushSet(false);
glState.viewport.pushSet(IntRect(0, 0, atlas.size.x, atlas.size.y));
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
SimpleShader &shader = shState->shaders().simple;
shader.bind();
shader.applyViewportProj();
shader.setTranslation(Vec2i());
Quad &quad = shState->gpQuad();
for (size_t i = 0; i < blits.size(); ++i)
{
const TileAtlas::Blit &blitOp = blits[i];
Vec2i texSize;
shState->ensureTexSize(tsLaneW, blitOp.h, texSize);
shState->bindTex();
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
0, 0, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
shader.setTexSize(texSize);
quad.setTexRect(FloatRect(0, 0, tsLaneW, blitOp.h));
quad.setPosRect(FloatRect(blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h));
quad.draw();
}
GLMeta::subRectImageEnd();
glState.viewport.pop();
glState.blend.pop();
}
else
{
/* Clean implementation */
TEX::bind(atlas.gl.tex);
for (size_t i = 0; i < blits.size(); ++i)
{
const TileAtlas::Blit &blitOp = blits[i];
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
}
GLMeta::subRectImageEnd();
}
GLMeta::subRectImageEnd();
}
else
{
@ -590,21 +629,6 @@ struct TilemapPrivate
return value;
}
FloatRect getAutotilePieceRect(int x, int y, /* in pixel coords */
int corner)
{
switch (corner)
{
case 0 : break;
case 1 : x += 16; break;
case 2 : x += 16; y += 16; break;
case 3 : y += 16; break;
default: abort();
}
return FloatRect(x, y, 16, 16);
}
void handleAutotile(int x, int y, int tileInd, SVVector *array)
{
/* Which autotile [0-7] */
@ -617,7 +641,9 @@ struct TilemapPrivate
/* Iterate over the 4 tile pieces */
for (int i = 0; i < 4; ++i)
{
FloatRect posRect = getAutotilePieceRect(x*32, y*32, i);
FloatRect posRect(x*32, y*32, 16, 16);
atSelectSubPos(posRect, i);
FloatRect texRect = pieceRect[i];
/* Adjust to atlas coordinates */
@ -635,7 +661,7 @@ struct TilemapPrivate
void handleTile(int x, int y, int z)
{
int tileInd =
tableGetWrapped(mapData, x + viewpPos.x, y + viewpPos.y, z);
tableGetWrapped(*mapData, x + viewpPos.x, y + viewpPos.y, z);
/* Check for empty space */
if (tileInd < 48)
@ -972,6 +998,9 @@ void GroundLayer::updateVboCount()
void GroundLayer::draw()
{
if (p->groundVert.size() == 0)
return;
ShaderBase *shader;
p->bindShader(shader);

View file

@ -33,7 +33,7 @@
#include "quad.h"
#include "quadarray.h"
#include "shader.h"
#include "flashmap.h"
#include "tilemap-common.h"
#include <vector>
#include <sigc++/connection.h>
@ -366,11 +366,10 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
void onGeometryChange(const Scene::Geometry &geo)
{
mapViewp.w = (geo.rect.w / 32) + !!(geo.rect.w % 32) + 1;
mapViewp.h = (geo.rect.h / 32) + !!(geo.rect.h % 32) + 1;
const Vec2i geoSize = geo.rect.size();
mapViewp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1));
sceneOffset.x = geo.rect.x - geo.xOrigin;
sceneOffset.y = geo.rect.y - geo.yOrigin;
sceneOffset = geo.offset();
sceneGeo = geo;
buffersDirty = true;

View file

@ -58,7 +58,6 @@ public:
Transform()
: scale(1, 1),
rotation(0),
xOffset(0), yOffset(0),
dirty(true)
{
memset(matrix, 0, sizeof(matrix));
@ -68,38 +67,47 @@ public:
}
Vec2 &getPosition() { return position; }
Vec2 &getScale() { return scale; }
Vec2 &getOrigin() { return origin; }
Vec2 &getScale() { return scale; }
float getRotation() { return rotation; }
Vec2i getPositionI() const
{
return Vec2i(position.x, position.y);
}
Vec2i getOriginI() const
{
return Vec2i(origin.x, origin.y);
}
void setPosition(const Vec2 &value)
{
position = value;
dirty = true;
}
void setScale(const Vec2 &value)
{
scale = value;
dirty = true;
}
void setOrigin(const Vec2 &value)
{
origin = value;
dirty = true;
}
void setScale(const Vec2 &value)
{
scale = value;
dirty = true;
}
void setRotation(float value)
{
rotation = value;
dirty = true;
}
void setGlobalOffset(int x, int y)
void setGlobalOffset(const Vec2i &value)
{
xOffset = x;
yOffset = y;
offset = value;
dirty = true;
}
@ -129,8 +137,8 @@ private:
float syc = scale.y * cosine;
float sxs = scale.x * sine;
float sys = scale.y * sine;
float tx = -origin.x * sxc - origin.y * sys + position.x + xOffset;
float ty = origin.x * sxs - origin.y * syc + position.y + yOffset;
float tx = -origin.x * sxc - origin.y * sys + position.x + offset.x;
float ty = origin.x * sxs - origin.y * syc + position.y + offset.y;
matrix[0] = sxc;
matrix[1] = -sxs;
@ -146,7 +154,7 @@ private:
float rotation;
/* Silently added to position */
int xOffset, yOffset;
Vec2i offset;
float matrix[16];

View file

@ -66,7 +66,7 @@ findNextPow2(int start)
inline bool readFile(const char *path,
std::string &out)
{
FILE *f = fopen(path, "r");
FILE *f = fopen(path, "rb");
if (!f)
return false;

View file

@ -144,8 +144,8 @@ void Viewport::update()
Flashable::update();
}
DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.xOrigin)
DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.yOrigin)
DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.orig.x)
DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.orig.y)
DEF_ATTR_SIMPLE(Viewport, Rect, Rect&, *p->rect)
DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color)
@ -155,10 +155,10 @@ void Viewport::setOX(int value)
{
guardDisposed();
if (geometry.xOrigin == value)
if (geometry.orig.x == value)
return;
geometry.xOrigin = value;
geometry.orig.x = value;
notifyGeometryChange();
}
@ -166,10 +166,10 @@ void Viewport::setOY(int value)
{
guardDisposed();
if (geometry.yOrigin == value)
if (geometry.orig.y == value)
return;
geometry.yOrigin = value;
geometry.orig.y = value;
notifyGeometryChange();
}

View file

@ -471,16 +471,15 @@ struct WindowPrivate
i += TileQuads::buildFrame(effectRect, cursorVert.vert);
}
/* Scroll arrows */
int scrollLRY = (size.y - 16) / 2;
int scrollTBX = (size.x - 16) / 2;
/* Scroll arrow position: Top Bottom X, Left Right Y */
const Vec2i scroll = (size - Vec2i(16)) / 2;
Sides<IntRect> scrollArrows;
scrollArrows.l = IntRect(4, scrollLRY, 8, 16);
scrollArrows.r = IntRect(size.x - 12, scrollLRY, 8, 16);
scrollArrows.t = IntRect(scrollTBX, 4, 16, 8);
scrollArrows.b = IntRect(scrollTBX, size.y - 12, 16, 8);
scrollArrows.l = IntRect(4, scroll.y, 8, 16);
scrollArrows.r = IntRect(size.x - 12, scroll.y, 8, 16);
scrollArrows.t = IntRect(scroll.x, 4, 16, 8);
scrollArrows.b = IntRect(scroll.x, size.y - 12, 16, 8);
if (contents)
{
@ -557,13 +556,10 @@ struct WindowPrivate
if (size == Vec2i(0, 0))
return;
Vec2i trans(position.x + sceneOffset.x,
position.y + sceneOffset.y);
SimpleAlphaShader &shader = shState->shaders().simpleAlpha;
shader.bind();
shader.applyViewportProj();
shader.setTranslation(trans);
shader.setTranslation(position + sceneOffset);
if (useBaseTex)
{
@ -598,12 +594,11 @@ struct WindowPrivate
controlsVertDirty = false;
}
/* Actual on screen coordinates */
int effectX = position.x + sceneOffset.x;
int effectY = position.y + sceneOffset.y;
/* Effective on screen coordinates */
const Vec2i efPos = position + sceneOffset;
IntRect windowRect(effectX, effectY, size.x, size.y);
IntRect contentsRect(effectX+16, effectY+16, size.x-32, size.y-32);
const IntRect windowRect(efPos, size);
const IntRect contentsRect(efPos + Vec2i(16), size - Vec2i(32));
glState.scissorTest.pushSet(true);
glState.scissorBox.push();
@ -615,7 +610,7 @@ struct WindowPrivate
if (!nullOrDisposed(windowskin))
{
shader.setTranslation(Vec2i(effectX, effectY));
shader.setTranslation(efPos);
/* Draw arrows / cursors */
windowskin->bindTex(shader);
@ -631,9 +626,7 @@ struct WindowPrivate
/* Draw contents bitmap */
glState.scissorBox.setIntersect(contentsRect);
effectX += 16-contentsOffset.x;
effectY += 16-contentsOffset.y;
shader.setTranslation(Vec2i(effectX, effectY));
shader.setTranslation(efPos + (Vec2i(16) - contentsOffset));
contents->bindTex(shader);
contentsQuad.draw();
@ -727,7 +720,7 @@ void Window::setWindowskin(Bitmap *value)
p->windowskin = value;
if (!value)
if (nullOrDisposed(value))
return;
value->ensureNonMega();
@ -743,7 +736,7 @@ void Window::setContents(Bitmap *value)
p->contents = value;
p->controlsVertDirty = true;
if (!value)
if (nullOrDisposed(value))
return;
value->ensureNonMega();
@ -876,8 +869,7 @@ void Window::draw()
void Window::onGeometryChange(const Scene::Geometry &geo)
{
p->sceneOffset.x = geo.rect.x - geo.xOrigin;
p->sceneOffset.y = geo.rect.y - geo.yOrigin;
p->sceneOffset = geo.offset();
}
void Window::setZ(int value)

View file

@ -506,15 +506,15 @@ struct WindowVXPrivate
void rebuildCtrlVert()
{
const int arrowTBX = (geo.w - 16) / 2;
const int arrowLRY = (geo.h - 16) / 2;
/* Scroll arrow position: Top Bottom X, Left Right Y */
const Vec2i arrow = (geo.size() - Vec2i(16)) / 2;
const Sides<FloatRect> arrowPos =
{
FloatRect( 4, arrowLRY, 8, 16 ), /* Left */
FloatRect( geo.w - 12, arrowLRY, 8, 16 ), /* Right */
FloatRect( arrowTBX, 4, 16, 8 ), /* Top */
FloatRect( arrowTBX, geo.h - 12, 16, 8 ) /* Bottom */
FloatRect( 4, arrow.y, 8, 16 ), /* Left */
FloatRect( geo.w - 12, arrow.y, 8, 16 ), /* Right */
FloatRect( arrow.x, 4, 16, 8 ), /* Top */
FloatRect( arrow.x, geo.h - 12, 16, 8 ) /* Bottom */
};
size_t i = 0;
@ -538,7 +538,7 @@ struct WindowVXPrivate
if (pause)
{
const FloatRect pausePos(arrowTBX, geo.h - 16, 16, 16);
const FloatRect pausePos(arrow.x, geo.h - 16, 16, 16);
pauseVert = &vert[i*4];
i += Quad::setTexPosRect(&vert[i*4], pauseSrc[0], pausePos);
@ -730,8 +730,7 @@ struct WindowVXPrivate
bool windowskinValid = !nullOrDisposed(windowskin);
bool contentsValid = !nullOrDisposed(contents);
Vec2i trans(geo.x + sceneOffset.x,
geo.y + sceneOffset.y);
Vec2i trans = geo.pos() + sceneOffset;
SimpleAlphaShader &shader = shState->shaders().simpleAlpha;
shader.bind();
@ -764,8 +763,7 @@ struct WindowVXPrivate
{
/* Translate cliprect from local into screen space */
IntRect clip = clipRect;
clip.x += trans.x;
clip.y += trans.y;
clip.setPos(clip.pos() + trans);
glState.scissorBox.push();
glState.scissorTest.pushSet(true);
@ -773,11 +771,10 @@ struct WindowVXPrivate
if (rgssVer >= 3)
glState.scissorBox.setIntersect(clip);
else
glState.scissorBox.setIntersect(IntRect(trans.x, trans.y, geo.w, geo.h));
glState.scissorBox.setIntersect(IntRect(trans, geo.size()));
IntRect pad = padRect;
pad.x += trans.x;
pad.y += trans.y;
pad.setPos(pad.pos() + trans);
if (drawCursor)
{
@ -786,10 +783,7 @@ struct WindowVXPrivate
contTrans.y += cursorRect->y;
if (rgssVer >= 3)
{
contTrans.x -= contentsOff.x;
contTrans.y -= contentsOff.y;
}
contTrans -= contentsOff;
shader.setTranslation(contTrans);
@ -804,8 +798,7 @@ struct WindowVXPrivate
glState.scissorBox.setIntersect(clip);
Vec2i contTrans = pad.pos();
contTrans.x -= contentsOff.x;
contTrans.y -= contentsOff.y;
contTrans -= contentsOff;
shader.setTranslation(contTrans);
TEX::setSmooth(false); // XXX
@ -921,6 +914,9 @@ void WindowVX::setContents(Bitmap *value)
p->contents = value;
if (nullOrDisposed(value))
return;
FloatRect rect = p->contents->rect();
p->contentsQuad.setTexPosRect(rect, rect);
p->ctrlVertDirty = true;
@ -1102,8 +1098,7 @@ void WindowVX::draw()
void WindowVX::onGeometryChange(const Scene::Geometry &geo)
{
p->sceneOffset.x = geo.rect.x - geo.xOrigin;
p->sceneOffset.y = geo.rect.y - geo.yOrigin;
p->sceneOffset = geo.offset();
}
void WindowVX::releaseResources()