Thu, Mar 28, 3:38 PM CDT

Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Mar 19 1:03 pm)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: Is there a way to support Undo with LoadLibraryPose


yarp ( ) posted Fri, 23 April 2021 at 11:49 AM · edited Sun, 11 February 2024 at 4:03 PM

Hi, whenever I load a Pose into Poser with P3DO the undo buffer is reset and the action is not undoable.
In order to load a pose into Poser I run a python script and call scene.LoadLibraryPose then scene.Draw and that's about all.
I have been looking all day for information on that process, but I still don't have any clue on how I could fix that.
Reading Poser dopcumentation, opening official Poser scripts and others. Found nothing.
Any idea ?
I would be grateful even if the answer is there's no way to do that. This is something that has been bothering me for years. And now that I have decided to fix it, it is even more frustrating :)
I haven't asked Poser yet. Will be filling a ticket if the answer is negative here.,

Yarp - author of P3DO Organizer for Poser


yarp ( ) posted Sat, 24 April 2021 at 2:33 AM

So this morning I did a simple test and ran the following script the same way as above:
actor = scene.CurrentActor()
parm = actor.ParameterByCode(poser.kParmCodeXSCALE)
parm.setValue(0.66)
This didn't reset the undo buffer and I was able to undo my script. So possibly the LoadLibraryPose method does reset the Undo buffer and I should make my own function.
How... :(

Yarp - author of P3DO Organizer for Poser


adp001 ( ) posted Sat, 24 April 2021 at 8:46 AM

As you probably know, a Poser file can do all sorts of things. Not just set a pose. So what should one do before loading such a file to make Undo possible? In your example, setting a single parameter, the matter is clear: the old value goes into the undo buffer. When loading a pose file, you would have to save the entire scene beforehand for an undo if you want to cover everything. Something you can do with Poser Python: poser.SaveDocument([filename]).

But saving the whole scene takes time. Possibly a lot of time. And that even though the loaded file may have changed very little.




yarp ( ) posted Sat, 24 April 2021 at 11:41 AM

Yes, I have been thinking about such a workaround.
Instead of saving the whole document I would save a Pose of the current figure before loading a Pose,a Light before loading a Light and so on. Far from being perfect but better than nothing.
There's something missing in my process. As you say, I should save the scene state before changing it. There are some intriguing commands like MemorizeAll. But all the combinations I have tried so far have failed.

Yarp - author of P3DO Organizer for Poser


adp001 ( ) posted Sat, 24 April 2021 at 11:58 AM

I tried to make a "discrete" Undo before. Turns out it is slower than saving the whole scene. But maybe you can use something of it to play around:

from __future__ import print_function
import sys

try:
    import poser
except ImportError:
    # Not required while inside Poser Python, but very helpfull for external editors.
    # See https://adp.spdns.org
    from PoserLibs import POSER_FAKE as poser

if sys.version_info.major > 2:
    # Python 3 (Poser 12 and above)
    map = lambda a, b: [a(_b) for _b in b]
    basestring = str


def actor_hasgeom(ac):
    assert isinstance(ac, poser.ActorType)
    return hasattr(ac, "Geometry") 
           and ac.Geometry() is not None 
           and ac.Geometry().NumVertices() > 0


def collect_parms(actor, include_morphs=True):
    assert isinstance(actor, poser.ActorType)
    geom = actor.Geometry() if actor_hasgeom(actor) else None
    parm_dict = dict()
    for parm in actor.Parameters():  # type: poser.ParmType
        d = parm_dict.setdefault(parm.InternalName(), dict())
        for entry in dir(poser.ParmType):
            if "MorphTargetDelta" in entry:
                # This is a special case
                if entry.startswith("Set"):
                    # This one isn't needed here.
                    continue
                morph = list()
                if geom is not None and include_morphs and parm.IsMorphTarget():
                    for i in range(geom.NumVertices()):
                        x, y, z = parm.MorphTargetDelta(i)
                        if x != 0 or y != 0 or z != 0:
                            morph.append((i, x, y, z))
                d["MorphTargetDelta"] = morph or None
            elif entry.startswith("Set"):
                # For an undo we need to save anything we can "Set"
                attr_name = entry[3:]
                if attr_name in ("ValueFrame", "RangeConstant", "RangeLinear", "RangeSpline",
                                 "SplineBreak", "UpdateCallback"):
                    # ignore this in this version...
                    continue
                value = getattr(parm, attr_name)()
                d[attr_name] = value

        parm_dict[parm.InternalName()] = d
    return parm_dict


def collectFigure(figure):
    actor_dict = dict()
    for actor in figure.Actors():
        actor_dict[actor.InternalName()] = collect_parms(actor, include_morphs=True)
    return actor_dict


def collectLights():
    light_dict = dict()
    for light in poser.Scene().Lights():
        light_dict[light.InternalName()] = collect_parms(light)
    return light_dict


def collectCams():
    cam_dict = dict()
    for cam in poser.Scene().Cameras():
        cam_dict[cam.InternalName()] = collect_parms(cam)
    return cam_dict


def collectProps():
    prop_dict = dict()
    for prop in [ac for ac in poser.Scene().Actors() if ac.IsProp()]:
        prop_dict[prop.InternalName()] = collect_parms(prop)
    return prop_dict


def set_parms(actor, parm_dicts):
    assert isinstance(actor, poser.ActorType)
    assert isinstance(parm_dicts, dict)

    for parm_name, parm_dict in parm_dicts.items():
        parm = actor.Parameter(parm_name)
        if not parm:
            continue
        for parm_key, parm_value in parm_dict.items():
            if parm_key == "MorphTargetDelta":
                if parm_value is not None:
                    for entry in parm_value:
                        parm.SetMorphTargetDelta(*entry)
            else:
                attr_name = "Set%s" % parm_key
                getattr(parm, attr_name)(parm_value)


def undo_figure(figure, actor_dict):
    print("Undo figure", end=" ")
    assert isinstance(figure, poser.FigureType)
    inames = set(ac.InternalName() for ac in figure.Actors())
    for key, value in actor_dict.items():
        print(key, end=" ")
        poser.Scene().ProcessSomeEvents()
        if key in inames:
            set_parms(figure.ActorByInternalName(key), value)
    print("Done")


def undo_lights(light_dict):
    print("Undo lights", end=" ")
    inames = set(ac.InternalName() for ac in poser.Scene().Lights())
    for key, value in light_dict.items():
        print(key, end=" ")
        if key in inames:
            set_parms(poser.Scene().ActorByInternalName(key), value)
    print("Done")


def undo_cams(cam_dict):
    print("Undo cams", end=" ")
    inames = set(ac.InternalName() for ac in poser.Scene().Cameras())
    for key, value in cam_dict.items():
        print(key, end=" ")
        if key in inames:
            set_parms(poser.Scene().ActorByInternalName(key), value)
    print("Done")


def undo_props(prop_dict):
    print("Undo props", end=" ")
    inames = set(ac.InternalName() for ac in poser.Scene().Actors() if ac.IsProp())
    for key, value in prop_dict.items():
        print(key, end=" ")
        if key in inames:
            set_parms(poser.Scene().ActorByInternalName(key), value)
    print("Done")


lights = collectLights()
cams = collectCams()
props = collectProps()
actors = collectFigure(poser.Scene().CurrentFigure())
print("Scene data collected for undo.")
poser.Scene().ProcessSomeEvents()
print("Undo figure now.")
poser.Scene().ProcessSomeEvents()
undo_figure(poser.Scene().CurrentFigure(), actors)
#undo_cams(cams)
#undo_lights(lights)
#undo_props(props)

Saving is quit fast. But when undoing something it feels like Poser has died. So better try undoing lights or cams first :)




adp001 ( ) posted Sat, 24 April 2021 at 2:46 PM

Got it!

Works fast enough now :)

from __future__ import print_function
import sys

try:
    import poser
except ImportError:
    # Not required while inside Poser Python, but very helpfull for external editors.
    # See https://adp.spdns.org
    from PoserLibs import POSER_FAKE as poser

if sys.version_info.major > 2:
    # Python 3 (Poser 12 and above)
    map = lambda a, b: [a(_b) for _b in b]
    basestring = str


def actor_hasgeom(ac):
    assert isinstance(ac, poser.ActorType)
    return hasattr(ac, "Geometry") 
           and ac.Geometry() is not None 
           and ac.Geometry().NumVertices() > 0


def collect_parms(actor, parmcodes=None, include_morphs=True):
    assert isinstance(actor, poser.ActorType)
    if parmcodes is None:
        parmcodes = set()
    else:
        parmcodes = set(parmcodes)

    geom = actor.Geometry() if actor_hasgeom(actor) else None
    parm_dict = dict()
    for parm in actor.Parameters():  # type: poser.ParmType
        if parmcodes and parm.TypeCode() not in parmcodes:
            continue

        d = parm_dict.setdefault(parm.InternalName(), dict())
        for entry in dir(poser.ParmType):
            if "MorphTargetDelta" in entry:
                # This is a special case
                if entry.startswith("Set"):
                    # This one isn't needed here.
                    continue
                morph = list()
                if geom is not None and include_morphs and parm.IsMorphTarget():
                    for i in range(geom.NumVertices()):
                        x, y, z = parm.MorphTargetDelta(i)
                        if x != 0 or y != 0 or z != 0:
                            morph.append((i, x, y, z))
                d["MorphTargetDelta"] = morph or None
            elif entry.startswith("Set"):
                # For an undo we need to save anything we can "Set"
                attr_name = entry[3:]
                if attr_name in ("ValueFrame", "RangeConstant", "RangeLinear", "RangeSpline",
                                 "SplineBreak", "UpdateCallback"):
                    # ignore this in this version...
                    continue
                value = getattr(parm, attr_name)()
                d[attr_name] = value

        parm_dict[parm.InternalName()] = d

    return parm_dict


def set_parms(actor, parm_dicts, include_morphs=True):
    assert isinstance(actor, poser.ActorType)
    assert isinstance(parm_dicts, dict)

    for parm_name, parm_dict in parm_dicts.items():
        parm = actor.Parameter(parm_name)
        if not parm:
            continue
        for parm_key, parm_value in parm_dict.items():
            if parm_key == "MorphTargetDelta":
                if parm_value is not None and include_morphs:
                    for entry in parm_value:
                        parm.SetMorphTargetDelta(*entry)
            else:
                value = getattr(parm, parm_key)()
                if value != parm_value:
                    attr_name = "Set%s" % parm_key
                    getattr(parm, attr_name)(parm_value)


def collectActor(actor, parmcodes=None, include_morphs=True):
    parms = collect_parms(actor, parmcodes=parmcodes, include_morphs=include_morphs)
    actor_dict = dict(Parameters=parms, InternalName=actor.InternalName())
    for name in dir(poser.ActorType):
        if name.startswith("Set"):
            attr_name = name[3:]
            if attr_name in ("EndPoint",):
                continue
            try:
                value = getattr(actor, attr_name)()
            except Exception:
                continue
            actor_dict[attr_name] = value
    return actor_dict


def undoActor(actor, actor_dict, include_morphs=True):
    assert isinstance(actor, poser.ActorType)
    for key, value in actor_dict.items():
        if key == "Parameters":
            set_parms(actor, value, include_morphs=include_morphs)
        elif key != "InternalName":
            if getattr(actor, key)() != value:
                try:
                    getattr(actor, "Set%s" % key)(value)
                except poser.error:
                    pass


def collectFigure(figure, parmcodes=None, include_morphs=True):
    actors = [collectActor(ac, parmcodes=parmcodes, include_morphs=include_morphs)
              for ac in figure.Actors() if ac.IsBodyPart()]
    figure_dict = dict(Actors=actors, InternalName=figure.InternalName())
    for name in dir(poser.FigureType):
        if name.startswith("Set"):
            attr_name = name[3:]
            try:
                value = getattr(figure, attr_name)()
            except Exception:
                continue
            figure_dict[attr_name] = value
    return figure_dict


def undoFigure(figure, figure_dict, include_morphs=True):
    assert isinstance(figure, poser.FigureType)
    assert isinstance(figure_dict, dict)
    for key, value in figure_dict.items():
        if key == "InternalName":
            pass
        elif key == "Actors":
            for ac_dict in value:
                ac = figure.ActorByInternalName(ac_dict["InternalName"])
                undoActor(ac, ac_dict, include_morphs=include_morphs)
        else:
            if getattr(figure, key)() != value:
                getattr(figure, "Set%s" % key)(value)


def collectLights(parmcodes=None):
    light_list = list()
    for light in poser.Scene().Lights():
        light_list.append(collectActor(light, parmcodes=parmcodes, include_morphs=False))
    return light_list


def undoLights(light_list):
    for light in light_list:
        try:
            ac = poser.Scene().ActorByInternalName(light["InternalName"])
        except poser.error:
            continue
        undoActor(ac)


def collectCams(parmcodes=None):
    cam_list = list()
    for cam in poser.Scene().Cameras():
        cam_list.append(collectActor(cam, parmcodes=parmcodes, include_morphs=False))
    return cam_list


def undoCams(cam_list):
    for cam in cam_list:
        try:
            ac = poser.Scene().ActorByInternalName(cam["InternalName"])
        except poser.error:
            continue
        undoActor(ac)


def collectProps(parmcodes=None, include_morphs=False):
    prop_list = list()
    for prop in [ac for ac in poser.Scene().Actors() if ac.IsProp()]:
        prop_list.append(collectActor(prop, parmcodes=parmcodes, include_morphs=include_morphs))
    return prop_list


def undoProps(prop_list):
    for prop in prop_list:
        try:
            ac = poser.Scene().ActorByInternalName(prop["InternalName"])
        except poser.error:
            continue
        undoActor(ac)


# You may restrict collected parameters by an allowed list of parmcodes. E.g.:
#    parmcodes = [
#        poser.kParmCodeXROT,
#        poser.kParmCodeYROT,
#        poser.kParmCodeZROT,
#        poser.kParmCodeXTRAN,
#        poser.kParmCodeYTRAN,
#        poser.kParmCodeZTRAN,
#       ...
#    ]
parmcodes = None

lights = collectLights(parmcodes=parmcodes)
cams = collectCams(parmcodes=parmcodes)
props = collectProps(parmcodes=parmcodes)
figure = collectFigure(poser.Scene().CurrentFigure(), parmcodes=parmcodes)
print("Scene data collected for undo.")




yarp ( ) posted Sat, 24 April 2021 at 2:57 PM

This is a bunch of code, thank you. It certainly took some time to write this.
Yes I could use it to save the state and restore it if the user is requesting to undo. It is not simple fro sure.
Thank you again.

Yarp - author of P3DO Organizer for Poser


yarp ( ) posted Sat, 24 April 2021 at 11:08 PM

Cool, sorry I didbn't see your 2nd post. Great you fixed the lag.
It seems like everything is undoable by hand. Well then. This requires much more work than I expected.

Yarp - author of P3DO Organizer for Poser


Dizzi ( ) posted Tue, 27 April 2021 at 1:31 PM

Are you just loading a regular pose? At least for poser 7 to 11 you could then just call the poser library interface via a http get request (would have to look that up).



formoz ( ) posted Tue, 27 April 2021 at 1:39 PM · edited Tue, 27 April 2021 at 1:43 PM

tested it, i had a poser crash and i chased down the culprit :

rFoot:6
key: NumbSubdivRenderLevels, MemorizedValue: '0', CurrentValue:'0'
key: ShadingRate, MemorizedValue: '0.20000000298', CurrentValue:'0.20000000298'
key: VisibleInIDL, MemorizedValue: '1', CurrentValue:'1'
key: VisibleInReflections, MemorizedValue: '1', CurrentValue:'1'
key: CreaseAngle, MemorizedValue: '80.0', CurrentValue:'80.0'
key: Parent, MemorizedValue: 'Actor object at 0x0000000013F215D0', CurrentValue:'Actor object at 0x0000000010CD1DF8'
key: VisibleInRender, MemorizedValue: '1', CurrentValue:'1'
key: SmoothPolys, MemorizedValue: '1', CurrentValue:'1'
key: AnimatableOrigin, MemorizedValue: '0', CurrentValue:'0'
key: BackfaceCull, MemorizedValue: '0', CurrentValue:'0'
key: DisplayStyle, MemorizedValue: '4', CurrentValue:'4'
key: Name, MemorizedValue: 'Right Foot', CurrentValue:'Right Foot'
key: Geometry, MemorizedValue: 'Geom object at 0x0000000013F3CF30', CurrentValue:'Geom object at 0x0000000013F51F90'
key: CastsShadows, MemorizedValue: '1', CurrentValue:'1'
key: AlignmentRotationXYZ, MemorizedValue: '(5.164360046386719, -7.982140064239502, -3.025599956512451)', CurrentValue:'(5.164360046386719, -7.982140064239502, -3.025599956512451)'
key: Orientation, MemorizedValue: '(5.164360046386719, -7.982140064239502, -3.025599956512451)', CurrentValue:'(5.164360046386719, -7.982140064239502, -3.025599956512451)'
key: Origin, MemorizedValue: '(-0.02469700016081333, 0.031172700226306915, -0.019022399559617043)', CurrentValue:'(-0.02469700016081333, 0.031172700226306915, -0.019022399559617043)'
key: NumbSubdivLevels, MemorizedValue: '0', CurrentValue:'0'
key: Bends, MemorizedValue: '1', CurrentValue:'1'
key: SubdivideWithFigure, MemorizedValue: '1', CurrentValue:'1'
key: VisibleInCamera, MemorizedValue: '1', CurrentValue:'1'
key: Visible, MemorizedValue: '1', CurrentValue:'1'
key: Static, MemorizedValue: '1', CurrentValue:'1'
key: DisplayOrigin, MemorizedValue: '0', CurrentValue:'0'
key: DisplacementBounds, MemorizedValue: '0.0', CurrentValue:'0.0'
key: OnOff, MemorizedValue: '1', CurrentValue:'1'

i had to remove "Parent" from collected attribs to avoid the crash, astonishly it didn't crash on geometry change. but i do'nt understand why the geometry changed while i changed it before collect and not after.


yarp ( ) posted Tue, 27 April 2021 at 1:57 PM

Hi Dizzi I think I have been tired of the Poser interface for the last 20 years or so. P3DO has all that too. I am just trying to improve the P3DO Poser interface.
P3DO Explorer 2.8
Yes I am loading a regular pose. Do those http request still work with the flash library disabled ? I tend to favor solutions where I am in control of what the program is doing. But it is not always possible.
At the moment I am seeing a solution similar to what adp001 is suggesting. That would be to save the status before loading. Far from perfect but simple and usable.
Another solution is to ask the Poser team to fix that. I don't see why they erase the undo list when LoadLibraryPose is called.

Yarp - author of P3DO Organizer for Poser


adp001 ( ) posted Tue, 27 April 2021 at 2:50 PM

formoz posted at 2:26PM Tue, 27 April 2021 - #4417828

tested it, i had a poser crash and i chased down the culprit :

rFoot:6
key: NumbSubdivRenderLevels, MemorizedValue: '0', CurrentValue:'0'
key: ShadingRate, MemorizedValue: '0.20000000298', CurrentValue:'0.20000000298'
key: VisibleInIDL, MemorizedValue: '1', CurrentValue:'1'
key: VisibleInReflections, MemorizedValue: '1', CurrentValue:'1'
key: CreaseAngle, MemorizedValue: '80.0', CurrentValue:'80.0'
key: Parent, MemorizedValue: 'Actor object at 0x0000000013F215D0', CurrentValue:'Actor object at 0x0000000010CD1DF8'
key: VisibleInRender, MemorizedValue: '1', CurrentValue:'1'
key: SmoothPolys, MemorizedValue: '1', CurrentValue:'1'
key: AnimatableOrigin, MemorizedValue: '0', CurrentValue:'0'
key: BackfaceCull, MemorizedValue: '0', CurrentValue:'0'
key: DisplayStyle, MemorizedValue: '4', CurrentValue:'4'
key: Name, MemorizedValue: 'Right Foot', CurrentValue:'Right Foot'
key: Geometry, MemorizedValue: 'Geom object at 0x0000000013F3CF30', CurrentValue:'Geom object at 0x0000000013F51F90'
key: CastsShadows, MemorizedValue: '1', CurrentValue:'1'
key: AlignmentRotationXYZ, MemorizedValue: '(5.164360046386719, -7.982140064239502, -3.025599956512451)', CurrentValue:'(5.164360046386719, -7.982140064239502, -3.025599956512451)'
key: Orientation, MemorizedValue: '(5.164360046386719, -7.982140064239502, -3.025599956512451)', CurrentValue:'(5.164360046386719, -7.982140064239502, -3.025599956512451)'
key: Origin, MemorizedValue: '(-0.02469700016081333, 0.031172700226306915, -0.019022399559617043)', CurrentValue:'(-0.02469700016081333, 0.031172700226306915, -0.019022399559617043)'
key: NumbSubdivLevels, MemorizedValue: '0', CurrentValue:'0'
key: Bends, MemorizedValue: '1', CurrentValue:'1'
key: SubdivideWithFigure, MemorizedValue: '1', CurrentValue:'1'
key: VisibleInCamera, MemorizedValue: '1', CurrentValue:'1'
key: Visible, MemorizedValue: '1', CurrentValue:'1'
key: Static, MemorizedValue: '1', CurrentValue:'1'
key: DisplayOrigin, MemorizedValue: '0', CurrentValue:'0'
key: DisplacementBounds, MemorizedValue: '0.0', CurrentValue:'0.0'
key: OnOff, MemorizedValue: '1', CurrentValue:'1'

i had to remove "Parent" from collected attribs to avoid the crash, astonishly it didn't crash on geometry change. but i do'nt understand why the geometry changed while i changed it before collect and not after.

I didn't have any trouble with "Parent" in my tests. But I have a clue why it comes to an error condition.

The script stores the "real reference". But this reference (actually more or less a memory address) may be dropped by Posers internal engine without notification. I know of this and avoid it usually by storing "InternalName" instead of the address.

function "collectActor" and "undoActor" should be changed to do exactly this: Storing/restoring the InternalName (including a test if this actor still exists). Having parents restored should be part of "Undo".

here we go:

def collectActor(actor, parmcodes=None, include_morphs=True):
    parms = collect_parms(actor, parmcodes=parmcodes, include_morphs=include_morphs)
    actor_dict = dict(Parameters=parms, InternalName=actor.InternalName())
    for name in dir(poser.ActorType):
        if name.startswith("Set"):
            attr_name = name[3:]
            if attr_name in ("EndPoint",):
                continue
            elif attr_name == "Parent":
                value = actor.Parent().InternalName()
            else:
                try:
                    value = getattr(actor, attr_name)()
                except Exception:
                    continue
            actor_dict[attr_name] = value
    return actor_dict


def undoActor(actor, actor_dict, include_morphs=True):
    assert isinstance(actor, poser.ActorType)
    for key, value in actor_dict.items():
        if key == "Parameters":
            set_parms(actor, value, include_morphs=include_morphs)
        elif key == "Parent":
            try:
                actor.SetParent(poser.Scene().ActorByInternalName(value))
            except poser.error:
                continue
        elif key != "InternalName":
            if getattr(actor, key)() != value:
                try:
                    getattr(actor, "Set%s" % key)(value)
                except poser.error:
                    pass

Maybe this hack may not work as expected at the end, because "SetParent" can have more than just the actor as parameter ('inheritBends' and 'realign*; both set to 0 by default).




formoz ( ) posted Wed, 28 April 2021 at 7:53 AM

Yes This correction works ! Thx, It's nice to you to deliver such quality python scripts to everyone !


yarp ( ) posted Wed, 28 April 2021 at 2:05 PM

Sure it is. I went to visit your website, you have many interesting scripts there.

Yarp - author of P3DO Organizer for Poser


formoz ( ) posted Fri, 30 April 2021 at 1:07 PM

i found another problem : if you do a actor.MarkGeomChanged() before even doing a FigureCollect() you'll have a total mess undo. For me the figure merged with the figure it was conformed . removed it and undo worked this happens in Poser 11.1.1.35510.

Logs :

figure Collect:(figure and actor)
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'BODY:2'//obj:'|Actor object at 0x00000000135AF708|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'CenterOfMass:2'//obj:'|Actor object at 0x00000000135AF1F8|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'GoalCenterOfMass:2'//obj:'|Actor object at 0x00000000135AF600|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'hip:2'//obj:'|Actor object at 0x000000001353BE10|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'abdomen:2'//obj:'|Actor object at 0x000000001353B960|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rThigh:2'//obj:'|Actor object at 0x000000001353B660|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rShin:2'//obj:'|Actor object at 0x000000001353BDB0|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rFoot:2'//obj:'|Actor object at 0x000000001353B7E0|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lThigh:2'//obj:'|Actor object at 0x000000001353BB58|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lShin:2'//obj:'|Actor object at 0x000000001353BA50|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lFoot:2'//obj:'|Actor object at 0x000000001353BD08|'
figure Undo: (figure and actor)
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'BODY:2'//obj:'|Actor object at 0x000000001353D798|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'CenterOfMass:2'//obj:'|Actor object at 0x000000001353BAE0|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'GoalCenterOfMass:2'//obj:'|Actor object at 0x000000001353BEA0|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'hip:2'//obj:'|Actor object at 0x000000001353B948|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'abdomen:2'//obj:'|Actor object at 0x000000001353BD08|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rThigh:2'//obj:'|Actor object at 0x000000001353B9A8|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rShin:2'//obj:'|Actor object at 0x000000001353BE10|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'rFoot:2'//obj:'|Actor object at 0x000000001353B960|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lThigh:2'//obj:'|Actor object at 0x000000001353B660|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lShin:2'//obj:'|Actor object at 0x000000001353BDB0|'
figure 'V4Hot_Shoes':'Figure 2'//obj:'|Figure object at 0x000000001353D3A8|', actor 'lFoot:2'//obj:'|Actor object at 0x000000001353B2A0|'
dictionary data before calling and figure checking name/internalname : ac = figure.ActorByInternalName(ac_dict["InternalName"])
figure 'V4Hot_Shoes':'Figure 2' // actor 'BODY:2'
figure 'V4Hot_Shoes':'Figure 2' // actor 'hip:2'
figure 'V4Hot_Shoes':'Figure 2' // actor 'abdomen:2'
  File "F:LocalRuntimeLibraries!BarzingsplitCR2.py", line 609, in undoFigure
    ac = figure.Actor(ac_dict["InternalName"])
poser.error: Figure has no actor by that name
------


formoz ( ) posted Fri, 30 April 2021 at 1:28 PM

hmm, finally it's more complicated, i have the same case but this time no MarkGeomChanged() involved ...


formoz ( ) posted Fri, 30 April 2021 at 2:05 PM

formoz posted at 2:05PM Fri, 30 April 2021 - #4418066

hmm, finally it's more complicated, i have the same case but this time no MarkGeomChanged() involved ...

forget this one, i found why


adp001 ( ) posted Fri, 30 April 2021 at 2:13 PM · edited Fri, 30 April 2021 at 2:13 PM

This is not a complete replacement for Posers undo. Can't be, because the Python API has restrictions.

Seems you removed an actor or renamed "InternalName". The error can be catched, but makes this undo useless.

Here is a version with a check:

def undoFigure(figure, figure_dict, include_morphs=True):
    assert isinstance(figure, poser.FigureType)
    assert isinstance(figure_dict, dict)
    for key, value in figure_dict.items():
        if key == "InternalName":
            pass
        elif key == "Actors":
            for ac_dict in value:
                try:
                    ac = figure.ActorByInternalName(ac_dict["InternalName"])
                except poser.error:
                    print("Actor '%s' no longer exists." % ac_dict["InternalName"])
                else:
                    undoActor(ac, ac_dict, include_morphs=include_morphs)
        else:
            if getattr(figure, key)() != value:
                getattr(figure, "Set%s" % key)(value)

A more stable version (but still no replacement for the original Undo) can be created using the script as an AddOn. But, as I said, still no replacement. So I'm not really interested in extending this script further. It's nice for certain situations. Not more.




formoz ( ) posted Fri, 30 April 2021 at 4:17 PM

in the log, you see it's not the case, figure and actors are the same between the "collect" and the "undo". the last actor that appears in the log : figure 'V4Hot_Shoes':'Figure 2' // actor 'abdomen:2', is flushed in the log file just before : ac = figure.ActorByInternalName(ac_dict["InternalName"]) that goes in error and abdomen:2 is part of the figure (logs just above)

But, yes, i'll probably make a personal version because i don't need a total undo. Just ckecking the name of actors in my case should be enough. since you put the figure as parameter of the undo, it should assume the actors are the good ones


formoz ( ) posted Fri, 30 April 2021 at 5:00 PM

ok, i just experienced that even with file.flush(), you're not necessarily getting the last lines before a crash ... :)


formoz ( ) posted Fri, 30 April 2021 at 5:24 PM

I am wrong or You do Set Value of Value instead of UnaffectedValue ?


adp001 ( ) posted Fri, 30 April 2021 at 7:48 PM · edited Fri, 30 April 2021 at 7:51 PM

Why do you ask – you can see it in the source :)

ValueOps are not saved either. And neither are materials. I made this script once mainly to be able to undo changes in morphtargets. The rest was more playing around. I posted it here to show a startpoint for something more useful.

Today I made something to convert material files to json. Tomorrow I'm going to do it the other way around – json mat-files to Poser. For a possibility to exchange materials between Poser and Blender. That's far more interesting (Blenders Cycle is still serveral times faster and has far more options than Posers implemtation) :)




adp001 ( ) posted Fri, 30 April 2021 at 7:56 PM

formoz posted at 7:55PM Fri, 30 April 2021 - #4418086

ok, i just experienced that even with file.flush(), you're not necessarily getting the last lines before a crash ... :)

I can't see on which part this script could be able to crash your Poser. Raising an error condition: Ok. But no crash. There must be something other in your script.




formoz ( ) posted Sat, 01 May 2021 at 4:14 AM

adp001 posted at 4:09AM Sat, 01 May 2021 - #4418096

formoz posted at 7:55PM Fri, 30 April 2021 - #4418086

ok, i just experienced that even with file.flush(), you're not necessarily getting the last lines before a crash ... :)

I can't see on which part this script could be able to crash your Poser. Raising an error condition: Ok. But no crash. There must be something other in your script.

yes absolutely, like reloading figure between the the collect and the undo.... Finally, i had to heavely personalized your scripts, keeping only numeric values, checking actors internalname differently (removing the instantiation check ":"), added a new parameter for this called "only_parms")


formoz ( ) posted Sat, 01 May 2021 at 4:37 AM · edited Sat, 01 May 2021 at 4:41 AM

adp001 posted at 4:17AM Sat, 01 May 2021 - #4418095

Today I made something to convert material files to json. Tomorrow I'm going to do it the other way around – json mat-files to Poser. For a possibility to exchange materials between Poser and Blender. That's far more interesting (Blenders Cycle is still serveral times faster and has far more options than Posers implemtation) :)

ah nice, i need to install blender. Blender use Json for its Files ? or you did a script on Blender to import your json ? I currently do a "CR2 (symetry) splitter" and reverse a "CR2 Mirrorer". It includs all : obj, weightMap, Morphs, MAterials and even merge a sculpting morph in geometry if needed.


adp001 ( ) posted Sat, 01 May 2021 at 3:24 PM

formoz posted at 3:14PM Sat, 01 May 2021 - #4418115

ah nice, i need to install blender. Blender use Json for its Files ?

No. B lender uses "blend files" for anything. But json makes an easy internediate format. Easy to import in any other software without without the need of many knowledge about the source internals.

or you did a script on Blender to import your json ?

Yes. That was the easy part. Blender has a nearly full fledged Python API.

I currently do a "CR2 (symetry) splitter" and reverse a "CR2 Mirrorer".

Can you tell what it is good for?




Dizzi ( ) posted Sun, 02 May 2021 at 8:00 AM

you can try, if loading files from outside poser still works (that was how the air library from Poser 8 communicated with Poser). Here' some C# code for loading and saving, port should be the one from the poser.ini:

load:

System.Net.WebClient Client = new System.Net.WebClient();

            Client.Encoding = Encoding.UTF8;

            Client.QueryString.Add("id", Util.EncodeUtfUriComponent(filename));
            Client.QueryString.Add("op", "addItem");
            
            Stream strm = Client.OpenRead(new Uri("http://localhost:11530/apps/lms/api.py"));
            StreamReader sr = new StreamReader(strm);
            string line;
            do {
                line = sr.ReadLine();
                Console.WriteLine(line);
            }
            while (line != null);
            strm.Close();

save:

string Path = SaveDialog.GetSavePath(); if (Path == null) return; System.Net.WebClient Client = new System.Net.WebClient(); Client.Encoding = Encoding.UTF8; Client.QueryString.Add("op", "saveItem"); Client.QueryString.Add("categoryId", Category); Client.QueryString.Add("folderId", Util.EncodeUtfUriComponent(Path));

        //Stream strm =
        IntPtr poserHandle = Util.GetPoserWindowHandle(this);
        if (poserHandle != IntPtr.Zero)
            SetForegroundWindow(poserHandle);
        try {
            Client.OpenRead(new Uri("http://localhost:11530/apps/lms/api.py"));



yarp ( ) posted Tue, 04 May 2021 at 2:23 AM

Cool, but instead of running this as an http request maybe running it as a Poser script would work too.
Since you can run python script with arguments there's a chance it runs ok.
If this doesn't I will save a Pose before loading a Pose and use it as a workaround undo system. Far from being satisfactory but bettet than nothing.

Yarp - author of P3DO Organizer for Poser


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.