You can find technical information about KCL files in the Custom Track Wiiki:
A KCL or OBJ file can also used to adjust points of different KMP sections. See »KCL-FALL« for details.
Compatible tools:
wszst extract --decode <TRACK_FILE.szs> ... wszst extract --all <TRACK_FILE.szs> ... wszst xdecode <TRACK_FILE.szs> ... wszst xall <TRACK_FILE.szs> ...The new directory contains the binary KCL file (e.g. course.kcl) and also an object file (e.g. course.kcl.obj). The disadvantage of the commands above is, that all files are extracted from the archive. The following commands will only decode the KCL and do not touch other files:
wkclt decode <TRACK_FILE.szs> wkclt decode <KCL_FILE.kcl> wkclt copy <TRACK_FILE.szs> <EXPORT>.obj wkclt copy <KCL_FILE.kcl> <EXPORT>.obj
There are also several commands to decode a KCL to standard output;
wszst kcl <TRACK_FILE.szs> wszst cat <TRACK_FILE.szs/course.kcl> --decode wkclt cat <TRACK_FILE.szs>
It is also possible, to inlcude KMP elements into the OBJ export. See command wkmpt DRAW for details.
The default is to create also a material file with adequate colors. The material file can be disabled by clearing the parameter MTL.
The first example shows a part of a Maple Treeway export in SketchUp:
The second example shows a part of a Koopa Cape export in 3ds max:
Compatible tools:
wszst create TRACK_DIR.d
To create a binary KCL file, use the command wkclt ENCODE or wkclt COPY:
wkclt encode OBJ_FILE.obj wkclt copy OBJ_FILE.obj COURSE.kclConfiguration parameters are also possible:
wkclt encode OBJ_FILE.obj --const kcl_max_depth=7 --kcl roundThe following command cleans the KCL and recreates the octree and saves the result by replacing the source file:
wkclt encode course.kcl --kcl drop,new
If found, the defined KCL flag is used and searching is aborted. A negative value means: Ignore the triangles of this group and exclude them from the KCL.
Example:
This old kind of definition is only accepted, if parameter HEX4 is set, either by option --kcl or by defining a variable in the flag file.
Example:
This old kind of definition is only accepted, if parameter HEX23 is set, either by option --kcl or by defining a variable in the flag file.
Example:
The flag file is searched for lines in the format:
The text parser is used for scanning the flag file. This means you have the power of if..then..else, loops, variable definitions, macros, functions and numeric expressions. It's also possible, to use extern defined constants for conditional execution.
Example for a simple flag file:
# KCL Flag assignment for MYTRACK (yes, comments are possible) # First, we define a flag function named f(). # This allows us to define type and variant as 2 values. @function f # (type,variant) @return $1 | $2 << 5 @endfunction # group_name = type,variant # comment #----------------------------------------------------------------------- *nokcl* = -1 # ignore all groups marked with 'nokcl' main_road = f(0x00,0x005) # this is the main road side_way = 0x0200 # define a KCL directly as 16 bits offroad = f(0x03,0x002) # mud road *road* = f(0x01,0x000) # all other groups marked with 'road' *boost* = f(0x06,0x000) # all groups marked with 'boost' * = f(0x0f,0x000) # all others are walls # Here we can override the global settings made by --kcl HEX4,HEX23. # Set HEX4 and/or HEX23 to 0 (disable) or 1 (enable) to accept group # names in the formats '_ffff' and/or '_tt_vvv' for defining KCl flags, # if all other rules fail. Uncomment to activate: #@def hex4 = 1 #@def hex23 = 1
The creation of the octree is done fully automated, but it can be controlled and fine tuned by the configuration parameters (in alphabetic order): KCL_BITS, KCL_BLOW, KCL_MAX, KCL_MAX_TRI, KCL_MAX_DEPTH, KCL_MIN, KCL_MIN_SIZE and KCL_MAX_SIZE.
For the octree, the world is divided into equal sized cubes. The world is the smallest cuboid that contains all triangles of the KCL model. The parameters KCL_MIN and KCL_MAX may override the automatic calculation. Remember, a cube is also a cuboid, but with 6 equal square sides and 12 equal edges.
For the octree operations, all coordinates are rounded to integers and a well defined minimal 3D-point (see above) is used as origin. The edge length of a base cube is always a power of 2. The number of base cubes of each direction is also a power of 2. All base cubes together are the cube world, which is usually larger than the triangle word, but never smaller.
If option CENTER is enabled, then adjust the octree entrance coordinates, so that thetriangle world is centered inside the cube world.
For a given point, a fast hash value is calculated form the highest bits
of each coordinate. The hash value is used as first index into the octree
to find the related base cube.
The parameter KCL_BITS defines the maximal
number of hash bits for the new octree.
The number of base cubes is exact
Now it becomes recursive: For each cube count the number of triangles that collide with the current cube. For this collision calculations the cube is blown up (see parameter KCL_BLOW) to integrate triangles of the neighborhood. The recursion is stopped, if one of the following 3 conditions becomes true:
If a source has more than 16383 (0x3fff) triangles, the fast modus for the creation of the vertex and normal lists is disabled to avoid a normal list overflow.
# wkclt filetype * type file name --------------------------- KCL course.kcl KCLTXT course.obj SKPOBJ sketchup-orig.obj WAVOBJ sketchup-plugin.obj
For KCL processing, there are 4 relevant file types:
Wavefront OBJ files are simple text files. To distinguish OBJ files from other text files, the tools try to find some prominent strings at special places. It is done by the following algorithm:
Another way to traverse the octree is the command wkclt FALL.
For each entered point, a cube with edge length 100.0 is created and dropped.
The cube falls until a KCL collison is found.
The new position is printed to standard output.
The cube size can be changed by setting the constant
The following table shows all user keyword (there are some more hidden keywords for development). Some few keywords are enabled by default; see the description.
Keywords for option --kcl | |
---|---|
keyword | Description |
This keyword clears (disables) all other keywords. | |
This keyword resets all keywords to their default status: MEDIUM and MTL are set, all others are cleared. | |
SMALL MEDIUM CHARY |
These keywords decide the default values for
the configuration parameters
KCL_BLOW and KCL_MAX_TRI
and some more settings:
|
If creating a binary KCL file,
the tools try to find duplicate vertex and normal entries.
For the octree creation, the tools try to find duplicate triangle lists.
These duplicates will share the same memory to reduce the file size.
If However, if a source has more than 16383 (0x3FFF) triangles (see limits), the fast modus for the creation of the vertex and normal lists is disabled to avoid a list overflow.
If keyword SMALL is active, |
|
Force the creation if a new octree. This keyword has only impact, if input and output are binary KCL files. | |
After calculating the octree parameters and before creating a new octree, adjust the octree entrance coordinates, so that the triangle world is centered in the octree relevant area. | |
On calculating normals, each coordinate is rounded to the nearest
multiple of
Parameter |
|
If creating an OBJ file and The default since version v1.30a is to do not export the normals. This setting is the best for the free SketchUp OBJ importer, because othwerwise it misinterprets some face directions. |
|
MTL MATERIALS |
If creating an OBJ file and |
Normally, each created OBJ file has its own material file with the same
filename, but with extension
If this option is set, the material file is called |
|
If creating an OBJ file, the triangles are stored as vertices
and faces, like other tools do and understand it.
But if
If
On scanning, |
|
OUT-SWAP OUTSWAP OSWAP |
If set, the second and third points (1-based counting) of the triangles are exchanged while creating an OBJ file. |
IN-SWAP INSWAP ISWAP |
If set, the second and third points (1-based counting) of the triangles are exchanged while reading an OBJ file. |
If this keyword is set while an OBJ file is scanned, then all points with a defined normal for point 1 are analyzed to find the optimal order of the second and third triangle point. | |
USEMTL |
If reading an OBJ file, the faces are divided into groups and a KCL flag
value is assigned to each group using a flag file.
The groups and its names are derived from the OBJ commands
|
Some custom tracks were created by overwriting some data into an existent KCL file.
Sometimes, triangles are not overwritten,
but some of their related source data (vertex or normals).
As result, the triangle points are far away from the main world.
If |
|
If this keyword is set and no flag is defined for an OBJ group,
and if the 5 last characters of the group name are in the format
This global setting can be overridden by defining a integer variable in
the flag file named |
|
If this keyword is set and no flag is defined for an OBJ group,
and if the 7 last characters of the group name are in the format
This global setting can be overridden by defining a integer variable in
the flag file named |
|
Keyword |
|
DROPUNUSED |
In some custom tracks you can find triangles that are not used by the octree.
And that means, that they are useless.
If keyword |
DROPFIXED |
If using KCL_CLIP to find extreme values,
some triangles may be marked internally as fixed.
If keyword |
DROPINVALID |
While reading data, the tools look for invalid numbers
(NAN and INFINITE for example).
Also calculations of the triangle points may result in invalid numbers
(examples: 2 points at the same position or 3 points in a line
or triangle to small or large).
If keyword |
If exporting a KCL to an object file and no DROP-Mode is specified,
|
|
RMFACEDOWN |
Face down roads are usually not needed and are the reason for a lot of glitches:
|
RMFACEUP |
Horizontal face up walls are like prisons, if a player reach it. Because of a wall, a player can't move. And because of the horizontal direction, the player don't slip to any direction. This feature is available since v1.49a. |
FIXALL |
|
CONVFACEUP |
Horizontal face up walls are like prisons, if a player reach it. Because of a wall, a player can't move. And because of the horizontal direction, the player don't slip to any direction. This feature is available since v1.49a. |
WEAKWALLS |
Set the most significant bit (bit 15, 0x8000) of KCL flag of all walls. It stops hard bumping at the edges and has similar effects like lowering the walls. |
If |
|
If a KCL file withing a SZS file is replaced by a new version,
the SZS file is rearanged (sub files are moved) to give the new KCL
optimal space.
If |
|
This debugging keyword sort the triangles by length and positions to make all dumps more and easier comparable. | |
If set, the KCL status lines about the set keywords and more are suppressed. | |
This is a debugging keyword. If set, the tools create a trace log about the main KCL reading, modifying and writing steps. |
See also »Configuration Parameters« for parameters with values.
Let's start with easy rules:
We want to find all triangles with KCL flag 0x1234 and want
to set the new KCL flag 0x5678:
You don't need to write leading zeros
and it's always possible to add more rule separated by a comma:
In the last example, 2 flags are replaced by the same value.
This can also be written as:
More usual is to replace the base type without changing the variant bits.
In the following example we replace type 0x01 (road) by 0x17 (another road).
We do this by using a
You can also enter you codes in decimal notation:
Now we want to replace all roads of types 0..4 to type 0x17:
You can use also the mask notation
An existing octree is untouched, if only KCL flags are changed. To force the creation of a new octree, use parameter NEW.
The main goal of a KCL script is to iterate through all items and to modify positions or KCL flags, or to add or remove complete triangles.
The following script shows an example for lowering walls to avoid the hard edges:
# Setup @def start = mSec() # start time, for the status line @def mod_count = 0 # modification counter # Get the value for lowering the walls. # If 'lower' is defined as number by option --const, use it. # Otherwise use the default of 50. @def lower = isNumeric(lower) ? lower : 50 # Define a function to test the KCL flag for walls @function isWall # flag @pdef t = $1 & 0x1f @return t == 0x0c || t == 0x0d || t == 0x0f > || t == 0x14 || t == 0x1e || t == 0x1f @endfunction # Main loop: Iterate through all triangles @for t=0;tri$n()-1 @if isWall(tri$flag(t)) # Is it a wall? # If yes, lower the wall & increment the counter @def status = tri$shift(t,-vy(lower)) @def mod_count = mod_count+1 @endif @endfor # Print a little status line @echo " - " mod_count " of " tri$n() " triangles lowered by " lower > " in " (mSec()-start) " msec."
The following table shows the special triangle function. All other parser functions are also available:
Triangle Functions | ||
---|---|---|
File Type |
Return Value & Function Name & Parameters |
Description |
KCL | int tri$create (kcl_flag,pt0,pt1,pt2,...) |
This function appends new triangles at the end of the triangle list with the entered parameters. If more than 3 points are entered, all points must be in the same plane and the polygon is split into multiple (N-2) triangles. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createAntiArrow (flag,pt1,pt2,ptX,r,n,a_flag[,a_size][,b_flag][,b_ht]) |
This function creates an antiprism based arrow with radius 'r' and N faces from 'pt1' to 'pt2', where 'pt2' is the place of the arrowhead. The point 'ptX' is used for the orientation (direction of first edge). 'flag', 'a_flag' and 'b_flag' are KCL flags to define the color. 'a_size' is the addition size factor of the arrowhead, the default is 1.0. If 'b_flag' is not set or @-1@, no base is drawn. If 'base_height' is set, a pyramid is drawn as base. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createAntiPrism (kcl_flag,pt1,pt2,ptX,r,n[,base_flag][,base_height]) |
This function creates an antiprism with radius 'r' and N faces from 'pt1' to 'pt2' by adding 2*N triangles. The point 'ptX' is used for the orientation (direction of first edge). If 'base_flag' is set and not @-1@, the base is printed with ths kcl flag value. If 'base_height' is set, a pyramid is drawn as base. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createArrow (flag,pt1,pt2,ptX,r,n,a_flag[,a_size][,b_flag][,b_ht]) |
This function creates a prism based arrow with radius 'r' and N faces from 'pt1' to 'pt2', where 'pt2' is the place of the arrowhead. The point 'ptX' is used for the orientation (direction of first edge). 'flag', 'a_flag' and 'b_flag' are KCL flags to define the color. 'a_size' is the addition size factor of the arrowhead, the default is 1.0. If 'b_flag' is not set or @-1@, no base is drawn. If 'base_height' is set, a pyramid is drawn as base. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createCuboid (kcl_flag,pos,size[,rot]) |
This function creates a cuboid by adding 12 triangles. If 'size' is a scalar, a cube with the entered edge length is created. If 'rot' is set, the cube is rotated. As last operation the center (origin) of the cube is shifted to 'pos'. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createJoist (kcl_flag,length,pt1,pt2,pt_dir[,n_marker][,mark5_flag]) |
This function appends a triangular joist from 'p1' to 'p2' to at the end of the triangle list. 'length' the length of the body and 'pt_dir' is a helper point for its direction. If 'n_marker' is >0, markers representing the number are added. If 'mark5_flag' is >0, every 5 markers are replaced by one of the entered flag. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createOctahedron (kcl_flag,pos,radius[,rot]) |
This function creates a octahedron by adding 8 triangles. If 'radius' is a scalar, a regular octahedron created. Otherwise it is a vector and define different radiuses for each axis. If 'rot' is set, the octahedron is rotated. As last operation the center (origin) of the cube is shifted to 'pos'. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createPrism (kcl_flag,pt1,pt2,ptX,r,n[,base_flag][,base_height]) |
This function creates a prism with radius 'r' and N faces from 'pt1' to 'pt2' by adding 2*N triangles. The point 'ptX' is used for the orientation (direction of first edge). If 'base_flag' is set and not @-1@, the base is printed with ths kcl flag value. If 'base_height' is set, a pyramid is drawn as base. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$createPyramid (kcl_flag,apex,pt1,pt2,...) |
This function creates a pyramid by adding N triangles. 'pt1'..'ptN' descibribes the base polygon, which is not created. The function returns the index of the first new triangle or -1 if failed. |
KCL | int tri$defColor (argb[,alpha]) |
Define a new color. 'ARGB' is a bytes coded color: alpha,red,green,blue. If 'ALPHA' is not set, the highest byte of 'ARGB' is used. If this highest byte is null, 0xff (no transparency) is used. The function returns -1, if already 200 colors defined. Otherwise it returns the virtual KCL flag for the user defined color. |
KCL | int tri$defColor (red,green,blue[,alpha]) |
Define a new color. If ALPHA is not set, 0xff (no transparency) is used. For the 3 colors, values between 0x00 and 0xff are expected. The function returns -1, if already 200 colors defined. Otherwise it returns the virtual KCL flag for the user defined color. |
KCL | int tri$flag (tri_index[,mode]) |
This function returns the KCL flag of the triangle 'tri_index' (0..). If mode is '1', the original source value is returned. If mode is '2', the original source value transformed by --kcl-flag is returned; if --kcl-flag is not set, it is the same as mode '1'. Otherwise the current value is returned. The current value is initialized by the value of mode '2'. Values >0xffff are possible and represent internal drawings. |
KCL | int tri$getColor (index) |
This function returns the color defined by a previous tri$defColor() call. INDEX is the virtual KCL flag for the user defined color. On error, the value NONE (type 'undefined') is returned. |
KCL | int tri$hRot (tri_index,degree[,origin]) |
This function rotates the triangle 'tri_index' (0..) horizontal counterclockwise by the angle 'degree' around the point 'origin'. If the origin is not set, v(0,0,0) is used instead. |
KCL | int tri$isRemoved (tri_index) |
This returns the status of the 'REMOVED' marker of the triangle 'tri_index' (0..). The return value is -1 for an invalid index, 1 if the triangle is marked as removed or 0 if not. |
KCL | float tri$length (tri_index) |
This function returns the length of triangle 'tri_index' (0..). |
KCL | vector tri$n () |
This function returns the number of triangles. |
KCL | vector tri$normal (tri_index,norm_index) |
This function returns the normal with index 'norm_index' (0..3) of triangle 'tri_index' (0..). |
KCL | vector tri$pt (tri_index,pt_index) |
This function returns the point with index 'pt_index' (0..2) of triangle 'tri_index' (0..). |
KCL | int tri$ptsInCuboid (tri_index,cube_min,cube_max) |
Parameters 'cube_*' are converted to vectors. They describe 2 diagonal corners of a rectangular cuboid, assuming that 'cube_min<=cube_max' is true for each coordinate. The functions returns the number of points of the triangle 'tri_index' (0..), that are inside of the cube including the border. If 'tri_index' is invalid, -1 is returned. |
KCL | int tri$remove (tri_index) |
This function marks the triangle 'tri_index' (0..) as 'REMOVED'. The return value is -1 for an invalid index, 1 if the triangle was already removed or 0 if not. |
KCL | int tri$scale (tri_index,scale[,origin]) |
This function scales the triangle 'tri_index' (0..) by the vector 'scale' relative to point 'origin'. If the origin is not set, v(0,0,0) is used instead. |
KCL | int tri$setFlag (tri_index,new_flag) |
This function sets the new KCL flag of triangle 'tri_index' (0..). The function returns -1 for an invalid index or the previous value of the KCL flag. |
KCL | int tri$setPt (tri_index,pt0,pt1,pt2) |
This function sets the coordinates of all 3 points of the triangle 'tri_index' (0..) to the vectors 'pt*'. |
KCL | int tri$setPt (tri_index,pt_index,pt) |
This function sets the coordinates of the single point with index 'pt_index' (0..2) of triangle 'tri_index' (0..). to the vector 'pt'. |
KCL | int tri$shift (tri_index,shift) |
This function adds the vector 'shift' to all 3 points of the triangle 'tri_index' (0..). |
KCL | int tri$type (tri_index[,mode]) |
This function returns the KCL type of the triangle 'tri_index' (0..). It works like tri$flag(), but the flag is transformed to a type. The return value is in the range of 0x00..0x1f (5 lowest bits of the flag), if it is a real KCL flag (<0x10000), or -1 otherwise (special type). |
KCL | int tri$unremove (tri_index) |
This function clears the 'REMOVED' marker of the triangle 'tri_index' (0..). The return value is -1 for an invalid index, 1 if the triangle was removed or 0 if not. |
Since v1.58a there exist 2 new options:
Option
Option
The tests for both options are executed after reading files, after transformations, and after calculating normals and lengths.
Examples:
# define a unique flag file: --flag-file /path/to/flag-file.ext # redirect only the search directory --flag-file /path/to/directory/%N.flag # use '.txt' as file extension --flag-file %P/%N.txt # disable flag files at all --flag-file ""Read »Escape Sequences« for more details about %-escapes.
Examples:
wkclt encode TRACK.obj --scale 100.0 # scale all 3 dimensions wkclt encode TRACK.obj --scale "v(100,1,100)" # scale only X+Z
If decoding or encoding a KCL file, some constants are used, to define parameters and to override the defaults of the algorithms. And here is the list of all constants, that are relevant for KCL handling.
Examples:
--const kcl_clip=2.0 -c 'KCL_CLIP=v(1,3,2)' --const KCL_BITS=4,KCL_MAX_TRI=20,KCL_MAX_DEPTH=6See also option
The default value is calculated by using the total number of triangles and will be never larger than 10 (1024 base cubes). The user can set values in the range of 3..20@ (8..1048576 base cubes). The impact of this parameter for running a track is not clear now.
While creating the octree, colliding triangles are searched for each cube.
Therefor the cube will be temporary expanded by addding the value of
The default value depends on the --kcl options
SMALL, MEDIUM and CHARY
and is either
The SZS Tools try to avoid this: If calculating the triangle points, borders are defined. Points outside this borders are set to the vertex point of the triangle. This border is only used, if setting CLIP is set.
The calculation is simple.
Find the minimal and maximal predefined vertex positions,
add a little value and expand the world by factor 3.
The world is then again expanded by the vector value
It is also possible to set each coordinate with a single assignment by using
BTW: --kcl DROP-UNUSED is a more intelligent method to find wasted triangles.
The real upper border is then:
It is also possible to set each coordinate with a single assignment by using
The average number of triangles in Nintendo tracks is
The default value depends on the --kcl options
SMALL, MEDIUM and CHARY
and is either
It is also possible to set each coordinate with a single assignment by using
The user can set values in the range of
It seems, that this is the main recursion stop reason if creating an octree, because all Nintendo tracks have cubes with 512 units and no one have smaller cubes. The impact of this parameter for running a track is not clear now.
The user can set values in the range of
A special optimization is done, if input and output are binary KCL and parameter NEW is not set and only KCL flags were changed: In this case, the changed flags are written to the original binary data and the modified binary data is written to the output file.