' Copyright (c) 2006 Ian Cowburn ' ' Permission is hereby granted, free of charge, to any person obtaining a copy of ' this software and associated documentation files (the "Software"), to deal in ' the Software without restriction, including without limitation the rights to ' use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies ' of the Software, and to permit persons to whom the Software is furnished to do ' so, subject to the following conditions: ' ' The above copyright notice and this permission notice shall be included in all ' copies or substantial portions of the Software. ' ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ' SOFTWARE. ' ' $Id$ ' Rem bbdoc: noddybox.vectorgfx EndRem Module noddybox.vectorgfx ModuleInfo "Framework: 2D Vector Graphics classes" ModuleInfo "Copyright: Ian Cowburn -- released under the MIT License" ModuleInfo "Author: Ian Cowburn" ModuleInfo "Version: $Revision$" Import brl.linkedlist Import brl.math Import brl.endianstream Import brl.max2d Import noddybox.vector Import noddybox.algorithm Rem bbdoc: Wibble about: Wobble EndRem Rem bbdoc: Defines a method for drawing vector lines about: For an example of creating a line drawing routine view the LineSolid type in the private section of this module. EndRem Type TVectorGfxLineStyle Abstract Rem bbdoc: Draws a vector line using IDs and @TVectorGfxCollisionMap method. returns: The or'ed mask of all collision IDs overwritten in @colmap by this line, or zero if @colmap is null. about: This routine must draw a line from @x1, @y1 to @x2, @y2 using the colour @r,@g,@b. about: @id, @obj and @line must be written into the collision map @colmap if @colmap is not null and @actor is false. about: If @colmap is set and @actor true, then collisions must be returned but no points written into the collision map. about: If @colmap is set, @actor is true and @list is not null then any collisions should be recorded into this list about: (no requirement for duplicate checking). EndRem Method LineToCollisionMap:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, id:Int, obj:TVectorGfxObject, line:Int, colmap:TVectorGfxCollisionMap, actor:Int, list:TList) Abstract Rem bbdoc: Draws a vector line using the point list method. about: This routine must draw a line from @x1, @y1 to @x2, @y2 using the colour @r,@g,@b. about: If list is not null, then the points drawn must be stored in the list as @TVectorGfxPoint objects. about: For an example of creating a line drawing routine view the LineSolid type in the private section of this module. EndRem Method LineToPointList:Int(x1:Int, y1:Int, x2:Int, y2:Int, r:Int, g:Int, b:Int, list:TList) 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 a custom drawing method. EndRem Function VectorGfxSetCustom(linedraw:TVectorGfxLineStyle) Static.linedraw=linedraw End Function Rem bbdoc: Defines a point in the vector graphics collision map. EndRem Type TVectorGfxCollision Rem bbdoc: The X co-ordinate of this collision (in the object co-ordinate space). EndRem Field x:Int Rem bbdoc: The Y co-ordinate of this collision (in the object co-ordinate space). EndRem Field y:Int Rem bbdoc: The collision masks at this point. EndRem Field mask:Int Rem bbdoc: The last vector object that wrote at this point. EndRem Field obj:TVectorGfxObject Rem bbdoc: The index of the line in the last vector object that wrote at this point. EndRem Field line:Int Function Create:TVectorGfxCollision(x:Int, y:Int, mask:Int, obj:TVectorGfxObject, line:Int) Local o:TVectorGfxCollision=New TVectorGfxCollision o.x=x o.y=y o.mask=mask o.obj=obj o.line=line Return o End Function End Type Rem bbdoc: Defines a vector graphics collision map. about: Collisions using this method in the library are defined using a bitmask (allowing 32 collision masks). EndRem Type TVectorGfxCollisionMap Field width:Int Field height:Int Field xoff:Int Field yoff:Int Field data:TVectorGfxCollision[,] 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.Clear() 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: Get a collision point. returns: The collision point, or null if nothing drawn there. about: @x and @y are the co-ordinates (in the objects co-ordinate space, not the collision map space) EndRem Method GetCollision:TVectorGfxCollision(x:Int, y:Int) If x=xoff+width Or y=yoff+height Return Null Else Return data[x-xoff,y-yoff] EndIf 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:Int(x:Int, y:Int, id:Int, obj:TVectorGfxObject, line:Int) If x=xoff+width Or y=yoff+height Return 0 EndIf Local ax:Int=x-xoff Local ay:Int=y-yoff Local cur:TVectorGfxCollision=data[ax,ay] If Not cur cur=TVectorGfxCollision.Create(x,y,id,obj,line) data[ax,ay]=cur Else cur.mask:|id cur.obj=obj cur.line=line EndIf Return cur.mask End Method Rem bbdoc: Clear the collision map EndRem Method Clear() data=New TVectorGfxCollision[width,height] 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 minimum X co-ordinate of the object. Only valid after a call to SetPoints(). EndRem Field min_x:Int Rem bbdoc: The maximum X co-ordinate of the object. Only valid after a call to SetPoints(). EndRem Field max_x:Int Rem bbdoc: The minimum Y co-ordinate of the object. Only valid after a call to SetPoints(). EndRem Field min_y:Int Rem bbdoc: The maximum Y co-ordinate of the object. Only valid after a call to SetPoints(). EndRem Field max_y:Int Rem bbdoc: The width of the object. Only valid after a call to SetPoints(). EndRem Field width:Int Rem bbdoc: The height of the object. Only valid after a call to SetPoints(). EndRem Field height:Int Rem bbdoc: The angle of the object, as degrees*10. Must be within the range 0-3599 inclusive. EndRem Field ang:Int Rem bbdoc: The scale of the object. EndRem Field scale:Double 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 min_x=9999999 min_y=9999999 max_x=-9999999 max_y=-9999999 width=0 height=0 ang=0 scale=1 End Method Rem bbdoc: Clones this object about: Returns a copy of this object, with its own copy of the line and points. EndRem Method Clone:TVectorGfxObject() Local o:TVectorGfxObject=New TVectorGfxObject o.x=x o.y=y o.min_x=min_x o.min_y=min_y o.max_x=max_x o.max_y=max_y o.width=width o.height=height o.ang=ang o.scale=scale o.SetPoints(points) o.SetLines(lines) Return o 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]) min_x=Min(min_x,points[f].x) min_y=Min(min_y,points[f].y) max_x=Max(max_x,points[f].x) max_y=Max(max_y,points[f].y) Next width=max_x-min_x height=max_y-min_y 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: Whether a point is inside the object returns: True if the point lies inside the object. The object is assumed to be a closed polygon for this test. about: @cx, @cy is the point to test. about: This routine is based on code from comp.graphics.algorithms FAQ 2.03 EndRem Method IsInside:Int(cx:Int, cy:Int) If rotated=Null Return False EndIf Local cross:Int=False For Local l:TVectorGfxLine=EachIn lines Local x1:Int=x+rotated[l.i1].x Local y1:Int=y+rotated[l.i1].y Local x2:Int=x+rotated[l.i2].x Local y2:Int=y+rotated[l.i2].y If ((((y1<=cy) And (cy