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);