OpenGL in Windows Forms (c++) - Buffer overflows? - winforms

I wrote a program in c++ using Windows forms. I use two Forms. The first form only contains a button. When it is pressed, a second form opens. This form contains a panel where a simple OpenGL simulation is played (rotated with the help of a timer provided by windows forms). The second form can be closed and opend again by pressing the botton in the first Form. The more often this is done, the slower the 3D-OpenGL-object rotates. After doing this for about 6 times the 3D-OpenGL-object starts to flicker totally crazy. I think it has to do with the fact, that the OpenGL-Object I construct is not destroyed properly and at a certain point the memory is full (in a more complicated version of the project it was flickering between the current 3D-object and a 3D object that should have been destroyed after the window was closed).
Here is a video of the Problem.
here is the code of OpenGL:
namespace OpenGLForm
{
public ref class COpenGL: public System::Windows::Forms::NativeWindow
{
public:
// Position/Orientation of 3D Mesh in Mesh-Viewer Window
float meshPos_x;
float meshPos_y;
float meshPos_z;
float meshOri_x;
float meshOri_y;
float meshOri_z;
COpenGL(System::Windows::Forms::Panel ^ parentForm, GLsizei iWidth, GLsizei iHeight)
{
// initialize all parameter / set pointers (for pointers of type MAT)
meshPos_x = 0.0;
meshPos_y = 0.0;
meshPos_z = -2.0;
meshOri_x = -63.0;
meshOri_y = 0.0;
meshOri_z = 0.0;
CreateParams^ cp = gcnew CreateParams;
m_hDC = GetDC((HWND)parentForm->Handle.ToPointer());
System::String^ filename = "C:/Advantech/Desktop/Const.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Const");
csvWriter->Close();
if(m_hDC)
{
MySetPixelFormat(m_hDC);
ReSizeGLScene(iWidth, iHeight);
InitGL();
}
}
//custom function for transformations
System::Void Transform(float xTrans, float yTrans, float zTrans, float xRot, float yRot, float zRot)
{
//translate object
glTranslatef(xTrans, yTrans, zTrans);
//rotate along x-axis
glRotatef(xRot,1.0f,0.0f,0.0f);
//rotate along y-axis
glRotatef(yRot,0.0f,1.0f,0.0f);
//rotate along z-axis
glRotatef(zRot,0.0f,0.0f,1.0f);
}
System::Void Render(System::Void)
{
// Initial Settings
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
glLoadIdentity();
meshOri_z = meshOri_z + 1;
// Set position and orientation of 3D mesh
Transform( meshPos_x,
meshPos_y,
meshPos_z,
meshOri_x,
meshOri_y,
meshOri_z );
glScalef( 0.05, 0.05, 0.05 );
int meshSize = 200;
// create 3D mesh Toplayer
for (int x = 1; x < meshSize; x++) {
for (int z = 1; z < meshSize; z++) {
glBegin(GL_QUADS);
int dm = 1;
glColor3f(dm,dm,dm);
glVertex3f( x, z, dm );
glVertex3f( (x+1), z, dm );
glVertex3f( (x+1), (z+1), dm );
glVertex3f( x, (z+1), dm );
glEnd();
}
}
}
System::Void SwapOpenGLBuffers(System::Void)
{
SwapBuffers(m_hDC) ;
}
private:
HDC m_hDC;
HGLRC m_hglrc;
protected:
~COpenGL(System::Void)
{
System::String^ filename = "C:/Advantech/Desktop/Dest.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Dest");
csvWriter->Close();
wglDeleteContext(m_hglrc);
DeleteDC(m_hDC);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->DestroyHandle();
}
GLint MySetPixelFormat(HDC hdc)
{
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
16, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
GLint iPixelFormat;
// get the device context's best, available pixel format match
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
MessageBox::Show("ChoosePixelFormat Failed");
return 0;
}
// make that match the device context's current pixel format
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
MessageBox::Show("SetPixelFormat Failed");
return 0;
}
if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
{
MessageBox::Show("wglCreateContext Failed");
return 0;
}
if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
{
MessageBox::Show("wglMakeCurrent Failed");
return 0;
}
return 1;
}
bool InitGL(GLvoid) // All setup for opengl goes here
{
glShadeModel(GL_SMOOTH); // Enable smooth shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black background
glClearDepth(1.0f); // Depth buffer setup
glEnable(GL_DEPTH_TEST); // Enables depth testing
glDepthFunc(GL_LEQUAL); // The type of depth testing to do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really nice perspective calculations
return TRUE; // Initialisation went ok
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialise the gl window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
System::Void detectBlack(){
}
};
}
the first form only contains a button to open the second form
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
Form1^ freaker = gcnew Form1();
freaker->ShowDialog();
}
and here is the code of the second form:
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
void Form1_Closing( Object^ /*sender*/, System::ComponentModel::CancelEventArgs^ e )
{
this->OpenGL->~COpenGL();
}
//Time tick for play button option
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e){
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(e);
OpenGL->Render();
OpenGL->SwapOpenGLBuffers();
}

After one week of searching and trying around here the answer:
I found a class to destroy openGL objects in Windows (wgl). This class alone did not solve the problem. I had to call all the commands, then switch buffers by calling SwapBuffers(m_hDC); and call all the commands again. Later on I recognized that it is enough only to call the commands g_hDC=NULL; and g_hWnd=NULL;. So this is how my destructor looks like now:
~COpenGL(System::Void){
if (g_bFullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (g_hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,TEXT("Release Of DC And RC Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(g_hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL,TEXT("Release Rendering Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
g_hRC=NULL; // Set RC To NULL
}
if (g_hDC && !ReleaseDC(g_hWnd,g_hDC)) // Are We Able To Release The DC
{
MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hDC=NULL; // Set DC To NULL
}
if (g_hWnd && !DestroyWindow(g_hWnd)) // Are We Able To Destroy The Window?
{
MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass(TEXT("OpenGL"),g_hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hInstance=NULL; // Set hInstance To NULL
}
SwapBuffers(g_hDC);
g_hDC=NULL;
g_hWnd=NULL;
}

Related

Font rendering (Freetype) with openGL ES 2.0 combined with other line drawing functions does not work

This thread is related to https: //stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype
I have a problem combining font rendering and using this function as follows:
// Create VBO (Vertex Buffer Object) based on the vertices provided, render the vertices on the
// background buffer and eventually swap buffers to update the display.
// Return index of VBO buffer
GLuint drawVertices(SDL_Window *window, Vertex *vertices, GLsizei numVertices, int mode){
// Number of vertices elements must be provided as a param (see numVertices) because
// sizeof() cannot calculate the size of the type a pointer points to
//GLsizei vertSize = sizeof(vertices[0]);
//SDL_Log("Vertices size is %d, no of vertices is %d", vertSize, numVertices);
// Create a VBO (Vertex Buffer Object)
GLuint VBO = vboCreate(vertices, numVertices);
if (!VBO) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
// Set up for rendering the triangle (activate the VBO)
GLuint positionIdx = 0; // Position is vertex attribute 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(positionIdx, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
glEnableVertexAttribArray(positionIdx);
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
if (mode & RENDER){ glDrawArrays(GL_LINE_STRIP, 0, numVertices); }
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return VBO;
}
This function uses glDrawArrays() to draw a series of lines connecting the provided vertices. Flags CLEAR, RENDER & UPDATE are being used to let me do something like:
drawVertices(window, vertices, sizeOfVertices, CLEAR | RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
I did the same thing with the font rendering function thus enabling me to draw multiple strings in various x,y coordinates. The next two functions do the font rendering based on the code i submitted at the first place and off course your corrections.
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
void glRenderText(char *text, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
int w=0, h=0;
SDL_GetWindowSize(SDLmain.window, &w, &h);
float xMax = 2.0 / (float)w;
float yMax = 2.0 / (float)h;
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 }; // red and opaque
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){ glClearColor(0.0, 0.0, 0.0, 1); glClear(GL_COLOR_BUFFER_BIT); }
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
}
I therefore can do:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER | UPDATE);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER | UPDATE);
It turns out that i can either render fonts at various x,y coordinates or use the function drawVertices to render lines connecting those vertices BUT not both. That is, i cannot do this:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
As you can tell the logic is that in either functions you have to just with a CLEAR | RENDER flag, then do only RENDER and on your last call to either functions use RENDER | UPDATE.
ISSUES:
(1) In my attempt to do the previous, that is, combinning glRenderText() + drawVertices() i failed because there is clearly something to be setup prior calling them one after the other.
(2) Another issue that i am facing is that running the code on my raspi3 resulted in drawVertices() working fine back when it comes to fonts i could only see the effect of glClearColor() & glClear(GL_COLOR_BUFFER_BIT) which means that the display was cleared with the color setup by glClearColor() but there was no font rendering to be seen. I tried both GL driver mode. There is one called FULL KMS GL driver and another called FAKE KMS GL driver.
Also, in order for the drawVertices() to work i had to comment the code provided below:
FT_Set_Pixel_Sizes(face, 0, 200);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint vbo;
GLuint attribute_coord=0;
glGenBuffers(1, &vbo);
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
I still had to keep the following code active:
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Activate the resulting shaders program
glUseProgram(shaderProg);
glUniform1i( tex_loc, 0 ); // 0, because the texture is bound to of texture unit 0
// Define RGB color + Alpha
float col[4] = { 0.0f, 1.0f, 1.0, 1.0f };
glUniform4fv( color_loc, 1, col);
i was able to resolve the issue by reseting pretty much everything that is not common to the two operations (glRenderText() & drawVertices())
The following code stays as is before calling any of the two functions ()glRenderText() & drawVertices()). These two functions have been updated so that a proper reset is done before reaching the point where glDrawArrays() is executed
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
// Activate the resulting shaders program
glUseProgram(shaderProg);
// After the shaders (vertex & fragment) have been compiled & linked into a program
// we can query the location index value of a uniform variable existing in the program.
// In this case we are querying uniform variables "tex" that exist in the fragment shader
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
// Set the value of the uniform variable "tex_loc" to 0, because the texture is bound to of texture unit 0
glUniform1i( tex_loc, 0 );
This is the updated function that resets some options so that we get the result we need. For example, glDisable(GL_BLEND); is used to disable blending when it comes to drawing lines. The most important off course is that i use glBindBuffer() to set the appropriate buffer for use by opengl every time drawVertices() is called. glGenBuffers() is used only once when the corresponding object name is 0 meaning that an used object name has not yet been assigned to the vbo.
GLuint drawVertices(SDL_Window *window, GLuint vbo, Vertex *vertices, GLsizei numVertices, SDL_Color rgb, int mode){
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1.0 };
// Get an available object name for glBindBuffer() when object name is ZERO
if (!vbo){ glGenBuffers(1, &vbo); }
// Check for problems
GLenum err = glGetError();
// Deal with errors
if (err != GL_NO_ERROR) {
// Failed
glDeleteBuffers(1, &vbo);
SDL_Log("Creating VBO failed, code %u\n", err);
vbo = 0;
}
else if (!vbo) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
if (mode & RENDER){
// Dissable blending when drawing lines
glDisable(GL_BLEND);
// Set up for rendering the triangle (activate the vbo)
// Position is vertex attribute 0
GLuint attribute_coord = 0;
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
// Set the buffer to be used from now on
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
// Get the location of the uniform variable "color_loc"
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" to array "col"
glUniform4fv( color_loc, 1, col);
// Copy vertices into buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_STATIC_DRAW);
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
// GL_TRIANGLE_FAN =
glDrawArrays(GL_LINE_STRIP, 0, numVertices);
}
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return vbo;
}
Things work pretty much the same way for function glRenderText()
// render_text is called by glRenderText()
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
//SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
GLuint glRenderText(char *text, int fontSize, GLuint vbo, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
float xMax = 2.0 / (float)getWindowWidth();
float yMax = 2.0 / (float)getWindowHeight();
GLuint attribute_coord=0;
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 };
// Enable blending when drawing fonts
glEnable(GL_BLEND);
// Set the W & H of the font loaded
FT_Set_Pixel_Sizes(face, 0, fontSize);
// If vbo is ZERO setup and get an object name
if (!vbo){
// Enables blending operations
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set texture parameters
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specifies the alignment requirements for the start of each pixel row in memory
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Save into vbo one unused buffer name (index) for use with glBindBuffer
glGenBuffers(1, &vbo);
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
}
// Set the buffer to be used from now on to the one indicated by vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" from array "col"
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
return vbo;
}
The logic is that 2 vbos (one for drawing line through drawVertices and one for drawing fonts through glRenderText()) are defined in main() or in the global scope and are passed to glRenderText() & drawVertices() . These two functions update the values of their local copies and return the vbos so that the vbo in main or in the global scope get updated. That off course could be done by passing them entirely by reference instead of adopting my approach.
I have not yet tested the functionality in my raspi3 though. I will get back real soon with an update. Anyway, the functions given above are fully functional.
Thanks again for your time.

How to Zoom with Poppler

Language C, UI library: GTK, renderer: poppler
I'm newbie in GTK/Poppler programming and a bit stuck with understanding how to solve Zoom issue with poppler.
When I use the function below everything is ok, except zooming (hence - scrollbars).
I've tried to get the ideas from here, but it seems, I don't get how the screen/doc is rendered at all :(.
PopplerPage *ppage_P2 = NULL;
PopplerDocument *document_P2 = NULL;
cairo_surface_t *surface_P2 = NULL;
/* pdf_doc__view_page
* page - page number;
* zoom - floating nomber, 1.0 is 'no zoom'
*/
void pdf_doc__view_page (int page, float _zoom){
int err;
int w, h;
double width, height;
cairo_t *cr;
if(document_P2==NULL) /
return;
ppage_P2 = poppler_document_get_page (document_P2, page);
if(ppage_P2==NULL)
return;
poppler_page_get_size (ppage_P2, &width, &height);
w = (int) ceil(width);
h = (int) ceil(height);
if(surface_P2)
cairo_surface_destroy (surface_P2);
surface_P2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*zoom_P2, h*zoom_P2);
cr = cairo_create (surface_P2);
poppler_page_render (ppage_P2, cr);
cairo_destroy (cr);
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w*zoom_P2, h*zoom_P2);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}
To have 'scrollers', you have to put the viewer in a GtkScrolledWindow, which I suspect you already did.
To have them actually working, once poppler rendered the page, you can ask poppler for the size of the render, then set the viewer to that size. Until then, the scrollbars don't know the size of drawing:
viewer_page = poppler_document_get_page(viewer_doc, 0);
// add a test to see if page was rendered correctly
poppler_page_get_size(viewer_page, &width, &height);
gtk_widget_set_size_request(viewer.drawingarea, (int)width, (int)height);
This is the answer. (but I still did not get how to create scrollers properly).
cr = cairo_create (surface_P2);
cairo_scale(cr, zoom_P1 , zoom_P1);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
poppler_page_render(ppage_P2, cairo);
cairo_destroy(cr);
cairo_surface_destroy(surface_P2);
g_object_unref(G_OBJECT(ppage_P2));
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w, h);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}

Performance issue while using PictureBox

I'm working on an application in Visual Studio 2010 and I'm coding in C++/CLI.
In my previous questions I had issue with data series from a serial port. Now it seems ok and now I'm trying to plot them.
I don't want to use Chart, so I would like to use handmade functions that use the class Graphics. In order to test my code, I created two arrays: the first one is filled with values coming from a Gaussian. The second one is filled with random numbers.
When I plot the values, I would like to see my plot growing and updating just like an oscilloscope. The second Do_Plot manages to "remove point" plotting them by the BackColor.
All the code works as intended but I'm experiencing problem with performances. If I run the code on my Pc, my series is plotted every 500/700 ms.
Sometimes it slows down to 1500ms and then it comes back faster.
I tried to run the code on my coworkers' Pc and I noticed the series is plotted every 170ms on the first one, whereas the series is plotted every 950ms on the second one.
This is the code:
System::Void Form1::button1_Click(System::Object^ sender, System::EventArgs^ e) {
button1->Enabled = false;
array<float,1>^ Gauss = gcnew array<float,1>(1001);
array<float,1>^ Rumore = gcnew array<float,1>(1001);
/*Some useful variables*/
Random^ generatore = gcnew Random;
float a = safe_cast<float>(Math::Round(5/(SIGMA*Math::Sqrt(2*PI)), 2));
float b = safe_cast<float>(2*(SIGMA*SIGMA));
/*Start */
float portante;
float r;
float s;
int convX =1000/1000;
int convY =500/2;
/*time variables */
int bias = 50;
int dif =600;
/*Gap between drawing and removing*/
int k = 3;
int e1 = 0;
for ( ; ; ) {
/*Start*/
clock_t Start = clock();
if(textBox1->Text==""){
portn = 5;
}
else
portn = float::Parse(textBox1->Text);
/*temp variables to go out the for cycle */
portante = portn;
r = rand;
s = sig;
/ckeck state is OK */
check = 0;
for(int i = 1; i<=1000; i++) {
Gauss[i] = safe_cast<float>(Math::Round( a*s*Math::Exp(-Math::Pow(((0.01*1*(i))-portante), 2)/b), 2));
Rumore[i] = safe_cast<float>(Math::Round(r*generatore->NextDouble(), 2));
bool clipSup = ClipSup(2, Gauss[i]+Rumore[i]);
if(clipSup==true) {
Gauss[i] = 1.99f;
Rumore[i] = 0;
}
Do_Plot(g, disegna, i-1, Gauss[i-1]+Rumore[i-1], i, Gauss[i]+Rumore[i], convX, convY);
e1 =(k+i)%1000;
Do_Plot(g, rimuovi, e1, Gauss[e1]+Rumore[e1], e1+1, Gauss[e1+1]+Rumore[e1+1], convX, convY);
/*Ckeck if go out for cycle*/
if(check == CODE_1 ) {
portante = portn;
break;
}
if(check == CODE_2 ) {
r = rand;
break;
}
if(check == CODE_3 ) {
s = sig;
break;
}
}
clock_t Stop = clock();
int Diff = Stop-Start;
label8->Text = Convert::ToString(Diff);
int tempDiff = (Stop-Start)+bias;
if(tempDiff>dif)
{
//Do_Axes(g); /*Do Axes*/
//Do_Grid(g); /*Do Grid */
Application::DoEvents();
dif = 600;
bias = 0;
}
else
bias +=50; //Else bias grows
}
}
Where Do_Plot is:
void Do_Plot(Graphics^ g, Pen^ penna, int Xi, float Yi, int Xf, float Yf, int convX, int convY) {
g->DrawLine(penna, (convX*Xi+50), safe_cast<int>(500-(Yi*convY)+50),
(convX*Xf+50), safe_cast<int>(500-(Yf*convY)+50));
}
I have declared Graphics^ g here:
public ref class Form1 : public System::Windows::Forms::Form
{
Graphics^ g;
public:
Form1(void)
{
InitializeComponent();
//
//TODO: aggiungere qui il codice del costruttore.
//
g = pictureBox1->CreateGraphics();
}
Onestly I don't know why my code works so differently when it runs on another Pc. I think the problem is g = pictureBox1->CreateGraphics(); but I'm just doing some hypothesis. Any kind of help would be really appreciated cause I'm stuck on this one since the previous week!!
Thanks a lot!
Emiliano
I am going to give you the code in c/c++. Will then find how to do it in c++/cli
First initialize the objects we will use (begining of button_click):
RECT rt = {0, 0, 1200, 600};
HBITMAP hBitmap = NULL;
HPEN hLinePen = NULL;
HDC hdcPctrBox = NULL, hdc = NULL, hdcMemTempImage = NULL;
HBRUSH hBrush = NULL;
POINT arrayPnt[1000]; //array of points
hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
hdcPctrBox = GetWindowDC(hwndPctrBox); //hwndPctrBox is the handle of picturebox
hdcMemTempImage = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, 1200, 600);
SelectObject(hdcMemTempImage, hBitmap);
hLinePen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); //width of pen = 1,and color (255, 0, 0)
SelectObject(hdcMemTempImage, hLinePen);
hBrush = CreateSolidBrush(RGB(100, 100, 255)); //color of picturebox
Then:
for ( ; ; ) {
/*Start*/
clock_t Start = clock();
FillRect(hdcMemTempImage, &rt, hBrush); //clear the hdcMemTempImage with the picturebox color
//your code continues...
In the for(int i = 1; i<=1000; i++) add one point at a time:
arrayPnt[i - 1].x = X; //calculate X
arrayPnt[i - 1].x = Y; ////calculate Y
And finaly we draw it, after the for loop and before the clock_t Stop (we dont need the Do_Plot()):
Polyline(hdcMemTempImage, &arrayPnt, 1000);
BitBlt(hdcPctrBox, 0, 0, 1200, 600, hdcMemTempImage, 0, 0, SRCCOPY);
clock_t Stop = clock();
//your code continues...
EDIT: use your original code(you dont need rt, hBitmap, hBrush, hdcMemTempImage, arrayPnt and hdc) and instead of calling Do_Plot() add this code:
//create two pens, one with the color you want hLinePen, and another with the color of picturebox hLinePenErase
//inside for(int i = 1; i<=1000; i++)
(some code...)
if(clipSup==true) {
Gauss[i] = 1.99f;
Rumore[i] = 0;
}
SelectObject(hdcPctrBox, hLinePen); //the pen to draw the line
MoveToEx(hdcPctrBox, xStart, yStart, NULL); //start point of line
LineTo(hdcPctrBox, xEnd, yEnd); //end point of line
SelectObject(hdcPctrBox, hLinePenErase); //the pen to erase the line
MoveToEx(hdcPctrBox, xStartErase, yStartErase, NULL); //start point of line to erase
LineTo(hdcPctrBox, xEndErase, yEndErase); //end point of line to erase
(code continues...)
To delete your resources:
HPEN hLinePen = NULL, hLinePenErase = NULL, originalPen = NULL;
HDC hdcPctrBox = NULL;
hdcPctrBox = GetWindowDC(hwndPctrBox); //hwndPctrBox is the handle of picturebox
originalPen = SelectObject(hdcPctrBox, GetStockObject(DC_PEN));
//create the two pens
//in the end release resources
SelectObject(hdcPctrBox, originalPen);
DeleteObject(hLinePen);
DeleteObject(hLinePenErase);
ReleaseDC(hwndPctrBox, hdcPctrBox);
valter
I suggest to implement your own painting class. Derive your own class from "Panel" or "UserControl" and do the following in the constructor, which activates double buffering and optimized drawing:
public ref class MyPaintControl : public System::Windows::Forms::UserControl
{
public:
MyPaintControl()
{
this->SetStyle(System::Windows::Forms::ControlStyles::AllPaintingInWmPaint, true);
this->SetStyle(System::Windows::Forms::ControlStyles::DoubleBuffer, true);
this->SetStyle(System::Windows::Forms::ControlStyles::ResizeRedraw, true);
this->SetStyle(System::Windows::Forms::ControlStyles::UserPaint, true);
}
// And then implement your painting in OnPaint:
protected:
virtual void OnPaint(PaintEventArgs^ e)
{
// Do painting...
System::Drawing::Brush^ br = gcnew System::Drawing::SolidBrush(this->BackColor);
e->Graphics->FillRectangle(br, this->ClientRectangle);
delete br;
// Do other paintings...
}
// This function might be called if new data arrived...
public:
void UpdateArea(int daten) // pass data here, if you want...
{
// Store the data in a member variable...
// force a redraw:
this->InvalidateRect(); // this will force a "OnPaint"
}
}
Then embedd this control in your UI. This should improve your painting very much!
Also this works, even if you move or resize your window. Be aware, that painting should always be done in "OnPaint"!
I would like to update the state of my coding.
I used the method posted by Jochen. It is very fast but it does not suit my application or maybe I'm not able to adapt it. What I need to do, is to update constantly my plot. At time t0, I should draw a line. At time t1, when I store a new line, I should draw the new line and add this to the previous one. The plot must be "alive". I tried to derive a panel class and override the OnPaintevent but my plot refreshing only if all lines are stored and displayed.

Checkers game in SDL

i'm trying to make a checkers game and atm i'm doing the interface with SDL, but i'm just learning C and SDL, how can I move a surface I added to the screen ? I want it the simplest as possible, just remove from X and show on Y, how do I remove a surface to make it appear on another place on the screen ? here is my code:
#include "SDL.h"
#define BRANCA 2
#define PRETA 1
#define DAMA 2
#define NORMAL 1
//The attributes of the screen
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//The surfaces that will be used
SDL_Surface *pecaPreta = NULL;
SDL_Surface *pecaBranca = NULL;
SDL_Surface *pecaDamaPreta = NULL;
SDL_Surface *pecaDamaBranca = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Event event;
SDL_Surface *load_image(char * filename )
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(filename);
if( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
if( optimizedImage != NULL )
{
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
}
}
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, destination, &offset );
}
void inserePeca(int tipo, int posX, int posY, int cor)
{
switch(cor)
{
case 1:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaPreta, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaPreta, screen);
break;
}
break;
case 2:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaBranca, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaBranca, screen);
break;
}
break;
}
}
int main()
{
int quit = 0;
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return 1;
}
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
if( screen == NULL )
{
return 1;
}
//Set the window caption
SDL_WM_SetCaption( "Jogo de Damas 0.1b", NULL );
//Load the images
pecaPreta = load_image( "pecapreta.bmp" );
pecaBranca = load_image("pecabranca.bmp");
pecaDamaPreta = load_image("pecadamapreta.bmp");
pecaDamaBranca = load_image("pecadamabranca.bmp");
background = load_image( "tabuleiro.bmp" );
//Apply the background to the screen
apply_surface( 0, 0, background, screen );
inserePeca(DAMA, 0,0, BRANCA);
inserePeca(NORMAL, 80,0, PRETA);
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
while( quit == 0 )
{
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if( event.type == SDL_QUIT )
{
//Quit the program
quit = -1;
}
}
}
//Free the surfaces
SDL_FreeSurface( pecaPreta );
SDL_FreeSurface( background );
//Quit SDL
SDL_Quit();
return 0;
}
as you can see I add a block on "inserePeca", I want to move it after I create it
The buffer for the screen doesn't keep all the things you draw on it as separate items -- it just holds the end result of all the drawing operations. So, you can't just draw the background, then draw a piece on it, then move the piece around -- you need to redraw the affected parts of the screen with the required changes.
You still have the images of the pieces, and you still have the background image; the way to move a piece you've drawn is simply to restore the background to the old position by blitting it again, and then blit the piece in the new position. Rather than drawing the whole screen and all the pieces over again, though, you can just draw the changed areas: blit just a part of the background to erase the old square, and then blit the piece onto the new square.
The following function is similar to your apply_surface() function, but instead of copying the whole source image to the the given coordinates of the destination, it copies a region of a given width and height from the given coordinates of the source image to the same coordinates of the destination. This can then be used to restore the background for a small part of the screen.
/* Blit a region from src to the corresponding region in dest. Uses the same
* x and y coordinates for the regions in both src and dest. w and h give the
* width and height of the region, respectively.
*/
void erase_rect( int x, int y, int w, int h, SDL_Surface *src, SDL_Surface *dest)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
offset.w = w;
offset.h = h;
SDL_BlitSurface( src, &offset, dest, &offset );
}
So if your squares are 50x50, and you need to move a piece from a square at (120, 40) to the square at (170, 90), you could do something like the following:
/* erase old 50x50 square at (120,40) (to background image) */
erase_rect( 120, 40, 50, 50, background, screen );
/* draw piece at new position of (170,90) */
inserePeca(NORMAL, 170, 90, PRETA);

Why is my openGL texture only covering half of my quad? Source included

Here is my code. I'm attempting to draw a simple quadrilateral, and place a checkerboard pattern on both sides of it. I want to allow the user to rotate around this piece with the mouse. Everything works fine, other than the texture - it is slanted, and only covers about half of the quad. Can anyone see something glaringly obvious that I am doing wrong? Thanks.
#include "glut-3.7.6-bin\glut.h"
// Constants for rotating camera
#define CAMERA_RELEASE 0
#define CAMERA_ROTATE 1
#define CAMERA_ZOOM 2
// Current camera control setting
int cameraSetting;
// Current viewing angle and scale of the scene
float viewAngleX, viewAngleY, scaleFactor = 1.0;
// Click coordinates
int clickX, clickY;
// Screen size
const int screenWidth = 600;
const int screenHeight = 600;
// Texture data
GLuint texture;
////////////////////////////////////////////////////////////////
// Function Prototypes
////////////////////////////////////////////////////////////////
GLuint loadTexture(const char * filename);
////////////////////////////////////////////////////////////////
// Callback and Initialization Functions
////////////////////////////////////////////////////////////////
void callbackMouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN)
{
// Store clicked coordinates
clickX = x;
clickY = y;
// Set camera mode to rotate
if (button == GLUT_LEFT_BUTTON)
{
cameraSetting = CAMERA_ROTATE;
}
// Set camera mode to zoom
else if (button == GLUT_RIGHT_BUTTON)
{
cameraSetting = CAMERA_ZOOM;
}
}
// Ignore camera commands if no button is clicked
else if (state == GLUT_UP)
{
cameraSetting = CAMERA_RELEASE;
}
}
void callbackKeyboard(unsigned char key, int x, int y)
{
if (key == 'q') {
exit(0);
}
}
void callbackMotion(int x, int y)
{
if (cameraSetting == CAMERA_ROTATE)
{
// Camera rotate setting - adjust the viewing angle by the direction of motion
viewAngleX += (x - clickX) / 5.0;
viewAngleX = viewAngleX > 180 ? (viewAngleX - 360) : (viewAngleX < - 180 ? (viewAngleX + 360) : viewAngleX);
clickX = x;
viewAngleY += (y - clickY) / 5.0;
viewAngleY = viewAngleY > 180 ? (viewAngleY - 360) : (viewAngleY < - 180 ? (viewAngleY + 360) : viewAngleY);
clickY = y;
}
else if (cameraSetting == CAMERA_ZOOM)
{
// Polygonal scale to simulate camera zoom
float currentScaleFactor = scaleFactor;
scaleFactor *= (1+ (y - clickY) / 60.0);
scaleFactor = scaleFactor < 0 ? currentScaleFactor : scaleFactor;
clickY = y;
}
glutPostRedisplay();
}
void callbackDisplay()
{
// Clear the screen
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// Set world window
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 1, 100);
// Setup 3D environment
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,5,
0,0,0,
0,1,0);
// Rotate and scale 3D environment to current user settings
glRotatef(viewAngleX, 0, 1, 0);
glRotatef(viewAngleY, 1, 0, 0);
glScalef(scaleFactor, scaleFactor, scaleFactor);
glBegin(GL_QUADS);
glTexCoord2d(0.0, 0.0); glVertex3f(-30, -5, -30);
glTexCoord2d(1.0, 0.0); glVertex3f(30, -5, -30);
glTexCoord2d(1.0, 1.0); glVertex3f(30, -5, 30);
glTexCoord2d(0.0, 1.0); glVertex3f(-30, -5, 30);
glEnd();
// Swap frame buffers
glutSwapBuffers();
}
void windowInitialization() {
// Enable textures by default
glEnable(GL_TEXTURE_2D);
// Load texture
texture = loadTexture("checkerboard.raw");
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
// GLUT Initialization
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(screenWidth,screenHeight);
// Create main window
glutCreateWindow("Test");
windowInitialization();
// Register callback functions
glutDisplayFunc(callbackDisplay);
glutMouseFunc(callbackMouse);
glutMotionFunc(callbackMotion);
glutKeyboardFunc(callbackKeyboard);
// Enter event processing loop
glutMainLoop();
}
////////////////////////////////////////////////////////////////
// Prototyped Functions
////////////////////////////////////////////////////////////////
GLuint loadTexture(const char * filename)
{
GLuint texture;
int width, height;
BYTE * data;
FILE * file;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) return 0;
// allocate buffer
width = 256;
height = 256;
data = (BYTE *) malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose( file );
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// texture wraps over at the edges
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 1 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 1);
// build texture
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, data );
// free buffer
free( data );
return texture;
}
Your code works fine for me; I suspect the problem is in the source image you're using for the texture. Double-check that the image is what you think it is. For example, using ImageMagick:
# Convert an image into raw RGB:
convert checkerboard.png checkerboard.rgb
# Convert raw RGB back to an image (assuming we know the size and color depth):
convert -size 256x256 -depth 8 checkerboard.rgb checkerboard.png

Resources