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;
}
ยดยดยด
Related
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.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I just don't understand why it does not work - it just shows a white screen... (or a black one, because glClearColor)
PS. > the texture also broke everything else...
I checked the shaders and the code: no errors, no responses, nothing. Including the texture.
I think the shaders are right, but i don't know about anything else. I also have all the libraries: GLEW, GLFW, OPENGL, a single header file copied from stb_image...
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#define ASSERT(x) if(!(x)) __debugbreak();
#define CALL(x) OpenGlClError(); x; ASSERT(OpenGlError(#x, __LINE__, __FILE__));
#define STB_IMAGE_IMPLEMENTATION
#include "extern/stb_image/stb_image_vendor/stb_image.h"
void OpenGlClError() {
while (glGetError());
}
bool OpenGlError(const char* func, int line, const char* file) {
while (GLenum error = glGetError()) {
std::cout << "GLTest: OPENGL ERROR: " << error << " in function " << func << " at line " << line << ", FILE: " << file << "\n";
return false;
}
return true;
}
#define ASSERT(x) if(!(x)) __debugbreak();
#define CALL(x) OpenGlClError(); x; ASSERT(OpenGlError(#x, __LINE__, __FILE__));
class Texture {
private:
unsigned int TextID;
std::string FilePath;
unsigned char* LocalBuffer;
int Width, Height, BytesPixel;
public:
Texture(const std::string path)
: TextID(0), FilePath(path), LocalBuffer(nullptr), Width(0), Height(0), BytesPixel(0) {
CALL(glGenTextures(1, &TextID));
CALL(glBindTexture(GL_TEXTURE_2D, TextID));
stbi_set_flip_vertically_on_load(1);
LocalBuffer = stbi_load(path.c_str(), &Width, &Height, &BytesPixel, 4);
CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, LocalBuffer));
CALL(glBindTexture(GL_TEXTURE_2D, 0));
if (LocalBuffer) { //if localbuffer exists
stbi_image_free(LocalBuffer);
}
}
~Texture() {
glDeleteTextures(1, &TextID);
}
void Bind(unsigned int slot = 0){
CALL(glActiveTexture(GL_TEXTURE0 + slot));
CALL(glBindTexture(GL_TEXTURE_2D, TextID));
}
void Unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
};
static std::string ReadShader(const std::string& filename) {
std::ifstream stream;
std::string line;
std::string str;
stream.open(filename);
while (getline(stream, line)) {
str.append(line).append("\n");
}
std::cout << str;
stream.close();
return str;
}
static unsigned int CompileShader(const std::string& source, unsigned int type) {
unsigned int shader = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
int result;
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
// i - int
// v - vector
if (result == GL_FALSE) {
std::cout << "Shader cannot be compiled.\n" << (type == GL_VERTEX_SHADER ? "vertex s." : "fragments.") << "\n";
int length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)_malloca(length * sizeof(char));
glGetShaderInfoLog(shader, length, &length, message);
std::cout << message << "\n";
glDeleteShader(shader);
}
return shader;
}
static int CreateShader(const std::string& vShader, const std::string& fShader) {
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(vShader, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(fShader, GL_FRAGMENT_SHADER);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main() {
glfwInit();
//make window
GLFWwindow* window;
//std::cout << "GLTest:" << glGetString(GL_VERSION) << "\n";
window = glfwCreateWindow(800, 500, "Modern OpenGL Test", NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
float texver[16] = {
-1.0f, -1.0f , 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 1.0f
};
float texindex[6] = {
0, 1, 2,
2, 3, 0
};
float vertices[12] = {
1.0f, 1.0f,
0.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
0.0f, 1.0f,
-1.0f, -1.0f
};
//unsigned int varray; //< dont actually need it...
//glGenVertexArrays(1, &varray);
//glBindVertexArray(varray);
//unsigned int vb;
//glGenBuffers(1, &vb);
//glBindBuffer(GL_ARRAY_BUFFER, vb);
//glBufferData(GL_ARRAY_BUFFER, 6 * 2 * sizeof(float), vertices, GL_STATIC_DRAW);
//
//glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); //said hey we have this set up like that, links in vertex array
//glEnableVertexAttribArray(0); //yea remember it
unsigned int tb;
glGenBuffers(1, &tb);
glBindBuffer(GL_ARRAY_BUFFER, tb);
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), texver, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); //said hey we have this set up like that, links in vertex array
glEnableVertexAttribArray(0); //yea remember it
unsigned int shaders = CreateShader(ReadShader("shaders/basic_texture_vertex.shader"), ReadShader("shaders/basic_texture_fragment.shader"));
glUseProgram(shaders);
Texture tt("../!Assets/editor/img/intro_logo.png");
tt.Bind();
CALL(int location = glGetUniformLocation(shaders, "u_Texture"));
CALL(glUniform1i(location, 0));
CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 1, 1, 1);
//Drawing
glDrawArrays(GL_TRIANGLES, 0, 6 * 2);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteProgram(shaders);
glfwTerminate();
}
You missed to specify the vertex attribute for the texture coordinates. For instance
unsigned int tb;
glGenBuffers(1, &tb);
glBindBuffer(GL_ARRAY_BUFFER, tb);
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), texver, GL_STATIC_DRAW);
// vertex cooridnates
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
glEnableVertexAttribArray(0);
// texture coordinates
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (void*)(sizeof(float)*2));
glEnableVertexAttribArray(1);
The last argument of glDrawArrays is the number of vertices. Since you just have 4 vertices, the argument cannot be 6*2.
Anyway, since you have specified an array indices it seems that you want to specify an Index buffer. You have to use glDrawElements for indexed rendering.
The indices have to be an integral data type:
int texindex[6] = {
0, 1, 2,
0, 2, 3
};
Generate the index (GL_ELEMENT_ARRAY_BUFFER) buffer:
unsigned int ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(int), texindex, GL_STATIC_DRAW);
Draw the tringles:
glDrawArrays(GL_TRIANGLES, 0, 6 * 2);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
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.
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
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.