How to create a dynamic list - c++

Newbie...
I want to create a dynamicly growing list that will hold Point variables, a couple of int variables and whatever the colour variable is for Argb.
I'm doing it in Visual Studio C++ 2010
What is the best approach to handle this data within the program? It needs to store location, size and colour of objects that the user makes on the screen so I can draw them back to the Form when I refresh the Form. Currently I have a really nice program that draws squares,circles and lines in different colours and I can move that object around but this is only because I'm still holding onto the current object/shape data.

Create a struct or class to hold the information for one shape, and then use an std::vector to hold a list of them.
std::vector<Shape> myShapes;
If all of your shapes can be described by essentially the same data set, with some variance in size of some pieces of data, e.g the number of "Point varaibles" changes from shape to shape, then have a std::vector inside the shape class to hold them that variable data, e.g:
struct coordinate2D
{
int x;
int y;
};
class Shape
{
coordinate2D position; //the location on the shape
std::vector<coordinate2D> points; // the coordinates of the vertices that make up this shape.
};
//elsewhere
std::vector<Shape> myShapes;

Related

SFML: How to check if a point is contained in a group of transformed drawables

Context
I have a class representing a text box. the text box contains a header, some text and a rectangle to enclose the box. It only displays itself (for now):
struct Textbox : public sf::Drawable, public sf::Transformable{
sf::Text header;
sf::Text text;
sf::RectangleShape border;
Textbox(){
// set relative locations of the members
header.setPosition(0,0);
auto header_bounds = header.getGlobalBounds();
// the text should be just below the header
text.setPosition(0, header_bounds.top + header_bounds.height);
auto source_bounds = text.getGlobalBounds();
// this function just returns a rectangle enclosing two rectangles
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
// this function sets the position, width and length of border to be equal to rect's.
setRectParams(border, rect);
}
void draw(sf::RenderTarget& target, sf::RenderStates states){
states.transform = getTransform();
target.draw(header,states);
target.draw(text,states);
target.draw(border,states);
};
The Problem
What I want
I want to add a contains method. It should return true if coor is inside the border of the box. Here is my naive implementation:
bool Textbox::contains(sf::Vector2i coor) const {
return border.getGlobalBounds().contains(coor.x, coor.y);
}
Why this implementation doesn't work
This implementation breaks when I move the Textbox via the Transformable non-virtual functions. The Textbox moves and it also draws the shapes as transformed. But! It does not actually transform them! it only displays them as transformed. So the border doesn't even know it has been moved.
Possible solutions
I can add all the functions of the Transformable API to this class, thus shadowing them and calling transform by myself on each of the members. I don;t like this because it make me write sooo much more code than I wanted. It also raises the question of how to tackle the double transforms (the one for the Textbox and the others for it's members).
I can write a completely different class Group that holds a vector of drawables and transformables and it has all that shadowing API mechanism. All that is left is to inherit from it. This doesn't actually sound that bad.
I heard about Entity System Component - it's just sound pretty overkill.
I can apply the transform when contains is called. The function is const - it's a query. Also, it's bad design to update your data on seemingly random calls.
just as before just that the transform applies to a function-local rectangle. This smells too - why do I call the transform functions on the whole Textbox just so it would apply them on every method call (so far just it's draw and contains but down the line who knows)
Make the members mutable and somehow transform them inside the draw method. This smell hackish.
The question
How do I group transformations onto multiple entities via an ergonomic API?
The only method that you really need to 'change', but to be fair add on your own is getGlobalBounds().
When you are inheriting from sf::Transformable, sf::Drawable you should treat the base class (your Textbox struct) as a shape itself therfore you just need to call myTextbox.getGlobalBounds().contains(x,y), where myTextbox is a Textbox.
Using your own code:
struct Textbox : public sf::Drawable, public sf::Transformable{
sf::Text header;
sf::Text text;
sf::RectangleShape border;
sf::FloatRect getGlobalBounds() const {
auto header_bounds = header.getGlobalBounds();
auto source_bounds = text.getGlobalBounds();
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
//Don't really know what it does but let say that it returns Top and Left as 0, and calculates Height, Width.
return sf::FloatRect(getPosition(), sf::Vector2f(rect.width,rect.height));
}
};
But you still have to manage the rotation, resizing,etc. when calculating globalBounds.
EDIT:
One way to implement rotation and scaling.
sf::FloatRect getGlobalBounds() const {
auto header_bounds = header.getGlobalBounds();
auto source_bounds = text.getGlobalBounds();
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
//Don't really know what it does but let say that it returns Top and Left as 0, and calculates Height, Width.
sf::RectangleShape textbox(sf::Vector2f(rect.width, rect.height));
//at this point textbox = globalBounds of Textbox without transformations
textbox.setOrigin(getOrigin());//setOrigin (point of transformation) before transforming
textbox.setScale(getScale());
textbox.setRotation(getRotation());
textbox.setPosition(getPosition());
//after transformation get the bounds
return textbox.getGlobalBounds();
}
The solution might be much more simple than you expect. Instead of applying all the transforms to the transformable children/members, just de-transform the point you want to check (take it to local space).
Try this:
bool Textbox::contains(sf::Vector2i coor) const {
// Get point in the local space of the rectangle
sf::Transform inverseTr = this->getInverseTransform();
sf::Vector2f pointAsLocal = inverseTr.transformPoint(coor.x, coor.y);
// Check if the point, now in local space, is containted in the rectangle
return border.getLocalBounds().contains(pointAsLocal);
// ^
// Important! Use local bounds here, not global
}
Why does this work?
Math!
When you work with transformation matrices, you can think of them as portals between spaces. You have a local space where no transformation have been applied, and you have a final space, where all transformations are applied.
The problem with global bounds of a transformable member is that they belong neither to the local space nor the final space. They are just a rectangle bounding the shape in a possibly intermediate space where this bounds doesn't even take rotation into account.
What we are doing here is taking the coordinates, that exist in the final space, and take them to the local space of the rectangle, thanks to the inverse transformation matrix. So no matter how many translations, rotations or scales (or even skews, if you have customized the matrix) you apply to the rectangle. The inverse matrix takes the point to a new space where you can just check if it belongs, as if no transformation have ever been applied.

How to create this generic data structure field for my Vulkan class?

I'm trying to create a class for an "Entity" in Vulkan (An entity is a graphical object that can be rendered in a Window);
This class will contain the corresponding Vertex Buffer, along with the descriptor set layout, descriptor pool, descriptor sets and so on, the problem is how to manage the uniform buffers, because I'd like something like this:
class Entity final {
public:
enum class Uniform_Type : char {
MODEL_MATRIX, VIEW_MATRIX, PROJECTION_MATRIX, AMBIENT_VECTOR, DIFFUSE_VECTOR,
SPECULAR_VECTOR, SHININESS_FLOAT, LIGHT_AMBIENT_VECTOR, LIGHT_DIFFUSE_VECTOR,
LIGHT_SPECULAR_VECTOR, IS_LIGHT_SOURCE_BOOLEAN, LIGHT_POSITION_VECTOR,
VIEW_POSITION_VECTOR
};
// Private fields
std::unordered_map<Uniform_Type, std::pair<WHAT_HERE, std::vector<Uniform_Buffer>>> uniformsMap;
};
so if my class only needs the model, view and projection matrix, I'll do something like this (First element of the std::pair will hold the corresponding object (A matrix in this case), the second one is a vector of Uniform Buffers so they can be as much as the number of images in the swapchain):
uniformsMap[MODEL_MATRIX] = { glm::mat4(1.0f), std::vector<Uniform_Buffer>() };
uniformsMap[VIEW_MATRIX] = { glm::mat4(1.0f), std::vector<Uniform_Buffer>() };
uniformsMap[PROJECTION_MATRIX] = { glm::mat4(1.0f), std::vector<Uniform_Buffer>() };
The problem is that there are various kind of Uniform Buffers (matrix, vector, float, bool, etc...) so I'm stuck on what to write as the first element of the std::pair object.
Thanks for your time.
You can use std::variant<> that you then pull down to the correct type with get<>() when you need it.
The template would then be a list of all possible types you will need it to contain.
Also, this is a more a style thing but, I'm not a fan of using std::pair like that. It's very little effort to make a small struct with dedicated field names (other than thinking up the names). And you won't have to deal with std::pair's peculiarities.

store list of objects in class

Brand new to c++, trying to figure out how to create a class that I can store a list of objects in.
I have a surface class with subclasses such as triangles, circles, ect.
I'm trying to create a class called Scene, that I can store a list of all the surfaces.
Here's the header file for what I'm trying to do. How do you do this in c++?
class Scene
{
private:
//background color elements
float bgRed;
float bgGreen;
float bgBlue;
//array of different surfaces
Surface surfaces[]; //<--- What I want
public:
Scene();
addSurface(Surface s);
};
There are many possibilities, here's a easy one with a std::vector:
vector<Surface> surfaces;
...
addSurface(const Surface &s) //const and & are not strictly necessary, but better
{
surfaces.push_back(s);
}
...
//accessing like an array: surfaces[index]
//element count: surfaces.size()
This copies the passed objects (s) while inserting. If you want the same object, so that changes in the vector affect the object "outside" too (and vice-versa), you'll need an additional pointer.
Also note that copying of an child class object of Surface will result in a pure Surface, without the child class part (object slicing). If you need that part, you'll need a pointer too (if you don't have one already).
//pointer variant
vector<Surface*> surfaces;
...
addSurface(Surface &s)
{
surfaces.push_back(&s);
}

Circular issue: accessing set of objects from within its own member function

I am simulating a set of spheres interacting with each other.
For this reason I made a class sphere that stores its position x-y-z and has a method update() that updates its position.
class cSphere {
double x; double y; double z;
void update()
}
This update function, however, depends on the positions of the other spheres. I am not sure how to best handle this circular problem.
What I tried first was to create a std::vector *vec_spheres in my main() as a global variable and access it within update() by defining extern std::vector *vec_spheres in cSphere.h. This does of course not work though.
I am now thinking about creating a singleton class that returns a pointer to *vec_spheres but that also seems hacky.
Thanks for your advice!
In the light of LawOfDemeter I don't suggest making that knowledge the responsability of cSphere::update.
Instead, make a higher entity (cSphereSimulation, PhysicsEngine, ...?) that knows how to calculate the new positions of all spheres.
In pseudo code:
struct cSimulation
{
std::vector<cSpheres> _spheres;
void update()
{
// calculations using all positions...
for (auto& sphere : _spheres)
sphere.update(newLocation);
}
// ...

What is a good design for this situation?

I am making a basic render engine.
In order to let the render engine operate on all kinds of geometry,
I made this class:
class Geometry
{
protected:
ID3D10Buffer* m_pVertexBuffer;
ID3D10Buffer* m_pIndexBuffer;
public:
[...]
};
Now, I would like the user to be able to create his own geometry by inheriting from this class.
So let's suppose the user made a class Cube : public Geometry
The user would have to create the vertexbuffer and indexbuffer at initialisation.
This is a problem, since it would recreate the vertexbuffer and indexbuffer each time a new Cube object is made. There should only be one instance of vertexbuffer and indexbuffer per derived class. Either that, or a completely different design.
A solution might be to make separate static ID3D10Buffer* for the inheriting class , and set the pointers of the inherited class equal to those in the constructor.
But that would require a static method like static void CreateBuffers() which the user would have to call explicitly one time in his application for each type he decides to make that inherits from Geometry. That doesn't seem like a nice design.
What is a good solution to this problem?
You should separate the concept of an instance from the concept of a mesh. This means you create one version of the Geometry for a cube that represents the vertex and index buffer for a cube.
You then introduce a new class called GeometryInstance which contains a transformation matrix. This class should also have a pointer/reference to a Geometry. Now you can create new Instances of your geometry by creating GeometryInstances that all refer the same Geometry object not duplicating memory or work when creating a new box.
EDIT:
Given that you have the Geometry class from the question and a Mesh class as in your comment your Mesh class should look something like this:
class Mesh {
private:
Matrix4x4 transformation;
Geometry* geometry;
public:
Mesh(const Matrix4x4 _t, Geometry* _g) : transformation(_t), geometry(_g) {}
}
Now when creating your scene you want to do things like this
...
std::vector<Mesh> myMeshes;
// OrdinaryGeometry is a class inheriting Geometry
OrdinaryGeometry* geom = new OrdinaryGeometry(...);
for(int i = 0; i < ordinaryGeomCount; ++i) {
// generateTransform is a function that generates some
// transformation Matrix given an index, just as an example
myMeshes.push_back(Mesh(generateTransform(i), geom);
}
// SpecialGeometry is a class inheriting Geometry with a different
// set of vertices and indices
SuperSpecialGeometry* specialGeom = new SuperSpecialGeometry(...);
for(int i = 0; i < specialGeomCount; ++i) {
myMeshes.push_back(Mesh(generateTransform(i), specialGeom);
}
// Now render all instances
for(int i = 0; i < myMeshes.size(); ++i) {
render(myMeshes[i]);
}
Note how we only have two Geometry objects that are shared between multiple Meshes. These should ideally be refcounted using std::shared_ptr or something similar but it's outside the scope of the question.
What would be the point of sub classing Geometry in your cube example? A cube is simply an instance of Geometry which has a certain set of triangles and indices. There would be no difference between a Cube class and a Sphere class, other than that they fill their triangle/index buffers with different data. So the data itself is what is important here. You need a way to allow the user to provide your engine with various shape data, and to then refer to that data in some way once its made.
For providing shape data, you have two options. You can decide to either keep the details of Geometry private, and provide some interface that takes raw data like a string from a file, or a float array filled in some user made function, creates a Geometry instance for that data, and then gives the user some handle to that instance (or allow the user to specify a handle). Or, you can create some class like GeometryInfo which has methods addTriangle, addVertex etc which the user fills him/herself, and then have some function that accepts a GeometryInfo, creates a Geometry instance for that data and then gives the user some handle again.
In both situations you need to provide some interface that allows the user to say "here's some data, make something out of it and give it some handle. Minimally it would have a function as I described. You would need to maintain a map somewhere of created Geometry instances in your engine. This is so you enforce your one instance per shape rule, and so you can associate what the user wants ("Ball", "Cube") with what your engine needs (Geometry with filled buffers).
Now about the handle. I would either let the user associate the data with a name, like "Ball", or return some integer that the user would then associate with a certain "Ball" instance. That way when you make your Rocket class, the user can then request the "Ball" instance from your engine, various other objects can use the "Ball" and everything's fine because they're just storing handles, not the ball itself. I wouldn't advise storing a pointer to the actual Geometry instance. The mesh doesn't own the geometry, because it can share it with other meshes. It doesn't need access to the geometry's members, because the renderer handles the grunt work. So it is an unnecessary dependency. The only reason would be for speed, but using hashing for your handles would work just as good.
Now for some examples:
Providing shape data:
//option one
engine->CreateGeometryFromFile("ball.txt", "Ball");
//option two
GeometryInfo ball;
ball.addTriangle(0, 1, 0, 1);
ball.addTriangle(...);
...
engine->CreateGeometryFromInfo(ball, "Ball");
Refering to that data using a handle:
class Drawable
{
std::string shape;
Matrix transform;
};
class Rocket : public Drawable
{
Rocket() { shape = "Ball";}
//other stuff here for physics maybe
};
class BallShapedEnemy : public Drawable
{
BallShapedEnemy() { shape = "Ball";}
...
}
...
...in user's render loop...
for each (drawable in myDrawables)
{
engine->Render(drawable.GetShape(), drawable.GetTransform());
}
Now, having a separate class for each different game object such as Rocket is debatable, and is the subject of another question entirely, I was just making it look like your example from a comment.
This may be a sloppy way of doing it but could you not just make a singleton?
#pragma once
#include <iostream>
#define GEOM Geometry::getInstance()
class Geometry
{
protected:
static Geometry* ptrInstance;
static Geometry* getInstance();
float* m_pVertexBuffer;
float* m_pIndexBuffer;
public:
Geometry(void);
~Geometry(void);
void callGeom();
};
#include "Geometry.h"
Geometry* Geometry::ptrInstance = 0;
Geometry::Geometry(void)
{
}
Geometry::~Geometry(void)
{
}
Geometry* Geometry::getInstance()
{
if(ptrInstance == 0)
{
ptrInstance = new Geometry();
}
return ptrInstance;
}
void Geometry::callGeom()
{
std::cout << "Call successful!" << std::endl;
}
Only problem with this method is you would only ever have one Geometry object and I'm assuming you might want more than one? If not it could be useful, but I think Lasserallan's method is probably a much better implementation for what your looking for.