UnderwareDESIGN

General => Competitions => CleverCoders => Topic started by: kevin on February 05, 2014, 11:33:55 AM

Title: Challenge #27 - Learn binary operations through Retro Computer Graphics
Post by: kevin on February 05, 2014, 11:33:55 AM

(http://www.underwaredesign.com/PlayBasicSig.png) (http://www.playbasic.com)


Challenge #27 -  Learn binary operations through Retro Computer Graphics  


   Those who grew up in the age of 8bit computers would no doubt remember the pain of writing video games on these systems.   It wasn't just the speed, but it felt like the graphics hardware designers were conspiring against the programmer at times, intentionally making it difficult to do the most trivial of tasks.     Like you'd think drawing a DOT would be easy right ?  Unfortunately not, as many if those systems have scrambled video memory layouts and packed bit / planar displays.   The upside of that, is it really made you learn about Binary operations and low level memory access.  Which seems to be a thing of the past today in BASIC programming.

   One common format seen in many retro computer systems for bitmap graphics are variations of planar.  Generally in these formats 8  pixels on screen are represented within a single byte (plus generally a character map).   Each bit in the byte is an individual pixel on screen.    This can be pretty efficient in terms of memory usage, but it raises the complexity of drawing bitmap graphics.     So to make this challenge somewhat easier the Retro Computer Environment library emulates a 2 colour planar graphics hardware.

   The screen is 640*400 pixels, each pixel is a single BIT, so it's two possible colours.  The screen memory is (640/8)*400 bytes.  Each row is a (640/80) 80 bytes long.  The manipulate the individual pixels you'll need to calculate the location of the byte that contains the pixel(s) then AND  / OR / XOR the bits..  


   The attached template does all the work (and includes some example rendering functions DOT / BOX / CLS to get you started), but your challenge is try and implement either better ways of doing those functions as well of other primitive drawing functions.  



   Graphics Programming Challenges:

     * Dot (Replace it)
     * Box (Replace it)
     * Add Font/Character Rendering
     * Add Sprite rendering (clipping optional)
     * Line  (clipping optional)
     * Circle  (clipping optional)
     * Polygon  (clipping optional)




    The challenge is not only to come up a with some rendering functions, but try and come up with the most optimal method you can.   What you'll find, is that the more you look over your code you'll start to see alternative methods for solving each problem.   I'll give you a hint, the most optimal solution tends not to be the first or second attempt, it's probably going to take you a 3 or 4 attempts to really get something up to speed..


   So for those that on take such this challenge, you'll learn many fundamentals (dealing with Binary data / memory access & more importantly optimization) that will translate into your everyday BASIC programming skills.       It's not an easiest challenge and it's not meant to be !  

    Good luck !



    As always we'll award   Extra Brownie points to the most creative submissions .

Downloads


     The Retro Computer Environment is attached to this post bellow.  The whole idea here is you add your functions to the template to build your own mini graphics library.   So when you post your solutions, you don't need to include the RCE library, just the code in your Main source file.  


8Bit Games

    Here's a look a classic game ELITE written way back in the early 80's

   

   


   BBC version shown


Submission

 * Submissions can be written in any version of PlayBASIC (https://www.playbasic.com)
 
 * Submission can only be accepted in Source Code form only.

 * No external media is permitted for this challenge.

 * Zip up your Submissions and please try to keep it smaller than 500K !

 * Authors automatically give consent for their submission(s) to distributed and used for promotional purposes via UnderwareDesign.com, PlayBasic.com code tank.

 * Authors can submit as many times as they like.

 * To make a submission, zip up your projects and either post it in this thread, or create your own thread in either the Source Codes or Show Case forums and post a link bellow.



Dead Line

    Anytime before the next ice age



Prizes

    * The best submissions will be periodically highlighted through the PlayBasic IDE news service / News Letters/ FaceBook (http://www.facebook.com/pages/PlayBasic/127905400584274),  Twitter (http://www.twitter.com/PlayBasic) or the PlayBASIC youtube channel (http://www.youtube.com/playbasic).




Return to Challenge Index (https://www.underwaredesign.com/forums/index.php?topic=3225.0)

Title: Re: Challenge #27 - Learn binary operations through Retro Computer Graphics
Post by: kevin on February 15, 2014, 08:06:30 AM

   In the example above, the code includes a hardwired character render routine.  Characters are aligned to BYTEs not bits, so the character can only be drawn to multiples of 8 pixels on the X axis.  To get around this we need to shift the bits into place.  Of course this introduces a problem, as If we take one byte (8pixels) and they need to be shifted right by 3 pixels say, then the bottom 3 bits in the original byte are lost..

   8pixels (all set to colour 1)

   pixels=%11111111

   if we shift them right 3, we get

   pixels=%00011111

   as you can see the bottom 3 bits are lost,since they're being pushed into the next byte.    So when our 8 pixels are offset, we need to access two bytes, not just one.


   The code bellow shows one way of doing it.    A better way would be to render to the sprite in 16bit..



[pbcode]

      // Cut'n'Paste into the RCE template   

      Do   
      
                  RCE_CLS()


         ; calc mouse position over the simulated video memory
            MX=RCE_MouseX()
            MY=RCE_MouseY()
         
         ; get mouse state
            State=MouseButton()
   
         ; if left mouse is pressed, draw a dot in colour 1
            if State=1            
                  RCE_Dot(mx,my,1)
            endif
   
         ; if right mouse is pressed we draw a box
            if State=2            
                  RCE_Box(mx,my,mx+50,my+50,1)
            endif


         ; if space key is pressed
         ;   if Spacekey()
         ;      RCE_CLS()
         ;   endif
            

         // Render 8by8 Sprite
            restore Sprite1            
            
            For lp=0 to 7
               ThisByte=readdata()
               Render_Sprite_Bits_To_Frame_Buffer(mx-8,my-8+lp,ThisByte)
            next

         ; render A character to frame buffer
            for lp =0 to 100
               Xpos=mod(CharPos+lp,80)
               Ypos=(CharPos+lp)/80
               Render_Character_To_Frame_Buffer(Xpos,Ypos)
            next
            CharPos=mod(CharPos+2,80*50)
            
         ;  draw the RCE screen and flip PB screen            
            RCE_SYNC()
         
      loop


;*=-----------------------------------------------------------------------------=*   
;*=---------------------->> Draw Character Example <<-----------------------=*   
;*=-----------------------------------------------------------------------------=*   

Psub Render_Character_To_Frame_Buffer(Xpos,Ypos)
      ptr=RCE_ScreenPointer()

      Modulo =RCE_SCreenModulo()   ; Bytes per row

      if Xpos>=0 and Xpos<Modulo
         if Ypos>=0 and Ypos<(RCE_ScreenHeight()/8)
      
            ptr+=(Ypos*(8*Modulo))+Xpos
      
            pokebyte ptr,%00000000      : Ptr+=Modulo
            pokebyte ptr,%00010000      : Ptr+=Modulo
            pokebyte ptr,%00111000      : Ptr+=Modulo
            pokebyte ptr,%01101100      : Ptr+=Modulo
            pokebyte ptr,%11000110      : Ptr+=Modulo
            pokebyte ptr,%11111110      : Ptr+=Modulo
            pokebyte ptr,%11000110      : Ptr+=Modulo
            pokebyte ptr,%11000110      : Ptr+=Modulo
         endif
      endif   

EndPsub






;*=-----------------------------------------------------------------------------=*   
;*=---------------------->> Draw 8bit Scan line <<-----------------------=*   
;*=-----------------------------------------------------------------------------=*   

Psub Render_Sprite_Bits_To_Frame_Buffer(Xpos,Ypos,SpriteBits)
      ptr=RCE_ScreenPointer()

      ScreenWidth=RCE_ScreenWidth()
      if Xpos>=0 and Xpos<ScreenWidth
         if Ypos>=0 and Ypos<RCE_ScreenHeight()
            Modulo =RCE_SCreenModulo()   ; Bytes per row

            // address of scan line in the frame buffer
            ptr+=(Ypos*Modulo)
            
            // compute the byte offset of this pixel
            Xoffset=Xpos/8

            // Shift offet
            Shift=(Xpos-(Xoffset*8))
                        
            Address=Ptr+Xoffset

            // read the existing group of 8 bits
            ThisByte=PeekByte(Address)
            
            // Or the sprite bits to the screen
            ThisByte|= SpriteBits>>Shift

            // write the or'd bits back to the frame buffer
            PokeByte Address, ThisByte

   
            // check if the  byte needs shifting, if so draw the overflowed bits
            // to the next byte on this row
            if Shift
                  Xoffset++
                  if Xoffset<Modulo
                        Address=Ptr+Xoffset
            
                        // read the existing group of 8 bits
                        ThisByte=PeekByte(Address)
            
                        // Or the sprite bits to the screen
                        ThisByte|= SpriteBits<<(8-Shift)

                        // write the or'd bits back to the frame buffer
                        PokeByte Address, ThisByte

                  endif
            endif
            

         endif
      endif   

EndPsub




SPRITE1:
         data %00000000      
         data %00010000      
         data %00111000      
         data %01101100      
         data %11000110      
         data %11111110      
         data %11000110      
         data %11000110      

[/pbcode]