Removed mojo dependency from vector2d, and fixed Angle property (how has this EVER worked???) o_O

Strict

Private
Import functions

Public
'Summary: 2D Vector Class
Class Vector2D
	Field x:Float
	Field y:Float

	'summary: Constructor
	Method New(x:Float = 0, y:Float = 0)
		Self.x = x
		Self.y = y
	End

	'summary: Sets the vector by another vector
	Method Set:Vector2D( vector2:Vector2D )
		Self.x = vector2.x
		Self.y = vector2.y
		Return Self
	End

	'summary: Sets the vector by the supplied x and y
	Method Set:Vector2D(x:Float, y:Float )
		Self.x = x
		Self.y = y
		Return Self
	End

	'summary: Creates a copy of the Vector2D
	Method CloneVector:Vector2D()
		Return New Vector2D(x, y)
	End

	'summary: Swaps x and y around
	Method SwapXY:Void(x:Float, y:Float)
		Self.x = y
		Self.y = x
	End

	'summary: Makes x and y zero
	Method ZeroVector:Vector2D()
		Self.x = 0
		Self.y = 0
		Return Self
	End

	'summary: Is this vector zeroed?
	Method IsZero:Bool()
		If Self.x = 0 And Self.y = 0 Then
			Return True
		End
		Return False
	End

	'summary: Is the vector's length one?
	Method IsNormalized:Bool()
		If Length = 1.0 Then
			Return True
		End
		Return False
	End

	'summary: Does this vector have the same location as another?
	Method Equals:Bool(vector2d:Vector2D)
		If Self.x = vector2d.x And Self.y = vector2d.y Then
			Return True
		End
		Return False
	End

	'summary: Sets the length, which will change x and y but not the angle
	Method Length:Void(value:Float) Property
		Local angle:Float = Angle
		Self.x = Cos(angle) * value
		Self.y = Sin(angle) * value
		If Abs(Self.x) < 0.00000001 Then Self.x = 0
		If Abs(Self.y) < 0.00000001 Then Self.y = 0
	End

	'summary: Gets the length
	Method Length:Float() Property
		Return Sqrt(LengthSquared)
	End

	'summary: Gets the length squared
	Method LengthSquared:Float() Property
		Return Self.x * Self.x + Self.y * Self.y
	End

	'summary: Sets the angle
	Method Angle:Void(value:Float) Property
		Local len:Float = Length
		Self.x = Cos(value) * len
		Self.y = Sin(value) * len
	End

	'summary: Gets the angle
	Method Angle:Float() Property
		Return ATan2(Self.y, Self.x)
	End

	'summary: Set the vector's length to one
	Method Normalize:Vector2D()
		If Length = 0 Then
			Self.x = 1
			Return Self
		End
		Local len:Float = Length
		Self.x /= len
		Self.y /= len
		Return Self
	End

	'summary: Sets the vector's length to len
	Method Normalize:Vector2D(len:Float)
		Length = len
		Return Self
	End

	'summary: Sets the length under the given value
	Method Truncate:Vector2D(max:Float)
		Length = Min(max, Length)
		Return Self
	End

	'summary: Makes the vector face the opposite way
	Method Reverse:Vector2D()
		Self.x = -Self.x
		Self.y = -Self.y
		Return Self
	End

	'summary: Calculate the dot product of this vector and another
	Method DotProduct:Float(vector2D:Vector2D)
		Return Self.x * vector2D.x + Self.y * vector2D.y
	End

	'summary: Calculate the cross product of this and another vector
	Method CrossProd:Float(vector2D:Vector2D)
		Return Self.x * vector2D.y - Self.y * vector2D.x
	End

	'summary: Calculate angle between any two vectors.
	Function AngleBetween:Float(vector1:Vector2D, vector2:Vector2D)
		If (Not vector1.IsNormalized()) Then vector1 = vector1.CloneVector().Normalize()
		If (Not vector2.IsNormalized()) Then vector2 = vector2.CloneVector().Normalize()
		Return ACos(vector1.DotProduct(vector2))
	End

	'summary: Is the vector to the right or left of this one?
	Method Sign:Int(vector2:Vector2D)
		If Perpendicular.DotProduct(vector2) < 0
			Return -1
		End
		Return 1
	End

	'summary: Get the vector that is perpendicular
	Method Perpendicular:Vector2D() Property
		Return New Vector2D(-y, x)
	End

	'summary: Calculate between two vectors
	Method Distance:Float(vector2:Vector2D)
		Return Sqrt(DistSQ(vector2))
	End

	'summary: Calculate squared distance between vectors. Faster than distance.
	Method DistSQ:Float(vector2:Vector2D)
		Local dx:Float = vector2.x - Self.x
		Local dy:Float = vector2.y - Self.y
		Return dx * dx + dy * dy
	End

	'summary: Add a vector to this vector.
	Method Add:Vector2D(vector2:Vector2D)
		Self.x += vector2.x
		Self.y += vector2.y
		Return Self
	End

	'summary: Subtract a vector from this one.
	Method Subtract:Vector2D(vector2:Vector2D)
		Self.x -= vector2.x
		Self.y -= vector2.y
		Return Self
	End

	'summary: Mutiplies this vector by a scalar
	Method Multiply:Vector2D(scalar:Float)
		Self.x *= scalar
		Self.y *= scalar
		Return Self
	End

	'summary: Divide this vector by a scalar
	Method Divide:Vector2D(scalar:Float)
		Self.x /= scalar
		Self.y /= scalar
		Return Self
	End

	'summary: Turn this vector into a string.
	Method ToString:String()
		Return "Vector2D x:" + Self.x + ", y:" + Self.y
	End

	'summary: Calculate distance between two points - overload using x,y
	Method Distance:Float(x:float, y:float)
		Return CalcDistance(Self.x, Self.y, x, y)
	End
End

Strict
Import mojo
Import functions

'Summary: 2D Vector Class
Class Vector2D
	Field x:Float
	Field y:Float

	'summary: Constructor
	Method New(x:Float = 0, y:Float = 0)
		Self.x = x
		Self.y = y
	End

	'summary: Sets the vector by another vector
	Method Set:Vector2D( vector2:Vector2D )
		Self.x = vector2.x
		Self.y = vector2.y
		Return Self
	End

	'summary: Sets the vector by the supplied x and y
	Method Set:Vector2D(x:Float, y:Float )
		Self.x = x
		Self.y = y
		Return Self
	End

	'summary: Creates a copy of the Vector2D
	Method CloneVector:Vector2D()
		Return New Vector2D(x, y)
	End

	'summary: Swaps x and y around
	Method SwapXY:Void(x:Float, y:Float)
		Self.x = y
		Self.y = x
	End

	'summary: Makes x and y zero
	Method ZeroVector:Vector2D()
		Self.x = 0
		Self.y = 0
		Return Self
	End

	'summary: Is this vector zeroed?
	Method IsZero:Bool()
		If Self.x = 0 And Self.y = 0 Then
			Return True
		End
		Return False
	End

	'summary: Is the vector's length one?
	Method IsNormalized:Bool()
		If Length = 1.0 Then
			Return True
		End
		Return False
	End

	'summary: Does this vector have the same location as another?
	Method Equals:Bool(vector2d:Vector2D)
		If Self.x = vector2d.x And Self.y = vector2d.y Then
			Return True
		End
		Return False
	End

	'summary: Sets the length, which will change x and y but not the angle
	Method Length:Void(value:Float) Property
		Local angle:Float = Angle
		Self.x = Cos(angle) * value
		Self.y = Sin(angle) * value
		If Abs(Self.x) < 0.00000001 Then Self.x = 0
		If Abs(Self.y) < 0.00000001 Then Self.y = 0
	End

	'summary: Gets the length
	Method Length:Float() Property
		Return Sqrt(LengthSquared)
	End

	'summary: Gets the length squared
	Method LengthSquared:Float() Property
		Return Self.x * Self.x + Self.y * Self.y
	End

	'summary: Sets the angle
	Method Angle:Void(value:Float) Property
		Local len:Float = Length
		Self.x = Cos(value) * len
		Self.y = Sin(value) * len
	End

	'summary: Gets the angle
	Method Angle:Float() Property
		Return ATan2(Self.y, Self.y)
	End

	'summary: Set the vector's length to one
	Method Normalize:Vector2D()
		If Length = 0 Then
			Self.x = 1
			Return Self
		End
		Local len:Float = Length
		Self.x /= len
		Self.y /= len
		Return Self
	End

	'summary: Sets the vector's length to len
	Method Normalize:Vector2D(len:Float)
		Length = len
		Return Self
	End

	'summary: Sets the length under the given value
	Method Truncate:Vector2D(max:Float)
		Length = Min(max, Length)
		Return Self
	End

	'summary: Makes the vector face the opposite way
	Method Reverse:Vector2D()
		Self.x = -Self.x
		Self.y = -Self.y
		Return Self
	End

	'summary: Calculate the dot product of this vector and another
	Method DotProduct:Float(vector2D:Vector2D)
		Return Self.x * vector2D.x + Self.y * vector2D.y
	End

	'summary: Calculate the cross product of this and another vector
	Method CrossProd:Float(vector2D:Vector2D)
		Return Self.x * vector2D.y - Self.y * vector2D.x
	End

	'summary: Calculate angle between any two vectors.
	Function AngleBetween:Float(vector1:Vector2D, vector2:Vector2D)
		If (Not vector1.IsNormalized()) Then vector1 = vector1.CloneVector().Normalize()
		If (Not vector2.IsNormalized()) Then vector2 = vector2.CloneVector().Normalize()
		Return ACos(vector1.DotProduct(vector2))
	End

	'summary: Is the vector to the right or left of this one?
	Method Sign:Int(vector2:Vector2D)
		If Perpendicular.DotProduct(vector2) < 0
			Return -1
		End
		Return 1
	End

	'summary: Get the vector that is perpendicular
	Method Perpendicular:Vector2D() Property
		Return New Vector2D(-y, x)
	End

	'summary: Calculate between two vectors
	Method Distance:Float(vector2:Vector2D)
		Return Sqrt(DistSQ(vector2))
	End

	'summary: Calculate squared distance between vectors. Faster than distance.
	Method DistSQ:Float(vector2:Vector2D)
		Local dx:Float = vector2.x - Self.x
		Local dy:Float = vector2.y - Self.y
		Return dx * dx + dy * dy
	End

	'summary: Add a vector to this vector.
	Method Add:Vector2D(vector2:Vector2D)
		Self.x += vector2.x
		Self.y += vector2.y
		Return Self
	End

	'summary: Subtract a vector from this one.
	Method Subtract:Vector2D(vector2:Vector2D)
		Self.x -= vector2.x
		Self.y -= vector2.y
		Return Self
	End

	'summary: Mutiplies this vector by a scalar
	Method Multiply:Vector2D(scalar:Float)
		Self.x *= scalar
		Self.y *= scalar
		Return Self
	End

	'summary: Divide this vector by a scalar
	Method Divide:Vector2D(scalar:Float)
		Self.x /= scalar
		Self.y /= scalar
		Return Self
	End

	'summary: Turn this vector into a string.
	Method ToString:String()
		Return "Vector2D x:" + Self.x + ", y:" + Self.y
	End

	'summary: Draw vector
	Method Draw:Void(startX:Float, startY:Float, r:Int = 255, g:Int = 255, b:Int = 255)
		Local rgb:=GetColor()
		SetColor r, g, b
		DrawLine startX, startY, Self.x, Self.y
	End

	'summary: Calculate distance between two points - overload using x,y
	Method Distance:Float(x:float, y:float)
		Return CalcDistance(Self.x, Self.y, x, y)
	End
End


Color now supports alpha channel and Activate/Deactivate

Alpha support is kind of self explaining but the new Activate() and Deactivate()
method are pretty neat. Here's a very short example:

    Local color:Color = New Color(255, 0, 0)
    color.Activate()
    DrawText("foo in red", 100, 100)
    color.Deactivate()
    DrawText("foo in old color", 100, 120)

Think of it like a specializes version of PushMatrix() and PopMatrix() - they
can also be stacked.

Strict

Private

Import mojo.graphics

Public

Class Color
    Private

    Field oldColor:Color

    Public

    Field red:Float
    Field green:Float
    Field blue:Float
    Field alpha:Float

    Method New(red:Float, green:Float, blue:Float, alpha:Float=0)
        Self.red = red
        Self.green = green
        Self.blue = blue
        Self.alpha = alpha
    End

    Method Activate:Void()
        If Not oldColor Then oldColor = New Color(0, 0, 0, 0)

        Local colorStack:Float[] = GetColor()
        oldColor.red = colorStack[0]
        oldColor.green = colorStack[1]
        oldColor.blue = colorStack[2]
        oldColor.alpha = GetAlpha()

        Set(Self)
    End

    Method Deactivate:Void()
        If oldColor Then Set(oldColor)
    End

    Private

    Method Set:Void(color:Color)
        SetColor(color.red, color.green, color.blue)
        SetAlpha(color.alpha)
    End
End

Strict

Class Color
    Field red:Float
    Field green:Float
    Field blue:Float

    Method New(red:Float, green:Float, blue:Float)
        Self.red = red
        Self.green = green
        Self.blue = blue
    End
End


Minor tweak to 'PublicDataStream'.

Minor tweak to 'PublicDataStream'.

Strict

Public

' Preprocessor related:
' Nothing so far.

' Imports (Public):
Import regal.byteorder

' BRL:
Import brl.stream

' Imports (Private):
Private

Import regal.util

' BRL:
Import brl.databuffer

Public

' Classes:
Class PublicDataStream Extends Stream Implements IOnLoadDataComplete
	' Constant variable(s):
	Const NOLIMIT:Int = 0 ' -1

	' Defaults:
	Const Default_ResizeScalar:Float = 1.5 ' 2.0

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = False

	' Constructor(s) (Public):
	Method New(Size:Int, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		GenerateBuffer(Size)

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(B:DataBuffer, Length:Int, Offset:Int=0, Copy:Bool=False, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		If (Copy) Then
			GenerateBuffer(B)

			OwnsBuffer = True
		Else
			Self.Data = B
		Endif

		Self.Offset = Offset
		Self._Length = Length

		Self.RawSize = Length

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(Path:String, BigEndianStorage:Bool=Default_BigEndianStorage, Async:Bool=False)
		If (Not Async) Then
			OnLoadDataComplete(DataBuffer.Load(Path), Path)
		Else
			DataBuffer.LoadAsync(Path, Self)
		Endif

		Self.BigEndianStorage = BigEndianStorage
	End

	' Constructor(s) (Protected):
	Protected

	Method GenerateBuffer:Void(Size:Int)
		Self.Data = New DataBuffer(Size)
		Self.RawSize = Size
		Self.OwnsBuffer = True

		Return
	End

	' This will copy the contents of 'B' into an internally managed buffer.
	Method GenerateBuffer:Void(B:DataBuffer)
		GenerateBuffer(B.Length)

		B.CopyBytes(0, Data, 0, Data.Length)

		Return
	End

	Public

	' Destructor(s):
	Method FreeBuffer:Void(DiscardBuffer:Bool=True)
		If (Data <> Null) Then
			If (DiscardBuffer) Then
				Data.Discard()
			Endif

			Data = Null
		Endif

		OwnsBuffer = False

		RawSize = 0

		Return
	End

	Method Close:Void()
		FreeBuffer(OwnsBuffer)

		Self.Offset = 0
		Self._Position = 0

		Return
	End

	' Methods:
	Method Seek:Int(Input:Int=0)
		Self._Position = Clamp(Input, 0, DataLength)

		Return Self._Position
	End

	Method Reset:Void()
		Seek()
		ResetLength()

		Return
	End

	' This states if the number of bytes specified may be read safely.
	Method WillOverReach:Bool(Bytes:Int)
		Return ReadWillOverReach(Bytes)
	End

	Method ReadWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > Length)
	End

	Method WriteWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > DataLength) ' Length
	End

	Method ReadShort:Int()
		If (BigEndianStorage) Then
			Return NToHS(Super.ReadShort())
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndianStorage) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndianStorage) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		If (WillOverReach(Count)) Then
			Count = Self.BytesLeft
		Endif

		#Rem
			For Local Index:= 0 Until Count
				Buf.PokeByte(Offset+Index, Self.Data.PeekByte(Offset+Position+Index))
			Next
		#End

		Self.Data.CopyBytes(Self.DataOffset, Buf, Offset, Count)

		Self._Position += Count

		Return Count
	End

	Method Write:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		Local NewPosition:= (Count+Position)

		If (NewPosition > DataLength) Then
			If (ShouldResize) Then
				AutoResize(Count)
			Else
				Count = (DataLength-Position) ' Max(..., 0)
			Endif
		Endif

		Buf.CopyBytes(Offset, Self.Data, Self.DataOffset, Count)

		Self._Position = NewPosition

		SetLengthSafe(NewPosition)

		Return Count
	End

	' This transfers a raw segment of the internal buffer into 'S'. (Use at your own risk)
	Method TransferSegment:Void(S:Stream, Bytes:Int, Offset:Int)
		S.WriteAll(Data, Offset, Bytes)

		Return
	End

	' This may be used to transfer the internal data of this stream to another.
	Method TransferTo:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, Length, ReadOffset)

		Return
	End

	' This may be used to transfer what has already been read.
	Method TransferPastData:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, (Position-ReadOffset), ReadOffset)

		Return
	End

	' This may be used to read the number of bytes specified, from this stream then transfer it to another.
	Method TransferAmount:Void(S:Stream, Bytes:Int, Offset:Int=0)
		Local P:= S.Position

		TransferSegment(S, Bytes, (Self.Offset+Self.Position+Offset))

		S.Seek(P)

		Return
	End

	Method AutoResize:Bool(MinBytes:Int=0)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		Return Resize(Max(Int(Float(Data.Length) * ResizeScalar), MinBytes))
	End

	Method SmartResize:Bool(MinBytes:Int)
		If (MinBytes <= DataLength) Then
			Return True
		Endif

		Return Resize(MinBytes)
	End

	Method Resize:Bool(NewSize:Int, Force:Bool=False)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		If (SizeLimit <> NOLIMIT) Then
			If (NewSize > SizeLimit) Then
				If (Force) Then
					NewSize = Min(NewSize, SizeLimit)
				Else
					Return False
				Endif
			Endif
		Endif

		Data = ResizeBuffer(Data, NewSize, True, True, True)

		Return (Data <> Null)
	End

	Method SetLength:Void(Value:Int)
		Self._Length = Min(Value, DataLength)

		Return
	End

	Method SetLengthSafe:Void(Value:Int)
		SetLength(Max(Value, Self._Length))

		Return
	End

	' This sets the internal length to the current position.
	Method ClampToPosition:Void()
		SetLength(Position)

		Return
	End

	Method ResetLength:Void()
		SetLength(0)

		Return
	End

	' Call-backs:
	Method OnLoadDataComplete:Void(Data:DataBuffer, Path:String)
		If (Self.Data = Null) Then
			Self.Data = Data
			Self._Length = Data.Length
		Endif

		Return
	End

	' Properties (Public):

	' The internal I/O buffer.
	Method Data:DataBuffer() Property
		Return Self._Data
	End

	Method Eof:Int() Property
		Return (Position >= Length)
	End

	' The furthest this stream has written.
	Method Length:Int() Property
		Return Self._Length
	End

	' The number of bytes into the buffer this stream is.
	Method Position:Int() Property
		Return Self._Position
	End

	' The overall length of the 'Data' buffer. (Taking 'Offset' into account)
	Method RawSize:Int() Property
		Return Self._RawSize
	End

	' This will return the 'RawSize' property adjusted to the internal offset.
	Method DataLength:Int() Property
		Return (RawSize - Offset)
	End

	' The real position in the 'Data' buffer. (After 'Offset')
	Method DataOffset:Int() Property
		Return (Offset+Position)
	End

	' The number of bytes left in 'Data'. (Input only)
	Method BytesLeft:Int() Property
		Return Max(Length - Position, 0)
	End

	' This specifies the number of bytes left.
	' (Based on 'RawSize' and 'DataOffset'; use at your own risk)
	Method RealBytesLeft:Int() Property
		Return Max(RawSize - DataOffset, 0)
	End

	' This may be used for asynchronous buffer-loading.
	Method DataReady:Bool() Property
		Return (Data <> Null)
	End

	' Properties (Protected):
	Protected

	Method Data:Void(Input:DataBuffer) Property
		Self._Data = Input

		Return
	End

	Method RawSize:Void(Input:Int) Property
		Self._RawSize = Input

		Return
	End

	Public

	' Fields (Public):

	' Please use any corresponding properties when possible:

	' This acts as an internal offset inside the 'Data' buffer.
	Field Offset:Int

	' The (Local) position of the stream.
	Field _Position:Int

	' The furthest point we have written in the internal buffer.
	Field _Length:Int

	' The internal buffer's size-limit. (Used when resizing)
	Field SizeLimit:Int = NOLIMIT

	' A floating-point scalar used when a resize-operation occurs.
	' Numbers will be rounded as the hardware sees fit. (Usually rounds down)
	Field ResizeScalar:Float = Default_ResizeScalar

	' Booleans / Flags:

	' This may be used to toggle resizing the internal buffer.
	Field ShouldResize:Bool

	' This specifies if big-endian byte-order should be used.
	Field BigEndianStorage:Bool

	' This specifies if this stream owns the internal buffer.
	Field OwnsBuffer:Bool

	' Fields (Protected):
	Protected

	Field _Data:DataBuffer
	Field _RawSize:Int

	Public
End

Strict

Public

' Preprocessor related:
' Nothing so far.

' Imports (Public):
Import regal.byteorder

' BRL:
Import brl.stream

' Imports (Private):
Private

Import regal.util

' BRL:
Import brl.databuffer

Public

' Classes:
Class PublicDataStream Extends Stream Implements IOnLoadDataComplete
	' Constant variable(s):
	Const NOLIMIT:Int = 0 ' -1

	' Defaults:
	Const Default_ResizeScalar:Float = 1.5 ' 2.0

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = False

	' Constructor(s) (Public):
	Method New(Size:Int, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		GenerateBuffer(Size)

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(B:DataBuffer, Length:Int, Offset:Int=0, Copy:Bool=False, BigEndianStorage:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		If (Copy) Then
			GenerateBuffer(B)

			OwnsBuffer = True
		Else
			Self.Data = B
		Endif

		Self.Offset = Offset
		Self._Length = Length

		Self.RawSize = Length

		Self.BigEndianStorage = BigEndianStorage
		Self.ShouldResize = Resizable
		Self.SizeLimit = SizeLimit
	End

	Method New(Path:String, BigEndianStorage:Bool=Default_BigEndianStorage, Async:Bool=False)
		If (Not Async) Then
			OnLoadDataComplete(DataBuffer.Load(Path), Path)
		Else
			DataBuffer.LoadAsync(Path, Self)
		Endif

		Self.BigEndianStorage = BigEndianStorage
	End

	' Constructor(s) (Protected):
	Protected

	Method GenerateBuffer:Void(Size:Int)
		Self.Data = New DataBuffer(Size)
		Self.RawSize = Size

		Return
	End

	' This will copy the contents of 'B' into an internally managed buffer.
	Method GenerateBuffer:Void(B:DataBuffer)
		GenerateBuffer(B.Length)

		B.CopyBytes(0, Data, 0, Data.Length)

		Return
	End

	Public

	' Destructor(s):
	Method FreeBuffer:Void(DiscardBuffer:Bool=True)
		If (Data <> Null) Then
			If (DiscardBuffer) Then
				Data.Discard()
			Endif

			Data = Null
		Endif

		OwnsBuffer = False

		RawSize = 0

		Return
	End

	Method Close:Void()
		FreeBuffer(OwnsBuffer)

		Self.Offset = 0
		Self._Position = 0

		Return
	End

	' Methods:
	Method Seek:Int(Input:Int=0)
		Self._Position = Clamp(Input, 0, DataLength)

		Return Self._Position
	End

	Method Reset:Void()
		Seek()
		ResetLength()

		Return
	End

	' This states if the number of bytes specified may be read safely.
	Method WillOverReach:Bool(Bytes:Int)
		Return ReadWillOverReach(Bytes)
	End

	Method ReadWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > Length)
	End

	Method WriteWillOverReach:Bool(Bytes:Int)
		Return (Position+Bytes > DataLength) ' Length
	End

	Method ReadShort:Int()
		If (BigEndianStorage) Then
			Return NToHS(Super.ReadShort())
		Endif

		Return Super.ReadShort()
	End

	Method ReadInt:Int()
		If (BigEndianStorage) Then
			Return NToHL(Super.ReadInt())
		Endif

		Return Super.ReadInt()
	End

	Method ReadFloat:Float()
		If (BigEndianStorage) Then
			Return NToHF(Super.ReadInt())
		Endif

		Return Super.ReadFloat()
	End

	Method WriteShort:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteShort(HToNS(Value))
		Else
			Super.WriteShort(Value)
		Endif

		Return
	End

	Method WriteInt:Void(Value:Int)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNL(Value))
		Else
			Super.WriteInt(Value)
		Endif

		Return
	End

	Method WriteFloat:Void(Value:Float)
		If (BigEndianStorage) Then
			Super.WriteInt(HToNF(Value))
		Else
			Super.WriteFloat(Value)
		Endif

		Return
	End

	Method Read:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		If (WillOverReach(Count)) Then
			Count = Self.BytesLeft
		Endif

		#Rem
			For Local Index:= 0 Until Count
				Buf.PokeByte(Offset+Index, Self.Data.PeekByte(Offset+Position+Index))
			Next
		#End

		Self.Data.CopyBytes(Self.DataOffset, Buf, Offset, Count)

		Self._Position += Count

		Return Count
	End

	Method Write:Int(Buf:DataBuffer, Offset:Int, Count:Int)
		Local NewPosition:= (Count+Position)

		If (NewPosition > DataLength) Then
			If (ShouldResize) Then
				AutoResize(Count)
			Else
				Count = (DataLength-Position) ' Max(..., 0)
			Endif
		Endif

		Buf.CopyBytes(Offset, Self.Data, Self.DataOffset, Count)

		Self._Position = NewPosition

		SetLengthSafe(NewPosition)

		Return Count
	End

	' This transfers a raw segment of the internal buffer into 'S'. (Use at your own risk)
	Method TransferSegment:Void(S:Stream, Bytes:Int, Offset:Int)
		S.WriteAll(Data, Offset, Bytes)

		Return
	End

	' This may be used to transfer the internal data of this stream to another.
	Method TransferTo:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, Length, ReadOffset)

		Return
	End

	' This may be used to transfer what has already been read.
	Method TransferPastData:Void(S:Stream, Offset:Int=0)
		Local ReadOffset:= (Self.Offset+Offset)

		TransferSegment(S, (Position-ReadOffset), ReadOffset)

		Return
	End

	' This may be used to read the number of bytes specified, from this stream then transfer it to another.
	Method TransferAmount:Void(S:Stream, Bytes:Int, Offset:Int=0)
		Local P:= S.Position

		TransferSegment(S, Bytes, (Self.Offset+Self.Position+Offset))

		S.Seek(P)

		Return
	End

	Method AutoResize:Bool(MinBytes:Int=0)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		Return Resize(Max(Int(Float(Data.Length) * ResizeScalar), MinBytes))
	End

	Method SmartResize:Bool(MinBytes:Int)
		If (MinBytes <= DataLength) Then
			Return True
		Endif

		Return Resize(MinBytes)
	End

	Method Resize:Bool(NewSize:Int, Force:Bool=False)
		If (Not OwnsBuffer) Then
			Return False
		Endif

		If (SizeLimit <> NOLIMIT) Then
			If (NewSize > SizeLimit) Then
				If (Force) Then
					NewSize = Min(NewSize, SizeLimit)
				Else
					Return False
				Endif
			Endif
		Endif

		Data = ResizeBuffer(Data, NewSize, True, True, True)

		Return (Data <> Null)
	End

	Method SetLength:Void(Value:Int)
		Self._Length = Min(Value, DataLength)

		Return
	End

	Method SetLengthSafe:Void(Value:Int)
		SetLength(Max(Value, Self._Length))

		Return
	End

	' This sets the internal length to the current position.
	Method ClampToPosition:Void()
		SetLength(Position)

		Return
	End

	Method ResetLength:Void()
		SetLength(0)

		Return
	End

	' Call-backs:
	Method OnLoadDataComplete:Void(Data:DataBuffer, Path:String)
		If (Self.Data = Null) Then
			Self.Data = Data
			Self._Length = Data.Length
		Endif

		Return
	End

	' Properties (Public):

	' The internal I/O buffer.
	Method Data:DataBuffer() Property
		Return Self._Data
	End

	Method Eof:Int() Property
		Return (Position >= Length)
	End

	' The furthest this stream has written.
	Method Length:Int() Property
		Return Self._Length
	End

	' The number of bytes into the buffer this stream is.
	Method Position:Int() Property
		Return Self._Position
	End

	' The overall length of the 'Data' buffer. (Taking 'Offset' into account)
	Method RawSize:Int() Property
		Return Self._RawSize
	End

	' This will return the 'RawSize' property adjusted to the internal offset.
	Method DataLength:Int() Property
		Return (RawSize - Offset)
	End

	' The real position in the 'Data' buffer. (After 'Offset')
	Method DataOffset:Int() Property
		Return (Offset+Position)
	End

	' The number of bytes left in 'Data'. (Input only)
	Method BytesLeft:Int() Property
		Return Max(Length - Position, 0)
	End

	' This specifies the number of bytes left.
	' (Based on 'RawSize' and 'DataOffset'; use at your own risk)
	Method RealBytesLeft:Int() Property
		Return Max(RawSize - DataOffset, 0)
	End

	' This may be used for asynchronous buffer-loading.
	Method DataReady:Bool() Property
		Return (Data <> Null)
	End

	' Properties (Protected):
	Protected

	Method Data:Void(Input:DataBuffer) Property
		Self._Data = Input

		Return
	End

	Method RawSize:Void(Input:Int) Property
		Self._RawSize = Input

		Return
	End

	Public

	' Fields (Public):

	' Please use any corresponding properties when possible:

	' This acts as an internal offset inside the 'Data' buffer.
	Field Offset:Int

	' The (Local) position of the stream.
	Field _Position:Int

	' The furthest point we have written in the internal buffer.
	Field _Length:Int

	' The internal buffer's size-limit. (Used when resizing)
	Field SizeLimit:Int = NOLIMIT

	' A floating-point scalar used when a resize-operation occurs.
	' Numbers will be rounded as the hardware sees fit. (Usually rounds down)
	Field ResizeScalar:Float = Default_ResizeScalar

	' Booleans / Flags:

	' This may be used to toggle resizing the internal buffer.
	Field ShouldResize:Bool

	' This specifies if big-endian byte-order should be used.
	Field BigEndianStorage:Bool

	' This specifies if this stream owns the internal buffer.
	Field OwnsBuffer:Bool

	' Fields (Protected):
	Protected

	Field _Data:DataBuffer
	Field _RawSize:Int

	Public
End