Changing From roImageCanvas to roScreen questions

It has become apparent that I will need to use roScreen in my program instead of roImageCanvas in order to speed up my program. My program makes heavy use of roImageCanvas, specifically the setLayer, clearLayer and swapLayer, in addition to the ability to setLayer something on an already occupied layer to overwrite what is already on that layer. I was wondering if there was a way for roScreen to reproduce any/all of these effects, and how I should go about changing my program to use roScreen, since I have never used it before.

Probably the biggest thing to realize is that if you double buffer the screen, you will have to redraw every object, every time. This will result in good clean movement if you optimize any calculations outside of the redraw loop. Double buffering is recommended so that you do not see “screen tears” during redraw, which happens when a draw occurs partially in two different frame refresh periods.

You will most likely have a similar wait() loop that checks for universal event type that differentiates press and release. If you must have faster speed, then search the forums on the wait / sleep bug on Roku 2 devices that cause an extra 15-20ms delay. It’s possible to get rid of that delay by using timers and polling message port(s) in a tight loop.

I hope that helps!

It helps somewhat. Is there anywhere can I find a very simple example of a program using roScreen for reference?

The 3.0 SDK has a sample roScreen app called “Snake”

DrawRect() takes 5 arguments, not 4, the fifth being the color you want your rect to be. http://sdkdocs.roku.com/display/RokuSDK … ntegerrgba

I threw together a little demo last night for you:

you can download it here: https://www.box.com/shared/93202d2c60d4bf2effd1

In terms of the SDK examples, check out BS2Dtest and simple2d for some more ideas of what you can do, including collision detection, scaling etc. There aren’t yet any examples of integrating 2DAPIs with video playback, but we should have some soon.

The action takes place in the while loops:

'lets say you have a set of images you want to draw as layers. You would draw them to the screen in the order in which they should appear, and you would keep redrawing them as often as possible:

sub main()

screen=createobject("roscreen",true)
screen.setalphaenable(false)
image1=createobject("robitmap","pkg:/images/imageone.png")
image2=createobject("robitmap","pkg:/images/imagetwo.png")
image3=createobject("robitmap","pkg:/images/imagethree.png")

'lets set up some positions for these images:
obj1={posx:200,posy:200}
obj2={posx:400,posy:400}
obj3={posx:600,posy:600}

timer=createobject("rotimespan")
timer.mark()

while timer.totalseconds() <15 'exit this loop after 15 seconds. 

screen.clear(&h000000FF) 'clear screen to black
screen.setalphaenable(false) 'disable alpha for this draw, since the object is not transparent
screen.drawobject(obj1.posx,obj1.posy,image1)
screen.setalphaenable(true) 're enable for transparent images
screen.drawobject(obj2.posx,obj2.posy,image2)
screen.drawobject(obj3.posx,obj3.posy,image3)
screen.setalphaenable(false)

screen.swapbuffers() 'display the completed draw on screen

'move objects
if obj1.posx > 0 then obj1.posx=obj1.posx-1
if obj1.posy > 0 then obj1.posy=obj1.posy-1

if obj2.posx > 0 then obj2.posx=obj2.posx-1
if obj2.posy > 0 then obj2.posy=obj2.posy-1

if obj3.posx > 0 then obj3.posx=obj3.posx-1
if obj3.posy > 0 then obj3.posy=obj3.posy-1

end while

'If one of the layers has transparancy, and you want the layer below to show through the transparant section, you would enable transprancy for that image when drawing to the screen.

'Another approach with roScreen is to create Sprites, which are images designed to be moved around the screen, typically as objects in a game, but they can be used for almost anything.

'lets create some sprites. first we need to create a compositor:
compositor=createobject("rocompositor")

'now we need to tell it where to draw and the background color:
compositor.setdrawto(screen,&h000000FF)

'To create a sprite, first we create a bitmap image, as we did before
bmp1=createobject("roBitmap", "pkg:/images/alien1.png")

'then we create a region from that bitmap:
reg1=createobject("roregion", bmp1,0,0,bmp1.getwidth(),bmp1.getheight())
bmp2=createobject("roBitmap", "pkg:/images/alien2.png")
reg2=createobject("roregion", bmp2,0,0,bmp2.getwidth(),bmp2.getheight())
bmp3=createobject("roBitmap", "pkg:/images/alien3.png")
reg3=createobject("roregion", bmp3,0,0,bmp3.getwidth(),bmp3.getheight())

'from those three regions, we will create our sprites:
spr1=compositor.newsprite(200,200,reg1,0) 'create a sprite on layer 0
spr2=compositor.newsprite(250,250,reg2,1) 'create a sprite on layer 1
spr3=compositor.newsprite(350,350,reg3,2) 'create a sprite on layer 3

'to make it easier to work with them, we are going to put them into an array:

sprArr=[spr1,spr2,spr3]
'we can actually store data inside a sprite! lets put our x and y positions into an Associative Array and store in our sprite:
for each sprite in sprarr
sprite.setdata({xpos:sprite.getx(),ypos:sprite.gety()})
end for

'Ok, now lets make a little routine that moves them randomly around the screen:
bounds={}
bounds.x=screen.getwidth()
bounds.y=screen.getheight()
screen.setalphaenable(true) 'enable transparency

'Lets set up a timer to control movement:

movetimer=createobject("rotimespan")
movetimer.mark()

'lets reset the timer we used for the while loop:
timer.mark()

for each sprite in sprarr
data=sprite.getdata()
data.movex=(rnd(3)-2)
data.movey=(rnd(3)-2)
sprite.setdata(data)
movetimer.mark()
end for
while timer.totalseconds() < 60

screen.clear(&h000000ff)

if movetimer.totalmilliseconds() > 500 then
for each sprite in sprarr
data=sprite.getdata()
xr=(rnd(3)-2)
yr=(rnd(3)-2)
if xr <>0 then data.movex=xr
if yr <>0 then data.movey=yr
sprite.setdata(data)
movetimer.mark()
end for
end if

'move sprites
for each sprite in sprarr
data=sprite.getdata()
x=data.xpos
y=data.ypos
x=x+data.movex
y=y+data.movey
if x > bounds.x then x=0-sprite.getregion().getbitmap().getwidth()
if y > bounds.y then y=0-sprite.getregion().getbitmap().getheight()
if x < 0-sprite.getregion().getbitmap().getwidth() then x=bounds.x
if y < 0-sprite.getregion().getbitmap().getheight() then y=bounds.y
sprite.moveto(x,y)
sprite.setdata({xpos:x,ypos:y,movex:data.movex,movey:data.movey})
end for

compositor.drawall() 'draw all sprites even if they have not moved or changed
screen.swapbuffers() 'swap screen buffers to display completed drawing
end while
end sub

Joel

Thank you, that is extremely helpful.

Here is a modified version of the same thing with video playback (video playback in motion too).:
https://www.box.com/shared/c46bb964b26f1347a41e

Note that there is now only one loop, screen.clear statements all clear to &h00000000 instead of &h000000FF

the video playback is pretty much ripped straight out of simplevideoplayer, modified to use roVideoPlayer instead of roVideoScreen.

This should supply a few minutes of annoying, but educational fun:


sub main()

    

    screen=createobject("roscreen",true)
    '**************************************

    print "Displaying video: "
    p = CreateObject("roMessagePort")
    video = CreateObject("roVideoPlayer")
    
    

    bitrates  = [0]    

    
    urls = ["http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"]
    qualities = ["SD"]
    streamformat = "hls"
    title = "Apple BipBop Test Stream"
    srt=""

    
    if type(args) = "roAssociativeArray"
        if type(args.url) = "roString" and args.url <> "" then
            urls[0] = args.url
        end if
        if type(args.StreamFormat) = "roString" and args.StreamFormat <> "" then
            StreamFormat = args.StreamFormat
        end if
        if type(args.title) = "roString" and args.title <> "" then
            title = args.title
        else 
            title = ""
        end if
        if type(args.srt) = "roString" and args.srt <> "" then
            srt = args.StreamFormat
        else 
            srt = ""
        end if
    end if
    
    videoclip = CreateObject("roAssociativeArray")
    videoclip.StreamBitrates = bitrates
    videoclip.StreamUrls = urls
    videoclip.StreamQualities = qualities
    videoclip.StreamFormat = StreamFormat
    videoclip.Title = title
    print "srt = ";srt
    if srt <> invalid and srt <> "" then
        videoclip.SubtitleUrl = srt
    end if
    
    targetrect = { x: 300, y: 300, w: 320, h: 180 }

    
    video.SetMessagePort(p)
    video.SetDestinationRect(targetrect)
    video.addContent(videoclip)
    video.Play()
   
'*****************************************
    'screen.setalphaenable(false)
    image1=createobject("robitmap","pkg:/images/imageone.png")
    image2=createobject("robitmap","pkg:/images/imagetwo.png")
    image3=createobject("robitmap","pkg:/images/imagethree.png")

    'lets set up some positions for these images:
    obj1={posx:200,posy:200}
    obj2={posx:400,posy:400}
    obj3={posx:600,posy:600}

'**********************************setup sprites******************************

    'If one of the layers has transparancy, and you want the layer below to show through the transparant section, you would enable transprancy for that image when drawing to the screen.

    'Another approach with roScreen is to create Sprites, which are images designed to be moved around the screen, typically as objects in a game, but they can be used for almost anything.

    'lets create some sprites. first we need to create a compositor:
    compositor=createobject("rocompositor")

    'now we need to tell it where to draw and the background color:
    compositor.setdrawto(screen,&h00000000)

    'To create a sprite, first we create a bitmap image, as we did before
    bmp1=createobject("roBitmap", "pkg:/images/alien1.png")
    
    'then we create a region from that bitmap:
    reg1=createobject("roregion", bmp1,0,0,bmp1.getwidth(),bmp1.getheight())
    'reg1.setalphaenable(true)
    bmp2=createobject("roBitmap", "pkg:/images/alien2.png")
    reg2=createobject("roregion", bmp2,0,0,bmp2.getwidth(),bmp2.getheight())
    bmp3=createobject("roBitmap", "pkg:/images/alien3.png")
    reg3=createobject("roregion", bmp3,0,0,bmp3.getwidth(),bmp3.getheight())

    'from those three regions, we will create our sprites:
    spr1=compositor.newsprite(200,200,reg1,0) 'create a sprite on layer 0
    spr2=compositor.newsprite(250,250,reg2,1) 'create a sprite on layer 1
    spr3=compositor.newsprite(350,350,reg3,2) 'create a sprite on layer 3

    'to make it easier to work with them, we are going to put them into an array:

    sprArr=[spr1,spr2,spr3]
    'we can actually store data inside a sprite! lets put our x and y positions into an Associative Array and store in our sprite:
    for each sprite in sprarr
    sprite.setdata({xpos:sprite.getx(),ypos:sprite.gety()})
    end for

    'Ok, now lets make a little routine that moves them randomly around the screen:
    bounds={}
    bounds.x=screen.getwidth()
    bounds.y=screen.getheight()
    screen.setalphaenable(true) 'enable transparency

    'Lets set up a timer to control movement:

    movetimer=createobject("rotimespan")
    movetimer.mark()

    'lets reset the timer we used for the while loop:
    
vmovex=0
vmovey=0

    for each sprite in sprarr
    data=sprite.getdata()
    data.movex=(rnd(3)-2)
    data.movey=(rnd(3)-2)
    sprite.setdata(data)
    movetimer.mark()
    end for
'*****************************************************************************
    timer=createobject("rotimespan")
    timer.mark()

    while timer.totalseconds() <60 'exit this loop after 15 seconds.

    screen.clear(&h00000000) 'clear screen to black
    screen.setalphaenable(false) 'disable alpha for this draw, since the object is not transparent
    screen.drawobject(obj1.posx,obj1.posy,image1)
    screen.setalphaenable(true) 're enable for transparent images
    screen.drawobject(obj2.posx,obj2.posy,image2)
    screen.drawobject(obj3.posx,obj3.posy,image3)
    

    'move objects
    if obj1.posx > 0 then obj1.posx=obj1.posx-1
    if obj1.posy > 0 then obj1.posy=obj1.posy-1

    if obj2.posx > 0 then obj2.posx=obj2.posx-1
    if obj2.posy > 0 then obj2.posy=obj2.posy-1

    if obj3.posx > 0 then obj3.posx=obj3.posx-1
    if obj3.posy > 0 then obj3.posy=obj3.posy-1

    'move video!
    
    
    '*********************move sprites*******************************
    
    if movetimer.totalmilliseconds() > 500 then
	    xr=(rnd(3)-2)
	    yr=(rnd(3)-2)
	    if xr <>0 then vmovex=xr
	    if yr <>0 then vmovey=yr
	    
	    
	    for each sprite in sprarr
	    data=sprite.getdata()
	    xr=(rnd(3)-2)
	    yr=(rnd(3)-2)
	    if xr <>0 then data.movex=xr
	    if yr <>0 then data.movey=yr
	    sprite.setdata(data)
	    movetimer.mark()
	    end for
    end if

    'move sprites
    for each sprite in sprarr
    data=sprite.getdata()
    x=data.xpos
    y=data.ypos
    x=x+data.movex
    y=y+data.movey
    if x > bounds.x then x=0-sprite.getregion().getbitmap().getwidth()
    if y > bounds.y then y=0-sprite.getregion().getbitmap().getheight()
    if x < 0-sprite.getregion().getbitmap().getwidth() then x=bounds.x
    if y < 0-sprite.getregion().getbitmap().getheight() then y=bounds.y
    sprite.moveto(x,y)
    sprite.setdata({xpos:x,ypos:y,movex:data.movex,movey:data.movey})
    end for
    targetrect.x=targetrect.x+vmovex
    targetrect.y=targetrect.y+vmovey
    if targetrect.x > bounds.x then targetrect.x=0-targetrect.w
    if targetrect.y > bounds.y then targetrect.y=0-targetrect.h
    if targetrect.x < 0-targetrect.w then x=bounds.x
    if targetrect.y < 0-targetrect.h then y=bounds.y
    video.SetDestinationRect(targetrect)

    compositor.drawall() 'draw all sprites even if they have not moved or changed
    screen.swapbuffers() 'display the completed draw on screen
    '****************************************************************
    
    
    
    
    
    end while

    end sub

I am learning a lot, but I still don’t understand how to make sure something will be displayed in front of something else. For example, I used the roscreen clear function to set a background color, and now my video is behind the background. I can hear it and everything, and when I remove the background I can see it, so I know its there. How do I make sure that the video displays on top?

Probably by never drawing anything that isn’t transparent on top of the video - for example, your overlays could be translucent so you could see the video through the images your are drawing. I’ll see if there is any other solution.

  • Joel

How do you make overlays transluscent?

You can use Adobe Photoshop or the gIMP which is free, or another graphic editor that allows you to manipulate images in .png format.

  • Joel

It’s worth noting (just in case you are using it) that rotation in roScreen is not equivalent to rotation in roImageCanvas. Last time I checked, roScreen could only rotate by 90 degree increments.

P.S. We would happily write a compatibility library so you could use roScreen like roImageCanvas if rotation was fixed, as we would be doing it anyway to fix KidPaint. Really, the only thing that’s kept KidPaint from being fixed from the buggy implementation that exists using multiple (many!) canvases is that the rotation we need can’t be achieved through roScreen. We would actually implement rotation ourselves (albeit slowly) if we could convert both directions between bytearray and roBitmap, but that’s missing as well last time I checked. In fact that’s what blocked us getting a very low-end (slow) VNC client working (the TCP server that speaks the protocol is written already…).

Since 4.5 or so firmware, you can rotate to any angle.

  • Joel

“RokuJoel” wrote:
Since 4.5 or so firmware, you can rotate to any angle.
Hmm, then I guess I have some work to do, don’t I? :wink:

“kbenson” wrote:

“RokuJoel” wrote:
Since 4.5 or so firmware, you can rotate to any angle.
Hmm, then I guess I have some work to do, don’t I? :wink:
I was actually testing this out the other day.. don’t get your hopes up too high… :wink:
Also, still limited to 90 degree rotations on the Roku 1.

“TheEndless” wrote:

“kbenson” wrote:

“RokuJoel” wrote:
Since 4.5 or so firmware, you can rotate to any angle.
Hmm, then I guess I have some work to do, don’t I? :wink:
I was actually testing this out the other day.. don’t get your hopes up too high… :wink:
Also, still limited to 90 degree rotations on the Roku 1.

Actually, I just checked some old email, and I was notified about this. I think the lack of arbitrary rotation angles on the Roku 1 that caused me to not go forward with creating a roImageCanvas shim. So, first, sorry to Roku for shooting my mouth off about it not being supported, that’s what I get for not paying attention.

Second, since I said I would work on implementing the an roImageCanvas to roScreen shim if they provided rotation, I’ll at least try. :slightly_smiling_face:

Guys

I’m working on a Scene Graph project and I have to overlay a non-transparent image over video while it is playing.
I saw this example and believe it is a great place to start. Looking at the 2DVideoLayers example (note : great example )

I changed the object from roScreen to roSGScreen … and ran into some issues.

orig = screen=createobject(“roscreen”,true)
new screen=createobject(“roSGScreen”,true)

I made some changes and did some debugging to find that I get stuck on line 119 screen.setalphaenable(true) 'enable transparency

roSGScreen does not have this method and I was wondering what the equivalent for setaplhaenable(true) might be using the roSGScreen object ?

Ran into some issues and wanted to ask someone if I’m going in the right direction.

Also trying to use roVideoPlayer instead of roVideoScreen… and then use roImageCanvas to paint the image on top of the video.

Any suggestions / help