A Procedural Graphics System
Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller
A Procedural Graphics System
Hi,
I am attaching a Procedural Graphics System stack and a user guide. In the user guide I talk a bit about changing the resolution of the image, but I have it hard wired for now at 800 x 800 pixels. The user guide should open directly in your browser; I've tested it with Safari, FireFox and Chrome successfully.
This has some similarities to the Minimum Drawing Library ( available here in the forums ) but I am interested in creating procedural art so I wanted a "playground" I could easily expand (next version is in work).
- Mike
[ 10/1/2025. Removed files and uploaded new versions below]
			
			
													I am attaching a Procedural Graphics System stack and a user guide. In the user guide I talk a bit about changing the resolution of the image, but I have it hard wired for now at 800 x 800 pixels. The user guide should open directly in your browser; I've tested it with Safari, FireFox and Chrome successfully.
This has some similarities to the Minimum Drawing Library ( available here in the forums ) but I am interested in creating procedural art so I wanted a "playground" I could easily expand (next version is in work).
- Mike
[ 10/1/2025. Removed files and uploaded new versions below]
					Last edited by Hutchboy on Thu Oct 02, 2025 1:14 am, edited 1 time in total.
									
			
									
						Re: A Procedural Graphics System
Hi,
The attached version 1.2.0 of the Procedural Graphics System adds some noise generators. These are fairly slow generators in an 800 x 800 pixel image, but not too bad. There is a small status update msg in the lower left corner that will show you progress for these generators so you know something is happening. I am running out of card real estate for controls for the next phase development so I will probably expand the stack width size to accommodate. I will hold off a bit before updating the user guide, probably for the next phase. Look up any terms that may seem unfamiliar for now (lacunarity!?) .
Note: for each generator type I changed the code to just disable/dim the unnecessary controls for that type. The first version hid them but that was too jarring.
- Mike
[10/1/25. Removed files and uploaded new revisions below]
			
			
													The attached version 1.2.0 of the Procedural Graphics System adds some noise generators. These are fairly slow generators in an 800 x 800 pixel image, but not too bad. There is a small status update msg in the lower left corner that will show you progress for these generators so you know something is happening. I am running out of card real estate for controls for the next phase development so I will probably expand the stack width size to accommodate. I will hold off a bit before updating the user guide, probably for the next phase. Look up any terms that may seem unfamiliar for now (lacunarity!?) .
Note: for each generator type I changed the code to just disable/dim the unnecessary controls for that type. The first version hid them but that was too jarring.
- Mike
[10/1/25. Removed files and uploaded new revisions below]
					Last edited by Hutchboy on Thu Oct 02, 2025 1:15 am, edited 1 time in total.
									
			
									
						Re: A Procedural Graphics System
@Hutchboy (Mike)
This is a fascinating project.
I am curious as to the meaning of Scale, Octaves, Persistence and Lacunarity at the top of the window.
I am enjoying your efforts.
Bob
			
			
									
									
						This is a fascinating project.
I am curious as to the meaning of Scale, Octaves, Persistence and Lacunarity at the top of the window.
I am enjoying your efforts.
Bob
Re: A Procedural Graphics System
Mike,
Firstly thank you for this elaborate and well written stack.
I took the liberty to change some code in your version 1.2.0 to improve speed a bit. It makes linear gradients about 10%+ faster.
1. I changed handler applyInterpolation to:
Code: Select all
function applyInterpolation @pRatio, @pMethodIn handler createLinearGradient I call it this way since tRatio is now changed in handler applyInterpolation
Code: Select all
get applyInterpolation(tRatio, pInterpolation) # changedCode: Select all
-- APPLY INTERPOLATION TO RATIO
function applyInterpolation @pRatio, @pMethod
   local tResult
   
   switch pMethod
      case "linear"
         put pRatio into pRatio
         break
      case "easein"
         -- Quadratic ease-in: ratio^2
         put pRatio * pRatio into pRatio
         break
      case "easeout"
         -- Quadratic ease-out: 1 - (1-ratio)^2
         put 1 - ((1 - pRatio) * (1 - pRatio)) into pRatio
         break
      default
         put pRatio into tResult
   end switch
   
   --return pRatio
end applyInterpolationCode: Select all
-- CREATE LINEAR GRADIENT (ORIGINAL - NOW WITH INTERPOLATION)
on createLinearGradient pWidth, pHeight, pStartColor, pEndColor, pDirection, pInterpolation
   local tData, tX, tY, tRatio
   local tStartR, tStartG, tStartB
   local tEndR, tEndG, tEndB
   local tR, tG, tB
   local tPixelColor
   local tMaxDimension
   
   -- Parse start color
   put item 1 of pStartColor into tStartR
   put item 2 of pStartColor into tStartG
   put item 3 of pStartColor into tStartB
   
   -- Parse end color
   put item 1 of pEndColor into tEndR
   put item 2 of pEndColor into tEndG
   put item 3 of pEndColor into tEndB
   
   -- Determine maximum dimension for diagonal
   if pDirection is "diagonal" then
      put sqrt(pWidth^2 + pHeight^2) into tMaxDimension
   end if
   
   
   -- Calculate ratio based on direction
   switch pDirection
      case "horizontal"
         
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat with tX = 0 to pWidth - 1
               -- Apply interpolation
               put tX / (pWidth - 1) into tRatio
               get applyInterpolation(tRatio, pInterpolation) # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data ## changed
               
            end repeat
         end repeat
         break
      case "vertical"
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat with tX = 0 to pWidth - 1
               put tY / (pHeight - 1) into tRatio
               -- Apply interpolation
               get applyInterpolation(tRatio, pInterpolation)  # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data # changed
               
            end repeat
         end repeat
         break
      case "diagonal"
         
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat with tX = 0 to pWidth - 1
               put sqrt(tX^2 + tY^2) / tMaxDimension into tRatio
               if tRatio > 1 then put 1 into tRatio
               -- Apply interpolation
               get applyInterpolation(tRatio, pInterpolation) --into tRatio
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data # changed
               
            end repeat
         end repeat
         
         break
      default
         put tX / (pWidth - 1) into tRatio
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat with tX = 0 to pWidth - 1
               -- Apply interpolation
               get applyInterpolation(tRatio, pInterpolation)  # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data # changed
               
            end repeat
         end repeat
         
   end switch
   
   -- Resize and apply image
   
   lock screen -- saves about 10 to 20 milliseconds # changed
   
   set the width of img "img_display" to pWidth
   set the height of img "img_display" to pHeight
   set the imageData of img "img_display" to tData
   
   -- Center image in display area
   centerImageInDisplay
   
   -- Store for export
   put tData into gLastGeneratedImage
end createLinearGradientAgain thanks for this nice example.
Kind regards
Bernd
Re: A Procedural Graphics System
Hi,
Attached is version 1.4 of my Procedural Graphics System. This version adds new features, enlarges the stack size to 1400 x 900, and removes the restriction on changing the resolution to ranges from a minimum of 200 pixels to a max of 800. I've added an "Reset" button that will return everything to the defaults and clear the image.
I have also updated the user guide to bring it up to date with this release.
[bn...Thanks, I will review and incorporate your speed up recommendations in the next phase]
[ Nov. 2 Update - replaced version 1.4 with version 1.5.1 in my next post; mainly to incorporate Bernd's speed up recommendation]
-Mike
			
			
													Attached is version 1.4 of my Procedural Graphics System. This version adds new features, enlarges the stack size to 1400 x 900, and removes the restriction on changing the resolution to ranges from a minimum of 200 pixels to a max of 800. I've added an "Reset" button that will return everything to the defaults and clear the image.
I have also updated the user guide to bring it up to date with this release.
[bn...Thanks, I will review and incorporate your speed up recommendations in the next phase]
[ Nov. 2 Update - replaced version 1.4 with version 1.5.1 in my next post; mainly to incorporate Bernd's speed up recommendation]
-Mike
					Last edited by Hutchboy on Sun Nov 02, 2025 7:36 pm, edited 1 time in total.
									
			
									
						Re: A Procedural Graphics System
Hi Mike,
The 1.4 version is very impressive, thank you very much.
I worked a bit on the code for "Linear Gradients" and made a couple of additional changes which superseeds the code suggestions I made above.
It breaks a bit your very structured coding style but on the other hand it increases speed quite considerably. Roughly by half for the diagonal options and to less than 10 percent for horizontal and vertical. As far as speed in image manipulation I am a bit obsessed...
You should be able to just replace the current "createLinearGradient" with the version below. If you put this accelerated version above the original version it will use the first handler it encounters without need to block the current handler. The handler is not cleaned up but I do not know what of it you want to use.
Kind regards
Bernd
Code: Select all
-- CREATE LINEAR GRADIENT (ORIGINAL - NOW WITH INTERPOLATION)
on createLinearGradient pWidth, pHeight, pStartColor, pEndColor, pDirection, pInterpolation
   local tData, tX, tY, tRatio
   local tStartR, tStartG, tStartB
   local tEndR, tEndG, tEndB
   local tR, tG, tB, tRedSeed, tGreenSeed, tBlueSeed
   local tPixelColor, tPixelNeeded, tPixelOneRow, tPixelDoubling
   local tDataOneRow
   local tMaxDimension
   
   -- Parse start color
   put item 1 of pStartColor into tStartR
   put item 2 of pStartColor into tStartG
   put item 3 of pStartColor into tStartB
   
   -- Parse end color
   put item 1 of pEndColor into tEndR
   put item 2 of pEndColor into tEndG
   put item 3 of pEndColor into tEndB
   
   -- Determine maximum dimension for diagonal
   if pDirection is "diagonal" then
      put sqrt(pWidth^2 + pHeight^2) into tMaxDimension
   end if
   
   
   -- Calculate ratio based on direction
   switch pDirection
      case "horizontal"
         
         -- Generate pixel data
         repeat 1 -- with tY = 0 to pHeight - 1
            --repeat with tX = 0 to pWidth - 1
            repeat with tX = 0 to pWidth - 1
               -- Apply interpolation
               put tX / (pWidth - 1) into tRatio
               
               switch pInterpolation
                  case "linear"
                     break
                  case "easeout"
                     -- Quadratic ease-out: 1 - (1-ratio)^2
                     put 1 - ((1 - tRatio) * (1 - tRatio)) into tRatio
                     break
                  case "easein"
                     -- Quadratic ease-in: ratio^2
                     put tRatio * tRatio into tRatio
                     break
               end switch
               --get applyInterpolation(tRatio, pInterpolation) # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tDataOneRow -- Append to image data ## changed
               
            end repeat
            
            repeat pHeight
               put tDataOneRow after tData
            end repeat
            
         end repeat
         break
      case "vertical"
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat 1 -- with tX = 0 to 1
               put tY / (pHeight - 1) into tRatio
               -- Apply interpolation
               
               switch pInterpolation
                  case "linear"
                     break
                  case "easeout"
                     -- Quadratic ease-out: 1 - (1-ratio)^2
                     put 1 - ((1 - tRatio) * (1 - tRatio)) into tRatio
                     break
                  case "easein"
                     -- Quadratic ease-in: ratio^2
                     put tRatio * tRatio into tRatio
                     break
               end switch
               --get applyInterpolation(tRatio, pInterpolation)  # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) into  tPixelColor -- Append to image data # changed
               
               put 800 * 4 into tPixelNeeded
               
               put tPixelColor & tPixelColor into tPixelDoubling
               
               repeat 
                  put tPixelDoubling & tPixelDoubling into tPixelDoubling
                  if the length of tPixelDoubling > tPixelNeeded then
                     exit repeat
                  end if
               end repeat
               put byte 1 to tPixelNeeded of tPixelDoubling after tData
               
            end repeat
         end repeat
         break
         
         
      case "diagonal"
         
         put tEndR - tStartR  into tRedSeed
         put ((tEndG - tStartG)) into tGreenSeed
         put ((tEndB - tStartB)) into tBlueSeed
         
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            --if tY = 500 then breakpoint
            repeat with tX = 0 to pWidth - 1
               put (sqrt(tX^2 + tY^2)) / tMaxDimension into tRatio
               if tRatio > 1 then put 1 into tRatio
               
               -- Apply interpolation
               
               --                  if pInterpolation is  "linear" then
               --                     -- nada
               --                  else if pInterpolation is "easeout" then
               --                     -- Quadratic ease-out: 1 - (1-ratio)^2
               --                     put 1 - ((1 - tRatio) * (1 - tRatio)) into tRatio
               
               --                  else if pInterpolation is  "easein" then
               --                     -- Quadratic ease-in: ratio^2
               --                     put tRatio * tRatio into tRatio
               --                  end if
               
               switch pInterpolation
                  case "linear"
                     break
                  case "easeout"
                     -- Quadratic ease-out: 1 - (1-ratio)^2
                     put 1 - ((1 - tRatio) * (1 - tRatio)) into tRatio
                     break
                  case "easein"
                     -- Quadratic ease-in: ratio^2
                     put tRatio * tRatio into tRatio
                     break
               end switch
               
               --get applyInterpolation(tRatio, pInterpolation) --into tRatio
               
               
               -- Interpolate RGB values
               
               --                  put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               --                  put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               --                  put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               put round(tStartR + (tRedSeed * tRatio)) into tR
               put round(tStartG + (tGreenSeed * tRatio)) into tG
               put round(tStartB + (tBlueSeed * tRatio)) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data # changed
               
            end repeat
         end repeat
         break
      default
         put tX / (pWidth - 1) into tRatio
         -- Generate pixel data
         repeat with tY = 0 to pHeight - 1
            repeat with tX = 0 to pWidth - 1
               -- Apply interpolation
               get applyInterpolation(tRatio, pInterpolation)  # changed
               
               -- Interpolate RGB values
               put round(tStartR + (tEndR - tStartR) * tRatio) into tR
               put round(tStartG + (tEndG - tStartG) * tRatio) into tG
               put round(tStartB + (tEndB - tStartB) * tRatio) into tB
               
               -- Encode pixel in ARGB format (alpha = 0 for opaque)
               put binaryEncode("CCCC", 0, tR, tG, tB) after tData -- Append to image data # changed
               
            end repeat
         end repeat
         
   end switch
   
   -- Resize and apply image
   
   lock screen -- saves about 10 to 20 milliseconds # changed
   
   set the width of img "img_display" to pWidth
   set the height of img "img_display" to pHeight
   set the imageData of img "img_display" to tData
   
   -- Center image in display area
   centerImageInDisplay
   
   -- Store for export
   put tData into gLastGeneratedImage
end createLinearGradient
Re: A Procedural Graphics System
Mike,
In case you have used the debugger while developing your stack it might have happened that the debugger had a very long "hang".
This is a long standing bug in the treeview widget used by the debugger which is triggered by non printable characters in imageData.
There is a bug report in Quality Control Center
https://quality.livecode.com/show_bug.cgi?id=19157
I had to patch the treeview widget manually to be able to use the debugger.
If this happened to you I offer to patch your version of the treeview widget. You could send me a private message, tell me which version of LC you are currently using and an email address where to send the treeview widget.
Kind regards
Bernd
			
			
									
									
						In case you have used the debugger while developing your stack it might have happened that the debugger had a very long "hang".
This is a long standing bug in the treeview widget used by the debugger which is triggered by non printable characters in imageData.
There is a bug report in Quality Control Center
https://quality.livecode.com/show_bug.cgi?id=19157
I had to patch the treeview widget manually to be able to use the debugger.
If this happened to you I offer to patch your version of the treeview widget. You could send me a private message, tell me which version of LC you are currently using and an email address where to send the treeview widget.
Kind regards
Bernd
Re: A Procedural Graphics System
Hi,
[Nov.2 Update - See updated attachments below]
Mike
			
			
													[Nov.2 Update - See updated attachments below]
Mike
					Last edited by Hutchboy on Mon Nov 03, 2025 2:52 am, edited 1 time in total.
									
			
									Mike Roberts 
https://mygiantbrain.com
						https://mygiantbrain.com
Re: A Procedural Graphics System
Mike,
unfortunately the handler for "Linear Graphic (Angled)" is missing.
Here are my versions based on your versions for the other scripts I have been working on.
And a script to invert colors that is extremely fast, just for your interest.
Here I was inspired by your Truchet tiles:
viewtopic.php?f=9&t=39951#p235341
Kind regards
Bernd
			
							unfortunately the handler for "Linear Graphic (Angled)" is missing.
Here are my versions based on your versions for the other scripts I have been working on.
And a script to invert colors that is extremely fast, just for your interest.
Here I was inspired by your Truchet tiles:
viewtopic.php?f=9&t=39951#p235341
Kind regards
Bernd
- Attachments
 - 
			
		
		
				
- various handlers for Procedural Graphics System.livecode.zip
 - (3.91 KiB) Downloaded 3 times
 
 
Re: A Procedural Graphics System
Hi,
The Procedural Graphics System has been updated to v.1.5.2.
Mike
bn: Thanks for the Invert Colors button script and gradient updates.
			
							The Procedural Graphics System has been updated to v.1.5.2.
Mike
bn: Thanks for the Invert Colors button script and gradient updates.
- Attachments
 - 
			
		
		
				
- procedural_graphics_guide.html.zip
 - (8.14 KiB) Downloaded 3 times
 
 - 
			
		
		
				
- Procedural Graphics System v1.5.2.livecode.zip
 - (28.9 KiB) Downloaded 4 times
 
 
