Jump to content

  • Log In with Google      Sign In   
  • Create Account

D Bits



Putting D's Array Slices to Use

Posted by , in BorderWatch, D 08 March 2012 - - - - - - · 1,841 views

I've been working on BorderWatch a little bit every day. My focus has been on getting the ASCII engine, Arthur, into a state that will let me get a game up and running. With the few modules that I've implemented so far, I believe I'm there. One of the D features that has come into play in this process has been array slices. Read Steven Schvieghoffer's excellent article on slices, now hosted at dlang,org, for a good introduction if you don't know what they are.

Take a look at the BorderWatch main method (or view the whole module for context):

void main()
{
	initArthur(AppName, OrgName);
	scope(exit) termArthur();

	auto console = createConsole(ConsoleData(AppName));
	menuScreen(console);
}


The Console is the means of displaying the ASCII graphics to the user. Initially, there was only one kind, a "heavyweight" console that represents a window on the OS. But after realizing how annoyingly awkward it was to position things appropriately with my naive implementation of clipping, I came to the conculsion it would be much nicer to have another type, "virtual consoles", that maintain their own coordinate space.

At the heart of both types of Console is an array of Symbols (an ASCII character and RGBA values). A virtual console's buffer is a subrect of its parent's buffer. Every time you print to a console, it is marked as dirty. When you call the render method on a console, it first looks to see if any of its children are dirty. If they are, it copies the children's symbols into the proper region of its own buffer.

In C, this sort of operation would most likely be accomplished with a loop and a memcpy, copying entire rows at a time. My D implementation is done similarly, but instead of memcpy, I use array slices. Here's the (uncommented) code from console.d that does the work:


void render()
{
    foreach(c; _children)
    {
	    if(c._dirty)
	    {
		    uint dstStart = c.x + (c.y * columns);
		    uint dstEnd = dstStart + c.columns;
		    uint srcStart, srcEnd;
		    for(uint i=0; i<c.rows; ++i)
		    {
			    srcStart = i*c.columns;
			    srcEnd = srcStart + c.columns;
			   
			    // Here's the slicing...
			    // The symbols from one row of the child's buffer are
			    // copied to one row of the destination buffer.
			    _symBuffer[dstStart .. dstEnd] = c._symBuffer[srcStart .. srcEnd];

			    dstStart += columns;
			    dstEnd = dstStart + c.columns;
		    }
		    _dirty = true;
		    c._dirty = false;
	    }
    }
}


If you haven't yet read the article I linked above, a quick explanation. _symBuffer[dstStart .. dstEnd] takes a 'slice' of the _symBuffer array, starting from the index indicated by dstStart (inclusive) and ending at the index indicated by dstEnd (exclusive). That slice is then assigned all of the values contained in the slice of the child's buffer that is taken from srcStart to srcEnd. There's no need for pointer arithmetic, no chance of overwriting memory, no need to worry about allocations or deallocations... it's all safe and convenient.

Another use I had for array slices, in the same file, is in the following method:

void fill(ubyte c, ubyte r, ubyte g, ubyte b, ubyte a = 255)
{
    auto symbol = Symbol(c, r, g, b, a);

    // Here's the slice...
    _symBuffer[] = symbol;
}


Here, I'm taking a single symbol and using the slice syntax to assign it to the entire array.

These are seemingly farily trivial things, but I can tell you that it makes a big difference. I've been using C for many years and, though I've been frustrated from time to time, I've never actually hated it. But the more I use D, the more I miss the little things like this when I go back to my C codebase. It almost makes me not want to go back at all.


BorderWatch

Posted by , in BorderWatch, D 05 March 2012 - - - - - - · 1,607 views

I'm afraid I'm going to be waving goodbye to Dolce. It's been sitting, bit rotting, for a while now. Some time ago I encountered two major issues with my Allegro binding in Derelict 2. One, a random (and I mean random) crashing bug, I've been unable to solve. Another, regarding Allegro's interaction with Cocoa on Mac, I don't have the means to test (no Mac), though I do have an idea on how to solve it. However, I'm washing my hands of it all for now. I may come back to the Allegro binding after the Allegro 5.1 branch is complete, but Dolce I think is quite dead.

But I still haven't lost my urge to make a game. In fact, I did make one as a way to get back into the groove. I didn't mention it here because I actually coded it in C. Nothing to brag about, just a simple reimplementation of the A5teroids example that ships with Allegro 5. I wanted to get familiar with the API and get my chops back without the distractions my binding was causing. And that brings me to the topic of this post.

I really, really want to make this game that has been in my head forever. So, now I am. But without Allegro. Instead, I'm going with an ASCII-based approach using SDL2. This is an evolution of the text-based idea I was contemplating a while back. The big difference is that this time, I've got some code to show for it. Also, though it is still in the early stages, it's getting to the point where I'm ready to have a git repo to manage my changes. Rather than just working on a local repo, I decided to bite the bullet and just put everything on github as is. And so, I give you BorderWatch.

One of the reasons I wanted to put it up on github is to give myself a reference to talk about features of D on this blog. Dolce was supposed to fill that role, but I never really felt it was ready for the world. BorderWatch is different, though, and I hope it can serve as a starting point for anyone curious about using D for game development. I can seriously say that after working on even a simple little game like an asteroids clone in C (a language I've used and loved/hated for a very long time), putting one together in D is a much different, and better, world entirely.

Please read the project README before you bother with the code. I'm using my recently implemented SDL2 and SDL2_image bindings from Derelict 3, and no other external libraries. If you want to build the project, you'll have to get the SDL2 and SDL2_image source and compile it all yourself. Also, only DMD and Windows are currently supported.

I do hope to work on this over the coming months as often as I can. I have a lot of ideas for it and it is proving to be a lot of fun so far. It's licensed under the zlib license, so do what you want with it. There's not a whole lot there yet, but what is there allows you to open a 'console' window, print ASCII characters and text strings to the whole window area or specific regions, and there's an effect implemented that can display text strings as a slideshow. Nothing is optimized, nothing is stable. But it's a start.


Compiling Data into a D Executable

Posted by , in D 03 March 2012 - - - - - - · 5,658 views

I'm supposed to be posting part three of my series on binding D to C. It's going to be boring to write, so I keep putting it off. But I *will* get to it eventually. In the meantime, I wanted to blog about a neat feature of D that I'd sort of forgotten about until I needed it.

I'm working on an ASCII-based strategy/simulation game in the vein of Dwarf Fortress. One of the things I want to have is an ASCII bitmap that is always available, a default that I can fall back on if any custom bitmaps fail to load. The best way to do this is to have the bitmap data compiled into the executable. A simple, cross-platform way to do that in C or C++ is to convert the bitmap data into a C array in a source file to be compiled and linked. In D, the compiler can do it all for you.

The import keyword in D plays two roles. The most common (and important) role is in import declarations. These are what you use to make the content of one module available to another. D also has a feature called import expressions, which allow you to specify a file that the compiler will build in to the final executable.

// Import declaration (no parentheses)
import mypackage.mymodule;

// Import expression (with parentheses)
string s = import("some.file");


The first thing you might notice is that the file is imported as a string. This isn't going to be very useful for binary data. But that's not a big deal. A simple cast to ubyte[] will do the trick. If other types are needed and casting doesn't fit, a compile-time function can be used to massage the data into the appropriate format. Also, the filename itself can be generated at compile time. Read more about D's compile time function execution.

Now for some real example code, straight from my game. I'm using SDL_image to load the default font image from a ubyte array,

// The name of the default font file, declared as a manifest constant.
enum DefaultFontName = "default_font.png";

// The image data. Loaded as a string, so casted to an immutable ubyte array.
immutable(ubyte)[] _defaultFont = cast(immutable(ubyte)[])import(DefaultFontName);

SDL_Surface* loadSurface(string filename)
{
	if(filename == DefaultFontName)
	{
		log.writeln("Loading default font image.");
		auto rwops = SDL_RWFromConstMem(_defaultFont.ptr, _defaultFont.length);
		if(rwops)
		{
			auto surface = IMG_Load_RW(rwops, 1);
			if(surface) return surface;
		}
		throw new Exception("Failed to load default font image: " ~ to!string(SDL_GetError()));
	}
	else
	{
		auto path = format("%s/data/gfx/%s", appDirectory, filename);
		log.writefln("Loading font image %s.", path);
		auto surface = IMG_Load(path.toStringz());
		if(surface) return surface;
		throw new Exception(format("Failed to load font image [%s]: %s", path, to!string(SDL_GetError())));
	}
}


A very important point in using this feature is that it won't compile unless you tell the compiler via a command line switch where it should look for import data. This is a security feature that, IIRC, was implemented to prevent things like remotely accessing a compiler to compile arbitrary data on that system. So you pass the root path with the command line switch -J (i.e. -Jpath). Any file you import via the import expression will be relative to that path.

This is one of those small features of D that mesh with the whole to make it such an enjoyable language to use.


Binding D to C Part Two

Posted by , in Binding to C, D 30 January 2012 - - - - - - · 3,953 views

This is part two of a series on creating bindings to C libraries for the D programming language.

In part one, I discussed the difference between dynamic and static bindings and some of the considerations to take into account when deciding which way to go. Here in part two, I'm going to talk about an important aspect of function declarations: linkage attributes.

When binding to C, it is critical to know which calling convention is used by the C library you are binding. In my experience, the large majority of C libraries use the cdecl calling convention across each platform. Modern Windows system libraries use the stdcall calling convention (older libraries used the pascal convention). See this page on x86 calling conventions if you want to know the differences.

D provides a storage class, extern, that does two things when used with a function. It tells the compiler that the given function is not stored in the current module and it specifies a calling convention via a linkage attribute. The D documentation lists all of the supported linkage attributes, but for C bindings the three you will be working with most are C, Windows and System.

Although I'm not going to specifically talk about static bindings in this post, the following examples use function declarations as you would in a static binding. For dynamic bindings, you'll use function pointers instead.

The C attribute is used on functions that have the cdecl calling convention. If no calling convention is specified in the C headers, it's safe to assume that the default convention is cdecl. There's a minor caveat in that some compilers allow the default calling convention to be changed via the command line. This isn't an issue in practice, but it's a possibility you should be aware of if you don't have control over how the C library is compiled.

// In C
extern void someCFunction(void);

// In D
extern(C) void someCFunction();

The Windows attribute is used on functions that have the stdcall calling convention. In the C headers, this means the function is prefixed with something like __stdcall, or a variation thereof depending on the compiler. Often, this is hidden behind a define. For example, the Windows headers use WINAPI, APIENTRY, and PASCAL. Some third party libraries will use these same defines or create their own.

// In C
#define WINAPI __stdcall
extern WINAPI someWin32Function(void);

// In D
extern(Windows) someWin32Function();

The System attribute (extern(System)) is useful when binding to libraries, like OpenGL, that use the stdcall convention on Windows, but cdecl on other systems. On Windows, the compiler sees it as extern(Windows), but on other systems as extern( C ). The difference is always hidden behind a define on the C side.

// In C
#ifdef _WIN32
#include <windows.h>
#define MYAPI WINAPI
#else
#define MYAPI
#endif

extern MYAPI void someFunc(void);

// In D
extern(System) void someFunc();

The examples above are just examples. In practice, there are a variety of techniques used to decorate function declarations with a calling convention. It's important to examine the headers thoroughly and make no assumptions about what a particular define actually translates to.

One more useful detail to note is that when implementing function declarations on the D side, you do not need to prefix each one with an extern attribute. You can use an attribute block like so:

extern(C)
{
	void functionOne();
	double functionTwo();
}

// Or, if you prefer
extern(C):
	void functionOne();
	void functionTwo();

In part three, I'll talk a bit about builtin types and how they translate between C and D. After that, we'll be ready to look at complete function declarations and how they differ between static and dynamic bindings.


Binding D to C

Posted by , in Binding to C, D, Derelict 08 January 2012 - * * * * * · 6,661 views

This is part one of a series on creating bindings to C libraries for the D programming language.

This is a topic that has become near and dear to my heart. Derelict is the first, and only, open source project I've ever maintained. It's not a complicated thing. There's very little actual original code outside of the Utility package (with the exception of some bookkeeping for the OpenGL binding). The majority of the project is a bunch of function and type declarations. Maintaining it has, overall, been relatively painless. And it has brought me a fair amount of experience in getting D and C to cooperate.

As the D community continues to grow, so does the amount of interest in bindings to C libraries. Recently, a project called Deimos was started over at github to collate a variety of bindings to C libraries. There are several bindings there already, and I'm sure it will grow. People creating D bindings for the first time will, usually, have no trouble. It's a straightforward process. But there are certainly some pitfalls along the way. In this post, I want to highlight some of the basic issues to be aware of. For the sake of clarity, I'm going to ignore D1 (for a straight-up "static" binding, the differences are minor, but they do exist.

The first thing to consider is what sort of binding you want, static or dynamic. By static, I mean a binding that allows you to link with C libraries or object files directly. By dynamic, I mean a binding that does not allow linking, but instead loads a shared library (DLL/so/dylib/framework) at runtime. Derelict is an example of the latter; most (if not all) of the bindings in the Deimos repository the former. There are tradeoffs to consider.

D understands the C ABI, so it can link with C object files and libraries just fine, as long as the D compiler understands the object format itself. Therein lies the rub. On Posix systems, this isn't going to be an issue. DMD (and of course, GDC and, I assume, LDC) uses the GCC toolchain on Posix systems. So getting C and D to link and play nicely together isn't much of a hassle. On Windows, though, it's a different world entirely.

On Windows, we have a variety of object file formats to contend with: COFF, OMF, ELF. DMD, which uses an ancient linker called Optlink, outputs OMF objects. GDC, which uses the MingW backend on Windows, outputs ELF objects. I haven't investigated LDC yet, but it uses whichever backend LLVM is configured to use. Meanwhile, the compiler that ships with Visual Studio outputs objects in the COFF format. What a mess!

This situation will improve in the future, but for now it is what it is. And that means when you make a C binding, you have to decide up front whether you want to deal with the mess or ignore it completely. If you want to ignore it, then a dynamic binding is the way to go. Generally, when you manually load DLLs, it doesn't matter what format they were compiled in, since the only interaction between your app and the DLL happens in memory. But if you use a static binding, the object file format determines whether or not the app will link. If the linker can't read the format, you get no executable. That means you have to either compile the C library you are binding with a compiler that outputs a format your D linker understands, use a conversion tool to convert the libraries into the proper format, or use a tool to extract a link library from a DLL. Will you ship the libraries with your binding, in multiple formats for the different compilers? Or will you push it off on the users to obtain the C libraries themselves? I've seen both approaches.

Whichever way you decide to go really doesn't matter. In my mind, the only drawback to dynamic bindings is that you can't choose to have a statically linked program. I've heard people complain about "startup overhead", but if there is any it's negligble and I've never seen it (you can try it with Derelict -- make an app using DerelictGL/SDL/SDLImage/SDLMixer/SDLNet/SDLttf and see what kind of overhead you get at startup). The only drawback to static bindings is the object file mess. But with a little initial work upfront, it can be minimzed for users so that it, too, is negligible.

Once you decide between static and dynamic, you aren't quite ready to roll up your sleeves and start implementing the binding. First, you have to decide how to create the binding. Doing it manually is a lot of work. Trust me! That's what I do for all of the bindings in Derelict. Once you develop a systematic method, it goes much more quickly. But it is still drastically more time consuming than using an automated approach. To that end, I know people have used SWIG and a tool called htod. VisualD now has an integrated C++-to-D converter which could probably do it as well. I've never used any of them (which is really incredible when I think about it, given how precious little time I usually have), so I can't comment on the pros and cons one way or another. But I do know that any automated output is going to require some massaging. There are a number of corner cases that make an automated one-for-one translation extremely difficult to get right. So regardless of your approach, if you don't want your binding to blow up on you down the road, you absolutely need to understand exactly how to translate D to C. And that's where the real fun begins.

That's going to have to wait for another post, though. It's Sunday evening here and I've got things to do. In part two, I'll talk about function declarations. I think they're easier to cover than types, which I'll save for a third post. Until then, Happy New Year!


Dolce and Da5teroids

Posted by , in D, Dolce 18 December 2011 - - - - - - · 816 views
D, Dolce, Derelict
So I've finally gotten started on some game code. In order to see if Dolce is actually useful or a waste of time, I decided to start by porting the A5teroids demo that ships with the Allegro 5 package. Here's what I've learned so far.

First, the whole idea of Dolce as a framework on top of Allegro to allow an absolute minimum amount of startup code for a game was a good idea on paper. All of the initialization details were tucked away behind a single method call. In practice, it's rather silly. I was happy with the little example I gave some time ago. But, the number of options that need configuring in order to make it useful actually make it more complex than it would be if I didn't hide all of the initialization details. So, now I don't. Now, you initialize the modules you need as you need them. It's cleaner, still takes just a few lines to get to the good stuff, and makes more sense.

Second, I've forgotten how fun it is to make a game. Once I dug into the A5teroids source, I decided it's not something I really want to port. It appears to have been cobbled together with little thought or consistency. So I decided to mostly start from scratch. I'm using the same resources and related data, but that's it. I've not spent a whole lot of time on it so far, but I'm having a blast. Along the way, I've been tweaking Dolce to make it more useful. I've also begun to expand it a bit and start implementing some utility modules.

Finally, as a result of moving forward on all of this I've hit on some aspects of D that would make useful posts here. I've been rather quiet here for a while, so it will be nice to have something to say again.

I anticipate that over the next three or four weeks I'll be able to get a lot more work done in D-Land than I have up until now. Not only do I need to refine Dolce and prepare it for public consumption, I also need to get busy putting the finishing touches on Derelict 2 (which I've also finally decided to move to github, thanks to a bit of encouragement). Fun times ahead.


On My Job, and Some Big D News

Posted by , in D, Dolce, Me 09 October 2011 - - - - - - · 816 views
Dolce, D, Me
Dolce is still very much alive, just getting little attention while I wrap up the second semester at the university. For anyone interested, I'm teaching in a special program where a local university here in Seoul is partnered with a university in America. The students do two semesters here in Korea before moving off to the States for three years. We started the second semester two months early this year in order to give the students more time between the end of the semester and their departure to America next January. Last year's students, the first to participate in the program, only had two weeks.

In addition to my Debate classes, I'm teaching a special English Fluency course this semester for the handful of students who have achieved their target TOEFL scores. Coupled with all of the private classes I teach six days a week, I don't have enough time to do everything I want to do. When my schedule gets full like this (which happens a couple of times a year), my D projects tend to suffer for it. I find it mentally tough to get any coding done if I can't work for long stretches at a time. I feel so unmotivated when it comes to short bursts at the keyboard.

Still, I've taken the time to do some nipping around the Dolce source here and there. Nothing major to report on that front yet. The semester ends for me in two more weeks, and I'm not giving my students a final exam this time around. So I'll find some nice gaps in my schedule soon that I'll use to give some attention to both Dolce and Derelict.

In the meantime, I'll leave you with this: a D compiler is now very close to being included in the GCC project. You might also be interested in checking out the related Reddit thread. That's great news all around. And I really need to get around to adding it to my D news blog.


Dolce Refinements

Posted by , in D, Dolce 04 September 2011 - - - - - - · 697 views
Dolce, D
In my last post, I showed the minimal amount of code needed to get something up and running with Dolce. And while it's a really small amount of code, something kept bugging me about the implementation. It just wasn't "D" enough.

Over the years, the lion's share of my programming experience has been with C and Java. When working with either language, I naturally, and effortlessly, use appropriate design patterns. In other words, I design "to the language." Maybe "design pattern" is the wrong noun here, but the point is that my code structure differs based on the capabilities and features of each language. And I can switch between them seamlessly, thanks to the years of doodling around I've got under my belt. My C code is "C", and my Java code is "Java". Unfortunately, I haven't quite gotten that line of clarity yet in D.

In D, it's possible to structure things like I do in C. It's also possible to structure things like I do in Java. That's why I've refactored Dolce so many times already. It's mentally distracting having both styles in the same code base. Unfortunately, I've found that sticking to one of the two styles is a source of annoyance, as I can't get over the feeling that if I'm writing Java or C in D, then why am I using D?

The approach demonstrated in my last post, where you subclass a Game class and override certain methods as needed, was obviously very Java-ish. And I didn't like the fact that I was requiring any methods to be implemented at all, even if there were only two of them. Finally, it seemed silly to me that if you want to avoid using the Game class, your only option was to handle all the boilerplate yourself. I knew I could do better than that.

So, I went back to the drawing board and came up with this.

import dolce.game.framework;

class MyGame
{	
}

int main(string[] args)
{
	Framework.start(new MyGame, "MyGame");
	return 0;
}

This will create a window that closes if the escape key or close button are pressed. Pretty useless in and of itself, but the point is that there are no longer any specific methods required and you don't need to subclass anything. In fact, you don't need a class at all. Change MyGame to a struct instead, and it will work fine (and you wouldn't need to 'new' it either, though you could if you wanted to). Even better, you can pick and choose the methods you want to implement.

Framework is a static class with a templated start method that looks like this:

static void start(T)(T game, string appname, string orgname = null)
{
	init(appname, orgname);
			
	static if(hasMember!(T, "init")) game.init();
			
	_running = true;
	al_start_timer(_frameTimer);
			
	while(_running)
	{
		// Pump all events.
		pumpEvents();
				
		// If it's time to update, do it.
		if(_update)
		{
			static if(hasMember!(T, "update"))  game.update();
			_update = false;
		}
				
		static if(hasMember!(T, "render")) game.render();
	}
			
	static if(hasMember!(T, "term")) game.term();
	term();
}

The thing I want to focus on is the hasMember template. It's implemented in the standard library module std.traits. It is not a function template. It takes a type list and no parameter list. The template itself contains one field, a bool value called hasMember. This calls for a brief detour to talk about templates in D.

Let's say I want to define a template that acts as a boolean value. Let's call it "isTrue".

template isTrue()
{
	enum bool val = true;
}

Here, the template has an empty type list and no parameter list. Internally, there is no function declared, only a single member, val (so it's not a function template). Notice that val is declared as an enum. In D2, single-member, anonymous enums are known as manifest constants. They are not actual variables, so cannot be used as lvalues or have their addresses taken. Essentially, every time the template is instantiated, that call to the template is replaced by the value of the enum.

Notice also that the template and the member have different names. This means that you have to explicitly type the member name when you instantiate the template. Also remember that D's template instantiation syntax is templateName!(). So, given that, this is how you would use this template:

void main()
{
	assert(isTrue!().val);
}

Sometimes you may want a template to have multiple members, but the large majority of templates you write are going to have only one. In that case, D let's you take some shortcuts if the member name is the same as the template name. In this case, we can eliminate the .val part when instantiating the template.

template isTrue()
{
	enum bool isTrue = true;
}

void main()
{
	assert(isTrue!());
}

std.traits.hasMember uses this approach. But it also takes two args to its type list -- one is the Type that it is to operate on, and the other is a string that will be used to look up a member method or variable of that type at compile time (this is accomplished via D's compile time reflection capabilities).

You may be wondering how a string value could be part of the type list, rather than the parameter list. The type list isn't just for types. You can also pass any sort of symbol that can be known at compile time. Let's change our isTrue example now to demonstrate this. The new job of the template is to evaluate to true if and only if a given string is equal to the string "true".

template isTrue(string s)
{
	enum bool isTrue = "true" == s;
}

void main()
{
	assert(isTrue!("true"));
	assert(isTrue!("bugaboo"));
}

Run this and the first assert will pass. The second will blow up. The string 's' is never used at runtime here. It's a compile-time-only symbol. When the template is instantiated, the compiler will run the test ("true" == s) and set the value of isTrue to the result. The asserts are basically being rewritten as:

assert(true);
assert(false);

By using hasMember the way I do in the Framework.start method shown above, no calls will be made to any methods not present in the given type. They simply won't be compiled in to the executable. If the method is implemented, a call to it will be compiled in. This means anyone using Framework.start can implement any combination of init, term, update and render methods.

One more thing to point out. Let's look at the minimal example again.

import dolce.game.framework;

class MyGame
{	
}

int main(string[] args)
{
	Framework.start(new MyGame, "MyGame");
	return 0;
}

According to the rules for instantiating templates, the call to Framework.start should look like this:

Framework.start!(MyGame)(new MyGame, "MyGame");

Again, the compiler is letting me take a shortcut. Because I only have one type in the typelist, I can omit the typelist and the ! when I instantiate the template. The compiler has all the information it needs to infer the type, so there's no need for me to be verbose about it.

With the new implementation, I managed to cut out several lines of code from the framework (previously 'game') module. And though I haven't implemented it yet, the door is now open to use Framework for handling the boilerplate if you want to use free functions instead of a class or struct. This is more what I would call "D style" than the first pass was.

Head on over to d-programming-language.org for more info on templates and the std.traits module.


Dolce and Overriding Methods in D

Posted by , in D, Dolce 21 August 2011 - - - - - - · 759 views
D, Dolce
I'm making very slow progress on Dolce, but progress nonetheless. I managed to grab a couple of hours today to refactor event handling and to simplify the framework interface.

In my initial implementation, it was necessary when making a game with Dolce to make all of the initialization and termination calls yourself. All of these calls are found in the different modules of the core package. They wrap a lot of Derelict and Allegro setup/cleanup in a way that is configurable, providing sensible defaults where required. But, while it's a good deal less boilerplate than you would otherwise need to type, it could be improved.

So, now, to start implementing a game with Dolce, the minimal amount of code you need is this:

module mygame.main;

import dolce.game.game;

class MyGame : Game
{
	protected override
	{
		string name()
		{
			return "MyGame";
		}
		
		void frame()
		{
			
		}
	}
}

int main(string[] args)
{
	Game.start(new MyGame);
	return 0;
}

Add your per-frame code in the frame method, and away you go. Both name and frame are abstract methods in the Game class, so they are the only two methods that must be overridden. I may yet rework it to eliminate the frame method and have a pair of render/update methods instead (haven't decided where or how to handle timing yet). But the point is, there's very little to do just to display something on screen. Of course, there are several other methods that can be overridden for game-specific init/cleanup, event handling, and more. But as is, this will call the frame method as fast as possible and has default handling for the escape key and window close button. And now this is starting to look like what I had envisioned in the beginning.

It's also possible to avoid the Game.start method and manage the life cycle yourself:

int main(string[] args)
{
	auto game = new MyGame;
	scope(exit) game.term();
	game.init();
	game.run();
	return 0;
}

Or, you can ignore the game module entirely and use the core package modules directly. Your choice.

The real point of this post, though, was a chance to talk about how D handles method overriding. Notice the override keyword in the first code block above. This is not mandatory when overriding, but it's a good idea to use it. DMD will spit out a warning if you don't. What it's good for is to protect against the case when the superclass changes. Imagine that you override a method from the Game class, but in the future that method is removed or renamed. By using override, the compiler will let you know the next time you compile that your method isn't actually overriding anything. Otherwise, it would be creating a new method in your derived class that doesn't override anything and you might never be the wiser until you get a funky bug in your app. So when writing D code, using override is a good habit to pick up.


D Structs vs Classes and a Simple Template Example

Posted by , in D, Dolce 02 August 2011 - - - - - - · 1,631 views

D shares a lot of similarities with C++ and Java, but a lot of the sameness is just a bit different. One of the first places new users see this is in the handling of structs and classes.

D's classes have more in common with those of Java than C++. For starters, they're reference types. Whenever you need an instance of a class, you new it and it is allocated on the heap (though scoped stack allocation is possible via a standard library template). Structs, on the other hand, are value types. But, you can create pointers to them, allocate them on the heap with new, or pass them by reference to a function that takes ref parameters. Another difference between the two is that classes have a vtable and can be extended. Structs, however, have no vtable and can not be extended. That also applies to the Java-esque interfaces in D -- classes can implement them, structs cannot.

Because of the differences between the two, there are certainly some design implications that need to be considered before implementing an object. But I'll talk about that another day. For now, I just wanted to give a little background before getting to an example illustrating the primary motivation for this particular post.

While working on Dolce, I thought it would be a good idea to wrap Allegro's ALLEGRO_CONFIG objects, simply because working with a raw, string-heavy C API in D can be a bit tedious. You have to convert D strings to C strings and vice versa. In this particular case, you also have to convert from string values to integers, booleans, and so on, since Allegro only returns raw C strings.

So what I wanted was something that allowed me to create and load configs, then set and fetch values of the standard built-in types. Rather than implementing a separate get/set method for each type, I chose to use templates. And in this case, I didn't want the whole object to be templated, just the methods that get and set values.

Initially, I implemented it as a class, but in the rewrite of Dolce I pulled the load,create and unload methods out and made them free functions. I also realized that this is a perfect candidate for a struct. The reason is that it contains only one member, a pointer to an ALLEGRO_CONFIG. This means I can pass it around by value without care, as it's only the size of a pointer. Here's the implementation:

struct Config
{
	private
	{
		ALLEGRO_CONFIG* _config;
	}
	
	ALLEGRO_CONFIG* allegroConfig() @property
	{
		return _config;
	}
	
	bool loaded() @property
	{
		return (_config !is null);
	}
	
	T get(T)(string section, string key, T defval)
	{
		if(!loaded)
			return defval;
		
		auto str = al_get_config_value(_config, toStringz(section), toStringz(key));
		if(str is null)
			return defval;
		
		// std.conv doesn't seem to want to convert char* values to numeric values.
		string s = to!string(str);
		static if( is(T == string) )
			return s;
		else
			return to!T(s);
	}
	
	void set(T)(string section, string key, T val)
	{
		if(!loaded)
			return;
		
		static if( is(T == string) )
			auto str = val;
		else
			auto str = to!string(val);
		
		al_set_config_value(_config, toStringz(section), toStringz(key), toStringz(str));
	}
}

You'll notice that the _config field is private. I don't normally make struct fields private, as the structs I implement are usually intended to be manipulated directly. But in this case I thought it prudent to hide the pointer away. I still provide access through the allegroConfig property (and I'll discuss properties another day) in case it's really needed.

So you may also be wondering how _config is ever set if it's private and there's nothing in the struct itself that sets the field. The answer lies here:

Config createConfig()
{
	return Config(al_create_config());
}

This is something that frequently trips up D newbies coming from other languages. What's going on is that the create function and the Config implementation are in the same module. You can think of modules as another level of encapsulation. And, for those who are steeped in C++ vernacular, you can think of modules as friends of every class and struct implemented within them. In other words, private class/struct members/methods are all visible within the same module. If you ever get to know D at all, you'll likely find this to be a very convenient feature.

Another thing that might jump out at you is the static if. This is one way to conditionally generate code at compile time. You'll frequently see it used in templates, though its use is not restricted to templates. Here, I'm testing if the type T is a string or not. In the get method, the value returned from Allegro is a char*, so it is converted to a D string. If the type of T is string, then there's no need for any further conversion and the D string can be returned. If not, the D string must be converted to the appropriate type (int, bool, long or whatever). Similarly, in the set method, a char* needs to be passed to Allegro, so any nonstring values are first converted to a D string. But if T is string, that step isn't necessary.

And now to the templates. D's template syntax is clean and extremely powerful. This example demonstrates the cleanliness part at least.

T get(T)(string section, string key, T defval)

If you've ever used C++ templates, it should be clear what is going on here. The type to be accepted is declared in the first pair of parentheses, the parameter list in the second pair. And in this case, a value of the specified type is returned.

Now, to use it:

auto config = createConfig();
auto i = config.get!int("Video", "Width", 800);
auto b = config.get!bool("Video", "Fullscreen", false);

Here, I've used the auto keyword for each variable. The compiler will infer the Config, int, and bool types for me. As for the template instantiations, notice the exclamation point used between the method name and the type. That's what you use to instantiate a template. Technically, I should be wrapping the type of the template in parentheses, like this:

auto i = config.get!(int)("Video", "Width", 800);

If you have a template with more than one type in the type list, then you have to use the parens. But if there is only one type, the compiler lets you get away with dropping them. For singly-typed templates, that has become a standard idiom in D.

If you decide to give D a spin and come from a C++ or Java background, I hope this post helps keep you from any initial confusion that might arise when you find that things aren't quite the same as you're used to.

You can learn more about D's structs, classes and templates at d-programming-language.org.






August 2016 »

S M T W T F S
 123456
78910111213
14151617181920
21222324 25 2627
28293031   

Recent Entries



PARTNERS