Пример #1
0
 def getWorldPlane(self):
     plane = Plane(self.plane)
     plane.xform(self.solid.np.getMat(NodePath()))
     return plane
Пример #2
0
class SolidFace(MapWritable):

    ObjectName = "side"

    def __init__(self, id = 0, plane = Plane(0, 0, 1, 0), solid = None):
        MapWritable.__init__(self, base.document)
        self.id = id
        self.material = FaceMaterial()
        self.vertices = []
        self.isSelected = False
        self.plane = plane
        self.solid = solid
        self.hasGeometry = False
        self.vdata = None

        # Different primitive representations of this face.
        self.geom3D = None
        self.geom3DLines = None
        self.geom2D = None

        # Index into the Solid's GeomNode of the Geoms we render for this face.
        self.index3D = -1
        self.index3DLines = -1
        self.index2D = -1

        # RenderState for each Geom we render for this face.
        self.state3D = RenderState.makeEmpty()
        self.state3DLines = RenderState.make(AntialiasAttrib.make(AntialiasAttrib.MLine), ColorAttrib.makeFlat(Vec4(1, 1, 0, 1)))
        self.state2D = RenderState.makeEmpty()
        if solid:
            self.setColor(self.solid.color)

        # Not None if face is a displacement.
        self.dispInfo = None

        #self.generateNodes()

    def setPreviewState(self):
        self.state3D = self.state3D.setAttrib(TransparencyAttrib.make(True))
        self.state3D = self.state3D.setAttrib(ColorScaleAttrib.make(Vec4(1, 1, 1, PreviewAlpha)))
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(LEGlobals.PreviewBrush2DColor))

    def isDisplacement(self):
        return self.dispInfo is not None

    def getBounds(self, other = None):
        return self.solid.getBounds(other)

    def setSolid(self, solid):
        self.solid = solid

    def getOrientation(self):
        plane = self.getWorldPlane()

        # The normal must have a nonzero length!
        if plane[0] == 0 and plane[1] == 0 and plane[2] == 0:
            return FaceOrientation.Invalid

        #
        # Find the axis that the surface normal has the greatest projection onto.
        #

        orientation = FaceOrientation.Invalid
        normal = plane.getNormal()

        maxDot = 0
        for i in range(6):
            dot = normal.dot(FaceNormals[i])

            if (dot >= maxDot):
                maxDot = dot
                orientation = FaceOrientation(i)

        return orientation

    def showClipVisRemove(self):
        self.geom3D.setDraw(False)
        self.state3DLines = self.state3DLines.setAttrib(ColorAttrib.makeFlat(Vec4(1, 0, 0, 1)))
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(Vec4(1, 0, 0, 1)))
        self.solid.setFaceGeomState(self.geom3DLines, self.state3DLines)
        self.solid.setFaceGeomState(self.geom2D, self.state2D)

    def showClipVisKeep(self):
        self.geom3D.setDraw(True)
        self.state3DLines = self.state3DLines.setAttrib(ColorAttrib.makeFlat(Vec4(1, 1, 0, 1)))
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(Vec4(1, 1, 1, 1)))
        self.solid.setFaceGeomState(self.geom3DLines, self.state3DLines)
        self.solid.setFaceGeomState(self.geom2D, self.state2D)

    def show3DLines(self):
        if self.geom3DLines:
            self.geom3DLines.setDraw(True)

    def hide3DLines(self):
        if self.geom3DLines:
            self.geom3DLines.setDraw(False)

    def copy(self, generator):
        f = SolidFace(generator.getNextID(), Plane(self.plane), self.solid)
        f.isSelected = self.isSelected
        f.setFaceMaterial(self.material.clone())
        for i in range(len(self.vertices)):
            newVert = self.vertices[i].clone()
            newVert.face = f
            f.vertices.append(newVert)
        return f

    def clone(self):
        f = self.copy(IDGenerator())
        f.id = self.id
        return f

    def paste(self, f):
        self.plane = Plane(f.plane)
        self.isSelected = f.isSelected
        self.setMaterial(f.material.clone())
        self.solid = f.solid
        self.vertices = []
        for i in range(len(f.vertices)):
            newVert = f.vertices[i].clone()
            newVert.face = self
            self.vertices.append(newVert)
        self.generate()

    def unclone(self, f):
        self.paste(f)
        self.id = f.id

    def xform(self, mat):
        for vert in self.vertices:
            vert.xform(mat)
        self.plane.xform(mat)
        self.calcTextureCoordinates(True)
        if self.hasGeometry:
            self.regenerateGeometry()

    def getAbsOrigin(self):
        avg = Point3(0)
        for vert in self.vertices:
            avg += vert.getWorldPos()
        avg /= len(self.vertices)
        return avg

    def getWorldPlane(self):
        plane = Plane(self.plane)
        plane.xform(self.solid.np.getMat(NodePath()))
        return plane

    def getName(self):
        return "Solid face"

    def select(self):
        self.state3D = self.state3D.setAttrib(ColorScaleAttrib.make(Vec4(1, 0.75, 0.75, 1)))
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(Vec4(1, 0, 0, 1)))
        self.state2D = self.state2D.setAttrib(CullBinAttrib.make("fixed", LEGlobals.SelectedSort))
        self.state2D = self.state2D.setAttrib(DepthWriteAttrib.make(False))
        self.state2D = self.state2D.setAttrib(DepthTestAttrib.make(False))
        self.solid.setFaceGeomState(self.geom3D, self.state3D)
        self.solid.setFaceGeomState(self.geom2D, self.state2D)
        self.show3DLines()
        self.isSelected = True

    def deselect(self):
        self.state3D = self.state3D.removeAttrib(ColorScaleAttrib)
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(self.solid.color))
        self.state2D = self.state2D.removeAttrib(DepthWriteAttrib)
        self.state2D = self.state2D.removeAttrib(DepthTestAttrib)
        self.state2D = self.state2D.removeAttrib(CullBinAttrib)
        self.solid.setFaceGeomState(self.geom3D, self.state3D)
        self.solid.setFaceGeomState(self.geom2D, self.state2D)
        self.hide3DLines()
        self.isSelected = False

    def readKeyValues(self, kv):
        self.id = int(self.id)
        base.document.reserveFaceID(self.id)

        p0 = Point3()
        p1 = Point3()
        p2 = Point3()
        kv.parsePlanePoints(kv.getValue("plane"), p0, p1, p2)
        self.plane = Plane.fromVertices(p0, p1, p2)

        self.material.readKeyValues(kv)
        self.setMaterial(self.material.material)

    def writeKeyValues(self, kv):
        kv.setKeyValue("id", str(self.id))

        # Write out the first three vertices to define the plane in world space
        vert0 = self.vertices[0].getWorldPos()
        vert1 = self.vertices[1].getWorldPos()
        vert2 = self.vertices[2].getWorldPos()
        kv.setKeyValue("plane", "(%f %f %f) (%f %f %f) (%f %f %f)" % (
            vert0.x, vert0.y, vert0.z,
            vert1.x, vert1.y, vert1.z,
            vert2.x, vert2.y, vert2.z
        ))

        # Write out material values
        self.material.writeKeyValues(kv)

    def generate(self):
        self.regenerateGeometry()

    def setMaterial(self, mat):
        self.material.material = mat
        if mat:
            #self.state3D = self.state3D.setAttrib(BSPMaterialAttrib.make(mat.material))
            self.state3D = self.state3D.setAttrib(TextureAttrib.make(mat.material))
            #if mat.material.hasKeyvalue("$translucent") and bool(int(mat.material.getKeyvalue("$translucent"))):
            #    self.state3D = self.state3D.setAttrib(TransparencyAttrib.make(TransparencyAttrib.MDual))
            if self.geom3D:
                self.solid.setFaceGeomState(self.geom3D, self.state3D)
                #if mat.material.hasKeyvalue("$basetexture") and "tools" in mat.material.getKeyvalue("$basetexture"):
                #    self.geom3D.setDraw(False)

    def setColor(self, color):
        self.state2D = self.state2D.setAttrib(ColorAttrib.makeFlat(color))
        if self.geom2D:
            self.solid.setFaceGeomState(self.geom2D, self.state2D)

    def setFaceMaterial(self, faceMat):
        self.material = faceMat
        self.setMaterial(self.material.material)
        self.calcTextureCoordinates(True)
        self.send('faceMaterialChanged', [self])

    def alignTextureToFace(self):
        self.material.alignTextureToFace(self)
        self.calcTextureCoordinates(True)

    def alignTextureToWorld(self):
        self.material.alignTextureToWorld(self)
        self.calcTextureCoordinates(True)

    def calcTextureCoordinates(self, minimizeShiftValues):
        if minimizeShiftValues:
            self.minimizeTextureShiftValues()

        for vert in self.vertices:
            vert.uv.set(0, 0)

        if self.material.material is None:
            return
        if self.material.material.size.x == 0 or self.material.material.size.y == 0:
            return
        if self.material.scale.x == 0 or self.material.scale.y == 0:
            return

        for vert in self.vertices:
            vertPos = vert.getWorldPos()
            #
            # projected s, t (u, v) texture coordinates
            #
            s = self.material.uAxis.dot(vertPos) / self.material.scale.x + self.material.shift.x
            t = self.material.vAxis.dot(vertPos) / self.material.scale.y + self.material.shift.y

            #
            # "normalize" the texture coordinates
            #
            vert.uv.x = s / self.material.material.size.x
            vert.uv.y = -t / self.material.material.size.y

        self.calcTangentSpaceAxes()

        if self.hasGeometry:
            self.modifyGeometryUVs()

    def calcTangentSpaceAxes(self):
        #
        # Create the axes from texture space axes
        #
        plane = self.getWorldPlane()
        normal = plane.getNormal()
        self.material.binormal = Vec3(self.material.vAxis).normalized()
        self.material.tangent = normal.cross(self.material.binormal).normalized()
        self.material.binormal = self.material.tangent.cross(normal).normalized()

        #
        # Adjust tangent for "backwards" mapping if need be
        #
        tmp = self.material.uAxis.cross(self.material.vAxis)
        if normal.dot(tmp) > 0.0:
            self.material.tangent = -self.material.tangent

    def modifyGeometryUVs(self):
        # Modifies the geometry vertex UVs in-place
        twriter = GeomVertexWriter(self.vdata, InternalName.getTexcoord())
        tanwriter = GeomVertexWriter(self.vdata, InternalName.getTangent())
        bwriter = GeomVertexWriter(self.vdata, InternalName.getBinormal())

        for i in range(len(self.vertices)):
            twriter.setData2f(self.vertices[i].uv)
            tanwriter.setData3f(self.material.tangent)
            bwriter.setData3f(self.material.binormal)

    def minimizeTextureShiftValues(self):
        if self.material.material is None:
            return

        # Keep the shift values to a minimum
        self.material.shift.x %= self.material.material.size.x
        self.material.shift.y %= self.material.material.size.y

        if self.material.shift.x < -self.material.material.size.x / 2:
            self.material.shift.x += self.material.material.size.x
        if self.material.shift.y < -self.material.material.size.y / 2:
            self.material.shift.y += self.material.material.size.y

    def classifyAgainstPlane(self, plane):
        front = back = onplane = 0
        count = len(self.vertices)

        for vert in self.vertices:
            test = plane.onPlane(vert.getWorldPos())
            if test <= 0:
                back += 1
            if test >= 0:
                front += 1
            if test == 0:
                onplane += 1

        if onplane == count:
            return PlaneClassification.OnPlane
        if front == count:
            return PlaneClassification.Front
        if back == count:
            return PlaneClassification.Back
        return PlaneClassification.Spanning

    def flip(self):
        self.vertices.reverse()
        self.plane = Plane.fromVertices(self.vertices[0].pos, self.vertices[1].pos, self.vertices[2].pos)
        if self.hasGeometry:
            self.regenerateGeometry()

    def regenerateGeometry(self):
        #
        # Generate vertex data
        #

        numVerts = len(self.vertices)

        vdata = GeomVertexData("SolidFace", getFaceFormat(), GeomEnums.UHStatic)
        vdata.uncleanSetNumRows(len(self.vertices))

        vwriter = GeomVertexWriter(vdata, InternalName.getVertex())
        twriter = GeomVertexWriter(vdata, InternalName.getTexcoord())
        nwriter = GeomVertexWriter(vdata, InternalName.getNormal())
        tanwriter = GeomVertexWriter(vdata, InternalName.getTangent())
        bwriter = GeomVertexWriter(vdata, InternalName.getBinormal())

        for i in range(len(self.vertices)):
            vert = self.vertices[i]
            vwriter.setData3f(vert.pos)
            twriter.setData2f(vert.uv)
            nwriter.setData3f(self.plane.getNormal())
            tanwriter.setData3f(self.material.tangent)
            bwriter.setData3f(self.material.binormal)

        #
        # Generate indices
        #

        # Triangles in 3D view
        prim3D = GeomTriangles(GeomEnums.UHStatic)
        prim3D.reserveNumVertices((numVerts - 2) * 3)
        for i in range(1, numVerts - 1):
            prim3D.addVertices(i + 1, i, 0)
            prim3D.closePrimitive()

        # Line loop in 2D view.. using line strips
        prim2D = GeomLinestrips(GeomEnums.UHStatic)
        prim2D.reserveNumVertices(numVerts + 1)
        for i in range(numVerts):
            prim2D.addVertex(i)
        # Close off the line strip with the first vertex.. creating a line loop
        prim2D.addVertex(0)
        prim2D.closePrimitive()

        #
        # Generate mesh objects
        #

        geom3D = SolidFaceGeom(vdata)
        geom3D.setDrawMask(VIEWPORT_3D_FULL)
        geom3D.setPlaneCulled(True)
        geom3D.setPlane(self.plane)
        geom3D.addPrimitive(prim3D)
        self.index3D = self.solid.addFaceGeom(geom3D, self.state3D)

        geom3DLines = SolidFaceGeom(vdata)
        geom3DLines.addPrimitive(prim2D)
        geom3DLines.setDrawMask(VIEWPORT_3D_MASK)
        geom3DLines.setDraw(False)
        self.index3DLines = self.solid.addFaceGeom(geom3DLines, self.state3DLines)

        geom2D = SolidFaceGeom(vdata)
        geom2D.addPrimitive(prim2D)
        geom2D.setDrawMask(VIEWPORT_2D_MASK)
        self.index2D = self.solid.addFaceGeom(geom2D, self.state2D)

        self.geom3D = geom3D
        self.geom3DLines = geom3DLines
        self.geom2D = geom2D

        self.vdata = vdata

        self.hasGeometry = True

    def delete(self):
        for vert in self.vertices:
            vert.delete()
        self.vertices = None
        self.id = None
        self.material.cleanup()
        self.material = None
        self.color = None
        self.index2D = None
        self.index3D = None
        self.index3DLines = None
        self.geom3D = None
        self.geom3DLines = None
        self.geom2D = None
        self.state3D = None
        self.state3DLines = None
        self.state2D = None
        self.solid = None
        self.isSelected = None
        self.plane = None
        self.vdata = None
        self.hasGeometry = None