Challenge #27 - Learn binary operations through Retro Computer Graphics

Started by kevin, February 05, 2014, 11:33:55 AM

Previous topic - Next topic

kevin





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
 
 * 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,  Twitter or the PlayBASIC youtube channel.



kevin


   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..



PlayBASIC Code: [Select]
      // 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
Login required to view complete source code