Home - Forums - Documentation - Gallery - Bugs
Current revision (10:31, 22 August 2008) (edit) (undo)
 
(9 intermediate revisions not shown.)
Line 1: Line 1:
-
This article intends to breakdown the Initialisation Section of the CS world file into it's different parts in-order to explain syntax and common usage although much of this is covered in the documentation some parts are not up to date and often aren't explained properly so this article hopes to pick up where the documentation leaves of so to speak.
+
[[Category:Tutorial]]
 +
This article intends to breakdown the CS world file into it's different parts in-order to explain syntax and common usage. Although much of this is covered in the documentation some parts are incomplete and not fully explained. So this article hopes to pick up where the documentation leaves of.
-
First of all, because the CS world format has the advantage of being in an ACSII format we can open in up in a standard text editor preferably one with XML syntax highlighting for simplification. So either start a new document or open an existing world file for editing (many examples can be found in the ''CS/data/'' sub-directories)
+
First of all, because the CS world format has the advantage of being in an ACSII format we can open in up in a standard text editor (preferably one with XML syntax highlighting for simplification). So either start a new document or open an existing world file for editing (many examples can be found in the ''CS/data/'' sub-directories)
= Initialization Part =
= Initialization Part =
Line 7: Line 8:
==In the beginning...==
==In the beginning...==
-
All CS world File must start with the ''<world>'' tag and end with ''</world>''. So to start us off we'll have:
+
All CS world files must start with the ''<world>'' tag and end with ''</world>''. So to start us off we'll have:
-
<pre>
+
<source lang="xml">
-
<world>
+
<world>
-
</world>
+
</world>
-
</pre>
+
</source>
Note that if you want to make a library then just replace ''world'' with ''library''. The rest of this tutorial is also valid for libraries except that libraries can only contain textures, materials, and mesh factories and no sectors.
Note that if you want to make a library then just replace ''world'' with ''library''. The rest of this tutorial is also valid for libraries except that libraries can only contain textures, materials, and mesh factories and no sectors.
Line 18: Line 19:
==Adding a Texture==
==Adding a Texture==
-
Next we initialise which ''textures'' and materials we intend to use this is done by specifying '''VFS''' paths. '''VFS''' paths are a way of defining real paths without using Operating-System specific functions, so you must mount the directories that your ''textures'' are in on the VFS in order for them to be found.
+
Next we initialise which textures and materials we intend to use. To specify file locations in Crystal Space we always use '''VFS''' paths. '''VFS''' paths are a way of defining real paths without using Operating-System specific paths. They also allow you to directly read textures (and other files) from ZIP archives.
-
'''VFS''' (Virtual File System) paths in case you were wondering are not just ordinary file system paths but paths that CS has set to ensure multi-platform compatibility, real paths are usually mounted to VFS paths in the ''vfs.cfg'' for example /lib/stdtex is actually a zip file called stdtex.zip in CS/Data which has been mounted to /lib/ '''VFS''' path, this comes in handy as you can refer to zip files as folders just by mounting them. We start by specifying that we are talking about ''textures'' using the ''<textures>'' tag and then specify which ''texture'' we are using with the ''<texture>'' tag, and specify it's location using the ''<file>'' tag.
+
-
<pre>
+
'''VFS''' (Virtual File System) paths are not just ordinary file system paths but paths that CS has set to ensure multi-platform compatibility. Real paths are usually mounted to '''VFS''' paths in the ''vfs.cfg''. For example ''/lib/stdtex ' is actually a zip file called stdtex.zip in ''CS/data'' which has been mounted to the ''/lib/'' '''VFS''' path. This comes in handy as you can refer to zip files as folders just by mounting them.
-
<textures>
+
-
<texture name="oldmetal">
+
-
<file>/lib/stdtex/oldmetal.jpg</file>
+
-
</texture>
+
-
</textures>
+
-
</pre>
+
-
This should load a ''texture'' which can now be referred to as oldmetal from that '''VFS''' path /lib/stdtex/.
+
We start the world file initialization by specifying that we are talking about ''textures'' using the ''<textures>'' tag and then specify which ''texture'' we are using with the ''<texture>'' tag. Finally for every texture we specify it's location using the ''<file>'' tag:
 +
<source lang="xml">
 +
<textures>
 +
<texture name="oldmetal">
 +
<file>/lib/stdtex/oldmetal.jpg</file>
 +
</texture>
 +
</textures>
 +
</source>
-
Other specifics relating to special cases in ''<textures>'' such as cubemaps and key colours can be read about in the official CS documentation or refer to ''cs/data/flarge/''
+
This should load a ''texture'' which can now be referred to as oldmetal from that '''VFS''' path ''/lib/stdtex/''.
 +
 
 +
Other specifics relating to special cases in ''<textures>'' such as cubemaps and key colours can be read about in the official CS documentation or you can look at examples in ''CS/data/flarge/world''
==Adding Shaders==
==Adding Shaders==
-
''Shaders'' will come into play in the material section. But before you can use a ''shader'' in a material we have to make sure the engine knows to load it.
+
''Shaders'' will come into play in the material section. But before you can use a ''shader'' in a material we have to load the shader:
-
<pre>
+
<source lang="xml">
-
<shaders>
+
<shaders>
-
<shader>
+
<shader>
-
<file>/shader/std_lighting_detail.xml</file>
+
<file>/shader/std_lighting_detail.xml</file>
-
</shader>
+
</shader>
-
</shaders>
+
</shaders>
-
</pre>
+
</source>
==Adding Materials With Shaders==
==Adding Materials With Shaders==
-
''Materials'' are a way of applying surface properties by name not just textures. An example of this can be for example applying a pure colour with no texture.
+
''Materials'' define surface attributes. Typically materials are associated with textures but there are many other possibilities. An example of a material that is not associated with a texture is a material defining a green color:
-
<pre>
+
<source lang="xml">
-
<materials>
+
<materials>
-
<material name="green_color">
+
<material name="green_color">
-
<color red="0" green="1" blue="0" />
+
<color red="0" green="1" blue="0" />
-
</material>
+
</material>
-
</materials>
+
</materials>
-
</pre>
+
</source>
-
This would make whatever the ''material'' was applied to a green colour. But most of the time you will want to specify a texture like so.
+
Usually however, you will want to specify a texture like this:
-
<pre>
+
<source lang="xml">
-
<material name="oldmetal">
+
<material name="oldmetal">
-
<texture>oldmetal</texture>
+
<texture>oldmetal</texture>
-
</material>
+
</material>
-
</pre>
+
</source>
Another example are shaders, I will not get into shader specifics but applying a shader to a ''material'' is a simple process. Lets refer to the shader we used earlier.
Another example are shaders, I will not get into shader specifics but applying a shader to a ''material'' is a simple process. Lets refer to the shader we used earlier.
-
<pre>
+
<source lang="xml">
-
<material name="oldmetal">
+
<material name="oldmetal">
-
<texture>oldmetal</texture>
+
<texture>oldmetal</texture>
-
<shader type="standard">std_lighting_detail</shader>
+
<shader type="standard">std_lighting_detail</shader>
-
</material>
+
</material>
-
</pre>
+
</source>
-
This would apply the shader, but if we were to examine the actual shader we would notice that it also takes 2 variables which we can specify here. One is a texture that will be overlayed on the existing texture, and the other is a 2-D vector which basically shrinks down that texture to that scale.
+
This would attach the shader to the ''oldmetal'' material. But if we were to examine the actual shader we would notice that it also takes 2 variables which we can specify here. One is a texture that will be overlayed on the existing texture, and the other is a 2-D vector which basically shrinks down that texture to that scale. To use these variables we can do the following:
-
To use these variables we would do the following:
+
-
<pre>
+
<source lang="xml">
-
<material name="oldmetal">
+
<material name="oldmetal">
-
<texture>oldmetal</texture>
+
<texture>oldmetal</texture>
-
<shader type="standard">std_lighting_detail</shader>
+
<shader type="standard">std_lighting_detail</shader>
-
<shadervar name="tex detail" type="texture">oldmetal</shadervar>
+
<shadervar name="tex detail" type="texture">oldmetal</shadervar>
-
<shadervar name="detail texture scale" type="vector2">10,10</shadervar>
+
<shadervar name="detail texture scale" type="vector2">10,10</shadervar>
-
</material>
+
</material>
-
</pre>
+
</source>
-
Luckily for us this shader is a standard shader and the default ''renderloop'' already includes standard shaders, had this been another kind of shader we would have needed to change the renderloop. I decided to keep the same texture as the detail texture to avoid having to specify another texture and shrunk it by 10 UV's. If you are confused as to how i got the variable names and types, you can check ''cs/data/shaders/std_lighting_detail.xml'' for the type and names of the shader variables it takes. This is the same for all shaders.
+
Luckily for us this shader is a standard shader and the default ''renderloop'' already includes standard shaders. If this was another kind of shader it was possible that we had to change the renderloop. I decided to keep the same texture as the detail texture to avoid having to specify another texture and shrunk it by 10 UV's. If you are confused as to how i got the variable names and types, you can check ''cs/data/shaders/std_lighting_detail.xml'' for the type and names of the shader variables it takes. This is the same for all shaders.
==So Far==
==So Far==
Line 93: Line 95:
So far we have specified a simple texture, material and shader-setup which looks like this:
So far we have specified a simple texture, material and shader-setup which looks like this:
-
<pre>
+
<source lang="xml">
-
<world>
+
<world>
-
<textures>
+
<textures>
-
<texture name="oldmetal">
+
<texture name="oldmetal">
-
<file>/lib/stdtex/oldmetal.jpg</file>
+
<file>/lib/stdtex/oldmetal.jpg</file>
-
</texture>
+
</texture>
-
</textures>
+
</textures>
-
<shaders>
+
<shaders>
-
<shader>
+
<shader>
-
<file>/shader/std_lighting_detail.xml</file>
+
<file>/shader/std_lighting_detail.xml</file>
-
</shader>
+
</shader>
-
</shaders>
+
</shaders>
-
<materials>
+
<materials>
-
<material name="oldmetal">
+
<material name="oldmetal">
-
<texture>oldmetal</texture>
+
<texture>oldmetal</texture>
-
<shader type="standard">std_lighting_detail</shader>
+
<shader type="standard">std_lighting_detail</shader>
-
<shadervar name="tex detail" type="texture">oldmetal</shadervar>
+
<shadervar name="tex detail" type="texture">oldmetal</shadervar>
-
<shadervar name="detail texture scale" type="vector2">10,10</shadervar>
+
<shadervar name="detail texture scale" type="vector2">10,10</shadervar>
-
</material>
+
</material>
-
</materials>
+
</materials>
-
</world>
+
</world>
-
</pre>
+
</source>
==Addings Sounds==
==Addings Sounds==
Line 120: Line 122:
Adding sounds is much like everything else in CS, very simple. It goes something like this:
Adding sounds is much like everything else in CS, very simple. It goes something like this:
-
<pre>
+
<source lang="xml">
-
<sounds>
+
<sounds>
-
<sound name="tada.wav">
+
<sound name="tada.wav">
-
<file>/lib/std/tada.wav</file>
+
<file>/lib/std/tada.wav</file>
-
</sound>
+
</sound>
-
</sounds>
+
</sounds>
-
</pre>
+
</source>
==Adding A Library==
==Adding A Library==
-
Another way of defining almost all of these things, is the use of libraries. A library is structured very much like a world file only it starts with ''<library>'' and ends in ''</library>'' it also cannot accept start locations and sectors. It is a good way of grouping certain things for loading. Also if specifying mesh factories in a library you will be able to load them into viewmesh. To include a library in a world file we would use:
+
Another way of defining almost all of these things is through the use of libraries. A library is structured very much like a world file only it starts with ''<library>'' and ends with ''</library>''. It also cannot accept start locations and sectors. It is a good way of grouping certain things for loading. Also if specifying mesh factories in a library you will be able to load them into viewmesh. To include a library in a world file we can use:
-
<pre>
+
<source lang="xml">
-
<library path="/lib/std" file="library" />
+
<library path="/lib/std" file="library" />
-
</pre>
+
</source>
==Adding Plugins==
==Adding Plugins==
-
There are an array of plugins that need to be handled in CS, only including the ones you need is the best way to go about things.For this reason we shall only include the thing-loader and factory plugin for this example.
+
Crystal Space is very modular. As a result map loading in Crystal Space is also modular. That means that every mesh object has its own plugin that is responsible for loading. Every plugin has a specific name. You can specify that full name everytime you need it (i.e. for every mesh object). But it is often easier to specify shortcuts for every plugin that you need. This can be done in the ''<plugins>'' section:
-
<pre>
+
<source lang="xml">
-
<plugins>
+
<plugins>
-
<plugin name="thing">crystalspace.mesh.loader.thing</plugin>
+
<plugin name="thing">crystalspace.mesh.loader.thing</plugin>
-
<plugin name="thingFact">crystalspace.mesh.loader.factory.thing</plugin>
+
<plugin name="thingFact">crystalspace.mesh.loader.factory.thing</plugin>
-
</plugins>
+
</plugins>
-
</pre>
+
</source>
-
We do this to allow us to use the full potential of it's factory and mesh setup.
 
Thing meshes are usually low-poly meshes that use pre-calculated light-mapped surfaces. Their downside is that they are less efficient than a general mesh.
Thing meshes are usually low-poly meshes that use pre-calculated light-mapped surfaces. Their downside is that they are less efficient than a general mesh.
Line 158: Line 159:
The Factory/meshobject scenario is often important if you wish to repeat meshes several times. But not always necessary if you wish to just have one instance of a mesh. For this article I will be taking advantage of the Factory/Meshobject setup to better familiarize users with it.
The Factory/meshobject scenario is often important if you wish to repeat meshes several times. But not always necessary if you wish to just have one instance of a mesh. For this article I will be taking advantage of the Factory/Meshobject setup to better familiarize users with it.
-
In a factory we usually tell the engine what factory will be called, the plugin used, the geometry information and also material(s) used on the mesh. With a thing mesh we have the option of mutliple materials based on the polygons you assign it to. This factory was taken from the simple map tutorial in the documentation. It is a simple cube with a single material applied.
+
In a factory we usually tell the engine what the factory will be called (the name), the plugin that is used to load it, the geometry information and also material(s) used on the mesh. With a thing mesh we have the option of multiple materials based on the polygons you assign it to. This factory was taken from the simple map tutorial in the documentation. It is a simple cube with a single material:
-
<pre>
+
<source lang="xml">
-
<meshfact name="walls">
+
<meshfact name="walls">
-
<plugin>thingFact</plugin>
+
<plugin>thingFact</plugin>
-
<zfill />
+
<zfill />
-
<params>
+
<params>
<v x="-10" y="-1" z="10"/> <v x="10" y="-1" z="10"/>
<v x="-10" y="-1" z="10"/> <v x="10" y="-1" z="10"/>
<v x="-10" y="-1" z="-10"/> <v x="10" y="-1" z="-10"/>
<v x="-10" y="-1" z="-10"/> <v x="10" y="-1" z="-10"/>
<v x="-10" y="4" z="10"/> <v x="10" y="4" z="10"/>
<v x="-10" y="4" z="10"/> <v x="10" y="4" z="10"/>
<v x="-10" y="4" z="-10"/> <v x="10" y="4" z="-10"/>
<v x="-10" y="4" z="-10"/> <v x="10" y="4" z="-10"/>
-
<material>wood</material>
+
<material>old_metal</material>
<texlen>4</texlen>
<texlen>4</texlen>
<p name="up">
<p name="up">
-
<v>6</v> <v>7</v> <v>5</v> <v>4</v>
+
<v>6</v> <v>7</v> <v>5</v> <v>4</v>
</p>
</p>
<p name="down">
<p name="down">
-
<v>3</v> <v>2</v> <v>0</v> <v>1</v>
+
<v>3</v> <v>2</v> <v>0</v> <v>1</v>
</p>
</p>
<p name="back">
<p name="back">
-
<v>7</v> <v>6</v> <v>2</v> <v>3</v>
+
<v>7</v> <v>6</v> <v>2</v> <v>3</v>
</p>
</p>
<p name="front">
<p name="front">
-
<v>4</v> <v>5</v> <v>1</v> <v>0</v>
+
<v>4</v> <v>5</v> <v>1</v> <v>0</v>
</p>
</p>
<p name="left">
<p name="left">
-
<v>6</v> <v>4</v> <v>0</v> <v>2</v>
+
<v>6</v> <v>4</v> <v>0</v> <v>2</v>
</p>
</p>
<p name="right">
<p name="right">
-
<v>5</v> <v>7</v> <v>3</v> <v>1</v>
+
<v>5</v> <v>7</v> <v>3</v> <v>1</v>
</p>
</p>
-
</params>
+
</params>
-
</meshfact>
+
</meshfact>
-
</pre>
+
</source>
-
The first line initilises and names the meshfactory. The second tells the loader what plugin we are using in this case a thing factory becuase we are defining geometry. ''<zfill />'' is used so that the card ignores the zbuffer and draws the Z value from the thing polygons over the old Z values present on screen. This is used by the outermost walls because it is a faster mode than ''<zuse/>'' as it does not need to read the zbuffer. It will be the first thing rendered in a back2front render. The next block is actually defining the position of vertexes. This box is made up of 8 vertexes. Next is the material. We specify the material we created earlier (old metal). Now we set ''<texlen>'' to 4 meaning that for every 4*4 world units one texture will be tiled. Next we define polygons by specifying the vertices that make up that polygon but remember that vertices start to count at 0. These polygons can also have names for debugging reasons mostly but they can have other uses.
+
The first line initializes and names the meshfactory. The second tells the loader what plugin we are using (in this case a thing factory because we are defining geometry). ''<zfill />'' is used so that the card ignores the zbuffer and draws the Z value from the thing polygons over the old Z values present on screen. This is used by the outermost walls because it is a faster mode than ''<zuse/>'' as it does not need to read the zbuffer. It will be the first thing rendered in a back2front render. Everything inside the ''<params>'' block is specific to the thing mesh (handled by the thing factory loader plugin). Other meshes will have other stuff there. The next block is actually defining the position of vertices. This box is made up of 8 vertices. Next comes the material. We specify the material we created earlier (old_metal). Now we set ''<texlen>'' to 4 meaning that for every 4*4 world units one texture will be tiled. This is a shortcut to make it easier to do the texture mapping. For real models you will probably want to specify UV coordinates directly. This is easier done by using a map editor like [http://www.blender.org Blender]. Next we define polygons by specifying the vertices that make up that polygon but remember that vertices start to count at 0. These polygons can also have names which is mostly useful for debugging purposes.
-
And that brings a close to our initialisation section of a world file. In the rest of this tutorial I will tell you how to use these to create a sector in a world that can be loaded by walktest.
+
And that brings a close to our initialization section of a world file. In the rest of this tutorial I will tell you how to use these to create a sector in a world that can be loaded by walktest.
=Creating a Room=
=Creating a Room=
Line 201: Line 202:
==Starting Us Off==
==Starting Us Off==
-
Now is time for use to use those loaded resources and create a simple room runable in walktest. Now normally the definition section would probly be the largest part of the world file, luckily we only have a small amount of objects. To Start us of, no pun intended we need a Spawning position we specify it like this:
+
Now is time for use to use those loaded resources and create a simple room runable in walktest. Now normally the definition section would probly be the largest part of the world file, luckily we only have a small amount of objects. To start us of, no pun intended we need a spawning position which we specify like this:
-
<pre>
+
<source lang="xml">
-
<start>
+
<start>
-
<sector>room</sector>
+
<sector>room</sector>
-
<position x="0" y="0" z="0" />
+
<position x="0" y="0" z="0" />
-
</start>
+
</start>
-
</pre>
+
</source>
-
"room" will be the eventual name of our sector. 0,0,0 will be the coordinate in that sector in which we shall spawn (Crystal Space Does not actually care about this, it is very app-specifc the way you handle start points. You can have multiple start positions and have people spawn at different locations). Now we create and name our sector like so:
+
''room'' will be the eventual name of our sector. 0,0,0 will be the coordinate in that sector in which we shall spawn (Crystal Space Does not actually care about this, it is very app-specifc the way you handle start points. You can have multiple start positions and have people spawn at different locations). Now we create and name our sector like so:
==Creating a Sector==
==Creating a Sector==
-
<pre>
+
<source lang="xml">
-
<sector name="room">
+
<sector name="room">
-
</sector>
+
</sector>
-
</pre>
+
</source>
-
Adding our MeshObj from a Factory:
+
==Adding our Mesh Object==
-
We now have a sector called room which we can fill with whatever we want and the first thing we shall fill it with will be our Thing Factory called walls, here is how we do it:
+
We now have a sector called room which we can fill with whatever we want. We start by adding a mesh object called ''walls'' which we create from the same-named factory that we created above.
-
<pre>
+
<source lang="xml">
-
<sector name="room">
+
<sector name="room">
-
<meshobj name="walls">
+
<meshobj name="walls">
-
<plugin>thing</plugin>
+
<plugin>thing</plugin>
-
<params>
+
<params>
-
<factory>walls</factory>
+
<factory>walls</factory>
-
</params>
+
</params>
-
</meshobj>
+
</meshobj>
-
</sector>
+
</sector>
-
</pre>
+
</source>
-
As you can see we once again name the mesh this is because we need to distinguish between mesh objects sharing the same factory in case we use that factory more than once. The second line that has been added is refering to the loader plugin, do not confuse this with the factory plugin if you look at the ''<plugin>'' section we have initialised two plugins: the loaded and factory.
+
The second line refers to the loader plugin again, do not confuse this with the factory plugin. If you look at the ''<plugin>'' section we have initialised two plugins: the mesh and factory loader.
The ''<params>'' sections only needs to have a reference to our factory. If I had not used a factory this would be the section where I would place the vertex and polygon information along with the materials. And finaly we terminate our meshobj section and we're done with this part.
The ''<params>'' sections only needs to have a reference to our factory. If I had not used a factory this would be the section where I would place the vertex and polygon information along with the materials. And finaly we terminate our meshobj section and we're done with this part.
==Adding A Light==
==Adding A Light==
-
At this point if we were to load the world file with this into walktest it would work, But you would not be able to see anything. why you ask? No lights. To add a light we have the following:
+
At this point if we were to load the world file with this into walktest it would work, but you would not be able to see anything. why you ask? No lights. To add a light we add the following:
-
<pre>
+
<source lang="xml">
-
<sector name="room">
+
<sector name="room">
-
<meshobj name="walls">
+
<meshobj name="walls">
-
<plugin>thing</plugin>
+
<plugin>thing</plugin>
-
<params>
+
<params>
-
<factory>walls</factory>
+
<factory>walls</factory>
-
</params>
+
</params>
-
</meshobj>
+
</meshobj>
-
<light name="light1">
+
<light name="light1">
-
<center x="0" y="0" z="0" />
+
<center x="0" y="0" z="0" />
-
<radius>20</radius>
+
<radius>20</radius>
-
<color red="2" green="2" blue="2" />
+
<color red="2" green="2" blue="2" />
-
<dynamic />
+
</light>
-
</light>
+
</sector>
-
</sector>
+
</source>
-
</pre>
+
-
We should be able to see from this that it is named "light1" and it will be created where we spawn (0,0,0 in sector "room"). Also i've set its radius to 20. This does not mean that everything will be full bright. It only means that the light will not begin to falloff as soon. Also light values are worked out on a percentage for colours r1g1b1 (100% Red 100% Green 100% Blue) being white but also the larger numbers have greater intensity meaning this is 2x brighter than a r1g1b1 light. The Last line is preperation for the final part of this series where we will manipulate the light's colour.
+
We should be able to see from this that it is named ''light1'' and it will be created where we spawn (0,0,0 in sector ''room''). Also we set its radius to 20. This does not mean that everything will be full bright. It only means that the light will not begin to falloff as soon. Also light values are worked out on a percentage for colours r1g1b1 (100% Red 100% Green 100% Blue) being white but also the larger numbers have greater intensity meaning this is 2x brighter than a r1g1b1 light.
==Loading Your Level Into Walktest==
==Loading Your Level Into Walktest==
Line 265: Line 265:
<pre>
<pre>
-
walktest directory_for_world
+
walktest directory_for_world -relight
</pre>
</pre>
Line 271: Line 271:
<pre>
<pre>
-
walktest /this
+
walktest /this -relight
</pre>
</pre>
The reason this all works is that walktest accepts both '''VFS''' paths (the ''/this'' above) and normal paths (the ''directory_for_world''). The '''VFS''' path ''/this'' is very useful for debugging (but should otherwise be avoided) and refers to the current directory.
The reason this all works is that walktest accepts both '''VFS''' paths (the ''/this'' above) and normal paths (the ''directory_for_world''). The '''VFS''' path ''/this'' is very useful for debugging (but should otherwise be avoided) and refers to the current directory.
 +
 +
The ''-relight'' commandline option is only needed the first time in case you are using thing meshes that require static precalculated lightmaps. It will actually calculate the lightmaps. Next time you run the map you don't need to add that option unless you changed the map (moved/added a light or changed geometry).
==Sectors And Portals==
==Sectors And Portals==
-
It seems that other articles have shed away from dealing with sectors and portals, so i decided to add another sector to this tutorial.
+
It seems that other articles have shed away from dealing with sectors and portals, so we decided to add another sector to this tutorial.
Duplicate your current sector and rename it like this:
Duplicate your current sector and rename it like this:
-
<pre>
+
<source lang="xml">
-
<sector name="room2">
+
<sector name="room2">
-
<meshobj name="walls">
+
<meshobj name="walls">
-
<plugin>thing</plugin>
+
<plugin>thing</plugin>
-
<params>
+
<params>
-
<factory>walls</factory>
+
<factory>walls</factory>
-
</params>
+
</params>
-
</meshobj>
+
</meshobj>
-
<light name="light1">
+
<light name="light1">
-
<center x="0" y="0" z="0" />
+
<center x="0" y="0" z="0" />
-
<radius>20</radius>
+
<radius>20</radius>
-
<color red="2" green="2" blue="2" />
+
<color red="2" green="2" blue="2" />
-
<dynamic />
+
<dynamic />
-
</light>
+
</light>
-
</sector>
+
</sector>
-
</pre>
+
</source>
==Duplicating your Sector==
==Duplicating your Sector==
-
Currently ''room2'' is just a duplcate of ''room'', what we want is another room on the side of room, to do this we must translate out light and walls 20 units in a direction, i chose the positive X direction. To do this we add a ''<move>'' tag to our mesh object like this:
+
Currently ''room2'' is just a duplcate of ''room''. What we want is another room on the side of our previous room. To do this we must translate our light and walls 20 units in a direction. We chose the positive X direction. To do this we add a ''<move>'' tag to our mesh object like this:
-
<pre>
+
<source lang="xml">
-
<move>
+
<move>
-
<v x="20" y="0" z="0" />
+
<v x="20" y="0" z="0" />
-
</move>
+
</move>
-
</pre>
+
</source>
Which in the context of ''room2'' is as follows:
Which in the context of ''room2'' is as follows:
-
<pre>
+
<source lang="xml">
-
<sector name="room2">
+
<sector name="room2">
-
<meshobj name="walls">
+
<meshobj name="walls">
-
<plugin>thing</plugin>
+
<plugin>thing</plugin>
-
<params>
+
<params>
-
<factory>walls</factory>
+
<factory>walls</factory>
-
</params>
+
</params>
-
<move>
+
<move>
-
<v x="20" y="0" z="0" />
+
<v x="20" y="0" z="0" />
-
</move>
+
</move>
-
</meshobj>
+
</meshobj>
-
<light name="light1">
+
<light name="light1">
-
<center x="20" y="0" z="0" />
+
<center x="20" y="0" z="0" />
-
<radius>20</radius>
+
<radius>20</radius>
-
<color red="2" green="2" blue="2" />
+
<color red="2" green="2" blue="2" />
-
<dynamic />
+
<dynamic />
-
</light>
+
</light>
-
</sector>
+
</sector>
-
</pre>
+
</source>
-
Note that we also moved the light. We now have two rooms side by side, Unfortunately they are not connected at all. I did not have to separate these into seperate sectors but a constricted doorway is a good opportunity to take advantage of portals and sectors. We are going to create a floating portal as not to distrub the geometry by adding a polygon inside the face, normally adding a portal polygon to a mesh would be a better solution as that way portals line up correctly with walls, but this portal is for illustrative purposes and concepts only.
+
Note that we also moved the light. We now have two rooms side by side, Unfortunately they are not connected at all. We did not have to separate these into seperate sectors but a constricted doorway is a good opportunity to take advantage of portals and sectors. We are going to create a floating portal as not to distrub the geometry by adding a polygon inside the face, normally adding a portal polygon to a mesh would be a better solution as that way portals line up correctly with walls, but this portal is for illustrative purposes and concepts only.
==Portals==
==Portals==
-
To start off we'll place a portal from ''room'' to ''room2' because is a floating portal we will not need it nested in a meshobj so we start by adding this to the ''room'' sector (add this right before the light for example):
+
To start off we'll place a portal from ''room'' to ''room2'. Add this to the ''room'' sector (right before the light for example):
-
<pre>
+
<source lang="xml">
-
<portals>
+
<portals>
-
<portal name="port1">
+
<portal name="port1">
-
<sector>room2</sector>
+
<sector>room2</sector>
-
</portal>
+
</portal>
-
</portals>
+
</portals>
-
</pre>
+
</source>
This creates a portal that goes to ''room2'' but it is not complete. We also have to specify the dimensions of the portal (as a polygon) like this:
This creates a portal that goes to ''room2'' but it is not complete. We also have to specify the dimensions of the portal (as a polygon) like this:
-
<pre>
+
<source lang="xml">
-
<portals>
+
<portals>
-
<portal name="port1">
+
<portal name="port1">
-
<v x="9.7" y="1" z="1" />
+
<v x="9.7" y="1" z="1" />
-
<v x="9.7" y="1" z="0" />
+
<v x="9.7" y="1" z="0" />
-
<v x="9.7" y="-1" z="0" />
+
<v x="9.7" y="-1" z="0" />
-
<v x="9.7" y="-1" z="1" />
+
<v x="9.7" y="-1" z="1" />
-
<sector>room2</sector>
+
<sector>room2</sector>
-
</portal>
+
</portal>
-
</portals>
+
</portals>
-
</pre>
+
</source>
-
Once again we are not able to see the portal because our render-priorities are not currently set, meaning our zfill walls don't know they are ment to be behind our portal so for our special case we need to use the ''object'' priority like so:
+
Once again we are not able to see the portal because our render-priorities are not currently set, meaning our zfill walls don't know they are meant to be behind our portal so for our special case we need to use the ''object'' priority like so (objects with render priority ''object'' are rendered behind objects with render priority ''walls''. And the default render priority for objects with ''<zfill/>'' is ''walls''):
-
<pre>
+
<source lang="xml">
-
<portals>
+
<portals>
-
<portal name="port1">
+
<portal name="port1">
-
<v x="9.7" y="1" z="1" />
+
<v x="9.7" y="1" z="1" />
-
<v x="9.7" y="1" z="0" />
+
<v x="9.7" y="1" z="0" />
-
<v x="9.7" y="-1" z="0" />
+
<v x="9.7" y="-1" z="0" />
-
<v x="9.7" y="-1" z="1" />
+
<v x="9.7" y="-1" z="1" />
-
<sector>room2</sector>
+
<sector>room2</sector>
-
</portal>
+
</portal>
-
<priority>object</priority>
+
<priority>object</priority>
-
</portals>
+
</portals>
-
</pre>
+
</source>
 +
Finally we are able to see our portal, unfortunately due to the nature and position of our portal it only warps us to the same position in the neighbouring sector, we need a bit of space warping and here's how we do it:
-
Finally we are able to see our portal, unfortunately due to the nature and position of our portal it only warps us to the same position in the neighbouring sector, we need a bit of space warping and here's how we do it:
+
<source lang="xml">
 +
<portals>
 +
<portal name="port1">
 +
<v x="9.7" y="1" z="1" />
 +
<v x="9.7" y="1" z="0" />
 +
<v x="9.7" y="-1" z="0" />
 +
<v x="9.7" y="-1" z="1" />
 +
<wv x="1" y="0" z="0" />
 +
<ww x="-1" y="0" z="0" />
 +
<sector>room2</sector>
 +
<float />
 +
</portal>
 +
<priority>object</priority>
 +
</portals>
 +
</source>
 +
 
 +
We will have to warp using negative coordinates. If you wish to visualise this it is as if we are moving the world one unit toward the player (unless of course we wanted to rotate our space in which case we would need a positive ''<wv/>'' coordinate and a rotation matrix)
 +
The last thing that is needed is the ''<float/>'' tag to indicate it is a floating portal and it is not on the boundary of a sector.
-
~~#FF0000:
+
And we're done, you should be able to load up you level (if you have been following) and get from room1 to room2 but not back again, i won't repeat the making of this portal.
-
&lt;portals&gt;
+
-
&lt;portal name="port1"&gt;
+
-
&lt;v x="9.7" y="1" z="1" /&gt;
+
-
&lt;v x="9.7" y="1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="1" /&gt;
+
-
&lt;wv x="1" y="0" z="0" /&gt;
+
-
&lt;ww x="0" y="0" z="0" /&gt;
+
-
&lt;sector&gt;room2&lt;/sector&gt;
+
-
&lt;ww x="-1" y="0" z="0" /&gt;
+
-
&lt;/portal&gt;
+
-
&lt;priority&gt;object&lt;/priority&gt;
+
-
&lt;/portals&gt;
+
-
~~
+
-
Contrary to popular belive we will have to warp using negative coordinates if you wish to visualise this it is asif we are moving the world one unit toward the player.(unless of course we wanted to rotate our space in which case we would need a positive &lt;wv /&gt; coordinate and a rotation matrix)
+
-
The Last thing that is needed is the &lt;float /&gt; tag to indicate it is a floating portal and it is not on the boundary of a sector.
+
-
~~#FF0000:
+
-
&lt;portals&gt;
+
-
&lt;portal name="port1"&gt;
+
-
&lt;v x="9.7" y="1" z="1" /&gt;
+
-
&lt;v x="9.7" y="1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="1" /&gt;
+
-
&lt;wv x="1" y="0" z="0" /&gt;
+
-
&lt;ww x="0" y="0" z="0" /&gt;
+
-
&lt;sector&gt;room2&lt;/sector&gt;
+
-
&lt;ww x="-1" y="0" z="0" /&gt;
+
-
&lt;float /&gt;
+
-
&lt;/portal&gt;
+
-
&lt;priority&gt;object&lt;/priority&gt;
+
-
&lt;/portals&gt;
+
-
~~
+
-
And we're done, you should be able to load up you level (if you have been following) and get from room1 to room2 but not back again, i won't repeat the making of this portal I will just paste the portal code, all the same principles apply.
+
-
~~#FF0000:
+
-
&lt;portals&gt;
+
-
&lt;portal name="port2"&gt;
+
-
&lt;v x="10.3" y="1" z="0" /&gt;
+
-
&lt;v x="10.3" y="1" z="1" /&gt;
+
-
&lt;v x="10.3" y="-1" z="1" /&gt;
+
-
&lt;v x="10.3" y="-1" z="0" /&gt;
+
-
&lt;sector&gt;room&lt;/sector&gt;
+
-
&lt;ww x="1" y="0" z="0" /&gt;
+
-
&lt;float /&gt;
+
-
&lt;/portal&gt;
+
-
&lt;priority&gt;object&lt;/priority&gt;
+
-
&lt;/portals&gt;
+
-
~~
+
-
-= The Final XML should look something like this: =-
+
-
~~#FF0000:
+
-
&lt;world&gt;
+
-
&lt;textures&gt;
+
-
&lt;texture name="oldmetal"&gt;
+
-
&lt;file&gt;/lib/stdtex/oldmetal.jpg&lt;/file&gt;
+
-
&lt;/texture&gt;
+
-
&lt;/textures&gt;
+
-
&lt;shaders&gt;
+
-
&lt;shader&gt;
+
-
&lt;file&gt;/shader/std_lighting_detail.xml&lt;/file&gt;
+
-
&lt;/shader&gt;
+
-
&lt;/shaders&gt;
+
-
&lt;materials&gt;
+
-
&lt;material name="oldmetal"&gt;
+
-
&lt;texture&gt;oldmetal&lt;/texture&gt;
+
-
&lt;shader type="standard"&gt;std_lighting_detail&lt;/shader&gt;
+
-
&lt;shadervar name="tex detail" type="texture"&gt;oldmetal&lt;/shadervar&gt;
+
-
&lt;shadervar name="detail texture scale" type="vector2"&gt;10,10&lt;/shadervar&gt;
+
-
&lt;/material&gt;
+
-
&lt;/materials&gt;
+
-
&lt;sounds&gt;
+
-
&lt;sound name="tada.wav"&gt;
+
-
&lt;file&gt;/lib/std/tada.wav&lt;/file&gt;
+
-
&lt;/sound&gt;
+
-
&lt;/sounds&gt;
+
-
&lt;library&gt;/lib/std/library&lt;/library&gt;
+
-
&lt;plugins&gt;
+
-
&lt;plugin name="thing"&gt;crystalspace.mesh.loader.thing&lt;/plugin&gt;
+
-
&lt;plugin name="thingFact"&gt;crystalspace.mesh.loader.factory.thing&lt;/plugin&gt;
+
-
&lt;/plugins&gt;
+
-
&lt;meshfact name="walls"&gt;
+
-
&lt;plugin&gt;thingFact&lt;/plugin&gt;
+
-
&lt;params&gt;
+
-
&lt;v x="-10" y="-1" z="10"/&gt; &lt;v x="10" y="-1" z="10"/&gt;
+
-
&lt;v x="-10" y="-1" z="-10"/&gt; &lt;v x="10" y="-1" z="-10"/&gt;
+
-
&lt;v x="-10" y="4" z="10"/&gt; &lt;v x="10" y="4" z="10"/&gt;
+
-
&lt;v x="-10" y="4" z="-10"/&gt; &lt;v x="10" y="4" z="-10"/&gt;
+
-
&lt;material&gt;oldmetal&lt;/material&gt;
+
-
&lt;texlen&gt;4&lt;/texlen&gt;
+
-
&lt;p name="up"&gt;
+
-
&lt;v&gt;6&lt;/v&gt;&lt;v&gt;7&lt;/v&gt;&lt;v&gt;5&lt;/v&gt;&lt;v&gt;4&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;p name="down"&gt;
+
-
&lt;v&gt;3&lt;/v&gt;&lt;v&gt;2&lt;/v&gt;&lt;v&gt;0&lt;/v&gt;&lt;v&gt;1&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;p name="back"&gt;
+
-
&lt;v&gt;7&lt;/v&gt;&lt;v&gt;6&lt;/v&gt;&lt;v&gt;2&lt;/v&gt;&lt;v&gt;3&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;p name="front"&gt;
+
-
&lt;v&gt;4&lt;/v&gt;&lt;v&gt;5&lt;/v&gt;&lt;v&gt;1&lt;/v&gt;&lt;v&gt;0&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;p name="left"&gt;
+
-
&lt;v&gt;6&lt;/v&gt;&lt;v&gt;4&lt;/v&gt;&lt;v&gt;0&lt;/v&gt;&lt;v&gt;2&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;p name="right"&gt;
+
-
&lt;v&gt;5&lt;/v&gt;&lt;v&gt;7&lt;/v&gt;&lt;v&gt;3&lt;/v&gt;&lt;v&gt;1&lt;/v&gt;
+
-
&lt;/p&gt;
+
-
&lt;/params&gt;
+
-
&lt;/meshfact&gt;
+
-
&lt;start&gt;
+
-
&lt;sector&gt;room&lt;/sector&gt;
+
-
&lt;position x="0" y="0" z="0" /&gt;
+
-
&lt;/start&gt;
+
-
&lt;sector name="room"&gt;
+
-
&lt;portals&gt;
+
-
&lt;portal name="port1"&gt;
+
-
&lt;v x="9.7" y="1" z="1" /&gt;
+
-
&lt;v x="9.7" y="1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="0" /&gt;
+
-
&lt;v x="9.7" y="-1" z="1" /&gt;
+
-
&lt;sector&gt;room2&lt;/sector&gt;
+
-
&lt;ww x="-1" y="0" z="0" /&gt;
+
-
&lt;float /&gt;
+
-
&lt;/portal&gt;
+
-
&lt;priority&gt;object&lt;/priority&gt;
+
-
&lt;/portals&gt;
+
-
&lt;meshobj name="walls1"&gt;
+
-
&lt;plugin&gt;thing&lt;/plugin&gt;
+
-
&lt;zfill /&gt;
+
-
&lt;params&gt;
+
-
&lt;factory&gt;walls&lt;/factory&gt;
+
-
&lt;/params&gt;
+
-
&lt;/meshobj&gt;
+
-
&lt;light name="Light1"&gt;
+
-
&lt;center x="0" y="0" z="0" /&gt;
+
-
&lt;radius&gt;20&lt;/radius&gt;
+
-
&lt;color red="2" green="2" blue="2" /&gt;
+
-
&lt;dynamic /&gt;
+
-
&lt;/light&gt;
+
-
&lt;/sector&gt;
+
-
&lt;sector name="room2"&gt;
+
-
&lt;portals&gt;
+
-
&lt;portal name="port2"&gt;
+
-
&lt;v x="10.3" y="1" z="0" /&gt;
+
-
&lt;v x="10.3" y="1" z="1" /&gt;
+
-
&lt;v x="10.3" y="-1" z="1" /&gt;
+
-
&lt;v x="10.3" y="-1" z="0" /&gt;
+
-
&lt;sector&gt;room&lt;/sector&gt;
+
-
&lt;ww x="1" y="0" z="0" /&gt;
+
-
&lt;float /&gt;
+
-
&lt;/portal&gt;
+
-
&lt;priority&gt;object&lt;/priority&gt;
+
-
&lt;/portals&gt;
+
-
&lt;meshobj name="walls1"&gt;
+
-
&lt;plugin&gt;thing&lt;/plugin&gt;
+
-
&lt;zfill /&gt;
+
-
&lt;params&gt;
+
-
&lt;factory&gt;walls&lt;/factory&gt;
+
-
&lt;/params&gt;
+
-
&lt;move&gt;
+
-
&lt;v x="20" y="0" z="0" /&gt;
+
-
&lt;/move&gt;
+
-
&lt;/meshobj&gt;
+
-
&lt;light name="Light2"&gt;
+
-
&lt;center x="16" y="0" z="0" /&gt;
+
-
&lt;radius&gt;20&lt;/radius&gt;
+
-
&lt;color red="2" green="2" blue="2" /&gt;
+
-
&lt;dynamic /&gt;
+
-
&lt;/light&gt;
+
-
&lt;/sector&gt;
+
-
&lt;/world&gt;
+
-
~~
+
-
And that should be it.
+

Current revision

This article intends to breakdown the CS world file into it's different parts in-order to explain syntax and common usage. Although much of this is covered in the documentation some parts are incomplete and not fully explained. So this article hopes to pick up where the documentation leaves of.

First of all, because the CS world format has the advantage of being in an ACSII format we can open in up in a standard text editor (preferably one with XML syntax highlighting for simplification). So either start a new document or open an existing world file for editing (many examples can be found in the CS/data/ sub-directories)

Contents

Initialization Part

In the beginning...

All CS world files must start with the <world> tag and end with </world>. So to start us off we'll have:

<world>
</world>

Note that if you want to make a library then just replace world with library. The rest of this tutorial is also valid for libraries except that libraries can only contain textures, materials, and mesh factories and no sectors.

Adding a Texture

Next we initialise which textures and materials we intend to use. To specify file locations in Crystal Space we always use VFS paths. VFS paths are a way of defining real paths without using Operating-System specific paths. They also allow you to directly read textures (and other files) from ZIP archives.

VFS (Virtual File System) paths are not just ordinary file system paths but paths that CS has set to ensure multi-platform compatibility. Real paths are usually mounted to VFS paths in the vfs.cfg. For example /lib/stdtex ' is actually a zip file called stdtex.zip in CS/data which has been mounted to the /lib/ VFS path. This comes in handy as you can refer to zip files as folders just by mounting them.

We start the world file initialization by specifying that we are talking about textures using the <textures> tag and then specify which texture we are using with the <texture> tag. Finally for every texture we specify it's location using the <file> tag:

<textures>
    <texture name="oldmetal">
        <file>/lib/stdtex/oldmetal.jpg</file>
    </texture>
</textures>

This should load a texture which can now be referred to as oldmetal from that VFS path /lib/stdtex/.

Other specifics relating to special cases in <textures> such as cubemaps and key colours can be read about in the official CS documentation or you can look at examples in CS/data/flarge/world

Adding Shaders

Shaders will come into play in the material section. But before you can use a shader in a material we have to load the shader:

<shaders>
    <shader>
        <file>/shader/std_lighting_detail.xml</file>
    </shader>
</shaders>

Adding Materials With Shaders

Materials define surface attributes. Typically materials are associated with textures but there are many other possibilities. An example of a material that is not associated with a texture is a material defining a green color:

<materials>
    <material name="green_color">
        <color red="0" green="1" blue="0" />
    </material>
</materials>

Usually however, you will want to specify a texture like this:

<material name="oldmetal">
    <texture>oldmetal</texture>
</material>

Another example are shaders, I will not get into shader specifics but applying a shader to a material is a simple process. Lets refer to the shader we used earlier.

<material name="oldmetal">
    <texture>oldmetal</texture>
    <shader type="standard">std_lighting_detail</shader>
</material>

This would attach the shader to the oldmetal material. But if we were to examine the actual shader we would notice that it also takes 2 variables which we can specify here. One is a texture that will be overlayed on the existing texture, and the other is a 2-D vector which basically shrinks down that texture to that scale. To use these variables we can do the following:

<material name="oldmetal">
    <texture>oldmetal</texture>
    <shader type="standard">std_lighting_detail</shader>
    <shadervar name="tex detail" type="texture">oldmetal</shadervar>
    <shadervar name="detail texture scale" type="vector2">10,10</shadervar>
</material>

Luckily for us this shader is a standard shader and the default renderloop already includes standard shaders. If this was another kind of shader it was possible that we had to change the renderloop. I decided to keep the same texture as the detail texture to avoid having to specify another texture and shrunk it by 10 UV's. If you are confused as to how i got the variable names and types, you can check cs/data/shaders/std_lighting_detail.xml for the type and names of the shader variables it takes. This is the same for all shaders.

So Far

So far we have specified a simple texture, material and shader-setup which looks like this:

<world>
    <textures>
        <texture name="oldmetal">
            <file>/lib/stdtex/oldmetal.jpg</file>
        </texture>
    </textures>
    <shaders>
        <shader>
            <file>/shader/std_lighting_detail.xml</file>
        </shader>
    </shaders>
    <materials>
        <material name="oldmetal">
            <texture>oldmetal</texture>
            <shader type="standard">std_lighting_detail</shader>
            <shadervar name="tex detail" type="texture">oldmetal</shadervar>
            <shadervar name="detail texture scale" type="vector2">10,10</shadervar>
        </material>
    </materials>
</world>

Addings Sounds

Adding sounds is much like everything else in CS, very simple. It goes something like this:

<sounds>
    <sound name="tada.wav">
        <file>/lib/std/tada.wav</file>
    </sound>
</sounds>

Adding A Library

Another way of defining almost all of these things is through the use of libraries. A library is structured very much like a world file only it starts with <library> and ends with </library>. It also cannot accept start locations and sectors. It is a good way of grouping certain things for loading. Also if specifying mesh factories in a library you will be able to load them into viewmesh. To include a library in a world file we can use:

<library path="/lib/std" file="library" />

Adding Plugins

Crystal Space is very modular. As a result map loading in Crystal Space is also modular. That means that every mesh object has its own plugin that is responsible for loading. Every plugin has a specific name. You can specify that full name everytime you need it (i.e. for every mesh object). But it is often easier to specify shortcuts for every plugin that you need. This can be done in the <plugins> section:

<plugins>
    <plugin name="thing">crystalspace.mesh.loader.thing</plugin>
    <plugin name="thingFact">crystalspace.mesh.loader.factory.thing</plugin>
</plugins>

Thing meshes are usually low-poly meshes that use pre-calculated light-mapped surfaces. Their downside is that they are less efficient than a general mesh.

Adding Settings

Settings are there to over-ride some default engine settings such as ambient light and lightmap size you can read about them in the documentation.

Adding Factories

The Factory/meshobject scenario is often important if you wish to repeat meshes several times. But not always necessary if you wish to just have one instance of a mesh. For this article I will be taking advantage of the Factory/Meshobject setup to better familiarize users with it.

In a factory we usually tell the engine what the factory will be called (the name), the plugin that is used to load it, the geometry information and also material(s) used on the mesh. With a thing mesh we have the option of multiple materials based on the polygons you assign it to. This factory was taken from the simple map tutorial in the documentation. It is a simple cube with a single material:

<meshfact name="walls">
    <plugin>thingFact</plugin>
    <zfill />
    <params>
        <v x="-10" y="-1" z="10"/> <v x="10" y="-1" z="10"/>
        <v x="-10" y="-1" z="-10"/> <v x="10" y="-1" z="-10"/>
        <v x="-10" y="4" z="10"/> <v x="10" y="4" z="10"/>
        <v x="-10" y="4" z="-10"/> <v x="10" y="4" z="-10"/>
        <material>old_metal</material>
        <texlen>4</texlen>
        <p name="up">
            <v>6</v> <v>7</v> <v>5</v> <v>4</v>
        </p>
        <p name="down">
            <v>3</v> <v>2</v> <v>0</v> <v>1</v>
        </p>
        <p name="back">
            <v>7</v> <v>6</v> <v>2</v> <v>3</v>
        </p>
        <p name="front">
            <v>4</v> <v>5</v> <v>1</v> <v>0</v>
        </p>
        <p name="left">
            <v>6</v> <v>4</v> <v>0</v> <v>2</v>
        </p>
        <p name="right">
            <v>5</v> <v>7</v> <v>3</v> <v>1</v>
        </p>
    </params>
</meshfact>

The first line initializes and names the meshfactory. The second tells the loader what plugin we are using (in this case a thing factory because we are defining geometry). <zfill /> is used so that the card ignores the zbuffer and draws the Z value from the thing polygons over the old Z values present on screen. This is used by the outermost walls because it is a faster mode than <zuse/> as it does not need to read the zbuffer. It will be the first thing rendered in a back2front render. Everything inside the <params> block is specific to the thing mesh (handled by the thing factory loader plugin). Other meshes will have other stuff there. The next block is actually defining the position of vertices. This box is made up of 8 vertices. Next comes the material. We specify the material we created earlier (old_metal). Now we set <texlen> to 4 meaning that for every 4*4 world units one texture will be tiled. This is a shortcut to make it easier to do the texture mapping. For real models you will probably want to specify UV coordinates directly. This is easier done by using a map editor like Blender. Next we define polygons by specifying the vertices that make up that polygon but remember that vertices start to count at 0. These polygons can also have names which is mostly useful for debugging purposes.

And that brings a close to our initialization section of a world file. In the rest of this tutorial I will tell you how to use these to create a sector in a world that can be loaded by walktest.

Creating a Room

Starting Us Off

Now is time for use to use those loaded resources and create a simple room runable in walktest. Now normally the definition section would probly be the largest part of the world file, luckily we only have a small amount of objects. To start us of, no pun intended we need a spawning position which we specify like this:

<start>
    <sector>room</sector>
    <position x="0" y="0" z="0" />
</start>

room will be the eventual name of our sector. 0,0,0 will be the coordinate in that sector in which we shall spawn (Crystal Space Does not actually care about this, it is very app-specifc the way you handle start points. You can have multiple start positions and have people spawn at different locations). Now we create and name our sector like so:

Creating a Sector

<sector name="room">
</sector>

Adding our Mesh Object

We now have a sector called room which we can fill with whatever we want. We start by adding a mesh object called walls which we create from the same-named factory that we created above.

<sector name="room">
    <meshobj name="walls">
        <plugin>thing</plugin>
        <params>
            <factory>walls</factory>
        </params>
    </meshobj>
</sector>

The second line refers to the loader plugin again, do not confuse this with the factory plugin. If you look at the <plugin> section we have initialised two plugins: the mesh and factory loader. The <params> sections only needs to have a reference to our factory. If I had not used a factory this would be the section where I would place the vertex and polygon information along with the materials. And finaly we terminate our meshobj section and we're done with this part.

Adding A Light

At this point if we were to load the world file with this into walktest it would work, but you would not be able to see anything. why you ask? No lights. To add a light we add the following:

<sector name="room">
    <meshobj name="walls">
        <plugin>thing</plugin>
        <params>
            <factory>walls</factory>
        </params>
    </meshobj>
    <light name="light1">
        <center x="0" y="0" z="0" />
        <radius>20</radius>
        <color red="2" green="2" blue="2" />
    </light>
</sector>

We should be able to see from this that it is named light1 and it will be created where we spawn (0,0,0 in sector room). Also we set its radius to 20. This does not mean that everything will be full bright. It only means that the light will not begin to falloff as soon. Also light values are worked out on a percentage for colours r1g1b1 (100% Red 100% Green 100% Blue) being white but also the larger numbers have greater intensity meaning this is 2x brighter than a r1g1b1 light.

Loading Your Level Into Walktest

This level is now ready (syntax wise) for walktest. To actually run it you have to specify the directory where the world file is located to walktest like this:

     walktest directory_for_world -relight

If you put world in the current directory then you can also do:

     walktest /this -relight

The reason this all works is that walktest accepts both VFS paths (the /this above) and normal paths (the directory_for_world). The VFS path /this is very useful for debugging (but should otherwise be avoided) and refers to the current directory.

The -relight commandline option is only needed the first time in case you are using thing meshes that require static precalculated lightmaps. It will actually calculate the lightmaps. Next time you run the map you don't need to add that option unless you changed the map (moved/added a light or changed geometry).

Sectors And Portals

It seems that other articles have shed away from dealing with sectors and portals, so we decided to add another sector to this tutorial.

Duplicate your current sector and rename it like this:

<sector name="room2">
    <meshobj name="walls">
        <plugin>thing</plugin>
        <params>
            <factory>walls</factory>
        </params>
    </meshobj>
    <light name="light1">
        <center x="0" y="0" z="0" />
        <radius>20</radius>
        <color red="2" green="2" blue="2" />
        <dynamic />
    </light>
</sector>


Duplicating your Sector

Currently room2 is just a duplcate of room. What we want is another room on the side of our previous room. To do this we must translate our light and walls 20 units in a direction. We chose the positive X direction. To do this we add a <move> tag to our mesh object like this:

<move>
    <v x="20" y="0" z="0" />
</move>

Which in the context of room2 is as follows:

<sector name="room2">
    <meshobj name="walls">
        <plugin>thing</plugin>
        <params>
            <factory>walls</factory>
        </params>
        <move>
            <v x="20" y="0" z="0" />
        </move>
    </meshobj>
    <light name="light1">
        <center x="20" y="0" z="0" />
        <radius>20</radius>
        <color red="2" green="2" blue="2" />
        <dynamic />
    </light>
</sector>

Note that we also moved the light. We now have two rooms side by side, Unfortunately they are not connected at all. We did not have to separate these into seperate sectors but a constricted doorway is a good opportunity to take advantage of portals and sectors. We are going to create a floating portal as not to distrub the geometry by adding a polygon inside the face, normally adding a portal polygon to a mesh would be a better solution as that way portals line up correctly with walls, but this portal is for illustrative purposes and concepts only.

Portals

To start off we'll place a portal from room to room2'. Add this to the room sector (right before the light for example):

<portals>
    <portal name="port1">
        <sector>room2</sector>
    </portal>
</portals>

This creates a portal that goes to room2 but it is not complete. We also have to specify the dimensions of the portal (as a polygon) like this:

<portals>
    <portal name="port1">
        <v x="9.7" y="1" z="1" />
        <v x="9.7" y="1" z="0" />
        <v x="9.7" y="-1" z="0" />
        <v x="9.7" y="-1" z="1" />
        <sector>room2</sector>
    </portal>
</portals>

Once again we are not able to see the portal because our render-priorities are not currently set, meaning our zfill walls don't know they are meant to be behind our portal so for our special case we need to use the object priority like so (objects with render priority object are rendered behind objects with render priority walls. And the default render priority for objects with <zfill/> is walls):

<portals>
    <portal name="port1">
        <v x="9.7" y="1" z="1" />
        <v x="9.7" y="1" z="0" />
        <v x="9.7" y="-1" z="0" />
        <v x="9.7" y="-1" z="1" />
        <sector>room2</sector>
    </portal>
    <priority>object</priority>
</portals>

Finally we are able to see our portal, unfortunately due to the nature and position of our portal it only warps us to the same position in the neighbouring sector, we need a bit of space warping and here's how we do it:

<portals>
    <portal name="port1">
        <v x="9.7" y="1" z="1" />
        <v x="9.7" y="1" z="0" />
        <v x="9.7" y="-1" z="0" />
        <v x="9.7" y="-1" z="1" />
        <wv x="1" y="0" z="0" />
        <ww x="-1" y="0" z="0" />
        <sector>room2</sector>
        <float />
    </portal>
    <priority>object</priority>
</portals>

We will have to warp using negative coordinates. If you wish to visualise this it is as if we are moving the world one unit toward the player (unless of course we wanted to rotate our space in which case we would need a positive <wv/> coordinate and a rotation matrix) The last thing that is needed is the <float/> tag to indicate it is a floating portal and it is not on the boundary of a sector.

And we're done, you should be able to load up you level (if you have been following) and get from room1 to room2 but not back again, i won't repeat the making of this portal.

| Article | Discussion | View source | History |