Reviews & Opinions
Independent and trusted. Read before buy Conitec 3D Gamestudio - Source Development!

Conitec 3D Gamestudio - Source Development


Bookmark
Conitec 3D Gamestudio - Source Development

Bookmark and Share

 

Conitec 3D Gamestudio - Source DevelopmentAbout Conitec 3D Gamestudio - Source Development
Here you can find all about Conitec 3D Gamestudio - Source Development like manual and other informations. For example: review.

Conitec 3D Gamestudio - Source Development manual (user guide) is ready to download for free.

On the bottom of page users can write a review. If you own a Conitec 3D Gamestudio - Source Development please write about it to help other people.
[ Report abuse or wrong photo | Share your Conitec 3D Gamestudio - Source Development photo ]

 

 

Manual

Preview of first few manual pages (at low quality). Check before download. Click to enlarge.
Manual - 1 page  Manual - 2 page  Manual - 3 page 

Download (English)
Conitec 3D Gamestudio-source Development, size: 214 KB

 

Conitec 3D Gamestudio - Source Development

 

 

User reviews and opinions

<== Click here to post a new opinion, comment, review, etc.

Comments to date: 7. Page 1 of 1. Average Rating:
eric_credou 9:55pm on Saturday, May 15th, 2010 
I have used Windows as long as I can remember. I always look forward to the next OS microsoft is working on.
gmmclean 12:31pm on Thursday, May 6th, 2010 
I had alot of success with the old version when it came down to video editing and photoshop. You can change the wallpaper to whatever you want none
salv236 10:33pm on Thursday, April 15th, 2010 
We bought the Apple Mac OS X 10.5 Leopard recently. This cost a little under £1K from PC World (there are other outlets).
dkotarba 10:02am on Monday, April 12th, 2010 
Leopard combines what an operating system needs to be with a shiny new interface that is both eye candy and important.
raj_open 9:27am on Friday, April 9th, 2010 
A question I would like to know if somebody can help me. I bought an Apple MacBook Pro MC118LL/A 15.
ionnek 11:59am on Wednesday, April 7th, 2010 
Leopard combines what an operating system nee...  Leopard is yet another superb operating system from Apple. Leopard combines what an operating system needs to be with a shiny new interface that is both eye candy and important.
dgaspary 4:05pm on Friday, April 2nd, 2010 
This was an upgrade in OS for my machines, and everyone saw performance improvements.

Comments posted on www.ps2netdrivers.net are solely the views and opinions of the people posting them and do not necessarily reflect the views or opinions of us.

 

Documents

doc0

// zooms the camera view fixed ZoomIn(fixed value) { A4_VIEW *camera = (A4_VIEW *)a5dll_getwdlobj("camera"); return (camera->arc -= value); // change the FOV and return it }
"Camera" is our main predefined view. Because a5dll_getwdlobj returns a long integer, you have to cast it to the desired type, as through the (A4_VIEW *) cast operator here. As you can see in the struct declarations in a5dll.h, the A4_VIEW struct contains all the parameters that you are used from C-Script, like arc, ambient etc., and once you have the pointer you can change and read
all of them. So now we know how to access all C-Script objects, and call DLL functions from C-Script. But how do we do the opposite calling engine and C-Script functions from a DLL?

Using the API

Accessing C-Script functions is done in a similar way like accessing C-Script objects, through:
long a5dll_getwdlfunc(char *name);
This function returns the address of the C-Script instruction with the given name. It can be used to call engine functions from inside a DLL plugin. Not all C-Script instructions are available for DLLs. If the instruction is not available because it makes no sense in a DLL (like wait() or inkey()), NULL is returned and an error message will pop up. Example for an entity AI DLL function that uses C-Script functions for scanning the environment of an entity:
// returns free distance in front of MY entity until next obstacle fixed DistAhead(long p_ent) { if (!my) return 0; // retrieve the pointer to the given entity A4_ENTITY *ent = (A4_ENTITY *)p_ent; // get the address of some script variables and functions fixed *tracemode = (fixed *)a5dll_getwdlobj("trace_mode"); wdlfunc2 vecrotate = (wdlfunc2)a5dll_getwdlfunc("vec_rotate"); wdlfunc2 trace = (wdlfunc2)a5dll_getwdlfunc("trace"); fixed target[3] = { FLOAT2FIX(1000.0),0,0 }; // trace target vector // rotate vector by entity engles, just as in C-Script (*vecrotate)((long)target,(long)&(ent->pan)); // add entity position to target target[0] += ent->x; target[1] += ent->y; target[2] += ent->z; // set trace_mode, then trace a line between entity and target, // and return the result *tracemode = INT2FIX(TRM_IGNORE_ME + TRM_IGNORE_PASSABLE + TRM_USE_BOX); return (*trace)((long)&(ent->x),(long)target); }
Let's examine the important part of the code in detail:
wdlfunc2 vecrotate = (wdlfunc2)a5dll_getwdlfunc("vec_rotate");
wdlfunc2 is a convenience typedef for a pointer to a C-Script instruction that takes 2 arguments.

Because all C-Script instructions take either 1, 2, 3, or 4 arguments, there are 4 such typedefs in the a5dll.h:
fixed fixed fixed fixed (*wdlfunc1)(long); (*wdlfunc2)(long,long); (*wdlfunc3)(long,long,long); (*wdlfunc4)(long,long,long,long);
typedef typedef typedef typedef
Once we've gotten the pointer to that instruction again, it's recommended to retrieve pointers to all used instructions in a startup function we can just call it:
// rotate vector by entity engles, just as in C-Script (*vecrotate)((long)target,(long)&(ent->pan));
This looks a little different than you are used to call a function in C++! However, it's quite straightforward: We have a pointer to that function, so for calling the function itself we have to use the (*.). And the arguments passed are always fixed or long. We have casted them to long instead of fixed as a convention to indicate that we are passing pointers. All vector instructions expect pointers to fixed. All this pointer handling and typecasting may seem a little complicated at first, but because it's logical you'll fast get the grip of it.
What if a C-Script instruction expects not a vector or value, but something more complicated like an entity? Well, we'll then just pass the A4_ENTITY pointer casted to long. And what if it expects a string must we really use a pointer to A4_STRING or can we just pass char*? We must use A4_STRING I'm afraid. But in the example ackdll.cpp you can find an easy way how to pass a string constant to a C-Script instruction:
long pSTRING(char* chars) // convenience function to make string passing easy { static A4_STRING tempstring; static char tempname[256]; strncpy(tempname,chars,255); tempstring.chars = tempname; return (long)&tempstring; } // example for passing a string to create an entity DLLFUNC fixed create_warlock(long vec_pos) { wdlfunc3 ent_create = (wdlfunc3)a5dll_getwdlfunc("ent_create"); return (*ent_create)(pSTRING("warlock.mdl"),vec_pos,0); }

Some special C-Script functions, like keyboard entry, can not be called directly from a DLL. However they can be executed indirectly by calling a script that executes that function. Scripts can be called from a DLL through the following functions:
long a5dll_getscript(char *name);
This function returns an addresss of the user-defined script function with the given name. It can be used to call user defined C-Script actions or functions from inside a DLL plugin. If the function is not found, NULL is returned and an error message will pop up.
fixed a5dll_callscript(long script,long p1=0,long p2=0,long p3=0,long p4=0); fixed a5dll_callname(char *name,long p1=0,long p2=0,long p3=0,long p4=0);
These functions call a user-defined script function with given address or given name. The 4 parameters can be a fixed point number, an array, or a pointer to a C-Script object. If the function expects less than 4 parameters, the superflous ones can just be set a 0. Example for a DLL function that calls a function that must be defined in the C-Script code:
DLLFUNC fixed WDLBeep(fixed value) { // get the function long beeptwice = a5dll_getscript("beeptwice"); // call it return a5dll_callscript(beeptwice,0,0,0,0); }
This DLL function expects the following function in the C-Script which is then called:
function beeptwice() { beep; beep; } // in the script
Now that we have learned to access every part of C-Script by a DLL and vice versa, let's continue with some special applications for DLL functions.

Using Direct3D functions

The following example shows how easy it is to use Direct3D functions for creating some effects on the screen. As all initialization is done by the engine, it is sufficient just to call the draw functions. All Direct3D functions are accessed through a LPDIRECT3DDEVICE8 pointer that is available through the DLL. For details refer to the DirectX documentation that is available, along with the DirectX 8.1 SDK, from the Microsoft site. The example paints a multicolored triangle onto the screen. You'll see the triangle briefly flashing in the upper left corner when you call PaintD3DTriangle() once. If you call it in a wait(1)-loop, the triangle will be permanently on the screen.
#include <d3dx8.h> // from the DIRECTX8.1 sdk // dllfunction PaintD3DTriangle(); // draws a red/blue/green triangle in D3D mode DLLFUNC fixed PaintD3DTriangle (void) { // get the active D3D device LPDIRECT3DDEVICE8 pd3ddev = (LPDIRECT3DDEVICE8) a5dx->pd3ddev8; if (!pd3ddev) return 0; // define a suited vertex struct struct VERTEX_FLAT { float x,y,z; float rhw; D3DCOLOR color; }; #define D3DFVF_FLAT (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) // define the three corner vertices VERTEX_FLAT v[3]; v[0].x = 10.0; v[0].y = 10.0; v[0].color = 0xFFFF0000; // the red corner v[1].x = 310.0; v[1].y = 10.0; v[1].color = 0xFF0000FF; // the blue corner v[2].x = 10.0; v[2].y = 310.0; v[2].color = 0xFF00FF00; // the green corner v[0].z = v[1].z = v[2].z = 0.0; // z buffer - paint over everything v[0].rhw = v[1].rhw = v[2].rhw = 1.0; // no perspective // begin a scene - needed before D3D draw operations pd3ddev->BeginScene(); // set some render and stage states (you have to set some more, normally) pd3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE); pd3ddev->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE); pd3ddev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG2); // now draw the triangle pd3ddev->SetVertexShader(D3DFVF_FLAT); pd3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,1,(LPVOID)v,sizeof(VERTEX_FLAT)); // do not forget to do a clean closing of the scene pd3ddev->EndScene(); return 0; }

Note: Depending on the 3D hardware, sometimes A5 has to release and reallocate the Direct3D device when the video output is switched between window and fullscreen mode. If you use the pd3ddev8 for allocating an object, like a texture or a buffer, you have to release the object before switching video, and recreate it afterwards. Otherwise the device can't be released and you'll receive an Uninitialized Device error message. Particle functions DLL functions can also be used for particles, using the A4_PARTICLE struct defined in a5dll.h. They can be used the same way as C-Script defined particle functions. A pointer to the particle is the sole argument of a DLL particle function. Example:
// examples for a particle effect function // dllfunction DLLEffect_Explo(particle); // dllfunction DLLPart_Alphafade(particle);
// start the particle effect by // effect(DLLEffect_Explo,1000,my.x,nullvector); fixed *var_time = NULL; long func_alphafade = 0; // helper function: fades out a particle DLLFUNC fixed DLLPart_Alphafade(long particle) { if (!var_time || !particle) return 0; A4_PARTICLE* p = (A4_PARTICLE*) particle; p->alpha -= *var_time * 2; if (p->alpha <= 0) p->lifespan = 0; return 0; } // helper function: return a random float float random(float max) { return (float)(rand()*max)/(float)RAND_MAX; }
// particle effect: generate a blue explosion DLLFUNC fixed DLLEffect_Explo(long particle) { if (!particle) return 0; // initialize time var and alphafade function (must only be done once) if (!var_time) var_time = (fixed *)a5dll_getwdlobj("time"); if (!func_alphafade) func_alphafade = a5dll_getscript("DLLPart_Alphafade"); A4_PARTICLE* p = (A4_PARTICLE*) particle; // initialize particle parameters p->flags |= EPF_STREAK|EPF_MOVE|ENF_FLARE|ENF_BRIGHT; p->vel_x = FLOAT2FIX(random(10) - 5); p->vel_y = FLOAT2FIX(random(10) - 5); p->vel_z = FLOAT2FIX(random(10) - 5); p->red = 0; p->green = 0; p->blue = INT2FIX(255); p->alpha = FLOAT2FIX(50 + random(50)); p->function = func_alphafade; return 0; }
Sending information over the network The SDK can use A5's send and receive functions for sending user-defined messages in a multiplayer environment. For this, the SendPacket and ReveivePacket function pointers are available via the ENGINE_INTERFACE:
typedef struct { byte *save_block;// pointer to block of variables for save/load (not used) int save_size; // size of block of variables for saving (not used) long (*Exec)(long n,long p1,long p2,long p3); // DLLLIB internal use only // only available in A5.51 or above - first packet byte must be 17 (0x11) for user defined packets void (*SendPacket)(long to,void *data,long size,long guaranteed); // the send function of the engine void (*ReceivePacket)(long from,void *data,long size); // user provided function } ENGINE_INTERFACE;

SendPacket sends a user defined packed from the client to the server, or vice versa.
Parameters: to - Identifier number for the client to receive the message. Set to 0 for sending to all clients. data - Data packet to be sent. First byte must be 17 (0x11) for identifying a user-defined packet. size - Size of the packet in bytes. guaranteed - set to 1 for TCP/IP mode, 0 for UDP mode.
ReceivePacket can be set to a user provided void(long,void*,long) function that receives and interprets messages sent with SendPacket.
Parameters: from ID Number of the sender. If at 0, the message was received from the server. data - Data packet to be sent. First byte is always 17 (0x11) for identifying a user-defined packet. size - Size of the packet in bytes. Note that the receive function should be very short and mainly just store the message, for not interfering the receive process. It must not send, open a file, render, or do anything time consuming. Programming a game in C++ Using the A4_ENTITY object (see below), a DLL can implement complex AI functions that would be harder to code in C-Script. Even the whole gameplay could be written in a DLL. The following example shows how to change entity parameters through a DLL function.
// rolls the given entity by 180 degrees DLLFUNC fixed FlipUpsideDown(long entity) { if (!entity) return 0; // retrieve the pointer to the given entity A4_ENTITY *ent = (A4_ENTITY *)entity; // set the entity's roll angle to 180 degrees ent->roll = FLOAT2FIX(180); return 0; }
This would be called by C-Script through FlipUpsideDown(my). For controlling entities totally through a DLL for instance, when you intend to write your whole game in C++ or Delphi, instead of C-Script C-Script dummy actions can be assigned to the entity, like this:
var appdll_handle; dllfunction dll_entmain(entity); dllfunction dll_entevent(entity); function main() { // open the application DLL appdll_handle = dll_open("myapp.dll");. } action myent_event { dll_handle = appdll_handle; dll_entevent(my); // this DLL function handles all entity events } action myentity { my.event = myent_event; while(1) { dll_handle = appdll_handle; dll_entmain(my); // this DLL function controls the entity wait(1); } }

DLL interface structures and special functions
Interface structs are initialized at DLL startup for accessing essential engine variables and pointers. There are three such interfaces, which are defined in the a5dll.h: the WDL_INTERFACE a5wdl that contains C-Script access functions and he MY and YOU entity pointers, the ENGINE_INTERFACE a5eng that contains basic engine functions, and the DX_INTERFACE a5dx that contains pointers to all DirectX devices initialized by A5. Normally you'll only need the last one. For instance, a5dx>pd3ddev8 will get you the pointer to the Direct3D 8.1 device. Some utility functions are provided for manipulation of textures and entities:
A4_TEX *a5dll_tex4ent(A4_ENTITY *entity,int frame,int texnum=0);
This function returns the texture of a sprite, model or terrain entity. It can be used to directly access D3D textures (see example below). Frame is the frame or skin number, texnum the subtexture number if it is split into several subtextures.
A4_ENTITY *a5dll_entnext(A4_ENTITY *entity);
This function enumerates local entities, and can be used to access all entities in a level. If called with NULL, it returns a pointer to the first entity in the level. If called with a level entity pointer, it returns a pointer to the next level entity. If called with a pointer to the last entity or no entity at all, it returns NULL. Example for a function that uses DirectX 8.1 for painting the textures of model, sprite and terrain entities red:
// dllfunction PaintEntitiesRed(); // paints the first mipmap of all sprite and model entities red DLLFUNC fixed PaintEntitiesRed(void) { // find the first entity in the level A4_ENTITY *ent = NULL; while (1) { // find the next entity ent = a5dll_entnext(ent); if (!ent) break; // we can not be sure that the entity texture exists - it could be purged A4_TEX *tex = a5dll_tex4ent(ent,0,0); if (!tex) continue; LPDIRECT3DTEXTURE8 dx8tex = (LPDIRECT3DTEXTURE8) tex->pd3dtex; if (!dx8tex) continue; // check the texture format D3DSURFACE_DESC ddsd; if (FAILED(dx8tex->GetLevelDesc(0,&ddsd))) continue; // lock the texture and retrieve a pointer to the surface D3DLOCKED_RECT d3dlr; if (FAILED(dx8tex->LockRect(0,&d3dlr,0,0))) continue; byte *pixels = (byte *)(d3dlr.pBits); // do we have a 16 bit or 32 bit format? if (ddsd.Format == D3DFMT_A8R8G8B8) for (unsigned y = 0; y < ddsd.Height; y++ ) { DWORD *target = (DWORD *)(pixels + y*d3dlr.Pitch); for (unsigned x = 0; x < ddsd.Width; x++ ) *target++ = 0xFFFF0000; // that's red in 8888 } else if (ddsd.Format == D3DFMT_A4R4G4B4) for (unsigned y = 0; y < ddsd.Height; y++ ) { WORD *target = (WORD *)(pixels + y*d3dlr.Pitch); for (unsigned x = 0; x < ddsd.Width; x++ ) *target++ = 0xFF00; // that's red in 4444 } else if (ddsd.Format == D3DFMT_A1R5G5B5) for (unsigned y = 0; y < ddsd.Height; y++ ) { WORD *target = (WORD *)(pixels + y*d3dlr.Pitch);

for (unsigned x = 0; x < ddsd.Width; x++ ) *target++ = 0xFC00; // that's red in 1555
} else if (ddsd.Format == D3DFMT_R5G6B5) for (unsigned y = 0; y < ddsd.Height; y++ ) { WORD *target = (WORD *)(pixels + y*d3dlr.Pitch); for (unsigned x = 0; x < ddsd.Width; x++ ) *target++ = 0xF800; // that's red in 565 } // Unlock the surface again dx8tex->UnlockRect(0); } a5dll_errormessage("Entities are now red!"); return 0; }
void a5dll_errormessage(char *text);
This function pops up an Error #1527 message requester with the given text. It can be used to display diagnostic messages, or notify the user of wrong DLL calls, like with an invalid entity pointer. One final consideration. On accessing system resources like sound, video, joystick and so on, the DLL must take care of possible resource conflicts. The engine shares its resources and expects the same from the code inside the DLL. For instance, code that requires exclusive access to the sound device (like some old MOD players) won't work. Some resources (like the midi player) can't be shared - if midi music is played by the DLL, the engine must not play a midi file at the same time and vice versa.
The A5 Client/Server Protocol
The protocol is optimized for using as less bandwidth as possible. Only parameters that have changed are sent over the network. Sending a player's changed XYZ coordinate from the server to the client, for instance, needs only 12 bytes (including header). A dead reckoning mechanism is used for extrapolating positions and angles between cycles. The structure of the messages is a single-byte code, followed by code-dependant informations. When describing the content of messages, we use the following conventions:
Byte = an unsigned integer, on one byte. Short = a signed integer, on two bytes, Big Endian order (Intel order). Long = a signed integer, on four bytes, Big Endian order (Intel order). Float = a floating point number, on four bytes, Big Endian order (Intel order). Fixed = a fixed point number in 22.10 format, on four bytes, Big Endian order (Intel order). String = a sequence of characters, terminated by 0 ('\0') Angle = a short, to be multiplied by 360.0/65535.0 to convert it to degrees. Position = a coordinate packed in three bytes by dividing it by 8 CPosition = either Position or Fixed, depending on the pos_resolution variable Scale(x) = a value packed into one byte to be multiplied by x/255.0.

// // // // // // // // // // // // // // //
"MDL3", "MDL4", or "MDL5" not used 3D position scale factors. 3D position offset. not used not used number of skin textures width of skin texture, for MDL3 and MDL4; height of skin texture, for MDL3 and MDL4; number of 3d wireframe vertices number of triangles surfaces number of frames number of 2D skin vertices always 0 number of bone vertices (not used yet)
The size of this header is 0x54 bytes (84). The MDL3 format is used by the A4 engine, while the newer MDL4 and MDL5 formats are used by the A5 engine, the latter supporting mipmaps. After the file header follow the skins, the skin vertices, the triangles, the frames, and finally the bones (in future versions). MDL skin format The model skins are flat pictures that represent the texture that should be applied on the model. There can be more than one skin. You will find the first skin just after the model header, at offset baseskin = 0x54. There are numskins skins to read. Each of these model skins is either in 8-bit palettized (type == 0), in 16-bit 565 format (type == 2) or 16-bit 4444 format (type == 3). The skin structure in the MDL3 and MDL4 format is:
typedef byte unsigned char; typedef struct { int skintype; // 0 for 8 bit (bpp == 1), 2 for 565 RGB, 3 for 4444 ARGB (bpp == 2) byte skin[skinwidth*skinheight*bpp]; // the skin picture } mdl_skin_t;
In the MDL5 format the skin is a little different, because now mipmaps can be stored and the model skins have not necessarily the same size. If the skin contains mipmaps, 8 is added to the skintype. In that case the 3 additional mipmap images follow immediately after the skin image. The texture width and height must be divisible by 8. 8 bit skins are not possible anymore in combination with mipmaps.
typedef word unsigned short; typedef struct { long skintype; // 2 for 565 RGB, 3 for 4444 ARGB, 10 for 565 mipmapped, 11 for 4444 mipmapped (bpp = 2), // 5 for 8888 ARGB, 13 for 8888 ARGB mipmapped (bpp = 4) long width,height; // size of the texture byte skin[bpp*width*height]; // the texture image byte skin1[bpp*width/2*height/2]; // the 1st mipmap (if any) byte skin2[bpp*width/4*height/4]; // the 2nd mipmap (if any) byte skin3[bpp*width/8*height/8]; // the 3rd mipmap (if any) } mdl5_skin_t;
8 bit skins are a table of bytes, which represent an index in the level palette. If the model is rendered in overlay mode, index 0x00 indicates transparency. 16 bit skins in 565 format are a table of unsigned shorts, which represent a true colour with the upper 5 bits for the red, the middle 6 bits for the green, and the lower 5 bits for the blue component. Green has one bit more because the human eye is more sensitive to green than to other colours. If the model is rendered in overlay mode, colour value 0x0000 indicates transparency. 16 bit alpha channel skins in 4444 format are represented as a table of unsigned shorts with 4 bits for each of the alpha, red, green, and blue component. 32 bit alpha channel skins in 8888 format are represented as a table of unsigned long integers with 4 bytes for each of the alpha, red, green, and blue component. Note that the byte order in that case is Intel order: blue, green, red, alpha. The size width and heights of skins should be a multiple of 4, to ensure long word alignement. When using mipmaps, they must be a multiple of 8. The skin pictures are usually made of as many pieces as there are independent parts in the model. For instance, for a player, there may be several pieces that defines the body, the face, the hands, and the weapon.

Illustration 1: Samurai skin
MDL skin vertices The list of skin vertices indicates only the position on texture picture, not the 3D position. That's because for a given vertex, the position on skin is constant, while the position in 3D space varies with the animation. The list of skin vertices is made of these structures:
typedef struct { short u; // position, horizontally in range 0.skinwidth-1 short v; // position, vertically in range 0.skinheight-1 } mdl_uvvert_t;
mdl_uvvert_t skinverts[numskinverts];
u and v are the pixel position on the skin picture. The skin vertices are stored in a list, that is stored at offset basestverts = baseskin + skinsize. skinsize is the sum of the size of all skin pictures. If they are all 8-bit skins, then skinsize = (4 + skinwidth * skinheight) * numskins. If they are 16-bit skins without mipmaps, then skinsize = (4 + skinwidth * skinheight * 2) * numskins.
Illustration 2: Samurai skin with uv mapping
MDL mesh triangles The model wireframe mesh is made of a set of triangle facets, with vertices at the boundaries. Triangles should all be valid triangles, not degenerates (like points or lines). The triangle face must be pointing to the outside of the model. Only vertex indexes are stored in triangles. Here is the structure of triangles:
typedef struct { short index_xyz[3]; // Index of 3 3D vertices in range 0.numverts short index_uv[3]; // Index of 3 skin vertices in range 0.numskinverts } mdl_triangle_t; mdl_triangle_t triangles[numtris];
At offset basetri = baseverts + numskinverts * sizeof(uvvert_t) in the.MDL file you will find the triangle list. MDL frames A model contains a set of animation frames, which can be used in relation with the behavior of the modeled entity, so as to display it in various postures (walking, attacking, spreading its guts all over the place, etc). Basically the frame contains of vertex positions and normals. Because models can have ten thousands of vertices and hundreds of animation frames, vertex posistion are packed, and vertex normals are indicated by an index in a fixed table, to save disk and memory space. Each frame vertex is defined by a 3D position and a normal for each of the 3D vertices in the model. In the MDL3 format, the vertices are always packed as bytes; in the MDL4 format that is used by the A5 engine they can also be packed as words (unsigned shorts). Therefore the MDL4 format allows more precise animation of huge models, and inbetweening with less distortion.

typedef struct { byte rawposition[3]; // X,Y,Z coordinate, packed on 0.255 byte lightnormalindex; // index of the vertex normal } mdl_trivertxb_t; typedef struct { unsigned short rawposition[3];
// X,Y,Z coordinate, packed on 0.65536
byte lightnormalindex; // index of the vertex normal byte unused; } mdl_trivertxs_t;
To get the real X coordinate from the packed coordinates, multiply the X coordinate by the X scaling factor, and add the X offset. Both the scaling factor and the offset for all vertices can be found in the mdl_header struct. The formula for calculating the real vertex positions is:
float position[i] = (scale[i] * rawposition[i] ) + offset[i];
The lightnormalindex field is an index to the actual vertex normal vector. This vector is the average of the normal vectors of all the faces that contain this vertex. The normal is necessary to calculate the Gouraud shading of the faces, but actually a crude estimation of the actual vertex normal is sufficient. That's why, to save space and to reduce the number of computations needed, it has been chosen to approximate each vertex normal. The ordinary values of lightnormalindex are comprised between 0 and 161, and directly map into the index of one of the 162 precalculated normal vectors:
float lightnormals[162][3] = { {-0.525725, 0.000000, 0.850650}, {-0.442863, 0.238856, 0.864188}, {-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000}, {0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, {0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, {0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, {0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, {0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, {-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, {-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856}, {-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, {-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, {-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, {-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863}, {0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, {0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242}, {-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, {0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, {0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, {0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, {0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, {0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, {0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, {0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567}, {0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866}, {0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, {0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, {0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567}, {0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856}, {0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, {0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567}, {0.681718, -0.147621, -0.716567}, {0.850651, 0.000000, -0.525731}, {0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856}, {0.951056, -0.162460, -0.262866}, {0.147621, 0.716567, -0.681718}, {0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785}, {0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191}, {0.688197, 0.587780, -0.425327}, {-0.147621, 0.716567, -0.681718}, {-0.309017, 0.500000, -0.809017}, {0.000000, 0.525731, -0.850651}, {-0.525731, 0.000000, -0.850651}, {-0.442863, 0.238856, -0.864188}, {-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056}, {0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423}, {0.162460, 0.262866, -0.951056}, {-0.442863,-0.238856, -0.864188}, {-0.309017,-0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056}, {0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718}, {0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651}, {0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188}, {0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863}, {0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785}, {0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325}, {0.587785, -0.425325, -0.688191}, {0.000000, -0.955423, -0.295242}, {0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460}, {0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242}, {0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460}, {0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621}, {0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863}, {-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460}, {-0.850651, -0.525731, 0.000000}, {-0.716567, -0.681718, -0.147621}, {-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000}, {-0.500000, -0.809017, 0.309017}, {-0.238856, -0.864188, 0.442863}, {-0.262866, -0.951056, 0.162460}, {-0.864188, -0.442863, 0.238856}, {-0.809017, -0.309017, 0.500000}, {-0.688191, -0.587785, 0.425325}, {-0.681718, -0.147621, 0.716567}, {-0.442863, -0.238856, 0.864188}, {-0.587785, -0.425325, 0.688191}, {-0.309017, -0.500000, 0.809017}, {-0.147621, -0.716567, 0.681718}, {-0.425325, -0.688191, 0.587785}, {-0.162460, -0.262866, 0.951056}, {0.442863, -0.238856, 0.864188}, {0.162460, -0.262866, 0.951056}, {0.309017, -0.500000, 0.809017}, {0.147621, -0.716567, 0.681718}, {0.000000, -0.525731, 0.850651}, {0.425325, -0.688191, 0.587785}, {0.587785, -0.425325, 0.688191}, {0.688191, -0.587785, 0.425325}, {-0.955423, 0.295242, 0.000000}, {-0.951056, 0.162460, 0.262866}, {-1.000000, 0.000000, 0.000000}, {-0.850651, 0.000000, 0.525731}, {-0.955423, -0.295242, 0.000000}, {-0.951056, -0.162460, 0.262866}, {-0.864188, 0.442863, -0.238856}, {-0.951056, 0.162460, -0.262866}, {-0.809017, 0.309017, -0.500000}, {-0.864188,-0.442863, -0.238856}, {-0.951056,-0.162460, -0.262866}, {-0.809017, -0.309017, -0.500000}, {-0.681718, 0.147621, -0.716567}, {-0.681718, -0.147621, -0.716567}, {-0.850651, 0.000000, -0.525731},

{-0.688191, 0.587785, -0.425325}, {-0.587785, 0.425325, -0.688191}, {-0.425325, 0.688191, -0.587785}, {-0.425325,-0.688191, -0.587785}, {-0.587785,-0.425325, -0.688191}, {-0.688197,-0.587780, -0.425327} };
A whole frame has the following structure:
typedef struct { long type; // 0 for byte-packed positions, and 2 for word-packed positions mdl_trivertx_t bboxmin,bboxmax; // bounding box of the frame char name[16]; // name of frame, used for animation mdl_trivertx_t vertex[numverts]; // array of vertices, either byte or short packed } mdl_frame_t;
is either mdl_trivertxb_t or mdl_trivertxs_t, depending on whether the type is 0 or 2. In the MDL3 format the type is always 0. The beginning of the frames

sizeof(mdl_triangle_t).

MDL bones This is for future expansion of the MDL format, and not supported yet. Bones are a linked list of 3D vertices that are used for animation in the MDL5 format. Each bone vertex can have a parent, and several childs. If a bone vertex is moved, the childs move with it. If on moving a bone vertex the connection line to his parent rotates, it's childs are rotated likewise about the parent position. If the distance of the bone vertex to its parent changes, the change is added onto the distance between childs and parent. So the movement of the childs is done in a spherical coordinate system, it is a combination of a rotation and a radius change. Each bone vertex has an influence on one or more mesh vertices. The mesh vertices influenced by a bone vertex move the same way as it's childs. If a mesh vertex is influenced by several bone vertices, it is moved by the average of the bone's movement. can be found in the.MDL file at offset
The size of each frame is while mdl_trivertx_t
sizeframe = 20 + (numverts+2) * sizeof(mdl_trivertx_t), baseframes = basetri + numtris

The HMP5 terrain format

A terrain is basically a rectangular mesh of height values with one or several surface textures. It is a simplified version of the GameStudio Model format, without all the data structures that are unnecessary for terrain. HMP file header Once the file header is read, all the other terrain parts can be found just by calculating their position in the file. Here is the format of the.HMP file header:
typedef float vec3[3]; typedef struct { char version[4]; long nu1; vec3 scale; vec3 offset; long nu6; float ftrisize_x; float ftrisize_y; float fnumverts_x; long numskins ; long nu8,nu9; long numverts; long nu10; long numframes; long nu11; long flags; long nu12; } hmp_header;

typedef struct { long type; // always 2 mdl_trivertx_t bboxmin,bboxmax; // bounding box of the frame see mdl description char name[16]; // name of the frame, used for animation hmp_trivertx_t height[numverts]; // array of height values } hmp_frame_t;

doc1

3D Gamestudio Programmer's Manual

Conitec May 2001

3D GameStudio Programmer's Manual
for A5 engine 5.10 Johann C. Lotter / Conitec May 2001
This manual is protected under the copyright laws of Germany and the U.S. Acknex and 3D GameStudio are trademarks of Conitec Corporation. Windows, DirectX and Direct3D are trademarks of Microsoft, Inc. Voodoo is a trademark of 3dfx, Inc. Quake is a trademark of Id Software, Inc. Any reproduction of the material and artwork printed herein without the written permission of Conitec is prohibited. We undertake no guarantee for the accuracy of this manual. Conitec reserves the right to make alterations or updates without further announcement.
Contents The A5 DLL interface....4
Getting started with the SDK....4 Implementing new WDL functions...5 Writing to the screen buffer....5 Using Direct3D functions....5 Programming a game in VC++...6 WDL object structures....7 DLL interface structures....9 DLL functions.....10
The A5 Client/Server Protocol...12
Client Messages....12 Server Messages....12
The MDL model format...14
MDL file header....14 MDL skin format....14 MDL skin vertices....15 MDL mesh triangles...15 MDL frames....16 MDL bones....17

The A5 DLL interface

DLLs can be used as extensions to the engine and to the WDL language, as well as for programming a game in VC++ instead of WDL. The DLL interface is available on all A5 editions. For creating an A5 DLL, the SDK (source development kit) and its DLL interface library is required. SDK owners can create arbitrary DLLs for adding new effects, actor AI or WDL instructions, and distribute or sell them to other 3D GameStudio users. The Microsoft Visual C++ 6.0 development system is used for creating DLL extensions. The DLL SDK contains an interface library that must be linked to any DLL. An example VC++ project with a DLL template is also provided, which makes it easy to create extensions even for not-so-experienced C programmers who have never used DLLs before. DLL extensions work bidirectionally: WDL instructions can access DLL functions, and DLL functions can access essential engine functions and variables. On opening a DLL, the engine transfers the pointer to an internal interface structure to the interface library. The interface contains pointers to engine variables and functions, like the frame buffer, the DirectX interface, the network interface, the DirectInput interface, the level, the WDL functions and so on. Theoretically everything - MP3 or MOD players, a physics engine, another 3D engine or even another scripting language - could be added to the engine this way. On accessing system resources like sound, video, joystick and so on, the DLL must take care of possible resource conflicts. The engine shares its resources and expects the same from the code inside the DLL. For instance, code that requires exclusive access to the sound device (like some old MOD players) won't work. Some resources (like the midi player) can't be shared - if midi music is played by the DLL, the engine must not play a midi file at the same time and vice versa. Also care must be taken that for writing something into the frame buffer it must be locked before, and unlocked afterwards. The interface library provides functions for that. Getting started with the SDK The SDK comes with a DLL ackdll.dll that contains just a few typical example functions. For testing one of those DLL functions, just copy the compiled ackdll.dll into the work folder, and insert the following WDL instructions into a function assigned to a key:
dll_open("ackdll.dll"); dll_exec("PaintScreenWhite",0); // or any other DLL function dll_close(dll_handle);
For creating a new DLL, just unzip the SDK into any directory and open it as a VC++ 6.0 project. The source code of ackdll.dll is included. It contains typical examples for all sorts of DLL functions. In the following, some typical DLL uses are described. All exported DLL functions must be of type DLLFUNC fixed func(long) or DLLFUNC fixed func(fixed), while fixed is a long integer interpreted by WDL as 22.10 fixed point value. The engine structs and functions accessible from DLL functions are described at the end of this chapers. All DLL functions can be accessed from WDL script through the dll_open, dll_close, dll_exec, and dll_exec_vec instructions that are described in the WDL manual.
Implementing new WDL functions A DLL can contain a library of new arithmetic or other functions that can be accessed by WDL. The following example implements an exp function (which is already available in WDL) just for demonstration purpose:

// returns e power n DLLFUNC fixed Exp(fixed var) { return (FLOAT2FIX(exp(FIX2FLOAT(var)))); }
After having openend the DLL, the new function can be used this way:
x = dll_exec("Exp",y); // calculates x = e power y
Writing to the screen buffer The following simple example shows how to lock the screen buffer, write into it and unlock it again. It paints the screen all white for one frame. This works in D3D as well as in 8-bit mode. From WDL, activate this function through dll_exec("PaintScreenWhite",0). You'll see a short white flash when you call this function once. If you call it in a wait(1)-loop, the screen will become all white.
DLLFUNC fixed PaintScreenWhite (long unused) { // retrieve the pointer to the screen buffer FRAME_INTERFACE *a5fb = a5->fb; // lock the screen buffer to get access to it (*a5fb->Lock)(); // paint it all white; note the use of a5fb->pitch here for (int j=0; j<a5fb->height; j++) { byte *buffer = a5fb->bytes + j*a5fb->pitch; for (int i=0; i<a5fb->width*a5fb->bpp; i++) *buffer++ = 255; } // unlock it so that A5 can use it again (*a5fb->Unlock)(); return 0; }
Using Direct3D functions The following example shows how easy it is to use Direct3D functions for creating some effects on the screen. As all initialization is done by the engine, it is sufficient just to call the draw functions. All Direct3D functions are accessed through a IDirect3DDevice7 pointer that is available through the DLL. For details refer to the DirectX documentation that is available, along with the DirectX 7 SDK, from the Microsoft site.
The example paints a multicolored triangle onto the screen. From WDL, activate this function through dll_exec("PaintD3DTriangle",0).You'll see the triangle briefly flashing in the upper left corner when you call this function once. If you call it in a wait(1)-loop, the triangle will be permanently on the screen. This code only works in 16- or 32-bit mode when Direct3D is activated.
#include <d3d.h> // from the DIRECTX7 sdk DLLFUNC fixed PaintD3DTriangle (long unused) { // get the active D3D device FRAME_INTERFACE *a5fb = a5->fb; IDirect3DDevice7 *pd3ddev = (IDirect3DDevice7 *) a5fb->pd3ddev; if (!pd3ddev) return 0; // no D3D device in 8 bit mode // define three corner vertices D3DTLVERTEX v[3]; v[0].sx = 10.0; v[0].sy = 10.0; v[0].color = 0xFFFF0000; v[1].sx = 310.0; v[1].sy = 10.0; v[1].color = 0xFF0000FF; v[2].sx = 10.0; v[2].sy = 310.0; v[2].color = 0xFF00FF00; // the red corner // the blue corner // the green corner
v[0].sz = v[1].sz = v[2].sz = 0.0; // z buffer - paint over everything v[0].rhw = v[1].rhw = v[2].rhw = 1.0; // no perspective // begin a scene - needed before D3D draw operations pd3ddev->BeginScene(); // set some render and stage states (you have to set some more for more complicated operations) pd3ddev->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE); pd3ddev->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_DIFFUSE); pd3ddev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG2); // now draw the triangle pd3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN,D3DFVF_TLVERTEX,(LPVOID)v,3,0); // Normally we have to store the old render and texture states before, and // set them back here. but the simple states above do no harm // do not forget to do a clean close of the scene pd3ddev->EndScene(); return 0; }

Programming a game in VC++ Using the A4_ENTITY object (see below), a DLL can implement complex AI functions that would be harder to code in WDL. Even the whole gameplay could be written in a DLL. The following example shows how to change entity parameters through a DLL function.
// rolls the given entity by 180 degrees DLLFUNC fixed FlipUpsideDown(long entity) { if (!entity) return 0; // retrieve the pointer to the given entity A4_ENTITY *ent = (A4_ENTITY *)entity; // set the entity's roll angle to 180 degrees ent->roll = FLOAT2FIX(180); return 0;
This would be called by WDL through dll_exec("FlipUpsideDown",my). For controlling entities totally through a DLL for instance, when you intend to write your whole game in VC++ instead of WDL WDL dummy actions can be assigned to the entity, like this:
var appdll_handle; function main() { // open the application DLL appdll_handle = dll_open("myapp.dll");. } action myent_event { dll_handle = appdll_handle; dll_exec("myent_event",my); // this DLL function handles all entity events } action myentity { my.event = myent_event; while(1) { dll_handle = appdll_handle; dll_exec("myent_main",my); // this DLL function controls the entity wait(1); } }
WDL object structures Pointers to WDL objects can be transferred to DLL functions, thus allowing object manipulation. The internal engine format of some important WDL objects is listed here (the structs are defined in the a5dll.h file).
#define DLLFUNC extern "C" __declspec(dllexport) typedef unsigned char byte; typedef #define #define #define #define long fixed; INT2FIX(i) FIX2INT(x) FIX2FLOAT(x) FLOAT2FIX(f) // fixed point 22.10 number format used by WDL ((i)<<10) ((x)>>10) (((double)(x))/(1<<10)) ((fixed)((f)*(1<<10)))
/////////////////////////////////////////////////////////////////////// // internal A4 / A5 structs typedef struct { long index; long next; char *name; } WDL_LINK;

// // // //

internal use only internal use only pointer to WDL name of the object WDL object header
typedef struct { WDL_LINK link; long modelkey; // internal use only fixed x,y,z; // position of the entity fixed pan,tilt,roll; // euler angles fixed scale_x,scale_y,scale_z; // scale factors, 0.255 long flags; // entity property flags, see ENF. union { fixed frame; // frame number for sprites & models
fixed u; // texture x offset for maps }; union { fixed nextframe; // interpolation target frame for models fixed v; // texture y offset for maps }; fixed skin; // skin texture number for models fixed ambient; // -100.+100 fixed albedo; // 0.100, light reflectivity fixed alpha; // 0.100, transparency, default 50 fixed lightrange; // dynamic light range in quants fixed red,green,blue; // dynamic light color, 0.255 long emask; // event enable flags, EVF. long eflags; // internal status flags fixed min[3],max[3]; // bounding box in quants fixed trigger_range; fixed push; fixed shadow_range; fixed floor_range; long client_id; // client # that has created this entity fixed skill[48]; // entity skills } A4_ENTITY; typedef struct { WDL_LINK link; char *text; long length; long flags; } A4_STRING;

// pointer to null terminated string // allocated length of string (NEVER exceed!) // 0 = don't save, 1 = save string at SAVE/LOAD
typedef struct { void *pd3dsurf; // pointer to the DirectDrawSurface7 (unlock before writing to it) long finalwidth,finalheight; // allocated size of the d3dsurf (not necessary the size of the bitmap!) byte *pixels; // pointer to the original pixels byte *palette; // pointer to the original palette when 8 bit long bitspp; // original bitspp - 8, 16, 24, or 32 long width,height; // original size of the bitmap long pitch; // original size of a horizontal line long flags; } A4_TEX; typedef struct { WDL_LINK link; long width,height; // size of the bitmap long bpp; // internal bytes per pixel (1 or 2) long flags; // 0 = don't save, 1 = save images at SAVE/LOAD byte *pixels8; // pointer to 8 bit image (color indexes) byte *pixels16; // NULL when palettized, otherwise ptr to 5-6-5 or 4-4-4-4 coded 16-bit image A4_TEX *tex; // pointer to one or more textures the image is split into } A4_BMAP; typedef struct { WDL_LINK link; long type; // internal use only fixed layer; // layer number (read only) fixed pos_x,pos_y; // screen position in pixels long flags; fixed alpha; // transparency factor fixed offset; // vertical offset fixed lines; // number of lines to display long fontkey; // internal use only long strings; // number of strings (read only) A4_STRING **pstrings; // pointer to array of string pointers } A4_TEXT; typedef struct { WDL_LINK link; long type; fixed layer;
// internal use only // layer number (read only)
fixed pos_x,pos_y; // screen position in pixels long flags; fixed alpha; // transparency factor A4_BMAP *bmap; // background bitmap } A4_PANEL; typedef struct { WDL_LINK link; long type; // internal use only fixed layer; // layer number (read only) fixed pos_x,pos_y; // screen position in pixels long flags; fixed size_x,size_y; // screen size in pixels fixed x,y,z; // position of the camera fixed pan,tilt,roll; // camera angles fixed offset_x,offset_y; // eye offsets fixed arc; // camera FOV, used for zooming fixed aspect; // width to height ratio fixed ambient; // brightness fixed fog; // fog strength fixed diameter; // camera size for collision detection A4_ENTITY *genius;// gives valid BSP tree leaf for the view } A4_VIEW;
DLL interface structures Internal structs are handed over to the DLL for accessing internal variables and pointers initialized by the engine.
typedef struct { byte *bytes; // pointer to frame buffer (only valid after Lock) int pitch; // size of a horizontal line in bytes (!= width!) int width,height; // width, height of the screen int bpp; // bytes per pixel of the frame buffer BOOL (*Lock)(void); // lock frame buffer before accessing it void (*Unlock)(void); // unlock frame buffer after accessing it void *pd3ddev; // pointer to the IDirect3DDevice7 initilized by A4/A5 } FRAME_INTERFACE; typedef struct { void *pdi; void *pdimouse; void *pdikbd; void *pdijoy; void *pdplay; void *pdplobby; DWORD pdplayer; void *pdpguid; void *pds; void *pdsb; } DX_INTERFACE;

// // // // // // // // // //
pointer to the IDirect3DDevice7 used by A4/A5 pointer to the mouse DirectInputDevice always zero (keyboard doesn't use DirectInput) always zero (joystick doesn't use DirectInput) pointer to the DirectPlay4 interface pointer to the DirectPlayLobby2A interface player ID multiplayer session GUID pointer to the DirectSound interface pointer to the DirectSoundBuffer interface
typedef struct { long (*GetObj)(char *name); // internal use only long (*GetFunc)(char *name);// internal use only A4_ENTITY **my,**you; // Pointer to MY, YOU entity pointers } WDL_INTERFACE;
typedef struct { long dll_version; // The version is automatically tested against A5DLL_VERSION // on opening the DLL. DLLs work with engines with the same or a higher // version number, but not with a lower version engine.
WDL_INTERFACE FRAME_INTERFACE DX_INTERFACE } A5_INTERFACE; *wdl; *fb; *dx;
// access to MY and YOU pointers // access to the frame buffer and the Direct3D Device // access to directx pointers
An A5_INTERFACE object named a5 is initialized on startup of each DLL and can be used for accessing the screen buffer, the Direct3D Device and the MY and YOU entities. For directly accessing any WDL object from a DLL, the a5dll.lib can be used in a way described in the following chapter. DLL functions Two functions in the a5dll.lib provide DLL access to internal WDL variables, objects and WDL script functions. This way, entity AI can be implemented in a DLL plugin, and can use most WDL script instructions. long a5dll_getwdlobj(char *name); This function returns the address of the WDL object or variable with the given name. It can be used to read or write any defined WDL object from inside a DLL plugin. If the object does not exist, NULL is returned and an error message will pop up. Examples for DLL functions that access WDL objects:
// adds the given value to the sky speed fixed AddToSkySpeed(fixed value) { // get the address of the variable fixed *skyspeed = (fixed *)a5dll_getwdlobj("sky_speed"); if (!skyspeed) return 0; // add the value to both the x and y components skyspeed[0] += value; // skyspeed X value skyspeed[1] += value; // skyspeed y value return INT2FIX(1); } // zooms the camera view fixed ZoomIn(fixed value) { A4_VIEW *camera = (A4_VIEW *)a5dll_getwdlobj("camera"); if (!camera) return 0; return (camera->arc -= value); // change the FOV and return it }
long a5dll_getwdlfunc(char *name); This function returns the address of the WDL function with the given name. It can be used to execute WDL functions from inside a DLL plugin. Not all WDL functions are available for DLLs. If the function is not available (as can be the case for some special WDL functions, like wait() or inkey()), NULL is returned and an error message will pop up. Example for an entity AI DLL function that uses WDL functions for scanning the environment of an entity:

// returns free distance in front of MY entity until next obstacle fixed DistAhead(long my) { if (!my) return 0;
// retrieve the pointer to the given entity A4_ENTITY *ent = (A4_ENTITY *)my; // get the address of some wdl variables and functions fixed *tracemode = (fixed *)a5dll_getwdlobj("trace_mode"); wdlfunc2 vecrotate = (wdlfunc2)a5dll_getwdlfunc("vec_rotate"); wdlfunc2 trace = (wdlfunc2)a5dll_getwdlfunc("trace"); if (!tracemode || !trace || !vecrotate) return 0; fixed target[3] = { FLOAT2FIX(1000.0),0,0 }; // trace target vector // rotate vector by entity engles, just as in WDL (*vecrotate)((long)target,(long)&(ent->pan)); // add entity position to target target[0] += ent->x; target[1] += ent->y; target[2] += ent->z; // set trace_mode, then trace a line between entity and target, // and return the result *tracemode = INT2FIX(TRM_IGNORE_ME + TRM_IGNORE_PASSABLE + TRM_USE_BOX); return (*trace)((long)&(ent->x),(long)target); }
Global WDL functions, like level loading and keyboard entry, can not be called directly from a DLL. However they can be executed indirectly from a WDL script that calls a DLL function for deciding which operation must be executed. Example:
function main_loop { while(1) { dll_handle = appdll_handle; operation = dll_exec("choose_operation",0); // this function returns a control code if (operation == 1) { load_level(<level1.wmb>); } if (operation == 2) { load_level(<level2.wmb>); } if (operation == 10) { inkey(entry_string); } wait(1); } }
The A5 Client/Server Protocol
The structure of the messages is a single-byte code, followed by code-dependant informations. When describing the content of messages, we will use the following conventions:
String = a sequence of characters, terminated by NULL ('\0') Angle = a short, to be multiplied by 360.0/65535.0 to convert it to degrees. Position a position packed in three bytes by dividing it by 8. Byte = an unsigned integer, on one byte. Scale(x) = a value packed into one byte to be multiplied by x/255.0. Short = a signed integer, on two bytes, Big Endian order (Intel order). Long = a signed integer, on four bytes, Big Endian order (Intel order). Fixed = a floating point number, on four bytes, Big Endian order (Intel order).

Client Messages The following commands are used for transferring information from the client to the server: Command CLS_JOIN CLS_CREATE CLS_REMOVE CLS_PING CLS_LEAVE CLS_LEVEL CLS_VAR CLS_STRING CLS_SKILL CLS_SKILL3 Bytecode 0x02 0x03 0x04 0x07 0x08 0x09 0x0a 0x0b 0x0e 0x0f Arguments Description Request for joining the session Create entity with given model name, and link client to it Remove entity on server Sent after each client frame Leave the session Client has loaded a level Send a variable Send a string Send an entity skill Send an entity vector skill
Server Messages The following commands are used for transferring information from the server to either a specific client, or to all clients connected: Command SVC_CREATE SVC_REMOVE SVC_ENTSOUND SVC_PARTICLE SVC_INFO SVC_LEAVE Bytecode 0x03 0x04 0x05 0x06 0x07 0x08 Arguments Description Created entity with given index Removed entity from server Play an entity sound on the clients Generate a particle effect on the clients Send the server time to the clients Server goes down
Command SVC_VAR CLS_STRING SVC_SKILL SVC_SKILL3 SVC_UPDATE1 SVC_UPDATE2 SVC_UPDATE3
Bytecode 0x0a 0x0b 0x0e 0x0f 0x40 0x80 0xc0

Arguments

Description Send a variable to all clients Send a string to all clients Send an entity skill to the entity's client Send an entity vector skill to the entity's client Update entity parameters 1 Update entity parameters 2 Update entity parameters 3

The MDL model format

A wireframe mesh, made of triangles, gives the general shape of a model. 3D vertices define the position of triangles. For each triangle in the wireframe, there will be a corresponding triangle cut from the skin picture. Or, in other words, for each 3D vertex of a triangle that describes a XYZ position, there will be a corresponding 2D vertex positioned that describes a UV position on the skin picture. It is not necessary that the triangle in 3D space and the triangle on the skin have the same shape (in fact, it is not possible for all triangles), but they should have shapes roughly similar, to limit distortion and aliasing. Several animation frames of a model are just several sets of 3D vertex positions. The 2D vertex positions always remain the same. A MDL file contains: - A list of skin textures in 8-bit palettized, 16-bit 565 RGB or 16 bit 4444 ARGB format. - A list of skin vertices, that are just the UV position of vertices on the skin texture. - A list of triangles, which describe the general shape of the model. - A list of animation frames. Each frame holds a list of 3D vertices. - A list of bone vertices, which are used for creating the animation frames. MDL file header Once the file header is read, all the other model parts can be found just by calculating their position in the file. Here is the format of the.MDL file header:

typedef float vec3[3]; typedef struct { char version[4]; long final; vec3 scale; vec3 offset; float pad; vec3 eye; long numskins ; long skinwidth; long skinheight; long numverts; long numtris; long numframes; long numskinverts; long flags; long numbones; } mdl_header;
// // // // // // // // // // // // // // //
"MDL3" or "MDL4" not used yet 3D position scale factors. 3D position offset. not used yet. not used yet. number of skin textures width of skin texture; must be a multiple of 2 height of skin texture number of 3d wireframe vertices number of triangles surfaces number of frames number of 2D skin vertice 0 = normal, 1 = terrain model number of bone vertices (MDL4 only, otherwise 0)
The size of this header is 0x54 bytes (84). The "MDL3" format is used by the A4 engine, while the "MDL4" format is used by the A5 engine. After the file header follow the skins, the skin vertices, the triangles, the frames, and finally the bones (future expansion). MDL skin format The model skins are flat pictures that represent the texture that should be applied on the model. There can be more than one skin. You will find the first skin just after the model header, at offset baseskin = 0x54. There are numskins skins to read. Each of these model skins is either in 8-bit palettized (type == 0), in 16-bit 565 format (type == 2) or 16-bit 4444 format (type == 3). The structure is:
typedef byte unsigned char; typedef struct { int skintype; // 0 for 8 bit (bpp == 1), 2 for 565 RGB, 3 for 4444 ARGB (bpp == 2) byte skin[skinwidth*skinheight*bpp]; // the skin picture } mdl_skin_t;
8 bit skins are a table of bytes, which represent an index in the level palette. If the model is rendered in overlay mode, index 0x00 indicates transparency. 16 bit skins are a table of shorts, which represent a true colour with the upper 5 bits for the red, the middle 6 bits for the green, and the lower 5 bits for the blue component. Green has one bit more because the human eye is more sensitive to green than to other colours. If the model is rendered in overlay mode, colour value 0x0000 indicates transparency. 16 bit alpha channel skins are represented as a table of shorts with 4 bits for each of the alpha, red, green, and blue component. The width of skins should be a multiple of 4, to ensure long word alignement. The skin pictures are usually made of as many pieces as there are independent parts in the model. For instance, for the a player, there may be two pieces that defines the body, and two others that define the gun. MDL skin vertices The list of skin vertices indicates only the position on texture picture, not the 3D position. That's because for a given vertex, the position on skin is constant, while the position in 3D space varies with the animation. The list of skin vertices is made of these structures:

typedef struct { short u; // position, horizontally in range 0.skinwidth-1 short v; // position, vertically in range 0.skinheight-1 } mdl_uvvert_t; mdl_uvvert_t skinverts[numskinverts];
u and v are the pixel position on the skin picture. The skin vertices are stored in a list, that is stored at offset basestverts = baseskin + skinsize. skinsize is the sum of the size of all skin pictures. If they are all 8-bit skins, then skinsize = (4 + skinwidth * skinheight) * numskins. If they are 16-bit skins, then skinsize = (4 + skinwidth * skinheight * 2) * numskins. MDL mesh triangles The model wireframe mesh is made of a set of triangle facets, with vertices at the boundaries. Triangles should all be valid triangles, not degenerates (like points or lines). The triangle face must be pointing to the outside of the model. Only vertex indexes are stored in triangles. Here is the structure of triangles:
typedef struct { short index_xyz[3]; // Index of 3 3D vertices in range 0.numverts short index_uv[3]; // Index of 3 skin vertices in range 0.numskinverts } mdl_triangle_t; mdl_triangle_t triangles[numtris];
At offset basetri = baseverts + numskinverts * sizeof(uvvert_t) in the.MDL file you will find the triangle list.
MDL frames A model contains a set of animation frames, which can be used in relation with the behavior of the modeled entity, so as to display it in various postures (walking, attacking, spreading its guts all over the place, etc). Basically the frame contains of vertex positions and normals. Because models can have ten thousands of vertices and hundreds of animation frames, vertex posistion are packed, and vertex normals are indicated by an index in a fixed table, to save disk and memory space. Each frame vertex is defined by a 3D position and a normal for each of the 3D vertices in the model. In the MDL3 format, the vertices are always packed as bytes; in the MDL4 format that is used by the A5 engine they can also be packed as words (unsigned shorts). Therefore the MDL4 format allows more precise animation of huge models, and inbetweening with less distortion.
typedef struct { byte rawposition[3]; // X,Y,Z coordinate, packed on 0.255 byte lightnormalindex; // index of the vertex normal } mdl_trivertxb_t; typedef struct { unsigned short rawposition[3]; // X,Y,Z coordinate, packed on 0.65536 byte lightnormalindex; // index of the vertex normal byte boneindex; // index of the bone this vertex belongs to } mdl_trivertxs_t;

To get the real X coordinate from the packed coordinates, multiply the X coordinate by the X scaling factor, and add the X offset. Both the scaling factor and the offset for all vertices can be found in the mdl_header struct. The formula for calculating the real vertex positions is:
float position[i] = (scale[i] * rawposition[i] ) + offset[i];
The lightnormalindex field is an index to the actual vertex normal vector. This vector is the average of the normal vectors of all the faces that contain this vertex. The normal is necessary to calculate the Gouraud shading of the faces, but actually a crude estimation of the actual vertex normal is sufficient. That's why, to save space and to reduce the number of computations needed, it has been chosen to approximate each vertex normal. The ordinary values of lightnormalindex are comprised between 0 and 161, and directly map into the index of one of the 162 precalculated normal vectors:
float lightnormals[162][3] = { {-0.525725, 0.000000, 0.850650}, {-0.442863, 0.238856, 0.864188}, {-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000}, {0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, {0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, {0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, {0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, {0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, {-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, {-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856}, {-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, {-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, {-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, {-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863}, {0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, {0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242}, {-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, {0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, {0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, {0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, {0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, {0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, {0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, {0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567}, {0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866}, {0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, {0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, {0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567}, {0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856}, {0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, {0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567},

A whole frame has the following structure:
typedef struct { long type; // 0 for byte-packed positions, and 2 for word-packed positions mdl_trivertx_t bboxmin,bboxmax; // bounding box of the frame char name[16]; // name of frame, used for animation mdl_trivertx_t vertex[numverts]; // array of vertices, either byte or short packed } mdl_frame_t;
The size of each frame is sizeframe = 20 + (numverts+2) * sizeof(mdl_trivertx_t), while mdl_trivertx_t is either mdl_trivertxb_t or mdl_trivertxs_t, depending on whether the type is 0 or 2. In the MDL3 format the type is always 0. The beginning of the frames can be found in the.MDL file at offset baseframes = basetri + numtris * sizeof(mdl_triangle_t). MDL bones This is only for future expansion of the MDL format, and not implemented yet. Bones are a linked list of 3D vertices that are used for animation in the MDL4 format. Each bone vertex can have a parent, and several childs. If a bone vertex is moved, the childs move with it. If on moving a bone vertex the connection line to his parent rotates, it's childs are rotated likewise about the parent position. If the distance of the bone vertex to its parent changes, the change is added onto the distance between childs and parent. So the movement of the childs is done in a spherical coordinate system, it is a combination of a rotation and a radius change. Each bone vertex has an influence on one or more mesh vertices. The mesh vertices influenced by a bone vertex move the same way as it's childs. If a mesh vertex is influenced by several bone vertices, it is moved by the average of the bone's movement.

 

Tags

CT-657 TI313BS1 Jornada 680 TH-37PX8ESA WEP410 Lansing 120I 69NT40-489-100 Ratchet SPP-AQ25 WR450F-2004 VPC-HD1000 XV-5050 GZ-MG530 CS-575 MDS712-A5U 42FD9935-17 Darklands 917-272921 Suisse 8045 Motorola C200 MG320C MC 1808 DCR-TRV265E 6720S Argos KDL-32EX400 Urc-4330 Serie F-401 CDX-S2270EE 2F2611 Samsung F300 LG500 TU-PTA100E VM-3100 Death KX-TG6312 SIM 200 RDR-DC105 Fostex PD-2 Vengeance LS110 Asus P5QC 14PT1342 58 Focus-2006 Fjdr1466W MO6-MO8 Ericsson T100 Aspire-5000 KLV-20SP2 YP-S2QG Digeo Moxi RDR-VX500 Enhwi-G2 BXR 60 FS-3700 Alcatel-lucent 4018 TW911P2 A6ukvrj FJR1300AS-2008 STR-DE898-B 14MG10G 130200 Croma Terminal 32 Intec DS-306 Wpxh214 C6500E 850e 860E Mapower KC31 GV-D800E Microlite 28 Ii N 1064B-5 SB4101 DLA-SX21 Digimax I50 KX-TG8220FX DVD5353 AXZ610 GR-399SNQ VSX-607RDS KV-29FS100 29476078 Shade LP2065 Speakers 150MP E53 E54 Lavalogic1400 Review Pilot III Reverb NWZ-B143F Satellite A10 Icom A6 BHP451RFE S80408KG28 Meal Oven TX-25CK1CM

 

manuel d'instructions, Guide de l'utilisateur | Manual de instrucciones, Instrucciones de uso | Bedienungsanleitung, Bedienungsanleitung | Manual de Instruções, guia do usuário | инструкция | návod na použitie, Užívateľská príručka, návod k použití | bruksanvisningen | instrukcja, podręcznik użytkownika | kullanım kılavuzu, Kullanım | kézikönyv, használati útmutató | manuale di istruzioni, istruzioni d'uso | handleiding, gebruikershandleiding

 

Sitemap

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101