In the following test program, I am trying to render a green square (250 x 250) in the bottom left corner of the screen (500 x 500).
I am using two buffer textures to pass in two int arrays (each array is of size 500 * 500) to the fragment shader. The arrays are simply populated with x (first array) and y (second array) values that correspond to all the (x, y) coordinates in screen space (this is shown in the init() part of the code below).
In the fragment shader, if the current fragment location (in screen space) is less than 250.0 in both the x and the y directions, that fragment is colored green. Otherwise, it is colored red. Images shown below.
Below is the full OpenGL code, along with the pass-through vertex shader (located in the main program) and a fragment shader (read in from a file). In the fragment shader, there are three tests (A, B, and C). Tests B and C are not working as expected. They draw the green square on the bottom right instead of the bottom left.
Test A (correct): The output of this code works as expected (a green square in bottom left corner of screen) when I use gl_FragCoord.xy in the conditional if check.
Test B (incorrect): If I use the buffer textures along with texelFetch to retrieve the x and y values of the current fragment and then use that in the conditional if check, the green square gets drawn in the lower right hand corner.
Test C (incorrect): If I forego the buffer textures and instead just compute the current fragment index and use a simple mod and division to to get the x, y indices, the green square is still drawn on the bottom right.
Any insight would be appreciated.
I'm using:
Ubuntu 12.04.5 LTS, 64 bit
glGetString(GL_VERSION) = 4.4.0 NVIDIA 331.113
Main Program: mytest.cc
// This program was modified from:
// https://www.opengl.org/discussion_boards/showthread.php/173917-samplerBuffer-example-needed
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glut.h>
using namespace std;
static const char Vertex_src[] =
"void main(void) \n"
"{ \n"
" gl_Position = ftransform(); \n"
"} \n";
std::string readFile(const char *filePath)
{
std::string content;
std::ifstream fileStream(filePath, std::ios::in);
if(!fileStream.is_open()) {
std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
return "";
}
std::string line = "";
while(!fileStream.eof()) {
std::getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
void keybd ( unsigned char, int, int )
{
exit ( 0 ) ;
}
void reshape(int wid, int ht)
{
glViewport(0, 0, wid, ht);
}
void showGLerror ()
{
GLenum err ;
while ( (err = glGetError()) != GL_NO_ERROR )
fprintf ( stderr, "OpenGL Error: %s\n", gluErrorString ( err ) ) ;
}
void display ( void )
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, 500, 500);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
// Draw a full screen quad.
GLfloat s = 1.0;
glBegin(GL_QUADS);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(s, 0.0f, 0.0f);
glVertex3f(s, s, 0.0f);
glVertex3f(0.0f, s, 0.0f);
glEnd();
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glutSwapBuffers () ;
glutPostRedisplay () ;
}
void showShaderInfo ( const char *what, GLuint handle )
{
int len = 0 ;
glGetObjectParameterivARB ( handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &len ) ;
if ( len > 0 )
{
int trueLen ;
char *s = new char [ len ] ;
glGetInfoLogARB ( handle, len, &trueLen, s ) ;
if ( trueLen > 0 && s [ 0 ] != '\0' )
fprintf ( stderr, "%s:\n%s\n", what, s ) ;
delete [] s ;
}
}
GLuint compileShader ( const char *src, GLenum type )
{
const char *type_str = type == GL_VERTEX_SHADER ? "vertex" : "fragment";
GLuint handle = glCreateShader( type ) ;
glShaderSource ( handle, 1, &src, 0 ) ;
glCompileShader( handle ) ;
GLint compiled ;
glGetShaderiv( handle, GL_COMPILE_STATUS, &compiled ) ;
if ( !compiled )
{
showShaderInfo ( type_str, handle ) ;
fprintf ( stderr, "Failed to compile %s shader.\n", type_str );
exit ( 1 ) ;
}
return handle ;
}
GLuint linkShaders ( GLuint vsHandle, GLuint fsHandle )
{
GLint linked ;
GLuint handle = glCreateProgram() ;
glAttachShader ( handle, vsHandle ) ;
glAttachShader ( handle, fsHandle ) ;
glLinkProgram ( handle ) ;
glGetProgramiv ( handle, GL_LINK_STATUS, & linked ) ;
if ( !linked )
{
showShaderInfo ( "Linking", handle ) ;
fprintf ( stderr, "Failed to link shader program.\n" ) ;
exit ( 1 ) ;
}
return handle ;
}
void init()
{
int arraySize = 500 * 500;
int *array_x = new int[arraySize];
int *array_y = new int[arraySize];
// Populate arrays.
for (int y = 0; y < 500; y++) {
for (int x = 0; x < 500; x++) {
array_x[(y * 500) + x] = x;
array_y[(y * 500) + x] = y;
}
}
const size_t size = sizeof( int ) * arraySize;
//// array_x
//
// Generate and fill buffer object
GLuint buffer;
glGenBuffers ( 1, &buffer );
glBindBuffer ( GL_TEXTURE_BUFFER, buffer );
glBufferData ( GL_TEXTURE_BUFFER, size, array_x, GL_STATIC_DRAW ); // Alloc & Fill
// Generate texture "wrapper" around buffer object
GLuint tex;
glGenTextures ( 1, &tex );
glActiveTexture( GL_TEXTURE0);
glBindTexture ( GL_TEXTURE_BUFFER, tex );
glTexBuffer ( GL_TEXTURE_BUFFER, GL_R32I, buffer );
//// array_y
//
// Generate and fill buffer object
GLuint buffer2;
glGenBuffers ( 1, &buffer2 );
glBindBuffer ( GL_TEXTURE_BUFFER, buffer2 );
glBufferData ( GL_TEXTURE_BUFFER, size, array_y, GL_STATIC_DRAW ); // Alloc & Fill
// Generate texture "wrapper" around buffer object
GLuint tex2;
glGenTextures ( 1, &tex2 );
glActiveTexture( GL_TEXTURE0 + 1);
glBindTexture ( GL_TEXTURE_BUFFER, tex2 );
glTexBuffer ( GL_TEXTURE_BUFFER, GL_R32I, buffer2 );
}
int main ( int argc, char **argv )
{
// Init GL context
glutInit ( &argc, argv ) ;
glutInitDisplayMode ( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE ) ;
glutInitWindowSize ( 500, 500 ) ;
glutCreateWindow ( "Shader Test" ) ;
glutDisplayFunc ( display ) ;
glutKeyboardFunc ( keybd ) ;
glutReshapeFunc ( reshape ) ;
// Create buffer object and its texture buffer object wrapper
init();
// Load and compile shaders
printf( "Compiling vertex shader...\n" );
GLuint vsHandle = compileShader ( Vertex_src, GL_VERTEX_SHADER );
printf( "Compiling fragment shader...\n" );
GLuint fsHandle = compileShader ( (readFile("mytest.glsl")).c_str(), GL_FRAGMENT_SHADER);
// Link shaders
printf( "Linking...\n" );
GLuint handle = linkShaders ( vsHandle, fsHandle ) ;
// Activate shader
glUseProgram( handle ) ;
// Populate uniform
// (buffer texture will be on TEXUNIT 0)
glUniform1i( glGetUniformLocation( handle, "tex" ), 0 );
// (buffer2 texture will be on TEXUNIT 1)
glUniform1i( glGetUniformLocation( handle, "tex2" ), 1 );
// Draw with shader
glutMainLoop () ;
return 0 ;
}
Fragment Shader: mytest.glsl
#version 130
#extension GL_EXT_gpu_shader4: enable
uniform isamplerBuffer tex;
uniform isamplerBuffer tex2;
void main(void)
{
int width = 500;
// Get the current screen index we are going to work on.
// (Used for TEST B and TEST C below.)
int index = int((gl_FragCoord.y * float(width)) + gl_FragCoord.x);
// TEST A: This works as expected.
/*if (gl_FragCoord.x < 250.0 && gl_FragCoord.y < 250.0) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}*/
// TEST B: Use buffer textures to get the value of the arrays at
// the index computed above. This does not work as expected.
int x_i = int(texelFetch(tex, index).r);
int y_i = int(texelFetch(tex2, index).r);
if (x_i < 250 && y_i < 250) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
// TEST C: Get the x, y screen space coordinates based on the index
// computed above. This does not work as expected.
/*int x_i = index % 500;
int y_i = index / 500;
if (x_i < 250 && y_i < 250) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}*/
}
Result of Test A
Test A http://www.shilpigupta.com/stack/TestA.png
Result of Test B and Test C
(Also notice the green line artifact at the top right of the image.)
Test B and Test C http://www.shilpigupta.com/stack/TestB.png
The mistake is how you calculate the index:
int index = int((gl_FragCoord.y * float(width)) + gl_FragCoord.x);
This code will only work if the fractional part of gl_FragCoord is zero. Note that OpenGL's window space is defined in such a way that pixel centers lie at half-integer positions ("at comma 5"). Without mutlisampling or other fancy settings, the fragment shader will be invoked exactly for pixel centers, so all of your gl_FragCoord values are at .5, which basically results in the shift in 0.5 * width pixels you are observing. (In the case B and C, the green area actually isn't a square, because one line in height is missing at the top, because you already start the bottom line at x_i=250).
The correct approach is
int index = int(gl_FragCoord.y) * width + int(gl_FragCoord.x);
Related
Is it possible to map texture to Sphere that are generated by parametric equation and rendered using GL_POINTS primitive ? If it is possible, how is it be done and inside my code, I copy the code image loading code from the web and load it as it is instructed. One thing that I did not followed them is specifying the vertex for the texture coordinate, which I am not sure how to specify it exactly when render it with Sphere and with GL_POINTS primitive.
I am using the old OpenGL2 for my project and doing a solar system simulation
Here is the repository to the code and it is public
This is how I generate the sphere
// void Sphere::render () method, inside src/sphere.cpp - line 28
void Sphere::render () {
unsigned int angle = 0, angle2 = 0;
const double degree_to_rad = 3.14 / 180.0;
double value = .0, value2 = .0;
if ( this -> texture_file_name != "" ) {
glEnable ( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, this -> texture );
}
glBegin ( GL_POINTS );
for ( ; angle < 360; ++ angle ) {
value = angle * degree_to_rad;
for ( ; angle2 < 180; ++ angle2 ) {
value2 = angle2 * degree_to_rad;
/*/////////////////////////////////////////////
// do I need to do sth in here like glTexCoord2d ( ... ) ?
////////////////////////////////////////////*/
glVertex3d (
this -> calculateX ( value, value2 ),
this -> calculateY ( value, value2 ),
this -> calculateZ ( value )
);
}
angle2 = 0;
}
glEnd ();
if ( this -> texture_file_name != "" ) {
glDisable ( GL_TEXTURE_2D );
}
};
// void Sphere::draw () method, src/sphere.cpp - line 75
void Sphere::draw () {
glPushMatrix ();
glTranslated (
this -> coordinate [ 0 ],
this -> coordinate [ 1 ],
this -> coordinate [ 2 ]
);
glRotated (
this -> angle_degree,
this -> rotation [ 0 ],
this -> rotation [ 1 ],
this -> rotation [ 2 ]
);
this -> render ();
glPopMatrix ();
};
double Sphere::calculateX ( const double theta_degree_angle, const double phi_degree_angle ) {
return this -> radius * sin ( theta_degree_angle ) * cos ( phi_degree_angle );
};
double Sphere::calculateY ( const double theta_degree_angle, const double phi_degree_angle ) {
return this -> radius * sin ( theta_degree_angle ) * sin ( phi_degree_angle );
};
double Sphere::calculateZ ( const double theta_degree_angle ) {
return this -> radius * cos ( theta_degree_angle );
};
This is my loadTexture method
void Object::loadTexture () {
int & w = this -> texture_width, & h = this -> texture_height;
unsigned char * data = new unsigned char [ w * h * 3 ];
FILE * file;
try {
file = fopen ( this -> texture_file_name.c_str () , "rb" );
if ( !file ) return;
fread ( data, w * h * 3, 1, file );
fclose ( file );
} catch ( std::exception & error ) {
std::cout << "Loading Texture Error: " << error.what () << std::endl;
}
glGenTextures ( 1, & this -> texture );
glBindTexture ( GL_TEXTURE_2D, this -> texture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
delete [] data;
};
void Object::setTexture ( const char * file_name, const int width, const int height ) {
this -> texture_file_name = file_name;
this -> texture_width = width;
this -> texture_height = height;
this -> loadTexture ();
};
This is my main.cpp
// main.cpp
// gloabl vars
NonStd::Sphere sun = NonStd::Sphere ( 10 );
NonStd::Sphere earth = NonStd::Sphere ( 3 );
NonStd::Sphere moon = NonStd::Sphere ( 1 );
NonStd::Object space = NonStd::Object ();
void render ();
void modelInit ();
void idle ();
void windowOnChange ( int width, int height );
void mouseOnDrag ( int x, int y );
int main ( int args_len, char ** args_context ) {
glutInit ( &args_len, args_context );
glutInitDisplayMode ( GLUT_SINGLE );
glutInitWindowSize ( WINDOW_WIDTH, WINDOW_HEIGHT );
glutInitWindowPosition ( 100, 100 );
glutCreateWindow ( "Solar System Simulation" );
glEnable ( GL_NORMALIZE );
glEnable ( GL_COLOR_MATERIAL );
// all models initialization
modelInit ();
// event handlers
glutDisplayFunc ( render );
glutReshapeFunc ( windowOnChange );
// glutMotionFunc ( mouseOnDrag );
// global idle func
glutIdleFunc ( idle );
glutMainLoop ();
return 0;
};
void render () {
glClearColor ( .2, .3, .5, .8 );
glClear ( GL_COLOR_BUFFER_BIT );
if ( sun.isObjectShown () ) {
sun.draw ();
}
if ( earth.isObjectShown () ) {
earth.draw ();
}
if ( moon.isObjectShown () ) {
moon.draw ();
}
glFlush ();
};
void modelInit () {
// object visibility default is false
sun.setVisible ( true );
// move to proper position to for object for better viewing
sun.translateZ ( -90.0 );
// set object texture
sun.setTexture ( "resources/earth.jpg", 100, 100 );
// spin default is false, toggle it for spinning
sun.toggleSpin ();
earth.setVisible ( true );
earth.translateZ ( -90.0 );
earth.translateX ( 26.0 );
earth.setTexture ( "resources/earth.jpg", 100, 100 );
earth.toggleSpin ();
earth.setSpinSpeed ( 2 );
moon.setVisible ( true );
moon.translateZ ( -90.0 );
moon.translateX ( 20.0 );
moon.setTexture ( "resources/earth.jpg", 100, 100 );
moon.toggleSpin ();
};
After I set the texture on my sphere object, the sphere turn into this yellow color and before setting the texture, it was white, does this mean the texture already set but I have not yet specify the texture coordinate for it ?
FYI: The project said it is 2D, but actually I am doing it in 3D just to clarify it.
A sphere can either be created by tessellating an existing object like a icosahedron, or by stacking discs.
Stacking discs:
The following code creates a sphere by stacking up a number of discs (layers). Each layer has circumferenceTiles tiles around its circum. The U texture coordinate is wrapped arund the circum. The V texture coordinate is wrapped from the south pole to the north pole of the sphere.
void CreateSphereMesh( int layers, int circumferenceTiles, std::vector<float> &va, std::vector<int> &ia )
{
const float pi = 3.1414927f;
// create the vertex attributes
va.reserve( (layers+1)*(circumferenceTiles+1)*5 ); // 5 floats: x, y, z, u, v
for ( int il = 0; il <= layers; ++ il )
{
float layer_rel = (float)il / (float)layers;
float layer_ang = (1.0f - 2.0f * layer_rel) * pi/2.0f ;
float layer_sin = std::sin( layer_ang );
float layer_cos = std::cos( layer_ang );
for ( int ic = 0; ic <= circumferenceTiles; ic ++ )
{
float circum_rel = (float)ic / (float)circumferenceTiles;
float cricum_ang = circum_rel * 2.0f*pi - pi;
float circum_sin = std::sin( cricum_ang );
float circum_cos = std::cos( cricum_ang );
va.push_back( layer_cos * circum_cos ); // x
va.push_back( layer_cos * circum_sin ); // y
va.push_back( layer_sin ); // z
va.push_back( circum_rel ); // u
va.push_back( 1.0f - layer_rel ); // v
}
}
// create the face indices
ia.reserve( layers*circumferenceTiles*6 );
for ( int il = 0; il < layers; ++ il )
{
for ( int ic = 0; ic < circumferenceTiles; ic ++ )
{
int i0 = il * (circumferenceTiles+1) + ic;
int i1 = i0 + 1;
int i3 = i0 + circumferenceTiles+1;
int i2 = i3 + 1;
int faces[]{ i0, i1, i2, i0, i2, i3 };
ia.insert(ia.end(), faces+(il==0?3:0), faces+(il==layers-1?3:6));
}
}
}
An vertex array object for the fixed function pipline can be specified like this:
GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, va.size()*sizeof(*va.data()), va.data(), GL_STATIC_DRAW );
GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, ia.size()*sizeof(*ia.data()), ia.data(), GL_STATIC_DRAW );
glVertexPointer( 3, GL_FLOAT, 5*sizeof(*va.data()), 0 );
glEnableClientState( GL_VERTEX_ARRAY );
glTexCoordPointer( 2, GL_FLOAT, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
For modern OpenGL the generic vertex attribute data arrays have to be defined like this:
GLint avert_loc = ....;
GLint atexc_loc = ....;
glVertexAttribPointer( avert_loc, 3, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), 0 );
glEnableVertexAttribArray( avert_loc );
glVertexAttribPointer( atexc_loc, 2, GL_FLOAT, GL_FALSE, 5*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) );
glEnableVertexAttribArray( atexc_loc );
Finall the drawing operation:
glEnable( GL_TEXTURE_2D ); // for fixed function pipeline only
glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)ia.size(), GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );
Preview:
Hello everyone im trying to learn openGL using shaders so i made a triangle that changes its color while it moves but for some reason the trigle does not appear in the window, just a black background , it doesn't crash or show any kind of error, i believe the libraries set up is ok since i've used them before.
Im using CLion on Ubuntu 16.04. Here is my code so hopefully you can check it out and give me a hand. Thanks!
#define GLEW_STATIC
#include <stdlib.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
int CurrentWidth = 800,
CurrentHeight = 600,
WindowHandle = 0;
GLuint
VertexShaderId,
FragmentShaderId,
ProgramId;
GLuint s_vertexLoc, s_colorLoc , s_factorLoc;
GLfloat runner = 0.0;
const GLchar* VertexShader =
{
"#version 150\n"
"attribute vec3 in_vertex;"
"attribute vec3 in_color;"
"uniform float factor;"
"varying vec3 intp_color;"
"void main(void)"
"{"
"intp_color = in_color;"
"gl_Position = vec4( in_vertex , 1.0 ) ;"
"gl_Position.y += factor; "
"}"
};
//Telling every single pixel is going to be red
const GLchar* FragmentShader =
{
"#version 150\n"
"uniform float factor;"
"varying vec3 intp_color;"
"void main(void){"
"gl_FragColor = vec4( intp_color , 1.0) * factor;"
"}"
};
// for. dec.
void ResizeFunction(int, int);
void RenderFunction(void);
void IdleFunction(void);
void CreateShaders(void);
// set up an array for the geometry of the object
GLfloat Vertices[] = {
-0.5f , -0.2f , 0.0f, // point A - x , y , z
0.5f , -0.2f , 0.0f, // point B - x , y , z
0.0f , 0.8f , 0.0f // point C - x , y , z
};
GLfloat Colors[] = {
1.0f , 0.0f , 0.0f, // point A - x , y , z
0.0f , 1.0f , 0.0f, // point B - x , y , z
0.0f , 0.0f , 1.0f // point C - x , y , z
};
int main( int argc , char* argv[] )
{
glutInit( &argc , argv);
//Target version 3.1
glutInitContextVersion(3 , 1 );
glutInitWindowSize(CurrentWidth, CurrentHeight);
glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA );
WindowHandle = glutCreateWindow( "OpenGL - Shader example" );
glutReshapeFunc( ResizeFunction );
glutDisplayFunc( RenderFunction );
glutIdleFunc( IdleFunction );
/// init GLEW
GLenum GlewInitResult;
GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
exit(EXIT_FAILURE);
/// Create our shaders
CreateShaders();
glutMainLoop();
exit(EXIT_SUCCESS);
}
void ResizeFunction(int Width, int Height)
{
CurrentWidth = Width;
CurrentHeight = Height;
glViewport( 0, 0, CurrentWidth, CurrentHeight );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
}
void RenderFunction(void)
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
//We enable the shader variable
glEnableVertexAttribArray( s_vertexLoc );
glEnableVertexAttribArray( s_colorLoc );
//How to send data to the variable:
//( Where to send the data , how its grouped , data type , dont normalize the data,
// there is no offset, you find it here)
glVertexAttribPointer( s_vertexLoc , 3 , GL_FLOAT , GL_FALSE , 0 , Vertices );
glVertexAttribPointer ( s_colorLoc , 3 , GL_FLOAT , GL_FALSE , 0 , Colors);
glUniform1f( s_factorLoc , runner );
runner += 0.01;
if(runner > 1.0f)
runner = -1.0f;
glDrawArrays( GL_TRIANGLES , 0 , 3 );
glDisableVertexAttribArray( s_vertexLoc );
glDisableVertexAttribArray( s_colorLoc );
glutSwapBuffers();
}
void IdleFunction(void)
{
glutPostRedisplay();
}
//Error checking
void printLog(GLuint obj)
{
int infologLength = 0;
int maxLength;
if( glIsShader( obj ) )
glGetShaderiv( obj , GL_INFO_LOG_LENGTH , &maxLength );
else
glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &maxLength);
char infoLog[1255];
if ( glIsShader(obj) )
glGetShaderInfoLog( obj, maxLength, &infologLength, infoLog );
else
glGetProgramInfoLog( obj, maxLength, &infologLength, infoLog );
if ( infologLength > 0 )
printf( "\n Error detail: %s\n" , infoLog );
}
void CreateShaders(void)
{
GLenum ErrorCheckValue = glGetError();
if( glCreateShader )
printf(" ---- shader suppot ok ---");
else
{
printf(" ---- no shader support ---");
return ;
}
///The VERTEX shader is created (tell it what it is)
VertexShaderId = glCreateShader( GL_VERTEX_SHADER );
//(shader we want to set the source, how many are they, the source of the shader , )
glShaderSource( VertexShaderId , 1 , &VertexShader , nullptr );
//Compile the shader
glCompileShader( VertexShaderId );
//Error checking
printLog( VertexShaderId );
///The FRAGMENT shader is created (tell it what it is)
FragmentShaderId = glCreateShader( GL_FRAGMENT_SHADER );
//(shader we want to set the source, how many are they, the source of the shader , )
glShaderSource( FragmentShaderId , 1 , &FragmentShader , nullptr );
//Compile the shader
glCompileShader( FragmentShaderId );
//Error checking
printLog( FragmentShaderId );
///Program Object links both shaders
ProgramId = glCreateProgram();
//Attach the compiled shaders to the program
glAttachShader( ProgramId , VertexShaderId );
glAttachShader( ProgramId , FragmentShaderId );
//Links the shaders to the program
glLinkProgram( ProgramId );
//Error checking
printLog( ProgramId );
//Uses the program to render
glUseProgram( ProgramId );
//( check this program , for this variable and return it)
s_vertexLoc = glGetAttribLocation( ProgramId , "in_vertex" );
s_colorLoc = glGetAttribLocation( ProgramId , "in_color" );
s_factorLoc = glGetUniformLocation( ProgramId , "factor" );
}
You have several issues.
First, using OpenGL 3.1 (GLSL 1.30) is discouraged. Try with at least
3.2 (GLSL 1.50) and ask for that Core Profile in your glut initialization. Then replace "attribute" with "in" in your
vertex shader and "varying" with "in" or "out" depending
if this var is going to be used as an input or an output.
Second. This
//How to send data to the variable:
//( Where to send the data , how its grouped , data type , dont normalize the data,
// there is no offset, you find it here)
glVertexAttribPointer( s_vertexLoc , 3 , GL_FLOAT , GL_FALSE , 0 , Vertices );
glVertexAttribPointer ( s_colorLoc , 3 , GL_FLOAT , GL_FALSE , 0 , Colors);
is not true. That last value is a byte offset into the buffer object's data store, not the data itself.
Third: You need a buffer for your vertices coordinates. Use
glGenBuffers(), glBufferData(), and glBindBuffer()
If I were in your case I'd follow some tutorial on "modern OpenGL". Search the web, there are a lot.
I'm trying to bind a sdl2 texture to a glsl shader though I'm not entirely sure how? I'm using a library called glfx to handle the glsl shaders and I've been helping with the development of this library as well. I'm pretty sure I've got everything else right but it crashes when I call SDL_GL_BindTexture. Can anyone see what I've done wrong?
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <GL/glew.h>
#include <GL/glfx.h>
#include <SDL2/SDL.h>
#include <FreeImage.h>
int main()
{
SDL_Window *mainwindow;
SDL_Renderer *renderer;
SDL_GLContext maincontext;
SDL_Init( SDL_INIT_VIDEO );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
SDL_CreateWindowAndRenderer( 512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN, &mainwindow, &renderer );
maincontext = SDL_GL_CreateContext( mainwindow );
glewExperimental = GL_TRUE;
glewInit( );
fprintf( stdout, "%s\n", glGetString(GL_VERSION) );
fprintf( stdout, "%s\n", glGetString(GL_SHADING_LANGUAGE_VERSION) );
FIBITMAP* dib = FreeImage_Load( FIF_PNG, "test.png" );
uint32_t w = FreeImage_GetWidth( dib );
uint32_t h = FreeImage_GetHeight( dib );
dib = FreeImage_ConvertTo32Bits( dib );
BYTE* pixeles = FreeImage_GetBits( dib );
GLubyte* textura = new GLubyte[4*w*h];
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, w, h );
const SDL_Rect rect = { 0, 0, w, h };
int pitch = 32;
SDL_LockTexture( texture, &rect, (void**)&textura, &pitch );
for( uint32_t j = 0; j < w * h; j++ )
{
textura[j*4+0] = pixeles[j*4+2];
textura[j*4+1] = pixeles[j*4+1];
textura[j*4+2] = pixeles[j*4+0];
textura[j*4+3] = pixeles[j*4+3];
}
SDL_UnlockTexture( texture );
FreeImage_Unload( dib );
delete [] textura;
int effect = glfxGenEffect( );
std::string shader;
shader ="struct VSinput\n"
"{\n"
" vec3 Position;\n"
"};\n"
"shader VSmain(in VSinput VSin, out vec2 TexCoord)\n"
"{\n"
" gl_Position = vec4(VSin.Position, 1.0);\n"
" TexCoord = vec2( 0.8, 0.8 );\n"
"};\n"
"uniform sampler2D gColorMap;\n"
"shader FSmain(in vec2 TexCoord, out vec4 FragColor)\n"
"{\n"
" FragColor = texture(gColorMap, TexCoord);\n"
"}\n"
"program SimpleTechnique\n"
"{\n"
" vs(150) = VSmain();\n"
" fs(150) = FSmain();\n"
"};\0";
glfxParseEffectFromMemory( effect, shader.c_str() );
int shaderProg = glfxCompileProgram( effect, "SimpleTechnique" );
if (shaderProg < 0)
{
std::string log = glfxGetEffectLog(effect);
fprintf( stderr, "%s\n", log.c_str() );
}
glClearColor ( 0.0, 0.0, 1.0, 1.0 );
glClear ( GL_COLOR_BUFFER_BIT );
float* vert = new float[9];
vert[0] = 0.0; vert[1] = 0.5; vert[2] =-1.0;
vert[3] =-1.0; vert[4] =-0.5; vert[5] =-1.0;
vert[6] = 1.0; vert[7] =-0.5; vert[8] =-1.0;
unsigned int m_vaoID;
unsigned int m_vboID;
glGenVertexArrays( 1, &m_vaoID );
glBindVertexArray( m_vaoID );
glGenBuffers( 1, &m_vboID );
glBindBuffer( GL_ARRAY_BUFFER, m_vboID );
glBufferData( GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), vert, GL_STATIC_DRAW );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 0 );
glEnable( GL_TEXTURE_2D );
int loc = glGetUniformLocation( shaderProg, "gColorMap" );
glActiveTexture( GL_TEXTURE0 );
SDL_GL_BindTexture(texture, NULL, NULL );
glUniform1i( loc, 0 );
glUseProgram( shaderProg );
glDrawArrays( GL_TRIANGLES, 0, 3 );
glDisableVertexAttribArray( 0 );
glBindVertexArray( 0 );
delete[] vert;
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboID );
glDeleteVertexArrays( 1, &m_vaoID );
SDL_GL_SwapWindow( mainwindow );
SDL_Delay( 2000 );
SDL_GL_DeleteContext( maincontext );
SDL_DestroyWindow( mainwindow );
SDL_Quit( );
return 0;
}
glUniform - Specify the value of a uniform variable for the current program object
glUseProgram() then glUniform1i(), not the other way around.
EDIT: This is looking like a bug in SDL2. You might try the demo program I attached to the report and see if you can repro on your system.
EDIT2: Looks like Sam has a fix in already.
I'm developing a simple sprite-based 2D game in C++ that uses OpenGL for hardware-accelerated rendering, and SDL for window management and user input handling. Since it's a 2D game, I'm only ever going to need to draw quads, but because the number of sprites is dynamic, I can never rely on there being a constant number of quads. Consequently, I need to rebuffer all of the vertex data via my VBO each frame (since there may be more or fewer quads than there were in the last frame, and thus the buffer may be a different size).
The prototype program I have so far creates a window and allows the user to add and remove quads in a diagonal row by using the up and down arrow keys. Right now the quads I'm drawing are simple, untextured white squares. Here is the code I'm working with (compiles and works correctly under OS X 10.6.8 and Ubuntu 12.04 with OpenGL 2.1):
#if defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#endif
#if defined(__linux__)
#define GL_GLEXT_PROTOTYPES
#include <GL/glx.h>
#endif
#include <GL/gl.h>
#include <SDL.h>
#include <iostream>
#include <vector>
#include <string>
struct Vertex
{
//vertex coordinates
GLint x;
GLint y;
};
//Constants
const int SCREEN_WIDTH = 1024;
const int SCREEN_HEIGHT = 768;
const int FPS = 60; //our framerate
//Globals
SDL_Surface *screen; //the screen
std::vector<Vertex> vertices; //the actual vertices for the quads
std::vector<GLint> startingElements; //the index where the 4 vertices of each quad begin in the 'vertices' vector
std::vector<GLint> counts; //the number of vertices for each quad
GLuint VBO = 0; //the handle to the vertex buffer
void createVertex(GLint x, GLint y)
{
Vertex vertex;
vertex.x = x;
vertex.y = y;
vertices.push_back(vertex);
}
//creates a quad at position x,y, with a width of w and a height of h (in pixels)
void createQuad(GLint x, GLint y, GLint w, GLint h)
{
//Since we're drawing the quads using GL_TRIANGLE_STRIP, the vertex drawing
//order is from top to bottom, left to right, like so:
//
// 1-----3
// | |
// | |
// 2-----4
createVertex(x, y); //top-left vertex
createVertex(x, y+h); //bottom-left vertex
createVertex(x+w, y); //top-right vertex
createVertex(x+w, y+h); //bottom-right vertex
counts.push_back(4); //each quad will always have exactly 4 vertices
startingElements.push_back(startingElements.size()*4);
std::cout << "Number of Quads: " << counts.size() << std::endl; //print out the current number of quads
}
//removes the most recently created quad
void removeQuad()
{
if (counts.size() > 0) //we don't want to remove a quad if there aren't any to remove
{
for (int i=0; i<4; i++)
{
vertices.pop_back();
}
startingElements.pop_back();
counts.pop_back();
std::cout << "Number of Quads: " << counts.size() << std::endl;
}
else
{
std::cout << "Sorry, you can't remove a quad if there are no quads to remove!" << std::endl;
}
}
void init()
{
//initialize SDL
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_OPENGL);
#if defined(__APPLE__)
//Enable vsync so that we don't get tearing when rendering
GLint swapInterval = 1;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &swapInterval);
#endif
//Disable depth testing, lighting, and dithering, since we're going to be doing 2D rendering only
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_DITHER);
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
//Set the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1.0, 1.0);
//Set the modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Create VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
}
void gameLoop()
{
int frameDuration = 1000/FPS; //the set duration (in milliseconds) of a single frame
int currentTicks;
int pastTicks = SDL_GetTicks();
bool done = false;
SDL_Event event;
while(!done)
{
//handle user input
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_UP: //create a new quad every time the up arrow key is pressed
createQuad(64*counts.size(), 64*counts.size(), 64, 64);
break;
case SDLK_DOWN: //remove the most recently created quad every time the down arrow key is pressed
removeQuad();
break;
default:
break;
}
break;
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
//Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//replace the current contents of the VBO with a completely new set of data (possibly including either more or fewer quads)
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vertex), &vertices.front(), GL_DYNAMIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
//Set vertex data
glVertexPointer(2, GL_INT, sizeof(Vertex), 0);
//Draw the quads
glMultiDrawArrays(GL_TRIANGLE_STRIP, &startingElements.front(), &counts.front(), counts.size());
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Check to see if we need to delay the duration of the current frame to match the set framerate
currentTicks = SDL_GetTicks();
int currentDuration = (currentTicks - pastTicks); //the duration of the frame so far
if (currentDuration < frameDuration)
{
SDL_Delay(frameDuration - currentDuration);
}
pastTicks = SDL_GetTicks();
// flip the buffers
SDL_GL_SwapBuffers();
}
}
void cleanUp()
{
glDeleteBuffers(1, &VBO);
SDL_FreeSurface(screen);
SDL_Quit();
}
int main(int argc, char *argv[])
{
std::cout << "To create a quad, press the up arrow. To remove the most recently created quad, press the down arrow." << std::endl;
init();
gameLoop();
cleanUp();
return 0;
}
At the moment I'm using GL_TRIANGLE_STRIPS with glMultiDrawArrays() to render my quads. This works, and seems do be pretty decent in terms of performance, but I have to wonder whether using GL_TRIANGLES in conjunction with an IBO to avoid duplicate vertices would be a more efficient way to render? I've done some research, and some people suggest that indexed GL_TRIANGLES generally outperform GL_TRIANGLE_STRIPS, but they also seem to assume that the number of quads would remain constant, and thus the size of the VBO and IBO would not have to be rebuffered each frame. That's my biggest hesitation with indexed GL_TRIANGLES: if I did implement indexed GL_TRIANGLES, I would have to rebuffer the entire index buffer each frame in addition to rebuffering the entire VBO each frame, again because of the dynamic number of quads.
So basically, my question is this: Given that I have to rebuffer all of my vertex data to the GPU each frame due to the dynamic number of quads, would it be more efficient to switch to indexed GL_TRIANGLES to draw the quads, or should I stick with my current GL_TRIANGLE_STRIP implementation?
You'll probably be fine using un-indexed GL_QUADS/GL_TRIANGLES and a glDrawArrays() call.
SDL_Surface *screen;
...
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_OPENGL);
...
SDL_FreeSurface(screen);
Don't do that:
The returned surface is freed by SDL_Quit and must not be freed by the caller. This rule also includes consecutive calls to SDL_SetVideoMode (i.e. resize or resolution change) because the existing surface will be released automatically.
EDIT: Simple vertex array demo:
// g++ main.cpp -lglut -lGL
#include <GL/glut.h>
#include <vector>
using namespace std;
// OpenGL Mathematics (GLM): http://glm.g-truc.net/
#include <glm/glm.hpp>
#include <glm/gtc/random.hpp>
using namespace glm;
struct SpriteWrangler
{
SpriteWrangler( unsigned int aSpriteCount )
{
verts.resize( aSpriteCount * 6 );
states.resize( aSpriteCount );
for( size_t i = 0; i < states.size(); ++i )
{
states[i].pos = linearRand( vec2( -400, -400 ), vec2( 400, 400 ) );
states[i].vel = linearRand( vec2( -30, -30 ), vec2( 30, 30 ) );
Vertex vert;
vert.r = (unsigned char)linearRand( 64.0f, 255.0f );
vert.g = (unsigned char)linearRand( 64.0f, 255.0f );
vert.b = (unsigned char)linearRand( 64.0f, 255.0f );
vert.a = 255;
verts[i*6 + 0] = verts[i*6 + 1] = verts[i*6 + 2] =
verts[i*6 + 3] = verts[i*6 + 4] = verts[i*6 + 5] = vert;
}
}
void wrap( const float minVal, float& val, const float maxVal )
{
if( val < minVal )
val = maxVal - fmod( maxVal - val, maxVal - minVal );
else
val = minVal + fmod( val - minVal, maxVal - minVal );
}
void Update( float dt )
{
for( size_t i = 0; i < states.size(); ++i )
{
states[i].pos += states[i].vel * dt;
wrap( -400.0f, states[i].pos.x, 400.0f );
wrap( -400.0f, states[i].pos.y, 400.0f );
float size = 20.0f;
verts[i*6 + 0].pos = states[i].pos + vec2( -size, -size );
verts[i*6 + 1].pos = states[i].pos + vec2( size, -size );
verts[i*6 + 2].pos = states[i].pos + vec2( size, size );
verts[i*6 + 3].pos = states[i].pos + vec2( size, size );
verts[i*6 + 4].pos = states[i].pos + vec2( -size, size );
verts[i*6 + 5].pos = states[i].pos + vec2( -size, -size );
}
}
struct Vertex
{
vec2 pos;
unsigned char r, g, b, a;
};
struct State
{
vec2 pos;
vec2 vel; // units per second
};
vector< Vertex > verts;
vector< State > states;
};
void display()
{
// timekeeping
static int prvTime = glutGet(GLUT_ELAPSED_TIME);
const int curTime = glutGet(GLUT_ELAPSED_TIME);
const float dt = ( curTime - prvTime ) / 1000.0f;
prvTime = curTime;
// sprite updates
static SpriteWrangler wrangler( 2000 );
wrangler.Update( dt );
vector< SpriteWrangler::Vertex >& verts = wrangler.verts;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// set up projection and camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -400 * ar, 400 * ar, -400, 400, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 2, GL_FLOAT, sizeof( SpriteWrangler::Vertex ), &verts[0].pos.x );
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( SpriteWrangler::Vertex ), &verts[0].r );
glDrawArrays( GL_TRIANGLES, 0, verts.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glutSwapBuffers();
}
// run display() every 16ms or so
void timer( int extra )
{
glutTimerFunc( 16, timer, 0 );
glutPostRedisplay();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitWindowSize( 600, 600 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutCreateWindow( "Sprites" );
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 0;
}
You can get decent performance with just vertex arrays.
Ideally most/all of your dts should be <= 16 milliseconds.
So I have a piece of code that runs fine on ubuntu machine, but fails to do so on xcode or via terminal. I'm trying to run it on xcode, but it fails on main with:
"Use of undeclared identifier glewInit; did you mean glutInit?"
"Too few argument to function call, expected 2, have 0"
The code is lengthy is been written by my professor and it runs on ubuntus. But with the errors, I'm thinking that the reasons is...well, underclared identifier, include is missing. So, after googling I figured out that glewInit is part of the glew library -> so I downloaded the code and installed it on my machine with following:
make
sudo -s
make install
which were successfully installed into my /usr/include/GL. Now, when i type into xcode #include or just #include , the compiler throws that glew.h is not found (though i can i see the file myself in the usr/include/GL).
Here is the code:
#include "include/Angel.h"
// The rotation around z axis
GLfloat Theta = 0.0; // Angle (in degrees)
GLfloat step = 0.01; // Incremental
GLuint locTheta;
enum { CW = 0, CCW = 1};
int direction = CW; // Direction
//Scale along x and y axes
GLfloat ScaleFactor[2] = {1.0, 1.0};
GLuint locScale;
const int NumPoints = 4;
void init();
void display( void );
void reshape( GLsizei w, GLsizei h );
void keyboard( unsigned char key, int x, int y );
void mouse( int button, int state, int x, int y );
void idle( void );
//----------------------------------------------------------------------------
// OpenGL initialization
void init()
{
// Vertices of a unit square centered at origin, sides aligned with axes
vec4 points[] = {
vec4( -0.5, -0.5, 0, 1.0 ), //v1
vec4( 0.5, -0.5, 0, 1.0 ), //v2
vec4( -0.5, 0.5, 0, 1.0 ), //v3
vec4( 0.5, 0.5, 0, 1.0 ) //v4
};
// RGBA colors
vec4 colors[] = {
vec4( 1.0, 0.0, 0.0, 1.0 ), // red
vec4( 0.0, 1.0, 0.0, 1.0 ), // green
vec4( 0.0, 1.0, 0.0, 1.0 ), // green
vec4( 0.0, 0.0, 1.0, 1.0 ), // blue
};
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors), NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(points), points );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(points), sizeof(colors), colors );
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader_rot.glsl", "fshader_rot.glsl" );
glUseProgram( program );
// set up vertex arrays
GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0) );
GLuint vColor = glGetAttribLocation( program, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(sizeof(points)) );
// The location of shader uniform variables
locTheta = glGetUniformLocation( program, "theta" );
locScale = glGetUniformLocation( program, "scale" );
glClearColor( 1.0, 1.0, 1.0, 1.0 );
}
//----------------------------------------------------------------------------
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform1f( locTheta, Theta );
glUniform2fv( locScale, 1, ScaleFactor );
glDrawArrays( GL_TRIANGLE_STRIP, 0, NumPoints);
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void reshape( GLsizei w, GLsizei h )
{
glViewport(0, 0, w, h);
// Scale the square to avoid stretching
if (w > h) ScaleFactor[0] = (float)h/w;
if (w < h) ScaleFactor[1] = (float)w/h;
}
//----------------------------------------------------------------------------
void keyboard( unsigned char key, int x, int y )
{
switch( key ) {
case 033: // Escape Key
case 'q': case 'Q':
exit( EXIT_SUCCESS );
break;
}
}
//----------------------------------------------------------------------------
void mouse( int button, int state, int x, int y )
{
if ( state == GLUT_DOWN ) {
switch( button )
{
case GLUT_LEFT_BUTTON:
direction = CCW;
break;
case GLUT_RIGHT_BUTTON:
direction = CW;
break;
}
}
}
//----------------------------------------------------------------------------
void idle( void )
{
// Animate the rotation
if (direction == CW)
Theta += step;
else
Theta -= step;
if ( Theta > 360.0 ) {
Theta -= 360.0;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize( 512, 512 );
glutCreateWindow( "Rotating Color Square" );
glewInit();
init();
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutMouseFunc( mouse );
glutIdleFunc( idle );
glutMainLoop();
return 0;
}
I have Lion 10.7.4 and xCode 4.2.1
glewInit() call (and the includes, of course) is not necessary on MacOS, so you might just exclude it this way:
#ifndef __APPLE__
glewInit();
#endif
The same with includes.
Now with the unresolved symbols. You have to include MacOSX's native GL headers:
#ifdef __APPLE__
# include <OpenGL/gl.h>
# include <OpenGL/glext.h>
#else /// your stuff for linux
# include "GL/GL.h"
.... whatever
#endif
OpenGL is a core technology for OSX, not an "extension", as in Linux/X Window. So just include the OpenGL and GLUT framework to your XCode project and hopefully it should build and work.