mirror of https://github.com/buggins/dlangui.git
commit
be19fbca45
|
@ -46,26 +46,12 @@ derelict.util.exception.ShouldThrow gl3MissingSymFunc( string symName ) {
|
|||
return derelict.util.exception.ShouldThrow.No;
|
||||
}
|
||||
|
||||
/* 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",
|
||||
0x0506: "GL_INVALID_FRAMEBUFFER_OPERATION",
|
||||
0x0507: "GL_CONTEXT_LOST"
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient wrapper around glGetError()
|
||||
* Using: checkgl!glFunction(funcParams);
|
||||
* TODO use one of the DEBUG extensions
|
||||
*/
|
||||
/// Using: checkgl!glFunction(funcParams);
|
||||
template checkgl(alias func)
|
||||
{
|
||||
debug auto checkgl(string functionName=__FUNCTION__, int line=__LINE__, Args...)(Args args)
|
||||
|
@ -78,28 +64,43 @@ template checkgl(alias func)
|
|||
bool checkError(string context="", string functionName=__FUNCTION__, int line=__LINE__)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
Log.e("OpenGL error ", errors.get(err, to!string(err)), " at ", functionName, ":", line, " -- ", context);
|
||||
if (err != GL_NO_ERROR) {
|
||||
Log.e("OpenGL error ", glerrorToString(err), " at ", functionName, ":", line, " -- ", context);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
string glerrorToString(in GLenum err) pure nothrow {
|
||||
switch(err) {
|
||||
case 0x0500: return "GL_INVALID_ENUM";
|
||||
case 0x0501: return "GL_INVALID_VALUE";
|
||||
case 0x0502: return "GL_INVALID_OPERATION";
|
||||
case 0x0505: return "GL_OUT_OF_MEMORY";
|
||||
case 0x0506: return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||||
case 0x0507: return "GL_CONTEXT_LOST";
|
||||
case GL_NO_ERROR: return "No GL error";
|
||||
default: return "Unknown GL error: " ~ to!string(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class GLProgram {
|
||||
@property abstract string vertexSource();
|
||||
@property abstract string fragmentSource();
|
||||
private GLuint vertexShader;
|
||||
private GLuint fragmentShader;
|
||||
protected GLuint program;
|
||||
protected bool initialized;
|
||||
protected bool error;
|
||||
|
||||
private GLuint vertexShader;
|
||||
private GLuint fragmentShader;
|
||||
private string glslversion;
|
||||
private int glslversionInt;
|
||||
private char[] glslversionString;
|
||||
this() {
|
||||
}
|
||||
|
||||
private void compatibilityFixes(ref char[] code, GLuint type) {
|
||||
if (glslversionInt < 150) {
|
||||
|
@ -125,7 +126,7 @@ class GLProgram {
|
|||
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);
|
||||
Log.d("compileShader: glsl = ", glslversion, ", type: ", (type == GL_VERTEX_SHADER ? "GL_VERTEX_SHADER" : (type == GL_FRAGMENT_SHADER ? "GL_FRAGMENT_SHADER" : "UNKNOWN")));
|
||||
GLuint shader = glCreateShader(type);
|
||||
const char * psrc = sourceCode.toStringz;
|
||||
glShaderSource(shader, 1, &psrc, null);
|
||||
|
@ -250,20 +251,19 @@ class GLProgram {
|
|||
Log.e("glGetAttribLocation failed for " ~ variableName);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SolidFillProgram : GLProgram {
|
||||
@property override string vertexSource() {
|
||||
return q{
|
||||
in vec4 vertex;
|
||||
in vec4 colAttr;
|
||||
in vec3 vertex_position;
|
||||
in vec4 vertex_color;
|
||||
out vec4 col;
|
||||
uniform mat4 matrix;
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = matrix * vertex;
|
||||
col = colAttr;
|
||||
gl_Position = matrix * vec4(vertex_position, 1);
|
||||
col = vertex_color;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -284,8 +284,8 @@ class SolidFillProgram : GLProgram {
|
|||
protected GLint colAttrLocation;
|
||||
override bool initLocations() {
|
||||
matrixLocation = getUniformLocation("matrix");
|
||||
vertexLocation = getAttribLocation("vertex");
|
||||
colAttrLocation = getAttribLocation("colAttr");
|
||||
vertexLocation = getAttribLocation("vertex_position");
|
||||
colAttrLocation = getAttribLocation("vertex_color");
|
||||
return matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
|
||||
}
|
||||
|
||||
|
@ -358,30 +358,29 @@ class LineProgram : SolidFillProgram {
|
|||
class TextureProgram : SolidFillProgram {
|
||||
@property override string vertexSource() {
|
||||
return q{
|
||||
in vec4 vertex;
|
||||
in vec4 colAttr;
|
||||
in vec4 texCoord;
|
||||
in vec3 vertex_position;
|
||||
in vec4 vertex_color;
|
||||
in vec2 vertex_UV;
|
||||
out vec4 col;
|
||||
out vec4 texc;
|
||||
out vec2 UV;
|
||||
uniform mat4 matrix;
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = matrix * vertex;
|
||||
col = colAttr;
|
||||
texc = texCoord;
|
||||
gl_Position = matrix * vec4(vertex_position, 1);
|
||||
col = vertex_color;
|
||||
UV = vertex_UV;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@property override string fragmentSource() {
|
||||
return q{
|
||||
uniform sampler2D tex;
|
||||
in vec4 col;
|
||||
in vec4 texc;
|
||||
in vec2 UV;
|
||||
out vec4 outColor;
|
||||
void main(void)
|
||||
{
|
||||
outColor = texture(tex, texc.st) * col;
|
||||
outColor = texture(tex, UV) * col;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -389,7 +388,7 @@ class TextureProgram : SolidFillProgram {
|
|||
GLint texCoordLocation;
|
||||
override bool initLocations() {
|
||||
bool res = super.initLocations();
|
||||
texCoordLocation = getAttribLocation("texCoord");
|
||||
texCoordLocation = getAttribLocation("vertex_UV");
|
||||
return res && texCoordLocation >= 0;
|
||||
}
|
||||
|
||||
|
@ -537,8 +536,8 @@ bool initGLSupport(bool legacy = false) {
|
|||
}
|
||||
}
|
||||
|
||||
/// OpenGL suport helper
|
||||
class GLSupport {
|
||||
/// OpenGL support helper
|
||||
final class GLSupport {
|
||||
|
||||
private bool _legacyMode;
|
||||
@property bool legacyMode() { return _legacyMode; }
|
||||
|
@ -551,9 +550,9 @@ class GLSupport {
|
|||
_legacyMode = legacy;
|
||||
}
|
||||
|
||||
TextureProgram _textureProgram;
|
||||
SolidFillProgram _solidFillProgram;
|
||||
LineProgram _lineProgram;
|
||||
TextureProgram _textureProgram;
|
||||
|
||||
@property bool valid() {
|
||||
return _legacyMode || _textureProgram && _solidFillProgram && _lineProgram;
|
||||
|
@ -703,7 +702,7 @@ class GLSupport {
|
|||
drawColorAndTextureRect(texture, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear);
|
||||
}
|
||||
|
||||
void drawColorAndTextureRect(Tex2D texture, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) {
|
||||
private void drawColorAndTextureRect(Tex2D texture, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) {
|
||||
Color[4] colors;
|
||||
FillColor(color, colors);
|
||||
float dstx0 = cast(float)xx;
|
||||
|
@ -758,7 +757,6 @@ class GLSupport {
|
|||
} else {
|
||||
_textureProgram.execute(vertices, cast(float[])colors, texcoords, texture, linear);
|
||||
}
|
||||
//drawColorAndTextureRect(vertices, texcoords, colors, texture, linear);
|
||||
}
|
||||
|
||||
/// call glFlush
|
||||
|
@ -768,7 +766,7 @@ class GLSupport {
|
|||
|
||||
bool setTextureImage(Tex2D texture, int dx, int dy, ubyte * pixels) {
|
||||
checkError("before setTextureImage");
|
||||
texture.setup();
|
||||
texture.bind();
|
||||
checkgl!glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
texture.setSamplerParams(true, true);
|
||||
|
||||
|
@ -778,12 +776,13 @@ class GLSupport {
|
|||
Log.e("Cannot set image for texture");
|
||||
return false;
|
||||
}
|
||||
texture.unbind();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setTextureImageAlpha(Tex2D texture, int dx, int dy, ubyte * pixels) {
|
||||
checkError("before setTextureImageAlpha");
|
||||
texture.setup();
|
||||
texture.bind();
|
||||
checkgl!glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
texture.setSamplerParams(true, true);
|
||||
|
||||
|
@ -821,10 +820,8 @@ class GLSupport {
|
|||
Log.e("glFramebufferTexture2D failed");
|
||||
res = false;
|
||||
}
|
||||
//glClearColor(0.5f, 0, 0, 1);
|
||||
checkgl!glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
checkgl!glClear(GL_COLOR_BUFFER_BIT);
|
||||
//CRLog::trace("CRGLSupportImpl::createFramebuffer %d,%d texture=%d, buffer=%d", dx, dy, textureId, framebufferId);
|
||||
currentFBO = fbo;
|
||||
|
||||
texture.unbind();
|
||||
|
@ -834,7 +831,6 @@ class GLSupport {
|
|||
}
|
||||
|
||||
void deleteFramebuffer(ref FBO fbo) {
|
||||
//CRLog::debug("GLDrawBuf::deleteFramebuffer");
|
||||
if (fbo.ID != 0) {
|
||||
destroy(fbo);
|
||||
}
|
||||
|
@ -842,36 +838,31 @@ class GLSupport {
|
|||
}
|
||||
|
||||
bool bindFramebuffer(FBO fbo) {
|
||||
//CRLog::trace("CRGLSupportImpl::bindFramebuffer(%d)", framebufferId);
|
||||
fbo.bind();
|
||||
currentFBO = fbo;
|
||||
return !checkError("glBindFramebuffer");
|
||||
}
|
||||
|
||||
void clearDepthBuffer() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
/// projection matrix
|
||||
/// current gl buffer width
|
||||
private int bufferDx;
|
||||
/// current gl buffer height
|
||||
private int bufferDy;
|
||||
//private float[16] matrix;
|
||||
private mat4 _projectionMatrix;
|
||||
|
||||
@property ref mat4 projectionMatrix() {
|
||||
return _projectionMatrix;
|
||||
}
|
||||
|
||||
/// clear depth buffer
|
||||
void clearDepthBuffer() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void setOrthoProjection(Rect windowRect, Rect view) {
|
||||
flushGL();
|
||||
bufferDx = windowRect.width;
|
||||
bufferDy = windowRect.height;
|
||||
_projectionMatrix.setOrtho(view.left, view.right, view.top, view.bottom, 0.5f, 50.0f);
|
||||
//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);
|
||||
|
@ -891,7 +882,6 @@ class GLSupport {
|
|||
bufferDx = windowRect.width;
|
||||
bufferDy = windowRect.height;
|
||||
float aspectRatio = cast(float)view.width / cast(float)view.height;
|
||||
//QMatrix4x4_perspective(fieldOfView, aspectRatio, nearPlane, farPlane);
|
||||
_projectionMatrix.setPerspective(fieldOfView, aspectRatio, nearPlane, farPlane);
|
||||
if (_legacyMode) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
@ -908,30 +898,34 @@ class GLSupport {
|
|||
}
|
||||
|
||||
enum GLObjectTypes { Buffer, VertexArray, Texture, Framebuffer };
|
||||
/** RAII OpenGL object template.
|
||||
* Note: on construction it binds itself to the target, and it binds 0 to target on destruction.
|
||||
* All methods (except ctor, dtor, bind(), unbind() and setup()) does not perform binding.
|
||||
*/
|
||||
class GLObject(GLObjectTypes type, GLuint target = 0) {
|
||||
@property auto ID() const { return id; }
|
||||
immutable GLuint ID;
|
||||
//alias ID this; // good, but it confuses destroy()
|
||||
|
||||
private GLuint id;
|
||||
|
||||
this() {
|
||||
mixin("checkgl!glGen" ~ to!string(type) ~ "s(1, &id);");
|
||||
GLuint handle;
|
||||
mixin("checkgl!glGen" ~ to!string(type) ~ "s(1, &handle);");
|
||||
ID = handle;
|
||||
bind();
|
||||
}
|
||||
|
||||
~this() {
|
||||
unbind();
|
||||
mixin("checkgl!glDelete" ~ to!string(type) ~ "s(1, &id);");
|
||||
mixin("checkgl!glDelete" ~ to!string(type) ~ "s(1, &ID);");
|
||||
}
|
||||
|
||||
void bind() {
|
||||
static if(target != 0)
|
||||
mixin("glBind" ~ to!string(type) ~ "(" ~ to!string(target) ~ ", id);");
|
||||
mixin("glBind" ~ to!string(type) ~ "(" ~ to!string(target) ~ ", ID);");
|
||||
else
|
||||
mixin("glBind" ~ to!string(type) ~ "(id);");
|
||||
mixin("glBind" ~ to!string(type) ~ "(ID);");
|
||||
}
|
||||
|
||||
void unbind() {
|
||||
static void unbind() {
|
||||
static if(target != 0)
|
||||
mixin("checkgl!glBind" ~ to!string(type) ~ "(" ~ to!string(target) ~ ", 0);");
|
||||
else
|
||||
|
@ -940,43 +934,43 @@ class GLObject(GLObjectTypes type, GLuint target = 0) {
|
|||
|
||||
static if(type == GLObjectTypes.Buffer)
|
||||
{
|
||||
void fill(float[][] buffs) {
|
||||
int length;
|
||||
foreach(b; buffs)
|
||||
length += b.length;
|
||||
glBufferData(target,
|
||||
length * float.sizeof,
|
||||
null,
|
||||
GL_STREAM_DRAW);
|
||||
int offset;
|
||||
foreach(b; buffs) {
|
||||
glBufferSubData(target,
|
||||
offset,
|
||||
b.length * float.sizeof,
|
||||
b.ptr);
|
||||
offset += b.length * float.sizeof;
|
||||
void fill(float[][] buffs) {
|
||||
int length;
|
||||
foreach(b; buffs)
|
||||
length += b.length;
|
||||
glBufferData(target,
|
||||
length * float.sizeof,
|
||||
null,
|
||||
GL_STREAM_DRAW);
|
||||
int offset;
|
||||
foreach(b; buffs) {
|
||||
glBufferSubData(target,
|
||||
offset,
|
||||
b.length * float.sizeof,
|
||||
b.ptr);
|
||||
offset += b.length * float.sizeof;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static if(type == GLObjectTypes.Texture)
|
||||
{
|
||||
void setSamplerParams(bool linear, bool clamp = false) {
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
checkError("filtering - glTexParameteri");
|
||||
if(clamp) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("clamp - glTexParameteri");
|
||||
void setSamplerParams(bool linear, bool clamp = false) {
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
checkError("filtering - glTexParameteri");
|
||||
if(clamp) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("clamp - glTexParameteri");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup(GLuint binding = 0) {
|
||||
glActiveTexture(GL_TEXTURE0 + binding);
|
||||
glBindTexture(target, id);
|
||||
checkError("setup texture");
|
||||
}
|
||||
void setup(GLuint binding = 0) {
|
||||
glActiveTexture(GL_TEXTURE0 + binding);
|
||||
glBindTexture(target, ID);
|
||||
checkError("setup texture");
|
||||
}
|
||||
}
|
||||
}
|
||||
alias VAO = GLObject!(GLObjectTypes.VertexArray);
|
||||
|
|
Loading…
Reference in New Issue