Graphics to DATA routine

Previous topic - Next topic

MrTAToad

This is the graphics to DATA program.  You need the 8.036 beta and DDGui

Code (glbasic) Select
// --------------------------------- //
// Project: GraphicToDATA
// Start: Friday, July 09, 2010
// IDE Version: 8.036

CONSTANT fileToLoadWidget$ = "fileToLoadWidget"
CONSTANT fileToLoad$ = "fileToLoad"
CONSTANT browseButton$ = "browse"
CONSTANT addButton$ = "add"
CONSTANT listOfFilesList$ = "filesList"
CONSTANT removeFileButton$ = "removeFile"
CONSTANT labelWidget$ = "labelWidget"
CONSTANT labelText$ = "labelText"
CONSTANT processButton$ = "process"
CONSTANT processResult$ = "processResult"
CONSTANT space$ = "    "
CONSTANT VERSION$ = "0.0.0.4"

LOCAL sW%,sH%,text$,label$

GETSCREENSIZE sW%,sH%

DDgui_pushdialog(0,0,sW%,sH%)
DDgui_set("","TEXT","Graphics To DATA ("+VERSION$+")")
DDgui_widget(fileToLoadWidget$,"File To Load :",0,0)
DDgui_text(fileToLoad$,"",sW%-100,0)
DDgui_button(browseButton$,"Browse",0,0)
DDgui_button(addButton$,"Add",0,0)
DDgui_list(listOfFilesList$,"",sW%-12,sH%-108)
DDgui_button(removeFileButton$,"Remove File",0,0)
DDgui_widget(labelWidget$,"Label Name :",0,0)
DDgui_text(labelText$,"graphic",sW%-280,0)
DDgui_button(processButton$,"Process",0,0)
DDgui_widget(processResult$,"",sW%-8,0)

WHILE TRUE
DDgui_show(FALSE)

IF DDgui_get(browseButton$,"CLICKED")
text$=DDgui_FileDialog$(TRUE,"*.*")
IF text$<>"" THEN addFile(listOfFilesList$,text$)
ELSEIF DDgui_get(addButton$,"CLICKED")
text$=DDgui_get$(fileToLoad$,"TEXT")
IF text$<>"" THEN addFile(listOfFilesList$,text$)
ELSEIF DDgui_get(processButton$,"CLICKED")
label$=DDgui_get$(labelText$,"TEXT")
IF label$=""
DDgui_msg("Please supply a valid label name",FALSE)
ELSE
processFiles(listOfFilesList$,label$)
ENDIF
ELSEIF DDgui_get(removeFileButton$,"CLICKED")
removeLine(listOfFilesList$)
ENDIF

SHOWSCREEN
WEND

FUNCTION addFile%:widget$,text$
IF DOESFILEEXIST(text$)
DDgui_set(widget$,"TEXT",DDgui_get$(widget$,"TEXT")+"|"+text$)
ELSE
DDgui_msg("The file doesn't exist",FALSE)
ENDIF
ENDFUNCTION

FUNCTION removeLine%:widget$
LOCAL index%,loop%,text$
LOCAL list$[]

index%=DDgui_get(widget$,"SELECT")
IF index%>=0
IF DDgui_msg("Are you sure that you want to delete this line ?",TRUE)
DIM list$[0]
IF SPLITSTR(DDgui_get$(widget$,"TEXT"),list$[],"|")>0
text$=""
FOR loop%=0 TO BOUNDS(list$[],0)-1
IF loop%<>index%
text$=text$+list$[loop%]+"|"
ENDIF
NEXT
DDgui_set(widget$,"TEXT",LEFT$(text$,LEN(text$)-1))
ELSE
DDgui_msg("There is nothing to split for some reason!",FALSE)
ENDIF
ENDIF
ELSE
DDgui_msg("There is nothing to select",FALSE)
ENDIF
ENDFUNCTION

FUNCTION processFiles%:widget$,label$
LOCAL files$[]
LOCAL data%[]
LOCAL fileLoop$,ext$,count%,found%,extLoop%
LOCAL handle%
LOCAL outputFile$
LOCAL maxDataPerLine%=32
LOCAL sW%,sH%,sprite%
LOCAL error$

handle%=-1
TRY
DIM files$[0]
IF SPLITSTR(DDgui_get$(widget$,"TEXT"),files$[],"|")>0
// Get the output filename
outputFile$=DDgui_FileDialog$(FALSE,"*.gbas")
IF outputFile$="" THEN RETURN FALSE
IF DOESFILEEXIST(outputFile$)
IF DDgui_msg("The file already exists.  Do you want to overwrite it ?",TRUE)
KILLFILE outputFile$
IF DOESFILEEXIST(outputFile$)
DDgui_msg("The file could not be deleted - it must be in use by a program",FALSE)
RETURN FALSE
ENDIF
ELSE
RETURN FALSE
ENDIF
ENDIF

count%=1
handle%=GENFILE()
IF handle%>=0
IF OPENFILE(handle%,outputFile$,0)
FOREACH fileLoop$ IN files$[]
// Validate the extension
found%=FALSE
FOR extLoop%=LEN(fileLoop$)-1 TO 0 STEP -1
IF MID$(fileLoop$,extLoop%,1)="."
ext$=UCASE$(MID$(fileLoop$,extLoop%+1))
IF ext$="JPEG" OR ext$="JPG"
DDgui_msg("JPEG files are not currently supported.  File will be skipped",FALSE)
ELSEIF ext$="PNG" OR ext$="BMP"
found%=TRUE
BREAK
ENDIF
ENDIF
NEXT

IF found%=FALSE
DDgui_msg("The file type is not valid - only PNG and BMP files are allowed.  File will be skipped",FALSE)
ENDIF

IF found%=TRUE
IF DOESFILEEXIST(fileLoop$)
sprite%=GENSPRITE()
IF sprite%>=0
DDgui_set(processResult$,"TEXT","Loading : "+fileLoop$); DDgui_show(FALSE); SHOWSCREEN

LOADSPRITE fileLoop$,sprite%
GETSPRITESIZE sprite%,sW%,sH%
IF sW%>0 AND sH%>0
DIM data%[0]
DEBUG sW%+" "+sH%+"\n" // Currently needed to make sure SPRITE2MEM works for more than 1 sprite
IF SPRITE2MEM(data%[],sprite%)
DEBUG sW%+" "+sH%+"\n" // Currently needed to make sure SPRITE2MEM works for more than 1 sprite
// Only write the GLBasic code once at the start
processData(handle%,data%[],maxDataPerLine%,fileLoop$,count%,sW%,sH%,label$,processResult$)

IF count%<BOUNDS(files$[],0)
WRITELINE handle,"\n"
ENDIF

INC count%
LOADSPRITE "",sprite%
ELSE
THROW "Unable to convert a sprite to data"
ENDIF
ELSE
THROW "Sprite size is invalid"
ENDIF
ELSE
THROW "Unable to get a sprite handle"
ENDIF
ELSE
THROW "A file doesn't exist"
ENDIF
ENDIF
NEXT

CLOSEFILE handle%
DDgui_set(processResult$,"TEXT","Finished"); DDgui_show(FALSE); SHOWSCREEN
ELSE
THROW "Unable to open "+outputFile$
ENDIF
ENDIF
ELSE
THROW "There is nothing to process"
ENDIF
CATCH error$
IF handle%>=0 THEN CLOSEFILE handle%
DDgui_msg(error$,FALSE)
RETURN FALSE
FINALLY

RETURN TRUE
ENDFUNCTION

//! Perform RLE compression on data
FUNCTION processData%:handle%,data%[],maxDataPerLine%,fileName$,count%,sprWidth%,sprHeight%,label$,processResult$
LOCAL loop%,loop2%,found%
LOCAL v1%,v2%,countDup%,numPerLine%,written%
LOCAL text$
LOCAL graphicDataHexSize% = 8 // 4 bytes
LOCAL sizeDataHexSize% = 4 // 2 bytes

text$=""
loop%=0
numPerLine%=0
written%=FALSE
WHILE loop%<BOUNDS(data%[],0)
v1%=data%[loop%]
countDup%=1
INC loop%
WHILE loop%<BOUNDS(data%[],0) AND countDup%<65535 AND data%[loop%]=v1%
IF MOD(loop%,4096)=0
DDgui_set(processResult$,"TEXT",loop%+"/"+countDup%); DDgui_show(FALSE); SHOWSCREEN
ENDIF

INC loop%
INC countDup%
WEND

IF countDup%>1
text$=text$+"*"+decToHex$(countDup%,sizeDataHexSize%)
ENDIF

text$=text$+decToHex$(v1%,graphicDataHexSize%)

INC numPerLine%
IF numPerLine%>maxDataPerLine%
IF written%=FALSE
DDgui_set(processResult$,"TEXT","Writing decompression routine"); DDgui_show(FALSE); SHOWSCREEN

IF count%=1
writeGLBasicCode(handle)
ENDIF

DDgui_set(processResult$,"TEXT","Writing DATA start"); DDgui_show(FALSE); SHOWSCREEN
WRITELINE handle%,"// This is the data for the file "+fileName$
WRITELINE handle%,"STARTDATA "+label$+"_"+count%+":"
WRITELINE handle%,space$+"DATA "+sprWidth%+","+sprHeight%
ENDIF

WRITELINE handle%,space$+"DATA "+CHR$(34)+text$+CHR$(34)

written%=TRUE
text$=""
numPerLine%=0
ENDIF
WEND

// Is there anything left over ?
IF text$<>""
DDgui_set(processResult$,"TEXT","Writing left-over text"); DDgui_show(FALSE); SHOWSCREEN
WRITELINE handle%,space$+"DATA "+CHR$(34)+text$+CHR$(34)
written%=TRUE
ENDIF

IF written%=TRUE
DDgui_set(processResult$,"TEXT","Writing terminator"); DDgui_show(FALSE); SHOWSCREEN
WRITELINE handle%,space$+"DATA "+CHR$(34)+"--------"+CHR$(34)
WRITELINE handle%,"ENDDATA"
ENDIF
ENDFUNCTION

// Fast search
//FUNCTION colourSearch%:value%,colour%[]
//LOCAL loop%
//
// IF BOUNDS(colour%[],0)=0
// DIMPUSH colour%[],value%
// RETURN TRUE
// ELSE
// IF BOUNDS(colour%[],0)=1
// IF colour%[0]=value%
// RETURN TRUE
// ELSE
// RETURN FALSE
// ENDIF
// ENDIF
// ENDIF
//
// FOR loop%=0 TO BOUNDS(colour%[],0)-1
// IF value%=colour%[loop%] THEN RETURN TRUE
// NEXT
//
// DIMPUSH colour%[],value%
// RETURN FALSE
//ENDFUNCTION

// This is the function that creates the function for reading in the data
FUNCTION writeGLBasicCode%:handle%
LOCAL text$

RESTORE readSpriteData
READ text$
WHILE text$<>"*"
text$=REPLACE$(text$,"'",CHR$(34))
text$=REPLACE$(text$,"@","\\")
DDgui_WaitCursor(TRUE)
WRITELINE handle%,text$
READ text$
WEND
ENDFUNCTION

STARTDATA readSpriteData:
DATA "//! This function will create a sprite from lines of hexadecimal pixel data.  You MUST set RESTORE to the appropriate data statement first!"
DATA "//@param  sprite% - The sprite number which will be created.  If this is < 0 then a sprite handle will be automatically found if possible"
DATA "//@return >=0 if the function completed successfully.  The value returned is the sprite number used."
DATA "FUNCTION readSpriteData%:sprite%=-1"
DATA "LOCAL text$,error$,one$,loop%,index%"
DATA "LOCAL array%[]"
DATA "LOCAL textLen% = 32"
DATA "LOCAL hexSize% = 8"
DATA "LOCAL dupSize%  =   4"
DATA "LOCAL width%,height%"
DATA ""
DATA "    TRY"
DATA "        IF sprite%<0"
DATA "            sprite%=GENSPRITE()"
DATA "            IF sprite%<0 THEN THROW 'Unable to get a sprite handle'"
DATA "        ENDIF"
DATA ""
DATA "        READ width%,height%"
DATA "        IF width%<=0 OR height%<=0 THEN THROW 'Sprite width and/or height is invalid'"
DATA "        IF width%*height%<0 THEN THROW 'Sprite width and/or height is too large'"
DATA ""
DATA "        DIM array%[width%*height%]"
DATA "        index%=0"
DATA ""
DATA "        READ text$"
DATA "        WHILE text$<>'--------'"
DATA "        IF LEN(text$)<8 THEN THROW 'A line has an invalid number of characters'"
DATA ""
DATA "            loop%=0"
DATA "            WHILE loop%<LEN(text$)"
DATA "               IF MID$(text$,loop%,1)='*'"
DATA "                  LOCAL value%,amount%"
DATA ""
DATA "                  // Duplicate data"
DATA "                  amount%=hexToDec(MID$(text$,loop%+1,dupSize%))"
DATA "                  value%=hexToDec(MID$(text$,loop%+1+dupSize%,hexSize%))"
DATA "                  WHILE amount%>0"
DATA "                      array%[index%]=value%"
DATA "                      INC index%"
DATA "                      DEC amount%"
DATA "                  WEND"
DATA ""
DATA "                  INC loop%,hexSize%+dupSize%+1"
DATA "               ELSE"
DATA "                   array%[index%]=hexToDec(MID$(text$,loop%,hexSize%))"
DATA "                   INC loop%,hexSize%"
DATA "                   INC index%"
DATA "               ENDIF"
DATA "            WEND"
DATA "            READ text$"
DATA "            SLEEP 1"
DATA "        WEND"
DATA ""
DATA "        // All finished, so we now call the MEM2SPRITE function"
DATA "        IF MEM2SPRITE(array%[],sprite%,width%,height%)=FALSE THEN THROW 'Unable TO convert DATA TO a sprite'"
DATA "    CATCH error$"
DATA "        // Put in your own code to display errors here.  Uncomment to use DDGui"
DATA "        // DDgui_msg(error$,FALSE)"
DATA "        // You MUST keep the following command"
DATA "        RETURN -1"
DATA "    FINALLY"
DATA ""
DATA "    RETURN sprite%"
DATA "ENDFUNCTION"
DATA ""
DATA "//! Convert a hexadecimal number of an integer"
DATA "//param hex$ - Hexidecimal string"
DATA "//@return The decimal value of the passed string"
DATA "FUNCTION hexToDec%:hex$"
DATA "LOCAL i%"
DATA "LOCAL j%"
DATA "LOCAL loop%"
DATA ""
DATA "    i%=0"
DATA "    j%=0"
DATA "    FOR loop%=0 TO LEN(hex$)-1"
DATA "        i%=ASC(MID$(hex$,loop%,1))-48"
DATA "        IF 9<i% THEN DEC i%,7"
DATA "        j%=bOR(j%*16,bAND(i,15))"
DATA "    NEXT"
DATA ""
DATA "    RETURN j%"
DATA "ENDFUNCTION"
DATA ""
DATA "*"
ENDDATA


Code (glbasic) Select
FUNCTION decToHex$:value%,length%=4
IF length%<=0
RETURN "0"
ENDIF

INLINE
DGStr result;
unsigned long value2;
int temp,digit;

value2=(unsigned long) value;
result=DGStr("");

for (digit=length; digit>=1; digit--)
{
temp=value2 % 16;
if (temp<10)
{
result=CHR_Str(temp+48)+result;
}
else
{
result=CHR_Str((temp-10)+65)+result;
}

value2/=16;
}

return result;
ENDINLINE
ENDFUNCTION


One thing that would be useful and thats a better compression/decompression routine.  Gernot suggested storing colours used and then using the index into them.  Other ideas would be to GZIP the graphics into the DATA statements.

Kitty Hello

instead of % 16 I think you can write number & 0xffff.
The / 16 could be written as num >> 4.
No idea if it would be faster then.

MrTAToad

I think the speed gain would be so slight as to be negligible... :)

But I'll update that later on...

MrTAToad

It used the O3 flag for maximum optimisation.  However, more optimisation could be introduced by selecting the processor type...