Jump to content
The Dark Mod Forums

Vertex Blending in DR


grayman

Recommended Posts

You are using an (very) outdated version of the script. Download the one in the linked thread and place it in the proper folder.

Which link thread, because the one listed here and as shown below -

 

 

 

# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****

#TODO:

# Set the command name so that DarkRadiant recognises this file
__commandName__ = 'aseExportBlend'
__commandDisplayName__ = 'Export blended ASE...'

# The actual algorithm called by DarkRadiant is contained in the execute() function
def execute():
    script = "Dark Radiant ASCII Scene Export (*.ase)"
    author = "Richard Bartlett, some additions by greebo and tels"
    version = "0.7"

    # Check if we have a valid selection
    #import time
    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.', Dialog.ERROR)
        errMsg.run()
        return

    shaderlist = []
    geomlist = []
    blendlist = []
    xcenter = 0
    ycenter = 0
    zcenter = 0

    def randfloat(a,:
        c=time.clock()
        return a+(b-a)*((c*1000000)%1)


    # used for getting the blend height

    def getBlendHeight(x,p,size):
        min = 0
        max = 0
        for i in range(size-1):
            y = x[i]
            y[2] 
            if y[2]<min:
                min=y[2]
            if y[2]>max:
                max=y[2]
        return max*float(p)+min*(1-float(p))

    # method checking whether a point is inside an aabb

    def isInside(x,ab):
        origin = ab.origin
        ext = ab.extents
        
        min = origin - ext
        max = origin + ext
        


        if (x[0]<min.x()-xcenter):
            return 0
        if (x[0]>max.x()-xcenter):
            return 0
        if (x[1]<min.y()-ycenter):
            return 0
        if (x[1]>max.y()-ycenter):
            return 0
        if (x[2]<min.z()-zcenter):
            return 0
        if (x[2]>max.z()-zcenter):
            return 0
        return 1

    # which texture to choose

    def getColor(x):
        for bl in blendlist:
            if (isInside(x,bl)):
                return 1
        return 0

    # simple linear triangulation of n-sided poly

    def triangulate(pointset):
        tris = []
        for count in range(1, len(pointset) - 1):
            tris.append([pointset[0], pointset[count], pointset[count + 1]])
        return tris

    # skin patch matrix with tris

    def skinmatrix(pointset, width, height):
        tris = []
        for h in range(height-1):
            for w in range(width-1):
                tris.append([pointset[w+(h*width)], pointset[w+1+(h*width)], pointset[w+width+(h*width)]])
                tris.append([pointset[w+1+(h*width)], pointset[w+1+width+(h*width)], pointset[w+width+(h*width)]])
        return tris

    # Obsttorte: Method to get the AABB of this Brush
    def processBlendBrush(brushnode):
        #ab = AABB(brushnode)
        origin = brushnode.getFace(0).getWinding()[0].vertex
        ab = AABB(origin,origin-origin)
        numfaces = brushnode.getNumFaces()
        for index in range(numfaces):
            facenode = brushnode.getFace(index)
            winding = facenode.getWinding()
            for x in winding:
                ab.includePoint(x.vertex)
        #print(ab.getRadius())
        blendlist.append(ab)

    def processBrush(brushnode):
        verts = []
        faces = []

        # Obsttorte: if blend, process seperately
        if (brushnode.hasShader('textures/common/blend')):
            processBlendBrush(brushnode)
            return

        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/aseExport/exportcaulk'))) == 0:
                continue

            if not shader in shaderlist:
                shaderlist.append(shader)
            winding = facenode.getWinding()
            tris = triangulate([x+len(verts) for x in range(len(winding))])
            for x in tris:
                x.append(shaderlist.index(shader))
                faces.append(x)
            for x in reversed(winding):
                verts.append([x.vertex.x(), x.vertex.y(), x.vertex.z(), x.texcoord.x(), x.texcoord.y() * -1, x.normal.x(), x.normal.y(), x.normal.z()])

        geomlist.append([verts, faces])
        return

    def processPatch(patchnode):
        verts = []
        faces = []

        shader = patchnode.getShader()

        # Tels: skip if caulk and no caulk should be exported
        if shader == 'textures/common/caulk' and int(GlobalRegistry.get('user/scripts/aseExport/exportcaulk')) == 0:
            return

        if not shader in shaderlist:
            shaderlist.append(shader)
        mesh = patchnode.getTesselatedPatchMesh()
        for x in mesh.vertices:
            verts.append([x.vertex.x(), x.vertex.y(), x.vertex.z(), x.texcoord.x(), x.texcoord.y() * -1, x.normal.x(), x.normal.y(), x.normal.z()])
        tris = skinmatrix([x for x in range(len(verts))], mesh.width, mesh.height)
        for x in tris:
            x.append(shaderlist.index(shader))
            faces.append(x)

        geomlist.append([verts, faces])
        return

    # Branch on primitive nodes
    def processPrimitive(scenenode):
        if scenenode.isBrush():
            processBrush(scenenode.getBrush())
        elif scenenode.isPatch():
            processPatch(scenenode.getPatch())
        return

    # Traversor class to visit child primitives of entities
    class nodeVisitor(SceneNodeVisitor):
        def pre(self, scenenode):
            # Brush?
            if scenenode.isBrush():
                processBrush(scenenode.getBrush())
            # Patch?
            elif scenenode.isPatch():
                processPatch(scenenode.getPatch())

            # Traverse all child nodes, regardless of type
            return 1

    class dataCollector(SelectionVisitor):
        def visit(self, scenenode):

            if scenenode.getNodeType() == 'primitive':
                processPrimitive(scenenode)
            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/aseExport/recentFilename'))

    # Add an entry box and remember the handle
    pathHandle = dialog.addPathEntry("Save path:", True)
    dialog.setElementValue(pathHandle, GlobalRegistry.get('user/scripts/aseExport/recentPath'))

    # Add a checkbox
    centerObjectsHandle = dialog.addCheckbox("Center objects at 0,0,0 origin")
    dialog.setElementValue(centerObjectsHandle, GlobalRegistry.get('user/scripts/aseExport/centerObjects'))

    # Add another checkbox
    exportCaulkHandle = dialog.addCheckbox("Export caulked faces")
    dialog.setElementValue(exportCaulkHandle, GlobalRegistry.get('user/scripts/aseExport/exportcaulk'))
    # Add a Spin Button for blending and one for random height
    #blendHeightHandle = dialog.addSpinButton("Level of blending in percent",0,1,0.05,2)
    #blendRandomnessHandle = dialog.addSpinButton("Randomness",0,1,0.05,2)
    if dialog.run() == Dialog.OK:
        fullpath = dialog.getElementValue(pathHandle) + '/' + dialog.getElementValue(fileHandle)
        if not fullpath.endswith('.ase'):
            fullpath = fullpath + '.ase'

        # Save the path for later use
        GlobalRegistry.set('user/scripts/aseExport/recentFilename', dialog.getElementValue(fileHandle))
        GlobalRegistry.set('user/scripts/aseExport/recentPath', dialog.getElementValue(pathHandle))
        GlobalRegistry.set('user/scripts/aseExport/centerObjects', dialog.getElementValue(centerObjectsHandle))
        GlobalRegistry.set('user/scripts/aseExport/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?', Dialog.ASK)
            if prompt.run() == Dialog.YES:
                overwrite = True
            else:
                overwrite = False
        except IOError:
            overwrite = True

        if overwrite:

            # Tels: Only collect the data if we are going to export it
            walker = dataCollector()
            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:
                    for vert in item[0]:
                        xlist.append(vert[0])
                        ylist.append(vert[1])
                        zlist.append(vert[2])
                xcenter=(max(xlist)+min(xlist))/2
                ycenter=(max(ylist)+min(ylist))/2
                zcenter=(max(zlist)+min(zlist))/2
                for item in geomlist:
                    for vert in item[0]:
                        vert[0] = vert[0] - xcenter
                        vert[1] = vert[1] - ycenter
                        vert[2] = vert[2] - zcenter
                

            # split objects that do not share the same texture on all faces
            newgeomlist = []
            for x in geomlist:
                texlist = []
                for data in x[1]:
                    texlist.append(data[3])
                if len(set(texlist)) > 1:
                    temp = []
                    for texture in set(texlist):
                        vertlist = []
                        facelist = []
                        for data in x[1]:
                            if data[3] == texture:
                                facelist.append(data)
                        usedverts = []
                        for face in facelist:
                            usedverts.extend(face[0:3])
                        usedverts = list(set(usedverts))
                        for index in usedverts:
                            vertlist.append(x[0][index])
                        newfacelist = []
                        for face in facelist:
                            newfacelist.append([vertlist.index(x[0][face[0]]),vertlist.index(x[0][face[1]]),vertlist.index(x[0][face[2]]),face[3]])
                        newgeomlist.append([vertlist, newfacelist])
                    #del geomlist[geomlist.index(x)]
                    #geomlist.extend(temp)
                    #newgeomlist.append(temp)
                else:
                    newgeomlist.append(x)
            geomlist = newgeomlist

            scene = '''\t*SCENE_FILENAME "{0}"
\t*SCENE_FIRSTFRAME 0
\t*SCENE_LASTFRAME 100
\t*SCENE_FRAMESPEED 30
\t*SCENE_TICKSPERFRAME 160
\t*SCENE_BACKGROUND_STATIC 0.0000\t0.0000\t0.0000
\t*SCENE_AMBIENT_STATIC 0.0000\t0.0000\t0.0000'''.format(GlobalMap.getMapName())

            materials = str()
            for x in shaderlist:
                materials = materials + '''\t*MATERIAL {0} {{
\t\t*MATERIAL_NAME "{1}"
\t\t*MATERIAL_CLASS "Standard"
\t\t*MATERIAL_AMBIENT 0.5882\t0.5882\t0.5882
\t\t*MATERIAL_DIFFUSE 0.5882\t0.5882\t0.5882
\t\t*MATERIAL_SPECULAR 0.9000\t0.9000\t0.9000
\t\t*MATERIAL_SHINE 0.1000
\t\t*MATERIAL_SHINESTRENGTH 0.0000
\t\t*MATERIAL_TRANSPARENCY 0.0000
\t\t*MATERIAL_WIRESIZE 1.0000
\t\t*MATERIAL_SHADING Blinn
\t\t*MATERIAL_XP_FALLOFF 0.0000
\t\t*MATERIAL_SELFILLUM 0.0000
\t\t*MATERIAL_FALLOFF In
\t\t*MATERIAL_XP_TYPE Filter
\t\t*MAP_DIFFUSE {{
\t\t\t*MAP_NAME "{2}"
\t\t\t*MAP_CLASS "Bitmap"
\t\t\t*MAP_SUBNO 1
\t\t\t*MAP_AMOUNT 1.0000
\t\t\t*BITMAP "\\\\purgatory\\purgatory\\doom\\base\{2}"
\t\t\t*MAP_TYPE Screen
\t\t\t*UVW_U_OFFSET 0.0000
\t\t\t*UVW_V_OFFSET 0.0000
\t\t\t*UVW_U_TILING 1.0000
\t\t\t*UVW_V_TILING 1.0000
\t\t\t*UVW_ANGLE 0.0000
\t\t\t*UVW_BLUR 1.0000
\t\t\t*UVW_BLUR_OFFSET 0.0000
\t\t\t*UVW_NOUSE_AMT 1.0000
\t\t\t*UVW_NOISE_SIZE 1.0000
\t\t\t*UVW_NOISE_LEVEL 1
\t\t\t*UVW_NOISE_PHASE 0.0000
\t\t\t*BITMAP_FILTER Pyramidal
\t\t}}
\t}}
'''.format(shaderlist.index(x), x, x.replace('/','\\'))

            geomobjects = str()

            for x in geomlist:
                # x[0] = vertices
                # vert[0] - vert[2] = vertex coords
                # vert[3] - vert[4] = texture coords
                # vert[5] - vert[7] = normal
                # x[1] = faces
                vertlist = str()
                #bh = getBlendHeight(x[0],dialog.getElementValue(blendHeightHandle),len(x[0]))
                clist = []
                for data in x[0]:
                    clist.append(getColor(data))
                for count, data in enumerate(x[0]):
                    vertlist = vertlist + '''\t\t\t*MESH_VERTEX {0}\t{1: 10.4f}\t{2: 10.4f}\t{3: 10.4f}\n'''.format(count, data[0], data[1], data[2])
                facelist = str()
                for count, data in enumerate(x[1]):
                    facelist = facelist + '''\t\t\t*MESH_FACE     {0}:  A:   {1} B:   {2} C:     {3} AB:       0 BC:    0 CA:    0\t *MESH_SMOOTHING 1 \t*MESH_MTLID {4}\n'''.format(count, data[0], data[1], data[2], data[3])
                tvertlist = str()
                for count, data in enumerate(x[0]):
                    tvertlist = tvertlist + '''\t\t\t*MESH_TVERT {0}\t{1: 10.4f}\t{2: 10.4f}\t0.0000\n'''.format(count, data[3], data[4])
                tfacelist = str()
                for count, data in enumerate(x[1]):
                    tfacelist = tfacelist + '''\t\t\t*MESH_TFACE {0}\t{1}\t{2}\t{3}\n'''.format(count, data[0], data[1], data[2])
                cfacelist = str()
                for count, data in enumerate(x[1]):
                    cfacelist = cfacelist + '''\t\t\t*MESH_CFACE {0}\t{1}\t{2}\t{3}\n'''.format(count,clist[data[0]],clist[data[1]],clist[data[2]])

                normals = str()
                for count, data in enumerate(x[1]):
                    normals += '''\t\t\t*MESH_FACENORMAL {0}\t{1: 10.4f}\t{2: 10.4f}\t{3: 10.4f}\n'''.format(count, x[0][data[0]][5], x[0][data[0]][6], x[0][data[0]][7]) # greebo: use first vertex normal as face normal
                    normals += '''\t\t\t\t*MESH_VERTEXNORMAL {0}\t{1: 10.4f}\t{2: 10.4f}\t{3: 10.4f}\n'''.format(data[0], x[0][data[0]][5], x[0][data[0]][6], x[0][data[0]][7])
                    normals += '''\t\t\t\t*MESH_VERTEXNORMAL {0}\t{1: 10.4f}\t{2: 10.4f}\t{3: 10.4f}\n'''.format(data[1], x[0][data[1]][5], x[0][data[1]][6], x[0][data[1]][7])
                    normals += '''\t\t\t\t*MESH_VERTEXNORMAL {0}\t{1: 10.4f}\t{2: 10.4f}\t{3: 10.4f}\n'''.format(data[2], x[0][data[2]][5], x[0][data[2]][6], x[0][data[2]][7])

                if len(x[1]) == 0:
                    continue

                geomobjects = geomobjects + '''*GEOMOBJECT {{
\t*NODE_NAME "{0}"
\t*NODE_TM {{
\t\t*NODE_NAME "{0}"
\t\t*INHERIT_POS 0 0 0
\t\t*INHERIT_ROT 0 0 0
\t\t*INHERIT_SCL 0 0 0
\t\t*TM_ROW0 1.0000\t0.0000\t0.0000
\t\t*TM_ROW1 0.0000\t1.0000\t0.0000
\t\t*TM_ROW2 0.0000\t0.0000\t1.0000
\t\t*TM_ROW3 0.0000\t0.0000\t0.0000
\t\t*TM_POS 0.0000\t0.0000\t0.0000
\t\t*TM_ROTAXIS 0.0000\t0.0000\t0.0000
\t\t*TM_ROTANGLE 0.0000
\t\t*TM_SCALE 1.0000\t1.0000\t1.0000
\t\t*TM_SCALEAXIS 0.0000\t0.0000\t0.0000
\t\t*TM_SCALEAXISANG 0.0000
\t}}
\t*MESH {{
\t\t*TIMEVALUE 0
\t\t*MESH_NUMVERTEX {1}
\t\t*MESH_NUMFACES {2}
\t\t*MESH_VERTEX_LIST {{
{3}\t\t}}
\t\t*MESH_FACE_LIST {{
{4}\t\t}}
\t\t*MESH_NUMTVERTEX {5}
\t\t*MESH_TVERTLIST {{
{6}\t\t}}
\t\t*MESH_NUMTVFACES {7}
\t\t*MESH_TFACELIST {{
{8}\t\t}}
\t\t*MESH_NUMCVERTEX 2
\t\t*MESH_CVERTLIST {{
\t\t\t*MESH_VERTCOL 0\t1.0000\t1.0000\t1.0000
\t\t\t*MESH_VERTCOL 1\t0.0000\t0.0000\t0.0000
\t\t}}
\t\t*MESH_NUMCVFACES {9}
\t\t*MESH_CFACELIST {{
{10}\t\t}}
\t\t*MESH_NORMALS {{
{11}\t\t}}
\t}}
\t*PROP_MOTIONBLUR 0
\t*PROP_CASTSHADOW 1
\t*PROP_RECVSHADOW 1
\t*MATERIAL_REF {12}
}}\n'''.format('mesh' + str(geomlist.index(x)), \
        len(x[0]), \
        len(x[1]), \
        vertlist, \
        facelist, \
        len(x[0]), \
        tvertlist, \
        len(x[1]), \
        tfacelist, \
        len(x[1]), \
        cfacelist, \
        normals, \
        x[1][0][3]) # material reference from first face

                data = '''*3DSMAX_ASCIIEXPORT\t200
*COMMENT "{0} v{1}"
*SCENE {{
{2}
}}
*MATERIAL_LIST {{
\t*MATERIAL_COUNT {3}
{4}}}
{5}'''.format(script, version, scene, len(shaderlist), materials, geomobjects)

                # Write the compiled data to the output file
                file = open(fullpath, 'w')
                file.write(data)
                file.close()

# __executeCommand__ evaluates to true after DarkRadiant has successfully initialised
if __executeCommand__:
    execute()


 

 

 

Dosen't appear to do anything using DR 2.03...

Link to comment
Share on other sites

You are using an (very) outdated version of the script. Download the one in the linked thread and place it in the proper folder.

 

Okay, I downloaded the exporter from the OP (this one: http://forums.thedarkmod.com/topic/15026-dr-ase-blend-exporter/?p=318475) and now it works as advertized.

 

The vertex blending exporter I had, I think, was the one that comes with DR 2.0.2. Does the DR come bundled with the wrong exporter? Can someone confirm?

Clipper

-The mapper's best friend.

Link to comment
Share on other sites

Hmm, why is it working for you and not for me - I have to missing something obvious here....

 

I asked Greebo to adde dit to 2.02 onwards, its possible I gave him the link to an older version by mistake. When he resumes work on 2.03 I will ask him to insert the latest version.

 

[update] just tested with DR 181 and the export works fine, it appears that DR 203 breaks or dosent want to work with the script :-(

Link to comment
Share on other sites

The script that comes with DR is a wrong one. I've already reported this to greebo.

 

Something got mixed up there as I made several versions.

 

 


it appears that DR 203 breaks or dosent want to work with the script

Will test that once I find the time.

FM's: Builder Roads, Old Habits, Old Habits Rebuild

Mapping and Scripting: Apples and Peaches

Sculptris Models and Tutorials: Obsttortes Models

My wiki articles: Obstipedia

Texture Blending in DR: DR ASE Blend Exporter

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recent Status Updates

    • nbohr1more

      Was checking out old translation packs and decided to fire up TDM 1.07. Rightful Property with sub-20 FPS areas yay! ( same areas run at 180FPS with cranked eye candy on 2.12 )
      · 2 replies
    • taffernicus

      i am so euphoric to see new FMs keep coming out and I am keen to try it out in my leisure time, then suddenly my PC is spouting a couple of S.M.A.R.T errors...
      tbf i cannot afford myself to miss my network emulator image file&progress, important ebooks, hyper-v checkpoint & hyper-v export and the precious thief & TDM gamesaves. Don't fall yourself into & lay your hands on crappy SSD
       
      · 5 replies
    • OrbWeaver

      Does anyone actually use the Normalise button in the Surface inspector? Even after looking at the code I'm not quite sure what it's for.
      · 7 replies
    • Ansome

      Turns out my 15th anniversary mission idea has already been done once or twice before! I've been beaten to the punch once again, but I suppose that's to be expected when there's over 170 FMs out there, eh? I'm not complaining though, I love learning new tricks and taking inspiration from past FMs. Best of luck on your own fan missions!
      · 4 replies
    • The Black Arrow

      I wanna play Doom 3, but fhDoom has much better features than dhewm3, yet fhDoom is old, outdated and probably not supported. Damn!
      Makes me think that TDM engine for Doom 3 itself would actually be perfect.
      · 6 replies
×
×
  • Create New...