Using OpenGL
Mike Parker via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Sep 3 09:01:34 PDT 2016
On Saturday, 3 September 2016 at 12:40:58 UTC, Darren wrote:
>
> I went through another tutorial. Changed the source code and
> left out the shaders. I get another coloured background but
> still no triangle. I have a feeling that
>
> glBufferData(GL_ARRAY_BUFFER,
> cast(int)g_vertex_buffer_data.sizeof,
> cast(void*)g_vertex_buffer_data,
> GL_STATIC_DRAW);
Your vertices array is declared as a dynamic array. That means
vertices.sizeof gives you the size of the *array reference*, not
the data it contains. For a static array, you get the cumulative
size of the data. See my changes in the code below.
> (In the first line, glBufferData wants an int, and .sizeof
> returns a uint, apparently.)
That's irrelevant in this case. But sizeof is size_t, which is
uint on 32-bit systems and long on 64-bit systems.
>
> I'm sure there's something simple I'm missing but I just don't
> have the experience to recognise it.
The following compiles, runs, and shows the triangle. It's the
code you posted above with the corrected call to glBufferData
along with more D style (as I would write it anyway) and less C.
Comments are inline. Probably best if you copy and paste it into
an editor.
```
import std.stdio,
std.format;
import derelict.glfw3.glfw3;
import derelict.opengl3.gl3;
// Match the Derelict decleration of GLFW callbacks
//
https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/types.d#L319
extern(C) nothrow {
// Setting an error handler will let you get better error
messages from GLFW
// when something fails.
//
http://www.glfw.org/docs/latest/intro_guide.html#error_handling
void onError(int error, const(char)* msg) {
import std.conv : to;
try {
// The callback is nothrow, but format is not, so the
// try...catch
errMsg = format("GLFW Error #%s: %s", error,
to!string(msg));
}
catch(Exception e) {}
}
void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mode) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
// This will save the error message from the callback
private auto errMsg = "No Error";
// Use manifest constants rather than const
// https://dlang.org/spec/enum.html#manifest_constants
enum WIDTH = 800;
enum HEIGHT = 600;
// Rather than using multiple string literals with manual
newlines, use
// WYSIWYG strings as manifest constants. Looks cleaner (but
requires an
// extra step when calling glShaderSource).
enum vertexShaderSource =
`#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}`;
enum fragmentShaderSource =
`#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}`;
void main()
{
DerelictGLFW3.load();
DerelictGL3.load();
// Set the error callback before calling glfwInit so that a
useful message
// can be reported on failure
glfwSetErrorCallback(&onError);
// Always check for failure
if(!glfwInit()) throw new Exception("Failed to init GLFW: " ~
errMsg);
// Ensure that glfwTerminate is called even when an exception
is thrown
scope(exit) glfwTerminate();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Optonal: Remove deprecated functionality
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Always check for failure
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT,
"LearnOpenGL", null, null);
if(!window) throw new Exception("Failed to create window");
glfwMakeContextCurrent(window);
DerelictGL3.reload();
glfwSetKeyCallback(window, &key_callback);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Because I switched the shader source to D strings, a
slight adjustment
// is needed here:
const(char)* srcPtr = vertexShaderSource.ptr;
glShaderSource(vertexShader, 1, &srcPtr, null);
glCompileShader(vertexShader);
GLint result;
// Use dynamic arrays for the info logs so that you can always
// ensure you have enough room. And throw exceptions on
failure.
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &result);
auto infoLog = new char[](result);
glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);
throw new Exception(format("Failed to compile vertex
shader:\n\t%s", infoLog));
}
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
srcPtr = fragmentShaderSource.ptr;
glShaderSource(fragmentShader, 1, &srcPtr, null);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &result);
auto infoLog = new char[](result);
glGetShaderInfoLog(vertexShader, 512, null, infoLog.ptr);
throw new Exception(format("Failed to compile fragment
shader:\n\t%s", infoLog));
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &result);
auto infoLog = new char[](result);
glGetProgramInfoLog(shaderProgram, 512, null,
infoLog.ptr);
throw new Exception(format("Failed to link shader
program:\n\t%s", infoLog));
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
GLfloat[] vertices = [
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
];
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
// Ensure these objects are always deleted on exit
scope(exit) {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// You've declared vertices as a dynamic array, not a static
array, so
// vertices.sizeof is *not* going to give you the result you
want -- it's
// giving you the size of an array reference. To get the size
of the data,
// you need to use vertices.length * float.sizeof (which is
always 4, so you
// could use that instead).
glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof,
vertices.ptr, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 *
GLfloat.sizeof, cast(GLvoid*)0);
glEnableVertexAttribArray(0);
// No need for this in this simple program, where you only
have one VAO and
// one VBO. Just leave them bound. You only need to reset
when you are using
// multiple buffers.
/*
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
*/
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
//glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glBindVertexArray(0);
glfwSwapBuffers(window);
}
}
```
More information about the Digitalmars-d-learn
mailing list