3
\$\begingroup\$

I am trying to implement graphic objects that can be either Sprite, Base, Point or some others, but not very many types at all. That's why I do not make separate classes. All types exist in 1 class due to unions and few short switches. I use directly objects, not pointers, and no virtual methods. The question is also, do you agree that it's a good idea to mark everything inline in this particular case.

In this exact code, unions don't look useful as the code is raw and classes unfinished.

Declarations:

#ifndef GFX_HPP_INCLUDED
#define GFX_HPP_INCLUDED
#include <vector>
namespace keng {
class gfx {
public: // types
 enum types {
 sprite,
 base,
 point
 };
 static const int base_default_size = 10;
private: // default base
 static gfx* const default_base;
public: // special construct methods
 static gfx* create_sprite(
 int position = 0,
 int map = 0,
 int x = 0,
 int y = 0,
 float scale = 1.0f,
 gfx* base = default_base
 );
 static gfx* create_base(
 int position = 0,
 int size = 0,
 float scale = 1.0f,
 gfx* base = default_base
 );
 static gfx* create_point(
 int position = 0,
 int x = 0,
 int y = 0,
 float scale = 1.0f,
 gfx* base = default_base
 );
public: // switching methods
 void render();
 ~gfx();
private: // untitled special constructors
 // sprite
 gfx(
 int map,
 int x,
 int y,
 float scale
 );
 // base
 gfx(
 int size,
 float scale
 );
 // point
 gfx(
 int x,
 int y,
 float scale
 );
private: // help
 typedef std::vector<std::vector<gfx>> gfx_container_t;
 template<typename... Args>
 static gfx* construct(gfx* base, int position, Args... args);
private: // type data
 int type;
private: // switching data
 union {
 int map; // sprite
 gfx_container_t* gfx_container; // base
 };
 union {
 int x; // sprite / point
 };
 union {
 int y; // sprite / point
 };
 union {
 float scale; // sprite / base / point
 };
 union {
 int map_x; // sprite
 };
 union {
 int map_y; // sprite
 };
 union {
 bool mirror_x; // sprite
 };
 union {
 bool mirror_y; // sprite
 };
}; // class gfx
} // namespace keng
#include "gfx.hh"
#endif // GFX_HPP_INCLUDED

Definitions:

#ifndef GFX_HH_INCLUDED
#define GFX_HH_INCLUDED
#include "spriteset.hpp"
using namespace keng;
// default gfx
gfx* const gfx::default_base = new gfx(base_default_size, 1.0f);
// special construct methods
inline gfx* gfx::create_sprite(
 int position,
 int map,
 int x,
 int y,
 float scale,
 gfx* base
)
{
 return construct(
 base,
 position,
 map,
 x,
 y,
 scale
 );
}
inline gfx* gfx::create_base(
 int position,
 int size,
 float scale,
 gfx* base
)
{
 return construct(
 base,
 position,
 size,
 scale
 );
}
inline gfx* gfx::create_point(
 int position,
 int x,
 int y,
 float scale,
 gfx* base
)
{
 return construct(
 base,
 position,
 x,
 y,
 scale
 );
}
// switching methods
inline void gfx::render() {
 switch (type) {
 case sprite:
 {
 int vertex_x1 = mirror_x * Spriteset::width[map];
 int vertex_x2 = (1 - mirror_x) * Spriteset::width[map];
 int vertex_y1 = mirror_y * Spriteset::height[map];
 int vertex_y2 = (1 - mirror_y) * Spriteset::height[map];
 GLfloat texture_x1 = Spriteset::normed_width[map] * map_x;
 GLfloat texture_x2 = texture_x1 + Spriteset::normed_width[map];
 GLfloat texture_y1 = Spriteset::normed_height[map] * map_y;
 GLfloat texture_y2 = texture_y1 + Spriteset::normed_height[map];
 glEnable(GL_TEXTURE_2D);
 glBindTexture(GL_TEXTURE_2D, Spriteset::texture[map]);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 glBegin(GL_POLYGON);
 glTexCoord2f(texture_x1, texture_y1);
 glVertex2f(vertex_x1, vertex_y1);
 glTexCoord2f(texture_x1, texture_y2);
 glVertex2f(vertex_x1, vertex_y2);
 glTexCoord2f(texture_x2, texture_y2);
 glVertex2f(vertex_x2, vertex_y2);
 glTexCoord2f(texture_x2, texture_y1);
 glVertex2f(vertex_x2, vertex_y1);
 glEnd();
 glDisable(GL_TEXTURE_2D);
 break;
 }
 case base:
 for (std::vector<gfx>& vg : *gfx_container)
 for (gfx& g : vg)
 g.render();
 break;
 case point:
 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 glBegin(GL_POINTS);
 glVertex2f(.0f, .0f);
 glEnd();
 break;
 }
}
inline gfx::~gfx() {
 switch (type) {
 case sprite:
 break;
 case base:
 delete gfx_container;
 break;
 case point:
 break;
 }
}
// untitled special constructors
inline gfx::gfx(
 int map,
 int x,
 int y,
 float scale
)
:
 type(sprite),
 map(map),
 x(x),
 y(y),
 scale(scale)
{
}
inline gfx::gfx(
 int size,
 float scale
)
:
 type(base),
 gfx_container(new gfx_container_t(size)),
 scale(scale)
{
}
inline gfx::gfx(
 int x,
 int y,
 float scale
)
:
 type(point),
 x(x),
 y(y),
 scale(scale)
{
}
// help
template<typename... Args>
inline gfx* gfx::construct(gfx* base, int position, Args... args) {
 gfx* result = new gfx(args...);
 (*base->gfx_container)[position].push_back(*result);
 return result;
}
#endif // GFX_HH_INCLUDED
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 14, 2015 at 17:53
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Being honest with you, this implementation is very confusing. I really can't believe you are so performance constrained that you can't pay for a virtual function call, and have resorted to this approach because of that. I mean, manual de-virtualization would be the last thing I'd think of as an optimization. The fact that you use fixed function OpenGL to draw the sprites is you number 1 performance cost. That's probably where 99% of the render() time is spent. If you're into optimizing the rendering, first thing is to change that immediate mode draw by buffered draws.

And still, it is expected than when optimizing code, some parts of it might become less readable, but there is a limit to how much you'd "disfigure" the code just to gain a tiny bit of runtime performance. So my only advice here would be: please do make that into a couple classes and use virtual methods if needed be. It will make this code so much more readable and easier to maintain. C++ introduced the concepts of inheritance and virtual dispatch so that we, the programmers, wouldn't have to do this kinds of godawful hacks we used to do back with C and Assembly.

answered Aug 14, 2015 at 19:25
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.