OpenGL VBO access violation - pointers

I've been learning OpenGL the past few weeks and after reading the Swiftless tuts and part of Nehe's tuts, along side with other articles concerning normals, scene graphs, bla bla, i've decided to create some sort of "framework", to allow me to insert newly learned code easier. So I decided to create a scenegraph/renderer combo, not that pretty, not that fast (prolly), but with the option to add just a new derived node class to render a new whatever feature i might just have read. So i look on the interwebz to see various examples on how to implement one and settle on this base class:
#pragma once
#ifndef NODE_H
#define NODE_H
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/glext.h>
#include <math.h>
#include <windows.h>
#include <list>
using namespace std;
class Node
{
public:
Node(void);
~Node(void);
//Node* parent;
void addChild(Node* node);
void removeChilds(Node* node);
virtual void traverse();
void kill();
protected:
std::list<Node*> childs;
};
#endif
.... from which i made this class:
#pragma once
#ifndef NODESPHERE_H
#define NODESPHERE_H
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/glext.h>
#include <math.h>
#include <windows.h>
#include "Various.h"
#include "Node.h"
class NodeSphere : public Node
{
public:
NodeSphere(double R, double H, double K, double Z, const int space);
~NodeSphere(){delete this;}
void traverse();
private:
float out[3];
int Radius;
int vhVertexCount;
Vert *vhVertices;
Normal *vhNormals,*vhVNormals;
TexCoord *vhTexCoords;
unsigned int vhVBOVertices;
unsigned int vhVBOTexCoords;
unsigned int vhVBONormals;
bool Init(void);
bool Normals(const int nIndex);
bool ReduceToUnit(void);
};
#endif
Now, i use freeglut to handle the window creation and the loop:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <GL/glext.h>
#include <math.h>
#include "Scenegraph.h"
#include "View.h"
#include "Control.h"
#define WIDTH 800
#define HEIGHT 600
Scenegraph *bob;
View *myView;
Control *controler;
.................
.................
void main(int argc, char **argv)
{
glewInit();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WIDTH,HEIGHT);
glutInitWindowPosition(0,0);
glutCreateWindow("Mediensoftware - Finale Übung");
bob = new Scenegraph();
myView = new View(WIDTH, HEIGHT, bob);
controler = new Control(myView);
glutDisplayFunc(display);
glutIdleFunc(idle);
glutReshapeFunc(resize);
glutKeyboardFunc(keyboard);
glutSpecialFunc(keyboard_s);
glutMainLoop();
}
The Scenegraph "bob" handles the creation of nodes like this:
Scenegraph::Scenegraph()
{
this->root = new Node();
this->sun = new NodeSphere(3,0,0,0,10);
this->sun_transform = new NodeTransform();
this->sun_tex = new NodeTexture("sunmap.bmp");
this->sun_mat = new NodeMaterial(1.0,0,1.0,0.7,0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0);
this->planet_earth = new NodeSphere(1,0,0,0,10);
this->planet_earth_transform = new NodeTransform(6,0,0);
this->planet_earth_tex = new NodeTexture("earthmap.bmp");
this->planet_earth_mat = new NodeMaterial(1.0,0,1.0,0.7,0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0);
this->moon = new NodeSphere(0.3,0,0,0,10);
this->moon_tex = new NodeTexture("moonmap.bmp");
this->moon_transform = new NodeTransform(1.5,0,0);
this->moon_mat = new NodeMaterial(1.0,0,1.0,0.7,0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0);
this->planet_venus = new NodeSphere(0.8,0,0,0,10);
this->planet_venus_transform = new NodeTransform(3,0,0);
this->planet_venus_tex = new NodeTexture("venusmap.bmp");
this->planet_venus_mat = new NodeMaterial(1.0,0,1.0,0.7,0,1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0);
this->planet_mars = new NodeSphere(0.6,0,0,0,10);
................................................................................................
this->root->addChild(this->sun_transform);
this->sun_transform->addChild(this->sun_mat);
this->sun_mat->addChild(this->sun_tex);
this->sun_tex->addChild(this->sun);
this->sun->addChild(this->planet_venus_transform);
this->planet_venus_transform->addChild(this->planet_venus_mat);
this->planet_venus_mat->addChild(this->planet_venus_tex);
...................................................................................................
}
The compiler doesn't see any errors and executes the code, but it receives an access violation here:
bool NodeSphere::Init(void){
glGenBuffersARB(1, &vhVBOVertices); // DERP here
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vhVBOVertices);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, this->vhVertexCount * 3 * sizeof(float), this->vhVertices, GL_STATIC_DRAW_ARB);
glGenBuffersARB(1, &vhVBONormals);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vhVBONormals);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, this->vhVertexCount * 3 * sizeof(float), this->vhVNormals, GL_STATIC_DRAW_ARB);
glGenBuffersARB(1, &vhVBOTexCoords);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vhVBOTexCoords);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, this->vhVertexCount * 2 * sizeof(float), this->vhTexCoords, GL_STATIC_DRAW_ARB);
delete [] vhVertices;
vhVertices = NULL;
delete [] vhTexCoords;
vhTexCoords = NULL;
delete [] vhNormals;
vhNormals = NULL;
delete [] vhVNormals;
vhVNormals = NULL;
return true;
}
The extensions are called in the View::initExtensions(), the init of the Scenegraph is done after the window creation, so.... i'm pretty sure it has something to do with pointers...
on previous programs i used the exact same code for VBO creation and it worked. The only difference is that the code used here is used in a Node*, while the previous ones were used in just Node (no pointer). But in any case, i'm gonna check if glew starts up well.
As for what video card i am using, on the laptop i have a crappy Intel integrated card, which should support OpenGL 1.5, but doesn't even have GLSL, and on the PC, a 6850. The thing is that i work a lot on the laptop, because of faculty and other stuff as well.
But anyway, the code for creating VBO's works, i mean, it has worked for the following:
#include <stdlib.h>
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <GL/glew.h>
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#include <GL/glext.h>
#include <math.h>
#define PI 3.14159265f
class Vert{
public:
float x;
float y;
float z;
};
class Normal{
public:
float x;
float y;
float z;
};
class TexCoord{
public:
float u;
float v;
};
class Scenegraph {
private:
float out[3];
int Radius;
GLuint tID[2];
int vhVertexCount;
Vert *vhVertices;
Normal *vhNormals,*vhVNormals;
TexCoord *vhTexCoords;
unsigned int vhVBOVertices;
unsigned int vhVBOTexCoords;
unsigned int vhVBONormals;
bool Init(void);
bool Normals(const int nIndex);
bool ReduceToUnit(void);
public:
bool Create(double R, double H, double K, double Z, const int space);
void Render();
};
which is identical to NodeSphere, except it was statically declared. Thanks in advance.

Most likely, the error is occurring because the NodeSphere doesn't exist (or is no longer valid) when you try to call init().
You should probably move the resource initialization code into the constructor (that's generally what they're for) unless you need it to occur later on. It makes sense for the VBO to have a similar lifespan to the object, so creating and destroying them in the ctor/dtor should work and saves you the complexity of explicitly initializing.

Related

Crash when adding QGraphicsProxyWidget

I'm trying to have a QPushButton in my scene, but when I'm trying to add the QGraphicsProxyWidget to the scene, it crashes.
So here's the .cpp:
#include "upgradecromagnon.h"
#include "game.h"
#include <QGraphicsProxyWidget>
#include <qDebug>
extern Game *game;
UpgradeCromagnon::UpgradeCromagnon()
{
this->setRect(-50,0,150,50);
buttonAmelio = new QPushButton("salut");
teste();
}
void UpgradeCromagnon::teste()
{
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();
proxy->setWidget(buttonAmelio);
scene()->addItem(proxy);
}
and its .h:
#ifndef UPGRADECROMAGNON_H
#define UPGRADECROMAGNON_H
#include <QPainter>
#include <QGraphicsRectItem>
#include <QPushButton>
class UpgradeCromagnon: public QGraphicsRectItem
{
public:
UpgradeCromagnon();
void teste();
private:
QPushButton *buttonAmelio;
};
#endif // UPGRADECROMAGNON_H
Your UpgradeCromagnon constructor calls UpgradeCromagnon::teste which, in turn, calls QGraphicsItem::scene. At that point QGraphicsItem::scene must return a null pointer since there's no possible way the UpgradeCromagnon instance can have been added to a QGraphicsScene before its contructor has completed (not according to the code you've provided at any rate).

How to exit a "game" in Qt when health is 0

I'm quite new to Qt, but I got into it to start experimenting with making 2D games. I've got a extremely rough and simple game started, but I have an issue. Whenever the health gets to 0, the game doesn't end. I just want to know how to end the game and where to put this exit command before making a "Game Over" screen. My code is below, and from what I can grasp, I assume the QApplication::quit() goes in the Game.cpp file. Doing this by taking the health integer from Health.cpp and Health.h and putting it in Game.cpp. Any help is appreciated. Here is the code I feel the answers lie in, if more info is needed, ask.
Game.h
#ifndef GAME_H
#define GAME_H
#include <QGraphicsView>
#include <QWidget>
#include <QGraphicsScene>
#include "Player.h"
#include "Score.h"
#include "Health.h"
#include "Level.h"
#include "Main.h"
class Game: public QGraphicsView{
public:
Game(QWidget * parent=0);
QGraphicsScene * scene;
Player * player;
Score * score;
Health * health;
Level * level;
Main * close;
int end();
};
#endif // GAME_H
Game.cpp
#include "Game.h"
#include <QTimer>
#include <QGraphicsTextItem>
#include <QFont>
#include "Enemy.h"
#include <QMediaPlayer>
#include <QBrush>
#include <QImage>
#include <QApplication>
Game::Game(QWidget *parent){
// create the scene
scene = new QGraphicsScene();
scene->setSceneRect(0,0,800,600); // make the scene 800x600 instead of infinity by infinity (default)
setBackgroundBrush(QBrush(QImage(":/images/bg.png")));
// make the newly created scene the scene to visualize (since Game is a QGraphicsView Widget,
// it can be used to visualize scenes)
setScene(scene);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFixedSize(800,600);
// create the player
player = new Player();
player->setPos(400,500); // TODO generalize to always be in the middle bottom of screen
// make the player focusable and set it to be the current focus
player->setFlag(QGraphicsItem::ItemIsFocusable);
player->setFocus();
// add the player to the scene
scene->addItem(player);
// create the score/health
score = new Score();
scene->addItem(score);
health = new Health();
health->setPos(health->x(),health->y()+25);
scene->addItem(health);
level = new Level();
scene->addItem(level);Bull
level->setPos(level->x(),level->y()+50);
// spawn enemies
QTimer * timer = new QTimer();
QObject::connect(timer,SIGNAL(timeout()),player,SLOT(spawn()));
timer->start(2000);
// play background music
QMediaPlayer * music = new QMediaPlayer();
music->setMedia(QUrl("qrc:/sounds/bgsound.mp3"));
music->play();
show();
}
int Game::end(){
if (health == 0){
QApplication::quit();
}
return 0;
}
Health.h
#ifndef HEALTH_H
#define HEALTH_H
#include <QGraphicsTextItem>
class Health: public QGraphicsTextItem{
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
private:
int health;
};
#endif // HEALTH_H
Health.cpp
#include "Health.h"
#include <QFont>
#include <QApplication>
Health::Health(QGraphicsItem *parent): QGraphicsTextItem(parent){
// initialize the score to 0
health = 3;
// draw the text
setPlainText(QString("Health: ") + QString::number(health)); // Health: 3
setDefaultTextColor(Qt::red);
setFont(QFont("times",16));
}
void Health::decrease(){
health--;
setPlainText(QString("Health: ") + QString::number(health)); // Health: 2
}
int Health::getHealth(){
return health;
}
main.cpp
#include <QApplication>
#include "Game.h"
#include "Main.h"
Game * game;
int main(int argc, char *argv[]){
QApplication a(argc, argv);
game = new Game();
game->show();
return a.exec();
}
Your end() function is never called.
The best way to achieve what you want to is to use Qt's signal/slot mechanism. It amkes it easy to connect an event (signal) to an action (slot):
Add Q_OBJECT macro to Health and Game classes and make sure your compilation environment moc's the two header files
Declare in Health a signal named dead()
Emit the signal from Health::decrease()
Make Game::end() be a slot and be void
Connect Health::dead() to Game::end()
Then, Game::end() will be called as soon as Health reaches zero.
class Health: public QGraphicsTextItem
{
Q_OBJECT
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
signals:
void dead();
private:
int health;
};
...
class Game: public QGraphicsView{
Q_OBJECT
public:
...
public slots:
void end();
};
...
void Health::decrease(){
health--;
setPlainText(QString("Health: ") + QString::number(health));
if ( health == 0 )
emit dead();
}
...
Game::Game(QWidget *parent){
...
connect( health, SIGNAL(dead()), this, SLOT(end()) );
}
...
void Game::end(){
// no need to test health anymore, as signal is emited when health is zero
// do some extra stuff before exiting
QApplication::quit();
}
If end() only calls QApplication::quit(), you can remove it and diectly connect the signal to QApplication::quit(), like that:
connect( health, SIGNAL(dead()), qApp, SLOT(quit()) );
Also note that you were testing health == 0 in Game::end(), but health is a pointer, and, looking at your code, it will never be 0 (you maybe meant to write if ( health->getHealth() == 0 ).
In Health::decrease emit a signal or put the logic for it in where the "player is shot" area. But to do that, you to Health or the class with the logic to be a QObject so that it gets the signals and slots in the header. EDIT QGraphicsTextItem is already a QObject. See comments.
Connect the signal to the view's close() right after the Health class or Player class is instantiated.
http://doc.qt.io/qt-5/signalsandslots.html
Hope that helps.

Dynamically adding widgets to gridLayout Qt

I am having a bit of difficulty with some code. I am super rather new to Qt so it is entirely possible that I am simply ignorant to the problem I am having.
Basically, I am blocking out a program so that I can add the specifics of it later. I want to be able to create a grid of buttons, and when one of those buttons is pressed, another shape to replace it.
I am able to make my button grid, have it be scrollable, and have the button call it its position on the grid when pressed. However, when I try and use those coordinates to add another button to the grid, Qt crashes.
Here's my code so far:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QScrollArea>
#include <QDebug>
#include <QString>
#include <QSignalMapper>
#include <QStringList>
#include <QLayoutItem>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
populateViewGrid(); //I wanted to see if I could add in a scrollbar
//from outside the main window. Could this be causing
// the issue?
}
void MainWindow::populateViewGrid()
{
QScrollArea*scrollArea = new QScrollArea(this);
QWidget*central = new QWidget(this);
QGridLayout*gridLayout = new QGridLayout(central);
QSignalMapper *signalMapper = new QSignalMapper(central);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
QString position= QString("%1,%2").arg(i).arg(j);
QPushButton* button = new QPushButton("addTrack",central);
gridLayout->addWidget(button, i, j);
connect(button, SIGNAL(clicked()),signalMapper, SLOT(map()));
signalMapper->setMapping(button, position);
}
}
connect(signalMapper, SIGNAL(mapped(QString)),this, SLOT(addTrack(QString )));
central->setLayout(gridLayout);
scrollArea->setWidget(central);
setCentralWidget(scrollArea);
}
void MainWindow::addTrack(QString position)
{
QStringList query = position.split(",");
int x;
x=query.at(0).toInt();
int y;
y=query.at(1).toInt() ;
QPushButton *Ifthisworks=new QPushButton(this);
//This first line is where is crashes. I know this due to having the code
//laced with qDebugs. From all of my google searches and such, it seems that
// something simple should be wrong and I can't find it.
QLayoutItem * existingitem = gridLayout->itemAtPosition(x, y);
if(existingitem) {
gridLayout->removeItem(existingitem);
delete existingitem;
}
// before I included the above to remove the button from the grid point, the
//program would crash here.
gridLayout->addWidget(Ifthisworks, x, y);
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <cmath>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QApplication>
#include <QPushButton>
#include <QMainWindow>
#include <QScrollArea>
#include <QSignalMapper>
#include <QHash>
//unrelated question, do I need the above in my code? I know not all of them
//used, but do I need includes in this file as well?
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void populateViewGrid();
QGridLayout *gridLayout;
public slots:
void addTrack(QString);
private:
QScrollArea*scrollArea;
QWidget * central;
QPushButton *Ifthisworks;
QSignalMapper *signalMapper;
QPushButton *clockViews;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
If you could help me understand how to not make Qt crash there and also add a button, that would be fantastic =)
So some background real quick incase you are looking at my code and are scratching your head. I'm a mechanical engineer who should have probably been an electrical or computer engineer and knows enough about coding to get myself into these kinds of messes. For the most part, I searched for what I wanted Qt to do and hacked it all together to hopefully make it work. Any bit of deeper understanding you can share would be more than welcome.
Thank you for your time.
You are initializing a local variable called gridLayout in your MainWindow::populateViewGrid() method:
QGridLayout*gridLayout = new QGridLayout(central);
Then in your MainWindow::addTrack(QString position) method, you are trying to access the member variable called gridLayout which is never initialized.
To fix this, simply initialize the member variable instead of creating a local variable in your MainWindow::populateViewGrid() method:
gridLayout = new QGridLayout(central);
You are doing the same mistake with your other member variables as well. Fix them the same way.
I would go for a different implementation.
Move gridlayout, signalmapper,... to be class members. I personally like also to keep a list of my widgets QList<QPushButton*> for manually deleting or keeping a button cache.
Make the signalmapper to map to index in list or QWidget*. For the example i`ll go with the QWidget* pointer.
QPushButton *newButton = new QPushButton("The new Thing");
QPushButton *oldButton = static_cast<QPushButton*>(widgetPointer);
gridLayout->replaceWidget(oldButton ,newButton);
buttonList->takeAt(buttonList->indexOf(oldButton))->deleteLater()); //if you keep a list..
buttonList->insert(buttonList->indexOf(oldButton),newButton);

Qt QOpenGLFunctions not declared in this scope

I'm creating a sort of drawable object class for mesh data and i'm getting this linker error. This is also on top of another class that handles the drawing of the meshes that was used in one of the Qt tutorials. I'm also using a QGLWidget to be the surface i'm drawing to. Here's what the header file looks for the first class.
#ifndef GLOBJECT_H
#define GLOBJECT_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector3D>
#include <QVector2D>
#include <QDebug>
#include <QFile>
struct VertexData
{
QVector3D position;
QVector2D texCoord;
QVector3D normal;
};
class GLObject
{
public:
GLObject();
VertexData *data;
GLushort *indices;
GLuint vboIds[2];
int faceCount, vertCount;
bool generateFromPLY(QString filename);
};
#endif // GLOBJECT_H
Here's the header for the other class.
#ifndef GEOMETRYENGINE_H
#define GEOMETRYENGINE_H
#include <QObject>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QVector2D>
#include <QVector3D>
#include <QFile>
#include <QDebug>
#include <QVector>
#include <globject.h>
class GeometryEngine : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
GeometryEngine();
~GeometryEngine();
void init();
void drawGeometry(QOpenGLShaderProgram *program);
//void drawCubeGeometry(QOpenGLShaderProgram *program);
bool generateFromPly(QString filename);
QVector<GLObject> drawables;
int drawableId = 0;
};
#endif // GEOMETRYENGINE_H
G:\Dropbox\GLSLDemo\globject.cpp:60: error: 'glGenBuffers' was not declared in this scope
glGenBuffers(2, vboIds);
along with the same error for the other gl calls.
Initially I had all the code in GeometryEngine to begin with. I didn't have a scope issue then. initilizeOpenGLFunctions() is called in GeometryEngine's init() if that's relevant.
^
QT OpenGL is weird. I think the QOpenGLFunctions maintains a common context. Also i'm bad at C++ and used protected wrong.

Problems with function QTimer::singleShot

I am trying to record sound by QAudioInput. According to the doc in this website QAudioInput. But when I ran, it exported an empty-raw file. After checking, It seems like the function QTimer::singleShot didn't working ( I added statement qWarning << "Done" in void stopRecording() and It didn't display "Done" so I thought it had some mistake in QTimer::singleShot function ).
This is my code used to check function QTimer::singleShot
----Check.pro----
QT += core
QT -= gui
TARGET = Check
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += test.h
-----test.h------
#ifndef TEST_H
#define TEST_H
#include <QCoreApplication>
#include <QTimer>
#include <iostream>
#include <QObject>
#include <test.h>
#include <QDebug>
using namespace std;
class Object: public QObject {
Q_OBJECT
private slots:
void func() { cout << "Hello"; }
};
#endif // TEST_H
----main.cpp----
#include <QCoreApplication>
#include <QTimer>
#include <iostream>
#include <QObject>
#include <test.h>
#include <QDebug>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object *o = new Object;
QTimer::singleShot(10000, o, SLOT(func()));
return 0;
}
And this code doesn't working, too. Can anyone explain me? I am newbie at Qt-programming.
Your program exits right after it's set the timer - it has no time to fire.
For the timer to work, you need an event loop running. Without the event loop, no events get processed.
Change the last line of your main to
return a.exec();
Also change your test slot by adding << std::endl or flush std::cout otherwise you might see no output on the console.
Your program should then work as expected (except it won't ever finish since nothing will cause the event loop to stop - just interrupt it).

Resources