Bitmap: Make #get_pixel/#set_pixel more accurate

This gets rid of the "batch/flush" semantics for #set_pixel
and instead just directly uploads the pixel color to the
texture, circumventing the float conversion entirely.
Also makes a lot of code simpler in many places as calling
'flush()' is no longer required for bitmaps.
This commit is contained in:
Jonas Kulla 2014-01-31 10:19:16 +01:00
parent 1b0eb2797d
commit e0a4dfe372
10 changed files with 23 additions and 157 deletions

View File

@ -202,7 +202,7 @@ RB_METHOD(bitmapGetPixel)
return Qnil;
)
Vec4 value;
Color value;
GUARD_EXC( value = b->getPixel(x, y); );
Color *color = new Color(value);
@ -223,7 +223,7 @@ RB_METHOD(bitmapSetPixel)
color = getPrivateDataCheck<Color>(colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); );
GUARD_EXC( b->setPixel(x, y, *color); );
return self;
}

View File

@ -194,7 +194,7 @@ MRB_METHOD(bitmapGetPixel)
return mrb_nil_value();
)
Vec4 value;
Color value;
GUARD_EXC( value = b->getPixel(x, y); )
Color *color = new Color(value);
@ -215,7 +215,7 @@ MRB_METHOD(bitmapSetPixel)
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); )
GUARD_EXC( b->setPixel(x, y, *color); )
return mrb_nil_value();
}

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);
@ -666,9 +634,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 +647,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 +656,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 +699,6 @@ void Bitmap::hueChange(int hue)
if ((hue % 360) == 0)
return;
flush();
TEXFBO newTex = shState->texPool().request(width(), height());
FloatRect texRect(rect());
@ -777,8 +750,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();
@ -1009,17 +980,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

@ -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

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

View File

@ -110,67 +110,4 @@ 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();
}
};
#endif // QUADARRAY_H

View File

@ -163,9 +163,6 @@ struct SpritePrivate
void prepare()
{
if (bitmap)
bitmap->flush();
updateVisibility();
}
};

View File

@ -511,8 +511,6 @@ struct TilemapPrivate
usableATs.push_back(i);
autotiles[i]->flush();
if (autotiles[i]->width() > autotileW)
animatedATs.push_back(i);
}
@ -623,13 +621,8 @@ 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::BlitVec blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
/* Clear atlas */

View File

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