dlangui/src/dlangui/graphics/glsupport.d

1307 lines
44 KiB
D

// Written in the D programming language.
/**
This module contains OpenGL access layer.
To enable OpenGL support, build with version(USE_OPENGL);
Synopsis:
----
import dlangui.graphics.glsupport;
----
Copyright: Vadim Lopatin, 2014
License: Boost License 1.0
Authors: Vadim Lopatin, coolreader.org@gmail.com
*/
module dlangui.graphics.glsupport;
public import dlangui.core.config;
static if (ENABLE_OPENGL):
import dlangui.core.logger;
import derelict.opengl3.gl3;
import derelict.opengl3.gl;
import dlangui.core.types;
import std.conv;
import std.string;
import std.array;
derelict.util.exception.ShouldThrow gl3MissingSymFunc( string symName ) {
import std.algorithm : equal;
foreach(s; ["glGetError", "glShaderSource", "glCompileShader",
"glGetShaderiv", "glGetShaderInfoLog", "glGetString",
"glCreateProgram", "glUseProgram", "glDeleteProgram",
"glDeleteShader", "glEnable", "glDisable", "glBlendFunc",
"glUniformMatrix4fv", "glGetAttribLocation", "glGetUniformLocation",
"glGenVertexArrays", "glBindVertexArray", "glBufferData",
"glBindBuffer", "glBufferSubData"]) {
if (symName.equal(s)) // Symbol is used
return derelict.util.exception.ShouldThrow.Yes;
}
// Don't throw for unused symbol
return derelict.util.exception.ShouldThrow.No;
}
// utility function to fill 4-float array of vertex colors with converted CR 32bit color
private void LVGLFillColor(uint color, float * buf, int count) {
float r = ((color >> 16) & 255) / 255.0f;
float g = ((color >> 8) & 255) / 255.0f;
float b = ((color >> 0) & 255) / 255.0f;
float a = (((color >> 24) & 255) ^ 255) / 255.0f;
for (int i=0; i<count; i++) {
*buf++ = r;
*buf++ = g;
*buf++ = b;
*buf++ = a;
}
}
/* For reporting OpenGL errors, it's nicer to get a human-readable symbolic name for the
* error instead of the numeric form. Derelict's GLenum is just an alias for uint, so we
* can't depend on D's nice toString() for enums.
*/
private immutable(string[int]) errors;
static this() {
errors = [
0x0500: "GL_INVALID_ENUM",
0x0501: "GL_INVALID_VALUE",
0x0502: "GL_INVALID_OPERATION",
0x0505: "GL_OUT_OF_MEMORY"
];
}
/**
* Convenient wrapper around glGetError()
* TODO use one of the DEBUG extensions instead
*/
bool checkError(string context="", string file=__FILE__, int line=__LINE__)
{
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
Log.e("OpenGL error ", err in errors ? errors[err] : to!string(err), " at ", file, ":", line, " -- ", context);
return true;
}
return false;
}
class GLProgram {
@property abstract string vertexSource();
@property abstract string fragmentSource();
protected GLuint vertexShader;
protected GLuint fragmentShader;
protected GLuint program;
protected bool initialized;
protected bool error;
protected string glslversion;
protected int glslversionInt;
protected char[] glslversionString;
this() {
}
private void compatibilityFixes(ref char[] code, GLuint type) {
if (glslversionInt < 150) {
code = replace(code, " texture(", " texture2D(");
code = replace(code, "in ", "");
code = replace(code, "out ", "");
}
}
private GLuint compileShader(string src, GLuint type) {
import core.stdc.stdlib;
import std.string;
char[] sourceCode;
sourceCode ~= "#version ";
sourceCode ~= glslversionString;
sourceCode ~= "\n";
sourceCode ~= src;
compatibilityFixes(sourceCode, type);
Log.d("compileShader glsl=", glslversion, " type:", (type == GL_VERTEX_SHADER ? "GL_VERTEX_SHADER" : (type == GL_FRAGMENT_SHADER ? "GL_FRAGMENT_SHADER" : "UNKNOWN")), " code:\n", sourceCode);
GLuint shader = glCreateShader(type);//GL_VERTEX_SHADER
const char * psrc = sourceCode.toStringz;
GLuint len = cast(uint)sourceCode.length;
glShaderSource(shader, 1, &psrc, cast(const(int)*)&len);
glCompileShader(shader);
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (compiled) {
// compiled successfully
return shader;
} else {
GLint blen = 0;
GLsizei slen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &blen);
if (blen > 1)
{
GLchar[] msg = new GLchar[blen + 1];
GLchar * pmsg = &msg[0];
glGetShaderInfoLog(shader, blen, &slen, pmsg);
Log.d("Shader compilation error: ", fromStringz(pmsg));
}
return 0;
}
}
bool compile() {
glslversion = std.string.fromStringz(glGetString(GL_SHADING_LANGUAGE_VERSION)).dup;
glslversionString.length = 0;
glslversionInt = 0;
foreach(ch; glslversion) {
if (ch >= '0' && ch <= '9') {
glslversionString ~= ch;
glslversionInt = glslversionInt * 10 + (ch - '0');
} else if (ch != '.')
break;
}
vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER);
fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER);
if (!vertexShader || !fragmentShader) {
error = true;
return false;
}
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if (!isLinked) {
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
GLchar[] msg = new GLchar[maxLength + 1];
GLchar * pmsg = &msg[0];
glGetProgramInfoLog(program, maxLength, &maxLength, pmsg);
Log.e("Error while linking program: ", fromStringz(pmsg));
error = true;
return false;
}
Log.d("Program compiled successfully");
//glDetachShader(program, vertexShader);
//glDetachShader(program, fragmentShader);
Log.v("trying glUseProgram with 0");
glUseProgram(0);
Log.v("before useProgram");
glUseProgram(program);
checkError("glUseProgram " ~ to!string(program));
Log.v("after useProgram");
if (!initLocations()) {
Log.e("some of locations were not found");
error = true;
}
initialized = true;
Log.v("Program is initialized successfully");
glUseProgram(0);
checkError("glUseProgram " ~ to!string(program));
return !error;
}
bool initLocations() {
return true;
}
bool bind() {
if (!initialized)
return false;
if (!glIsProgram(program))
Log.e("!glIsProgram(program)");
glUseProgram(program);
checkError("glUseProgram " ~ to!string(program));
return true;
}
void release() {
glUseProgram(0);
checkError("glUseProgram(0)");
}
~this() {
clear();
}
void clear() {
// TODO: cleanup
if (program)
glDeleteProgram(program);
if (vertexShader)
glDeleteShader(vertexShader);
if (fragmentShader)
glDeleteShader(fragmentShader);
program = vertexShader = fragmentShader = 0;
initialized = false;
}
}
immutable string HIGHP = "";
immutable string LOWP = "";
immutable string MEDIUMP = "";
class SolidFillProgram : GLProgram {
@property override string vertexSource() {
return q{
in vec4 vertex;
in vec4 colAttr;
out vec4 col;
uniform mat4 matrix;
void main(void)
{
gl_Position = matrix * vertex;
col = colAttr;
}
};
}
@property override string fragmentSource() {
return q{
in vec4 col;
out vec4 outColor;
void main(void)
{
outColor = col;
}
};
}
void beforeExecute() {
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
checkError("glDisable(GL_CULL_FACE)");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
bind();
//glUniformMatrix4fv(matrixLocation, 1, false, m.value_ptr);
//glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr);
glUniformMatrix4fv(matrixLocation, 1, false, glSupport.qtmatrix.ptr);
checkError("glUniformMatrix4fv");
}
void afterExecute() {
release();
}
protected GLint matrixLocation;
protected GLint vertexLocation;
protected GLint colAttrLocation;
protected GLuint vertexBuffer;
protected GLuint colAttrBuffer;
override bool initLocations() {
bool res = super.initLocations();
//glGenBuffers(1, &vertexBuffer);
//glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 3 * 6, null, GL_DYNAMIC_DRAW);
//glGenBuffers(1, &colAttrBuffer);
//glBindBuffer(GL_ARRAY_BUFFER, colAttrBuffer);
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 4 * 6, null, GL_DYNAMIC_DRAW);
matrixLocation = glGetUniformLocation(program, "matrix");
checkError("glGetUniformLocation matrix");
if (matrixLocation == 0)
Log.e("glGetUniformLocation failed for matrixLocation");
vertexLocation = glGetAttribLocation(program, "vertex");
checkError("glGetAttribLocation vertex");
if (vertexLocation == 0)
Log.e("glGetUniformLocation failed for vertexLocation");
colAttrLocation = glGetAttribLocation(program, "colAttr");
checkError("glGetAttribLocation colAttr");
if (colAttrLocation == 0)
Log.e("glGetUniformLocation failed for colAttrLocation");
return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
}
bool execute(float[] vertices, float[] colors) {
if (error)
return false;
if (!initialized)
if (!compile())
return false;
beforeExecute();
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,
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);
glEnableVertexAttribArray(vertexLocation);
checkError("glEnableVertexAttribArray");
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
checkError("glVertexAttribPointer");
glEnableVertexAttribArray(colAttrLocation);
checkError("glEnableVertexAttribArray");
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*6));
checkError("glVertexAttribPointer");
glDrawArrays(GL_TRIANGLES, 0, 6);
checkError("glDrawArrays");
glDisableVertexAttribArray(vertexLocation);
checkError("glDisableVertexAttribArray");
glDisableVertexAttribArray(colAttrLocation);
checkError("glDisableVertexAttribArray");
afterExecute();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
return true;
}
}
class LineProgram : SolidFillProgram {
override bool execute(float[] vertices, float[] colors) {
if (error)
return false;
if (!initialized)
if (!compile())
return false;
beforeExecute();
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,
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);
glEnableVertexAttribArray(vertexLocation);
checkError("glEnableVertexAttribArray");
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
checkError("glVertexAttribPointer");
glEnableVertexAttribArray(colAttrLocation);
checkError("glEnableVertexAttribArray");
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*2));
checkError("glVertexAttribPointer");
glDrawArrays(GL_LINES, 0, 2);
checkError("glDrawArrays");
glDisableVertexAttribArray(vertexLocation);
checkError("glDisableVertexAttribArray");
glDisableVertexAttribArray(colAttrLocation);
checkError("glDisableVertexAttribArray");
afterExecute();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
return true;
}
}
class TextureProgram : SolidFillProgram {
@property override string vertexSource() {
return q{
in vec4 vertex;
in vec4 colAttr;
in vec4 texCoord;
out vec4 col;
out vec4 texc;
uniform mat4 matrix;
void main(void)
{
gl_Position = matrix * vertex;
col = colAttr;
texc = texCoord;
}
};
}
@property override string fragmentSource() {
return q{
uniform sampler2D tex;
in vec4 col;
in vec4 texc;
out vec4 outColor;
void main(void)
{
outColor = texture(tex, texc.st) * col;
}
};
}
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;
}
}
class FontProgram : SolidFillProgram {
@property override string vertexSource() {
return q{
in vec4 vertex;
in vec4 colAttr;
in vec4 texCoord;
out vec4 col;
out vec4 texc;
uniform mat4 matrix;
void main(void)
{
gl_Position = matrix * vertex;
col = colAttr;
texc = texCoord;
}
};
}
@property override string fragmentSource() {
return q{
uniform sampler2D tex;
in vec4 col;
in vec4 texc;
out vec4 outColor;
void main(void)
{
outColor = texture(tex, texc.st) * col;
}
};
}
GLint texCoordLocation;
override bool initLocations() {
bool res = super.initLocations();
texCoordLocation = glGetAttribLocation(program, "texCoord");
return res && texCoordLocation >= 0;
}
override void beforeExecute() {
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
checkError("glDisable(GL_CULL_FACE)");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_ONE, GL_SRC_COLOR);
//glBlendFunc(GL_ONE, GL_SRC_COLOR);
//glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
//glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_SRC_COLOR);
checkError("glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)");
bind();
glUniformMatrix4fv(matrixLocation, 1, false, glSupport.qtmatrix.ptr);
checkError("glUniformMatrix4fv");
}
override void afterExecute() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
super.afterExecute();
}
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) {
Log.f("GLSupport is not initialized");
assert(false, "GLSupport is not initialized");
}
if (!_glSupport.valid) {
Log.e("GLSupport programs are not initialized");
}
return _glSupport;
}
class GLSupport {
private bool _legacyMode;
@property bool legacyMode() { return _legacyMode; }
this(bool legacy = false) {
_legacyMode = legacy;
}
TextureProgram _textureProgram;
SolidFillProgram _solidFillProgram;
LineProgram _lineProgram;
FontProgram _fontProgram;
@property bool valid() {
return _legacyMode || _textureProgram && _solidFillProgram && _fontProgram && _lineProgram;
}
bool initShaders() {
if (_solidFillProgram is null) {
Log.v("Compiling solid fill program");
_solidFillProgram = new SolidFillProgram();
if (!_solidFillProgram.compile())
return false;
}
if (_lineProgram is null) {
Log.v("Compiling line program");
_lineProgram = new LineProgram();
if (!_lineProgram.compile())
return false;
}
if (_textureProgram is null) {
Log.v("Compiling texture program");
_textureProgram = new TextureProgram();
if (!_textureProgram.compile())
return false;
}
if (_fontProgram is null) {
Log.v("Compiling font program");
_fontProgram = new FontProgram();
if (!_fontProgram.compile())
return false;
}
Log.d("Shaders compiled successfully");
return true;
}
bool uninitShaders() {
Log.d("Uniniting shaders");
if (_solidFillProgram !is null) {
destroy(_solidFillProgram);
_solidFillProgram = null;
}
if (_lineProgram !is null) {
destroy(_lineProgram);
_lineProgram = null;
}
if (_textureProgram !is null) {
destroy(_textureProgram);
_textureProgram = null;
}
if (_fontProgram !is null) {
destroy(_fontProgram);
_fontProgram = null;
}
return true;
}
bool isTexture(uint textureId) {
return glIsTexture(textureId) == GL_TRUE;
}
void setRotation(int x, int y, int rotationAngle) {
/*
this->rotationAngle = rotationAngle;
rotationX = x;
rotationY = y;
if (!currentFramebufferId) {
rotationY = bufferDy - rotationY;
}
QMatrix4x4 matrix2;
matrix2.ortho(0, bufferDx, 0, bufferDy, 0.5f, 5.0f);
if (rotationAngle) {
matrix2.translate(rotationX, rotationY, 0);
matrix2.rotate(rotationAngle, 0, 0, 1);
matrix2.translate(-rotationX, -rotationY, 0);
}
matrix2.copyDataTo(m);
*/
}
void drawLine(Point p1, Point p2, uint color1, uint color2) {
float[2 * 4] colors;
LVGLFillColor(color1, colors.ptr + 4*0, 1);
LVGLFillColor(color2, colors.ptr + 4*1, 1);
float x0 = cast(float)(p1.x);
float y0 = cast(float)(bufferDy-p1.y);
float x1 = cast(float)(p2.x);
float y1 = cast(float)(bufferDy-p2.y);
// don't flip for framebuffer
if (currentFramebufferId) {
y0 = cast(float)(p1.y);
y1 = cast(float)(p2.y);
}
float[3 * 2] vertices = [
x0,y0,Z_2D,
x1,y1,Z_2D
];
if (_lineProgram !is null) {
//Log.d("solid fill: vertices ", vertices, " colors ", colors);
_lineProgram.execute(vertices, colors);
} else
Log.e("No program");
}
static immutable float Z_2D = -2.0f;
void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
float[6 * 4] colors;
LVGLFillColor(color1, colors.ptr + 4*0, 1);
LVGLFillColor(color4, colors.ptr + 4*1, 1);
LVGLFillColor(color3, colors.ptr + 4*2, 1);
LVGLFillColor(color1, colors.ptr + 4*3, 1);
LVGLFillColor(color3, colors.ptr + 4*4, 1);
LVGLFillColor(color2, colors.ptr + 4*5, 1);
float x0 = cast(float)(rc.left);
float y0 = cast(float)(bufferDy-rc.top);
float x1 = cast(float)(rc.right);
float y1 = cast(float)(bufferDy-rc.bottom);
// don't flip for framebuffer
if (currentFramebufferId) {
y0 = cast(float)(rc.top);
y1 = cast(float)(rc.bottom);
}
float[3 * 6] vertices = [
x0,y0,Z_2D,
x0,y1,Z_2D,
x1,y1,Z_2D,
x0,y0,Z_2D,
x1,y1,Z_2D,
x1,y0,Z_2D];
if (_legacyMode) {
glColor4f(1,1,1,1);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
checkError("glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
glEnableClientState(GL_VERTEX_ARRAY);
checkError("glEnableClientState(GL_VERTEX_ARRAY)");
glEnableClientState(GL_COLOR_ARRAY);
checkError("glEnableClientState(GL_COLOR_ARRAY)");
glVertexPointer(3, GL_FLOAT, 0, cast(void*)vertices.ptr);
checkError("glVertexPointer(3, GL_FLOAT, 0, vertices)");
glColorPointer(4, GL_FLOAT, 0, cast(void*)colors);
checkError("glColorPointer(4, GL_FLOAT, 0, colors)");
glDrawArrays(GL_TRIANGLES, 0, 6);
checkError("glDrawArrays(GL_TRIANGLES, 0, 6)");
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
} else {
if (_solidFillProgram !is null) {
//Log.d("solid fill: vertices ", vertices, " colors ", colors);
_solidFillProgram.execute(vertices, colors);
} else
Log.e("No program");
}
}
void drawColorAndTextureGlyphRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color) {
//Log.v("drawColorAndGlyphRect 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);
}
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) {
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];
if (_legacyMode) {
bool linear = dx != srcdx || dy != srcdy;
glDisable(GL_CULL_FACE);
glActiveTexture(GL_TEXTURE0);
checkError("glActiveTexture");
glEnable(GL_TEXTURE_2D);
checkError("glEnable(GL_TEXTURE_2D)");
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");
glColor4f(1,1,1,1);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
glEnableClientState(GL_COLOR_ARRAY);
checkError("glEnableClientState(GL_COLOR_ARRAY)");
glEnableClientState(GL_VERTEX_ARRAY);
checkError("glEnableClientState(GL_VERTEX_ARRAY)");
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
checkError("glEnableClientState(GL_TEXTURE_COORD_ARRAY)");
glVertexPointer(3, GL_FLOAT, 0, cast(void*)vertices.ptr);
checkError("glVertexPointer(3, GL_FLOAT, 0, vertices)");
glTexCoordPointer(2, GL_FLOAT, 0, cast(void*)texcoords.ptr);
checkError("glTexCoordPointer(2, GL_FLOAT, 0, texcoords)");
glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr);
checkError("glColorPointer(4, GL_FLOAT, 0, colors)");
glDrawArrays(GL_TRIANGLES, 0, 6);
checkError("glDrawArrays");
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D);
} else {
_fontProgram.execute(vertices, texcoords, colors, textureId, false);
}
//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);
}
void drawColorAndTextureRect(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];
if (_legacyMode) {
glDisable(GL_CULL_FACE);
glActiveTexture(GL_TEXTURE0);
checkError("glActiveTexture");
glEnable(GL_TEXTURE_2D);
checkError("glEnable(GL_TEXTURE_2D)");
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");
glColor4f(1,1,1,1);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
glEnableClientState(GL_COLOR_ARRAY);
checkError("glEnableClientState(GL_COLOR_ARRAY)");
glEnableClientState(GL_VERTEX_ARRAY);
checkError("glEnableClientState(GL_VERTEX_ARRAY)");
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
checkError("glEnableClientState(GL_TEXTURE_COORD_ARRAY)");
glVertexPointer(3, GL_FLOAT, 0, cast(void*)vertices.ptr);
checkError("glVertexPointer(3, GL_FLOAT, 0, vertices)");
glTexCoordPointer(2, GL_FLOAT, 0, cast(void*)texcoords.ptr);
checkError("glTexCoordPointer(2, GL_FLOAT, 0, texcoords)");
glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr);
checkError("glColorPointer(4, GL_FLOAT, 0, colors)");
glDrawArrays(GL_TRIANGLES, 0, 6);
checkError("glDrawArrays");
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D);
} else {
_textureProgram.execute(vertices, texcoords, colors, textureId, linear);
}
//drawColorAndTextureRect(vertices, texcoords, colors, textureId, linear);
}
/// generate new texture ID
uint genTexture() {
GLuint textureId = 0;
glGenTextures(1, &textureId);
return textureId;
}
/// delete OpenGL texture
void deleteTexture(ref uint textureId) {
if (!textureId)
return;
if (glIsTexture(textureId) != GL_TRUE) {
Log.e("Invalid texture ", textureId);
return;
}
GLuint id = textureId;
glDeleteTextures(1, &id);
checkError("glDeleteTextures");
textureId = 0;
}
/// call glFlush
void flushGL() {
glFlush();
checkError("glFlush");
}
bool setTextureImage(uint textureId, int dx, int dy, ubyte * pixels) {
//checkError("before setTextureImage");
glActiveTexture(GL_TEXTURE0);
checkError("updateTexture - glActiveTexture");
glBindTexture(GL_TEXTURE_2D, 0);
checkError("updateTexture - glBindTexture(0)");
glBindTexture(GL_TEXTURE_2D, textureId);
checkError("updateTexture - glBindTexture");
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
checkError("updateTexture - glPixelStorei");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
checkError("updateTexture - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
checkError("updateTexture - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
checkError("updateTexture - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
checkError("updateTexture - glTexParameteri");
if (!glIsTexture(textureId))
Log.e("second test - invalid texture passed to CRGLSupportImpl::setTextureImage");
// ORIGINAL: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
checkError("updateTexture - glTexImage2D");
if (glGetError() != GL_NO_ERROR) {
Log.e("Cannot set image for texture");
return false;
}
checkError("after setTextureImage");
return true;
}
bool setTextureImageAlpha(uint textureId, int dx, int dy, ubyte * pixels) {
checkError("before setTextureImageAlpha");
glActiveTexture(GL_TEXTURE0);
checkError("updateTexture - glActiveTexture");
glBindTexture(GL_TEXTURE_2D, 0);
checkError("updateTexture - glBindTexture(0)");
glBindTexture(GL_TEXTURE_2D, textureId);
checkError("setTextureImageAlpha - glBindTexture");
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
checkError("setTextureImageAlpha - glPixelStorei");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
checkError("setTextureImageAlpha - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
checkError("setTextureImageAlpha - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
checkError("setTextureImageAlpha - glTexParameteri");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
checkError("setTextureImageAlpha - glTexParameteri");
if (!glIsTexture(textureId))
Log.e("second test: invalid texture passed to CRGLSupportImpl::setTextureImageAlpha");
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, dx, dy, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
checkError("setTextureImageAlpha - glTexImage2D");
if (glGetError() != GL_NO_ERROR) {
Log.e("Cannot set image for texture");
return false;
}
glBindTexture(GL_TEXTURE_2D, 0);
checkError("updateTexture - glBindTexture(0)");
checkError("after setTextureImageAlpha");
return true;
}
private uint currentFramebufferId;
/// returns texture ID for buffer, 0 if failed
bool createFramebuffer(ref uint textureId, ref uint framebufferId, int dx, int dy) {
checkError("before createFramebuffer");
bool res = true;
textureId = framebufferId = 0;
textureId = genTexture();
if (!textureId)
return false;
GLuint fid = 0;
glGenFramebuffers(1, &fid);
if (checkError("createFramebuffer glGenFramebuffersOES")) return false;
framebufferId = fid;
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
if (checkError("createFramebuffer glBindFramebuffer")) return false;
glBindTexture(GL_TEXTURE_2D, textureId);
checkError("glBindTexture(GL_TEXTURE_2D, _textureId)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dx, dy, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
checkError("glTexImage2D");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
checkError("texParameter");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
checkError("texParameter");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
checkError("texParameter");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
checkError("texParameter");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
checkError("glFramebufferTexture2D");
// Always check that our framebuffer is ok
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
Log.e("glFramebufferTexture2D failed");
res = false;
}
checkError("glCheckFramebufferStatus");
//glClearColor(0.5f, 0, 0, 1);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
checkError("glClearColor");
glClear(GL_COLOR_BUFFER_BIT);
checkError("glClear");
checkError("after createFramebuffer");
//CRLog::trace("CRGLSupportImpl::createFramebuffer %d,%d texture=%d, buffer=%d", dx, dy, textureId, framebufferId);
currentFramebufferId = framebufferId;
glBindTexture(GL_TEXTURE_2D, 0);
checkError("createFramebuffer - glBindTexture(0)");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkError("createFramebuffer - glBindFramebuffer(0)");
return res;
}
void deleteFramebuffer(ref uint framebufferId) {
//CRLog::debug("GLDrawBuf::deleteFramebuffer");
if (framebufferId != 0) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkError("deleteFramebuffer - glBindFramebuffer");
GLuint fid = framebufferId;
glDeleteFramebuffers(1, &fid);
checkError("deleteFramebuffer - glDeleteFramebuffer");
}
//CRLog::trace("CRGLSupportImpl::deleteFramebuffer(%d)", framebufferId);
framebufferId = 0;
checkError("after deleteFramebuffer");
currentFramebufferId = 0;
}
bool bindFramebuffer(uint framebufferId) {
//CRLog::trace("CRGLSupportImpl::bindFramebuffer(%d)", framebufferId);
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
currentFramebufferId = framebufferId;
return !checkError("glBindFramebuffer");
}
/// projection matrix
//private mat4 m;
/// current gl buffer width
private int bufferDx;
/// current gl buffer height
private int bufferDy;
//private float[16] matrix;
private float[16] qtmatrix;
void QMatrix4x4_ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
{
// Bail out if the projection volume is zero-sized.
if (left == right || bottom == top || nearPlane == farPlane)
return;
// Construct the projection.
float width = right - left;
float invheight = top - bottom;
float clip = farPlane - nearPlane;
float[4][4] m;
m[0][0] = 2.0f / width;
m[1][0] = 0.0f;
m[2][0] = 0.0f;
m[3][0] = -(left + right) / width;
m[0][1] = 0.0f;
m[1][1] = 2.0f / invheight;
m[2][1] = 0.0f;
m[3][1] = -(top + bottom) / invheight;
m[0][2] = 0.0f;
m[1][2] = 0.0f;
m[2][2] = -2.0f / clip;
m[3][2] = -(nearPlane + farPlane) / clip;
m[0][3] = 0.0f;
m[1][3] = 0.0f;
m[2][3] = 0.0f;
m[3][3] = 1.0f;
for (int y = 0; y < 4; y++)
for (int x = 0; x < 4; x++)
qtmatrix[y * 4 + x] = m[y][x];
}
void QMatrix4x4_perspective(float angle, float aspect, float nearPlane, float farPlane)
{
import std.math;
// Bail out if the projection volume is zero-sized.
if (nearPlane == farPlane || aspect == 0.0f)
return;
// Construct the projection.
float[4][4] m;
float radians = (angle / 2.0f) * PI / 180.0f;
float sine = sin(radians);
if (sine == 0.0f)
return;
float cotan = cos(radians) / sine;
float clip = farPlane - nearPlane;
m[0][0] = cotan / aspect;
m[1][0] = 0.0f;
m[2][0] = 0.0f;
m[3][0] = 0.0f;
m[0][1] = 0.0f;
m[1][1] = cotan;
m[2][1] = 0.0f;
m[3][1] = 0.0f;
m[0][2] = 0.0f;
m[1][2] = 0.0f;
m[2][2] = -(nearPlane + farPlane) / clip;
m[3][2] = -(2.0f * nearPlane * farPlane) / clip;
m[0][3] = 0.0f;
m[1][3] = 0.0f;
m[2][3] = -1.0f;
m[3][3] = 0.0f;
for (int y = 0; y < 4; y++)
for (int x = 0; x < 4; x++)
qtmatrix[y * 4 + x] = m[y][x];
}
void setOrthoProjection(Rect view) {
bufferDx = view.width;
bufferDy = view.height;
QMatrix4x4_ortho(view.left, view.right, view.top, view.bottom, 0.5f, 50.0f);
//myGlOrtho(0, dx, 0, dy, 0.1f, 5.0f);
if (_legacyMode) {
glMatrixMode(GL_PROJECTION);
//glPushMatrix();
//checkError("glPushMatrix");
//glLoadIdentity();
glLoadMatrixf(qtmatrix.ptr);
//glOrthof(0, _dx, 0, _dy, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
//glPushMatrix();
//checkError("glPushMatrix");
glLoadIdentity();
}
glViewport(view.left, view.top, view.right, view.bottom);
checkError("glViewport");
}
void setPerspectiveProjection(float fieldOfView, float aspectRatio, float nearPlane, float farPlane) {
// TODO
}
}