OpenGL - drawing objects using text file - c++

I have loaded an array from a text file, which contains positions of objects, and it looks like this:
0,0,0,5
0,5,0,0
0,0,5,0
0,5,5,0
The object looks like this:
struct object
{
int x, y, value;
}
Where x,y are coordinates, and value is 1 or 0 (it tells if an object was "picked", all objects have 1 at the beginning). Objects are stored in an array object obj_array[5].
To draw them, I use this function:
(BOARD_Y and BOARD_Y is size of the array, here is 4x4)
void draw_board(){
for (int iy = 0; iy < BOARD_Y; iy++) {
for (int ix = 0; ix < BOARD_X; ix++) {
if ( (board[iy][ix] == 5) )
{
glPushMatrix();
glTranslatef( ix, iy, 0 );
glutSolidCube(1);
glPopMatrix();
}
}
}
}
And it draws all of them perfectly. But I want to skip drawing an object, if its value is 0 (the object was picked by a player). How can I do this?

Okey, I can see what's going on; you've complicated the things a bit. There's no way to access the arbitrary object just from this loop, apart from pretty stupid comparison of position:
if ( (board[iy][ix] == 5) ) {
for (auto const& obj : objects) {
if (obj.x == ix && obj.y == iy) {
// obj is the object in given position
// ...
break;
}
}
}
Don't do that.
Instead either store some reference to the objects on the board. By reference I mean (not limited to!):
An unique object ID
Pointer to the object
Then, you will be able to access the object residing on given tile much faster and easier. If you want examples, drop a comment, but I think both options are fairly easy to implement.
If you still want to hold these "5" inside, change board to array of structs. And oh, please use std::array instead of int**.
Here's the example
using id_t = unsigned;
std::map<id_t, object> objects;
constexpr std::size_t size_x = 4, size_y = 4;
std::array<id_t, size_x * size_y> board;
Let's assume that id equal to 0 means that the object is not there.
Now you can access the specific object by:
unsigned x, y;
id_t obj_id = board[x + size_x * y];
if (obj_id != 0) // is there any object?
if (objects[obj_id].value != 0) // is its value equal to 0?
// ...
And set it by board[...] = obj;
Easy way to generate unique id for every object is just to increment the counter.
id_t last_id = 1;
objects[last_id++] = obj_id;

Related

Overflowing the stack memory with my quadtree class and don't know why

I have been working on a quadtree class for possible collision detections, but the more items I add the faster I overflow the stack.
I also noticed the memory usage increases linearly as the program runs so I assume I am not deleting something properly and it is just stacking on each other?
I know most stack overflow errors are caused by recursion but it shouldn't be happening with just 100 objects.
#include "Quadtree.h"
Quadtree::Quadtree(Rectangle* bounds)
{
this->bIsSplit = false;
this->bounds = bounds;
this->maxObjects = 5;
}
void Quadtree::Split(std::vector<std::pair<SpaceObject*, SpaceObject*>> &collidingObjects)
{
float x = bounds->x;
float y = bounds->y;
float subWidth = bounds->width / 2;
float subHeight = bounds->height / 2;
// Top Left
nodes.push_back(new Quadtree(new Rectangle(x, y, subWidth, subHeight)));
// Top Right
nodes.push_back(new Quadtree(new Rectangle(x + subWidth, y, subWidth, subHeight)));
// Bottom Left
nodes.push_back(new Quadtree(new Rectangle(x, y + subHeight, subWidth, subHeight)));
// Bottom Right
nodes.push_back(new Quadtree(new Rectangle(x + subWidth, y + subHeight, subWidth, subHeight)));
// takes all the objects in the parent node and splits them into there corresponding subdivided quadtree
for (auto o : this->objects)
{
for (int i = 0; i < nodes.size(); i++)
{
if (nodes[i]->bounds->Contains(o->x, o->y, o->size))
{
nodes[i]->Insert(o, collidingObjects);
}
}
}
this->objects.clear();
this->bIsSplit = true;
}
void Quadtree::Insert(SpaceObject* spaceObject, std::vector<std::pair<SpaceObject*, SpaceObject*>> &collidingObjects)
{
// if the object does not fit inside this quadtree, this isn't the right quadtree
if (!bounds->Contains(spaceObject->x, spaceObject->y, spaceObject->size))
{
return;
}
if (!bIsSplit && this->objects.size() < maxObjects) // add the object to the quadtree if the max has not been hit
{
objects.push_back(spaceObject);
for (auto o : this->objects)
{
// if the objects are not the same and overlapping (pythag)
if (spaceObject != o &&
((spaceObject->x - o->x) * (spaceObject->x - o->x)) + ((spaceObject->y - o->y) * (spaceObject->y - o->y)) <= (spaceObject->size + o->size) * (spaceObject->size + o->size))
{
// Add colliding pair to the collidingObjects vector
collidingObjects.push_back(std::make_pair(spaceObject, o));
}
}
}
else
{
if (!this->bIsSplit) // splits the quadtree if this quadtree has not been split yet
{
this->Split(collidingObjects);
}
// adds the passed in object to one of the subnodes
for (auto n : nodes)
{
n->Insert(spaceObject, collidingObjects);
}
}
}
void Quadtree::Delete(SpaceObject* spaceObject)
{
if (!bounds->Contains(spaceObject->x, spaceObject->y, spaceObject->size))
{
return;
}
if (!bIsSplit)
{
for (int i = 0; i < objects.size(); i++)
{
if (objects[i] == spaceObject)
{
this->objects.erase(objects.begin() + i);
return;
}
}
}
else
{
for (auto n : nodes)
{
n->Delete(spaceObject);
}
}
}
void Quadtree::Clear()
{
if (bIsSplit)
{
for (auto n : nodes)
{
n->Clear();
}
this->bIsSplit = false;
}
nodes.clear();
objects.clear();
}
Well, I can't tell what nodes is or how Quadtree is defined because you are not showing the complete code. But it's suspicious that you are using new. Is nodes a collection of pointers? If so, you are probably dropping them on the floor since they are never deleted.
Don't write this-> all over the place. Members are in the scope of the member functions. Your Quadtree constructor should be using inline initializers for the constant members and an initializer list for the bounds. And, using a bare pointer here is a red flag. What is the ownership of this bounds? Why does it need to be a pointer rather than simply a value of type Rectangle?
I wonder if you are used to a different language, one that uses new for all construction, and has reference semantics and objects are really pointers. C++ is different.
I'd suggest writing it without using any pointers. For sure, the Rectangle should be a value. A vector of Quadtree can be efficient when inserting and deleting etc. if the elements can be efficiently moved. So, Quadtree should have a move constructor. That is probably an advanced concept if you don't know all about constructors and special members yet.
What you should definitely follow, even as (especially as) a beginner, is ⧺C.149 — no naked new or delete. So, if you need to make a vector of pointers to Quadtree, make it a vector of shared_ptr. Remember, you don't have garbage collection in C++ so anything that's using a pointer has to explicitly deal with responsibility of lifetime management. A shared_ptr will behave more like you're used to, and they are safe for use in containers like vector.

How to check whether an index in an array is empty

I'm making a small OpenGL program for my intro to C++ class in Uni. I have a program that is complete but I want to change it up a bit to make it more unique. I have a Cube class:
class Cube {
public:
Cube(Mesh* mesh, Texture2D* texture, float x, float y, float z);
~Cube();
void Draw();
void Update(float rSpeed);
Vector3 position;
private:
GLfloat rotationSpeed;
Vector3 rotationVector;
Mesh* _mesh;
Texture2D* _texture;
};
I then create an array of type Cube:
Cube* cubes[CUBE_AMOUNT];
I then fill each index of this array with data to draw the cube on screen later in the program:
for (int i = 0; i < CUBE_AMOUNT; i++) {
float x = ((rand() % 400) / 10.0f) - 20.0f;
float y = ((rand() % 200) / 10.0f) - 10.0f;
float z = -(rand() % 1000);
if (i % 2 == 1) {
cubes[i] = new Cube(cubeMesh, textureStars, x, y, z);
}
else {
cubes[i] = new Cube(cubeMesh, texturePenguins, x, y, z);
}
}
With this new thing I want to add to the program, I want to check whether an index of cubes[] has been filled with the data yet. However I keep getting exceptions when running. I have tried to check whether cubes[i] is equal to nullptr, and tried checking whether it is NULL too, but neither seem to match.
Sorry for any errors in terminology that I used. New to C++, and having come from only doing Python before this, it is confusing!
Solution:
When I create the array, I changed it to Cube* cubes[CUBE_AMOUNT] = { NULL }, and now when checking the array, cubes[i] == NULL!
If cubes is not a global variable, you can use:
Cube* cubes[CUBE_AMOUNT] = {};
to initialize all the elements to nullptr.
You can also use:
std::vector<std::unique_ptr<Cube>> cubes(CUBE_AMOUNT);
to remove the burden of having to deallocate dynamic memory in your code.
In either case, can use:
if ( cubes[index] )
{
// Got a valid pointer. Use it.
}
Your cubes variable is not automatically initialized with null_ptr's. Until you either fill it with null_ptr's or good pointers it initially points to random garbage.
I think this would work
//This bit should check if theres anything stored currently.
cout << "\nWhich Slot would you like to store the informaton in ?(1-10)";
cin >> i;
i--;
if (information[i] != NULL){
// Already written
cout << "THERES SOMETHING HERE";
}
else{
cout << "\nEMPTY!!!!!!!!!";
}

Unspecified behaviour of std::vector with pointer to object

I have found nerve wracking issue which I seem to be unable to solve.
SceneSettings::SceneSettings()
{
unsigned int w = (ConfigurationManager::GetInstance().GetWidth() >> 1) - 80;
unsigned int h = (ConfigurationManager::GetInstance().GetHeight() >> 1) - 50;
std::vector< std::string > menu_items;
menu_items.push_back("Graphic Settings");
menu_items.push_back("Sound Settings");
menu_items.push_back("Game Settings");
menu_items.push_back("Back");
Label* aux = NULL;
for ( unsigned int i = 0; i < menu_items.size(); i++ )
{
aux = new Label(menu_items[i], w, h);
items.push_back(aux);
aux = NULL;
aux = new Label(menu_items[i], w, h);
aux->SetColor(255, 0, 0);
hover_section.push_back(aux);
hover.push_back(false);
aux = NULL;
h += 25;
}
}
SceneSettings::~SceneSettings()
{
for (unsigned int i = 0; i < items.size(); i++)
{
delete items[i];
delete hover_section[i];
}
items.clear();
hover_section.clear();
}
void SceneSettings::Draw()
{
for ( unsigned int i = 0; i < items.size(); i++ )
{
if (hover[i])
hover_section[i]->Draw();
else
items[i]->Draw();
}
}
void SceneSettings::HandleEvents(SDL_Event& event)
{
switch(event.type)
{
case SDL_MOUSEMOTION :
{
int x = event.motion.x;
int y = event.motion.y;
for ( unsigned int i = 0; i < items.size(); i++ )
hover[i] = items[i]->GetIsInLabel(x, y);
} break;
}
}
Now what it does is, that first label "Graphic Settings" is not displayed. (not invisible, just plainly not visible)
items are defined as:
std::vector< Label* > items;
std::vector< Label* > hover_section;
std::vector< bool > hover;
For some reason it doesnt work, however in another scene ("main_menu") I have identical vector of labels (only captions are different) which works ok.
Now this one is more interesting that it seems. Since not only does it not display first item, but it displays 1st hover item even if mouse is completely out its range.
If I replace std::vector for direct Label* menu_item_1 in SceneSettings header, it displays correctly. Which leads me to think its connected to std::vector
One more thing I don't quite understand is, that if I run it in debug mode and going by steps, it displays correctly, however neither watches nor call stack does show anything unusual.
Any help is appreciated.
If you are passing SceneSettings objects by value anywhere, either as arguments to functions or returning such objects, then you definitely need to consider your use of pointers in the vectors, or have to implement a copy-constructor and a copy-assignment operator (as told by the rule of three).
The default functions created by the compiler will only do shallow copying, i.e. it copies the vectors and the pointers, it doesn't create new pointers (deep copying). That leads to you having two objects both containing pointers to the same objects in the vectors, and if one object is destructed if will free the memory, leaving the other object with stray pointers and that will lead to undefined behavior.
It turns out the problem was in Label class, in which I neglected to initialize texture and buffer ids for GLSL. Adding initial values (0) to them in Label constructor fixed the problem.

passing values to a boolean array

I'm working on a simple 2d game engine, and am trying to set up a system where the player model can move behind certain objects. Every time an non-player object is blitted to the screen, its X and Y are recorded in an array so they can be used later. As such, I have set up a system where if the player X and player Y are relative to an environmental object's X and Y in a certain way, the environmental object is not immediately blitted (Normally, it would be immediately blitted before the player character so that the player character is above the object). Instead of being blitted, I have a true value be handed to a boolean array. I have an int variable that gets 1 larger every time an object is blitted so that the different X, Y and boolean values are associated with a certain position in the array. Essentially, the system looks like this:
HDcounter += 1;
forbiddenX[HDcounter] = modelX[modelNumber] + modelXChange;
forbiddenY[HDcounter] = modelY[modelNumber] + modelYChange;
forbiddenSpriteWidth[HDcounter] = 100;
forbiddenSpriteHeight[HDcounter] = 200;
forbiddenSpriteDepth[HDcounter] = 25;
if((forbiddenX[HDcounter] <= playerXE + forbiddenSpriteWidth[HDcounter]) && (forbiddenX[HDcounter] + forbiddenSpriteWidth[HDcounter] >= playerXE) && (forbiddenY[HDcounter] <= playerYE + forbiddenSpriteWidth[HDcounter]) && (forbiddenY[HDcounter] + forbiddenSpriteHeight[HDcounter] >= playerYE + 77))
{
pineTreeBlitAP = true;
blitModelAP[HDcounter] = true;
}
else
{
modelIMAGE = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(modelX[modelNumber] + modelXChange, modelY[modelNumber] + modelYChange, windowMODELS, modelIMAGE, 0, 0, 200, 200);
}
The problem is that when I try to use the boolean array to blit the model after the player, it does not seem to work. I can get something to happen when the player X and Y hits the threshold, but I cannot seem to get the true value recorded inside the boolean array and then used by my function.
This is the function where it is used:
void enviroment::blitEnviroModelsAP(SDL_Surface* BAPwindow, int modelAmount)
{
SDL_Surface* modelAPimage;
for(int model = 0; model < modelAmount; model++)
{
if((pineTreeBlitAP == true) && (blitModelAP[model] == true))
{
modelAPimage = IBFobjectENVIRO.loadIMG("pineTree.png");
IBFobjectENVIRO.blitIMG(forbiddenX[model], forbiddenY[model], BAPwindow, modelAPimage, 0, 0, 200, 200);
}
}
}
I get that this is probably a totally noob question, I just want some kind of help with this as I have been stuck for nearly a week.
Edit: Here are how my arrays are declared.
int forbiddenX[2000] = {0};
int forbiddenY[2000] = {0};
int forbiddenSpriteHeight[2000] = {0};
int forbiddenSpriteWidth[2000] = {0};
int forbiddenSpriteDepth[2000] = {0};
int blitModelAP[2000] = {false};

C++ vector element is different when accessed at different times

I'm developing a 3D game using SDL and OpenGL on Ubuntu 9.04 using Eclipse CDT. I've got a class to hold the mesh data in vectors for each type. Such as Vertex, Normal, UVcoord (texture coordinates), as well as a vector of faces. Each face has 3 int vectors which hold indexes to the other data. So far my game has been working quite well at rendering at nice rates. But then again I only had less then one hundred vertexes among two objects for testing purposes.
The loop accessing this data looks like this:
void RenderFace(oFace face)
{
/*
* More Stuff
*/
oVertice gvert;
oUVcoord tvert;
oNormal nvert;
for (unsigned int fvIndex = 0; fvIndex < face.GeoVerts.size(); fvIndex++)
{
gvert = obj.TheMesh.GetVertice(face.GeoVerts[fvIndex] - 1);
tvert = obj.TheMesh.GetUVcoord(face.UV_Verts[fvIndex] - 1);
nvert = obj.TheMesh.GetNormal(face.NrmVerts[fvIndex] - 1);
glNormal3f(nvert.X, nvert.Y, nvert.Z);
glTexCoord2f(tvert.U, tvert.V);
glVertex3f(scale * gvert.X, scale * gvert.Y, scale * gvert.Z);
}
/*
* More Stuff
*/
}
There is a loop that calls the renderFace() function which includes the above for loop. The minus one is because Wavefront .obj files are 1 indexed (instead of c++ 0 index). Anyway, I discovered that once you have about 30 thousand or so faces, all those calls to glVertex3f() and the like slow the game down to about 10 FPS. That I can't allow. So I learned about vertex arrays, which require pointers to arrays. Following the example of a NeHe tutorial I continued to use my oVertice class and the others. Which just have floats x, y, z, or u, v. So I added the same function above to my OnLoad() function to build the arrays which are just "oVertice*" and similar.
Here is the code:
bool oEntity::OnLoad(std::string FileName)
{
if (!obj.OnLoad(FileName))
{
return false;
}
unsigned int flsize = obj.TheMesh.GetFaceListSize();
obj.TheMesh.VertListPointer = new oVertice[flsize];
obj.TheMesh.UVlistPointer = new oUVcoord[flsize];
obj.TheMesh.NormListPointer = new oNormal[flsize];
oFace face = obj.TheMesh.GetFace(0);
oVertice gvert;
oUVcoord tvert;
oNormal nvert;
unsigned int counter = 0;
unsigned int temp = 0;
for (unsigned int flIndex = 0; flIndex < obj.TheMesh.GetFaceListSize(); flIndex++)
{
face = obj.TheMesh.GetFace(flIndex);
for (unsigned int fvIndex = 0; fvIndex < face.GeoVerts.size(); fvIndex++)
{
temp = face.GeoVerts[fvIndex];
gvert = obj.TheMesh.GetVertice(face.GeoVerts[fvIndex] - 1);
temp = face.UV_Verts[fvIndex];
tvert = obj.TheMesh.GetUVcoord(face.UV_Verts[fvIndex] - 1);
temp = face.NrmVerts[fvIndex];
nvert = obj.TheMesh.GetNormal(face.NrmVerts[fvIndex] - 1);
obj.TheMesh.VertListPointer[counter].X = gvert.X;
obj.TheMesh.VertListPointer[counter].Y = gvert.Y;
obj.TheMesh.VertListPointer[counter].Z = gvert.Z;
obj.TheMesh.UVlistPointer[counter].U = tvert.U;
obj.TheMesh.UVlistPointer[counter].V = tvert.V;
obj.TheMesh.NormListPointer[counter].X = nvert.X;
obj.TheMesh.NormListPointer[counter].Y = nvert.Y;
obj.TheMesh.NormListPointer[counter].Z = nvert.Z;
counter++;
}
}
return true;
}
The unsigned int temp variable is for debugging purposes. Apparently I don't have a default constructor for oFace that doesn't have something to initialize with. Anyway, as you can see it's pretty much that same exact routine. Only instead of calling a gl function I add the data to three arrays.
Here's the kicker:
I'm loading a typical cube made of triangles.
When I access element 16 (0 indexed) of the UV_Verts vector from the RenderFace() function I get 12.
But when I access element 16 (0 indexed) of the same UV_Verts vector from the OnLoad() function I get something like 3045472189
I am so confused.
Does anyone know what's causing this? And if so how to resolve it?
One possible reason could be that you're creating arrays with size flsize:
obj.TheMesh.VertListPointer = new oVertice[flsize];
obj.TheMesh.UVlistPointer = new oUVcoord[flsize];
obj.TheMesh.NormListPointer = new oNormal[flsize];
but use the arrays with indices up to flsize * face.GeoVerts.size
for (...; flIndex < obj.TheMesh.GetFaceListSize(); ...) { // flsize = GetFaceListSize
for (...; fvIndex < face.GeoVerts.size(); ...) {
...
obj.TheMesh.UVlistPointer[counter].U = ...;
...
counter++;
}
}
so your array creation code should actually be more like
obj.TheMesh.VertListPointer = new oVertice[flsize * face.GeoVerts.size()];
obj.TheMesh.UVlistPointer = new oUVcoord[flsize * face.GeoVerts.size()];
obj.TheMesh.NormListPointer = new oNormal[flsize * face.GeoVerts.size()];