Code archives/Graphics/Seamless Tiles
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| Create a seamless tile pixmap from a source pixmap | |||||
Rem
Seamless Texture Tiling Example
ORIGINAL AUTHOR (Article and C Code):
Paul Bourke
January 2000
http://local.wasp.uwa.edu.au/~pbourke/texture/tiling/
REQUIREMENTS:
BlitzMax 1.22
Windows XP (Linux and MacOS untested)
PURPOSE:
Create a seamless 'tile' pixmap from a source pixmap
EndRem
SuperStrict
AppTitle = "Seamless Texture Tiling Example"
Graphics 1024, 768
SetBlend SOLIDBLEND
Local tex:TPixmap = LoadPixmap("tex.png") '<--- Provide your own texture for this example. <---
If (tex.format <> PF_RGBA8888) Then tex = ConvertPixmap(tex, PF_RGBA8888)
Local tile:TPixmap = createSeamlessTile(tex, MASK_RADIAL)
Local img:TImage = LoadImage(tile)
SetClsColor 255, 255, 255
While Not KeyHit(KEY_ESCAPE)
Cls
SetViewport 0, 0, GraphicsWidth(), GraphicsHeight()
DrawText "Source:", 2, 2
DrawPixmap tex, 2, 22
DrawText "Result:", 2, tex.height + 42
DrawPixmap tile, 2, tex.height + 62
DrawText "Tiled Result:", tex.width + 20, 2
SetViewport tex.width + 20, 22, GraphicsWidth() - tex.width - 22, GraphicsHeight() - 26
TileImage img
Flip 1
Wend
End
'*************** SEAMLESS TILE FUNCTION AND RELATED CONSTANTS *************************************
Const MASK_LINEAR:Int = 0
Const MASK_RADIAL:Int = 1
Function createSeamlessTile:TPixmap(src:TPixmap, masktype:Int = MASK_LINEAR)
'src: Source pixmap texture. Format should be PF_RGBA8888.
'masktype: Mask type. MASK_LINEAR or MASK_RADIAL. Some textures tile better using a different mask.
'Returns a new 'tileable' pixmap.
Local outp:TPixmap = CreatePixmap(src.width, src.height, src.format)
Local diag:TPixmap = CreatePixmap(src.width, src.height, src.format)
Local temp:TPixmap = PixmapWindow(src, 0, 0, src.width / 2, src.height / 2)
For Local x:Int = 0 To temp.width - 1
For Local z:Int = 0 To temp.height - 1
WritePixel diag, (src.width / 2) + x, (src.height / 2) + z, ReadPixel(temp, x, z)
Next
Next
temp = PixmapWindow(src, src.width / 2, src.height / 2, src.width / 2, src.height / 2)
For Local x:Int = 0 To temp.width - 1
For Local z:Int = 0 To temp.height - 1
WritePixel diag, x, z, ReadPixel(temp, x, z)
Next
Next
temp = PixmapWindow(src, src.width / 2, 0, src.width / 2, src.height / 2)
For Local x:Int = 0 To temp.width - 1
For Local z:Int = 0 To temp.height - 1
WritePixel diag, x, (src.height / 2) + z, ReadPixel(temp, x, z)
Next
Next
temp = PixmapWindow(src, 0, src.height / 2, src.width / 2, src.height / 2)
For Local x:Int = 0 To temp.width - 1
For Local z:Int = 0 To temp.height - 1
WritePixel diag, (src.width / 2) + x, z, ReadPixel(temp, x, z)
Next
Next
Local masksize:Int
If (src.width > src.height) Then masksize = src.width Else masksize = src.height
Local mask:TPixmap = CreatePixmap(masksize, masksize, PF_RGB888)
For Local x:Int = 0 To masksize / 2
For Local z:Int = 0 To masksize / 2
Local d:Float = 0.0
If masktype = MASK_RADIAL
d = Sqr((x - (masksize / 2)) * (x - (masksize / 2)) + (z - (masksize / 2)) * (z - (masksize / 2))) / (masksize / 2)
Else
If masktype = MASK_LINEAR
d = Max(Float((masksize / 2) - x), Float((masksize / 2) - z)) / Float(masksize / 2)
EndIf
EndIf
d = 255 - (255 * d)
If d < 1 Then d = 1
If d > 255 Then d = 255
WritePixel mask, x, z, Int(Byte(d) Shl 16 | Byte(d) Shl 8 | Byte(d))
WritePixel mask, x, (masksize - 1 - z), Int(Byte(d) Shl 16 | Byte(d) Shl 8 | Byte(d))
WritePixel mask, (masksize - 1 - x), z, Int(Byte(d) Shl 16 | Byte(d) Shl 8 | Byte(d))
WritePixel mask, (masksize - 1 - x), (masksize - 1 - z), Int(Byte(d) Shl 16 | Byte(d) Shl 8 | Byte(d))
Next
Next
mask = ResizePixmap(mask, src.width, src.height)
For Local z:Int = 0 To src.height - 1
For Local x:Int = 0 To src.width - 1
Local a1:Float = Float(Byte(ReadPixel(mask, x, z) Shr 16))
Local a2:Float = Float(Byte(ReadPixel(mask, ((x + src.width / 2) Mod src.width), ((z + src.height / 2) Mod src.height)) Shr 16))
Local px1:Int = ReadPixel(src, x, z)
Local px1a:Byte = px1 Shr 24
Local px1b:Byte = px1 Shr 16
Local px1g:Byte = px1 Shr 8
Local px1r:Byte = px1
Local px2:Int = ReadPixel(diag, x, z)
Local px2a:Byte = px2 Shr 24
Local px2b:Byte = px2 Shr 16
Local px2g:Byte = px2 Shr 8
Local px2r:Byte = px2
Local pxRa:Byte = px1a
Local pxRb:Byte = (a1 * (px1b / (a1 + a2))) + (a2 * (px2b / (a1 + a2)))
Local pxRg:Byte = (a1 * (px1g / (a1 + a2))) + (a2 * (px2g / (a1 + a2)))
Local pxRr:Byte = (a1 * (px1r / (a1 + a2))) + (a2 * (px2r / (a1 + a2)))
Local pxR:Int = Int(pxRa Shl 24 | pxRb Shl 16 | pxRg Shl 8 | pxRr)
WritePixel outp, x, z, pxR
Next
Next
Return outp
EndFunction |
Comments
| ||
| Thats damned handy! I did notice on a few test runs that a horizontal black line appears on some images that I used. Just picked some random grass images from here: http://www.injuryupdate.com.au/issues/grass_types.php but other than that its a killer bit of code, thanks! |
| ||
| EDIT: Removed dead links. |
| ||
| Tested With about half a dozen of my own images of varying sizes and sources and had no problems. Good work, and a useful utility. |
| ||
| As requested in another thread, here's the source for Ultra Simple Seamless Tiler V1.00. You will need to change the framework and possibly tweak the code if compiling for other platforms. The MaxGUI module is required. EDIT: Added code line "Import BRL.EventQueue". |
| ||
| Here's the latest version of Ultra Simple Seamless Tiler 1.01, to be compiled against maxgui.mod revision 29: |
Code Archives Forum