def pre(self, node): # Try to get a patch from this node patch = node.getPatch() if not patch.isNull(): print('Patch information:') print('Dimensions: ' + str(patch.getWidth()) + 'x' + str(patch.getHeight())) w = 0 while w < patch.getWidth(): h = 0 while h < patch.getHeight(): # Push the vertex around a bit ctrl = patch.ctrlAt(h, w) ctrl.vertex += dr.Vector3(0, 0, 10 * (h - w)) h += 1 w += 1 patch.controlPointsChanged() return 1
str(s.y()) + ',' + str(s.z())) return 1 walker = ModelFinder() GlobalSceneGraph.root().traverse(walker) # Test the ModelSkinCache interface #allSkins = GlobalModelSkinCache.getAllSkins() # #for skin in allSkins: # modelskin = GlobalModelSkinCache.capture(skin) # print('Skin found: ' + modelskin.getName()) v = dr.Vector3(6, 6, 6) v += dr.Vector3(10, 10, 10) print(v) # Test patch manipulation class PatchManipulator(dr.SceneNodeVisitor): def pre(self, node): # Try to get a patch from this node patch = node.getPatch() if not patch.isNull(): print('Patch information:') print('Dimensions: ' + str(patch.getWidth()) + 'x' + str(patch.getHeight()))
def execute(): script = "DarkRadiant Wavefront OBJ Export (*.obj)" author = "Python port by greebo, based on original exporter C++ code in DarkRadiant and the ASE exporter scripts" version = "0.2" import darkradiant as dr # Check if we have a valid selection selectionInfo = GlobalSelectionSystem.getSelectionInfo() # Don't allow empty selections or selected components only if selectionInfo.totalCount == 0 or selectionInfo.totalCount == selectionInfo.componentCount: errMsg = GlobalDialogManager.createMessageBox( 'No selection', 'Nothing selected, cannot run exporter.', dr.Dialog.ERROR) errMsg.run() return # An exportable object found in the map class Geometry(object): name = '' # Name of the object to be exported vertices = [] # Vertices texcoords = [] # Texture coordinates faces = [ ] # Each face in turn is an array of indices referencing the vertices and texcoords # For simplicity, we assume that the referenced vertices and texcoords always # have the same global index number. def __init__(self, name): self.name = name self.vertices = [] self.texcoords = [] self.faces = [] # An exportable object found in the map class Geometries(object): vertexCount = 0 # Global Vertex Index (every vertex in an OBJ file has a unique number) objects = [] # List of Geometry objects # We put all of the objects we collect in the map into this array # Before we write it to the output stream the vertices can be processed (e.g. centered) geomlist = Geometries() def processBrush(brushnode): # Create a new exportable object geometry = Geometry('Brush{0}'.format(len(geomlist.objects))) numfaces = brushnode.getNumFaces() for index in range(numfaces): facenode = brushnode.getFace(index) shader = facenode.getShader() # Tels: skip if caulk and no caulk should be exported if (shader == 'textures/common/caulk') and (int( GlobalRegistry.get('user/scripts/objExport/exportcaulk')) ) == 0: continue winding = facenode.getWinding() # Remember the index of the first vertex firstVertex = geomlist.vertexCount for point in winding: # Write coordinates into the export buffers geometry.vertices.append(point.vertex) geometry.texcoords.append(point.texcoord) # Keep track of the exported vertices geomlist.vertexCount += 1 # Append the face to the list, referencing vertices from firstVertex to the current count # Face indices are 1-based, so increase by 1 each time # Reverse the list to produce the correct face normal direction geometry.faces.append([ i for i in reversed( range(firstVertex + 1, geomlist.vertexCount + 1)) ]) print('Processed brush geometry: {0} verts and {1} faces'.format( len(geometry.vertices), len(geometry.faces))) geomlist.objects.append(geometry) return def processPatch(patchnode): shader = patchnode.getShader() # Tels: skip if caulk and no caulk should be exported if shader == 'textures/common/caulk' and int( GlobalRegistry.get('user/scripts/objExport/exportcaulk')) == 0: return # Create a new exportable object geometry = Geometry('Patch{0}'.format(len(geomlist.objects))) mesh = patchnode.getTesselatedPatchMesh() # Remember the index of the first vertex firstVertex = geomlist.vertexCount for h in range(0, mesh.height): for w in range(0, mesh.width): point = mesh.vertices[mesh.width * h + w] # Write coordinates into the lists geometry.vertices.append(point.vertex) geometry.texcoords.append(point.texcoord) # Keep track of the exported vertices geomlist.vertexCount += 1 # Starting from the second row, we're gathering the faces if h > 0 and w > 0: # Gather the indices forming a quad v1 = 1 + firstVertex + h * mesh.width + w v2 = 1 + firstVertex + (h - 1) * mesh.width + w v3 = 1 + firstVertex + (h - 1) * mesh.width + (w - 1) v4 = 1 + firstVertex + h * mesh.width + (w - 1) # Construct the quad geometry.faces.append([v1, v4, v3, v2]) print('Processed patch geometry: {0} verts and {1} faces'.format( len(geometry.vertices), len(geometry.faces))) geomlist.objects.append(geometry) return # Traversor class to visit child primitives of entities class nodeVisitor(dr.SceneNodeVisitor): def pre(self, scenenode): if scenenode.isBrush(): processBrush(scenenode.getBrush()) elif scenenode.isPatch(): processPatch(scenenode.getPatch()) # Traverse all child nodes, regardless of type return 1 class SelectionWalker(dr.SelectionVisitor): def visit(self, scenenode): if scenenode.isBrush(): processBrush(scenenode.getBrush()) elif scenenode.isPatch(): processPatch(scenenode.getPatch()) elif scenenode.isEntity(): # greebo: Found an entity, this could be a func_static or similar # Traverse children of this entity using a new walker nodewalker = nodeVisitor() scenenode.traverse(nodewalker) else: print('WARNING: unsupported node type selected. Skipping: ' + scenenode.getNodeType()) # Dialog dialog = GlobalDialogManager.createDialog(script + ' v' + version) # Add an entry box and remember the handle fileHandle = dialog.addEntryBox("Filename:") dialog.setElementValue( fileHandle, GlobalRegistry.get('user/scripts/objExport/recentFilename')) # Add an entry box and remember the handle pathHandle = dialog.addPathEntry("Save path:", True) dialog.setElementValue( pathHandle, GlobalRegistry.get('user/scripts/objExport/recentPath')) # Add a checkbox centerObjectsHandle = dialog.addCheckbox("Center objects at 0,0,0 origin") dialog.setElementValue( centerObjectsHandle, GlobalRegistry.get('user/scripts/objExport/centerObjects')) # Add another checkbox exportCaulkHandle = dialog.addCheckbox("Export caulked faces") dialog.setElementValue( exportCaulkHandle, GlobalRegistry.get('user/scripts/objExport/exportcaulk')) if dialog.run() == dr.Dialog.OK: fullpath = dialog.getElementValue( pathHandle) + '/' + dialog.getElementValue(fileHandle) if not fullpath.endswith('.obj'): fullpath = fullpath + '.obj' # Save the path for later use GlobalRegistry.set('user/scripts/objExport/recentFilename', dialog.getElementValue(fileHandle)) GlobalRegistry.set('user/scripts/objExport/recentPath', dialog.getElementValue(pathHandle)) GlobalRegistry.set('user/scripts/objExport/centerObjects', dialog.getElementValue(centerObjectsHandle)) GlobalRegistry.set('user/scripts/objExport/exportcaulk', dialog.getElementValue(exportCaulkHandle)) try: file = open(fullpath, 'r') file.close() prompt = GlobalDialogManager.createMessageBox( 'Warning', 'The file ' + fullpath + ' already exists. Do you wish to overwrite it?', dr.Dialog.ASK) if prompt.run() == dr.Dialog.YES: overwrite = True else: overwrite = False except IOError: overwrite = True if overwrite: walker = SelectionWalker() GlobalSelectionSystem.foreachSelected(walker) # greebo: Check if we should center objects at the 0,0,0 origin if int(dialog.getElementValue(centerObjectsHandle)) == 1: # center objects at 0,0,0 xlist = [] ylist = [] zlist = [] for item in geomlist.objects: for vert in item.vertices: xlist.append(vert.x()) ylist.append(vert.y()) zlist.append(vert.z()) xcenter = (max(xlist) + min(xlist)) / 2 ycenter = (max(ylist) + min(ylist)) / 2 zcenter = (max(zlist) + min(zlist)) / 2 for item in geomlist.objects: for vert in item.vertices: vert -= dr.Vector3(xcenter, ycenter, zcenter) # This string will hold our export data data = str() for x in geomlist.objects: objstr = str() # Group name (g) objstr = objstr + "g {0}\n\n".format(x.name) # Vertex list (v) for vert in x.vertices: objstr = objstr + "v {0} {1} {2}\n".format( vert.x(), vert.y(), vert.z()) objstr = objstr + "\n" # Texture coord list (vt) for texcoord in x.texcoords: objstr = objstr + "vt {0} {1}\n".format( texcoord.x(), 1 - texcoord.y()) # reverse V coord objstr = objstr + "\n" # Face list (f) for faceIndices in x.faces: objstr = objstr + "f" for faceIndex in faceIndices: objstr = objstr + " {0}/{1}".format( faceIndex, faceIndex) objstr = objstr + "\n" objstr = objstr + "\n" data = data + objstr # Write the compiled data to the output file file = open(fullpath, 'w') file.write(data) file.close() print('Done writing OBJ data to {0}'.format(fullpath))