1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27
28 #if ENABLE(ACCELERATED_2D_CANVAS)
29
30 #include "LoopBlinnTextureCoords.h"
31
32 #include <math.h>
33 #include <wtf/Assertions.h>
34
35 namespace WebCore {
36
compute(const LoopBlinnClassifier::Result & classification,LoopBlinnConstants::FillSide sideToFill)37 LoopBlinnTextureCoords::Result LoopBlinnTextureCoords::compute(const LoopBlinnClassifier::Result& classification, LoopBlinnConstants::FillSide sideToFill)
38 {
39 // Loop and Blinn's formulation states that the right side of the
40 // curve is defined to be the inside (filled region), but for some
41 // reason it looks like with the default orientation parameters we
42 // are filling the left side of the curve. Regardless, because we
43 // can receive arbitrarily oriented curves as input, we might have
44 // to reverse the orientation of the cubic texture coordinates even
45 // in cases where the paper doesn't say it is necessary.
46 bool reverseOrientation = false;
47 static const float OneThird = 1.0f / 3.0f;
48 static const float TwoThirds = 2.0f / 3.0f;
49 LoopBlinnClassifier::CurveType curveType = classification.curveType;
50
51 LoopBlinnTextureCoords::Result result;
52
53 switch (curveType) {
54 case LoopBlinnClassifier::kSerpentine: {
55 float t1 = sqrtf(9.0f * classification.d2 * classification.d2 - 12 * classification.d1 * classification.d3);
56 float ls = 3.0f * classification.d2 - t1;
57 float lt = 6.0f * classification.d1;
58 float ms = 3.0f * classification.d2 + t1;
59 float mt = lt;
60 float ltMinusLs = lt - ls;
61 float mtMinusMs = mt - ms;
62 result.klmCoordinates[0] = FloatPoint3D(ls * ms,
63 ls * ls * ls,
64 ms * ms * ms);
65 result.klmCoordinates[1] = FloatPoint3D(OneThird * (3.0f * ls * ms - ls * mt - lt * ms),
66 ls * ls * (ls - lt),
67 ms * ms * (ms - mt));
68 result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)),
69 ltMinusLs * ltMinusLs * ls,
70 mtMinusMs * mtMinusMs * ms);
71 result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs,
72 -(ltMinusLs * ltMinusLs * ltMinusLs),
73 -(mtMinusMs * mtMinusMs * mtMinusMs));
74 if (classification.d1 < 0.0f)
75 reverseOrientation = true;
76 break;
77 }
78
79 case LoopBlinnClassifier::kLoop: {
80 float t1 = sqrtf(4.0f * classification.d1 * classification.d3 - 3.0f * classification.d2 * classification.d2);
81 float ls = classification.d2 - t1;
82 float lt = 2.0f * classification.d1;
83 float ms = classification.d2 + t1;
84 float mt = lt;
85
86 // Figure out whether there is a rendering artifact requiring
87 // the curve to be subdivided by the caller.
88 float ql = ls / lt;
89 float qm = ms / mt;
90 if (0.0f < ql && ql < 1.0f) {
91 result.hasRenderingArtifact = true;
92 result.subdivisionParameterValue = ql;
93 return result;
94 }
95
96 if (0.0f < qm && qm < 1.0f) {
97 result.hasRenderingArtifact = true;
98 result.subdivisionParameterValue = qm;
99 return result;
100 }
101
102 float ltMinusLs = lt - ls;
103 float mtMinusMs = mt - ms;
104 result.klmCoordinates[0] = FloatPoint3D(ls * ms,
105 ls * ls * ms,
106 ls * ms * ms);
107 result.klmCoordinates[1] = FloatPoint3D(OneThird * (-ls * mt - lt * ms + 3.0f * ls * ms),
108 -OneThird * ls * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms),
109 -OneThird * ms * (ls * (2.0f * mt - 3.0f * ms) + lt * ms));
110 result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)),
111 OneThird * (lt - ls) * (ls * (2.0f * mt - 3.0f * ms) + lt * ms),
112 OneThird * (mt - ms) * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms));
113 result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs,
114 -(ltMinusLs * ltMinusLs) * mtMinusMs,
115 -ltMinusLs * mtMinusMs * mtMinusMs);
116 reverseOrientation = ((classification.d1 > 0.0f && result.klmCoordinates[0].x() < 0.0f)
117 || (classification.d1 < 0.0f && result.klmCoordinates[0].x() > 0.0f));
118 break;
119 }
120
121 case LoopBlinnClassifier::kCusp: {
122 float ls = classification.d3;
123 float lt = 3.0f * classification.d2;
124 float lsMinusLt = ls - lt;
125 result.klmCoordinates[0] = FloatPoint3D(ls,
126 ls * ls * ls,
127 1.0f);
128 result.klmCoordinates[1] = FloatPoint3D(ls - OneThird * lt,
129 ls * ls * lsMinusLt,
130 1.0f);
131 result.klmCoordinates[2] = FloatPoint3D(ls - TwoThirds * lt,
132 lsMinusLt * lsMinusLt * ls,
133 1.0f);
134 result.klmCoordinates[3] = FloatPoint3D(lsMinusLt,
135 lsMinusLt * lsMinusLt * lsMinusLt,
136 1.0f);
137 break;
138 }
139
140 case LoopBlinnClassifier::kQuadratic: {
141 result.klmCoordinates[0] = FloatPoint3D(0, 0, 0);
142 result.klmCoordinates[1] = FloatPoint3D(OneThird, 0, OneThird);
143 result.klmCoordinates[2] = FloatPoint3D(TwoThirds, OneThird, TwoThirds);
144 result.klmCoordinates[3] = FloatPoint3D(1, 1, 1);
145 if (classification.d3 < 0)
146 reverseOrientation = true;
147 break;
148 }
149
150 case LoopBlinnClassifier::kLine:
151 case LoopBlinnClassifier::kPoint:
152 result.isLineOrPoint = true;
153 break;
154
155 default:
156 ASSERT_NOT_REACHED();
157 break;
158 }
159
160 if (sideToFill == LoopBlinnConstants::RightSide)
161 reverseOrientation = !reverseOrientation;
162
163 if (reverseOrientation) {
164 for (int i = 0; i < 4; ++i) {
165 result.klmCoordinates[i].setX(-result.klmCoordinates[i].x());
166 result.klmCoordinates[i].setY(-result.klmCoordinates[i].y());
167 }
168 }
169
170 return result;
171 }
172
173 } // namespace WebCore
174
175 #endif
176