1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 #include "shadowutils.h"
16
17 #include <array>
18 #include <native_drawing/drawing_brush.h>
19 #include <native_drawing/drawing_color.h>
20 #include <native_drawing/drawing_matrix.h>
21 #include <native_drawing/drawing_path.h>
22 #include <native_drawing/drawing_pen.h>
23 #include <native_drawing/drawing_point.h>
24 #include <native_drawing/drawing_round_rect.h>
25 #include <native_drawing/drawing_shader_effect.h>
26 #include <vector>
27
28 #include "test_common.h"
29
30 #include "common/log_common.h"
31
32 enum { K_W = 800, K_H = 960 };
33 const uint32_t AMBIENT_COLOR = OH_Drawing_ColorSetArgb(0.1 * 255, 0, 0, 0); // 0.1 * 255 ambientColor
34 const uint32_t SPOT_COLOR = OH_Drawing_ColorSetArgb(0.25 * 255, 0, 0, 0); // 0.25 * 255 spotColor
35 typedef struct {
36 float height;
37 uint32_t color;
38 OH_Drawing_Point3D lightPos;
39 float lightR;
40 bool isAmbient;
41 OH_Drawing_CanvasShadowFlags flags;
42 } DRAW_PARAM;
43
44 typedef struct {
45 std::vector<OH_Drawing_Path*>& paths;
46 std::vector<DrawRect>& pathsBounds;
47 std::vector<OH_Drawing_Matrix*>& matrices;
48 ShadowUtils::ShadowMode mode;
49 OH_Drawing_Point3D lightPos;
50 float kHeight;
51 float kLightR;
52 float kPad;
53 float dy;
54 float x;
55 OH_Drawing_CanvasShadowFlags flags;
56 OH_Drawing_Matrix* m;
57 } DRAW_RECT_PARAM;
58
draw_shadow(OH_Drawing_Canvas * canvas,OH_Drawing_Path * path,DRAW_PARAM param)59 void draw_shadow(OH_Drawing_Canvas* canvas, OH_Drawing_Path* path, DRAW_PARAM param)
60 {
61 float height = param.height;
62 uint32_t color = param.color;
63 OH_Drawing_Point3D lightPos = param.lightPos;
64 float lightR = param.lightR;
65 bool isAmbient = param.isAmbient;
66 OH_Drawing_CanvasShadowFlags flags = param.flags;
67
68 float ambientAlpha = isAmbient ? 0.5f : 0.f; // 0.5f ambient alpha
69 float spotAlpha = isAmbient ? 0.f : 0.5f; // 0.5f spot alpha
70 uint8_t a = (color >> 24) & 0xFF; // 24 颜色值 偏移量
71 uint8_t r = (color >> 16) & 0xFF; // 16 颜色值 偏移量
72 uint8_t g = (color >> 8) & 0xFF; // 8 颜色值 偏移量
73 uint8_t b = color & 0xFF;
74
75 uint32_t ambientColor = OH_Drawing_ColorSetArgb(a * ambientAlpha, r, g, b);
76 uint32_t spotColor = OH_Drawing_ColorSetArgb(a * spotAlpha, r, g, b);
77 OH_Drawing_Point3D planeParams = { 0, 0, height };
78
79 OH_Drawing_CanvasDrawShadow(canvas, path, planeParams, lightPos, lightR, ambientColor, spotColor, flags);
80 }
81
make_path_rect(std::vector<OH_Drawing_Path * > & paths,std::vector<DrawRect> & pathsBounds)82 void make_path_rect(std::vector<OH_Drawing_Path*>& paths, std::vector<DrawRect>& pathsBounds)
83 {
84 float rSize = 50.f;
85 // add rrect
86 OH_Drawing_Path* path1 = OH_Drawing_PathCreate();
87 OH_Drawing_Rect* rect = OH_Drawing_RectCreate(0, 0, rSize, rSize);
88 OH_Drawing_RoundRect* roundRect = OH_Drawing_RoundRectCreate(rect, 10.f, 10.00002f); // 10.f, 10.00002f 圆角矩形rad
89 OH_Drawing_PathAddRoundRect(path1, roundRect, OH_Drawing_PathDirection::PATH_DIRECTION_CCW);
90 paths.push_back(path1);
91 pathsBounds.push_back({ 0, 0, rSize, rSize });
92
93 // add rrect 这里应该是不规则的圆角矩形,四个圆角不同,oh暂不支持,先用普通圆角代替
94 OH_Drawing_RoundRect* addRRect = OH_Drawing_RoundRectCreate(rect, 9.f, 13.f); // 9.f, 13.f 圆角矩形rad
95 OH_Drawing_Path* path2 = OH_Drawing_PathCreate();
96 OH_Drawing_PathAddRoundRect(path2, addRRect, OH_Drawing_PathDirection::PATH_DIRECTION_CCW);
97 paths.push_back(path2);
98 pathsBounds.push_back({ 0, 0, rSize, rSize });
99 OH_Drawing_RoundRectDestroy(addRRect);
100
101 // add rect
102 OH_Drawing_Path* path3 = OH_Drawing_PathCreate();
103 OH_Drawing_PathAddRect(path3, 0, 0, rSize, rSize, OH_Drawing_PathDirection::PATH_DIRECTION_CCW);
104 paths.push_back(path3);
105 pathsBounds.push_back({ 0, 0, rSize, rSize });
106
107 // add circle
108 OH_Drawing_Path* path4 = OH_Drawing_PathCreate();
109 OH_Drawing_PathAddArc(path4, rect, 0, 360.f); // 360.f 旋转角度
110 paths.push_back(path4);
111 pathsBounds.push_back({ 0, 0, rSize, rSize });
112 OH_Drawing_RectDestroy(rect);
113
114 OH_Drawing_Path* path5 = OH_Drawing_PathCreate();
115 OH_Drawing_PathCubicTo(path5, 100, 50, 20, 100, 0, 0); // 100, 50, 20, 100, 0, 0 gm 要求的图形坐标
116 paths.push_back(path5);
117 pathsBounds.push_back({ 0, 0, 100.f, 100.f }); // 100.f, 100.f 矩形参数
118
119 // add oval
120 OH_Drawing_Path* path6 = OH_Drawing_PathCreate();
121 rect = OH_Drawing_RectCreate(0, 0, 20.f, 60.f); // 20.f, 60.f 矩形参数
122 OH_Drawing_PathAddArc(path6, rect, 0, 360.f); // 360.f 旋转角度
123 paths.push_back(path6);
124 pathsBounds.push_back({ 0, 0, 20.f, 60.f }); // 20.f, 60.f 矩形参数
125 OH_Drawing_RectDestroy(rect);
126 }
127
make_path_star(std::vector<OH_Drawing_Path * > & paths,std::vector<DrawRect> & pathsBounds)128 void make_path_star(std::vector<OH_Drawing_Path*>& paths, std::vector<DrawRect>& pathsBounds)
129 {
130 OH_Drawing_Path* path = OH_Drawing_PathCreate();
131 path = OH_Drawing_PathCreate();
132 OH_Drawing_PathMoveTo(path, 0.0, -33.3333); // 0.0, -33.3333 gm 要求的图形坐标
133 OH_Drawing_PathLineTo(path, 9.62, -16.6667); // 9.62, -16.6667 gm 要求的图形坐标
134 OH_Drawing_PathLineTo(path, 28.867f, -16.6667f); // 28.867f, -16.6667f gm 要求的图形坐标
135 OH_Drawing_PathLineTo(path, 19.24f, 0.0f); // 19.24f, 0.0f gm 要求的图形坐标
136 OH_Drawing_PathLineTo(path, 28.867f, 16.6667f); // 28.867f, 16.6667f gm 要求的图形坐标
137 OH_Drawing_PathLineTo(path, 9.62f, 16.6667f); // 9.62f, 16.6667f gm 要求的图形坐标
138 OH_Drawing_PathLineTo(path, 0.0f, 33.3333f); // 0.0f, 33.3333f gm 要求的图形坐标
139 OH_Drawing_PathLineTo(path, -9.62f, 16.6667f); // -9.62f, 16.6667f gm 要求的图形坐标
140 OH_Drawing_PathLineTo(path, -28.867f, 16.6667f); // -28.867f, 16.6667f gm 要求的图形坐标
141 OH_Drawing_PathLineTo(path, -19.24f, 0.0f); // -19.24f, 0.0f gm 要求的图形坐标
142 OH_Drawing_PathLineTo(path, -28.867f, -16.6667f); // -28.867f, -16.6667f gm 要求的图形坐标
143 OH_Drawing_PathLineTo(path, -9.62f, -16.6667f); // -9.62f, -16.6667f gm 要求的图形坐标
144 OH_Drawing_PathClose(path);
145 paths.push_back(path);
146 pathsBounds.push_back(
147 { -28.867f, -33.3333, 28.867f, 33.3333f }); // -28.867f, -33.3333, 28.867f, 33.3333f gm 要求的图形坐
148
149 // dumbbell
150 OH_Drawing_Path* path1 = OH_Drawing_PathCreate();
151 OH_Drawing_PathMoveTo(path1, 50.0, 0); // 50.0, 0 gm 要求的图形坐标
152 OH_Drawing_PathCubicTo(path1, 100, 25, 60, 50, 50, 0); // 100, 25, 60, 50, 50, 0 gm 要求的图形坐标
153 OH_Drawing_PathCubicTo(path1, 0, -25, 40, -50, 50, 0); // 0, -25, 40, -50, 50, 0 gm 要求的图形坐标
154 paths.push_back(path1);
155 pathsBounds.push_back({ 0, -50, 100, 50 }); // 0, -50, 100, 50 gm 要求的图形坐标
156 }
157
destory_path(std::vector<OH_Drawing_Path * > & paths,std::vector<OH_Drawing_Path * > & concavePaths,std::vector<OH_Drawing_Matrix * > & matrices)158 void destory_path(std::vector<OH_Drawing_Path*>& paths, std::vector<OH_Drawing_Path*>& concavePaths,
159 std::vector<OH_Drawing_Matrix*>& matrices)
160 {
161 for (auto p : paths) {
162 OH_Drawing_PathDestroy(p);
163 }
164 for (auto p : concavePaths) {
165 OH_Drawing_PathDestroy(p);
166 }
167 for (auto m : matrices) {
168 OH_Drawing_MatrixDestroy(m);
169 }
170 paths.clear();
171 concavePaths.clear();
172 matrices.clear();
173 }
174
draw_rect_path(OH_Drawing_Canvas * canvas,OH_Drawing_Path * path,ShadowUtils::ShadowMode mode,OH_Drawing_CanvasShadowFlags flags)175 void draw_rect_path(
176 OH_Drawing_Canvas* canvas, OH_Drawing_Path* path, ShadowUtils::ShadowMode mode, OH_Drawing_CanvasShadowFlags flags)
177 {
178 OH_Drawing_Brush* brush = OH_Drawing_BrushCreate();
179 OH_Drawing_BrushSetAntiAlias(brush, true);
180 OH_Drawing_Pen* pen = OH_Drawing_PenCreate();
181 OH_Drawing_PenSetAntiAlias(pen, true);
182 if (ShadowUtils::K_NO_OCCLUDERS == mode) {
183 if (flags & SHADOW_FLAGS_TRANSPARENT_OCCLUDER) {
184 OH_Drawing_PenSetColor(pen, 0xFF00FFFF); // SK_ColorCYAN
185 } else {
186 OH_Drawing_PenSetColor(pen, 0xFF00FF00); // SK_ColorGREEN
187 }
188 OH_Drawing_PenSetWidth(pen, 0);
189 OH_Drawing_CanvasAttachPen(canvas, pen);
190 } else {
191 OH_Drawing_BrushSetColor(brush, ShadowUtils::K_OCCLUDERS == mode ? 0xFFCCCCCC : 0xFFFFFFFF);
192 if (flags & SHADOW_FLAGS_TRANSPARENT_OCCLUDER)
193 OH_Drawing_BrushSetAlpha(brush, 0x80); // 0.5 alpha
194 OH_Drawing_CanvasAttachBrush(canvas, brush);
195 }
196 OH_Drawing_CanvasDrawPath(canvas, path);
197 OH_Drawing_CanvasDetachPen(canvas);
198 OH_Drawing_CanvasDetachBrush(canvas);
199 OH_Drawing_PenDestroy(pen);
200 OH_Drawing_BrushDestroy(brush);
201 }
202
draw_rect_path_shadow(OH_Drawing_Canvas * canvas,DRAW_RECT_PARAM & param,float & dy,float & x)203 void draw_rect_path_shadow(OH_Drawing_Canvas* canvas, DRAW_RECT_PARAM& param, float& dy, float& x)
204 {
205 ShadowUtils::ShadowMode mode = param.mode;
206 OH_Drawing_Point3D lightPos = param.lightPos;
207 float kHeight = param.kHeight;
208 float kLightR = param.kLightR;
209 float kPad = param.kPad;
210 OH_Drawing_CanvasShadowFlags flags = param.flags;
211 OH_Drawing_Matrix* m = param.m;
212 int pathCounter = 0;
213 for (const auto path : param.paths) {
214 DrawRect pathBound = param.pathsBounds[pathCounter];
215 float dx = pathBound.Width() + kHeight + kPad;
216 if (x + dx > K_W - 3 * kPad) { // 3倍间距
217 OH_Drawing_CanvasRestore(canvas);
218 OH_Drawing_CanvasTranslate(canvas, 0, dy);
219 OH_Drawing_CanvasSave(canvas);
220 x = 0;
221 dy = 0;
222 }
223 OH_Drawing_CanvasSave(canvas);
224 OH_Drawing_CanvasConcatMatrix(canvas, m);
225 if (SHADOW_FLAGS_TRANSPARENT_OCCLUDER == flags && 0 == pathCounter % 3) { // 3个图形换行
226 OH_Drawing_CanvasSave(canvas);
227 OH_Drawing_CanvasRotate(canvas, 180.f, 25.f, 25.f); // 180.f 旋转角度, 25.f x偏移 , 25.f y偏移
228 }
229 if (ShadowUtils::K_NO_OCCLUDERS == mode || ShadowUtils::K_OCCLUDERS == mode) {
230 draw_shadow(canvas, path, { kHeight, 0xFFFF0000, lightPos, kLightR, true, flags });
231 draw_shadow(canvas, path, { kHeight, 0xFF0000FF, lightPos, kLightR, false, flags });
232 } else if (ShadowUtils::K_GRAY_SCALE == mode) {
233 OH_Drawing_CanvasDrawShadow(
234 canvas, path, { 0, 0, kHeight }, lightPos, kLightR, AMBIENT_COLOR, SPOT_COLOR, flags);
235 }
236 draw_rect_path(canvas, path, mode, flags);
237 if (SHADOW_FLAGS_TRANSPARENT_OCCLUDER == flags && 0 == pathCounter % 3) { // 3个图形换行
238 OH_Drawing_CanvasRestore(canvas);
239 }
240 OH_Drawing_CanvasRestore(canvas);
241 OH_Drawing_CanvasTranslate(canvas, dx, 0);
242 x += dx;
243 dy = std::max(dy, pathBound.Height() + kPad + kHeight);
244 ++pathCounter;
245 }
246 }
247
draw_rect(OH_Drawing_Canvas * canvas,DRAW_RECT_PARAM & param)248 void draw_rect(OH_Drawing_Canvas* canvas, DRAW_RECT_PARAM& param)
249 {
250 float dy = 0;
251 float x = 0;
252 for (auto m : param.matrices) {
253 for (OH_Drawing_CanvasShadowFlags flags : { SHADOW_FLAGS_NONE, SHADOW_FLAGS_TRANSPARENT_OCCLUDER }) {
254 param.flags = flags;
255 param.m = m;
256 draw_rect_path_shadow(canvas, param, dy, x);
257 }
258 }
259 }
260
draw_star(OH_Drawing_Canvas * canvas,DRAW_RECT_PARAM & param)261 void draw_star(OH_Drawing_Canvas* canvas, DRAW_RECT_PARAM& param)
262 {
263 ShadowUtils::ShadowMode mode = param.mode;
264 OH_Drawing_Point3D lightPos = param.lightPos;
265 float kHeight = param.kHeight;
266 float kLightR = param.kLightR;
267 float kPad = param.kPad;
268 float x = kPad;
269 float dy = 0;
270 for (auto m : param.matrices) {
271 int pathCounter = 0;
272 for (const auto path : param.paths) {
273 DrawRect pathBounds = param.pathsBounds[pathCounter];
274 float dx = pathBounds.Width() + kHeight + kPad;
275 OH_Drawing_CanvasSave(canvas);
276 OH_Drawing_CanvasConcatMatrix(canvas, m);
277 if (ShadowUtils::K_NO_OCCLUDERS == mode || ShadowUtils::K_OCCLUDERS == mode) {
278 draw_shadow(canvas, path, { kHeight, 0xFFFF0000, lightPos, kLightR, true, SHADOW_FLAGS_NONE });
279 draw_shadow(canvas, path, { kHeight, 0xFF0000FF, lightPos, kLightR, false, SHADOW_FLAGS_NONE });
280 } else if (ShadowUtils::K_GRAY_SCALE == mode) {
281 OH_Drawing_CanvasDrawShadow(
282 canvas, path, { 0, 0, kHeight }, lightPos, kLightR, AMBIENT_COLOR, SPOT_COLOR, SHADOW_FLAGS_NONE);
283 }
284 OH_Drawing_Brush* brush = OH_Drawing_BrushCreate();
285 OH_Drawing_BrushSetAntiAlias(brush, true);
286 OH_Drawing_Pen* pen = OH_Drawing_PenCreate();
287 OH_Drawing_PenSetAntiAlias(pen, true);
288 if (ShadowUtils::K_NO_OCCLUDERS == mode) {
289 OH_Drawing_PenSetColor(pen, 0xFF00FF00);
290 OH_Drawing_PenSetWidth(pen, 0);
291 OH_Drawing_CanvasAttachPen(canvas, pen);
292 } else {
293 OH_Drawing_BrushSetColor(brush,
294 ShadowUtils::K_OCCLUDERS == mode ? 0xFFCCCCCC : 0xFFFFFFFF); // SK_ColorLTGRAY : SK_ColorWHITE
295 OH_Drawing_CanvasAttachBrush(canvas, brush);
296 }
297 OH_Drawing_CanvasDrawPath(canvas, path);
298 OH_Drawing_CanvasDetachPen(canvas);
299 OH_Drawing_CanvasDetachBrush(canvas);
300 OH_Drawing_PenDestroy(pen);
301 OH_Drawing_BrushDestroy(brush);
302 OH_Drawing_CanvasRestore(canvas);
303 OH_Drawing_CanvasTranslate(canvas, dx, 0);
304 x += dx;
305 dy = std::max(dy, pathBounds.Height() + kPad + kHeight);
306 pathCounter++;
307 }
308 }
309 }
310
draw_black_point(OH_Drawing_Canvas * canvas,OH_Drawing_Point3D lightPos,float kLightR)311 void draw_black_point(OH_Drawing_Canvas* canvas, OH_Drawing_Point3D lightPos, float kLightR)
312 {
313 OH_Drawing_Matrix* invCanvasM = OH_Drawing_MatrixCreate();
314 OH_Drawing_CanvasGetTotalMatrix(canvas, invCanvasM);
315 OH_Drawing_Matrix* invert = OH_Drawing_MatrixCreate();
316
317 bool ret1 = OH_Drawing_MatrixIsIdentity(invCanvasM);
318 bool ret2 = OH_Drawing_MatrixInvert(invCanvasM, invert);
319 if (ret1 || ret2) {
320 if (ret1)
321 OH_Drawing_MatrixSetMatrix(invCanvasM, 1, 0, 0, 0, 1, 0, 0, 0, 1); // 1, 0, 0, 0, 1, 0, 0, 0, 1 单位矩阵
322 OH_Drawing_CanvasSave(canvas);
323 OH_Drawing_CanvasConcatMatrix(canvas, invert);
324 OH_Drawing_Brush* brush = OH_Drawing_BrushCreate();
325 OH_Drawing_BrushSetAntiAlias(brush, true);
326 OH_Drawing_BrushSetColor(brush, 0xFF000000);
327 OH_Drawing_CanvasAttachBrush(canvas, brush);
328 OH_Drawing_Point* center = OH_Drawing_PointCreate(lightPos.x, lightPos.y);
329 float fDiv = 10.f;
330 OH_Drawing_CanvasDrawCircle(canvas, center, kLightR / fDiv);
331 OH_Drawing_CanvasDetachBrush(canvas);
332 OH_Drawing_BrushDestroy(brush);
333 OH_Drawing_CanvasRestore(canvas);
334 }
335 }
ShadowUtils(ShadowMode m)336 ShadowUtils::ShadowUtils(ShadowMode m) : sMode(m)
337 {
338 bitmapWidth_ = K_W;
339 bitmapHeight_ = K_H;
340 fileName_ = "shadow_utils";
341 }
342
OnTestFunction(OH_Drawing_Canvas * canvas)343 void ShadowUtils::OnTestFunction(OH_Drawing_Canvas* canvas)
344 {
345 draw_paths(canvas, sMode);
346 }
347
draw_paths(OH_Drawing_Canvas * canvas,ShadowMode mode)348 void ShadowUtils::draw_paths(OH_Drawing_Canvas* canvas, ShadowMode mode)
349 {
350 // rect
351 std::vector<OH_Drawing_Path*> paths;
352 std::vector<DrawRect> pathsBounds;
353 make_path_rect(paths, pathsBounds);
354
355 // star
356 std::vector<OH_Drawing_Path*> concavePaths;
357 std::vector<DrawRect> concavePathsBounds;
358 make_path_star(concavePaths, concavePathsBounds);
359
360 static constexpr float kPad = 15.f;
361 static constexpr float kLightR = 100.f;
362 static constexpr float kHeight = 50.f;
363
364 // transform light position relative to canvas to handle tiling
365 OH_Drawing_Point2D lightXY = { 250.f, 400.f }; // 250.f, 400.f 坐标参数
366 OH_Drawing_Point3D lightPos = { lightXY.x, lightXY.y, 500.f }; // 500.f 坐标参数
367
368 OH_Drawing_CanvasTranslate(canvas, 3 * kPad, 3 * kPad); // 3 3 个xy平移单位
369 OH_Drawing_CanvasSave(canvas);
370 float x = 0;
371 float dy = 0;
372 std::vector<OH_Drawing_Matrix*> matrices;
373 OH_Drawing_Matrix* mI = OH_Drawing_MatrixCreate();
374 OH_Drawing_MatrixReset(mI);
375 matrices.push_back(mI);
376
377 OH_Drawing_Matrix* matrix = OH_Drawing_MatrixCreateRotation(33.0, 25.0, 25.0); // 33.0, 25.0, 25.0 gm 要求的矩阵参数
378 OH_Drawing_MatrixPostScale(matrix, 1.2, 0.8, 25.0, 25.0); // 1.2, 0.8, 25.0, 25.0 gm 要求的矩阵参数
379 matrices.push_back(matrix);
380
381 float n = 80;
382 DRAW_RECT_PARAM param = { paths, pathsBounds, matrices, mode, lightPos, kHeight, kLightR, kPad };
383 draw_rect(canvas, param);
384
385 OH_Drawing_CanvasRestore(canvas);
386 OH_Drawing_CanvasTranslate(canvas, 0, 3 * n); // 3个平移单位
387 OH_Drawing_CanvasSave(canvas);
388
389 DRAW_RECT_PARAM concaveParam = { concavePaths, concavePathsBounds, matrices, mode, lightPos, kHeight, kLightR,
390 kPad };
391 draw_star(canvas, concaveParam);
392
393 draw_black_point(canvas, lightPos, kLightR);
394 destory_path(paths, concavePaths, matrices);
395 }