Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Black line above sprites

edited March 2015 in Bugs Posts: 15

Hey everyone,
I encountered a little problem/issue while coding today: everytime I create a sprite, import it into Codea and draw it on the screen, I get a black line above it, as shown http://imgur.com/fVia9Ox . It doesn't really bother me that much as the line is relatively thin, but I would like to know if I am doing something wrong when importing the sprites, or if it is a bug I should submit to the Issue Tracker.
Thank you for taking the time to read through my post :)
ColourCoder

Tagged:

Comments

  • edited March 2015 Posts: 15

    If you have trouble telling where the line is, I can post another picture if you want

  • dave1707dave1707 Mod
    Posts: 7,836

    @ColourCoder I've seen this before. I think it's a one pixel line from the bottom of the sprite, but I don't remember what I did about it. I was able to determine that because the bottom of my sprite wasn't a solid color and the line matched the bottom of the sprite.

  • dave1707dave1707 Mod
    Posts: 7,836

    @ColourCoder Did you pull your sprite from a sprite sheet. I think I was doing something with a sprite sheet when I saw this. I thought maybe it was getting some of the sprite that was above the one I wanted, but the line matched the bottom of my sprite and not the one above it. It was quite awhile ago and I don't remember what I ended up doing. I'll look around, maybe something will jog my memory.

  • Posts: 1,976

    Try calling noSmooth() before drawing, it might fix it.

  • Posts: 41

    Thanks @SkyTheCoder. I had the same problem.

  • @SkyTheCoder calling noSmooth() does actually help a little as the line is now even less visible, thanks.
    @dave1707 if by sprite sheet you mean a sprite with the several status the Hero might have (e.g: walking, attacking,etc.), I prefer using individual sprite for each of them. However, as you said, the black line appears when the bottom pixels of the sprite being used are black. Maybe it has something to do with the sprite's dimensions ?

  • Posts: 127

    Would you be able to let us see the actual sprite you're using? Did you already try to crop the image of a couple of pixels from the top? Maybe that line is part of the sprite and you're somehow filling it with black.

  • SimeonSimeon Admin Mod
    Posts: 5,054

    @ColourCoder does the sprite file have power-of-two dimensions? E.g., 128x128, or 256x256 (and so on)?

    Codea has special treatment for power-of-two images in that they are tile-able, I wonder if that could be causing the artefact.

  • @Simeon yes, the sprite is 32x32
    @deactive the line cannot be part of the original sprite as the top of the Hero's head marks the limit of it

  • SimeonSimeon Admin Mod
    Posts: 5,054

    @ColourCoder could you try adding a 1px transparent padding to the sprite so it becomes 34x34 and let me know if it still happens?

  • IgnatzIgnatz Mod
    edited March 2015 Posts: 5,396

    I tried making my own sprite of various sizes with black at the bottom, but didn't get a line at the top. Saving and reloading it didn't make a difference.

    Could the file format be a factor?

  • @Simeon I changed the sprites to 34x34 like you told me and it now seems that the black line has disappeared. Thanks!
    @Ignatz since I download my sprites into my iPad's pictures and then import them into Codea, I think their file is .jpeg. Are your sprites also .jpeg?

  • @ColourCoder - If your sprite has transparency, which, looking at your picture, I think it does, then the file extension will be .png

  • dave1707dave1707 Mod
    Posts: 7,836

    @Simeon Not sure if this is like the problem here, but here's an example of the bottom of the image showing at the top. The image at the lower left is the original image. The image at the upper left is a copy of the upper left corner of the original image. The image on the right is an enlargement of the copied image. Using the slider, I extent the black and red rectangle down in the original image so that it will eventually get copied. When the black/red rectangle reached the bottom of the larger image, you can see some of the image at the top.

    supportedOrientations(LANDSCAPE_ANY)
    
    function setup()
        spriteMode(CORNER)
        rectMode(CORNER)    
        parameter.integer("val",55,65,65,change)
    end
    
    function draw()
        background(40)
        sprite(img1,50,200)
        sprite(img2,80,300)
        sprite(img2,200,200,500)
    end
    
    function change()
        img1=image(80,80)
        setContext(img1)
        background(255)
        -- draw a varying size rectangle with a red stripe
        fill(0)
        rect(6,val,8,75-val)
        fill(255, 0, 0, 255)
        rect(8,val,2,75-val)
        setContext()
    
        -- copy upper left corner of original image
        img2=img1:copy(2,63,16,16)   
    end
    
  • IgnatzIgnatz Mod
    Posts: 5,396

    Good test, @dave1707. And if you use a size that isn't a power of 2, you don't get the stripe.

  • SimeonSimeon Admin Mod
    edited March 2015 Posts: 5,054

    @dave1707 thank you very much for the example. It does appear to be due to the bilinear filtering when smooth() is enabled and you have a power-of-two texture. The sampling window exceeds the texture boundary and so wraps past the edge, noSmooth() or a non-power-of-two texture will resolve this.

    Codea purposely interprets power-of-two textures with wrapping enabled on the UV coordinates — so if the texture coordinates exceed 1.0 or go less than 0.0 the texture will wrap. This is handy on meshes where you want a tiled texture on a single quad.

    (Cargo-Bot uses this effect to do the infinite scrolling star background, below is an adaptation of it as a demo)

    --# Main
    -- ScrollingStars
    function setup()
        texDemo = ScrollingTexture("Cargo Bot:Starry Background")
    end
    
    function draw()
        texDemo:setRect(WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)
    
        texDemo:setOffset( (texDemo.offset + vec2(DeltaTime, DeltaTime)):unpack() )
    
        texDemo:draw()
    end
    
    
    --# ScrollingTexture
    ScrollingTexture = class()
    
    local function imageOrSpriteSize(imgOrKey)
        local w,h = 0,0
        if type(imgOrKey) == "string" then
            w, h = spriteSize(imgOrKey)
        else
            w = imgOrKey.width
            h = imgOrKey.height
        end
    
        return w,h
    end
    
    function ScrollingTexture:init(tex)
        -- note: requires a power-of-two image    
        self.mesh = mesh()
        self.mesh.texture = tex
        self.offset = vec2()
        self.tw, self.th = imageOrSpriteSize(tex)
        self.rect = self.mesh:addRect(0,0,0,0)
        self:setRect(0, 0, 100, 100)
    end
    
    function ScrollingTexture:setRect(x, y, w, h)
        self.mw, self.mh = w, h
        self.mesh:setRect(self.rect, x, y, w, h)
        self:setOffset(self.offset:unpack())
    end
    
    function ScrollingTexture:setOffset(x, y)
        self.offset = vec2(x,y)
    
        local w = self.mw / self.tw
        local h = self.mh / self.th
    
        self.mesh:setRectTex(self.rect, x, y, w, h)
    end
    
    function ScrollingTexture:draw()
        self.mesh:draw()
    end
    
  • IgnatzIgnatz Mod
    edited March 2015 Posts: 5,396

    I found that example a bit complicated, so I tried to create a simpler one, below, which tiles an image across a surface.

    I note two things.

    A. My example draws a fractional number of copies of the original image, which looks a bit untidy.

    You can make it an integer number by simply adjusting the numbers in setRectTex. For example, if we use 60 (instead of 64) as the width and height of the image, then it fits exactly 5x across and 10x up, so m2:setRectTex(r,0,0,5,10) will look neater.

    You may find the image is the wrong scale for the rest of your scene, so you want to make the tiles smaller. You can halve their size, by simply doubling the numbers in setRectTex.

    This works because Codea only requires the image size to be a power of two. You can tile it as many times as you want, to get the effect you want.

    Also, it works on all meshes of all shapes and sizes, not just rectangles.

    B. This approach requires a power of two square image. What do you do if it's not a power of two, or not square? The answer is a shader which can handle any size image, and it's not difficult to use.

    function setup()
        --read an image
        img=readImage("Platformer Art:Block Brick")
        --this is the size we want to draw
        local w,h=300,600
    
        --First, set up a normal mesh
        --this will stretch our image across the whole mesh
        m1=mesh()
        m1:addRect(200,400,w,h)
        m1.texture=img
    
        --Second, set up another mesh which tiles the image repeatedly
        --The image needs to be a power of 2 size, ie 4,8,16,... pixels square
        --Our image is 70x70, so we need to convert it to a 
        --  power of two - 64 is closest
        img2=image(64,64) --create a 64x64 image and copy our picture 
        setContext(img2)
        sprite(img,32,32,64) --copy our image and shrink it to 64 pixels
        setContext()
    
        m2=mesh()
        m2.texture=img2
    
        --add rectangle as before (store id number of rectangle in r)
        local r=m2:addRect(500,400,w,h)
        --we set texture coordinates as multiples of image size
        --normal texture coords are (0,0) at bottom left to (1,1) top right
        --we calculate them as multiples of actual image size
        --so in this case, width=300 and image size=64, so it fits 4.6875 times
        --and height=600 and image height is 64, so it fits 9.375 times
        --set new texture coordinates
        m2:setRectTex(r,0,0,w/img2.width,h/img2.height) 
    end
    
    function draw()
        background(40)
        m1:draw()
        m2:draw()
    end
    
Sign In or Register to comment.