Archive for the 'Game Development' Category

Creating SVN patches and saving them as ZIP file

I use SVN as source control system for one of my projects. Sometimes I want to create patches in form of a zip file containing the changed/new files. Doing so manually is a pain and error prone. First you have to diff between your branches to find all change since your last release, export those files from SVN, then package them into a proper structured ZIP file.
So here is a PowerShell snippet doing exactly that automatically:

function new-patch
{
    param($from, $to)
    # get diff summary as XML
    [xml] $summary = (svn diff $to $from -x --ignore-eol-style --xml --summarize)
    # loop through all diff/paths/path nodes
    # each node represents a modified/new file
    foreach($item in $summary.diff.paths.path)
    {
        # the SVN url
        $url=$item."#text"
        # the relative filename
        $file=($item."#text".Substring($to.Length))
        # the parent directory
        $dir=($file | split-path -parent)
        # create parent directory if it doesn't exist already
        if((test-path $dir) -eq $false) { mkdir $dir -force}
        # export current files from the SVN repository
        svn export $url $file
    }
    # package the current dir (.) into patch.zip
    sevenzip.exe a patch.zip .
}

The function is then used like this:

PS> new-patch "https://actiongame.svn.sourceforge.net/svnroot/
actiongame/tags/v01_00_00/" "https://actiongame.svn.sourceforge.net/svnroot/actiongame/branches/v01_00_xx/"

I specified the old branch as first argument and the new branch as second argument. Now after processing I get all the changes as proper filetree inside a zip file. Ready to ship..

The whole process could be optimized quite a bit. Right now a new SVN request is sent for each single file, it could as well be batched into one request to improve the export performance.

Advertisements

Create .lib file from .dll

When working with 3rd party win dll’s you somtimes miss the according .lib file required to compile against it. There is a MS KB article showing how to generate a .lib file from a .dll, however the required steps are not described detailed enough I think. So here is my quick guide:

Open the Visual Studio Command Prompt, you find its shortcut in Start->Programs->Microsoft Visual Studio->Tools. Now run the dumpbin command to get a list of all exported functions of your dll:


dumpbin /exports C:\yourpath\yourlib.dll

This will print quite a bit of text to the console. However we are only interested in the functions:


ordinal hint RVA      name

1    0 00017770 jcopy_block_row
2    1 00017710 jcopy_sample_rows
3    2 000176C0 jdiv_round_up
4    3 000156D0 jinit_1pass_quantizer
5    4 00016D90 jinit_2pass_quantizer
6    5 00005750 jinit_c_coef_controller
...etc

Now copy all those function names (only the names!) and paste them into a new textfile. Name the nextfile yourlib.def and put the line “EXPORTS” at its top. My yourlib.def file looks like this:


EXPORTS
jcopy_block_row
jcopy_sample_rows
jdiv_round_up
jinit_1pass_quantizer
jinit_2pass_quantizer
jinit_c_coef_controller
...

Now from that definition file, we can finally create the .lib file. We use the “lib” tool for this, so run this command in your Visual Studio Command Prompt:


lib /def:C:\mypath\mylib.def /OUT:C:\mypath\mylib.lib

That’s it, happy coding 🙂

Replacing alutLoadWAV by SDL_LoadWAV

In the fps game AssaultCube, we only use straight OpenAL without using the ALUT library. Well almost, the only function we actually used was alutLoadWAV. Since this function is officially declared deprecated and nothing else was used from this library, we decided to replace this functionality by SDL_LoadWAV from the SDL library we use extensively. Here a C++ code snippet:

SDL_AudioSpec wavspec; uint32_t wavlen; uint8_t *wavbuf; if(!SDL_LoadWAV(file, &wavspec, &wavbuf, &wavlen)) return false;
// map wav header to openal format ALenum format; switch(wavspec.format) { case AUDIO_U8: case AUDIO_S8: format = wavspec.channels==2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8; break; case AUDIO_U16: case AUDIO_S16: format = wavspec.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; break; default: SDL_FreeWAV(wavbuf); return false; } alBufferData(id, format, wavbuf, wavlen, wavspec.freq); SDL_FreeWAV(wavbuf);

Well it’s not a big deal, you only need to be careful with the format info, make sure you map the wav header correctly to the format enumeration for OpenAL, otherwise you will hear some strange sounds 😛

artifacts and other OpenAL issues

When using the OpenAL library for audio output, you might experienced playback problems such as sound artifacts, “clicks”, volume problems, etc. Here a list of hints that might help:

  • Always set the correct gain, position, etc _BEFORE_ calling alSourcePlay(). Otherwise OpenAL might output the first milliseconds of the sound on a totally wrong position using a wrong gain, etc.
  • Always check for errors when creating new sources. If you blindly use an invalid source you might hear the sound from some weird position or you might not hear it at all. Make sure your error handling code addresses all possible issues.
  • Ensure that your sound files (e.g. WAV) aren’t broken. I once used a wav sound that worked well in players like VLC but in OpenAL it just played at full gain all the time, no matter what distance I set. The solution was to edit the wav and to reduce the overall volume of the sound into a valid range.

To be extended some day..

OpenAL with multiple distance models

OpenAL is a great library to manage 3D surround in your application. For the FPS game AssaultCube I rewrote the sound related code to use OpenAL instead of simple stereo output. There are different distance models to calculate the effective gain (volume) of the sound sources: inverse distance, exponential distance, linear distance, etc. For FPS games the inverse distance models seems to fit best, it just sounds more realistic than simple linear models. Now the problem with inverse models is that no matter how far away the sound source is, the volume will never completely drop down to 0, you will always hear it, this is a real issue:

  • Processing almost silent sounds is a waste of resources that could be used otherwise. The sound channels for mixing are usually limited to 32 (!) on most hardware.
  • You can not limit the sound to a specific radius e.g. to make it present in a single room/area only.

Now you could just disable the distance model using alDistanceModel(AL_NONE) and write your own code to handle all gain calculations yourself. However for AssaultCube I found a better solution, the important sources in the game such as sounds from players are using the inverse distance model, on the other hand all map sound entities that are placed in certain areas as well as low priority sounds such as footsteps use my own distance model. Because OpenAL allows only one distance model to be active, we need to bypass the distance model calculation for these sounds:

alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcef(id, AL_ROLLOFF_FACTOR, 0.0f);
alSource3f(id, AL_POSITION, 0.0, 0.0, 0.0);

This way the source is always on the same position as the listener, causing the gain value to stay at the maximum. Now that we know that OpenAL won’t touch this source’s gain anymore, we can calculate it using our own rules:

float dist = camera1->o.dist(vec(e->x, e->y, e->z));
float gain = 0.0f;
// clamp to full gain (attr3 is a object "size" property)
if(dist <= e->attr3) gain = 1.0f;
// linear calc (attr2 is a "radius" property)
else if(dist <= e->attr2) gain = 1.0f - dist/(float)e->attr2;
alSourcef(id, AL_GAIN, gain);

Now this object uses our own linear model while the other more important objects still rely on the better but expensive inverse model. I think this is the best solution to the problem regarding code size and simplicity.