Jump to content

  • Log In with Google      Sign In   
  • Create Account

#ActualHodgman

Posted 27 September 2012 - 10:11 PM

Theres two ways to approach this kind of system
a) make a generic message buffering system that you can use to store/sort/call any function.
b) make a buffering system specific to your renderer.

In my engine, I've got both -- I use (a) for general buffering of gameplay commands, but use (b) when it comes to drawing things, because I rarely add new basic drawing functions (new drawing functions are usually a composition of the basic commands).

For my drawing commands, I keep the system as simple as possible, and it boils down to something like:
struct DrawCommand
{
  enum Type
  {
    Foo,
    Bar
  };
  Type type;
  int Size();
}
struct DrawFoo : public DrawCommand
{
  static int Size() { return sizeof(DrawFoo); }
  DrawFoo() { type = Foo; }
  int foo;
}
struct DrawBar : public DrawCommand
{
  static int Size() { return sizeof(DrawBar); }
  DrawBar() { type = Bar; }
  float x, y, z;
}
int DrawCommand::Size()
{
  switch(type)
  {
    case Foo: return DrawFoo::Size();
    case Bar: return DrawBar::Size();
  }
  return 0;
}


....

std::vector<char> bytes(1024);
int pointer = 0;
struct DrawItem
{
  int byteOffset;
  int layer;
};
std::vector<DrawItem> items;
...
void Push( DrawCommand& cmd, int layer )
{
  char* out = &bytes[pointer];
  DrawItem item = { pointer, layer };
  items.push_back( item );
  int size = cmd.Size();
  pointer += size;
  assert( pointer <= bytes.size() );
  memcpy( out, &cmd, size );
}


...
std::stable_sort( items.begin(), items.end(), sortByLayer() );
foreach( items as item )
{
  DrawCommand& cmd = *(DrawCommand*)&bytes[item.byteOffset];
  switch( cmd.type )
    ...
}

#3Hodgman

Posted 27 September 2012 - 09:53 PM

Theres two ways to approach this kind of system
a) make a generic message buffering system that you can use to store/sort/call any function.
b) make a buffering system specific to your renderer.

In my engine, I've got both -- I use (a) for general buffering of gameplay commands, but use (b) when it comes to drawing things, because I rarely add new basic drawing functions (new drawing functions are usually a composition of the basic commands).

For my drawing commands, I keep the system as simple as possible, and it boils down to something like:
struct DrawCommand
{
  enum Type
  {
    Foo,
    Bar
  };
  Type type;
  int Size();
}
struct DrawFoo : public DrawCommand
{
  static int Size() { return sizeof(DrawFoo); }
  DrawFoo() { type = Foo; }
  int foo;
}
struct DrawBar : public DrawCommand
{
  static int Size() { return sizeof(DrawBar); }
  DrawBar() { type = Bar; }
  float x, y, z;
}
int DrawCommand::Size()
{
  switch(type)
  {
    case Foo: return DrawFoo::Size();
    case Bar: return DrawBar::Size();
  }
  return 0;
}


....

std::vector<char> bytes(1024);
int pointer = 0;
struct DrawItem
{
  int byteOffset;
  int layer;
};
std::vector<DrawItem> items;
...
void Push( DrawCommand& cmd, int layer )
{
  char* out = &bytes[pointer];
  DrawItem item = { pointer, layer };
  items.push_back( item );
  int size = cmd.Size();
  pointer += size;
  assert( pointer <= bytes.size() );
  memcpy( out, &layer, size );
}


...
std::stable_sort( items.begin(), items.end(), sortByLayer() );
foreach( items as item )
{
  DrawCommand& cmd = *(DrawCommand*)&bytes[item.byteOffset];
  switch( cmd.type )
    ...
}

#2Hodgman

Posted 27 September 2012 - 09:52 PM

Theres two ways to approach this kind of system
a) make a generic message buffering system that you can use to store/sort/call any function.
b) make a buffering system specific to your renderer.

In my engine, I've got both -- I use (a) for general buffering of gameplay commands, but use (b) when it comes to drawing things, because I rarely add new basic drawing functions (new drawing functions are usually a composition of the basic commands).

For my drawing commands, I keep the system as simple as possible, and it boils down to something like:
struct DrawCommand
{
  enum Type
  {
	Foo,
	Bar
  };
  Type type;
  int Size();
}
struct DrawFoo : public DrawCommand
{
  static int Size() { return sizeof(DrawFoo); }
  DrawFoo() { type = Foo; }
  int foo;
}
struct DrawBar : public DrawCommand
{
  static int Size() { return sizeof(DrawBar); }
  DrawBar() { type = Bar; }
  float x, y, z;
}
int DrawCommand::Size()
{
  switch(type)
  {
	case Foo: return DrawFoo::Size();
	case Bar: return DrawBar::Size();
  }
  return 0;
}
std::vector<char> bytes(1024);
int pointer = 0;
struct DrawItem
{
  int byteOffset;
  int layer;
};
std::vector<DrawItem> items;
...
void Push( DrawCommand& cmd, int layer )
{
  char* out = &bytes[pointer];
  DrawItem item = { pointer, layer };
  items.push_back( item );
  int size = cmd.Size();
  pointer += size;
  assert( pointer <= bytes.size() );
  memcpy( out, &layer, size );
}
...
std::stable_sort( items.begin(), items.end(), sortByLayer() );
foreach( items as item )
{
  DrawCommand& cmd = *(DrawCommand*)&bytes[item.byteOffset];
  switch( cmd.type )
    ...
}

#1Hodgman

Posted 27 September 2012 - 09:50 PM

Theres two ways to approach this kind of system
a) make a generic message buffering system that you can use to store/sort/call any function.
b) make a buffering system specific to your renderer.

In my engine, I've got both -- I use (a) for general buffering of gameplay commands, but use (b) when it comes to drawing things, because I rarely add new basic drawing functions (new drawing functions are usually a composition of the basic commands).

For my drawing commands, I keep the system as simple as possible, and it boils down to something like:
struct DrawCommand
{
  enum Type
  {
    Foo,
    Bar
  };
  Type type;
  int Size();
}
struct DrawFoo : public DrawCommand
{
  static int Size() { return sizeof(DrawFoo); }
  DrawFoo() { type = Foo; }
  int foo;
}
struct DrawBar : public DrawCommand
{
  static int Size() { return sizeof(DrawBar); }
  DrawBar() { type = Bar; }
  float x, y, z;
}
int DrawCommand::Size()
{
  switch(type)
  {
    case Foo: return DrawFoo::Size();
    case Bar: return DrawBar::Size();
  }
  return 0;
}
std::vector<char> bytes(1024);
int pointer = 0;
struct DrawItem
{
  int byteOffset;
  int layer;
};
std::vector<DrawItem> items;
void Push( DrawCommand& cmd, int layer )
{
  char* out = &bytes[pointer];
  DrawItem item = { pointer, layer };
  items.push_back( item );
  int size = cmd.Size();
  pointer += size;
  assert( pointer <= bytes.size() );
  memcpy( out, &layer, size );
}

PARTNERS