
qdgdf - Quick and Dirty Game Development Framework
Copyright (C) 1997-2001 Angel Ortega <angel@triptico.com>
Home Page: http://www.triptico.com/software/qdgdf

This software is GPL. NO WARRANTY. See file 'COPYING' for details.

Intro
=====

qdgdf stands for Quick and Dirty Game Development Framework, and it's a
set of libraries designed to allow fast development of games under a
variety of systems. Its main goal is to show a platform-independent,
consistent interface to Unix/Linux and MS Windows.

qdgdf has two libraries: qdgdfv (Video) and qdgdfa (Audio). Any of them
can be used independently (except for a special MS Windows issue, see below).
They are built as static libraries only; no support for dynamic ones by
now.

qdgdfv
======

qdgdfv (Video library) implements a virtual screen (framebuffer). Though
this virtual screen uses 8 bit depth (256 color) mode, the real screen can
use any depth. It has been tested in MS Windows DirectX and the
X11 Window System in 8, 15, 16, 24 and 32 pixel depths.

As it is an internal 256 color mode, a palette must be provided. A
highly optimized one is included if you don't supply it. Also, the
necessary functions to load 256-color PCX files (they must all use the
same palette) are also provided. Later qdgdfv versions won't be so
palette-dependent and will provide three virtual screens for real 24
bit RGB operation.

This library also implements basic keyboard input (sorry, no joystick nor
mouse in this version), filling a short set of variables with current
cursor key (and some modifiers) status.

In X11, windowed mode is always used, and both horizontal and vertical
sizes can be set to any reasonable value. A special double-mode flag can
also be activated, in case of a huge screen resolution with tiny pixels is
active.

Full screen mode is always used in Win32. As it uses DirectX, the screen
dimensions are limited to usual resolutions (640x480, 800x600, etc.). Not
all of them are available in all hardware, just experiment. If the resolution
you ask for isn't available but the double one does, double-mode is
automaticly activated (say, if you ask for an unavailable 320x200, 640x400
double-mode can be used). So, remember to check the contents of screen's x
and y size after initialization, as they could have changed from what you
had set.

qdgdfa
======

qdgdfa (Audio library) lets you launch previously loaded sounds
simultaneously. It can use 8 and/or 16 bit mono sounds in 8 and/or 16
bit mono/stereo soundcards at a 11025 sampling rate, providing the necessary
conversions. Though sounds must be mono (i.e., they only have one channel),
they are played in stereo, so it's possible to set the pan in play time to
whatever you want.

Wav files (.wav) are supported (remember, sampled at 11025 Hz). 16 bit mode
will be used unless explicitly requested or hardware limited. You don't have
to take the endianess of the CPU into account as sounds are byte-swapped if
needed.

In Linux systems, qdgdfa uses the OSS Free interface (no ALSA by now,
sorry). A new process is forked to attend the sound mixing; it
communicates with the main one via a pipe.

In MS Windows, DirectSound is used (see below).

A stub library is also available for unsupported systems.

The MS Windows interoperability issue
-------------------------------------

Microsoft boneheads thought it will be a good idea to vinculate a
DirectSound object to a window (not to an application or 'instance').
It's absolutely necessary to have a window handler for sound to work, so
creating purely-independent audio code is impossible and a trick must be
provided to do this. The problem is worst when using qdgdfa win32 driver
with another video library, say GLUT (that provides a good platform-
independent OpenGL layer and knows nothing about moron MS window
handlers).

The trick is to find the window by it's title. That is what the string
_qdgdfa_window_title is about; copy _qdgdfv_window_title value into it
before calling qdgdfa_startup() and that's it. This means that the audio
library must be started up AFTER the video one for the window being
correctly found.

I talked about GLUT: if you use qdgdfa with it, init GLUT first. If you
are using EnterGameMode (so you have a full screen unnamed window), set
_qdgdfa_window_title to exactly "GLUT" (this is not magic, is the real
name of the hidden window).

Of course, non-win32 versions doesn't have this problem, but it's a good
idea to startup the audio library before the video one so you get
portability.

Compilation and usage
=====================

To build the libraries, just type

	$ make

and everything must be correctly detected. If you want to use the
alternative, null sound library, just type

	$ make AUDIO=NONE

legal values for AUDIO are LINUX, WIN32 and NONE. There is another make
variable, VIDEO, with legal values X11 and WIN32 (no NONE, obviously).

For X11 you need the basic X11 development headers, and the same for Linux
sound. The GNU C compiler and GNU make are also mandatory.

For Win32 you must have Borland C. You can obtain the command line
compiler for free from their web site. You must also have DirectX and
DJGPP's make.

Once built, you must have two libraries, qdgdfv.a and qdgdfa.a (qdgdfv.lib
and qdgdfa.lib for Win32). You must insert the qdgdf_video.h and
qdgdf_audio.h headers into your C code and fed the libraries into your C
compiler with the usual command line arguments, as always.

Building a cross-platform game in one evening and 10 steps
==========================================================

1.- Think a plot for your game. All game plots suck, so don't treat
    yourself too badly here.

2.- In your favorite bitmap editor tool, draw the characters / enemies /
    objects / decorations. Set all of them to the provided palette, and
    save them as 256 color PCX files.

3.- Drag the Internet looking for appropriate sounds for jumping / dying /
    shooting / whatever. Convert all of them to 11025 Hz using your
    favorite sound conversion tool.

4.- Open your text editor and start to type C code:

	#ifdef __WIN32__
	#include <windows.h>
	#endif

	#include <stdio.h>
	#include "qdgdf_video.h"
	#include "qdgdf_audio.h"

    You won't be too much surprised here; the usual mumbo-jumbo, and the
    qdgdf header files. The #ifdef __WIN32__ is necessary for WinMain,
    because you probably don't want to get a console window attached to
    your game, and this is what you'll get if you use main(). So,

	#ifdef __WIN32__
	int __stdcall WinMain(HINSTANCE hi, HINSTANCE hpi, LPSTR cmd, int cm)
	{
		_qdgdfv_additional_int_info=(int)hi;
	#else
	int main(void)
	{
	#endif

    will work. You'll notice another strange thing: that (int)hi assignment.
    As you'll suppose, that WinMain parameter is necessary for DirectDraw
    objects; this is the last Microsoftism needed. I swore.

    Before qdgdf starting up, you need to set up some values. Here there
    you have some of them:

	/* use 16 bit sound whenever possible */
	_qdgdfa_16_bit=1;
	/* use 320 x 200 resolution */
	_qdgdfv_screen_x_size=320;
	_qdgdfv_screen_y_size=200;
	/* the clear color */
	_qdgdfv_clear_color=0;
	/* window title(s) */
	strcpy(_qdgdfv_window_title, "awesome qdgdf based game");
	strcpy(_qdgdfa_window_title,_qdgdfv_window_title);

    And then, the real startup:

	qdgdfa_startup();
	qdgdfv_startup();

    Wow. You'll ready for doing game things; let's start another step.

5.- Of course, you need to load the bitmaps and sounds you have ready for
    that game. Load the pictures with:

	qdgdfv_load_pcx(good_guy,"good_guy.pcx",16*16);
	qdgdfv_load_pcx(bad_guy,"bad_guy.pcx",16*16);
	qdgdfv_load_pcx(background,"the_deep_space_background.pcx",512*300);

    of course, you must have that 16*16 and 512*300 space previously
    allocated in that char * variables.

    Loading sounds isn't harder:

	shoot_sound=qdgdfa_load_sound("gun_shot.wav");
	player_die_sound=qdgdfa_load_sound("aaaarrrgh.wav");
	evil_laugh_sound=qdgdfa_load_sound("muaaahahaha.wav");

    that variables are int,s.

6.- Let's start to loop:

	/* while player is alive (this variables are yours) */
	while(_player_alive && !_aborted)
	{
		/* clear the virtual screen */
		qdgdfv_clear_virtual_screen();

		/* poll the input system */
		qdgdfv_input_poll();

		/* test the keys that were hit */
		if(_qdgdfv_key_escape)
			_aborted=1;

		/* do whatever you must;
		   _some_variable and _do_fire() are yours */
		if(_qdgdfv_key_left)
			_some_variable--;
		if(_qdgdfv_key_right)
			_some_variable++;
		if(_qdgdfv_key_control_l)
			_do_fire();

		/* fill the virtual screen with whatever you want
		   (preferably the good_guy, the bad_guy, etc.) */
		/* ... */

		/* finally, dump it out over the real screen */
		qdgdfv_dump_virtual_screen();
	}

	/* game over, man!; exit cleanly */

	qdgdfv_shutdown();
	qdgdfa_shutdown();

	return(0);

7.- The rest of steps (upto 10) are for you to write your game. Filling
    the gaps and writing a non-stinking AI and plot are left as an exercise
    to the reader (you).

qdgdfv (video) quick & dirty reference
======================================

int _qdgdfv_double_mode;
int _qdgdfv_screen_x_size;
int _qdgdfv_screen_y_size;
int _qdgdfv_window_x;
int _qdgdfv_window_y;
char _qdgdfv_window_title[150];
int _qdgdfv_additional_int_info;
void qdgdfv_startup(void);
void qdgdfv_shutdown(void);

	Startup basic info. _qdgdfv_screen_x_size and _qdgdfv_screen_y_size
	define the wanted window (or screen) dimensions; _qdgdfv_window_x
	and _qdgdfv_window_y specify the original position of the window
	(of course, this is meaningless in full screen mode).
	_qdgdfv_double_mode, qdgdfv_window_title and
	_qdgdfv_additional_int_info act as described before. Please note
	that _qdgdfv_screen_x_size and _qdgdfv_screen_y_size values after
	calling qdgdfv_startup() can be different from what you filled
	them with (you must obey these values and not assume yours).

int _qdgdfv_palette[3*256];

	This array contains by default the qdgdf suggested palette. If you
	want to use yours, fill this array before calling qdgdfv_startup().

unsigned char * _qdgdfv_virtual_screen;
unsigned char _qdgdfv_clear_color;
void qdgdfv_clear_virtual_screen(void);
void qdgdfv_dump_virtual_screen(void);

	qdgdfv_clear_virtual_screen() fills the space pointed to by
	_qdgdfv_virtual_screen with _qdgdfv_clear_color. You can fill that
	virtual screen with whatever you want and assume it has enough
	space to hold _qdgdfv_screen_x_size * _qdgdfv_screen_y_size bytes.
	Once done, you can dump it to the real screen using
	qdgdfv_dump_virtual_screen().

int _qdgdfv_key_up;
int _qdgdfv_key_down;
int _qdgdfv_key_left;
int _qdgdfv_key_right;
int _qdgdfv_key_escape;
int _qdgdfv_key_space;
int _qdgdfv_key_enter;
int _qdgdfv_key_control_l;
int _qdgdfv_key_control_r;
void qdgdfv_input_poll(void);

	The input polling system. After a call to qdgdfv_input_pool(),
	these variables will be positive if any of the associated keys are
	down.

void qdgdfv_load_pcx(unsigned char * pcx, char * pcxfile, int size);

	This routine allows to load 256 color PCX files. The array pcx
	must point to a size buffer (you must allocate it or have it
	static). The file to load is pcxfile. The palette inside these
	files is ignored; if it is not the same than the one defined in
	_qdgdfv_palette[], the results will be undetermined (and, very
	possibly, funny looking).

int _qdgdfv_use_logger;
char _qdgdfv_logger_file[150];
void qdgdfv_logger(char * where, char * msg);

	qdgdfv includes a simple logger to make life easier. If you set
	_qdgdfv_use_logger to 1 and _qdgdfv_logger_file[] to some file
	name, you will be able to do some logging with qdgdfv_logger().

void volatile qdgdfv_bang(char * where, char * msg);
void * qdgdfv_malloc(int size);
FILE * qdgdfv_fopen(char * file, char * mode);

	qdgdfv_bang() just bangs (write a message and exit to system).
	qdgdfv_malloc() and qdgdfv_fopen() are just convenience routines
	that bang when unsuccesful.

qdgdfa (audio) quick & dirty reference
======================================

int _qdgdfa_sound;
char _qdgdfa_window_title[150];
int _qdgdfa_16_bit;
void qdgdfa_startup(void);
void qdgdfa_shutdown(void);

	Startup stuff. _qdgdfa_sound, when set to 0, just disable the
	whole thing. _qdgdfa_16_bit is usually set to 1 to use, whenever
	possible, 16 bit audio mode; if you don't want to use it (I
	don't know why you could want this), just set it to 0. If, after
	all, the sound card is just an 8 bit one or the 16 bit hardware
	could not be initialized, this variable will have a 0 after
	calling qdgfa_startup(). Remember to set _qdgdfa_window_title[] to
	the title the game window has, as previously described.

int qdgdfa_load_sound(char * wavfile);

	Loads the wavfile, that must be 8/16 bit mono at 11025 Hz. If
	succesful, a positive integer is returned, that can be used to do
	whatever possible things with a sound can be done.

void qdgdfa_play_sound(int snd, int loop);
void qdgdfa_stop_sound(int snd);
void qdgdfa_set_pan(int snd, int pan);

	These routines do obvious things with a sound. If loop is 1, the
	sound is played in a neverending, at-nauseam loop play. pan can
	be -1, 0 or 1 if you want the sound to be left, center o right
	channel biased.

void qdgdfa_reset(void);
void qdgdfa_pause(int p);

	qdgdfa_reset() resets all the sound system, unloading all sound
	files from memory. All sound file descriptors become invalid.
	qdgdfa_pause() just pauses/unpauses all sound.

Misc Notes
==========

 - Wouldn't it be good to have framebuffer / svgalib versions?

 - You can pick the qdgdf palette from the bitmap in bola.pcx ('bola' is
   the main character from a very old, never finished game).

 - This is a quick and dirty work, but you can bet that it works.

---
Angel Ortega http://www.triptico.com
