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
29static void debugTransform(SgTransform *data, const ParentData *parent) {
30    rsDebug("****** <Transform> ******", (int)data);
31    printName(data->name);
32    rsDebug("isDirty", data->isDirty);
33    rsDebug("parent", (int)parent);
34    rsDebug("child ", rsIsObject(data->children));
35
36    // Refresh matrices if dirty
37    if (data->isDirty && rsIsObject(data->components)) {
38        uint32_t numComponenets = rsAllocationGetDimX(data->components);
39        for (int i = 0; i < numComponenets; i ++) {
40            const SgTransformComponent *comp = NULL;
41            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
42
43            if (rsIsObject(comp->name)) {
44                rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
45                rsDebug("Type", comp->type);
46            } else {
47                rsDebug("no name", comp->value);
48                rsDebug("Type", comp->type);
49            }
50        }
51    }
52
53    rsDebug("timestamp", data->timestamp);
54    rsDebug("****** </Transform> ******", (int)data);
55}
56
57static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
58    rs_matrix4x4 temp;
59
60    switch (type) {
61    case TRANSFORM_TRANSLATE:
62        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
63        break;
64    case TRANSFORM_ROTATE:
65        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
66        break;
67    case TRANSFORM_SCALE:
68        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
69        break;
70    }
71    rsMatrixMultiply(mat, &temp);
72}
73
74void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
75
76    SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
77    const ParentData *parent = (const ParentData *)usrData;
78
79#ifdef DEBUG_TRANSFORMS
80    debugTransform(data, parent);
81#endif //DEBUG_TRANSFORMS
82
83    rs_matrix4x4 *localMat = &data->localMat;
84    rs_matrix4x4 *globalMat = &data->globalMat;
85
86    // Refresh matrices if dirty
87    if (data->isDirty && rsIsObject(data->components)) {
88        bool resetLocal = false;
89        uint32_t numComponenets = rsAllocationGetDimX(data->components);
90        for (int i = 0; i < numComponenets; i ++) {
91            if (!resetLocal) {
92                // Reset our local matrix only for component transforms
93                rsMatrixLoadIdentity(localMat);
94                resetLocal = true;
95            }
96            const SgTransformComponent *comp = NULL;
97            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
98            appendTransformation(comp->type, comp->value, localMat);
99        }
100    }
101
102    if (parent) {
103        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
104        if (data->isDirty) {
105            rsMatrixLoad(globalMat, parent->mat);
106            rsMatrixMultiply(globalMat, localMat);
107        }
108    } else if (data->isDirty) {
109        rsMatrixLoad(globalMat, localMat);
110    }
111
112    ParentData toChild;
113    toChild.changed = 0;
114    toChild.mat = globalMat;
115
116    if (data->isDirty) {
117        toChild.changed = 1;
118        data->timestamp ++;
119    }
120
121    if (rsIsObject(data->children)) {
122        rs_allocation nullAlloc;
123        rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
124    }
125
126    data->isDirty = 0;
127}
128