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 }