Z Project - universal screen size scaling system

Previous topic - Next topic

ampos

Yes, it is (again) a UNIVERSAL SCREEN SIZE SCALING SYSTEM   :S

I had the idea to port ALL gfx commands to use polyvectors and be resolution independents, so we can code to just 1 resolution and will work at all platforms, using the (almost) fastest polyvector system, targetting any target resolution with/without aspect ratio.

To start, I have made the initialization function and ported the very first function, DRAWSPRITE. If one of each us made 1 function, it could be done real soon. I will copy your functions to this first post to keep it updated. Please, post the function you are going to do before so no one else does the same.

HOW-TO USE

In your proyect, you only need to change the CONSTANTS x_orig and y_orig with the values of the screen size you are coding for (the size that will draw at size 1:1).

Call the "z_init" function at the start of your program. If you dont want it to keep the aspect ratio of your graphics, call it with value=0

That's all, just call the functions as if they were original GLBasic commands, same syntax. (Note that I added the "color" param to the function as optional; as it is going to be used by polyvector anyway, just put it!)

You call the functions with "absolute" values, as if they were for a fixed screen size. The commands themself will scale your graphics to the device resolution, leaving black borders for unused screen.

In many console games (I recall some Wii examples) they draw a background that fills the entire screen and the game is drawn really in a center 4:3 "window" in the center of the screen. An iPAD (1024x768) resolution game will look similar in a 800x480 android device. If you do not want the screen to be filled with black borders, just do this:

Code (glbasic) Select
CLEARSCREEN -1 //if the entire screen is going to be redrawn, do not clear it before!
...your game here
SC()   //use this instead of showscreen

function SC:  //this routine will fill your entire screen with a nice background
   showscreen
   stretchsprite background,0,0,x_res,y_res
endfunction


Example:
   x_orig=1024;z_drawsprite id,512,0 will be always drawn at the center of the screen, even at a 320x240 screen resolution.

Code (glbasic) Select
// --------------------------------- //
// Project: ProjectoZ
// Start: Tuesday, October 25, 2011
// IDE Version: 10.118

GLOBAL x_offset,y_offset //offset to add to X&Y to display correctly
GLOBAL x_res,y_res //X&Y real screen size
GLOBAL x_zoom,y_zoom //zoom to scale sprites and so
GLOBAL x_orig=768,y_orig=1024 //the screen size our app is designed for
GLOBAL single_sheet=0 //1 IF all sprites in a single sheet

FUNCTION initZ: keep_ratio=0
LOCAL z

GETSCREENSIZE x_res,y_res

x_zoom=x_res/x_orig
y_zoom=y_res/y_orig

IF keep_ratio<>0
z=MIN(x_zoom,y_zoom)
x_zoom=z
    y_zoom=z
x_offset=(x_res-(x_orig*x_zoom))/2
y_offset=(y_res-(y_orig*y_zoom))/2
IF x_offset<1 THEN x_offset=0
IF y_offset<1 THEN y_offset=0

ENDIF

init_SC()

ENDFUNCTION

FUNCTION z_drawsprite: num%,x%,y%,color=0xFFFFFF
LOCAL sx,sy,x1,y1,x2,y2

GETSPRITESIZE num,sx,sy

x1=x_offset+(x*x_zoom)
x2=sx*x_zoom
y1=y_offset+(y*y_zoom)
y2=sy*y_zoom

// STRETCHSPRITE num,x1,y1,x2,y2

STARTPOLY num
POLYVECTOR x1,y1,0,0,color
POLYVECTOR x1,y1+y2,0,sy,color
POLYVECTOR x1+x2,y1+y2,sx,sy,color
POLYVECTOR x1+x2,y1,sx,0,color
ENDPOLY

ENDFUNCTION

FUNCTION z_drawanim: num%,frame%,x%,y%,w%,h%,color=0xFFFFFF
LOCAL sx,sy,x1,y1,x2,y2,ancho,alto,xa,ya

GETSPRITESIZE num,sx,sy

x1=x_offset+(x*x_zoom)
x2=w*x_zoom
y1=y_offset+(y*y_zoom)
y2=h*y_zoom

ancho=sx/w;alto=sy/h
ya=INTEGER(frame/ancho)*h
xa=MOD(frame,ancho)*w

// STRETCHANIM num,frame,x1,y1,x2,y2

IF single_sheet=0 THEN STARTPOLY num
POLYVECTOR x1,y1,xa,ya,color //TL
POLYVECTOR x1,y1+y2,xa,ya+h,color //BL
POLYVECTOR x1+x2,y1+y2,xa+w,ya+h,color //
POLYVECTOR x1+x2,y1,xa+w,ya,color
IF single_sheet=0
ENDPOLY
ELSE
POLYNEWSTRIP
ENDIF
ENDFUNCTION

FUNCTION z_rotozoomanim: num%,frame%,x%,y%,w%,h%,ang,size,color=0xFFFFFF
LOCAL sx,sy,x1,y1,x2,y2,ancho,alto,xa,ya,x3,x4,y3,y4,xcos,ysin,xs,ys,sw,sh

GETSPRITESIZE num,sx,sy
sw=w;sh=h

x=x_offset+(x*x_zoom)-(((w*size)-w)/2)
w=w*x_zoom*size
y=y_offset+(y*y_zoom)-(((h*size)-h)/2)
h=h*y_zoom*size
INC x2,x1;INC y2,y1

ancho=sx/sw;alto=sy/sh
ya=INTEGER(frame/ancho)*sh
xa=MOD(frame,ancho)*sw

h=h/2
w=w/2
INC x,w
INC y,h

x1 = x
y1 = y
x2 = x
y2 = (y + h)
x3 = (x + w)
y3 = y
x4 = (x + w)
y4 = (y + h)

xcos = tCOS(ang)
ysin = tSIN(ang)

x1 = x - (xcos * w) - (ysin * h)
y1 = y - (xcos * h) + (ysin * w)

x2 = x - (xcos * w) + (ysin * h)
y2 = y + (xcos * h) + (ysin * w)

x3 = x + (xcos * w) - (ysin * h)
y3 = y - (xcos * h) - (ysin * w)

x4 = x + (xcos * w) + (ysin * h)
y4 = y + (xcos * h) - (ysin * w)

SELECT single_sheet
CASE 0
STARTPOLY num
POLYVECTOR x1, y1, xa, ya,color //TL
POLYVECTOR x2, y2, xa, ya + sh,color //BL
POLYVECTOR x4, y4, xa + sw, ya + sh,color //BR
POLYVECTOR x3, y3, xa + sw, ya,color //TR
ENDPOLY
CASE 1
POLYVECTOR x2, y2, xa, ya + sh,color //BL
POLYVECTOR x1, y1, xa, ya,color //TL
POLYVECTOR x4, y4, xa + sw, ya + sh,color //BR
POLYVECTOR x3, y3, xa + sw, ya,color //TR
POLYNEWSTRIP
ENDSELECT

ENDFUNCTION

FUNCTION z_print: t$,x,y,font=100,centered=1,zoom=1,color=0xFFFFFF,underline=0,italic=0
LOCAL fx,fy,l,c$,tx,ty,dx,dy,fxz,fyz,t1,t2,t3,t4,tl
LOCAL line_width=2 //width of the underline line in pixels at zoom 1 (100%)
LOCAL outline=2 //width of the outline in underline in pixels at zoom 1 (100%)
LOCAL und_pos=.9 //vertical position of underline (in % of Font Y size)
LOCAL ital_ang=.5 //inclination of font (in % of font X size)

GETSPRITESIZE font,fx,fy
fx=fx/16;fy=fy/16 //change to fy/8 if you dont use full charset fonts
        fxz=fx*zoom*x_zoom;fyz=fy*zoom*y_zoom
        tl=LEN(t$,1)*zoom*x_zoom

x=x_offset+(x*x_zoom)
y=y_offset+(y*y_zoom)

DEC x,(LEN(t$,1)*zoom*centered*x_zoom)/2

IF underline=1   
t1=line_width*(zoom*y_zoom);IF t1<1 THEN t1=1
t2=fxz/4
t3=fyz*und_pos
t4=outline*(zoom*x_zoom);IF t4<1 THEN t4=1

STARTPOLY   //this can be changed with a call to z_drawline...
POLYVECTOR x-t2-t4,y+t3-t4,0,0,0
POLYVECTOR x-t2-t4,y+t3+t1+t4,0,0,0
POLYVECTOR x+t2+tl+t4,y+t3+t1+t4,0,0,0
POLYVECTOR x+t2+tl+t4,y+t3-t4,0,0,0
ENDPOLY

STARTPOLY
POLYVECTOR x-t2,y+t3,0,0,color
POLYVECTOR x-t2,y+t3+t1,0,0,color
POLYVECTOR x+t2+tl,y+t3+t1,0,0,color
POLYVECTOR x+t2+tl,y+t3,0,0,color
ENDPOLY

ENDIF

    italic=italic*zoom*fx*ital_ang*x_zoom
STARTPOLY font,2
FOR n=0 TO LEN(t$)-1
c$=MID$(t$,n,1)
l=ASC(c$)

ty=ASR(l,4)
tx=INTEGER(MOD(l,ty*16))
dx=tx*fx
dy=ty*fy

POLYVECTOR x,y+fyz,dx,dy+fy,color //BL
POLYVECTOR x+italic,y,dx,dy+1,color //TL
POLYVECTOR x+fxz,y+fyz,dx+fx,dy+fy,color //BR
POLYVECTOR x+fxz+italic,y,dx+fx,dy+1,color //TR
POLYNEWSTRIP
INC x,LEN(c$,1)*zoom*x_zoom
NEXT
ENDPOLY
ENDFUNCTION

FUNCTION z_drawline: x1,y1,x2,y2,color=0xFFFFFF,width=1
LOCAL w=(x2-x1)*x_zoom
LOCAL h=(y2-y1)*y_zoom

x1=x_offset+(x1*x_zoom)
y1=y_offset+(y1*y_zoom)
x2=x_offset+(x2*x_zoom)
y2=y_offset+(y2*y_zoom)

width=width*x_zoom
glLineWidth (width)
DRAWLINE x1,y1,x2,y2,color
glLineWidth(1)

// STARTPOLY
// POLYVECTOR x1,y1,0,0,color
// POLYVECTOR x1+w,y1+h,0,0,color
// POLYVECTOR x1+w+1,y1+1+h,0,0,color
// POLYVECTOR x1+1,y1+1,0,0,color
// ENDPOLY

ENDFUNCTION

FUNCTION z_drawrect: x,y,w,h,color=0xFFFFFF

x=x_offset+(x*x_zoom)
y=y_offset+(y*y_zoom)
w=w*x_zoom
h=h*y_zoom

STARTPOLY
POLYVECTOR x,y,0,0,color
POLYVECTOR x,y+h,0,0,color
POLYVECTOR x+w,y+h,0,0,color
POLYVECTOR x+w,y,0,0,color
ENDPOLY

ENDFUNCTION

INLINE
#define OGL ::
typedef float           GLfloat;
ENDINLINE

INLINE
} extern "C" { void __stdcall glLineWidth( GLfloat width );; }; namespace __GLBASIC__ {
ENDINLINE
FUNCTION glLineWidth: width
INLINE
OGL glLineWidth(width);
ENDINLINE
ENDFUNCTION


INLINE
} //  + + + A T T E N T I O N + + +
// int __a__ needs to be a n^2 value.
// Higher values give better precision
// but larger lookup tables as well!

const unsigned int __a__ = 131072 ;
const DGInt __b__ = (360.0 / __a__) ;
const unsigned int __c__ = (__a__ - 1) ;
DGInt _sin_tbl_[__c__] ;
DGInt _cos_tbl_[__c__] ;
const DGInt __d__ = (1 / __b__);
namespace __GLBASIC__ {
ENDINLINE

FUNCTION init_SC:
INLINE
for(int i=0; i < __c__; ++i)
{
_sin_tbl_[i] = SIN( i * __b__ ) ;
_cos_tbl_[i] = COS( i * __b__ ) ;
}
ENDINLINE
ENDFUNCTION // INIT_SIN_COS_TABLES

// ------------------------------------------------------------- //
// ---  TCOS  ---
// ------------------------------------------------------------- //
FUNCTION tCOS: x // in degrees
INLINE
return _cos_tbl_[ (int)(x * __d__) & __c__ ] ;
ENDINLINE
ENDFUNCTION // TCOS



// ------------------------------------------------------------- //
// ---  TSIN  ---
// ------------------------------------------------------------- //
FUNCTION tSIN: x  // in degrees
INLINE
return _sin_tbl_[ (int)(x * __d__) & __c__ ] ;
ENDINLINE
ENDFUNCTION // TSIN






HOW TO MAKE FUNCTIONS

I think that the z_drawsprite function is easy enough to understand, but to clarify how to calculate target resolutions

Initial X & Y coordinates are calculated with

Code (glbasic) Select
x1=x_offset+(x*x_zoom)
y1=y_offset+(y*y_zoom)


You have to use, mandatory, x_offset & y_offset, as the init function will set this values correctly if the user wants or not "aspect ratio lock"

The target sprite sizes are easily calculated too with

Code (glbasic) Select
x2=sx*x_zoom
y2=sy*y_zoom


being sx and sy, current sprite size.

0.01 - Initial release
        - DRAWSPRITE
0.02 - PRINT (with attributes)
0.03 - DRAWLINE
          DRAWRECT
          Added a "+1" on z_print text print part to fix gfx glitches
0.04 - DRAWANIM (it needs in the function the size of the anim frame)
          ROTOZOOMANIM (it needs in the function the size of the anim frame
          Uses tCOS and tSIN for faster SIN/COS
          Updated PRINT to use POLYNEWSTRIP
          The variable SINGLESHEET can be used to use POLYNEWSTRIP when drawing multiple sprites from a single sheet.
          The DRAWLINE command has the option WIDTH, through OpenGL itself.
0.05- Minor update. Removed some old lines. Add more explanations for use.
0.06- RotoZoomAnim had a bug
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

Wampus

Good stuff. Can be used as a basis for scalable control schemes too.

ampos

Added  Z_PRINT.

Nobody wants to contribute?
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

ampos

I have added more things:

DRAWANIM, that needs also the size of the sprite animation frame.

ROTOZOOMANIM, also need the frame size. It uses also tCOS and tSIN functions for speed.

The DRAWLINE get a WIDTH option, that is set using OpenGL.

PRINT uses POLYNEWSTRIP, making it much more faster.

Some functions read the global variable SINGLESHEET. If =1, they will use POLYNEWSTRIP, making it MUCH faster if you are drawing multiple sprites from the same sprite sheet.

Example:

You have a sheet with multiple flowers pictrures. You normally will use this to draw:

Code (glbasic) Select
FOREACH f IN flowers()
   Z_DRAWSPRITE f.id,f.x,f.y
NEXT
SHOWSCREEN


That will be

Code (glbasic) Select
FOREACH f IN flowers()
   Z_DRAWANIM f.id,f.frame,f.x,f.y
       {STARTPOLY f.id
       ...blah...blah POLYVECTOR
       ENDPOLY}
NEXT
SHOWSCREEN


Ok, the SINGLESHEET has to be done this way:

Code (glbasic) Select
SINGLESHEET=1
STARTPOLY id,2
FOREACH f IN flowers()
   Z_DRAWSPRITE f.id,f.x,f.y
NEXT
ENDPOLY
SHOWSCREEN


Will translate into:

Code (glbasic) Select
SINGLESHEET=1
STARTPOLY id,2
FOREACH f IN flowers()
   Z_DRAWSPRITE f.id,f.x,f.y
      {blah, blah... POLYVECTOR
      NEWPOLYSTRIP}
NEXT
ENDPOLY
SHOWSCREEN


Probably I will not create DRAWANIM or ROTOSPRITE as it can be used easily in ROTOZOOMANIM with frame=0

check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

bigsofty

Congrats and thanks Ampos, great stuff!  :good:
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

Wampus

Ampos you are generous with your code.  :booze:

If anyone relatively new to GLBasic is reading this thread and isn't sure if they need code like this, YOU DO! It is kind of essential if you want games to work on multiple resolutions without necessarily knowing what the resolution will be. For example, with Android, your game could start in many different resolutions depending on device. The thing Ampos is doing with POLYVECTOR is also very useful. Although its more complicated than the sprite commands it is also quicker when used properly. That can make a big difference to performance on slower devices.

monono

Nicely done. Much nicer than copying and scaling the screen. This is some kind of the approach I use too. I would change the name. "z". It reminds me of the 3th dimension."v" like "virtual screen" would suit better. :)

Moru

Great stuff, this is the way I would like to do it. Naming with Z is a bit strange though, as Z-order usually is the order you paint it on the screen, from back to front. That was what I was expecting to find here :-)

ampos

Really I dont remember why I call it "Proyect Z", perhaps it is best to call it...

PROJECT USSSS

universal screen size scaling system  :S
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

Ruidesco

Better yet, swap "universal" for "standard" and call it Project S5. :D

ampos

RotoZoomAnim had a bug

Code (glbasic) Select
xcos = tCOS(ang/4)
ysin = tSIN(ang/4)


and has to be

Code (glbasic) Select
xcos = tCOS(ang)
ysin = tSIN(ang)
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

mrplant


mrplant

Hi Ampos.

In your z_print function you have a line of code:

   DRAWRECT x,y,2,2,0

what is this line for?
Just I remove it and everything still looks the same to me?

thanks
mrp

ampos

It was just a reference on-screen "point", should not be gone to "final production"  =D

removed.
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

mrplant

Thought that's what it would be but just wanted to make sure!

cheers Ampos!