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

 

About 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:
allenrmaher 8:33am on Tuesday, September 28th, 2010 
A question I would like to know if somebody can help me. I bought an Apple MacBook Pro MC118LL/A 15.
Nyx 9:20am on Wednesday, September 22nd, 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).
softnob 7:19pm on Monday, August 30th, 2010 
Upgrade alert After you install OS X 10.5. MAC Leopard software It appears to be working just fine. Glad I could find this software since Apple Stores do not carry it anymore!
LornaB 6:44pm on Sunday, August 29th, 2010 
I have used Windows as long as I can remember. I always look forward to the next OS microsoft is working on.
thetemplarknight 3:51am on Saturday, August 28th, 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.
lenshapiro 9:14am on Friday, July 23rd, 2010 
Leopard combines what an operating system needs to be with a shiny new interface that is both eye candy and important.
firenurse4 6:26am on Sunday, April 18th, 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 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

3D Gamestudio Programmer's Manual

Conitec February 2003

3D GameStudio Source Development Kit Programmer's Manual
for A5 Engine 5.51 Johann C. Lotter / Conitec February 2003
This manual is protected under the copyright laws of Germany and the U.S. Acknex, A4, A5, and 3D GameStudio are trademarks of Conitec Corporation. Windows, DirectX and Direct3D are trademarks of Microsoft, 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 plugin interface....4
Getting started with the SDK....4 Using C-Script objects in a DLL...6 Using the API....7 Using Direct3D functions....9 Particle functions....9 Sending information over the network....10 Programming a game in C++...11 DLL interface structures and special functions...12
The A5 Client/Server Protocol...14
Client Messages....14 Server Messages....15
The MDL5 model format....17
MDL file header....17 MDL skin format....17 MDL skin vertices....18 MDL mesh triangles...19 MDL frames....19 MDL bones....21
The HMP5 terrain format...22
HMP file header....22 HMP texture format....22 HMP height values....22

The A5 plugin interface

What is a DLL? Basically it's an external library that adds functions to a program. A5 DLLs can be used as "plugin" extensions to the engine and to the C-Script language. For creating an A5 plugin, the SDK (source development kit) and a development system like VC++ or Delphi is required. DLL plugins are used for adding new effects, actor AI or new C-Script instructions, as well as for programming a game totally in C++ or Delphi instead of C-Script. 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. Because DLL plugins work with all editions, they can be distributed or sold to other 3D GameStudio users. On our download and link pages at http://www.3dgamestudio.com you can already find a lot of useful plugins created with the SDK by GameStudio users. While the Microsoft Visual C++ (version 6.0 or.NET) development system normally is recommended for creating DLL plugins, users have also provided libraries for Borland C++, C++ Builder, or Delphi up to version 6, which are included in the SDK. Please note however that Conitec can not give support for user-provided Delphi and Borland libraries. The DLL SDK contains an example project, which makes it easy to create extensions even for not-so-experienced C or Delphi programmers who have never written a DLLs before. The SDK license includes the right to freely distribute DLLs created with it, as long as the DLL functions only provide application functionality. It is not allowed to distribute DLLs that work as a 'wrapper' for the library by providing functions that allow direct access of the interface structures or the library functions from outside the DLL. The following documentation contains just the description of the DLL interface to the C-Script API, and some examples. The C-Script functions themselves are described in the GameStudio C-Script Manual. C-Script functions are the API for the DLL as well as for scripts, so you'll definitely need both manuals for creating DLL plugins. Getting started with the SDK You'll find the SDK either as a ZIP file on your key disk, or on a separate SDK disk. You can unzip or copy the SDK into a directory of your choice, and open it as a VC++ project. The SDK comes with a DLL source file, ackdll.cpp, that contains some typical examples for DLL functions. Examine the examples carefully it's the best way to see how to program DLL functions and access engine parameters! You can use them as a 'template' for your own DLL. If you have updated to the most recent SDK version, you'll find the Borland file versions in the BCPP and Delphi subfolders read the readme.txt for more information about how to create Borland and Delphi projects. We are here using VC++.Net for our following examples. We are also assuming that you have some basic knowledge of C and C-Script. If not, read a C++ book, and read the first chapter of the C-Script tutorial before continuing here. When you create a new project (File->New Project), VC++ offers you a choice of project templates. Don't select "MFC DLL" here with VC++.Net it's the plain Win32 Project, with VC++ 6.0 the Win32 Dynamic-Link Library that you'll want to create. When the Win32 Application Wizard pops up, select DLL (.NET) or Simple DLL (6.0) in the application settings and you're done. VC++ now creates a new DLL project for you. The main.cpp file will look like this:

// plugin.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; }
That's the main entry point of your DLL and you can leave that function unchanged. Copy all of the SDK files (except the Borland/Delphi subfolders of course) into the folder that is created by VC++. Now for compiling an A5 plugin DLL, you have to link the a5dll.lib (one of the files of the SDK) to the project (Project Properties -> Linker Input -> Additional Dependencies), and include the a5dll.h and a5funcs.h files to your main.cpp file. These 3 files are what you need for creating A5 DLLs. You can see in the ackdll.cpp example how it should look like.
Now you can begin to add functions to the DLL that can then later be called by a script, or by the main function of your game. To be recognized by the engine, all such functions must be of type DLLFUNC fixed function(.), like this:
// returns the value of x * 2n DLLFUNC fixed ldexp(fixed x,fixed n) { return (FLOAT2FIX(FIX2FLOAT(x)*pow(2.0,FIX2FLOAT(n)))); }
This example function just returns an arithmetic expression of its arguments. DLLFUNC is not a part of C++ - it's just a convenience shortcut for declaring DLL export functions. fixed is the all-purpose numeric variable type of A5 and C-Script - a long integer that can be used either as 22.10 fixed point value, or as a pointer. Both are declared in the a5dll.h together with some conversion functions:
#define DLLFUNC extern "C" __declspec(dllexport) typedef long fixed; // fixed inline fixed INT2FIX(int i) { inline int FIX2INT(fixed x) { inline double FIX2FLOAT(fixed inline fixed FLOAT2FIX(double point 22.10 number format used by C-Script return i<<10; } return x>>10; } x) { return ((double)x)/(1<<10); } f) { return (fixed)(f*(1<<10)); }
The engine will pass and expect all numbers coordinates, variables, no matter what in fixed type. So convert any number to fixed before you return it to the engine, like in the example above. Ready? Now compile your DLL let's assume that you named it plugin.dll and copy it into your work folder. How can we now call our ldexp function by a script? We have to do two things: declare the function, and open the DLL. The first is achieved by a dllfunction prototype in the script:

dllfunction ldexp(x,n); // declaration of a DLL function
This makes our ldexp function known to C-Script. Before we can call it, we have to open the DLL. A good place to do this is the main() function of your script:
function main() {. dll_open("plugin.dll");
and do not forget to close the DLL before exiting the game:
. dll_close(dll_handle); exit; // just use the default handle as long as there's only one DLL
After this is done, you can now enjoy that C-Script has gotten one extra instruction:
. x = ldexp(y,n); // calculates x = y * 2n.
For debugging your DLL in VC++, set the command in Project Properties -> Debug to the engine EXE path (like "C:\program files\gstudio\bin\acknex.exe"), the command arguments to your script and command line parameters (like "mygame.wdl -wnd") and the working directory to your game directory (like "C:\program files\gstudio\mygame"). In Project Properties -> General, set the output directory and the intermediate directory to. (a period, meaning the working directory) for the engine to find the intermediate files. Then you can compile and debug your DLL by setting breakpoints as usual. Ok, this was the basics of writing plugin DLLs. Of course, there's a lot more to learn. The methods for exchanging data with the engine are described in the following. All DLL functions can be declared and called in scripts just like each other C-Script function, after having activated the DLL through the dll_open and dll_close instructions described in the script manual.
Using C-Script objects in a DLL
We have learned how to add new C-Script instructions, but how can we access C-Script variables, objects and functions from within a DLL? We have some library functions to do that. All library functions provided by the SDK are preceded by a5dll_. The most often used function is
long a5dll_getwdlobj(char *name);
This function returns the address of the C-Script object or variable with the given name. It can be used to read or write any defined C-Script 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 C-Script objects:
// adds the given value to a C-Script vector fixed AddToVector(fixed value) { // get the address of the variable fixed *myvector = (fixed *)a5dll_getwdlobj("myvector"); // add the same value to the 3 components myvector[0] += value; myvector[1] += value; myvector[2] += value; return value; }

So you can use this function to obtain a pointer to any C-Script object, no matter whether it's predefined by the engine or defined in our script. In this case it's a vector which was defined in CScript by

var myvector[3] = 1,2,3;

and a5dll_getwdlobj just returns a pointer to this vector, which is, by the way, an array of fixed. Why don't we have to convert to/from fixed here? Because value is already fixed and we can add two fixed numbers just as we add two integers (however we could not do this with multiplication and division!). It is not wise to obtain the myvector pointer directly in the function where it's needed, the way it's done here for tutorial purposes. a5dll_getwdlobj executes slow because it has to find the address in a list. Rather, you would have a global list of pointers to all WDL objects that you need in your DLL, and obtain the pointers once at the beginning in a startup function by calling a5dll_getwdlobj for each of them. So now we know how to read and change a C-Script variable, but how about more complex objects, like panels, views or entities? Take a look at a5dll.h there you will find declared all structs known to C-Script, like A4_STRING, A4_ENTITY, A4_PARTICLE, A4_BMAP, A4_TEX etc. All those struct names begin with A4_ (even if it's the A5 engine meanwhile). You can get a pointer to such a struct the same way like to a variable:
// 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:

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.

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.

Client Messages The following commands are used for transferring information from a client to the server. Command Bytecode Arguments Description Filler byte for inflating UDP messages to a minimum length. Can be ignored.
cls_fill cls_join cls_create
0x01 0x02 0x03 String Player_Name String File_Name Position Start[3] Short Action_Index Short Identifier Long Entity_Index
Request for joining the session (TCP). Request creating an entity with given model name, and link the client to it (TCP). Request removing entity on the server (TCP). Sent after each client frame (UDP). If a client does not send anything for more than 5 seconds, it is automatically disconnected by the server.

cls_remove cls_ping

0x04 0x07

cls_level cls_var

0x09 0x0a
String Level_Name Short Var_Index Short Var_Length Fixed Var[Var_Length] Short String_Index String Text Short Entity_Index Short Struct_Offset Fixed Skill Short Entity_Index Short Struct_Offset Fixed Skill[3]
Inform server that client has loaded a level (TCP). Send a variable or an array (TCP).

cls_string cls_skill

0x0b 0x0e
Send a string (TCP). Send an entity skill (TCP).
Struct_Offset gives the byte offset of the skill in the A4_ENTITY struct.
Send an entity vector skill (TCP).

cls_skill3

Server Messages
The following commands are used for transferring information from the server to either a specific client, or to all clients connected. Server-client communication uses the reliable TCP protocol for important messages, and the unreliable UDP protocol for unimportant messages. Command Bytecode Arguments Description Filler byte for inflating UDP packets to at least 8 bytes (can be ignored).
svc_fill svc_create svc_remove svc_entsound
0x01 0x03 0x04 0x05 Short Entity_Index Short Identifier Short Entity_Index Short Entity_Index Short Sound_Index Scale(2000) Volume Long Sound_Handle Short Action_Index Short Number Position Start[3] Fixed Vel[3]
Created entity with given index (TCP). Removed entity from server (TCP). Play an entity sound on the clients (UDP).

svc_effect

Generate a particle or beam effect on the clients (UDP).

svc_info

Send a sync value and the server time Long 0x11191218 Byte Protocol_Version to the clients (TCP). This is sent once a frame. Float Server_Time Float Frame_Time Send a variable to the client (TCP). Short Var_Index Short Var_Length Fixed Var[Var_Length]

svc_var

svc_string svc_skill
Short String_Index String Text Short Entity_Index Short Struct_Offset Fixed Skill Short Entity_Index Short Struct_Offset Fixed Skill[3] Short Entity_Index Short Function_Index
(Parameters see below) (Parameters see below) (Parameters see below)

typedef float vec3[3]; typedef struct { char version[4]; long unused1; vec3 scale; vec3 offset; long unused2; vec3 unused3; long numskins ; long skinwidth; long skinheight; long numverts; long numtris; long numframes; long numskinverts; long flags; long numbones; } mdl_header;
// // // // // // // // // // // // // // //
"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.

The size of this header is 0x54 bytes (84). The "HMP4" format is used by the A5 engine prior to 5.230, while the new "HMP5" format is used by the A5 engine since version 5.230. The number of vertices in the rectangular mesh can be determined by
int numverts_x = (int) fnumverts_x; int numverts_y = numverts/numverts_x;
After the file header follow the textures and then the array of height values. HMP texture format The terrain surface textures are flat pictures. There can be more than one texture. By default, the first texture is the terrain skin, and the second texture is the detail map if it has a different size. Further textures are not used yet. You will find the first texture just after the model header, at offset baseskin = 0x54. There are numskins textures to read. The texture and pixel formats are the same as for MDL skins, and are described in detail in the MDL format description. HMP height values A terrain contains a set of animation frames, which each is a set of height values. Normally only the first frame is used, because terrain does not animate. Each mesh vertex is defined by a height value and a normal.
typedef byte unsigned char; typedef word unsigned short; typedef struct { word z; // height value, packed on 0.65536 byte lightnormalindex; // index of the vertex normal byte unused; // not used } hmp_trivertx_t;
To get the real Z coordinate from the packed coordinates, multiply it by the Z scaling factor, and add the Z offset. Both the scaling factor and the offset can be found in the mdl_header struct. Thus the formula for calculating the real height positions is:
float height = (scale[2] * z) + offset[2];
The X and Y position of the vertes results of the number of the vertex in the mesh, and thus must not be stored. The lightnormalindex field is an index to the actual vertex normal vector, just like in the MDL format description. A whole frame has the following structure:
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:

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

PAY DAY FP720 LH-T9656IA GL2 5TI X1261 OT-V770 SGH-X566 Ff GN Bizhub 164 3000 Head SD257WXC Dreamweaver VGN-FW DI200F Sony D303 Suite 10 Scanjet 8300 3 2 CMD 126 MIO C320 WS1094H PA-30 Expedition-1997 HT-TZ315R 1200-UB- Plus TE 450 UC4000 XL-MP60 TC7114 M-430 220-240V KS-AX3300 Doro 730R DTM 7802 Rsdx-02 FS-V21R LQ-1070 CMT-Z100IR CD5400 GR-389SQA ST-S550ES 95-82 0 3 PV-L779D PL42A450 CCD-TR501E S-302 Monitor III E KH 967 FP567 Photosmart M537 Xdvdn8190 Omnivista 2500 DSL-2640R ZT 321 SGH-X820B B3236 D VGN-A417M GO 930 HQ7360 PKM 600 ST-SA50ES A3380 ADR3006 NEX-5A RFG297aabp XAA DVP3000 ES-8500 ICD-B25 AX4pemax SP0008 GR-D375U Aspire 1350 Dremel 750 Programchart VP-D905 D-NE321 PSC 1300 Professional MZ-42PZ24 AQ18FAN Review XE-A120 TX-28DK1 TM-U295 KM600 PL42B450 UX256 DAV-DZ730 Gr-213 Electrique Blazer 12 PS4X4 PRO DVD-P191 DEH-P8650MP Armband 3DE-7985E AKP 942 LE46A558 DAV-DZ850M

 

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