Opengles2 (Racing) Game Development


whynodd

Member
Joined
Sep 20, 2008
Messages
262
Edit: No problem anymore. This thread is now my game development thread. I'm updating it regularly and sometimes I post interesting code sections.


Hello!

I need some serious help with this.
This is where i took most of the code: wiki

Compiled directly on pandora with:
Code:
gcc -o opengles opengles.cpp -lEGL -lGLESv2  -Iusr/include/SDL -Lusr/lib -lSDL -lSDL_image -lstdc++ -DGLES1

My code:
Code:
#ifdef GLES1
	#include <EGL/egl.h>
	#include <GLES2/gl2.h>
	#include <SDL/SDL_syswm.h>
#else
	#include <GL/gl.h>
	#include <SDL/SDL.h>
#endif

#include <iostream>
#include <SDL/SDL.h>
 
 
#ifdef GLES1
	EGLDisplay g_eglDisplay = 0;
	EGLConfig g_eglConfig = 0;
	EGLContext g_eglContext = 0;
	EGLSurface g_eglSurface = 0;
#endif
 
// consts
#define COLOURDEPTH_RED_SIZE  		5
#define COLOURDEPTH_GREEN_SIZE 		6
#define COLOURDEPTH_BLUE_SIZE 		5
#define COLOURDEPTH_DEPTH_SIZE		16
 
#ifdef GLES1
static const EGLint g_configAttribs[] ={
										  EGL_RED_SIZE,      	    COLOURDEPTH_RED_SIZE,
										  EGL_GREEN_SIZE,    	    COLOURDEPTH_GREEN_SIZE,
										  EGL_BLUE_SIZE,     	    COLOURDEPTH_BLUE_SIZE,
										  EGL_DEPTH_SIZE,	    COLOURDEPTH_DEPTH_SIZE,
										  EGL_SURFACE_TYPE,         EGL_WINDOW_BIT,
										  EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES_BIT,
										  //EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE, // fails at eglChoseConfig!
										  EGL_NONE
									   };
#endif
 
unsigned int xRes = 320;
unsigned int yRes = 240;

SDL_Surface* videoSurface = 0;
 
/*===========================================================
Initialise opengl settings. Call straight after SDL_SetVideoMode()
===========================================================*/
 
int initOpenGL()
{
#ifdef GLES1
	// use EGL to initialise GLES
	g_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	if (g_eglDisplay == EGL_NO_DISPLAY)
	{
		printf("Unable to initialise EGL display.\n");
		return 0;
	}
 
	// Initialise egl
	if (!eglInitialize(g_eglDisplay, NULL, NULL))
	{
		printf("Unable to initialise EGL display.\n");
		return 0;
	}
 
	// Find a matching config
	EGLint numConfigsOut = 0;
	if (eglChooseConfig(g_eglDisplay, g_configAttribs, &g_eglConfig, 1, &numConfigsOut) != EGL_TRUE || numConfigsOut == 0)
	{
		fprintf(stderr, "Unable to find appropriate EGL config.\n");
		return 0;
	}
 
	// Get the SDL window handle
	SDL_SysWMinfo sysInfo; //Will hold our Window information
	SDL_VERSION(&sysInfo.version); //Set SDL version
	if(SDL_GetWMInfo(&sysInfo) <= 0) 
	{
		printf("Unable to get window handle");
		return 0;
	}
 
	g_eglSurface = eglCreateWindowSurface(g_eglDisplay, g_eglConfig, (EGLNativeWindowType)sysInfo.info.x11.window, 0);
	if ( g_eglSurface == EGL_NO_SURFACE)
	{
		printf("Unable to create EGL surface!\n");  // <<<<<<------- SPITS THIS OUT
		return 0;
	}
 
	// Bind GLES and create the context
	eglBindAPI(EGL_OPENGL_ES_API);
	//EGLint contextParams[] = {EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE};		// Use GLES version 2.x
	g_eglContext = eglCreateContext(g_eglDisplay, g_eglConfig, EGL_NO_CONTEXT, NULL);
	if (g_eglContext == EGL_NO_CONTEXT)
	{
		printf("Unable to create GLES context!\n");
		return 0;
	}
 
	if (eglMakeCurrent(g_eglDisplay,  g_eglSurface,  g_eglSurface, g_eglContext) == EGL_FALSE)
	{
		printf("Unable to make GLES context current\n");
		return 0;
	}
 
#else
 
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, COLOURDEPTH_RED_SIZE);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, COLOURDEPTH_GREEN_SIZE);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, COLOURDEPTH_BLUE_SIZE);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, COLOURDEPTH_DEPTH_SIZE);
 
#endif
 
	return 1;
}
 
/*======================================================
 * Kill off any opengl specific details
  ====================================================*/
void terminateOpenGL()
{
#ifdef GLES1
	eglMakeCurrent(g_eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
	eglDestroySurface(g_eglDisplay, g_eglSurface);
	eglDestroyContext(g_eglDisplay, g_eglContext);
	g_eglSurface = 0;
	g_eglContext = 0;
	g_eglConfig = 0;
	eglTerminate(g_eglDisplay);
	g_eglDisplay = 0;
#endif
}
 
 
int swapBuffers()
{
#ifdef GLES1
	eglSwapBuffers(g_eglDisplay, g_eglSurface);
#else
	SDL_GL_SwapBuffers();
#endif
}

int initSDL()
{
	// Initialize SDL and the video subsystem
	SDL_Init(SDL_INIT_VIDEO);
	// Set the video mode
	videoSurface = SDL_SetVideoMode(xRes, yRes, 16, SDL_HWSURFACE);//SDL_DOUBLEBUF);
	// Print out some information about the video surface
	if (videoSurface != NULL)
	{
		std::cout << "The current video surface bits per pixel is " << (int)videoSurface->format->BitsPerPixel << std::endl;
	}
	else
	{
		std::cerr << "Video initialization failed: " << SDL_GetError() << std::endl;
		return 0;
	}
	return 1;
}

int terminateSDL()
{
	SDL_Quit();
}


int main( int argc, const char* argv[] )
{
	initSDL();
	initOpenGL();
	SDL_Delay(1000);
	terminateOpenGL();
	terminateSDL();
}

This program fails at creating an EGL surface - so I'm stuck here.
First I noticed that the code from the wiki isn't even runnable at all, incomplete and there are instructions missing on how to actually compile and use this. Perhaps it works in Cpas' OpenGL-Emulator, but not on the real machine.
I find it extremly difficult to find a GLES2 Hello Triangle that compiles and works on my pandora.

I have a couple of questions about some things I don't quite understand:
- Is it nessecary to use SDL?
- What is the concept behind surfaces and contexts?
- Especially contexts, what is it? I dont' get it.. Can't I just give the SGX a pointer to a simple framebuffer?
- What is EGL?
- #include <GLES2/gl2.h> or #include <GLES/gl.h> (I want to use openGLES2, but where should be the difference in initialization?
- Why the hell does one need to write 200(!) lines of code for the initialization and the code for drawing a SINGLE TRIANGLE is still missing?
- Whats the shortest possible way to draw a fullscreen triangle?
- My code above compiles without -lGLESv2. Why? Isn't it needed?

Every F**N (sorry..) time I want to code something, there are millions of dumb things in the way, mostly missing documentation. I know there are tutorials but every "tutor" uses another device or uses cross compilers, uses an OpenGLES-Emulator or some weird libs to do unnessecary things (Or uses and Iphone for GLES!).
I want to do the real stuff, program shaders, a game. Please Devs, write it in the wiki how it really works. A newb has serious problems even if simple things like #include<iostream> are missing in your tutorials! Test your code on the real machine, comment the code like hell and give instructions how to compile it, explain even the simplest lines of code. I can't do it, I'm the newb here. So just hope someone can help me.
 
hi Whynodd,

Whynodd said:
I have a couple of questions about some things I don't quite understand:
- Is it nessecary to use SDL?
no. SDL gives you some extras, which would not be needed if you're after a hello-world GL ES app.

- What is the concept behind surfaces and contexts?
surfaces keep either framebuffers or textures (or both, in the case of render-target textures).

- Especially contexts, what is it? I dont' get it.. Can't I just give the SGX a pointer to a simple framebuffer?
contexts are containers for a single GL client/server state. you need at least one context to be able to do anything with GL. most drawing APIs have the concept of a context, so GL is nothing unique there.

you don't tell SGX where its framebuffer is (it's normally not in your userspace).

- What is EGL?
a framework used to interface a class of drawing APIs (including GL ES) to the native platform; it takes care of surfaces and contexts. you can learn a lot about it from here.

also, i strongly suggest you bookmark this link.

- #include <GLES2/gl2.h> or #include <GLES/gl.h> (I want to use openGLES2, but where should be the difference in initialization?
the differences in EGL initialization between ES1 and ES2 are small. once you have the basics of the EGL API you will not have issues to initialize either.

- Why the hell does one need to write 200(!) lines of code for the initialization and the code for drawing a SINGLE TRIANGLE is still missing?
API authors' choice of abstraction level. if you think that's too low and dirty, you can always write your wrapper on top of EGL.

- Whats the shortest possible way to draw a fullscreen triangle?
i believe there have been a couple of examples, in this very forum too, of drawing simple stuff in either ES1 and ES2 scenarios. perhaps the wiki needs some bringing up to date (i have not checked it recently), but as a word of advice, don't expect to find everything you might need for ES/EGL in the wiki.

- My code above compiles without -lGLESv2. Why? Isn't it needed?
you code above does not make a single ES call, so it gets away with linking vs the wrong (ES2) library. you need to link versus the correct ES1 library (if that's what you plan to use).

Every F**N (sorry..) time I want to code something, there are millions of dumb things in the way, mostly missing documentation. I know there are tutorials but every "tutor" uses another device or uses cross compilers, uses an OpenGLES-Emulator or some weird libs to do unnessecary things (Or uses and Iphone for GLES!).
pandora is quite young an ES dev platform, so most of the things you'd find on internet do not account for the little quirks and tweaks you'd need to have in your pandora code (not that there are that many). the major point of differentiation on the EGL side is that you need to pass your actual X11 Display to the eglGetDisplay(), instead of EGL_DEFAULT_DISPLAY (which is what i suspect stops you from getting the surface).

I want to do the real stuff, program shaders, a game. Please Devs, write it in the wiki how it really works. A newb has serious problems even if simple things like #include<iostream> are missing in your tutorials! Test your code on the real machine, comment the code like hell and give instructions how to compile it, explain even the simplest lines of code. I can't do it, I'm the newb here. So just hope someone can help me.
frustration is part of the learning process - the more complex the subject, the more frustrating the learning curve. if you think that's frustrating now, just wait till you get to the 'real stuff' as you called it ; ) generally, read a lot about the APIs you plan to use (e.g. that link to khronos.org i gave you above), be ready to experiment with code from other platforms which may not work 'out of the box' on pandora, and last but not least, have patience. we all have desired for the proverbial 'do stuff i want' button at one stage or another in our careers. such moments are usually a sign we don't have a mastery in the field yet ; )
 
Last edited by a moderator:
Thanks for your answers.

no. SDL gives you some extras, which would not be needed if you're after a hello-world GL ES app.
In other words, SDL is only used to create the window here? After this, the surface for GL is created on this Window by
eglCreateWindowSurface(g_eglDisplay, g_eglConfig, (EGLNativeWindowType)sysInfo.info.x11.window, 0);
Maybe the initialisation of that SDL window is wrong. Maybe I used the wrong flags in SDL_SetVideoMode. Fullscreen or not double buffered? I've tried several things.

API authors' choice of abstraction level. if you think that's too low and dirty, you can always write your wrapper on top of EGL.
Thats my plan. I'll wrap it away immediately when I got it to work.

i believe there have been a couple of examples, in this very forum too, of drawing simple stuff in either ES1 and ES2 scenarios. perhaps the wiki needs some bringing up to date (i have not checked it recently), but as a word of advice, don't expect to find everything you might need for ES/EGL in the wiki.
Yup, I browsed through the forum and found some examples, but they didn't help me getting working code that helps me to build my own little framework. (I know: Search harder...)

you code above does not make a single ES call, so it gets away with linking vs the wrong (ES2) library. you need to link versus the correct ES1 library (if that's what you plan to use).
I want to use ES2. Messing with shaders will be fun.

the major point of differentiation on the EGL side is that you need to pass your actual X11 Display to the eglGetDisplay(), instead of EGL_DEFAULT_DISPLAY (which is what i suspect stops you from getting the surface).
eglGetDisplay does not generate an error. The error happens later at eglCreateWindowSurface.

frustration is part of the learning process - the more complex the subject, the more frustrating the learning curve. if you think that's frustrating now, just wait till you get to the 'real stuff' as you called it ; ) generally, read a lot about the APIs you plan to use (e.g. that link to khronos.org i gave you above), be ready to experiment with code from other platforms which may not work 'out of the box' on pandora, and last but not least, have patience. we all have desired for the proverbial 'do stuff i want' button at one stage or another in our careers. such moments are usually a sign we don't have a mastery in the field yet ; )
I'm a patient guy, but after 2 days of senseless guessing issues like this are blocking my creativity. I'm full of ideas how to do this and that, I'm already thinking of lightmaps, multitexturing, funky shader thingies, blender obj-exporting, per pixel lighting etc.
I want to make a time trial racing game, obstacle courses and such with realistic physics, very slow and careful driving. I'm not that noob in programming but failing at Hello Worlds is apparently too common in c++, compiling, linking, libhellstuff and OpenGL(ES).
I have already a little engine prototype/framework (normal opengl) on my desktop that I want to run on the pandora, of course I need workingGLES2 for that.
Mockup of the graphical style I'm aiming at:
file.php?id=710.jpg


Every little bit of help is greatly appreciated.
 
Whynodd said:
In other words, SDL is only used to create the window here? After this, the surface for GL is created on this Window by
eglCreateWindowSurface(g_eglDisplay, g_eglConfig, (EGLNativeWindowType)sysInfo.info.x11.window, 0);
Maybe the initialisation of that SDL window is wrong. Maybe I used the wrong flags in SDL_SetVideoMode. Fullscreen or not double buffered? I've tried several things.
generally yes, but i cannot help you with specifics there - i'm not an SDL user.

Yup, I browsed through the forum and found some examples, but they didn't help me getting working code that helps me to build my own little framework. (I know: Search harder...)
are you looking particularly for an SDL+EGL one? because if you're ok with talking directly to X, here's a direct link to ES2 initializing code, known to work on pandora.

I want to use ES2. Messing with shaders will be fun.
i guess your code actual trying to initialize ES1 was just a result from following the wiki example then.

eglGetDisplay does not generate an error. The error happens later at eglCreateWindowSurface.
that does not mean you don't have the wrong display for this window-surface, though. as a rule of thumb, try getting further info with eglGetError() after such failures.

I want to make a time trial racing game, obstacle courses and such with realistic physics, very slow and careful driving. I'm not that noob in programming but failing at Hello Worlds is apparently too common in c++, compiling, linking, libhellstuff and OpenGL(ES).
I have already a little engine prototype/framework (normal opengl) on my desktop that I want to run on the pandora, of course I need working GLES2 for that.
Mockup of the graphical style I'm aiming at:
file.php?id=710.jpg
nice mockup. you may have issues with getting soft self-shadowing on the current set of drivers (no depth textures), but it might be still doable.
 
Last edited by a moderator:
Get the Wakebreaker code:

http://w1xer.at/pandora/

It contains all the bare-bones functionality for setting up 3D and doing a simple playing field, and may well give you the leg-up you need .. at the very least it can provide you with a known working reference for some of your problems.
 
are you looking particularly for an SDL+EGL one? because if you're ok with talking directly to X, here's a direct link to ES2 initializing code, known to work on pandora.
Thx, I'll work through this link and compare it with my code.

that does not mean you don't have the wrong display for this window-surface, though. as a rule of thumb, try getting further info with eglGetError() after such failures.
eglGetError() throws EGL_BAD_NATIVE_WINDOW. Hmm.

nice mockup. you may have issues with getting soft self-shadowing on the current set of drivers (no depth textures), but it might be still doable.
I plan to do the shading like this: A directional bright light (sun) and a dark bluish hemilight + baked ambient occlusion from a grayscale texture. Its just a bit of vector algebra in the fragment shader. Maybe I will bake the direct shadows together with ambient occlusion. Should look nice enough.
 
Ok, thanks guys, took the guts of wavebreaker and now I actually have the most basic (ES1) program. A white deforming triangle. Tomorrow I will try to use ES2 and a X11 fullscreen window instead of this ('cause of remaining glitches on screen after termination and gui elements from desktop flickering) but its a start. Yay!

Code:
gcc -o opengles opengles.cpp -lEGL -lGLES_CM  -Iusr/include/SDL -Lusr/lib -lSDL -lSDL_image -lstdc++ -g -fomit-frame-pointer -mcpu=cortex-a8 -mfpu=neon

Code:
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <SDL/SDL_syswm.h>

#include <linux/matroxfb.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include <iostream>
#include <fstream>

static EGLDisplay	eglDisplay	= 0;
static EGLConfig	eglConfig	= 0;
static EGLSurface	eglSurface	= 0;
static EGLContext	eglContext	= 0;
 
// unsigned int xRes = 320;
// unsigned int yRes = 240;
int vsync         = 0;
int fsaa          = 1;
 
int testEGLError( char* pszLocation )
{
	EGLint iErr = eglGetError();
	if (iErr != EGL_SUCCESS)
	{
		printf("%s failed (%d).\n", pszLocation, iErr);
		return 0;
	}

	return 1;
}
 
 
int initVideoRaw( int w, int h, int vsync, int fsaa )
{
	eglDisplay = eglGetDisplay((NativeDisplayType)0);

	EGLint iMajorVersion, iMinorVersion;
	if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion))
	{
		printf ("Error: eglInitialize() failed!");
		return 0;
	}

	EGLint pi32ConfigAttribs[5];
	int attrib = 0;
	pi32ConfigAttribs[attrib++] = EGL_SURFACE_TYPE;
	pi32ConfigAttribs[attrib++] = EGL_WINDOW_BIT;
	pi32ConfigAttribs[attrib++] = EGL_NONE;
	if ( fsaa )
	{
		pi32ConfigAttribs[attrib++] = EGL_SAMPLE_BUFFERS, 1;
		pi32ConfigAttribs[attrib++] = EGL_SAMPLES, 4;
	}
	pi32ConfigAttribs[attrib++] = EGL_NONE;

	int iConfigs;
	if (!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
	{
		printf ("Error: eglChoseConfig() failed!");
		return 0;
	}

	eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (NativeWindowType)0, NULL);
	if (!testEGLError((char *)"eglCreateWindowSurface"))
	{
		return 0;
	}

	eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
	if (!testEGLError((char *)"eglCreateContext"))
	{
		return 0;
	}

	eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
	if (!testEGLError((char *)"eglMakeCurrent"))
	{
		exit(0);
	}
	return 1;
}

int swapBuffers()
{
	if ( vsync )
	{
		int fd = open( "/dev/fb0" , O_RDWR );
		if( 0 < fd )
		{
			int ret = 0;
			ret = ioctl(fd, FBIO_WAITFORVSYNC, &ret );
			if ( ret != 0 )
			{
				printf ("FBIO_WAITFORVSYNC failed!");
			}
		}
		close(fd);
	}
	eglSwapBuffers( eglDisplay, eglSurface );
	if ( !testEGLError((char *) "eglSwapBuffers" ) )
	{
		return 0;
	}
	return 1;
}

int quitEGL()
{
	eglMakeCurrent( eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
	eglDestroyContext ( eglDisplay, eglContext );
	eglDestroySurface ( eglDisplay, eglSurface );
	eglTerminate ( eglDisplay );
	return 1;
}

int draw(float i)
{
	glClear(GL_COLOR_BUFFER_BIT);
	GLfloat vertices[] =
		{-1,0,0,
		 0,-1,0,
		i,0,0};
	 
	glEnableClientState(GL_VERTEX_ARRAY);
	 
	glVertexPointer(3, GL_FLOAT, 0, vertices);
	 
	glDrawArrays(GL_TRIANGLES, 0, 3);
	 
	glDisableClientState(GL_VERTEX_ARRAY);
}

int main( int argc, const char* argv[] )
{ 
	if (!initVideoRaw(100, 80, vsync, fsaa))
	{
		printf ("Error setting up GLES2D!");
		quitEGL(); // clean up
		return 0;
	}
	for (float i=0; i<=1; i=i+0.0005f)
	{
		draw(i);
		swapBuffers();
	}
	quitEGL(); //clean up
	return 1;
}
 
Whynodd, see, there was no need to panic ; )

ps:

torpor, your filling up of the config attribs array (pi32ConfigAttribs) overruns the next variable in case of fsaa (and generally the fsaa request part is broken). you may want to remove the first occurrence of

Code:
pi32ConfigAttribs[attrib++] = EGL_NONE;
and generally rewrite the attribs filling-up as

Code:
EGLint pi32ConfigAttribs[7];
int attrib = 0;
pi32ConfigAttribs[attrib++] = EGL_SURFACE_TYPE;
pi32ConfigAttribs[attrib++] = EGL_WINDOW_BIT;

if ( fsaa )
{
        pi32ConfigAttribs[attrib++] = EGL_SAMPLE_BUFFERS;
        pi32ConfigAttribs[attrib++] = 1;
        pi32ConfigAttribs[attrib++] = EGL_SAMPLES
        pi32ConfigAttribs[attrib++] = 4;
}
pi32ConfigAttribs[attrib++] = EGL_NONE;
 
Thanks darkblu, the WakeBreaker port was all a very quick hack and next time I get a chance I'll sit down and clean things up a bit .. still want to fix the controls, too ..
 
Ok, now its a X11-Window and ES2.
But: The triangle doesn't show up. I mixed code from several tutorials and from an example of the Khronos ES2 SDK. No compile or runtime errors.

complete source:
in a pastebin

Suprisingly, glClearColor works and shows (as intended) alternating background colors from blue to red. Buffer swap, contexts, surfaces - everything seems to be ok, but not my sweet little triangle.

My triangle:
Code:
GLfloat afVertices[] = {0.0f,0.5f,0.0f, // Position
                        -0.5f ,-0.5f,0.0f,
                        0.5f ,-0.5f ,0.0f};

The draw method:
Code:
int draw(float i)
{
    glClearColor(i, 0.0f, 1.0-i, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    // Draws a triangle
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, afVertices);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glDisableVertexAttribArray(0);
    return 1;
}

and the shaders, they also compile and link without errors:
Code:
const char* pszFragShader = "\
	void main (void)\
	{\
		gl_FragColor = vec4(0.0, 1.0, 0.0 ,1.0);\
	}";

const char* pszVertShader = "\
    attribute   vec4    vPosition;\
    void main(void)\
    {\
        gl_Position = vPosition;\
    }";

(I tried vertex buffer objects like in the khronos SDK first, same result: No triangle on the screen)

Frustration level rising...
 
Try either giving 4 component vertex positions or setting w to 1.0 explicitly in the shader.
 
Whynodd said:
Code:
const char* pszFragShader = "\
	void main (void)\
	{\
		gl_FragColor = vec4(0.0, 1.0, 0.0 ,1.0);\
	}";

const char* pszVertShader = "\
    attribute   vec4    vPosition;\
    void main(void)\
    {\
        gl_Position = vPosition;\
    }";

your vertex shader does not do anything than just copying the vertex position. keep in mind that with GLES2 you need to do everything by hand that was previously done automagically by the fixed function pipeline like lighting, projection, modelview matrix stuff. so at least you ar missing a matrix multiplication within the vertex shader:

wiki: http://en.wikipedia.org/wiki/GLSL near "A sample trivial GLSL Vertex Shader"
 
Last edited by a moderator:
I think his coordinates should be fine for clip space.

Another thing the code is lacking is a call to glViewport to properly convert clip space to screen space coordinates. The Khronos example does have it (although it also has the same problem of having an uninitialized w). I've seen problems when w (or z) is not initialized that didn't show up in IMG's OGL ES2 wrapper, so I do recommend initializing it, else your triangle might end up getting frustum clipped or otherwise distorted.
 
Exophase said:
Try either giving 4 component vertex positions or setting w to 1.0 explicitly in the shader.
I will try that.


crow_riot said:
your vertex shader does not do anything than just copying the vertex position. keep in mind that with GLES2 you need to do everything by hand that was previously done automagically by the fixed function pipeline like lighting, projection, modelview matrix stuff. so at least you ar missing a matrix multiplication within the vertex shader:
wiki: http://en.wikipedia.org/wiki/GLSL near "A sample trivial GLSL Vertex Shader"
The Hello Triangle example program from the Khronos SDK did pass an identity matrix to the vertex shader, so a multiplication with it does not change the point coordinates. As a test, i took the matrix stuff out completely. Its like using normal opengl without touching the projection and modelview matrices. I always thought that then the viewport is from (-1,-1,z) to (1,1,z) so my triangle should be displayed. Perhaps backface culling skips the triangle.
Lighting is another story, I will manage that after the first triangle showed up on my screen. As long as I set the fragment color to a constant color there should be drawn at least something.
From wikipedia (GLSL):
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
if the projection and modelview is unit here, that line just appends the homogenous coordinate to the vertex position. Maybe Exophase is right: 4th coordinate missing. I'll try that later.
 
Last edited by a moderator:
Whynodd said:
gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
if the projection and modelview is unit here, that line just appends the homogenous coordinate to the vertex position. Maybe Exophase is right: 4th coordinate missing. I'll try that later.

exos suggestion and the projection/modelview matrix multiplication will have the same result if i'm correct. just that you'll need that multiplication sooner or later anyway, so by leaving this in, i think it would've worked from the very beginning saving you some headache.

*edit typo*
 
Last edited by a moderator:
Found the error.

if (!compileShaders())
{
...
return 0;
}

Forgot those red "()". Ugh, so, the function was not called and shaders have not been compiled. RHAAAAHHHHHHHHHHHHHH! Now it works, even antialiasing (max 4 samples/pixel allowed). Green triangle on changing background. More tomorrow.
 
Whynodd, a few remarks from first glance:

* your application does not have an x event loop - i guess you're fine with that at this stage, though i'm surprised eglSwapBuffers() still manages to work without an even loop.
* in theory, your vec4 vPosition attribute should get an implicit w = 1 by default (when an vec3 is fed to a vec4 attribute), but Exophase is right to suspect that that might create an issue with the driver. better output as "gl_Position = vec4(vPosition, 1.0)", and have your vPosition attr as vec3.
* your fragment shader does not have the mandatory precision qualifiers - i have no idea why the driver does not fuss about that. put a "precision mediump float;" as first line in the fragment shader.
* some drivers mishandle glBindAttribLocation() - you're safer using glGetAttribLocation() once the program is linked.
* your iErr variable (EGL error state?) is unused in you rendition loop, but more importantly - you may want to also check for ES errors in the loop. glGetError() is your friend.

ed: glad to hear you already got it working.
 
darkblu said:
Whynodd, a few remarks from first glance:

* your application does not have an x event loop - i guess you're fine with that at this stage, though i'm surprised eglSwapBuffers() still manages to work without an even loop.
* in theory, your vec4 vPosition attribute should get an implicit w = 1 by default (when an vec3 is fed to a vec4 attribute), but Exophase is right to suspect that that might create an issue with the driver. better output as "gl_Position = vec4(vPosition, 1.0)", and have your vPosition attr as vec3.
* your fragment shader does not have the mandatory precision qualifiers - i have no idea why the driver does not fuss about that. put a "precision mediump float;" as first line in the fragment shader.
* some drivers mishandle glBindAttribLocation() - you're safer using glGetAttribLocation() once the program is linked.
* your iErr variable (EGL error state?) is unused in you rendition loop, but more importantly - you may want to also check for ES errors in the loop. glGetError() is your friend.

ed: glad to hear you already got it working.

Thanks for these tips and thanks to the other guys for your help.
I don't need an event loop. This is just a prototype to test stuff. Feeding vec3 to vec4 worked, I don't know if the 4th coordinate is random or default 1, so I just use vec4.
Precision qualifiers: Good idea. I will use them if I find out how they affect performance and quality.
glGetError()... Is it nessesary/advisable to poll errors after every gl call? I mean, its like kids who cry permanently "ARE WE THERE YET???" ;) Half of my code is error handling. Hmm, another way to code inefficient ;) .
 
Last edited by a moderator:
Whynodd said:
Feeding vec3 to vec4 worked, I don't know if the 4th coordinate is random or default 1, so I just use vec4.
feeding a vec3 array to a vec4 attrib should work accoring to the specs, but you're into seldom-threaded, little-tested driver code territory there. alternatively, you can use a vec3 position attrib and output a constant w from within the shader - no guessing, no driver uncertainty.

Precision qualifiers: Good idea. I will use them if I find out how they affect performance and quality.
i think you missed my point (precision qualifiers undoubtedly affect performance - that's not being discussed) - any specs-compliant driver would reject your fragment shader if it did not have a default precision qualifier for floats. that fact the current driver did not complain indicates a bug in the driver.

glGetError()... Is it nessesary/advisable to poll errors after every gl call? I mean, its like kids who cry permanently "ARE WE THERE YET???" ;) Half of my code is error handling. Hmm, another way to code inefficient ;) .
i thought you were trying to get a hello world to work, no? if you had a simple error check in place you'd have saved yourself some of that frustration ; )
 
Last edited by a moderator:
i think you missed my point (precision qualifiers undoubtedly affect performance - that's not being discussed) - any specs-compliant driver would reject your fragment shader if it did not have a default precision qualifier for floats. that fact the current driver did not complain indicates a bug in the driver.
Oh, I didn't know that, just copied from the examples in the khronos sdk. Hmm, like with the vec3<->vec4 issue: I'll just use qualifiers to be on the safe side.

i thought you were trying to get a hello world to work, no? if you had a simple error check in place you'd have saved yourself some of that frustration ;)
Hehe, during development I try to do error checking where nessesary. And when I'm totally sure that my code is correct, then I remove the error checks.
Its weird: I like it more when my software just crashes at an error condition, thats easier to debug ;) . But when another API (here GLES2, egl) runs in "quirks mode" after errors then you and your triangles are lost. I had no clue where to find the error, it could be everywhere. I'm glad that it was a typo.

Enough words ;) I will show more results if I find out something interesting.
 
Back
Top