Main

Version 1.05

Welcome to Serious Engine Software Development Kit. Serious Engine is 3D engine developed by Croteam.

To see changes in Serious Editor from V008 to V009 click here.
To see changes in Serious Editor from V009 to V012 click here.
To see changes in Serious Modeler from V008 to V1.00 click here.

Important notes:
Latest help updates can be downloaded from: www.croteam.com/help
You can visit Serious Engine SDK forum at Serious Engine forum.

Serious Engine

  • Overview
  • Basic information
  • Optimizing Rendering Performance

Serious Modeler

  • Overview
  • Usage
    • Navigation
    • Tools Window
    • Texture Types
    • Adding Textures
    • Texture Mapping
    • Defining Collision
    • Defining LOD
    • Adding Attachments
    • Synchronizing Sounds
    • Adding Animations
  • Model Creation
    • Tools You Need
    • Geometry Setup, Creating Surfaces and Defining UV Mapping
    • Creating Models and Scripts
    • Defining LOD
    • Collision Box
    • Adding Animations
    • Adding Attachments
  • Tutorials
    • Tutorial 1: Player Model Creation
      • Overview
      • Table of Contents
  • Shortcuts
  • How to ...
    • Add Reflections
    • Add Specularity
    • Add Bump and Detail
    • Create Flat Models

Serious Editor

  • Overview
  • Tutorials
    • Navigation
    • Basic room

  • Shortcuts
  • How to ...
  • Tips and tricks
  • Class help (Part I)

Software Development Kit

  • General information
    • Basics for Programming with Serious Engine
    • Setting up the Development Environment
    • Programming Conventions
  • Engine sections
    • Base
    • Math
  • Entities
    • Basics of ES Programming
    • Entity Source (ES) Syntax
    • Advanced Tips on ES Programming

MOD support

  • Legal Information
  • Overview

3rd party tutorials

  • From great Michael Harris
    • In directory Help\Extras\MichaelHarris\ItemByItem\ you can find .doc tutorial (V019) that covers all components of Serious Editor's user interface
    • In directory Help\Extras\MichaelHarris\GravityAndSectoring\ you can find several .doc tutorials about sector splitting and gravity handling
  • From several authors
    • In directory Help\Extras\SeveralAuthors\ you can find file SeriousEditorTipsAndTricksV08.txt. It is a compilation of tips and tricks from people who worked with Serious Editor.
  • From Forager
    • In directory Help\Extras\Forager\ you can find helpful levels that show you how some basic templates are created.

    Croteam and the Croteam logo are trademarks of Croteam, Ltd. Serious Sam and the Serious Sam logo are trademarks of Croteam, Ltd. Serious Engine, Serious Editor, Serious Modeler and the Serious Engine logo are trademarks of Croteam, Ltd. Copyright © 2010 Croteam, Ltd. All Rights Reserved.


Changes
  • Serious Editor: Version 008 to 009
  • Serious Editor: Version 009 to 012
  • Serious Modeler: Version 008 to 1.00


Changes V008 to V009

Changes made from V008 to V009:

  • Terrain primitive
    • Terrain primitive now automaticly generates detail polygons, auto-sets side polygons to be portals, and has ability to generate rougher mip brushes. New terrain primitive is generated much faster than the old one.

  • Occluder flag for polygons
    • Ability to define occluder polygons. Polygon property page of info window has check box for setting occluder flag. Setting of this flag automaticly clears portal and detail flags, and sets don't cast shadow flag. Engine's visibility algorythm will not add sector behind occluder to further rendering. This polygon acs just like the wall except that it is not rendered. Great for adjusting visibility.

  • Clonning interface
    • SED now has ability to work with virtual clones. All entities with same names are considered as clones. All af the clone's childs entities are involved in cloning operation. Select one clone entity, change it and choose update clones. SED will delete all clones and their child entities and will replace them with new ones. Old clones will be deleted and source clone will be copied to their positions. Clones will also have source clone's child entities. This way you can have many columns that are clones (have same name), and you change shape or texture on one of them. Select modified one and apply 'Update clones' operation. All clones will look like source clone. It is also very useful to work with clones and their child entities. You can add a torch model, fire model, sound and light to a column source, set child-parent links (column is parent) and update clones. All clones should now have lights, sound, fire... Very useful feature.

  • Deselecting polygons by orientation with mouse
    • Ability to use mouse (Ctrl+Shift+LMB or RMB) for deselecteing or leaving selected polygons according to their orientation.

  • Delete entities in browse entities dialog
    • Ability to delete entities while in browse entity dialog.

  • Automatized shadow discarding
    • When brush is moved, its polygons must discard their shadow map. This process is now automatized.

  • Zoning and ancored flags
    • When brush is created using join layers operation, it appears as non-zoning and non-anchored brush. Only first brush in the world is zoning and anhored (not moveable nor deleteable until angored operations are enabled).

  • Mip brush swith distance in meters
    • Mip brush switch distance is now easily editable and controlable. Distance is measured in meters (not in mip factor any more). Edit box added to mip brushing tool bar that enables easy swith distance setting.

  • Mapping exporting
    • Serious modeler can export mapping for skinning purposes. You can select surface colors, wire frame and surface numbers exporting.

  • Other minor changes:
    • - ability to select entity and its descendants with LMBx2
    - moving of zoning entities (water or lava contents can be raised or lowered)
    - ability to select portals that link to this sector and ability to select sectors that are linked trough this portal
    - Serious Modeler: rendering of surface colors enabled in mapping mode
    - Serious Modeler: synchronized animation start for main model and its attachments


Changes V009 to V012

Changes made from V009 to V012:

  • Vertex mode
    • Vertex mode added. Now you can alter each vertex on the world. Invoke vertex mode using key '.' on any part of keyboard. You can select/deselect vertices using mouse click or lasso tool (just draw lasso). Vertex moving on selection is performed using Ctrl key. All polygons containing wertex that is moved are automatically trianglularized. You can also merge two or more vertices. All selected vertices will collapse into last selected vertex after merging (M). Note that lasso selecting can be also used to select entities.

  • Fly mode
    • You can enter/exit (toggle) free flying mode using Esc key. In free fly mode, you can fly arround using mouse, mouse keys and keyboard keys: W,S,Q,E,R or Space, F. You can also use arrows and mouse for navigation. Use mouse wheel to double or halve speed of moving (mouse wheel up/down). There are many standard keys available in free fly mode, like: toggle shadow (H), hiding/showing selected secors and entities, toggling selection marking (`), link displaying (G), storing/restoring of viewver position, changing of rendering settings (keys 1-0) on both numeric and standard part of keyboard.

  • Spawn flags for level
    • Now you can use 'World settings dialog' to define type of your level, is it supposed to be available in deathmatch, cooperative, single player ... Dialog also enables you to give name to your level. This name should application utilitizing Serious Editor display to user in 'Start custom level' menu as the name of the level.

  • New way to invoke info screen
    • You don't have to enter info mode any more to be able to see information on selected item(s). Just point with a mouse to it and press I. That will display info as long as you hold down the key.

  • Cut mode
    • Now you can easily cut selected polygons or sectors using one plane. Select polygon(s) or sector(s) that is target of your splitting. Enter cut mode using Ctrl+X. In cutting view, hold LMB and drag to define cut line. You can modify cut line by adjusting positions of two control points. You can exit cut mode using same shortcut or apply cut operation along defined line using Enter.

  • Gradient marker
    • Gradient marker is entity that can be used to define gradiental lightning (either as dark light or as illuminating one). World base contains pointers to gradient markers. If world base points to a certain gradient marker, polygons of that entity can be assigned to be lightened by gradient defined that marker. After world base and shadow gradeint are conneceted, name of the gradient can be browsed using gradient combo box on shadow page of info window. These markers are used to create vertical shadow gradients thus simulating radiosity behaviour of light in a room. This way you can easily define darker shadows beneath roofs or emanating areas over lava. Gradients are defined using height and two colors.

  • Usage of mouse wheel (MW)
    • Mouse wheel can be used for many different things. In free fly mode, use it to double/halve speed of moving. Use Ctrl+MW to toggle modes. In polygon mode use it for browsing trough selected polygons. In entity mode use it for browsing trough entities selected in volume. Also, use Ctrl+Shift+MW to auto select previous/next property or just Shift+MW to select fist previous/next empty target property.

  • New way to work with volume
    • Volume is kind of entity container. You can visually define area of space occupied by 'green box' visible in volume mode (V). In volume mode, you can 'feed' this volume with all entities inside green box. If you invoke select entities dialog, you will be able to toggle working with entities in world and working with entities in volume. In entity mode, you can directly 'feed' volume by currently selected entities using key F. You can also instantly select all entities from volume using Ctrl+A. Mouse wheel is used to circle trough entities in volume.

  • Pretenders
    • You can 'tweak' visibility using this feature. Pretender is a portal that becomes opaque instead of transparent, and stops adding sector behind it after certain distance. This way you can cut off part of level and create texture that will render instead of it. Portals become pretenders after distance that can be defined on polygon page of info window. Distance is given in meters. If it is 0, portal isn't pretender. This feature can be applied only for portals.

  • New selecting shortcuts
    • There are two new types of shortcuts used for selecting. Each shortcut acts according to current mode. Ctrl+A selects: all entities in volume (in entity mode), all entities in selected sector or sector under mouse (in sector mode), all polygons in sector (in polygon mode), all vertices in polygon(s) (in polygon mode). Another shortcut, Ctrl+Alt+A, is used to select all members in certain mode and to switch to next mode. This way, you can select all sectors in selected entities (in entity mode), all polygons in selected sectors (in sector mode), all vertices in selected polygons (in polygon mode). For example, If you select an entity and press Ctrl+Alt+A three times, you will be in vertex mode and will have all vertices from that entity selected.

  • Other minor changes:
    • - increased number of available gravity marker pointers in world base entity
    - select any number of polygons and request displace map exporting for occupied checquered area
    - you can set stairs flag for polygons, to define specific smooth translation of player over stairs
    - now you can define any texure or color filling polygon modes for isometric views
    - copy/paste (Ctrl+C,Ctrl+V) in polygon mode doesn't copy all polygon properties any more, it just copies texture properties
    - hiding and showing opearations are now available also for entities. Shortcuts are the same as for sectors
    - smooth scroll of thumbnails and icons for changing display type are added to browsing window
    - in entity mode, Ctrl+E is used for selecting clones, Ctrl+Shift+E for selecting entities of the same class,
    - in polygon mode, F is used for invoking filter polygons dialog
    - you can re-triangularize two selected triangles (context menu, polygon mode)
    - system is implemented that rejects most of the entities as possible targets thus not adding them to target combo box
    - light class is modified to enable animation of both ambient and diffuse components of light
    - when Serious Sam application is started, it automaticly finds all custom levels and adds them to "Start custom level menu"
    - there are new console commands available that can be used to change rendering preferences during game testing
    - there is ability to execute script for a shortcut from Serious Editor. Available shortcuts are F2,F3,F4 and Mouse 3
    - Serious Modeler: ability to recursivly render axis of all attachments
    - Serious Modeler: ability to simulate translation of model along z-axis
    - Serious Modeler: .map file is now automaticly saved, containing information about model (attachments, collision,...)


Serious Modeler Changes v.03

New Serious Modeler Features and changes

1) With addition of new 3d object formats to import capabilities of Serious Modeler, new lines have been added to .scr file (for indepth explanation of script file please refer to Serious Tools Help file under Serious Modeler->Model Creation Tutorial-> Creating Models and Scripts).

By default, mapping is read from object model is created from. If there is no UV data assigned to polygons in that object, error message will be produced.

; Old style mapping definition <-- Legacy maping loader for compatibility with old maping loader (no longer needed, thus commented)
;DEFINE_MAPPING
; CoolWeapon_Closed.lwo
; CoolWeapon_Opened.lwo
; CoolWeapon_Unwrapped.lwo

2) Map file (.map) is now saved whenever model is saved (for indepth explanation of map file please refer to Serious Tools Help file). This eliminates problem of different values in .mdl and .map file if .map file wasnt updated to reflect changes in model.

3) Tiling texture shortcut (T) in Mapping mode has been removed, use icon "Toggle texture tiling" instead.

Texture mapping bar with toggle texture tiling button squared in red |
 | Texture tiling options

4) New animation controls have been added to Animation control window of Serious Modeler. They consist of 2 values. First determines how fast will be loaded model translated along Z axes and second how many time will current animation loop. This controls is usefull when creating walk/run cycles for characters. When given speed of character from engine, you can type that value as first parameter and add few loops in animation to see does your character animation is in sync with that speed (to avoid sliding etc...).

1) Z axes translation speed 2) Current animation looping time |
 | Animation control

5) Axis rendering is added to Serious Modeler. This feature is usefull when handling multipart models (via attachments). It is accesed with "X" shortcut or "Toggle axis rendering" button. It has 3 states: OFF- no axis rendering, NORMAL - only loaded model's axis are drawn and RECURSIVE- axis are rendered for current model and it's attachments. You would use that to help you adjust positions of attachments in for example Weapon items models. Basically weapon item model is set of triangles on wich you attach different models. In game, you want player to be able to pick new weapons during play. For that use Weapon Item model. It will be rendered in world as rotating model with particle effects. You want rotation to happen along its axis, thats when rendering axis in Modeler comes handy, to adjust attachments positions in case they arent offseted correctly. Try loading any multipart model, enable RECURSIVE axis rendering and click "R" to enable model rotatition to see if its roation axis are offseted.

Axis drawn for current model only |
 | Normal mode ON

6) Frame rate info has been added to Serious Modeler (similar to World Editor's one). Its toggled on/off with "alt-r" shortcut or "Show/hide frame rate" button in main screen. It comes handy in case of multipart models (with attachments). In example of RocketLauncher weapon. It consists of 5 triangles (2 for body parts and 3 for rockets). Every attachment on that model have LOD (created either manually or with Serious Modeler auto mipmodel creating tools). When you look in Info window ("Q" shortcut) under Mip tab you will see number of polygons 5. This is because Modeler normally dont count polygon count recursive (adding it from attachments). With frame rate info you can see from how many models actual models consists and how many polygons are in total (Including Floor model, so disabling floor rendering with "F" shortcut is good idea). If you have defined and adjusted miplevels (for more on defining and adjusting LOD check Serious Tools Help under Serious Modeler->Modeler Usage-> Defining LOD), with SPACE+RMB zoom out model and see how number of polygons and models change when miplevel is changed. This way you can see when miplevel is changed and how many polygons are removed in each miplevel, then use that information to adjust switching factor if needed. This eliminates need to constantly reload model in World Editor to adjust effective miplevel switching.

1. World info only (no use in Serious Modeler) 2. Total number of models and total number of polygons 3. Time needed to render models 4. World info only (no use in Serious Modeler) 5. Swap buffer time 6. Current framerate |
 | Frame rate info
7) Update animation process has been Seriously optimised ( now faster more than 60times!!). Thank you Dean.

8) You can mix different file formats in animations sequences (adding animations in script).

9) Misc bugs have been fixed, some optimisations in model recreation/update have been done, resulting much faster process.


Serious Engine Overview

Overview

In 'Serious Engine', 3D world can be imagined as a set of entities (everything is an entity: sound, enemy, item, light, architecture, ...). Entities can be rendered as brushes or models. Models are objects compiled with 'Serious Modeler'. They are build from many polygons (enemies, trees, statues, ...). Models use level of detail (LOD) system for fast rendering. Brushes are entities that form world's architecture. They are usually big solid objects like a building or a mountain. Brush contains sectors, sector contains polygons. Each polygon has up to three layers of textures (picture or series of pictures saved in a specific format). Polygons between sectors are called portals (these terms are specific to engine, but are very important). Portals are used in dynamic visibility determination.

If you are creating a game from scratch, you have to create models, create entities (programming classes of entities), and build worlds. First you create some 3D models using Serious Modeler. After that, you code classes to use these models. Then you build a world using Serious Editor. Create textures from targa pictures and texturize your world. At the end you drop some entities into world and adjust their properties.

If you create custom levels, you build worlds using already existing entities and altering their properties.


Basic Information

Engine Directory

First of all, Serious Engine requires that all the files it manages reside in one directory, or any of its subdirectories. It is not allowed to load or save a file from outside that directory, or from some other disk. We call that directory 'engine directory' (engine dir for short). This keeps all the files in one place and prevents the possible problem of using the absolute paths in inter-file dependencies. Any file is uniquely identified by its path relatively to the engine dir.

On each computer, the directory can have a completely different name; you can even have more than one copy of the engine at the same time coexisting on the same system.
When the game or any of the editors is started, the engine auto-detects the path from where it is started. In the entire engine dir and its directories, there are no files with any references to the absolute path of the engine dir. That way, you can simply make a copy of the entire engine dir to another directory, disk or computer, and it will automagically work.
When working in a team, you will usually want to share that directory to be visible to the other members of your team through network, so that they don't need to take care where you put it. Also, you may want to make a master directory on a fileserver for keeping the newest version of all the files (artwork, sounds, levels, etc. there).

If you have installed Serious Sam and the Serious Engine tools, you probably have engine dir like 'C:\Program files\Croteam\SeriousSam\'

It is very important that you remember that you cannot load any file out of that directory. If you try to do so in an editor, a warning message box will pop up telling that 'the file resides outside of xyz directory and it cannot be loaded', where xyz is your engine dir. To load the file, first copy it somewhere inside the engine dir.

Directory Structure

Inside the engine dir, directory structure is more or less free. Some files must be in specific directories, but the rest is flexibile. Here, I will describe the structure used for Serious Sam in detail:
Bin\
The binaries of engine, game, entities and editors must reside in this directory.

Bin\Debug\
Debug versions of the binaries are located here.

Classes\
Entity class links (.ecl) files are located here. Those are used to identify individual entity classes.

Data\
Misc data files, like file lists, config files etc. are saved here.

Data\Translations
Translation files for language localization are located here.

Data\Var
Some specific variables that need to work independently of the usual persistent symbol storage scheme are put here saved as text files.

Fonts\
Font files and their respective textures.

Levels\
World files for the game.

Models\
Put model '.mdl' files here and in the subdirectories.

Models\Editor\
Some specific model files required by WorldEditor and Modeler must be here.

Music\
Music .mp3 files.

Players\
Player configuration files (players name and appearance for each player).

SaveGame\
Savegames are saved here sorted in different directories for each player, plus one directory for split-screen multiplayer saving and one for network multiplayer.

Screenshots\
Screenshot are auto-saved here when you press F11.

Scripts\
Script files for the console startup.

Scripts\GLSettings\
Special scripts for automatic adjustment of GL settings for each 3D card.

Sound\
Sound files (.wav)

Temp\
Engine, game and editors save various temporary files there. For example, quick-saved demos, editor undo/redo files and clipboards, and similar are saved there.

Textures\
.tex files

Thumbnails\
Thumbnails (.tbn) for each entity class that can be inserted in the world.

VirtualTrees\
WorldEditor saves your custom virtual directory trees for the browser there.

If you are just making additional content for the Serious Sam, you will have to respect this structure in order to have the things work. If you have licenced the engine, perhaps you may want to change it thoughly if you need to. (Maybe you don't need player configurations, savegames and such things, which are Serious Sam dependent.)

Working with File Dependencies

Each file by itself is a separate module and the engine does not rely on any kind of packages. Still, there are some things that you have to take care of before moving files around. The files are refered to by their paths relative to the engine dir. If, e.g. a world 'levels\mylevel.wld' uses a texture 'textures\wall01.tex', and you decide to move the texture to 'textures\walls\bricks.tex', the world will not be able to load any more. To enable you to do that, Serious Engine supports automatic file replacement.
The file 'Data\BaseForReplacingFiles.txt' maps names of original files to the paths where they have been moved to. In the above example, if you add a line:
"textures\wall01.tex" "textures\walls\bricks.tex"
to that file, the world mylevel.wld will be loaded automatically replacing the the old path name for the new one. If you try to load the world without making the replacement file in the game, the loading will fail. But, if you try to load it in the WorldEditor, it will ask you to browse for the new file. If you do that once, it will remember the replacement in the aforementioned text file, so if you try to load another world with the same texture, the replacement will work automatically without your intervention. At the end, you will be noted that some replacements were made.

This is a usefull tool if you rename/move your files sometimes. However, sometimes you may not want that to happen. Perhaps, you want to know that you don't have some file on disk. If you use the replacement feature, you may want to check the remap manually in a text editor from time to time, to make sure you know what is going on. Also, take extensive care not to create recursive remappings!

Usual dependencies are that the worlds depend on all the textures, models, sounds and classes used in the world. Classes depend also on the models, textures and sound used by the classes. Etc.

Those dependencies are saved in each file that engine uses in a special tagged format. The Depend utility (depend.exe) can later be used to extract those dependencies and see what is dependent on what. This is useful for updating new versions files, for distribution of new content and similar.

For example, once you have created a level, lets say 'levels\mylevel.wld', you can use Depend utility to recursively extract all the files needed to run that level. If you then want to distribute that level, you know that you must include all those files in the distribution. You can also check those files against some previous distribution of the game which did not contain that level and find only those files that are newer or added, etc.

For more information on how to use Depend utility, see its own documentation.

Group (.gro) Files

Serious Engine, its editors and the game will work very well having all the files put in directories like said above. However, putting several hundreds of files in their directories is both inconvenient for the end user (due to the mess itself, and potential induced slack-space) and impractical for distribution.

To solve that, you can zip a group of files together in one large '.gro' file. Group files are just ordinary zip files, which you can create using your favorite zip utility (like InfoZip, PKZip, WinZip, WindowsCommander, etc.). After compressing it, rename the file to give it a '.gro' extension, and put it in the engine directory (in the root of it). At startup time, the engine will scan for all the group files in its engine dir and add them to an internal search list.

When loading a file, engine uses following scheme:

If MOD is started
- it first tries to directly open the file on the disk, but relative to corresponding mod directory (i.e. Mods\MyMod\Models\Player\SeriousSam\...)
- if file isn't found, engine tries to locate it in all .gro files in mod root (Mods\MyMod\) directory, following reversed alphabetical order logic (newer versions by alphabetical order have priority)
If MOD is not started
- it tries to directly open the file on the disk (in its corresponding directory)
- if file doens't exist on disk, it searches on CD - if the file is not there, it looks in each of the group files in the reversed alphabetical order
- if the file was not find even in the group files, it tries to look for the replacement file path if the replacement is found, return to 1) and try again with the new path
- if no replacement is found it asks the user to locate a replacement file (only if editors are installed)
- if the file is still not found, an error is reported

So when you add a group file with a completely new content, you can generally give it any name you like, provided it has the '.gro' extension and that it is located in the engine dir root.
But, if you want to create a group file which will override some older file, you must make sure that:
1) The file that needs to be overridden does not exist on the disk. Physical files on the disk always override all group files.
2) The name of the group file is _after_ (in the alphabetical order) all the other group files that might contain the file to be overridden.


Optimizing Rendering Performance

Here are some guidelines for how to extract maximum from Seroius Engine (SE). There are simply too many thing that are more or less related to engine performances that you cannot get just one number out. What you're about to read in this chapter will clarify some things, but practicing will help you to increase performance factor from SE.

There are some rules that you should stick with:

Visibility: Serious Engine implements dynamic visibility rendering algorithm based on idea of advancing trough sectors (also called zones) connected with portals (polygons between sectors). Models are then rendered if the sector they are classified in is rendered. Common world in SE is actually a soup of entities, but there is one major zoning entity, entity that controls visibility. This huge zoning entity is used to define sectors. Sector is actually group of polygons. Some of them are portals, serving as a link to another sector, some of them are occluders, some detail polygons (don't occlude anything). Generally, you have to build major world architecture on the initial 'WorldBase' brush (you may change its name if you wish) which is 'Zoning'. Zoning means that sectors of that brush will define visibility zones in the world. Non-zoning brushes are not involved in zoning process.

We will explain in more detail how visibility determination and rendering in SE works:

In the simplest case you have only one brush entity which is zoning and has some sectors. The rendering process begins by starting from camera position and adding all the zoning sectors that directly contain the camera (camera is not one point, but rather considered as entire bounding box of a player).

All the walls and portals of those sectors are tested to see if some of the occlude another. (This process is the heart of the SE, it is called ASER - advancing sorted edge rasterizer, and is very fast).

If some portal is found visible (i.e. not occluded by any walls), the sector(s) on the other side of that portal is added too. That means adding their walls and portals too. The procces loops until there are no more visible portals to add. Now all the walls and portals (portals are rendered as semi-transparents if translucent flag is set, like water surface) of all those sectors are rendered to screen.

Effectively, if one zoning sector is not visible, then it is not even considered by the algorithm. This is where the speed ups come from and you should try to maximize that speed up by sectorizing your world properly.

Now, all the models and non-zoning brushes in the world are classified with respect to which zoning sector(s) they are in, and they get rendered if those sectors are determined visible.

Now, if you stand in a room and you don't see the door out, because e.g. there is a column between you and the door, or if the door is closed, the room on the other side of the door will not be rendered. This means that all the models, brushes, particles, lensflares etc, in that other room will not even be considered for rendering and will spend 0 CPU time.

Let's consider how you should create a world utilizing terrain, water, and building filled with columns:

1. Start from a room primitive. Create the terrain as a room, not material, and then select all the polygons around it and mark them as portals (to see through to the background. And make the terrain zoning. This gives you the first room to start working with.

2. Major buildings. Not join, but add the two buildings, so that they define new zoning sectors inside the buildings. Do so with every major building. Those little ones, I'd advice to make non-zoning, but create two mips, so that second mip doesn't have the interior.

3. Doors. Add doors to the passages leading inside the buildings, so you cannot see inside from far away.

4. Full bright. Make terrain's polygons 'full bright'. It is wise to make terrain texture exactly as you want it in the game (of exact brightness, rendered with shadows directly on terrain texture). Then you can turn on flag 'full bright' on all terrain polygons, which will turn off the shadow on them. That way you keep the visual quality, but gain rendering speed and conserve memory.

5. Water. Split terrain sector horizontally, where you want to put water surface. Then simply select this newely created portal (from both sides), give it 'transparent' flag and water texture via blending mode, so you can adjust translucency.

6. Sector content. If you want player to swim in water, just select water sector and change content to 'water' (at sector properties tab). Simple as it is.

7. Adding. You don't add brushes to one another where they can stand separated, When you make a new brush, you know that you can either 'join', 'add' or 'substract' it. If you join it, it becomes a new entity in the world - it means you'd create a non-zoning brush. If you add it, it is CSG added to the current 'target brush' (displayed on the toolbar). Make sure you take care what to add to what. You shouldn't e.g. added some columns to one another, etc. You can see what was added to what by selecting entities in the entity mode and observing what becomes blue. Generally, you should have one zoning brush and add all major architecture to it. Each of the columns, small houses and such detailed objects should be non-zoning brushes. And keep each column, house, etc. to itself, Don't merge them together.

8. Detail polygons. Maybe the most important performance increasers. What are detail polygons? These polygon aren't included in visibility determination process. This is due the fact that some polygons are not much of a occluders. For instance, if you have big wall, it IS occluder and therefore should not be detail. On the other hand, tiny little stairs aren't much of an occluder, so it is best to be rendered as detail polygons. Pillars, little brushes, anything that doesn't block the view has to be detail. This helps performance big time!

9. Mip-brushing. The case of stairs. Stairs are nice, but there are lot of polygons which you can't quite see from a distance. You're stairs looks great when I walk over them, but form a distance, they look just like one slope. And this is the school case for mip-brushing usage. Let first mip-brush be stairs at they are, but you make next mip-brush just with slope. Adjust mip-brush switching distance and see how your stairs switch to slope (lower mip-brush). When you can't see much of a difference, than you have optimal quality-performance ratio. From near, your stairs looks great, and from far no one will see the difference except CPU. :) It'll be much faster.

10. Use models as architecture. Some things are better made from models than brushes. Columns especially. That way you can have columns with lots of polygons that render very fast and have automatic LOD. You make a model of a column and put it in world. Since models have inexact collision, you then build a simple brush with much less polygons and mark all its polygons as invisible (so that they are not rendered). Take a look at how those rounded columns are made in the beginning of our demo level (Karnak Temple Complex).

11. Mirrors. Handle mirrors with care! Mirror have one nasty habbit - it reflect world. This means that everything in the world must be rendered twice. So, you must be very carefull with what you want to be reflected. Closed rooms with hight frame reate are ideal for mirrors. But be carefull! If mirror reflects something that comes thru the door, this might be the problem. If your level has lot of details, everything has to be calculated once again for the mirror reflection, EVEN IF IT IS NOT DIRECTLY VISIBLE IN THE MIRROR. This results in 2x performance drop.

12. Drop entities to floor. This is nice little feature in SED that is used to drop trees, items and other entities to drop down. Select entities, click RMB, and select 'drop to floor'. This will let the gravity do the biz.

13. Decadic grid. Don't use it. Humans think decadic, machines not. They prefer binary. So, it is much better to use binary grid (there are lotta reasons, I can't mention them here). The main issue is precision. You can have some glitches in geometry that are directly caused by decadic grid imperfection.

14. Directional light. You should use it. You can adjust ambient color of directional light which is infact the color of the shadows. Experiment! Also, sectors can have their ambient light. You can find it in sector property page. They work best in combination with dark lights and gradiental shadows.

15. Polygon splitting. Cut polygons with many edges, they tend to slow-down physics considerably.

16. Detail textures. just two basic rules:
(a) have to be in 3rd layer (you can easly switch this layer off to gain performance on slower 3d accelerators)
(b) detail textures must be 'equalized' and applied with 'shade' blending mode. This will produce both best visuals and best performance.

Equilized texture means exactly what 'equilize' function does in Photoshop. It spreads all the gray levels equally over tones. This means that last texture's mipmap will have middle-gray tone (128 value, +-3). In shade blending mode, this texture can be removed and no-one will ever see the difference. So, when you're looking at the wall from far distance, detail texture won't be rendered at all, but everything still looks the same.
Console variable for adjusting mipmap in which detail textures won't be rendered is 'wld_iDetailRemovingBias'. If you turn 'wld_bShowDetailTextures' on, the textures that satisfy the 'equalization' rule will be rendered in magenta if it is on 3rd layer, or cyan if on 2nd layer.


Serious Editor Overview

Overview

Engine's main editor is Serious Editor. It is used for creating 3D worlds. You build worlds by adding or substracting primitives (objects that form some kind of opened or closed 3D geometry like box, sphere, stairs, terrain,...) and by adding entities (lights, trees, platforms, enemies,...).
When you create a new world, it is completely empty. This emptiness can be either unlimited empty space or borderless solid material. How Serious Editor will consider it, depends on the first operation that you will apply. You can either drill a hole in material (this way you get your first room) or add some material into empty space (this way you can get a column).
A standard room can be created in two ways: by adding a primitive limited by walls (a box with polygons oriented inwards) or by substracting some material (a box with polygons oriented outwards). When you add a room to an existing room, you will get some kind of a corridor. If you add a box inside a room, you will get a column. It is simple and logical for adding operations: if you add a material into space, you get material. If you add a space into material, you drill a hole. If you subtract material from material, you drill a hole in it.
Serious Editor is a standard Windows multi-document application. That means that you can work simultaneously on one or more worlds, each world can have many windows opened for viewing, and each window can be divided with splitters into 1,2 or 4 views.
There are several popular editing techniques used in Serious Editor, such as: drag and drop, copy and paste, tool tips, data tips, status line info, editing with multiple selection, property editing, dialogs with property pages, trees, wizards, history, etc. All common operations have useful keyboard shortcuts.
This picture of a standard Serious Editor layout will be used to explain its basic components.

Components:

1. Toolbars
2. Status line
3. Views
4. Mode indicator
5. Entity property window
6. Tool window
7. Browser

1. Toolbars

Windows standard toolbars. They can be turned off and rearranged by preference. Each button has a tooltip with short description and optional shortcut key.

2. Status line

Right part of status line displays useful information like coordinates under mouse, object position or orientation, grid size, count of selected items... Main part of status line guides you in using keyboard shortcuts. Displayed message informs you what you can do with currently pressed keys and what other keys you can press.

3. Views

View displays currently loaded world. World can be viewed in many ways. There are many parameters that control how world and its components are displayed (wire frame, selection colors, shadows, sector colors, different projections,...). Serious Editor supports full customization of display settings. Up to 4 views form one window configuration. All views are updated simultaneously. You can define up to ten of your favourite window configurations and invoke them quickly when you need them. Common window configuration contains 4 views: world rendered in top, front and left projection and one perspective (3D) view. Another commonly used configuration is with one perspective view displayed in full rendering quality (used for game testing).
For navigation, Serious Editor uses an unusual but very powerful system. Two control points define camera position. These control points are viewer and focus (you can imagine them as arrow tail and arrow head). Viewer (arrow tail) always looks at its focus (arrow head). Viewer always rotates arround focus. Focus can be translated. Distance between viewer and focus can be increased or decreased. Changing of distance applies zooming (arrow stretching).
This whole concept of camera positioning allows extremely easy navigation when one gets used to it. For example, you can double click point anywhere in a world that you want to focus to. Make sure you exercise navigation tutorial before you start editing.

4. Mode indicator

Serious Editor can be in few modes: entity, sector, polygon, vertex mode, and layer mode,. You switch modes depending on what you want to edit. Layer mode is a mode where two worlds are rendered simultaneously one over another. World in second layer is floating over the one in document and can be moved or rotated freely. You can't switch to another mode while you are in layer mode. You have to join (merge) the second layer before. Second layer mode is used either to edit architecture (usually with CSG operations involving primitives) or to merge two worlds.
Current editing mode can be easily recognized by the color of a box placed inside status line (blue color stands for entity mode, green for sector, yellow for polygon, black for vertex and red for layer mode). This colored box is called mode indicator.

5. Entity property window

Entity property window is a docked dialog used for editing entity properties. It is placed just above the browser. Entities have attributes that can be altered using this dialog. Dialog is split in two parts. In first part, by using combo box, you select attribute that you want to change. At the top of the dialog there is information about class of selected entity, name and description. According to selected attribute type, the lower part of the dialog changes enabling you to edit many types of attributes in the same place. You can either change property values of one selected entity or multiple entities by using entity selection (so you can select all lights inside one room and then change their color). If you select more entities of a different type, you will be offered to edit only attributes that they have in common.

6. Tool window

The most used tool in data editing is tool window. Too window is floating that contains property pages. Configuration of tool window's property pages is changed when editing mode is changed. For example, when you are in polygon mode, you can edit textures, reflections, shadows, ... When you are in sector mode, you can edit properties of selected sectors like content, gravity, ambient light,... Tool window is also used to define shape of primitives.

7. Browser

On the left edge of Serious Editor layout is window called browser. Browser works just like 'Windows Explorer', but uses virtual directories (they don't actually exist on disk). It displays one virtual directory tree. Virtual tree can be loaded and saved, so you can have more virtual trees. This way you can have one virtual tree for each world that you are working on (for example, tree with special textures and architecture templates for egyptian world). Little window on top of browser acts like folders part of 'Windows Explorer'. Here you can select curently opened ditrectory, create new ones, delete, rename, ... Tall window shows items (virtual files) of currently opened directory using their thumbnails or file names. You can have unlimited number of both directories and items. Items can be entity classes, textures or worlds. An item can be dragged and dropped into world. This way you add new entities, texturize polygons or merge two worlds.


Serious Engine Navigation Tutorial

Navigation tutorial

To be able to use Serious Editor properly, you will have to exercise navigation first. This tutorial will guide you. You will practice navigation in a simple world prepared specially for that purpose. First, you have to open the world. Open the file named "Help\Serious Editor\Navigation Tutorial.wld". Loaded world should look like this:

Views:

1. Top view
2. Front view
3. Side view
4. Perspective view

General

The first thing to know about the navigation is that if you want to do anything, you must hold Space. By holding Space, you define that you want to move the viewer. It is also important to know that Serious Editor auto focuses the window under the mouse pointer. That means that you don't have to click on a window if you want it to have focus, just put the mouse over it. This is a very useful feature, but can be irritating when you first start working with Serious Editor. For example, if you want to edit a string or a number in any of the dialogs, take care not to accidentally move mouse over some view or the edit control will loose its focus. Once you get used to it, it will not bother you any more.

Movement - Space+LMB

We will start practicing navigation by exercising in the top view. Place the mouse over the top view (window no 1). Press and hold Space. Then press the Left Mouse Button (LMB) and move the mouse a little bit. After you release the LMB, all other views have changed. That happened because you moved the viewer focus. All other views update according to the new position of the viewer focus. Release the Space button. Move the mouse over the window no 2 (front view). Hold Space and press the LMB again. Move the mouse. Now you are moving the focus in the plane of the front view. Repeat the same process for the side view (window no 3) and perspective view (window no 4). When you hold Space and LMB, you move the focus left/right/up/down.

Zooming - Space+RMB

Now we will practice zooming. Zooming is actually decreasing of the distance between the viewer and the focus. Place the mouse over the perspective view (window no 4). Hold Space, press Right Mouse Button (RMB) and move the mouse up/down. You get a feeling of going in/out of the screen. This is because the distance between the viewer and its focus is changed. Now try to move the focus left/right/up/down like we practiced in the previous chapter. Notice that the speed of moving left/right (applied with Space+LMB) depends on how close the viewer and focus are. Zoom in a lot (hold Space+RMB and move the mouse down few times). Now try to move using Space+LMB. It is hard to move at all. You have to zoom out if you want to move significantly. This moving/zooming relationship can described with an example: imagine that you are examining two pictures with a magnifying lens. First is a close-up picture of a brick. Second is a satellite picture of a city. If you move the lens over the first picture, you have moved the focus for a few inches. If you move the lens over the satellite picture in the same extent, you have moved the focus for few miles. Practice zooming and moving together, until you are sure that you know how it works.

Rotation - Space+LMB+RMB

We are still missing the rotation to complete the navigation functionality. It is important to notice that the viewer is always rotated around its focus. Put the mouse over the perspective view (window 4). Hold down Space and press both mouse buttons. Move the mouse around to apply rotation to the viewer. The rotation is performed using a trackball system. Trackball system can be compared to rotation of a sphere (this way the trackballs used in laptops are rotated). Heading (horizontal angle) is changed by left/right mouse movement while the pitch (vertical angle) is changed by up/down mouse movement.

Teleporting - Space+LMB-double click

It would be very hard to navigate around in large worlds if focus teleporting wouldn't exist. Focus teleporting is a process of instant movement of the focus to a picked point in the world. By focus teleporting you actually say "I want to focus that point". Focus teleporting is performed by holding Space and double-clicking the Left Mouse Button. First you place the mouse over the perspective view. Then you move it over any point in the world that you want to focus to. Press Space and double-click the LMB. Focus has teleported to the wanted position. You can also exercise rotation around the teleported focus. Practice the focus teleporting a lot, because once you master it, you will be able to examine a world lightningly fast.

Teleporting with Zooming - Space+Ctrl+LMB/RMB-double click

Best navigation performance is achieved using a special option: 2x zooming with focus teleporting. Zoom in 2x with focus teleporting is accomplished by pressing Ctrl+Space and clicking LMB. The point under the mouse pointer is focused and zoom in 2x is applied. If you hold Ctrl+Space and click RMB, zoom out 2x will be performed. If you get accustomized with this way of navigating, you will be able to navigate around quickly.


Serious Engine Basic Room Tutorial

Basic room tutorial

In this tutorial we will create a room. The room will be pretty simple, but will contain some columns. It will be textured and lighted. At the end of editing, we will apply reflection to the floor, add one enemy and play-test what we have done. This tutorial goes along with accompanying movie of a room creation process. You can download a movie from the Croteam site.
This is a screenshot of a room that we will create:

First of all, we have to create a new document (world). We do it using the File/New command. When the new world is created, we can see a small spherical object that looks like the Earth (see picture).

This is our first brush entity of the world. Since it has no polygons yet, it is called empty brush. Serious Editor displays empty brushes as small globes. The brush will be displayed as a globe until we apply an operation that will create some polygons.
To add some polygons, we will drill a room in the infinite solid material of this new world. To do so, we will invoke a Conus primitive by clicking on [image]. As we clicked on the tool button, mode indicator turned red, indicating that we are in layer mode (CSG mode), and the Tool window appeared. We will type parameters that will define our primitive. Notice that typed value will not be applied until Return key is pressed. Since we want to create a room, we will set room flag to on, meaning that primitive will define interior. This way we will get a room surrounded by walls. If we didn't set room flag to on, we would get a box with polygons looking outward.
For our example we will use a room primitive with parameters like this:

Position: X=0, Y=0, Z=0
Orientation: Heading=0, Pitch=0, Banking=0
Size: Width=16, Lenghth=24, Height=8
Shear: X=0, Y=0
Stretch: X=1, Y=1
Vertices 4
Room flag: On

For the given values, Position and Primitive pages of the Tools window should look like this:

We have to select default texture for our primitive. We will do that by double-clicking on a texture thumbnail in the Browser window.
First we have to invoke virtual directory that contains textures. You can do this in three ways: by browsing to the "Textures" directory in the upper window showing directories, by pressing W and clicking "Textures" button (offered directories have keyboard shortcuts set) or by pressing the shortcut key of the "Textures" directory (3 on the main keyboard).
Now double-click on third texture in first line to apply it for floating primitive.
Now Serious Editor layout should look like this:

If you did anything wrong, and the primitive does not appear the way it should, you can always press theCancel CSG tool button ( [image]). It will cancel the CSG mode, without applying any changes.
To drill a hole in the infinite solid material of the world, we will have to add this room primitive. Press the CSG Add tool button ( [image]). You can as well press the keyboard shortcut for CSG Add which is + on numeric keyboard. When you have added the primitive, CSG mode is turned off as the floating world and the editing one are merged. Our world should look something like this:

Again, if you did something wrong, you can press Ctrl+Z to undo the CSG operation. The room is here, but is completly dark because there are no lights. We will add some lights later, but first we will texturize this room. That means that we have to switch to polygon mode. You do that by pressing P. Mode indicator must be yellow. To be able to texturize without any lights added, you have to turn off the shadow maps. Shadows are toggled by clicking the Toggle Shadow button [image] or using shortcut H. Tool button with shadows turned off should look like this: .
World is now rendered in full bright:

Serious Editor uses polygon grouping for easier selection. Each polygon can be colorized individually. You can use colorizing to group individual polygons at your preference. Polygons grouped in this way can be quickly selected by double-clicking. You just have to double-click on any of the group's polygons and the whole group will be selected. All polygons of a primitive are colorized with the same color by default. That means that we will select all 6 polygons of our room by double clicking. As you try it, you can notice that the polygon selection is displayed as a yellow filter. If we want to group only polygons that form the walls, we will have to colorize them. First we have to select them. We select them by selecting all polygons (double-click on any) and then deselecting the floor and ceiling (deselect them by clicking on them while holding Shift). We can also select each of the wall's polygons by shift-clicking them. When we selected the wall polygons, we should colorize them. Colorization is carried out through Colors palette window. Colors palette is invoked using tool button [image] or by shortcut C. Our room with selected walls and invoked Colors palette looks like this:

When we click on a color from the Color palette, polygons get colorized. Selection can be canceled with the tilde key (~). Note that tilde key will work only on some keyboards. You can also deselect by mouse click. Deselect the polygons. We will examine polygon grouping in color rendering mode. There are numerous parameters for controling rendering at your disposal. Rendering parameters can be set for each view. All views of a window form one window configuration. You can define up to 10 window configurations with rendering modes at your preference. Window configurations are stored and restored using numbers on numeric keyboard (they are stored when holding Ctrl). Color polygon rendering mode is stored as the window configuration no. 2 by default (can be invoked with Num 2 ). Commonly used window configuration with three isometric projections and a textured perspective view is stored as the configuration 0.
Our room rendered using polygon colors looks like this:

Switch back to window configuration 0. Now we will texturize the room. Double click on a wall. You have selected all four of the wall polygons. Yellow selection filter will bother us when texturing, so we will turn it using button [image] or shortcut Z. We still have the polygons selected, but the selection is not visible any more (right part of status line displays a message with the count of selected polygons). Open the virtual tree directory containing textures (shortcut 3). Double-click the texture of Egyptian painted wall texture (second column, second row) that looks like this:

We applied the texture over the selection. Now we have something like this:

We have to adjust mapping of the textures to fit on our walls. We can adjust offset, rotation and stretch. Press Q to invoke the Tools window. Texture property page is used for defining mapping. After we typed 0 for offset and rotation, we have to type 0.5 under texture stretch for both axis. Now we textured our walls properly. The interface enables few more things for mapping control: +-90 deg. rotation (Tab, Shift+Tab), 2x zooming (Ctrl+Alt+LMB/RMB), mapping moving (Ctrl+LMB+mouse move), mapping teleporting (Ctrl+LMB double-click), spreading mapping using copy (Ctrl+C) and paste (Ctrl+V), ...
This is how our room looks with textured walls:

Now we will create a column. It will have a footer, body and a header. Footer will be created from a conus primitive [image]. When you invoked primitive it seams like your room is messed up. It is not erased nor destroyed, it is just that new primitive has same size as your textured room, and is rendered over it. Newly invoked primitive always has same size as last primitive that has been applied. Overlapped rendering occured because of this. Set Width to 2, Length to 2, Height to 1 (size 2x2x1). Set 4 vertices, Room flag off. Double-click on the texture named "Textures\Test\BetterQuality\Border10.tex" (check name using tooltip). Here is how it looks like:

Move primitive using Ctrl+LMB in the top and front views until it reaches coordinates x=-4, y=0, z=-6 (you can check coordinates on the status line or set them manually using the Position property page).
Layout should look like this:

We will not add this primitive using a CSG operation, but will add it in a way that will not merge their geometry. We will join these two worlds. This means that no mathematical operations will be applied. The entity that holds the column footer from floating world will just be copied into the edited world. This operation is called Join layers and is applied with button [image] or shortcut L. We can see that the mode indicator is blue informing us that Serious Editor switched to the entity mode. If we turn on selection filter ( [image] or Z) we can see that the footer is now an entity. That means that it can be moved around because it is not merged with the other entity (our room).

Since moving of entities that form architecture is dangerous (imagine moving our world but leaving torches and other objects in place), it is disabled by default. You can enable it if you turn off their Anchored flag. We will also turn off the Zoning flag. This is a way to tell the engine that this entity does not define zones in the world, but is considered to be a detail object.
We will turn off these flags using the Entity property dialog. First we have to select a property that we want to change. Let's say Zoning flag. Using the combo box on the Entity property dialog, we select "Zoning (Z)". The lower part of the dialog shows a checked check-box. Clear it. Do the same for the Anchored flag. Here is how it should look like when turned off:

Now we will give a descriptive name to the column. Select the property named "Name (N)". Lower part of the dialog enables you to edit a string. Let's name it "Column". This is how it should look like:

We can see now that we have two entities in the world: a room and a column footer. We have to select which one's geometry we will edit. To set which entity will be modified, right-click it and choose Select brush menu item. Combo box embeded in the tool bar left to buttons that invoke primitives should show: "Column":

Now we will texturize the column base. First we switch to polygon mode (P). the mode indicator is yellow. We will copy texture from the room floor to the top and bottom polygons of column footer. Put the mouse pointer over the textured floor. Press Ctrl+C to copy mapping and texture values. Put the pointer over the top polygon of the column footer. Press Ctrl+V to paste texture and mapping properties from the clipboard. Do the same for the bottom of the collumn footer. Rotate to see bottom and paste the clipboard properties over the bottom polygon.
This is how texturized column footer should look like:

Column header will be created as duplicated column footer. Switch to entity mode (E). Select the column footer using the left mouse button. It should be blue. Copy it with Ctrl+C. Move mouse over the top view and point in the middle of the box representing the column footer. Press Ctrl+V to paste the column footer. You should have a situation like this:

Now move the selected column header to coordinates -4,7,6. It should result in this:

Add geometry of the column header to the column footer. You will do it by pressing ( [image]) or Num+. Make sure that the combo box displaying curent brush shows: "Column". When you added the header to the column footer, try selecting the entity. You will see that the footer and the header define geometry of one entity. We have to connect footer and header with a column body. We will use the Conus primitive ( [image]) with 8 sides.

Position: X=-4, Y=1, Z=6
Orientation: Heading=0, Pitch=0, Banking=0
Size: Width=2, Lenghth=2, Height=6
Shear: X=0, Y=0
Stretch: X=1, Y=1
Vertices: 8
Room flag: Off

Texture: Textures\Test\BetterQuality\Collumn05.tex

You have to add ( [image]) the column body primitive. Adjust mapping to fit the collumn body (adjust it on one polygon, copy mapping from it, select all polygons that form column body, and press paste when mouse is over selected polygon). It should look like this:

Now we have our column as an entity. We will multiply it to get 6 columns. Switch to entity mode, select the column (should be blue). Copy it. Move the mouse pointer over the top view and paste column twice, every 6 meters. Now you should have this situation:

Hold Shift and add the other two columns to the selection. Copy all three of them and paste them into the right part of the room. This is what you get:

We have to add some lights to our room. To see the light influence, we have to turn on shadows ( [image] or H). Perspective view displays our room in complete darkness. Now select the virtual directory containing entities. That directory is named "Entities" and invoked with shortcut 1. You will add a light entity using the drag and drop interface. Left-click on the light thumbnail ( [image]) and drag it over to the perspective view, drop it somewhere near the center of the coordinate system.
This is how world with the dropped light entity could look like:

We didn't notice any change in the perspective view, world is still dark. This is because shadow clusters are too big by default (2 m) and light's default range of influence is very small (1 m). First we will increase shadow quality. Switch to polygon mode (P) and select polygons that form walls of the room (double-click). Invoke tools window (Q). Set shadow size to 0.5 m using combo box on shadow property page.
Now we will increase light's fall-off. Switch to entity mode (E). Make sure that the light entity is selected. Select its property named "Fall off (F)". We should change its value to, let say, 8m. You enter 8 in edit part of entity property dialog, and press return (try setting a bigger fall-off value and then move light around. You will notice that the shadows are cast in real-time.).
This is what you get:

The green circle displays range of light's influence. We can see some little lighting on the columns in perspective view, but that's not what we want. This is because our light is in the floor (as we dropped it to coordinate with 0 altitude). Move the light towards up in front or side view for 2 meters. Now we can see lighted floor:

We can modify light's color. Select property named "Color (C)". The edit part of the Entity property dialog offers light editing using a control called Color button:

The Color button is divided in two parts. Right part of the button displays current color. If you click on it, you will be prompted to select a color using a standard Windows color picker. Left part of the Color button is used for continuous color editing. The three upper boxes visualize Hue, Saturation and Value of the current color. The three lower buttons visualize Red, Green and Blue components for the current color. A tall black box in the middle of the button visualizes Alpha chanell of a color. Tool tip displays values of these color components. Any component of a color can be modified by clicking on appropriate area and moving mouse horizontaly while holding the left mouse button down. By changing value for hue to 32 and saturation to 32, we colorized the light a little bit:

We need to add some more lights to our room. The easiest way is to do that is to copy the existing light and paste it few times over the room:

Now we will drop an enemy to add some action. Invoke the virtual directory named "Enemies" (invoked using 2). Drag the first enemy, "Beheaded Firecracker". Drop it somewhere between the two topmost columns as seen in the top view. We need to rotate the enemy because he is facing the wall. We can do that by typing 180 into the heading control on Position property page or by rotating the entity for 90 degrees twice (using Tab). You can press keyboard shortcut A (as allign) to focus on enemy. This is how it looks from close-up:

The last thing that we will do before game testing is to add reflection to the floor. Switch to polygon mode (P). Select floor polygon using left-click. Turn off selection display (Z). Invoke perspective-view-only configuration. Window configurations are changed using numeric part of keyboard. Be sure that NumLock is on. Perspective-view-only configuration is stored under window configuration 6, so press key 6 on numeric keyboard to invoke it. Your layout should look like this:

Invoke Tools window (Q). On the Polygon property page select "std mirror 1" int the Mirror combo box. On the Texture property page, choose "Blend" in the Blend combo box. We still don't see any reflections. This is because the floor's texture is opaque. We have to decrease its opacity to enable floor's reflectivity. We will increase texture's transparency when we decrease alpha value for the texture's color. We change the alpha value with tall button, placed in the middle of the color button. We will set it to 96, simulating very reflective surface. This is the how the final room should look like:

All we have to do now is to play-test this room. Test game mode is invoked with key T.

Troughout this tutorial you exercised how basic architecture is created, some textures and lights applied, and enemies added.
We congratulate you on your first world built using Serious Editor.


How to ...

  • Edit colors

  • Work with virtual tree

  • Work with browser

  • Work with primitives

  • Use CSG wizard

  • Test game

  • Easily select entities

  • Edit entity properties

  • Work with lights

  • Create backgrounds

  • Use cloning

  • Create moving brushes

  • Add sound and music

  • Copy sectors

  • Edit sector properties

  • Add fog or haze

  • Change gravity

  • Group and select polygons

  • Edit polygon properties

  • Use texture layers

  • Create sliding polygons

  • Create scrolling texture

  • Apply projected mapping

  • Create translucent polygons

  • Create mirror

  • Create warp


Edit colors

How to edit colors

WED has many places where colors should be edited. To be able to easily edit colors in a same way, color button has been created. Right part of color button shows current color. Tall rectangle in middle shows value of alpha channel (shown in grayscale: from black=0 to white=255). Top three buttons in left part of button show hue, saturation and value for color. Bottom three colors show red, green and blue value for current color. Any component can be changed by LMB +mouse left/right. Click on right part of button (current color) to invoke standard windows color picker. Right click will invoke context menu that allows copy/paste operations and ability to enter numerically alpha channel.


Work with virtual tree

How to work with virtual tree

Virtual tree acts like explorer (virtual means that there are no directories on disk). All operations with tree are listed on context menu (right click). There you can load or save tree. Each user can have his/hers own virtual tree or a tree for each world. You can create, destroy and rename directories. Little icon is assigned to each directory. Directories can have shortcuts. Shortcuts are invoked with keys 0-9, set using Ctrl+keys 0-9. Currently assigned shortcuts can be listed with key 'W'. Shortcuts are saved along with virtual tree.


Browser

How to work with browser

Browser contains icons. Icons are actually links to files. Icons can be viewed as thumbnails in three sizes, as descriptions or as a file names. Files can be inserted or dropped into browser. Icons can be moved inside one directory. You can select range of items with Shift+LMB, toggle selection of single item with Ctrl+LMB (to delete more items at once). LMBx2 will set current texture for primitives, apply texture to selected polygons or open clicked world. There are few very useful operations for selecting polygons in world and option to add all textures from world to browser.


Primitives

How to work with primitives

Worlds are built by adding or subtracting basic 3D volumes. These 3D volumes are called primitives. SED supports many types of fully editable primitives: cones, toruses, staircases, spheres and terrain. There are many parameters for each type of primitive. By modifying these parameters you can create numerous variations of 3D shapes. Vertices on base of cone primitive can be dragged in top view. Top polygon of cone can be stretched and sheared. Vertices of terrain primitive can be extruded using grayscale picture (displacement map) or manually using PgUp/PgDn on vertex under mouse. If triangulation is on (set by combo box near primitive icons on tool bar), vertices can be dragged in all directions.


Wizard

How to use CSG wizard

Wizard is a tool used for repetitive operations. It can be used to build worlds or for multiple entity pasting. Wizard tool can be used for multiple pasting of torches with flares and sounds, columns, circular stairs,... This tool actually repeats last operation (CSG or join layers) applying primitive or world translation and rotation delta to cloned operation.


Test game

How to test game

Edited world can be game-tested at any time using key 'T'. Testing will take place in perspective view with currently active rendering preferences. By default, view configuration no. 6 stores one view with maximum rendering quality which is best for game testing. This view configuration is invoked using key 6 on numeric keyboard. 'Alt+Return' can be used to toggle full screen mode. Player will start from position and orientation determined by player start marker. There can be more that 1 player start markers. You can jump to any marker using console command cht_iGoToMarker=.


Select entities

How to easily select entities

Entities must be often selected during editing. They can be selected by left mouse click or using option to select all entities in world or sector. They can be also selected using volume selection, by pressing 'V'. Volume is a virtual box placed anywhere in the world. It can be aligned to viewing area using key 'A'. You can also invoke select entities dialog using 'N' or 'Ctrl+Shift+A' which will list all entities from world or entities contained with volume box. Dialog will allow you to sort entities using class, name, id number or position. 'RMB' on certain entity property (i.e. class) will remove all entities from list that don't have same property value. 'Shift+RMB' will remove all entities that do have same property value. 'LMBx2' will close dialog and select clicked entity. 'Feed volume' operation will put selected entities into volume. That way they can be circled using '[ ' and ']' ' keys.


Edit properties

How to edit entity properties

Entity properties are edited in entity mode ('E') using entity property dialog. Select entity (or entities) and select property you want to alter. Then enter new property value in lower part of entity property dialog. Common entity properties have shortcuts. Certain entity property is invoked using 'Shift+entity property shortcut key'. Range and angle properties can be edited using 'Ctrl+Shift+LMB+mouse move'.


Lights

How to work with lights

Light is added to world using drag and drop operation (from browser window). Initial light settings are: white (no overbrightning) colored point light with small falloff radius. Selecting property 'Type' we can change light to ambient light or directional light. Directional light will influence only polygons that have directional light flag on. To calculate shadows from directional light (they are not updated automatically) press 'R' or click on calculate shadows tool button. For point light we can adjust hotspot and falloff radius properties according to our needs. You can move point light around and it will automatically cast shadows on polygons inside range of influence. To animate certain light, select 'animation file' property. Browse light animation file created using light animation editor. To add lens flares and reflections, select 'lens flare' property and select light effect. To change color of light select 'color' property and select new color.


Background

How to create backgrounds

Background is rendered as seen from background viewer entity. All entities that have background flag turned on will be included when rendering background viewer's view. To create background, drop background viewer entity outside area occupied by edited world. Build background world around it. Turn on background flag on each entity that will be included in background rendering. You can have more backgrounds on each world. Send start event using trigger entity and triggered background entity will become active one.


Gravity

How to use cloning

All entities with same names are considered to be clones. All af the clone's childs entities are involved in cloning operation. Select one clone entity, change it and choose update clones. SED will delete all clones and their child entities and will replace them with new ones. Old clones will be deleted and source clone will be copied to their positions. Positions and rotations of old clones will remain the same. Updated clones will have source clone's child entities. For example: you can have many columns that are clones (have same name), and you change shape or texture on one of them. Select modified column and apply 'Update clones' operation. All other columns will look like source clone. It is also very useful to work with clones and their child entities. You can add a torch model, fire model, sound and light to a column source, set child-parent links (column is parent) and update clones. All clones should now have lights, sound, fire... Very useful feature.


Moving brushes

How to create moving brushes

Drop moving brush entity. Check that it is selected as CSG target (combo box on top of the screen near CSG icons must say 'moving brush'). Add box of material to it using CSG operation. Drop first marker using 'D'. Move brush to another location (you can also try to rotate it). Drop second marker ('D'). Repeat 'marker drop' operation as many times as you wish. Test path of moving brush using 'Alt+D' command. Turn on 'move on touch' entity property flag. Moving brush will start its voyage trough markers when touched. You can disable move on touch flag. In that case moving brush will start when triggered with start event. You can also add sounds to brushes, change wait time and speed, ... Value of each property can be changed in marker by setting marker's property value to value different from -1 (-1 means don't change property).


Sound

How to add sounds and music

There are two types of entities for controlling sounds: sound and music holder. Both are very easy to understand. All that you have to do is to drop entity (sound or music holder) into world and browse .wav file for sound or .mp3 file containing music. You can choose between two types of music: peace music and fight music. You can set how many enemies should attack you for fight music to be played.


Copy sectors

How to copy sectors

Select one or more sectors using LMB (hold Shift to toggle sector selection). Press Ctrl+C to copy selected sectors together with entities contained in those sectors. If you want to copy sectors without containing entities press Ctrl+Shift+C.


Edit sector properties

How to edit sector properties

Sector properties can be changed on sector property page on info window (info is invoked by 'Q' in sector mode, sector mode is invoked by 'S'). Select one or more sectors using LMB (hold Shift to toggle sector selection). Change sector ambient light or content type.


Fog

How to add fog or haze

Fog can be easily selected for each sector if world base entity that contains that sector has fog pointer set. To set this pointer, you have to drop fog marker entity. This entity will be used later to change parameters of fog (like density, color, height, ...). Now we have to setup world base fog pointer. Select world base entity that contains sectors with fog. Select fog pointer property. In target combo box select dropped fog marker or Ctrl+Alt+click it from world. Now select sectors that will have fog and set new fog type on sector page of info window. Same works for haze.


Gravity

How to change direction of gravity

Gravities are edited in same fashion as mist and haze. Drop gravity marker. Select world base entity that contains sector with modified gravity. Select any gravity pointer property. Change value of property to target gravity marker (in target combo box select gravity marker or Ctrl+Alt+click it from world). Now go to sector mode ('S'). Set new gravity type for selected sectors on sector page of info window. Gravity is modified using gravity entity orientation and gravity entity properties. There are also few default gravities (down(normal), up, north, south, east, west) that can be used without markers.


Group polygons

How to group and select polygons

You can group polygons by colorizing them. Select any number of polygons and press 'C'' or click on colorize button. Select color. Display world in polygon color mode to check colorization effect. Double click will select all nearby polygons with same color. You can also select all polygons with same texture on active texture layer with Ctrl+LMBx2. You can select adjacent polygons with same texture with Ctrl+RMBx2. Ctrl+Shift+LMBx2 will select all polygons with same color in sector. Ctrl+Shift+RMBx2 will select all polygons with same texture in sector. In you right click on texture in browser you can choose to select all polygons with current texture in world. There is also ability to select polygons in world that don't contain any of selected textures in browser. You can also add all textures from world into browser.

Shortcuts for polygon selecting:

  • LMBx2 selects similar by color adjacent (continuos, touching polygons)
  • Ctrl + Shift + LMBx2 selects similar by texture in sector
  • Ctrl + RMBx2 selects similar by texture adjacent
  • Ctrl + Shift + RMBx2 selects similar by color in sector


Edit polygon properties

How to edit polygon properties

Polygon properties can be changed on polygon, shadow and texture pages of info window (info is invoked by 'Q' in polygon mode, polygon mode is invoked by 'P'). Select one or more polygons using LMB (hold Shift to toggle polygon selection). Polygon properties can be changed on all three polygon related pages of info window: polygon, shadow and texture.


Use texture layers

How to use texture layers

There are three available texture layers per polygon. Each layer has its own texture, color, blend mode, mapping and scroll. Set active layer using Shift+1, Shift+2 or Shift+3. Toggle layer visibility using Ctrl+Shift+1, Ctrl+Shift+2 or Ctrl+Shift+3.


Sliding

How to create sliding polygon

Select polygon(s) that will have changed friction. Change friction type using combo box on polygon page of info window.


Scrolling

How to create scrolling texture

Select polygon(s) that will have scrolling texture. Select layer of texture (Ctrl+Shift+layer no). Change scrolling type using combo box on texture page of info window.


Projected mapping

How to use projected mapping

Projected mapping is used to seamlessly apply texture over many polygons. It is also used to apply texture over terrain. Copy mapping from any polygon using 'M'. Select polygons to be projected mapped. Press 'U' over one of selected polygons. If you select texture scroll on polygons that are mapped using projected mapping, it will look great: texture will seamlessly travel over mountains and buildings.


Translucent

How to create translucent polygon

Serious engine's portals (polygons that divide two sectors) can be translucent. For some polygon to be translucent, you have to convert it to portal : set portal flag on polygon page of info window. Set also translucent flag on same page. Switch to texture page. Select blend mode: blend. Change transparency of polygon's texture by changing value of color 's alpha channel (see how to edit colors)


Mirror

How to create mirror

Select polygon that will be mirror. On polygon page of info window change mirror and warp combo box to mirror 1. Switch to texture page. Select blend mode: blend. Alter reflectivity by changing transparency of polygon's texture: change value of color 's alpha channel (see how to edit colors paragraph)


Warp

How to create warp

Warp is created similar as fog, haze and gravity. Entity that contains polygons with warp must point to mirror source entity. Mirror source entity must point to mirror target entity. Mirror target entity is used as camera origin for warp rendering. To create warp: select world base, select mirror 1 target property. Change value of property to point to mirror source entity (in target combo box select mirror target or Ctrl+Alt+click it from world). Select mirror source entity. Its target set to be mirror target. Select polygons to render warp. In polygon page of info window select mirror 1. Alter transparency of polygon's texture: change value of color 's alpha channel (see how to edit colors).


Serious Editor Shortcuts

Keyboard shortcuts

  • Mode switching

  • Moving

  • Windows standard

  • Rendering settings

  • Virtual tree

  • CSG operations

  • Common operations

  • Misc

You can also examine latest SDK changes for additional shortcuts.

Mode switching

E | switch to entity mode
S | switch to sector mode
P | switch to polygon mode
. (dot) | switch to vertex mode

Moving

Space+LMB+mouse | move view left/right/up/down
Space+RMB+mouse | move view left/right/in/out
Space+LMB+RMB+mouse | rotate view around focus
Space+LMBx2 | focus clicked point
Ctrl+Space+LMB | zoom in 2 x
Ctrl+Space+RMB | zoom out 2 x
Ctrl+LMB+mouse | move entity/mapping left/right/up/down
Ctrl+RMB+mouse | move entity/mapping left/right/in/out
Ctrl+LMB+RMB+mouse | rotate entity/mapping
Ctrl+LMBx2 | teleport entity/mapping to double clicked point
Ctrl+(Num +) | zoom in x 2
Ctrl+(Num -) | zoom out x 2
Backspace | center to center of map
Shift+Backspace | center to background viewer

Windows standard

F1 | help
Ctrl+N | new document
Ctrl+O | open document
Ctrl+S | save document
Ctrl+Shift+S | save as document
Ctrl+P | preferences
Alt+Q | close document window
Ctrl+L | invoke console
Ctrl+U | game settings
Ctrl+C | copy (selected entity or whole world, polygon settings, selected sectors)
Ctrl+Shift+C | alternative copy (copy selected sectors but without contained entities)
Ctrl+V | paste
Ctrl+Shift+V | alternative paste (polygon properties without mapping, entities to second layer)
Ctrl+W | remember undo
Ctrl+Z | undo
Ctrl+Y | redo

Rendering settings

Alt+(0-9) | apply rendering settings (0-9)
Ctrl+Alt+(0-9) | store current rendering settings under buffer (0-9)
Ctrl+Num 0-9 | store current view and rendering configuration
Num 0-9 | restore view and rendering configuration

Virtual tree

W | invoke currently assigned shortcut list
0-9 | shortcut to virtual directory
Ctrl+(0-9) | set shortcut to currently opened virtual directory
/ | open/close virtual directory list

CSG operations

Return | start CSG mode
Ctrl+Shift+LMB | size primitive
Ctrl+Shift+RMB | shear top of primitive
Shift+LMB/RMB | add/remove closest vertice in primitive base
Ctrl+LMB | move closest vertice of primitive base
O | repeat CSG wizard (clone last operation)
Alt+O | invoke numeric CSG wizard
L | join layers (copy entities from second layer into edited world)
Num + | CSG add
Num - | CSG subtract
Num Del | cancel CSG mode
Delete | delete selected entities
Num / | CSG split sectors
Shift + (Num /) | join sectors
Num * | split polygons
Shift + Num * | join polygons
Shift+(Num *) | join polygons

Common operations

T | test game
Alt+Return | start full screen mode
Q | toggle tools window
Ctrl+I | toggle tools window
Z | toggle selection mark on/off
` | deselect all
LMBx2 | select polygons similar by color or select entity with its child entities
C | center entity selection, colorize polygon and sector selection
Ctrl+Alt+LMB/RMB | double/halve texture mapping on polygon
Shift+Alt+LMB | deselect polygons with orientation different to clicked one
Shift+Alt+RMB | deselect polygons with orientation same as clicked one
V | toggle browse entities by volume mode
A | teleports viewer to focus primitive, world, sectors, polygons, entities
Ctrl+Shift+A | invokes select entities dialog
N | invokes select entities dialog
H | view shadows on/off
Ctrl+H | auto shadow calculation on/off
R | calculate shadows from directional light
, | copy texture from current layer
K | paste texture over selection or polygon under mouse
M | copy mapping from polygon under mouse
U | paste as projected mapping
J | paste mapping over selection or polygon under mouse
Ctrl+A | select all entities in volume, align primitive to screen, show all sectors
X | hide unselected sectors
Alt+X | hide selected sectors
Y | view from entity
D | drop marker
Alt+D | test movement along path
F | open virtual directory that contains texture under mouse
Ctrl+Q | toggle measure mode
I | toggle data tips on/off
Ctrl+Home | store viewer position 1
Ctrl+End | store viewer position 2
Home | restore viewer position 1
End | restore viewer position 2
[ | previous (entity in volume mode, polygon in selection in polygon mode)
] | next (entity in volume mode, polygon in selection in polygon mode)
\ | select target
Alt+~ | toggle maximization of view under mouse
Tab | rotate entity/layer 90 deg clockwise
Tab | rotate entity/layer 90 deg counter clockwise
Arrow left | rotate entity/layer world left
Arrow right | rotate entity/layer world right
Arrow up | rotate entity/layer world up
Arrow down | rotate entity/layer world down
Ctrl+Shift+R | recreate active texture
Ctrl+T | create texture
Ctrl+Shift+U | update clones

Misc

Alt+S | take screenshot
Alt+T | save thumbnail
Alt+R | toggle scene rendering profile
/ | flips circularly (around x, y, z, no flip) world in second layer
Alt+M | measurement tape on/off
B | toggle auto mip brushing (LOD on brushes)
Ctrl+B | toggle decade/binary grid
G | view link lines on/off
Ctrl+G | view grid on/off
Ctrl+Shift+I | toggle view direction icons
Ctrl+K | align mapping in u direction
Ctrl+Shift+K | align mapping in v direction
Alt+P | toggle background pictures/objects on/off
F5 | top view
Shift+F5 | bottom view
F6 | right view
Shift+F6 | left view
F7 | front view
Shift+F7 | back view
F8 | perspective view
Ctrl+Shift+W | invoke world settings dialog


Serious Editor Tips And Tricks

Tips and tricks

  • Key 'Q' is used to toggle info dialog (very important editing tool).
  • Key 'Z' is used to toggle view selection (sometimes selection disables effective editing).
  • Key '~' is used to cancel selection.
  • 'Alt+~' is used to maximize or restore view under mouse.
  • Use data tips. Point to object (entity, polygon, sector) in info mode to display information about it. Info mode is toggled with key 'I'.
  • Key 'A' is used for aligning. It will either focus current selection (polygons, sectors, entities) or align selecting volume (operation Entity/Volume/Align: keys 'E'/'V'/'A').
  • 'Shift+entity property shortcut key' will select certain entity property for editing.
  • 'Ctrl+A' is to select all entities in volume (in volume mode) or to align primitive to currently viewed area.
  • Keys 'Home' and 'End' are used for restoring two custom view position. Position is stored using 'Ctrl+Home' and 'Ctrl+End'. This is very usefull when moving between two different positions on the world frequently.
  • 'Tab' and 'Shift+Tab' keys are used for 90 degree rotation. 'Arrows' rotate for 15 degrees. Rotation is performed logically in current view (view under mouse).
  • Ctrl + Space + LMB zooms in 2x into clicked direction and centers clicked point, Ctrl + Space + RMB zooms out 2x. Use these operations for very easy world navigation.
  • Keys '[ ' and ']' ' are used to circle between entities selected by volume box or selected with 'feed volume' button in select entities dialog.


Serious Modeler Overview

Overview

'Serious Modeler' is Serious engine's application used for compiling and editing models. Models are static or animated 3D objects that usually consist of many polygons (like weapons, monsters, furniture, statues, effects, etc.). 'Serious Modeler' enables model creating, unwrap texture mapping defining, model rendering setup, level of detail creation, switch distance control, hierarhical model attaching, sound linking, patch positioning and collision box definining. Modeler is standard Windows multi-document application. It can work on two types of documents: model and script. Script is a text file used in model creation. It contains file names used for model creating, files used in texture mapping defining and files that form animations. Model is built eather from a single 3D object file or from a series of files exported from an 3D modeling program like Lightwave or 3D Studio. Since models in 'Serious Engine' use unwrap skin texture mapping, all frames that form one model's animations and mapping must have same number of vertices and polygons.
'Serious Modeler' displays 3D view of a model and 2D view of skin mapped texture. In 3D view mode you can examine model's animations. Animation can be paused and viewed using frame by frame. Model can be rendered in numerous ways (wire frame, hiden lines, bounding box, surface colors, on and off colors, white shade,...). Model is shaded as result of ambient and point light illumination. Color of lights can be changed, light direction and distance can be modified.
One or more skin textures can be added to a model. They can be switched at any time. You can also add some effects to a model like reflection, specular or bump. Reflection texture can be generated to reflect a certain place in a level from series of pictures exported by 'Serious Editor'. Specular texture can be generated in Modeler using specularity editor.
'Serious Modeler' implements level of detail (LOD) generation. Model can have up to 32 precalculated LODs. Application's user interface enables intuitive way for setting mip switching distance. Quality of one of model's level of detail can be examined from close-up using manual mip switching. 'Serious Modeler' also enables patch (texture that can be applied over skin texture) position defining. Main editing tool of 'Serious Modeler' is tool window. It consist of property pages. Tool window displays usefull information (global info about model, current animation name and length, current mip info, ...) and enables data editing (collision box size, sounds, attachments, rendering, ...). This picture of a standard Serious Editor layout will be used to explain its basic components.

Components:

1. Model render view
2. Script
3. Tools window
4. Toolbars
5. Status line
6. Edited model


Basic tutorial: SEM Navigation

Navigation

This section is designed to help you quickly start using Serious Modeler. First start Serious Modeler (Figure 01 shows one possible configured look of Serious Modeler). As you can see Serious Modeler is full Windows application wich can be easily configured via VIEW menu and PREFERENCES MENU (in file menu or CTRL-P) to match Your preferences. Serious Modeler is multi-document application meaning you can work on multiply models and scripts at a time. For more informations about Serious Modeler refer to overview and Modeler shortcuts sections of Tools help file.
Figure 01

For start click CTRL-O (Open file in File menu) to open model file ( .mdl extension) from directory HELP\MODELER\HEADMAN\ called Headman.mdl. This model represents one of basic enemy found in Public Test version. Figure 02 shows loaded Headman.mdl. Once model is loaded Rendering view is opened.
Figure 02

Interface of Modeler consists of numerus menus and buttons which can be configured to user preferences. From it user have easy access to all models animations (if any), textures, different rendering modes etc. For example, this model have 4 textures loaded, to browse between them use Page Up/Down shortcut, other way is to click on TEXTURE CONTROL pulldown menu (Figure 02a). As you click on those buttons texture on model changes.

1. Create New Texture 2. Recreate Texture 3. Select Texture Pulldown 4. Change Texture Size 5. Add Texture 6. Remove Texture 7. Previous Texture 8. Nect Texture |
 | Figure 02a

Interactive navigating in Serious Modeler is conducted using combinations of keyboard and mouse. When you press keyboard-mouse combination Status Line changes messages accordingly. For rotating view in all axes press and hold SPACE BAR and BOTH mouse buttons and move mouse in any direction to see view rotated around model. To zoom view press and hold SPACE BAR and RMB and move mouse up-down to zoom in model. To move view press and hold SPACE BAR and LMB and move mouse in any direction to move view. It is important to notice that viewer is always rotated around focus (model).
Same tehnique apply for moving,rotating,zooming of model in Serious Modeler. For moving model in all axes press CTRL and LEFT mouse button and move mouse in any direction to see model rotated. To zoom model press and hold CTRL and RMB and move mouse up-down to zoom in out model. To rotate model press and hold CTRL and BOTH mouse buttons and move mouse in any direction to rotate model. By pressing ALT Z model is reset to its default position. By pressing BACKSPACE view is reset to its default position. Pressing just RMB anywhere in view window opens conext menu where you can easily configure rendering preferences of Serious Modeler. For example you can toggle on/off wirewrafe rendering mode (Figure 03) or by pressing W on keyboard or by clicking on wireframe icon in toolbar (Figure 04).

Figure 03

Figure 04

Figure 05 shows toggled wireframe and texture rendering.

Figure 05

There are a lot more rendering options you can access via keyboard shortcuts, context menus or by pressing appropriate icon in toolbars like disabling/enabling texture rendering or toggling on/off surface(material) color rendering. You can toggle rendering virtual floor (to see model's shadow casted) by pressing F key on keyboard or icon in toolbar (Figure06 ).

Figure 06

Another configurable options is changing color of background (change paper color) and background picture from context menu (press RMB).

Ambient color and default light color are also configurable, by pressing ALT A ambient intesity can be changed (Figure07).

Figure 07

Figure 08 shows scene without ambient light (RGB=0).

Figure 08

Pressing ALT L opens light color and intesity color picker (Figure09).

Figure 09

Light allways targets object (Light rendering can be toggled by pressing L shortcut, light item appears on screen as seen on Figure10 ), press SHIFT BOTH mouse buttons to move light around and SHIFT RMB to zoom light into model (pressing L again toggles off light editing).
Figure 10

Modeler features additional viewing options like autorotating object (R shortcut), Dolly mode (D shortucut) etc which can be used for evaluating different parameters created in Serios Modeler (Figure 11).

Figure 11

This concludes basic tehniques in seting up Serious Modeler enviroment and navigation in it.


Basic tutorial: SEM Tools window

Tools window

Most important part of Serious Modeler is Tools window accessed by pressing Q shortcut (Figure 12). It consists of 8 tabs all representing different settings appliable to model (variing from surface properties to tweaking geometry).

Figure 12

First lets take look at GLOBAL tab (Figure 12a). It gives some general informations about loaded model like size of curent texture (you can have unlimited number of textures on model) and its name (Difuse line), quality mode that model is created in (High Quality line), global rendering options etc. Its usefull for general revision of model.

Figure 12a

RENDERING tab (Figure 12) allows you to change rendering properties of single or multiply surface (material) on model. Surface(material) represents group of polygons sharing same informations like type of rendering, color, etc. For instance if you want Boots on Headman to be red (changing DIFFUSE) cycle with TAB (shift TAB cycles backwards) button thru all materials on model (Surface name will change in Rendering tab) until Boot Sides surface shows. Now you can change its color by pressing color picker under Diffuse name ( Figure13) and select red color. More interactive way is to change HSV values (Figure13) by clicking LMB above one of 3 boxes and moving mouse left right to see color updates on model in realtime.

Figure 13

After adjusting color press RMB in color box and copy its value in buffer for using it on other surfaces (Figure 14).

Figure 14

Since Headman boots are mapped from 3 sufraces press TAB again to select next surface (Boot Front in this case), press RMB in color box and color you copied from previous surface paste on curent (Figure15).

Figure 15

Repeat this for next suface (Boot back). In this case you could save time by multiple surfaces editing,selected by Z shortcut or Link Surfaces icon.

Figure 16

After Link Surfaces menu opens click on checkbox left from surface names to select or deselect desired surfaces (Figure16) or hold LMB and drag mouse down to multiple select surfaces and press OK button. In Rendering tab surface name changes to number how many surfaces you have selected (Figure 17).

Figure 17

Now you can adjust options (in this case diffuse color) on more then one surface in same fashion as on one. Click with RMB on color box and select paste color to change all Boots surfaces color to red (Figure 18).

Figure 18

If you want to manipulate all surfaces in same time click on SELECT ALL SURFACES button in Rendering tab (Figure 12) and adjust parameters on all surfaces in realtime. Other rendering options (like reflections, specular etc...), shading parameteres and texture blending will be covered later.

Figure 18


Basic tutorial: SEM Texture types

Texture types

There are 3 types of textures currently supported in Serious Engine:
1) Stil images, created either from 24, 32bit TGA (uncompressed) or 24bit PCX images, used for character skins, world texturing etc...32 bit images (TGA olny) have 24bit RGB and 8bit alpha chanel that used as transparency control over blending)

2) Images sequences, sequence of still images created either from 24, 32bit TGA or 24bit PCX images, used for explosions, smokes and special effects. Animated texture creation is similar to model creation. You need sequence of images that will be converted to animated texture ( Explosion for instance). From Serious Editor or Modeler click CTRL SHIFT T to call texture creation menu. From there click Animated texture button, requester for selection of multiple images opens or you can use predefined .scr file (like one on Listing 05). Once images sequence or .scr file are select new window opens ( Figure 60).

Figure 60

From there script can be adjusted, animations interactivly previewed. When you are happy with texture click on Create button and texure will be created in folder where script points to.

3) Procedural (Effect) textures are created with tools in Serious Editor or Serious Modeler. There are 3 basic types of effect (Water, Plasma and Fire) which applied on Base texture (still image or animated texture) can produce amazing effects (sea surface, pool surface, torch fire, waterfall etc....). To create Procedural texture from Editor or Modeler click CTRL SHIFT T to call texture creation menu. From there click Effect texture button to access Create Effect Texture menu ( Figure 61).

Figure 61

Select base texture (or experiment on default), adjust texture size in pixels (Width and Height) and in meters , select Effect class (water, plasm, fire) and its effector (point, oscilator) and with LMB and RMB (different displacement effect) click on left image to add effect on base texture. RemoveFX removes all effects from base. When you are happy with settings click on Create or CreateAs buttons to save .tex file. Since base texture can have alpha chanel for transparency, Effect texture created from that base texture also inherits its transparency settings (usefull for creating waterfalls for example, wich have edges less transparent then middle).

Like models textures can have their mips (less quality when in distance) called MIPMAPS. When creating still texture or animated, options for selecting how many mipmaps we want to create for that texture is available (Figure 62).

Figure 62

Below size box, options for selecting number of mipmaps is located. For image size 512 x 512 pixels 10 mipmaps is maximum number that can be created (512x 512 as 0th, 256x256, 128x128, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2, 1x1 ).
Maximum option will tell engine to create maximum available mipmaps for this texture once its loaded in game. If you dont want maximum mipmaps (dont want texture to be blured when sized down) you can select how many mipmaps will be created.When happy with settings click Create button to save texture. For textures representing lights or glow effects, creating one mipmap is best solution.


Basic tutorial: SEM Textures and mapping

Textures and mapping

Serious Modeler supports couple mapping modes (way you attach texture on model): UV and planar are most usefull tho Modeler supports cylindrical and spherical maping types. Texture (*.tex) types it supports are Still images (TGA or PCX), Animated sequences and Effect textures (created with Modeler's tools).

Couple rules and advices must be followed in order to achive maximum performances and corect display:
1) Image texture size must be power of 2 i.e. 64x64 or 8x256 or 1024x256 pixels where first number represents width and second height.

2) All textures must have size in meters ( how many meters does texture cover i.e. if texture is 256 pixels wide how many meters of model will those 256 pixels cover) , that depends on size of model. For example if you are making very tall tree, lets say 32 meters tall and want its texture to tile (repeat) 4 times you will create texture 8 meters in height so it will tile 4 times to cover 32 meters tall tree.

3) Textures can have alpha chanel (TGA 32bit), for example to make teeth of character via transparent texture blending mode (explained later).

4) Textures can have mip maps ( way Opengl renders very distant polygons with texture in them) wich you can creat in Modeler.

5) Texture are allways 32bit when you create it from image, so no losses will happen during making.

Since Headman model allready have couple textures loaded press CTRL SHIFT R to recreate one of loaded texture or click on RECREATE TEXTURE button. Menu like on Figure 18b appears.

Figure 18b

(NOTE: to recreate texture, image from which texture was created must be present on hard disk in same folder as .tex file). As you can see in it textures' size in meters, number of mipmaps, etc can be adjusted. All those parameters are saved in .tex file so every time you recreate texture it will offer those settings as default. Press CREATE to recreate texture and close this menu. Recreate is used if you allready have texture created from image file and want to change parameters or image file has changed. Lets say you want to create new texture for Headman, press CTRL SHIFT T or click CREATE NEW TEXTURE button. Menu like on Figure 18c appears.

Figure 18c

From here you can make NORMAL texture (still 2d image , tga or pcx), ANIMATED texture (sequence of 2d images , tga or pcx) or EFFECT texture (opens modeler's tool for creating algorithmic procedural textures, used to create effects like water, fire, plasma etc....). Click on NORMAL texture to open requester asking you to select image file (Figure 18d).

Figure 18d

Click on Kamikaze.tga and menu same like one from RECREATE TEXTURE appears. Click on CREATE button and Kamikaze.tex is added in list of textures for Headman model (with Page Up/Down you can cycle between loaded textures).

Now lets see how this textures is mapped on model. Press Mshortcut or press Toggle Mapping mode icon to access Mapping mode. Figure 19 shows model's mapping (UV ) with curent texture.
Figure 19

With CTRL RMB you can zoom in out view (that wont actually change mapping). SPACE LMB combination moves view (same like model in rendering view). Pressing Q toggles Tools window where additional properties of surface or rendering can be adjusted.
Pressing RMB opens Context menus (Figure20) where additional preferences (like in rendering view) can be adjusted.

Figure 20

Pressing B shortcut toggles off texture rendering (Figure 21) and leaves mapping rendered, so you can check if mapping is loaded corectly.

Figure 21

While in that mode you can press ALT S to take screenshot of mapping mode and use it as template for creating texture in painting application.
Pressing A disables mapping rendering (Figure 22).

Figure 22

Since Serious Modeler is multiple-document application more than one view can be opened in same time, mapping and rendering view. To do that, press in Window pulldown menu NewWindow button. Now same model is opened twice in Modeler (you can see number in Window Title bar). Now in window pulldown menu press TileVerticaly button and Modeler should look like Figure23.

Figure 23

This way you can manipulate mapping and see changes immidieately on model in Rendering view. Others mapping types and mapping tweaking will be discussed later.


Basic tutorial: SEM Texture mapping and shading

Texture mapping and shading

For maximum flexibility and visual appereance, textures (diffuse chanell) mapped on model can have additional properties. Those are divided in shading and blending options that can be edited on per surface basis.

Shading tells renderer how to cast shadows and illuminates polygons in surfaces.
FULL BRIGHT <-- no matter in what enviroment model is it will be allways shaded with maximum ambient (i.e. no shadows will be cast on it). This method of shading is used, for Fire or Explosions models where you dont want fire to catch any shadows or be darkened.Best used on low polygonal models (single flat plane)
SMOOTH <-- used on rest of models.With higher polygon count models are shaded dependebly on enviroment they are in (darkened or overbrightened), that can dramatically add to better visual appereance of model. Also model can have custom shading (only accesible from Serious Editor).

Blending modes tell renderer how to map texture on model's surfaces.Diffuse checkbox must be checked.
OPAQUE <-- texture is completely mapped on surface (Figure 80) without transparency , i.e. blended 100%.Diffuse color can be adjusted.

Figure 80

TRANSPARENT <-- to use this blending mode texture with alpha chanel (32 bit TGA) must be used. Alpha chanel is interpreted black/white via treshold, white in alpha chanel is totally notransparent, black is totally transparent, everything in alpha with value greater then 0.5 is interpreted as nontransparent. This way fine blured transition is achieved. Low polygonal torches can be easily made using transparent mod (Figure 81).

Figure 81

TRANSLUCENT <-- to use this blending mode texture with alpha chanel (32 bit TGA) must be used. Alpha chanel is interpreted with its values i.e. any value between 0 and 1 is used, white in alpha chanel is totally notransparent, black is totally transparent, gradient alpha chanel can be used to simulate model's fade off. Notice gradient texture fade on Figure 82.

Figure 82

ADD <-- to use this mode any texture can be used (even procedural). With add blending color luminosity ( same way add in layers work in Photoshop for example ) is add to background model is on, very light color will be added more then dark, black wont have any effect at all. Add mode can be succesfully used when creating explosion model (Flat) where there is no need for alpha chanel to blend model with enviroment and to avoid ugly edges when using alpha. Also lensflares models use add mode to map flare textures (Figure 83).

Figure 83

MULTIPLY <-- to use this mode any texture can be used (even procedural). This blending mode works like in Photoshop for example, high luminos pixels will darken more background while low luminos pixels wont affact background at all. This mode works opposite to Add mode. Best usage for this blend mode is when making particles models or smoke models (Figure 84).

Figure 84

Shading and blending parameters can be adjusted on per surface basis or on multiply surfaces.


Basic tutorial: SEM Collision

Collision

Every model in Serious Engine can colide with other models or with world geometry. Collision can be per polygon (generally slow with high polygon count) or with use of bounding boxes. To create model's collison box COLLISION tab in Tools window (Q shortcut) is used (Figure 24).

1. Collision Box Size 2. Collision Box Offsets 3. Collision Box Name 4. Add/Remove Collision |
 | Figure 24

Models can have numerous collision boxes (which can be added and removed in any time), for example one for normal pose, one for death, one for fly state etc. Press C on keyboard to toggle collision box rendering (Figure25).
Figure 25

Green box for DEFAULT pose draws around model. Its size and position can be adjusted in collision menu (Width, Height, position etc...). As you change those numbers size and position of box interactivly changes. Press > button to view other collsion boxes, DEATH is next one used when Headman is dead. Collision properties are saved with model so every time you recreate model it will have those properties.


Basic tutorial: SEM Level of detail

Level of detail

LOD (Level Of Detail) is strong feature of Serious Engine. As model is in distance from viewer less detail on it is actually seen so those details dont need to be drawn and have impact on Engine's performance i.e. if model have teeth modeled (with many polygons) and its far away from viewer those teeth looks like few pixels on screen and they can be removed. MIPMODELING tool is used for creating and adjusting LOD. You can access it by clicking on MIP tab in Tools window (Figure 26).

Figure 26

LOD allows you to have high polygon count models when they are very close to viewer and few polygons in model far in distance. In this tab you can create mipmodels and get informations about number of mipmodels for model, switch factor, number of vertices in every mipmodel etc. Serious Engine supports up to 32 mipmodels per model. LOD techonolgy in Serious Engine allows manually creating mipmodels in 3d application like Lightwave3d, 3DS Max etc. This model have 7 mipmodels created manually in Lightwave3d. By default MIPMODELING tools is in AUTOMIPMODEL mode, meaning when you zoom out model from viewer (SPACE RMB) it will draw less geometry as model is more away from viewer (and mipmodel number changes) i.e you see less details in geometry (Figure 27).

Figure 27

To view how model's mips look like toggle off AUTOMIPMODEL mode (O shortuct) and use [ and ] to cycle between mipmodels (Figure 27) or use icons in AUTOMIPMODEL toolbar (note: mapping for each mipmodel is either automaticaly generated or read from 3d object so there is no need for adjusting mapping after mipmodels are created or loaded). As you cycle mipmodels distance at wich model changes to less geometry is shown (Figure 28). Last (7th) mip contains no geometry meaning that at certain distance model isnt rendered at all.

Figure 28


Basic tutorial: SEM Attachments

Attachments

You may noticed that Head model (in left hand) and RocketLauncher model (in right hand) dont change geometry at all with changing mipmodels. Explanation for that brings us to next powerfull feature called Attachment models. Attachment models are normal models as any (containing its own texture, mipmodels, animations, colision, animations and even its own attachment models). Attachment models can be used to create multipart models or to keep geometry count and memory usage down and to easily change parts of model without need to recreate all things from scratch (like texture, mapping, animations etc). Good example is RocketLauncher attached to Headman where in few animations he fires rockets and in others Rocketlauncher is in rest postition. Attachments can have their own animations easily controled in Serious Engine. RocketLauncher have so called "rest" animation played while Headman runs, walk, patrol or is idle and Fire and Reload animations while he fires weapons at player. When you attach model to another its animations are loaded with it so you can examine how would RocketLauncher "Fire" animation look in combination with HeadMan animation. All functions for adding/removing and examining attachments are found in Attachment tab ( Figure 29 ) in Tools Window menu .

1. Attachment Name 2. Attachment Model Browser 3. Attachment Animation Selection Pulldown 4. Translation Offset Fields 5. Rotation Offset Fields 6. Attachment Visibilty checkbox 7. Add/Remove Attachment Buttons |
 | Figure 29

Here you can add and remove attachments (7), name them(1), adjust position(4) and rotation(5), choose animation(3) and disable attachment's rendering(6). Headman have couple attachment models added and first one is Head.mdl named HEAD for easier manipulating, since head don't have any animations DEFAULT one is shown. Lower part of menu consist of Translation and Rotation offset fields where finetuning of attachment is performed.

Premise of attaching is that attached model uses 3 points from model its attached to as "anchor" points meaning that when ever those 3 points are moved or rotated attached model is also moved and rotated accordingly. Those 3 points' positions are represent by names center, front and up in attachment tab. Usually you add so called "attachment triangles" geometry on model you wish to attach additional models to (those triangles will have disabled rendering so they wont appear in game). To show how head is attached to Headman's left hand, disable visible checkbox for HEAD in Attachment tab and toggle wireframe mode (W shortcut), rotate model so you have best view on left hand, you should have something like on Figure 30 .

Figure 30

Numbers on Figure 30 represent "Anchor" points (1 is center, 2 is front and 3 is up).Selecting points for anchoring will be explained in advance tutorial section.


Basic tutorial: SEM Sound

Sound

SOUND tab is used to attach different sounds to model's different animations, for easy testing duration and combination of model and sound in game (Figure 31).

Figure 31


Basic tutorial: SEM Animations

Animations

Models animations are saved inside .mdl file and are easy accesed in Serious Modeler. Each animation have its unique name in order to be played corectly in Serious Engine.
To play model's animations Anim Control menu is used (Figure 02b).

1. Play/Stop Animation (Looping) 2. Play Animation Once 3. Synchronize Model and Texture Animation 4. Show/Hide Frame Rate 5. Select Animation Pulldown 6. Chose Animation Menu |
 | Figure 02b

Use cursors Up/Down to cycle thru model's animations or use Select Animation Pulldown menu to select animation(Figure 02c).

Figure 02c

Manual scrubbing thru frames can be achived with Left/Right cursors (while animations is stopped). Animation tab in Tools Window is used to interactivly adjust speed of curent animation and it gives you information about number of frames in it and lenght of whole animation (Figure 33).
Note: animation speed adjusted in Animation tab isnt saved in script, next time model is recreated or animations are updated, values from script file will be used.

Figure 33

With Shift Up/Shift Down you can jump on first/last animation in model.


Tools You Need

Serious Modeler supports many 3D object formats: Lightwave 3D's .lwo files, 3DS Max via .3ds files, Alias WaveFront trough .obj and many others. Tehniques described in this tutorial can apply in any 3D application (with minor differences). Any Application capable of saving uncompressed 24 and 32bit TGA images (like Photoshop, PaintShopPor etc..) is suitable for creating texture files.


Mapping Objects and Importing in Serious Modeler

 Note: Serious Modeler has been updated to import vast number of 3d objects with UV data directly from object. This eliminate use of unwrapped and opened objects (its still available as legacy option). For now importer has been tested with .lwo files (v1 and v2), .3ds files and .obj files (if you have any 3d format object that is supported by Serious Modeler and it doesnt load correctly please let us know). This tutorial is addendum to Help file for Serious Modeler that you will find in Serious Tools instalation archive.

Tutorial 1: Mapping Objects and Importing in Serious Modeler

Serious Modeler now supports importing of most popular 3d object formats (.lwo (v1 and v2), .3ds , .obj among others). This tutorial will explain how to proper UV map object and import it in Serious Modeler.

Note: though screencaps are from Lightwave6.x all tehniques apply in other 3d modeling packages.

There are few rules that must be followed in order to load UV mapped object with proper mapping in Serious Modeler:

1) ALL polygons must be triangles only!

2) Material (surfaces) assigning is crucial in order to maping import properly. Take a look at Image01,
Image01

Its 8-sided cylindar with top and bottom polygons removed. If you would assign UV map to it, you would probably use Cylindrical mapping on Y axes (in Lightwave ).
Image02 shows that cylindar with single surface (material) UV maped.
Image02

Only one surface (material) is assigned to cylindar and it have single seam in mapping. All cool you might think ? Well not exactly, though it looks ok in your favourite 3d program, it wont import correctly in Serious Modeler. Reason is that this way you have 1 geometry vertex with more than 1 coordinate in UV map, i.e. there are more 2 texture coordinates in surface with same UV value attached to single geometry vertex. (Image03 shows those vertices on mapping seam, in this case there are 2 pairs of vertices with same value).
Image03

Solution is to have 2 surfaces (materials) assigned to cylindar where seam is created (place where texture coordinates are detached). Assign another surface to cylindar on seam like on Image04, this way there wont be single surface(material) with more than 1 geometry vertex with more than 1 UV coordinate in mapping.
Image04

This kind of problems can occur when mapping for example character arm (wich is basically deformed cylindar), solution is to assign 2 surfaces (materials) to arm polygons and make seam on back of arm (Image05 shows 2 surfaces on arm part of object with seam on selected yellow points on back of arm, where its less visible).
Image05

Same rule applies on any part of object that have closed shape (legs, head.....).

3) Object must have single UV map.

4) Use low count of surfaces(materials names) as possible (will speed up OpenGL performance in OpenGL).

Now when all is clear, lets get going. For this part of tutorial i will use Rocket launcher i modeled for Serious Sam. Image06 shows object loaded and surfaced.
Image06

As you noticed same surfacing rule was applied on this model as noted under rule 2. Since object is modeled symetrical on sides, it will be mapped symetrical. While mapping you can add as many surfaces or only one for easy mapping and then when finished mapping reduce that number to some normal count (yes Dean, i lessened surface count on Rocket Launcher :P). Since this object is used as weapon player will hold in first person view, some parts of it will be more closer to view than others. Its good practice to create rough shape of model without mapping and load it in game, position it in position it will be to see what parts of it will be more visible and then give those parts more space in maping so more details can be added to it. Same applies in modeling (more detail in places that will be seen most of time). In case of Rocket Launcher selected polygons on Image06a are seen closer than others so they are mapped to ocupy more space on texture.
Image06a

Planing ahead will spare you extra time adjusting and correcting model and mapping. When giving names to surfaces (materials) use name that have meaning like BodySides, Handle or similar instead of 01, aaaaaa etc... it will make skinner's life easy and he/she will be your best friend forever. Another thing to watch, since Serious Modeler allows different texture blending modes on surfaces (materials), like alpha transparent teeth on monster's head, while rest is opaque texture, you need to create surfaces for parts of object that will have different texture blending. Same thing applies if you want selective reflections, specular or bump textures. Selective (surface based) properties of Serious Modeler allows you for example to have shiny reflective metal on shotgun (with chrome reflection) while having old wood on handles. This way you dont have to add reflections, specular to whole model and slow down rendering, you can just assign those properties to surfaces that are visible from certain view. Plan ahead how will model look and surface it accordingly!

Usually when dealing with characters, weapons and similar models they will be mapped symetricaly. i.e. character's left part of torso will have same texture as right (this way texture isnt wasted and more details can be added to model's texture while keeping texture size small). When in such situation, delete either left or right part of object, map it and then mirror it (this way you are dealing with smaller polygon count when maping and mapping will be 100% symetrical).

Grouping polygons in global surfaces will keep surfaces count smaller. For example if you dont need different properties on surfaces you can select all polygons that represent sides of Rocket Launcher and call it "Side" surface (Image06b).
Image06b

Same goes for polygons on either top or bottom of object. This way you wont be able to resize individual polygons in object to have more space in maping (without affecting sourounding polygon's mapping) but you will have less surfaces in object. Remember rule 2 about closed shapes and need to have at least 2 surfaces for maping to be imported properly. Image06c shows part of RocketLauncher maped with 2 surfaces that will load correctly in Serious Modeler.

Image06c

Another good tip is when unwrapping object if its symetrically mapped like on Image06d, is to know will weapon (in this case) be holded on right side or left side on screen.
Image06d

If weapon is on right side of screen (usually in FPS games), there is big chance that right side of weapon wont be seen, position polygons in mapping that seam created is on right side of weapon. Image06e shows points on left side of object that are positioned so there is no seam in mapping between parts of object.

Image06e

Image06f shows points on right side object that create seam and might not align perfectly when texture is created, but they wont be seen anyway).

Image06f

When finished with modeling and mapping, try adjusting lighting in your 3d application similar to in game atmosphere. This way you can check does object need more or less details in some places. Also try mimicing smoothing options like in Engine so you can add or remove polygons where needed. Setting max smoothing angle of 180 in Lightwave equals Engine's smoothing ammount.

Good idea is when mapping object to apply checkerboard texture on it to correct stretching that might occur. Once mapped object is ready for importing in Serious Modeler.

Image07 shows UV map (right window) and mapped object with finished texture that Petar made for RocketLauncher.

Image07

Run Serious Modeler and click on File-> New (CTRL N shortcut). Browse to folder where you did saved your object and doubleclick on it (Image08).

Image08

After model is imported save it (CTRL S). When model is created from object, .scr (script) file is created in folder where object is saved (model is created with default name of object its created from).
With addition of new 3d object formats to import capabilities of Serious Modeler, new lines have been added to .scr file (for indepth explanation of script file please refer to Serious Tools Help file under Serious Modeler->Model Creation Tutorial-> Creating Models and Scripts). segment from new script (.scr) file when new importer is used:

By default, mapping is read from object model is created from. If there is no UV data assigned to polygons in that object,
error message will be produced.

; Old style mapping definition                                <-- Legacy maping loader for compatibility with old maping loader
                                                                                (no longer needed, thus commented)

;DEFINE_MAPPING
;    CoolWeapon_Closed.lwo
;    CoolWeapon_Opened.lwo
;    CoolWeapon_Unwrapped.lwo
Image09 shows body of Rocket Launcher that we mapped in previous part of tutorial.

Image09

By pressing "m" shortcut, so called "Mapping mode" is opened (Image10).

Image10

There, imported mapping from object can be reviewed, different per surface properties can be adjusted and texture aligment on maping checked. You noticed that when model is created it was rendered white, same white box appeared bellow wireframe in Mapping mode. That is because once model is created or recreated from object, it looks for texture (.tex file, for more info on how to create .tex files check Serious Modeler Help) with same name as object its created from (Body_Lw6.tex in this case). If you want to change model's default texture name, click "m" to close Mapping mode and press "s" to edit .scr (script) file, where you can alter texture name. Script file is explained in details in Serious Tools Help file that shiped with Editor and Modeler so i wont waste space and time repeating myself.

If you happy with model and its mapping, click form File menu "Export for skinning button". It will ask you first to select name of image file in wich mapping will be exported (wireframe of mapping will be saved in image and resolution you choose). Among other options (Image11) you can choose background (paper) and wireframe (wire) color.

Image11

Also wireframe can be colored accordingly to surface(material) colors you created in your 3d application. If you choose "surface numbers" option, number will be centered in every surface wich corespond to .txt file saved in folder where you choose to save mapping. All this will help skin artists to easily recognize what represents what in mapping (if you named surfaces with some meaning names).

When texture is created, it can be added to model by clicking "Add working texture" (CTRL T shortcut) or if texture with same name exists it can be recreated from image file (CTLR R shortcut).

This is all for now. Stay tuned for more....

APPENDIX: Tested 3d objects

LWO:
If importing LWO files V1 (prior LW6.x version) there are few options for UV data import:
* use opened/unwrapped solution
* use UV files saved by UView or similar software. UV file with same name as object you are importing plus .uv extension must be saved in folder where is object you are importing. Same rule of closed shapes (2 surfaces) applies.

When importing LWO files V2 (generated by Lightwave6.x) mapping will be read from object itself(if exists). Same rule of closed shapes (2 surfaces) applies. Only one UV map must exist in object.
Importer supports "Discontinued mapping" feature from Lw6.5.

Known problems:
If object is saved from Lw6.5 beta 2 sometimes importer wrongly interprets UV data. Solution is to load that object in Lightwave 6.5 and resave it there.

3DS:
When importing 3DS files mapping will be read from object itself (if exists).
Same rule of closed shapes (2 surfaces) applies.
Only one UV map must exist in object.

Known problems:
Layered objects (subobjects) arent yet supported by importer (only first subobject will load, thus screwing mapping and geometry). Solution is to merge object in single mesh and then import it.

OBJ:
When importing .OBJ files mapping will be read from .mat (material) file. Material file (with same name as object being imported) must be saved in same folder with object. Same rule of closed shapes (2 surfaces) applies.
Only one UV map must exist in object.

Known problems:
Depending on program .obj file is saved, .mtl file have wrong UV data. Solution is to use program with native .obj support or use 3rd party converter program to convert it to corect .obj (and .mtl) file.

MD2:
When importing MD2 files mapping will be read from object itself (if exists). Same rule of closed shapes (2 surfaces) applies.
Only one UV map must exist in object.

MD3:
When importing MD3 files mapping will be read from object itself (if exists). Same rule of closed shapes (2 surfaces) applies. Only one UV map must exist in object.

Known problems:
Layered objects (subobjects) arent yet supported by importer (only first subobject will load, thus screwing mapping and geometry). Solution is to merge object in single mesh and then import it.

MAX:
Doesnt load properly. Export to .3DS rather and then import it.


Creating .mdl and Script (.scr) Explained

Creating Models and Scripts
Figure 01
Run Serious Modeler (Figure 01).To create model from 3d geometry file you need 3d object supported by Serious Modeler. Press CTRL-N or select New from file menu. Requester opens asking you to click on 3d object file you want to create model from. Select Headman.lwo and voila model is created (Figure44).
Note: if 3d object doesnt contain UV data, error message will be shown.

Figure 44

Press CTRL S or Save from file menu to save model with name HeadMan.mdl (you can save it under different name pressing Save As from file menu).

Once model is created in folder with objects file , 4 additional text files are created:
  • .scr (script) is necessary part of model creating. Model can be created either from script file or 3d geometry. When model is created from 3d geometry, script file is created (examine Listing 03 for full script explanation). Script can be easily accessed (s shortcut) and changed. Changing some settings (like changing object's geometry, texture size, number and polygon distribution in mipmodels etc...) in script requires model to be recreated from existing script while, some like adding/removing and adjusting model's animations require model to be updated (Update model's animations).

  • .h (header) in which animations names, colision boxes and attachment names are saved.This file is created for usage in engine's AI for character.(Listing 01)

  • .ini which contains pointers to all model's textures (diffuse, reflection, specular and bump), pointers to attachment models, pointers to model sound files , thumbnail settings for saving thumbnail file (Listing 02)

  • .map in which texture map coordinates for all mipmodels are saved, pointers to attached sounds, names and definitions of collision boxes and pointers on patches .

    Once script is created and model saved, its time to edit script and adjust some settings. First, press s shortuct to access script and change model's TEXTURE_DIM line (2.0X 2.0Y is by default) to 1.0 1.0 . As you can see in Listing 03, by default Headman.tex (name of model plus suffix .tex) is added. Since Headman is multifunction model instead of TEXTURE HeadMan.tex line add this 4 lines:
    TEXTURE BomberMan.tex
TEXTURE FireCracker.tex
TEXTURE Kamikaze.tex
TEXTURE RocketMan.tex
    NOTE: for creating and adding textures manually please reffer to Basic tutorial.
    This 4 textures are skins for 4 models derived from basic headman model. Save script and click on Recreate model from script icon or press CTRL SHIFT S shortcut. After recreating you should have Headman looking like on Figure 45.
    Figure 45

    Browse thru textures (PAGE UP/DOWN shortcut) to see how they change on model. Model size is now ~90kb. For easy editing script and model can be on screen is same time. From WINDOW Menu click New Window and then enableTileVertically checkbox. Select left window and access script. Modeler should look like on Figure46.
    Figure 46

    Having both, script and render view opened in same time will speed up process of model creation and adjustments.


Defining LOD

Next step is to create or add mipmodels by making them in 3d application. For Headman i created 6 mipmodels in Lightwave 3d (Figure 48).

Figure 48

There are few rules to follow when making mipmodels manualy:
1) vertices must NOT be moved or add in lower mipmodels (ones with less geometry), vertices can only be removed. This is due way Modeler saves model to save memory.
2) polygons can be diferently tripled in mipmodels but new surfaces must not be created otherwise uw mapping wont work on those surfaces (mapping is taken from first mipmodel i.e. object you created model with).
3) When making LOD, you dont need to worry about UV data, once LOD is added to model Modeler recalculates mapping from original model.

There are no general pattern how to make efficient mipmodels, its different from model to model. Generally idea is to keep volume of model in as much mipmodels as possible and to remove first details which are not seen or hardly seen in distance (like mouth on character's head or fingers in hand).

NOTE: for Lightwave users Decimate modeler plugin is excelent tool for creating mipmodels with interactive display (search www.flay.com for it)

Back to Serious Modeler. We have 6 mipmodels created and HeadMan.lwo as 0th.
Change
MIP_MODELS 1
   HeadMan.lwo
lines in script with:
MIP_MODELS 7
     Headman.lwo
     Headman_Mip001.lwo
     Headman_Mip002.lwo
     Headman_Mip003.lwo
     Headman_Mip004.lwo
     Headman_Mip005.lwo
     Headman_Mip006.lwo
Headman.lwo <-this is object we created model from.It should ALLWAYS be 0th mipmodel. Save script, recreate model and save it. Model size is now ~300 kb so you should be careful with number of mipmodels (more mipmodels = more memory usage).
Everytime you recreate model, if manually created mipmodels are listed in script, they will be recreated with it (unlike automatic mipmodels).
For every mipmodel texture mapping settings can be tweaked from Rendering tab.
Now we will adjust distances wher models changes its mipmodels, whom Engine ill use in game. Inspect manually (press O to enable manual mipmodel switching and use [ and ] to cycle thru them) how all mipmodels look (Figure 28).

Figure 28

Press O again to toggle automipmodeling.

Idea of mipmodeling changes is to tell Engine when to switch from higher polygon count model to one with less geometry. Serious modeler allows you to visually adjust switching, meaning that you can decide to switch to lower mipmodel when model's size is so small that details in curent mipmodel are hardly or not seen at all. To visually switch mipmodels press and hold CTLR SHIFT, click and hold RMB and move mouse up, model will zoom out and when you release RMB mipmodel will switch (check mipmodel number in menu). For Headman i decided to have 0th (highest polygon count mip for very long time and then fast change to lower mipmodels). Press and hold CTLR SHIFT, click and hold RMB move mouse up, watch Distance number in Mip tab and when its around ~30m release RMB (in that distance model is pretty small on screen and details arent seen). Press and hold CTLR SHIFT, click and hold RMB, move mouse up until distance is around 40-50 meters, release RMB and you have 2 mips added. Repeat procedure for rest mipmodels (3rd at 65m, 4th at 110m, 5th at 150m, 6th at 200 and last at 450m after wich model wont be rendered at all). Save model and press BACKSPACE to reset view. To see how we setup mipfactor, while holding SPACE and RMB move mouse up to zoom out model. Notice how mip number changes in Mip menu.

NOTE: distances in Modeler don't reflect actual distances in game if model is stretched. Mipmodels are saved directly in .mdl file and are easy accessed from engine.

NOTE2: you can adjust mip switching factor directly in Serious Editor on per model basis.


Collision Box

We need to create collision boxes for model.Open Tools window (Q shortcut) and access Collision tab (Figure 24).

1. Collision Box Size 2. Collision Box Offsets 3. Collision Box Name 4. Add/Remove Collision |
 | Figure 24

We will create 2 collision boxes, one that will be used when model is "dead" (lying on floor) and one for rest (DEFAULT). Press C to enable interactive collision box render. First we will create DEFAULT collision box. Select option L=W ( lenght = width). This tells modeler to use same numbers for 2 values (width and lenght). For width type in 0.75 and for height type in 1.8 (Figure 49).

Figure 49

This collision box will use as collision of HeadMan and player's bullets, for collision between headman and world. To add "Death" collision box, click on Add button in collision tab. You have now 2 collision boxes (scroll between them with arrows < > in menu). For DEATH model will lye on floor (enable floor pressing F), collision box need to be totally different than for DEFAULT. Select H=W (height = width) option nad type for width 0.4 and 1.5 for lenght. (Figure 50).
Figure 50

Collision boxes can be adjusted, add, removed in any time so aditional tweaking of it might be required once we add model's animations. Colision box size is saved in .mdl file and in .h file required for Engine's AI.


Adding Animations

Note: though this tutorial refrence .lwo files, files from any supported 3d application can be used.

It s time to add animations to model.Switch to script (S shortuct). Serious Modeler supports various 3d object formats as animation frames.

From Lightwave frames can be exported in couple ways:
1) use of save transformed function from Object panel (painfull if you have more frames)
2) applying savemorph plugin in Object displacement tab.

Every frame in animation is represent with single .lwo/.3ds/.obj ... object (for example if you have object walk in 30 frames, 1sec, you will have 30 .lwo objects representing walk saved from Lightwave). In archive with headman model is folder called Frames where all frames are stored. In script add after these lines
ANIMATION Default_Animation	<- usually default position used for adding attachments and textures
SPEED 0.1
    HeadMan.lwo
new lines describing animation called Walk
DIRECTORY Help\Modeler\Headman\Frames\Walk                      <-- path to files
ANIMATION Walk                                                  <-- animation name
SPEED 0.055                                                     <-- single frame lenght
    13.lwo                                                      <-- list of all frames in animation
    15.lwo
    17.lwo
    19.lwo
    21.lwo
    23.lwo
    25.lwo
    27.lwo
    29.lwo
    31.lwo
    33.lwo
    35.lwo
    37.lwo
    39.lwo
    41.lwo
    43.lwo
    45.lwo
    47.lwo
    49.lwo
    51.lwo
    53.lwo
    55.lwo
    57.lwo
    59.lwo
As you noticed strict sequential numbering isnt required, nor there are any naming guidelines (use of similar names is good since you can easy copy/paste names in different animations). Since Engine supports geometry interpolation you dont need to use all frames from animation (for example every 2nd frame can be left out and animation will still be fluent). Click on Update animation (CTRL SHIFT A) and after few seconds you should have 2 animations in model (Default_Animation and Walk). Browse thru animations with cursors UP/DOWN. Select animaton called WALK and it will automatically start playing (RETURN start/stops animation play). While animation is stoped use cursors LEFT/RIGHT to scrubb thru animation. Open Tools window and select Animation tab to get information about animation lenght (in seconds and frames). Also from there you can speed animation (small number for frame lenght) or slow down animation. With scripting approach to defining animations, interesting effects can be achieved, like creating couple animations from same frames (no extra memory used) or combining more animations into macro animations (for example combining walk, pick_object and walk again animations can be joined in one macro animation called ACTION). In archive you will find script file with all animations defined and their respectively frames in Frames folder.

Note: When adding new animations to model, you cant use Update animation (CTRL SHIFT A), you need to recreate model so Modeler can calculate bounding boxes and precission for all frames of animations in model.


Adding Attachments

To finish model's functionality we need to add its attachments. For this tutorial we will presume that they have been made from .lwo objects using same tehnique as Headman.mdl itself. Run Tools window and select Attachment tab (Figure 52) which is empty for now.
Figure 52

As explained in basic tutorial attachment models are parented to their attachment triangles found in Headman.mdl. To see them. select surface called Attachment Triangles from Rendering tab. Make them doublesided and toggle wireframe rendering (W). Position model like on Figure 53 .
Figure 53
Click on Add button to add first attachment model and in requester that opens select Head.mdl. Rename attachment from No Name to HEAD. As you can see on Figure 54 Head isnt position as it should be (in left hand) so we will use attachment triangles as guide for right positioning.
Figure 54

Disable visible checkbox (its easier to adjust its place), toggle wireframe render, disable texture render (E), zoom left hand until you see it like on Figure 55.
Figure 55
Now lay mouse cursor over vertex numbered 1 and press 1 on keyboard (number next to center in Vertices part of menu is changed), lay cursor over vertex numbered 2 and press number 2 (number next to front in Vertices part of menu is changed), lay cursor over vertex numbered 3 and press number 3 (number next to up in Vertices part of menu is changed). Enable attachment visibility and head should be attached to hand like on Figure 56.
Figure 56

As you can see head isnt well positioned in contrast to hand (it's to low positioned). Now we can manually adjust its position changing numbers in DX, DY and DZ editboxes. Type 0,09 in DY box and head should fit perfect in left hand (Figure 57).
Figure 57

To add more attachments click on Add button and repeat process of parenting models to traingles for each attachment (RocketLauncher....).

NOTE: more attachment models can be attached on single attachment traingles.
NOTE2: you dont need to use attachment triangles, you can use any 3 vertices in object as triangle, but generally adding specific triangle guarantie precision. After ading all attachments select Attachment Traingles surface and in Rendering tab disable DoubleSided and enable ignored (this way polygons with ignored flag enabled wont render in engine) flags. Play few animations from model to see how attachments fit on model.(Figure 58).
Figure 58

NOTE: When making models that will be used as attachment, its best to position them centered around origin of coordinate system or that it lays on the ground. For example Head.mdl will be attached on neck. Attachment triangle on the neck of Headman.mdl is positioned as it was head itself, this way when you attach head to neck triangle it will fit on the neck without adjusting positions in Attachment tab.


Creating player model

Creating player model overview

Player models are multipart models. They are created as any other models (read more about model creation in Serious Modeler Help). Main model is player's legs called by default player.mdl (you can change it in Player's .amc file). Torso (by default body.mdl, but could be changed in .amc file) is attached on player.mdl (read more on attachments in Serious Modeler help). Body must have attachment called HEAD (by default head.mdl, but could be changed in .amc file). Other models (like glasses, helmets....) are optional and must be included in player's .amc file.
Everyone of required models have set of attachments (body, head, weapons...) which names and sequencing should be as default (additional attachments can be added and controled via .amc files). When loading any player model in Serious Modeler, in in Tools panel (Q) under Attachments tab, next to each attachment name, link to actual model is found. Bellow is list of required attachments for Player model (from .h file).

Legs model: (player.mdl)
PLAYER_ATTACHMENT_TORSO 0 -Attachment name for torso (body.mdl), additional attachments can be added on model and controled via .amc file

Torso model: (body.mdl)
BODY_ATTACHMENT_HEAD 0 -Attachment name for Head (Head.mdl), additional attachments can be added after on model and controled via .amc file
BODY_ATTACHMENT_COLT_RIGHT 1 -Attachment name for colt (in right hand)
BODY_ATTACHMENT_KNIFE 2 -Attachment name for Knife (in right hand)
BODY_ATTACHMENT_SINGLE_SHOTGUN 3 -Attachment name for Single shotgun (controled by right hand's triangle by default)
BODY_ATTACHMENT_DOUBLE_SHOTGUN 4 -Attachment name for Double shotgun (controled by right hand's triangle by default)
BODY_ATTACHMENT_FLAMER 5 -unused
BODY_ATTACHMENT_TOMMYGUN 6 -Attachment name for Tommy gun (controled by right hand's triangle by default)
BODY_ATTACHMENT_CANNON 7 -Attachment name for Cannon (controled by right hand's triangle by default)
BODY_ATTACHMENT_GRENADE_LAUNCHER 8 -Attachment name for Grenade launcher (controled by right hand's triangle by default)
BODY_ATTACHMENT_LASER 9 -Attachment name for Laser gun (controled by right hand's triangle by default)
BODY_ATTACHMENT_MINIGUN 10 -Attachment name for Minigun (controled by right hand's triangle by default)
BODY_ATTACHMENT_ROCKET_LAUNCHER 11 -Attachment name for Rocket launcher (controled by right hand's triangle by default)
BODY_ATTACHMENT_COLT_LEFT 12 -Attachment name for colt (controled by left hand's triangle by default)
BODY_ATTACHMENT_ITEM 13 -Attachment name misc items (used in singleplay only)

Head model: (Head.mdl)
Dont have any required attachments,additional attachments can be added on model and controled via player's .amc file

Player's legs model (player.mdl by default) need to have 3 assinged collision boxes, their names and sequencing must not be changed but properties as size and positions are adjustable.
PLAYER_COLLISION_BOX_STAND 0 -Standing collision when player walks, stand, fires weapons...
PLAYER_COLLISION_BOX_CROUCH 1 -Crouch collision when player is crouched
PLAYER_COLLISION_BOX_SWIM 2 -Swimming collision when player swims
PLAYER_COLLISION_BOX_SWIMSMALL 3 -Optional collision when player changes from walk to swim or vice versa.

Serious Sam model have extra set of animations for Cut sequences. They must exist in Serious Sam model in order to game properly work but to keep file size smaller they can be replaced with any existing animation from that model or can consist of single frame. To keep model's size smaller, body's weapons animations have been grouped in 3 groups:
1)Colt_: for colts and knife idle/attack/redrawing/drawing weapons....
2)Shotgun_: for single/double shotgun, laser, tommygun idle/attack/redrawing/drawing weapons....
3)Minigun_: for minigun/rocketlauncher/grenadelauncher and cannon idle/attack/redrawing/drawing weapons....
Those 3 groups have animations for swiming and walking.
Bellow is list of animations per model with comment which are must for singleplayer model and which can be replaced with other animations.

Torso model: (body.mdl)
Required animations

Colt animations
BODY_ANIM_DEFAULT_ANIMATION 0 -optional, best used for adding/adjusting attachments
BODY_ANIM_COLT_STAND 1-idle/running/walking/jumping animation
BODY_ANIM_COLT_REDRAW 2-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_COLT_DRAW 3-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_COLT_FIRERIGHT 4-firing right hand colt(can be only 1 frame to keep filesize smaller)
BODY_ANIM_COLT_FIRELEFT 5-firing left hand colt(can be only 1 frame to keep filesize smaller)
BODY_ANIM_KNIFE_ATTACK 6-knife attack(can be only 1 frame to keep filesize smaller)

Swimming Colt animations
BODY_ANIM_COLT_SWIM_STAND 7-swim idle/swimming animation
BODY_ANIM_COLT_SWIM_REDRAW 8-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_COLT_SWIM_DRAW 9-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_COLT_SWIM_FIRERIGHT 10-firing right hand colt(can be only 1 frame to keep filesize smaller)
BODY_ANIM_COLT_SWIM_FIRELEFT 11-firing left hand colt(can be only 1 frame to keep filesize smaller)
BODY_ANIM_KNIFE_SWIM_ATTACK 12-knife attack(can be only 1 frame to keep filesize smaller)

Shotgun animations
BODY_ANIM_SHOTGUN_STAND 13-idle/running/walking/jumping animation (can be same as Colt_stand to keep file size smaller)
BODY_ANIM_SHOTGUN_REDRAW 14-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_DRAW 15-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_SHOTGUN_FIRELONG 16-firing heavy weapons like doubleshotgun(can be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_FIRESHORT 17-firing smaller weapons like singleshotgun/laser/tommygun(can be only 1 frame to keep filesize smaller)

Swimming Shotgun animations
BODY_ANIM_SHOTGUN_SWIM_STAND 18-swim idle/swimming animation
BODY_ANIM_SHOTGUN_SWIM_REDRAW 19-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_SWIM_DRAW 20-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_SHOTGUN_SWIM_FIRELONG 21-firing heavy weapons like doubleshotgun(can be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_SWIM_FIRESHORT 22-firing smaller weapons like singleshotgun/laser/tommygun(can be only 1 frame to keep filesize smaller)

Migun animations
BODY_ANIM_MINIGUN_STAND 23-idle/running/walking/jumping animation (can be same as Colt_stand to keep file size smaller)
BODY_ANIM_MINIGUN_REDRAW 24-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_DRAW 25-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_MINIGUN_FIRELONG 26-firing heavy weapons like Rocket/Grenade launcher and cannon(can be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_FIRESHORT 27-firing faster weapons like minigun(can be only 1 frame to keep filesize smaller)

Swimming Migun animations
BODY_ANIM_MINIGUN_SWIM_STAND 28-swim idle/swimming animation
BODY_ANIM_MINIGUN_SWIM_REDRAW 29-puting weapon away (can be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_SWIM_DRAW 30-taking weapon out (can be same animation as Draw, with frames sequence inverted)
BODY_ANIM_MINIGUN_SWIM_FIRELONG 31b>-firing heavy weapons like Rocket/Grenade launcher and cannon(can be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_SWIM_FIRESHORT 32-firing faster weapons like minigun(can be only 1 frame to keep filesize smaller)

Death animations
BODY_ANIM_DEATH_UNDERWATER 33-death when killed while swimming or drawned
BODY_ANIM_DEATH_UNDERWATERIDLE 34-death idle underwater
BODY_ANIM_DEATH_BACK 35-death when killed with heavy weapon or by receiving large ammount of damage from front
BODY_ANIM_DEATH_EASYFALLBACK 36-death when killed with small weapon or by receiving small ammount of damage from front
BODY_ANIM_DEATH_FORWARD 37-death when killed with heavy weapon or by receiving large ammount of damage from back
BODY_ANIM_DEATH_EASYFALLFORWARD 38-death when killed with small weapon or by receiving small ammount of damage from front
BODY_ANIM_DEATH_SPIKES 39-death when pierced with spikes

Cut sequences only: (not used in multiplayer)
BODY_ANIM_COLT_REDRAWSLOW 40- puting weapon away slowly (same animation as redraw just slower, could be only 1 frame to keep filesize smaller)
BODY_ANIM_COLT_DEACTIVATETOWALK 41- weapon redraw to 1st frame of walk animation (could be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_REDRAWSLOW 42- puting weapon away slowly (same animation as redraw just slower, could be only 1 frame to keep filesize smaller)
BODY_ANIM_SHOTGUN_DEACTIVATETOWALK 43- weapon redraw to 1st frame of walk animation (could be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_REDRAWSLOW 44- puting weapon away slowly (same animation as redraw just slower, could be only 1 frame to keep filesize smaller)
BODY_ANIM_MINIGUN_DEACTIVATETOWALK 45- weapon redraw to 1st frame of walk animation (could be only 1 frame to keep filesize smaller)
BODY_ANIM_STATUE_PULL 46- puting misc items to altars
BODY_ANIM_LOOKAROUNDONCE 47- looking around
BODY_ANIM_WAIT 48- inner animation from idle to look around
BODY_ANIM_WAITTOLOOKAROUND- inner animation from idle to look around 49
BODY_ANIM_LOOKAROUNDTOWAIT- inner animation from idle to look around with sequence inverted 50
BODY_ANIM_LOOKAROUND 51- macro animation, consist of WaitToLookAround,4 times LookAoundOnce adn LookAroundToWait
BODY_ANIM_NORMALWALK 52-body walk animation without weapons
BODY_ANIM_SPAWNPOSE 53- spawning frame for beggining of the game
BODY_ANIM_BRIDGEFALLPOSE- falling from the bridge animation 54
BODY_ANIM_KEYLIFT - taking items from altar55
BODY_ANIM_ABYSSFALL 56- falling to abyss
BODY_ANIM_SPAWN_FALLDOWN 57- spawning animation for beggining of the game
BODY_ANIM_SPAWN_GETUP 58- geting up for beggining of the game

Legs model: (Player.mdl)
Required animations

PLAYER_ANIM_DEFAULT_ANIMATION 0- default animation, can be any of frames from other animations, good for testing LOD, attachment adding/adjusting....
PLAYER_ANIM_STAND 1- idle when standing still (can be used in computer/model browser)
PLAYER_ANIM_BACKPEDAL 2- walk backwards (can be same as walk just frames sequence inverted or Backpedalrun but faster
PLAYER_ANIM_BACKPEDALRUN 3- run backwards (can be same as run just frames sequence inverted)
PLAYER_ANIM_JUMPSTART 4-jump up part, player will stay in last frame while flying thru air
PLAYER_ANIM_JUMPEND 5-falling down from jump
PLAYER_ANIM_TURNLEFT 6-turning left (can be replaced with walk/run)
PLAYER_ANIM_TURNRIGHT 7-turning right (can be replaced with walk/run)
PLAYER_ANIM_RUN 8-run animation
PLAYER_ANIM_NORMALWALK 9-run animation (if doesnt look wierd can be replaced with run but should be slower)
PLAYER_ANIM_CROUCH 10-crouching, player will stay in last frame while crouched
PLAYER_ANIM_RISE 11-standing up to idle (can be same as crouch but inverted)
PLAYER_ANIM_CROUCH_IDLE 12-idle while crouched (can be only 1 frame to keep filesize smaller)
PLAYER_ANIM_CROUCH_TURNLEFT 13-turning left crouched (can be replaced with crouch walk)
PLAYER_ANIM_CROUCH_TURNRIGHT 14-turning right crouched (can be replaced with crouch walk)
PLAYER_ANIM_CROUCH_WALK 15-crouched walk
PLAYER_ANIM_CROUCH_WALKBACK 16-can be replaced with crouched walk but inverted
PLAYER_ANIM_SWIM 17-swim
PLAYER_ANIM_SWIMIDLE 18-swim idle (can be replaced with few frames from swim but much slower)
PLAYER_ANIM_DEATH_UNDERWATER 19-death when killed while swimming or drawned
PLAYER_ANIM_DEATH_UNDERWATERIDLE 20-Death underwater idle (can be replaced with few frames from Death_Underwater but much slower)
PLAYER_ANIM_DEATH_BACK 35-death when killed with heavy weapon or by receiving large ammount of damage from front
PLAYER_ANIM_DEATH_EASYFALLBACK 36-death when killed with small weapon or by receiving small ammount of damage from front
PLAYER_ANIM_DEATH_FORWARD 37-death when killed with heavy weapon or by receiving large ammount of damage from back
PLAYER_ANIM_DEATH_EASYFALLFORWARD 38-death when killed with small weapon or by receiving small ammount of damage from front
PLAYER_ANIM_DEATH_SPIKES 39-death when pierced with spikes

Cut sequences only: (not used in multiplayer)
PLAYER_ANIM_STATUE_PUT 26-not used, should be 1 frame
PLAYER_ANIM_SPAWNPOSE 27- 1 frame for game beggining
PLAYER_ANIM_BRIDGEFALLPOSE 28- falling from the bridge
PLAYER_ANIM_KEYLIFT 29- taking items from altar
PLAYER_ANIM_ABYSSFALL 30- falling into deep abyss (death)
PLAYER_ANIM_SPAWN_FALLDOWN 31- falling from spawn pose
PLAYER_ANIM_SPAWN_GETUP 32- getup
PLAYER_ANIM_ENTERSPACESHIP 33- pose for the end of game
PLAYER_ANIM_INTRO 34- pose for game intro
Serious Sam model is only one available in singleplay and multiplay because it have additional animations needed for ingame cut sequences.

Note: Since weapons used in Serious Sam are different visually, we used those 3 groups of weapon handling for player models (Colt,Shotgun and Minigun). You can group them in single group and point different animations to same model animations (like Colt_stand, Shotgun_stand and Minigun_stand can be same animation).
To keep filesize smaller, some animations can be single frames only (like drawing/redrawing, fireing....).
Serious Engine uses interpolation between animation frames, so some animations with linear motion can have frame count reduced and still look good. If animation have complex nonlinear motion, more frames is needed.

Every player model uses same sounds located in Sounds/Player in .gro file. To change those sounds, unpack that directory from .gro file (zip archive) to root directory where Serious Sam is installed.
When game is started it will load sounds/models/textures first from folders where Serious Sam is installed and if cant find them there, it will look in .gro file.
To change Serious Sam model, unpack directory Models/Player/SeriousSam/ from .gro file (zip archive) to root directory where Serious Sam is installed.

Attachment model configuration files (.amc) located in root of Model/Player folder are used in Serious Sam's Players and Controls menu, though their implementation in future will be expanded and modified. Currrently they are used when previewing multiplayer models and attaching weapons to them ingame. There are 2 types of .amc files: one for weapons and one for multiplayer models. Weapons .amc files are located in Models/Weapons directory in .gro file, Player .amc files are located in Models/Player folder in .gro file.

Weapons:

This is .amc file for Rocket Launcher weapon (RocketLauncher.amc).
    { 						-beggining of .amc

      Attachment: 11 					-attachment number on Player's body model
      {						-beggining of models definition

        Model:   TFNM Models\Weapons\RocketLauncher\RocketLauncherItem.mdl 	-main weapon model
        Texture: TFNM Models\Weapons\RocketLauncher\Body.tex 		-main weapon model's texture

        Attachment: 0 					-1st attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\Body.mdl 		-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\Body.tex 		-attachment model' texture name
        }

        Attachment: 1 					-2nd attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\RotatingPart.mdl 	-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\RotatingPart.tex 	-attachment model' texture name
        }

        Attachment: 2 					-3rd attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.mdl 	-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.tex 	-attachment model' texture name
        }
        Attachment: 3 					-4th attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.mdl 	-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.tex 	-attachment model' texture name
        }

        Attachment: 4 					-5th attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.mdl 	-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.tex 	-attachment model' texture name
        }

     Attachment: 5				-6th attachment on main weapon model
        {
          Model:   TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.mdl 	-attachment model name
          Texture: TFNM Models\Weapons\RocketLauncher\Projectile\Rocket.tex 	-attachment model' texture name
        }

      }						-end of models definition

    }						-end of .amc
Every multiplayer model have in its .amc file reference to weapon .amc file in preview mode. Attachments should be added in .amc file in order as they are added in model file.

Player:

This is .amc file for Serious Sam player (SeriousSam.amc).
Name: Serious Sam 					-name of model
{						-beggining of model definition
  Model:   TFNM Models\Player\SeriousSam\Player.mdl			-player model name (master model )
  Texture: TFNM Models\Player\SeriousSam\Player.tex			-player model's texture name
  Animation: 1					-preview animation number

  Attachment: 0					-1st attachment on player model (should be body if exists)
  {						-beggining of body attachment models definition

    Model:   TFNM Models\Player\SeriousSam\Body.mdl			-body model name
    Texture: TFNM Models\Player\SeriousSam\Body.tex			-body model's texture name
    Animation: 23					-preview animation number

    Attachment: 0					-1st attachment on body model (should be head if exists)
    {
      Model:   TFNM Models\Player\SeriousSam\Head.mdl			-head model name
      Texture: TFNM Models\Player\SeriousSam\Head.tex			-head model's texture name

      Attachment: 0					-1st attachment on head model
      {
        Model:   TFNM Models\Player\SeriousSam\Glasses.mdl		-glasses model name
        Texture: TFNM Models\Player\SeriousSam\Glasses.tex		-glasses model's texture name
      }
    }
    PreviewOnly
     {

      Include: TFNM Models\Weapons\Minigun.amc			-weapon's .amc for preview
     }

  }						-end of body attachment models definition
}						-end of model definition
In model's definition section, specular textures can be added. For specular add line Specular:TFNM Models\SpecularTextures\Medium.tex bellow Texture definition line. Same applies for bump (Bump:TFNM Models\BumpTextures\Metal.tex) and reflection (Reflection:TFNM Models\ReflectionTextures\gold.tex).


Tutorial 01

Creating and importing multiplayer models in Serious Modeler

This tutorial will cover process of creating multiplayer models for Serious Sam. There will be couple sections:

  • Preparing Model
  • UV Mapping,Texturing and Creating .mdl File
  • Attachments
  • Animations
  • Optimizing Models and LOD
  • Importing Player into Serious Sam


Adding Reflection Textures on Models

Things in realworld like metal, water, plastic etc.. have material properties to reflect enviroment around them. To simulate that in Serious Engine (without huge impact on CPU) REFLECTION maps are used. They can be any of 3 possible texture types supported in Serious Engine but 1st (still image) are ones to make sence using. Reflection texture dont replace diffuse, its added on model as spherical coat (shrinkwrapped aound it). Model can have only one Reflection texture (Figure 64 shows one typical reflection texture with alpha chanell ) and not all surfaces in model have to have reflection enabled.

Figure 64

Usually they are greyscaled or colored fractal patterns or background created with Create Reflection texture tool. Load any model with diffuse map or create new one. Open Tools window and in Render tab click on Select all surfaces button and enable Reflections checkbox. Nothing changes on model. We need to add reflection texture for this model (Figure 63) by clicking on Browse reflection Texture button.

Figure 63

After selecting proper texture, model changes its appereance (Figure 65).

Figure 65

If you rotate model around you will notice how it reflection changes. By default reflection strenght is 100% meaning model is 100% reflective. Color and reflection strenght can be changed in Reflection settings under Rendering tab (Figure 66).

Figure 66

All surfaces in model can have different color and astrenght settings (but all must have same texture). Serious Modeler have inbuilt tool for creating Reflection Textures. You need 6 panoramic images (90 FOV, Floor, East, Right, Ceiling, North and South ) either rendered in 3D application, photographed or saved from WorldEditor. When you have those 6 images ready run Reflection Texture Creator ( Figure 67).

Figure 67

To test created texture, Teapot is used. Click on black box right from Ceiling text and point to image used as ceiling. If filenames are like:
curved_envC.tga		ceiling
curved_envE.tga		east
curved_envF.tga		floor
curved_envN.tga		north
curved_envW.tga		west
curved_envS.tga		south
modeler will load rest of images automatically. Rotate teapot with LMB to observe created texture and click on Create button to save it (you can change texture size to be smaller than images texture is created from). After texture is saved load it as reflection texture and apply on model.

TIP1:You dont need to use large pixel size textures (256 or higher) for reflection texture.
TIP2: Use greyscale images as reflection texture and color them in Serious Modeler (from Rendering tab) for maximum flexibility and texture reusage.
TIP3:Since rendering reflection texture adds one pass in rendering of model, reflection texture can be disable in mipmodels (in manual mipmodel mode select mipmodel you dont want relfections to be rendered and surfaces you dont want reflection to be drawn for).
TIP4: Reflection looks best on higher polygon count models with curved geometry (reflection texture applied on simple box model wont give impressive visual appereance). Reflection texture can be added to model's script so when model is recreated texture will be automatically loaded.


Adding Specular Textures on Models

Highly reflective materials in nature (like metals and water) tend to reflect strong lightsources like Sun. To simulate that in Serious Engine with minimum impact on performance (and smaller CPU overload) SPECULAR textures are used. There can be only one specular texture per model. Specular textures are procedural textures created with Serious Modeler's tool (Figure 68).

Figure 68
Texture size and strenght can be adjusted (with interactive update on teapot) and texture saved. Most used settings are medium, used for simulating gold statue or metal armor. After saving texture (Create button), go to Rendering tab of Tools window and click on Specularity checkbox for current surface (or all surface). Nothing has changed on model, so you need to load Specular texture (using Browse Specular Texture icon. After loading rotate or move model around or move light around object to see changes on model (Figure 69).

Figure 69

Specular color and strenght can be adjusted in rendering tab (Figure 70).

Figure 70

Specular textures can cooexist on model along with reflection textures. Surfaces can have different specular settings.

TIP1: Specular can be removed from mipmodels (same as Reflectivity)
TIP2: With smaller specular highlight metals are simulated while with high more plastic looks is achieved.
TIP3: Specular looks best on higher polygon count models with curved geometry (specular texture applied on simple box model wont give impressive visual appereance). Specular texture can be added to model's script so when model is recreated texture will be automatically loaded.


Creating and Adding Bump Textures

Adding Bump to models adds another level of realism in model's vizualisation. When observing model very closely viewer may noticed bluriness of texture (texture size isn't big to eliminate huge impact on graphic cards and Engine). To eliminate blur and to simulate nature of material like stone, rocks and old metals, Bump textures are used. Bump textures should be greyscale 2d images used to displace texture on models (Figure 71 shows typical bump map used in Serious Engine).

Figure 71

As you can see their size in meters is very small allowing them to "tile" (repeat) over model. Since they use model's mapping coordinates no distortion occurs. Figure 72a shows model with texture that resembles as it was made from stone.

Figure 72

Such model is very suitable for adding Bump, in same fashion as reflection and specularity. From Rendering tab select all surfaces or ones you want to add bump to. Click on Bump checkbox and load bump texture using Browse Bump Texture icon. You need to get very close to model to see bump effect. Another way to add small details to model is to use Detail texture instead of Bump. Bump effect takes in account light's angle and positions while Detail only adds small amount of grain over texture (but have less impact on CPU). Those 2 modes are exclusive i.e. you cant have both enabled. Same as for specular and reflection textures, bump texture can be added in script, so any model recreating will result in automatic Bump texture adding.

Figure 72b - Detail texture

Figure 72c - Bump texture

TIP1: Bump or Detail can be removed from mipmodels (in same fashion as reflection and specular texture).
TIP2: Good idea is to add 2 same mipmodels (0th and 1st) , with difference being in that 0th have Bump and 1st and rest of mipmodels dont.


Creating Flat and Half Flat Models

Flat and Half_Flat models differ from "normal" in fact they are usually single plane (or very small polygon count ) models used to represent fires, explosions, particle effects, smokes etc. Example of Flat model would be single plane (2 triangles) model of explosion, mapped with animated texture (see TextureTypes) of explosion. Example of Half_Flat model would be single plane model of Fire, mapped with Fire Procedural texture (see TextureTypes). Flat or Half_Flat models allways target viewer in way that polygons' normal is 90 degree to viewer (targeted).

FLAT model

Create object like on Figure 73,surface it in single surface, save as ExplosionRocket.lwo.

Figure 73

Open Serious Modeler and click on New model (CTRL N shortcut). Select ExplosionRocket.lwo , you should end with something like on Figure 74.

Figure 74

Add animated texture (or any). When you move around model or model itself you notice that its flat plane (Figure 75).

Figure 75

Open script (S shortcut) and change line FLAT NO to FLAT YES, recreate model (CTRL SHIFT S). Try moving object, you may see how polygons (W shortcut toggles wireframe render) are allways targeted (rotates to viewer) to view no matter in what angle are we looking at model. This asures that you will see, for example explosion allways rotated to viewer (Figure 76).

Figure 76

HALF FLAT model

Create object like on Figure 77,surface it in single surface, save as Fire.lwo.

Figure 77
Open Serious Modeler and click on New model (CTRL N shortcut). Select Fire.lwo, you should end with something like on Figure78.

Figure 78

Add Effect texture and try moving model around (Figure 79).

Figure 79

Open script and change line HALF_FLAT NO to HALF_FLAT YES, recreate model and try rotating around model sideways. No matter how you rotate it, model will target you directly. Try rotating or moving above or under model, you will notice that model doesnt target you. As you see difference between Half and Flat models are on what axes does model try to target you. This two types of models gives you power to create very low polygonal model and still have them appear as fake volume models with many polygons and real volume.


Serious Modeler Keyboard Shortcuts

Keyboard shortcuts

  • Mode switching

  • Moving

  • Windows standard

  • Textures

  • Animations

  • Misc

  • Rendering settings

  • Mip modeling

  • Patches

Mode switching

M | toggle model/mapping view
S | load script

Moving

Space+LMB+mouse | move viewer/mapping left/right/up/down
Space+RMB+mouse | move viewer/mapping left/right/in/out
Space+LMB+RMB+mouse | rotate viewer around focus
Ctrl+LMB+mouse | move model left/right/up/down
Ctrl+RMB+mouse | move model left/right/in/out
Ctrl+(Num +) / Ctrl+Space+LMB | zoom in viewer/mapping x 2
Ctrl+(Num -) / Ctrl+Space+RMB | zoom out viewer/mapping x 2
Backspace | reset view/mapping position

Windows standard

F1 | help
Ctrl+N | new document
Ctrl+O | open document
Ctrl+S | save document
Ctrl+Shift+S | save as document (non script mode)
Ctrl+Shift+S | recreate model from script (script mode)
Ctrl+P | preferences
Alt+Q | close document window
G | toggle all tool bars
Ctrl+I | toggle info window
Ctrl+J | toggle color palette
Ctrl+K | toggle patch palette
Alt+S | take screenshot
Ctrl+U | save thumbnail

Textures

PgUp | previous texture
PgDn | next texture
Ctrl+T | add texture
Ctrl+Shift+T | create texture
R | recreate current texture
Ctrl+R | remove texture

Animations

Alt+A | animation list (model view mode)
Ctrl+Shift+A | update model animations
Arrow up | previous animation
Arrow up/down | previous/next animation
Shift+Arrow up/down | first/last animation
Shift+Arrow left/right | first/last frame
Return | toggle animation pause mode on/off
Shift+Return | play current anim once
F5 | rotate heading for 90 deg clockwise
F6 | rotate pitch for 90 deg clockwise
F7 | rotate banking for 90 deg clockwise

Misc

I | create level of details
Z | select surface(s) dialog
Tab | next surface
Shift+Tab | previous surface
C | center mapping area on screen (mapping mode)
C | toggle view collision box (model view mode)
, | toggle pick color mode
1 | set center vertex for attachment placement
2 | set front vertex for attachment placement
3 | set up vertex for attachment placement
A | toggle view all surfaces (mapping mode)
Alt+B | animate mapping area texture on/off
Ctrl+Q | toggle measure relative offset mode

Rendering settings

B | toggle texture in background
Ctrl+Shift+B | change color for background
Ctrl+B | toggle skin rendering
F | view floor on/off
W | toggle wire frame on/off
Alt+C | view model in surface colors
A | change light color
U | toggle auto rotation
Alt+R | toggle rendering statistics
N | render model without texture
T | render model using texture
E | render in white texture
Num+ | render model using on colors
Num- | render model using off colors

Mip modeling

O | toggle auto mip modeling (auto LOD)
[ or Ctrl+Up | switch to rougher mip level (LOD)
] or Ctrl+Down | switch to more precise mip level (LOD)

Patches

Insert | add current patch
Delete | remove current patch
Ctrl+Arrow left | previous patch
Ctrl+Arrow right | next patch


Basics for Programming with Serious Engine

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Basic Information
    Required knowledge:
  • C++ programming
    Explains:
  • Basic information about programming classes and game executables with Serious Engine.

    Required Tools

    [Win32 specific]
  • VisualC++ 6.0 w/ sp3
    This will be the compiler, debugger and editor, both for the game and engine executables and for the classes.
    • [/Win32 specific]
  • Entity Class Compiler (ecc.exe)
    Ecc is used for compiling the entity class sources (.es) into .cpp files which are in turn compiled by the cpp compiler to get the final binary code. Ecc comes in a binary form with a complete distribution of engine, and should be located in the Bin\ directory of the engine dir.
    • [licensees only]
  • Parser generator tools (flex and bison)
    You do not need these unless you will recompile the engine itself, or the ecc.
    • [/licensees only]

    Directories and Path Settings

    While all the data and executables must reside in the engine directory, sources have their independent directory tree. They all reside in a directory that we will refer to as 'sources directory', or sources dir. The sources dir is always separate from the engine dir (e.g. D:\Work\Sources\ being my sources dir, while D:\Work\SeriousSam\ is my engine dir).
    In the sources dir, each project has its own subdirectory, named by that project. The sources are compiled there as usual, while the last stage in project building must always include copying the final binaries to the Bin\ (or Bin\Debug\) directory in the engine dir.
    To enable access to the sources and binaries from the makefiles, you must have the following environment variables and settings set up:

    [Win32 specific]
    You should set the ENGINE_DIR in your global environment (using autoexec.bat on Win9x, or SystemProperties control panel under WinNT) and adjust the rest in the 'Directories' tab under Tools/Options in VisualC++.
    [/Win32 specific]

    1) ENGINE_DIR env var must point to the engine directory (e.g. 'D:\Work\SeriousSam'). Do not put the trailing backslash here.

    2) Include file path must be set to include both the engine dir and the sources dir. (e.g. D:\Work\Sources; D:\Work\SeriousSam). The sources dir must be here, because all the includes are specified relatively to the sources dir, and the engine dir must be here because automatically generated header files for models are put in the same directory where the models are.

    3) Library file path must include Bin\ and Bin\Debug\ subdirectories of the engine dir (e.g. D:\Work\SeriousSam\Bin; D:\Work\SeriousSam\Bin\Debug). Link libraries for the engine and game dlls are put there.

    4) Executable file path must include Bin\ subdirectory of the engine dir (e.g. D:\Work\SeriousSam\Bin). This is because the build requires access to the Entity Class Compiler (ecc.exe) which is located there.

    [licencees only]
    Also, if you will rebuild the engine binaries itself, you must add one more directory to the executable path: the directory where you have installed parser generator tools - Flex and Bison.
    [/licencees only]

    Project Hierarchy

    (only those parts relevant for changing are described, this excludes the editors for now)

  • Ecc builds the Entity Class Compiler executable. It is the base project and does not depend on anything.
  • Engine is the dll containing most of the engine's code, including base support, graphics, sound, input, rendering, networking, built-in classes etc. But it does not contain any GUI elements. It depends on Ecc because some built-in classes are compiled using Ecc.
  • Entities dll is a package containing all the classes used in Serious Sam. Classes can be separated across many different dlls, and any custom classes will most certainly be in some separate dlls. Depends on Engine and on Ecc.
  • Game dll contains code of the game that is run both from SeriousSam.exe and from the WorldEditor. This enables embedded game testing. Game takes care of all the game management including: starting a game, managing network connecting, loading, saving, managing game controls, game-specific rendering options etc. Buit it does not contain any GUI elements. It is just a small dll, since it relies heavily on Engine for carrying out these tasks. Game dll only calls specific functions from the Engine. Depends on Engine and on Entities.
  • SeriousSam builds the main game executables whose main task is to load the Game dll, open a window any provide menu management. It relays all of the game management to the Game dll, Engine dll and entities. Depends on Engine, Game and Entitites.
  • EngineGUI is a dll containing those parts of the engine that rely on the Windows GUI. This is available only under Win32, and is used only by the editors. Depends on Engine.
  • GameGUI is a dll containing the part of game with a few customizable dialogs that WorldEditor. This is available only under Win32, and is used only by the editors. Depends on Engine and on Game.


Setting up the Development Environment

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • None
    Required knowledge:
  • Using Visual C++ 6.0
    Explains:
  • How to customize VC6 for more comfortable work with Serious Engine.

    User Defined Keywords

    As you may know, syntax coloring feature of Developer Studio supports custom keywords. You should add additional keywords defined for entity sources ('.es' files) and specific types and classes defined in Serious Engine.
    Entire list of the entity source keywords together with engine standard types is in the supplied Usertype.dat file. Just append it to the file 'UserType.dat' in the 'Common\MSDev98\Bin\' directory in the installation of Developer Studio.
    Remember to restart Developer Studio after you do that.

    Auto Expansion in Debugger

    Developer Studio also supports automatic formatting of watched variables of some user type. To enable that for Serious Engine types, use the supplied Autoexp.dat file which you can put instead of the original in the 'Common\MSDev98\Bin\' directory in the installation of Developer Studio. If you have already added some of your own formatting there, you should manually merge the supplied file with yours.
    Remember to restart Developer Studio after you do that.

    Enabling Syntax Coloring for '.es' files

    If you have never worked on entities before, you Developer Studio is not customized for proper display of '.es' files, and they will appear all as black-on-white, like ordinary text files, unlike C++ '.cpp' sources which have syntax coloring.
    To make Developer Studio recognize your '.es' files as it does with '.cpp' files and do syntax coloring for them, you should use Registry Editor to edit the following key:
    HKEY_CURRENT_USER\Software\Microsoft\Devstudio\6.0\Text Editor\Tabs/Language Settings\C/C++
    and add 'es' to the list of extensions.
    You can use the supplied registry file SyntaxColoring.reg which will do that for you.
    IMPORTANT: Make sure that Developer Studio is not running when you do that! If it is, it will delete your settings when it exits.


Programming Conventions

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Basics for Programming with Serious Engine
    Required knowledge:
  • C++ programming
    Explains:
    Conventions that you should take care and/or be aware of when you write code for.

    Indentation

    All sources have been written using two-space indentation and with inserting spaces instead tabs. Hold on to that if you want, but you don't really have to unless you work in Croteam. This one is optional for all except Croteam programmers.

    Symbol Naming

    Functions and variables and types are named with CapitalFirstLettersOfEachWord.
    Class type names are prefixed with a capital 'C'. If there is a risk of a possible name-clash, 'CT' (short for Croteam) is used instead of 'C'.
    Preprocessor macros are ALLCAPITALS.
    Relaxed Hungarian convention is used for variables. Variables do have prefixed type, but more than one type can have same prefix, if they are not used in same scope. E.g 'f' can be a prefix for both floats and doubles. If both floats and doubles are used in the same context, then sometimes 'd' is used for doubles to make distinction.
    Member variables or classes are prefixed with abbreviation of the class type and an underscore (gffi_fnFileName). Exception to this are the entity classes, where the prefix is always 'm_' for simplicity.

    Exception throwing

    Only (char *) typed exceptions are thrown by all the code. Note that this is not the same as (const char *) and this one includes the immediate string constants in code. Usually a function throws an error report string which can be an immediate string constant, or formated using ThrowF_t() function.
    The fact that a function may throw such an exception, or call some other function which does so is denoted by appending the '_t' suffix to the function name (e.g CTStream::Read_t() ).
    This enables a programmer to manually check that no unhandled exceptions will occur. So much for that, until the method of using 'throw' keyword in function declaration becomes supported by compilers.
    Most of the functions throwing exceptions are loading, saving or network connection functions.

    Member Access Privileges

    Most member variables and functions are declared public. But they are usually separated into two different blocks in the class declaration using 'implementation:' and 'interface:' comments. You should respect those comments and not use the implementation parts of the class.
    This was done to remove the neccessity for a large number of 'friend' declarations and to enable access to some of the implementation parts from assembler functions.
    In some places, you may find some private or protected declarations. Those were used to prevent the programmer from accessing some functions/variables by mistake.

    Translation and Localization Support

    All string constants in the code that must be relayed through TRANS() preprocessor macro that will generate binary tags for automatic translation support.
    Example:
  Bad:   CPrintF("Successfully loaded\n");
  Good:  CPrintF(TRANS("Successfully loaded\n"));

    Filename Dependencies in the Executable Code

    The Engine takes care that every file name (CTFileName) that you save in a binary or text file has a tag that can be found by the Depend utility. This tag is DFNM for binary data files, TFNM for text files. In executable binaries, the tag is EFNM. But the compiler cannot know which of the string constants are filenames. To add the tag, you must relay all the file names in code through either CTFILENAME() or DECLARE_CTFILENAME() macro.
    Use CTFILENAME() for immediate constants, or DECLARE_CTFILENAME() to declare a filename and assign a value to it.
    To prevent a programmer from inadvertently forgetting to do so, it is impossible to initialize a CTFileName variable directly with a (char *) constant or variable. This was disabled by declaring all functions for construction from (char *) as private. If you encounter a compiler error stating that you cannot convert from (char *) to CTFileName, you will know that you must use CTFILENAME() macro, or cast through CTString.
    Example (with dependency):
  Bad:  strm.Open_t("file.dat");
  Good: strm.Open_t(CTFILENAME("file.dat"));
    Usually, you will want to have the filenames to be dependencies. If you don't (perhaps for temporary files, log files etc.), you must cast it through CTString.
    Example (without dependency):
  Bad:  strm.Open_t("file.log");
  Good: strm.Open_t(CTString("file.log"));


Base Section of the Engine

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Programming Conventions
    Required knowledge:
  • C++ programming

    Explains:
  • Description of the most relevant classes and functions in the 'Base' part of the Engine dll.

    Basic Types

    Typedef-ed integral and rational types are used instead of ANSI C types for brevity, clarity, symmetry and portability.
    SLONG - 32 bit signed integer
SWORD - 16 bit signed integer
SBYTE -  8 bit signed integer

ULONG - 32 bit unsigned integer
UWORD - 16 bit unsigned integer
UBYTE -  8 bit unsigned integer

INDEX - 32 integer (implicitly signed) - used for indices, counters and counts
BOOL  - ordinary int used as boolean - TRUE and FALSE are #defined

PIX - same as SLONG, integer coordinates in pixels
TEX - same as SLONG, integer coordinates in texels
MEX - same as SLONG, integer coordinates in mexels (see Graphics)
COLOR - same as ULONG, color in 32 bit RGBA format

FLOAT - 32 bit IEEE float
DOUBLE - 64 bit IEEE float

ANGLE - same as FLOAT, used for angles (in degrees)
TIME - same as FLOAT, used for time values (in seconds)

    CTString

    A generic string class. Note difference between CTString and CString (as used by MFC). This is to avoid name clashes. Contains a zero terminated string by value and takes care of all the memory allocation/freeing. Standard operators like '+' and '+=' (concatenation), '==' and '!=' (case insensitive comparison), etc. are implemented. Supports PrintF, ScanF, pattern matching, trimming, loading and saving to binary and text files etc. An empty string always contains one character (the null terminator), so it can always be safely cast to (const char*).

    CTFileName

    Inherits CTString and adds filename management (FileDir(), FileName(), FileExt(), NoExt() and RemoveApplicationPath_t() functions).
    IMPORTANT: Although you may cast the CTFileName to (const char *) and pass it to some function that takes (const char *) input (like strlen()), take care that it will not work with var-arg functions like printf(). CTFileName is 8 bytes in size, and passing it directly to printf-style functions will create an extra argument (usually NULL). Always cast CTFileName to (const CTString &) when passing it to printf-style functions.

    Double-Linked Lists

    CListNode and CListHead are Used for double linked lists. Add one CListNode type member to class that will be added to a list, and one CListHead to a class that will hold the list (or instance a local CListHead if you need a temporary list).
    Use CListHead::AddTail() / CListHead::AddHead() to add members to list, and CListNode::Remove() to remove members from list.
    For iteration use following macros
    FOREACHINLIST(baseclass, member, head, iter)
  for normal iteration

FORDELETELIST(baseclass, member, head, iter)
  if current element may be destroyed during iteration

    Streams

    All loading and saving goes through a custom set of stream classes. The base class is CTStream. It supports binary and text reading/writing, chunk ID management, seeking, and filename dependency dictionary.
    Use Read_t() to read a block of data from a stream and Write_t() to write it. Standard '>>' and '<<' operators are overloaded for most simple data types including builtin types, strings and filenames.
    Dictionary is used when one file contains a lot of dependencies to other files, which are often repeated. This happens for example with textures, models etc. in world files. Then all those filenames are saved in a 'dictionary' only once for each distinct filename. Dictionary must be specially enabled for a certain stream, or one part of stream. If it is not enabled, filenames are saved/loaded directly.
    CTFileStream is a CTStream that resembles a file on disk.
    CTMemoryStream is a CTStream that resident in memory.
    Engine uses memory mapping for fast stream handling. On Win32, memory mapping is handled by the engine itself using a custom 'access violation' exception handler. In order for that to be possible, base of the call stack in each thread must be bracketed with a CTSTREAM_BEGIN/CTSTREAM_END block. If some thread is not bracketed that way, you cannot load/save files in that thread. That is the case with the timer thread.
    On Linux, memory mapping is automatically handled by the system.
    CTFileStream will refuse to open for any file that is outside of engine dir. To suppress such behaviour and temporarily enable usage of absolute paths, use global functions:
      IgnoreApplicationPath()
  UseApplicationPath()
    Additional handy global functions:
      FileExists()
  GetFileTimeStamp_t()

    CSerial and the Stocks

    'Stocking' is an automatic system for preventing redundant loads and extra memory usage. A 'Stock' is an object that keeps track of all loaded objects of one class, and takes care that they are not loaded twice. Objects derived from CSerial can be put in stocks. Currently used stocks in the Serious Engine are those of:
      light animations (CAnimData)
  entity classes (CEntityClass)
  models (CModelData)
  sounds (CSoundData)
  texture (CTextureData)
    You obtain an object from the stock by calling Obtain_t() and mark that you don't need it by calling Release(). The stock then loads the object if it is not already loaded and maintains a used count. Even when an object is not used any more, it is still kept in the stock, until FreeUnusedStock() is called. This way, when a user loads a saved game, or restarts a level, almost nothing is loaded, since all the textures, models, sounds, etc. are already loaded.

    Auto Animation Support

    Autoanimation means that an animatable object (derived from CAnimObject) is not in fact animated in real time, i.e. no CPU cycles are spent to update its current frame number through time, but rather current frame can be calculated on demand. I.e. when some part of code wants to know the current frame, it is calculated from its current parameters. E.g. when a model is rendered, the rendering system asks the CModelObject (derived from CAnimObject) what is its current frame. If the model is not rendered (because it is not visible), no time is wasted.

    Current frame is calculated from the following parameters:

  • current animation and its parameters (speed)
  • time when animation was started
  • current time
  • model object state (paused, smooth animation, looping...)

    Each CAnimObject is linked to its CAnimData. CAnimData represents a class of animatable objects like e.g. a Beheaded model. It is usually loaded from a file and has all the data regarding the number of animations, all of their parameters and a list of frames for each anim. All CAnimObjects in memory always link to the same CAnimData. (This is accomplished using 'stocking' for all CSerial derived classes - and CAnimData is derived from CSerial).
    For manipulation with CAnimObject derived objects, you will usually use following functions:
      SetData()
  SetData_t()
  PlayAnim()
  GetCurrentAnimLength()
  GetAnimLength()
  IsAnimFinished()
  GetPassedTime()

    Error Reporting

    There are some global functions for reporting an error to user:

    ThrowF_t()
    formats a string in a printf style and throws an exception with it

    FatalError()
    formats a string in a printf style, reports a fatal error to the user with that string, prints it to the console, then dumps the console to FatalError.log and quits program.

    WarningMessage()
    First, formats a string in a printf style.
    If the console variable 'con_bNoWarnings' is set, just prints it to the console.
    If it is not set, a popup message with the warning message is shown to the user, and the program pauses until the user presses Ok button.

    Console

    Basic meaning of the word console in Serious Engine is just a buffer where strings are printed. You can use CPrintF() and CPutString() to print to the console. Functions CON_NumberOfLinesAfter(), CON_GetLastLine(), and CON_GetBuffer() are then used in Game dll to actually show that on screen.

    Shell

    Shell is the part of engine that handles what is commonly refered to as 'console variables', but should more correctly be called 'shell symbols'.
    You can declare shell symbols using DeclareSymbol(). To execute statement(s) from the shell, use Execute().
    The Game dll itself uses that function to execute the statements that you type in the console in Serious Sam.
    Declaration syntax for declaring a new symbol is following:
    declaration
  : declaration_qualifiers type_specifier identifier pre_func_opt post_func_opt ';'
  | declaration_qualifiers type_specifier identifier '[' expression  ']' pre_func_opt post_func_opt ';'
  | declaration_qualifiers type_specifier identifier '(' type_specifier ')' ';'

declaration_qualifiers
  : /* nothing */
  | declaration_qualifiers 'const'
  | declaration_qualifiers 'user'
  | declaration_qualifiers 'persistent'
  | declaration_qualifiers 'extern'

type_specifier
  : 'FLOAT'
  | 'INDEX'
  | 'void'

pre_func
  : 'pre' ':' identifier

post_func
  : 'post' ':' identifier
    The first declaration is for scalars, second one is for arrays and the last one for functions.

persistent - denotes that the symbol will be saved/restored when the game exits/restarts
user - denotes that the symbol will be visible in ListSymbols() and accessible through 'tab'-cycling
const - the symbol cannot be changed from the shell
extern - the symbol is declared from a script file, not from executable code
    You declare a new symbol by passing a shell syntax declaration as the first parameter to the DeclareSymbol() function, while you give the address of the C++ variable or function as the second parameter.

    Pre- and post- functions are functions that are executed before and after a symbol is changed. If pre function returns FALSE, the symbol cannot be changed. You can use same function for more then one symbol, since the address of the symbol is passed as input parameter. Prototypes for pre and post functions are:

BOOL pPreFunc(void *);
void pPostFunc(void *);


Math Section of the Engine

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Base Section of the Engine
    Required knowledge:
  • C++ programming,
  • familiarity with geometry and linear algebra
    Explains:
  • Description of the most relevant classes and functions in the 'Math' part of the Engine dll.

    Vectors

    Vector<> is templated by scalar type contained in the vector and its dimension.
    Following vector types are used:
    typedef Vector          PIX2D;
typedef Vector          MEX2D;
typedef Vector        ANGLE3D; // Euclidean angles (h,p,b)
typedef Vector        FLOAT2D;
typedef Vector        FLOAT3D;
typedef Vector       DOUBLE2D;
typedef Vector       DOUBLE3D;
    Vector<> has standard operators overloaded:
  • sign flipping (unary-)
  • addition and substraction of two vectors (+, -, +=, -=)
  • multiplication and division with scalar (*, /, *=, /=)
  • cross (outer) product (*) (3D only)
  • scalar (inner) product (%)

    Three norms are defined: Euclidean (Length()), Manhattan (ManhattanNorm()) and Max-norm (MaxNorm).

    Normalization works on the vector object itself, and returns its reference (quite like +=).

    Elements of the vector are accessed using overloaded operator(), and one-based indices. This is similar to mathematical notations, unlike C-styled arrays. Constructors from elements are given for up to 4 dimensions.
    Example:
 FLOAT3D v(10, 20, 30);
 FLOAT x = v(1);
 FLOAT y = v(2);
 FLOAT z = v(3);

    Matrices

    Matrix<> is templated by the scalar type contained in the matrix and its two dimensions.

    Following matrix types are used:
    typedef Matrix     FLOATmatrix3D;
typedef Matrix    DOUBLEmatrix3D;
    Elements of the matrix are accessed using overloaded operator(), and one-based indices. First index denotes row and the second one column. This is similar to mathematical notations, unlike C-styled arrays. There are no constructors except default one (which trashes the contents in debug version) and constructor for clearing entire matrix to one given value.

    Diagonal matrix can be made with diagonal set to a scalar value or filled with a vector using two overloaded versions of Diagonal().

    Multiplication/division with scalar is defined by *, /, *= and /=. Matrix is transposed in-place using ! and from another matrix using !=.

    Matrix addition substraction is done by +, -, +=, -=. Matrix multiplication is * or *=.

    Quaternions

    Quaternion<> is templated by the scalar type contained. It defines construction from 4 scalars, conversion from euler angles (FromEuler()) and into a rotation matrix (ToMatrix()).

    Standar operations are defined: flipping (-), congjugation (~), inversion (Inv()), multiplication and division by a scalar (*, *=, /, /=), addition and substraction (+, -, +=, -=), multiplication (*, *=) and dot product (%).

    Norm() gives Euclidean lenght of the quaternion. For interpolation, Exp(), Log(), Slerp(), and Squad() are defined.

    Axis-aligned Bounding Boxes

    AABBox<> is templated by contained scalar type and dimension.

    Following box types are used:
    typedef AABBox          MEXaabbox2D;
typedef AABBox          PIXaabbox2D;
typedef AABBox        FLOATaabbox2D;
typedef AABBox        FLOATaabbox3D;
typedef AABBox       DOUBLEaabbox2D;
typedef AABBox       DOUBLEaabbox3D;
    By default, and aabbox is initialized to a normalized empty bounding box. That is a box whose min vector has maximum values and max vector has minimum values allowed for the type.

    It can be constructed to contain only one point, a sphere, or two points (for diagonal construction).

    Defined operations are: union (|=), intersection (&, &=), translation by a vector (+=, -=), stretching and expanding (Expand(), StretchByFactor(), StretchByVector()).

    Bounding box checking is done with == and != for (in)equality, >= and <= for containment, HasContactWith() and TouchesSphere() for adjacency/contact checking.

    To get properties of bounding box, you can use: Size(), Center(), Min(), Max() and IsEmpty().

    Oriented Bounding Boxes

    OBBox<> is templated by the contained scalar type and is always a 3D box.

    Following box types are used:
    typedef OBBox            FLOATobbox3D;
typedef OBBox           DOUBLEobbox3D;
    Oriented bounding box is defined by its center, 3 axis direction vectors and box size along each of the axes.

    It can be constructed as empty, from its components, or from an aabbox and given position and orientation in 3D.
    It can be tested only against a 3D plane for now.

    Plane

    Plane<> is templated by the contained scalar type and dimension. Currently, only 3D planes are supported.

    Following box types are used:
    typedef Plane         FLOATplane3D;
typedef Plane        DOUBLEplane3D;
    A plane is defined by the plane normal vector (always normalized) and distance from the origin along the normal vector.

    It can be constructed from its components, from normal vector and a point on the plane, and from 3 points on the plane (in ccw order).

    You can access the distance parameter by Distance(), and take advantage of the fact that Plane<> inherites from Vector<> to access its normal vector.

    Plane can be flipped (-), translated by a vector (+, -, +=, -=), rotated by multiplication with a matrix (*) and offset forward (Offset()).

    PointDistance() finds distance of a point from the plane, GetCoordinate() fills in a missing coordinate of a point on the plane, PlaneDistance() finds distance of a plane from the plane (assuming they are parallel or anti-parallel).

    ProjectPoint() and ProjectDirection() project a point or a direction vector to the plane.
    DeprojectPoint() and DeprojectDirection() project a point or a direction vector to the plane, but not along this planes normal, but rather along another plane's normal (used in projected mapping).

    Euler Angles

    Euler angles (ANGLE3D) used in Serious Engine are Heading, Pitch and Banking (HPB). Heading is rotation around Y axis, Pitch around X axis and Banking around Z axis. All rotations are mathematically positive (counter-clockwise if viewed from the tip of the imaginary plus vector of the rotation axis, along the axis down towards negative direction).

    Simplified: increasing Heading rotates left, increasing Pitch rotates up, increasing Banking tilts to the left. Order of rotations is Banking-Pitch-Heading making Heading most influencing one.

    To convert between Euler angles and rotation matrices, use following functions:
    MakeRotationMatrix()
MakeInverseRotationMatrix()
DecomposeRotationMatrix()

or

MakeRotationMatrixFast()
MakeInverseRotationMatrixFast()
DecomposeRotationMatrixNoSnap()
    The first versions perform snapping, while the latter are faster and smooth.

    Placements

    CPlacement3D is a class consisting simply of a 3D vector (FLOAT3D) and a set of 3 Euler angles (ANGLE3D).
    It defines position and orientation of an object in a reference system. The reference can be the absolute coordinate system, or some relative system, depending on the meaning in any given context. The class itself does not retain that information.
    For various rotations and translations of a placement use:
      Rotate_TrackBall()
  Rotate_Airplane()
  Rotate_HPB()
  Translate_OwnSystem()
  Translate_AbsoluteSystem()
    To transform between different reference systems use:
      AbsoluteToRelative()
  RelativeToAbsolute()
  RelativeToRelative()

or

  AbsoluteToRelativeSmooth()
  RelativeToAbsoluteSmooth()
  RelativeToRelativeSmooth()
    The base function (non-'Smooth') snap the coordinates of the placement after transformation, and are useful only in GUI editing, or CSG operations. Use 'Smooth' variants if snapping is not required.

    Projections

    CProjection3D is an abstract base class for all projections. Projections are generally used for transforming coordinates from one 3D space to another 3D or 2D space.

    CSimpleProjection3D implements simple transformation from 3D to 3D, including translation, rotation, uniform stretch and mirroring.

    CIsometricProjection3D implements 3D to 2D orthografic projection along an axis parallel to the viewing plane.

    CPerspectiveProjection3D implements 3D to 2D perspective projection.

    CParallelProjection3D implements 3D to 2D orthografic projection along an axis that is generally not parallel to the viewing plane.

    They are mostly used inside engine when rendering or performing some other calculations. From the outside, you will only need to set them up by adjusting viewer placement and viewing parameters (FOV, zoom etc.). You will seldom need to manually project points using projections.

    Additional Geometry Helper Functions

    You can transform Euclidean angles to direction vectors and vice versa using:
      AnglesToDirectionVector()
  DirectionVectorToAngles()
  UpVectorToAngles()

      ReflectPositionVectorByPlane()
  ReflectDirectionVectorByPlane()
  ReflectRotationMatrixByPlane_cols()
  ReflectRotationMatrixByPlane_rows()
    Misc. management with vectors and matrices (useful in AI and physics):
      GetParallelComponent()
  GetNormalComponent()
  GetParallelAndNormalComponents()
  OrthonormalizeRotationMatrix()


Basics of ES Programming

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Programming Conventions
    Required knowledge:
  • C++ programming
    Explains:
  • Basic facts about entity classes in Serious Engine.

    Types of Entities

    Entities in SeriousEngine are classified by their type (enum RenderType, declared in
    Each entity must declare its type as the first step of initialization in its Main() procedure.

    1) Model entities (RT_MODEL) (like enemies, player, statues etc.)

    Initialized by calling InitAsModel().

    Each model entity has a CModelObject which it can obtain a pointer to by calling GetModelObject(). Usually, model is set by calling SetModel() with the component number of the desired model file and its texture by calling SetModelMainTexture() with the component number of the desired texture file. If you desire to set the model's specular, reflection or bump textures, add attachments or similar, use GetModelObject() and then modify the model object manually.

    Model entities use their collision boxes edited in Serious Modeler for collision.
    /2) Editor model entities (RT_EDITORMODEL) (like lights, triggers, etc) Initialized by calling InitAsEditorModel().

    Editor models are similar to ordinary model entities in every way, except that they are only rendered in Serious Editor and only if 'Render Editor Models' flag is turned on for the particular view.

    Beware that they can collide with other entities in game, even though they will be invisible. You will usually want to declare them as immaterial, so that they do not collide with other entities.

    3) Brush entities (RT_BRUSH) (the world's architecture, doors, moving platforms, etc.)

    Initialized by calling InitAsBrush().

    Each brush entity is accompanied by one CBrush. Initially, the brush will be empty and level editor will then create it in the Serious Editor. In the entity source code, programmer really does not need to access the brush at all. All of its appearance settings are set by the level editor. Programmer just sets its collision and physics settings and defines its behavior.

    4) Field brush entities (RT_FIELDBRUSH) (trigger fields)

    Initialized by calling InitAsFieldBrush().

    Field brushes are same as brushes, just that they do not have any textures and are only rendered as green translucent objects. Level editors define its geometry only, they cannot texture them. Their geometry is then used to detect if some entity has entered the field. When that happens, the field entity receives an event, and it can react on it. They are rendered only in Serious Editor and only if 'Render Fields' flag is turned on for the particular view.

    5) Void entities (RT_VOID)

    Initialized by calling InitAsVoid().

    Voids are used when you need to create a parallel thread for some AI purposes. They are nevered rendered, they do not collide, they cannot move, cannot emit light, cannot make sound etc. They are made such to reduce the performance impact on the rendering and physics algorithms, but to still be present in the world.

    Built in Base Entity Classes

    1) CEntity

    The base class of the entire hierarchy of entity classes is CEntity. Simplest entities can be derived from that class, but they won't be able to move and execute any other AI procedures except the initialization procedure Main().

    Examples of such entities are lights and markers.

    2) CLiveEntity

    CLiveEntity derives from CEntity and extends with ability to be damaged. It tracks its own health and reports death event when the health reaches zero. Note that even the base class CEntity receives damage, by the ReceiveDamageFunction(), but its default behavior is to ignore it.

    3) CRationalEntity

    CRationalEntity derives from CLiveEntity and extends with ability execute AI procedures using its own state stack.

    4) CMovableEntity

    CMovableEntity derives from CRationalEntity and extends with a physics engine based on movement requests. IMPORTANT: You should never derive directly from this class. Use either CMovableModelEntity or CMovableBrushEntity.
    Entities derived from this class must have EPF_MOVABLE physics flag set in order to work properly. Then, you can call following functions to make it move:
      SetDesiredTranslation()
  SetDesiredRotation()
  GiveImpulseTranslationRelative()
  GiveImpulseTranslationAbsolute()
  LaunchAsPropelledProjectile()
  LaunchAsFreeProjectile()
  ForceStopTranslation()
  ForceStopRotation()
  ForceFullStop()
    To get useful information about the entity's direction (if you want to have 6DOF movement and variable gravity support) use:
      GetRelativeHeading()
  GetRelativePitch()
  GetReferenceHeadingDirection()
  GetHeadingDirection()
  GetPitchDirection()

    5) CMovableModelEntity

    CMovableModelEntity is a CMovableEntity of render type RT_MODEL. It has additional ability to change its collision box using following functions:
      GetCollisionBoxIndex()
  ChangeCollisionBoxIndexNow()
  ChangeCollisionBoxIndexWhenPossible()

    6) CMovableBrushEntity

    CMovableModelEntity is a CMovableEntity of render type RT_BRUSH.

    7) CPlayerEntity

    CPlayerEntity is a CMovableModelEntity used for players and spectators.

    You must override ApplyAction() and Disconnect() functions.

    ApplyAction() will be called each tick with a new action packet that the entity should apply to its movement.

    Disconnect() will be called just for notification that the client was disconnected. The entity should die and/or destroy itself.

    Entity Destruction and Reference Counting

    Entities are dynamic inside a world and they can be constructed and deleted on the fly, both in the SeriousEditor and in the game. Since other entities and various structures inside the engine and the game can have pointers to an entity, it would be unsafe to just delete it at any time. To prevent invalid address accesses, a reference counting scheme is used in the entity management.

    Each entity has an internal counter which counts the number of times it is referenced by a pointer. Normally, the counter is at least equal to one. This means that the entity is referenced by the world's container of existing entities. It shows the entity's intent to exist. As other entities or some code in engine and/or game make pointers to it, the counter can increase and decrease.

    When the entity wants to cease existing, it calls its Destroy() function. It is then marked as deleted (ENF_DELETED), as much memory as possible is freed (deleting its model object, brush, etc.), its properties are adjusted so that it is neither rendered nor interacting physically, and its counter is decremented by one. This way it uses as little resources as possible, while it still exists in memory in case that there are pointers to it.

    If the entity's reference count reaches zero, the entity is really deleted.

    Usual scenarios are like a missile having a pointer to its owner and the owner gets deleted while the missle still flies, and is trying to send some event to the owner or similar. The owner stays in memory while the missile lives. Or if a monster has a pointer to the player it is attacking, and some other monster kills the player. The player never really is removed since there is a pointer to it. Such situation is resolved by the fact that on Destroy(), ENF_ALIVE is also cleared, so the monster will cease attacking the player, since he/she is already dead. As the monster deduces that the player is dead, and sets its pointer to null, the player can be released from its zombie state and freed from memory.

    To prevent circular references, Destroy() function clears all eventual pointers to other entities.

    The reference counting uses a special class CEntityPointer (4 bytes in size, just the pointer itself), which implements the standard reference counting algorithms. You must make sure you do not keep any non-temporary ordinary pointers to entities (CEntity *), since they do not take care of reference counts. You do not have to worry much about that, since Ecc will not allow you to declare any CEntity* member variables, only CEntityPointer are allowed.

    Entity Flags

    Some entity settings and physics and collision behavior is primarily defined with three sets of flags: base entity flags (just flags), physics flags and collision flags. They are all defined in "Engine/Entities/Entity.h".

    The flags can be accessed and modified using SetFlags(), GetFlags(), SetPhysicsFlags(), GetPhysicsFlags(), SetCollisionFlags() and GetCollisionFlags().

    1) Base flags define various properties. Some of them are used by the engine internally, while others can be set to impose a specific property.

    Following flags are meaningful for changing:

    - ENF_ZONING
    Set this for brushes which should define worlds spatial classification by sectors. Those are the base of the architecture, as opposed to moving brushes (doors and similar) and detail brushes (like columns etc.) which you do not want to be zoning.

    - ENF_DELETED
    Engine sets this for entities that were destroyed, but are still kept in memory while someone holds a pointer to them.

    - ENF_ALIVE
    Set if the entity is currently a living being.

    - ENF_SEETHROUGH
    Physical ray-casts will pass through this object.

    - ENF_CLUSTERSHADOWS
    Set this for models that you want to cast shadows on shadow maps, instead dynamic shadows. Used for immovable models like statues and light-holders.

    - ENF_BACKGROUND
    A brush or model marked this way will be rendered on background, using the background viewer entity as a viewer.

    - ENF_ANCHORED
    Entity marked this way cannot be moved in editor without special allowance from the user (clicking a toolbar button). This is used to prevent editors from accidentially moving entire buildings around.

    - ENF_HASPARTICLES
    Set for a model entity if it should render particles.

    - ENF_INVISIBLE
    The entity is marked as invisible for AI purposes. It is entirely up to the custom ES code to take care about that. Does not influence rendering at all.

    - ENF_DYNAMICSHADOWS
    A moving brush that causes automatic shadow recalculation as it moves. This one can be slow on large worlds, use with care.

    - ENF_NOTIFYLEVELCHANGE
    If this set, the entity is notified when level is changed.

    - ENF_CROSSESLEVELS
    If this is set, the entity must be carried to the new level when level is changed.

    2) Collision flags define which other entities this one will collide with. The collision flags are divided in three groups: 'is', 'test' and 'pass'. Each group has identical layout of 10 bits each completely customizable by the programmer. Engine does not assign any particular meaning to any of the bits inside the group. When two entities (A and B) might collide, the following algorithm (in pseudo code) is applied:
    if (!(isA&testB) || !(isB&testA))
  do not test at all
else
  if ((isA&passB) || (isB&passA))
    test and report if passed one through another
  else
    test and apply collision response
    By proper assignment of is, test and pass flags, you can adjust which entities collide which, and which pass through.

    Usual combinations are that magical projectiles can pass through one another, and the players and creatures can pass through items etc. Magical projectiles can pass through physical projectiles, while physical projectiles cannot pass through one another etc.

    3) Physics flags define collision response and general physical properties of the entity. This includes how entity is infuenced by gravity (rotated and/or translated), how it reacts if its movement is blocked and how the entity breathes.

    Here is a snippet from the header file:

    Following flags are meaningful for changing:

    - EPF_ORIENTEDBYGRAVITY
    If set, the entity always turns to be feet-down.

    - EPF_TRANSLATEDBYGRAVITY
    Without this flag, entity levitates/flies.

    - EPF_PUSHABLE
    If this is not set, the entity cannot be pushed by brushes.

    - EPF_STICKYFEET
    Sticky feet entities always fall to the nearest polygons. They can walk on the walls like spiders.

    - EPF_RT_SYNCHRONIZED
    Set if rotation and translation are synchronized. Used for moving brushes which must not be allowed to continue turning if they cannot translate when blocked.

    - EPF_ABSOLUTETRANSLATE
    Set if entity is translated absolute and not relative to its position. Use for moving brushes.

    - EPF_NOACCELERATION
    Set if entity can change its speed immediately. Used for moving brushes.

    - EPF_HASLUNGS and EPF_HASGILLS
    Defines entity's way of breathing. Entity that has both lungs and gills will be amphibious, but can still choke in vacuum. Note that an entity which has neither is considered unaerobes, and can newer choke/drown.

    - EPF_MOVABLE
    Must set this if derived from CMovableEntity.

    - EPF_NOIMPACT
    Entities are not damaged when hitting this one.

    - EPF_CANFADESPINNING
    Desired rotation can be reduced by sector contents (like water).

    Flags in the EPF_ONBLOCK_MASK decide the collision response:
    - EPF_ONBLOCK_STOP            stop moving
- EPF_ONBLOCK_SLIDE           slide along wall
- EPF_ONBLOCK_CLIMBORSLIDE    clim up a stair or slide along
- EPF_ONBLOCK_BOUNCE          bounce off
- EPF_ONBLOCK_PUSH            push the obstacle

    Managing Entity's Placement

    Each entity (even the voids) have its placement in the world. The placement defines its position and orientation. The placement is primarily kept as a CPlacement3D (consisting of a FLOAT3D for position and an ANGLE3D - a set of Euler angles - for orientation). A copy of the orientation is also kept as a rotation matrix. The placement also influences the entity's linking in the spatial classification structures in the world.

    The spatial classification must not be corrupted, or the engine might malfunction. Therefore, you must never change the placement manually. Use SetPlacement(), GetPlacement() and GetRotationMatrix() to access the placement data. To teleport entity from one place to another use Teleport() instead of SetPlacement().

    The GetLerpedPlacement() function is used by the engine's rendered to calculate placement of an entity in-between two ticks. That is for an effect called lerping (from LERP=Linear intERPolation), and is used to smooth out annoying visual effects of unstable frame rate and inconsistency between physics/AI ticks and rendering frame rate. It is already implemented in CMovableEntity, but you can override it if you provide your own movement code.

    Damaging Entities

    An entity can inflict damage to another entity by calling InflictDirectDamage(). Be sure to provide all the needed parameters. If you do not supply the hit point and direction it won't interfere with the engines capability of tracking the entity's health, but the other entity's AI won't have exact info.

    InflictDirectDamage() inflicts damage to all entities within given range.

    Here are some damage types declared in the MovableEntity.es:
    DMT_EXPLOSION
DMT_PROJECTILE
DMT_CLOSERANGE
DMT_BULLET
DMT_DROWNING
DMT_IMPACT
DMT_BRUSH
DMT_BURNING
DMT_ACID
DMT_TELEPORT
DMT_FREEZING
    You can add you own enums as you like above the value of 100.

    Entity Initialization

    One of the most important facts you have to keep in mind is that the code of an entity is not executed only when the game is running. It is also executed in the SeriousEditor, when the entity is initialized or changed.

    SeriousEditor is based on the principle of 'frozen time'. While a level editor is working on a world in SeriousEditor, the world is frozen in the moment of zero-time. A '.wld' file can in fact be thought about as a save game at the zero-time, with no players added. The process of game starting involves loading that save-game to the server and adding players to it.

    When a new entity is added to the world, it is initialized in the following way:

    1) The entity is constructed and added to the world's container of entities.
    2) The entity's Main() procedure is called.
    3) Main() procedure initializes the entity's appearance and settings and continues running the AI. After this point, the Main() will usually return, or will try to start behaving.
    4a) If it returns (for simple non-rational entities, like lights), it will never continue to execute any procedures, and will only execute overriden virtual functions.
    4b) If it starts behaving (for rational entities, like enemies), it must ultimately, at some point, wait for some time interval, or for the next event. When it does so, it is put on a waiting queue. Since the time is frozen, that's it. It will continue executing only after the game starts.
    5) After the Main() returns, or waits, the engine initializes other parameters, like spatial classification and collision, and precaches its components.

    At the initialization, the entity usually sets its model, textures, description, etc. to reflect its properties, which are initially set to defaults.

    When any of the properties is changed, the entity is reinitialized. The process of reinitialization goes as follows:

    1) The entity is ended (but not destructed!). That means that its cached data like spatial classification, collision etc., is flushed, and its model object, if any, is deleted.
    2) The property (or properties) is/are changed.
    3) The entity is initialized again, as described above, just that it doesn't need to be constructed again, since it already exists.

    Entity Events

    Entity AI in SeriousEngine is based on states and events.

    Events are sent to entities by the engine e.g. when two entities touch, when an entity is damaged, when levels are changed, at certain moments in time programmed by the entities themselves, etc. Also entities can send events to each other at will.

    An event is a class derived from base class CEntityEvent. It contains the event code and additional event data. Event code describes the type of event and is must have unique value for each event type. Event data is stored in the class and is different for each event type.

    For example, ETouch, the event sent to an entity when it touches another entity, has its unique code EVENTCODE_ETouch with value 0x00010004. The value is derived from the number of the entity source file where the event is declared (CMovableEntity - number 1), and the number of the event in the file (4). The data that ETouch holds is a pointer to the touched entity, a flag telling which of the two entities moved when the collision occured, and a plane of collision.

    You do not need to care about the interns of an event type. You just declare it similarly to any other structure in an .es file, and the Ecc generates the code and supporting functions. More about it in EntitySyntax.

    Each entity has ability to receive events using SendEvent() function. When SendEvent() is called for an entity, the event is stored in a global event queue together with a reference to the entity which is to receive it. The stored events are handled in the FIFO order.

    The most primitive way an entity can handle events is using its HandleEvent() function. It can test the event type to see if it is interested in the event and then cast it to the proper event class to examine its data. This is use, for example, by CLight in SeriousSam which handle some specific events in a simple way by changing their color, but they never perform any complicated AI or behavior.

    If an entity is supposed to have a complicated behavior, it executes the behavior via procedures.

    Entity Functions and Procedures

    Each entity class has both functions and procedures.

    The differences between procedures and functions is following:

    1) Stack they are running on

    Functions execute on the ordinary call stack of the main application thread.

    Procedures, on the other hand, execute on the state stack of the entity they were called for. Each entity derived from CRationalEntity has its own state stack.

    2) Parallelism

    Functions always have to return, so that the engine can continue working.

    State stacks enable virtual parallelism of procedures, so the procedures do not have to return. When a procedure waits for a timer or for an event, it is just stored on the top of the state stack for that entity, and the engine continues to run.

    3) Syntax constructs

    Functions are ordinary C++ functions and can be either overrides of virtual functions from base entity classes declared in the engine, or can be written independently by the entity programmer for some custom uses. Virtual overriding is used to provide some facilities like custom rendering, custom physics, interaction with the SeriousEditor etc. Custom used functions can be used as usual in C++, for code simplification, communication between different entity classes etc.

    Procedures are similar to C++ functions, and can contain most of the C++ constructs, plus they can contain .es specific AI-related syntax constructs. Those include waiting for timer and/or event, specific event handling and routing, calling or jumping to other procedures etc.

    Entity State Stack

    State stack is kept separately for each entity derived from CRationalEntity. It is just a stack of integers, each integer representing one state.

    Entities derived from CRationalEntity can execute procedures, wait for time delays, and react on events using their hierarchy of states on stack. In fact, each state on the state stack represents one procedure on the call stack of procedures.

    When Ecc compiles procedures, it divides each of them in parts, along the lines of specific waiting constructs. Each such part is one state.

    For example, take a look at this simple procedure:
    // run for two seconds
Run()
{
  // start running animation
  GetModelObject()->PlayAnim(ANIM_RUN, AOF_LOOPING);
  // wait a bit
  autowait(2.0f)
  // stop running animation
  GetModelObject()->PlayAnim(ANIM_STAND, 0);

  return;
}
    It is divided in three parts, one before the autowait, one is the wait intself, one is the part after the autowait. Each state has its integer code, automatically assigned by the Ecc, and that state code represents that part of the procedure on the stack.

    When the procedure is executed, initially, the first state is on the top of stack. That state is simple, it just starts the animation, and proceeds to the second state.

    The first state which was on the top of stack, is now replaced with the second state. Since this state waits, the timer is set and this entity runs no more AI for now, it is placed on waiting.

    When the timer expires, an ETimer event is sent to the entity. The state at the top of the stack handles the event and skips over to the next state. Now the third state replaces it on the top of stack.

    The third state just sets new animation and returns from the procedure. On return, current state is popped off the stack, and the control is given to the procedure below (if any) that called this one. If there are no more states below on the stack, this entity has finished its AI, and will never run again (that doesn't usually happen, unless the entity destroys itself).

    The state stack provides calling and jumping facilities.

    If a procedure executes call() construct calling another procedure, the state code of that other procedure is pushed on the stack above the current one, and the new procedure takes the control. The caller procedure is in the call() event handler and can handle any events that the callee doesn't handle or explicitly ignore.

    If a procedure executes jump() construct jumping to another procedure, the state code of that other procedure replaces current procedure's state code on the stack. When (and if) the new procedure returns, it will return to the one below on the stack, which is the one that called the original procedure.

    If a procedure executes return, its state code on top of stack is popped off, and the procedure below (if any) will continue executing.

    Call, jump and return can carry over some event, which will be immediately handled by the target procedure, without beeing put on the event queue.

    If the calling procedure traps some event that the callee has not handled, it can decide that it wants to abort the call. Then the callee and its eventual deeper callees are cleaned off from the stack, and the caller continues running.

    This concept of stack machine with hierarchical event handling enables programmer to modularize an entity's AI in two axes: horizontally, for sequential execution and vertically for task abstraction. An example of such usage would be calling a procedure that will do something (e.g. just run around), and trapping any eventual events which might mean that you have to do something else (like damage event meaning you should attack the one that attacked you, etc.).

    More on that in EntitySyntax.

    Entity Class Properties

    To simplify loading, saving and editing of entities, SeriousEngine uses a concept of properties. Entity properties are member variables which have additional support for editing in SeriousEditor, automatic loading/saving and copying etc.

    You just declare each property with its type, identifier, name, default value etc in the .es file. The engine then handles the serialization tasks, and editing works automatically.

    In SeriousEditor, level editor can see those properties that you declare as visible, and sees them by their names. You can also add keyboard shortcuts to the properties. The properties are edited according to their type. For example, COLOR properties are edited with color edit controls with HSV and RGB sliders, CEntityPointer properties can be edited by pointing to the target entity, RANGE properties are visible as spheres in space which can be stretched in 3D etc.

    Entity Class Components and Precaching

    Each entity class can also contain components like models, textures, sounds and other classes. The fact that a class has a component means that when some entity of that class is loaded, the component should be loaded also, since the entity might need it. Each class holds only one pointer to the cached component to speed up and simplify the loading.

    The exact caching method can be controlled with console variable 'gam_iPrecachePolicy' which can be set to following values:

    - precache_NONE - do not precache components until needed. Makes slowdowns in game.

    - precache_ALL - precache all components of all classes in the world when the game starts. If some classes have much more components then they use, this may lead to unneeded memory consumption. E.g. all beheaded soldiers are one class in Serious Sam, but each of the has their own components. Even if only one is present on a world, all components will be loaded.

    - precache_SMART - let each entity tell which components it wants. This is done by overriding Precache() virtual function. In the Precache(), an entity should examine its properties and call following functions to precache the components it will need:
      PrecacheModel()
  PrecacheTexture()
  PrecacheSound()
  PrecacheClass()
    - precache_PARANOIA - same as precache_ALL, but if some component cannot be loaded, an error is reported.


Entity Source (ES) Syntax

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Basics of ES Programming
    Required knowledge:
  • C++ programming
    Explains:
  • Detailed explanation of the '.es' syntax and functionality.

    A Bit About the Ecc

    Entity Class Compiler (Ecc) is a translator (a compiler-like program) which compiles '.es' with the code you write into '.cpp' sources that are later compiled by ordinary C++ compiler to generate binary code.

    It does not do a full C++ syntactic and semantic check on the source. It first performs lexical analysis, breaking it into tokens. The parts of the declaration and implementation that are specific to the '.es' syntax, like events, properties, components and procedures, are analyzed syntactically and semantically and translated to C++ code and declarations. The parts that are purely C++, like function calls, pure C++ loops without waiting, expresions etc., are only checked in global, for matching brackets and similar, and copied verbatim.

    Ecc reports its errors in a format that is compatibile with VisualC++ (and should be compatibile with most ANSI compilers) so that Developer Studio can automatically show the line with the error just as it does with the C++ compiler.

    It also generates #line directives. That way, when the code you write is syntactically and semantically correct with respect to the .es grammar, but cannot be compiled with C++ compiler (for example, mismatched types or operators in an expression, undeclared variable, etc.), the C++ compiler reports the error inside the .es file instead inside the generated C++ file. Also, when you debug the compiled code, the original .es file is shown.

    General Format of Entity Source File

    Each entity source file has following elements:

    1) the class's unique identifier

    First thing in the file must be an integer in the range 1-32767, the identifier of the class. It is used in the generation of identifiers for events, properties, components and states declared in the class. If you make two classes with same identifier, they will work, but might have conficts if you try to derive one from another, or use one another's events etc. The numbers below 100 are reserved by the engine. For the SeriousSam, numbers between 100 and 999 are always used by the Serious Sam entities, while custom MODs can use the numbers above 1000. For come other application, the way of assigning numbers above 100 can be different.

    2) an optional C++ block

    Here, you can optionally insert a block of completely free C++ declarations/statements/preprocessor directives. The block must be bracketed with '%{' and '%}'. You will usually have to put your #includes and #defines here, and you can also add some module or global functions and variables. The part inside the block is always copied verbatim. You can write any C++ code there.
    Example:

%{
#include "StdH.h"
#include
#include
%}

    3) 'uses' list

    Like you #include header files at the start of each C++ file, here you declare that your class will use some other classes or their enums or events. The format of each 'uses' statement is:
    uses_statement : 'uses' string ';'
    The string is the filename of the class's .es file, without the extension.

    If you use the class only in implementation, you don't need to add the 'uses' statement for it. You can just add its generated header file to the #includes in the above C++ block. That can speed up your compilation time. 'Uses' adjusts the generated header so that each other class that references this includes its header file. It is needed if, for example, one of this class's properties is an enum declared in the other class.
    Example:

uses "Entities/EnvironmentMarker";
uses "Entities/WatchPlayers";

    4) 'enum' and 'event' declarations list

    Here, you declare enums and events for this class. The order is arbitrary, and you can mix enums and events any way you like.

    Each event is declared like this:
    event_declaration : 'event' identifier '{' event_members_list '}' ';'
    where the identifier is the name of the event type, like ETimer, EDamage, or EStartRunningAway, etc.

    Event members are separated with a comma ',' and each event can have zero or more members in format:
    event_member : any_type identifier

    Examples:

event ETimer {        // timer elapsed
};
event ETouch {
  CEntityPointer penOther,    // other entity
  BOOL bThisMoved,           // if this entity has touched other entity
  FLOATplane3D   plCollision, // plane of collision
};
    Each enum is declared very similary to C++ enums, but with the change that each value has its name:
    enum_declaration : 'enum' identifier '{' enum_values_list '}' ';'
    Enum values are separated with a comma ',' and have following format:
    enum_value : int identifier string
    The integer is the value of the identifier, and the string is its name as seen by level editor in SeriousEditor.
    Example:

enum DamageType {
   1 DMT_EXPLOSION  "Explosion",    // caused by dynamites, rockets and other ordinary explosives
   2 DMT_PROJECTILE "Projectile",   // caused by projectile (non exploding)
   3 DMT_CLOSERANGE "Close range",  // caused by close range weapon (chainsaw, head-saw, ...)
};

    5) an optional C++ block

    Another block same as the one before, just that this one can freely use the above declared events and enums. It is recommended that you use this one for everything else except #includes.

    6) class declaration

    The last part, and usually largest part of the source is the class declaration itself. The syntax layout of the class declaration is the following:
    class_declaration :
(1)  'class' identifier ':' identifier '{'
(2)  'name' string ';'
(3)  'thumbnail' string ';'
(4)  ('features' features_list ';' )opt
(5)  'properties' ':' property_declaration_list
(6)  ('{' internal_properties '}')opt
(7)  'components' ':' component_declaration_list
(8)  'functions' ':' function_list
(9)  'procedures' ':' procedure_list
     '}' ';'
  • (1) declares the C++ identifier for the class and its base class.
  • (2) declares the name that the class is shown by in the SeriousEditor.
  • (3) declares the thumbnail file for showing the class in the VirtualTree. The thumbnail is just a texture file, usually renamed to a '.tbn' extension.
  • (4) is an optional list of features to be auto-implemented by Ecc.
  • (5) declares properties for the class.
  • (6) declares internal properties for the class.
  • (7) declares the class's components (models, textures, sounds and other classes).
  • In (8) class member functions are declared and implemented.
  • In (9) class procedures are declared and implemented.

    Class Features

    Some special features can be implemented by Ecc without the need for you to write code for it. It usually means that Ecc will automatically add some functions, or variables or adjust some class settings.

    Features declaration consists of the 'features' keyword followed by a comma separated list of strings. Each string can be one from the following list:

    - AbstractBaseClass - means that the class will be only a base class for deriving other classes from it. It can never be instantiated.
  • - IsTargetable - makes entities of this class targetable. That means that they will appear on the list of possible targets when changing an CEntityPointer property in the SeriousEditor.

    - HasName - implies that the class has a string property named 'm_strName' which is shown as the name of the entity in SeriousEngine. You must declare the property manually.

    - HasDescription - implies that the class has a string property named 'm_strDescription' which is shown as the description of the entity in SeriousEngine. You must declare the property manually.

    - HasTarget - implies that the class has a CEntityPointer property named 'm_penTarget' which is the default entity pointer property considered if no other is selected. You must declare the property manually.

    - ImplementsOnInitClass
    ImplementsOnEndClass
    ImplementsOnPrecache
    ImplementsOnWorldInit
    ImplementsOnWorldEnd
    ImplementsOnWorldTick
    ImplementsOnWorldRender
    - these declare the fact that the class has one of the OnXXX functions implemented in its C++ block.

    Class Properties

    Entity properties are member variables which have additional support for editing in SeriousEditor, automatic loading/saving and copying etc. They are declared in a comma-separated list, each property with this syntax:
    property_declaration :
 integer property_type identifier (string (char)opt ('COLOR' '(' color ')') opt )opt ('=' expression)opt
    The integer is the property identifier. Each property within one class must have one unique identifier in the range 0-255. These identifiers are used for saving and loading. You should never change the number given to each property. You may rename the property's symbolic name in code, or change its name for SeriousEditor, but if you change the number, the value of that properties in all saved worlds will be lost.

    After the property number follows the property type, same as it would be in C++. Following types are supported so far:

    enums - any enum declared in this .es file, or those included with 'uses' statements
    CTString - a string
    CTStringTrans - a string that will be translated during localization
    CTFileName - a filename - automatically generates a dependency
    CTFileNameNoDep - a filename that does not generate a dependency
    BOOL - simple boolean
    COLOR - edited using color editing control in SeriousEditor
    FLOAT - float typed in edit box
    INDEX - integer typed in edit box
    RANGE - same as float, but can be visually edited as range in SeriousEditor
    CEntityPointer - pointer to some other entity
    CModelObject - a model object
    CAnimObject - an anim object
    CSoundObject - a sound channel for playing sounds
    CPlacement3D - placement (cannot be edited)
    FLOATaabbox3D - axis aligned bounding box
    FLOATquat3D - a quaternion (cannot be edited)
    ANGLE - same as float
    ANGLE3D - 3 angles, can also be edited as a direction vector
    FLOAT3D - 3 floats
    FLOATplane3D - a plane - cannot be edited
    ILLUMINATIONTYPE - same as index, edited with illumination drop-down
    ANIMATION - same as index, edited with animation drop-down

    After the type there is property identifier, same as in C++ declaration.

    Optional name of the property follows. This name is used to represent the property in SeriousEditor. If the property does not have a name, or if the name is an empty string, the property will not show in editor. If there is a name, you may add a shorcut key (one single-quoted character).

    CEntityPointer properties may also have a color assigned. The color is then used to render arrows showing the pointers.

    Finally, each property has a default value. Each property must have a default value. Some property types (like CEntityPointer, CSoundObject, CAnimObject, etc.) cannot have default values assigned by the user, but they have implicit defaults that are always same. E.g. CEntityPointer properties are always NULL by default.

    Examples:

  2 CEntityPointer m_penTarget  "Target" 'T' COLOR(C_dGREEN|0xFF),
  1 CTString m_strName          "Name" 'N' = "Marker",
 15 CTString m_strDescription = "",

    Internal Class Properties

    At the end of the property block, you may insert internal properties. You do so by bracketing them with '{' and '}'. Internal properties are just like a C++ block. They are not handled by the engine, but rather represent member variables that the class will take care of itself. Do not use these unless you are absolutely sure what you are doing.

    If you use internal properties, you must be sure that they do not need loading and saving, or you must do it yourself by overriding Read_t() and Write_t() functions.

    Internal properties are not visible or editable in SeriousEditor.
    Examples:

{
  // these are not saved via the property system

  CPlacement3D en_plLastPlacement;
  CListNode en_lnInMovers;
  CBrushPolygon *en_pbpoStandOn;
}

    Class Components

    Class components are declared in a comma separated list after the 'components' keyword. Each component has this syntax:
    component_declaration : integer component_type identifier string
    The integer is an ID in the range 0-255. These, you can renumber any way you like, the numbers are never saved/loaded, they are just for some internal reference.

    The component type can be: 'model' for a model (.mdl) file, 'texture' for a texture file (.tex), 'sound' for a sample (.wav or .mp3), or 'class' for another class (.ecl).
    Examples:

  1 model   MDL_ROCKET_EXPLOSION      "Models\\Effects\\ExplosionRocket\\ExplosionRocket.mdl",
  3 texture TXT_ROCKET_EXPLOSION      "Models\\Effects\\Explosionrocket\\Texture.tex",
 10 sound   SOUND_EXPLOSION           "Sounds\\Weapons\\_Explosion02.wav",
  5 class   CLASS_BASIC_EFFECT        "Classes\\BasicEffect.ecl",

    Class Functions

    Functions are just ordinary C++ functions with some minor limitations on declaration (they cannot be declared as pure virtual, they cannot be var-args etc.).

    The syntax is following:
    function_implementation :
  ('export')opt ('virtual')opt return_type ('~')opt identifier '(' parameters_list ')' ('const')opt
  '{' statements '}'
  (';')opt
    You can see that this is similar to C++ function declarations. Only extension is the 'export' keyword which declares that the function will be exported from the package DLL.

    Note that there is no separation between declaration and the implementation. Ecc generates the header file for you, so you do not need to take care of forward references.

    Class Procedures

    Procedures are similar to the functions in appearance, but are functionally completely different. See EntitiesBasics for the explanation of procedures and state stack.

    The syntax of one procedure is following:
    procedure_implementation :
  identifier '(' event_specification ')' (':' identifier '::' identifier)opt
  '{' statements '}' (';')opt
    The declaration line is quite different from the one used for functions. First, there is no return tyep. The procedures can return only events, and they can return events of any type.

    The only input parameter specified to a procedure is event. The event specification can be empty, with type only, or with type and variable name. If there is no type, the type of event is assumed to be EVoid. If there is no variable name, it means that the event must be of given type, but that you don't care about its contents. Whether the actual type of event passed when calling the procedure matches the one in the declaration, it is checked on run-time, not on compile time. It the types are not same, an ASSERT will fail.

    After input parameters, you may put an optional override. Procedure overriding is an advanced feature explained in more detail in EntitiesAdvanced.

    The body of a procedure is similar to the body of a function. Usual C++ constructs like 'if' statements and 'while' loops are supported. Additional syntactical constructs for waiting, calling, jumping etc. are added. These two can be intermixed with only a few limitations.

    Procedures that do not have .es specific constructs behave same as functions, just that they have a slightly greater call-overhead, and cannot be called as normal functions.

    IMPORTANT: Waiting constructs cannot be nested within one another (altough the can be nested in ordinary C++ constructs and vice versa). Also, if you can nest a 'wait' inside a loop, but not inside a two-level (or more) deep loops.
    IMPORTANT: You may not use one-statement blocks without brackets.
    Example:
Bad:  if (a>b) CPrintF(""a>b);
Good: if (a>b) { CPrintF(""a>b); }

    Conditional Statements and Loops

    'If' and 'if-else' statements can be used just as in C++, and waiting constructs can be put inside them. If you do a chained 'if-else-if' construct, you cannot end it with an else. Use "} else if (TRUE) {" instead of just "} else {". This is a limitation of the Ecc parser.

    'While' and 'do-while' can have waiting constructs within them, but only to level one. 'For' loop cannot have a wait construct inside it.

    Waiting Constructs

    The foundation of the functionality of a class procedure is the 'wait' construct.

    Its syntax is following:
    statement_wait
  : 'wait' '(' (expression)opt ')' '{' handlers_list '}'
    If the expression is not present, the procedure will wait forever, and only trap events. If there is an expression, it must be of the 'float' type (or convertible), and represents the number of seconds to wait. After the timer elapses, an ETimer event is sent to the entity, and one of the handlers should capture it and stop waiting.

    When the waiting initally begins, an EBegin event is sent to the entity. You can do initialization or something similar here. It is usually used for 'call' statements. You can later simulate a restart of the wait by sending the EBegin yourself.

    IMPORTANT: You should always handle EBegin event if only just to ignore it. Otherwise, it might be cached by some of the callers of this procedure!

    Each handler is of the following format:
    (1) 'on' '(' event_specification ')' ':' '{' statements '}' (';')opt
or
(2) 'otherwise' '(' (event_specification)opt ')' ':' '{' statements '}' (';')opt
    Event specification can contain the event type and the event variable, or only the event type. If the variable is not present, it is assumed that you are not interested in the contents of the event data.

    (1) If the event of given type is received during the wait, the statements of the handler are executed. The statements must in the end do either 'call', 'jump', 'stop', 'resume', 'pass' or 'return'.

    (2) If none of the handlers before this one handles some event, it is passed to the 'otherwise' handler. This is similar to 'default' in C++ switch construct.

    Simplest ways to end an event handler are 'stop', 'resume', or 'pass':

    1) 'stop' means that the waiting stops and the part of the procedure after the wait construct continues to execute.
    2) 'resume' means that the event has been handled and that the waiting continues on.
    3) 'pass' means that you do not want to handle the event, and it will be passed to the next procedure on the call stack (its state is below this one on the state stack).
    Example:
// wait for some time
wait(GetWaitingTime()+1.0f) {
  on (EBegin) : {
    resume;
  }
  // when damaged
  on (EDamage eDamage) : {
    // if only minor damage
    if (eDamage.fAmount<10) {
      // ignore
      resume;
    // if serious damage
    } else {
      // let higher level procedure handle it
      pass;
    }
  }
  // when time expires
  on (ETimer) {
    // stop waiting
    stop;
  }
}
    More advanced ways to end an event handler are 'call', 'jump' and 'return';

    1) 'call' means that you want to call another procedure (i.e. push its state above this one on the state stack), and the called procedure will continue executing, while this wait can still capture the events which the called procedure misses.

    Syntax of a 'call' is this:
    'call' jumptarget '(' event_expression ')' ';'
    The jumptarget is the name of the called procedure (can be in class::procedure format if overriding is used). Event_expression is the event that will be sent to the called procedure.

    2) 'jump' means that you want to jump to another procedure (i.e. make its state replace this one on the state stack). The new procedure continues executing instead this one, and will never return here. All the other procedures below on the stack still remain, and when the new one returns, it will return to the one that called this one.

    Syntax of a 'jump' is this:
    'jump' jumptarget '(' event_expression ')' ';'
    3) 'return' means that you want to return to the procedure below this one on the state stack.

    Syntax of a 'return' is this:
    'return' (event_expression)opt ';'
    The event_expression gives the event that the procedure returned to will execute immediately. If no event is given, EVoid event is sent.

    IMPORTANT: While 'jump' and 'return' can be used anywhere inside a procedure, 'call', 'stop', 'resume', and 'pass' can be used only in event handlers.
    Example:

// wait forever
wait() {
  // initially
  on (EBegin) : {
    // run around
    EStartRunning eStartRunning;
    eStartRunning.vDestination = m_vTarget;
    call RunAround(eStartRunning);
  }
  // when damaged
  on (EDamage eDamage) : {
    // switch to fighting
    jump Fight();
  }
  // when touched
  on (ETouch) {
    // abort running and return to caller
    return EStop();
  }
}

    Automatized Waiting

    The 'wait' construct offers complete control over event handling, but most usually, you will want only to do three different things: either just wait for a specified amount of time, just wait for a specified event, or call another procedure and wait until it returns. To simplify those tasks, there are specific statements: 'autowait', 'waitevent' and 'autocall'.

    1) syntax of the autowait is:
    'autowait' '(' (expression)opt ')' ';'
    If the expression is not given, the wait will be forever, if it is given it will be for the specified ammount of time.
    autowait(someexpression);
    is same as:
    wait(someexpression) {
  on (EBegin) { resume; };
  on (ETimer) { stop; };
}

Example:

/* This just waits for 5 seconds. Any events occuring in that interval will
be passed to procedures below on the stack. */
autowait(5.0f);
    2) syntax of the waitevent is:
    'waitevent' '(' ')' identifier (identifier)opt ';'
    The identifier after the parentheses defines event type that will break the wait. Optional second identifier defines the variable where the event will be stored. If you are not interested in the event data, you don't have to give a variable name.
    waitevent () ETouch eTouch;
somecode...
    is similar to:
    wait() {
  on(EBegin) : { resume; }
  on(ETouch eTouch) {
    somecode...
    stop;
  }
};
    3) syntax of autocall is:
    'autocall' jumptarget '(' event_expression ')' identifier opt_eventvar ';'
    The jumptarget is the name of the called procedure (can be in class::procedure format if overriding is used). Event_expression is the event that will be sent to the called procedure.

    The identifier after the parentheses defines event type that will break the wait. This is usually the one that is returned from the called procedure. Optional second identifier defines the variable where the event will be stored. If you are not interested in the event data, you don't have to give the variable name.
    autocall StartRunning(EStart()) ETouch eTouch;
somecode...
    is similar to:
    wait() {
  on(EBegin) : {
    call StartRunning(EStart());
  }
  on(ETouch eTouch) {
    somecode...
    stop;
  }
};


Advanced Tips on ES Programming

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • Basics of ES Programming
  • Entity Source (ES) Syntax
    Required knowledge:
  • C++ programming
    Explains:
  • Basic facts about entity classes in Serious Engine.

    Pitfalls of Euler Angles

    Eulers are good because they are simple, small and easy to represent for user interface.

    If you do not intend to have any support for multiple gravities, you can just as well use them in your AI. Usually, you will change just the heading of an object, or adjust pitch when shooting and similar.

    If you want to have your entities behave properly in a gravity field other than default gravity, you must never use entity's orientation in euler angles (pl_OrientationAngle part of its placement). You should only refer to its matrix. You will set its desired rotation in relative coordinate system. To get some useful information about orientation use these functions (implemented in CMovableEntity):
      GetRelativeHeading()
  GetRelativePitch()
  GetReferenceHeadingDirection()
  GetHeadingDirection()
  GetPitchDirection()

    Entity Procedure Overriding

    In the EntitySyntax, in the part about procedure declaration, overriding possibility is mentioned. Procedures cannot be overloaded, but they have a system similar to C++ virtual function overriding. Sometimes you have a procedure that you call in a base class and want to be able to replace it for certain derived classes to behave differently. In that case, you can use overriding.

    When you override a procedure from a base class, if any other procedure calls it (or jumps to it), the overriding procedure will be called (jumped to) instead.

    The syntax is described briefly in Entity Source (ES) Syntax like this:
    procedure_implementation :
  identifier '(' event_specification ')' (':' identifier '::' identifier)opt
  '{' statements '}' (';')opt
    The optional part after the input event specification is the override. The first identifier is the class you override from and the second is the procedure name that you want to override. E.g. ": CEnemyBase::StartAttack" means that this procedure overrides the procedure StartAttack from the CEnemyBase class.

    Overridden and overriding procedures do not need to have same names, and, on the other hand, giving them same names will not be considered overriding if the overriding specification is not present.

    IMPORTANT: When you override some procedure, both procedures get same state numbers, and there is no way to call the base procedure from any entity of this class, or derived classes. So, when you plan to use overriding, you usually make a dummy procedure that just jumps to the one that does the job. Then you override the dummy procedure. This way you can always call (jump to) the one that does the job if you want to.

    Demo Consistency and Network Synchronization

    NOTE: If you are not deeply familiar with the networking and demo saving/replay systems in games, perhaps you are not aware of the fact that those things are usually just two variants of the same technique. Demo replay is usually just a little extension to the networking system enabling saving the data that would be sent to another computer in a network game to be saved to disk instead, and later loaded and replayed as if connected to a network game. When demo saving is initiated, the network system (which always runs, even in a single player game it runs in a local-loop mode) saves the data identical to that sent to a new client connecting to a server. Then during the game, all packets that would be sent to the client are saved to the disk. Later, that same data can be loaded and played back as if you are connected to that saved game session.

    Current built-in networking system in Serious Engine, uses an action-based system, usual for peer-to-peer technologies, as opposed to current frame packets which would be used in a client-server system. This means that each computer keeps an entire copy of the session state and the server relays actions from all players to each computer. Each computer must do exactly same thing when it receives same actions.

    Exactly defined, current session state is a value of an integral function maintained at each computer. Each action packet is then a delta applied to that function. If all computers start with a session state and receive same actions, they should maintain same state.

    IMPORTANT: Note that for those assumptions to hold, applying same actions to same session state must yield same changes. This means that you have to take care you do not do any random actions in the entity code AI.

    The term random actions, however, does not exclude pseudo-random actions. You may use IRnd() and FRnd() functions in from CEntity class. They are safe because they use a custom pseudo-random number generator which relies on a seed stored in the session state.

    IMPORTANT: Never use ANSI C rand() function and its companion functions in entity AI, because they can create inconsistencies between session states on different computers and improper demo playback.

    You may only use rand() in parts that are not related to maintaning the session state, i.e in rendering only. E.g. you may use rand() in RenderGameView(), RenderParticles(), AdjustShadingParameters(), etc.

    One more thing needs to be kept in mind. Rendering is independent of the session state ticks. Tick always run at 20 Hz, while rendering speed (frame rate) can be different. I.e. more than one frame can be rendered between two ticks (using lerping), or more than one tick can be calculated between two frames (if frame rate drops below 20). Therefore, you must not change entity's state in the rendering functions, since it will interfere with session state consistency.

    This also implies that you must never use IRnd() and FRnd() in rendering. The engine will assert against doing this, so it is unlikely that you can oversee that problem.


How to Create a new Entity Package

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • None
    Required knowledge:
  • Using Visual C++ 6.0
    Explains:
  • How to create a new project for an entity package DLL.

    STEP 1: Creating New Project

    First, you need to make a new Developer Studio Project, to build a DLL where entity classes will be packaged. Create a new project of type 'Win32 Dynamic-Link Library' and name it 'Tutorial'. You can add it to an existing workspace or create a new workspace for it. It is up to you.

    IMPORTANT: Make sure that you put it in the Sources directory, since the include path points there.

    When the DLL wizard asks you what kind of DLL do you want, answer 'An empty DLL project'.

    STEP 2: Adjusting Global Settings

    Go to Project/Settings.

    under 'Debug' tab

    For 'Executable for debug session' type the path to SeriousEditor.exe in the Bin\ directory of the engine dir. For 'Win32 Release', use the release version of SeriousEditor.exe. For 'Win32 Debug', use the debug version of SeriousSam.exe located in the 'Bin\Debug\' directory.

    [lincencee programmers only]
    You must put debug version of the Serious Engine executables to Bin\Debug\ directory to be able to run in debug mode. The debug build is distributed separately from the original installation, since the artists and level editors do not need it.
    [/lincencee programmers only]

    [public programmers only]
    If you do not have the debug build of Serious Engine, you will not be able to run the debug version of your entities. In that case, you can manually turn off optimizations in the release version while you are debugging. That way, you should be able to debug it normally (viewing the variables, etc). You just won't have extra safety checks made by the engine, like assertions and similar.
    [/public programmers only]

    under 'C/C++' tab

    In 'Code Generation' category, for 'Use run-time library' select 'Debug Multithreaded DLL' for 'Win32 Debug', and 'Multithreaded DLL' for 'Win32 Release'. If all separate executables (entity packages, engine, game, editors, etc.) were linked to the static runtime library, loading several modules at the same time would consume too much memory. This way they all share one instance of the runtime DLL.

    under 'Link' tab

    In 'General' category, enable 'Generate debug info' and 'Generate map file', for 'All configurations'. This way, the debug info will be generated even in release version (it is stored separately from the executable, so it won't hinder it in any way and you will not distribute it). Also, map files allow you to later track crashes that might occur for your end-users or beta-testers using '.rpt' files that engine generates if the program crashes.

    Change 'Output file name' for 'Win32 Debug' fom 'Debug/Tutorial.dll' to 'Debug/TutorialD.dll'. We name all the debug versions of the DLLs with an additional 'D', so that no filename clashes will ever appear regarding the fact that the 'Bin\' directory is in the executable path.

    under 'Custom Build' tab

    For 'Win32 Debug', set:
'Description' to:
    Copying $(InputName) binaries to $(ENGINE_DIR)\Bin\Debug
'Commands' to:
    copy Debug\$(InputName).dll "$(ENGINE_DIR)\Bin\Debug" >nul
    copy Debug\$(InputName).map "$(ENGINE_DIR)\Bin\Debug" >nul
and 'Outputs' to:
    $(ENGINE_DIR)\Bin\Debug\$(InputName).dll

For 'Win32 Release', set:
'Description' to:
    Copying $(InputName) binaries to $(ENGINE_DIR)\Bin
'Commands' to:
    copy Release\$(InputName).dll "$(ENGINE_DIR)\Bin" >nul
    copy Release\$(InputName).map "$(ENGINE_DIR)\Bin" >nul
and 'Outputs' to:
    $(ENGINE_DIR)\Bin\$(InputName).dll
    This will copy the final '.dll' and its '.map' to the engine directory, after the dll was built.

    STEP 3: Adding Precompiled Header Support

    Serious Engine has a large number of header files, to gain on compiling speed and simplicity, all of the enigine headers are precompiled together in a single '.pch'. This enables you to just include one file ('StdH.h') in each entity source and you don't need to include any extra headers.

    The precompiled header sources should be located in a directory named 'StdH\' in the projects root directory. Create that directory manually using Windows Explorer or similar. Now create files 'StdH.cpp' and 'StdH.h' in that directory and add them to the project.

    'StdH.cpp' should contain only one line stating: '#include "StdH.h"'.

    For a start, 'StdH.h' should look like this:
    #include <Engine\Engine.h>
// include any global headers here
#define DECL_DLL _declspec(dllexport)
// include any local headers here
    Later, you will add more headers to the marked places in it.

    For example, the 'StdH.h' file for Serious Sam entities is exactly this:
    #include <Engine\Engine.h>
#include <Game/SessionProperties.h>

#define DECL_DLL _declspec(dllexport)

#include "..\Global.h"
#include "..\Common\Common.h"
#include "..\Common\Particles.h"
#include "..\Common\GameInterface.h"
    Go to Project/Settings again, select the entire project (the project itself, do not multiselect each folder individually!) and select 'C/C++' tab. In 'Precompiled Headers' category, for 'All configurations' select 'Use precompiled header file (.pch)' and type 'StdH.h' in the edit box. Then select just the file 'StdH.cpp' and change its options to 'Create precompiled header file (.pch)' and type 'StdH.h' again.

    This way, pch using will be automatically set for all cpp files we will later add to the project, and 'StdH.cpp' will create the .pch file.

    In each source file in the project, you will use '#include "StdH.h"'. This will work even if that source file is not in the same directory as the 'StdH.h' file. That enables files from different directories to be compiled with same .pch file.

    STEP 4: Making Classes Folder

    The entity source files are not .cpp files, they have .es extension and are compiled using Ecc.exe. You should create a new folder for them in the 'Tutorial' project. (In the Project Workspace window, Files tab, right click on the 'Tutorial files' and select 'New Folder'.) Name it 'Classes' and and type 'es' for 'File extensions'.


How to Create an Entity Class

Authors:
  • Alen Ladavac, Lead Programmer, Croteam
    Targeted audience:
  • Croteam programmers
  • licencee programmers
  • public programmers
    Required reading:
  • None
    Required knowledge:
  • Using Visual C++ 6.0
    Explains:
  • How to create a new entity class in an existing entity package DLL.

    Introduction

    It is assumed that you already have the DLL project name 'Tutorial' set up and opened in Developer Studio. If you don't, consult How to Create a new Entity Package tutorial on how to create one.

    The Blob

    What we will try to do here is just make one simple class with some basic behavior and movement. Our Blob will be just a stupid piece of jelly jumping around.

    Creating and Preparing the Entity Source File

    Make a new file named 'Blob.es' (in the project directory e.g. 'Tutorial\Blob.es') and add it to the project. Since entity sources are not generically supported by VisualC++, select 'C++ Source File' for the file type. The file should be automatically added to the 'Classes' folder of the project.

    Note that the project must be in the Sources directory, or it will not be compiled properly.

    There is no default action to build .es files, so you have to add a custom build for that. Go to Project/Settings, select the 'Blob.es' file and choose 'Custom Build' tab.

    For 'All configurations', set:
    'Description' to:
    Tutorial/$(InputName).es
'Commands' to:
    cd ..\
    ecc Tutorial/$(InputName).es
and 'Outputs' to:
    $(InputName).cpp
    Now, the file has a custom build action which will compile it using Ecc and make cpp source files out of it.

    Writing Initial Source

    Empty entity source will not compile with Ecc. You must give it some basic skeleton to make it pass syntax and semantic checking.
    For detailed information on the .es syntax, see Entity Source (ES) Syntax. Here is a minimum compileable source for the Blob class:
    1001
%{
#include "StdH.h"
%}

class CBlob: CMovableModelEntity {
name      "Blob";
thumbnail "";
properties:
components:
functions:
procedures:
  Main() { }
};
    The number on the top is the identifier of the class. Without explanation, 1001 is chosen arbitrarily now. Below the identifier, there is an initial C++ code block, and header file for precompiled headers is added there.

    Finally the Blob class is declared with no thumbnail, no features, no components, no functions and just an empty Main() procedure.

    Adding the C++ Sources to the Project

    When you have added the above snippet to the source, build the project. The build should succeed, but there is still no code. The first build has just created the C++ source files from your entity source.

    Following files were created:
        Blob.cpp
    Blob.h
    Blob_tables.h
    Now add those files to the project, and build it again. This build has really compiled the created C++ file Blob.cpp.

    IMPORTANT: Since those three files are auto-generated from 'Blob.es', you must never edit them manually, because any of your changes would be lost with the first next recompilation of 'Blob.es'. Also, if you use SourceSafe, or any other source control system, you must never add the autogenerated files to the source control, because that would make them read-only. Those files are intermediate files, just like '.obj' files, and it is enough to add '.es' to source control. The rest can be rebuilt from it.

    Creating the Entity Link

    The class is now compiled and exists inside the 'Tutorial.dll' package. To be able to insert it in a world using Serious Editor, you must have an Entity Class Link (.ecl) file for it.

    In the 'Classes\' directory in engine dir, create a text file (using NotePad, or similar) named 'Blob.ecl'.

    NOTE: This 'Classes\' directory is in the engine dir, that is where the game and sdk are installed. It is not the Engine\Classes directory in the sources directory. If you have not yet unzipped the .gro file, you probably do not have Classes directory in the engine dir. Either unzip the .gro file, or create the directory manually.

    Edit the file to look like this:
    Package: TFNM Bin\Tutorial.dll
Class: CBlob
    Make sure that you have pressed 'enter' at the end of the last line.

    This file represents the class in SeriousEditor, and the class is added to a world by dragging the .ecl file and dropping it onto the world.

    Adding Required Features for a Usable Class

    This class now exists and has its link file. Before you can drag-and-drop it to a world in SeriousEditor you must add some more code to it.

    It must have a thumbnail. Edit the line with thumbnail definition and enter "Help\\SDK\\Models\\Blob\\Blob.tbn" instead of the empty string. This thumbnail is just a texture file (same as .tex, just that this one has .tbn extension), and it is used when the SeriousEditor displays the classes in the VirtualTree Browser window, or in file open dialog preview.

    It must have some appearance. We will use a pre-created model for this tutorial. First add the model and its texture as components by typing this under the 'components' keyword:
      1 model   MODEL_BLOB     "Help\\SDK\\Models\\Blob\\Blob.mdl",
  2 texture TEXTURE_BLOB   "Help\\SDK\\Models\\Blob\\Blob.tex",
    Now, add this code to the Main() procedure:
        InitAsModel();
    SetPhysicsFlags(0);
    SetCollisionFlags(0);

    // set appearance
    SetModel(MODEL_BLOB);
    SetModelMainTexture(TEXTURE_BLOB);
    return;
    This tells the engine that this class should be rendered as a model, sets its physical parameters and chooses the model and the texture. These physical parameters will just make it float in the air with no interaction with the other entities in the world.

    Testing the Class in SeriousEditor

    Now build the project and run it from the debugger. If you do not have the debug build of the editor, you will have to build and run the release version.

    SeriousEditor will start. For info on how to work in the SeriousEditor, see its accompanying documentation. You should now load a test world from the 'Help\SDK\Worlds\Room.wld'. It is just an empty room with one light. Drop the 'Blob.ecl' in it, either using the Virtual Directory Browser, or directly from the Windows Explorer. A big green Blob should appear. Save the world as 'Blob.wld'

    Adjusting the Model's Appearance

    Now the little blob is in the world, but it does not really look the way it should. First of all it is not that little. The blob is 10 meters big. But it is not a problem, you can adjust its size dynamically. Add the following line before the SetModel() call:
        GetModelObject()->StretchModel(FLOAT3D(0.1f,0.1f,0.1f));
    This should shrink the model 10 times.

    Try that again in SeriousEditor. Make sure you exit SeriousEditor, build the project and run it again. (Though this looks like a tedious process if you have to repeat it a lot, it shouldn't be a problem, because SeriousEditor starts in a matter of seconds.)

    Now the model is of a moderate size, it comes to just under your waist. Exit the SeriousEditor and continue to adjust the code. If you want to check it out in the SeriousEditor once in a while during the process, feel free to do so whenever you want.

    The next thing you can notice (if you have checked the Blob model in SeriousModeler) is that it should be a kind of shiny, while the one in the world is diffuse. To make it appear same as in modeler, we have to add specular and reflection textures to it.

    Start SeriousModeler and load the Blob model from the 'Help\SDK\Models\Blob\' directory. Press 'Q' to invoke the info window and select 'Global' tab. There you can read which specular and reflection textures the model uses. To add those textures to the Blob class, add the following components:
        10 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex",
    11 texture TEX_REFL_LIGHTBLUEMETAL01   "Models\\ReflectionTextures\\LightBlueMetal01.tex",
    and add code that will set those to the model after SetModelMainTexture() call:
        GetModelObject()->mo_toSpecular.SetData(
      GetTextureDataForComponent(TEX_SPEC_MEDIUM));
    GetModelObject()->mo_toReflection.SetData(
      GetTextureDataForComponent(TEX_REFL_LIGHTBLUEMETAL01));
    Now the Blob should be shiny.

    Making It Move

    But the blob just levitates in the air wherever you put it. To start the blob moving, you must adjust its physical parameters.

    First change the calls to SetPhysicsFlags() and SetCollisionFlags() to this:
        SetPhysicsFlags(EPF_MODEL_WALKING);
    SetCollisionFlags(ECF_MODEL);
    That marks the Blob as a model which behaves like a live being. This is a usual setting for models like enemies, or player. The constants used here do not originate directly from Serious Engine, but are Serious Sam dependent. Collision flags are defineable by application. For short, you must include one more file below 'StdH.h', or in the StdH.h itself:
        #include <Entities/Common/Flags.h>
    This file defines all the collision and physics flags used by SeriousSam entities. When you use it, you make your entity compatibile with SeriousSam entities for collision.

    Also, you must jump-start the physics functions for the Blob. You do that by adding the following line at the end of the Main() procedure:
        // initialize moving
    SetDesiredTranslation(FLOAT3D(0,0,0));
    If you test it now, you can see that the Blob has fallen to the floor as soon as the game was started (it can be positioned in the air in the editor because time is frozen while editing). Also, you cannot pass through it anymore, because its collision works now.

    To make it really move, change the last line to this:
        SetDesiredTranslation(FLOAT3D(0,0,-1));
    That makes the Blob move forward at the speed of 1 meter per second.

    Adding Some Will

    The blob now moves, but when it hits a wall, it stops. It is actually trying to move, because its desired translation is still set to (0,0,-1), but the collision with the wall prevents it to move.

    To make the blob behave more reasonable, you must add some kind of primitive 'AI' to it. It will not really be AI, just some basic behaviour.

    Let's say you want the Blob to bounce up and down. It should jump up, wait while it flies, then when it hits the ground, it should wait for a bit as if preparing for the next jump and repeat the process.

    To do that, instead of the last line write the following code:
        // repeat forever
    while(TRUE) {
      // pulse jump up
      SetDesiredTranslation(FLOAT3D(0,10,0));
      autowait(0.1f);
      SetDesiredTranslation(FLOAT3D(0,0,0));

      // wait
      wait() {
        // if touched something
        on (ETouch) : {
          // stop waiting
          stop;
        }
        // ignore all other events
        otherwise() : { resume; }
      }

      // wait a bit on impact
      autowait(0.5f);
    }
    This translates the description of the wanted behavior to the entity source code.

    If you try that, you will see that it really does behave as described.

    The Animations

    Ok, the Blob is jumping up and down, but it looks a bit too stiff for a piece of jelly. It should show some effect on each impact with the floor.

    It can be accomplished by playing the 'Melt' animation of the Blob model. You can view it in modeler. In the animation, the Blob hits the ground, compresses, then it decompresses again as if bouncing. That is just appropriate. To be able to play the animations, you must know their names. Take a look at the 'Blob.h' file in the same directory as 'Blob.mdl'. That header file is autogenerated by the SeriousModeler each time the model is saved. It contains the following two lines defining the animations:
    #define BLOB_ANIM_DEFAULT_ANIMATION 0
#define BLOB_ANIM_MELT 1
    First, include the '.h' file at the top cpp block.
        #include <Help/SDK/Models/Blob/Blob.h>
    Now to play the animations, replace the following block:
          // wait a bit on impact
      autowait(0.5f);
    with this one:
        // play the bouncing animation
    GetModelObject()->PlayAnim(BLOB_ANIM_MELT, 0);
    // wait for the bouncing to finish
    autowait(GetModelObject()->GetCurrentAnimLength());
    // continue in still pose
    GetModelObject()->PlayAnim(BLOB_ANIM_DEFAULT_ANIMATION, 0);
    Try that one out to see what it looks like.

    Conclusion

    If you did all that, the final file should look like the supplied Blob.es. This is just a basic tutorial. Take a look at the entity documentation for more deeper insight to entity source syntax.


Customizing Views

Overview

Serious Engine implements game modification system. There are many types of modifications (MOD) that can be made to original game like: new levels, new playing modes, players, weapons and other models, items and enemies, new music and sounds, textures,.... Croteam encurages and supports MODs.

Basic notes about creating a MOD:

- When developing MOD, you create and keep your files in game's root directory. When you are over, you create MyMod\ subdirectory in \Mod\ directory, and move your files there (you should later create single .gro file for distribution). This way you use files with paths relative to game root directory when developing, and later, when you move them into MOD's root directory (i.e. Mods\MyMod\) and activate you MOD within the game, engine's MOD system will prefere Mods\MyMod\ as a root directory over game's root directory.

- Additional levels must have MyLevel.vis file if you want it to be available trough SinglePlayer->CustomLevel menu.

- You have to set world flags and description for additional levels. Flags define if level will be available in single player, deathmatch or cooperative mode. Description will be used for displaying level name in menu. Both level flags and description can be easily set in Serious Editor, using World Settings dialog.

- Multiplayer characters and weapons are defined using .amc scripts. Chapters under "Advanced Model Creation Tutorial " section of help describe how to use them.

- To understand how Serious Engine handles directories and prefere files when loading, read basic information chapter of help.

Some notes to use advanced features of Serious Engine's MOD system

- There is a system that allows MOD creators to control saving and browsing directories, to define starting and intro level. To control saving, you write BaseWriteInclude.lst and BaseWriteExclude.lst files. These scripts contain lines with directory names. Files in these directories in the base dir (not mod dir) will be allowed to be saved to.
BaseBrowseInclude.lst and BaseBrowseExclude.lst define which directories in the base dir (not mod dir) will be browsed in menus that browse directories (like the Player model menu, or CustomLevels menu).
Generally, just keep them as it is, later you might want to make base game levels or models not show up in your mod by setting BaseBrowseExclude.lst to contain lines:
Levels\
Models\Player\
Or similar.

If you want your Mod's savegames to be separated from the base savegames, make a copy of the SaveGame directory in your mod (make sure you make all the subdirs too!), and add this line:
SaveGame\
to both the BaseBrowseExclude.lst and BaseWriteExclude.lst

Also, you might want to set up a name for your mod to appear in the main menu (instead of the title 'The First Encounter'). You do this by making a file
Data\Var\ModName.var with one line containing the name.

You can also change the default level that will be started when someone presses 'New Game' in the single player menu. To do this, you have to set the cvar sam_strFirstLevel to the level path (relative to your mod dir, not the base dir!). Usually, one would do this in a file Scripts/Game_startup.ini (add this to your mod directory). Also you can change the intro animation played by setting the cvar sam_strIntroLevel.

Important note:
To find out more information about developing modifications, you can visit Serious Engine SDK forum at Serious Engine forum or contact Croteam.


Class help (Part I)

Classes (Entities) and Properties

INTRODUCTION

Classes (entities) discussed here are those that are present in the Serious Editor's virtual tree or that exist in the Classes directory and can be added to the virtual tree. Note that some classes (entities) present in the Classes directory are not intended for users' direct use within the editor and cannot be added to the virtual tree (you can try, but they will ultimately not be added).

Units Of Measure: Measurements in Serious are in meters.

Property Types: Values stored and edited in classes' (entities') properties are of the following types:

FLOAT (decimal number)

BOOL (flag, yes/no, i.e. light switch)

POINTER (link, relation)

ENUM (defined set of values i.e. light types: directional, ambient, point,..)

Common Properties (shared by most entities)

Most entities share some common properties, due to entities being implemented in base classes or added through 'Features' .es coding interface. Some of these properties are listed below

Name

-string property. Almost all entity classes have a Name property. It is used to assign individual names to specified entity(s). It is very important to properly name your important entities, so that you can identify them later. Names of entities are also used to define clones. Clones are all entities having the same name (the entities don't have to be of the same class).

Parent

-pointer to another entity. The Serious engine implements hierarchical linking of entities. Hierarchical structure is obtained by defining relationships between objects. The 'Parent' property is used to target the entity that is parent of the entity being edited. An entity can have only one parent. If one moves a parent, all of its children are moved identically, maintaining their location and orientation relative to the parent. Child entities can be moved freely, without moving their parent. Parenting is important when working with clones. For example, create a few bare columns and assign all of them the same name. This way they become clones. Then, on one column, create a torch with a fire and a light. Form this into a hierarchical structure: set column as parent of torch, torch as parent of fire and light. Apply "update clones" to this column equipped with torch/file/light and all remaining columns having the same name will be replaced by columns equipped with torch/fire/light. Parenting is also useful for destroying entities during game play. If you destroy a parent entity, all of its child entities will also be destroyed. Destroy a "parent" column and its torch, fire and light will be destroyed. Destroy a 'parent" torch and its fire and light will also be destroyed.

Spawn flags

-array of flags. All entities have this property. It is an array of editable flags that determine in which game levels of difficulty (easy, normal, hard,...) and game modes (single play, cooperative, deathmatch, ...) an entity (health, trees, enemy spawners, ....) will exist.

Background

-flag property. Background (skybox) is rendered as viewed from backgroundviewer entity. All entities that have 'Background' property flag set are taken into consideration for rendering when rendering view from backgroundviewer.

Target

-entity pointer. This is also a common property. In general, there are two types of target properties. The first one comes from class CMarker, which is one of the basic .es classes. Its basic purpose is to serve as a position in space, defining a position and an orientation. All classes extracted from CMarker (CPlayerMarker, CBackgroundViewer, CCameraMarker, CGradientMarker,....) share this property due to inheritance behaviour of object programming (higher classes have all properties of classes beneath). Second type of target properties are widely used to link with destination entity that should be notified that source entity has been activated. For example, when you press a switch, through target property (actually named On/Off target) you activate entity that is to perform an action due to switch activation. Or, if you enter an area contained in a touch field entity, the touch field entity detects it and sends event (trigger, activate, start,....) to target entity (i.e. enemy spawner).

Targetable

-flag property. If this flag isn't set, entity can't be targeted by other entities. This flag exists to prevent typically unwanted numerous entities (such as lights) from appearing as possible targets in target combo boxes. So if you want to perform triggering on such entities (that have the "Targetable" property), you will have to set this flag in order to be able to target it.

BASIC ENTITIES

WorldBase

- basic brush entity. It is used for 'holding' a world's (or a portion of a world’s) geometry. There can be two types of world base entity: zoning and non-zoning. Zoning are used to define classification of other entities. Non-zoning are usually used to form detailed architecture or distant architecture.

Anchored

-flag property. It is normally undesirable for the user to be able to move zoning entities, due to the intensive processor calculations involved (such as classification, directional shadow recalculating, portal link setup...). The Anchored flag property is used to prevent user from accidentally moving zoning entities. If an entity has this flag turned on, the user won't be able to move it until tool button 'Anchor' is set on.

Fog 0 (special case, see end of paragraph)

Fog 1 thru 4

-pointers to fog markers. Makes up to 5 pointers (links) to fog marker entities available to the worldbase’s sectors. Each sector can have one applied fog effect. This effect is used to form all kinds of fogs (thick, dense, dark, colored, orthogonal (vertical) , rotated (shaking), ...). When such a sector is rendered it asks its brush (brushes consist of sectors) to obtain fog parameters of the fog assigned to it via a fog number. That's why worldbase brush has pointers to fog markers. Via these pointers, brushes are able to access fog parameters (color, height, density,...) from fog marker, which must be known for fog rendering. This pointer mechanism is used to link entities with sectors or polygons. Fog 0 represents every sector's default fog, so setting fog 0 will tell the engine to render fog in each and every sector in the level.

Gradient 0 thru 19

-pointers to gradient markers. To obtain gradient properties, polygons use the same mechanism that is used for obtaining fog properties. A polygon that has a gradient shadow is linked with a gradient marker via its brush. Gradiental shadows are gradients that are applied when a shadow map is generated. They are used to simulate 'radiosity effect', in which light power falls near ceilings or decreases intensity with distance from illuminating areas (lava).

Gravity 0 thru 9

-pointers to gravity markers. The Serious engine is able to handle multi-directional gravity (6 degrees of freedom). Gravity that influences an entity is the result of the combined efforts of all gravities that are applied to this entity (if entity is classified into more than one sectors). The Gravity pointer property holds a pointer (link) to a gravity marker. A Gravity marker defines parameters for calculating gravity in certain point in space.

Haze 0 (special case, see end of paragraph)

Haze 1 thru 4

-pointer to haze markers. Works the same way as fog does. It simulates natural phenomena caused by light being reflected from particles in the atmosphere. Use of haze greatly contributes to the reality of the rendered view. Outdoor views rendered without haze look synthetic and unnatural, whereas proper use of haze gives a photo-realistic look. Haze also removes difference between world and background in a such a way that the transition between them is not noticeable. Haze 0 represents every sector's default haze, so setting haze 0 will tell the engine to render haze in each and every sector in the level.

Mirror 0 thru 4

-pointers to mirror markers. Mirror markers are used to define camera origin for rendering warp hole portal. When a polygon is marked as warp hole, it asks its brush to provide warped placement. To obtain warp hole exit camera placement, user has to create two linked mirror markers. Brush is via pointer properties linked to first mirror marker. This first mirror marker targets second one, one that is used to define warp hole exit. To be able to render effect properly, the warp hole rendering system has to use two placements. That's why two mirror markers must be used.

Zoning

-flag property. If this flag is set, brush is used to define zones. All non-zoning entities (non-brush entities and non-zoning brushes) are classified into zones (sectors). When classifying non-zoning brush, it is considered to behave as any other non-zoning entity (like bush or item). When it is rendered, all of its sectors (and all of the sectors' polygons) are added into rendering queue. Because a non-zoning brush can't classify entities, a model that is placed inside a non-zoning brush is actually classified into sector of zoning brush that contains the non-zoning brush. And if this sector is visible, model is added to rendering, no matter if it is occluded by non-zoning brush. Example: if you have non-zoning chapel inside one yard, and torch inside chapel, if yard is visible, torch is also visible.

WorldLink

-This entity is level's exit. It is used to create links between two levels. When it is triggered, it starts changing level sequence. One level can host more than one exit (world link) and more than one entrance (player marker). That's why world link has 'Group' property. World name defines which world the player will appear in. Group name defines which 'PlayerMarker' in that world player will appear at. For example, if player exits level A via world link specifying world B and group "town gates 1", player will appear in level B at player marker having group name of "town gates 1". It is also possible for the player to exit that same level A via world link specifying world B and group "secret channel" and appear in level B at player marker having group name "secret channel".

Group

-string property. It is used to link a 'world link' with a specific 'player marker' in the specified level. World link and player marker that have same group name are linked.

Store world

-flag property. If it is set, state of world being exited is saved and will be restored when player re-enters this level. This is very useful when creating several linked levels with multiple exits and need to re-enter one level more than once.

Type

-enum property. There are two types of world links. The first type is relative. It is used to simulate seamless level transition. For example, player enters corridor that looks the same at level A and level B. When level transition is triggered, engine calculates relative offset between player and world link. This offset is kept when player appears at new level, virtually at the same position in the corridor, so the feeling of smooth transition is achieved. The second type is absolute. The player appears at the location of the specified player marker, with no offset, regardless of the offset they had from the world link that sent them.

World

-file property. Used to specify next level. This level is loaded and started when world link is triggered.

Obsolete (explained above)

Name

Parent

Spawn flags

Target

GradientMarker

-Gradient marker is used to define gradient (interpolated color) that is applied as additional shadow. It is used to create more realistic lighting model, since real life light reflects from floors and ceilings, creating shadows that tend to be darker near ceiling and fall gradually towards floor. The same thing happens with illuminating planes, where light intensity falls away from illuminating plane. Position of gradient marker determines origin of gradient. Shadow is interpolated from two given shadow colors along given height. Gradient can also be applied as a dark light, where it is used to remove existing light. Shadow gradients are used to simulate radiosity. See WorldBase->Gradient 0 thru 19 discussion, to find out how gradient markers are linked with polygons (how gradiental shadow can be attached to a polygon).

Color 0 and 1

-color properties. These two colors are used for shadow interpolation. Center of gradient marker is used as origin of interpolation, point where gradient shadow has value defined with color 0. At distance greater or equal to value defined with 'Height' property, shadow has value given through color 1 property. Rotation of entity is also calculated, so angled gradiental shadows are also possible.

Dark light

-flag property. If this flag is true, gradient is subtracted from, instead of added to, shadow that applies gradiental shadow.

Height

-float number property. Used to define direction and length of gradient. If height is negative, direction of interpolation is changed (gradient is interpolated down from position of gradient marker).

Obsolete (explained above)

Name

Parent

Spawn flags

Target

BackgroundViewer

This entity is used to define camera origin and direction for rendering backgrounds. One level can have more than one background viewer, but only one can be active at a time. When a game's frame (player's view) is rendered, the engine first renders the background as seen from current background viewer. After background is rendered, engine renders world geometry as seen from player's eyes. The process of rendering the background is exactly the same as when rendering from player's eyes, but the engine processes only entities that have their background flag set. Since the 'background' part of the level is by no means different than any other, it can be as dynamic and complex as you want. This way you can create the feeling of moving on a train or inside a space ship, have birds flying all of the time in the sky,......

Active

-flag property. When one clicks the Active property, it activates the background viewer as the current one. The same happens when a background viewer receives an activate event. It forces that background viewer to become the active one.

World Settings Controller

-pointer to world settings controller (WSC) entity. The WSC entity class has a major role in all interactive environment effects such as earthquake, event-based blending or scrolling, storm, rain... It is used as a stock of variables that determine effects (FX) behavior. If you want to perform an event triggered FX, you should point to WSC with this pointer property. Here is how a complex FX is executed…. An FX (storm) must perform texture transformation or view change according to event that occurs in world (i.e. blend should start when player reaches current point in level). So, engine has to provide mechanism where an event in world (like switch activated or area triggered) produces reaction on geometry (like texture blending or shadow darkening in case of storm). For each frame, a global function in World Base entity class calculates once-per-frame geometry reaction parameters (i.e. current scroll value for scroll applied on cloud polygons or current alpha value for storm blend type->value is 0 when storm is not on, and alpha is max (255) when storm reaches max power). To obtain current power of storm, this function locates current background viewer. Then it peeks 'World Settings Controller' pointer from property that we try to explain in this section. This global function can read state of WSC entity. In the case of a storm, when Storm controller (entity used for controlling storm FX) is triggered, it locates WSC (using same mechanism: get current background viewer, get WSC pointer from it) and changes WSC variables that control state of the storm (lets say that storm controller marks in WSC that storm has started in time xx:yy:zz). Now, on each rendering, global function of world base will locate WSC via this pointer in background viewer and will know current storm power (can be easily calculated from current time and storm start time).

Obsolete

Name

Parent

Spawn flags

Target

Light

Source of light. Serious Engine's light engine supports these light types: directional lights (sun, parallel beams, casts shadows), shadow gradients (controlled via gradient markers) and point lights. Point lights can either cast shadows (normal point light) or ambient light (doesn't cast shadows). All lights can be set to be dark, which means that they will subtract light instead of adding it (inverse color logic: white color will extract all light). So, if you want to darken the corner of a room, you can add dark light in that corner. Point lights have two ranges: fall-off and hot-spot. Inside hot-spot range light has maximum influence, influence that falls to 0 at fall-off. Real-life lights can't be realistically simulated using linear interpolation. That's why diffusion light distribution is used by default. Light can be animated and can be assigned to hold lens flare and/or lens reflections.

Ambient light animation

-enumerated animations. You can browse one of animations from animation file browsed under 'Ambient light animation file'. Lights can animate both ambient and diffuse component. This animation can be changed later using animation changer.

Ambient light animation file

-animation file. You browse animation file here. When you do so, you can select one of file's animations under 'Ambient light animation' property. Light animation file can be edited and manipulated with light animation editor from within Serious Editor.

Clip far

-float number property. Serious Engine does not use ray-casting algorithms for shadow mass calculation. Instead, it uses the much faster in-game scene rendering ASER algorithm that is used when rendering normal frame. That's why you can move point lights and have shadows updated in real-time. Clip near and clip far properties hold values that define distance of near and far clip planes that are used for scene rendering. Usually, you don't have to change these numbers. Only change this when you experience strange artifacts in shadow rendering when light is placed near wall or a model. Adjust and recalculate shadows until shadow are ok.

Clip near

-float number property. Explained under 'Clip far' section.

Color

-color property. Defines color of light. Color's alpha value has no meaning. When light casts light to a polygon, light's intensity is interpolated from color given through this property (from hot spot distance) down to no influence at all (at hot spot distance). The influence of all lights that have impact on a polygon are calculated into a special texture called a shadow map. When a polygon is rendered on the screen, this shadow map texture is mixed with polygon's basic texture(s) and then rendered. This is the way the engine displays shadows. If we now take a close look at what happens at just one rendered pixel, where one texture's pixel and one shadow map's pixel are combined, we could observe the following: if shadow map's pixel color is gray (R=128, G=128, B=128), then texture pixels isn't changed at all. For shadow map pixel values below gray, texture is darkened. For values above gray, texture is brightened. Brightening gives impression of strong light influence. One can experiment with wide range of light colors and get interesting results. Formula for mixing texture and shadow map is: result=texture*shadow map*2.

So, when we have gray shadow map (value 128, half from white, max influence which is 256), one channel's result will be calculated as: y=x*128/256*2, further: y=x*256/256 which is equal to multiplying with 1, resulting in y=x. Therefore, gray shadow value leaves texture as is. If we have light gray shadow map, value 192, result will be calculated as follows: y=x*192/256*2, y=1.5*x. That means that at shadow map value of 192, brightness of texture pixel will be 50% increased. For shadow map value 64, combined pixel will have halved texture's value. When shadow map lightens texture, it is said that it has over-brightening influence.

Dark light

-flag property. If this flag is set, color doesn't add light to polygons, it subtracts it. This type of light doesn’t exist in nature, but is useful when we want to lower the lightness of an area. Dark lights work with inverse logic: black color of dark light has no influence, where white color sucks out all existing light when creating an shadow map.

Diffusion

-flag property. Real life light spreading is well simulated with lights that have diffusion flag set. To calculate a specific point in shadow map for diffusive light, Serious Engine calculates not only light source-shadow map pixels distance influence, but also influence of light ray's entering angle. Lights that don't have diffusion flag set ignore entering ray angle's influence.

Directional ambient

-color property. Used for directional lights only. This color defines lighting of areas that are not seen by directional light's rays. Real life atmosphere produces ambient color that gravitates toward blue (because of blue color of sky).

Dynamic

-flag property. This flag should be set for moving lights. This causes the engine to invoke special optimization for dynamic lights. Dynamic lights can't simulate diffusion behavior.

Fall-off

-float number property. Defines distance from light's source (in meters) where light's influence ends.

Hot-spot

-float number property. Defines distance from light's source (in meters) within which light has maximum influence. Light's intensity is applied with maximum light's power inside hot spot and is then interpolated down to nothing at fall off range, where light's influence ends.

Lens flare

-enum property. When seen through objects with lenses (cameras), lights appear to have glaring rings around them. These are called lens flares. Serious Engine allows you to add as much lens flare types. With this property you can assign one of several offered types to a certain light. Serious Engine implements lens FX power drop when light is near center of view.

Lens flare only

-flag property. If this flag is set, light's lens flare effect is rendered, but light’s lighting influence is discarded. This way you can create a background sun that displays lens flare with reflections but that has no lighting influence, while having a 'real' sun light cast sun beams somewhere else (where is more appropriate for the user).

Light animation

-enumerated animations. This works just like ambient light animation, but is applied to the normal (diffuse) component of light, not ambient.

Light animation file

-animation file. See previous property description.

Light animation offset

-float number, representing time in seconds. Given time is added to time when animation has started, forming time offset. Use this property when you want to remove synchronization from some lights that are animated with same animation. By altering this property on an array of lights, you can achieve a traveling light effect.

Polygon illumination

-enumerated illumination types. If you want to simulate illuminating polygons, you should set some kind of illumination type. If you set illumination type xxx for a light, it will cast rays only trough polygons that have same illumination type set. For example, you can use light illumination for a corridor where vitrajes (colored glass) casts light from outside.

Render as small

-flag property. Light is seen as a small star, rather than a light of significant size, in Serious Editor's view that renders editor models. Normally, as a light has a greater fall-off, its rendered size in the editor grows. Sometimes, if you have many lights in a level, it can get pretty crowded. If you set this flag, light's editor model will be rendered as small and won't get in the way when you need to see and select other entities.

Subtract sector ambient

-flag property. Set this flag to smoothen differences in ambient lightning between areas that are influenced with directional light and those that are not. By setting subtract sector ambient flag, you can achieve a subtle sun influence effect, where sun rays don't create sharp edge, but rather a smooth edge as sun power drops while entering dark area inside architecture. For advanced users only. Use to polish lightning in your levels.

Type

-enumerated light types. Select between available light types: directional (distant lights, parallel beams), ambient (point light that doesn't cast shadows) and point light (cast shadows). There are two modifications with prefix strong: strong ambient and strong point light. These lights automatically set hot spot at 90% of fall off distance.

Obsolete

Name

Parent

Spawn flags

Background

PlayerMarker

Controls player spawning. It is used to link with world link from previous level, via name given through Group property. Each level can have more than one level exit and entrance, due to their being matched via group name. Up to 16 players can be spawned on one player marker simultaneously. In Serious Editor, the player marker is displayed as race start checkered flag with bottom divided into 16 colored areas. Each area the is spawn point for a player (i.e. coop player). When a player marker is triggered, it becomes active one for re-spawning on the same level. In a Serious Sam coop game, when the party leader enters an area, player marker is triggered and set to be checkpoint. Next re-spawned player will be placed on last checkpoint, and will have spawn attributes taken from that player marker. On player marker, you can set both masks for weapons and ammo that will be added to a player, and masks for removing ammo or weapons (if some weapon is brought from previous level and should be removed).

Give weapons

-ulong mask. Combination of bits representing weapons. Players have these weapons when they are spawned at the player marker. The weapons mask is actually a bit field, with each weapon having one bit: The knife is 1, the Colt is 2, the Double Colt is 4, the Shotgun is 8, Double Shotgun is 16, the Tommygun is 32, the Minigun is 64, the Rocket Launcher is 128, the Grenades Launcher is 256, the Laser Rifle is

8192, and the Iron Cannon is 32768. If you want the player to gain or lose specific weapons, simply add the numbers; for example, a double colt and shotgun is 4+8=12. On the First Encounter, the Knife and Colt are always given to the player.

Group

-string property. Used to match world link (previous level's exit) with player marker (level's entrance). If you set same group name (xxx) on world link in level A and on player marker in level B, when player exits level A via world link having group named xxx, they will appear in level B, on player marker having group named xxx.

Health

-float number. When player is spawned, they receive this amount of health.

Max ammo rate

-float number. When player is spawned, they receive amount of ammo given though this property. Note that there is a minimum- for example, 10 shells for the shotgun.

Message

-entity pointer. Points to a MessageHolder entity that will be loaded as soon as the player enters the game. The player will have to call NETRICSA in order to read the message, so mark the "Start in computer" property if you want the level to start with the message.

Quick start

-flag. Used to mark this player marker to be used exclusively in Serious Editor. It is used to distinguish editor test markers from regular in-game player markers. You can freely move this player marker around your editing level, so as to be able to conveniently test various areas’ game play.

Shield

-float number. When player is spawned, they receives amount of shield given through this property.

Start in computer

-flag property. NETRICSA (Sam's implanted computer) will be called when player is spawned.

Take ammo

-ulong mask. Combination of flags, where each set flag represents one ammunition type to be taken from player upon spawning.

Take weapons

-ulong mask. Combination of flags, where each set flag represents one weapon to be taken from player upon spawning.

Target

-entity pointer. Entity targeted trough this property is triggered when player is spawned on player marker.

Obsolete

Name

Parent

Spawn flags

ModelHolder2

The main entity class used for placing models into a level. Each content model (not enemy or item) that needs to be placed in level will have one model holder. To add a model into world, drop ModelHolder2 entity and adjust its properties to fit your needs. Use Model property to browse and select model. Class auto loads textures as lastly saved in Serious Editor. You can browse and select texture via Texture property. Modelholder2 class allows you to adjust model's shading, to set destruction behavior, turn on collision, stretch it, adjust mipping (level of detail) distance switching,...

Active

-flag property. If you set this flag off, model will be invisible in game, but will still be visible in Serious Editor. You can set it visible inside game by sending Activate event to it.

Ambient color

-color. Models in Serious Editor are lit with ambient color and diffuse light color. In un-customized model shading mode, light direction, ambient and light color are calculated as resulting influence of the lights that surround the model. This shading model allows models to fit the world seamlessly as long as the level doesn't feature over-brightening. Due to older hardware’s inability to apply over-brightening onto interpolated shading, models can't have over-brightening, as world's polygons can. That's why sometimes it seems that models are darker than surrounding environment. Sometimes you want to add more drama to the lighting of a model and it can get tricky trying not to spoil the level's lightning. ModelHolder2 allows you to set your own shading for models. To do so, you have to set custom shading property to "Full customized". Then you adjust ambient shading component with the Ambient color property that we are describing here, change diffuse light component with "Light color" property and adjust light direction with "Light direction" property.

Light color

-color. Here you set diffuse component of light when you use customized shading as described in description of previous property.

Light direction

-vector property. This property is used to define the direction which will be used to lighten model.

Apply RND stretch

-flag property. When you set this property, model is resized according to random stretch factors. Flag is automatically cleared, so this property serves as some kind of 'Randomize again' button.

Attachments

-flag property. If this flag is set (by default), model automatically loads attachments that are saved within the .ini file saved when Serious Modeler saves a model.

Bump

-file property. You can browse and select bump texture for your model here. Bump texture adds detail to model's main texture (i.e. wood skin).

Classification stretch

-float property. Serious Engine uses a model's bounding box (box that collects all of the model's vertices) to classify it into sectors. When rendering sectors, if a sector becomes visible, models that are classified into it also become visible and are added to rendering queue. Sometimes you wish to 'unclassify' a model from some sectors. For example, if you create yard sector with 8 meters surrounding walls, and you have palms that are 12 or more meters high, they will be classified into both the yard sector and the sector above it. The sector above the yard sector is visible from a huge distance and, because the palm is classified into it, whenever this high sector is visible, the palm is rendered. That's the case if you don't tweak (read cheat) the model's classification. This property, classification stretch, is used to tweak model's classification. It represents number, actually ratio ranging from 0 to 1, that will be used to scale down model's bounding box before it is used for classification. If you set classification stretch of 0.5 to our 12-meter palm, it will be classified the same as a 6-meter palm would be. Now it will be classified only into yard's sector, and will be contained into upper sector.

Colliding

-flag property. If this flag is cleared, players and other moving entities won't collide with the model. A modern engine should be able to perform two collision detections: 'normal' physical collision (model to model and model to brush) and ray cast (bullet hit) collisions. Serious Engine's physical collision engine is based upon colliding with a model's oriented collision box, which is approximated with group of spheres. It is important to note the 'oriented' collision box, a mechanism that allows multiple gravities and a whole range of other physical effects. For ray cast collision, you can choose between exact, per polygon ray cast, and approximate, but much faster, ray cast algorithm.

Custom shading

-enumerated custom shading types. Here you can take control of model holder's shading and adjust shading parameters manually. In addition to normal un-customized shading model (where shading is left for engine to handle), there are two more shading models: fully customized and so-called constant shading. Up to now, we described fully customized shading where you provide separate color for ambient and color for diffuse shading component. Sometimes, however, you would like to erase shading effect and leave only lighting influence. In that case you should use "constant shading" setting.

Destruction

-entity pointer. An interactive engine should provide gamers the ability of destroying models. For example, one should be allowed to blow up trees, stones, statues, torches,... Modelholder2 implements destroying feature through model destruction entity. With this 'Destruction' property, you can target model destruction entity. This entity holds 'exploding data' info. When certain criteria are achieved, such as if model is hit so bad that destroy health provided by model destruction is reached, model 'explodes'. The engine then uses data stored in model destruction to form an exploding effect (i.e. type of debris) and to switch to next destroy phase, because model destruction points to next model holder 2 that can have its own model destruction. Through this model holder-model destruction chain you can have as many destruction phases as you wish (i.e. statue without head, statue without head and upper part of torso,...).

Destruction target

-entity pointer. When an model is destroyed, entity linked trough this property is triggered with trigger event. You can use this feature for numerous purposes. For example, you can activate secret door when a statue is destroyed (or you can spawn some enemies :).

Light animation

-enumerated animations. A model's shading can also be animated, so you can have all kinds of model's lighting behavior (i.e. flickering, colored light dancing, pulsating,...). Model holder's model can be animated using the same interface as for animating light: with one property you browse light animation file and with another (described here) you select one animation from animation file. Light animation can be changed later within game using animation changer. Just to remind you, a light animation file can be edited and manipulated with the light animation editor from within Serious Editor.

Light animation file

-file property. Here you browse and select one of your animation files as described in previous property section.

Mip Add

-float number. Serious Engine uses level of detail (LOD) for the models, and we call it mip-modeling (term is based on texture's mip-mapping effect, where texture switches to lower mip map on certain distance). Mip models are variations of the same model that differ in number of polygons. To speed up rendering of a model, engine uses lower mip model (one with less polygons) for rendering when model reaches certain distance. Since model is smaller on the screen, it doesn't need so many polygons for rendering. If model is even further away, engine will take next available mip model, and so on, and so on. These mip switching distances are defined within Serious Modeler, but sometimes you want to adjust this distance. Mip add and Mip mul properties are used for this purpose. Mip factor is number that engine uses to determine which mip model to use for rendering. Mip factor is heavily dependent upon model's distance from camera, but is also changed when resolution is changed. For the sake of simplicity, we can calculate that mip factor is a logarithm of base 2 of current model's distance. So, if model is 64 meters away, mip factor will be around 6. Let's imagine an unrealistic example where we have 10 mip models, each switching at next whole mip factor value (1,2,3,4,5...). So, for mip factor value of 6, engine would display mip model no 6. If we set this mip add property to certain value greather than 0, let's say 2, 2 will be added to original mip factor before determining which mip model to use for rendering, add we would get mip model 8 (6+2=8) instead of 6, so we achieved earlier mip switching by increasing mip add factor. To be more precise, we scrolled mip switching towards camera. Mip mul factor is used to stretch mip switching factor, not to scroll them. This way, if we set mip mul factor to 1.5, at distance that is represented with mip factor 6, engine will choose mip model 9 instead of 6 (6*1.5=9).

Mip mul

-float number. Explained under previous section.

Mip Fade dist

-float number. There is another way to setup mip model disappearing that will result in rendering speedup. It is implemented trough "mip fade dist" and "mip fade len" properties. These two also act using current mip factor (explained under "Mip add" chapter). They are used to define mip factor where model will start to disappear (using blending) and mip factor where model will completely disappear. If we use example from previous chapter, and set "Mip fade dist" to 6, "Mip fade len" to 2, model will start to disappear at mip factor (cca 64m) 6 and will completely disappear at mip factor 8 (cca 256 m). This can be very useful for larger number of objects. For example, if you would like to render an area full of trees, you could use this fading interface. You can set tree model's fading out distance (which is much more tolerable than mip model's "plopping") and add some haze to cover it. You will get smoother disappearing and much faster rendering.

Mip Fade Len

-float number. Explained under previous section.

Model

-file property. Here you can browse and select model holder's model. Once you select it, engine will try to open model's .ini file and automatically set textures that model was saved with from Serious Modeler. If model holder's attachments flag is set (defined via attachments property), engine will also try to automatically add attachments that were attached to most recently saved model.

Model animation

-enumerated model animations. When you browse and select a model via 'Model' property, animations that are featured for selected model appear under this property and can be selected. You can change these animations later with animation changer. For example, you can have statue of liberty model holding torch up and when you activate a switch, lady can start waving with the torch. Important point: in Serious Engine, animations do not take any time to calculate. So you can have thousands of animated models and they will take exactly the same time to render as if they weren’t animated. So, make your levels alive (all trees can move affected by the wind, flags can wave, ...).

Reflection

-file property. Here you can browse for and select reflection texture for a model.

Shadows

-enumerated shadow casting types. Models can cast different types of shadows: no shadows, cluster shadows and polygonal shadows. When you choose cluster shadows, models will behave exactly as if they were built as brushes, casting their shape onto the shadow map, and shadow will be blurred. If you choose polygonal shadows, all of the model's polygons will be projected onto polygon nearest to the model holder's handle and you will see the exact shape of the model. Edges will be sharp, and some polygons will be overlapped and will produce darker shadow areas.

Specular

-file property. Here you can browse specularity texture for a model.

Stretch All/X/Y/Z

-float factors. When you browse for and select a model, via the 'Model' property, the model will have a size that was defined inside Serious Modeler. Usually you want to stretch model to better fit your world. If you want to decrease the model’s size, you should set value less than 1 for "Stretch All". If you want to double model in size, set 2 for “Stretch All”.. You can stretch one or more components of a model. This way you can create taller or fatter models. If you set negative value as a stretch, let's say stretch x = -1, model will be mirrored around given axis (around x). This way you can create two mirrored guardians, each one to guard one side of an gate. Resulting stretch will be combination of all influences: if axis stretches are x=2, y=1, z=1, and Stretch All=3, model will be stretched 6 times along x, 3 times along y and z.

Stretch RND All/X/Y/Z

-float factors. These factors are used to define how much of random stretch will be applied to original stretch defined using Stretch All/X/Y/Z properties. Random factors define percentage, percentage of original stretch that is allowed random range. For example, if you set "Stretch RND All" to 0.1, you allowed random in range of +-10% of original model's stretch. If we have a palm that is 12 meters high, and we set "Stretch RND All" to 0.1, we allowed stretch sized from 12-1.2 up to 12+1.2. Random x,y,z work in the same way, but are applied only to according coordinates. Random stretch is not applied when these properties are changed, but when "Apply RND stretch" flag is set. You can think of this flag setting just like pushing "Randomize again" button.

Texture

-file property. Here you can browse and select model's main texture.

Texture animation

-enumerated main model's texture animations. All textures in Serious Engine can be animated. So can model's main texture. Sometimes a texture file holds more than one animation and here you can select one of animations available for main model's texture.

Obsolete

Background

Name

Parent

Spawn flags

Targetable

ModelDestruction

This entity class is used to 'hold' data that is used in the moment of model holder destruction. It tells the type of debris (i.e. flying rocks or broken wood) to be sprayed around, how big and numerous will they be, what amount of health has to be taken from model until it explodes, specifies next broken phase, bullet hit particles (little stones that are sprayed when you hit them with guns,...). You can read more about process of model destruction under "ModelHolder2->Destruction" property (property that is used to target this entity). Note that a model holder that uses only one model destruction entity isn't reinitialized when a model destruction property is changed. So, if you want destroyable model to apply changes made in model destruction, you have to reinitialize it (change any of its properties, i.e. click twice on Active property)

Body Type

-enumerated body types. Here you can change body type for model. Only "Rock" body type has an influence, that of inability of weapons utilizing bullets (guns, machine guns) to destroy the model. Other body types make no difference in current implementation.

Debris

-enumerated debris types. Debris are the pieces of model left after model's destruction. Select what kind of debris the destroyed model will leave after explosion: stones, palm parts, wood.

Debris Count

-integer number. How many pieces of debris of type selected with "Debris" property will model leave after exploding.

Debris Size

-float number. Here you define size of debris that model will leave after being destroyed.

Health

-float number. This property tells model's virtual health. When you hurt model that uses this within certain period with damage that is greater than specified here, described property model will explode. Note that health regenerates over time. Only damage impulses applied within a certain amount of time is counted.

Model 0/1/2/3/4

-entity pointers. Through these 5 entity pointers you can provide up to 5 different versions of next broken phase. If you set pointers 0,1& 2 and not set 3&4, engine will randomly choose one from first three model holders and will replace original one with it. Note that if you set phase 4 and not set phase 3, engine won't take into consideration phase 4. A broken phase is actually a modelholder2 entity. This next phase's modelholder2 can have its own model destruction, thus forming model holder-model destruction chain with an unlimited number of broken phases.

Particle Type

-enumerated particle types. Select type of objects that will be sprayed when model holder is hit but not destroyed (i.e. little stones sprayed from stone statues or wood parts broken from and tree).

Obsolete

Name

Parent

Spawn flags

WorldSettingsController

Functionality of world settings controller class is also described under "BackgroundViewer->World Settings Controller" section. World settings controller (WSC) entity usually appears only once in a level. It serves as a holder for data needed by some complex interactive effects that are to be performed on the level (i.e. storm or room morphing). WSC also enables you to set height map and define box that height map refers to. Height map is grayscale picture where bright pixels represent high areas, and dark ones low areas. “Height map” is the term widely used in terrain displacing applications. This height map is actually a Z-buffer of level saved from above (for those who know what Z-buffer is). You can save height map for certain area with Serious Editor: select polygons that will define axis aligned height map box and select "Export displace map". Select file name to hold saved height map. Bounding box that this height map represents is dumped into SED's console. Browse for and select exported height map under "Height map" property and type dumped values under "Height map box". Height map is used for procedural particle rendering (rain or grass). You wouldn't like rain to fall under roof. That's why you have height map of a level, which can be understood as a 'rain map' in this case. This grayscale picture mapped into world coordinates (that's what height map box is for) determines heights for certain area of your level. So, when the engine renders a rain drop, it looks into rain map's y coordinate and if rain drop's y coordinate is above, it will be rendered, otherwise it won't.

Height map

-file property. Here you browse for and select a height map.

Height map box

-bounding box property. Here you set min and max coordinates for each axis, defining a boxed volume area. Height map is mapped onto this box, where first left pixel is mapped onto min x,z coordinates, lower right height map's pixel is mapped onto box's max x,z position. Engine then extracts y coordinate according to mapped pixel's color where black pixels are mapped onto bottom of box, white onto roof. Since one color component is one byte, you can have 256 distinct values for y. Along x and z coordinate you have texture size proportional to the number of values: the bigger the height map is (in pixels), the more precision you will have, since each pixel will be mapped onto smaller world area.

Obsolete

Name

Parent

Spawn flags

FogMarker

Used to provide parameters for fog effect rendering. Serious engine is able to create fully dynamic real time gradiental wall of fog with almost no penalty. Fog marker is connected with brush via fog pointer interface explained under "World Base->Fog 0-4" section.

Fog is rendered using fog table that is calculated and uploaded each rendered frame. This table contains two dimensions. Size of fog table is given through 'Size Depth' and 'Size Distance' parameters. The bigger this table is, the more time it takes to calculate and upload, but also the more precise fog effect that results. It is a tradeoff: quality vs. speed.

The table's first dimension contains info about fog behavior at certain vertical distance from fog marker. This dimension is called depth dimension, because fog is rendered as gradient along y coordinate (if fog marker isn't rotated). Three parameters define how depth fog table data is mapped onto world. And note that this table covers world's area much larger than visible fog layer itself. It should map onto entire area that can be seen from within the fog. Objects that fall outside mapped area when seen from within fog won't be rendered correctly. Parameter 'above' is used to define height above fog marker. Parameter 'depth' stands for height of area covered by fog, calculated from fog marker position downward. Note that fog is rendered from fog marker, downwards! 'Below' defines height of area below fog layer.

To make it easier to understand, you should imagine a room 60 x 60 meters. Now imagine that we slice it into three horizontal layers, one laying on another. Lowest layer is 10 meters high, middle one is 20 meters high and topmost is 30 meters high. If we want our fog to cover only middle layer, we should place gradient marker on the border of middle and upper layer. Thus we should supply 30 for 'above', 20 for ‘depth’ and 10 for ‘below’. Don't forget that an object contained within range limited by above and below heights will be rendered correctly when seen from inside the fog. So, then, how is our room's fog table mapped? If we, for example, set 'Size depth' to 64 we would get 64 pixels mapped onto 60 meters (above+depth+below) giving approximately one pixel for one meter of world area defined with fog marker (but only 1/3 of pixels will be used to describe 20 meters of second layer, layer that actually contains fog).

Second dimension contains data describing how the fog acts relative to viewer position. It contains info about fog behavior along central view frustum line. View frustum or view pyramid is pyramid that starts in viewer's eye and spreads 45 degrees left, right, up and down from central view frustum line. Table's second dimension describes how fog is changed along central view frustum line. Since this line has start, fog's mapping line length is given through one property: Far. This property stands for: how far away from viewer along sight line will fog table be mapped.

Size Depth

index property. Defines width of fog table (texture) in pixels.

Size Distance

index property. Defines height of fog table (texture) in pixels.

Above

Below

Depth

-float numbers. Described above. Used to define height fog table mapping area.

Far

-float number. Described above. Used to define maximum distance (length of view frustum) in world coordinates, distance that is mapped with fog table's second dimension.

Attenuation Type

-enumerated functions. SE supports these attenuation types: exp (exponential), exp2 (square exponential), linear. Use this property to select function that will be used for density decreasing. All three functions have one alterable parameter (i.e. line angle for linear function) given through density property.

Density

-float value. By modifying this value you change function's control parameter and thus changing function step (degree, curvature). If you want to directly define this density function parameter, you should set "Density Direct" flag property and enter density value here. If you, however, want to define density (attenuation type's function step controlling parameter) using distance and percentage (i.e. at distance 100 m percentage is 75%), you should clear "Density Direct" flag and adjust values for "Density Distance" and "Density Percentage". By setting density direct flag, you can note that value for density will be only be reset if you change it. Otherwise, value for density is calculated using values under "Density Distance" and "Density Percentage" properties.

Density Direct

-flag property. Defines how density value will be calculated: directly (using value entered under Density property) or using values under "Density Distance" and "Density Percentage" properties.

Density Distance

-float property. Described above.

Density Percentage

-float property. Described above.

Gradation Type

-enumerated functions. You can choose between constant, linear and exponential functions. By default, border between fog and non-fog area is sharp (constant). That means that if you are inside fog and you are looking parallel to fog plane, and you start walking out of the fog, you will be able to see sharp line where fog area ends. To achieve smooth fog border you should have non-constant gradation type. This way, when entering fog, view will be smoothly fogged through some period of time and you won't even know when you entered fog. Gradation is edited the same way as density is: under "Gradation Type" you select function, under "Gradation" you set function step (control parameter, function 'angle') either directly or using "percentage at distance" logic (this logic is on when you clear "Gradation Direct" flag).

Gradation

-float value. This is function control parameter. You can define it directly (if "Gradation Direct" flag is set) or using "Gradation Distance" and "Gradation Percentage" properties (if "Gradation Direct" flag is cleared).

Gradation Direct

-flag property. Explained above.

Gradation Distance

-float property. Described above.

Gradation Percentage

-float property. Described above.

Color

-color property. Here you change fog color and fog power multiplier (alpha channel). Fog power multiplier is used to decrease fogging. Alpha 0-255 are translated into power multiply factors ranging from 0 to 1. For alpha value of 255 (translates as 1), fog won't be changed at all. For alpha value of 128 (translates as 0.5), you will halve fog power. This way when object is completely in fog, its fogging will be halved. For alpha value of 0 (translates as 0), fog effect won't be visible.

Obsolete

Name

Parent

Spawn flags

Target


Tutorial 01: Modeling

Animations and collisions

With all attachments added we can proceed on importing animations.
Serious Modeler supports Vertex animation system. Every animation in model consist of several frames of 3d objects. Since managing large number of frames could be painfull, its advised to create folder in your player directory with name Frames. In that folder you can have subfolder for body frames, legs frames etc.
On Image50 Lightwave's Layout is shown with Colt setup scene loaded.

Image50

First frame of scene represents pose in which player holds colt and knife. This frame will be used for creating COLT_STAND animation for player's body.
From Layout save transformed Body object or use Savetransformed displacement plugin. Save object int Frames_body folder (for example) with name like Colt_stand.lwo. In Serious Modeler open script (s shortuct).
Script should look something like:
;******* Creation settings
TEXTURE_DIM 2.0 2.0
SIZE 1.0
MAX_SHADOW 0
HI_QUALITY YES
FLAT NO
HALF_FLAT NO
STRETCH_DETAIL NO

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo

;******* End of animation block
ANIM_END

END
Every animation needs name and pointer to files, to create Colt_Stand animation, select this part of script
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo
and paste it after Body.lwo line.
Change path,animation name and name of object that is animation. After editing script should look like this:
;******* Creation settings
TEXTURE_DIM 2.0 2.0
SIZE 1.0
MAX_SHADOW 0
HI_QUALITY YES
FLAT NO
HALF_FLAT NO
STRETCH_DETAIL NO

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body
ANIMATION Colt_Stand
SPEED 0.1
    Colt_Stand.lwo

;******* End of animation block
ANIM_END

END

Click on CTRL SHIFT S to recreate model (add animation to model). Every time you add or remove something from model's script you need to recreate model. If you update frames in animation or animation's speed you can update model without recreating. Once model is recreated, cycle thru animations (curently 2) with Cursor Up and Cursor Down. For now there arent much to see. Next we will add colt redraw animation. This is animation when player changes weapon (from colt to shotgun or similar). To save on filesize (and speed up animation creation process) and to demonstrate Modeler's scripting strenght, we will use same frames for draw and redraw animation. Image51 shows few frames from Redraw animation (10 frames long).

Image51

Use savemorph displacement plugin or manualy export frames (painfull) from Lightwave.
Open model's script and add lines:
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body\Colt_Redraw\
ANIMATION Colt_ReDraw
SPEED 0.12
01.lwo
05.lwo
10.lwo

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body\Colt_Redraw\
ANIMATION Colt_Draw
SPEED 0.12
10.lwo
05.lwo
00.lwo
after
    Colt_Stand.lwo
line.
Speed line defines speed of every frame in animation. If you have 3 frames and speed is 0.12, whole animation will be 0.26 seconds long. Second animation, Colt_draw is done using same frames as Redraw animation but with sequence inverted. This feature of Serious Modeler allows adding more animations but keeping filesize small. Click on CTRL SHIFT S to recreate model (add animation to model). In animation control panel you have now 4 animations. Select Colt_Redraw animation and press Enter shortuct to play this animation looping (Shift Enter) plays animation only once. While animation is playing, in Animation tab of Tools panel change animation frames speed to see different behaviour (Image52).

Image52

This number will be saved in model once its saved, but wont be saved in model's script (replace value in script with new one and update model's animations).
Press Enter again to stop animation. With Shift Cursor Up and Shift Cursor Down you can jump to first/last animation in model.
With Shift Cursor Left and Shift Cursor Right you can jump to first/last frame in current animation.
Continue adding other animations. When you make animations for certain weapon, like shotgun, enable its visibility in atachment tab for visual guide.Save model

Load player model and repeat adding animations setup we did for body. If all went ok, you should have model fully animated (Image53) and ready for adding another 2 collision boxes (swim and death).

Image53

Select "Crouch" animation from Animation control panel, in Attachment tab select any of Body's stand animation (Image54).

Image54

For visual guide, enable virtual floor rendering (f shortcut). Go to Collision tab in Tools panel and add new collision. Name it CROUCH, press c to enable collision box rendering. Leave Width to default 1.0 meter, change Height to something like 1.5 or 1.6 meters.

Image55

We need to add one more collision, Swim collision box.
Select "Swim" or "SwimIdle" animation from Animation control panel, in Attachment tab select any of Body's swom stand animation (Image56).

Image56

Click on Add button in Collision tab to add new collision box, name it SWIM. Click on checkbox left from H=W. What it means is that Serious Modeler will apply same values you type in for Width, to Height parameter. Change Width and Lenght to 1.5 and in DY field type -0.75. This means that virtual collision box will be centered 0.75 bellow ground with diameter of 1.5 meters (Image57).

Image57


Tutorial 01: Modeling

Attachments

Next part is to add torso attachment. Image40 shows body.mdl which represents torso model.

Image40

It has been mapped and imported in same fashion as player model. With player model loaded open Attachment tab in Tools window, adjust player model on screen as on image41.

Image41

Click on Add button and point to Body.mdl. You should end with something like on Image42.

Image42

Body model is attached to player model, if you move, rotate player model, body will follow. Its time now to adjust position of attachment. For that, we will use triangle we created on player model. Position model so triangle is visible (Image43), press e to disable texture rendering and w to enable wireframe rendering (it will be easier to adjust attachment position).

Image43

Disable visible option (attachment model wont render). Observe vertices circled green on "attachment triangle". They represent Center(1), Up(2) and Front(3) axis. Center is vertex on player model on which attachment will be "glued". Up and Front are orientation. Place mouse over "center" vertex and click 1 on keyboard. In attachment tab number next to center: will change to new number. This is player model's vertex number on which is body attached. Place mouse over "front" vertex and press 2 on keyboard. Last place mouse over "up" vertex and press 3. This completes adjusting attachment positions. Enable visibility in attachment tab. If you did all corect, body model should be attached like on image44.

Image44

In position(DX,DY,DZ) and rotation(H,P,B) fields, additional adjustment can be done.
Final thing to do is to change attahment name to TORSO. This name is used by engine to know which model is refered as Torso. Additional models are added in same manner as torso. Click on add button to create new attachment set, point to model and adjust positions. Give it some reasonable name. You can also change default animation in animation pulldown.
As said earlier, "attachment" triangle wont be rendered. I assigned attachment surface to this triangle. In rendering tab, find this surface and click on invisible. This prevents triangle from rendering.

Next we will add Head model as attachment and weapons model attachment on body. Body model (Image45) has 3 attachment triangles, first on neck for Head, and two on hand palms for weapons and misc items.

Image45

First, lets add Head model (Image46).

Image46

Open attachment tab in Tools panel and click on add button. Point to head.mdl. Same as we did with body, select points on neck's triangle as attachment guide. Head position is seen on Image47.

Image47

Rename "no name" to HEAD, so Engine will know what attached model is Head.
Next, we need to add weapons attachment. In Creating player model section of Serious Modeler Help, types of weapons with descriptions and attachment names are listed. First we will add Colt_Right. In attachment tab, click on add button, select ColtItem.mdl from models/weapons/colt folder. Zoom into right hand and select points: center,front, up (Image48).

Image48

After adjusting positions and rotation, colt should look like in Image49.

Image49

Repeat those steps for other weapons and items. Dont forget to give them appropriate names. In rendering panel select surfaces on attachment triangles and make them invisible.
Note: You dont have to use right hand triangle as attachment guide, depending on your model, you can position this attachment anywhere.


Tutorial 01: Modeling

Modeling and preparing models
Steve

Multiplayer models in Serious Sam are multipart models, consisting at least of 3 models: Player (representing legs), Body (representing torso) and Head (representing head, helmet or whatever). Since Serious Engine supports recursive, hiearchical approach to "attaching" (joining/parenting more models in single entity), additional models can be added and controled via powerfull scripts (.amc, attachment model configuration file).

Note: tutorial will be conducted in Lightwave v6.5, though any 3d application supported by Serious Modeler can be used.

Lets start with loading player legs player.lwo into Lightave Modeler.
Image01

There are few things to note, when creating player model, object should be rested on ground, because Engine treats ground plane as 0 on height. Another thing, on player model body will be attached. Serious Modeler needs so called attachment triangle to know where to add body model on player model.
Another rules: all polygons in object that is imported must be triangles (error message will be display warning you about nontriangle polygons existing in object).
Image02

Image02 shows this triangle positioned on object. It wont render in game (will be set as ignored in Modeler's rendering menu), but it will be used as guide when player model is animated.
Same as adding triangle for body, more triangles can be added for additional attachments, like knee caps, tail etc... All those additional model can be attached on single triangle, but since "attachment triangle" isnt rendered in game, the more triangles you add, the more control you have.

Next part is assign UV data on object. With latest build of Serious Engine, Modeler supports more than 1 UV map per model. When 3d object is imported in Serious Modeler, multiple UV maps will be merged in single (1st one) UV map. Though it may be handy to have multiple UV map per object, working with only one will eliminate possible problems.
When importing 3d object in Serious Modeler, there are few rules to follow regarding surfacing (assigning materials). Since assigning UV data means flatening and unfolding object mapping, seams will be created. Take look a Image03,
Image03

it shows disc cylindrical UV mapped with checker texture applied. Yellow selected polygons represent seam in UV map. This is place where so called stich is created, where uv mapping isnt continued. If we assign single surface(material) to this object and try to import it in Serious Modeler, mapping wont be imported properly. This is shown in image04.

Image04

You can see selected with white outline texture stretched to 1 pixel on object and mapping that doesnt look exact like in Lightwave. Reason for that is with single surface/material assigned, you have 1 geometry vertex with more than 1 coordinate in UV map., i.e. there are more than 2 texture cooredinates in same surface/material with same UV valueattached to single geometry vertex. Image 05 shows those vertices on object and in mapping. Image05 shows 2 vertices on object with 4 mapping coordinates.

Image05

This mapping isnt supported in Serious Modeler, but there is an easy solution for that. All you need to do when come to such problem is to add new surface/material with same UV data to polygons on border of mapping (seam polygons). In Lightwave 6.x best way to find and select those polygons is to use "Select UV seam" function. Image 06 shows 2 surfaces with same UV map assigned to object.

Image06

When you recreate disc model in Serious Modeler, mapping wont be stretched or wrong. Take a look at image07, 2 surfaces has been assigned on disc model and model is recreated.

Image07

When uv mapping, you can work with object with single surface to ease process of creating mapping and then assign surfaces.

In low poly modeling, biggest chalenge when it comes to UV mapping is compromise between stiches in mapping (easier to map object with many stiches) and texture stretching. Consult your skin artist where to create stiches and where to have possible texture stretching. It is good to know what part of model will be less visible and create stiches in mapping there (like inside of arm, bottom of body or bottom part of head). Avoid creating stiches or texture stretching on muscles and highly visible parts of object like torso, face....
Another thing to have in mind is that object dont need to have proportional mapping, for example arm can occupy more space in mapping than bottom of torso, though it can sometimes lead to problems if face and head sides occupy different space in mapping, it will be hard to adjust continuity when texture is draw.

Lets get back to our player object. On this model, legs are symetrically modeled and will have same texture applied on them. Same is with boxes around vaist and feet. Save object or make copy of it in another layer (Lightwave specific). Delete object parts that are symetrical. After cuting and layer aragment i left with situation like on Image08.

Image08

Next step is to surface parts that will be separatelly mapped (like belt, leg, belt buckle, foot) for easier selecting and manipulating. In image09 you can see i assign different surfaces on different parts and arranged them in layers.

Image09

Ill first map ammoboxes that are placed around vaist (cyan color in Image09). I decided to make seam in back of boxes (polygons that are oriented inside body, because they wont be seen at all. Knowing rule about mapping and importing in Serious Modeler i assign another surface for polygons back (Image10).

Image10

Since most of polygons in box are faceted in X axis, apply planar UV mapping with X axis selected (Image11).

Image11

Change name of UV map and leave other options as default. In surface editor, select those 2 surfaces and add UV projection for Color chanel (Image12).

Image12

I have prepared checker texture (quadratic red-white checker) for mapping testing. When you apply it as texture map on object, you can easily check mapping stretching or wierdness in mapping. Check Image13, with checker texture applied, you can see how mapping is shrinked on U axis in mapping window (right window). To corect that, put mouse pointer in UV window, activate stretch tool (h), click LMB and drag mouse to right until checker in mapping becomes quadric.

Image13

With planar uv mapping, some stretching in mapping occured. Image14 shows stretching on polygons that are ortogonal or under large angle to axis you are mapping on.

Image14

To correct that, select 3 points on top in mapping and move them up (Image15).

Image15

Repeat same for bottom and side polygons which are stretched.

Another approach you can take to avoid stretching is to detach top and bottom polygons. Image16 shows box mapped with polygons detached. With this mapping, stretching is avoided but seams in mapping are created.

Image16

Next step involves mapping of leg. Leg in this case is extracted from rest of object so it can be mapped cylindrically (Image17).

Image17

Apply cylindrical UV mapping (Y axis), leave other options as default. In Surface editor apply to leg's surface UV projection, with correct vmap name and texture (checker for testing). Mapping is stretched on some places, maybe squished, but its easy curable. When you assing UV coordinates, Lightwave tends to lock some vertices from moving. Image18 shows those vertices.

Image18

Though they appear in mapping, you cant move them or edit, unless you unweld them. Select polygons that include those points (row of polygons left of them) and run "unweld" tool. It will detach points and allow their manipulation. This comes crucial when adjusting mapping or moving parts of mapping somewhere else. When fixing mapping, i have 2 window viewport setup, left is perspective with texture, right is UV Texture window. In left window select polygons that have stretched texture and those polygons will be selected in UV map also. Activate drag tool or move tool and move points in mapping to adjust positions. If checker on polygons is to small, it means those polygons have to much space in mapping, same if checker is to big, there are to less space in mapping for those polygons. For leg, i decided to have seam inside of leg, which is hardly seen anyway. With Lightwave UV edit features, editing (adjusting positions and eliminating stretching) of mapping is a lot easier.Image19 shows seam inside of leg. When happy with adjusting merge vertices (it wont mess your mapping).

Image19

Same as we did for ammobox, we need to do for leg, we need to add new surfaces on seam so leg will be properly imported in Serious Modeler. Select polygons on seam (Image20) and add new surface on them (like LegSeam).

Image20

You need to assign Uv projection in surface editor on newly created surface (Image21).

Image21

Copy this object, paste it into new document and save it as legtest.lwo. Create new model in Serious Modeler from this object. Image22 shows mdl created with corect mapping.

Image22

Repeat process of mapping for other parts of object and arange mapping so there are no big gaps between mapping vertices, like on Image23.

Image23

On image24 you can see object surfaced and ready to be mirrored and saved for importing. To show more clearly importance of proper surfacing, i resurfaced object so seams can be easy visible.

Image24

After assigning surfaces its time to mirror leg part. Select polygons (surfaces) in leg and mirror them on Z axis. If object is symetrical, points should be merged automatically. Image25 shows object mirrored and ready for importing in Serious Modeler.

Image25

In Serious Modeler from file menu (or CTRL N shortcut) select New and point to player.lwo object. Object should be imported, save it with CTRL S shortcut (or Save from File menu). Press m shortcut to open mapping window. There you can check is mapping imported properly. Image26 shows Player model and mapping window.

Image26

When you import 3d object in Serious Modeler, in object's folder, script file (.scr) with object name is created. From Serious Modeler you can acess and edit script by pressing s shortcut. Bellow is script created for player model.
;******* Creation settings
TEXTURE_DIM 2.0 2.0		-dimension of texture for model in texels.
SIZE 1.0			-model stretch, higher number, the bigger model in meters.
MAX_SHADOW 0			-shadow quality
HI_QUALITY YES		-high quality means lower compression and less distortion on model
FLAT NO			-use this option for plane models that will be used as explosions, smoke effects..
HALF_FLAT NO			-use this option for plane models that will be used as torches, fire effects....
STRETCH_DETAIL NO		-if model is stretched, you can stretch its bump/detail texture

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1			-number and list of LOD models created for this model
    Player.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Player.lwo		-default animation, created by default once object is imported in Modeler.

;******* End of animation block
ANIM_END
END
When creating model from 3d object, if texture (.tex) with object name exists (like player.tex) it will be automatically loaded. Otherwise you need to add it manualy. To test model and its mapping lets create and add checker texture we used in Lightwave as mapping guide. Click CTRL SHIFT T shortcut or from Texture panel click on Create new texture button. Menu with 3 options will open (Image27).

Image27

From there you can select to create:
"Normal texture" -single image texture (with alpha chanel or without), used for maping weapon, player and similar models.
"Animated texture" -image sequence used for explosions, smoke or particle effects.
"Effect texture" -procedural texture used for water, fire, waterfall and similar effects.

For this model we wil use Normal texture, click on Normal texture button or n shortcut. Requester will open asking you to select .tga image that will be converted into .tex file suitable for Serious Modeler. Double click on checker texture in requester, additional properties will be presented for you (image28).

Image28

Left in panel texture is displayed, size in meters coresponds to TEXTURE_DIM variable in model's script (if size in meters is smaller than TEXTURE_DIM, texture will tile on model, If size is bigger, texture wont whole fit on model's mapping). Mip maps tels how many mipmaps to create for this texture. Mipmaps are way to scale texture's dimension down when model with that texture is moving away from viewer. Sometimes you want to create only one mipmap (for textures that will be used as fake lightsources) to prevent bilinear algorithm in destroying texture content. When texture have alpha chanel, its quality is reduced in expence of memory it occupies. If quality isnt satisfactory check on "Preserve 32-bit quality" checkbox and texture will be saved as 32bit but it will take more memory. Use this on textures with gradients or alpha chanels, like Background textures, explosion effects and similar. In bottom of panel is "Use chequered background" button, usefull when checking texture's alpha chanel.
Click on "Create" button,texture will be created and loaded on model (image29). Save model to preserve texture's path into model file.

Image29

In Texture panel, texture name will appear. You can add as many textures as you want, they will appear in texture panel for browsing, or use PageUp, PageDown shortcuts to browse thru loaded textures. Rotate and examine model (check Navigation part in Serious Modeler). If you make any changes to object, simply recreate model (CTRL SHIFT S). Change rendering options (wireframe,surfaces...) to examine model. If you are happy with how model looks, its time to export mapping into tga file for texture painting (though it can be done in any 3d application). Serious Modeler's export mapping offers additional options. From File menu select "Export for skinning option", requester will open asking you give name of to be saved image. After that Exporting properties panel opens (image30).

Image30

On top path and name are displayed. With "Picture size" you can define pixel size of texture. Paper color defines background color, while Wire color defines color of wirframe mesh. Additionaly insted of empty wireframe, mapping can be flatfiled with surface color. Wireframe enables wireframe mapping to be saved. If you select "Surface numbers" option, text file with numbers and surface names will be saved and numbers will be added above surfaces in mapping texture. Image31 shows exported mapping for player model.

Image31

Create new texture from this image for easy editing. Load that image into your paint program and paint model's texture in it. When you finish painting or want to check paint progress,save image and in Serious Modeler click CTRL SHIFT R shortuct to recreate texture. It will load image from disk that texture is created from and update texture.
Its time to take a look at rendering and texture blending options available in Serious Modeler. Image32 shows texture made for this model.

Image32

In mapping view you may noticed holes in texture (where grey background is visible). This is because texture have alpha chanel, Modeler automaticaly displays texture with alpha chanels. We will now apply alpha chanel blending on model using per surface blending. Click Q shortcut to open Tools panel and click on Rendering tab (for more information check Tools window part of Serious Modeler Help).

Image33

This model is designed to have transparent parts of its geometry (thus texture with alpha chanel). Serious Modeler have per surface editing approach for texture blending and rendering options. This means that you can assign number of surfaces in your 3d program and individualy or multiple edit them in Serious Modeler.
In rendering panel you can cycle thru defined surfaces with Tab and Shift Tab shortcuts. Lets start with legs first, cycle in rendering tab until Leg surface (or how you called it in 3d program) becomes active. Another approach is to run Link surfaces tool (Z) shortcut and select multiple surfaces for editing (Image34).

Image34

Select surfaces you want to edit and press OK. In Rendering panel name of active surface will change to number of select surfaces. Quick check selection by clicking on invisible button (they wont render). Disable invisible option, for Transluscency select Transparent option (use alpha chanel). Also enable Double sided option. Model should look like on Image35.

Image35

Another thing we want to add on model is specular texture (since model have metalish texture, specular and reflection effects are calling). With leg surfaces selected, in Rendering panel check on Specularity buton. Nothing changes since we dont have Specular texture loaded. You can create your own specular texture, or loaded predifined one (for more on Specular texture check Add Specularity section in Serious Modeler Help. Click on "Browse specular texture" in FX control panel and load Medium.tex from models/SpecularTextures/ folder.

Image36

Hold Shift Both mouse buttons and rotate mouse to roate light around model and see how specularity changes on model. You can also hold Space Both mouse buttons to rotate model and see specular effect.

Image37

By default specular color and strenght is white. For this model we will change it to more orange color (to simulate sun reflacting on metal). Use HSV sliders bellow specularity or double click on white box to change color. We ended with something like on Image38.

Image38

Same as we add specular we can add reflection or bump. Note that every of those effects have impact on rendering time !

Next step is adding Colision properties.
In Tools panel click on Collision tab and press c short to enable collision box rendering (For more information on collision refer to Collision box section in Serious Modeler Help). Image39 shows default collision created with model.
Image39

For multiplayer models, 3 collision boxes are needed. Change PART_NAME line to STAND (this will represent collision when player is runing, walking etc...). Also change Height to 2.2 (numbers here are arbitrary, you can change them to fit your model). Collision represents collision of whole model not just legs. Another 2 collision will be added once we add all attachments and animations.

Next part is to add torso attachment. Image40 shows body.mdl which represents torso model.

Image40

It has been mapped and imported in same fashion as player model. With player model loaded open Attachment tab in Tools window, adjust player model on screen as on image41.

Image41

Click on Add button and point to Body.mdl. You should end with something like on Image42.

Image42

Body model is attached to player model, if you move, rotate player model, body will follow. Its time now to adjust position of attachment. For that, we will use triangle we created on player model. Position model so triangle is visible (Image43), press e to disable texture rendering and w to enable wireframe rendering (it will be easier to adjust attachment position).

Image43

Disable visible option (attachment model wont render). Observe vertices circled green on "attachment triangle". They represent Center(1), Up(2) and Front(3) axis. Center is vertex on player model on which attachment will be "glued". Up and Front are orientation. Place mouse over "center" vertex and click 1 on keyboard. In attachment tab number next to center: will change to new number. This is player model's vertex number on which is body attached. Place mouse over "front" vertex and press 2 on keyboard. Last place mouse over "up" vertex and press 3. This completes adjusting attachment positions. Enable visibility in attachment tab. If you did all corect, body model should be attached like on image44.

Image44

In position(DX,DY,DZ) and rotation(H,P,B) fields, additional adjustment can be done.
Final thing to do is to change attahment name to TORSO. This name is used by engine to know which model is refered as Torso. Additional models are added in same manner as torso. Click on add button to create new attachment set, point to model and adjust positions. Give it some reasonable name. You can also change default animation in animation pulldown.
As said earlier, "attachment" triangle wont be rendered. I assigned attachment surface to this triangle. In rendering tab, find this surface and click on invisible. This prevents triangle from rendering.

Next we will add Head model as attachment and weapons model attachment on body. Body model (Image45) has 3 attachment triangles, first on neck for Head, and two on hand palms for weapons and misc items.

Image45

First, lets add Head model (Image46).

Image46

Open attachment tab in Tools panel and click on add button. Point to head.mdl. Same as we did with body, select points on neck's triangle as attachment guide. Head position is seen on Image47.

Image47

Rename "no name" to HEAD, so Engine will know what attached model is Head.
Next, we need to add weapons attachment. In Creating player model section of Serious Modeler Help, types of weapons with descriptions and attachment names are listed. First we will add Colt_Right. In attachment tab, click on add button, select ColtItem.mdl from models/weapons/colt folder. Zoom into right hand and select points: center,front, up (Image48).

Image48

After adjusting positions and rotation, colt should look like in Image49.

Image49

Repeat those steps for other weapons and items. Dont forget to give them appropriate names. In rendering panel select surfaces on attachment triangles and make them invisible.
Note: You dont have to use right hand triangle as attachment guide, depending on your model, you can position this attachment anywhere.

With all attachments added we can proceed on importing animations.
Serious Modeler supports Vertex animation system. Every animation in model consist of several frames of 3d objects. Since managing large number of frames could be painfull, its advised to create folder in your player directory with name Frames. In that folder you can have subfolder for body frames, legs frames etc.
On Image50 Lightwave's Layout is shown with Colt setup scene loaded.

Image50

First frame of scene represents pose in which player holds colt and knife. This frame will be used for creating COLT_STAND animation for player's body.
From Layout save transformed Body object or use Savetransformed displacement plugin. Save object int Frames_body folder (for example) with name like Colt_stand.lwo. In Serious Modeler open script (s shortuct).
Script should look something like:
;******* Creation settings
TEXTURE_DIM 2.0 2.0
SIZE 1.0
MAX_SHADOW 0
HI_QUALITY YES
FLAT NO
HALF_FLAT NO
STRETCH_DETAIL NO

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo

;******* End of animation block
ANIM_END

END
Every animation needs name and pointer to files, to create Colt_Stand animation, select this part of script
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo
and paste it after Body.lwo line.
Change path,animation name and name of object that is animation. After editing script should look like this:
;******* Creation settings
TEXTURE_DIM 2.0 2.0
SIZE 1.0
MAX_SHADOW 0
HI_QUALITY YES
FLAT NO
HALF_FLAT NO
STRETCH_DETAIL NO

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Body.lwo

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body
ANIMATION Colt_Stand
SPEED 0.1
    Colt_Stand.lwo

;******* End of animation block
ANIM_END

END

Click on CTRL SHIFT S to recreate model (add animation to model). Every time you add or remove something from model's script you need to recreate model. If you update frames in animation or animation's speed you can update model without recreating. Once model is recreated, cycle thru animations (curently 2) with Cursor Up and Cursor Down. For now there arent much to see. Next we will add colt redraw animation. This is animation when player changes weapon (from colt to shotgun or similar). To save on filesize (and speed up animation creation process) and to demonstrate Modeler's scripting strenght, we will use same frames for draw and redraw animation. Image51 shows few frames from Redraw animation (10 frames long).

Image51

Use savemorph displacement plugin or manualy export frames (painfull) from Lightwave.
Open model's script and add lines:
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body\Colt_Redraw\
ANIMATION Colt_ReDraw
SPEED 0.12
01.lwo
05.lwo
10.lwo

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\Frames\Frames_Body\Colt_Redraw\
ANIMATION Colt_Draw
SPEED 0.12
10.lwo
05.lwo
00.lwo
after
    Colt_Stand.lwo
line.
Speed line defines speed of every frame in animation. If you have 3 frames and speed is 0.12, whole animation will be 0.26 seconds long. Second animation, Colt_draw is done using same frames as Redraw animation but with sequence inverted. This feature of Serious Modeler allows adding more animations but keeping filesize small. Click on CTRL SHIFT S to recreate model (add animation to model). In animation control panel you have now 4 animations. Select Colt_Redraw animation and press Enter shortuct to play this animation looping (Shift Enter) plays animation only once. While animation is playing, in Animation tab of Tools panel change animation frames speed to see different behaviour (Image52).

Image52

This number will be saved in model once its saved, but wont be saved in model's script (replace value in script with new one and update model's animations).
Press Enter again to stop animation. With Shift Cursor Up and Shift Cursor Down you can jump to first/last animation in model.
With Shift Cursor Left and Shift Cursor Right you can jump to first/last frame in current animation.
Continue adding other animations. When you make animations for certain weapon, like shotgun, enable its visibility in atachment tab for visual guide.Save model

Load player model and repeat adding animations setup we did for body. If all went ok, you should have model fully animated (Image53) and ready for adding another 2 collision boxes (swim and death).

Image53

Select "Crouch" animation from Animation control panel, in Attachment tab select any of Body's stand animation (Image54).

Image54

For visual guide, enable virtual floor rendering (f shortcut). Go to Collision tab in Tools panel and add new collision. Name it CROUCH, press c to enable collision box rendering. Leave Width to default 1.0 meter, change Height to something like 1.5 or 1.6 meters.

Image55

We need to add one more collision, Swim collision box.
Select "Swim" or "SwimIdle" animation from Animation control panel, in Attachment tab select any of Body's swom stand animation (Image56).

Image56

Click on Add button in Collision tab to add new collision box, name it SWIM. Click on checkbox left from H=W. What it means is that Serious Modeler will apply same values you type in for Width, to Height parameter. Change Width and Lenght to 1.5 and in DY field type -0.75. This means that virtual collision box will be centered 0.75 bellow ground with diameter of 1.5 meters (Image57).

Image57

With all collision boxes setup, we can go now on creating and adding LOD to models.
LOD, Level Of Detail is strong feature of Serious Engine. As model is in distance from viewer less detail on it is actually seen so those details dont need to be drawn and have impact on Engine's performance i.e. if model have teeth modeled (with many polygons) and its far away from viewer those teeth looks like few pixels on screen and they can be removed.
MipModels are created in 3d application or by using Automatical mip modeling tool in Serious Modeler. Mipmodels once imported and added are saved inside model, there is no need for extra models representing mips. When making mipmodels in 3d apllication, you have more control in removing vertices and polygons. However there are few rules in creation of mipmodels (although they might look like limitation, they help maintaining filesize smaller and rendering faster).
1) When making mipmodels, vertices on model must not be moved or added, they only can be deleted.
2) In mipmodels polygons can be retripled and new added, but adding new surfaces isnt allowed (it will be ignored).
3) Serious Modeler recalculates mapping on mipmodels, based on main model's mapping, there is no need to adjust mapping in mipmodels.
Depending on model's polygon count, choose number of mipmodels (up to 32). For this model we will make 5 mipmodels (with 0th, highest polygon count it will be 6).
Removing polygons/vertices in mipmodels doesnt need to be linear, if 0th mipmodel have 1000 triangles, make 1st with 900, 2nd with 650, 3rd with 350, 4th with 200 and last with 60 or less triangles.
Load player.lwo in Lightwave Modeler. Observe object, try zooming out and determine which polygons/vertices can be removed for 1st mip. Its good practice to leave vertices needed for good looking animations, in many mipmodels as possible, like elbow joints, knee caps, feet.. and remove those vertices that are rather decorative (buckle on vaist, fingers on hands...). For legs, i decided to remove vertices on thighs and on heel, beltbuckle... Zoom into thigh, select vertex numbered 1, then select vertex numbered 2 and press CTRL W to weld those points (Image58).

Image58

Repeat that for other leg. Weld few more unneccesary points. In statistic panel (w) select all polygons with 2 vertices and delete them (otherwise you will be prompted with error message when importing those mipmodels in Serious Modeler). Save this object as player_mip01.lwo or something meaningfull. Create other mip models from mip01 and save them as mip02, mip03... On Image59 player object and its mipmodels are shown.

Image59

Note: There are plugins, available for Lightwave, suitable for creating mipmodels, like PolygonEater, Decimate, Polygon cruncher and other. All those plugins will do very good job, but from personal expirience, best way to create them is to manualy weld and merge vertices, you will have more control over removing.
Load Player model in Serious Modeler and open script. Examine section titled Mip Models:
;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo
When ever you create model 1 mipmodel will be added. Its created from object model is created from. You need to tell Modeler how many mipmodels there will be. Change value MIP_MODELS value from 1 to number of mipmodels you created+1 (0th). Under Body.lwo line type in names of mipmodels. After editing, script should look like this:
;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 5
    Player.lwo
    Player_Mip01.lwo
    Player_Mip02.lwo
    Player_Mip03.lwo
    Player_Mip04.lwo
Save script and recreate model. After few secs, model will be ready. Save model. If you examined size of model before and after adding mipmodels, you will notice that model is bigger now. Adding many mipmodels will speed up rendering but can have impact on memory. Balance well, remove mipmodels, rearange polygon count until you are satisfied.
Open Tools panel and select Mip Tab (Image60).

Image60

Number of usefull information can be found in that tab. It will also be used as guide when adjusting mipswitching distances.
Press o shortcut to acess manual mipswitching mode. Use [ and ] to cycle thru mipmodels we added. Note how values in Mip tab change and how mipmodels have effect on global model look.
All we have to do now is to adjust mipswitching distances. Its distance from view when model switch from more to less polygons or viceversa.
Hold CTRL SHIFT RMB and move mouse up. Watch Distance value in Mip tab and when it reaches 10 meters release RMB. We have created 1st mipswitch. Press Backspace to reset model's position, press SPACE RMB and move mouse up. When Distance reaches 10 meters, mipmodel will switch. Thats how it will behave in game, when model is 10 meters from viewer it will be in 1st mip. Hold CTRL SHIFT RMB and move mouse up again until Distance value is 18 meters. We created 2nd mip. Repeat this for 3rd (35 meters), and 4th mip (90 meters). Last (5th) mip should be visible from distance of 90 meters to 1000 meters. Since its mip with lowest polygon count, it wont have high impact on rendering. 5th mip is last one, after 1000 meters, model wont be seen at all. Play with mip switching distances and look its impact on rendering in game.
The reason we added mipmodels as last part is when you recreate model to add mipmodels, surface properties and mipswitching distances are reset or not inherited. We added specular and transparency when we created player model. Those parameters arent saved in mipmodels (Image61a).

Image61a

To fix that we use manual mipmodels switching and Rendering panel. In rendering tab find surfaces we set specular on, and press RMB on color picker (Image62).

Image62

Select "Copy color" to copy color value into memory buffer. Press o to enter in manual mipmodel switching mode. Use [ to select next mipmodel, mipmodel number should change. Select all surfaces (using Link surfaces panel,Z) you want to edit, click on DoubleSided, select Transparent as blending mode, click on Specularity. Another thing we need to do is to paste specular color. Click with RMB on color picker bellow Specularity and select "Paste color". You should end with something like Image63. Dont forget to set attachment triangle's surface as inivisible also. Repeat this for other mipmodels.
Image63

Note: In higher mipmodels (3rd, 4th ...) you dont have to put specular, doublesided or reflection properties. It will speed up rendering, those properties arent seen in large distances anyway.

Same as we did for player, create mipmodels for Body and Head models. When you create mips for all models, load player model and press ALT R to acess global rendering options(Image61).

Image61

Bordered red are models informations, number of models, polygon count and sounds attached to that model. Press SPACE RMB and move mouse up, as model is further away, mips are switching. We are ready now to create .amc files and test our model in Serious Sam.


Tutorial 01: Modeling

Importing player into Serious Sam

Besides model and texture files, Player model needs 2 .amc (attachment model configuration) files, description .des and Tumbnail .tex to be succesfuly imported in Serious Sam.
First .amc file controls player model itself. Bellow Stainless Steve's .amc file is listed.

Name: Stainless Steve					-name of model
{								-beggining of model definition
  Model:   TFNM Models\Player\EmptyEd\Player.mdl	-path to player legs model
  Texture: TFNM Models\Player\EmptyEd\Player.tex	-path to player legs texture
  Specular:TFNM Models\SpecularTextures\Medium.tex	-path to specular texture (if used, otherwise this line can be omitted)
  Animation: 1			-legs animation, used in player browser preview (read this from Player.h file)

  Attachment: 0			-first attachment on Player.mdl (should be Body model, Body.mdl)
  {
    Model:   TFNM Models\Player\EmptyEd\Body.mdl	-path to player Body model
    Texture: TFNM Models\Player\EmptyEd\Body.tex	-path to player Body texture
    Specular:TFNM Models\SpecularTextures\Medium.tex	-path to specular texture (if used, otherwise this line can be omitted)
    Animation: 13			-body animation, used in player browser preview (read this from Body.h file), should match weapon used in Preview

    Attachment: 0			-first attachment on Body.mdl (should be Head model, Head.mdl)
    {
      Model:   TFNM Models\Player\EmptyEd\Head.mdl	-path to Head model
      Texture: TFNM Models\Player\EmptyEd\Head.tex	-path to Head texture
      Specular:TFNM Models\SpecularTextures\Medium.tex -path to specular texture (if used, otherwise this line can be omitted)

      Attachment: 0			-first attachment on Head.mdl, this attachment is not required
      {
        Model:   TFNM Models\Player\EmptyEd\Brain.mdl	-path to Brain model
        Texture: TFNM Models\Player\EmptyEd\Brain.tex	-path to Brain texture
    }

    }
    PreviewOnly 			-weapon definition used in Player browers
    {

      Include: TFNM Models\Weapons\Laser.amc	-path to weapon's amc

    }

  }
}
With .amc files, variaty of Player models can be created, you can mix different legs,torso and head models, with different textures and have low memory consumption.
Animation defined in .amc file dont have to be animation used in game, you can add additional animation at the end of animation list in model and use that animation for preview in Player browser.
Next needed file is Description file .des. It consists of 2 lines, first line contains name used in Player model browser. Second line (not required) is description for Player browser window.
Stainless Steve
100% Chromium, 0% Brains
Tumbnail (.tex) is image file, used as tumbnail in Player browser window. It should be 256x256 image. You can create it in Serious Modeler or Editor (create new texture). Name must be PlayerNameTbn.tex (like StainlessSteveTbn.tex)

Stainless Steve Tumbnail

Now that we have all files ready, copy needed .mdl and .tex to folder you listed in players .amc file (like Models\Player\EmptyEd\). Copy .amc, .des and tbn.tex to Models\Player folder where Serious Sam is installed.
Run Serious Sam. Click on Options button in Main menu.
Image64

Select Player and controls menu.

Image 65

Click on window with active player model to access Player browser.

Image 66

In Player browser, click on name of player model you want to set as active player.

Image 67

Game will return to Player profile menu, active player will be one you selected in Player browser.
If something is misconfigured in .amc files or files are missing, error will be reported in console (accesse with F1 or `). Simple copy missing files or adjust .amc files and select Player model again. You dont need to exit game.

Image 68

Run any of game's modes to test Player model. 3rd person view is activated with h shortcut.

Player in game

Use that view to check model and animations in game. If you change something on model(texture), simply copy changed models/textures over old ones.
If you plan to release your Player model, dont forget to pack all needed files (mdl, tex, .amc) in archive.
Good Luck!


Tutorial 01: Modeling

Creating level of detail (LOD)

With all collision boxes setup, we can go now on creating and adding LOD to models.
LOD, Level Of Detail is strong feature of Serious Engine. As model is in distance from viewer less detail on it is actually seen so those details dont need to be drawn and have impact on Engine's performance i.e. if model have teeth modeled (with many polygons) and its far away from viewer those teeth looks like few pixels on screen and they can be removed.
MipModels are created in 3d application or by using Automatical mip modeling tool in Serious Modeler. Mipmodels once imported and added are saved inside model, there is no need for extra models representing mips. When making mipmodels in 3d apllication, you have more control in removing vertices and polygons. However there are few rules in creation of mipmodels (although they might look like limitation, they help maintaining filesize smaller and rendering faster).
1) When making mipmodels, vertices on model must not be moved or added, they only can be deleted.
2) In mipmodels polygons can be retripled and new added, but adding new surfaces isnt allowed (it will be ignored).
3) Serious Modeler recalculates mapping on mipmodels, based on main model's mapping, there is no need to adjust mapping in mipmodels.
Depending on model's polygon count, choose number of mipmodels (up to 32). For this model we will make 5 mipmodels (with 0th, highest polygon count it will be 6).
Removing polygons/vertices in mipmodels doesnt need to be linear, if 0th mipmodel have 1000 triangles, make 1st with 900, 2nd with 650, 3rd with 350, 4th with 200 and last with 60 or less triangles.
Load player.lwo in Lightwave Modeler. Observe object, try zooming out and determine which polygons/vertices can be removed for 1st mip. Its good practice to leave vertices needed for good looking animations, in many mipmodels as possible, like elbow joints, knee caps, feet.. and remove those vertices that are rather decorative (buckle on vaist, fingers on hands...). For legs, i decided to remove vertices on thighs and on heel, beltbuckle... Zoom into thigh, select vertex numbered 1, then select vertex numbered 2 and press CTRL W to weld those points (Image58).

Image58

Repeat that for other leg. Weld few more unneccesary points. In statistic panel (w) select all polygons with 2 vertices and delete them (otherwise you will be prompted with error message when importing those mipmodels in Serious Modeler). Save this object as player_mip01.lwo or something meaningfull. Create other mip models from mip01 and save them as mip02, mip03... On Image59 player object and its mipmodels are shown.

Image59

Note: There are plugins, available for Lightwave, suitable for creating mipmodels, like PolygonEater, Decimate, Polygon cruncher and other. All those plugins will do very good job, but from personal expirience, best way to create them is to manualy weld and merge vertices, you will have more control over removing.
Load Player model in Serious Modeler and open script. Examine section titled Mip Models:
;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1
    Body.lwo
When ever you create model 1 mipmodel will be added. Its created from object model is created from. You need to tell Modeler how many mipmodels there will be. Change value MIP_MODELS value from 1 to number of mipmodels you created+1 (0th). Under Body.lwo line type in names of mipmodels. After editing, script should look like this:
;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 5
    Player.lwo
    Player_Mip01.lwo
    Player_Mip02.lwo
    Player_Mip03.lwo
    Player_Mip04.lwo
Save script and recreate model. After few secs, model will be ready. Save model. If you examined size of model before and after adding mipmodels, you will notice that model is bigger now. Adding many mipmodels will speed up rendering but can have impact on memory. Balance well, remove mipmodels, rearange polygon count until you are satisfied.
Open Tools panel and select Mip Tab (Image60).

Image60

Number of usefull information can be found in that tab. It will also be used as guide when adjusting mipswitching distances.
Press o shortcut to acess manual mipswitching mode. Use [ and ] to cycle thru mipmodels we added. Note how values in Mip tab change and how mipmodels have effect on global model look.
All we have to do now is to adjust mipswitching distances. Its distance from view when model switch from more to less polygons or viceversa.
Hold CTRL SHIFT RMB and move mouse up. Watch Distance value in Mip tab and when it reaches 10 meters release RMB. We have created 1st mipswitch. Press Backspace to reset model's position, press SPACE RMB and move mouse up. When Distance reaches 10 meters, mipmodel will switch. Thats how it will behave in game, when model is 10 meters from viewer it will be in 1st mip. Hold CTRL SHIFT RMB and move mouse up again until Distance value is 18 meters. We created 2nd mip. Repeat this for 3rd (35 meters), and 4th mip (90 meters). Last (5th) mip should be visible from distance of 90 meters to 1000 meters. Since its mip with lowest polygon count, it wont have high impact on rendering. 5th mip is last one, after 1000 meters, model wont be seen at all. Play with mip switching distances and look its impact on rendering in game.
The reason we added mipmodels as last part is when you recreate model to add mipmodels, surface properties and mipswitching distances are reset or not inherited. We added specular and transparency when we created player model. Those parameters arent saved in mipmodels (Image61a).

Image61a

To fix that we use manual mipmodels switching and Rendering panel. In rendering tab find surfaces we set specular on, and press RMB on color picker (Image62).

Image62

Select "Copy color" to copy color value into memory buffer. Press o to enter in manual mipmodel switching mode. Use [ to select next mipmodel, mipmodel number should change. Select all surfaces (using Link surfaces panel,Z) you want to edit, click on DoubleSided, select Transparent as blending mode, click on Specularity. Another thing we need to do is to paste specular color. Click with RMB on color picker bellow Specularity and select "Paste color". You should end with something like Image63. Dont forget to set attachment triangle's surface as inivisible also. Repeat this for other mipmodels.
Image63

Note: In higher mipmodels (3rd, 4th ...) you dont have to put specular, doublesided or reflection properties. It will speed up rendering, those properties arent seen in large distances anyway.

Same as we did for player, create mipmodels for Body and Head models. When you create mips for all models, load player model and press ALT R to acess global rendering options(Image61).

Image61

Bordered red are models informations, number of models, polygon count and sounds attached to that model. Press SPACE RMB and move mouse up, as model is further away, mips are switching. We are ready now to create .amc files and test our model in Serious Sam.


Tutorial 01: Modeling

Modeling and preparing models
Steve

Multiplayer models in Serious Sam are multipart models, consisting at least of 3 models: Player (representing legs), Body (representing torso) and Head (representing head, helmet or whatever). Since Serious Engine supports recursive, hiearchical approach to "attaching" (joining/parenting more models in single entity), additional models can be added and controled via powerfull scripts (.amc, attachment model configuration file).

Note: tutorial will be conducted in Lightwave v6.5, though any 3d application supported by Serious Modeler can be used.

Lets start with loading player legs player.lwo into Lightave Modeler.
Image01

There are few things to note, when creating player model, object should be rested on ground, because Engine treats ground plane as 0 on height. Another thing, on player model body will be attached. Serious Modeler needs so called attachment triangle to know where to add body model on player model.
Another rules: all polygons in object that is imported must be triangles (error message will be display warning you about nontriangle polygons existing in object).
Image02

Image02 shows this triangle positioned on object. It wont render in game (will be set as ignored in Modeler's rendering menu), but it will be used as guide when player model is animated.
Same as adding triangle for body, more triangles can be added for additional attachments, like knee caps, tail etc... All those additional model can be attached on single triangle, but since "attachment triangle" isnt rendered in game, the more triangles you add, the more control you have.

Next part is assign UV data on object. With latest build of Serious Engine, Modeler supports more than 1 UV map per model. When 3d object is imported in Serious Modeler, multiple UV maps will be merged in single (1st one) UV map. Though it may be handy to have multiple UV map per object, working with only one will eliminate possible problems.
When importing 3d object in Serious Modeler, there are few rules to follow regarding surfacing (assigning materials). Since assigning UV data means flatening and unfolding object mapping, seams will be created. Take look a Image03,
Image03

it shows disc cylindrical UV mapped with checker texture applied. Yellow selected polygons represent seam in UV map. This is place where so called stich is created, where uv mapping isnt continued. If we assign single surface(material) to this object and try to import it in Serious Modeler, mapping wont be imported properly. This is shown in image04.

Image04

You can see selected with white outline texture stretched to 1 pixel on object and mapping that doesnt look exact like in Lightwave. Reason for that is with single surface/material assigned, you have 1 geometry vertex with more than 1 coordinate in UV map., i.e. there are more than 2 texture cooredinates in same surface/material with same UV valueattached to single geometry vertex. Image 05 shows those vertices on object and in mapping. Image05 shows 2 vertices on object with 4 mapping coordinates.

Image05

This mapping isnt supported in Serious Modeler, but there is an easy solution for that. All you need to do when come to such problem is to add new surface/material with same UV data to polygons on border of mapping (seam polygons). In Lightwave 6.x best way to find and select those polygons is to use "Select UV seam" function. Image 06 shows 2 surfaces with same UV map assigned to object.

Image06

When you recreate disc model in Serious Modeler, mapping wont be stretched or wrong. Take a look at image07, 2 surfaces has been assigned on disc model and model is recreated.

Image07

When uv mapping, you can work with object with single surface to ease process of creating mapping and then assign surfaces.

In low poly modeling, biggest chalenge when it comes to UV mapping is compromise between stiches in mapping (easier to map object with many stiches) and texture stretching. Consult your skin artist where to create stiches and where to have possible texture stretching. It is good to know what part of model will be less visible and create stiches in mapping there (like inside of arm, bottom of body or bottom part of head). Avoid creating stiches or texture stretching on muscles and highly visible parts of object like torso, face....
Another thing to have in mind is that object dont need to have proportional mapping, for example arm can occupy more space in mapping than bottom of torso, though it can sometimes lead to problems if face and head sides occupy different space in mapping, it will be hard to adjust continuity when texture is draw.


Tutorial 01: Modeling

UV Mapping, texturing and creating .mdl file

Lets get back to our player object. On this model, legs are symetrically modeled and will have same texture applied on them. Same is with boxes around vaist and feet. Save object or make copy of it in another layer (Lightwave specific). Delete object parts that are symetrical. After cuting and layer aragment i left with situation like on Image08.

Image08

Next step is to surface parts that will be separatelly mapped (like belt, leg, belt buckle, foot) for easier selecting and manipulating. In image09 you can see i assign different surfaces on different parts and arranged them in layers.

Image09

Ill first map ammoboxes that are placed around vaist (cyan color in Image09). I decided to make seam in back of boxes (polygons that are oriented inside body, because they wont be seen at all. Knowing rule about mapping and importing in Serious Modeler i assign another surface for polygons back (Image10).

Image10

Since most of polygons in box are faceted in X axis, apply planar UV mapping with X axis selected (Image11).

Image11

Change name of UV map and leave other options as default. In surface editor, select those 2 surfaces and add UV projection for Color chanel (Image12).

Image12

I have prepared checker texture (quadratic red-white checker) for mapping testing. When you apply it as texture map on object, you can easily check mapping stretching or wierdness in mapping. Check Image13, with checker texture applied, you can see how mapping is shrinked on U axis in mapping window (right window). To corect that, put mouse pointer in UV window, activate stretch tool (h), click LMB and drag mouse to right until checker in mapping becomes quadric.

Image13

With planar uv mapping, some stretching in mapping occured. Image14 shows stretching on polygons that are ortogonal or under large angle to axis you are mapping on.

Image14

To correct that, select 3 points on top in mapping and move them up (Image15).

Image15

Repeat same for bottom and side polygons which are stretched.

Another approach you can take to avoid stretching is to detach top and bottom polygons. Image16 shows box mapped with polygons detached. With this mapping, stretching is avoided but seams in mapping are created.

Image16

Next step involves mapping of leg. Leg in this case is extracted from rest of object so it can be mapped cylindrically (Image17).

Image17

Apply cylindrical UV mapping (Y axis), leave other options as default. In Surface editor apply to leg's surface UV projection, with correct vmap name and texture (checker for testing). Mapping is stretched on some places, maybe squished, but its easy curable. When you assing UV coordinates, Lightwave tends to lock some vertices from moving. Image18 shows those vertices.

Image18

Though they appear in mapping, you cant move them or edit, unless you unweld them. Select polygons that include those points (row of polygons left of them) and run "unweld" tool. It will detach points and allow their manipulation. This comes crucial when adjusting mapping or moving parts of mapping somewhere else. When fixing mapping, i have 2 window viewport setup, left is perspective with texture, right is UV Texture window. In left window select polygons that have stretched texture and those polygons will be selected in UV map also. Activate drag tool or move tool and move points in mapping to adjust positions. If checker on polygons is to small, it means those polygons have to much space in mapping, same if checker is to big, there are to less space in mapping for those polygons. For leg, i decided to have seam inside of leg, which is hardly seen anyway. With Lightwave UV edit features, editing (adjusting positions and eliminating stretching) of mapping is a lot easier.Image19 shows seam inside of leg. When happy with adjusting merge vertices (it wont mess your mapping).

Image19

Same as we did for ammobox, we need to do for leg, we need to add new surfaces on seam so leg will be properly imported in Serious Modeler. Select polygons on seam (Image20) and add new surface on them (like LegSeam).

Image20

You need to assign Uv projection in surface editor on newly created surface (Image21).

Image21

Copy this object, paste it into new document and save it as legtest.lwo. Create new model in Serious Modeler from this object. Image22 shows mdl created with corect mapping.

Image22

Repeat process of mapping for other parts of object and arange mapping so there are no big gaps between mapping vertices, like on Image23.

Image23

On image24 you can see object surfaced and ready to be mirrored and saved for importing. To show more clearly importance of proper surfacing, i resurfaced object so seams can be easy visible.

Image24

After assigning surfaces its time to mirror leg part. Select polygons (surfaces) in leg and mirror them on Z axis. If object is symetrical, points should be merged automatically. Image25 shows object mirrored and ready for importing in Serious Modeler.

Image25

In Serious Modeler from file menu (or CTRL N shortcut) select New and point to player.lwo object. Object should be imported, save it with CTRL S shortcut (or Save from File menu). Press m shortcut to open mapping window. There you can check is mapping imported properly. Image26 shows Player model and mapping window.

Image26

When you import 3d object in Serious Modeler, in object's folder, script file (.scr) with object name is created. From Serious Modeler you can acess and edit script by pressing s shortcut. Bellow is script created for player model.
;******* Creation settings
TEXTURE_DIM 2.0 2.0		-dimension of texture for model in texels.
SIZE 1.0			-model stretch, higher number, the bigger model in meters.
MAX_SHADOW 0			-shadow quality
HI_QUALITY YES		-high quality means lower compression and less distortion on model
FLAT NO			-use this option for plane models that will be used as explosions, smoke effects..
HALF_FLAT NO			-use this option for plane models that will be used as torches, fire effects....
STRETCH_DETAIL NO		-if model is stretched, you can stretch its bump/detail texture

;******* Mip models
DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
MIP_MODELS 1			-number and list of LOD models created for this model
    Player.lwo

ANIM_START
;******* Start of animation block

DIRECTORY Models\Tutorials\Tutorial01\Player\StainlessSteve\
ANIMATION Default
SPEED 0.1
    Player.lwo		-default animation, created by default once object is imported in Modeler.

;******* End of animation block
ANIM_END
END
When creating model from 3d object, if texture (.tex) with object name exists (like player.tex) it will be automatically loaded. Otherwise you need to add it manualy. To test model and its mapping lets create and add checker texture we used in Lightwave as mapping guide. Click CTRL SHIFT T shortcut or from Texture panel click on Create new texture button. Menu with 3 options will open (Image27).

Image27

From there you can select to create:
"Normal texture" -single image texture (with alpha chanel or without), used for maping weapon, player and similar models.
"Animated texture" -image sequence used for explosions, smoke or particle effects.
"Effect texture" -procedural texture used for water, fire, waterfall and similar effects.

For this model we wil use Normal texture, click on Normal texture button or n shortcut. Requester will open asking you to select .tga image that will be converted into .tex file suitable for Serious Modeler. Double click on checker texture in requester, additional properties will be presented for you (image28).

Image28

Left in panel texture is displayed, size in meters coresponds to TEXTURE_DIM variable in model's script (if size in meters is smaller than TEXTURE_DIM, texture will tile on model, If size is bigger, texture wont whole fit on model's mapping). Mip maps tels how many mipmaps to create for this texture. Mipmaps are way to scale texture's dimension down when model with that texture is moving away from viewer. Sometimes you want to create only one mipmap (for textures that will be used as fake lightsources) to prevent bilinear algorithm in destroying texture content. When texture have alpha chanel, its quality is reduced in expence of memory it occupies. If quality isnt satisfactory check on "Preserve 32-bit quality" checkbox and texture will be saved as 32bit but it will take more memory. Use this on textures with gradients or alpha chanels, like Background textures, explosion effects and similar. In bottom of panel is "Use chequered background" button, usefull when checking texture's alpha chanel.
Click on "Create" button,texture will be created and loaded on model (image29). Save model to preserve texture's path into model file.

Image29

In Texture panel, texture name will appear. You can add as many textures as you want, they will appear in texture panel for browsing, or use PageUp, PageDown shortcuts to browse thru loaded textures. Rotate and examine model (check Navigation part in Serious Modeler). If you make any changes to object, simply recreate model (CTRL SHIFT S). Change rendering options (wireframe,surfaces...) to examine model. If you are happy with how model looks, its time to export mapping into tga file for texture painting (though it can be done in any 3d application). Serious Modeler's export mapping offers additional options. From File menu select "Export for skinning option", requester will open asking you give name of to be saved image. After that Exporting properties panel opens (image30).

Image30

On top path and name are displayed. With "Picture size" you can define pixel size of texture. Paper color defines background color, while Wire color defines color of wirframe mesh. Additionaly insted of empty wireframe, mapping can be flatfiled with surface color. Wireframe enables wireframe mapping to be saved. If you select "Surface numbers" option, text file with numbers and surface names will be saved and numbers will be added above surfaces in mapping texture. Image31 shows exported mapping for player model.

Image31

Create new texture from this image for easy editing. Load that image into your paint program and paint model's texture in it. When you finish painting or want to check paint progress,save image and in Serious Modeler click CTRL SHIFT R shortuct to recreate texture. It will load image from disk that texture is created from and update texture.
Its time to take a look at rendering and texture blending options available in Serious Modeler. Image32 shows texture made for this model.

Image32

In mapping view you may noticed holes in texture (where grey background is visible). This is because texture have alpha chanel, Modeler automaticaly displays texture with alpha chanels. We will now apply alpha chanel blending on model using per surface blending. Click Q shortcut to open Tools panel and click on Rendering tab (for more information check Tools window part of Serious Modeler Help).

Image33

This model is designed to have transparent parts of its geometry (thus texture with alpha chanel). Serious Modeler have per surface editing approach for texture blending and rendering options. This means that you can assign number of surfaces in your 3d program and individualy or multiple edit them in Serious Modeler.
In rendering panel you can cycle thru defined surfaces with Tab and Shift Tab shortcuts. Lets start with legs first, cycle in rendering tab until Leg surface (or how you called it in 3d program) becomes active. Another approach is to run Link surfaces tool (Z) shortcut and select multiple surfaces for editing (Image34).

Image34

Select surfaces you want to edit and press OK. In Rendering panel name of active surface will change to number of select surfaces. Quick check selection by clicking on invisible button (they wont render). Disable invisible option, for Transluscency select Transparent option (use alpha chanel). Also enable Double sided option. Model should look like on Image35.

Image35

Another thing we want to add on model is specular texture (since model have metalish texture, specular and reflection effects are calling). With leg surfaces selected, in Rendering panel check on Specularity buton. Nothing changes since we dont have Specular texture loaded. You can create your own specular texture, or loaded predifined one (for more on Specular texture check Add Specularity section in Serious Modeler Help. Click on "Browse specular texture" in FX control panel and load Medium.tex from models/SpecularTextures/ folder.

Image36

Hold Shift Both mouse buttons and rotate mouse to roate light around model and see how specularity changes on model. You can also hold Space Both mouse buttons to rotate model and see specular effect.

Image37

By default specular color and strenght is white. For this model we will change it to more orange color (to simulate sun reflacting on metal). Use HSV sliders bellow specularity or double click on white box to change color. We ended with something like on Image38.

Image38

Same as we add specular we can add reflection or bump. Note that every of those effects have impact on rendering time !

Next step is adding Colision properties.
In Tools panel click on Collision tab and press c short to enable collision box rendering (For more information on collision refer to Collision box section in Serious Modeler Help). Image39 shows default collision created with model.
Image39

For multiplayer models, 3 collision boxes are needed. Change PART_NAME line to STAND (this will represent collision when player is runing, walking etc...). Also change Height to 2.2 (numbers here are arbitrary, you can change them to fit your model). Collision represents collision of whole model not just legs. Another 2 collision will be added once we add all attachments and animations.


;			 >>> HeadMan <<<		<-- name of model read from 3d geometry file
;********* Model settings
DIRECTORY Models\Help\Modeler\HeadMan\			<-- main folder where all neccessary files should reside

TEXTURE_DIM 2.0 2.0					<-- defines texture dimension
TEXTURE HeadMan.tex					<-- name of difuse texture created in modeler
;TEXTURE_REFLECTION HeadManR.tex			<-- name of reflection texture created in modeler
;TEXTURE_SPECULAR HeadManS.tex				<-- name of specular texture created in modeler
;TEXTURE_BUMP HeadManB.tex				<-- name of bump texture created in modeler
MAPPING HeadMan.map					<-- name of maping file

HI_QUALITY NO						<-- model can have 2 quality settings when created 							(vertex coordinates can be saved in 8 and 16bit 							precission quality). When created in HI_QUALITY NO setting, vertex coordinates arent stored in maximal precission quality that can affect look of model when rendered (some jolting and jittering can occur in animations) but model occupies less memory once loaded. If model is created in HI_QUALITY YES mode precission is 256 times bigger and there are no vertex distortion but memory occupied is twice larger.

SIZE 1.0						 <-- size of model to appear in Modeler and Engine (if model is 2x2 meters with SIZE 1.0 setting model will be rendered in its original size). If you want to make model smaller adjust its size to less than 1.0 (same applies if you want to make model bigger).
MAX_SHADOW 0						 <-- determines how quality will shadow of this model appear (0 means it will be in highest quailty, 2 for example means it will be twice less quality in contrast to mipmodels and 100 means it wont have any shadow cosue it means its shadow casted from last mipmodels which contains no polygons to cast shadow)

FLAT NO							  <-- this settings should be enabled when creating models such as explosions or smokes.If model is created with this option it will allways target viewer around 360 degree of freedom.Usualy those models are created as flat plane and its normal will allways face viewer.
HALF_FLAT NO						    <-- this settings should be enabled when creating models such as torches or fire models.Model representing fire or plasma are usually flat plane and it will target  viewer only in 180 degree freedom around 1 axes.

;********* Mip models
DIRECTORY Models\Help\Modeler\HeadMan\

MIP_MODELS 1					 <-- number of mipmodels if mipmodels are made in 3d 						     application(model can have up to 32 mipmodels)
    HeadMan.lwo					 <-- if mipmodels are made in 3d application mipmodels (from higher polygon count to smaller) are listed one by one. By default only 1 mipmodel is loaded and its actual object from which model is created.

LEGACY:						; UV data are read directly from 3d object model is created from.
;DEFINE_MAPPING					<--- this section defines models mapping.
;    HeadMan_Closed.lwo				<--- same model as headman.lwo (and in mipmodel)
;    HeadMan_Opened.lwo				<--- unwelded version.
;    HeadMan_Unwrapped.lwo			<--- unwrapped (UV mapped) version.

ANIM_START					<--- this sections defines models animations.
;********* Animations
DIRECTORY Models\Help\Modeler\HeadMan\

ANIMATION Default_Animation			<-- this is default animation allways created with new model.
                            Animation structure consist of: name, speed of single frame and list of frames in animation (frame being object look in animation)
                        <-- its name can be changed in script.
SPEED 0.1					<-- this is speed (in seconds) of single frame in animation. For 						    						instance if you have 10 frames in animation and frame speed 						    						    						   						is 1.0 seconds whole animation is 10.0 seconds long.Animations 						   						can be played in 3d view of modeler and interactivly adjusted.
                        model can have unlimited number of animations with unique 						   												names that will be used in engine's AI for corect playback 						   											(along with its speed).
    HeadMan.lwo					<-- list of all frames in animation.

ANIM_END					<-- defines end of aniamtions section
END						<-- defines end of script


;************************* Texture name: Explosion		<-- name of animated texture

;************************* Texture description ...
TEXTURE_WIDTH 8.0						<-- texture size

ANIM_START							<-- animation section (texture can have more than one anim)
;************************* Animations ...
DIRECTORY Models\Effects\ExplosionRocket\			<-- path

ANIMATION Default_Animation					<-- animation name
SPEED 0.1							<-- speed of single frame
    Frame001.tga						<-- frames sequence
    Frame003.tga
    Frame005.tga
    Frame006.tga
    Frame008.tga
    Frame010.tga
    Frame011.tga
    Frame013.tga
    Frame015.tga
    Frame018.tga
    Frame020.tga
ANIM_END							 <-- end of animations section
END								 <-- end of script