Code archives/3D Graphics - Misc/Portable Lightmapper

This code has been declared by its author to be Public Domain code.

Download source code

Portable Lightmapper by starfox2002
Here is the lightmapper that I planned to release sooner or later. It isn't perfect, but good enough for my needs since it was only a test, to see I was capable of creating a lightmapper. The only requirement for using this lightmapper is to give me credit in any of the used programs. ReUpdated! Some Thanks to Olive and Peter! This now includes different sized lightmaps!

Features Are:
Lightmap Compression(Saves on one texture)
Automatic Lightmap lumel size choser(Based on surface area)
Eight very conveniant Lightmap Related functions!
Very Cool Lightmap Sharing(Similar lightmaps share vertices)
Suppports three types of light(Direct,Point,Spot)
Open Source And Easy To Use!

Example of Lightmap Sharing:
Unshared lightmapped cube looks like this:

But a shared lightmapped cube looks like this:

Which takes up a lot less space, and is quicker to write!
;Simple Lightmap Package
;Open Source, by David Dawkins(Starfox)
;Some thanks go to Elias for his lightmapper!
;All meshes must be unwelded!
;Built in 9/07/02 - 11/29/02
;Added Lightmap Compression!
;Added Optimization, thanks to Olive!
;Added Automatic lightmap size choser
;Sped up lightmap placement
;Lightmap Sharing is now in!
;This now includes light types(1-Direct,2-Point,3-Spot)

;LightmapMesh(mesh,saveuvfilename,detail,lightmapsize,scale-true|false,AmR,G,B,Luminance,Share)
;CreatelmLight(x,y,z,red,green,blue,range,ltype)
;CreateLUVs(mesh,savefilename,coordset)
;LoadLUVs(mesh,openfilename,coordset)
;Unweld(mesh)
;LightmapTerrain(terrain,Amr,G,B,size,luminance)
Function example()
Graphics3D 640,480,0,2
cube = CreateCube() ;Create a object to lightmap
unweld(cube) ;try it without this line:)
EntityPickMode cube,2 ;Make sure that anything you want in the way is pickable
sha = CreateCube() ;Create a cube shadow
ScaleEntity sha,.25,.25,.25
MoveEntity sha,-3,0,0
EntityPickMode sha,2
CreateLight()
UpdateNormals cube
ScaleEntity cube,10,3,3
FlipMesh(cube) ;Make sure you are able to see inside out
cam = CreateCamera()
UpdateNormals cube
MoveEntity cam,0,0,-15
PointEntity cam,cube
EntityPickMode cube,2

;Create generic lights to do the lightmapping
createlmlight(0,0,0,0,0,255,25) ;Position the lights
createlmlight(-5,0,0,255,0,0,15) ;light 2 is at -5,0,0 and color is 255,0,0 and range is 20
While Not KeyHit(1)
If MouseHit(1)
CameraPick(cam,MouseX(),MouseY())
If PickedEntity()
en = PickedEntity()
food = MilliSecs()
tex = lightmapmesh(en,"",0,128,1,0,0,0,1,share) ;Lightmapper
EntityFX cube,1
time = MilliSecs() - food
EntityTexture en,tex
im = CreateImage(256,256)
CopyRect(0,0,256,256,0,0,TextureBuffer(tex),ImageBuffer(im))
FreeTexture tex
EndIf
EndIf

UpdateWorld
RenderWorld
Color 255,255,255
If im > 0
DrawImage im,0,0
EndIf
Text 0,30,"Time To Lightmap: "+time
Text 0,40,"Hit Space To Toggle Lightmap Sharing: "+share
Text 0,50,"Click On Object"
If KeyHit(57)
share = 1-share
EndIf
Flip
Wend
End
End Function

example() ;The example

Type tris
Field x#[3],y#[3],z#[3]
Field surf,index,mesh
Field ver[3],u#[3],v#[3]
Field tex,size#
Field xpos#,ypos#,hosttex
End Type

Type lmlight
Field x#,y#,z#,range#
Field r#,g#,b#,lmtype
Field inner,outer
Field pitch,yaw,roll
End Type

Type lightmapnode
Field x,y,size
End Type

Function LightmapMesh(mesh,luvsave$="",detail=16,bound=256,scaletex=1,ambr=0,ambg=0,ambb=0,lum#=1,share=0)
Local nx#,ny#,nz#,normlen#
Local imagepivot = CreatePivot()
EntityPickMode imagepivot,1:EntityRadius imagepivot,.625
Local lightpivot = CreatePivot()
For surfcount = 1 To CountSurfaces(mesh) ;Surface count
surf = GetSurface(mesh,surfcount)
For tricount = 0 To CountTriangles(surf)-1 ;Triangle count
;Prestuff
t.tris = New tris
t\surf = surf : t\mesh = mesh
t\index = tricount
	in = TriangleVertex(t\surf,t\index,0)
	t\x[1] = VertexX(surf,in) : t\y[1] = VertexY(surf,in)
	t\z[1] = VertexZ(surf,in) : t\ver[1] = in
	t\u[1] = VertexU(surf,in) : t\v[1] = VertexV(surf,in)
	TFormPoint(t\x[1],t\y[1],t\z[1],t\mesh,0)
	t\x[1] = TFormedX() : t\y[1] = TFormedY() : t\z[1] = TFormedZ()
	in = TriangleVertex(t\surf,t\index,1)
	t\x[2] = VertexX(surf,in) : t\y[2] = VertexY(surf,in)
	t\z[2] = VertexZ(surf,in) : t\ver[2] = in
	t\u[2] = VertexU(surf,in) : t\v[2] = VertexV(surf,in)
	TFormPoint(t\x[2],t\y[2],t\z[2],t\mesh,0)
	t\x[2] = TFormedX() : t\y[2] = TFormedY() : t\z[2] = TFormedZ()
	in = TriangleVertex(t\surf,t\index,2)
	t\x[3] = VertexX(surf,in) : t\y[3] = VertexY(surf,in)
	t\z[3] = VertexZ(surf,in) : t\ver[3] = in
	t\u[3] = VertexU(surf,in) : t\v[3] = VertexV(surf,in)
	TFormPoint(t\x[3],t\y[3],t\z[3],t\mesh,0)
	t\x[3] = TFormedX() : t\y[3] = TFormedY() : t\z[3] = TFormedZ()
VertexTexCoords t\surf,t\ver[1],t\u[1],t\v[1]
VertexTexCoords t\surf,t\ver[2],t\u[2],t\v[2]
VertexTexCoords t\surf,t\ver[3],t\u[3],t\v[3]
;Get the normals
nx = getnorm(t\x[1],t\y[1],t\z[1],t\x[2],t\y[2],t\z[2],t\x[3],t\y[3],t\z[3],1)
ny = getnorm(t\x[1],t\y[1],t\z[1],t\x[2],t\y[2],t\z[2],t\x[3],t\y[3],t\z[3],2)	
nz = getnorm(t\x[1],t\y[1],t\z[1],t\x[2],t\y[2],t\z[2],t\x[3],t\y[3],t\z[3],3)	
normlen# = Sqr#((nx*nx)+(ny*ny)+(nz*nz))
If normlen > 0
nx = nx/normlen : ny = ny/normlen : nz = nz/normlen
Else
nx = 0 : ny = 0 : nz = 1
EndIf
;End Pre
Local plane
Local uvmin#[2],uvmax#[2]
Local uvdelta#[2]
;Figure out the plane its on
uvxnorm# = nx : uvynorm# = ny : uvznorm# = nz
nx = Abs(nx) : ny = Abs(ny) : nz = Abs(nz)
plane = 3
If nx > ny And nx > nz Then plane = 1 ;YZ Right
If ny > nx And ny > nz Then plane = 2 ;XZ Top
If nz > nx And nz > ny Then plane = 3 ;XY Front
If nx = ny And nx = nz Then plane = 1
If nz = ny And nz = nx Then plane = 2

If nz = nx And nz = ny Then plane = 3
If plane = 2
t\u[1] = t\x[1] : t\v[1] = t\z[1] ;1st
t\u[2] = t\x[2] : t\v[2] = t\z[2] ;2nd
t\u[3] = t\x[3] : t\v[3] = t\z[3] ;3rd
ElseIf plane = 1
t\u[1] = t\y[1] : t\v[1] = t\z[1] ;1st
t\u[2] = t\y[2] : t\v[2] = t\z[2] ;2nd
t\u[3] = t\y[3] : t\v[3] = t\z[3] ;3rd
ElseIf plane = 3
t\u[1] = t\x[1] : t\v[1] = t\y[1] ;1st
t\u[2] = t\x[2] : t\v[2] = t\y[2] ;2nd
t\u[3] = t\x[3] : t\v[3] = t\y[3] ;3rd
EndIf
;Get the bounding box for the uv coords
uvmin[1] = t\u[1] : uvmin[2] = t\v[1]
uvmax[1] = t\u[1] : uvmax[2] = t\v[1]
For co = 1 To 3
	If t\u[co] < uvmin[1] Then uvmin[1] = t\u[co];If U is < uv minimun u then uvmin u = U
	If t\v[co] < uvmin[2] Then uvmin[2] = t\v[co];If V is < uv minimun v then uvmin v = V
	If t\u[co] > uvmax[1] Then uvmax[1] = t\u[co];If U is > uv maximum u then uvmax u = U
	If t\v[co] > uvmax[2] Then uvmax[2] = t\v[co];If V is > uv maximum v then uvmax v = V
Next
uvdelta[1] = uvmax[1] - uvmin[1] ;U Delta = U Max - U Min
uvdelta[2] = uvmax[2] - uvmin[2] ;V Delta = V Max - V Min
;Now make it a range from 0.0 to 1.0
For co = 1 To 3
	t\u[co] = t\u[co] - uvmin[1] ;Subtract to make the min at the origin
	t\v[co] = t\v[co] - uvmin[2]
	t\u[co] = t\u[co] / uvdelta[1] ;Then Divide to make it range from 0 to 1
	t\v[co] = t\v[co] / uvdelta[2]
Next
;Convert Lumels(Lightmap Pixels) to global space using vectors
Local uvor,dist#,uvvector#[3]
Local vec1#[3], vec2#[3] ;X,Y,Z
Local edge1#[3], edge2#[3]
Local lumelpos#[3]
Local nedge1#[3],nedge2#[3]
Local lightvector#[3]
For co = 1 To 3 ;Find the origin
	If t\u[co] = 0 And t\v[co] = 0 Then uvor = co
Next
uvor = 1
;Distance on a plane Formula by Elias 
nx = uvxnorm : ny = uvynorm : nz = uvznorm
dist = -(uvxnorm * t\x[uvor] + uvynorm * t\y[uvor] + uvznorm * t\z[uvor])
;Confusing vector work
If plane = 1 ;YZ
	tempx# = - (ny * uvmin[1] + nz * uvmin[2] + dist) / nx
	uvvector[1] = tempx
	uvvector[2] = uvmin[1] : uvvector[3] = uvmin[2]
	tempx# = - (ny * uvmax[1] + nz * uvmin[2] + dist) / nx
	vec1[1] = tempx

	vec1[2] = uvmax[1] : vec1[3] = uvmin[2]
	tempx# = - (ny * uvmin[1] + nz * uvmax[2] + dist) / nx
	vec2[1] = tempx
	vec2[2] = uvmin[1] : vec2[3] = uvmax[2]
ElseIf plane = 2 ;XZ
	tempy# = - (nx * uvmin[1] + nz * uvmin[2] + dist) / ny
	uvvector[2] = tempy
	uvvector[1] = uvmin[1] : uvvector[3] = uvmin[2]
	tempy# = - (nx * uvmax[1] + nz * uvmin[2] + dist) / ny
	vec1[2] = tempy
	vec1[1] = uvmax[1] : vec1[3] = uvmin[2]
	tempy# = - (nx * uvmin[1] + nz * uvmax[2] + dist) / ny
	vec2[2] = tempy
	vec2[1] = uvmin[1] : vec2[3] = uvmax[2]
ElseIf plane = 3 ;XY
	tempz# = - (nx * uvmin[1] + ny * uvmin[2] + dist) / nz
	uvvector[3] = tempz
	uvvector[1] = uvmin[1] : uvvector[2] = uvmin[2]
	tempz# = - (nx * uvmax[1] + ny * uvmin[2] + dist) / nz
	vec1[3] = tempz
	vec1[1] = uvmax[1] : vec1[2] = uvmin[2]
	tempz# = - (nx * uvmin[1] + ny * uvmax[2] + dist) / nz
	vec2[3] = tempz
	vec2[1] = uvmin[1] : vec2[2] = uvmax[2]
EndIf
edge1[1] = vec1[1] - uvvector[1] ;X
edge1[2] = vec1[2] - uvvector[2] ;Y
edge1[3] = vec1[3] - uvvector[3] ;Z
edge2[1] = vec2[1] - uvvector[1] ;X
edge2[2] = vec2[2] - uvvector[2] ;Y
edge2[3] = vec2[3] - uvvector[3] ;Z
;Done with vectors, now onto the image
Local lightmapsize = 0 ;Size of lightmap ^2 or whatever
If detail > 0 Then lightmapsize = detail
If detail = 0
mydist# = Abs(uvdelta[1] + uvdelta[2])
If mydist < 1 Then lightmapsize = 1
If mydist >= 1 And mydist < 4 Then lightmapsize = 2
If mydist >= 4 And mydist < 10 Then lightmapsize = 4
If mydist >= 10 And mydist < 26 Then lightmapsize = 8
If mydist >= 26 And mydist < 50 Then lightmapsize = 16
If mydist >= 50 And mydist < 100 Then lightmapsize = 32
If mydist >= 100 And mydist < 200 Then lightmapsize = 64
If mydist >= 200 And mydist < 400 Then lightmapsize = 128
If mydist >= 400 Then lightmapsize = 256
EndIf
Local uf#,vf#
Local lx#,ly#,lz#,lrange#
Local lightmapim = CreateTexture(lightmapsize,lightmapsize)
SetBuffer TextureBuffer(lightmapim)
ClsColor ambr,ambg,ambb : Cls : ClsColor 0,0,0
LockBuffer()
For l.lmlight = Each lmlight ;Incorperate lights
If l\lmtype = 3
piv = CreateCone(8,0)
RotateMesh piv,-90,0,0
PositionEntity piv,l\x,l\y,l\z
FlipMesh piv:RotateEntity piv,l\pitch,l\yaw,l\roll
ScaleMesh piv,l\outer,l\outer,l\inner
EntityPickMode piv,2
EndIf
PositionEntity lightpivot,l\x,l\y,l\z
lrange = l\range
falloffr# = l\r#/lrange#
falloffg# = l\g#/lrange#
falloffb# = l\b#/lrange#
For y = 0 To lightmapsize-1
	For x = 0 To lightmapsize-1
		uf = Float(x) / Float(lightmapsize)
		vf = Float(y) / Float(lightmapsize)
		nedge1[1] = edge1[1] * uf ;X
		nedge1[2] = edge1[2] * uf ;Y
		nedge1[3] = edge1[3] * uf ;Z
		nedge2[1] = edge2[1] * vf
		nedge2[2] = edge2[2] * vf
		nedge2[3] = edge2[3] * vf
		;Get image pos in 3d space
		lumelpos[1] = uvvector[1] + nedge2[1] + nedge1[1]
		lumelpos[2] = uvvector[2] + nedge2[2] + nedge1[2]
		lumelpos[3] = uvvector[3] + nedge2[3] + nedge1[3]
		lightvector[1] = lx - lumelpos[1]
		lightvector[2] = ly - lumelpos[2]
		lightvector[3] = lz - lumelpos[3]
		PositionEntity imagepivot,lumelpos[1],lumelpos[2],lumelpos[3]
		xi# = EntityX(imagepivot) : yi# = EntityY(imagepivot) : zi# = EntityZ(imagepivot)
		;Check for visibility
		distx# = xi-l\x
		disty# = yi-l\y
		distz# = zi-l\z
		endist# = EntityDistance(imagepivot,lightpivot)
		If endist <= lrange Or l\lmtype = 1
		If LinePick(l\x,l\y,l\z,distx,disty,distz,0)=imagepivot
			;If endist < 1 Then endist = 1
			normx# = xi - l\x : normy# = yi - l\y : normz# = zi - l\z
			normx = normx/endist : normy = normy/endist : normz = normz/endist
			cosangle# = (nx*normx)+(ny*normy)+(nz*normz)
			If cosangle > 0
			intense# = Abs(cosangle)
			If intense > 1 Then intense = 1
			If intense < 0 Then intense = 0
			minusr# = falloffr*endist
			minusg# = falloffg*endist
			minusb# = falloffb*endist
			colr# = l\r - minusr+falloffr
			colg# = l\g - minusg+falloffg
			colb# = l\b - minusb+falloffb
			If l\lmtype = 1 Then colr = l\r:colg=l\g:colb=l\b;Direct
			colr = colr*intense*lum : colg = colg*intense*lum
			colb = colb*intense*lum
			argb = ReadPixelFast(x,y) And $FFFFFF
			colr = colr + (argb Shr 16 And %11111111)
			colg = colg + (argb Shr 8 And %11111111)
			colb = colb + (argb And %11111111)
			If colr < 0 Then colr = 0
			If colr > 255 Then colr = 255
			If colg < 0 Then colg = 0
			If colg > 255 Then colg = 255
			If colb < 0 Then colb = 0
			If colb > 255 Then colb = 255
			rgb = colb Or (colg Shl 8) Or (colr Shl 16)
			;Color colr,colg,colb
			;Rect x,y,1,1
			WritePixelFast x,y,rgb
			EndIf
			EndIf
		EndIf
	Next
Next
If l\lmtype = 3 Then FreeEntity piv
Next
UnlockBuffer()
SetBuffer BackBuffer()
t\tex = lightmapim : t\size = lightmapsize
;Do all the transformations here
;blur(t\tex) or whatever
Next
Next

;Do lightmap sharing
If share = 1
For t.tris = Each tris
	For tr.tris = Each tris
	If tr <> t And tr\hosttex = 0
		alike = texturealike(tr\tex,t\tex)
		If alike = 1
			t\hosttex = tr\tex:Exit
		EndIf
	EndIf
	Next
Next
;Second Wave
For t.tris = Each tris
	If t\hosttex > 0
		For tr.tris = Each tris
		If tr\hosttex = 0
			alike = texturealike(tr\tex,t\tex)
			If alike = 1
				t\hosttex = tr\tex:Exit
			EndIf
		EndIf
		Next
	EndIf
Next
EndIf

;Pack on one big bitmap
Local lightmapbound# = lightmapsize^2;Maximum size for lightmap ^2
Local lightbound =bound
Local xpos#,ypos#
Local xsmall#,ysmall#
Local move#
Local bigtex = CreateTexture(lightbound,lightbound,512)
scale# = lightbound/lightmapbound
move# = lightmapsize/lightmapbound
If detail = 0

;tbcount = 0
;tbcurrent=0

;tbbank = CreateBank(tbcount*3*4)

For t.tris = Each tris
If t\hosttex = 0
scale# = lightbound/(t\size*t\size)
lightmapbound = t\size*t\size
	For ypos = 0 To lightbound-1
		For xpos = 0 To lightbound-1
		overlap = 0
		
		;For cmk = 0 To tbcurrent
		;off = cmk*3*4
		;	nlx = PeekInt(tbbank,off)
		;	nly = PeekInt(tbbank,off+4)
		;	nlsize = PeekInt(tbbank,off+8)
		;	If RectsOverlap(nlx,nly,nlsize,nlsize,xpos,ypos,t\size,t\size) = 1
		;	overlap=1:xpos=xpos+nlsize-1
		;	Exit
		;	EndIf
		;Next
		
		For nl.lightmapnode = Each lightmapnode
			If RectsOverlap(nl\x,nl\y,nl\size,nl\size,xpos,ypos,t\size,t\size) = 1
				overlap=1:xpos=xpos+nl\size-1
			Exit
			EndIf
		Next
		If xpos + t\size > lightbound Then overlap = 1:dot1=1:ypos=ypos+1:xpos=-1
		If ypos + t\size > lightbound Then overlap = 1:dot2=1:ypos=lightbound:xpos=lightbound
		
		If overlap = 0
		;off = tbcurrent*3*4
		;tbcurrent = tbcurrent + 1
		t\xpos = xpos : t\ypos = ypos
			n.lightmapnode = New lightmapnode
			n\x = xpos : n\y = ypos : n\size = t\size
		;	PokeInt(tbbank,off,xpos):PokeInt(tbbank,off+4,ypos):PokeInt(tbbank,off+8,t\size)
			CopyRect(0,0,t\size,t\size,xpos,ypos,TextureBuffer(t\tex),TextureBuffer(bigtex))
			xsmall# = xpos/Float(lightmapbound) : ysmall# = ypos/Float(lightmapbound)

			For co = 1 To 3
			;Get rid of the black lines by scaling up and down
			If scaletex = 1
			If t\u[co] > .5 Then t\u[co] = t\u[co]-.1
			If t\v[co] > .5 Then t\v[co] = t\v[co]-.1
			If t\u[co] < .5 Then t\u[co] = t\u[co]+.1
			If t\v[co] < .5 Then t\v[co] = t\v[co]+.1
			EndIf
			
			t\u[co] = (t\u[co]/t\size) + xsmall
			t\v[co] = (t\v[co]/t\size) + ysmall
			t\u[co] = t\u[co]/scale : t\v[co] = t\v[co] / scale

			VertexTexCoords t\surf,t\ver[co],t\u[co],t\v[co],0,1
			Next
		Exit
		EndIf
		Next
		If overlap = 0 Then Exit
	Next
	If dot1=1 And dot2=1 Then RuntimeError "Too Many Polys or too high detail, Increase Bound"
EndIf
Next
FreeBank tbbank
ElseIf detail > 0
For t.tris = Each tris
If t\hosttex = 0
t\xpos = xpos : t\ypos = ypos
	CopyRect(0,0,t\size,t\size,xpos,ypos,TextureBuffer(t\tex),TextureBuffer(bigtex))
	For co = 1 To 3
	;Get rid of the black lines by scaling up and down
	If scaletex = 1
	If t\u[co] > .5 Then t\u[co] = t\u[co]-.1
	If t\v[co] > .5 Then t\v[co] = t\v[co]-.1
	If t\u[co] < .5 Then t\u[co] = t\u[co]+.1
	If t\v[co] < .5 Then t\v[co] = t\v[co]+.1
	EndIf
	uvm# = t\u[co]
	uvn# = t\v[co]
	
	t\u[co] = (t\u[co]/t\size) + xsmall
	t\v[co] = (t\v[co]/t\size) + ysmall
	t\u[co] = t\u[co]/scale : t\v[co] = t\v[co] / scale
	uvm = t\u[co]
	uvn = t\v[co]
	VertexTexCoords t\surf,t\ver[co],t\u[co],t\v[co],0,1
	Next
	xpos = xpos + t\size
	xsmall = xsmall + move
	If xpos >= lightbound Then xpos = 0 : ypos = ypos + t\size:xsmall = 0:ysmall = ysmall +move
If ypos>lightbound Then RuntimeError "Too Many Polys, or too high detail, Increase Lightmap bound"
EndIf
Next
EndIf

;Finally share the lightmap
For t.tris = Each tris
If t\hosttex > 0
	For tr.tris = Each tris
	If tr\tex = t\hosttex
	scale# = lightbound/(t\size*t\size)
	lightmapbound = t\size*t\size
	xsmall# = tr\xpos/Float(lightmapbound) : ysmall# = tr\ypos/Float(lightmapbound)
		For co = 1 To 3
		;Get rid of the black lines by scaling up and down
		If scaletex = 1
		If t\u[co] > .5 Then t\u[co] = t\u[co]-.1
		If t\v[co] > .5 Then t\v[co] = t\v[co]-.1
		If t\u[co] < .5 Then t\u[co] = t\u[co]+.1
		If t\v[co] < .5 Then t\v[co] = t\v[co]+.1
		EndIf
		
		t\u[co] = (t\u[co]/t\size) + xsmall
		t\v[co] = (t\v[co]/t\size) + ysmall
	uvm = t\u[co]
	uvn = t\v[co]
		t\u[co] = t\u[co]/scale : t\v[co] = t\v[co] / scale
	uvm = t\u[co]
	uvn = t\v[co]

		VertexTexCoords t\surf,t\ver[co],t\u[co],t\v[co],0,1
		Next
	Exit
	EndIf
	Next
EndIf
If t\tex > 0 Then FreeTexture t\tex
Delete t
Next
	

Delete Each lightmapnode
TextureCoords bigtex,1
If luvsave <> ""
createluvs(mesh,luvsave,1)
EndIf
;FreeEntity copy
FreeEntity lightpivot : FreeEntity imagepivot
Return bigtex
End Function 

Function getNorm#(x1#,y1#,z1#,x2#,y2#,z2#,x3#,y3#,z3#,axis)
;Once again, thanks to elias and sswift
  	ux#= x1#- x2#
   	uy#= y1#- y2#
  	uz#= z1#- z2#
    vx#= x3#- x2#
    vy#= y3#- y2#
   	vz#= z3#- z2#
If axis = 1
	Return (uy#*vz#)-(vy#*uz#)
ElseIf axis = 2
	Return (uz#*vx#)-(vz#*ux#)
ElseIf axis = 3
	Return (ux#*vy#)-(vx#*uy#)
EndIf
End Function 

Function CreateLMLight.lmlight(x#,y#,z#,r#,g#,b#,range#,ltype=2)
l.lmlight = New lmlight
l\x = x : l\y = y : l\z = z
l\r =r : l\g = g : l\b =b
l\outer = 1:l\inner =1
l\range = range:l\lmtype = ltype
Return l
End Function

Function CreateLUVs(mesh,filename$,coordset=1)
file = WriteFile(filename+".luv")
For surfcount = 1 To CountSurfaces(mesh)
	surf = GetSurface(mesh,surfcount)
	For vercount = 0 To CountVertices(surf)-1
		WriteFloat(file,VertexU(surf,vercount,coordset))
		WriteFloat(file,VertexV(surf,vercount,coordset))
	Next
Next
CloseFile file
End Function

Function LoadLUVs(mesh,filename$,coordset=1)
file = ReadFile(filename)
For surfcount = 1 To CountSurfaces(mesh)
	surf = GetSurface(mesh,surfcount)
	For vercount = 0 To CountVertices(surf)-1
		u# = ReadFloat(file)
		v# = ReadFloat(file)
		VertexTexCoords surf,vercount,u,v,0,coordset
	Next
Next
CloseFile file
End Function

Function Unweld(mesh)
;Unweld a mesh, retaining all of its textures coords and textures
For surfcount = 1 To CountSurfaces(mesh)
	surf = GetSurface(mesh,surfcount)

	count = CountTriangles(surf)
	bank = CreateBank((15*count)*4)
	For tricount = 0 To count-1
	off = (tricount*15)*4
	in = TriangleVertex(surf,tricount,0)
	x# = VertexX(surf,in):y#=VertexY(surf,in):z#=VertexZ(surf,in)
	u# = VertexU(surf,in):v#=VertexV(surf,in)
	PokeFloat(bank,off,x)
	PokeFloat(bank,off+4,y)
	PokeFloat(bank,off+8,z)
	PokeFloat(bank,off+12,u)
	PokeFloat(bank,off+16,v)

	in = TriangleVertex(surf,tricount,1)
	x# = VertexX(surf,in):y#=VertexY(surf,in):z#=VertexZ(surf,in)
	u# = VertexU(surf,in):v#=VertexV(surf,in)
	PokeFloat(bank,off+20,x)
	PokeFloat(bank,off+24,y)
	PokeFloat(bank,off+28,z)
	PokeFloat(bank,off+32,u)
	PokeFloat(bank,off+36,v)

	in = TriangleVertex(surf,tricount,2)
	x# = VertexX(surf,in):y#=VertexY(surf,in):z#=VertexZ(surf,in)
	u# = VertexU(surf,in):v#=VertexV(surf,in)
	PokeFloat(bank,off+40,x)
	PokeFloat(bank,off+44,y)
	PokeFloat(bank,off+48,z)
	PokeFloat(bank,off+52,u)
	PokeFloat(bank,off+56,v)

	Next
	
	ClearSurface(surf,True,True)
	
	For tricount = 0 To count-1
	off = (tricount*15)*4
	x# = PeekFloat(bank,off)
	y# = PeekFloat(bank,off+4)
	z# = PeekFloat(bank,off+8)
	u# = PeekFloat(bank,off+12)
	v# = PeekFloat(bank,off+16)
	a = AddVertex(surf,x,y,z,u,v)
	x# = PeekFloat(bank,off+20)
	y# = PeekFloat(bank,off+24)
	z# = PeekFloat(bank,off+28)
	u# = PeekFloat(bank,off+32)
	v# = PeekFloat(bank,off+36)
	b = AddVertex(surf,x,y,z,u,v)
	x# = PeekFloat(bank,off+40)
	y# = PeekFloat(bank,off+44)
	z# = PeekFloat(bank,off+48)
	u# = PeekFloat(bank,off+52)
	v# = PeekFloat(bank,off+56)
	c = AddVertex(surf,x,y,z,u,v)
	AddTriangle(surf,a,b,c)
	Next
	FreeBank bank
Next
UpdateNormals mesh
Return mesh
End Function

Function LightmapTerrain(terr,r=0,g=0,b=0,detail=0,lum#=1)
width = TerrainSize(terr)
If detail = 0 Then detail = width
If detail < width Then detail = width
tex = CreateTexture(detail,detail,512)
vx# = GetMatElement(terr,0,0)
vy# = GetMatElement(terr,0,1)
vz# = GetMatElement(terr,0,2)
xscale# = Sqr(vx*vx+vy*vy+vz*vz)
vx# = GetMatElement(terr,1,0)
vy# = GetMatElement(terr,1,1)
vz# = GetMatElement(terr,1,2)
yscale# = Sqr(vx*vx+vy*vy+vz*vz)
vx# = GetMatElement(terr,2,0)
vy# = GetMatElement(terr,2,1)
vz# = GetMatElement(terr,2,2)
zscale# = Sqr(vx*vx+vy*vy+vz*vz)
scale# = 1
If detail < width
scale# = Float(detail)/Float(width)
EndIf
piv = CreatePivot():EntityPickMode piv,1
EntityRadius piv,5
light = CreatePivot()
SetBuffer TextureBuffer(tex)
ClsColor r,g,b : Cls : Color 0,0,0
LockBuffer()
For l.lmlight = Each lmlight
PositionEntity light,l\x,l\y,l\z
lrange# = l\range
falloffr# = l\r#/lrange#
falloffg# = l\g#/lrange#
falloffb# = l\b#/lrange#
For z = 0 To detail-1
	For x = 0 To detail-1
	xpos# = EntityX(terr) : ypos# = EntityY(terr) : zpos# = EntityZ(terr)
	movx# = (xpos+x*xscale)/scale
	movy# = (ypos+(TerrainHeight(terr,x,width-z)*yscale))/scale
	movz# = ((zpos+(width*zscale))-(z*zscale))/scale
		PositionEntity piv,movx,movy,movz
		xi# = EntityX(piv) : zi# = EntityZ(piv) : yi# = EntityY(piv)
		distx# = xi-l\x : disty# = yi-l\y : distz# = zi-l\z
		If LinePick(l\x,l\y,l\z,distx,disty,distz)=piv
		endist# = EntityDistance(piv,light)
		If endist <= lrange
			minusr# = falloffr*endist
			minusg# = falloffg*endist
			minusb# = falloffb*endist
			colr# = l\r - minusr
			colg# = l\g - minusg
			colb# = l\b - minusb
			colr = colr*lum : colg = colg*lum : colb = colb*lum
			argb = ReadPixelFast(x,z) And $FFFFFF
			colr = colr + (argb Shr 16 And %11111111)
			colg = colg + (argb Shr 8 And %11111111)
			colb = colb + (argb And %11111111)
			If colr < 0 Then colr = 0
			If colr > 255 Then colr = 255
			If colg < 0 Then colg = 0
			If colg > 255 Then colg = 255
			If colb < 0 Then colb = 0
			If colb > 255 Then colb = 255
			rgb = colb Or (colg Shl 8) Or (colr Shl 16)
			WritePixelFast(x,z,rgb)
			;Color colr,colg,colb
			;Rect x,z,1,1
		EndIf
		EndIf
	Next
Next
Next
UnlockBuffer()
SetBuffer BackBuffer()
ScaleTexture tex,detail,detail
FreeEntity piv : FreeEntity light
Return tex
End Function

Function TextureAlike(tex1,tex2)
;Check if textures are congruent
width1 = TextureWidth(tex1) : width2 = TextureWidth(tex2)
If width1 <> width2 Then Return 0
height1 = TextureHeight(tex1) : height2 = TextureHeight(tex2)
If height1 <> height2 Then Return 0
LockBuffer(TextureBuffer(tex1))
LockBuffer(TextureBuffer(tex2))
For y = 0 To height1-1
	For x = 0 To width1-1
	rgb1 = ReadPixelFast(x,y,TextureBuffer(tex1))
	rgb2 = ReadPixelFast(x,y,TextureBuffer(tex2))
	If rgb1 <> rgb2
	UnlockBuffer(TextureBuffer(tex1))
	UnlockBuffer(TextureBuffer(tex2))
	Return 0
	EndIf
	Next
Next
UnlockBuffer(TextureBuffer(tex1))
UnlockBuffer(TextureBuffer(tex2))
Return 1
End Function

Comments

None.

Code Archives Forum