My program doesn't display anything on the screen. I've tried several things but nothing worked.
Here's my source, vertex and fragment shader:
Renderer.cpp:
#include "Renderer.h"
Renderer::Renderer( Camera& camera, float w, float h )
:
cam( camera ),
winW( w ),
winH( h )
{}
Renderer::~Renderer()
{
glDeleteBuffers( 1, &quad );
glDeleteBuffers( 1, &color );
glDeleteBuffers( 1, &UV );
glDeleteVertexArrays( 1, &vao );
}
void Renderer::load()
{
projectionMatrix = glm::mat4( 1.0f );
projectionMatrix = glm::perspective<float>( 45.0f, (float) winW / (float) winH, 0.01f, 100.0f );
shader.loadAndCompile( "Res/Shaders/std.vs", "Res/Shaders/std.fs" );
texture.loadTexture( "Res/Tex/sheet.png" );
texture.bind();
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
Vertex quadArray[] = {
{ -0.5, -0.5, 0.0 },
{ -0.5, 0.5, 0.0 },
{ 0.5, -0.5, 0.0 },
{ 0.5, -0.5, 0.0 },
{ 0.5, 0.5, 0.0 },
{ -0.5, 0.5, 0.0 }
};
glUseProgram( shader.getProgram() );
MVPLocation = glGetUniformLocation( shader.getProgram(), "MVP" );
glGenBuffers( 1, &quad );
glBindBuffer( GL_ARRAY_BUFFER, quad );
glBufferData( GL_ARRAY_BUFFER, sizeof( quadArray ), quadArray, GL_STATIC_DRAW );
glGenBuffers( 1, &color );
glBindBuffer( GL_ARRAY_BUFFER, color );
glBufferData( GL_ARRAY_BUFFER, 48, NULL, GL_STREAM_DRAW );
glGenBuffers( 1, &UV );
glBindBuffer( GL_ARRAY_BUFFER, UV );
glBufferData( GL_ARRAY_BUFFER, 48, NULL, GL_STREAM_DRAW );
}
void Renderer::translate( glm::vec3 pos )
{
this->transMatrix = glm::translate( glm::mat4( 1.0f ), pos );
}
void Renderer::translate( float x, float y, float z )
{
translate( glm::vec3( x, y, z ) );
}
void Renderer::rotate( float angle, glm::vec3 axis )
{
this->rotationMatrix = glm::rotate( glm::mat4( 1.0f ), angle, axis );
}
void Renderer::scale( glm::vec3 scale )
{
this->scaleMatrix = glm::scale( glm::mat4( 1.0f ), scale );
}
void Renderer::scale( float x, float y, float z )
{
scale( glm::vec3( x, y, z ) );
}
void Renderer::drawSpriteBillboarded( glm::vec3 pos, glm::vec3 lookAtPos, int w, int h, int uP, int vP, glm::vec4 col )
{
int texW = texture.getWidth(), texH = texture.getHeight();
float u = (float) uP / (float) texW, v = (float) vP / (float) texH, uEnd = (float) ( uP + w ) / (float) texW, vEnd = (float) ( vP + h ) / (float) texH;
Color colArray[] = {
{ col.r, col.g, col.b, col.a },
{ col.r, col.g, col.b, col.a },
{ col.r, col.g, col.b, col.a },
{ col.r, col.g, col.b, col.a },
{ col.r, col.g, col.b, col.a },
{ col.r, col.g, col.b, col.a }
};
Vertex uvArray[] = {
{ u, v },
{ u, vEnd },
{ uEnd, v },
{ uEnd, v },
{ uEnd, vEnd },
{ u, vEnd }
};
translate( pos );
glm::vec2 dist = glm::vec2( lookAtPos.x, lookAtPos.z ) - glm::vec2( pos.x, pos.z );
rotate( atan2f( dist.y, dist.x ), glm::vec3( 0, 1, 0 ) );
scale( w / 16 * 1.0, h / 16 * 1.0, 1.0 );
modelMatrix = transMatrix * rotationMatrix * scaleMatrix;
camTransMatrix = glm::translate( glm::mat4( 1.0f ), cam.getPos() );
camRotationMatrix = glm::rotate( camRotationMatrix, cam.getRotX(), glm::vec3( 1, 0, 0 ) );
camRotationMatrix = glm::rotate( camRotationMatrix, cam.getRotY(), glm::vec3( 0, 1, 0 ) );
camRotationMatrix = glm::rotate( camRotationMatrix, cam.getRotZ(), glm::vec3( 0, 0, 1 ) );
viewMatrix = camTransMatrix * camRotationMatrix;
modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix;
glUniformMatrix4fv( MVPLocation, 1, GL_FALSE, &modelViewProjectionMatrix[ 0 ][ 0 ] );
glBindBuffer( GL_ARRAY_BUFFER, quad );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0 );
glBindBuffer( GL_ARRAY_BUFFER, color );
glBufferData( GL_ARRAY_BUFFER, sizeof( colArray ), colArray, GL_STREAM_DRAW );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (void*)0 );
glBindBuffer( GL_ARRAY_BUFFER, UV );
glBufferData( GL_ARRAY_BUFFER, sizeof( uvArray ), uvArray, GL_STREAM_DRAW );
glEnableVertexAttribArray( 2 );
glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}
void Renderer::drawSprite( glm::vec3 pos, int w, int h, int uP, int vP, glm::vec4 col )
{}
vertex shader
#version 330 core
layout(location = 0) in vec3 vertPosition;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 in_UV;
uniform mat4 MVP;
out vec4 col;
out vec2 uv;
void main(void)
{
gl_Position = MVP * vec4(vertPosition, 1.0);
col = color;
uv = in_UV;
}
fragment shader
#version 330 core
in vec4 col;
in vec2 uv;
out vec4 color;
uniform sampler2D tex;
void main(void)
{
vec4 Color = texture2D( tex, uv ) * col;
color = Color;
}
I call the drawSpriteBillboarded function from my Game class like so:
drawSpriteBillboarded( glm::vec3( 0, 0, -5 ), cam.getPos(), 16, 16, 0, 0, glm::vec3( 255, 255, 255, 255 ) );
The camera's position is at 0, 0, 0
I've tried changing the vertex shader to not multiply by the MVP matrix and also tried changing the fragment shader to this:
#version 330 core
in vec4 col;
in vec2 uv;
out vec4 color;
void main(void)
{
color = vec4(1.0, 1.0, 1.0, 1.0);
}
But it doesn't show anything either.
I've also tried changing GL_TRIANGLES to GL_POINTS, but nothing.
EDIT
I also added the loadAndCompile() function:
void Shader::loadAndCompile( const char* vertPath, const char* fragPath )
{
std::string vsCode = "";
std::ifstream vsStream( vertPath, std::ios::in );
fprintf( stdout, "loading vertex shader %s\n", vertPath );
if( vsStream.is_open() )
{
std::string line;
while( std::getline( vsStream, line ) )
vsCode += line + '\n';
vsStream.close();
}
else
{
fprintf( stderr, "Error: could not find vertex shader %s\n", vertPath );
return;
}
std::string fsCode = "";
std::ifstream fsStream( fragPath, std::ios::in );
fprintf( stdout, "loading fragment shader %s\n", fragPath );
if( fsStream.is_open() )
{
std::string line;
while( std::getline( fsStream, line ) )
fsCode += line + '\n';
fsStream.close();
}
else
{
fprintf( stderr, "Error: could not find fragment shader %s\n", fragPath );
return;
}
fprintf( stdout, "Compiling vertexShader %s\n", vertPath );
const char* vertCode = vsCode.c_str();
GLuint vertShader = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertShader, 1, &vertCode, NULL );
glCompileShader( vertShader );
GLint result = GL_FALSE;
int infoLogLength;
glGetShaderiv( vertShader, GL_COMPILE_STATUS, &result );
glGetShaderiv( vertShader, GL_INFO_LOG_LENGTH, &infoLogLength );
if( infoLogLength > 0 )
{
std::vector< char > errorMsg( infoLogLength );
glGetShaderInfoLog( vertShader, infoLogLength, NULL, &errorMsg[ 0 ] );
fprintf( stderr, "%s\n", &errorMsg[ 0 ] );
}
fprintf( stdout, "Compiling fragmentShader %s\n", fragPath );
const char* fragCode = fsCode.c_str();
GLuint fragShader = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragShader, 1, &fragCode, NULL );
glCompileShader( fragShader );
glGetShaderiv( fragShader, GL_COMPILE_STATUS, &result );
glGetShaderiv( fragShader, GL_INFO_LOG_LENGTH, &infoLogLength );
if( infoLogLength > 0 )
{
std::vector< char > errorMsg( infoLogLength );
glGetShaderInfoLog( fragShader, infoLogLength, NULL, &errorMsg[ 0 ] );
fprintf( stderr, "%s\n", &errorMsg[ 0 ] );
}
fprintf( stdout, "Linking program...\n" );
GLuint tmpProgID = glCreateProgram();
glAttachShader( tmpProgID, vertShader );
glAttachShader( tmpProgID, fragShader );
glLinkProgram( tmpProgID );
glGetProgramiv( tmpProgID, GL_LINK_STATUS, &result );
glGetProgramiv( tmpProgID, GL_INFO_LOG_LENGTH, &infoLogLength );
if( infoLogLength > 0 )
{
std::vector< char > errorMsg( infoLogLength );
glGetProgramInfoLog( tmpProgID, infoLogLength, NULL, &errorMsg[ 0 ] );
fprintf( stderr, "%s\n", &errorMsg[ 0 ] );
}
glDeleteShader( vertShader );
glDeleteShader( fragShader );
this->programID = tmpProgID;
}
So I'm basically asking you to check my code to see if I made a (silly) mistake.
Solved! - The winW and winH variables were not initialized when the constructor gets called.
I also had to change glDrawElements(...) to glDrawArrays(...)
Related
Is there some way to get OpenGL ES 3.0 to broadcast the value of a single-output fragment shader to all active (as per glDrawBuffers()) FBO color attachments?
If possible I'd like to keep my shaders more-or-less as-is and avoid the re-write required by multiple layout'd outputs:
layout( location = 0 ) out vec4 out_color0;
layout( location = 1 ) out vec4 out_color1;
layout( location = 2 ) out vec4 out_color2;
layout( location = 3 ) out vec4 out_color3;
void main()
{
out_color0 = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color1 = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color2 = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color3 = vec4( 1.0, 0.2, 0.0, 1.0 );
}
...or an output array:
out vec4 out_color[4];
void main()
{
out_color[0] = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color[1] = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color[2] = vec4( 1.0, 0.2, 0.0, 1.0 );
out_color[3] = vec4( 1.0, 0.2, 0.0, 1.0 );
}
Here's the program I'm using for testing, it (tries) to draw a red triangle to all four FBO attachments & then blits the 3rd attachment to the default framebuffer:
#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <cstdlib>
#include <cstdarg>
#include <iostream>
#include <vector>
struct Program
{
static GLuint Load( const char* shader, ... )
{
const GLuint prog = glCreateProgram();
va_list args;
va_start( args, shader );
while( shader )
{
AttachShader( prog, va_arg( args, GLenum ), shader );
shader = va_arg( args, const char* );
}
va_end( args );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
std::exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
const GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
const char* vert = 1 + R"GLSL(
#version 300 es
void main()
{
const vec2 verts[3] = vec2[3]
(
vec2( -0.5, -0.5 ),
vec2( 0.5, -0.5 ),
vec2( 0.0, 0.5 )
);
gl_Position = vec4( verts[ gl_VertexID ], 0.0, 1.0 );
}
)GLSL";
const char* frag = 1 + R"GLSL(
#version 300 es
precision mediump float;
out vec4 out_color;
void main()
{
out_color = vec4( 1.0, 0.2, 0.0, 1.0 );
}
)GLSL";
int main( int argc, char** argv )
{
glfwSetErrorCallback( []( int err, const char* desc )
{
std::cerr << "GLFW error: " << desc << std::endl;
} );
if( !glfwInit() )
return EXIT_FAILURE;
glfwWindowHint( GLFW_CLIENT_API, GLFW_OPENGL_ES_API );
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 0 );
glfwWindowHint( GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API );
GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
if( nullptr == window )
return EXIT_FAILURE;
glfwMakeContextCurrent( window );
glfwSwapInterval( 1 );
gladLoadGLES2Loader( (GLADloadproc)glfwGetProcAddress );
const GLuint prog = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
glUseProgram( prog );
// init framebuffer attachments
std::vector< GLuint > textures( 4, 0 );
glGenTextures( 4, textures.data() );
for( size_t i = 0; i < textures.size(); ++ i )
{
glBindTexture( GL_TEXTURE_2D, textures[i] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
}
GLuint rbDepth = 0;
glGenRenderbuffers(1, &rbDepth );
glBindRenderbuffer( GL_RENDERBUFFER, rbDepth );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32 );
// init FBO
GLuint fbo = 0;
glGenFramebuffers( 1, &fbo );
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
for( size_t i = 0; i < textures.size(); ++ i )
{
glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0 );
}
glFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbDepth );
if( GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus( GL_FRAMEBUFFER ) )
{
std::cerr << "Incomplete framebuffer" << std::endl;
std::exit( EXIT_FAILURE );
}
while( !glfwWindowShouldClose( window ) )
{
glfwPollEvents();
// render to FBO
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
GLenum bufs[] =
{
GL_COLOR_ATTACHMENT0 + 0,
GL_COLOR_ATTACHMENT0 + 1,
GL_COLOR_ATTACHMENT0 + 2,
GL_COLOR_ATTACHMENT0 + 3,
};
glDrawBuffers( 4, bufs );
glViewport( 0, 0, 32, 32 );
glClearColor( 0.0f, 0.6f, 1.0f, 1.f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glDrawArrays( GL_TRIANGLES, 0, 3 );
// switch back to default framebuffer & clear it with non-black color
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
GLenum defaultBuf = GL_BACK;
glDrawBuffers( 1, &defaultBuf );
glClearColor( 1.0f, 0.0f, 1.0f, 1.f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// blit a color attachment to the default framebuffer
glBindFramebuffer( GL_READ_FRAMEBUFFER, fbo );
glReadBuffer( GL_COLOR_ATTACHMENT0 + 2 );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBlitFramebuffer( 0, 0, 32, 32, 0, 0, 640, 480, GL_COLOR_BUFFER_BIT, GL_LINEAR );
glfwSwapBuffers( window );
}
glfwMakeContextCurrent( NULL );
glfwDestroyWindow( window );
glfwTerminate();
return EXIT_SUCCESS;
}
On this Windows 10 machine using a recent-ish ANGLE build I get the blue clear color but no triangle ("undefined") for the 3rd attachment:
The first attachment is fine:
No such functionality exists in the API:
3) Should we support broadcast from gl_FragColor to all gl_FragData[x]
or should it be synonymous with gl_FragData[0]?
DISCUSSION: With NV_draw_buffers, writing to gl_FragColor writes to all
the enabled draw buffers (ie broadcast). In OpenGL ES 3.0 when using
ESSL 1.0, gl_FragColor is equivalent to writing a single output to
gl_FragData[0] and multiple outputs are not possible. When using ESSL 3.0,
only user-defined out variables may be used.
If broadcast is supported, some implementations may have to replace
writes to gl_FragColor with replicated writes to all possible gl_FragData
locations when this extension is enabled.
RESOLVED: Writes to gl_FragColor are broadcast to all enabled color
buffers. ES 3.0 using ESSL 1.0 doesn't support broadcast because
ESSL 1.0 was not extended to have multiple color outputs (but that is
what this extension adds). ESSL 3.0 doesn't support the broadcast because
it doesn't have the gl_FragColor variable at all, and only has user-
defined out variables. This extension extends ESSL 1.0 to have multiple
color outputs. Broadcasting from gl_FragColor to all enabled color
buffers is the most consistent with existing draw buffer extensions to
date (both NV_draw_buffers and desktop GL).
I am trying to pass in a distance as a vertex attribute from my c++ code into the shader which draws a line between two vertices.
Currently one line has distance 0 (start), and the other has distance 1.0. I would expect this value to be interpolated just like the colors, but it does not seem to work. Thus I would expect half of the line to be red and the other green, but the whole line turns out green.
Fragment shader code below, where dist in the vertex shader comes in from layout(location = 2) in float in_dist and is passed out as out float dist (no operations performed).
in float dist;
Fragment getFragment()
{
Fragment frag;
frag.depth = vs_positionScreenSpace.w;
frag.gPosition = vs_gPosition;
if(dist > 0.5){
frag.color = vec4(1.0,0.0,0.0,1.0);
}else{
frag.color = vec4(0.0,1.0,0.0,1.0);
}
frag.gNormal = vec4(0.0, 0.0, 1.0, 0.0);
return frag;
}
Vertex shader
layout(location = 0) in vec3 in_point_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in float in_dist;
out float dist;
void main() {
//somestuff....
dist = in_dist;
}
Workin' fine here:
MCVE:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <vector>
#include <iostream>
#include <cstdarg>
struct Program
{
static GLuint Load( const char* shader, ... )
{
GLuint prog = glCreateProgram();
va_list args;
va_start( args, shader );
while( shader )
{
const GLenum type = va_arg( args, GLenum );
AttachShader( prog, type, shader );
shader = va_arg( args, const char* );
}
va_end( args );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
std::exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
const char* vert = R"GLSL(
#version 330 core
layout( location = 0 ) in vec4 inPos;
layout( location = 1 ) in float inDist;
out float dist;
void main()
{
dist = inDist;
gl_Position = inPos;
}
)GLSL";
const char* frag = R"GLSL(
#version 330 core
in float dist;
out vec4 outColor;
void main()
{
if( dist > 0.5 )
{
outColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
else
{
outColor = vec4( 0.0, 1.0, 0.0, 1.0 );
}
}
)GLSL";
int main( int argc, char** argv )
{
glfwInit();
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
glfwMakeContextCurrent( window );
glewInit();
glfwSwapInterval( 1 );
GLuint prog = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
glUseProgram( prog );
GLuint vao = 0;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo0 = 0;
glGenBuffers( 1, &vbo0 );
glBindBuffer( GL_ARRAY_BUFFER, vbo0 );
std::vector<float> data0 =
{
-0.5f, -0.5f,
0.5f, 0.5f,
};
glBufferData( GL_ARRAY_BUFFER, data0.size() * sizeof( std::vector<float>::value_type ), data0.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 0 , 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 0 );
GLuint vbo1 = 0;
glGenBuffers( 1, &vbo1 );
glBindBuffer( GL_ARRAY_BUFFER, vbo1 );
std::vector<float> data1 =
{
0.0f, 1.0f,
};
glBufferData( GL_ARRAY_BUFFER, data1.size() * sizeof( std::vector<float>::value_type ), data1.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 1 , 1, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 1 );
while( !glfwWindowShouldClose( window ) )
{
glfwPollEvents();
int w, h;
glfwGetFramebufferSize( window, &w, &h );
glViewport( 0, 0, w, h );
glClear( GL_COLOR_BUFFER_BIT );
glUseProgram( prog );
glBindVertexArray( vao );
glDrawArrays( GL_LINES, 0, 2 );
glfwSwapBuffers( window );
}
glfwDestroyWindow( window );
glfwTerminate();
}
Solved; The issue turned out to not be in the shader code, but in how the vertex attribute was defined att glVertexAttributePointer.
Could someone please explain me what is wrong in my code? When I try to run it I get a black window, but if I don't set the perspective matrix as I do in the 31th line I get the right solid (a pyramid) drawn on the window. Here's the main of the code. In the vertex shader I just define model, view and projection as uniform 4x4 matrices and multiply them by the poistion of the vertex and pass the colors of the vertices to the fragment shader. I don't think the problem is in those files but if you need them I'll post them.
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <string>
#include <fstream>
#include <sstream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
GLuint IBO, VBO, gModelLocation, gViewLocation, gProjectionLocation;
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
const char* VSfileName = "vertex.vs";
const char* FSfileName = "fragment.fs";
void RenderSceneCB()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glm::mat4 model;
model = glm::rotate( model, 0.0f, glm::normalize( glm::vec3( 1.0, 0.0, 0.0 ) ) );
glm::mat4 view;
view = glm::translate( view, glm::vec3( 0.0f, 0.0f, 0.0f ) );
glm::mat4 projection;
projection = glm::perspective( 90.0f, float( WINDOW_WIDTH ) / float( WINDOW_HEIGHT ), 0.1f, 100.0f );
glUniformMatrix4fv( gModelLocation, 1, GL_FALSE, &model[ 0 ][ 0 ] );
glUniformMatrix4fv( gViewLocation, 1, GL_FALSE, &view[ 0 ][ 0 ] );
glUniformMatrix4fv( gProjectionLocation, 1, GL_FALSE, glm::value_ptr( projection ) );
glBindBuffer( GL_ARRAY_BUFFER, VBO );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IBO );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)( 15 * sizeof( GLfloat ) ) );
glEnableVertexAttribArray( 1 );
glDrawElements( GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0 );
//glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray( 1 );
glDisableVertexAttribArray( 0 );
glutSwapBuffers();
}
void InizializeGlutCallBacks()
{
glutDisplayFunc( RenderSceneCB );
glutIdleFunc( RenderSceneCB );
}
void InizializeVertices()
{
GLfloat Vertices[ 9 ][ 3 ]
{
{ -0.5f, 0.5f, 0.0f},
{ 0.5f, -0.5f, 0.0f },
{ 0.5f, 0.5f, 0.0f},
{ -0.5f, -0.5f, 0.0f },
{ 0.0f, 0.0f, 1.0f},
{ 1.0f, 0.0f, 0.0f},
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f },
{ 1.0f, 1.0f, 1.0f}
};
GLint Indices[ 12 ]
{
0,2,4,0,3,4,1,2,4,1,3,4
};
glGenBuffers( 1, &VBO );
glGenBuffers( 1, &IBO );
glBindBuffer( GL_ARRAY_BUFFER, VBO );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IBO );
glBufferData( GL_ARRAY_BUFFER, sizeof( Vertices ), Vertices, GL_STATIC_DRAW );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( Indices ), Indices, GL_STATIC_DRAW );
}
void AddShader( GLuint ShaderProgram, const char* ShaderSource, GLenum ShaderType )
{
GLuint ShaderObj = glCreateShader( ShaderType );
if( ShaderObj == 0 )
{
fprintf( stderr, "Error creating Shader Object %d \n", ShaderType );
}
const GLchar* p[ 1 ];
p[ 0 ] = ShaderSource;
GLint Lengths[ 1 ];
Lengths[ 0 ] = strlen( p[ 0 ] );
glShaderSource( ShaderObj, 1, p, Lengths );
glCompileShader( ShaderObj );
GLint success;
glGetShaderiv( ShaderObj, GL_COMPILE_STATUS, &success );
if( !success )
{
GLchar InfoLog[ 1024 ];
glGetShaderInfoLog( ShaderObj, 1024, NULL, InfoLog );
fprintf( stderr, "Error Compiling Shader %d: '%s' \n", ShaderType, InfoLog );
}
glAttachShader( ShaderProgram, ShaderObj );
}
void CompileShaders()
{
GLuint ShaderProgram = glCreateProgram();
if( ShaderProgram == 0 )
{
fprintf( stderr, "Error creating Shader Program \n" );
}
string vs, fs;
ifstream VertexFile;
ifstream FragmentFile;
VertexFile.open( VSfileName );
if( !VertexFile )
{
std::cout << "Error in opening vertex.vs \n";
exit( 1 );
}
FragmentFile.open( FSfileName );
if( !FragmentFile )
{
std::cout << "Error in opening fragment.fs \n";
exit( 1 );
}
stringstream VertexStream;
stringstream FragmentStream;
VertexStream << VertexFile.rdbuf();
FragmentStream << FragmentFile.rdbuf();
vs = VertexStream.str();
fs = FragmentStream.str();
AddShader( ShaderProgram, vs.c_str(), GL_VERTEX_SHADER );
AddShader( ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER );
glLinkProgram( ShaderProgram );
GLint success;
glGetProgramiv( ShaderProgram, GL_LINK_STATUS, &success );
if( !success )
{
GLchar InfoLog[ 1024 ];
glGetProgramInfoLog( ShaderProgram, 1024, NULL, InfoLog );
fprintf( stderr, "Error in linking Shader '%s' \n", InfoLog );
}
glValidateProgram( ShaderProgram );
glGetProgramiv( ShaderProgram, GL_VALIDATE_STATUS, &success );
if( !success )
{
GLchar InfoLog[ 1024 ];
glGetProgramInfoLog( ShaderProgram, 1024, NULL, InfoLog );
fprintf( stderr, "Error in linking Shader '%s' \n", InfoLog );
}
//gScaleLocation = glGetUniformLocation(ShaderProgram, "gScale");
gModelLocation = glGetUniformLocation( ShaderProgram, "gModel" );
gViewLocation = glGetUniformLocation( ShaderProgram, "gView" );
gProjectionLocation = glGetUniformLocation( ShaderProgram, "gProjection" );
glUseProgram( ShaderProgram );
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA );
glutInitWindowSize( WINDOW_WIDTH, WINDOW_HEIGHT );
glutInitWindowPosition( 100, 100 );
glutCreateWindow( "Hello World" );
InizializeGlutCallBacks();
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
GLenum res = glewInit();
if( res != GLEW_OK )
{
std::cout << "Error, check please \n";
}
glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
glEnable( GL_DEPTH_TEST );
// enable alpha support
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
InizializeVertices();
CompileShaders();
glutMainLoop();
system( "pause" );
return 0;
}
First of all you should initialize all the matrizes (see glm returning nan on simple translate):
glm::mat4 model(1.0f);
glm::mat4 view(1.0f);
glm::mat4 projection(1.0f);
The geometry has to be in the clip space. When you setup the projection, then you define a near plan of 0.1 and a far plane of 100.0. This both values define the near and the far clipping plane.
This means you can only "see" the geomentry with a Z-component in the range [0.1, 100.0].
Setup the view matrix, to solve your issue.
glm::mat4 view(1.0f);
view = glm::translate( view, glm::vec3( 0.0f, 0.0f, -1.0f ) );
Further:
See the GLM documentation of glm::perspective, version 0.9.8:
LM_FUNC_DECL tmat4x4<T, defaultp> glm::perspective(T fovy, T aspect, T near, T far)
Creates a matrix for a symetric perspective-view frustum based on the default handedness.
Parameters
fovy Specifies the field of view angle in the y direction. Expressed in radians.
At the same place is noted for the version 0.9.4 (glm::perspective, version 0.9.4):
fovy Expressed in radians if GLM_FORCE_RADIANS is define or degrees otherwise.
This is because the GLM in general changed from degrees to radians a while ago.
Setup the perspective projection matrix like this:
projection = glm::perspective(
90.0f * (float)M_PI / 180.0,
float( WINDOW_WIDTH ) / float( WINDOW_HEIGHT ),
0.1f, 100.0f );
Explanation:
The view matrix describes the direction and position from which the scene is looked at. The view matrix transforms from the wolrd space to the view (eye) space.
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1). Every geometry which is out of the clippspace is clipped.
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport. The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
In general what I want is to read a specific vbo buffer in a custom way:
i have a buffer-> an array of 3 of class Triangle
class Triangle {
public:
CD_FLOAT3 a;
CD_FLOAT3 b;
CD_FLOAT3 c;
CD_FLOAT3 direction;
CD_FLOAT velocity;
CD_FLOAT3 color;
}
This is how i generate the vbo:
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And what I want from my render function is to render the 3 Vertices of the triangle than to skip for the stride as the sizeof(Triangle) (the next element). So i position the glVertexPointer to the 3 position of the points A,B,C accordingly. I only want one color ont the triangle as well, so i am using one glColorPointer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
glVertexPointer( 3, GL_FLOAT, sizeof(Triangle), 0);
glVertexPointer(3, GL_FLOAT, sizeof(Triangle), (void*)12);
glVertexPointer(3, GL_FLOAT, sizeof(Triangle), (void*)24);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, sizeof(Triangle), (void*)(sizeof(CD_FLOAT)*13));
glDrawArrays(GL_TRIANGLES, 0, numTriangles);
glDisableClientState(GL_COLOR_ARRAY);
The result of this function only draws one triangle, one point per stride, i think that the "glVertexPointer" only repositions the pointer so only the third triangle is drawn.
What i really want to know how can i make the reading of the buffer for the draw of the 3 triangles with:
Triangle1: a; b; c; color; STRIDE:
Triangle2: a; b; c; color; STRIDE
Triangle3: a; b; c; color;
You can't do what you want with fixed-function OpenGL.
Best you can do is duplicate your color attribute information and split off your kinematics state:
class Vertex {
public:
CD_FLOAT3 pos;
CD_FLOAT3 color;
};
class State {
public:
CD_FLOAT3 direction;
CD_FLOAT velocity;
};
const unsigned int NumTris = ...;
std::vector< State > states( NumTris );
std::vector< Vertex > verts( NumTris * 3 );
PopulateAndBindVBO();
glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), 0 );
glColorPointer( 3, GL_FLOAT, sizeof(Vertex), sizeof(CD_FLOAT3) );
glDrawArrays(GL_TRIANGLES, 0, NumTris );
You could use a geometry shader to split out an array of your Triangle structs into triangles though:
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <vector>
#include <cstddef>
using namespace std;
#include <glm/glm.hpp>
using namespace glm;
struct Program
{
static GLuint Load( const char* vert, const char* geom, const char* frag )
{
GLuint prog = glCreateProgram();
if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
exit( -1 );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
#define GLSL(version, shader) "#version " #version "\n" #shader
struct Triangle
{
glm::vec3 a;
glm::vec3 b;
glm::vec3 c;
glm::vec3 color;
glm::vec3 direction;
GLfloat velocity;
};
const char* vert = GLSL
(
330 core,
layout ( location = 0 ) in vec3 A;
layout ( location = 1 ) in vec3 B;
layout ( location = 2 ) in vec3 C;
layout ( location = 3 ) in vec3 Color;
out VertToGeom
{
vec3 A;
vec3 B;
vec3 C;
vec3 Color;
} outData;
void main()
{
outData.A = A;
outData.B = B;
outData.C = C;
outData.Color = Color;
}
);
const char* geom = GLSL
(
330 core,
in VertToGeom
{
vec3 A;
vec3 B;
vec3 C;
vec3 Color;
} inData[];
out GeomToFrag
{
vec3 Color;
} outData;
layout ( points ) in;
layout ( triangle_strip, max_vertices = 3 ) out;
void main()
{
gl_Position.xyz = inData[ 0 ].A;
outData.Color = inData[ 0 ].Color;
EmitVertex();
gl_Position.xyz = inData[ 0 ].B;
outData.Color = inData[ 0 ].Color;
EmitVertex();
gl_Position.xyz = inData[ 0 ].C;
outData.Color = inData[ 0 ].Color;
EmitVertex();
EndPrimitive();
}
);
const char* frag = GLSL
(
330 core,
in GeomToFrag
{
vec3 Color;
} inData;
void main()
{
gl_FragColor = vec4( inData.Color, 1.0 );
}
);
GLuint vbo = 0;
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
static GLuint prog = Program::Load( vert, geom, frag );
glUseProgram( prog );
vector< Triangle > tris( 2 );
tris[0].a = glm::vec3( 0, 0, 0 );
tris[0].b = glm::vec3( 1, 0, 0 );
tris[0].c = glm::vec3( 1, 1, 0 );
tris[0].color = glm::vec3( 1, 0, 0 );
tris[1].a = glm::vec3( 0, 0, 0 );
tris[1].b = glm::vec3( -1, 0, 0 );
tris[1].c = glm::vec3( -1, -1, 0 );
tris[1].color = glm::vec3( 0, 1, 0 );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, sizeof( Triangle ) * tris.size(), &tris[0], GL_STREAM_DRAW );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 0 ) );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 1 ) );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 2 ) );
glEnableVertexAttribArray( 2 );
glVertexAttribPointer( 3, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 3 ) );
glEnableVertexAttribArray( 3 );
glDrawArrays( GL_POINTS, 0, tris.size() );
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutSetOption( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS );
glutInitContextVersion( 3, 3 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glewExperimental = GL_TRUE;
glewInit();
GLuint vao = 0;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
glGenBuffers( 1, &vbo );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
you can try "glVertexAttribPointer"
https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml
I think you can store your data like this:
struct vertex
{
//posision
float x;
float y;
float z;
//color
float r;
float g;
float b;
}
GLuint buffer;
static const vertex vertices[]={....};
glGenBuffers(1,&buffer);
glBindBuffer(GL_ARRAY_BUFFER,buffer);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
//set up two vertex attributes---first positions
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(vertex),(void*)offsetof(vertex,x));
glEnableVertexAttribArray(0);
//now colors
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(vertex),(void*)offsetof(vertex,r));
glEnableVertexAttribArray(1);
I'm trying to draw part of a texture on a triangle. The triangle is defined by 3 points. One of the points will always be the center of the image. Now I want to draw a part of the texture on that triangle. So the triangle would cut out that part of the image and draw it on itself. But I don't want the texture to scale when drawn. It has to stay the same. So even if the triangle's base points fall outside of the image. The image can't be scaled. I don't understand how this can be done. Whenever I play around with texturing, the image gets scaled or drawn multiple times it seems.
Here is an image: so the red triangle would be drawn exactly like that in openGL.
In your fragment shader check the s & t values on your texcoord and discard if either is less than zero or greater than one.
EDIT: Example:
// g++ main.cpp -o main -lglut -lGLEW
#include <GL/glew.h>
#include <GL/glut.h>
#include <vector>
#include <iostream>
using namespace std;
void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE, len = 10;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_INFO_LOG_LENGTH, &len );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &len );
vector< char > log( len, 'X' );
if( glIsShader(obj) ) glGetShaderInfoLog( obj, len, NULL, &log[0] );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, len, NULL, &log[0] );
cerr << &log[0] << endl;
exit( -1 );
}
GLuint LoadShader( GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
return shader;
}
GLuint LoadProgram( const char* vert, const char* geom, const char* frag )
{
GLuint program = glCreateProgram();
if( vert ) glAttachShader( program, LoadShader( GL_VERTEX_SHADER, vert ) );
if( geom ) glAttachShader( program, LoadShader( GL_GEOMETRY_SHADER, geom ) );
if( frag ) glAttachShader( program, LoadShader( GL_FRAGMENT_SHADER, frag ) );
glLinkProgram( program );
CheckStatus( program );
return program;
}
#define GLSL(version, shader) "#version " #version "\n" #shader
const GLchar* vert = GLSL
(
120,
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
);
const GLchar* frag = GLSL
(
120,
uniform sampler2D texture;
void main()
{
if( any( lessThan( gl_TexCoord[0].st, vec2( 0.0, 0.0 ) ) ) ||
any( greaterThan( gl_TexCoord[0].st, vec2( 1.0, 1.0 ) ) ) )
{
gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );
//discard;
}
else
{
gl_FragColor = texture2D( texture, gl_TexCoord[0].st );
}
}
);
GLuint prog = 0;
GLuint tex = 0;
void init()
{
prog = LoadProgram( vert, NULL, frag );
unsigned char bits[ 32 * 32 * 4 ];
for( unsigned int i = 0; i < 32*32; ++i )
{
bits[i*4 + 0] = rand() % 255;
bits[i*4 + 1] = rand() % 255;
bits[i*4 + 2] = rand() % 255;
bits[i*4 + 3] = 255;
}
glGenTextures( 1, &tex );
glBindTexture( GL_TEXTURE_2D, tex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexImage2D( GL_TEXTURE_2D, 0, 4, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits );
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -3 * ar, 3 * ar, -3, 3, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glUseProgram( prog );
glUniform1i( glGetUniformLocation( prog, "texture" ), 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, tex );
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.5, 0.5 );
glVertex2f( 0, 0 );
glTexCoord2f( 1.5, 0.5 );
glVertex2f( 2, 0 );
glTexCoord2f( 0.5, 1.5 );
glVertex2f( 0, 2 );
glEnd();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640,480 );
glutCreateWindow( "test" );
glutDisplayFunc( display );
glewInit();
init();
glutMainLoop();
return 0;
}