I'm trying to render to a texture using OpenGL ES on an Android phone (using a native plugin/C++). I can set the color of the texture using glClear, and I can clear different sections to different colors using glScissor so I'm fairly sure the issue isn't the framebuffer setup/attachment. Probably there's an issue with the shaders or the vertex data, but I can't see what it is.
Here's the code I've reduced the problem down to:
#include <GLES3/gl31.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3ext.h>
const int32_t WIDTH = 512;
const int32_t HEIGHT = 512;
char vertex_code[] = R"(
#version 300 es
in vec3 VertexPosition;
void main() {
gl_Position = vec4(VertexPosition, 1.0f);
}
)";
char fragment_code[] = R"(
#version 300 es
precision mediump float;
out vec4 FragColor;
void main() {
FragColor = vec4(1.0f, 0.0f, 1.0f, 1.0f);
}
)";
GLuint compile_shader(char* shader_code, GLenum shader_type) {
GLuint shader_id = glCreateShader(shader_type);
glShaderSource(shader_id, 1, &shader_code, nullptr);
glCompileShader(shader_id);
// check shader compilation:
GLint result = 0;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
glDeleteShader(shader_id);
return 0;
}
return shader_id;
}
GLuint create_shader_program(char* vertex_code, char* fragment_code) {
GLuint vertex_id = compile_shader(vertex_code, GL_VERTEX_SHADER);
GLuint fragment_id = compile_shader(fragment_code, GL_FRAGMENT_SHADER);
GLuint shader_program_id = glCreateProgram();
// attach shaders and link:
glAttachShader(shader_program_id, vertex_id);
glAttachShader(shader_program_id, fragment_id);
glLinkProgram(shader_program_id);
// check linking status:
GLint result = 0;
glGetProgramiv(shader_program_id, GL_LINK_STATUS, &result);
if (result == GL_FALSE) {
glDeleteProgram(shader_program_id);
glDeleteShader(vertex_id);
glDeleteShader(fragment_id);
return 0;
}
// delete the shaders now that they're linked:
glDetachShader(shader_program_id, vertex_id);
glDetachShader(shader_program_id, fragment_id);
glDeleteShader(vertex_id);
glDeleteShader(fragment_id);
return shader_program_id;
}
GLuint render_texture() {
// *** create framebuffer and texture to render into
GLuint framebuffer_id;
glGenFramebuffers(1, &framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
GLuint target_texture_id;
glGenTextures(1, &target_texture_id);
glBindTexture(GL_TEXTURE_2D, target_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture_id, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return 0;
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// *** create shader program
GLuint shader_program_id = create_shader_program(vertex_code, fragment_code);
// *** set up quad
float quad[] = {
// positions
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLuint vertex_data_buffer, vertex_array;
glGenVertexArrays(1, &vertex_array);
glGenBuffers(1, &vertex_data_buffer);
glBindVertexArray(vertex_array);
// load vertex data into VBO:
glBindBuffer(GL_ARRAY_BUFFER, vertex_data_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
// position attribute
GLint vertex_pos_location = glGetAttribLocation(shader_program_id, "VertexPosition");
Log("vertex_pos_location %i", vertex_pos_location);
glVertexAttribPointer(vertex_pos_location, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// *** render
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program_id);
glBindVertexArray(vertex_array);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glFinish();
return target_texture_id;
}
When I use this texture elsewhere (within Unity, for what it's worth) I can see that the glClear(GL_COLOR_BUFFER_BIT); call has worked fine, but I'm not seeing the pink colour I'd expect from the basic fragment shader. I've used glGetError() to check for errors after each GL call, and they all seem fine...
Any thoughts on what the issue could be?
Related
I’m struggling with rendering a simple overlay image on top of an already rendered frame. The frame is rendered by a mapbox library which I modified by calling my rendering code just after mapbox renders the frame. I don't know whether the fact that I’m rendering on top of an already rendered frame by mapbox library is important, but maybe it is, so I’m mentioning it here.
The problem seems somewhat related to texturing. The image I try to render is a checkerboard with red and transparent squares. The image bitmap does not have any edges. The image is visible but the edges are also coloured red which is not what I’ve intended and I've already spent a couple of days trying to figure out the reason why these edges are being rendered. I’ll be more than grateful if someone could enlighten me on what I’m doing wrong.
checkerboard with edges. Notice that one edge fades out at the top
namespace mbgl {
void MapOverlayRenderer::arm() { // called when rendering surface has changed
releaseLog("MOR a");
program = createProgram();
vertexBuffer = createVertexBuffer();
indexBuffer = createIndexBuffer();
glGenTextures(1, &texture);
fillTexture();
}
void MapOverlayRenderer::render() { // called just after mapbox frame has rendered
if (!_image.valid()) {
return;
}
glUseProgram(program);
auto positionHandle = glGetAttribLocation(program, "vertexData");
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(positionHandle);
GLint numberOfValuesPerVertex = 4;
GLsizei stride = numberOfValuesPerVertex * sizeof(GLfloat);
glVertexAttribPointer(positionHandle, numberOfValuesPerVertex, GL_FLOAT, false, stride, nullptr);
auto imagePositionHandle = glGetUniformLocation(program, "imagePosition");
GLfloat imagePosition[] = {_leftPadding, _topPadding, _rightPadding, _bottomPadding};
glUniform4fv(imagePositionHandle, 1, imagePosition);
auto imageTextureHandle = glGetUniformLocation(program, "imageTexture");
glUniform1i(imageTextureHandle, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
auto numberOfVertices = 6;
glDrawElements(GL_TRIANGLES, numberOfVertices, GL_UNSIGNED_INT, nullptr);
glDisableVertexAttribArray(positionHandle);
}
void MapOverlayRenderer::setImage(float leftPadding, float topPadding, float rightPadding,
float bottomPadding, PremultipliedImage &&image) { // is called when I pass new image to be rendered
this->_image = std::move(image);
this->_leftPadding = leftPadding;
this->_topPadding = topPadding;
this->_rightPadding = rightPadding;
this->_bottomPadding = bottomPadding;
fillTexture();
}
void MapOverlayRenderer::removeImage() {
this->_leftPadding = 0.0f;
this->_topPadding = 0.0f;
this->_rightPadding = 0.0f;
this->_bottomPadding = 0.0f;
this->_image = PremultipliedImage();
}
GLuint MapOverlayRenderer::createVertexBuffer() {
GLuint result;
glGenBuffers(1, &result);
std::array<GLfloat, 16u> vertices{
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
glBindBuffer(GL_ARRAY_BUFFER, result);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
return result;
}
GLuint MapOverlayRenderer::createIndexBuffer() {
GLuint result;
glGenBuffers(1, &result);
std::array<GLuint, 6u> indices{
0u, 1u, 2u,
2u, 1u, 3u
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, GL_STATIC_DRAW);
return result;
}
GLuint MapOverlayRenderer::createVertexShader() {
auto vertexShaderCode = R"(
precision highp float;
precision highp int;
precision highp sampler2D;
attribute vec4 vertexData;
varying vec2 fullscreenTextureCoordinates;
void main() {
fullscreenTextureCoordinates = vertexData.zw;
gl_Position = vec4(vertexData.xy, 0.0, 1.0);
})";
auto shader = loadShader(GL_VERTEX_SHADER, &vertexShaderCode);
return shader;
}
GLuint MapOverlayRenderer::createFragmentShader() {
auto fragmentShaderCode = R"(
precision highp float;
precision highp int;
precision highp sampler2D;
varying vec2 fullscreenTextureCoordinates;
uniform vec4 imagePosition;
uniform sampler2D imageTexture;
void main() {
float left = imagePosition[0];
float top = imagePosition[1];
float right = imagePosition[2];
float bottom = imagePosition[3];
if (fullscreenTextureCoordinates[0] < left ||
fullscreenTextureCoordinates[0] > right ||
fullscreenTextureCoordinates[1] > 1.0 - top ||
fullscreenTextureCoordinates[1] < 1.0 - bottom) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
} else {
float imageHorizontalCoordinate = (fullscreenTextureCoordinates[0] - left) / (right - left);
float imageVerticalCoordinate = 1.0 - (fullscreenTextureCoordinates[1] - top) / (bottom - top);
vec2 imageTextureCoordinates = vec2(imageHorizontalCoordinate, imageVerticalCoordinate);
gl_FragColor = texture2D(imageTexture, imageTextureCoordinates);
}
})";
auto shader = loadShader(GL_FRAGMENT_SHADER, &fragmentShaderCode);
return shader;
}
GLuint MapOverlayRenderer::createProgram() {
auto vertexShader = createVertexShader();
auto fragmentShader = createFragmentShader();
auto result = glCreateProgram();
glAttachShader(result, vertexShader);
glAttachShader(result, fragmentShader);
glLinkProgram(result);
return result;
}
GLuint MapOverlayRenderer::loadShader(GLenum type, GLchar const *const *shaderCode) {
auto shader = glCreateShader(type);
glShaderSource(shader, 1, shaderCode, nullptr);
glCompileShader(shader);
return shader;
}
void MapOverlayRenderer::fillTexture() {
if (!_image.valid()) {
return;
}
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(_image.size.width), static_cast<GLsizei>(_image.size.height), 0, GL_RGBA,
GL_UNSIGNED_BYTE, _image.data.get());
glGenerateMipmap(GL_TEXTURE_2D);
}
}
The default texture wrapping mode is set to wrap around to the other side of the texture. If any filtering is being done, this will end up sampling pixels from the opposite side of the texture, which explains the thin red border.
To change it to clamping, use this in fillTexture after binding the texture:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
I use FreeType 2.10.2 to render text on Android. Now the bitmap is generated, but there are multiple (4) repeated texts. The picture is as follows:
The rendered text is "G", where the black range is the size of the bitmap, but there is a problem. First, there are four "G" in the bitmap, and then the text "G" does not fill the entire bitmap. I don't know why this is, here is the code:
int initTexture() {
if (init) return -1;
FT_Face face;
FT_Library ft;
FT_Init_FreeType(&ft);
FT_New_Face(ft, fontPathNativeString, 0, &face);
FT_Set_Pixel_Sizes(face, 0, 12 * 12);
FT_ULong wChar = textUnicodeString[0];
FT_Load_Char(face, wChar, FT_LOAD_DEFAULT);
FT_GlyphSlot glyph = face->glyph;
FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
glActiveTexture(GL_TEXTURE0);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
characterTextureID = texture;
GLfloat xpos = 0 + face->glyph->bitmap_left;
GLfloat ypos = 500 + (face->glyph->bitmap.rows - face->glyph->bitmap_top);
GLfloat scale = 5.0f;
GLfloat w = face->glyph->bitmap.width / surfaceWidth * scale;
GLfloat h = face->glyph->bitmap.rows * scale / surfaceHeight;
xpos = (xpos - surfaceWidth) / surfaceWidth;
ypos = (surfaceHeight - ypos) / surfaceHeight;
GLfloat vertices[24] = {
xpos, ypos, 0.0f, 0.0f,
xpos, ypos - h, 0.0f, 1.0f,
xpos + w, ypos - h, 1.0f, 1.0f,
xpos, ypos, 0.0f, 0.0f,
xpos + w, ypos - h, 1.0f, 1.0f,
xpos + w, ypos, 1.0f, 0.0f
};
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_STATIC_DRAW);
FT_Done_Face(face);
FT_Done_FreeType(ft);
init = 1;
return 0;
}
JNIEXPORT void JNICALL
Java_me_excq_androidopengles20demo_chapters11_MyRenderer02_drawFrame(JNIEnv *env, jobject thiz) {
initTexture();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.5f, 1.0f, 0.0f);
glUseProgram(programID);
glUniform3f(glGetUniformLocation(programID, "ourTextColor"), 0.5, 0.8, 0.2);
GLuint vertexHandle = (GLuint) glGetAttribLocation(programID, "vertex");
glEnableVertexAttribArray(vertexHandle);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(vertexHandle, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, characterTextureID);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(vertexHandle);
}
and my vertex shader code is:
attribute vec4 vertex;
varying vec2 outTexCoord;
void main() {
gl_Position = vec4(vertex.xy, 0.0, 1.0);
outTexCoord = vertex.zw;
}
I wrote it according to this tutorial(LearnOpenGL - Text Rendering), but I don’t know why this happens, how can I solve it?
Thank you.
If you closely look at the image, then you can see, that the 4 characters are different:
What seems to be 4 characters, actually is 1 character, splitted in parts.
The issue is caused by the fact, that FT_Render_Glyph generates an image, with 1 channel rather than an RGBA image. Hence the format argument to glTexImage2D hast to be GL_RED, GL_LUMINANCE or GL_ALPHA:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
New to OpenGl and currently working on Android NDK. I am currently getting this error, and can't figure it out. I feel like it's something basic, but I could be wrong. the appRender is run every frame by the java render side.
Error:
E/emuglGLESv2_enc: glDrawArrays: a vertex attribute array is enabled with no data bound
app.cpp:
void appRender(long tick, int width, int height){
const float vertices[] =
{
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
glClear(GL_COLOR_BUFFER_BIT);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Setup colors for each vertex
GLfloat colors[3*4];
for (int v = 0; v < 3; v++){
colors[4*v+0] = 0;
colors[4*v+1] = 1;
colors[4*v+2] = 0;
colors[4*v+3] = 1;
}
// Setup color buffer
GLuint colorBuffer;
glGenBuffers(1, &colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindTexture(GL_TEXTURE_2D, 0);
//textRenderer.RenderTexts(0.5f);
//boxRenderer.RenderBoxes(0.5f);
}
So I found it, and yes, I'm bad.
glVertexAttribPointer(1,3,...) -> glVertexAttribPointer(0,3,...)
I'm having trouble understanding where/how to setup buffers for a native android application in VS 2015. I apologize if this isn't the best way to ask a question. I appreciate any help/insight.
This is what I have so far:
(in engine_init_display)
GLint vShaderLength = vertex_shader.length();
const GLchar* vcode = vertex_shader.c_str();
GLint fShaderLength = fragment_shader.length();
const GLchar* fcode = fragment_shader.c_str();
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vcode, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fcode, NULL);
glCompileShader(fs);
shader_programme = glCreateProgram();
glAttachShader(shader_programme, fs);
glAttachShader(shader_programme, vs);
glLinkProgram(shader_programme);
GLint pos_id = glGetAttribLocation(shader_programme, "position");
//Set vertex data
glUseProgram(shader_programme);
glVertexAttribPointer(pos_id, 0, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(pos_id, //GLuint
3, //GLint size
GL_FLOAT, //GLenum type
GL_FALSE, //GLboolean
(sizeof(float) * 5), //GLsizei stride
points //const GLvoid *pointer
);
glEnableVertexAttribArray(pos_id);
(in engine_draw_frame)
glClearColor(1.0f, 0.41f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
eglSwapBuffers(engine->display, engine->surface);
With this, I get a pink (clear colour) background. I'm not sure what I'm doing wrong.
Here are my vertex data and shaders
float points[] =
{
-0.2f, 0.6f, 0.0f,
0.0f, 1.0f,
0.5f, 0.5f, 0.0f,
1.0f, 1.0f,
-0.5f, -0.5f, 0.0f,
0.0f, 0.0f,
0.5f, -0.5f, 0.0f,
1.0f, 0.0f
};
unsigned short indices[] =
{
0, 2, 1, 2, 3, 1
};
std::string vertex_shader =
"#version 300 es \n"
"in vec3 position; \n"
"void main () { \n"
" gl_Position = vec4 (position, 1.0); \n"
"} \n";
std::string fragment_shader =
"#version 300 es \n"
"precision highp float; \n"
"out vec4 frag_colour; \n"
"void main () { \n"
" frag_colour = vec4 (0.5, 0.0, 0.5, 1.0); \n"
"} \n";
OK, I figured it out. There isn't anything wrong with my shaders or vertex array. The problem was that I didn't specify EGL to create an OpenGLES2 context using EGL_CONTEXT_CLIENT_VERSION.
Check here -> Khronos Specification, page 43 (of pdf) for more info
Sample from specification:
EGLContext eglCreateContext(EGLDisplay dpy,
EGLConfig config, EGLContext share_context,
const EGLint *attrib_list);
if the *attrib_list is left null, the default is OpenGLES1 and shaders will not work in that context.
So, what you need to do is create an attribute list. Something along the lines of:
EGLint contextAttributes[]=
{
EGL_CONTEXT_CLIENT_VERSION,2,
EGL_NONE
}
and pass that to the create context
p_context = eglCreateContext(display, config, NULL, contextAttributes);
Basically, I was too unsure of my ability with vertex buffers that I focused on that for a long time.
I've read that using VAOs is recommended but I don't know how.
I am using the tegra android development pack (which uses OpenGL ES 2.0) and I can't find the methodes glGenVertexArrays and glBindVertexArray. Are VAOs supported in ES 2.0 (without extensions)?
Also I don't understand what the benefit of a VAO is. Currently I compile the shaders and use glBindAttribLocation. After that I define the vertex positions and colors for a triangle and use glVertexAttribPointer. Then I just draw the triangle again and again.
This is the program (without error checks):
static void createProgram() {
// vertex shader
const char* vertexShaderCode = getVertexShaderCode();
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShader);
// fragment shader
const char* fragmentShaderCode = getFragmentShaderCode();
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShader);
// create program
program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
// Dem Programm sagen, unter welchem Index die Daten der Shader Attribute liegen
glBindAttribLocation(program, 1, "in_pos");
glBindAttribLocation(program, 2, "in_color");
glLinkProgram(program);
}
And this is the triangle:
static void loadGeometry() {
GLuint buffers[2];
glGenBuffers(2, buffers);
GLuint vboPosition = buffers[0];
GLuint vboColor = buffers[1];
const int VERTEX_POSITION_BUFFER_SIZE = 12;
const int VERTEX_POSITION_BUFFER_BYTESIZE = sizeof(GLfloat)* VERTEX_POSITION_BUFFER_SIZE;
GLfloat vertexPositionBuffer[VERTEX_POSITION_BUFFER_SIZE] = {
0.0f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f };
glBindBuffer(GL_ARRAY_BUFFER, vboPosition);
glBufferData(GL_ARRAY_BUFFER, VERTEX_POSITION_BUFFER_BYTESIZE, vertexPositionBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Repeat for color...
}
And in the draw call I just do
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);