rem Most of the code is converted from an old C project.

import "OpenGL.lib"
import "gl_h.lib"

constant:
	MAP_VERSION 1

	rem shaders.
	TD_NONE 0
	TD_FLAT 1
	TD_SMOOTH 2
	MAX_OBJECTS 100

	rem Wallmap.
	TD_MAX_TEXTURES 64

	rem Diagonal split types.
	TD_SPLIT_0Z_X0   0
	TD_SPLIT_00_XZ   1
	TD_SPLIT_0Z_X0_L 2
	TD_SPLIT_0Z_X0_R 3
	TD_SPLIT_00_XZ_L 4
	TD_SPLIT_00_XZ_R 5

	rem Texture modes.
	TD_MAP 0
	TD_STRETCH 1
	TD_STICK_TOP 2
	TD_STICK_BTM 3

	TD_EDIT_WALLS     0
	TD_EDIT_FLOOR     1
	TD_EDIT_CEILING   2
	TD_EDIT_HEIGHTMAP 3

	rem Wall, floor and ceil fields.
	TD_Y0 0
	TD_Y1 1
	TD_y2 2
	TD_y3 3
	TD_N0X 4
	TD_N0Y 5
	TD_N0Z 6
	TD_N1X 7
	TD_N1Y 8
	TD_N1Z 9

	rem Corners.
	TD_CORNER_BTM_LEFT	1
	TD_CORNER_BTM_RIGHT	2
	TD_CORNER_TOP_RIGHT	4
	TD_CORNER_TOP_LEFT	8
	TD_CORNER_BTM       3
	TD_CORNER_TOP       12
	TD_CORNER_LEFT      9
	TD_CORNER_RIGHT     6
	TD_CORNER_ALL       15

	UNIT_2X1# 0.70710678	

visible:
	vMeshName
	vObjects?[MAX_OBJECTS]
	
	rem camera.
	vCamX#
	vCamY#
	vCamZ#
	vCamYaw#
	vCamPitch#
	vCamRoll#

	rem light.
	vLightDX#
	vLightDY#
	vLightDZ#

	rem heightmap.
	hm_Map?[][]
	hm_SizeX
	hm_SizeZ
	hm_Diff#
	td_Heightmap
	hm_Filename$

	rem background.
	td_BGSphere
	td_BGTexture
	td_BGTextureFN$
	td_BG = false

	rem Every tile consists of four orthogonal walls, one diagonal,
	rem one floor and one ceiling. Each entity is defined by four
	rem y values.
	td_Wallmap
	td_wmw
	td_wmh
	td_floor#[][][]
	td_ceil#[][][]
	td_wall#[][][][]
	td_tile?[][]
	td_color#[10][3]
	td_WMTextures[TD_MAX_TEXTURES]
	td_WMTextureFN$[TD_MAX_TEXTURES]
	td_WMNumTextures

	rem wallmap edit.
	tded_XTile
	tded_ZTile
	tded_Wall
	tded_Diagonal
	tded_Y#
	tded_Mode = TD_EDIT_WALLS
	tded_Texture = 0
	tded_Corner = TD_CORNER_BTM_LEFT OR TD_CORNER_BTM_RIGHT OR TD_CORNER_TOP_RIGHT OR TD_CORNER_TOP_LEFT
	tded_Visible = false
	tded_Wireframe = false
	tded_SplitMode = TD_SPLIT_0Z_X0
	tded_TextureWrapMode = TD_MAP

hidden:

rem if not TD_Init("ThreeDee Test", 32, 32, 800, 600, 60.0, 0.1, 16.0, false) then end
rem if not TD_LoadWallmap("assets/wallmap.txt") then end

rem Init map.
procedure TD_InitMap(w, h)
	td_wmw = w
	td_wmh = h
	td_floor#[td_wmw][td_wmh][10]
	td_ceil#[td_wmw][td_wmh][10]
	td_wall#[td_wmw][td_wmh][5][4]
	td_tile?[td_wmw][td_wmh]
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			rem Textures.
			td_tile[x][z].f = -1
			td_tile[x][z].c = -1
			td_tile[x][z].ft = -1
			td_tile[x][z].ct = -1
			td_tile[x][z].w0 = -1
			td_tile[x][z].w1 = -1
			td_tile[x][z].w2 = -1
			td_tile[x][z].w3 = -1
			td_tile[x][z].w4 = -1
			td_tile[x][z].wt0 = TD_MAP
			td_tile[x][z].wt1 = TD_MAP
			td_tile[x][z].wt2 = TD_MAP
			td_tile[x][z].wt3 = TD_MAP
			td_tile[x][z].wt4 = TD_MAP
			td_tile[x][z].l# = 1.0
			rem Diagonal info.
			td_tile[x][z].d = 0
			rem Blocked?..
			td_tile[x][z].b = 0
			rem Coordinates.
			for i = 0 to 3; td_floor[x][z][i] = 0.0; td_ceil[x][z][i] = 1.0; next
			td_floor[x][z][4] = 0.0; td_floor[x][z][5] = 1.0; td_floor[x][z][6] = 0.0
			td_floor[x][z][7] = 0.0; td_floor[x][z][8] = 1.0; td_floor[x][z][9] = 0.0
			td_ceil[x][z][4] = 0.0; td_ceil[x][z][5] = -1.0; td_ceil[x][z][6] = 0.0
			td_ceil[x][z][7] = 0.0; td_ceil[x][z][8] = -1.0; td_ceil[x][z][9] = 0.0
			for i = 0 to 4
				td_wall[x][z][i][0] = 0.0
				td_wall[x][z][i][1] = 0.0
				td_wall[x][z][i][2] = 1.0
				td_wall[x][z][i][3] = 1.0
			next
		next
	next
	for i = 0 to TD_MAX_TEXTURES - 1
		if td_WMTextures[i] > 0 then _glDeleteTexture td_WMTextures[i]
		td_WMTextureFN[i] = ""
	next
	rem Colors.
	for i = 0 to 9; for j = 0 to 2; td_color#[i][j] = 1.0; next; next
	_TD_BuildMap
endproc

rem Render wall map while editing or building.
procedure TD_RenderWallmap()
	rem Should do one cycle per texture instead to avoid binding.
	for i = 0 to TD_MAX_TEXTURES - 1
	_glBindTexture GL_TEXTURE_2D, td_WMTextures[i]
	_glBegin GL_QUADS
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			rem Orthogonal walls.
			if td_tile[x][z].w0 = i
				_glColor3f td_color[0][0], td_color[0][1], td_color[0][2]
				if td_tile[x][z].wt0 = TD_MAP
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][0][0]; _glVertex3f float(x), td_wall[x][z][0][0], float(z)
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][0][1]; _glVertex3f float(x), td_wall[x][z][0][1], float(z) + 1.0
      		_glTexCoord2f 1.0, 1.0 - td_wall[x][z][0][2]; _glVertex3f float(x), td_wall[x][z][0][2], float(z) + 1.0
      		_glTexCoord2f 0.0, 1.0 - td_wall[x][z][0][3]; _glVertex3f float(x), td_wall[x][z][0][3], float(z)
				else
					_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_wall[x][z][0][0], float(z)
					_glTexCoord2f 1.0, 1.0; _glVertex3f float(x), td_wall[x][z][0][1], float(z) + 1.0
      		_glTexCoord2f 1.0, 0.0; _glVertex3f float(x), td_wall[x][z][0][2], float(z) + 1.0
      		_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_wall[x][z][0][3], float(z)
				endif
			endif
			if td_tile[x][z].w1 = i
				_glColor3f td_color[1][0], td_color[1][1], td_color[1][2]
				if td_tile[x][z].wt1 = TD_MAP
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][1][0]; _glVertex3f float(x) + 1.0, td_wall[x][z][1][0], float(z)
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][1][1]; _glVertex3f float(x), td_wall[x][z][1][1], float(z)
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][1][2]; _glVertex3f float(x), td_wall[x][z][1][2], float(z)
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][1][3]; _glVertex3f float(x) + 1.0, td_wall[x][z][1][3], float(z)
				else
					_glTexCoord2f 0.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][1][0], float(z)
					_glTexCoord2f 1.0, 1.0; _glVertex3f float(x), td_wall[x][z][1][1], float(z)
					_glTexCoord2f 1.0, 0.0; _glVertex3f float(x), td_wall[x][z][1][2], float(z)
					_glTexCoord2f 0.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][1][3], float(z)
				endif
			endif
			if td_tile[x][z].w2 = i
				_glColor3f td_color[2][0], td_color[2][1], td_color[2][2]
				if td_tile[x][z].wt2 = TD_MAP
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][2][0]; _glVertex3f float(x) + 1.0, td_wall[x][z][2][0], float(z) + 1.0
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][2][1]; _glVertex3f float(x) + 1.0, td_wall[x][z][2][1], float(z)
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][2][2]; _glVertex3f float(x) + 1.0, td_wall[x][z][2][2], float(z)
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][2][3]; _glVertex3f float(x) + 1.0, td_wall[x][z][2][3], float(z) + 1.0
				else
					_glTexCoord2f 0.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][2][0], float(z) + 1.0
					_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][2][1], float(z)
					_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][2][2], float(z)
					_glTexCoord2f 0.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][2][3], float(z) + 1.0
				endif
			endif
			if td_tile[x][z].w3 = i
				_glColor3f td_color[3][0], td_color[3][1], td_color[3][2]
				if td_tile[x][z].wt3 = TD_MAP
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][3][0]; _glVertex3f float(x), td_wall[x][z][3][0], float(z) + 1.0
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][3][1]; _glVertex3f float(x) + 1.0, td_wall[x][z][3][1], float(z) + 1.0
					_glTexCoord2f 1.0, 1.0 - td_wall[x][z][3][2]; _glVertex3f float(x) + 1.0, td_wall[x][z][3][2], float(z) + 1.0
					_glTexCoord2f 0.0, 1.0 - td_wall[x][z][3][3]; _glVertex3f float(x), td_wall[x][z][3][3], float(z) + 1.0
				else
					_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_wall[x][z][3][0], float(z) + 1.0
					_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][3][1], float(z) + 1.0
					_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][3][2], float(z) + 1.0
					_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_wall[x][z][3][3], float(z) + 1.0
				endif
			endif
			rem Diagonals walls.
			if td_tile[x][z].w4 = i
				if td_tile[x][z].d = 1
					_glColor3f td_color[4][0], td_color[4][1], td_color[4][2]
					if td_tile[x][z].wt4 = TD_MAP
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][0]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][0], float(z)
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][1]; _glVertex3f float(x), td_wall[x][z][4][1], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][2]; _glVertex3f float(x), td_wall[x][z][4][2], float(z) + 1.0
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][3]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][3], float(z)
					else
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][0], float(z)
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x), td_wall[x][z][4][1], float(z) + 1.0
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x), td_wall[x][z][4][2], float(z) + 1.0
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][3], float(z)
					endif
				elseif td_tile[x][z].d = 2
					_glColor3f td_color[5][0], td_color[5][1], td_color[5][2]
					if td_tile[x][z].wt4 = TD_MAP
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][0]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][0], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][1]; _glVertex3f float(x), td_wall[x][z][4][1], float(z)
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][2]; _glVertex3f float(x), td_wall[x][z][4][2], float(z)
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][3]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][3], float(z) + 1.0
					else
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][0], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x), td_wall[x][z][4][1], float(z)
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x), td_wall[x][z][4][2], float(z)
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][3], float(z) + 1.0
					endif
				elseif td_tile[x][z].d = 3
					_glColor3f td_color[6][0], td_color[6][1], td_color[6][2];
					if td_tile[x][z].wt4 = TD_MAP
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][0]; _glVertex3f float(x), td_wall[x][z][4][0], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][1]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][1], float(z)
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][2]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][2], float(z)
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][3]; _glVertex3f float(x), td_wall[x][z][4][3], float(z) + 1.0
					else
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_wall[x][z][4][0], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][1], float(z)
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][2], float(z)
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_wall[x][z][4][3], float(z) + 1.0
					endif
				else
					_glColor3f td_color[7][0], td_color[7][1], td_color[7][2]
					if td_tile[x][z].wt4 = TD_MAP
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][0]; _glVertex3f float(x), td_wall[x][z][4][0], float(z)
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][1]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][1], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0 - td_wall[x][z][4][2]; _glVertex3f float(x) + 1.0, td_wall[x][z][4][2], float(z) + 1.0
						_glTexCoord2f 0.0, 1.0 - td_wall[x][z][4][3]; _glVertex3f float(x), td_wall[x][z][4][3], float(z)
					else
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_wall[x][z][4][0], float(z)
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][1], float(z) + 1.0
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_wall[x][z][4][2], float(z) + 1.0
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_wall[x][z][4][3], float(z)
					endif
				endif
			endif
		next
	next
	_glEnd

	_glBegin GL_TRIANGLES
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			rem Floor.
			if td_tile[x][z].f = i
				_glColor3f td_color[8][0], td_color[8][1], td_color[8][2]
				if td_tile[x][z].ft = 0 or td_tile[x][z].ft = 2 or td_tile[x][z].ft = 3
					if td_tile[x][z].ft <> 3
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_floor[x][z][0], float(z)
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_floor[x][z][3], float(z) + 1.0
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_floor[x][z][1], float(z)
					endif
					if td_tile[x][z].ft <> 2
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_floor[x][z][1], float(z)
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_floor[x][z][3], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_floor[x][z][2], float(z) + 1.0
					endif
				else
					if td_tile[x][z].ft <> 5
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_floor[x][z][0], float(z)
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_floor[x][z][3], float(z) + 1.0
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_floor[x][z][2], float(z) + 1.0
					endif
					if td_tile[x][z].ft <> 4
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_floor[x][z][0], float(z)
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_floor[x][z][2], float(z) + 1.0
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_floor[x][z][1], float(z)
					endif
				endif
			endif
			rem Ceiling.
			if td_tile[x][z].c = i
				_glColor3f td_color[9][0], td_color[9][1], td_color[9][2]
  	    if td_tile[x][z].ct = 0 or td_tile[x][z].ct = 2 or td_tile[x][z].ct = 3
					if td_tile[x][z].ct <> 3
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][1], float(z)
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_ceil[x][z][3], float(z) + 1.0
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_ceil[x][z][0], float(z)
					endif
					if td_tile[x][z].ct <> 2
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][2], float(z) + 1.0
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_ceil[x][z][3], float(z) + 1.0
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][1], float(z)
					endif
				else
					if td_tile[x][z].ct <> 5
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][2], float(z) + 1.0
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), td_ceil[x][z][3], float(z) + 1.0
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_ceil[x][z][0], float(z)
					endif
					if td_tile[x][z].ct <> 4
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][1], float(z)
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, td_ceil[x][z][2], float(z) + 1.0
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), td_ceil[x][z][0], float(z)
					endif
				endif
			endif
		next
	next
	_glEnd
	next
endproc

rem Build map, must be called before rendering.
procedure TD_BuildMap()
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			_TD_CalcWallmapNormals x, z
		next
	next 

	if td_Wallmap then _glDeleteLists td_Wallmap, 1
	td_Wallmap = glGenLists(1)
	_glNewList td_Wallmap, GL_COMPILE
	_glEnable GL_TEXTURE_2D
	_TD_RenderWallmap
	_glEndList
endproc

function get_path$(filename$)
	l = len(filename)
	if l = 0 then return ""
	for i = l - 1 downto 0
		if mid(filename, i) = "/" or mid(filename, i) = "\" then break
	next
	if i > 0
		return left(filename, i + 1)
	else
		return ""
	endif
endfunc

function get_clean_filename$(filename$)
	l = len(filename)
	if l = 0 then return ""
	for i = l - 1 downto 0
		if mid(filename, i) = "/" or mid(filename, i) = "\" then break
	next
	if i > 0
		return right(filename, i + 1)
	else
		return filename
	endif
endfunc

function TD_GetTextureFilename$()
	return td_WMTextureFN[tded_Texture]
endfunc

function TD_GetTextureFilenameByIndex$(index)
	return td_BGTextureFN
endfunc

rem load map from rc editor.
function TD_LoadRCMap(filename$, &plyx#, &plyz#, &plya#, build)
	open file 0, filename$
	if not file(0) then return false
	path$ = get_path(filename)
	numTex = read(0)
	fns$[numTex]
	rem td_WMTextures[td_WMNumTextures]
	for i = 0 to numTex - 1
		rem ... index?
		tmp = read(0); fn$ = path + read$(0)
		fns[i] = fn
		ck = read(0); r = read(0); g = read(0); b = read(0)
	next
	rem objects?..
	count = read(0)
	for i = 0 to count - 1; for j = 0 to 4; tmp = read(0); next; next
	rem fog.
	fogActive = read(0)
	fogR = read(0); fogG = read(0); fogB = read(0)
	fogZMin# = read#(0); fogZMax# = read#(0)
	if fogActive; _TD_SetFog fogR, fogG, fogB, fogZMin, fogZMax
	else; _TD_DisableFog; endif
	rem map.
	w = read(0); h = read(0)
	_TD_InitMap w, h
	td_WMNumTextures = numTex
	for i = 0 to td_WMNumTextures - 1
		td_WMTextureFN[i] = fns[i]
		td_WMTextures[i] = TD_LoadTexture(td_WMTextureFN[i])
	next
	rem walls.
	for z = 0 to h - 1; for x = 0 to w - 1
		wall = read(0)
		if wall > 0
			SUB wall 1
			td_tile[x][z].w0 = wall; td_tile[x][z].w1 = wall; td_tile[x][z].w2 = wall; td_tile[x][z].w3 = wall
			for i = 0 to 3
				td_wall[x][z][i][0] = 0.0
				td_wall[x][z][i][1] = 0.0
				td_wall[x][z][i][2] = 1.0
				td_wall[x][z][i][3] = 1.0
			next
			td_tile[x][z].wt0 = TD_STRETCH
			td_tile[x][z].wt1 = TD_STRETCH
			td_tile[x][z].wt2 = TD_STRETCH
			td_tile[x][z].wt3 = TD_STRETCH
			td_tile[x][z].wt4 = TD_STRETCH
		endif

	next; next
	rem floor.
	for z = 0 to h - 1; for x = 0 to w - 1
		floor = read(0)
		if floor > 0; td_tile[x][z].f = floor - 1; td_tile[x][z].ft = 0; endif
	next; next
	rem ceiling.
	for z = 0 to h - 1; for x = 0 to w - 1
		ceil = read(0)
		if ceil > 0; td_tile[x][z].c = ceil - 1; td_tile[x][z].ct = 0; endif
	next; next
	rem unused here.
	for i = 0 to 2; for z = 0 to h - 1; for x = 0 to w - 1; tmp = read(0); next; next; next
	rem player.
	plyx = float(read(0)) + 0.5; plyz = float(read(0)) + 0.5; plya = float(read(0))
	free file 0
	if build then _TD_BuildMap
	return true
endfunc

procedure TD_CalcWallmapNormals(x, z)
	a#[3]; b#[3]
	if td_tile[x][z].ft = 0 or td_tile[x][z].ft = 2 or td_tile[x][z].ft = 3
		a[0] = 0.0; a[1] = td_floor[x][z][3] - td_floor[x][z][0]; a[2] = 1.0
		b[0] = 1.0; b[1] = td_floor[x][z][1] - td_floor[x][z][0]; b[2] = 0.0
		n#[] = crossvp(a, b); _normv n
		td_floor[x][z][4] = n[0]; td_floor[x][z][5] = n[1]; td_floor[x][z][6] = n[2]

		a[0] = 0.0; a[1] = td_floor[x][z][1] - td_floor[x][z][2]; a[2] = -1.0
		b[0] = -1.0; b[1] = td_floor[x][z][3] - td_floor[x][z][2]; b[2] = 0.0
		n#[] = crossvp(a, b); _normv n
		td_floor[x][z][7] = n[0]; td_floor[x][z][8] = n[1]; td_floor[x][z][9] = n[2]
	else
		a[0] = -1.0; a[1] = td_floor[x][z][0] - td_floor[x][z][1]; a[2] = 0.0
		b[0] = 0.0; b[1] = td_floor[x][z][2] - td_floor[x][z][1]; b[2] = 1.0
		n#[] = crossvp(a, b); _normv n
		td_floor[x][z][4] = n[0]; td_floor[x][z][5] = n[1]; td_floor[x][z][6] = n[2]

		a[0] = 1.0; a[1] = td_floor[x][z][2] - td_floor[x][z][3]; a[2] = 0.0
		b[0] = 0.0; b[1] = td_floor[x][z][0] - td_floor[x][z][3]; b[2] = -1.0
		n#[] = crossvp(a, b); _normv n
		td_floor[x][z][7] = n[0]; td_floor[x][z][8] = n[1]; td_floor[x][z][9] = n[2]
	endif
	if td_tile[x][z].ct = 0 or td_tile[x][z].ct = 2 or td_tile[x][z].ct = 3
		a[0] = 0.0; a[1] = td_ceil[x][z][3] - td_ceil[x][z][0]; a[2] = 1.0
		b[0] = 1.0; b[1] = td_ceil[x][z][1] - td_ceil[x][z][0]; b[2] = 0.0
		n#[] = crossvp(a, b); _normv n
		td_ceil[x][z][4] = n[0]; td_ceil[x][z][5] = n[1]; td_ceil[x][z][6] = n[2]

		a[0] = 0.0; a[1] = td_ceil[x][z][1] - td_ceil[x][z][2]; a[2] = -1.0
		b[0] = -1.0; b[1] = td_ceil[x][z][3] - td_ceil[x][z][2]; b[2] = 0.0
		n#[] = crossvp(a, b); _normv n
		td_ceil[x][z][7] = n[0]; td_ceil[x][z][8] = n[1]; td_ceil[x][z][9] = n[2]
	else
		a[0] = -1.0; a[1] = td_ceil[x][z][0] - td_ceil[x][z][1]; a[2] = 0.0
		b[0] = 0.0; b[1] = td_ceil[x][z][2] - td_ceil[x][z][1]; b[2] = 1.0
		n#[] = crossvp(a, b); _normv n
		td_ceil[x][z][4] = n[0]; td_ceil[x][z][5] = n[1]; td_ceil[x][z][6] = n[2]

		a[0] = 1.0; a[1] = td_ceil[x][z][2] - td_ceil[x][z][3]; a[2] = 0.0
		b[0] = 0.0; b[1] = td_ceil[x][z][0] - td_ceil[x][z][3]; b[2] = -1.0
		n#[] = crossvp(a, b); _normv n
		td_ceil[x][z][7] = n[0]; td_ceil[x][z][8] = n[1]; td_ceil[x][z][9] = n[2] 
	endif

endproc

	rem pos#[] = TD_TryMove(vPlayerX, vPlayerY, vPlayerZ, plyDX, plyDY, plyDZ, 0.3, 1.0, 0.2)

procedure TD_Move(&xp#, &yp#, &zp#, dx#, dy#, dz#, distance#, hgt#, ySkip#)
	xNew#; zNew#; yhm#; yFloor#; yCeiling#; ymin#
	floor; ceiling
	norm#[3]; n#[3]
	dir#[3]
	k#
	ix; iz;

  ceilingHit = 0
  floorHit = 0
  wallHit = 0

	if td_Heightmap
		if TD_GetHeightmapHeight(yhm, xp, zp)			
		endif
	endif
	ymin = yhm

	floor = wmFloorHeight(yFloor, xp, zp)
	ceiling = wmCeilingHeight(yCeiling, xp, zp)
	floorHit = -1;
	if floor
		if (yFloor >= yhm or td_Heightmap = 0) and not (ceiling and yCeiling <= yFloor and yp < yCeiling)
			ymin = yFloor
			floorHit = -2;
    endif
	endif
	yp = yp + dy

	if yp < ymin
		yp = ymin
		if ymin = yhm
			floorHit = 1
			_hmNormal norm, xp, zp
			dir[0] = dx
			dir[1] = 0.0
			dir[2] = dz
			k = dotvp(dir, norm)
			n[0] = norm[0]; n[1] = norm[1]; n[2] = norm[2]
			_mulv n, k
			norm[0] = dir[0]; norm[1] = dir[1]; norm[2] = dir[2]
			_subv norm, n
			if norm[1] > 0.0
				dx = norm[0]
				dz = norm[2]
      endif
		else
			floorHit = 2
		endif
  endif

	if ceiling and yp+hgt > yCeiling and yp < yFloor
		yp = yCeiling-hgt
		ceilingHit = 1
  endif

	wallHit = wmTryMove(xNew, zNew, xp, yp, zp, dx, dz, distance, hgt, ySkip)
	xp = xNew
	zp = zNew
endproc

function wmTryMove(&xAp#, &zAp#, xPos#, yPos#, zPos#, dx#, dz#, distance#, hgt#, ySkip#)
	ix; iz
	distInv# = 1.0 - distance
	xNew#; zNew#
	legalXP; legalXN; legalZP; legalZN
	ret

  rem Om inga frndringar sker ...
  xAp = xPos + dx
  zAp = zPos + dz
  
	if dx = 0.0 and dz = 0.0 then return 0
  
	ix = int(xPos); iz = int(zPos)
  xPos = xPos - float(ix); zPos = zPos - float(iz)
  
  xNew = xPos + dx; zNew = zPos + dz
  
	if ix < td_wmw - 1 then legalXP = 1
	if ix > 0 then legalXN = 1
	if iz < td_wmh - 1 then legalZP = 1
  if iz > 0 then legalZN = 1

  rem hrn
  rem Upperright
	if not (inway(ix + 1, iz, 0, xPos, yPos, zPos, hgt, ySkip) or inway(ix, iz + 1, 1, xPos, yPos, zPos, hgt, ySkip))
		if inway(ix+1, iz+1, 0, xPos, yPos, zPos, hgt, ySkip) or inway(ix+1, iz+1, 1, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix][iz+1].d = 1 and inway(ix, iz+1, 4, xPos, yPos, zPos, hgt, ySkip)) or (td_tile[ix+1][iz].d = 1 and inway(ix+1, iz, 4, xPos, yPos, zPos, hgt, ySkip))
			if dummy(1.0, distInv, -UNIT_2X1, UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
				ret = 5
				xAp = xAp + float(ix)
				zAp = zAp + float(iz)
			endif
		endif
  endif

  rem upperleft
  if not (inway(ix-1, iz, 2, xPos, yPos, zPos, hgt, ySkip) or inway(ix, iz+1, 1, xPos, yPos, zPos, hgt, ySkip))
		if (inway(ix-1, iz+1, 2, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix][iz+1].d = 2 and inway(ix, iz+1, 4, xPos, yPos, zPos, hgt, ySkip))) or (inway(ix-1, iz+1, 1, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix-1][iz].d = 2 and inway(ix-1, iz, 4, xPos, yPos, zPos, hgt, ySkip)))
			if dummy(distance, 1.0, -UNIT_2X1, -UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
				ret = 6
    		xAp = xAp + float(ix)
    		zAp = zAp + float(iz)
			endif
		endif
	endif
  
	rem bottomleft 
  if not (inway(ix-1, iz, 2, xPos, yPos, zPos, hgt, ySkip) or inway(ix, iz-1, 3, xPos, yPos, zPos, hgt, ySkip))
  	if (inway(ix-1, iz-1, 2, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix][iz-1].d = 3 and inway(ix, iz-1, 4, xPos, yPos, zPos, hgt, ySkip))) or (inway(ix-1, iz-1, 3, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix-1][iz].d = 3 and inway(ix-1, iz, 4, xPos, yPos, zPos, hgt, ySkip)))
			if dummy(0.0, distance, UNIT_2X1, -UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
				ret = 7
				xAp = xAp + float(ix)
				zAp = zAp + float(iz)
    	endif
		endif
  endif
  
  rem bottomright
  if not (inway(ix+1, iz, 0, xPos, yPos, zPos, hgt, ySkip) or inway(ix, iz-1, 3, xPos, yPos, zPos, hgt, ySkip))
  	if (inway(ix+1, iz-1, 0, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix][iz-1].d = 4 and inway(ix, iz-1, 4, xPos, yPos, zPos, hgt, ySkip))) or (inway(ix+1, iz-1, 3, xPos, yPos, zPos, hgt, ySkip) or (td_tile[ix+1][iz].d = 4 and inway(ix+1, iz, 4, xPos, yPos, zPos, hgt, ySkip)))
			if dummy(distInv, 0.0, UNIT_2X1, UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
				ret = 8
				xAp = xAp + float(ix)
				zAp = zAp + float(iz)
			endif
		endif
	endif
  
  
  rem Sneda vggar inom tile
	if td_tile[ix][iz].d = 1 and inway(ix, iz, 4, xPos, yPos, zPos, hgt, ySkip)
		if dummy(1.0-distance, 0.0, -UNIT_2X1, UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
			ret = 5
			xAp = xAp + float(ix)
			zAp = zAp + float(iz)
		endif
	endif
	if td_tile[ix][iz].d = 2 and inway(ix, iz, 4, xPos, yPos, zPos, hgt, ySkip)
		if dummy(1.0, 1.0-distance, -UNIT_2X1, -UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
			ret = 6
			xAp = xAp + float(ix)
			zAp = zAp + float(iz)
		endif
	endif
	if td_tile[ix][iz].d = 3 and inway(ix, iz, 4, xPos, yPos, zPos, hgt, ySkip)
		if dummy(distance, 1.0, UNIT_2X1, -UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
			ret = 7
			xAp = xAp + float(ix)
			zAp = zAp + float(iz)
		endif
	endif
	if td_tile[ix][iz].d = 4 and inway(ix, iz, 4, xPos, yPos, zPos, hgt, ySkip)
		if dummy(0.0, distance, UNIT_2X1, UNIT_2X1, xPos, zPos, dx, dz, xAp, zAp)
			ret = 8;
			xAp = xAp + float(ix)
			zAp = zAp + float(iz)
    endif
  endif
  
  rem orto
  if dx > 0.0 and xNew > distInv and inway(ix+1, iz, 0, xPos, yPos, zPos, hgt, ySkip)
		xAp = float(ix)+distInv
		ret = 1
	endif
  
	if dx < 0.0 and xNew < distance and inway(ix-1, iz, 2, xPos, yPos, zPos, hgt, ySkip)
		xAp = float(ix)+distance
		ret = 3
	endif
  
	if dz > 0.0 and zNew > distInv and inway(ix, iz+1, 1, xPos, yPos, zPos, hgt, ySkip)
		zAp = float(iz)+distInv
		ret = 2
	endif
  
	if dz < 0.0 and zNew < distance and inway(ix, iz-1, 3, xPos, yPos, zPos, hgt, ySkip)
		zAp = float(iz)+distance
		ret = 4
	endif
  
	rem ???
	ix = int(xAp)
	iz = int(zAp)

	return ret
endfunc

function wmFloorHeight(&yAp#, x#, z#)
	ix = int(x); iz = int(z)
	if ix < 0 or ix >= td_wmw or iz < 0 or iz >= td_wmh then return 0
	if td_tile[ix][iz].f = -1 then return 0
	x = x - float(ix)
	z = z - float(iz)
	if td_tile[ix][iz].ft = 0 or td_tile[ix][iz].ft = 2 or td_tile[ix][iz].ft = 3
		if x < 1.0-z
			if td_tile[ix][iz].ft = 3 then return 0
			yAp = td_floor[ix][iz][0]-(td_floor[ix][iz][4]*x+td_floor[ix][iz][6]*z)/td_floor[ix][iz][5]
		else
			if td_tile[ix][iz].ft = 2 then return 0
			x = x - 1.0
			z = z - 1.0
			yAp = td_floor[ix][iz][2]-(td_floor[ix][iz][7]*x+td_floor[ix][iz][9]*z)/td_floor[ix][iz][8]
		endif
	else
		if x < z
			if td_tile[ix][iz].ft = 5 then return 0
			z = z - 1.0
			yAp = td_floor[ix][iz][3]-(td_floor[ix][iz][7]*x+td_floor[ix][iz][9]*z)/td_floor[ix][iz][8]
		else
			if td_tile[ix][iz].ft = 4 then return 0
			x = x - 1.0
			yAp = td_floor[ix][iz][1]-(td_floor[ix][iz][4]*x+td_floor[ix][iz][6]*z)/td_floor[ix][iz][5]
		endif
	endif
	return 1
endfunc

function wmCeilingHeight(&yAp#, x#, z#)
  ix = int(x); iz = int(z)
	if ix < 0 or ix >= td_wmw or iz < 0 or iz >= td_wmh then return 0
	if td_tile[ix][iz].c = -1 then return 0
	x = x-float(ix)
	z = z-float(iz)
	if td_tile[ix][iz].ct = 0 or td_tile[ix][iz].ct = 2 or td_tile[ix][iz].ct = 3
		if x < 1.0-z
			if td_tile[ix][iz].ct = 3 then return 0
			yAp = td_ceil[ix][iz][0]-(td_ceil[ix][iz][4]*x+td_ceil[ix][iz][6]*z)/td_ceil[ix][iz][5]
		else
			if td_tile[ix][iz].ct = 2 then return 0
			x = x - 1.0
			z = z - 1.0
			yAp = td_ceil[ix][iz][2]-(td_ceil[ix][iz][7]*x+td_ceil[ix][iz][9])/td_ceil[ix][iz][8]
		endif
	else
		if x < z
			if td_tile[ix][iz].ct = 5 then return 0
			z = z - 1.0
			yAp = td_ceil[ix][iz][3]-(td_ceil[ix][iz][7]*x+td_ceil[ix][iz][9]*z)/td_ceil[ix][iz][8]
		else
			if td_tile[ix][iz].ct = 4 then return 0
			x = x - 1.0
			yAp = td_ceil[ix][iz][1]-(td_ceil[ix][iz][4]*x+td_ceil[ix][iz][6]*z)/td_ceil[ix][iz][5]
		endif
	endif
	return 1
endfunc

function inway(x, z, wall, xPos#, yPos#, zPos#, hgt#, ySkip#)
	yb#; yt#

	rem if x < 0 or x >= td_wmw-2 or z < 0 or z >= td_wmh-2 then return 1
	if x < 0 or x >= td_wmw-1 or z < 0 or z >= td_wmh-1 then return 1

	rem Trivialt.
  rem if(wm->tile[x][z] == NULL)
  rem  return(0);

	if td_tile[x][z].b then return 1

	if wall = 0
		if td_tile[x][z].w0 = -1 then return 0
	elseif wall = 1
		if td_tile[x][z].w1 = -1 then return 0
	elseif wall = 2
		if td_tile[x][z].w2 = -1 then return 0
	elseif wall = 3
		if td_tile[x][z].w3 = -1 then return 0
	else
		if td_tile[x][z].w4 = -1 then return 0
	endif

	if td_wall[x][z][wall][0] < td_wall[x][z][wall][1]
		yb = td_wall[x][z][wall][0]
	else
		yb = td_wall[x][z][wall][1]
	endif
  
	if td_wall[x][z][wall][2] > td_wall[x][z][wall][3]
		yt = td_wall[x][z][wall][2]
	else
		yt = td_wall[x][z][wall][3]
	endif
  
	if yPos < yt-ySkip and yPos+hgt > yb
    return 1
	endif
  
  return 0
endfunc

function dummy(Ax#, Az#, ax#, az#, Bx#, Bz#, bx#, bz#, &x#, &z#)
	t#; dx#; dz#
	if bx*az-bz*ax <= 0.0 then return 0
  t = (az*Bx - az*Ax + ax*Az - ax*Bz)/(ax*bz - az*bx)
 	if t < 1.0
		x = Bx+bx*t; z = Bz+bz*t
		bx = (1.0-t)*bx; bz = (1.0-t)*bz
		dx = (bx*ax+bz*az)*ax; dz = (bx*ax+bz*az)*az
		x = x + dx;z = z + dz 
		return 1    
  else
		return 0
  endif
endfunc

rem init.
function TD_Init(title$, x, y, w, h, fov#, zMin#, zMax#, hide)
	vMeshName = 1
	for i = 0 to MAX_OBJECTS - 1
		vObjects[i].used = false
	next
	res = glInit(title, x, y, w, h, hide)
	if res
		_glSet3D fov, zMin, zMax
		return true
	else
		return false
	endif
endfunc

procedure TD_Update()
	_glUpdate
endproc

function TD_Running()
	return glRunning()
endfunc

rem load mesh, return handle.
function TD_LoadMesh(filename$, smooth, reverse)
	return TD_LoadCGM(filename, smooth, reverse)
endfunc

rem free mesh.
procedure TD_FreeMesh(handle)
	rem ???
	rem cge free mesh handle	
endproc

rem ==================================================================
rem objects.
rem ==================================================================

rem create object, return handle.
function TD_CreateObj(meshHandle)
	for i = 0 to MAX_OBJECTS - 1
		if vObjects[i].used = false then break
	next

	if i < MAX_OBJECTS
		vObjects[i].used = true
		vObjects[i].m = meshHandle
		vObjects[i].x# = 0.0
		vObjects[i].y# = 0.0
		vObjects[i].z# = 0.0
		vObjects[i].sx# = 1.0
		vObjects[i].sy# = 1.0
		vObjects[i].sz# = 1.0
		vObjects[i].pivx# = 0.0
		vObjects[i].pivy# = 0.0
		vObjects[i].pivz# = 0.0
		vObjects[i].yaw# = 0.0
		vObjects[i].pitch# = 0.0
		vObjects[i].roll# = 0.0
		vObjects[i].tex = 0
		vObjects[i].lgt = 0
		vObjects[i].shd = TD_NONE
		return i + 1
	else
		return 0
	endif
endfunc

procedure TD_FreeObject(obj)
	obj = obj - 1
	vObjects[obj].used = false
endproc

rem set position.
procedure TD_SetObjPosition(obj, x#, y#, z#)
	obj = obj - 1
	vObjects[obj].x# = x
	vObjects[obj].y# = y
	vObjects[obj].z# = z
endproc

rem set pivot.
procedure TD_SetObjPivot(obj, x#, y#, z#)
	obj = obj - 1
	vObjects[obj].pivx# = x
	vObjects[obj].pivy# = y
	vObjects[obj].pivz# = z
endproc

rem set orientation.
procedure TD_SetObjOrientation(obj, yaw#, pitch#, roll#)
	obj = obj - 1
	vObjects[obj].yaw# = yaw
	vObjects[obj].pitch# = pitch
	vObjects[obj].roll# = roll
endproc

rem set scale.
procedure TD_SetObjScale(obj, x#, y#, z#)
	obj = obj - 1
	vObjects[obj].sx# = x; vObjects[obj].sy# = y; vObjects[obj].sz# = z
endproc

rem set texture.
procedure TD_SetObjTexture(obj, tex)
	obj = obj - 1; vObjects[obj].tex = tex
endproc

procedure TD_SetObjShader(obj, type)
	obj = obj - 1; vObjects[obj].shd = type
endproc

rem set light.
procedure TD_SetObjLightmap(obj, lgt)
	obj = obj - 1; vObjects[obj].lgt = lgt
endproc

rem ==================================================================
rem camera.
rem ==================================================================

rem set position.
procedure TD_SetCamPosition(x#, y#, z#)
	vCamX = x; vCamY = y; vCamZ = z
endproc

rem set orientation.
procedure TD_SetCamOrientation(yaw#, pitch#, roll#)
	vCamYaw = yaw; vCamPitch = pitch; vCamRoll = roll
endproc

rem ==================================================================
rem light.
rem ==================================================================

rem set direction.
procedure TD_SetLightDirection(dx#, dy#, dz#)
	vLightDX = dx; vLightDY = dy; vLightDZ = dz
endproc

rem ==================================================================
rem other.
rem ==================================================================

procedure TD_Render()
	_glClear GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT
	_glLoadIdentity
	_glRotatef vCamRoll, 0.0, 0.0, 1.0
	_glRotatef vCamPitch, 1.0, 0.0, 0.0
	_glRotatef vCamYaw + 90.0, 0.0, 1.0, 0.0

	if td_BG
		_glDepthMask false
		_glBindTexture GL_TEXTURE_2D, td_BGTexture
		_glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
		_glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
		_glPushMatrix
			_glRotatef 180.0, 1.0, 0.0, 0.0
			_glCallList td_BGSphere
		_glPopMatrix
		_glDepthMask true
	endif

	_glTranslatef -vCamX, -vCamY, -vCamZ
	_glEnable GL_TEXTURE_2D

	if td_Heightmap
		_glCallList td_Heightmap
	endif
	if td_Wallmap
		_glCallList td_Wallmap
	endif

	for i = 0 to MAX_OBJECTS - 1
		if vObjects[i].used
			_glPushMatrix
			_glTranslatef vObjects[i].x#, vObjects[i].y#, vObjects[i].z#
			_glRotatef vObjects[i].yaw#, 0.0, 1.0, 0.0
			_glRotatef vObjects[i].pitch#, 1.0, 0.0, 0.0
			_glRotatef vObjects[i].roll#, 0.0, 0.0, 1.0
			_glTranslatef -vObjects[i].pivx#, -vObjects[i].pivy#, -vObjects[i].pivz#
			_glScalef vObjects[i].sx#, vObjects[i].sy#, vObjects[i].sz#
			if vObjects[i].tex
				_glBindTexture GL_TEXTURE_2D, vObjects[i].tex
				_glCallList vObjects[i].m
			else
				_glDisable GL_TEXTURE_2D
				_glCallList vObjects[i].m
				_glEnable GL_TEXTURE_2D
			endif
			_glPopMatrix
		endif
	next

	if tded_Visible
		_TD_DrawEditor
	endif

	_glRender
endproc

procedure TD_SetBGColor(r, g, b)
	_glClearColor float(r)/255.0, float(g)/255.0, float(b)/255.0, 1.0
endproc

procedure TD_SetFog(r, g, b, zMin#, zMax#)
	_glEnable GL_FOG
	_glFogi GL_FOG_MODE, GL_LINEAR
	_glFogf GL_FOG_START, zMin
	_glFogf GL_FOG_END, zMax
	_glFogfv GL_FOG_COLOR, [float(r)/255.0, float(g)/255.0, float(b)/255.0, 1.0]
endproc

procedure TD_DisableFog()
	_glDisable GL_FOG
endproc

procedure TD_EnableFog()
	_glEnable GL_FOG
endproc

function TD_EditorLoadTexture(filename$)
	tex = TD_LoadTexture(filename)
	if tex
		if td_WMTextures[tded_Texture] > 0 then _glDeleteTexture td_WMTextures[tded_Texture]
		td_WMTextures[tded_Texture] = tex
		td_WMTextureFN[tded_Texture] = filename
		return true
	else
		return false
	endif
endfunc

function TD_LoadTexture(filename$)
	load image -1087, filename
	if image(-1087)
		tex = glCreateTexture(-1087, true)
		free image -1087
		return tex
	else
		return 0
	endif
endfunc

function TD_LoadBackground(filename$)
	td_BG = false
	td_BGTexture = TD_LoadTexture(filename)
	td_BGTextureFN = filename
	if td_BGTexture
		td_BG = true
		if td_BGSphere = 0
			td_BGSphere = TD_LoadCGM("assets/sphere.cgm", true, true)
			if td_BGSphere = 0
				td_BG = false
			endif
		endif
	endif
	return td_BG
endfunc

procedure TD_EnableBackground()
	td_BG = true
endproc

procedure TD_DisableBackground()
	td_BG = false
endproc

rem ==================================================================
rem Load CGM model.
rem ==================================================================
function TD_LoadCGM(filename$, smooth, reverse)
	open file 0, filename$, true
	if not file(0) then return 0
	head[256]
	i
	do
		byte = read8(0)
		head[i] = byte
		i = i + 1
		if i = 3 and not (head[0] = asc("C") and head[1] = asc("G") and head[2] = asc("M"))
			free file 0
			return 0
		endif	
	until byte = 0

	i = 3
	nFlag = false
	NFlag = false
	cFlag = false
	CFlag = false
	tFlag = false
	TFlag = false
	iFlag = false
	while head[i] <> 0
		if head[i] = asc("n")
			nFlag = true
		elseif head[i] = asc("N")
			NFlag = true
		elseif head[i] = asc("c")
			cFlag = true
		elseif head[i] = asc("C")
			CFlag = true
		elseif head[i] = asc("t")
			tFlag = true
		elseif head[i] = asc("T")
			TFlag = true
		elseif head[i] = asc("i")
			iFlag = true
		endif
		i = i + 1
	wend

	vertexCount = read32(0)
	triangleCount = read32(0)
	textureCount = read32(0)
	vertices?[vertexCount]
	triangles?[triangleCount]
	textures[textureCount]

	for i = 0 to vertexCount - 1
		vertices[i].x# = readf(0)
		vertices[i].y# = readf(0)
		vertices[i].z# = readf(0)
		if nFlag
			vertices[i].nx# = readf(0)
			vertices[i].ny# = readf(0)
			vertices[i].nz# = readf(0)
		endif
		if cFlag
			vertices[i].r# = readf(0)
			vertices[i].g# = readf(0)
			vertices[i].b# = readf(0)
		endif
		if iFlag
			vertices[i].i# = readf(0)
		endif
		if tFlag
			vertices[i].u# = readf(0)
			vertices[i].v# = readf(0)
		endif
	next

	for i = 0 to triangleCount - 1
		if reverse
			triangles[i].v2 = read32(0)
			triangles[i].v1 = read32(0)
			triangles[i].v0 = read32(0)
		else
			triangles[i].v0 = read32(0)
			triangles[i].v1 = read32(0)
			triangles[i].v2 = read32(0)
		endif
		if NFlag
			triangles[i].nx# = readf(0)
			triangles[i].ny# = readf(0)
			triangles[i].nz# = readf(0)
		endif
		if CFlag
			triangles[i].r# = readf(0)
			triangles[i].g# = readf(0)
			triangles[i].b# = readf(0)
		endif
		if TFlag
			rem texture index, starting at 1?..
			triangles[i].t = read32(0)
			if reverse
				triangles[i].v2u# = readf(0)
				triangles[i].v2v# = readf(0)
				triangles[i].v1u# = readf(0)
				triangles[i].v1v# = readf(0)
				triangles[i].v0u# = readf(0)
				triangles[i].v0v# = readf(0)
			else
				triangles[i].v0u# = readf(0)
				triangles[i].v0v# = readf(0)
				triangles[i].v1u# = readf(0)
				triangles[i].v1v# = readf(0)
				triangles[i].v2u# = readf(0)
				triangles[i].v2v# = readf(0)
			endif
		else
			triangles[i].t = -1
		endif
	next

	rem Load textures.
	for i = 0 to textureCount - 1
		w = read32(0)
		h = read32(0)
		texels[w*h]
		create image -1087, w, h
		set image -1087
		for j = 0 to w*h - 1
			red = read8(0)
			green = read8(0)
			blue = read8(0)
			set color red, green, blue
			set pixel j%w, j/w
		next
		set image primary
		textures[i] = glCreateTexture(-1087, true)
		free image -1087
	next

	free file 0

	rem Triangle normals.
	if not NFlag
		for i = 0 to triangleCount - 1
			v0 = triangles[i].v0
			v1 = triangles[i].v1
			v2 = triangles[i].v2
			a#[] = [vertices[v1].x# - vertices[v0].x#, vertices[v1].y# - vertices[v0].y#, vertices[v1].z# - vertices[v0].z#]
			b#[] = [vertices[v2].x# - vertices[v0].x#, vertices[v2].y# - vertices[v0].y#, vertices[v2].z# - vertices[v0].z#]
			n#[] = crossvp(a, b)
			_normv n
			triangles[i].nx# = n[0]
			triangles[i].ny# = n[1]
			triangles[i].nz# = n[2]
		next
	endif

	rem Vertex normals.
	if not nFlag
		for i = 0 to vertexCount - 1
			n#[] = [0.0, 0.0, 0.0]
			rem Look for triangles that include this vertex.
			for j = 0 to triangleCount - 1
				if triangles[j].v0 = i or triangles[j].v1 = i or triangles[j].v2 = i
					n[0] = n[0] + triangles[j].nx#
					n[1] = n[1] + triangles[j].ny#
					n[2] = n[2] + triangles[j].nz#
				endif
			next
			_normv n
			vertices[i].nx# = n[0]
			vertices[i].ny# = n[1]
			vertices[i].nz# = n[2]
		next
	endif

	rem Generate mesh.
	m = glGenLists(1)
	wln m
	_glNewList m, GL_COMPILE
			for t = -1 to textureCount - 1
				if t = -1 and textureCount > 0
					_glDisable(GL_TEXTURE_2D)
				elseif t >= 0
					_glBindTexture GL_TEXTURE_2D, textures[t]
				endif
				_glBegin GL_TRIANGLES
				for i = 0 to triangleCount - 1
					if triangles[i].t = t
						if CFlag and t = -1 then _glColor3f triangles[i].r#, triangles[i].g#, triangles[i].b#
						v0 = triangles[i].v0
						v1 = triangles[i].v1
						v2 = triangles[i].v2
						if smooth
							_glNormal3f vertices[v0].nx#, vertices[v0].ny#, vertices[v0].nz#
						else
						 	_glNormal3f triangles[i].nx#, triangles[i].ny#, triangles[i].nz#
						endif
						if TFlag
							_glTexCoord2f triangles[i].v0u#, triangles[i].v0v#
						elseif tFlag
							_glTexCoord2f vertices[v0].u#, vertices[v0].v#
						endif
						if cFlag then _glColor3f vertices[v0].r#, vertices[v0].g#, vertices[v0].b#
						_glVertex3f vertices[v0].x#, vertices[v0].y#, vertices[v0].z#
	
						if smooth then _glNormal3f vertices[v1].nx#, vertices[v1].ny#, vertices[v1].nz#
						if TFlag
							_glTexCoord2f triangles[i].v1u#, triangles[i].v1v#
						elseif tFlag
							_glTexCoord2f vertices[v1].u#, vertices[v1].v#
						endif
						if cFlag then _glColor3f vertices[v1].r#, vertices[v1].g#, vertices[v1].b#
						_glVertex3f vertices[v1].x#, vertices[v1].y#, vertices[v1].z#

						if smooth then _glNormal3f vertices[v2].nx#, vertices[v2].ny#, vertices[v2].nz#
						if TFlag
							_glTexCoord2f triangles[i].v2u#, triangles[i].v2v#
						elseif tFlag
							_glTexCoord2f vertices[v2].u#, vertices[v2].v#
						endif
						if cFlag then _glColor3f vertices[v2].r#, vertices[v2].g#, vertices[v2].b#
						_glVertex3f vertices[v2].x#, vertices[v2].y#, vertices[v2].z#
					endif
				next
				_glEnd
				if t = -1 and textureCount > 0
					_glEnable(GL_TEXTURE_2D)
				endif
			next
	_glEndList
	
	return m
endfunc

function TD_LoadHeightmap(filename$, heightdiff#)
	smooth = true
	if smooth = true; flat = false
	else; flat = true; endif
	load image -1087, filename
	if not image(-1087) then return false


	hm_Diff = heightdiff

	hm_Filename = filename
	rem Generate heightmap from image.
	hm_SizeZ = min(height(-1087), td_wmw)
	hm_SizeX = min(width(-1087), td_wmh)
	hm_Map[hm_SizeX][hm_SizeZ]
	rem Read heights.
	set image -1087
	for z = 0 to hm_SizeZ - 1
		for x = 0 to hm_SizeX - 1
			hm_Map[x][z].h# = heightdiff*float(pixeli(x, z) AND 0xff)/255.0
			hm_Map[x][z].t = 0
		next
	next
	set image primary
	free image -1087

rem	load image -1087, tex_filename
rem	if image(-1087)
rem		td_HeightmapTexture = glCreateTexture(-1087, true)
rem		free image(-1087)
rem	endif

	rem Calculate distant light vector.
	lightx# = 1.0; lightz# = 1.0; lighty# = 2.0
	k# = 1.0/sqr(lightx*lightx + lightz*lightz + lighty*lighty)
	lightx = lightx*k; lightz = lightz*k; lighty = lighty*k

	rem Calculate two normals and one light (for flat shading) per tile.
	for z = 0 to hm_SizeZ - 2
		for x = 0 to hm_SizeX - 2
			a#[] = [0.0, hm_Map[x][z + 1].h# - hm_Map[x][z].h#, 1.0]
			b#[] = [1.0, hm_Map[x + 1][z + 1].h# - hm_Map[x][z].h#, 1.0]
			c#[] = [1.0, hm_Map[x + 1][z].h# - hm_Map[x][z].h#, 0.0]	
			n#[] = crossvp(a, b); _normv n
			hm_Map[x][z].nLx# = n[0]; hm_Map[x][z].nLy# = n[1]; hm_Map[x][z].nLz# = n[2]
			il# = max#(0.0, n[0]*lightx + n[1]*lighty + n[2]*lightz)
			n#[] = crossvp(b, c); _normv n
			hm_Map[x][z].nRx# = n[0]; hm_Map[x][z].nRy# = n[1]; hm_Map[x][z].nRz# = n[2]
			ir# = max#(0.0, n[0]*lightx + n[1]*lighty + n[2]*lightz)
			hm_Map[x][z].iF# = (il + ir)*0.5
		next
	next

	rem Calculate light for smooth shading.
	for z = 0 to hm_SizeZ - 1
		for x = 0 to hm_SizeX - 1
			n#[3]
			if x > 0 and z > 0
				n[0] = n[0] + hm_Map[x - 1][z - 1].nLx# + hm_Map[x - 1][z - 1].nRx#
				n[1] = n[1] + hm_Map[x - 1][z - 1].nLy# + hm_Map[x - 1][z - 1].nRy#
				n[2] = n[2] + hm_Map[x - 1][z - 1].nLz# + hm_Map[x - 1][z - 1].nRz#
			endif
			if x > 0 and z < hm_SizeZ - 1
				n[0] = n[0] + hm_Map[x - 1][z].nLx# + hm_Map[x - 1][z].nRx#
				n[1] = n[1] + hm_Map[x - 1][z].nLy# + hm_Map[x - 1][z].nRy#
				n[2] = n[2] + hm_Map[x - 1][z].nLz# + hm_Map[x - 1][z].nRz#
			endif
			if z < hm_SizeZ - 1 and x < hm_SizeX - 1	
				n[0] = n[0] + hm_Map[x][z].nLx# + hm_Map[x][z].nRx#
				n[1] = n[1] + hm_Map[x][z].nLy# + hm_Map[x][z].nRy#
				n[2] = n[2] + hm_Map[x][z].nLz# + hm_Map[x][z].nRz#
			endif
			if z > 0 and x < hm_SizeX - 1
				n[0] = n[0] + hm_Map[x][z - 1].nLx# + hm_Map[x][z - 1].nRx#
				n[1] = n[1] + hm_Map[x][z - 1].nLy# + hm_Map[x][z - 1].nRy#
				n[2] = n[2] + hm_Map[x][z - 1].nLz# + hm_Map[x][z - 1].nRz#
			endif
			_normv n
			hm_Map[x][z].i# = max#(0.0, n[0]*lightx + n[1]*lighty + n[2]*lightz)
		next
	next

	rem Build display list.
	_TD_BuildHM
	return true
endfunc

procedure TD_BuildHM()
	flat = false
	if td_Heightmap then _glDeleteLists td_Heightmap, 1
	td_Heightmap = glGenLists(1)
	_glNewList td_Heightmap, GL_COMPILE
	_glEnable GL_TEXTURE_2D
	for t = 0 to TD_MAX_TEXTURES - 1
		rem Check if texture is used.
		used = false
		for z = 0 to hm_SizeZ - 2; for x = 0 to hm_SizeX - 2
			if hm_Map[x][z].t = t
				used = true
				break
			endif	
		next; next
		if used
			_glBindTexture GL_TEXTURE_2D, td_WMTextures[t]
			_glBegin GL_TRIANGLES	
			for z = 0 to hm_SizeZ - 2
				for x = 0 to hm_SizeX - 2
					if hm_Map[x][z].t = t
						if flat then _glColor3f hm_Map[x][z].iF#, hm_Map[x][z].iF#, hm_Map[x][z].iF#

						if not flat then _glColor3f hm_Map[x][z].i#, hm_Map[x][z].i#, hm_Map[x][z].i#
						_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), hm_Map[x][z].h#, float(z)
						if not flat then _glColor3f hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), hm_Map[x][z + 1].h#, float(z) + 1.0
						if not flat then _glColor3f hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, hm_Map[x + 1][z].h#, float(z)

						if not flat then _glColor3f hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#
						_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), hm_Map[x][z + 1].h#, float(z) + 1.0
						if not flat then _glColor3f hm_Map[x + 1][z + 1].i#, hm_Map[x + 1][z + 1].i#, hm_Map[x + 1][z + 1].i#
						_glTexCoord2f 1.0, 1.0; _glVertex3f float(x) + 1.0, hm_Map[x + 1][z + 1].h#, float(z) + 1.0
						if not flat then _glColor3f hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#
						_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, hm_Map[x + 1][z].h#, float(z)
					endif	
				next
			next
			_glEnd
		endif
	next
	_glEndList

endproc

procedure TD_BuildHMOld()
	flat = true
	if td_Heightmap then _glDeleteLists td_Heightmap, 1
	td_Heightmap = glGenLists(1)
	_glNewList td_Heightmap, GL_COMPILE
	rem for t = 0 to MAX_TEXTURES - 1
		for z = 0 to hm_SizeZ - 2
			_glBegin GL_TRIANGLE_STRIP
				x = 0
				if flat; _glColor3f hm_Map[x][z].iF#, hm_Map[x][z].iF#, hm_Map[x][z].iF#
				else; _glColor3f hm_Map[x][z].i#, hm_Map[x][z].i#, hm_Map[x][z].i#; endif
				_glTexCoord2f 0.0, 0.0; _glVertex3f float(x), hm_Map[x][z].h#, float(z)
				if not flat then _glColor3f hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#
				_glTexCoord2f 0.0, 1.0; _glVertex3f float(x), hm_Map[x][z + 1].h#, float(z) + 1.0
				if not flat then _glColor3f hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#
				_glTexCoord2f 1.0, 0.0; _glVertex3f float(x) + 1.0, hm_Map[x + 1][z].h#, float(z)
				for x = 1 to hm_SizeX - 2
					if flat;_glColor3f hm_Map[x - 1][z].iF#, hm_Map[x - 1][z].iF#, hm_Map[x - 1][z].iF#
					else; _glColor3f hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#; endif
					_glTexCoord2f float(x), 1.0; _glVertex3f float(x), hm_Map[x][z + 1].h#, float(z) + 1.0
					if flat then; _glColor3f hm_Map[x][z].iF#, hm_Map[x][z].iF#, hm_Map[x][z].iF#
					else; _glColor3f hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#, hm_Map[x + 1][z].i#; endif
					_glTexCoord2f float(x + 1), 0.0; _glVertex3f float(x) + 1.0, hm_Map[x + 1][z].h#, float(z)
				next
				if flat; _glColor3f hm_Map[x - 1][z].iF#, hm_Map[x - 1][z].iF#, hm_Map[x - 1][z].iF#
				else; _glColor3f hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#, hm_Map[x][z + 1].i#; endif
				_glTexCoord2f float(x), 1.0; _glVertex3f float(x), hm_Map[x][z + 1].h#, float(z) + 1.0
			_glEnd
		next
	remnext
	_glEndList
endproc

rem Get height
function TD_GetHeightmapHeight(&y#, x#, z#)
	if x < 0.0 or z < 0.0 then return false
	ix = int(x); iz = int(z)
	if ix >= hm_SizeX - 1 or iz >= hm_SizeZ - 1 then return false
	x = x - float(ix); z = z - float(iz)
	if x < z
		y# = hm_Map[ix][iz].h# - (hm_Map[ix][iz].nLx#*x + hm_Map[ix][iz].nLz#*z)/hm_Map[ix][iz].nLy#
	else
		x = x - 1.0; z = z - 1.0
		y# = hm_Map[ix + 1][iz + 1].h# - (hm_Map[ix][iz].nRx#*x + hm_Map[ix][iz].nRz#*z)/hm_Map[ix][iz].nRy#
	endif
	return true
endfunc

procedure hmNormal(&norm#[], x#, z#)
	ix = int(x); iz = int(z); index
	if ix < 0 or ix >= hm_SizeX - 1 or iz < 0 or iz >= hm_SizeZ - 1
		norm[0] = 0.0; norm[1] = 1.0;norm[2] = 0.0
		return
	endif
	x = x-float(ix); z = z-float(iz)
	if x < 1.0-z
		norm[0] = hm_Map[ix][iz].nLx#; norm[1] = hm_Map[ix][iz].nLy#; norm[2] = hm_Map[ix][iz].nLz#
	else
		norm[0] = hm_Map[ix][iz].nRx#; norm[1] = hm_Map[ix][iz].nRy#; norm[2] = hm_Map[ix][iz].nRz#
	endif
endproc

function TD_GetWidth()
	return glWidth()
endfunc

function TD_GetHeight()
	return glHeight()
endfunc

procedure TD_PullCeiling(offs#)
	x = tded_XTile
	z = tded_ZTile
	for i = 0 to 3
		 td_ceil[x][z][i] = td_ceil[x][z][i] + offs
	next
	for i = 0 to 3
		td_wall[x][z][i][2] = td_wall[x][z][i][2] + offs
		td_wall[x][z][i][3] = td_wall[x][z][i][3] + offs
	next
	td_wall[x - 1][z][2][2] = td_wall[x - 1][z][2][2] + offs
	td_wall[x - 1][z][2][3] = td_wall[x - 1][z][2][3] + offs
	td_wall[x - 1][z][1][3] = td_wall[x - 1][z][1][3] + offs
	td_wall[x - 1][z][3][2] = td_wall[x - 1][z][3][2] + offs
	td_wall[x + 1][z][0][2] = td_wall[x + 1][z][0][2] + offs
	td_wall[x + 1][z][0][3] = td_wall[x + 1][z][0][3] + offs
	td_wall[x + 1][z][1][2] = td_wall[x + 1][z][1][2] + offs
	td_wall[x + 1][z][3][3] = td_wall[x + 1][z][3][3] + offs
	td_wall[x][z - 1][3][2] = td_wall[x][z - 1][3][2] + offs
	td_wall[x][z - 1][3][3] = td_wall[x][z - 1][3][3] + offs
	td_wall[x][z - 1][2][3] = td_wall[x][z - 1][2][3] + offs
	td_wall[x][z - 1][0][2] = td_wall[x][z - 1][0][2] + offs
	td_wall[x][z + 1][1][2] = td_wall[x][z + 1][1][2] + offs
	td_wall[x][z + 1][1][3] = td_wall[x][z + 1][1][3] + offs
	td_wall[x][z + 1][2][2] = td_wall[x][z + 1][2][2] + offs
	td_wall[x][z + 1][0][3] = td_wall[x][z + 1][0][3] + offs
	td_wall[x - 1][z - 1][2][3] = td_wall[x - 1][z - 1][2][3] + offs
	td_wall[x - 1][z - 1][3][2] = td_wall[x - 1][z - 1][3][2] + offs
	td_wall[x - 1][z + 1][1][3] = td_wall[x - 1][z + 1][1][3] + offs
	td_wall[x - 1][z + 1][2][2] = td_wall[x - 1][z + 1][2][2] + offs
	td_wall[x + 1][z - 1][0][2] = td_wall[x + 1][z - 1][0][2] + offs
	td_wall[x + 1][z - 1][3][3] = td_wall[x + 1][z - 1][3][3] + offs
	td_wall[x + 1][z + 1][1][2] = td_wall[x + 1][z + 1][1][2] + offs
	td_wall[x + 1][z + 1][0][3] = td_wall[x + 1][z + 1][0][3] + offs

	td_ceil[x + 1][z][3] = td_ceil[x + 1][z][3] + offs
	td_ceil[x + 1][z][0] = td_ceil[x + 1][z][0] + offs
	td_ceil[x - 1][z][1] = td_ceil[x - 1][z][1] + offs
	td_ceil[x - 1][z][2] = td_ceil[x - 1][z][2] + offs
	td_ceil[x][z + 1][0] = td_ceil[x][z + 1][0] + offs
	td_ceil[x][z + 1][1] = td_ceil[x][z + 1][1] + offs
	td_ceil[x][z - 1][2] = td_ceil[x][z - 1][2] + offs
	td_ceil[x][z - 1][3] = td_ceil[x][z - 1][3] + offs
	td_ceil[x + 1][z + 1][0] = td_ceil[x + 1][z + 1][0] + offs
	td_ceil[x + 1][z - 1][3] = td_ceil[x + 1][z - 1][3] + offs
	td_ceil[x - 1][z + 1][1] = td_ceil[x - 1][z + 1][1] + offs
	td_ceil[x - 1][z - 1][2] = td_ceil[x - 1][z - 1][2] + offs
	_TD_BuildMap
endproc

procedure TD_PullFloor(offs#)
	x = tded_XTile
	z = tded_ZTile
	for i = 0 to 3
		td_floor[x][z][i] = td_floor[x][z][i] + offs
	next
	for i = 0 to 3
		td_wall[x][z][i][1] = td_wall[x][z][i][1] + offs
		td_wall[x][z][i][0] = td_wall[x][z][i][0] + offs
	next
	td_wall[x - 1][z][2][1] = td_wall[x - 1][z][2][1] + offs
	td_wall[x - 1][z][2][0] = td_wall[x - 1][z][2][0] + offs
	td_wall[x - 1][z][1][0] = td_wall[x - 1][z][1][0] + offs
	td_wall[x - 1][z][3][1] = td_wall[x - 1][z][3][1] + offs
	td_wall[x + 1][z][0][1] = td_wall[x + 1][z][0][1] + offs
	td_wall[x + 1][z][0][0] = td_wall[x + 1][z][0][0] + offs
	td_wall[x + 1][z][1][1] = td_wall[x + 1][z][1][1] + offs
	td_wall[x + 1][z][3][0] = td_wall[x + 1][z][3][0] + offs
	td_wall[x][z - 1][3][1] = td_wall[x][z - 1][3][1] + offs
	td_wall[x][z - 1][3][0] = td_wall[x][z - 1][3][0] + offs
	td_wall[x][z - 1][2][0] = td_wall[x][z - 1][2][0] + offs
	td_wall[x][z - 1][0][1] = td_wall[x][z - 1][0][1] + offs
	td_wall[x][z + 1][1][1] = td_wall[x][z + 1][1][1] + offs
	td_wall[x][z + 1][1][0] = td_wall[x][z + 1][1][0] + offs
	td_wall[x][z + 1][2][1] = td_wall[x][z + 1][2][1] + offs
	td_wall[x][z + 1][0][0] = td_wall[x][z + 1][0][0] + offs
	td_wall[x - 1][z - 1][2][0] = td_wall[x - 1][z - 1][2][0] + offs
	td_wall[x - 1][z - 1][3][1] = td_wall[x - 1][z - 1][3][1] + offs
	td_wall[x - 1][z + 1][1][0] = td_wall[x - 1][z + 1][1][0] + offs
	td_wall[x - 1][z + 1][2][1] = td_wall[x - 1][z + 1][2][1] + offs
	td_wall[x + 1][z - 1][0][1] = td_wall[x + 1][z - 1][0][1] + offs
	td_wall[x + 1][z - 1][3][0] = td_wall[x + 1][z - 1][3][0] + offs
	td_wall[x + 1][z + 1][1][1] = td_wall[x + 1][z + 1][1][1] + offs
	td_wall[x + 1][z + 1][0][0] = td_wall[x + 1][z + 1][0][0] + offs

	td_floor[x + 1][z][3] = td_floor[x + 1][z][3] + offs
	td_floor[x + 1][z][0] = td_floor[x + 1][z][0] + offs
	td_floor[x - 1][z][1] = td_floor[x - 1][z][1] + offs
	td_floor[x - 1][z][2] = td_floor[x - 1][z][2] + offs
	td_floor[x][z + 1][0] = td_floor[x][z + 1][0] + offs
	td_floor[x][z + 1][1] = td_floor[x][z + 1][1] + offs
	td_floor[x][z - 1][2] = td_floor[x][z - 1][2] + offs
	td_floor[x][z - 1][3] = td_floor[x][z - 1][3] + offs
	td_floor[x + 1][z + 1][0] = td_floor[x + 1][z + 1][0] + offs
	td_floor[x + 1][z - 1][3] = td_floor[x + 1][z - 1][3] + offs
	td_floor[x - 1][z + 1][1] = td_floor[x - 1][z + 1][1] + offs
	td_floor[x - 1][z - 1][2] = td_floor[x - 1][z - 1][2] + offs
	_TD_BuildMap
endproc

procedure TD_SetWallColor(i, r, g, b)
	td_color[i][0] = float(r)/255.0; td_color[i][1] = float(g)/255.0; td_color[i][2] = float(b)/255.0
endproc

procedure TD_UpdateEditor()
	angle# = vCamYaw
	while angle < 0.0; ADD# angle 360.0; wend
	while angle >= 360.0; SUB# angle 360.0; wend
	y = int(vCamY*10.0); tded_Y = 0.1*float(y) - 0.5
  if angle > 337.0 or angle <= 22.0
		tded_XTile = 2 + int(vCamX); tded_ZTile = int(vCamZ)
		tded_Wall = 0; tded_Diagonal = 0
	endif
  if angle > 22.0 and angle <= 67.0
		tded_XTile = 1 + int(vCamX); tded_ZTile = 1 + int(vCamZ)
		tded_Wall = 4; tded_Diagonal = 1
	endif
	if angle > 67.0 and angle <= 112.0
		tded_XTile = int(vCamX); tded_ZTile = 2 + int(vCamZ)
		tded_Wall = 1; tded_Diagonal = 0
	endif
	if angle > 112.0 and angle <= 157.0
		tded_XTile = -1 + int(vCamX); tded_ZTile = 1 + int(vCamZ)    
		tded_Wall = 4; tded_Diagonal = 2
	endif
	if angle > 157.0 and angle <= 202.0
		tded_XTile = -2 + int(vCamX); tded_ZTile = int(vCamZ)
		tded_Wall = 2; tded_Diagonal = 0
  endif
	if(angle > 202.0 and angle <= 247.0)
		tded_XTile = -1 + int(vCamX); tded_ZTile = -1 + int(vCamZ)
		tded_Wall = 4; tded_Diagonal = 3
  endif
	if angle > 247.0 and angle <= 292.0
		tded_XTile = int(vCamX); tded_ZTile = -2 + int(vCamZ)
		tded_Wall = 3; tded_Diagonal = 0
	endif
	if angle > 292.0 and angle <= 337.0
		tded_XTile = 1 + int(vCamX); tded_ZTile = -1 + int(vCamZ)
		tded_Wall = 4;tded_Diagonal = 4
  endif
	if tded_XTile < 0 then tded_XTile = 0
	if tded_XTile >= td_wmw - 1 then tded_XTile = td_wmw - 1
	if tded_ZTile < 0 then tded_ZTile = 0
	if tded_ZTile >= td_wmh - 1 then tded_ZTile = td_wmh - 1
endfunc

procedure TD_SetEditorVisible(value)
	tded_Visible = value
endproc

procedure TD_SetEditorWireframe(value)
	tded_Wireframe = value
endproc

procedure TD_SetEditorCornerMode(value)
	tded_Corner = value
endproc

procedure TD_SetEditorWrapMode(value)
	tded_TextureWrapMode = value
endproc

procedure TD_SetEditorSplitMode(value)
	tded_SplitMode = value
endproc

procedure TD_AddWall()
	ct
	if tded_Wall = 0
		ct = td_tile[tded_XTile][tded_ZTile].w0; td_tile[tded_XTile][tded_ZTile].w0 = tded_Texture; td_tile[tded_XTile][tded_ZTile].wt0 = tded_TextureWrapMode
	elseif tded_Wall = 1
		ct = td_tile[tded_XTile][tded_ZTile].w1; td_tile[tded_XTile][tded_ZTile].w1 = tded_Texture; td_tile[tded_XTile][tded_ZTile].wt1 = tded_TextureWrapMode
	elseif tded_Wall = 2
		ct = td_tile[tded_XTile][tded_ZTile].w2; td_tile[tded_XTile][tded_ZTile].w2 = tded_Texture; td_tile[tded_XTile][tded_ZTile].wt2 = tded_TextureWrapMode
	elseif tded_Wall = 3
		ct = td_tile[tded_XTile][tded_ZTile].w3; td_tile[tded_XTile][tded_ZTile].w3 = tded_Texture; td_tile[tded_XTile][tded_ZTile].wt3 = tded_TextureWrapMode
	else
		ct = td_tile[tded_XTile][tded_ZTile].w4; td_tile[tded_XTile][tded_ZTile].w4 = tded_Texture; td_tile[tded_XTile][tded_ZTile].wt4 = tded_TextureWrapMode
		td_tile[tded_XTile][tded_ZTile].d = tded_Diagonal
	endif

	if ct = -1
		td_wall[tded_XTile][tded_ZTile][tded_Wall][0] = tded_Y
		td_wall[tded_XTile][tded_ZTile][tded_Wall][1] = tded_Y
		td_wall[tded_XTile][tded_ZTile][tded_Wall][2] = tded_Y + 1.0
		td_wall[tded_XTile][tded_ZTile][tded_Wall][3] = tded_Y + 1.0
	endif
	_TD_BuildMap
endproc

procedure TD_AddFloor()
	if td_tile[tded_XTile][tded_ZTile].f = -1
		td_floor[tded_XTile][tded_ZTile][0] = tded_Y
		td_floor[tded_XTile][tded_ZTile][1] = tded_Y            
		td_floor[tded_XTile][tded_ZTile][2] = tded_Y
		td_floor[tded_XTile][tded_ZTile][3] = tded_Y
		rem wmTileCalcNormals(wm->tile[ed->xTile][ed->zTile]);
	endif
	td_tile[tded_XTile][tded_ZTile].f = tded_Texture
	td_tile[tded_XTile][tded_ZTile].ft = tded_SplitMode
	_TD_BuildMap
endproc

procedure TD_AddCeiling()
	if td_tile[tded_XTile][tded_ZTile].c = -1
		td_ceil[tded_XTile][tded_ZTile][0] = tded_Y + 1.0
		td_ceil[tded_XTile][tded_ZTile][1] = tded_Y + 1.0            
		td_ceil[tded_XTile][tded_ZTile][2] = tded_Y + 1.0
		td_ceil[tded_XTile][tded_ZTile][3] = tded_Y + 1.0
	endif
	td_tile[tded_XTile][tded_ZTile].c = tded_Texture
	td_tile[tded_XTile][tded_ZTile].ct = tded_SplitMode
	_TD_BuildMap
endproc

procedure TD_SetHeightmapTexture()
	if not sizeof(hm_Map) then return
	hm_Map[tded_XTile][tded_ZTile].t = tded_Texture
	_TD_BuildHM
endproc

procedure TD_EditorDelete()
	if tded_Mode = TD_EDIT_WALLS
		if tded_Wall = 0;     td_tile[tded_XTile][tded_ZTile].w0 = -1
		elseif tded_Wall = 1; td_tile[tded_XTile][tded_ZTile].w1 = -1
		elseif tded_Wall = 2; td_tile[tded_XTile][tded_ZTile].w2 = -1
		elseif tded_Wall = 3; td_tile[tded_XTile][tded_ZTile].w3 = -1
		elseif tded_Wall = 4; td_tile[tded_XTile][tded_ZTile].w4 = -1
		endif
	elseif tded_Mode = TD_EDIT_FLOOR
		td_tile[tded_XTile][tded_ZTile].f = -1
	elseif tded_Mode = TD_EDIT_CEILING
		td_tile[tded_XTile][tded_ZTile].c = -1
	endif
	_TD_BuildMap
endproc

procedure TD_EditorApplySplit()
	if tded_Mode = TD_EDIT_FLOOR
		td_tile[tded_XTile][tded_ZTile].ft = tded_SplitMode; _TD_BuildMap
	elseif tded_Mode = TD_EDIT_CEILING
		td_tile[tded_XTile][tded_ZTile].ct = tded_SplitMode; _TD_BuildMap
	endif
endproc

procedure TD_EditorApplyTextureWrap()
	if tded_Mode = TD_EDIT_WALLS
		if tded_Wall = 0;     td_tile[tded_XTile][tded_ZTile].wt1 = tded_TextureWrapMode
		elseif tded_Wall = 1; td_tile[tded_XTile][tded_ZTile].wt2 = tded_TextureWrapMode
		elseif tded_Wall = 3; td_tile[tded_XTile][tded_ZTile].wt3 = tded_TextureWrapMode
		else;                 td_tile[tded_XTile][tded_ZTile].wt4 = tded_TextureWrapMode
		endif
		_TD_BuildMap
	endif
endproc

procedure TD_SetFocus()
	_glSetFocus
endproc

procedure TD_EditorHeighten()
	if tded_Mode = TD_EDIT_WALLS
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_wall[tded_XTile][tded_ZTile][tded_Wall][0] = td_wall[tded_XTile][tded_ZTile][tded_Wall][0] + 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_wall[tded_XTile][tded_ZTile][tded_Wall][1] = td_wall[tded_XTile][tded_ZTile][tded_Wall][1] + 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_wall[tded_XTile][tded_ZTile][tded_Wall][2] = td_wall[tded_XTile][tded_ZTile][tded_Wall][2] + 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_wall[tded_XTile][tded_ZTile][tded_Wall][3] = td_wall[tded_XTile][tded_ZTile][tded_Wall][3] + 0.1
	elseif tded_Mode = TD_EDIT_FLOOR
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_floor[tded_XTile][tded_ZTile][0] = td_floor[tded_XTile][tded_ZTile][0] + 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_floor[tded_XTile][tded_ZTile][1] = td_floor[tded_XTile][tded_ZTile][1] + 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_floor[tded_XTile][tded_ZTile][2] = td_floor[tded_XTile][tded_ZTile][2] + 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_floor[tded_XTile][tded_ZTile][3] = td_floor[tded_XTile][tded_ZTile][3] + 0.1
	elseif tded_Mode = TD_EDIT_CEILING
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_ceil[tded_XTile][tded_ZTile][0] = td_ceil[tded_XTile][tded_ZTile][0] + 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_ceil[tded_XTile][tded_ZTile][1] = td_ceil[tded_XTile][tded_ZTile][1] + 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_ceil[tded_XTile][tded_ZTile][2] = td_ceil[tded_XTile][tded_ZTile][2] + 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_ceil[tded_XTile][tded_ZTile][3] = td_ceil[tded_XTile][tded_ZTile][3] + 0.1
	endif
	_TD_BuildMap
endproc

procedure TD_EditorLower()
	if tded_Mode = TD_EDIT_WALLS
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_wall[tded_XTile][tded_ZTile][tded_Wall][0] = td_wall[tded_XTile][tded_ZTile][tded_Wall][0] - 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_wall[tded_XTile][tded_ZTile][tded_Wall][1] = td_wall[tded_XTile][tded_ZTile][tded_Wall][1] - 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_wall[tded_XTile][tded_ZTile][tded_Wall][2] = td_wall[tded_XTile][tded_ZTile][tded_Wall][2] - 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_wall[tded_XTile][tded_ZTile][tded_Wall][3] = td_wall[tded_XTile][tded_ZTile][tded_Wall][3] - 0.1
	elseif tded_Mode = TD_EDIT_FLOOR
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_floor[tded_XTile][tded_ZTile][0] = td_floor[tded_XTile][tded_ZTile][0] - 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_floor[tded_XTile][tded_ZTile][1] = td_floor[tded_XTile][tded_ZTile][1] - 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_floor[tded_XTile][tded_ZTile][2] = td_floor[tded_XTile][tded_ZTile][2] - 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_floor[tded_XTile][tded_ZTile][3] = td_floor[tded_XTile][tded_ZTile][3] - 0.1
	elseif tded_Mode = TD_EDIT_CEILING
		if tded_Corner AND TD_CORNER_BTM_LEFT  then td_ceil[tded_XTile][tded_ZTile][0] = td_ceil[tded_XTile][tded_ZTile][0] - 0.1
		if tded_Corner AND TD_CORNER_BTM_RIGHT then td_ceil[tded_XTile][tded_ZTile][1] = td_ceil[tded_XTile][tded_ZTile][1] - 0.1
		if tded_Corner AND TD_CORNER_TOP_RIGHT then td_ceil[tded_XTile][tded_ZTile][2] = td_ceil[tded_XTile][tded_ZTile][2] - 0.1
		if tded_Corner AND TD_CORNER_TOP_LEFT  then td_ceil[tded_XTile][tded_ZTile][3] = td_ceil[tded_XTile][tded_ZTile][3] - 0.1
	endif
	_TD_BuildMap
endproc

procedure TD_SetEditMode(mode)
	tded_Mode = mode
endproc

procedure TD_DecTextureIndex()
	tded_Texture = max(tded_Texture - 1, 0)
endproc

procedure TD_IncTextureIndex()
	tded_Texture = min(tded_Texture + 1, TD_MAX_TEXTURES - 1)
endproc

function TD_GetTextureIndex()
	return tded_Texture
endfunc

procedure TD_DrawEditor()
	_glDisable GL_FOG
	_glColor3ub 255, 255, 255
	_glDisable GL_TEXTURE_2D
	_glBegin GL_LINE_LOOP
		_glVertex3f 0.0, 0.0, 0.0
		_glVertex3f float(td_wmw), 0.0, 0.0
		_glVertex3f float(td_wmw), 0.0, float(td_wmh)
		_glVertex3f 0.0, 0.0, float(td_wmh)
	_glEnd
	_glEnable GL_TEXTURE_2D

	_glPushMatrix
	_glTranslatef float(tded_XTile), tded_Y, float(tded_ZTile)
  _glTranslatef 0.5, 0.0, 0.5
  if tded_Mode = TD_EDIT_WALLS
		if tded_Wall <> 4
			if tded_Wall = 1; _glRotatef 270.0, 0.0, 1.0, 0.0
			elseif tded_Wall = 2; _glRotatef 180.0, 0.0, 1.0, 0.0
			elseif tded_Wall = 3; _glRotatef 90.0, 0.0, 1.0, 0.0
			endif
			rem _glEnable GL_BLEND
			rem _glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
			_glColor4ub 255, 255, 255, 200
			if tded_Wireframe
				_glDisable GL_DEPTH_TEST
				_glDisable GL_TEXTURE_2D
				_glBegin GL_LINE_LOOP
					_glVertex3f -0.6, 0.0, -0.5
					_glVertex3f -0.6, 0.0, 0.5
					_glVertex3f -0.6, 1.0, 0.5
					_glVertex3f -0.6, 1.0, -0.5
				_glEnd
			else
				_glBindTexture GL_TEXTURE_2D, td_WMTextures[tded_Texture]
				_glBegin GL_QUADS
					_glTexCoord2f 0.0, 1.0; _glVertex3f -0.6, 0.0, -0.5
					_glTexCoord2f 1.0, 1.0; _glVertex3f -0.6, 0.0, 0.5
					_glTexCoord2f 1.0, 0.0; _glVertex3f -0.6, 1.0, 0.5
					_glTexCoord2f 0.0, 0.0; _glVertex3f -0.6, 1.0, -0.5
				_glEnd
				_glDisable GL_DEPTH_TEST
				_glDisable GL_TEXTURE_2D
			endif
			rem _glDisable GL_BLEND
			_glPointSize 8.0
			_glColor3ub 255, 255, 255
			_glBegin GL_POINTS
				if tded_Corner AND TD_CORNER_BTM_LEFT  then _glVertex3f -0.6, 0.0, -0.5
				if tded_Corner AND TD_CORNER_BTM_RIGHT then _glVertex3f -0.6, 0.0, 0.5
				if tded_Corner AND TD_CORNER_TOP_RIGHT then _glVertex3f -0.6, 1.0, 0.5
				if tded_Corner AND TD_CORNER_TOP_LEFT  then _glVertex3f -0.6, 1.0, -0.5
			_glEnd
			_glEnable GL_TEXTURE_2D
			_glEnable GL_DEPTH_TEST
    else
			if tded_Diagonal = 2; _glRotatef 270.0, 0.0, 1.0, 0.0
			elseif tded_Diagonal = 3; _glRotatef 180.0, 0.0, 1.0, 0.0
			elseif tded_Diagonal = 4; _glRotatef 90.0, 0.0, 1.0, 0.0
			endif
			rem _glEnable GL_BLEND
			rem _glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
			_glColor4ub 255, 255, 255, 200
			if tded_Wireframe
				_glDisable GL_DEPTH_TEST
				_glDisable GL_TEXTURE_2D
				_glBegin GL_LINE_LOOP
					_glVertex3f 0.4, 0.0, -0.6
					_glVertex3f -0.6, 0.0, 0.4
					_glVertex3f -0.6, 1.0, 0.4
					_glVertex3f 0.4, 1.0, -0.6
      	_glEnd
			else
				_glBindTexture GL_TEXTURE_2D, td_WMTextures[tded_Texture]
				_glBegin GL_QUADS
					_glTexCoord2f 0.0, 1.0; _glVertex3f 0.4, 0.0, -0.6
					_glTexCoord2f 1.0, 1.0; _glVertex3f -0.6, 0.0, 0.4
					_glTexCoord2f 1.0, 0.0; _glVertex3f -0.6, 1.0, 0.4
					_glTexCoord2f 0.0, 0.0; _glVertex3f 0.4, 1.0, -0.6
      	_glEnd
				_glDisable GL_DEPTH_TEST
				_glDisable GL_TEXTURE_2D
			endif
			rem _glDisable GL_BLEND
			_glPointSize 8.0
			_glColor3f 1.0, 1.0, 1.0
			_glBegin GL_POINTS
			if tded_Corner AND TD_CORNER_BTM_LEFT  then _glVertex3f 0.4, 0.0, -0.6
			if tded_Corner AND TD_CORNER_BTM_RIGHT then _glVertex3f -0.6, 0.0, 0.4
			if tded_Corner AND TD_CORNER_TOP_RIGHT then _glVertex3f -0.6, 1.0, 0.4
			if tded_Corner AND TD_CORNER_TOP_LEFT  then _glVertex3f 0.4, 1.0, -0.6
			_glEnd
			_glEnable GL_TEXTURE_2D
			_glEnable GL_DEPTH_TEST
		endif
	elseif tded_Mode = TD_EDIT_FLOOR
		rem _glEnable GL_BLEND
		rem _glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
		_glColor4ub 255, 255, 255, 200
		if tded_Wireframe
			_glDisable GL_DEPTH_TEST
			_glDisable GL_TEXTURE_2D
			_glBegin GL_LINE_LOOP
				_glVertex3f -0.5, 0.05, -0.5
				_glVertex3f -0.5, 0.05, 0.5
				_glVertex3f 0.5, 0.05, 0.5
				_glVertex3f 0.5, 0.05, -0.5
			_glEnd
		else
			_glBindTexture GL_TEXTURE_2D, td_WMTextures[tded_Texture]
			_glBegin GL_QUADS
				_glTexCoord2f 0.0, 0.0; _glVertex3f -0.5, 0.05, -0.5
				_glTexCoord2f 0.0, 1.0; _glVertex3f -0.5, 0.05, 0.5
				_glTexCoord2f 1.0, 1.0; _glVertex3f 0.5, 0.05, 0.5
				_glTexCoord2f 1.0, 0.0; _glVertex3f 0.5, 0.05, -0.5
			_glEnd
			_glDisable GL_DEPTH_TEST
			_glDisable GL_TEXTURE_2D
		endif
		rem _glDisable GL_BLEND
		_glColor3f 1.0, 1.0, 1.0
		_glPointSize 8.0
		_glBegin GL_POINTS
			if tded_Corner AND TD_CORNER_BTM_LEFT  then _glVertex3f -0.5, 0.0, -0.5
			if tded_Corner AND TD_CORNER_BTM_RIGHT then _glVertex3f 0.5, 0.0, -0.5
			if tded_Corner AND TD_CORNER_TOP_RIGHT then _glVertex3f 0.5, 0.0, 0.5
			if tded_Corner AND TD_CORNER_TOP_LEFT  then _glVertex3f -0.5, 0.0, 0.5
    _glEnd
	elseif tded_Mode = TD_EDIT_CEILING
    rem _glEnable GL_BLEND
    rem _glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
    _glColor4ub 255, 255, 255, 200
		if tded_Wireframe
			_glDisable GL_DEPTH_TEST
			_glDisable GL_TEXTURE_2D
    	_glBegin GL_LINE_LOOP
      	_glVertex3f 0.5, 0.95, -0.5
      	_glVertex3f 0.5, 0.95, 0.5
      	_glVertex3f -0.5, 0.95, 0.5
      	_glVertex3f -0.5, 0.95, -0.5
    	_glEnd
		else
    	_glBindTexture GL_TEXTURE_2D, td_WMTextures[tded_Texture]
    	_glBegin GL_QUADS
      	_glTexCoord2f 1.0, 0.0; _glVertex3f 0.5, 0.95, -0.5
      	_glTexCoord2f 1.0, 1.0; _glVertex3f 0.5, 0.95, 0.5
      	_glTexCoord2f 0.0, 1.0; _glVertex3f -0.5, 0.95, 0.5
      	_glTexCoord2f 0.0, 0.0; _glVertex3f -0.5, 0.95, -0.5
    	_glEnd
			_glDisable GL_DEPTH_TEST
			_glDisable GL_TEXTURE_2D
		endif
    rem _glDisable GL_BLEND
    _glColor3f 1.0, 1.0, 1.0
    _glPointSize 8.0
    _glBegin GL_POINTS
			if tded_Corner AND TD_CORNER_BTM_LEFT  then _glVertex3f -0.5, 1.0, -0.5
			if tded_Corner AND TD_CORNER_BTM_RIGHT then _glVertex3f 0.5, 1.0, -0.5
			if tded_Corner AND TD_CORNER_TOP_RIGHT then _glVertex3f 0.5, 1.0, 0.5
			if tded_Corner AND TD_CORNER_TOP_LEFT  then _glVertex3f -0.5, 1.0, 0.5
    _glEnd
  endif
	_glDisable GL_TEXTURE_2D
	_glDisable GL_DEPTH_TEST
	_glColor3f 1.0, 1.0, 1.0
	_glBegin GL_LINE_LOOP
		_glVertex3f -0.5, 0.0, -0.5
		_glVertex3f -0.5, 0.0, 0.5
		_glVertex3f 0.5, 0.0, 0.5
		_glVertex3f 0.5, 0.0, -0.5
	_glEnd
	_glPopMatrix
	if tded_Mode = TD_EDIT_HEIGHTMAP and sizeof(hm_Map) > 0
		_glBegin GL_LINE_LOOP
			_glVertex3f float(tded_XTile),       hm_Map[tded_XTile][tded_ZTile].h#,         float(tded_ZTile)
			_glVertex3f float(tded_XTile),       hm_Map[tded_XTile][tded_ZTile + 1].h#,     float(tded_ZTile) + 1.0
			_glVertex3f float(tded_XTile) + 1.0, hm_Map[tded_XTile + 1][tded_ZTile + 1].h#, float(tded_ZTile) + 1.0
			_glVertex3f float(tded_XTile) + 1.0, hm_Map[tded_XTile + 1][tded_ZTile].h#,     float(tded_ZTile)
		_glEnd
	endif

	_glEnable GL_DEPTH_TEST
	_glEnable GL_TEXTURE_2D 
	_glEnable GL_FOG
endproc

procedure TD_SaveMap(filename$)
	create file 0, filename, true

	if file(0) = 0 then end

	write32 0, MAP_VERSION
	rem size.
	write32 0, td_wmw
	write32 0, td_wmh
	rem textures.
	for i = 0 to TD_MAX_TEXTURES - 1
		writes 0, get_clean_filename(td_WMTextureFN[i])
	next
	rem colors.
	for i = 0 to 9
		writef 0, td_color[i][0]
		writef 0, td_color[i][1]
		writef 0, td_color[i][2]
	next
	rem tiles.
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			rem tile.
			write32 0, td_tile[x][z].f
			write32 0, td_tile[x][z].ft
			write32 0, td_tile[x][z].c
			write32 0, td_tile[x][z].ct
			write32 0, td_tile[x][z].w0
			write32 0, td_tile[x][z].w1
			write32 0, td_tile[x][z].w2
			write32 0, td_tile[x][z].w3
			write32 0, td_tile[x][z].w4
			write32 0, td_tile[x][z].wt0
			write32 0, td_tile[x][z].wt1
			write32 0, td_tile[x][z].wt2
			write32 0, td_tile[x][z].wt3
			write32 0, td_tile[x][z].wt4
			write32 0, td_tile[x][z].b
			write32 0, td_tile[x][z].d
			rem walls.
			for i = 0 to 4
				for j = 0 to 3
					writef 0, td_wall[x][z][i][j]
				next
			next
			rem floor.
			for i = 0 to 3
				writef 0, td_floor[x][z][i]
			next
			rem ceiling.
			for i = 0 to 3
				writef 0, td_ceil[x][z][i]
			next
		next
	next
	if sizeof(hm_Map) > 0
		write32 0, 1
		writes 0, get_clean_filename(hm_Filename)
		write32 0, hm_SizeX
		write32 0, hm_SizeZ
		writef 0, hm_Diff
		for z = 0 to hm_SizeZ - 1
			for x = 0 to hm_SizeX - 1
				write32 0, hm_Map[x][z].t
			next
		next
	else
		write32 0, 0
	endif
	free file 0
endproc

function TD_LoadMap(filename$)
	open file 0, filename, true
	if not file(0) then return false	

	path$ = get_path(filename)

	rem map version.
	ver = read32(0)
	rem size.
	w = read32(0)
	h = read32(0)
	proc TD_InitMap w, h 
	rem textures.
	for i = 0 to TD_MAX_TEXTURES - 1
		td_WMTextureFN[i] = path + reads(0)
		td_WMTextures[i] = TD_LoadTexture(td_WMTextureFN[i])
	next
	rem colors.
	for i = 0 to 9
		td_color[i][0] = readf(0)
		td_color[i][1] = readf(0)
		td_color[i][2] = readf(0)
	next
	rem tiles.
	for z = 0 to td_wmh - 1
		for x = 0 to td_wmw - 1
			rem tile.
			td_tile[x][z].f = read32(0)
			td_tile[x][z].ft = read32(0)
			td_tile[x][z].c = read32(0)
			td_tile[x][z].ct = read32(0)
			td_tile[x][z].w0 = read32(0)
			td_tile[x][z].w1 = read32(0)
			td_tile[x][z].w2 = read32(0)
			td_tile[x][z].w3 = read32(0)
			td_tile[x][z].w4 = read32(0)
			td_tile[x][z].wt0 = read32(0)
			td_tile[x][z].wt1 = read32(0)
			td_tile[x][z].wt2 = read32(0)
			td_tile[x][z].wt3 = read32(0)
			td_tile[x][z].wt4 = read32(0)
			td_tile[x][z].b = read32(0)
			td_tile[x][z].d = read32(0)
			rem walls.
			for i = 0 to 4
				for j = 0 to 3
					td_wall[x][z][i][j] = readf(0)
				next
			next
			rem floor.
			for i = 0 to 3
				td_floor[x][z][i] = readf(0)
			next
			rem ceiling.
			for i = 0 to 3
				td_ceil[x][z][i] = readf(0)
			next
		next
	next
	if read32(0)
		hm_Filename = path + reads(0)
		w = read32(0)
		h = read32(0)
		diff# = readf(0)
		if TD_LoadHeightmap(hm_Filename, diff#)
			for z = 0 to h - 1
				for x = 0 to w - 1
					hm_Map[x][z].t = read32(0)
				next
			next
			_TD_BuildHM
		endif
	endif
	free file 0
	_TD_BuildMap
	return true
endfunc

