-- Required for building fragment-proxys: filein "pipeline/export/maps/mapsetup.ms" struct RsPropRenderSettings ( buildFragsBool=undefined, p4checkoutBool=undefined, syncTexturesBool=undefined, renderOutputPath=undefined, renderStandardBool=undefined, renderScaleObjectBool=undefined, renderAngle=undefined, minCamZoom = undefined, jpgQualitySetting =undefined, batchMode = false ) struct RsPropRenderUtils ( fn GenerateAndSaveImages filename renderSmall:false edgeFaces:false ThumbSize:[640,480] RatioDiff:1.0 = ( clearSelection() -- Large img viewport.setShowEdgeFaces edgeFaces redrawviews() img = gw.getViewportDib() img.filename = filename save img -- format "Render: %\n" (RsMakeBackSlashes filename) if (RatioDiff != 1.0) do ( local tempTexture = bitmapTexture bitmap:img case of ( (RatioDiff > 1): ( tempTexture.coords.U_Tiling /= RatioDiff ) (RatioDiff < 1): ( tempTexture.coords.V_Tiling *= RatioDiff ) ) img = renderMap tempTexture size:ThumbSize filter:False img.filename = filename save img ) -- Small img if renderSmall do ( smallImg = bitmap (ThumbSize.X / 2) (ThumbSize.Y / 2) copy img smallImg smallImg.filename = (getFilenamePath filename) + (getFilenameFile filename) + "_Small.jpg" -- format "Render: %\n" smallImg.filename save smallImg close smallImg ) close img ), -- -- fn: GetObjDimensions -- desc: Returns the object's dimensions -- fn GetObjDimensions obj bb = ( widthX = bb[2].x - bb[1].x lengthY = bb[2].y - bb[1].y heightZ = bb[2].z - bb[1].z -- Incase these come out negative, make them positive if (widthX < 0 ) do ( widthX *= -1 ) if (lengthY < 0 ) do ( lengthY *= -1 ) if (heightZ < 0 ) do ( heightZ *= -1 ) objDim = Point3 widthX lengthY heightZ ), fn getObjRadius obj objCentre xyRadius:false= ( -- Get the max radius of the object: local centreOffset = objCentre - obj.pos - obj.objectoffsetpos if xyRadius do ( centreOffset.z = 0 ) local objMesh = copy obj.mesh local objRadius = 0.0 local vertPos, vertDist for vert in objMesh.verts do ( vertPos = vert.pos if xyRadius do (vertPos.z = 0) vertDist = distance (vertPos * obj.scale) centreOffset if (vertDist > objRadius) do (objRadius = vertDist) ) objRadius ), -- -- fn: PositionScaleObj -- desc: Places the scale-object (i.e. standing human) depending on the size of the object being rendered -- fn PositionScaleObj ScaleObj objDim objCentre ScaleObjDim ScaleObjRadius camAngle= ( ScaleObj.isHidden = false ScaleObj.wirecolor = case of ( -- Object is shown as pink if object is over 10 units (objDim.z >= 10):(color 255 64 200) -- Yellow if between 2 and 10 units (objDim.z >= 2):(color 200 200 32) -- Green if smaller than 2 units Default:(color 0 128 0) ) ScaleObj.pos = objCentre -- The origin isn't consistent for all objects - some have their z origin in their centre -- so make sure the ScaleObj is 'standing' at same level as the prop is, rather than just -- relying on the origin to always start on the 'ground' plane ScaleObj.pos.z = objCentre.z - (objDim.z / 2) local posMults = #([1,1,0],[1,-1,0],[-1,-1,0],[-1,1,0]) local posMultNum = case of ( (camAngle == (eulerAngles 0 0 90)):1 (camAngle == (eulerAngles 0 0 0)):2 (camAngle == (eulerAngles 0 0 180)):3 (camAngle == (eulerAngles 0 0 -90)):4 ) -- If obj is longer (x axis) than longer (y axis), put ScaleObj in front/behind -- Otherwise, put ScaleObj to left of object local posMult = if (objDim.x < objDim.y) then posMults[posMultNum] else ( if (objDim.z > ScaleObjDim.z) then ( posMultNum -= 1 ) else ( posMultNum += 1 ) posMultNum = mod posMultNum 4 if (posMultNum == 0) do (posMultNum = 4) posMult = posMults[posMultNum] * [0,1,0] ) ScaleObj.pos += (posMult * (ScaleObjRadius + (objDim / 2))) ), -- this should be called directly after creating the camera, but before you transform the camera at all... it is a simple setup. fn placeTextInRender parentCamera renderTextString= ( local placedTextObj = text size:0.25 text:renderTextString render_renderable:true wirecolor:[255,0,0] pos:parentCamera.target.pos render_thickness:0.05 rotate placedTextObj (eulerAngles 90 0 90) move placedTextObj [-10, 0, -2.5] placedTextObj.parent = parentCamera ), -- This needs to be extended to work from a settings file in the future. for now it is hard coded fn generateTextFlags filepath= ( local textFlag = undefined local pathCases = #(datapair name:"lev_des" value:"DESIGN ONLY", datapair name:"areas" value:"AREA FILE TEST") for pattern in pathCases do ( if (matchpattern (toLower filepath) pattern:("*" + pattern.name + "*")) then ( if textFlag == undefined then ( textFlag = pattern.value ) else ( textFlag = textFlag + ", " + pattern.value ) ) ) textFlag ), -- -- fn: SetupCamera -- desc: Returns a camera and sets the viewport to use it for the render -- fn SetupCamera cam objCentre objRadius camDistanceFactor camMinZoom camAngle = ( if (objRadius < camMinZoom) do -- Set minimum object-size for zooming: ( objRadius = camMinZoom ) local camDirMult = case of ( ( camAngle == (eulerAngles 0 0 90)):[-1,1,1] (camAngle == (eulerAngles 0 0 0)):[1,1,1] (camAngle == (eulerAngles 0 0 180)):[-1,-1,1] (camAngle == (eulerAngles 0 0 -90)):[1,-1,1] -- Default direction ) cam.target.pos = objCentre cam.fovType = 1 local camDistance = (objRadius * 1.0) / (tan (0.5 * cam.curFOV)) cam.pos = objCentre + (camDirMult * camDistance * camDistanceFactor) cam.clipManually = true cam.nearclip = 0.0 viewport.setcamera cam cam ), -- -- fn: RenderSelected -- desc: Render selected objects out to network drive, two images. -- One rendered textured, another with edged faces and a standing-human scale-object. -- --fn RenderObjs objs buildFrags:chkRebuildFrags.checked p4checkout:chkPerforce.checked syncTextures:chkSyncTextures.checked = fn RenderObjs objs settingsObject quiet:true ThumbSize:[640,480] = ( local modelsDir = RsConfigGetModelSourceDir() local modelsDirCount = modelsDir.count local currentPath = RsMakeSafeSlashes (maxfilePath + (getFilenameFile maxfileName)) print ("Cur Path:" + currentPath) if not (matchPattern currentPath pattern:(modelsDir + "*")) do ( messageBox ("Can't render props - Maxfile must be saved under:\n\n" + modelsDir) title:"Error: Invalid Maxfile path" return false ) local textFlag = generateTextFlags currentPath --used to generate text in the render --print ("TEXTFLAGS:" + textFlag) local exportPath = RsMakeSafeSlashes (settingsObject.renderOutputPath + "/" + (substring currentPath modelsDirCount -1) + "/") RsMakeSurePathExists exportPath if settingsObject.buildFragsBool do ( gRsMapExportFragments.preExportRename() gRsMapExportFragments.buildAllFragments silent:true objs:objs gRsMapExportFragments.postExportRename() ) -- Filter objs down to what we're actually going to render local doObjs = for obj in objs where (isValidNode obj) collect ( local useObj = obj local isFragProxy = False -- If this is a frag object, render its proxy if (matchpattern obj.name pattern:"*_frag_") do ( local fragProxy = getNodeByName (substring obj.name 1 (obj.name.count - 6)) useObj = fragProxy if (useObj != undefined) do ( isFragProxy = True ) ) if ( -- Only render for Gta Objects: (GetAttrClass useObj == "Gta Object") and -- Don't render if object-parent is geometry too: (GetAttrClass useObj.parent != "Gta Object") and -- Don't render for X/RsRefs: (not isRefObj useObj) and -- Don't render thumbs for objects with SceneLink children: (i.e. LODs of all kinds) ( local getObjs = #() RsSceneLink.GetChildren -1 obj &getObjs (getObjs.count == 0) ) and -- Don't render "Dont Export" geometry, unless it's a Frag Proxy: (isFragProxy or ((GetAttr useObj (GetAttrIndex "Gta Object" "Dont Export")) != true)) ) then useObj else dontCollect ) -- Pre-generate the object-filenames: local renderFiles = #() local defaultFilenames = #() local scaleFilenames = #() for obj in doObjs do ( local filenameStart = exportPath + obj.name if settingsObject.renderStandardBool do ( append defaultFilenames (filenameStart + ".jpg") ) if settingsObject.renderScaleObjectBool do ( append scaleFilenames (filenameStart + "_Jaxx.jpg") ) ) local renderFiles = #() join renderFiles defaultFilenames join renderFiles scaleFilenames -- Exit if no files are to be rendered: if (renderFiles.count == 0) do ( return true ) if settingsObject.p4checkoutBool do ( -- Perforce-add/edit all render-files: pushPrompt "Preparing Perforce for export" local perforceSuccess = gRsPerforce.add_or_edit renderFiles queueAdd:true popPrompt() if (not perforceSuccess) and (queryBox "Problems were encountered accessing Perforce.\nCancel render?" title:"Prop Render: Perforce Errors") do ( return false ) ) if settingsObject.syncTexturesBool do ( local matsUsed = #() for obj in doObjs do ( local objMats = RsGetMaterialsOnObjFaces obj join matsUsed objMats ) local textureList = #() for mat in (makeUniqueArray matsUsed) do ( RsGetMaterialTextures mat textureList:textureList ) RsP4syncTextures textureList ) undo off ( -- Changing render-options is slow when Diplay panel is up, so this'll speed it up: max create mode -- Remember which things were hidden/shown local selectionWas = selection as array local objectsWas = objects as array local hiddenWas = for obj in objectsWas collect obj.isHidden for object in objects do (object.isHidden = true) local activeViewport = viewport.activeViewport local gridVisWas = viewport.getGridVisibility activeViewport viewport.setGridVisibility #all false local renderLevelWas = viewport.getRenderLevel() viewport.setRenderLevel #smoothhighlights local jpegQualityWas = jpeg.getQuality() jpeg.setQuality settingsObject.jpgQualitySetting local BGColorWas = getUIColor 41 setUIColor 41 [0.49,0.49,0.49] local displayColorWireframeWas = displayColor.wireframe local displayColorShadedWas = displayColor.shaded displayColor.wireframe = #object displayColor.shaded = #material local edgeFacesWas = viewport.getShowEdgeFaces() local viewCamWas = getActiveCamera() local viewTypeWas = viewport.getType() viewport.setType #view_persp_user local viewTMWas = viewport.getTM() local fovWas = viewport.getFOV() local focalWas = viewport.getFocalDistance() local windowSizeWas = [gw.getWinSizeX(), gw.getWinSizeY()] local camDistanceFactor = 1.1 -- Set viewport size/shape: local currentSizeRatio = (windowSizeWas.X / windowSizeWas.Y) local ThumbSizeRatio = (ThumbSize.X / ThumbSize.Y) local RatioDiff = (currentSizeRatio / ThumbSizeRatio) local newViewSize = ThumbSize case of ( (RatioDiff > 1): ( newViewSize = [ThumbSize.X * RatioDiff, ThumbSize.Y] camDistanceFactor *= RatioDiff ) (RatioDiff < 1): ( newViewSize = [ThumbSize.X, ThumbSize.Y / RatioDiff] ) ) --format "%, % : %\n" currentSizeRatio ThumbSizeRatio newViewSize gw.setPos 0 0 newViewSize.X newViewSize.Y -- If the viewcube or stats is visible, turn it off for renders. -- Turned back on at end, if it was visible before this script was called. local viewCubeWas if (ViewCubeOps != undefined) do ( viewCubeWas = ViewCubeOps.Visibility ViewCubeOps.Visibility = false ) popPrompt() local cam = TargetCamera target:(TargetObject()) if textFlag != undefined then ( placeTextInRender cam textFlag -- add text into the render... ) local ScaleObj = undefined local copyObj = undefined -- try ( progressStart "Rendering objects:" format "Rendering % objects to \"%\"\n%\n" doObjs.count exportPath (doObjs as string) -- Create scale-object: ScaleObj = P_Standing() local ScaleObjBB = nodeLocalBoundingBox ScaleObj local ScaleObjDim = GetObjDimensions ScaleObj ScaleObjBB local ScaleObjRadius = 0.45 --getObjRadius ScaleObj [0,0,0] xyRadius:true local ScaleObjRot = settingsObject.renderAngle rotate ScaleObj ScaleObjRot for objNum = 1 to doObjs.count while (progressupdate ((100.0 * objNum) / doObjs.count)) do ( local obj = doObjs[objNum] local bb = nodeLocalBoundingBox obj local objCentre = (bb[1]+ bb[2]) / 2 local objDim = GetObjDimensions obj bb local objRadius = getObjRadius obj objCentre cam = SetupCamera cam objCentre objRadius camDistanceFactor settingsObject.minCamZoom settingsObject.renderAngle filenameConcat = exportPath + obj.name -- Show object: obj.isHidden = false -- Make inverted copy, to make up for lack of 2-sidedness in some shaders: copyObj = copy obj copyObj.name += "_TEMPCOPY" addModifier copyObj (Mesh_Select()) addModifier copyObj (Normalmodifier flip:true) select obj -- Render default image: if settingsObject.renderStandardBool do ( ScaleObj.isHidden = true GenerateAndSaveImages defaultFilenames[objNum] edgeFaces:false ThumbSize:ThumbSize RatioDiff:RatioDiff ) -- Render scale-object image if settingsObject.renderScaleObjectBool do ( ScaleObj.isHidden = false scaleFilename = scaleFilenames[objNum] PositionScaleObj ScaleObj objDim objCentre ScaleObjDim ScaleObjRadius settingsObject.renderAngle select #(obj, ScaleObj) GenerateAndSaveImages scaleFilename edgeFaces:true ThumbSize:ThumbSize RatioDiff:RatioDiff ) delete copyObj -- Hide object again for now obj.isHidden = true ) ) -- catch ( -- format "Exception caught while rendering the props:\n%\n" (getCurrentException()) ) progressEnd() for TempObj in #(Cam, ScaleObj, CopyObj) do ( if (isValidNode TempObj) do ( delete TempObj ) ) pushPrompt "Restoring viewport settings" -- Revert object-hidden states for n = 1 to objectsWas.count do ( objectsWas[n].isHidden = hiddenWas[n] ) clearSelection() select selectionWas -- Revert viewport settings gw.setPos 0 0 windowSizeWas.X windowSizeWas.Y viewport.setFocalDistance focalWas viewport.setFOV fovWas viewport.setTM viewTMWas viewport.setType viewTypeWas viewport.setGridVisibility activeViewport gridVisWas viewport.setRenderLevel renderLevelWas viewport.setShowEdgeFaces edgeFacesWas displayColor.wireframe = displayColorWireframeWas displayColor.shaded = displayColorShadedWas setUIColor 41 BGColorWas jpeg.setQuality jpegQualityWas if (viewCubeWas != undefined) do ( ViewCubeOps.Visibility = viewCubeWas ) popPrompt() ) -- Add queued files to Perforce, if any: gRsPerforce.postExportAdd showProgress:showProgress if quiet == false then ( messageboxmessage = "Successfully rendered " + doObjs.count as string + " objects." messagebox messageboxmessage title:"Render Finished" beep:false ) setFocus RsRenderPropsRoll return true ) )