November 24, 2020, 06:52:59 AM

Author Topic: [bmx] Cellular Textures by BlitzSupport [ 1+ years ago ]  (Read 751 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] Cellular Textures by BlitzSupport [ 1+ years ago ]
« on: June 29, 2017, 12:28:38 AM »
Title : Cellular Textures
Author : BlitzSupport
Posted : 1+ years ago

Description : This is just a quick hacky implementation of the method described in this great little article by Carsten Przyluczky:

<a href="http://www.gamedev.net/reference/programming/features/cellTxt/" target="_blank">http://www.gamedev.net/reference/programming/features/cellTxt/[/url]

I have only implemented the method outlined in the first section, "The basic approach", just to see if I could get it to work, so it's not fast. I recommend reading the article for suggestions as to how this can be improved or altered to create other patterns and speed it up. (I do intend to try the grid approach for the sake of creating cool tileable textures!)


Code :
Code: BlitzMax
  1. ' Array of pixels in 'texture' to be generated...
  2.  
  3. Local points:Float [256, 256]
  4.  
  5. ' Number of random points to use for generating cells...
  6.  
  7. rpoints = 20 ' Play with this! Higher values get slower and slower...
  8.  
  9. ' 2D point type...
  10.  
  11. Type Point
  12.         Field x:Float
  13.         Field y:Float
  14. End Type
  15.  
  16. ' Array of Point objects...
  17.  
  18. Local random:Point [rpoints]
  19.  
  20. ' A list for the random points...
  21.  
  22. pointlist:TList = CreateList ()
  23.  
  24. ' Display stuff...
  25.  
  26. Graphics 640, 480
  27.  
  28. gw2 = GraphicsWidth () / 2.0
  29. gh2 = GraphicsHeight () / 2.0
  30.  
  31. SetBlend LIGHTBLEND
  32. AutoMidHandle True
  33.  
  34. ' Create a pixmap to draw to...
  35.  
  36. pix:TPixmap = CreatePixmap (256, 256, PF_RGB888)
  37.  
  38. ' Main loop...
  39.  
  40. Repeat
  41.  
  42.         Cls
  43.  
  44.         ' Delete last set of random points...
  45.                
  46.         ClearList pointlist
  47.        
  48.         ' Generate new ones and add to list...
  49.        
  50.         For r = 0 To rpoints - 1
  51.                 pt:Point = New Point
  52.                 pt.x = Rand (0, 255)
  53.                 pt.y = Rand (0, 255)
  54.                 ListAddLast pointlist, pt
  55.         Next
  56.                
  57.         ' Iterate through all pixels in texture...
  58.        
  59.         For x = 0 To 255
  60.        
  61.                 For y = 0 To 255
  62.                
  63.                         ' Set start values...
  64.                        
  65.                         closest# = 255
  66.                         furthest# = 0
  67.                        
  68.                         ' For every pixel, find the nearest of the random points...
  69.                        
  70.                         For pt = EachIn pointlist
  71.                                 d# = Dist (x, y, pt.x, pt.y)
  72.                                 If d < closest Then closest = d
  73.                         Next
  74.                        
  75.                         ' This pixel's colour value is based on distance to nearest random point...
  76.                        
  77.                         points [x, y] = closest
  78.        
  79.                 Next
  80.                
  81.         Next
  82.        
  83.         ' Have to scale the distance to 0-255 so it can be used to set the colour...
  84.  
  85.         scale# = 255.0 / closest
  86.        
  87.         ' Scale each pixel's colour value to fit 0-255 (points is the pixel array)...
  88.        
  89.         For p:Float = EachIn points
  90.                 p = p * scale
  91.         Next
  92.  
  93.         ' Write colour value for each pixel into the pixmap...
  94.        
  95.         For x = 0 To 255
  96.                 For y = 0 To 255
  97.                         color = points [x, y]
  98.                         color = ((color Shl 16) + (color Shl 8) + color) ' Conversion to RGB...
  99.                         WritePixel pix, x, y, color
  100.                 Next
  101.         Next
  102.        
  103.         ' Grab image from bitmap so it can be scaled...
  104.        
  105.         image:TImage = LoadImage (pix)
  106.  
  107.         ' Draw result! Try different combinations of the below...
  108.        
  109.         SetScale GraphicsWidth () / 256.0, GraphicsHeight () / 256.0
  110.         SetColor 255, 255, 255
  111.         DrawImage image, gw2, gh2
  112.  
  113. '       SetScale GraphicsWidth () / 256.0, -GraphicsHeight () / 256.0
  114. '       SetColor 255, 0, 0
  115. '       DrawImage image, gw2, gh2
  116.  
  117. '       SetScale -GraphicsWidth () / 256.0, GraphicsHeight () / 256.0
  118. '       SetColor 0, 255, 0
  119. '       DrawImage image, gw2, gh2
  120.  
  121. '       SetScale -GraphicsWidth () / 256.0, -GraphicsHeight () / 256.0
  122. '       SetColor 0, 0, 255
  123. '       DrawImage image, gw2, gh2
  124.  
  125.         ' Draw the random points used for calculation...
  126.        
  127.         'SetColor 255, 0, 0
  128.        
  129.         'For pt = EachIn pointlist
  130.         '       Plot pt.x, pt.y
  131.         'Next
  132.        
  133.         Flip
  134.  
  135. Until KeyHit (KEY_ESCAPE)
  136.  
  137. End
  138.  
  139. ' Distance between x/y points...
  140.  
  141. Function Dist:Float (x1:Float, y1:Float, x2:Float, y2:Float)
  142.         Return Sqr (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)))
  143. End Function


Comments :


GW(Posted 1+ years ago)

 This is pretty cool. Thanks!looks a lot like the Voronoi diagram. but less complicated. too bad its not possible to get access to the lines and intersections created.


tesuji(Posted 1+ years ago)

 Very nice.Spent an evening playing around with this and got the tileable version working. Still aesthetically prefer the un-optimized version somehow as it's a bit more random but tiling is useful.
Code: [Select]
SuperStrict

Graphics 1024, 768, 32

Local displayTiled:Int = True

While Not KeyHit(KEY_ESCAPE)

Cls

If displayTiled
Local image:TImage = LoadImage(TextureGenerator.cellTileTexture(8,8))
SetScale GraphicsWidth()/512.0, GraphicsHeight()/512.0
SetColor 255,255,255
DrawImage image, 0,0
SetColor 200,255,255
DrawImage image, GraphicsWidth()/2,0
SetColor 200,255,255
DrawImage image, 0,GraphicsHeight()/2
SetColor 255,255,255
DrawImage image, GraphicsWidth()/2,GraphicsHeight()/2
Else
Local image:TImage = LoadImage(TextureGenerator.cellTexture(64,256,256))
SetScale GraphicsWidth()/256.0, GraphicsHeight()/256.0
SetColor 255,255,255
DrawImage image, 0,0
End If

If KeyHit(KEY_ENTER) Then displayTiled = Not displayTiled ' Press Enter to toggle texture
While KeyDown(KEY_SPACE) ' hold down space to pause
Delay(1)
Wend

Flip

Wend

End

' ---------------------------------------------------------------------------------------------

Type Point
Field x:Float
Field y:Float
Field neighbours:Point[9]

Function clone:Point(from:Point, offsetX:Float=0.0, offsetY:Float=0.0)
Local pt:Point = New Point
pt.x = from.x + offsetX
pt.y = from.y + offsetY
Return pt
End Function

End Type


Type TextureGenerator

' speed optimized - points are constrained to grid squares
' tileable
Function cellTileTexture:TPixmap(gridWidth:Int=8, gridHeight:Int=8, width:Int=256, height:Int=256)

Local grid:Point[gridWidth,gridHeight]
Local gridCellWidth:Int = width/gridWidth
Local gridCellHeight:Int = height/gridHeight

For Local x:Int = 0 To gridWidth-1
For Local y:Int = 0 To gridHeight-1
grid[x,y] = New Point
grid[x,y].x = Rand(0,gridCellWidth)
grid[x,y].y = Rand(0,gridCellHeight)
Next
Next

' pre-generate neighbour points including screen wrap around
For Local x:Int = 0 To gridWidth-1
For Local y:Int = 0 To gridHeight-1
Local x0:Int = (x+(gridWidth-1)) Mod gridWidth
Local x1:Int = (x+1) Mod gridWidth
Local y0:Int = (y+(gridHeight-1)) Mod gridHeight
Local y1:Int = (y+1) Mod gridHeight
grid[x,y].neighbours[0] = Point.clone(grid[x0,y0], -gridCellWidth,-gridCellHeight)
grid[x,y].neighbours[1] = Point.clone(grid[x,y0], 0,-gridCellHeight)
grid[x,y].neighbours[2] = Point.clone(grid[x1,y0], gridCellWidth,-gridCellHeight)
grid[x,y].neighbours[3] = Point.clone(grid[x0,y], -gridCellWidth,0)
grid[x,y].neighbours[4] = Point.clone(grid[x,y], 0,0)
grid[x,y].neighbours[5] = Point.clone(grid[x1,y], gridCellWidth,0)
grid[x,y].neighbours[6] = Point.clone(grid[x0,y1], -gridCellWidth,gridCellHeight)
grid[x,y].neighbours[7] = Point.clone(grid[x,y1], 0,gridCellHeight)
grid[x,y].neighbours[8] = Point.clone(grid[x1,y1], gridCellWidth,gridCellHeight)
Next
Next

Local distances:Float[width, height]
Local furthest:Float = 0.0

' For every pixel, find the nearest of the random points and use the distance as colour
For Local x:Int = 0 To width-1
For Local y:Int = 0 To height-1
Local closest:Float = 255.0
Local gridX:Int = x/gridCellWidth
Local gridY:Int = y/gridCellHeight
Local gridPoint:Point = grid[gridX,gridY]
Local xx:Int = x - (gridX*gridCellWidth) ' convert pixel to grid coords
Local yy:Int = y - (gridY*gridCellHeight)
For Local pt:Point = EachIn gridPoint.neighbours
Local distance:Float = Sqr(((pt.x-xx) * (pt.x-xx)) + ((pt.y-yy) * (pt.y-yy)))
If distance < closest Then closest = distance
Next
distances[x,y] = closest ' distance from closest point
If closest > furthest Then furthest = closest
Next
Next

Local pix:TPixmap = CreatePixmap (width, height, PF_RGB888)
Local scale:Float = 255.0 / furthest

' Write colour value for each pixel into the pixmap...
For Local x:Int = 0 To width-1
For Local y:Int = 0 To height-1
Local color:Int = distances[x, y]*scale
color = ((color Shl 16) + (color Shl 8) + color)
WritePixel pix, x, y, color
Next
Next

Return pix

End Function

Function cellTexture:TPixmap(cells:Int=40, width:Int=256, height:Int=256)

' create a set of random points
Local pointlist:TList = New TList
For Local r:Int = 0 To cells - 1
Local pt:Point = New Point
pt.x = Rand(0, width-1)
pt.y = Rand(0, height-1)
pointlist.addLast(pt)
Next

Local distances:Float[width, height]
Local furthest:Float = 0.0
For Local x:Int = 0 To width-1
For Local y:Int = 0 To height-1
Local closest:Float = 255.0

' For every pixel, find the nearest of the random points...
For Local pt:Point = EachIn pointlist
Local distance:Float = Sqr(((pt.x-x) * (pt.x-x)) + ((pt.y-y) * (pt.y-y)))
If distance < closest Then closest = distance
Next

distances[x, y] = closest ' distance from closest point
If closest > furthest Then furthest = closest
Next
Next

Local scale:Float = 255.0 / furthest
Local pix:TPixmap = CreatePixmap (width, height, PF_RGB888)

' Write colour value for each pixel into the pixmap...
For Local x:Int = 0 To width-1
For Local y:Int = 0 To height-1
Local color:Int = distances[x, y]*scale
color = ((color Shl 16) + (color Shl 8) + color)
WritePixel pix, x, y, color
Next
Next

Return pix

End Function

End Type





BlitzSupport(Posted 1+ years ago)

 Only just noticed this -- nice update, tesuji! [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal