Rem bbdoc: noddybox.vectorgfx EndRem Module noddybox.vectorgfx ModuleInfo "Framework: 2D Vector Graphics classes" ModuleInfo "Copyright: Public Domain" ModuleInfo "Author: Ian Cowburn" ModuleInfo "Version: $Revision$" ' $Id$ Strict Import brl.linkedlist Import brl.math Import brl.endianstream Import brl.max2d Import noddybox.vector Import noddybox.algorithm Rem bbdoc: Defines a method for drawing vector lines EndRem Type TVectorGfxLineStyle Abstract Rem bbdoc: Draws a vector line. returns: The or'ed mask of all collision IDs overwritten in @colmap by this line. about: This routine must draw a line from @x1, @y1 to @x2, @y2 using the colour @r,@g,@b. @id must be written into the collision map @colmap. EndRem Method Draw:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, id:Int, colmap:TVectorGfxCollisionMap) Abstract End Type Rem bbdoc: Set to use solid lines for drawing. about: This mode draws vector lines as solid colour lines using the current alpha, and is the default mode. EndRem Function VectorGfxSetSolid() Static.linedraw=New LineSolid End Function Rem bbdoc: Set to use alpha lines for drawing. about: This mode draws vector lines using a @line_alpha for the lines, except for the end-points drawn with @end_alpha. EndRem Function VectorGfxSetAlpha(line_alpha:Double,end_alpha:Double) Local l:LineAlpha=New LineAlpha l.la=line_alpha l.ea=end_alpha Static.linedraw=l End Function Rem bbdoc: Set to use thick lines for drawing. about: This mode draws vector lines using solid line, surrounded by points of alpha @line_alpha. EndRem Function VectorGfxSetThickAlpha(line_alpha:Double) Local l:ThickAlpha=New ThickAlpha l.a=line_alpha Static.linedraw=l End Function Rem bbdoc: Set to use a custom drawing method. EndRem Function VectorGfxSetCustom(linedraw:TVectorGfxLineStyle) Static.linedraw=linedraw End Function Rem bbdoc: Defines a vector graphics collision map. about: Collisions in the library a defined using a bitmask (allowing 32 collision masks). Note that with the way that lines are drawn in an object you are likely about: to receive collisions for the IDs used by the lines in the object. EndRem Type TVectorGfxCollisionMap Field width:Int Field height:Int Field xoff:Int Field yoff:Int Field data:Int[,] Rem bbdoc: Create a collision map. returns: The created collision map. about: @width and @height are the size of the collision map. EndRem Function Create:TVectorGfxCollisionMap(width:Int, height:Int) Local o:TVectorGfxCollisionMap=New TVectorGfxCollisionMap o.width=width o.height=height o.xoff=0 o.yoff=0 o.data=New Int[width,height] Return o End Function Rem bbdoc: Set the offset of the collision map. about: @x and @y are the offsets into the co-ordinate space where the collision map lives. EndRem Method SetOffset(x:Int, y:Int) xoff=x yoff=y End Method Rem bbdoc: Set a collision point. returns: The current collision mask for that point, or zero if the point is out of the map's range. about: @x and @y are the co-ordinates (in the objects co-ordinate space, not the collision map space) EndRem Method SetCollision(x:Int, y:Int, id:Int) If x=xoff+width Or y=yoff+height Return 0 EndIf x:-xoff y:-yoff Local cur:Int=data[x,y] data[x,y]:|id Return cur End Method Rem bbdoc: Clear the collision map EndRem Method Clear() For Local x:Int=0 Until width For Local y:Int=0 Until height data[x,y]=0 Next Next End Method End Type Rem bbdoc: Defines a 2D vector graphics object EndRem Type TVectorGfxObject Rem bbdoc: The points making up this object EndRem Field points:TVectorGfxPoint[] Rem bbdoc: The lines making up this object EndRem Field lines:TVectorGfxLine[] Rem bbdoc: The X co-ordinate of the object EndRem Field x:Int Rem bbdoc: The Y co-ordinate of the object EndRem Field y:Int Rem bbdoc: The angle of the object, as degrees*10. Must be within the range 0-3599 inclusive. EndRem Field ang:Int Field rotated:TVectorGfxPoint[] Rem bbdoc: Creates a new empty object returns: The created object. EndRem Method New() points=Null lines=Null rotated=Null x=0 y=0 ang=0 End Method Rem bbdoc: Sets the points for this object about: @pa is an array of points for this object. EndRem Method SetPoints(pa:Object[]) points=New TVectorGfxPoint[pa.length] For Local f:Int=0 Until pa.length points[f]=TVectorGfxPoint(pa[f]) Next End Method Rem bbdoc: Sets the lines for this object. about: @la is the array of lines for this object. EndRem Method SetLines(la:Object[]) lines=New TVectorGfxLine[la.length] For Local f:Int=0 Until la.length lines[f]=TVectorGfxLine(la[f]) Next End Method Rem bbdoc: A line's adjusted co-ordinates. returns: The rotated points (in object co-ordinates) of the line. about: @i is the index of the line to return the points for. about: Calling it before drawing then will cause runtime errors. EndRem Method AdjustedCoords:TVectorGfxPoint[](i:Int) Local p:TVectorGfxPoint[]=New TVectorGfxPoint[2] Local l:TVectorGfxLine=lines[i] p[0]=rotated[l.i1] p[1]=rotated[l.i2] Return p End Method Rem bbdoc: A line's normal. returns: The normal of the selected line. about: @i is the index of the line to return the normal of. This will return the normal due to the rotation of the object after the object is drawn. about: Calling it before drawing then will cause runtime errors. EndRem Method Normal:TVector(i:Int) Local l:TVectorGfxLine=lines[i] Local v:TVector=TVector.Create(rotated[l.i2].y-rotated[l.i1].y,rotated[l.i1].x-rotated[l.i2].x) v.Normalise() Return v End Method Rem bbdoc: Loads the object from the supplied @filename. returns: The loaded object, or null if the file could not be opened. EndRem Function Load:TVectorGfxObject(filename:String) Local s:TStream=ReadStream(filename) If Not s Return Null EndIf s=LittleEndianStream(s) Local o:TVectorGfxObject=New TVectorGfxObject o.x=s.ReadInt() o.y=s.ReadInt() o.ang=s.ReadInt() Local l:TList=CreateList() Local i:Int=s.ReadInt() For Local f=0 Until i l.AddLast(TVectorGfxPoint.Load(s)) Next o.SetPoints(l.ToArray()) l.Clear() i=s.ReadInt() For Local f=0 Until i l.AddLast(TVectorGfxLine.Load(s)) Next o.SetLines(l.ToArray()) s.Close() Return o End Function Rem bbdoc: Saves the object to the supplied @filename. EndRem Method Save(filename:String) Local s:TStream=WriteStream(filename) If Not s Return Null EndIf s=LittleEndianStream(s) s.WriteInt(x) s.WriteInt(y) s.WriteInt(ang) s.WriteInt(points.length) For Local p:TVectorGfxPoint=EachIn points p.Save(s) Next s.WriteInt(lines.length) For Local l:TVectorGfxLine=EachIn lines l.Save(s) Next s.Close() End Method Rem bbdoc: Draw the object. returns: A bitmask of collisions. about: Draws the object. @colmap cannot be null - use a small collision map instead if you're uninterested in collisions. EndRem Method Draw:Int(colmap:TVectorGfxCollisionMap) Local col:Int=0 rotated=New TVectorGfxPoint[points.length] For Local f:Int=0 Until points.length Local p:TAlgoPoint=DoRotate(points[f].x,points[f].y,ang) rotated[f]=TVectorGfxPoint.Create(p.x,p.y) Next For Local l:TVectorGfxLine=EachIn lines col:|Static.linedraw.draw(x+rotated[l.i1].x,y+rotated[l.i1].y,x+rotated[l.i2].x,y+rotated[l.i2].y,l.r,l.g,l.b,l.id,colmap) Next Return col End Method End Type Rem bbdoc: Defines a point EndRem Type TVectorGfxPoint Field x:Int Field y:Int Rem bbdoc: Create a point. returns: The created point. about: @x and @y are the co-ordinates of the point. EndRem Function Create:TVectorGfxPoint(x:Int, y:Int) Local o:TVectorGfxPoint=New TVectorGfxPoint o.x=x o.y=y Return o End Function Rem bbdoc: This is for internal library use. EndRem Function Load:TVectorGfxPoint(s:TStream) Local o:TVectorGfxPoint o=New TVectorGfxPoint o.x=s.ReadInt() o.y=s.ReadInt() Return o End Function Rem bbdoc: This is for internal library use. EndRem Method Save(s:TStream) s.WriteInt(x) s.WriteInt(y) End Method End Type Rem bbdoc: Defines a line EndRem Type TVectorGfxLine Field i1:Int Field i2:Int Field id:Int Field r:Int Field g:Int Field b:Int Rem bbdoc: Create a line. returns: The created line. about: @i1 and @i2 are the indexes into the point list. @r, @g and @b is the line's colour. @id is the collision map mask for the line. EndRem Function Create:TVectorGfxLine(i1:Int, i2:Int, r:Int, g:Int, b:Int, id:Int) Local o:TVectorGfxLine=New TVectorGfxLine o.i1=i1 o.i2=i2 o.r=r o.g=g o.b=b o.id=id Return o End Function Rem bbdoc: This is for internal library use. EndRem Function Load:TVectorGfxLine(s:TStream) Local o:TVectorGfxLine o=New TVectorGfxLine o.i1=s.ReadInt() o.i2=s.ReadInt() o.r=s.ReadInt() o.g=s.ReadInt() o.b=s.ReadInt() o.id=s.ReadInt() Return o End Function Rem bbdoc: This is for internal library use. EndRem Method Save:TVectorGfxLine(s:TStream) s.WriteInt(i1) s.WriteInt(i2) s.WriteInt(r) s.WriteInt(g) s.WriteInt(b) s.WriteInt(id) End Method End Type Private Type Static Global linedraw:TVectorGfxLineStyle Function Init() linedraw=New LineSolid End Function End Type Type LineSolid Extends TVectorGfxLineStyle Method Draw:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, id:Int, colmap:TVectorGfxCollisionMap) Local mask:Int=0 Local lp:TList=DoLine(x1,y1,x2,y2) SetColor(r,g,b) For Local p:TAlgoPoint=EachIn lp mask:|colmap.SetCollision(p.x,p.y,id) Plot(p.x,p.y) Next Return mask End Method End Type Type LineAlpha Extends TVectorGfxLineStyle Field la:Double Field ea:Double Method Draw:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, id:Int, colmap:TVectorGfxCollisionMap) Local mask:Int=0 Local lp:TList=DoLine(x1,y1,x2,y2) Local p:TAlgoPoint Local a:Double=GetAlpha() SetColor(r,g,b) SetAlpha(ea) p=TAlgoPoint(lp.RemoveFirst()) mask:|colmap.SetCollision(p.x,p.y,id) Plot(p.x,p.y) If lp.Count()=0 Return id EndIf p=TAlgoPoint(lp.RemoveLast()) mask:|colmap.SetCollision(p.x,p.y,id) Plot(p.x,p.y) SetAlpha(la) For Local p:TAlgoPoint=EachIn lp mask:|colmap.SetCollision(p.x,p.y,id) Plot(p.x,p.y) Next SetAlpha(a) Return mask End Method End Type Type ThickAlpha Extends TVectorGfxLineStyle Field a:Double Method PlotPoint(x,y) SetAlpha(a) DrawLine(x-1,y-1,x+1,y-1,False) DrawLine(x+1,y-1,x+1,y+1,False) DrawLine(x+1,y+1,x-1,y+1,False) DrawLine(x-1,y+1,x-1,y-1,False) SetAlpha(1.0) Plot(x,y) End Method Method Draw:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, id:Int, colmap:TVectorGfxCollisionMap) Local mask:Int=0 Local lp:TList=DoLine(x1,y1,x2,y2) SetColor(r,g,b) For Local p:TAlgoPoint=EachIn lp mask:|colmap.SetCollision(p.x,p.y,id) PlotPoint(p.x,p.y) Next Return mask End Method End Type Static.Init()