How to draw points efficiently - c++

My program receives PCL pointcloud and plot each point one by one using:
glBegin(GL_POINTS);
glVertex3f(point.x, point.y, point].z);
glEnd();
It works but due to the large number of points the program is pretty slow. Is there a more efficient way to do this?

Jam all the points into a big VBO when the point-cloud changes & draw 'em all in one go using a single glDrawArrays() call. That way OpenGL can shift all the vertex data to GPU once instead of you spoon-feeding the driver geometry one glVertex() at a time every frame.
Heck, even vertex arrays will buy you a huge speed-up by avoiding hundreds of thousands of function-calls into the GL driver.
EDIT: Comparison:
10 million random points, using vertex buffer objects:
Vertex arrays:
Display lists:
And using immediate-mode:
Code (hit 'n' to cycle between drawing methods):
// http://glew.sourceforge.net/
#include <GL/glew.h>
// http://freeglut.sourceforge.net/
#include <GL/freeglut.h>
// http://glm.g-truc.net/
#include <glm/glm.hpp>
#include <glm/gtc/random.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <vector>
#include <sstream>
#include <chrono>
#include <cstddef>
struct Vertex
{
glm::vec4 pos;
glm::vec4 color;
};
std::vector< Vertex > verts;
GLuint vbo = 0;
GLuint dlist = 0;
void init()
{
// init geometry
for( size_t i = 0; i < 10000000; i++ )
{
Vertex vert;
vert.pos = glm::vec4( glm::linearRand( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( 1.0f, 1.0f, 1.0f ) ), 1.0f );
vert.color = glm::vec4( glm::linearRand( glm::vec3( 0.00f, 0.0f, 0.0f ), glm::vec3( 1.0f, 1.0f, 1.0f ) ), 1.0f );
verts.push_back( vert );
}
// create display list
dlist = glGenLists( 1 );
glNewList( dlist, GL_COMPILE );
glBegin( GL_POINTS );
for( size_t i = 0; i < verts.size(); ++i )
{
glColor4fv( glm::value_ptr( verts[i].color) );
glVertex4fv( glm::value_ptr( verts[i].pos) );
}
glEnd();
glEndList();
// create VBO
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, sizeof( Vertex ) * verts.size(), verts.data(), GL_STATIC_DRAW );
}
unsigned int method = 0;
void keyboard( unsigned char key, int x, int y )
{
if( 'n' == key )
{
method++;
if( method > 3 ) method = 0;
}
}
void display()
{
// timekeeping
static std::chrono::steady_clock::time_point prv = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point cur = std::chrono::steady_clock::now();
const float dt = std::chrono::duration< float >( cur - prv ).count();
prv = cur;
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective( 60.0, w / h, 0.1, 10.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( 2, 2, 2, 0, 0, 0, 0, 0, 1 );
static float angle = 0.0f;
angle += dt * 6.0f;
glRotatef( angle, 0, 0, 1 );
// render
switch( method )
{
case 0:
// VBO
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 4, GL_FLOAT, sizeof( Vertex ), (void*)offsetof( Vertex, pos ) );
glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), (void*)offsetof( Vertex, color ) );
glDrawArrays( GL_POINTS, 0, verts.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
break;
case 1:
// vertex array
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].pos );
glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].color );
glDrawArrays( GL_POINTS, 0, verts.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
break;
case 2:
// display list
glCallList( dlist );
break;
case 3:
// immediate mode
glBegin( GL_POINTS );
for( size_t i = 0; i < verts.size(); ++i )
{
glColor4fv( glm::value_ptr( verts[i].color) );
glVertex4fv( glm::value_ptr( verts[i].pos) );
}
glEnd();
break;
}
// info/frame time output
std::stringstream msg;
msg << "Using ";
switch( method )
{
case 0: msg << "vertex buffer object"; break;
case 1: msg << "vertex array"; break;
case 2: msg << "display list"; break;
case 3: msg << "immediate mode"; break;
}
msg << std::endl;
msg << "Frame time: " << (dt * 1000.0f) << " ms";
glColor3ub( 255, 255, 0 );
glWindowPos2i( 10, 25 );
glutBitmapString( GLUT_BITMAP_9_BY_15, (unsigned const char*)( msg.str().c_str() ) );
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glewInit();
init();
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutIdleFunc( display );
glutMainLoop();
return 0;
}

Yes definitely, the code you are showing is from a quite old version of OpenGL.
In more recent versions you can pack your data together and send it to the GPU in one call. The code becomes a little bit more complex but it is worth it.
I suggest you to look at this website : https://learnopengl.com/
It gathers everything you need to start using modern opengl.
Hope it helped.

Related

How to map texture to sphere that rendered by parametric equation using points primitive

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:

Creating structure for geometry data

I want to draw multiple polygons in one buffer, here is my conception of how I think it should work, but it does not.
This is what I have:
GLuint VertexArrayID;
GLuint vao;
GLuint program;
typedef struct object{
GLuint vao;
GLuint numVertices;
} object;
object objects[MAX_VERTEX_COUNT];
Here I create VBO:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, VertexArrayID);
glBufferData(GL_ARRAY_BUFFER, 2 * vertex_count * sizeof(float), data, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(data), data);
glUseProgram(program);
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glVertexPointer(2, GL_FLOAT, 0, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
//glDrawArrays(GL_TRIANGLE_FAN, 0, vertex_count);
And I made loop like that, but I think, when I put vao in objects[i].vao, every time when I came through that loop, it does the same without this loop, but I am not sure.
for (int i = 0; i < 5; i++)
{
objects[i].vao = vao;
glBindVertexArray(objects[i].vao);
objects[i].numVertices = vertex_count;
glDrawArrays(GL_TRIANGLE_FAN, 0, objects[i].numVertices);
}
glDisableClientState(GL_VERTEX_ARRAY);
Maybe you have some ideas?
Here I have an Image2D class object that is used to render basic 2D Images that works with my GUI hierarchy. My Shader Engine is quite large for I have a system to manage Shaders using template types. It also uses a Batch Process and all of my Assets that are loaded into memory are saved into a Storage class that handles the clean up of their memory footprint. It is too large of a project to show everything necessary to be able to compile a working program, but here is an example of a generated renderable object from within my ShaderEngine.
Image2d.h
class Image2d : public VisualMko {
private:
TextureInfo m_textureInfo;
// --- Only For Version 1.0 ---
// VBO //
unsigned m_vboTexture; //
unsigned m_vboPosition; //
unsigned m_vboIndices; //
// //
// VAO //
unsigned m_vao; //
// ------------------------- //
// version 2.0 variables below
glm::vec2 m_offsetPosition;
public:
Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId );
Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId = std::string() );
virtual ~Image2d();
void setOffsetPosition( const glm::vec2& offset );
virtual void clearTextureInfos() override;
void render() override;
TextureInfo getTextureInfo() const;
void setTextureInfo( const TextureInfo& textureInfo );
private:
Image2d( const Image2d& c ); // Not Implemented
Image2d& operator=( const Image2d& c );
}; // Image2d
} // namespace vmk
#endif // IMAGE2D_H
Image2d.cpp
#include "stdafx.h"
#include "Image2d.h"
#include "AssetStorage.h"
#include "ShaderManager.h" // Only Needed For Version 1.0
#include "TextureFileReader.h"
namespace vmk {
// ----------------------------------------------------------------------------
// Image2d()
// Creates A Rectangular 2D Imgae Of The Size Specified And Stores It In A
// Vertex Array Object For Rendering. The Surface Verts Are Defined Like:
// width
// <------->
// v0 --- v2 ^
// : / : | height
// : / : |
// v1 --- v3 v
//
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
if ( fWidth <= 0 || fHeight <= 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
throw ExceptionHandler( strStream );
}
// Save TextureID
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );
// Define Texture Coordinates
std::vector<float> vTextureCoordinates;
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0.0f );
// Define Vertex Positions (x,y,z)
std::vector<float> vVertexPositions;
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( 0.0f );
vVertexPositions.push_back( 0.0f );
// Define 2 Triangle Faces
std::vector<unsigned char> vIndices;
vIndices.push_back( 0 );
vIndices.push_back( 1 );
vIndices.push_back( 2 );
vIndices.push_back( 3 );
// Create Vertex Array Object
glGenVertexArrays( 1, &m_vao );
glBindVertexArray( m_vao ); // Start Array
m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );
// Create Position Buffer And Store On Video Card
glGenBuffers( 1, &m_vboPosition );
glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_POSITION );
// Create Texture Coordinate Buffer
glGenBuffers( 1, &m_vboTexture );
glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );
// Create Index Buffer
glGenBuffers( 1, &m_vboIndices );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );
glBindVertexArray( 0 ); // Stop Array
// Disable Attribute Pointers
m_pShaderManager->disableAttribute( A_POSITION );
m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );
// THIS MUST BE AFTER: Vertex Array Buffer Is Unbound!
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer
} // Image2d - v1.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
m_version = 2;
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
m_config.uTextureId = m_textureInfo.uTextureId;
if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
throw ExceptionHandler( strStream );
}
// Verify Image Fits Inside Texture
if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
<< " which is too small for an image that is " << size
<< " pixels in size, with an origin point set at " << origin ;
throw ExceptionHandler( strStream );
}
glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
1.0f / static_cast<float>( m_textureInfo.size.y ) );
glm::vec2 texCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
glm::vec2 texCoordTopRight = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
textureCoordScaleFactor.y * (m_textureInfo.size.y - origin.y ) );
// Set Colors And Texture Coordinates (Position Will Be Updated In Render Function
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordBottomLeft.x, texCoordBottomLeft.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x, texCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( texCoordTopRight.x, texCoordBottomLeft.y ) ) );
} // Image2d() - v2.0
// ----------------------------------------------------------------------------
// ~Image2d()
Image2d::~Image2d() {
if ( 1 == m_version ) {
// Destroy Objects
if ( m_vboTexture != 0 ) {
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboTexture );
m_vboTexture = 0;
}
if ( m_vboPosition != 0 ) {
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboPosition );
m_vboPosition = 0;
}
if ( m_vboIndices != 0 ) {
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &m_vboIndices );
m_vboIndices = 0;
}
if ( m_vao != 0 ) {
glBindVertexArray( 0 );
glDeleteVertexArrays( 1, &m_vao );
m_vao = 0;
}
}
} // Image2d
// ----------------------------------------------------------------------------
// setOffsetPosition()
void Image2d::setOffsetPosition( const glm::vec2& offset ) {
if ( offset.x != m_offsetPosition.x || offset.y != m_offsetPosition.y ) {
m_offsetPosition = offset;
m_transformMatrix.updateTranslation = true;
}
} // setOffsetPosition
// ----------------------------------------------------------------------------
// clearTextureInfos()
void Image2d::clearTextureInfos() {
if ( m_pAssetStorage->removeTextureInfo( m_textureInfo.uTextureId ) ) {
m_textureInfo = TextureInfo();
}
} // clearTextureInfos
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
if ( 1 == m_version ) {
m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );
glBindVertexArray( m_vao );
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
glBindVertexArray( 0 );
} else {
// Version 2.0
// Update Vertices
if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;
// Order Of Operations Matter Here!
glm::mat4 matrix; // identity
if ( m_transformMatrix.hasTranslation ) {
matrix[3][0] = m_transformMatrix.translation.x;
matrix[3][1] = m_transformMatrix.translation.y;
}
if ( m_transformMatrix.hasRotation ) {
matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleDegrees, glm::vec3( 0.0f, 0.0f, -1.0f ) );
}
if ( m_transformMatrix.hasScale ) {
matrix = matrix * glm::mat4( m_transformMatrix.scale.x, 0.0f, 0.0f, 0.0f,
0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f );
}
// Center Offset
if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
}
// Apply Transformation To All 4 Vertices
m_vVertices[0].position = glm::vec2( matrix * glm::vec4( 0, 0, 0, 1.0f ) );
m_vVertices[1].position = glm::vec2( matrix * glm::vec4( 0, m_size.y, 0, 1.0f ) );
m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x, 0, 0, 1.0f ) );
m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
}
renderBatch();
}
} // render
// ----------------------------------------------------------------------------
// getTextureInfos()
TextureInfo Image2d::getTextureInfo() const {
return m_textureInfo;
} // getTextureInfo
// ----------------------------------------------------------------------------
// setTextureInfo()
void Image2d::setTextureInfo( const TextureInfo& textureInfo ) {
m_textureInfo = textureInfo;
} // setTextureInfo
} // namespace vmk
Now this class has two constructors which will get called depending on which version of the Image2d is being used. If I remember correctly version 1 does not use the BatchManager or Batch Process while version 2 does. If you look at the 1st Constructor. glBindVertexArray( 0 ); and glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); methods are called to stop the arrays and buffers. In render call in the first section of the if statement again we call glBindVertexArray( 0 ); to stop the array.
If you look at the destructor version 2 does not get cleaned up due to the fact that it is being used through the BatchManager and everything that is used through the BatchManager is automatically cleaned up and handled by my AssetStorage class. However, since version 1 of this class does not use the BatchManager it has to clean itself up and you can see the calls to glBindBuffer( BUFFER_ENUMERATED_TYPE, 0 ); followed by a glDeleteBuffers(...); call then setting the VBOs and VAO to 0.
If you would like to know more about this and how to successfully build a 3D Graphics ShaderEngine using modern OpenGL visit http://www.marekknows.com for this is where I have learned how to successfully use OpenGL. These works are not of my own design, but everything in this Engine was manually typed and debugged by following Marek's video tutorials.

my sprites are switching between textures opengl

I'm drawing sprites that are all in a buffer using glDrawElements.
To tell sprites what texture to be in the fragment shader I have uniform sampler2D textures[32]; each vertex has an index, which is passed to the fragment shader from the vertex shader:
color = texture(textures[index], fs_in.uv);
when I try draw my sprites with more than 1 texture active it gets the wrong textures in the top right corner
http://puu.sh/lyr5j/d8c2cf6c8f.png
I have no clue why this is happening have tried texture parameters
I cant seem to find anyone who has had a similar problem.
This is my renderer's init function (I am purposly passing the texid as float since I have heard ints don't work well (also tried))
glGenBuffers(1, &m_VDBO);
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
glBindBuffer(GL_ARRAY_BUFFER, m_VDBO);
glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_VERTEX_INDEX);
glEnableVertexAttribArray(SHADER_UV_INDEX);
glEnableVertexAttribArray(SHADER_COLOR_INDEX);
glEnableVertexAttribArray(SHADER_TEXID_INDEX);
glVertexAttribPointer(SHADER_VERTEX_INDEX, 3, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::vertex));
glVertexAttribPointer(SHADER_UV_INDEX, 2, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::uv));
glVertexAttribPointer(SHADER_COLOR_INDEX, 4, GL_UNSIGNED_BYTE, GL_TRUE, RENDERER_VERTEX_SIZE, (const void *) offsetof(VertexData, VertexData::color));
glVertexAttribPointer(SHADER_TEXID_INDEX, 1, GL_FLOAT, GL_FALSE, RENDERER_VERTEX_SIZE, (const void *)offsetof(VertexData, VertexData::texID));
glBindBuffer(GL_ARRAY_BUFFER, 0);
const GLushort modelindices[] = { 0, 1, 2, 2, 3, 0 };
GLuint indices[RENDERER_INDICES_SIZE];
for (int i = 0; i < RENDERER_INDICES_SIZE; i += 6)
{
for (int o = 0; o < 6; o++)
{
indices[i + o] = modelindices[o] + (i / 6 * 4);
}
}
glGenBuffers(1, &m_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, RENDERER_INDICES_SIZE * sizeof(GLuint), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
the flush function
glBindVertexArray(m_VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
for (int i = 0; i < m_TextureSlots.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_TextureSlots[i]);
}
glDrawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, 0);
m_TextureSlots.clear();
m_IndexCount = 0;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
It is hard for me to see where your problem is coming from, the only thing I can suggest is taking a look at an Image2d class object constructor that I have. Now, my source depends on outside classes such as a ShaderManager class that relies heavily on template types and a Batch class and a BatchManager class to send over the vertices to the video card. Also this Image2d is an inherited object. However, this may serve as some help to you in tracking down your own problem. There are two different constructors for different versions of the implementation depending on which version of OpenGL and GLSL is being used. If I remember correctly version 2 uses the BatchManager to send the vertices to the video card where version 1 doesn't which can be seen within the render() method.
Image2d v1.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( float fWidth, float fHeight, TextureInfo::FilterQuality filterQuality, bool generateMipMap, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( glm::uvec2(), strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
if ( fWidth <= 0 || fHeight <= 0 ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid image size (" << fWidth << "," << fHeight << ") must be more then 0 in each dimension.";
throw ExceptionHandler( strStream );
}
// Save TextureId
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( filterQuality, generateMipMap, false );
// Define Texture Co-Ordinates
std::vector<float> vTextureCoordinates;
vTextureCoordinates.push_back( 0.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 0 );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 1.0f );
vTextureCoordinates.push_back( 0 );
// Define Vertex Positions (x,y,z)
std::vector<float> vVertexPositions;
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( fHeight );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( fWidth );
vVertexPositions.push_back( 0 );
vVertexPositions.push_back( 0 );
// Define 2 Triangle Faces
std::vector<unsigned char> vIndices;
vIndices.push_back( 0 );
vIndices.push_back( 1 );
vIndices.push_back( 2 );
vIndices.push_back( 3 );
// Create Vertex Array Object
glGenVertexArrays( 1, &m_vao );
glBindVertexArray( m_vao ); // Start Array
m_pShaderManager->setAttribute( A_COLOR, COLOR_WHITE );
// Create Position Buffer And Store On Video Card
glGenBuffers( 1, & m_vboPosition );
glBindBuffer( GL_ARRAY_BUFFER, m_vboPosition );
glBufferData( GL_ARRAY_BUFFER, vVertexPositions.size() * sizeof( vVertexPositions[0] ), &vVertexPositions[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_POSITION );
// Create Texture Coordinate Buffer
glGenBuffers( 1, &m_vboTexture );
glBindBuffer( GL_ARRAY_BUFFER, m_vboTexture );
glBufferData( GL_ARRAY_BUFFER, vTextureCoordinates.size() * sizeof( vTextureCoordinates[0] ), &vTextureCoordinates[0], GL_STATIC_DRAW );
m_pShaderManager->enableAttribute( A_TEXTURE_COORD0 );
// Create Index Buffer
glGenBuffers( 1, &m_vboIndices );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_vboIndices );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, vIndices.size() * sizeof( vIndices[0] ), &vIndices[0], GL_STATIC_DRAW );
glBindVertexArray( 0 ); // Stop Array
// Disable Attribute Pointers
m_pShaderManager->disableAttribute( A_POSITION );
m_pShaderManager->disableAttribute( A_TEXTURE_COORD0 );
// THIS MUST BE AFTER Vertex Array Buffer Is Unbound!
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // Stop Buffer Index
glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Stop Buffer
// We have a Valid Image2d Save Filename
m_strFilename = strTextureFilename;
} // Image2D - v1.0
Image2D - v2.0
// ----------------------------------------------------------------------------
// Image2d()
Image2d::Image2d( const glm::uvec2& origin, const glm::uvec2& size, const std::string& strTextureFilename, const std::string& strId ) :
VisualMko( size, strId ),
m_vboTexture( 0 ),
m_vboPosition( 0 ),
m_vboIndices( 0 ),
m_vao( 0 ) {
m_version = 2;
TextureFileReader textureFileReader( strTextureFilename );
m_textureInfo = textureFileReader.getOrCreateTextureInfo( TextureInfo::FILTER_NONE, false, false );
m_config.uTextureId = m_textureInfo.uTextureId;
if ( 0 == m_textureInfo.size.x || 0 == m_textureInfo.size.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << "size of " << strTextureFilename << " is invalid " << m_textureInfo.size;
throw ExceptionHandler( strStream );
}
// Verify Image Fits Inside Texture
if ( m_textureInfo.size.x < size.x + origin.x || m_textureInfo.size.y < size.y + origin.y ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " " << strTextureFilename << " size is " << m_textureInfo.size
<< " which is too small for an image that is " << size
<< " pixels in size, with an origin point set at " << origin ;
throw ExceptionHandler( strStream );
}
glm::vec2 textureCoordScaleFactor( 1.0f / static_cast<float>( m_textureInfo.size.x ),
1.0f / static_cast<float>( m_textureInfo.size.y ) );
glm::vec2 textureCoordBottomLeft = glm::vec2( textureCoordScaleFactor.x * origin.x,
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y - size.y ) );
glm::vec2 textureCoordTopRight = glm::vec2( textureCoordScaleFactor.x * ( origin.x + size.x ),
textureCoordScaleFactor.y * ( m_textureInfo.size.y - origin.y ) );
// Set Colors And Texture Coordinates (Position Will Be Updated In Render Function)
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordBottomLeft.x, textureCoordBottomLeft.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordTopRight.y ) ) );
m_vVertices.push_back( GuiVertex( glm::vec2(), COLOR_WHITE, glm::vec2( textureCoordTopRight.x, textureCoordBottomLeft.y ) ) );
} // Image2d - v2.0
and here is my render() method
// ----------------------------------------------------------------------------
// render()
void Image2d::render() {
if ( 1 == m_version ) {
m_pShaderManager->setTexture( 0, U_TEXTURE0_SAMPLER_2D, m_textureInfo.uTextureId );
glBindVertexArray( m_vao );
glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, nullptr );
glBindVertexArray( 0 );
} else {
// Version 2.0
// Update Vertices
if ( m_transformMatrix.updateTranslation || m_transformMatrix.updateScale || m_transformMatrix.updateRotation ) {
m_transformMatrix.updateTranslation = m_transformMatrix.updateScale = m_transformMatrix.updateRotation = false;
// Order Of Operations Matter Here!
glm::mat4 matrix; // Identity
if ( m_transformMatrix.hasTranslation ) {
matrix[3][0] = m_transformMatrix.translation.x;
matrix[3][1] = m_transformMatrix.translation.y;
}
if ( m_transformMatrix.hasRotation ) {
matrix = glm::rotate( matrix, m_transformMatrix.fRotationAngleRadians, glm::vec3( 0.0f, 0.0f, -1.0f ) );
}
if ( m_transformMatrix.hasScale ) {
matrix = matrix * glm::mat4( m_transformMatrix.scale.x, 0.0f, 0.0f, 0.0f,
0.0f, m_transformMatrix.scale.y, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f );
}
// Center Offset
if ( m_offsetPosition.x != 0 || m_offsetPosition.y != 0 ) {
matrix = glm::translate( matrix, glm::vec3( -m_offsetPosition.x, -m_offsetPosition.y, 0.0f ) );
}
// Apply Transformation To All 4 Vertices
m_vVertices[0].position = glm::vec2( matrix * glm::vec4( 0, 0, 0, 1.0f ) );
m_vVertices[1].position = glm::vec2( matrix * glm::vec4( 0, m_size.y, 0, 1.0f ) );
m_vVertices[2].position = glm::vec2( matrix * glm::vec4( m_size.x, 0, 0, 1.0f ) );
m_vVertices[3].position = glm::vec2( matrix * glm::vec4( m_size.x, m_size.y, 0, 1.0f ) );
}
renderBatch();
}
} // render
Make sure that the sizes you are specifying in your glBufferData(GL_ARRAY_BUFFER, RENDERER_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
is accurate. Also make sure that you are stopping your your VertexArray at the appropriate time as well as disabling your Attribute Pointers. Everything that you bound must be unbound, and for some types Order does matter!

Bind SDL2 texture to GLSL shader

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.

glewInit() fails on macOS

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.