TAJGA 2D graphic library

----------------------------------------------------------------------------------------------------

TABLE OF CONTENTS:

0 - About this document

1 - Library hierarchy

2 - Structures
  2.1 - bitmap
    2.1.1 - Members 
    2.1.2 - Flag values
  2.2 - videobitmap
  2.3 - rect (internal)

3 - Procedure bodies
  3.1 - Library controlling
    3.1.1 - Init
    3.1.2 - Close
  3.2 - Bitmaps
    3.2.1 - CreateBitmap
    3.2.2 - FreeBitmap
  3.3 - Screen
    3.3.1 - SetVideoMode
    3.3.2 - ResetVideoMode
    3.3.3 - Lock
    3.3.4 - Unlock
    3.3.5 - Retrace

4 - Routines
  4.1 - rtn.clip
  4.2 - rtn.blit_rect

5 - OS access
  5.1 - os.memalloc
  5.2 - os.memfree
  5.3 - os.Init
  5.4 - os.Close
  5.5 - os.SetVideoMode
  5.6 - os.ResetVideoMode
  5.7 - os.Lock
  5.8 - os.Unlock
  5.9 - os.Retrace

6 - Usage
  6.1 - Error Handling
    6.1.1 - User level error handling
    6.1.2 - Common error handling
    6.1.3 - OS access error handling
    6.1.4 - Common (platform independent) errors

----------------------------------------------------------------------------------------------------

0 - About this document
=======================
  This document describes platform independent part of tg2d. 

  It is meant for developers of tg2d and for people who use it's default interface (currently it is
  only interface, so this is manual for all users. Users should be interested only in chapters 0, 2,
  3 and 6). 

  NOTE:
  - Word "TODO" marks something in documentation is not done.

1 - Hierarchy
==============
  TODO (You should read document "hierarchy.txt" instead, for now)
  
  Currently there is no special interface, you must access library using interface of procedure
  bodies by including it into FASM project. This would be called "default interface".

2 - Structures
==============

  For all structures variable "sizeof.<structure name>" is defined.

  All structure names have "tg2d." (note the dot) prefix (if they arent aliased in interface to some
  other name). I write names without "tg2d." here for simplicity.

  Members are separated from structure name with dot ("."). For example full name to access relative
  address of member "xsz" in structure "bitmap" is "tg2d.bitmap.Xsz". Same for static structures, to
  access to xsz of structure defined with "BMP tg2d.bitmap" you use "BMP.Xsz".

  2.1 - bitmap
  ============
    This structure describes two dimensional array of pixels.
    
    2.1.1 - Members 
    ===============
      all are dwords, their pseudo C definition follows
      
      xsz, ysz (unsigned ints)
        sizes of bitmap (in pixel). Size 0 is valid, value of "bmp" member is then zero and bitmap
        is called "empty".
      
      bmp (*(pixel[][]))
        pointer to 2 dimensional array of pixels. Type (size) of pixel depends on "bpp" member.
        Sizes of array are specified in "xsz" and "ysz" member. Bitmap is stored by lines, so it is
        "(pixel[xsz])[ysz]", or "array[1..Ysz] of array[1..Xsz] of pixel". If this member holds
        value 0, bitmap is treated as "undefined".
      
      flags (bit[32])
        Set of flags that describe bitmap. Values are described below.
      
      bpp (unsigned int)
        Number of bytes per pixel (not bits!). Describes pixel in array pointed by "bmp" member.
        Only low-order byte can be used, rest must be zero. 

      clipx, clipy, clipxsz, clipysz (unsigned ints)
        Specifies clipping region of bitmap. Clipping on bitmap is performed only when
        TG2D_BITMAP_CLIP flag is set, otherwise these members are ignored. Clipping rectangle cant
        be outside bitmap, and can't be empty eg: 
          0 <= clipx < xsz
          0 <= clipy < ysz
          0 < clipxsz <= (xsz - clipx)
          0 < clipysz <= (ysz - clipy)

    2.1.2 - Flag values
    ===================

      user flags - you specify them as you like

        none

      internal flags - you do not need to care about them
      
        0x00000002 - TG2D_BITMAP_CLIP
          If set, all operations on bitmap will be clipped to rectangle specified by ".clipx", ".clipy",
          ".clipxsz", ".clipysz" members. If flag is clear clear, these members are ignored. Set this
          flag only when you are sure clipping is required, for example flag dont have to be set
          when you are bltitting rectangle from bitmap and you are sure rectangle won't be out of
          bitmap.
        
        0x80000000 - TG2D_BITMAP_INTERNAL_ONECHUNK
          Is set only on bitmaps whose header (not only pixel array) was allocated by tg2d.  When
          you pass 0 as bitmap header pointer to CreateBitmap, it will allocate header and pixel
          array in one chunk of memory (this is where the name comes from). So FreeBitmap should
          know how bitmap is allocated and this is what is this flag for.

  2.2 - videobitmap
  =================    
    TODO
    TODO - pitch in Xsz, active resolution in clipxsz

  2.3 - rect (internal)
  =====================
    TODO

3 - Procedure bodies
====================
  All procedure body names have "tg2d." prefix.

  3.1 - Library controlling
  =========================
  
    3.1.1 - Init
    ============
      This procedure initializes library (makes it usuable) and also returns you current video
      framebuffer so you can modify screen, not only change it whole. 

      args: none
      returns: 
        eax = -1 on error, otherwise current video bitmap pointer or 0 if unsupported
        other GPRs preserved
      notes:
        - this procedure must be called before any other procedure. In such case procedure returns
          TG2D_ERROR_NOTINITIALIZED (value 1) error by called procedure.
        - on some platforms returned video bitmap structure has "bmp" member set to 0 and must be
          locked before accessing. This should be detected by checking TG2D_VIDEOBITMAP_MUSTBELOCKED
          flag in "tg2d.vbflags".
        - on platforms which doesnt allows you to modify screen, 0 is returned in eax
        - if Init returns 0 you can't use "tg2d.videobitmap", if you pass it to tg2d procedure as
          bitmap, procedure won't check whether it is present or not (because you should be using
          pointer returned by Init, not "tg2d.videobitmap" explicitly).
        - Xsz of returned video bitmap can be higher than current resolution's one, see video bitmap
          description for more informations on this.
      errors:
        TG2D_ERROR_INITIALIZED (value 2)
          this value is returned when function is called when library is already initialized. You
          are calling Init twice.
        + errors returned by os.Init
  
    3.1.2 - Close
    =============
      This procedure uninitializes library. After it is called, library cannot be used and only
      procedure you can call then is Init to intialize it again.
  
      args: none
      returns: 
        eax = -1 on errors, otherwise value is undefined
        other GPRs preserved
      notes:
        - If dislay mode was changed and wasnt restored, then it is restored now.
        - If video bitmap is locked, it will be unlocked
        - Close should be able to clean up even after tg2d error occured
        - If Close returns error (except TG2D_ERROR_NOTINITIALIZED) then library is still
          initialized and you can use it.
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Procedure was called when library is not initialized. You must call Init before.
        + errors returned by os.Close
        + errors returned by ResetVideoMode if video mode is changed when called.
        + errors returned by Unlock if screen is locked when called

  3.2 - Bitmaps
  =============    

    3.2.1 - CreateBitmap
    ====================
      args:
        ebx, ecx (unsigned ints)
          sizes of bitmap to create. Value must be in range 0 to 7FFFFFFFh.
        edx (unsigned int)
          bytes per pixel of bitmap to create. Value must be in range 0 to 0FFh
        eax (bit[])
          flags of bitmap. Only user flags are allowed here, other types of flags are defined by
          this procedure
        edi (bitmap*)
          0 or pointer to bitmap header. 
      returns:
        eax = -1 on errors, otherwise pointer to new bitmap
        other GPRs are reserved
      notes:
        - if you specify edi other than 0, then value returned in eax remains in edi too (of course)
        - If edi contains 0, CreateBitmap will allocate header in same block of memory with pixel
          array and set TG2D_BITMAP_INTERNAL_ONECHUNK flag in "flags" member. If header is specified
          in edi only pixel array is allocated.
        - If TG2D_BITMAP_CLIP flag is specified in eax, then clip rectangle is set to entire bitmap
          (clipx = 0, clipy = 0, clipxsz = xsz = ebx, clipysz = ysz = ecx)
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        TG2D_ERROR_OUTOFRANGE (value 4)
          ebx or ecx above 7FFFFFFFh, some position wouldnt be addressable.
        TG2D_ERROR_OVERFLOW (value 5)
          size of pixel array too big: xsz*ysz*bytes_per_pixel >= 2^32
        TG2D_ERROR_INVALIDARGS (value 6)
          non-user flags specified in eax.
        + errors returned by memalloc

    3.2.2 - FreeBitmap
    ==================
      args:
        edi (bitmap*)
          pointer to bitmap to free
      returns:
        eax = -1 on errors, undefined otherwise
        other GPRs are reserved
      notes:
        - if bitmap has TG2D_BITMAP_INTERNAL_ONECHUNK flag set, then header is freed too, otherwise
          all header members are zeroed. (see CreateBitmap for more info on this)
        - you cannot free video bitmap, if you try so TG2D_ERROR_INVALIDARGS error is returned.
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        TG2D_ERROR_UNDEFINEDBITMAP (value 9)
          bitmap you entered was undefined ("bmp" member is 0). You are freeing bitmap twice or you
          are trying to free uncreated bitmap.
        TG2D_ERROR_INVALIDARGS (value 6)
          you are trying to free video bitmap.
        + errors returned by memfree

  
  3.3 - Screen
  ============
    Screen is called video framebuffer. Screen is described by video bitmap (generally called video
    framebuffer, but it is described by tg2d.bitmap structure so i use name video bitmap). You
    receive video bitmap pointer from Init or SetVideoMode.

    3.3.1 - SetVideoMode
    ====================
      Sets another display mode (resolution and bit depth)

      args:
        ebx = X resolution of mode to set
        ecx = Y resolution of mode to set
        edx = bytes per pixel of mode to set. (BYTES, not bits!)
      returns:
        eax = -1 on error, otherwise it is pointer to "tg2d.videobitmap"
      notes:
        - Xsz of returned video bitmap can be higher than one specified in ebx, see video bitmap
          description for more informations on this.
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        + errors returned by os.SetVideoMode
    
    3.3.2 - ResetVideoMode
    ======================
      Returns display to state it was in when Init was called

      args: none
      returns:
        eax = -1 on error, pointer to "tg2d.videobitmap" if supported, or 0 if access to screen is
          not supported now
      notes:
        - called automaticaly by Close if you changed display mode and didnt restore it. But better
          do not rely on this behavior, it would be unclear for anyone reading your code.
        - in version for win32 ddraw it returns to state when first SetVideoMode was called (instead
          of Init), but this shouldn't matter very much.
        - Xsz of returned video bitmap can be higher than original resolution's one, see video
          bitmap description for more informations on this.
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        TG2D_ERROR_ALREADYDONE (value 10)
          You are in original display mode already, this call is obsolete.
        + errors returned by os.ResetVideoMode
    
    3.3.3 - Lock
    ============
      On some platforms video bitmap must be "locked" before you can use it. When you use video
      bitmap in tg2d routine then tg2d locks it for you if it is needed, but in some cases you want
      to lock it yourself (like when you want to modify it with non-tg2d routine)
      
      args: none
      returns:
        tg2d.videobitmap.bmp = valid pointer to displayed pixel array. "tg2d.videobitmap" is pointed
          by return value of Init and SetVideoMode.
        eax = -1 on error, undefined otherwise
        other GPRs are reserved
      notes:
        - On platforms where locking is not required this procedure does nothing, otherwise it sets
          "tg2d.videobitmap.bmp" to valid pointer.
        - Locking takes lot of time, so video bitmap should be locked only once per drawing loop. If
          you make more consectutive draws onto video bitmap in one loop, you should call Lock
          before, otherwise video bitmap is locked and unlocked by tg2d for each draw.
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        TG2D_ERROR_NOVIDEOBITMAP (value 11)
          Video bitmap is not accessible now (Init returned 0, so you cant use video bitmap)
        TG2D_ERROR_ALREADYDONE (value 10)
          Video bitmap is locked already
        + errors returned by os.Lock

    3.3.4 - Unlock
    ==============
      Unlocks locked bitmap.

      args: none
      returns:
        tg2d.videobitmap.bmp = 0 on platforms on which locking is required. "tg2d.videobitmap" is
          pointed by return value of Init and SetVideoMode.
        eax = -1 on error, undefined otherwise
        other GPRs are reserved
      notes:
        - you should try to spend as few time as possible between Lock and Unlock, because purpose
          of locking is to suspend other processes to make sure no one else will change screen. So
          while video bitmap is locked multitasking is disabled.
        - video bitmap is unlocked automaticaly when Close is called when it is locked
      errors:
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        TG2D_ERROR_NOVIDEOBITMAP (value 11)
          Video bitmap is not accessible now (Init returned 0, so you cant use video bitmap)
        TG2D_ERROR_ALREADYDONE (value 10)
          Video bitmap is unlocked already
        + errors returned by os.Unlock

    3.3.5 - Retrace
    ===============
      Gets vertical retrace status. For smooth animation you should write screen only during
      vertical retrace

      args: none
      returns:
        eax = -1 on error, 0 when retrace is not in progress, 1 during retrace
        other GPRs are reserved
      errors: 
        TG2D_ERROR_NOTINITIALIZED (value 1)
          Init wasnt called
        + errors returned by os.Retrace


4 - Routines
============
  Routines are procedures which do one time-consuming or often-used task. They are called from
  procedure bodies. Routines can't call any other procedures, only other routines. Routines have
  'tg2d.rtn.' name prefix, in this text only 'rtn.' will be used.
  
  4.1 - rtn.clip
  ==============
    This routines clips source (draw) rectangle into destination rectangle.

    args:
      
  
  4.2 - rtn.blit_rect
  ===================

5 - OS access
=============
  This information is important only for people who want to develop TG2D port for some unsupported
  platform. It describes interface which is used for wrapped platform access. Example of such wrap
  is file "os_access\ddraw.inc". 

  (Almost) all symbols you define must have "tg2d.os." prefix. I write only "os." in this document.
  
  You shouldn't define any macros, if you do then you should purge them.
    
  Do not await that some standard libraries are included, look up constants in library's include
  files and write them as a numeric value with their name in comment, like:
    push 32512 ;IDI_APPLICATION

  Of course, some symbols have to be defined (system procedure pointers), but try to keep their
  number as small as possible. Do not force user to include something he may not want to have
  included if he includes tg2d into his project.

  You must support few OS access procedures for every platform. On error you must fill error info
  structure and return with CF flag set. If no error error occured, you must return with CF flag
  clear:

  5.1 - os.memalloc
  =================      
    Allocates memory
      
    args:
      eax = size of memory block to allocate, in bytes
    returns:
      CF = 1 on error
      eax = pointer to allocated block      

  5.2 - os.memfree
  =================
    Frees memory allocated by os.memalloc
    
    args:
      eax = pointer to memory block to free, returned by os.memalloc
    returns:
      CF = 1 on error
    
  5.3 - os.Init
  ==============
    OS dependant part of Init. That means it
      1. Fills variables defined by OS-dependant part with default value. This is important, all
         values must be filled here.
      2. Gains information about user of library needed later, initializes programs used by
         OS-dependant part (like ddraw).
      3. If possible, gives user access to modify screen.
    
    args: none
    returns: 
      CF = 1 on error
      tg2d.videobitmap and tg2d.vbflags filled
    notes:
      - if you can provide access to modify screen, then set flag TG2D_VIDEOBITMAP_PRESENT in
        tg2d.vbflags, and fill tg2d.videobitmap and tg2d.vbflags. Otherwise zero entire
        tg2d.videobitmap and tg2d.vbflags too (so TG2D_VIDEOBITMAP_PRESENT will be clear).
      - be sure to have tg2d.videobitmap filled with valid values even on case of error. For
        example if Init failed during getting access to screen, flag TG2D_VIDEOBITMAP_PRESENT
        should be clear, if it failed later flag should be set and structure filled.
        
  5.4 - os.Close
  ============
    OS dependant part of Close. It should just undo all that Init did.
    
    args: none
    returns:
      CF = 1 on error
    notes:
      - remember that library should be operable after calling Close and then calling Init again!
      - os.Close should be able to clean up even after tg2d error occured, remember this when
        writing other procedures!
  
  5.5 - os.SetVideoMode
  =====================
    This one should set display mode and fill tg2d.videobitmap and tg2d.vbflags.

    args:
      ebx = x resoultion
      ecx = y resolution
      edx = bytes per pixel (bytes, not bits!)
    returns:
      CF = 1 on error
      tg2d.videobitmap and tg2d.vbflags
    notes:
      - be sure to have tg2d.videobitmap filled with valid values even on case of error. For
        example if Init failed during getting access to screen, flag TG2D_VIDEOBITMAP_PRESENT
        should be clear, if it failed later flag should be set and structure filled.
  
  5.6 - os.ResetVideoMode
  =======================
    This procedure should restore display changed by SetVideoMode to state it was in when Init was
    called (last time). It should also give you access to modify screen, like Init does (read it's
    documentation for more information). 

    args: none
    returns:
      CF = 1 on error
      tg2d.videobitmap and tg2d.vbflags filled
    notes:
      - if you can provide access to modify screen, then set flag TG2D_VIDEOBITMAP_PRESENT in
        tg2d.vbflags, and fill tg2d.videobitmap and tg2d.vbflags. Otherwise zero entire
        tg2d.videobitmap and tg2d.vbflags too (so TG2D_VIDEOBITMAP_PRESENT will be clear).
      - be sure to have tg2d.videobitmap filled with valid values even on case of error. For
        example if Init failed during getting access to screen, flag TG2D_VIDEOBITMAP_PRESENT
        should be clear, if it failed later, flag should be set and structure filled.
  
  5.7 - os.Lock
  =============
    This procedure should lock video bitmap, set flag TG2D_VIDEOBITMAP_LOCKED in tg2d.vbflags and
    set tg2d.videobitmap.bmp.

    args: none
    returns:
      CF=1 on error
    notes:
      - if locking is not required on platform, and thus TG2D_VIDEOBITMAP_MUSTBELOCKED flag then
        it is enough to define label for procedure (It should never be called).
    
  5.8 - os.Unlock
  ===============
    This procedure should unlock video bitmap, and set flag TG2D_VIDEOBITMAP_LOCKED in
    tg2d.vbflags.

    args: none
    returns: CF=1 on error
    notes:
      - if locking is not required on platform, and thus TG2D_VIDEOBITMAP_MUSTBELOCKED flag then
        it is enough to define label for procedure (It should never be called).

  5.9 - os.Retrace
  ================
    This procedure should check vertical retrace status and return it: eax = 1 during retrace, 0
    otherwise.
    
    args: none
    returns: 
      CF=1 on error
      eax = 1 during retrace, 0 otherwise
    


6 - Usage
=========

  6.1 - Error Handling
  ====================
    There are severals layers of error handling.
    
    6.1.1 - User level error handling
    =================================
      This chapter describes default error handling provided to user. This can be changed by
      interface of library, so every interface description should contain description of it's error
      handling or note that it uses default error handling.
      
      After calling any TG2D procedure, user should check value of eax register for value -1. If it
      contains error, then value of dword "tg2d.error' is nonzero and specifies error. Common
      (platform independant) errors are enumrated from 1 upwards. Platform dependant errors are
      enumerated from -1 downwards. For each error constant TG2D_ERROR_<error name> is defined.

      If some error occured then dword variable "tg2d.error.proc" contains pointer to procedure in
      which error occured. Altough user must check for error after each procedure call, so he should
      know which procedure he called when error occured, this information is useful in case when
      called tg2d procedure calls another tg2d procedure. Both procedures can be returning same
      error, but with different meaning so this way you can differentiate. 
      I know this system is not 100%, it would require call stack of tg2d procedures to fully
      describe error placement, but in most cases this is enough and it is much easier to use.
      
      If you are using some 3rd party engine (like directdraw, including OS) which returns some
      errors that are not translated to TG2D_ERROR_ form, then you must define platform dependant
      error (with negative value), like TG2D_ERROR_WINDOWS, which means that value of dword variable
      "tg2d.error.originial" contains error returned by 3rd party engine. Meaning of contents of
      "tg2d.error.originial" depends on TG2D_ERROR_ value and should be described in platform
      dependant documentation.

      Values in "tg2d.error.nameA" and "tg2d.error.nameW" are pointers to ASCII and unicode error
      name. Name is same, as name in library sources, for example 'TG2D_ERROR_NOTINITIALIZED'.

      NOTES:
        - User is responsible for handling returned error. If you call some procedure after error
          occured in previous procedure, library wouldnt check this case and would act is if no
          error occured. It's on user to check for error after EVERY tg2d procedure call.
        - It is possible that in future there will be some procedure which will return -1 as valid
          value, and so that i will change error handling. So it would be better checking testing
          (tg2d.error != 0) instead of (eax == -1). However, currently i cant imagine such procedure
          so i still use (eax == -1) way. If you use (tg2d.error != 0) way, it would only be good
          for you, because you will be forward - compatible. I wont like breaking backwards
          compatibility, but maybe i'll be forced to.
        - After tg2d error occured user should call tg2d.Close to clean up.
          
    6.1.2 - Common error handling
    =============================
    TODO - bout this chapter, OnError

    6.1.3 - OS access error handling
    ================================
      This chapter describes standard used in passing errors from OS access part to OS independant
      part of library.
      
      When error occured in OS-access procedure, it must return with CF set, otherwise it must
      return with CF clear. If it returns error, all error informations must be filled, so that
      procedury body will only return to interface. Values of other tg2d variables should too
      validly describe situation.

      OS access part must define string table for platform dependant error names. First member of
      table is for error -1, second is for error -2 etc. There should be two tables, one for ASCII
      and one for unicode, named "tg2d.os.error.nametableA" and "tg2d.os.error.nametableW". (String
      table is array of pointers to strings).
      
    6.1.4 - Common (platform independent) errors
    ============================================
      TODO

vim: tw=100 expandtab
