1 //
2 //   Copyright 2014 DreamWorks Animation LLC.
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 #include "../sdc/crease.h"
25 
26 namespace OpenSubdiv {
27 namespace OPENSUBDIV_VERSION {
28 
29 namespace Sdc {
30 
31 //
32 //  Declarations of creasing constants and non-inline methods:
33 //
34 float const Crease::SHARPNESS_SMOOTH   =  0.0f;
35 float const Crease::SHARPNESS_INFINITE = 10.0f;
36 
37 
38 //
39 //  Creasing queries dependent on sharpness values:
40 //
41 Crease::Rule
DetermineVertexVertexRule(float vertexSharpness,int sharpEdgeCount) const42 Crease::DetermineVertexVertexRule(float vertexSharpness, int sharpEdgeCount) const {
43 
44     if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
45 
46     return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
47 }
48 
49 Crease::Rule
DetermineVertexVertexRule(float vertexSharpness,int incidentEdgeCount,float const * incidentEdgeSharpness) const50 Crease::DetermineVertexVertexRule(float        vertexSharpness,
51                                      int          incidentEdgeCount,
52                                      float const* incidentEdgeSharpness) const {
53 
54     if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
55 
56     int sharpEdgeCount = 0;
57     for (int i = 0; i < incidentEdgeCount; ++i) {
58         sharpEdgeCount += IsSharp(incidentEdgeSharpness[i]);
59     }
60     return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
61 }
62 
63 float
ComputeFractionalWeightAtVertex(float parentVertexSharpness,float childVertexSharpness,int incidentEdgeCount,float const * parentSharpness,float const * childSharpness) const64 Crease::ComputeFractionalWeightAtVertex(float        parentVertexSharpness,
65                                            float        childVertexSharpness,
66                                            int          incidentEdgeCount,
67                                            float const* parentSharpness,
68                                            float const* childSharpness) const {
69 
70     int   transitionCount = 0;
71     float transitionSum   = 0.0f;
72 
73     if (IsSharp(parentVertexSharpness) && IsSmooth(childVertexSharpness)) {
74         transitionCount = 1;
75         transitionSum   = parentVertexSharpness;
76     }
77 
78     //
79     //  We need the child-edge sharpness values for non-simple methods to ensure
80     //  that the sharpness went from a non-zero value (potentially greater than
81     //  1.0) to zero...
82     //
83     if (IsUniform() || (childSharpness == 0)) {
84         for (int i = 0; i < incidentEdgeCount; ++i) {
85             if (IsSharp(parentSharpness[i]) && (parentSharpness[i] <= 1.0f)) {
86                 transitionSum   += parentSharpness[i];
87                 transitionCount ++;
88             }
89         }
90     } else {
91         for (int i = 0; i < incidentEdgeCount; ++i) {
92             if (IsSharp(parentSharpness[i]) && IsSmooth(childSharpness[i])) {
93                 transitionSum   += parentSharpness[i];
94                 transitionCount ++;
95             }
96         }
97     }
98     if (transitionCount == 0) return 0.0f;
99     float fractionalWeight = transitionSum / (float)transitionCount;
100     return (fractionalWeight > 1.0f) ? 1.0f : fractionalWeight;
101 }
102 
103 //
104 //  Subdividing edge sharpness values (vertex sharpness is inline):
105 //
106 float
SubdivideEdgeSharpnessAtVertex(float edgeSharpness,int incEdgeCountAtVertex,float const * incEdgeSharpness) const107 Crease::SubdivideEdgeSharpnessAtVertex(float         edgeSharpness,
108                                        int           incEdgeCountAtVertex,
109                                        float const * incEdgeSharpness) const {
110 
111     if (IsUniform() || (incEdgeCountAtVertex < 2)) {
112         return decrementSharpness(edgeSharpness);
113     }
114 
115     if (IsSmooth(edgeSharpness)) return Crease::SHARPNESS_SMOOTH;
116     if (IsInfinite(edgeSharpness)) return Crease::SHARPNESS_INFINITE;
117 
118     float sharpSum   = 0.0f;
119     int   sharpCount = 0;
120     for (int i = 0; i < incEdgeCountAtVertex; ++i) {
121         if (IsSemiSharp(incEdgeSharpness[i])) {
122             sharpCount ++;
123             sharpSum += incEdgeSharpness[i];
124         }
125     }
126     if (sharpCount > 1) {
127         //  Chaikin rule is 3/4 original sharpness + 1/4 average of the others
128 
129         float avgSharpnessAtVertex = (sharpSum - edgeSharpness) / (float)(sharpCount - 1);
130 
131         edgeSharpness = (0.75f * edgeSharpness) + (0.25f * avgSharpnessAtVertex);
132     }
133     edgeSharpness -= 1.0f;
134     return IsSharp(edgeSharpness) ? edgeSharpness : Crease::SHARPNESS_SMOOTH;
135 }
136 
137 void
SubdivideEdgeSharpnessesAroundVertex(int edgeCount,float const * parentSharpness,float * childSharpness) const138 Crease::SubdivideEdgeSharpnessesAroundVertex(int          edgeCount,
139                                                 float const* parentSharpness,
140                                                 float *      childSharpness) const {
141 
142     if (IsUniform() || (edgeCount < 2)) {
143         for (int i = 0; i < edgeCount; ++i) {
144             childSharpness[i] = decrementSharpness(parentSharpness[i]);
145         }
146         return;
147     }
148 
149     //
150     //  Chaikin creasing is most efficiently computed for all edges around a vertex at
151     //  once as the subdivided value for each creased edge depends on the average of
152     //  the other edges around the vertex.  So we can sum up the sharpness around the
153     //  vertex once and use that for each edge, rather than iterating around the vertex
154     //  for each incident edge.
155     //
156     if (_options.GetCreasingMethod() == Options::CREASE_CHAIKIN) {
157         float sharpSum   = 0.0f;
158         int   sharpCount = 0;
159         for (int i = 0; i < edgeCount; ++i) {
160             if (IsSemiSharp(parentSharpness[i])) {
161                 sharpCount ++;
162                 sharpSum += parentSharpness[i];
163             }
164         }
165 
166         //
167         //  The smooth case is most common -- specialize for it first:
168         //
169         if (sharpCount == 0) {
170             for (int i = 0; i < edgeCount; ++i) {
171                 childSharpness[i] = parentSharpness[i];
172             }
173         } else {
174             for (int i = 0; i < edgeCount; ++i) {
175                 float const& pSharp = parentSharpness[i];
176                 float&       cSharp = childSharpness[i];
177 
178                 if (IsSmooth(pSharp)) {
179                     cSharp = Crease::SHARPNESS_SMOOTH;
180                 } else if (IsInfinite(pSharp)) {
181                     cSharp = Crease::SHARPNESS_INFINITE;
182                 } else if (sharpCount == 1) {
183                     //  Need special case here anyway to avoid divide by zero below...
184                     cSharp = decrementSharpness(pSharp);
185                 } else {
186                     float pOtherAverage = (sharpSum - pSharp) / (float)(sharpCount - 1);
187 
188                     //  Chaikin rule is 3/4 original sharpness + 1/4 average of the others
189                     cSharp = ((0.75f * pSharp) + (0.25f * pOtherAverage)) - 1.0f;
190                     if (IsSmooth(cSharp)) cSharp = Crease::SHARPNESS_SMOOTH;
191                 }
192             }
193         }
194     }
195 }
196 
197 } // end namespace sdc
198 
199 } // end namespace OPENSUBDIV_VERSION
200 } // end namespace OpenSubdiv
201