Menu

Even simpler ili9341 sprite

2017-11-15
2017-12-12
  • stan cartwright

    stan cartwright - 2017-11-15

    This is the simplest way to draw a multi coloured sprite I've found. It writes sprite height x width number of words to the display in a graphic window.
    Problem is sprite data is stored in tables that can only be 256 items and that includes the 1st byte which holds the table size..from help.
    A 16 x 16 pixel sprite is 256 words so as the last pixel is black a problem doesn't show. A square would show the problem but coloured thing looks more interesting.
    To get over this table size problem I used two tables and as the sprite sub is only a few lines I copied it to use two tables....I know, sloppy but can't think of another solution other than copy table to array then use that..
    It's quite fast visually but could be faster.
    https://www.youtube.com/watch?v=Wz8iw07ncqI&feature=youtu.be
    Sorry,can't see add file so-

    ;ILI9341 sprite demo
    #chip mega328p, 16
    #option explicit
    #include <glcd.h>
    ;
    #define GLCD_TYPE GLCD_TYPE_ILI9341
    #define GLCD_DC   portb.2
    #define GLCD_CS   portd.7
    #define GLCD_RESET   portd.4
    #define GLCD_DO   portb.3 ;  MOSI SDI
    #define GLCD_SCK   portb.5 ;    SCK
    #define ILI9341_HardwareSPI
    #define GLCD_EXTENDEDFONTSET1
    ;
    ;now rename colours to make it easier to set up sprite data
    #define bk ILI9341_BLACK
    #define re ILI9341_RED
    #define gr ILI9341_GREEN
    #define bl ILI9341_BLUE
    #define wh ILI9341_WHITE
    #define pu ILI9341_PURPLE
    #define ye ILI9341_YELLOW
    #define cy ILI9341_CYAN
    #define dg ILI9341_D_GRAY
    #define lg ILI9341_L_GRAY
    #define si ILI9341_SILVER
    #define ma ILI9341_MAROON
    #define ol ILI9341_OLIVE
    #define li ILI9341_LIME
    #define aq ILI9341_AQUA
    #define te ILI9341_TEAL
    #define na ILI9341_NAVY
    #define fu ILI9341_FUCHSIA
    ;
    GLCDBackground = ILI9341_BLACK
    GLCDRotate Portrait_Rev
    GLCDCLS ILI9341_BLACK
    ;
    dim sprite_height,sprite_width as byte ;height and width of sprite in pixels
    ;dim spritedata as byte;data to make sprite
    dim sprite_x,sprite_y as Word
    dim ptr,spritedata_ptr,pixel as word
    ;
    ;demo vars
    dim temp,frame as byte
    dim dx(8),dy(8) as word
    dim spy(8),oldspy(8) as word
    dim spx(8),oldspx(8) as word
    ;set up start sprite positions and directions
    dx(1)=2:dx(2)=3:dx(3)=65536-4:dx(4)=6
    dx(5)=65536-8:dx(6)=65536-8:dx(7)=65536-8:dx(8)=65536-8
    dy(1)=65536-5:dy(2)=65536-3:dy(3)=65536-8:dy(4)=3
    dy(5)=2:dy(6)=7:dy(7)=2:dy(8)=8
    spx(1)=30:spx(2)=100:spx(3)=150:spx(4)=50
    spx(5)=160:spx(6)=100:spx(7)=80:spx(8)=30
    spy(1)=20:spy(2)=20:spy(3)=16:spy(4)=50:spy(5)=60:spy(6)=40
    spy(5)=20:spy(6)=30:spy(7)=24:spy(8)=36
    sprite_height=16:sprite_width=16
    spritedata_ptr=0
    frame=0
    ;
    do ;demo moving sprite
      for temp=1 to 8
        if spx(temp)> (229-sprite_width) then ;check right edge
          dx(temp)= 65536-dx(temp)
        end if
        if spx(temp)<8 then ;check left edge
          dx(temp)= 65536-dx(temp)
        end if
        if spy(temp)> (319-sprite_height) then ;check bottom edge
          dy(temp)= 65536-dy(temp)
        end if
        if spy(temp)<8 then ;check top edge
          dy(temp)= 65536-dy(temp)
        end if
      ;
        oldspx(temp)=spx(temp):oldspy(temp)=spy(temp) ;get last position for erase
        spx(temp)=spx(temp)+dx(temp):spy(temp)=spy(temp)+dy(temp) ;get new position for draw
      ;
        if frame=0 then
          erase_sprite (oldspx(temp),oldspy(temp)) ;erase sprite at last position
          sprite1 (spx(temp),spy(temp)) ;draw sprite1 at new position
        else
          erase_sprite (oldspx(temp),oldspy(temp)) ;erase sprite at last position
          sprite2 (spx(temp),spy(temp)) ;draw sprite2 at new position
        end if
      ;
      next temp
      frame=!frame
    ;  wait 20 ms
    loop ;end demo
    ;
    sub sprite1 (sprite_x,sprite_y) ;fills box with sprite data
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +15,sprite_y +15 )
      for ptr=1 to 256
        ReadTable spritedata1,ptr,pixel
        SendWord_ILI9341 pixel
      next ptr
    end sub
    ;
    sub sprite2 (sprite_x,sprite_y) ;fills box with sprite data
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +15,sprite_y +15 )
      for ptr=1 to 256
        ReadTable spritedata2,ptr,pixel
        SendWord_ILI9341 pixel
      next ptr
    end sub
    ;
    sub erase_sprite (sprite_x,sprite_y) ;write a box of 0's
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +15,sprite_y +15 )
      repeat 256
        SendWord_ILI9341 0
      end repeat
    end sub
    ;
    table spritedata1
    bl,bl,bl,bl,bl,bk,bk,bk,bk,bk,bk,bl,bl,bl,bl,bl
    bk,bl,re,re,re,bl,bl,bk,bk,bl,bl,re,re,re,bl,bk
    bk,bk,bl,re,re,re,bl,bk,bk,bl,re,re,re,bl,bk,bk
    bk,bk,bk,bl,re,wh,bl,bk,bk,bl,wh,re,bl,bk,bk,bk
    bk,bk,bk,bk,bl,wh,bl,bk,bk,bl,wh,bl,bk,bk,bk,bk
    bk,bk,bk,bk,bk,bl,bl,bk,bk,bl,bl,bk,bk,bk,bk,bk
    bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk
    bk,bk,bk,bk,ye,ye,ye,bk,bk,ye,ye,ye,bk,bk,bk,bk
    bk,bk,bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk,bk,bk
    bk,ye,ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye,ye,bk
    bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk
    ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye
    ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye
    ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye
    bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk
    bk,bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk,bk
    end table
    ;
    table spritedata2
    bl,bl,bl,bl,bl,bk,bk,bk,bk,bk,bk,bl,bl,bl,bl,bl
    bk,bl,re,re,re,bl,bl,bk,bk,bl,bl,re,re,re,bl,bk
    bk,bk,bl,re,re,re,bl,bk,bk,bl,re,re,re,bl,bk,bk
    bk,bk,bk,bl,re,wh,bl,bk,bk,bl,wh,re,bl,bk,bk,bk
    bk,bk,bk,bk,bl,wh,bl,bk,bk,bl,wh,bl,bk,bk,bk,bk
    bk,bk,bk,bk,bk,bl,bl,bk,bk,bl,bl,bk,bk,bk,bk,bk
    bk,bk,bk,bk,bk,bk,bk,ye,ye,bk,bk,bk,bk,bk,bk,bk
    bk,bk,bk,bk,bk,ye,ye,bk,bk,ye,ye,bk,bk,bk,bk,bk
    bk,bk,bk,bk,ye,ye,bk,bk,bk,bk,ye,ye,bk,bk,bk,bk
    bk,bk,bk,bk,ye,bk,bk,bk,bk,bk,bk,ye,bk,bk,bk,bk
    bk,bk,bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk,bk,bk
    bk,bk,ye,bk,bk,bk,bk,bk,bk,bk,bk,bk,bk,ye,bk,bk
    bk,bk,bk,ye,ye,bk,bk,bk,bk,bk,bk,ye,ye,bk,bk,bk
    bk,bk,bk,bk,ye,ye,bk,bk,bk,bk,ye,ye,bk,bk,bk,bk
    bk,bk,bk,bk,bk,ye,bk,bk,bk,bk,ye,bk,bk,bk,bk,bk
    bk,bk,bk,bk,bk,bk,ye,bk,bk,ye,bk,bk,bk,bk,bk,bk
    end table
    
     
    • Anobium

      Anobium - 2017-11-15

      Good stuff

      I am not aware of a table limitation of 256. This is an error in the Help - where does it state this. I will revise.

       
      • Anobium

        Anobium - 2017-11-15

        I have just tried the code.

        Can you check the code is complete and it works on cleanish installation? I get nothing on the screen. I have used the standard 'GLCD_Read_Demonstation_mega328p_for_ILI9341@16.gcb' as a compplete test and this works ok.

         
  • stan cartwright

    stan cartwright - 2017-11-15

    I just downloaded/installed gcb 98.01 again and loaded/flashed program and works ok.
    Instead of copy/paste I've attatched the code.

     
  • stan cartwright

    stan cartwright - 2017-11-15

    From readtable help-
    Item is 1 for the first line of the table, 2 for the second, and so on. Item 0 gives the size of the table. Care must be taken to ensure that the program is not told to read beyond the end of the table, or strange effects will be observed.
    I tried using var sprite_ptr. Set to 1 read first sprite table. Set to 257 read second sprite table but didn't!
    I can only read 256 of 512 items...words.Note I defined background pixels in table as black not 0 which is one byte as in my previous sprite code and two 12 x 12 sprites was 288 items was not a problem.
    Please test readtable for table size.

    sub sprite (sprite_x,sprite_y) ;fills box with sprite data
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +15,sprite_y +15 )
      for ptr=sprite_ptr to sprite-ptr+256
        ReadTable spritedata2,ptr,pixel
        SendWord_ILI9341 pixel
      next ptr
    end sub
    
     
    • Anobium

      Anobium - 2017-11-15

      I will update the Help. There is no limitation on 256 elements. Where exactly is this stated in the Help.

      You must therefore use a WORD to read the table data. Try again with a WORD.

       
  • stan cartwright

    stan cartwright - 2017-11-15

    In the code I posted I used dim ptr,spritedata_ptr,pixel as word to access table which was one big table not two. Setting ptr to 257 didn't read second table.
    Please try to read both tables ie remove end table and table sprite_data2 so it's one 512 item table and please let me know. I'll try to do code to illustrate not more than 256 items. Hope it's an error on my part. Could you not just read a 1000 word table and ser print results to test.
    Create one line and copy/paste to many,

     
    • Anobium

      Anobium - 2017-11-15

      you give it a go first, post your results.

       
  • stan cartwright

    stan cartwright - 2017-11-15

    I take it back.DOH moment.
    I changed sprite sub to one sub and spritedata_ptr points to start of table or 257 items further and it works. This was my first effort that failed. Can't see what I've changed. Hmmmm...

    sub sprite (sprite_x,sprite_y) ;fills box with sprite data
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +15,sprite_y +15 )
      for ptr=spritedata_ptr to spritedata_ptr+256
        ReadTable spritedata,ptr,pixel
        SendWord_ILI9341 pixel
      next ptr
    end sub
    

    and changed frame to animate between 2 sprites

        if frame=0 then
          erase_sprite (oldspx(temp),oldspy(temp)) ;erase sprite at last position
    spritedata_ptr=1 :start of sprite one data
          sprite (spx(temp),spy(temp)) ;draw sprite1 at new position
        else
          erase_sprite (oldspx(temp),oldspy(temp)) ;erase sprite at last position
    spritedata_ptr=257 :start of sprite two data
          sprite (spx(temp),spy(temp)) ;draw sprite2 at new position
        end if
    
     

    Last edit: stan cartwright 2017-11-15
    • Anobium

      Anobium - 2017-11-15

      I can test. Is this complete working solution?
      Did you sort the last byte in the sprite table?

      And, we need to agree the standard ports for CS and DC. We are not using the same ports... with one of mine being the same as the Arduino library and your CS&DC neither match. If we aggree on a standard then I will change the demos to suit our new standard ports for CD&DC.

       
  • stan cartwright

    stan cartwright - 2017-11-15

    Fair,I changed ports for existing hardware.Posted more in the spirit, I thought it so simple so share.
    I added a frame counter to "show" animation at end of demo. Only 2 frames but could be 3 or more.
    I've attatched working code that uses "#include <UNO_mega328p.h>" and "DIGITAL_8" for gcb standard for arduino. Should plug play hope
    video of code working https://youtu.be/YS2wjLmu4zA

      frame_count++
      if frame_count=5 then
        frame=!frame
        frame_count=0
      end if
    ;  wait 20 ms
    loop ;end demo
    
     
  • stan cartwright

    stan cartwright - 2017-11-15

    bollards. I can see why you test stuff. For 256 items then I was one out.
    Was spritedata_ptr+256. should be

      for ptr=spritedata_ptr to spritedata_ptr+255
    

    gcb starts at 1
    first "item" in table is length of tabel. What is the item , byte,word or long as the items in a table can be byte,word or long?

     
    • Anobium

      Anobium - 2017-11-16

      Confused. Is this a change that needs be made to all the demos?

      for ptr=spritedata_ptr to spritedata_ptr+255

      Do I need to add?


      I have remove Item 0 gives the size of the table. from the Help as this is not general rule and is clearly confusing.


      And, to clarify. Great Cow BASIC table data starts at element 1. The Table handler will look after element Zero for you - so, as a general principle do not ever assume element Zero is the length.
      You should use the following principe to ensure that you get it right all the time.
      1. The first "item" in table is NOT the length of table.
      2. A single value should be on each line
      3. Byte, word, longs and integer values are valid (no strings or decimals!)
      4. Multiple elements on a single line separated by commas but see item #2 above. A good practice is #2
      5. Constants and calculations within the single line data table entries are permitted
      6. You can use an external data source file as your table dataset.
      7. To read a table of more than 256 elements you MUST you a WORD variable to address the element.

       
  • stan cartwright

    stan cartwright - 2017-11-16

    I re-attatched the last code posted, seems ok but I need a magnifier to see the sprite pixels.
    It uses

    #define GLCD_TYPE GLCD_TYPE_ILI9341
    'Pin mappings for SPI - this GLCD driver supports Hardware SPI and Software SPI
    #define GLCD_DC       DIGITAL_8         ' Data command line
    #define GLCD_CS       DIGITAL_10          ' Chip select line
    #define GLCD_RESET    DIGITAL_9         ' Reset line
    #define GLCD_DI       DIGITAL_12          ' Data in | MISO    - Not used therefore not really required
    #define GLCD_DO       DIGITAL_11          ' Data out | MOSI
    #define GLCD_SCK      DIGITAL_13          ' Clock Line
    

    as in the glcd solutions if this is the standard gcb pins for uno.
    As you hinted, using glcd window and writing words is faster than checking lit pixels and writing one word at a time. Also the erase is easy to.
    Did the code run for you?
    ps will miso be defined for read pixel routine?

     
    • Anobium

      Anobium - 2017-11-16

      Works dandy.

      The others dont know what they are missing!

      I have adapted. Tiny improvements in passing paramers, background color change is now very easy, changing the framerate is now a constant (I like #define bg = teal), I have reverted to UNO Shield naming convension - all the other demos use this method.

      If you want to review, and final tweaks, I would gladly publish as a demo.

      I want to see the next part of the game when the touch one eats the another! One less.....

       
  • stan cartwright

    stan cartwright - 2017-11-16

    I'm implementing collision detection tests. I thought the few lines I pinched from the include to use glcd_window may be useful to add to the other graphic routines. Surprised you didn't add it as you wrote the glcd include and are familiar with it. A fill routine would be useful now we have pixel read to implement it. Try drawing a dart board without fill. I thought about that and it and remembered doing Bullseye on amstrad converted from bbc micro with no fill. I cheated and made 1/4 of the dartboard a sprite and copied the data to the other 3/4.

     
    • Anobium

      Anobium - 2017-11-16

      can you adapt the one I just posted? else, I am doing the same thing over and over again which is trying to improve your code and you are not levering.

       
  • stan cartwright

    stan cartwright - 2017-11-16

    For a routine I'd suggest sprite (x,y,width,height,ptr)
    erase_sprite (x,y,width,height)
    The table could be 8 x8, 16 x 16, any size blocks in one table...as is and the ptr to which block to use you choose and set width and height to display that block.
    The whole post comes down to this, a sprite sub. It was posted as a guide idea.
    Is this what you'd like? As I decribed it's adaptable and seems easy to. I could change the demo to use this and as always, any suggestions welcome.
    I would keep draw and erase separate as you might not want to erase just draw.

    sub sprite (sprite_x,sprite_y,sprite_width,sprite_height,spritedata_ptr)
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +sprite_width-1,sprite_y +sprite_height-1 )
      for ptr=spritedata_ptr to spritedata_ptr+(sprite_width * sprite_height)
        ReadTable spritedata,ptr,pixel
        SendWord_ILI9341 pixel
      next ptr
    end sub
    ;
    sub erase_sprite (sprite_x,sprite_y,sprite_width,sprite_height) ;write a box of 0's
      SetAddressWindow_ILI9341 ( sprite_x,sprite_y,sprite_x +sprite_width-1,sprite_y +sprite_height-1 )
      repeat 256
        SendWord_ILI9341 GLCDBackground
      end repeat
    end sub
    

    draft idea not tested yet
    ps thinking the demo is too big, just as in help, keep it simple, so a simple draw GCB Cow image and data for cow image say 32 x48...and to show off, make it moov :)

     

    Last edit: stan cartwright 2017-11-16
    • Anobium

      Anobium - 2017-11-16

      So, are you going to do what? I am confused. Are you asking me to change the file I have here?

       
  • stan cartwright

    stan cartwright - 2017-11-16

    you have my code Anobium, I thought it would stay in the forum here to use as wanted.
    If you can use it officially then the above sprite and erase sprite with height width, not set as in demo, would be more general purpose.
    It wasn't intended for demos, just A demo.
    By tomorrow I'll do a proper demo with lot's of explanation griff. I'll send it to @Bed..he won't understand it either :)

     
    • bed

      bed - 2017-12-12

      Hi Stan I must have overseen this.
      Did you already sent the demo to me?
      Maybe sometimes is something wrong with the sf.net email address so I'll send you my main emailaddress as PM

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.