I found this C++ code here. It draws simple rectangle. Works great.
#define GLEW_STATIC
#include <iostream>
#include <glew.h>
#include <freeglut.h>
const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"in vec3 color;"
"out vec3 Color;"
"void main() {"
" Color = color;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSource =
"#version 150 core\n"
"in vec3 Color;"
"out vec4 outColor;"
"void main() {"
" outColor = vec4(Color, 1.0);"
"}";
void Display()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glFlush();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_MULTISAMPLE);
glutInitWindowSize(800, 600);
glutInitContextVersion(4, 4);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("OpenGL");
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit())
exit(1);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 1.0f, 1.0f, 1.0f // Bottom-left
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint ebo;
glGenBuffers(1, &ebo);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
glutDisplayFunc(Display);
glutMainLoop();
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
}
So I decided to rewrite it on C# with OpenTK framework:
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.IO;
namespace OpenTKTest
{
public class Game : GameWindow
{
private Int32 vao;
private Int32 vbo;
private Int32 ebo;
private Int32 vertexShader;
private Int32 fragmentShader;
private Int32 shaderProgram;
public Game() : base()
{
}
[STAThread]
public static void Main()
{
var window = new Game();
window.Run(120, 120);
window.Dispose();
}
protected override void OnLoad(EventArgs e)
{
GL.GenVertexArrays(1, out vao);
GL.BindVertexArray(vao);
GL.GenBuffers(1, out vbo);
var vertices = new Single[]
{
-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 1.0f, 1.0f, 1.0f // Bottom-left
};
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(Single) * vertices.Length), vertices, BufferUsageHint.StaticDraw);
GL.GenBuffers(1, out ebo);
var elements = new Single[]
{
0, 1, 2,
2, 3, 0
};
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(sizeof(UInt32) * elements.Length), elements, BufferUsageHint.StaticDraw);
vertexShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertexShader, File.ReadAllText("vs.glsl"));
GL.CompileShader(vertexShader);
Console.WriteLine(GL.GetShaderInfoLog(vertexShader));
fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragmentShader, File.ReadAllText("fs.glsl"));
GL.CompileShader(fragmentShader);
Console.WriteLine(GL.GetShaderInfoLog(fragmentShader));
shaderProgram = GL.CreateProgram();
GL.AttachShader(shaderProgram, vertexShader);
GL.AttachShader(shaderProgram, fragmentShader);
GL.BindFragDataLocation(shaderProgram, 0, "outColor");
GL.LinkProgram(shaderProgram);
GL.UseProgram(shaderProgram);
var posAttrib = GL.GetAttribLocation(shaderProgram, "position");
GL.EnableVertexAttribArray(posAttrib);
GL.VertexAttribPointer(posAttrib, 2, VertexAttribPointerType.Float, false, 5 * sizeof(Single), IntPtr.Zero);
var colAttrib = GL.GetAttribLocation(shaderProgram, "color");
GL.EnableVertexAttribArray(colAttrib);
GL.VertexAttribPointer(colAttrib, 3, VertexAttribPointerType.Float, false, 5 * sizeof(Single), new IntPtr(2 * sizeof(Single)));
GL.Viewport(0, 0, Width, Height);
}
protected override void OnRenderFrame(FrameEventArgs e)
{
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit);
GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, IntPtr.Zero);
GL.Flush();
SwapBuffers();
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
GL.DeleteProgram(shaderProgram);
GL.DeleteShader(fragmentShader);
GL.DeleteShader(vertexShader);
GL.DeleteBuffers(1, ref ebo);
GL.DeleteBuffers(1, ref vbo);
GL.DeleteVertexArrays(1, ref vao);
}
}
}
Vertex shader:
#version 150 core
in vec2 position;
in vec3 color;
out vec3 Color;
void main()
{
Color = color;
gl_Position = vec4(position, 0.0, 1.0);
}
Fragment shader:
#version 150 core
in vec3 Color;
out vec4 outColor;
void main()
{
outColor = vec4(Color, 1.0);
}
Both sources are almost identical. But in C# version GL.DrawElements function is never called (I found it out while debugging with gDEBugger from gremedy).
Why this code doesn't work in OpenTK?
Related
I'm trying to draw something using OpenGL with VAO and VBO objects. To do that, I just subclassed NSOpenGLView. By default, OpenGL v2.1 was used, so, I put a PixelFormat, wrote code, and solved all the printed errors. For now the app is running well, but nothing is drawing at the window, even glClearColor has no effect. Please, help me to find and solve the problems. My OS is Mac v10.12 with OpenGL v4.1.
MyOpenGLView.m, part 1:
#import "MyOpenGLView.h"
#include <OpenGL/gl3.h>
#include "error.h"
static const char *vertexShaderSource =
"#version 410\n"
"in vec3 posAttr;\n"
"in vec3 colAttr;\n"
"out vec3 col;\n"
"void main() {\n"
" col = colAttr;\n"
" gl_Position.xyz = posAttr;\n"
" gl_Position.w = 1.0;\n"
" col = colAttr;\n"
"}\n";
static const char *fragmentShaderSource =
"#version 410\n"
"in vec3 col;\n"
"out vec4 color;\n"
"void main() {\n"
" color.rgb = col;\n"
" color.a = 1.0;\n"
//" color = vec4(1,1,1,1);\n"
"}\n";
// Shader properties
GLuint m_posAttr;
GLuint m_colAttr;
GLuint program;
// Arrays of positions and colors
float fTriangle[9];
float fTriangleColor[9];
// Low-level VBOs and VBAs
GLuint uiVBO[2];
GLuint uiVAO[1];
GLuint makeShader(GLenum type, const char *source) {
GLuint shader;
shader = glCreateShader(type);
GetError();
glShaderSource(shader, 1, &source, NULL);
GetError();
glCompileShader(shader);
GetError();
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
GetError();
if (logLength > 0) {
GLchar *log = malloc((size_t)logLength);
glGetShaderInfoLog(shader, logLength, &logLength, log);
GetError();
NSLog(#"Shader compilation failed with error:\n%s", log);
free(log);
}
#endif
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
GetError();
if (0 == status) {
glDeleteShader(shader);
GetError();
NSLog(#"Shader compilation failed from code!");
assert(0);
}
return shader;
}
MyOpenGLView.m, part 2:
//// General staff
#implementation MyOpenGLView
- (void)awakeFromNib {
// Positions and colors of figures
fTriangle[0] = -0.4f; fTriangle[1] = 0.1f; fTriangle[2] = 0.0f;
fTriangle[3] = 0.4f; fTriangle[4] = 0.1f; fTriangle[5] = 0.0f;
fTriangle[6] = 0.0f; fTriangle[7] = 0.7f; fTriangle[8] = 0.0f;
fTriangleColor[0] = 1.0f; fTriangleColor[1] = 0.0f; fTriangleColor[2] = 0.0f;
fTriangleColor[3] = 0.0f; fTriangleColor[4] = 1.0f; fTriangleColor[5] = 0.0f;
fTriangleColor[6] = 0.0f; fTriangleColor[7] = 0.0f; fTriangleColor[8] = 1.0f;
NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAOpenGLProfile,
NSOpenGLProfileVersion4_1Core,
0
};
NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if (!pf) {
NSLog(#"No OpenGL pixel format");
}
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
[self setPixelFormat:pf];
[self setOpenGLContext:context];
NSLog(#"%s", glGetString(GL_VERSION));
GetError();
GLuint vertexShader = makeShader(GL_VERTEX_SHADER, vertexShaderSource);
GLuint fragmentShader = makeShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
program = glCreateProgram();
GetError();
glAttachShader(program, vertexShader);
GetError();
glAttachShader(program, fragmentShader);
GetError();
glLinkProgram(program);
GetError();
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
GetError();
if (0 == status) {
NSLog(#"Failed to link shader program");
assert( 0 );
}
m_posAttr = glGetAttribLocation(program, "posAttr");
GetError();
m_colAttr = glGetAttribLocation(program, "colAttr");
GetError();
glGenVertexArrays(1, &uiVAO[0]);
glGenBuffers(2, &uiVBO[0]);
GetError();
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
GetError();
glBindVertexArray(uiVAO[0]);
GetError();
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[0]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), fTriangle, GL_STATIC_DRAW);
glEnableVertexAttribArray(m_posAttr);
GetError();
glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
GetError();
glBindBuffer(GL_ARRAY_BUFFER, uiVBO[1]);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), fTriangleColor, GL_STATIC_DRAW);
glEnableVertexAttribArray(m_colAttr);
GetError();
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, 0);
GetError();
glDrawArrays(GL_TRIANGLES, 0, 3);
GetError();
glDisableVertexAttribArray(m_posAttr);
glDisableVertexAttribArray(m_colAttr);
glFlush();
GetError();
}
- (void)dealloc {
glDeleteProgram(program);
glDeleteBuffers(2, uiVBO);
glDeleteVertexArrays(1, uiVAO);
GetError();
}
#end
error.h:
//// Prints OpenGL errors
#ifndef __ERROR_H__
#define __ERROR_H__
#include <stdlib.h>
#include <assert.h>
#ifdef DEBUG
#define GetError( )\
{\
for ( GLenum Error = glGetError( ); ( GL_NO_ERROR != Error ); Error = glGetError( ) )\
{\
switch ( Error )\
{\
case GL_INVALID_ENUM: printf( "\n%s\n\n", "GL_INVALID_ENUM" ); assert( 0 ); break;\
case GL_INVALID_VALUE: printf( "\n%s\n\n", "GL_INVALID_VALUE" ); assert( 0 ); break;\
case GL_INVALID_OPERATION: printf( "\n%s\n\n", "GL_INVALID_OPERATION" ); assert( 0 ); break;\
case GL_OUT_OF_MEMORY: printf( "\n%s\n\n", "GL_OUT_OF_MEMORY" ); assert( 0 ); break;\
default: break;\
}\
}\
}
#else
#define GetError( )
#endif /* DEBUG */
#endif /* __ERROR_H__ */
After lots of effort and code's modifications I figured it out: the only real problem was with NSOpenGLPFADoubleBuffer option in NSOpenGLPixelFormatAttribute array. After commenting this option I got the desired output.
To my mind, the reason is that I had 2 output graphical buffers. However, the code was executed a single time, 1st buffer was painted and then swapped. So, the 2nd buffer, which is empty, was drawn.
I'm trying to use OpenCL to draw to a cl_image that I got from a OpenGL texture and then render that texture. The problem is when I run my code on CL_DEVICE_TYPE_CPU it works fine however when I run on CL_DEVICE_TYPE_GPU the texture appears to be some random pixels. I'm new to OpenCL and not sure what's goin on so I'll post code below, also using OpenCL on OSX.
Host Code:
#import "GLView.h"
#import <GLKit/GLKit.h>
#import <OpenCL/OpenCL.h>
#import "kernel.cl.h"
#define WIDTH 500
#define HEIGHT 500
static GLfloat squareVertexData[] =
{
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.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, 1.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
#interface GLView ()
#property (strong, nonatomic) GLKBaseEffect *effect;
#property (nonatomic) GLuint vertexArray;
#property (nonatomic) GLuint vertexBuffer;
#property (nonatomic) GLuint tex;
#property (nonatomic) cl_image clImage;
#property (nonatomic) dispatch_queue_t queue;
#end
#implementation GLView
#pragma mark - Lifecycle methods
- (void)awakeFromNib
{
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAOpenGLProfile,
NSOpenGLProfileVersion3_2Core,
NSOpenGLPFAColorSize, 8,
NSOpenGLPFAAlphaSize, 8,
0
};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
[self setPixelFormat:pixelFormat];
NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
[self setOpenGLContext:context];
}
- (void)dealloc
{
[self.openGLContext makeCurrentContext];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArrays(1, &_vertexArray);
glDeleteTextures(1, &_tex);
gcl_release_image(self.clImage);
}
#pragma mark - NSOpenGLView methods
- (void)prepareOpenGL
{
GLint swapInterval = 1;
[self.openGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
glGenVertexArrays(1, &_vertexArray);
glBindVertexArray(self.vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertexData), squareVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 20, (char *)NULL + (0));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 20, (char *)NULL + (12));
glBindVertexArray(0);
self.effect = [[GLKBaseEffect alloc] init];
self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
glGenTextures(1, &_tex);
glBindTexture(GL_TEXTURE_2D, self.tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
self.effect.texture2d0.name = self.tex;
CGLShareGroupObj sharegroup = CGLGetShareGroup(self.openGLContext.CGLContextObj);
gcl_gl_set_sharegroup(sharegroup);
self.clImage = gcl_gl_create_image_from_texture(GL_TEXTURE_2D, 0, self.tex);
self.queue = gcl_create_dispatch_queue(CL_DEVICE_TYPE_GPU, NULL);
dispatch_sync(self.queue, ^{
cl_ndrange range = {
2,
{ 0 },
{ WIDTH, HEIGHT },
{ 0 }
};
mykernel_kernel(&range, self.clImage);
});
glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(self.vertexArray);
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
[self.openGLContext flushBuffer];
}
#end
Kernel Code:
kernel void mykernel(write_only image2d_t image)
{
size_t x = get_global_id(0);
size_t y = get_global_id(1);
uint4 color;
color.x = 255;
color.w = 255;
write_imageui(image, (int2) (x,y), color);
}
I’m not clear why you’re asking for:
NSOpenGLPFAColorSize, 8,
This seems like not a lot of color. Possibly it’d work better if you ask for 32-bits (8 per pixel, plus alpha at end?):
NSOpenGLPFAColorSize, 32,
That’s the default created by Scene Kit, anyhow.
I am trying to get my texture to show up in a basic OpenGL view (subclass of UIView), but no matter which texture I use, it shows up black. The code for my view is as follows:
#implementation SymGLView
typedef struct {
float Position[3];
float Color[4];
float TexCoord[2];
} Vertex;
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}, {0, 0}},
{{1, 1, 0}, {0, 1, 0, 1}, {0, 1}},
{{-1, 1, 0}, {0, 0, 1, 1}, {1, 1}},
{{-1, -1, 0}, {0, 0, 0, 1}, {1, 0}}
};
const GLubyte Indices[] = {
0, 1, 2,
2, 3, 0
};
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (void)setupLayer {
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;
}
- (void)setupContext {
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(#"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
if (![EAGLContext setCurrentContext:_context]) {
NSLog(#"Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
- (void)setupDepthBuffer {
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);
}
- (void)setupFrameBuffer {
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}
- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:#"glsl"];
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(#"Error loading shader: %#", error.localizedDescription);
exit(1);
}
GLuint shaderHandle = glCreateShader(shaderType);
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = [shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
glCompileShader(shaderHandle);
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
return shaderHandle;
}
- (void)compileShaders {
GLuint vertexShader = [self compileShader:#"SimpleVertex" withType:GL_VERTEX_SHADER];
GLuint fragmentShader = [self compileShader:#"SimpleFragment" withType:GL_FRAGMENT_SHADER];
GLuint programHandle = glCreateProgram();
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glLinkProgram(programHandle);
GLint linkSuccess;
glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
glUseProgram(programHandle);
_positionSlot = glGetAttribLocation(programHandle, "Position");
_colorSlot = glGetAttribLocation(programHandle, "SourceColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
_modelViewUniform = glGetUniformLocation(programHandle, "Modelview");
_texCoordSlot = glGetAttribLocation(programHandle, "TexCoordIn");
glEnableVertexAttribArray(_texCoordSlot);
_textureUniform = glGetUniformLocation(programHandle, "Texture");
}
- (void)setupVBOs {
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)render {
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,
sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _floorTexture);
glUniform1i(_textureUniform, 0);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),
GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
- (GLuint)setupTexture:(NSString *)fileName {
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage) {
NSLog(#"Failed to load image %#", fileName);
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
[self setupContext];
[self setupDepthBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self compileShaders];
[self setupVBOs];
[self render];
}
_floorTexture = [self setupTexture:#"tile_floor.png"];
return self;
}
#end
Vertex shader:
attribute vec4 Position;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
Fragment shader:
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = texture2D(Texture, TexCoordOut);
}
I can create a gradient by changing the values for gl_FragColor, but I have tried several different textures and am at a loss.
This could be depending on the fact that your textures are not power of 2 (i.e. 512X512)
Some OpenGL drivers react in weird ways to this, some others just perform a rescaling of the textures to the nearest power of 2 size.
From OpenGL gold book you can find the below:
You can find a quite good explanation in the OpenGL Gold Book, the OpenGL ES 2.0:
In OpenGL ES 2.0, textures can have non-power-of-two (npot)
dimensions. In other words, the width and height do not need to be a
power of two. However, OpenGL ES 2.0 does have a restriction on the
wrap modes that can be used if the texture dimensions are not power of
two. That is, for npot textures, the wrap mode can only be
GL_CLAMP_TO_EDGE and the minifica- tion filter can only be GL_NEAREST
or GL_LINEAR (in other words, not mip- mapped). The extension
GL_OES_texture_npot relaxes these restrictions and allows wrap modes
of GL_REPEAT and GL_MIRRORED_REPEAT and also allows npot textures to
be mipmapped with the full set of minification filters.
I hope this helps.
Cheers
I need to draw small circles on a frame and make them to disappear after few frames (fading out). How can I achieve this with OpenGL ES?
This is what I have so far, the code to draw the circle in a frame:
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat vertices[720];
for (int i = 0; i < 720; i += 2) {
vertices[i] = (cos(DEGREES_TO_RADIANS(i)) * 1);
vertices[i+1] = (sin(DEGREES_TO_RADIANS(i)) * 1);
}
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
What I don't understand is how to keep track of the same circle and fade it in the successive frames.
Thanks
You will need to re-render all objects (circles) on every frame. So you need to keep around a data structure which holds the information about the circles (probably their center, radius, and opacity would be sufficient). Something like this:
typedef struct Circle {
NSPoint center;
float radius;
float opacity;
} Circle;
Circle allCircles [ kMaxNumCircles ];
Then, when you go to draw them, you iterate over the array of circles, updating their opacity and then drawing them:
for (int i = 0; i < kMaxNumCircles; i++)
{
allCircles [ i ].opacity -= someDelta;
drawCircle (allCircles [ i ]);
}
The drawCircle() function could just be what you've written above:
void drawCircle(Circle c)
{
GLfloat vertices[720];
for (int i = 0; i < 720; i += 2) {
vertices[i] = (cos(DEGREES_TO_RADIANS(i)) * 1) + c.center.x;
vertices[i+1] = (sin(DEGREES_TO_RADIANS(i)) * 1) + c.center.y;
}
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 1.0f, 0.0f, c.opacity);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
}
I'm trying to get the bytes from a RGBA texture in openGL ES. I think I'm trying to imitate glGetTexImage from vanilla openGL. As is right now, the pixels are all nil, from the call to glClear, not the texture data I'm looking for.
This is a method in a category extending SPTexture from Sparrow Framework.
-(NSMutableData *) getPixelsFromTexture
{
GLsizei width = (GLsizei) self.width;
GLsizei height = (GLsizei) self.height;
GLint oldBind = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBind);
glBindTexture(GL_TEXTURE_2D, self.textureID);
GLuint fbo[1];
glGenFramebuffersOES(1, fbo);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, fbo[0]);
GLuint rbo[1];
glGenRenderbuffersOES(1, rbo);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, rbo[0]);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA4_OES, width, height);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, rbo[0]);
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(#"Incomplete FBO");
}
// draw
static float texCoords[8] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
static float vertexCoords[8] = { -1.0f, -1.0f, 1-.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f };
glMatrixMode (GL_PROJECTION);
glPushMatrix();
glLoadIdentity ();
glOrthof(0.0f, self.width, self.height, 0.0f, 0.0f, 1.0f);
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glVertexPointer(2, GL_FLOAT, 0, vertexCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
// end draw
GLsizei count = width * height * 4;
GLubyte * pixels = (GLubyte *)malloc((sizeof(GLubyte) * count));
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glBindTexture(GL_TEXTURE_2D, oldBind);
glDeleteRenderbuffersOES(1, rbo);
glDeleteFramebuffersOES(1, fbo);
return [NSMutableData dataWithBytes:pixels length:count];
}
What am I doing wrong?
So, I was eventually able to solve this using a variation of the code seen here. My code is:
#interface SPRenderTexture (RenderToImage)
- (NSMutableData *)renderToPixelData;
#end
#implementation SPRenderTexture (RenderToImage)
- (NSMutableData *)renderToPixelData
{
__block NSMutableData * pixels = nil;
[self bundleDrawCalls:^()
{
float scale = [SPStage contentScaleFactor];
int width = scale * self.width;
int height = scale * self.height;
int nrOfColorComponents = 4; //RGBA
int rawImageDataLength = width * height * nrOfColorComponents;
GLenum pixelDataFormat = GL_RGBA;
GLenum pixelDataType = GL_UNSIGNED_BYTE;
GLubyte *rawImageDataBuffer = (GLubyte *) malloc(rawImageDataLength);
glReadPixels(0, 0, width, height, pixelDataFormat, pixelDataType, rawImageDataBuffer);
pixels = [[NSMutableData alloc] initWithBytes:rawImageDataBuffer length:rawImageDataLength];
}];
return [pixels autorelease];
}
#end
I hope this will be useful to other people.