Пример #1
0
    def fireLaser(self):
        result = PhysicsUtils.rayTestClosestNotMe(
            self, self.laserVec[0], self.laserVec[1],
            CIGlobals.WorldGroup | CIGlobals.CharacterGroup,
            self.getBattleZone().getPhysicsWorld())
        traceEnd = self.laserVec[1]
        if result:
            traceEnd = result.getHitPos()
            hitNode = NodePath(result.getNode())

            avNP = hitNode.getParent()

            for obj in base.air.avatars[self.getBattleZone().zoneId]:
                if (CIGlobals.isAvatar(obj) and obj.getKey() == avNP.getKey()
                        and self.getBattleZone().getGameRules().canDamage(
                            self, obj, None)):

                    dmgInfo = TakeDamageInfo(self, -1, 10, traceEnd,
                                             self.laserVec[0])

                    obj.takeDamage(dmgInfo)

                    break

        self.getBattleZone().getTempEnts().makeLaser(self.laserVec[0],
                                                     traceEnd,
                                                     Vec4(1, 0, 0, 1), 1.0)
Пример #2
0
 def getSelectionCenter(self):
     if not self.selection:
         return Point3()
     else:
         min, max = Point3(), Point3()
         tmpmin, tmpmax = Point3(), Point3()
         np = NodePath(self.selection[0])
         np.calcTightBounds(min, max)
         min += np.getPos(render) - np.getPos()
         max += np.getPos(render) - np.getPos()
         for i in xrange(1, len(self.selection)):
             np = NodePath(self.selection[i])
             np.calcTightBounds(tmpmin, tmpmax)
             if np.getParent() != render:
                 tmpmin += np.getPos(render) - np.getPos()
                 tmpmax += np.getPos(render) - np.getPos()
             min = min.fmin(tmpmin)
             max = max.fmax(tmpmax)
         return Point3(min + (max - min) / 2)
Пример #3
0
 def getSelectionCenter(self):
     if not self.selection:
         return Point3()
     else:
         min, max = Point3(), Point3()
         tmpmin, tmpmax = Point3(), Point3()
         np = NodePath(self.selection[0])
         np.calcTightBounds(min, max)
         min += np.getPos(render) - np.getPos()
         max += np.getPos(render) - np.getPos()
         for i in xrange(1, len(self.selection)):
             np = NodePath(self.selection[i])
             np.calcTightBounds(tmpmin, tmpmax)
             if np.getParent() != render:
                 tmpmin += np.getPos(render) - np.getPos()
                 tmpmax += np.getPos(render) - np.getPos()
             min = min.fmin(tmpmin)
             max = max.fmax(tmpmax)
         return Point3(min + (max - min)/2)
Пример #4
0
class Transform(Component):
    """Each game object has exactly one of these. A transform holds data
    about position, rotation, scale and parent relationship.
    
    In Panity this is a wrapper for a NodePath.
    """
    def __init__(self, game_object, name):
        # Component class sets self.game_object = game_object
        Component.__init__(self, game_object)
        self.node = NodePath(name)
        self.node.setPythonTag("transform", self)

    @classmethod
    def getClassSerializedProperties(cls):
        """Return all special property attributes in a dict. Only attributes
        derived from SerializedProperty are respected.

        On transform component this method always returns local position,
        -rotation and scale only.
        """
        d = {}
        d["local_position"] = Transform.local_position
        d["local_euler_angles"] = Transform.local_euler_angles
        d["local_scale"] = Transform.local_scale
        return d

    def getSerializedProperties(self):
        """Return all properties for serialization. In the case of transform
        this only returns local position, -rotation and -scale, which are
        required to restore the state of the node.
        """
        d = {}
        d["local_position"] = self.local_position
        d["local_euler_angles"] = self.local_euler_angles
        d["local_scale"] = self.local_scale
        return d

    # We use the panda node to save the name on it for better debugging and
    # efficient finding of nodes with NodePath().find()
    @SerializedPropertyDecorator
    def name(self):
        return self.node.getName()

    @name.setter
    def name(self, name):
        if name == "render":
            name = "_render"
        self.node.setName(name)

    @SerializedPropertyDecorator
    def position(self):
        return self.node.getPos(self.root.node)

    @position.setter
    def position(self, position):
        self.node.setPos(self.root.node, *position)

    @SerializedPropertyDecorator
    def local_position(self):
        return self.node.getPos()

    @local_position.setter
    def local_position(self, position):
        self.node.setPos(*position)

    @SerializedPropertyDecorator
    def euler_angles(self):
        return self.node.getHpr(self.root.node)

    @euler_angles.setter
    def euler_angles(self, angles):
        self.node.setHpr(self.root.node, *angles)

    @SerializedPropertyDecorator
    def local_euler_angles(self):
        return self.node.getHpr()

    @local_euler_angles.setter
    def local_euler_angles(self, angles):
        self.node.setHpr(*angles)

    @SerializedPropertyDecorator
    def rotation(self):
        return self.node.getQuat(self.root.node)

    @rotation.setter
    def rotation(self, quaternion):
        self.node.setQuat(self.root.node, *quaternion)

    @SerializedPropertyDecorator
    def local_rotation(self):
        return self.node.getQuat()

    @local_rotation.setter
    def local_rotation(self, quaternion):
        self.node.setQuat(*quaternion)

    @SerializedPropertyDecorator
    def local_scale(self):
        return self.node.getScale()

    @local_scale.setter
    def local_scale(self, scale):
        self.node.setScale(*scale)

    @SerializedPropertyDecorator
    def parent(self):
        p = self.node.getParent()
        if p.isEmpty() or p.getName() == "render":
            return self
        elif p.hasPythonTag("transform"):
            return p.getPythonTag("transform")

    @parent.setter
    def parent(self, parent):
        self.node.wrtReparentTo(parent.node)

    @SerializedPropertyDecorator
    def root(self):
        if self.parent is not self:
            return self.parent.root()
        else:
            return self

    def destroy(self):
        """Ultimately remove this transform. Warning: this might cause errors
        for other components on this game object. Use this only when removing
        the whole GameObject.
        """
        self.node.removeNode()

    def getChildren(self):
        """Return children as Transforms."""
        # this requires the __iter__() method
        return [c for c in self]

    def __iter__(self):
        """Iterate over children nodes and yield the transform instances."""
        for child in self.node.getChildren():
            if child.hasPythonTag("transform"):
                yield child.getPythonTag("transform")

    def __str__(self):
        r = "Transform for '{}'\n".format(self.name)
        r += "local position: {}\n".format(self.local_position)
        r += "local rotation: {}\n".format(self.local_euler_angles)
        r += "local scale:    {}\n".format(self.local_scale)
        return r
Пример #5
0
class Transform(Component):
    """Each game object has exactly one of these. A transform holds data
    about position, rotation, scale and parent relationship.
    
    In Panity this is a wrapper for a NodePath.
    """

    def __init__(self, game_object, name):
        # Component class sets self.game_object = game_object
        Component.__init__(self, game_object)
        self.node = NodePath(name)
        self.node.setPythonTag("transform", self)

    @classmethod
    def getClassSerializedProperties(cls):
        """Return all special property attributes in a dict. Only attributes
        derived from SerializedProperty are respected.

        On transform component this method always returns local position,
        -rotation and scale only.
        """
        d = {}
        d["local_position"] = Transform.local_position
        d["local_euler_angles"] = Transform.local_euler_angles
        d["local_scale"] = Transform.local_scale
        return d

    def getSerializedProperties(self):
        """Return all properties for serialization. In the case of transform
        this only returns local position, -rotation and -scale, which are
        required to restore the state of the node.
        """
        d = {}
        d["local_position"] = self.local_position
        d["local_euler_angles"] = self.local_euler_angles
        d["local_scale"] = self.local_scale
        return d

    # We use the panda node to save the name on it for better debugging and
    # efficient finding of nodes with NodePath().find()
    @SerializedPropertyDecorator
    def name(self):
        return self.node.getName()
    @name.setter
    def name(self, name):
        if name == "render":
            name = "_render"
        self.node.setName(name)

    @SerializedPropertyDecorator
    def position(self):
        return self.node.getPos(self.root.node)
    @position.setter
    def position(self, position):
        self.node.setPos(self.root.node, *position)
    
    @SerializedPropertyDecorator
    def local_position(self):
        return self.node.getPos()
    @local_position.setter
    def local_position(self, position):
        self.node.setPos(*position)

    @SerializedPropertyDecorator
    def euler_angles(self):
        return self.node.getHpr(self.root.node)
    @euler_angles.setter
    def euler_angles(self, angles):
        self.node.setHpr(self.root.node, *angles)
    
    @SerializedPropertyDecorator
    def local_euler_angles(self):
        return self.node.getHpr()
    @local_euler_angles.setter
    def local_euler_angles(self, angles):
        self.node.setHpr(*angles)
    
    @SerializedPropertyDecorator
    def rotation(self):
        return self.node.getQuat(self.root.node)
    @rotation.setter
    def rotation(self, quaternion):
        self.node.setQuat(self.root.node, *quaternion)

    @SerializedPropertyDecorator
    def local_rotation(self):
        return self.node.getQuat()
    @local_rotation.setter
    def local_rotation(self, quaternion):
        self.node.setQuat(*quaternion)

    @SerializedPropertyDecorator
    def local_scale(self):
        return self.node.getScale()
    @local_scale.setter
    def local_scale(self, scale):
        self.node.setScale(*scale)

    @SerializedPropertyDecorator
    def parent(self):
        p = self.node.getParent()
        if p.isEmpty() or p.getName() == "render":
            return self
        elif p.hasPythonTag("transform"):
            return p.getPythonTag("transform")
    @parent.setter
    def parent(self, parent):
        self.node.wrtReparentTo(parent.node)

    @SerializedPropertyDecorator
    def root(self):
        if self.parent is not self:
            return self.parent.root()
        else:
            return self
    
    def destroy(self):
        """Ultimately remove this transform. Warning: this might cause errors
        for other components on this game object. Use this only when removing
        the whole GameObject.
        """
        self.node.removeNode()

    def getChildren(self):
        """Return children as Transforms."""
        # this requires the __iter__() method
        return [c for c in self]

    def __iter__(self):
        """Iterate over children nodes and yield the transform instances."""
        for child in self.node.getChildren():
            if child.hasPythonTag("transform"):
                yield child.getPythonTag("transform")
    
    def __str__(self):
        r = "Transform for '{}'\n".format(self.name)
        r += "local position: {}\n".format(self.local_position)
        r += "local rotation: {}\n".format(self.local_euler_angles)
        r += "local scale:    {}\n".format(self.local_scale)
        return r
Пример #6
0
class MapObject(MapWritable):

    ObjectName = "object"

    def __init__(self, id):
        MapObjectInit.start()

        MapWritable.__init__(self, base.document)
        self.temporary = False
        self.id = id
        self.selected = False
        self.classname = ""
        self.parent = None
        self.children = {}
        self.boundingBox = BoundingBox(Vec3(-0.5, -0.5, -0.5), Vec3(0.5, 0.5, 0.5))
        self.boundsBox = Box()
        self.boundsBox.addView(GeomView.Lines, VIEWPORT_3D_MASK, state = BoundsBox3DState)
        self.boundsBox.addView(GeomView.Lines, VIEWPORT_2D_MASK, state = BoundsBox2DState)
        self.boundsBox.generateGeometry()
        self.collNp = None

        self.group = None

        self.properties = {}

        # All MapObjects have transform
        self.addProperty(OriginProperty(self))
        self.addProperty(AnglesProperty(self))
        self.addProperty(ScaleProperty(self))
        self.addProperty(ShearProperty(self))

        self.np = NodePath(ModelNode(self.ObjectName + ".%i" % self.id))
        self.np.setPythonTag("mapobject", self)
        self.applyCollideMask()
        # Test bounding volume at this node and but nothing below it.
        self.np.node().setFinal(True)

        MapObjectInit.stop()

    def getClassName(self):
        return self.classname

    def isWorld(self):
        return False

    def r_findAllParents(self, parents, type):
        if not self.parent or self.parent.isWorld():
            return

        if type is None or isinstance(self.parent, type):
            parents.append(self.parent)

        self.parent.r_findAllParents(parents, type)

    def findAllParents(self, type = None):
        parents = []
        self.r_findAllParents(parents, type)
        return parents

    def findTopmostParent(self, type = None):
        parents = self.findAllParents(type)
        if len(parents) == 0:
            return None

        return parents[len(parents) - 1]

    def r_findAllChildren(self, children, type):
        for child in self.children.values():
            if type is None or isinstance(child, type):
                children.append(child)
            child.r_findAllChildren(children, type)

    def findAllChildren(self, type = None):
        children = []

        self.r_findAllChildren(children, type)

        return children

    def applyCollideMask(self):
        self.np.setCollideMask(LEGlobals.ObjectMask)

    def setTemporary(self, flag):
        self.temporary = flag

    # Returns the bounding volume of the object itself, not including children objects.
    def getObjBounds(self, other = None):
        if not other:
            other = self.np.getParent()
        return self.np.getTightBounds(other)

    # Returns the min and max points of the bounds of the object, not including children.
    def getBounds(self, other = None):
        if not other:
            other = self.np.getParent()
        mins = Point3()
        maxs = Point3()
        self.np.calcTightBounds(mins, maxs, other)
        return [mins, maxs]

    def findChildByID(self, id):
        if id == self.id:
            return self

        if id in self.children:
            return self.children[id]

        for child in self.children.values():
            ret = child.findChildByID(id)
            if ret is not None:
                return ret

        return None

    def hasChildWithID(self, id):
        return id in self.children

    def copy(self, generator):
        raise NotImplementedError

    def paste(self, o, generator):
        raise NotImplementedError

    def clone(self):
        raise NotImplementedError

    def unclone(self, o):
        raise NotImplementedError

    #
    # Base copy and paste functions shared by all MapObjects.
    # Each specific MapObject must implement the functions above for their
    # specific functionality.
    #

    def copyProperties(self, props):
        newProps = {}
        for key, prop in props.items():
            newProp = prop.clone(self)
            newProp.setValue(prop.getValue())
            newProps[key] = newProp
        self.updateProperties(newProps)

    def copyBase(self, other, generator, clone = False):
        if clone and other.id != self.id:
            parent = other.parent
            setPar = other.parent is not None and other.parent.hasChildWithID(other.id) and other.parent.children[other.id] == other
            if setPar:
                other.reparentTo(NodePath())
            other.id = self.id
            if setPar:
                other.reparentTo(parent)

        other.parent = self.parent

        for child in self.children.values():
            if clone:
                newChild = child.clone()
            else:
                newChild = child.copy(generator)
            newChild.reparentTo(other)

        other.setClassname(self.classname)
        other.copyProperties(self.properties)
        other.selected = self.selected

    def pasteBase(self, o, generator, performUnclone = False):
        if performUnclone and o.id != self.id:
            parent = self.parent
            setPar = self.parent is not None and self.parent.hasChildWithID(self.id) and self.parent.children[self.id] == self
            if setPar:
                self.reparentTo(NodePath())
            self.id = o.id
            if setPar:
                self.reparentTo(parent)

        for child in o.children.values():
            if performUnclone:
                newChild = child.clone()
            else:
                newChild = child.copy(generator)
            newChild.reparentTo(self)

        self.setClassname(o.classname)
        self.copyProperties(o.properties)
        self.selected = o.selected

    def getName(self):
        return "Object"

    def getDescription(self):
        return "Object in a map."

    def addProperty(self, prop):
        self.properties[prop.name] = prop

    # Returns list of property names with the specified value types.
    def getPropsWithValueType(self, types):
        if isinstance(types, str):
            types = [types]
        props = []
        for propName, prop in self.properties.items():
            if prop.valueType in types:
                props.append(propName)
        return props

    def getPropNativeType(self, key):
        prop = self.properties.get(key, None)
        if not prop:
            return str

        return prop.getNativeType()

    def getPropValueType(self, key):
        prop = self.properties.get(key, None)
        if not prop:
            return "string"

        return prop.valueType

    def getPropDefaultValue(self, prop):
        if isinstance(prop, str):
            prop = self.properties.get(prop, None)

        if not prop:
            return ""

        return prop.defaultValue

    def getPropertyValue(self, key, asString = False, default = ""):
        prop = self.properties.get(key, None)
        if not prop:
            return default

        if asString:
            return prop.getSerializedValue()
        else:
            return prop.getValue()

    def getProperty(self, name):
        return self.properties.get(name, None)

    def updateProperties(self, data):
        for key, value in data.items():
            if not isinstance(value, ObjectProperty):
                # If only a value was specified and not a property object itself,
                # this is an update to an existing property.

                prop = self.properties.get(key, None)
                if not prop:
                    continue

                oldValue = prop.getValue()

                val = prop.getUnserializedValue(value)

                # If the property has a min/max range, ensure the value we want to
                # set is within that range.
                if (not prop.testMinValue(val)) or (not prop.testMaxValue(val)):
                    # Not within range. Use the default value
                    val = prop.defaultValue

                prop.setValue(val)
            else:
                # A property object was given, simply add it to the dict of properties.
                prop = value
                oldValue = None
                val = prop.getValue()
                self.properties[prop.name] = prop

            self.propertyChanged(prop, oldValue, val)

    def propertyChanged(self, prop, oldValue, newValue):
        if oldValue != newValue:
            self.send('objectPropertyChanged', [self, prop, newValue])

    def setAbsOrigin(self, origin):
        self.np.setPos(base.render, origin)
        self.transformChanged()

    def setOrigin(self, origin):
        self.np.setPos(origin)
        self.transformChanged()

    def getAbsOrigin(self):
        return self.np.getPos(base.render)

    def getOrigin(self):
        return self.np.getPos()

    def setAngles(self, angles):
        self.np.setHpr(angles)
        self.transformChanged()

    def setAbsAngles(self, angles):
        self.np.setHpr(base.render, angles)
        self.transformChanged()

    def getAbsAngles(self):
        return self.np.getHpr(base.render)

    def getAngles(self):
        return self.np.getHpr()

    def setScale(self, scale):
        self.np.setScale(scale)
        self.transformChanged()

    def setAbsScale(self, scale):
        self.np.setScale(base.render, scale)
        self.transformChanged()

    def getAbsScale(self):
        return self.np.getScale(base.render)

    def getScale(self):
        return self.np.getScale()

    def setShear(self, shear):
        self.np.setShear(shear)
        self.transformChanged()

    def setAbsShear(self, shear):
        self.np.setShear(base.render, shear)
        self.transformChanged()

    def getAbsShear(self):
        return self.np.getShear(base.render)

    def getShear(self):
        return self.np.getShear()

    def transformChanged(self):
        self.recalcBoundingBox()
        self.send('objectTransformChanged', [self])

    def showBoundingBox(self):
        self.boundsBox.np.reparentTo(self.np)

    def hideBoundingBox(self):
        self.boundsBox.np.reparentTo(NodePath())

    def select(self):
        self.selected = True
        self.showBoundingBox()
        #self.np.setColorScale(1, 0, 0, 1)

    def deselect(self):
        self.selected = False
        self.hideBoundingBox()
        #self.np.setColorScale(1, 1, 1, 1)

    def setClassname(self, classname):
        self.classname = classname

    def fixBounds(self, mins, maxs):
        # Ensures that the bounds are not flat on any axis
        sameX = mins.x == maxs.x
        sameY = mins.y == maxs.y
        sameZ = mins.z == maxs.z

        invalid = False

        if sameX:
            # Flat horizontal
            if sameY and sameZ:
                invalid = True
            elif not sameY:
                mins.x = mins.y
                maxs.x = maxs.y
            elif not sameZ:
                mins.x = mins.z
                maxs.x = maxs.z

        if sameY:
            # Flat forward/back
            if sameX and sameZ:
                invalid = True
            elif not sameX:
                mins.y = mins.x
                maxs.y = maxs.x
            elif not sameZ:
                mins.y = mins.z
                maxs.y = maxs.z

        if sameZ:
            if sameX and sameY:
                invalid = True
            elif not sameX:
                mins.z = mins.x
                maxs.z = maxs.x
            elif not sameY:
                mins.z = mins.y
                maxs.z = maxs.y

        return [invalid, mins, maxs]

    def recalcBoundingBox(self):
        if not self.np:
            return

        # Don't have the picker box or selection visualization contribute to the
        # calculation of the bounding box.
        if self.collNp:
            self.collNp.stash()
        self.hideBoundingBox()

        # Calculate a bounding box relative to ourself
        mins, maxs = self.getBounds(self.np)

        invalid, mins, maxs = self.fixBounds(mins, maxs)
        if invalid:
            mins = Point3(-8)
            maxs = Point3(8)

        self.boundingBox = BoundingBox(mins, maxs)
        self.boundsBox.setMinMax(mins, maxs)
        if self.selected:
            self.showBoundingBox()

        if self.collNp:
            self.collNp.unstash()
            self.collNp.node().clearSolids()
            self.collNp.node().addSolid(CollisionBox(mins, maxs))
            self.collNp.hide(~VIEWPORT_3D_MASK)

        self.send('mapObjectBoundsChanged', [self])

    def removePickBox(self):
        if self.collNp:
            self.collNp.removeNode()
            self.collNp = None

    def delete(self):
        if not self.temporary:
            # Take the children with us
            for child in list(self.children.values()):
                child.delete()
            self.children = None
            # if we are selected, deselect
            base.selectionMgr.deselect(self)

        if self.boundsBox:
            self.boundsBox.cleanup()
            self.boundsBox = None

        self.removePickBox()

        if not self.temporary:
            self.reparentTo(NodePath())
        self.np.removeNode()
        self.np = None
        self.properties = None
        self.metaData = None

        self.temporary = None

    def __clearParent(self):
        if self.parent:
            self.parent.__removeChild(self)
            self.np.reparentTo(NodePath())
            self.parent = None

    def __setParent(self, other):
        if isinstance(other, NodePath):
            # We are reparenting directly to a NodePath, outside of the MapObject tree.
            self.parent = None
            self.np.reparentTo(other)
        else:
            self.parent = other
            if self.parent:
                self.parent.__addChild(self)
                self.np.reparentTo(self.parent.np)
            else:
                # If None was passed, assume base.render
                self.np.reparentTo(base.render)

    def reparentTo(self, other):
        # If a NodePath is passed to this method, the object will be placed under the specified node
        # in the Panda3D scene graph, but will be taken out of the MapObject tree. If None is passed,
        # the object will be parented to base.render and taken out of the MapObject tree.
        #
        # Use reparentTo(NodePath()) to place the object outside of both the scene graph and the
        # MapObject tree.
        self.__clearParent()
        self.__setParent(other)

    def __addChild(self, child):
        self.children[child.id] = child
        #self.recalcBoundingBox()

    def __removeChild(self, child):
        if child.id in self.children:
            del self.children[child.id]
            #self.recalcBoundingBox()

    def doWriteKeyValues(self, parent):
        kv = CKeyValues(self.ObjectName, parent)
        self.writeKeyValues(kv)
        for child in self.children.values():
            child.doWriteKeyValues(kv)

    def writeKeyValues(self, keyvalues):
        keyvalues.setKeyValue("id", str(self.id))
        # Write out our object properties
        for name, prop in self.properties.items():
            prop.writeKeyValues(keyvalues)

    def readKeyValues(self, keyvalues):
        for i in range(keyvalues.getNumKeys()):
            key = keyvalues.getKey(i)
            value = keyvalues.getValue(i)
            if MetaData.isPropertyExcluded(key):
                continue
            # Find the property with this name.
            prop = self.properties.get(key, None)
            if not prop:
                # Prop wasn't explicit or part of FGD metadata (if it's an Entity)
                continue

            nativeValue = prop.getUnserializedValue(value)

            # Set the value!
            self.updateProperties({prop.name: nativeValue})
Пример #7
0
class TQGraphicsNodePath:
    """ Anything that fundamentally is a only a graphics object in this engine should have these properties.

    Kwargs:
        TQGraphicsNodePath_creation_parent_node : this is assigned in the constructor, and after makeObject and the return of
        the p3d Nodepath, each TQGraphicsNodePath object has to call set_p3d_node """

    def __init__(self, **kwargs):
        """ """
        self.TQGraphicsNodePath_creation_parent_node = None
        self.p3d_nodepath = NodePath("empty")
        self.p3d_nodepath_changed_post_init_p = False
        self.p3d_parent_nodepath = NodePath("empty")

        self.node_p3d = None

        self.p3d_nodepath.reparentTo(self.p3d_parent_nodepath)

        self.apply_kwargs(**kwargs)

    def apply_kwargs(self, **kwargs):
        """ """
        if 'color' in kwargs:
            TQGraphicsNodePath.setColor(self, kwargs.get('color'))
        else:
            TQGraphicsNodePath.setColor(self, Vec4(1., 1., 1., 1.))

    def attach_to_render(self):
        """ """
        # assert self.p3d_nodepath
        # self.p3d_nodepath.reparentTo(render)
        assert self.p3d_nodepath
        self.reparentTo(engine.tq_graphics_basics.tq_render)

    def attach_to_aspect2d(self):
        """ """
        # assert self.p3d_nodepath
        # self.p3d_nodepath.reparentTo(aspect2d)
        assert self.p3d_nodepath
        self.reparentTo(engine.tq_graphics_basics.tq_aspect2d)

    def _set_p3d_nodepath_plain_post_init(p3d_nodepath):
        """ """
        self.p3d_nodepath = p3d_nodepath
        self.p3d_nodepath_changed_post_init_p = True

    @staticmethod
    def from_p3d_nodepath(p3d_nodepath, **tq_graphics_nodepath_kwargs):
        """ factory """
        go = TQGraphicsNodePath(**tq_graphics_nodepath_kwargs)
        go.set_p3d_nodepath(p3d_nodepath)
        return go

    def set_parent_node_for_nodepath_creation(
            self, TQGraphicsNodePath_creation_parent_node):
        """ when calling attachNewNode_p3d, a new node pat is generated.
        E.g.: To attach a line to render (3d world) is different than attaching
        it to aspect2d (2d GUI plane), since the aspect2d children are not directly
        affected by camera movements
        Args:
        - TQGraphicsNodePath_creation_parent_node : the NodePath to attach the TQGraphicsNodePath to
                                          (e.g. render or aspect2d in p3d)
        """

        # self.set_parent_node_for_nodepath_creation(self.TQGraphicsNodePath_creation_parent_node)
        self.TQGraphicsNodePath_creation_parent_node = TQGraphicsNodePath_creation_parent_node

    def set_p3d_nodepath(self, p3d_nodepath, remove_old_nodepath=True):
        """ """
        self.p3d_nodepath = p3d_nodepath

    def get_p3d_nodepath(self):
        """ """
        return self.p3d_nodepath

    def set_render_above_all(self, p):
        """ set render order to be such that it renders normally (false), or above all (true)
        Args:
            p: True or False to enable or disable the 'above all' rendering mode """

        try:
            if p == True:
                self.p3d_nodepath.setBin("fixed", 0)
                self.p3d_nodepath.setDepthTest(False)
                self.p3d_nodepath.setDepthWrite(False)
            else:
                self.p3d_nodepath.setBin("default", 0)
                self.p3d_nodepath.setDepthTest(True)
                self.p3d_nodepath.setDepthWrite(True)
        except NameError:       # if p3d_nodepath is not yet defined
            print("NameError in set_render_above_all()")

    def remove(self):
        """ """
        self.p3d_nodepath.removeNode()

    def setPos(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setPos(*args, **kwargs)

    def getPos(self):
        """ """
        return self.p3d_nodepath.getPos()

    def setScale(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setScale(*args, **kwargs)

    def getScale(self):
        """ """
        return self.p3d_nodepath.getScale()

    def setMat(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setMat(*args, **kwargs)

    def setMat_normal(self, mat4x4_normal_np):
        """ normal convention (numpy array), i.e. convert to forrowvecs convention for p3d setMat call """
        return self.p3d_nodepath.setMat(math_utils.to_forrowvecs(mat4x4_normal_np))


    def getMat(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.getMat(*args, **kwargs)

    def getMat_normal(self, *args, **kwargs):
        """ """
        return math_utils.from_forrowvecs(self.p3d_nodepath.getMat(*args, **kwargs))

    def setTexture(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setTexture(*args, **kwargs)

    def setColor(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setColor(*args, **kwargs)

    def setTwoSided(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setTwoSided(*args, **kwargs)

    def setRenderModeWireframe(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setRenderModeWireframe(*args, **kwargs)

    def reparentTo(self, *args, **kwargs):
        """ """
        new_args = list(args)
        new_args[0] = new_args[0].p3d_nodepath
        return self.p3d_nodepath.reparentTo(*new_args, **kwargs)

    def reparentTo_p3d(self, *args, **kwargs):
        """ input a p3d nodepath directly """
        # new_args = list(args)
        # new_args[0] = new_args[0].p3d_nodepath
        return self.p3d_nodepath.reparentTo(*args, **kwargs)

    def get_node_p3d(self):
        """ """
        # return self.p3d_nodepath.node()
        return self.node_p3d

    def set_node_p3d(self, node_p3d):
        """ not available in p3d NodePath class """
        self.node_p3d = node_p3d

    def setRenderModeFilled(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setRenderModeFilled(*args, **kwargs)

    def setLightOff(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setLightOff(*args, **kwargs)

    def show(self):
        """ """
        return self.p3d_nodepath.show()

    def hide(self):
        """ """
        return self.p3d_nodepath.hide()

    def setRenderModeThickness(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setRenderModeThickness(*args, **kwargs)

    def removeNode(self):
        """ """
        return self.p3d_nodepath.removeNode()

    def setHpr(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setHpr(*args, **kwargs)

    def showBounds(self):
        """ """
        return self.p3d_nodepath.showBounds()

    def setCollideMask(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setCollideMask(*args, **kwargs)

    def getParent_p3d(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.getParent(*args, **kwargs)

    def wrtReparentTo(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.wrtReparentTo(*args, **kwargs)

    def setBin(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setBin(*args, **kwargs)

    def setDepthTest(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setDepthTest(*args, **kwargs)

    def setDepthWrite(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setDepthWrite(*args, **kwargs)

    def get_children_p3d(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.get_children(*args, **kwargs)

    def attachNewNode_p3d(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.attachNewNode(*args, **kwargs)

    def lookAt(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.lookAt(*args, **kwargs)

    def setLight(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setLight(*args, **kwargs)

    def setAntialias(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setAntialias(*args, **kwargs)

    def getRelativeVector(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.getRelativeVector(*args, **kwargs)

    def setTransparency(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setTransparency(*args, **kwargs)

    def getHpr(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.getHpr(*args, **kwargs)

    def setHpr(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.setHpr(*args, **kwargs)

    def getTightBounds(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.getTightBounds(*args, **kwargs)

    def showTightBounds(self, *args, **kwargs):
        """ """
        return self.p3d_nodepath.showTightBounds(*args, **kwargs)