fix alpha blending + add depth/stencil buffers

This commit is contained in:
Konstantin Käfer
2014-05-21 18:34:41 +02:00
parent 16a79b42ca
commit 53a6992728
15 changed files with 252 additions and 165 deletions

View File

@@ -261,6 +261,10 @@ void show_color_debug_image(std::string name, const char *data, size_t logical_w
float x_scale = (float)fb_width / (float)width;
float y_scale = (float)fb_height / (float)height;
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelZoom(x_scale, -y_scale);
glRasterPos2f(-1.0f, 1.0f);
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data);

View File

@@ -22,6 +22,8 @@ namespace llmr {
class Source;
typedef std::map<std::string, const std::unique_ptr<Source>> Sources;
class Map : private util::noncopyable {
public:
explicit Map(View &view);
@@ -96,6 +98,7 @@ public:
inline uv_loop_t *getLoop() { return loop; }
inline time getAnimationTime() const { return animationTime; }
inline Texturepool &getTexturepool() { return texturepool; }
inline const Sources &getSources() { return sources; }
private:
// uv async callbacks
@@ -108,7 +111,7 @@ private:
void loadStyle(const uint8_t *const data, uint32_t bytes);
void updateTiles();
void updateClippingIDs();
void updateRenderState();
size_t countLayers(const std::vector<LayerDescription>& layers);
@@ -123,11 +126,6 @@ private:
void renderLayers(const std::vector<LayerDescription>& layers);
void renderLayer(const LayerDescription& layer_desc, RenderPass pass);
void clearFramebuffers();
void bindFramebuffer();
void pushFramebuffer();
GLuint popFramebuffer();
private:
// If cleared, the next time the render thread attempts to render the map, it will *actually*
// render the map.
@@ -152,17 +150,13 @@ private:
SpriteAtlas spriteAtlas;
Painter painter;
std::map<std::string, const std::unique_ptr<Source>> sources;
Sources sources;
bool debug = false;
time animationTime = 0;
int indent = 0;
std::vector<GLuint> fbos;
std::vector<GLuint> fbos_color;
int fbo_level = -1;
private:
bool async = false;
uv_loop_t *loop = nullptr;

View File

@@ -36,7 +36,9 @@ public:
bool update();
size_t prepareRender(const TransformState &transform);
void updateMatrices(const TransformState &transform);
void drawClippingMasks();
size_t getTileCount() const;
void render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc);
void finishRender();

View File

@@ -22,12 +22,15 @@
#include <llmr/map/transform_state.hpp>
#include <map>
namespace llmr {
class Transform;
class Style;
class Tile;
class GlyphAtlas;
class Source;
class FillBucket;
class LineBucket;
@@ -38,9 +41,12 @@ class RasterBucket;
class LayerDescription;
class RasterTileData;
typedef std::map<std::string, const std::unique_ptr<Source>> Sources;
class Painter : private util::noncopyable {
public:
Painter(Map &map);
~Painter();
void setup();
@@ -76,17 +82,20 @@ public:
void setDebug(bool enabled);
// Opaque/Translucent pass setting
void startOpaquePass();
void startTranslucentPass();
void endPass();
void setOpaque();
void setTranslucent();
// Configures the painter strata that is used for early z-culling of fragments.
void setStrata(float strata);
void prepareClippingMask();
void drawClippingMasks(const Sources &sources);
void drawClippingMask(const mat4& matrix, const ClipID& clip);
void finishClippingMask();
void clearFramebuffers();
void resetFramebuffer();
void bindFramebuffer();
void pushFramebuffer();
GLuint popFramebuffer();
void drawComposite(GLuint texture, const CompositeProperties &properties);
bool needsAnimation() const;
@@ -163,6 +172,13 @@ private:
VertexArrayObject tileBorderArray;
// Framebuffer management
std::vector<GLuint> fbos;
std::vector<GLuint> fbos_color;
GLuint fbo_depth_stencil;
int fbo_level = -1;
bool fbo_depth_stencil_valid = false;
};
}

View File

@@ -55,11 +55,23 @@ bool SpriteAtlas::resize(const float newRatio) {
void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, const int src_y,
uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y,
const int width, const int height) {
const int stride = width * sizeof(uint32_t);
src += src_y * src_stride + src_x;
dst += dst_y * dst_stride + dst_x;
for (int y = 0; y < height; y++, src += src_stride, dst += dst_stride) {
memcpy(dst, src, stride);
for (int x = 0; x < width; x++) {
const uint8_t *s = reinterpret_cast<const uint8_t *>(src + x);
uint8_t *d = reinterpret_cast<uint8_t *>(dst + x);
// Premultiply the bitmap.
// Note: We don't need to clamp the component values to 0..255, since
// the source value is already 0..255 and the operation means they will
// stay within the range of 0..255 and won't overflow.
const uint8_t a = s[3];
d[0] = s[0] * a / 255;
d[1] = s[1] * a / 255;
d[2] = s[2] * a / 255;
d[3] = a;
}
}
}

View File

@@ -35,8 +35,6 @@ Map::Map(View& view)
}
Map::~Map() {
clearFramebuffers();
uv_loop_delete(loop);
loop = nullptr;
}
@@ -185,10 +183,15 @@ void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width
if (transform.resize(width, height, ratio, fb_width, fb_height)) {
changed = true;
}
// TODO: Make sure we're not currently rendering anything
if (spriteAtlas.resize(ratio)) {
changed = true;
}
// TODO: Make sure we're not currently rendering anything
painter.clearFramebuffers();
if (changed) {
update();
}
@@ -369,24 +372,23 @@ void Map::updateTiles() {
}
}
void Map::updateClippingIDs() {
void Map::updateRenderState() {
std::forward_list<Tile::ID> ids;
for (auto &pair : sources) {
const std::unique_ptr<Source> &source = pair.second;
if (source->enabled) {
ids.splice_after(ids.before_begin(), source->getIDs());
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
ids.splice_after(ids.before_begin(), source.getIDs());
source.updateMatrices(state);
}
}
const std::map<Tile::ID, ClipID> clipIDs = computeClipIDs(ids);
for (auto &pair : sources) {
const std::unique_ptr<Source> &source = pair.second;
if (source->enabled) {
source->updateClipIDs(clipIDs);
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
source.updateClipIDs(clipIDs);
}
}
}
@@ -413,8 +415,6 @@ void Map::prepare() {
}
updateTiles();
updateClippingIDs();
}
void Map::render() {
@@ -422,26 +422,25 @@ void Map::render() {
painter.clear();
painter.resetFramebuffer();
painter.resize();
painter.changeMatrix();
// First, update the sources' tile matrices with the new
// transform and render into the stencil buffer, including
// drawing the background.
updateRenderState();
painter.prepareClippingMask();
painter.drawClippingMasks(sources);
// Generate debug information
size_t source_id = 0;
for (auto &pair : sources) {
Source &source = *pair.second;
size_t count = source.prepareRender(state);
for (const auto &pair : sources) {
const Source &source = *pair.second;
size_t count = source.getTileCount();
debug.emplace_back(util::sprintf<100>("source %d: %d\n", source_id, count));
source_id++;
}
painter.finishClippingMask();
// Actually render the layers
if (debug::renderTree) { std::cout << "{" << std::endl; indent++; }
renderLayers(style.layers);
@@ -451,7 +450,7 @@ void Map::render() {
// This guarantees that we have at least one function per tile called.
// When only rendering layers via the stylesheet, it's possible that we don't
// ever visit a tile during rendering.
for (auto &pair : sources) {
for (const auto &pair : sources) {
Source &source = *pair.second;
const std::string &name = pair.first;
gl::group group(std::string("debug ") + name);
@@ -481,14 +480,14 @@ void Map::renderLayers(const std::vector<LayerDescription>& layers) {
if (debug::renderTree) {
std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl;
}
painter.startOpaquePass();
typedef std::vector<LayerDescription>::const_reverse_iterator riterator;
int i = 0;
for (riterator it = layers.rbegin(), end = layers.rend(); it != end; ++it, ++i) {
painter.setOpaque();
painter.setStrata(i * strata_thickness);
renderLayer(*it, Opaque);
}
painter.endPass();
// painter.endPass();
if (debug::renderTree) {
std::cout << std::string(--indent * 4, ' ') << "}" << std::endl;
}
@@ -499,14 +498,14 @@ void Map::renderLayers(const std::vector<LayerDescription>& layers) {
if (debug::renderTree) {
std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl;
}
painter.startTranslucentPass();
typedef std::vector<LayerDescription>::const_iterator iterator;
--i;
for (iterator it = layers.begin(), end = layers.end(); it != end; ++it, --i) {
painter.setTranslucent();
painter.setStrata(i * strata_thickness);
renderLayer(*it, Translucent);
}
painter.endPass();
// painter.endPass();
if (debug::renderTree) {
std::cout << std::string(--indent * 4, ' ') << "}" << std::endl;
}
@@ -554,13 +553,11 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
<< " (Composite) {" << std::endl;
}
pushFramebuffer();
glClear(GL_COLOR_BUFFER_BIT);
painter.pushFramebuffer();
renderLayers(layer_desc.child_layer);
GLuint texture = popFramebuffer();
GLuint texture = painter.popFramebuffer();
// Render the previous texture onto the screen.
painter.drawComposite(texture, properties);
@@ -630,73 +627,3 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
}
}
}
void Map::clearFramebuffers() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Delete any framebuffers that we might have allocated
glDeleteTextures(fbos_color.size(), fbos.data());
fbos_color.clear();
glDeleteFramebuffersEXT(fbos.size(), fbos.data());
fbos.clear();
}
void Map::bindFramebuffer() {
if (fbo_level < 0) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
} else if (fbos.size() > (size_t)fbo_level) {
GLuint fbo = fbos[fbo_level];
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
} else {
// TODO: Convert this to textures so we can composite them and use them in blend operations
GLuint fbo_color;
glGenTextures(1, &fbo_color);
glBindTexture(GL_TEXTURE_2D, fbo_color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, state.getFramebufferWidth(), state.getFramebufferHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
fbos_color.emplace_back(fbo_color);
// TODO: Stencil/Depth buffer
// Allocate new framebuffer
GLuint fbo = 0;
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
fbos.emplace_back(fbo);
// Assemble the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_color, 0);
// TODO: Stencil/Depth buffer
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
fprintf(stderr, "Couldn't create framebuffer: ");
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break;
case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break;
default: fprintf(stderr, "other\n"); break;
}
return;
}
}
}
void Map::pushFramebuffer() {
fbo_level++;
bindFramebuffer();
}
GLuint Map::popFramebuffer() {
GLuint texture = fbos_color[fbo_level];
fbo_level--;
bindFramebuffer();
return texture;
}

View File

@@ -45,27 +45,31 @@ void Source::updateClipIDs(const std::map<Tile::ID, ClipID> &mapping) {
});
}
size_t Source::prepareRender(const TransformState &transform) {
if (!enabled) return 0;
void Source::updateMatrices(const TransformState &transform) {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
transform.matrixFor(tile.matrix, tile.id);
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
}
}
size_t masks = 0;
size_t Source::getTileCount() const {
return tiles.size();
}
void Source::drawClippingMasks() {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
gl::group group(util::sprintf<32>("mask %d/%d/%d", tile.id.z, tile.id.y, tile.id.z));
transform.matrixFor(tile.matrix, tile.id);
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
painter.drawClippingMask(tile.matrix, tile.clip);
masks++;
}
return masks;
}
void Source::render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc) {
if (!enabled) return;
gl::group group(std::string("layer: ") + layer_desc.name);
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
if (tile.data && tile.data->state == TileData::State::parsed) {
painter.renderTileLayer(tile, layer_desc);

View File

@@ -20,6 +20,10 @@ Painter::Painter(Map &map)
: map(map) {
}
Painter::~Painter() {
clearFramebuffers();
}
bool Painter::needsAnimation() const {
return frameHistory.needsAnimation(300);
}
@@ -133,24 +137,18 @@ void Painter::clear() {
#endif
}
void Painter::startOpaquePass() {
gl::start_group("opaque pass");
void Painter::setOpaque() {
pass = Opaque;
glDisable(GL_BLEND);
depthMask(true);
}
void Painter::startTranslucentPass() {
gl::start_group("translucent pass");
void Painter::setTranslucent() {
pass = Translucent;
glEnable(GL_BLEND);
depthMask(false);
}
void Painter::endPass() {
gl::end_group();
}
void Painter::setStrata(float value) {
strata = value;
}

View File

@@ -1,18 +1,39 @@
#include <llmr/renderer/painter.hpp>
#include <llmr/renderer/fill_bucket.hpp>
#include <llmr/map/map.hpp>
#include <llmr/map/source.hpp>
#include <llmr/util/clip_ids.hpp>
using namespace llmr;
void Painter::prepareClippingMask() {
gl::start_group("clipping masks");
void Painter::drawClippingMasks(const Sources &sources) {
gl::group group("clipping masks");
useProgram(plainShader->program);
glDisable(GL_DEPTH_TEST);
depthMask(false);
glDepthRange(1.0f, 1.0f);
glStencilMask(0xFF);
Color background = map.getStyle().computed.background.color;
background[0] *= map.getStyle().computed.background.opacity;
background[1] *= map.getStyle().computed.background.opacity;
background[2] *= map.getStyle().computed.background.opacity;
background[3] *= map.getStyle().computed.background.opacity;
plainShader->setColor(background);
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
source.drawClippingMasks();
}
}
glEnable(GL_DEPTH_TEST);
depthMask(true);
glStencilMask(0x0);
}
void Painter::drawClippingMask(const mat4& matrix, const ClipID &clip) {
@@ -21,22 +42,6 @@ void Painter::drawClippingMask(const mat4& matrix, const ClipID &clip) {
GLint id = clip.mask.to_ulong();
GLuint mask = clipMask[clip.length];
glStencilFunc(GL_ALWAYS, id, mask);
glStencilMask(0xFF);
Color background = map.getStyle().computed.background.color;
background[0] *= map.getStyle().computed.background.opacity;
background[1] *= map.getStyle().computed.background.opacity;
background[2] *= map.getStyle().computed.background.opacity;
background[3] *= map.getStyle().computed.background.opacity;
plainShader->setColor(background);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
}
void Painter::finishClippingMask() {
glEnable(GL_DEPTH_TEST);
depthMask(true);
glStencilMask(0x0);
gl::end_group();
}

View File

@@ -5,8 +5,14 @@
using namespace llmr;
void Painter::drawComposite(GLuint texture, const CompositeProperties &properties) {
// We're doing full-screen framebuffer blending, so no need to do stencil testing here.
glDisable(GL_STENCIL_TEST);
// Normally, we're using premultiplied alpha, but the resulting image we've
// just drawn is non-premultiplied. That means when blending, we have to make
// sure that we account for that.
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
useProgram(compositeShader->program);
compositeShader->setMatrix(nativeMatrix);
@@ -14,12 +20,19 @@ void Painter::drawComposite(GLuint texture, const CompositeProperties &propertie
glBindTexture(GL_TEXTURE_2D, texture);
compositeShader->setImage(0);
// TODO: layerstyle
// TODO: translate
compositeShader->setOpacity(properties.opacity);
// Draw the clipping mask
// Draw the full screen texture.
// TODO: Do more blend effects like multiply + blur
compositeArray.bind(*compositeShader, tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
glBindTexture(GL_TEXTURE_2D, 0);
// Reset back.
glEnable(GL_STENCIL_TEST);
// Reset back to use premultiplied alpha blending.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}

View File

@@ -0,0 +1,111 @@
#include <llmr/renderer/painter.hpp>
#include <llmr/renderer/fill_bucket.hpp>
#include <llmr/map/map.hpp>
#include <llmr/util/clip_ids.hpp>
using namespace llmr;
void Painter::clearFramebuffers() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Delete any framebuffers that we might have allocated
glDeleteTextures(fbos_color.size(), fbos.data());
fbos_color.clear();
if (fbo_depth_stencil != 0) {
glDeleteRenderbuffersEXT(1, &fbo_depth_stencil);
fbo_depth_stencil = 0;
}
glDeleteFramebuffersEXT(fbos.size(), fbos.data());
fbos.clear();
}
void Painter::bindFramebuffer() {
if (fbo_level < 0) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
} else if (fbos.size() > (size_t)fbo_level) {
GLuint fbo = fbos[fbo_level];
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
} else {
// TODO: Convert this to textures so we can composite them and use them in blend operations
GLuint fbo_color;
glGenTextures(1, &fbo_color);
glBindTexture(GL_TEXTURE_2D, fbo_color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, map.getState().getFramebufferWidth(), map.getState().getFramebufferHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
fbos_color.emplace_back(fbo_color);
// Use a shared depth/stencil buffer for all framebuffer objects
if (fbo_depth_stencil == 0) {
// Create depth/stencil buffer
glGenRenderbuffersEXT(1, &fbo_depth_stencil);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth_stencil);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, map.getState().getFramebufferWidth(), map.getState().getFramebufferHeight());
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
}
// Allocate new framebuffer
GLuint fbo = 0;
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
fbos.emplace_back(fbo);
// Assemble the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_color, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fbo_depth_stencil);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
fprintf(stderr, "Couldn't create framebuffer: ");
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break;
case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break;
default: fprintf(stderr, "other\n"); break;
}
return;
}
}
}
void Painter::resetFramebuffer() {
if (fbo_level >= 0) {
fbo_level = -1;
bindFramebuffer();
}
fbo_depth_stencil_valid = false;
}
void Painter::pushFramebuffer() {
fbo_level++;
bindFramebuffer();
if (fbo_depth_stencil_valid) {
glClear(GL_COLOR_BUFFER_BIT);
} else {
depthMask(true);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glColorMask(false, false, false, false);
drawClippingMasks(map.getSources());
glColorMask(true, true, true, true);
fbo_depth_stencil_valid = true;
}
}
GLuint Painter::popFramebuffer() {
GLuint texture = fbos_color[fbo_level];
fbo_level--;
bindFramebuffer();
return texture;
}

View File

@@ -4,5 +4,6 @@ uniform float u_opacity;
varying vec2 v_pos;
void main() {
gl_FragColor = texture2D(u_image, v_pos / 2.0 + 0.5) * u_opacity;
vec4 color = texture2D(u_image, v_pos);
gl_FragColor = color * u_opacity;
}

View File

@@ -5,5 +5,5 @@ varying vec2 v_pos;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
v_pos = gl_Position.xy;
v_pos = (gl_Position.xy + 1.0) / 2.0;
}

View File

@@ -7,8 +7,8 @@ using namespace llmr;
const shader_source llmr::shaders[SHADER_COUNT] = {
{
"#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = tmpvar_2.xy;\n}\n\n",
"#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((v_pos / 2.0) + 0.5)) * u_opacity);\n}\n\n",
"#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) / 2.0);\n}\n\n",
"#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, v_pos) * u_opacity);\n}\n\n",
},
{
"#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n",

View File

@@ -7,8 +7,8 @@ using namespace llmr;
const shader_source llmr::shaders[SHADER_COUNT] = {
{
"precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying highp vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = tmpvar_2.xy;\n}\n\n",
"precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n lowp vec4 tmpvar_1;\n tmpvar_1 = (texture2D (u_image, ((v_pos / 2.0) + 0.5)) * u_opacity);\n gl_FragColor = tmpvar_1;\n}\n\n",
"precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvarying highp vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n vec4 tmpvar_2;\n tmpvar_2 = (u_matrix * tmpvar_1);\n gl_Position = tmpvar_2;\n v_pos = ((tmpvar_2.xy + 1.0) / 2.0);\n}\n\n",
"precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n lowp vec4 tmpvar_1;\n tmpvar_1 = (texture2D (u_image, v_pos) * u_opacity);\n gl_FragColor = tmpvar_1;\n}\n\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n",