Related
The following code compiles and runs without errors on linux but gives error
"Error validating program: 'Validation Failed: No vertex array object bound."
on mac OS 10.14.2 (Mojave). Note that the program compiles successfully but has a problem during runtime.
MacBook Pro (Retina, 15-inch, Mid 2015)
I am compiling using g++ -std=c++11 test.cpp -w -framework OpenGL -lglfw -lGLEW -o p
test.cpp
#include <bits/stdc++.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
#define cout(a) cout<<a<<endl
// IDs
GLuint VAO, VBO, VAO2, VBO2, shaderID, uniformModel;
float scale = 1.0, x = 0.0, y = 0.0;
const int numPoints = 50000;
const char* vShader = "shader.vert";
const char* fShader = "shader.frag";
void createSierpinskiGasket()
{
GLfloat points[3 * numPoints];
GLfloat vertices[] = {
-1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f
};
points[0] = 0.25f; points[1] = 0.50f; points[2] = 0.0f;
for(int i = 3; i < numPoints * 3; i += 3)
{
int j = rand() % 3;
points[i] = (points[i - 3] + vertices[j * 3]) / 2.0;
points[i + 1] = (points[i - 2] + vertices[j * 3 + 1]) / 2.0;
points[i + 2] = (points[i - 1] + vertices[j * 3 + 2]) / 2.0;
}
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
glGenBuffers(1, &VBO2);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void createTriangle()
{
GLfloat vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glGenVertexArrays(1, &VAO);
// Subsequent code will be associated with this VAO
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
// GL_ARRAY_BUFFER = Vertex data
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// GL_STATIC_DRAW = Not going to change the data (transforms are OK)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Location, number, type, normalize, stride, offset
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Enable location 0
glEnableVertexAttribArray(0);
// Unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void addShader(const char* shaderIDCode, GLenum shaderIDType)
{
GLuint theShader = glCreateShader(shaderIDType);
const GLchar* theCode[1];
theCode[0] = shaderIDCode;
GLint codeLength[1];
codeLength[0] = strlen(shaderIDCode);
glShaderSource(theShader, 1, theCode, codeLength);
glCompileShader(theShader);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetShaderiv(theShader, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(theShader, sizeof(eLog), NULL, eLog);
printf("Error compiling the %d shaderID: '%s'\n", shaderIDType, eLog);
return;
}
glAttachShader(shaderID, theShader);
}
void compileShader(const char* vertexCode, const char* fragmentCode)
{
// Creating shaderID program
shaderID = glCreateProgram();
if(!shaderID)
{
cout("Error creating shaderID.");
return;
}
addShader(vertexCode, GL_VERTEX_SHADER);
addShader(fragmentCode, GL_FRAGMENT_SHADER);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glLinkProgram(shaderID);
glGetProgramiv(shaderID, GL_LINK_STATUS, &result);
if (!result)
{
glGetProgramInfoLog(shaderID, sizeof(eLog), NULL, eLog);
printf("Error linking program: '%s'\n", eLog);
return;
}
glValidateProgram(shaderID);
glGetProgramiv(shaderID, GL_VALIDATE_STATUS, &result);
if (!result)
{
glGetProgramInfoLog(shaderID, sizeof(eLog), NULL, eLog);
printf("Error validating program: '%s'\n", eLog);
return;
}
}
string readFile(const char* fileLocation)
{
string content;
ifstream fileStream(fileLocation, ios::in);
if (!fileStream.is_open()) {
printf("Failed to read %s! File doesn't exist.", fileLocation);
return "";
}
string line = "";
while (!fileStream.eof())
{
getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
void createShader(const char* vertexLocation, const char* fragmentLocation)
{
string vertexString = readFile(vertexLocation);
string fragmentString = readFile(fragmentLocation);
const char* vertexCode = vertexString.c_str();
const char* fragmentCode = fragmentString.c_str();
compileShader(vertexCode, fragmentCode);
}
void handleKeys(GLFWwindow* window, int key, int code, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, GL_TRUE);
}
if (key == GLFW_KEY_EQUAL && action == GLFW_PRESS)
{
scale += 0.05;
}
if (key == GLFW_KEY_MINUS && action == GLFW_PRESS)
{
scale -= 0.05;
}
if (key == GLFW_KEY_LEFT && action == GLFW_PRESS)
{
x -= 0.05;
}
if (key == GLFW_KEY_RIGHT && action == GLFW_PRESS)
{
x += 0.05;
}
if (key == GLFW_KEY_UP && action == GLFW_PRESS)
{
y += 0.05;
}
if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
{
y -= 0.05;
}
}
int main(void)
{
const GLint WIDTH = 800, HEIGHT = 600;
// Initializing GLFW
if(!glfwInit())
{
cout("GLFW initialization failed.");
glfwTerminate();
return 1;
}
// Setup GLFW window properties
// OpenGL version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Not backwards compatible
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Allow forward compatibility
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* mainWindow = glfwCreateWindow(WIDTH, HEIGHT, "Test Window", NULL, NULL);
if(!mainWindow)
{
cout("GLFW window creation failed.");
glfwTerminate();
return 1;
}
// Get buffer size information
int bufferWidth, bufferHeight;
glfwGetFramebufferSize(mainWindow, &bufferWidth, &bufferHeight);
// Set context for GLEW to use
glfwMakeContextCurrent(mainWindow);
// Allow modern extension features
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
{
cout("GLEW initialization failed.");
glfwDestroyWindow(mainWindow);
glfwTerminate();
return 1;
}
// Setup viewport size
glViewport(0, 0, bufferWidth, bufferHeight);
createTriangle();
createShader(vShader, fShader);
createSierpinskiGasket();
uniformModel = glGetUniformLocation(shaderID, "model");
// Loop until window is closed
while(!glfwWindowShouldClose(mainWindow))
{
// Get and handle user input
glfwPollEvents();
glfwSetKeyCallback(mainWindow, handleKeys);
// Clear window
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Clear colour buffer before next frame
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderID);
glm::mat4 model = glm::mat4();
model = glm::translate(model, glm::vec3(x, y, 0));
//model = glm::rotate(model, rotX * toRadians, glm::vec3(1, 0, 0));
//model = glm::rotate(model, rotY * toRadians, glm::vec3(0, 1, 0));
//model = glm::rotate(model, rotZ * toRadians, glm::vec3(0, 0, 1));
model = glm::scale(model, glm::vec3(scale, scale, scale));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
/*glBindVertexArray(VAO2);
glDrawArrays(GL_POINTS, 0, numPoints);
glBindVertexArray(0);*/
glUseProgram(0);
glfwSwapBuffers(mainWindow);
}
return 0;
}
shader.frag
#version 330
in vec4 vCol;
uniform mat4 model;
out vec4 color;
void main()
{
//color = vec4(1.0f, 1.0f, 0.0f, 1.0f);
color = vec4(vCol.x, vCol.y, 0.5, 1.0);
}
shader.vert
#version 330
layout (location = 0) in vec3 pos;
uniform mat4 model;
out vec4 vCol;
void main()
{
gl_Position = model * vec4(pos.x, pos.y, pos.z, 1.0f);
vCol = vec4(clamp(pos, 0.0f, 1.0f), 1.0f);
}
The message
Validation Failed: No vertex array object bound.
means that the validation of the program could not be performed, because no Vertex Array Object is bound, when glValidateProgram is called
See OpenGL 4.6 API Core Profile Specification; 11.1. VERTEX SHADERS; page 402
[...] As a development aid, use the command
void ValidateProgram( uint program );
to validate the program object program against the current GL state.
This means that the VAO which is should be drawn, by the shader program, has to be bound, before glValidateProgram is called.
Bind the "triangle" VAO, before the shader program is validated:
createTriangle();
glBindVertexArray(VAO);
createShader(vShader, fShader);
I've got an OpenGL context with an FBO and all of my simple drawing operations work fine except for glClear(). I can draw textures and rectangles but glClear() refuses to do anything. glGetError() does not return any error.
Im calling glClear() like this:
glRectd(0, 0, 1024, 1080); // I see the results of this call
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // This does nothing
Note that this code with glClear() works fine on some Macs but not on others so perhaps I've been getting lucky and I need to setup the context or some other setting differently. Any suggestions would be greatly appreciated!
Edit: This has something to do with drawing the texture from the FBO onto another context. After that happens, glClear() stops working.
Edit 2: I now have it reproduced in a small Xcode project and I'm pretty sure I've concluded that everything works on the NVIDIA card but not on the integrated Intel Iris card. I'll post the test code shortly.
Edit 3: Code. I tried to minimize it but there's still a bit of bulk.
//
// On the NVIDIA card, we'll see the video switch between red and green.
// On the Intel Iris, it will get stuck on blue because of "break" code below.
//
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Initialize the view to white
[self clearContext:_view.openGLContext.CGLContextObj toRed:1 green:1 blue:1 alpha:1];
// FBO context
fbo = [[WTFBOContext alloc] initWithWidth:_view.frame.size.width height:_view.frame.size.height shareContext:_view.openGLContext];
// Clear the FBO context (and thus texture) to solid blue
[self clearContext:fbo.oglCtx.CGLContextObj toRed:0 green:0 blue:1 alpha:1];
// These calls "break" the FBO on Intel Iris chips
{
CGLContextObj cgl_ctx = _view.openGLContext.CGLContextObj;
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, fbo.texture);
glBegin(GL_QUADS);
glEnd();
}
__block int r = 0;
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
r = 1 - r;
// Clear the FBO context (and thus texture) to solid red or green
[self clearContext:fbo.oglCtx.CGLContextObj toRed:r green:1 - r blue:0 alpha:1];
[self drawTexture:fbo.texture
fromRect:_view.frame
toContext:_view.openGLContext.CGLContextObj
inRect:_view.frame
flipped:NO
mirrored:NO
blending:NO
withAlpha:1.0];
}];
}
- (void) clearContext:(CGLContextObj) cgl_ctx
toRed:(GLfloat) red
green:(GLfloat) green
blue:(GLfloat) blue
alpha:(GLfloat) alpha
{
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
}
- (void) drawTexture:(GLuint) tname
fromRect:(CGRect) fromRect
toContext:(CGLContextObj) cgl_ctx
inRect:(CGRect) inRect
flipped:(BOOL) flipped
mirrored:(BOOL) mirrored
blending:(BOOL) blending
withAlpha:(GLfloat) withAlpha
{
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tname);
GLint vp[4];
glGetIntegerv(GL_VIEWPORT, vp);
GLdouble left, right, bottom, top;
if (flipped)
{
bottom = vp[1] + vp[3];
top = vp[1];
}
else
{
bottom = vp[1];
top = vp[1] + vp[3];
}
if (mirrored)
{
left = vp[0] + vp[2];
right = vp[0];
}
else
{
left = vp[0];
right = vp[0] + vp[2];
}
glMatrixMode (GL_PROJECTION);
glPushMatrix();
glLoadIdentity ();
glOrtho (left, right, bottom, top, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
GLboolean wasBlending = glIsEnabled(GL_BLEND);
if (blending)
{
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
else
glDisable(GL_BLEND);
// Texures are multiplied by the current color.
glColor4f(withAlpha, withAlpha, withAlpha, withAlpha);
glBegin(GL_QUADS);
glTexCoord2f(fromRect.origin.x, fromRect.origin.y);
glVertex2i(inRect.origin.x, inRect.origin.y);
glTexCoord2f(fromRect.origin.x, fromRect.origin.y + fromRect.size.height);
glVertex2i(inRect.origin.x, inRect.origin.y + inRect.size.height);
glTexCoord2f(fromRect.origin.x + fromRect.size.width, fromRect.origin.y + fromRect.size.height);
glVertex2i(inRect.origin.x + inRect.size.width, inRect.origin.y + inRect.size.height);
glTexCoord2f(fromRect.origin.x + fromRect.size.width, fromRect.origin.y);
glVertex2i(inRect.origin.x + inRect.size.width, inRect.origin.y);
glEnd();
glMatrixMode (GL_PROJECTION);
glPopMatrix();
if (wasBlending)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
glFlush();
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
}
Support Files:
#interface WTFBOContext : NSObject
{
GLuint framebuffer;
}
#property (nonatomic, retain) NSOpenGLContext *oglCtx;
#property (nonatomic, retain) NSOpenGLPixelFormat *oglFmt;
#property (nonatomic) GLuint texture;
#property (nonatomic, readonly) NSUInteger width;
#property (nonatomic, readonly) NSUInteger height;
- (id)initWithWidth:(NSUInteger)width height:(NSUInteger)height shareContext:(NSOpenGLContext *)shareContext;
// We take ownership of the texture
- (void)setTexture:(GLuint)texture;
- (BOOL)isComplete;
#end
#implementation WTFBOContext
- (id)initWithWidth:(NSUInteger)width height:(NSUInteger)height shareContext:(NSOpenGLContext *)shareContext
{
self = [super init];
_width = width;
_height = height;
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFANoRecovery,
NSOpenGLPFAAccelerated,
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
(NSOpenGLPixelFormatAttribute)0};
self.oglFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
self.oglCtx = [[NSOpenGLContext alloc] initWithFormat:self.oglFmt shareContext:shareContext];
CGLContextObj cgl_ctx = self.oglCtx.CGLContextObj;
glGenFramebuffersEXT(1, &framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
[self _makeTexture];
glViewport(0, 0, _width, _height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, _width, 0, _height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
return self;
}
- (void)dealloc
{
CGLContextObj cgl_ctx = self.oglCtx.CGLContextObj;
glDeleteTextures(1, &_texture);
}
- (void)_makeTexture
{
CGLContextObj cgl_ctx = self.oglCtx.CGLContextObj;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
self.texture = texture;
}
- (void)setTexture:(GLuint)tex
{
CGLContextObj cgl_ctx = self.oglCtx.CGLContextObj;
if (_texture > 0)
glDeleteTextures(1, &_texture);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, tex, 0);
if (!self.isComplete)
NSLog(#"glFramebufferTexture2DEXT");
_texture = tex;
}
- (BOOL)isComplete
{
CGLContextObj cgl_ctx = self.oglCtx.CGLContextObj;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
return status == GL_FRAMEBUFFER_COMPLETE_EXT;
}
#end
On iOS works fine but on apportable not, maybe I did something wrong:
GLsizei height = _glview.drawableHeight;
GLsizei width = _glview.drawableWidth;
if (pickingFramebuffer == 0) {
glGenFramebuffers(1, &pickingFramebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, pickingFramebuffer);
if (pickingColorRenderbuffer == 0) {
glGenRenderbuffers(1, &pickingColorRenderbuffer);
}
glBindRenderbuffer(GL_RENDERBUFFER, pickingColorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, pickingColorRenderbuffer);
if (pickingDepthRenderbuffer == 0) {
glGenRenderbuffers(1, &pickingDepthRenderbuffer);
}
glBindRenderbuffer(GL_RENDERBUFFER, pickingDepthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, pickingDepthRenderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"Framebuffer status: %x", (int)status);
}
Log:
Framebuffer status: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
Many thanks!
EDIT:
If I will add to everyone function and opengl directive OES, Framebuffer status will be 0
EDIT 2: OK, it's a bug https://code.google.com/p/apportable/issues/detail?id=3
I'm trying to use NDK to display a bitmap on a full screen. The requirement force me to develop with completely native code. I use Skia to draw a SkBitmap, then display it by Opengl APIs. When my application first time run on a real android device, it always works well. However, after I keep opening and closing the program for several times, it will show a bad image. Why does this happen?
Function engine_init_display is to initialize OpenGL ES and EGL, create bitmap and load texture.
static int engine_init_display(struct engine* engine){
// initialize OpenGL ES and EGL
/*
* Here specify the attributes of the desired configuration.
* Below, we select an EGLConfig with at least 8 bits per color
* component compatible with on-screen windows
*/
const EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, 16,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLint w, h, dummy, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
/* Here, the application chooses the configuration it desires. In this
* sample, we have a very simplified selection process, where we pick
* the first EGLConfig that matches our criteria */
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
* As soon as we picked a EGLConfig, we can safely reconfigure the
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
context = eglCreateContext(display, config, NULL, NULL);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
LOGW("Unable to eglMakeCurrent");
return -1;
}
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
engine->display = display;
engine->context = context;
engine->surface = surface;
engine->width = w;
engine->height = h;
engine->state.angle = 0;
engine->format=format;
// Initialize GL state.
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
SkBitmap bitmap;
GLvoid* bitmapBuffer;
createBitmap(bitmap,bitmapBuffer,width,height);
drawBitmap(bitmap,width,height);
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&sTexture);
glBindTexture(GL_TEXTURE_2D,sTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)bitmapBuffer);
glDisable(GL_TEXTURE_2D);
glFinish();
clearBitmapBuffer(bitmap,bitmapBuffer);
//engine_draw_frame(engine);
return 0;
}
Function render is to display a bitmap
void render(struct engine* engine, int width, int height){
glViewport((engine->width-width)/2, (engine->height-height)/2, width, height);
glClearColorx((GLfixed)(0.1f * 65536),(GLfixed)(0.2f * 65536),(GLfixed)(0.3f * 65536), 0x10000);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D,sTexture);
glFrontFace(GL_CW);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glFlush();
eglSwapBuffers(engine->display, engine->surface);
}
And when the window is being closed, engine_term_display will be called
static void engine_term_display(struct engine* engine) {
if (engine->display != EGL_NO_DISPLAY) {
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (engine->context != EGL_NO_CONTEXT) {
eglDestroyContext(engine->display, engine->context);
}
if (engine->surface != EGL_NO_SURFACE) {
eglDestroySurface(engine->display, engine->surface);
}
eglTerminate(engine->display);
}
engine->display = EGL_NO_DISPLAY;
engine->context = EGL_NO_CONTEXT;
engine->surface = EGL_NO_SURFACE;
}
update
android_main is the main entry point of my native application. I find that when this main function has returned, the whole application is still running.
void android_main(struct android_app* state) {
struct engine engine;
// Make sure glue isn't stripped.
app_dummy();
memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;
ANativeActivity_setWindowFlags(engine.app->activity, AWINDOW_FLAG_FULLSCREEN, 0);
if (state->savedState != NULL) {
// We are starting with a previous saved state; restore from it.
engine.state = *(struct saved_state*)state->savedState;
}
while(1){
int ident;
int events;
struct android_poll_source* source;
if((ident=ALooper_pollAll(-1, NULL, &events,(void**)&source))>=0){
// Process this event.
if (source != NULL) {
source->process(state, source);
}
if (state->destroyRequested != 0) {
engine_term_display(&engine);
return;
}
}
}
}
I fix it by myself, use exit(0) instead of return to finish the activity completely.
if (state->destroyRequested != 0) {
engine_term_display(&engine);
exit(0);
}
I am working on my first OpenGL application using Cocoa (I have used OpenGL ES on the iPhone) and I am having trouble loading a texture from an image file. Here is my texture loading code:
#interface MyOpenGLView : NSOpenGLView
{
GLenum texFormat[ 1 ]; // Format of texture (GL_RGB, GL_RGBA)
NSSize texSize[ 1 ]; // Width and height
GLuint textures[1]; // Storage for one texture
}
- (BOOL) loadBitmap:(NSString *)filename intoIndex:(int)texIndex
{
BOOL success = FALSE;
NSBitmapImageRep *theImage;
int bitsPPixel, bytesPRow;
unsigned char *theImageData;
NSData* imgData = [NSData dataWithContentsOfFile:filename options:NSUncachedRead error:nil];
theImage = [NSBitmapImageRep imageRepWithData:imgData];
if( theImage != nil )
{
bitsPPixel = [theImage bitsPerPixel];
bytesPRow = [theImage bytesPerRow];
if( bitsPPixel == 24 ) // No alpha channel
texFormat[texIndex] = GL_RGB;
else if( bitsPPixel == 32 ) // There is an alpha channel
texFormat[texIndex] = GL_RGBA;
texSize[texIndex].width = [theImage pixelsWide];
texSize[texIndex].height = [theImage pixelsHigh];
if( theImageData != NULL )
{
NSLog(#"Good so far...");
success = TRUE;
// Create the texture
glGenTextures(1, &textures[texIndex]);
NSLog(#"tex: %i", textures[texIndex]);
NSLog(#"%i", glIsTexture(textures[texIndex]));
glPixelStorei(GL_UNPACK_ROW_LENGTH, [theImage pixelsWide]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Typical texture generation using data from the bitmap
glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
NSLog(#"%i", glIsTexture(textures[texIndex]));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texSize[texIndex].width, texSize[texIndex].height, 0, texFormat[texIndex], GL_UNSIGNED_BYTE, [theImage bitmapData]);
NSLog(#"%i", glIsTexture(textures[texIndex]));
}
}
return success;
}
It seems that the glGenTextures() function is not actually creating a texture because textures[0] remains 0. Also, logging glIsTexture(textures[texIndex]) always returns false.
Any suggestions?
Thanks,
Kyle
glGenTextures(1, &textures[texIndex] );
What is your textures definition?
glIsTexture only returns true if the texture is already ready. A name returned by glGenTextures, but not yet associated with a texture by calling glBindTexture, is not the name of a texture.
Check if the glGenTextures is by accident executed between glBegin and glEnd -- that's the only official failure reason.
Also:
Check if the texture is square and has dimensions that are a power of 2.
Although it isn't emphasized anywhere enough iPhone's OpenGL ES implementation requires them to be that way.
OK, I figured it out. It turns out that I was trying to load the textures before I set up my context. Once I put loading textures at the end of the initialization method, it worked fine.
Thanks for the answers.
Kyle