[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section documents the major changes between versions 0.96 and 0.98 of Crystal Space.
The following methods have been removed:
iMeshWrapper::DeferUpdateLighting()
iMeshWrapper::UpdateLighting()
Instead there is a new function iMeshWrapper::SetLightingUpdate()
with
which you can exhibit the same control. The big difference is that you don't
have to call this function every time a light or object moves. This is all
updated automatically now.
Also removed the CS_NLIGHT_
flags. iEngine::GetNearbyLights()
has been modified so that the flags parameter is no longer accepted.
The notion of curve templates has been reworked. `iCurveTemplate' has been removed and it's functionality has moved to `iCurve' itself. As a consequence of this change the bezier addon loader has been removed. Also curves have been separated from the thing plugin and now live in the `bezier' plugin. So, a curve like this in the past:
<addon> <plugin>crystalspace.mesh.loader.thing.bezier</plugin> <params> <name>b1</name> <material>mosaic</material> <v>0</v> <v>1</v> <v>2</v> <v>3</v> <v>4</v> <v>5</v> <v>6</v> <v>7</v> <v>8</v> </params> </addon> <meshfact name="tunnel"> <plugin>crystalspace.mesh.loader.factory.thing</plugin> <params> <curvecenter x="0" y="0" z="0" /> <curvescale>80</curvescale> <curvecontrol x="5" y="2" z="0" u="1" v="0" /> ... <curve name="bez">b1</curve> </params> </meshfact> |
should now become (note the new plugin line):
<meshfact name="tunnel"> <plugin>crystalspace.mesh.loader.factory.bezier</plugin> <params> <curvecenter x="0" y="0" z="0" /> <curvescale>80</curvescale> <curvecontrol x="5" y="2" z="0" u="1" v="0" /> ... <curve name="b1"> <material>mosaic</material> <v>0</v> <v>1</v> <v>2</v> <v>3</v> <v>4</v> <v>5</v> <v>6</v> <v>7</v> <v>8</v> </curve> </params> </meshfact> |
On the API side nothing much changes except that when you use the bezier mesh plugin you need to use `iBezierState' and `iBezierFactoryState'.
The `iThingEnvironment' no longer has code to maintain bezier curve templates.
The interface `iThingState' no longer inherits from
`iObject', thus the QueryObject()
function has been removed.
`iThingState' has been split into `iThingState' and
`iThingFactoryState'. A thing mesh no longer implements both a mesh
object and a mesh object factory. Instead things now work like usual
mesh objects where iMeshObjectType::NewFactory()
creates a
factory that implements `iThingFactoryState' and
iMeshObjectFactory::NewInstance()
creates an instance that implements
`iThingState'. The engine convenience functions to create a thing
mesh will automatically create both the factory and mesh so you don't
have to worry about that. You can use iThingState::GetFactory()
from a thing mesh object to get the `iThingFactoryState' so you can
build the polygons. Note that SCF_QUERY_INTERFACE()
of
`iThingFactoryState' no longer works on a thing mesh object. You must
use GetFactory()
.
iThingState::GetVertexC()
has been removed. It is no longer possible
to get camera space information from a thing.
The interface `iPolygon3D' is completely removed. The `iThingFactoryState' now contains a lot of new functions to create and manipulate polygons. Here is an example:
First the old code:
iPolygon3D* p; p = state->CreatePolygon ("First one"); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->SetMaterial (mat); p = state->CreatePolygon ("Second one"); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->SetMaterial (mat); ... |
Here the new code:
state->AddQuad ( csVector3 (...), csVector3 (...), csVector3 (...), csVector3 (...)); state->SetPolygonName (CS_POLYRANGE_LAST, "First one"); state->AddQuad ( csVector3 (...), csVector3 (...), csVector3 (...), csVector3 (...)); state->SetPolygonName (CS_POLYRANGE_LAST, "Second one"); state->SetPolygonMaterial (CS_POLYRANGE_ALL, mat); |
If you want to add a box that can be seen from the inside (typically a room) then you can do it like this:
state->AddInsideBox (csVector3 (-5, 0, -5), csVector3 (5, 20, 5)); state->SetPolygonMaterial (CS_POLYRANGE_LAST, mat); state->SetPolygonTextureMapping (CS_POLYRANGE_LAST, 3); |
The interfaces `iStatLight' and `iDynLight' have been removed
and their functionality has been merged into `iLight' (this includes
the function iDynLight::Setup()
. There is now a new function
iLight::GetDynamicType()
which returns one of the following
constants depending on the type of the light:
CS_LIGHT_DYNAMICTYPE_STATIC
: for static lights.
CS_LIGHT_DYNAMICTYPE_PSEUDO
: for pseudo-dynamic lights.
CS_LIGHT_DYNAMICTYPE_DYNAMIC
: for fully dynamic lights.
The method iLight::IsDynamic()
was removed;
use iLight::GetDynamicType()
to get the same information.
The following functions have been modified to work with `iLight' instead of `iStatLight' and `iDynLight':
iEngine::CreateLight()
.
iEngine::FindLight()
.
iEngine::FindLightID()
.
iEngine::ForceRelight()
.
The last parameter of iEngine::CreateLight()
routine has
changed to be the dynamic type of the light (one of the above
`CS_LIGHT_DYNAMICTYPE' constants) instead of a boolean. Thus, the
iEngine::CreateDynLight()
method has been superceded by this
function.
All functions related to dynamic lights have been removed. Dynamic
lights are now treated exactly like static lights. For example, you have to
call iSector::GetLights()
and then Add()
to add the light to the
sector. The iLight::Setup()
function remains, however, and is
specific to dynamic lights.
The following interfaces have been removed: `iPolyTexNone', `iPolyTexGouraud', `iPolyTexFlat', and `iPolyTexLightMap'. The combined API from `iPolyTexNone' and the `iPolyTexLightMap' have moved to `iThingFactoryState'.
It is no longer possible to set mixmode and alpha for individual polygons
Instead use the new iThingState::SetMixMode()
function to set the
mixmode globally. If needed you will have to separate the transparent polygon
in a separate thing mesh.
It is also no longer possible to get camera space information from polygons.
The <shading>
keyword in polygons in map files now accepts a boolean
value instead of `NONE', `FLAT', `GOURAUD', or `LIGHTMAP'.
With this you can enable/disable lightmapping.
If you want gouraud shaded polygons you should use the `genmesh' mesh object plugin instead.
Polygon planes are removed. So it is no longer possible to use the plane addon loader to define texture mapping for a polygon outside of the polygon itself. To fix this you must specify all texture mapping information in the `texmap' statement of the polygon. `map2cs' now correctly outputs polygons like this (no longer outputs planes) and `levtool' can convert old style maps to new format like this:
levtool -planes yourmap.zip |
`iThingEnvironment' no longer has code to maintain polygon texture mapping planes.
The plane loader and saver addons have been removed from the thing loader plugin.
Removed `iPolyTxtPlane' interface.
Several methods in `iPortal' have changed slightly. For example,
SetMirror()
now expects a plane instead of a polygon.
In the map loader the syntax for specifying warp vectors for portals has changed from `v' to `wv' and `w' to `ww'.
Portals in thing have been removed completely! Instead there is now a separate
portal container object which belongs in the engine (otherwise it is just
a mesh like any other mesh). To create a portal you can use the conveniance
functions iEngine::CreatePortal()
and
iEngine::CreatePortalContainer()
. Here is an example of old code
and how to change it to new code:
... create thing in sourceSector ... iPolygon3D* p = state->CreatePolygon (); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); p->CreateVertex (csVector3 (...)); iPortal* portal = p->CreatePortal (destSector); |
New code:
csPoly3D poly; poly.AddVertex (csVector3 (...)); poly.AddVertex (csVector3 (...)); poly.AddVertex (csVector3 (...)); poly.AddVertex (csVector3 (...)); iPortal* portal; csRef<iMeshWrapper> portal_mesh = engine->CreatePortal ( "my_portal", sourceSector, csVector3 (0, 0, 0), destSector, poly.GetVertices (), poly.GetVertexCount (), portal); |
In map files the old way to create portals in a polygon is still supported. Internally it will also create a portal container (as a child mesh of the thing it is in). The new way to create portals is by using the new `portals' and `portal' keywords in sectors or as children of other meshes.
The `csSome', `csConstSome' and `uint' types have been removed. Use `void*', `const void*' and `unsigned int' instead.
Instead of only built-in types, procedural textures have been moved into
plugins. That means that the <type>
token now works the same way
as the <plugin>
token for meshes. That is, either specify a full
class ID (e.g. `crystalspace.proctex.loader.fire'), or a shortcut
specified in the <plugins>
token of the world. To simulate the
old <type>
behaviour, paste the following lines into a map's
<plugin>
section:
<plugin name="dots">crystalspace.texture.loader.dots</plugin> <plugin name="fire">crystalspace.texture.loader.fire</plugin> <plugin name="water">crystalspace.texture.loader.water</plugin> <plugin name="plasma">crystalspace.texture.loader.plasma</plugin> |
This requires that you move the <plugin>
block in front of the
<textures>
block, as otherwise the shortcuts won't be recognised.
The behaviour of procedural textures also differs as a material of the same name was created along with the texture; this isn't the case any more, you have to create a material which uses the procedural texture manually.
In addition, the loader now doesn't distinguish between normal and procedural
textures any more, both are loaded with the same <texture>
block. The
syntax recognized is a combination of both old <texture>
and
<proctex>
tokens--so renaming all <proctex>
to <texture>
tags is sufficient to convert a level (apart from fixing the <type>
tokens.)
Region handling has changed considerably. The engine no longer has the concept of a current region. The engine still manages all regions though. Objects also no longer register themselves to the current region. It is the responsability of the object creator to do that. The standard loader has support for adding objects to a region now.
The following functions have been removed from `iEngine':
SelectRegion()
GetCurrentRegion()
AddToCurrentRegion()
There is one new function iEngine::CreateRegion()
which will create
a new region.
In `iLoader' the functions LoadMapFile()
and
ThreadedLoadMapFile()
now expect an optional pointer to a region
in addition with a boolean to restrict searching to that region.
In addition to all these changes the <region>
keyword in map files is no
longer supported.
Some mesh factories used to support the querying of the `iPolygonMesh' interface (e.g. Thing, Sprite3D, Genmesh). Due to the way this was implemented internally this caused leaks. So, querying `iPolygonMesh' directly from the object is now discouraged. Although it may still work in some cases, this feature may be dropped without further notice and may not work in all cases.
Similar for mesh objects. Querying `iPolygonMesh' is discouraged here, as well.
Instead, if you want the polygon mesh from an object, use the
GetObjectModel()
method from the `iMeshObject' interface;
respectively query for the `iObjectModel' interface in case of a factory,
and utilize one of the GetPolygonMeshXXX()
methods, depending on what
you need (the old interface query returned the collision detection mesh.) This
has also the advantages that you can get different meshes for different
purposes (currently, visibility culling and collision detection in addition the
the base mesh), and that those meshes can be overridden by user-defined meshes
(e.g. if the collision detection mesh needs to have a shape different from the
visible mesh.)
In `iPolygonMesh' the IsDeformable()
method has been replaced
with the more general GetFlags()
. In addition to that Cleanup()
is removed and instead Lock()
and Unlock()
are added.
`iPolygonMesh' now has GetTriangles()
and GetTriangleCount()
.
Check out the API docs for implementation details.
Changed the following iterators to conform to the following iterator standard:
bool iterator->HasNext() // returns true if there are more items. T* iterator->Next() // returns next element or 0. void Reset() // resets iterator (not all implement this). |
iVisibilityObjectIterator
iLightIterator
iSectorIterator
iObjectIterator
iStreamIterator
iObjectRegistryIterator
csTypedObjectIterator
csModelDataActionIterator
csModelDataPolygonIterator
csModelDataTextureIterator
csModelDataMaterialIterator
csModelDataObjectIterator
csNodeIterator
iAWS::CreateCustomCanvas()
was removed. To set up AWS with a
canvas, use iAWS::SetupCanvas()
instead.
iAWS::CreateTransition()
and iAWS::CreateTransitionEx()
have been
changed to take a delay parameter specified in `csTicks' instead of
using a step_size parameter. This change ensures that transitions take
the same amount of time on computers having different processor speeds.
iAWS::ComponentIsInTransition()
has been added to allow users to query
if a specified `iAwsComponent' is in the midst of a transition.
All arrays have been modified to inherit from `csArray'. This means that there are some slight API changes because some methods were not consistent with `csArray'.
`csGrowingArray' has been renamed to `csDirtyAccessArray' in order to
better reflect its intention, which is that it publishes a method allowing the
client to obtain access to the raw memory block containing the items in
contiguous memory. This potentially unsafe operation is not available in the
other array templates. Use this class only in very special-purpose cases where
you need to construct a list of objects dynamically and then pass the address
of the raw memory containing those objects to some foreign function which does
not understand csArray<>
.
`csPArray' has been removed in favor of the csArray<>
template.
So, use csArray<T*>
instead of csPArray<T>
.
`csStrVector' and `iStrVector' have been removed in favor of
`csStringArray' and `iStringArray'. This means that functions like
iVFS::MountRoot()
and iVFS::FindFiles()
now return an
`iStringArray'.
`csVector' and `csBasicVector' have been removed. Instead you
should use one of the templated arrays: csArray<>
, csPDelArray<>
,
or csRefArray<>
.
If you were using a regular `csVector' then this can usually be
replaced directly by csArray<type*>
with `type' the type you
were storing in the vector.
If you subclassed from `csVector' in order to override FreeItem()
then you have to decide what to do depending on the code in FreeItem()
.
If that code performed a `delete' then you can use csPDelArray<>
.
If that code performed a DecRef()
then you can use csRefArray<>
but you still have to be careful because csRefArray<>
will automatically
incref objects that are pushed on the array. In other cases you probably
need to handle deletion manually.
`csVector' also allowed to override Compare()
and
CompareKey()
in order to drive QuickSort()
,
FindSortedKey()
, InsertSorted()
, and FindKey()
. This is
no longer possible. Instead you can do the following transformation. First
the old code:
class MyVector : public csVector { public: virtual ~MyVector () { DeleteAll (); } virtual void FreeItem (void* item) { delete (MyType*)item; } virtual int Compare (void* i1, void* i2, int mode) const { ... } virtual int CompareKey (void* i, const void* key, int mode) const { ... } }; |
This could be transformed roughly to the following class:
class MyVector : public csPDelArray<MyType> { public: static int Compare (MyType const* i1, MyType const* i2) { ... } static int CompareKey (MyType const* i, void* key) { ... } }; |
In the calls to InsertSorted()
, FindKey()
, etc., you would then
pass in one of the static functions to use.
The new template classes csHash<>
and csSet<>
are available for
use by new code; and older code will be upgraded over time to use these
template classes. The older `csHashMap' and `csHashSet' classes are
now deprecated.
The deprecated `csHashIterator' can no longer iterate over all objects. To do that you need to use `csGlobalHashIterator'.
Signatures of the iEvent::Find()
methods have been unified so that they
all now accept a reference into which to store the found item. Previously,
some Find()
methods used a reference for this purpose, while others used
a pointer. In addition, rather than accepting a pointer to a pointer of type
`iEvent', the Find()
method for finding an event now takes a
reference to a csRef<iEvent>
.
Previously, iEventQueue::Post()
had a special case where it assumed that
the caller was giving up ownership of the posted `iEvent' if the caller
had allocated the event manually, rather than obtaining the event via
iEventQueue::CreateEvent()
or iEventOutlet::CreateEvent()
. In
this case, Post()
would hijack the caller's reference to the
`iEvent' for itself. This special case allowed the caller to write code,
such as the following, which appeared to leak a reference to the event, but
which did not in fact do so.
iEvent* e = new csEvent(...); eventq->Post(e); |
Now, however, iEventQueue::Post()
takes the more sane approach of
treating all incoming events identically. It never hijacks ownership of the
event by stealing the caller's reference. Instead, Post()
uniformly
invokes IncRef()
on each incoming event in order to claim its own
reference. This means that callers are no longer burdened by having to
determine whether or not the event's reference is going to be hijacked. Thus,
the above code should be re-written as:
csRef<iEvent> e; e.AttachNew(new csEvent(...)); eventq->Post(e); |
Events created with iEventQueue::CreateEvent()
or
iEventOutlet::CreateEvent()
are unaffected by this change since the
client has always been responsible for managing the event's reference count in
these cases.
The mesh object API has changed considerably, thus we recommend looking at the documentation on that to see how to modify your own mesh object for the new API. In this section we describe API modifications that are relevant for user applications.
For `iLight': SetRadius()
, GetRadius()
, and
GetSquaredRadius()
have been replaced with SetInfluenceRadius()
,
GetInfluenceRadius()
, and GetInfluenceRadiusSq()
.
For `iMaterialEngine' and related: GetTextureWrapper()
for
layers now expects a `csStringID' instead of an integer.
Written by Eric Sunshine, sunshine@sunshineco.com.
The monolithic and inflexible plugin-registry database, `scf.cfg', has been eliminated. Instead, plugin modules are now self-describing via a meta-information resource associated with each module. It is possible to access this meta-information without actually loading the plugin, thus avoiding a time-consuming and costly operation.
A plugin's meta-information is now stored in an XML-format file rather than being hard-coded via the plugin's C++ code. The meta-information file is named after the associated plugin module, except with filename extension `.csplugin'. For instance, the meta-information for the `vfs.so' (or `vfs.dll') plugin will be named `vfs.csplugin'.
Since the meta-information is now maintained via an external resource, the following SCF macros, which were used to export this information from the C++ code, have been removed:
SCF_EXPORT_CLASS_TABLE()
SCF_EXPORT_CLASS()
SCF_EXPORT_CLASS_DEP()
SCF_EXPORT_CLASS_TABLE_END
To deal with this change in your own code, simply remove the entire
SCF_EXPORT_CLASS_TABLE()
block from the C++ code which implements the
plugin module.
Creation of the meta-information resource file involves a straight-forward translation of the information from the obsolete SCF macros into a structured XML-format file. For example:
SCF_EXPORT_CLASS_TABLE(foo) SCF_EXPORT_CLASS( MyClass1, "myproj.myplugin.foo1", "My first custom foo class") SCF_EXPORT_CLASS_DEP( MyClass2, "myproj.myplugin.foo2", "My second custom foo class", "myproj.myplugin.bar1,myproj.myplugin.bar2") SCF_EXPORT_CLASS_TABLE_END |
This table exports two C++ classes, `MyClass1' and `MyClass2' under the SCF class names `myproj.myplugin.foo1' and `myproj.myplugin.foo2', respectively. Furthermore, the second exported class has a dependency upon two other SCF classes, `myproj.myplugin.bar1' and `myproj.myplugin.bar2'. To convert this to an XML-format meta-information resource, just copy the above values into the appropriate XML nodes. For instance:
<?xml version="1.0"?> <!-- myplugin.csplugin --> <plugin> <scf> <classes> <class> <name>myproj.myplugin.foo1</name> <implementation>MyClass1</implementation> <description>My first custom foo class</description> </class> <class> <name>myproj.myplugin.foo2</name> <implementation>MyClass2</implementation> <description>My second custom foo class</description> <requires> <class>myproj.myplugin.bar1</class> <class>myproj.myplugin.bar2</class> </requires> </class> </classes> </scf> </plugin> |
The top-level node of a meta-information file is named <plugin>
. All
SCF-related information is contained within an <scf>
child node.
Plugin modules can export multiple named SCF classes. Each exported class
is represented by a <class>
node within the <classes>
group. The
<name>
node of a <class>
is the class' SCF name. The
<implementation>
node references the C++ class which actually implements
the named SCF class. This is the same name that is privided as an
argument to the SCF_IMPLEMENT_FACTORY()
macro. When an SCF class
depends upon other SCF classes, the dependencies are indicated via the
optional <requires>
group, which contains one <class>
node per
dependency.
Meta-information in the `.csplugin' file is extensible; it is not
restricted to SCF-only usage. Plugin authors can choose to publish
supplementary information about plugins in addition to the SCF information
already published. As a hypothetical example, image loading plugins might
desire to publish image indentification information which would allow the
image loading multiplexor to selectively request image loading plugins
on-demand, rather than requesting all plugins unconditionally, even if
they are not needed. Here is a possible meta-information table for a PNG
image loader (with the <scf>
node collapsed to `...' for the
sake of illustration):
<?xml version="1.0"?> <!-- cspngimg.csplugin --> <plugin> <scf>...</scf> <imageloader> <imagetype> <class>crystalspace.graphic.image.io.png</class> <identify> <mimetype>image/png</mimetype> <extension>png</extension> <extension>PNG</extension> <scan length="4" bytes="\0x89PNG"/> </identify> </imagetype> </imageloader> </plugin> |
In this example, the PNG loader meta-information tells the multiplexor several different ways to identify a PNG image:
If the hypothetical multiplexor identifies the image as PNG, only then will it actually request the PNG loader plugin.
At program launch time, SCF discovers plugins automatically by searching a set of directories, and creates an internal database associating available SCF class names with the plugin modules which implement them. The directories which SCF searches by default are:
csGetResourceDir()
.
On most platforms, this is the same as the directory containing the
application, however, on MacOS/X, it is the `Resources' directory within
the Cocoa application wrapper.
csGetAppDir()
.
csGetConfigPath()
. This is often the value of the `CRYSTAL'
environment variable, or the `CrystalSpaceRoot' default setting on MacOS/X
(which is often stored within the `NSGlobalDomain' domain).
If you would like SCF to scan additional directories, you can invoke either of these two functions (multiple times, if necessary):
scfInitialize(csPluginPaths const*)
iSCF::ScanPluginsPath(char const*, bool, char const*)
Finally, if you need to manually register a single plugin module with SCF
for which you know the native pathname (not a VFS pathname), you can
invoke iSCF::RegisterPlugin()
.
For those relatively rare cases when a named SCF class is built
directly into an application, rather than being implemented via a plugin, the
class must be registered with SCF manually since SCF will not
otherwise be able to discover it automatically as is the case with named
classes exported from plugin modules. Manual registration is accomplished with
the SCF_REGISTER_STATIC_CLASS()
macro. This macro existed previously,
but accepted a different set of arguments. The new arguments are:
SCF_REGISTER_STATIC_CLASS( C++Class, "scf.class.name", "description", "comma-separated dependency list" or NULL) |
Invoke this macro in one of the source files of your application; usually in the source file which implements the class. This macro should be invoked at file scope (that is, not from inside a function). For instance:
SCF_REGISTER_STATIC_CLASS( MyClass2, "myproj.myplugin.foo2", "My second custom foo class", "myproj.myplugin.bar1,myproj.myplugin.bar2") |
If you used to use SCF_REGISTER_STATIC_LIBRARY()
or
SCF_REGISTER_STATIC_CLASS_DEP()
for this same purpose, you must now
instead use SCF_REGISTER_STATIC_CLASS()
. (A macro named
SCF_REGISTER_STATIC_LIBRARY()
still exists, but it has a completely
different purpose than the original version, and is typically only used by very
low-level mechanisms, rather than by end-users. See
`CS/include/csutil/scf.h' for the gory details, if you are curious.)
The Crystal Space `configure' script option `--enable-meta-info-embedding' controls whether or not the build system embeds the plugin meta-information into plugin modules (if supported by the platform), and whether or not the plugin loader looks for embedded meta-information. If this option is disabled, or if embedding is not supported by the platform, then the meta-information is laid down alongside the built plugin module (`.so' or `.dll') in a text file with the same name as the plugin module, except with extension `.csplugin'. The meta-information embedding option is enabled by default for most platforms, but is disabled by default for Unix platforms.
Warning: Meta-information embedding on Unix is accomplished via the `libbfd' library which carries a GPL license. This license is incompatible with Crystal Space's LGPL license. Unlike the LGPL which is compatible with closed-source projects, the GPL license is not. For this reason, embedding is disabled by default on Unix, and must be enabled explicitly with the `configure' script's `--enable-meta-info-embedding' option. Enable this option on Unix only if you are certain that your project is compatible with the GPL license.
The platform-specific plugin loaders are capable of reading embedded plugin meta-information, as well as meta-information in stand-alone `.csplugin' files. Even when configured for embedding, the plugin loaders will still be able to recognize and utilize external `.csplugin' resources. This means that Crystal Space-based projects with unsophisticated build systems, which are incapable of embedding meta-information into the plugin module, can still create usable plugins simply by placing a copy of the `.csplugin' file alongside the plugin executable (`.so' or `.dll').
External projects which are based upon Crystal Space's Jam build system (`CS/mk/jam') inherit, for free, the capability of embedding meta-information within plugin modules (if supported by the platform). Simply grab the newer `.jam' files from `CS/mk/jam', and add a few definitions to the project's `Jamconfig' file. The exact set of definitions is platform-specific, so consult the appropriate Jam file (`unix.jam', `win32.jam', or `macosx.jam') to determine precisely which which definitions are required. Here is a list of definitions required at the time of writing:
EMBED_META = yes
LIBBFD.AVAILABLE = yes
OBJCOPY.AVAILABLE = yes
CMD.OBJCOPY = objcopy
EMBED_META = yes
EMBED_META = yes
The `scfreg' tool whose job was to manipulate the monolithic SCF plugin-registry database, `scf.cfg', has been eliminated since it is no longer required.
The macros SCF_DESTRUCT_IBASE()
and SCF_DESTRUCT_EMBEDDED_IBASE()
have been introduced. Just as a destructor reverses initialization performed
by a constructor, these new macros reverse the initialization performed by the
corresponding SCF_CONSTRUCT_IBASE()
and
SCF_CONSTRUCT_EMBEDDED_IBASE()
macros. Typically, you should invoke
these macros within your class' destructor, just as you invoke the
corresponding SCF construction macros in your class' constructor.
The SCF_CREATE_INSTANCE()
macro now returns csPtr<>
to be
consistent with the other SCF instantiation and query macros. This means
that you should now assign the result of SCF_CREATE_INSTANCE()
to a
csRef<>
.
The macros SCF_SET_REF()
, SCF_INC_REF()
, and SCF_DEC_REF()
have been removed. Instead you should use csRef<>
.
The method iSCF::GetInterfaceName(scfInterfaceID)
has been added to
complement the existing iSCF::GetInterfaceID()
.
The query template class scfInterface<>
has been introduced. This class
provides a means to query static information about SCF interfaces, such as
an interface's version number. Presently, this class allows access to the
following static information:
GetID()
---Retrieves the interface's low-level identifier as an
`scfInterfaceID', which is typically a small integer. SCF identifies
interfaces internally by an ID for performance reasons.
GetName()
---Retrieves the interface's name as a null-terminated
C-string.
GetVersion()
---Retrieves the interface's current version number.
Here is an example illustrating how to retrieve various pieces of information about an interface.
int ver = scfInterface<iFoo>::GetVersion(); scfInterfaceID ident = scfInterface<iFoo>::GetID(); char const* name = scfInterface<iFoo>::GetName(); |
An important benefit of the new scfInterface<>
template class is that it
is now possible for template authors to perform queries for interface-related
information. For example, the author of a new template class may know an
SCF interface via only the opaque identifier T
, yet it is still
possible to query T
's version using
scfInterface<T>::GetVersion()
.
The old hidden, semi-private API for obtaining interface information via
the global `name_VERSION' constant and global name_scfGetID()
function has been removed. Conversion from the old API to the new is
straight forward. For example:
iFoo_VERSION
=> scfInterface<iFoo>::GetVersion()
iFoo_scfGetID()
=> scfInterface<iFoo>::GetID()
A consequence of this change is that it is no longer possible to invoke the
SCF_VERSION()
macro inside an alternate namespace. If previously you
were invoking this macro within your project's own namespace, you must relocate
the invocation so that it appears outside the namespace. For example:
#include <csutil/scf.h> namespace MyProject { struct iMyInterface : public iBase { ... }; } SCF_VERSION(MyProject::iMyInterface, 1, 0, 0); |
The `cssys' library has been merged into the `csutil' library. This eliminates many problems resulting from the large number of circular dependencies which existed between these two libraries. From the client viewpoint, this change manifests in two ways:
#include <cssys/header.h>
to
#include <csutil/header.h>
.
The `csengine' library has been removed. Direct use of this library has long been deprecated, so its removal will probably go unnoticed by most or all projects. Any projects which were using this library must now instead interact with the 3D engine via the `engine' plugin and the SCF interfaces in the `CS/include/iengine' directory.
The csString::strlwr()
method was renamed to Downcase()
. A
complementary Upcase()
method was added for completeness. These methods
were also added to `iString'. A Slice()
method was added to
`iString' and `csString' which copies a sub-portion of a string.
Slice()
is similar to the existing SubString()
method, but
follows a more natural calling convention. Several `iString' methods
which were incorrectly returning raw `iString*' or `iString&' now
correctly return csRef<iString>
.
A csMD5(csString const&)
constructor was added to complement the
existing csMD5(char const*)
constructor. The new method
csMD5::Digest:HexString()
returns a hexadecimal string representation of
the MD5 digest using lowercase hexadecimal characters.
csMD5::Digest::HEXString()
returns uppercase hexadecimal characters.
IntersectSegment()
for `iThingFactoryState' and `iThingState'
has been removed. Use iMeshObject::HitBeamObject()
instead.
iMeshObject::HitBeamObject()
now has an optional polygon index
parameter so you can get the index of the polygon that was hit.
iSector::HitBeam()
which doesn't support portals now returns a polygon
index instead of a polygon pointer.
iSector::HitBeam()
that supports portals has been renamed
to HitBeamPortals()
. It additionally returns a polygon index.
Same for iPortal::HitBeam()
which has also been renamed
to HitBeamPortals()
.
iCamera::GetHit()
has been removed. Instead, use the completely
equivalent function iSector::HitBeamPortals()
.
iVisibilityCuller::IntersectSegment()
now returns a polygon index
instead of a portal.
The following low-level functions, declared in `csutil/syspath.h' can be
used to query various directories and paths. Each of these functions expects
to be passed argv[0]
obtained from the program's main()
function.
csGetAppPath()
csGetAppDir()
csGetResourceDir()
csGetAppDir()
. On MacOS/X, however, for GUI applications, this
function will return the `Resources' directory within the Cocoa
application wrapper.
Since it is rarely convenient to squirrel-away argv[0]
, the following
higher-level methods, declared in `iutil/cmdline.h', are also available
for obtaining the same information once the application has been initialized.
These methods do not require access to argv[0]
. You can obtain a handle
to the shared `iCommandLineParser' from the object registry,
`iObjectRegistry', which is declared in `iutil/objreg.h'.
iCommandLineParser::GetAppPath()
iCommandLineParser::GetAppDir()
iCommandLineParser::GetResourceDir()
VFS (see section 7.2 Virtual File System (VFS)) now understands two new pseudo-variables, `$*' and `$^', in its configuration file, `vfs.cfg', and during programmatic mounts. The full list of pseudo-variables is:
$/
$@
csGetConfigPath()
.
$*
csGetResourceDir()
.
$^
csGetAppDir()
.
The expansions of the `$@', `$*', and `$^' variables always contain a trailing path delimiter.
At initialization time, VFS now searches for its configuration file,
`vfs.cfg', in the application resource directory
(csGetResourceDir()
), then in the directory containing the application
(csGetAppDir()
), and finally in the Crystal Space installation directory
(csGetConfigPath()
). The first `vfs.cfg' file found during this
search is the one used to initialize the facility. In the past, VFS
searched for `vfs.cfg' only in the Crystal Space installation directory.
Some work to improve internationalization support in Crystal Space has been performed. Crystal Space now has more complete support for Unicode input and output.
The `csUnicodeTransform' class provides functions to deal with and convert between UTF-8, UTF-16, and UTF-32 encoded strings.
Several portions of the CrystalSpace API now accept UTF-8-encoded strings. These include:
csPrintf()
csPrintfV()
csFPutErr()
iGraphics2D::Write()
csReport()
csReportV()
iReporter::Report()
iReporter::ReportV()
iNativeWindowManager::Alert()
iNativeWindowManager::AlertV()
iNativeWindow::SetTitle()
Keyboard events have changed. The event data related to keyboard events is no
longer stored in a structure inside `iEvent', but instead now resides
within `iEvent''s property bag. That means the way to access the event
data has changed slightly; you now either query for the data via
iEvent::Find()
to get a specific property, or you access it via the the
`csKeyEventHelper' class.
Another change is that the `csevKeyDown' and `csevKeyUp' events have been collapsed to a single `csevKeyboard' event; the up/down information is transported along with the event data.
The notion of scan code and characters has been replaced with raw and cooked codes. Basically, the raw code identifies the key uniquely, while the cooked code is a processed version of it. An important aspect of this is that both the raw and cooked codes are Unicode characters. Special keys (such as function keys) are encoded as characters from a Unicode private use area. Almost all event handling code should consult the raw code because the raw code is invariant; that is, an a is an `a' even if the ALT or SHIFT key, or both, are depressed. This is useful for games, for instance, which need to map keys to particular actions. Cooked codes are useful typically only for text input, such as within a text input field.
You can find additional information in Crystal Space's public API documentation in the Event Handling and Keyboard Events sections.
To understand how to adjust your code for these changes, see the following examples.
iEvent& e = ...; if (e.Type == csevKeyDown && e.Key.Code == CSKEY_ESC) { |
Change to:
if (e.Type == csevKeyboard && csKeyEventHelper::GetEventType(&e) == csKeyEventTypeDown) && csKeyEventHelper::GetCookedCode(&e) == CSKEY_ESC)) { |
Another example:
iEvent& e = ...; switch (e.Type) { case csevKeyDown: Foo(); break; case csevKeyUp: Bar(); break; } |
Change to:
switch (e.Type) { case csevKeyboard: if (csKeyEventHelper::GetEventType(&e) == csKeyEventTypeDown) Foo(); else Bar(); break; } |
The functionality provided by WriteBaseline()
is now available by
specifying the `CS_WRITE_BASELINE' flag when calling
iGraphics2D::Write()
. Hence, WriteBaseline()
is superfluous and
has been deprecated.
csInitializer::RequestPlugins(csArray<csPluginRequest>)
has been added
to complement the existing RequestPlugins(...)
which accepts a variable
number of arguments. The new overload allows the list of requested plugins to
be composed at run-time, whereas the older variable-argument method required
the list be known at compile-time, which was not always convenient or possible.
The following symbols have been renamed in order to avoid pollution of the global namespace.
STATIC_CAST()
=> CS_STATIC_CAST()
DYNAMIC_CAST()
=> CS_DYNAMIC_CAST()
REINTERPRET_CAST()
=> CS_REINTERPRET_CAST()
CONST_CAST()
=> CS_CONST_CAST()
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |