• Advertisement
Sign in to follow this  

C++ Copy, move, and assignment operators with a derived class

Recommended Posts

When it comes to the copy, move, and assignment operators of a child class how is it supposed to look?

If this is the implementation of my parent class

//Default constructor
Buffer::Buffer()
{
	buffer = nullptr;
}

//Copy constructor
Buffer::Buffer(const Buffer& other)
{
	buffer = other.buffer;
	buffer->AddRef();
}

//Move constructor
Buffer::Buffer(Buffer&& other)
{
	buffer = other.buffer;
	buffer->AddRef();
	other.release(); //Free the buffer resource of the other instance
}

//Destructor
Buffer::~Buffer()
{
	release();
}

//Copy assignment
Buffer& Buffer::operator=(const Buffer& other)
{
	if (&other != this)
	{
		release(); //Free the buffer of this instance

		buffer = other.buffer;
		buffer->AddRef();
	}

	return *this;
}

//Move assignment
Buffer& Buffer::operator=(Buffer&& other)
{
	if (&other != this)
	{
		release(); //Free the buffer of this instance

		buffer = other.buffer;
		buffer->AddRef();

		other.release(); //Free the buffer of the other instance
	}

	return *this;
}

And this is the implementation of my child class. Is this correct?

I'm really just wondering about the at the copy, move, and I'm not too sure about the assignment operators

//Default constructor
VertexBuffer::VertexBuffer() : Buffer()
{
}

//Copt constructor
VertexBuffer::VertexBuffer(const VertexBuffer& other) : Buffer(other)
{
}

//Move constructor
VertexBuffer::VertexBuffer(VertexBuffer&& other) : Buffer(other)
{
}

//Destructor
VertexBuffer::~VertexBuffer()
{
}

//Not sure how to handle the copy/move operators.
//Do I treat them as there own operators and copy the Buffer assignment operators code?
VertexBuffer& VertexBuffer::operator=(const VertexBuffer& other)
{
}

VertexBuffer& VertexBuffer::operator=(VertexBuffer&& other)
{
}

 

Share this post


Link to post
Share on other sites
Advertisement

Deriving from a copyable base class is a bit of a code smell IMHO (but so is deriving from concrete classes in general :) ). FWIW I don't know if I've ever needed to solve this problem... 

As for how to call the base class assignment operator, you can always do something like:

*static_cast<Base*>(this) = other 

Share this post


Link to post
Share on other sites
8 minutes ago, Hodgman said:

Deriving from a copyable base class is a bit of a code smell IMHO (but so is deriving from concrete classes in general ). FWIW I don't know if I've ever needed to solve this problem... 

As for how to call the base class assignment operator, you can always do something like:

*static_cast<Base*>(this) = other 

Just make it very explicit: Base::operator=(other);

Share this post


Link to post
Share on other sites

A copy assignment operator should always look like this.

VertexBuffer& VertexBuffer::operator=(const VertexBuffer other)
{
	this->swp(other);
	return *this;
}

Of course, you need to implement your swap() member function, but that should be fairly trivial.  See, the magic of this is it implements the copy assignment operator in terms of the copy constructor, which is generally the expected behaviour, so you only write the meaty function once.  Even your base class should implement the operator this way.  Trace it through, you'll see what I mean.

Also, why would you create a class hierarchy without a virtual destructor in the base class?  That smells of a misuse of inheritance.

Share this post


Link to post
Share on other sites
16 minutes ago, Bregma said:

A copy assignment operator should always look like this.


VertexBuffer& VertexBuffer::operator=(const VertexBuffer other)
{
	this->swp(other);
	return *this;
}

Of course, you need to implement your swap() member function, but that should be fairly trivial.  See, the magic of this is it implements the copy assignment operator in terms of the copy constructor, which is generally the expected behaviour, so you only write the meaty function once.  Even your base class should implement the operator this way.  Trace it through, you'll see what I mean.

Also, why would you create a class hierarchy without a virtual destructor in the base class?  That smells of a misuse of inheritance.

Shoudn't the argument be a reference for a general copy assignment operator?

My understanding of the default copy assignment operator was to call the base copy assignment operator first and then the copy assignment operators of each of the object's members.

Edited by matt77hias

Share this post


Link to post
Share on other sites

Why are you using inheritance here? Do you have anywhere in your code a pointer or reference to a buffer that might be a vertex buffer or a different type of buffer, and you'll only know at run time? That would be about the only situation in which I'd use inheritance.

Inheritance is easily abused. Don't use it until you really need it.

 

Share this post


Link to post
Share on other sites
7 hours ago, Hodgman said:

Deriving from a copyable base class is a bit of a code smell IMHO (but so is deriving from concrete classes in general )

I actually don't mean for the Buffer class to be concrete I just don't know how to make it not since there are no methods that need to be implemented for the child

//Parent class
class Buffer
{
public:
	Buffer();
	Buffer(const Buffer& other);
	Buffer(Buffer&& other);
	virtual ~Buffer();
	Buffer& operator=(const Buffer& other);
	Buffer& operator=(Buffer&& other);

private:
	ID3D11Buffer *buffer;
	void release(); //Releases the buffer member variable and cleans it up
};


//VertexBuffer child class, other versions would be ConstantBuffer or IndexBuffer
class VertexBuffer : public Buffer
{
public:
	VertexBuffer();
	VertexBuffer(const VertexBuffer& other);
	VertexBuffer(VertexBuffer&& other);
	~VertexBuffer();
	VertexBuffer& operator=(const VertexBuffer& other);
	VertexBuffer& operator=(VertexBuffer&& other);
};

 

7 hours ago, matt77hias said:

Just make it very explicit: Base::operator=(other);

Do I need to set anything to the left hand side when I do this? or is it really just:

//Vertex Buffer copy assignment opt
VertexBuffer& VertexBuffer::operator=(const VertexBuffer& other)
{
	if (&other != this)
	{
		Buffer::operator=(other);
	}

	return *this;
}

//Vertex Buffer move assignment opt
VertexBuffer& VertexBuffer::operator=(VertexBuffer&& other)
{
	if (&other != this)
	{
		Buffer::operator=(other);
	}
  
	return *this;
}

 

1 hour ago, Bregma said:

why would you create a class hierarchy without a virtual destructor in the base class?

I posted the implementation file contents before. Intellisense gets mad at me if use the virtual keyword there, but its in the header file :)

 

15 minutes ago, alvaro said:

Why are you using inheritance here? Do you have anywhere in your code a pointer or reference to a buffer that might be a vertex buffer or a different type of buffer, and you'll only know at run time? That would be about the only situation in which I'd use inheritance.

Inheritance is easily abused. Don't use it until you really need it.

Currently I really don't have a point where I need a container of Buffers. For now I will definitely know that I need a VertexBuffer here or I should use a IndexBuffer there. I guess I really just have a base class, because regardless of whether my instance object is a VertexBuffer, ConstantBuffer, or XXXXBuffer they are still all buffers at the core and all have that ID3D11Buffer *buffer member variable in common

Edited by noodleBowl

Share this post


Link to post
Share on other sites
12 minutes ago, noodleBowl said:

I actually don't mean for the Buffer class to be concrete I just don't know how to make it not since there are no methods that need to be implemented for the child

If the derived class destructor needs to be called as well, when the object is destroyed via the base class destructor, you need a virtual destructor in the base class.

12 minutes ago, noodleBowl said:

Do I need to set anything to the left hand side when I do this? or is it really just:

That is ok if you have no data to copy for the VertexBuffer itself. For the move assignment operator, you need to use std::move(other), otherwise you will invoke the copy instead of move assignment operator of the base class.

If this is literally the implementation you want, just use = default for both.

Edited by matt77hias

Share this post


Link to post
Share on other sites
13 minutes ago, noodleBowl said:

I posted the implementation file contents before. Intellisense gets mad at me if use the virtual keyword there, but its in the header file :)

I don't know why Intellisense gets mad, but normally you shouldn't care about Intellisense. The only one who really knows and is allowed to complain is your compiler (output window).

Share this post


Link to post
Share on other sites
13 minutes ago, noodleBowl said:

Currently I really don't have a point where I need a container of Buffers. For now I will definitely know that I need a VertexBuffer here or I should use a IndexBuffer there. I guess I really just have a base class, because regardless of whether my instance object is a VertexBuffer, ConstantBuffer, or XXXXBuffer they are still all buffers at the core and all have that ID3D11Buffer *buffer member variable in common

 

You don't need to inherit to share functionality. Composition will be better in the vast majority of situations. So both VertexBuffer and ConstantBuffer can have a member of type Buffer (or MemoryBuffer, or RawBuffer... Using good names is important) and share functionality that way.

 

Share this post


Link to post
Share on other sites
35 minutes ago, matt77hias said:

I don't know why Intellisense gets mad

Intellisesne might be the wrong word here. Its whichever entity is responsible putting a red squiggly under things. The linter?

30 minutes ago, alvaro said:

 

You don't need to inherit to share functionality. Composition will be better in the vast majority of situations. So both VertexBuffer and ConstantBuffer can have a member of type Buffer (or MemoryBuffer, or RawBuffer... Using good names is important) and share functionality that way.

 

I kind of lied here, completely forgot what I was trying to do. I actually do have a spot where I could use a vector of Buffers. I have this factory called BufferModule which has methods like createVertexBuffer, createIndexBuffer, etc. All of those buffer classes (VertexBuffer, IndexBuffer, etc) are derived from the base Buffer. So in order to hold all of these I need a member variable like

std::vector<Buffer*> bufferObjects;

Cause if I were to just a normal vector of objects, my child buffer class  would be sliced when I would try to do something like this right?

//Vector of the parent class Buffer
std::vector<Buffer> bufferObjects;

//Put the child class VertexBuffer into the vector
VertexBuffer vertexBuffer;
graphicsDevice->device->CreateBuffer(&bufferDescription, NULL, &vertexBuffer.buffer);
buffers.push_back(vertexBuffer); // Not good... Just lost all of the info that was not specifically a part of the parent class

So to fix this I would need to do

//Vector of the parent class Buffer. Using a pointer to prevent the object slice
std::vector<Buffer*> bufferObjects;

VertexBuffer vertexBuffer = new VertexBuffer(); //Need to use new here otherwise when this goes out of scope all of our data goes bye-bye
graphicsDevice->device->CreateBuffer(&bufferDescription, NULL, &vertexBuffer.buffer);
buffers.push_back(&vertexBuffer); //Hurray! No object slicing happens

Only problem I have here is that I really don't like the use of the new keyword :(

Share this post


Link to post
Share on other sites
1 hour ago, alvaro said:

 

You don't need to inherit to share functionality. Composition will be better in the vast majority of situations. So both VertexBuffer and ConstantBuffer can have a member of type Buffer (or MemoryBuffer, or RawBuffer... Using good names is important) and share functionality that way.

 

Note that private inheritance is one implementation of composition :P

Share this post


Link to post
Share on other sites
4 minutes ago, matt77hias said:

Note that private inheritance is one implementation of composition

Yes, it's the one with the confusing syntax. :)

 

Share this post


Link to post
Share on other sites
30 minutes ago, alvaro said:

Yes, it's the one with the confusing syntax. :)

And the confusing defaults. Why use public always as default for struct and use private always as default for class? This makes no sense for inheritance. But on the other hand if the syntax is not explicit, one asks for trouble sooner or later.

Share this post


Link to post
Share on other sites

Types should usually either have value semantics or reference semantics, but not both. Value types can be used as reference types occasionally (what C# would consider "boxing"), but not vice versa.

A polymorphic assignment operator has properties of both and is definitely a code smell. Instead, try creating a reference type that can be owned by a value type. This gives you the best of both worlds, and allows you to use pImpl and other helpful patterns. The stricter semantic dichotomy also makes the code easier to work with and allows you to avoid a lot of these dark corners of C++ :)

Share this post


Link to post
Share on other sites
5 hours ago, matt77hias said:

Shoudn't the argument be a reference for a general copy assignment operator?

No.  Trace through the operation of the code I wrote.  See how the copy constructor is used to implement the assignment operator?  Now, isn't it elegant?

Share this post


Link to post
Share on other sites
10 minutes ago, Bregma said:

No.  Trace through the operation of the code I wrote.  See how the copy constructor is used to implement the assignment operator?  Now, isn't it elegant?

Ok I get it. Elegant: yes.

But come on, you need to look at this few lines of code twice imho to get what is happening.

Someone of your team sees your signature. Adds the "missing" reference. And then it all depends on you "swp" signature, how things would go...

Share this post


Link to post
Share on other sites
58 minutes ago, matt77hias said:

Ok I get it. Elegant: yes.

But come on, you need to look at this few lines of code twice imho to get what is happening.

Someone of your team sees your signature. Adds the "missing" reference. And then it all depends on you "swp" signature, how things would go...

I personally prefer the reference as well, since you can add an if(this != &other) before creating the temporary and swapping. Even though your swap function will have the same check, and it's semantically the same either way, no use creating a throwaway copy in that case :)

Share this post


Link to post
Share on other sites
18 hours ago, matt77hias said:

Ok I get it. Elegant: yes.

But come on, you need to look at this few lines of code twice imho to get what is happening.

Someone of your team sees your signature. Adds the "missing" reference. And then it all depends on you "swp" signature, how things would go...

I do not work with bottom-grade programmers who would alter functionality without understanding it first. 

If you absolutely must blindly follow rigid ideology and make the argument to your copy assignment operator a reference, the code would look like this.

VertexBuffer& VertexBuffer::operator=(VertexBuffer const& other)
{
	VertexBuffer tmp(other);
	this->swap(tmp);
	return *this;
}

Interestingly, modern compilers will pessimize that alternative code because they can not take advantage of copy elision like they can with pass-by-value parameters.  Your coworker's blind obedience to cargo-cult pass-by-const-reference just cost a thousand CPU cycles.  Consider giving them an opportunity to pursue a more satisfying role as a node.js front-end developer where they can cause less harm.

One of the big advantages of the copy-and-swap idiom is that it provides the strong exception safety guarantee, whereas the original code did not (again, trace it through).  You might argue against the use of exceptions in C++ (after all, we're already speaking of a level of mindless reverence at play in your place of work) but writing the most robust code as possible is usually a win in the long run.  Sure, in this trivial example you're unlikely to see an exception, but not all code is so trivial and the copy-and-swap idiom will always apply.

As for adding a self-check, consider the cost of adding and maintaining an equality operator (and corresponding inequality operator) and the cost of calling it every time and compare that to how ofter you write code that performs self-assignment.  I know I very very rarely write code that assigns an object to itself, but code that is never written costs less and is guaranteed bug-free.  Always spending extra CPU cycles and increasing the risk in code to make a single highly unlikely edge-case more efficient seems like a lose-lose tradeoff to me.

Really, other than deleting the copy assignment operator entirely or adding debug printfs, why would you ever use anything other than the two-line copy-and-swap I wrote above for all your classes?

Share this post


Link to post
Share on other sites
15 minutes ago, Bregma said:

Really, other than deleting the copy assignment operator entirely or adding debug printfs, why would you ever use anything other than the two-line copy-and-swap I wrote above for all your classes?

I use for 95% of the cases:

VertexBuffer &VertexBuffer::operator=(const VertexBuffer &buffer) = delete;

and for 4.99% of the cases:

VertexBuffer &VertexBuffer::operator=(const VertexBuffer &buffer) = default;

 

Edited by matt77hias

Share this post


Link to post
Share on other sites
6 hours ago, Bregma said:

If you absolutely must blindly follow rigid ideology

 

6 hours ago, Bregma said:

Your coworker's blind obedience to cargo-cult pass-by-const-reference

 

6 hours ago, Bregma said:

Really, other than deleting the copy assignment operator entirely or adding debug printfs, why would you ever use anything other than the two-line copy-and-swap I wrote above for all your classes?

Certainly you must see the irony among these statements?

Passing by value may often elide the copy for R-values, but not L-values. Passing by reference will always copy R-values, but L-values don't necessarily have to be copied if there are (exception-safe) optimizations that can be done during assignment. While I concede that a self-check isn't a strong case for preferring the latter approach, and I'll definitely be preferring pass-by-value in the general case going forward as it's more idiomatic, it should be obvious enough that both approaches are valid depending on the usage and implementation details of specific types.

It's a fool's errand to try an make an argument for either based on contrived usage and performance conditions, especially at the micro-optimization level. I wouldn't even entertain such an argument coming from a coworker. If this code ever does become an issue, I guarantee it's because your software has much bigger issues than assignment operators performing extra copies. But again, without real data there's no way to know.

Share this post


Link to post
Share on other sites
On 14/10/2017 at 11:47 PM, Bregma said:

A copy assignment operator should always look like this.

Before I start blindly following this rigid ideology, what about cases where swapping is just as expensive as copying? 

Share this post


Link to post
Share on other sites
1 minute ago, Hodgman said:

Before I start blindly following this rigid ideology, what about cases where swapping is just as expensive as copying? 

Under no circumstances should you question my obviously superior intellect.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By francoisdiy
      So I wrote a programming language called C-Lesh to program games for my game maker Platformisis. It is a scripting language which tiles into the JavaScript game engine via a memory mapper using memory mapped I/O. Currently, I am porting the language as a standalone interpreter to be able to run on the PC and possibly other devices excluding the phone. The interpreter is being written in C++ so for those of you who are C++ fans you can see the different components implemented. Some background of the language and how to program in C-Lesh can be found here:

      http://www.codeloader.net/readme.html
      As I program this thing I will post code from different components and explain.
    • By isu diss
      I'm trying to duplicate vertices using std::map to be used in a vertex buffer. I don't get the correct index buffer(myInds) or vertex buffer(myVerts). I can get the index array from FBX but it differs from what I get in the following std::map code. Any help is much appreciated.
      struct FBXVTX { XMFLOAT3 Position; XMFLOAT2 TextureCoord; XMFLOAT3 Normal; }; std::map< FBXVTX, int > myVertsMap; std::vector<FBXVTX> myVerts; std::vector<int> myInds; HRESULT FBXLoader::Open(HWND hWnd, char* Filename, bool UsePositionOnly) { HRESULT hr = S_OK; if (FBXM) { FBXIOS = FbxIOSettings::Create(FBXM, IOSROOT); FBXM->SetIOSettings(FBXIOS); FBXI = FbxImporter::Create(FBXM, ""); if (!(FBXI->Initialize(Filename, -1, FBXIOS))) { hr = E_FAIL; MessageBox(hWnd, (wchar_t*)FBXI->GetStatus().GetErrorString(), TEXT("ALM"), MB_OK); } FBXS = FbxScene::Create(FBXM, "REALMS"); if (!FBXS) { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to create the scene"), TEXT("ALM"), MB_OK); } if (!(FBXI->Import(FBXS))) { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to import fbx file content into the scene"), TEXT("ALM"), MB_OK); } FbxAxisSystem OurAxisSystem = FbxAxisSystem::DirectX; FbxAxisSystem SceneAxisSystem = FBXS->GetGlobalSettings().GetAxisSystem(); if(SceneAxisSystem != OurAxisSystem) { FbxAxisSystem::DirectX.ConvertScene(FBXS); } FbxSystemUnit SceneSystemUnit = FBXS->GetGlobalSettings().GetSystemUnit(); if( SceneSystemUnit.GetScaleFactor() != 1.0 ) { FbxSystemUnit::cm.ConvertScene( FBXS ); } if (FBXI) FBXI->Destroy(); FbxNode* MainNode = FBXS->GetRootNode(); int NumKids = MainNode->GetChildCount(); FbxNode* ChildNode = NULL; for (int i=0; i<NumKids; i++) { ChildNode = MainNode->GetChild(i); FbxNodeAttribute* NodeAttribute = ChildNode->GetNodeAttribute(); if (NodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh) { FbxMesh* Mesh = ChildNode->GetMesh(); if (UsePositionOnly) { NumVertices = Mesh->GetControlPointsCount();//number of vertices MyV = new XMFLOAT3[NumVertices]; for (DWORD j = 0; j < NumVertices; j++) { FbxVector4 Vertex = Mesh->GetControlPointAt(j);//Gets the control point at the specified index. MyV[j] = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]); } NumIndices = Mesh->GetPolygonVertexCount();//number of indices MyI = (DWORD*)Mesh->GetPolygonVertices();//index array } else { FbxLayerElementArrayTemplate<FbxVector2>* uvVertices = NULL; Mesh->GetTextureUV(&uvVertices); int idx = 0; for (int i = 0; i < Mesh->GetPolygonCount(); i++)//polygon(=mostly triangle) count { for (int j = 0; j < Mesh->GetPolygonSize(i); j++)//retrieves number of vertices in a polygon { FBXVTX myVert; int p_index = 3*i+j; int t_index = Mesh->GetTextureUVIndex(i, j); FbxVector4 Vertex = Mesh->GetControlPointAt(p_index);//Gets the control point at the specified index. myVert.Position = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]); FbxVector4 Normal; Mesh->GetPolygonVertexNormal(i, j, Normal); myVert.Normal = XMFLOAT3((float)Normal.mData[0], (float)Normal.mData[1], (float)Normal.mData[2]); FbxVector2 uv = uvVertices->GetAt(t_index); myVert.TextureCoord = XMFLOAT2((float)uv.mData[0], (float)uv.mData[1]); if ( myVertsMap.find( myVert ) != myVertsMap.end() ) myInds.push_back( myVertsMap[ myVert ]); else { myVertsMap.insert( std::pair<FBXVTX, int> (myVert, idx ) ); myVerts.push_back(myVert); myInds.push_back(idx); idx++; } } } } } } } else { hr = E_FAIL; MessageBox(hWnd, TEXT("Failed to create the FBX Manager"), TEXT("ALM"), MB_OK); } return hr; } bool operator < ( const FBXVTX &lValue, const FBXVTX &rValue) { if (lValue.Position.x != rValue.Position.x) return(lValue.Position.x < rValue.Position.x); if (lValue.Position.y != rValue.Position.y) return(lValue.Position.y < rValue.Position.y); if (lValue.Position.z != rValue.Position.z) return(lValue.Position.z < rValue.Position.z); if (lValue.TextureCoord.x != rValue.TextureCoord.x) return(lValue.TextureCoord.x < rValue.TextureCoord.x); if (lValue.TextureCoord.y != rValue.TextureCoord.y) return(lValue.TextureCoord.y < rValue.TextureCoord.y); if (lValue.Normal.x != rValue.Normal.x) return(lValue.Normal.x < rValue.Normal.x); if (lValue.Normal.y != rValue.Normal.y) return(lValue.Normal.y < rValue.Normal.y); return(lValue.Normal.z < rValue.Normal.z); }  
    • By Karol Plewa
      Hi, 
       
      I am working on a project where I'm trying to use Forward Plus Rendering on point lights. I have a simple reflective scene with many point lights moving around it. I am using effects file (.fx) to keep my shaders in one place. I am having a problem with Compute Shader code. I cannot get it to work properly and calculate the tiles and lighting properly. 
       
      Is there anyone that is wishing to help me set up my compute shader?
      Thank you in advance for any replies and interest!
    • By fishyperil
      I'm looking for some references that could help me learn how to program some really basic 2D enemy behaviours.
      I wasn't sure whether to post this here or in the AI section but I think it might be more suitable to be posted here since it has more to do with basic maths than any AI related algorithms.
      Could anyone help recommend some resources (books, posts, videos) that could help me understand how to properly implement the basics of enemy movement in 2d games ? So far I've only managed to get them to chase the player character and to stop moving on collision, but the movement is pretty unrealistic and once the collision occurs the enemies all "pile up" on the player character. I'm doing this in C++ so no guides that explain how to script this using an engine api please.
    • By LifeArtist
      Good Evening,
      I want to make a 2D game which involves displaying some debug information. Especially for collision, enemy sights and so on ...
      First of I was thinking about all those shapes which I need will need for debugging purposes: circles, rectangles, lines, polygons.
      I am really stucked right now because of the fundamental question:
      Where do I store my vertices positions for each line (object)? Currently I am not using a model matrix because I am using orthographic projection and set the final position within the VBO. That means that if I add a new line I would have to expand the "points" array and re-upload (recall glBufferData) it every time. The other method would be to use a model matrix and a fixed vbo for a line but it would be also messy to exactly create a line from (0,0) to (100,20) calculating the rotation and scale to make it fit.
      If I proceed with option 1 "updating the array each frame" I was thinking of having 4 draw calls every frame for the lines vao, polygons vao and so on. 
      In addition to that I am planning to use some sort of ECS based architecture. So the other question would be:
      Should I treat those debug objects as entities/components?
      For me it would make sense to treat them as entities but that's creates a new issue with the previous array approach because it would have for example a transform and render component. A special render component for debug objects (no texture etc) ... For me the transform component is also just a matrix but how would I then define a line?
      Treating them as components would'nt be a good idea in my eyes because then I would always need an entity. Well entity is just an id !? So maybe its a component?
      Regards,
      LifeArtist
  • Advertisement