include '%lib%/freshlib.inc'

@BinaryType GUI

include '%lib%/freshlib.asm'

; Topic: Complex data structures in FASM
;   subtopic: Easy way to create initialized arrays of structures in FASM.
;
;       This example was written, because this is one of most common
;    questions on FASM message board. Sometimes it is problem even for
;    expirianced assembly programmers using other assemblers. Actually it is
;    not so hard to create not only arrays but even more complex data structures
;    as linked lists or trees, using so powerfull macro system of FASM.
;
;       I will refrain from using very complex macroses, because it is not
;    very useful for beginers to use them, even using ready for use libraries.
;    IMHO, it is better for every beginer to understand what actually happen and
;    then to begin to use complex macro libaries with full understanding.
;
;       Actually structures in FASM are almost same thing as macroses.
;    Only difference is that structures need label before it, but macro does
;    not need it.
;
;      There are two aspects in the "arrays" problem: "definition" and "using".
;    I will try to explain both aspects on the simple example.
;    Let we need some array with points and then we need some procedure that will
;    draw poliline from the first point to the last point of the array.
;    Indication for end of the array will be the point with negative x coordinate.
;
;    At first we will define base point structure, because we will need it when we
;    want to access defined data:

struct TPoint
  .x dd ?
  .y dd ?
ends

;    Then we will define macro for definition of initialized array.
macro PointArray [x, y] {
  forward  ; This means that following rows will be repeated for every set of arguments
    dd x
    dd y
  common
    dd -1  ; This will define one dword with content -1 at the end of the array.
}


iglobal

; Ok, we have the macro definitions, let's define an array:
MyArray:
        PointArray                      \
          100, 100,                     \
          200, 100,                     \
          200, 200,                     \
          100, 200,                     \
          100, 100,                     \
          150, 130,                     \
          200, 100

cMessage:
         db 'You can see a window with black wireframe figure like "envelope".', 13, 13
         db 'This is example how to create and use initialized arrays in FASM.',13, 13
         db 'For details, read carefully the source code.', 13, 0

rectWindow dd 0, 0, 300, 300
endg

uglobal
  width dd ?
  height dd ?
endg


start:
        invoke  AdjustWindowRect, rectWindow, SS_OWNERDRAW or WS_OVERLAPPEDWINDOW, 0
        mov     eax, [rectWindow+8]
        mov     ecx, [rectWindow+12]
        sub     eax, [rectWindow]
        sub     ecx, [rectWindow+4]
        mov     [width], eax
        mov     [height], ecx

        invoke  CreateWindowExA, 0, "STATIC", 0, SS_OWNERDRAW or WS_OVERLAPPEDWINDOW or WS_VISIBLE, 0, 0, [width], [height], 0, 0, [hInstance], 0
        mov     ebx, eax

        invoke  GetDC, ebx
        mov     edi, eax

        invoke  Rectangle, edi, 0, 0, [width], [height]

; And here the program will make some draw on the surface of the application console.
; I make it this way to keep additional code as small as possible.

        mov     esi, MyArray
        invoke  MoveToEx, edi, [esi+TPoint.x], [esi+TPoint.y], NULL   ; first point
        add     esi, sizeof.TPoint

.drawloop:
        cmp    [esi+TPoint.x], -1
        je     .enddraw

        invoke  LineTo, edi, [esi+TPoint.x], [esi+TPoint.y]
        add     esi, sizeof.TPoint
        jmp     .drawloop

.enddraw:
        invoke  ReleaseDC, edi
        invoke  MessageBoxA, NULL, cMessage, "Initialized arrays" , MB_OK or MB_ICONINFORMATION

        invoke  DestroyWindow, ebx

        invoke  ExitProcess, 0

