Generic graphics loading routine

Previous topic - Next topic

Crivens

Ok, so you have designed everything to work on an iPhone 4 with retina display. However you want all the graphics to also work on an older iPhone (or any other device really) without having to have the program always load in the full sized graphics using up far more memory than it really needs to use.

So what this routine does is work out the ratio of your current device compared to the target device which you designed all your graphics for. It then (if the ratio is not 1-1) resizes everything to fit the current device and saves into a separate directory (iPhone cannot write to the MEDIA directory by the looks of things) to load forever after. You can get it to rescan everything by using a ver.txt file in the media directory that you load a new value into every time you have new graphics (so just update ver.txt when making an update to the app store and you have changed your graphics). It also uses sprite2mem so all the alpha values of semi transparent graphics can be kept (rather than just resizing and grabbing the sprite again).

That's about it really. I'm sure someone can improve on it (some kind of smoothing operation when it resizes would be good) or point out some bugs as I just knocked it up quickly. Note that jpgs seem to crash it, but I believe this is just a bug in GLB fullstop. The build in font system is also a bit glitchy, but I think it is because mucking about with the built in functionality. Use your own bitmap routine instead basically. Also note it will also scale up. ie. make graphics bigger if on a higher resolution than intended. On a PC you should be really using the target resolution, but if you want to test then keep changing the ver.txt value in media, or for a quicker method removing the ver.txt file from the secondary storage (it's in documents).

Code (glbasic) Select
// --------------------------------- //
// Project: AlphaTest
// Start: Friday, June 03, 2011
// IDE Version: 9.040


SETCURRENTDIR("Media") // Will use this directory if using target device

TYPE tMouse
x%
y%
active%
ENDTYPE
GLOBAL mouse[] AS tMouse
DIM mouse[5]
SYSTEMPOINTER TRUE

?IFDEF WIN32
SETSCREEN 320,480,0 //Pretend to be an older iPhone - Note should always be the same as target on a PC, but remove/change ver.txt to auto update graphics if choose to test resolutions
?ENDIF

GLOBAL dx#,dy#
GETSCREENSIZE dx#,dy#
GLOBAL targetx#=640 //Graphics originally made for
GLOBAL targety#=960 //Retina display iPhone 4
GLOBAL x#;x=dx/targetx //This works as one command with local, not with global however...
GLOBAL y#;y=dy/targety
GLOBAL docdir$;docdir$=PLATFORMINFO$("DOCUMENTS")+"/alphatest-bin" //Has to be different for iPhone as cannot update MEDIA directory
GOSUB remapall

TYPE stype
x%
y%
width%
height%
s%
text$
visible%
ENDTYPE
GLOBAL spr[] AS stype
DIM spr[0]
GLOBAL tspr AS stype

tspr.s=GENSPRITE()
LOADSPRITE "1.png",tspr.s
tspr.x=10;tspr.y=50;tspr.text$="1";tspr.visible=1
GETSPRITESIZE tspr.s,tspr.width,tspr.height;tspr.width=tspr.width/x;tspr.height=tspr.height/y
DIMPUSH spr[],tspr
tspr.s=GENSPRITE()
LOADSPRITE "2.png",tspr.s
tspr.x=400;tspr.y=700;tspr.text$="2";tspr.visible=1
GETSPRITESIZE tspr.s,tspr.width,tspr.height;tspr.width=tspr.width/x;tspr.height=tspr.height/y
DIMPUSH spr[],tspr

CLEARSCREEN
LOADBMP "background.png"
LOCAL myfont=GENFONT()
LOADFONT "myfont.png",myfont //Font's dont really work well. Resized ones need to be resaved in a paint package (eg. PSP8) to regain transparency but rarely still looks good. May have to use own routine for text, or just have a few different ones
LOCAL tprint$="0"
LOCAL oprint$=tprint$
LOCAL sloop%

//Remember to show anything using x/y ratios (see below)
WHILE 1=1
IF INKEY$()<>"" THEN BREAK
ALPHAMODE -1
updateMice()
tprint$=oprint$
FOR sloop=0 TO BOUNDS(spr[],0)-1
IF spr[sloop].visible
DRAWSPRITE spr[sloop].s,x*spr[sloop].x,y*spr[sloop].y
IF mouse[0].active=1 //Click (and hold) on a sprite to see its text
IF mouse[0].x>=spr[sloop].x AND mouse[0].x<=spr[sloop].x+spr[sloop].width AND mouse[0].y>=spr[sloop].y AND mouse[0].y<=spr[sloop].y+spr[sloop].height
tprint$=spr[sloop].text$
ENDIF
ENDIF
ENDIF
NEXT
PRINT tprint$,x*10,y*10,10
SHOWSCREEN
WEND
END

SUB remapall: //Takes all pictures and resizes them for the device being used
IF x<>1 AND y<>1 //If exactly the same then you are using the device made for
CREATEDIR(docdir$)
LOCAL needresize=1
IF DOESFILEEXIST(docdir$+"/ver.txt") //Must exist in target directory
IF DOESFILEEXIST("ver.txt") //And in media directory
LOCAL file1=GENFILE()
OPENFILE(file1,docdir$+"/ver.txt",TRUE)
LOCAL file2=GENFILE()
OPENFILE(file2,"ver.txt",TRUE)
LOCAL file1line$,file2line$
READLINE file1,file1line$
READLINE file2,file2line$
IF file1line$=file2line$ THEN needresize=0
CLOSEFILE file1
CLOSEFILE file2
ENDIF
ENDIF
IF needresize=1
LOCAL file$[],num,i
num=GETFILELIST("*.*",file$[])
IF num>0
FOR i=0 TO BOUNDS(file$[],0)-1
remapimage(file$[i])
NEXT
ENDIF
COPYFILE "ver.txt",docdir$+"/ver.txt"
ENDIF
SETCURRENTDIR(docdir$)
ENDIF
ENDSUB

FUNCTION remapimage:file$ //Takes a picture and resizes it for the device being used
IF DOESFILEEXIST(file$)
LOCAL rightf$=UCASE$(RIGHT$(file$,3))
IF rightf$="PNG" OR rightf$="BMP" OR rightf$="JPG" //I know it says it can but JPG just doesn't work. Wrong colours and crashes a lot. Use PNG!
LOCAL width,height
LOCAL usesprite=GENSPRITE()
LOADSPRITE file$,usesprite
GETSPRITESIZE usesprite,width,height
LOCAL pix%[]
LOCAL ok%=SPRITE2MEM(pix[],usesprite)
LOCAL pix2%[]
LOCAL xwidth%=width*x
IF INTEGER(xwidth)<>xwidth THEN xwidth=INTEGER(xwidth)+1
LOCAL xheight%=height*y
IF INTEGER(xheight)<>xheight THEN xheight=INTEGER(xheight)+1
DIM pix2%[xwidth*xheight]
LOCAL xl
LOCAL bx,by
FOR xl=0 TO BOUNDS(pix2[],0)-1
bx=INTEGER(MOD(xl,xwidth)/x)
by=INTEGER(INTEGER(xl/xwidth)/y)
pix2[xl]=pix[bx+by*width]
NEXT
LOCAL usesprite2=GENSPRITE()
MEM2SPRITE(pix2[], usesprite2, xwidth, xheight)
SAVESPRITE docdir$+"/"+file$,usesprite2
LOADSPRITE "",usesprite
LOADSPRITE "",usesprite2
ENDIF
ENDIF
ENDFUNCTION

FUNCTION debug_out: in$
LOCAL out$
out$="[APP] "+MID$(PLATFORMINFO$("TIME"),11,8) + ": "+ in$+"\n"
?IFDEF IPHONE
STDOUT out$
?ELSE
DEBUG out$
?ENDIF
ENDFUNCTION

FUNCTION updateMice:
LOCAL imouse%,mx%, my%, b1%, b2%
FOR imouse% = 0 TO MIN(GETMOUSECOUNT()-1,4)
SETACTIVEMOUSE imouse%
MOUSESTATE mx%, my%, b1%, b2%
mouse[imouse].x=mx/x
mouse[imouse].y=my/y
mouse[imouse].active=b1
NEXT
ENDFUNCTION


Cheers

[attachment deleted by admin]
Current fave quote: Cause you like musicians and I like people with boobs.

erico

this seems quite handy, congrats! :good:

spicypixel

Useful but personally I always think it better to create all the graphics needed individually for all resolutions. Resizing could be useful when you have an Android screen of 800x480 and an iPhone of 480x320 which are different aspect ratios. Still you have given me food for thought, nice post.
http://www.spicypixel.net | http://www.facebook.com/SpicyPixel.NET

Comps Owned - ZX.81, ZX.48K, ZX.128K+2, Vic20, C64, Atari-ST, A500.600.1200, PC, Apple Mini-Mac.

Crivens

I know what you mean but I mainly wanted something to easily go between iPhone 4 and iPhone 3 which have the same aspect ratios. It will work with other aspect ratios but obviously can look squished or stretched. Possibly using the target ratio is another idea and then use the remainder for adverts or some kind of border (ie a routine to place everything in the centre). Hmm.

Cheers
Current fave quote: Cause you like musicians and I like people with boobs.