Examples



This is by no means, an exhaustive reference of all functions available to plugins.

*All examples assume a Dogwaffle object has been created.

* Note, VB.Net will require a change in data types. VB5/6 uses 32 bit longs, and 16 bit Integers. VB.Net uses 64 bit longs, and 32 bit integers. Usage of VB5/6 is assumed in this document except where specified. See your VB.net migration documentation for full details.


The Basics and Image Related

Creating a Dogwaffle object

Getting a copy of the current image

Sending an image back to Project Dogwaffle

Getting the width and height of the current image

Working with an alpha channel

The progress bar and hourglass pointers

Creating a new image

Undos

Buffer locks


Brush Related

Getting the current custom brush image

Create a new custom brush

Getting the current custom brush’s width and height

 

Colors, Gradients, and Wells

Getting the primary and secondary colors

Getting a copy of the gradient

Setting colors in the color wells


Animation Related

Playing and going to a specific frame 

Creating a new animation

Processing an animation


Input Boxes and Special Functions

File Open and Save requesters

Message boxes

Question boxes

Value boxes    

The Temp Directory

Reading and Writing memory

Image Processing dll Functions

Utility dll functions

Wallpaper and Styles



Creating a Dogwaffle object


All functions available to plugins are evoked through a Dogwaffle object.

 

'create a dogwaffle object

Dim Dogwaffle As Object

Set Dogwaffle = CreateObject("Dogwaffle.Dogwaffle_Class")


Getting a copy of the current image


'allocate the main buffers

Dim MainRBuffer() As Byte

Dim MainGBuffer() As Byte

Dim MainBBuffer() As Byte

Dim MainaBuffer() As Byte

'get the buffers

MainRBuffer() = Dogwaffle.Dog_GetRBuffer

MainGBuffer() = Dogwaffle.Dog_GetGBuffer

MainBBuffer() = Dogwaffle.Dog_GetBBuffer

MainaBuffer() = Dogwaffle.Dog_GetaBuffer


Sending an image back to Project Dogwaffle


'send the buffers back to dogwaffle.

Dogwaffle.Dog_SetRbuffer MainRBuffer()

Dogwaffle.Dog_SetGbuffer MainGBuffer()

Dogwaffle.Dog_SetBbuffer MainBBuffer()


'and refresh the screen

Dogwaffle.Dog_Refresh


Getting the width and height of the current image


'get the width and height of the buffer

dim tw as long, th as long

th = Dogwaffle.Dog_BufferHeight

tw = Dogwaffle.Dog_BufferWidth


Creating a new image (new buffer)


Dim MyFilename As String

MyFilename = "My new buffer"

tw = 640

th = 480

Dogwaffle.Dog_NewBuffer CInt(tw), CInt(th)


'Give the new buffer a name

'and update dogwaffles internal filename string

Dogwaffle.Dog_RenameBuffer (MyFilename)

Dogwaffle.Dog_NewFilename (MyFilename)


Working with an alpha channel


Dim alphabits As Long

alphabits = Dogwaffle.Dog_GetAlphabits


If alphabits is 0, then the alpha is active. 

You can achieve alpha mixing like this. ((r * a) + (r2 * (255-a))) \ 255


‘r2,g2,b2 should be defined.

      r = MainRBuffer(x, y)

      g = MainGBuffer(x, y)

      b = MainBBuffer(x, y)

        If alphabits = 0 Then

        a = MainaBuffer(x, y)

        a2 = 255 - a

            r = ((r * a) + (r2 * a2)) \ 255

            g = ((g * a) + (g2 * a2)) \ 255

            b = ((b * a) + (b2 * a2)) \ 255

        End If 


The progress bar

 

ole.gif

As your plugin executes code, you can keep the user informed about the progress with the plugin progress bar. It is called with a Single value between 0 and 100, like this:


Dim Value As Single

Value = 50

Dogwaffle.Dog_SetProgress Value


Always remember to reset the progress bar when finished.


Dogwaffle.Dog_SetProgress 0


Changing the mouse pointer to an hourglass pointer


Dogwaffle.Dog_ChangePointer (11)


Change it back


Dogwaffle.Dog_RestorePointer


Saving an undo


You are not required to save an undo when running a plugin, since one is automatically saved, however, the function is available.

 

Dogwaffle.Dog_SaveUndo


Buffer locks


A buffer can be locked to keep the user from making changes while a plugin is in progress. You must unlock a buffer once you have finished with it.


 

Dogwaffle.Dog_Lock

 

Unlock buffer

 

Dogwaffle.Dog_Unlock

 

The locking mechanism keeps a count of buffer locks. If a plugin should happen to crash before unlocking the buffer, it may be required to perform a hard unlock.

 

Dogwaffle.Dog_UnlockHard





Custom Brushes


Getting the current custom brush image


If the width of the current custom brush is 0, then there is no custom brush currently defined. See Getting the current custom brush’s width and height


'dim the buffers

Dim MainRBuffer() As Byte

Dim MainGBuffer() As Byte 

Dim MainBBuffer() As Byte

Dim MainABuffer() As Byte


'get the buffers from dogwaffle

MainRBuffer() = Dogwaffle.Dog_GetBrushRBuffer

MainGBuffer() = Dogwaffle.Dog_GetBrushGBuffer

MainBBuffer() = Dogwaffle.Dog_GetBrushBBuffer

MainABuffer() = Dogwaffle.Dog_GetBrushABuffer


Getting the current custom brush’s width and height


Dim tw As Long, th As Long

tw = Dogwaffle.Dog_GetBrushWidth

th = Dogwaffle.Dog_GetBrushHeight


Creating a new custom brush


To create a new custom brush, first you initialize it by calling CreateEmptyBrush, then you send your own imagery defined in a set of byte arrays.


Dim tw As Long, th As Long


'create a brush at 100x100 pixel...

tw = 100

th = 100


'dim the buffers

ReDim BrushRBuffer(tw, th) As Byte

ReDim BrushGBuffer(tw, th) As Byte

ReDim BrushBBuffer(tw, th) As Byte

'brushes have a 'key' channel, similar to an alpha channel.

ReDim BrushABuffer(tw, th) As Byte


'create a new, empty brush. This must be done before sending any imagery.

Dogwaffle.Dog_CreateEmptyBrush tw, th


'Do something to fill in the brush arrays here...

For y = 0 To th - 1

 For x = 0 To tw - 1

  BrushRBuffer(x, y) = Rnd * 255

  BrushGBuffer(x, y) = Rnd * 255

  BrushBBuffer(x, y) = Rnd * 255

  BrushABuffer(x, y) = Rnd * 255

 Next

Next


'send the brush buffers to dogwaffle.

Dogwaffle.Dog_SetBrushRBuffer BrushRBuffer()

Dogwaffle.Dog_SetBrushGBuffer BrushGBuffer()

Dogwaffle.Dog_SetBrushBBuffer BrushBBuffer()

Dogwaffle.Dog_SetBrushABuffer BrushABuffer()


'can optionally activate the brush tool.

Dogwaffle.Dog_ActivateCustomBrush


'Also optional, but refreshes things like the brush key panel when the brush changes.

Dogwaffle.Dog_Refresh_BrushDisplays




User input


There are several pre-defined requesters (dialog boxes) that plugins can access. They include file requesters, text and value input, and message boxes.



File Open and Save requesters


Presents a file dialog to the user


MyFilename = Dogwaffle.Dog_RequestFile_Open("Select a file to open", "", "BMP|*.bmp")

MyFilename = Dogwaffle.Dog_RequestFile_Save("Select a file to save", "", "BMP|*.bmp")


A result of “” means the requester was canceled.


Message boxes

examples.gifMessage box

Presents a message to the user


Dogwaffle.dog_MessageBox "Done"


Question boxes

examples1.gifQuestion box

Presents the user with a choice of Ok or Cancel.


Dummy = Dogwaffle.Dog_QuestionBox("Shall I proceed?")

If Dummy = 2 Then Exit Sub 

 

*Messages with multiple lines can be created by instering chr$(13) into the message string for message and question boxes.


MyString = "The first line of text" + Chr$(13) + "The second line of text"

Dummy = Dogwaffle.Dog_QuestionBox(MyString)


Value boxes 

valuebox.gifValue box

Retrieves a value from the user within a specific range.


Value = Dogwaffle.Dog_ValueBox("Enter new value ", 1, 100)

If Value = -1 Then Exit Sub


A variation on this allows a caption and a default value to be applied to the window


Value = Dogwaffle.Dog_ValueBox2("Enter new value ", "Caption", 1, 100, 10)






The Primary and Secondayr Colors


Getting the primary or secondary colors


Dim tempcolor

tempcolor = Dogwaffle.Dog_getPrimaryColor

‘tempcolor = Dogwaffle.Dog_getSecondaryColor

r = tempcolor And &HFF& 'the extra '&' coerces it into a long. VB is 16 bit by default. Go figure.

g = (tempcolor And &HFF00&) \ 256

b = (tempcolor And &HFF0000) \ 65536


The gradient


Getting a copy of the gradient


An example. This displays the gradient on a picturebox control with scalemode set to pixel.


Dim MyArray() As Byte

ReDim MyArray(255, 2)

MyArray = Dogwaffle.Dog_GetGradient(Dogwaffle.Dog_GetGradientIndex)


h = Picture1.ScaleWidth


For X = 0 To 255

            r = MyArray(X, 0)

            g = MyArray(X, 1)

            b = MyArray(X, 2)

            Picture1.Line (X, 0)-(X, h), RGB(r, g, b)

Next




Wells


Setting colors in the color wells


'example, put random colors in the color wells


Dim MyWell() As Long

ReDim MyWell(63) '64 colors

For n = 0 To 63

MyWell(n) = RGB(Rnd * 255, Rnd * 255, Rnd * 255)

Next


'send it to dogwaffle

Dogwaffle.Dog_SetWells MyWell




Animation 


Goto a specific frame


Dogwaffle.dog_gotoframe frame


Getting the number of frames in an animation


TotalFrames = Dogwaffle.dog_GetTotalFrames


Play and stop animation playback


Dogwaffle.dog_PlayAnimation


Dogwaffle.dog_StopAnimation


Create a new animation


An example of asking the user how many frames of a new animation to create.


Dim Value As Long

Value = Val(InputBox("Create new animation", "Frame count", "30"))

If Value <= 1 Then Exit Sub

Dogwaffle.Dog_CreateAnim Value

Dogwaffle.Dog_ShowScrub 0, Dogwaffle.Dog_GetTotalFrames

                                                                                                            

Processing the frames of an animation


To process the frames of an animation, simply go to each frame with a call to Dog_GotoFrame, then use the regular buffer functions to retrieve and set the RGB buffers. When finished with every frame, return to the first frame with a final call to Dog_GotoFrame.


'allocate the main buffers

Dim n As Long

Dim MainRBuffer() As Byte

Dim MainGBuffer() As Byte

Dim MainBBuffer() As Byte

Dim MainaBuffer() As Byte

Dim tw As Long, th As Long, x As Long, y As Long

Dim Begin_Frame As Long, End_Frame As Long


th = Dogwaffle.Dog_BufferHeight

tw = Dogwaffle.Dog_BufferWidth


Begin_Frame = 0

End_Frame = Dogwaffle.dog_GetTotalFrames - 1


For n = Begin_Frame To End_Frame


Dogwaffle.Dog_GotoFrame n


'Get the buffers for the current frame

MainRBuffer() = Dogwaffle.Dog_GetRBuffer

MainGBuffer() = Dogwaffle.Dog_GetGBuffer

MainBBuffer() = Dogwaffle.Dog_GetBBuffer

MainaBuffer() = Dogwaffle.Dog_GetaBuffer


'Process the buffer in some way.

For y = 0 To th-1

  For x = 0 To tw-1

    MainRBuffer(x, y) = 255 - MainRBuffer(x, y)

    MainGBuffer(x, y) = 255 - MainGBuffer(x, y)

    MainBBuffer(x, y) = 255 - MainBBuffer(x, y)

  Next

Next


'Send it back

Dogwaffle.Dog_SetRbuffer MainRBuffer

Dogwaffle.Dog_SetGbuffer MainGBuffer

Dogwaffle.Dog_SetBbuffer MainBBuffer


'should probably use progress bar

Next


Dogwaffle.Dog_GotoFrame Begin_Frame

Dogwaffle.dog_Refresh




Special Functions


The Temp Directory


Project Dogwaffle maintains a Temp directory for temporary storage. You may use this directory for your own use, and you are required to clean up after yourself. Here’s how to get the pathname for the Temp directory.


Dim tempdir As String

tempdir = Dogwaffle.Dog_GetTempDir


Here’s an example that lets the user explore the temp directory.


Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Const SW_SHOWNORMAL = 1


Sub Main()

Dim Dogwaffle As Object, Dim tempdir As String

Set Dogwaffle = CreateObject("Dogwaffle.Dogwaffle_Class")

tempdir = Dogwaffle.Dog_GetTempDir

ShellExecute 0, vbNullString, "", vbNullString, tempdir, SW_SHOWNORMAL

End Sub


Reading and Writing memory


These functions are exported by Drpaint.dll.


There are some structures in the Windows OS that require direct access to memory, such as Dibs. The following functions are exported for your convenience, but use them with caution. 


'send by ref and returns a pointer in a long

Declare Function GetAddressByte Lib "Drpaint.dll" (ByRef MyArray As Byte) As Long

Declare Function GetAddressWord Lib "Drpaint.dll" (ByRef MyArray As Integer) As Long

Declare Function GetAddressLong Lib "Drpaint.dll" (ByRef MyArray As Long) As Long

'

Declare Sub WriteByte Lib "Drpaint.dll" (ByVal Address As Long, ByVal val As Byte)

Declare Sub WriteWord Lib "Drpaint.dll" (ByVal Address As Long, ByVal val As Integer)

Declare Sub WriteLong Lib "Drpaint.dll" (ByVal Address As Long, ByVal val As Long)

'

Declare Function ReadByte Lib "Drpaint.dll" (ByVal Address As Long) As Byte

Declare Function ReadWord Lib "Drpaint.dll" (ByVal Address As Long) As Integer

Declare Function ReadLong Lib "Drpaint.dll" (ByVal Address As Long) As Long




General Image Processing


These are not members of the plugin interface, but are functions exported from drfilter.dll for general image processing


Convolution Kernel


This function performs a convolution kernel filter on an image contained in an byte array, and stores it in another array.


Declare Function Convolve8 Lib "drfilter.dll" (source As Byte, dest As Byte, ByVal W As Integer, ByVal h As Integer, ByVal v1 As Single, ByVal v2 As Single, ByVal v3 As Single, ByVal v4 As Single, ByVal v5 As Single, ByVal v6 As Single, ByVal v7 As Single, ByVal v8 As Single, ByVal v9 As Single, ByVal vsum As Single, ByVal mean As Integer) As Long


Example of using a convolution kernel to emboss an image. In this case, it’s a greyscale image; Apply once for each buffer of a color image.

With different kernels, you could also apply blur, edge detect, sharpen, and other effects.


'do an emboss

v1 = -1 : v2 = -1 : v3 = 0

v4 = -1 : v5 = 0 : v6 = 1

v7 = 0 : v8 = 1 : v9 = 1

vsum = 1

dummy = Convolve8(TempBuffer(0, 0), Mainbuffer(0, 0), TempWidth, TempHeight, v1, v2, v3, v4, v5, v6, v7, v8, v9, vsum, 128)


Sobel Edge Detection


Sobel Edge detection is an important component of many of the routines used to mimic traditional pencil drawing, such as ‘Loose and Sketchy’. This implementation uses a floating point buffer, so a Dogwaffle buffer needs to be converted to single before use, and then back.


Declare Function SobelF Lib "drfilter.dll" (Source As Single, Dest As Single, ByVal W As Long, ByVal h As Long) As Long


Channel value


This function multiplies all the values in a byte array by a specified value. You could use this once for each R,G, and B channels to make a color adjustment filter, or to adjust the value of a greyscale image.


Declare Function ChannelValue Lib "drfilter.dll" (source As Byte, dest As Byte, abuf As Byte, ByVal alphabits As Byte, ByVal W As Integer, ByVal h As Integer, ByVal value As Single) As Long


Noise


These functions apply color or value noise to all the arrays of an image.


Declare Sub ApplyValueNoise Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal alphabits As Byte, ByVal W As Long, ByVal h As Long, ByVal value As Long)


Declare Sub ApplyColorNoise Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal alphabits As Byte, ByVal W As Long, ByVal h As Long, ByVal value As Long)


Blue Screen and Green Screen


The blue and greenscreen functions require a lookup table of 256 bytes that define a ramp.


Declare Sub FastBluescreen Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal W As Long, ByVal h As Long, rbuf2 As Byte, gbuf2 As Byte, bbuf2 As Byte, rbuf3 As Byte, gbuf3 As Byte, bbuf3 As Byte, lut As Byte, ByVal Fakeblue As Long, ByVal alphabits As Long)


Declare Sub FastGreenscreen Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal W As Long, ByVal h As Long, rbuf2 As Byte, gbuf2 As Byte, bbuf2 As Byte, rbuf3 As Byte, gbuf3 As Byte, bbuf3 As Byte, lut As Byte, ByVal Fakegreen As Long, ByVal alphabits As Long)


Threshold


Converts an image to black or white, with the median being a specified value.


Declare Sub FastThreshold Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, rbuf2 As Byte, gbuf2 As Byte, bbuf2 As Byte, ByVal W As Long, ByVal h As Long, ByVal Threshold As Long, ByVal Invert As Long)


Median


Declare Sub FastMedian Lib "drfilter.dll" (uRbuf As Byte, ugBuff As Byte, ubBuff As Byte, Rbuff As Byte, Gbuff As Byte, BBuff As Byte, abuf As Byte, ByVal alphabits As Byte, ByVal W As Long, ByVal h As Long)


Jitter


Declare Sub FastJitter Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal W As Long, ByVal h As Long, rbuf2 As Byte, gbuf2 As Byte, bbuf2 As Byte, ByVal value As Long, ByVal alphabits As Long)


Posterize


Declare Sub FastPosterize Lib "drfilter.dll" (rbuf As Byte, gbuf As Byte, bbuf As Byte, abuf As Byte, ByVal W As Long, ByVal h As Long, rbuf2 As Byte, gbuf2 As Byte, bbuf2 As Byte, ByVal value As Long, ByVal alphabits As Long)


Tint


Declare Sub FastTint Lib "drfilter.dll" (ByRef rbuffer As Byte, ByRef GBuffer As Byte, ByRef bbuffer As Byte, ByRef destrbuffer As Byte, ByRef destgbuffer As Byte, ByRef destbbuffer As Byte, ByVal r As Long, ByVal g As Long, ByVal b As Long, ByVal W As Long, ByVal h As Long)


Drawing Functions


Draws a pen into a single channel. Requires 3 calls for color, one for each channel. The pen is fully antialiased and uses floating point coordinates.


Declare Sub AAcpen Lib "drfilter.dll" (ByRef Dest As Byte, ByVal X As Single, ByVal Y As Single, ByVal Size As Single, ByVal intensity As Single, ByVal opacity As Single, ByVal W As Long, ByVal h As Long)


Declare Sub AAcpenAlhpa Lib "drfilter.dll" (ByRef Dest As Byte, ByRef Alpha As Byte, ByVal X As Single, ByVal Y As Single, ByVal Size As Single, ByVal intensity As Single, ByVal opacity As Single, ByVal W As Long, ByVal h As Long)





Utility Functions


AngleOf


Returns the angle between x, y, and 0, 0.


Declare Function Angleof Lib "drfilter.dll" (ByVal X As Single, ByVal Y As Single) As Single


HSV


Declare Sub RGB_To_HSV Lib "drfilter.dll" (ByVal r As Single, ByVal g As Single, ByVal b As Single, h As Single, s As Single, v As Single)


Declare Sub HSV_To_RGB Lib "drfilter.dll" (r As Single, g As Single, b As Single, ByVal h As Single, ByVal s As Single, ByVal v As Single)


Bit Shift


Shift Right


Public Function ShiftR(ByVal e As Long, ByVal v As Long) As Long

If v = 0 Then ShiftR = e: Exit Function

Dim n As Long

For n = 0 To v - 1

e = e \ 2

Next

ShiftR = e

End Function

 

Shift Left


Public Function ShiftL(ByVal e As Long, ByVal v As Long) As Long

If v = 0 Then ShiftL = e: Exit Function

Dim n As Long

For n = 0 To v - 1

e = e * 2

Next

ShiftL = e

End Function


Swap



Public Sub Swap(ByRef v1, ByRef v2)


'swap two variables. saves declairing spare storage

'simple enough to do inline.


v1 = v1 Xor v2

v2 = v2 Xor v1

v1 = v1 Xor v2

End Sub


Return minimum of two values


Public Function Minimum(ByVal v1 As Long, ByVal v2 As Long) As Long

'returns the min of two values

If v1 > v2 Then Minimum= v2 Else Minimum= v1

End Function


Return maximum of two values


Public Function Maximum(ByVal v1 As Long, ByVal v2 As Long) As Long

'returns the max of two values

If v1 > v2 Then Maximum= v1 Else Maximum= v2

End Function


Swaps two values so the first is the smallest value


Public Function MinSwap(ByRef v1 As Long, ByRef v2 As Long) As Long

'swaps the values to make the smallest first

'returns 1 if values swapped or 0 if not

If v1 > v2 Then

v1 = v1 Xor v2

v2 = v2 Xor v1

v1 = v1 Xor v2

MinSwap = 1

Else

MinSwap = 0

End If

End Function


Swaps two values so the first is the largest value


Public Function MaxSwap(ByRef v1 As Long, ByRef v2 As Long) As Long

'swaps the values to make the smallest first

'returns 1 if values swapped or 0 if not

If v1 < v2 Then

MaxSwap = 1

v1 = v1 Xor v2

v2 = v2 Xor v1

v1 = v1 Xor v2

Else

MaxSwap = 0

End If

End Function


Rotates a 2-D point around 0


Public Sub RotatePoint(ByVal angle As Single, ByRef u As Single, ByRef v As Single)

'currently rotates around 0

'Rotating a 2d object is around a single axis

'rotating a 3d object is around 3 axisis,

'so call this once for each axis.

angle = angle * 0.01745

Dim New_U As Single

Dim New_V As Single

New_U = u * Cos(angle) - v * Sin(angle)

New_V = u * Sin(angle) + v * Cos(angle)

u = New_U

v = New_V

End Sub


Converting ‘packed’ colors


Dim R As Long, G As Long, B As Long, C As Long

C = Picture1.Point(X, Y)

R = C And &HFF&

G = (C And &HFF00&) \ &H100&

B = (C And &HFF0000) \ &H10000


Distance between two points


Public Function Distance(x1 As Single, y1 As Single, x2 As Single, y2 As Single) As Single

'Find the distance

Dim xSum As Single

Dim ySum As Single

Dim Totalsum As Single

xSum = x1 - x2

xSum = Abs(xSum)

xSum = xSum ^ 2

ySum = y1 - y2

ySum = Abs(ySum)

ySum = ySum ^ 2

Totalsum = xSum + ySum

Distance = Sqr(Totalsum) 'return value

End Function


Smoothstep


Public Function smoothstep(ByVal a As Single, ByVal b As Single, ByVal x As Single) As Single

If (x < a) Then smoothstep = 0: Exit Function

If (x >= b) Then smoothstep = 1: Exit Function

x = (x - a) / (b - a)

smoothstep = (x * x * (3 - 2 * x))

End Function


A Simple lattice noise function (requires smoothstep from above)


For best results, sum several layers of the noise function at different scales and offsets.


Public Static Function Noise(ByVal x As Single, ByVal y As Single) As Single

Const LatticeSize As Long = 64

Dim Lattice() As Single

Dim Initialized As Boolean

Dim lx As Long, ly As Long

Dim difx As Single, dify As Single

Dim x1 As Long, y1 As Long, x2 As Long, y2 As Long

Dim x3 As Long, y3 As Long, x4 As Long, y4 As Long

Dim v1 As Single, v2 As Single, v3 As Single, v4 As Single


'initialize if this is the first call

If Initialized <> True Then

ReDim Lattice(LatticeSize - 1, LatticeSize - 1)

For ly = 0 To LatticeSize - 1

 For lx = 0 To LatticeSize - 1

  Lattice(lx, ly) = Rnd

 Next

Next

Initialized = True

End If


x = Abs(x) : y = Abs(y)


difx = x - Int(x)

dify = y - Int(y)


'smoothstep the differences

difx = smoothstep(0, 1, difx) 

dify = smoothstep(0, 1, dify)


x1 = Int(x) : y1 = Int(y)

x2 = x1 + 1: y2 = y1

x3 = x1 : y3 = y1 + 1

x4 = x1 + 1 : y4 = y1 + 1

x1 = x1 Mod LatticeSize : y1 = y1 Mod LatticeSize

x2 = x2 Mod LatticeSize : y2 = y2 Mod LatticeSize

x3 = x3 Mod LatticeSize : y3 = y3 Mod LatticeSize

x4 = x4 Mod LatticeSize : y4 = y4 Mod LatticeSize

v1 = Lattice(x1, y1) : v2 = Lattice(x2, y2)

v3 = Lattice(x3, y3) : v4 = Lattice(x4, y4)


Noise = (((v1 * (1 - difx)) + (v2 * difx)) * (1 - dify)) _

        + (((v3 * (1 - difx)) + (v4 * difx)) * dify)


End Function