DSICLAIMER: Do not read this section. It's a bad proposal. ; )
ShapeSpheres said:
The compute functions on the other hand the camera doesn't really need that it's just for the render and potentially other code so is this a better usage?
Personally i came up with an unusual solution here. But there is a catch, so i'm open for proposals if anyone knows.
Instead camera i use a mesh for example:
namespace MeshProcessing
{
class HEMesh
{
public:
// some data...
typedef int32_t Index;
// vertices
std::vector<Index> mVertexEdge;
std::vector<vec> mVertexPosition;
// ...
// some functions
void SetVertexPos (const int vertex, const vec &pos) { mVertexPosition[(Index)vertex] = pos; }
vec GetVertexPos (const int vertex) const { return mVertexPosition[(Index)vertex]; }
// ...
The functions are general stuff i need everywhere. Accessing the data, but also calculating a vertex normal or polygon area, basic things.
I could not add all specific functionality to the same mesh class. It would get too big.
I need mesh editing functions, visualization, serialization, conversation, and even more specific stuff like Delaunay triangulation.
So i use derived classes for each of those topics, for example:
namespace MeshProcessing
{
class HEMesh_Modeling : public HEMesh
{
public:
int AddPolygon (const int edge,
const int atIndex = -1);
int AddPolygonFromEdges (const int *edgeIndices, const int numEdges,
const int atIndex = -1);
int AddPolygonFromVertices (const int *vertexIndices, const int numVertices,
const int atIndex = -1);
void RemovePolygon (const int poly);
// ...
So i have all my editing functions grouped on one derived class to keep things organized by topic.
To use the derive class, i do a cast:
HEMesh mesh;
((HEMesh_Serialization&) mesh).LoadFromFile("...");
((HEMesh_Modeling&) mesh).AddPolygon(17);
((HEMesh_Vis&) mesh).RenderPolygonsFilled();
Maybe this looks a bit awkward, but it's better than giving a mesh as parameter to all those specific functions while avoiding the derived class.
It's actually nice for things which have a lot of functionality associated to it. But surely overkill to a Camera.
But the catch is: The derived classes must not introduce any new member data to the base class. Otherwise i could not cast one to the other just to ‘switch topics’.
And sadly C++ has no way to enforce a derived class can only add functions but no data, afaict.
If it had, my proposal here would make much more sense.
Alternatively, we could dump all functionality to the header file of mesh class definition, but use multiple C++ files to group by multiple topics. But then our header file becomes bloated with lots of inlined functions we need only rarely, which is bad for many reasons.
So i really wonder what other programmers do here. There should be a better, standard way to do group class functionality, but i could not find any. And actually i feel like misusing the concept of derived classes for a different purpose.
ShapeSpheres said:
I recently learned how I can simplify/improve code by using structs and non-member functions so to test this new discovery I refactored my camera code and I have a feeling I misused it.
Ha, it's actually coincidence i've used the word ‘misuse’ as well. : )
But coming from C, to me it's member functions which was the new discovery.
Still, today i do not use global functions anymore. I use namespaces to group them by some topic, so they are no longer global but technically still the same.
Maybe you can do the same to make non-member functions feel less alien.
Example:
namespace TextureFilter
{
// box filter
template <typename T>
static T SampleTextureBox (const T *texture,
const int *gridI0, const float *gridF0,
const int *gridI1, const float *gridF1,
const int *size);
template <typename T>
static T SampleTiledTextureBox (const T *texture,
const int *gridI0, const float *gridF0,
const int *gridI1, const float *gridF1,
const int *size,
const bool tileH, const bool tileV);
// ...
};
Those functions give me similar functionality then a texture lookup on GPU. It has lots of functions, so it's convenient to group them all by a namespace.
I could use a struct or class without any member data for the same purpose, but by using a namespace it's obviously clear there is no member data right from the start to anybody. So the namespace is clearly better.
However, sometimes it is useful to have private functions internal to the topic as well, to reduce visible complexity to the outside.
Then i use a class instead a namespace. Again i would like to make clear the class has no member data.
Following this, you could end up with something like this:
Camera cam;
cam.Update(...);
auto m = CameraTools::ComputeViewMatrix(cam); // CameraTools would be a namespace / class / struct to group related functionality
But as others said, this as a matter of finding your personal preferences with time, or the ability to adopt conventions from the code base you are working on with others.