Author Topic: Z Project - universal screen size scaling system  (Read 30029 times)

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
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
« Last Edit: 2012-Feb-13 by ampos »
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

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Re: Z Proyect
« Reply #1 on: 2011-Oct-25 »
Good stuff. Can be used as a basis for scalable control schemes too.

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
Re: Z Proyect
« Reply #2 on: 2011-Oct-26 »
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

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
Re: Z Proyect
« Reply #3 on: 2011-Dec-20 »
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

Offline bigsofty

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 2490
    • View Profile
Re: Z Proyect
« Reply #4 on: 2011-Dec-20 »
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)

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
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.

Offline monono

  • Mr. Polyvector
  • ***
  • Posts: 213
    • View Profile
    • Sockel Lernmedien
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. :)

Offline Moru

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 1750
    • View Profile
    • Homepage
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 :-)

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
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

Offline Ruidesco

  • Mr. Polyvector
  • ***
  • Posts: 236
    • View Profile
Better yet, swap "universal" for "standard" and call it Project S5. :D

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
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

Offline mrplant

  • Mr. Polyvector
  • ***
  • Posts: 232
    • View Profile
great!

Offline mrplant

  • Mr. Polyvector
  • ***
  • Posts: 232
    • View Profile
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

Offline ampos

  • Prof. Inline
  • *****
  • Posts: 1592
    • View Profile
    • AMpostata Website
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

Offline mrplant

  • Mr. Polyvector
  • ***
  • Posts: 232
    • View Profile
Thought that's what it would be but just wanted to make sure!

cheers Ampos!