Map Editor Alpha -(x360 Version)-

Miscellaneous Forums/Blitz Showcase/Map Editor Alpha -(x360 Version)-

www.dreamspaced.com/WOT360.rar


Alpha of the map editor for World of Tomorrow. Although it can be used by any game using the map engine, which is not tied to the twot code base.

The map engine now supports 360 Rotational scrolling as well as regular scrolling.

Features:

Load,Save - Custom format. The .map file compresses and saves any tiles used in it so it is self-contained.

PasteTile,Line Tile,Hollow Box, Filled Box,Tile Picker and Clear tools.

It has a global ini file that saves all current settings when you quit.

You can create new maps of any size by clicking on new map.

The W and D keys cycle through tiles. Tile window is there, but not implemented.

To load a folder of tiles, click on load tile folder and pick a folder. It'll load any images without "nm" or "bump" in the file name.

If you place a NM file of a tile, the map engine will use it for normal mapping.

Hold in rmb and move the mouse to rotate the map, hold in 3rd mouse button and move mouse to scroll map. alternatively move to the edge of the screen.

Lmb = Active tool.

Presently you cannot edit a map that is rotated as the tile picker hasn't been updated to take rotation into account.
Scroll has though..so it's natural.

Here's the engine code for you to to load use the maps.

Example usage,


Local Test:Map = Map.Load("MyMap.map")

Repeat
cls

Test.Rotate( 180 )

Test.Scroll( 5,0 )
Test.Draw()
flip
forever




Strict
'
'
'Map Engine V0.1.
'(c)Dreamspace 2005.


Type Base
		Field x:Float,y:Float
		Field z:Float
		Method Draw(x,y) Abstract
		Method Pasted( mapx,mapy,Mapz,ax,ay) Abstract
End Type


Type Light Extends Base

	Field r:Float,g:Float,b:Float

	Field castShadow:Byte 
	Field radius:Float
	Global Lights:TList
		
	Function Create:Light( r,g,b )
		Local out:light = New light
		out.r=r
		out.g=g
		out.b=b
		out.castShadow=True
		ListAddLast Light.Lights,out
		Return out
	End Function
	
	Method Color(nr,ng,nb)
		r=nr
		g=ng
		b=nb
	End Method

	Method SetRadius( nRadius)
		radius = nradius
	End Method
	
	Method Shadows( enable:Byte = True)
		castShadow = enable
	End Method
	
	
	Method Draw(x,y) Final
		
		Local tr,tg,tb
		GetColor(tr,tg,tb)
		
		Local tblend = GetBlend()
		Local alpha:Float =GetAlpha()
		SetBlend AlphaBlend 
		SetAlpha 0.5
		
		SetColor r,g,b
		DrawOval x-Radius/2,y-radius/2,radius,radius
		SetBlend SolidBlend
		SetColor tr,tg,tb
		SetAlpha alpha
		
	End Method
	
	Method pasted(mapx,mapy,Mapz,ax,ay) Final
		x=ax
		y=ay
		z = mapz
	End Method
	
End Type
Light.Lights = CreateList()

Type Occluder

	Field map:Byte[,]
	Function Create:Occluder(Width,Height)
		Local out:occluder = New occluder
		out.map = New Byte[width,height]
		Return out
	End Function

	Method FromPixMap( pix:TPixmap )

		For Local x=0 To PixmapWidth( pix ) - 1
		For Local y=0 To PixmapHeight( pix) - 1
			Local p:Byte Ptr = pix.PixelPtr(x,y)
			Local lum = p[2]+p[1]+p[3]/3
			
			If lum<30
				map[x,y]=False
			Else 
				map[x,y]=True
			EndIf
			
		Next
		Next
		
	End Method
			
		
End Type

Type ColMap

	Field Pix:Byte[,,] 
	Field Hi:Byte[,]
	Field w,h
	
	Function Create:ColMap( Width,Height )
		
		Local out:colMap = New colmap
		out.pix = New Byte[width,height,3]
		out.hi = New Byte[width,height]
		out.w=width
		out.h=height
		Return out
					
	End Function
	
	Method FromPixMap( raw:TPixMap )
		
		For Local x=0 To w-1
		For Local y=0 To h-1
			
			Local p:Byte Ptr = raw.PixelPtr(x,y)
			pix[x,y,0] = p[2]
			pix[x,y,1] = p[1]
			pix[x,y,2] = p[0]			
				
		Next
		Next
		 
	End Method
	
	Method LumFromPix( raw:TPixMap )
	
		For Local x=0 To w-1
		For Local y=0 To h-1
		
			Local p:Byte Ptr = raw.pixelPtr(x,y)
			hi[x,y] =(p[2]+p[1]+p[0])/3
		
		Next
		Next
	
	End Method


		
End Type


Type BumpMap

	Field Col:ColMap

	Function Create:BumpMap(width,height )
		Local out:bumpmap = New bumpmap
		out.col = colMap.create( width,height )
		Return out
	End Function

	
	Function Load:BumpMap( file:String )
		
		Local out:Bumpmap = New bumpmap
		Local pix:TPixmap = LoadPixmap( file )
		If pix=Null
			Print "Bump map not found"
			Return Null 
		EndIf
		ConvertPixmap( pix,PF_BGRA8888)
		
		
		
		out.col = Colmap.create(PixmapWidth(pix),PixmapHeight(pix) )
		out.col.frompixmap( pix )
		Return out
		
	End Function
		
	Method GetPixels:Byte[,,]( )
		Return col.pix
	End Method
	
End Type


Type Tile
	Field image:TImage
	Field raw:TPixmap
	Field isAlphaAdjancent:Byte
	Field isWalkable:Byte 
	Field cFrame:Float 
	Field cMaxFrame:Float 
	Field cAnimSpd:Float
	Field Width,Height
	Field shape:Occluder
	Field Name:String
	Field Bump:BumpMap

	Method mSize:Long()
		
		Local siz=0
		siz:+width*height*4
		siz:+SizeOf(width)*4
		siz:+SizeOf(name)
		siz:+SizeOf(cMaxFrame)
		
		siz:+SizeOf(cAnimSpd)
		Return siz
		
	End Method
	
	Method ReadTile( Stream:TStream )
	
		width = Readint(stream)
		height = Readint(stream)
		Local slen=Readint(stream)
		name=ReadString(stream,sLen)
		cMaxFrame=Readint(Stream)
		cAnimSpd=ReadFloat(Stream)
		
		image = CreateImage( width,height,1,MASKEDIMAGE)
		raw = LockImage( image,0,False,True )
		
		For Local x=0 To width-1
		For Local y=0 To height-1
			Local p:Byte Ptr = raw.pixelptr(x,y)
			p[0]=ReadByte(stream)
			p[1]=ReadByte(stream)
			p[2]=ReadByte(stream)
			p[3]=ReadByte(stream)
		Next
		Next
	
		Local crc = Readint( stream )
		If crc<>-1 RuntimeError "Tile load crc mismatch"
		
		Print "Loaded tile Width:"+width+" Height:"+height
		UnlockImage(image) 

		
	End Method


	Method WriteTile( stream:TStream )
		
		Local at = StreamPos(stream)
		WriteInt stream,width
		WriteInt stream,height
		WriteInt stream,Len( name )
		WriteString stream,name
		WriteInt stream,cMaxFrame
		WriteFloat stream,cAnimSpd
		
		Local raw:TPixmap = LockImage( image,0,True,False )
		
		For Local x=0 To width-1
		For Local y=0 To height-1
			Local p:Byte Ptr = raw.pixelPtr(x,y)
			WriteByte stream,p[0]
			WriteByte stream,p[1]
			WriteByte stream,p[2]
			WriteByte stream,p[3]
		Next
		Next
		
		WriteInt stream,-1
				
		Print "Tile was "+String(StreamPos(stream)-at)+" Bytes"
		
	End Method
	
	Function Load:Tile(file:String)
		Local out:Tile = New tile 
		If FileType(file)<>1 RuntimeError "Cannot load Tile "+file+" Not a valid file."
		
		out.image = LoadImage( file,MASKEDIMAGE )
		If out.image = Null RuntimeError "Cannot load Image "+File
		out.raw = LoadPixmap( file )
		If out.raw = Null RuntimeError "Image loaded but pixal map failed."
		out.raw = ConvertPixmap( out.raw,PF_BGRA8888)
		out.cFrame=0	
		out.width = ImageWidth(out.image)
		out.height = ImageHeight(out.image)
		out.name = StripAll( file )
		Local t1:String = ExtractDir( file )+"\nm"+out.name+".bmp"
		Local t2:String = ExtractDir( file )+"bump"+out.name+"."+".bmp" 'ExtractExt( file ) 
		
	
		out.bump = BumpMap.Load( t1 )
		If out.bump = Null
			
			RuntimeError t1+" not present."
		'	out.bump = BumpMap.Create( out.width,out.height )
		EndIf
	'	Local braw:TPixMap = LoadPixmap( t2 )
	'	If braw = Null
	'		Print "No height map"
	'		out.bump.col.lumFromPix( out.raw )
	'	Else
	'		out.bump.col.lumFromPix( braw )
	'	EndIf
		
		out.shape = Occluder.Create( out.width,out.height )
		out.shape.fromPixMap( out.raw )
		
		Return out
	
	End Function

	Function Create:Tile(Width,Height,Name:String ="Custom Tile")

		Local out:tile = New Tile
		out.name = name
		out.width=width
		out.height = height
		out.raw = CreatePixmap(width,height,PF_BGRA8888)
		Return out

	End Function
	
	
	Method process() 
	    image = CreateImage(width,height,cMaxFrame+1,DYNAMICIMAGE | MASKEDIMAGE )
	    Local traw:TPixmap = LockImage(image,0,False,False)
	
		Local p1:Byte Ptr
		Local p2:Byte Ptr
	    For Local x=0 To width-1
	    For Local y=0 To height-1
	'		WritePixel( traw,x,y,ReadPixel(raw,x,y) )
			p1 = traw.PixelPtr(x,y)
			p2 = raw.pixelptr(x,y)
			p1[0]=p2[2]
			p1[1]=p2[1]
			p1[2]=p2[0]
			p1[3]=p2[3]
		Next
		Next	
		
		UnlockImage( image,0 )
		
	End Method
	
	Method AlphaArea( enable:Byte )
		isalphaAdjancent = enable
	End Method
	
	Method Walkable( enable:Byte )
		isWalkable = True
	End Method
	
	Method GetRaw:TPixmap()
		Return raw
	End Method
	
	Method Update()
		If(cmaxFrame>0)
			cFrame:+cAnimSpd
			If(cFrame>cmaxFrame)
				cFrame=0
			EndIf
		End If
	End Method
		
	Method Draw(x:Int,y:Int)
		DrawImage image,x,y,cFrame
	End Method
	
	Method getWidth()
		Return width
	End Method
	
	Method getHeight()
		Return height
	End Method
	
End Type

Type ObjLayer
	Field obj:TList
	
End Type


Type Layer

	Field Lay:Tile[]
	Field Obj:ObjLayer[]
	Field isHigh:Byte  
	
	Method Init( Layers:Short)
		Lay = New Tile[Layers]
		Obj = New ObjLayer[Layers]
		For Local j=0 To layers-1
			obj[j] = New ObjLayer
			obj[j].obj = CreateList()
		Next
		
	End Method
	
	Method Highlight( enable:Byte )
	
		isHigh = enable
		
	End Method

	
	Method AddObj(depth,this:base)
		ListAddLast obj[depth].obj,this
	End Method
	
	Method GetObjList:TList(depth)
		Return obj[depth].obj
	End Method

	Method ResetObjs(depth)
		ClearList obj[depth].obj
	End Method
	
End Type


Type Row
	Field Col:Layer[]
	Method Init( Rows:Short,depth:Short )
		Col = New Layer[rows]
		For Local j=0 To rows-1
			col[j] = New Layer
			col[j].init( depth )
		Next
	End Method	
End Type

Type Map

	Field mWidth,mHeight,mDepth
	Field col:Row[]

	Function Load:Map( file:String )
		
		Local out:map = New map
		out.loadFile( file )
		Return out
		
	End Function

	Function Create:Map(width:Short,height:Short,depth:Short)
		Local out:Map = New Map
		out.twidth=-1
		out.vwidth = GraphicsWidth()
		out.vheight = GraphicsHeight()
		out.mWidth = width
		out.mHeight = height
		out.mDepth = depth
		out.populate()
		Return out
	End Function
	

	Method populate()
	
		col = New Row[mwidth]
		For Local j=0 To mwidth-1
			col[j] = New Row
			col[j].init( mheight,mdepth )
		Next
	
	End Method

	
	Method FindId( tiles:TList,til:Tile )
		
		Local index=0
		For Local ct:Tile = EachIn tiles
			If ct = til
				Return index
			EndIf
			index:+1
		Next
		Return -1
		
	End Method

	Method ListHas( list:TList,obj:Object )
		For Local ob:Object = EachIn list
			If ob = obj Return True
		Next
		Return False
	End Method

	Method LoadFile( file:String )
	
		Local tiles:TList = CreateList()
		Local fStream = ReadFile( file )
		Local oSize = Readint( fstream)
		Local cSize = Readint( fstream )
		Local tb = CreateBank( cSize )
		ReadBank( tb,fStream,0,cSize )
		Local nb = CreateBank( oSize*2 )
		oSize=oSize*2
		uncompress( BankBuf(nb),oSize,BankBuf(tb),cSize ) 
		
		Local crc = Readint( fStream )
		If crc<>-1 RuntimeError "Map corrupted."
		Print "Orig Size:"+osize
		Print "Com Siz:"+cSize
		Local ts:TbankStream = CreateBankStream( nb )
						
		Local tileC:Int = Readint( fStream )
		While tileC>0
		
			Local nTile:Tile = New Tile 
			ListAddLast tiles,ntile
			ntile.readTile( ts )
			tWidth = ntile.width
			theight = ntile.height
			tileC:-1
		Wend
		
		mWidth = Readint( fstream )
		mHeight = Readint( fstream )
		mDepth = Readint( fstream )
		
		Local TileL:Object[] = ListToArray( tiles )
		 
		
		populate()
			
		For Local x=0 To mWidth-1
		For Local y=0 To mHeight-1
		For Local z=0 To mDepth-1
			Local id =Readint(fstream)
			If id<>-1
				PasteTile( x,y,z,Tile( tileL[ id ] ) )
			EndIf
		Next
		Next
		Next
		
		crc = Readint(fstream)
		If crc<>-2 RuntimeError "Crc failed on map load."
				
		CloseFile fstream
				
		Print "Loaded "+CountList( tiles)+" Tiles"
		Print "Map sucesfully loaded."
		vwidth=GraphicsWidth()
		vheight = GraphicsHeight()
		setUp()
				
	End Method

	
	Method Save( file:String )
		
		Local Tiles:TList = CreateList()
		
		Local tSize:Long =0
		
		For Local x=0 To mWidth-1
		For Local y=0 To mHeight-1
		For Local z=0 To mDepth-1
		
			Local tmp:tile = col[x].col[y].lay[z]
			If tmp<>Null
				If Not ListContains( Tiles,tmp )
					ListAddLast tiles,tmp
					tSize:+tmp.mSize()
				EndIf
			EndIf
		
		Next
		Next
		Next
		
		Print "Predicted Size:"+tSize+" Bytes For "+CountList(tiles)+" Unique Tiles"
			
		Local tb:TBank = CreateBank( tSize+1024 )
		
		Local bStream:TBankStream=CreateBankStream( tb )
		For Local Til:Tile = EachIn Tiles
			til.writeTile( bStream )	
		Next
		
				 
		Print "Tiles pooled. Compressing."
		
		Local n:TBank = CreateBank( tSize )
		Local dLen = tSize
		compress2( BankBuf(n),Dlen,BankBuf(tb),tSize,9)
		Print "Compressed Size:"+dLen
		Print "Saved "+String(tSize-dLen)+" Bytes"			
		Local fStream:TStream = WriteFile(file)
		If Not fStream RuntimeError "Could not write file "+file
		WriteInt fstream,tSize
		WriteInt fstream,dLen
		WriteBank( n,fstream,0,dLen ) 
		WriteInt fStream,-1
		WriteInt fStream,CountList( tiles )
		WriteInt fStream,mWidth
		WriteInt fstream,mHeight
		WriteInt fStream,mDepth
		
		For Local x=0 To mWidth-1
		For Local y=0 To mHeight-1
		For Local z=0 To mDepth-1
		
			If col[x].col[y].lay[z]<>Null
				Local Id = FindId( tiles,col[x].col[y].lay[z] )
				If id=-1 RuntimeError "map could not be wrote."
				WriteInt fstream,id		
			Else
				WriteInt fstream,-1
			EndIf
		
		Next
		Next
		Next
		WriteInt fstream,-2
		
		CloseFile(fStream)
		
		Print "Map Saved."
		
			
	End Method

	
	Method Size( x:Short,y:Short,width:Short,height:Short)
		xview = x
		yview = y
		vwidth = width
		vheight = height
		Setup()
	End Method
	
	Method PasteTile(x:Short,y:Short,z:Short,actual:Tile)
		col[x].col[y].lay[z] = actual
		If(tWidth=-1)
			tWidth = actual.width
			tHeight = actual.height
			SetUp()
		EndIf
	End Method
	
	Method PasteFill( Layer:Byte,actual:tile )
		For Local j=0 To mWidth-1
		For Local k=0 To mHeight-1
			PasteTile(j,k,layer,actual)
		Next
		Next
	End Method

	Method PasteBox( x:Short,y:Short,w:Short,h:Short,layer:Short,actual:tile,solid:Byte = True)
		For Local ax=x To x+w-1
		For Local ay=y To y+h-1
			If(solid=True)
				pasteTile( ax,ay,layer,actual )
			Else
				If ax=x Or ax=x+w-1 Or ay=y Or ay=y+h-1
					pasteTile( ax,ay,layer,actual )
				EndIf
			EndIf
		Next
		Next
	End Method
	
	Method Highlight( x1,y1,x2,y2 )
		
		For Local j=x1 To x2
		For Local k=y1 To y2
			col[j].col[k].isHigh=True
		Next
		Next
	
	End Method 	
	
	Method PasteLine( x:Float,y:Float,x2:Float,y2:Float,layer:Short,actual:tile )
		
		Local xd:Float = x2-x
		Local yd:Float = y2-y
		Local steps:Float=0
		If Abs(xd)>Abs(yd) steps = Abs(xd) Else steps = Abs(yd)
		Local xi:Float = xd/steps
		Local yi:Float = yd/steps
		
		While steps>0
			pasteTile( x,y,layer,actual )
			x:+xi
			y:+yi
			steps:-1
		Wend
				
	End Method
	
	Method LineLight( x:Float,y:Float,x2:Float,y2:Float )
	
		Local xd:Float = x2-x
		Local yd:Float = y2-y
		Local steps:Float=0
		If Abs(xd)>Abs(yd) steps = Abs(xd) Else steps = Abs(yd)
		Local xi:Float = xd/steps
		Local yi:Float = yd/steps
		
		While steps>0
			'pasteTile( x,y,layer,actual )
			col[x].col[y].isHigh=True
			x:+xi
			y:+yi
			steps:-1
		Wend
	
	End Method
	
	Method SetUp()
		xLen = vWidth/tWidth+2
		yLen = vHeight/tHeight+2
		If xLen<3 Or yLen<3
			RuntimeError "size mismatch, cannot initiate map"
		EndIf
		
		Print ""
		Print "XLen:"+xLen
		Print "YLen:"+yLen
		
	End Method
	
	
	Method getTile:Tile(x:Short,y:Short,z:Short)
		Return col[x].col[y].lay[z]
	End Method
	
	Field AtX,AtY
	
	Method LayerAt:Layer( px,py )
		
		If tWidth<1 Or tHeight<1 Return 
		Local tilex = xp*tWidth-xinc
		Local tiley = yp*tHeight-yinc
		Local lx = (tilex+px)/tWidth
		Local ly = (tiley+py)/theight
		atx=lx
		aty=ly
		If lx>-1 And ly>-1 And lx<mwidth And ly<mheight
		
			Return col[lx].col[ly]
		
		EndIf
		Return col[0].col[0]
				
		Local sx:Float=-1
		Local sy:Float=-1
		
		For Local tx= xp-1 To xp+xLen
			Local dx:Float = sx+tWidth+xInc
		For Local ty= yp-1 To yp+yLen
			Local dy:Float = sy*tHeight+yInc
		
			If px>=dx And px<=dx+tWidth
			If py>=dy And py<=dy+tHeight
				
				atX = tx
				atY = ty
				If tx>-1 And ty>-1 And tx<mWidth And ty<mHeight 
					Return col[tx].col[ty]
				Else
					Return Null
				EndIf
			
			EndIf
			EndIf
			
		Next
			sy=-1
			sx:+1
		Next
		
		atx=0
		aty=0
		Return Null 
		Print "Mouse is not registering with any tiles."
		WaitKey
		End
		
	End Method

	Field Rot:Float
		
	Method Rotate( val:Float )
		rot = val
	End Method
	
	Method GetRotate:Float()
		Return rot
	End Method
	
	Method Draw()
		If tWidth=-1 Or tWidth=0
			Return 
			'RuntimeError "Map has no known tile asscoitation."
		EndIf
		SetRotation rot
				
		Local ax:Float,ay:Float
		
		Local cx:Float = GraphicsWidth()/2
		Local cy:Float = GraphicsHeight()/2
		
		Local tw#=-1*tWidth+xInc
		Local th#=-1*Theight+yInc		
		Local ew#=(xLen+2)*tWidth+xInc		
		Local eh#=(yLen+2)*tHeight+yinc
		Local mx#=(ew-tw)/2
		Local my#=(eh-th)/2
										
		ax=-3
		ay=-3
		For Local td=0 To mDepth-1

		ax=-5
		ay=-5
	
		For Local tx = xp-5 To xp+xLen+7
			Local dx:Float = ax*tWidth+xInc
		For Local ty = yp-5 To yp+yLen+7
			Local dy:Float = ay*tHeight+yInc
			
			If(tx>-1 And ty>-1)
				
				Local xo:Float = dx-mx
				Local yo:Float = dy-my
				Local nx:Float,ny:Float
				nx=Cos (rot)*xo - Sin (rot)*yo
			    ny=Sin (rot)*xo + Cos (rot)*yo	
								
				Render( tx,ty,td,mx+nx,my+ny )
				
				If td=mdepth-1
				If tx<mWidth And ty<mHeight
				If Col[tx].col[ty].isHigh  
					
					col[tx].col[ty].isHigh=False
					Local lr,lg,lb
					Local lAlpha:Float
					Local lBlend 
					lblend = GetBlend()
					lAlpha = GetAlpha()
					GetColor(lr,lg,lb)		
					SetColor 0,255,255
					SetBlend ShadeBlend 
					SetAlpha 0.5
					DrawRect mx+nx,my+ny,tWidth,tHeight
					SetColor lr,lg,lb
					SetBlend lBlend
					SetAlpha lAlpha
							
				EndIf
				EndIf
				EndIf
			
			EndIf
		

			ay:+1
		Next
			ay=-5
			ax:+1
		Next
			
		ax=-3
		ay=-3
		
			For Local tx = xp-1 To xp+xLen
			Local dx:Float = ax*tWidth+xInc
		For Local ty = yp-1 To yp+yLen
			Local dy:Float = ay*tHeight+yInc
			
			If(tx>-1 And ty>-1)
				RenderObjects( tx,ty,td,dx,dy )
			EndIf			
			
			ay:+1
		Next
			ay=-1
			ax:+1
		Next
	
			
		
		Next
		
		SetRotation 0
		
	End Method
	

	Method Scroll( xMov:Float,yMov:Float )
		If xMov<-tWidth-1 xMov=-tWidth-1
		If xMov>tWidth xMov=tWidth-1
		If yMov<-tHeight-1 yMov=-tHeight-1
		If yMov>tHeight-1 yMov=tHeight-1
		mover( Varptr xInc,Varptr xLen,Varptr xp,xmov,twidth,mWidth )
		mover( Varptr yInc,Varptr yLen,Varptr yp,ymov,theight,mHeight )
	End Method
		
	Method Mover( vInc:Float Ptr,vLen:Float Ptr,vp:Float Ptr,val:Float,size:Float,total:Float  )
	
		vInc[0]:+val
	
		If vInc[0]<0 
			vInc[0] = size-Abs(vInc[0])
			vp[0]:+1
		 	If vp[0]>total-vLen[0]-1
				vp[0]=total-vLen[0]-1
				vInc[0] = 0
			EndIf
		EndIf
	
		If vInc[0]>size
			vInc[0]:-size
			vp[0]:-1
			If vp[0]<1
				vp[0] =1
				vInc[0] =size
			EndIf
		EndIf
					
	End Method
	
	Method RenderObjects(tileX,tileY,tileZ,xPix,yPix)
	
		If tileX<0 Or tileX>mWidth-1 Or tileY>mHeight-1 Or tileY<0
			Return
		EndIf
		
		If col[tilex] = Null Return
		If col[tilex].col[tiley] = Null Return
		 
		Local lay:Tile[] = col[tilex].col[tiley].lay
		
		For Local obj:base = EachIn col[tilex].col[tiley].obj[tileZ].obj
			obj.Draw(xPix+tWidth/2,yPix+tHeight/2)
		Next
					
	
	End Method


	Method Render( tileX,tileY,TileZ,xPix,yPix)
	
		If tileX=>mWidth Return
		If tileY=>mHeight Return
		If tileX<0 Return
		If tileY<0 Return 
		If col[tilex] = Null Return
		If col[tilex].col[tiley] = Null Return
		 
		Local lay:Tile[] = col[tilex].col[tiley].lay
		
		If lay[tileZ]<>Null
			col[tilex].col[tiley].lay[tileZ].Draw( xPix,yPix )	
		EndIf
			
		
	End Method
	
	Method PasteObject( x,y,d,this:Base)
		ListAddLast col[x].col[y].obj[d].obj,this
		this.pasted( x,y,d,x*tWidth+tWidth/2,y*tHeight+tHeight/2 )
		Print "Added Object At "+X+","+Y+","+d+" Count:"+CountList( col[x].col[y].obj[d].obj )
	End Method
	
	Field tWidth,tHeight
	Field xInc:Float,yInc:Float
	Field xP:Float,yP:Float
	Field xlen:Float,ylen:Float
	Field xview:Float,yview:Float
	Field vwidth,vheight
			
End Type


Const FlatLight=1,BumpLight =2,NormalLight=3
Type LightMap
	Global LightModel
	Global pMap:Map
	Global eMap:occluder
	
	
	
	Function DoEnvMap()
	
		Local z=0
		Local nx:Float
		Local ny:Float
		Local nz:Float
		For Local x:Float=0 To 255
		For Local y:Float=0 To 255
			nx = (x-128)/128
			ny = (y-128)/128
			nz = 1 - Sqr(nx*nx+ny*ny)
			If nz<0 nz=0
			emap.map[x,y] = nz * 256
		Next
		Next
		
	End Function
	
	
	Function RenderMap:Map( from:Map )
	
		Local st = MilliSecs()
		If LightModel = BumpLight	
			emap = Occluder.Create( 256,256 )
			LightMap.DoEnvMap()
		EndIf
		
		
		LightMap.pMap = from
		Local out:Map = Map.Create( from.mWidth,from.mHeight,from.mDepth )
		For Local d=0 To from.mDepth-1
		For Local x=0 To from.mWidth-1
		For Local y=0 To from.mHeight-1
			
			If from.col[x].col[y].lay[d]<>Null
	'			Print "Processing Tile at "+X+","+Y+","+"Z:"+d
				out.col[x].col[y].lay[d] = Tile.Create( from.tWidth,from.tHeight )
				RenderTile( out,x,y,d,from.col[x].col[y].lay[d] )
			EndIf
			FlushMem	 
		Next
		
		Next
		Next
		
		
		out.twidth = from.twidth
		out.theight = from.theight
		out.setUp()
		Print "Took "+String(MilliSecs()-St)+" To render Lightmap"
		Return out

	End Function
	
	Function RenderTile( from:map,x,y,d,orig:Tile )
		
		Local this:tile = from.col[x].col[y].lay[d]
		
		Local raw:TPixmap = this.raw
		
		Local tileX:Float,tileY:Float
		
		tileX = x*orig.width
		tileY = y*orig.height
		Local revert=0
		Local bmap:bumpMap=Null
		Local bpix:Byte[,,] 
		Local hm:Byte[,]
		
		Local llist:TList = Light.lights
		Local lModel = LightMap.LightModel
		
		LightMap.LightModel = NORMALLIGHT
		If orig.bump<>Null 
			bmap = orig.bump
			bpix = bmap.col.pix
			hm = bmap.col.hi
		Else
		End
		'	If LightMap.LightModel = NormalLight
		'		LightMap.LightModel = FlatLight
		'		Revert=True
		'	EndIf
			
		End If

		Local r,g,b
		Local p:Byte Ptr
		Local ra,ga,ba
		Local nx:Float,ny:Float,nz:Float
		Local mag:Float,lt:Float
		Local lscale:Float
		Local px:Float,py:Float,pz:Float
					
							
		
		For x=0 To this.width-1
		For y=0 To this.height-1
		
			p=orig.raw.PixelPtr(x,y)
			b=p[0]
			g=p[1]
			r=p[2]
		
					
			Select lModel
				Case FlatLight
					
					Local ra=0,ga=0,ba=0
					
					End
				
					For Local Lgt:Light = EachIn Light.Lights
					
						
						Local xd:Float,yd:Float
						xd = lgt.x-(tileX+x)
						yd = lgt.y-(tileY+y)
					
						Local td:Float = Sqr( xd*xd+yd*yd )
						If td>lgt.radius Continue
						Local col = LightMap.RayCast( LightMap.pMap,tileX+x,tileY+y,lgt.x,lgt.y,lgt.z,d)
						If col=True Continue
						Local lScale:Float = 1-td/lgt.radius
						If lScale>1 lScale=1 
						If lScale<0 lScale=0
						ra:+lgt.r*lScale
						ga:+lgt.g*lScale
						ba:+lgt.b*lScale
						
						If ra<0 ra=0
						If ga<0 ga=0
						If ba<0 ba=0
						If ra>255 ra=255
						If ga>255 ga=255
						If ba>255 ba=255
				
					Next
					
					Local rm:Float = ra/255.0
					Local gm:Float = ga/255.0
					Local bm:Float = ba/255.0
					
					r=r*(rm*2)
					g=g*(gm*2)
					b=b*(bm*2)				
							
				Case BumpLight
					RuntimeError "What The FUCK."
					Local ra,ga,ba
					
					If x>0 And y>0 And x<orig.width-1 And y<orig.height-1
					
						For Local lgt:Light = EachIn light.lights
						
							Local nx:Float = hm[x+1,y]-hm[x-1,y]
							Local ny:Float = hm[x,y+1]-hm[y,y-1]
							Local lx:Float = (tilex+x)-lgt.x
							Local ly:Float = (tiley+y)-lgt.y
						    Local mag:Float = Sqr(lx*lx+ly*ly)
							
							
								
							nx:-lx
							ny:-ly
							nx:+128
							ny:+128
							If nx<0 Or nx>255 nx=0
							If ny<0 Or ny>255 ny=0
						
							Local lScale:Float = LightMap.emap.map[lx,ly]
							ra:+lgt.r*(lscale/255.0)
							ga:+lgt.g*(lscale/255.0)
							ba:+lgt.b*(lscale/255.0)
							
							
						Next
					
						
					
					EndIf
					
					Local rm:Float = ra/255.0
					Local gm:Float = ga/255.0
					Local bm:Float = ba/255.0
					
					r=r*(rm)
					g=g*(gm)
					b=b*(bm)				
					
					r=ra
					g=ga
					b=ba		
					 
								
							
				Case NormalLight
				
					ra=0
					ga=0
					ba=0
	
					
					For Local lgt:Light = EachIn lList		
						
										
						nx = lgt.x-(tilex+x)
						ny = lgt.y-(tiley+y)
						nz = 65
						mag = Sqr( nx*nx+ny*ny+nz*nz )
						lt = Sqr(nx*nx+ny*ny)
												
						nx = nx/mag
						ny = ny/mag
						nz = nz/mag
						
						px =bpix[x,y,0]/255.0
						py =bpix[x,y,1]/255.0
						pz =bpix[x,y,2]/255.0
						
						Local ft:Double =1-mag/lgt.radius
						lt = 1-lt/lgt.radius
						If ft<0 ft=0
						px=(-1+px*2)*1.7
						py=(-1+py*2)*1.7
						pz=(-1+pz*2)*1.7
						Local tag:Float = Sqr(px*px+py*py+pz*pz)
						px=px/tag
						py=py/tag
						pz=pz/tag
			
				
						
						lscale =((px * nx) + (py * ny)  + (pz * nz))*lt 
						If lscale>0
							
							If Not LightMap.RayCast( LightMap.pMap,tileX+x,tileY+y,lgt.x,lgt.y,lgt.z,d) 
										
								ra:+lgt.r*lscale
								ga:+lgt.g*lscale
								ba:+lgt.b*lscale
							EndIf
						
						EndIf

									
					Next
				
						
					r=r*((ra/255.0)*2)
					g=g*((ga/255.0)*2)
					b=b*((ba/255.0)*2)
					
									 
									
			End Select
			
			If r>255 r=255
			If g>255 g=255
			If b>255 b=255
	
			WritePixel raw,x,y,r Shl 16 | g Shl 8 | b | 255 Shl 24
		
		Next
		Next
		
		'FlushMem 
		this.process()
		If revert =True LightMap.LightModel = BumpLight
		
	'	Print "Finished processing Tile in "+String(MilliSecs()-start)+" Millisecs" 	
	
	End Function
	
	Function RayCast( on:map,sx:Float,sy:Float,dx:Float,dy:Float,z:Byte,mz:Byte)
	
		Local xd:Float = dx-sx
		Local yd:Float = dy-sy
		If mz = z Return False 
		Local steps:Float =0	
		If Abs(xd)>Abs(yd) steps = Abs(xd) Else steps = Abs(yd)
		Local xi:Float,yi:Float
		xi = xd/steps
		yi = yd/steps
		Local tWidth = LightMap.pMap.tWidth
		Local tHeight = LightMap.pMap.tHeight
		
		'Local pMap:map = LightMap.pMap
		
		Local col:Row[] = LightMap.pMap.col
		Local tileX,tileY,xo,yo
		Local lastx,lasty,lz
		Local sm:Byte[,]=Null
		Local do:Byte=0
		
		While steps>0
		
			TileX = sx / tWidth
			TileY = sy / tHeight
			If tileX<>lastx Or tiley<>lasty
				lastx=tilex
				lasty=tiley
				If col[tilex].col[tiley].lay[z]<>Null
					sm = col[tilex].col[tiley].lay[z].shape.map
					do=True
				Else
					do=False
				EndIf
				
			EndIf
			
			xo = sx-(tileX*tWidth)
			yo = sy-(tileY*tHeight)
			sx:+xi*4
			sy:+yi*4
			steps:-4
			If do = False Or sm[xo,yo]=False Continue
			
			Return True
						
			
		
		Wend
		Return False
		
			
	End Function
	

	Function GenRgb( red,green,blue,alpha=255  )
	
		Return red Shl 16 | green Shl 8 | blue | alpha Shl 24
		
	End Function

	
	Function GetRGB(argb:Int,a Var,r Var, g Var, b Var)
	
		a=(argb Shr 24) 
		r=(argb Shr 16) 
		g=(argb Shr 8) 
		b=argb 
	
	End Function


End Type
LightMap.LightModel = NormalLight





Although not yet implemented in the map editor, you can render lightmaps manually in code, add light sources, with per pixel normal mapping.

Tile1.jpg

needs a tile called nmTile1.jpg

This is a regular 3d normal map, you can produce them in deep exploration (Free download. The 2d image part doesn't run out.)

Report any non obvious bugs please.

very cool,thanks

www.dreamspaced.com/Alpha2.rar
You need to install this over alpha 1.

Tile selection remains pixel perfect even whilst rotated now.





Rotation is real time, not pre-rendered like the normal mapping.