Beispiel #1
0
    def reset(self):

        self._id_ranges = SparseArray.range(1, 2**24)
        self._ids_to_recover = SparseArray()
        self._ids_to_discard = SparseArray()
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color IDs reset.')
Beispiel #2
0
    def __init__(self):

        self._mgrs[self.get_managed_object_type()] = self

        self._id_ranges = SparseArray.range(1, 2**24)
        self._ids_to_recover = SparseArray()
        self._ids_to_discard = SparseArray()
        self._id_ranges_backup = None
Beispiel #3
0
    def discard_picking_color_ids(self, color_ids):
        """ Discard the given color IDs, so they can no longer be used. """

        s = SparseArray()
        [s.set_bit(i) for i in color_ids]

        if self._ids_to_discard & s:
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color IDs '
                f'already discarded!')

        self._ids_to_discard |= s
        Notifiers.reg.debug(
            f'****** {self.get_managed_object_type()} picking color IDs '
            f'to be discarded:\n{self._ids_to_discard}')
Beispiel #4
0
    def recover_picking_color_ids(self, color_ids):
        """ Recover the given color IDs, so they can be used again. """

        s = SparseArray()
        [s.set_bit(i) for i in color_ids]

        if self._ids_to_recover & s:
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color IDs '
                f'already recovered!')

        self._ids_to_recover |= s
        Notifiers.reg.debug(
            f'****** {self.get_managed_object_type()} picking color IDs '
            f'to be recovered:\n{self._ids_to_recover}')
Beispiel #5
0
def getNodeFromController(controller, controlled_prim):
    if type(controlled_prim) is collada.controller.BoundSkinPrimitive:
        ch = Character('simplechar')
        bundle = ch.getBundle(0)
        skeleton = PartGroup(bundle, '<skeleton>')

        character_joints = {}
        for (name, joint_matrix) in controller.joint_matrices.iteritems():
            joint_matrix.shape = (-1)
            character_joints[name] = CharacterJoint(ch, bundle, skeleton, name,
                                                    Mat4(*joint_matrix))

        tbtable = TransformBlendTable()

        for influence in controller.index:
            blend = TransformBlend()
            for (joint_index, weight_index) in influence:
                char_joint = character_joints[controller.getJoint(joint_index)]
                weight = controller.getWeight(weight_index)[0]
                blend.addTransform(JointVertexTransform(char_joint), weight)
            tbtable.addBlend(blend)

        array = GeomVertexArrayFormat()
        array.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32,
                        Geom.CPoint)
        array.addColumn(InternalName.make('normal'), 3, Geom.NTFloat32,
                        Geom.CPoint)
        array.addColumn(InternalName.make('texcoord'), 2, Geom.NTFloat32,
                        Geom.CTexcoord)
        blendarr = GeomVertexArrayFormat()
        blendarr.addColumn(InternalName.make('transform_blend'), 1,
                           Geom.NTUint16, Geom.CIndex)

        format = GeomVertexFormat()
        format.addArray(array)
        format.addArray(blendarr)
        aspec = GeomVertexAnimationSpec()
        aspec.setPanda()
        format.setAnimation(aspec)
        format = GeomVertexFormat.registerFormat(format)

        dataname = controller.id + '-' + controlled_prim.primitive.material.id
        vdata = GeomVertexData(dataname, format, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')
        texcoord = GeomVertexWriter(vdata, 'texcoord')
        transform = GeomVertexWriter(vdata, 'transform_blend')

        numtris = 0
        if type(controlled_prim.primitive) is collada.polylist.BoundPolylist:
            for poly in controlled_prim.primitive.polygons():
                for tri in poly.triangles():
                    for tri_pt in range(3):
                        vertex.addData3f(tri.vertices[tri_pt][0],
                                         tri.vertices[tri_pt][1],
                                         tri.vertices[tri_pt][2])
                        normal.addData3f(tri.normals[tri_pt][0],
                                         tri.normals[tri_pt][1],
                                         tri.normals[tri_pt][2])
                        if len(controlled_prim.primitive._texcoordset) > 0:
                            texcoord.addData2f(tri.texcoords[0][tri_pt][0],
                                               tri.texcoords[0][tri_pt][1])
                        transform.addData1i(tri.indices[tri_pt])
                    numtris += 1
        elif type(controlled_prim.primitive
                  ) is collada.triangleset.BoundTriangleSet:
            for tri in controlled_prim.primitive.triangles():
                for tri_pt in range(3):
                    vertex.addData3f(tri.vertices[tri_pt][0],
                                     tri.vertices[tri_pt][1],
                                     tri.vertices[tri_pt][2])
                    normal.addData3f(tri.normals[tri_pt][0],
                                     tri.normals[tri_pt][1],
                                     tri.normals[tri_pt][2])
                    if len(controlled_prim.primitive._texcoordset) > 0:
                        texcoord.addData2f(tri.texcoords[0][tri_pt][0],
                                           tri.texcoords[0][tri_pt][1])
                    transform.addData1i(tri.indices[tri_pt])
                numtris += 1

        tbtable.setRows(SparseArray.lowerOn(vdata.getNumRows()))

        gprim = GeomTriangles(Geom.UHStatic)
        for i in range(numtris):
            gprim.addVertices(i * 3, i * 3 + 1, i * 3 + 2)
            gprim.closePrimitive()

        pgeom = Geom(vdata)
        pgeom.addPrimitive(gprim)

        render_state = getStateFromMaterial(controlled_prim.primitive.material)
        control_node = GeomNode("ctrlnode")
        control_node.addGeom(pgeom, render_state)
        ch.addChild(control_node)

        bundle = AnimBundle('simplechar', 5.0, 2)
        skeleton = AnimGroup(bundle, '<skeleton>')
        root = AnimChannelMatrixXfmTable(skeleton, 'root')

        #hjoint = AnimChannelMatrixXfmTable(root, 'joint1')
        #table = [10, 11, 12, 13, 14, 15, 14, 13, 12, 11]
        #data = PTAFloat.emptyArray(len(table))
        #for i in range(len(table)):
        #    data.setElement(i, table[i])
        #hjoint.setTable(ord('i'), CPTAFloat(data))

        #vjoint = AnimChannelMatrixXfmTable(hjoint, 'joint2')
        #table = [10, 9, 8, 7, 6, 5, 6, 7, 8, 9]
        #data = PTAFloat.emptyArray(len(table))
        #for i in range(len(table)):
        #    data.setElement(i, table[i])
        #vjoint.setTable(ord('j'), CPTAFloat(data))

        wiggle = AnimBundleNode('wiggle', bundle)

        np = NodePath(ch)
        anim = NodePath(wiggle)
        a = Actor(np, {'simplechar': anim})
        a.loop('simplechar')
        return a
        #a.setPos(0, 0, 0)

    else:
        raise Exception("Error: unsupported controller type")
def test_bitarray_constructor_sparse():
    # Create a BitArray from a SparseArray.
    ba = BitArray(SparseArray.all_on())
    assert ba.is_all_on()

    ba = BitArray(SparseArray())
    assert ba.is_zero()

    sa = SparseArray()
    sa.set_range(3, 64)
    sa.set_range(0, 1)
    sa.clear_range(60, 2)
    ba = BitArray(sa)
    exp = 0b1111100111111111111111111111111111111111111111111111111111111111001
    assert ba.__getstate__() == exp

    sa.invert_in_place()
    ba = BitArray(sa)
    assert ba.__getstate__() == ~exp
Beispiel #7
0
class PickingColorIDManager:

    _mgrs = {}
    _id_range_backups_created = set()

    @classmethod
    def init(cls):

        Mgr.accept("reset_picking_col_id_ranges", cls.__reset_id_ranges)
        Mgr.accept("update_picking_col_id_ranges", cls.__update_id_ranges)
        Mgr.accept("create_id_range_backups", cls.__create_id_range_backups)
        Mgr.accept("restore_id_range_backups", cls.__restore_id_range_backups)
        Mgr.add_notification_handler("long_process_cancelled",
                                     "picking_col_mgr",
                                     cls.__restore_id_range_backups)

    @classmethod
    def __reset_id_ranges(cls, obj_types=None):

        types = cls._mgrs if obj_types is None else obj_types

        for obj_type in types:
            cls._mgrs[obj_type].reset()

    @classmethod
    def __update_id_ranges(cls, as_task=True):
        def task():

            for mgr in cls._mgrs.values():
                mgr.update_picking_color_id_ranges()

        if as_task:
            task_id = "update_picking_col_id_ranges"
            PendingTasks.add(task, task_id, "object")
        else:
            task()

    @classmethod
    def __create_id_range_backups(cls, obj_types=None):

        types = set(cls._mgrs) if obj_types is None else set(obj_types)
        types -= cls._id_range_backups_created

        if not types:
            return

        for obj_type in types:
            cls._mgrs[obj_type].create_id_ranges_backup()

        task = cls.__remove_id_range_backups
        task_id = "remove_id_range_backups"
        PendingTasks.add(task, task_id, "object", sort=100)
        cls._id_range_backups_created.update(types)

    @classmethod
    def __restore_id_range_backups(cls, info=""):

        if not cls._id_range_backups_created:
            return

        Notifiers.reg.info(f'Restoring ID ranges;\ninfo: {info}')

        for obj_type in cls._id_range_backups_created:
            cls._mgrs[obj_type].restore_id_ranges_backup()

        cls.__remove_id_range_backups()

    @classmethod
    def __remove_id_range_backups(cls):

        if not cls._id_range_backups_created:
            return

        for obj_type in cls._id_range_backups_created:
            cls._mgrs[obj_type].remove_id_ranges_backup()

        cls._id_range_backups_created.clear()

    def __init__(self):

        self._mgrs[self.get_managed_object_type()] = self

        self._id_ranges = SparseArray.range(1, 2**24)
        self._ids_to_recover = SparseArray()
        self._ids_to_discard = SparseArray()
        self._id_ranges_backup = None

    def reset(self):

        self._id_ranges = SparseArray.range(1, 2**24)
        self._ids_to_recover = SparseArray()
        self._ids_to_discard = SparseArray()
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color IDs reset.')

    def get_next_picking_color_id(self):

        if not self._id_ranges:
            # TODO: pop up a message notifying the user that no more objects
            # can be created
            return

        next_id = self._id_ranges.get_lowest_on_bit()
        self._id_ranges.clear_bit(next_id)

        return next_id

    def recover_picking_color_id(self, color_id):
        """ Recover the given color ID, so it can be used again """

        if self._ids_to_recover.get_bit(color_id):
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color ID '
                f'already recovered!')

        self._ids_to_recover.set_bit(color_id)

    def recover_picking_color_ids(self, color_ids):
        """ Recover the given color IDs, so they can be used again. """

        s = SparseArray()
        [s.set_bit(i) for i in color_ids]

        if self._ids_to_recover & s:
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color IDs '
                f'already recovered!')

        self._ids_to_recover |= s
        Notifiers.reg.debug(
            f'****** {self.get_managed_object_type()} picking color IDs '
            f'to be recovered:\n{self._ids_to_recover}')

    def discard_picking_color_id(self, color_id):
        """ Discard the given color ID, so it can no longer be used """

        if self._ids_to_discard.get_bit(color_id):
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color ID '
                f'already discarded!')

        self._ids_to_discard.set_bit(color_id)

    def discard_picking_color_ids(self, color_ids):
        """ Discard the given color IDs, so they can no longer be used. """

        s = SparseArray()
        [s.set_bit(i) for i in color_ids]

        if self._ids_to_discard & s:
            Notifiers.reg.warning(
                f'!!!!!! {self.get_managed_object_type()} picking color IDs '
                f'already discarded!')

        self._ids_to_discard |= s
        Notifiers.reg.debug(
            f'****** {self.get_managed_object_type()} picking color IDs '
            f'to be discarded:\n{self._ids_to_discard}')

    def update_picking_color_id_ranges(self):

        id_ranges = self._id_ranges
        ids_to_recover = self._ids_to_recover
        ids_to_discard = self._ids_to_discard

        if not (ids_to_recover or ids_to_discard):
            return

        Notifiers.reg.debug(
            f'++++++ Updating {self.get_managed_object_type()} '
            f'picking color IDs ranges, starting with:\n{id_ranges}')

        # remove the common IDs from both arrays
        if ids_to_recover.has_bits_in_common(ids_to_discard):
            ids_to_recover ^= ids_to_discard
            ids_to_discard &= ids_to_recover
            ids_to_recover &= ~ids_to_discard

        if ids_to_recover:
            Notifiers.reg.debug(
                f'++++++ Recovering {self.get_managed_object_type()} '
                f'picking color IDs:\n{ids_to_recover}')
            id_ranges |= ids_to_recover

        if ids_to_discard:
            Notifiers.reg.debug(
                f'++++++ Discarding {self.get_managed_object_type()} '
                f'picking color IDs:\n{ids_to_discard}')
            id_ranges &= ~ids_to_discard

        ids_to_recover.clear()
        ids_to_discard.clear()
        Notifiers.reg.debug(f'++++++ New {self.get_managed_object_type()} '
                            f'picking color ID ranges:\n{id_ranges}')

    def create_id_ranges_backup(self):

        self._id_ranges_backup = SparseArray(self._id_ranges)
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color IDs '
            f'backup created:\n{self._id_ranges_backup}')

    def restore_id_ranges_backup(self):

        self._id_ranges = self._id_ranges_backup
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color '
            f'IDs backup restored:\n{self._id_ranges}')

    def remove_id_ranges_backup(self):

        self._id_ranges_backup = None
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color IDs backup removed.'
        )
Beispiel #8
0
    def create_id_ranges_backup(self):

        self._id_ranges_backup = SparseArray(self._id_ranges)
        Notifiers.reg.debug(
            f'"{self.get_managed_object_type()}" picking color IDs '
            f'backup created:\n{self._id_ranges_backup}')
Beispiel #9
0
def getNodeFromController(controller, controlled_prim):
    if type(controlled_prim) is collada.controller.BoundSkinPrimitive:
        ch = Character('simplechar')
        bundle = ch.getBundle(0)
        skeleton = PartGroup(bundle, '<skeleton>')

        character_joints = {}
        for (name, joint_matrix) in controller.joint_matrices.iteritems():
            joint_matrix.shape = (-1)
            character_joints[name] = CharacterJoint(ch, bundle, skeleton, name, Mat4(*joint_matrix)) 
        
        tbtable = TransformBlendTable()
        
        for influence in controller.index:
            blend = TransformBlend()
            for (joint_index, weight_index) in influence:
                char_joint = character_joints[controller.getJoint(joint_index)]
                weight = controller.getWeight(weight_index)[0]
                blend.addTransform(JointVertexTransform(char_joint), weight)
            tbtable.addBlend(blend)
            
        array = GeomVertexArrayFormat()
        array.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32, Geom.CPoint)
        array.addColumn(InternalName.make('normal'), 3, Geom.NTFloat32, Geom.CPoint)
        array.addColumn(InternalName.make('texcoord'), 2, Geom.NTFloat32, Geom.CTexcoord)
        blendarr = GeomVertexArrayFormat()
        blendarr.addColumn(InternalName.make('transform_blend'), 1, Geom.NTUint16, Geom.CIndex)
        
        format = GeomVertexFormat()
        format.addArray(array)
        format.addArray(blendarr)
        aspec = GeomVertexAnimationSpec()
        aspec.setPanda()
        format.setAnimation(aspec)
        format = GeomVertexFormat.registerFormat(format)
        
        dataname = controller.id + '-' + controlled_prim.primitive.material.id
        vdata = GeomVertexData(dataname, format, Geom.UHStatic)
        vertex = GeomVertexWriter(vdata, 'vertex')
        normal = GeomVertexWriter(vdata, 'normal')
        texcoord = GeomVertexWriter(vdata, 'texcoord')
        transform = GeomVertexWriter(vdata, 'transform_blend') 
        
        numtris = 0
        if type(controlled_prim.primitive) is collada.polylist.BoundPolylist:
            for poly in controlled_prim.primitive.polygons():
                for tri in poly.triangles():
                    for tri_pt in range(3):
                        vertex.addData3f(tri.vertices[tri_pt][0], tri.vertices[tri_pt][1], tri.vertices[tri_pt][2])
                        normal.addData3f(tri.normals[tri_pt][0], tri.normals[tri_pt][1], tri.normals[tri_pt][2])
                        if len(controlled_prim.primitive._texcoordset) > 0:
                            texcoord.addData2f(tri.texcoords[0][tri_pt][0], tri.texcoords[0][tri_pt][1])
                        transform.addData1i(tri.indices[tri_pt])
                    numtris+=1
        elif type(controlled_prim.primitive) is collada.triangleset.BoundTriangleSet:
            for tri in controlled_prim.primitive.triangles():
                for tri_pt in range(3):
                    vertex.addData3f(tri.vertices[tri_pt][0], tri.vertices[tri_pt][1], tri.vertices[tri_pt][2])
                    normal.addData3f(tri.normals[tri_pt][0], tri.normals[tri_pt][1], tri.normals[tri_pt][2])
                    if len(controlled_prim.primitive._texcoordset) > 0:
                        texcoord.addData2f(tri.texcoords[0][tri_pt][0], tri.texcoords[0][tri_pt][1])
                    transform.addData1i(tri.indices[tri_pt])
                numtris+=1
                    
        tbtable.setRows(SparseArray.lowerOn(vdata.getNumRows())) 
        
        gprim = GeomTriangles(Geom.UHStatic)
        for i in range(numtris):
            gprim.addVertices(i*3, i*3+1, i*3+2)
            gprim.closePrimitive()
            
        pgeom = Geom(vdata)
        pgeom.addPrimitive(gprim)
        
        render_state = getStateFromMaterial(controlled_prim.primitive.material)
        control_node = GeomNode("ctrlnode")
        control_node.addGeom(pgeom, render_state)
        ch.addChild(control_node)
    
        bundle = AnimBundle('simplechar', 5.0, 2)
        skeleton = AnimGroup(bundle, '<skeleton>')
        root = AnimChannelMatrixXfmTable(skeleton, 'root')
        
        #hjoint = AnimChannelMatrixXfmTable(root, 'joint1') 
        #table = [10, 11, 12, 13, 14, 15, 14, 13, 12, 11] 
        #data = PTAFloat.emptyArray(len(table)) 
        #for i in range(len(table)): 
        #    data.setElement(i, table[i]) 
        #hjoint.setTable(ord('i'), CPTAFloat(data)) 
        
        #vjoint = AnimChannelMatrixXfmTable(hjoint, 'joint2') 
        #table = [10, 9, 8, 7, 6, 5, 6, 7, 8, 9] 
        #data = PTAFloat.emptyArray(len(table)) 
        #for i in range(len(table)): 
        #    data.setElement(i, table[i]) 
        #vjoint.setTable(ord('j'), CPTAFloat(data)) 

        wiggle = AnimBundleNode('wiggle', bundle)

        np = NodePath(ch) 
        anim = NodePath(wiggle) 
        a = Actor(np, {'simplechar' : anim})
        a.loop('simplechar') 
        return a
        #a.setPos(0, 0, 0)
    
    else:
        raise Exception("Error: unsupported controller type")