' ---------------------------------------------------
' UVDup v.1 (25.09.01)          (C) Odyseja|DDD 2001
' by Bartek Dabkowski          http://ddd.odyseja.pl
' bartekd@odyseja.pl              kontakt@odyseja.pl
' ---------------------------------------------------
' 
' Contains:
'   UVDup          - Creates NxN grid of instanced
'                    objects, surface-constraining
'                    them to a NURBS patch
'
'   UVDup_Jitter   - Randomizes selected
'                    surface-constrained objects'
'                    U and V position parameters
'                    by a set amount
'
' language:
' VBScript
'
' ---------------------------------------------------
'
'   UVDup procedure:
'
' 1. (Branch) select an object to be duplicated
' 2. CTRL-select target NURBS surface
' 3. Run the script
' 4. Enter how many instances should be created
'    along U and V directions.
'    The resulting object count would be
'    Ucount * Vcount, so entering 20 and 20
'    will produce 400 instances
'
' ---------------------------------------------------
'
'   UVDup_Jitter procedure:
'
' 1. Multi-select surface-constrained objects
' 2. Run the script
' 3. Enter how much the object's positions should
'    be randomized. The value is in parametric
'    space, so entering 1 would offset every object
'    across the entire surface in the worst case.
'
' ---------------------------------------------------
    
Option Explicit

'un-comment one of the following:

'UVDup
'UVDup_Jitter

sub UVDup_Jitter
  dim root, element           ' object variables
  dim constraints, cns
  dim r, xu, xv, ru, rv       ' data variables
  dim caption			' caption for inputbox
  dim cnt

  if selection.count = 0 then
    logmessage "Select surface-constrained objects first!", 2
    exit sub
  end if
  
  caption = "UVDup_Jitter"
  
  ru = 0.05
  rv = 0.05


  ru = CDbl(inputbox("Randomize by (U)", caption, ru))
  rv = CDbl(inputbox("Randomize by (V)", caption, rv))
  
  logmessage "Processing selection ("& selection.count &" elements):"
  cnt = 0
  for each element in selection
    set constraints = element.Kinematics.Constraints
    for each cns in constraints
      if cns.type = "surfcns" then
        xu = cns.parameters("posu").Value
        xv = cns.parameters("posv").Value
        r = (2*rnd())-1
        xu = xu + r * ru
        r = (2*rnd())-1
        xv = xv + r * rv
        if xu < 0 then xu = 0
        if xu > 1 then xu = 1
        if xv < 0 then xv = 0
        if xv > 1 then xv = 1
        cns.parameters("posu").Value = xu
        cns.parameters("posv").Value = xv
      end if
    next
    cnt = cnt + 1
    if cnt MOD 100 = 0 then
      logmessage Int((cnt / selection.count)*100) &" percent processed"
    end if
  next
end sub

sub UVDup
  if NOT selection.count = 2 then
  	logmessage "First select the object to duplicate, then CTRL-Select the target surface...", 2
  	exit sub
  end if
  
  if selection(1).type = "surfmsh" then
  	doit selection(0), selection(1)
  else
  	logmessage "The target must be a NURBS surface!", 2
  	exit sub
  end if
end sub

sub doit(source, target)
  dim caption
  dim nu, nv, xu, xv
  dim count
  dim root, dup_root, dups, element, cns
  dim cnt
  
  caption = "UV_Dup"  
  nu = 10
  nv = 10
  
  nu = Int(inputbox( "How many duplicates in U?", caption, nu )) - 1 
  nv = Int(inputbox( "And V?", caption, nv )) - 1

  count = (nu+1) * (nv+1)

  set root = Application.ActiveProject.ActiveScene.Root
  set dup_root = root.AddNull

  dup_root.Name = "dup_root"
  
  logmessage "Creating instances"
  set dups = Instance(source, count, 1)

  logmessage "Parenting"
  ParentObj dup_root, dups  
  
  xu = 0
  xv = 0
  
  logmessage "Processing "& dups.count &" elements:"
  cnt = 0
  for each element in dups
  	set cns = element.Kinematics.AddConstraint("Surface", target)
  	if xu > nu then
  		xu = 0
  		xv = xv + 1
  	end if
  	cns.Parameters("upvct_active").Value = True
  	cns.Parameters("tangent").Value = True
	cns.Parameters("posu").Value = (xu / nu)
	cns.Parameters("posv").Value = (xv / nv)
  	xu = xu + 1
  	cnt = cnt + 1
  	if cnt MOD 100 = 0 then
  	  logmessage Int((cnt / dups.count)*100) &" percent processed"
  	end if
  next
  logmessage "done!"
end sub