Bitmap#get_pixel: Use cached client side copy of pixels
A very simplistic optimization for games that create a Bitmap and then only ever query pixels from it.
This commit is contained in:
parent
caae9c5689
commit
d1bad9b45f
|
@ -25,6 +25,7 @@
|
||||||
#include <SDL_image.h>
|
#include <SDL_image.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
#include <SDL_rect.h>
|
#include <SDL_rect.h>
|
||||||
|
#include <SDL_surface.h>
|
||||||
|
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@
|
||||||
|
|
||||||
struct BitmapPrivate
|
struct BitmapPrivate
|
||||||
{
|
{
|
||||||
|
Bitmap *self;
|
||||||
|
|
||||||
TEXFBO gl;
|
TEXFBO gl;
|
||||||
|
|
||||||
Font *font;
|
Font *font;
|
||||||
|
@ -63,6 +66,12 @@ struct BitmapPrivate
|
||||||
* any context other than as Tilesets */
|
* any context other than as Tilesets */
|
||||||
SDL_Surface *megaSurface;
|
SDL_Surface *megaSurface;
|
||||||
|
|
||||||
|
/* A cached version of the bitmap in client memory, for
|
||||||
|
* getPixel calls. Is invalidated any time the bitmap
|
||||||
|
* is modified */
|
||||||
|
SDL_Surface *surface;
|
||||||
|
SDL_PixelFormat *format;
|
||||||
|
|
||||||
/* The 'tainted' area describes which parts of the
|
/* The 'tainted' area describes which parts of the
|
||||||
* bitmap are not cleared, ie. don't have 0 opacity.
|
* bitmap are not cleared, ie. don't have 0 opacity.
|
||||||
* If we're blitting / drawing text to a cleared part
|
* If we're blitting / drawing text to a cleared part
|
||||||
|
@ -71,9 +80,13 @@ struct BitmapPrivate
|
||||||
* ourselves the expensive blending calculation */
|
* ourselves the expensive blending calculation */
|
||||||
pixman_region16_t tainted;
|
pixman_region16_t tainted;
|
||||||
|
|
||||||
BitmapPrivate()
|
BitmapPrivate(Bitmap *self)
|
||||||
: megaSurface(0)
|
: self(self),
|
||||||
|
megaSurface(0),
|
||||||
|
surface(0)
|
||||||
{
|
{
|
||||||
|
format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
|
||||||
|
|
||||||
font = &shState->defaultFont();
|
font = &shState->defaultFont();
|
||||||
pixman_region_init(&tainted);
|
pixman_region_init(&tainted);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +96,13 @@ struct BitmapPrivate
|
||||||
pixman_region_fini(&tainted);
|
pixman_region_fini(&tainted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void allocSurface()
|
||||||
|
{
|
||||||
|
surface = SDL_CreateRGBSurface(0, gl.width, gl.height, format->BitsPerPixel,
|
||||||
|
format->Rmask, format->Gmask,
|
||||||
|
format->Bmask, format->Amask);
|
||||||
|
}
|
||||||
|
|
||||||
void clearTaintedArea()
|
void clearTaintedArea()
|
||||||
{
|
{
|
||||||
pixman_region_clear(&tainted);
|
pixman_region_clear(&tainted);
|
||||||
|
@ -175,6 +195,17 @@ struct BitmapPrivate
|
||||||
SDL_FreeSurface(surf);
|
SDL_FreeSurface(surf);
|
||||||
surf = surfConv;
|
surf = surfConv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onModified()
|
||||||
|
{
|
||||||
|
if (surface)
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
surface = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->modified();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitmap::Bitmap(const char *filename)
|
Bitmap::Bitmap(const char *filename)
|
||||||
|
@ -193,7 +224,7 @@ Bitmap::Bitmap(const char *filename)
|
||||||
if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize)
|
if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize)
|
||||||
{
|
{
|
||||||
/* Mega surface */
|
/* Mega surface */
|
||||||
p = new BitmapPrivate;
|
p = new BitmapPrivate(this);
|
||||||
p->megaSurface = imgSurf;
|
p->megaSurface = imgSurf;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -211,7 +242,7 @@ Bitmap::Bitmap(const char *filename)
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = new BitmapPrivate;
|
p = new BitmapPrivate(this);
|
||||||
p->gl = tex;
|
p->gl = tex;
|
||||||
|
|
||||||
TEX::bind(p->gl.tex);
|
TEX::bind(p->gl.tex);
|
||||||
|
@ -230,7 +261,7 @@ Bitmap::Bitmap(int width, int height)
|
||||||
|
|
||||||
TEXFBO tex = shState->texPool().request(width, height);
|
TEXFBO tex = shState->texPool().request(width, height);
|
||||||
|
|
||||||
p = new BitmapPrivate;
|
p = new BitmapPrivate(this);
|
||||||
p->gl = tex;
|
p->gl = tex;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
@ -240,7 +271,7 @@ Bitmap::Bitmap(const Bitmap &other)
|
||||||
{
|
{
|
||||||
other.ensureNonMega();
|
other.ensureNonMega();
|
||||||
|
|
||||||
p = new BitmapPrivate;
|
p = new BitmapPrivate(this);
|
||||||
|
|
||||||
p->gl = shState->texPool().request(other.width(), other.height());
|
p->gl = shState->texPool().request(other.width(), other.height());
|
||||||
|
|
||||||
|
@ -345,7 +376,7 @@ void Bitmap::stretchBlt(const IntRect &destRect,
|
||||||
|
|
||||||
SDL_FreeSurface(blitTemp);
|
SDL_FreeSurface(blitTemp);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +426,7 @@ void Bitmap::stretchBlt(const IntRect &destRect,
|
||||||
|
|
||||||
p->addTaintedArea(destRect);
|
p->addTaintedArea(destRect);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::fillRect(int x, int y,
|
void Bitmap::fillRect(int x, int y,
|
||||||
|
@ -420,7 +451,7 @@ void Bitmap::fillRect(const IntRect &rect, const Vec4 &color)
|
||||||
/* Fill op */
|
/* Fill op */
|
||||||
p->addTaintedArea(rect);
|
p->addTaintedArea(rect);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RGSS2
|
#ifdef RGSS2
|
||||||
|
@ -473,7 +504,7 @@ void Bitmap::gradientFillRect(const IntRect &rect,
|
||||||
|
|
||||||
p->addTaintedArea(rect);
|
p->addTaintedArea(rect);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::clearRect(int x, int y, int width, int height)
|
void Bitmap::clearRect(int x, int y, int width, int height)
|
||||||
|
@ -489,7 +520,7 @@ void Bitmap::clearRect(const IntRect &rect)
|
||||||
|
|
||||||
p->fillRect(rect, Vec4());
|
p->fillRect(rect, Vec4());
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::blur()
|
void Bitmap::blur()
|
||||||
|
@ -534,7 +565,7 @@ void Bitmap::blur()
|
||||||
|
|
||||||
shState->texPool().release(auxTex);
|
shState->texPool().release(auxTex);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::radialBlur(int angle, int divisions)
|
void Bitmap::radialBlur(int angle, int divisions)
|
||||||
|
@ -629,7 +660,7 @@ void Bitmap::radialBlur(int angle, int divisions)
|
||||||
shState->texPool().release(p->gl);
|
shState->texPool().release(p->gl);
|
||||||
p->gl = newTex;
|
p->gl = newTex;
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -650,7 +681,7 @@ void Bitmap::clear()
|
||||||
|
|
||||||
p->clearTaintedArea();
|
p->clearTaintedArea();
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Bitmap::getPixel(int x, int y) const
|
Color Bitmap::getPixel(int x, int y) const
|
||||||
|
@ -662,16 +693,27 @@ Color Bitmap::getPixel(int x, int y) const
|
||||||
if (x < 0 || y < 0 || x >= width() || y >= height())
|
if (x < 0 || y < 0 || x >= width() || y >= height())
|
||||||
return Vec4();
|
return Vec4();
|
||||||
|
|
||||||
FBO::bind(p->gl.fbo, FBO::Read);
|
if (!p->surface)
|
||||||
|
{
|
||||||
|
p->allocSurface();
|
||||||
|
|
||||||
glState.viewport.pushSet(IntRect(0, 0, width(), height()));
|
FBO::bind(p->gl.fbo, FBO::Read);
|
||||||
|
|
||||||
uint8_t pixel[4];
|
glState.viewport.pushSet(IntRect(0, 0, width(), height()));
|
||||||
gl.ReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
|
|
||||||
|
|
||||||
glState.viewport.pop();
|
gl.ReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, p->surface->pixels);
|
||||||
|
|
||||||
return Color(pixel[0], pixel[1], pixel[2], pixel[3]);
|
glState.viewport.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = x*p->format->BytesPerPixel + y*p->surface->pitch;
|
||||||
|
uint8_t *bytes = (uint8_t*) p->surface->pixels + offset;
|
||||||
|
uint32_t pixel = *((uint32_t*) bytes);
|
||||||
|
|
||||||
|
return Color((pixel >> p->format->Rshift) & 0xFF,
|
||||||
|
(pixel >> p->format->Gshift) & 0xFF,
|
||||||
|
(pixel >> p->format->Bshift) & 0xFF,
|
||||||
|
(pixel >> p->format->Ashift) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::setPixel(int x, int y, const Color &color)
|
void Bitmap::setPixel(int x, int y, const Color &color)
|
||||||
|
@ -693,7 +735,7 @@ void Bitmap::setPixel(int x, int y, const Color &color)
|
||||||
|
|
||||||
p->addTaintedArea(IntRect(x, y, 1, 1));
|
p->addTaintedArea(IntRect(x, y, 1, 1));
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::hueChange(int hue)
|
void Bitmap::hueChange(int hue)
|
||||||
|
@ -734,7 +776,7 @@ void Bitmap::hueChange(int hue)
|
||||||
shState->texPool().release(p->gl);
|
shState->texPool().release(p->gl);
|
||||||
p->gl = newTex;
|
p->gl = newTex;
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::drawText(int x, int y,
|
void Bitmap::drawText(int x, int y,
|
||||||
|
@ -914,7 +956,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
|
||||||
SDL_FreeSurface(txtSurf);
|
SDL_FreeSurface(txtSurf);
|
||||||
p->addTaintedArea(posRect);
|
p->addTaintedArea(posRect);
|
||||||
|
|
||||||
modified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* http://www.lemoda.net/c/utf8-to-ucs2/index.html */
|
/* http://www.lemoda.net/c/utf8-to-ucs2/index.html */
|
||||||
|
|
Loading…
Reference in New Issue