Mini Kabibi Habibi
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Here are a few parameters that you can change to modify the behavior of the patterm
// Feel free to modify the values, don't change the variable names
modelParameters = {
// Density of the covered pattern
// For example,density of 1 places patters such that if they were aligned one next to another
// they would cover all pixels. Keep in mind that since the patterns overlap, you will see gaps.
density : 2, // use a value between 0.1 to 10. The default is 2.
// Maximum distance from a path
// If a path is selected the patterns are placed randomly around it, with a give maximum
// distance of the pattern ceter from the parth. The default is 20 pixels.
maxDistanceFromPath : 20, // in pixels
// Variation of color of the pattern.
// For example, value of 0.2 means that each of the red, green, and blue color components
// will be multiplied by a DIFFERENT random value from interval 0.8 and 1.2.
// Set to 0 if you do not want to modify the pattern color.
colorRandomness : 0.05, // use a value between 0 and 1. The default is 0.05.
// Variation of pattern brightness.
// For example, value of 0.6 means that each of the red, green, and blue color components
// will be multiplied by THE SAME random value from interval 0.4 and 1..6
// Set to 0 if you do not want to modify the pattern brightness.
brightnessRandomness : 0.1, // use a value between 0 and 1. The default is 0.1.
// You include random scaling of the patter
// If you don't want any variation, set both to 1
patternScaleFrom : 0.5, // use a values between 0.1 and 3 . The default is 0.5.
patternScaleTo : 1, // use a values between 0.1 and 3 , larger or equal to patternScaleFrom. The default is 1.
// Shoud we apply random rotation?
applyRotation : true // the default is true - we are doing rotations
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// You can modify the code below but keep in mind that as with any scripting
// you can break things. Keep a backup copy.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Get pattern
var pattern = RenderAPI.getParameter(kpsPattern)
var inputPaths = RenderAPI.getParameter (kpsSelectedPaths)
// For the script to work with a menu with preview, you need to define a run method with the following three parameters:
// 1. api - render api to be used. Do not use RenderAPI directly, since preview uses a different renderer
// 2. parameter - contains model parameters. Do not refer directly to modelParameters inside the run method or methods called from it.
// 3. scale - preview can be scaled up or down depending on the size of the input pattern. Accomodate scale inside the run method.
function run (api, parameters, scale)
{
// get the size of the output area
var outputSize = api.getParameter(kpsSize)
var outputOrigin = api.getParameter(kpsOrigin)
var patternSize = pattern.getParameter(kpsSize)
// scale up if the patternsize is 1 to avoid long loop
if (patternSize.x == 1 && patternSize.y == 1)
{
if (scale == 1)
scale = 20
patternSize *= scale
parameters.applyRotation = false // 1x1 patterns that are scaled up do not rotate gracefully
}
//api.translater(bbox.min[0], bbox.min[1])
// possibly add spacing
patternSize.x += 0
patternSize.y += 0
// place elements at random locations and size
if (parameters == previewParameters)
Engine.rand(1) // sets a fixed seed for preview
else
Engine.rand(Math.random()*214013) // random seed for a regular run
var sizes = new Array()
sizes.push (5)
sizes.push (2)
//sizes.push (1)
//sizes.push (0.5)
if (inputPaths.length > 0)
{
// adjust preview size
var maxPatternSize = patternSize.x // x only
if (parameters == previewParameters)
{
// set scale so that we show about 10-15 patterns
if (maxPatternSize < previewSize / 15)
scale = previewSize / (15 * maxPatternSize)
else if (maxPatternSize > previewSize / 10)
scale = previewSize / (10 * maxPatternSize)
if (parameters.maxDistanceFromPath * scale > previewSize / 4)
scale = previewSize / (4 * parameters.maxDistanceFromPath)
}
//alert ("scale = " + scale)
var paths = inputPaths
if (parameters == previewParameters)
{
paths = new Array(0)
paths.push (new DecoGeometry)
//paths[0].addLineStrip(new Vector3(0,0,0) + outputOrigin, new Vector3(255, 255, 0) + outputOrigin)
paths[0].addBezier (new Vector3(10, (previewSize-10), 0) + outputOrigin,
new Vector3(10, 115,0 ) + outputOrigin,
new Vector3( (previewSize-10), 140, 0) + outputOrigin,
new Vector3( (previewSize-10), 10, 0) + outputOrigin)
}
for (var p = 0; p < paths.length; p++)
{
var geometry = paths[p]
var length = geometry.getValue(kGetGeometryLength)
// determine the number approximately based on size of the element and filled area
var num = length * parameters.maxDistanceFromPath * 2 / (patternSize.x * patternSize.y * scale * scale) * parameters.density
if (num < 1)
num = 1
for (var i = 0; i < num; i++)
{
api.pushMatrix()
var r = Engine.rand()
var w = parameters.maxDistanceFromPath * Math.pow(r, 0.5);
var spanAlong = length
var l = spanAlong * Engine.rand();
var pt = geometry.getValue(kGetPointAlongGeometry, l)
var normal = geometry.getValue(kGetNormalAlongGeometry, l)
normal.normalize()
if (Engine.rand() > 0.5)
w = -w;
// place an element randomly along a circle of radius w
var alpha = Engine.rand() * 2 * Math.PI
var dx = Math.sin(alpha)
var dy = Math.cos(alpha)
pt.x += dx * w
pt.y += dy * w
api.translate(pt - outputOrigin)
var localScale = scale * (parameters.patternScaleFrom + (parameters.patternScaleTo - parameters.patternScaleFrom) * (1 - (Math.abs(w) / parameters.maxDistanceFromPath)) )
api.scale(localScale, localScale)
if (parameters.applyRotation)
{
var rotate = 360/30 * Math.floor(Engine.rand() * 30) // 30 distinct rotations
api.rotate(rotate)
}
//var seed = Math.floor(l *17 + p * 2531011) % 0x7fffffff //7327)
var rc = parameters.colorRandomness // color randomness
var br = 1 - parameters.brightnessRandomness + Engine.rand() * parameters.brightnessRandomness*2 // brightness
api.Color (kFillColor, br *(1 - rc + Engine.rand()*rc*2), br*(1 - rc + Engine.rand()*rc*2), br*(1 - rc + Engine.rand()*rc*2))
pattern.render(api)
api.popMatrix()
}
}
return // we are done
}
// to finetune the progress bar, specify how many pixels are covered by patterns
api.setParameter(kpsPixelCoverage, parameters.density * 0.9 *
(parameters.patternScaleTo * parameters.patternScaleTo - parameters.patternScaleFrom * parameters.patternScaleFrom) / 3)
// determine the number approximately based on size of the element and filled area
var num = ((outputSize.x + patternSize.x) * (outputSize.y + patternSize.y)) / (patternSize.x * patternSize.y * scale *scale) * parameters.density
if (num < 1)
num = 1
for (var n = 0; n < num; n++)
{
api.pushMatrix()
var localScale = scale * (parameters.patternScaleFrom + (parameters.patternScaleTo - parameters.patternScaleFrom) * Engine.rand() )
var spanx = outputSize.x + patternSize.x * localScale
var spany = outputSize.y + patternSize.y * localScale
var x = -patternSize.x * localScale * 0.5 + spanx * Engine.rand()
var y = -patternSize.y * localScale * 0.5 + spany * Engine.rand()
api.translate(x, y)
api.scale(localScale, localScale)
if (parameters.applyRotation)
{
var rotate = 360/30 * Math.floor(Engine.rand() * 30) // 30 distinct rotations
api.rotate(rotate)
}
var rc = parameters.colorRandomness // color randomness
var br = 1 - parameters.brightnessRandomness + Engine.rand() * parameters.brightnessRandomness*2 // brightness
api.Color (kFillColor, br *(1 - rc + Engine.rand()*rc*2), br*(1 - rc + Engine.rand()*rc*2), br*(1 - rc + Engine.rand()*rc*2))
pattern.render(api)
api.popMatrix()
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Menu start
// If you want to create a menu in which you change some of the script parameters, include the following code:
// For shipped scripts we can include localized strings, prefixed with $$$/ - call method localize(string) on the prefixed string
// For your own strings, you can query app.locale and select several language versions (for example, your native language and english). Try alert ("Language is: " + app.locale)
var decoMenu = { // an object that defines the menu
menuTitle : localize("$$$/DecoScripts/RandomFill/RandomFill=Random Fill"),
menuBackground : [0.93, 0.93, 0.93, 1],
previewBackground : [1, 1, 1, 1],
panels : [
{ panelName : "",
leftColumnWidth : 180,
unitsWidth : 65,
panelMenu : [
{ itemName : localize("$$$/DecoScripts/RandomFill/Density=Density:"),
itemUnit : localize("$$$/DecoScripts/Units/pixels=pixels"),
itemType : 'slider', itemValue : modelParameters.density, itemMin : 0.1, itemMax : 10, itemStep : 0.1, varName : 'density' },
{ itemName : localize("$$$/DecoScripts/RandomFill/PatternScaleFrom=Minimum scale factor:"),
itemUnit : '',
itemType : 'slider', itemValue : modelParameters.patternScaleFrom, itemMin : 0.1, itemMax : 3, itemStep : 0.01, itemLEQitem : 2, varName : 'patternScaleFrom' },
// you can link two sliders together by using itemLEQitem : item_index (less or equal to value in item item_index)
// and itemGEQitem: item_index (). This can be used when teh two slides control min and max range for some random parameter.
{ itemName : localize("$$$/DecoScripts/RandomFill/PatternScaleTo=Maximum scale factor:"),
itemUnit : '',
itemType : 'slider', itemValue : modelParameters.patternScaleTo, itemMin : 0.1, itemMax : 3, itemStep : 0.01, itemGEQitem : 1, varName : 'patternScaleTo' },
{ itemName : localize("$$$/DecoScripts/RandomFill/MaxDistanceToPath=Max distance from path:"),
itemUnit : localize("$$$/DecoScripts/Units/pixels=pixels"),
itemType : 'slider', itemValue : modelParameters.maxDistanceFromPath, itemMin : 0, itemMax : 250, itemStep : 1, enabled: inputPaths.length > 0, varName : 'maxDistanceFromPath' },
{ itemName : localize("$$$/DecoScripts/RandomFill/RotatePattern=Rotate pattern:"),
itemUnit : '', itemType : 'checkbox', itemValue : modelParameters.applyRotation, itemMin : 0, itemMax : 0, varName : 'applyRotation' },
{ itemName : localize("$$$/DecoScripts/ColorRandomness=Color randomness:"),
itemUnit : "", itemType : 'slider', itemValue : modelParameters.colorRandomness, itemMin : 0, itemMax : 1, itemStep : 0.01, varName : 'colorRandomness' },
{ itemName : localize("$$$/DecoScripts/BrightnessRandomness=Brightness randomness:"),
itemUnit : "", itemType : 'slider', itemValue : modelParameters.brightnessRandomness, itemMin : 0, itemMax : 1, itemStep : 0.01, varName : 'brightnessRandomness' },
] }
] // end of panels
}; // end of menu
// If livePreview is set to 1, the preview image is updated live. Note that due to limitations of scripted menus the update is slow and the flickering may be disturbing.
livePreview = 0 // recommended value is 0
// Call Photoshop Script that creates the menu
Engine.evalFile ("_Deco Menu.jsx")
// Menu finished
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (typeof skipRun == 'undefined' || !skipRun) // run unles we exited the preview window without pressing a button
run(RenderAPI, modelParameters, 1)