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