Twitter Updates

Recommended Productions

CommonLib 9.0

Universal library for C++, created especially with game programmers in mind. Includes: math module (vectors, matrices, quaternions, planes, rich set of collision functions and more), string operations, conversions, smart pointers, configuration files handling, date and time module, exception class hierarchy for error handling, file system handling, stream class hierarchy, FreeList - free memory allocator, complex logger, profiler, library for threading and synchronization, tokenizer, wrappers for compression with zlib.

Language: C++. Platforms: Windows and Linux. License: GNU LGPL. Optional support for Unicode. Optional integration with D3DX. Documentation made with Doxygen.

Date: 2009-12-16

Download:
CommonLib_9_0.zip (4.92 MB)

Aqua Fish 2

Game for children - clone of PacMan. Player swims as a fish and collects points, as well as special items. Player also have to run away from enemies or destroy them. 60 maps in 6 different titlesets. Low hardware requirements. See also YouTube video. Game was published by Play Publishing company.

The Final Quest

3D graphics engine - my biggest project. Available for download is demo as application or video, as well as full source code under GNU GPL license.

Architecture and Implementation of 3D Graphics Engine

My master thesis. It describes my graphics engine "The Final Quest". It includes literature overview, description of my engine architecture (layers, modules, classes and fields) and implementation details (rendering process organization, shader code explanation, skeletal animation computations, particle effects implementation, model file format and more).

Date: 2008-06-16

Download:
Adam Sawicki - Praca mgr.pdf (4.68 MB)

GameDev Calc

Calculator for game programmers. Basic data unit is a vector of 1-4 floating point numbers, which can be treated as (x,y,z,w) vector or (r,g,b,a) color. Next to basic calculations like addition, multiplication or sinus, vector operations are also available, e.g. vector normalization, conversion between degrees and radians, color conversion between RGB and HSB, finding linear an quadratic function coefficients and much more. Instead of entering single number, here you can see all the history of your calculations in form of stack and all operations are performed on that stack. Data can be entered and retrieved in different formats, like "D3DXVECTOR4(0.0f, 0.5f, 0.752f, 1.0f)" or "0xFF0080C0". Platform: Windows. Language: C#. License: GNU GPL.

Download:
GameDevCalc_1-0.zip (53.06 KB)
GameDevCalc_1-0_src.zip (50.73 KB)

Blog RSS Feed: Adam Sawicki - Homepage (Blog)

19:11
Sun
24
Jan 2010

Doing Something Every X Time

Games are one of these applications where we have a loop spinning infinitely as fast as it can (or at least 30 times per second) and calling some DoFrame function that make all the computations and rendering of a game frame. Dealing with time is an important task in game programming. One of the things game frameworks usually do are retrieving precise current time from the system and measuring FPS. Xion wrote an interesting article about all this stuff some time ago, entitled Pêtla czasu rzeczywistego [pl].

By the way, a fact not so well known by beginners is that FPS (frames per second) is not good measurement of a game performance, because it is expressed in Hz which is reciprocal of average frame time and thus it is nonlinear. The real metric for how much more optimization do you have to put into your game should be average frame time in milliseconds. But that's another topic. I've blogged about this some time ago here [pl]. Others also did this, like Humus or Real-Time Rendering Blog.

Subject I want to write about today is inspired by recent question from forum.gamedev.pl - Koniec z timerami [pl]. It's about implementing timers in games. The question is how to execute some code - let's say to call DoSomething() function - every EventTime time, e.g. every 200 ms. Two solutions have been proposed there by Kos and cybek. The difference between them is suble but important.

Let's assume we have have access to variables:

  • const float EventTime - desired time between DoSomething() calls
  • float CurrTime - time of the beginning of the current frame
  • float LastTime - time of the beginning of the previous frame
  • float DeltaTime = CurrTime - LastTime

Time may be expressed in seconds, milliseconds or any units - it doesn't matter here. First solutions looks like this:

// Defining helper variable
float EventCounter;
// Initialization
EventCounter = 0.f;

// Inside DoFrame, called every frame
EventCounter += DeltaTime;
while (EventCounter >= EventTime)
{
  DoSomething();
  EventCounter -= EventTime; // !
}

And here is the second example:

// Inside DoFrame, called every frame
EventCounter += DeltaTime;
if (EventCounter >= EventTime)
{
  DoSomething();
  EventCounter = 0.f; // !
}

So what's the difference? Method number 1 is precise. DoSometing will be always called every EventTime, plus/minus one frame and exactly every EventTime on average. On the other hand, method 2 calls DoSomething() not more often than every EventTime, but usually more rarely. I suppose it's EventTime + average_frame_time/2 on average. I hope you can see from this code why is that.

Why does it make a difference? First case is when you have a stall for, let's say, 500 ms between frames because you did some very expensive computations like failed A* pathfinding or some background process like antivirus slowed down the system. In the next executed frame, the first code above will "catch up" executing DoSomething two or three times, but the second code will just execute DoSomething() once and continue as nothing happened. Second difference is when you measure how many times was DoSomething() executed during some longer period. First code will probably do it exactly period/EventTime +/- 1 and the second code will result in no more, but probably less number of calls.

There is another question: How to express EventCounter variable? This problem is orthogonal to the one described above and make no difference to the code logic, so it's just your choice. Here are the options: As time passes since the last DoSomething call...

  • EventCounter increases from 0 towards EventTime (that's what I used here)
  • EventCounter decreases from EventTime towards 0
  • EventCounter increases from CurrTime of that frame towards CurrFrame+EventTime

As a side note, you don't have to tell me that float is not a good type for expressing absolute and precise time inside games. I know that and I will write more about it another time. The code above was just and example.

Comments (2) | Tags: algorithms

22:30
Sat
16
Jan 2010

Overtime Concern in Game Industry

For those who are not up-to-date with news from the industry: There is lots of stuff posted and commented recently about the the concern of overtime work at Rockstar San Diego. I won't comment it as I don't like controversies, I'll just show interesting links:

  • Wives of Rockstar San Diego employees have collected themselves (2010-01-07) - an open letter by "Determined Devoted Wives of Rockstar San Diego employees" complaining about work conditions (especially overtime work aka Crunch Time) in the studio. (You probably need to be registered at Gamasutra.com to view the article.)
  • IGDA: Regarding Overtime Concerns at Rockstar San Diego (2010-01-13) - official IGDA (International Game Developers Association) standpoint in this matter.
  • ea_spouse - a blog of Electronic Arts employee's spouse who wrote similar letter in 2004 (entitled "EA: The Human Story") and is now an activist popularizing quality of life concerns in the game industry.

Comments (1) | Tags: game industry

22:00
Tue
12
Jan 2010

Processing File Paths in C++

Paths to files and directories are special kind of strings. Sometimes they have to be processed, e.g. merged or splitted into some parts like drive letter, directory, file name and extension. Standard C library provides two function for this: makepath and splitpath. They use char* strings and operate always on all possible parts (drive, dir, fname, ext). In my opinion they are not very convenient. On the other hand, modern programming languages have more functionality in this field. For example, .NET has System.IO.Path static class with methods like GetExtension, GetFileName, GetDirectoryName.

To make operations on file paths convenient in C++, I've developed some time ago my own functions for that which operate on std::string strings. I've included them in my CommonLib library. They are similar a bit to these from Delphi :) Here is how I approach this topic: First, a common task is to extract part of a path (e.g. "C:\Windows\notepad.exe"). My functions for this are:

  • ExtractFileDir returns path without final name ("C:\Windows"). It does not include trailing delimter unless returned path is a root directory, like "C:\".
  • ExtractFileName returns only the final name, without preceding path ("notepad.exe"). Result is the full name including extension.
  • ExtractFileExt returns only the extension of final name (".exe"). It's good to treat the dot as part of an extension because we sometimes need to strip or add an extension to an existing file name.
  • ExtractPathPrefix returns only the starting point of an absolute path. For local Windows paths it looks like "C:\", but there is a second possibility - a network share like "\\ComputerName\ShareName\".

I also have some functions for processing paths:

  • IncludeTrailingPathDelimiter and ExcludeTrailingPathDelimiter address a problem that sometimes paths to directories end with trailing backslash. These functions can be used whenever you want to ensure that your path ends or doesn't end with the '\'.
  • ChangeFileExt is maybe a misnomer as it doesn't change an extension of a real file. It only changes file extension inside a path. For example, you can pass ".txt" to get "C:\Windows\notepad.txt". Thanks to requiring dot in the extension you can also use this function to strip extension from the path by passing empty string "" as the new extension.

Path can be absolute or relative. In Windows, absolute paths start with drive letter like "C:\" (which we can recognized by looking for colon) or network share (paths that begin with "\\"). Relative paths (where most basic example is a single file name) make sense only in some context. When we use relative paths to open real files, we address them relative to the "Current Directory" (which is a separate topic, I will write about it another time). To deal with absolute and relative paths, I've coded functions such as:

  • PathIsAbsolute - tells whether a path is absolute
  • RelativeToAbsolutePath - that's the most important function for me. Given base path (like "C:\Windows") and relative path (like "notepad.exe") it combines them into full path. This function is equivalent to System.IO.Path.Combine from .NET. There are many possibilities here. Base path can be relative or empty. Second path can be absolute (function directly returns second path in such case). It also automatically adds '\' separator between paths if needed.
  • AbsoluteToRelativePath - does the opposite: Given full path and a base path to some drive or directory, it returns a path that points to the same file/directory relative to the base directory.

NormalizePath function preprocessess all the . and .. drectories in the path. A single dot used as directory name means "my own directory" (just does nothing) and two dots mean going up one level to the parent directory. So the path we consider here is logically equal to "C:\Windows\.\system32\..\notepad.exe". Paths like this still work, but they can look a bit unclear, so you can use NormalizePath function to clean them.

Paths in Linux are quite different. My functions also support them, although I didn't test this case in real situations yet. First of all, there are no drive letters in Linux, so absolute paths just start with '/', like "/etc/passwd". Second, a slash sign is used as a separator instead of backslash (it's interesting that slash also works in Windows). It's also more common in Linux than in Windows to meet files that don't have extension or have double extension (like "MyFile.tar.gz"). A question arises here whether what we call "extension" starts from the first or from the second dot :)

Comments (1) | Tags: algorithms c++ commonlib

18:18
Sun
10
Jan 2010

A Reminder About My Links

For those who don't know yet, on my website there is more than my blog, photos and screenshots gallery and portfolio. I also maintain quite long list of links to other people's blogs, especially programmers dealing with game programming and graphics programming. So if you are interested in this subject, I encourage you to take a look. I try to keep it up to date by removing not working or inactive sites while adding new ones I find interesting. I also have my parsonal links collection called Links - gamedev.txt which I update sometiemes by addign URL-s to interesting articles and websites related to gamedev.

It may sound funny by I currently find blogs and Twitter as my most valuable source of interesting news and links. With careful choice of places you visit and people you follow it has much bigger "Signal/Noise Ratio" than any Internet forum :)

Comments (3) | Tags: internet homepage

22:17
Sun
03
Jan 2010

RegScript - Bidirectional Type Inference

Coding my RegScript programming language is no longer easy as code grows bigger, but it's still much fun. In the last days I've added support for numeric types of different size. Here is the full list: float, double, uint8, uint16, uint32 (uint), uint64, int8, int16, int32 (int), int64.

I try to keep the syntax as close to C/C++ as possible, but at the same time I introduce some interesting details like:

  • Conversion between types, e.g. char to string (of length 1), any type to string (makes string representation of a value) or string to any type (tries to parse the string). Implicit conversions of this kind generate compiler warning though.
  • Indexing with multiple indices: object[x,y,z]
  • Arbitrary expressions as default function parameters: void Func(float x = sin(globalVar)) { ... }
  • Multiple values in switch case label: switch (val) { case 1, 2, 3: ...
  • Arbitrary expressions in switch case label: switch (val) { case someVar+1: ...
  • Possibility to define variables in switch case labels.

I've also implemented function overloading and many compiler errors and warnings similar to these from C++ compiler. But most interesting feature so far is what I call "Bidirectional Type Inference" :) I first introduced auto keyword to allow skipping type name and next I've made literal constants like 123 typeless so their type is deduced from the context (because I hate typing this f, u or ll postfixes everywhere in C++ code). For example:

// Left to right - these numbers are int16
int16 myShort = -32000 + 10;
// Right to left - newVar is int16
auto newVar = myShort;

Comments (2) | Tags: regscript compilers c++

19:45
Sat
02
Jan 2010

WTS Keyboard

It definitely wasn't a good buy. I was dreaming about new keyboard with multimedia keys to control mp3 player instead of binding strange global hotkeys like Ctrl+Alt+Home, so I was more than happy when I chose nice looking A4-Tech X-SLIM KL-7MU model with USB, headphones and microphone extension cable. It was part of my hardware upgrade together with new processor, motherboard, monitor and more. I've also installed Windows 7 then.

It took place 1.5 months ago and I've experienced many things since then. Most things work fine but I couldn't get rid of strange feeling that coding on my new computer is less comfortable than before. I blamed it on Windows 7 and I was partially right as there is a scandalous flaw in this new Microsoft product - GUI is no longer hardware accelerated! So it's no suprise that I can often see windows and controls being drawn as I move them, scroll them or type my code, even after turning off all the animations, transparencies and even all this beautiful Aero. As a proof, look at this YouTube video: Windows 7 GUI slowness. I just feel like working under Linux before installing graphics drivers. What a shame, a big step backward...

But after comparing my experiences from work with these from home I've noticed that it has to do something with the keyboard. I've always been opposing to "flat", laptop-style keyboards and my new A4tech one is just like this. So I returned to my old-school, white keyboard. Now the GUI of Windows 7 still annoys me a bit, but coding is much better. You may tell it's the matter of taste but as for me, I'm sure now that I prefer to code on a keyboard with high "step", where I can clearly see, hear and feel whether I've pressed particular key or not. I just type faster and make less mistakes on such keyboard. I'm also sure it's not the matter of getting used to it as I tried to use laptop-style keyboard now for more than a month as well as for three months when I've been in USA and in both cases I couldn't start to like it. So now I want to sell my new great keyboard (see the auction). Anyone interested? :)


Comments (7) | Tags: hardware shopping

17:44
Wed
30
Dec 2009

RegScript - my Scripting Language

RegScript is my scripting language I've started coding yesterday. I'm not a guru in formal languages theory, but I'm quite fascinated with programming languages, parsers and interpreters. I don't know why but I felt I'd love to write my own programming language so I just started coding it, even if it doesn't make any sense. Maybe that's just because it's like being the creator of something that we, as developers, are usually only users. The language syntax is similar to C++. Here are features I've coded untill now:

  • Variable types: bool, int, float, char, string, auto (automatic type inference)
  • Values like: -10, 0xFFFF, 0b1010, 1e-6f, false, true, 'A', "foo"
  • Operators: + - * / % < ?: ! && || ~ & | ^ << >> = += -= *= /= %= &= |= ^= <<= >>= ++ -- == != < > <= >= ( ) sizeof ,
  • Instructions: if-else, while, do-while, for
  • Intrinsic functions: sin, print, intrinsic constants: PI.

The implementation is not optimal yet as I don't generate any bytecode. I just execute statements and evaluate expressions from a tree made of polymorphic nodes dynamically allocated by parser. Sample program:

print("Hello World!\n");
for (auto i = 0; i < 10; i++)
  print("i = " + i + '\n');

Comments (2) | Tags: scripts compilers regscript

18:31
Mon
28
Dec 2009

Generating and Compressing AVI Video Files

Yesterday I've decided to share all my home code using Project Hosting on Google Code, so now everyone can browse my code online by entering project called blueway. I'll be very glad to hear your opinions and suggestions about it.

Today I've researched subject of generating video data as AVI file, compressed on the fly with codecs installed in Windows. After succeeding with that I've created simple class to support this task, called VideoCompressor. You can find it in Video.hpp and Video.cpp. Test code is in ProgramMain.cpp, line 2318. It generates a 5 second video with a white horizonal line moving from bottom to top.

Here are some technical details. Functionality needed to handle video files is already inside Windows API, described in MSDN Library. The AVIFile library contains functions like AVIFileOpen, AVIFileCreateStream, AVIStreamWrite. It supports reading and writing AVI files. You need to include <Vfw.h> header and link with Vfw32.lib file. AVI is actually a container file format made of RIFF data chunks identified by 4-byte FOURCC codes (if you ever loaded 3DS models, you know what I mean). It can contain multiple streams like video and audio, which can be coded in many different formats, compressed and decompressed by codecs.

Compressing and decompressing frames of video with installed codecs can be done with Video Compression Manager library. You can display standard, system dialog window to let the user choose and configure codec with ICCompressorChoose function. Then you can just pass subsequent video frames as uncompressed RGB images to a function like ICSeqCompressFrame and you get a piece of compressed data that you can save to your AVI file.

Comments (1) | Tags: video winapi

Older entries >

STAT NO AD [Stat] [Admin] [STAT NO AD] [pub] [Mirror] Copyright © 2004-2010 Adam Sawicki 0.02 s
Copyright © 2004-2010 Adam Sawicki