1 hour ago, JoeJ said:
This is still the post which calls my attention.
Using different classes still smells to me. But it's not just a matter of taste or programming paradigms - it's the hope you could reduce complexity maybe.
I could use one class. I could put flags and ifs in and do check throughout the routine. That's perhaps what many people would do. However by calling a separate function I make all those little decisions at the top in one virtual function call. The program is doing less work for the same result at the expense of more destination code (not really so much source code) . But then these days code is cheap compared to data. Here's what one of my classes looks like
class CDLSpherePrismViewDataUpBW2C3 : public CDLSpherePrismViewDataUpBW2
{
public:
CDLSpherePrismViewDataUpBW2C3( CDLTerrainObject *pObj, CDLSpherePrismViewData *pParent, IDLChildIndex iCI, CDLObjectNode *pCenter, FDLCoord fRad,
CDLSphereFaceTriView *pFloor, CDLSphereFaceTriView *pCeiling,
CDLSphereFaceQuadView *pWall1, CDLSphereFaceQuadView *pWall2, CDLSphereFaceQuadView *pWall3) :
CDLSpherePrismViewDataUpBW2(pObj,pParent,iCI,pCenter,fRad,pFloor,pCeiling,pWall1,pWall2,pWall3)
{
this->m_clCA.SetPrismUpChild3(pParent->m_clCA);
}
int GetChildID() override { return 2; }
};
static_assert(sizeof(CDLSpherePrismViewDataUpBW2C3) == sizeof(CDLSpherePrismViewData), "CDLSpherePrismViewDataUpBW2C3 size mismatch!");
And that essentially inherits from this :
typedef TDLSpherePrismData<CDLSpherePrismViewUpData, CDLSpherePrismViewData,
CDLSpherePrismViewDataUpFW2C1, CDLSpherePrismViewDataUpBW2C2, CDLSpherePrismViewDataUpBW2C3, CDLSpherePrismViewDataDnBW2C4,
CDLSpherePrismViewDataUpFW2C5, CDLSpherePrismViewDataUpBW2C6, CDLSpherePrismViewUpDataBW2C7, CDLSpherePrismViewDataDnBW2C8,
CDLSphereFaceTriViewUpCW2 , CDLSphereFaceTriViewUpCC2 , CDLSphereFaceTriViewDnCC2 , CDLSphereFaceTriView ,
CDLSphereFaceQuadView , EDLFaceSides::_FBFFB_ , EDLFaceSides::_FBFBB_ , EDLFaceSides::_FBFBB_ ,
0> TDLSpherePrismViewDataUpBW2;
Almost all differences in the class are handheld by the temples. Call it a performance hack....
Quote
For example, assuming you have N classes to handle all prism cases, could you use just one or two instead N to handle them all? Using some bit flags per node, maybe ending up with less code at least, while the number of branches remains similar to what you have now including the inheritance logic done by the language?
Yes I could .... but again, the program would have to check for all those bit flags when the code is running and do different things based on them. That's extra work and would slow it down. My programming style is straight though code as much as possible... Try to eliminate as many run-time checks as you can. It's analogous to taking the if out of the loop and having two loops instead. It may be more code, but it should run faster.
Quote
I assume the whole indexing thing would become a lot easier as well if this makes sense. (that's what i meant initially)
It might, but I don't try to make my life easier. I try to make the computer's life easier. What I've settled on now is create a class object (kind of a container) with a big buffer in the middle and use placement new to populate it with the 8 octree nodes. As I said earlier I'm using a 2 byte offset in each octree node that will get me to it's container.
In general sometimes I come up with new ways (at least new for me) to handle things and in if they work out, I've added a new weapon to my arsenal that I can use again and again. Once you figure it out, it's not so complex.
Quote
But what confuses me the most is: Why do you need a owner class for the children? Couldn't the parent handle this, reducing complexity again?
Well for example, I want to have a back pointer from the children to the parent. I can put it in each child but but that's 8 bytes each. But the two byte offset I'm using to get to the container is packed in with a bunch of other flags so it's basically free. Now I can put the back pointer in the container because it's shared by all children and I'm only using 8 bytes instead of 64.
Furthermore allocated objects need a reference count since they can be referenced outside of the tree, and I need to make sure I'm not deleting a node when the tree is being reorganized, because that node (i.e. voxel) may be being used by a mesh. There is also other information in the header for the memory allocation as is usually the case in most heap systems.
However it turns out because of the algorithm this is a very temporary situation. If a node dies it's siblings will die in the next iteration. So putting them together in memory make sense because it's 1 memory header as opposed to 8, and there is also a memory cache advantage when things are together in memory. So again that's a big memory savings.