L3DT users' wiki
Large 3D terrain generator

 

Scripts > Wang tiles

Description This script generates a plane of Wang Tile indicies using the size of the design map.
Author David Walters
Created 2009 / 05 / 30
Updated 2013 / 05 / 21
Requires L3DT v2.9 or later
Download WangTiles_May2013.zs
Forum thread http://www.bundysoft.com/phpBB2/viewtopic.php?f=11&t=1156

Script contents

//
// Wang Tiling Generator
//
// by David Walters
//
// Requires L3DT v2.9 (or later).
//
// Based on: http://research.microsoft.com/en-us/um/people/cohen/WangFinal.pdf
//
// This script generates a plane of Wang Tile indicies using the size of the design map.
// It is based around a set of 8 tiles, as per. figure 1a
//
// In the above paper the tile edges are coloured. This colouring of north/south
// and east/west edges uses four colours - but this can actually be reduced to two
// colours as only opposite edges are ever compared. This lets us create a set of
// binary codes for each tile:
//
// RED or BLUE = 0; GREEN or YELLOW = 1
//
//               NS:EW
// 0: WANG_A => [01:10]
// 1: WANG_B => [11:00]
// 2: WANG_C => [00:11]
// 3: WANG_D => [10:01]
// 4: WANG_E => [01:01]
// 5: WANG_F => [11:11]
// 6: WANG_G => [00:00]
// 7: WANG_H => [10:10]
//
//
// Changes:
//
// 21st May 2013
//
//  * Updated to support new ZeoScript syntax in L3DT v2.9 and later (by A.T.)
//
// 6th May 2009
//
//  * Update to new variable declaration style
//  * Update to use new 'SetValue2' when building tables
//	* Add a call to the EditUI function to allow manual adjustment of size.
//


//==============================================================================
// Configure
//==============================================================================

// Create settings list 'ls'
varlist ls
uint ls.size_x
uint ls.size_y

// Use the design map size as default
hvar hDM
set hDM <GetMap "DM">
set ls.size_x <map.GetWidth hDM>
set ls.size_y <map.GetHeight hDM>

// edit settings list
assert <EditUI &ls "Enter Map Dimensions"> "Calculation aborted!"




//==============================================================================
// Initialisation
//==============================================================================

int x
int y
int value
int index
int current
int random

byte b

int row_base
int above_base
int is_west_one
int is_north_one




// Starting up
echo "Initialising ..."


//
// Populate 'is_east_one' array
//
// This array is a simple lookup table storing the value of the east edge.
//

hvar is_east_one
set is_east_one <new buffer>
assert <buffer.InitByType is_east_one 8 int > "Allocation failure."

// Does a tile have an 'east' value of one?
assert <buffer.SetValue2 is_east_one 0 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 1 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 2 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 3 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 4 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 5 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 6 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_east_one 7 1 > "Cannot set buffer value."


//
// Populate 'is_south_one' array
//
// This array is a simple lookup table storing the value of the south edge.
//

hvar is_south_one
set is_south_one <new buffer>
assert <buffer.InitByType is_south_one 8 int > "Allocation failure."

// Does a tile have a 'south' value of one?
assert <buffer.SetValue2 is_south_one 0 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 1 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 2 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 3 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 4 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 5 1 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 6 0 > "Cannot set buffer value."
assert <buffer.SetValue2 is_south_one 7 0 > "Cannot set buffer value."


//
// Populate 'west' array
//
// This is an array of tiles, two groups of four, that are the tiles
// that can be matched with east values of zero and one respectively.
//

hvar west
set west <new buffer>
assert <buffer.InitByType west 8 int > "Allocation failure."

// EAST: 0 => WEST: 0 (abgh)

assert <buffer.SetValue2 west 0 0 > "Cannot set buffer value." // WANG_A
assert <buffer.SetValue2 west 1 1 > "Cannot set buffer value." // WANG_B
assert <buffer.SetValue2 west 2 6 > "Cannot set buffer value." // WANG_G
assert <buffer.SetValue2 west 3 7 > "Cannot set buffer value." // WANG_H

// EAST: 1 => WEST: 1 (cdef)  

assert <buffer.SetValue2 west 4 2 > "Cannot set buffer value." // WANG_C
assert <buffer.SetValue2 west 5 3 > "Cannot set buffer value." // WANG_D
assert <buffer.SetValue2 west 6 4 > "Cannot set buffer value." // WANG_E
assert <buffer.SetValue2 west 7 5 > "Cannot set buffer value." // WANG_F


//
// Populate 'north' array
//
// This is an array of tiles, two groups of four, that are the tiles
// that can be matched with south values of zero and one respectively.
//

hvar north
set north <new buffer>
assert <buffer.InitByType north 8 int > "Allocation failure."

// SOUTH: 0 => NORTH: 0 (aceg)

assert <buffer.SetValue2 north 0 0 > "Cannot set buffer value." // WANG_A
assert <buffer.SetValue2 north 1 2 > "Cannot set buffer value." // WANG_C
assert <buffer.SetValue2 north 2 4 > "Cannot set buffer value." // WANG_E
assert <buffer.SetValue2 north 3 6 > "Cannot set buffer value." // WANG_G

// SOUTH: 1 => NORTH: 1 (bdfh)

assert <buffer.SetValue2 north 4 1 > "Cannot set buffer value." // WANG_B
assert <buffer.SetValue2 north 5 3 > "Cannot set buffer value." // WANG_D
assert <buffer.SetValue2 north 6 5 > "Cannot set buffer value." // WANG_F
assert <buffer.SetValue2 north 7 7 > "Cannot set buffer value." // WANG_H


//
// Populate 'wang_table' array
//
// This is an array of tiles that resolves the two constraints of
// main body tiles. Each combination of constraints has two choices
// picked at random.
// 

hvar wang_table
set wang_table <new buffer>
assert <buffer.InitByType wang_table 8 int > "Allocation failure."

// ====== WEST:0

// === NORTH:0
assert <buffer.SetValue2 wang_table 0 0 > "Cannot set buffer value." // WANG_A
assert <buffer.SetValue2 wang_table 1 6 > "Cannot set buffer value." // WANG_G

// == NORTH:1
assert <buffer.SetValue2 wang_table 2 1 > "Cannot set buffer value." // WANG_B
assert <buffer.SetValue2 wang_table 3 7 > "Cannot set buffer value." // WANG_H

// ====== WEST:1

// === NORTH:0
assert <buffer.SetValue2 wang_table 4 2 > "Cannot set buffer value." // WANG_C
assert <buffer.SetValue2 wang_table 5 4 > "Cannot set buffer value." // WANG_E

// === NORTH:1
assert <buffer.SetValue2 wang_table 6 3 > "Cannot set buffer value." // WANG_D
assert <buffer.SetValue2 wang_table 7 5 > "Cannot set buffer value." // WANG_F

// Prepare a buffer for all tiles
hvar tiles
set tiles <new buffer>
assert <buffer.InitByType tiles <mul ls.size_x ls.size_y > int > "Allocation failure."



//==============================================================================
// Generate Tiles
//==============================================================================

//
// Say Hello
//

string hello
set hello "Generating Wang Tiles ( "
set hello <strcat hello ls.size_x >
set hello <strcat hello " x " >
set hello <strcat hello ls.size_y >
set hello <strcat hello " )" >
echo hello


//
// Generate First Tile - pick any tile
//

// current = rand() % 8
set current <mod <rand > 8 > // [0-7]

// tiles[ 0 ] = current
assert <buffer.SetValue tiles 0 current > "Cannot set buffer value."


//
// Tile the First Row
//
// For each tile in this row the east/west "colour" should match. We use the
// 'is_east_one' lookup table to first see what our constraint is, then pick one
// of the four possible tiles at random from the 'west' array.
//

set x 1
do

  // value = is_east_one[ current ]
  assert <buffer.GetValue is_east_one current value > "Cannot get buffer value."

  // current = west[ value ][ random ]
  set random <mod <rand > 4 > // [0-3]
  set index <add <mul value 4 > random >
  assert <buffer.GetValue west index current > "Cannot get buffer value."

  // Store 'current' as new tile
  assert <buffer.SetValue tiles x current > "Cannot set buffer value."

set x <incr x >
while <islt x ls.size_x >


//
// For each remaining row...
//

set y 1
do

  // First: Compute index of the first element of the row, and the one above.
  set row_base <mul y ls.size_x >
  set above_base <mul <sub y 1 > ls.size_x >


  //
  // Pick Row Start
  //
  // The first tile of a row must match with the south edge of the tile above.
  // We use the 'is_south_one' this time to identify our constraint and then pick
  // randomly from one of the four tiles in the 'north' array.
  //
  
  // value = is_south_one[ tiles[ above_base ] ]
  assert <buffer.GetValue tiles above_base current > "Cannot get buffer value."
  assert <buffer.GetValue is_south_one current value > "Cannot get buffer value."

  // current = north[ value ][ random ]
  set random <mod <rand > 4 > // [0-3]
  set index <add <mul value 4 > random >
  assert <buffer.GetValue north index current >  "Cannot get buffer value."

  // Store 'current' as new tile of this row
  assert <buffer.SetValue tiles row_base current >  "Cannot set buffer value."



  //
  // Complete the Row
  //
  // Additional tiles of these rows must now conform to two constraints.
  // One from the north, and another from the west.
  //

  set x 1
  do

    // What is the 'colour' of the edge to the west of this tile?
    // (the value of the tile to the west is stored in 'current')
    assert <buffer.GetValue is_east_one current is_west_one >  "Cannot get buffer value."

    // What is the 'colour' of the edge to the north of this tile?
    set index <add above_base x >
    assert <buffer.GetValue tiles index value >  "Cannot get buffer value."
    assert <buffer.GetValue is_south_one value is_north_one >  "Cannot set buffer value."

     // We have two choices for each tile ...
    set random <mod <rand > 2 >


    // current = wang_table[ is_west_one ][ is_north_one ][ random ]
    set index <mul is_west_one 4 >
    set index <add index <mul is_north_one 2 > >
    set index <add index random >
    assert <buffer.GetValue wang_table index current >  "Cannot get buffer value."

    // Store 'current' in our row in the tiles array
    set index <add row_base x >
    assert <buffer.SetValue tiles index current >  "Cannot set buffer value."

  set x <incr x >
  while <islt x ls.size_x >

set y <incr y >
while <islt y ls.size_y >


echo " ...generation complete."



//==============================================================================
// Write Data
//==============================================================================

string FileName
set FileName <file.SaveDlg "bin" NULL "Wang Tiling files (*.bin)|*.bin|All files (*.*)|*.*|">
if <iseq 0 <strlen FileName>>
  return 0
endif

voidptr fp
set fp <fopen FileName "w">
assert fp "Cannot open file!"

set y 0
do

  set x 0
  do

    // Get the tile value
    set index <add <mul y ls.size_x > x >
    assert <buffer.GetValue tiles index current >  "Cannot get buffer value."

    // Cast to a byte, and write 8-bits
    set b current
    fwrite fp b

  set x <incr x >
  while <islt x ls.size_x >

set y <incr y >
while <islt y ls.size_y >

fclose fp

echo "done."

// [EOF]
 
scripts/wang_tiles.txt · Last modified: 2017/08/31 04:45 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki