memory leak when loading and unloading textures - c++

Does anyone know why there is a memory leak when loading and unloading textures to memory? Memory leak asserts under specific conditions
I have a texture class. The code is below:
Texture.h
#pragma once
#include <string>
#include <vector>
#include "../../vendor/headers/stb_image.h"
class Texture {
friend class BatchRenderer;
// Object
private:
unsigned int textureID, textureSlot;
unsigned char* image;
int width, height, bpp;
public:
Texture(const std::string& path); // To-Do: Replace "const std::string& path" with a char array. "const std::string& path" is alive for the lifetime of the program.
Texture(const char* path);
unsigned int getTextureID() const;
int getTextureSlot() const;
unsigned int getWidth() const;
unsigned int getHeight() const;
unsigned int getBPP() const;
~Texture();
};
Texture.cpp
#include "Texture.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// To-Do: Replace "const std::string& path" with a char array. "const std::string& path" is alive for the lifetime of the program.
Texture::Texture(const std::string& path) : textureID(0), image(nullptr), width(0), height(0), bpp(0) {
stbi_set_flip_vertically_on_load(1);
image = stbi_load(path.c_str(), &width, &height, &bpp, 4);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glBindTexture(GL_TEXTURE_2D, 0);
textureSlot = 0;
}
Texture::Texture(const char* path) {
stbi_set_flip_vertically_on_load(1);
image = stbi_load(path, &width, &height, &bpp, 4);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glBindTexture(GL_TEXTURE_2D, 0);
textureSlot = 0;
}
unsigned int Texture::getTextureID() const {
return textureID;
}
int Texture::getTextureSlot() const {
return textureSlot;
}
unsigned int Texture::getWidth() const {
return width;
}
unsigned int Texture::getHeight() const {
return height;
}
unsigned int Texture::getBPP() const {
return bpp;
}
Texture::~Texture() {
if (image)
stbi_image_free(image);
glDeleteTextures(1, &textureID);
}
Main.cpp
#include <iostream>
#include "batchrenderer/classes/Texture.h"
using namespace std;
int main() {
cout << "Program operating..." << endl;
string pause;
cout << "Enter anything to continue: ";
cin >> pause;
for (unsigned int i = 0; i < 1000; i++) {
Texture* texture = new Texture("C:\\Users\\chris\\source\\repos\\BatchRenderer\\BatchRenderer\\resources\\coloredsquares\\black.png");
delete(texture);
}
cout << "Enter anything to continue: ";
cin >> pause;
for (unsigned int i = 0; i < 1000; i++) {
Texture* texture = new Texture("C:\\Users\\chris\\source\\repos\\BatchRenderer\\BatchRenderer\\resources\\coloredsquares\\black.png");
delete(texture);
}
cout << "Enter anything to continue: ";
cin >> pause;
for (unsigned int i = 0; i < 1000; i++) {
Texture* texture = new Texture("C:\\Users\\chris\\source\\repos\\BatchRenderer\\BatchRenderer\\resources\\coloredsquares\\black.png");
delete(texture);
}
cout << "Enter anything to continue: ";
cin >> pause;
cout << "Program terminated..." << endl;
}
Here is what my diagnostics tool looks like. I am not sure if there is a small bug in the VS code and there is actually no memory leak or if there is a memory leak and it is something SO small that I cannot pin point it. When the code is profiled with a loop of 100 times, there is no leak. The memory leak only asserts when the loop exceeds 1000 loops. Does anyone know anything about why this is happening. Note: there appear to be no memory leak when only 1 texture is load. Or maybe there is, but it is negligible until you have created a LOT of Texture objects.
Note: I was suspecting it was the string object but did not find anything when I profiled that specific thing. Unless I profiled it wrong.

Related

Assertion error when trying to include textures SDL2 c++

I made a graphic engine with SDL2, and when I add a texture, it displays an error:
However, if i dont include textures, everything works fine.
I also have reasons to belive, that the error is connected to the IDE, because I read other questions.
My IDE: VS 2017 pro
The code
run()
void maingame::run()
{
initSystems();
_sprite.init(-1.0f, -1.0f, 2.0f, 2.0f);
_enemyTexture = ImageLoader::loadPNG("textures/jimmyJump_pack/PNG/CharacterRight_Standing.png");
gameLoop();
}
run() method gets called by main() func
The initialization of the sprite:
void targetSprite::init(float x, float y, float width, float height)
{
_x = x;
_y = y;
_width = width;
_height = height;
if (_vboID == 0) {
glGenBuffers(1, &_vboID);
}
Vertex vertexData[6];
//1st
vertexData[0].setPos(_x + _width, _y + _height);
vertexData[0].setUV(1.0f, 1.0f);
vertexData[1].setPos(_x, _y + _height);
vertexData[1].setUV(0.0f, 1.0f);
vertexData[2].setPos(_x, _y);
vertexData[2].setUV(0.0f, 0.0f);
//2nd
vertexData[3].setPos(_x, _y);
vertexData[3].setUV(0.0f, 0.0f);
vertexData[4].setPos(_x + _width, _y);
vertexData[4].setUV(1.0f, 0.0f);
vertexData[5].setPos(_x + _width, _y + _height);
vertexData[5].setUV(1.0f, 1.0f);
for (int i = 0; i < 6; i++) {
vertexData[i].setColor(127, 127, 255, 255);
}
vertexData[1].setColor(255, 0, 255, 255);
vertexData[4].setColor(0, 255, 255, 255);
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
}
I posted this because I belive the error is in here.
But it is not necessary, because this same code runs whitout textures.
On line 10 "Vertex" is a struct.
I tried changing build from debug to release, but then I got problems with .dll files.
EDIT:
This calls the error in vector:
GLTexture ImageLoader::loadPNG(std::string filePath)
{
GLTexture texture = {};
std::vector<unsigned char> out;
unsigned long width;
unsigned long height;
std::vector<unsigned char> in;
if (IOManager::readFileToBuffer(filePath, in) == false) { //read the texture to buffer
fatalError2("FTB 1");
}
int errorCode = decodePNG(out, width, height, &(in[0]), in.size()); //error line
if (errorCode != 0) {
fatalError2("DPNG 1: " + std::to_string(errorCode));
}
glGenTextures(1, &(texture.id));
glBindTexture(GL_TEXTURE_2D, texture.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(out[0]));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
texture.width = width;
texture.height = height;
return texture;
}
Line 25, then goes back to run(), main(), and then opens a "sdl_windows_main.c not found" window.
So i guess the question is where that file is located?
EDIT 2
the readFileToBuffer() method, i belive responsible for filling the "in" vector
bool IOManager::readFileToBuffer(std::string filePath, std::vector<unsigned char> buffer)
{
std::ifstream file(filePath, std::ios::binary);
if (file.fail()) {
perror(filePath.c_str());
return false;
}
file.seekg(0, std::ios::end);
int fileSize = file.tellg();
file.seekg(0, std::ios::beg);
fileSize = fileSize - file.tellg();
buffer.resize(fileSize);
file.read((char *)&(buffer[0]), fileSize);
file.close();
return true;
}
The solution was to pass "buffer" by reference
bool IOManager::readFileToBuffer(std::string filePath, std::vector<unsigned char>&buffer)
{
std::ifstream file(filePath, std::ios::binary);
if (file.fail()) {
perror(filePath.c_str());
return false;
}
file.seekg(0, std::ios::end);
int fileSize = file.tellg();
file.seekg(0, std::ios::beg);
fileSize = fileSize - file.tellg();
buffer.resize(fileSize);
file.read((char *)&(buffer[0]), fileSize);
file.close();
return true;
}
ยดยดยด

opengl crashes when trying to apply textures

I'm trying to apply textures to opengl program, but the program just crashes for some reason, can someone tell me what I did wrong? Trying to fix this problem for two days now :/ works fine when color in fragment shader is set to some random color, but when color is:
vec4 textColor = texture(u_Texture, v_TextCoord);
color = textColor;
Edited:
#define GLEW_STATIC
#define alloca __builtin_alloca
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stb_image.h>
using namespace std;
static string ParseShader(const string& filepath);
static unsigned int CompileShader(unsigned int type, const string& source);
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader);
void glCheckError();
float vertex[] =
{
0.5f, 0.5f, 0.0f,
1.0f, 1.0f, // 0
0.5f, -0.5f, 0.0f,
1.0f, 0.0f, // 1
-0.5f, -0.5f, 0.0f,
0.0f, 0.0f, // 2
-0.5f, 0.5f, 0.0f,
0.0f, 1.0f // 3
};
float vertexBack[] =
{
-0.6, -0.6f, -0.5f, // 0
0.6f, -0.6f, -0.5f, // 1
0.6f, 0.6f, -0.5f, // 2
-0.6f, 0.6f, -0.5f // 3
};
unsigned int indexes[] =
{
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
{
cout << "GLFW failed to load!" << endl;
return -1;
}
else
cout << "GLFW loaded" << endl << endl;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(800, 600, "Window", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK)
cout << "Error loading GLEW" << endl;
else
cout << "GLEW loaded - version: " << glGetString(GL_VERSION) << endl;
unsigned int shader = CreateShader(ParseShader("shaders/vertex.shader"), ParseShader("shaders/fragment.shader"));
glUseProgram(shader);
// Make vertex position array
unsigned int buffers;
glGenBuffers(1, &buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);
// Make vertex position indexes out of arrays
unsigned int ib;
glGenBuffers(1, &ib);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);
// Position layout
unsigned int posAttrib = glGetAttribLocation(shader, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
// Texture layout
unsigned int texAttrib = glGetAttribLocation(shader, "texCoord");
glEnableVertexAttribArray(texAttrib);
glCheckError();
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(3 * sizeof(float)));
// Load image
int h, w, v_bpp;
unsigned char *image = stbi_load("texture.png", &w, &h, &v_bpp, 4);
if(image == nullptr)
cout << "failed to load image!" << endl;
unsigned int texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(image);
// Set slot
glActiveTexture(GL_TEXTURE0);
int location = glGetUniformLocation(shader, "u_Texture");
glUniform1i(location, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window) && glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS)
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
//glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
glCheckError();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
static string ParseShader(const string& filepath) {
ifstream stream(filepath);
string line;
stringstream code;
while(getline(stream, line))
code << line << "\n";
return code.str();
}
static unsigned int CompileShader(unsigned int type, const string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, NULL);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if(result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "Vertex" : "Fragment") << " shader!" << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void glCheckError() {
GLenum err = glGetError();
while(err!=GL_NO_ERROR) {
string error;
switch(err) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break;
}
cerr << err << " (" << error.c_str() << ")" <<endl;
err=glGetError();
}
}
You totally screwed up your vertex attribute ponter setup:
// Position layout
unsigned int posAttrib = glGetAttribLocation(shader, "position");
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
First, you query for an attribute named position, but you never use that index, you instead use 0.
// Texture layout
unsigned int texAttrib = glGetAttribLocation(shader, "texCoord");
glEnableVertexAttribArray(1);
glCheckError();
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(3 * sizeof(float)));
Then, you query for texCoord, ignore it again, enable attribute array 1, and overwrite the attribute pointer for attribute 0.
THis means that attribute 1 has some undefined pointer value, and you have undefined behavior.
What most likely happens is that you are lucky when you not use the texture, because you only have one active attribute which happens to get location 0. And your GL implementation seems to ignore attribute arrays for non-active attributes, so it does not crash. When you have both attributes enables, chances are that they will be 0 and 1, and there is no way not to dereference that invalid pointer.

Mapping a texture to an imported object Opengl

I'm having trouble mapping a texture to an object imported into Opengl. I found a tutorial to import an obj file, but I can't figure out mapping a texture.
This is the code I have written:
class Model
{
public:
Model();
Model(string modelFilename, string textureFilename);
void LoadTexture(string fileName);
void LoadObj(const string& filename, vector<glm::vec4> &vertices, vector<glm::vec3> &normals, vector<GLushort> &elements);
void Draw();
private:
vector<glm::vec4> m_Vertices;
vector<glm::vec3> m_Normals;
vector<GLushort> m_Elements;
string m_ModelFilename;
int m_Texture;
string m_TextureName;
};
Model::Model(string modelFilename, string textureFilename)
{
m_ModelFilename = modelFilename;
m_TextureName = textureFilename;
LoadObj(m_ModelFilename, m_Vertices, m_Normals, m_Elements);
LoadTexture(m_TextureName);
}
void Model::LoadTexture(string TextureName)
{
// Local storage for bmp image data.
BitMapFile *image[1];
string filename = TextureName;
filename.append(".bmp");
// Load the texture.
image[0] = getBMPData(filename);
// Bind grass image to texture index[i].
glBindTexture(GL_TEXTURE_2D, m_Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
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, GL_RGB, image[0]->sizeX, image[0]->sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, image[0]->data);
}
void Model::LoadObj(const string& filename, vector<glm::vec4> &vertices, vector<glm::vec3> &normals, vector<GLushort> &elements) {
ifstream in(filename, ios::in);
if (!in) { cerr << "Cannot open " << filename << endl; exit(1); }
string line;
while (getline(in, line)) {
if (line.substr(0,2) == "v ") {
istringstream s(line.substr(2));
glm::vec4 v; s >> v.x; s >> v.y; s >> v.z; v.w = 1.0f;
vertices.push_back(v);
} else if (line.substr(0,2) == "f ") {
istringstream s(line.substr(2));
GLushort a,b,c;
s >> a; s >> b; s >> c;
a--; b--; c--;
elements.push_back(a); elements.push_back(b); elements.push_back(c);
}
else if (line[0] == '#') { /* ignoring this line */}
// else { /* ignoring this line */ }
}
normals.resize(vertices.size(), glm::vec3(0.0, 0.0, 0.0));
for (int i = 0; i < elements.size(); i+=3) {
GLushort ia = elements[i];
GLushort ib = elements[i+1];
GLushort ic = elements[i+2];
glm::vec3 normal = glm::normalize(glm::cross(glm::vec3(vertices[ib]) - glm::vec3(vertices[ia]), glm::vec3(vertices[ic]) - glm::vec3(vertices[ia])));
normals[ia] = normals[ib] = normals[ic] = normal;
}
}
void Model::Draw()
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_Texture);
for (int i = 0; i < m_Elements.size(); i+=3)
{
GLushort ia = m_Elements[i];
GLushort ib = m_Elements[i+1];
GLushort ic = m_Elements[i+2];
glBegin(GL_TRIANGLES);
glBegin(GL_TRIANGLES);
glNormal3f(m_Normals[ia].x,m_Normals[ia].y,m_Normals[ia].z);//
glNormal3f(m_Normals[ib].x,m_Normals[ib].y,m_Normals[ib].z);//
glNormal3f(m_Normals[ic].x,m_Normals[ic].y,m_Normals[ic].z);//
glTexCoord2f(0.0, 0.0);glVertex3f(m_Vertices[ia].x,m_Vertices[ia].y,m_Vertices[ia].z);
glTexCoord2f(1.0, 1.0);glVertex3f(m_Vertices[ib].x,m_Vertices[ib].y,m_Vertices[ib].z);
glTexCoord2f(0.0, 1.0);glVertex3f(m_Vertices[ic].x,m_Vertices[ic].y,m_Vertices[ic].z);
glEnd();
glEnd();
}
glDisable(GL_TEXTURE_2D);
}
Model model;
void setup(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
model = Model("monkey.obj", "launch");
// Specify how texture values combine with current surface color values.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_BLEND); // Enable blending.
// Cull back faces.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// stops GL_QUAD from showing faces by priority
glEnable(GL_DEPTH_TEST);
}
// Drawing routine.
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
model.Draw();
glutSwapBuffers();
}
When i run the program this is what happens: http://imgur.com/okMul77
It seems to be mapping the entire image to each triangle, but I don't know how to fix it. Anyone have any ideas? Thank you in advance

Converting OpenCV CV-to-CV2-Code

Im trying to convert an OpenCV-codesample, which i found on the internet, from the old IplImage-Format to the currently used Mat-Format, but im inexperienced regarding the correct use of pointers/classes and hope someone can help me convert the few codelines. The code mainly initializes a webcam, grabs the frames und displays them via OpenGL.
The mentioned difficult code:
CvCapture *cvCapture = 0;
cvCapture = cvCreateCameraCapture(0);
IplImage* newImage = cvQueryFrame( cvCapture );
cvReleaseCapture( &cvCapture );
I tried:
cv::VideoCapture *cvCapture = 0;
cvCapture.open(0);
cvCapture.read(cv:Mat& newImage);
cvCapture.release;
Original Code:
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <opencv/highgui.h>
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// GLUT callbacks and functions
void initGlut(int argc, char **argv);
void displayFunc(void);
void idleFunc(void);
void reshapeFunc(int width, int height);
void mouseFunc(int button, int state, int x, int y);
void mouseMotionFunc(int x, int y);
void keyboardFunc(unsigned char key, int x, int y);
void specialFunc(int key, int x, int y);
//-----------------------------------------------------------------------------
// other [OpenGL] functions
void countFrames(void);
void renderBitmapString(float x, float y, float z, void *font, char *string);
//-----------------------------------------------------------------------------
bool bFullsreen = false;
int nWindowID;
//-----------------------------------------------------------------------------
// parameters for the framecounter
char pixelstring[30];
int cframe = 0;
int time = 0;
int timebase = 0;
//-----------------------------------------------------------------------------
// OpenCV variables
CvCapture *cvCapture = 0;
GLuint cameraImageTextureID;
//-----------------------------------------------------------------------------
bool bInit = false;
//-----------------------------------------------------------------------------
void displayFunc(void) {
if(!bInit) {
// initialize 1st camera on the bus
cvCapture = cvCreateCameraCapture(0);
// initialze OpenGL texture
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &cameraImageTextureID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cameraImageTextureID);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
bInit = true;
}
IplImage* newImage = cvQueryFrame( cvCapture );
if( (newImage->width > 0) && (newImage->height > 0)) {
// clear the buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)newImage->width,0.0,(GLdouble)newImage->height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cameraImageTextureID);
if(newImage->nChannels == 3)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, newImage->width, newImage->height, 0,
GL_BGR, GL_UNSIGNED_BYTE, newImage->imageData);
else if(newImage->nChannels == 4)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, newImage->width, newImage->height,
0, GL_BGRA, GL_UNSIGNED_BYTE, newImage->imageData);
glBegin(GL_QUADS);
glTexCoord2i(0,0);
glVertex2i(0,0);
glTexCoord2i(newImage->width,0);
glVertex2i(newImage->width,0);
glTexCoord2i(newImage->width,newImage->height);
glVertex2i(newImage->width,newImage->height);
glTexCoord2i(0,newImage->height);
glVertex2i(0,newImage->height);
glEnd();
}
glDisable(GL_TEXTURE_RECTANGLE_ARB);
countFrames();
glutSwapBuffers();
}
//-----------------------------------------------------------------------------
void initGlut(int argc, char **argv) {
// GLUT Window Initialization:
glutInit (&argc, argv);
glutInitWindowSize (640, 480);
glutInitWindowPosition(300, 100);
glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
nWindowID = glutCreateWindow ("simpleGLUT - CvCamera");
// Register callbacks:
glutDisplayFunc (displayFunc);
glutReshapeFunc (reshapeFunc);
glutKeyboardFunc (keyboardFunc);
glutSpecialFunc (specialFunc);
glutMouseFunc (mouseFunc);
glutMotionFunc (mouseMotionFunc);
glutIdleFunc (idleFunc);
}
//-----------------------------------------------------------------------------
void idleFunc(void) {
glutPostRedisplay();
}
//-----------------------------------------------------------------------------
void reshapeFunc(int width, int height) {
glViewport(0, 0, width, height);
}
//-----------------------------------------------------------------------------
// mouse callback
void mouseFunc(int button, int state, int x, int y) {
}
//-----------------------------------------------------------------------------
void mouseMotionFunc(int x, int y) {
}
//-----------------------------------------------------------------------------
void keyboardFunc(unsigned char key, int x, int y) {
switch(key) {
// -----------------------------------------
#ifdef WIN32
// exit on escape
case '\033':
if(bInit) {
glDeleteTextures(1, &cameraImageTextureID);
cvReleaseCapture( &cvCapture );
}
exit(0);
break;
#endif
// -----------------------------------------
// switch to fullscreen
case 'f':
bFullsreen = !bFullsreen;
if(bFullsreen)
glutFullScreen();
else {
glutSetWindow(nWindowID);
glutPositionWindow(100, 100);
glutReshapeWindow(640, 480);
}
break;
// -----------------------------------------
}
}
//-----------------------------------------------------------------------------
void specialFunc(int key, int x, int y) {
//printf("key pressed: %d\n", key);
}
//-----------------------------------------------------------------------------
void countFrames(void) {
time=glutGet(GLUT_ELAPSED_TIME);
cframe++;
if (time - timebase > 50) {
sprintf(pixelstring, "fps: %4.2f", cframe*1000.0/(time-timebase));
timebase = time;
cframe = 0;
// Draw status text and uni-logo:
}
glDisable(GL_LIGHTING);
glColor4f(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 200, 0, 200);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// render the string
renderBitmapString(5,5,0.0,GLUT_BITMAP_HELVETICA_10,pixelstring);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
//-----------------------------------------------------------------------------
void renderBitmapString(float x, float y, float z, void *font, char *string) {
char *c;
glRasterPos3f(x, y,z);
for (c=string; *c != '\0'; c++) {
glutBitmapCharacter(font, *c);
}
}
//-----------------------------------------------------------------------------
void main(int argc, char **argv) {
initGlut(argc, argv);
glutMainLoop();
}
Solved my own problem. Also had to change old code like: newImage->width and newImage->nChannels. Dont know how stable the code is, but maybe someone can use it:
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <opencv/highgui.h>
#include <opencv2\highgui.hpp>
#include <opencv2\core.hpp>
//-----------------------------------------------------------------------------
// GLUT callbacks and functions
void initGlut(int argc, char **argv);
void displayFunc(void);
void idleFunc(void);
void reshapeFunc(int width, int height);
void mouseFunc(int button, int state, int x, int y);
void mouseMotionFunc(int x, int y);
void keyboardFunc(unsigned char key, int x, int y);
void specialFunc(int key, int x, int y);
//-----------------------------------------------------------------------------
// other [OpenGL] functions
void countFrames(void);
void renderBitmapString(float x, float y, float z, void *font, char *string);
//-----------------------------------------------------------------------------
bool bFullsreen = false;
int nWindowID;
//-----------------------------------------------------------------------------
// parameters for the framecounter
char pixelstring[30];
int cframe = 0;
int time = 0;
int timebase = 0;
//-----------------------------------------------------------------------------
// OpenCV variables
cv::VideoCapture cap(0);
GLuint cameraImageTextureID;
//-----------------------------------------------------------------------------
bool bInit = false;
//-----------------------------------------------------------------------------
void displayFunc(void) {
if(!bInit) {
// initialize 1st camera on the bus
// initialze OpenGL texture
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &cameraImageTextureID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cameraImageTextureID);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
bInit = true;
}
cv::Mat newImage;
cap.read(newImage);
int rows = newImage.rows;
int cols = newImage.cols;
cv::Size s = newImage.size();
rows = s.height;
cols = s.width;
if( (s.width > 0) && (s.height > 0)) {
// clear the buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)s.width,0.0,(GLdouble)s.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cameraImageTextureID);
if(newImage.channels() == 3)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, s.width, s.height, 0, GL_BGR,
GL_UNSIGNED_BYTE, newImage.data);
else if(newImage.channels() == 4)
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, s.width, s.height, 0, GL_BGRA,
GL_UNSIGNED_BYTE, newImage.data);
glBegin(GL_QUADS);
glTexCoord2i(0,0);
glVertex2i(0,0);
glTexCoord2i(s.width,0);
glVertex2i(s.width,0);
glTexCoord2i(s.width,s.height);
glVertex2i(s.width,s.height);
glTexCoord2i(0,s.height);
glVertex2i(0,s.height);
glEnd();
}
glDisable(GL_TEXTURE_RECTANGLE_ARB);
countFrames();
glutSwapBuffers();
}
void idleFunc(void) {
glutPostRedisplay();
}
void reshapeFunc(int width, int height) {
glViewport(0, 0, width, height);
}
void mouseFunc(int button, int state, int x, int y) {
}
void mouseMotionFunc(int x, int y) {
}
void keyboardFunc(unsigned char key, int x, int y) {
switch(key) {
// exit on escape
case '\033':
if(bInit) {
glDeleteTextures(1, &cameraImageTextureID);
cap.release();
}
exit(0);
break;
// switch to fullscreen
case 'f':
bFullsreen = !bFullsreen;
if(bFullsreen)
glutFullScreen();
else {
glutSetWindow(nWindowID);
glutPositionWindow(100, 100);
glutReshapeWindow(640, 480);
}
break;
}
}
void specialFunc(int key, int x, int y) {
//printf("key pressed: %d\n", key);
}
void countFrames(void) {
time=glutGet(GLUT_ELAPSED_TIME);
cframe++;
if (time - timebase > 50) {
sprintf(pixelstring, "fps: %4.2f", cframe*1000.0/(time-timebase));
timebase = time;
cframe = 0;
// Draw status text and uni-logo:
}
glDisable(GL_LIGHTING);
glColor4f(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 200, 0, 200);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// render the string
renderBitmapString(5,5,0.0,GLUT_BITMAP_HELVETICA_10,pixelstring);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void renderBitmapString(float x, float y, float z, void *font, char *string) {
char *c;
glRasterPos3f(x, y,z);
for (c=string; *c != '\0'; c++) {
glutBitmapCharacter(font, *c);
}
}
void main(int argc, char **argv) {
glutInit (&argc, argv);
glutInitWindowSize (640, 480);
glutInitWindowPosition(300, 100);
glutInitDisplayMode ( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
nWindowID = glutCreateWindow ("simpleGLUT - CvCamera");
// Register callbacks:
glutDisplayFunc (displayFunc);
glutReshapeFunc (reshapeFunc);
glutKeyboardFunc (keyboardFunc);
glutSpecialFunc (specialFunc);
glutMouseFunc (mouseFunc);
glutMotionFunc (mouseMotionFunc);
glutIdleFunc (idleFunc);
glutMainLoop();
}

Problems copying freetype bitmap to opengl texture

I'm trying to generate all the bitmaps for characters from ' ' to '~' and add them to one long texture. I intend to position them in a fixed width texture but for now I just wanted to make sure the concept would work.
But I am having problems. Instead of getting the expected texture I just get the below for a 16px font:
It looks to me as if I'm copying it wrong but no matter what I seem to do I seem to always get the same output.
Finally, the code:
Font.h
#ifndef _FONT_H_
#define _FONT_H_
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <GL/gl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "vector2.h"
#include "math_helper.h"
class Font {
public:
Font(const std::string font_path, int size);
~Font();
int get_texture() const { return texture_; }
private:
unsigned int width_, height_, texture_;
static FT_Library LIBRARY;
static const char START_CHAR = ' ';
static const char END_CHAR = '~';
static void initialize_library();
};
#endif
Font.cpp
#include "font.h"
FT_Library Font::LIBRARY = NULL;
Font::Font(const std::string font_path, int size)
: width_(64), height_(2), texture_(0) {
initialize_library();
FT_Face face = NULL;
int error = FT_New_Face(Font::LIBRARY, font_path.c_str(), 0, &face);
if(error == FT_Err_Unknown_File_Format) {
std::cout << "Error: Unknown file format for font \"" << font_path << "\"" << std::endl;
} else if(error) {
std::cout << "Error: Could not open font \"" << font_path << "\"" << std::endl;
}
error = FT_Set_Pixel_Sizes(face, 0, size);
if(error) {
std::cout << "Error: Could not set pixel size for font \"" << font_path << "\"" << std::endl;
}
int num_chars = (END_CHAR - START_CHAR);
width_ = to_nearest_pow2(num_chars * size);
height_ = to_nearest_pow2(size);
std::vector<unsigned char> buffer(width_ * height_, 0);
Vector2 pen;
for(char c = START_CHAR; c <= END_CHAR; ++c) {
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if(error) {
std::cout << "Error: Could not load char \"" << c << "\"" << std::endl;
continue;
}
FT_Bitmap bmp = face->glyph->bitmap;
int advance = (face->glyph->advance.x >> 6);
int bitmapWidth = bmp.width; //I have tried pitch, same problem
int bitmapHeight = bmp.rows;
for(int h = 0; h < bitmapHeight; ++h) {
for(int w = 0; w < bitmapWidth; ++w) {
int index = h * bitmapWidth + pen.x;
buffer[index + w] = bmp.buffer[w + bitmapWidth * h];
}
}
pen.x += advance;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture_);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width_, height_, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &buffer[0]);
FT_Done_Face(face);
}
Font::~Font() {
if(texture_ != 0) {
glDeleteTextures(1, &texture_);
}
}
void Font::initialize_library() {
if(Font::LIBRARY == NULL) {
if(FT_Init_FreeType(&Font::LIBRARY) != 0) {
std::cout << "Error: Unable to initialize FreeType Library" << std::endl;
return;
}
}
}
Vector2 is just a simple struct with an x and y field that are initialized to 0 on construction.
to_nearest_pow2 is defined as:
template<typename T>
T to_nearest_pow2(const T num) {
T nearest = 2;
while((nearest <<= 1) < num);
return nearest;
}
Oh and here's how I am drawing it to screen (I am using orthographic projection)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, test->get_texture());
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(0, 0);
glTexCoord2i(1, 0); glVertex2i(400, 0);
glTexCoord2i(1, 1); glVertex2i(400, 400);
glTexCoord2i(0, 1); glVertex2i(0, 400);
glEnd();
Edit
I changed index to what was suggested by #shouston and now I get this output
Rescale your output image to something like 1000x60, and you'll get a surprise. Here's what paint.net made of the PNG you attached.
Obvious things first. The characters are basically there, but for some reason you;'re just rendering them very small (what value of size did you pass?)
Also, you're not trying to handle any of the freetype character metrics, so don't expect them to all line up nicely. yet...
The problem is with the index into your texture buffer:
int index = h * bitmapWidth + pen.x;
should be
int index = h * width_ + pen.x;
i.e multiply h by the full width of the texture, not the width of the glyph.