OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // We would like to use M_PI on windows too. | 5 // We would like to use M_PI on windows too. |
6 #ifdef _WIN32 | 6 #ifdef _WIN32 |
7 #define _USE_MATH_DEFINES | 7 #define _USE_MATH_DEFINES |
8 #endif | 8 #endif |
9 | 9 |
10 #include <stddef.h> | 10 #include <stddef.h> |
11 | 11 |
12 #include <limits> | 12 #include <limits> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "cc/output/bsp_compare_result.h" | 16 #include "cc/output/bsp_compare_result.h" |
17 #include "cc/quads/draw_polygon.h" | 17 #include "cc/quads/draw_polygon.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
19 #include "ui/gfx/transform.h" | 19 #include "ui/gfx/transform.h" |
20 | 20 |
21 namespace cc { | 21 namespace cc { |
22 | 22 |
23 #if !defined(OS_WIN) | 23 #if !defined(OS_WIN) |
24 void DrawPolygon::RecomputeNormalForTesting() { | 24 void DrawPolygon::RecomputeNormalForTesting() { |
25 ConstructNormal(); | 25 ConstructNormal(); |
26 } | 26 } |
27 #endif | 27 #endif |
28 | 28 |
| 29 static int sign(float v) { |
| 30 static const float epsilon = 0.00001f; |
| 31 |
| 32 if (v > epsilon) |
| 33 return 1; |
| 34 if (v < -epsilon) |
| 35 return -1; |
| 36 return 0; |
| 37 } |
| 38 |
| 39 bool IsPlanarForTesting(const DrawPolygon& p) { |
| 40 static const float epsilon = 0.00001f; |
| 41 for (size_t i = 1; i < p.points_.size(); i++) { |
| 42 if (gfx::DotProduct(p.points_[i] - p.points_[0], p.normal_) > epsilon) |
| 43 return false; |
| 44 } |
| 45 return true; |
| 46 } |
| 47 |
| 48 bool IsConvexForTesting(const DrawPolygon& p) { |
| 49 if (p.points_.size() < 3) |
| 50 return true; |
| 51 |
| 52 gfx::Vector3dF prev = |
| 53 p.points_[p.points_.size() - 1] - p.points_[p.points_.size() - 2]; |
| 54 gfx::Vector3dF next = p.points_[0] - p.points_[p.points_.size() - 1]; |
| 55 int ccw = sign(gfx::DotProduct(CrossProduct(prev, next), p.normal_)); |
| 56 for (size_t i = 1; i < p.points_.size(); i++) { |
| 57 prev = next; |
| 58 next = p.points_[i] - p.points_[i - 1]; |
| 59 int next_sign = sign(gfx::DotProduct(CrossProduct(prev, next), p.normal_)); |
| 60 if (ccw == 0) |
| 61 ccw = next_sign; |
| 62 if (next_sign != 0 && next_sign != ccw) |
| 63 return false; |
| 64 } |
| 65 return true; |
| 66 } |
| 67 |
29 namespace { | 68 namespace { |
30 | 69 |
31 #define CREATE_NEW_DRAW_POLYGON(name, points_vector, normal, polygon_id) \ | 70 #define CREATE_NEW_DRAW_POLYGON(name, points_vector, normal, polygon_id) \ |
32 DrawPolygon name(NULL, points_vector, normal, polygon_id) | 71 DrawPolygon name(NULL, points_vector, normal, polygon_id) |
33 | 72 |
34 #define CREATE_NEW_DRAW_POLYGON_PTR(name, points_vector, normal, polygon_id) \ | 73 #define CREATE_NEW_DRAW_POLYGON_PTR(name, points_vector, normal, polygon_id) \ |
35 std::unique_ptr<DrawPolygon> name(base::MakeUnique<DrawPolygon>( \ | 74 std::unique_ptr<DrawPolygon> name(base::MakeUnique<DrawPolygon>( \ |
36 nullptr, points_vector, normal, polygon_id)) | 75 nullptr, points_vector, normal, polygon_id)) |
37 | 76 |
38 #define CREATE_TEST_DRAW_FORWARD_POLYGON(name, points_vector, id) \ | 77 #define CREATE_TEST_DRAW_FORWARD_POLYGON(name, points_vector, id) \ |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 vertices_b.push_back(gfx::Point3F(5.0f, 0.0f, 0.0f)); | 349 vertices_b.push_back(gfx::Point3F(5.0f, 0.0f, 0.0f)); |
311 | 350 |
312 CREATE_NEW_DRAW_POLYGON(polygon_a, vertices_a, | 351 CREATE_NEW_DRAW_POLYGON(polygon_a, vertices_a, |
313 gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0); | 352 gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0); |
314 CREATE_NEW_DRAW_POLYGON(polygon_b, vertices_b, | 353 CREATE_NEW_DRAW_POLYGON(polygon_b, vertices_b, |
315 gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1); | 354 gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1); |
316 | 355 |
317 EXPECT_EQ(BSP_BACK, SideCompare(polygon_b, polygon_a)); | 356 EXPECT_EQ(BSP_BACK, SideCompare(polygon_b, polygon_a)); |
318 } | 357 } |
319 | 358 |
| 359 // One quad intersects a pent with an occluded side. |
| 360 TEST(DrawPolygonSplitTest, SlimClip) { |
| 361 std::vector<gfx::Point3F> vertices_a; |
| 362 vertices_a.push_back(gfx::Point3F(0.0f, 10.0f, 0.0f)); |
| 363 vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); |
| 364 vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f)); |
| 365 vertices_a.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f)); |
| 366 std::vector<gfx::Point3F> vertices_b; |
| 367 vertices_b.push_back(gfx::Point3F(9.0f, 9.0f, 5.000f)); |
| 368 vertices_b.push_back(gfx::Point3F(1.0f, 1.0f, 0.001f)); |
| 369 vertices_b.push_back(gfx::Point3F(1.0f, 1.0f, 0.000f)); |
| 370 vertices_b.push_back(gfx::Point3F(1.002f, 1.002f, -0.005f)); |
| 371 vertices_b.push_back(gfx::Point3F(9.0f, 9.0f, -4.000f)); |
| 372 |
| 373 CREATE_NEW_DRAW_POLYGON_PTR(polygon_a, vertices_a, |
| 374 gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0); |
| 375 CREATE_NEW_DRAW_POLYGON_PTR( |
| 376 polygon_b, vertices_b, |
| 377 gfx::Vector3dF(sqrt(2) / 2, -sqrt(2) / 2, 0.000000), 1); |
| 378 |
| 379 // These are well formed, convex polygons. |
| 380 EXPECT_TRUE(IsPlanarForTesting(*(polygon_a.get()))); |
| 381 EXPECT_TRUE(IsConvexForTesting(*(polygon_a.get()))); |
| 382 EXPECT_TRUE(IsPlanarForTesting(*(polygon_b.get()))); |
| 383 EXPECT_TRUE(IsConvexForTesting(*(polygon_b.get()))); |
| 384 |
| 385 std::unique_ptr<DrawPolygon> front_polygon; |
| 386 std::unique_ptr<DrawPolygon> back_polygon; |
| 387 bool is_coplanar; |
| 388 |
| 389 polygon_a->SplitPolygon(std::move(polygon_b), &front_polygon, &back_polygon, |
| 390 &is_coplanar); |
| 391 |
| 392 EXPECT_FALSE(is_coplanar); |
| 393 EXPECT_TRUE(front_polygon != nullptr); |
| 394 EXPECT_TRUE(back_polygon != nullptr); |
| 395 } |
| 396 |
320 // One quad intersects another and becomes two pieces. | 397 // One quad intersects another and becomes two pieces. |
321 TEST(DrawPolygonSplitTest, BasicSplit) { | 398 TEST(DrawPolygonSplitTest, BasicSplit) { |
322 std::vector<gfx::Point3F> vertices_a; | 399 std::vector<gfx::Point3F> vertices_a; |
323 vertices_a.push_back(gfx::Point3F(0.0f, 10.0f, 0.0f)); | 400 vertices_a.push_back(gfx::Point3F(0.0f, 10.0f, 0.0f)); |
324 vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); | 401 vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); |
325 vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f)); | 402 vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f)); |
326 vertices_a.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f)); | 403 vertices_a.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f)); |
327 std::vector<gfx::Point3F> vertices_b; | 404 std::vector<gfx::Point3F> vertices_b; |
328 vertices_b.push_back(gfx::Point3F(5.0f, 10.0f, -5.0f)); | 405 vertices_b.push_back(gfx::Point3F(5.0f, 10.0f, -5.0f)); |
329 vertices_b.push_back(gfx::Point3F(5.0f, 0.0f, -5.0f)); | 406 vertices_b.push_back(gfx::Point3F(5.0f, 0.0f, -5.0f)); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 test_points_b.push_back(gfx::Point3F(1.0f, 0.0f, 0.0f)); | 476 test_points_b.push_back(gfx::Point3F(1.0f, 0.0f, 0.0f)); |
400 test_points_b.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); | 477 test_points_b.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); |
401 test_points_b.push_back(gfx::Point3F(0.0f, 0.0f, 10.0f)); | 478 test_points_b.push_back(gfx::Point3F(0.0f, 0.0f, 10.0f)); |
402 test_points_b.push_back(gfx::Point3F(10.0f, 0.0f, 10.0f)); | 479 test_points_b.push_back(gfx::Point3F(10.0f, 0.0f, 10.0f)); |
403 test_points_b.push_back(gfx::Point3F(10.0f, 0.0f, 9.0f)); | 480 test_points_b.push_back(gfx::Point3F(10.0f, 0.0f, 9.0f)); |
404 | 481 |
405 ValidatePointsWithinDeltaOf(*(front_polygon.get()), test_points_a, 1e-6f); | 482 ValidatePointsWithinDeltaOf(*(front_polygon.get()), test_points_a, 1e-6f); |
406 ValidatePointsWithinDeltaOf(*(back_polygon.get()), test_points_b, 1e-6f); | 483 ValidatePointsWithinDeltaOf(*(back_polygon.get()), test_points_b, 1e-6f); |
407 } | 484 } |
408 | 485 |
| 486 // In this test we cut the corner of a quad so that it creates a triangle and |
| 487 // a pentagon as a result, and then cut the pentagon. |
| 488 TEST(DrawPolygonSplitTest, DoubleSplit) { |
| 489 std::vector<gfx::Point3F> vertices_a; |
| 490 vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); |
| 491 vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 10.0f)); |
| 492 vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 10.0f)); |
| 493 vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f)); |
| 494 std::vector<gfx::Point3F> vertices_b; |
| 495 vertices_b.push_back(gfx::Point3F(2.0f, 5.0f, 1.0f)); |
| 496 vertices_b.push_back(gfx::Point3F(2.0f, -5.0f, 1.0f)); |
| 497 vertices_b.push_back(gfx::Point3F(-1.0f, -5.0f, -2.0f)); |
| 498 vertices_b.push_back(gfx::Point3F(-1.0f, 5.0f, -2.0f)); |
| 499 |
| 500 CREATE_NEW_DRAW_POLYGON_PTR(polygon_a, vertices_a, |
| 501 gfx::Vector3dF(0.0f, 1.0f, 0.0f), 0); |
| 502 CREATE_NEW_DRAW_POLYGON_PTR(polygon_b, vertices_b, |
| 503 gfx::Vector3dF(sqrt(2) / 2, 0.0f, -sqrt(2) / 2), |
| 504 1); |
| 505 |
| 506 std::unique_ptr<DrawPolygon> front_polygon; |
| 507 std::unique_ptr<DrawPolygon> back_polygon; |
| 508 bool is_coplanar; |
| 509 |
| 510 polygon_b->SplitPolygon(std::move(polygon_a), &front_polygon, &back_polygon, |
| 511 &is_coplanar); |
| 512 EXPECT_FALSE(is_coplanar); |
| 513 EXPECT_TRUE(front_polygon != nullptr); |
| 514 EXPECT_TRUE(back_polygon != nullptr); |
| 515 |
| 516 EXPECT_EQ(3u, front_polygon->points().size()); |
| 517 EXPECT_EQ(5u, back_polygon->points().size()); |
| 518 |
| 519 std::vector<gfx::Point3F> vertices_c; |
| 520 vertices_c.push_back(gfx::Point3F(0.0f, 0.0f, 10.0f)); |
| 521 vertices_c.push_back(gfx::Point3F(1.0f, -0.05f, 0.0f)); |
| 522 vertices_c.push_back(gfx::Point3F(10.0f, 0.05f, 9.0f)); |
| 523 |
| 524 CREATE_NEW_DRAW_POLYGON_PTR(polygon_c, vertices_c, |
| 525 gfx::Vector3dF(0.0055f, -0.999f, 0.0055f), 0); |
| 526 |
| 527 std::unique_ptr<DrawPolygon> second_front_polygon; |
| 528 std::unique_ptr<DrawPolygon> second_back_polygon; |
| 529 |
| 530 polygon_c->SplitPolygon(std::move(back_polygon), &second_front_polygon, |
| 531 &second_back_polygon, &is_coplanar); |
| 532 EXPECT_FALSE(is_coplanar); |
| 533 EXPECT_TRUE(second_front_polygon != nullptr); |
| 534 EXPECT_TRUE(second_back_polygon != nullptr); |
| 535 |
| 536 EXPECT_EQ(3u, second_front_polygon->points().size()); |
| 537 EXPECT_EQ(3u, second_back_polygon->points().size()); |
| 538 } |
| 539 |
409 TEST(DrawPolygonTransformTest, TransformNormal) { | 540 TEST(DrawPolygonTransformTest, TransformNormal) { |
410 std::vector<gfx::Point3F> vertices_a; | 541 std::vector<gfx::Point3F> vertices_a; |
411 vertices_a.push_back(gfx::Point3F(1.0f, 0.0f, 1.0f)); | 542 vertices_a.push_back(gfx::Point3F(1.0f, 0.0f, 1.0f)); |
412 vertices_a.push_back(gfx::Point3F(-1.0f, 0.0f, -1.0f)); | 543 vertices_a.push_back(gfx::Point3F(-1.0f, 0.0f, -1.0f)); |
413 vertices_a.push_back(gfx::Point3F(0.0f, 1.0f, 0.0f)); | 544 vertices_a.push_back(gfx::Point3F(0.0f, 1.0f, 0.0f)); |
414 CREATE_NEW_DRAW_POLYGON(polygon_a, vertices_a, | 545 CREATE_NEW_DRAW_POLYGON(polygon_a, vertices_a, |
415 gfx::Vector3dF(sqrt(2) / 2, 0.0f, -sqrt(2) / 2), 0); | 546 gfx::Vector3dF(sqrt(2) / 2, 0.0f, -sqrt(2) / 2), 0); |
416 EXPECT_NORMAL(polygon_a, sqrt(2) / 2, 0.0f, -sqrt(2) / 2); | 547 EXPECT_NORMAL(polygon_a, sqrt(2) / 2, 0.0f, -sqrt(2) / 2); |
417 | 548 |
418 gfx::Transform transform; | 549 gfx::Transform transform; |
419 transform.RotateAboutYAxis(45.0f); | 550 transform.RotateAboutYAxis(45.0f); |
420 // This would transform the vertices as well, but we are transforming a | 551 // This would transform the vertices as well, but we are transforming a |
421 // DrawPolygon with 0 vertices just to make sure our normal transformation | 552 // DrawPolygon with 0 vertices just to make sure our normal transformation |
422 // using the inverse tranpose matrix gives us the right result. | 553 // using the inverse tranpose matrix gives us the right result. |
423 polygon_a.TransformToScreenSpace(transform); | 554 polygon_a.TransformToScreenSpace(transform); |
424 | 555 |
425 // Note: We use EXPECT_FLOAT_WITHIN_EPSILON instead of EXPECT_FLOAT_EQUAL here | 556 // Note: We use EXPECT_FLOAT_WITHIN_EPSILON instead of EXPECT_FLOAT_EQUAL here |
426 // because some architectures (e.g., Arm64) employ a fused multiply-add | 557 // because some architectures (e.g., Arm64) employ a fused multiply-add |
427 // instruction which causes rounding asymmetry and reduces precision. | 558 // instruction which causes rounding asymmetry and reduces precision. |
428 // http://crbug.com/401117. | 559 // http://crbug.com/401117. |
429 EXPECT_NORMAL(polygon_a, 0.0f, 0.0f, -1.0f); | 560 EXPECT_NORMAL(polygon_a, 0.0f, 0.0f, -1.0f); |
430 } | 561 } |
431 | 562 |
432 } // namespace | 563 } // namespace |
433 } // namespace cc | 564 } // namespace cc |
OLD | NEW |