GLBasic forum

Main forum => GLBasic - en => Topic started by: Stevester on 2011-Jun-14

Title: Hi there - Newb Question :)
Post by: Stevester on 2011-Jun-14
Hi there,

I'm looking at GLBasic as a replacement to DBPro and have downloaded and been playing with it tonight.

Love some of the sample games out there, especially those with the vector style 'glowy' graphics (glowingrocksfromouterspace, scramble, etc)! I'm a ways off from anything like that tho. :)

Anyhoo, I'm made my first 'Hello World' program and am well on the way but have a question on my second (and most complex program to date) . . . .

I'm trying to display lots of random rectangles on the screen, adding one with each loop but I'm finding the SHOWSCREEN command appears to be getting in the way as its clearing the screen on every loop. What I'm wanting is to add a rectangle to screen on every loop rather than draw, show, clear, repeat.

This is what I have so far:

REPEAT
      DRAWRECT RND(800), RND(600), RND(100), RND(100), RGB(RND(255), RND(255), RND(255))
      SHOWSCREEN
UNTIL KEY(28)
MOUSEWAIT
END

I don't want the showscreen command to clear the backscreen every time, I want the rectangles to randomly overlap and fill the screen. Is there an alternative command to use to draw to the main screen or prevent the backscreen from wiping?

Any help would be appreciated. :)

Steve.
Title: Re: Hi there - Newb Question :)
Post by: MrTAToad on 2011-Jun-14
You could use CLEARSCREEN -1 for a blurry effect.  However, unlike DBPro, you do have to render all graphics for each display loop, which does give you the power to change the order of rendering.
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
What you can do is render each rectangle to a sprite/screen and then display that.

Code (glbasic) Select

// Set screen resolution (Windowed mode=0 - full screen=1)
SETSCREEN 800,600,0

// Create a virtual screen and use it as sprite #999
CREATESCREEN 1,999,640,480

// Repeat until ESC pressed
WHILE TRUE

// Switch all drawing processes to the virtual screen
USESCREEN 1

// Draw rectangles ONTO the virtual screen sprite
DRAWRECT RND(800), RND(600), RND(100), RND(100), RGB(RND(255), RND(255), RND(255))

// Switch back to normal screen
USESCREEN -1

// Draw the virtual screen sprite
DRAWSPRITE 999,0,0

// Update the screen
SHOWSCREEN

// Repeat loop if WEND condition is not met
WEND


:)
Title: Re: Hi there - Newb Question :)
Post by: Moru on 2011-Jun-14
Or USEASBMP

Oh, and welcome to the boards :-)
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
USEASBMP will capture the entire screen and ANY and ALL changes. This would be OK for the example above, as there's no moving elements and you just want to update the rectangles. IIRC it also takes CPU time to use this.

My code above will only capture what is drawn onto the virtual screen, so you can have other things moving over/on/behind the sprite image and they won't appear repeatedly in the scene. Obviously the request was only for DRAWRECTs and this would work fine (as I said above), but if you want anything else moving on screen as well, then avoid USEASBMP (or you can end up with some very funky and cool effects).

And yes, welcome :)
Title: Re: Hi there - Newb Question :)
Post by: ampos on 2011-Jun-14
Code not tested, just typing "online" :)
Code (glbasic) Select

type r
x;y;w;h
endtype

dim rect[] as r

repeat
s=bounds(rect[],0)
redim rect[s]
rect[s].x=rnd(100) rect[s].y=rnd(100) rect[s].w=rnd(100) rect[s].h=rnd(100)
for each box in rect[]
   drawrect box.x,box.y,box.w,box.h
next
showscreen
until exit=true
Title: Re: Hi there - Newb Question :)
Post by: quangdx on 2011-Jun-14
I second Ian Price on his solution,
as I was about to suggest the exact same thing.


Quote from: Ian Price on 2011-Jun-14
What you can do is render each rectangle to a sprite/screen and then display that.

Code (glbasic) Select

// Set screen resolution (Windowed mode=0 - full screen=1)
SETSCREEN 800,600,0

// Create a virtual screen and use it as sprite #999
CREATESCREEN 1,999,640,480

// Repeat until ESC pressed
WHILE TRUE

// Switch all drawing processes to the virtual screen
USESCREEN 1

// Draw rectangles ONTO the virtual screen sprite
DRAWRECT RND(800), RND(600), RND(100), RND(100), RGB(RND(255), RND(255), RND(255))

// Switch back to normal screen
USESCREEN -1

// Draw the virtual screen sprite
DRAWSPRITE 999,0,0

// Update the screen
SHOWSCREEN

// Repeat loop if WEND condition is not met
WEND


:)
Title: Re: Hi there - Newb Question :)
Post by: Stevester on 2011-Jun-14
Thanks for the responses (and the welcomes) :)

So i can draw to a virtual screen then show the results. The virtual screen isn't cleared and can be added to and flipped back to the realscreen (if I got that correct!). Will have a play when i get home tonight.

Am i right in thinking Ampos' solution is building an array on each loop and redrawing rects to the screen on each sync?

It's gonna take me a while to get my head round the ins and outs but I'm liking the simplicity/clarity so far.

Cheers,

Steve.

Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
Yes, ampos is building an array of Types and then every loop iterating through them to draw the rect. This is not a good idea, as eventually you'll have to iterate through thousands of rects, which will significantly slow down the system.

The virtual screen solution will never have any slowdown, as it's only ever drawing one rect per loop to the virtual screen (which has all the old rects on it) and displaying that to the actual screen.
Title: Re: Hi there - Newb Question :)
Post by: Moru on 2011-Jun-14
Quote from: Ian Price on 2011-Jun-14
USEASBMP will capture the entire screen and ANY and ALL changes. This would be OK for the example above, as there's no moving elements and you just want to update the rectangles. IIRC it also takes CPU time to use this.

Not entirely true, it will only capture the content of the screen at the time of the call. Everything you add after this is not captured and will be cleared the next time. Perfect for paint-programs or for a background-effect. And simple to understand for a newbie :-)

I'm not saying it's the only way of doing it, just another way of getting static content on the screen.
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
QuoteNot entirely true, it will only capture the content of the screen at the time of the call. Everything you add after this is not captured and will be cleared the next time.

Actually, just using the BMP image from calling USEASBMP takes longer than displaying a full-screen sprite (I tested this a long while back and it may have changes since then). Calling the USEASBMP before a main loop slowed the actual FPS for the main loop by a fraction, and that was only calling it once. Calling it every frame may have a more dramatic effect.
Title: Re: Hi there - Newb Question :)
Post by: Slydog on 2011-Jun-14
This is a fun one!

Updating ampos's code, you could have a maximum rectangles allowed in the array at once, with the older ones getting overwritten in the array.  This could be updated to allow for effects for the older rectangles such as fading away, or slowly moving off the screen.

But even at 1000, DRAWRECT could get slow.  I would recommend using POLYVECTORS for anything real.

Code (glbasic) Select
TYPE TRectangle
  left%
  top%
  width%
  height%
  colour%
 
  FUNCTION Set: l%, t%, w%, h%, colour%
self.left = l
self.top = t
self.width = w
self.height = h
self.colour = colour
  ENDFUNCTION

  FUNCTION Draw:
    // Exit if rectangle hasn't been initialized
    IF (self.left=0) AND (self.top=0) AND (self.width=0) AND (self.height=0) THEN RETURN
    DRAWRECT self.left, self.top, self.width, self.height, self.colour
  ENDFUNCTION

ENDTYPE

CONSTANT RECT_MAX% = 1000
GLOBAL rects[] AS TRectangle
GLOBAL pos%
GLOBAL rx%
DIM rects[RECT_MAX]

REPEAT
  // New Rectangle
  INC pos
  IF pos>=RECT_MAX THEN pos=0
  rects[pos].Set(RND(100), RND(100), RND(100), RND(100),  RGB(RND(255),RND(255),RND(255)) )

  // Draw all rectangles in the reverse order they were added, this controls the 'z-order' so latest is on top
  // . . . draw the ones at the end of the array first
  FOR rx = pos+1 TO RECT_MAX-1
    rects[rx].Draw()
  NEXT
  // . . . draw the ones at the start of the array next
  FOR rx = 0 TO pos
    rects[rx].Draw()
  NEXT
UNTIL FALSE
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
Yep, POLYVECTOR should be faster than multiple DRAWRECTS. And you can add extra effects to them.

You have to remember though that the OP has limited experience with GLB, so that's perhaps pushing him a bit too far and too fast. Let him get the basics down first! :P
Title: Re: Hi there - Newb Question :)
Post by: Slydog on 2011-Jun-14
Ya, I understand he's new to GLB, and was just trying to introduce him to some useful GLB concepts.   :good:

Pushing it a bit too far would be this:  (my attempt of fading the older rects!)     :O
Code (glbasic) Select
TYPE TRectangle
  left%
  top%
  width%
  height%
  colour%
 
  FUNCTION Set: l%, t%, w%, h%, colour%
self.left = l
self.top = t
self.width = w
self.height = h
self.colour = colour
  ENDFUNCTION

  FUNCTION Draw:
// Exit if rectangle hasn't been initialized
    IF (self.left=0) AND (self.top=0) AND (self.width=0) AND (self.height=0) THEN RETURN
    DRAWRECT self.left, self.top, self.width, self.height, self.colour
  ENDFUNCTION

  FUNCTION Expand: amount%=1
    DEC self.left, amount
    DEC self.top, amount
    INC self.width, amount*2;  IF (self.width<1) THEN self.width=0
    INC self.height, amount*2; IF (self.height<1) THEN self.height=0
  ENDFUNCTION

ENDTYPE

CONSTANT RECT_MAX% = 100
GLOBAL rects[] AS TRectangle
GLOBAL pos%
GLOBAL rx%
DIM rects[RECT_MAX]

ALLOWESCAPE TRUE

REPEAT
  // New Rectangle
  INC pos
  IF pos>=RECT_MAX THEN pos=0
  rects[pos].Set(RND(200), RND(200), RND(200)+20, RND(200)+20,  RGB(RND(255),RND(255),RND(255)) )

  // Draw all rectangles in reverse order they were added, this controls the 'z-order' so latest is on top
  // . . . draw the ones at the end of the array first
  FOR rx = pos+1 TO RECT_MAX-1
    rects[rx].colour = Fade(rects[rx].colour, rx, pos)
    rects[rx].Expand(-1)
    rects[rx].Draw()
  NEXT
  // . . . draw the ones at the start of the array next
  FOR rx = 0 TO pos
    rects[rx].colour = Fade(rects[rx].colour, rx, pos)
    rects[rx].Expand(-1)
    rects[rx].Draw()
  NEXT

  SLEEP 50
  SHOWSCREEN
UNTIL FALSE

FUNCTION Fade%: colour%, rx%, pos%
  LOCAL colour_new%
  LOCAL age#
  age = pos - rx
  IF age < 0 THEN age = age + RECT_MAX
  // Set 'age' to range: [0.0] - [1.0]
  age = age / (RECT_MAX * 1.0)
  colour_new = Colour_Brightness(colour, -(age * 100))
  RETURN colour_new
ENDFUNCTION

// colour_new = Colour_Brightness(colour,  25) // new colour 25% brighter
// colour_new = Colour_Brightness(colour, -50) // new colour 50% darker
FUNCTION Colour_Brightness%: colour%, increase%
LOCAL r%, g%, b%, percent#
    percent = increase / 100.0
r=bAND(colour,0xff)
g=bAND(colour/0x100,0xff)
b=bAND(colour/0x10000,0xff)
//a=bAND(colour/0x1000000,0xff)
    IF percent >= 0
    r = INTEGER((255 - r) * percent + r)
    g = INTEGER((255 - g) * percent + g)
    b = INTEGER((255 - b) * percent + b)
    ELSE
    r = INTEGER(r * ABS(-1 - percent))
    g = INTEGER(g * ABS(-1 - percent))
    b = INTEGER(b * ABS(-1 - percent))
    ENDIF
    RETURN RGB(r, g, b)
ENDFUNCTION


[Edit] Updated to shrink rectangles as they get older, they appear to get further away.
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
That's a good effect =D
Title: Re: Hi there - Newb Question :)
Post by: Crivens on 2011-Jun-14
Ampos: You should push onto the array rather than redimming. Is a bit less code and is easier to read IMO.

Cheers
Title: Re: Hi there - Newb Question :)
Post by: kanonet on 2011-Jun-14
Hi and welcome.
As you can see, there are often many solutions for one problem. As a programer its up to you, to find the one, that fits best to your needs. My solution for your Problem would be GRABSPRITE:
Code (glbasic) Select
REPEAT
      DRAWSPRITE 1, 0,0
      DRAWRECT RND(800), RND(600), RND(100), RND(100), RGB(RND(255), RND(255), RND(255))
      GRABSPRITE 1, 0,0, 800,800
      SHOWSCREEN
UNTIL KEY(28)
MOUSEWAIT
END
Title: Re: Hi there - Newb Question :)
Post by: Ian Price on 2011-Jun-14
GRABSPRITE would again grab the whole screen (like USEASBMP) and any action on it. It would be OK on just the rectangles but if you want to add anything else (moving player etc.) then avoid.
Title: Re: Hi there - Newb Question :)
Post by: quangdx on 2011-Jun-15
Going back to the original question, I've just tested CLEARSCREEN -1 using GLBasic 9.040
and it gives the required effect.

Code (glbasic) Select
CLEARSCREEN -1
REPEAT
      DRAWRECT RND(800), RND(600), RND(100), RND(100), RGB(RND(255), RND(255), RND(255))
      SHOWSCREEN
UNTIL KEY(28)
MOUSEWAIT
END


I know previously it would flicker between odd and even frames of rendering (back and front buffers, as they were swapped with the SHOWSCREEN command) But it now looks like they are one in the same.


Quote from: Stevester on 2011-Jun-14
I'm trying to display lots of random rectangles on the screen, adding one with each loop but I'm finding the SHOWSCREEN command appears to be getting in the way as its clearing the screen on every loop. What I'm wanting is to add a rectangle to screen on every loop rather than draw, show, clear, repeat.

I don't want the showscreen command to clear the backscreen every time, I want the rectangles to randomly overlap and fill the screen. Is there an alternative command to use to draw to the main screen or prevent the backscreen from wiping?

Any help would be appreciated. :)

Steve.
Title: Re: Hi there - Newb Question :)
Post by: Stevester on 2011-Jun-15
Thanks for the responses on this one guys.

Looks like there are a few options to achieving what I was looking for, and running through them has led me onto learning some of the other commands.

I like the fading / shrinking effect in particular - adds a bit of style to the program :)

Struggling to understand the 'self' command though. Can't find reference to it in the help doc:

Code (glbasic) Select
FUNCTION Set: l%, t%, w%, h%, colour%
self.left = l
self.top = t
self.width = w
self.height = h
self.colour = colour
  ENDFUNCTION


Cheers,

Steve.
Title: Re: Hi there - Newb Question :)
Post by: MrTAToad on 2011-Jun-16
Self is used to let a function in a type access a variable defined in it :

Code (glbasic) Select

TYPE TTest
  a%

  FUNCTION test%:
    self.a%=1 // Set the a% value in TTest to 1
  ENDFUNCTION
ENDTYPE


You may be interested in my Programmers Reference Guide, which details it all : http://www.lulu.com/product/paperback/glbasic-programmers-reference-guide-%28second-edition%29/16044005
Title: Re: Hi there - Newb Question :)
Post by: spacefractal on 2011-Jun-16
alternative you can use CREATESCREEN and draw each box into that, and then draw that screen to the backbuffer.

SCREENS other than backbuffer is never clean up, so its can been alternativt to avoid drawing 1000boxes in one frame.
Title: Re: Hi there - Newb Question :)
Post by: Stevester on 2011-Jun-16
QuoteYou may be interested in my Programmers Reference Guide, which details it all : http://www.lulu.com/product/paperback/glbasic-programmers-reference-guide-%28second-edition%29/16044005

Had a look at this and will definitely be looking into a copy though there's quite a difference (price-wise) between the hardcopy and the download (about £70) - is this correct? The hardcopy seems really expensive but the download seems too cheap!

QuotePosted by: spacefractal
« on: Today at 01:45:14 pm »
alternative you can use CREATESCREEN and draw each box into that, and then draw that screen to the backbuffer.
SCREENS other than backbuffer is never clean up, so its can been alternativt to avoid drawing 1000boxes in one frame.

Thats very handy to have a screen (or image) that isn't cleared every cycle. You then copy this to the backscreen and flip it to the visible screen using SHOWSCREEN command.

This is slightly different to what I'm used to but I think I'm starting to get the hang of it!! :)

I'd been thinking that having to pass everything through the SHOWSCREEN command at the end of every cycle was a bit of a limitation but thats not looking to be the case with the alternative options available. I think it promotes a bit more structure to the coding as well.

I was also a bit stumped with the explicit declarations (hadn't realised theres a tick box in options) but I can see the benefit of this facility - especially with my dodgy coding! :) Will be very useful in larger programs when I accidentally misspell one of my variables. (Mind, I've turned it off for now!).
Title: Re: Hi there - Newb Question :)
Post by: Gary on 2011-Jun-16
Quote from: Ian Price on 2011-Jun-14
GRABSPRITE would again grab the whole screen (like USEASBMP) and any action on it. It would be OK on just the rectangles but if you want to add anything else (moving player etc.) then avoid.
but if you drew the sprite, then the new rectangle, then grab it, then draw the player which could move, then showscreen you would keep the rectangles sprite minus any other moving images added after.