News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

libwebp Api - WebPEncodeLosslessBGRA

Started by guga, October 01, 2020, 06:17:09 PM

Previous topic - Next topic

guga

Some specifications of WebPEncodeLosslessBGRA function from libwebp Api

WebPEncodeLosslessBGRA

This function encodes images pointed to by bgra parameter and returns the WebP image file and it´s size.

It compresses the image using the lossless format. Files are usually larger than lossy format, but will not suffer any compression loss. For lossy compression, you can use the WebPEncodeRGBA family.

The lossy functions (WebPEncodeLosslessRGB, WebPEncodeLosslessBGR, WebPEncodeLosslessRGBA and WebPEncodeLosslessBGRA), use the library's default settings. For lossless this means exact is disabled. RGB values in transparent areas will be modified to improve compression.
To avoid this, use WebPEncode() and set WebPConfig::exact to 1.

Parameters:
   bgra (in) - Pointer to the Pixel data of the image in BGRA format. So, it points to a Array of RGBQUAD structures. You can retrieve the Pixels from gdiplus, simple gdi or whatever other library
   Width (in) - An integer representing the width of the image (In pixels)
   Height (in) - An integer representing the height of the image (In pixels)
   stride (in) -   An integer specifying the stride of the image (In bytes). It specifies the byte offset between the beginning of one scan line and the next.
                       This is usually (but not necessarily) the number of bytes in the pixel format (for example, 2 for 16 bits per pixel and 4 for 24 or 32bpp) multiplied by the width of the bitmap.
                       An easier way to calculate the stride is with GetStride function showed below
   output(out) - Pointer to a variable (int) where the WebpImage will be stored

Return Values:
       If the function suceeds, it returns the size of the converted image
       If the function fails, it returns 0

Remarks:

    The function allocates internally enough memory to do the convertion, so, after using the function, you must deallocate the memory with WebPFree Api.


Example of usage:

    call GetStride D@ImgWidth, 32
    lea ecx D@OutData | mov D$ecx 0
    call 'libwebp.WebPEncodeLosslessBGRA' D@PixData, D@ImgWidth, D@ImgHeight, eax, ecx

   call 'libwebp.WebPFree' D@OutData ; release the allocated memory used internally in libwebp library


More info (although very very incomplete) can be found at:
https://developers.google.com/speed/webp/docs/api

Additional Function:

GetStride


;;
    GetStride
        This function calculates the Line Stride of the Image given a BitCount, biPlane and Width input.
        Similar to GetLineStrideFromBmpNfoHdr Api, Line Strides (also known as RowSize, line padding or Stride) are basically
        the number of bytes occupied in memory by a line of an image.
        It specifies the byte offset between the beginning of one scan line and the next.
        This is usually (but not necessarily) the number of bytes in the pixel format (for example, 2 for 16 bits per pixel) multiplied by the width of the bitmap.
        In GdiPlus Api, the value passed as a Stride (in GdipCreateBitmapFromScan0 for example), must be a multiple of four.

    Parameters:
        Width - A integer representing the width of the image
        BitCount - A integer representing the bit count of the image. It specifies the number of bits per pixel (bpp).
                   For uncompressed formats, this value is the average number of bits per pixel.
                   For compressed formats, this value is the implied bit depth of the uncompressed image,
                   after the image has been decoded.
                   Allowed values are: 1, 4, 8, 16, 24 and 32
       
    Return value:
        The function will return in eax the stride of a given bitmap image. (In bytes)

    Remarks:
        Stride is calculated as a padding bytes. The following table illustrates the relationship between width and stride.
        width  stride
            1   4
            2   4
            3   4
            4   4
            5   8
            6   8
            7   8
            8   8
            9   12
            10  12
            11  12
            12  12
            ......

        Be carefull when using the returned value, because it is always in Bytes, but some Apis may uses the stride as a multiple of 4 (to represent the RGBQUAD values)
        On google Libwebp library, gdiplus, normal gdi, FGetDIBits or GdipSaveWebpImage, the returned value are in Bytes, so we don´t need to divide it by 4.
       
        The function works for:
        BITMAPINFOHEADER, BITMAPV2INFOHEADER, BITMAPV3INFOHEADER, BITMAPV4INFOHEADER, BITMAPV5INFOHEADER

        Example of usage:

        a) With libwebp:
       
            call GetStride D@ImgWidth, 32
            lea ecx D@OutData | mov D$ecx 0
            call 'libwebp.WebPEncodeLosslessBGRA' D@PixData, D@ImgWidth, D@ImgHeight, eax, ecx

        b) With gdiplus:
       
            call GetStride D@ImgWidth, 32
            call 'gdiplus.GdipCreateBitmapFromScan0' D@ImageWidth, D@ImageHeight, eax, PIXELFORMAT_32BPPARGB, D@ImgBits, D@pImage

        c) with gdi to calculate the amount of memory neded to build the pixels data

            call GetLineStrideFromBmpNfoHdr OutBmpNfo
            Align_On 4 eax | imul eax D@BITMAP.bmHeightDis | mov D@RawImgDataSize eax
            mov D@TmpMem 0 | lea eax D@TmpMem
            call 'RosMem.VMemAlloc' eax, D@RawImgDataSize

    References: http://mapw.elte.hu/elek/bmpinmemory.html
                https://medium.com/@oleg.shipitko/what-does-stride-mean-in-image-processing-bba158a72bcd
                https://www.collabora.com/news-and-blog/blog/2016/02/16/a-programmers-view-on-digital-images-the-essentials/

;;

Proc GetStride::
    Arguments @Width, @BitCount
    Local @cClrBits
    Uses edx

    ; Convert the color format to a count of bits. No need to calculate the bitplanes sicne it is always 1 for bitmaps
    movzx eax W@BitCount
    If ax <= 1
        mov eax 1
    Else_If ax <= 4
        mov eax 4
    Else_If ax <= 8
        mov eax 8
    Else_If ax <= 16
        mov eax 16
    Else_If ax <= 24
        mov eax 24
    Else
        mov eax 32
    End_If
    mov D@cClrBits eax

    ; Compute the number of bytes in the array of color indices and store the result in biSizeImage.
    ; For Windows NT, the width must be DWORD aligned unless the bitmap is RLE compressed. This example shows this.
    ; For Windows 95/98/Me, the width must be WORD aligned unless the bitmap is RLE compressed.
    movzx eax W@Width
    imul eax D@cClrBits | add eax 31 | and eax (0-32)
    cdq | and edx 7 | add eax edx | sar eax 3

EndP



Libwebp (v 1.1.0) Library attached
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Interesting, Gustavo. Does it compress better than PNG?

guga

Hi JJ. Much much better.

the documentation really sucks. I spent the last 2 days trying to find a way to encode and decode this stuff, but it is worthfull and it is relatively simple to do :)


I created a function to convert a GdiPlus image to this webp format. It is like this:



;;
    GdipSaveWebpImage
        This function saves a given GdiPlus image to a Webp file (Google image file for the web).

    Parameters:

        pGdiPlusImage(in) - Pointer to the GDIPlus Image object.

        pFilename(in) - Pointer to a Null terminated Ansi string that specifies the path and the filename for the saved image.

        Return Value:
            If the function suceeeds, it returns &TRUE
            If fails returns &FALSE
           
        Remarks:
            The function uses internally libwebp library v 1.1.0 (google image library for the web), so you must have in your system or in
            the same directory as your app where FastCrt library is, the file libwebp.dll
           

        Example of usage:

            [MyFileName: B$ "c:\MyFile.webp", 0]
                call 'FastCRT.GdipSaveWebpImage' D@pImage, MyFileName


    References:
        http://www.jose.it-berater.org/smfforum/index.php?topic=1858.msg6500#msg6500
        https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-listing-parameters-and-values-for-all-encoders-use
        https://docs.rs/libwebp/0.1.2/libwebp/fn.WebPEncodeLosslessRGBA.html
        https://ffmpeg.org/doxygen/3.1/libwebpenc_8c_source.html
        https://docs.rs/libwebp-sys2/0.1.1/libwebp_sys/fn.WebPEncode.html
        https://docs.rs/libwebp-sys2/0.1.1/libwebp_sys/struct.WebPPicture.html
        https://hg.libsdl.org/SDL_image
        https://hg.libsdl.org/SDL/
        http://game.gamezone.space/ufo-run/cocos2d-x-2.2/cocos2dx/platform/third_party/win32/libwebp/
       
        You can download newer versions of libwebp library at:

        https://developers.google.com/speed/webp/docs/precompiled
        https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html
;;

Proc GdipSaveWebpImage::
    Arguments @pImage, @pFileName
    Local @ImgHeight, @ImgWidth, @hBitMap, @PixData, @Stride, @OutData, @ReturnValue
    Uses ecx, edx

    mov D@ReturnValue &FALSE

    lea eax D@ImgWidth
    call 'gdiplus.GdipGetImageWidth' D@pImage, eax

    lea eax D@ImgHeight
    call 'gdiplus.GdipGetImageHeight' D@pImage, eax

    lea eax D@hBitMap
    call 'gdiplus.GdipCreateHBITMAPFromBitmap' D@pImage, eax, 0 ;0FF000000; The last parameter is in RGBQUAD: format Ex: 0FF000000 or simply 0 if the background is tranbsparent

    lea eax D@PixData
    call FGetDIBits D@hBitMap, eax, &TRUE ; pixels is obtained in format RGBQUAD; (Blue, Red, Green and Alpha) and not RGBA ;. This is just a function i made to get the pixels of a image. (A bit lomng to post here, but basically you need to get the true pixel data and put here. (In RGBQUAD format)

    ; FGetDibits creates a Pixel data in RGQUAD format creating a Bitmap in 32 bpp with 1 plane, therefore we need to calculate
    ; the stride from it. There´s a internal function inside RosAsm FAstCRT library called FGetDIBitsEx that do the similar thing (GetLineStrideFromBmpNfoHdr) (I´ll release this library soon. I need to fix some damn bugs in RosAsm 1st)
    call GetStride D@ImgWidth, 32 ; <---- As explained in the 1st post

    lea ecx D@OutData | mov D$ecx 0

    ;call 'libwebp.WebPEncodeLosslessRGBA' D@PixData, D@ImgWidth, D@ImgHeight, eax, ecx ; <--- This Api will exchange Red with Blue. Incorrect, but fun to see :)

    call 'libwebp.WebPEncodeLosslessBGRA' D@PixData, D@ImgWidth, D@ImgHeight, eax, ecx
    ; returned in eax the size of the image
    .If eax <> 0
        call FileCreate D@pFileName, D@OutData, eax
        call 'libwebp.WebPFree' D@OutData
        mov D@ReturnValue &TRUE
    .End_If
    call 'RosMem.VMemFree' D@PixData

    mov eax D@ReturnValue

EndP

___________________________________________________________________________________________



I´m not sure if i configured the Api correctly, but it is finally saving it as webp. In fact, i didn´t configured it at all. I simply used the Api directly to see how it worked. The difference of quality don´t seems to me be that big (afterall i didn´t configured it) :biggrin: :biggrin:.

The size is reduced way better then in png, for example. I´m posting it here the tests i did :)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

Btw, GdiPlus and a Library called Wic also handles this webp format, but i don´t know if they are something only available for Windows10 and neither if they save the files.

On GdiPlus for example it do contains the GUID to webp format, but i don´t know how to activated it to see if it can decode or encode or both

On Wic, it do decodes the webpformat, but i don´t know if it encodes.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

Other format of interest that i plan to make the proper functions to encode and decode is the heic file. It can be loaded directly without having to install any windows10 plugin or codec (And most likely will work on older windows versions as well).

https://www.libde265.org/downloads-software/
https://mpeg.chiariglione.org/standards/mpeg-h/image-file-format
https://github.com/strukturag/libheif
https://github.com/nokiatech/heif

I´ll check this format later. Gdiplus also has the GUID for it, but apparently as with webp it does not have the proper encoders or decoders for all windows versions, that´s why i choose to use the dlls directly from them.

The only problem i see on those libraries is the fact that they must be located on the same directory as the main file (In case: RosAsm.exe), i would like to know if there is way to put them on their own directory like a plugin for example (preference without using loadlibrary api.)  Ex: i want to create a directory named as "data" or 'libraries" or "plugin" etc, put those dlls there and keep the main directory only with the main executable file (RosAsm.exe)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Siekmanski

Hi Guga,

GdiPlus can compress your 307254 bytes .BMP, to a 3885 bytes .PNG file.
Creative coders use backward thinking techniques as a strategy.

jj2007

What's your secret trick, Marinus? I get 8922 bytes for PNG, 8531 for GIF :cool:

include \masm32\MasmBasic\Res\MbGui.asm
Event Paint
  SaveImageToFile "GugaBitmap.png" ; 8922 bytes
  GuiImage "GugaBitmap.bmp"
EndOfCode

guga

Hi Marinus.

I saw that. You need to use the EncoderParameter Structure, right ? I used that to create Tiff files, as well.

JJ, you may need to setup the Encoder Structure, like this example in tiff.


[ENCODER_PARAMETER_VALUE_TYPE_BYTE 1 ; 8-bit unsigned int
ENCODER_PARAMETER_VALUE_TYPE_ASCII 2 ; 8-bit byte containing one 7-bit ASCII code. NULL terminated.
ENCODER_PARAMETER_VALUE_TYPE_SHORT 3 ; 16-bit unsigned int
ENCODER_PARAMETER_VALUE_TYPE_LONG 4 ; 32-bit unsigned int
ENCODER_PARAMETER_VALUE_TYPE_RATIONAL 5 ; Two Longs. The first Long is the numerator, the second Long expresses the denomintor.
ENCODER_PARAMETER_VALUE_TYPE_LONGRANGE 6 ; Two longs which specify a range of integer values. The first Long specifies the lower end and the second one specifies the higher end. All values are inclusive at both ends
ENCODER_PARAMETER_VALUE_TYPE_UNDEFINED 7 ; 8-bit byte that can take any value depending on field definition
ENCODER_PARAMETER_VALUE_TYPE_RATIONALRANGE 8] ; Two Rationals. The first Rational specifies the lower end and the second specifies the higher end. All values are inclusive at both ends

[CLSID_TIF:  D$ 0557CF405, W$ 01A04, 011D3,  B$ 09A, 073, 0, 0, 0F8, 01E, 0F3, 02E]


[TiffEncParam:
TiffEncParam.Count: D$ 2
; Fill and EncoderParameter structure with the compression
TiffEncParam.Parameter1.Guid.Data1: D$ 0E09D739D ; GUID_ENCODER_COMPRESSION
TiffEncParam.Parameter1.Guid.Data2: W$ 0CCD4
TiffEncParam.Parameter1.Guid.Data3: W$ 044EE
TiffEncParam.Parameter1.Guid.Data4: B$ 08E, 0BA, 03F, 0BF, 08B, 0E4, 0FC, 058
TiffEncParam.Parameter1.NumberOfValues: D$ 1
TiffEncParam.Parameter1.Type: D$ ENCODER_PARAMETER_VALUE_TYPE_LONG
TiffEncParam.Parameter1.Value: D$ TiffCompression

; Fill and EncoderParameter structure with the color depth
TiffEncParam.Parameter2.Guid.Data1: D$ 066087055 ; GUID_ENCODER_COLORDEPTH
TiffEncParam.Parameter2.Guid.Data2: W$ 0AD66
TiffEncParam.Parameter2.Guid.Data3: W$ 04C7C
TiffEncParam.Parameter2.Guid.Data4: B$ 09A, 018, 038, 0A2, 031, 0B, 083, 037
TiffEncParam.Parameter2.NumberOfValues: D$ 1
TiffEncParam.Parameter2.Type: D$ ENCODER_PARAMETER_VALUE_TYPE_LONG
TiffEncParam.Parameter2.Value: D$ TiffEncoderColorDepth]

[TiffCompression: D$ 0]
[TiffEncoderColorDepth: D$ 0]

call 'gdiplus.GdipSaveImageToFile' D@pGdiPlusImage, D@FilenameWDis, CLSID_TIF, TiffEncParam


But, using the CLSID for png, right marinus ?


http://www.jose.it-berater.org/smfforum/index.php?topic=1858.msg6500#msg6500


Another thing...How can i create a bitmap in memory (containing the headers) from a gdi pixel data ? Does GdipCreateBitmapFromFile generates a full Bitmap ?

I suceeded to open jpg, png, tiff files using your routine, but how to convert it to a full bitmap so i can manipulate it´s contents (including the headers) directly ?


Other question. How i convert the pixel format without using GdipBitmapConvertFormat ? I mean, say i open a image (jpg, for example) and figure it out that it is 24bpp. How can i convert it directly to 32bpp ?

I made a small routine to scan the pixel data taking onto account the bpp, but what happens if the opened file is 24bpp ? When i pass it to GdipCreateBitmapFromScan0 will it automatically convert to 32bpp or i need to setup it to 32 ?

I mean, i did this:


    lea eax D@PixFmt
    call 'gdiplus.GdipGetImagePixelFormat' D@ImagePix, eax
    If eax <> &S_OK
        call 'gdiplus.GdipDisposeImage' D@pImage ; Dispose image in case of failure
        xor eax eax
        ExitP
    End_If

    call GdipGetPixelFormatSize D@PixFmt ; <---- Identity if it is 24bp, 1bpp, 4bpp, 32bpp etc
    call GetStride D@ImgWidth, eax
    call 'gdiplus.GdipCreateBitmapFromScan0' D@ImgWidth, D@ImgHeight, eax, D@PixFmt, &NULL, D@pImage
    If eax <> &S_OK
        call 'gdiplus.GdipDisposeImage' D@pImage ; Dispose image in case of failure
        xor eax eax
    Else
        mov eax &TRUE
    End_If


Say that at GdipGetPixelFormatSize it displays it as a 24bpp. To i create a 32bp should i do something like this ?

    lea eax D@PixFmt
    call 'gdiplus.GdipGetImagePixelFormat' D@ImagePix, eax
    If eax <> &S_OK
        call 'gdiplus.GdipDisposeImage' D@pImage ; Dispose image in case of failure
        xor eax eax
        ExitP
    End_If

    ;mov eax D@ImgWidth | shl eax 2
    call GdipGetPixelFormatSize D@PixFmt
     If eax <> 32
           mov D@PixFmt PIXELFORMAT_32BPPARGB
     End_If

    call GetStride D@ImgWidth, eax
    call 'gdiplus.GdipCreateBitmapFromScan0' D@ImgWidth, D@ImgHeight, eax, D@PixFmt, &NULL, D@pImage
    If eax <> &S_OK
        call 'gdiplus.GdipDisposeImage' D@pImage ; Dispose image in case of failure
        xor eax eax
    Else
        mov eax &TRUE
    End_If


Or...also even a more direct way right below GdipGetImagePixelFormat, like:
    lea eax D@PixFmt
    call 'gdiplus.GdipGetImagePixelFormat' D@ImagePix, eax
    If eax <> &S_OK
        call 'gdiplus.GdipDisposeImage' D@pImage ; Dispose image in case of failure
        xor eax eax
        ExitP
    End_If
   If D@PixFmt <>  PIXELFORMAT_32BPPARGB ; IF pixel format is not 32bpp ARGB, set to 32bpp
           mov D@PixFmt PIXELFORMAT_32BPPARGB
     End_If
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Siekmanski

Hi Jochen,

I looked for the maximum count of unique colors in the image guga used.
In guga's .bmp image there are 10 unique colors.
I saved the image as an indexed color image with only 10 entries in the Color Palette.
Now the image only needs 4 bits per index to 1 of the 10 colors.

It creates a lossless image as small as possible.

You can use this routine for it:


; save Color Indexed images with 2 to 256 colors. ( any number between 2 to 256 )
SaveColorIndexedImage proc pGdiPlusImage:DWORD,pFilename:DWORD,Image_Type:DWORD,Color_Count:DWORD

    mov     ecx,Color_Count
    mov     eax,offset ColorPalette
    mov     dword ptr [eax],PaletteFlagsGrayScale
    mov     dword ptr [eax+4],ecx
    invoke  GdipInitializePalette,eax,PaletteTypeOptimal,dword ptr [eax+4],FALSE,pGdiPlusImage
    test    eax,eax
    jnz     Done

    mov     ecx,Color_Count
    mov     eax,PixelFormat8bppIndexed
    cmp     ecx,16
    ja      ConvertFormat   
    mov     eax,PixelFormat4bppIndexed
    cmp     ecx,2
    ja      ConvertFormat   
    mov     eax,PixelFormat1bppIndexed
   
ConvertFormat:
    invoke  GdipBitmapConvertFormat,pGdiPlusImage,eax,DitherTypeSolid,PaletteTypeOptimal,offset ColorPalette,0
    test    eax,eax
    jnz     Done

    invoke  MultiByteToWideChar,CP_ACP,0,pFilename,-1,offset FilenameW,MAX_PATH-1
    mov     eax,Image_Type
    mov     byte ptr[CLSID_ImageTypes],al
    invoke  GdipSaveImageToFile,pGdiPlusImage,offset FilenameW,offset CLSID_ImageTypes,NULL
Done:
    ret

SaveColorIndexedImage endp


Function call:

    invoke  GdipCreateBitmapFromFile,offset FilenameW,offset pImage

    invoke  SaveColorIndexedImage,pImage,TEXT_("Guga_Bitmap.png"),Image_PNG,10


The routines are also posted in the thread: Bare Minimum GDIplus code to save different Image Types.
http://masm32.com/board/index.php?topic=8483.0

Sources GDIplusColors.zip
http://masm32.com/board/index.php?action=dlattach;topic=8483.0;attach=10350

NOTE: You can remove the "invoke  GdipCloneImage,pGdiPlusImage,offset pImageTemp" and "invoke  GdipDisposeImage,pImageTemp" lines.
          I used "GdipCloneImage" function to use the same bitmap image over and over again to save multiple image types as an example.

Creative coders use backward thinking techniques as a strategy.

Siekmanski

Hi Guga,

I'm writing the example sources as we speak, hope to finish it tonight, it will give an answer to all your questions.  :biggrin:
Creative coders use backward thinking techniques as a strategy.

guga

Quote from: Siekmanski on October 02, 2020, 03:44:11 AM
Hi Guga,

I'm writing the example sources as we speak, hope to finish it tonight, it will give an answer to all your questions.  :biggrin:

Wahooo :biggrin: :biggrin: :biggrin: :biggrin: :thumbsup: :thumbsup: :thumbsup: :thumbsup: :thumbsup:
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

Quote from: Siekmanski on October 02, 2020, 03:31:23 AMI looked for the maximum count of unique colors in the image guga used.
In guga's .bmp image there are 10 unique colors.
I saved the image as an indexed color image with only 10 entries in the Color Palette.
Now the image only needs 4 bits per index to 1 of the 10 colors.

It creates a lossless image as small as possible.

Hi Marinus,

I had noticed that Guga's bmp has only a few colours, and my old PaintShop Pro knows how to save 16-colour PNGs. So I had a suspicion that you were going for a palette ;-)

Thanks for all the code, this is great stuff :thumbsup:

Siekmanski

Creative coders use backward thinking techniques as a strategy.

Siekmanski

Hi Guga,

Posted the sources here: http://masm32.com/board/index.php?topic=8483.msg96272#msg96272
Creative coders use backward thinking techniques as a strategy.

guga

Thank you a lot, marinus. I´ll take a look :)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com