From 4e90c9b39ebab18d13cff281b653cb1d67c1b06b Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 26 Jan 2015 07:29:53 +0300 Subject: [PATCH] cleartype for opengl, part 1; WARNING: openGL text rendering is broken - don't sync to this commit --- dlanguilib.visualdproj | 2 +- examples/example1/example1.visualdproj | 2 +- src/dlangui/graphics/drawbuf.d | 29 +++++ src/dlangui/graphics/gldrawbuf.d | 45 +++---- src/dlangui/graphics/glsupport.d | 156 ++++++++++++++++++++++++- 5 files changed, 200 insertions(+), 34 deletions(-) diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index bdf716d7..8483c29f 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -66,7 +66,7 @@ 0 DebugFocus 0 - EmbedStandardResources Unicode USE_FREETYPE + EmbedStandardResources Unicode USE_FREETYPE USE_OPENGL 0 0 1 diff --git a/examples/example1/example1.visualdproj b/examples/example1/example1.visualdproj index 753ecc88..a0427bb2 100644 --- a/examples/example1/example1.visualdproj +++ b/examples/example1/example1.visualdproj @@ -66,7 +66,7 @@ 0 0 - Unicode USE_FREETYPE + Unicode USE_FREETYPE USE_OPENGL 0 3 0 diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index 3344bda0..e848cf28 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -600,6 +600,35 @@ class ColorDrawBufBase : DrawBuf { } } + void drawGlyphToTexture(int x, int y, Glyph * glyph) { + ubyte[] src = glyph.glyph; + int srcdx = glyph.blackBoxX; + int srcdy = glyph.blackBoxY; + bool subpixel = glyph.subpixelMode != SubpixelRenderingMode.None; + for (int yy = 0; yy < srcdy; yy++) { + int liney = y + yy; + uint * row = scanLine(liney); + ubyte * srcrow = src.ptr + yy * srcdx; + int increment = subpixel ? 3 : 1; + for (int xx = 0; xx <= srcdx - increment; xx += increment) { + int colx = x + (subpixel ? xx / 3 : xx); + uint alpha1 = srcrow[xx] ^ 255; + if (subpixel) { + //int x0 = xx % 3; + //ubyte * dst = cast(ubyte*)(row + colx); + //ubyte * pcolor = cast(ubyte*)(&color); + //blendSubpixel(dst, pcolor, alpha, x0, glyph.subpixelMode); + } else { + uint pixel = (alpha1 << 24) || 0xFFFFFF; //(alpha1 << 16) || (alpha1 << 8) || alpha1; + row[colx] = pixel; + } + } + } + // for debugging + fillRect(Rect(x,y,x+2, y+2), 0xFF8040C0); + fillRect(Rect(x+2,y+2,x+4, y+4), 0x40408070); + } + override void fillRect(Rect rc, uint color) { if (applyClipping(rc)) { for (int y = rc.top; y < rc.bottom; y++) { diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index 5aeee356..1c3f95f3 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -537,9 +537,6 @@ private class TextureSceneItem : SceneItem { }; -/// by some reason ALPHA texture does not work as expected -private immutable USE_RGBA_TEXTURE_FOR_GLYPHS = true; - private class GLGlyphCache { static class GLGlyphCacheItem { @@ -557,7 +554,7 @@ private class GLGlyphCache { private GLGlyphCache _cache; private int _tdx; private int _tdy; - private GrayDrawBuf _drawbuf; + private ColorDrawBuf _drawbuf; private int _currentLine; private int _nextLine; private int _x; @@ -585,9 +582,6 @@ private class GLGlyphCache { } } - static if (USE_RGBA_TEXTURE_FOR_GLYPHS) { - uint[] _rgbaBuffer; - } void updateTexture() { if (_drawbuf is null) return; // no draw buffer!!! @@ -598,23 +592,11 @@ private class GLGlyphCache { return; } //CRLog::debug("updateTexture - setting image %dx%d", _drawbuf.width, _drawbuf.height); - ubyte * pixels = _drawbuf.scanLine(0); - static if (USE_RGBA_TEXTURE_FOR_GLYPHS) { - int len = _drawbuf.width * _drawbuf.height; - _rgbaBuffer.length = len; - for (int i = 0; i < len; i++) - _rgbaBuffer[i] = ((cast(uint)pixels[i]) << 24) | 0x00FFFFFF; - if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)_rgbaBuffer.ptr)) { - glSupport.deleteTexture(_textureId); - _textureId = 0; - return; - } - } else { - if (!setTextureImageAlpha(_textureId, _drawbuf.width, _drawbuf.height, pixels)) { - deleteTexture(_textureId); - _textureId = 0; - return; - } + int len = _drawbuf.width * _drawbuf.height; + if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte *)_drawbuf.scanLine(0))) { + glSupport.deleteTexture(_textureId); + _textureId = 0; + return; } _needUpdateTexture = false; if (_closed) { @@ -622,6 +604,7 @@ private class GLGlyphCache { _drawbuf = null; } } + GLGlyphCacheItem reserveSpace(uint objectId, int width, int height) { GLGlyphCacheItem cacheItem = new GLGlyphCacheItem(this, objectId); if (_closed) @@ -643,10 +626,11 @@ private class GLGlyphCache { if (_nextLine < _currentLine + height + 2) _nextLine = _currentLine + height + 2; if (!_drawbuf) { - _drawbuf = new GrayDrawBuf(_tdx, _tdy); + _drawbuf = new ColorDrawBuf(_tdx, _tdy); //_drawbuf.SetBackgroundColor(0x000000); //_drawbuf.SetTextColor(0xFFFFFF); - _drawbuf.fill(0x00000000); + //_drawbuf.fill(0x00000000); + _drawbuf.fill(0xFF000000); } _x += width + 1; _needUpdateTexture = true; @@ -662,7 +646,8 @@ private class GLGlyphCache { GLGlyphCacheItem cacheItem = reserveSpace(glyph.id, glyph.correctedBlackBoxX, glyph.blackBoxY); if (cacheItem is null) return null; - _drawbuf.drawGlyph(cacheItem._rc.left, cacheItem._rc.top, glyph, 0xFFFFFF); + //_drawbuf.drawGlyph(cacheItem._rc.left, cacheItem._rc.top, glyph, 0xFFFFFF); + _drawbuf.drawGlyphToTexture(cacheItem._rc.left, cacheItem._rc.top, glyph); _needUpdateTexture = true; return cacheItem; } @@ -697,7 +682,8 @@ private class GLGlyphCache { } if (!dstrc.empty) { //Log.d("drawing glyph with color ", color); - glSupport.drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, false); + glSupport.drawColorAndTextureGlyphRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, false); + //glSupport.drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, false); } } @@ -706,9 +692,6 @@ private class GLGlyphCache { _closed = true; if (_needUpdateTexture) updateTexture(); - static if (USE_RGBA_TEXTURE_FOR_GLYPHS) { - _rgbaBuffer = null; - } } } diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index bfef4498..6ab8f6b4 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -416,6 +416,116 @@ class TextureProgram : SolidFillProgram { } } +class FontProgram : SolidFillProgram { + @property override string vertexSource() { + return + "attribute " ~ HIGHP ~ " vec4 vertex;\n" + "attribute " ~ LOWP ~ " vec4 colAttr;\n" + "attribute " ~ MEDIUMP ~ " vec4 texCoord;\n" + "varying " ~ LOWP ~ " vec4 col;\n" + "varying " ~ MEDIUMP ~ " vec4 texc;\n" + "uniform " ~ MEDIUMP ~ " mat4 matrix;\n" + "void main(void)\n" + "{\n" + " gl_Position = matrix * vertex;\n" + " col = colAttr;\n" + " texc = texCoord;\n" + "}\n"; + + } + @property override string fragmentSource() { + return + "uniform sampler2D texture;\n" + "varying " ~ LOWP ~ " vec4 col;\n" + "varying " ~ MEDIUMP ~ " vec4 texc;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(texture, texc.st) * col;\n" + "}\n"; + } + + GLint texCoordLocation; + override bool initLocations() { + bool res = super.initLocations(); + texCoordLocation = glGetAttribLocation(program, "texCoord"); + return res && texCoordLocation >= 0; + } + + bool execute(float[] vertices, float[] texcoords, float[] colors, uint textureId, bool linear) { + if (error) + return false; + if (!initialized) + if (!compile()) + return false; + beforeExecute(); + glActiveTexture(GL_TEXTURE0); + checkError("glActiveTexture GL_TEXTURE0"); + glBindTexture(GL_TEXTURE_2D, textureId); + checkError("glBindTexture"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); + checkError("drawColorAndTextureRect - glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); + checkError("drawColorAndTextureRect - glTexParameteri"); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + + colors.length * colors[0].sizeof + + texcoords.length * texcoords[0].sizeof, + null, + GL_STREAM_DRAW); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + vertices.length * vertices[0].sizeof, + vertices.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof, + colors.length * colors[0].sizeof, + colors.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof, + texcoords.length * texcoords[0].sizeof, + texcoords.ptr); + + glEnableVertexAttribArray(vertexLocation); + glEnableVertexAttribArray(colAttrLocation); + glEnableVertexAttribArray(texCoordLocation); + + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof)); + glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof)); + + glDrawArrays(GL_TRIANGLES, 0, 6); + checkError("glDrawArrays"); + + glDisableVertexAttribArray(vertexLocation); + glDisableVertexAttribArray(colAttrLocation); + glDisableVertexAttribArray(texCoordLocation); + + afterExecute(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vbo); + + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); + + glBindTexture(GL_TEXTURE_2D, 0); + checkError("glBindTexture"); + return true; + } +} + __gshared GLSupport _glSupport; @property GLSupport glSupport() { if (!_glSupport) { @@ -432,9 +542,10 @@ class GLSupport { TextureProgram _textureProgram; SolidFillProgram _solidFillProgram; + FontProgram _fontProgram; @property bool valid() { - return _textureProgram && _solidFillProgram; + return _textureProgram && _solidFillProgram && _fontProgram; } bool initShaders() { @@ -443,6 +554,11 @@ class GLSupport { if (!_textureProgram.compile()) return false; } + if (_fontProgram is null) { + _fontProgram = new FontProgram(); + if (!_fontProgram.compile()) + return false; + } if (_solidFillProgram is null) { _solidFillProgram = new SolidFillProgram(); if (!_solidFillProgram.compile()) @@ -458,6 +574,10 @@ class GLSupport { destroy(_textureProgram); _textureProgram = null; } + if (_fontProgram !is null) { + destroy(_fontProgram); + _fontProgram = null; + } if (_solidFillProgram !is null) { destroy(_solidFillProgram); _solidFillProgram = null; @@ -522,6 +642,40 @@ class GLSupport { Log.e("No program"); } + void drawColorAndTextureGlyphRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color, bool linear) { + //Log.v("drawColorAndTextureRect tx=", textureId, " src=", srcrc, " dst=", dstrc); + drawColorAndTextureGlyphRect(textureId, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear); + } + + void drawColorAndTextureGlyphRect(uint textureId, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) { + float[6*4] colors; + LVGLFillColor(color, colors.ptr, 6); + float dstx0 = cast(float)xx; + float dsty0 = cast(float)(bufferDy - (yy)); + float dstx1 = cast(float)(xx + dx); + float dsty1 = cast(float)(bufferDy - (yy + dy)); + + // don't flip for framebuffer + if (currentFramebufferId) { + dsty0 = cast(float)((yy)); + dsty1 = cast(float)((yy + dy)); + } + + float srcx0 = srcx / cast(float)tdx; + float srcy0 = srcy / cast(float)tdy; + float srcx1 = (srcx + srcdx) / cast(float)tdx; + float srcy1 = (srcy + srcdy) / cast(float)tdy; + float[3 * 6] vertices = [dstx0,dsty0,Z_2D, + dstx0,dsty1,Z_2D, + dstx1,dsty1,Z_2D, + dstx0,dsty0,Z_2D, + dstx1,dsty1,Z_2D, + dstx1,dsty0,Z_2D]; + float[2 * 6] texcoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy1, srcx0,srcy0, srcx1,srcy1, srcx1,srcy0]; + _fontProgram.execute(vertices, texcoords, colors, textureId, linear); + //drawColorAndTextureRect(vertices, texcoords, colors, textureId, linear); + } + void drawColorAndTextureRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color, bool linear) { //Log.v("drawColorAndTextureRect tx=", textureId, " src=", srcrc, " dst=", dstrc); drawColorAndTextureRect(textureId, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear);