Monday, August 13, 2012

So I kind of have a dynamic code generation...

So I kind of have a dynamic code generation and execution library written in C# that works on Linux now, if you have GCC installed.

It works, as long as you define your delegate ahead of time, and pass it in as part of the process.

But what if you don't know what you want ahead of time? Say you want to ask the user, how many parameters do you want to pass to the function?

Right now you can't generate dynamically your calls, it won't let you cheat, but I think I figured a way around this. And that is...
Using the CodeDOM
The CodeDOM provides types that represent many common types of source code elements. You can design a program that builds a source code model using CodeDOM elements to assemble an object graph. This o...
View or comment on Joel Longanecker's post »
Google+ makes sharing on the web more like sharing in real life. Learn more.
Join Google+
You received this message because Joel Longanecker shared it with longjoel.baconbacon@blogger.com. Unsubscribe from these emails.
You can't reply to this email. View the post to add a comment.

Monday, March 19, 2012

OpenGL Buffer Packing

This weekend I felt a drain to my creativity brought about by a combination of not feeling well, disappointment in the ending of Mass Effect 3, and actually getting decent at call of duty. Drop-box replacing some important code files with emptiness didn't help either. So I've decided to start from scratch, rather than trying to repair my existing code base.

Starting from square one usually involves a trip to good old fashioned C. If I can code it in C, I can take it anywhere. I had gotten quite good at doing OpenGL from inside OpenTK, so my idea was to take some of the  modern concepts learned from there, and apply them back in C.

Modern OpenGL consists really of two things, cramming things in to buffers, and making pretties with shaders.

So, let's talk about array buffers, no, wait, let's talk about vertexes first.

In a mathematical sense, a vertex buffer is an intersection of two or more lines in space. We use vertexes to define the bounds of our geometry instead of lines or rays. However, in OpenGL, vertexes do not just represent points in space that define boundaries of geometry. Color, texture, lighting, and other information can also be attached to a vertex as well.

There are two ways of packing data into buffers. The first way is to give each type of element it's own buffer. 

So in case A:

* vertexes would be in their own vertex buffer
* colors would be in their own color buffer
* texture coordinates would be in their own buffer
* normals would be in their own normal buffer

Case B: (Eeach vertex would contain the following)

* x, y, z (position)
* s, t (texture)
* r, g, b, a (color)
* nx, ny, nz (normal)

In general, case B is the better way to go. It only requires one bind buffer operation, vs one for each component type. 

For case A, you would do your drawing like this:

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle);
glVertexPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, color_buffer_handle);
glColorPointer(4, GL_FLOAT, 0, 0);

glDrawArrays(GL_TRIANGLES, 0, number_triangles);
...

for case B, you would draw like this:

typedef struct {

float x, y, z;
float r, g, b, a;

}custom_vertex_format;

...

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
glVertexPointer(3, GL_FLOAT, sizeof(custom_vertex_format), 
    offsetof(custom_vertex_format, x);

glColorPointer(4, GL_FLOAT, sizeof(custom_vertex_format), 
    offsetof(custom_vertex_format, r);

glDrawArrays(GL_TRIANGLES, 0, number_triangles);

offsetof is a macro defined in stddef.h http://linux.die.net/man/3/offsetof

Again, in most circumstances, method B is going to be faster. The reasoning for this is as follows.

Fewer cache misses, since all the data is tightly packed together. In case A, it might be conceivable that the vertex buffer and the color buffer might be in completely different areas in memory. In case B, each vertex should be adjacent to each other. It's also especially important when working with element arrays.

What's an element array?

Consider the following. Say you have a mesh, and in this mesh, you have multiple adjacent triangles. These triangles, 'share' a vertex. As in, the vertex has the exact same position, color, normal and texture attributes. The more attributes you have packed in your vertex, the more expensive it becomes to have duplicates in your vertex buffer.

Say you have the following vertexes 
V = {A, B, C, D, E, F, G, H, I, J}

Say your triangle mesh 
M = {A, B, C, B, C, D, C, D, E, F, G, H}

So, B is an element twice, C is an element 3 times, D is in there twice, etc. At this point, each vertex is composed of at least 11 floating point elements. If only there was a way to send each vertex to the buffer exactly once, and then just draw by index... There is!

Say V = {A, B, C, D, E, F, G, H, I, J}
and M = {A, B, C, B, C, D, C, D, E, F, G, H}

Let Mi = {1,2,3,2,3,4,3,4,5,6,7,8}

So we would bind V as our vertex buffer, and Mi as our element buffer. we would use glDrawElements instead of glDrawArrays. http://www.opengl.org/sdk/docs/man/xhtml/glDrawElements.xml

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
glVertexPointer(3, GL_FLOAT, sizeof(custom_vertex_format), 
    offsetof(custom_vertex_format, x);

glColorPointer(4, GL_FLOAT, sizeof(custom_vertex_format), 
    offsetof(custom_vertex_format, r);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_handle);

glDrawElements(GL_TRIANGLES, number_triangles, GL_SHORT, 0);

Take note that we only had to bind the element array buffer in order to use glDrawElements, we didn't have to specify an element pointer, or enable the client state for it.

Also, notice that there isn't a separate element buffer for each attribute of the vertex. It sounds like it could be a great idea, but the reality is that it would be incredibly slow. It's the same reason why non-power of two textures are such a problem. It's just a constraint we have to live with.

I hope this has helped distinguish some of the differences in how OpenGL can process buffers for you.

Thursday, March 15, 2012

Service Driven Game Development

When most people think of a service, web servers, printer spoolers, and drivers come to mind. In a different sense, a service can be thought of as a program that runs for as long as the operating system is running. Most services are independent of each other, do one thing, and do it well, like serve web pages. The same concept can be applied to games. If each component of your game does one thing, and does it well, it allows you to focus on one component at a time, it also makes your game more testable. By bringing services up and down, you can simulate failure in a specific part, such as when the network drops out, or the screen gets unplugged.

One of the things to keep in mind when doing this is cross-service communication. How is one service going to talk to another? In the example presented, each service is going to register for the types of events that it wishes to be notified of. It will be a bit clearer when the code is presented.

First things first, let's define the service interface.

interface IService
+ void RegisterEvents(ServiceManager m)
+ void ExecuteFrame(ServiceManager m)

Each IService must be able to register events with the service manager, and each service must expose a method that the service manager can call to process events.

The other primary component is the Message.

class Message
+ public IService Sender {get; set;}
+ public EventArgs EventArguments {get; set;}

A message contains a sender, and event arguments. Sender tells you what service the message came from, and EventArguments contains other arguments that a service would want.

The Services Manager class is responsible for keeping track of the services and routing the messages between the services.

class ServiceManager
+ public delegate void OnRecievedMessage(Message m);
+ Dictionary<Type, IService> _services;
+ List<Tuple<Type, IService, OnRecievedMessage>> _routes;
+ public void RegisterService(Type service) { ... }
+ public void UnregisterService(Type service) { ... }
+ private void UnregisterEventHandler(IService sender) { ... }
+ public void RegisterEventHandler
    (Type eventsArgType, OnRecievedMessage m) { ... }
+ public void SubmitMessage
    (IService sender, 
        Type eventArgsType, EventArgs message) { ... }
+ public void Execute() { ... }

** OnRecievedMessage is the delegate for when a service receives a message.

** _services is a dictionary of service types mapped to the service. That means for each type, there can be exactly one service.

** _routes specifies the path each message takes when it's dispatched. If you haven't seen a Tuple before, it can be considered to be a read only, fixed length list. This establishes a many to many mapping between the types of messages, and delegates that process messages.

If you had a process that was responsible for switching states, and needed to listen for the pause button, and a state responsible for processing immediate game events, they both might listen for a key down event.

The other thing to note is that any process may dispatch any type of event. If you are writing a multi-player game, and it supports local input as well as network input, the network service might send the same player movement actions as the physics service.


** RegisterService is used to register a new service with the game server manager. Notice that instead of registering an instance of an existing service, you register a type, so that the server manager itself instantiates the object.




public void RegisterService(Type service)
{
    _services[service] = 
        (IService)Activator.CreateInstance(service);
    _services[service].RegisterEvents(this);
}






** UnregisterService is used to take a service out of circulation, including all of the routes that said service might deliver messages.


public void UnregisterService(Type service)
{
    var s = _services[service];
    UnregisterEventHandler(s);
    _services.Remove(service);
}



** UnregisterEventHandler is called internally to remove the services that have been registered when the service was created.


private void UnregisterEventHandler(IService sender)
{
    for (int i = _routes.Count - 1; i >= 0; i--)
    {
        if (_routes[i].Item2 == sender)
            _routes.RemoveAt(i);
    }
}



** RegisterEventHandler is called by a service to add an event to the routing map. It's not really something that should be exposed to anything but the Service, but it is what it is. C# doesn't support the friend keyword like C++ does.


public void RegisterEventHandler(Type eventsArgType, 
    IService sender, 
    OnRecievedMessage m)
{
    _routes.Add(
        new Tuple<Type, IService, OnRecievedMessage>
            (eventsArgType, sender, m));
}



** The SubmitMessage method is used to insert a message for the services to consume.


public void SubmitMessage(IService sender, 
    Type eventArgsType, 
    EventArgs message)
{
    (from r in _routes 
     where r.Item1 == eventArgsType 
     select r.Item3)
        .ToList()
        .ForEach(m => m(new Message() { 
            EventArguments = message, 
            Sender = sender }));
}



** Execute is called each frame, so that each of the services can execute their core. Recall ExecuteFrame from the IService interface.


public void Execute()
{
    _services.Values
        .ToList()
        .ForEach(x => x.ExecuteFrame(this));
}



Activation of the services would look something like this


var sm = new ServicesManager();
sm.RegisterService(typeof(InputService));
sm.RegisterService(typeof(GameService));


If we wanted to execute the game for 10 steps, it would look like this.

for (int i = 0; i < 10; i++)
     sm.Execute();

To unregister a service.

sm.UnregisterService(typeof(GameService));


A sample implementation of InputEventArgs and InputService

class InputEventArgs:EventArgs
{
    public char ScanCode { get; set; }
}

class InputService:IService
{
    public void RegisterEvents(ServicesManager m)
    {}

    public void ExecuteFrame(ServicesManager m)
    {
        m.SubmitMessage(this, 
            typeof(InputEventArgs), 
            new InputEventArgs() {ScanCode = 'a' });
    }
}

Each time ExecuteFrame is called, this sample service puts a new message into the queue.

This is the sample implementation for a game service, it a very trivial implementation.

class GameService : IService
{
    public void RegisterEvents(ServicesManager m)
    {
        m.RegisterEventHandler(
            typeof(InputEventArgs),
            this,
            (a) =>
            {
                Console.WriteLine(
                    (a.EventArguments
                    as InputEventArgs).ScanCode);
            }
            );
    }

    public void ExecuteFrame(ServicesManager m)
    { }
}


That more or less wraps it up. This isn't 'the' way to do it, there's certainly much better ways to do it. You could have each service executing in it's own thread. Some people would rather not use tuples. The takeaway should be that this is another tool you throw in your toolbox.

Thursday, February 9, 2012

Adventures in homebrew -- wii part 1

I work on a lot of different things, all the time.

Tonight I finally got devkitpro working for doing wii development.

My environment is the following

VirtualBox image of debian 6
DevkitPPC
codelite IDE
and a softmodded nintendo wii


My initial goal was to port Mono to the wii, but that seems like quite the daunting task. Mono is a big platform, and I certainly don't know my way around auto-tools, but getting it ported could certainly be worth it.

For now though, it might be worth trying to port a smaller platform over to the wii.

Python is certainly a candidate. Javascript and lua certainly have their appeal.

V8 looks interesting, if I can figure out how to force scons to use the devkitpro ppc compiler.

That will be the next avenue of attack, I think. For now, sleep!


edit:

Found this until I can figure how to make v8 do my bidding!

http://code.google.com/p/tiny-js/

Tuesday, February 7, 2012

viper - next steps

So I've made some decent progress on viper. I think now would be a great time to justify yet another game development library, seeing as there is already xna, openTK, Tao.NET, Unity, SFML, and several others.

Maybe the biggest one is that they aren't all that friendly to use. I'm not saying that they are difficult. DirectX is difficult, OpenGL + Extensions under win32 is difficult. I'm just saying that they aren't friendly. 

OpenTK and XNA both require that the gut class of your program inherit from a class in their assembly. I'm not saying that inheritance is a bad thing, it's actually quite useful, but it forces you to adopt their way of thinking, and at least in the case of XNA, for a beginner, it's not always clear what to override.

Viper provides a more explicit interface. In viper, you create the window, not inherit from an abstract window or game class. You explicitly define it.

Another thing that viper provides is thread safety. Most of the time, you aren't going to want your rendering code in a secondary thread anyways, but you might want your resource loading to happen in the background. With OpenGL, and much of Direct3D, all the calls are required to be made on the same thread in which the context was created.

When the pitviper window is initialized, the first thing it does is create it's own UI Thread. That thread creates the output window and does message processing from two message queues; the windows system message queue, and an internal message queue.

The internal message queue is a queue of Action<> delegates. When you call a method like myGameWindow.Clear(255,255,255) what it's really doing is queuing up a new action delegate containing the command, and placing it into the private queue. The UI Thread will then dequeue the call, and execute it. This is how thread safety is achieved.

This also has the unintended side effect of potentially making your code faster. If you are in the habit of doing a lot of calculations in your rendering code, on the same thread, you are doing that math, then the rendering, then more logic, then more rendering. By offloading the rendering to a dedicated thread you can go from this

logic  |  render   |   logic   | render  |

to this

logic 1 |   logic 2  | logic 3  | logic 4  |  logic 5  |
        |  render 1  | render 2 | render 3 |  render 4 | render 5

Granted, you do have the overhead of a context switch, and you won't see a huge boost on hardware with only a single thread, but the goal here is not ultimate performance, but rather simplicity. If we can get a small performance boost out of it at the same time in some scenarios, then awesome!


***

Another thing that sets viper apart is that it's primarily 2D, and I don't see that changing. There are constraints with what you can realistically do in a 2D environment. When you go 3D, you can either do far too little, or far too much. The first thing that comes to mind is vertex formats. Position? Position + color? Position + color + texture + normal? Position + color + texture + normal + extra info for the shader? I feel that by going 3d, it would break away from the concept of simplicity that I'm aiming for.

***

Currently, I'm relying on OpenGL 1.2, and I don't know if that will ever change. Having support for shaders would definitely be nifty but GLSL is far from being simplistic, and at this point I'm not sure the benefits out weigh the obstacles. If somebody wanted to help me enable them in a sane fashion, that would be amazing.


*** 

I suppose the next big huge step is going to be finishing up the input sub system. Keyboard and mouse should be fairly straight forward. Right now, the keyboard uses get async key state to poll the keyboard directly, but I'm going to investigate using raw input instead.

***

I'm working on tutorials and documentation for the time being in hopes of attracting more attention to the project, and oh yeah, I should probably host it somewhere. A game showing it off would be nice too.