Author Topic: WIP: BMP-loader (intended for GL)  (Read 116 times)

SkyCharger001

  • Hero Member
  • *****
  • Posts: 1594
WIP: BMP-loader (intended for GL)
« on: March 20, 2013, 01:40:25 PM »
This is derived from technical documentation on the format.
!!highly untested!!
Code: [Select]
TYPE vec
    x AS LONG
    y AS LONG
    z AS LONG
END TYPE
TYPE headertype
    magic AS STRING * 2
    fsize AS LONG
    res AS LONG
    boff AS _UNSIGNED LONG
    headsize AS LONG
    xsize AS LONG
    ysize AS LONG
    planes AS INTEGER
    bpp AS INTEGER
    comp AS LONG
    bmpsize AS LONG
    HorRes AS LONG
    VerRes AS LONG
    UseCol AS LONG
    ImpCol AS LONG
    rmask AS LONG
    gmask AS LONG
    bmask AS LONG
    amask AS LONG
    cstype AS LONG
    rpoint AS vec
    gpoint AS vec
    bpoint AS vec
    gamma AS vec
END TYPE
TYPE bmp2type 'for one specific flavor of BMP
    magic AS STRING * 2
    fsize AS LONG
    res AS LONG
    boff AS _UNSIGNED LONG
    headsize AS LONG
    xsize AS INTEGER
    ysize AS INTEGER
    planes AS INTEGER
    bpp AS INTEGER
END TYPE
ref = _LOADIMAGE("something.bmp", 256)
PRINT ref
a = loadbmp("something.bmp")


SLEEP
SCREEN a
SLEEP
SCREEN ref
SLEEP
SYSTEM
FUNCTION loadbmp (bmpstring AS STRING)
IF _FILEEXISTS(bmpstring) = 0 THEN target = -1: GOTO funcend
OPEN bmpstring FOR BINARY AS #1
DIM target AS LONG
DIM magic AS STRING * 2
DIM bmp AS headertype
DIM bmp2 AS bmp2type
GET 1, 1, bmp
IF bmp.magic <> "BM" THEN target = -1: GOTO funcend
pdiv = 4
SELECT CASE bmp.headsize
    CASE 12 'BMP 2.X
        pdiv = 3
        BMPMODE = 1
        GET 1, 1, bmp2
        bmp.xsize = bmp2.xsize
        bmp.ysize = bmp2.ysize
        bmp.bpp = bmp2.bpp
        bmp.comp = 0
    CASE 40 'BMP 3.X/NT
        IF bmp.comp = 3 THEN BMPMODE = 2 ELSE BMPMODE = 1
    CASE 108 'BMP 4.X
        BMPMODE = 3
END SELECT
IF BMPMODE >= 2 AND bmp.bpp > 8 THEN
    u = 0
    max = bmp.rmask
    DO UNTIL max / 2 > max \ 2
        max = max \ 2
        u = u + 1
    LOOP
    rmax = max + 1
    rdiv = 2 ^ u
    max = bmp.gmask
    u = 0
    DO UNTIL max / 2 > max \ 2
        max = max \ 2
        u = u + 1
    LOOP
    gmax = max + 1
    gdiv = 2 ^ u
    u = 0
    max = bmp.amask
    DO UNTIL max / 2 > max \ 2
        max = max \ 2
        u = u + 1
    LOOP
    bmax = max + 1
    adiv = 2 ^ u
    u = 0
    max = bmp.bmask
    DO UNTIL max / 2 > max \ 2
        max = max \ 2
        u = u + 1
    LOOP
    bmax = max + 1
    bdiv = 2 ^ u
END IF
IF bmp.bpp <= 8 THEN
    target = _NEWIMAGE(bmp.xsize, ABS(bmp.ysize), 256)
ELSE
    target = _NEWIMAGE(bmp.xsize, ABS(bmp.ysize), 32)
END IF
DIM r AS _UNSIGNED _BYTE
DIM g AS _UNSIGNED _BYTE
DIM b AS _UNSIGNED _BYTE
DIM z AS _UNSIGNED _BYTE
_DEST target
GET 1, 14 + bmp.headsize, r
colcount = bmp.boff - 14 - bmp.headsize
colcount = colcount \ pdiv
aby = ABS(bmp.ysize)
sy = SGN(bmp.ysize)
IF bmp.bpp <= 8 THEN
    FOR t = 1 TO colcount
        GET 1, , b
        GET 1, , g
        GET 1, , r
        IF pdiv = 4 THEN GET 1, , z
        _PALETTECOLOR v, _RGB32(r, g, b), target
        v = v + 1
    NEXT t
END IF
GET 1, bmp.boff, r
t = 0
u = aby - 1
IF sy < 0 THEN u = 0
j = bmp.boff + 1
SELECT CASE bmp.bpp
    CASE 1
        FOR j = bmp.boff + 1 TO LOF(1)
            GET 1, , r
            FOR w = 0 TO 7
                PSET (t, u), (r \ (2 ^ (7 - w))) MOD 2
                t = (t + 1) MOD bmp.xsize
                IF t = 0 THEN u = modval(u - sy, 0, aby)
            NEXT w
        NEXT j
    CASE 4
        _PALETTECOLOR 17, _RGB32(255, 255, 255)

        DO UNTIL j >= LOF(1)
            SELECT CASE bmp.comp
                CASE 2
                    IF EOR > 0 THEN
                        j = j + 1
                    ELSE
                        GET 1, j, r
                        GET 1, j + 1, g
                        j = j + 2
                        SELECT CASE r
                            CASE 0

                                SELECT CASE g

                                    CASE 0
                                        IF t > 0 OR sp = 1 THEN
                                            t = 0
                                            u = modval(u - sy, 0, aby)
                                            sp = 1
                                        END IF
                                    CASE 1
                                        EOR = 1
                                    CASE 2
                                        sp = 0
                                        GET 1, , b
                                        GET 1, , z
                                        t = (t + b) MOD bmp.xsize
                                        u = modval(u - (z * sy), 0, aby)
                                        j = j + 2
                                    CASE ELSE
                                        sp = 0
                                        FOR p = 1 TO (g \ 2)
                                            GET 1, , b
                                            cola = b \ 16
                                            IF cola >= bmp.UseCol THEN cola = bmp.UseCol - 1
                                            colb = b MOD 16
                                            IF colb >= bmp.UseCol THEN colb = bmp.UseCol - 1

                                            PSET (t, u), cola
                                            t = (t + 1) MOD bmp.xsize
                                            IF t = 0 THEN u = modval(u - sy, 0, aby)
                                            PSET (t, u), colb
                                            t = (t + 1) MOD bmp.xsize
                                            IF t = 0 THEN u = modval(u - sy, 0, aby)
                                            j = j + 1
                                        NEXT p
                                        IF g MOD 2 = 1 THEN
                                            GET 1, , b
                                            PSET (t, u), cola
                                            t = (t + 1) MOD bmp.xsize
                                            IF t = 0 THEN u = modval(u - sy, 0, aby)
                                            j = j + 1
                                        END IF
                                        IF g MOD 4 >= 2 THEN j = j + 1
                                END SELECT

                            CASE ELSE
                                sp = 0
                                cola = g \ 16
                                IF cola >= bmp.UseCol THEN cola = bmp.UseCol - 1
                                colb = g MOD 16
                                IF colb >= bmp.UseCol THEN colb = bmp.UseCol - 1

                                FOR p = 1 TO (r \ 2)
                                    PSET (t, u), cola MOD 16
                                    t = (t + 1) MOD bmp.xsize
                                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                                    PSET (t, u), colb
                                    t = (t + 1) MOD bmp.xsize
                                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                                NEXT p
                                IF r MOD 2 = 1 THEN
                                    GET 1, , b
                                    PSET (t, u), cola
                                    t = (t + 1) MOD bmp.xsize
                                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                                END IF
                        END SELECT
                    END IF
                CASE ELSE 'no RLE
                    GET 1, , r
                    PSET (t, u), r \ 16
                    t = (t + 1) MOD bmp.xsize
                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                    PSET (t, u), r MOD 16
                    t = (t + 1) MOD bmp.xsize
                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                    j = j + 1

            END SELECT
        LOOP
    CASE 8
        t = 0
        DO UNTIL j >= LOF(1)
            SELECT CASE bmp.comp
                CASE 0
                    GET 1, j, r
                    PSET (t, u), r
                    t = (t + 1) MOD bmp.xsize
                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                    j = j + 1
                CASE 1
                    IF EOR > 0 THEN
                        j = j + 1
                    ELSE
                        GET 1, j, r: GET 1, j + 1, g
                        j = j + 2
                        SELECT CASE r
                            CASE 0
                                SELECT CASE g
                                    CASE 0
                                        IF t > 0 OR sp = 1 THEN
                                            t = 0
                                            u = modval(u - sy, 0, aby)
                                            sp = 1
                                        END IF
                                    CASE 1
                                        EOR = 1
                                    CASE 2
                                        sp = 0
                                        GET 1, , b: GET 1, , z
                                        t = (t + b) MOD bmp.xsize
                                        u = modval(u - (z * sy), 0, aby)
                                        j = j + 2
                                    CASE ELSE
                                        sp = 0
                                        FOR p = 1 TO g
                                            GET 1, , b
                                            PSET (t, u), b
                                            t = (t + 1) MOD bmp.xsize
                                            IF t = 0 THEN u = modval(u - sy, 0, aby)
                                            j = j + 1
                                        NEXT p
                                        IF g MOD 2 THEN j = j + 1
                                END SELECT
                            CASE ELSE
                                sp = 0
                                FOR p = 1 TO r
                                    PSET (t, u), g
                                    t = (t + 1) MOD bmp.xsize
                                    IF t = 0 THEN u = modval(u - sy, 0, aby)
                                NEXT p
                        END SELECT
                    END IF
            END SELECT


        LOOP
    CASE 16
        rdiv = rdiv / 65536
        gdiv = gdiv / 65536
        bdiv = bdiv / 65536
        adiv = adiv / 65536
        DIM p AS _UNSIGNED INTEGER

        FOR j = bmp.boff + 1 TO LOF(1) STEP 2
            GET 1, , p
            r = (p \ rdiv) MOD rmax
            g = (p \ gdiv) MOD gmax
            b = (p \ bdiv) MOD bmax
            IF BMPMODE = 2 THEN
                a = 255
            ELSE
                a = (p \ adiv) MOD amax
                a = 255 * a / (amax - 1)
            END IF
            r = 255 * r / (rmax - 1)
            g = 255 * g / (gmax - 1)
            b = 255 * b / (bmax - 1)
            PSET (t, u), _RGBA(r, g, b, a)
            t = (t + 1) MOD bmp.xsize
            IF t = 0 THEN u = modval(u - sy, 0, aby)

        NEXT j
    CASE 24


        FOR j = bmp.boff + 1 TO LOF(1) STEP 3
            GET 1, , b
            GET 1, , g
            GET 1, , r
            PSET (t, u), _RGB(r, g, b)
            t = (t + 1) MOD bmp.xsize
            IF t = 0 THEN u = modval(u - sy, 0, aby)

        NEXT j
    CASE 32
        DIM up AS _UNSIGNED LONG

        FOR j = bmp.boff + 1 TO LOF(1) STEP 4
            GET 1, , up
            r = (up \ rdiv) MOD rmax
            g = (up \ gdiv) MOD gmax
            b = (up \ bdiv) MOD bmax
            IF BMPMODE = 2 THEN
                a = 255
            ELSE
                a = (up \ adiv) MOD amax
                a = 255 * a / (amax - 1)
            END IF
            r = 255 * r / (rmax - 1)
            g = 255 * g / (gmax - 1)
            b = 255 * b / (bmax - 1)
            PSET (t, u), _RGBA(r, g, b, a)
            t = (t + 1) MOD bmp.xsize
            IF t = 0 THEN u = modval(u - sy, 0, aby)

        NEXT j

END SELECT
funcend:
loadbmp = target
END FUNCTION
FUNCTION modval (tv, min, max)
v = tv
mcheck:
IF v < min THEN
    v = v + max - min
    GOTO mcheck
END IF
IF v >= max THEN
    v = v - max + min
    GOTO mcheck
END IF
modval = v
END FUNCTION

edit: added preliminary support for 16/32 bit color-modes
edit2: RLE4/8 now functional

only thing I need now are a few bitmaps to test it against, at least one of each flavor. (excepting BMP1.X, it's been deprecated since Windows 2.0 as it was a device-dependent-bitmap as opposed to the device-INdependent-bitmaps of the later versions.)

bmp3.0 confirmed.
bmp2.0, 3.NT, 4.0+ untested
« Last Edit: March 27, 2013, 11:40:42 AM by SkyCharger001 »