Code archives/Graphics/2d lightning
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
taken from the german blitz site and modified to support color | |||||
SuperStrict Type TLightning Const MIN_SEG_LENGTH:Int = 20 'Minimum segment length Const MIN_SEG_BRANCH_LENGTH:Int = 5 'Minimum segment length on branches Const BRANCH_ANGLE_MOD:Int = 40 'Max angle difference between mainlightning and branches Field glowred:Int = 100 Field glowgreen:Int = 100 Field glowblue:Int = 255 Field segments:TList = CreateList() 'List of segments of the mainlightning Field branches:TList = CreateList() 'List of branches Field branches2:TList = CreateList() 'Branches of the segmentized branches Field generations:Int = 4 'Iterations of seperation of the mainlightning Field offset:Int = 10 'Segments offset Rem bbdoc:Creates a new lightning from x1, y1 to x2, y2. Public Function End Rem Function getInstance:TLightning(x1:Int, y1:Int, x2:Int, y2:Int) Local instance:TLightning = New TLightning instance.setStartEndPoint(x1, y1, x2, y2) Return instance End Function Rem bbdoc:Changes the color of the lightning Public Function End Rem Method SetGlowColor(r:Int, g:Int, b:Int) glowred = r glowgreen = g glowblue = b End Method Rem bbdoc:Sets new start- and endpoint coordinates. Public Method End Rem Method setStartEndPoint(x1:Int, y1:Int, x2:Int, y2:Int) 'Create segment from x1,y1 to x2,y2 Local startpoint:TPoint = TPoint.getInstance(x1, y1) Local endpoint:TPoint = TPoint.getInstance(x2, y2) Local firstSeg:TSegment = TSegment.getInstance(startpoint, endpoint) 'Remove old lightning Self.segments.Clear() Self.branches.Clear() Self.branches2.Clear() 'Create the lightning out of the first segment Self.segments.AddFirst(firstSeg) Self.segmentize(Self.segments, Self.generations, Self.offset) Self.branches = Self.createBranches(Self.segments) Self.segmentize(Self.branches, Self.generations - 1, Self.offset - 7, True) Self.branches2 = Self.createBranches(Self.branches) Self.segmentize(Self.branches2, Self.generations - 3, Self.offset - 7, True) End Method Rem bbdoc:Draws the lightning (Scale must be set to 1.0/1.0) Public Method End Rem Method draw() SetBlend(ALPHABLEND) 'Branch2 Glow Self.setDrawings(0.4, 3, True) Self.drawSegments(Self.branches2) 'Branches2 Self.setDrawings(0.5, 1) Self.drawSegments(Self.branches2) 'Branch Glow Self.setDrawings(0.5, 5, True) Self.drawSegments(Self.branches) 'Branches Self.setDrawings(0.6, 1) Self.drawSegments(Self.branches) 'Glow Paths Self.setDrawings(0.09, 20, True) Self.drawSegments(Self.segments) Self.setDrawings(0.25, 11, True) Self.drawSegments(Self.segments) Self.setDrawings(0.55, 6, True) Self.drawSegments(Self.segments) 'Original Paths SetColor(255, 255, 255) SetAlpha(0.45) Local counter:Int = 0 For Local seg:TSegment = EachIn Self.segments counter:+1 Local thickness:Float = 0.3 * Float(Self.segments.Count() - counter) If thickness < 2.0 Then thickness = 2.0 SetLineWidth(thickness) DrawLine(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y) Next End Method Rem bbdoc:Private Method (don__COMMENT18__ Draws a list of segments. End Rem Method drawSegments(givenList:TList) Local realLineWidth:Float = GetLineWidth() For Local seg:TSegment = EachIn givenList Local lineWidth:Float = realLineWidth/2 Local ps1point:TPoint Local ps2point:TPoint Local pe1point:TPoint Local pe2point:TPoint Local lastSeg:TSegment = seg.lastSegment Local nextSeg:TSegment = seg.nextSegment Local tvec:TPoint = seg.endpoint.sub(seg.startpoint) Local tvecn:TPoint = tvec.normalize() Local tnorm:TPoint = tvec.normalize().normal() If (lastSeg=Null) Then ps1point = seg.startpoint.add(tnorm.mult(lineWidth)) ps2point = seg.startpoint.add(tnorm.mult(-lineWidth)) Else Local lvec:TPoint = lastSeg.endpoint.sub(lastSeg.startpoint) Local lnorm:TPoint = lvec.normalize().normal() ps1point = seg.startpoint.add(lnorm.mult(lineWidth)) ps2point = seg.startpoint.add(lnorm.mult(-lineWidth)) EndIf If (nextSeg=Null) Then lineWidth = lineWidth/2 EndIf pe1point = seg.endpoint.add(tnorm.mult(-lineWidth)) pe2point = seg.endpoint.add(tnorm.mult(lineWidth)) Local corners:Float[] = [ps1point.x,ps1point.y,ps2point.x,ps2point.y,pe1point.x,pe1point.y,pe2point.x,pe2point.y] DrawPoly(corners) Next End Method Rem bbdoc:Private Method (don__COMMENT19__ Sets the color to "Glow-Color" End Rem Method setDrawings(alpha:Float, lineThickness:Float, isGlowing:Byte = False) SetColor(255, 255, 255) If isGlowing Then SetColor(glowred, glowgreen, glowblue) SetAlpha(alpha) SetLineWidth(lineThickness) End Method Rem bbdoc:Private Method (don__COMMENT20__ Splits a line (segment) into two lines, which are moved by maxOffset at one point (start or endpoint of the line). End Rem Method segmentize(givenList:TList, generations:Int, offset:Int, isBranch:Byte = False) 'Preconditions If givenList.IsEmpty() Then Return Local minLength:Int = TLightning.MIN_SEG_LENGTH If isBranch Then minLength = TLightning.MIN_SEG_BRANCH_LENGTH 'Start segmentation For Local i:Int = 1 To generations Local workList:TList = givenList.Copy() For Local seg:TSegment = EachIn workList 'Check if the segments length allows a split into 2 segments If TDistance.pointToPoint(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y) >= minLength Then 'The original segment is obsolete, as we replace it with 2 new ones Local lastSegment:TSegment = seg.lastSegment Local nextSegment:TSegment = seg.nextSegment givenList.Remove(seg) Local midpoint:TPoint = seg.getMidPoint() Local randomAngle:Int = 90 If Rand(1, 2) = 1 Then randomAngle = -90 'Move the midpoint midpoint.x:+(Cos(seg.angle + randomAngle) * offset) midpoint.y:+(Sin(seg.angle + randomAngle) * offset) 'Add the new segments Local seg1:TSegment = TSegment.getInstance(seg.startpoint, midpoint) Local seg2:TSegment = TSegment.getInstance(midpoint, seg.endpoint) seg1.lastSegment = lastSegment seg1.nextSegment = seg2 seg2.lastSegment = seg1 seg2.nextSegment = nextSegment If (lastSegment<>Null) Then lastSegment.nextSegment = seg1 If (nextSegment<>Null) Then nextSegment.lastSegment = seg2 givenList.AddLast(seg1) givenList.AddLast(seg2) End If Next Next End Method Rem bbdoc:Private Method (don__COMMENT27__ Creates a branch at every segments startpoint. End Rem Method createBranches:TList(givenList:TList) 'Preconditions If givenList.IsEmpty() Then Return Null Local returnList:TList = New TList Local i:Int = 0 For Local seg:TSegment = EachIn givenList i:+1 Local branchAngle:Int = seg.angle + Rand(-TLightning.BRANCH_ANGLE_MOD, TLightning.BRANCH_ANGLE_MOD) Local branchLength:Int = Float((Rnd(1.0, 3.0) * TDistance.pointToPoint(seg.startpoint.x, seg.startpoint.y, seg.endpoint.x, seg.endpoint.y))) * Float((Float(i) / Float(givenList.Count()))) Local branchX:Int = seg.endpoint.x + Cos(branchAngle) * branchLength Local branchY:Int = seg.endpoint.y + Sin(branchAngle) * branchLength Local branchpoint:Tpoint = TPoint.getInstance(branchX, branchY) Local branch:TSegment = TSegment.getInstance(seg.endpoint, branchpoint) returnList.AddLast(branch) Next Return returnList End Method End Type Rem bbdoc:Defines a linesegment between two points in 2D space. End Rem Type TSegment Field startpoint:TPoint Field endpoint:TPoint Field angle:Int Field lastSegment:TSegment Field nextSegment:TSegment Rem bbdoc:Constructor. End Rem Function getInstance:TSegment(startpoint:TPoint, endpoint:TPoint) Local instance:TSegment = New TSegment instance.startpoint = startpoint instance.endpoint = endpoint instance.angle = ATan2((endpoint.y - startpoint.y), (endpoint.x - startpoint.x)) Return instance End Function Rem bbdoc:Returns a point on the mid of the segment. End Rem Method getMidPoint:TPoint() Local midpoint:Tpoint = New TPoint midpoint.x = (startpoint.x + endpoint.x)/2 midpoint.y = (startpoint.y + endpoint.y)/2 Return midpoint End Method End Type Rem bbdoc:2D Point helper class. End Rem Type TPoint Field x:Float Field y:Float Rem bbdoc:Constructor. End Rem Function getInstance:TPoint(x:Float, y:Float) Local instance:TPoint = New TPoint instance.x = x instance.y = y Return instance End Function Rem bbdoc:Addiert zwei TPoints zusammen (Vektorrechnung) End Rem Method add:TPoint(other:TPoint) Return getInstance(x+other.x,y+other.y) End Method Rem bbdoc:Subtrahiert zwei TPoints (Vektorrechnung) End Rem Method sub:TPoint(other:TPoint) Return getInstance(x-other.x,y-other.y) End Method Rem bbdoc:Multipliziert einen TPoint mit einem Skalar (Vektorrechnung) End Rem Method mult:TPoint(f:Float) Return getInstance(x*f,y*f) End Method Rem bbdoc:Liefert die Laenge des Vektors (Vektorrechnung) End Rem Method length:Float() Return Sqr(x*x+y*y) End Method Rem bbdoc:Normalisiert den Vektor (Vektorrechnung) End Rem Method normalize:TPoint() Return mult(1.0/length()) End Method Rem bbdoc:Erstellt einen Normalvektor (Vektorrechnung) End Rem Method normal:TPoint() Return getInstance(y,-x) End Method Rem bbdoc:Liefert das Skalarprodukt zweier Vektoren (Vektorrechnung) End Rem Method dot:Float(other:TPoint) Return (x*other.x+y*other.y) End Method End Type Rem bbdoc:Helper tool to calculate the distance between 2 points in a 2D environment. End Rem Type TDistance Abstract Rem bbdoc:Berechnet die Distanz zwischen 2 Punkten. End Rem Function pointToPoint:Double(x1:Double, y1:Double, x2:Double, y2:Double) Return Sqr(TDistance.quad(x2 - x1) + TDistance.quad(y2 - y1)) End Function Rem bbdoc:Quadriert einen Integer. End Rem Function quad:Double(v:Double) Return (v * v) End Function End Type 'Test 'Include "Lightning.bmx" Graphics 1024, 768 Global blitz:TLightning = TLightning.getInstance(100, 100, 500, 500) blitz.setGlowColor(255,0,0) Global oldMausX:Int Global oldMausY:Int SetClsColor(10, 10, 10) Repeat Cls If MouseX() <> oldMausX Or MouseY() <> oldMausY Then oldMausX = MouseX() oldMausY = MouseY() blitz.setStartEndPoint(100, 100, MouseX(), MouseY()) End If blitz.draw() Flip Until AppTerminate() |
Comments
| ||
Cool! |
Code Archives Forum