Posted: 29th Sep 2013 14:28
Hi there, i made this 2d "lightmap" thing recently for a litle project im working on, thought id share it as i found it to be fairly effective and neat.



+ Code Snippet
function lightmap(x#,y#,ip,jp,cr,cg,cb)     ` x#/y# = position of your light , ip/jp = grid position of your light , cr,cg,cb = colors of the light
    range# = (cr+cg+cb)*2 : set vector2 v(6),x#,y#  ` range is calclated from the light strength , v(6) is used to store the light position
    draw to image 3                                 ` draw to some rendertarget with screen dimensions ( make image 3,screen width(),screen height() ) 
    a2setblendmode 2,1,1 : a2fillbox 0,0,w,h,rgb(0,0,0) ` set blendmode to normal , this line does the same as "cls" clears the rendertarget
    a2drawimage 4,x#,y#,0,512,512,range#/512.0,0,rgb(cr,cg,cb)      `paste the light image
    for i = 0 to a : for j = 0 to b                                 ` go through all the grid squares ( might be faster if you had a list with just the wall blocks )
        if n(i,j).w = 1 and squaredist(i*density#,j*density#,x#,y#) < range#*range#     ` if theres a wall and its within range of the light
            set vector2 v(0),i*density#,j*density#                          ` store the walls position in a vector
            subtract vector2 v(1),v(0),v(6)                         ` get the vetor from light to wall
            mina1# = 10000000 : mina2# = 10000000                   ` set initial values 
            for n = 1 to 4                                          ` corner vectors
                add vector2 v(2),v(1),corner(n) : l# = length vector2(v(2)) ` goes through all the corners of the wall to determine which 2 are at the "edge" of the square
                a# = dot product vector2(v(1),v(2))/l#          
                if a# < mina1# 
                    mina2# = mina1# : min2 = min1 : l2# = l1# : mina1# = a# : min1 = n : l1# = l#   `stores the 2 corners in min1 and min2 
                    else
                    if a# < mina2# then mina2# = a# : min2 = n : l2# = l#
                endif                           
            NEXT    
            if min1 > 0 and min2 > 0  then add vector2 v(2),v(0),corner(min1) : add vector2 v(3),v(0),corner(min2) 
            add vector2 v(4),v(1),corner(min1) : add vector2 v(5),v(1),corner(min2) 
            lenvec(v(4),v(4),range#-l1#+150) : lenvec(v(5),v(5),range#-l2#+150) : add vector2 v(4),v(2),v(4) : add vector2 v(5),v(3),v(5)   `cast vectors from the corners outward from the light far enough
            a2filltriangle x vector2(v(2)),y vector2(v(2)),x vector2(v(3)),y vector2(v(3)),x vector2(v(4)),y vector2(v(4)),rgb(0,0,0)       `draw triangles to fill the quad that is the shadow
            a2filltriangle x vector2(v(5)),y vector2(v(5)),x vector2(v(3)),y vector2(v(3)),x vector2(v(4)),y vector2(v(4)),rgb(0,0,0)
            a2fillbox (i+0.5)*density#+1,(j+0.5)*density#+1,(i-0.5)*density#-1,(j-0.5)*density#-1,rgb(0,0,0)    ` fill the square with a shadow
        endif
    next : next
    draw to image 5     `draw to the mainlightmap
    a2setblendmode 2,2,1    ` additive blending
    a2drawimage 3,0,0,0,0,0,1,0,rgb(255,255,255)    ` paste the generated lightmap onto the main lightmap
    a2setblendmode 2,1,1 : a2dot 0,0,512        `reset the blendmode to normal
    draw to bitmap 0        `draw to the main bitmap
endfunction


its part of a bigger code and needs a light image (attached in the next post )but the code is very heavily commented so you should be able to figure it out.
It requires Matr1x utils and advanced2d which can both be found on theese forums
Posted: 29th Sep 2013 14:33
the above image has 11 huge area lights all rendered every frame (and recalculated that is they can be moved dynamically) running at 30fps and theres also the game running in the background so performance is quite good. this post has the lightarea image attached which i use in the function.
Posted: 20th Nov 2013 23:06
Hi noobnerd,

It looks incredible, and great work.
What you have done is what i am looking for a long time and trying myself.
But could you help me to complete my demo.
I have found the missing functions

[edit]
I got it to work.
But having problems with the alpha/blendmode.
Here is the demo code (no media needed):


+ Code Snippet
set display mode 800,600,32,1
set image colorkey 0,0,0

make image 3,screen width(),screen height()
make image 5,screen width(),screen height()

make image 4,1024,1024
draw to image 4
for r=1 to 512
	a2fillcircle 512,512,512-r,rgb(r/2,r/2,r/2)
next r

dim v(6)
for i=0 to 6
	v(i)=i
	make vector2 v(i)
next i
//v(0) wall pos
//v(1) light to wall dist
//v(2) light to corner dist
//v(3) "
//v(4) light to left corner dist && shadow left corner
//v(5) light to right corner dist && shadow right corner
//v(6) light pos


make image 1,10,10
draw to image 1
a2fillbox 1,1,9,9,RGB(53,27,0)
a2box 0,0,10,10,RGB(0,0,0)

type testdata
	w
endtype

global a
global b
a=100
b=100
dim n(a,b) as testdata
for i=1 to a
	for j= 1 to b
		n(i,j).w=(rnd(100)=1)
	next j
next i

dim corner(4)
for i=1 to 4
	corner(i)=6+i
	make vector2 corner(i)
next i
set vector2 corner(1),5,5
set vector2 corner(2),5,-5
set vector2 corner(3),-5,5
set vector2 corner(4),-5,-5

global density#
density#=8

draw to bitmap 0
hide mouse
do
	lightmap(50,59,20,20,100)
	lightmap(mousex(),mousey(),100,20,20)
	a2drawimage 3,0,0,0,0,0,1,0,rgb(255,255,255) // draw the lightmap
	
	for i = 0 to a
		for j = 0 to b
			if n(i,j).w then a2drawimage 1,(i-0.5)*density#,(j-0.5)*density#,0,0,0,1,0,RGB(255,255,255) // draw the boxes
		next j
	next i
loop

function lightmap(x#,y#,cr,cg,cb)     ` x#/y# = position of your light , ip/jp = grid position of your light , cr,cg,cb = colors of the light
    range# = (cr+cg+cb)*2
	set vector2 v(6),x#,y#  ` range is calclated from the light strength , v(6) is used to store the light position
    draw to image 3                                 ` draw to some rendertarget with screen dimensions ( make image 3,screen width(),screen height() ) 
    a2setblendmode 2,1,1
	a2fillbox 0,0,w,h,rgb(0,0,0) ` set blendmode to normal , this line does the same as "cls" clears the rendertarget
    a2drawimage 4,x#,y#,0,512,512,range#/512.0,0,rgb(cr,cg,cb)      `paste the light image
    for i = 0 to a
		for j = 0 to b                                 ` go through all the grid squares ( might be faster if you had a list with just the wall blocks )
			if n(i,j).w = 1 and squaredist(i*density#,j*density#,x#,y#) < range#*range#     ` if theres a wall and its within range of the light
				set vector2 v(0),i*density#,j*density#                          ` store the walls position in a vector
				subtract vector2 v(1),v(0),v(6)                         ` get the vetor from light to wall
				mina1# = 10000000 : mina2# = 10000000                   ` set initial values 
				for n = 1 to 4                                          ` corner vectors
					add vector2 v(2),v(1),corner(n)
					l# = length vector2(v(2)) ` goes through all the corners of the wall to determine which 2 are at the "edge" of the square
					a# = dot product vector2(v(1),v(2))/l#          
					if a# < mina1#
						mina2# = mina1#
						min2 = min1
						l2# = l1#
						mina1# = a#
						min1 = n
						l1# = l#   `stores the 2 corners in min1 and min2 
                    else
						if a# < mina2#
							mina2# = a#
							min2 = n
							l2# = l#
						endif
					endif                            
				next n
				if min1 > 0 and min2 > 0
					add vector2 v(2),v(0),corner(min1)
					add vector2 v(3),v(0),corner(min2)
				endif
				add vector2 v(4),v(1),corner(min1)
				add vector2 v(5),v(1),corner(min2) 
				lenvec(v(4),v(4),range#-l1#+150)
				lenvec(v(5),v(5),range#-l2#+150)
				add vector2 v(4),v(2),v(4)
				add vector2 v(5),v(3),v(5)   `cast vectors from the corners outward from the light far enough
				a2filltriangle x vector2(v(2)),y vector2(v(2)),x vector2(v(3)),y vector2(v(3)),x vector2(v(4)),y vector2(v(4)),rgb(0,0,0)       `draw triangles to fill the quad that is the shadow
				a2filltriangle x vector2(v(5)),y vector2(v(5)),x vector2(v(3)),y vector2(v(3)),x vector2(v(4)),y vector2(v(4)),rgb(0,0,0)
				a2fillbox (i+0.5)*density#,(j+0.5)*density#,(i-0.5)*density#,(j-0.5)*density#,rgb(0,0,0)    ` fill the square with a shadow
			endif
		next j
	next i
	draw to image 5     `draw to the mainlightmap
	a2setblendmode 2,2,1    ` additive blending
	a2drawimage 3,0,0,0,0,0,1,0,rgb(255,255,255)    ` paste the generated lightmap onto the main lightmap
	a2setblendmode 2,1,1
	a2dot 0,0,512        `reset the blendmode to normal
	draw to bitmap 0        `draw to the main bitmap
endfunction

function squaredist(x1#,y1#,x2#,y2#)
    d# = (x1#-x2#)^2+(y1#-y2#)^2
endfunction d#

function lenvec(v,v1,len#)
    normalize vector2 v,v1
    multiply vector2 v,len#
endfunction

[/edit]

sorry for my English and thank you for sharing with us.