Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gltf2_blender_gather_cache.py « exp « blender « io_scene_gltf2 - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4f95431ca94edc900ba24dc033a2acdc4932b096 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# SPDX-License-Identifier: Apache-2.0
# Copyright 2018-2021 The glTF-Blender-IO authors.

import functools
import bpy
from io_scene_gltf2.blender.exp import gltf2_blender_get


def cached_by_key(key):
    """
    Decorates functions whose result should be cached. Use it like:
        @cached_by_key(key=...)
        def func(..., export_settings):
            ...
    The decorated function, func, must always take an "export_settings" arg
    (the cache is stored here).
    The key argument to the decorator is a function that computes the key to
    cache on. It is passed all the arguments to func.
    """
    def inner(func):
        @functools.wraps(func)
        def wrapper_cached(*args, **kwargs):
            if kwargs.get("export_settings"):
                export_settings = kwargs["export_settings"]
            else:
                export_settings = args[-1]

            cache_key = key(*args, **kwargs)

            # invalidate cache if export settings have changed
            if not hasattr(func, "__export_settings") or export_settings != func.__export_settings:
                func.__cache = {}
                func.__export_settings = export_settings
            # use or fill cache
            if cache_key in func.__cache:
                return func.__cache[cache_key]
            else:
                result = func(*args, **kwargs)
                func.__cache[cache_key] = result
                return result

        return wrapper_cached

    return inner


def default_key(*args, **kwargs):
    """
    Default cache key for @cached functions.
    Cache on all arguments (except export_settings).
    """
    assert len(args) >= 2 and 0 <= len(kwargs) <= 1, "Wrong signature for cached function"
    cache_key_args = args
    # make a shallow copy of the keyword arguments so that 'export_settings' can be removed
    cache_key_kwargs = dict(kwargs)
    if kwargs.get("export_settings"):
        del cache_key_kwargs["export_settings"]
    else:
        cache_key_args = args[:-1]

    cache_key = ()
    for i in cache_key_args:
        cache_key += (i,)
    for i in cache_key_kwargs.values():
        cache_key += (i,)

    return cache_key


def cached(func):
    return cached_by_key(key=default_key)(func)

def objectcache(func):

    def reset_cache_objectcache():
        func.__objectcache = {}

    func.reset_cache = reset_cache_objectcache

    @functools.wraps(func)
    def wrapper_objectcache(*args, **kwargs):
        cache_key_args = args
        cache_key_args = args[:-1]

        if not hasattr(func, "__objectcache"):
            func.reset_cache()

        # object is not cached yet
        if cache_key_args[0] not in func.__objectcache.keys():
            result = func(*args)
            func.__objectcache = result
            return result[cache_key_args[0]][cache_key_args[1]][cache_key_args[4]]
        # object is in cache, but not this action
        # We need to keep other actions
        elif cache_key_args[1] not in func.__objectcache[cache_key_args[0]].keys():
            result = func(*args)
            func.__objectcache[cache_key_args[0]][cache_key_args[1]] = result[cache_key_args[0]][cache_key_args[1]]
            return result[cache_key_args[0]][cache_key_args[1]][cache_key_args[4]]
        # all is already cached
        else:
            return func.__objectcache[cache_key_args[0]][cache_key_args[1]][cache_key_args[4]]
    return wrapper_objectcache

def bonecache(func):

    def reset_cache_bonecache():
        func.__current_action_name = None
        func.__current_armature_uuid = None
        func.__bonecache = {}

    func.reset_cache = reset_cache_bonecache

    @functools.wraps(func)
    def wrapper_bonecache(*args, **kwargs):

        armature = args[-1]['vtree'].nodes[args[0]].blender_object

        cache_key_args = args
        cache_key_args = args[:-1]

        if cache_key_args[2] is None:
            pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(armature,
                                                                cache_key_args[1][0].data_path)
        else:
            pose_bone_if_armature = armature.pose.bones[cache_key_args[2]]

        if not hasattr(func, "__current_action_name"):
            func.reset_cache()
        if cache_key_args[6] != func.__current_action_name or cache_key_args[0] != func.__current_armature_uuid:
            result = func(*args)
            func.__bonecache = result
            func.__current_action_name = cache_key_args[6]
            func.__current_armature_uuid = cache_key_args[0]
            return result[cache_key_args[7]][pose_bone_if_armature.name]
        else:
            return func.__bonecache[cache_key_args[7]][pose_bone_if_armature.name]
    return wrapper_bonecache

# TODO: replace "cached" with "unique" in all cases where the caching is functional and not only for performance reasons
call_or_fetch = cached
unique = cached

def skdriverdiscovercache(func):

    def reset_cache_skdriverdiscovercache():
        func.__current_armature_uuid = None
        func.__skdriverdiscover = {}

    func.reset_cache = reset_cache_skdriverdiscovercache

    @functools.wraps(func)
    def wrapper_skdriverdiscover(*args, **kwargs):

        cache_key_args = args
        cache_key_args = args[:-1]

        if not hasattr(func, "__current_armature_uuid") or func.__current_armature_uuid is None:
            func.reset_cache()

        if cache_key_args[0] != func.__current_armature_uuid:
            result = func(*args)
            func.__skdriverdiscover[cache_key_args[0]] = result
            func.__current_armature_uuid = cache_key_args[0]
            return result
        else:
            return func.__skdriverdiscover[cache_key_args[0]]
    return wrapper_skdriverdiscover

def skdrivervalues(func):

    def reset_cache_skdrivervalues():
        func.__skdrivervalues = {}

    func.reset_cache = reset_cache_skdrivervalues

    @functools.wraps(func)
    def wrapper_skdrivervalues(*args, **kwargs):
        if not hasattr(func, "__skdrivervalues") or func.__skdrivervalues is None:
            func.reset_cache()

        armature = args[-1]['vtree'].nodes[args[0]].blender_object

        cache_key_args = args
        cache_key_args = args[:-1]

        if armature.name not in func.__skdrivervalues.keys():
            func.__skdrivervalues[armature.name] = {}
        if cache_key_args[1] not in func.__skdrivervalues[armature.name]:
            vals = func(*args)
            func.__skdrivervalues[armature.name][cache_key_args[1]] = vals
            return vals
        else:
            return func.__skdrivervalues[armature.name][cache_key_args[1]]
    return wrapper_skdrivervalues