4 Hugues Ross - Blog: 2016
Hugues Ross

12/31/16

2016 End of Year Wrap-up

Quick Notice: I've made a form to try and see what viewers want out of this blog. There's a link to it below, but just in case you're in a hurry you can click here to get to it as well.

It has been quite a year!

I haven't been as productive with personal projects as in years past, but many things happened ion my life. The biggest two events were the completion of my College Capstone (and my subsequent graduation from Champlain College), and moving to Quebec for a new job. I'm happy with how life is going but these two events disrupted things quite a bit, and I've only just started falling back into a normal routine.

The Year's Bounty

So, what did I accomplish this year? I managed to pull off a few things, so let's review them:

DFGame

This year, I finally put the DFEngine project to rest, and tried a new approach with DFGame. For the most part, I think it has been a success! DFEngine's two greatest sins, in my opinion, were being difficult for new projects and being woefully inflexible, both of which are fixed by its successor.

Of course, nothing is without its faults. As of a few days ago, I started refactoring/rewriting parts of DFGame. I don't plan on throwing everything away, but I'm hoping to make the codebase cleaner and better commented, while also filling much-needed holes in the API. My projects are still awaiting an official OK from on high though, so I'll hold off on discussing the changes until later.

Singularity

The Singularity rewrite is still going. I haven't been working too hard on it recently, but it certainly feels more polished than before. With any luck, it'll be wrapped up and released some time in the next 6 months.

Growgue

Like the previous two years, I gave 7drl a shot. However, this year's entry didn't really go so well. I finished the game, but it isn't very fun to play. Honestly, I think my head just wasn't in the game this year. Here's to hoping that next year goes better!

At least the walls look ok...

Looking Towards Next Year

So, this year wasn't too impressive. I think it was just a fluke, though. I wasn't programming much when the job started, but now I'm slowly getting back to my old ways and I think the restarted roguelike series is going to help as well.

I have a few goals for next year: Release Singularity 0.3, finish the DFGame rework and get started on a larger game project. However, the biggest change that I want to see is an improvement to this blog's quality.

I want to see the content of this blog evolve from the old "Update!" posts into something more interesting, informative, and directed. To that end, I've made a form to let you provide your input. I want to know what you'd like to see out of a blog like mine, and I'll use that feedback going forward.

To access the form, click here. This is very important, so please take the few minutes out of your day to fill it out.

12/19/16

Let's Make a Roguelike, for the 3rd Time

Hello again! Last week, I promised the return of my roguelike tutorial. Today, I'm making good on that promise. Sort of.

I've pushed out a new update to the site and blog, which the observant among you may have noticed already. In addition to making the navigation bar a little bit nicer looking, I've also reorganized the pages a bit. The portfolio section is completely gone, because it never had any content and I don't really need one right now. To fill the space, I've split the games page off of the software page, and added a section for tutorials. The overall theming of the site has gotten some tweaks, and if you click the logo in the upper left-hand corner, then you'll see a very rough work-in-progress landing page. I could have withheld it, but I think it looks better than the word 'Placeholder'.

The tutorial section is also a bit of a work-in-progress. I'm planning on remaking the ring segment collision tutorial that I did a while back, but that could still be a while from now. i also need to play with the theme some more to make it look more polished.

The Tutorial

I've put up the first entry of the new-and-improved roguelike tutorial, a nice little introductory page. You can read it here. It borrows a couple sections from the old part 1, but most of the content is new. It's probably not the most exciting start for a new series but I expect the new tutorial to have a slightly faster pace overall, so hopefully that will offset the slow start.

That's all for the moment! You can expect the first numbered chapter of the tutorial to be up on January 2nd, and more will come every other Monday after that. This means that I might have the beginnings of a schedule! I'll be posting here whenever I put up a new part, and you can expect the other regular posts to appear once in a while, as they typically do. I'm still waiting for my projects to get an official OK from on high, so in the meantime please enjoy these updated tutorial chapters.

12/11/16

Update: New Stuff Coming Up!

It's been almost 3 months since the last substantial update. My last post explained some of it, but I imagine you might still like to see this place become a little more active. Well, I think it's time for a small announcement: I will soon be restarting my roguelike tutorial!

The tutorial will be moving to its own dedicated section of the site, and I'll also be releasing a bunch of small tweaks and improvements to the site's design. The current plan is to start things up again on December 19th, with new updates coming every other Monday after that.

Like last time, I'm going to be starting over from the beginning. You may find this frustrating if you were following along before, but I think it's a good decision because I've learned and improved a lot in the past year or so. I've taken the time to look over my old work, and I think that there are many things that could use improving. It won't be a full rewrite, but I'll be making tons of changes nonetheless. In the meantime, here's a screenshot to look at:
Click the image to view it in full size
Nothing here is final, and the text is unedited. However, I think it still does a good job showing off some of the changes. I'll be sure to give a full rundown when the time comes.

11/9/16

Quick Life Update Post

Update:  I'm more or less all set, and I'll be back to posting regularly soon enough, but I'm leaving the rest of the post intact for those curious what I've been up to lately. I might make a proper update post about this later, at which point this will be deleted.

"Hugues, you haven't updated in nearly 2 months! Where's my fix?!"

No-one has said this, but I feel an inexplicable urge to explain regardless. You see, I'm employed. Not only that, I'm videogames employed.

If you're not too sure what that actually means, what I'm getting at is that I have a lot of red tape to deal with now. As of mid-October, I'm working as a professional game programmer. Now, while I can probably do some kind of work (the company I work for seems to be pretty cool about these sorts of things), the sheer quantity and scale of my side projects means that I don't really want to touch them or this blog without proper permission.

I still have every intent to continue this blog and hopefully get a more regular schedule going again. With any luck, I'll be able to fully resolve things within the next few weeks and then I can go back to normal development, but in the mean time just sit tight and know that I'm not dead or anything. pleasedon'tunsubscribe

Cheers!

9/28/16

Revamped Games Page

Last week, I discreetly pushed a new update to my website. I've completely redone the games page, improving the look and adding a few titles that weren't there before along the way.

I started work on a new site last year, but got too bogged down with Capstone to finish. Then, I got a job almost immediately after graduation (In fact, I'm starting soon. I'll make a quick post about it once that happens.). As a result, I haven't really had a time where I felt that improving my site and building a proper portfolio was really necessary, and the site has remained half-finished. Hopefully, I'll be fixing that problem in the coming weeks.

I decided to start with the games page for a few reasons. The biggest reason was that it was a horrible, disgusting mess of boxes, but I also felt that the games page was one of the most important parts of the site. While I make software and do other things, I am primarily seen by my peers as a game developer. Furthermore, the vast majority of the work that I've shared is game-related in some form.

So, what's new?
  • I've moved from the previous design (boxes with a small icon and some text/links) to a cleaner, more responsive design with tiles representing each game.
  •  Game information is now hidden; clicking a tile brings up  a popup with a description and links.
  • I've fixed the previously scrunched-up icons.
  • I've added controls to most game detail popups.
  • I've greatly fleshed-out each description. I would highly recommend reading through them all, as I've added some fun never-shared-before tidbits.
  • I've added The Last Light, Core Breaker, Cloudy Climb, and Growgue to the page.
That list of changes kept me busy for about a week, but the result was well worth it. I recommend taking a look at the new page here.

8/30/16

Singularity: Multi-threading for dummies

Finally, I'm back for another update. Sorry about the wait, but I think this one will be nice and informative.

I've been working on getting Singularity's new version ready for use, and it's now almost at a point where I can use it as my daily driver. Today, I'm going to discuss how I've changed Singularity to feel faster and smoother by moving most of the work it does to separate threads.

Disclaimer:

the following post is meant as a simple (ish) introduction to event-driven applications and multi-threading for non-programmers. This is not a comprehensive guide, and I smooth over many details. It's certainly not a good introduction for developers looking to learn multi-threading, so please keep that in mind while reading this post.

 

The Problem

In the previous version of Singularity, I'd noticed some performance issues. Updates took a fairly long time to run, and even just starting up the application could cause a few seconds of unresponsiveness as it loaded up the initial data. One of my goals for the new version was to eliminate any unresponsiveness, and make everything just a bit faster and smoother.

However, the new version was much, much worse. The initial lag was gone, but updates took much longer and continued to leave the application frozen. Even just scrolling quickly could cause lag!

But why? Let's look deeper...

 

Where Do Lockups Come From?

Let's step back for a moment and discuss unresponsiveness in general. In many older, or poorly-coded applications, some actions can cause the application to freeze temporarily. Nothing will happen when you click on buttons or type, and the display might even display other windows on top of it! See below for an example:

Image courtesy of Wikipedia


If you don't write code, you might find this perplexing, but the reason is quite simple. It all comes back to how an application "flows".

Most modern applications are event-driven. Don't run away, it'll make sense in a moment! They run using a main loop, which is a fancy way to say that the do the same common set of actions over and over again, forever. A simple window that does nothing might look like this:
Note: UI means "user interface". It's the stuff that is shown to the user.
Every time the loop begins, it will do something like this:
  1. Check for input. This could be clicking, moving the mouse, pushing buttons on your keyboard, or anything else that the programmer wants to know about.
  2. When it gets the input that the programmer wants, it will do something immediately. This is why our application is event-driven: It waits for an event to happen, like getting input, then responds to the event.
  3. If it needs to, it redraws itself to the screen. This usually only happens if something has changed, like a switch being flipped or an animation playing.
As you can see, the main loop is fairly simple: Our window waits for something to happen, redraws its contents, then repeats. Even trying to close the window is just another event: If we don't tell it to close, it won't.


So, what happens when we add a cool button to our window? When we click the button, we'll do something. It doesn't really matter what. Let's go back to our flowchart:
Maybe it plays an airhorn sound?
Notice how pushing the button and performing the action happen before the loop repeats? Most code works in a linear fashion: It can only do one thing at a time. Pushing the button stops our application from looking for input or redrawing itself until it's done working.

Next, we'll make our button check 100 sources for updates when pressed. After all, we need our news! Here's what happens:
This could take a while!
This could easily take a few minutes, and the whole time our application can do nothing else. Moving your mouse to another button and clicking will do nothing. And how could it? It's busy updating, and it can't check to see that you clicked until it's done. Even adding a progress bar wont help--It can't draw any changes to the bar until it's done with the updates.

Our users will be furious! How can we solve this problem?

First Pass: Networking

So, that's basic explanation of the problem that was facing Singularity. The updates were taking longer for two reasons: I was making some extra checks to improve the cleanup feature, and I was speeding up my updates in the old version using a method that I'll explain in another post. What I did to help alleviate the problem was create a separate thread for running updates.

What's a Thread?

Remember when I said that most code works in a linear fashion? Every action has to happen in order, as if it was following a line. Or in this case, a thread. And that's exactly what threads are: A thread can be thought of a list of instructions for the computer to follow. A single-threaded application is an application like the one above, that does one thing at a time. A multi-threaded application creates new threads, allowing it to do several things at the same time.

Still following me? They say a picture is worth a thousand words, so let's make our application check for updates in a second thread:
Note the branch after start update, and how the two lines merge back together after running the updates.
When we push our button now, all the main thread (the thread with our main loop) has to do is tell the update thread to start checking. While the update thread does the heavy lifting, our main thread can get input, redraw itself, and act responsive and alive while it works. We win!

However, it's not perfect. As soon as the updates finish loading, the window freezes again. It has to process and save the new updates to our database, and we can't tell our update thread to do it. I have several reasons for this, but to keep things simple I'm not going to get into it. It suffices to say that we should avoid having our update loader save our updates.

How do we get around this issue?

 

Second Pass: Database IO

 If you've been observant, you may have noticed that our update thread is also a loop. After sending the updates back to the main thread, it goes back to waiting. We can do something similar with our database too: By making it wait for requests (input), we can have it react to requests that we make.

Just like the update thread, we can make a database thread and ask it to save our updates. Now our main thread will have almost nothing keeping it from its important duty:
Note how the database sends nothing back. It doesn't need to since it's just saving, but we could always return something like the number of updates saved.

One advantage of this design is that our database can take any sort of request that we make, and all database interactions no longer stop our application from running smoothly.

 

The Results

This is an excellent start, although it doesn't solve all of our problems. Our application should never freeze or stutter anymore, but it's still slow as molasses when running updates. We also won't be able to use our database while saving updates, so any actions that involve the database will simply be delayed until the save is done. Our users won't think the application is broken, but they'll soon learn to hate that little progress bar in the corner.

To fix this, we can add more threads for handling more updates at a time, or give database requests priority levels (both of which I've done, although the priorities are still a work-in-progress), both of which will make things feel a bit faster and smoother. Ultimately, there are limits to how much you can optimize an application, but there's a lot that can be done to make things feel silky-smooth.

7/13/16

Listening to Your Javascript

It's been a while, but I haven't been idle. I've made a great amount of progress on Singularity, and I've finally discovered a secret that has eluded me for years!

The Problem

These stories always have to start with a problem. In this case, the problem was a seemingly simple one:

"When the user interacts with Singularity's WebKitGTK viewport, how do I make the app react to it?"

This used to be really easy, back in the days of Webkit 1. However, when Webkit2 changed the API and moved some functionality to it's web extension API, Javascript support followed suit. For a long time, the only solution was to simply create an 'extension' that used some form of IPC to communicate with the main app, but I didn't want to do that in Singularity. Instead, I used a crude hack by encoding messages in URL requests.

A Tentative Solution

Needless to say, this solution is slow and terrible, but I've found a better answer. At some point since my work on Singularity started, WebKit introduced the UserContentManager, which can apply custom CSS and Javascript to web pages. This is a really awesome feature that I plan on using in future projects, but it also provides me with a new tool, a signal for handling certain Javascript calls. According to valadoc.org:

public signal void script_message_received (JavascriptResult js_result)
"This signal is emitted when JavaScript in a web view calls
window.webkit.messageHandlers.name.postMessage()
after registering name using register_script_message_handler"

In other words, it lets you set up a callback that is called whenever a script calls a certain function, sending arbitrary data from the web page to the application displaying it. This is a really powerful feature.

So powerful, in fact, that you can't actually use it in Vala.

What Gives?

As it turns out, Vala's JavascriptResult class has no useful functions or properties. I'm not entirely certain why, given the solution that I'm about to provide.

While WebKitGTK's JavascriptResult does contain the necessary functions, no Vala bindings exist for them. Instead, you need to access them from C and return whatever result your app is expecting. This seems really odd, and I hope I don't have to find out the hard way later on, but for now I'm feeling pretty good about this.

I'll be posting an update with a more thorough rundown of my work on Singularity soon.

6/7/16

DFGame Summer Progress: More Graphics!

Time for my first summer post. I haven't talked about dfgame's improvements since my second three-week project a few months ago.I've been making some decent progress, so it's time for another update blog post. Here are some of the highlights:

Data Structures

One of the biggest things that I miss from C++ is STL, the Standard Template Library. It may not be the fastest or most reliable thing on the planet, but it still provides basic structures for storing data that make my life a tad easier. For better or worse, C has none of that. I could probably seek out a library to provide me with some basic data structures, but I figured it would be good practice to roll my own.

The first one that I built was an arraylist (also known in some parts as a vector). It's a fairly simple structure that more or less serves as a self-resizing array. When I was making my demos for Consol Programming, I noticed that I was making arrays that could grow on their own over and over. Since it's a common need, I decided to just add it to dfgame.

I recently also made a self-balancing binary search tree. Trees don't get a whole lot of love, but they do provide a relatively quick way to find values, so I figured it would be good to have an implementation on hand.

Convenience Features

I noticed a number of code bits that kept getting reused during the creation of the dfgame demo, so I also spent some time putting them together into the main library.

I started off by trying to improve the safety of my code a little, with macro wrappers for malloc, calloc, and free. These add extra error checking and logging as well as automatically zeroing pointers when freeing. I also updated my destructors to zero-out pointers via macros as well.

I also added a camera object that combines a transform matrix with a projection matrix to generate a view-projection matrix as needed. Now, I can just tell the camera to move around instead of doing extra math whenever I want to look around in a game.

Meshes, Shaders, and Fonts

Alright, now it's time for the fun stuff. I've made a lot of progress on adding more graphical capabilities to dfgame in the past few months.

I kicked things off with a revamp of how shader programs were handled. Before, there was just a function that compiled shaders, but now shaders are handled by a struct and some functions that allow binding data and retrieving handles. The result is less boilerplate code as well as the potential for more options later on. For instance, I'm planning on tracking uniforms with a hash table, which should make setting values a tad quicker. While I was at it, I also added support for geometry shaders!
My test geometry shader may have had a bug or two...
One obvious feature that dfgame has been missing for a while was loading/rendering actual meshes. I've thrown together a quick-and-dirty OBJ loader, so this issue has now been resolved. Combined with the new shader setup, I can play around with graphics programming much more easily.
The fixed shader
Lastly, I've added some initial support for font loading/text rendering. For the first time in my life, I've finally managed to get TTF fonts to render properly with FreeType. This will be super useful for making any demos/tutorials in the future. I'm currently in the process of creating actual text objects with word wrapping and some other handy features, which will hopefully be working by next week. If you looked at the above images, you might've noticed the Japanese Hiragana character floating to the right of Suzanne. One of the nicest features of my new system is that it has (basic) Unicode support. For now, text objects are going to stick to ASCII only, but all of the necessary groundwork has been laid out, and at least Unicode can still be used for icons and the like.

Next Up

Once text is figured out, I'm going to go back and fill in some holes. There are a few bugs with audio that need to be fixed, and I need to finish the input implementation. After that, I'm probably going to get the html5 version up to speed, while also continuing work on Halberd. I'm also thinking of adding particles somewhere in-between just for the fun of it!

5/16/16

Update: Graduation, and a new approach

Let's get the big news out of the way: On May 14th, I graduated from Champlain College with a Bachelor's Degree in Game Programming!

That's right. This blog was started just before the start of my Freshman year, with the goal of documenting my work throughout my studies. Its purpose is now fulfilled, but I have no plans on stopping anytime soon. I'm going to keep posting as long as I can, so don't worry about me disappearing.

Now that I have my degree, I also have to start considering how to divvy up my time for working on projects. I doubt it'll be very long before I'm working 40 hours a week, so I need to come up with a solution that will last beyond my current 'vacation'.


The Plan

Right now, I'm planning to adopt an Agile-like method of working on my projects. Every week, I'll figure out which tasks from various projects to work on, and then try to get them done that week. For now though, that seems like a bit of a leap from my current carefree work-on-whatever schedule, so I'm going to be taking this transition in steps.

For now, I'll be trying to make a list of several projects every week, and focus on one or two every day. This should give me enough content to make at least one post per week. (No promises, though)

It's likely that you'll also see more non-programming content. I've been meaning to do more with art and audio for a while, but school got in the way time and time again. I'm hoping to practice those skills a bit, and maybe that practice will turn into posts once in a while!

5/7/16

Capstone Update 19: Project Statistics

It's been a few weeks since my last capstone post, and quite a lot has happened! Last week we finished The Last Light and presented it at the senior show, and it got a pretty great reaction all around. Even better, the game got several Let's Plays after we put it up on itch.io, and the overall reaction seems to be pretty good.

By the way, you can download the game here:

(Sadly, it's Windows only right now. I might see if I can put a Linux build together at some point though)

Now that the dust has settled, I thought it might be a good time to go over some statistics from the project. I got a few requests from fellow team members, and also wanted to do some things myself, so here we go:
(Please keep in mind that these numbers are estimates pulled from hastily-constructed git queries. They should be close to the right number, but may not be perfect)

Total Number of Merge Conflicts

When dealing with teams that have more than a couple of members, it's only natural that at some point, merge conflicts are going to happen. This problem becomes even more common when your project consists mostly of binary files that can't be merged normally. We certainly had our fair share with 122 merge conflicts resolved.

Floor_400x400

For some reason, a random unused asset from the UE4 starter content folder, Floor_400x400.uasset, kept getting marked as changed. My team was curious how many times it got 'updated' in git. Apparently, 60 times. That's about once every other day!

Substance Plugin Kill Counter

Unreal really loves the Substance plugin. If your machine has it installed, Unreal has a habit of quietly slipping it into your project when you're not looking. Then, everyone else on your team gets a little popup saying something along the lines of
"This project requires the Substance plugin. Do you want to download it now?"
Naturally, this message is a tad irritating, so we tended to go into the project file and purge the plugin. We did this 34 times, in fact. That number actually seems remarkably low, but I think it's because we didn't always remove the plugin immediately if we were busy, so sometimes it would stick around for a while.

Total Number of Binary Updates

Have you ever an artist to go compile some code? It's not pretty. Although Unreal makes compiles pretty easy, we programmers made a point to include the compiled binaries in git so that our fellow team members could spend less time compiling and more time developing. This happened 96 times.


That's it, but hang on to your seats, boys and girls! It's time for.....

Uncle Huey's Repo Analysis Awards

The "Biggest Git" Award for Total Commits

 Let's start with a simple one: Who made the most commits overall? It was a close race, but the winner is:
Chris Johnson, with 292 commits
Second place is Vincent Loignon, with 288 commits. 
Simple, right? On to the next category!



The "Man of Mystery" Award for Commits under an Alias

Not everyone keeps to a single name, especially when jumping from computer to computer. This award is for the person who made the most commits under a non-name:
Jesse McKinley, with 122 commits listed as 'Dekeche'
Second place is Hugues Ross (me), with 121 commits listed as 'DF458'
Looks like it's another close one. Next!



The "Fashionably Late" Award for Latest First Commit

You know what they say: The early bird is a total loser.  This award goes to the person who was the last to start making commits to the repo. Who won? Why, it was:
Paul Scardera, who first committed on April 13th
Second place is Kyle Patterson, who began on April 8th
I think it's important to mention that these awards are meant to be fun, and that this isn't any sort of condemnation. Paul and Kyle are both producers, so they only joined in with direct development at the end to help with 11th-hour grunt work. They've been super helpful throughout the project, just not with commits.
And speaking of strange awards...



The "Writing is for Losers" Award for Most Commits Without Changing a Single Line of Text

Git keeps track of how many lines of text were added, removed, or changed in text files. This award goes to the developer who made the most commits while maintaining a perfect 0 in all of those categories. Let's hear it for:
Paul Scardera, with 7 commits and 0 lines
Second place is Scott Beecher, with 6 commits and 0 lines
Again, be nice, not everyone's work is represented by commits, yada yada.
Now, time for the final award:



The "Who's That Pokemon" Award for Most Enigmatic Team Member

Among the huddled masses of our Slack channel, there are rumors of a secret developer, spoken of only in hushed tones, working from the shadows. Who are they? Where did they come from? No-one knows for sure. Of course, I'm talking about:
Unknown, with 18 commits
Yeah, so someone probably just forgot to enter their name into git before committing. Still, it's good to have fun with these things, that's what the awards are for!
Actually, I just double-checked and apparently it was me all along (with one commit from vince). Whoops!



Project Development Visualization

All this text is pretty boring. Thankfully, I have a solution to that problem. In addition to all of these stats, I also have a visualization of the project's development, starting from February (Fullscreen viewing is recommended):


This video was made with a super-cool tool called gource. Go check it out!

5/6/16

Console Programming 8-Week Project: Bringing DFGame to the web

This semester, I posted twice about console programming projects. They were small, carefully scoped projects to help me get a jump-start with DFGame. Now, it's time for the big reveal: My final, 2-month long console programming project. That's right, I

PORTED DFGAME TO HTML5/WEBGL

Yes, all of it.

One of the requirements for Console Programming is to develop at least one project on an unfamiliar platform or with unfamiliar tools. I decided to try my hand at developing a web-based game framework that was fully compatible with DFGame. The project was a big success, and I actually have a playable demo up on my site (based on the demo I produced for my previous project).
You can check it out here. (Note: you need a relatively recent version of a modern web browser such as Firefox or Chrome. IE won't work and Edge/Opera/Safari are untested)

Now, let's talk a little bit more in-depth about the project.

History

When I originally kicked off this project in class, I had much bigger aspirations. My original goal was to port both DFGame and Halberd, then add an HTML5 export option to Halberd's editor. Obviously, that was way out of scope. After a week or two, I decided to scope down to only porting DFGame, and that's what I stuck with throughout the project.

I wasn't sure how much of a demo I'd be able to put together, but I managed to complete the DFGame port quicker than expected and ended up with a couple of spare weeks to work on the demo.

The current demo doesn't have a title screen or audio in it, but is otherwise mostly indistinguishable from the desktop version.



Now, let's talk about the platform in general, and weigh the pros and cons of the platform.

Pros

  • This setup is mostly cross-platform. I don't have to worry as much about weird edge-cases, at least compared to developing native Windows and Linux versions of my games.
  • The games that I make with this are more accessible in general. There's no need to download an executable, just load up a link and play.
  • Since the library draws to an HTML5 canvas, I can pretty much embed DFGame into any web page that I want.
Those are some pretty good benefits. However, there are some pretty big problems with it as well.

Cons

  •  Unlike the C version of DFGame, all IO is required to be asynchronous. This isn't necessarily a bad thing, but it means that I need extra boilerplate to ensure that the right assets are loaded before the game begins.
  • The actual performance of DFGame is way lower when using the HTML5 version. This is to be expected, of course--You can't really compare raw C to embedded JS, especially not in web browsers with single-threaded renderers, such as Firefox's current release. Chrome currently gets way higher FPS than Firefox, but it still lags if enough is happening on-screen.
  • The WebGL API is currently outdated, compared to the current OpenGL and OpenGL ES standards. As far as I can tell, WebGL is still locked to the GLSL 1.0 standard, compared to 4.3 in GL and 3.2 in GLES. As a result, I need to rewrite all of my shaders whenever I move something over.

Further Work

Despite the problems with developing HTML5-based games, I'm actually pretty happy with the result. I think it's worth my time to continue developing and using the DFGame port, especially for game jams and other simple prototypes.

The port is currently behind, because I've been recently developing DFGame some more. I'll be posting about some of the new improvements soon. I also want to look into optimizing for WebGL better. I can't get a comparable framerate to the C version, but maybe I can eke out some more performance out of the web.

Lastly, I want to polish the demo some more. If I get it into a good enough shape, I think it could make a good portfolio piece. For now, I'm going to let it sit in a dark and dusty corner of my site until it's properly finished. Hopefully I'll have more time to do that now that my finals are over.

4/17/16

Capstone Update 18: Doors, my greatest weakness!

Recently, I had the misfortune of dealing with a number of issues in Unreal, and all because of doors. One of the last features that the designers wanted me to add to the monster was the ability to slip under doors and gates. "How hard could this possibly be?" I wondered to myself.

As it turns out, it was much harder than it should've been.

First try: The sensible approach

My first attempt was using Unreal's NavLink system. Nav Link Proxies allow you to have your AI take routes that aren't part of a level's navmesh, and have the ability to set up "Smart Links" which can have additional scripting added to them. The idea was to use this system to make the monster play an animation and warp to the other link, but there were some issues with this approach. The primary issue is that you can't remove all of the normal links and use only smart links. My research seems to suggest that this is a long-standing bug in UE4, so there's not much I can do about it. (As an aside, it's times like these that make me regret not trying to convince the team to make our own branch of the 4.9 codebase) If the monster chooses the 'dumb' link, which seemed to happen randomly, it would run into the door/gate and become permanently stuck. Clearly, a new approach was needed.

Second try: The unpleasant approach

After that, my next idea was to add a higher tier of pathfinding for the monster. By generating a set of links, I could create a small pathfinding graph that represented the level. With a basic A* implementation, I could make the monster select movement targets while attempting to reach a certain position or object. This was an incredibly large undertaking, but the result would likely work well. As such, I made all of the necessary preparations for pulling an all-nighter. However, this is not the solution in our build.
I constructed all of the necessary objects, but when I went to actually get them generating links I noticed something odd. specifically, none of them were linking up. I'd written a small function that used a quick pathfinding check to see if one link was reachable from another, but they always failed top make a connection. As it turns out, the returning value was always 'error'. Note that Unreal didn't provide any specifics, nor did I find any way of seeing what precisely this error was. After yet more research, I found out that this is yet another long-standing bug in Unreal. Epic really needs to crack down on some of these. Frustrated, but not yet asleep, I thought up another way.

Third try: The 'Why the hell not' approach

With all of the obvious and reasonable solutions out of the way, it was clearly time for a disgusting hack. After searching some more, I found a way to make Unreal ignore a given solid object when building the navmesh. However, as demonstrated by the first approach, this kills an AI's movement when they walk move an unexpected solid. To prevent this, I put a box trigger around every door and gate. Then, I made a special collision layer for the monster that would make doors/gates ignore all collisions with it. When the monster entered the trigger, it would change and be able to pass through! As an added bonus, the monster would even pass through the floor and fall out of the level, despite the fact that the floor is supposed to collide with it! To prevent that little issue, I had to temporarily disable gravity, while also changing collision layers and animations. Lastly, I needed to adjust the monster's speed. The monster is supposed to be slowed down by these obstacles, after all.

So, that's how I came up with a dumb solution for a dumb problem. I really hate that I had to do this, since it's a much less elegant and flexible solution, but I don't really see any available alternatives. As long as it holds together, I suppose it'll have to do.

4/7/16

Capstone Update 17: Looking Good!

As the beta milestone (the effective 'due date' for the monster) approaches, I've started filling in the remaining gaps that are left over from earlier in development.

One of those gaps is art. I gave the monster a graphical upgrade several weeks ago, but I've gotten plenty of feedback since then. I've also added more abilities to the monster since then, which require more animations.

The two biggest complaints about the monster were that it wasn't very scary, and that it was still hard to tell when the player was taking damage. The designers haven't had a chance to play with the monster's stats yet, but I still found it odd that my damage feedback wasn't doing enough. One thing that we'd been wanting to do for a while is make it more apparent that the monster was nearby, so I added a noise effect that grows as you get closer to it. In addition, I made the damage effect on the player smoother and slightly reduced the monster's damage. This seems to have greatly improved player reactions to getting hurt.

One of our designers added a nice cinematic introducing the monster, where it leaps down to attack you but is driven away by a flickering ceiling light. We think it's really nice, and much scarier than normal interactions with the monster. Part of this is because the player can fight back, but we've also identified a few other things that could use improvement. First off, the monster is almost always seen from a high angle. In other words, it looks harmless because the player towers over it. Just making the monster taller than the player has added to the monster's scare factor by a decent bit. I also pumped up the alpha and particle count to try and make the monster look a little bit more solid than before.


The last thing to add, which I addressed last weekend, is animation. There were  two main situations where the monster needed animations: Blinking, and slipping under doors. Blinking especially needed an animation, because the player needed a warning that the monster was about to appear. I spent a long time considering how to make the blink look. The blink is probably the most 'outlandish' thing that the monster is capable of, so I wasn't really sure how to make it work visually. Most of the monster's abilities are closely tied to the fact that it's more of a cloud than a solid object, but teleportation doesn't really fit as obviously.  Ultimately, I decided to interpret the blink as the monster slipping into a crack and popping out elsewhere, which I've represented with the monster's particles compressing and flying into the ground, while a second animation has them pop out and expand at its destination. It may not be perfect, but I think it fits nicely nevertheless.

The slipping animation was much easier. I scaled down the monster's particles, then made them stationary and emitted them using a flat disk. The result is a mostly-flat shadow creeping around. I'm pretty happy with the result, and also a little sad because I think a bigger, more elaborate version of it might've made for a creepier design overall. My original idea was for the shadow to be a vague squid-like silhouette that scurried around the floor and walls, and I still kinda regret not giving it a shot.

3/31/16

Capstone Update 16: Blink and you'll miss it

It has been quite a while since my last post. I've gotten a lot of work done since then, so I've decided to split my post into two parts. In this first part, I'll discuss the changes to the monster's AI, and in the second part I'll talk about graphics some more.

I've made several major changes to the monster's AI to make it more dangerous and unpredictable. The first change is the ability to 'blink'. When the monster is trapped or otherwise unable to reach the player, it can now teleport to designer-specified points called 'blink nodes', favoring nodes that are close to the player, but not to close to be unfair. This gives the monster more options, and makes it more challenging to trap.

Another major change that I've made is making the monster more resistant to the flashlight. The player's flashlight no longer marks them as 'safe' when in the dark, and the monster will now attack them. If the player sees the monster and reacts quickly, it can still be warded off with the flashlight. However, if it gets close enough then the flashlight becomes ineffective and the player will be forced to fumble with a flare to escape. This rewards careful play, and prevents the player from being 100% safe for most of the game.

Lastly, I've made the monster change speed based on its state. This not only makes it seem more dangerous, it also makes it very difficult to chase and kill, as we found some testers liked to do. Combine that with regenerating health similar to what the player has, and the monster is suddenly much more dangerous than it used to be.

Now, the monster is much more dangerous. On the visual side though, it's still a bit of a cute fluff cloud. In my next post, I'll discuss the steps that are being taken to fix that.

3/6/16

Capstone Update 15: Monster Beauty Pageant

During the past couple of weeks, I've been working on the monster as always. The AI work has been slowing down since I've had to look up how to alter some of the pathing. In the meantime, I've also started working on the particle effects that make up the monster. I think I've made some pretty good progress so far.

Shaping the Monster

When I asked the artists on the team for some guidance on how the monster should look,  they brought up images of schools of fish, and various swarms of animals. Following that idea, I added an additional emitter that created tiny particles to erratically orbit the monster's origin point. The original cloud of smoke now had what looked like a swarm of insects buzzing around it.

Next, I decided to try and fix a simple problem: Because the monster is entirely black, it's nearly impossible to see against a dark backdrop. I needed to find a way to make the monster visible while still being creepy. One of the original concepts that spawned this game was the common fear of the dark. That concept led me to try and make the monster create glowing 'eyes' within its mass, both to add to the creepiness factor and to make it more visible to the player.
Even in a bright preview window, it still looks a tad unsettling

Changing Form

I got some useful feedback in class. My teacher showed me some videos of snakes, barracudas, and other 'long' predatory animals to help make the monster seem more dynamic and alive. I've taken her feedback into consideration, and made a few interesting changes.

The monster in its natural habitat

My first change was to "give the monster legs", as I like to call it. As you can see in the screenshot above, the monster's main mass actually falls now, and sits on the ground. The result is that the monster seems to actually drag its body across the floor, rather than simply float like a cloud. It also serves to almost make it feel more like a creature, by giving it what looks like a discernible head.

When fleeing a light, the monster puffs itself up

After that, I started working on making its state more visually obvious. I started off by making the monster's size depend on a variable that I could alter. When the monster charges the player, it becomes thin and agile. When it runs away, it puffs up to look more intimidating. This change alone makes it feel more interesting and alive.

The monster going in for the kill. Believe me--it's creepier when it moves.

With the size changing in place, I began working on giving it some more interesting movement as well. When attacking, the monster now undulates along two sin waves. Each axis (horizontal and vertical) has a slightly offset multiplier and length. The result is desynchronized movements that make it look both dangerous and a little bizarre.

As a little teaser, here's some updated damage feedback.

3/5/16

Console Programming 3-Week Project 2 - DFGame Expansion

Hello again! After a few weeks of toil, I've finished my second 3-week project for Console Programming. I opted to make this project about building up DFGame to a more usable level, and I'm happy to say that the project was quite successful!

Project Overview

My ultimate goal for DFGame is to be able to build the base of a game from scratch, editor and all, in a single week. I decided that a nice way to cap this project off (and test the viability of DFGame in the process) would be to try and make a super-basic game/tech demo without an editor in a single week. I'm pleased to say that the result way a success!

To make this game happen, as well as improving Halberd a bit, I decided to implement the following features during weeks 1 and 2:
  • A script for generating new DFGame-based projects
  • Some UI widgets for editor development
  • Input handling code
  • Sprite loading/drawing code
  • Some initial project management code
In the downtime between projects, I also started work on audio loading/playback.

Project Script

One of the main differences between DFEngine and DFGame is one of approach. DFEngine's goal was to make a fully-featured game engine, but with DFGame I add features that will benefit me directly in game projects. As a result, I can get things done faster because my focus is specifically on making games.

The project script is a great example of such a feature. It's designed to set up a new DFGame-based project as quickly as possible, while also being easy to modify and extend.

DFGame now creates a folder in /usr/share (on *nix-based systems, of course), and adds folders which act like templates to it. This means that users can add their own, as well. It also installs the script to /usr/bin, so you can create a project just by calling "dfgame new project-name folder-name". folder-name is optional too, if you omit it, it'll set up the default project. The script moves over the contents of the template folder, and then checks for a special script within the folder. If the script is found, it's executed as well, to allow for extra customization. The current template scripts set up a config.mk file, for instance. Finally, the script initializes Git and builds the project, ensuring that everything is in working order.

UI Widgets

I've been meaning to move several parts of Halberd's UI over to dfgame for some time now. Most of the more 'generic' UI elements, such as the asset pan and missing files window are mostly self-contained, so moving them over was quite simple.

I also took the opportunity to make something new: a log viewer. I've wanted this for a while, so that I could debug issues without having to look at several windows at once. Now, it's in!
It's not an enormous addition, but it feels like another good step towards making my editors more professional.

Input

 My input code has always been fairly simple, but this time I decided to try and make a more powerful system.

This new system lives up to my expectations quite nicely! It revolves around mapping inputs of any kind to either (or both) of two input types, actions and axes. An action is any kind of digital input. It generally used to represent singular in-game actions, such as opening a menu or attacking an enemy. Axes, on the other hand, are 2D analog inputs. An axis can be thought of as a 2D vector, like a joystick input. Axes should be used to describe inherently directional actions, such as movement or aiming. Any keyboard, controller, or mouse input should be translatable to any actions and/or axes.

So, we have a decent base here. But what makes this so powerful is the way it's implemented. DFGame's input code is broken up over 2 of its modules: the base game module, which is used everywhere, and the game frontend module which is only used in released copies of a game, not the editor. This means that the editor and game are responsible for handling their own inputs, and passing the result to the base input system.

Not only does this separation make inputs inherently rebindable, since the actual keys are disconnected from the in-game actions, but it also allows the editor to simulate inputs and the game to take inputs from custom sources and input devices. Ultimately, this makes input code way easier to deal with, and it also makes adding or changing controls during development a cinch.

Sprites

DFGame's new sprite system is mostly identical to Halberd's, with one main exception.In addition to the sprite/animation system that I described in this post, DFGame's implementation has an additional layer of abstraction.

In order to speed up rendering and save on memory, I've split sprites into two parts, the spriteset and the sprite [player]. This is a similar approach to the one I took with audio: One struct controls data access, while others act as interfaces to play back this data. The spriteset holds the texture atlas and animations, while the sprites hold information about the currently playing animation.

Project Management

One of the most important features that you can put into an engine is the ability to create new projects. Even if you plan to only use an editor once, being able to go back and create brand-new content with it can be quite useful. In addition, it gives the editor potential for a decent public release. For that reason, I've moved Halberd's project management code into DFGame. It could still use a bit of cleaning, but for now it'll do the trick.

The Game

All of this technical talk is good, but you might've noticed that I mentioned a game earlier. In addition to the DFGame improvements, I also created a small game as a test. I planned to spend a week on it, but instead I only ended up with 3 1/2 days. Despite that, I still managed to make a small, well-scoped twin-stick arena shooter.

The game isn't currently packaged and available for download, although I'm considering that right now. The game's code is quite messy, since the point was simply to use it as a quick test of my library's capabilities, rather than to start a 'serious' development project. It's more of a game jam-style game.

Regardless, I took the time to make a video of the gameplay. Since there aren't any sound effects anyway, and the music was borrowed from one of my old game jam entries, I decided not to record the audio. Feel free to add whatever background music you like while watching.

Conclusion

I'm really happy with the progress that I've made in the past 3 weeks. I took a simple collection of asset loaders and turned it into a wonderful budding library of game development tools. Now that I've proven that rapid development is possible with this engine, I'm going to try and participate in more game jams again. In addition, I think I might try to make some smaller games as well.

Most of that will have to wait until after I graduate though. This is a very tough semester for me.

2/24/16

Small Hiatus

If you've been waiting for more roguelike tutorial posts, you may be disappointed. Because of the amount of work I've had on my plate recently, I've been unable to keep up with my schedule. For the moment, I've decided to put the series on hiatus until I have more time freed up. Im guessing that it'll be a couple of months before I really have the free time to devote to this project, but after that I'll try to post more frequently.

I have some standalone tutorials and informative posts planned as well, to add some more work to my portfolio, but there's no ETA on those. In the mean time, this blog will still have plenty of content thanks to class.

2/22/16

Capstone Update 14: The blog post where I actually discuss monster AI

This past week, our team took The Last Light to an expo in Montreal. By all accounts, it went well, but the work leading up to it was intense. I'll probably be taking things a bit easy, given that I spent 17+ hours working on the project last week.

One of the big things that I worked on last week was the monster AI. We now have a rough sketch of the AI implemented, and in the first level. I'm going to go through a quick rundown of the behaviors here, and what I plan to add in the future.

The Monster is based on a basic finite state machine, currently containing 4 states:

Wandering

 This is the default state for the monster. Currently, it chooses a random location within a small radius that isn't illuminated and that it can see, then goes there and repeats. This was implemented before I received the full designer spec for the monster, so it differs somewhat from their design for the moment.

Their system has the monster moving randomly between predetermined points, with a bias towards the player's position. This is partially implemented, but the waypoint EQS generator is still WIP.

Seeking

Previously, the player would die if they stayed in the darkness too long. Now, we have a more concrete and visible threat in the monster. When the player strays into the darkness without a light, the monster is alerted and enters a seeking state.

In this state, the monster finds a direct path to the player and chases them. If the player is caught, they begin to rapidly lose health, shown by a post-processing effect. Their health will regenerate after a few seconds of safety, however.

Currently, this is a pretty dumb state. Because the monster uses UE4's default pathfinding, it finds the most direct route. However, this route usually passing through includes light, which harms it. I haven't decided how to handle this yet, but I'm considering both navigation modifiers and custom navigation. Only time will tell.

Fleeing

 When the monster is lit and begins to take damage, it retreats. This is done using a simple pair of EQS tests on top of the same generator used for wandering. The tests A. ensure that the monster won't be moving into light and B. Heavily favor locations that are more distant from the player. The result is a behavior that feels 'right' when the player shines a light on the monster.

Dead

The monster takes damage from light, so if it spends too much time lit up it will enter a dead state. Once 'dead', it disappears for a few seconds, before reforming and continuing with what it was doing.

One major thing that needs to be done still is making it move in this state. It seems counter-intuitive, but by making it move as if it were fleeing, I can ensure that the monster won't reform directly on the player or inside a light.

My Goals

I've explained all the monster work that remains, but I also have some other goals for this coming week, mostly focused on graphical improvements.

First off, I need to improve the damage effect. Right now, it's not quite "in your face" enough, which probably makes it difficult for new players to realize that they're dying. Some additional blur, contrast, and color tweaks should hopefully make the player more aware of what's happening.

After that, I need to work some more on the interaction shader. Currently, it works well, but the designers have requested more control over it, such as color and width options. I'd like to get that done soon so that they have more time to play with it.

I don't expect to solve the pathfinding issue just yet, but we'll see.

2/12/16

Capstone Update 13: Making a Monster

The time has come for me to return, take up my mantle as an AI programmer, and write a bait-and-switch post about Unix shell scripting. I did work on our buddy the shadow monster this week, but it's not in the game yet and I'll be making much more progress on it this weekend. In the meantime, I'm going to make a post about a specific problem, and how I solved it with a just a tiny bit of scripting.

If you've used Unreal Engine 4, you probably know about the Substance plugin. This plugin is useful for making materials, but also has some issues. First off, it absolutely does not run on Linux. Given that my primary dev machine exclusively runs Linux, this is a problem. If I try loading a project that contains the plugin without installing it, Unreal simply crashes. The second issue is that it spreads. For some reason, installing Substance in one project seems to make it quietly install itself into other projects. So, if a single member installs Substance, the rest of the team will have to install the plugin on every new computer that they load the project onto.
Clearly, we have a problem.

However, I'm not here to complain about a problem, but instead to describe how I solved it. As a linux user, I think I can safely say that I'm more comfortable with shell scripting than your average developer. I'm also quite comfortable with git's command-line interface as well. Lastly, I know that Unreal stores plugins in the its text-based .uproject file. Going with my knowledge and experience, I decided to try and create a script that could auto-remove Substance whenever it appeared, so that no-one would ever need to deal with it on this project again.

Search and Destroy

The first thing that I had to tackle was finding and removing Substance. After all, if I couldn't do that then there would be no point to this exercise. Here's an example of a .uproject file with Substance installed:
{
    "FileVersion": 3,
    "EngineAssociation": "4.9",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "MindTreeGames",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine",
                "CoreUObject"
            ]
        }
    ],
    "Plugins": [
        {
            "Name": "Substance",
            "Enabled": true,
            "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/offers/2f6439c2f9584f49809d9b13b16c2ba4"
        }
    ]
}
Keeping in mind that the plugins section only appears if there are plugins installed, and that The Last Light doesn't make use of any plugins. In other words, we're free to simply wipe the Plugins section out entirely. Of course, we still need to find Substance, but we can easily fix that with a simple grep.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file
fi
With this basic script, we can now find and remove the Substance plugin from a project with a single call!

Hooking it Up

I had a good start with my script, but I wanted a proper automated solution. Luckily, git provides us with the necessary tools to make this happen. By placing scripts in the .git/hooks directory, we can add scripts that are called on certain git-related events. If we add our script as a post-merge hook, then we can make our script run every time we pull changes from a remote.

In addition to adding a hook, we may want to commit our changes, and push them to save other team members the work of removing it themselves. As it turns out, we can simply call git commit and git push from a post-merge hook, and they work completely fine.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file

    # Commit and push our changes immediately
    git commit -a -m "[bot] Removed Substance Plugin"
    git push origin master
fi
With these changes, all we have to do when we pull in the Substance Plugin is type in a password, and our script handles the rest.

2/11/16

Console Programming 3-Week Project 1 - Texture Loading in DFGame

What is this?

In one of my current classes, students are expected to design and implement coding projects of their choosing, then provide a writeup on their blog or portfolio where they explain the project. This is my first writeup, and you can expect 2 more similar posts later in the year.

As I've mentioned previously, one of my goals for the year is to ditch the DFEngine project and go back to developing games from the ground up. Instead of building on a large, monolithic engine, the goal is to implement lots of helpful code in libraries, which I can use to get started on projects quickly. I gave the library, DFGame, a short mention in a recent Halberd update, but I didn't go particularly in-depth as to what I'm actually doing with the engine. Here, I'll be documenting the work I've done on this engine over the past 3 weeks.

A General Overview of DFGame

Technically speaking DFGame is actually a set of 5 libraries broken up into the following modules:
  • common - The common code that all other modules rely on. Contains various low-level systems such as IO and logging.
  • editor [empty] - The editor-specific backend. Examples of editor-specific backend code include debug drawing, or handling assets that are baked or repackaged in the final exported game.
  • game [empty] - The game-specific backend. Mostly intended for game logic. This is deliberately separated from the frontend code to allow embedding it directly into an editor instance.
  • editor-front - The editor-specific frontend. Written in Vala, and provides helpful widgets and classes for building a graphical GTK3-based editor interface.
  • game-front [empty] - The game-specific frontend. Examples of game-specific frontend code include graphics context creation, or main loop handling.

Note: Why Vala?

I chose to use Vala for all developer front-end code for the same reasons as with Halberd. Writing GTK code (or any UI code, for that matter) in C is a huge pain. Dealing with inherently hierarchical systems like a complex user interface is one of the few most obvious advantages of object-oriented programming as a whole.

I chose Vala because it is fully compatible with C, even more than C++. Vala uses vapi files and gobject-introspection to convert a C#-like object-oriented syntax directly to GObject C, allowing for it to both use and be used in C code. I consider the flexibility that Vala affords me to be extremely valuable.

Using this system of modules gives me a few specific advantages:
  • It physically separates my code, which organizes it and also forces me to decouple distinct sections of my codebase as much as possible.
  • I can write functions that do the same things in different ways for different purposes. For instance, I can write an editor asset loader for my editor that reads in an xml file, then write a game loader for the same asset that loads it from compressed binary.
    • This same principle can be applied to a number of other uses, such as handling logs. If I had to specifically prefix all of these functions with whether they belonged to the editor or the game, then sort through all of them every time they were needed, I'd probably sob into a pillow before going to sleep at night.
  • It allows me to link game logic and rendering into my editor for play-in-editor support, (A necessary feature in any modern engine) without having to perform folder wizardry with multiple main functions.
I've taken the time to write pkg-config files for every module, so linking against DFGame on any *NIX system is a breeze.

The DFGame Texture Loader

In DFGame, textures are stored in a super-simple texture struct:

typedef struct texture
{
    GLuint    handle;
    uint16_t  width;
    uint16_t  height;
} texture;

The handle refers to a texture buffer handled by OpenGL, and is guaranteed by all texture-related functions to be in 32-bit RGBA format.

Note

When I refer to the bit depth of an image, I'm referring to the number of bits per-pixel, not per-channel.

You might notice that I'm using 16-bit unsigned integers to store the texture dimensions. As it turns out, a 32-bit true color image with the maximum dimensions that this struct supports would take up approximately 135 Gigabytes of VRAM. (Also, most OpenGL implementations don't support maximum texture resolutions beyond 4096 anyway)

The Texture Loading Process

Next, I'm going to go over the higher-level part of the texture loader.
The main entry function for the loader is load_resource_to_texture. This function takes in a resource string pair, and returns a newly allocated texture struct containing the image pointed to by the pair. Alternatively, there is also load_resource_to_texture_buffer, which load_resource_to_texture calls. That function gives a nice, 32-bit RGBA buffer for more specialized loaders such as the Halberd tileset loader.

I'm going to go on a quick tangent to explain what a resource string pair is, and how it actually works. If you don't care about that and just want to read about the loaders, feel free to skip to the next heading. The concept of the resource pair goes back to Halberd's development, when I was looking for ways to handle assets in the editor and the game with the same functions. Ultimately, I ended up breaking up file paths into 3 parts: The base path, the resource path, and the filename.

The base path is the path to the actual content directory of the project. In other words, it points to wherever you store all of the game's assets. The base path is kept as a hidden static variable in the C file that handles most resource-related functions. To get the actual filepath to an asset, I have the construct_extended_resource_path function. Most asset loading functions, including the texture loader, use this function to get to the actual file they need. The function simply takes in a resource string pair, then concatenates it with the base path (with some basic error checking, of course). As simple as it is, it gives me a lot of flexibility. I can move the base path all I want, and the engine won't care at all. Furthermore, resource string pairs let me easily separate the actual filename from the path. This is very important for any filename-related functions, because it ensures that I don't accidentally read from/write to the path to the file when messing with the name.

The Loaders

Next, I'll briefly talk about the loaders. They're all based on the lib[type] libraries, but each one is a little different so I think they're worth discussing a little bit.

PNG Loader

My PNG loader is the oldest one that I have, dating back to before this project, and even well before I started Halberd work this summer. Despite that, it's still not a full implementation. Also, because it's so old, it's starting to need some real cleaning up. Notably, there seem to be a few error cases missing still. It works reliably, but could probably benefit the most from another pass.

JPEG Loader

libjpeg is a strange beast. The other libraries were very well documented, but libjpeg contained no API docs at all. From my understanding, this may have been intentional, in order to ensure that users were sufficiently good at working with C to use it. Thankfully, there were some well-commented example applications, so it could've been worse. To distinguish the JPEG test texture, I exported my PNG test with as many artifacts as I could muster (by setting the quality to 5% in the Gimp).

TGA Loader

I started the TGA loader before finishing the JPEG loader, but the end was delayed because of an amusing bug caused by a momentary lapse of judgement. When converting the raw data from a TGA file to the internal standard format that I use, I use the byte-depth to determine where to move bytes around. However, I accidentally passed the bit-depth in instead, resulting in an 8x smaller image! Interestingly, this didn't crash the program. It's definitely worth keeping an eye on memory access, that's for sure.

Tiff Loader

Sadly, the TIFF loader was fairly unremarkable. However, I think it's safe to say that the TIFF and PNG formats are the top two formats that I'm handling, as far as features go. Looking over the documentation surprised me quite a bit, because I don't usually use TIFFs very much. In particular, the ability to store multiple images in a TIFF may be worth revisiting at some point.

Conclusion

So, there you have it. I think this first project went quite well, fitting perfectly into the 3-week slot I carved out for it. My next project is probably going to involve Unix sockets, and be less related to games and more to general software development.

I'll be putting the dfgame project up on my software page soon. Until then, here's a link to the dfgame git repo.

2/5/16

Halberd Update 4 - Watch this!

It's been too long since my last Halberd update, but rest assured: I've been hard at work.

The Asset Registry

The registry can automatically tell when an asset has been changed outside the editor, and can prompt the user for more information.
I was been aware for a while that if I didn't create some method for handling assets and their relationships with each other, I was going to be in a world of hurt later. Over break, I spent a lot of time considering my options and came up with the asset registry.
The asset registry is a special container that records assets and assigns numerical IDs to them. The engine can report changes to the locations/names of registered assets, and the registry will change accordingly. Then, assets that depend on them can refer to them with their ID, and never have to worry about moves or deletions. Whenever you make some sort of connection between an asset and another, the depended asset is automatically registered (unless it exists in the registry, in which case the ID is returned). This makes managing assets extremely simple and straightforward.

New Editors

Adding a reference to an asset is quite simple, thanks to my generic asset-selection widget
For a long time, I've had to make most assets by writing config files, DFEngine style. This is a horribly slow, boring, and imprecise way to actually produce a game, so I've started making views in the editor for designing and editing various game objects. So far, I've finished the first pass on the Actor editor and I've started on the Sprite editor. I've got a lot of work on my plate, so progress here has been a bit slow.
I've also added a tile selection pane to the map editor. Not only can you choose specific tiles to place, you can also add new tilesets to a map and save them into the map file as well! I made this before the asset registry, so it needs some adjustments in order to fall in line with the rest of the asset editors. The tile selector is also a bit slow sometimes. I'll need to look into this in the future.

The Logging System

One thing that I've wanted in my engines for a while is a better way to log information and errors. After taking some time to work out logging in Halberd, I think I have a decent system. Using variadic macros, I've made logging fuinctions that can take arguments in the same way that printf can. This alone is a huge boon, as far as getting information goes. On top of that, I've added a simple way to add a callback function for logging. I'm not using any at the moment, but once I get the chance I'll be adding popups for error messages and a logging window to search, filter, and examine messages from the editor.

DFGame

Of course, what real good is such a nice log, if I can only use it for a single project? As I mentioned in my 2015 retrospective, I want to have a few basic libraries to make development simpler. I've started work on DFGame, a game engine utility library, and so far I'm happy with the results. Much of my resource handling and logging code has been added already, and I'll be adding much more in the near future.

By doing this, I've been able to rip several files straight out of Halberd and into DFGame, which has the added benefit of making Halberd's codebase just a tad smaller and simpler. I'm hoping that in a couple of months I'll have enough in there to give me an easy jumpstart on any new game projects.