I have been trying to make an asteroids clone using openGL and have gotten totally stuck on a segmentation error I am unsure how to fix. It seems to happen on the usage of the function glGenBuffersARB(). If I comment out the lines using the vertexbuffer, the program compiles and runs fine (but obviously with nothing rendered). I am using the minGW compiler on eclipse with the gdb debugger and trying to use extensions so I can support versions of OpenGL earlier than 1.5.
glGenBuffers(1, &_VertexBufferObject);
glBindBufferARB( GL_ARRAY_BUFFER_ARB, _VertexBufferObject ); // Bind The Buffer
glBufferDataARB( GL_ARRAY_BUFFER_ARB, U8VertexCount*3*sizeof(GLfloat), quad,GL_STATIC_DRAW_ARB );
GLuints are declared as private in a header like this:
GLuint _VertexArrayObject;
GLuint _VertexBufferObject;
int U8VertexStride;
int U8VertexCount;
gdb traces are here: gdb trace
I have found a solution to the problem. It would appear that declaring and using an object was not working the way I had intended. I was declaring the objects as:
CObj Obj;
and calling draw like this:
Obj.Draw();
when I switched to declaring it as a pointer:
CObj * Obj;
and initialising it like this:
Obj = new CObj();
then using:
Obj->Draw();
started to work as i thought it should. I am unsure why this is the case and would appreciate it if anyone is able to clear this up for me.
Related
So when I run the app, at the biginning every thing runs smooth, but the more it goes, the slower it is. I looked at the memory it was using and when it reaches 400 mb it completely stops for 30 secs and then drop back to 200.
I am pretty new to SDL2, and I assume it is because each frame I call:
optionsTS = TTF_RenderText_Blended(font, "Options.", blanc);
optionsT = SDL_CreateTextureFromSurface(renderer, optionsTS);
for example and I have plenty of them.
The problem is that I don't know how to delete properly the object each frame, because if I do a SDL_FreeSurface I get an error.
I won't publish my whole code because it's a mess, but if you want it, feel free to ask.
Do you know how to fix that?
Just thought I would turn my comment into an answer.
In your code you call
optionsTS = TTF_RenderText_Blended(font, "Options.", blanc);
optionsT = SDL_CreateTextureFromSurface(renderer, optionsTS);
every frame, I suspect that if you remove them from there, initialise them outwith of the render loop and simply pass them in as arguments, you should lose the memory leak: the reason being that you will create only one in-memory instance of each and then you can repeatedly use them as needed. On looking at it again, I suspect that you could destroy optionTS once you have made optionT, that way you will save even more memory. (not tested yet as my main machine just crashed this weekend, and I am still re-installing drivers and VS2010)
As a general rule, try and not create/destroy any objects in the render loop, tends to get big and messy fast.
Consider taking advantage of RAII in C++ if possible.
For example, create a class that wraps an SDL_Surface and calls SDL_FreeSurface in the destructor.
class MySurface
{
public:
MySurface(SDL_Surface & surface) : m_surface(surface) {}
~MySurface() {SDL_FreeSurface(m_surface);}
SDL_Surface & GetSDLSurface() {return m_surface;}
private:
SDL_Surface & m_surface;
};
You would then create an instance of MySurface every time you grabbed an SDL_Surface from the SDL API, and you won't have to worry about when or whether to free that surface. The surface will be freed as soon as your instance of MySurface goes out of scope.
I'm certain better implementations can be written and tailored to your needs, but at a minimum something similar to this may prevent you from having leaks in the future.
I am creating an application using SDL2 & OpenGL, and it worked fine on 3 different computers. But on another computer (an updated arch linux), it doesn't, and it crashes with this error:
OpenGL context already created
So my question is: How do I check if the OpenGL context has already been created? And then, if it is already created, how do I get a handle for it?
If I can't do this, how do I bypass this issue?
SDL2 does not in fact create an OpenGL context without you asking to make one. However, if you ask it to create an OpenGL context when OpenGL doesn't work at all, SDL2 likes to, erm, freestyle a bit. (The actual reason is that it does a bad job in error checking, so if X fails to create an OpenGL context, it assumes that it's because a context was already created)
So, to answer the third question ("how do I bypass this issue"), you have to fix OpenGL before attempting to use it. Figures, right?
To answer the first and second, well, no API call that I know of... but you can do it a slightly different way:
SDL_Window* window = NULL;
SDL_GLContext* context = NULL; // NOTE: This is a pointer!
...
int main(int argc, char** argv) {
// Stuff here, initialize 'window'
*context = SDL_GL_CreateContext(window);
// More stuff here
if (context) {
// context is initialized!! yay!
}
return 2; // Just to confuse people a bit =P
}
I am facing an odd problem with the OpenGL function glGenBuffers().
I'm writing a fairly simple application in which I use a VBO declared in the following way:
#include <QGLFunctions>
#include <QGLWidget>
class MyClass : public QGLWidget, protected QGLFunctions {
GLuint vertexBufferObject;
// ...
GLuint makeBufferList(void);
}
GLuint MyClass::makeBufferList(void) {
vertexBufferObject = 0;
glGenBuffers(1, &vertexBufferObject); // <-- Here it crashes
// ... load data and render
return vertexBufferList;
}
MyClass::MyClass(QWidget* parent)
: QGLWidget(parent),
vertexBufferObject(0)
{
QGLContext* context = new QGLContext(this->format());
initializeGLFunctions(context);
glInit();
}
MyClass::~MyClass() {
glDeleteBuffers(1, &vertexBufferObject);
}
This all works perfectly fine in the Debug Build. The data is rendered nicely and all and the programme finishes correctly in the end.
However, in Release Build, the glGenBuffers() crashes the programme. It doesn't just return 0 or do nothing, it crashes right at the function call. But since the problem only occurs in Release mode, I can't use the debugger to find out what's going wrong.
I'm working on a Windows 7 system and developing in Qt 4.8.1. The compiler is the MSVC 2010 (Qt SDK) compiler.
Does anyone have any suggestions that I might try?
// Edit:
Maybe useful to know: I tried to compile exactly the same code on a Mac, using the GCC (Qt SDK) compiler, and both the Debug and Release Build work perfectly fine. But on Windows 7, the problem persists.
Found the the trouble (thanks to #MahmoudFayez): the problem comes from a bug in the Qt API, which makes the glGenBuffers() function (and possibly others as well) crash. The question is directly equivalent to the issue discussed here:
Unhandled Exception using glGenBuffer on Release mode only - QT
http://qt-project.org/forums/viewthread/12794
The solution is relatively simple although not very elegant: use GLEW instead of QGLFunctions. I fixed my problem in the following way:
#include "glew.h"
#include <QGLWidget>
class MyClass : public QGLWidget {
// ...same as the above
}
MyClass::MyClass(QWidget* parent)
: QGLWidget(parent),
vertexBufferObject(0)
{
makeCurrent();
glewInit();
}
This solved everything. A disadvantage is that this involves using an extra external dependency, whereas using Qt is all about being as compatible as possible, with as few external dependencies as you possibly can. However, it seems that we need to wait until Qt 5.0 is released before this bug may be fixed.
As a final comment: I have not been able to figure out which part in this bug makes only the Release Build that crashes, but not the Debug mode.
I have fixed the linker errors I had in this question, but now I am having another problem. I create my objects by calling createObject() in lua and that creates a boost::shared_ptr to a new object, adds it to a list, and returns it.
On windows with mingw when I make changes in lua the changes do not get applied to the C++ object. it cannot be a problem with my code because I built the same thing on Linux and it worked fine.
ObjectPtr createObject(PlayerPtr player){
ObjectPtr obj(new Object(player));
window->world.objects.push_back(obj);
return obj;
}
bool setup(lua_State* luastate, Window* caller){
open(luastate);
// initialize some other classes here.
class_<Player, PlayerPtr> Player("Player");
Player.def_readwrite("playerColor", &Player::playerColor);
Player.def_readwrite("displayName", &Player::displayName);
class_<Object, ObjectPtr> Object("WorldObject");
Object.def_readwrite("health", &Object::health);
Object.def_readwrite("maxHealth", &Object::maxHealth);
Object.def_readwrite("mesh", &Object::mesh);
Object.def_readwrite("location", &Object::location);
Object.property("player", &Object::getPlayer, &Object::setPlayer);
Object.def("setOnDeath", &Object::setOnDeath);
module(luastate)[
vec3,
color,
Player,
WorldObject,
def("isWindowOpen", &isWindowOpen),
def("loadMesh", &MeshManager::LoadMesh),
def("createObject", &createObject),
def("createPlayer", &createPlayer),
];
window = caller;
}
ObjectPtr and PlayerPtr are boost::shared_ptr of Object and Player, window is a static Window pointer, and createPlayer() is the same as createObject() without any arguments and using Player instead of Object.
in lua:
red = createPlayer()
red.playerColor = Color(255,0,0)
red.displayName = "Red"
obj = createObject(red)
obj.location = vec3(10,10,0)
print(obj.player.displayName)
results in "Red" being put in the console.
but in C++ the value is just "".
I debugged it and the objects do get created and added to the list in C++, but no changes were ever made, as all variables are in there default state.
I think it is a problem with luabind and mingw, or just something wrong with the build,
the only things I changed from the default build setup were 2 things I needed to do to get it to compile at all: I set LUA_PATH in the jamfile to point to the directory lua is in (rather than getting it from an environmental variable) and I changed
#elif BOOST_PP_ITERATION_FLAGS() == 1
to
#else
#if BOOST_PP_ITERATION_FLAGS() == 1
because mingw did not like the ( for some reason... (and yes I did add the #endif in the right place)
UPDATE: I have tried using msvc10 also, and it still has the same problem. I have also tried building it against the same version of boost that is on my Linux. but to no avail.
This is an SDL problem, however I have the strong feeling that the problem I came across is not related to SDL, but more to C++ / pointers in general.
To make a long story short, this code doesn't work (edited to show what I really did):
player->picture = IMG_Load("player");
SDL_BlitSurface(player->picture, NULL, screen, &pictureLocation);
I see nothing on the screen. However, when I do it like this, it works:
SDL_Surface* picture = IMG_Load("player.png");
player->picture = picture;
SDL_BlitSurface(player->picture, NULL, screen, &pictureLocation);
I can see the little guy just fine.
The real problem is that I cannot instantiate Player::picture directly. Even when I try
picture = IMG_Load("player.png")
in player.cpp, I end up with a nullpointer.
I am so stupid. Turns out like I forgot the file extension ".png" every time I tried to store the surface in Player::picture, and conveniently remembered to add it every time I stired it in an SDL_Surface declared in main.cpp.
I had the feeling I was overlooking something really simple here, but this is just embarassing. What's a fitting punishment for this?
What data type is player->picture? What type does IMG_Load return? It's really hard to come up with a scenario where saving an expression in a temporary variable changes the result, unless a type conversion is involved.
And I wouldn't call this pointer instantiation. You're instantiating an instance of some picture type and storing a pointer to it.
This is why you should always check to see what IMG_Load() returns...
SDL_Surface* picture = IMG_Load("player.png");
if (picture == NULL) {
// there was obviously some sort of error.
// what does SDL_GetError() say?
}
Some SDL functions return -1 if there is an error. Just check the documentation and make sure you're checking your function returns. These steps make debugging a lot easier.