1// Copyright (C) 2011 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma version(1)
16
17#pragma rs java_package_name(com.android.modelviewer)
18
19#include "scenegraph_objects.rsh"
20
21rs_script gTransformScript;
22
23typedef struct {
24    int changed;
25    rs_matrix4x4 *mat;
26} ParentData;
27
28//#define DEBUG_TRANSFORMS
29/* Unused function:
30static void debugTransform(SgTransform *data, const ParentData *parent) {
31    rsDebug("****** <Transform> ******", (int)data);
32    printName(data->name);
33    rsDebug("isDirty", data->isDirty);
34    rsDebug("parent", (int)parent);
35    rsDebug("child ", rsIsObject(data->children));
36
37    // Refresh matrices if dirty
38    if (data->isDirty && rsIsObject(data->components)) {
39        uint32_t numComponenets = rsAllocationGetDimX(data->components);
40        for (int i = 0; i < numComponenets; i ++) {
41            const SgTransformComponent *comp = NULL;
42            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
43
44            if (rsIsObject(comp->name)) {
45                rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
46                rsDebug("Type", comp->type);
47            } else {
48                rsDebug("no name", comp->value);
49                rsDebug("Type", comp->type);
50            }
51        }
52    }
53
54    rsDebug("timestamp", data->timestamp);
55    rsDebug("****** </Transform> ******", (int)data);
56}
57*/
58
59static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
60    rs_matrix4x4 temp;
61
62    switch (type) {
63    case TRANSFORM_TRANSLATE:
64        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
65        break;
66    case TRANSFORM_ROTATE:
67        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
68        break;
69    case TRANSFORM_SCALE:
70        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
71        break;
72    }
73    rsMatrixMultiply(mat, &temp);
74}
75
76void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
77
78    SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
79    const ParentData *parent = (const ParentData *)usrData;
80
81#ifdef DEBUG_TRANSFORMS
82    debugTransform(data, parent);
83#endif //DEBUG_TRANSFORMS
84
85    rs_matrix4x4 *localMat = &data->localMat;
86    rs_matrix4x4 *globalMat = &data->globalMat;
87
88    // Refresh matrices if dirty
89    if (data->isDirty && rsIsObject(data->components)) {
90        bool resetLocal = false;
91        uint32_t numComponenets = rsAllocationGetDimX(data->components);
92        for (int i = 0; i < numComponenets; i ++) {
93            if (!resetLocal) {
94                // Reset our local matrix only for component transforms
95                rsMatrixLoadIdentity(localMat);
96                resetLocal = true;
97            }
98            const SgTransformComponent *comp = NULL;
99            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
100            appendTransformation(comp->type, comp->value, localMat);
101        }
102    }
103
104    if (parent) {
105        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
106        if (data->isDirty) {
107            rsMatrixLoad(globalMat, parent->mat);
108            rsMatrixMultiply(globalMat, localMat);
109        }
110    } else if (data->isDirty) {
111        rsMatrixLoad(globalMat, localMat);
112    }
113
114    ParentData toChild;
115    toChild.changed = 0;
116    toChild.mat = globalMat;
117
118    if (data->isDirty) {
119        toChild.changed = 1;
120        data->timestamp ++;
121    }
122
123    if (rsIsObject(data->children)) {
124        rs_allocation nullAlloc = {0};
125        rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
126    }
127
128    data->isDirty = 0;
129}
130