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:
		
							parent
							
								
									1b0eb2797d
								
							
						
					
					
						commit
						e0a4dfe372
					
				
					 10 changed files with 23 additions and 157 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,9 +93,6 @@ struct PlanePrivate
 | 
			
		|||
			updateQuadSource();
 | 
			
		||||
			quadSourceDirty = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (bitmap)
 | 
			
		||||
			bitmap->flush();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,9 +163,6 @@ struct SpritePrivate
 | 
			
		|||
 | 
			
		||||
	void prepare()
 | 
			
		||||
	{
 | 
			
		||||
		if (bitmap)
 | 
			
		||||
			bitmap->flush();
 | 
			
		||||
 | 
			
		||||
		updateVisibility();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -508,12 +508,6 @@ struct WindowPrivate
 | 
			
		|||
	{
 | 
			
		||||
		bool updateBaseQuadArray = false;
 | 
			
		||||
 | 
			
		||||
		if (windowskin)
 | 
			
		||||
			windowskin->flush();
 | 
			
		||||
 | 
			
		||||
		if (contents)
 | 
			
		||||
			contents->flush();
 | 
			
		||||
 | 
			
		||||
		if (baseVertDirty)
 | 
			
		||||
		{
 | 
			
		||||
			buildBaseVert();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue