Problem with net image displayed (carousel)

All,
Trying to set up a carousel in which images are downloaded from a site on the net. The images are displayed free downloading to a table and iterating through the table in the draw() function.
I have tried to build an image in setup by downloading images within setContext() and sprite them onto the image, then Sprite the resultant image in the draw() function. But the images don’t seem to be pasted into the target image.

Are images downloaded in this way only displayable direct to screen and not to other memory locations?

@Bri_G Msybe this is close enough for you to modify. Tap screen to read and display the next image.

viewer.mode=FULLSCREEN

function setup()
    tab={
        "http://www.freeimageslive.com/galleries/home/playroom/pics/objects00016g.jpg",
        "http://www.freeimageslive.com/galleries/transtech/auto/pics/03250046.jpg",
        "http://www.freeimageslive.com/galleries/transtech/auto/pics/car00708.jpg",
        }
    z=0
    getNext=false
end

function draw()
    background(40,40,50)
    if getNext then
        getNext=false
        z=z+1
        if z<=#tab then
            http.request(tab[z],gotImage,noImage)
        end
    end
    if img~=nil then
        sprite(img,WIDTH/2,HEIGHT/2)
    end
end

function noImage()
    print("Error:  ",tab[z])
    getNext=true
end

function gotImage(image1,status,header)
    print("Success:  ",tab[z])
    img=image1 
end

function touched(t)
    if t.state==BEGAN then
        getNext=true
    end
end

@dave1707 - missed the point there. What I suspect is you are constantly streaming to the screen there via the http.request, possibly to a buffer. That’s what happens in the Carousel from the other thread.

I am trying to download the images onto a defined blank image using setContext() within setup. That way I can play around with the image. I suspect the http protocol will only allow streaming of the image and an array of several images merely holds a pointer to the image for streaming.

@Bri_G I’m displaying the image from img. I only do a http request when you tap the screen. The images could be moved into a table and viewed from there so you could rotate thru them.

@dave1707 - attached a listing of your code slightly adapted. Run it then switch the in context commenting to other copy and re-run.

Moving the code to the subroutine works, so I have a way forward. Thanks.


viewer.mode=FULLSCREEN
function setup()
    --
    tab = {"http://www.freeimageslive.com/galleries/home/playroom/pics/objects00016g.jpg"}
    z=#tab
    http.request(tab[z],gotImage,noImage)
    pic = image(400,400)
    setContext(pic)
    spriteMode(CENTER)
    sprite(img,200,200,400,400)
    setContext()
end

function draw()
    background(40,40,50)
    sprite(pic,WIDTH/2,HEIGHT/2)
end

function addImageToTable( theImage, status, head )
    print(i,status,head)
    table.insert(imageTable, theImage)
end

function noImage()
    print("Error:  ",tab[z])
    getNext=true
end

function gotImage(image1,status,header)
    print("Success:  ",tab[z])
    img=image1
    --[[
    setContext(pic)
    spriteMode(CENTER)
    sprite(img,200,200,400,400)
    setContext()
    ]]
end

function touched(t)
    if t.state==BEGAN then
        getNext=true
    end
end

@Bri_G Are you perhaps misunderstanding how the http request works? The key thing here is that it’s always asynchronous, so the code following http.request will always execute before either of the callbacks are actually executed.

The callbacks themselves will be executed outside of any setup() or draw() call. As Lua is inherently single-threaded the entire setup() call in which the request is made will run in its entirety before any of the callbacks are executed by the Codea runtime.

@Simeon Is this right or am I talking crap?

@dave1707 @steppers - you may be right, I wondered if it was down to timing as downloads over the net vary wildly. However downloading 1 image in setup and writing to a blank image I should have thought was fine. How do you explain the difference in location of the setContext() loop?

@Bri_G With the setcontext in setup, it’s being executed before the http.request is finished. So img isn’t loaded yet giving you nil. With it in gotImage, then http.request is done and the gotImage function is called.

@dave1707 - aha, so it is down to timing. Thanks, I’m sure I have encountered this before but it’s not something I use on a regular basis - hence having to ask for support. Thanks again.

@Bri_G Just a quick refresher. The http.request will download whatever you request. When the download is done and successful, it calls the gotImage function or whatever name you have for the first callback. If the request fails, then the noImage function is called or whatever function name you have for the second callback. So you can download multiple items one after the other by setting a variable in the gotImage callback to start then next request.

@Bri_G Yes, timing entirely. The callbacks are only called when the request/download completes or fails. In the case of a large file this could mean ‘draw()’ is called and a frame rendered multiple times before any callback is even executed. Even for a small file the callback won’t be executed until execution returns to the runtime (setup() or draw() returning)

Hi All,

Have attached a project with a 3D cube carousel using the image downloads from the net mentioned in this thread and others. It’s not finished, I struggled to reload a new set of images with the routine I have put in. Also I left a routine to display the downloaded images in to check whilst developing. Any ideas would be appreciated.

@Bri_G Try this. Slide the Boolean parameter for next set of images.

Updated version below

@dave1707 - thanks for that, very neat and tidy as usual. Always something to learn when you post.

One thing, I originally used ‘load’ in my parameter.action but it turned orange when I tried to use it as a variable. Looks like it may be a reserved word but you’ve used it as a function.

@Bri_G There’s a volume:load(), so maybe that’s why.

@Bri_G Here’s an updated version. The changes are

  1. I create the cube only once.
  2. When all six new images are received, I update the cubes material.map with the new images.
viewer.mode=STANDARD

function setup()
    wTab={}
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()
    scene.ambientColor=color(255)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 40, 0, 200)    
    v.rx,v.ry=30,30
    createCube()
    parameter.boolean("New_images",new)
    new()
end

function draw()
    update(DeltaTime)
    scene:draw()
end

function update(dt)
    scene:update(dt)
end

function new()
    New_images=false
    getImages()
end

function createCube()
    createWall(vec3(-5,0,0),vec3(.1,10,10))
    createWall(vec3(5,0,0),vec3(.1,10,10))    
    createWall(vec3(0,-5,0),vec3(10,.1,10))    
    createWall(vec3(0,0,5),vec3(10,10,.1))    
    createWall(vec3(0,0,-5),vec3(10,10,.1))
    createWall(vec3(0,5,0),vec3(10,.1,10))
end

function createWall(pos,mod)
    local temp=scene:entity()
    temp.position=pos
    temp.model = craft.model.cube(mod)
    temp.material = craft.material(asset.builtin.Materials.Standard)
    temp.material.map = readImage(asset.builtin.SpaceCute.Health_Heart)
    table.insert(wTab,temp)
end

function getImages()
    images={}
    for i=1,6 do
        http.request( 'https://picsum.photos/200/200',addImageToTable)
    end
end

function addImageToTable( theImage, status, head )
    table.insert(images,theImage)
    if #images==6 then
        for z=1,6 do
            wTab[z].material.map=images[z]
        end
    end
end

@dave1707 - great, it’s getting really compact and tidy now. I never think about using a craft cube made up of Craft walls but the code looks so neat and tidy. Need to go back and add to a few other projects. Thanks for this. I’m busy trying to add a default cube from local assets (Dropbox) so that it is present until you use the Boolean slider.