15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/geometry/cubic_bezier.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gfx { 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(CubicBezierTest, Basic) { 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CubicBezier function(0.25, 0.0, 0.75, 1.0); 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double epsilon = 0.00015; 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0), 0, epsilon); 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.05), 0.01136, epsilon); 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.1), 0.03978, epsilon); 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.15), 0.079780, epsilon); 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.2), 0.12803, epsilon); 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.25), 0.18235, epsilon); 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.3), 0.24115, epsilon); 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.35), 0.30323, epsilon); 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.4), 0.36761, epsilon); 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.45), 0.43345, epsilon); 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.5), 0.5, epsilon); 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.6), 0.63238, epsilon); 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.65), 0.69676, epsilon); 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.7), 0.75884, epsilon); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.75), 0.81764, epsilon); 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.8), 0.87196, epsilon); 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.85), 0.92021, epsilon); 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.9), 0.96021, epsilon); 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.95), 0.98863, epsilon); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(1), 1, epsilon); 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Tests that solving the bezier works with knots with y not in (0, 1). 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(CubicBezierTest, UnclampedYValues) { 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CubicBezier function(0.5, -1.0, 0.5, 2.0); 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double epsilon = 0.00015; 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.0), 0.0, epsilon); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.05), -0.08954, epsilon); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.1), -0.15613, epsilon); 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.15), -0.19641, epsilon); 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.2), -0.20651, epsilon); 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.25), -0.18232, epsilon); 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.3), -0.11992, epsilon); 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.35), -0.01672, epsilon); 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.4), 0.12660, epsilon); 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.45), 0.30349, epsilon); 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.5), 0.50000, epsilon); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.55), 0.69651, epsilon); 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.6), 0.87340, epsilon); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.65), 1.01672, epsilon); 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.7), 1.11992, epsilon); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.75), 1.18232, epsilon); 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.8), 1.20651, epsilon); 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.85), 1.19641, epsilon); 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.9), 1.15613, epsilon); 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(0.95), 1.08954, epsilon); 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(function.Solve(1.0), 1.0, epsilon); 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST(CubicBezierTest, Range) { 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double epsilon = 0.00015; 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double min, max; 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative is a constant. 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<CubicBezier> function( 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new CubicBezier(0.25, (1.0 / 3.0), 0.75, (2.0 / 3.0))); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative is linear. 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, -0.5, 0.75, (-1.0 / 6.0))); 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(min, -0.225, epsilon); 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has no real roots. 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.25, 0.75, 0.5)); 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has exactly one real root. 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.0, 1.0, 1.0, 0.0)); 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has one root < 0 and one root > 1. 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.1, 0.75, 0.9)); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has two roots in [0,1]. 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 2.5, 0.75, 0.5)); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(max, 1.28818, epsilon); 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.5, 0.75, -1.5)); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(min, -0.28818, epsilon); 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has one root < 0 and one root in [0,1]. 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.1, 0.75, 1.5)); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(max, 1.10755, epsilon); 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has one root in [0,1] and one root > 1. 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, -0.5, 0.75, 0.9)); 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_NEAR(min, -0.10755, epsilon); 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has two roots < 0. 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.3, 0.75, 0.633)); 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0, min); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1, max); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Derivative has two roots > 1. 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function.reset(new CubicBezier(0.25, 0.367, 0.75, 0.7)); 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function->Range(&min, &max); 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(0.f, min); 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(1.f, max); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST(CubicBezierTest, Slope) { 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CubicBezier function(0.25, 0.0, 0.75, 1.0); 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) double epsilon = 0.00015; 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0), 0, epsilon); 1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.05), 0.42170, epsilon); 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.1), 0.69778, epsilon); 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.15), 0.89121, epsilon); 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.2), 1.03184, epsilon); 1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.25), 1.13576, epsilon); 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.3), 1.21239, epsilon); 1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.35), 1.26751, epsilon); 1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.4), 1.30474, epsilon); 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.45), 1.32628, epsilon); 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.5), 1.33333, epsilon); 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.55), 1.32628, epsilon); 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.6), 1.30474, epsilon); 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.65), 1.26751, epsilon); 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.7), 1.21239, epsilon); 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.75), 1.13576, epsilon); 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.8), 1.03184, epsilon); 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.85), 0.89121, epsilon); 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.9), 0.69778, epsilon); 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(0.95), 0.42170, epsilon); 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) EXPECT_NEAR(function.Slope(1), 0, epsilon); 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace gfx 169