December 03, 2020, 08:02:37 PM

Author Topic: [bmx] Palette Rotation by TomToad [ 1+ years ago ]  (Read 779 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] Palette Rotation by TomToad [ 1+ years ago ]
« on: June 29, 2017, 12:28:43 AM »
Title : Palette Rotation
Author : TomToad
Posted : 1+ years ago

Description : This program will simulate the palette rotation used to animate back in 8 bit days.  By creating "color planes" out of images and layering them, you can assign colors to each plane and alter them quickly.  Hopefully my example code is clear. It draws a "bullseye" of concentric colored rings, then rotates the colors.  

If you really want to have fun, stare at the middle of the "bullseye" for 30 seconds, then look at something like the back of your hand or someone's face.

Edit: Changed Pallet to Palette in the description. :)

Edit 2: Optimised the PlotPixel routine.  Cuts plotting time by as much as 50%.  Also changed all instances of Pallet to Palette. :)


Code :
Code: BlitzMax
  1. SuperStrict
  2.  
  3. Graphics 800,600
  4.  
  5. 'We need to create the color planes.  We will use 16 fullscreen TImages.  Note that you only need the images to
  6. '  Be big enough to cover the area you wish to have a Palette
  7. Global Planes:TImage[16]
  8.  
  9. 'Next, we need to create a Palette.  Each color corrisponds to one of the color planes.  You can use any color you want
  10. '  Here, I fill it with some default values
  11. Global Palette:Int[] = [$000000,$FFFFFF,$FF0000,$00FF00,$0000FF,$FF00FF,$FFFF00,$00FFFF, ..
  12.                                                 $7F7F7F,$7f0000,$007F00,$00007F,$7F007F,$7F7F00,$007F7F,$FF7F00]
  13.  
  14.  
  15.  
  16. 'This is a more optimized PlotPixel than before.  It will queue all the changes, but only commit the changes when rendering to the screen
  17. '   for the first time
  18. Type TPixel 'a pixel type
  19.         Field x:Int, y:Int
  20.        
  21.         Function Create:TPixel(x:Int,y:Int)
  22.                 Local Pixel:TPixel = New TPixel
  23.                 Pixel.x = x
  24.                 Pixel.y = y
  25.                 Return Pixel
  26.         End Function
  27. End Type
  28.  
  29. Type TQueue 'Creating a type for the queued pixels
  30.         Field Dirty:Int = False 'A flag that is set when pixels are queued
  31.        
  32.         Field Pixels:Byte[800,600] 'An array to hold the indexes for the Planes pixel queue.  To make searching the queue faster.
  33.         Field Pixmaps:TPixmap[16] 'All rendering will be done to pixmaps then transfered to the Planes
  34.         Field Queue:TList[16] 'An array of lists to hold the queued pixels
  35.         Field ClearQueue:TList = CreateList() 'Pixels to be cleared in each plane
  36.        
  37.         Method New() 'Initialize the values
  38.                 For Local i:Int = 0 To 15
  39.                         Queue[i] = CreateList() 'Initialize the queue
  40.                         Pixmaps[i] = CreatePixmap(800,600,PF_RGBA8888) 'Create the pixmap
  41.                         If i = 0 'Pixmap 0 will be all set, the rest clear
  42.                                 ClearPixels(Pixmaps[0],$FFFFFFFF)
  43.                         Else
  44.                                 ClearPixels(Pixmaps[i],$00FFFFFF)
  45.                         End If
  46.                         Planes[i] = LoadImage(Pixmaps[i]) 'Transfer the pixmap to the Plane
  47.                 Next
  48.                 For Local y:Int = 0 To 599
  49.                         For Local x:Int = 0 To 799
  50.                                 Pixels[x,y] = 16 'Using 16 to signify that this pixel hasn't been queued anywhere
  51.                         Next
  52.                 Next
  53.         End Method
  54.        
  55.         Method QueuePixel(x:Int, y:Int, Plane:Int) 'queues the pixel for writing
  56.                 Local Queued:Int = Pixels[x,y] 'Which plane is this pixel queued in?
  57.                 If Plane = Queued Then Return 'This pixel is already queued.  No need to do it twice
  58.                
  59.                 'We must first remove the queued pixel before changing planes
  60.                 If Queued < 16 'If 16, then pixel is not queued and does not need to be removed
  61.                         For Local Pixel:TPixel = EachIn Queue[Queued]
  62.                                 If Pixel.x = x And Pixel.y = y 'We have found our queued pixel
  63.                                         Queue[Queued].Remove(Pixel) 'Remove this pixel from the queue
  64.                                         Exit 'exit the loop
  65.                                 End If
  66.                         Next
  67.                 End If
  68.                
  69.                 'Now we must queue the pixel into the new plane
  70.                 Pixels[x,y] = Plane
  71.                 Queue[Plane].AddLast(TPixel.Create(x,y))
  72.                
  73.                 'last, we need to mark the queue dirty so the renderer knows it needs to commit
  74.                 Dirty = True
  75.         End Method
  76.        
  77.         'Here we commit the changes made and clear the queue
  78.         Method Commit()
  79.                 If Not Dirty Then Return 'no need to commit if no changes are made
  80.                
  81.                 For Local i:Int = 0 To 15 'Go through each plane's queue
  82.                         For Local Pixel:TPixel = EachIn ClearQueue 'First we will set alpha to 0 on pixels that should be clear
  83.                                 Pixmaps[i].pixels[Pixel.y*Pixmaps[i].pitch+Pixel.x*4+3] = 0 'A little bit of math for faster access to the pixmap's pixels
  84.                         Next
  85.                         For Local Pixel:TPixel = EachIn Queue[i] 'now we will write the pixels in the queue
  86.                                 Pixmaps[i].pixels[Pixel.y*pixmaps[i].pitch+Pixel.x*4+3] = $ff 'same math as before :)
  87.                                 ClearQueue.AddLast(Pixel) 'Add this pixel to the Clear queue so all planes above will clear this pixel
  88.                                 Pixels[Pixel.x,Pixel.y] = 16 'this pixel no longer needs to be indexed
  89.                         Next
  90.                         Queue[i].Clear() 'Clear this plane's queue
  91.                         Planes[i] = LoadImage(Pixmaps[i]) 'transfer the pixmap to the image
  92.                 Next
  93.                
  94.                 ClearQueue.Clear() 'Clear the clear queue.
  95.                 Dirty = False 'now everything is reset to be filled again :)
  96.         End Method
  97. End Type
  98. Global Queue:TQueue = New TQueue 'now to create the queue
  99.                
  100.                
  101. ' Place a pixel into the queue
  102. Function PlotPixel(x:Int,y:Int,Plane:Int)
  103.         If x > 799 Or x < 0 Or y > 599 Or y < 0 Or plane > 15 Or plane < 0 Then Return 'Pixel out of range
  104.         Queue.QueuePixel(x,y,Plane)
  105. End Function
  106.  
  107. 'Here we render the planes.  We grab the color from the Palette and seperate the components for SetColor.  Then draw the plane to the screen
  108. Function RenderScreen()
  109.         Queue.Commit() 'commit any changes to the planes
  110.         For Local i:Int = 0 To 15
  111.                 Local Red:Int = (Palette[i] & $FF0000) Shr 16
  112.                 Local Green:Int = (Palette[i] & $FF00) Shr 8
  113.                 Local Blue:Int = Palette[i] & $FF
  114.                
  115.                 SetColor Red,Green,Blue
  116.                 DrawImage Planes[i],0,0
  117.         Next
  118. End Function
  119.  
  120. 'A little message to display to let people know something is going on.
  121. Cls
  122. DrawText "Please wait, setting up graphics",10,10
  123. Flip
  124. 'We shall plot some concentric rings. Distance is modded to 16 to corrispond to one of the 16 planes
  125. For Local y:Int = 0 To 599
  126.         For Local x:Int = 0 To 799
  127.                 Local Distance:Int = Sqr((x-400)^2+(y-300)^2)/5
  128.                 PlotPixel(x,y,Distance Mod 16)
  129.         Next
  130. Next
  131.  
  132.  
  133. While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
  134.         RenderScreen 'Here we render the color planes, no need for Cls as the planes will cover the entire screen
  135.         Flip 'Then flip, If you get a lot of tearing on the screen, change this to Flip 1
  136. 'Rem   
  137.         'Here we rotate the Palette entries by one. :-)
  138.         Local Temp:Int = Palette[0]
  139.         For Local i:Int = 0 To 14
  140.                 Palette[i] = Palette[i+1]
  141.         Next
  142.         Palette[15] = temp     
  143. 'End Rem
  144.  
  145. Rem 'rem out the previous lines and remove the rem/endrem here to see Palette being manipulated in a different way
  146.         For Local i:Int = 0 To 15
  147.                 Palette[i] = (Palette[i] + 1) &$FFFFFF
  148.         Next
  149. End Rem
  150. Wend


Comments :


dw817(Posted 1+ years ago)

 Good Old School graphics ! You even have the palettes right, I recognize that color set. :)There MIGHT be a faster way to do this. How about using drawing your circles with DrawOval() and using GrabImage() ?


TomToad(Posted 1+ years ago)

 I'm sure there are faster ways to plot the pixels, but it is not as easy as just using DrawOval.  In order for this to work, for every pixel set on a plane, the alpha must be 0 on the corresponding  pixel on every other plane.  I guess you can create each plane in a paint program and use Loadimage to load them in.


skidracer(Posted 1+ years ago)

 TomToad: from your spelling I was a bit confused. I was expecting code using shipping pallets not colour palettes.


TomToad(Posted 1+ years ago)

 @simonarmstrong:  Fixed in my update :)


 

SimplePortal 2.3.6 © 2008-2014, SimplePortal