The building of caveman part 4 - The Z game library

posted in Caveman
Published April 20, 2014
Advertisement
The Building of Caveman - Part 4

Z3D - The low level generic game development library




So far i had a wrapper for the dx9 fixed function pipeline, and a
render queue and state manager desigend to feed data to the pipeline
in optimal order for fastest performance. The render queue allows
the game to make drawing callis in a more of less arbitrary order.

But it takes much more than a render queue and state manager to
build a game. additional componets required included:

* fonts
i went with d3dx fonts at first. later, i switched
to a custom font using faster d3dx sprites.

* materials
d3d lighting equations are complex and powerful.
i decided to control lighting primarily via materials to simplify things.
the game uses a database of about 8 materials. everything from dirt to
emissive beacon. Some materials such as plant specular and clouds vary
depending on time of day. A fair amount of time was spent tweaking the
lights and materials for the best lighting behavior possible with the
limited capabilites of dx9 fixed function.
A side benefit of controlling lighting
through materials is the ability to adjust brightness by simply scaling
material values. This avoids the "washed out" look of using gamma to
adjust brightness.

* textures
i created a textures database. a simple array of d3dx9 texture pointers.
it includes routines for creating, loading, and saving textures.
It supports solid and alpha tested textures with or without mipmaps,
as well as alpha blended textures with mipmaps.
textures are refereced via their array index (Texture ID).

* meshes
again, a simple database. d3dxmesh pointers at first, later replaced by
a struct with a vb, ib, numverts, and numtris. references are via
index # (Mesh ID).

* multi-mesh models
since the game uses one texture per mesh for speed, two textures means
two separate meshes. so a rigid body modeling system was created.
It was also required for the rigd body charater animation system.
Caveman uses rigid body animation instead of skinned meshes.
This allows it to draw about five times as many characters on
screen at once.
So a models database was required to hold the model data.
its an array of structs, obe for each type of model.
a struct contains info like the number of limbs, and the mesh, texture,
scale, location, parent, etc, of each limb.
As with all the content databases in the game, reference is via
array index # (model #).

* animations
animations are keyframe in style, and manipulate the limbs of
a multi-mesh model. the game has a database of animations (array
of structs). each struct contains info like number of keyframes,
limb rotations for each keyframe, number of frames between keyframes,
etc.

* animation players.
an animation player takes an animation, and a model, and an animation
frame counter, and tweens the model for drawing. animation players are
assigned to bandmemebrs, animals, and npc's when they start an animation.
the game contains an array of 200
animation players - an "animation manager".
a animation player is just a struct with info like an "active" field,
animation #, model #, and framecounter.

* sprites
d3dx sprites, with some wrapper routines to provide an api like:
drawsprite x,y, x scale, y scale
where x,y is the upper left corner, and the scale values are
0.0 through 1.0 inclusive. sprites use the textures database.

* gui components
a popup menu, and a text entry dialog box. the popup menu can
double as a message dialog box, just make the last option "ok",
and repeat until they select "ok". everything else is custom
screens done with sprites and fonts. thankfully there are very
few custom screen required - less than a dozen. menu() and
getstring() handle all the rest. There is also a text file
viewer for help. the menu system uses an array of strings.
the game calls Znewmenu(title_string) to begin assigning text
to a menu to be displayed. it then calls Zaddmenu(option_text)
to add text for menu options it then calls pick=menu(num_options)
to get a menu pick (option #).

* lights
Caveman tries to do simple to implement and fast yet realitic
lighting within the limitations of DX9 fixed function. It uses
a single directional light for sunlight and moonlight. point
lights with a small radius are used for fires and torches. These
are the only lights used. sun and moon light are varied based
on time of day and cloud cover. Lighting is primarily controlled
via materials, with an overall lightness_factor() being the only
variation in actual light settings, and then only for the sun/moon
light. Light settings for rendering scenes were determined first,
then materials were adjusted to get the desired behavior, with
new materails added as new behaviors were required. Light settings
are heavy on the diffuse, and very light on the ambient for a more
realistic look.


many other low level genric routines are reqiured for games:
math functions
file i/o
high resolution timers
keyboard input
mouse input
etc.

in the past, i've collected such routines into a generic game
development library that i've both used in-house and sold publicly
(passes the dog food test! ).

so i proceeded to round out my graphics code with the additional
generic low level stuff required. The result is the latest
incarnation of Rockland Software Productions game development
library. This version is called the Z game library.

the Z3D module is the main module, containing the graphics and
generic game code. There's also an audio module, and a
modeler / animation editor module. The are also experimental
modules for fonts, gui components, a "game engine", an entities
list with AI routines, and a directx 11 version of the Z library.

here's the API for the Z3D module:
// Z3D.h #ifndef z3d_h#define z3d_h #include #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers#include #include #include #include //####################### PUBLIC GLOBAL DEFINITIONS ################################## #define pi D3DX_PI //################## PUBLIC GLOBAL VARIABLES ##################################################### extern HWND Zprogram_window_handle; extern int Zalphatestlvl; extern int mousewheel; // d3d font objectsextern ID3DXFont *pFont;extern ID3DXFont *pFont2;extern ID3DXFont *pFont3; // d3d sprite objextern ID3DXSprite *Zsprite; extern D3DPRESENT_PARAMETERS Zparams;extern LARGE_INTEGER Ztimer_freq; extern int Ztrace[20]; extern DWORD Znum_verts,Znum_primitives; extern int Zcurrentmesh,Zcurrenttex; extern int old_mousex,old_mousey; //######################### MATERIALS ##################################### #define ZMAXMATERIALS 10 extern D3DMATERIAL9 Zmaterial[ZMAXMATERIALS]; void Zsetmaterial(int materialID); void Zinit_materials(); void Zload_materials(); // load materials from materials.dat file //############################# MENU STRINGS ################################### #define MaxMenuStrings 50#define MenuStringLength 100 extern char Zmenu[MaxMenuStrings][MenuStringLength]; // menu stringsextern int LastMenuOption; void Zgetstring(char *s,char *s2);int Zdomenu(int mousetex);void Zclearmenu();void Zaddmenu(char *s);void Znewmenu(char *s); // clear + addint Zmenu_char_width(int i); // returns menu width in chars //############################# SPRITES ###################################### extern ID3DXSprite *Zsprite; // d3d sprite obj void Zbeginsprite();void Zendsprite();void Zdrawsprite(int texID,int x,int y,float sx,float sy); // x,y are UL corner of spritevoid Zdrawsprite2(int texID,int x,int y,float sx,float sy,float rz); // draw a rotated sprite. x,y are screen coords of the center.void Zflushsprites(); //########################## tex DB ############################################ #define Zmaxtextures 400 struct Ztexrec{char name[100];LPDIRECT3DTEXTURE9 tex;}; extern Ztexrec Ztex[Zmaxtextures];extern int numtextures; void Zloadtex(char *s);void Zloadbitmap(char *s);void Zloadsprite(char *s);void Zload_dynamic_bitmap(char *s);void Zloadspritetex(char *s); // alpha transparencyvoid Zloadspritetex2(char *s); // alpha transparency, 5 mip lvls in dds file.void Zloadspritetex3(char *s); // colorkey transparencyvoid Zunload_last_bitmap(); void Zload_textures(); //########################### mesh DB ########################################### #define maxmeshes 300 struct Zmesh{IDirect3DVertexBuffer9 *vb;IDirect3DIndexBuffer9 *ib;int numverts,numfaces;}; // meshDB recordstruct meshrec{char name[100];//LPD3DXMESH mesh;Zmesh mesh2;}; // mesh DBextern meshrec mesh[maxmeshes]; void Zloadmesh(char *s,int dynamic); // dynamic = 0 or 1. extern int DBnummeshes; void Zload_meshes(); void optimize_meshes(); //######################### DRAWLIST ################################################# struct Zdrawinfo{int type, // 0=mesh, 1=model, 2=2d billboard, 3=3d billboardmeshID, // for models: modelID texID, // for models: aniID alphatest,cull,clamp,materialID,rad,cliprng,data[5];float sx,sy,sz,x,y,z,rx,ry,rz,range; // range is rng to camera. not currently used.D3DXMATRIX mWorld;}; extern int Znumdrawrecs;//extern int alphatest_numdrawrecs; void Zcleardrawlist(); void Zcdi(Zdrawinfo *a); // "ZClearDrawInfo". memset's a Zdrawinfo struct to 0. void Zdraw(Zdrawinfo *info);void Zdraw2(Zdrawinfo *info);void Zd(Zdrawinfo *b); // draw mesh, model, 2d billbaord, or 3d billboard void Zdrawlist(); void Zpresent();int Zshowscene(); // 1=success 0=failure //############################# models ################################################### #define maxlimbs 20 // limb recordstruct limbrec{int parent,meshID,texID,alphatest; // parent = index of parent limb. -1=no parent.float x,y,z,xr,yr,zr,sx,sy,sz; // location of limbs origin (in parent's coords). current orientation of limb.float xr0,yr0,zr0; // "at rest" orientation of the limbchar name[20];}; // model recordstruct modelrec{int numlimbs;limbrec limb[maxlimbs];char name[20];}; void Zdrawmodel(Zdrawinfo *info); // meshID=modelID. uses x,y,z,xr,yr,zr.void Zdrawmodel2(Zdrawinfo *info); // meshID=modelID. uses mWorld. //################################### models datatbase ########################################## #define maxmodels 200extern modelrec model[maxmodels];extern int nummodels; void loadmodel(char *s);void savemodel(int modelID,char *s); void Zload_models(); // load models from models.dat file //####################### animations ################################################ #define maxkeyframes 20 // a 3d vector (position, orientation, etc)struct xyzrec{float x,y,z;}; // keyframe recordstruct keyframerec{int numframes,numlimbs;xyzrec rotation[maxlimbs];}; // animation recordstruct anirec{int numkeyframes;keyframerec keyframe[maxkeyframes];}; int startani(int aniID,int modelID);void stopani(int playerID);int set_animation_frame(int playerID); // animation player recordstruct aniplayerrec{int active,aniID,modelID,curkeyframe,curframe;}; #define maxaniplayers 200 // animation playerextern aniplayerrec aniplayer[maxaniplayers]; //############################ animations DB #################################### #define maxanimations 200 extern anirec animation[maxanimations];extern int numanimations; void loadani(char *s);void saveani(int aniID,char *s); void Zload_anis(); // load anis from anis.dat file //########################## MATRIX MANIPULATOR ################################ extern D3DXMATRIX Mmat;void Mstart();void Mrotate(int axis,int degrees);void MrotateRADS(int axis,float radians);void Mmove(float x,float y,float z);void Mscale(float x,float y,float z);void Mtrans(float *x,float *y,float *z); // transform point x,y,z by matrix Mmat //#################### STRING MANIPULATOR ################################# extern char S[1000];void Ss(char *s2);void Sa(char *s2); // string add intvoid Sai(int i); // string add floatvoid Saf(float f); //###################### GRAPHICS ENGINE ######################################### const DWORD ZFVF=(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) ); // D3DFVF_DIFFUSE | D3DFVF_SPECULAR | /*struct Zvertexrec{float x,y,z;float nx,ny,nz;float tu,tv; DWORD diffuse,specular;};*/ struct Zvertexrec{D3DVECTOR position,normal;//D3DCOLOR diffuse,specular;float tu,tv;}; extern IDirect3DDevice9 *Zd3d_device_ptr; extern D3DXMATRIX ZmView; // view matrixextern D3DXMATRIX Zprojection_matrix; // projection matrixextern float Zcamx,Zcamy,Zcamz,Zcamxr,Zcamyr,Zcamzr; // camera position int Zinit(HINSTANCE program_instance_handle,int width,int height,char *progname,float nearplane,int farplane); // ,int zbuf24bit);void Zshutdown();void Zsetlite(DWORD liteID,float x,float y,float z,float brightness);void Zsetcam(float x,float y,float z,float rx,float ry,float rz);void Zsetcam2(float x,float y,float z,D3DXMATRIX *m); // m is rot matrixvoid Zclearscreen(int r,int g,int b);void Zclearscreen2(); // clears screen to z game engine default color (blacklight)void Zclearzbuf();void Zbeginscene();void Zambient(int r,int g,int b);void Zlighting(int onoff);void Zalphablend(int onoff);void zbuftest(int onoff);void zbufwrite(int onoff);void Zcull(int onoff);void Znormalize(int onoff);void Zlite(DWORD liteID,int onoff);void Zalphatest(int onoff);void Zmipmaps(int onoff);void Zclamp(int onoff);//void Zanisotropic(int onoff);void Zminmagfilter(int filter_type); // filter_type: 0=point, 1=linear, 2=anisotropicvoid Zspecular(int onoff); int Zsuperclip(int x,int y,int z,int rad,int cliprng); void Zset_clip_planes(float nearplane,int farplane); void Zcalc_frustum_planes(); // must set proj and view mats first! int Zsuperclip2(int x, int y, int z, int rad, int cliprng); // must call Zcalc_frustum_planes first! int Zarea_in_frustum(int x1,int z1,int x2,int z2); // must call Zcalc_frustum_planes first! void Zsetmesh(int meshID); void Zcreate_mesh(int vbsize,int ibsize); void Zsettex(int texID); void Zdrawimmediate(Zdrawinfo *a); void Zdrawimmediate2(Zdrawinfo *a); // uses Zdrawinfo's mWorld mat void Zcalc_frustum_planes2(); // rotation only //############################ TEXT ######################################## void Ztextcolor(int r,int g,int b);void Ztext(int x,int y,char *s);void Ztext3d(int x,int y,char *s);void Zsetfont(int font); // 0=comic ms sans 1= ariel 2=times new romanint textwidth(char *s); // returns width of string s in pixels. uses current font setting. //################################ MOUSE ######################################### void Zgetmouse(int *x,int *y,int *b);void Zputmouse(int x,int y);void nobutton();void pause(); //########################## WINDOWS MESSAGE PROCESSOR ############################ void Zdomessages(); //########################### GENERIC GUI COMPONENTS ################################### void Zmsg(char *s,char *title);void Zmsg2(char *s); //############################ KEYBOARD ########################################## int Zkeypressed(int vkey); //####################### STRING CONVERSION ROUTINES ############################# int s2i(char *s);void i2s(int i, char *s);void f2s(float f,char *s);float s2f(char *s); //############################ DICE ###################################### int dice(int a);void initdice(); //####################### TIMERS ######################################## void Zstarttimer(int a);int Zelapsedtime(int a);int Zelapsedticks(int a); //####################### FILEIO ########################################## // general int filefound(char *s);int filesize(char *s);time_t timestamp(char *s); // returns file create time (UTC format: secs since 1970). returns -1 if file not found.void closefile(FILE *f); // text file i/o FILE* infile(char *s); FILE* outfile(char *s); int readfile(FILE *f,char *s); // returns: 0=fail 1=successint readfileint(FILE *f);float readfilefloat(FILE *f); void writefile(FILE *f,char *s);void writefileint(FILE *f,int i);void writefilefloat(FILE *f,float i); // binary file i/o FILE* infilebin(char *s);FILE* appendfilebin(char *s); FILE* outfilebin(char *s); int readfilebin(FILE *f,unsigned char *buf,int numbytes); // returns numbytes readint readFBint(FILE *f);float readFBfloat(FILE *f); void writefilebin(FILE *f,unsigned char *buf,int numbytes);void writeFBint(FILE *f,int a);void writeFBfloat(FILE *f,float a); //####################### GENERIC MATH ROUTINES ############################# int isin(int x,int y,int x1,int y1,int x2,int y2);int dist(int x1,int z1,int x2,int z2); // diamond bounding box distint dist3d(int x1,int y1,int z1,int x2,int y2,int z2);int BBdist(int x1,int z1,int x2,int z2); // sq bounding box distfloat deg2rad(float deg);float rad2deg(float rad);int heading(int x1,int z1,int x2,int z2);int relheading(int x1,int z1,int h1,int x2,int z2);void llim(int *a,int b);void ulim(int *a,int b);void limit(int *a,int b,int c); // 0 degrees = up. 90 degrees = forward. 180 degrees = down. int angle(int x1,int y1,int z1,int x2,int y2,int z2);int rng2D(int x1,int z1,int x2,int z2);int BBdist3d(int x1,int y1,int z1,int x2,int y2,int z2); // 3d bounding box distancevoid normangl(float *a); // normalize angle to 0 to 2 pifloat rng3d(float x1,float y1,float z1,float x2,float y2,float z2); //################################ TEXT COLORS ############################### void redtext();void greentext();void bluetext();void yellowtext();void magentatext();void cyantext();void whitetext();void blacktext();void greytext(); // ################################### mouse aimed camera ################################### void Zresetmouse(); extern float cam_xr;extern float cam_yr; int Zmouse_aim_camera(); // returns mouse button pressed: 0 none, 1 LB, 2 RB, etc. // load meshes and textures using a list of filenames stored on disk in a text file //################################## SCREEN DUMP ############################################## void Zscreendump(); //############################ TARGET LIST ######################################################### // #################################################### TARGET LIST DATA STRUCTURES ##################################################### #define stepsize 0.1f struct ttyperec // a target type record{float maxspd,turnrate;int ai,rad,hp,mass,canfly,userID,value,animated,usefuel,maxfuel;Zdrawinfo d;}; struct tgtrec{float x,y,z,xr,yr,spd;int type,dp,owner,fuel,alive,active,userID,aniplayerID,dontdraw;}; #define maxttypes 50#define maxtgts 200 extern ttyperec ttype[maxttypes]; // target types database extern tgtrec tgt[maxtgts]; // targets database extern int numtgts; // index of last active tgt + 1. // max possible number of active tgts at the moment. // search tgt list using: for a=0 a


Note that Caveman uses its own custom target list, AI,
skybox, mouse aimed camera, fonts, screen dump, FPS meter,
ground drawing code, and buttons. The genric GUI components
are only used for error messages during startup before going
fullscreen 3d.


part 3:
https://www.gamedev.net/blog/1730/entry-2259520-the-building-of-caveman-part-3-getting-a-handle-on-directx/
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement
Advertisement