// * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
// * $License$
global string $llPrimScript;
global proc string llFirst(string $list[])
{
return $list[0];
}
global proc string llGetShadingGroup(string $object)
{
string $allNodes[] = (`listHistory -f true $object` );
string $node = "";
for ($node in $allNodes)
{
if(`nodeType $node` == "shadingEngine"
{
return $node;
}
}
return "";
}
global proc llSculptExport(string $object,
string $file_name, string $file_extension, string $file_format,
int $resolution_x, int $resolution_y,
int $maximize_scale, int $fix_orientation,
int $surface_bake, int $surface_resolution_x, int $surface_resolution_y, int $surface_shadows,
int $generate_primscript)
{
// copy it, because we're going to mutilate it. MUHAHAHAAAaa...
string $object_copy = llFirst(duplicate($object));
// disentangle from groups
string $parents[] = listRelatives("-parent", $object_copy);
if (size($parents) != 0)
$object_copy = llFirst(parent("-world", $object_copy));
// scale it to unit cube
float $bounding_min[3];
float $bounding_max[3];
$bounding_min = getAttr($object_copy + ".boundingBoxMin"

;
$bounding_max = getAttr($object_copy + ".boundingBoxMax"

;
float $scale[3];
int $i;
for ($i = 0; $i < 3; $i++)
{
$scale[$i] = $bounding_max[$i] - $bounding_min[$i];
if ($scale[$i] < 0.00001)
$scale[$i] = 1;
}
float $scale_max = 0;
for ($i = 0; $i < 3; $i++)
if ($scale[$i] > $scale_max)
$scale_max = $scale[$i];
if ($maximize_scale)
{
print($object + " scale normalized - scale by " +
$scale[0] + " " + $scale[1] + " " + $scale[2] + " inside SL to get original shape\n"

;
}
else
{
for ($i = 0; $i < 3; $i++)
$scale[$i] = $scale_max;
}
scale("-relative", 1/$scale[0], 1/$scale[1], 1/$scale[2], $object_copy);
// position it in unit cube
$bounding_min = getAttr($object_copy + ".boundingBoxMin"

;
$bounding_max = getAttr($object_copy + ".boundingBoxMax"

;
float $center[3];
for ($i = 0; $i < 3; $i++)
$center[$i] = ($bounding_min[$i] + $bounding_max[$i]) / 2.0;
move("-relative", 0.5 - $center[0], 0.5 - $center[1], 0.5 - $center[2], $object_copy);
//
// nurbs surfaces can be adjusted to ensure correct orientation
//
if ($fix_orientation)
{
string $shape = llFirst(listRelatives("-shapes", $object_copy));
if ((nodeType($object_copy) == "nurbsSurface"

||
(($shape != ""

&& (nodeType($shape) == "nurbsSurface"

))
{
// try to determine the "north pole";
float $pole[] = pointOnSurface("-turnOnPercentage", 1,
"-parameterU", 0.5,
"-parameterV", 0,
$object_copy);
float $total_distance = 0;
float $v;
for ($v = 0; $v <= 1; $v += 0.1)
{
float $point[] = pointOnSurface("-turnOnPercentage", 1,
"-parameterU", $v,
"-parameterV", 0,
$object_copy);
float $distance = 0;
int $i;
for ($i = 0; $i < 3; $i++)
$distance += pow($pole[$i] - $point[$i], 2);
$distance = sqrt($distance);
$total_distance += $distance;
}
if ($total_distance > 0.1) // the points don't converge on the pole - swap
{
print("swapping UVs to orient poles for " + $object + "\n"

;
reverseSurface("-direction", 3, $object_copy);
}
// now try to ensure the normal points "out"
// note: this could easily fail - but there's no better way (i think.)
float $total_orientation = 0;
float $u;
for ($u = 0; $u <= 1; $u += 0.1)
for ($v = 0; $v <= 1; $v += 0.1)
{
float $point[] = pointOnSurface("-turnOnPercentage", 1,
"-parameterU", $u,
"-parameterV", $v,
$object_copy);
float $normal[] = pointOnSurface("-normal",
"-turnOnPercentage", 1,
"-parameterU", $u,
"-parameterV", $v,
$object_copy);
// check the orientation of the normal w/r/t the direction from center
float $center_dir[];
for ($i = 0; $i < 3; $i++)
$center_dir[$i] = $point[$i] - 0.5;
float $orientation = 0; // dot product
for ($i = 0; $i < 3; $i++)
$orientation += $center_dir[$i] * $normal[$i];
$total_orientation += $orientation;
}
if ($total_orientation < 0) // need to invert
{
print("reversing V for " + $object + "\n"

;
reverseSurface("-direction", 1, $object_copy);
}
}
else
{
warning("cannot fix orientation on non-nurbs object: " + $object);
}
}
// create temporary shading network
string $sampler_info = createNode("samplerInfo"

;
string $full_file_name = $file_name + "." + $file_extension;
print("exporting sculpt map for " + $object + " into file " + $full_file_name + "\n"

;
// bake sculpt texture
string $fileNodes[] = convertSolidTx("-fileImageName", $full_file_name,
"-fileFormat", $file_format,
"-force", 1,
"-resolutionX", $resolution_x,
"-resolutionY", $resolution_y,
$sampler_info + ".pointWorld",
$object_copy);
delete($fileNodes); // we don't want 'em. why do you make 'em?
delete($sampler_info);
delete($object_copy);
//
// bake texture also?
//
if ($surface_bake)
{
string $texture_file_name = $file_name + "-surface." + $file_extension;
string $shading_group = llGetShadingGroup($object);
print("baking texture for " + $object + " into file " + $texture_file_name + "\n"

;
// bake sculpt texture
string $fileNodes[] = convertSolidTx("-fileImageName", $texture_file_name,
"-fileFormat", $file_format,
"-force", 1,
"-resolutionX", $surface_resolution_x,
"-resolutionY", $surface_resolution_y,
"-shadows", $surface_shadows,
$shading_group,
$object);
delete($fileNodes); // still don't want 'em.
}
//
// construct primScript
//
if ($generate_primscript)
{
global string $llPrimScript;
// strip dir from filename
string $tokens[];
tokenize($file_name, "/", $tokens);
string $base_name = $tokens[size($tokens)-1];
$llPrimScript += "newPrim\n";
$llPrimScript += "prim -setObjectName " + $object + " -deleteScript\n";
$llPrimScript += "shape -setSculpt " + $base_name + " 1 -deleteScript\n";
$llPrimScript += "texture";
if ($surface_bake)
$llPrimScript += " -setTexture " + $base_name + "-surface -1";
$llPrimScript += " -deleteScript\n";
$llPrimScript += "transform -setScale " +
$scale[0] + " " + $scale[1] + " " +$scale[2] +
" -gotoRelativePos " +
$center[0]*$scale[0] + " " + $center[1]*$scale[1] + " " +$center[2]*$scale[2] +
" -deleteScript \n";
}
}
global proc int llSculptEditorCallback()
{
string $objects[] = ls("-sl"

;
if (size($objects) == 0)
{
warning("please select objects to export"

;
return 0;
}
string $filename = textFieldButtonGrp("-query", "-fileName", "llSculptEditorFilename"

;
int $resolution_x = intSliderGrp("-query", "-value", "llSculptEditorResolutionX"

;
int $resolution_y = intSliderGrp("-query", "-value", "llSculptEditorResolutionY"

;
int $fix_orientation = checkBoxGrp("-query", "-value1", "llSculptEditorFixOrientation"

;
int $maximize_scale = checkBoxGrp("-query", "-value1", "llSculptEditorMaximizeScale"

;
int $surface_bake = checkBoxGrp("-query", "-value1", "llSculptEditorSurfaceBake"

;
int $surface_resolution_x = intSliderGrp("-query", "-value", "llSculptEditorSurfaceResolutionX"

;
int $surface_resolution_y = intSliderGrp("-query", "-value", "llSculptEditorSurfaceResolutionY"

;
int $surface_shadows = checkBoxGrp("-query", "-value1", "llSculptEditorSurfaceShadows"

;
int $generate_primscript = checkBoxGrp("-query", "-value1", "llSculptEditorGeneratePrimScript"

;
// get filetype
string $file_type;
string $file_base;
string $file_extension;
string $tokens[];
tokenize($filename, ".", $tokens);
if (size($tokens) == 1) // no extension, default to bmp
{
$file_base = $filename;
$file_type = "bmp";
$file_extension = "bmp";
}
else
{
$file_extension = $tokens[size($tokens) - 1];
int $i;
for ($i = 0; $i < size($tokens) - 1; $i++)
{
$file_base += $tokens[$i];
if ($i != size($tokens) - 2)
$file_base += ".";
}
if ($file_extension == "bmp"

$file_type = "bmp";
else if (($file_extension == "jpg"

|| ($file_extension == "jpeg"

)
$file_type = "jpg";
else if (($file_extension == "tif"

|| ($file_extension == "tiff"

)
$file_type = "tif";
else if ($file_extension == "tga"

$file_type = "tga";
else
{
warning("unknown image type (" + $file_extension + "

. switching to bmp"

;
$file_type = "bmp";
$file_extension = "bmp";
}
}
global string $llPrimScript;
$llPrimScript = "";
int $multi_file = 0;
if (size($objects) > 1)
$multi_file = 1;
if ($generate_primscript)
$multi_file = 1;
string $object;
for ($object in $objects)
{
string $this_filename = $file_base;
if ($multi_file)
$this_filename += "-" + $object;
llSculptExport($object, $this_filename, $file_extension, $file_type, $resolution_x, $resolution_y,
$maximize_scale, $fix_orientation,
$surface_bake, $surface_resolution_x, $surface_resolution_y, $surface_shadows,
$generate_primscript);
}
if ($generate_primscript)
{
int $file_id=fopen($file_base + ".primscript"

;
fwrite($file_id, $llPrimScript);
fclose($file_id);
}
select($objects);
return 1;
}
global proc llSculptEditorSetFilenameCallback(string $filename, string $filetype)
{
textFieldButtonGrp("-edit", "-fileName", $filename, "llSculptEditorFilename"

;
}
global proc llSculptEditorBrowseCallback()
{
fileBrowser("llSculptEditorSetFilenameCallback", "Export", "image", 1);
}
global proc llSculptEditorSurfaceBakeCallback()
{
int $surface_bake = checkBoxGrp("-query", "-value1", "llSculptEditorSurfaceBake"

;
control("-edit", "-enable", $surface_bake, "llSculptEditorSurfaceResolutionX"

;
control("-edit", "-enable", $surface_bake, "llSculptEditorSurfaceResolutionY"

;
control("-edit", "-enable", $surface_bake, "llSculptEditorSurfaceShadows"

;
}
global proc llSculptEditor()
{
string $commandName = "llSculptExport";
string $layout = getOptionBox();
setParent $layout;
setOptionBoxCommandName($commandName);
setUITemplate -pushTemplate DefaultTemplate;
scrollLayout;
tabLayout -tabsVisible 0 -scrollable 1;
string $parent = `columnLayout -adjustableColumn 1`;
separator -height 10 -style "none";
textFieldButtonGrp
-label "Filename"
-fileName "sculpt.bmp"
-buttonLabel "Browse"
-buttonCommand "llSculptEditorBrowseCallback"
llSculptEditorFilename;
intSliderGrp
-field on
-label "X Resolution"
-minValue 1
-maxValue 512
-fieldMinValue 1
-fieldMaxValue 4096
-value 64
llSculptEditorResolutionX;
intSliderGrp
-field on
-label "Y Resolution"
-minValue 1
-maxValue 512
-fieldMinValue 1
-fieldMaxValue 4096
-value 64
llSculptEditorResolutionY;
checkBoxGrp
-label ""
-label1 "Maximize scale"
-numberOfCheckBoxes 1
-value1 on
llSculptEditorMaximizeScale;
checkBoxGrp
-label ""
-label1 "Correct orientation"
-numberOfCheckBoxes 1
-value1 off
llSculptEditorFixOrientation;
separator;
checkBoxGrp
-label ""
-label1 "Bake surface texture"
-numberOfCheckBoxes 1
-value1 off
-changeCommand llSculptEditorSurfaceBakeCallback
llSculptEditorSurfaceBake;
intSliderGrp
-field on
-label "X Resolution"
-minValue 1
-maxValue 512
-fieldMinValue 1
-fieldMaxValue 4096
-value 128
llSculptEditorSurfaceResolutionX;
intSliderGrp
-field on
-label "Y Resolution"
-minValue 1
-maxValue 512
-fieldMinValue 1
-fieldMaxValue 4096
-value 128
llSculptEditorSurfaceResolutionY;
checkBoxGrp
-label ""
-label1 "Include shadows"
-numberOfCheckBoxes 1
-value1 off
llSculptEditorSurfaceShadows;
separator;
checkBoxGrp
-label ""
-label1 "Generate primscript"
-numberOfCheckBoxes 1
-value1 off
llSculptEditorGeneratePrimScript;
setUITemplate -popTemplate;
string $applyBtn = getOptionBoxApplyBtn();
button -edit
-label "Export"
-command "llSculptEditorCallback"
$applyBtn;
string $applyAndCloseBtn = getOptionBoxApplyAndCloseBtn();
button -edit
-label "Export and Close"
-command "llSculptEditorCallback"
$applyAndCloseBtn;
setOptionBoxTitle("Export Sculpt Texture"

;
setOptionBoxHelpTag( "ConvertFileText" );
llSculptEditorSurfaceBakeCallback();
showOptionBox();
}
//
llSculptEditor;