Merge branch 'dev'

This commit is contained in:
Jonas Kulla 2014-04-17 08:19:24 +02:00
commit 58d86039d5
46 changed files with 1121 additions and 632 deletions

View file

@ -23,6 +23,7 @@
#define ALUTIL_H
#include <al.h>
#include <alc.h>
#include <alext.h>
namespace AL

View file

@ -366,6 +366,7 @@ struct SDLSoundSource : ALDataSource
~SDLSoundSource()
{
/* This also closes 'srcOps' */
Sound_FreeSample(sample);
}

View file

@ -55,10 +55,6 @@ struct BitmapPrivate
{
TEXFBO gl;
/* 'setPixel()' calls are cached and executed
* in batches on 'flush()' */
PointArray pointArray;
Font *font;
/* "Mega surfaces" are a hack to allow Tilesets to be used
@ -154,32 +150,9 @@ struct BitmapPrivate
glState.blendMode.pop();
}
void flushPoints()
{
if (pointArray.count() == 0)
return;
SimpleColorShader &shader = shState->shaders().simpleColor;
shader.bind();
shader.setTranslation(Vec2i());
bindFBO();
pushSetViewport(shader);
glState.blendMode.pushSet(BlendNone);
pointArray.commit();
pointArray.draw();
pointArray.reset();
glState.blendMode.pop();
popViewport();
}
void fillRect(const IntRect &rect,
const Vec4 &color)
{
flushPoints();
bindFBO();
glState.scissorTest.pushSet(true);
@ -271,7 +244,6 @@ Bitmap::Bitmap(const Bitmap &other)
p->gl = shState->texPool().request(other.width(), other.height());
other.flush();
blt(0, 0, other, rect());
}
@ -368,8 +340,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
if (opacity == 255 && !p->touchesTaintedArea(destRect))
{
/* Fast blit */
flush();
FBO::bind(source.p->gl.fbo, FBO::Read);
FBO::bind(p->gl.fbo, FBO::Draw);
@ -379,8 +349,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
else
{
/* Fragment pipeline */
flush();
float normOpacity = (float) opacity / 255.0f;
TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h);
@ -461,8 +429,6 @@ void Bitmap::gradientFillRect(const IntRect &rect,
GUARD_MEGA;
flush();
SimpleColorShader &shader = shState->shaders().simpleColor;
shader.bind();
shader.setTranslation(Vec2i());
@ -520,8 +486,6 @@ void Bitmap::blur()
GUARD_MEGA;
flush();
Quad &quad = shState->gpQuad();
FloatRect rect(0, 0, width(), height());
quad.setTexPosRect(rect, rect);
@ -567,8 +531,6 @@ void Bitmap::radialBlur(int angle, int divisions)
GUARD_MEGA;
flush();
angle = clamp<int>(angle, 0, 359);
divisions = clamp<int>(divisions, 2, 100);
@ -666,9 +628,6 @@ void Bitmap::clear()
GUARD_MEGA;
/* Any queued points won't be visible after this anyway */
p->pointArray.reset();
p->bindFBO();
glState.clearColor.pushSet(Vec4());
@ -682,7 +641,7 @@ void Bitmap::clear()
modified();
}
Vec4 Bitmap::getPixel(int x, int y) const
Color Bitmap::getPixel(int x, int y) const
{
GUARD_DISPOSED;
@ -691,24 +650,34 @@ Vec4 Bitmap::getPixel(int x, int y) const
if (x < 0 || y < 0 || x >= width() || y >= height())
return Vec4();
flush();
FBO::bind(p->gl.fbo, FBO::Read);
glState.viewport.pushSet(IntRect(0, 0, width(), height()));
Vec4 pixel = FBO::getPixel(x, y);
uint8_t pixel[4];
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
glState.viewport.pop();
return pixel;
return Color(pixel[0], pixel[1], pixel[2], pixel[3]);
}
void Bitmap::setPixel(int x, int y, const Vec4 &color)
void Bitmap::setPixel(int x, int y, const Color &color)
{
GUARD_DISPOSED;
GUARD_MEGA;
p->pointArray.append(Vec2(x+.5, y+.5), color);
uint8_t pixel[] =
{
(uint8_t) clamp<double>(color.red, 0, 255),
(uint8_t) clamp<double>(color.green, 0, 255),
(uint8_t) clamp<double>(color.blue, 0, 255),
(uint8_t) clamp<double>(color.alpha, 0, 255)
};
TEX::bind(p->gl.tex);
TEX::uploadSubImage(x, y, 1, 1, &pixel, GL_RGBA);
p->addTaintedArea(IntRect(x, y, 1, 1));
@ -724,8 +693,6 @@ void Bitmap::hueChange(int hue)
if ((hue % 360) == 0)
return;
flush();
TEXFBO newTex = shState->texPool().request(width(), height());
FloatRect texRect(rect());
@ -748,8 +715,6 @@ void Bitmap::hueChange(int hue)
p->blitQuad(quad);
shader.unbind();
p->popViewport();
TEX::unbind();
@ -779,8 +744,6 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
if (str[0] == ' ' && str[1] == '\0')
return;
flush();
TTF_Font *font = p->font->getSdlFont();
Color *fontColor = p->font->getColor();
@ -1011,17 +974,6 @@ IntRect Bitmap::textSize(const char *str)
DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font)
void Bitmap::flush() const
{
if (isDisposed())
return;
if (p->megaSurface)
return;
p->flushPoints();
}
TEXFBO &Bitmap::getGLTypes()
{
return p->gl;

View file

@ -81,8 +81,8 @@ public:
void clear();
Vec4 getPixel(int x, int y) const;
void setPixel(int x, int y, const Vec4 &color);
Color getPixel(int x, int y) const;
void setPixel(int x, int y, const Color &color);
void hueChange(int hue);
@ -105,9 +105,6 @@ public:
DECL_ATTR(Font, Font*)
/* <internal> */
/* Warning: Flushing might change the current
* FBO binding (so don't call it during 'draw()' routines */
void flush() const;
TEXFBO &getGLTypes();
SDL_Surface *megaSurface() const;
void ensureNonMega() const;

View file

@ -35,7 +35,6 @@ namespace po = boost::program_options;
Config::Config()
: debugMode(false),
screenshots(false),
winResizable(false),
fullscreen(false),
fixedAspectRatio(true),
@ -57,7 +56,6 @@ void Config::read(int argc, char *argv[])
{
#define PO_DESC_ALL \
PO_DESC(debugMode, bool) \
PO_DESC(screenshots, bool) \
PO_DESC(winResizable, bool) \
PO_DESC(fullscreen, bool) \
PO_DESC(fixedAspectRatio, bool) \
@ -85,6 +83,7 @@ void Config::read(int argc, char *argv[])
podesc.add_options()
PO_DESC_ALL
("RTP", po::value<StringVec>()->composing())
("fontSub", po::value<StringVec>()->composing())
;
po::variables_map vm;
@ -117,6 +116,8 @@ void Config::read(int argc, char *argv[])
GUARD_ALL( rtps = vm["RTP"].as<StringVec>(); );
GUARD_ALL( fontSubs = vm["fontSub"].as<StringVec>(); );
#undef PO_DESC
#undef PO_DESC_ALL
}

View file

@ -28,7 +28,6 @@
struct Config
{
bool debugMode;
bool screenshots;
bool winResizable;
bool fullscreen;
@ -56,6 +55,8 @@ struct Config
std::string customScript;
std::vector<std::string> rtps;
std::vector<std::string> fontSubs;
/* Game INI contents */
struct {
std::string scripts;

View file

@ -46,7 +46,7 @@ public:
~Debug()
{
std::clog << buf.str() << "\n";
std::clog << buf.str() << std::endl;
}
private:

View file

@ -209,9 +209,6 @@ void EventThread::process(RGSSThreadData &rtData)
break;
}
if (event.key.keysym.scancode == SDL_SCANCODE_F3 && rtData.config.screenshots)
rtData.rqScreenshot = true;
keyStates[event.key.keysym.scancode] = true;
break;

View file

@ -178,8 +178,6 @@ struct RGSSThreadData
std::string rgssErrorMsg;
volatile bool rqScreenshot;
RGSSThreadData(EventThread *ethread,
const char *argv0,
SDL_Window *window,
@ -190,8 +188,7 @@ struct RGSSThreadData
argv0(argv0),
window(window),
sizeResoRatio(1, 1),
config(newconf),
rqScreenshot(false)
config(newconf)
{}
};

View file

@ -21,6 +21,7 @@
#include "filesystem.h"
#include "font.h"
#include "util.h"
#include "exception.h"
#include "boost-hash.h"
@ -297,8 +298,12 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
/* Check header */
uint32_t header1, header2;
readUint32(io, header1);
readUint32(io, header2);
if (!readUint32(io, header1))
return 0;
if (!readUint32(io, header2))
return 0;
if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2)
return 0;
@ -476,41 +481,133 @@ RGSS_noop2(void*, const char*)
static const PHYSFS_Archiver RGSS_Archiver =
{
0,
{
"RGSSAD",
"RGSS encrypted archive format",
"Jonas Kulla <Nyocurio@gmail.com>",
"http://k-du.de/rgss/rgss.html",
0 /* symlinks not supported */
},
RGSS_openArchive,
RGSS_enumerateFiles,
RGSS_openRead,
RGSS_noop1, /* openWrite */
RGSS_noop1, /* openAppend */
RGSS_noop2, /* remove */
RGSS_noop2, /* mkdir */
RGSS_stat,
RGSS_closeArchive
{
"RGSSAD",
"RGSS encrypted archive format",
"Jonas Kulla <Nyocurio@gmail.com>",
"http://k-du.de/rgss/rgss.html",
0 /* symlinks not supported */
},
RGSS_openArchive,
RGSS_enumerateFiles,
RGSS_openRead,
RGSS_noop1, /* openWrite */
RGSS_noop1, /* openAppend */
RGSS_noop2, /* remove */
RGSS_noop2, /* mkdir */
RGSS_stat,
RGSS_closeArchive
};
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
{
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
}
static Sint64 SDL_RWopsSize(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
return PHYSFS_fileLength(f);
}
static Sint64 SDL_RWopsSeek(SDL_RWops *ops, int64_t offset, int whence)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int64_t base;
switch (whence)
{
default:
case RW_SEEK_SET :
base = 0;
break;
case RW_SEEK_CUR :
base = PHYSFS_tell(f);
break;
case RW_SEEK_END :
base = PHYSFS_fileLength(f);
break;
}
int result = PHYSFS_seek(f, base + offset);
return (result != 0) ? PHYSFS_tell(f) : -1;
}
static size_t SDL_RWopsRead(SDL_RWops *ops, void *buffer, size_t size, size_t maxnum)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_readBytes(f, buffer, size*maxnum);
return (result != -1) ? (result / size) : 0;
}
static size_t SDL_RWopsWrite(SDL_RWops *ops, const void *buffer, size_t size, size_t num)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_writeBytes(f, buffer, size*num);
return (result != -1) ? (result / size) : 0;
}
static int SDL_RWopsClose(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int result = PHYSFS_close(f);
f = 0;
return (result != 0) ? 0 : -1;
}
static int SDL_RWopsCloseFree(SDL_RWops *ops)
{
int result = SDL_RWopsClose(ops);
SDL_FreeRW(ops);
return result;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
struct FileSystemPrivate
{
/* All keys are lower case */
/* Maps: lower case filename, To: actual (mixed case) filename.
* 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];
// FIXME Need to find a better way to do this..
char pathBuffer[512];
bool havePathCache;
/* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the
* extension, or null is returned */
const char *findExt(const char *filename)
{
int len;
size_t len;
for (len = strlen(filename); len > 0; --len)
{
@ -524,110 +621,147 @@ struct FileSystemPrivate
return 0;
}
const char *completeFileName(const char *filename,
FileSystem::FileType type,
const char **foundExt)
/* Complete filename via regular physfs lookup */
bool completeFilenameReg(const char *filename,
FileSystem::FileType type,
char *outBuffer,
size_t outN,
const char **foundExt)
{
if (!havePathCache)
/* Try supplementing extensions to find an existing path */
const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i)
{
if (PHYSFS_exists(filename))
const char *ext = extList[i].c_str();
snprintf(outBuffer, outN, "%s.%s", filename, ext);
if (PHYSFS_exists(outBuffer))
{
if (foundExt)
*foundExt = findExt(filename);
*foundExt = ext;
return filename;
return true;
}
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(pathBuffer, sizeof(pathBuffer), "%s.%s", filename, ext);
if (PHYSFS_exists(pathBuffer))
{
if (foundExt)
*foundExt = ext;
return pathBuffer;
}
}
// Is this even necessary?
if (foundExt)
*foundExt = 0;
return 0;
}
char buff[512];
size_t i;
for (i = 0; i < sizeof(buff) && filename[i]; ++i)
buff[i] = tolower(filename[i]);
buff[i] = '\0';
std::string key(buff);
/* If the path was already complete,
* we are done at this point */
if (pathCache.contains(key))
/* Doing the check without supplemented extension
* fits the usage pattern of RMXP games */
if (PHYSFS_exists(filename))
{
/* The extension might already be included here,
* so try to find it */
strncpy(outBuffer, filename, outN);
if (foundExt)
*foundExt = findExt(filename);
return pathCache[key].c_str();
return true;
}
char buff2[512];
return false;
}
/* Try supplementing extensions
* to find an existing path */
if (type != FileSystem::Undefined)
/* Complete filename via path cache */
bool completeFilenamePC(const char *filename,
FileSystem::FileType type,
char *outBuffer,
size_t outN,
const char **foundExt)
{
size_t i;
char lowCase[512];
for (i = 0; i < sizeof(lowCase)-1 && filename[i]; ++i)
lowCase[i] = tolower(filename[i]);
lowCase[i] = '\0';
std::string key;
const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i)
{
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))
{
const char *ext = extList[i].c_str();
strncpy(outBuffer, pathCache[key].c_str(), outN);
snprintf(buff2, sizeof(buff2), "%s.%s", buff, ext);
key = buff2;
if (foundExt)
*foundExt = ext;
if (pathCache.contains(key))
{
if (foundExt)
*foundExt = ext;
return pathCache[key].c_str();
}
return true;
}
}
if (foundExt)
*foundExt = 0;
key = lowCase;
return 0;
if (pathCache.contains(key))
{
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt)
*foundExt = findExt(filename);
return true;
}
return false;
}
PHYSFS_File *openReadInt(const char *filename,
FileSystem::FileType type,
const char **foundExt)
/* 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,
char *outBuffer,
size_t outN,
const char **foundExt)
{
const char *foundName = completeFileName(filename, type, foundExt);
if (havePathCache)
return completeFilenamePC(filename, type, outBuffer, outN, foundExt);
else
return completeFilenameReg(filename, type, outBuffer, outN, foundExt);
}
if (!foundName)
PHYSFS_File *openReadHandle(const char *filename,
FileSystem::FileType type,
const char **foundExt)
{
char found[512];
if (!completeFileName(filename, type, found, sizeof(found), foundExt))
throw Exception(Exception::NoFileError, "%s", filename);
PHYSFS_File *handle = PHYSFS_openRead(foundName);
PHYSFS_File *handle = PHYSFS_openRead(found);
if (!handle)
throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
return handle;
}
void initReadOps(PHYSFS_File *handle,
SDL_RWops &ops,
bool freeOnClose)
{
ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite;
if (freeOnClose)
ops.close = SDL_RWopsCloseFree;
else
ops.close = SDL_RWopsClose;
ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle;
}
};
FileSystem::FileSystem(const char *argv0,
@ -724,123 +858,83 @@ void FileSystem::createPathCache()
p->havePathCache = true;
}
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
static void strToLower(std::string &str)
{
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
static Sint64 SDL_RWopsSize(SDL_RWops *ops)
struct FontSetsCBData
{
PHYSFS_File *f = sdlPHYS(ops);
FileSystemPrivate *p;
SharedFontState *sfs;
};
if (!f)
return -1;
static void fontSetEnumCB(void *data, const char *,
const char *fname)
{
FontSetsCBData *d = static_cast<FontSetsCBData*>(data);
FileSystemPrivate *p = d->p;
return PHYSFS_fileLength(f);
/* Only consider filenames with font extensions */
const char *ext = p->findExt(fname);
if (!ext)
return;
std::string lower(ext);
strToLower(lower);
if (!contains(p->extensions[FileSystem::Font], lower))
return;
std::string filename("Fonts/");
filename += fname;
PHYSFS_File *handle = PHYSFS_openRead(filename.c_str());
if (!handle)
return;
SDL_RWops ops;
p->initReadOps(handle, ops, false);
d->sfs->initFontSetCB(ops, filename);
SDL_RWclose(&ops);
}
static Sint64 SDL_RWopsSeek(SDL_RWops *ops, int64_t offset, int whence)
void FileSystem::initFontSets(SharedFontState &sfs)
{
PHYSFS_File *f = sdlPHYS(ops);
FontSetsCBData d = { p, &sfs };
if (!f)
return -1;
int64_t base;
switch (whence)
{
default:
case RW_SEEK_SET :
base = 0;
break;
case RW_SEEK_CUR :
base = PHYSFS_tell(f);
break;
case RW_SEEK_END :
base = PHYSFS_fileLength(f);
break;
}
int result = PHYSFS_seek(f, base + offset);
return (result != 0) ? PHYSFS_tell(f) : -1;
PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d);
}
static size_t SDL_RWopsRead(SDL_RWops *ops, void *buffer, size_t size, size_t maxnum)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_readBytes(f, buffer, size*maxnum);
return (result != -1) ? (result / size) : 0;
}
static size_t SDL_RWopsWrite(SDL_RWops *ops, const void *buffer, size_t size, size_t num)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_writeBytes(f, buffer, size*num);
return (result != -1) ? (result / size) : 0;
}
static int SDL_RWopsClose(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int result = PHYSFS_close(f);
f = 0;
return (result != 0) ? 0 : -1;
}
static int SDL_RWopsCloseFree(SDL_RWops *ops)
{
int result = SDL_RWopsClose(ops);
SDL_FreeRW(ops);
return result;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
void FileSystem::openRead(SDL_RWops &ops,
const char *filename,
FileType type,
bool freeOnClose,
const char **foundExt)
{
PHYSFS_File *handle = p->openReadInt(filename, type, foundExt);
PHYSFS_File *handle = p->openReadHandle(filename, type, foundExt);
ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite;
p->initReadOps(handle, ops, freeOnClose);
}
if (freeOnClose)
ops.close = SDL_RWopsCloseFree;
else
ops.close = SDL_RWopsClose;
void FileSystem::openReadRaw(SDL_RWops &ops,
const char *filename,
bool freeOnClose)
{
PHYSFS_File *handle = PHYSFS_openRead(filename);
assert(handle);
ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle;
p->initReadOps(handle, ops, freeOnClose);
}
bool FileSystem::exists(const char *filename, FileType type)
{
const char *foundName = p->completeFileName(filename, type, 0);
char found[512];
return (foundName != 0);
return p->completeFileName(filename, type, found, sizeof(found), 0);
}

View file

@ -25,6 +25,7 @@
#include <SDL_rwops.h>
struct FileSystemPrivate;
class SharedFontState;
class FileSystem
{
@ -35,9 +36,13 @@ public:
void addPath(const char *path);
/* Call this after the last 'addPath()' */
/* Call these after the last 'addPath()' */
void createPathCache();
/* Scans "Fonts/" and creates inventory of
* available font assets */
void initFontSets(SharedFontState &sfs);
/* For extension supplementing */
enum FileType
{
@ -53,6 +58,11 @@ public:
bool freeOnClose = false,
const char **foundExt = 0);
/* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops,
const char *filename,
bool freeOnClose = false);
bool exists(const char *filename,
FileType type = Undefined);

View file

@ -55,7 +55,7 @@ public:
flashAlpha = flashColor.w;
}
void update()
virtual void update()
{
if (!flashing)
return;

View file

@ -26,6 +26,7 @@
#include "exception.h"
#include "boost-hash.h"
#include "util.h"
#include "config.h"
#include <string>
#include <utility>
@ -45,88 +46,151 @@
typedef std::pair<std::string, int> FontKey;
static void strToLower(std::string &str)
{
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
struct FontPoolPrivate
{
BoostHash<FontKey, TTF_Font*> hash;
};
FontPool::FontPool()
{
p = new FontPoolPrivate;
}
FontPool::~FontPool()
{
BoostHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->hash.cbegin(); iter != p->hash.cend(); ++iter)
TTF_CloseFont(iter->second);
delete p;
}
static SDL_RWops *openBundledFont()
{
return SDL_RWFromConstMem(BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT));
}
_TTF_Font *FontPool::request(const char *filename,
int size)
struct FontSet
{
// FIXME Find out how font path resolution is done in VX/Ace
std::string nameKey(filename);
strToLower(nameKey);
strReplace(nameKey, ' ', '_');
/* 'Regular' style */
std::string regular;
bool useBundled = false;
std::string path = std::string("Fonts/") + nameKey;
if (!shState->fileSystem().exists(path.c_str(), FileSystem::Font))
/* Any other styles (used in case no 'Regular' exists) */
std::string other;
};
struct SharedFontStatePrivate
{
/* Maps: font family name, To: substituted family name,
* as specified via configuration file / arguments */
BoostHash<std::string, std::string> subs;
/* Maps: font family name, To: set of physical
* font filenames located in "Fonts/" */
BoostHash<std::string, FontSet> sets;
/* Pool of already opened fonts; once opened, they are reused
* and never closed until the termination of the program */
BoostHash<FontKey, TTF_Font*> pool;
};
SharedFontState::SharedFontState(const Config &conf)
{
p = new SharedFontStatePrivate;
/* Parse font substitutions */
for (size_t i = 0; i < conf.fontSubs.size(); ++i)
{
/* Use the same name key for the bundled font
* even when it resulted from multiple different
* font name requests. The space at the front is
* to prevent collisions (spaces are normally
* replaced with '_' */
useBundled = true;
nameKey = " bundled";
const std::string &raw = conf.fontSubs[i];
size_t sepPos = raw.find_first_of('>');
if (sepPos == std::string::npos)
continue;
std::string from = raw.substr(0, sepPos);
std::string to = raw.substr(sepPos+1);
p->subs.insert(from, to);
}
}
SharedFontState::~SharedFontState()
{
BoostHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->pool.cbegin(); iter != p->pool.cend(); ++iter)
TTF_CloseFont(iter->second);
delete p;
}
void SharedFontState::initFontSetCB(SDL_RWops &ops,
const std::string &filename)
{
TTF_Font *font = TTF_OpenFontRW(&ops, 0, 0);
if (!font)
return;
std::string family = TTF_FontFaceFamilyName(font);
std::string style = TTF_FontFaceStyleName(font);
TTF_CloseFont(font);
FontSet &set = p->sets[family];
if (style == "Regular")
set.regular = filename;
else
set.other = filename;
}
_TTF_Font *SharedFontState::getFont(std::string family,
int size)
{
/* Check for substitutions */
if (p->subs.contains(family))
family = p->subs[family];
/* Find out if the font asset exists */
const FontSet &req = p->sets[family];
if (req.regular.empty() && req.other.empty())
{
/* Doesn't exist; use built-in font */
family = "";
}
FontKey key(nameKey, size);
FontKey key(family, size);
TTF_Font *font = p->hash.value(key, 0);
TTF_Font *font = p->pool.value(key);
if (font)
return font;
/* Not in hash, open */
/* Not in pool; open new handle */
SDL_RWops *ops;
if (useBundled)
if (family.empty())
{
/* Built-in font */
ops = openBundledFont();
}
else
{
/* Use 'other' path as alternative in case
* we have no 'regular' styled font asset */
const char *path = !req.regular.empty()
? req.regular.c_str() : req.other.c_str();
ops = SDL_AllocRW();
shState->fileSystem().openRead(*ops, path.c_str(), FileSystem::Font, true);
shState->fileSystem().openReadRaw(*ops, path, true);
}
// FIXME 0.9 is guesswork at this point
font = TTF_OpenFontRW(ops, 1, (float) size * .90);
// float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
font = TTF_OpenFontRW(ops, 1, size* .90);
if (!font)
throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError());
throw Exception(Exception::SDLError, "%s", SDL_GetError());
p->hash.insert(key, font);
p->pool.insert(key, font);
return font;
}
bool SharedFontState::fontPresent(std::string family)
{
/* Check for substitutions */
if (p->subs.contains(family))
family = p->subs[family];
const FontSet &set = p->sets[family];
return !(set.regular.empty() && set.other.empty());
}
struct FontPrivate
{
@ -173,7 +237,7 @@ struct FontPrivate
{}
};
std::string FontPrivate::defaultName = "MS PGothic";
std::string FontPrivate::defaultName = "Arial";
int FontPrivate::defaultSize = 22;
bool FontPrivate::defaultBold = false;
bool FontPrivate::defaultItalic = false;
@ -183,9 +247,7 @@ Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
bool Font::doesExist(const char *name)
{
std::string path = std::string("Fonts/") + std::string(name);
return shState->fileSystem().exists(path.c_str(), FileSystem::Font);
return shState->fontState().fontPresent(name);
}
Font::Font(const char *name,
@ -223,6 +285,10 @@ void Font::setSize(int value)
if (p->size == value)
return;
/* Catch illegal values (according to RMXP) */
if (value < 6 || value > 96)
throw Exception(Exception::ArgumentError, "%s", "bad value for size");
p->size = value;
p->sdlFont = 0;
}
@ -253,8 +319,8 @@ void Font::setDefaultName(const char *value)
_TTF_Font *Font::getSdlFont()
{
if (!p->sdlFont)
p->sdlFont = shState->fontPool().request(p->name.c_str(),
p->size);
p->sdlFont = shState->fontState().getFont(p->name.c_str(),
p->size);
int style = TTF_STYLE_NORMAL;

View file

@ -25,22 +25,50 @@
#include "etc.h"
#include "util.h"
struct SDL_RWops;
struct _TTF_Font;
struct FontPoolPrivate;
struct Config;
class FontPool
struct SharedFontStatePrivate;
class SharedFontState
{
public:
FontPool();
~FontPool();
SharedFontState(const Config &conf);
~SharedFontState();
_TTF_Font *request(const char *filename,
/* Called from FileSystem during font cache initialization
* (when "Fonts/" is scanned for available assets).
* 'ops' is an opened handle to a possible font file,
* 'filename' is the corresponding path */
void initFontSetCB(SDL_RWops &ops,
const std::string &filename);
_TTF_Font *getFont(std::string family,
int size);
bool fontPresent(std::string family);
private:
FontPoolPrivate *p;
SharedFontStatePrivate *p;
};
/* Concerning Font::name/defaultName :
* In RGSS, this is not actually a string; any type of
* object is accepted, however anything but strings and
* arrays is ignored (and text drawing turns blank).
* Single strings are interpreted as font family names,
* and directly passed to the underlying C++ object;
* arrays however are searched for the first string
* object corresponding to a valid font family name,
* and rendering is done with that. In mkxp, we pass
* this first valid font family as the 'name' attribute
* back to the C++ object on assignment and object
* creation (in case Font.default_name is also an array).
* Invalid parameters (things other than strings or
* arrays not containing any valid family name) are
* passed back as "". */
struct FontPrivate;
class Font
@ -57,9 +85,9 @@ public:
const char *getName() const;
void setName(const char *value);
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color* )
DECL_ATTR_STATIC( DefaultName, const char* )

View file

@ -216,15 +216,6 @@ namespace FBO
blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode);
}
inline Vec4 getPixel(int x, int y)
{
Vec4 pixel;
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
return pixel;
}
inline void clear()
{
glClear(GL_COLOR_BUFFER_BIT);

View file

@ -20,6 +20,7 @@
*/
#include "glstate.h"
#include "shader.h"
#include "etc.h"
#include <glew.h>
@ -95,6 +96,11 @@ void GLViewport::apply(const IntRect &value)
glViewport(value.x, value.y, value.w, value.h);
}
void GLProgram::apply(const unsigned int &value)
{
glUseProgram(value);
}
GLState::Caps::Caps()
{
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
@ -110,4 +116,5 @@ GLState::GLState()
scissorTest.init(false);
scissorBox.init(IntRect(0, 0, 640, 480));
texture2D.init(true);
program.init(0);
}

View file

@ -99,6 +99,11 @@ class GLViewport : public GLProperty<IntRect>
void apply(const IntRect &value);
};
class GLProgram : public GLProperty<unsigned int> /* GLuint */
{
void apply(const unsigned int &value);
};
class GLState
{
@ -109,6 +114,7 @@ public:
GLTexture2D texture2D;
GLBlendMode blendMode;
GLViewport viewport;
GLProgram program;
struct Caps
{

View file

@ -191,7 +191,6 @@ public:
screenQuad.draw();
glState.blendMode.pop();
shader.unbind();
}
#ifdef RGSS2
@ -508,44 +507,6 @@ struct GraphicsPrivate
swapGLBuffer();
}
void writeScreenshot(const char *filename)
{
int bpp;
uint32_t rm, gm, bm, am;
SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &rm, &gm, &bm, &am);
/* Discard alpha channel because it might have bogus values */
SDL_Surface *screenshot =
SDL_CreateRGBSurface(0, scRes.x, scRes.y, bpp, rm, gm, bm, 0);
screen.getPP().bindLastBuffer();
glReadPixels(0, 0, scRes.x, scRes.y, GL_RGBA, GL_UNSIGNED_BYTE, screenshot->pixels);
IMG_SavePNG(screenshot, filename);
SDL_FreeSurface(screenshot);
}
void checkScreenshotRq()
{
if (!threadData->rqScreenshot)
return;
threadData->rqScreenshot = false;
struct timeval tv;
gettimeofday(&tv, 0);
struct tm tm = *localtime(&tv.tv_sec);
char filename[32];
snprintf(filename, sizeof(filename), "%d%02d%02d-%02d%02d%02d.png",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
writeScreenshot(filename);
}
};
Graphics::Graphics(RGSSThreadData *data)
@ -569,8 +530,6 @@ void Graphics::update()
// p->cpuTimer->endTiming();
// p->gpuTimer->startTiming();
p->checkScreenshotRq();
if (p->frozen)
return;

View file

@ -93,9 +93,6 @@ struct PlanePrivate
updateQuadSource();
quadSourceDirty = false;
}
if (bitmap)
bitmap->flush();
}
};

View file

@ -34,17 +34,41 @@
typedef uint32_t index_t;
#define _GL_INDEX_TYPE GL_UNSIGNED_INT
struct ColorQuadArray
/* A small hack to get mutable QuadArray constructors */
inline void initBufferBindings(Vertex *)
{
std::vector<Vertex> vertices;
glEnableVertexAttribArray(Shader::Color);
glEnableVertexAttribArray(Shader::Position);
glEnableVertexAttribArray(Shader::TexCoord);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::texPosOffset());
}
inline void initBufferBindings(SVertex *)
{
glEnableVertexAttribArray(Shader::Position);
glEnableVertexAttribArray(Shader::TexCoord);
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), SVertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), SVertex::texPosOffset());
}
template<class VertexType>
struct QuadArray
{
std::vector<VertexType> vertices;
VBO::ID vbo;
VAO::ID vao;
int quadCount;
GLsizeiptr vboSize;
ColorQuadArray()
: quadCount(0)
QuadArray()
: quadCount(0),
vboSize(-1)
{
vbo = VBO::gen();
vao = VAO::gen();
@ -53,20 +77,16 @@ struct ColorQuadArray
VBO::bind(vbo);
shState->bindQuadIBO();
glEnableVertexAttribArray(Shader::Color);
glEnableVertexAttribArray(Shader::Position);
glEnableVertexAttribArray(Shader::TexCoord);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::texPosOffset());
/* Call correct implementation here via overloading */
VertexType *dummy = 0;
initBufferBindings(dummy);
VAO::unbind();
IBO::unbind();
VBO::unbind();
}
~ColorQuadArray()
~QuadArray()
{
VBO::del(vbo);
VAO::del(vao);
@ -78,15 +98,36 @@ struct ColorQuadArray
quadCount = size;
}
void clear()
{
vertices.clear();
quadCount = 0;
}
/* This needs to be called after the final 'append()' call
* and previous to the first 'draw()' call. */
void commit()
{
VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), &vertices[0], GL_DYNAMIC_DRAW);
VBO::unbind();
shState->ensureQuadIBO(quadCount);
GLsizeiptr size = vertices.size() * sizeof(VertexType);
if (size > vboSize)
{
/* New data exceeds already allocated size.
* Reallocate VBO. */
VBO::uploadData(size, &vertices[0], GL_DYNAMIC_DRAW);
vboSize = size;
shState->ensureQuadIBO(quadCount);
}
else
{
/* New data fits in allocated size */
VBO::uploadSubData(0, size, &vertices[0]);
}
VBO::unbind();
}
void draw(size_t offset, size_t count)
@ -110,67 +151,7 @@ struct ColorQuadArray
}
};
struct PointArray
{
std::vector<Vertex> vertices;
VBO::ID vbo;
VAO::ID vao;
PointArray()
{
vbo = VBO::gen();
vao = VAO::gen();
VAO::bind(vao);
VBO::bind(vbo);
glEnableVertexAttribArray(Shader::Color);
glEnableVertexAttribArray(Shader::Position);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
VAO::unbind();
VBO::unbind();
}
~PointArray()
{
VBO::del(vbo);
VAO::del(vao);
}
void append(const Vec2 &pos, const Vec4 &color)
{
Vertex vert;
vert.pos = pos;
vert.color = color;
vertices.push_back(vert);
}
void commit()
{
VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), &vertices[0]);
VBO::unbind();
}
void reset()
{
vertices.clear();
}
void draw()
{
VAO::bind(vao);
glDrawArrays(GL_POINTS, 0, count());
VAO::unbind();
}
int count()
{
return vertices.size();
}
};
typedef QuadArray<Vertex> ColorQuadArray;
typedef QuadArray<SVertex> SimpleQuadArray;
#endif // QUADARRAY_H

View file

@ -99,13 +99,13 @@ Shader::~Shader()
void Shader::bind()
{
glUseProgram(program);
glState.program.set(program);
}
void Shader::unbind()
{
glActiveTexture(GL_TEXTURE0);
glUseProgram(0);
glState.program.set(0);
}
void Shader::init(const unsigned char *vert, int vertSize,

View file

@ -67,8 +67,8 @@ struct SharedStatePrivate
ShaderSet shaders;
TexPool texPool;
FontPool fontPool;
SharedFontState fontState;
Font *defaultFont;
TEX::ID globalTex;
@ -90,6 +90,7 @@ struct SharedStatePrivate
rtData(*threadData),
config(threadData->config),
graphics(threadData),
fontState(threadData->config),
stampCounter(0)
{
if (!config.gameFolder.empty())
@ -121,6 +122,8 @@ struct SharedStatePrivate
if (config.pathCache)
fileSystem.createPathCache();
fileSystem.initFontSets(fontState);
globalTexW = 128;
globalTexH = 64;
@ -206,8 +209,8 @@ GSATT(Audio&, audio)
GSATT(GLState&, _glState)
GSATT(ShaderSet&, shaders)
GSATT(TexPool&, texPool)
GSATT(FontPool&, fontPool)
GSATT(Quad&, gpQuad)
GSATT(SharedFontState&, fontState)
void SharedState::setBindingData(void *data)
{

View file

@ -43,8 +43,8 @@ class Input;
class Audio;
class GLState;
class TexPool;
class FontPool;
class Font;
class SharedFontState;
struct GlobalIBO;
struct Config;
struct Vec2i;
@ -74,8 +74,8 @@ struct SharedState
ShaderSet &shaders();
TexPool &texPool();
FontPool &fontPool();
SharedFontState &fontState();
Font &defaultFont();
sigc::signal<void> prepareDraw;

View file

@ -32,6 +32,9 @@
#include "transform.h"
#include "shader.h"
#include "glstate.h"
#include "quadarray.h"
#include <math.h>
#include <SDL_rect.h>
@ -63,6 +66,22 @@ struct SpritePrivate
Color *color;
Tone *tone;
#ifdef RGSS2
struct
{
int amp;
int length;
int speed;
float phase;
/* Wave effect is active (amp != 0) */
bool active;
/* qArray needs updating */
bool dirty;
SimpleQuadArray qArray;
} wave;
#endif
EtcTemps tmp;
sigc::connection prepareCon;
@ -87,6 +106,13 @@ struct SpritePrivate
prepareCon = shState->prepareDraw.connect
(sigc::mem_fun(this, &SpritePrivate::prepare));
#ifdef RGSS2
wave.amp = 0;
wave.length = 180;
wave.speed = 360;
wave.phase = 0.0;
#endif
}
~SpritePrivate()
@ -117,6 +143,10 @@ struct SpritePrivate
quad.setPosRect(IntRect(0, 0, srcRect->width, srcRect->height));
recomputeBushDepth();
#ifdef RGSS2
wave.dirty = true;
#endif
}
void updateSrcRectCon()
@ -141,6 +171,16 @@ struct SpritePrivate
if (!opacity)
return;
#ifdef RGSS2
if (wave.active)
{
/* Don't do expensive wave bounding box
* calculations */
isVisible = true;
return;
}
#endif
/* Compare sprite bounding box against the scene */
/* If sprite is zoomed/rotated, just opt out for now
@ -161,10 +201,101 @@ struct SpritePrivate
isVisible = SDL_HasIntersection(&self, &sceneRect);
}
#ifdef RGSS2
void emitWaveChunk(SVertex *&vert, float phase, int width,
float zoomY, int chunkY, int chunkLength)
{
float wavePos = phase + (chunkY / (float) wave.length) * M_PI * 2;
float chunkX = sin(wavePos) * wave.amp;
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
FloatRect pos = tex;
pos.x = chunkX;
Quad::setTexPosRect(vert, tex, pos);
vert += 4;
}
void updateWave()
{
if (!bitmap)
return;
if (wave.amp == 0)
{
wave.active = false;
return;
}
wave.active = true;
int width = srcRect->width;
int height = srcRect->height;
float zoomY = trans.getScale().y;
if (wave.amp < -(width / 2))
{
wave.qArray.resize(0);
wave.qArray.commit();
return;
}
/* RMVX does this, and I have no fucking clue why */
if (wave.amp < 0)
{
wave.qArray.resize(1);
int x = -wave.amp;
int w = width - x * 2;
FloatRect tex(x, srcRect->y, w, srcRect->height);
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex);
wave.qArray.commit();
return;
}
/* The length of the sprite as it appears on screen */
int visibleLength = height * zoomY;
/* First chunk length (aligned to 8 pixel boundary */
int firstLength = ((int) trans.getPosition().y) % 8;
/* Amount of full 8 pixel chunks in the middle */
int chunks = (visibleLength - firstLength) / 8;
/* Final chunk length */
int lastLength = (visibleLength - firstLength) % 8;
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
SVertex *vert = &wave.qArray.vertices[0];
float phase = (wave.phase * M_PI) / 180.f;
if (firstLength > 0)
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
for (int i = 0; i < chunks; ++i)
emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8);
if (lastLength > 0)
emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength);
wave.qArray.commit();
}
#endif
void prepare()
{
if (bitmap)
bitmap->flush();
#ifdef RGSS2
if (wave.dirty)
{
updateWave();
wave.dirty = false;
}
#endif
updateVisibility();
}
@ -196,14 +327,21 @@ DEF_ATTR_RD_SIMPLE(Sprite, Angle, float, p->trans.getRotation())
DEF_ATTR_RD_SIMPLE(Sprite, Mirror, bool, p->mirrored)
DEF_ATTR_RD_SIMPLE(Sprite, BushDepth, int, p->bushDepth)
DEF_ATTR_RD_SIMPLE(Sprite, BlendType, int, p->blendType)
DEF_ATTR_RD_SIMPLE(Sprite, Width, int, p->srcRect->width)
DEF_ATTR_RD_SIMPLE(Sprite, Height, int, p->srcRect->height)
DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity)
DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity)
DEF_ATTR_SIMPLE(Sprite, Color, Color*, p->color)
DEF_ATTR_SIMPLE(Sprite, Tone, Tone*, p->tone)
#ifdef RGSS2
DEF_ATTR_RD_SIMPLE(Sprite, Width, int, p->srcRect->width)
DEF_ATTR_RD_SIMPLE(Sprite, Height, int, p->srcRect->height)
DEF_ATTR_RD_SIMPLE(Sprite, WaveAmp, int, p->wave.amp)
DEF_ATTR_RD_SIMPLE(Sprite, WaveLength, int, p->wave.length)
DEF_ATTR_RD_SIMPLE(Sprite, WaveSpeed, int, p->wave.speed)
DEF_ATTR_RD_SIMPLE(Sprite, WavePhase, float, p->wave.phase)
#endif
void Sprite::setBitmap(Bitmap *bitmap)
{
GUARD_DISPOSED
@ -221,6 +359,10 @@ void Sprite::setBitmap(Bitmap *bitmap)
*p->srcRect = bitmap->rect();
p->onSrcRectChange();
p->quad.setPosRect(p->srcRect->toFloatRect());
#ifdef RGSS2
p->wave.dirty = true;
#endif
}
void Sprite::setSrcRect(Rect *rect)
@ -255,6 +397,10 @@ void Sprite::setY(int value)
return;
p->trans.setPosition(Vec2(getX(), value));
#ifdef RGSS2
p->wave.dirty = true;
#endif
}
void Sprite::setOX(int value)
@ -296,6 +442,10 @@ void Sprite::setZoomY(float value)
p->trans.setScale(Vec2(getZoomX(), value));
p->recomputeBushDepth();
#ifdef RGSS2
p->wave.dirty = true;
#endif
}
void Sprite::setAngle(float value)
@ -349,6 +499,36 @@ void Sprite::setBlendType(int type)
}
}
#ifdef RGSS2
#define DEF_WAVE_SETTER(Name, name, type) \
void Sprite::setWave##Name(type value) \
{ \
GUARD_DISPOSED; \
if (p->wave.name == value) \
return; \
p->wave.name = value; \
p->wave.dirty = true; \
}
DEF_WAVE_SETTER(Amp, amp, int)
DEF_WAVE_SETTER(Length, length, int)
DEF_WAVE_SETTER(Speed, speed, int)
DEF_WAVE_SETTER(Phase, phase, float)
#undef DEF_WAVE_SETTER
/* Flashable */
void Sprite::update()
{
Flashable::update();
p->wave.phase += p->wave.speed / 180;
p->wave.dirty = true;
}
#endif
/* Disposable */
void Sprite::releaseResources()
{
@ -410,7 +590,14 @@ void Sprite::draw()
p->bitmap->bindTex(*base);
#ifdef RGSS2
if (p->wave.active)
p->wave.qArray.draw();
else
p->quad.draw();
#else
p->quad.draw();
#endif
glState.blendMode.pop();
}

View file

@ -41,9 +41,6 @@ public:
Sprite(Viewport *viewport = 0);
~Sprite();
int getWidth() const;
int getHeight() const;
DECL_ATTR( Bitmap, Bitmap* )
DECL_ATTR( SrcRect, Rect* )
DECL_ATTR( X, int )
@ -61,6 +58,18 @@ public:
DECL_ATTR( Color, Color* )
DECL_ATTR( Tone, Tone* )
#ifdef RGSS2
int getWidth() const;
int getHeight() const;
DECL_ATTR( WaveAmp, int )
DECL_ATTR( WaveLength, int )
DECL_ATTR( WaveSpeed, int )
DECL_ATTR( WavePhase, float )
void update();
#endif
private:
SpritePrivate *p;

View file

@ -21,8 +21,6 @@
#include "tileatlas.h"
#include <list>
namespace TileAtlas
{
@ -37,8 +35,7 @@ struct Column
{}
};
// FIXME: this can be optimized to a vector
typedef std::list<Column> ColumnList;
typedef std::vector<Column> ColumnVec;
/* Autotile area width */
static const int atAreaW = 96*4;
@ -79,9 +76,10 @@ Vec2i minSize(int tilesetH, int maxAtlasSize)
return Vec2i(-1, -1);
}
static ColumnList calcSrcCols(int tilesetH)
static ColumnVec calcSrcCols(int tilesetH)
{
ColumnList cols;
ColumnVec cols;
cols.reserve(2);
cols.push_back(Column(0, 0, tilesetH));
cols.push_back(Column(tsLaneW, 0, tilesetH));
@ -89,9 +87,10 @@ static ColumnList calcSrcCols(int tilesetH)
return cols;
}
static ColumnList calcDstCols(int atlasW, int atlasH)
static ColumnVec calcDstCols(int atlasW, int atlasH)
{
ColumnList cols;
ColumnVec cols;
cols.reserve(3);
/* Columns below the autotile area */
const int underAt = atlasH - atAreaH;
@ -110,19 +109,21 @@ static ColumnList calcDstCols(int atlasW, int atlasH)
return cols;
}
static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols)
static BlitVec calcBlitsInt(ColumnVec &srcCols, ColumnVec &dstCols)
{
BlitList blits;
BlitVec blits;
while (!srcCols.empty())
/* Using signed indices here is safer, as we
* might decrement dstI while it is zero. */
int dstI = 0;
for (size_t srcI = 0; srcI < srcCols.size(); ++srcI)
{
Column srcCol = srcCols.front();
srcCols.pop_front();
Column &srcCol = srcCols[srcI];
while (!dstCols.empty() && srcCol.h > 0)
for (; dstI < (int) dstCols.size() && srcCol.h > 0; ++dstI)
{
Column dstCol = dstCols.front();
dstCols.pop_front();
Column &dstCol = dstCols[dstI];
if (srcCol.h > dstCol.h)
{
@ -141,7 +142,10 @@ static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols)
dstCol.y += srcCol.h;
dstCol.h -= srcCol.h;
dstCols.push_front(dstCol);
/* Queue this column up again for processing */
--dstI;
srcCol.h = 0;
}
else
@ -156,10 +160,10 @@ static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols)
return blits;
}
BlitList calcBlits(int tilesetH, const Vec2i &atlasSize)
BlitVec calcBlits(int tilesetH, const Vec2i &atlasSize)
{
ColumnList srcCols = calcSrcCols(tilesetH);
ColumnList dstCols = calcDstCols(atlasSize.x, atlasSize.y);
ColumnVec srcCols = calcSrcCols(tilesetH);
ColumnVec dstCols = calcDstCols(atlasSize.x, atlasSize.y);
return calcBlitsInt(srcCols, dstCols);
}

View file

@ -46,16 +46,17 @@ struct Blit
{}
};
typedef std::vector<Blit> BlitList;
typedef std::vector<Blit> BlitVec;
/* Calculates the minimum atlas size required to hold
* a tileset of height 'tilesetH'. If the required dimensions
* exceed 'maxAtlasSize', Vec2i(-1, -1) is returned. */
Vec2i minSize(int tilesetH, int maxAtlasSize);
/* Calculates a series of blits necessary to fill dstRows
* with srcRows without wasting any space */
BlitList calcBlits(int tilesetH, const Vec2i &atlasSize);
/* Calculates a series of blits necessary to fill an atlas
* of size 'atlasSize' with a tileset of height 'tilesetH'.
* Usually fed results from 'minSize()'. */
BlitVec calcBlits(int tilesetH, const Vec2i &atlasSize);
/* Translates a tile coordinate (not pixel!) to a physical
* pixel coordinate in the atlas */

View file

@ -48,13 +48,6 @@ extern const StaticRect autotileRects[];
typedef std::vector<SVertex> SVVector;
typedef struct { SVVector v[4]; } TileVBuffer;
/* Check if [C]ontainer contains [V]alue */
template<typename C, typename V>
inline bool contains(const C &c, const V &v)
{
return std::find(c.begin(), c.end(), v) != c.end();
}
static const int tilesetW = 8 * 32;
static const int autotileW = 3 * 32;
static const int autotileH = 4 * 32;
@ -511,8 +504,6 @@ struct TilemapPrivate
usableATs.push_back(i);
autotiles[i]->flush();
if (autotiles[i]->width() > autotileW)
animatedATs.push_back(i);
}
@ -623,14 +614,9 @@ struct TilemapPrivate
/* Assembles atlas from tileset and autotile bitmaps */
void buildAtlas()
{
tileset->flush();
updateAutotileInfo();
for (size_t i = 0; i < atlas.usableATs.size(); ++i)
autotiles[atlas.usableATs[i]]->flush();
TileAtlas::BlitList blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
TileAtlas::BlitVec blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
/* Clear atlas */
FBO::bind(atlas.gl.fbo, FBO::Draw);

View file

@ -24,6 +24,7 @@
#include <stdio.h>
#include <string>
#include <algorithm>
static inline int
wrapRange(int value, int min, int max)
@ -93,6 +94,13 @@ inline void strReplace(std::string &str,
str[i] = after;
}
/* Check if [C]ontainer contains [V]alue */
template<typename C, typename V>
inline bool contains(const C &c, const V &v)
{
return std::find(c.begin(), c.end(), v) != c.end();
}
#define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0]))
#define elementsN(obj) const int obj##N = ARRAY_SIZE(obj)

View file

@ -508,12 +508,6 @@ struct WindowPrivate
{
bool updateBaseQuadArray = false;
if (windowskin)
windowskin->flush();
if (contents)
contents->flush();
if (baseVertDirty)
{
buildBaseVert();